diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 89 |
1 files changed, 65 insertions, 24 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index d01ced1..bcfb900 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -496,13 +496,18 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) { unsigned int src = mpic_irq_to_hw(irq); + struct mpic *mpic; if (irq < NUM_ISA_INTERRUPTS) return NULL; + + mpic = irq_desc[irq].chip_data; + if (is_ipi) - *is_ipi = (src >= MPIC_VEC_IPI_0 && src <= MPIC_VEC_IPI_3); + *is_ipi = (src >= mpic->ipi_vecs[0] && + src <= mpic->ipi_vecs[3]); - return irq_desc[irq].chip_data; + return mpic; } /* Convert a cpu mask from logical to physical cpu numbers. */ @@ -540,7 +545,11 @@ static inline void mpic_eoi(struct mpic *mpic) #ifdef CONFIG_SMP static irqreturn_t mpic_ipi_action(int irq, void *dev_id) { - smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0); + struct mpic *mpic; + + mpic = mpic_find(irq, NULL); + smp_message_recv(mpic_irq_to_hw(irq) - mpic->ipi_vecs[0]); + return IRQ_HANDLED; } #endif /* CONFIG_SMP */ @@ -663,7 +672,7 @@ static void mpic_end_ht_irq(unsigned int irq) static void mpic_unmask_ipi(unsigned int irq) { struct mpic *mpic = mpic_from_ipi(irq); - unsigned int src = mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0; + unsigned int src = mpic_irq_to_hw(irq) - mpic->ipi_vecs[0]; DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); @@ -807,11 +816,11 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw); - if (hw == MPIC_VEC_SPURRIOUS) + if (hw == mpic->spurious_vec) return -EINVAL; #ifdef CONFIG_SMP - else if (hw >= MPIC_VEC_IPI_0) { + else if (hw >= mpic->ipi_vecs[0]) { WARN_ON(!(mpic->flags & MPIC_PRIMARY)); DBG("mpic: mapping as IPI\n"); @@ -904,6 +913,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, u32 reg; const char *vers; int i; + int intvec_top; u64 paddr = phys_addr; mpic = alloc_bootmem(sizeof(struct mpic)); @@ -912,11 +922,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, memset(mpic, 0, sizeof(struct mpic)); mpic->name = name; - mpic->of_node = node ? of_node_get(node) : NULL; + mpic->of_node = of_node_get(node); - mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 256, + mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, isu_size, &mpic_host_ops, - MPIC_VEC_SPURRIOUS); + flags & MPIC_LARGE_VECTORS ? 2048 : 256); if (mpic->irqhost == NULL) { of_node_put(node); return NULL; @@ -944,6 +954,21 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->irq_count = irq_count; mpic->num_sources = 0; /* so far */ + if (flags & MPIC_LARGE_VECTORS) + intvec_top = 2047; + else + intvec_top = 255; + + mpic->timer_vecs[0] = intvec_top - 8; + mpic->timer_vecs[1] = intvec_top - 7; + mpic->timer_vecs[2] = intvec_top - 6; + mpic->timer_vecs[3] = intvec_top - 5; + mpic->ipi_vecs[0] = intvec_top - 4; + mpic->ipi_vecs[1] = intvec_top - 3; + mpic->ipi_vecs[2] = intvec_top - 2; + mpic->ipi_vecs[3] = intvec_top - 1; + mpic->spurious_vec = intvec_top; + /* Check for "big-endian" in device-tree */ if (node && get_property(node, "big-endian", NULL) != NULL) mpic->flags |= MPIC_BIG_ENDIAN; @@ -1084,11 +1109,6 @@ void __init mpic_init(struct mpic *mpic) int i; BUG_ON(mpic->num_sources == 0); - WARN_ON(mpic->num_sources > MPIC_VEC_IPI_0); - - /* Sanitize source count */ - if (mpic->num_sources > MPIC_VEC_IPI_0) - mpic->num_sources = MPIC_VEC_IPI_0; printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); @@ -1104,7 +1124,7 @@ void __init mpic_init(struct mpic *mpic) i * MPIC_INFO(TIMER_STRIDE) + MPIC_INFO(TIMER_VECTOR_PRI), MPIC_VECPRI_MASK | - (MPIC_VEC_TIMER_0 + i)); + (mpic->timer_vecs[0] + i)); } /* Initialize IPIs to our reserved vectors and mark them disabled for now */ @@ -1113,7 +1133,7 @@ void __init mpic_init(struct mpic *mpic) mpic_ipi_write(i, MPIC_VECPRI_MASK | (10 << MPIC_VECPRI_PRIORITY_SHIFT) | - (MPIC_VEC_IPI_0 + i)); + (mpic->ipi_vecs[0] + i)); } /* Initialize interrupt sources */ @@ -1136,8 +1156,8 @@ void __init mpic_init(struct mpic *mpic) 1 << hard_smp_processor_id()); } - /* Init spurrious vector */ - mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), MPIC_VEC_SPURRIOUS); + /* Init spurious vector */ + mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), mpic->spurious_vec); /* Disable 8259 passthrough, if supported */ if (!(mpic->flags & MPIC_NO_PTHROU_DIS)) @@ -1184,9 +1204,9 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri) spin_lock_irqsave(&mpic_lock, flags); if (is_ipi) { - reg = mpic_ipi_read(src - MPIC_VEC_IPI_0) & + reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) & ~MPIC_VECPRI_PRIORITY_MASK; - mpic_ipi_write(src - MPIC_VEC_IPI_0, + mpic_ipi_write(src - mpic->ipi_vecs[0], reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); } else { reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) @@ -1207,7 +1227,7 @@ unsigned int mpic_irq_get_priority(unsigned int irq) spin_lock_irqsave(&mpic_lock, flags); if (is_ipi) - reg = mpic_ipi_read(src = MPIC_VEC_IPI_0); + reg = mpic_ipi_read(src = mpic->ipi_vecs[0]); else reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); spin_unlock_irqrestore(&mpic_lock, flags); @@ -1313,7 +1333,7 @@ unsigned int mpic_get_one_irq(struct mpic *mpic) #ifdef DEBUG_LOW DBG("%s: get_one_irq(): %d\n", mpic->name, src); #endif - if (unlikely(src == MPIC_VEC_SPURRIOUS)) + if (unlikely(src == mpic->spurious_vec)) return NO_IRQ; return irq_linear_revmap(mpic->irqhost, src); } @@ -1345,12 +1365,12 @@ void mpic_request_ipis(void) for (i = 0; i < 4; i++) { unsigned int vipi = irq_create_mapping(mpic->irqhost, - MPIC_VEC_IPI_0 + i); + mpic->ipi_vecs[0] + i); if (vipi == NO_IRQ) { printk(KERN_ERR "Failed to map IPI %d\n", i); break; } - request_irq(vipi, mpic_ipi_action, IRQF_DISABLED, + request_irq(vipi, mpic_ipi_action, IRQF_DISABLED|IRQF_PERCPU, ipi_names[i], mpic); } } @@ -1375,4 +1395,25 @@ void smp_mpic_message_pass(int target, int msg) break; } } + +int __init smp_mpic_probe(void) +{ + int nr_cpus; + + DBG("smp_mpic_probe()...\n"); + + nr_cpus = cpus_weight(cpu_possible_map); + + DBG("nr_cpus: %d\n", nr_cpus); + + if (nr_cpus > 1) + mpic_request_ipis(); + + return nr_cpus; +} + +void __devinit smp_mpic_setup_cpu(int cpu) +{ + mpic_setup_this_cpu(); +} #endif /* CONFIG_SMP */ |