[haiku-commits] r41528 - in haiku/trunk: headers/private/kernel/arch/x86 src/system/kernel/arch/x86

  • From: mmlr@xxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 16 May 2011 14:57:40 +0200 (CEST)

Author: mmlr
Date: 2011-05-16 14:57:40 +0200 (Mon, 16 May 2011)
New Revision: 41528
Changeset: https://dev.haiku-os.org/changeset/41528

Modified:
   haiku/trunk/headers/private/kernel/arch/x86/pic.h
   haiku/trunk/src/system/kernel/arch/x86/ioapic.cpp
   haiku/trunk/src/system/kernel/arch/x86/pic.cpp
Log:
* Implement interrupt source overrides. We install a relay interrupt handler
  at the override entry to trigger the overriden vector so that we don't need
  to configure any additional redirections.
* Also configures the polarity and trigger modes found in the override entry.
* When disabling the legacy PIC, retrieve the enabled interrupts and re-enable
  then in the IO-APIC. This will for example make the ACPI SCI work that is
  installed prior to switching interrupt models. Through the transparent support
  for interrupt source overrides it'll also automatically relay from the old to
  the new vector.

This should make ACPI interrupts work and should support relocating the ISA PIT
from irq 0 to a different global system interrupt (usually 2) so that it can
still work when IO-APICs are in use.


Modified: haiku/trunk/headers/private/kernel/arch/x86/pic.h
===================================================================
--- haiku/trunk/headers/private/kernel/arch/x86/pic.h   2011-05-16 08:42:30 UTC 
(rev 41527)
+++ haiku/trunk/headers/private/kernel/arch/x86/pic.h   2011-05-16 12:57:40 UTC 
(rev 41528)
@@ -5,7 +5,9 @@
 #ifndef _KERNEL_ARCH_x86_PIC_H
 #define _KERNEL_ARCH_x86_PIC_H
 
+#include <SupportDefs.h>
+
 void pic_init();
-void pic_disable();
+void pic_disable(uint16& enabledInterrupts);
 
 #endif // _KERNEL_ARCH_x86_PIC_H

Modified: haiku/trunk/src/system/kernel/arch/x86/ioapic.cpp
===================================================================
--- haiku/trunk/src/system/kernel/arch/x86/ioapic.cpp   2011-05-16 08:42:30 UTC 
(rev 41527)
+++ haiku/trunk/src/system/kernel/arch/x86/ioapic.cpp   2011-05-16 12:57:40 UTC 
(rev 41528)
@@ -84,7 +84,9 @@
 #define IO_APIC_INTERRUPT_VECTOR_SHIFT         0
 #define IO_APIC_INTERRUPT_VECTOR_MASK          0xff
 
+#define ISA_INTERRUPT_COUNT                                    16
 
+
 struct ioapic_registers {
        volatile uint32 io_register_select;
        uint32                  reserved[3];
@@ -109,6 +111,7 @@
 
 
 static ioapic* sIOAPICs = NULL;
+static int32 sSourceOverrides[ISA_INTERRUPT_COUNT];
 
 
 // #pragma mark - I/O APIC
@@ -218,6 +221,12 @@
 static void
 ioapic_enable_io_interrupt(int32 gsi)
 {
+       // If enabling an overriden source is attempted, enable the override 
entry
+       // instead. An interrupt handler was installed at the override GSI to 
rely
+       // interrupts to the overriden source.
+       if (gsi < ISA_INTERRUPT_COUNT && sSourceOverrides[gsi] != 0)
+               gsi = sSourceOverrides[gsi];
+
        struct ioapic* ioapic = find_ioapic(gsi);
        if (ioapic == NULL)
                return;
@@ -342,8 +351,8 @@
                        entry |= (IO_APIC_TRIGGER_MODE_EDGE << 
IO_APIC_TRIGGER_MODE_SHIFT)
                                | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << 
IO_APIC_PIN_POLARITY_SHIFT)
                                | (IO_APIC_DELIVERY_MODE_EXT_INT << 
IO_APIC_DELIVERY_MODE_SHIFT);
-               } else if (gsi < 16) {
-                       // make GSIs 1-15 ISA interrupts
+               } else if (gsi < ISA_INTERRUPT_COUNT) {
+                       // identity map the legacy ISA interrupts
                        entry |= (IO_APIC_TRIGGER_MODE_EDGE << 
IO_APIC_TRIGGER_MODE_SHIFT)
                                | (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << 
IO_APIC_PIN_POLARITY_SHIFT)
                                | (IO_APIC_DELIVERY_MODE_FIXED << 
IO_APIC_DELIVERY_MODE_SHIFT);
@@ -362,15 +371,18 @@
 }
 
 
