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 39a7de7c74SMichael Ellerman #include "mpic.h" 40a7de7c74SMichael Ellerman 4114cf11afSPaul Mackerras #ifdef DEBUG 4214cf11afSPaul Mackerras #define DBG(fmt...) printk(fmt) 4314cf11afSPaul Mackerras #else 4414cf11afSPaul Mackerras #define DBG(fmt...) 4514cf11afSPaul Mackerras #endif 4614cf11afSPaul Mackerras 4714cf11afSPaul Mackerras static struct mpic *mpics; 4814cf11afSPaul Mackerras static struct mpic *mpic_primary; 4914cf11afSPaul Mackerras static DEFINE_SPINLOCK(mpic_lock); 5014cf11afSPaul Mackerras 51c0c0d996SPaul Mackerras #ifdef CONFIG_PPC32 /* XXX for now */ 52e40c7f02SAndy Whitcroft #ifdef CONFIG_IRQ_ALL_CPUS 53e40c7f02SAndy Whitcroft #define distribute_irqs (1) 54e40c7f02SAndy Whitcroft #else 55e40c7f02SAndy Whitcroft #define distribute_irqs (0) 56e40c7f02SAndy Whitcroft #endif 57c0c0d996SPaul Mackerras #endif 5814cf11afSPaul Mackerras 597233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 607233593bSZang Roy-r61911 static u32 mpic_infos[][MPIC_IDX_END] = { 617233593bSZang Roy-r61911 [0] = { /* Original OpenPIC compatible MPIC */ 627233593bSZang Roy-r61911 MPIC_GREG_BASE, 637233593bSZang Roy-r61911 MPIC_GREG_FEATURE_0, 647233593bSZang Roy-r61911 MPIC_GREG_GLOBAL_CONF_0, 657233593bSZang Roy-r61911 MPIC_GREG_VENDOR_ID, 667233593bSZang Roy-r61911 MPIC_GREG_IPI_VECTOR_PRI_0, 677233593bSZang Roy-r61911 MPIC_GREG_IPI_STRIDE, 687233593bSZang Roy-r61911 MPIC_GREG_SPURIOUS, 697233593bSZang Roy-r61911 MPIC_GREG_TIMER_FREQ, 707233593bSZang Roy-r61911 717233593bSZang Roy-r61911 MPIC_TIMER_BASE, 727233593bSZang Roy-r61911 MPIC_TIMER_STRIDE, 737233593bSZang Roy-r61911 MPIC_TIMER_CURRENT_CNT, 747233593bSZang Roy-r61911 MPIC_TIMER_BASE_CNT, 757233593bSZang Roy-r61911 MPIC_TIMER_VECTOR_PRI, 767233593bSZang Roy-r61911 MPIC_TIMER_DESTINATION, 777233593bSZang Roy-r61911 787233593bSZang Roy-r61911 MPIC_CPU_BASE, 797233593bSZang Roy-r61911 MPIC_CPU_STRIDE, 807233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_0, 817233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_STRIDE, 827233593bSZang Roy-r61911 MPIC_CPU_CURRENT_TASK_PRI, 837233593bSZang Roy-r61911 MPIC_CPU_WHOAMI, 847233593bSZang Roy-r61911 MPIC_CPU_INTACK, 857233593bSZang Roy-r61911 MPIC_CPU_EOI, 86f365355eSOlof Johansson MPIC_CPU_MCACK, 877233593bSZang Roy-r61911 887233593bSZang Roy-r61911 MPIC_IRQ_BASE, 897233593bSZang Roy-r61911 MPIC_IRQ_STRIDE, 907233593bSZang Roy-r61911 MPIC_IRQ_VECTOR_PRI, 917233593bSZang Roy-r61911 MPIC_VECPRI_VECTOR_MASK, 927233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_POSITIVE, 937233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_NEGATIVE, 947233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_LEVEL, 957233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_EDGE, 967233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_MASK, 977233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_MASK, 987233593bSZang Roy-r61911 MPIC_IRQ_DESTINATION 997233593bSZang Roy-r61911 }, 1007233593bSZang Roy-r61911 [1] = { /* Tsi108/109 PIC */ 1017233593bSZang Roy-r61911 TSI108_GREG_BASE, 1027233593bSZang Roy-r61911 TSI108_GREG_FEATURE_0, 1037233593bSZang Roy-r61911 TSI108_GREG_GLOBAL_CONF_0, 1047233593bSZang Roy-r61911 TSI108_GREG_VENDOR_ID, 1057233593bSZang Roy-r61911 TSI108_GREG_IPI_VECTOR_PRI_0, 1067233593bSZang Roy-r61911 TSI108_GREG_IPI_STRIDE, 1077233593bSZang Roy-r61911 TSI108_GREG_SPURIOUS, 1087233593bSZang Roy-r61911 TSI108_GREG_TIMER_FREQ, 1097233593bSZang Roy-r61911 1107233593bSZang Roy-r61911 TSI108_TIMER_BASE, 1117233593bSZang Roy-r61911 TSI108_TIMER_STRIDE, 1127233593bSZang Roy-r61911 TSI108_TIMER_CURRENT_CNT, 1137233593bSZang Roy-r61911 TSI108_TIMER_BASE_CNT, 1147233593bSZang Roy-r61911 TSI108_TIMER_VECTOR_PRI, 1157233593bSZang Roy-r61911 TSI108_TIMER_DESTINATION, 1167233593bSZang Roy-r61911 1177233593bSZang Roy-r61911 TSI108_CPU_BASE, 1187233593bSZang Roy-r61911 TSI108_CPU_STRIDE, 1197233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_0, 1207233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_STRIDE, 1217233593bSZang Roy-r61911 TSI108_CPU_CURRENT_TASK_PRI, 1227233593bSZang Roy-r61911 TSI108_CPU_WHOAMI, 1237233593bSZang Roy-r61911 TSI108_CPU_INTACK, 1247233593bSZang Roy-r61911 TSI108_CPU_EOI, 125f365355eSOlof Johansson TSI108_CPU_MCACK, 1267233593bSZang Roy-r61911 1277233593bSZang Roy-r61911 TSI108_IRQ_BASE, 1287233593bSZang Roy-r61911 TSI108_IRQ_STRIDE, 1297233593bSZang Roy-r61911 TSI108_IRQ_VECTOR_PRI, 1307233593bSZang Roy-r61911 TSI108_VECPRI_VECTOR_MASK, 1317233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_POSITIVE, 1327233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_NEGATIVE, 1337233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_LEVEL, 1347233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_EDGE, 1357233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_MASK, 1367233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_MASK, 1377233593bSZang Roy-r61911 TSI108_IRQ_DESTINATION 1387233593bSZang Roy-r61911 }, 1397233593bSZang Roy-r61911 }; 1407233593bSZang Roy-r61911 1417233593bSZang Roy-r61911 #define MPIC_INFO(name) mpic->hw_set[MPIC_IDX_##name] 1427233593bSZang Roy-r61911 1437233593bSZang Roy-r61911 #else /* CONFIG_MPIC_WEIRD */ 1447233593bSZang Roy-r61911 1457233593bSZang Roy-r61911 #define MPIC_INFO(name) MPIC_##name 1467233593bSZang Roy-r61911 1477233593bSZang Roy-r61911 #endif /* CONFIG_MPIC_WEIRD */ 1487233593bSZang Roy-r61911 14914cf11afSPaul Mackerras /* 15014cf11afSPaul Mackerras * Register accessor functions 15114cf11afSPaul Mackerras */ 15214cf11afSPaul Mackerras 15314cf11afSPaul Mackerras 154fbf0274eSBenjamin Herrenschmidt static inline u32 _mpic_read(enum mpic_reg_type type, 155fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, 15614cf11afSPaul Mackerras unsigned int reg) 15714cf11afSPaul Mackerras { 158fbf0274eSBenjamin Herrenschmidt switch(type) { 159fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 160fbf0274eSBenjamin Herrenschmidt case mpic_access_dcr: 16183f34df4SMichael Ellerman return dcr_read(rb->dhost, reg); 162fbf0274eSBenjamin Herrenschmidt #endif 163fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_be: 164fbf0274eSBenjamin Herrenschmidt return in_be32(rb->base + (reg >> 2)); 165fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_le: 166fbf0274eSBenjamin Herrenschmidt default: 167fbf0274eSBenjamin Herrenschmidt return in_le32(rb->base + (reg >> 2)); 168fbf0274eSBenjamin Herrenschmidt } 16914cf11afSPaul Mackerras } 17014cf11afSPaul Mackerras 171fbf0274eSBenjamin Herrenschmidt static inline void _mpic_write(enum mpic_reg_type type, 172fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, 17314cf11afSPaul Mackerras unsigned int reg, u32 value) 17414cf11afSPaul Mackerras { 175fbf0274eSBenjamin Herrenschmidt switch(type) { 176fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 177fbf0274eSBenjamin Herrenschmidt case mpic_access_dcr: 178d9d1063dSJohannes Berg dcr_write(rb->dhost, reg, value); 179d9d1063dSJohannes Berg break; 180fbf0274eSBenjamin Herrenschmidt #endif 181fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_be: 182d9d1063dSJohannes Berg out_be32(rb->base + (reg >> 2), value); 183d9d1063dSJohannes Berg break; 184fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_le: 185fbf0274eSBenjamin Herrenschmidt default: 186d9d1063dSJohannes Berg out_le32(rb->base + (reg >> 2), value); 187d9d1063dSJohannes Berg break; 188fbf0274eSBenjamin Herrenschmidt } 18914cf11afSPaul Mackerras } 19014cf11afSPaul Mackerras 19114cf11afSPaul Mackerras static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) 19214cf11afSPaul Mackerras { 193fbf0274eSBenjamin Herrenschmidt enum mpic_reg_type type = mpic->reg_type; 1947233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 1957233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 19614cf11afSPaul Mackerras 197fbf0274eSBenjamin Herrenschmidt if ((mpic->flags & MPIC_BROKEN_IPI) && type == mpic_access_mmio_le) 198fbf0274eSBenjamin Herrenschmidt type = mpic_access_mmio_be; 199fbf0274eSBenjamin Herrenschmidt return _mpic_read(type, &mpic->gregs, offset); 20014cf11afSPaul Mackerras } 20114cf11afSPaul Mackerras 20214cf11afSPaul Mackerras static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) 20314cf11afSPaul Mackerras { 2047233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 2057233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 20614cf11afSPaul Mackerras 207fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); 20814cf11afSPaul Mackerras } 20914cf11afSPaul Mackerras 21014cf11afSPaul Mackerras static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) 21114cf11afSPaul Mackerras { 21214cf11afSPaul Mackerras unsigned int cpu = 0; 21314cf11afSPaul Mackerras 21414cf11afSPaul Mackerras if (mpic->flags & MPIC_PRIMARY) 21514cf11afSPaul Mackerras cpu = hard_smp_processor_id(); 216fbf0274eSBenjamin Herrenschmidt return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg); 21714cf11afSPaul Mackerras } 21814cf11afSPaul Mackerras 21914cf11afSPaul Mackerras static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) 22014cf11afSPaul Mackerras { 22114cf11afSPaul Mackerras unsigned int cpu = 0; 22214cf11afSPaul Mackerras 22314cf11afSPaul Mackerras if (mpic->flags & MPIC_PRIMARY) 22414cf11afSPaul Mackerras cpu = hard_smp_processor_id(); 22514cf11afSPaul Mackerras 226fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value); 22714cf11afSPaul Mackerras } 22814cf11afSPaul Mackerras 22914cf11afSPaul Mackerras static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) 23014cf11afSPaul Mackerras { 23114cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 23214cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 23314cf11afSPaul Mackerras 2340d72ba93SOlof Johansson #ifdef CONFIG_MPIC_BROKEN_REGREAD 2350d72ba93SOlof Johansson if (reg == 0) 2360d72ba93SOlof Johansson return mpic->isu_reg0_shadow[idx]; 2370d72ba93SOlof Johansson else 2380d72ba93SOlof Johansson #endif 239fbf0274eSBenjamin Herrenschmidt return _mpic_read(mpic->reg_type, &mpic->isus[isu], 2407233593bSZang Roy-r61911 reg + (idx * MPIC_INFO(IRQ_STRIDE))); 24114cf11afSPaul Mackerras } 24214cf11afSPaul Mackerras 24314cf11afSPaul Mackerras static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, 24414cf11afSPaul Mackerras unsigned int reg, u32 value) 24514cf11afSPaul Mackerras { 24614cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 24714cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 24814cf11afSPaul Mackerras 249fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->isus[isu], 2507233593bSZang Roy-r61911 reg + (idx * MPIC_INFO(IRQ_STRIDE)), value); 2510d72ba93SOlof Johansson 2520d72ba93SOlof Johansson #ifdef CONFIG_MPIC_BROKEN_REGREAD 2530d72ba93SOlof Johansson if (reg == 0) 2540d72ba93SOlof Johansson mpic->isu_reg0_shadow[idx] = value; 2550d72ba93SOlof Johansson #endif 25614cf11afSPaul Mackerras } 25714cf11afSPaul Mackerras 258fbf0274eSBenjamin Herrenschmidt #define mpic_read(b,r) _mpic_read(mpic->reg_type,&(b),(r)) 259fbf0274eSBenjamin Herrenschmidt #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) 26014cf11afSPaul Mackerras #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) 26114cf11afSPaul Mackerras #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) 26214cf11afSPaul Mackerras #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) 26314cf11afSPaul Mackerras #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) 26414cf11afSPaul Mackerras #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) 26514cf11afSPaul Mackerras #define mpic_irq_write(s,r,v) _mpic_irq_write(mpic,(s),(r),(v)) 26614cf11afSPaul Mackerras 26714cf11afSPaul Mackerras 26814cf11afSPaul Mackerras /* 26914cf11afSPaul Mackerras * Low level utility functions 27014cf11afSPaul Mackerras */ 27114cf11afSPaul Mackerras 27214cf11afSPaul Mackerras 273c51a3fdcSBecky Bruce static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr, 274fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, unsigned int offset, 275fbf0274eSBenjamin Herrenschmidt unsigned int size) 276fbf0274eSBenjamin Herrenschmidt { 277fbf0274eSBenjamin Herrenschmidt rb->base = ioremap(phys_addr + offset, size); 278fbf0274eSBenjamin Herrenschmidt BUG_ON(rb->base == NULL); 279fbf0274eSBenjamin Herrenschmidt } 280fbf0274eSBenjamin Herrenschmidt 281fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 2825a2642f6SBenjamin Herrenschmidt static void _mpic_map_dcr(struct mpic *mpic, struct device_node *node, 2835a2642f6SBenjamin Herrenschmidt struct mpic_reg_bank *rb, 284fbf0274eSBenjamin Herrenschmidt unsigned int offset, unsigned int size) 285fbf0274eSBenjamin Herrenschmidt { 2860411a5e2SMichael Ellerman const u32 *dbasep; 2870411a5e2SMichael Ellerman 2885a2642f6SBenjamin Herrenschmidt dbasep = of_get_property(node, "dcr-reg", NULL); 2890411a5e2SMichael Ellerman 2905a2642f6SBenjamin Herrenschmidt rb->dhost = dcr_map(node, *dbasep + offset, size); 291fbf0274eSBenjamin Herrenschmidt BUG_ON(!DCR_MAP_OK(rb->dhost)); 292fbf0274eSBenjamin Herrenschmidt } 293fbf0274eSBenjamin Herrenschmidt 2945a2642f6SBenjamin Herrenschmidt static inline void mpic_map(struct mpic *mpic, struct device_node *node, 2955a2642f6SBenjamin Herrenschmidt phys_addr_t phys_addr, struct mpic_reg_bank *rb, 2965a2642f6SBenjamin Herrenschmidt unsigned int offset, unsigned int size) 297fbf0274eSBenjamin Herrenschmidt { 298fbf0274eSBenjamin Herrenschmidt if (mpic->flags & MPIC_USES_DCR) 2995a2642f6SBenjamin Herrenschmidt _mpic_map_dcr(mpic, node, rb, offset, size); 300fbf0274eSBenjamin Herrenschmidt else 301fbf0274eSBenjamin Herrenschmidt _mpic_map_mmio(mpic, phys_addr, rb, offset, size); 302fbf0274eSBenjamin Herrenschmidt } 303fbf0274eSBenjamin Herrenschmidt #else /* CONFIG_PPC_DCR */ 3045a2642f6SBenjamin Herrenschmidt #define mpic_map(m,n,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) 305fbf0274eSBenjamin Herrenschmidt #endif /* !CONFIG_PPC_DCR */ 306fbf0274eSBenjamin Herrenschmidt 307fbf0274eSBenjamin Herrenschmidt 30814cf11afSPaul Mackerras 30914cf11afSPaul Mackerras /* Check if we have one of those nice broken MPICs with a flipped endian on 31014cf11afSPaul Mackerras * reads from IPI registers 31114cf11afSPaul Mackerras */ 31214cf11afSPaul Mackerras static void __init mpic_test_broken_ipi(struct mpic *mpic) 31314cf11afSPaul Mackerras { 31414cf11afSPaul Mackerras u32 r; 31514cf11afSPaul Mackerras 3167233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0), MPIC_VECPRI_MASK); 3177233593bSZang Roy-r61911 r = mpic_read(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0)); 31814cf11afSPaul Mackerras 31914cf11afSPaul Mackerras if (r == le32_to_cpu(MPIC_VECPRI_MASK)) { 32014cf11afSPaul Mackerras printk(KERN_INFO "mpic: Detected reversed IPI registers\n"); 32114cf11afSPaul Mackerras mpic->flags |= MPIC_BROKEN_IPI; 32214cf11afSPaul Mackerras } 32314cf11afSPaul Mackerras } 32414cf11afSPaul Mackerras 3256cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 32614cf11afSPaul Mackerras 32714cf11afSPaul Mackerras /* Test if an interrupt is sourced from HyperTransport (used on broken U3s) 32814cf11afSPaul Mackerras * to force the edge setting on the MPIC and do the ack workaround. 32914cf11afSPaul Mackerras */ 3301beb6a7dSBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 33114cf11afSPaul Mackerras { 3321beb6a7dSBenjamin Herrenschmidt if (source >= 128 || !mpic->fixups) 33314cf11afSPaul Mackerras return 0; 3341beb6a7dSBenjamin Herrenschmidt return mpic->fixups[source].base != NULL; 33514cf11afSPaul Mackerras } 33614cf11afSPaul Mackerras 337c4b22f26SSegher Boessenkool 3381beb6a7dSBenjamin Herrenschmidt static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source) 33914cf11afSPaul Mackerras { 3401beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 34114cf11afSPaul Mackerras 3421beb6a7dSBenjamin Herrenschmidt if (fixup->applebase) { 3431beb6a7dSBenjamin Herrenschmidt unsigned int soff = (fixup->index >> 3) & ~3; 3441beb6a7dSBenjamin Herrenschmidt unsigned int mask = 1U << (fixup->index & 0x1f); 3451beb6a7dSBenjamin Herrenschmidt writel(mask, fixup->applebase + soff); 3461beb6a7dSBenjamin Herrenschmidt } else { 34714cf11afSPaul Mackerras spin_lock(&mpic->fixup_lock); 3481beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * fixup->index, fixup->base + 2); 349c4b22f26SSegher Boessenkool writel(fixup->data, fixup->base + 4); 35014cf11afSPaul Mackerras spin_unlock(&mpic->fixup_lock); 35114cf11afSPaul Mackerras } 3521beb6a7dSBenjamin Herrenschmidt } 35314cf11afSPaul Mackerras 3541beb6a7dSBenjamin Herrenschmidt static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, 3551beb6a7dSBenjamin Herrenschmidt unsigned int irqflags) 3561beb6a7dSBenjamin Herrenschmidt { 3571beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 3581beb6a7dSBenjamin Herrenschmidt unsigned long flags; 3591beb6a7dSBenjamin Herrenschmidt u32 tmp; 36014cf11afSPaul Mackerras 3611beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 3621beb6a7dSBenjamin Herrenschmidt return; 3631beb6a7dSBenjamin Herrenschmidt 36406fe98e6SBenjamin Herrenschmidt DBG("startup_ht_interrupt(0x%x, 0x%x) index: %d\n", 3651beb6a7dSBenjamin Herrenschmidt source, irqflags, fixup->index); 3661beb6a7dSBenjamin Herrenschmidt spin_lock_irqsave(&mpic->fixup_lock, flags); 3671beb6a7dSBenjamin Herrenschmidt /* Enable and configure */ 3681beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 3691beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 3701beb6a7dSBenjamin Herrenschmidt tmp &= ~(0x23U); 3711beb6a7dSBenjamin Herrenschmidt if (irqflags & IRQ_LEVEL) 3721beb6a7dSBenjamin Herrenschmidt tmp |= 0x22; 3731beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 3741beb6a7dSBenjamin Herrenschmidt spin_unlock_irqrestore(&mpic->fixup_lock, flags); 3753669e930SJohannes Berg 3763669e930SJohannes Berg #ifdef CONFIG_PM 3773669e930SJohannes Berg /* use the lowest bit inverted to the actual HW, 3783669e930SJohannes Berg * set if this fixup was enabled, clear otherwise */ 3793669e930SJohannes Berg mpic->save_data[source].fixup_data = tmp | 1; 3803669e930SJohannes Berg #endif 3811beb6a7dSBenjamin Herrenschmidt } 3821beb6a7dSBenjamin Herrenschmidt 3831beb6a7dSBenjamin Herrenschmidt static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, 3841beb6a7dSBenjamin Herrenschmidt unsigned int irqflags) 3851beb6a7dSBenjamin Herrenschmidt { 3861beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 3871beb6a7dSBenjamin Herrenschmidt unsigned long flags; 3881beb6a7dSBenjamin Herrenschmidt u32 tmp; 3891beb6a7dSBenjamin Herrenschmidt 3901beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 3911beb6a7dSBenjamin Herrenschmidt return; 3921beb6a7dSBenjamin Herrenschmidt 39306fe98e6SBenjamin Herrenschmidt DBG("shutdown_ht_interrupt(0x%x, 0x%x)\n", source, irqflags); 3941beb6a7dSBenjamin Herrenschmidt 3951beb6a7dSBenjamin Herrenschmidt /* Disable */ 3961beb6a7dSBenjamin Herrenschmidt spin_lock_irqsave(&mpic->fixup_lock, flags); 3971beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 3981beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 39972b13819SSegher Boessenkool tmp |= 1; 4001beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 4011beb6a7dSBenjamin Herrenschmidt spin_unlock_irqrestore(&mpic->fixup_lock, flags); 4023669e930SJohannes Berg 4033669e930SJohannes Berg #ifdef CONFIG_PM 4043669e930SJohannes Berg /* use the lowest bit inverted to the actual HW, 4053669e930SJohannes Berg * set if this fixup was enabled, clear otherwise */ 4063669e930SJohannes Berg mpic->save_data[source].fixup_data = tmp & ~1; 4073669e930SJohannes Berg #endif 4081beb6a7dSBenjamin Herrenschmidt } 4091beb6a7dSBenjamin Herrenschmidt 410812fd1fdSMichael Ellerman #ifdef CONFIG_PCI_MSI 411812fd1fdSMichael Ellerman static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, 412812fd1fdSMichael Ellerman unsigned int devfn) 413812fd1fdSMichael Ellerman { 414812fd1fdSMichael Ellerman u8 __iomem *base; 415812fd1fdSMichael Ellerman u8 pos, flags; 416812fd1fdSMichael Ellerman u64 addr = 0; 417812fd1fdSMichael Ellerman 418812fd1fdSMichael Ellerman for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; 419812fd1fdSMichael Ellerman pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { 420812fd1fdSMichael Ellerman u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); 421812fd1fdSMichael Ellerman if (id == PCI_CAP_ID_HT) { 422812fd1fdSMichael Ellerman id = readb(devbase + pos + 3); 423812fd1fdSMichael Ellerman if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_MSI_MAPPING) 424812fd1fdSMichael Ellerman break; 425812fd1fdSMichael Ellerman } 426812fd1fdSMichael Ellerman } 427812fd1fdSMichael Ellerman 428812fd1fdSMichael Ellerman if (pos == 0) 429812fd1fdSMichael Ellerman return; 430812fd1fdSMichael Ellerman 431812fd1fdSMichael Ellerman base = devbase + pos; 432812fd1fdSMichael Ellerman 433812fd1fdSMichael Ellerman flags = readb(base + HT_MSI_FLAGS); 434812fd1fdSMichael Ellerman if (!(flags & HT_MSI_FLAGS_FIXED)) { 435812fd1fdSMichael Ellerman addr = readl(base + HT_MSI_ADDR_LO) & HT_MSI_ADDR_LO_MASK; 436812fd1fdSMichael Ellerman addr = addr | ((u64)readl(base + HT_MSI_ADDR_HI) << 32); 437812fd1fdSMichael Ellerman } 438812fd1fdSMichael Ellerman 439fe333321SIngo Molnar printk(KERN_DEBUG "mpic: - HT:%02x.%x %s MSI mapping found @ 0x%llx\n", 440812fd1fdSMichael Ellerman PCI_SLOT(devfn), PCI_FUNC(devfn), 441812fd1fdSMichael Ellerman flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled", addr); 442812fd1fdSMichael Ellerman 443812fd1fdSMichael Ellerman if (!(flags & HT_MSI_FLAGS_ENABLE)) 444812fd1fdSMichael Ellerman writeb(flags | HT_MSI_FLAGS_ENABLE, base + HT_MSI_FLAGS); 445812fd1fdSMichael Ellerman } 446812fd1fdSMichael Ellerman #else 447812fd1fdSMichael Ellerman static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, 448812fd1fdSMichael Ellerman unsigned int devfn) 449812fd1fdSMichael Ellerman { 450812fd1fdSMichael Ellerman return; 451812fd1fdSMichael Ellerman } 452812fd1fdSMichael Ellerman #endif 453812fd1fdSMichael Ellerman 4541beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, 4551beb6a7dSBenjamin Herrenschmidt unsigned int devfn, u32 vdid) 45614cf11afSPaul Mackerras { 457c4b22f26SSegher Boessenkool int i, irq, n; 4581beb6a7dSBenjamin Herrenschmidt u8 __iomem *base; 45914cf11afSPaul Mackerras u32 tmp; 460c4b22f26SSegher Boessenkool u8 pos; 46114cf11afSPaul Mackerras 4621beb6a7dSBenjamin Herrenschmidt for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; 4631beb6a7dSBenjamin Herrenschmidt pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { 4641beb6a7dSBenjamin Herrenschmidt u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); 46546ff3463SBrice Goglin if (id == PCI_CAP_ID_HT) { 466c4b22f26SSegher Boessenkool id = readb(devbase + pos + 3); 467beb7cc82SMichael Ellerman if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_IRQ) 468c4b22f26SSegher Boessenkool break; 469c4b22f26SSegher Boessenkool } 470c4b22f26SSegher Boessenkool } 471c4b22f26SSegher Boessenkool if (pos == 0) 472c4b22f26SSegher Boessenkool return; 473c4b22f26SSegher Boessenkool 4741beb6a7dSBenjamin Herrenschmidt base = devbase + pos; 4751beb6a7dSBenjamin Herrenschmidt writeb(0x01, base + 2); 4761beb6a7dSBenjamin Herrenschmidt n = (readl(base + 4) >> 16) & 0xff; 477c4b22f26SSegher Boessenkool 4781beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x" 4791beb6a7dSBenjamin Herrenschmidt " has %d irqs\n", 4801beb6a7dSBenjamin Herrenschmidt devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1); 481c4b22f26SSegher Boessenkool 482c4b22f26SSegher Boessenkool for (i = 0; i <= n; i++) { 4831beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * i, base + 2); 4841beb6a7dSBenjamin Herrenschmidt tmp = readl(base + 4); 48514cf11afSPaul Mackerras irq = (tmp >> 16) & 0xff; 4861beb6a7dSBenjamin Herrenschmidt DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp); 4871beb6a7dSBenjamin Herrenschmidt /* mask it , will be unmasked later */ 4881beb6a7dSBenjamin Herrenschmidt tmp |= 0x1; 4891beb6a7dSBenjamin Herrenschmidt writel(tmp, base + 4); 4901beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].index = i; 4911beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].base = base; 4921beb6a7dSBenjamin Herrenschmidt /* Apple HT PIC has a non-standard way of doing EOIs */ 4931beb6a7dSBenjamin Herrenschmidt if ((vdid & 0xffff) == 0x106b) 4941beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = devbase + 0x60; 4951beb6a7dSBenjamin Herrenschmidt else 4961beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = NULL; 4971beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * i, base + 2); 4981beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].data = readl(base + 4) | 0x80000000; 49914cf11afSPaul Mackerras } 50014cf11afSPaul Mackerras } 50114cf11afSPaul Mackerras 50214cf11afSPaul Mackerras 5031beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 50414cf11afSPaul Mackerras { 50514cf11afSPaul Mackerras unsigned int devfn; 50614cf11afSPaul Mackerras u8 __iomem *cfgspace; 50714cf11afSPaul Mackerras 5081beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n"); 50914cf11afSPaul Mackerras 51014cf11afSPaul Mackerras /* Allocate fixups array */ 51114cf11afSPaul Mackerras mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); 51214cf11afSPaul Mackerras BUG_ON(mpic->fixups == NULL); 51314cf11afSPaul Mackerras memset(mpic->fixups, 0, 128 * sizeof(struct mpic_irq_fixup)); 51414cf11afSPaul Mackerras 51514cf11afSPaul Mackerras /* Init spinlock */ 51614cf11afSPaul Mackerras spin_lock_init(&mpic->fixup_lock); 51714cf11afSPaul Mackerras 518c4b22f26SSegher Boessenkool /* Map U3 config space. We assume all IO-APICs are on the primary bus 519c4b22f26SSegher Boessenkool * so we only need to map 64kB. 52014cf11afSPaul Mackerras */ 521c4b22f26SSegher Boessenkool cfgspace = ioremap(0xf2000000, 0x10000); 52214cf11afSPaul Mackerras BUG_ON(cfgspace == NULL); 52314cf11afSPaul Mackerras 5241beb6a7dSBenjamin Herrenschmidt /* Now we scan all slots. We do a very quick scan, we read the header 5251beb6a7dSBenjamin Herrenschmidt * type, vendor ID and device ID only, that's plenty enough 52614cf11afSPaul Mackerras */ 527c4b22f26SSegher Boessenkool for (devfn = 0; devfn < 0x100; devfn++) { 52814cf11afSPaul Mackerras u8 __iomem *devbase = cfgspace + (devfn << 8); 52914cf11afSPaul Mackerras u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); 53014cf11afSPaul Mackerras u32 l = readl(devbase + PCI_VENDOR_ID); 5311beb6a7dSBenjamin Herrenschmidt u16 s; 53214cf11afSPaul Mackerras 53314cf11afSPaul Mackerras DBG("devfn %x, l: %x\n", devfn, l); 53414cf11afSPaul Mackerras 53514cf11afSPaul Mackerras /* If no device, skip */ 53614cf11afSPaul Mackerras if (l == 0xffffffff || l == 0x00000000 || 53714cf11afSPaul Mackerras l == 0x0000ffff || l == 0xffff0000) 53814cf11afSPaul Mackerras goto next; 5391beb6a7dSBenjamin Herrenschmidt /* Check if is supports capability lists */ 5401beb6a7dSBenjamin Herrenschmidt s = readw(devbase + PCI_STATUS); 5411beb6a7dSBenjamin Herrenschmidt if (!(s & PCI_STATUS_CAP_LIST)) 5421beb6a7dSBenjamin Herrenschmidt goto next; 54314cf11afSPaul Mackerras 5441beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pic(mpic, devbase, devfn, l); 545812fd1fdSMichael Ellerman mpic_scan_ht_msi(mpic, devbase, devfn); 54614cf11afSPaul Mackerras 54714cf11afSPaul Mackerras next: 54814cf11afSPaul Mackerras /* next device, if function 0 */ 549c4b22f26SSegher Boessenkool if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0) 55014cf11afSPaul Mackerras devfn += 7; 55114cf11afSPaul Mackerras } 55214cf11afSPaul Mackerras } 55314cf11afSPaul Mackerras 5546cfef5b2SMichael Ellerman #else /* CONFIG_MPIC_U3_HT_IRQS */ 5556e99e458SBenjamin Herrenschmidt 5566e99e458SBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 5576e99e458SBenjamin Herrenschmidt { 5586e99e458SBenjamin Herrenschmidt return 0; 5596e99e458SBenjamin Herrenschmidt } 5606e99e458SBenjamin Herrenschmidt 5616e99e458SBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 5626e99e458SBenjamin Herrenschmidt { 5636e99e458SBenjamin Herrenschmidt } 5646e99e458SBenjamin Herrenschmidt 5656cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 56614cf11afSPaul Mackerras 5673c10c9c4SKumar Gala #ifdef CONFIG_SMP 5683c10c9c4SKumar Gala static int irq_choose_cpu(unsigned int virt_irq) 5693c10c9c4SKumar Gala { 570e65e49d0SMike Travis cpumask_t mask; 5713c10c9c4SKumar Gala int cpuid; 5723c10c9c4SKumar Gala 573e65e49d0SMike Travis cpumask_copy(&mask, irq_desc[virt_irq].affinity); 5743c10c9c4SKumar Gala if (cpus_equal(mask, CPU_MASK_ALL)) { 5753c10c9c4SKumar Gala static int irq_rover; 5763c10c9c4SKumar Gala static DEFINE_SPINLOCK(irq_rover_lock); 5773c10c9c4SKumar Gala unsigned long flags; 5783c10c9c4SKumar Gala 5793c10c9c4SKumar Gala /* Round-robin distribution... */ 5803c10c9c4SKumar Gala do_round_robin: 5813c10c9c4SKumar Gala spin_lock_irqsave(&irq_rover_lock, flags); 5823c10c9c4SKumar Gala 5833c10c9c4SKumar Gala while (!cpu_online(irq_rover)) { 5843c10c9c4SKumar Gala if (++irq_rover >= NR_CPUS) 5853c10c9c4SKumar Gala irq_rover = 0; 5863c10c9c4SKumar Gala } 5873c10c9c4SKumar Gala cpuid = irq_rover; 5883c10c9c4SKumar Gala do { 5893c10c9c4SKumar Gala if (++irq_rover >= NR_CPUS) 5903c10c9c4SKumar Gala irq_rover = 0; 5913c10c9c4SKumar Gala } while (!cpu_online(irq_rover)); 5923c10c9c4SKumar Gala 5933c10c9c4SKumar Gala spin_unlock_irqrestore(&irq_rover_lock, flags); 5943c10c9c4SKumar Gala } else { 5953c10c9c4SKumar Gala cpumask_t tmp; 5963c10c9c4SKumar Gala 5973c10c9c4SKumar Gala cpus_and(tmp, cpu_online_map, mask); 5983c10c9c4SKumar Gala 5993c10c9c4SKumar Gala if (cpus_empty(tmp)) 6003c10c9c4SKumar Gala goto do_round_robin; 6013c10c9c4SKumar Gala 6023c10c9c4SKumar Gala cpuid = first_cpu(tmp); 6033c10c9c4SKumar Gala } 6043c10c9c4SKumar Gala 6057a0d7940SKumar Gala return get_hard_smp_processor_id(cpuid); 6063c10c9c4SKumar Gala } 6073c10c9c4SKumar Gala #else 6083c10c9c4SKumar Gala static int irq_choose_cpu(unsigned int virt_irq) 6093c10c9c4SKumar Gala { 6103c10c9c4SKumar Gala return hard_smp_processor_id(); 6113c10c9c4SKumar Gala } 6123c10c9c4SKumar Gala #endif 61314cf11afSPaul Mackerras 6140ebfff14SBenjamin Herrenschmidt #define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) 6150ebfff14SBenjamin Herrenschmidt 61614cf11afSPaul Mackerras /* Find an mpic associated with a given linux interrupt */ 617d69a78d7STony Breeds static struct mpic *mpic_find(unsigned int irq) 61814cf11afSPaul Mackerras { 6190ebfff14SBenjamin Herrenschmidt if (irq < NUM_ISA_INTERRUPTS) 62014cf11afSPaul Mackerras return NULL; 6210ebfff14SBenjamin Herrenschmidt 622d69a78d7STony Breeds return irq_desc[irq].chip_data; 62314cf11afSPaul Mackerras } 62414cf11afSPaul Mackerras 625d69a78d7STony Breeds /* Determine if the linux irq is an IPI */ 626d69a78d7STony Breeds static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq) 627d69a78d7STony Breeds { 628d69a78d7STony Breeds unsigned int src = mpic_irq_to_hw(irq); 629d69a78d7STony Breeds 630d69a78d7STony Breeds return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); 631d69a78d7STony Breeds } 632d69a78d7STony Breeds 633d69a78d7STony Breeds 63414cf11afSPaul Mackerras /* Convert a cpu mask from logical to physical cpu numbers. */ 63514cf11afSPaul Mackerras static inline u32 mpic_physmask(u32 cpumask) 63614cf11afSPaul Mackerras { 63714cf11afSPaul Mackerras int i; 63814cf11afSPaul Mackerras u32 mask = 0; 63914cf11afSPaul Mackerras 64014cf11afSPaul Mackerras for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1) 64114cf11afSPaul Mackerras mask |= (cpumask & 1) << get_hard_smp_processor_id(i); 64214cf11afSPaul Mackerras return mask; 64314cf11afSPaul Mackerras } 64414cf11afSPaul Mackerras 64514cf11afSPaul Mackerras #ifdef CONFIG_SMP 64614cf11afSPaul Mackerras /* Get the mpic structure from the IPI number */ 64714cf11afSPaul Mackerras static inline struct mpic * mpic_from_ipi(unsigned int ipi) 64814cf11afSPaul Mackerras { 649b9e5b4e6SBenjamin Herrenschmidt return irq_desc[ipi].chip_data; 65014cf11afSPaul Mackerras } 65114cf11afSPaul Mackerras #endif 65214cf11afSPaul Mackerras 65314cf11afSPaul Mackerras /* Get the mpic structure from the irq number */ 65414cf11afSPaul Mackerras static inline struct mpic * mpic_from_irq(unsigned int irq) 65514cf11afSPaul Mackerras { 656b9e5b4e6SBenjamin Herrenschmidt return irq_desc[irq].chip_data; 65714cf11afSPaul Mackerras } 65814cf11afSPaul Mackerras 65914cf11afSPaul Mackerras /* Send an EOI */ 66014cf11afSPaul Mackerras static inline void mpic_eoi(struct mpic *mpic) 66114cf11afSPaul Mackerras { 6627233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_EOI), 0); 6637233593bSZang Roy-r61911 (void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI)); 66414cf11afSPaul Mackerras } 66514cf11afSPaul Mackerras 66614cf11afSPaul Mackerras /* 66714cf11afSPaul Mackerras * Linux descriptor level callbacks 66814cf11afSPaul Mackerras */ 66914cf11afSPaul Mackerras 67014cf11afSPaul Mackerras 67105af7bd2SMichael Ellerman void mpic_unmask_irq(unsigned int irq) 67214cf11afSPaul Mackerras { 67314cf11afSPaul Mackerras unsigned int loops = 100000; 67414cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 6750ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 67614cf11afSPaul Mackerras 677bd561c79SPaul Mackerras DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); 67814cf11afSPaul Mackerras 6797233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 6807233593bSZang Roy-r61911 mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & 681e5356640SBenjamin Herrenschmidt ~MPIC_VECPRI_MASK); 68214cf11afSPaul Mackerras /* make sure mask gets to controller before we return to user */ 68314cf11afSPaul Mackerras do { 68414cf11afSPaul Mackerras if (!loops--) { 68514cf11afSPaul Mackerras printk(KERN_ERR "mpic_enable_irq timeout\n"); 68614cf11afSPaul Mackerras break; 68714cf11afSPaul Mackerras } 6887233593bSZang Roy-r61911 } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK); 6891beb6a7dSBenjamin Herrenschmidt } 6901beb6a7dSBenjamin Herrenschmidt 69105af7bd2SMichael Ellerman void mpic_mask_irq(unsigned int irq) 69214cf11afSPaul Mackerras { 69314cf11afSPaul Mackerras unsigned int loops = 100000; 69414cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 6950ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 69614cf11afSPaul Mackerras 69714cf11afSPaul Mackerras DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); 69814cf11afSPaul Mackerras 6997233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 7007233593bSZang Roy-r61911 mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) | 701e5356640SBenjamin Herrenschmidt MPIC_VECPRI_MASK); 70214cf11afSPaul Mackerras 70314cf11afSPaul Mackerras /* make sure mask gets to controller before we return to user */ 70414cf11afSPaul Mackerras do { 70514cf11afSPaul Mackerras if (!loops--) { 70614cf11afSPaul Mackerras printk(KERN_ERR "mpic_enable_irq timeout\n"); 70714cf11afSPaul Mackerras break; 70814cf11afSPaul Mackerras } 7097233593bSZang Roy-r61911 } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK)); 71014cf11afSPaul Mackerras } 71114cf11afSPaul Mackerras 71205af7bd2SMichael Ellerman void mpic_end_irq(unsigned int irq) 71314cf11afSPaul Mackerras { 71414cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 71514cf11afSPaul Mackerras 7161beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_IRQ 71714cf11afSPaul Mackerras DBG("%s: end_irq: %d\n", mpic->name, irq); 7181beb6a7dSBenjamin Herrenschmidt #endif 71914cf11afSPaul Mackerras /* We always EOI on end_irq() even for edge interrupts since that 72014cf11afSPaul Mackerras * should only lower the priority, the MPIC should have properly 72114cf11afSPaul Mackerras * latched another edge interrupt coming in anyway 72214cf11afSPaul Mackerras */ 72314cf11afSPaul Mackerras 72414cf11afSPaul Mackerras mpic_eoi(mpic); 72514cf11afSPaul Mackerras } 72614cf11afSPaul Mackerras 7276cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 728b9e5b4e6SBenjamin Herrenschmidt 729b9e5b4e6SBenjamin Herrenschmidt static void mpic_unmask_ht_irq(unsigned int irq) 730b9e5b4e6SBenjamin Herrenschmidt { 731b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 7320ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 733b9e5b4e6SBenjamin Herrenschmidt 734b9e5b4e6SBenjamin Herrenschmidt mpic_unmask_irq(irq); 735b9e5b4e6SBenjamin Herrenschmidt 736b9e5b4e6SBenjamin Herrenschmidt if (irq_desc[irq].status & IRQ_LEVEL) 737b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 738b9e5b4e6SBenjamin Herrenschmidt } 739b9e5b4e6SBenjamin Herrenschmidt 740b9e5b4e6SBenjamin Herrenschmidt static unsigned int mpic_startup_ht_irq(unsigned int irq) 741b9e5b4e6SBenjamin Herrenschmidt { 742b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 7430ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 744b9e5b4e6SBenjamin Herrenschmidt 745b9e5b4e6SBenjamin Herrenschmidt mpic_unmask_irq(irq); 746b9e5b4e6SBenjamin Herrenschmidt mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); 747b9e5b4e6SBenjamin Herrenschmidt 748b9e5b4e6SBenjamin Herrenschmidt return 0; 749b9e5b4e6SBenjamin Herrenschmidt } 750b9e5b4e6SBenjamin Herrenschmidt 751b9e5b4e6SBenjamin Herrenschmidt static void mpic_shutdown_ht_irq(unsigned int irq) 752b9e5b4e6SBenjamin Herrenschmidt { 753b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 7540ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 755b9e5b4e6SBenjamin Herrenschmidt 756b9e5b4e6SBenjamin Herrenschmidt mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); 757b9e5b4e6SBenjamin Herrenschmidt mpic_mask_irq(irq); 758b9e5b4e6SBenjamin Herrenschmidt } 759b9e5b4e6SBenjamin Herrenschmidt 760b9e5b4e6SBenjamin Herrenschmidt static void mpic_end_ht_irq(unsigned int irq) 761b9e5b4e6SBenjamin Herrenschmidt { 762b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 7630ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 764b9e5b4e6SBenjamin Herrenschmidt 765b9e5b4e6SBenjamin Herrenschmidt #ifdef DEBUG_IRQ 766b9e5b4e6SBenjamin Herrenschmidt DBG("%s: end_irq: %d\n", mpic->name, irq); 767b9e5b4e6SBenjamin Herrenschmidt #endif 768b9e5b4e6SBenjamin Herrenschmidt /* We always EOI on end_irq() even for edge interrupts since that 769b9e5b4e6SBenjamin Herrenschmidt * should only lower the priority, the MPIC should have properly 770b9e5b4e6SBenjamin Herrenschmidt * latched another edge interrupt coming in anyway 771b9e5b4e6SBenjamin Herrenschmidt */ 772b9e5b4e6SBenjamin Herrenschmidt 773b9e5b4e6SBenjamin Herrenschmidt if (irq_desc[irq].status & IRQ_LEVEL) 774b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 775b9e5b4e6SBenjamin Herrenschmidt mpic_eoi(mpic); 776b9e5b4e6SBenjamin Herrenschmidt } 7776cfef5b2SMichael Ellerman #endif /* !CONFIG_MPIC_U3_HT_IRQS */ 778b9e5b4e6SBenjamin Herrenschmidt 77914cf11afSPaul Mackerras #ifdef CONFIG_SMP 78014cf11afSPaul Mackerras 781b9e5b4e6SBenjamin Herrenschmidt static void mpic_unmask_ipi(unsigned int irq) 78214cf11afSPaul Mackerras { 78314cf11afSPaul Mackerras struct mpic *mpic = mpic_from_ipi(irq); 7847df2457dSOlof Johansson unsigned int src = mpic_irq_to_hw(irq) - mpic->ipi_vecs[0]; 78514cf11afSPaul Mackerras 78614cf11afSPaul Mackerras DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); 78714cf11afSPaul Mackerras mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); 78814cf11afSPaul Mackerras } 78914cf11afSPaul Mackerras 790b9e5b4e6SBenjamin Herrenschmidt static void mpic_mask_ipi(unsigned int irq) 79114cf11afSPaul Mackerras { 79214cf11afSPaul Mackerras /* NEVER disable an IPI... that's just plain wrong! */ 79314cf11afSPaul Mackerras } 79414cf11afSPaul Mackerras 79514cf11afSPaul Mackerras static void mpic_end_ipi(unsigned int irq) 79614cf11afSPaul Mackerras { 79714cf11afSPaul Mackerras struct mpic *mpic = mpic_from_ipi(irq); 79814cf11afSPaul Mackerras 79914cf11afSPaul Mackerras /* 80014cf11afSPaul Mackerras * IPIs are marked IRQ_PER_CPU. This has the side effect of 80114cf11afSPaul Mackerras * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from 80214cf11afSPaul Mackerras * applying to them. We EOI them late to avoid re-entering. 8036714465eSThomas Gleixner * We mark IPI's with IRQF_DISABLED as they must run with 80414cf11afSPaul Mackerras * irqs disabled. 80514cf11afSPaul Mackerras */ 80614cf11afSPaul Mackerras mpic_eoi(mpic); 80714cf11afSPaul Mackerras } 80814cf11afSPaul Mackerras 80914cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 81014cf11afSPaul Mackerras 811d5dedd45SYinghai Lu int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask) 81214cf11afSPaul Mackerras { 81314cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 8140ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 81514cf11afSPaul Mackerras 8163c10c9c4SKumar Gala if (mpic->flags & MPIC_SINGLE_DEST_CPU) { 8173c10c9c4SKumar Gala int cpuid = irq_choose_cpu(irq); 8183c10c9c4SKumar Gala 8193c10c9c4SKumar Gala mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); 8203c10c9c4SKumar Gala } else { 82114cf11afSPaul Mackerras cpumask_t tmp; 82214cf11afSPaul Mackerras 8230de26520SRusty Russell cpumask_and(&tmp, cpumask, cpu_online_mask); 82414cf11afSPaul Mackerras 8257233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 82614cf11afSPaul Mackerras mpic_physmask(cpus_addr(tmp)[0])); 82714cf11afSPaul Mackerras } 828d5dedd45SYinghai Lu 829d5dedd45SYinghai Lu return 0; 8303c10c9c4SKumar Gala } 83114cf11afSPaul Mackerras 8327233593bSZang Roy-r61911 static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) 8330ebfff14SBenjamin Herrenschmidt { 8340ebfff14SBenjamin Herrenschmidt /* Now convert sense value */ 8356e99e458SBenjamin Herrenschmidt switch(type & IRQ_TYPE_SENSE_MASK) { 8360ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_RISING: 8377233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 8387233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 8390ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_FALLING: 8406e99e458SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_BOTH: 8417233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 8427233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 8430ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_HIGH: 8447233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 8457233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 8460ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_LOW: 8470ebfff14SBenjamin Herrenschmidt default: 8487233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 8497233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 8500ebfff14SBenjamin Herrenschmidt } 8516e99e458SBenjamin Herrenschmidt } 8526e99e458SBenjamin Herrenschmidt 85305af7bd2SMichael Ellerman int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) 8546e99e458SBenjamin Herrenschmidt { 8556e99e458SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(virq); 8566e99e458SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(virq); 8576e99e458SBenjamin Herrenschmidt struct irq_desc *desc = get_irq_desc(virq); 8586e99e458SBenjamin Herrenschmidt unsigned int vecpri, vold, vnew; 8596e99e458SBenjamin Herrenschmidt 86006fe98e6SBenjamin Herrenschmidt DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", 8616e99e458SBenjamin Herrenschmidt mpic, virq, src, flow_type); 8626e99e458SBenjamin Herrenschmidt 8636e99e458SBenjamin Herrenschmidt if (src >= mpic->irq_count) 8646e99e458SBenjamin Herrenschmidt return -EINVAL; 8656e99e458SBenjamin Herrenschmidt 8666e99e458SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_NONE) 8676e99e458SBenjamin Herrenschmidt if (mpic->senses && src < mpic->senses_count) 8686e99e458SBenjamin Herrenschmidt flow_type = mpic->senses[src]; 8696e99e458SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_NONE) 8706e99e458SBenjamin Herrenschmidt flow_type = IRQ_TYPE_LEVEL_LOW; 8716e99e458SBenjamin Herrenschmidt 8726e99e458SBenjamin Herrenschmidt desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); 8736e99e458SBenjamin Herrenschmidt desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; 8746e99e458SBenjamin Herrenschmidt if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) 8756e99e458SBenjamin Herrenschmidt desc->status |= IRQ_LEVEL; 8766e99e458SBenjamin Herrenschmidt 8776e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, src)) 8786e99e458SBenjamin Herrenschmidt vecpri = MPIC_VECPRI_POLARITY_POSITIVE | 8796e99e458SBenjamin Herrenschmidt MPIC_VECPRI_SENSE_EDGE; 8806e99e458SBenjamin Herrenschmidt else 8817233593bSZang Roy-r61911 vecpri = mpic_type_to_vecpri(mpic, flow_type); 8826e99e458SBenjamin Herrenschmidt 8837233593bSZang Roy-r61911 vold = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 8847233593bSZang Roy-r61911 vnew = vold & ~(MPIC_INFO(VECPRI_POLARITY_MASK) | 8857233593bSZang Roy-r61911 MPIC_INFO(VECPRI_SENSE_MASK)); 8866e99e458SBenjamin Herrenschmidt vnew |= vecpri; 8876e99e458SBenjamin Herrenschmidt if (vold != vnew) 8887233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); 8896e99e458SBenjamin Herrenschmidt 8906e99e458SBenjamin Herrenschmidt return 0; 8910ebfff14SBenjamin Herrenschmidt } 8920ebfff14SBenjamin Herrenschmidt 89338958dd9SOlof Johansson void mpic_set_vector(unsigned int virq, unsigned int vector) 89438958dd9SOlof Johansson { 89538958dd9SOlof Johansson struct mpic *mpic = mpic_from_irq(virq); 89638958dd9SOlof Johansson unsigned int src = mpic_irq_to_hw(virq); 89738958dd9SOlof Johansson unsigned int vecpri; 89838958dd9SOlof Johansson 89938958dd9SOlof Johansson DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", 90038958dd9SOlof Johansson mpic, virq, src, vector); 90138958dd9SOlof Johansson 90238958dd9SOlof Johansson if (src >= mpic->irq_count) 90338958dd9SOlof Johansson return; 90438958dd9SOlof Johansson 90538958dd9SOlof Johansson vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 90638958dd9SOlof Johansson vecpri = vecpri & ~MPIC_INFO(VECPRI_VECTOR_MASK); 90738958dd9SOlof Johansson vecpri |= vector; 90838958dd9SOlof Johansson mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); 90938958dd9SOlof Johansson } 91038958dd9SOlof Johansson 911b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_chip = { 912b9e5b4e6SBenjamin Herrenschmidt .mask = mpic_mask_irq, 913b9e5b4e6SBenjamin Herrenschmidt .unmask = mpic_unmask_irq, 914b9e5b4e6SBenjamin Herrenschmidt .eoi = mpic_end_irq, 9156e99e458SBenjamin Herrenschmidt .set_type = mpic_set_irq_type, 916b9e5b4e6SBenjamin Herrenschmidt }; 917b9e5b4e6SBenjamin Herrenschmidt 918b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_SMP 919b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_ipi_chip = { 920b9e5b4e6SBenjamin Herrenschmidt .mask = mpic_mask_ipi, 921b9e5b4e6SBenjamin Herrenschmidt .unmask = mpic_unmask_ipi, 922b9e5b4e6SBenjamin Herrenschmidt .eoi = mpic_end_ipi, 923b9e5b4e6SBenjamin Herrenschmidt }; 924b9e5b4e6SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 925b9e5b4e6SBenjamin Herrenschmidt 9266cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 927b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_ht_chip = { 928b9e5b4e6SBenjamin Herrenschmidt .startup = mpic_startup_ht_irq, 929b9e5b4e6SBenjamin Herrenschmidt .shutdown = mpic_shutdown_ht_irq, 930b9e5b4e6SBenjamin Herrenschmidt .mask = mpic_mask_irq, 931b9e5b4e6SBenjamin Herrenschmidt .unmask = mpic_unmask_ht_irq, 932b9e5b4e6SBenjamin Herrenschmidt .eoi = mpic_end_ht_irq, 9336e99e458SBenjamin Herrenschmidt .set_type = mpic_set_irq_type, 934b9e5b4e6SBenjamin Herrenschmidt }; 9356cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 936b9e5b4e6SBenjamin Herrenschmidt 93714cf11afSPaul Mackerras 9380ebfff14SBenjamin Herrenschmidt static int mpic_host_match(struct irq_host *h, struct device_node *node) 9390ebfff14SBenjamin Herrenschmidt { 9400ebfff14SBenjamin Herrenschmidt /* Exact match, unless mpic node is NULL */ 94152964f87SMichael Ellerman return h->of_node == NULL || h->of_node == node; 9420ebfff14SBenjamin Herrenschmidt } 9430ebfff14SBenjamin Herrenschmidt 9440ebfff14SBenjamin Herrenschmidt static int mpic_host_map(struct irq_host *h, unsigned int virq, 9456e99e458SBenjamin Herrenschmidt irq_hw_number_t hw) 9460ebfff14SBenjamin Herrenschmidt { 9470ebfff14SBenjamin Herrenschmidt struct mpic *mpic = h->host_data; 9486e99e458SBenjamin Herrenschmidt struct irq_chip *chip; 9490ebfff14SBenjamin Herrenschmidt 95006fe98e6SBenjamin Herrenschmidt DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw); 9510ebfff14SBenjamin Herrenschmidt 9527df2457dSOlof Johansson if (hw == mpic->spurious_vec) 9530ebfff14SBenjamin Herrenschmidt return -EINVAL; 9547fd72186SBenjamin Herrenschmidt if (mpic->protected && test_bit(hw, mpic->protected)) 9557fd72186SBenjamin Herrenschmidt return -EINVAL; 95606fe98e6SBenjamin Herrenschmidt 9570ebfff14SBenjamin Herrenschmidt #ifdef CONFIG_SMP 9587df2457dSOlof Johansson else if (hw >= mpic->ipi_vecs[0]) { 9590ebfff14SBenjamin Herrenschmidt WARN_ON(!(mpic->flags & MPIC_PRIMARY)); 9600ebfff14SBenjamin Herrenschmidt 96106fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping as IPI\n"); 9620ebfff14SBenjamin Herrenschmidt set_irq_chip_data(virq, mpic); 9630ebfff14SBenjamin Herrenschmidt set_irq_chip_and_handler(virq, &mpic->hc_ipi, 9640ebfff14SBenjamin Herrenschmidt handle_percpu_irq); 9650ebfff14SBenjamin Herrenschmidt return 0; 9660ebfff14SBenjamin Herrenschmidt } 9670ebfff14SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 9680ebfff14SBenjamin Herrenschmidt 9690ebfff14SBenjamin Herrenschmidt if (hw >= mpic->irq_count) 9700ebfff14SBenjamin Herrenschmidt return -EINVAL; 9710ebfff14SBenjamin Herrenschmidt 972a7de7c74SMichael Ellerman mpic_msi_reserve_hwirq(mpic, hw); 973a7de7c74SMichael Ellerman 9746e99e458SBenjamin Herrenschmidt /* Default chip */ 9750ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_irq; 9760ebfff14SBenjamin Herrenschmidt 9776cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 9780ebfff14SBenjamin Herrenschmidt /* Check for HT interrupts, override vecpri */ 9796e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, hw)) 9800ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_ht_irq; 9816cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 9820ebfff14SBenjamin Herrenschmidt 98306fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping to irq chip @%p\n", chip); 9840ebfff14SBenjamin Herrenschmidt 9850ebfff14SBenjamin Herrenschmidt set_irq_chip_data(virq, mpic); 9860ebfff14SBenjamin Herrenschmidt set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); 9876e99e458SBenjamin Herrenschmidt 9886e99e458SBenjamin Herrenschmidt /* Set default irq type */ 9896e99e458SBenjamin Herrenschmidt set_irq_type(virq, IRQ_TYPE_NONE); 9906e99e458SBenjamin Herrenschmidt 9910ebfff14SBenjamin Herrenschmidt return 0; 9920ebfff14SBenjamin Herrenschmidt } 9930ebfff14SBenjamin Herrenschmidt 9940ebfff14SBenjamin Herrenschmidt static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, 9950ebfff14SBenjamin Herrenschmidt u32 *intspec, unsigned int intsize, 9960ebfff14SBenjamin Herrenschmidt irq_hw_number_t *out_hwirq, unsigned int *out_flags) 9970ebfff14SBenjamin Herrenschmidt 9980ebfff14SBenjamin Herrenschmidt { 9990ebfff14SBenjamin Herrenschmidt static unsigned char map_mpic_senses[4] = { 10000ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_RISING, 10010ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_LOW, 10020ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_HIGH, 10030ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_FALLING, 10040ebfff14SBenjamin Herrenschmidt }; 10050ebfff14SBenjamin Herrenschmidt 10060ebfff14SBenjamin Herrenschmidt *out_hwirq = intspec[0]; 100706fe98e6SBenjamin Herrenschmidt if (intsize > 1) { 100806fe98e6SBenjamin Herrenschmidt u32 mask = 0x3; 100906fe98e6SBenjamin Herrenschmidt 101006fe98e6SBenjamin Herrenschmidt /* Apple invented a new race of encoding on machines with 101106fe98e6SBenjamin Herrenschmidt * an HT APIC. They encode, among others, the index within 101206fe98e6SBenjamin Herrenschmidt * the HT APIC. We don't care about it here since thankfully, 101306fe98e6SBenjamin Herrenschmidt * it appears that they have the APIC already properly 101406fe98e6SBenjamin Herrenschmidt * configured, and thus our current fixup code that reads the 101506fe98e6SBenjamin Herrenschmidt * APIC config works fine. However, we still need to mask out 101606fe98e6SBenjamin Herrenschmidt * bits in the specifier to make sure we only get bit 0 which 101706fe98e6SBenjamin Herrenschmidt * is the level/edge bit (the only sense bit exposed by Apple), 101806fe98e6SBenjamin Herrenschmidt * as their bit 1 means something else. 101906fe98e6SBenjamin Herrenschmidt */ 102006fe98e6SBenjamin Herrenschmidt if (machine_is(powermac)) 102106fe98e6SBenjamin Herrenschmidt mask = 0x1; 102206fe98e6SBenjamin Herrenschmidt *out_flags = map_mpic_senses[intspec[1] & mask]; 102306fe98e6SBenjamin Herrenschmidt } else 10240ebfff14SBenjamin Herrenschmidt *out_flags = IRQ_TYPE_NONE; 10250ebfff14SBenjamin Herrenschmidt 102606fe98e6SBenjamin Herrenschmidt DBG("mpic: xlate (%d cells: 0x%08x 0x%08x) to line 0x%lx sense 0x%x\n", 102706fe98e6SBenjamin Herrenschmidt intsize, intspec[0], intspec[1], *out_hwirq, *out_flags); 102806fe98e6SBenjamin Herrenschmidt 10290ebfff14SBenjamin Herrenschmidt return 0; 10300ebfff14SBenjamin Herrenschmidt } 10310ebfff14SBenjamin Herrenschmidt 10320ebfff14SBenjamin Herrenschmidt static struct irq_host_ops mpic_host_ops = { 10330ebfff14SBenjamin Herrenschmidt .match = mpic_host_match, 10340ebfff14SBenjamin Herrenschmidt .map = mpic_host_map, 10350ebfff14SBenjamin Herrenschmidt .xlate = mpic_host_xlate, 10360ebfff14SBenjamin Herrenschmidt }; 10370ebfff14SBenjamin Herrenschmidt 103814cf11afSPaul Mackerras /* 103914cf11afSPaul Mackerras * Exported functions 104014cf11afSPaul Mackerras */ 104114cf11afSPaul Mackerras 10420ebfff14SBenjamin Herrenschmidt struct mpic * __init mpic_alloc(struct device_node *node, 1043a959ff56SBenjamin Herrenschmidt phys_addr_t phys_addr, 104414cf11afSPaul Mackerras unsigned int flags, 104514cf11afSPaul Mackerras unsigned int isu_size, 104614cf11afSPaul Mackerras unsigned int irq_count, 104714cf11afSPaul Mackerras const char *name) 104814cf11afSPaul Mackerras { 104914cf11afSPaul Mackerras struct mpic *mpic; 1050d9d1063dSJohannes Berg u32 greg_feature; 105114cf11afSPaul Mackerras const char *vers; 105214cf11afSPaul Mackerras int i; 10537df2457dSOlof Johansson int intvec_top; 1054a959ff56SBenjamin Herrenschmidt u64 paddr = phys_addr; 105514cf11afSPaul Mackerras 1056*85355bb2SKumar Gala mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); 105714cf11afSPaul Mackerras if (mpic == NULL) 105814cf11afSPaul Mackerras return NULL; 105914cf11afSPaul Mackerras 106014cf11afSPaul Mackerras mpic->name = name; 106114cf11afSPaul Mackerras 1062b9e5b4e6SBenjamin Herrenschmidt mpic->hc_irq = mpic_irq_chip; 106314cf11afSPaul Mackerras mpic->hc_irq.typename = name; 106414cf11afSPaul Mackerras if (flags & MPIC_PRIMARY) 106514cf11afSPaul Mackerras mpic->hc_irq.set_affinity = mpic_set_affinity; 10666cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 1067b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq = mpic_irq_ht_chip; 1068b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq.typename = name; 1069b9e5b4e6SBenjamin Herrenschmidt if (flags & MPIC_PRIMARY) 1070b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq.set_affinity = mpic_set_affinity; 10716cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 1072fbf0274eSBenjamin Herrenschmidt 107314cf11afSPaul Mackerras #ifdef CONFIG_SMP 1074b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ipi = mpic_ipi_chip; 10750ebfff14SBenjamin Herrenschmidt mpic->hc_ipi.typename = name; 107614cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 107714cf11afSPaul Mackerras 107814cf11afSPaul Mackerras mpic->flags = flags; 107914cf11afSPaul Mackerras mpic->isu_size = isu_size; 108014cf11afSPaul Mackerras mpic->irq_count = irq_count; 108114cf11afSPaul Mackerras mpic->num_sources = 0; /* so far */ 108214cf11afSPaul Mackerras 10837df2457dSOlof Johansson if (flags & MPIC_LARGE_VECTORS) 10847df2457dSOlof Johansson intvec_top = 2047; 10857df2457dSOlof Johansson else 10867df2457dSOlof Johansson intvec_top = 255; 10877df2457dSOlof Johansson 10887df2457dSOlof Johansson mpic->timer_vecs[0] = intvec_top - 8; 10897df2457dSOlof Johansson mpic->timer_vecs[1] = intvec_top - 7; 10907df2457dSOlof Johansson mpic->timer_vecs[2] = intvec_top - 6; 10917df2457dSOlof Johansson mpic->timer_vecs[3] = intvec_top - 5; 10927df2457dSOlof Johansson mpic->ipi_vecs[0] = intvec_top - 4; 10937df2457dSOlof Johansson mpic->ipi_vecs[1] = intvec_top - 3; 10947df2457dSOlof Johansson mpic->ipi_vecs[2] = intvec_top - 2; 10957df2457dSOlof Johansson mpic->ipi_vecs[3] = intvec_top - 1; 10967df2457dSOlof Johansson mpic->spurious_vec = intvec_top; 10977df2457dSOlof Johansson 1098a959ff56SBenjamin Herrenschmidt /* Check for "big-endian" in device-tree */ 1099e2eb6392SStephen Rothwell if (node && of_get_property(node, "big-endian", NULL) != NULL) 1100a959ff56SBenjamin Herrenschmidt mpic->flags |= MPIC_BIG_ENDIAN; 1101a959ff56SBenjamin Herrenschmidt 11027fd72186SBenjamin Herrenschmidt /* Look for protected sources */ 11037fd72186SBenjamin Herrenschmidt if (node) { 1104d9d1063dSJohannes Berg int psize; 1105d9d1063dSJohannes Berg unsigned int bits, mapsize; 11067fd72186SBenjamin Herrenschmidt const u32 *psrc = 11077fd72186SBenjamin Herrenschmidt of_get_property(node, "protected-sources", &psize); 11087fd72186SBenjamin Herrenschmidt if (psrc) { 11097fd72186SBenjamin Herrenschmidt psize /= 4; 11107fd72186SBenjamin Herrenschmidt bits = intvec_top + 1; 11117fd72186SBenjamin Herrenschmidt mapsize = BITS_TO_LONGS(bits) * sizeof(unsigned long); 11127fd72186SBenjamin Herrenschmidt mpic->protected = alloc_bootmem(mapsize); 11137fd72186SBenjamin Herrenschmidt BUG_ON(mpic->protected == NULL); 11147fd72186SBenjamin Herrenschmidt memset(mpic->protected, 0, mapsize); 11157fd72186SBenjamin Herrenschmidt for (i = 0; i < psize; i++) { 11167fd72186SBenjamin Herrenschmidt if (psrc[i] > intvec_top) 11177fd72186SBenjamin Herrenschmidt continue; 11187fd72186SBenjamin Herrenschmidt __set_bit(psrc[i], mpic->protected); 11197fd72186SBenjamin Herrenschmidt } 11207fd72186SBenjamin Herrenschmidt } 11217fd72186SBenjamin Herrenschmidt } 1122a959ff56SBenjamin Herrenschmidt 11237233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 11247233593bSZang Roy-r61911 mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; 11257233593bSZang Roy-r61911 #endif 11267233593bSZang Roy-r61911 1127fbf0274eSBenjamin Herrenschmidt /* default register type */ 1128fbf0274eSBenjamin Herrenschmidt mpic->reg_type = (flags & MPIC_BIG_ENDIAN) ? 1129fbf0274eSBenjamin Herrenschmidt mpic_access_mmio_be : mpic_access_mmio_le; 1130fbf0274eSBenjamin Herrenschmidt 1131a959ff56SBenjamin Herrenschmidt /* If no physical address is passed in, a device-node is mandatory */ 1132a959ff56SBenjamin Herrenschmidt BUG_ON(paddr == 0 && node == NULL); 1133a959ff56SBenjamin Herrenschmidt 1134a959ff56SBenjamin Herrenschmidt /* If no physical address passed in, check if it's dcr based */ 11350411a5e2SMichael Ellerman if (paddr == 0 && of_get_property(node, "dcr-reg", NULL) != NULL) { 1136fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 11370411a5e2SMichael Ellerman mpic->flags |= MPIC_USES_DCR; 1138fbf0274eSBenjamin Herrenschmidt mpic->reg_type = mpic_access_dcr; 1139fbf0274eSBenjamin Herrenschmidt #else 11400411a5e2SMichael Ellerman BUG(); 1141fbf0274eSBenjamin Herrenschmidt #endif /* CONFIG_PPC_DCR */ 11420411a5e2SMichael Ellerman } 1143fbf0274eSBenjamin Herrenschmidt 1144a959ff56SBenjamin Herrenschmidt /* If the MPIC is not DCR based, and no physical address was passed 1145a959ff56SBenjamin Herrenschmidt * in, try to obtain one 1146a959ff56SBenjamin Herrenschmidt */ 1147a959ff56SBenjamin Herrenschmidt if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) { 1148d9d1063dSJohannes Berg const u32 *reg = of_get_property(node, "reg", NULL); 1149a959ff56SBenjamin Herrenschmidt BUG_ON(reg == NULL); 1150a959ff56SBenjamin Herrenschmidt paddr = of_translate_address(node, reg); 1151a959ff56SBenjamin Herrenschmidt BUG_ON(paddr == OF_BAD_ADDR); 1152a959ff56SBenjamin Herrenschmidt } 1153a959ff56SBenjamin Herrenschmidt 115414cf11afSPaul Mackerras /* Map the global registers */ 11555a2642f6SBenjamin Herrenschmidt mpic_map(mpic, node, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); 11565a2642f6SBenjamin Herrenschmidt mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); 115714cf11afSPaul Mackerras 115814cf11afSPaul Mackerras /* Reset */ 115914cf11afSPaul Mackerras if (flags & MPIC_WANTS_RESET) { 11607233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 11617233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 116214cf11afSPaul Mackerras | MPIC_GREG_GCONF_RESET); 11637233593bSZang Roy-r61911 while( mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 116414cf11afSPaul Mackerras & MPIC_GREG_GCONF_RESET) 116514cf11afSPaul Mackerras mb(); 116614cf11afSPaul Mackerras } 116714cf11afSPaul Mackerras 1168d91e4ea7SKumar Gala /* CoreInt */ 1169d91e4ea7SKumar Gala if (flags & MPIC_ENABLE_COREINT) 1170d91e4ea7SKumar Gala mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1171d91e4ea7SKumar Gala mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1172d91e4ea7SKumar Gala | MPIC_GREG_GCONF_COREINT); 1173d91e4ea7SKumar Gala 1174f365355eSOlof Johansson if (flags & MPIC_ENABLE_MCK) 1175f365355eSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1176f365355eSOlof Johansson mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1177f365355eSOlof Johansson | MPIC_GREG_GCONF_MCK); 1178f365355eSOlof Johansson 117914cf11afSPaul Mackerras /* Read feature register, calculate num CPUs and, for non-ISU 118014cf11afSPaul Mackerras * MPICs, num sources as well. On ISU MPICs, sources are counted 118114cf11afSPaul Mackerras * as ISUs are added 118214cf11afSPaul Mackerras */ 1183d9d1063dSJohannes Berg greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); 1184d9d1063dSJohannes Berg mpic->num_cpus = ((greg_feature & MPIC_GREG_FEATURE_LAST_CPU_MASK) 118514cf11afSPaul Mackerras >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1; 11865073e7eeSAnton Vorontsov if (isu_size == 0) { 1187475ca391SKumar Gala if (flags & MPIC_BROKEN_FRR_NIRQS) 1188475ca391SKumar Gala mpic->num_sources = mpic->irq_count; 1189475ca391SKumar Gala else 1190d9d1063dSJohannes Berg mpic->num_sources = 1191d9d1063dSJohannes Berg ((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) 119214cf11afSPaul Mackerras >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; 11935073e7eeSAnton Vorontsov } 119414cf11afSPaul Mackerras 119514cf11afSPaul Mackerras /* Map the per-CPU registers */ 119614cf11afSPaul Mackerras for (i = 0; i < mpic->num_cpus; i++) { 11975a2642f6SBenjamin Herrenschmidt mpic_map(mpic, node, paddr, &mpic->cpuregs[i], 1198fbf0274eSBenjamin Herrenschmidt MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE), 1199fbf0274eSBenjamin Herrenschmidt 0x1000); 120014cf11afSPaul Mackerras } 120114cf11afSPaul Mackerras 120214cf11afSPaul Mackerras /* Initialize main ISU if none provided */ 120314cf11afSPaul Mackerras if (mpic->isu_size == 0) { 120414cf11afSPaul Mackerras mpic->isu_size = mpic->num_sources; 12055a2642f6SBenjamin Herrenschmidt mpic_map(mpic, node, paddr, &mpic->isus[0], 1206fbf0274eSBenjamin Herrenschmidt MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); 120714cf11afSPaul Mackerras } 120814cf11afSPaul Mackerras mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); 120914cf11afSPaul Mackerras mpic->isu_mask = (1 << mpic->isu_shift) - 1; 121014cf11afSPaul Mackerras 121131207dabSKumar Gala mpic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 121231207dabSKumar Gala isu_size ? isu_size : mpic->num_sources, 121331207dabSKumar Gala &mpic_host_ops, 121431207dabSKumar Gala flags & MPIC_LARGE_VECTORS ? 2048 : 256); 121531207dabSKumar Gala if (mpic->irqhost == NULL) 121631207dabSKumar Gala return NULL; 121731207dabSKumar Gala 121831207dabSKumar Gala mpic->irqhost->host_data = mpic; 121931207dabSKumar Gala 122014cf11afSPaul Mackerras /* Display version */ 1221d9d1063dSJohannes Berg switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) { 122214cf11afSPaul Mackerras case 1: 122314cf11afSPaul Mackerras vers = "1.0"; 122414cf11afSPaul Mackerras break; 122514cf11afSPaul Mackerras case 2: 122614cf11afSPaul Mackerras vers = "1.2"; 122714cf11afSPaul Mackerras break; 122814cf11afSPaul Mackerras case 3: 122914cf11afSPaul Mackerras vers = "1.3"; 123014cf11afSPaul Mackerras break; 123114cf11afSPaul Mackerras default: 123214cf11afSPaul Mackerras vers = "<unknown>"; 123314cf11afSPaul Mackerras break; 123414cf11afSPaul Mackerras } 1235a959ff56SBenjamin Herrenschmidt printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," 1236a959ff56SBenjamin Herrenschmidt " max %d CPUs\n", 1237a959ff56SBenjamin Herrenschmidt name, vers, (unsigned long long)paddr, mpic->num_cpus); 1238a959ff56SBenjamin Herrenschmidt printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", 1239a959ff56SBenjamin Herrenschmidt mpic->isu_size, mpic->isu_shift, mpic->isu_mask); 124014cf11afSPaul Mackerras 124114cf11afSPaul Mackerras mpic->next = mpics; 124214cf11afSPaul Mackerras mpics = mpic; 124314cf11afSPaul Mackerras 12440ebfff14SBenjamin Herrenschmidt if (flags & MPIC_PRIMARY) { 124514cf11afSPaul Mackerras mpic_primary = mpic; 12460ebfff14SBenjamin Herrenschmidt irq_set_default_host(mpic->irqhost); 12470ebfff14SBenjamin Herrenschmidt } 124814cf11afSPaul Mackerras 124914cf11afSPaul Mackerras return mpic; 125014cf11afSPaul Mackerras } 125114cf11afSPaul Mackerras 125214cf11afSPaul Mackerras void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, 1253a959ff56SBenjamin Herrenschmidt phys_addr_t paddr) 125414cf11afSPaul Mackerras { 125514cf11afSPaul Mackerras unsigned int isu_first = isu_num * mpic->isu_size; 125614cf11afSPaul Mackerras 125714cf11afSPaul Mackerras BUG_ON(isu_num >= MPIC_MAX_ISU); 125814cf11afSPaul Mackerras 12595a2642f6SBenjamin Herrenschmidt mpic_map(mpic, mpic->irqhost->of_node, 12605a2642f6SBenjamin Herrenschmidt paddr, &mpic->isus[isu_num], 0, 12617233593bSZang Roy-r61911 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); 12625a2642f6SBenjamin Herrenschmidt 126314cf11afSPaul Mackerras if ((isu_first + mpic->isu_size) > mpic->num_sources) 126414cf11afSPaul Mackerras mpic->num_sources = isu_first + mpic->isu_size; 126514cf11afSPaul Mackerras } 126614cf11afSPaul Mackerras 12670ebfff14SBenjamin Herrenschmidt void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count) 12680ebfff14SBenjamin Herrenschmidt { 12690ebfff14SBenjamin Herrenschmidt mpic->senses = senses; 12700ebfff14SBenjamin Herrenschmidt mpic->senses_count = count; 12710ebfff14SBenjamin Herrenschmidt } 12720ebfff14SBenjamin Herrenschmidt 127314cf11afSPaul Mackerras void __init mpic_init(struct mpic *mpic) 127414cf11afSPaul Mackerras { 127514cf11afSPaul Mackerras int i; 1276cc353c30SArnd Bergmann int cpu; 127714cf11afSPaul Mackerras 127814cf11afSPaul Mackerras BUG_ON(mpic->num_sources == 0); 127914cf11afSPaul Mackerras 128014cf11afSPaul Mackerras printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); 128114cf11afSPaul Mackerras 128214cf11afSPaul Mackerras /* Set current processor priority to max */ 12837233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 128414cf11afSPaul Mackerras 128514cf11afSPaul Mackerras /* Initialize timers: just disable them all */ 128614cf11afSPaul Mackerras for (i = 0; i < 4; i++) { 128714cf11afSPaul Mackerras mpic_write(mpic->tmregs, 12887233593bSZang Roy-r61911 i * MPIC_INFO(TIMER_STRIDE) + 12897233593bSZang Roy-r61911 MPIC_INFO(TIMER_DESTINATION), 0); 129014cf11afSPaul Mackerras mpic_write(mpic->tmregs, 12917233593bSZang Roy-r61911 i * MPIC_INFO(TIMER_STRIDE) + 12927233593bSZang Roy-r61911 MPIC_INFO(TIMER_VECTOR_PRI), 129314cf11afSPaul Mackerras MPIC_VECPRI_MASK | 12947df2457dSOlof Johansson (mpic->timer_vecs[0] + i)); 129514cf11afSPaul Mackerras } 129614cf11afSPaul Mackerras 129714cf11afSPaul Mackerras /* Initialize IPIs to our reserved vectors and mark them disabled for now */ 129814cf11afSPaul Mackerras mpic_test_broken_ipi(mpic); 129914cf11afSPaul Mackerras for (i = 0; i < 4; i++) { 130014cf11afSPaul Mackerras mpic_ipi_write(i, 130114cf11afSPaul Mackerras MPIC_VECPRI_MASK | 130214cf11afSPaul Mackerras (10 << MPIC_VECPRI_PRIORITY_SHIFT) | 13037df2457dSOlof Johansson (mpic->ipi_vecs[0] + i)); 130414cf11afSPaul Mackerras } 130514cf11afSPaul Mackerras 130614cf11afSPaul Mackerras /* Initialize interrupt sources */ 130714cf11afSPaul Mackerras if (mpic->irq_count == 0) 130814cf11afSPaul Mackerras mpic->irq_count = mpic->num_sources; 130914cf11afSPaul Mackerras 13101beb6a7dSBenjamin Herrenschmidt /* Do the HT PIC fixups on U3 broken mpic */ 131114cf11afSPaul Mackerras DBG("MPIC flags: %x\n", mpic->flags); 131205af7bd2SMichael Ellerman if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) { 13131beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pics(mpic); 131405af7bd2SMichael Ellerman mpic_u3msi_init(mpic); 131505af7bd2SMichael Ellerman } 131614cf11afSPaul Mackerras 131738958dd9SOlof Johansson mpic_pasemi_msi_init(mpic); 131838958dd9SOlof Johansson 1319cc353c30SArnd Bergmann if (mpic->flags & MPIC_PRIMARY) 1320cc353c30SArnd Bergmann cpu = hard_smp_processor_id(); 1321cc353c30SArnd Bergmann else 1322cc353c30SArnd Bergmann cpu = 0; 1323cc353c30SArnd Bergmann 132414cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources; i++) { 132514cf11afSPaul Mackerras /* start with vector = source number, and masked */ 13266e99e458SBenjamin Herrenschmidt u32 vecpri = MPIC_VECPRI_MASK | i | 13276e99e458SBenjamin Herrenschmidt (8 << MPIC_VECPRI_PRIORITY_SHIFT); 132814cf11afSPaul Mackerras 13297fd72186SBenjamin Herrenschmidt /* check if protected */ 13307fd72186SBenjamin Herrenschmidt if (mpic->protected && test_bit(i, mpic->protected)) 13317fd72186SBenjamin Herrenschmidt continue; 133214cf11afSPaul Mackerras /* init hw */ 13337233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); 1334cc353c30SArnd Bergmann mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); 133514cf11afSPaul Mackerras } 133614cf11afSPaul Mackerras 13377df2457dSOlof Johansson /* Init spurious vector */ 13387df2457dSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), mpic->spurious_vec); 133914cf11afSPaul Mackerras 13407233593bSZang Roy-r61911 /* Disable 8259 passthrough, if supported */ 13417233593bSZang Roy-r61911 if (!(mpic->flags & MPIC_NO_PTHROU_DIS)) 13427233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 13437233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 134414cf11afSPaul Mackerras | MPIC_GREG_GCONF_8259_PTHROU_DIS); 134514cf11afSPaul Mackerras 1346d87bf3beSOlof Johansson if (mpic->flags & MPIC_NO_BIAS) 1347d87bf3beSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1348d87bf3beSOlof Johansson mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1349d87bf3beSOlof Johansson | MPIC_GREG_GCONF_NO_BIAS); 1350d87bf3beSOlof Johansson 135114cf11afSPaul Mackerras /* Set current processor priority to 0 */ 13527233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 13533669e930SJohannes Berg 13543669e930SJohannes Berg #ifdef CONFIG_PM 13553669e930SJohannes Berg /* allocate memory to save mpic state */ 13563669e930SJohannes Berg mpic->save_data = alloc_bootmem(mpic->num_sources * sizeof(struct mpic_irq_save)); 13573669e930SJohannes Berg BUG_ON(mpic->save_data == NULL); 13583669e930SJohannes Berg #endif 135914cf11afSPaul Mackerras } 136014cf11afSPaul Mackerras 1361868ea0c9SMark A. Greer void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) 1362868ea0c9SMark A. Greer { 1363868ea0c9SMark A. Greer u32 v; 136414cf11afSPaul Mackerras 1365868ea0c9SMark A. Greer v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 1366868ea0c9SMark A. Greer v &= ~MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK; 1367868ea0c9SMark A. Greer v |= MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(clock_ratio); 1368868ea0c9SMark A. Greer mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 1369868ea0c9SMark A. Greer } 1370868ea0c9SMark A. Greer 1371868ea0c9SMark A. Greer void __init mpic_set_serial_int(struct mpic *mpic, int enable) 1372868ea0c9SMark A. Greer { 1373ba1826e5SBenjamin Herrenschmidt unsigned long flags; 1374868ea0c9SMark A. Greer u32 v; 1375868ea0c9SMark A. Greer 1376ba1826e5SBenjamin Herrenschmidt spin_lock_irqsave(&mpic_lock, flags); 1377868ea0c9SMark A. Greer v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 1378868ea0c9SMark A. Greer if (enable) 1379868ea0c9SMark A. Greer v |= MPIC_GREG_GLOBAL_CONF_1_SIE; 1380868ea0c9SMark A. Greer else 1381868ea0c9SMark A. Greer v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE; 1382868ea0c9SMark A. Greer mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 1383ba1826e5SBenjamin Herrenschmidt spin_unlock_irqrestore(&mpic_lock, flags); 1384868ea0c9SMark A. Greer } 138514cf11afSPaul Mackerras 138614cf11afSPaul Mackerras void mpic_irq_set_priority(unsigned int irq, unsigned int pri) 138714cf11afSPaul Mackerras { 1388d69a78d7STony Breeds struct mpic *mpic = mpic_find(irq); 13890ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 139014cf11afSPaul Mackerras unsigned long flags; 139114cf11afSPaul Mackerras u32 reg; 139214cf11afSPaul Mackerras 139306a901c5SStephen Rothwell if (!mpic) 139406a901c5SStephen Rothwell return; 139506a901c5SStephen Rothwell 139614cf11afSPaul Mackerras spin_lock_irqsave(&mpic_lock, flags); 1397d69a78d7STony Breeds if (mpic_is_ipi(mpic, irq)) { 13987df2457dSOlof Johansson reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) & 1399e5356640SBenjamin Herrenschmidt ~MPIC_VECPRI_PRIORITY_MASK; 14007df2457dSOlof Johansson mpic_ipi_write(src - mpic->ipi_vecs[0], 140114cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 140214cf11afSPaul Mackerras } else { 14037233593bSZang Roy-r61911 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) 1404e5356640SBenjamin Herrenschmidt & ~MPIC_VECPRI_PRIORITY_MASK; 14057233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 140614cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 140714cf11afSPaul Mackerras } 140814cf11afSPaul Mackerras spin_unlock_irqrestore(&mpic_lock, flags); 140914cf11afSPaul Mackerras } 141014cf11afSPaul Mackerras 141114cf11afSPaul Mackerras void mpic_setup_this_cpu(void) 141214cf11afSPaul Mackerras { 141314cf11afSPaul Mackerras #ifdef CONFIG_SMP 141414cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 141514cf11afSPaul Mackerras unsigned long flags; 141614cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 141714cf11afSPaul Mackerras unsigned int i; 141814cf11afSPaul Mackerras 141914cf11afSPaul Mackerras BUG_ON(mpic == NULL); 142014cf11afSPaul Mackerras 142114cf11afSPaul Mackerras DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 142214cf11afSPaul Mackerras 142314cf11afSPaul Mackerras spin_lock_irqsave(&mpic_lock, flags); 142414cf11afSPaul Mackerras 142514cf11afSPaul Mackerras /* let the mpic know we want intrs. default affinity is 0xffffffff 142614cf11afSPaul Mackerras * until changed via /proc. That's how it's done on x86. If we want 142714cf11afSPaul Mackerras * it differently, then we should make sure we also change the default 1428a53da52fSIngo Molnar * values of irq_desc[].affinity in irq.c. 142914cf11afSPaul Mackerras */ 143014cf11afSPaul Mackerras if (distribute_irqs) { 143114cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources ; i++) 14327233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 14337233593bSZang Roy-r61911 mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) | msk); 143414cf11afSPaul Mackerras } 143514cf11afSPaul Mackerras 143614cf11afSPaul Mackerras /* Set current processor priority to 0 */ 14377233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 143814cf11afSPaul Mackerras 143914cf11afSPaul Mackerras spin_unlock_irqrestore(&mpic_lock, flags); 144014cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 144114cf11afSPaul Mackerras } 144214cf11afSPaul Mackerras 144314cf11afSPaul Mackerras int mpic_cpu_get_priority(void) 144414cf11afSPaul Mackerras { 144514cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 144614cf11afSPaul Mackerras 14477233593bSZang Roy-r61911 return mpic_cpu_read(MPIC_INFO(CPU_CURRENT_TASK_PRI)); 144814cf11afSPaul Mackerras } 144914cf11afSPaul Mackerras 145014cf11afSPaul Mackerras void mpic_cpu_set_priority(int prio) 145114cf11afSPaul Mackerras { 145214cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 145314cf11afSPaul Mackerras 145414cf11afSPaul Mackerras prio &= MPIC_CPU_TASKPRI_MASK; 14557233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), prio); 145614cf11afSPaul Mackerras } 145714cf11afSPaul Mackerras 145814cf11afSPaul Mackerras void mpic_teardown_this_cpu(int secondary) 145914cf11afSPaul Mackerras { 146014cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 146114cf11afSPaul Mackerras unsigned long flags; 146214cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 146314cf11afSPaul Mackerras unsigned int i; 146414cf11afSPaul Mackerras 146514cf11afSPaul Mackerras BUG_ON(mpic == NULL); 146614cf11afSPaul Mackerras 146714cf11afSPaul Mackerras DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 146814cf11afSPaul Mackerras spin_lock_irqsave(&mpic_lock, flags); 146914cf11afSPaul Mackerras 147014cf11afSPaul Mackerras /* let the mpic know we don't want intrs. */ 147114cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources ; i++) 14727233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 14737233593bSZang Roy-r61911 mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) & ~msk); 147414cf11afSPaul Mackerras 147514cf11afSPaul Mackerras /* Set current processor priority to max */ 14767233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 14777132799bSValentine Barshak /* We need to EOI the IPI since not all platforms reset the MPIC 14787132799bSValentine Barshak * on boot and new interrupts wouldn't get delivered otherwise. 14797132799bSValentine Barshak */ 14807132799bSValentine Barshak mpic_eoi(mpic); 148114cf11afSPaul Mackerras 148214cf11afSPaul Mackerras spin_unlock_irqrestore(&mpic_lock, flags); 148314cf11afSPaul Mackerras } 148414cf11afSPaul Mackerras 148514cf11afSPaul Mackerras 148614cf11afSPaul Mackerras void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) 148714cf11afSPaul Mackerras { 148814cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 148914cf11afSPaul Mackerras 149014cf11afSPaul Mackerras BUG_ON(mpic == NULL); 149114cf11afSPaul Mackerras 14921beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_IPI 149314cf11afSPaul Mackerras DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); 14941beb6a7dSBenjamin Herrenschmidt #endif 149514cf11afSPaul Mackerras 14967233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + 14977233593bSZang Roy-r61911 ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), 149814cf11afSPaul Mackerras mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); 149914cf11afSPaul Mackerras } 150014cf11afSPaul Mackerras 1501f365355eSOlof Johansson static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg) 150214cf11afSPaul Mackerras { 15030ebfff14SBenjamin Herrenschmidt u32 src; 150414cf11afSPaul Mackerras 1505f365355eSOlof Johansson src = mpic_cpu_read(reg) & MPIC_INFO(VECPRI_VECTOR_MASK); 15061beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_LOW 1507f365355eSOlof Johansson DBG("%s: get_one_irq(reg 0x%x): %d\n", mpic->name, reg, src); 15081beb6a7dSBenjamin Herrenschmidt #endif 15095cddd2e3SJosh Boyer if (unlikely(src == mpic->spurious_vec)) { 15105cddd2e3SJosh Boyer if (mpic->flags & MPIC_SPV_EOI) 15115cddd2e3SJosh Boyer mpic_eoi(mpic); 15120ebfff14SBenjamin Herrenschmidt return NO_IRQ; 15135cddd2e3SJosh Boyer } 15147fd72186SBenjamin Herrenschmidt if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { 15157fd72186SBenjamin Herrenschmidt if (printk_ratelimit()) 15167fd72186SBenjamin Herrenschmidt printk(KERN_WARNING "%s: Got protected source %d !\n", 15177fd72186SBenjamin Herrenschmidt mpic->name, (int)src); 15187fd72186SBenjamin Herrenschmidt mpic_eoi(mpic); 15197fd72186SBenjamin Herrenschmidt return NO_IRQ; 15207fd72186SBenjamin Herrenschmidt } 15217fd72186SBenjamin Herrenschmidt 15220ebfff14SBenjamin Herrenschmidt return irq_linear_revmap(mpic->irqhost, src); 152314cf11afSPaul Mackerras } 152414cf11afSPaul Mackerras 1525f365355eSOlof Johansson unsigned int mpic_get_one_irq(struct mpic *mpic) 1526f365355eSOlof Johansson { 1527f365355eSOlof Johansson return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_INTACK)); 1528f365355eSOlof Johansson } 1529f365355eSOlof Johansson 153035a84c2fSOlaf Hering unsigned int mpic_get_irq(void) 153114cf11afSPaul Mackerras { 153214cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 153314cf11afSPaul Mackerras 153414cf11afSPaul Mackerras BUG_ON(mpic == NULL); 153514cf11afSPaul Mackerras 153635a84c2fSOlaf Hering return mpic_get_one_irq(mpic); 153714cf11afSPaul Mackerras } 153814cf11afSPaul Mackerras 1539d91e4ea7SKumar Gala unsigned int mpic_get_coreint_irq(void) 1540d91e4ea7SKumar Gala { 1541d91e4ea7SKumar Gala #ifdef CONFIG_BOOKE 1542d91e4ea7SKumar Gala struct mpic *mpic = mpic_primary; 1543d91e4ea7SKumar Gala u32 src; 1544d91e4ea7SKumar Gala 1545d91e4ea7SKumar Gala BUG_ON(mpic == NULL); 1546d91e4ea7SKumar Gala 1547d91e4ea7SKumar Gala src = mfspr(SPRN_EPR); 1548d91e4ea7SKumar Gala 1549d91e4ea7SKumar Gala if (unlikely(src == mpic->spurious_vec)) { 1550d91e4ea7SKumar Gala if (mpic->flags & MPIC_SPV_EOI) 1551d91e4ea7SKumar Gala mpic_eoi(mpic); 1552d91e4ea7SKumar Gala return NO_IRQ; 1553d91e4ea7SKumar Gala } 1554d91e4ea7SKumar Gala if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { 1555d91e4ea7SKumar Gala if (printk_ratelimit()) 1556d91e4ea7SKumar Gala printk(KERN_WARNING "%s: Got protected source %d !\n", 1557d91e4ea7SKumar Gala mpic->name, (int)src); 1558d91e4ea7SKumar Gala return NO_IRQ; 1559d91e4ea7SKumar Gala } 1560d91e4ea7SKumar Gala 1561d91e4ea7SKumar Gala return irq_linear_revmap(mpic->irqhost, src); 1562d91e4ea7SKumar Gala #else 1563d91e4ea7SKumar Gala return NO_IRQ; 1564d91e4ea7SKumar Gala #endif 1565d91e4ea7SKumar Gala } 1566d91e4ea7SKumar Gala 1567f365355eSOlof Johansson unsigned int mpic_get_mcirq(void) 1568f365355eSOlof Johansson { 1569f365355eSOlof Johansson struct mpic *mpic = mpic_primary; 1570f365355eSOlof Johansson 1571f365355eSOlof Johansson BUG_ON(mpic == NULL); 1572f365355eSOlof Johansson 1573f365355eSOlof Johansson return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_MCACK)); 1574f365355eSOlof Johansson } 157514cf11afSPaul Mackerras 157614cf11afSPaul Mackerras #ifdef CONFIG_SMP 157714cf11afSPaul Mackerras void mpic_request_ipis(void) 157814cf11afSPaul Mackerras { 157914cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 158078608dd3SMilton Miller int i; 158114cf11afSPaul Mackerras BUG_ON(mpic == NULL); 158214cf11afSPaul Mackerras 15830ebfff14SBenjamin Herrenschmidt printk(KERN_INFO "mpic: requesting IPIs ... \n"); 158414cf11afSPaul Mackerras 15850ebfff14SBenjamin Herrenschmidt for (i = 0; i < 4; i++) { 15860ebfff14SBenjamin Herrenschmidt unsigned int vipi = irq_create_mapping(mpic->irqhost, 15877df2457dSOlof Johansson mpic->ipi_vecs[0] + i); 15880ebfff14SBenjamin Herrenschmidt if (vipi == NO_IRQ) { 158978608dd3SMilton Miller printk(KERN_ERR "Failed to map %s\n", smp_ipi_name[i]); 159078608dd3SMilton Miller continue; 15910ebfff14SBenjamin Herrenschmidt } 159278608dd3SMilton Miller smp_request_message_ipi(vipi, i); 15930ebfff14SBenjamin Herrenschmidt } 159414cf11afSPaul Mackerras } 1595a9c59264SPaul Mackerras 1596a9c59264SPaul Mackerras void smp_mpic_message_pass(int target, int msg) 1597a9c59264SPaul Mackerras { 1598a9c59264SPaul Mackerras /* make sure we're sending something that translates to an IPI */ 1599a9c59264SPaul Mackerras if ((unsigned int)msg > 3) { 1600a9c59264SPaul Mackerras printk("SMP %d: smp_message_pass: unknown msg %d\n", 1601a9c59264SPaul Mackerras smp_processor_id(), msg); 1602a9c59264SPaul Mackerras return; 1603a9c59264SPaul Mackerras } 1604a9c59264SPaul Mackerras switch (target) { 1605a9c59264SPaul Mackerras case MSG_ALL: 1606a9c59264SPaul Mackerras mpic_send_ipi(msg, 0xffffffff); 1607a9c59264SPaul Mackerras break; 1608a9c59264SPaul Mackerras case MSG_ALL_BUT_SELF: 1609a9c59264SPaul Mackerras mpic_send_ipi(msg, 0xffffffff & ~(1 << smp_processor_id())); 1610a9c59264SPaul Mackerras break; 1611a9c59264SPaul Mackerras default: 1612a9c59264SPaul Mackerras mpic_send_ipi(msg, 1 << target); 1613a9c59264SPaul Mackerras break; 1614a9c59264SPaul Mackerras } 1615a9c59264SPaul Mackerras } 1616775aeff4SMichael Ellerman 1617775aeff4SMichael Ellerman int __init smp_mpic_probe(void) 1618775aeff4SMichael Ellerman { 1619775aeff4SMichael Ellerman int nr_cpus; 1620775aeff4SMichael Ellerman 1621775aeff4SMichael Ellerman DBG("smp_mpic_probe()...\n"); 1622775aeff4SMichael Ellerman 1623775aeff4SMichael Ellerman nr_cpus = cpus_weight(cpu_possible_map); 1624775aeff4SMichael Ellerman 1625775aeff4SMichael Ellerman DBG("nr_cpus: %d\n", nr_cpus); 1626775aeff4SMichael Ellerman 1627775aeff4SMichael Ellerman if (nr_cpus > 1) 1628775aeff4SMichael Ellerman mpic_request_ipis(); 1629775aeff4SMichael Ellerman 1630775aeff4SMichael Ellerman return nr_cpus; 1631775aeff4SMichael Ellerman } 1632775aeff4SMichael Ellerman 1633775aeff4SMichael Ellerman void __devinit smp_mpic_setup_cpu(int cpu) 1634775aeff4SMichael Ellerman { 1635775aeff4SMichael Ellerman mpic_setup_this_cpu(); 1636775aeff4SMichael Ellerman } 163714cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 16383669e930SJohannes Berg 16393669e930SJohannes Berg #ifdef CONFIG_PM 16403669e930SJohannes Berg static int mpic_suspend(struct sys_device *dev, pm_message_t state) 16413669e930SJohannes Berg { 16423669e930SJohannes Berg struct mpic *mpic = container_of(dev, struct mpic, sysdev); 16433669e930SJohannes Berg int i; 16443669e930SJohannes Berg 16453669e930SJohannes Berg for (i = 0; i < mpic->num_sources; i++) { 16463669e930SJohannes Berg mpic->save_data[i].vecprio = 16473669e930SJohannes Berg mpic_irq_read(i, MPIC_INFO(IRQ_VECTOR_PRI)); 16483669e930SJohannes Berg mpic->save_data[i].dest = 16493669e930SJohannes Berg mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); 16503669e930SJohannes Berg } 16513669e930SJohannes Berg 16523669e930SJohannes Berg return 0; 16533669e930SJohannes Berg } 16543669e930SJohannes Berg 16553669e930SJohannes Berg static int mpic_resume(struct sys_device *dev) 16563669e930SJohannes Berg { 16573669e930SJohannes Berg struct mpic *mpic = container_of(dev, struct mpic, sysdev); 16583669e930SJohannes Berg int i; 16593669e930SJohannes Berg 16603669e930SJohannes Berg for (i = 0; i < mpic->num_sources; i++) { 16613669e930SJohannes Berg mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), 16623669e930SJohannes Berg mpic->save_data[i].vecprio); 16633669e930SJohannes Berg mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 16643669e930SJohannes Berg mpic->save_data[i].dest); 16653669e930SJohannes Berg 16663669e930SJohannes Berg #ifdef CONFIG_MPIC_U3_HT_IRQS 16673669e930SJohannes Berg { 16683669e930SJohannes Berg struct mpic_irq_fixup *fixup = &mpic->fixups[i]; 16693669e930SJohannes Berg 16703669e930SJohannes Berg if (fixup->base) { 16713669e930SJohannes Berg /* we use the lowest bit in an inverted meaning */ 16723669e930SJohannes Berg if ((mpic->save_data[i].fixup_data & 1) == 0) 16733669e930SJohannes Berg continue; 16743669e930SJohannes Berg 16753669e930SJohannes Berg /* Enable and configure */ 16763669e930SJohannes Berg writeb(0x10 + 2 * fixup->index, fixup->base + 2); 16773669e930SJohannes Berg 16783669e930SJohannes Berg writel(mpic->save_data[i].fixup_data & ~1, 16793669e930SJohannes Berg fixup->base + 4); 16803669e930SJohannes Berg } 16813669e930SJohannes Berg } 16823669e930SJohannes Berg #endif 16833669e930SJohannes Berg } /* end for loop */ 16843669e930SJohannes Berg 16853669e930SJohannes Berg return 0; 16863669e930SJohannes Berg } 16873669e930SJohannes Berg #endif 16883669e930SJohannes Berg 16893669e930SJohannes Berg static struct sysdev_class mpic_sysclass = { 16903669e930SJohannes Berg #ifdef CONFIG_PM 16913669e930SJohannes Berg .resume = mpic_resume, 16923669e930SJohannes Berg .suspend = mpic_suspend, 16933669e930SJohannes Berg #endif 1694af5ca3f4SKay Sievers .name = "mpic", 16953669e930SJohannes Berg }; 16963669e930SJohannes Berg 16973669e930SJohannes Berg static int mpic_init_sys(void) 16983669e930SJohannes Berg { 16993669e930SJohannes Berg struct mpic *mpic = mpics; 17003669e930SJohannes Berg int error, id = 0; 17013669e930SJohannes Berg 17023669e930SJohannes Berg error = sysdev_class_register(&mpic_sysclass); 17033669e930SJohannes Berg 17043669e930SJohannes Berg while (mpic && !error) { 17053669e930SJohannes Berg mpic->sysdev.cls = &mpic_sysclass; 17063669e930SJohannes Berg mpic->sysdev.id = id++; 17073669e930SJohannes Berg error = sysdev_register(&mpic->sysdev); 17083669e930SJohannes Berg mpic = mpic->next; 17093669e930SJohannes Berg } 17103669e930SJohannes Berg return error; 17113669e930SJohannes Berg } 17123669e930SJohannes Berg 17133669e930SJohannes Berg device_initcall(mpic_init_sys); 1714