Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/arch/x86_64/kernel/apic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,26 @@ fn ioapic_set_interrupt(irq: u8, apicid: u8, enabled: bool) {
ioapic_write(IOAPIC_REG_TABLE + off + 1, ioredirect_upper);
}

/// Reconfigures an interrupt line for a legacy PCI interrupt.
///
/// [`init_ioapic`] sets up every line for the edge triggered, active high
/// behavior of the ISA interrupts. PCI signals its interrupts level triggered
/// and active low instead.
#[cfg(feature = "pci")]
pub(crate) fn ioapic_set_pci_interrupt(irq: u8, apicid: u8) {
assert!(irq <= 24);

let off = u32::from(irq * 2);
let ioredirect_upper = u32::from(apicid) << 24;
// Vector, active low (bit 13) and level triggered (bit 15).
let ioredirect_lower = u32::from(0x20 + irq) | (1 << 13) | (1 << 15);

debug!("Configuring irq {irq} as level triggered, active low");

ioapic_write(IOAPIC_REG_TABLE + off, ioredirect_lower);
ioapic_write(IOAPIC_REG_TABLE + off + 1, ioredirect_upper);
}

pub fn init_local_apic() {
// Mask out all interrupts we don't need right now.
local_apic_write(IA32_X2APIC_LVT_TIMER, APIC_LVT_MASK);
Expand Down
9 changes: 9 additions & 0 deletions src/drivers/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,15 @@ impl<T: ConfigRegionAccess> PciDevice<T> {
return None;
}

// A legacy PCI interrupt is signaled level triggered and active
// low, while the IOAPIC defaults to the edge triggered, active
// high behavior of the ISA interrupts. Without the correction a
// passed-through device stops delivering interrupts after its
// first one, because the host only unmasks the interrupt once the
// guest has completed a level triggered one.
#[cfg(target_arch = "x86_64")]
crate::arch::kernel::apic::ioapic_set_pci_interrupt(line, 0);

Some(line)
}
5.. => {
Expand Down
Loading