]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ACPI: PCI: IRQ: Fix INTx GSIs signedness
authorLorenzo Pieralisi <lpieralisi@kernel.org>
Mon, 5 Jan 2026 10:17:05 +0000 (11:17 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 5 Jan 2026 18:06:40 +0000 (19:06 +0100)
In ACPI Global System Interrupts (GSIs) are described using a 32-bit
value.

ACPI/PCI legacy interrupts (INTx) parsing code treats GSIs as 'int',
which poses issues if the GSI interrupt value is a 32-bit value with the
MSB set (as required in some interrupt configurations - eg ARM64 GICv5
systems) because acpi_pci_link_allocate_irq() treats a negative gsi
return value as a failed GSI allocation (and acpi_irq_get_penalty()
would trigger an out-of-bounds array dereference if the 'irq' param is
a negative value).

Fix ACPI/PCI legacy INTx parsing by converting variables representing
GSIs from 'int' to 'u32' bringing the code in line with the ACPI
specification and fixing the current parsing issue.

Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
Reviewed-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20260105101705.36703-1-lpieralisi@kernel.org
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/pci_irq.c
drivers/acpi/pci_link.c
drivers/xen/acpi.c
include/acpi/acpi_drivers.h

index ad81aa03fe2f8534cf76bc323e6b2dd9b0a54883..c416942ff3e2625c1832e7bc4b21c2f6c874808d 100644 (file)
@@ -188,7 +188,7 @@ static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev,
         * the IRQ value, which is hardwired to specific interrupt inputs on
         * the interrupt controller.
         */
-       pr_debug("%04x:%02x:%02x[%c] -> %s[%d]\n",
+       pr_debug("%04x:%02x:%02x[%c] -> %s[%u]\n",
                 entry->id.segment, entry->id.bus, entry->id.device,
                 pin_name(entry->pin), prt->source, entry->index);
 
@@ -384,7 +384,7 @@ static inline bool acpi_pci_irq_valid(struct pci_dev *dev, u8 pin)
 int acpi_pci_irq_enable(struct pci_dev *dev)
 {
        struct acpi_prt_entry *entry;
-       int gsi;
+       u32 gsi;
        u8 pin;
        int triggering = ACPI_LEVEL_SENSITIVE;
        /*
@@ -422,18 +422,21 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
                        return 0;
        }
 
+       rc = -ENODEV;
+
        if (entry) {
                if (entry->link)
-                       gsi = acpi_pci_link_allocate_irq(entry->link,
+                       rc = acpi_pci_link_allocate_irq(entry->link,
                                                         entry->index,
                                                         &triggering, &polarity,
-                                                        &link);
-               else
+                                                        &link, &gsi);
+               else {
                        gsi = entry->index;
-       } else
-               gsi = -1;
+                       rc = 0;
+               }
+       }
 
-       if (gsi < 0) {
+       if (rc < 0) {
                /*
                 * No IRQ known to the ACPI subsystem - maybe the BIOS /
                 * driver reported one, then use it. Exit in any case.
index bed7dc85612e3ec2f33d5f2418960616779de625..b91b039a3d20f8656891942e35f630c448ca519a 100644 (file)
@@ -448,7 +448,7 @@ static int acpi_isa_irq_penalty[ACPI_MAX_ISA_IRQS] = {
        /* >IRQ15 */
 };
 
-static int acpi_irq_pci_sharing_penalty(int irq)
+static int acpi_irq_pci_sharing_penalty(u32 irq)
 {
        struct acpi_pci_link *link;
        int penalty = 0;
@@ -474,7 +474,7 @@ static int acpi_irq_pci_sharing_penalty(int irq)
        return penalty;
 }
 
-static int acpi_irq_get_penalty(int irq)
+static int acpi_irq_get_penalty(u32 irq)
 {
        int penalty = 0;
 
@@ -528,7 +528,7 @@ static int acpi_irq_balance = -1;   /* 0: static, 1: balance */
 static int acpi_pci_link_allocate(struct acpi_pci_link *link)
 {
        acpi_handle handle = link->device->handle;
-       int irq;
+       u32 irq;
        int i;
 
        if (link->irq.initialized) {
@@ -598,44 +598,53 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
        return 0;
 }
 
-/*
- * acpi_pci_link_allocate_irq
- * success: return IRQ >= 0
- * failure: return -1
+/**
+ * acpi_pci_link_allocate_irq(): Retrieve a link device GSI
+ *
+ * @handle: Handle for the link device
+ * @index: GSI index
+ * @triggering: pointer to store the GSI trigger
+ * @polarity: pointer to store GSI polarity
+ * @name: pointer to store link device name
+ * @gsi: pointer to store GSI number
+ *
+ * Returns:
+ *     0 on success with @triggering, @polarity, @name, @gsi initialized.
+ *     -ENODEV on failure
  */
 int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
-                              int *polarity, char **name)
+                              int *polarity, char **name, u32 *gsi)
 {
        struct acpi_device *device = acpi_fetch_acpi_dev(handle);
        struct acpi_pci_link *link;
 
        if (!device) {
                acpi_handle_err(handle, "Invalid link device\n");
-               return -1;
+               return -ENODEV;
        }
 
        link = acpi_driver_data(device);
        if (!link) {
                acpi_handle_err(handle, "Invalid link context\n");
-               return -1;
+               return -ENODEV;
        }
 
        /* TBD: Support multiple index (IRQ) entries per Link Device */
        if (index) {
                acpi_handle_err(handle, "Invalid index %d\n", index);
-               return -1;
+               return -ENODEV;
        }
 
        mutex_lock(&acpi_link_lock);
        if (acpi_pci_link_allocate(link)) {
                mutex_unlock(&acpi_link_lock);
-               return -1;
+               return -ENODEV;
        }
 
        if (!link->irq.active) {
                mutex_unlock(&acpi_link_lock);
                acpi_handle_err(handle, "Link active IRQ is 0!\n");
-               return -1;
+               return -ENODEV;
        }
        link->refcnt++;
        mutex_unlock(&acpi_link_lock);
@@ -647,7 +656,9 @@ int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
        if (name)
                *name = acpi_device_bid(link->device);
        acpi_handle_debug(handle, "Link is referenced\n");
-       return link->irq.active;
+       *gsi = link->irq.active;
+
+       return 0;
 }
 
 /*
index d2ee605c5ca1c7898a4dc5cc324b51af84497f13..eab28cfe993918d4c80c22b28c9f7e7a076e736c 100644 (file)
@@ -89,11 +89,11 @@ int xen_acpi_get_gsi_info(struct pci_dev *dev,
                                                  int *trigger_out,
                                                  int *polarity_out)
 {
-       int gsi;
+       u32 gsi;
        u8 pin;
        struct acpi_prt_entry *entry;
        int trigger = ACPI_LEVEL_SENSITIVE;
-       int polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ?
+       int ret, polarity = acpi_irq_model == ACPI_IRQ_MODEL_GIC ?
                                      ACPI_ACTIVE_HIGH : ACPI_ACTIVE_LOW;
 
        if (!dev || !gsi_out || !trigger_out || !polarity_out)
@@ -105,17 +105,18 @@ int xen_acpi_get_gsi_info(struct pci_dev *dev,
 
        entry = acpi_pci_irq_lookup(dev, pin);
        if (entry) {
+               ret = 0;
                if (entry->link)
-                       gsi = acpi_pci_link_allocate_irq(entry->link,
+                       ret = acpi_pci_link_allocate_irq(entry->link,
                                                         entry->index,
                                                         &trigger, &polarity,
-                                                        NULL);
+                                                        NULL, &gsi);
                else
                        gsi = entry->index;
        } else
-               gsi = -1;
+               ret = -ENODEV;
 
-       if (gsi < 0)
+       if (ret < 0)
                return -EINVAL;
 
        *gsi_out = gsi;
index b14d165632e761b668a8913830cd856158a0efe4..402b97d1213818ab61e0411bef67b89e99a95e5e 100644 (file)
@@ -51,7 +51,7 @@
 
 int acpi_irq_penalty_init(void);
 int acpi_pci_link_allocate_irq(acpi_handle handle, int index, int *triggering,
-                              int *polarity, char **name);
+                              int *polarity, char **name, u32 *gsi);
 int acpi_pci_link_free_irq(acpi_handle handle);
 
 /* ACPI PCI Device Binding */