Commit 5f5109af authored by Oleksij Rempel's avatar Oleksij Rempel Committed by David S. Miller
Browse files

net: dsa: add support switches global DSCP priority mapping



Some switches like Microchip KSZ variants do not support per port DSCP
priority configuration. Instead there is a global DSCP mapping table.

To handle it, we will accept set/del request to any of user ports to
make global configuration and update dcb app entries for all other
ports.

Signed-off-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ea1078d9
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -433,6 +433,11 @@ struct dsa_switch {
	 */
	u32			fdb_isolation:1;

	/* Drivers that have global DSCP mapping settings must set this to
	 * true to automatically apply the settings to all ports.
	 */
	u32			dscp_prio_mapping_is_global:1;

	/* Listener for switch fabric events */
	struct notifier_block	nb;

@@ -586,6 +591,10 @@ static inline bool dsa_is_user_port(struct dsa_switch *ds, int p)
	dsa_switch_for_each_port((_dp), (_ds)) \
		if (dsa_port_is_user((_dp)))

#define dsa_switch_for_each_user_port_continue_reverse(_dp, _ds) \
	dsa_switch_for_each_port_continue_reverse((_dp), (_ds)) \
		if (dsa_port_is_user((_dp)))

#define dsa_switch_for_each_cpu_port(_dp, _ds) \
	dsa_switch_for_each_port((_dp), (_ds)) \
		if (dsa_port_is_cpu((_dp)))
+75 −0
Original line number Diff line number Diff line
@@ -2189,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)
{
@@ -2220,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;
}

@@ -2290,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;
}