diff options
-rw-r--r-- | arch/powerpc/platforms/pseries/xics.c | 53 |
1 files changed, 41 insertions, 12 deletions
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 6b1a005cc0c..1bccd4a56b5 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) lpar_xirr_info_set((0xff << 24) | irq); } -static inline unsigned int xics_remap_irq(unsigned int vec) +static inline unsigned int xics_xirr_vector(unsigned int xirr) { - unsigned int irq; + /* + * The top byte is the old cppr, to be restored on EOI. + * The remaining 24 bits are the vector. + */ + return xirr & 0x00ffffff; +} - vec &= 0x00ffffff; +static void xics_mask_unknown_vec(unsigned int vec) +{ + printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec); + xics_mask_real_irq(vec); +} + +static unsigned int xics_get_irq_direct(void) +{ + unsigned int xirr = direct_xirr_info_get(); + unsigned int vec = xics_xirr_vector(xirr); + unsigned int irq; if (vec == XICS_IRQ_SPURIOUS) return NO_IRQ; + irq = irq_radix_revmap_lookup(xics_host, vec); if (likely(irq != NO_IRQ)) return irq; - printk(KERN_ERR "Interrupt %u (real) is invalid," - " disabling it.\n", vec); - xics_mask_real_irq(vec); - return NO_IRQ; -} + /* We don't have a linux mapping, so have rtas mask it. */ + xics_mask_unknown_vec(vec); -static unsigned int xics_get_irq_direct(void) -{ - return xics_remap_irq(direct_xirr_info_get()); + /* We might learn about it later, so EOI it */ + direct_xirr_info_set(xirr); + return NO_IRQ; } static unsigned int xics_get_irq_lpar(void) { - return xics_remap_irq(lpar_xirr_info_get()); + unsigned int xirr = lpar_xirr_info_get(); + unsigned int vec = xics_xirr_vector(xirr); + unsigned int irq; + + if (vec == XICS_IRQ_SPURIOUS) + return NO_IRQ; + + irq = irq_radix_revmap_lookup(xics_host, vec); + if (likely(irq != NO_IRQ)) + return irq; + + /* We don't have a linux mapping, so have RTAS mask it. */ + xics_mask_unknown_vec(vec); + + /* We might learn about it later, so EOI it */ + lpar_xirr_info_set(xirr); + return NO_IRQ; } #ifdef CONFIG_SMP |