]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
irqchip/loongson-eiointc: Route interrupt parsed from bios table
authorBibo Mao <maobibo@loongson.cn>
Mon, 4 Aug 2025 08:19:45 +0000 (16:19 +0800)
committerThomas Gleixner <tglx@linutronix.de>
Sun, 24 Aug 2025 10:51:04 +0000 (12:51 +0200)
Interrupt controller eiointc routes interrupts to CPU interface IP0 - IP7.

It is currently hard-coded that eiointc routes interrupts to the CPU
starting from IP1, but it should base that decision on the parent
interrupt, which is provided by ACPI or DTS.

Retrieve the parent's hardware interrupt number and store it in the
descriptor of the eointc instance, so that the routing function can utilize
it for the correct route settings.

[ tglx: Massaged change log ]

Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20250804081946.1456573-2-maobibo@loongson.cn
drivers/irqchip/irq-loongson-eiointc.c

index b2860eb2d32c55415de96ecf4f34ab1f5eb6c3d6..baa406904de55a3c18b5d9ec152370fdede2ca67 100644 (file)
@@ -68,6 +68,7 @@ struct eiointc_priv {
        struct fwnode_handle    *domain_handle;
        struct irq_domain       *eiointc_domain;
        int                     flags;
+       irq_hw_number_t         parent_hwirq;
 };
 
 static struct eiointc_priv *eiointc_priv[MAX_IO_PICS];
@@ -211,7 +212,12 @@ static int eiointc_router_init(unsigned int cpu)
                }
 
                for (i = 0; i < eiointc_priv[0]->vec_count / 32 / 4; i++) {
-                       bit = BIT(1 + index); /* Route to IP[1 + index] */
+                       /*
+                        * Route to interrupt pin, relative offset used here
+                        * Offset 0 means routing to IP0 and so on
+                        * Every 32 vector routing to one interrupt pin
+                        */
+                       bit = BIT(eiointc_priv[index]->parent_hwirq - INT_HWI0);
                        data = bit | (bit << 8) | (bit << 16) | (bit << 24);
                        iocsr_write32(data, EIOINTC_REG_IPMAP + i * 4);
                }
@@ -495,7 +501,7 @@ int __init eiointc_acpi_init(struct irq_domain *parent,
 
        priv->vec_count = VEC_COUNT;
        priv->node = acpi_eiointc->node;
-
+       priv->parent_hwirq = acpi_eiointc->cascade;
        parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade);
 
        ret = eiointc_init(priv, parent_irq, acpi_eiointc->node_map);
@@ -527,8 +533,9 @@ out_free_priv:
 static int __init eiointc_of_init(struct device_node *of_node,
                                  struct device_node *parent)
 {
-       int parent_irq, ret;
        struct eiointc_priv *priv;
+       struct irq_data *irq_data;
+       int parent_irq, ret;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -544,6 +551,12 @@ static int __init eiointc_of_init(struct device_node *of_node,
        if (ret < 0)
                goto out_free_priv;
 
+       irq_data = irq_get_irq_data(parent_irq);
+       if (!irq_data) {
+               ret = -ENODEV;
+               goto out_free_priv;
+       }
+
        /*
         * In particular, the number of devices supported by the LS2K0500
         * extended I/O interrupt vector is 128.
@@ -552,7 +565,7 @@ static int __init eiointc_of_init(struct device_node *of_node,
                priv->vec_count = 128;
        else
                priv->vec_count = VEC_COUNT;
-
+       priv->parent_hwirq = irqd_to_hwirq(irq_data);
        priv->node = 0;
        priv->domain_handle = of_fwnode_handle(of_node);