PCI中斷路由
1
PCI設(shè)備中斷
PCI spec為每個PCI設(shè)備定義了四個中斷引腳,分別是INTA#,INTB#,INTC#和INTD#,如圖:
如果PCI設(shè)備為單功能設(shè)備,則必須使用INTA#,對于多功能設(shè)備,各功能設(shè)備可任意接至PCI 總線的四條中斷申請線INTA# - INTD# 。那么如何設(shè)定某個PCI設(shè)備的某個功能使用那個中斷引腳呢?實際上這個是由PCI設(shè)備制造商決定的,并不能由主板固件后期更改。我們翻出PCI體系結(jié)構(gòu)文中介紹的PCI配置空間,在其中interrupt pin會告知主板固件該func使用了哪個引腳,如圖中紅色圈標(biāo)注:
一個PCI設(shè)備可以有8個func,而4個終端引腳意味著中斷共享不可避免。PCI為了方便中斷共享,定義中斷是電平觸發(fā),低電平有效。中斷信號與PCI CLK異步,設(shè)備一旦Assert為低,則要維持低電平狀態(tài),直到驅(qū)動程序清除這個中斷請求。這樣PCI中斷可以為通過鏈的方式來共享,某個設(shè)備中斷處理完畢后將其電平置高,只有該中斷信號上所有的設(shè)備中斷處理都結(jié)束了,該中斷信號才能恢復(fù)高電平,整個中斷處理才能結(jié)束。實際上中斷共享不僅僅存在PCI設(shè)備各個func中,假設(shè)系統(tǒng)中有10個PCI設(shè)備,每個設(shè)備有4個中斷引腳,要它們每個都獨立意味著中斷控制器需要有40個引腳。我們通過前文知道PIC只有15個引腳,IOAPIC通常有24個引腳,還有很多保留不可用,而一臺計算機內(nèi)部PCI設(shè)備往往超過20個。所以,中斷更需要在設(shè)備之間共享。
讓我們舉個形象的比喻來理解中斷共享的處理。想象操作系統(tǒng)中斷處理調(diào)度器是個嚴(yán)厲的老師,設(shè)備中斷處理例程是一群可愛的小朋友,他們被按照連接在PIC/IOAPIC引腳數(shù)分成若干排。每個小朋友手里都有個按鈕,小朋友想要問問題,就按下按鈕,老師回答完后他會再按一下恢復(fù)彈起狀態(tài)。問題是老師是個近視眼,他看不見后面的小朋友。為了解決這個問題,在每排座位前面安裝了個燈泡,當(dāng)這排小朋友有人的按鍵被按下,燈就亮了。老師上課時,看見第2排燈亮了,他就停下來,問:“第2排第1個小朋友,是不是你要問問題?”得到肯定的答復(fù)就解答該小朋友,否定的話就問下一個,如此往復(fù),直到該排沒有人有問題,燈才滅,老師才能繼續(xù)講課。
看來在老師沒有換個更好的眼鏡或者做個近視矯正手術(shù)之前這是唯一的辦法了。那么該如何為這些小朋友分組呢,老師把這個任務(wù)交給了班長小張。我們幫小張想想,怎么分配才能既公平又上課效率高呢?是不是平均分最好呢?假設(shè)小朋友都很乖,這樣是最好的辦法,但是小張知道班里有個話癆小朋友--小明,他什么都不懂但問題很多,他會頻繁提問。假設(shè)他被分在第3排最后一個,老師每次看到第3排燈亮了,都從第一個小朋友問,經(jīng)過了好久才問到小明,效率好低,小明每次很久才輪到他也很不滿,上課節(jié)奏整體也被拖慢了!
怎么辦?開除小明嗎?可惜小明是校董的兒子,絕對不能少!讓小明坐第一個位置嗎?校規(guī)規(guī)定座位是流水席,每排都先來先坐,再說讓小明又高問題又多,誰坐他后面別想問問題了,太不公平??磥碇挥薪o小明開小灶了,讓他單獨坐一排!
世界上沒有絕對的公平,在資源捉襟見肘時會叫的孩子有奶吃在我們天朝還少嗎?班長小張也只有做些妥協(xié)了。我們的計算機固件和主板硬件工程師在很多時候就扮演了左右為難的小張的角色,在硬件的限制下,盡量保證系統(tǒng)的響應(yīng)時間。他們基于一些簡單的原則:
A. 公平:盡量減少中斷共享。
B. 效率:緊急或者頻繁的設(shè)備可以獨占中斷
同時要充分理解PC系統(tǒng)中絕大多數(shù)設(shè)備都是單功能設(shè)備,所以僅使用INTA#信號,很少使用INTB#和INTC#信號,而INTD#信號更是極少使用。映射INTA#~INTD#到PIC/IOAPIC IRQ的機制稱為“Swizzling”,它在不同情況下實現(xiàn)機制有很大不同,我們分別來看看。
2
PCI/PCIe擴展插槽
對主板上的PCI擴展插槽,用戶插入什么設(shè)備,插在哪個槽內(nèi)都不能在出廠時確定。我們這里要盡量考慮平衡原則和效率原則。我們將所有插槽的INTA#~INTD#分成四組串聯(lián)起來如何?這樣離得最近的Slot 1高興了,每個都是我優(yōu)先!萬一有個用戶把重要的網(wǎng)卡插在slot 4,效率會嚴(yán)重下降。在充分考慮到PCI設(shè)備絕大多數(shù)都是單功能設(shè)備(僅使用INTA#信號,很少使用INTB#和INTC#信號,而INTD#信號更是極少使用),PCI SIG推薦PCI to PCI bridge后slot連接關(guān)系應(yīng)該組成如下圖:
即Slot1 INTA#->Slot2 INT B#->Slot3 INTC#->Slot4 INTD#等等。這樣,當(dāng)然slot 1還是占些小便宜,但其他slot也有很大機會獨占某個中斷線(想想為什么)。這種Swizzling是主板設(shè)計硬件連線決定的,不由主板固件決定,但是主板固件需要了解這些信息。
PCI橋則將它下面的轉(zhuǎn)換結(jié)果INTx轉(zhuǎn)化為本身的INTx,接入芯片組內(nèi)部的Swizzling。PCIe的插槽是1:1對應(yīng)PCIe root port,PCIe root port可以看作PCI橋,等同處理。
3
芯片組內(nèi)部
PCI SIG并沒有規(guī)定芯片組內(nèi)部Swizzling的規(guī)則,而芯片組內(nèi)部設(shè)備在出廠時就已經(jīng)確定了,芯片是不是可以hard code一個中斷路由關(guān)系呢?實際上有些芯片組就是這么做的,在芯片硬件說明書中注明各種PCI設(shè)備INTx到IRQ的關(guān)系表,BIOS只要照著報告給OS就可以了。而Intel芯片組提供了更靈活的方式,BIOS可以根據(jù)需要設(shè)置中斷路由,以適應(yīng)不同的應(yīng)用市場。不同的芯片組設(shè)置方法不同,有些給出了幾組應(yīng)用場景,BIOS可以根據(jù)需要選擇一種,而在很早開始南橋芯片組ICH/PCH就給出了一種更靈活的方式,就是我們前文提到的PIRQ。簡單來說就是在ICH/PCH內(nèi)部加入了幾個新的寄存器:IR寄存器組。IR寄存器組用于設(shè)定芯片組內(nèi)部PCI設(shè)備中斷INTA#-H# 連接到具體PIC/IOAPIC的哪個引腳上。這樣BIOS就可以根據(jù)面向市場不同重新繪制中斷路由圖了,好方便!
OS接口
班長小張終于給小朋友排好了座位,他怎么把這些信息告訴各個老師呢?一個個告訴太麻煩,不如把所有情況打印成一張表貼子講臺上。我們的固件也是通過表告訴OS的,這里有兩種表。
1
MP table
有感于DOS階段中斷設(shè)置的混亂,微軟在推出Win95時聯(lián)合Intel提出了PCI Interrupt Routing Table的數(shù)據(jù)結(jié)構(gòu),它的作用就是用來描述在使用8259中斷控制器的系統(tǒng)下,PCI中斷的路由關(guān)系。它和其他一些表構(gòu)成了傳統(tǒng)的MP table。它只在PIC模式下起作用,而PIC模式已經(jīng)被淘汰,所以它的具體結(jié)構(gòu)我們這里略過。這里要特別指出的是,固件在提交PIRQ table時要同步更新PCI配置空間的Interrupt line寄存器,如圖籃圈部分:
2
ACPI table
在APIC模式下,固件應(yīng)該通過ACPI的_PRT(PCI Routing Table) method返回主板上無論硬件還是固件設(shè)定的中斷路由信息。ACPI spec有示例,但內(nèi)容比較單薄。我們來看一個Intel開源硬件平臺Minnowboard MAX固件是怎么處理的。
_PRT代碼如下:
Method(_PRT,0)
{
If(PICM) {Return(AR00)} // APIC mode
Return (PR00) // PIC Mode
} // end _PRT
這里判斷如果是PIC模式,返回PR00,如果是APIC模式返回AR00表。PR00和AR00其實是同一個中斷路由關(guān)系的兩個view,其實質(zhì)內(nèi)容是一致的。我們單看一下AR00就好:
Name(AR00, Package()
{
// SD Host #0 - eMMC
Package() {0x0010FFFF, 0, 0, 16 },
// SD Host #1 - SDIO
Package() {0x0011FFFF, 0, 0, 17 },
// SD Host #2 - SD Card
Package() {0x0012FFFF, 0, 0, 18 },
// SATA Controller
Package() {0x0013FFFF, 0, 0, 19 },
// xHCI Host
Package() {0x0014FFFF, 0, 0, 20 },
// Low Power Audio Engine
Package() {0x0015FFFF, 0, 0, 21 },
// USB OTG
Package() {0x0016FFFF, 0, 0, 22 },
//
// MIPI-HSI
Package() {0x0017FFFF, 0, 0, 23 },
//
// LPSS2 DMA
// LPSS2 I2C #4
Package() {0x0018FFFF, 0, 0, 17 },
// LPSS2 I2C #1
// LPSS2 I2C #5
Package() {0x0018FFFF, 2, 0, 19 },
// LPSS2 I2C #2
// LPSS2 I2C #6
Package() {0x0018FFFF, 3, 0, 18 },
// LPSS2 I2C #3
// LPSS2 I2C #7
Package() {0x0018FFFF, 1, 0, 16 },
// SeC
Package() {0x001AFFFF, 0, 0, 21 },
//
// High Definition Audio Controller
Package() {0x001BFFFF, 0, 0, 22 },
//
// EHCI Controller
Package() {0x001DFFFF, 0, 0, 23 },
// LPSS DMA
Package() {0x001EFFFF, 0, 0, 19 },
// LPSS I2C #0
Package() {0x001EFFFF, 3, 0, 16 },
// LPSS I2C #1
Package() {0x001EFFFF, 1, 0, 17 },
// LPSS PCM
Package() {0x001EFFFF, 2, 0, 18 },
// LPSS I2S
// LPSS HS-UART #0
// LPSS HS-UART #1
// LPSS SPI
// LPC Bridge
//
// SMBus Controller
Package() {0x001FFFFF, 1, 0, 18 },
//
。。。。
}
通過這張大表,OS才能確定主板PCI設(shè)備和IRQ的連接關(guān)系。
其他中斷信息
除了中斷路由表之外,還有很多和中斷相關(guān)的信息也需要通過ACPI向OS報告
1. LAPIC和IOAPIC
固件需要在ACPI的MADT表里向OS報告所有的LAPIC和IOAPIC。LAPIC默認映射到物理地是0xFEE00000(想想為什么不會互相沖突?),不需要報告,只要LAPIC ID即可。需要特別說明的是,因為APIC ID不一定從0開始,也不一定連續(xù),所以其值要動態(tài)枚舉而得。同時由于很多OS在調(diào)度processor時是挨個調(diào)度的,而HT的兩個thread的APIC ID往往連續(xù),同時被調(diào)度效能大大降低,Intel推薦HT的兩個thread隔開報告。如果多個CPU socket,情況又有變化,這是系統(tǒng)調(diào)優(yōu)的手段之一,這里不再贅述。
IOAPIC的地址和ID都由固件指定,必選準(zhǔn)確的在MADT里向OS報告,每個IOAPIC的GSI偏移量也要報告。
2. SCI
在Intel的芯片組中,SCI通常缺省占用了中斷9。它的值可以在芯片組的寄存器中修改,并需要通過FADT報告OS。因為這是個特殊指定的中斷,所以在MADT中還要通過interrupt override節(jié)予以保留。
-
寄存器
+關(guān)注
關(guān)注
31文章
5359瀏覽量
120831 -
中斷處理
+關(guān)注
關(guān)注
0文章
94瀏覽量
10992 -
中斷控制器
+關(guān)注
關(guān)注
0文章
59瀏覽量
9476 -
PCI協(xié)議
+關(guān)注
關(guān)注
0文章
2瀏覽量
5503 -
調(diào)度器
+關(guān)注
關(guān)注
0文章
98瀏覽量
5264
發(fā)布評論請先 登錄
相關(guān)推薦
評論