📄 e1000_ethtool.c
字号:
phy_reg |= MII_CR_LOOPBACK; e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, phy_reg); /* Setup TX_CLK and TX_CRS one more time. */ e1000_phy_reset_clk_and_crs(adapter); /* Check Phy Configuration */ e1000_read_phy_reg(&adapter->hw, PHY_CONTROL, &phy_reg); if (phy_reg != 0x4100) return 9; e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg); if (phy_reg != 0x0070) return 10; e1000_read_phy_reg(&adapter->hw, 29, &phy_reg); if (phy_reg != 0x001A) return 11; return 0;}static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter){ u32 ctrl_reg = 0; u32 stat_reg = 0; adapter->hw.mac.autoneg = FALSE; if (adapter->hw.phy.type == e1000_phy_m88) { /* Auto-MDI/MDIX Off */ e1000_write_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* reset to update Auto-MDI/MDIX */ e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, 0x9140); /* autoneg off */ e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, 0x8140); } else if (adapter->hw.phy.type == e1000_phy_gg82563) e1000_write_phy_reg(&adapter->hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC); ctrl_reg = E1000_READ_REG(&adapter->hw, E1000_CTRL); if (adapter->hw.phy.type == e1000_phy_ife) { /* force 100, set loopback */ e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, 0x6100); /* Now set up the MAC to the same speed/duplex as the PHY. */ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ E1000_CTRL_SPD_100 |/* Force Speed to 100 */ E1000_CTRL_FD); /* Force Duplex to FULL */ } else { /* force 1000, set loopback */ e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, 0x4140); /* Now set up the MAC to the same speed/duplex as the PHY. */ ctrl_reg = E1000_READ_REG(&adapter->hw, E1000_CTRL); ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ E1000_CTRL_FD); /* Force Duplex to FULL */ } if (adapter->hw.phy.media_type == e1000_media_type_copper && adapter->hw.phy.type == e1000_phy_m88) { ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ } else { /* Set the ILOS bit on the fiber Nic if half duplex link is * detected. */ stat_reg = E1000_READ_REG(&adapter->hw, E1000_STATUS); if ((stat_reg & E1000_STATUS_FD) == 0) ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); } E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl_reg); /* Disable the receiver on the PHY so when a cable is plugged in, the * PHY does not begin to autoneg when a cable is reconnected to the NIC. */ if (adapter->hw.phy.type == e1000_phy_m88) e1000_phy_disable_receiver(adapter); udelay(500); return 0;}static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw; u32 ctrl = E1000_READ_REG(hw, E1000_CTRL); int link = 0; /* special requirements for 82571/82572 fiber adapters */ /* jump through hoops to make sure link is up because serdes * link is hardwired up */ ctrl |= E1000_CTRL_SLU; E1000_WRITE_REG(hw, E1000_CTRL, ctrl); /* disable autoneg */ ctrl = E1000_READ_REG(hw, E1000_TXCW); ctrl &= ~(1 << 31); E1000_WRITE_REG(hw, E1000_TXCW, ctrl); link = (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU); if (!link) { /* set invert loss of signal */ ctrl = E1000_READ_REG(hw, E1000_CTRL); ctrl |= E1000_CTRL_ILOS; E1000_WRITE_REG(hw, E1000_CTRL, ctrl); } /* special write to serdes control register to enable SerDes analog * loopback */#define E1000_SERDES_LB_ON 0x410 E1000_WRITE_REG(hw, E1000_SCTL, E1000_SERDES_LB_ON); msleep(10); return 0;}static int e1000_set_phy_loopback(struct e1000_adapter *adapter){ u16 phy_reg = 0; u16 count = 0; switch (adapter->hw.mac.type) { case e1000_82543: if (adapter->hw.phy.media_type == e1000_media_type_copper) { /* Attempt to setup Loopback mode on Non-integrated PHY. * Some PHY registers get corrupted at random, so * attempt this 10 times. */ while (e1000_nonintegrated_phy_loopback(adapter) && count++ < 10); if (count < 11) return 0; } break; case e1000_82544: case e1000_82540: case e1000_82545: case e1000_82545_rev_3: case e1000_82546: case e1000_82546_rev_3: case e1000_82541: case e1000_82541_rev_2: case e1000_82547: case e1000_82547_rev_2: case e1000_82571: case e1000_82572: case e1000_82573: case e1000_80003es2lan: case e1000_ich8lan: case e1000_ich9lan: return e1000_integrated_phy_loopback(adapter); break; default: /* Default PHY loopback work is to read the MII * control register and assert bit 14 (loopback mode). */ e1000_read_phy_reg(&adapter->hw, PHY_CONTROL, &phy_reg); phy_reg |= MII_CR_LOOPBACK; e1000_write_phy_reg(&adapter->hw, PHY_CONTROL, phy_reg); return 0; break; } return 8;}/* only call this for fiber/serdes connections to es2lan */static int e1000_set_es2lan_mac_loopback(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw; u32 ctrlext = E1000_READ_REG(hw, E1000_CTRL_EXT); u32 ctrl = E1000_READ_REG(hw, E1000_CTRL); /* save CTRL_EXT to restore later, reuse an empty variable (unused on mac_type 80003es2lan) */ adapter->tx_fifo_head = ctrlext; /* clear the serdes mode bits, putting the device into mac loopback */ ctrlext &= ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrlext); /* force speed to 1000/FD, link up */ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SPD_1000 | E1000_CTRL_FD); E1000_WRITE_REG(hw, E1000_CTRL, ctrl); /* set mac loopback */ ctrl = E1000_READ_REG(hw, E1000_RCTL); ctrl |= E1000_RCTL_LBM_MAC; E1000_WRITE_REG(hw, E1000_RCTL, ctrl); /* set testing mode parameters (no need to reset later) */#define KMRNCTRLSTA_OPMODE (0x1F << 16)#define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582 E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, (KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII)); return 0;}static int e1000_setup_loopback_test(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw; u32 rctl; if (hw->phy.media_type == e1000_media_type_fiber || hw->phy.media_type == e1000_media_type_internal_serdes) { switch (hw->mac.type) { case e1000_80003es2lan: return e1000_set_es2lan_mac_loopback(adapter); break; case e1000_82545: case e1000_82546: case e1000_82545_rev_3: case e1000_82546_rev_3: return e1000_set_phy_loopback(adapter); break; case e1000_82571: case e1000_82572: return e1000_set_82571_fiber_loopback(adapter); break; default: rctl = E1000_READ_REG(hw, E1000_RCTL); rctl |= E1000_RCTL_LBM_TCVR; E1000_WRITE_REG(hw, E1000_RCTL, rctl); return 0; } } else if (hw->phy.media_type == e1000_media_type_copper) return e1000_set_phy_loopback(adapter); return 7;}static void e1000_loopback_cleanup(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw; u32 rctl; u16 phy_reg; rctl = E1000_READ_REG(hw, E1000_RCTL); rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); E1000_WRITE_REG(hw, E1000_RCTL, rctl); switch (hw->mac.type) { case e1000_80003es2lan: if (hw->phy.media_type == e1000_media_type_fiber || hw->phy.media_type == e1000_media_type_internal_serdes) { /* restore CTRL_EXT, stealing space from tx_fifo_head */ E1000_WRITE_REG(hw, E1000_CTRL_EXT, adapter->tx_fifo_head); adapter->tx_fifo_head = 0; } /* fall through */ case e1000_82571: case e1000_82572: if (hw->phy.media_type == e1000_media_type_fiber || hw->phy.media_type == e1000_media_type_internal_serdes) {#define E1000_SERDES_LB_OFF 0x400 E1000_WRITE_REG(hw, E1000_SCTL, E1000_SERDES_LB_OFF); msleep(10); break; } /* Fall Through */ case e1000_82545: case e1000_82546: case e1000_82545_rev_3: case e1000_82546_rev_3: default: hw->mac.autoneg = TRUE; if (hw->phy.type == e1000_phy_gg82563) e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x180); e1000_read_phy_reg(hw, PHY_CONTROL, &phy_reg); if (phy_reg & MII_CR_LOOPBACK) { phy_reg &= ~MII_CR_LOOPBACK; e1000_write_phy_reg(hw, PHY_CONTROL, phy_reg); e1000_phy_commit(hw); } break; }}static void e1000_create_lbtest_frame(struct sk_buff *skb, unsigned int frame_size){ memset(skb->data, 0xFF, frame_size); frame_size &= ~1; memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);}static int e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size){ frame_size &= ~1; if (*(skb->data + 3) == 0xFF) { if ((*(skb->data + frame_size / 2 + 10) == 0xBE) && (*(skb->data + frame_size / 2 + 12) == 0xAF)) { return 0; } } return 13;}static int e1000_run_loopback_test(struct e1000_adapter *adapter){ struct e1000_tx_ring *tx_ring = &adapter->test_tx_ring; struct e1000_rx_ring *rx_ring = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; int i, j, k, l, lc, good_cnt, ret_val=0; unsigned long time; E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), rx_ring->count - 1); /* Calculate the loop count based on the largest descriptor ring * The idea is to wrap the largest ring a number of times using 64 * send/receive pairs during each loop */ if (rx_ring->count <= tx_ring->count) lc = ((tx_ring->count / 64) * 2) + 1; else lc = ((rx_ring->count / 64) * 2) + 1; k = l = 0; for (j = 0; j <= lc; j++) { /* loop count loop */ for (i = 0; i < 64; i++) { /* send the packets */ e1000_create_lbtest_frame(tx_ring->buffer_info[k].skb, 1024); pci_dma_sync_single_for_device(pdev, tx_ring->buffer_info[k].dma, tx_ring->buffer_info[k].length, PCI_DMA_TODEVICE); if (unlikely(++k == tx_ring->count)) k = 0; } E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), k); msleep(200); time = jiffies; /* set the start time for the receive */ good_cnt = 0; do { /* receive the sent packets */ pci_dma_sync_single_for_cpu(pdev, rx_ring->buffer_info[l].dma, E1000_RXBUFFER_2048, PCI_DMA_FROMDEVICE); ret_val = e1000_check_lbtest_frame( rx_ring->buffer_info[l].skb, 1024); if (!ret_val) good_cnt++; if (unlikely(++l == rx_ring->count)) l = 0; /* time + 20 msecs (200 msecs on 2.4) is more than * enough time to complete the receives, if it's * exceeded, break and error off */ } while (good_cnt < 64 && jiffies < (time + 20)); if (good_cnt != 64) { ret_val = 13; /* ret_val is the same as mis-compare */ break; } if (jiffies >= (time + 20)) { ret_val = 14; /* error code for time out error */ break; } } /* end loop count loop */ return ret_val;}static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data){ /* PHY loopback cannot be performed if SoL/IDER * sessions are active */ if (e1000_check_reset_block(&adapter->hw)) { DPRINTK(DRV, ERR, "Cannot do PHY loopback test " "when SoL/IDER is active.\n"); *data = 0; goto out; } if ((*data = e1000_setup_desc_rings(adapter))) goto out; if ((*data = e1000_setup_loopback_test(adapter))) goto err_loopback; *data = e1000_run_loopback_test(adapter); e1000_loopback_cleanup(adapter);err_loopback: e1000_free_desc_rings(adapter);out: return *data;}static int e1000_link_test(struct e1000_adapter *adapter, u64 *data){ *data = 0; if (adapter->hw.phy.media_type == e1000_media_type_internal_serdes) { int i = 0; adapter->hw.mac.serdes_has_link = FALSE; /* On some blade server designs, link establishment * could take as long as 2-3 minutes */ do { e1000_check_for_link(&adapter->hw); if (adapter->hw.mac.serdes_has_link == TRUE) return *data; msleep(20); } while (i++ < 3750); *data = 1; } else { e1000_check_for_link(&adapter->hw); if (adapter->hw.mac.autoneg) msleep(4000); if (!(E1000_READ_REG(&adapter->hw, E1000_STATUS) & E1000_STATUS_LU)) { *data = 1; } } return *data;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -