* [PATCH 0/3] irqchip: mips-gic: Remove dev domain & fixes @ 2017-04-20 9:07 ` Matt Redfearn 0 siblings, 0 replies; 11+ messages in thread From: Matt Redfearn @ 2017-04-20 9:07 UTC (permalink / raw) To: Thomas Gleixner, Marc Zyngier Cc: linux-mips, Ralf Baechle, Matt Redfearn, Jason Cooper, linux-kernel This series fixes a couple of issues with the MIPS GIC driver and also vastly simplifies it by removing the separate dev domain. The first patch fixes a long standing issue with IPI reservation. The second patch reqorks the driver to simplify it by removing the overly complex device IRQ domain. The third fixes an issue seen in v4.11 which broke the Malta platforms legacy IRQ controller. These patches have been tested on multiple MIPS platforms including Malta, Boston, Ci40 and SEAD3. Matt Redfearn (1): irqchip: mips-gic: Replace static map with dynamic Paul Burton (2): irqchip: mips-gic: Separate IPI reservation & usage tracking irqchip: mips-gic: Remove device IRQ domain drivers/irqchip/irq-mips-gic.c | 338 +++++++++++++---------------------------- 1 file changed, 106 insertions(+), 232 deletions(-) -- 2.7.4 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 0/3] irqchip: mips-gic: Remove dev domain & fixes @ 2017-04-20 9:07 ` Matt Redfearn 0 siblings, 0 replies; 11+ messages in thread From: Matt Redfearn @ 2017-04-20 9:07 UTC (permalink / raw) To: Thomas Gleixner, Marc Zyngier Cc: linux-mips, Ralf Baechle, Matt Redfearn, Jason Cooper, linux-kernel This series fixes a couple of issues with the MIPS GIC driver and also vastly simplifies it by removing the separate dev domain. The first patch fixes a long standing issue with IPI reservation. The second patch reqorks the driver to simplify it by removing the overly complex device IRQ domain. The third fixes an issue seen in v4.11 which broke the Malta platforms legacy IRQ controller. These patches have been tested on multiple MIPS platforms including Malta, Boston, Ci40 and SEAD3. Matt Redfearn (1): irqchip: mips-gic: Replace static map with dynamic Paul Burton (2): irqchip: mips-gic: Separate IPI reservation & usage tracking irqchip: mips-gic: Remove device IRQ domain drivers/irqchip/irq-mips-gic.c | 338 +++++++++++++---------------------------- 1 file changed, 106 insertions(+), 232 deletions(-) -- 2.7.4 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/3] irqchip: mips-gic: Separate IPI reservation & usage tracking @ 2017-04-20 9:07 ` Matt Redfearn 0 siblings, 0 replies; 11+ messages in thread From: Matt Redfearn @ 2017-04-20 9:07 UTC (permalink / raw) To: Thomas Gleixner, Marc Zyngier Cc: linux-mips, Ralf Baechle, Paul Burton, Matt Redfearn, Jason Cooper, linux-kernel From: Paul Burton <paul.burton@imgtec.com> Since commit 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") introduced the GIC IPI IRQ domain we have tracked both reservation of interrupts & their use with a single bitmap - ipi_resrv. If an interrupt is reserved for use as an IPI but not actually in use then the appropriate bit is set in ipi_resrv. If an interrupt is either not reserved for use as an IPI or has been allocated as one then the appropriate bit is clear in ipi_resrv. Unfortunately this means that checking whether a bit is set in ipi_resrv to prevent IPI interrupts being allocated for use with a device is broken, because if the interrupt has been allocated as an IPI first then its bit will be clear. Fix this by separating the tracking of IPI reservation & usage, introducing a separate ipi_available bitmap for the latter. This means that ipi_resrv will now always have bits set corresponding to all interrupts reserved for use as IPIs, whether or not they have been allocated yet, and therefore that checking it when allocating device interrupts works as expected. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Fixes: 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com> --- drivers/irqchip/irq-mips-gic.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index cd20df12d63d..db058e10df00 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -55,6 +55,7 @@ static unsigned int gic_cpu_pin; static unsigned int timer_cpu_pin; static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS); +DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS); static void __gic_irq_dispatch(void); @@ -746,17 +747,17 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return gic_setup_dev_chip(d, virq, spec->hwirq); } else { - base_hwirq = find_first_bit(ipi_resrv, gic_shared_intrs); + 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_resrv)) + if (!test_bit(i, ipi_available)) return -EBUSY; } - bitmap_clear(ipi_resrv, base_hwirq, nr_irqs); + bitmap_clear(ipi_available, base_hwirq, nr_irqs); /* map the hwirq for each cpu consecutively */ i = 0; @@ -787,7 +788,7 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return 0; error: - bitmap_set(ipi_resrv, base_hwirq, nr_irqs); + bitmap_set(ipi_available, base_hwirq, nr_irqs); return ret; } @@ -802,7 +803,7 @@ void gic_irq_domain_free(struct irq_domain *d, unsigned int virq, return; base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data)); - bitmap_set(ipi_resrv, base_hwirq, nr_irqs); + bitmap_set(ipi_available, base_hwirq, nr_irqs); } int gic_irq_domain_match(struct irq_domain *d, struct device_node *node, @@ -1098,6 +1099,7 @@ static void __init __gic_init(unsigned long gic_base_addr, 2 * gic_vpes); } + bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS); gic_basic_init(); gic_map_interrupts(node); } -- 2.7.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 1/3] irqchip: mips-gic: Separate IPI reservation & usage tracking @ 2017-04-20 9:07 ` Matt Redfearn 0 siblings, 0 replies; 11+ messages in thread From: Matt Redfearn @ 2017-04-20 9:07 UTC (permalink / raw) To: Thomas Gleixner, Marc Zyngier Cc: linux-mips, Ralf Baechle, Paul Burton, Matt Redfearn, Jason Cooper, linux-kernel From: Paul Burton <paul.burton@imgtec.com> Since commit 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") introduced the GIC IPI IRQ domain we have tracked both reservation of interrupts & their use with a single bitmap - ipi_resrv. If an interrupt is reserved for use as an IPI but not actually in use then the appropriate bit is set in ipi_resrv. If an interrupt is either not reserved for use as an IPI or has been allocated as one then the appropriate bit is clear in ipi_resrv. Unfortunately this means that checking whether a bit is set in ipi_resrv to prevent IPI interrupts being allocated for use with a device is broken, because if the interrupt has been allocated as an IPI first then its bit will be clear. Fix this by separating the tracking of IPI reservation & usage, introducing a separate ipi_available bitmap for the latter. This means that ipi_resrv will now always have bits set corresponding to all interrupts reserved for use as IPIs, whether or not they have been allocated yet, and therefore that checking it when allocating device interrupts works as expected. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Fixes: 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com> --- drivers/irqchip/irq-mips-gic.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index cd20df12d63d..db058e10df00 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -55,6 +55,7 @@ static unsigned int gic_cpu_pin; static unsigned int timer_cpu_pin; static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS); +DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS); static void __gic_irq_dispatch(void); @@ -746,17 +747,17 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return gic_setup_dev_chip(d, virq, spec->hwirq); } else { - base_hwirq = find_first_bit(ipi_resrv, gic_shared_intrs); + 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_resrv)) + if (!test_bit(i, ipi_available)) return -EBUSY; } - bitmap_clear(ipi_resrv, base_hwirq, nr_irqs); + bitmap_clear(ipi_available, base_hwirq, nr_irqs); /* map the hwirq for each cpu consecutively */ i = 0; @@ -787,7 +788,7 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return 0; error: - bitmap_set(ipi_resrv, base_hwirq, nr_irqs); + bitmap_set(ipi_available, base_hwirq, nr_irqs); return ret; } @@ -802,7 +803,7 @@ void gic_irq_domain_free(struct irq_domain *d, unsigned int virq, return; base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data)); - bitmap_set(ipi_resrv, base_hwirq, nr_irqs); + bitmap_set(ipi_available, base_hwirq, nr_irqs); } int gic_irq_domain_match(struct irq_domain *d, struct device_node *node, @@ -1098,6 +1099,7 @@ static void __init __gic_init(unsigned long gic_base_addr, 2 * gic_vpes); } + bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS); gic_basic_init(); gic_map_interrupts(node); } -- 2.7.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [tip:irq/core] irqchip/mips-gic: Separate IPI reservation & usage tracking 2017-04-20 9:07 ` Matt Redfearn (?) @ 2017-04-20 14:09 ` tip-bot for Paul Burton -1 siblings, 0 replies; 11+ messages in thread From: tip-bot for Paul Burton @ 2017-04-20 14:09 UTC (permalink / raw) To: linux-tip-commits Cc: marc.zyngier, tglx, hpa, jason, matt.redfearn, ralf, linux-kernel, mingo, paul.burton Commit-ID: f8dcd9e81797ae24acc44c84f0eb3b9e6cee9791 Gitweb: http://git.kernel.org/tip/f8dcd9e81797ae24acc44c84f0eb3b9e6cee9791 Author: Paul Burton <paul.burton@imgtec.com> AuthorDate: Thu, 20 Apr 2017 10:07:34 +0100 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Thu, 20 Apr 2017 16:07:02 +0200 irqchip/mips-gic: Separate IPI reservation & usage tracking Since commit 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") introduced the GIC IPI IRQ domain we have tracked both reservation of interrupts & their use with a single bitmap - ipi_resrv. If an interrupt is reserved for use as an IPI but not actually in use then the appropriate bit is set in ipi_resrv. If an interrupt is either not reserved for use as an IPI or has been allocated as one then the appropriate bit is clear in ipi_resrv. Unfortunately this means that checking whether a bit is set in ipi_resrv to prevent IPI interrupts being allocated for use with a device is broken, because if the interrupt has been allocated as an IPI first then its bit will be clear. Fix this by separating the tracking of IPI reservation & usage, introducing a separate ipi_available bitmap for the latter. This means that ipi_resrv will now always have bits set corresponding to all interrupts reserved for use as IPIs, whether or not they have been allocated yet, and therefore that checking it when allocating device interrupts works as expected. Fixes: 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") 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-2-git-send-email-matt.redfearn@imgtec.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- drivers/irqchip/irq-mips-gic.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index cd20df1..db058e1 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -55,6 +55,7 @@ static unsigned int gic_cpu_pin; static unsigned int timer_cpu_pin; static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS); +DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS); static void __gic_irq_dispatch(void); @@ -746,17 +747,17 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return gic_setup_dev_chip(d, virq, spec->hwirq); } else { - base_hwirq = find_first_bit(ipi_resrv, gic_shared_intrs); + 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_resrv)) + if (!test_bit(i, ipi_available)) return -EBUSY; } - bitmap_clear(ipi_resrv, base_hwirq, nr_irqs); + bitmap_clear(ipi_available, base_hwirq, nr_irqs); /* map the hwirq for each cpu consecutively */ i = 0; @@ -787,7 +788,7 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return 0; error: - bitmap_set(ipi_resrv, base_hwirq, nr_irqs); + bitmap_set(ipi_available, base_hwirq, nr_irqs); return ret; } @@ -802,7 +803,7 @@ void gic_irq_domain_free(struct irq_domain *d, unsigned int virq, return; base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data)); - bitmap_set(ipi_resrv, base_hwirq, nr_irqs); + bitmap_set(ipi_available, base_hwirq, nr_irqs); } int gic_irq_domain_match(struct irq_domain *d, struct device_node *node, @@ -1098,6 +1099,7 @@ static void __init __gic_init(unsigned long gic_base_addr, 2 * gic_vpes); } + bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS); gic_basic_init(); gic_map_interrupts(node); } ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/3] irqchip: mips-gic: Remove device IRQ domain @ 2017-04-20 9:07 ` Matt Redfearn 0 siblings, 0 replies; 11+ messages in thread From: Matt Redfearn @ 2017-04-20 9:07 UTC (permalink / raw) To: Thomas Gleixner, Marc Zyngier Cc: linux-mips, Ralf Baechle, Paul Burton, Matt Redfearn, Jason Cooper, linux-kernel From: Paul Burton <paul.burton@imgtec.com> 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> --- drivers/irqchip/irq-mips-gic.c | 290 +++++++++++++---------------------------- 1 file changed, 93 insertions(+), 197 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index db058e10df00..eb448a1d57b4 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -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, -- 2.7.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/3] irqchip: mips-gic: Remove device IRQ domain @ 2017-04-20 9:07 ` Matt Redfearn 0 siblings, 0 replies; 11+ messages in thread From: Matt Redfearn @ 2017-04-20 9:07 UTC (permalink / raw) To: Thomas Gleixner, Marc Zyngier Cc: linux-mips, Ralf Baechle, Paul Burton, Matt Redfearn, Jason Cooper, linux-kernel From: Paul Burton <paul.burton@imgtec.com> 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> --- drivers/irqchip/irq-mips-gic.c | 290 +++++++++++++---------------------------- 1 file changed, 93 insertions(+), 197 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index db058e10df00..eb448a1d57b4 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -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, -- 2.7.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [tip:irq/core] irqchip/mips-gic: Remove device IRQ domain 2017-04-20 9:07 ` Matt Redfearn (?) @ 2017-04-20 14:10 ` tip-bot for Paul Burton -1 siblings, 0 replies; 11+ messages in thread From: tip-bot for Paul Burton @ 2017-04-20 14:10 UTC (permalink / raw) To: linux-tip-commits Cc: paul.burton, linux-kernel, ralf, matt.redfearn, hpa, marc.zyngier, jason, mingo, tglx Commit-ID: b87281e7f205eda08c911fdacd27d4d2f01daa09 Gitweb: http://git.kernel.org/tip/b87281e7f205eda08c911fdacd27d4d2f01daa09 Author: Paul Burton <paul.burton@imgtec.com> AuthorDate: Thu, 20 Apr 2017 10:07:35 +0100 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Thu, 20 Apr 2017 16:07:02 +0200 irqchip/mips-gic: Remove device IRQ domain 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 | 290 +++++++++++++---------------------------- 1 file changed, 93 insertions(+), 197 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index db058e1..eb448a1 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -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, ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/3] irqchip: mips-gic: Replace static map with dynamic @ 2017-04-20 9:07 ` Matt Redfearn 0 siblings, 0 replies; 11+ messages in thread From: Matt Redfearn @ 2017-04-20 9:07 UTC (permalink / raw) To: Thomas Gleixner, Marc Zyngier Cc: linux-mips, Ralf Baechle, Matt Redfearn, Jason Cooper, linux-kernel Commit 4cfffcfa5106 ("irqchip/mips-gic: Fix local interrupts") fixed local interrupts by creating virq mappings for them all at startup. Unfortunately this change broke legacy IRQ controllers in the same system, such as the i8259 on the Malta platform, as it allocates virq numbers that were expected to be available for the legacy controller. Instead of creating the mappings statically when the GIC is probed, re-introduce the irq domain .map function, removed by commit e875bd66dfb ("irqchip/mips-gic: Fix local interrupts") and use it to set up the irq handler and chip. Since a good deal of the required functionality is already implemented by gic_irq_domain_alloc, repurpose that function for gic_irq_domain_map and add a new gic_irq_domain_alloc which wraps gic_irq_domain_map with the necessary conversion. This change fixes the legacy interrupt controller of the Malta platform without breaking the perf interrupt fixed by commit e875bd66dfb ("irqchip/mips-gic: Fix local interrupts"). Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com> --- drivers/irqchip/irq-mips-gic.c | 60 +++++++++++++----------------------------- 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index eb448a1d57b4..eb7fbe159963 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -700,16 +700,12 @@ static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, return 0; } -static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, - unsigned int nr_irqs, void *arg) +static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) { - struct irq_fwspec *fwspec = arg; - irq_hw_number_t hwirq; int err; - if (fwspec->param[0] == GIC_SHARED) { - hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]); - + if (hwirq >= GIC_SHARED_HWIRQ_BASE) { /* verify that shared irqs don't conflict with an IPI irq */ if (test_bit(GIC_HWIRQ_TO_SHARED(hwirq), ipi_resrv)) return -EBUSY; @@ -723,8 +719,6 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return gic_shared_irq_domain_map(d, virq, hwirq, 0); } - hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]); - switch (GIC_HWIRQ_TO_LOCAL(hwirq)) { case GIC_LOCAL_INT_TIMER: case GIC_LOCAL_INT_PERFCTR: @@ -758,6 +752,20 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return gic_local_irq_domain_map(d, virq, hwirq); } +static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, + unsigned int nr_irqs, void *arg) +{ + struct irq_fwspec *fwspec = arg; + irq_hw_number_t hwirq; + + if (fwspec->param[0] == GIC_SHARED) + hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]); + else + hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]); + + return gic_irq_domain_map(d, virq, hwirq); +} + void gic_irq_domain_free(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs) { @@ -767,6 +775,7 @@ 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, + .map = gic_irq_domain_map, }; static int gic_ipi_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, @@ -872,38 +881,6 @@ static struct irq_domain_ops gic_ipi_domain_ops = { .match = gic_ipi_domain_match, }; -static void __init gic_map_single_int(struct device_node *node, - unsigned int irq) -{ - unsigned int linux_irq; - struct irq_fwspec local_int_fwspec = { - .fwnode = &node->fwnode, - .param_count = 3, - .param = { - [0] = GIC_LOCAL, - [1] = irq, - [2] = IRQ_TYPE_NONE, - }, - }; - - if (!gic_local_irq_is_routable(irq)) - return; - - linux_irq = irq_create_fwspec_mapping(&local_int_fwspec); - WARN_ON(!linux_irq); -} - -static void __init gic_map_interrupts(struct device_node *node) -{ - gic_map_single_int(node, GIC_LOCAL_INT_WD); - gic_map_single_int(node, GIC_LOCAL_INT_COMPARE); - gic_map_single_int(node, GIC_LOCAL_INT_TIMER); - gic_map_single_int(node, GIC_LOCAL_INT_PERFCTR); - gic_map_single_int(node, GIC_LOCAL_INT_SWINT0); - gic_map_single_int(node, GIC_LOCAL_INT_SWINT1); - gic_map_single_int(node, GIC_LOCAL_INT_FDC); -} - static void __init __gic_init(unsigned long gic_base_addr, unsigned long gic_addrspace_size, unsigned int cpu_vec, unsigned int irqbase, @@ -997,7 +974,6 @@ static void __init __gic_init(unsigned long gic_base_addr, bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS); gic_basic_init(); - gic_map_interrupts(node); } void __init gic_init(unsigned long gic_base_addr, -- 2.7.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/3] irqchip: mips-gic: Replace static map with dynamic @ 2017-04-20 9:07 ` Matt Redfearn 0 siblings, 0 replies; 11+ messages in thread From: Matt Redfearn @ 2017-04-20 9:07 UTC (permalink / raw) To: Thomas Gleixner, Marc Zyngier Cc: linux-mips, Ralf Baechle, Matt Redfearn, Jason Cooper, linux-kernel Commit 4cfffcfa5106 ("irqchip/mips-gic: Fix local interrupts") fixed local interrupts by creating virq mappings for them all at startup. Unfortunately this change broke legacy IRQ controllers in the same system, such as the i8259 on the Malta platform, as it allocates virq numbers that were expected to be available for the legacy controller. Instead of creating the mappings statically when the GIC is probed, re-introduce the irq domain .map function, removed by commit e875bd66dfb ("irqchip/mips-gic: Fix local interrupts") and use it to set up the irq handler and chip. Since a good deal of the required functionality is already implemented by gic_irq_domain_alloc, repurpose that function for gic_irq_domain_map and add a new gic_irq_domain_alloc which wraps gic_irq_domain_map with the necessary conversion. This change fixes the legacy interrupt controller of the Malta platform without breaking the perf interrupt fixed by commit e875bd66dfb ("irqchip/mips-gic: Fix local interrupts"). Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com> --- drivers/irqchip/irq-mips-gic.c | 60 +++++++++++++----------------------------- 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index eb448a1d57b4..eb7fbe159963 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -700,16 +700,12 @@ static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, return 0; } -static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, - unsigned int nr_irqs, void *arg) +static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) { - struct irq_fwspec *fwspec = arg; - irq_hw_number_t hwirq; int err; - if (fwspec->param[0] == GIC_SHARED) { - hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]); - + if (hwirq >= GIC_SHARED_HWIRQ_BASE) { /* verify that shared irqs don't conflict with an IPI irq */ if (test_bit(GIC_HWIRQ_TO_SHARED(hwirq), ipi_resrv)) return -EBUSY; @@ -723,8 +719,6 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return gic_shared_irq_domain_map(d, virq, hwirq, 0); } - hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]); - switch (GIC_HWIRQ_TO_LOCAL(hwirq)) { case GIC_LOCAL_INT_TIMER: case GIC_LOCAL_INT_PERFCTR: @@ -758,6 +752,20 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return gic_local_irq_domain_map(d, virq, hwirq); } +static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, + unsigned int nr_irqs, void *arg) +{ + struct irq_fwspec *fwspec = arg; + irq_hw_number_t hwirq; + + if (fwspec->param[0] == GIC_SHARED) + hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]); + else + hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]); + + return gic_irq_domain_map(d, virq, hwirq); +} + void gic_irq_domain_free(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs) { @@ -767,6 +775,7 @@ 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, + .map = gic_irq_domain_map, }; static int gic_ipi_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, @@ -872,38 +881,6 @@ static struct irq_domain_ops gic_ipi_domain_ops = { .match = gic_ipi_domain_match, }; -static void __init gic_map_single_int(struct device_node *node, - unsigned int irq) -{ - unsigned int linux_irq; - struct irq_fwspec local_int_fwspec = { - .fwnode = &node->fwnode, - .param_count = 3, - .param = { - [0] = GIC_LOCAL, - [1] = irq, - [2] = IRQ_TYPE_NONE, - }, - }; - - if (!gic_local_irq_is_routable(irq)) - return; - - linux_irq = irq_create_fwspec_mapping(&local_int_fwspec); - WARN_ON(!linux_irq); -} - -static void __init gic_map_interrupts(struct device_node *node) -{ - gic_map_single_int(node, GIC_LOCAL_INT_WD); - gic_map_single_int(node, GIC_LOCAL_INT_COMPARE); - gic_map_single_int(node, GIC_LOCAL_INT_TIMER); - gic_map_single_int(node, GIC_LOCAL_INT_PERFCTR); - gic_map_single_int(node, GIC_LOCAL_INT_SWINT0); - gic_map_single_int(node, GIC_LOCAL_INT_SWINT1); - gic_map_single_int(node, GIC_LOCAL_INT_FDC); -} - static void __init __gic_init(unsigned long gic_base_addr, unsigned long gic_addrspace_size, unsigned int cpu_vec, unsigned int irqbase, @@ -997,7 +974,6 @@ static void __init __gic_init(unsigned long gic_base_addr, bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS); gic_basic_init(); - gic_map_interrupts(node); } void __init gic_init(unsigned long gic_base_addr, -- 2.7.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [tip:irq/core] irqchip/mips-gic: Replace static map with dynamic 2017-04-20 9:07 ` Matt Redfearn (?) @ 2017-04-20 14:10 ` tip-bot for Matt Redfearn -1 siblings, 0 replies; 11+ messages in thread From: tip-bot for Matt Redfearn @ 2017-04-20 14:10 UTC (permalink / raw) To: linux-tip-commits Cc: marc.zyngier, hpa, tglx, mingo, ralf, linux-kernel, jason, matt.redfearn Commit-ID: 8ada00a650ec7ec639fb72964f0e4eba928786f8 Gitweb: http://git.kernel.org/tip/8ada00a650ec7ec639fb72964f0e4eba928786f8 Author: Matt Redfearn <matt.redfearn@imgtec.com> AuthorDate: Thu, 20 Apr 2017 10:07:36 +0100 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Thu, 20 Apr 2017 16:07:02 +0200 irqchip/mips-gic: Replace static map with dynamic Commit 4cfffcfa5106 ("irqchip/mips-gic: Fix local interrupts") fixed local interrupts by creating virq mappings for them all at startup. Unfortunately this change broke legacy IRQ controllers in the same system, such as the i8259 on the Malta platform, as it allocates virq numbers that were expected to be available for the legacy controller. Instead of creating the mappings statically when the GIC is probed, re-introduce the irq domain .map function, removed by commit e875bd66dfb ("irqchip/mips-gic: Fix local interrupts") and use it to set up the irq handler and chip. Since a good deal of the required functionality is already implemented by gic_irq_domain_alloc, repurpose that function for gic_irq_domain_map and add a new gic_irq_domain_alloc which wraps gic_irq_domain_map with the necessary conversion. This change fixes the legacy interrupt controller of the Malta platform without breaking the perf interrupt fixed by commit e875bd66dfb ("irqchip/mips-gic: Fix local interrupts"). 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-4-git-send-email-matt.redfearn@imgtec.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- drivers/irqchip/irq-mips-gic.c | 60 +++++++++++++----------------------------- 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index eb448a1..eb7fbe1 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -700,16 +700,12 @@ static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, return 0; } -static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, - unsigned int nr_irqs, void *arg) +static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) { - struct irq_fwspec *fwspec = arg; - irq_hw_number_t hwirq; int err; - if (fwspec->param[0] == GIC_SHARED) { - hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]); - + if (hwirq >= GIC_SHARED_HWIRQ_BASE) { /* verify that shared irqs don't conflict with an IPI irq */ if (test_bit(GIC_HWIRQ_TO_SHARED(hwirq), ipi_resrv)) return -EBUSY; @@ -723,8 +719,6 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return gic_shared_irq_domain_map(d, virq, hwirq, 0); } - hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]); - switch (GIC_HWIRQ_TO_LOCAL(hwirq)) { case GIC_LOCAL_INT_TIMER: case GIC_LOCAL_INT_PERFCTR: @@ -758,6 +752,20 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return gic_local_irq_domain_map(d, virq, hwirq); } +static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, + unsigned int nr_irqs, void *arg) +{ + struct irq_fwspec *fwspec = arg; + irq_hw_number_t hwirq; + + if (fwspec->param[0] == GIC_SHARED) + hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]); + else + hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]); + + return gic_irq_domain_map(d, virq, hwirq); +} + void gic_irq_domain_free(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs) { @@ -767,6 +775,7 @@ 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, + .map = gic_irq_domain_map, }; static int gic_ipi_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, @@ -872,38 +881,6 @@ static struct irq_domain_ops gic_ipi_domain_ops = { .match = gic_ipi_domain_match, }; -static void __init gic_map_single_int(struct device_node *node, - unsigned int irq) -{ - unsigned int linux_irq; - struct irq_fwspec local_int_fwspec = { - .fwnode = &node->fwnode, - .param_count = 3, - .param = { - [0] = GIC_LOCAL, - [1] = irq, - [2] = IRQ_TYPE_NONE, - }, - }; - - if (!gic_local_irq_is_routable(irq)) - return; - - linux_irq = irq_create_fwspec_mapping(&local_int_fwspec); - WARN_ON(!linux_irq); -} - -static void __init gic_map_interrupts(struct device_node *node) -{ - gic_map_single_int(node, GIC_LOCAL_INT_WD); - gic_map_single_int(node, GIC_LOCAL_INT_COMPARE); - gic_map_single_int(node, GIC_LOCAL_INT_TIMER); - gic_map_single_int(node, GIC_LOCAL_INT_PERFCTR); - gic_map_single_int(node, GIC_LOCAL_INT_SWINT0); - gic_map_single_int(node, GIC_LOCAL_INT_SWINT1); - gic_map_single_int(node, GIC_LOCAL_INT_FDC); -} - static void __init __gic_init(unsigned long gic_base_addr, unsigned long gic_addrspace_size, unsigned int cpu_vec, unsigned int irqbase, @@ -997,7 +974,6 @@ static void __init __gic_init(unsigned long gic_base_addr, bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS); gic_basic_init(); - gic_map_interrupts(node); } void __init gic_init(unsigned long gic_base_addr, ^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2017-04-20 14:13 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2017-04-20 9:07 [PATCH 0/3] irqchip: mips-gic: Remove dev domain & fixes Matt Redfearn 2017-04-20 9:07 ` Matt Redfearn 2017-04-20 9:07 ` [PATCH 1/3] irqchip: mips-gic: Separate IPI reservation & usage tracking Matt Redfearn 2017-04-20 9:07 ` Matt Redfearn 2017-04-20 14:09 ` [tip:irq/core] irqchip/mips-gic: " tip-bot for Paul Burton 2017-04-20 9:07 ` [PATCH 2/3] irqchip: mips-gic: Remove device IRQ domain Matt Redfearn 2017-04-20 9:07 ` Matt Redfearn 2017-04-20 14:10 ` [tip:irq/core] irqchip/mips-gic: " tip-bot for Paul Burton 2017-04-20 9:07 ` [PATCH 3/3] irqchip: mips-gic: Replace static map with dynamic Matt Redfearn 2017-04-20 9:07 ` Matt Redfearn 2017-04-20 14:10 ` [tip:irq/core] irqchip/mips-gic: " tip-bot for Matt Redfearn
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.