powerpc/xive: Introduce an IPI interrupt domain
authorCédric Le Goater <clg@kaod.org>
Wed, 31 Mar 2021 14:45:07 +0000 (16:45 +0200)
committerMichael Ellerman <mpe@ellerman.id.au>
Wed, 14 Apr 2021 13:04:14 +0000 (23:04 +1000)
The IPI interrupt is a special case of the XIVE IRQ domain. When
mapping and unmapping the interrupts in the Linux interrupt number
space, the HW interrupt number 0 (XIVE_IPI_HW_IRQ) is checked to
distinguish the IPI interrupt from other interrupts of the system.

Simplify the XIVE interrupt domain by introducing a specific domain
for the IPI.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210331144514.892250-3-clg@kaod.org
arch/powerpc/sysdev/xive/common.c

index 595310e056f4dec4d00e10bafd6f1f639e6ec9a3..e6abc38b8b40185a269cadafd7b55cb1497efac0 100644 (file)
@@ -1067,24 +1067,58 @@ static struct irq_chip xive_ipi_chip = {
        .irq_unmask = xive_ipi_do_nothing,
 };
 
-static void __init xive_request_ipi(void)
+/*
+ * IPIs are marked per-cpu. We use separate HW interrupts under the
+ * hood but associated with the same "linux" interrupt
+ */
+static int xive_ipi_irq_domain_map(struct irq_domain *h, unsigned int virq,
+                                  irq_hw_number_t hw)
 {
+       irq_set_chip_and_handler(virq, &xive_ipi_chip, handle_percpu_irq);
+       return 0;
+}
+
+static const struct irq_domain_ops xive_ipi_irq_domain_ops = {
+       .map = xive_ipi_irq_domain_map,
+};
+
+static int __init xive_request_ipi(void)
+{
+       struct fwnode_handle *fwnode;
+       struct irq_domain *ipi_domain;
        unsigned int virq;
+       int ret = -ENOMEM;
 
-       /*
-        * Initialization failed, move on, we might manage to
-        * reach the point where we display our errors before
-        * the system falls appart
-        */
-       if (!xive_irq_domain)
-               return;
+       fwnode = irq_domain_alloc_named_fwnode("XIVE-IPI");
+       if (!fwnode)
+               goto out;
+
+       ipi_domain = irq_domain_create_linear(fwnode, 1,
+                                             &xive_ipi_irq_domain_ops, NULL);
+       if (!ipi_domain)
+               goto out_free_fwnode;
 
        /* Initialize it */
-       virq = irq_create_mapping(xive_irq_domain, XIVE_IPI_HW_IRQ);
+       virq = irq_create_mapping(ipi_domain, XIVE_IPI_HW_IRQ);
+       if (!virq) {
+               ret = -EINVAL;
+               goto out_free_domain;
+       }
+
        xive_ipi_irq = virq;
 
-       WARN_ON(request_irq(virq, xive_muxed_ipi_action,
-                           IRQF_PERCPU | IRQF_NO_THREAD, "IPI", NULL));
+       ret = request_irq(virq, xive_muxed_ipi_action,
+                         IRQF_PERCPU | IRQF_NO_THREAD, "IPI", NULL);
+
+       WARN(ret < 0, "Failed to request IPI %d: %d\n", virq, ret);
+       return ret;
+
+out_free_domain:
+       irq_domain_remove(ipi_domain);
+out_free_fwnode:
+       irq_domain_free_fwnode(fwnode);
+out:
+       return ret;
 }
 
 static int xive_setup_cpu_ipi(unsigned int cpu)
@@ -1178,19 +1212,6 @@ static int xive_irq_domain_map(struct irq_domain *h, unsigned int virq,
         */
        irq_clear_status_flags(virq, IRQ_LEVEL);
 
-#ifdef CONFIG_SMP
-       /* IPIs are special and come up with HW number 0 */
-       if (hw == XIVE_IPI_HW_IRQ) {
-               /*
-                * IPIs are marked per-cpu. We use separate HW interrupts under
-                * the hood but associated with the same "linux" interrupt
-                */
-               irq_set_chip_and_handler(virq, &xive_ipi_chip,
-                                        handle_percpu_irq);
-               return 0;
-       }
-#endif
-
        rc = xive_irq_alloc_data(virq, hw);
        if (rc)
                return rc;
@@ -1202,15 +1223,7 @@ static int xive_irq_domain_map(struct irq_domain *h, unsigned int virq,
 
 static void xive_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
 {
-       struct irq_data *data = irq_get_irq_data(virq);
-       unsigned int hw_irq;
-
-       /* XXX Assign BAD number */
-       if (!data)
-               return;
-       hw_irq = (unsigned int)irqd_to_hwirq(data);
-       if (hw_irq != XIVE_IPI_HW_IRQ)
-               xive_irq_free_data(virq);
+       xive_irq_free_data(virq);
 }
 
 static int xive_irq_domain_xlate(struct irq_domain *h, struct device_node *ct,