diff --git a/src/system/kernel/arch/x86/Jamfile b/src/system/kernel/arch/x86/Jamfile index 9d6f08664a..e58d5f38c9 100644 --- a/src/system/kernel/arch/x86/Jamfile +++ b/src/system/kernel/arch/x86/Jamfile @@ -32,6 +32,7 @@ KernelMergeObject kernel_arch_x86.o : apm.cpp bios.cpp cpuid.S + irq_routing_table.cpp syscall.S vm86.cpp x86_physical_page_mapper.cpp diff --git a/src/system/kernel/arch/x86/arch_int.cpp b/src/system/kernel/arch/x86/arch_int.cpp index 0059adc0b9..6a4282daef 100644 --- a/src/system/kernel/arch/x86/arch_int.cpp +++ b/src/system/kernel/arch/x86/arch_int.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2010, Clemens Zeidler, haiku@clemens-zeidler.de. * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. @@ -29,8 +30,10 @@ #include #include "interrupts.h" +#include "irq_routing_table.h" #include +#include #include #include #include @@ -578,11 +581,25 @@ ioapic_init(kernel_args *args) // TODO: remove when the PCI IRQ routing through ACPI is available below return; - acpi_module_info *acpi; - if (get_module(B_ACPI_MODULE_NAME, (module_info **)&acpi) != B_OK) { + // load acpi modul + status_t status; + acpi_module_info* acpiModule; + status = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule); + if (status != B_OK) { dprintf("acpi module not available, not configuring ioapic\n"); return; } + BPrivate::CObjectDeleter + acpiModulePutter(B_ACPI_MODULE_NAME, put_module); + // load pci modul + pci_module_info* pciModule; + status = get_module(B_PCI_MODULE_NAME, (module_info**)&pciModule); + if (status != B_OK) { + dprintf("could not load pci module, not configuring ioapic\n"); + return; + } + CObjectDeleter pciModulePutter(B_PCI_MODULE_NAME, + put_module); // map in the ioapic sIOAPIC = (ioapic *)args->arch_args.ioapic; @@ -645,8 +662,23 @@ ioapic_init(kernel_args *args) // TODO: here ACPI needs to be used to properly set up the PCI IRQ // routing. + IRQRoutingTable table; + status = read_irq_routing_table(pciModule, acpiModule, &table); + if (status != B_OK) + return; + + // configure apic interrupts assume 1:1 mapping + for (int i = 0; i < table.Count(); i++) { + irq_routing_entry& entry = table.ElementAt(i); + irq_discriptor irqDiscriptor; + read_current_irq(acpiModule, entry.source, &irqDiscriptor); + uint32 config = 0; + config |= irqDiscriptor.polarity; + config |= irqDiscriptor.interrupt_mode; + ioapic_configure_io_interrupt(irqDiscriptor.irq, config); + } + // prefer the ioapic over the normal pic - put_module(B_ACPI_MODULE_NAME); dprintf("using ioapic for interrupt routing\n"); sCurrentPIC = &ioapicController; gUsingIOAPIC = true; diff --git a/src/system/kernel/arch/x86/irq_routing_table.cpp b/src/system/kernel/arch/x86/irq_routing_table.cpp new file mode 100644 index 0000000000..a4375dc93e --- /dev/null +++ b/src/system/kernel/arch/x86/irq_routing_table.cpp @@ -0,0 +1,283 @@ +/* + * Copyright 2009, Clemens Zeidler haiku@clemens-zeidler.de. All rights reserved. + * + * Distributed under the terms of the MIT License. + */ + + +#include "irq_routing_table.h" + + +#include + + +//#define TRACE_PRT +#ifdef TRACE_PRT +# define TRACE(x...) dprintf("IRQRoutingTable: "x) +#else +# define TRACE(x...) +#endif + + +const int kIRQDescriptor = 0x04; + + +const char* kACPIPciRootName = "PNP0A03"; + + +irq_discriptor::irq_discriptor() + : + irq(0), + shareable(false), + polarity(B_HIGH_ACTIVE_POLARITY), + interrupt_mode(B_EDGE_TRIGGERED) +{ + +} + + +void +print_irq_discriptor(irq_discriptor* discriptor) +{ + for (int i = 0; i < 16; i++) { + if (discriptor->irq >> i & 0x01) + dprintf("interrupt: %i\n", i); + } + + const char* activeHighString = "active high"; + const char* activeLowString = " active low"; + const char* levelTriggeredString = "level triggered"; + const char* edgeTriggeredString = " edge triggered"; + + dprintf("shareable: %i, polarity: %s, interrupt_mode: %s\n", + discriptor->shareable, discriptor->polarity == B_HIGH_ACTIVE_POLARITY + ? activeHighString : activeLowString, + discriptor->interrupt_mode == B_LEVEL_TRIGGERED ? levelTriggeredString + : edgeTriggeredString); +} + + +void +print_irq_routing_table(IRQRoutingTable* table) +{ + dprintf("Print table %i entries\n", (int)table->Count()); + for (int i = 0; i < table->Count(); i++) { + irq_routing_entry& entry = table->ElementAt(i); + dprintf("address: %x\n", entry.device_address); + dprintf("pin: %i\n", entry.pin); + dprintf("source: %x\n", int(entry.source)); + dprintf("source index: %i\n", entry.source_index); + + dprintf("pci_bus: %i\n", entry.pci_bus); + dprintf("pci_device: %i\n", entry.pci_device); + } +} + + +static status_t +find_pci_device(pci_module_info *pci, irq_routing_entry* entry) +{ + pci_info info; + int pciN = 0; + while ((*pci->get_nth_pci_info)(pciN, &info) == B_OK) { + pciN ++; + + int16 deviceAddress = entry->device_address >> 16 & 0xFFFF; + if (info.device == deviceAddress + && info.u.h0.interrupt_pin == entry->pin + 1) { + entry->pci_bus = info.bus; + entry->pci_device = info.device; + return B_OK; + } + } + + return B_ERROR; +} + + +static status_t +read_device_irq_routing_table(pci_module_info *pci, acpi_module_info* acpi, + acpi_handle device, IRQRoutingTable* table) +{ + acpi_data buffer; + buffer.pointer = 0; + buffer.length = ACPI_ALLOCATE_BUFFER; + status_t status = acpi->get_irq_routing_table(device, &buffer); + if (status != B_OK) + return status; + + acpi_object_type* object = (acpi_object_type*)buffer.pointer; + if (object->object_type != ACPI_TYPE_PACKAGE) { + free(buffer.pointer); + return B_ERROR; + } + + irq_routing_entry irqEntry; + acpi_pci_routing_table* acpiTable + = (acpi_pci_routing_table*)buffer.pointer; + while (acpiTable->length) { + irqEntry.device_address = acpiTable->address; + irqEntry.pin = acpiTable->pin; + irqEntry.source = acpiTable->source; + irqEntry.source_index = acpiTable->sourceIndex; + + // connect to pci device + if (find_pci_device(pci, &irqEntry) != B_OK) { + TRACE("no pci dev found, device %x, pin %i\n", + irqEntry.device_address, irqEntry.pin); + acpiTable = (acpi_pci_routing_table*)((uint8*)acpiTable + + acpiTable->length); + continue; + } + + table->PushBack(irqEntry); + acpiTable = (acpi_pci_routing_table*)((uint8*)acpiTable + + acpiTable->length); + } + + free(buffer.pointer); + return B_OK; +} + + +status_t +read_irq_routing_table(pci_module_info *pci, acpi_module_info* acpi, + IRQRoutingTable* table) +{ + char rootPciName[255]; + acpi_handle rootPciHandle; + rootPciName[0] = 0; + status_t status = acpi->get_device(kACPIPciRootName, 0, rootPciName, 255); + if (status != B_OK) + return status; + + status = acpi->get_handle(NULL, rootPciName, &rootPciHandle); + if (status != B_OK) + return status; + TRACE("Read root pci bus irq rooting table\n"); + status = read_device_irq_routing_table(pci, acpi, rootPciHandle, table); + if (status != B_OK) + return status; + + TRACE("find p2p \n"); + + char result[255]; + result[0] = 0; + void *counter = NULL; + while (acpi->get_next_entry(ACPI_TYPE_DEVICE, rootPciName, result, 255, + &counter) == B_OK) { + acpi_handle brigde; + status = acpi->get_handle(NULL, result, &brigde); + if (status != B_OK) + continue; + + status = read_device_irq_routing_table(pci, acpi, brigde, table); + if (status == B_OK) + TRACE("p2p found %s\n", result); + } + + return status; +} + + +status_t +read_irq_discriptor(acpi_module_info* acpi, acpi_handle device, + const char* method, irq_discriptor* discriptor) +{ + acpi_data buffer; + buffer.pointer = NULL; + buffer.length = ACPI_ALLOCATE_BUFFER; + status_t status = acpi->evaluate_method(device, method, NULL, + &buffer); + if (status != B_OK) { + free(buffer.pointer); + return status; + } + + acpi_object_type* resourceBuffer = (acpi_object_type*)buffer.pointer; + if (resourceBuffer[0].object_type != ACPI_TYPE_BUFFER) + return B_ERROR; + + int8* resourcePointer = (int8*)resourceBuffer[0].data.buffer.buffer; + int8 integer = resourcePointer[0]; + if (integer >> 3 != kIRQDescriptor) { + TRACE("resource is not a irq discriptor\n"); + return B_ERROR; + } + + int8 size = resourcePointer[0] & 0x07; + if (size < 2) { + TRACE("invalid resource size\n"); + return B_ERROR; + } + + discriptor->irq = resourcePointer[2]; + discriptor->irq = discriptor->irq << 8; + discriptor->irq |= resourcePointer[1]; + + // if size equal 2 we are don't else read the third entry + if (size == 2) + return B_OK; + + int irqInfo = resourcePointer[3]; + int bit; + + bit = irqInfo & 0x01; + discriptor->interrupt_mode = (bit == 0) ? B_LEVEL_TRIGGERED + : B_EDGE_TRIGGERED; + bit = irqInfo >> 3 & 0x01; + discriptor->polarity = (bit == 0) ? B_HIGH_ACTIVE_POLARITY + : B_LOW_ACTIVE_POLARITY; + discriptor->shareable = irqInfo >> 4 & 0x01; + + return B_OK; +} + + +status_t +read_current_irq(acpi_module_info* acpi, acpi_handle device, + irq_discriptor* discriptor) +{ + return read_irq_discriptor(acpi, device, "_CRS", discriptor); +} + + +status_t +read_possible_irq(acpi_module_info* acpi, acpi_handle device, + irq_discriptor* discriptor) +{ + return read_irq_discriptor(acpi, device, "_PRS", discriptor); +} + + +status_t +set_acpi_irq(acpi_module_info* acpi, acpi_handle device, + irq_discriptor* discriptor) +{ + acpi_object_type outBuffer; + outBuffer.object_type = ACPI_TYPE_BUFFER; + + int8 data[4]; + data[0] = 0x23; + data[1] = discriptor->irq & 0xFF; + data[2] = discriptor->irq >> 8; + + data[3] = 0; + int8 bit; + bit = (discriptor->interrupt_mode == B_HIGH_ACTIVE_POLARITY) ? 0 : 1; + data[3] |= bit; + bit = (discriptor->polarity == B_LEVEL_TRIGGERED) ? 0 : 1; + data[3] |= bit << 3; + bit = discriptor->shareable ? 1 : 0; + data[3] |= bit << 4; + + outBuffer.data.buffer.length = sizeof(data); + outBuffer.data.buffer.buffer = data; + + acpi_objects parameter; + parameter.count = 1; + parameter.pointer = &outBuffer; + status_t status = acpi->evaluate_method(device, "_SRS", ¶meter, NULL); + + return status; +} diff --git a/src/system/kernel/arch/x86/irq_routing_table.h b/src/system/kernel/arch/x86/irq_routing_table.h new file mode 100644 index 0000000000..dbc5cb2c40 --- /dev/null +++ b/src/system/kernel/arch/x86/irq_routing_table.h @@ -0,0 +1,59 @@ +#ifndef IRQ_ROUTING_TABLE_H +#define IRQ_ROUTING_TABLE_H + + +#include +#include + + +#include "util/Vector.h" + + +struct irq_routing_entry +{ + int device_address; + int8 pin; + + acpi_handle source; + int source_index; + + // pci busmanager connection + uchar pci_bus; + uchar pci_device; +}; + + +typedef Vector IRQRoutingTable; + + +struct irq_discriptor +{ + irq_discriptor(); + // bit 0 is interrupt 0, bit 2 is interrupt 2, and so on + int16 irq; + bool shareable; + // B_LOW_ACTIVE_POLARITY or B_HIGH_ACTIVE_POLARITY + int8 polarity; + // B_LEVEL_TRIGGERED or B_EDGE_TRIGGERED + int8 interrupt_mode; +}; + + +void print_irq_discriptor(irq_discriptor* discriptor); +void print_irq_routing_table(IRQRoutingTable* table); + + +status_t read_irq_routing_table(pci_module_info *pci, acpi_module_info* acpi, + IRQRoutingTable* table); +status_t read_irq_discriptor(acpi_module_info* acpi, acpi_handle device, + const char* method, irq_discriptor* discriptor); + +status_t read_current_irq(acpi_module_info* acpi, acpi_handle device, + irq_discriptor* discriptor); +status_t read_possible_irq(acpi_module_info* acpi, acpi_handle device, + irq_discriptor* discriptor); + +status_t set_acpi_irq(acpi_module_info* acpi, acpi_handle device, + irq_discriptor* discriptor); + +#endif