4.3 Base寄存器和Limit寄存器(Base and Limit Registers)
4.3.1 整体说明(General)
一旦一个Function的BAR们都被编程写入了,这个Function就知道自己所拥有的地址范围了,这意味着这个Function将会把任何目的地址在这一范围内的事务都声明为自己的,这个地址范围就是被写入它的某一个BAR的地址范围。这本身没什么问题,但是更重要的是要认识到,Function要“看到”它应该声明的事务的唯一办法是,它上方的Bridge需要将这些事务向下转发到这个目标Function所连接的相应的链路。因此,每个Bridge(例如Switch的端口和RC端口)都需要知道它下方所存在的可用地址范围,这样Bridge才能确定哪些请求需要从它的主接口(Primary interface,它在上方)被转发到它的次级接口(Secondary interface,它在下方)。如果一个请求的目标地址是这个Bridge下方Function的BAR中的地址,那么这个请求就应该被转发到Bridge的次级接口。
在Bridge的Type 1 Header中有Base寄存器和Limit寄存器,而Bridge下方的地址范围将会被编程写入这两种寄存器。在每个Type 1 Header中可以看到有3套Base和Limit寄存器。之所以需要三套是因为一个Bridge下的地址范围可以被分成三类:
n 可预取内存空间(P-MMIO)
n 不可预取内存空间(NP-MMIO)
n IO空间(IO)
为了解释这些Base和Limit寄存器是如何工作的,让我们在上一节的例子上继续进行讲解,并将上一节例子中那个已经完成BAR配置的EP放在一个Switch的下方,如图 4‑7所示。图中也列出了这个Function中各个BAR所拥有的地址范围。
对于每个下方存在EP的Bridge来说,它的Base和Limit寄存器都需要被编程写入,但在开始这个写入过程之前,我们先来关注一下连接到我们示例EP的Bridge,也就是Switch的Port B。
图 4‑7设置建立Base和Limit寄存器值的示例的拓扑
4.3.2 P-MMIO可预取范围(Prefetchable Range)
Type 1 Header有两对可预取内存base/limit寄存器。被称为Prefetchable Memory Base/Limit的寄存器要储存可预取地址范围的低32bit地址信息。如果这个Bridge支持对64bit地址进行译码,那么另一个被称为Prefetchable Memory Base/Limit Upper 32bits寄存器就也需要被启用,要用它来储存地址范围的高32bit,也就是bit[63:32]。图 4‑8中展示了软件应该写入这些寄存器的值,以此来指示这个Bridge(Switch的Port B)下方的可预取地址范围为2_4000_0000h-2_43FF_FFFFh。这些寄存器的每个字段的含义都被总结在了表 4‑4中。
下面对表 4‑4中内容进行复述。
n Prefetchable Memory Base寄存器:
n 值为4001h。
n 用法为,寄存器的高12bit用来存放32bit BASE地址的高12bit,也就是[31:20]。Base地址中的低20bit全是0,这意味着Base地址总是在1MB边界上对齐。
寄存器的低4bit用于指示Bridge中是否支持64bit地址译码,这4bit值为1则意味着Upper Base/Limit寄存器要被启用。
n Prefetchable Memory Limit寄存器:
n 值为43F1h。
n 用法与Base寄存器相似,这个寄存器的高12bit用来存放32bit LIMIT地址的高12bit,也就是[31:20]。Limit地址的低20bit为全1(16进制下都是F)。这个寄存器的低4bit和base寄存器的低4bit含义相同。
n Prefetchable Memory Base Upper 32bits寄存器:
n 值为00000002h。
n 用法为,这个寄存器用来存放这个端口下方可预取内存的64bit BASE地址的高32bit。
n Prefetchable Memory Limit Upper 32bits寄存器:
n 值为00000002h。
n 用法为,这个寄存器用来存放这个端口下方可预取内存的64bit Limit地址的高32bit。
图 4‑8示例中Prefetchable Memory Base/Limit 寄存器的值
表 4‑4示例中Prefetchable Memory Base/Limit 寄存器的含义
4.3.3 NP-MMIO不可预取范围(Non-Prefetchable Range)
不可预取内存空间只支持32bit地址,这一点不同于可预取内存空间范围。因此对于不可预取内存空间来说,只有1个base寄存器和1个limit寄存器。按照图 4‑7的示例,Port B的Bridge中的Non-Prefetchable Memory Base/Limit寄存器应该被写入的值被展示在图 4‑9中。这些寄存器的每个字段的含义都被总结在了表 4‑5中。
下面对表 4‑5中内容进行复述。
n Non-Prefetchable Memory Base寄存器:
n 值为F900h。
n 用法为,寄存器的高12bit用来存放32bit BASE地址的高12bit,也就是[31:20]。Base地址中的低20bit全是0,这意味着Base地址总是在1MB边界上对齐。
寄存器的低4bit必须要为0。
n Non-Prefetchable Memory Limit寄存器:
n 值为F900h。
n 用法与Base寄存器相似,这个寄存器的高12bit用来存放32bit LIMIT地址的高12bit,也就是[31:20]。Limit地址的低20bit为全1(16进制下都是F)。这个寄存器的低4bit和base寄存器的低4bit含义相同。
寄存器的低4bit必须要为0。
图 4‑9示例中Non-Prefetchable Memory Base/Limit 寄存器的值
表 4‑5示例中Non-Prefetchable Memory Base/Limit 寄存器的含义
这个例子展示了一个很有趣的情况,那就是实际上Port B下方的EP所拥有的NP-MMIO范围大小为4KB,但是Port B的配置空间却表示出了1MB的范围,这远大于4KB。这是因为Type 1 Header中的base/limit寄存器只能用来表示地址的[31:20]。低20bit也就是[19:0],则会被隐去。因此内存空间base/limit寄存器所能标志的最小范围就是1MB。
在我们的例子中,EP请求并被授予了4KB的NP-MMIO(F900_0000h-F900_0FFFh)。而Port B中NP-MMIO的base/limit寄存器被写入的值则指示了这个Port下存在的NP-MMIO大小为1MB(F900_0000h-F90F_FFFFh),或者说是1024KB。这意味着有1020KB的内存地址空间(F900_1000h-F90F_FFFFh)被浪费了。即使这样,这些被浪费的地址空间也一定不能被分配给其他的EP,否则这会导致对数据包的路由机制无法工作。
4.3.4 IO范围(IO Range)
类似于可预取内存范围,Type 1 Header中IO base/limit寄存器也有两对。被称为IO Base/Limit的寄存器用于存放IO地址范围的低16bit地址信息。若这个Bridge支持32bit IO地址的译码操作(现实设备中很少见),那么就要启用IO Base/Limit Upper 16Bits寄存器来存放地址信息的高16bit,也就是IO地址范围的[31:16]。按照我们的前面的示例,在图 4‑10中给出了软件要写入这些寄存器的值,以此来表示这个Bridge(Port B)之下存在的IO地址范围为4000h-4FFFh。这些寄存器的每个字段的含义都被总结在了表 4‑6中。
下面对表 4‑6中内容进行复述。
n IO Base寄存器:
n 值为40h。
n 用法为,寄存器的高4bit用来存放16bit BASE地址的高4bit,也就是[15:12]。Base地址中的低12bit全部被设置为0,这意味着Base地址总是在4KB边界上对齐。
寄存器的低4bit用于指示Bridge中是否支持32bit地址译码,这4bit值为1则意味着Upper Base/Limit寄存器要被启用。
n IO Limit寄存器:
n 值为40h。
n 用法与Base寄存器相似,这个寄存器的高4bit用来存放16bit LIMIT地址的高4bit,也就是[15:12]。Limit地址的低12bit为全1(16进制下都是F)。这个寄存器的低4bit和base寄存器的低4bit含义相同。
n IO Base Upper 32bits寄存器:
n 值为0000h。
n 用法为,这个寄存器用来存放这个端口下方IO地址空间的32bit BASE地址的高16bit。
n IO Limit Upper 32bits寄存器:
n 值为0000h。
n 用法为,这个寄存器用来存放这个端口下方IO地址空间的32bit Limit地址的高16bit。
图 4‑10示例中IO Memory Base/Limit 寄存器的值
表 4‑6示例中IO Base/Limit 寄存器的含义
在这个例子中,我们又看到了一种情况,Bridge被编程写入的地址空间要远大于其下方的Function所拥有的的实际IO地址空间。例子中EP拥有的地址空间为256Byte(4000h-40FFh)。而Port B被编程写入的值却表示其下方存在的IO地址空间为4KB(4000h-4FFFh)。同前面讨论MMIO时一样,这也是Type 1 Header的一种局限。对于内存地址空间来说,低12bit(bit[11:0])的值是被隐去的,因此能被指定的IO地址范围的最小值就是4KB。这种局限比内存范围中的1MB最小窗口(1MB minimum window)要更加严重。在基于x86(Intel兼容)的系统中,处理器仅支持16bit的IO地址空间,而由于IO地址信息仅有bit[15:12]是可以被指定在Bridge中,这就意味着一个系统中最多就只能有16个(2^4)不同的IO地址范围。
4.3.5 未被使用的Base和Limit寄存器
并不是每个PCIe设备都会使用全部的3种地址空间(P-MMIO、NP-MMIO、IO)。实际上,PCIe协议中不鼓励使用IO地址空间,支持这种操作仅仅是受一些传统遗留因素影响,并有可能在未来新版本的协议中被弃用。
我们来假设这种情况,一个EP中并没有请求使用所有的3种地址空间,那么对于这样的设备上方的Bridge来说,它的base和limit寄存器应该被配成什么值呢?首先,我们肯定不能简单地就把它们写入全0,因为低位的被隐去的地址bit依然是不同的(base中低位bit认为全0,limit中低位bit认为全F),这依然会表示出一个有效的地址范围。所以为了解决这些情况,就必须令base寄存器中的写入值大于limit寄存器的写入值。例如,如果一个EP并没有请求IO地址空间,那么这个Function上方直接相连的Bridge将会把IO Limit寄存器写为00h,将IO Base寄存器写为F0h。由于Base地址大于Limit地址,Bridge会知道这是一个无效的设置,并以此来认定其下方没有Function拥有IO地址空间。(这里原书中有误,写成了将limit配置为大于base,这个错误在errata中已经列出)
这种使base和limit寄存器无效化配置的方法对于所有的3种base/limit寄存器都是可行的,而不只是针对IO base/limit寄存器。
4.4 理解检查:对所有地址路由的寄存器(Sanity Check:Registers Used For Address Routing)
为了确保你已经理解了设置建立BARs和Base/Limit寄存器的规则和方法,请仔细查看图 4‑11,以保证你对它们的正确认知。我们简单的对示例系统进行了扩展,在Switch的Port A下方加入了另一个EP以及它所请求的地址空间。要记得,Type 1 Header中也含有2个BAR,它们也可以请求地址空间。而一个Bridge的Base/Limit寄存器表示的地址空间范围并不包括Bridge自身的BAR所请求的地址空间,也就是说Base/Limit寄存器只表示Bridge下方存在的地址空间。
图 4‑11最终的地址路由示例建立
原文: Mindshare
译者: Michael ZZY
校对: Karl DGR
欢迎参与 《Mindshare PCI Express Technology 3.0 一书的中文翻译计划》
https://gitee.com/ljgibbs/chinese-translation-of-pci-express-technology
转载自:知乎
作者:LogicJitterGibbs
推荐阅读
- PCI Express Technology 3.0:地址空间与事务路由4.1-4.2节
- PCI Express Technology 3.0:PCIe配置概述 3.8-3.14 节(完)
- PCI Express Technology 3.0:PCIe配置概述 3.1-3.7 节
更多招聘及面经请关注FPGA的逻辑。