diff options
author | jhb <jhb@FreeBSD.org> | 2004-01-26 19:34:24 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2004-01-26 19:34:24 +0000 |
commit | fffdd26a90f14d4fd47f1690634668119cbe27b7 (patch) | |
tree | befd833eafbea94fb180c7db5cd801d9ba719015 /sys/i386 | |
parent | 217fb330c26cc6bc733ebc468bcfee39aa6860ea (diff) | |
download | FreeBSD-src-fffdd26a90f14d4fd47f1690634668119cbe27b7.zip FreeBSD-src-fffdd26a90f14d4fd47f1690634668119cbe27b7.tar.gz |
- 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
Diffstat (limited to 'sys/i386')
-rw-r--r-- | sys/i386/acpica/madt.c | 50 |
1 files changed, 43 insertions, 7 deletions
diff --git a/sys/i386/acpica/madt.c b/sys/i386/acpica/madt.c index 01d7ccc..8116d2a 100644 --- a/sys/i386/acpica/madt.c +++ b/sys/i386/acpica/madt.c @@ -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)); + } } /* |