From: Icenowy Zheng Date: Sat, 21 Mar 2026 09:20:30 +0000 (+0800) Subject: irqchip/loongson-pch-lpc: Extract non-ACPI-related code from ACPI init X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=29c10a0af04e9b3eb7b06e72e9f75fccca45205e;p=thirdparty%2Fkernel%2Flinux.git irqchip/loongson-pch-lpc: Extract non-ACPI-related code from ACPI init A lot of code can be shared between the existing ACPI init flow with the upcoming OF init flow. Extract it into a dedicated function. The re-ordering of parent interrupt allocation requires the architecture code to reserve legacy interrupts from the dynamic allocation by overriding arch_dynirq_lower_bound(), otherwise the parent of LPC irqchip will be allocated in the intended static range of LPC interrupts, which leads to allocation failure of LPC interrupts. Co-developed-by: Jiaxun Yang Signed-off-by: Jiaxun Yang Signed-off-by: Icenowy Zheng Signed-off-by: Thomas Gleixner Reviewed-by: Huacai Chen Link: https://patch.msgid.link/20260321092032.3502701-5-zhengxingda@iscas.ac.cn --- diff --git a/drivers/irqchip/irq-loongson-pch-lpc.c b/drivers/irqchip/irq-loongson-pch-lpc.c index 3ad46ec94e3c0..2bb6659e9a93c 100644 --- a/drivers/irqchip/irq-loongson-pch-lpc.c +++ b/drivers/irqchip/irq-loongson-pch-lpc.c @@ -175,13 +175,10 @@ static struct syscore pch_lpc_syscore = { .ops = &pch_lpc_syscore_ops, }; -int __init pch_lpc_acpi_init(struct irq_domain *parent, - struct acpi_madt_lpc_pic *acpi_pchlpc) +static int __init pch_lpc_init(phys_addr_t addr, unsigned long size, + struct fwnode_handle *irq_handle, int parent_irq) { - int parent_irq; struct pch_lpc *priv; - struct irq_fwspec fwspec; - struct fwnode_handle *irq_handle; priv = kzalloc_obj(*priv); if (!priv) @@ -189,7 +186,7 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, raw_spin_lock_init(&priv->lpc_lock); - priv->base = ioremap(acpi_pchlpc->address, acpi_pchlpc->size); + priv->base = ioremap(addr, size); if (!priv->base) goto free_priv; @@ -198,12 +195,6 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, goto iounmap_base; } - irq_handle = irq_domain_alloc_named_fwnode("lpcintc"); - if (!irq_handle) { - pr_err("Unable to allocate domain handle\n"); - goto iounmap_base; - } - /* * The LPC interrupt controller is a legacy i8259-compatible device, * which requires a static 1:1 mapping for IRQs 0-15. @@ -213,15 +204,10 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, &pch_lpc_domain_ops, priv); if (!priv->lpc_domain) { pr_err("Failed to create IRQ domain\n"); - goto free_irq_handle; + goto iounmap_base; } pch_lpc_reset(priv); - fwspec.fwnode = parent->fwnode; - fwspec.param[0] = acpi_pchlpc->cascade + GSI_MIN_PCH_IRQ; - fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH; - fwspec.param_count = 2; - parent_irq = irq_create_fwspec_mapping(&fwspec); irq_set_chained_handler_and_data(parent_irq, lpc_irq_dispatch, priv); pch_lpc_priv = priv; @@ -230,8 +216,6 @@ int __init pch_lpc_acpi_init(struct irq_domain *parent, return 0; -free_irq_handle: - irq_domain_free_fwnode(irq_handle); iounmap_base: iounmap(priv->base); free_priv: @@ -239,3 +223,36 @@ free_priv: return -ENOMEM; } + +int __init pch_lpc_acpi_init(struct irq_domain *parent, struct acpi_madt_lpc_pic *acpi_pchlpc) +{ + struct fwnode_handle *irq_handle; + struct irq_fwspec fwspec; + int parent_irq, ret; + + irq_handle = irq_domain_alloc_named_fwnode("lpcintc"); + if (!irq_handle) { + pr_err("Unable to allocate domain handle\n"); + return -ENOMEM; + } + + fwspec.fwnode = parent->fwnode; + fwspec.param[0] = acpi_pchlpc->cascade + GSI_MIN_PCH_IRQ; + fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH; + fwspec.param_count = 2; + parent_irq = irq_create_fwspec_mapping(&fwspec); + if (parent_irq <= 0) { + pr_err("Unable to map LPC parent interrupt\n"); + irq_domain_free_fwnode(irq_handle); + return -ENOMEM; + } + + ret = pch_lpc_init(acpi_pchlpc->address, acpi_pchlpc->size, irq_handle, parent_irq); + if (ret) { + irq_dispose_mapping(parent_irq); + irq_domain_free_fwnode(irq_handle); + return ret; + } + + return 0; +}