2018年8月20日 星期一

PCI Configuration Space

入行BIOS工程師,通常第一份spec就PCI Local Bus Specification Revision 3.0(簡稱PCI spec),PCI 最精髓的地方就是Configuration Space,PCI 的Configuration Space 有256-byte(0h - FFh),它可以被分為兩個部分,分別是"predefined header region" and a "device dependent region"。



Predefined header region的部分又可以分為2個部分,前16 bytes所有的device都是相同的,剩下的bytes則depend on device support的功能決定。

Predefined header region 的Header Type field定義三種不同格式Configuration  space,值為00h的話,格式會如下圖所示,01h則為PCI-to-PCI bridge(有另外一份spec來闡述,這分spec沒有記載),02h則為CardBus Bridges,但最主要是要了解Type 00h的東西。


Vendor ID(Offset 00h)/ Device ID(Offset 02h): 
長度分別為2 bytes,製造device的廠商會給這兩個field一個特別的值。System Software(通常是BIOS) 會去scan 所有的PCI deivce,那如何知道device存不存在(Present or not),則是Read Vendor和Device ID field ,如果return FFFFh /FFFFh,則device不存在。

Revision ID(08h): 
長度為1 byte,d
evice修訂版本號,由Vendor給定。

Header Type
(0Eh)
長度為1 byteBit7用來表示這個device是否為multi-function device,如果為1表示這個device有多個function number.
            (ex. Bus 0/Dev 0/Func0, 
                   Bus 0/Dev 0/Func1,
                   Bus 0/Dev 0/Func2.....等)
Bit0-6則如前面所提到的,用來決定Configuration Space是什麼的Type。

Class Code
(09h): 
長度為3 bytesClass Code用來得知此device的種類為何,可以分為三個bytes(1) Base class(0Bh), (2) Sub-class(0Ah)和(3) Interface(09h),如下圖所示,如果Class code為01h/04h/00h表示它是一個RAID Controller,詳細請參考Appendix D。


Device Control
(04h): 
長度為2 bytes,Device command control regsiter 主要是用來產生或回應PCI cycles。

[1:0]: 是用來當發生有PCI transactions到device的IO space 或 Memory Space時,這些cycles能不能正常被decode,如果為1表示enable,為0則是disable 。
[2]: Bus master,bus master的用意是為了減輕CPU的負擔。當device想要發出DMA transactions,它會assert REQ# signal 來爭取bus的使用權, 當獲得GNT# signal的回應後,這個device就可以使用bus。

[10]: Bit10為device能不能使用INTx來產生interrupt,為1表示disable INTx,為0表示enable,如果disable INTx,通常就會使用MSI/MSI-X來作為interrup來源。


Device Status
(06h)
長度為2 bytes


[3]: 表示現在是不是有interrupt 正在pending,為read only屬性
[4]: 這個bit表示是否有capability list,第一個Capabilities List Pointer會再offset 34h的位置,offset 34h裡面的值為下一個capabilities list的offset位置,然後層層往下串值到ID為00h而停止(如下圖所示)。


Interrupt Pin
(3Dh):
每個PCI device都會有四根interrupt pin,分別為INTA#, INTB#, INTC#, INTD#, 這個register用來表示當device要發出interrupt的時候會用哪一根pin腳。

Base Address Register:
再6.2.5.1有描述到Base address register(簡稱BAR, 在offset 10h - 24h的位置),PCI device有兩種space,也就是IO space和memory space。

圖6-5為Memory Base Address Register的format,bit0為零代表他是個Memory BAR,bit1,2表示Base Address的地址是32或64位元,bit3表示這個memory range是否為prefetchable。Prefetchable代表CPU可以事先發出request來cache這個memory,表示CPU猜測未來這個memory可能會需要用到,等到下次有access這塊memory range的cycles,則會從cache裡拿。

Bit4-31則為Memory range的address,Software可以透過sizing的方式來得知range的大小,假如device需要4 KB的address space,做device的廠商會在device出廠的時候,將register的lower 12 bits hardwire to 0(類似電氣的接地),之後,software可以透過以下幾個步驟的知device所需的size:

    Step1: Software會全部寫1也就是FFFF_FFFFh,
    Step2: Read back會得到FFFF_F00Xh,
    Step3: Clear lower 4 bits(FFFF_F000h) and Invert all bits(FFFh)

所以結果會得到FFFh,也就是4K的address space。


I/O space BAR則如圖6-6所示,bit0為1表示IO BAR,bit1為Reserved,剩下的bit則用來map IO space,IO BAR always 是32-bit register。







2 則留言:

  1. 在下從事測試PC及PCIE相關,感謝資訊。
    常常看到RD用RW tool去看一些link speed, width, L1 capability等資訊
    RD也用RW, 一下8bit byte, 一下32bit dword切來切去都搞的不是很容易理解 XD...

    回覆刪除
    回覆
    1. Windows常用的tool就是RWEverything,但要很熟悉register的欄位位置,還是要一個一個register去比對。
      現在最方便的是Linux系統(例如Ubuntu),打開terminal,使用lspci這個工具,所有資訊都幫你展列的很詳細,完全不用一個一個去對registers,如果你有興趣,指令如下。

      ex. 假設想要看的device bus, dev, func number為 00:01.0,那麼指令為
      lspci -s 00:01.0 -vvvv

      刪除

解析 NVM Express - 透過Linux OS 解析M.2 NVMe SSD

在之前,我撰寫了三篇有關NVMe的文章 ,分別是" 原理NVM Express - NVMe Submission Queue & Completion Queue (SQ & CQ) "、" 原理NVM Express - Admi...