Changeset View
Standalone View
sys/x86/x86/io_apic.c
Context not available. | |||||
u_int io_apic_id:4; | u_int io_apic_id:4; | ||||
u_int io_intbase:8; /* System Interrupt base */ | u_int io_intbase:8; /* System Interrupt base */ | ||||
u_int io_numintr:8; | u_int io_numintr:8; | ||||
u_int io_haseoi:1; | |||||
volatile ioapic_t *io_addr; /* XXX: should use bus_space */ | volatile ioapic_t *io_addr; /* XXX: should use bus_space */ | ||||
vm_paddr_t io_paddr; | vm_paddr_t io_paddr; | ||||
STAILQ_ENTRY(ioapic) io_next; | STAILQ_ENTRY(ioapic) io_next; | ||||
Context not available. | |||||
SYSCTL_INT(_hw_apic, OID_AUTO, enable_extint, CTLFLAG_RDTUN, &enable_extint, 0, | SYSCTL_INT(_hw_apic, OID_AUTO, enable_extint, CTLFLAG_RDTUN, &enable_extint, 0, | ||||
"Enable the ExtINT pin in the first I/O APIC"); | "Enable the ExtINT pin in the first I/O APIC"); | ||||
static __inline void | static void | ||||
_ioapic_eoi_source(struct intsrc *isrc) | _ioapic_eoi_source(struct intsrc *isrc, int locked) | ||||
{ | { | ||||
struct ioapic_intsrc *src; | |||||
struct ioapic *io; | |||||
volatile uint32_t *apic_eoi; | |||||
uint32_t low1; | |||||
lapic_eoi(); | lapic_eoi(); | ||||
if (!lapic_eoi_suppression) | |||||
return; | |||||
src = (struct ioapic_intsrc *)isrc; | |||||
if (src->io_edgetrigger) | |||||
return; | |||||
io = (struct ioapic *)isrc->is_pic; | |||||
/* | |||||
* Handle targeted EOI for level-triggered pins, if broadcast | |||||
* EOI suppression is supported by LAPICs. | |||||
*/ | |||||
if (io->io_haseoi) { | |||||
/* | |||||
* If IOAPIC has EOI Register, simply write vector | |||||
* number into the reg. | |||||
*/ | |||||
apic_eoi = (volatile uint32_t *)((volatile char *) | |||||
io->io_addr + IOAPIC_EOIR); | |||||
*apic_eoi = src->io_vector; | |||||
} else { | |||||
/* | |||||
* Otherwise, if IO-APIC is too old to provide EOIR, | |||||
* do what Intel did for the Linux kernel. Temporary | |||||
* switch the pin to edge-trigger and back, masking | |||||
* the pin during the trick. | |||||
*/ | |||||
if (!locked) | |||||
mtx_lock_spin(&icu_lock); | |||||
low1 = src->io_lowreg; | |||||
low1 &= ~IOART_TRGRLVL; | |||||
low1 |= IOART_TRGREDG | IOART_INTMSET; | |||||
ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(src->io_intpin), | |||||
low1); | |||||
ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(src->io_intpin), | |||||
src->io_lowreg); | |||||
if (!locked) | |||||
mtx_unlock_spin(&icu_lock); | |||||
} | |||||
} | } | ||||
static u_int | static u_int | ||||
Context not available. | |||||
} | } | ||||
if (eoi == PIC_EOI) | if (eoi == PIC_EOI) | ||||
_ioapic_eoi_source(isrc); | _ioapic_eoi_source(isrc, 1); | ||||
mtx_unlock_spin(&icu_lock); | mtx_unlock_spin(&icu_lock); | ||||
} | } | ||||
Context not available. | |||||
ioapic_eoi_source(struct intsrc *isrc) | ioapic_eoi_source(struct intsrc *isrc) | ||||
{ | { | ||||
_ioapic_eoi_source(isrc); | _ioapic_eoi_source(isrc, 0); | ||||
} | } | ||||
/* | /* | ||||
Context not available. | |||||
io->io_addr = apic; | io->io_addr = apic; | ||||
io->io_paddr = addr; | io->io_paddr = addr; | ||||
if (bootverbose) { | |||||
printf("ioapic%u: ver 0x%02x maxredir 0x%02x\n", io->io_id, | |||||
(value & IOART_VER_VERSION), (value & IOART_VER_MAXREDIR) | |||||
>> MAXREDIRSHIFT); | |||||
} | |||||
/* | |||||
neel: I suspect that this comment only applies to Intel IO-APICs. I wasn't able to find any… | |||||
Not Done Inline ActionsAMD seems to not provide EOI suppression mechanism in LAPIC. There is not capability bit in the version register, and no enable bit in the spurious interrupt vector register. Since I do not set lapic_eoi_suppression to true for such machine, io_haseoi does not matter at all. But, according to the sb7xxx chipset documentation, AMD IO-APIC version is 0x21, and it has compatible EOIR implementation. I have no idea what bumped version of the IO-APIC signifies. kib: AMD seems to not provide EOI suppression mechanism in LAPIC. There is not capability bit in… | |||||
* The summary information about IO-APIC versions is taken from | |||||
* the Linux kernel source: | |||||
* 0Xh 82489DX | |||||
* 1Xh I/OAPIC or I/O(x)APIC which are not PCI 2.2 Compliant | |||||
* 2Xh I/O(x)APIC which is PCI 2.2 Compliant | |||||
* 30h-FFh Reserved | |||||
* IO-APICs with version >= 0x20 have working EOIR register. | |||||
*/ | |||||
io->io_haseoi = (value & IOART_VER_VERSION) >= 0x20; | |||||
Not Done Inline ActionsIt might be useful to allow this to be set to 0 via a tunable to be able to test the case where local APIC supports EOI suppression but the IO-APIC does not. neel: It might be useful to allow this to be set to 0 via a tunable to be able to test the case where… | |||||
Not Done Inline ActionsI tested this by always setting io_haseoi to 0. The way I test both io_haseoi 0 or 1 is to watch the interrupt statistic with vmstat -i. I claim that EOI is working properly when non-MSI level interrupts are delivered more than once. Do you want this knob available at field, or just noted it so the behaviour with older ioapics can be tested ? kib: I tested this by always setting io_haseoi to 0. The way I test both io_haseoi 0 or 1 is to… | |||||
Not Done Inline ActionsThanks. It was mainly for testing behavior of older ioapics. neel: Thanks. It was mainly for testing behavior of older ioapics. | |||||
/* | /* | ||||
* Initialize pins. Start off with interrupts disabled. Default | * Initialize pins. Start off with interrupts disabled. Default | ||||
* to active-hi and edge-triggered for ISA interrupts and active-lo | * to active-hi and edge-triggered for ISA interrupts and active-lo | ||||
Context not available. |
I suspect that this comment only applies to Intel IO-APICs. I wasn't able to find any information about EOI suppression for AMD.