net: dsa: allow DSA switch drivers to provide their own phylink mac ops
authorRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Wed, 10 Apr 2024 19:42:43 +0000 (20:42 +0100)
committerJakub Kicinski <kuba@kernel.org>
Fri, 12 Apr 2024 03:01:14 +0000 (20:01 -0700)
Rather than having a shim for each and every phylink MAC operation,
allow DSA switch drivers to provide their own ops structure. When a
DSA driver provides the phylink MAC operations, the shimmed ops must
not be provided, so fail an attempt to register a switch with both
the phylink_mac_ops in struct dsa_switch and the phylink_mac_*
operations populated in dsa_switch_ops populated.

Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Link: https://lore.kernel.org/r/E1rudqF-006K9H-Cc@rmk-PC.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/dsa.h
net/dsa/dsa.c
net/dsa/port.c

index f228b479a5fd24eca2eccf19bfee1106f8de5e17..7edfd8de8882feb68c0b6b27941c9224ce5596f0 100644 (file)
@@ -457,6 +457,11 @@ struct dsa_switch {
         */
        const struct dsa_switch_ops     *ops;
 
+       /*
+        * Allow a DSA switch driver to override the phylink MAC ops
+        */
+       const struct phylink_mac_ops    *phylink_mac_ops;
+
        /*
         * User mii_bus and devices for the individual ports.
         */
index 09d2f5d4b3dd40f5ab1090b7b6002df0bf9a34bb..2f347cd37316234ab83e06ea0232efc0de41d845 100644 (file)
@@ -1505,6 +1505,17 @@ static int dsa_switch_probe(struct dsa_switch *ds)
        if (!ds->num_ports)
                return -EINVAL;
 
+       if (ds->phylink_mac_ops) {
+               if (ds->ops->phylink_mac_select_pcs ||
+                   ds->ops->phylink_mac_prepare ||
+                   ds->ops->phylink_mac_config ||
+                   ds->ops->phylink_mac_finish ||
+                   ds->ops->phylink_mac_link_down ||
+                   ds->ops->phylink_mac_link_up ||
+                   ds->ops->adjust_link)
+                       return -EINVAL;
+       }
+
        if (np) {
                err = dsa_switch_parse_of(ds, np);
                if (err)
index 02bf1c306bdcaf81669cd7124e0d12b9e4216915..c6febc3d96d9bba0864cca00f3b4576c07e91ce9 100644 (file)
@@ -1662,6 +1662,7 @@ static const struct phylink_mac_ops dsa_port_phylink_mac_ops = {
 
 int dsa_port_phylink_create(struct dsa_port *dp)
 {
+       const struct phylink_mac_ops *mac_ops;
        struct dsa_switch *ds = dp->ds;
        phy_interface_t mode;
        struct phylink *pl;
@@ -1685,8 +1686,12 @@ int dsa_port_phylink_create(struct dsa_port *dp)
                }
        }
 
-       pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
-                           mode, &dsa_port_phylink_mac_ops);
+       mac_ops = &dsa_port_phylink_mac_ops;
+       if (ds->phylink_mac_ops)
+               mac_ops = ds->phylink_mac_ops;
+
+       pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), mode,
+                           mac_ops);
        if (IS_ERR(pl)) {
                pr_err("error creating PHYLINK: %ld\n", PTR_ERR(pl));
                return PTR_ERR(pl);
@@ -1952,12 +1957,23 @@ static void dsa_shared_port_validate_of(struct dsa_port *dp,
                dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
 }
 
+static void dsa_shared_port_link_down(struct dsa_port *dp)
+{
+       struct dsa_switch *ds = dp->ds;
+
+       if (ds->phylink_mac_ops && ds->phylink_mac_ops->mac_link_down)
+               ds->phylink_mac_ops->mac_link_down(&dp->pl_config, MLO_AN_FIXED,
+                                                  PHY_INTERFACE_MODE_NA);
+       else if (ds->ops->phylink_mac_link_down)
+               ds->ops->phylink_mac_link_down(ds, dp->index, MLO_AN_FIXED,
+                                              PHY_INTERFACE_MODE_NA);
+}
+
 int dsa_shared_port_link_register_of(struct dsa_port *dp)
 {
        struct dsa_switch *ds = dp->ds;
        bool missing_link_description;
        bool missing_phy_mode;
-       int port = dp->index;
 
        dsa_shared_port_validate_of(dp, &missing_phy_mode,
                                    &missing_link_description);
@@ -1973,9 +1989,7 @@ int dsa_shared_port_link_register_of(struct dsa_port *dp)
                                 "Skipping phylink registration for %s port %d\n",
                                 dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
                } else {
-                       if (ds->ops->phylink_mac_link_down)
-                               ds->ops->phylink_mac_link_down(ds, port,
-                                       MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);
+                       dsa_shared_port_link_down(dp);
 
                        return dsa_shared_port_phylink_register(dp);
                }