igb: Fix for DH89xxCC near end loopback test
Robert Healy [Tue, 12 Jul 2011 08:46:20 +0000 (08:46 +0000)]
On this chipset it is required to configure the MPHY block for loopback tests. If MPHY is not configured then all loopback tests will report failures.

Signed-off-by: Robert Healy <robert.healy@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>

drivers/net/igb/e1000_defines.h
drivers/net/igb/igb_ethtool.c

index 2cd4082..7b8ddd8 100644 (file)
 #define E1000_GCR_CMPL_TMOUT_RESEND     0x00010000
 #define E1000_GCR_CAP_VER2              0x00040000
 
+/* mPHY Address Control and Data Registers */
+#define E1000_MPHY_ADDR_CTL          0x0024 /* mPHY Address Control Register */
+#define E1000_MPHY_ADDR_CTL_OFFSET_MASK 0xFFFF0000
+#define E1000_MPHY_DATA                 0x0E10 /* mPHY Data Register */
+
+/* mPHY PCS CLK Register */
+#define E1000_MPHY_PCS_CLK_REG_OFFSET  0x0004 /* mPHY PCS CLK AFE CSR Offset */
+/* mPHY Near End Digital Loopback Override Bit */
+#define E1000_MPHY_PCS_CLK_REG_DIGINELBEN 0x10
+
 /* PHY Control Register */
 #define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
 #define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
index ed63ff4..ff244ce 100644 (file)
@@ -1461,6 +1461,22 @@ static int igb_setup_loopback_test(struct igb_adapter *adapter)
 
        /* use CTRL_EXT to identify link type as SGMII can appear as copper */
        if (reg & E1000_CTRL_EXT_LINK_MODE_MASK) {
+               if ((hw->device_id == E1000_DEV_ID_DH89XXCC_SGMII) ||
+               (hw->device_id == E1000_DEV_ID_DH89XXCC_SERDES) ||
+               (hw->device_id == E1000_DEV_ID_DH89XXCC_BACKPLANE) ||
+               (hw->device_id == E1000_DEV_ID_DH89XXCC_SFP)) {
+
+                       /* Enable DH89xxCC MPHY for near end loopback */
+                       reg = rd32(E1000_MPHY_ADDR_CTL);
+                       reg = (reg & E1000_MPHY_ADDR_CTL_OFFSET_MASK) |
+                       E1000_MPHY_PCS_CLK_REG_OFFSET;
+                       wr32(E1000_MPHY_ADDR_CTL, reg);
+
+                       reg = rd32(E1000_MPHY_DATA);
+                       reg |= E1000_MPHY_PCS_CLK_REG_DIGINELBEN;
+                       wr32(E1000_MPHY_DATA, reg);
+               }
+
                reg = rd32(E1000_RCTL);
                reg |= E1000_RCTL_LBM_TCVR;
                wr32(E1000_RCTL, reg);
@@ -1502,6 +1518,23 @@ static void igb_loopback_cleanup(struct igb_adapter *adapter)
        u32 rctl;
        u16 phy_reg;
 
+       if ((hw->device_id == E1000_DEV_ID_DH89XXCC_SGMII) ||
+       (hw->device_id == E1000_DEV_ID_DH89XXCC_SERDES) ||
+       (hw->device_id == E1000_DEV_ID_DH89XXCC_BACKPLANE) ||
+       (hw->device_id == E1000_DEV_ID_DH89XXCC_SFP)) {
+               u32 reg;
+
+               /* Disable near end loopback on DH89xxCC */
+               reg = rd32(E1000_MPHY_ADDR_CTL);
+               reg = (reg & E1000_MPHY_ADDR_CTL_OFFSET_MASK) |
+               E1000_MPHY_PCS_CLK_REG_OFFSET;
+               wr32(E1000_MPHY_ADDR_CTL, reg);
+
+               reg = rd32(E1000_MPHY_DATA);
+               reg &= ~E1000_MPHY_PCS_CLK_REG_DIGINELBEN;
+               wr32(E1000_MPHY_DATA, reg);
+       }
+
        rctl = rd32(E1000_RCTL);
        rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
        wr32(E1000_RCTL, rctl);