net: dsa: add plumbing for changing and getting MAC merge layer state
authorVladimir Oltean <vladimir.oltean@nxp.com>
Thu, 19 Jan 2023 12:27:00 +0000 (14:27 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 23 Jan 2023 12:44:18 +0000 (12:44 +0000)
The DSA core is in charge of the ethtool_ops of the net devices
associated with switch ports, so in case a hardware driver supports the
MAC merge layer, DSA must pass the callbacks through to the driver.
Add support for precisely that.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/dsa.h
net/dsa/slave.c

index 9608628..a15f17a 100644 (file)
@@ -938,6 +938,17 @@ struct dsa_switch_ops {
                               struct ethtool_ts_info *ts);
 
        /*
+        * ethtool MAC merge layer
+        */
+       int     (*get_mm)(struct dsa_switch *ds, int port,
+                         struct ethtool_mm_state *state);
+       int     (*set_mm)(struct dsa_switch *ds, int port,
+                         struct ethtool_mm_cfg *cfg,
+                         struct netlink_ext_ack *extack);
+       void    (*get_mm_stats)(struct dsa_switch *ds, int port,
+                               struct ethtool_mm_stats *stats);
+
+       /*
         * DCB ops
         */
        int     (*port_get_default_prio)(struct dsa_switch *ds, int port);
index aab79c3..6014ac3 100644 (file)
@@ -1117,6 +1117,40 @@ static void dsa_slave_net_selftest(struct net_device *ndev,
        net_selftest(ndev, etest, buf);
 }
 
+static int dsa_slave_get_mm(struct net_device *dev,
+                           struct ethtool_mm_state *state)
+{
+       struct dsa_port *dp = dsa_slave_to_port(dev);
+       struct dsa_switch *ds = dp->ds;
+
+       if (!ds->ops->get_mm)
+               return -EOPNOTSUPP;
+
+       return ds->ops->get_mm(ds, dp->index, state);
+}
+
+static int dsa_slave_set_mm(struct net_device *dev, struct ethtool_mm_cfg *cfg,
+                           struct netlink_ext_ack *extack)
+{
+       struct dsa_port *dp = dsa_slave_to_port(dev);
+       struct dsa_switch *ds = dp->ds;
+
+       if (!ds->ops->set_mm)
+               return -EOPNOTSUPP;
+
+       return ds->ops->set_mm(ds, dp->index, cfg, extack);
+}
+
+static void dsa_slave_get_mm_stats(struct net_device *dev,
+                                  struct ethtool_mm_stats *stats)
+{
+       struct dsa_port *dp = dsa_slave_to_port(dev);
+       struct dsa_switch *ds = dp->ds;
+
+       if (ds->ops->get_mm_stats)
+               ds->ops->get_mm_stats(ds, dp->index, stats);
+}
+
 static void dsa_slave_get_wol(struct net_device *dev, struct ethtool_wolinfo *w)
 {
        struct dsa_port *dp = dsa_slave_to_port(dev);
@@ -2205,6 +2239,9 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
        .set_rxnfc              = dsa_slave_set_rxnfc,
        .get_ts_info            = dsa_slave_get_ts_info,
        .self_test              = dsa_slave_net_selftest,
+       .get_mm                 = dsa_slave_get_mm,
+       .set_mm                 = dsa_slave_set_mm,
+       .get_mm_stats           = dsa_slave_get_mm_stats,
 };
 
 static const struct dcbnl_rtnl_ops __maybe_unused dsa_slave_dcbnl_ops = {