This patch declares acpi_register_gsi() as weak and allows architecture to specify its own acpi_register_gsi().
In ARM64 case, we need to specify GIC_INT_TYPE_XXX when calling irq_domain_ops.init_alloc_info(), which is specific to ARM64.
Signed-off-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com --- arch/arm64/kernel/acpi.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/gsi.c | 4 ++-- include/linux/acpi.h | 4 ++++ 3 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 19de753..05e9c07 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -20,6 +20,7 @@ #include <linux/cpumask.h> #include <linux/init.h> #include <linux/irq.h> +#include <linux/irqchip/arm-gic.h> #include <linux/irqdomain.h> #include <linux/memblock.h> #include <linux/of_fdt.h> @@ -230,3 +231,50 @@ void __init acpi_gic_init(void)
early_acpi_os_unmap_memory((char *)table, tbl_size); } + +int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, + int polarity) +{ + unsigned int irq; + unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity); + struct irq_data *d = NULL; + + if (acpi_irq_domain && acpi_irq_domain->ops->init_alloc_info) { + void *info; + int err; + uint32_t data[3] = {GIC_INT_TYPE_NONE, gsi, irq_type}; + + err = acpi_irq_domain->ops->init_alloc_info(data, 3, + NULL, &info); + if (err) + return err; + + irq = irq_domain_alloc_irqs(acpi_irq_domain, 1, + dev_to_node(dev), info); + if (irq < 0) + return -ENOSPC; + + d = irq_domain_get_irq_data(acpi_irq_domain, irq); + if (!d) + return -EFAULT; + } else { + /* + * There is no IRQ domain on ACPI, + * hence always create mapping referring to the default domain + * by passing NULL as irq_domain parameter + */ + irq = irq_create_mapping(NULL, gsi); + if (!irq) + return -EINVAL; + } + + /* Set irq type if specified and different than the current one */ + if (irq_type != IRQ_TYPE_NONE && + irq_type != irq_get_trigger_type(irq)) { + if (d) + d->chip->irq_set_type(d, irq_type); + else + irq_set_irq_type(irq, irq_type); + } + return irq; +} diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c index 8fa8a01..a015d9e 100644 --- a/drivers/acpi/gsi.c +++ b/drivers/acpi/gsi.c @@ -80,8 +80,8 @@ EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); * Returns: a valid linux IRQ number on success * -EINVAL on failure */ -int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, - int polarity) +int __weak acpi_register_gsi(struct device *dev, u32 gsi, int trigger, + int polarity) { unsigned int irq; unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 6826ca4..5254d39 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -221,6 +221,10 @@ extern unsigned long acpi_realmode_flags; int acpi_register_gsi (struct device *dev, u32 gsi, int triggering, int polarity); int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi); +unsigned int acpi_gsi_get_irq_type(int trigger, int polarity); + +extern struct irq_domain *acpi_irq_domain; +int acpi_gsi_set_domain(struct irq_domain *domain);
#ifdef CONFIG_X86_IO_APIC extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);