diff options
Diffstat (limited to 'net/dsa')
| -rw-r--r-- | net/dsa/devlink.c | 3 | ||||
| -rw-r--r-- | net/dsa/dsa.c | 10 | ||||
| -rw-r--r-- | net/dsa/port.c | 175 | ||||
| -rw-r--r-- | net/dsa/user.c | 107 | 
4 files changed, 153 insertions, 142 deletions
diff --git a/net/dsa/devlink.c b/net/dsa/devlink.c index 431bf52290a1..0aac887d0098 100644 --- a/net/dsa/devlink.c +++ b/net/dsa/devlink.c @@ -194,7 +194,8 @@ int dsa_devlink_param_get(struct devlink *dl, u32 id,  EXPORT_SYMBOL_GPL(dsa_devlink_param_get);  int dsa_devlink_param_set(struct devlink *dl, u32 id, -			  struct devlink_param_gset_ctx *ctx) +			  struct devlink_param_gset_ctx *ctx, +			  struct netlink_ext_ack *extack)  {  	struct dsa_switch *ds = dsa_devlink_to_ds(dl); diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 09d2f5d4b3dd..12521a7d4048 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -1505,6 +1505,16 @@ static int dsa_switch_probe(struct dsa_switch *ds)  	if (!ds->num_ports)  		return -EINVAL; +	if (ds->phylink_mac_ops) { +		if (ds->ops->phylink_mac_select_pcs || +		    ds->ops->phylink_mac_prepare || +		    ds->ops->phylink_mac_config || +		    ds->ops->phylink_mac_finish || +		    ds->ops->phylink_mac_link_down || +		    ds->ops->phylink_mac_link_up) +			return -EINVAL; +	} +  	if (np) {  		err = dsa_switch_parse_of(ds, np);  		if (err) diff --git a/net/dsa/port.c b/net/dsa/port.c index c42dac87671b..9a249d4ac3a5 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -1535,30 +1535,11 @@ void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp,  	cpu_dp->tag_ops = tag_ops;  } -static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp) -{ -	struct device_node *phy_dn; -	struct phy_device *phydev; - -	phy_dn = of_parse_phandle(dp->dn, "phy-handle", 0); -	if (!phy_dn) -		return NULL; - -	phydev = of_phy_find_device(phy_dn); -	if (!phydev) { -		of_node_put(phy_dn); -		return ERR_PTR(-EPROBE_DEFER); -	} - -	of_node_put(phy_dn); -	return phydev; -} -  static struct phylink_pcs *  dsa_port_phylink_mac_select_pcs(struct phylink_config *config,  				phy_interface_t interface)  { -	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); +	struct dsa_port *dp = dsa_phylink_to_port(config);  	struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP);  	struct dsa_switch *ds = dp->ds; @@ -1572,7 +1553,7 @@ static int dsa_port_phylink_mac_prepare(struct phylink_config *config,  					unsigned int mode,  					phy_interface_t interface)  { -	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); +	struct dsa_port *dp = dsa_phylink_to_port(config);  	struct dsa_switch *ds = dp->ds;  	int err = 0; @@ -1587,7 +1568,7 @@ static void dsa_port_phylink_mac_config(struct phylink_config *config,  					unsigned int mode,  					const struct phylink_link_state *state)  { -	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); +	struct dsa_port *dp = dsa_phylink_to_port(config);  	struct dsa_switch *ds = dp->ds;  	if (!ds->ops->phylink_mac_config) @@ -1600,7 +1581,7 @@ static int dsa_port_phylink_mac_finish(struct phylink_config *config,  				       unsigned int mode,  				       phy_interface_t interface)  { -	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); +	struct dsa_port *dp = dsa_phylink_to_port(config);  	struct dsa_switch *ds = dp->ds;  	int err = 0; @@ -1615,18 +1596,11 @@ static void dsa_port_phylink_mac_link_down(struct phylink_config *config,  					   unsigned int mode,  					   phy_interface_t interface)  { -	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); -	struct phy_device *phydev = NULL; +	struct dsa_port *dp = dsa_phylink_to_port(config);  	struct dsa_switch *ds = dp->ds; -	if (dsa_port_is_user(dp)) -		phydev = dp->user->phydev; - -	if (!ds->ops->phylink_mac_link_down) { -		if (ds->ops->adjust_link && phydev) -			ds->ops->adjust_link(ds, dp->index, phydev); +	if (!ds->ops->phylink_mac_link_down)  		return; -	}  	ds->ops->phylink_mac_link_down(ds, dp->index, mode, interface);  } @@ -1638,14 +1612,11 @@ static void dsa_port_phylink_mac_link_up(struct phylink_config *config,  					 int speed, int duplex,  					 bool tx_pause, bool rx_pause)  { -	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); +	struct dsa_port *dp = dsa_phylink_to_port(config);  	struct dsa_switch *ds = dp->ds; -	if (!ds->ops->phylink_mac_link_up) { -		if (ds->ops->adjust_link && phydev) -			ds->ops->adjust_link(ds, dp->index, phydev); +	if (!ds->ops->phylink_mac_link_up)  		return; -	}  	ds->ops->phylink_mac_link_up(ds, dp->index, mode, interface, phydev,  				     speed, duplex, tx_pause, rx_pause); @@ -1662,6 +1633,7 @@ static const struct phylink_mac_ops dsa_port_phylink_mac_ops = {  int dsa_port_phylink_create(struct dsa_port *dp)  { +	const struct phylink_mac_ops *mac_ops;  	struct dsa_switch *ds = dp->ds;  	phy_interface_t mode;  	struct phylink *pl; @@ -1685,8 +1657,12 @@ int dsa_port_phylink_create(struct dsa_port *dp)  		}  	} -	pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), -			    mode, &dsa_port_phylink_mac_ops); +	mac_ops = &dsa_port_phylink_mac_ops; +	if (ds->phylink_mac_ops) +		mac_ops = ds->phylink_mac_ops; + +	pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), mode, +			    mac_ops);  	if (IS_ERR(pl)) {  		pr_err("error creating PHYLINK: %ld\n", PTR_ERR(pl));  		return PTR_ERR(pl); @@ -1703,78 +1679,6 @@ void dsa_port_phylink_destroy(struct dsa_port *dp)  	dp->pl = NULL;  } -static int dsa_shared_port_setup_phy_of(struct dsa_port *dp, bool enable) -{ -	struct dsa_switch *ds = dp->ds; -	struct phy_device *phydev; -	int port = dp->index; -	int err = 0; - -	phydev = dsa_port_get_phy_device(dp); -	if (!phydev) -		return 0; - -	if (IS_ERR(phydev)) -		return PTR_ERR(phydev); - -	if (enable) { -		err = genphy_resume(phydev); -		if (err < 0) -			goto err_put_dev; - -		err = genphy_read_status(phydev); -		if (err < 0) -			goto err_put_dev; -	} else { -		err = genphy_suspend(phydev); -		if (err < 0) -			goto err_put_dev; -	} - -	if (ds->ops->adjust_link) -		ds->ops->adjust_link(ds, port, phydev); - -	dev_dbg(ds->dev, "enabled port's phy: %s", phydev_name(phydev)); - -err_put_dev: -	put_device(&phydev->mdio.dev); -	return err; -} - -static int dsa_shared_port_fixed_link_register_of(struct dsa_port *dp) -{ -	struct device_node *dn = dp->dn; -	struct dsa_switch *ds = dp->ds; -	struct phy_device *phydev; -	int port = dp->index; -	phy_interface_t mode; -	int err; - -	err = of_phy_register_fixed_link(dn); -	if (err) { -		dev_err(ds->dev, -			"failed to register the fixed PHY of port %d\n", -			port); -		return err; -	} - -	phydev = of_phy_find_device(dn); - -	err = of_get_phy_mode(dn, &mode); -	if (err) -		mode = PHY_INTERFACE_MODE_NA; -	phydev->interface = mode; - -	genphy_read_status(phydev); - -	if (ds->ops->adjust_link) -		ds->ops->adjust_link(ds, port, phydev); - -	put_device(&phydev->mdio.dev); - -	return 0; -} -  static int dsa_shared_port_phylink_register(struct dsa_port *dp)  {  	struct dsa_switch *ds = dp->ds; @@ -1952,12 +1856,23 @@ static void dsa_shared_port_validate_of(struct dsa_port *dp,  		dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);  } +static void dsa_shared_port_link_down(struct dsa_port *dp) +{ +	struct dsa_switch *ds = dp->ds; + +	if (ds->phylink_mac_ops && ds->phylink_mac_ops->mac_link_down) +		ds->phylink_mac_ops->mac_link_down(&dp->pl_config, MLO_AN_FIXED, +						   PHY_INTERFACE_MODE_NA); +	else if (ds->ops->phylink_mac_link_down) +		ds->ops->phylink_mac_link_down(ds, dp->index, MLO_AN_FIXED, +					       PHY_INTERFACE_MODE_NA); +} +  int dsa_shared_port_link_register_of(struct dsa_port *dp)  {  	struct dsa_switch *ds = dp->ds;  	bool missing_link_description;  	bool missing_phy_mode; -	int port = dp->index;  	dsa_shared_port_validate_of(dp, &missing_phy_mode,  				    &missing_link_description); @@ -1967,46 +1882,28 @@ int dsa_shared_port_link_register_of(struct dsa_port *dp)  					dsa_switches_apply_workarounds))  		return -EINVAL; -	if (!ds->ops->adjust_link) { -		if (missing_link_description) { -			dev_warn(ds->dev, -				 "Skipping phylink registration for %s port %d\n", -				 dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index); -		} else { -			if (ds->ops->phylink_mac_link_down) -				ds->ops->phylink_mac_link_down(ds, port, -					MLO_AN_FIXED, PHY_INTERFACE_MODE_NA); +	if (missing_link_description) { +		dev_warn(ds->dev, +			 "Skipping phylink registration for %s port %d\n", +			 dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index); +	} else { +		dsa_shared_port_link_down(dp); -			return dsa_shared_port_phylink_register(dp); -		} -		return 0; +		return dsa_shared_port_phylink_register(dp);  	} -	dev_warn(ds->dev, -		 "Using legacy PHYLIB callbacks. Please migrate to PHYLINK!\n"); - -	if (of_phy_is_fixed_link(dp->dn)) -		return dsa_shared_port_fixed_link_register_of(dp); -	else -		return dsa_shared_port_setup_phy_of(dp, true); +	return 0;  }  void dsa_shared_port_link_unregister_of(struct dsa_port *dp)  { -	struct dsa_switch *ds = dp->ds; - -	if (!ds->ops->adjust_link && dp->pl) { +	if (dp->pl) {  		rtnl_lock();  		phylink_disconnect_phy(dp->pl);  		rtnl_unlock();  		dsa_port_phylink_destroy(dp);  		return;  	} - -	if (of_phy_is_fixed_link(dp->dn)) -		of_phy_deregister_fixed_link(dp->dn); -	else -		dsa_shared_port_setup_phy_of(dp, false);  }  int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr, diff --git a/net/dsa/user.c b/net/dsa/user.c index 16d395bb1a1f..867c5fe9a4da 100644 --- a/net/dsa/user.c +++ b/net/dsa/user.c @@ -2120,7 +2120,7 @@ int dsa_user_change_mtu(struct net_device *dev, int new_mtu)  	if (err)  		goto out_port_failed; -	dev->mtu = new_mtu; +	WRITE_ONCE(dev->mtu, new_mtu);  	dsa_bridge_mtu_normalization(dp); @@ -2137,6 +2137,32 @@ out_conduit_failed:  }  static int __maybe_unused +dsa_user_dcbnl_set_apptrust(struct net_device *dev, u8 *sel, int nsel) +{ +	struct dsa_port *dp = dsa_user_to_port(dev); +	struct dsa_switch *ds = dp->ds; +	int port = dp->index; + +	if (!ds->ops->port_set_apptrust) +		return -EOPNOTSUPP; + +	return ds->ops->port_set_apptrust(ds, port, sel, nsel); +} + +static int __maybe_unused +dsa_user_dcbnl_get_apptrust(struct net_device *dev, u8 *sel, int *nsel) +{ +	struct dsa_port *dp = dsa_user_to_port(dev); +	struct dsa_switch *ds = dp->ds; +	int port = dp->index; + +	if (!ds->ops->port_get_apptrust) +		return -EOPNOTSUPP; + +	return ds->ops->port_get_apptrust(ds, port, sel, nsel); +} + +static int __maybe_unused  dsa_user_dcbnl_set_default_prio(struct net_device *dev, struct dcb_app *app)  {  	struct dsa_port *dp = dsa_user_to_port(dev); @@ -2163,6 +2189,58 @@ dsa_user_dcbnl_set_default_prio(struct net_device *dev, struct dcb_app *app)  	return 0;  } +/* Update the DSCP prio entries on all user ports of the switch in case + * the switch supports global DSCP prio instead of per port DSCP prios. + */ +static int dsa_user_dcbnl_ieee_global_dscp_setdel(struct net_device *dev, +						  struct dcb_app *app, bool del) +{ +	int (*setdel)(struct net_device *dev, struct dcb_app *app); +	struct dsa_port *dp = dsa_user_to_port(dev); +	struct dsa_switch *ds = dp->ds; +	struct dsa_port *other_dp; +	int err, restore_err; + +	if (del) +		setdel = dcb_ieee_delapp; +	else +		setdel = dcb_ieee_setapp; + +	dsa_switch_for_each_user_port(other_dp, ds) { +		struct net_device *user = other_dp->user; + +		if (!user || user == dev) +			continue; + +		err = setdel(user, app); +		if (err) +			goto err_try_to_restore; +	} + +	return 0; + +err_try_to_restore: + +	/* Revert logic to restore previous state of app entries */ +	if (!del) +		setdel = dcb_ieee_delapp; +	else +		setdel = dcb_ieee_setapp; + +	dsa_switch_for_each_user_port_continue_reverse(other_dp, ds) { +		struct net_device *user = other_dp->user; + +		if (!user || user == dev) +			continue; + +		restore_err = setdel(user, app); +		if (restore_err) +			netdev_err(user, "Failed to restore DSCP prio entry configuration\n"); +	} + +	return err; +} +  static int __maybe_unused  dsa_user_dcbnl_add_dscp_prio(struct net_device *dev, struct dcb_app *app)  { @@ -2194,6 +2272,17 @@ dsa_user_dcbnl_add_dscp_prio(struct net_device *dev, struct dcb_app *app)  		return err;  	} +	if (!ds->dscp_prio_mapping_is_global) +		return 0; + +	err = dsa_user_dcbnl_ieee_global_dscp_setdel(dev, app, false); +	if (err) { +		if (ds->ops->port_del_dscp_prio) +			ds->ops->port_del_dscp_prio(ds, port, dscp, new_prio); +		dcb_ieee_delapp(dev, app); +		return err; +	} +  	return 0;  } @@ -2264,6 +2353,18 @@ dsa_user_dcbnl_del_dscp_prio(struct net_device *dev, struct dcb_app *app)  		return err;  	} +	if (!ds->dscp_prio_mapping_is_global) +		return 0; + +	err = dsa_user_dcbnl_ieee_global_dscp_setdel(dev, app, true); +	if (err) { +		if (ds->ops->port_add_dscp_prio) +			ds->ops->port_add_dscp_prio(ds, port, dscp, +						    app->priority); +		dcb_ieee_setapp(dev, app); +		return err; +	} +  	return 0;  } @@ -2376,6 +2477,8 @@ static const struct ethtool_ops dsa_user_ethtool_ops = {  static const struct dcbnl_rtnl_ops __maybe_unused dsa_user_dcbnl_ops = {  	.ieee_setapp		= dsa_user_dcbnl_ieee_setapp,  	.ieee_delapp		= dsa_user_dcbnl_ieee_delapp, +	.dcbnl_setapptrust	= dsa_user_dcbnl_set_apptrust, +	.dcbnl_getapptrust	= dsa_user_dcbnl_get_apptrust,  };  static void dsa_user_get_stats64(struct net_device *dev, @@ -2445,7 +2548,7 @@ EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_change);  static void dsa_user_phylink_fixed_state(struct phylink_config *config,  					 struct phylink_link_state *state)  { -	struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); +	struct dsa_port *dp = dsa_phylink_to_port(config);  	struct dsa_switch *ds = dp->ds;  	/* No need to check that this operation is valid, the callback would  |