不同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系统中,中断负载均衡等需求就无法实现了。
VectorVector是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 = 64 nr_cpu_ids = 16 X = The number of irq sources we can talk about = nr_irqs_gsi+8*nr_cpu_ids+nr_irqs_gsi*16 = 1216 Y = The number of irqs we can possibly service = NR_VECTORS*nr_cpu_ids = 4096 nr_irqs = min(X, Y) = min(1216,4096) = 1216 NR_VECTORS = 256 NR_CPUS = 64 CPU_VECTOR_LIMIT = 64 * NR_CPUS = 256 * nr_cpu_ids = 4096 MAX_IO_APICS = 128 IO_APIC_VECTOR_LIMIT = 32 * MAX_IO_APICS = 4096 NR_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请求处理或者正在处理中。