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

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
...@@ -433,6 +433,11 @@ struct dsa_switch { ...@@ -433,6 +433,11 @@ struct dsa_switch {
*/ */
u32 fdb_isolation:1; 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 */ /* Listener for switch fabric events */
struct notifier_block nb; struct notifier_block nb;
...@@ -586,6 +591,10 @@ static inline bool dsa_is_user_port(struct dsa_switch *ds, int p) ...@@ -586,6 +591,10 @@ static inline bool dsa_is_user_port(struct dsa_switch *ds, int p)
dsa_switch_for_each_port((_dp), (_ds)) \ dsa_switch_for_each_port((_dp), (_ds)) \
if (dsa_port_is_user((_dp))) 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) \ #define dsa_switch_for_each_cpu_port(_dp, _ds) \
dsa_switch_for_each_port((_dp), (_ds)) \ dsa_switch_for_each_port((_dp), (_ds)) \
if (dsa_port_is_cpu((_dp))) if (dsa_port_is_cpu((_dp)))
......
...@@ -2189,6 +2189,58 @@ dsa_user_dcbnl_set_default_prio(struct net_device *dev, struct dcb_app *app) ...@@ -2189,6 +2189,58 @@ dsa_user_dcbnl_set_default_prio(struct net_device *dev, struct dcb_app *app)
return 0; 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 static int __maybe_unused
dsa_user_dcbnl_add_dscp_prio(struct net_device *dev, struct dcb_app *app) 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) ...@@ -2220,6 +2272,17 @@ dsa_user_dcbnl_add_dscp_prio(struct net_device *dev, struct dcb_app *app)
return err; 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; return 0;
} }
...@@ -2290,6 +2353,18 @@ dsa_user_dcbnl_del_dscp_prio(struct net_device *dev, struct dcb_app *app) ...@@ -2290,6 +2353,18 @@ dsa_user_dcbnl_del_dscp_prio(struct net_device *dev, struct dcb_app *app)
return err; 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; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment