PCI Express配置空间PCI-E是用来互联如计算和通信平台应用中外围设备的第三代高性能I/O总线。PCI-E采用了与PCI相同的使用模型和读写(load-store)通信模型,支持各种常见的事务,如存储器读/写、IO读/写和配置读/写事务。其存储器、IO和配置地址空间与PCI的地址空间相同。PCI Express与PCI系统是软件向后兼容的。 PCI-E的配置空间大小为4096字节,如下图所示。其中前256字节是与PCI兼容的配置寄存器,该区域可以用以下两种机制访问:
Memory-mapped I/O (MMIO)与port I/OMMIO和port I/O(也称为port-mapped I/O或PMIO)是两种CPU与外设之间进行I/O操作的方式。 Port I/O是通过特殊的CPU指令来进行I/O操作,在x86架构上,可以通过指令in和out在特定的端口上进行I/O读写。I/O设备拥有与内存不同的地址空间,实现的方式是通过在CPU上额外的I/O pin或者将整个总线赋予端口。 MMIO即内存映射I/O,它是PCI规范一部分,I/O设备被放置在内存空间而不是I/O空。从处理器角度看,内存映射I/O后系统设备访问起来和内存一样。这样访问AGP/PCI-E显卡上的帧缓存,BIOS,PCI设备就可以使用读写内存一样的汇编指令完成,简化了程序设计的难度和接口的复杂性。 对软件人员来说,MMIO比Port I/O更方便使用。 PCI Express扩展配置空间访问《PCI Express Base Specification Revision 1.1》规范中规定了PCI-E扩展配置空间(257~4096字节)的访问方式,即通过MMIO方式访问。 PCI-E规范规定物理内存地址如下表: 规范中只规定了物理地址中A[(20+n-1):20]遵从的规则。因为PCI Express规范最大支持256个总线,所以A[(20+n-1):20]中n的最大值为8。 PCI Express设备配置空间的物理内存地址基址(Base Address)对齐。 最大支持32设备,Device Number A[19:15]占5bit; 最大8个功能号,Function Number A[14:12]占3bit; PCI Express配置空间大小4096字节,因此占用12bit, A[11:8], A[7:2],A[1:0]。 注意:上面的n为CPU架构中支持的最大总线数。 如下面设备Broadcom NetXtreme II 5709网卡 01:00.0 Ethernet controller: Broadcom Corporation NetXtreme II BCM5709 Gigabit Ethernet (rev 20) Bus Number:01 Device Number: 00 Function Number: 00 则对应物理地址低21bit为 A[20]为1 A[19:15]为00000 A[14:12]为000 即01:00.0设备PCI Express配置空间的MMIO物理地址低21bit起始地址为0x100000 x86/x86_64 CPU中PCI Express扩展配置空间访问在上一节中,我们从PCI Express规范来了解扩展配置空间和物理内存地址对应关系,但只提到A[(20+n-1): 0],那么在CPU中的地址高bit(64位CPU为A[63: (20+n)])是由CPU桥片和Firmware来确定。 PCI Express设备配置空间的物理内存地址基址(Base Address)对齐。
在x86/x86_64 CPU默认的是支持最大总线为256,PCI Express设备配置空间所占的内存物理地址范围为0xe0000000-0xefffffff。 下面是Linux内核启动部分打印信息,可以看到BIOS e820图中,将0xe0000000-0xf0000000作为保留区域,给PCI Express配置空间使用, [ 0.000000] BIOS-e820: 0000000000000000 – 000000000009f800 (usable) [ 0.000000] BIOS-e820: 000000000009f800 – 00000000000a0000 (reserved) [ 0.000000] BIOS-e820: 00000000000ca000 – 00000000000cc000 (reserved) [ 0.000000] BIOS-e820: 00000000000dc000 – 00000000000e4000 (reserved) [ 0.000000] BIOS-e820: 00000000000e8000 – 0000000000100000 (reserved) [ 0.000000] BIOS-e820: 0000000000100000 – 000000001fef0000 (usable) [ 0.000000] BIOS-e820: 000000001fef0000 – 000000001feff000 (ACPI data) [ 0.000000] BIOS-e820: 000000001feff000 – 000000001ff00000 (ACPI NVS) [ 0.000000] BIOS-e820: 000000001ff00000 – 0000000020000000 (usable) [ 0.000000] BIOS-e820: 00000000e0000000 – 00000000f0000000 (reserved) [ 0.000000] BIOS-e820: 00000000fec00000 – 00000000fec10000 (reserved) [ 0.000000] BIOS-e820: 00000000fee00000 – 00000000fee01000 (reserved) [ 0.000000] BIOS-e820: 00000000fffe0000 – 0000000100000000 (reserved) … … [ 0.834563] PCI: MMCONFIG for domain 0000 [bus 00-ff] at [mem 0xe0000000-0xefffffff] (base 0xe0000000) [ 0.834729] PCI: MMCONFIG at [mem 0xe0000000-0xefffffff] reserved in E820 Linux中如何读写PCI Express配置空间通过上面介绍,我们可以计算出某个具体PCI Express设备配置空间的起始物理内存地址,但Linux内核并不能直接读写这些物理地址,需要将这些物理内存地址映射到内核中的逻辑地址后,才可以读写PCI Express配置空间。具体原因,请参考x86/x86_64 CPU中逻辑地址、线性地址与物理地址。 我会在另外一篇文章中单独介绍Linux PCI-E设备配置空间读取与修改内核详细实现。 |
|