mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-01-11 17:10:13 +00:00
ACPI: PCI: IRQ: Fix INTx GSIs signedness
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>
This commit is contained in:
parent
9ace4753a5
commit
1ca8677d9f
@ -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.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user