diff options
Diffstat (limited to 'arch/arm/common')
-rw-r--r-- | arch/arm/common/gic.c | 40 |
1 files changed, 24 insertions, 16 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index 772f95f1aecd..e6388dcd8cfa 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c | |||
@@ -146,9 +146,15 @@ static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val) | |||
146 | unsigned int shift = (irq % 4) * 8; | 146 | unsigned int shift = (irq % 4) * 8; |
147 | unsigned int cpu = cpumask_first(mask_val); | 147 | unsigned int cpu = cpumask_first(mask_val); |
148 | u32 val; | 148 | u32 val; |
149 | struct irq_desc *desc; | ||
149 | 150 | ||
150 | spin_lock(&irq_controller_lock); | 151 | spin_lock(&irq_controller_lock); |
151 | irq_desc[irq].node = cpu; | 152 | desc = irq_to_desc(irq); |
153 | if (desc == NULL) { | ||
154 | spin_unlock(&irq_controller_lock); | ||
155 | return -EINVAL; | ||
156 | } | ||
157 | desc->node = cpu; | ||
152 | val = readl(reg) & ~(0xff << shift); | 158 | val = readl(reg) & ~(0xff << shift); |
153 | val |= 1 << (cpu + shift); | 159 | val |= 1 << (cpu + shift); |
154 | writel(val, reg); | 160 | writel(val, reg); |
@@ -210,7 +216,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, | 216 | void __init gic_dist_init(unsigned int gic_nr, void __iomem *base, |
211 | unsigned int irq_start) | 217 | unsigned int irq_start) |
212 | { | 218 | { |
213 | unsigned int max_irq, i; | 219 | unsigned int gic_irqs, irq_limit, i; |
214 | u32 cpumask = 1 << smp_processor_id(); | 220 | u32 cpumask = 1 << smp_processor_id(); |
215 | 221 | ||
216 | if (gic_nr >= MAX_GIC_NR) | 222 | if (gic_nr >= MAX_GIC_NR) |
@@ -226,47 +232,49 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base, | |||
226 | 232 | ||
227 | /* | 233 | /* |
228 | * Find out how many interrupts are supported. | 234 | * 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. | 235 | * The GIC only supports up to 1020 interrupt sources. |
235 | * Limit this to either the architected maximum, or the | ||
236 | * platform maximum. | ||
237 | */ | 236 | */ |
238 | if (max_irq > max(1020, NR_IRQS)) | 237 | gic_irqs = readl(base + GIC_DIST_CTR) & 0x1f; |
239 | max_irq = max(1020, NR_IRQS); | 238 | gic_irqs = (gic_irqs + 1) * 32; |
239 | if (gic_irqs > 1020) | ||
240 | gic_irqs = 1020; | ||
240 | 241 | ||
241 | /* | 242 | /* |
242 | * Set all global interrupts to be level triggered, active low. | 243 | * Set all global interrupts to be level triggered, active low. |
243 | */ | 244 | */ |
244 | for (i = 32; i < max_irq; i += 16) | 245 | for (i = 32; i < gic_irqs; i += 16) |
245 | writel(0, base + GIC_DIST_CONFIG + i * 4 / 16); | 246 | writel(0, base + GIC_DIST_CONFIG + i * 4 / 16); |
246 | 247 | ||
247 | /* | 248 | /* |
248 | * Set all global interrupts to this CPU only. | 249 | * Set all global interrupts to this CPU only. |
249 | */ | 250 | */ |
250 | for (i = 32; i < max_irq; i += 4) | 251 | for (i = 32; i < gic_irqs; i += 4) |
251 | writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); | 252 | writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); |
252 | 253 | ||
253 | /* | 254 | /* |
254 | * Set priority on all global interrupts. | 255 | * Set priority on all global interrupts. |
255 | */ | 256 | */ |
256 | for (i = 32; i < max_irq; i += 4) | 257 | for (i = 32; i < gic_irqs; i += 4) |
257 | writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); | 258 | writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); |
258 | 259 | ||
259 | /* | 260 | /* |
260 | * Disable all interrupts. Leave the PPI and SGIs alone | 261 | * Disable all interrupts. Leave the PPI and SGIs alone |
261 | * as these enables are banked registers. | 262 | * as these enables are banked registers. |
262 | */ | 263 | */ |
263 | for (i = 32; i < max_irq; i += 32) | 264 | for (i = 32; i < gic_irqs; i += 32) |
264 | writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); | 265 | writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); |
265 | 266 | ||
266 | /* | 267 | /* |
268 | * Limit number of interrupts registered to the platform maximum | ||
269 | */ | ||
270 | irq_limit = gic_data[gic_nr].irq_offset + gic_irqs; | ||
271 | if (WARN_ON(irq_limit > NR_IRQS)) | ||
272 | irq_limit = NR_IRQS; | ||
273 | |||
274 | /* | ||
267 | * Setup the Linux IRQ subsystem. | 275 | * Setup the Linux IRQ subsystem. |
268 | */ | 276 | */ |
269 | for (i = irq_start; i < gic_data[gic_nr].irq_offset + max_irq; i++) { | 277 | for (i = irq_start; i < irq_limit; i++) { |
270 | set_irq_chip(i, &gic_chip); | 278 | set_irq_chip(i, &gic_chip); |
271 | set_irq_chip_data(i, &gic_data[gic_nr]); | 279 | set_irq_chip_data(i, &gic_data[gic_nr]); |
272 | set_irq_handler(i, handle_level_irq); | 280 | set_irq_handler(i, handle_level_irq); |