📄 ethtool.c
字号:
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_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; int i, j, k, l; int lc; int good_cnt; int ret_val = 0; unsigned long time; ew32(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 = 0; 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); k++; if (k == tx_ring->count) k = 0; } ew32(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, 2048, PCI_DMA_FROMDEVICE); ret_val = e1000_check_lbtest_frame( rx_ring->buffer_info[l].skb, 1024); if (!ret_val) good_cnt++; l++; if (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) && !time_after(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){ struct e1000_hw *hw = &adapter->hw; /* * PHY loopback cannot be performed if SoL/IDER * sessions are active */ if (hw->phy.ops.check_reset_block && hw->phy.ops.check_reset_block(&adapter->hw)) { e_err("Cannot do PHY loopback test when SoL/IDER is active.\n"); *data = 0; goto out; } *data = e1000_setup_desc_rings(adapter); if (*data) goto out; *data = e1000_setup_loopback_test(adapter); if (*data) 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){ struct e1000_hw *hw = &adapter->hw; *data = 0; if (hw->phy.media_type == e1000_media_type_internal_serdes) { int i = 0; hw->mac.serdes_has_link = 0; /* * On some blade server designs, link establishment * could take as long as 2-3 minutes */ do { hw->mac.ops.check_for_link(hw); if (hw->mac.serdes_has_link) return *data; msleep(20); } while (i++ < 3750); *data = 1; } else { hw->mac.ops.check_for_link(hw); if (hw->mac.autoneg) msleep(4000); if (!(er32(STATUS) & E1000_STATUS_LU)) *data = 1; } return *data;}static int e1000_get_self_test_count(struct net_device *netdev){ return E1000_TEST_LEN;}static int e1000_get_stats_count(struct net_device *netdev){ return E1000_STATS_LEN;}static void e1000_diag_test(struct net_device *netdev, struct ethtool_test *eth_test, u64 *data){ struct e1000_adapter *adapter = netdev_priv(netdev); u16 autoneg_advertised; u8 forced_speed_duplex; u8 autoneg; bool if_running = netif_running(netdev); set_bit(__E1000_TESTING, &adapter->state); if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ /* save speed, duplex, autoneg settings */ autoneg_advertised = adapter->hw.phy.autoneg_advertised; forced_speed_duplex = adapter->hw.mac.forced_speed_duplex; autoneg = adapter->hw.mac.autoneg; e_info("offline testing starting\n"); /* * 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) /* indicate we're in test mode */ dev_close(netdev); 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); /* make sure the phy is powered up */ e1000_power_up_phy(&adapter->hw); if (e1000_loopback_test(adapter, &data[3])) eth_test->flags |= ETH_TEST_FL_FAILED; /* restore speed, duplex, autoneg settings */ adapter->hw.phy.autoneg_advertised = autoneg_advertised; adapter->hw.mac.forced_speed_duplex = forced_speed_duplex; adapter->hw.mac.autoneg = autoneg; /* force this routine to wait until autoneg complete/timeout */ adapter->hw.phy.autoneg_wait_to_complete = 1; e1000_reset(adapter); adapter->hw.phy.autoneg_wait_to_complete = 0; clear_bit(__E1000_TESTING, &adapter->state); if (if_running) dev_open(netdev); } else { e_info("online testing starting\n"); /* Online tests */ if (e1000_link_test(adapter, &data[4])) eth_test->flags |= ETH_TEST_FL_FAILED; /* Online tests aren't run; pass by default */ data[0] = 0; data[1] = 0; data[2] = 0; data[3] = 0; clear_bit(__E1000_TESTING, &adapter->state); } msleep_interruptible(4 * 1000);}static void e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol){ struct e1000_adapter *adapter = netdev_priv(netdev); wol->supported = 0; wol->wolopts = 0; if (!(adapter->flags & FLAG_HAS_WOL)) return; wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC | WAKE_PHY | WAKE_ARP; /* apply any specific unsupported masks here */ if (adapter->flags & FLAG_NO_WAKE_UCAST) { wol->supported &= ~WAKE_UCAST; if (adapter->wol & E1000_WUFC_EX) e_err("Interface does not support directed (unicast)" " frame wake-up packets\n"); } 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; if (adapter->wol & E1000_WUFC_LNKC) wol->wolopts |= WAKE_PHY; if (adapter->wol & E1000_WUFC_ARP) wol->wolopts |= WAKE_ARP;}static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol){ struct e1000_adapter *adapter = netdev_priv(netdev); if (wol->wolopts & WAKE_MAGICSECURE) return -EOPNOTSUPP; if (!(adapter->flags & FLAG_HAS_WOL)) return wol->wolopts ? -EOPNOTSUPP : 0; /* these settings will always override what we currently have */ 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; if (wol->wolopts & WAKE_PHY) adapter->wol |= E1000_WUFC_LNKC; if (wol->wolopts & WAKE_ARP) adapter->wol |= E1000_WUFC_ARP; 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 void e1000_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)) adapter->hw.mac.ops.led_off(&adapter->hw); else adapter->hw.mac.ops.led_on(&adapter->hw); mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);}static int e1000_phys_id(struct net_device *netdev, u32 data){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; if (!data) data = INT_MAX; if ((hw->phy.type == e1000_phy_ife) || (hw->mac.type == e1000_82574)) { 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; } mod_timer(&adapter->blink_timer, jiffies); msleep_interruptible(data * 1000); del_timer_sync(&adapter->blink_timer); if (hw->phy.type == e1000_phy_ife) hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); } else { hw->mac.ops.blink_led(hw); msleep_interruptible(data * 1000); } hw->mac.ops.led_off(hw); clear_bit(E1000_LED_ON, &adapter->led_status); hw->mac.ops.cleanup_led(hw); return 0;}static int e1000_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec){ struct e1000_adapter *adapter = netdev_priv(netdev); if (adapter->itr_setting <= 3) ec->rx_coalesce_usecs = adapter->itr_setting; else ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting; ec->stats_block_coalesce_usecs = adapter->stats_freq_us; return 0;}static int e1000_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) || ((ec->rx_coalesce_usecs > 3) && (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) || (ec->rx_coalesce_usecs == 2) || (ec->stats_block_coalesce_usecs > (10 * 1000000))) return -EINVAL; adapter->stats_freq_us = ec->stats_block_coalesce_usecs; if (ec->rx_coalesce_usecs <= 3) { adapter->itr = 20000; adapter->itr_setting = ec->rx_coalesce_usecs; } else { adapter->itr = (1000000 / ec->rx_coalesce_usecs); adapter->itr_setting = adapter->itr & ~3; } if (adapter->itr_setting != 0) ew32(ITR, 1000000000 / (adapter->itr * 256)); else ew32(ITR, 0); return 0;}static int e1000_nway_reset(struct net_device *netdev){ struct e1000_adapter *adapter = netdev_priv(netdev); if (netif_running(netdev)) e1000_reinit_locked(adapter); return 0;}static void e1000_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data){ struct e1000_adapter *adapter = netdev_priv(netdev); 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(u64)) ? *(u64 *)p : *(u32 *)p; }}static void e1000_get_strings(struct net_device *netdev, u32 stringset, u8 *data){ u8 *p = data; int i; switch (stringset) { case ETH_SS_TEST: memcpy(data, *e1000_gstrings_test, sizeof(e1000_gstrings_test)); 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; } break; }}static const 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 = e1000_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 = e1000_diag_test, .get_strings = e1000_get_strings, .phys_id = e1000_phys_id, .get_ethtool_stats = e1000_get_ethtool_stats, .self_test_count = e1000_get_self_test_count, .get_stats_count = e1000_get_stats_count, .get_coalesce = e1000_get_coalesce, .set_coalesce = e1000_set_coalesce,};void e1000_set_ethtool_ops(struct net_device *netdev){ /* have to "undeclare" const on this struct to remove warnings */ SET_ETHTOOL_OPS(netdev, (struct ethtool_ops *)&e1000_ethtool_ops);}#endif /* SIOCETHTOOL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -