114cf11afSPaul Mackerras /* 214cf11afSPaul Mackerras * arch/powerpc/kernel/mpic.c 314cf11afSPaul Mackerras * 414cf11afSPaul Mackerras * Driver for interrupt controllers following the OpenPIC standard, the 514cf11afSPaul Mackerras * common implementation beeing IBM's MPIC. This driver also can deal 614cf11afSPaul Mackerras * with various broken implementations of this HW. 714cf11afSPaul Mackerras * 814cf11afSPaul Mackerras * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. 914cf11afSPaul Mackerras * 1014cf11afSPaul Mackerras * This file is subject to the terms and conditions of the GNU General Public 1114cf11afSPaul Mackerras * License. See the file COPYING in the main directory of this archive 1214cf11afSPaul Mackerras * for more details. 1314cf11afSPaul Mackerras */ 1414cf11afSPaul Mackerras 1514cf11afSPaul Mackerras #undef DEBUG 161beb6a7dSBenjamin Herrenschmidt #undef DEBUG_IPI 171beb6a7dSBenjamin Herrenschmidt #undef DEBUG_IRQ 181beb6a7dSBenjamin Herrenschmidt #undef DEBUG_LOW 1914cf11afSPaul Mackerras 2014cf11afSPaul Mackerras #include <linux/types.h> 2114cf11afSPaul Mackerras #include <linux/kernel.h> 2214cf11afSPaul Mackerras #include <linux/init.h> 2314cf11afSPaul Mackerras #include <linux/irq.h> 2414cf11afSPaul Mackerras #include <linux/smp.h> 2514cf11afSPaul Mackerras #include <linux/interrupt.h> 2614cf11afSPaul Mackerras #include <linux/bootmem.h> 2714cf11afSPaul Mackerras #include <linux/spinlock.h> 2814cf11afSPaul Mackerras #include <linux/pci.h> 2914cf11afSPaul Mackerras 3014cf11afSPaul Mackerras #include <asm/ptrace.h> 3114cf11afSPaul Mackerras #include <asm/signal.h> 3214cf11afSPaul Mackerras #include <asm/io.h> 3314cf11afSPaul Mackerras #include <asm/pgtable.h> 3414cf11afSPaul Mackerras #include <asm/irq.h> 3514cf11afSPaul Mackerras #include <asm/machdep.h> 3614cf11afSPaul Mackerras #include <asm/mpic.h> 3714cf11afSPaul Mackerras #include <asm/smp.h> 3814cf11afSPaul Mackerras 3914cf11afSPaul Mackerras #ifdef DEBUG 4014cf11afSPaul Mackerras #define DBG(fmt...) printk(fmt) 4114cf11afSPaul Mackerras #else 4214cf11afSPaul Mackerras #define DBG(fmt...) 4314cf11afSPaul Mackerras #endif 4414cf11afSPaul Mackerras 4514cf11afSPaul Mackerras static struct mpic *mpics; 4614cf11afSPaul Mackerras static struct mpic *mpic_primary; 4714cf11afSPaul Mackerras static DEFINE_SPINLOCK(mpic_lock); 4814cf11afSPaul Mackerras 49c0c0d996SPaul Mackerras #ifdef CONFIG_PPC32 /* XXX for now */ 50e40c7f02SAndy Whitcroft #ifdef CONFIG_IRQ_ALL_CPUS 51e40c7f02SAndy Whitcroft #define distribute_irqs (1) 52e40c7f02SAndy Whitcroft #else 53e40c7f02SAndy Whitcroft #define distribute_irqs (0) 54e40c7f02SAndy Whitcroft #endif 55c0c0d996SPaul Mackerras #endif 5614cf11afSPaul Mackerras 57*7233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 58*7233593bSZang Roy-r61911 static u32 mpic_infos[][MPIC_IDX_END] = { 59*7233593bSZang Roy-r61911 [0] = { /* Original OpenPIC compatible MPIC */ 60*7233593bSZang Roy-r61911 MPIC_GREG_BASE, 61*7233593bSZang Roy-r61911 MPIC_GREG_FEATURE_0, 62*7233593bSZang Roy-r61911 MPIC_GREG_GLOBAL_CONF_0, 63*7233593bSZang Roy-r61911 MPIC_GREG_VENDOR_ID, 64*7233593bSZang Roy-r61911 MPIC_GREG_IPI_VECTOR_PRI_0, 65*7233593bSZang Roy-r61911 MPIC_GREG_IPI_STRIDE, 66*7233593bSZang Roy-r61911 MPIC_GREG_SPURIOUS, 67*7233593bSZang Roy-r61911 MPIC_GREG_TIMER_FREQ, 68*7233593bSZang Roy-r61911 69*7233593bSZang Roy-r61911 MPIC_TIMER_BASE, 70*7233593bSZang Roy-r61911 MPIC_TIMER_STRIDE, 71*7233593bSZang Roy-r61911 MPIC_TIMER_CURRENT_CNT, 72*7233593bSZang Roy-r61911 MPIC_TIMER_BASE_CNT, 73*7233593bSZang Roy-r61911 MPIC_TIMER_VECTOR_PRI, 74*7233593bSZang Roy-r61911 MPIC_TIMER_DESTINATION, 75*7233593bSZang Roy-r61911 76*7233593bSZang Roy-r61911 MPIC_CPU_BASE, 77*7233593bSZang Roy-r61911 MPIC_CPU_STRIDE, 78*7233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_0, 79*7233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_STRIDE, 80*7233593bSZang Roy-r61911 MPIC_CPU_CURRENT_TASK_PRI, 81*7233593bSZang Roy-r61911 MPIC_CPU_WHOAMI, 82*7233593bSZang Roy-r61911 MPIC_CPU_INTACK, 83*7233593bSZang Roy-r61911 MPIC_CPU_EOI, 84*7233593bSZang Roy-r61911 85*7233593bSZang Roy-r61911 MPIC_IRQ_BASE, 86*7233593bSZang Roy-r61911 MPIC_IRQ_STRIDE, 87*7233593bSZang Roy-r61911 MPIC_IRQ_VECTOR_PRI, 88*7233593bSZang Roy-r61911 MPIC_VECPRI_VECTOR_MASK, 89*7233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_POSITIVE, 90*7233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_NEGATIVE, 91*7233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_LEVEL, 92*7233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_EDGE, 93*7233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_MASK, 94*7233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_MASK, 95*7233593bSZang Roy-r61911 MPIC_IRQ_DESTINATION 96*7233593bSZang Roy-r61911 }, 97*7233593bSZang Roy-r61911 [1] = { /* Tsi108/109 PIC */ 98*7233593bSZang Roy-r61911 TSI108_GREG_BASE, 99*7233593bSZang Roy-r61911 TSI108_GREG_FEATURE_0, 100*7233593bSZang Roy-r61911 TSI108_GREG_GLOBAL_CONF_0, 101*7233593bSZang Roy-r61911 TSI108_GREG_VENDOR_ID, 102*7233593bSZang Roy-r61911 TSI108_GREG_IPI_VECTOR_PRI_0, 103*7233593bSZang Roy-r61911 TSI108_GREG_IPI_STRIDE, 104*7233593bSZang Roy-r61911 TSI108_GREG_SPURIOUS, 105*7233593bSZang Roy-r61911 TSI108_GREG_TIMER_FREQ, 106*7233593bSZang Roy-r61911 107*7233593bSZang Roy-r61911 TSI108_TIMER_BASE, 108*7233593bSZang Roy-r61911 TSI108_TIMER_STRIDE, 109*7233593bSZang Roy-r61911 TSI108_TIMER_CURRENT_CNT, 110*7233593bSZang Roy-r61911 TSI108_TIMER_BASE_CNT, 111*7233593bSZang Roy-r61911 TSI108_TIMER_VECTOR_PRI, 112*7233593bSZang Roy-r61911 TSI108_TIMER_DESTINATION, 113*7233593bSZang Roy-r61911 114*7233593bSZang Roy-r61911 TSI108_CPU_BASE, 115*7233593bSZang Roy-r61911 TSI108_CPU_STRIDE, 116*7233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_0, 117*7233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_STRIDE, 118*7233593bSZang Roy-r61911 TSI108_CPU_CURRENT_TASK_PRI, 119*7233593bSZang Roy-r61911 TSI108_CPU_WHOAMI, 120*7233593bSZang Roy-r61911 TSI108_CPU_INTACK, 121*7233593bSZang Roy-r61911 TSI108_CPU_EOI, 122*7233593bSZang Roy-r61911 123*7233593bSZang Roy-r61911 TSI108_IRQ_BASE, 124*7233593bSZang Roy-r61911 TSI108_IRQ_STRIDE, 125*7233593bSZang Roy-r61911 TSI108_IRQ_VECTOR_PRI, 126*7233593bSZang Roy-r61911 TSI108_VECPRI_VECTOR_MASK, 127*7233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_POSITIVE, 128*7233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_NEGATIVE, 129*7233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_LEVEL, 130*7233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_EDGE, 131*7233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_MASK, 132*7233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_MASK, 133*7233593bSZang Roy-r61911 TSI108_IRQ_DESTINATION 134*7233593bSZang Roy-r61911 }, 135*7233593bSZang Roy-r61911 }; 136*7233593bSZang Roy-r61911 137*7233593bSZang Roy-r61911 #define MPIC_INFO(name) mpic->hw_set[MPIC_IDX_##name] 138*7233593bSZang Roy-r61911 139*7233593bSZang Roy-r61911 #else /* CONFIG_MPIC_WEIRD */ 140*7233593bSZang Roy-r61911 141*7233593bSZang Roy-r61911 #define MPIC_INFO(name) MPIC_##name 142*7233593bSZang Roy-r61911 143*7233593bSZang Roy-r61911 #endif /* CONFIG_MPIC_WEIRD */ 144*7233593bSZang Roy-r61911 14514cf11afSPaul Mackerras /* 14614cf11afSPaul Mackerras * Register accessor functions 14714cf11afSPaul Mackerras */ 14814cf11afSPaul Mackerras 14914cf11afSPaul Mackerras 15014cf11afSPaul Mackerras static inline u32 _mpic_read(unsigned int be, volatile u32 __iomem *base, 15114cf11afSPaul Mackerras unsigned int reg) 15214cf11afSPaul Mackerras { 15314cf11afSPaul Mackerras if (be) 15414cf11afSPaul Mackerras return in_be32(base + (reg >> 2)); 15514cf11afSPaul Mackerras else 15614cf11afSPaul Mackerras return in_le32(base + (reg >> 2)); 15714cf11afSPaul Mackerras } 15814cf11afSPaul Mackerras 15914cf11afSPaul Mackerras static inline void _mpic_write(unsigned int be, volatile u32 __iomem *base, 16014cf11afSPaul Mackerras unsigned int reg, u32 value) 16114cf11afSPaul Mackerras { 16214cf11afSPaul Mackerras if (be) 16314cf11afSPaul Mackerras out_be32(base + (reg >> 2), value); 16414cf11afSPaul Mackerras else 16514cf11afSPaul Mackerras out_le32(base + (reg >> 2), value); 16614cf11afSPaul Mackerras } 16714cf11afSPaul Mackerras 16814cf11afSPaul Mackerras static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) 16914cf11afSPaul Mackerras { 17014cf11afSPaul Mackerras unsigned int be = (mpic->flags & MPIC_BIG_ENDIAN) != 0; 171*7233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 172*7233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 17314cf11afSPaul Mackerras 17414cf11afSPaul Mackerras if (mpic->flags & MPIC_BROKEN_IPI) 17514cf11afSPaul Mackerras be = !be; 17614cf11afSPaul Mackerras return _mpic_read(be, mpic->gregs, offset); 17714cf11afSPaul Mackerras } 17814cf11afSPaul Mackerras 17914cf11afSPaul Mackerras static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) 18014cf11afSPaul Mackerras { 181*7233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 182*7233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 18314cf11afSPaul Mackerras 18414cf11afSPaul Mackerras _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset, value); 18514cf11afSPaul Mackerras } 18614cf11afSPaul Mackerras 18714cf11afSPaul Mackerras static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) 18814cf11afSPaul Mackerras { 18914cf11afSPaul Mackerras unsigned int cpu = 0; 19014cf11afSPaul Mackerras 19114cf11afSPaul Mackerras if (mpic->flags & MPIC_PRIMARY) 19214cf11afSPaul Mackerras cpu = hard_smp_processor_id(); 193b9e5b4e6SBenjamin Herrenschmidt return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, 194b9e5b4e6SBenjamin Herrenschmidt mpic->cpuregs[cpu], reg); 19514cf11afSPaul Mackerras } 19614cf11afSPaul Mackerras 19714cf11afSPaul Mackerras static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) 19814cf11afSPaul Mackerras { 19914cf11afSPaul Mackerras unsigned int cpu = 0; 20014cf11afSPaul Mackerras 20114cf11afSPaul Mackerras if (mpic->flags & MPIC_PRIMARY) 20214cf11afSPaul Mackerras cpu = hard_smp_processor_id(); 20314cf11afSPaul Mackerras 20414cf11afSPaul Mackerras _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg, value); 20514cf11afSPaul Mackerras } 20614cf11afSPaul Mackerras 20714cf11afSPaul Mackerras static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) 20814cf11afSPaul Mackerras { 20914cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 21014cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 21114cf11afSPaul Mackerras 21214cf11afSPaul Mackerras return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], 213*7233593bSZang Roy-r61911 reg + (idx * MPIC_INFO(IRQ_STRIDE))); 21414cf11afSPaul Mackerras } 21514cf11afSPaul Mackerras 21614cf11afSPaul Mackerras static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, 21714cf11afSPaul Mackerras unsigned int reg, u32 value) 21814cf11afSPaul Mackerras { 21914cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 22014cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 22114cf11afSPaul Mackerras 22214cf11afSPaul Mackerras _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], 223*7233593bSZang Roy-r61911 reg + (idx * MPIC_INFO(IRQ_STRIDE)), value); 22414cf11afSPaul Mackerras } 22514cf11afSPaul Mackerras 22614cf11afSPaul Mackerras #define mpic_read(b,r) _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,(b),(r)) 22714cf11afSPaul Mackerras #define mpic_write(b,r,v) _mpic_write(mpic->flags & MPIC_BIG_ENDIAN,(b),(r),(v)) 22814cf11afSPaul Mackerras #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) 22914cf11afSPaul Mackerras #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) 23014cf11afSPaul Mackerras #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) 23114cf11afSPaul Mackerras #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) 23214cf11afSPaul Mackerras #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) 23314cf11afSPaul Mackerras #define mpic_irq_write(s,r,v) _mpic_irq_write(mpic,(s),(r),(v)) 23414cf11afSPaul Mackerras 23514cf11afSPaul Mackerras 23614cf11afSPaul Mackerras /* 23714cf11afSPaul Mackerras * Low level utility functions 23814cf11afSPaul Mackerras */ 23914cf11afSPaul Mackerras 24014cf11afSPaul Mackerras 24114cf11afSPaul Mackerras 24214cf11afSPaul Mackerras /* Check if we have one of those nice broken MPICs with a flipped endian on 24314cf11afSPaul Mackerras * reads from IPI registers 24414cf11afSPaul Mackerras */ 24514cf11afSPaul Mackerras static void __init mpic_test_broken_ipi(struct mpic *mpic) 24614cf11afSPaul Mackerras { 24714cf11afSPaul Mackerras u32 r; 24814cf11afSPaul Mackerras 249*7233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0), MPIC_VECPRI_MASK); 250*7233593bSZang Roy-r61911 r = mpic_read(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0)); 25114cf11afSPaul Mackerras 25214cf11afSPaul Mackerras if (r == le32_to_cpu(MPIC_VECPRI_MASK)) { 25314cf11afSPaul Mackerras printk(KERN_INFO "mpic: Detected reversed IPI registers\n"); 25414cf11afSPaul Mackerras mpic->flags |= MPIC_BROKEN_IPI; 25514cf11afSPaul Mackerras } 25614cf11afSPaul Mackerras } 25714cf11afSPaul Mackerras 25814cf11afSPaul Mackerras #ifdef CONFIG_MPIC_BROKEN_U3 25914cf11afSPaul Mackerras 26014cf11afSPaul Mackerras /* Test if an interrupt is sourced from HyperTransport (used on broken U3s) 26114cf11afSPaul Mackerras * to force the edge setting on the MPIC and do the ack workaround. 26214cf11afSPaul Mackerras */ 2631beb6a7dSBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 26414cf11afSPaul Mackerras { 2651beb6a7dSBenjamin Herrenschmidt if (source >= 128 || !mpic->fixups) 26614cf11afSPaul Mackerras return 0; 2671beb6a7dSBenjamin Herrenschmidt return mpic->fixups[source].base != NULL; 26814cf11afSPaul Mackerras } 26914cf11afSPaul Mackerras 270c4b22f26SSegher Boessenkool 2711beb6a7dSBenjamin Herrenschmidt static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source) 27214cf11afSPaul Mackerras { 2731beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 27414cf11afSPaul Mackerras 2751beb6a7dSBenjamin Herrenschmidt if (fixup->applebase) { 2761beb6a7dSBenjamin Herrenschmidt unsigned int soff = (fixup->index >> 3) & ~3; 2771beb6a7dSBenjamin Herrenschmidt unsigned int mask = 1U << (fixup->index & 0x1f); 2781beb6a7dSBenjamin Herrenschmidt writel(mask, fixup->applebase + soff); 2791beb6a7dSBenjamin Herrenschmidt } else { 28014cf11afSPaul Mackerras spin_lock(&mpic->fixup_lock); 2811beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * fixup->index, fixup->base + 2); 282c4b22f26SSegher Boessenkool writel(fixup->data, fixup->base + 4); 28314cf11afSPaul Mackerras spin_unlock(&mpic->fixup_lock); 28414cf11afSPaul Mackerras } 2851beb6a7dSBenjamin Herrenschmidt } 28614cf11afSPaul Mackerras 2871beb6a7dSBenjamin Herrenschmidt static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, 2881beb6a7dSBenjamin Herrenschmidt unsigned int irqflags) 2891beb6a7dSBenjamin Herrenschmidt { 2901beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 2911beb6a7dSBenjamin Herrenschmidt unsigned long flags; 2921beb6a7dSBenjamin Herrenschmidt u32 tmp; 29314cf11afSPaul Mackerras 2941beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 2951beb6a7dSBenjamin Herrenschmidt return; 2961beb6a7dSBenjamin Herrenschmidt 29706fe98e6SBenjamin Herrenschmidt DBG("startup_ht_interrupt(0x%x, 0x%x) index: %d\n", 2981beb6a7dSBenjamin Herrenschmidt source, irqflags, fixup->index); 2991beb6a7dSBenjamin Herrenschmidt spin_lock_irqsave(&mpic->fixup_lock, flags); 3001beb6a7dSBenjamin Herrenschmidt /* Enable and configure */ 3011beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 3021beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 3031beb6a7dSBenjamin Herrenschmidt tmp &= ~(0x23U); 3041beb6a7dSBenjamin Herrenschmidt if (irqflags & IRQ_LEVEL) 3051beb6a7dSBenjamin Herrenschmidt tmp |= 0x22; 3061beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 3071beb6a7dSBenjamin Herrenschmidt spin_unlock_irqrestore(&mpic->fixup_lock, flags); 3081beb6a7dSBenjamin Herrenschmidt } 3091beb6a7dSBenjamin Herrenschmidt 3101beb6a7dSBenjamin Herrenschmidt static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, 3111beb6a7dSBenjamin Herrenschmidt unsigned int irqflags) 3121beb6a7dSBenjamin Herrenschmidt { 3131beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 3141beb6a7dSBenjamin Herrenschmidt unsigned long flags; 3151beb6a7dSBenjamin Herrenschmidt u32 tmp; 3161beb6a7dSBenjamin Herrenschmidt 3171beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 3181beb6a7dSBenjamin Herrenschmidt return; 3191beb6a7dSBenjamin Herrenschmidt 32006fe98e6SBenjamin Herrenschmidt DBG("shutdown_ht_interrupt(0x%x, 0x%x)\n", source, irqflags); 3211beb6a7dSBenjamin Herrenschmidt 3221beb6a7dSBenjamin Herrenschmidt /* Disable */ 3231beb6a7dSBenjamin Herrenschmidt spin_lock_irqsave(&mpic->fixup_lock, flags); 3241beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 3251beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 32672b13819SSegher Boessenkool tmp |= 1; 3271beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 3281beb6a7dSBenjamin Herrenschmidt spin_unlock_irqrestore(&mpic->fixup_lock, flags); 3291beb6a7dSBenjamin Herrenschmidt } 3301beb6a7dSBenjamin Herrenschmidt 3311beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, 3321beb6a7dSBenjamin Herrenschmidt unsigned int devfn, u32 vdid) 33314cf11afSPaul Mackerras { 334c4b22f26SSegher Boessenkool int i, irq, n; 3351beb6a7dSBenjamin Herrenschmidt u8 __iomem *base; 33614cf11afSPaul Mackerras u32 tmp; 337c4b22f26SSegher Boessenkool u8 pos; 33814cf11afSPaul Mackerras 3391beb6a7dSBenjamin Herrenschmidt for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; 3401beb6a7dSBenjamin Herrenschmidt pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { 3411beb6a7dSBenjamin Herrenschmidt u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); 3421beb6a7dSBenjamin Herrenschmidt if (id == PCI_CAP_ID_HT_IRQCONF) { 343c4b22f26SSegher Boessenkool id = readb(devbase + pos + 3); 344c4b22f26SSegher Boessenkool if (id == 0x80) 345c4b22f26SSegher Boessenkool break; 346c4b22f26SSegher Boessenkool } 347c4b22f26SSegher Boessenkool } 348c4b22f26SSegher Boessenkool if (pos == 0) 349c4b22f26SSegher Boessenkool return; 350c4b22f26SSegher Boessenkool 3511beb6a7dSBenjamin Herrenschmidt base = devbase + pos; 3521beb6a7dSBenjamin Herrenschmidt writeb(0x01, base + 2); 3531beb6a7dSBenjamin Herrenschmidt n = (readl(base + 4) >> 16) & 0xff; 354c4b22f26SSegher Boessenkool 3551beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x" 3561beb6a7dSBenjamin Herrenschmidt " has %d irqs\n", 3571beb6a7dSBenjamin Herrenschmidt devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1); 358c4b22f26SSegher Boessenkool 359c4b22f26SSegher Boessenkool for (i = 0; i <= n; i++) { 3601beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * i, base + 2); 3611beb6a7dSBenjamin Herrenschmidt tmp = readl(base + 4); 36214cf11afSPaul Mackerras irq = (tmp >> 16) & 0xff; 3631beb6a7dSBenjamin Herrenschmidt DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp); 3641beb6a7dSBenjamin Herrenschmidt /* mask it , will be unmasked later */ 3651beb6a7dSBenjamin Herrenschmidt tmp |= 0x1; 3661beb6a7dSBenjamin Herrenschmidt writel(tmp, base + 4); 3671beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].index = i; 3681beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].base = base; 3691beb6a7dSBenjamin Herrenschmidt /* Apple HT PIC has a non-standard way of doing EOIs */ 3701beb6a7dSBenjamin Herrenschmidt if ((vdid & 0xffff) == 0x106b) 3711beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = devbase + 0x60; 3721beb6a7dSBenjamin Herrenschmidt else 3731beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = NULL; 3741beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * i, base + 2); 3751beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].data = readl(base + 4) | 0x80000000; 37614cf11afSPaul Mackerras } 37714cf11afSPaul Mackerras } 37814cf11afSPaul Mackerras 37914cf11afSPaul Mackerras 3801beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 38114cf11afSPaul Mackerras { 38214cf11afSPaul Mackerras unsigned int devfn; 38314cf11afSPaul Mackerras u8 __iomem *cfgspace; 38414cf11afSPaul Mackerras 3851beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n"); 38614cf11afSPaul Mackerras 38714cf11afSPaul Mackerras /* Allocate fixups array */ 38814cf11afSPaul Mackerras mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); 38914cf11afSPaul Mackerras BUG_ON(mpic->fixups == NULL); 39014cf11afSPaul Mackerras memset(mpic->fixups, 0, 128 * sizeof(struct mpic_irq_fixup)); 39114cf11afSPaul Mackerras 39214cf11afSPaul Mackerras /* Init spinlock */ 39314cf11afSPaul Mackerras spin_lock_init(&mpic->fixup_lock); 39414cf11afSPaul Mackerras 395c4b22f26SSegher Boessenkool /* Map U3 config space. We assume all IO-APICs are on the primary bus 396c4b22f26SSegher Boessenkool * so we only need to map 64kB. 39714cf11afSPaul Mackerras */ 398c4b22f26SSegher Boessenkool cfgspace = ioremap(0xf2000000, 0x10000); 39914cf11afSPaul Mackerras BUG_ON(cfgspace == NULL); 40014cf11afSPaul Mackerras 4011beb6a7dSBenjamin Herrenschmidt /* Now we scan all slots. We do a very quick scan, we read the header 4021beb6a7dSBenjamin Herrenschmidt * type, vendor ID and device ID only, that's plenty enough 40314cf11afSPaul Mackerras */ 404c4b22f26SSegher Boessenkool for (devfn = 0; devfn < 0x100; devfn++) { 40514cf11afSPaul Mackerras u8 __iomem *devbase = cfgspace + (devfn << 8); 40614cf11afSPaul Mackerras u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); 40714cf11afSPaul Mackerras u32 l = readl(devbase + PCI_VENDOR_ID); 4081beb6a7dSBenjamin Herrenschmidt u16 s; 40914cf11afSPaul Mackerras 41014cf11afSPaul Mackerras DBG("devfn %x, l: %x\n", devfn, l); 41114cf11afSPaul Mackerras 41214cf11afSPaul Mackerras /* If no device, skip */ 41314cf11afSPaul Mackerras if (l == 0xffffffff || l == 0x00000000 || 41414cf11afSPaul Mackerras l == 0x0000ffff || l == 0xffff0000) 41514cf11afSPaul Mackerras goto next; 4161beb6a7dSBenjamin Herrenschmidt /* Check if is supports capability lists */ 4171beb6a7dSBenjamin Herrenschmidt s = readw(devbase + PCI_STATUS); 4181beb6a7dSBenjamin Herrenschmidt if (!(s & PCI_STATUS_CAP_LIST)) 4191beb6a7dSBenjamin Herrenschmidt goto next; 42014cf11afSPaul Mackerras 4211beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pic(mpic, devbase, devfn, l); 42214cf11afSPaul Mackerras 42314cf11afSPaul Mackerras next: 42414cf11afSPaul Mackerras /* next device, if function 0 */ 425c4b22f26SSegher Boessenkool if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0) 42614cf11afSPaul Mackerras devfn += 7; 42714cf11afSPaul Mackerras } 42814cf11afSPaul Mackerras } 42914cf11afSPaul Mackerras 4306e99e458SBenjamin Herrenschmidt #else /* CONFIG_MPIC_BROKEN_U3 */ 4316e99e458SBenjamin Herrenschmidt 4326e99e458SBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 4336e99e458SBenjamin Herrenschmidt { 4346e99e458SBenjamin Herrenschmidt return 0; 4356e99e458SBenjamin Herrenschmidt } 4366e99e458SBenjamin Herrenschmidt 4376e99e458SBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 4386e99e458SBenjamin Herrenschmidt { 4396e99e458SBenjamin Herrenschmidt } 4406e99e458SBenjamin Herrenschmidt 44114cf11afSPaul Mackerras #endif /* CONFIG_MPIC_BROKEN_U3 */ 44214cf11afSPaul Mackerras 44314cf11afSPaul Mackerras 4440ebfff14SBenjamin Herrenschmidt #define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) 4450ebfff14SBenjamin Herrenschmidt 44614cf11afSPaul Mackerras /* Find an mpic associated with a given linux interrupt */ 44714cf11afSPaul Mackerras static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) 44814cf11afSPaul Mackerras { 4490ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 45014cf11afSPaul Mackerras 4510ebfff14SBenjamin Herrenschmidt if (irq < NUM_ISA_INTERRUPTS) 45214cf11afSPaul Mackerras return NULL; 4530ebfff14SBenjamin Herrenschmidt if (is_ipi) 4540ebfff14SBenjamin Herrenschmidt *is_ipi = (src >= MPIC_VEC_IPI_0 && src <= MPIC_VEC_IPI_3); 4550ebfff14SBenjamin Herrenschmidt 4560ebfff14SBenjamin Herrenschmidt return irq_desc[irq].chip_data; 45714cf11afSPaul Mackerras } 45814cf11afSPaul Mackerras 45914cf11afSPaul Mackerras /* Convert a cpu mask from logical to physical cpu numbers. */ 46014cf11afSPaul Mackerras static inline u32 mpic_physmask(u32 cpumask) 46114cf11afSPaul Mackerras { 46214cf11afSPaul Mackerras int i; 46314cf11afSPaul Mackerras u32 mask = 0; 46414cf11afSPaul Mackerras 46514cf11afSPaul Mackerras for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1) 46614cf11afSPaul Mackerras mask |= (cpumask & 1) << get_hard_smp_processor_id(i); 46714cf11afSPaul Mackerras return mask; 46814cf11afSPaul Mackerras } 46914cf11afSPaul Mackerras 47014cf11afSPaul Mackerras #ifdef CONFIG_SMP 47114cf11afSPaul Mackerras /* Get the mpic structure from the IPI number */ 47214cf11afSPaul Mackerras static inline struct mpic * mpic_from_ipi(unsigned int ipi) 47314cf11afSPaul Mackerras { 474b9e5b4e6SBenjamin Herrenschmidt return irq_desc[ipi].chip_data; 47514cf11afSPaul Mackerras } 47614cf11afSPaul Mackerras #endif 47714cf11afSPaul Mackerras 47814cf11afSPaul Mackerras /* Get the mpic structure from the irq number */ 47914cf11afSPaul Mackerras static inline struct mpic * mpic_from_irq(unsigned int irq) 48014cf11afSPaul Mackerras { 481b9e5b4e6SBenjamin Herrenschmidt return irq_desc[irq].chip_data; 48214cf11afSPaul Mackerras } 48314cf11afSPaul Mackerras 48414cf11afSPaul Mackerras /* Send an EOI */ 48514cf11afSPaul Mackerras static inline void mpic_eoi(struct mpic *mpic) 48614cf11afSPaul Mackerras { 487*7233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_EOI), 0); 488*7233593bSZang Roy-r61911 (void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI)); 48914cf11afSPaul Mackerras } 49014cf11afSPaul Mackerras 49114cf11afSPaul Mackerras #ifdef CONFIG_SMP 49214cf11afSPaul Mackerras static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) 49314cf11afSPaul Mackerras { 4940ebfff14SBenjamin Herrenschmidt smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0, regs); 49514cf11afSPaul Mackerras return IRQ_HANDLED; 49614cf11afSPaul Mackerras } 49714cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 49814cf11afSPaul Mackerras 49914cf11afSPaul Mackerras /* 50014cf11afSPaul Mackerras * Linux descriptor level callbacks 50114cf11afSPaul Mackerras */ 50214cf11afSPaul Mackerras 50314cf11afSPaul Mackerras 504b9e5b4e6SBenjamin Herrenschmidt static void mpic_unmask_irq(unsigned int irq) 50514cf11afSPaul Mackerras { 50614cf11afSPaul Mackerras unsigned int loops = 100000; 50714cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 5080ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 50914cf11afSPaul Mackerras 510bd561c79SPaul Mackerras DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); 51114cf11afSPaul Mackerras 512*7233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 513*7233593bSZang Roy-r61911 mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & 514e5356640SBenjamin Herrenschmidt ~MPIC_VECPRI_MASK); 51514cf11afSPaul Mackerras /* make sure mask gets to controller before we return to user */ 51614cf11afSPaul Mackerras do { 51714cf11afSPaul Mackerras if (!loops--) { 51814cf11afSPaul Mackerras printk(KERN_ERR "mpic_enable_irq timeout\n"); 51914cf11afSPaul Mackerras break; 52014cf11afSPaul Mackerras } 521*7233593bSZang Roy-r61911 } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK); 5221beb6a7dSBenjamin Herrenschmidt } 5231beb6a7dSBenjamin Herrenschmidt 524b9e5b4e6SBenjamin Herrenschmidt static void mpic_mask_irq(unsigned int irq) 52514cf11afSPaul Mackerras { 52614cf11afSPaul Mackerras unsigned int loops = 100000; 52714cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 5280ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 52914cf11afSPaul Mackerras 53014cf11afSPaul Mackerras DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); 53114cf11afSPaul Mackerras 532*7233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 533*7233593bSZang Roy-r61911 mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) | 534e5356640SBenjamin Herrenschmidt MPIC_VECPRI_MASK); 53514cf11afSPaul Mackerras 53614cf11afSPaul Mackerras /* make sure mask gets to controller before we return to user */ 53714cf11afSPaul Mackerras do { 53814cf11afSPaul Mackerras if (!loops--) { 53914cf11afSPaul Mackerras printk(KERN_ERR "mpic_enable_irq timeout\n"); 54014cf11afSPaul Mackerras break; 54114cf11afSPaul Mackerras } 542*7233593bSZang Roy-r61911 } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK)); 54314cf11afSPaul Mackerras } 54414cf11afSPaul Mackerras 54514cf11afSPaul Mackerras static void mpic_end_irq(unsigned int irq) 54614cf11afSPaul Mackerras { 54714cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 54814cf11afSPaul Mackerras 5491beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_IRQ 55014cf11afSPaul Mackerras DBG("%s: end_irq: %d\n", mpic->name, irq); 5511beb6a7dSBenjamin Herrenschmidt #endif 55214cf11afSPaul Mackerras /* We always EOI on end_irq() even for edge interrupts since that 55314cf11afSPaul Mackerras * should only lower the priority, the MPIC should have properly 55414cf11afSPaul Mackerras * latched another edge interrupt coming in anyway 55514cf11afSPaul Mackerras */ 55614cf11afSPaul Mackerras 55714cf11afSPaul Mackerras mpic_eoi(mpic); 55814cf11afSPaul Mackerras } 55914cf11afSPaul Mackerras 560b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_MPIC_BROKEN_U3 561b9e5b4e6SBenjamin Herrenschmidt 562b9e5b4e6SBenjamin Herrenschmidt static void mpic_unmask_ht_irq(unsigned int irq) 563b9e5b4e6SBenjamin Herrenschmidt { 564b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 5650ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 566b9e5b4e6SBenjamin Herrenschmidt 567b9e5b4e6SBenjamin Herrenschmidt mpic_unmask_irq(irq); 568b9e5b4e6SBenjamin Herrenschmidt 569b9e5b4e6SBenjamin Herrenschmidt if (irq_desc[irq].status & IRQ_LEVEL) 570b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 571b9e5b4e6SBenjamin Herrenschmidt } 572b9e5b4e6SBenjamin Herrenschmidt 573b9e5b4e6SBenjamin Herrenschmidt static unsigned int mpic_startup_ht_irq(unsigned int irq) 574b9e5b4e6SBenjamin Herrenschmidt { 575b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 5760ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 577b9e5b4e6SBenjamin Herrenschmidt 578b9e5b4e6SBenjamin Herrenschmidt mpic_unmask_irq(irq); 579b9e5b4e6SBenjamin Herrenschmidt mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); 580b9e5b4e6SBenjamin Herrenschmidt 581b9e5b4e6SBenjamin Herrenschmidt return 0; 582b9e5b4e6SBenjamin Herrenschmidt } 583b9e5b4e6SBenjamin Herrenschmidt 584b9e5b4e6SBenjamin Herrenschmidt static void mpic_shutdown_ht_irq(unsigned int irq) 585b9e5b4e6SBenjamin Herrenschmidt { 586b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 5870ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 588b9e5b4e6SBenjamin Herrenschmidt 589b9e5b4e6SBenjamin Herrenschmidt mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); 590b9e5b4e6SBenjamin Herrenschmidt mpic_mask_irq(irq); 591b9e5b4e6SBenjamin Herrenschmidt } 592b9e5b4e6SBenjamin Herrenschmidt 593b9e5b4e6SBenjamin Herrenschmidt static void mpic_end_ht_irq(unsigned int irq) 594b9e5b4e6SBenjamin Herrenschmidt { 595b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 5960ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 597b9e5b4e6SBenjamin Herrenschmidt 598b9e5b4e6SBenjamin Herrenschmidt #ifdef DEBUG_IRQ 599b9e5b4e6SBenjamin Herrenschmidt DBG("%s: end_irq: %d\n", mpic->name, irq); 600b9e5b4e6SBenjamin Herrenschmidt #endif 601b9e5b4e6SBenjamin Herrenschmidt /* We always EOI on end_irq() even for edge interrupts since that 602b9e5b4e6SBenjamin Herrenschmidt * should only lower the priority, the MPIC should have properly 603b9e5b4e6SBenjamin Herrenschmidt * latched another edge interrupt coming in anyway 604b9e5b4e6SBenjamin Herrenschmidt */ 605b9e5b4e6SBenjamin Herrenschmidt 606b9e5b4e6SBenjamin Herrenschmidt if (irq_desc[irq].status & IRQ_LEVEL) 607b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 608b9e5b4e6SBenjamin Herrenschmidt mpic_eoi(mpic); 609b9e5b4e6SBenjamin Herrenschmidt } 6106e99e458SBenjamin Herrenschmidt #endif /* !CONFIG_MPIC_BROKEN_U3 */ 611b9e5b4e6SBenjamin Herrenschmidt 61214cf11afSPaul Mackerras #ifdef CONFIG_SMP 61314cf11afSPaul Mackerras 614b9e5b4e6SBenjamin Herrenschmidt static void mpic_unmask_ipi(unsigned int irq) 61514cf11afSPaul Mackerras { 61614cf11afSPaul Mackerras struct mpic *mpic = mpic_from_ipi(irq); 6170ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0; 61814cf11afSPaul Mackerras 61914cf11afSPaul Mackerras DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); 62014cf11afSPaul Mackerras mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); 62114cf11afSPaul Mackerras } 62214cf11afSPaul Mackerras 623b9e5b4e6SBenjamin Herrenschmidt static void mpic_mask_ipi(unsigned int irq) 62414cf11afSPaul Mackerras { 62514cf11afSPaul Mackerras /* NEVER disable an IPI... that's just plain wrong! */ 62614cf11afSPaul Mackerras } 62714cf11afSPaul Mackerras 62814cf11afSPaul Mackerras static void mpic_end_ipi(unsigned int irq) 62914cf11afSPaul Mackerras { 63014cf11afSPaul Mackerras struct mpic *mpic = mpic_from_ipi(irq); 63114cf11afSPaul Mackerras 63214cf11afSPaul Mackerras /* 63314cf11afSPaul Mackerras * IPIs are marked IRQ_PER_CPU. This has the side effect of 63414cf11afSPaul Mackerras * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from 63514cf11afSPaul Mackerras * applying to them. We EOI them late to avoid re-entering. 6366714465eSThomas Gleixner * We mark IPI's with IRQF_DISABLED as they must run with 63714cf11afSPaul Mackerras * irqs disabled. 63814cf11afSPaul Mackerras */ 63914cf11afSPaul Mackerras mpic_eoi(mpic); 64014cf11afSPaul Mackerras } 64114cf11afSPaul Mackerras 64214cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 64314cf11afSPaul Mackerras 64414cf11afSPaul Mackerras static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) 64514cf11afSPaul Mackerras { 64614cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 6470ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 64814cf11afSPaul Mackerras 64914cf11afSPaul Mackerras cpumask_t tmp; 65014cf11afSPaul Mackerras 65114cf11afSPaul Mackerras cpus_and(tmp, cpumask, cpu_online_map); 65214cf11afSPaul Mackerras 653*7233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 65414cf11afSPaul Mackerras mpic_physmask(cpus_addr(tmp)[0])); 65514cf11afSPaul Mackerras } 65614cf11afSPaul Mackerras 657*7233593bSZang Roy-r61911 static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) 6580ebfff14SBenjamin Herrenschmidt { 6590ebfff14SBenjamin Herrenschmidt /* Now convert sense value */ 6606e99e458SBenjamin Herrenschmidt switch(type & IRQ_TYPE_SENSE_MASK) { 6610ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_RISING: 662*7233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 663*7233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 6640ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_FALLING: 6656e99e458SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_BOTH: 666*7233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 667*7233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 6680ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_HIGH: 669*7233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 670*7233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 6710ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_LOW: 6720ebfff14SBenjamin Herrenschmidt default: 673*7233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 674*7233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 6750ebfff14SBenjamin Herrenschmidt } 6766e99e458SBenjamin Herrenschmidt } 6776e99e458SBenjamin Herrenschmidt 6786e99e458SBenjamin Herrenschmidt static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) 6796e99e458SBenjamin Herrenschmidt { 6806e99e458SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(virq); 6816e99e458SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(virq); 6826e99e458SBenjamin Herrenschmidt struct irq_desc *desc = get_irq_desc(virq); 6836e99e458SBenjamin Herrenschmidt unsigned int vecpri, vold, vnew; 6846e99e458SBenjamin Herrenschmidt 68506fe98e6SBenjamin Herrenschmidt DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", 6866e99e458SBenjamin Herrenschmidt mpic, virq, src, flow_type); 6876e99e458SBenjamin Herrenschmidt 6886e99e458SBenjamin Herrenschmidt if (src >= mpic->irq_count) 6896e99e458SBenjamin Herrenschmidt return -EINVAL; 6906e99e458SBenjamin Herrenschmidt 6916e99e458SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_NONE) 6926e99e458SBenjamin Herrenschmidt if (mpic->senses && src < mpic->senses_count) 6936e99e458SBenjamin Herrenschmidt flow_type = mpic->senses[src]; 6946e99e458SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_NONE) 6956e99e458SBenjamin Herrenschmidt flow_type = IRQ_TYPE_LEVEL_LOW; 6966e99e458SBenjamin Herrenschmidt 6976e99e458SBenjamin Herrenschmidt desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); 6986e99e458SBenjamin Herrenschmidt desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; 6996e99e458SBenjamin Herrenschmidt if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) 7006e99e458SBenjamin Herrenschmidt desc->status |= IRQ_LEVEL; 7016e99e458SBenjamin Herrenschmidt 7026e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, src)) 7036e99e458SBenjamin Herrenschmidt vecpri = MPIC_VECPRI_POLARITY_POSITIVE | 7046e99e458SBenjamin Herrenschmidt MPIC_VECPRI_SENSE_EDGE; 7056e99e458SBenjamin Herrenschmidt else 706*7233593bSZang Roy-r61911 vecpri = mpic_type_to_vecpri(mpic, flow_type); 7076e99e458SBenjamin Herrenschmidt 708*7233593bSZang Roy-r61911 vold = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 709*7233593bSZang Roy-r61911 vnew = vold & ~(MPIC_INFO(VECPRI_POLARITY_MASK) | 710*7233593bSZang Roy-r61911 MPIC_INFO(VECPRI_SENSE_MASK)); 7116e99e458SBenjamin Herrenschmidt vnew |= vecpri; 7126e99e458SBenjamin Herrenschmidt if (vold != vnew) 713*7233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); 7146e99e458SBenjamin Herrenschmidt 7156e99e458SBenjamin Herrenschmidt return 0; 7160ebfff14SBenjamin Herrenschmidt } 7170ebfff14SBenjamin Herrenschmidt 718b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_chip = { 719b9e5b4e6SBenjamin Herrenschmidt .mask = mpic_mask_irq, 720b9e5b4e6SBenjamin Herrenschmidt .unmask = mpic_unmask_irq, 721b9e5b4e6SBenjamin Herrenschmidt .eoi = mpic_end_irq, 7226e99e458SBenjamin Herrenschmidt .set_type = mpic_set_irq_type, 723b9e5b4e6SBenjamin Herrenschmidt }; 724b9e5b4e6SBenjamin Herrenschmidt 725b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_SMP 726b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_ipi_chip = { 727b9e5b4e6SBenjamin Herrenschmidt .mask = mpic_mask_ipi, 728b9e5b4e6SBenjamin Herrenschmidt .unmask = mpic_unmask_ipi, 729b9e5b4e6SBenjamin Herrenschmidt .eoi = mpic_end_ipi, 730b9e5b4e6SBenjamin Herrenschmidt }; 731b9e5b4e6SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 732b9e5b4e6SBenjamin Herrenschmidt 733b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_MPIC_BROKEN_U3 734b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_ht_chip = { 735b9e5b4e6SBenjamin Herrenschmidt .startup = mpic_startup_ht_irq, 736b9e5b4e6SBenjamin Herrenschmidt .shutdown = mpic_shutdown_ht_irq, 737b9e5b4e6SBenjamin Herrenschmidt .mask = mpic_mask_irq, 738b9e5b4e6SBenjamin Herrenschmidt .unmask = mpic_unmask_ht_irq, 739b9e5b4e6SBenjamin Herrenschmidt .eoi = mpic_end_ht_irq, 7406e99e458SBenjamin Herrenschmidt .set_type = mpic_set_irq_type, 741b9e5b4e6SBenjamin Herrenschmidt }; 742b9e5b4e6SBenjamin Herrenschmidt #endif /* CONFIG_MPIC_BROKEN_U3 */ 743b9e5b4e6SBenjamin Herrenschmidt 74414cf11afSPaul Mackerras 7450ebfff14SBenjamin Herrenschmidt static int mpic_host_match(struct irq_host *h, struct device_node *node) 7460ebfff14SBenjamin Herrenschmidt { 7470ebfff14SBenjamin Herrenschmidt struct mpic *mpic = h->host_data; 7480ebfff14SBenjamin Herrenschmidt 7490ebfff14SBenjamin Herrenschmidt /* Exact match, unless mpic node is NULL */ 7500ebfff14SBenjamin Herrenschmidt return mpic->of_node == NULL || mpic->of_node == node; 7510ebfff14SBenjamin Herrenschmidt } 7520ebfff14SBenjamin Herrenschmidt 7530ebfff14SBenjamin Herrenschmidt static int mpic_host_map(struct irq_host *h, unsigned int virq, 7546e99e458SBenjamin Herrenschmidt irq_hw_number_t hw) 7550ebfff14SBenjamin Herrenschmidt { 7560ebfff14SBenjamin Herrenschmidt struct mpic *mpic = h->host_data; 7576e99e458SBenjamin Herrenschmidt struct irq_chip *chip; 7580ebfff14SBenjamin Herrenschmidt 75906fe98e6SBenjamin Herrenschmidt DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw); 7600ebfff14SBenjamin Herrenschmidt 7610ebfff14SBenjamin Herrenschmidt if (hw == MPIC_VEC_SPURRIOUS) 7620ebfff14SBenjamin Herrenschmidt return -EINVAL; 76306fe98e6SBenjamin Herrenschmidt 7640ebfff14SBenjamin Herrenschmidt #ifdef CONFIG_SMP 7650ebfff14SBenjamin Herrenschmidt else if (hw >= MPIC_VEC_IPI_0) { 7660ebfff14SBenjamin Herrenschmidt WARN_ON(!(mpic->flags & MPIC_PRIMARY)); 7670ebfff14SBenjamin Herrenschmidt 76806fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping as IPI\n"); 7690ebfff14SBenjamin Herrenschmidt set_irq_chip_data(virq, mpic); 7700ebfff14SBenjamin Herrenschmidt set_irq_chip_and_handler(virq, &mpic->hc_ipi, 7710ebfff14SBenjamin Herrenschmidt handle_percpu_irq); 7720ebfff14SBenjamin Herrenschmidt return 0; 7730ebfff14SBenjamin Herrenschmidt } 7740ebfff14SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 7750ebfff14SBenjamin Herrenschmidt 7760ebfff14SBenjamin Herrenschmidt if (hw >= mpic->irq_count) 7770ebfff14SBenjamin Herrenschmidt return -EINVAL; 7780ebfff14SBenjamin Herrenschmidt 7796e99e458SBenjamin Herrenschmidt /* Default chip */ 7800ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_irq; 7810ebfff14SBenjamin Herrenschmidt 7820ebfff14SBenjamin Herrenschmidt #ifdef CONFIG_MPIC_BROKEN_U3 7830ebfff14SBenjamin Herrenschmidt /* Check for HT interrupts, override vecpri */ 7846e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, hw)) 7850ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_ht_irq; 7866e99e458SBenjamin Herrenschmidt #endif /* CONFIG_MPIC_BROKEN_U3 */ 7870ebfff14SBenjamin Herrenschmidt 78806fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping to irq chip @%p\n", chip); 7890ebfff14SBenjamin Herrenschmidt 7900ebfff14SBenjamin Herrenschmidt set_irq_chip_data(virq, mpic); 7910ebfff14SBenjamin Herrenschmidt set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); 7926e99e458SBenjamin Herrenschmidt 7936e99e458SBenjamin Herrenschmidt /* Set default irq type */ 7946e99e458SBenjamin Herrenschmidt set_irq_type(virq, IRQ_TYPE_NONE); 7956e99e458SBenjamin Herrenschmidt 7960ebfff14SBenjamin Herrenschmidt return 0; 7970ebfff14SBenjamin Herrenschmidt } 7980ebfff14SBenjamin Herrenschmidt 7990ebfff14SBenjamin Herrenschmidt static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, 8000ebfff14SBenjamin Herrenschmidt u32 *intspec, unsigned int intsize, 8010ebfff14SBenjamin Herrenschmidt irq_hw_number_t *out_hwirq, unsigned int *out_flags) 8020ebfff14SBenjamin Herrenschmidt 8030ebfff14SBenjamin Herrenschmidt { 8040ebfff14SBenjamin Herrenschmidt static unsigned char map_mpic_senses[4] = { 8050ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_RISING, 8060ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_LOW, 8070ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_HIGH, 8080ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_FALLING, 8090ebfff14SBenjamin Herrenschmidt }; 8100ebfff14SBenjamin Herrenschmidt 8110ebfff14SBenjamin Herrenschmidt *out_hwirq = intspec[0]; 81206fe98e6SBenjamin Herrenschmidt if (intsize > 1) { 81306fe98e6SBenjamin Herrenschmidt u32 mask = 0x3; 81406fe98e6SBenjamin Herrenschmidt 81506fe98e6SBenjamin Herrenschmidt /* Apple invented a new race of encoding on machines with 81606fe98e6SBenjamin Herrenschmidt * an HT APIC. They encode, among others, the index within 81706fe98e6SBenjamin Herrenschmidt * the HT APIC. We don't care about it here since thankfully, 81806fe98e6SBenjamin Herrenschmidt * it appears that they have the APIC already properly 81906fe98e6SBenjamin Herrenschmidt * configured, and thus our current fixup code that reads the 82006fe98e6SBenjamin Herrenschmidt * APIC config works fine. However, we still need to mask out 82106fe98e6SBenjamin Herrenschmidt * bits in the specifier to make sure we only get bit 0 which 82206fe98e6SBenjamin Herrenschmidt * is the level/edge bit (the only sense bit exposed by Apple), 82306fe98e6SBenjamin Herrenschmidt * as their bit 1 means something else. 82406fe98e6SBenjamin Herrenschmidt */ 82506fe98e6SBenjamin Herrenschmidt if (machine_is(powermac)) 82606fe98e6SBenjamin Herrenschmidt mask = 0x1; 82706fe98e6SBenjamin Herrenschmidt *out_flags = map_mpic_senses[intspec[1] & mask]; 82806fe98e6SBenjamin Herrenschmidt } else 8290ebfff14SBenjamin Herrenschmidt *out_flags = IRQ_TYPE_NONE; 8300ebfff14SBenjamin Herrenschmidt 83106fe98e6SBenjamin Herrenschmidt DBG("mpic: xlate (%d cells: 0x%08x 0x%08x) to line 0x%lx sense 0x%x\n", 83206fe98e6SBenjamin Herrenschmidt intsize, intspec[0], intspec[1], *out_hwirq, *out_flags); 83306fe98e6SBenjamin Herrenschmidt 8340ebfff14SBenjamin Herrenschmidt return 0; 8350ebfff14SBenjamin Herrenschmidt } 8360ebfff14SBenjamin Herrenschmidt 8370ebfff14SBenjamin Herrenschmidt static struct irq_host_ops mpic_host_ops = { 8380ebfff14SBenjamin Herrenschmidt .match = mpic_host_match, 8390ebfff14SBenjamin Herrenschmidt .map = mpic_host_map, 8400ebfff14SBenjamin Herrenschmidt .xlate = mpic_host_xlate, 8410ebfff14SBenjamin Herrenschmidt }; 8420ebfff14SBenjamin Herrenschmidt 84314cf11afSPaul Mackerras /* 84414cf11afSPaul Mackerras * Exported functions 84514cf11afSPaul Mackerras */ 84614cf11afSPaul Mackerras 8470ebfff14SBenjamin Herrenschmidt struct mpic * __init mpic_alloc(struct device_node *node, 8480ebfff14SBenjamin Herrenschmidt unsigned long phys_addr, 84914cf11afSPaul Mackerras unsigned int flags, 85014cf11afSPaul Mackerras unsigned int isu_size, 85114cf11afSPaul Mackerras unsigned int irq_count, 85214cf11afSPaul Mackerras const char *name) 85314cf11afSPaul Mackerras { 85414cf11afSPaul Mackerras struct mpic *mpic; 85514cf11afSPaul Mackerras u32 reg; 85614cf11afSPaul Mackerras const char *vers; 85714cf11afSPaul Mackerras int i; 85814cf11afSPaul Mackerras 85914cf11afSPaul Mackerras mpic = alloc_bootmem(sizeof(struct mpic)); 86014cf11afSPaul Mackerras if (mpic == NULL) 86114cf11afSPaul Mackerras return NULL; 86214cf11afSPaul Mackerras 86314cf11afSPaul Mackerras memset(mpic, 0, sizeof(struct mpic)); 86414cf11afSPaul Mackerras mpic->name = name; 8650ebfff14SBenjamin Herrenschmidt mpic->of_node = node ? of_node_get(node) : NULL; 86614cf11afSPaul Mackerras 8670ebfff14SBenjamin Herrenschmidt mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 256, 8680ebfff14SBenjamin Herrenschmidt &mpic_host_ops, 8690ebfff14SBenjamin Herrenschmidt MPIC_VEC_SPURRIOUS); 8700ebfff14SBenjamin Herrenschmidt if (mpic->irqhost == NULL) { 8710ebfff14SBenjamin Herrenschmidt of_node_put(node); 8720ebfff14SBenjamin Herrenschmidt return NULL; 8730ebfff14SBenjamin Herrenschmidt } 8740ebfff14SBenjamin Herrenschmidt 8750ebfff14SBenjamin Herrenschmidt mpic->irqhost->host_data = mpic; 876b9e5b4e6SBenjamin Herrenschmidt mpic->hc_irq = mpic_irq_chip; 87714cf11afSPaul Mackerras mpic->hc_irq.typename = name; 87814cf11afSPaul Mackerras if (flags & MPIC_PRIMARY) 87914cf11afSPaul Mackerras mpic->hc_irq.set_affinity = mpic_set_affinity; 880b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_MPIC_BROKEN_U3 881b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq = mpic_irq_ht_chip; 882b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq.typename = name; 883b9e5b4e6SBenjamin Herrenschmidt if (flags & MPIC_PRIMARY) 884b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq.set_affinity = mpic_set_affinity; 885b9e5b4e6SBenjamin Herrenschmidt #endif /* CONFIG_MPIC_BROKEN_U3 */ 88614cf11afSPaul Mackerras #ifdef CONFIG_SMP 887b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ipi = mpic_ipi_chip; 8880ebfff14SBenjamin Herrenschmidt mpic->hc_ipi.typename = name; 88914cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 89014cf11afSPaul Mackerras 89114cf11afSPaul Mackerras mpic->flags = flags; 89214cf11afSPaul Mackerras mpic->isu_size = isu_size; 89314cf11afSPaul Mackerras mpic->irq_count = irq_count; 89414cf11afSPaul Mackerras mpic->num_sources = 0; /* so far */ 89514cf11afSPaul Mackerras 896*7233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 897*7233593bSZang Roy-r61911 mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; 898*7233593bSZang Roy-r61911 #endif 899*7233593bSZang Roy-r61911 90014cf11afSPaul Mackerras /* Map the global registers */ 901*7233593bSZang Roy-r61911 mpic->gregs = ioremap(phys_addr + MPIC_INFO(GREG_BASE), 0x1000); 902*7233593bSZang Roy-r61911 mpic->tmregs = mpic->gregs + 903*7233593bSZang Roy-r61911 ((MPIC_INFO(TIMER_BASE) - MPIC_INFO(GREG_BASE)) >> 2); 90414cf11afSPaul Mackerras BUG_ON(mpic->gregs == NULL); 90514cf11afSPaul Mackerras 90614cf11afSPaul Mackerras /* Reset */ 90714cf11afSPaul Mackerras if (flags & MPIC_WANTS_RESET) { 908*7233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 909*7233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 91014cf11afSPaul Mackerras | MPIC_GREG_GCONF_RESET); 911*7233593bSZang Roy-r61911 while( mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 91214cf11afSPaul Mackerras & MPIC_GREG_GCONF_RESET) 91314cf11afSPaul Mackerras mb(); 91414cf11afSPaul Mackerras } 91514cf11afSPaul Mackerras 91614cf11afSPaul Mackerras /* Read feature register, calculate num CPUs and, for non-ISU 91714cf11afSPaul Mackerras * MPICs, num sources as well. On ISU MPICs, sources are counted 91814cf11afSPaul Mackerras * as ISUs are added 91914cf11afSPaul Mackerras */ 920*7233593bSZang Roy-r61911 reg = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); 92114cf11afSPaul Mackerras mpic->num_cpus = ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK) 92214cf11afSPaul Mackerras >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1; 92314cf11afSPaul Mackerras if (isu_size == 0) 92414cf11afSPaul Mackerras mpic->num_sources = ((reg & MPIC_GREG_FEATURE_LAST_SRC_MASK) 92514cf11afSPaul Mackerras >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; 92614cf11afSPaul Mackerras 92714cf11afSPaul Mackerras /* Map the per-CPU registers */ 92814cf11afSPaul Mackerras for (i = 0; i < mpic->num_cpus; i++) { 929*7233593bSZang Roy-r61911 mpic->cpuregs[i] = ioremap(phys_addr + MPIC_INFO(CPU_BASE) + 930*7233593bSZang Roy-r61911 i * MPIC_INFO(CPU_STRIDE), 0x1000); 93114cf11afSPaul Mackerras BUG_ON(mpic->cpuregs[i] == NULL); 93214cf11afSPaul Mackerras } 93314cf11afSPaul Mackerras 93414cf11afSPaul Mackerras /* Initialize main ISU if none provided */ 93514cf11afSPaul Mackerras if (mpic->isu_size == 0) { 93614cf11afSPaul Mackerras mpic->isu_size = mpic->num_sources; 937*7233593bSZang Roy-r61911 mpic->isus[0] = ioremap(phys_addr + MPIC_INFO(IRQ_BASE), 938*7233593bSZang Roy-r61911 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); 93914cf11afSPaul Mackerras BUG_ON(mpic->isus[0] == NULL); 94014cf11afSPaul Mackerras } 94114cf11afSPaul Mackerras mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); 94214cf11afSPaul Mackerras mpic->isu_mask = (1 << mpic->isu_shift) - 1; 94314cf11afSPaul Mackerras 94414cf11afSPaul Mackerras /* Display version */ 94514cf11afSPaul Mackerras switch (reg & MPIC_GREG_FEATURE_VERSION_MASK) { 94614cf11afSPaul Mackerras case 1: 94714cf11afSPaul Mackerras vers = "1.0"; 94814cf11afSPaul Mackerras break; 94914cf11afSPaul Mackerras case 2: 95014cf11afSPaul Mackerras vers = "1.2"; 95114cf11afSPaul Mackerras break; 95214cf11afSPaul Mackerras case 3: 95314cf11afSPaul Mackerras vers = "1.3"; 95414cf11afSPaul Mackerras break; 95514cf11afSPaul Mackerras default: 95614cf11afSPaul Mackerras vers = "<unknown>"; 95714cf11afSPaul Mackerras break; 95814cf11afSPaul Mackerras } 95914cf11afSPaul Mackerras printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %lx, max %d CPUs\n", 96014cf11afSPaul Mackerras name, vers, phys_addr, mpic->num_cpus); 96114cf11afSPaul Mackerras printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size, 96214cf11afSPaul Mackerras mpic->isu_shift, mpic->isu_mask); 96314cf11afSPaul Mackerras 96414cf11afSPaul Mackerras mpic->next = mpics; 96514cf11afSPaul Mackerras mpics = mpic; 96614cf11afSPaul Mackerras 9670ebfff14SBenjamin Herrenschmidt if (flags & MPIC_PRIMARY) { 96814cf11afSPaul Mackerras mpic_primary = mpic; 9690ebfff14SBenjamin Herrenschmidt irq_set_default_host(mpic->irqhost); 9700ebfff14SBenjamin Herrenschmidt } 97114cf11afSPaul Mackerras 97214cf11afSPaul Mackerras return mpic; 97314cf11afSPaul Mackerras } 97414cf11afSPaul Mackerras 97514cf11afSPaul Mackerras void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, 97614cf11afSPaul Mackerras unsigned long phys_addr) 97714cf11afSPaul Mackerras { 97814cf11afSPaul Mackerras unsigned int isu_first = isu_num * mpic->isu_size; 97914cf11afSPaul Mackerras 98014cf11afSPaul Mackerras BUG_ON(isu_num >= MPIC_MAX_ISU); 98114cf11afSPaul Mackerras 982*7233593bSZang Roy-r61911 mpic->isus[isu_num] = ioremap(phys_addr, 983*7233593bSZang Roy-r61911 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); 98414cf11afSPaul Mackerras if ((isu_first + mpic->isu_size) > mpic->num_sources) 98514cf11afSPaul Mackerras mpic->num_sources = isu_first + mpic->isu_size; 98614cf11afSPaul Mackerras } 98714cf11afSPaul Mackerras 9880ebfff14SBenjamin Herrenschmidt void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count) 9890ebfff14SBenjamin Herrenschmidt { 9900ebfff14SBenjamin Herrenschmidt mpic->senses = senses; 9910ebfff14SBenjamin Herrenschmidt mpic->senses_count = count; 9920ebfff14SBenjamin Herrenschmidt } 9930ebfff14SBenjamin Herrenschmidt 99414cf11afSPaul Mackerras void __init mpic_init(struct mpic *mpic) 99514cf11afSPaul Mackerras { 99614cf11afSPaul Mackerras int i; 99714cf11afSPaul Mackerras 99814cf11afSPaul Mackerras BUG_ON(mpic->num_sources == 0); 9990ebfff14SBenjamin Herrenschmidt WARN_ON(mpic->num_sources > MPIC_VEC_IPI_0); 10000ebfff14SBenjamin Herrenschmidt 10010ebfff14SBenjamin Herrenschmidt /* Sanitize source count */ 10020ebfff14SBenjamin Herrenschmidt if (mpic->num_sources > MPIC_VEC_IPI_0) 10030ebfff14SBenjamin Herrenschmidt mpic->num_sources = MPIC_VEC_IPI_0; 100414cf11afSPaul Mackerras 100514cf11afSPaul Mackerras printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); 100614cf11afSPaul Mackerras 100714cf11afSPaul Mackerras /* Set current processor priority to max */ 1008*7233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 100914cf11afSPaul Mackerras 101014cf11afSPaul Mackerras /* Initialize timers: just disable them all */ 101114cf11afSPaul Mackerras for (i = 0; i < 4; i++) { 101214cf11afSPaul Mackerras mpic_write(mpic->tmregs, 1013*7233593bSZang Roy-r61911 i * MPIC_INFO(TIMER_STRIDE) + 1014*7233593bSZang Roy-r61911 MPIC_INFO(TIMER_DESTINATION), 0); 101514cf11afSPaul Mackerras mpic_write(mpic->tmregs, 1016*7233593bSZang Roy-r61911 i * MPIC_INFO(TIMER_STRIDE) + 1017*7233593bSZang Roy-r61911 MPIC_INFO(TIMER_VECTOR_PRI), 101814cf11afSPaul Mackerras MPIC_VECPRI_MASK | 101914cf11afSPaul Mackerras (MPIC_VEC_TIMER_0 + i)); 102014cf11afSPaul Mackerras } 102114cf11afSPaul Mackerras 102214cf11afSPaul Mackerras /* Initialize IPIs to our reserved vectors and mark them disabled for now */ 102314cf11afSPaul Mackerras mpic_test_broken_ipi(mpic); 102414cf11afSPaul Mackerras for (i = 0; i < 4; i++) { 102514cf11afSPaul Mackerras mpic_ipi_write(i, 102614cf11afSPaul Mackerras MPIC_VECPRI_MASK | 102714cf11afSPaul Mackerras (10 << MPIC_VECPRI_PRIORITY_SHIFT) | 102814cf11afSPaul Mackerras (MPIC_VEC_IPI_0 + i)); 102914cf11afSPaul Mackerras } 103014cf11afSPaul Mackerras 103114cf11afSPaul Mackerras /* Initialize interrupt sources */ 103214cf11afSPaul Mackerras if (mpic->irq_count == 0) 103314cf11afSPaul Mackerras mpic->irq_count = mpic->num_sources; 103414cf11afSPaul Mackerras 10351beb6a7dSBenjamin Herrenschmidt /* Do the HT PIC fixups on U3 broken mpic */ 103614cf11afSPaul Mackerras DBG("MPIC flags: %x\n", mpic->flags); 103714cf11afSPaul Mackerras if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) 10381beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pics(mpic); 103914cf11afSPaul Mackerras 104014cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources; i++) { 104114cf11afSPaul Mackerras /* start with vector = source number, and masked */ 10426e99e458SBenjamin Herrenschmidt u32 vecpri = MPIC_VECPRI_MASK | i | 10436e99e458SBenjamin Herrenschmidt (8 << MPIC_VECPRI_PRIORITY_SHIFT); 104414cf11afSPaul Mackerras 104514cf11afSPaul Mackerras /* init hw */ 1046*7233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); 1047*7233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 104814cf11afSPaul Mackerras 1 << hard_smp_processor_id()); 104914cf11afSPaul Mackerras } 105014cf11afSPaul Mackerras 105114cf11afSPaul Mackerras /* Init spurrious vector */ 1052*7233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), MPIC_VEC_SPURRIOUS); 105314cf11afSPaul Mackerras 1054*7233593bSZang Roy-r61911 /* Disable 8259 passthrough, if supported */ 1055*7233593bSZang Roy-r61911 if (!(mpic->flags & MPIC_NO_PTHROU_DIS)) 1056*7233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1057*7233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 105814cf11afSPaul Mackerras | MPIC_GREG_GCONF_8259_PTHROU_DIS); 105914cf11afSPaul Mackerras 106014cf11afSPaul Mackerras /* Set current processor priority to 0 */ 1061*7233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 106214cf11afSPaul Mackerras } 106314cf11afSPaul Mackerras 1064868ea0c9SMark A. Greer void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) 1065868ea0c9SMark A. Greer { 1066868ea0c9SMark A. Greer u32 v; 106714cf11afSPaul Mackerras 1068868ea0c9SMark A. Greer v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 1069868ea0c9SMark A. Greer v &= ~MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK; 1070868ea0c9SMark A. Greer v |= MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(clock_ratio); 1071868ea0c9SMark A. Greer mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 1072868ea0c9SMark A. Greer } 1073868ea0c9SMark A. Greer 1074868ea0c9SMark A. Greer void __init mpic_set_serial_int(struct mpic *mpic, int enable) 1075868ea0c9SMark A. Greer { 1076ba1826e5SBenjamin Herrenschmidt unsigned long flags; 1077868ea0c9SMark A. Greer u32 v; 1078868ea0c9SMark A. Greer 1079ba1826e5SBenjamin Herrenschmidt spin_lock_irqsave(&mpic_lock, flags); 1080868ea0c9SMark A. Greer v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 1081868ea0c9SMark A. Greer if (enable) 1082868ea0c9SMark A. Greer v |= MPIC_GREG_GLOBAL_CONF_1_SIE; 1083868ea0c9SMark A. Greer else 1084868ea0c9SMark A. Greer v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE; 1085868ea0c9SMark A. Greer mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 1086ba1826e5SBenjamin Herrenschmidt spin_unlock_irqrestore(&mpic_lock, flags); 1087868ea0c9SMark A. Greer } 108814cf11afSPaul Mackerras 108914cf11afSPaul Mackerras void mpic_irq_set_priority(unsigned int irq, unsigned int pri) 109014cf11afSPaul Mackerras { 109114cf11afSPaul Mackerras int is_ipi; 109214cf11afSPaul Mackerras struct mpic *mpic = mpic_find(irq, &is_ipi); 10930ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 109414cf11afSPaul Mackerras unsigned long flags; 109514cf11afSPaul Mackerras u32 reg; 109614cf11afSPaul Mackerras 109714cf11afSPaul Mackerras spin_lock_irqsave(&mpic_lock, flags); 109814cf11afSPaul Mackerras if (is_ipi) { 10990ebfff14SBenjamin Herrenschmidt reg = mpic_ipi_read(src - MPIC_VEC_IPI_0) & 1100e5356640SBenjamin Herrenschmidt ~MPIC_VECPRI_PRIORITY_MASK; 11010ebfff14SBenjamin Herrenschmidt mpic_ipi_write(src - MPIC_VEC_IPI_0, 110214cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 110314cf11afSPaul Mackerras } else { 1104*7233593bSZang Roy-r61911 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) 1105e5356640SBenjamin Herrenschmidt & ~MPIC_VECPRI_PRIORITY_MASK; 1106*7233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 110714cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 110814cf11afSPaul Mackerras } 110914cf11afSPaul Mackerras spin_unlock_irqrestore(&mpic_lock, flags); 111014cf11afSPaul Mackerras } 111114cf11afSPaul Mackerras 111214cf11afSPaul Mackerras unsigned int mpic_irq_get_priority(unsigned int irq) 111314cf11afSPaul Mackerras { 111414cf11afSPaul Mackerras int is_ipi; 111514cf11afSPaul Mackerras struct mpic *mpic = mpic_find(irq, &is_ipi); 11160ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 111714cf11afSPaul Mackerras unsigned long flags; 111814cf11afSPaul Mackerras u32 reg; 111914cf11afSPaul Mackerras 112014cf11afSPaul Mackerras spin_lock_irqsave(&mpic_lock, flags); 112114cf11afSPaul Mackerras if (is_ipi) 11220ebfff14SBenjamin Herrenschmidt reg = mpic_ipi_read(src = MPIC_VEC_IPI_0); 112314cf11afSPaul Mackerras else 1124*7233593bSZang Roy-r61911 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 112514cf11afSPaul Mackerras spin_unlock_irqrestore(&mpic_lock, flags); 112614cf11afSPaul Mackerras return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT; 112714cf11afSPaul Mackerras } 112814cf11afSPaul Mackerras 112914cf11afSPaul Mackerras void mpic_setup_this_cpu(void) 113014cf11afSPaul Mackerras { 113114cf11afSPaul Mackerras #ifdef CONFIG_SMP 113214cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 113314cf11afSPaul Mackerras unsigned long flags; 113414cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 113514cf11afSPaul Mackerras unsigned int i; 113614cf11afSPaul Mackerras 113714cf11afSPaul Mackerras BUG_ON(mpic == NULL); 113814cf11afSPaul Mackerras 113914cf11afSPaul Mackerras DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 114014cf11afSPaul Mackerras 114114cf11afSPaul Mackerras spin_lock_irqsave(&mpic_lock, flags); 114214cf11afSPaul Mackerras 114314cf11afSPaul Mackerras /* let the mpic know we want intrs. default affinity is 0xffffffff 114414cf11afSPaul Mackerras * until changed via /proc. That's how it's done on x86. If we want 114514cf11afSPaul Mackerras * it differently, then we should make sure we also change the default 1146a53da52fSIngo Molnar * values of irq_desc[].affinity in irq.c. 114714cf11afSPaul Mackerras */ 114814cf11afSPaul Mackerras if (distribute_irqs) { 114914cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources ; i++) 1150*7233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1151*7233593bSZang Roy-r61911 mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) | msk); 115214cf11afSPaul Mackerras } 115314cf11afSPaul Mackerras 115414cf11afSPaul Mackerras /* Set current processor priority to 0 */ 1155*7233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 115614cf11afSPaul Mackerras 115714cf11afSPaul Mackerras spin_unlock_irqrestore(&mpic_lock, flags); 115814cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 115914cf11afSPaul Mackerras } 116014cf11afSPaul Mackerras 116114cf11afSPaul Mackerras int mpic_cpu_get_priority(void) 116214cf11afSPaul Mackerras { 116314cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 116414cf11afSPaul Mackerras 1165*7233593bSZang Roy-r61911 return mpic_cpu_read(MPIC_INFO(CPU_CURRENT_TASK_PRI)); 116614cf11afSPaul Mackerras } 116714cf11afSPaul Mackerras 116814cf11afSPaul Mackerras void mpic_cpu_set_priority(int prio) 116914cf11afSPaul Mackerras { 117014cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 117114cf11afSPaul Mackerras 117214cf11afSPaul Mackerras prio &= MPIC_CPU_TASKPRI_MASK; 1173*7233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), prio); 117414cf11afSPaul Mackerras } 117514cf11afSPaul Mackerras 117614cf11afSPaul Mackerras /* 117714cf11afSPaul Mackerras * XXX: someone who knows mpic should check this. 117814cf11afSPaul Mackerras * do we need to eoi the ipi including for kexec cpu here (see xics comments)? 117914cf11afSPaul Mackerras * or can we reset the mpic in the new kernel? 118014cf11afSPaul Mackerras */ 118114cf11afSPaul Mackerras void mpic_teardown_this_cpu(int secondary) 118214cf11afSPaul Mackerras { 118314cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 118414cf11afSPaul Mackerras unsigned long flags; 118514cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 118614cf11afSPaul Mackerras unsigned int i; 118714cf11afSPaul Mackerras 118814cf11afSPaul Mackerras BUG_ON(mpic == NULL); 118914cf11afSPaul Mackerras 119014cf11afSPaul Mackerras DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 119114cf11afSPaul Mackerras spin_lock_irqsave(&mpic_lock, flags); 119214cf11afSPaul Mackerras 119314cf11afSPaul Mackerras /* let the mpic know we don't want intrs. */ 119414cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources ; i++) 1195*7233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1196*7233593bSZang Roy-r61911 mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) & ~msk); 119714cf11afSPaul Mackerras 119814cf11afSPaul Mackerras /* Set current processor priority to max */ 1199*7233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 120014cf11afSPaul Mackerras 120114cf11afSPaul Mackerras spin_unlock_irqrestore(&mpic_lock, flags); 120214cf11afSPaul Mackerras } 120314cf11afSPaul Mackerras 120414cf11afSPaul Mackerras 120514cf11afSPaul Mackerras void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) 120614cf11afSPaul Mackerras { 120714cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 120814cf11afSPaul Mackerras 120914cf11afSPaul Mackerras BUG_ON(mpic == NULL); 121014cf11afSPaul Mackerras 12111beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_IPI 121214cf11afSPaul Mackerras DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); 12131beb6a7dSBenjamin Herrenschmidt #endif 121414cf11afSPaul Mackerras 1215*7233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + 1216*7233593bSZang Roy-r61911 ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), 121714cf11afSPaul Mackerras mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); 121814cf11afSPaul Mackerras } 121914cf11afSPaul Mackerras 12200ebfff14SBenjamin Herrenschmidt unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) 122114cf11afSPaul Mackerras { 12220ebfff14SBenjamin Herrenschmidt u32 src; 122314cf11afSPaul Mackerras 1224*7233593bSZang Roy-r61911 src = mpic_cpu_read(MPIC_INFO(CPU_INTACK)) & MPIC_INFO(VECPRI_VECTOR_MASK); 12251beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_LOW 12260ebfff14SBenjamin Herrenschmidt DBG("%s: get_one_irq(): %d\n", mpic->name, src); 12271beb6a7dSBenjamin Herrenschmidt #endif 12280ebfff14SBenjamin Herrenschmidt if (unlikely(src == MPIC_VEC_SPURRIOUS)) 12290ebfff14SBenjamin Herrenschmidt return NO_IRQ; 12300ebfff14SBenjamin Herrenschmidt return irq_linear_revmap(mpic->irqhost, src); 123114cf11afSPaul Mackerras } 123214cf11afSPaul Mackerras 12330ebfff14SBenjamin Herrenschmidt unsigned int mpic_get_irq(struct pt_regs *regs) 123414cf11afSPaul Mackerras { 123514cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 123614cf11afSPaul Mackerras 123714cf11afSPaul Mackerras BUG_ON(mpic == NULL); 123814cf11afSPaul Mackerras 123914cf11afSPaul Mackerras return mpic_get_one_irq(mpic, regs); 124014cf11afSPaul Mackerras } 124114cf11afSPaul Mackerras 124214cf11afSPaul Mackerras 124314cf11afSPaul Mackerras #ifdef CONFIG_SMP 124414cf11afSPaul Mackerras void mpic_request_ipis(void) 124514cf11afSPaul Mackerras { 124614cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 12470ebfff14SBenjamin Herrenschmidt int i; 12480ebfff14SBenjamin Herrenschmidt static char *ipi_names[] = { 12490ebfff14SBenjamin Herrenschmidt "IPI0 (call function)", 12500ebfff14SBenjamin Herrenschmidt "IPI1 (reschedule)", 12510ebfff14SBenjamin Herrenschmidt "IPI2 (unused)", 12520ebfff14SBenjamin Herrenschmidt "IPI3 (debugger break)", 12530ebfff14SBenjamin Herrenschmidt }; 125414cf11afSPaul Mackerras BUG_ON(mpic == NULL); 125514cf11afSPaul Mackerras 12560ebfff14SBenjamin Herrenschmidt printk(KERN_INFO "mpic: requesting IPIs ... \n"); 125714cf11afSPaul Mackerras 12580ebfff14SBenjamin Herrenschmidt for (i = 0; i < 4; i++) { 12590ebfff14SBenjamin Herrenschmidt unsigned int vipi = irq_create_mapping(mpic->irqhost, 12606e99e458SBenjamin Herrenschmidt MPIC_VEC_IPI_0 + i); 12610ebfff14SBenjamin Herrenschmidt if (vipi == NO_IRQ) { 12620ebfff14SBenjamin Herrenschmidt printk(KERN_ERR "Failed to map IPI %d\n", i); 12630ebfff14SBenjamin Herrenschmidt break; 12640ebfff14SBenjamin Herrenschmidt } 12650ebfff14SBenjamin Herrenschmidt request_irq(vipi, mpic_ipi_action, IRQF_DISABLED, 12660ebfff14SBenjamin Herrenschmidt ipi_names[i], mpic); 12670ebfff14SBenjamin Herrenschmidt } 126814cf11afSPaul Mackerras } 1269a9c59264SPaul Mackerras 1270a9c59264SPaul Mackerras void smp_mpic_message_pass(int target, int msg) 1271a9c59264SPaul Mackerras { 1272a9c59264SPaul Mackerras /* make sure we're sending something that translates to an IPI */ 1273a9c59264SPaul Mackerras if ((unsigned int)msg > 3) { 1274a9c59264SPaul Mackerras printk("SMP %d: smp_message_pass: unknown msg %d\n", 1275a9c59264SPaul Mackerras smp_processor_id(), msg); 1276a9c59264SPaul Mackerras return; 1277a9c59264SPaul Mackerras } 1278a9c59264SPaul Mackerras switch (target) { 1279a9c59264SPaul Mackerras case MSG_ALL: 1280a9c59264SPaul Mackerras mpic_send_ipi(msg, 0xffffffff); 1281a9c59264SPaul Mackerras break; 1282a9c59264SPaul Mackerras case MSG_ALL_BUT_SELF: 1283a9c59264SPaul Mackerras mpic_send_ipi(msg, 0xffffffff & ~(1 << smp_processor_id())); 1284a9c59264SPaul Mackerras break; 1285a9c59264SPaul Mackerras default: 1286a9c59264SPaul Mackerras mpic_send_ipi(msg, 1 << target); 1287a9c59264SPaul Mackerras break; 1288a9c59264SPaul Mackerras } 1289a9c59264SPaul Mackerras } 129014cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 1291