bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2 1/1 libacpica] acpi_init: Get pci root port handle \_SB.PCI0 d


From: Damien Zammit
Subject: [PATCH v2 1/1 libacpica] acpi_init: Get pci root port handle \_SB.PCI0 directly
Date: Sat, 28 Dec 2024 02:36:06 +0000

This mostly fixes the numbering of IRQs when requested.
This now works on an old AMD board with broken _CRS.
It requests the possible irqs from _PRS and generates
a valid _SRS request to set the one from the end of the list.

v2: It also no longer errors on a valid _CRS.

---
 debian/patches/acpi-init-files.diff | 327 +++++++++++++++++++---------
 1 file changed, 221 insertions(+), 106 deletions(-)

diff --git a/debian/patches/acpi-init-files.diff 
b/debian/patches/acpi-init-files.diff
index eb7482c..f45cec9 100644
--- a/debian/patches/acpi-init-files.diff
+++ b/debian/patches/acpi-init-files.diff
@@ -1,6 +1,6 @@
 --- /dev/null
 +++ b/acpi_init.c
-@@ -0,0 +1,597 @@
+@@ -0,0 +1,712 @@
 +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
 +#include <acpi/acpi.h>
 +
@@ -32,6 +32,9 @@
 +#define PCI_CFG1_START 0xcf8
 +#define PCI_CFG1_END   0xcff
 +
++#define LEGACY_ISA_IRQS 8
++#define PCI_IRQ_START 16
++
 +extern acpi_status acpi_hw_legacy_sleep(u8 sleep_state);
 +
 +// Lets keep the ACPI tables in this module
@@ -361,162 +364,165 @@
 +  acpi_hw_legacy_sleep (sleep_state);
 +}
 +
++
 +static acpi_status
-+register_slot(acpi_handle handle, u32 lev, void *context, void **rv)
++acpi_pci_link_count_all(struct acpi_resource *resource, void *context)
 +{
-+  if (!context)
-+    return AE_ERROR;
++  int *count = (int *)context;
 +
-+  u64 addr, addr_bus;
-+  acpi_status err;
++  (*count)++;
 +
-+  struct slots *s = (void *)malloc(sizeof (struct slots));
-+  if (!s)
-+    return -1;
-+
-+  {
-+    struct acpi_buffer buffer = { 0, NULL };
-+    union acpi_object element;
-+    buffer.length = sizeof(union acpi_object);
-+    buffer.pointer = &element;
-+    err = acpi_evaluate_object(handle, METHOD_NAME__BBN, NULL, &buffer);
-+    if (ACPI_SUCCESS(err) && element.type == ACPI_TYPE_INTEGER)
-+      addr_bus = element.integer.value;
-+    else if (err == AE_NOT_FOUND)
-+      addr_bus = 0;
-+    else
-+      {
-+        free(s);
-+        return AE_ERROR;
-+      }
-+  }
-+
-+  s->bus = addr_bus & 0xff;
-+
-+  {
-+    struct acpi_buffer buffer = { 0, NULL };
-+    union acpi_object element;
-+    buffer.length = sizeof(union acpi_object);
-+    buffer.pointer = &element;
-+
-+    err = acpi_evaluate_object(handle, METHOD_NAME__ADR, NULL, &buffer);
-+    if (ACPI_SUCCESS(err) && element.type == ACPI_TYPE_INTEGER)
-+      addr = element.integer.value;
-+    else if (err == AE_NOT_FOUND)
-+      {
-+        free(s);
-+        return AE_OK;
-+      }
-+    else
-+      {
-+        free(s);
-+        return AE_ERROR;
-+      }
-+  }
-+
-+  s->dev = (addr >> 16) & 0xffff;
-+  s->func = addr & 0xffff;
-+  s->handle = handle;
-+  s->next = NULL;
-+
-+  struct slots **slot_ptr_ptr = (struct slots **)(context);
-+  if (!(*slot_ptr_ptr))
-+    *slot_ptr_ptr = s;
-+  else
++  return AE_OK;
++}
++
++static acpi_status
++acpi_pci_link_count_irq(struct acpi_resource *resource, void *context)
++{
++  int *count = (int *)context;
++
++  if (!resource->length)
++    return AE_OK;
++
++  switch (resource->type)
 +    {
-+      struct slots *slot_ptr = *slot_ptr_ptr;
-+      while(slot_ptr->next)
-+        slot_ptr = slot_ptr->next;
-+      slot_ptr->next = s;
++      case ACPI_RESOURCE_TYPE_IRQ:
++        {
++          struct acpi_resource_irq *irq_resource = &resource->data.irq;
++          if (!irq_resource || !irq_resource->interrupt_count || 
!irq_resource->interrupts[0])
++            return AE_OK;
++          (*count)++;
++        }
++        break;
++      case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
++        {
++          struct acpi_resource_extended_irq *irq_resource = 
&resource->data.extended_irq;
++          if (!irq_resource || !irq_resource->interrupt_count || 
!irq_resource->interrupts[0])
++            return AE_OK;
++          (*count)++;
++        }
++        break;
++      default:
++        break;
++    }
++
++  return AE_OK;
++}
++
++static acpi_status
++acpi_pci_link_subset_last_irq(struct acpi_resource *resource, void *context)
++{
++  struct acpi_resource *res = (struct acpi_resource *)context;
++
++  switch (resource->type)
++    {
++      case ACPI_RESOURCE_TYPE_IRQ:
++        {
++          struct acpi_resource_irq *irq_resource = &resource->data.irq;
++          if (!irq_resource || !irq_resource->interrupt_count || 
!irq_resource->interrupts[0])
++            return AE_OK;
++          *res = *resource;
++          return AE_OK;
++        }
++        break;
++      case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
++        {
++          struct acpi_resource_extended_irq *irq_resource = 
&resource->data.extended_irq;
++          if (!irq_resource || !irq_resource->interrupt_count || 
!irq_resource->interrupts[0])
++            return AE_OK;
++          *res = *resource;
++          return AE_OK;
++        }
++        break;
++      default:
++        break;
 +    }
++
 +  return AE_OK;
 +}
 +
 +static acpi_status
-+acpi_pci_link_check(struct acpi_resource *resource, void *context)
++acpi_pci_link_get_last_valid_irq(struct acpi_resource *resource, void 
*context)
 +{
 +  int *irq = (int *)context;
 +
++  if (!resource->length)
++    {
++      acpi_os_printf("Empty resource\n");
++      return AE_OK;
++    }
++
 +  switch (resource->type)
 +    {
 +      case ACPI_RESOURCE_TYPE_IRQ:
 +        {
 +          struct acpi_resource_irq *irq_resource = &resource->data.irq;
-+          if (!irq_resource || !irq_resource->interrupt_count)
++          if (!irq_resource || !irq_resource->interrupt_count || 
!irq_resource->interrupts[0])
 +            {
 +              // no IRQ# bits set generally w/ _STA disabled
 +              acpi_os_printf("Empty _CRS IRQ resource\n");
 +              return AE_OK;
 +            }
 +          *irq = irq_resource->interrupts[0];
-+          break;
 +        }
++        break;
 +      case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
 +        {
 +          struct acpi_resource_extended_irq *irq_resource = 
&resource->data.extended_irq;
-+          if (!irq_resource || !irq_resource->interrupt_count)
++          if (!irq_resource || !irq_resource->interrupt_count || 
!irq_resource->interrupts[0])
 +            {
 +              // extended IRQ descriptors should return at least 1 IRQ
 +              acpi_os_printf("Empty _CRS EXT IRQ resource\n");
 +              return AE_OK;
 +            }
 +          *irq = irq_resource->interrupts[0];
-+          break;
 +        }
++        break;
++      case ACPI_RESOURCE_TYPE_END_TAG:
++        return AE_OK;
++        break;
 +      default:
++        acpi_os_printf("Not IRQ resource\n");
 +        return AE_OK;
 +    }
 +
-+  return AE_CTRL_TERMINATE;
++  acpi_os_printf("Found IRQ resource %d\n", *irq);
++  return AE_OK;
 +}
 +
 +int
 +acpi_get_irq_number(uint16_t bus, uint16_t dev, uint16_t func)
 +{
 +  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;
++
 +  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;
-+  struct slots *pcislots = NULL, *iter;
-+  int nslots = 0;
 +
-+  err = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, INT_MAX, register_slot, 
NULL, (struct slots **)&pcislots, NULL);
++  err = acpi_get_handle(handle, "\\_SB.PCI0", &parent_handle);
 +  if (ACPI_FAILURE(err))
 +    return -EIO;
 +
-+  for (iter = pcislots; iter; iter = iter->next)
-+    {
-+      if ((iter->bus == bus) && (iter->dev == dev) && (iter->func == func))
-+        {
-+        handle = iter->handle;
-+          break;
-+        }
-+      nslots++;
-+    }
++  err = acpi_get_handle(parent_handle, METHOD_NAME__PRT, &prt);
++  if (ACPI_FAILURE(err))
++    return -EIO;
 +
-+  err = acpi_get_parent(handle, &parent_handle);
++  err = acpi_evaluate_object(prt, NULL, NULL, &buffer);
 +  if (ACPI_FAILURE(err))
 +    return -EIO;
 +
 +  err = acpi_get_irq_routing_table(parent_handle, &buffer);
 +  if (ACPI_FAILURE(err))
-+    {
-+      free(buffer.pointer);
-+      // free pcislots allocated in register_slot function
-+      struct slots *current_pcislot = pcislots;
-+      while (current_pcislot)
-+        {
-+          free(current_pcislot);
-+          pcislots = pcislots->next;
-+          current_pcislot = pcislots;
-+        }
-+      return -EIO;
-+    }
++    return -EIO;
 +
-+  entry = ACPI_CAST_PTR(struct acpi_pci_routing_table, buffer.pointer);
++  entry = ACPI_CAST_PTR(struct acpi_pci_routing_table, ACPI_CAST_PTR(u8, 
buffer.pointer));
 +  while (entry && (entry->length > 0))
 +    {
 +      /* Already applies to the bus of the device */
@@ -525,28 +531,137 @@
 +      if ((prt_dev == dev) && (prt_func == 0xffff))
 +        {
 +          if (entry->source[0])
-+          {
++            {
++              int crs_count = 0;
++              int prs_count_irq = 0;
++              int prs_count_all = 0;
++              int irq = -1;
++
 +              /* Dynamic:
 +               * - source field specifies PCI interrupt LNK
 +               * - source_index specifies which resource descriptor in
 +               *   resource template of LNK to allocate this interrupt
 +               */
-+              err = acpi_get_handle(handle, entry->source, &lnk);
++              err = acpi_get_handle(ACPI_ROOT_OBJECT, entry->source, &lnk);
 +              if (ACPI_FAILURE(err))
 +                return -EIO;
 +
 +              if (!lnk)
-+                acpi_os_printf("error invalid lnk");
-+
-+              int irq = -1;
-+              err = acpi_walk_resources(lnk, METHOD_NAME__CRS, 
acpi_pci_link_check, &irq);
++                {
++                  acpi_os_printf("Error invalid lnk\n");
++                  return -EIO;
++                }
++
++              err = acpi_walk_resources(lnk, "_CRS", acpi_pci_link_count_irq, 
&crs_count);
++              if (ACPI_FAILURE(err) || !crs_count)
++                acpi_os_printf("Warning: missing _CRS\n");
++              acpi_walk_resources(lnk, "_PRS", acpi_pci_link_count_all, 
&prs_count_all);
++              err = acpi_walk_resources(lnk, "_PRS", acpi_pci_link_count_irq, 
&prs_count_irq);
 +              if (ACPI_FAILURE(err))
-+                return -EIO;
-+              return irq;
-+              // FIXME check the LNK irq _CRS and then set it with _SRS
++                {
++                  if (crs_count == 0)
++                    {
++                      acpi_os_printf("Error: missing _PRS when needed\n");
++                      return -EIO;
++                    }
++                }
++              if (crs_count > 0)
++                {
++                  irq = 0;
++                  err = acpi_walk_resources(lnk, "_CRS", 
acpi_pci_link_get_last_valid_irq, &irq);
++                  if (ACPI_FAILURE(err) || !irq)
++                    {
++                      acpi_os_printf("Error walk_resources _CRS\n");
++                      return -EIO;
++                    }
++
++                  err = acpi_get_current_resources(lnk, &srs_buffer);
++                  if (ACPI_FAILURE(err))
++                    {
++                      acpi_os_printf("Error getting _CRS\n");
++                      return -EIO;
++                    }
++
++                  err = acpi_set_current_resources(lnk, &srs_buffer);
++                  if (ACPI_FAILURE(err))
++                    {
++                      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;
++                }
++              else if (prs_count_irq > 0)
++                {
++                  irq = 0;
++                  err = acpi_walk_resources(lnk, "_PRS", 
acpi_pci_link_get_last_valid_irq, &irq);
++                  if (ACPI_FAILURE(err) || !irq)
++                    {
++                      acpi_os_printf("Error walk_resources _PRS\n");
++                      return -EIO;
++                    }
++
++                  if (irq > 16)
++                    {
++                      acpi_os_printf("Error IRQ > 16, not implemented\n");
++                      return -EIO;
++                    }
++
++                  /* Found a possible irq, but need to call _SRS to set it */
++
++                  /* IRQ resource + end tagged resource */
++                  srs_count = 2;
++
++                  res = (struct acpi_resource *)calloc(1, srs_count * 
sizeof(struct acpi_resource));
++
++                  err = acpi_walk_resources(lnk, "_PRS", 
acpi_pci_link_subset_last_irq, res);
++                  if (err)
++                    {
++                      acpi_os_printf("Error _PRS cannot be read\n");
++                      free(res);
++                      return -EIO;
++                    }
++
++                  /* Patch the _PRS to use for _SRS */
++                  srs_buffer.length = sizeof(struct acpi_resource) + 1;
++                  srs_buffer.pointer = res;
++
++                  switch (res->type)
++                    {
++                      case ACPI_RESOURCE_TYPE_IRQ:
++                        res->data.irq.interrupt_count = 1;
++                        res->data.irq.interrupts[0] = irq;
++                        break;
++                      case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
++                        res->data.extended_irq.interrupt_count = 1;
++                        res->data.extended_irq.interrupts[0] = irq;
++                        break;
++                    }
++
++                  res[1].type = ACPI_RESOURCE_TYPE_END_TAG;
++                  res[1].length = sizeof(struct acpi_resource);
++
++                  err = acpi_set_current_resources(lnk, &srs_buffer);
++                  if (ACPI_FAILURE(err))
++                    {
++                      acpi_os_printf("Error setting _SRS\n");
++                      free(res);
++                      return -EIO;
++                    }
++                  free(res);
++                  irq += (irq > LEGACY_ISA_IRQS) ? 0 : PCI_IRQ_START;
++                  acpi_os_printf("Final irq %d\n", irq);
++                  return irq;
++                }
++              else
++                {
++                  acpi_os_printf("Error: _CRS has empty IRQ resources\n");
++                  return -EIO;
++                }
 +            }
-+        else
-+          {
++          else
++            {
 +              /* Static:
 +               * - source field is zero
 +               * - source_index specifies IRQ value hardwired to
-- 
2.45.2





reply via email to

[Prev in Thread] Current Thread [Next in Thread]