PCIe架构定义了4种地址空间:配置空间、Memory空间、IO空间和message空间。
1. 配置空间
每个PCIe Function都有4KB的配置空间(Configuration Space)。前256 Bytes是和PCI兼容的配置空间,剩余的是PCIe扩展配置空间(Extended Configuration Space)。PCIe配置空间如下图所示,地址范围为0x000~0xfff。
软件可以通过配置空间来对设备的状态进行控制和检查。PCI兼容的配置空间可以通过CAM或者ECAM机制来访问,而PCIe扩展配置空间只能通过ECAM机制来访问。
PCIe Enhanced Configuration Access Mechanism (ECAM)是访问PCIe配置空间的一种机制。是将PCIe的配置空间映射到MEM空间,使用MEM访问其配置空间的一种实现。
PCI兼容的配置空间Header如下图,大小是64B,分为Type0和Type1。Type 0有6个BAR(每个大小为32bit),Type 1有2个BAR。Type 1 Header存在于所有Bridge设备中,即每个Switch和RC都有1个Type 1 Header。Type 0 Header只存在于非Bridge设备中,即Endpoint设备。
2. IO空间
PCIe支持I/O空间,以便与需要使用I/O空间的传统设备(legacy device)兼容,即PCI或PCI-x设备。IO地址空间的大小只有4GB(32-bit)。PCIe spec并不推荐使用I/O空间,推荐使用内存空间映射(MMIO)。
3. memory空间
访问memory的地址空间,即mmio空间,对于32位操作系统来说是4G(2^32),对于64位系统来说,有2^64的空间大小。
此mmio空间和main memory(内存或者主存)是两个概念。MMIO,即Memory Mapped IO,就是把这些IO设备中的内部存储和寄存器都映射到统一的存储地址空间(Memory Address Space)中。
下图是一种通用的memory和IO的映射。PCIe支持的memory地址最多为64bit。图中仅展示了EP所使用的MMIO和IO,但是这种能力并不是EP所独有的。Switch和RC内部也存在着可以通过MMIO和IO地址来进行访问的设备特定寄存器。
图4‑1展示了两种不同类型的MMIO:可预取MMIO(Prefetchable MMIO,P-MMIO)和不可预取MMIO(Non-Prefetchable MMIO,NP-MMIO)。可预取空间有两个属性:
- 读操作不存在副作用。(Reads do not have side effects)
- 允许写合并(Write merging is allowed)
X86采用独立编址的方式,将memory操作与外设IO操作分开了,才有了memory空间和IO空间的区分。ARM采用统一编码的方式。
BAR空间示例 -- 32bit内存地址空间请求
接下来介绍一个获取4KB大小的不可预取MMIO的例子。首先看一下PCIe spec中对BAR寄存器的描述:bit 0指示是Memory空间还是I/O空间,bit[2:1]指示是32-bit映射还是64-bit映射,bit 3表示是否支持预取,为1表示支持预取。bit[3:0]是只读的。当采用64-bit映射时,需要使用2个BAR来定义基地址。
具体过程如下图(1)、(2)、(3)所示:
(1) 表示BAR未初始化的状态,设计者将低bit[11:0]固定为一个数值,属性只读(RO),用来指示需要的memory大小和类型,高位bit(属性RW)用X来表示,即它们的值还未知。
(2) 软件(OS)把每个BAR都通过配置写操作将可写入的bit写为全1(被固定的低位bit不受影响)。除了bit[11:0]以外,所有的bit都被写为1。写全1是为了确定最低位的可写入的bit是哪一位,这个bit的位置指示了请求的地址空间大小。在本例中,最低位可写入的bit为bit 12,因此这个BAR需要请求2^12(4KB)的地址空间。如果最低可写入bit为bit 20,那么就要请求2^20(1MB)的地址空间。
然后软件从BAR0开始,依次读取每个BAR的数值,从而确定各个BAR要请求的地址空间的大小和类型。
(3) 软件通过将起始地址写入BAR0来为BAR0分配一个地址范围。在本例中,这个起始地址为F900_0000h。
至此,对BAR0的配置就完成了。一旦软件使能了命令寄存器(Command register,偏移地址04h)中的Memory Space Enable bit,那么这个设备就会接受地址在F900_0000h-F900_0FFFh(4KB大小)范围的memory请求。
BAR空间示例 -- 64bit内存地址空间请求
上个例子是通过BAR0来请求32-bit的不可预取的MMIO空间。本例介绍通过BAR1和BAR2来请求一块64-bit的可预取MMIO空间(64MB大小)。由于地址是64-bit,因此必须将两个连续相连的BAR一起使用。
跟上个例子一样,将BAR配置过程分为3个节点:
(1) BAR1和BAR2都处于未初始化的状态。设计者将低位BAR(本例中为BAR1)中的低bit固定为一个数值,指示需要的memory大小和类型,高位BAR(BAR2)中的bit则都是可读可写的,没有被固定。
(2) 软件把每个BAR都通过配置写操作将可写入的bit写为全1。除了BAR1中被固定的低位bit以外,所有的bit都被写为1。
软件读取BAR0后,读取下一个BAR(BAR1)来确定设备是否在请求更多的地址空间。一旦BAR1被读取,软件发现设备在请求更多的地址空间,并且是64-bit的可预取MMIO空间。因此软件会读取BAR2,但并不会对BAR2进行低bit的评估,因为软件仅仅是将BAR2当做BAR1发起的64-bit地址请求的高32-bit。
(3) 软件为这一对BAR分配地址范围。软件通过两次配置写操作将64-bit起始地址写入BAR1与BAR2。在本例中,高位BAR的bit 1(BAR pair的bit 33)被置为1,低位BAR的bit 30(BAR pair的bit 30)也被置为1,这表示地址是2_4000_0000h。两个BAR中所有其他可写bit都被清零。
至此,BAR1和BAR2的配置就完成了。一旦软件使能了命令寄存器(Command register,偏移地址04h)中的Memory Space Enable bit,那么设备就会接受所有地址在2_4000_0000h-2_43FF_FFFFh(64MB大小)范围的memory请求。
4. message空间
message空间用来report带内的message和event。例如error message、电源管理消息等。