aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2017-11-30 08:59:16 -0500
committerDavid S. Miller <davem@davemloft.net>2017-12-01 15:18:42 -0500
commit710dfbb01a8ac0fc8d0cc191131bd84dc3796497 (patch)
treef222b7ac19317e981b325d0c8fdc53fb543b9039
parentacf1c02f023926b8b04672a9e81b1711ae681619 (diff)
sfp: improve RX_LOS handling
There are two bits in the option word for the RX_LOS signal. One reports that the RX_LOS signal is active high, the other reports that it is active low. When both or neither are set, the result is not well defined in the specification. Rather than assuming that neither set means normal RX_LOS, take this as meaning no RX_LOS signal available, thereby ignoring the signal. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/phy/sfp.c33
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 3355141688a6..c1aab6a81ce9 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -351,12 +351,13 @@ static void sfp_sm_link_check_los(struct sfp *sfp)
351{ 351{
352 unsigned int los = sfp->state & SFP_F_LOS; 352 unsigned int los = sfp->state & SFP_F_LOS;
353 353
354 /* FIXME: what if neither SFP_OPTIONS_LOS_INVERTED nor 354 /* If neither SFP_OPTIONS_LOS_INVERTED nor SFP_OPTIONS_LOS_NORMAL
355 * SFP_OPTIONS_LOS_NORMAL are set? For now, we assume 355 * are set, we assume that no LOS signal is available.
356 * the same as SFP_OPTIONS_LOS_NORMAL set.
357 */ 356 */
358 if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_INVERTED)) 357 if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_INVERTED))
359 los ^= SFP_F_LOS; 358 los ^= SFP_F_LOS;
359 else if (!(sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_NORMAL)))
360 los = 0;
360 361
361 if (los) 362 if (los)
362 sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0); 363 sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0);
@@ -364,6 +365,22 @@ static void sfp_sm_link_check_los(struct sfp *sfp)
364 sfp_sm_link_up(sfp); 365 sfp_sm_link_up(sfp);
365} 366}
366 367
368static bool sfp_los_event_active(struct sfp *sfp, unsigned int event)
369{
370 return (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_INVERTED) &&
371 event == SFP_E_LOS_LOW) ||
372 (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_NORMAL) &&
373 event == SFP_E_LOS_HIGH);
374}
375
376static bool sfp_los_event_inactive(struct sfp *sfp, unsigned int event)
377{
378 return (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_INVERTED) &&
379 event == SFP_E_LOS_HIGH) ||
380 (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_LOS_NORMAL) &&
381 event == SFP_E_LOS_LOW);
382}
383
367static void sfp_sm_fault(struct sfp *sfp, bool warn) 384static void sfp_sm_fault(struct sfp *sfp, bool warn)
368{ 385{
369 if (sfp->sm_retries && !--sfp->sm_retries) { 386 if (sfp->sm_retries && !--sfp->sm_retries) {
@@ -581,10 +598,7 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event)
581 case SFP_S_WAIT_LOS: 598 case SFP_S_WAIT_LOS:
582 if (event == SFP_E_TX_FAULT) 599 if (event == SFP_E_TX_FAULT)
583 sfp_sm_fault(sfp, true); 600 sfp_sm_fault(sfp, true);
584 else if (event == 601 else if (sfp_los_event_inactive(sfp, event))
585 (sfp->id.ext.options &
586 cpu_to_be16(SFP_OPTIONS_LOS_INVERTED) ?
587 SFP_E_LOS_HIGH : SFP_E_LOS_LOW))
588 sfp_sm_link_up(sfp); 602 sfp_sm_link_up(sfp);
589 break; 603 break;
590 604
@@ -592,10 +606,7 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event)
592 if (event == SFP_E_TX_FAULT) { 606 if (event == SFP_E_TX_FAULT) {
593 sfp_sm_link_down(sfp); 607 sfp_sm_link_down(sfp);
594 sfp_sm_fault(sfp, true); 608 sfp_sm_fault(sfp, true);
595 } else if (event == 609 } else if (sfp_los_event_active(sfp, event)) {
596 (sfp->id.ext.options &
597 cpu_to_be16(SFP_OPTIONS_LOS_INVERTED) ?
598 SFP_E_LOS_LOW : SFP_E_LOS_HIGH)) {
599 sfp_sm_link_down(sfp); 610 sfp_sm_link_down(sfp);
600 sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0); 611 sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0);
601 } 612 }