DM9000网卡驱动源码分析系列04 - ethtool

ethtool是一个用于查看和修改以太网卡配置信息的Linux命令,包括速度、双工模式、驱动信息等。本文详细介绍了ethtool的用途、语法、标志和使用示例,帮助用户理解和运用ethtool进行网络设备的管理和故障排查。
/* ethtool ops */
static void dm9000_get_drvinfo(struct net_device *dev,
			       struct ethtool_drvinfo *info)
{
	struct board_info *dm = to_dm9000_board(dev);

	strlcpy(info->driver, CARDNAME, sizeof(info->driver));
	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
	strlcpy(info->bus_info, to_platform_device(dm->dev)->name,
		sizeof(info->bus_info));
}

static u32 dm9000_get_msglevel(struct net_device *dev)
{
	struct board_info *dm = to_dm9000_board(dev);

	return dm->msg_enable;
}

static void dm9000_set_msglevel(struct net_device *dev, u32 value)
{
	struct board_info *dm = to_dm9000_board(dev);

	dm->msg_enable = value;
}

static int dm9000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
	struct board_info *dm = to_dm9000_board(dev);

	mii_ethtool_gset(&dm->mii, cmd);
	return 0;
}

static int dm9000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
	struct board_info *dm = to_dm9000_board(dev);

	return mii_ethtool_sset(&dm->mii, cmd);
}

static int dm9000_nway_reset(struct net_device *dev)
{
	struct board_info *dm = to_dm9000_board(dev);
	return mii_nway_restart(&dm->mii);
}

static u32 dm9000_get_link(struct net_device *dev)
{
	struct board_info *dm = to_dm9000_board(dev);
	u32 ret;

	if (dm->flags & DM9000_PLATF_EXT_PHY)
		ret = mii_link_ok(&dm->mii);
	else
		ret = dm9000_read_locked(dm, DM9000_NSR) & NSR_LINKST ? 1 : 0;

	return ret;
}

#define DM_EEPROM_MAGIC		(0x444D394B)

static int dm9000_get_eeprom_len(struct net_device *dev)
{
	return 128;
}

static int dm9000_get_eeprom(struct net_device *dev,
			     struct ethtool_eeprom *ee, u8 *data)
{
	struct board_info *dm = to_dm9000_board(dev);
	int offset = ee->offset;
	int len = ee->len;
	int i;

	/* EEPROM access is aligned to two bytes */

	if ((len & 1) != 0 || (offset & 1) != 0)
		return -EINVAL;

	if (dm->flags & DM9000_PLATF_NO_EEPROM)
		return -ENOENT;

	ee->magic = DM_EEPROM_MAGIC;

	for (i = 0; i < len; i += 2)
		dm9000_read_eeprom(dm, (offset + i) / 2, data + i);

	return 0;
}

static int dm9000_set_eeprom(struct net_device *dev,
			     struct ethtool_eeprom *ee, u8 *data)
{
	struct board_info *dm = to_dm9000_board(dev);
	int offset = ee->offset;
	int len = ee->len;
	int done;

	/* EEPROM access is aligned to two bytes */

	if (dm->flags & DM9000_PLATF_NO_EEPROM)
		return -ENOENT;

	if (ee->magic != DM_EEPROM_MAGIC)
		return -EINVAL;

	while (len > 0) {
		if (len & 1 || offset & 1) {
			int which = offset & 1;
			u8 tmp[2];

			dm9000_read_eeprom(dm, offset / 2, tmp);
			tmp[which] = *data;
			dm9000_write_eeprom(dm, offset / 2, tmp);

			done = 1;
		} else {
			dm9000_write_eeprom(dm, offset / 2, data);
			done = 2;
		}

		data += done;
		offset += done;
		len -= done;
	}

	return 0;
}

static void dm9000_get_wol(struct net_device *dev, struct ethtool_wolinfo *w)
{
	struct board_info *dm = to_dm9000_board(dev);

	memset(w, 0, sizeof(struct ethtool_wolinfo));

	/* note, we could probably support wake-phy too */
	w->supported = dm->wake_supported ? WAKE_MAGIC : 0;
	w->wolopts = dm->wake_state;
}

static int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w)
{
	struct board_info *dm = to_dm9000_board(dev);
	unsigned long flags;
	u32 opts = w->wolopts;
	u32 wcr = 0;

	if (!dm->wake_supported)
		return -EOPNOTSUPP;

	if (opts & ~WAKE_MAGIC)
		return -EINVAL;

	if (opts & WAKE_MAGIC)
		wcr |= WCR_MAGICEN;

	mutex_lock(&dm->addr_lock);

	spin_lock_irqsave(&dm->lock, flags);
	iow(dm, DM9000_WCR, wcr);
	spin_unlock_irqrestore(&dm->lock, flags);

	mutex_unlock(&dm->addr_lock);

	if (dm->wake_state != opts) {
		/* change in wol state, update IRQ state */

		if (!dm->wake_state)
			irq_set_irq_wake(dm->irq_wake, 1);
		else if (dm->wake_state && !opts)
			irq_set_irq_wake(dm->irq_wake, 0);
	}

	dm->wake_state = opts;
	return 0;
}

static const struct ethtool_ops dm9000_ethtool_ops = {
	.get_drvinfo		= dm9000_get_drvinfo,
	.get_settings		= dm9000_get_settings,
	.set_settings		= dm9000_set_settings,
	.get_msglevel		= dm9000_get_msglevel,
	.set_msglevel		= dm9000_set_msglevel,
	.nway_reset		= dm9000_nway_reset,
	.get_link		= dm9000_get_link,
	.get_wol		= dm9000_get_wol,
	.set_wol		= dm9000_set_wol,
	.get_eeprom_len		= dm9000_get_eeprom_len,
	.get_eeprom		= dm9000_get_eeprom,
	.set_eeprom		= dm9000_set_eeprom,
};

ethtool的底层驱动的实现,可以看到很多都是直接调用mii的接口

下面附上一些ethtool工具的使用说明:


用途

显示或修改以太网卡的配置信息。

语法

ethtool [ -a | -c | -g | -i | -d | -k | -r | -S |] ethX

ethtool [-A] ethX [autonegon|off] [rxon|off] [tx on|off]

ethtool [-C] ethX [adaptive-rxon|off] [adaptive-txon|off] [rx-usecs N] [rx-frames N] [rx-usecs-irq N] [rx-frames-irqN] [tx-usecs N] [tx-framesN] [tx-usecs-irq N] [tx-frames-irqN] [stats-block-usecsN][pkt-rate-low N][rx-usecs-low N] [rx-frames-low N] [tx-usecs-low N] [tx-frames-low N] [pkt-rate-highN] [rx-usecs-highN] [rx-frames-high N] [tx-usecs-high N] [tx-frames-highN] [sample-interval N]

ethtool [-G] ethX [rx N] [rx-mini N] [rx-jumbo N] [tx N]

ethtool [-e] ethX [rawon|off] [offsetN] [length N]

ethtool [-E] ethX [magic N] [offsetN] [valueN]

ethtool [-K] ethX [rx on|off] [txon|off] [sgon|off] [tso on|off]

ethtool [-p] ethX [N]

ethtool [-t] ethX [offline|online]

ethtool [-s] ethX [speed10|100|1000] [duplexhalf|full] [autoneg on|off] [porttp|aui|bnc|mii] [phyadN] [xcvr internal|external]

[wol p|u|m|b|a|g|s|d...] [sopass xx:yy:zz:aa:bb:cc] [msglvl N]

描述

Ethtool命令用于获取以太网卡的配置信息,或者修改这些配置。

ethX是以太网卡的名称,Linux系统将检测到的第一块以太网卡命名为eth0, 第二块为eth1,…….。

标志
-a查看网卡中 接收模块RX、发送模块TX和Autonegotiate模块的状态:启动on 或 停用off
-A修改网卡中 接收模块RX、发送模块TX和Autonegotiate模块的状态:启动on 或 停用off
-cdisplay the Coalesce information of the specified ethernet card
-CChange the Coalesce setting of the specified ethernet card
-gDisplay the rx/tx ring parameter information of the specified ethernet card
-Gchange the rx/tx ring setting of the specified ethernet card
-i显示网卡驱动的信息,如驱动的名称、版本等
-d显示register dump信息, 部分网卡驱动不支持该选项
-e显示EEPROM dump信息,部分网卡驱动不支持该选项
-E修改网卡EEPROM byte
-k显示网卡Offload参数的状态:on 或 off,包括rx-checksumming、tx-checksumming等。
-K修改网卡Offload参数的状态
-p用于区别不同ethX对应网卡的物理位置,常用的方法是使网卡port上的led不断的闪;N指示了网卡闪的持续时间,以秒为单位。
-r如果auto-negotiation模块的状态为on,则restarts auto-negotiation
-S显示NIC- and driver-specific 的统计参数,如网卡接收/发送的字节数、接收/发送的广播包个数等。
-t让网卡执行自我检测,有两种模式:offline or online
-s修改网卡的部分配置,包括网卡速度、单工/全双工模式、mac地址等
示例
  1. 查看机器上网卡的速度:百兆还是千兆,请输入:

ethool eth0

操作完毕后,输出信息中‘Speed:’ 这一项就指示了网卡的速度。

  1. 停止网卡的发送模块TX,请输入:

ethtool -A tx off eth0

操作完毕后,可输入:ethtool -a eth0,查看tx模块是否已被停止。

  1. 查看网卡eth0采用了何种驱动,请输入:

ethtool -i eth0

操作完毕后,显示 driver: bnx2;version: 1.4.30 等信息。

  1. 关闭网卡对收到的数据包的校验功能,请输入:

ethtool -K eth0 rx off

操作完毕后,可输入:ethtool –k eth0,查看校验功能是否已被停止。

  1. 如果机器上安装了两块网卡,那么eth0对应着哪块网卡呢?输入:

ethtool -p eth0 10

操作完毕后,看哪块网卡的led灯在闪,eth0就对应着哪块网卡。

  1. 查看网卡,在接收/发送数据时,有没有出错?请输入:

ethtool –S eth0

  1. 将千兆网卡的速度降为百兆,请输入:

ethtool -s eth0 speed 100

数据来源

Ethtool命令显示的信息来源于网卡驱动层,即TCP/IP协议的链路层。

该命令在Linux内核中实现的逻辑层次为:

最重要的结构体struct ethtool_ops,该结构体成员为用于显示或修改以太网卡配置的一系列函数指针,见下表中的第二列

网卡驱动负责实现(部分)这些函数,并将其封装入ethtool_ops结构体,为网络核心层提供统一的调用接口。因此,不同的网卡驱动会给应用层返回不同的信息。

Ethtool命令选项、struct ethtool_ops成员函数、Ethtool命令显示参数的来源,三者间的对应关系如下表所示。

命令选项struct ethtool_ops成员函数Ethtool命令显示参数的来源(以网卡驱动BNX2为例)

-s

get_settingsget_wol

get_msglevel

get_link

set_settings

set_wol

set_msglevel

网卡寄存器中获得网卡速度等信息,可配置
-a-Aget_pauseparam set_pauseparam网卡寄存器中获得 Autonegotiate/RX/TX模块的状态:on oroff,可配置
-c-Cget_coalesceset_coalesce网卡寄存器中获得coalescing参数:TX/RX一个数据包后,推迟发生TX/RX中断的时间(us)/数据包个数—减小该值可以提高网卡的响应时间。

当rx-usecs&rx-frames同时被设为0时,RX中断停止。

当tx-usecs&tx-frames同时被设为0时,TX中断停止。

-g-Gget_ringparam set_ringparam当前TX/RX ring的值(从网卡寄存器中读取得到,可配置)外,其它为网卡bnx2自己固定的信息。
-k

-K

get_rx_csumget_tx_csum

get_sg

get_tso

set_rx_csum

set_tx_csum

set_sg

set_tso

显示信息从保存该状态的变量中读取得到,没有对应的寄存器。因此,TX/RX校验等模块一直处于on状态,实际上是无法修改的。
-iget_drvinfo[self_test_count,

get_stats_coun,t

get_regs_len,

get_eeprom_len]

网卡bnx2自己固定的信息,如——————————————————–

driver: bnx2

version: 1.4.30

firmware-version: 1.8.0.5

bus-info: 0000:09:00.0

——————————————————–

-dget_drvinfoget_regs不支持,即bnx2中没有实现函数get_regs
-e-Eget_eepromset_eeprom不支持,即bnx2中没有实现函数get_eeprom
-rnway_reset配置网卡MII_BMCR寄存器,重启Auto negotiation模块
-pphys_id配置网卡BNX2_EMAC_LED寄存器,实现LED闪功能
-tself_test通过配置网卡寄存器,逐一测试网卡的硬件模块:registers,memory,loopback,Link stat,interrupt
-Sget_ethtool_stats显 示信息来源于网卡驱动中的结构体变量stats_blk。(网卡通过DMA方式,将寄存器BNX2_HC_STATISTICS _ADDR_L和BNX2_HC_STATISTICS_ADDR_H中的数据实时地读取到结构体变量struct statistics_block *stats_blk中。)

—显示的数据都是从网卡寄存器中统计得到的,各项的含义需查询网卡(芯片)手册。

由上可见,ethtool命令用于显示/配置网卡硬件(寄存器)。

参考链接:http://www.cnblogs.com/xf-linux-arm-java-android/p/3742720.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值