diff --git a/src/system/kernel/arch/x86/arch_int.cpp b/src/system/kernel/arch/x86/arch_int.cpp index 8e95767ffd..a941eec3a2 100644 --- a/src/system/kernel/arch/x86/arch_int.cpp +++ b/src/system/kernel/arch/x86/arch_int.cpp @@ -415,6 +415,15 @@ pic_init(void) } +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 @@ ioapic_init(kernel_args* args) = ((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 @@ ioapic_init(kernel_args* args) 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; diff --git a/src/system/kernel/arch/x86/irq_routing_table.cpp b/src/system/kernel/arch/x86/irq_routing_table.cpp index 2a2c680eed..f145d4f1a9 100644 --- a/src/system/kernel/arch/x86/irq_routing_table.cpp +++ b/src/system/kernel/arch/x86/irq_routing_table.cpp @@ -49,7 +49,7 @@ print_irq_descriptor(irq_descriptor* descriptor) 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 @@ read_device_irq_routing_table(acpi_module_info* acpi, acpi_handle device, 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 @@ read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable* table) } -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 @@ status_t 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 @@ status_t 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); } diff --git a/src/system/kernel/arch/x86/irq_routing_table.h b/src/system/kernel/arch/x86/irq_routing_table.h index 9e6770cba5..efe4a820f0 100644 --- a/src/system/kernel/arch/x86/irq_routing_table.h +++ b/src/system/kernel/arch/x86/irq_routing_table.h @@ -31,37 +31,55 @@ typedef Vector IRQRoutingTable; 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[]; }; @@ -70,8 +88,6 @@ 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);