3. 网卡设备的注册与初始化
网卡设备的注册与初始化是在其相关的驱动程序的e1000_probe()函数中实现的,有关设备如何与该驱动相关联,以及如何调用到e1000_probe()的,在此不作介绍。在函数e1000_probe()中首先调用函数pci_enable_device()启用设备,然后声明了DMA空间,接着调用函数alloc_etherdev()生成结构体net_device,该结构体就表示了网卡设备,对net_device的参数进行了初始化后,调用register_netdev()注册该设备。
以上仅是对设备的注册,设备的初始化主要包括对两个结构体的赋值,一个是net_device,另一个则是e1000_adapter。对e1000_adapter的初始化包括对其中的e1000_hw结构的初始化,其调用函数e1000_sw_init()实现。在对e1000_hw的初始化过程中使用了ioremap()实现了网卡硬件地址与内存虚拟地址之间的映射。
对网卡设备进行撤销则调用函数free_netdev()实现。有关网卡设备注册与初始化的更详细的过程可以参考《Understanding Linux Network Internals》。
4. 网卡设备的启动与关闭
网卡设备启动时首先调用函数e1000_open(),在该函数中调用e1000_request_irq()申请中断号及其相应的中断处理程序e1000_intr(),其实际是调用request_irq()函数来实现的。在函数e1000_open()中调用e1000_setup_all_tx_resources()根据发送队列数建立发送缓冲区,每个缓冲区的建立由函数e1000_setup_tx_resources()实现,在e1000_setup_tx_resources()中,主要是对描述发送缓冲区的结构体e1000_tx_ring的初始化,其将DMA缓冲区与网卡所映射的虚拟地址空间联系起来,使用函数pci_alloc_consistent()实现一致性映射。而虚拟地址空间与网卡的物理地址相对应,故而这三种空间就对应了起来,DMA也就可以在此基础上实现了,当数据包内容被映射到DMA缓冲区后,其将完全由设备操控。DMA的缓冲区的初始化在驱动程序的e1000_probe()函数中实现。e1000_open()函数会调用e1000_up()对网卡的一些相关的软硬件参数与空间进行配置,如硬件寄存器的读写,数据包接收与发送空间的处理函数的初始化等。发送缓冲空间的初始化结构及相互间的关系如图4-1所示。
接收缓冲区的初始化与上述类似,由e1000_setup_all_rx_resources()调用e1000_setup_rx_resources()对结构体e1000_rx_ring进行初始化。接收缓冲空间的结构如图4-2所示。
图4-1 发送缓冲区的结构图
图4-2 接收缓冲区的结构图
网卡的关闭由函数e1000_close()实现,其会首先关闭中断,然后释放中断号,并且会释放网卡申请的相应的空间。