网络设备驱动
上一篇分析的loopback是所谓的"伪设备",即它不对应真实世界中的硬件,而只是一种软件抽象。今天我们来看一个真实硬件设备的驱动程序,它就是Intel 8255x 10/100 Mbps网卡,对应的内核文件是drivers/net/ethernet/intel/e100.c
。
e100
8255x是一系列网卡的统称,包括82557, 82558, 82559, 82550,82551。以82557为例,其硬件模块图如下所示
可以看到,该型网卡主要由三部分组成:
- MAC, 即图中标有82557的部分,是核心部件
- PHY, 即物理层接口设备,与核心部件之间以 MII 连接
- EEPROM, 用来存储相关节点地址和 PCI 配置参数等信息
PCI接口
来到代码的最末,可以看到模块的初始化函数中只是简单的进行了PCI驱动信息的注册。
在pci_driver
结构中,最重要的两个成员分别是id_table
和probe
。前者列出了设备支持的PCI标识信息,后者为当系统发现有匹配的PCI设备插入时所调用的函数。
id_table
中包含以下成员:vendor
, device
, subvendor
, subdevice
, class
, class_mask
, driver_data
。对于Intel的这款网卡来说,vendor
为0x8086
表示Intel,class
为0x0200
表示以太网设备。代码中定义了宏
#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 }
来辅助id_table
信息的填充。从代码可以看到,在这个表里注册的设备可真多呀1。可不要忘了使用MODULE_DEVICE_TABLE()
导出我们的设备列表。
在probe
函数中,除了之前说过的对net_device
结构的填充之外,还要进行PCI相关的初始化操作,关于这部分,可参考内核文档2。主要的API包括:
pci_enable_device()
/pci_disable_device()
pci_request_regions()
/pci_release_region()
pci_set_dma_mask()
pci_iomap()
/pci_iounmap()
说到pci_iomap()
,就不得不提及PCI配置空间。每个PCI设备都至少有256字节的地址空间,其中前64字节是标准化的,我们现在就来看一下这块网卡的配置空间的情况。
为什么说pci_iomap()
跟这个配置空间有关呢。注意图中用红框框起来的部分,那就是所谓的基地址,共有6个,官方名称为PCI_BASE_ADDREESS_0
到PCI_BASE_ADDREESS_5
。而
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);