net: mscc: ocelot: add support for mqprio offload
authorVladimir Oltean <vladimir.oltean@nxp.com>
Sat, 15 Apr 2023 17:05:49 +0000 (20:05 +0300)
committerJakub Kicinski <kuba@kernel.org>
Tue, 18 Apr 2023 02:01:19 +0000 (19:01 -0700)
This doesn't apply anything to hardware and in general doesn't do
anything that the software variant doesn't do, except for checking that
there isn't more than 1 TXQ per TC (TXQs for a DSA switch are a dubious
concept anyway). The reason we add this is to be able to parse one more
field added to struct tc_mqprio_qopt_offload, namely preemptible_tcs.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Ferenc Fejes <fejes@inf.elte.hu>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/ocelot/felix_vsc9959.c
drivers/net/ethernet/mscc/ocelot.c
include/soc/mscc/ocelot.h

index 478893c..66ec274 100644 (file)
@@ -1612,6 +1612,13 @@ static int vsc9959_qos_port_cbs_set(struct dsa_switch *ds, int port,
 static int vsc9959_qos_query_caps(struct tc_query_caps_base *base)
 {
        switch (base->type) {
+       case TC_SETUP_QDISC_MQPRIO: {
+               struct tc_mqprio_caps *caps = base->caps;
+
+               caps->validate_queue_counts = true;
+
+               return 0;
+       }
        case TC_SETUP_QDISC_TAPRIO: {
                struct tc_taprio_caps *caps = base->caps;
 
@@ -1635,6 +1642,8 @@ static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port,
                return vsc9959_qos_query_caps(type_data);
        case TC_SETUP_QDISC_TAPRIO:
                return vsc9959_qos_port_tas_set(ocelot, port, type_data);
+       case TC_SETUP_QDISC_MQPRIO:
+               return ocelot_port_mqprio(ocelot, port, type_data);
        case TC_SETUP_QDISC_CBS:
                return vsc9959_qos_port_cbs_set(ds, port, type_data);
        default:
index 1502bb2..8dc5fb1 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/if_bridge.h>
 #include <linux/iopoll.h>
 #include <linux/phy/phy.h>
+#include <net/pkt_sched.h>
 #include <soc/mscc/ocelot_hsio.h>
 #include <soc/mscc/ocelot_vcap.h>
 #include "ocelot.h"
@@ -2699,6 +2700,55 @@ void ocelot_port_mirror_del(struct ocelot *ocelot, int from, bool ingress)
 }
 EXPORT_SYMBOL_GPL(ocelot_port_mirror_del);
 
+static void ocelot_port_reset_mqprio(struct ocelot *ocelot, int port)
+{
+       struct net_device *dev = ocelot->ops->port_to_netdev(ocelot, port);
+
+       netdev_reset_tc(dev);
+}
+
+int ocelot_port_mqprio(struct ocelot *ocelot, int port,
+                      struct tc_mqprio_qopt_offload *mqprio)
+{
+       struct net_device *dev = ocelot->ops->port_to_netdev(ocelot, port);
+       struct netlink_ext_ack *extack = mqprio->extack;
+       struct tc_mqprio_qopt *qopt = &mqprio->qopt;
+       int num_tc = qopt->num_tc;
+       int tc, err;
+
+       if (!num_tc) {
+               ocelot_port_reset_mqprio(ocelot, port);
+               return 0;
+       }
+
+       err = netdev_set_num_tc(dev, num_tc);
+       if (err)
+               return err;
+
+       for (tc = 0; tc < num_tc; tc++) {
+               if (qopt->count[tc] != 1) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Only one TXQ per TC supported");
+                       return -EINVAL;
+               }
+
+               err = netdev_set_tc_queue(dev, tc, 1, qopt->offset[tc]);
+               if (err)
+                       goto err_reset_tc;
+       }
+
+       err = netif_set_real_num_tx_queues(dev, num_tc);
+       if (err)
+               goto err_reset_tc;
+
+       return 0;
+
+err_reset_tc:
+       ocelot_port_reset_mqprio(ocelot, port);
+       return err;
+}
+EXPORT_SYMBOL_GPL(ocelot_port_mqprio);
+
 void ocelot_init_port(struct ocelot *ocelot, int port)
 {
        struct ocelot_port *ocelot_port = ocelot->ports[port];
index ee8d43d..9596c79 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/regmap.h>
 #include <net/dsa.h>
 
+struct tc_mqprio_qopt_offload;
+
 /* Port Group IDs (PGID) are masks of destination ports.
  *
  * For L2 forwarding, the switch performs 3 lookups in the PGID table for each
@@ -1154,6 +1156,8 @@ int ocelot_port_set_mm(struct ocelot *ocelot, int port,
                       struct netlink_ext_ack *extack);
 int ocelot_port_get_mm(struct ocelot *ocelot, int port,
                       struct ethtool_mm_state *state);
+int ocelot_port_mqprio(struct ocelot *ocelot, int port,
+                      struct tc_mqprio_qopt_offload *mqprio);
 
 #if IS_ENABLED(CONFIG_BRIDGE_MRP)
 int ocelot_mrp_add(struct ocelot *ocelot, int port,