irqchip/mips-gic: Remove device IRQ domain
authorPaul Burton <paul.burton@imgtec.com>
Thu, 20 Apr 2017 09:07:35 +0000 (10:07 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Thu, 20 Apr 2017 14:07:02 +0000 (16:07 +0200)
In commit c98c1822ee13 ("irqchip/mips-gic: Add device hierarchy domain")
Qais indicates that he felt having a separate device IRQ domain was
cleaner, but along with everyone else I'm aware of touching this driver
I disagree.

Remove the separate device IRQ domain so that we simply have the main
GIC IRQ domain used for devices, and an IPI IRQ domain as a child. The
logic for handling the device interrupts & IPIs is cleanly separated
into the appropriate domain ops, making it much easier to reason about
what the driver is doing than the previous approach where the 2 child
domains had to call up to their parent, which had to handle both types
of interrupt & had all sorts of weird & wonderful duplication or
outright clobbering of setup performed by multiple domains.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Link: http://lkml.kernel.org/r/1492679256-14513-3-git-send-email-matt.redfearn@imgtec.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
drivers/irqchip/irq-mips-gic.c

index db058e10df0073adc8aa13c8f1fa5447320e8108..eb448a1d57b43350205c1935b696739644c49199 100644 (file)
@@ -29,25 +29,12 @@ struct gic_pcpu_mask {
        DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
 };
 
-struct gic_irq_spec {
-       enum {
-               GIC_DEVICE,
-               GIC_IPI
-       } type;
-
-       union {
-               struct cpumask *ipimask;
-               unsigned int hwirq;
-       };
-};
-
 static unsigned long __gic_base_addr;
 
 static void __iomem *gic_base;
 static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
 static DEFINE_SPINLOCK(gic_lock);
 static struct irq_domain *gic_irq_domain;
-static struct irq_domain *gic_dev_domain;
 static struct irq_domain *gic_ipi_domain;
 static int gic_shared_intrs;
 static int gic_vpes;
@@ -694,132 +681,7 @@ static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
        return 0;
 }
 
-static int gic_setup_dev_chip(struct irq_domain *d, unsigned int virq,
-                             unsigned int hwirq)
-{
-       struct irq_chip *chip;
-       int err;
-
-       if (hwirq >= GIC_SHARED_HWIRQ_BASE) {
-               err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
-                                                   &gic_level_irq_controller,
-                                                   NULL);
-       } else {
-               switch (GIC_HWIRQ_TO_LOCAL(hwirq)) {
-               case GIC_LOCAL_INT_TIMER:
-               case GIC_LOCAL_INT_PERFCTR:
-               case GIC_LOCAL_INT_FDC:
-                       /*
-                        * HACK: These are all really percpu interrupts, but
-                        * the rest of the MIPS kernel code does not use the
-                        * percpu IRQ API for them.
-                        */
-                       chip = &gic_all_vpes_local_irq_controller;
-                       irq_set_handler(virq, handle_percpu_irq);
-                       break;
-
-               default:
-                       chip = &gic_local_irq_controller;
-                       irq_set_handler(virq, handle_percpu_devid_irq);
-                       irq_set_percpu_devid(virq);
-                       break;
-               }
-
-               err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
-                                                   chip, NULL);
-       }
-
-       return err;
-}
-
-static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq,
-                               unsigned int nr_irqs, void *arg)
-{
-       struct gic_irq_spec *spec = arg;
-       irq_hw_number_t hwirq, base_hwirq;
-       int cpu, ret, i;
-
-       if (spec->type == GIC_DEVICE) {
-               /* verify that shared irqs don't conflict with an IPI irq */
-               if ((spec->hwirq >= GIC_SHARED_HWIRQ_BASE) &&
-                   test_bit(GIC_HWIRQ_TO_SHARED(spec->hwirq), ipi_resrv))
-                       return -EBUSY;
-
-               return gic_setup_dev_chip(d, virq, spec->hwirq);
-       } else {
-               base_hwirq = find_first_bit(ipi_available, gic_shared_intrs);
-               if (base_hwirq == gic_shared_intrs) {
-                       return -ENOMEM;
-               }
-
-               /* check that we have enough space */
-               for (i = base_hwirq; i < nr_irqs; i++) {
-                       if (!test_bit(i, ipi_available))
-                               return -EBUSY;
-               }
-               bitmap_clear(ipi_available, base_hwirq, nr_irqs);
-
-               /* map the hwirq for each cpu consecutively */
-               i = 0;
-               for_each_cpu(cpu, spec->ipimask) {
-                       hwirq = GIC_SHARED_TO_HWIRQ(base_hwirq + i);
-
-                       ret = irq_domain_set_hwirq_and_chip(d, virq + i, hwirq,
-                                                           &gic_level_irq_controller,
-                                                           NULL);
-                       if (ret)
-                               goto error;
-
-                       irq_set_handler(virq + i, handle_level_irq);
-
-                       ret = gic_shared_irq_domain_map(d, virq + i, hwirq, cpu);
-                       if (ret)
-                               goto error;
-
-                       i++;
-               }
-
-               /*
-                * tell the parent about the base hwirq we allocated so it can
-                * set its own domain data
-                */
-               spec->hwirq = base_hwirq;
-       }
-
-       return 0;
-error:
-       bitmap_set(ipi_available, base_hwirq, nr_irqs);
-       return ret;
-}
-
-void gic_irq_domain_free(struct irq_domain *d, unsigned int virq,
-                        unsigned int nr_irqs)
-{
-       irq_hw_number_t base_hwirq;
-       struct irq_data *data;
-
-       data = irq_get_irq_data(virq);
-       if (!data)
-               return;
-
-       base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data));
-       bitmap_set(ipi_available, base_hwirq, nr_irqs);
-}
-
-int gic_irq_domain_match(struct irq_domain *d, struct device_node *node,
-                        enum irq_domain_bus_token bus_token)
-{
-       /* this domain should'nt be accessed directly */
-       return 0;
-}
-
-static const struct irq_domain_ops gic_irq_domain_ops = {
-       .alloc = gic_irq_domain_alloc,
-       .free = gic_irq_domain_free,
-       .match = gic_irq_domain_match,
-};
-
-static int gic_dev_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
                                const u32 *intspec, unsigned int intsize,
                                irq_hw_number_t *out_hwirq,
                                unsigned int *out_type)
