深入理解Linux网络技术内幕 第6章 PCI层和网卡

数据结构

  • pci_device_id
    pci_device_id设备标识符,这不是Linux使用的本地ID,是根据PCI标准定义的ID

  • pci_dev
    每个PCI设备都会被分派一个pci_dev实例,这个结构由内核引用一个PCI设备

  • pci_driver
    定义PCI层和设备驱动程序之间的接口。这个结构主要由函数指针构成。所有的PCI设备都会使用这个结构。
    name驱动程序的名称
    id_table这是一个pci_device_id向量,用于把一些设备关联到此驱动程序。
    probe函数是当PCI层发现正在搜寻驱动程序的设备pci_device_id 和前边提到的id_table中的某个元素匹配时,就会调用此函数。这个函数应该开启硬件,分配所需的资源等。
    remove函数当驱动程序从内核移除时或者当可热插拔设备删除时,PCI层调用这个函数。

struct pci_driver {
	struct list_head	node;
	const char		*name;
	const struct pci_device_id *id_table;	/* Must be non-NULL for probe to be called */
	int  (*probe)(struct pci_dev *dev, const struct pci_device_id *id);	/* New device inserted */
	void (*remove)(struct pci_dev *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
	int  (*suspend)(struct pci_dev *dev, pm_message_t state);	/* Device suspended */
	int  (*suspend_late)(struct pci_dev *dev, pm_message_t state);
	int  (*resume_early)(struct pci_dev *dev);
	int  (*resume) (struct pci_dev *dev);	/* Device woken up */
	void (*shutdown) (struct pci_dev *dev);
	int  (*sriov_configure) (struct pci_dev *dev, int num_vfs); /* On PF */
	const struct pci_error_handlers *err_handler;
	const struct attribute_group **groups;
	struct device_driver	driver;
	struct pci_dynids	dynids;
};

PCI NIC设备驱动程序注册

PCI设备通过一些独一无二的参数识别一个设备。一般通过vendor和device可以识别设备。
每个设备驱动都会把一个pci_device_id 向量注册到内核中,这个向量中保存有这个驱动可以处理的设备ID。

struct pci_device_id {
	__u32 vendor, device;		/* Vendor and device ID or PCI_ANY_ID*/
	__u32 subvendor, subdevice;	/* Subsystem ID's or PCI_ANY_ID */
	__u32 class, class_mask;	/* (class,subclass,prog-if) triplet */
	kernel_ulong_t driver_data;	/* Data private to the driver */
};

PCI设备驱动程序使用pci_register_driver和pci_unregister_driver向内核注册和注销驱动程序。
sys文件系统中有输出PCI相关总线的信息。

电源管理和网络唤醒

pci_driver 中的suspend和resume函数处理PCI电源管理事件。
这两个函数除了需要负责PCI状态的保存和恢复。
当NIC使用PCI时,这两个函数还需要

  • suspend主要用于停止设备出口队列,使得设备无法再传输。
  • resume重启出口队列,使得设备可以继续传输报文。

PCI NIC驱动程序注册范例

通过这个例子我们可以看到首先代码会定义一个pci_device_id 的向量数组,其中的每个元素就是支持的一个PCI设备类型。
此外驱动程序由e100_init_module进行初始化,会调用pci_register_driver将驱动注册到内核。

#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
	PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
	PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich }
static const struct pci_device_id e100_id_table[] = {
	INTEL_8255X_ETHERNET_DEVICE(0x1029, 0),
	...
	INTEL_8255X_ETHERNET_DEVICE(0x27DC, 7),
	{ 0, }
};
static struct pci_driver e100_driver = {
	.name =         DRV_NAME,
	.id_table =     e100_id_table,
	.probe =        e100_probe,
	.remove =       e100_remove,
#ifdef CONFIG_PM
	/* Power Management hooks */
	.suspend =      e100_suspend,
	.resume =       e100_resume,
#endif
	.shutdown =     e100_shutdown,
	.err_handler = &e100_err_handler,
};

static int __init e100_init_module(void)
{
	if (((1 << debug) - 1) & NETIF_MSG_DRV) {
		pr_info("%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
		pr_info("%s\n", DRV_COPYRIGHT);
	}
	return pci_register_driver(&e100_driver);
}

static void __exit e100_cleanup_module(void)
{
	pci_unregister_driver(&e100_driver);
}

module_init(e100_init_module);
module_exit(e100_cleanup_module);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值