PCI-E是用來(lái)互聯(lián)如計算和通信平臺應用中外圍設備的第三代高性能I/O總線(xiàn)。PCI-E采用了與PCI相同的使用模型和讀寫(xiě)(load-store)通信模型,支持各種常見(jiàn)的事務(wù),如存儲器讀/寫(xiě)、IO讀/寫(xiě)和配置讀/寫(xiě)事務(wù)。其存儲器、IO和配置地址空間與PCI的地址空間相同。PCI Express與PCI系統是軟件向后兼容的。
PCI-E的配置空間大小為4096字節,如下圖所示。其中前256字節是與PCI兼容的配置寄存器,該區域可以用以下兩種機制訪(fǎng)問(wèn):

MMIO和port I/O(也稱(chēng)為port-mapped I/O或PMIO)是兩種CPU與外設之間進(jìn)行I/O操作的方式。
Port I/O是通過(guò)特殊的CPU指令來(lái)進(jìn)行I/O操作,在x86架構上,可以通過(guò)指令in和out在特定的端口上進(jìn)行I/O讀寫(xiě)。I/O設備擁有與內存不同的地址空間,實(shí)現的方式是通過(guò)在CPU上額外的I/O pin或者將整個(gè)總線(xiàn)賦予端口。
MMIO即內存映射I/O,它是PCI規范一部分,I/O設備被放置在內存空間而不是I/O空。從處理器角度看,內存映射I/O后系統設備訪(fǎng)問(wèn)起來(lái)和內存一樣。這樣訪(fǎng)問(wèn)AGP/PCI-E顯卡上的幀緩存,BIOS,PCI設備就可以使用讀寫(xiě)內存一樣的匯編指令完成,簡(jiǎn)化了程序設計的難度和接口的復雜性。
對軟件人員來(lái)說(shuō),MMIO比Port I/O更方便使用。
《PCI Express Base Specification Revision 1.1》規范中規定了PCI-E擴展配置空間(257~4096字節)的訪(fǎng)問(wèn)方式,即通過(guò)MMIO方式訪(fǎng)問(wèn)。
PCI-E規范規定物理內存地址如下表:

規范中只規定了物理地址中A[(20+n-1):20]遵從的規則。因為PCI Express規范最大支持256個(gè)總線(xiàn),所以A[(20+n-1):20]中n的最大值為8。
PCI Express設備配置空間的物理內存地址基址(Base Address)
最大支持32設備,Device Number A[19:15]占5bit;
最大8個(gè)功能號,Function Number A[14:12]占3bit;
PCI Express配置空間大小4096字節,因此占用12bit, A[11:8], A[7:2],A[1:0]。
注意:上面的n為CPU架構中支持的最大總線(xiàn)數。
如下面設備Broadcom NetXtreme II 5709網(wǎng)卡
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
在上一節中,我們從PCI Express規范來(lái)了解擴展配置空間和物理內存地址對應關(guān)系,但只提到A[(20+n-1): 0],那么在CPU中的地址高bit(64位CPU為A[63: (20+n)])是由CPU橋片和Firmware來(lái)確定。
PCI Express設備配置空間的物理內存地址基址(Base Address)


在x86/x86_64 CPU默認的是支持最大總線(xiàn)為256,PCI Express設備配置空間所占的內存物理地址范圍為0xe0000000-0xefffffff。
下面是Linux內核啟動(dòng)部分打印信息,可以看到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

通過(guò)上面介紹,我們可以計算出某個(gè)具體PCI Express設備配置空間的起始物理內存地址,但Linux內核并不能直接讀寫(xiě)這些物理地址,需要將這些物理內存地址映射到內核中的邏輯地址后,才可以讀寫(xiě)PCI Express配置空間。具體原因,請參考x86/x86_64 CPU中邏輯地址、線(xiàn)性地址與物理地址。
我會(huì )在另外一篇文章中單獨介紹Linux PCI-E設備配置空間讀取與修改內核詳細實(shí)現。
聯(lián)系客服