* Implement the PCI address retrieval on the kernel side and remove the need
for the introduced get_pci_info() method in ACPI as it doesn't work reliably. The new version should be more robust and efficient as it only resolves the root bridge values once. * Don't try to read and use the secondary bus register for the root bridge as it isn't actually a normal bridge. We get the root bridge bus by using the Base Bus Number (_BBN) method. * Rewrite the logic to recurse down to all busses. * Minor debug output changes to make the info more readable. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41371 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
56b5ad0781
commit
9b50b2889a
|
@ -70,7 +70,9 @@ print_irq_routing_entry(const irq_routing_entry& entry)
|
|||
else
|
||||
dprintf(" source %p %lu;", entry.source, entry.source_index);
|
||||
|
||||
dprintf(" pci %u:%u\n", entry.pci_bus, entry.pci_device);
|
||||
dprintf(" pci %u:%u pin %u; gsi %u; config 0x%02x\n", entry.pci_bus,
|
||||
entry.pci_device, entry.pin + 1, entry.irq,
|
||||
entry.polarity | entry.trigger_mode);
|
||||
}
|
||||
|
||||
|
||||
|
@ -133,39 +135,73 @@ update_pci_info_for_entry(pci_module_info* pci, irq_routing_entry& entry)
|
|||
|
||||
|
||||
static status_t
|
||||
read_bridge_irq_routing_table(acpi_module_info* acpi, pci_module_info* pci,
|
||||
acpi_handle possibleBridge, acpi_handle rootPciHandle,
|
||||
IRQRoutingTable* table)
|
||||
evaluate_integer(acpi_module_info* acpi, acpi_handle handle,
|
||||
const char* method, uint64& value)
|
||||
{
|
||||
acpi_object_type result;
|
||||
acpi_data resultBuffer;
|
||||
resultBuffer.pointer = &result;
|
||||
resultBuffer.length = sizeof(result);
|
||||
|
||||
status_t status = acpi->evaluate_method(handle, method, NULL,
|
||||
&resultBuffer);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if (result.object_type != ACPI_TYPE_INTEGER)
|
||||
return B_BAD_TYPE;
|
||||
|
||||
value = result.data.integer;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
read_irq_routing_table_recursive(acpi_module_info* acpi, pci_module_info* pci,
|
||||
acpi_handle device, const pci_address& parentAddress,
|
||||
IRQRoutingTable* table, bool rootBridge)
|
||||
{
|
||||
acpi_data buffer;
|
||||
buffer.pointer = NULL;
|
||||
buffer.length = ACPI_ALLOCATE_BUFFER;
|
||||
status_t status = acpi->get_irq_routing_table(possibleBridge, &buffer);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// It appears to be a bridge device, resolve the PCI infos. As all routing
|
||||
// table entries will be relative to this bus we can then just address the
|
||||
// devices using the device number extracted from the address field.
|
||||
acpi_pci_info pciInfo;
|
||||
status = acpi->get_pci_info(rootPciHandle, possibleBridge, &pciInfo);
|
||||
status_t status = acpi->get_irq_routing_table(device, &buffer);
|
||||
if (status != B_OK) {
|
||||
dprintf("failed to resolve pci info of bridge device, can't configure"
|
||||
" irq routing of devices below\n");
|
||||
return B_ERROR;
|
||||
// simply not a bridge
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the secondary bus number (the "downstream" bus number for the
|
||||
// attached devices) in the bridge configuration.
|
||||
uint8 secondaryBus = pci->read_pci_config(pciInfo.bus, pciInfo.device,
|
||||
pciInfo.function, PCI_secondary_bus, 1);
|
||||
if (secondaryBus == 255)
|
||||
return B_ERROR;
|
||||
TRACE("found irq routing table\n");
|
||||
|
||||
if (secondaryBus == pciInfo.bus && possibleBridge != rootPciHandle) {
|
||||
dprintf("invalid secondary bus %u on primary bus %u, can't configure"
|
||||
" irq routing of devices below\n", secondaryBus, pciInfo.bus);
|
||||
return B_ERROR;
|
||||
uint64 value;
|
||||
pci_address pciAddress = parentAddress;
|
||||
if (evaluate_integer(acpi, device, "_ADR", value) == B_OK) {
|
||||
pciAddress.device = (uint8)(value >> 16);
|
||||
pciAddress.function = (uint8)value;
|
||||
} else {
|
||||
pciAddress.device = 0;
|
||||
pciAddress.function = 0;
|
||||
}
|
||||
|
||||
if (!rootBridge) {
|
||||
// Find the secondary bus number (the "downstream" bus number for the
|
||||
// attached devices) in the bridge configuration.
|
||||
uint8 secondaryBus = pci->read_pci_config(pciAddress.bus,
|
||||
pciAddress.device, pciAddress.function, PCI_secondary_bus, 1);
|
||||
if (secondaryBus == 255) {
|
||||
// The bus below this bridge is inactive, nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
// The secondary bus cannot be the same as the current one.
|
||||
if (secondaryBus == parentAddress.bus) {
|
||||
dprintf("invalid secondary bus %u on primary bus %u,"
|
||||
" can't configure irq routing of devices below\n",
|
||||
secondaryBus, parentAddress.bus);
|
||||
return;
|
||||
}
|
||||
|
||||
// Everything below is now on the secondary bus.
|
||||
pciAddress.bus = secondaryBus;
|
||||
}
|
||||
|
||||
irq_routing_entry irqEntry;
|
||||
|
@ -187,7 +223,7 @@ read_bridge_irq_routing_table(acpi_module_info* acpi, pci_module_info* pci,
|
|||
irqEntry.pin = acpiTable->pin;
|
||||
irqEntry.source = noSource ? NULL : source;
|
||||
irqEntry.source_index = acpiTable->source_index;
|
||||
irqEntry.pci_bus = secondaryBus;
|
||||
irqEntry.pci_bus = pciAddress.bus;
|
||||
irqEntry.pci_device = (uint8)(acpiTable->address >> 16);
|
||||
|
||||
// resolve any link device so we get a straight GSI in all cases
|
||||
|
@ -221,9 +257,8 @@ read_bridge_irq_routing_table(acpi_module_info* acpi, pci_module_info* pci,
|
|||
" can't update interrupt_line info:\n");
|
||||
print_irq_routing_entry(irqEntry);
|
||||
#endif
|
||||
}
|
||||
|
||||
table->PushBack(irqEntry);
|
||||
} else
|
||||
table->PushBack(irqEntry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,7 +267,34 @@ read_bridge_irq_routing_table(acpi_module_info* acpi, pci_module_info* pci,
|
|||
}
|
||||
|
||||
free(buffer.pointer);
|
||||
return B_OK;
|
||||
|
||||
// recurse down to the child devices
|
||||
acpi_data pathBuffer;
|
||||
pathBuffer.pointer = NULL;
|
||||
pathBuffer.length = ACPI_ALLOCATE_BUFFER;
|
||||
if (acpi->ns_handle_to_pathname(device, &pathBuffer) != B_OK) {
|
||||
dprintf("failed to resolve handle to path\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char childName[255];
|
||||
void* counter = NULL;
|
||||
while (acpi->get_next_entry(ACPI_TYPE_DEVICE, (char*)pathBuffer.pointer,
|
||||
childName, sizeof(childName), &counter) == B_OK) {
|
||||
|
||||
acpi_handle childHandle;
|
||||
status = acpi->get_handle(NULL, childName, &childHandle);
|
||||
if (status != B_OK) {
|
||||
dprintf("failed to get handle to child \"%s\"\n", childName);
|
||||
continue;
|
||||
}
|
||||
|
||||
TRACE("recursing down to child \"%s\"\n", childName);
|
||||
read_irq_routing_table_recursive(acpi, pci, childHandle, pciAddress,
|
||||
table, false);
|
||||
}
|
||||
|
||||
free(pathBuffer.pointer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -250,6 +312,17 @@ read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable* table)
|
|||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// We reset the structure to 0 here. Any failed evaluation means default
|
||||
// values, so we don't have to do anything in the error case.
|
||||
pci_address rootPciAddress;
|
||||
memset(&rootPciAddress, 0, sizeof(pci_address));
|
||||
|
||||
uint64 value;
|
||||
if (evaluate_integer(acpi, rootPciHandle, "_SEG", value) == B_OK)
|
||||
rootPciAddress.segment = (uint8)value;
|
||||
if (evaluate_integer(acpi, rootPciHandle, "_BBN", value) == B_OK)
|
||||
rootPciAddress.bus = (uint8)value;
|
||||
|
||||
pci_module_info* pci;
|
||||
status = get_module(B_PCI_MODULE_NAME, (module_info**)&pci);
|
||||
if (status != B_OK) {
|
||||
|
@ -259,32 +332,8 @@ read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable* table)
|
|||
return status;
|
||||
}
|
||||
|
||||
TRACE("read root pci bus irq routing table\n");
|
||||
status = read_bridge_irq_routing_table(acpi, pci, rootPciHandle,
|
||||
rootPciHandle, table);
|
||||
if (status != B_OK) {
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
return status;
|
||||
}
|
||||
|
||||
TRACE("find routing tables \n");
|
||||
|
||||
char name[255];
|
||||
name[0] = 0;
|
||||
void* counter = NULL;
|
||||
while (acpi->get_next_entry(ACPI_TYPE_DEVICE, rootPciName, name,
|
||||
sizeof(name), &counter) == B_OK) {
|
||||
acpi_handle possibleBridge;
|
||||
status = acpi->get_handle(NULL, name, &possibleBridge);
|
||||
if (status != B_OK)
|
||||
continue;
|
||||
|
||||
status = read_bridge_irq_routing_table(acpi, pci, possibleBridge,
|
||||
rootPciHandle, table);
|
||||
if (status == B_OK)
|
||||
TRACE("routing table found %s\n", name);
|
||||
// if it failed it simply was no bridge at all
|
||||
}
|
||||
read_irq_routing_table_recursive(acpi, pci, rootPciHandle, rootPciAddress,
|
||||
table, true);
|
||||
|
||||
put_module(B_PCI_MODULE_NAME);
|
||||
return table->Count() > 0 ? B_OK : B_ERROR;
|
||||
|
|
|
@ -46,6 +46,14 @@ struct irq_descriptor {
|
|||
};
|
||||
|
||||
|
||||
struct pci_address {
|
||||
uint8 segment;
|
||||
uint8 bus;
|
||||
uint8 device;
|
||||
uint8 function;
|
||||
};
|
||||
|
||||
|
||||
// TODO: Hack until we expose ACPI structs better; these are duplicates of
|
||||
// the types in acrestype.h
|
||||
struct acpi_pci_routing_table {
|
||||
|
|
Loading…
Reference in New Issue