net: dsa: microchip: add support DSCP priority mapping
authorOleksij Rempel <o.rempel@pengutronix.de>
Fri, 3 May 2024 13:13:50 +0000 (15:13 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 8 May 2024 09:35:11 +0000 (10:35 +0100)
Microchip KSZ and LAN variants do not have per port DSCP priority
configuration. Instead there is a global DSCP mapping table.

This patch provides write access to this global DSCP map. In case entry
is "deleted", we map corresponding DSCP entry to a best effort prio,
which is expected to be the default priority for all untagged traffic.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/microchip/ksz_dcb.c
drivers/net/dsa/microchip/ksz_dcb.h

index 996e8e893b662e4a898821c09763ec8aa395b6ba..bbf9925c98d91fd2d16b4ae4abc9f1716209c8c5 100644 (file)
@@ -2360,6 +2360,7 @@ static int ksz_setup(struct dsa_switch *ds)
        ksz_init_mib_timer(dev);
 
        ds->configure_vlan_while_not_filtering = false;
+       ds->dscp_prio_mapping_is_global = true;
 
        if (dev->dev_ops->setup) {
                ret = dev->dev_ops->setup(ds);
@@ -3989,6 +3990,8 @@ static const struct dsa_switch_ops ksz_switch_ops = {
        .port_get_default_prio  = ksz_port_get_default_prio,
        .port_set_default_prio  = ksz_port_set_default_prio,
        .port_get_dscp_prio     = ksz_port_get_dscp_prio,
+       .port_add_dscp_prio     = ksz_port_add_dscp_prio,
+       .port_del_dscp_prio     = ksz_port_del_dscp_prio,
        .port_get_apptrust      = ksz_port_get_apptrust,
        .port_set_apptrust      = ksz_port_set_apptrust,
 };
index 80fb322de8f745e8f2d9af48aa8f01f29cb15864..5e520c02afd72a278639fbc12cff18dffd72603c 100644 (file)
@@ -310,6 +310,19 @@ int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)
        return (data >> shift) & mask;
 }
 
+static int ksz_set_global_dscp_entry(struct ksz_device *dev, u8 dscp, u8 ipv)
+{
+       int reg, per_reg, shift;
+       u8 mask;
+
+       ksz_get_dscp_prio_reg(dev, &reg, &per_reg, &mask);
+
+       shift = (dscp % per_reg) * (8 / per_reg);
+
+       return ksz_rmw8(dev, reg + (dscp / per_reg), mask << shift,
+                       ipv << shift);
+}
+
 /**
  * ksz_init_global_dscp_map - Initializes the global DSCP-to-priority mapping
  * @dev: Pointer to the KSZ switch device structure
@@ -321,9 +334,7 @@ int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)
  */
 static int ksz_init_global_dscp_map(struct ksz_device *dev)
 {
-       int reg, per_reg, ret, dscp;
-       u8 data = 0;
-       u8 mask;
+       int ret, dscp;
 
        /* On KSZ9xxx variants, DSCP remapping is disabled by default.
         * Enable to have, predictable and reproducible behavior across
@@ -337,10 +348,8 @@ static int ksz_init_global_dscp_map(struct ksz_device *dev)
                        return ret;
        }
 
-       ksz_get_dscp_prio_reg(dev, &reg, &per_reg, &mask);
-
        for (dscp = 0; dscp < DSCP_MAX; dscp++) {
-               int ipv, shift, tt;
+               int ipv, tt;
 
                /* Map DSCP to Traffic Type, which is corresponding to the
                 * Internal Priority Value (IPV) in the switch.
@@ -362,19 +371,40 @@ static int ksz_init_global_dscp_map(struct ksz_device *dev)
                if (ipv < 0)
                        return ipv;
 
-               shift = (dscp % per_reg) * (8 / per_reg);
-               data |= (ipv & mask) << shift;
+               ret = ksz_set_global_dscp_entry(dev, dscp, ipv);
+       }
 
-               if (dscp % per_reg == per_reg - 1) {
-                       ret = ksz_write8(dev, reg + (dscp / per_reg), data);
-                       if (ret)
-                               return ret;
+       return 0;
+}
 
-                       data = 0;
-               }
+int ksz_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (prio >= dev->info->num_ipvs)
+               return -ERANGE;
+
+       return ksz_set_global_dscp_entry(dev, dscp, prio);
+}
+
+int ksz_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio)
+{
+       struct ksz_device *dev = ds->priv;
+       int ipv;
+
+       if (ksz_port_get_dscp_prio(ds, port, dscp) != prio)
+               return 0;
+
+       if (is_ksz8(dev)) {
+               ipv = ieee8021q_tt_to_tc(IEEE8021Q_TT_BE,
+                                        dev->info->num_tx_queues);
+               if (ipv < 0)
+                       return ipv;
+       } else {
+               ipv = IEEE8021Q_TT_BE;
        }
 
-       return 0;
+       return ksz_set_global_dscp_entry(dev, dscp, ipv);
 }
 
 /**
index 254c0e7bdafcaa306f8f989a7b6a8acf44b3f246..e2065223ba90c8267e43ca82ec6e125012cfd397 100644 (file)
@@ -11,6 +11,8 @@
 int ksz_port_get_default_prio(struct dsa_switch *ds, int port);
 int ksz_port_set_default_prio(struct dsa_switch *ds, int port, u8 prio);
 int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp);
+int ksz_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio);
+int ksz_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio);
 int ksz_port_set_apptrust(struct dsa_switch *ds, int port,
                          const unsigned char *sel,
                          int nsel);