虽然PMD是在用户态实现设备驱动,但还是依赖于内核提供的策略。其中uio模块,是内核提供的用户态驱动框架,而igb_uio是DPDK kit中拥有与uio交互,bind指定网卡的内核模块。
当使用DPDK脚本dpdk-devbind来bind网卡时,会通过sysfs与内核交互,让内核使用指定驱动来匹配网卡。具体的行为向/sys/bus/pci/devices/(pci id)/driver_override写入指定驱动名称,或者向/sys/bus/pci/drivers/igb_uio(驱动名称)/new_id写入要绑定网卡的PCI ID。前者是配置设备,让其选择驱动。后者是是配置驱动,让其支持新的PCI设备。按照内核的文档https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-pci,这两个动作都会促使驱动bind新设备。但是在dpdk-devbind脚本中,还是通过向/sys/bus/pci/drivers/igb_uio(驱动名称)/bind写入pci id来保证bind。—— 也许是处于兼容性考虑吧。
当使用igb_uio bind指定设备后,内核会调用igb_uio注册的struct pci_driver的probe函数,即igbuio_pci_probe。在这个函数中,设置PCI的一些操作(如设置PCI BAR、DMA等),不是重点,那是驱动工程师的职责:) 对于PMD来说,重点是与UIO的交互
uio_event_notify
这个函数很简单:1. 增加uio设备的“事件”数; 2. 唤醒在idev->wait等待队列中的task;3. 使用信号异步通知async_queue队列中的进程;目前DPDK没有使用异步IO的方式,所有对于DPDK的PMD来说,只有前两个语句有用。
uio模块除了实现了上面的“事件”通知,还支持了mmap方法,用于将注册的uio设备的“内存空间”映射到应用空间。其mmap的函数为uio_mmap,关键代码如下:
在pci_uio_alloc_resource中,主要是打开dpdk要管理的uio设备
在pci_uio_alloc_resource中,主要是打开dpdk要管理的uio设备
PMD同时,DPDK还需要把PCI设备的BAR映射到应用层。在pci_uio_map_resource函数中,除了调用上图中的pci_uio_alloc_resource,还会调用pci_uio_mPMDap_resource_by_index做资源映射。