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

📄 ethtool.c

📁 DELL755 Intel 网卡驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
/*******************************************************************************  Intel PRO/1000 Linux driver  Copyright(c) 1999 - 2008 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 <linux/pci.h>#include <linux/delay.h>#include "e1000.h"#ifdef NETIF_F_HW_VLAN_TX#include <linux/if_vlan.h>#endif#ifdef ETHTOOL_OPS_COMPAT#include "kcompat_ethtool.c"#endifstruct 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.gorc) },	{ "tx_bytes", E1000_STAT(stats.gotc) },	{ "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.gorc) },	{ "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) },	{ "rx_dma_failed", E1000_STAT(rx_dma_failed) },	{ "tx_dma_failed", E1000_STAT(tx_dma_failed) },};#define E1000_GLOBAL_STATS_LEN	\	sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN)static 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 ARRAY_SIZE(e1000_gstrings_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;	u32 status;	if (hw->phy.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;		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;		ecmd->transceiver = XCVR_EXTERNAL;	}	status = er32(STATUS);	if (status & E1000_STATUS_LU) {		if (status & E1000_STATUS_SPEED_1000)			ecmd->speed = 1000;		else if (status & E1000_STATUS_SPEED_100)			ecmd->speed = 100;		else			ecmd->speed = 10;		if (status & E1000_STATUS_FD)			ecmd->duplex = DUPLEX_FULL;		else			ecmd->duplex = DUPLEX_HALF;	} else {		ecmd->speed = -1;		ecmd->duplex = -1;	}	ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||			 hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;	return 0;}static u32 e1000_get_link(struct net_device *netdev){	struct e1000_adapter *adapter = netdev_priv(netdev);	struct e1000_hw *hw = &adapter->hw;	u32 status;		status = er32(STATUS);	return (status & E1000_STATUS_LU);}static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx){	struct e1000_mac_info *mac = &adapter->hw.mac;	mac->autoneg = 0;	/* Fiber NICs only allow 1000 gbps Full duplex */	if ((adapter->hw.phy.media_type == e1000_media_type_fiber) &&		spddplx != (SPEED_1000 + DUPLEX_FULL)) {		e_err("Unsupported Speed/Duplex configuration\n");		return -EINVAL;	}	switch (spddplx) {	case SPEED_10 + DUPLEX_HALF:		mac->forced_speed_duplex = ADVERTISE_10_HALF;		break;	case SPEED_10 + DUPLEX_FULL:		mac->forced_speed_duplex = ADVERTISE_10_FULL;		break;	case SPEED_100 + DUPLEX_HALF:		mac->forced_speed_duplex = ADVERTISE_100_HALF;		break;	case SPEED_100 + DUPLEX_FULL:		mac->forced_speed_duplex = ADVERTISE_100_FULL;		break;	case SPEED_1000 + DUPLEX_FULL:		mac->autoneg = 1;		adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL;		break;	case SPEED_1000 + DUPLEX_HALF: /* not supported */	default:		e_err("Unsupported Speed/Duplex configuration\n");		return -EINVAL;	}	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 (hw->phy.ops.check_reset_block &&	    hw->phy.ops.check_reset_block(&adapter->hw)) {		e_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->phy.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;		if (adapter->fc_autoneg)			hw->fc.original_type = e1000_fc_default;	} 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->fc.type == e1000_fc_rx_pause) {		pause->rx_pause = 1;	} else if (hw->fc.type == e1000_fc_tx_pause) {		pause->tx_pause = 1;	} else if (hw->fc.type == 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->fc.type = e1000_fc_full;	else if (pause->rx_pause && !pause->tx_pause)		hw->fc.type = e1000_fc_rx_pause;	else if (!pause->rx_pause && pause->tx_pause)		hw->fc.type = e1000_fc_tx_pause;	else if (!pause->rx_pause && !pause->tx_pause)		hw->fc.type = e1000_fc_none;	hw->fc.original_type = hw->fc.type;	if (adapter->fc_autoneg == AUTONEG_ENABLE) {		hw->fc.type = e1000_fc_default;		if (netif_running(adapter->netdev)) {			e1000_down(adapter);			e1000_up(adapter);		} else {			e1000_reset(adapter);		}	} else {		retval = ((hw->phy.media_type == e1000_media_type_fiber) ?				hw->mac.ops.setup_link(hw) :				e1000_force_mac_fc_generic(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->flags & FLAG_RX_CSUM_ENABLED);}static int e1000_set_rx_csum(struct net_device *netdev, u32 data){	struct e1000_adapter *adapter = netdev_priv(netdev);	if (data)		adapter->flags |= FLAG_RX_CSUM_ENABLED;	else		adapter->flags &= ~FLAG_RX_CSUM_ENABLED;	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){	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);	int i;	struct net_device *v_netdev;	if (data) {		netdev->features |= NETIF_F_TSO;#ifdef NETIF_F_TSO6		netdev->features |= NETIF_F_TSO6;#endif	} else {		netdev->features &= ~NETIF_F_TSO;#ifdef NETIF_F_TSO6		netdev->features &= ~NETIF_F_TSO6;#endif#ifdef NETIF_F_HW_VLAN_TX		/* disable TSO on all VLANs if they're present */		if (!adapter->vlgrp)			goto tso_out;		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {			v_netdev = vlan_group_get_device(adapter->vlgrp, i);			if (!v_netdev)				continue;			v_netdev->features &= ~NETIF_F_TSO;#ifdef NETIF_F_TSO6			v_netdev->features &= ~NETIF_F_TSO6;#endif			vlan_group_set_device(adapter->vlgrp, i, v_netdev);		}#endif	} tso_out:	e_info("TSO is %s\n", data ? "Enabled" : "Disabled");	adapter->flags |= FLAG_TSO_FORCE;	return 0;}#endifstatic 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 /* overestimate */	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;	u8 revision_id;	memset(p, 0, E1000_REGS_LEN * sizeof(u32));	pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id);	regs->version = (1 << 24) | (revision_id << 16) | adapter->pdev->device;	regs_buff[0]  = er32(CTRL);	regs_buff[1]  = er32(STATUS);	regs_buff[2]  = er32(RCTL);	regs_buff[3]  = er32(RDLEN(0));	regs_buff[4]  = er32(RDH(0));	regs_buff[5]  = er32(RDT(0));	regs_buff[6]  = er32(RDTR);	regs_buff[7]  = er32(TCTL);	regs_buff[8]  = er32(TDLEN(0));	regs_buff[9]  = er32(TDH(0));	regs_buff[10] = er32(TDT(0));	regs_buff[11] = er32(TIDV);	regs_buff[12] = adapter->hw.phy.type;  /* PHY type (IGP=1, M88=0) */	if (hw->phy.type == e1000_phy_m88) {		hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);		regs_buff[13] = (u32)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) */		hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);		regs_buff[17] = (u32)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 */	hw->phy.ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);	regs_buff[24] = (u32)phy_data;  /* phy local receiver status */	regs_buff[25] = regs_buff[24];  /* phy remote receiver status */}static int e1000_get_eeprom_len(struct net_device *netdev){	struct e1000_adapter *adapter = netdev_priv(netdev);	return adapter->hw.nvm.word_size * 2;}static int e1000_get_eeprom(struct net_device *netdev,			    struct ethtool_eeprom *eeprom, u8 *bytes){	struct e1000_adapter *adapter = netdev_priv(netdev);

⌨️ 快捷键说明

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