OSDN Git Service

net: lan966x: Add support for PCP rewrite
authorHoratiu Vultur <horatiu.vultur@microchip.com>
Tue, 16 May 2023 20:14:07 +0000 (22:14 +0200)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 18 May 2023 13:32:10 +0000 (15:32 +0200)
Add support for rewrite of PCP and DEI value, based on QoS and DP level.

The DCB rewrite table is queried for mappings between priority and
PCP/DEI. The classified DP level is then encoded in the DEI bit, if a
mapping for DEI exists.

Reviewed-by: Daniel Machon <daniel.machon@microchip.com>
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.h
drivers/net/ethernet/microchip/lan966x/lan966x_port.c

index 273e3bf..0ea6509 100644 (file)
@@ -46,9 +46,11 @@ static bool lan966x_dcb_apptrust_contains(int portno, u8 selector)
 
 static void lan966x_dcb_app_update(struct net_device *dev)
 {
+       struct dcb_rewr_prio_pcp_map pcp_rewr_map = {0};
        struct lan966x_port *port = netdev_priv(dev);
        struct lan966x_port_qos qos = {0};
        struct dcb_app app_itr;
+       bool pcp_rewr = false;
 
        /* Get pcp ingress mapping */
        for (int i = 0; i < ARRAY_SIZE(qos.pcp.map); i++) {
@@ -69,10 +71,24 @@ static void lan966x_dcb_app_update(struct net_device *dev)
        if (qos.default_prio)
                qos.default_prio = fls(qos.default_prio) - 1;
 
+       /* Get pcp rewrite mapping */
+       dcb_getrewr_prio_pcp_mask_map(dev, &pcp_rewr_map);
+       for (int i = 0; i < ARRAY_SIZE(pcp_rewr_map.map); i++) {
+               if (!pcp_rewr_map.map[i])
+                       continue;
+
+               pcp_rewr = true;
+               qos.pcp_rewr.map[i] = fls(pcp_rewr_map.map[i]) - 1;
+       }
+
        /* Enable use of pcp for queue classification */
-       if (lan966x_dcb_apptrust_contains(port->chip_port, DCB_APP_SEL_PCP))
+       if (lan966x_dcb_apptrust_contains(port->chip_port, DCB_APP_SEL_PCP)) {
                qos.pcp.enable = true;
 
+               if (pcp_rewr)
+                       qos.pcp_rewr.enable = true;
+       }
+
        /* Enable use of dscp for queue classification */
        if (lan966x_dcb_apptrust_contains(port->chip_port, IEEE_8021QAZ_APP_SEL_DSCP))
                qos.dscp.enable = true;
@@ -252,11 +268,54 @@ static int lan966x_dcb_getapptrust(struct net_device *dev, u8 *selectors,
        return 0;
 }
 
+static int lan966x_dcb_delrewr(struct net_device *dev, struct dcb_app *app)
+{
+       int err;
+
+       err = dcb_delrewr(dev, app);
+       if (err < 0)
+               return err;
+
+       lan966x_dcb_app_update(dev);
+
+       return 0;
+}
+
+static int lan966x_dcb_setrewr(struct net_device *dev, struct dcb_app *app)
+{
+       struct dcb_app app_itr;
+       u16 proto;
+       int err;
+
+       err = lan966x_dcb_app_validate(dev, app);
+       if (err)
+               goto out;
+
+       /* Delete current mapping, if it exists. */
+       proto = dcb_getrewr(dev, app);
+       if (proto) {
+               app_itr = *app;
+               app_itr.protocol = proto;
+               lan966x_dcb_delrewr(dev, &app_itr);
+       }
+
+       err = dcb_setrewr(dev, app);
+       if (err)
+               goto out;
+
+       lan966x_dcb_app_update(dev);
+
+out:
+       return err;
+}
+
 static const struct dcbnl_rtnl_ops lan966x_dcbnl_ops = {
        .ieee_setapp = lan966x_dcb_ieee_setapp,
        .ieee_delapp = lan966x_dcb_ieee_delapp,
        .dcbnl_setapptrust = lan966x_dcb_setapptrust,
        .dcbnl_getapptrust = lan966x_dcb_getapptrust,
+       .dcbnl_setrewr = lan966x_dcb_setrewr,
+       .dcbnl_delrewr = lan966x_dcb_delrewr,
 };
 
 void lan966x_dcb_init(struct lan966x *lan966x)
index 53711d5..16b0149 100644 (file)
 
 #define LAN966X_PORT_QOS_DSCP_COUNT    64
 
+/* Port PCP rewrite mode */
+#define LAN966X_PORT_REW_TAG_CTRL_CLASSIFIED   0
+#define LAN966X_PORT_REW_TAG_CTRL_MAPPED       2
+
 /* MAC table entry types.
  * ENTRYTYPE_NORMAL is subject to aging.
  * ENTRYTYPE_LOCKED is not subject to aging.
@@ -409,9 +413,15 @@ struct lan966x_port_qos_dscp {
        bool enable;
 };
 
+struct lan966x_port_qos_pcp_rewr {
+       u16 map[NUM_PRIO_QUEUES];
+       bool enable;
+};
+
 struct lan966x_port_qos {
        struct lan966x_port_qos_pcp pcp;
        struct lan966x_port_qos_dscp dscp;
+       struct lan966x_port_qos_pcp_rewr pcp_rewr;
        u8 default_prio;
 };
 
index a660887..6887746 100644 (file)
@@ -463,12 +463,49 @@ static int lan966x_port_qos_default_set(struct lan966x_port *port,
        return 0;
 }
 
+static void lan966x_port_qos_pcp_rewr_set(struct lan966x_port *port,
+                                         struct lan966x_port_qos_pcp_rewr *qos)
+{
+       u8 mode = LAN966X_PORT_REW_TAG_CTRL_CLASSIFIED;
+       u8 pcp, dei;
+
+       if (qos->enable)
+               mode = LAN966X_PORT_REW_TAG_CTRL_MAPPED;
+
+       /* Map the values only if it is enabled otherwise will be the classified
+        * value
+        */
+       lan_rmw(REW_TAG_CFG_TAG_PCP_CFG_SET(mode) |
+               REW_TAG_CFG_TAG_DEI_CFG_SET(mode),
+               REW_TAG_CFG_TAG_PCP_CFG |
+               REW_TAG_CFG_TAG_DEI_CFG,
+               port->lan966x, REW_TAG_CFG(port->chip_port));
+
+       /* Map each value to pcp and dei */
+       for (int i = 0; i < ARRAY_SIZE(qos->map); i++) {
+               pcp = qos->map[i];
+               if (pcp > LAN966X_PORT_QOS_PCP_COUNT)
+                       dei = 1;
+               else
+                       dei = 0;
+
+               lan_rmw(REW_PCP_DEI_CFG_DEI_QOS_VAL_SET(dei) |
+                       REW_PCP_DEI_CFG_PCP_QOS_VAL_SET(pcp),
+                       REW_PCP_DEI_CFG_DEI_QOS_VAL |
+                       REW_PCP_DEI_CFG_PCP_QOS_VAL,
+                       port->lan966x,
+                       REW_PCP_DEI_CFG(port->chip_port,
+                                       i + dei * LAN966X_PORT_QOS_PCP_COUNT));
+       }
+}
+
 void lan966x_port_qos_set(struct lan966x_port *port,
                          struct lan966x_port_qos *qos)
 {
        lan966x_port_qos_pcp_set(port, &qos->pcp);
        lan966x_port_qos_dscp_set(port, &qos->dscp);
        lan966x_port_qos_default_set(port, qos);
+       lan966x_port_qos_pcp_rewr_set(port, &qos->pcp_rewr);
 }
 
 void lan966x_port_init(struct lan966x_port *port)