Hi,
nooooooooos wrote:Good, now I think i'm going to use only Apic-Mode...But when I want to connect for example the keyboard IRQ, which bus does connect the keyboard controller to the APIC and then, which IRQ of this bus i should take? And how I do this for general?
Devices
In general, there's 3 different types of devices:
- ISA Devices With Fixed IRQs - these devices always have the same ISA IRQs numbers for historical reasons (backwards compatability). This includes the PS/2 controller (IRQ 1 and IRQ 12), the PIT chip, the CMOS/RTC, the first floppy controller, the first 2 serial ports and the first parallel port. The first 2 PATA/ATAPI/SATA hard disk contollers might also fit in this category - modern hard disk controllers have a "legacy mode" and a "native mode" where they use ISA IRQ 14 or 15 in legacy mode and behave like PCI devices in native mode.
ISA Devices Without Fixed IRQs - these devices use ISA IRQs but there are no predefined IRQs for them. Examples include network cards, sound cards, SCSI controllers, video cards, additional serial ports, additional parallel ports, additional floppy controllers and additional PATA/ATAPI/SATA hard disk controllers; but only if they aren't PCI devices. For these devices you might be able to use "ISA Plug and Play" to detect (and reconfigure) the resources they use, but in general you need to use configuration scripts or something that are setup by the end-user.
PCI Devices - for these devices the BIOS/firmware/OS can automatically detect (and reconfigure) resources the devices use. For the sake of completeness, MCA devices also fit in this category (I'm not sure about EISA).
The I/O APIC
For the I/O APIC, the MP specification and/or ACPI tables will tell you which IRQ each PCI device uses. This means you'll find an "I/O Interrupt Assignment Entry" for every PCI device (and if 2 or more PCI devices share the same IRQ line you'll get 2 or more "I/O Interrupt Assignment Entries" for that IRQ line rather than just one).
In addition, you will (should) also find an "I/O Interrupt Assignment Entry" for every possible ISA IRQ line, regardless of how many devices are connected to that ISA IRQ line (if any).
How To Make Sense Of It - The Lazy Way
The lazy way to do things is to do very little during boot. When an ISA device driver wants to install an IRQ handler you search the MP specification and/or ACPI tables for the "I/O Interrupt Assignment Entry" that corresponds to the ISA IRQ, then install the IRQ handler and enable the IRQ in the I/O APIC.
When a PCI device driver wants to install an IRQ handler you can do something very similar - search for the PCI device in the MP specification and/or ACPI tables (e.g. using it's "bus:device:function") to find out which I/O APIC input it's using, and then either (if nothing is already using the IRQ) install a new IRQ handler and enable the IRQ in the I/O APIC, or (if something is already using the IRQ) find the existing IRQ handler and add the new device's IRQ handler to it. [Note: I'm not going to describe methods of handling PCI IRQ sharing here]
How To Make Sense Of It - The Compatible Way
Another way to do things would be to setup dummy IRQ handlers for ISA devices during boot, so that (for example) if the PIC chips are being used then ISA IRQs generate interrupts 0x20 to 0x2F, and if I/O APICs are being used then ISA IRQs still generate interrupts 0x20 to 0x2F. In this case, an ISA device driver (e.g. a keyboard driver) just needs to install an IRQ handler (e.g. interrupt 0x21) without caring if the OS is using PIC chips or I/O APICs (except for the EOI).
You could handle PCI devices the same way as you would for the lazy way, or you could install dummy handlers and configure these in the I/O APIC during boot too.
Notes
Copy the information you need from the MP specification and/or ACPI tables into your own data structure/s so that you don't need to care which (MP or ACPI) was used after boot, and can reclaim (free and reuse) any RAM that the ACPI tables were using. I'd recommend a hierarchical tree with one entry for each device that describes everything about the device (I/O ports, IRQs, DMA channels, device driver name, status, etc).
Next, realise that (if you're using I/O APICs) the interrupt vector you set (and the IDT entry you use) determines the priority of the interrupt (but makes no difference otherwise). For this reason the "Compatible Way" is probably a bad way. For example, where possible you might want to ensure that some IRQs are higher priority than others (e.g. for me the RTC/CMOS IRQ is the highest priority IRQ when I/O APICs are used).
Also, some PCI devices support MSI (Message Signalled Interrupts) where the device can send an IRQ directly to the CPU/s (without using an I/O APIC input or being configured in the I/O APIC). I assume this is intended to reduce the need for IRQ sharing.
Lastly, for NUMA and SMP systems you might want to consider some intelligent IRQ balancing. There's several conflicting ideas here - attempt to reduce the overhead of interrupts on CPUs running high priority tasks by sending IRQs to CPUs running low priority tasks; make sure IRQs are sent to CPUs where the corresponding IRQ handler and it's data is still in the CPUs cache; don't send IRQs to sleeping/halted CPUs to avoid waking them up (to improve power management/consumption). Stock Linux kernels are crap when it comes to IRQ balancing (there isn't any), but people (AFAIK Intel is a contributor) are trying to fix it with an add-on daemon called "irqbalance". The
irqbalance website does have good ideas and explanations that are worth reading (but I wouldn't recommend fixing bad design with add-on daemons).
Phantom IRQ 7
This is probably a spurious IRQ from the PIC chips. Even though all of the IRQs in the PIC chips are masked/disabled, you can still get spurious IRQs from the PIC chips on IRQ 7 and IRQ 15 (depending on the motherboard).
Cheers,
Brendan