+static int32
+ioapic_source_override_handler(void* data)
+{
+       int32 vector = (int32)data;
+       bool levelTriggered = ioapic_is_level_triggered_interrupt(vector);
+       return int_io_interrupt_handler(vector, levelTriggered);
+}
+
+
 static status_t
-acpi_enumerate_ioapics(acpi_module_info* acpi)
+acpi_enumerate_ioapics(acpi_table_madt* madt)
 {
-       acpi_table_madt* madt = NULL;
-       if (acpi->get_table(ACPI_SIG_MADT, 0, (void**)&madt) != B_OK) {
-               dprintf("failed to get MADT from ACPI, not configuring 
io-apics\n");
-               return B_ERROR;
-       }
-
        struct ioapic* lastIOAPIC = sIOAPICs;
 
        acpi_subtable_header* apicEntry
@@ -418,30 +430,90 @@
                                lastIOAPIC = ioapic;
                                break;
                        }
+               }
 
-#ifdef TRACE_IOAPIC
-                       case ACPI_MADT_TYPE_LOCAL_APIC:
-                       {
-                               // purely informational
-                               acpi_madt_local_apic* info = 
(acpi_madt_local_apic*)apicEntry;
-                               dprintf("found local apic with id %u, processor 
id %u, "
-                                       "flags 0x%08lx\n", info->Id, 
info->ProcessorId,
-                                       (uint32)info->LapicFlags);
-                               break;
-                       }
+               apicEntry
+                       = (acpi_subtable_header*)((uint8*)apicEntry + 
apicEntry->Length);
+       }
 
+       return B_OK;
+}
+
+
+static void
+acpi_configure_source_overrides(acpi_table_madt* madt)
+{
+       acpi_subtable_header* apicEntry
+               = (acpi_subtable_header*)((uint8*)madt + 
sizeof(acpi_table_madt));
+       void* end = ((uint8*)madt + madt->Header.Length);
+       while (apicEntry < end) {
+               switch (apicEntry->Type) {
                        case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
                        {
-                               // TODO: take these into account
                                acpi_madt_interrupt_override* info
                                        = 
(acpi_madt_interrupt_override*)apicEntry;
                                dprintf("found interrupt override for bus %u, 
source irq %u, "
                                        "global irq %lu, flags 0x%08lx\n", 
info->Bus,
                                        info->SourceIrq, 
(uint32)info->GlobalIrq,
                                        (uint32)info->IntiFlags);
+
+                               if (info->SourceIrq >= ISA_INTERRUPT_COUNT) {
+                                       dprintf("source override exceeds isa 
interrupt count\n");
+                                       break;
+                               }
+
+                               if (info->SourceIrq != info->GlobalIrq) {
+                                       // we need a vector mapping
+                                       
install_io_interrupt_handler(info->GlobalIrq,
+                                               
&ioapic_source_override_handler, (void*)info->SourceIrq,
+                                               B_NO_ENABLE_COUNTER);
+
+                                       sSourceOverrides[info->SourceIrq] = 
info->GlobalIrq;
+                               }
+
+                               // configure non-standard polarity/trigger modes
+                               uint32 config = 0;
+                               switch (info->IntiFlags & 
ACPI_MADT_POLARITY_MASK) {
+                                       case ACPI_MADT_POLARITY_ACTIVE_LOW:
+                                               config = B_LOW_ACTIVE_POLARITY;
+                                               break;
+                                       default:
+                                               dprintf("invalid polarity in 
source override\n");
+                                               // fall through and assume 
active high
+                                       case ACPI_MADT_POLARITY_ACTIVE_HIGH:
+                                       case ACPI_MADT_POLARITY_CONFORMS:
+                                               config = B_HIGH_ACTIVE_POLARITY;
+                                               break;
+                               }
+
+                               switch (info->IntiFlags & 
ACPI_MADT_TRIGGER_MASK) {
+                                       case ACPI_MADT_TRIGGER_LEVEL:
+                                               config |= B_LEVEL_TRIGGERED;
+                                               break;
+                                       default:
+                                               dprintf("invalid trigger mode 
in source override\n");
+                                               // fall through and assume edge 
triggered
+                                       case ACPI_MADT_TRIGGER_CONFORMS:
+                                       case ACPI_MADT_TRIGGER_EDGE:
+                                               config |= B_EDGE_TRIGGERED;
+                                               break;
+                               }
+
+                               ioapic_configure_io_interrupt(info->GlobalIrq, 
config);
                                break;
                        }
 
+#ifdef TRACE_IOAPIC
+                       case ACPI_MADT_TYPE_LOCAL_APIC:
+                       {
+                               // purely informational
+                               acpi_madt_local_apic* info = 
(acpi_madt_local_apic*)apicEntry;
+                               dprintf("found local apic with id %u, processor 
id %u, "
+                                       "flags 0x%08lx\n", info->Id, 
info->ProcessorId,
+                                       (uint32)info->LapicFlags);
+                               break;
+                       }
+
                        case ACPI_MADT_TYPE_NMI_SOURCE:
                        {
                                // TODO: take these into account
@@ -483,8 +555,6 @@
                apicEntry
                        = (acpi_subtable_header*)((uint8*)apicEntry + 
apicEntry->Length);
        }
-
-       return B_OK;
 }
 
 
@@ -555,7 +625,13 @@
        BPrivate::CObjectDeleter<const char, status_t>
                acpiModulePutter(B_ACPI_MODULE_NAME, put_module);
 
-       status = acpi_enumerate_ioapics(acpiModule);
+       acpi_table_madt* madt = NULL;
+       if (acpiModule->get_table(ACPI_SIG_MADT, 0, (void**)&madt) != B_OK) {
+               dprintf("failed to get MADT from ACPI, not configuring 
io-apics\n");
+               return;
+       }
+
+       status = acpi_enumerate_ioapics(madt);
        if (status != B_OK) {
                // We don't treat this case as fatal just yet. If we are able to
                // route everything with the available IO-APICs we're fine, if 
not
@@ -607,6 +683,9 @@
                return;
        }
 
+       // configure the source overrides, but let the PCI config below 
override it
+       acpi_configure_source_overrides(madt);
+
        // configure IO-APIC interrupts from PCI routing table
        for (int i = 0; i < table.Count(); i++) {
                irq_routing_entry& entry = table.ElementAt(i);
@@ -623,8 +702,15 @@
                // shouldn't really harm, but should eventually be corrected.
 
        // disable the legacy PIC
-       pic_disable();
+       uint16 legacyInterrupts;
+       pic_disable(legacyInterrupts);
 
+       // enable previsouly enabled legacy interrupts
+       for (uint8 i = 0; i < 16; i++) {
+               if ((legacyInterrupts & (1 << i)) != 0)
+                       ioapic_enable_io_interrupt(i);
+       }
+
        // prefer the ioapic over the normal pic
        dprintf("using io-apics for interrupt routing\n");
        arch_int_set_interrupt_controller(ioapicController);

Modified: haiku/trunk/src/system/kernel/arch/x86/pic.cpp
===================================================================
--- haiku/trunk/src/system/kernel/arch/x86/pic.cpp      2011-05-16 08:42:30 UTC 
(rev 41527)
+++ haiku/trunk/src/system/kernel/arch/x86/pic.cpp      2011-05-16 12:57:40 UTC 
(rev 41528)
@@ -235,8 +235,11 @@
 
 
 void
-pic_disable()
+pic_disable(uint16& enabledInterrupts)
 {
+       enabledInterrupts = in8(PIC_MASTER_MASK) | in8(PIC_SLAVE_MASK) << 8;
+       enabledInterrupts &= 0xfffb; // remove slave PIC from the mask
+
        // Mask off all interrupts on master and slave
        out8(0xff, PIC_MASTER_MASK);
        out8(0xff, PIC_SLAVE_MASK);


Other related posts:

  • » [haiku-commits] r41528 - in haiku/trunk: headers/private/kernel/arch/x86 src/system/kernel/arch/x86 - mmlr