📄 e1000_ethtool.c
字号:
static int e1000_diag_test_count(struct net_device *netdev){ return E1000_TEST_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, 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; 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 */ if (adapter->hw.phy.media_type == e1000_media_type_copper) { e1000_power_up_phy(&adapter->hw); e1000_setup_link(&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 = TRUE; e1000_reset(adapter); adapter->hw.phy.autoneg_wait_to_complete = FALSE; clear_bit(__E1000_TESTING, &adapter->state); 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; /* 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 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_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: case E1000_DEV_ID_82546GB_QUAD_COPPER: case E1000_DEV_ID_82546GB_PCIE: case E1000_DEV_ID_82571EB_SERDES_QUAD: /* 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, E1000_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_82571EB_QUAD_FIBER: case E1000_DEV_ID_82571EB_QUAD_COPPER_LP: case E1000_DEV_ID_82571PT_QUAD_COPPER: case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: /* quad port adapters only support WoL on port A */ if (!(adapter->flags & E1000_FLAG_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, E1000_STATUS) & E1000_STATUS_FUNC_1 && !adapter->eeprom_wol) { wol->supported = 0; break; } retval = 0; } return retval;}static void e1000_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 support 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 int e1000_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 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)) e1000_led_off(&adapter->hw); else e1000_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); if (!data) data = INT_MAX; 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(&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 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; return 0;}static int e1000_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec){ struct e1000_adapter *adapter = netdev_priv(netdev); 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)) return -EINVAL; if (!(adapter->flags & E1000_FLAG_HAS_INTR_MODERATION)) return -ENOTSUPP; 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) E1000_WRITE_REG(&adapter->hw, E1000_ITR, 1000000000 / (adapter->itr * 256)); else E1000_WRITE_REG(&adapter->hw, E1000_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 int e1000_get_stats_count(struct net_device *netdev){ return E1000_STATS_LEN;}static void e1000_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data){ struct e1000_adapter *adapter = netdev_priv(netdev);#ifdef CONFIG_E1000_MQ u64 *queue_stat; int stat_count = sizeof(struct e1000_queue_stats) / sizeof(u64); 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(u64)) ? *(u64 *)p : *(u32 *)p; }#ifdef CONFIG_E1000_MQ if (adapter->num_tx_queues > 1) { for (j = 0; j < adapter->num_tx_queues; j++) { queue_stat = (u64 *)&adapter->tx_ring[j].tx_stats; for (k = 0; k < stat_count; k++) data[i + k] = queue_stat[k]; i += k; } } if (adapter->num_rx_queues > 1) { for (j = 0; j < adapter->num_rx_queues; j++) { queue_stat = (u64 *)&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 void e1000_get_strings(struct net_device *netdev, u32 stringset, u8 *data){#ifdef CONFIG_E1000_MQ struct e1000_adapter *adapter = netdev_priv(netdev);#endif u8 *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 if (adapter->num_tx_queues > 1) { 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; } } if (adapter->num_rx_queues > 1) { 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_w
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -