⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 e1000_ethtool.c

📁 82546千兆网卡驱动程序,支持该系列所有芯片
💻 C
📖 第 1 页 / 共 4 页
字号:
/*******************************************************************************  Intel PRO/1000 Linux driver  Copyright(c) 1999 - 2006 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 "e1000.h"#ifdef	SIOCETHTOOL#include <asm/uaccess.h>extern 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, uint16_t 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_OPS_COMPAT#include "kcompat_ethtool.c"#endif#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(net_stats.rx_packets) },	{ "tx_packets", E1000_STAT(net_stats.tx_packets) },	{ "rx_bytes", E1000_STAT(net_stats.rx_bytes) },	{ "tx_bytes", E1000_STAT(net_stats.tx_bytes) },	{ "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(net_stats.multicast) },	{ "collisions", E1000_STAT(net_stats.collisions) },	{ "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(net_stats.rx_crc_errors) },	{ "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },	{ "rx_no_buffer_count", E1000_STAT(stats.rnbc) },	{ "rx_missed_errors", E1000_STAT(net_stats.rx_missed_errors) },	{ "tx_aborted_errors", E1000_STAT(net_stats.tx_aborted_errors) },	{ "tx_carrier_errors", E1000_STAT(net_stats.tx_carrier_errors) },	{ "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(net_stats.tx_window_errors) },	{ "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) },	{ "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) },#ifdef E1000_COUNT_ICR	{ "txdw", E1000_STAT(icr_txdw) },	{ "txqe", E1000_STAT(icr_txqe) },	{ "lsc", E1000_STAT(icr_lsc) },	{ "rxseq", E1000_STAT(icr_rxseq) },	{ "rxdmt", E1000_STAT(icr_rxdmt) },	{ "rxo", E1000_STAT(icr_rxo) },	{ "rxt", E1000_STAT(icr_rxt) },	{ "mdac", E1000_STAT(icr_mdac) },	{ "rxcfg", E1000_STAT(icr_rxcfg) },	{ "gpi", E1000_STAT(icr_gpi) },#endif};#define E1000_QUEUE_STATS_LEN 0#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 inte1000_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->autoneg == 1) {			ecmd->advertising |= ADVERTISED_Autoneg;			/* the e1000 autoneg seems to match ethtool nicely */			ecmd->advertising |= hw->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 (netif_carrier_ok(adapter->netdev)) {		e1000_get_speed_and_duplex(hw, &adapter->link_speed,		                                   &adapter->link_duplex);		ecmd->speed = adapter->link_speed;		/* unfortunatly 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->autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;	return 0;}static inte1000_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_phy_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->flags))		msleep(1);	if (ecmd->autoneg == AUTONEG_ENABLE) {		hw->autoneg = 1;		if (hw->media_type == e1000_media_type_fiber)			hw->autoneg_advertised = ADVERTISED_1000baseT_Full |				     ADVERTISED_FIBRE |				     ADVERTISED_Autoneg;		else			hw->autoneg_advertised = ecmd->advertising |			                         ADVERTISED_TP |			                         ADVERTISED_Autoneg;		ecmd->advertising = hw->autoneg_advertised;	} else		if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {			clear_bit(__E1000_RESETTING, &adapter->flags);			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->flags);	return 0;}static voide1000_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->fc == E1000_FC_RX_PAUSE)		pause->rx_pause = 1;	else if (hw->fc == E1000_FC_TX_PAUSE)		pause->tx_pause = 1;	else if (hw->fc == E1000_FC_FULL) {		pause->rx_pause = 1;		pause->tx_pause = 1;	}}static inte1000_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->flags))		msleep(1);	if (pause->rx_pause && pause->tx_pause)		hw->fc = E1000_FC_FULL;	else if (pause->rx_pause && !pause->tx_pause)		hw->fc = E1000_FC_RX_PAUSE;	else if (!pause->rx_pause && pause->tx_pause)		hw->fc = E1000_FC_TX_PAUSE;	else if (!pause->rx_pause && !pause->tx_pause)		hw->fc = E1000_FC_NONE;	hw->original_fc = hw->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->flags);	return retval;}static uint32_te1000_get_rx_csum(struct net_device *netdev){	struct e1000_adapter *adapter = netdev_priv(netdev);	return adapter->rx_csum;}static inte1000_set_rx_csum(struct net_device *netdev, uint32_t 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 uint32_te1000_get_tx_csum(struct net_device *netdev){	return (netdev->features & NETIF_F_HW_CSUM) != 0;}static inte1000_set_tx_csum(struct net_device *netdev, uint32_t 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 inte1000_set_tso(struct net_device *netdev, uint32_t data){	struct e1000_adapter *adapter = netdev_priv(netdev);	if ((adapter->hw.mac_type < e1000_82544) ||	    (adapter->hw.mac_type == e1000_82547))		return data ? -EINVAL : 0;	if (data)		netdev->features |= NETIF_F_TSO;	else		netdev->features &= ~NETIF_F_TSO;	DPRINTK(PROBE, INFO, "TSO is %s\n", data ? "Enabled" : "Disabled");	adapter->tso_force = TRUE;	return 0;}#endif /* NETIF_F_TSO */static uint32_te1000_get_msglevel(struct net_device *netdev){	struct e1000_adapter *adapter = netdev_priv(netdev);	return adapter->msg_enable;}static voide1000_set_msglevel(struct net_device *netdev, uint32_t data){	struct e1000_adapter *adapter = netdev_priv(netdev);	adapter->msg_enable = data;}static inte1000_get_regs_len(struct net_device *netdev){#define E1000_REGS_LEN 32	return E1000_REGS_LEN * sizeof(uint32_t);}static voide1000_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;	uint32_t *regs_buff = p;	uint16_t phy_data;	memset(p, 0, E1000_REGS_LEN * sizeof(uint32_t));	regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;	regs_buff[0]  = E1000_READ_REG(hw, CTRL);	regs_buff[1]  = E1000_READ_REG(hw, STATUS);	regs_buff[2]  = E1000_READ_REG(hw, RCTL);	regs_buff[3]  = E1000_READ_REG(hw, RDLEN);	regs_buff[4]  = E1000_READ_REG(hw, RDH);	regs_buff[5]  = E1000_READ_REG(hw, RDT);	regs_buff[6]  = E1000_READ_REG(hw, RDTR);	regs_buff[7]  = E1000_READ_REG(hw, TCTL);	regs_buff[8]  = E1000_READ_REG(hw, TDLEN);	regs_buff[9]  = E1000_READ_REG(hw, TDH);	regs_buff[10] = E1000_READ_REG(hw, TDT);	regs_buff[11] = E1000_READ_REG(hw, TIDV);	regs_buff[12] = adapter->hw.phy_type;  /* PHY type (IGP=1, M88=0) */	if (hw->phy_type == e1000_phy_igp) {		e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,				    IGP01E1000_PHY_AGC_A);		e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_A &				   IGP01E1000_PHY_PAGE_SELECT, &phy_data);		regs_buff[13] = (uint32_t)phy_data; /* cable length */		e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,				    IGP01E1000_PHY_AGC_B);		e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_B &				   IGP01E1000_PHY_PAGE_SELECT, &phy_data);		regs_buff[14] = (uint32_t)phy_data; /* cable length */		e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,				    IGP01E1000_PHY_AGC_C);		e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_C &				   IGP01E1000_PHY_PAGE_SELECT, &phy_data);		regs_buff[15] = (uint32_t)phy_data; /* cable length */		e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,				    IGP01E1000_PHY_AGC_D);		e1000_read_phy_reg(hw, IGP01E1000_PHY_AGC_D &				   IGP01E1000_PHY_PAGE_SELECT, &phy_data);		regs_buff[16] = (uint32_t)phy_data; /* cable length */		regs_buff[17] = 0; /* extended 10bt distance (not needed) */		e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0);		e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS &				   IGP01E1000_PHY_PAGE_SELECT, &phy_data);		regs_buff[18] = (uint32_t)phy_data; /* cable polarity */		e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,				    IGP01E1000_PHY_PCS_INIT_REG);		e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG &				   IGP01E1000_PHY_PAGE_SELECT, &phy_data);		regs_buff[19] = (uint32_t)phy_data; /* cable polarity */		regs_buff[20] = 0; /* polarity correction enabled (always) */		regs_buff[22] = 0; /* phy receive errors (unavailable) */		regs_buff[23] = regs_buff[18]; /* mdix mode */		e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0);	} else {		e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);		regs_buff[13] = (uint32_t)phy_data; /* cable length */		regs_buff[14] = 0;  /* Dummy (to align w/ IGP phy reg dump) */		regs_buff[15] = 0;  /* Dummy (to align w/ IGP phy reg dump) */		regs_buff[16] = 0;  /* Dummy (to align w/ IGP phy reg dump) */		e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);		regs_buff[17] = (uint32_t)phy_data; /* extended 10bt distance */		regs_buff[18] = regs_buff[13]; /* cable polarity */		regs_buff[19] = 0;  /* Dummy (to align w/ IGP phy reg dump) */		regs_buff[20] = regs_buff[17]; /* polarity correction */		/* phy receive errors */		regs_buff[22] = adapter->phy_stats.receive_errors;		regs_buff[23] = regs_buff[13]; /* mdix mode */	}	regs_buff[21] = adapter->phy_stats.idle_errors;  /* phy idle errors */	e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);	regs_buff[24] = (uint32_t)phy_data;  /* phy local receiver status */	regs_buff[25] = regs_buff[24];  /* phy remote receiver status */	if (hw->mac_type >= e1000_82540 &&	   hw->media_type == e1000_media_type_copper) {		regs_buff[26] = E1000_READ_REG(hw, MANC);	}}static inte1000_get_eeprom_len(struct net_device *netdev){	struct e1000_adapter *adapter = netdev_priv(netdev);	return adapter->hw.eeprom.word_size * 2;}static inte1000_get_eeprom(struct net_device *netdev,                      struct ethtool_eeprom *eeprom, uint8_t *bytes){	struct e1000_adapter *adapter = netdev_priv(netdev);	struct e1000_hw *hw = &adapter->hw;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -