Commit a83e4630 authored by Horatiu Vultur's avatar Horatiu Vultur Committed by Paolo Abeni

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: default avatarDaniel Machon <daniel.machon@microchip.com>
Reviewed-by: default avatarPiotr Raczynski <piotr.raczynski@intel.com>
Signed-off-by: default avatarHoratiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 1fd22211
......@@ -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.
......@@ -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
......
// 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;
}
}
......@@ -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:
......
......@@ -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,
......
......@@ -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;
......
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