@@ -838,58 +700,73 @@ static int gic_dev_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
        return 0;
 }
 
-static int gic_dev_domain_alloc(struct irq_domain *d, unsigned int virq,
+static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq,
                                unsigned int nr_irqs, void *arg)
 {
        struct irq_fwspec *fwspec = arg;
-       struct gic_irq_spec spec = {
-               .type = GIC_DEVICE,
-       };
-       int i, ret;
+       irq_hw_number_t hwirq;
+       int err;
 
-       if (fwspec->param[0] == GIC_SHARED)
-               spec.hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]);
-       else
-               spec.hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]);
+       if (fwspec->param[0] == GIC_SHARED) {
+               hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]);
 
-       ret = irq_domain_alloc_irqs_parent(d, virq, nr_irqs, &spec);
-       if (ret)
-               return ret;
+               /* verify that shared irqs don't conflict with an IPI irq */
+               if (test_bit(GIC_HWIRQ_TO_SHARED(hwirq), ipi_resrv))
+                       return -EBUSY;
 
-       for (i = 0; i < nr_irqs; i++) {
-               ret = gic_setup_dev_chip(d, virq + i, spec.hwirq + i);
-               if (ret)
-                       goto error;
+               err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
+                                                   &gic_level_irq_controller,
+                                                   NULL);
+               if (err)
+                       return err;
+
+               return gic_shared_irq_domain_map(d, virq, hwirq, 0);
        }
 
-       return 0;
+       hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]);
 
-error:
-       irq_domain_free_irqs_parent(d, virq, nr_irqs);
-       return ret;
-}
+       switch (GIC_HWIRQ_TO_LOCAL(hwirq)) {
+       case GIC_LOCAL_INT_TIMER:
+       case GIC_LOCAL_INT_PERFCTR:
+       case GIC_LOCAL_INT_FDC:
+               /*
+                * HACK: These are all really percpu interrupts, but
+                * the rest of the MIPS kernel code does not use the
+                * percpu IRQ API for them.
+                */
+               err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
+                                                   &gic_all_vpes_local_irq_controller,
+                                                   NULL);
+               if (err)
+                       return err;
 
-void gic_dev_domain_free(struct irq_domain *d, unsigned int virq,
-                        unsigned int nr_irqs)
-{
-       /* no real allocation is done for dev irqs, so no need to free anything */
-       return;
+               irq_set_handler(virq, handle_percpu_irq);
+               break;
+
+       default:
+               err = irq_domain_set_hwirq_and_chip(d, virq, hwirq,
+                                                   &gic_local_irq_controller,
+                                                   NULL);
+               if (err)
+                       return err;
+
+               irq_set_handler(virq, handle_percpu_devid_irq);
+               irq_set_percpu_devid(virq);
+               break;
+       }
+
+       return gic_local_irq_domain_map(d, virq, hwirq);
 }
 
-static void gic_dev_domain_activate(struct irq_domain *domain,
-                                   struct irq_data *d)
+void gic_irq_domain_free(struct irq_domain *d, unsigned int virq,
+                        unsigned int nr_irqs)
 {
-       if (GIC_HWIRQ_TO_LOCAL(d->hwirq) < GIC_NUM_LOCAL_INTRS)
-               gic_local_irq_domain_map(domain, d->irq, d->hwirq);
-       else
-               gic_shared_irq_domain_map(domain, d->irq, d->hwirq, 0);
 }
 
-static struct irq_domain_ops gic_dev_domain_ops = {
-       .xlate = gic_dev_domain_xlate,
-       .alloc = gic_dev_domain_alloc,
-       .free = gic_dev_domain_free,
-       .activate = gic_dev_domain_activate,
+static const struct irq_domain_ops gic_irq_domain_ops = {
+       .xlate = gic_irq_domain_xlate,
+       .alloc = gic_irq_domain_alloc,
+       .free = gic_irq_domain_free,
 };
 
 static int gic_ipi_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
@@ -911,20 +788,32 @@ static int gic_ipi_domain_alloc(struct irq_domain *d, unsigned int virq,
                                unsigned int nr_irqs, void *arg)
 {
        struct cpumask *ipimask = arg;
-       struct gic_irq_spec spec = {
-               .type = GIC_IPI,
-               .ipimask = ipimask
-       };
-       int ret, i;
+       irq_hw_number_t hwirq, base_hwirq;
+       int cpu, ret, i;
+
+       base_hwirq = find_first_bit(ipi_available, gic_shared_intrs);
+       if (base_hwirq == gic_shared_intrs)
+               return -ENOMEM;
 
-       ret = irq_domain_alloc_irqs_parent(d, virq, nr_irqs, &spec);
-       if (ret)
-               return ret;
+       /* check that we have enough space */
+       for (i = base_hwirq; i < nr_irqs; i++) {
+               if (!test_bit(i, ipi_available))
+                       return -EBUSY;
+       }
+       bitmap_clear(ipi_available, base_hwirq, nr_irqs);
+
+       /* map the hwirq for each cpu consecutively */
+       i = 0;
+       for_each_cpu(cpu, ipimask) {
+               hwirq = GIC_SHARED_TO_HWIRQ(base_hwirq + i);
+
+               ret = irq_domain_set_hwirq_and_chip(d, virq + i, hwirq,
+                                                   &gic_edge_irq_controller,
+                                                   NULL);
+               if (ret)
+                       goto error;
 
-       /* the parent should have set spec.hwirq to the base_hwirq it allocated */
-       for (i = 0; i < nr_irqs; i++) {
-               ret = irq_domain_set_hwirq_and_chip(d, virq + i,
-                                                   GIC_SHARED_TO_HWIRQ(spec.hwirq + i),
+               ret = irq_domain_set_hwirq_and_chip(d->parent, virq + i, hwirq,
                                                    &gic_edge_irq_controller,
                                                    NULL);
                if (ret)
@@ -933,18 +822,32 @@ static int gic_ipi_domain_alloc(struct irq_domain *d, unsigned int virq,
                ret = irq_set_irq_type(virq + i, IRQ_TYPE_EDGE_RISING);
                if (ret)
                        goto error;
+
+               ret = gic_shared_irq_domain_map(d, virq + i, hwirq, cpu);
+               if (ret)
+                       goto error;
+
+               i++;
        }
 
        return 0;
 error:
-       irq_domain_free_irqs_parent(d, virq, nr_irqs);
+       bitmap_set(ipi_available, base_hwirq, nr_irqs);
        return ret;
 }
 
 void gic_ipi_domain_free(struct irq_domain *d, unsigned int virq,
                         unsigned int nr_irqs)
 {
-       irq_domain_free_irqs_parent(d, virq, nr_irqs);
+       irq_hw_number_t base_hwirq;
+       struct irq_data *data;
+
+       data = irq_get_irq_data(virq);
+       if (!data)
+               return;
+
+       base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data));
+       bitmap_set(ipi_available, base_hwirq, nr_irqs);
 }
 
 int gic_ipi_domain_match(struct irq_domain *d, struct device_node *node,
@@ -1072,13 +975,6 @@ static void __init __gic_init(unsigned long gic_base_addr,
                panic("Failed to add GIC IRQ domain");
        gic_irq_domain->name = "mips-gic-irq";
 
-       gic_dev_domain = irq_domain_add_hierarchy(gic_irq_domain, 0,
-                                                 GIC_NUM_LOCAL_INTRS + gic_shared_intrs,
-                                                 node, &gic_dev_domain_ops, NULL);
-       if (!gic_dev_domain)
-               panic("Failed to add GIC DEV domain");
-       gic_dev_domain->name = "mips-gic-dev";
-
        gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain,
                                                  IRQ_DOMAIN_FLAG_IPI_PER_CPU,
                                                  GIC_NUM_LOCAL_INTRS + gic_shared_intrs,