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: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Oleksij Rempel 2024-05-03 15:13:49 +02:00 committed by David S. Miller
parent ea1078d94c
commit 5f5109af47
2 changed files with 84 additions and 0 deletions

View File

@ -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)))

View File

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