[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
- [PATCH v2 1/1 libacpica] acpi_init: Get pci root port handle \_SB.PCI0 directly,
Damien Zammit <=