標籤:工作 索引 ack 原因 style nbsp 映射 輸入 oss
不同CPU體系間的中斷控制器工作原理有較大差異,本文是《Linux mips64r2 PCI中斷路由機制分析》的姊妹篇,主要分析Broadwell-DE X86_64 APIC中斷路由原理、中斷配置和處理過程,並嘗試回答如下問題:
- 為什麼x86中斷路由使用IO-APIC/LAPIC架構,其有什麼價值?
- pin/irq/vector的區別、作用,取值範圍和分配機制?
x86_64 APIC關鍵概念
Pin
此處的pin特指APIC的中斷輸入引腳,與內外部裝置的中斷輸入訊號相連。從中可以看出,Pin的最大值受APIC管腳數限制,目前取值範圍是[0,23]。其中[0, 15]這16個pin,基於與PIC相容等原因考慮,有固定用途;PIRQ[A..H]這8個引腳為PCI IRQ引腳,為PCI裝置提供中斷路由,其中PIRQ[A..D]為純中斷引腳,PIRQ[E..H]可配置為中斷引腳或GPIO引腳。
內部裝置中斷路由到哪個PIRQ,可以通過DxxIR(Device XX Interrupt Route Register)寄存器設定;外部裝置使用哪個APIC引腳,在硬體PCB設計時即固定下來。
為什麼裝置中斷要經過APIC再與CPU相連,而不直接與CPU相連?原因有二:1)存在大量的外部裝置,但CPU的中斷引腳等資源是很有限的,滿足不了所有的直連需求;2)如果裝置中斷與CPU直接相連,串連關係隨硬體固化,這樣在MP系統中,中斷負載平衡等需求就無法實現了。
Vector
Vector是CPU的概念,以CPU核的角度看,其以vector標識中斷,詳見下節中斷路由原理介紹。
vector是IDT表(idt_table)的索引。
gate_desc idt_table[NR_VECTORS] __page_aligned_data = { { { { 0, 0 } } }, };
vector的個數由硬體決定,從可知,Broadwell-DE X86_64支援最多256個vector。其中前32個為系統保留使用,其他由作業系統動態分配。
vector提供優先順序和親和性綁定的支援,vector的高4位為優先順序,0最低,15最高。CPU只處理優先順序高於LAPIC TPR值的vector中斷。
為什麼在irq之外,又增加個vector概念,兩者是否可以合二為一?不可以,原因主要是:vector是針對每個CPU核的,描述每個CPU核對上報中斷的優先順序處理和親和性關係;而irq是全域的,它維護所有CPU核上的中斷處理相關資訊。
IRQ
在PIC和單核時代,irq、vector、pin這個概念的確是合三為一的,irq就是PIC控制器的pin引腳,irq也暗示著中斷優先順序,例如IRQ0比IRQ3有著更高的優先順序。當進入MP多核時代,多核CPU下中斷處理帶來很多問題(如如何決定哪個中斷在哪個核上處理,如何保證各核上中斷負載平衡等),為瞭解決這些問題,vector、pin等概念都從irq中剝離出來,irq僅代表所有cpu核支援的中斷總數,作為irq_desc的索引維護中斷處理的相關資訊。
irq的總數由下面的方式計算得出,nr_irqs為所有cpu核支援的中斷總數,NR_IRQS為nr_irqs的初始值。
當irq很大時,靜態分配irq_desc表將不是個明智的決定,這時核心會使用radix tree來組織irq_desc,即irq_desc_tree
nr_irqs_gsi = 64nr_cpu_ids = 16 X = The number of irq sources we can talk about = nr_irqs_gsi+8*nr_cpu_ids+nr_irqs_gsi*16 = 1216Y = The number of irqs we can possibly service = NR_VECTORS*nr_cpu_ids = 4096nr_irqs = min(X, Y) = min(1216,4096) = 1216NR_VECTORS = 256NR_CPUS = 64CPU_VECTOR_LIMIT = 64 * NR_CPUS = 256 * nr_cpu_ids = 4096MAX_IO_APICS = 128IO_APIC_VECTOR_LIMIT = 32 * MAX_IO_APICS = 4096NR_IRQS = NR_VECTORS + max(CPU_VECTOR_LIMIT,IO_APIC_VECTOR_LIMIT) = 4352
x86_64 PCI裝置中斷路由原理
如所示,local APIC通過 I/O APIC接受中斷,I/O APIC負責把中斷處理成中斷訊息並按一定規則轉寄給local APIC。
如所示,local APIC提供the interrupt request register (IRR) 和 in-service register (ISR) 2個寄存器,在處理一個vector的同時,緩衝一個相同的vector,vector通過2個256-bit的寄存器標識,256個bit代表256個可能的vector,置1表示上報了相應的vector請求處理或者正在處理中。
local APIC以vector值作為優先順序順序來處理中斷。每個vector為8-bit,高4位作為中斷優先順序,1最低,15最高。vector 0-31為Intel 64 and IA-32體系保留專用,所以可用的中斷優先順序為2-15。
另外,local APIC提供Task-Priority Register (TPR),Processor-Priority Register (PPR)來設定local APIC的task優先順序和cpu優先順序,但I/O APIC轉寄的中斷vector優先順序小於local APIC TPR的設定時,此中斷不能打斷當前CPU核上啟動並執行task;當中斷vector優先順序小於local APIC PPR的設定時,此CPU核不處理此中斷。作業系統通過動態設定TPR和PPR,從而實現作業系統的即時性需求和中斷負載平衡需求。
中斷處理過程
Broadwell-DE X86_64的中斷處理過程基本和《Linux mips64r2 PCI中斷路由機制分析》的類似,不同點是x86_64從ax寄存器中擷取需要處理的中斷vector,而不是從APIC的特定寄存器中擷取。然後從vector_irq數組中根據vector查詢到對於的irq號。
unsigned int __irq_entry do_IRQ(struct pt_regs *regs){ struct pt_regs *old_regs = set_irq_regs(regs); /* high bit used in ret_from_ code */ unsigned vector = ~regs->orig_ax; unsigned irq; irq_enter(); exit_idle(); irq = __this_cpu_read(vector_irq[vector]); if (!handle_irq(irq, regs)) { ack_APIC_irq(); if (printk_ratelimit()) pr_emerg("%s: %d.%d No irq handler for vector (irq %d)\n", __func__, smp_processor_id(), vector, irq); } irq_exit(); set_irq_regs(old_regs); return 1;}
中斷配置過程
- 動態分配irq,以IRQ_BITMAP_BITS (NR_IRQS + 8196) bitmap資料結構管理;
- 動態分配vector,為保證最大利用local APIC上vector優先順序,減少具有相同vector優先順序的中斷,以16為間隔依次分配vector;
- 配置vector與irq的映射表:vector_irq表;
- 初始化irq_desc;
- 配置APIC PIRQ[A..H] pin腳屬性;
- 配置I/O APIC pin與vector 映射表:REDIR_TBL寄存器;共有24個REDIR_TBL條目,與24個pin腳對應。除了定義相應的vector以外,還支援定義中斷引腳具有如下功能:定義此引腳中斷通過I/O APIC上報給指定的local APIC或local APIC組;中斷觸發模式;中斷屏蔽等。詳見下表。
--EOF--
Linux x86_64 APIC中斷路由機制分析