PCIe设备的配置空间
很多PCI设备仅仅支持者64字节的配置空间。PCI和PCIe配置空间的区别如下文。
此外PCI/PCI-X和PCIe设备还扩展了0x40和0xFF这段配置空间,这段空间主要存放一些与MSI或者MSI-X 中断机制相关的Capability结构。其中所有能够提交中断请求的PCIe设备,必须支持MSI或者MSI-X 中断机制相关的Capability结构。
PCIe设备还支持0x100 -0xFFF这段扩展配置空间。PCIe设备的扩展配置空间最大为4KB,在PCIe总线的扩展配置空间中,存放PCIe所独有的一些Capability结构,而PCI设备不能使用这段空间。
在x86处理器中,使用CONFIG_ADDRESS寄存器与CONFIG_DATA寄存器访问0x00-0xFF,而使用ECAM方式访问0x000-0xFFF这段空间;而在PowerPC处理器中,可以使用CFG_DATA和CFG_ADDR寄存器访问0x000-0xFFF。
PCI- x和PCIe总线规范要求其设备必须支持Capabilities结构。在PCI基本配置空间中有一个Capabilities Pointer寄存器,存放指向Capabilities结构链表的头指针。一个PCIe设备可以包含多个Capability结构,包括电源管理、与 PCIe总线相关的结构、与中断请求相关的结构、PCIe Capability结构和PCIe 扩展Capability结构
PCI/PCIE配置空间按照寄存器的范围可以划分为两大部分。
1. PCI Configuration Space
在PCI规范中,这部分的寄存器范围是从偏移量[0-255],共256字节。
PCI Configuration Space的寄存器,又可细分为以下两种类型,
1.1 PCI Configuration Space Header
PCI Configuration Space Header的范围是头64字节[0,63]。
PCI Configuration Space Header分为type 0和type 1,type 1是专门给桥设备用的,type 0是给其它设备用的。两种类型首部的寄存器定义有相同的部分,规范中称之为Common Header,也有各自相区别的部分,详细内容请参考规范。不论是那种类型,只要确定了,那么它的格式就是确定的,是严格按照规范定义了的。
1.2 PCI Capability List
PCI Capability List位于[64-255]区间范围。
它可以被看做是一个由PCI Capability Item组成的一个链表。链表的头指针就存在了PCI Configuration Space Header的0x34的一字节的寄存器里。有了这个指针,就可以知道链表的第一个Capability Item存在于[64-255]区间的哪个位置。每个Capability Iteam的大小长度范围不都是一样的,但所有Capability Iteam都定义了一个标准化的Cap Header。例如,PCI规范中对Capability Iteam的类型做了严格定义,都给出了Capability的ID号,这个Cap ID就存放在这个Header里。Header里另一个重要的内容就是下一个Capability Iteam的偏移量,以便形成链表。在PCI Capability List的所有存放指针的寄存器都是8位的,因为8位足够在256字节范围内定位了。
具体的Capability类型的定义可能存在于不同的规范中,PCI的基本规范并没有全部覆盖。如果设备自定义Capability只能属于Vendor Specific的类型。标准化了的Capability Item的格式长度是可知的,可以参考相关规范。但对于Vendor Specific类型,由于格式是自定义的,所以规范中给出了求得长度的方法,就是利用存放下一个Capalibity Iteam的寄存器来存放长度。
2. PCIE Extended Configuration Space
在后续的PCIX和PCIE规范中,引入了Extened Configuration Space[256-4095],使得配置空间的范围最大达到4K字节。
扩展的配置空间在PCI-X规范中没有看到更多的说明。在PCIE规范中,扩展的配置空间用于存放PCIE Enhanced Capability List。这个List是一个和PCI Capability List逻辑上类似的一个链表结构,不同的是,链表的
第一个Iteam就位于0x100,即从256字节起始。
Enhanced Capability List Iteam也有一个标准化了的Cap Header, 格式也略有变化,除了Cap ID之外,还有几个bit存放版本号。另外,在Cap header里,存放下一个Cap Iteam的位置的寄存器是12位的,以便能在4K范围内定位。因为PCIE Enhanced Capability List和PCI Capability List在空间上是保证隔离的,因此他们的Cap ID定义不需要考虑编码冲突,不同的Cap Item即可能使用相同的Cap ID的值。
同样的,Enhanced Capability List Iteam也有Vendor Specifc的Iteam用于设备存放自定义的寄存器,其长度值被要求存在指定的寄存器中。
3. 配置空间的访问
一般来说,在x86平台上,有两大类方式可以访问这一区间的寄存器,
3.1 配置机制1#或者配置机制2#
访问时借助in/out指令。请注意,这种方式有别于一般的in/out指令访问PCI的IO空间,它引入了地址端口和数据端口。
配置机制2#只在某些特定的主板上被使用。 新的设计应使用配置机制1#来产生配置空间的物理操作。这种机制使用了两个特定的32位I/O空间,即CF8h和CFCh。这两个空间对应于PCI桥路的两个寄存器,当桥路看到CPU在局部总线对这两个I/O空间进行双字操作时,就将该I/O操作转变为PCI总线的配置操作。寄存器CF8h用于产生配置空间的地址(CONFIG-ADDRESS),寄存器CFCh用于保存配置空间的读写数据(CONFIG-DATA)。 将要访问配置空间寄存器的总线号、设备号、功能号和寄存器号以一个双字的格式写到配置地址端口 (CF8H-CFBH),接着执行配置数据端口 (CFCH)的读和写,向配置数据口写数据即向配置空间写数据,从配置数据口读数据即从配置空间读数据。
3.2 内存映射
访问时借助mov指令,就如访问常规的物理内存一样。
PCI配置空间的寄存器被编址到系统的物理内存空间,在支持ACPI规范x86系统上,操作系统通过读MCFG表获得系统中所有设备PCI配置空间的基地址。操作系统在引导时,枚举PCI设备,从而知道每个PCI设备的Bus, Device, Function号。有了BDF这三个编号,加上从MCFG中得到的基地址,就可以计算出给定设备的PCI配置空间在物理内存空间的地址。
那么,x86上,这两种访问方式的用途和区别在哪里呢?
?首先,配置机制#1只能访问[0-255]偏移之间的寄存器,也就是标准的PCI配置空间的寄存器。对于扩展PCI配置空间的寄存器[256-4095],只能使用内存映射方式访问。
?其次,配置机制#1一般用于操作系统引导时枚举PCI设备阶段,此时系统尝试在BDF的编址空间内对每个可能的BDF来读取PCI配置空间的寄存器,当能成功读取,则认为设备存在,当返回全1的错误码,则认为改设备不存在。显然,内存映射方式是无法在此阶段使用的,因为你可以用配置机制#1来访问不对应实际物理设备的BDF,因为这时最坏情况是得到全1的错误码。但用内存映射方式这样做时,访问不存在的物理地址会产生一个异常。
?最后,某些legacy的PCI设备或者桥片本身就不支持内存映射方式,所以此时配置机制#1是访问PCI配置空间的唯一选择。
4. Big Picture - PCI/PCIE配置空间