关于PCI IRQ routing的讨论
一直以来,本人就认为,一切事物的兴起和发生均会合时代有关系。任何时期出现的事物都会有一点的历史特征,历史局限性。当然,也要承认他的客观性和合理性。毕竟存在即合理。PC界尤其明显。比如从PATA到SATA总线的进化、ISA总线到PCI总线,再到PCIe总线等。
这里说的PCI IRQrouting 显而易见,必须牵扯到IRQ的分配。IRQ是什么?为何要研究其分配?而PCI IRQ又有何特征?
传统的PIC 模式下两个8259A级联,可以提供最多16个IRQ出来,用来给外围设备向cpu申请中断。以前由于外围设备很少,处理就简单化,每个设备固定对应一个IRQ,比如KB使用irq1、mouse使用irq12,这些一直沿袭下来。
随着PC行业的发展,可用的外围设备已然越来越多,16个IRQ已经不够用了,就算新的APIC模式下也只是24个IRQ。那么自然想到了PCI是否能共享?所以后来相继出现的PCI总线和PCIe总线均是采用IRQ 共享方式。传统的IRQ分配方式已经不能使用新型总线的设计需求了。
PCI总线上设备是并联的,设备都可以使用总线INT#,中断低电平有效。但是,如果所有的设备都共享到一个IRQ上呢?这种情况当然允许,但是必然会影响到系统性能,可以考虑使用IRQ balance的概念,将这些PCI设备平均分配到不同的IRQ上去,以提高系统处理pci中断的性能。这就自然引出了PCI IRQ routing。在Linux在处理多核系统中断时候,就有个工具,实现多核的irq balance。思想是差不多的。
我们知道PCI总线上有四个中断Pin,pci设备一般使用INTA#,但是在多功能设备上,则可以使用INTA#、INTB#等线,那么PCI IRQ routing就是需要将所有pci设备这些INTA# 、INTB#、INTC#、INTD#以一定算法公平的分配到不同的IRQ上去。如下图所示,可以将PCI IRQ routing看成一个路由器,对于网络路由器是一对多的,但是PCI IRQ route则是多对多的。
如何实现PCI irq routing呢?
这部分的功能实现是需要bios工程师来完成,每添加一个pci slot到总线上,则需要将对应的route方式添加到PCI IRQ Router中来。在bios启动时候,PCI BIOS则会通过某种算法找到PCI IRQ Router(函数GetIRQRoutingTable),再依据Router中的方式对PCI 总线上设备分配IRQ。
这里涉及到两个问题:
1、 BIOS中如何针对HW线路---pci slot来配置Routing table
2、 Routing table的工作机制是如何?
问题一:
HW线路设计出来,HW工程师会告知至少两个信息:Pcislot的IDSEL线是选的哪个AD线,而slot上的INTA#、INTB#、INTC#、INTD#分别对应南桥的PIRQx,x可以使1-4-8。HW线路上这种绕法不是随便绕的,需要遵循一定规范:
IRQ= (D + I )mod 4
其中,IRQ表示设备使用主板上的irq序号(1/2/3/4);南桥有PIRQa-PIRQd和PIRQe-PIRQh
D表示PCI槽上IDSEL连接到的主板的AD NO;一般情况为AD[31-11]
I表示PCI槽上INTx#的序号(1/2/3/4).
具体的连线搭配如下图
问题二:
什么是Routing Table呢?这个在Microsoft的官网上可以找到一份权威的文档,说明Routing table的具体概念。这个router表生成之后会保留在memory中,可以搜索F0000h-FFFFFh段的字串“$PIRQ”.找到该字串之后,可以按照格式列出PCI IRQ Routing Table。如下图,是在dos下搜索到的router 表。
按照规范,这里简单的说明一下router表单的内容。
Byte Offset | Size in Bytes | Name |
0 | 4 | Signature |
4 | 2 | Version |
6 | 2 | Table Size |
8 | 1 | PCI Interrupt Router's Bus |
9 | 1 | PCI Interrupt Router's DevFunc |
10 | 2 | PCI Exclusive IRQs |
12 | 4 | Compatible PCI Interrupt Router |
16 | 4 | Miniport Data |
20 | 11 | Reserved (Zero) |
31 | 1 | Checksum |
32 | 16 | First Slot Entry |
48 | 16 | Second Slot Entry |
(N+1)*16 | 16 | Nth Slot Entry |
看上面的表头,byte0开始4个字节表示的Signature即我们要搜索的字串:“$PIRQ”。而byte6开始的两个字节为table size,表示整个Router table的总大小,如果有5个pci slot,那么tableSize为32 + (5 * 16) = 112.
第32个byte开始就是一系列的slot表,每个slot表大小16bytes。其实这16个byte才是PCI IRQ routing的核心。
Slot entry的说明:
Byte Offset | Size in Bytes | Name |
0 | Byte | PCI Bus Number |
1 | Byte | PCI Device Number (in upper five bits) |
2 | Byte | Link Value for INTA# |
3 | Word | IRQ Bitmap for INTA# |
5 | Byte | Link Value for INTB# |
6 | Word | IRQ Bitmap for INTB# |
8 | Byte | Link Value for INTC# |
9 | Word | IRQ Bitmap for INTC# |
11 | Byte | Link Value for INTD# |
12 | Word | IRQ Bitmap for INTD# |
14 | Byte | Slot Number |
15 | Byte | Reserved |
具体解释:
PCI Bus Number:这个是HW给出的slot的pci bus号。
PCI Device Number:对应的slot的PCI DeviceNO,该字节的高5bit表示。Hw给出链接的AD线之后,可以算出slot的DeviceNO。NO.=AD-16。
Link Value for INTx# 为对应的slot上,INTx#对应链接到南桥的哪个PIRQ。
IRQ Bitmap :为PCI 设备可以共享使用的IRQ bitmap。这些irq必须对ISA device来说是reserved。
其中南桥的PIRQ有两组4个:PIRQ[A-D]和PIRQ[E-H]。分别对应南桥的PIRQx#,这些寄存器是需要将PCI可用的irq填入。
如何通过Router表确定PCI分配的IRQ呢?
如下图,举例来说明。
南桥上的两个UHCI,B0/D16/F0和B0/D16/F01. 都是在Bus0 上,Dveice 16上面。
1、 在上图中找到对应的Slotentry行---倒数第二行(行号为E0的那一行)。在RouterTable中Device字节为D0h,取其高5bit,即为16.
2、 在Slot entry行中,解释为:INTA#对应60h(PIRQA#);INTB#对应69h(PIRQF#);INTC#对应62h(PIRQC#);INTD#无分配。
3、 读取两个UHCI的配置寄存器3Dh—interruptPIN。UHCI#1为01h(INTA#);UHCI#2为02h(INTB#).
4、 针对UCHI#1,因为其使用的中断pin为INTA#,那么在其Slotentry行中对应的南桥的PIRQA#寄存器,查找该寄存器中的值为05h,那么相应的UHCI#使用的IRQ为05。
5、 针对UHCI#2,因为其使用的中断PIN为INTB#,哪儿在slotentry行中对应到南桥PIRQF#寄存器,查找寄存器值为07h,那么UHCI#2使用IRQ为7。
6、 其他slot以此类推
PCI IRQ的分配是在PCI总线initial的时候完成的,当然,这个过程需要完成的事情很多,包括memory 、io资源的分配,这中间也有很多学问存在。