📄 e1000_ethtool.c
字号:
/******************************************************************************* Intel PRO/1000 Linux driver Copyright(c) 1999 - 2007 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, version 2, as published by the Free Software Foundation. This program is distributed in the hope it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. The full GNU General Public License is included in this distribution in the file called "COPYING". Contact Information: Linux NICS <linux.nics@intel.com> e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497*******************************************************************************//* ethtool support for e1000 */#include <linux/netdevice.h>#ifdef SIOCETHTOOL#include <linux/ethtool.h>#include "e1000.h"#include "e1000_82541.h"#ifdef ETHTOOL_OPS_COMPAT#include "kcompat_ethtool.c"#endifextern char e1000_driver_name[];extern char e1000_driver_version[];extern int e1000_up(struct e1000_adapter *adapter);extern void e1000_down(struct e1000_adapter *adapter);extern void e1000_reinit_locked(struct e1000_adapter *adapter);extern void e1000_reset(struct e1000_adapter *adapter);extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx);extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);extern void e1000_update_stats(struct e1000_adapter *adapter);#ifdef ETHTOOL_GSTATSstruct e1000_stats { char stat_string[ETH_GSTRING_LEN]; int sizeof_stat; int stat_offset;};#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \ offsetof(struct e1000_adapter, m)static const struct e1000_stats e1000_gstrings_stats[] = { { "rx_packets", E1000_STAT(stats.gprc) }, { "tx_packets", E1000_STAT(stats.gptc) }, { "rx_bytes", E1000_STAT(stats.gorcl) }, { "tx_bytes", E1000_STAT(stats.gotcl) }, { "rx_broadcast", E1000_STAT(stats.bprc) }, { "tx_broadcast", E1000_STAT(stats.bptc) }, { "rx_multicast", E1000_STAT(stats.mprc) }, { "tx_multicast", E1000_STAT(stats.mptc) }, { "rx_errors", E1000_STAT(net_stats.rx_errors) }, { "tx_errors", E1000_STAT(net_stats.tx_errors) }, { "tx_dropped", E1000_STAT(net_stats.tx_dropped) }, { "multicast", E1000_STAT(stats.mprc) }, { "collisions", E1000_STAT(stats.colc) }, { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) }, { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) }, { "rx_crc_errors", E1000_STAT(stats.crcerrs) }, { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) }, { "rx_no_buffer_count", E1000_STAT(stats.rnbc) }, { "rx_missed_errors", E1000_STAT(stats.mpc) }, { "tx_aborted_errors", E1000_STAT(stats.ecol) }, { "tx_carrier_errors", E1000_STAT(stats.tncrs) }, { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) }, { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) }, { "tx_window_errors", E1000_STAT(stats.latecol) }, { "tx_abort_late_coll", E1000_STAT(stats.latecol) }, { "tx_deferred_ok", E1000_STAT(stats.dc) }, { "tx_single_coll_ok", E1000_STAT(stats.scc) }, { "tx_multi_coll_ok", E1000_STAT(stats.mcc) }, { "tx_timeout_count", E1000_STAT(tx_timeout_count) }, { "tx_restart_queue", E1000_STAT(restart_queue) }, { "rx_long_length_errors", E1000_STAT(stats.roc) }, { "rx_short_length_errors", E1000_STAT(stats.ruc) }, { "rx_align_errors", E1000_STAT(stats.algnerrc) }, { "tx_tcp_seg_good", E1000_STAT(stats.tsctc) }, { "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) }, { "rx_flow_control_xon", E1000_STAT(stats.xonrxc) }, { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) }, { "tx_flow_control_xon", E1000_STAT(stats.xontxc) }, { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) }, { "rx_long_byte_count", E1000_STAT(stats.gorcl) }, { "rx_csum_offload_good", E1000_STAT(hw_csum_good) }, { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }, { "rx_header_split", E1000_STAT(rx_hdr_split) }, { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) }, { "tx_smbus", E1000_STAT(stats.mgptc) }, { "rx_smbus", E1000_STAT(stats.mgprc) }, { "dropped_smbus", E1000_STAT(stats.mgpdc) },};#ifdef CONFIG_E1000_MQ#define E1000_QUEUE_STATS_LEN \ ((((((struct e1000_adapter *)netdev->priv)->num_rx_queues > 1) ? \ ((struct e1000_adapter *)netdev->priv)->num_rx_queues : 0 ) + \ (((((struct e1000_adapter *)netdev->priv)->num_tx_queues > 1) ? \ ((struct e1000_adapter *)netdev->priv)->num_tx_queues : 0 ))) * \ (sizeof(struct e1000_queue_stats) / sizeof(u64)))#else#define E1000_QUEUE_STATS_LEN 0#endif#define E1000_GLOBAL_STATS_LEN \ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN + E1000_QUEUE_STATS_LEN)#endif /* ETHTOOL_GSTATS */#ifdef ETHTOOL_TESTstatic const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { "Register test (offline)", "Eeprom test (offline)", "Interrupt test (offline)", "Loopback test (offline)", "Link test (on/offline)"};#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN#endif /* ETHTOOL_TEST */static int e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; if (hw->media_type == e1000_media_type_copper) { ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full| SUPPORTED_Autoneg | SUPPORTED_TP); if (hw->phy.type == e1000_phy_ife) ecmd->supported &= ~SUPPORTED_1000baseT_Full; ecmd->advertising = ADVERTISED_TP; if (hw->mac.autoneg == 1) { ecmd->advertising |= ADVERTISED_Autoneg; /* the e1000 autoneg seems to match ethtool nicely */ ecmd->advertising |= hw->phy.autoneg_advertised; } ecmd->port = PORT_TP; ecmd->phy_address = hw->phy.addr; if (hw->mac.type == e1000_82543) ecmd->transceiver = XCVR_EXTERNAL; else ecmd->transceiver = XCVR_INTERNAL; } else { ecmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE | SUPPORTED_Autoneg); ecmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE | ADVERTISED_Autoneg); ecmd->port = PORT_FIBRE; if (hw->mac.type >= e1000_82545) ecmd->transceiver = XCVR_INTERNAL; else ecmd->transceiver = XCVR_EXTERNAL; } if (E1000_READ_REG(&adapter->hw, E1000_STATUS) & E1000_STATUS_LU) { e1000_get_speed_and_duplex(hw, &adapter->link_speed, &adapter->link_duplex); ecmd->speed = adapter->link_speed; /* unfortunately FULL_DUPLEX != DUPLEX_FULL * and HALF_DUPLEX != DUPLEX_HALF */ if (adapter->link_duplex == FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; else ecmd->duplex = DUPLEX_HALF; } else { ecmd->speed = -1; ecmd->duplex = -1; } ecmd->autoneg = ((hw->media_type == e1000_media_type_fiber) || hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; return 0;}static int e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; /* When SoL/IDER sessions are active, autoneg/speed/duplex * cannot be changed */ if (e1000_check_reset_block(hw)) { DPRINTK(DRV, ERR, "Cannot change link characteristics " "when SoL/IDER is active.\n"); return -EINVAL; } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) msleep(1); if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; if (hw->media_type == e1000_media_type_fiber) hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | ADVERTISED_FIBRE | ADVERTISED_Autoneg; else hw->phy.autoneg_advertised = ecmd->advertising | ADVERTISED_TP | ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; } else { if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); return -EINVAL; } } /* reset the link */ if (netif_running(adapter->netdev)) { e1000_down(adapter); e1000_up(adapter); } else { e1000_reset(adapter); } clear_bit(__E1000_RESETTING, &adapter->state); return 0;}static void e1000_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; pause->autoneg = (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); if (hw->mac.fc == e1000_fc_rx_pause) pause->rx_pause = 1; else if (hw->mac.fc == e1000_fc_tx_pause) pause->tx_pause = 1; else if (hw->mac.fc == e1000_fc_full) { pause->rx_pause = 1; pause->tx_pause = 1; }}static int e1000_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; int retval = 0; adapter->fc_autoneg = pause->autoneg; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) msleep(1); if (pause->rx_pause && pause->tx_pause) hw->mac.fc = e1000_fc_full; else if (pause->rx_pause && !pause->tx_pause) hw->mac.fc = e1000_fc_rx_pause; else if (!pause->rx_pause && pause->tx_pause) hw->mac.fc = e1000_fc_tx_pause; else if (!pause->rx_pause && !pause->tx_pause) hw->mac.fc = e1000_fc_none; hw->mac.original_fc = hw->mac.fc; if (adapter->fc_autoneg == AUTONEG_ENABLE) { if (netif_running(adapter->netdev)) { e1000_down(adapter); e1000_up(adapter); } else { e1000_reset(adapter); } } else { retval = ((hw->media_type == e1000_media_type_fiber) ? e1000_setup_link(hw) : e1000_force_mac_fc(hw)); } clear_bit(__E1000_RESETTING, &adapter->state); return retval;}static u32 e1000_get_rx_csum(struct net_device *netdev){ struct e1000_adapter *adapter = netdev_priv(netdev); return adapter->rx_csum;}static int e1000_set_rx_csum(struct net_device *netdev, u32 data){ struct e1000_adapter *adapter = netdev_priv(netdev); adapter->rx_csum = data; if (netif_running(netdev)) e1000_reinit_locked(adapter); else e1000_reset(adapter); return 0;}static u32 e1000_get_tx_csum(struct net_device *netdev){ return (netdev->features & NETIF_F_HW_CSUM) != 0;}static int e1000_set_tx_csum(struct net_device *netdev, u32 data){ struct e1000_adapter *adapter = netdev_priv(netdev); if (adapter->hw.mac.type < e1000_82543) { if (!data) return -EINVAL; return 0; } if (data) netdev->features |= NETIF_F_HW_CSUM; else netdev->features &= ~NETIF_F_HW_CSUM; return 0;}#ifdef NETIF_F_TSOstatic int e1000_set_tso(struct net_device *netdev, u32 data){ struct e1000_adapter *adapter = netdev_priv(netdev); if (!adapter->flags.has_tso) return data ? -EINVAL : 0; if (data) netdev->features |= NETIF_F_TSO; else netdev->features &= ~NETIF_F_TSO;#ifdef NETIF_F_TSO6 if (adapter->flags.has_tso6) { if (data) netdev->features |= NETIF_F_TSO6; else netdev->features &= ~NETIF_F_TSO6; }#endif DPRINTK(PROBE, INFO, "TSO is %s\n", data ? "Enabled" : "Disabled"); adapter->flags.tso_force = 1; return 0;}#endif /* NETIF_F_TSO */static u32 e1000_get_msglevel(struct net_device *netdev){ struct e1000_adapter *adapter = netdev_priv(netdev); return adapter->msg_enable;}static void e1000_set_msglevel(struct net_device *netdev, u32 data){ struct e1000_adapter *adapter = netdev_priv(netdev); adapter->msg_enable = data;}static int e1000_get_regs_len(struct net_device *netdev){#define E1000_REGS_LEN 32 return E1000_REGS_LEN * sizeof(u32);}static void e1000_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; u32 *regs_buff = p; u16 phy_data; memset(p, 0, E1000_REGS_LEN * sizeof(u32)); regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; regs_buff[0] = E1000_READ_REG(hw, E1000_CTRL); regs_buff[1] = E1000_READ_REG(hw, E1000_STATUS); regs_buff[2] = E1000_READ_REG(hw, E1000_RCTL); regs_buff[3] = E1000_READ_REG(hw, E1000_RDLEN); regs_buff[4] = E1000_READ_REG(hw, E1000_RDH); regs_buff[5] = E1000_READ_REG(hw, E1000_RDT); regs_buff[6] = E1000_READ_REG(hw, E1000_RDTR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -