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


Reply via email to