- 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:
John Baldwin 2004-01-26 19:34:24 +00:00
parent bbc2815c8d
commit afa632035c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=125048

View file

@ -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));
}
}
/*