git: a1330a71d20d - main - acpi: Handle multiple interrupts
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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;