irq: MSI first, and poll the INTx lines that never arrive
PCI drivers took their interrupt from INTERRUPT_LINE. On real hardware that is the 8259's number, not the IOAPIC pin the device is wired to (that is in ACPI _PRT, which needs AML), so nothing ever arrived. xHCI is entirely interrupt-driven, so the USB keyboard and a USB root would have hung even on a clean boot. Under QEMU the two numbers agree, which is why it never showed. - pci_irq_attach()/pci_irq_detach(): MSI, then MSI-X if the driver allows it, then INTx. The handler is registered before MSI is enabled, so no edge is lost. xHCI, e1000, r8169 and rtl8139 use it. - Lines 24-29 are MSI vectors. The LAPIC error vector moves from 19, which is a PCI pin on Intel chipsets, to 30. Nothing is placed at or above vector 64 (T_SYSCALL). - A storming line is masked and its handlers are polled instead of being left to eat the CPU. A level line that has had a handler for 2 s and never fired is polled every tick by a kernel thread. Tested in QEMU q35 with the root on a USB stick: xHCI and e1000e on MSI; then MSI disabled and INTx deliberately misrouted, where xHCI got zero interrupts and the root still mounted through the poller. i440fx INTx and the rtl8139 hand-over are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HH7xukt4aaiGj1nQEAoQf1
This commit is contained in:
parent
94c936ed98
commit
7e8d5e2821
11 changed files with 407 additions and 35 deletions
|
|
@ -20,7 +20,16 @@
|
|||
// whether its own device actually raised the interrupt and do nothing if it
|
||||
// did not.
|
||||
|
||||
#define NIRQ 24 // IOAPIC redirection entries on a PC
|
||||
// Lines 0-23 are the IOAPIC's pins. 24-29 are MSI vectors, which are not pins
|
||||
// at all -- a device writes the vector number to the local APIC directly --
|
||||
// and are dispatched through the same table so that a handler cannot tell
|
||||
// which kind it is on. 30 and 31 are the LAPIC's error and spurious vectors.
|
||||
// Everything stops below vector 64, which is T_SYSCALL: a line there would
|
||||
// let a user-mode `int $0x40` dispatch an interrupt and EOI one that is not.
|
||||
#define NIRQ_IOAPIC 24
|
||||
#define IRQ_MSI_FIRST 24
|
||||
#define IRQ_MSI_LAST 29
|
||||
#define NIRQ 31
|
||||
#define NCHAIN 4 // handlers that may share one line
|
||||
|
||||
typedef void (*irq_handler_t)(void *arg);
|
||||
|
|
@ -41,4 +50,11 @@ int irq_handler_count(int irq);
|
|||
void irq_dispatch(int irq);
|
||||
|
||||
void irq_init(void);
|
||||
|
||||
// An MSI vector for pci_irq_attach(). -1 when all six are in use.
|
||||
int irq_alloc_msi(void);
|
||||
void irq_free_msi(int irq);
|
||||
|
||||
// The thread that polls PCI lines which never interrupt. After sinit().
|
||||
void irq_poll_start(void);
|
||||
int irq_info(char *buf, int cap); // /proc/interrupts
|
||||
|
|
|
|||
Loading…
Reference in a new issue