aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pseries/xics.c
diff options
context:
space:
mode:
authorMilton Miller <miltonm@bga.com>2008-10-09 21:56:23 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-10-12 19:55:47 -0400
commit8767e9badca7cdf0adc2564d7524092d47ababf3 (patch)
treec293dc4e096384386a14619e8cb7cab3eea3c1f3 /arch/powerpc/platforms/pseries/xics.c
parentbb3d55e2505d8de15b132a3f6a1d596c1e2a13ee (diff)
powerpc/xics: EOI unmapped irqs after disabling them
When reciving an irq vector that does not have a linux mapping, the kernel prints a message and calls RTAS to disable the irq source. Previously the kernel did not EOI the interrupt, causing the source to think it is still being processed by software. While this does add an additional layer of protection against interrupt storms had RTAS failed to disable the source, it also prevents the interrupt from working when a driver later enables it. (We could alternatively send an EOI on startup, but that strategy would likely fail on an emulated xics.) All interrupts should be disabled when the kernel starts, but this can be observed if a driver does not shutdown an interrupt in its reboot hook before starting a new kernel with kexec. Michael reports this can be reproduced trivially by banging the keyboard while kexec'ing on a P5 LPAR: even though the hvc_console driver request's the console irq later in boot, the console is non-functional because we're receiving no console interrupts. Reported-By: Michael Ellerman Signed-off-by: Milton Miller <miltonm@bga.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms/pseries/xics.c')
-rw-r--r--arch/powerpc/platforms/pseries/xics.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 6b1a005cc0cc..1bccd4a56b57 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -332,32 +332,61 @@ static void xics_eoi_lpar(unsigned int virq)
332 lpar_xirr_info_set((0xff << 24) | irq); 332 lpar_xirr_info_set((0xff << 24) | irq);
333} 333}
334 334
335static inline unsigned int xics_remap_irq(unsigned int vec) 335static inline unsigned int xics_xirr_vector(unsigned int xirr)
336{ 336{
337 unsigned int irq; 337 /*
338 * The top byte is the old cppr, to be restored on EOI.
339 * The remaining 24 bits are the vector.
340 */
341 return xirr & 0x00ffffff;
342}
338 343
339 vec &= 0x00ffffff; 344static void xics_mask_unknown_vec(unsigned int vec)
345{
346 printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec);
347 xics_mask_real_irq(vec);
348}
349
350static unsigned int xics_get_irq_direct(void)
351{
352 unsigned int xirr = direct_xirr_info_get();
353 unsigned int vec = xics_xirr_vector(xirr);
354 unsigned int irq;
340 355
341 if (vec == XICS_IRQ_SPURIOUS) 356 if (vec == XICS_IRQ_SPURIOUS)
342 return NO_IRQ; 357 return NO_IRQ;
358
343 irq = irq_radix_revmap_lookup(xics_host, vec); 359 irq = irq_radix_revmap_lookup(xics_host, vec);
344 if (likely(irq != NO_IRQ)) 360 if (likely(irq != NO_IRQ))
345 return irq; 361 return irq;
346 362
347 printk(KERN_ERR "Interrupt %u (real) is invalid," 363 /* We don't have a linux mapping, so have rtas mask it. */
348 " disabling it.\n", vec); 364 xics_mask_unknown_vec(vec);
349 xics_mask_real_irq(vec);
350 return NO_IRQ;
351}
352 365
353static unsigned int xics_get_irq_direct(void) 366 /* We might learn about it later, so EOI it */
354{ 367 direct_xirr_info_set(xirr);
355 return xics_remap_irq(direct_xirr_info_get()); 368 return NO_IRQ;
356} 369}
357 370
358static unsigned int xics_get_irq_lpar(void) 371static unsigned int xics_get_irq_lpar(void)
359{ 372{
360 return xics_remap_irq(lpar_xirr_info_get()); 373 unsigned int xirr = lpar_xirr_info_get();
374 unsigned int vec = xics_xirr_vector(xirr);
375 unsigned int irq;
376
377 if (vec == XICS_IRQ_SPURIOUS)
378 return NO_IRQ;
379
380 irq = irq_radix_revmap_lookup(xics_host, vec);
381 if (likely(irq != NO_IRQ))
382 return irq;
383
384 /* We don't have a linux mapping, so have RTAS mask it. */
385 xics_mask_unknown_vec(vec);
386
387 /* We might learn about it later, so EOI it */
388 lpar_xirr_info_set(xirr);
389 return NO_IRQ;
361} 390}
362 391
363#ifdef CONFIG_SMP 392#ifdef CONFIG_SMP