📄 ethtool.c
字号:
* the cause register and then force the same * interrupt and see if one gets posted. If * an interrupt was not posted to the bus, the * test failed. */ adapter->test_icr = 0; ew32(IMS, mask); ew32(ICS, mask); msleep(10); if (!(adapter->test_icr & mask)) { *data = 4; break; } if (!shared_int) { /* * Disable the other interrupts to be reported in * the cause register and then force the other * interrupts and see if any get posted. If * an interrupt was posted to the bus, the * test failed. */ adapter->test_icr = 0; ew32(IMC, ~mask & 0x00007FFF); ew32(ICS, ~mask & 0x00007FFF); msleep(10); if (adapter->test_icr) { *data = 5; break; } } } /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); msleep(10); /* Unhook test interrupt handler */ free_irq(irq, netdev);#ifdef CONFIG_E1000E_MSIXout: if (int_mode == E1000E_INT_MODE_MSIX) { e1000_reset_interrupt_capability(adapter); adapter->int_mode = int_mode; e1000_set_interrupt_capability(adapter); } return ret_val;#else return *data;#endif}static void e1000_free_desc_rings(struct e1000_adapter *adapter){ struct e1000_ring *tx_ring = &adapter->test_tx_ring; struct e1000_ring *rx_ring = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; int i; if (tx_ring->desc && tx_ring->buffer_info) { for (i = 0; i < tx_ring->count; i++) { if (tx_ring->buffer_info[i].dma) pci_unmap_single(pdev, tx_ring->buffer_info[i].dma, tx_ring->buffer_info[i].length, PCI_DMA_TODEVICE); if (tx_ring->buffer_info[i].skb) dev_kfree_skb(tx_ring->buffer_info[i].skb); } } if (rx_ring->desc && rx_ring->buffer_info) { for (i = 0; i < rx_ring->count; i++) { if (rx_ring->buffer_info[i].dma) pci_unmap_single(pdev, rx_ring->buffer_info[i].dma, 2048, PCI_DMA_FROMDEVICE); if (rx_ring->buffer_info[i].skb) dev_kfree_skb(rx_ring->buffer_info[i].skb); } } if (tx_ring->desc) { dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc, tx_ring->dma); tx_ring->desc = NULL; } if (rx_ring->desc) { dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc, rx_ring->dma); rx_ring->desc = NULL; } kfree(tx_ring->buffer_info); tx_ring->buffer_info = NULL; kfree(rx_ring->buffer_info); rx_ring->buffer_info = NULL;}static int e1000_setup_desc_rings(struct e1000_adapter *adapter){ struct e1000_ring *tx_ring = &adapter->test_tx_ring; struct e1000_ring *rx_ring = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; struct e1000_hw *hw = &adapter->hw; u32 rctl; int i; int ret_val; /* Setup Tx descriptor ring and Tx buffers */ if (!tx_ring->count) tx_ring->count = E1000_DEFAULT_TXD; if (!(tx_ring->buffer_info = kcalloc(tx_ring->count, sizeof(struct e1000_buffer), GFP_KERNEL))) { ret_val = 1; goto err_nomem; } tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); tx_ring->size = ALIGN(tx_ring->size, 4096); tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size, &tx_ring->dma, GFP_KERNEL); if (!tx_ring->desc) { ret_val = 2; goto err_nomem; } tx_ring->next_to_use = 0; tx_ring->next_to_clean = 0; ew32(TDBAL(0), ((u64) tx_ring->dma & 0x00000000FFFFFFFF)); ew32(TDBAH(0), ((u64) tx_ring->dma >> 32)); ew32(TDLEN(0), tx_ring->count * sizeof(struct e1000_tx_desc)); ew32(TDH(0), 0); ew32(TDT(0), 0); ew32(TCTL, E1000_TCTL_PSP | E1000_TCTL_EN | E1000_TCTL_MULR | E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT | E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT); for (i = 0; i < tx_ring->count; i++) { struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i); struct sk_buff *skb; unsigned int skb_size = 1024; skb = alloc_skb(skb_size, GFP_KERNEL); if (!skb) { ret_val = 3; goto err_nomem; } skb_put(skb, skb_size); tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[i].length = skb->len; tx_ring->buffer_info[i].dma = pci_map_single(pdev, skb->data, skb->len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(tx_ring->buffer_info[i].dma)) { ret_val = 4; goto err_nomem; } tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma); tx_desc->lower.data = cpu_to_le32(skb->len); tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS); tx_desc->upper.data = 0; } /* Setup Rx descriptor ring and Rx buffers */ if (!rx_ring->count) rx_ring->count = E1000_DEFAULT_RXD; if (!(rx_ring->buffer_info = kcalloc(rx_ring->count, sizeof(struct e1000_buffer), GFP_KERNEL))) { ret_val = 5; goto err_nomem; } rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc); rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size, &rx_ring->dma, GFP_KERNEL); if (!rx_ring->desc) { ret_val = 6; goto err_nomem; } rx_ring->next_to_use = 0; rx_ring->next_to_clean = 0; rctl = er32(RCTL); ew32(RCTL, rctl & ~E1000_RCTL_EN); ew32(RDBAL(0), ((u64) rx_ring->dma & 0xFFFFFFFF)); ew32(RDBAH(0), ((u64) rx_ring->dma >> 32)); ew32(RDLEN(0), rx_ring->size); ew32(RDH(0), 0); ew32(RDT(0), 0); rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_LPE | E1000_RCTL_SBP | E1000_RCTL_SECRC | E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); ew32(RCTL, rctl); for (i = 0; i < rx_ring->count; i++) { struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i); struct sk_buff *skb; skb = alloc_skb(2048 + NET_IP_ALIGN, GFP_KERNEL); if (!skb) { ret_val = 7; goto err_nomem; } skb_reserve(skb, NET_IP_ALIGN); rx_ring->buffer_info[i].skb = skb; rx_ring->buffer_info[i].dma = pci_map_single(pdev, skb->data, 2048, PCI_DMA_FROMDEVICE); if (pci_dma_mapping_error(rx_ring->buffer_info[i].dma)) { ret_val = 8; goto err_nomem; } rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma); memset(skb->data, 0x00, skb->len); } return 0;err_nomem: e1000_free_desc_rings(adapter); return ret_val;}static void e1000_phy_disable_receiver(struct e1000_adapter *adapter){ /* Write out to PHY registers 29 and 30 to disable the Receiver. */ adapter->hw.phy.ops.write_reg(&adapter->hw, 29, 0x001F); adapter->hw.phy.ops.write_reg(&adapter->hw, 30, 0x8FFC); adapter->hw.phy.ops.write_reg(&adapter->hw, 29, 0x001A); adapter->hw.phy.ops.write_reg(&adapter->hw, 30, 0x8FF0);}static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw; u32 ctrl_reg = 0; u32 stat_reg = 0; u16 phy_reg = 0; hw->mac.autoneg = 0; if (hw->phy.type == e1000_phy_m88) { /* Auto-MDI/MDIX Off */ hw->phy.ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* reset to update Auto-MDI/MDIX */ hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x9140); /* autoneg off */ hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x8140); } else if (hw->phy.type == e1000_phy_gg82563) hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC); ctrl_reg = er32(CTRL); switch (hw->phy.type) { case e1000_phy_ife: /* force 100, set loopback */ hw->phy.ops.write_reg(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 */ break; case e1000_phy_bm: /* Set Default MAC Interface speed to 1GB */ hw->phy.ops.read_reg(hw, PHY_REG(2, 21), &phy_reg); phy_reg &= ~0x0007; phy_reg |= 0x006; hw->phy.ops.write_reg(hw, PHY_REG(2, 21), phy_reg); /* Assert SW reset for above settings to take effect */ hw->phy.ops.commit(hw); mdelay(1); /* Force Full Duplex */ hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &phy_reg); hw->phy.ops.write_reg(hw, PHY_REG(769, 16), phy_reg | 0x000C); /* Set Link Up (in force link) */ hw->phy.ops.read_reg(hw, PHY_REG(776, 16), &phy_reg); hw->phy.ops.write_reg(hw, PHY_REG(776, 16), phy_reg | 0x0040); /* Force Link */ hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &phy_reg); hw->phy.ops.write_reg(hw, PHY_REG(769, 16), phy_reg | 0x0040); /* Set Early Link Enable */ hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg); hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg | 0x0400); /* fall through */ default: /* force 1000, set loopback */ hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x4140); mdelay(250); /* Now set up the MAC to the same speed/duplex as the PHY. */ ctrl_reg = er32(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->flags & FLAG_IS_ICH) ctrl_reg |= E1000_CTRL_SLU; /* Set Link Up */ } if (hw->phy.media_type == e1000_media_type_copper && 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 = er32(STATUS); if ((stat_reg & E1000_STATUS_FD) == 0) ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); } ew32(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 (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 = er32(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; ew32(CTRL, ctrl); /* disable autoneg */ ctrl = er32(TXCW); ctrl &= ~(1 << 31); ew32(TXCW, ctrl); link = (er32(STATUS) & E1000_STATUS_LU); if (!link) { /* set invert loss of signal */ ctrl = er32(CTRL); ctrl |= E1000_CTRL_ILOS; ew32(CTRL, ctrl); } /* * special write to serdes control register to enable SerDes analog * loopback */#define E1000_SERDES_LB_ON 0x410 ew32(SCTL, E1000_SERDES_LB_ON); msleep(10); return 0;}/* 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 = er32(CTRL_EXT); u32 ctrl = er32(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; ew32(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); ew32(CTRL, ctrl); /* set mac loopback */ ctrl = er32(RCTL); ctrl |= E1000_RCTL_LBM_MAC; ew32(RCTL, ctrl); /* set testing mode parameters (no need to reset later) */#define KMRNCTRLSTA_OPMODE (0x1F << 16)#define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582 ew32(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_82571: case e1000_82572: return e1000_set_82571_fiber_loopback(adapter); break; default: rctl = er32(RCTL); rctl |= E1000_RCTL_LBM_TCVR; ew32(RCTL, rctl); return 0; } } else if (hw->phy.media_type == e1000_media_type_copper) { return e1000_integrated_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 = er32(RCTL); rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); ew32(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 */ ew32(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 ew32(SCTL, E1000_SERDES_LB_OFF); msleep(10); break; } /* Fall Through */ default: hw->mac.autoneg = 1; if (hw->phy.type == e1000_phy_gg82563) hw->phy.ops.write_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x180); if(hw->phy.ops.read_reg) hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_reg); if (phy_reg & MII_CR_LOOPBACK) { phy_reg &= ~MII_CR_LOOPBACK; hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_reg); if (hw->phy.ops.commit) hw->phy.ops.commit(hw); } break; }}static void e1000_create_lbtest_frame(struct sk_buff *skb, unsigned int frame_size){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -