diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 946ec4947da2..7005ee0b074d 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -367,6 +367,10 @@ struct mpic #define MPIC_SINGLE_DEST_CPU 0x00001000 /* Enable CoreInt delivery of interrupts */ #define MPIC_ENABLE_COREINT 0x00002000 +/* Disable resetting of the MPIC. + * NOTE: This flag trumps MPIC_WANTS_RESET. + */ +#define MPIC_NO_RESET 0x00004000 /* MPIC HW modification ID */ #define MPIC_REGSET_MASK 0xf0000000 diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index eb7021815e2d..3bf71035ff50 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -913,6 +913,20 @@ void mpic_set_vector(unsigned int virq, unsigned int vector) mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); } +void mpic_set_destination(unsigned int virq, unsigned int cpuid) +{ + struct mpic *mpic = mpic_from_irq(virq); + unsigned int src = mpic_irq_to_hw(virq); + + DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", + mpic, virq, src, cpuid); + + if (src >= mpic->irq_count) + return; + + mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); +} + static struct irq_chip mpic_irq_chip = { .irq_mask = mpic_mask_irq, .irq_unmask = mpic_unmask_irq, @@ -993,6 +1007,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, /* Set default irq type */ set_irq_type(virq, IRQ_TYPE_NONE); + /* If the MPIC was reset, then all vectors have already been + * initialized. Otherwise, a per source lazy initialization + * is done here. + */ + if (!mpic_is_ipi(mpic, hw) && (mpic->flags & MPIC_NO_RESET)) { + unsigned int cpu = 0; + + if (mpic->flags & MPIC_PRIMARY) + cpu = hard_smp_processor_id(); + + mpic_set_vector(virq, hw); + mpic_set_destination(virq, cpu); + mpic_irq_set_priority(virq, 8); + } + return 0; } @@ -1040,6 +1069,11 @@ static struct irq_host_ops mpic_host_ops = { .xlate = mpic_host_xlate, }; +static int mpic_reset_prohibited(struct device_node *node) +{ + return node && of_get_property(node, "pic-no-reset", NULL); +} + /* * Exported functions */ @@ -1160,7 +1194,15 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); /* Reset */ - if (flags & MPIC_WANTS_RESET) { + + /* When using a device-node, reset requests are only honored if the MPIC + * is allowed to reset. + */ + if (mpic_reset_prohibited(node)) + mpic->flags |= MPIC_NO_RESET; + + if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { + printk(KERN_DEBUG "mpic: Resetting\n"); mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | MPIC_GREG_GCONF_RESET); @@ -1325,17 +1367,19 @@ void __init mpic_init(struct mpic *mpic) else cpu = 0; - for (i = 0; i < mpic->num_sources; i++) { - /* start with vector = source number, and masked */ - u32 vecpri = MPIC_VECPRI_MASK | i | - (8 << MPIC_VECPRI_PRIORITY_SHIFT); + if (!(mpic->flags & MPIC_NO_RESET)) { + for (i = 0; i < mpic->num_sources; i++) { + /* start with vector = source number, and masked */ + u32 vecpri = MPIC_VECPRI_MASK | i | + (8 << MPIC_VECPRI_PRIORITY_SHIFT); - /* check if protected */ - if (mpic->protected && test_bit(i, mpic->protected)) - continue; - /* init hw */ - mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); - mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); + /* check if protected */ + if (mpic->protected && test_bit(i, mpic->protected)) + continue; + /* init hw */ + mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); + mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); + } } /* Init spurious vector */