Skip to content

Commit

Permalink
Merge branch 'dsa-felix-qos'
Browse files Browse the repository at this point in the history
Vladimir Oltean says:

====================
Basic QoS classification on Felix DSA switch using dcbnl

Basic QoS classification for Ocelot switches means port-based default
priority, DSCP-based and VLAN PCP based. This is opposed to advanced QoS
classification which is done through the VCAP IS1 TCAM based engine.

The patch set is a logical continuation of this RFC which attempted to
describe the default-prio as a matchall entry placed at the end of a
series of offloaded tc filters:
https://patchwork.kernel.org/project/netdevbpf/cover/20210113154139.1803705-1-olteanv@gmail.com/

I have tried my best to satisfy the feedback that we should cater for
pre-configured QoS profiles. Ironically, the only pre-configured QoS
profile that the Felix switch driver has is for VLAN PCP (1:1 mapping
with QoS class), yet IEEE 802.1Q or dcbnl offer no mechanism for
reporting or changing that.

Testing was done with the iproute2 dcb app. The qos_class of packets was
dumped from net/dsa/tag_ocelot.c.

(1) $ dcb app show dev swp3
default-prio 0
(2) $ dcb app replace dev swp3 default-prio 3
(3) $ dcb app replace dev swp3 dscp-prio CS3:5
(4) $ dcb app replace dev swp3 dscp-prio CS2:2
(5) $ dcb app show dev swp3
default-prio 3
dscp-prio CS2:2 CS3:5

Traffic sent with "ping -Q 64 <ipaddr>", which means CS2.
These packets match qos_class 0 after command (1),
qos_class 3 after command (2),
qos_class 3 after command (3), and
qos_class 2 after command (2).
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed Mar 14, 2022
2 parents 102e4a8 + 978777d commit 92ebb23
Show file tree
Hide file tree
Showing 5 changed files with 399 additions and 0 deletions.
43 changes: 43 additions & 0 deletions drivers/net/dsa/ocelot/felix.c
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,44 @@ felix_mrp_del_ring_role(struct dsa_switch *ds, int port,
return ocelot_mrp_del_ring_role(ocelot, port, mrp);
}

static int felix_port_get_default_prio(struct dsa_switch *ds, int port)
{
struct ocelot *ocelot = ds->priv;

return ocelot_port_get_default_prio(ocelot, port);
}

static int felix_port_set_default_prio(struct dsa_switch *ds, int port,
u8 prio)
{
struct ocelot *ocelot = ds->priv;

return ocelot_port_set_default_prio(ocelot, port, prio);
}

static int felix_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)
{
struct ocelot *ocelot = ds->priv;

return ocelot_port_get_dscp_prio(ocelot, port, dscp);
}

static int felix_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
u8 prio)
{
struct ocelot *ocelot = ds->priv;

return ocelot_port_add_dscp_prio(ocelot, port, dscp, prio);
}

static int felix_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp,
u8 prio)
{
struct ocelot *ocelot = ds->priv;

return ocelot_port_del_dscp_prio(ocelot, port, dscp, prio);
}

const struct dsa_switch_ops felix_switch_ops = {
.get_tag_protocol = felix_get_tag_protocol,
.change_tag_protocol = felix_change_tag_protocol,
Expand Down Expand Up @@ -1862,6 +1900,11 @@ const struct dsa_switch_ops felix_switch_ops = {
.port_mrp_del_ring_role = felix_mrp_del_ring_role,
.tag_8021q_vlan_add = felix_tag_8021q_vlan_add,
.tag_8021q_vlan_del = felix_tag_8021q_vlan_del,
.port_get_default_prio = felix_port_get_default_prio,
.port_set_default_prio = felix_port_set_default_prio,
.port_get_dscp_prio = felix_port_get_dscp_prio,
.port_add_dscp_prio = felix_port_add_dscp_prio,
.port_del_dscp_prio = felix_port_del_dscp_prio,
};

struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port)
Expand Down
116 changes: 116 additions & 0 deletions drivers/net/ethernet/mscc/ocelot.c
Original file line number Diff line number Diff line change
Expand Up @@ -2907,6 +2907,122 @@ void ocelot_port_bridge_flags(struct ocelot *ocelot, int port,
}
EXPORT_SYMBOL(ocelot_port_bridge_flags);

int ocelot_port_get_default_prio(struct ocelot *ocelot, int port)
{
int val = ocelot_read_gix(ocelot, ANA_PORT_QOS_CFG, port);

return ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL_X(val);
}
EXPORT_SYMBOL_GPL(ocelot_port_get_default_prio);

int ocelot_port_set_default_prio(struct ocelot *ocelot, int port, u8 prio)
{
if (prio >= IEEE_8021QAZ_MAX_TCS)
return -ERANGE;

ocelot_rmw_gix(ocelot,
ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL(prio),
ANA_PORT_QOS_CFG_QOS_DEFAULT_VAL_M,
ANA_PORT_QOS_CFG,
port);

return 0;
}
EXPORT_SYMBOL_GPL(ocelot_port_set_default_prio);

