📄 e1000_ethtool.c
字号:
if ((*(skb->data + frame_size / 2 + 10) == 0xBE) && (*(skb->data + frame_size / 2 + 12) == 0xAF)) { return 0; } } 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;}extern void e1000_power_up_phy(struct e1000_adapter *);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); set_bit(__E1000_TESTING, &adapter->flags); 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; DPRINTK(HW, 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); 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); clear_bit(__E1000_TESTING, &adapter->flags); if (if_running) dev_open(netdev); } else { DPRINTK(HW, INFO, "online testing starting\n"); /* 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; clear_bit(__E1000_TESTING, &adapter->flags); } msleep_interruptible(4 * 1000);}static int e1000_wol_exclusion(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol){ struct e1000_hw *hw = &adapter->hw; int retval = 1; /* fail by default */ switch (hw->device_id) { 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: case E1000_DEV_ID_82546GB_QUAD_COPPER: case E1000_DEV_ID_82546GB_PCIE: /* these don't support WoL at all */ wol->supported = 0; break; case E1000_DEV_ID_82546EB_FIBER: case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82571EB_FIBER: case E1000_DEV_ID_82571EB_SERDES: case E1000_DEV_ID_82571EB_COPPER: /* Wake events not supported on port B */ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) { wol->supported = 0; break; } /* return success for non excluded adapter ports */ retval = 0; break; case E1000_DEV_ID_82571EB_QUAD_COPPER: case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: /* quad port adapters only support WoL on port A */ if (!adapter->quad_port_a) { wol->supported = 0; break; } /* return success for non excluded adapter ports */ retval = 0; break; default: /* dual port cards only support WoL on port A from now on * unless it was enabled in the eeprom for port B * so exclude FUNC_1 ports from having WoL enabled */ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1 && !adapter->eeprom_wol) { wol->supported = 0; break; } retval = 0; } return retval;}static voide1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol){ struct e1000_adapter *adapter = netdev_priv(netdev); wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; wol->wolopts = 0; /* this function will set ->supported = 0 and return 1 if wol is not * supported by this hardware */ if (e1000_wol_exclusion(adapter, wol)) return; /* apply any specific unsupported masks here */ switch (adapter->hw.device_id) { case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: /* KSP3 does not suppport UCAST wake-ups */ wol->supported &= ~WAKE_UCAST; if (adapter->wol & E1000_WUFC_EX) DPRINTK(DRV, ERR, "Interface does not support " "directed (unicast) frame wake-up packets\n"); break; default: break; } 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; if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) return -EOPNOTSUPP; if (e1000_wol_exclusion(adapter, wol)) return wol->wolopts ? -EOPNOTSUPP : 0; switch (hw->device_id) { case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: if (wol->wolopts & WAKE_UCAST) { DPRINTK(DRV, ERR, "Interface does not support " "directed (unicast) frame wake-up packets\n"); return -EOPNOTSUPP; } break; default: break; } /* 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; 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.phy_type == e1000_phy_ife) { 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); e1000_write_phy_reg(&(adapter->hw), IFE_PHY_SPECIAL_CONTROL_LED, 0); } else { e1000_blink_led_start(&adapter->hw); 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_reinit_locked(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); 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; }/* BUG_ON(i != E1000_STATS_LEN); */}static voide1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data){ 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; }/* 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,#ifdef ETHTOOL_GPERMADDR .get_perm_addr = ethtool_op_get_perm_addr,#endif};void e1000_set_ethtool_ops(struct net_device *netdev){ SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);}#endif /* SIOCETHTOOL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -