]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
irqchip/loongson-pch-lpc: Extract non-ACPI-related code from ACPI init
authorIcenowy Zheng <zhengxingda@iscas.ac.cn>
Sat, 21 Mar 2026 09:20:30 +0000 (17:20 +0800)
committerThomas Gleixner <tglx@kernel.org>
Thu, 26 Mar 2026 15:15:03 +0000 (16:15 +0100)
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 <jiaxun.yang@flygoat.com>
Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Icenowy Zheng <zhengxingda@iscas.ac.cn>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Huacai Chen <chenhuacai@loongson.cn>
Link: https://patch.msgid.link/20260321092032.3502701-5-zhengxingda@iscas.ac.cn
drivers/irqchip/irq-loongson-pch-lpc.c

index 3ad46ec94e3c08eaad52dea09f9036c13a16614b..2bb6659e9a93c42cfa54345e8ffa1bfe75c3efb3 100644 (file)
@@ -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;
+}