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:
Nexoniarz 2026-10-22 10:29:24 +02:00
commit 7e8d5e2821
11 changed files with 407 additions and 35 deletions

View file

@ -468,9 +468,9 @@ r8169_probe(struct pci_dev *d)
wr16(r, R_IMR, ISR_ROK | ISR_RER | ISR_TOK | ISR_TER |
ISR_RDU | ISR_LINKCHG);
if (d->irq != 0xFF && d->irq < 24)
irq_register(d->irq, r8169_intr, r, "r8169", 1);
else
// MSI first: every 8111 has it, and on the boards these are soldered to it
// is the only interrupt that is sure to arrive. See pci_irq_attach().
if (pci_irq_attach(d, r8169_intr, r, "r8169", 0) < 0)
cprintf("r8169: no usable interrupt line; the link will be polled\n");
r->ready = 1;
@ -487,10 +487,10 @@ r8169_probe(struct pci_dev *d)
uint32 xid = (rd32(r, R_TCR) >> 20) & 0xFCF;
int bmsr = mii_read(r, 1);
cprintf("r8169: xid %x, %x:%x:%x:%x:%x:%x, irq %d, %s (bmsr %x)\n",
cprintf("r8169: xid %x, %x:%x:%x:%x:%x:%x, irq %d (%s), %s (bmsr %x)\n",
xid,
r->mac[0], r->mac[1], r->mac[2], r->mac[3], r->mac[4], r->mac[5],
d->irq,
d->irq_line, pci_irq_kind(d),
(rd8(r, R_PHYSTATUS) & PHYSTATUS_LINK) ? "link up" : "link down",
bmsr);
}