int ocelot_port_get_dscp_prio(struct ocelot *ocelot, int port, u8 dscp)
{
int qos_cfg = ocelot_read_gix(ocelot, ANA_PORT_QOS_CFG, port);
int dscp_cfg = ocelot_read_rix(ocelot, ANA_DSCP_CFG, dscp);

/* Return error if DSCP prioritization isn't enabled */
if (!(qos_cfg & ANA_PORT_QOS_CFG_QOS_DSCP_ENA))
return -EOPNOTSUPP;

if (qos_cfg & ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA) {
dscp = ANA_DSCP_CFG_DSCP_TRANSLATE_VAL_X(dscp_cfg);
/* Re-read ANA_DSCP_CFG for the translated DSCP */
dscp_cfg = ocelot_read_rix(ocelot, ANA_DSCP_CFG, dscp);
}

/* If the DSCP value is not trusted, the QoS classification falls back
* to VLAN PCP or port-based default.
*/
if (!(dscp_cfg & ANA_DSCP_CFG_DSCP_TRUST_ENA))
return -EOPNOTSUPP;

return ANA_DSCP_CFG_QOS_DSCP_VAL_X(dscp_cfg);
}
EXPORT_SYMBOL_GPL(ocelot_port_get_dscp_prio);

int ocelot_port_add_dscp_prio(struct ocelot *ocelot, int port, u8 dscp, u8 prio)
{
int mask, val;

if (prio >= IEEE_8021QAZ_MAX_TCS)
return -ERANGE;

/* There is at least one app table priority (this one), so we need to
* make sure DSCP prioritization is enabled on the port.
* Also make sure DSCP translation is disabled
* (dcbnl doesn't support it).
*/
mask = ANA_PORT_QOS_CFG_QOS_DSCP_ENA |
ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA;

ocelot_rmw_gix(ocelot, ANA_PORT_QOS_CFG_QOS_DSCP_ENA, mask,
ANA_PORT_QOS_CFG, port);

/* Trust this DSCP value and map it to the given QoS class */
val = ANA_DSCP_CFG_DSCP_TRUST_ENA | ANA_DSCP_CFG_QOS_DSCP_VAL(prio);

ocelot_write_rix(ocelot, val, ANA_DSCP_CFG, dscp);

return 0;
}
EXPORT_SYMBOL_GPL(ocelot_port_add_dscp_prio);

int ocelot_port_del_dscp_prio(struct ocelot *ocelot, int port, u8 dscp, u8 prio)
{
int dscp_cfg = ocelot_read_rix(ocelot, ANA_DSCP_CFG, dscp);
int mask, i;

/* During a "dcb app replace" command, the new app table entry will be
* added first, then the old one will be deleted. But the hardware only
* supports one QoS class per DSCP value (duh), so if we blindly delete
* the app table entry for this DSCP value, we end up deleting the
* entry with the new priority. Avoid that by checking whether user
* space wants to delete the priority which is currently configured, or
* something else which is no longer current.
*/
if (ANA_DSCP_CFG_QOS_DSCP_VAL_X(dscp_cfg) != prio)
return 0;

/* Untrust this DSCP value */
ocelot_write_rix(ocelot, 0, ANA_DSCP_CFG, dscp);

for (i = 0; i < 64; i++) {
int dscp_cfg = ocelot_read_rix(ocelot, ANA_DSCP_CFG, i);

/* There are still app table entries on the port, so we need to
* keep DSCP enabled, nothing to do.
*/
if (dscp_cfg & ANA_DSCP_CFG_DSCP_TRUST_ENA)
return 0;
}

/* Disable DSCP QoS classification if there isn't any trusted
* DSCP value left.
*/
mask = ANA_PORT_QOS_CFG_QOS_DSCP_ENA |
ANA_PORT_QOS_CFG_DSCP_TRANSLATE_ENA;

ocelot_rmw_gix(ocelot, 0, mask, ANA_PORT_QOS_CFG, port);

return 0;
}
EXPORT_SYMBOL_GPL(ocelot_port_del_dscp_prio);

void ocelot_init_port(struct ocelot *ocelot, int port)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
Expand Down
12 changes: 12 additions & 0 deletions include/net/dsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,18 @@ struct dsa_switch_ops {
int (*get_ts_info)(struct dsa_switch *ds, int port,
struct ethtool_ts_info *ts);

/*
* DCB ops
*/
int (*port_get_default_prio)(struct dsa_switch *ds, int port);
int (*port_set_default_prio)(struct dsa_switch *ds, int port,
u8 prio);
int (*port_get_dscp_prio)(struct dsa_switch *ds, int port, u8 dscp);
int (*port_add_dscp_prio)(struct dsa_switch *ds, int port, u8 dscp,
u8 prio);
int (*port_del_dscp_prio)(struct dsa_switch *ds, int port, u8 dscp,
u8 prio);

/*
* Suspend and resume
*/
Expand Down
5 changes: 5 additions & 0 deletions include/soc/mscc/ocelot.h
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,11 @@ int ocelot_port_pre_bridge_flags(struct ocelot *ocelot, int port,
struct switchdev_brport_flags val);
void ocelot_port_bridge_flags(struct ocelot *ocelot, int port,
struct switchdev_brport_flags val);
int ocelot_port_get_default_prio(struct ocelot *ocelot, int port);
int ocelot_port_set_default_prio(struct ocelot *ocelot, int port, u8 prio);
int ocelot_port_get_dscp_prio(struct ocelot *ocelot, int port, u8 dscp);
int ocelot_port_add_dscp_prio(struct ocelot *ocelot, int port, u8 dscp, u8 prio);
int ocelot_port_del_dscp_prio(struct ocelot *ocelot, int port, u8 dscp, u8 prio);
int ocelot_port_bridge_join(struct ocelot *ocelot, int port,
struct net_device *bridge, int bridge_num,
struct netlink_ext_ack *extack);
Expand Down
Loading

0 comments on commit 92ebb23

Please sign in to comment.