[haiku-commits] r41328 - haiku/trunk/src/system/kernel/arch/x86

  • From: mmlr@xxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 5 May 2011 21:59:05 +0200 (CEST)

Author: mmlr
Date: 2011-05-05 21:59:04 +0200 (Thu, 05 May 2011)
New Revision: 41328
Changeset: https://dev.haiku-os.org/changeset/41328

Modified:
   haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp
   haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp
   haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h
Log:
* Change some of the structure fields to more sensible types.
* The irq values we get from ACPICA are already converted, remove the wrong
  extra conversion from bitfield to irq number.
* Add and handle extended irq structures.
* Disable the legacy PIC when done configuring the IOAPIC. Since during that
  configuration the ACPI module is initialized, the ACPI SCI is still enabled
  in the PIC instead of the IOAPIC. We'll have to delay that routing in the
  ACPI module for it to work.
* Correctly handle the fixed IRQ case for the PCI interrupt routing (hopefully).
* Actually allow for enumeration of possible IRQ settings. Not yet used though.

All of this brings us a bit closer, though it still won't work for PCI
interrupts. ISA interrupts work fine through the IOAPIC as far as my hardware
goes, but PCI interrupts are connected to dedicated IOAPIC pins and I still
haven't figured out how to determine their exact routing.


Modified: haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp
===================================================================
--- haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp 2011-05-05 19:41:52 UTC 
(rev 41327)
+++ haiku/trunk/src/system/kernel/arch/x86/arch_int.cpp 2011-05-05 19:59:04 UTC 
(rev 41328)
@@ -415,6 +415,15 @@
 }
 
 
+static void
+pic_disable()
+{
+       // Mask off all interrupts on master and slave
+       out8(0xff, PIC_MASTER_MASK);
+       out8(0xff, PIC_SLAVE_MASK);
+}
+
+
 // #pragma mark - I/O APIC
 
 
@@ -615,6 +624,8 @@
                = ((version >> IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT)
                        & IO_APIC_MAX_REDIRECTION_ENTRY_MASK);
 
+       TRACE(("ioapic has %lu entries\n", sIOAPICMaxRedirectionEntry + 1));
+
        // use the boot CPU as the target for all interrupts
        uint64 targetAPIC = args->arch_args.cpu_apic_id[0];
 
@@ -652,26 +663,35 @@
        for (uint32 i = 0; i < 256; i++)
                sIRQToIOAPICPin[i] = i;
 
-       // configure apic interrupts assume 1:1 mapping
+       // configure io apic interrupts from pci routing table
        for (int i = 0; i < table.Count(); i++) {
-               irq_routing_entry& entry = table.ElementAt(i);
-               irq_descriptor irqDescriptor;
-               read_current_irq(acpiModule, entry.source, &irqDescriptor);
+               uint8 irq = 0;
                uint32 config = 0;
-               config |= irqDescriptor.polarity;
-               config |= irqDescriptor.interrupt_mode;
 
-               int32 num = entry.source_index;
-               for (int a = 0; a < 16 && num == 0; a++) {
-                       if (irqDescriptor.irq >> i & 0x01) {
-                               num = a;
-                               break;
+               irq_routing_entry& entry = table.ElementAt(i);
+               if (entry.source == 0) {
+                       // fixed irq configuration
+                       irq = entry.source_index;
+                       config = B_LEVEL_TRIGGERED | B_LOW_ACTIVE_POLARITY;
+               } else {
+                       // irq comes from the link device and is configurable
+                       irq_descriptor irqDescriptor;
+                       status = read_current_irq(acpiModule, entry.source, 
&irqDescriptor);
+                       if (status != B_OK) {
+                               dprintf("failed to read current irq config of 
link device\n");
+                               continue;
                        }
+
+                       irq = irqDescriptor.irq;
+                       config = irqDescriptor.polarity | 
irqDescriptor.interrupt_mode;
                }
 
-               ioapic_configure_io_interrupt(num, config);
+               ioapic_configure_io_interrupt(irq, config);
        }
 
+       // disable the legacy PIC
+       pic_disable();
+
        // prefer the ioapic over the normal pic
        dprintf("using ioapic for interrupt routing\n");
        sCurrentPIC = &ioapicController;

Modified: haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp
===================================================================
--- haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp        
2011-05-05 19:41:52 UTC (rev 41327)
+++ haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.cpp        
2011-05-05 19:59:04 UTC (rev 41328)
@@ -49,7 +49,7 @@
        const char* levelTriggeredString = "level triggered";
        const char* edgeTriggeredString = " edge triggered";
 
-       dprintf("irq: %i, shareable: %i, polarity: %s, interrupt_mode: %s\n",
+       dprintf("irq: %u, shareable: %u, polarity: %s, interrupt_mode: %s\n",
                descriptor->irq, descriptor->shareable,
                descriptor->polarity == B_HIGH_ACTIVE_POLARITY ? 
activeHighString
                        : activeLowString,
@@ -87,11 +87,14 @@
        acpi_pci_routing_table* acpiTable = 
(acpi_pci_routing_table*)buffer.pointer;
        while (acpiTable->length) {
                acpi_handle source;
-               if (acpi->get_handle(NULL, acpiTable->source, &source) == B_OK) 
{
+               bool noSource = acpiTable->source == NULL || 
acpiTable->source[0] == 0;
+               if (noSource
+                       || acpi->get_handle(NULL, acpiTable->source, &source) 
== B_OK) {
+
                        irqEntry.device_address = acpiTable->address;
                        irqEntry.pin = acpiTable->pin;
-                       irqEntry.source = source;
-                       irqEntry.source_index = acpiTable->sourceIndex;
+                       irqEntry.source = noSource ? 0 : source;
+                       irqEntry.source_index = acpiTable->source_index;
                        table->PushBack(irqEntry);
                }
 
@@ -143,38 +146,113 @@
 }
 
 
-status_t
+static status_t
 read_irq_descriptor(acpi_module_info* acpi, acpi_handle device,
-       const char* method, irq_descriptor* descriptor)
+       bool readCurrent, irq_descriptor* descriptor)
 {
        acpi_data buffer;
        buffer.pointer = NULL;
        buffer.length = ACPI_ALLOCATE_BUFFER;
-       status_t status = acpi->get_current_resources(device, &buffer);
+
+       status_t status;
+       if (readCurrent)
+               status = acpi->get_current_resources(device, &buffer);
+       else
+               status = acpi->get_possible_resources(device, &buffer);
+
        if (status != B_OK) {
+               dprintf("failed to read %s resources for irq\n",
+                       readCurrent ? "current" : "possible");
                free(buffer.pointer);
                return status;
        }
 
+       descriptor->irq = 0;
        acpi_resource* resource = (acpi_resource*)buffer.pointer;
-       //TODO Don't hardcode END TAG
+       // TODO: Don't hardcode END TAG
        while (resource->type != 7) {
-               //TODO: Don't hardcode IRQ or Extended IRQ
-               if (resource->type == 0 || resource->type == 15) {
-                       descriptor->irq = resource->interrupts[0];
-                       descriptor->shareable = resource->sharable != 0;
-                       descriptor->interrupt_mode = resource->triggering == 0 ?
-                               B_LEVEL_TRIGGERED : B_EDGE_TRIGGERED;
-                       descriptor->polarity = resource->polarity == 0 ?
-                               B_HIGH_ACTIVE_POLARITY : B_LOW_ACTIVE_POLARITY;
+               // TODO: Don't hardcode IRQ and Extended IRQ
+               switch (resource->type) {
+                       case 0: // IRQ
+                       {
+                               acpi_resource_irq* irq = 
(acpi_resource_irq*)resource;
+                               if (irq->interrupt_count < 1) {
+                                       dprintf("acpi irq resource with no 
interrupts\n");
+                                       break;
+                               }
 
-                       free(buffer.pointer);
-                       return B_OK;
+                               descriptor->irq = irq->interrupts[0];
+                               descriptor->shareable = irq->sharable != 0;
+                               descriptor->interrupt_mode = irq->triggering == 0
+                                       ? B_LEVEL_TRIGGERED : B_EDGE_TRIGGERED;
+                               descriptor->polarity = irq->polarity == 0
+                                       ? B_HIGH_ACTIVE_POLARITY : 
B_LOW_ACTIVE_POLARITY;
+
+#ifdef TRACE_PRT
+                               dprintf("acpi irq resource (%s):\n",
+                                       readCurrent ? "current" : "possible");
+                               dprintf("\ttriggering: %s\n",
+                                       irq->triggering == 0 ? "level" : 
"edge");
+                               dprintf("\tpolarity: %s active\n",
+                                       irq->polarity == 0 ? "high" : "low");
+                               dprintf("\tsharable: %s\n", irq->sharable != 0 
? "yes" : "no");
+                               dprintf("\tcount: %u\n", irq->interrupt_count);
+                               if (irq->interrupt_count > 0) {
+                                       dprintf("\tinterrupts:");
+                                       for (uint16 i = 0; i < 
irq->interrupt_count; i++)
+                                               dprintf(" %u", 
irq->interrupts[i]);
+                                       dprintf("\n");
+                               }
+#endif
+                               break;
+                       }
+
+                       case 15: // Extended IRQ
+                       {
+                               acpi_resource_extended_irq* irq
+                                       = (acpi_resource_extended_irq*)resource;
+                               if (irq->interrupt_count < 1) {
+                                       dprintf("acpi extended irq resource 
with no interrupts\n");
+                                       break;
+                               }
+
+                               descriptor->irq = irq->interrupts[0];
+                               descriptor->shareable = irq->sharable != 0;
+                               descriptor->interrupt_mode = irq->triggering == 0
+                                       ? B_LEVEL_TRIGGERED : B_EDGE_TRIGGERED;
+                               descriptor->polarity = irq->polarity == 0
+                                       ? B_HIGH_ACTIVE_POLARITY : 
B_LOW_ACTIVE_POLARITY;
+
+#ifdef TRACE_PRT
+                               dprintf("acpi extended irq resource (%s):\n",
+                                       readCurrent ? "current" : "possible");
+                               dprintf("\tproducer: %s\n",
+                                       irq->producer_consumer ? "yes" : "no");
+                               dprintf("\ttriggering: %s\n",
+                                       irq->triggering == 0 ? "level" : 
"edge");
+                               dprintf("\tpolarity: %s active\n",
+                                       irq->polarity == 0 ? "high" : "low");
+                               dprintf("\tsharable: %s\n", irq->sharable != 0 
? "yes" : "no");
+                               dprintf("\tcount: %u\n", irq->interrupt_count);
+                               if (irq->interrupt_count > 0) {
+                                       dprintf("\tinterrupts:");
+                                       for (uint16 i = 0; i < 
irq->interrupt_count; i++)
+                                               dprintf(" %lu", 
irq->interrupts[i]);
+                                       dprintf("\n");
+                               }
+#endif
+                               break;
+                       }
                }
+
+               if (descriptor->irq != 0)
+                       break;
+
                resource = (acpi_resource*)((uint8*)resource + 
resource->length);
        }
+
        free(buffer.pointer);
-       return B_ERROR;
+       return descriptor->irq != 0 ? B_OK : B_ERROR;
 }
 
 
@@ -182,7 +260,7 @@
 read_current_irq(acpi_module_info* acpi, acpi_handle device,
        irq_descriptor* descriptor)
 {
-       return read_irq_descriptor(acpi, device, "_CRS", descriptor);
+       return read_irq_descriptor(acpi, device, true, descriptor);
 }
 
 
@@ -190,7 +268,7 @@
 read_possible_irq(acpi_module_info* acpi, acpi_handle device,
        irq_descriptor* descriptor)
 {
-       return read_irq_descriptor(acpi, device, "_PRS", descriptor);
+       return read_irq_descriptor(acpi, device, false, descriptor);
 }
 
 

Modified: haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h
===================================================================
--- haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h  2011-05-05 
19:41:52 UTC (rev 41327)
+++ haiku/trunk/src/system/kernel/arch/x86/irq_routing_table.h  2011-05-05 
19:59:04 UTC (rev 41328)
@@ -31,47 +31,63 @@
 struct irq_descriptor {
        irq_descriptor();
        // bit 0 is interrupt 0, bit 2 is interrupt 2, and so on
-       int16                   irq;
+       uint8                   irq;
        bool                    shareable;
        // B_LOW_ACTIVE_POLARITY or B_HIGH_ACTIVE_POLARITY
-       int8                    polarity;
+       uint8                   polarity;
        // B_LEVEL_TRIGGERED or B_EDGE_TRIGGERED
-       int8                    interrupt_mode;
+       uint8                   interrupt_mode;
 };
 
 
-// Similar to bus_managers/acpi/include/acrestyp.h definition
-typedef struct acpi_prt {
-       uint32                  length;
-       uint32                  pin;
-       uint64                  address;        // here for 64-bit alignment
-       uint32                  sourceIndex;
-       char                    source[4];      // pad to 64 bits so sizeof()
-                                               // works in all cases
-} acpi_pci_routing_table;
+// TODO: Hack until we expose ACPI structs better; these are duplicates of
+// the types in acrestype.h
+struct acpi_pci_routing_table {
+       uint32  length;
+       uint32  pin;
+       uint64  address;
+       uint32  source_index;
+       char    source[4];
+};
 
-//TODO: Hack until we expose ACPI structs better, currently hardcoded to
-// ACPI_RESOURCE_IRQ
 struct acpi_resource {
-    uint32          type;
-    uint32                     length;
+       uint32  type;
+       uint32  length;
+};
 
-    uint8                      descriptorLength;
-    uint8                      triggering;
-    uint8                      polarity;
-    uint8                      sharable;
-    uint8                      interruptCount;
-    uint8                      interrupts[];
+struct acpi_resource_source {
+       uint8   index;
+       uint16  string_length;
+       char*   string_pointer;
 };
 
+struct acpi_resource_irq {
+       acpi_resource header;
+       uint8   descriptor_ength;
+       uint8   triggering;
+       uint8   polarity;
+       uint8   sharable;
+       uint8   interrupt_count;
+       uint8   interrupts[];
+};
 
+struct acpi_resource_extended_irq {
+       acpi_resource header;
+       uint8   producer_consumer;
+       uint8   triggering;
+       uint8   polarity;
+       uint8   sharable;
+       uint8   interrupt_count;
+       acpi_resource_source source;
+       uint32  interrupts[];
+};
+
+
 void print_irq_descriptor(irq_descriptor* descriptor);
 void print_irq_routing_table(IRQRoutingTable* table);
 
 
 status_t read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable* 
table);
-status_t read_irq_descriptor(acpi_module_info* acpi, acpi_handle device,
-                       const char* method, irq_descriptor* descriptor);
 
 status_t read_current_irq(acpi_module_info* acpi, acpi_handle device,
                        irq_descriptor* descriptor);


Other related posts: