📄 e1000_ethtool.c
字号:
* 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; E1000_WRITE_REG(&adapter->hw, IMC, (~mask & 0x00007FFF)); E1000_WRITE_REG(&adapter->hw, ICS, (~mask & 0x00007FFF)); msec_delay(10); if(adapter->test_icr) { *data = 5; break; } } } /* Disable all the interrupts */ E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF); msec_delay(10); /* Unhook test interrupt handler */ free_irq(irq, netdev); return *data;}static voide1000_free_desc_rings(struct e1000_adapter *adapter){ struct e1000_desc_ring *txdr = &adapter->test_tx_ring; struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; int i; if(txdr->desc && txdr->buffer_info) { for(i = 0; i < txdr->count; i++) { if(txdr->buffer_info[i].dma) pci_unmap_single(pdev, txdr->buffer_info[i].dma, txdr->buffer_info[i].length, PCI_DMA_TODEVICE); if(txdr->buffer_info[i].skb) dev_kfree_skb(txdr->buffer_info[i].skb); } } if(rxdr->desc && rxdr->buffer_info) { for(i = 0; i < rxdr->count; i++) { if(rxdr->buffer_info[i].dma) pci_unmap_single(pdev, rxdr->buffer_info[i].dma, rxdr->buffer_info[i].length, PCI_DMA_FROMDEVICE); if(rxdr->buffer_info[i].skb) dev_kfree_skb(rxdr->buffer_info[i].skb); } } if(txdr->desc) pci_free_consistent(pdev, txdr->size, txdr->desc, txdr->dma); if(rxdr->desc) pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma); if(txdr->buffer_info) kfree(txdr->buffer_info); if(rxdr->buffer_info) kfree(rxdr->buffer_info); return;}static inte1000_setup_desc_rings(struct e1000_adapter *adapter){ struct e1000_desc_ring *txdr = &adapter->test_tx_ring; struct e1000_desc_ring *rxdr = &adapter->test_rx_ring; struct pci_dev *pdev = adapter->pdev; uint32_t rctl; int size, i, ret_val; /* Setup Tx descriptor ring and Tx buffers */ txdr->count = 80; size = txdr->count * sizeof(struct e1000_buffer); if(!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) { ret_val = 1; goto err_nomem; } memset(txdr->buffer_info, 0, size); txdr->size = txdr->count * sizeof(struct e1000_tx_desc); E1000_ROUNDUP(txdr->size, 4096); if(!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) { ret_val = 2; goto err_nomem; } memset(txdr->desc, 0, txdr->size); txdr->next_to_use = txdr->next_to_clean = 0; E1000_WRITE_REG(&adapter->hw, TDBAL, ((uint64_t) txdr->dma & 0x00000000FFFFFFFF)); E1000_WRITE_REG(&adapter->hw, TDBAH, ((uint64_t) txdr->dma >> 32)); E1000_WRITE_REG(&adapter->hw, TDLEN, txdr->count * sizeof(struct e1000_tx_desc)); E1000_WRITE_REG(&adapter->hw, TDH, 0); E1000_WRITE_REG(&adapter->hw, TDT, 0); E1000_WRITE_REG(&adapter->hw, TCTL, E1000_TCTL_PSP | E1000_TCTL_EN | E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT | E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT); for(i = 0; i < txdr->count; i++) { struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*txdr, i); struct sk_buff *skb; unsigned int size = 1024; if(!(skb = alloc_skb(size, GFP_KERNEL))) { ret_val = 3; goto err_nomem; } skb_put(skb, size); txdr->buffer_info[i].skb = skb; txdr->buffer_info[i].length = skb->len; txdr->buffer_info[i].dma = pci_map_single(pdev, skb->data, skb->len, PCI_DMA_TODEVICE); tx_desc->buffer_addr = cpu_to_le64(txdr->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_RPS); tx_desc->upper.data = 0; } /* Setup Rx descriptor ring and Rx buffers */ rxdr->count = 80; size = rxdr->count * sizeof(struct e1000_buffer); if(!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) { ret_val = 4; goto err_nomem; } memset(rxdr->buffer_info, 0, size); rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); if(!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) { ret_val = 5; goto err_nomem; } memset(rxdr->desc, 0, rxdr->size); rxdr->next_to_use = rxdr->next_to_clean = 0; rctl = E1000_READ_REG(&adapter->hw, RCTL); E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN); E1000_WRITE_REG(&adapter->hw, RDBAL, ((uint64_t) rxdr->dma & 0xFFFFFFFF)); E1000_WRITE_REG(&adapter->hw, RDBAH, ((uint64_t) rxdr->dma >> 32)); E1000_WRITE_REG(&adapter->hw, RDLEN, rxdr->size); E1000_WRITE_REG(&adapter->hw, RDH, 0); E1000_WRITE_REG(&adapter->hw, RDT, 0); rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT); E1000_WRITE_REG(&adapter->hw, RCTL, rctl); for(i = 0; i < rxdr->count; i++) { struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rxdr, i); struct sk_buff *skb; if(!(skb = alloc_skb(E1000_RXBUFFER_2048 + 2, GFP_KERNEL))) { ret_val = 6; goto err_nomem; } skb_reserve(skb, 2); rxdr->buffer_info[i].skb = skb; rxdr->buffer_info[i].length = E1000_RXBUFFER_2048; rxdr->buffer_info[i].dma = pci_map_single(pdev, skb->data, E1000_RXBUFFER_2048, PCI_DMA_FROMDEVICE); rx_desc->buffer_addr = cpu_to_le64(rxdr->buffer_info[i].dma); memset(skb->data, 0x00, skb->len); } return 0;err_nomem: e1000_free_desc_rings(adapter); return ret_val;}static voide1000_phy_disable_receiver(struct e1000_adapter *adapter){ /* Write out to PHY registers 29 and 30 to disable the Receiver. */ e1000_write_phy_reg(&adapter->hw, 29, 0x001F); e1000_write_phy_reg(&adapter->hw, 30, 0x8FFC); e1000_write_phy_reg(&adapter->hw, 29, 0x001A); e1000_write_phy_reg(&adapter->hw, 30, 0x8FF0);}static voide1000_phy_reset_clk_and_crs(struct e1000_adapter *adapter){ uint16_t phy_reg; /* Because we reset the PHY above, we need to re-force TX_CLK in the * Extended PHY Specific Control Register to 25MHz clock. This * value defaults back to a 2.5MHz clock when the PHY is reset. */ e1000_read_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg); phy_reg |= M88E1000_EPSCR_TX_CLK_25; e1000_write_phy_reg(&adapter->hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_reg); /* In addition, because of the s/w reset above, we need to enable * CRS on TX. This must be set for both full and half duplex * operation. */ e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg); phy_reg |= M88E1000_PSCR_ASSERT_CRS_ON_TX; e1000_write_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, phy_reg);}static inte1000_nonintegrated_phy_loopback(struct e1000_adapter *adapter){ uint32_t ctrl_reg; uint16_t phy_reg; /* Setup the Device Control Register for PHY loopback test. */ ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL); ctrl_reg |= (E1000_CTRL_ILOS | /* Invert Loss-Of-Signal */ 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 */ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg); /* Read the PHY Specific Control Register (0x10) */ e1000_read_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, &phy_reg); /* Clear Auto-Crossover bits in PHY Specific Control Register * (bits 6:5). */ phy_reg &= ~M88E1000_PSCR_AUTO_X_MODE; e1000_write_phy_reg(&adapter->hw, M88E1000_PHY_SPEC_CTRL, phy_reg); /* Perform software reset on the PHY */ e1000_phy_reset(&adapter->hw); /* Have to setup TX_CLK and TX_CRS after software reset */ e1000_phy_reset_clk_and_crs(adapter); e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8100); /* Wait for reset to complete. */ udelay(500); /* Have to setup TX_CLK and TX_CRS after software reset */ e1000_phy_reset_clk_and_crs(adapter); /* Write out to PHY registers 29 and 30 to disable the Receiver. */ e1000_phy_disable_receiver(adapter); /* Set the loopback bit in the PHY control register. */ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); phy_reg |= MII_CR_LOOPBACK; e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 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_CTRL, &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 inte1000_integrated_phy_loopback(struct e1000_adapter *adapter){ uint32_t ctrl_reg = 0; uint32_t stat_reg = 0; adapter->hw.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_CTRL, 0x9140); /* autoneg off */ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8140); } /* force 1000, set loopback */ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140); /* Now set up the MAC to the same speed/duplex as the PHY. */ ctrl_reg = E1000_READ_REG(&adapter->hw, 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.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 is half * duplex link is detected. */ stat_reg = E1000_READ_REG(&adapter->hw, STATUS); if((stat_reg & E1000_STATUS_FD) == 0) ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); } E1000_WRITE_REG(&adapter->hw, 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 inte1000_set_phy_loopback(struct e1000_adapter *adapter){ uint16_t phy_reg = 0; uint16_t count = 0; switch (adapter->hw.mac_type) { case e1000_82543: if(adapter->hw.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: 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_CTRL, &phy_reg); phy_reg |= MII_CR_LOOPBACK; e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg); return 0; break; } return 8;}static inte1000_setup_loopback_test(struct e1000_adapter *adapter){ uint32_t rctl; if(adapter->hw.media_type == e1000_media_type_fiber || adapter->hw.media_type == e1000_media_type_internal_serdes) { if(adapter->hw.mac_type == e1000_82545 || adapter->hw.mac_type == e1000_82546 || adapter->hw.mac_type == e1000_82545_rev_3 || adapter->hw.mac_type == e1000_82546_rev_3) return e1000_set_phy_loopback(adapter); else { rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl |= E1000_RCTL_LBM_TCVR; E1000_WRITE_REG(&adapter->hw, RCTL, rctl); return 0; } } else if(adapter->hw.media_type == e1000_media_type_copper) return e1000_set_phy_loopback(adapter); return 7;}static voide1000_loopback_cleanup(struct e1000_adapter *adapter)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -