Rescue acpi irq stuff from my defect laptop. Code is disabled and should't to any harm.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36059 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Clemens Zeidler
2010-04-07 12:50:55 +00:00
parent 7f0bff63d0
commit cb58e3f784
4 changed files with 378 additions and 3 deletions
+1
View File
@@ -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
+35 -3
View File
@@ -1,4 +1,5 @@
/*
* Copyright 2010, Clemens Zeidler, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected].
* Copyright 2002-2009, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
@@ -29,8 +30,10 @@
#include <arch/x86/vm86.h>
#include "interrupts.h"
#include "irq_routing_table.h"
#include <ACPI.h>
#include <AutoDeleter.h>
#include <safemode.h>
#include <string.h>
#include <stdio.h>
@@ -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<const char, status_t>
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<const char, status_t> 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;
@@ -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 <int.h>
//#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", &parameter, NULL);
return status;
}
@@ -0,0 +1,59 @@
#ifndef IRQ_ROUTING_TABLE_H
#define IRQ_ROUTING_TABLE_H
#include <ACPI.h>
#include <PCI.h>
#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<irq_routing_entry> 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