请教一个关于linux系统中断linux cpu亲缘性性绑定的问题

Linux中断机制之二:初始化 - CSDN博客
Linux中断机制之二:初始化
http://blog.csdn.net/phenix_lord/article/details/?ref=myread
相关概念和关键数据结构
1、 irq号:在当前系统中全局唯一,对应内核数据结构struct irq_desc,每个外设的中断有一个irq号(体系结构预留的中断,是没有对应的irq_desc结构和irq号的),该irq在该中断的生命周期内都不会改变,且和该中断的中断处理函数关联;内核使用一个bitmap allocated_irqs来标识当前系统已经分配的irq;irq号的管理与底层中断设备和配置无关,属于Generic Interrupt
Layer;对于irq号分布集中的情况,不配置CONFIG_SPARSE_IRQ,内核采用数组直接管理,数组下标就是irq号;而对于irq号比较分散的,设置CONFIG_SPARSE_IRQ,内核采用radix tree来管理所有的irq号。&
2、 vector号:内核使用全局bitmap used_vectors来标识那些vector被系统预留,不能被外设分配使用。&
3、 irq号和vector号的关联:内核中使用per-cpu变量vector_irq来描述irq号和vector号的关联,对每个CPU,vector_irq是一个数组,在X86架构下成员数量为256,其数组的index为vector,值为irq,如果为-1则表示该CPU上的这个vector尚未分配。&
4、 struct irq_desc结构,用来描述一个中断,是内核generic interrupt layer的关键数据结构,其包含了中断的大部分信息,并连接了driver层和物理中断设备层,每个irq号对应一个该结构,共享相同irq号的中断共享该结构。它的关键成员包括:
:为该中断对应的物理中断设备层相关的数据。
handle_irq:为该该中断使用的通用逻辑接口。
action:为driver层提供的ISR信息,其为一个单向链表结构,所有共享该中断的设备的ISR都链接在这里。
内核关键数据结构和相关初始化
对X86 CPU,Linux内核使用全局idt_table来表达当前的IDT,该变量定义在traps.c
&code class=&hljs fix has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&&span class=&hljs-attribute& style=&box-sizing: border-&&gate_desc
idt_table[NR_VECTORS] __page_aligned_data &/span&=&span class=&hljs-string& style=&color: rgb(0, 136, 0); box-sizing: border-&& { { { { 0, 0 } } }, };//初始化为全0。&/span&&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&/ul&
对中断相关的初始化,内核主要有以下工作:&
1、 设置used_vectors,确保外设不能分配到X86保留使用的vector(预留的vector范围为[0,31],另外还有其他通过apic_intr_init等接口预留的系统使用的vector);&
2、 设置X86CPU保留使用的vector对应的IDT这些entry使用特定的中断处理接口;&
3、 设置外设 (包括ISA中断)使用的中断处理接口,这些中断处理接口都一样。&
4、 设置ISA IRQ使用的irq_desc;&
5、 把IDT的首地址加载到CPU的IDTR(Interrupt Descriptor Table Register);&
6、 初始化中断控制器(下一章描述)&
以上工作主要在以下函数中完成:
&code class=&hljs scss has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&start_kernel
使用set_intr_gate等接口初始化保留vector
used_vectors中&span class=&hljs-attr_selector& style=&color: rgb(0, 136, 0); box-sizing: border-&&[0,0x1f]&/span&对应的vector被置1,表示已经预留不能再使用
&span class=&hljs-function& style=&box-sizing: border-&&load_idt((const struct desc_ptr *)&/span&&idt_descr) 把&idt_descr的地址加载到idtr
&span class=&hljs-function& style=&box-sizing: border-&&native_load_idt()&/span&
初始化0号CPU的vector_irq:其vector&span class=&hljs-attr_selector& style=&color: rgb(0, 136, 0); box-sizing: border-&&[0x30-0x3f]&/span&和irq号&span class=&hljs-attr_selector& style=&color: rgb(0, 136, 0); box-sizing: border-&&[0-15]&/span&(ISA中断)对应
x86_init&span class=&hljs-class& style=&box-sizing: border-&&.irqs&/span&&span class=&hljs-class& style=&box-sizing: border-&&.intr_init&/span&(native_init_IRQ)
x86_init&span class=&hljs-class& style=&box-sizing: border-&&.irqs&/span&&span class=&hljs-class& style=&box-sizing: border-&&.pre_vector_init&/span&(init_ISA_irqs)
init_ISA_irqs&span class=&hljs-value& style=&box-sizing: border-&&:初始化ISA,设置irq号[&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&,&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&15&/span&] (ISA中断)的irq_desc
apic_intr_init 设置APIC相关中断(使用的alloc_intr_gate会设置used_vectors)
使用interrupt数组初始化设置外设中断idt entry&/span&&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&li style=&box-sizing: border- padding: 0px 5&&2&/li&&li style=&box-sizing: border- padding: 0px 5&&3&/li&&li style=&box-sizing: border- padding: 0px 5&&4&/li&&li style=&box-sizing: border- padding: 0px 5&&5&/li&&li style=&box-sizing: border- padding: 0px 5&&6&/li&&li style=&box-sizing: border- padding: 0px 5&&7&/li&&li style=&box-sizing: border- padding: 0px 5&&8&/li&&li style=&box-sizing: border- padding: 0px 5&&9&/li&&li style=&box-sizing: border- padding: 0px 5&&10&/li&&li style=&box-sizing: border- padding: 0px 5&&11&/li&&li style=&box-sizing: border- padding: 0px 5&&12&/li&&li style=&box-sizing: border- padding: 0px 5&&13&/li&&li style=&box-sizing: border- padding: 0px 5&&14&/li&&/ul&
可以看到,这个过程会完成每个中断vector对应的idt entry的初始化,系统把这些中断vector分成以下几种:&
1、X86保留vector,这些vector包括[0,0x1f]和APIC等系统部件占用的vector,对这些vector,会记录在bitmap used_vectors中,确保不会被外设分配使用;同时这些vector都使用各自的中断处理接口,其中断处理过程相对简单(没有generic interrupt layer的参与,CPU直接调用到各自的ISR)。&
2、ISA irqs,对这些中断,在初始化过程中已经完成了irq_desc、vector_irq、以及IDT中对应entry的分配和设置,同时可以发现ISA中断,在初始化的时候都被设置为运行在0号CPU。&
3、其它外设的中断,对这些中断,在初始化过程中仅设置了对应的IDT,和ISA中断一样,其中断处理接口都来自interrupt数组。
中断处理接口interrupt数组&
interrupt数组是内核中外设中断对应的IDT entry,其在entry_64.S中定义,定义如下:
&code class=&hljs cpp has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&
.section .init.rodata,&span class=&hljs-string& style=&color: rgb(0, 136, 0); box-sizing: border-&&&a&&/span&&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*符号interrupt位于数据段*/&/span&
ENTRY(interrupt)
.section .entry.text&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*以下开始内容输出到text段*/&/span&
.p2align &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&5&/span&
.p2align CONFIG_X86_L1_CACHE_SHIFT
ENTRY(irq_entries_start)&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*符号irq_entries_start位于代码段*/&/span&
INTR_FRAME
&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&=FIRST_EXTERNAL_VECTOR
.rept (NR_VECTORS-FIRST_EXTERNAL_VECTOR+&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&6&/span&)/&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&7&/span&&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*一共224/7次外层循环*/&/span&
.balign &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&32&/span&
.rept &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&7&/span&&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*内层循环每组为7个vector对应的处理接口*/&/span&
.&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& &span class=&hljs-stl_container& style=&box-sizing: border-&&&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span& & NR_VECTORS
.&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& &span class=&hljs-stl_container& style=&box-sizing: border-&&&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span& &&&/span& FIRST_EXTERNAL_VECTOR
CFI_ADJUST_CFA_OFFSET -8
pushq_cfi $(~&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&+0x80) /* 代码段内容*/
.&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& ((&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&-FIRST_EXTERNAL_VECTOR)%7) &&&/span& &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&6&/span&&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*每组最后一个接口不需要jmp*/&/span&
jmp &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&2f&/span&
.previous&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*返回之前的段,也就是以下内容输出到数据段*/&/span&
.quad &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&1&/span&b &span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*数据段的数据为标号1的地址,b表示这个标号在前面*/&/span&
.section .entry.text&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*切换回代码段*/&/span&
&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&=&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&+&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&1&/span&
.endr&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*循环7次,跳转到.rept7 */&/span&
&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&2&/span&:
jmp common_interrupt
.endr&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*循环,对应前面的.rept (NR_VECTORS-FIRST_EXTERNAL_VECTOR+6)/7对应*/&/span&
CFI_ENDPROC
END(irq_entries_start)
END(interrupt)
.previous&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&li style=&box-sizing: border- padding: 0px 5&&2&/li&&li style=&box-sizing: border- padding: 0px 5&&3&/li&&li style=&box-sizing: border- padding: 0px 5&&4&/li&&li style=&box-sizing: border- padding: 0px 5&&5&/li&&li style=&box-sizing: border- padding: 0px 5&&6&/li&&li style=&box-sizing: border- padding: 0px 5&&7&/li&&li style=&box-sizing: border- padding: 0px 5&&8&/li&&li style=&box-sizing: border- padding: 0px 5&&9&/li&&li style=&box-sizing: border- padding: 0px 5&&10&/li&&li style=&box-sizing: border- padding: 0px 5&&11&/li&&li style=&box-sizing: border- padding: 0px 5&&12&/li&&li style=&box-sizing: border- padding: 0px 5&&13&/li&&li style=&box-sizing: border- padding: 0px 5&&14&/li&&li style=&box-sizing: border- padding: 0px 5&&15&/li&&li style=&box-sizing: border- padding: 0px 5&&16&/li&&li style=&box-sizing: border- padding: 0px 5&&17&/li&&li style=&box-sizing: border- padding: 0px 5&&18&/li&&li style=&box-sizing: border- padding: 0px 5&&19&/li&&li style=&box-sizing: border- padding: 0px 5&&20&/li&&li style=&box-sizing: border- padding: 0px 5&&21&/li&&li style=&box-sizing: border- padding: 0px 5&&22&/li&&li style=&box-sizing: border- padding: 0px 5&&23&/li&&li style=&box-sizing: border- padding: 0px 5&&24&/li&&li style=&box-sizing: border- padding: 0px 5&&25&/li&&li style=&box-sizing: border- padding: 0px 5&&26&/li&&li style=&box-sizing: border- padding: 0px 5&&27&/li&&li style=&box-sizing: border- padding: 0px 5&&28&/li&&li style=&box-sizing: border- padding: 0px 5&&29&/li&&li style=&box-sizing: border- padding: 0px 5&&30&/li&&li style=&box-sizing: border- padding: 0px 5&&31&/li&&li style=&box-sizing: border- padding: 0px 5&&32&/li&&/ul&
这段汇编的效果是:在代码段,生成了一个符号irq_entries_start,该符号对应的内容是一组可执行代码,一共(NR_VECTORS-FIRST_EXTERNAL_VECTOR+6)/7组,每组为7个中断入口,为:
&code class=&hljs javascript has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&pushq_cfi $(~&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0x20&/span&+&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0x80&/span&)
jmp &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&2&/span&f &span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*2f是一个地址,表示为后面标号2的地址,也就是后面jmp common_interrupt 这段代码的地址*/&/span&
以上内容重复&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&5&/span&次,一共&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&6&/span&次,下面是第&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&7&/span&个中断入口。
pushq_cfi $(~&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0x26&/span&+&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0x80&/span&)
jmp common_interrupt&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&li style=&box-sizing: border- padding: 0px 5&&2&/li&&li style=&box-sizing: border- padding: 0px 5&&3&/li&&li style=&box-sizing: border- padding: 0px 5&&4&/li&&li style=&box-sizing: border- padding: 0px 5&&5&/li&&/ul&
每组的最后一个中断入口不需要jmp 2f是因为其pushq_cfi(就是pushq咯)下面就&
是2f这个标号的地址了。(不明白的是:为什么不在jmp 2f的地方直接写上jmp common_interrupt?非要jmp 2f,2f的地方再次jmp common_interrupt?&)
而interrupt是一个数组,该数组在初始化完成后释放,其每个数组项都是一个地址,是对应的“pushq_cfi”代码的地址(每个代表中断入口的标号)。系统在初始化的时候,对外设使用interrupt数组作中断处理接口,就是在中断发生时,执行代码段:
&code class=&hljs avrasm has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&pushq_cfi $(~vector+&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0x80&/span&)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&jmp&/span& &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&2&/span&f (执行&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&jmp&/span& common_interrupt)&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&li style=&box-sizing: border- padding: 0px 5&&2&/li&&/ul&
初始化中断控制器
对中断控制器的使用基本上有三种机制:&
1、 中断路由表 $PIR&
struct irq_routing_table,该结构用于使用PIR和8259A的系统,在微软的文献《PCI IRQ Routing Table Specification》中描述了该结构详细信息。其描述了一个PCI设备的INT#是如何连接到PIR设备的输入端口的。其关键数据是一个可变长的struct irq_info数组,每个struct irq_info描述了一个PCI物理设备的4个INT#相关的中断路由信息和对应可用的ISA IRQs的bitmap。BIOS根据相关设备的物理连接填写该数据结构,OS在设备初始化过程中使用这些信息为使用INT#的设备分配对应的vector和irq。&
2、 MP table&
struct mpc_intsrc,该数据结构用于使用I/O APIC的系统中,描述系统中所有PCI设备4个INT#信号和I/O APIC输入引脚的对应关系。该数据结构的srcbus成员为对应PCI设备的bus id;srcbusirq描述了一个INT#信号,其bit0-bit1用于描述是INTA#–INTD#中的哪一个(对应值为0-3),bit2-bit6描述该PCI设备的slot id。dstapic为该描述对应的I/O APIC的ID。dstirq描述srcbus和srcbusirq确定的INT#对应的irq号信息(具体的解析有多种情况)。在系统中有一个以该数据结构为成员的全局数组mp_irqs,用于管理系统中所有的硬件中断信号和irq之间的关联。对MP
table及其使用的更加详细的描述,见《Multiprocessor Specification v1.4》&
3、 ACPI(Advanced Configuration and PowerInterface)机制&
这种机制为I/O APIC机制和中PIR机制提供统一的管理界面,该机制使用struct acpi_prt_entry描述INT#和GSI(能和vector、irq对应)的关系,系统中所有的struct acpi_prt_entry由OS从BIOS提供的信息中获取,并保存在链表acpi_prt_list中。&
注:对GSI的说明,GSI(global system interrupt)表示的是系统中中断控制器的每个输入管脚的唯一编号,在使用ACPI模式管理中断控制器的时候使用。对使用8259A的系统,GSI和ISA IRQ是一一对应的。对于使用APIC的,每个I/O APIC会由BISO分配一个基址,这个base+对应管脚的编号(从0开始)就是对应的GSI。通常是基址为0的I/O APIC的前16个管脚用于ISA IRQS,对GSI更加详细的描述,见《Advanced Configuration and Power
Interface Revision 2.0》
除了中断路由表,其它两种机制的初始化(包括相关中断路由信息的初始化)的在《interrupt in linux》中有很详细的描述。这些初始化操作都在内核初始化的时候完成。
为PCI设备配置中断
为PCI设备配置中断,分为两个步骤,&
步骤一:为设备分配irq号(对MSIX,会有多个),为该中断分配执行CPU和它使用的vector,并通过对中断控制器的设置,确保对应的中断信号和vector匹配。对于使用INT#类型的中断,通常通过pci_enable_device/pci_enable_device_mem/pci_enable_device_io中对函数pcibios_enable_device的调用来完成(只有在没有开启MSI/MSIX的时候才会为INT#做配置),而要配置MSI/MSIX中断要使用的是pci_enable_msix。&
步骤二:request_irq为该设备的irq指定对应的中断处理例程,把irq号和驱动定义ISR关联。
pcibios_enable_device
该接口用于使能PCI设备INT#模式的中断。其主要功能由pcibios_enable_irq(dev)完成,pcibios_enable_irq是一个函数指针,对于ACPI模式,其在上电过程中被设置为acpi_pci_irq_enable,其它情况被设置为pirq_enable_irq。
对ACPI模式,其执行过程为:&
1、 acpi_pci_irq_enable:其先根据设备的管脚信息获取一个GSI(可以认为有了GSI,就有了irq号,gsi_to_irq可以完成其转换),有了gsi/irq,要完成设置还必须有vector并且把它们关联起来,因此如果GSI获取成功,会使用acpi_register_gsi来完成后续操作。&
2、 acpi_register_gsi:其主要功能由__acpi_register_gsi来完成,该函数指针在ACPI模式下被设置为acpi_register_gsi_ioapic,acpi_register_gsi_ioapic的执行过程如下:&
mp_register_gsi===&io_apic_set_pci_routing===&io_apic_set_pci_routing===&io_apic_setup_irq_pin_once===&io_apic_setup_irq_pin===&setup_ioapic_irq,在setup_ioapic_irq中,就会利用assign_irq_vector为该irq选择对应的执行CPU,并分配该CPU上的vector,同时还把该vector等配置写入到I/O APIC对应管脚的RTE,从而完成整个中断的配置。这样在该INT#信号到来的时候,I/O
APIC就能根据对应管脚的RTE,把该信号翻译为一个vector,并通过中断消息发送到local APIC。同时在setup_ioapic_irq中,还通过ioapic_register_intr===&irq_set_chip_and_handler_name为得到的irq号对应的irq_desc设置了-&irq_data.chip和handle_irq函数指针(对level触发的,为handle_fasteoi_irq,否则为handle_edge_irq)
对其它模式,其通过pcibios_lookup_irq完成执行:&
在配置了I/O APIC的场景,pirq_enable_irq通过IO_APIC_get_PCI_irq_vector获取到irq号,然后和ACPI模式一样,通过io_apic_set_pci_routing完成对I/O APIC的配置。而对没有配置I/O APIC的场景,主要通过pcibios_lookup_irq来完成相关操作:&
1、 pcibios_lookup_irq通过读取BIOS提供的中断路由表 ($PIR表,irq_routing_table)信息和当前irq分配情况(pirq_penalty数组),在考虑均衡的前提下为当前设备分配一个可用的irq。&
2、 根据当前PIR的相关信息,决定最终的irq号选择,相关代码行如下
&code class=&hljs perl has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& ((pirq & &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0xf0&/span&) == &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0xf0&/span&) {
irq = pirq & &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0xf&/span&;
msg = &span class=&hljs-string& style=&color: rgb(0, 136, 0); box-sizing: border-&&&hardcoded&&/span&;
} &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&else&/span& &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (r-&get && (irq = r-&get(pirq_router_dev, dev, pirq)) && \ /&span class=&hljs-variable& style=&color: rgb(102, 0, 102); box-sizing: border-&&*pirq_piix_get&/span&&span class=&hljs-variable& style=&color: rgb(102, 0, 102); box-sizing: border-&&*/&/span&
((!(pci_probe & PCI_USE_PIRQ_MASK)) || ((&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&1&/span& && irq) & mask))) {
msg = &span class=&hljs-string& style=&color: rgb(0, 136, 0); box-sizing: border-&&&found&&/span&;
eisa_set_level_ir&span class=&hljs-string& style=&color: rgb(0, 136, 0); box-sizing: border-&&q(irq)&/span&;
} &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&else&/span& &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (newirq && r-&set &&
(dev-&class && &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&8&/span&) != PCI_CLASS_DISPLAY_VGA) {
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (r-&set(pirq_router_dev, dev, pirq, newirq)) {
eisa_set_level_ir&span class=&hljs-string& style=&color: rgb(0, 136, 0); box-sizing: border-&&q(newirq)&/span&;
msg = &span class=&hljs-string& style=&color: rgb(0, 136, 0); box-sizing: border-&&&assigned&&/span&;
}&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&li style=&box-sizing: border- padding: 0px 5&&2&/li&&li style=&box-sizing: border- padding: 0px 5&&3&/li&&li style=&box-sizing: border- padding: 0px 5&&4&/li&&li style=&box-sizing: border- padding: 0px 5&&5&/li&&li style=&box-sizing: border- padding: 0px 5&&6&/li&&li style=&box-sizing: border- padding: 0px 5&&7&/li&&li style=&box-sizing: border- padding: 0px 5&&8&/li&&li style=&box-sizing: border- padding: 0px 5&&9&/li&&li style=&box-sizing: border- padding: 0px 5&&10&/li&&li style=&box-sizing: border- padding: 0px 5&&11&/li&&li style=&box-sizing: border- padding: 0px 5&&12&/li&&li style=&box-sizing: border- padding: 0px 5&&13&/li&&li style=&box-sizing: border- padding: 0px 5&&14&/li&&li style=&box-sizing: border- padding: 0px 5&&15&/li&&/ul&
也就是:如果是硬链接(INT#直接连接到了8259A,没有经过PIR),直接获取irq号,如果PIR中已经有该输入线的配置,使用已有的值,否则利用刚刚分配的可用irq,并写入到PIR,以便能够完成中断信号到irq号的转换。&
1、这里的r,也就是pirq_router,代表一种PIR硬件,全局配置pirq_routers中描述了当前支持的PIR,并在初始化的时候通过pirq_find_router获取了对应当前配置的PIR对应的描述。&
2、这里没有分配vector,是因为这里使用的irq号范围为0-16,是ISA IRQs,其与vector的对应关系简单:vector = IRQ0_VECTOR + irq,并在系统初始化过程中,已经通过early_irq_init中分配了irq_desc结构,通过init_IRQ设置了vector_irq(只运行于CPU0上),然后通过x86_init.irqs.intr_init(native_init_IRQ)===& x86_init.irqs.pre_vector_init(init_ISA_irqs)设置了-&irq_data.chip(i8259A_chip)和handle_irq函数指针(handle_level_irq)。
Pci_enable_msix
该函数完成MSIX中断相关的设置。
&code class=&hljs cs has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& pci_enable_msix(&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&struct&/span& pci_dev *dev, &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&struct&/span& msix_entry *entries, &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& nvec)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& status, nr_
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& i,
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (!entries)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& -EINVAL;
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*检查MSIX中断功能在当前设备上是否可用*/&/span&
status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (status)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span&
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*该设备支持的MSI-X中断数量*/&/span&
nr_entries = pci_msix_table_size(dev);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (nvec & nr_entries)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& nr_
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/* Check for any invalid entries */&/span&
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&for&/span& (i = &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&; i & i++) {
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (entries[i].entry &= nr_entries)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& -EINVAL;
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/* invalid entry */&/span&
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&for&/span& (j = i + &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&1&/span&; j & j++) {
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (entries[i].entry == entries[j].entry)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& -EINVAL; &span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/* duplicate entry */&/span&
WARN_ON(!!dev-&msix_enabled);
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/* Check whether driver already requested for MSI irq */&/span&
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (dev-&msi_enabled) {
dev_info(&dev-&dev, &span class=&hljs-string& style=&color: rgb(0, 136, 0); box-sizing: border-&&&can't enable MSI-X &&/span&
&span class=&hljs-string& style=&color: rgb(0, 136, 0); box-sizing: border-&&&(MSI IRQ already assigned)\n&&/span&);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& -EINVAL;
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*关键函数:完成MSI-X中断相关设置*/&/span&
status = msix_capability_init(dev, entries, nvec);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span&
&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&li style=&box-sizing: border- padding: 0px 5&&2&/li&&li style=&box-sizing: border- padding: 0px 5&&3&/li&&li style=&box-sizing: border- padding: 0px 5&&4&/li&&li style=&box-sizing: border- padding: 0px 5&&5&/li&&li style=&box-sizing: border- padding: 0px 5&&6&/li&&li style=&box-sizing: border- padding: 0px 5&&7&/li&&li style=&box-sizing: border- padding: 0px 5&&8&/li&&li style=&box-sizing: border- padding: 0px 5&&9&/li&&li style=&box-sizing: border- padding: 0px 5&&10&/li&&li style=&box-sizing: border- padding: 0px 5&&11&/li&&li style=&box-sizing: border- padding: 0px 5&&12&/li&&li style=&box-sizing: border- padding: 0px 5&&13&/li&&li style=&box-sizing: border- padding: 0px 5&&14&/li&&li style=&box-sizing: border- padding: 0px 5&&15&/li&&li style=&box-sizing: border- padding: 0px 5&&16&/li&&li style=&box-sizing: border- padding: 0px 5&&17&/li&&li style=&box-sizing: border- padding: 0px 5&&18&/li&&li style=&box-sizing: border- padding: 0px 5&&19&/li&&li style=&box-sizing: border- padding: 0px 5&&20&/li&&li style=&box-sizing: border- padding: 0px 5&&21&/li&&li style=&box-sizing: border- padding: 0px 5&&22&/li&&li style=&box-sizing: border- padding: 0px 5&&23&/li&&li style=&box-sizing: border- padding: 0px 5&&24&/li&&li style=&box-sizing: border- padding: 0px 5&&25&/li&&li style=&box-sizing: border- padding: 0px 5&&26&/li&&li style=&box-sizing: border- padding: 0px 5&&27&/li&&li style=&box-sizing: border- padding: 0px 5&&28&/li&&li style=&box-sizing: border- padding: 0px 5&&29&/li&&li style=&box-sizing: border- padding: 0px 5&&30&/li&&li style=&box-sizing: border- padding: 0px 5&&31&/li&&li style=&box-sizing: border- padding: 0px 5&&32&/li&&li style=&box-sizing: border- padding: 0px 5&&33&/li&&li style=&box-sizing: border- padding: 0px 5&&34&/li&&li style=&box-sizing: border- padding: 0px 5&&35&/li&&li style=&box-sizing: border- padding: 0px 5&&36&/li&&li style=&box-sizing: border- padding: 0px 5&&37&/li&&/ul&
msix_capability_init中实现中断初始化的是arch_setup_msi_irqs,对于X86系统,其为x86_setup_msi_irqs,x86_setup_msi_irqs中直接调用了native_setup_msi_irqs,该函数是X86系统中实现MSIX中断初始化的关键函数,对于没有启用interrupt remap的系统,其实现如下:
&code class=&hljs perl has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& native_setup_msi_irqs(struct pci_dev &span class=&hljs-variable& style=&color: rgb(102, 0, 102); box-sizing: border-&&*dev&/span&, &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& nvec, &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& type)
node = dev_to_node(&dev-&dev);
&span class=&hljs-regexp& style=&color: rgb(0, 136, 0); box-sizing: border-&&/*nr_irqs_gsi是MSI-X的irq号起始地址,是按照IOAPIC引脚分配
的最大irq号+1*/&/span&
irq_want = nr_irqs_
sub_handle = &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&;
list_for_each_entry(msidesc, &dev-&msi_list, list) {
&span class=&hljs-regexp& style=&color: rgb(0, 136, 0); box-sizing: border-&&/*按照全局配置分配irq号和对应的irq_desc,并
在目标*/&/span&
irq = create_irq_nr(irq_want, node);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (irq == &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& -&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&1&/span&;
irq_want = irq + &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&1&/span&;
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (!intr_remapping_enabled)/&span class=&hljs-variable& style=&color: rgb(102, 0, 102); box-sizing: border-&&*对&/span&于没有启用interrupt remap的系统,intr_remapping_enabled=&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&&span class=&hljs-variable& style=&color: rgb(102, 0, 102); box-sizing: border-&&*/&/span&
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&goto&/span& no_
&span class=&hljs-regexp& style=&color: rgb(0, 136, 0); box-sizing: border-&&/*使能MSIX中断,把中断信息(关键的vector)
写入PCIE配置区,设置irq_desc数据*/&/span&
ret = setup_msi_ir&span class=&hljs-string& style=&color: rgb(0, 136, 0); box-sizing: border-&&q(dev, msidesc, irq)&/span&;
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (ret & &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&goto&/span&
sub_handle++;
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&;
destroy_ir&span class=&hljs-string& style=&color: rgb(0, 136, 0); box-sizing: border-&&q(irq)&/span&;
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span&
}&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&li style=&box-sizing: border- padding: 0px 5&&2&/li&&li style=&box-sizing: border- padding: 0px 5&&3&/li&&li style=&box-sizing: border- padding: 0px 5&&4&/li&&li style=&box-sizing: border- padding: 0px 5&&5&/li&&li style=&box-sizing: border- padding: 0px 5&&6&/li&&li style=&box-sizing: border- padding: 0px 5&&7&/li&&li style=&box-sizing: border- padding: 0px 5&&8&/li&&li style=&box-sizing: border- padding: 0px 5&&9&/li&&li style=&box-sizing: border- padding: 0px 5&&10&/li&&li style=&box-sizing: border- padding: 0px 5&&11&/li&&li style=&box-sizing: border- padding: 0px 5&&12&/li&&li style=&box-sizing: border- padding: 0px 5&&13&/li&&li style=&box-sizing: border- padding: 0px 5&&14&/li&&li style=&box-sizing: border- padding: 0px 5&&15&/li&&li style=&box-sizing: border- padding: 0px 5&&16&/li&&li style=&box-sizing: border- padding: 0px 5&&17&/li&&li style=&box-sizing: border- padding: 0px 5&&18&/li&&li style=&box-sizing: border- padding: 0px 5&&19&/li&&li style=&box-sizing: border- padding: 0px 5&&20&/li&&li style=&box-sizing: border- padding: 0px 5&&21&/li&&li style=&box-sizing: border- padding: 0px 5&&22&/li&&li style=&box-sizing: border- padding: 0px 5&&23&/li&&li style=&box-sizing: border- padding: 0px 5&&24&/li&&li style=&box-sizing: border- padding: 0px 5&&25&/li&&li style=&box-sizing: border- padding: 0px 5&&26&/li&&li style=&box-sizing: border- padding: 0px 5&&27&/li&&li style=&box-sizing: border- padding: 0px 5&&28&/li&&li style=&box-sizing: border- padding: 0px 5&&29&/li&&/ul&
该函数中有两个关键函数,分别是create_irq_nr和setup_msi_irq,其中create_irq_nr是分配一个vector给当前的中断,分配vector的同时,也为该中断指定了执行CPU。setup_msi_irq则负责把相关配置信息写入到PCIE配置区,并设置irq_desc的数据,其中关键的是irq_desc的handle_irq被设置为handle_edge_irq。&
create_irq_nr的实现如下:
&code class=&hljs cs has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&unsigned &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& create_irq_nr(unsigned &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&from&/span&, &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& node)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&from&/span& & nr_irqs_gsi)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&from&/span& = nr_irqs_
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*从全局bitmap中查找一个没有用的irq号,并分配和
初始化一个对应的irq_desc*/&/span&
irq = alloc_irq_from(&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&from&/span&, node);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (irq & &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&;
cfg = alloc_irq_cfg(irq, node);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (!cfg) {
free_irq_at(irq, NULL);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&;
raw_spin_lock_irqsave(&vector_lock, flags);
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*关键函数:负责分配一个vector,并和irq号关联
其中的&apic&是根据系统配置在系统加载过程中
初始化,在当前系统为apic_physflat*/&/span&
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (!__assign_irq_vector(irq, cfg, apic-&target_cpus()))
raw_spin_unlock_irqrestore(&vector_lock, flags);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (ret) {
irq_set_chip_data(irq, cfg);
irq_clear_status_flags(irq, IRQ_NOREQUEST);
} &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&else&/span& {
free_irq_at(irq, cfg);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span&
}&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&li style=&box-sizing: border- padding: 0px 5&&2&/li&&li style=&box-sizing: border- padding: 0px 5&&3&/li&&li style=&box-sizing: border- padding: 0px 5&&4&/li&&li style=&box-sizing: border- padding: 0px 5&&5&/li&&li style=&box-sizing: border- padding: 0px 5&&6&/li&&li style=&box-sizing: border- padding: 0px 5&&7&/li&&li style=&box-sizing: border- padding: 0px 5&&8&/li&&li style=&box-sizing: border- padding: 0px 5&&9&/li&&li style=&box-sizing: border- padding: 0px 5&&10&/li&&li style=&box-sizing: border- padding: 0px 5&&11&/li&&li style=&box-sizing: border- padding: 0px 5&&12&/li&&li style=&box-sizing: border- padding: 0px 5&&13&/li&&li style=&box-sizing: border- padding: 0px 5&&14&/li&&li style=&box-sizing: border- padding: 0px 5&&15&/li&&li style=&box-sizing: border- padding: 0px 5&&16&/li&&li style=&box-sizing: border- padding: 0px 5&&17&/li&&li style=&box-sizing: border- padding: 0px 5&&18&/li&&li style=&box-sizing: border- padding: 0px 5&&19&/li&&li style=&box-sizing: border- padding: 0px 5&&20&/li&&li style=&box-sizing: border- padding: 0px 5&&21&/li&&li style=&box-sizing: border- padding: 0px 5&&22&/li&&li style=&box-sizing: border- padding: 0px 5&&23&/li&&li style=&box-sizing: border- padding: 0px 5&&24&/li&&li style=&box-sizing: border- padding: 0px 5&&25&/li&&li style=&box-sizing: border- padding: 0px 5&&26&/li&&li style=&box-sizing: border- padding: 0px 5&&27&/li&&li style=&box-sizing: border- padding: 0px 5&&28&/li&&li style=&box-sizing: border- padding: 0px 5&&29&/li&&li style=&box-sizing: border- padding: 0px 5&&30&/li&&/ul&
其中__assign_irq_vector负责分配vector,并和中断在CPU上的调度相关,其实现如下
&code class=&hljs cpp has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*@mask:该vector可以分配在哪些CPU上*/&/span&
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&static&/span& &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span&
__assign_irq_vector(&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& irq, &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&struct&/span& irq_cfg *cfg, &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&const&/span& &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&struct&/span& cpumask *mask)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&static&/span& &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&static&/span& &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& current_offset = VECTOR_OFFSET_START % &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&8&/span&;
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&unsigned&/span& &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& old_
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& cpu,
cpumask_var_t tmp_
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (cfg-&move_in_progress)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& -EBUSY;
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (!alloc_cpumask_var(&tmp_mask, GFP_ATOMIC))
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& -ENOMEM;
old_vector = cfg-&&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&;
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (old_vector) {&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*如果已经存在满足CPU绑定要求的vector,不
多次分配*/&/span&
cpumask_and(tmp_mask, mask, cpu_online_mask);
cpumask_and(tmp_mask, cfg-&domain, tmp_mask);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (!cpumask_empty(tmp_mask)) {
free_cpumask_var(tmp_mask);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span& &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&;
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/* Only try and allocate irqs on cpus that are present */&/span&
err = -ENOSPC;
for_each_cpu_and(cpu, mask, cpu_online_mask) {
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& new_
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&int&/span& &span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&,
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*获取当前APIC配置要求的中断运行cpu,大部分
(包括当前系统apic_physflat)为tmp_mask就对应变量'cpu'*/&/span&
apic-&vector_allocation_domain(cpu, tmp_mask);
&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span& = current_
offset = current_
&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span& += &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&8&/span&;
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span& &= first_system_vector) {
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/* If out of vectors on large boxen, must share them. */&/span&
offset = (offset + &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&1&/span&) % &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&8&/span&;
&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span& = FIRST_EXTERNAL_VECTOR +
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (unlikely(current_vector == &span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&))
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&continue&/span&;
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*如果是系统预留的vector,不可使用*/&/span&
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (test_bit(&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&, used_vectors))
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&goto&/span&
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*如果apic要求的任何cpu核心上该vector已经被占用,则
该vector不可用*/&/span&
for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (per_cpu(vector_irq, new_cpu)[&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&] != -&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&1&/span&)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&goto&/span&
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/* Found one! */&/span&
current_vector = &span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&;
current_offset =
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&if&/span& (old_vector) {
cfg-&move_in_progress = &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&1&/span&;
cpumask_copy(cfg-&old_domain, cfg-&domain);
&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&/*关键步骤:对当前apic配置的可能运行该中断的所有CPU
配置其vector_irq,以便中断发生时可以通过vector查找到
irq号*/&/span&
for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
per_cpu(vector_irq, new_cpu)[&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&] =
cfg-&&span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span& = &span class=&hljs-built_in& style=&color: rgb(102, 0, 102); box-sizing: border-&&vector&/span&;
cpumask_copy(cfg-&domain, tmp_mask);
err = &span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&0&/span&;
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&break&/span&;
free_cpumask_var(tmp_mask);
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&return&/span&
}&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&li style=&box-sizing: border- padding: 0px 5&&2&/li&&li style=&box-sizing: border- padding: 0px 5&&3&/li&&li style=&box-sizing: border- padding: 0px 5&&4&/li&&li style=&box-sizing: border- padding: 0px 5&&5&/li&&li style=&box-sizing: border- padding: 0px 5&&6&/li&&li style=&box-sizing: border- padding: 0px 5&&7&/li&&li style=&box-sizing: border- padding: 0px 5&&8&/li&&li style=&box-sizing: border- padding: 0px 5&&9&/li&&li style=&box-sizing: border- padding: 0px 5&&10&/li&&li style=&box-sizing: border- padding: 0px 5&&11&/li&&li style=&box-sizing: border- padding: 0px 5&&12&/li&&li style=&box-sizing: border- padding: 0px 5&&13&/li&&li style=&box-sizing: border- padding: 0px 5&&14&/li&&li style=&box-sizing: border- padding: 0px 5&&15&/li&&li style=&box-sizing: border- padding: 0px 5&&16&/li&&li style=&box-sizing: border- padding: 0px 5&&17&/li&&li style=&box-sizing: border- padding: 0px 5&&18&/li&&li style=&box-sizing: border- padding: 0px 5&&19&/li&&li style=&box-sizing: border- padding: 0px 5&&20&/li&&li style=&box-sizing: border- padding: 0px 5&&21&/li&&li style=&box-sizing: border- padding: 0px 5&&22&/li&&li style=&box-sizing: border- padding: 0px 5&&23&/li&&li style=&box-sizing: border- padding: 0px 5&&24&/li&&li style=&box-sizing: border- padding: 0px 5&&25&/li&&li style=&box-sizing: border- padding: 0px 5&&26&/li&&li style=&box-sizing: border- padding: 0px 5&&27&/li&&li style=&box-sizing: border- padding: 0px 5&&28&/li&&li style=&box-sizing: border- padding: 0px 5&&29&/li&&li style=&box-sizing: border- padding: 0px 5&&30&/li&&li style=&box-sizing: border- padding: 0px 5&&31&/li&&li style=&box-sizing: border- padding: 0px 5&&32&/li&&li style=&box-sizing: border- padding: 0px 5&&33&/li&&li style=&box-sizing: border- padding: 0px 5&&34&/li&&li style=&box-sizing: border- padding: 0px 5&&35&/li&&li style=&box-sizing: border- padding: 0px 5&&36&/li&&li style=&box-sizing: border- padding: 0px 5&&37&/li&&li style=&box-sizing: border- padding: 0px 5&&38&/li&&li style=&box-sizing: border- padding: 0px 5&&39&/li&&li style=&box-sizing: border- padding: 0px 5&&40&/li&&li style=&box-sizing: border- padding: 0px 5&&41&/li&&li style=&box-sizing: border- padding: 0px 5&&42&/li&&li style=&box-sizing: border- padding: 0px 5&&43&/li&&li style=&box-sizing: border- padding: 0px 5&&44&/li&&li style=&box-sizing: border- padding: 0px 5&&45&/li&&li style=&box-sizing: border- padding: 0px 5&&46&/li&&li style=&box-sizing: border- padding: 0px 5&&47&/li&&li style=&box-sizing: border- padding: 0px 5&&48&/li&&li style=&box-sizing: border- padding: 0px 5&&49&/li&&li style=&box-sizing: border- padding: 0px 5&&50&/li&&li style=&box-sizing: border- padding: 0px 5&&51&/li&&li style=&box-sizing: border- padding: 0px 5&&52&/li&&li style=&box-sizing: border- padding: 0px 5&&53&/li&&li style=&box-sizing: border- padding: 0px 5&&54&/li&&li style=&box-sizing: border- padding: 0px 5&&55&/li&&li style=&box-sizing: border- padding: 0px 5&&56&/li&&li style=&box-sizing: border- padding: 0px 5&&57&/li&&li style=&box-sizing: border- padding: 0px 5&&58&/li&&li style=&box-sizing: border- padding: 0px 5&&59&/li&&li style=&box-sizing: border- padding: 0px 5&&60&/li&&li style=&box-sizing: border- padding: 0px 5&&61&/li&&li style=&box-sizing: border- padding: 0px 5&&62&/li&&li style=&box-sizing: border- padding: 0px 5&&63&/li&&li style=&box-sizing: border- padding: 0px 5&&64&/li&&li style=&box-sizing: border- padding: 0px 5&&65&/li&&li style=&box-sizing: border- padding: 0px 5&&66&/li&&li style=&box-sizing: border- padding: 0px 5&&67&/li&&li style=&box-sizing: border- padding: 0px 5&&68&/li&&li style=&box-sizing: border- padding: 0px 5&&69&/li&&li style=&box-sizing: border- padding: 0px 5&&70&/li&&li style=&box-sizing: border- padding: 0px 5&&71&/li&&li style=&box-sizing: border- padding: 0px 5&&72&/li&&li style=&box-sizing: border- padding: 0px 5&&73&/li&&li style=&box-sizing: border- padding: 0px 5&&74&/li&&li style=&box-sizing: border- padding: 0px 5&&75&/li&&/ul&
从实现中可以看到,该函数从FIRST_EXTERNAL_VECTOR(外设中断的起始vector号,通常是0x20) 到first_system_vector(外部中断结束vector号,通常是254,255被系统作为保留的SPURIOUS_APIC_VECTOR使用)的范围中,为当前中断分配一个vector,要求该vector在对应的cpu上均可用,该vector按照系统配置的要求和对应的cpu核心绑定,并在要求的cpu中没有被其它中断使用。需要说明的是,在setup_msi_irq中会再次通过msi_compose_msg再次调用__assign_irq_vector,但是由于这时已经存在满足CPU绑定要求的vector,不会多次分配。
从以上分析可以得到MSI-X中断的一个绑定特征:根据当前APIC配置,每个中断都有对应的可以运行的cpu,pci_enable_msix在这些要求的cpu核心上建立了vector (APIC的配置由数据结构struct apic来抽象,其vector_allocation_domain用于决定需要在那些cpu核心上为该中断建立vector),当前我的系统使用的是apic_physflat,对每个MSI中断,其只在一个cpu核心上建立vector,对应的MSI-X中断事实上被绑定到该cpu核心上。在用户通过echo
xxx & /proc/irq/xxx/affinity来调整中断的绑定属性时,内核会重新为该中断分配一个新的在对应核心上可用的vector,但是irq号不会改变。绑定属性调整的调用路径大致为irq_affinity_proc_fops===&irq_affinity_proc_write===& write_irq_affinity===&irq_set_affinity===&__irq_set_affinity_locked===&chip-&irq_set_affinity(msi_set_affinity)。也就是最终通过msi_set_affinity来实现,在该函数中首先通过
__ioapic_set_affinity在绑定属性要求的cpu中选择空闲vector,然后通过__write_msi_msg把配置写入PCIE配置区。需要说明的是:该irq最终可以运行的cpu数量并不完全由用户指定,还与apic的模式相关,对于apic_physflat,实际上只为该irq分配了一个cpu核心,该irq只能运行在用户指定的cpu中的一个,而不是全部。
附:关于全局变量apic
该全局变量为local apic的抽象,在不同的系统配置下,有不同的选择,其最终的选择结果,由内核的config(反应在/arch/x86/kernel/apic/Makefile)和硬件配置等来决定。&
1、 定义各种apic driver&
首先,每种apic配置都会使用apic_driver/ apic_drivers来定义,apic_driver的定义如下
&code class=&hljs cs has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&&span class=&hljs-preprocessor& style=&color: rgb(68, 68, 68); box-sizing: border-&&#&span class=&hljs-keyword& style=&box-sizing: border-&&define&/span& apic_driver(sym)
&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&static&/span& &span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&struct&/span& apic *__apicdrivers_&span class=&hljs-preprocessor& style=&color: rgb(68, 68, 68); box-sizing: border-&&##sym __used
__aligned(&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&sizeof&/span&(&span class=&hljs-keyword& style=&color: rgb(0, 0, 136); box-sizing: border-&&struct&/span& apic *))
__section(.apicdrivers) = { &sym }&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&li style=&box-sizing: border- padding: 0px 5&&2&/li&&li style=&box-sizing: border- padding: 0px 5&&3&/li&&li style=&box-sizing: border- padding: 0px 5&&4&/li&&/ul&
这个定义的目的是把sym的地址写入到名为” .apicdrivers”的段中。&
2、 定义全局符号__apicdrivers和__apicdrivers_end&
在linker script vmlinux.lds.S中,定义了__apicdrivers为” .apicdrivers”段的开始地址,而__apicdrivers_end为结束地址。” .apicdrivers”段中是各个不同的apic配置对应的struct apic。
&code class=&hljs avrasm has-numbering& style=&display: padding: 0 color: box-sizing: border- font-family: 'Source Code Pro',font-size: white-space: border-radius: 0 word-wrap: background:&&
. = ALIGN(&span class=&hljs-number& style=&color: rgb(0, 102, 102); box-sizing: border-&&8&/span&)&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&;&/span&
&span class=&hljs-preprocessor& style=&color: rgb(68, 68, 68); box-sizing: border-&&.apicdrivers&/span& : AT(ADDR(&span class=&hljs-preprocessor& style=&color: rgb(68, 68, 68); box-sizing: border-&&.apicdrivers&/span&) - LOAD_OFFSET) {
__apicdrivers = .&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&;&/span&
*(&span class=&hljs-preprocessor& style=&color: rgb(68, 68, 68); box-sizing: border-&&.apicdrivers&/span&)&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&;&/span&
__apicdrivers_end = .&span class=&hljs-comment& style=&color: rgb(136, 0, 0); box-sizing: border-&&;&/span&
}&/code&&ul class=&pre-numbering& style=&box-sizing: border- position: width: 50 top: 0 left: 0 margin: 0 padding: 6px 0px 40 border-right-width: 1 border-right-style: border-right-color: rgb(221, 221, 221); list-style: text-align: background-color: rgb(238, 238, 238);&&&li style=&box-sizing: border- padding: 0px 5&&1&/li&&li style=&box-sizing: border- padding: 0px 5&&2&/li&&li style=&box-sizing: border- padding: 0px 5&&3&/li&&li style=&box-sizing: border- padding: 0px 5&&4&/li&&li style=&box-sizing: border- padding: 0px 5&&5&/li&&li style=&box-sizing: border- padding: 0px 5&&6&/li&&/ul&
3、 apic的probe&
在初始化过程(start_kernel)中,会调用default_setup_apic_routing(probe_64.c中定义)来完成apic的probe,该函数会按照各个struct apic结构在.apicdrivers中的顺序,依次调用其probe接口,第一个调用返回非0的struct apic结构就被初始化到全局变量apic。也就是:如果有多个apic结构可用,最终会选择在.apicdrivers段中出现的第一个;所以makefile文件中各个.o出现的顺序也会觉得最终的apic probe结果。
request_irq
该函数把irq和用户指定的中断处理函数关联。用户指定的每个处理函数对应于一个struct irqaction结构,这些处理函数构成一个链表,保存在struct irq_desc::action成员中。详细见request_irq===&request_threaded_irq中的处理。
本文已收录于以下专栏:
相关文章推荐
简介irq_desc数据结构用于描述一个irq对应的各种信息,主要有以下方面:
irq_data,描述该irq的irq number,irq chip,irq domain,处理器亲和力等等
相关概念和关键数据结构1、
irq号:在当前系统中全局唯一,对应内核数据结构struct irq_desc,每个外设的中断有一个irq号(体系结构预留的中断,是没有对应的irq_desc结构和irq...
深入剖析Linux中断机制之二---Linux中断的组织形式
转载:http://blog.csdn.net/sailor_8318/archive//2627136.aspx
深入剖析Linux中断机制之二
--Linux中断的组织形式...
Linux的通用中断子系统的一个设计原则就是把底层的硬件实现尽可能地隐藏起来,使得驱动程序的开发人员不用关注底层的实现,要实现这个目标,内核的开发者们必须把硬件相关的内容剥离出来,然后定义一些列标准的...
Linux的通用中断子系统的一个设计原则就是把底层的硬件实现尽可能地隐藏起来,使得驱动程序的开发人员不用关注底层的实现,要实现这个目标,内核的开发者们必须把硬件相关的内容剥离出来,然后定义一些列标准的...
Linux的通用中断子系统的一个设计原则就是把底层的硬件实现尽可能地隐藏起来,使得驱动程序的开发人员不用关注底层的实现,要实现这个目标,内核的开发者们必须把硬件相关的内容剥离出来,然后定义一些列标准的...
Linux的通用中断子系统的一个设计原则就是把底层的硬件实现尽可能地隐藏起来,使得驱动程序的开发人员不用关注底层的实现,要实现这个目标,内核的开发者们必须把硬件相关的内容剥离出来,然后定义一些列标准的...
Linux的通用中断子系统的一个设计原则就是把底层的硬件实现尽可能地隐藏起来,使得驱动程序的开发人员不用关注底层的实现,要实现这个目标,内核的开发者们必须把硬件相关的内容剥离出来,然后定义一些列标准的...
他的最新文章
讲师:宋宝华
讲师:何宇健
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 linux中断处理流程 的文章

 

随机推荐