📄 e1000_idiag.c
字号:
M88E1000_EXT_PHY_SPEC_CTRL, 0x0c04); /* reset to update MAC interface speed */ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8100); /* force 10, set loopback */ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4100); /* 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_SLU | /* Set the Force Link Bit */ E1000_CTRL_FRCSPD |/* Set the Force Speed Bit */ E1000_CTRL_FRCDPX |/* Set the Force Duplex Bit */ E1000_CTRL_SPD_10 |/* Force Speed to 10 */ E1000_CTRL_FD); /* Force Duplex to FULL */ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg); loopback_mode_set = TRUE; break; default: loopback_mode_set = FALSE; break; } /* 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. */ e1000_phy_disable_receiver(adapter); usec_delay(500); return loopback_mode_set ? 0 : 1;}/** * e1000_set_phy_loopback - Set the PHY into loopback mode. * @adapter: board private structure * * Returns 0 on success, 1 on failure **/static inte1000_set_phy_loopback(struct e1000_adapter *adapter){ uint16_t phy_reg = 0; uint16_t speed = 0; uint16_t duplex = 0; int status = 1; int count; 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. */ for(count = 0; count < 10; count++) if(!e1000_nonintegrated_phy_loopback(adapter)) break; status = 0; } break; case e1000_82544: if(adapter->hw.media_type == e1000_media_type_copper) e1000_get_speed_and_duplex(&adapter->hw, &speed, &duplex); status = e1000_integrated_phy_loopback(adapter, speed); break; case e1000_82540: case e1000_82545: case e1000_82546: e1000_get_speed_and_duplex(&adapter->hw, &speed, &duplex); status = e1000_integrated_phy_loopback(adapter, speed); 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); status = 0; break; } return status;}static inte1000_set_loopback_mode(struct e1000_adapter *adapter, enum idiag_e1000_diag_loopback_mode mode){ uint32_t rctl; uint16_t phy_reg; int status = 1; switch (mode) { case IDIAG_E1000_DIAG_NONE_LB: /* Clear bits 7:6 to turn off loopback mode */ rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); E1000_WRITE_REG(&adapter->hw, RCTL, rctl); /* Only modify the GMII/MII PHY device if the * media type is copper. */ if(adapter->hw.media_type == e1000_media_type_copper || (adapter->hw.media_type == e1000_media_type_fiber && (adapter->hw.mac_type == e1000_82545 || adapter->hw.mac_type == e1000_82546))) { adapter->hw.autoneg = TRUE; /* De-assert bit 14 (loopback mode) in PHY */ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); /* Only turn off PHY loopback if enabled */ if(phy_reg & MII_CR_LOOPBACK) { phy_reg &= ~MII_CR_LOOPBACK; e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg); /* Reset the PHY to make sure we * regain link */ e1000_phy_reset(&adapter->hw); } } status = 0; break; case IDIAG_E1000_DIAG_MAC_LB: /* Not supported */ break; case IDIAG_E1000_DIAG_PHY_TCVR_LB: if(adapter->hw.media_type == e1000_media_type_fiber) { if(adapter->hw.mac_type == e1000_82545 || adapter->hw.mac_type == e1000_82546) { status = 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); status = 0; } } if(adapter->hw.media_type == e1000_media_type_copper) { status = e1000_set_phy_loopback(adapter); } break; } return status;}static voide1000_create_lbtest_frame(struct sk_buff *skb, unsigned int frame_size){ memset(skb->data, 0xFF, frame_size); frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size; 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 inte1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size){ frame_size = (frame_size % 2) ? (frame_size - 1) : frame_size; if(*(skb->data + 3) == 0xFF) { if((*(skb->data + frame_size / 2 + 10) == 0xBE) && (*(skb->data + frame_size / 2 + 12) == 0xAF)) { return 1; } } return 0;}static enum idiag_e1000_diag_loopback_resulte1000_loopback_test(struct e1000_adapter *adapter){ struct e1000_desc_ring *txdr = &adapter->diag_tx_ring; struct e1000_desc_ring *rxdr = &adapter->diag_rx_ring; struct pci_dev *pdev = adapter->pdev; int i; E1000_WRITE_REG(&adapter->hw, RDT, rxdr->count - 1); for(i = 0; i < 64; i++) { e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024); pci_dma_sync_single(pdev, txdr->buffer_info[i].dma, txdr->buffer_info[i].length, PCI_DMA_TODEVICE); } E1000_WRITE_REG(&adapter->hw, TDT, i); msec_delay(200); pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma, rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE); if(e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024)) return IDIAG_E1000_LOOPBACK_TEST_OK; else return IDIAG_E1000_LOOPBACK_TEST_FAILED;}static enum idiag_pro_state1000_diag_loopback_test(struct e1000_adapter *adapter, uint8_t *diag_param){ struct idiag_e1000_diag_loopback_test_param *param = (struct idiag_e1000_diag_loopback_test_param *) diag_param; if(param->mode == IDIAG_E1000_DIAG_MAC_LB) { /* Loopback test not support */ param->result = IDIAG_E1000_LOOPBACK_TEST_NOT_EXEC; return IDIAG_PRO_STAT_NOT_SUPPORTED; } if(e1000_setup_desc_rings(adapter)) { param->result = IDIAG_E1000_LOOPBACK_TEST_NOT_EXEC; return IDIAG_PRO_STAT_TEST_FAILED; } if(e1000_set_loopback_mode(adapter, param->mode)) { param->result = IDIAG_E1000_LOOPBACK_TEST_NOT_EXEC; e1000_free_desc_rings(adapter); return IDIAG_PRO_STAT_TEST_FAILED; } param->result = e1000_loopback_test(adapter); e1000_set_loopback_mode(adapter, IDIAG_E1000_DIAG_NONE_LB); e1000_free_desc_rings(adapter); return (param->result == IDIAG_E1000_LOOPBACK_TEST_OK) ? IDIAG_PRO_STAT_OK : IDIAG_PRO_STAT_TEST_FAILED;}static enum idiag_pro_state1000_diag_link_test(struct e1000_adapter *adapter, uint8_t *diag_param){ e1000_check_for_link(&adapter->hw); if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) return IDIAG_PRO_STAT_OK; else return IDIAG_PRO_STAT_TEST_FAILED;}inte1000_diag_ioctl(struct net_device *netdev, struct ifreq *ifr){ struct e1000_adapter *adapter = netdev->priv; struct idiag_pro_data *diag_data = (struct idiag_pro_data *) ifr->ifr_data; boolean_t run_offline; boolean_t interface_up = netif_running(netdev); diag_data->status = IDIAG_PRO_STAT_NOT_SUPPORTED; if(!capable(CAP_NET_ADMIN)) /* must have admin capabilities */ return -EPERM; if(diag_data->interface_ver != IDIAG_PRO_VERSION) /* incorrect diagnostics interface version */ return -EFAULT; if(diag_data->cmd != IDIAG_PRO_IDENTIFY_DRIVER && diag_data->driver_id != IDIAG_E1000_DRIVER) /* incorrect driver identifier */ return -EFAULT; /* Some test requring exclusive access to hardware, so * we need to teardown the hardware setup, run the test, * and restore the hardware to resume the network * connection. */ run_offline = (diag_data->cmd == IDIAG_E1000_DIAG_REG_TEST || diag_data->cmd == IDIAG_E1000_DIAG_INTR_TEST || diag_data->cmd == IDIAG_E1000_DIAG_LOOPBACK_TEST); if(run_offline) { if(interface_up) e1000_down(adapter); else e1000_reset(adapter); } /* Run the diagnotic test */ switch (diag_data->cmd) { case IDIAG_PRO_IDENTIFY_DRIVER: diag_data->driver_id = IDIAG_E1000_DRIVER; diag_data->status = IDIAG_PRO_STAT_OK; break; case IDIAG_E1000_DIAG_REG_TEST: diag_data->status = e1000_diag_reg_test(adapter, diag_data->diag_param); break; case IDIAG_E1000_DIAG_XSUM_TEST: diag_data->status = e1000_diag_eeprom_test(adapter, diag_data->diag_param); break; case IDIAG_E1000_DIAG_INTR_TEST: diag_data->status = e1000_diag_intr_test(adapter, diag_data->diag_param); break; case IDIAG_E1000_DIAG_LOOPBACK_TEST: diag_data->status = e1000_diag_loopback_test(adapter, diag_data->diag_param); break; case IDIAG_E1000_DIAG_LINK_TEST: diag_data->status = e1000_diag_link_test(adapter, diag_data->diag_param); break; default: diag_data->status = IDIAG_PRO_STAT_NOT_SUPPORTED; break; } if(run_offline) { e1000_reset(adapter); if(interface_up) { if(e1000_up(adapter)) { diag_data->status = IDIAG_PRO_STAT_TEST_FATAL; return -EFAULT; } } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -