UIO的意思如下:
UIO(Userspace IO)是运行在用户空间的IO技术。Linux系统中一般的驱动设备都是运行在内核空间,而在用户空间用应用程序调用即可,而UIO则是将驱动的很少一部分运行在内核空间,而在用户空间实现驱动的绝大多数功能,使用UIO可以避免设备的驱动程序需要随着内核的更新而更新的问题。
工作原理:
UIO在用户空间下的驱动程序比运行在内核空间的驱动要多得多,UIO框架下运行在内核空间的驱动程序所做的工作很简单,常做的只有两个:分配和记录。设备需要的资源和注册UIO设备和,必须在内核空间,实现的小部分中断应答函数。
UIO内核空间的程序所做的越少越好,在用户空间能完成的,就不需要放在内核空间做(比如说响应中断),这样假如内核有变化,UIO框架中的驱动维护也是比较简单的。对于用户空间的驱动程序,还可以集成到某款应用软件中。因为使用UIO的设备一般比较少见,所以,可以作出这类的驱动,也可以针对某款或者一类设备作出应用程序集成驱动即可。
本文整理下之前的学习笔记,基于DPDK17.11版本源码分析。主要分析一下igb_uio驱动源码。
首先简单介绍一下kernel中的总线-设备-驱动模型,以pci总线为例,pci总线上有两个表,一个用于保存系统中的pci设备,一个用于保存pci设备对应的驱动。每当加载pci设备驱动时,就会遍历pci总线上的pci设备进行匹配,每当插入pci设备到系统中时,热插拔机制就会自动遍历pci总线上的pci设备驱动进行匹配,如果匹配成功则使用此驱动初始化设备。
注册pci总线
可以调用bus_register注册总线。比如下面的pci总线,平台总线和usb总线等。
注册总线后,会在 /sys/bus 下生成总线目录,比如 pci 总线会生成目录 /sys/bus/pci
注册总线后,会生成文件/sys/bus/pci/drivers_autoprobe,写此文件时在kernel中会调用如下函数,如果为1,表示 bus 支持自动探测 device,则加载驱动时,自动遍历所有pci设备进行匹配
注册驱动到pci总线
结构体struct pci_driver表示一个pci设备驱动,其中id_table和dynids用来保存此驱动支持的设备id等信息,如果有匹配的设备,则调用probe函数。
调用函数pci_register_driver注册pci设备驱动。
注册驱动后,会在/sys/bus/pci/drivers目录下创建以驱动名字命名的目录,并在此目录下创建new_id, bind和unbind等sys文件,可以通过这些文件动态修改驱动信息。
向new_id写入"0x0806 0x1521"信息(0x0806表示vendor id,0x1521为device id)时,会调用kernel中的store_new_id,解析相关字段后,保存到动态链表dynids,然后遍历当前所有的pci设备进行匹配。
向bind文件写入网卡的pci地址时,会调用kernel中的bind_store,将此网卡绑定到此驱动。
向unbind文件写入网卡的pci地址时,会调用kernel中的unbind_store,将此网卡和此驱动解绑。
发现pci设备
系统启动时会扫描所有的pci设备,以他们的pci地址为名字创建目录,并在此目录下创建相关的sys文件。并且会遍历所有的pci设备驱动进行匹配。
向设备的driver_override文件写入驱动名字,表示此设备只能绑定到此驱动。
如何匹配?
前面多次提到设备和驱动进行匹配,究竟如何匹配呢?
先看一下用来表示一个pci设备的结构体pci_dev,其中如下几个成员变量表示此pci设备的类型,一般vendor和device就足够,vendor表示此设备是哪个厂商的,device表示此设备的类型。
再看一下用来表示设备驱动的pci_driver,其中id_table和dynids用来保存此驱动支持的设备类型,前者是静态值,后者可以通过驱动目录下的new_id动态添加。设备类型使用pci_device_id结构体来表示,其成员变量也是vendor,device等信息,和pci_dev中的信息是一样的,所以可以使用这几个字段进行匹配。
最终使用函数pci_match_device进行驱动和设备的匹配。
网卡如何绑定到igb_uio驱动呢?这里拿DPDK提供的脚步文件dpdk-devbind.py中的函数bind_one进行分析。
igb_uio驱动的id_table为空,则在加载此驱动时,是不会匹配到任何设备的。
经过上面的分析,有三种方法可以将网卡绑定到驱动igb_uio
igb_uio probe
经过前面的分析网卡绑定到了igb_uio驱动后,会调用驱动的probe函数igbuio_pci_probe,主要做了如下几个事情:
a. 调用pci_enable_device使能pci设备
b. 设置DMA mask
c. 填充struct uio_info信息,注册uio设备
d. 注册中断处理函数
宏uio_register_device用来注册uio设备。
简单总结一下,igb_uio是DPDK使用网卡的一个通用驱动,不只intel网卡可以用,其他厂商的网卡也可以用(有一个例外,mellanox的网卡不用绑定到igb_uio就能被使用DPDK),因为它只使能了pci设备,注册uio,和注册中断处理函数,这些工作是不区分网卡类型的。
加载igb_uio时,不会自动探测pci设备,而是需要写sys文件将设备绑定到igb_uio。
igb_uio依赖uio驱动,注册uio设备后,会生成/dev/uiox,和网卡一一对应,用户态可以poll /dev/uiox监听中断是否到来。
同时uio设备还会将网卡的BAR地址通过sys文件系统暴露出去,用户态可以mmap sys文件后 *** 作网卡寄存器。但是DPDK没有采用这种方式,而是直接mmap网卡自身暴露出去的sys文件 /sys/bus/pci/devices/'pci address'/resource0。
https://www.cnblogs.com/jungle1996/p/12398915.html
https://www.cnblogs.com/jungle1996/p/12452636.html
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)