Hi,
Selenic wrote:PCI has four interrupt lines, which are shared by all devices in a rotating manner (so if you have four one-function devices, they'll all use different ones, but if you have more or two-function devices then you'll have overlaps and will have to work out which one has sent the interrupt).
It's a little more complex than that - each PCI host controller has 4 interrupt lines (but some systems have more than one PCI host controller); and in some cases devices built into the chipset may be connected to the I/O APIC using "extra" interrupt line/s (which I think is a violation of the PCI spec, but it does happen). On top of that there's PCI devices (e.g. disk controllers) that are emulating legacy devices (and therefore, these PCI devices use ISA IRQ lines not PCI IRQ lines), and MSI.
zity wrote:Every PCI device has an Interrupt Pin value and an Interrupt Line value. If the value of both Interrupt Pin and Interrupt Line is zero, the device doesn't use any IRQs. Interrupt Pin value 1,2,3,4 is normally called A,B,C,D which generates signal 16-19 in the I/O APIC, right?
The "Interrupt line" field in PCI configuration space says which ISA IRQ the interrupt is routed to when you're using the PIC chips (it's useless when you're using I/O APICs).
The MP Specification tables include an "I/O Interrupt Assignment Entry" for each PCI device that can generate an IRQ - e.g. "bus0:device1:function2 is connected I/O APIC input #123". This is fairly easy to use, but it can't handle things that have changed after the firmware set it up (e.g. hotplug PCI).
For ACPI there's "Interrupt Source Overrides" in the MADT which tell you how legacy/ISA IRQs are mapped to I/O APIC inputs. Unlike the MP Specification tables there are no entries describing PCI interrupts. For PCI interrupts you need to use an AML interpretter to decode/execute the AML code (for e.g. the "_PRT" object). This is a massive pain in the neck, but can handle things that change after firmware sets them up.
However, for ACPI the entire AML thing is an ugly mess that takes a long time to understand properly and even longer to implement properly; and if/when your code is perfect it's vulnerable to bugs in the firmware's AML. Also, the same AML can behave differently depending on which "OS name" you tell it; so AML that works perfectly when it's told that the OS is "Windows NT" may be buggy when it's told the OS is something else.
For ISA IRQs it's easy (the MP and/or APCI tables should work). For newer devices that support MSI it's easy (you don't need to care what MP or ACPI tables say if you're using MSI). For older PCI devices you have 4 choices:
- Use the older MP tables for PCI IRQ information (even when ACPI is present)
- Use ACPI AML and learn to cope with an overcomplicated mess
- Implement some sort of IRQ auto-detection feature (e.g. have an IRQ handler for every possible I/O APIC interrupt, and do "IRQ detection" for one device at a time; so that when you get an IRQ that isn't handled by any "already configured" device driver you know it belongs to the device currently doing "IRQ detection").
- Have a motherboard/chipset driver (one for each motherboard/chipset) that can tell you which PCI devices are connected to which I/O APIC inputs.
zity wrote:Oh btw, can I assume that the PCI interrupts always are connected to the I/O APICs line 16-19?
Definitely not. Any ISA IRQ and any PCI IRQ can be connected to any I/O APIC input. Most motherboards tend to connect most ISA IRQs to I/O APIC inputs 0 to 15, but nothing says this must be the case.
For example, nothing prevents I/O APIC inputs 7, 11, 13, 17, 19, 23, 29 and 31 from being used for PCI IRQs (with 2 different PCI host controllers); while I/O APIC inputs 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2 are used for ISA IRQs 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 (in that "upside-down" order). This very messed up example is perfectly valid (as long as there's appropriate MP table entries and ACPI "Interrupt Source Overrides").
Cheers,
Brendan