net: sfp: cope with SFPs that set both LOS normal and LOS inverted
Subsystems (4)
PATCH 1/1 net: sfp: cope with SFPs that set both LOS normal and LOS inverted
From: Russell King <[email protected]>
[ Upstream commit 624407d2cf14ff58e53bf4b2af9595c4f21d606e ]
The SFP MSA defines two option bits in byte 65 to indicate how the Rx_LOS signal on SFP pin 8 behaves:
bit 2 - Loss of Signal implemented, signal inverted from standard
definition in SFP MSA (often called "Signal Detect").
bit 1 - Loss of Signal implemented, signal as defined in SFP MSA
(often called "Rx_LOS").
Clearly, setting both bits results in a meaningless situation: it would mean that LOS is implemented in both the normal sense (1 = signal loss) and inverted sense (0 = signal loss).
Unfortunately, there are modules out there which set both bits, which will be initially interpret as "inverted" sense, and then, if the LOS signal changes state, we will toggle between LINK_UP and WAIT_LOS states.
Change our LOS handling to give well defined behaviour: only interpret these bits as meaningful if exactly one is set, otherwise treat it as if LOS is not implemented.
---
Please apply this commit to all stable releases where was already backported commit f0b4f847673299577c29b71d3f3acd3c313d81b7 ("net: sfp: add mode quirk for GPON module Ubiquiti U-Fiber Instant") as it depends on this commit. The Ubiquiti U-Fiber Instant SFP GPON module has set both LOS_NORMAL and LOS_INVERTED bits so without this commit it does not work. If I checked it correctly patch should go into 5.10 and 5.11 releases.
--- drivers/net/phy/sfp.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-)
drivers/net/phy/sfp.c +22 -14
@@ -1482,15 +1482,19 @@ static void sfp_sm_link_down(struct sfp *sfp)static void sfp_sm_link_check_los (struct sfp *sfp) { -unsigned int los = sfp->state &SFP_F_LOS ; +const __be16 los_inverted =cpu_to_be16 (SFP_OPTIONS_LOS_INVERTED ); +const __be16 los_normal =cpu_to_be16 (SFP_OPTIONS_LOS_NORMAL ); +__be16 los_options = sfp->id.ext.options & (los_inverted | los_normal); +bool los = false;/* If neither SFP_OPTIONS_LOS_INVERTED nor SFP_OPTIONS_LOS_NORMAL -* are set, we assume that no LOS signal is available. +* are set, we assume that no LOS signal is available. If both are +* set, we assume LOS is not implemented (and is meaningless.) */ -if (sfp->id.ext.options &cpu_to_be16 (SFP_OPTIONS_LOS_INVERTED )) - los ^=SFP_F_LOS ; -else if (!(sfp->id.ext.options &cpu_to_be16 (SFP_OPTIONS_LOS_NORMAL ))) - los =0 ; +if (los_options == los_inverted) + los = !(sfp->state &SFP_F_LOS ); +else if (los_options == los_normal) + los = !!(sfp->state &SFP_F_LOS );if (los)sfp_sm_next (sfp,SFP_S_WAIT_LOS ,0 );
@@ -1500,18 +1504,22 @@ static void sfp_sm_link_check_los(struct sfp *sfp)static bool sfp_los_event_active (struct sfp *sfp,unsigned int event) { -return (sfp->id.ext.options &cpu_to_be16 (SFP_OPTIONS_LOS_INVERTED ) && - event ==SFP_E_LOS_LOW ) || - (sfp->id.ext.options &cpu_to_be16 (SFP_OPTIONS_LOS_NORMAL ) && - event ==SFP_E_LOS_HIGH ); +const __be16 los_inverted =cpu_to_be16 (SFP_OPTIONS_LOS_INVERTED ); +const __be16 los_normal =cpu_to_be16 (SFP_OPTIONS_LOS_NORMAL ); +__be16 los_options = sfp->id.ext.options & (los_inverted | los_normal); + +return (los_options == los_inverted && event ==SFP_E_LOS_LOW ) || + (los_options == los_normal && event ==SFP_E_LOS_HIGH ); }static bool sfp_los_event_inactive (struct sfp *sfp,unsigned int event) { -return (sfp->id.ext.options &cpu_to_be16 (SFP_OPTIONS_LOS_INVERTED ) && - event ==SFP_E_LOS_HIGH ) || - (sfp->id.ext.options &cpu_to_be16 (SFP_OPTIONS_LOS_NORMAL ) && - event ==SFP_E_LOS_LOW ); +const __be16 los_inverted =cpu_to_be16 (SFP_OPTIONS_LOS_INVERTED ); +const __be16 los_normal =cpu_to_be16 (SFP_OPTIONS_LOS_NORMAL ); +__be16 los_options = sfp->id.ext.options & (los_inverted | los_normal); + +return (los_options == los_inverted && event ==SFP_E_LOS_HIGH ) || + (los_options == los_normal && event ==SFP_E_LOS_LOW ); }static void sfp_sm_fault (struct sfp *sfp,unsigned int next_state,bool warn)
Signature · 1 line
2.20.1
Quoted 37 lines · Pali Rohár
From: Russell King <[email protected]>
[ Upstream commit
624407d2cf14ff58e53bf4b2af9595c4f21d606e]The SFP MSA defines two option bits in byte 65 to indicate how the
Rx_LOSsignal on SFP pin 8 behaves:bit 2 - Loss of Signal implemented, signal inverted from standard
definition in SFP MSA (often called "Signal Detect").
bit 1 - Loss of Signal implemented, signal as defined in SFP MSA
(often called "Rx_LOS").Clearly, setting both bits results in a meaningless situation: it would mean that LOS is implemented in both the normal sense (1 = signal loss) and inverted sense (0 = signal loss).
Unfortunately, there are modules out there which set both bits, which will be initially interpret as "inverted" sense, and then, if the LOS signal changes state, we will toggle between
LINK_UPandWAIT_LOSstates.Change our LOS handling to give well defined behaviour: only interpret these bits as meaningful if exactly one is set, otherwise treat it as if LOS is not implemented.
Signed-off-by Russell King <[email protected]>Reviewed-by Andrew Lunn <[email protected]>Signed-off-by Jakub Kicinski <[email protected]>---
Please apply this commit to all stable releases where was already backported commitf0b4f847673299577c29b71d3f3acd3c313d81b7("net: sfp: add mode quirk for GPON module Ubiquiti U-Fiber Instant") as it depends on this commit. The Ubiquiti U-Fiber Instant SFP GPON module has set bothLOS_NORMALandLOS_INVERTEDbits so without this commit it does not work. If I checked it correctly patch should go into 5.10 and 5.11 releases.
Quoted 3 lines
--- drivers/net/phy/sfp.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-)
Now queued up, thanks.
greg k-h