]> www.infradead.org Git - users/hch/misc.git/commitdiff
net: sfp: pre-parse the module support
authorRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Tue, 16 Sep 2025 21:46:41 +0000 (22:46 +0100)
committerJakub Kicinski <kuba@kernel.org>
Mon, 22 Sep 2025 23:05:14 +0000 (16:05 -0700)
Pre-parse the module support on insert rather than when the upstream
requests the data. This will allow more flexible and extensible
parsing.

Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Link: https://patch.msgid.link/E1uydVZ-000000061WE-2pXD@rmk-PC.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/phy/sfp-bus.c
include/linux/sfp.h

index f13c00b5b449cfe61af3a7b2aada9d741a663509..35030c527fbed41e196e183dd643ed8ae8e6f9c0 100644 (file)
@@ -22,7 +22,6 @@ struct sfp_bus {
        const struct sfp_socket_ops *socket_ops;
        struct device *sfp_dev;
        struct sfp *sfp;
-       const struct sfp_quirk *sfp_quirk;
 
        const struct sfp_upstream_ops *upstream_ops;
        void *upstream;
@@ -30,6 +29,8 @@ struct sfp_bus {
 
        bool registered;
        bool started;
+
+       struct sfp_module_caps caps;
 };
 
 /**
@@ -48,6 +49,13 @@ struct sfp_bus {
  */
 int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
                   unsigned long *support)
+{
+       return bus->caps.port;
+}
+EXPORT_SYMBOL_GPL(sfp_parse_port);
+
+static void sfp_module_parse_port(struct sfp_bus *bus,
+                                 const struct sfp_eeprom_id *id)
 {
        int port;
 
@@ -91,21 +99,18 @@ int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
                break;
        }
 
-       if (support) {
-               switch (port) {
-               case PORT_FIBRE:
-                       phylink_set(support, FIBRE);
-                       break;
+       switch (port) {
+       case PORT_FIBRE:
+               phylink_set(bus->caps.link_modes, FIBRE);
+               break;
 
-               case PORT_TP:
-                       phylink_set(support, TP);
-                       break;
-               }
+       case PORT_TP:
+               phylink_set(bus->caps.link_modes, TP);
+               break;
        }
 
-       return port;
+       bus->caps.port = port;
 }
-EXPORT_SYMBOL_GPL(sfp_parse_port);
 
 /**
  * sfp_may_have_phy() - indicate whether the module may have a PHY
@@ -117,8 +122,17 @@ EXPORT_SYMBOL_GPL(sfp_parse_port);
  */
 bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id)
 {
-       if (id->base.e1000_base_t)
-               return true;
+       return bus->caps.may_have_phy;
+}
+EXPORT_SYMBOL_GPL(sfp_may_have_phy);
+
+static void sfp_module_parse_may_have_phy(struct sfp_bus *bus,
+                                         const struct sfp_eeprom_id *id)
+{
+       if (id->base.e1000_base_t) {
+               bus->caps.may_have_phy = true;
+               return;
+       }
 
        if (id->base.phys_id != SFF8024_ID_DWDM_SFP) {
                switch (id->base.extended_cc) {
@@ -126,13 +140,13 @@ bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id)
                case SFF8024_ECC_10GBASE_T_SR:
                case SFF8024_ECC_5GBASE_T:
                case SFF8024_ECC_2_5GBASE_T:
-                       return true;
+                       bus->caps.may_have_phy = true;
+                       return;
                }
        }
 
-       return false;
+       bus->caps.may_have_phy = false;
 }
-EXPORT_SYMBOL_GPL(sfp_may_have_phy);
 
 /**
  * sfp_parse_support() - Parse the eeprom id for supported link modes
@@ -148,8 +162,17 @@ EXPORT_SYMBOL_GPL(sfp_may_have_phy);
 void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
                       unsigned long *support, unsigned long *interfaces)
 {
+       linkmode_or(support, support, bus->caps.link_modes);
+       phy_interface_copy(interfaces, bus->caps.interfaces);
+}
+EXPORT_SYMBOL_GPL(sfp_parse_support);
+
+static void sfp_module_parse_support(struct sfp_bus *bus,
+                                    const struct sfp_eeprom_id *id)
+{
+       unsigned long *interfaces = bus->caps.interfaces;
+       unsigned long *modes = bus->caps.link_modes;
        unsigned int br_min, br_nom, br_max;
-       __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
 
        /* Decode the bitrate information to MBd */
        br_min = br_nom = br_max = 0;
@@ -338,13 +361,22 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
        phylink_set(modes, Autoneg);
        phylink_set(modes, Pause);
        phylink_set(modes, Asym_Pause);
+}
+
+static void sfp_init_module(struct sfp_bus *bus,
+                           const struct sfp_eeprom_id *id,
+                           const struct sfp_quirk *quirk)
+{
+       memset(&bus->caps, 0, sizeof(bus->caps));
 
-       if (bus->sfp_quirk && bus->sfp_quirk->modes)
-               bus->sfp_quirk->modes(id, modes, interfaces);
+       sfp_module_parse_support(bus, id);
+       sfp_module_parse_port(bus, id);
+       sfp_module_parse_may_have_phy(bus, id);
 
-       linkmode_or(support, support, modes);
+       if (quirk && quirk->modes)
+               quirk->modes(id, bus->caps.link_modes,
+                            bus->caps.interfaces);
 }
-EXPORT_SYMBOL_GPL(sfp_parse_support);
 
 /**
  * sfp_select_interface() - Select appropriate phy_interface_t mode
@@ -794,7 +826,7 @@ int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
        const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
        int ret = 0;
 
-       bus->sfp_quirk = quirk;
+       sfp_init_module(bus, id, quirk);
 
        if (ops && ops->module_insert)
                ret = ops->module_insert(bus->upstream, id);
@@ -809,8 +841,6 @@ void sfp_module_remove(struct sfp_bus *bus)
 
        if (ops && ops->module_remove)
                ops->module_remove(bus->upstream);
-
-       bus->sfp_quirk = NULL;
 }
 EXPORT_SYMBOL_GPL(sfp_module_remove);
 
index 60c65cea74f62650b322609e43b3fae627ea38a2..5fb59cf49882c3d9b0ab1679d79f551b7621cead 100644 (file)
@@ -521,6 +521,28 @@ struct ethtool_eeprom;
 struct ethtool_modinfo;
 struct sfp_bus;
 
+/**
+ * struct sfp_module_caps - sfp module capabilities
+ * @interfaces: bitmap of interfaces that the module may support
+ * @link_modes: bitmap of ethtool link modes that the module may support
+ */
+struct sfp_module_caps {
+       DECLARE_PHY_INTERFACE_MASK(interfaces);
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(link_modes);
+       /**
+        * @may_have_phy: indicate whether the module may have an ethernet PHY
+        * There is no way to be sure that a module has a PHY as the EEPROM
+        * doesn't contain this information. When set, this does not mean that
+        * the module definitely has a PHY.
+        */
+       bool may_have_phy;
+       /**
+        * @port: one of ethtool %PORT_* definitions, parsed from the module
+        * EEPROM, or %PORT_OTHER if the port type is not known.
+        */
+       u8 port;
+};
+
 /**
  * struct sfp_upstream_ops - upstream operations structure
  * @attach: called when the sfp socket driver is bound to the upstream