git: a1330a71d20d - main - acpi: Handle multiple interrupts

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Tue, 19 Nov 2024 17:47:01 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=a1330a71d20d862eb9d930d87245f23ee4853527

commit a1330a71d20d862eb9d930d87245f23ee4853527
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2024-11-18 15:29:42 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2024-11-19 17:14:42 +0000

    acpi: Handle multiple interrupts
    
    When multiple IRQs are specified in a single resource then we only
    check the first. Change this to check all interrupts for the value
    we expect to find.
    
    Without this we may still enable the interrupt, but it can have the
    wrong polatiry or trigger. This can cause an interrupt storm if the
    interrupt was configured with a level trigger when it should have
    been an edge.
    
    PR:             282241
    Reported by:    trasz
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D47487
---
 sys/dev/acpica/acpi_resource.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/sys/dev/acpica/acpi_resource.c b/sys/dev/acpica/acpi_resource.c
index 1257ed30cc65..8c5a3ed57f32 100644
--- a/sys/dev/acpica/acpi_resource.c
+++ b/sys/dev/acpica/acpi_resource.c
@@ -72,19 +72,33 @@ acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
 {
     struct lookup_irq_request *req;
     size_t len;
-    u_int irqnum, irq, trig, pol;
+    u_int irqnum, trig, pol;
+    bool found;
+
+    found = false;
+    req = (struct lookup_irq_request *)context;
 
     switch (res->Type) {
     case ACPI_RESOURCE_TYPE_IRQ:
 	irqnum = res->Data.Irq.InterruptCount;
-	irq = res->Data.Irq.Interrupts[0];
+	for (int i = 0; i < irqnum; i++) {
+	    if (res->Data.Irq.Interrupts[i] == req->irq) {
+		found = true;
+		break;
+	    }
+	}
 	len = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ);
 	trig = res->Data.Irq.Triggering;
 	pol = res->Data.Irq.Polarity;
 	break;
     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
 	irqnum = res->Data.ExtendedIrq.InterruptCount;
-	irq = res->Data.ExtendedIrq.Interrupts[0];
+	for (int i = 0; i < irqnum; i++) {
+	    if (res->Data.ExtendedIrq.Interrupts[i] == req->irq) {
+		found = true;
+		break;
+	    }
+	}
 	len = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ);
 	trig = res->Data.ExtendedIrq.Triggering;
 	pol = res->Data.ExtendedIrq.Polarity;
@@ -92,18 +106,13 @@ acpi_lookup_irq_handler(ACPI_RESOURCE *res, void *context)
     default:
 	return (AE_OK);
     }
-    if (irqnum != 1)
+    if (!found)
 	return (AE_OK);
-    req = (struct lookup_irq_request *)context;
     if (req->checkrid) {
 	if (req->counter != req->rid) {
 	    req->counter++;
 	    return (AE_OK);
 	}
-	KASSERT(irq == req->irq, ("IRQ resources do not match"));
-    } else {
-	if (req->irq != irq)
-	    return (AE_OK);
     }
     req->found = 1;
     req->pol = pol;