]> git.dujemihanovic.xyz Git - linux.git/commitdiff
net: dsa: add support switches global DSCP priority mapping
authorOleksij Rempel <o.rempel@pengutronix.de>
Fri, 3 May 2024 13:13:49 +0000 (15:13 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 8 May 2024 09:35:10 +0000 (10:35 +0100)
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>
include/net/dsa.h
net/dsa/user.c

index 40c127a3018789d805737193bea4c835e2c0c3a3..b60e7e410aba78321d2e5e0ed446be1286146989 100644 (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)))
index 89282c0867765836d9b594dcdc248acf3ee7f9ad..867c5fe9a4dafbb4796b5521bc3ed1a503d2fecf 100644 (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;
 }