📄 e1000_ethtool.c
字号:
return 13;}static inte1000_run_loopback_test(struct e1000_adapter *adapter){ struct e1000_tx_ring *txdr = &adapter->test_tx_ring; struct e1000_rx_ring *rxdr = &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, RDT, rxdr->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 (rxdr->count <= txdr->count) lc = ((txdr->count / 64) * 2) + 1; else lc = ((rxdr->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(txdr->buffer_info[i].skb, 1024); pci_dma_sync_single_for_device(pdev, txdr->buffer_info[k].dma, txdr->buffer_info[k].length, PCI_DMA_TODEVICE); if (unlikely(++k == txdr->count)) k = 0; } E1000_WRITE_REG(&adapter->hw, TDT, k); msec_delay(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, rxdr->buffer_info[l].dma, rxdr->buffer_info[l].length, PCI_DMA_FROMDEVICE); ret_val = e1000_check_lbtest_frame( rxdr->buffer_info[l].skb, 1024); if (!ret_val) good_cnt++; if (unlikely(++l == rxdr->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 + 2)) { ret_val = 14; /* error code for time out error */ break; } } /* end loop count loop */ return ret_val;}static inte1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data){ /* PHY loopback cannot be performed if SoL/IDER * sessions are active */ if (e1000_check_phy_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 inte1000_link_test(struct e1000_adapter *adapter, uint64_t *data){ *data = 0; if (adapter->hw.media_type == e1000_media_type_internal_serdes) { int i = 0; adapter->hw.serdes_link_down = TRUE; /* 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.serdes_link_down == FALSE) return *data; msec_delay(20); } while (i++ < 3750); *data = 1; } else { e1000_check_for_link(&adapter->hw); if (adapter->hw.autoneg) /* if auto_neg is set wait for it */ msec_delay(4000); if (!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) { *data = 1; } } return *data;}static inte1000_diag_test_count(struct net_device *netdev){ return E1000_TEST_LEN;}static voide1000_diag_test(struct net_device *netdev, struct ethtool_test *eth_test, uint64_t *data){ struct e1000_adapter *adapter = netdev_priv(netdev); boolean_t if_running = netif_running(netdev); if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ /* save speed, duplex, autoneg settings */ uint16_t autoneg_advertised = adapter->hw.autoneg_advertised; uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex; uint8_t autoneg = adapter->hw.autoneg; /* Link test performed before hardware reset so autoneg doesn't * interfere with test result */ if (e1000_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; if (if_running) e1000_down(adapter); else e1000_reset(adapter); if (e1000_reg_test(adapter, &data[0])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); if (e1000_eeprom_test(adapter, &data[1])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); if (e1000_intr_test(adapter, &data[2])) eth_test->flags |= ETH_TEST_FL_FAILED; e1000_reset(adapter); if (e1000_loopback_test(adapter, &data[3])) eth_test->flags |= ETH_TEST_FL_FAILED; /* restore speed, duplex, autoneg settings */ adapter->hw.autoneg_advertised = autoneg_advertised; adapter->hw.forced_speed_duplex = forced_speed_duplex; adapter->hw.autoneg = autoneg; e1000_reset(adapter); if (if_running) e1000_up(adapter); } else { /* Online tests */ if (e1000_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; /* Offline tests aren't run; pass by default */ data[0] = 0; data[1] = 0; data[2] = 0; data[3] = 0; } msleep_interruptible(4 * 1000);}static voide1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; switch (adapter->hw.device_id) { case E1000_DEV_ID_82542: case E1000_DEV_ID_82543GC_FIBER: case E1000_DEV_ID_82543GC_COPPER: case E1000_DEV_ID_82544EI_FIBER: case E1000_DEV_ID_82546EB_QUAD_COPPER: case E1000_DEV_ID_82545EM_FIBER: case E1000_DEV_ID_82545EM_COPPER: wol->supported = 0; wol->wolopts = 0; return; case E1000_DEV_ID_82546EB_FIBER: case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82571EB_FIBER: /* Wake events only supported on port A for dual fiber */ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) { wol->supported = 0; wol->wolopts = 0; return; } /* Fall Through */ default: wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; wol->wolopts = 0; if (adapter->wol & E1000_WUFC_EX) wol->wolopts |= WAKE_UCAST; if (adapter->wol & E1000_WUFC_MC) wol->wolopts |= WAKE_MCAST; if (adapter->wol & E1000_WUFC_BC) wol->wolopts |= WAKE_BCAST; if (adapter->wol & E1000_WUFC_MAG) wol->wolopts |= WAKE_MAGIC; return; }}static inte1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; switch (adapter->hw.device_id) { case E1000_DEV_ID_82542: case E1000_DEV_ID_82543GC_FIBER: case E1000_DEV_ID_82543GC_COPPER: case E1000_DEV_ID_82544EI_FIBER: case E1000_DEV_ID_82546EB_QUAD_COPPER: case E1000_DEV_ID_82545EM_FIBER: case E1000_DEV_ID_82545EM_COPPER: return wol->wolopts ? -EOPNOTSUPP : 0; case E1000_DEV_ID_82546EB_FIBER: case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82571EB_FIBER: /* Wake events only supported on port A for dual fiber */ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) return wol->wolopts ? -EOPNOTSUPP : 0; /* Fall Through */ default: if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) return -EOPNOTSUPP; adapter->wol = 0; if (wol->wolopts & WAKE_UCAST) adapter->wol |= E1000_WUFC_EX; if (wol->wolopts & WAKE_MCAST) adapter->wol |= E1000_WUFC_MC; if (wol->wolopts & WAKE_BCAST) adapter->wol |= E1000_WUFC_BC; if (wol->wolopts & WAKE_MAGIC) adapter->wol |= E1000_WUFC_MAG; } return 0;}/* toggle LED 4 times per second = 2 "blinks" per second */#define E1000_ID_INTERVAL (HZ/4)/* bit defines for adapter->led_status */#define E1000_LED_ON 0static voide1000_led_blink_callback(unsigned long data){ struct e1000_adapter *adapter = (struct e1000_adapter *) data; if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) e1000_led_off(&adapter->hw); else e1000_led_on(&adapter->hw); mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);}static inte1000_phys_id(struct net_device *netdev, uint32_t data){ struct e1000_adapter *adapter = netdev_priv(netdev); if (!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ)) data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ); if (adapter->hw.mac_type < e1000_82571) { if (!adapter->blink_timer.function) { init_timer(&adapter->blink_timer); adapter->blink_timer.function = e1000_led_blink_callback; adapter->blink_timer.data = (unsigned long) adapter; } e1000_setup_led(&adapter->hw); mod_timer(&adapter->blink_timer, jiffies); msleep_interruptible(data * 1000); del_timer_sync(&adapter->blink_timer); } else if (adapter->hw.mac_type < e1000_82573) { E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE | E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED2_BLINK | (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) | (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED0_MODE_SHIFT) | (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED1_MODE_SHIFT))); msleep_interruptible(data * 1000); } else { E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE | E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK | (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) | (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) | (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT))); msleep_interruptible(data * 1000); } e1000_led_off(&adapter->hw); clear_bit(E1000_LED_ON, &adapter->led_status); e1000_cleanup_led(&adapter->hw); return 0;}static inte1000_nway_reset(struct net_device *netdev){ struct e1000_adapter *adapter = netdev_priv(netdev); if (netif_running(netdev)) { e1000_down(adapter); e1000_up(adapter); } return 0;}static inte1000_get_stats_count(struct net_device *netdev){ return E1000_STATS_LEN;}static voide1000_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data){ struct e1000_adapter *adapter = netdev_priv(netdev);#ifdef CONFIG_E1000_MQ uint64_t *queue_stat; int stat_count = sizeof(struct e1000_queue_stats) / sizeof(uint64_t); int j, k;#endif int i; e1000_update_stats(adapter); for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; }#ifdef CONFIG_E1000_MQ for (j = 0; j < adapter->num_tx_queues; j++) { queue_stat = (uint64_t *)&adapter->tx_ring[j].tx_stats; for (k = 0; k < stat_count; k++) data[i + k] = queue_stat[k]; i += k; } for (j = 0; j < adapter->num_rx_queues; j++) { queue_stat = (uint64_t *)&adapter->rx_ring[j].rx_stats; for (k = 0; k < stat_count; k++) data[i + k] = queue_stat[k]; i += k; }#endif/* BUG_ON(i != E1000_STATS_LEN); */}static voide1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data){#ifdef CONFIG_E1000_MQ struct e1000_adapter *adapter = netdev_priv(netdev);#endif uint8_t *p = data; int i; switch (stringset) { case ETH_SS_TEST: memcpy(data, *e1000_gstrings_test, E1000_TEST_LEN*ETH_GSTRING_LEN); break; case ETH_SS_STATS: for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { memcpy(p, e1000_gstrings_stats[i].stat_string, ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; }#ifdef CONFIG_E1000_MQ for (i = 0; i < adapter->num_tx_queues; i++) { sprintf(p, "tx_queue_%u_packets", i); p += ETH_GSTRING_LEN; sprintf(p, "tx_queue_%u_bytes", i); p += ETH_GSTRING_LEN; } for (i = 0; i < adapter->num_rx_queues; i++) { sprintf(p, "rx_queue_%u_packets", i); p += ETH_GSTRING_LEN; sprintf(p, "rx_queue_%u_bytes", i); p += ETH_GSTRING_LEN; }#endif/* BUG_ON(p - data != E1000_STATS_LEN * ETH_GSTRING_LEN); */ break; }}static struct ethtool_ops e1000_ethtool_ops = { .get_settings = e1000_get_settings, .set_settings = e1000_set_settings, .get_drvinfo = e1000_get_drvinfo, .get_regs_len = e1000_get_regs_len, .get_regs = e1000_get_regs, .get_wol = e1000_get_wol, .set_wol = e1000_set_wol, .get_msglevel = e1000_get_msglevel, .set_msglevel = e1000_set_msglevel, .nway_reset = e1000_nway_reset, .get_link = ethtool_op_get_link, .get_eeprom_len = e1000_get_eeprom_len, .get_eeprom = e1000_get_eeprom, .set_eeprom = e1000_set_eeprom, .get_ringparam = e1000_get_ringparam, .set_ringparam = e1000_set_ringparam, .get_pauseparam = e1000_get_pauseparam, .set_pauseparam = e1000_set_pauseparam, .get_rx_csum = e1000_get_rx_csum, .set_rx_csum = e1000_set_rx_csum, .get_tx_csum = e1000_get_tx_csum, .set_tx_csum = e1000_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg,#ifdef NETIF_F_TSO .get_tso = ethtool_op_get_tso, .set_tso = e1000_set_tso,#endif .self_test_count = e1000_diag_test_count, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, .phys_id = e1000_phys_id, .get_stats_count = e1000_get_stats_count, .get_ethtool_stats = e1000_get_ethtool_stats, .get_perm_addr = ethtool_op_get_perm_addr,};void e1000_set_ethtool_ops(struct net_device *netdev){ SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -