一、BDF&配置空间
系统在启动过程中会枚举所有的pcie设备,当这些设备加载完成之后,软件上是根据什么信息来找到其中的某一设备的呢?就是BDF,即 Bus number、Devicesnumber、Function number。如下图中 Bus number 为 01,Devicesnumber 为 00,Function number 为 0。
每一个 PCIe 设备可以只有一个功能(Function),即 Fun0。也可以拥有最多 8 个功能,即多功能设备(Multi-Fun)。不管这个 PCIe 设备拥有多少个功能,其每一个功能都有一个唯一独立的配置空间(Configuration Space)与之对应。
看一下 PCI 配置空间具体信息如下
配置空间类型分为两种,一种为EP(设备)、一种为桥片,共为256字节。在引入 PCIe 时,原始的256字节配置区域没有足够的空间来容纳所有需要的新能力结构。因此,配置空间的大小从每个功能的 256 字节扩展到 4KB,称为扩展配置空间(Extended Configuration Space)。
在 BDF 中,Bus Number占用 8 位,Device Number占用 5 位,Function Number占用 3 位。显然,PCIe总线最多支持256个子总线,每个子总线最多支持32个设备,每个设备最多支持 8 个功能。因此配置空间最大为 256bus * 32device * 8function * 4KB = 256M,服务器上可以通过 /proc/iomem 查看地址范围:
二、Memory Address Space(存储器地址空间)
Memory Address Space 是一块用于访问设备内存区域的地址范围。PCI设备可以通过读写事务与系统的主存储器进行数据交换。
使用存储器地址空间时,设备的内存被视为系统内存的一部分,设备可以像读写主存储器一样读写这些内存区域。
在Linux中,设备驱动程序可以通过内核提供的函数(如ioremap)将设备的存储器地址空间映射到内核虚拟地址空间中。然后,驱动程序可以使用指针对这些内存区域进行读写操作,也可以使用devmem 命令来直接进行读写物理地址。
三、I/O Address Space(I/O地址空间)
I/O Address Space 是一块用于访问设备的I/O端口的地址范围。PCI设备可以通过读写事务与系统的I/O地址空间进行数据交换。
使用I/O地址空间时,设备的I/O端口被视为系统的一部分,设备可以像读写常规I/O端口一样读写这些端口。
在Linux中,设备驱动程序可以使用函数(如inb、outb)来读写设备的I/O端口。例如,在串口设备驱动程序中,可以使用I/O地址空间中的inb和outb函数来读取和写入串口的数据寄存器。