The ZYXEL PMG3000-D20B GPON SFP module reports LOS and TX_FAULT in a way that prevents the SFP state machine from initialising it. Its EEPROM also advertises autonegotiation support although the module does not implement it, and the module needs about 60 seconds before it is ready. Ignore LOS and TX_FAULT, disable the advertised autonegotiation and use T_START_UP_BAD_GPON as the wait time before the module is assumed to be initialised. Tested with a ZYXEL PMG3000-D20B in an SFP cage. Signed-off-by: Martin Ostertag --- v2: - add sfp_fixup_long_wait() helper and use it instead of assigning module_t_wait directly - document why module_t_start_up cannot be used for this module v1: https://lore.kernel.org/netdev/20261026135757.100139-1-martin.ostertag@gmx.de/ drivers/net/phy/sfp.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 85e57a1..fd10b85 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -371,6 +371,17 @@ static void sfp_fixup_long_startup(struct sfp *sfp) sfp->module_t_start_up = T_START_UP_BAD_GPON; } +/* + * Some modules need a long time before they are ready, but keep + * TX_FAULT asserted. As TX_FAULT is ignored for those modules, + * module_t_start_up is not evaluated by the state machine, so use + * module_t_wait instead. + */ +static void sfp_fixup_long_wait(struct sfp *sfp) +{ + sfp->module_t_wait = T_START_UP_BAD_GPON; +} + static void sfp_fixup_ignore_los(struct sfp *sfp) { /* This forces LOS to zero, so we ignore transitions */ @@ -472,6 +483,13 @@ static void sfp_fixup_potron(struct sfp *sfp) sfp_fixup_ignore_hw(sfp, SFP_F_TX_FAULT | SFP_F_LOS); } +static void sfp_fixup_zyxel(struct sfp *sfp) +{ + /* The LOS and TX_FAULT signals are not usable on this module. */ + sfp_fixup_ignore_tx_fault_and_los(sfp); + sfp_fixup_long_wait(sfp); +} + static void sfp_fixup_rollball_cc(struct sfp *sfp) { sfp_fixup_rollball(sfp); @@ -654,6 +672,10 @@ static const struct sfp_quirk sfp_quirks[] = { SFP_QUIRK_F("XikeStor", "SKT-2.5G-100M", sfp_fixup_xikestor_2_5g), SFP_QUIRK_S("ZOERAX", "SFP-2.5G-T", sfp_quirk_oem_2_5g), + + /* The module advertises autonegotiation it does not support. */ + SFP_QUIRK("ZYXEL", "PMG3000-D20B", sfp_quirk_disable_autoneg, + sfp_fixup_zyxel), }; static size_t sfp_strlen(const char *str, size_t maxlen) -- 2.56.0