1. 程式人生 > >從cpu角度理解PCIe

從cpu角度理解PCIe

  1. 概述

為什麼需要寫這篇文章,當我閱讀《深入淺出SSD》這篇書籍中PCIe章節時發現,本書籍的側重點是放在PCIe控制器和PCIe協議上,從CPU角度理解PCIe知識偏少,本文對下面幾個知識點做出一些補充。

  1. CPU訪問外設暫存器與記憶體編址方式;
  2. CPU如何訪問PCIe配置空間;
  3. CPU能夠通過暫存器訪問配置空間,為什麼還需要對映PCIe配置空間;
  4. 如何掃描PCIe樹並且為PCIe分配ID;
  5. 如何將pcie域地址對映到儲存器域地址空間。

通過本篇文章將對問題1、2、3做出解答。

  1. 統一編址於獨立編址

CPU編址是程式指令與實體地址線建立連結的方式,在CPU內部有專門的地址集合,編址過程是由CPU體系架構所決定的,參考示意圖如圖 1所示(僅僅代表示意圖,講解一種邏輯結構,不代表實際電路)。CPU編址時就已經指定了0x8000_0000~0xFFFF_FFFF這個地址空間為連線到圖中記憶體的地址線,記憶體如何連線到CPU需要當參考CPU的datasheet,當CPU程式指令對0x8000_0000這個實體地址地址發起訪問時,等價於是在訪問圖中2G記憶體的首地址。

                                                                                                     圖 1

記憶體通過CPU地址匯流排來定址定位,然後通過CPU資料匯流排讀寫資料。CPU的地址匯流排位數是CPU設計時確定,因此一款CPU所能定址的地址範圍是一定的,而記憶體是需要佔用CPU的定址空間的,記憶體與CPU採用匯流排直接連線。

IO指的是與CPU連線的各種外設,CPU訪問各種外設有兩種方式:一種是類似於訪問記憶體的方式,即把外設的暫存器當成記憶體地址讀寫,從文可以以訪問記憶體方式操作外設暫存器。這時,IO與記憶體統一編址,IO地址與記憶體地址在同一個地址空間下,這種編址方式叫做IO與記憶體統一編址。另外一種編址方式是IO地址與記憶體地址分開獨立編址,這種編址方式叫做獨立編址,此時,CPU訪問外設暫存器需要通過CPU特定的指令去訪問外設暫存器,而不能通過地址直接訪問外設暫存器。常見的ARM、PowerPc、MIPS架構都是採用統一編址,X86架構採用獨立編址。

  1. 訪問PCIe配置空間256bytes

PCI匯流排規定訪問配置空間匯流排事務,使用ID號進行定址。PCI裝置ID號由匯流排號(Bus Number)、裝置號(Device Number)和功能號(Function Number)。其中匯流排號在HOST主橋遍歷PCI匯流排樹時確定,在一顆PCI匯流排樹上,匯流排號由系統軟體決定,通常與HOST主橋直接相連線的PCI匯流排編號為0,系統軟體使用DFS(Depth-First Search)演算法掃描PCI匯流排樹上的所有PCI匯流排,並依次編號。一條PCI匯流排的裝置號由PCI裝置的IDSEL訊號與PCI匯流排地址線的連線關係確定,功能號與PCI裝置的具體設計有關。一個PCIe系統最多有256條Bus,每條Bus上最多可以掛在32個裝置,每個PCIe裝置最多有8個功能裝置。

在XX處理器中的HOST主橋中,與PCIE裝置配置相關的暫存器由CFG_ADDR、CFG_DATA等組成。系統軟體使用CFG_ADDR(CFG_ADDR暫存器結構如圖 2所示)和CFG_DATA暫存器訪問PCIe裝置的配置空間,這些暫存器都是採取同一編址(所有記憶體暫存器都使用儲存器對映方式進行定址)。當處理器訪問PCIe配置空間時,首先需要在CFG_ADD暫存器中設定這個PCIe裝置對應的匯流排號、裝置號、功能號和暫存器偏移,然後使能Enable位,之後當處理器對CFG_DATA讀寫訪問時,HOST主橋將這個儲存器讀寫訪問轉換成PCIe配置讀寫請求,並且傳送到PCIe總線上。如果Enable位沒有使能,那麼CPU對暫存器的訪問也就是一個普通IO的訪問,而不能讓HOST轉換成匯流排請求訪問,訪問PCIe配置空間時按照PCIe匯流排標準配置TLP請求,CFG_DATA是讀取的資料或者待寫入的資料。

                                                                                                       圖 2

  1. 31位:Enable位,為1時,對CFG_DATA讀寫才能轉換成PCIe匯流排配置請求。
  2. 30~24位:保留。
  3. 23~16位:匯流排號,最多=256個。
  4. 15~11位:裝置號,最多=32個。
  5. 10~8位:功能號,最多=8個。
  6. 7~2位:暫存器偏移,最多訪問暫存器=64個地址,這裡一個地址是DW,那麼能幹訪問的PCIe配置空間大小為64*4=256Byte,所以訪問PCIe配置空間都是以4位元組對齊訪問的。

