General support for applying ACPI data to subordinate buses:
Parse ACPI tables to find PCI-PCI bridges, their bus numbers and _PRT tables.
Use the parsed data to apply appropriate _PRT table per GSI lookup.
Translate PCI pin numbers whilst iterating the bus hierarchy.
---
debian/patches/acpi-init-files.diff | 269 +++++++++++++++++++++++++---
1 file changed, 242 insertions(+), 27 deletions(-)
diff --git a/debian/patches/acpi-init-files.diff
b/debian/patches/acpi-init-files.diff
index 8f2080b..5ee59dd 100644
--- a/debian/patches/acpi-init-files.diff
+++ b/debian/patches/acpi-init-files.diff
@@ -1,6 +1,8 @@
---- /dev/null
-+++ b/acpi_init.c
-@@ -0,0 +1,830 @@
+Index: libacpica/acpi_init.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ libacpica/acpi_init.c 2025-10-26 13:07:39.753578190 +0000
+@@ -0,0 +1,1041 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+#include <acpi/acpi.h>
+
@@ -33,12 +35,16 @@
+#define PCI_CFG1_START 0xcf8
+#define PCI_CFG1_END 0xcff
+
-+#define LEGACY_ISA_IRQS 8
-+#define PCI_IRQ_START 16
-+
+#define PCI_INTERRUPT_PIN 0x3d
+#define BAD_PIC_MODE(m) ((m) < ACPI_PICMODE_PIC || (m) > ACPI_PICMODE_SAPIC)
+
++#define PCI_HDR_TYPE_REG 0x0e
++#define PCI_HDR_TYPE_PPB 1
++#define PCI_PPB_SECBUS_REG 0x19
++#define PCI_MAX_DEV_ID 0x1f
++#define PCI_MAX_FUNC_ID 0x7
++#define PCI_MULTI_FUNC_MASK 0x80
++
+extern acpi_status acpi_hw_legacy_sleep(u8 sleep_state);
+
+// Lets keep the ACPI tables in this module
@@ -48,6 +54,16 @@
+static int numdevs = -1;
+static int pic_mode = -1;
+
++typedef struct acpi_pci_bridge
++{
++ acpi_handle handle;
++ uint8_t up_bus;
++ uint8_t down_bus;
++ struct acpi_pci_bridge* next;
++} acpi_pci_bridge_t;
++
++static acpi_pci_bridge_t* acpi_pci_bridges;
++
+struct slots {
+ uint8_t bus;
+ uint16_t dev;
@@ -111,6 +127,17 @@
+ return NULL;
+}
+
++static void
++acpi_unload_pci_bridges(void)
++{
++ while (acpi_pci_bridges != NULL)
++ {
++ acpi_pci_bridge_t* bridge = acpi_pci_bridges;
++ acpi_pci_bridges = bridge->next;
++ free(bridge);
++ }
++}
++
+void
+acpi_ds_dump_method_stack(acpi_status status, ...)
+// struct acpi_walk_state *walk_state, union acpi_parse_object *op)
@@ -331,6 +358,7 @@
+acpi_os_terminate(void)
+{
+ free(pci_devices);
++ acpi_unload_pci_bridges();
+ acpi_os_printf("Bye!\n");
+ return AE_OK;
+}
@@ -508,29 +536,22 @@
+ : (int)pci_pin);
+}
+
-+int
-+acpi_get_irq_number(uint16_t bus, uint16_t dev, uint16_t func)
++static int
++acpi_get_irq_from_handle(acpi_handle handle,
++ uint16_t dev, uint16_t func, int pci_pin)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_buffer srs_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_pci_routing_table *entry;
+ struct acpi_resource *res;
-+ uint8_t *buf;
+ int srs_count;
-+ int pci_pin;
+
-+ acpi_handle handle = ACPI_ROOT_OBJECT;
-+ acpi_handle parent_handle = NULL;
+ acpi_handle prt = NULL;
+ acpi_handle lnk = NULL;
+ acpi_status err = AE_OK;
+ u16 prt_dev, prt_func;
+
-+ err = acpi_get_handle(handle, "\\_SB.PCI0", &parent_handle);
-+ if (ACPI_FAILURE(err))
-+ return -EIO;
-+
-+ err = acpi_get_handle(parent_handle, METHOD_NAME__PRT, &prt);
++ err = acpi_get_handle(handle, METHOD_NAME__PRT, &prt);
+ if (ACPI_FAILURE(err))
+ return -EIO;
+
@@ -538,7 +559,7 @@
+ if (ACPI_FAILURE(err))
+ return -EIO;
+
-+ err = acpi_get_irq_routing_table(parent_handle, &buffer);
++ err = acpi_get_irq_routing_table(handle, &buffer);
+ if (ACPI_FAILURE(err))
+ return -EIO;
+
@@ -546,11 +567,6 @@
+ if (BAD_PIC_MODE(pic_mode))
+ return -EIO;
+
-+ pci_pin = acpi_pci_get_device_pin(bus, dev, func);
-+ /* Fail if the device pin used is unknown (0) */
-+ if (pci_pin <= 0)
-+ return -EIO;
-+
+ entry = ACPI_CAST_PTR(struct acpi_pci_routing_table, ACPI_CAST_PTR(u8,
buffer.pointer));
+ while (entry && (entry->length > 0))
+ {
@@ -619,7 +635,6 @@
+ acpi_os_printf("Error setting _SRS\n");
+ return -EIO;
+ }
-+ irq += (irq > LEGACY_ISA_IRQS) ? 0 : PCI_IRQ_START;
+ acpi_os_printf("Final irq %d\n", irq);
+ return irq;
+ }
@@ -681,7 +696,6 @@
+ return -EIO;
+ }
+ free(res);
-+ irq += (irq > LEGACY_ISA_IRQS) ? 0 : PCI_IRQ_START;
+ acpi_os_printf("Final irq %d\n", irq);
+ return irq;
+ }
@@ -708,6 +722,55 @@
+ return -EIO;
+}
+
++static acpi_pci_bridge_t*
++acpi_find_pci_bridge(int bus)
++{
++ if (bus == 0)
++ return NULL;
++
++ acpi_pci_bridge_t* bridge = acpi_pci_bridges;
++
++ while (bridge != NULL)
++ {
++ if (bridge->down_bus == bus)
++ return bridge;
++
++ bridge = bridge->next;
++ }
++
++ return NULL;
++}
++
++int
++acpi_get_irq_number(uint16_t bus, uint16_t dev, uint16_t func)
++{
++ int pci_pin = acpi_pci_get_device_pin(bus, dev, func);
++ /* Fail if the device pin used is unknown (0) */
++ if (pci_pin <= 0)
++ return -EIO;
++
++ acpi_pci_bridge_t* bridge = acpi_find_pci_bridge(bus);
++
++ while (bridge != NULL)
++ {
++ int irq = acpi_get_irq_from_handle(bridge->handle, dev, func, pci_pin);
++ if (irq >= 0)
++ return irq;
++
++ /* Translate the downstream INTx to the upstream one */
++ pci_pin = ((pci_pin + dev) % 4);
++ bus = bridge->up_bus;
++ bridge = acpi_find_pci_bridge(bus);
++ }
++
++ acpi_handle handle;
++ acpi_status err = acpi_get_handle(ACPI_ROOT_OBJECT, "\\_SB.PCI0", &handle);
++ if (ACPI_FAILURE(err))
++ return -EIO;
++
++ return acpi_get_irq_from_handle(handle, dev, func, pci_pin);
++}
++
+/* Fetch the active interrupt mode from GNU mach */
+static error_t
+acpi_required_pic_mode (void)
@@ -792,6 +855,152 @@
+ return err;
+}
+
++static acpi_status
++acpi_pci_bridge_add(acpi_handle handle, uint8_t up_bus, uint8_t down_bus)
++{
++ acpi_pci_bridge_t* bridge =
++ (acpi_pci_bridge_t*)malloc(sizeof(acpi_pci_bridge_t));
++
++ if (bridge == NULL)
++ return AE_NO_MEMORY;
++
++ bridge->handle = handle;
++ bridge->up_bus = up_bus;
++ bridge->down_bus = down_bus;
++ bridge->next = acpi_pci_bridges;
++ acpi_pci_bridges = bridge;
++
++ return AE_OK;
++}
++
++struct acpi_find_bus_context
++{
++ int is_bridge; /* Is this level a bridge or not */
++ uint8_t down_bus; /* The downstream bus num if a bridge */
++ struct acpi_find_bus_context* parent;
++};
++
++static acpi_status
++acpi_find_busses_down(acpi_handle handle, uint32_t level,
++ void *context_arg, void **status)
++{
++ struct acpi_find_bus_context** context =
++ (struct acpi_find_bus_context**)context_arg;
++
++ struct acpi_device_info *devinfo;
++ acpi_status rv = acpi_get_object_info(handle, &devinfo);
++
++ if (ACPI_FAILURE(rv))
++ return rv;
++
++ struct acpi_find_bus_context* device_context =
++ (struct acpi_find_bus_context*)malloc(sizeof(struct
acpi_find_bus_context));
++
++ if (device_context == NULL)
++ return AE_NO_MEMORY;
++
++ device_context->is_bridge = 0;
++ device_context->down_bus = 0;
++ device_context->parent = *context;
++ *context = device_context;
++
++ if (devinfo->flags & ACPI_PCI_ROOT_BRIDGE)
++ {
++ device_context->is_bridge = 1;
++ }
++ else if (device_context->parent->is_bridge && (devinfo->valid &
ACPI_VALID_ADR))
++ {
++ uint8_t bus = device_context->parent->down_bus;
++ uint32_t devfunc = ACPI_LODWORD(devinfo->address);
++ uint16_t dev = ACPI_HIWORD(devfunc);
++ uint16_t func = ACPI_LOWORD(devfunc);
++
++ if (func <= PCI_MAX_FUNC_ID && dev <= PCI_MAX_DEV_ID)
++ {
++ struct acpi_pci_id pci_id =
++ {
++ .segment = 0, .bus = bus, .device = dev, .function = func
++ };
++ u64 val;
++
++ /* Ignore ACPI entries that refer to absent devices. */
++ if (acpi_os_read_pci_configuration(&pci_id, PCI_HDR_TYPE_REG, &val,
8))
++ goto exit;
++
++ {
++ /* Only 8 bits was read from the PCI configuration so cast OK. */
++ uint8_t hdrType = (uint8_t)val;
++ uint8_t mask = PCI_MULTI_FUNC_MASK;
++
++ if ((hdrType & ~mask) != PCI_HDR_TYPE_PPB)
++ goto exit;
++ }
++
++ if (acpi_os_read_pci_configuration(&pci_id, PCI_PPB_SECBUS_REG, &val,
8))
++ {
++ acpi_os_printf("Failed to find secondary bus for: %x:%x:%x\n",
++ bus, dev, func);
++ rv = AE_IO_ERROR;
++ goto exit;
++ }
++
++ /* Only 8 bits was read from the PCI configuration so cast OK. */
++ device_context->down_bus = (uint8_t)val;
++ device_context->is_bridge = 1;
++
++ rv = acpi_pci_bridge_add(handle, bus, device_context->down_bus);
++ }
++ }
++
++ exit:
++ ACPI_FREE(devinfo);
++
++ return rv;
++}
++
++static acpi_status
++acpi_find_busses_up(acpi_handle handle, uint32_t level,
++ void *context_arg, void **status)
++{
++ struct acpi_find_bus_context** context =
++ (struct acpi_find_bus_context**)context_arg;
++
++ struct acpi_find_bus_context* entry = *context;
++ *context = entry->parent;
++
++ free(entry);
++
++ return AE_OK;
++}
++
++static acpi_status
++acpi_load_pci_bridges(void)
++{
++ struct acpi_find_bus_context head_context =
++ {
++ .is_bridge = 0,
++ .down_bus = 0,
++ .parent = NULL
++ };
++
++ struct acpi_find_bus_context* context = &head_context;
++
++ acpi_status rv = acpi_walk_namespace
++ (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, UINT_MAX,
++ acpi_find_busses_down, acpi_find_busses_up, &context, NULL);
++
++ /* There should only be anything to free here in error cases */
++ while (context != &head_context)
++ {
++ struct acpi_find_bus_context* entry = context;
++ context = context->parent;
++
++ free(entry);
++ }
++
++ return rv;
++}
++
+void acpi_init(void)
+{
+ acpi_status err;
@@ -815,6 +1024,10 @@
+ if (ACPI_FAILURE (err))
+ goto die;
+
++ err = acpi_load_pci_bridges();
++ if (ACPI_FAILURE (err))
++ goto die;
++
+ /* Ignore return value for old gnumach without irq status */
+ acpi_configure_pic_mode();
+
@@ -831,8 +1044,10 @@
+die:
+ acpi_os_printf("OUCH!\n");
+}
---- /dev/null
-+++ b/include/acpi/acpi_init.h
+Index: libacpica/include/acpi/acpi_init.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ libacpica/include/acpi/acpi_init.h 2025-10-26 13:07:13.161934280 +0000
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+#ifndef ACPI_INIT_H_
--
2.39.5