kernel: add support for HALNy HL-GSFP and other related fixes
authorJosef Schlehofer <pepe.schlehofer@gmail.com>
Fri, 26 Aug 2022 14:21:44 +0000 (16:21 +0200)
committerDaniel Golle <daniel@makrotopia.org>
Tue, 6 Sep 2022 15:26:23 +0000 (16:26 +0100)
It was reported on Turris forum [1] that HALNy HL-GSFP module does not
work as it should with kernel 5.15. Russell King prepared this patch
series, which fixes broken SFP module to work.

Compile and run tested with Turris Omnia.

[1] https://forum.turris.cz/t/hbl-turrisos-6-0-alpha2-halny-hl-gsfp-sfp-gpon-stick-problems/17547

Signed-off-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
target/linux/generic/pending-5.15/770-net-sfp-move-quirk-handling-into-sfp.c.patch [new file with mode: 0644]
target/linux/generic/pending-5.15/771-net-sfp-move-Alcatel-Lucent-3FE46541AA-fixup.patch [new file with mode: 0644]
target/linux/generic/pending-5.15/772-net-sfp-move-Huawei-MA5671A-fixup.patch [new file with mode: 0644]
target/linux/generic/pending-5.15/773-net-sfp-add-support-for-HALNy-GPON-SFP.patch [new file with mode: 0644]
target/linux/generic/pending-5.15/774--net-sfp-redo-soft-state-polling.patch [new file with mode: 0644]
target/linux/generic/pending-5.15/775-net-sfp-change-HALNy-to-ignore-hardware-pins.patch [new file with mode: 0644]

diff --git a/target/linux/generic/pending-5.15/770-net-sfp-move-quirk-handling-into-sfp.c.patch b/target/linux/generic/pending-5.15/770-net-sfp-move-quirk-handling-into-sfp.c.patch
new file mode 100644 (file)
index 0000000..8d43ccb
--- /dev/null
@@ -0,0 +1,290 @@
+From a4648a1957cd79bc389538aa0472db39a56e3df6 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 26 Aug 2022 08:43:30 +0100
+Subject: [PATCH 1/6] net: sfp: move quirk handling into sfp.c
+
+We need to handle more quirks than just those which affect the link
+modes of the module. Move the quirk lookup into sfp.c, and pass the
+quirk to sfp-bus.c
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp-bus.c | 98 ++-------------------------------------
+ drivers/net/phy/sfp.c     | 94 ++++++++++++++++++++++++++++++++++++-
+ drivers/net/phy/sfp.h     |  9 +++-
+ 3 files changed, 104 insertions(+), 97 deletions(-)
+
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -10,12 +10,6 @@
+ #include "sfp.h"
+-struct sfp_quirk {
+-      const char *vendor;
+-      const char *part;
+-      void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes);
+-};
+-
+ /**
+  * struct sfp_bus - internal representation of a sfp bus
+  */
+@@ -38,93 +32,6 @@ struct sfp_bus {
+       bool started;
+ };
+-static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
+-                              unsigned long *modes)
+-{
+-      phylink_set(modes, 2500baseX_Full);
+-}
+-
+-static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
+-                                    unsigned long *modes)
+-{
+-      /* Ubiquiti U-Fiber Instant module claims that support all transceiver
+-       * types including 10G Ethernet which is not truth. So clear all claimed
+-       * modes and set only one mode which module supports: 1000baseX_Full.
+-       */
+-      phylink_zero(modes);
+-      phylink_set(modes, 1000baseX_Full);
+-}
+-
+-static const struct sfp_quirk sfp_quirks[] = {
+-      {
+-              // Alcatel Lucent G-010S-P can operate at 2500base-X, but
+-              // incorrectly report 2500MBd NRZ in their EEPROM
+-              .vendor = "ALCATELLUCENT",
+-              .part = "G010SP",
+-              .modes = sfp_quirk_2500basex,
+-      }, {
+-              // Alcatel Lucent G-010S-A can operate at 2500base-X, but
+-              // report 3.2GBd NRZ in their EEPROM
+-              .vendor = "ALCATELLUCENT",
+-              .part = "3FE46541AA",
+-              .modes = sfp_quirk_2500basex,
+-      }, {
+-              // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd
+-              // NRZ in their EEPROM
+-              .vendor = "HUAWEI",
+-              .part = "MA5671A",
+-              .modes = sfp_quirk_2500basex,
+-      }, {
+-              // Lantech 8330-262D-E can operate at 2500base-X, but
+-              // incorrectly report 2500MBd NRZ in their EEPROM
+-              .vendor = "Lantech",
+-              .part = "8330-262D-E",
+-              .modes = sfp_quirk_2500basex,
+-      }, {
+-              .vendor = "UBNT",
+-              .part = "UF-INSTANT",
+-              .modes = sfp_quirk_ubnt_uf_instant,
+-      },
+-};
+-
+-static size_t sfp_strlen(const char *str, size_t maxlen)
+-{
+-      size_t size, i;
+-
+-      /* Trailing characters should be filled with space chars */
+-      for (i = 0, size = 0; i < maxlen; i++)
+-              if (str[i] != ' ')
+-                      size = i + 1;
+-
+-      return size;
+-}
+-
+-static bool sfp_match(const char *qs, const char *str, size_t len)
+-{
+-      if (!qs)
+-              return true;
+-      if (strlen(qs) != len)
+-              return false;
+-      return !strncmp(qs, str, len);
+-}
+-
+-static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
+-{
+-      const struct sfp_quirk *q;
+-      unsigned int i;
+-      size_t vs, ps;
+-
+-      vs = sfp_strlen(id->base.vendor_name, ARRAY_SIZE(id->base.vendor_name));
+-      ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn));
+-
+-      for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++)
+-              if (sfp_match(q->vendor, id->base.vendor_name, vs) &&
+-                  sfp_match(q->part, id->base.vendor_pn, ps))
+-                      return q;
+-
+-      return NULL;
+-}
+-
+ /**
+  * sfp_parse_port() - Parse the EEPROM base ID, setting the port type
+  * @bus: a pointer to the &struct sfp_bus structure for the sfp module
+@@ -786,12 +693,13 @@ void sfp_link_down(struct sfp_bus *bus)
+ }
+ EXPORT_SYMBOL_GPL(sfp_link_down);
+-int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id)
++int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
++                    const struct sfp_quirk *quirk)
+ {
+       const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
+       int ret = 0;
+-      bus->sfp_quirk = sfp_lookup_quirk(id);
++      bus->sfp_quirk = quirk;
+       if (ops && ops->module_insert)
+               ret = ops->module_insert(bus->upstream, id);
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -252,6 +252,8 @@ struct sfp {
+       unsigned int module_t_start_up;
+       bool tx_fault_ignore;
++      const struct sfp_quirk *quirk;
++
+ #if IS_ENABLED(CONFIG_HWMON)
+       struct sfp_diag diag;
+       struct delayed_work hwmon_probe;
+@@ -308,6 +310,93 @@ static const struct of_device_id sfp_of_
+ };
+ MODULE_DEVICE_TABLE(of, sfp_of_match);
++static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
++                              unsigned long *modes)
++{
++      linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, modes);
++}
++
++static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
++                                    unsigned long *modes)
++{
++      /* Ubiquiti U-Fiber Instant module claims that support all transceiver
++       * types including 10G Ethernet which is not truth. So clear all claimed
++       * modes and set only one mode which module supports: 1000baseX_Full.
++       */
++      linkmode_zero(modes);
++      linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, modes);
++}
++
++static const struct sfp_quirk sfp_quirks[] = {
++      {
++              // Alcatel Lucent G-010S-P can operate at 2500base-X, but
++              // incorrectly report 2500MBd NRZ in their EEPROM
++              .vendor = "ALCATELLUCENT",
++              .part = "G010SP",
++              .modes = sfp_quirk_2500basex,
++      }, {
++              // Alcatel Lucent G-010S-A can operate at 2500base-X, but
++              // report 3.2GBd NRZ in their EEPROM
++              .vendor = "ALCATELLUCENT",
++              .part = "3FE46541AA",
++              .modes = sfp_quirk_2500basex,
++      }, {
++              // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd
++              // NRZ in their EEPROM
++              .vendor = "HUAWEI",
++              .part = "MA5671A",
++              .modes = sfp_quirk_2500basex,
++      }, {
++              // Lantech 8330-262D-E can operate at 2500base-X, but
++              // incorrectly report 2500MBd NRZ in their EEPROM
++              .vendor = "Lantech",
++              .part = "8330-262D-E",
++              .modes = sfp_quirk_2500basex,
++      }, {
++              .vendor = "UBNT",
++              .part = "UF-INSTANT",
++              .modes = sfp_quirk_ubnt_uf_instant,
++      },
++};
++
++static size_t sfp_strlen(const char *str, size_t maxlen)
++{
++      size_t size, i;
++
++      /* Trailing characters should be filled with space chars */
++      for (i = 0, size = 0; i < maxlen; i++)
++              if (str[i] != ' ')
++                      size = i + 1;
++
++      return size;
++}
++
++static bool sfp_match(const char *qs, const char *str, size_t len)
++{
++      if (!qs)
++              return true;
++      if (strlen(qs) != len)
++              return false;
++      return !strncmp(qs, str, len);
++}
++
++static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
++{
++      const struct sfp_quirk *q;
++      unsigned int i;
++      size_t vs, ps;
++
++      vs = sfp_strlen(id->base.vendor_name, ARRAY_SIZE(id->base.vendor_name));
++      ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn));
++
++      for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++)
++              if (sfp_match(q->vendor, id->base.vendor_name, vs) &&
++                  sfp_match(q->part, id->base.vendor_pn, ps))
++                      return q;
++
++      return NULL;
++}
++
+ static unsigned long poll_jiffies;
+ static unsigned int sfp_gpio_get_state(struct sfp *sfp)
+@@ -1952,6 +2041,8 @@ static int sfp_sm_mod_probe(struct sfp *
+       else
+               sfp->tx_fault_ignore = false;
++      sfp->quirk = sfp_lookup_quirk(&id);
++
+       return 0;
+ }
+@@ -2063,7 +2154,8 @@ static void sfp_sm_module(struct sfp *sf
+                       break;
+               /* Report the module insertion to the upstream device */
+-              err = sfp_module_insert(sfp->sfp_bus, &sfp->id);
++              err = sfp_module_insert(sfp->sfp_bus, &sfp->id,
++                                      sfp->quirk);
+               if (err < 0) {
+                       sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
+                       break;
+--- a/drivers/net/phy/sfp.h
++++ b/drivers/net/phy/sfp.h
+@@ -6,6 +6,12 @@
+ struct sfp;
++struct sfp_quirk {
++      const char *vendor;
++      const char *part;
++      void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes);
++};
++
+ struct sfp_socket_ops {
+       void (*attach)(struct sfp *sfp);
+       void (*detach)(struct sfp *sfp);
+@@ -23,7 +29,8 @@ int sfp_add_phy(struct sfp_bus *bus, str
+ void sfp_remove_phy(struct sfp_bus *bus);
+ void sfp_link_up(struct sfp_bus *bus);
+ void sfp_link_down(struct sfp_bus *bus);
+-int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
++int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
++                    const struct sfp_quirk *quirk);
+ void sfp_module_remove(struct sfp_bus *bus);
+ int sfp_module_start(struct sfp_bus *bus);
+ void sfp_module_stop(struct sfp_bus *bus);
diff --git a/target/linux/generic/pending-5.15/771-net-sfp-move-Alcatel-Lucent-3FE46541AA-fixup.patch b/target/linux/generic/pending-5.15/771-net-sfp-move-Alcatel-Lucent-3FE46541AA-fixup.patch
new file mode 100644 (file)
index 0000000..f285561
--- /dev/null
@@ -0,0 +1,68 @@
+From 21fdd8281de3022aee35dd5bfccc892bd46529a3 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 26 Aug 2022 08:43:35 +0100
+Subject: [PATCH 2/6] net: sfp: move Alcatel Lucent 3FE46541AA fixup
+
+Add a new fixup mechanism to the SFP quirks, and use it for this
+module.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 14 +++++++++-----
+ drivers/net/phy/sfp.h |  1 +
+ 2 files changed, 10 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -310,6 +310,11 @@ static const struct of_device_id sfp_of_
+ };
+ MODULE_DEVICE_TABLE(of, sfp_of_match);
++static void sfp_fixup_long_startup(struct sfp *sfp)
++{
++      sfp->module_t_start_up = T_START_UP_BAD_GPON;
++}
++
+ static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
+                               unsigned long *modes)
+ {
+@@ -340,6 +345,7 @@ static const struct sfp_quirk sfp_quirks
+               .vendor = "ALCATELLUCENT",
+               .part = "3FE46541AA",
+               .modes = sfp_quirk_2500basex,
++              .fixup = sfp_fixup_long_startup,
+       }, {
+               // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd
+               // NRZ in their EEPROM
+@@ -2029,11 +2035,7 @@ static int sfp_sm_mod_probe(struct sfp *
+       if (ret < 0)
+               return ret;
+-      if (!memcmp(id.base.vendor_name, "ALCATELLUCENT   ", 16) &&
+-          !memcmp(id.base.vendor_pn, "3FE46541AA      ", 16))
+-              sfp->module_t_start_up = T_START_UP_BAD_GPON;
+-      else
+-              sfp->module_t_start_up = T_START_UP;
++      sfp->module_t_start_up = T_START_UP;
+       if (!memcmp(id.base.vendor_name, "HUAWEI          ", 16) &&
+           !memcmp(id.base.vendor_pn, "MA5671A         ", 16))
+@@ -2042,6 +2044,8 @@ static int sfp_sm_mod_probe(struct sfp *
+               sfp->tx_fault_ignore = false;
+       sfp->quirk = sfp_lookup_quirk(&id);
++      if (sfp->quirk && sfp->quirk->fixup)
++              sfp->quirk->fixup(sfp);
+       return 0;
+ }
+--- a/drivers/net/phy/sfp.h
++++ b/drivers/net/phy/sfp.h
+@@ -10,6 +10,7 @@ struct sfp_quirk {
+       const char *vendor;
+       const char *part;
+       void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes);
++      void (*fixup)(struct sfp *sfp);
+ };
+ struct sfp_socket_ops {
diff --git a/target/linux/generic/pending-5.15/772-net-sfp-move-Huawei-MA5671A-fixup.patch b/target/linux/generic/pending-5.15/772-net-sfp-move-Huawei-MA5671A-fixup.patch
new file mode 100644 (file)
index 0000000..dfd08af
--- /dev/null
@@ -0,0 +1,47 @@
+From 4c9d8c654827ef42da702c5b6c3392e8ac0bc60a Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 26 Aug 2022 08:43:40 +0100
+Subject: [PATCH 3/6] net: sfp: move Huawei MA5671A fixup
+
+Move this module over to the new fixup mechanism.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -315,6 +315,11 @@ static void sfp_fixup_long_startup(struc
+       sfp->module_t_start_up = T_START_UP_BAD_GPON;
+ }
++static void sfp_fixup_ignore_tx_fault(struct sfp *sfp)
++{
++      sfp->tx_fault_ignore = true;
++}
++
+ static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
+                               unsigned long *modes)
+ {
+@@ -352,6 +357,7 @@ static const struct sfp_quirk sfp_quirks
+               .vendor = "HUAWEI",
+               .part = "MA5671A",
+               .modes = sfp_quirk_2500basex,
++              .fixup = sfp_fixup_ignore_tx_fault,
+       }, {
+               // Lantech 8330-262D-E can operate at 2500base-X, but
+               // incorrectly report 2500MBd NRZ in their EEPROM
+@@ -2037,11 +2043,7 @@ static int sfp_sm_mod_probe(struct sfp *
+       sfp->module_t_start_up = T_START_UP;
+-      if (!memcmp(id.base.vendor_name, "HUAWEI          ", 16) &&
+-          !memcmp(id.base.vendor_pn, "MA5671A         ", 16))
+-              sfp->tx_fault_ignore = true;
+-      else
+-              sfp->tx_fault_ignore = false;
++      sfp->tx_fault_ignore = false;
+       sfp->quirk = sfp_lookup_quirk(&id);
+       if (sfp->quirk && sfp->quirk->fixup)
diff --git a/target/linux/generic/pending-5.15/773-net-sfp-add-support-for-HALNy-GPON-SFP.patch b/target/linux/generic/pending-5.15/773-net-sfp-add-support-for-HALNy-GPON-SFP.patch
new file mode 100644 (file)
index 0000000..9ec4781
--- /dev/null
@@ -0,0 +1,86 @@
+From 43ac680124bc57951a6d0356b41498c2324388bf Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 26 Aug 2022 08:43:45 +0100
+Subject: [PATCH 4/6] net: sfp: add support for HALNy GPON SFP
+
+Add a quirk for the HALNy HL-GSFP module, which appears to have an
+inverted RX_LOS signal, and possibly uses TX_FAULT as an inverted
+host-link status signal. As we can't be certain about the modules
+use of TX_FAULT, we ignore it.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp-bus.c |  2 +-
+ drivers/net/phy/sfp.c     | 29 ++++++++++++++++++++++++++---
+ 2 files changed, 27 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -283,7 +283,7 @@ void sfp_parse_support(struct sfp_bus *b
+                       phylink_set(modes, 2500baseX_Full);
+       }
+-      if (bus->sfp_quirk)
++      if (bus->sfp_quirk && bus->sfp_quirk->modes)
+               bus->sfp_quirk->modes(id, modes);
+       bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS);
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -320,6 +320,23 @@ static void sfp_fixup_ignore_tx_fault(st
+       sfp->tx_fault_ignore = true;
+ }
++static void sfp_fixup_inverted_los(struct sfp *sfp)
++{
++      const __be16 los_inverted = cpu_to_be16(SFP_OPTIONS_LOS_INVERTED);
++      const __be16 los_normal = cpu_to_be16(SFP_OPTIONS_LOS_NORMAL);
++
++      sfp->id.ext.options &= ~los_normal;
++      sfp->id.ext.options |= los_inverted;
++}
++
++static void sfp_fixup_halny_gsfp(struct sfp *sfp)
++{
++      /* LOS is inverted */
++      sfp_fixup_inverted_los(sfp);
++      /* TX fault might be inverted, but we don't know for certain. */
++      sfp_fixup_ignore_tx_fault(sfp);
++}
++
+ static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
+                               unsigned long *modes)
+ {
+@@ -352,6 +369,10 @@ static const struct sfp_quirk sfp_quirks
+               .modes = sfp_quirk_2500basex,
+               .fixup = sfp_fixup_long_startup,
+       }, {
++              .vendor = "HALNy",
++              .part = "HL-GSFP",
++              .fixup = sfp_fixup_halny_gsfp,
++      }, {
+               // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd
+               // NRZ in their EEPROM
+               .vendor = "HUAWEI",
+@@ -368,16 +389,18 @@ static const struct sfp_quirk sfp_quirks
+               .vendor = "UBNT",
+               .part = "UF-INSTANT",
+               .modes = sfp_quirk_ubnt_uf_instant,
+-      },
++      }
+ };
+ static size_t sfp_strlen(const char *str, size_t maxlen)
+ {
+       size_t size, i;
+-      /* Trailing characters should be filled with space chars */
++      /* Trailing characters should be filled with space chars, but
++       * some manufacturers can't read SFF-8472 and use NUL.
++       */
+       for (i = 0, size = 0; i < maxlen; i++)
+-              if (str[i] != ' ')
++              if (str[i] != ' ' && str[i] != '\0')
+                       size = i + 1;
+       return size;
diff --git a/target/linux/generic/pending-5.15/774--net-sfp-redo-soft-state-polling.patch b/target/linux/generic/pending-5.15/774--net-sfp-redo-soft-state-polling.patch
new file mode 100644 (file)
index 0000000..3aa51de
--- /dev/null
@@ -0,0 +1,79 @@
+From 9a84d699ddde0d4e272aa919ad8fd50271a3f932 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 26 Aug 2022 08:48:20 +0100
+Subject: [PATCH 5/6] net: sfp: redo soft state polling
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 35 ++++++++++++++++++++++++-----------
+ 1 file changed, 24 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -234,6 +234,7 @@ struct sfp {
+       bool need_poll;
+       struct mutex st_mutex;                  /* Protects state */
++      unsigned int state_ignore_hw_mask;
+       unsigned int state_soft_mask;
+       unsigned int state;
+       struct delayed_work poll;
+@@ -623,17 +624,18 @@ static void sfp_soft_set_state(struct sf
+ static void sfp_soft_start_poll(struct sfp *sfp)
+ {
+       const struct sfp_eeprom_id *id = &sfp->id;
++      unsigned int mask = 0;
+       sfp->state_soft_mask = 0;
+-      if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE &&
+-          !sfp->gpio[GPIO_TX_DISABLE])
+-              sfp->state_soft_mask |= SFP_F_TX_DISABLE;
+-      if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT &&
+-          !sfp->gpio[GPIO_TX_FAULT])
+-              sfp->state_soft_mask |= SFP_F_TX_FAULT;
+-      if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS &&
+-          !sfp->gpio[GPIO_LOS])
+-              sfp->state_soft_mask |= SFP_F_LOS;
++      if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE)
++              mask |= SFP_F_TX_DISABLE;
++      if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT)
++              mask |= SFP_F_TX_FAULT;
++      if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS)
++              mask |= SFP_F_LOS;
++
++      // Poll the soft state for hardware pins we want to ignore
++      sfp->state_soft_mask = sfp->state_ignore_hw_mask & mask;
+       if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
+           !sfp->need_poll)
+@@ -647,10 +649,12 @@ static void sfp_soft_stop_poll(struct sf
+ static unsigned int sfp_get_state(struct sfp *sfp)
+ {
++      unsigned int soft = sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT);
+       unsigned int state = sfp->get_state(sfp);
+-      if (state & SFP_F_PRESENT &&
+-          sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT))
++      state &= ~sfp->state_ignore_hw_mask;
++
++      if (state & SFP_F_PRESENT && soft)
+               state |= sfp_soft_get_state(sfp);
+       return state;
+@@ -2064,6 +2068,15 @@ static int sfp_sm_mod_probe(struct sfp *
+       if (ret < 0)
+               return ret;
++      /* Initialise state bits to ignore from hardware */
++      sfp->state_ignore_hw_mask = 0;
++      if (!sfp->gpio[GPIO_TX_DISABLE])
++              sfp->state_ignore_hw_mask |= SFP_F_TX_DISABLE;
++      if (!sfp->gpio[GPIO_TX_FAULT])
++              sfp->state_ignore_hw_mask |= SFP_F_TX_FAULT;
++      if (!sfp->gpio[GPIO_LOS])
++              sfp->state_ignore_hw_mask |= SFP_F_LOS;
++
+       sfp->module_t_start_up = T_START_UP;
+       sfp->tx_fault_ignore = false;
diff --git a/target/linux/generic/pending-5.15/775-net-sfp-change-HALNy-to-ignore-hardware-pins.patch b/target/linux/generic/pending-5.15/775-net-sfp-change-HALNy-to-ignore-hardware-pins.patch
new file mode 100644 (file)
index 0000000..7aa29cd
--- /dev/null
@@ -0,0 +1,35 @@
+From 32a59a1c5dc8f6fa755bab9a5f9751fdb66bb234 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 26 Aug 2022 08:48:25 +0100
+Subject: [PATCH 6/6] net: sfp: change HALNy to ignore hardware pins
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 14 +-------------
+ 1 file changed, 1 insertion(+), 13 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -321,21 +321,9 @@ static void sfp_fixup_ignore_tx_fault(st
+       sfp->tx_fault_ignore = true;
+ }
+-static void sfp_fixup_inverted_los(struct sfp *sfp)
+-{
+-      const __be16 los_inverted = cpu_to_be16(SFP_OPTIONS_LOS_INVERTED);
+-      const __be16 los_normal = cpu_to_be16(SFP_OPTIONS_LOS_NORMAL);
+-
+-      sfp->id.ext.options &= ~los_normal;
+-      sfp->id.ext.options |= los_inverted;
+-}
+-
+ static void sfp_fixup_halny_gsfp(struct sfp *sfp)
+ {
+-      /* LOS is inverted */
+-      sfp_fixup_inverted_los(sfp);
+-      /* TX fault might be inverted, but we don't know for certain. */
+-      sfp_fixup_ignore_tx_fault(sfp);
++      sfp->state_ignore_hw_mask |= SFP_F_TX_FAULT | SFP_F_LOS;
+ }
+ static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,