PCI IRQ Routing
在计算机发展的历史中,很多技术的出现都是为了解决当前所面临的问题而产生和发展出来的,PCI IRQ Routing也不例外,随着计算机系统的功能需求的增加,越来越多的PCI/PCIE设备被加入到系统中来,可是PIC mode下却只有15 个IRQ可供使用(即使是APIC,目前也只是有24个INTIN),而且在早期device都是直接拉线到8259 IRQ,所以一旦确定就没法改变,没有灵活性。于是中断共享就是这种情况下解决这一问题的一个方法(当然其他的方法如使用MSI,SIRQ等也都可以实现中断的复用),可是中断共享了以后又会有新的问题出现 那就是如何分配这些中断的使用 才能够达到负载均衡(Loading Banlance),上述的这些问题就使得PCI IRQ Routing应运而生了。
新的chipset为了Internal Device Interrupt Routing有更大的灵活性,在chipset内部加入了以下几个新的register 为方便SBIOS去配置;这几个register分别是D**IP(Intertupt Pin Register)用于设定对应的device所使用的Interupt Pin;D**IR(Interrupt Router Register)用于设定Interrupt Pin所使用的Interrupt Router(PIRQA#-H#);PIRQ_ROUT (Routing Control Register),用于设定PCI Device Interrupt Pin INTA#-H# 连接到具体PIC controller的IRQ*上,在8259 PIC Mode下SBIOS需要去设置PIRQ_ROUT的register 用于指定具体的IRQ;APIC Mode PIRQ_ROUT则是固定的连接到APIC INTIN pin上,PIRQA#-H#分别连接到INTIN16-INT23。比如我们想配置Device31 Function2 也就是Sata Controller 1的IRQ Routing 是使用INTA# PIRQA# 最终接到PIC 的IRQ5,那么我们需要做的配置将会如下图所示:
PCIE Root Ports扮演的是一个P2P bridge的角色,Root Ports自身产生的Intterupts的处理方式和Internal Devices处理方式一样;Root Ports所接入的设备所产生的Intterupts,则会有Root Ports转发给上一级的Root Complex去处理。为了Intterupt Sharing更加的均衡合理, 在转发给Root Complex之前这些来自Downstream PCIE Devices产生的Intterupt将会被chipset内部的称之为swizzling的一个机制处理过之后再丢给Root Complex,这个部分就是完全的HW机制,它的基本原理就是将来自Downstream PCIE Devices INTA#=H# 产生的中断请求 再转化一遍,比如接在Root Ports 2上的INTA#将会被转成INTB# 然后再丢给上层的Root Complex。经过Swizzling之后,INTA#-H# 会被分别连接到PIRQA#-H#.
PCI Expansion Slots通常是指通过PNP Bridge扩展出来的PCI 插槽(slots),在这些slots上可以接入PCI Device。这些PCI Expansion Slots的 IRQ Routing和PCIE Root Ports非常接近,主要的区别可能就是swizzling的部分需要HW自己去拉,实现的原理和chipset 内置的swizzling应该是类似的。最终PCI Slot上的device经过swizzling之后 ,INTA#-H#会被分别连接到PIRQA#-H#.
SBIOS将PCI IRQ Routing信息配置好以后就需要将这些信息提供给OS,为OS获取系统整个IRQ的分配提供一个基本的参考依据。当然OS并不一定要严格按照SBIOS提供的信息去配置PCI Device它也会依据获取信息动态的去分配这些IRQ Routing。通常SBIOS回报给OS这些信息有两种方式,
对于Legacy OS,SBIOS会通过PCI IRQ Routing Table 的方式告知OS;对于ACPI OS SBIOS则是通过在对应的PCI Device space中提供_PRT method告知ACPI OS 系统的IRQ Routing的方式。
Legacy OS 下Intterupt Controller 通常是工作在PIC Mode,BIOS需要按照微软规定的PCI IRQ Routing Table Specification将PCI Devices IRQ Routing信息回报给Legacy OS。这张IRQ Routing Table的格式如下所示:
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 |
2 |
16 |
First Slot Entry |
48 |
16 |
Second Slot Entry |
(N + 1) * 16 |
16 |
Nth 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 |
SBIOS会将这张table放在F segment(F0000h-FFFFF), 我们可以通过Search “$PIR” Signature去找到这张表格。
ACPI OS 需要通过_PRT Packages 将Routing的信息 Report给OS,而且根据PIC/APIC Mode的不同,_PRT回报给OS 的Packages也会有不同。
A.PIC Mode回报Routing信息的sample code如下所示:(所有code 均来自google 大神):
OperationRegion (/_SB.PCI0.SBRG.PIX0, PCI_Config, 0x60, 0x0C)
Field (/_SB.PCI0.SBRG.PIX0, ByteAcc, NoLock, Preserve)
{
PIRA, 8,
PIRB, 8,
…
}
Device (LNKA)
{
Name (_HID, EisaId ("PNP0C0F"))
Name (_UID, 0x01)
Method (_STA, 0, NotSerialized)
{
And (PIRA, 0x80, Local0)
If (Local0)
{
Return (0x09)
}
Else
{
Return (0x0B)
}
}
Method (_PRS, 0, NotSerialized)
{
Return (PRSA)
}
Method (_DIS, 0, NotSerialized)
{
Or (PIRA, 0x80, PIRA)
}
Method (_CRS, 0, NotSerialized)
{
And (PIRA, 0x0F, Local0)
ShiftLeft (0x01, Local0, IRA0)
Return (BUFA)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, IRA)
FindSetRightBit (IRA, Local0)
Decrement (Local0)
Store (Local0, PIRA)
}
}
Name (PR00, Package (0x12)
{
Package (0x04)
{
0x0001FFFF,
0x00,
LNKA,
0x00
},
Package (0x04)
{
0x0001FFFF,
0x01,
LNKB,
0x00
},
……
Package (0x04)
{
0x001DFFFF,
0x00,
LNKH,
0x00
},
Package (0x04)
{
0x001DFFFF,
0x01,
LNKD,
0x00
},
Package (0x04)
{
0x001DFFFF,
0x02,
LNKC,
0x00
},
Package (0x04)
{
0x001DFFFF,
0x03,
LNKA,
0x00
},
…
})
Device (PCI0)
{
Name (_HID, EisaId ("PNP0A08"))
Name (_CID, 0x030AD041)
Name (_ADR, 0x00)
Method (_PRT, 0, NotSerialized)
{
If (PICM)
{
Return (AR00)
}
Return (PR00)
}
…
}
上面是从网上搜到的一个PIC Mode Routing 信息的一部分的code,我们从底往上看,上述code表示Device (PCI0) scope下的所有device 的Routing信息PICM用于表示当前使用的是PIC 还是APIC Mode,当PIC Mode时就回复PR00的package,PR00表示bus 0 device 0x1f INTA#被routing到PIRQA,bus 0 device 0x1f INTB#被routing到PIRQB,后面的一个bus 0 device 0x1d也是表示相同的意义。PR00 Package中的LNKA LNKB device其实表示的是PIRQA PIRQB这些register以及操作这些register的function ,Device (LNKA)中的_STA表示现在使用的PIRQ* Status 如果Interrupt Routing Enable bit被disable了,将会report 0x1001表示device is disable and do not decode its resource;_PRS表示该PIRQ* 可以使用的interrupt 范围以及相关的属性(level /edge trigger active low/high shared …);_CRS表示当前的Interrupt 以及属性,_SRS用设定相应的interrupt及属性;所有这些操作都是对PIRQ* register进行,这些register则通过ACPI OperationRegion的方式宣告出来如下所示:
OperationRegion (/_SB.PCI0.SBRG.PIX0, PCI_Config, 0x60, 0x0C)
Field (/_SB.PCI0.SBRG.PIX0, ByteAcc, NoLock, Preserve)
{
PIRA, 8,
PIRB, 8,
…
}
B.APIC Mode回报Routing信息的sample code如下所示:(所有code 均来自google 大神):
Name (AR00, Package (0x12)
{
Package (0x04)
{
0x0001FFFF,
0x00,
0x00,
0x10
},
Package (0x04)
{
0x0001FFFF,
0x01,
0x00,
0x11
},
Package (0x04)
{
0x0001FFFF,
0x02,
0x00,
0x12
},
Package (0x04)
{
0x0001FFFF,
0x03,
0x00,
0x13
},
Package (0x04)
{
0x001FFFFF,
0x00,
0x00,
0x12
},
Package (0x04)
{
0x001FFFFF,
0x01,
0x00,
0x13
},
Package (0x04)
{
0x001DFFFF,
0x00,
0x00,
0x17
},
Package (0x04)
{
0x001DFFFF,
0x01,
0x00,
0x13
},
Package (0x04)
{
0x001DFFFF,
0x02,
0x00,
0x12
},
Package (0x04)
{
0x001DFFFF,
0x03,
0x00,
0x10
},
…
})
Device (PCI0)
{
Name (_HID, EisaId ("PNP0A08"))
Name (_CID, 0x030AD041)
Name (_ADR, 0x00)
Method (_PRT, 0, NotSerialized)
{
If (PICM)
{
Return (AR00)
}
Return (PR00)
}
…
}
APIC Mode _PRT就比较简单了,Package AR00回报bus 0 device 0x1f INTA#直接连接到APIC INTIN16 ,INTB#连接到INTIN17,INTC#连接到INTIN18, INTD#连接到INTIN19等等,在ACPI OS下会有APIC相关的driver根据这些信息设置REDIR_TBL中每个INITIN* 的属性及中断向量等信息。
SBIOS如果需要更改Routing信息,就可以按照上面的sample code的做法去修改AR00 PR00 package中的设置。另外关于APIC(I/O APIC ,LAPIC)Base Address GlobalIrqBase…等信息 SBIOS会通过Multiple APIC Description Table (MADT) 回报给ACPI OS,这样OS下的driver就可以直接配置和处理与APIC相关的中断的产生、处理、属性等。
《PCI IRQ Routing Table Specification》
《PCI IRQ Routing on a Multiprocessor ACPI System》
《ACPI Spec 3.0》
Peter
2010-10-29