mirror of https://gitlab.com/nakst/essence
use ACPI to get PCI interrupt information
This commit is contained in:
parent
02e039b3f5
commit
75a97ae783
111
drivers/acpi.cpp
111
drivers/acpi.cpp
|
@ -653,50 +653,73 @@ UINT32 ACPIPowerButtonPressed(void *) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ACPIFoundDevice(const char *name, ACPI_HANDLE object) {
|
int32_t ACPIFindIRQ(ACPI_HANDLE object) {
|
||||||
if (0 == EsCRTstrcmp(name, "PCI0")) {
|
ACPI_BUFFER buffer = {};
|
||||||
ACPI_BUFFER buffer = {};
|
ACPI_STATUS status = AcpiGetCurrentResources(object, &buffer);
|
||||||
ACPI_STATUS status = AcpiGetIrqRoutingTable(object, &buffer);
|
if (status != AE_BUFFER_OVERFLOW) return -1;
|
||||||
if (status != AE_BUFFER_OVERFLOW) return;
|
buffer.Pointer = EsHeapAllocate(buffer.Length, false, K_FIXED);
|
||||||
buffer.Pointer = EsHeapAllocate(buffer.Length, false, K_FIXED);
|
EsDefer(EsHeapFree(buffer.Pointer, buffer.Length, K_FIXED));
|
||||||
EsDefer(EsHeapFree(buffer.Pointer, buffer.Length, K_FIXED));
|
if (!buffer.Pointer) return -1;
|
||||||
if (!buffer.Pointer) return;
|
status = AcpiGetCurrentResources(object, &buffer);
|
||||||
status = AcpiGetIrqRoutingTable(object, &buffer);
|
if (status != AE_OK) return -1;
|
||||||
if (status != AE_OK) return;
|
ACPI_RESOURCE *resource = (ACPI_RESOURCE *) buffer.Pointer;
|
||||||
ACPI_PCI_ROUTING_TABLE *table = (ACPI_PCI_ROUTING_TABLE *) buffer.Pointer;
|
|
||||||
|
|
||||||
while (table->Length) {
|
while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) {
|
||||||
KernelLog(LOG_INFO, "ACPI", "PRT entry", "length: %d; pin: %d; address: %x; source index: %d; source: %z\n",
|
if (resource->Type == ACPI_RESOURCE_TYPE_IRQ) {
|
||||||
table->Length, table->Pin, table->Address, table->SourceIndex, table->Source);
|
if (resource->Data.Irq.InterruptCount) {
|
||||||
table = (ACPI_PCI_ROUTING_TABLE *) ((uint8_t *) table + table->Length);
|
return resource->Data.Irq.Interrupts[0];
|
||||||
}
|
}
|
||||||
} else if (0 == EsCRTmemcmp(name, "LNK", 3)) {
|
} else if (resource->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
|
||||||
ACPI_BUFFER buffer = {};
|
if (resource->Data.ExtendedIrq.InterruptCount) {
|
||||||
ACPI_STATUS status = AcpiGetCurrentResources(object, &buffer);
|
return resource->Data.ExtendedIrq.Interrupts[0];
|
||||||
if (status != AE_BUFFER_OVERFLOW) return;
|
|
||||||
buffer.Pointer = EsHeapAllocate(buffer.Length, false, K_FIXED);
|
|
||||||
EsDefer(EsHeapFree(buffer.Pointer, buffer.Length, K_FIXED));
|
|
||||||
if (!buffer.Pointer) return;
|
|
||||||
status = AcpiGetCurrentResources(object, &buffer);
|
|
||||||
if (status != AE_OK) return;
|
|
||||||
ACPI_RESOURCE *resource = (ACPI_RESOURCE *) buffer.Pointer;
|
|
||||||
|
|
||||||
while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) {
|
|
||||||
if (resource->Type == ACPI_RESOURCE_TYPE_IRQ) {
|
|
||||||
KernelLog(LOG_INFO, "ACPI", "IRQ resource", "count: %d; first: %d\n",
|
|
||||||
resource->Data.Irq.InterruptCount, resource->Data.Irq.Interrupts[0]);
|
|
||||||
} else if (resource->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
|
|
||||||
KernelLog(LOG_INFO, "ACPI", "IRQ resource", "count: %d; first: %d; (extended)\n",
|
|
||||||
resource->Data.ExtendedIrq.InterruptCount, resource->Data.ExtendedIrq.Interrupts[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource = (ACPI_RESOURCE *) ((uint8_t *) resource + resource->Length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO.
|
resource = (ACPI_RESOURCE *) ((uint8_t *) resource + resource->Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ACPIEnumeratePRTEntries(ACPI_HANDLE pciBus) {
|
||||||
|
// TODO Other PCI buses.
|
||||||
|
// TODO Is this always bus 0?
|
||||||
|
|
||||||
|
ACPI_BUFFER buffer = {};
|
||||||
|
ACPI_STATUS status = AcpiGetIrqRoutingTable(pciBus, &buffer);
|
||||||
|
if (status != AE_BUFFER_OVERFLOW) return;
|
||||||
|
buffer.Pointer = EsHeapAllocate(buffer.Length, false, K_FIXED);
|
||||||
|
EsDefer(EsHeapFree(buffer.Pointer, buffer.Length, K_FIXED));
|
||||||
|
if (!buffer.Pointer) return;
|
||||||
|
status = AcpiGetIrqRoutingTable(pciBus, &buffer);
|
||||||
|
if (status != AE_OK) return;
|
||||||
|
ACPI_PCI_ROUTING_TABLE *table = (ACPI_PCI_ROUTING_TABLE *) buffer.Pointer;
|
||||||
|
|
||||||
|
while (table->Length) {
|
||||||
|
ACPI_HANDLE source;
|
||||||
|
|
||||||
|
if (AE_OK == AcpiGetHandle(pciBus, table->Source, &source)) {
|
||||||
|
int32_t irq = ACPIFindIRQ(source);
|
||||||
|
|
||||||
|
if (irq != -1) {
|
||||||
|
KernelLog(LOG_INFO, "ACPI", "PRT entry", "Pin: %d; PCI slot: %X; IRQ: %d\n",
|
||||||
|
table->Pin, (table->Address >> 16) & 0xFF, irq);
|
||||||
|
|
||||||
|
if (irq != 9 && irq != 10 && irq != 11) {
|
||||||
|
KernelLog(LOG_ERROR, "ACPI", "unexpected IRQ", "IRQ %d was unexpected; expected values are 9, 10 or 11.\n", irq);
|
||||||
|
} else if ((table->Address >> 16) > 0xFF) {
|
||||||
|
KernelLog(LOG_ERROR, "ACPI", "unexpected address", "Address %x was larger than expected.\n", table->Address);
|
||||||
|
} else if (table->Pin > 3) {
|
||||||
|
KernelLog(LOG_ERROR, "ACPI", "unexpected pin", "Pin %d was larger than expected.\n", table->Pin);
|
||||||
|
} else {
|
||||||
|
pciIRQLines[table->Address >> 16][table->Pin] = irq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table = (ACPI_PCI_ROUTING_TABLE *) ((uint8_t *) table + table->Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ACPIInitialise2() {
|
void ACPIInitialise2() {
|
||||||
|
@ -724,15 +747,21 @@ void ACPIInitialise2() {
|
||||||
EsMemoryCopy(name, &information->Name, 4);
|
EsMemoryCopy(name, &information->Name, 4);
|
||||||
name[4] = 0;
|
name[4] = 0;
|
||||||
|
|
||||||
KernelLog(LOG_INFO, "ACPI", "device object", "Found device object '%z' with HID '%z' and UID '%z'.\n",
|
KernelLog(LOG_INFO, "ACPI", "device object", "Found device object '%z' with HID '%z', UID '%z' and address %x.\n",
|
||||||
name, (information->Valid & ACPI_VALID_HID) ? information->HardwareId.String : "??",
|
name, (information->Valid & ACPI_VALID_HID) ? information->HardwareId.String : "??",
|
||||||
(information->Valid & ACPI_VALID_UID) ? information->UniqueId.String : "??");
|
(information->Valid & ACPI_VALID_UID) ? information->UniqueId.String : "??",
|
||||||
|
(information->Valid & ACPI_VALID_ADR) ? information->Address : 0);
|
||||||
ACPIFoundDevice(name, object);
|
|
||||||
|
|
||||||
ACPI_FREE(information);
|
ACPI_FREE(information);
|
||||||
return AE_OK;
|
return AE_OK;
|
||||||
}, nullptr, &result);
|
}, nullptr, &result);
|
||||||
|
|
||||||
|
ACPI_HANDLE pciBus;
|
||||||
|
char pciBusPath[] = "\\_SB_.PCI0";
|
||||||
|
|
||||||
|
if (AE_OK == AcpiGetHandle(nullptr, pciBusPath, &pciBus)) {
|
||||||
|
ACPIEnumeratePRTEntries(pciBus);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
acpi.StartupApplicationProcessors();
|
acpi.StartupApplicationProcessors();
|
||||||
|
|
|
@ -240,8 +240,21 @@ bool KPCIDevice::EnableSingleInterrupt(KIRQHandler irqHandler, void *context, co
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (interruptPin == 0) {
|
||||||
|
// The device does not support interrupts.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interruptPin > 4) {
|
||||||
|
KernelLog(LOG_ERROR, "PCI", "bad interrupt pin", "Interrupt pin should be between 0 and 4; got %d.\n", interruptPin);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
EnableFeatures(K_PCI_FEATURE_INTERRUPTS);
|
EnableFeatures(K_PCI_FEATURE_INTERRUPTS);
|
||||||
|
|
||||||
|
// If we booted from EFI, we need to get the interrupt line from ACPI.
|
||||||
|
// See the comment in InterruptHandler for what happens when passing -1.
|
||||||
|
|
||||||
if (KRegisterIRQ(KBootedFromEFI() ? -1 : interruptLine, irqHandler, context, cOwnerName, this)) {
|
if (KRegisterIRQ(KBootedFromEFI() ? -1 : interruptLine, irqHandler, context, cOwnerName, this)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,8 @@ struct VirtualAddressSpaceData {
|
||||||
|
|
||||||
uint8_t coreL1Commit[(0xFFFF800200000000 - 0xFFFF800100000000) >> (/* ENTRIES_PER_PAGE_TABLE_BITS */ 9 + K_PAGE_BITS + 3)];
|
uint8_t coreL1Commit[(0xFFFF800200000000 - 0xFFFF800100000000) >> (/* ENTRIES_PER_PAGE_TABLE_BITS */ 9 + K_PAGE_BITS + 3)];
|
||||||
|
|
||||||
|
uint8_t pciIRQLines[0x100 /* slots */][4 /* pins */];
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef IMPLEMENTATION
|
#ifdef IMPLEMENTATION
|
||||||
|
@ -1112,8 +1114,29 @@ extern "C" void InterruptHandler(InterruptContext *context) {
|
||||||
for (uintptr_t i = 0; i < sizeof(irqHandlers) / sizeof(irqHandlers[0]); i++) {
|
for (uintptr_t i = 0; i < sizeof(irqHandlers) / sizeof(irqHandlers[0]); i++) {
|
||||||
IRQHandler *handler = &irqHandlers[i];
|
IRQHandler *handler = &irqHandlers[i];
|
||||||
if (!handler->callback) continue;
|
if (!handler->callback) continue;
|
||||||
if (handler->line != -1 && (uintptr_t) handler->line != line) continue;
|
|
||||||
if (handler->line == -1 && line != 9 && line != 10 && line != 11) continue;
|
if (handler->line == -1) {
|
||||||
|
// Before we get the actual IRQ line information from ACPI (which might take it a while),
|
||||||
|
// only test that the IRQ is in the correct range for PCI interrupts.
|
||||||
|
// This is a bit slower because we have to dispatch the interrupt to more drivers,
|
||||||
|
// but it shouldn't break anything because they're all supposed to handle overloading anyway.
|
||||||
|
// This is mess. Hopefully all modern computers will use MSIs for anything important.
|
||||||
|
|
||||||
|
if (line != 9 && line != 10 && line != 11) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
uint8_t mappedLine = pciIRQLines[handler->pciDevice->slot][handler->pciDevice->interruptPin - 1];
|
||||||
|
|
||||||
|
if (mappedLine && line != mappedLine) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((uintptr_t) handler->line != line) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handler->callback(interrupt - IRQ_BASE, handler->context);
|
handler->callback(interrupt - IRQ_BASE, handler->context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue