diff options
author | Pawel Moll <pawel.moll@arm.com> | 2010-11-26 07:45:43 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-11-30 08:38:57 -0500 |
commit | e6afec9b6808eff6dc392ac07c1552e87aebcdf7 (patch) | |
tree | 67ea03e347da896518f96c7611eb792bf6a9f374 /arch/arm/common/gic.c | |
parent | e8a7e48bb248a1196484d3f8afa53bded2b24e71 (diff) |
ARM: 6496/1: GIC: Do not try to register more then NR_IRQS interrupts
This change limits number of GIC-originating interrupts to the
platform maximum (defined by NR_IRQS) while still initialising
all distributor registers.
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/common/gic.c')
-rw-r--r-- | arch/arm/common/gic.c | 32 |
1 files changed, 17 insertions, 15 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 772f95f1aecd..fea1bd7249b6 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c | |||
@@ -210,7 +210,7 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) | |||
210 | void __init gic_dist_init(unsigned int gic_nr, void __iomem *base, | 210 | void __init gic_dist_init(unsigned int gic_nr, void __iomem *base, |
211 | unsigned int irq_start) | 211 | unsigned int irq_start) |
212 | { | 212 | { |
213 | unsigned int max_irq, i; | 213 | unsigned int gic_irqs, irq_limit, i; |
214 | u32 cpumask = 1 << smp_processor_id(); | 214 | u32 cpumask = 1 << smp_processor_id(); |
215 | 215 | ||
216 | if (gic_nr >= MAX_GIC_NR) | 216 | if (gic_nr >= MAX_GIC_NR) |
@@ -226,47 +226,49 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base, | |||
226 | 226 | ||
227 | /* | 227 | /* |
228 | * Find out how many interrupts are supported. | 228 | * Find out how many interrupts are supported. |
229 | */ | ||
230 | max_irq = readl(base + GIC_DIST_CTR) & 0x1f; | ||
231 | max_irq = (max_irq + 1) * 32; | ||
232 | |||
233 | /* | ||
234 | * The GIC only supports up to 1020 interrupt sources. | 229 | * The GIC only supports up to 1020 interrupt sources. |
235 | * Limit this to either the architected maximum, or the | ||
236 | * platform maximum. | ||
237 | */ | 230 | */ |
238 | if (max_irq > max(1020, NR_IRQS)) | 231 | gic_irqs = readl(base + GIC_DIST_CTR) & 0x1f; |
239 | max_irq = max(1020, NR_IRQS); | 232 | gic_irqs = (gic_irqs + 1) * 32; |
233 | if (gic_irqs > 1020) | ||
234 | gic_irqs = 1020; | ||
240 | 235 | ||
241 | /* | 236 | /* |
242 | * Set all global interrupts to be level triggered, active low. | 237 | * Set all global interrupts to be level triggered, active low. |
243 | */ | 238 | */ |
244 | for (i = 32; i < max_irq; i += 16) | 239 | for (i = 32; i < gic_irqs; i += 16) |
245 | writel(0, base + GIC_DIST_CONFIG + i * 4 / 16); | 240 | writel(0, base + GIC_DIST_CONFIG + i * 4 / 16); |
246 | 241 | ||
247 | /* | 242 | /* |
248 | * Set all global interrupts to this CPU only. | 243 | * Set all global interrupts to this CPU only. |
249 | */ | 244 | */ |
250 | for (i = 32; i < max_irq; i += 4) | 245 | for (i = 32; i < gic_irqs; i += 4) |
251 | writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); | 246 | writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); |
252 | 247 | ||
253 | /* | 248 | /* |
254 | * Set priority on all global interrupts. | 249 | * Set priority on all global interrupts. |
255 | */ | 250 | */ |
256 | for (i = 32; i < max_irq; i += 4) | 251 | for (i = 32; i < gic_irqs; i += 4) |
257 | writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); | 252 | writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); |
258 | 253 | ||
259 | /* | 254 | /* |
260 | * Disable all interrupts. Leave the PPI and SGIs alone | 255 | * Disable all interrupts. Leave the PPI and SGIs alone |
261 | * as these enables are banked registers. | 256 | * as these enables are banked registers. |
262 | */ | 257 | */ |
263 | for (i = 32; i < max_irq; i += 32) | 258 | for (i = 32; i < gic_irqs; i += 32) |
264 | writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); | 259 | writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); |
265 | 260 | ||
266 | /* | 261 | /* |
262 | * Limit number of interrupts registered to the platform maximum | ||
263 | */ | ||
264 | irq_limit = gic_data[gic_nr].irq_offset + gic_irqs; | ||
265 | if (WARN_ON(irq_limit > NR_IRQS)) | ||
266 | irq_limit = NR_IRQS; | ||
267 | |||
268 | /* | ||
267 | * Setup the Linux IRQ subsystem. | 269 | * Setup the Linux IRQ subsystem. |
268 | */ | 270 | */ |
269 | for (i = irq_start; i < gic_data[gic_nr].irq_offset + max_irq; i++) { | 271 | for (i = irq_start; i < irq_limit; i++) { |
270 | set_irq_chip(i, &gic_chip); | 272 | set_irq_chip(i, &gic_chip); |
271 | set_irq_chip_data(i, &gic_data[gic_nr]); | 273 | set_irq_chip_data(i, &gic_data[gic_nr]); |
272 | set_irq_handler(i, handle_level_irq); | 274 | set_irq_handler(i, handle_level_irq); |