net: lan966x: Add support for offloading pcp table

Add support for offloading pcp app entries. Lan966x has 8 priority
queues per port and for each priority it also has a drop precedence.

Reviewed-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Piotr Raczynski <piotr.raczynski@intel.com>
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Horatiu Vultur 2023-05-16 22:14:03 +02:00 committed by Paolo Abeni
parent 1fd2221135
commit a83e463036
6 changed files with 172 additions and 0 deletions

View File

@ -10,3 +10,14 @@ config LAN966X_SWITCH
select VCAP
help
This driver supports the Lan966x network switch device.
config LAN966X_DCB
bool "Data Center Bridging (DCB) support"
depends on LAN966X_SWITCH && DCB
default y
help
Say Y here if you want to use Data Center Bridging (DCB) in the
driver. This can be used to assign priority to traffic, based on
DSCP and PCP.
If unsure, set to Y.

View File

@ -15,6 +15,7 @@ lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \
lan966x_xdp.o lan966x_vcap_impl.o lan966x_vcap_ag_api.o \
lan966x_tc_flower.o lan966x_goto.o
lan966x-switch-$(CONFIG_LAN966X_DCB) += lan966x_dcb.o
lan966x-switch-$(CONFIG_DEBUG_FS) += lan966x_vcap_debugfs.o
# Provide include files

View File

@ -0,0 +1,103 @@
// SPDX-License-Identifier: GPL-2.0+
#include "lan966x_main.h"
static void lan966x_dcb_app_update(struct net_device *dev, bool enable)
{
struct lan966x_port *port = netdev_priv(dev);
struct lan966x_port_qos qos = {0};
struct dcb_app app_itr;
/* Get pcp ingress mapping */
for (int i = 0; i < ARRAY_SIZE(qos.pcp.map); i++) {
app_itr.selector = DCB_APP_SEL_PCP;
app_itr.protocol = i;
qos.pcp.map[i] = dcb_getapp(dev, &app_itr);
}
qos.pcp.enable = enable;
lan966x_port_qos_set(port, &qos);
}
static int lan966x_dcb_app_validate(struct net_device *dev,
const struct dcb_app *app)
{
int err = 0;
switch (app->selector) {
/* Pcp checks */
case DCB_APP_SEL_PCP:
if (app->protocol >= LAN966X_PORT_QOS_PCP_DEI_COUNT)
err = -EINVAL;
else if (app->priority >= NUM_PRIO_QUEUES)
err = -ERANGE;
break;
default:
err = -EINVAL;
break;
}
if (err)
netdev_err(dev, "Invalid entry: %d:%d\n", app->protocol,
app->priority);
return err;
}
static int lan966x_dcb_ieee_delapp(struct net_device *dev, struct dcb_app *app)
{
int err;
err = dcb_ieee_delapp(dev, app);
if (err < 0)
return err;
lan966x_dcb_app_update(dev, false);
return 0;
}
static int lan966x_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app)
{
struct dcb_app app_itr;
int err;
u8 prio;
err = lan966x_dcb_app_validate(dev, app);
if (err)
return err;
/* Delete current mapping, if it exists */
prio = dcb_getapp(dev, app);
if (prio) {
app_itr = *app;
app_itr.priority = prio;
dcb_ieee_delapp(dev, &app_itr);
}
err = dcb_ieee_setapp(dev, app);
if (err)
return err;
lan966x_dcb_app_update(dev, true);
return 0;
}
static const struct dcbnl_rtnl_ops lan966x_dcbnl_ops = {
.ieee_setapp = lan966x_dcb_ieee_setapp,
.ieee_delapp = lan966x_dcb_ieee_delapp,
};
void lan966x_dcb_init(struct lan966x *lan966x)
{
for (int p = 0; p < lan966x->num_phys_ports; ++p) {
struct lan966x_port *port;
port = lan966x->ports[p];
if (!port)
continue;
port->dev->dcbnl_ops = &lan966x_dcbnl_ops;
}
}

View File

