Commit f37a53cc authored by Rob Herring's avatar Rob Herring Committed by Arnd Bergmann

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: default avatarRob Herring <rob.herring@calxeda.com>
parent b3f7ed03
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/err.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/smp.h> #include <linux/smp.h>
...@@ -562,7 +563,7 @@ const struct irq_domain_ops gic_irq_domain_ops = { ...@@ -562,7 +563,7 @@ const struct irq_domain_ops gic_irq_domain_ops = {
#endif #endif
}; };
void __init gic_init(unsigned int gic_nr, unsigned int irq_start, void __init gic_init(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base) void __iomem *dist_base, void __iomem *cpu_base)
{ {
struct gic_chip_data *gic; struct gic_chip_data *gic;
...@@ -583,7 +584,8 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start, ...@@ -583,7 +584,8 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
if (gic_nr == 0) { if (gic_nr == 0) {
gic_cpu_base_addr = cpu_base; gic_cpu_base_addr = cpu_base;
domain->hwirq_base = 16; domain->hwirq_base = 16;
irq_start = (irq_start & ~31) + 16; if (irq_start > 0)
irq_start = (irq_start & ~31) + 16;
} else } else
domain->hwirq_base = 32; domain->hwirq_base = 32;
...@@ -598,8 +600,13 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start, ...@@ -598,8 +600,13 @@ void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
gic->gic_irqs = gic_irqs; gic->gic_irqs = gic_irqs;
domain->nr_irq = gic_irqs - domain->hwirq_base; domain->nr_irq = gic_irqs - domain->hwirq_base;
domain->irq_base = irq_alloc_descs(-1, irq_start, domain->nr_irq, domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq,
numa_node_id()); numa_node_id());
if (IS_ERR_VALUE(domain->irq_base)) {
WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
irq_start);
domain->irq_base = irq_start;
}
domain->priv = gic; domain->priv = gic;
domain->ops = &gic_irq_domain_ops; domain->ops = &gic_irq_domain_ops;
irq_domain_add(domain); irq_domain_add(domain);
...@@ -659,7 +666,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) ...@@ -659,7 +666,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
domain->of_node = of_node_get(node); domain->of_node = of_node_get(node);
gic_init(gic_cnt, 16, dist_base, cpu_base); gic_init(gic_cnt, -1, dist_base, cpu_base);
if (parent) { if (parent) {
irq = irq_of_parse_and_map(node, 0); irq = irq_of_parse_and_map(node, 0);
......
...@@ -39,7 +39,7 @@ struct device_node; ...@@ -39,7 +39,7 @@ struct device_node;
extern void __iomem *gic_cpu_base_addr; extern void __iomem *gic_cpu_base_addr;
extern struct irq_chip gic_arch_extn; extern struct irq_chip gic_arch_extn;
void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *); void gic_init(unsigned int, int, void __iomem *, void __iomem *);
int gic_of_init(struct device_node *node, struct device_node *parent); int gic_of_init(struct device_node *node, struct device_node *parent);
void gic_secondary_init(unsigned int); void gic_secondary_init(unsigned int);
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment