Resource Assignment
ID、IO、Memory三种基本资源是PCIe设备的工作基础。在系统启动时,BIOS会给各个PCIe设备分配如上三种资源,这个过程就是我们常说的枚举(Enumeration)。注意,在进入Linux系统后,内核会重新扫描总线并check资源。
整个枚举过程分为两个阶段,首先扫描设备。其次再对每个设备进行资源分配。
一切从根开始,也就是扫描会从RootComplex开始,并且按照深度优先的方式遍历完所有的设备。在扫描过程中,如果扫描到EP,则返回。如果是桥,则继续往桥后扫描,总线号增加。扫描完成后,就得到了整个PCIe大树的整体形状,也就是我们所说的整个PCIe拓扑。资源的分配也是从RC开始,同样按照深度优先方式遍历,为每个设备分配必要的资源。
每个PCIe设备的资源大小是怎么确定的呢?Spec规定,每个PCIe设备都有6个寄存器来向系统声明它需要什么样的资源以及大小。这6个寄存器称之为BAR(Base AddressRegister),从BAR0到BAR5。当向这些寄存器写全1,并再读取这些寄存器的值。第一个的非0的bit位即是此设备需要的资源大小。举个例子,假设我们写0xFFFF_FFFF到BAR0,回读的值为0xFFFF_0000,低16bit为零,意味着整个BAR的大小需要216 = 64K bytes。确认PCIe设备资源大小后,BIOS就把系统分配给这个设备的地址写入到这个BAR里面。驱动程序只需要读取这个BAR寄存器,获取地址后,就可以操作对应的额数据了。
Bar address: Bit0 标示是IO还是Memory,bit0=1, IO address, bit0=0 memory address。 bit1/2 用来标示是64Bit access 还是32bit access。 Bit1/2=00 表示32 bit address。Bit3为prefetchable