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);