以下文章來源于AdriftCoreFPGA芯研社,作者CNL中子
前言
PCIe 中斷機制主要分為兩類:一類是繼承自傳統(tǒng) PCI 的 物理中斷線(INTx)中斷,通過硬件引腳觸發(fā);另一類是 MSI(Message Signaled Interrupt)中斷,通過向指定內(nèi)存地址寫入數(shù)據(jù)來通知系統(tǒng)。
很多人可能會好奇:為什么現(xiàn)代系統(tǒng)逐漸淘汰了傳統(tǒng)中斷?MSI 相比之下究竟有哪些優(yōu)勢?本文將帶你逐一揭開這些問題的答案。
傳統(tǒng)PCI中斷
虛擬邊帶信號
在老式的 PCI 插槽上,主板是真的有四根物理信號線連著設(shè)備的,分別叫 INTA,INTB,INTC,INTD。

image
但是 PCIe 變成了串行的高速差分線,早就沒有這四根物理引腳了。那老驅(qū)動怎么用呢?
報文模擬
PCIe 規(guī)范發(fā)明了消息報文 (Message TLP)來驅(qū)動 INTx 中斷線產(chǎn)生中斷。

image
電平模擬
物理線的電平有拉高和拉低。所以在 TLP 報文里,必須成對發(fā)送。
當你的設(shè)備想發(fā)中斷時,硬件邏輯組裝一個Assert_INTA (消息碼 20h) 的報文發(fā)出去,告訴主機我把線拉低了。
當主機處理完中斷后,你的硬件邏輯必須再發(fā)一個Deassert_INTA (消息碼 24h) 的報文,告訴主機我把線松開了。如果忘了發(fā) Deassert,系統(tǒng)就會一直被中斷卡死。

image
配置空間
在 PCIe Header 的配置空間里有兩個寄存器,Interrupt Pin (中斷引腳) 和Interrupt Line (中斷線) ,這兩個配置空間里的寄存器僅僅是為傳統(tǒng)中斷 (Legacy INTx) 服務(wù)的。
Interrupt Pin (中斷引腳)
這是硬件管的。
它是由 Device 這一側(cè)在初始化 IP 的時候配置好的。比如寫 1 代表用 INTA,寫 2 代表 INTB。
如果是 Xilinx 7 系列的 PCIe IP,并且是 Single Function(單功能設(shè)備),那么它只支持 INTA。所以你在配置 IP 時這個值通常寫死為 1。
Interrupt Line (中斷線)
這是軟件的草稿紙。
它是一個 8bit (0~255) 的寄存器,里面存的是系統(tǒng)的 irq 編號。
這個編號是上位機軟件(OS)根據(jù)系統(tǒng)中斷路由分配后,通過 RC 下發(fā)配置包寫進來的。
對于底層硬件設(shè)備來說,這個值完全沒有用,它只是給上層軟件驅(qū)動層留的一個存儲位置,方便驅(qū)動程序自己去讀,甚至發(fā)出去的 TLP 包里也根本不需要帶這個值。
INTX的困境
INTx 實在太慢、太難用了。它不僅需要來回發(fā) Assert/Deassert 兩次報文,而且 4 根線常常需要和主板上的其他設(shè)備共享,導致 CPU 每次收到中斷還得挨個去查到底是哪個設(shè)備觸發(fā)的。
如果是做網(wǎng)卡這種需要處理海量網(wǎng)絡(luò)高并發(fā)數(shù)據(jù)的芯片,如果用 INTx,系統(tǒng)性能直接就崩潰了?,F(xiàn)代的網(wǎng)卡設(shè)計,起步就是MSI,或者是支持成千上萬個中斷向量的MSI-X。
現(xiàn)代PCIe中斷
用寫內(nèi)存代替拉信號線
在 MSI 機制下,你的芯片不再需要去拉扯虛擬的信號線(像 INTx 發(fā)送 Assert/Deassert 報文那樣)。
當設(shè)備需要觸發(fā) CPU 中斷時,它直接往一條特定的總線地址發(fā)送一個Memory Write TLP (內(nèi)存寫報文)。
就像送快遞。INTx 是你在樓下按門鈴大喊有快遞,CPU 得自己下樓看是誰的;而 MSI 則是你直接把寫著你名字的包裹塞進 CPU 指定的專屬信箱里。
MSI Capability 結(jié)構(gòu)
既然是往特定地址寫特定數(shù)據(jù),那這個地址和數(shù)據(jù)怎么來呢?這就要靠配置空間里的MSI Capability Register了。
在系統(tǒng)啟動枚舉 PCIe 設(shè)備時,操作系統(tǒng)和你的硬件會這樣配合

image
Message Address (消息地址)
軟件(驅(qū)動)在系統(tǒng)的內(nèi)存空間(通常是 CPU 的 APIC 中斷控制器映射的一段空間)里申請好一個專屬地址,然后把這個地址寫入你配置空間里的Message Address寄存器。如果系統(tǒng)是 64 位的,就會用到帶Message Upper Address的 64-bit 結(jié)構(gòu)。
Message Data (消息數(shù)據(jù))
這是一串特定格式的數(shù)據(jù)包。不同的 CPU 架構(gòu)對這個數(shù)據(jù)格式有不同的定義,內(nèi)核可以通過 API 獲取,填入這個寄存器,為了讓 CPU 能區(qū)分到底是哪個具體的向量觸發(fā)了中斷,PCIe 硬件在發(fā)送報文時,會動態(tài)地把向量的編號(0~31)作為偏移量,加到這個基準 Message Data 的低位上。
當你網(wǎng)卡的某個業(yè)務(wù)模塊(比如收到一個網(wǎng)絡(luò)包)產(chǎn)生中斷請求時,你的 PCIe MAC/應(yīng)用層邏輯,就會去讀取這兩個寄存器里的 Address 和 Data,把它們拼成一個 Memory Write TLP,直接發(fā)給 Host。
Mask & Pending

image
既然 MSI 支持了多達 32 個 Vector,那自然就需要一個 32 bit 的Mask Bits來讓軟件挨個控制這 32 個中斷源誰該靜音,以及一個 32 bit 的Pending Bits讓硬件挨個記錄誰在靜音期間舉手了。為了不讓 CPU 被海量的中斷請求淹沒,PCIe 規(guī)范定義了這套 Mask(屏蔽)和 Pending(掛起)的機制。
我們可以從控制權(quán)和工作流的角度,把這兩個寄存器的作用拆解得清清楚楚:
Mask Bits (屏蔽位)
他是軟件的靜音鍵
誰來控制: 由上層軟件 (OS / 設(shè)備驅(qū)動) 負責讀寫。
有什么用: MSI 模式最多支持 32 個中斷向量 (Vector),這里的 Mask Bits 恰好是 32 bit,每一位對應(yīng)一個向量的掩碼。當軟件把某一位寫為1時,就表示屏蔽 (Mask) 對應(yīng)的中斷向量。
實際場景: 比如 CPU 現(xiàn)在正在處理一段非常關(guān)鍵的代碼,或者正在批量處理網(wǎng)卡剛剛收上來的網(wǎng)絡(luò)包,不想被打擾。驅(qū)動程序就會把對應(yīng)的 Mask Bit 置為 1。這時候,你的網(wǎng)卡硬件就算有天大的事,也不能往主機發(fā)那個中斷 TLP。
Pending Bits (掛起/未決位)
他是硬件的未接來電記錄
誰來控制: 由你的硬件 (DPU 的 RTL 邏輯) 負責置位 (Set) 和清零 (Clear)。軟件只能讀,不能寫。
有什么用: 它是用于掛起中斷的標志。如果在 Mask Bit 被置 1 (靜音) 的這段時間里,你的 DPU 內(nèi)部剛好產(chǎn)生了一個中斷請求,因為被靜音了發(fā)不出去,你的硬件邏輯就會把對應(yīng)的 Pending Bit 拉高。
實際場景: 這相當于給 CPU 留了一個“未接來電”。它保證了在軟件屏蔽中斷的期間,硬件產(chǎn)生的新中斷不會丟失。
系統(tǒng)設(shè)計的聯(lián)動過程
在系統(tǒng)設(shè)計中,處理這兩個寄存器的聯(lián)動邏輯通常是這樣的:
正常情況 (Mask = 0): 硬件產(chǎn)生中斷請求 -> 檢查對應(yīng)的 Mask Bit 為 0 -> 直接組裝一個 Memory Write TLP (即 MSI 報文) 發(fā)給主機 -> Pending Bit 保持 0。
屏蔽情況 (Mask = 1): 硬件產(chǎn)生中斷請求 -> 檢查對應(yīng)的 Mask Bit 為 1 -> 阻斷 TLP 的發(fā)送 -> 將對應(yīng)的 Pending Bit 置為 1。
解除屏蔽 (Mask 1 -> 0): 軟件忙完了,決定放開中斷,通過讀取Peding寄存器知道設(shè)置掩碼時掛起了一個中斷請求。軟件在合理時機清除 Mask Bits,你的硬件邏輯檢測到 Mask Bit 從 1 變 0,且對應(yīng)的 Pending Bit 為 1,就會立刻發(fā)送積壓的 MSI 報文,并同時把 Pending Bit 清零。
MSI的最大優(yōu)勢
MSI 有個巨大的優(yōu)點:它支持多達32 個配置的 vector (向量)。
INTx 因為只有 4 根線,經(jīng)常幾個設(shè)備共用一根,CPU 收到中斷后還得一個個問 是你叫我嗎?。
32 個 vector 意味著你的網(wǎng)卡可以分配 32 個完全獨立的中斷源。
比如:你可以讓 Vector 0 專管網(wǎng)口 0 的接收,Vector 1 管網(wǎng)口 0 的發(fā)送,Vector 2 管錯誤報警
硬件發(fā) MSI TLP 時,會根據(jù)具體的業(yè)務(wù),把對應(yīng)的 Vector 編號(0~31)動態(tài)疊加到前面軟件配好的Message Data的低位里。CPU 收到報文,瞬間就能精準定位是網(wǎng)卡的哪個隊列觸發(fā)了中斷。
MSI-X
剛才聊了 MSI 最多只能支持 32 個 Vector。對于一塊普通的網(wǎng)卡可能夠了,但對于動輒幾百上千個網(wǎng)絡(luò)隊列(Queue)并發(fā)的智能網(wǎng)卡來說,32 個中斷源簡直是杯水車薪。
MSI-X 作為升級版,每個 Function 支持的 Vector 數(shù)量直接飆升到了2048 個。這意味著你的網(wǎng)卡邏輯可以為每一個獨立的業(yè)務(wù)隊列分配一個專屬的中斷通道,徹底告別中斷擁擠。
MSI 只支持一個 MSI address?;貞浺幌聞偛?MSI 的配置空間,系統(tǒng)只分配了一個基地址(Message Address)。如果設(shè)備要發(fā)不同的中斷,只能去修改數(shù)據(jù)包(Message Data)的低位來區(qū)分 Vector。
這導致所有的中斷報文最終都擠向了同一個內(nèi)存地址(通常對應(yīng) CPU 的同一個處理節(jié)點)。
MSI-X 可以支持多個 address。在 MSI-X 的架構(gòu)中,不再把地址寫在配置空間里了,而是直接在你的芯片內(nèi)部(通常是 BAR 空間)開辟一塊專門的內(nèi)存區(qū)域,叫做MSI-X Table。在這張表里,你可以為這 2048 個 Vector 中的每一個,都單獨配置獨立的 Address 和 Data。
MSI-X 最大的實戰(zhàn)價值是對于多核CPU可以均衡地分配資源。
在服務(wù)器環(huán)境里,CPU 都是幾十上百核的。 如果用 MSI(單地址),網(wǎng)卡幾百個隊列產(chǎn)生的中斷全都會砸到同一個 CPU 核心上,導致這個核心忙死(100% 負載),而其他核心閑死,網(wǎng)絡(luò)吞吐量直接卡住。 用了 MSI-X(多地址),系統(tǒng)軟件就可以在 MSI-X Table 里,把 Vector 0 的地址配給 CPU 核 1,把 Vector 1 的地址配給 CPU 核 2……以此類推。這樣網(wǎng)卡的硬件并發(fā)就能完美映射到 CPU 的多核并發(fā)上,真正實現(xiàn)性能的起飛。
寫在最后
PCIe 中斷機制的發(fā)展,本質(zhì)上是一條非常典型的工程演進路徑——從兼容歷史 到 追求性能 再到 面向并行擴展
INTx 誕生在一個設(shè)備數(shù)量少、并發(fā)需求低的時代,它解決的是能不能通知 CPU這個最基礎(chǔ)的問題。而當系統(tǒng)進入高速網(wǎng)絡(luò)、NVMe 存儲、多隊列 DMA 的時代,中斷不再只是通知機制,而是系統(tǒng)性能鏈路中的關(guān)鍵一環(huán)。
這時,MSI 用一次內(nèi)存寫入替代信號線拉扯,讓中斷從共享廣播變成精準投遞;再往后,MSI-X 進一步把中斷從可區(qū)分升級為可擴展,讓硬件并行度能夠真正映射到多核 CPU 架構(gòu)上。
而這,正是 PCIe 體系最核心的設(shè)計哲學之一:讓數(shù)據(jù)更快地流動,讓事件更精準地到達,讓并行真正發(fā)揮價值。
-
中斷
+關(guān)注
關(guān)注
5文章
918瀏覽量
43777 -
PCIe
+關(guān)注
關(guān)注
16文章
1462瀏覽量
88476 -
引腳
+關(guān)注
關(guān)注
16文章
2112瀏覽量
55718
原文標題:一文看懂PCIe中斷
文章出處:【微信號:HXSLH1010101010,微信公眾號:FPGA技術(shù)江湖】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
PCIE MSI中斷的配置
PCI中斷機制分析
PCIe掃盲—PCIe錯誤檢測機制的詳細資料概述
PCIe中斷機制介紹(MSI)
PCIe兩種中斷傳遞方式
Kinetis的中斷機制詳細資料說明
簡述PCI總線的中斷機制
STM32的中斷機制 stm32中斷方式有幾種
簡述MSI和MSI-X中斷機制
Linux內(nèi)核PCIE基礎(chǔ)知識整理
一文看懂PCIe中斷機制
評論