diff options
| author | Rob Herring <rob.herring@calxeda.com> | 2011-10-21 18:14:27 -0400 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2011-10-31 09:03:27 -0400 |
| commit | f37a53cc5d8a8fb199e41386d125d8c2ed9e54ef (patch) | |
| tree | ccf7658e1dae54e7b3eeaa8413dd86d4b865eaec | |
| parent | b3f7ed0324091e2cb23fe1b3c10570700f614014 (diff) | |
ARM: gic: fix irq_alloc_descs handling for sparse irq
Commit "ARM: gic: add irq_domain support" (b49b6ff) breaks SPARSE_IRQ
on platforms with GIC. When SPARSE_IRQ is enabled, all NR_IRQS or
mach_desc->nr_irqs will be allocated by arch_probe_nr_irqs(). This caused
irq_alloc_descs to allocate irq_descs after the pre-allocated space.
Make irq_alloc_descs search for an exact irq range and assume it has
been pre-allocated on failure. For DT probing dynamic allocation is used.
DT enabled platforms should set their nr_irqs to NR_IRQ_LEGACY and have all
irq_chips allocate their irq_descs with irq_alloc_descs if SPARSE_IRQ is
enabled.
gic_init irq_start param is changed to be signed with negative meaning do
dynamic Linux irq assigment.
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
| -rw-r--r-- | arch/arm/common/gic.c | 15 | ||||
| -rw-r--r-- | arch/arm/include/asm/hardware/gic.h | 2 |
2 files changed, 12 insertions, 5 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 1333e68b1f96..9d77777076f0 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | */ | 24 | */ |
| 25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
| 26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
| 27 | #include <linux/err.h> | ||
| 27 | #include <linux/export.h> | 28 | #include <linux/export.h> |
| 28 | #include <linux/list.h> | 29 | #include <linux/list.h> |
| 29 | #include <linux/smp.h> | 30 | #include <linux/smp.h> |
| @@ -562,7 +563,7 @@ const struct irq_domain_ops gic_irq_domain_ops = { | |||
| 562 | #endif | 563 | #endif |
| 563 | }; | 564 | }; |
| 564 | 565 | ||
| 565 | void __init gic_init(unsigned int gic_nr, unsigned int irq_start, | 566 | void __init gic_init(unsigned int gic_nr, int irq_start, |
| 566 | void __iomem *dist_base, void __iomem *cpu_base) | 567 | void __iomem *dist_base, void __iomem *cpu_base) |
| 567 | { | 568 | { |
| 568 | struct gic_chip_data *gic; | 569 | struct gic_chip_data *gic; |
| @@ -583,7 +584,8 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start, | |||
| 583 | if (gic_nr == 0) { | 584 | if (gic_nr == 0) { |
| 584 | gic_cpu_base_addr = cpu_base; | 585 | gic_cpu_base_addr = cpu_base; |
| 585 | domain->hwirq_base = 16; | 586 | domain->hwirq_base = 16; |
| 586 | irq_start = (irq_start & ~31) + 16; | 587 | if (irq_start > 0) |
| 588 | irq_start = (irq_start & ~31) + 16; | ||
| 587 | } else | 589 | } else |
| 588 | domain->hwirq_base = 32; | 590 | domain->hwirq_base = 32; |
| 589 | 591 | ||
| @@ -598,8 +600,13 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start, | |||
| 598 | gic->gic_irqs = gic_irqs; | 600 | gic->gic_irqs = gic_irqs; |
| 599 | 601 | ||
| 600 | domain->nr_irq = gic_irqs - domain->hwirq_base; | 602 | domain->nr_irq = gic_irqs - domain->hwirq_base; |
| 601 | domain->irq_base = irq_alloc_descs(-1, irq_start, domain->nr_irq, | 603 | domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq, |
| 602 | numa_node_id()); | 604 | numa_node_id()); |
| 605 | if (IS_ERR_VALUE(domain->irq_base)) { | ||
| 606 | WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", | ||
| 607 | irq_start); | ||
| 608 | domain->irq_base = irq_start; | ||
| 609 | } | ||
| 603 | domain->priv = gic; | 610 | domain->priv = gic; |
| 604 | domain->ops = &gic_irq_domain_ops; | 611 | domain->ops = &gic_irq_domain_ops; |
| 605 | irq_domain_add(domain); | 612 | irq_domain_add(domain); |
| @@ -659,7 +666,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) | |||
| 659 | 666 | ||
| 660 | domain->of_node = of_node_get(node); | 667 | domain->of_node = of_node_get(node); |
| 661 | 668 | ||
| 662 | gic_init(gic_cnt, 16, dist_base, cpu_base); | 669 | gic_init(gic_cnt, -1, dist_base, cpu_base); |
| 663 | 670 | ||
| 664 | if (parent) { | 671 | if (parent) { |
| 665 | irq = irq_of_parse_and_map(node, 0); | 672 | irq = irq_of_parse_and_map(node, 0); |
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 0a026b9290f2..3e91f22046f5 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h | |||
| @@ -39,7 +39,7 @@ struct device_node; | |||
| 39 | extern void __iomem *gic_cpu_base_addr; | 39 | extern void __iomem *gic_cpu_base_addr; |
| 40 | extern struct irq_chip gic_arch_extn; | 40 | extern struct irq_chip gic_arch_extn; |
| 41 | 41 | ||
| 42 | void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *); | 42 | void gic_init(unsigned int, int, void __iomem *, void __iomem *); |
| 43 | int gic_of_init(struct device_node *node, struct device_node *parent); | 43 | int gic_of_init(struct device_node *node, struct device_node *parent); |
| 44 | void gic_secondary_init(unsigned int); | 44 | void gic_secondary_init(unsigned int); |
| 45 | void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); | 45 | void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); |