走到這裡很多讀者可能就會有這樣的疑問,既然CPU能夠直接通過暫存器訪問配置空間,為啥還會出現配置空間在儲存域地址的對映這一說法呢?下面給出詳細解答。

訪問PCIe配置空間暫存器的方法需要追溯到原始的PCI規範。為了發起PCI匯流排配置週期,Intel(Intel是PCIe龍頭老大,最新的PCIe的規範總是它最先嚐試的)實現的PCI規範使用IO空間的CF8h和CFCh來分別作為索引和資料暫存器,這種方法可以訪問所有PCI裝置的255 bytes配置暫存器。Intel Chipsets目前仍然支援這種訪PCI配置空間的方法。PCIe規範在PCI規範的基礎上,將配置空間擴充套件到4K bytes,至於為什麼擴充套件到4K,具體可以參考PCIe規範,這些配置CFG_ADDR和CFG_DATA暫存器方法仍然可以訪問所有PCIe裝置配置空間的頭255 bytes,但是該方法訪問不了剩下的(255B~4K)配置空間。怎麼辦呢?Intel外一種PCIe配置空間訪問方法。Intel Chipset通過將配置空間對映到記憶體地址空間,PCIe配置空間可以像對對映範圍內的記憶體進行read/write來訪問了。這種對映是由北橋晶片來完成的,但是不同晶片的對映方式也是不同的。目前我查看了ARM晶片的datasheet,確實是這樣的方式。

PCIe規範為每個PCIe裝置添加了更多的配置暫存器,空間為4K,儘管CFG_ADDR和CFG_DATA暫存器方法仍然能夠訪問lower 255 bytes,但是必須提供另外一種方法來訪問剩下的(255B~4K)range暫存器。Intel的解決方案是使用了預留256MB記憶體地址空間,對這段記憶體的任何訪問都會發起PCIe 配置cycle。由於4K的配置空間是directly mapped to memory的,那麼PCIe規範必須保證所有的PCIe裝置的配置空間佔用不同的記憶體地址,按照PCIe規範,支援最多256個bus,每個Bus支援最多32個PCIe devices,每個device支援最多8個function,也就是說:佔用記憶體的最大值為:256 * 32 * 8 * 4K = 256MB。圖 3是ARM Cortex-A9 datasheet記憶體地址分配區域性圖。被PCIe配置空間佔用的256M記憶體空間會遮蔽掉DRAM使用該段記憶體區,這些地址都由CPU出廠時已經固化好了。

                                                                                                    圖 3

  1. PCIe配置空間的記憶體對映對32bit系統的影響

由於PCIe配置空間佔用了256M記憶體空間,而且該被佔用空間對DRAM來說是不可用的,這意味著256M空間消失於系統記憶體,這在32bit系統中更為明顯。比如,在32 bit winxp中(作者目前電腦還是用的XP系統,電腦用了七八年了),理論上可以訪問到的記憶體是4G,如果4G空間都被DRAM給佔用,由於PCIe的存在,被PCIe佔用的那部分記憶體空間對OS來說是不可用的,莫名的消失了最多256M記憶體,其實還有其他外設暫存器需要對映到記憶體,如果是獨立編址就不存在暫存器佔用記憶體。所以在XP系統中實際能夠訪問DRAM空間最大值為3.2G。64位CPU定址不存在這個情況,個地址目前來說應該用不完,這裡讀者需要注意的是CPU有32和64位定址方式,同樣作業系統也有32和64位之分,在Linux系統中主要體現在庫檔案上。

有些CPU沒有直接指定PCIe配置空間的地址範圍,需要讀取某個暫存器的值BaseAddr,這個值就說PCIe配置暫存器在記憶體區域對映的基地址。訪問PCIe裝置配置空間時候需要手動計算訪問PCIe配置空間的地址。計算髮放如下:

SIZE_PER_FUNC = 4K = 1000h

SIZE_PER_DEVICE = 4K * 8 = 8000h

SIZE_PER_BUS = 4K *8* 32 = 100000h

訪問匯流排號為busNo,裝置號為DevNo,功能號為funcNo的offset暫存器的計算公式是:

Memory Address = BaseAddr+ busNo * SIZE_PER_BUS+ devNo * SIZE_PER_DEVICE+ funcNo * SIZE_PER_FUNC+ offset

訪問PCIe配置空間就需要通過匯流排號、裝置號、功能號、暫存器偏移進行轉換成記憶體地址。轉換函式如圖 2所示。

                                                                                                            圖 4

問題4和5在下篇文章中講解,介於作者實力有限。如有錯誤,望讀者給出寶貴的意見。