@ -1213,6 +1213,8 @@ static int lan966x_probe(struct platform_device *pdev)
if (err)
goto cleanup_fdma;
lan966x_dcb_init(lan966x);
return 0;
cleanup_fdma:

View File

@ -104,6 +104,11 @@
#define LAN966X_VCAP_CID_ES0_L0 VCAP_CID_EGRESS_L0 /* ES0 lookup 0 */
#define LAN966X_VCAP_CID_ES0_MAX (VCAP_CID_EGRESS_L1 - 1) /* ES0 Max */
#define LAN966X_PORT_QOS_PCP_COUNT 8
#define LAN966X_PORT_QOS_DEI_COUNT 8
#define LAN966X_PORT_QOS_PCP_DEI_COUNT \
(LAN966X_PORT_QOS_PCP_COUNT + LAN966X_PORT_QOS_DEI_COUNT)
/* MAC table entry types.
* ENTRYTYPE_NORMAL is subject to aging.
* ENTRYTYPE_LOCKED is not subject to aging.
@ -392,6 +397,15 @@ struct lan966x_port_tc {
struct flow_stats mirror_stat;
};
struct lan966x_port_qos_pcp {
u8 map[LAN966X_PORT_QOS_PCP_DEI_COUNT];
bool enable;
};
struct lan966x_port_qos {
struct lan966x_port_qos_pcp pcp;
};
struct lan966x_port {
struct net_device *dev;
struct lan966x *lan966x;
@ -456,6 +470,9 @@ int lan966x_port_pcs_set(struct lan966x_port *port,
struct lan966x_port_config *config);
void lan966x_port_init(struct lan966x_port *port);
void lan966x_port_qos_set(struct lan966x_port *port,
struct lan966x_port_qos *qos);
int lan966x_mac_ip_learn(struct lan966x *lan966x,
bool cpu_copy,
const unsigned char mac[ETH_ALEN],
@ -680,6 +697,14 @@ int lan966x_goto_port_del(struct lan966x_port *port,
unsigned long goto_id,
struct netlink_ext_ack *extack);
#ifdef CONFIG_LAN966X_DCB
void lan966x_dcb_init(struct lan966x *lan966x);
#else
static inline void lan966x_dcb_init(struct lan966x *lan966x)
{
}
#endif
static inline void __iomem *lan_addr(void __iomem *base[],
int id, int tinst, int tcnt,
int gbase, int ginst,

View File

@ -394,6 +394,36 @@ int lan966x_port_pcs_set(struct lan966x_port *port,
return 0;
}
static void lan966x_port_qos_pcp_set(struct lan966x_port *port,
struct lan966x_port_qos_pcp *qos)
{
u8 *pcp_itr = qos->map;
u8 pcp, dp;
lan_rmw(ANA_QOS_CFG_QOS_PCP_ENA_SET(qos->enable),
ANA_QOS_CFG_QOS_PCP_ENA,
port->lan966x, ANA_QOS_CFG(port->chip_port));
/* Map PCP and DEI to priority */
for (int i = 0; i < ARRAY_SIZE(qos->map); i++) {
pcp = *(pcp_itr + i);
dp = (i < LAN966X_PORT_QOS_PCP_COUNT) ? 0 : 1;
lan_rmw(ANA_PCP_DEI_CFG_QOS_PCP_DEI_VAL_SET(pcp) |
ANA_PCP_DEI_CFG_DP_PCP_DEI_VAL_SET(dp),
ANA_PCP_DEI_CFG_QOS_PCP_DEI_VAL |
ANA_PCP_DEI_CFG_DP_PCP_DEI_VAL,
port->lan966x,
ANA_PCP_DEI_CFG(port->chip_port, i));
}
}
void lan966x_port_qos_set(struct lan966x_port *port,
struct lan966x_port_qos *qos)
{
lan966x_port_qos_pcp_set(port, &qos->pcp);
}
void lan966x_port_init(struct lan966x_port *port)
{
struct lan966x_port_config *config = &port->config;