- Call acpi_Startup() before parsing interrupt-related APIC resources so we
can look at the ACPI tables. If the startup fails, we panic and tell the user to try rebooting with ACPI disabled. Previously in this case we would try to use $PIR interrupt routing which only works for the atpic while using the apic to handle interrupts which would result in misrouted interrupts and a hang at boot time with no error message. - Read the SCI out of the FADT instead of hardcoding 9 when checking to see if an interrupt override entry is for the SCI. - Try to work around some BIOS brain damage for the SCI's programming by forcing the SCI to be level triggered and active low if it is routed to a non-ISA interrupt (greater than 15) or if it is identity mapped with edge trigger and active high polarity. This should fix some of the hangs with device apic and ACPI that some people see. Reviewed by: njl
This commit is contained in:
parent
217fb330c2
commit
fffdd26a90
@ -320,13 +320,22 @@ madt_setup_local(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Run through the MP table enumerating I/O APICs.
|
||||
* Enumerate I/O APICs and setup interrupt sources.
|
||||
*/
|
||||
static int
|
||||
madt_setup_io(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Try to initialize ACPI so that we can access the FADT. */
|
||||
i = acpi_Startup();
|
||||
if (ACPI_FAILURE(i)) {
|
||||
printf("MADT: ACPI Startup failed with %s\n",
|
||||
AcpiFormatException(i));
|
||||
printf("Try disabling either ACPI or apic support.\n");
|
||||
panic("Using MADT but ACPI doesn't work");
|
||||
}
|
||||
|
||||
/* First, we run through adding I/O APIC's. */
|
||||
madt_walk_table(madt_parse_apics, NULL);
|
||||
|
||||
@ -522,6 +531,7 @@ madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr)
|
||||
{
|
||||
void *new_ioapic, *old_ioapic;
|
||||
u_int new_pin, old_pin;
|
||||
int force_lo;
|
||||
|
||||
if (bootverbose)
|
||||
printf("MADT: intr override: source %u, irq %u\n",
|
||||
@ -534,9 +544,27 @@ madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the SCI is remapped to a non-ISA global interrupt,
|
||||
* force it to level trigger and active-lo polarity.
|
||||
* If the SCI is identity mapped but has edge trigger and
|
||||
* active-hi polarity, also force it to use level/lo.
|
||||
*/
|
||||
force_lo = 0;
|
||||
if (intr->Source == AcpiGbl_FADT->SciInt)
|
||||
if (intr->Interrupt > 15 || (intr->Interrupt == intr->Source &&
|
||||
intr->TriggerMode == TRIGGER_EDGE &&
|
||||
intr->Polarity == POLARITY_ACTIVE_HIGH))
|
||||
force_lo = 1;
|
||||
|
||||
if (intr->Source != intr->Interrupt) {
|
||||
/* XXX: This assumes that the SCI uses IRQ 9. */
|
||||
if (intr->Interrupt > 15 && intr->Source == 9)
|
||||
/*
|
||||
* If the SCI is remapped to a non-ISA global interrupt,
|
||||
* then override the vector we use to setup and allocate
|
||||
* the interrupt.
|
||||
*/
|
||||
if (intr->Interrupt > 15 &&
|
||||
intr->Source == AcpiGbl_FADT->SciInt)
|
||||
acpi_OverrideInterruptLevel(intr->Interrupt);
|
||||
else
|
||||
ioapic_remap_vector(new_ioapic, new_pin, intr->Source);
|
||||
@ -548,10 +576,18 @@ madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr)
|
||||
intr->Source)
|
||||
ioapic_disable_pin(old_ioapic, old_pin);
|
||||
}
|
||||
ioapic_set_triggermode(new_ioapic, new_pin,
|
||||
interrupt_trigger(intr->TriggerMode));
|
||||
ioapic_set_polarity(new_ioapic, new_pin,
|
||||
interrupt_polarity(intr->Polarity));
|
||||
if (force_lo) {
|
||||
printf(
|
||||
"MADT: Forcing active-lo polarity and level trigger for IRQ %d\n",
|
||||
intr->Source);
|
||||
ioapic_set_polarity(new_ioapic, new_pin, 0);
|
||||
ioapic_set_triggermode(new_ioapic, new_pin, 0);
|
||||
} else {
|
||||
ioapic_set_polarity(new_ioapic, new_pin,
|
||||
interrupt_polarity(intr->Polarity));
|
||||
ioapic_set_triggermode(new_ioapic, new_pin,
|
||||
interrupt_trigger(intr->TriggerMode));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user