Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9c76f99 authored by Bruce Allan's avatar Bruce Allan Committed by Jeff Kirsher
Browse files

e1000e: 82571 Serdes can fail to get link



When link partner is sending continuous Config symbols, the 82571 Serdes
FIFO can overflow resulting in Invalid bit getting set.  To resolve this,
if Sync and Config bits are both 1 ignore the Invalid bit and restart
auto-negotiation.

Signed-off-by: default avatarBruce Allan <bruce.w.allan@intel.com>
Tested-by: default avatarEmil Tantilov <emil.s.tantilov@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent cbd006cb
Loading
Loading
Loading
Loading
+27 −8
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@
			      (ID_LED_DEF1_DEF2))

#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
#define AN_RETRY_COUNT          5 /* Autoneg Retry Count value */
#define E1000_BASE1000T_STATUS          10
#define E1000_IDLE_ERROR_COUNT_MASK     0xFF
#define E1000_RECEIVE_ERROR_COUNTER     21
@@ -1503,6 +1504,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
	u32 rxcw;
	u32 ctrl;
	u32 status;
	u32 txcw;
	u32 i;
	s32 ret_val = 0;

	ctrl = er32(CTRL);
@@ -1613,16 +1616,32 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
			e_dbg("ANYSTATE  -> DOWN\n");
		} else {
			/*
			 * We have sync, and can tolerate one invalid (IV)
			 * codeword before declaring link down, so reread
			 * to look again.
			 * Check several times, if Sync and Config
			 * both are consistently 1 then simply ignore
			 * the Invalid bit and restart Autoneg
			 */
			for (i = 0; i < AN_RETRY_COUNT; i++) {
				udelay(10);
				rxcw = er32(RXCW);
			if (rxcw & E1000_RXCW_IV) {
				mac->serdes_link_state = e1000_serdes_link_down;
				if ((rxcw & E1000_RXCW_IV) &&
				    !((rxcw & E1000_RXCW_SYNCH) &&
				      (rxcw & E1000_RXCW_C))) {
					mac->serdes_has_link = false;
					mac->serdes_link_state =
					    e1000_serdes_link_down;
					e_dbg("ANYSTATE  -> DOWN\n");
					break;
				}
			}

			if (i == AN_RETRY_COUNT) {
				txcw = er32(TXCW);
				txcw |= E1000_TXCW_ANE;
				ew32(TXCW, txcw);
				mac->serdes_link_state =
				    e1000_serdes_link_autoneg_progress;
				mac->serdes_has_link = false;
				e_dbg("ANYSTATE  -> AN_PROG\n");
			}
		}
	}