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> 295a0e3ad6STejun Heo #include <linux/slab.h> 3014cf11afSPaul Mackerras 3114cf11afSPaul Mackerras #include <asm/ptrace.h> 3214cf11afSPaul Mackerras #include <asm/signal.h> 3314cf11afSPaul Mackerras #include <asm/io.h> 3414cf11afSPaul Mackerras #include <asm/pgtable.h> 3514cf11afSPaul Mackerras #include <asm/irq.h> 3614cf11afSPaul Mackerras #include <asm/machdep.h> 3714cf11afSPaul Mackerras #include <asm/mpic.h> 3814cf11afSPaul Mackerras #include <asm/smp.h> 3914cf11afSPaul Mackerras 40a7de7c74SMichael Ellerman #include "mpic.h" 41a7de7c74SMichael Ellerman 4214cf11afSPaul Mackerras #ifdef DEBUG 4314cf11afSPaul Mackerras #define DBG(fmt...) printk(fmt) 4414cf11afSPaul Mackerras #else 4514cf11afSPaul Mackerras #define DBG(fmt...) 4614cf11afSPaul Mackerras #endif 4714cf11afSPaul Mackerras 4814cf11afSPaul Mackerras static struct mpic *mpics; 4914cf11afSPaul Mackerras static struct mpic *mpic_primary; 50203041adSThomas Gleixner static DEFINE_RAW_SPINLOCK(mpic_lock); 5114cf11afSPaul Mackerras 52c0c0d996SPaul Mackerras #ifdef CONFIG_PPC32 /* XXX for now */ 53e40c7f02SAndy Whitcroft #ifdef CONFIG_IRQ_ALL_CPUS 54e40c7f02SAndy Whitcroft #define distribute_irqs (1) 55e40c7f02SAndy Whitcroft #else 56e40c7f02SAndy Whitcroft #define distribute_irqs (0) 57e40c7f02SAndy Whitcroft #endif 58c0c0d996SPaul Mackerras #endif 5914cf11afSPaul Mackerras 607233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 617233593bSZang Roy-r61911 static u32 mpic_infos[][MPIC_IDX_END] = { 627233593bSZang Roy-r61911 [0] = { /* Original OpenPIC compatible MPIC */ 637233593bSZang Roy-r61911 MPIC_GREG_BASE, 647233593bSZang Roy-r61911 MPIC_GREG_FEATURE_0, 657233593bSZang Roy-r61911 MPIC_GREG_GLOBAL_CONF_0, 667233593bSZang Roy-r61911 MPIC_GREG_VENDOR_ID, 677233593bSZang Roy-r61911 MPIC_GREG_IPI_VECTOR_PRI_0, 687233593bSZang Roy-r61911 MPIC_GREG_IPI_STRIDE, 697233593bSZang Roy-r61911 MPIC_GREG_SPURIOUS, 707233593bSZang Roy-r61911 MPIC_GREG_TIMER_FREQ, 717233593bSZang Roy-r61911 727233593bSZang Roy-r61911 MPIC_TIMER_BASE, 737233593bSZang Roy-r61911 MPIC_TIMER_STRIDE, 747233593bSZang Roy-r61911 MPIC_TIMER_CURRENT_CNT, 757233593bSZang Roy-r61911 MPIC_TIMER_BASE_CNT, 767233593bSZang Roy-r61911 MPIC_TIMER_VECTOR_PRI, 777233593bSZang Roy-r61911 MPIC_TIMER_DESTINATION, 787233593bSZang Roy-r61911 797233593bSZang Roy-r61911 MPIC_CPU_BASE, 807233593bSZang Roy-r61911 MPIC_CPU_STRIDE, 817233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_0, 827233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_STRIDE, 837233593bSZang Roy-r61911 MPIC_CPU_CURRENT_TASK_PRI, 847233593bSZang Roy-r61911 MPIC_CPU_WHOAMI, 857233593bSZang Roy-r61911 MPIC_CPU_INTACK, 867233593bSZang Roy-r61911 MPIC_CPU_EOI, 87f365355eSOlof Johansson MPIC_CPU_MCACK, 887233593bSZang Roy-r61911 897233593bSZang Roy-r61911 MPIC_IRQ_BASE, 907233593bSZang Roy-r61911 MPIC_IRQ_STRIDE, 917233593bSZang Roy-r61911 MPIC_IRQ_VECTOR_PRI, 927233593bSZang Roy-r61911 MPIC_VECPRI_VECTOR_MASK, 937233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_POSITIVE, 947233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_NEGATIVE, 957233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_LEVEL, 967233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_EDGE, 977233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_MASK, 987233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_MASK, 997233593bSZang Roy-r61911 MPIC_IRQ_DESTINATION 1007233593bSZang Roy-r61911 }, 1017233593bSZang Roy-r61911 [1] = { /* Tsi108/109 PIC */ 1027233593bSZang Roy-r61911 TSI108_GREG_BASE, 1037233593bSZang Roy-r61911 TSI108_GREG_FEATURE_0, 1047233593bSZang Roy-r61911 TSI108_GREG_GLOBAL_CONF_0, 1057233593bSZang Roy-r61911 TSI108_GREG_VENDOR_ID, 1067233593bSZang Roy-r61911 TSI108_GREG_IPI_VECTOR_PRI_0, 1077233593bSZang Roy-r61911 TSI108_GREG_IPI_STRIDE, 1087233593bSZang Roy-r61911 TSI108_GREG_SPURIOUS, 1097233593bSZang Roy-r61911 TSI108_GREG_TIMER_FREQ, 1107233593bSZang Roy-r61911 1117233593bSZang Roy-r61911 TSI108_TIMER_BASE, 1127233593bSZang Roy-r61911 TSI108_TIMER_STRIDE, 1137233593bSZang Roy-r61911 TSI108_TIMER_CURRENT_CNT, 1147233593bSZang Roy-r61911 TSI108_TIMER_BASE_CNT, 1157233593bSZang Roy-r61911 TSI108_TIMER_VECTOR_PRI, 1167233593bSZang Roy-r61911 TSI108_TIMER_DESTINATION, 1177233593bSZang Roy-r61911 1187233593bSZang Roy-r61911 TSI108_CPU_BASE, 1197233593bSZang Roy-r61911 TSI108_CPU_STRIDE, 1207233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_0, 1217233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_STRIDE, 1227233593bSZang Roy-r61911 TSI108_CPU_CURRENT_TASK_PRI, 1237233593bSZang Roy-r61911 TSI108_CPU_WHOAMI, 1247233593bSZang Roy-r61911 TSI108_CPU_INTACK, 1257233593bSZang Roy-r61911 TSI108_CPU_EOI, 126f365355eSOlof Johansson TSI108_CPU_MCACK, 1277233593bSZang Roy-r61911 1287233593bSZang Roy-r61911 TSI108_IRQ_BASE, 1297233593bSZang Roy-r61911 TSI108_IRQ_STRIDE, 1307233593bSZang Roy-r61911 TSI108_IRQ_VECTOR_PRI, 1317233593bSZang Roy-r61911 TSI108_VECPRI_VECTOR_MASK, 1327233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_POSITIVE, 1337233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_NEGATIVE, 1347233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_LEVEL, 1357233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_EDGE, 1367233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_MASK, 1377233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_MASK, 1387233593bSZang Roy-r61911 TSI108_IRQ_DESTINATION 1397233593bSZang Roy-r61911 }, 1407233593bSZang Roy-r61911 }; 1417233593bSZang Roy-r61911 1427233593bSZang Roy-r61911 #define MPIC_INFO(name) mpic->hw_set[MPIC_IDX_##name] 1437233593bSZang Roy-r61911 1447233593bSZang Roy-r61911 #else /* CONFIG_MPIC_WEIRD */ 1457233593bSZang Roy-r61911 1467233593bSZang Roy-r61911 #define MPIC_INFO(name) MPIC_##name 1477233593bSZang Roy-r61911 1487233593bSZang Roy-r61911 #endif /* CONFIG_MPIC_WEIRD */ 1497233593bSZang Roy-r61911 150d6a2639bSMeador Inge static inline unsigned int mpic_processor_id(struct mpic *mpic) 151d6a2639bSMeador Inge { 152d6a2639bSMeador Inge unsigned int cpu = 0; 153d6a2639bSMeador Inge 154d6a2639bSMeador Inge if (mpic->flags & MPIC_PRIMARY) 155d6a2639bSMeador Inge cpu = hard_smp_processor_id(); 156d6a2639bSMeador Inge 157d6a2639bSMeador Inge return cpu; 158d6a2639bSMeador Inge } 159d6a2639bSMeador Inge 16014cf11afSPaul Mackerras /* 16114cf11afSPaul Mackerras * Register accessor functions 16214cf11afSPaul Mackerras */ 16314cf11afSPaul Mackerras 16414cf11afSPaul Mackerras 165fbf0274eSBenjamin Herrenschmidt static inline u32 _mpic_read(enum mpic_reg_type type, 166fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, 16714cf11afSPaul Mackerras unsigned int reg) 16814cf11afSPaul Mackerras { 169fbf0274eSBenjamin Herrenschmidt switch(type) { 170fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 171fbf0274eSBenjamin Herrenschmidt case mpic_access_dcr: 17283f34df4SMichael Ellerman return dcr_read(rb->dhost, reg); 173fbf0274eSBenjamin Herrenschmidt #endif 174fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_be: 175fbf0274eSBenjamin Herrenschmidt return in_be32(rb->base + (reg >> 2)); 176fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_le: 177fbf0274eSBenjamin Herrenschmidt default: 178fbf0274eSBenjamin Herrenschmidt return in_le32(rb->base + (reg >> 2)); 179fbf0274eSBenjamin Herrenschmidt } 18014cf11afSPaul Mackerras } 18114cf11afSPaul Mackerras 182fbf0274eSBenjamin Herrenschmidt static inline void _mpic_write(enum mpic_reg_type type, 183fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, 18414cf11afSPaul Mackerras unsigned int reg, u32 value) 18514cf11afSPaul Mackerras { 186fbf0274eSBenjamin Herrenschmidt switch(type) { 187fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 188fbf0274eSBenjamin Herrenschmidt case mpic_access_dcr: 189d9d1063dSJohannes Berg dcr_write(rb->dhost, reg, value); 190d9d1063dSJohannes Berg break; 191fbf0274eSBenjamin Herrenschmidt #endif 192fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_be: 193d9d1063dSJohannes Berg out_be32(rb->base + (reg >> 2), value); 194d9d1063dSJohannes Berg break; 195fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_le: 196fbf0274eSBenjamin Herrenschmidt default: 197d9d1063dSJohannes Berg out_le32(rb->base + (reg >> 2), value); 198d9d1063dSJohannes Berg break; 199fbf0274eSBenjamin Herrenschmidt } 20014cf11afSPaul Mackerras } 20114cf11afSPaul Mackerras 20214cf11afSPaul Mackerras static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) 20314cf11afSPaul Mackerras { 204fbf0274eSBenjamin Herrenschmidt enum mpic_reg_type type = mpic->reg_type; 2057233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 2067233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 20714cf11afSPaul Mackerras 208fbf0274eSBenjamin Herrenschmidt if ((mpic->flags & MPIC_BROKEN_IPI) && type == mpic_access_mmio_le) 209fbf0274eSBenjamin Herrenschmidt type = mpic_access_mmio_be; 210fbf0274eSBenjamin Herrenschmidt return _mpic_read(type, &mpic->gregs, offset); 21114cf11afSPaul Mackerras } 21214cf11afSPaul Mackerras 21314cf11afSPaul Mackerras static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) 21414cf11afSPaul Mackerras { 2157233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 2167233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 21714cf11afSPaul Mackerras 218fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); 21914cf11afSPaul Mackerras } 22014cf11afSPaul Mackerras 22114cf11afSPaul Mackerras static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) 22214cf11afSPaul Mackerras { 223d6a2639bSMeador Inge unsigned int cpu = mpic_processor_id(mpic); 22414cf11afSPaul Mackerras 225fbf0274eSBenjamin Herrenschmidt return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg); 22614cf11afSPaul Mackerras } 22714cf11afSPaul Mackerras 22814cf11afSPaul Mackerras static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) 22914cf11afSPaul Mackerras { 230d6a2639bSMeador Inge unsigned int cpu = mpic_processor_id(mpic); 23114cf11afSPaul Mackerras 232fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value); 23314cf11afSPaul Mackerras } 23414cf11afSPaul Mackerras 23514cf11afSPaul Mackerras static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) 23614cf11afSPaul Mackerras { 23714cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 23814cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 23911a6b292SMichael Ellerman unsigned int val; 24014cf11afSPaul Mackerras 24111a6b292SMichael Ellerman val = _mpic_read(mpic->reg_type, &mpic->isus[isu], 24211a6b292SMichael Ellerman reg + (idx * MPIC_INFO(IRQ_STRIDE))); 2430d72ba93SOlof Johansson #ifdef CONFIG_MPIC_BROKEN_REGREAD 2440d72ba93SOlof Johansson if (reg == 0) 24511a6b292SMichael Ellerman val = (val & (MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY)) | 24611a6b292SMichael Ellerman mpic->isu_reg0_shadow[src_no]; 2470d72ba93SOlof Johansson #endif 24811a6b292SMichael Ellerman return val; 24914cf11afSPaul Mackerras } 25014cf11afSPaul Mackerras 25114cf11afSPaul Mackerras static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, 25214cf11afSPaul Mackerras unsigned int reg, u32 value) 25314cf11afSPaul Mackerras { 25414cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 25514cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 25614cf11afSPaul Mackerras 257fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->isus[isu], 2587233593bSZang Roy-r61911 reg + (idx * MPIC_INFO(IRQ_STRIDE)), value); 2590d72ba93SOlof Johansson 2600d72ba93SOlof Johansson #ifdef CONFIG_MPIC_BROKEN_REGREAD 2610d72ba93SOlof Johansson if (reg == 0) 26211a6b292SMichael Ellerman mpic->isu_reg0_shadow[src_no] = 26311a6b292SMichael Ellerman value & ~(MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY); 2640d72ba93SOlof Johansson #endif 26514cf11afSPaul Mackerras } 26614cf11afSPaul Mackerras 267fbf0274eSBenjamin Herrenschmidt #define mpic_read(b,r) _mpic_read(mpic->reg_type,&(b),(r)) 268fbf0274eSBenjamin Herrenschmidt #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) 26914cf11afSPaul Mackerras #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) 27014cf11afSPaul Mackerras #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) 27114cf11afSPaul Mackerras #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) 27214cf11afSPaul Mackerras #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) 27314cf11afSPaul Mackerras #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) 27414cf11afSPaul Mackerras #define mpic_irq_write(s,r,v) _mpic_irq_write(mpic,(s),(r),(v)) 27514cf11afSPaul Mackerras 27614cf11afSPaul Mackerras 27714cf11afSPaul Mackerras /* 27814cf11afSPaul Mackerras * Low level utility functions 27914cf11afSPaul Mackerras */ 28014cf11afSPaul Mackerras 28114cf11afSPaul Mackerras 282c51a3fdcSBecky Bruce static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr, 283fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, unsigned int offset, 284fbf0274eSBenjamin Herrenschmidt unsigned int size) 285fbf0274eSBenjamin Herrenschmidt { 286fbf0274eSBenjamin Herrenschmidt rb->base = ioremap(phys_addr + offset, size); 287fbf0274eSBenjamin Herrenschmidt BUG_ON(rb->base == NULL); 288fbf0274eSBenjamin Herrenschmidt } 289fbf0274eSBenjamin Herrenschmidt 290fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 2915a2642f6SBenjamin Herrenschmidt static void _mpic_map_dcr(struct mpic *mpic, struct device_node *node, 2925a2642f6SBenjamin Herrenschmidt struct mpic_reg_bank *rb, 293fbf0274eSBenjamin Herrenschmidt unsigned int offset, unsigned int size) 294fbf0274eSBenjamin Herrenschmidt { 2950411a5e2SMichael Ellerman const u32 *dbasep; 2960411a5e2SMichael Ellerman 2975a2642f6SBenjamin Herrenschmidt dbasep = of_get_property(node, "dcr-reg", NULL); 2980411a5e2SMichael Ellerman 2995a2642f6SBenjamin Herrenschmidt rb->dhost = dcr_map(node, *dbasep + offset, size); 300fbf0274eSBenjamin Herrenschmidt BUG_ON(!DCR_MAP_OK(rb->dhost)); 301fbf0274eSBenjamin Herrenschmidt } 302fbf0274eSBenjamin Herrenschmidt 3035a2642f6SBenjamin Herrenschmidt static inline void mpic_map(struct mpic *mpic, struct device_node *node, 3045a2642f6SBenjamin Herrenschmidt phys_addr_t phys_addr, struct mpic_reg_bank *rb, 3055a2642f6SBenjamin Herrenschmidt unsigned int offset, unsigned int size) 306fbf0274eSBenjamin Herrenschmidt { 307fbf0274eSBenjamin Herrenschmidt if (mpic->flags & MPIC_USES_DCR) 3085a2642f6SBenjamin Herrenschmidt _mpic_map_dcr(mpic, node, rb, offset, size); 309fbf0274eSBenjamin Herrenschmidt else 310fbf0274eSBenjamin Herrenschmidt _mpic_map_mmio(mpic, phys_addr, rb, offset, size); 311fbf0274eSBenjamin Herrenschmidt } 312fbf0274eSBenjamin Herrenschmidt #else /* CONFIG_PPC_DCR */ 3135a2642f6SBenjamin Herrenschmidt #define mpic_map(m,n,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) 314fbf0274eSBenjamin Herrenschmidt #endif /* !CONFIG_PPC_DCR */ 315fbf0274eSBenjamin Herrenschmidt 316fbf0274eSBenjamin Herrenschmidt 31714cf11afSPaul Mackerras 31814cf11afSPaul Mackerras /* Check if we have one of those nice broken MPICs with a flipped endian on 31914cf11afSPaul Mackerras * reads from IPI registers 32014cf11afSPaul Mackerras */ 32114cf11afSPaul Mackerras static void __init mpic_test_broken_ipi(struct mpic *mpic) 32214cf11afSPaul Mackerras { 32314cf11afSPaul Mackerras u32 r; 32414cf11afSPaul Mackerras 3257233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0), MPIC_VECPRI_MASK); 3267233593bSZang Roy-r61911 r = mpic_read(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0)); 32714cf11afSPaul Mackerras 32814cf11afSPaul Mackerras if (r == le32_to_cpu(MPIC_VECPRI_MASK)) { 32914cf11afSPaul Mackerras printk(KERN_INFO "mpic: Detected reversed IPI registers\n"); 33014cf11afSPaul Mackerras mpic->flags |= MPIC_BROKEN_IPI; 33114cf11afSPaul Mackerras } 33214cf11afSPaul Mackerras } 33314cf11afSPaul Mackerras 3346cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 33514cf11afSPaul Mackerras 33614cf11afSPaul Mackerras /* Test if an interrupt is sourced from HyperTransport (used on broken U3s) 33714cf11afSPaul Mackerras * to force the edge setting on the MPIC and do the ack workaround. 33814cf11afSPaul Mackerras */ 3391beb6a7dSBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 34014cf11afSPaul Mackerras { 3411beb6a7dSBenjamin Herrenschmidt if (source >= 128 || !mpic->fixups) 34214cf11afSPaul Mackerras return 0; 3431beb6a7dSBenjamin Herrenschmidt return mpic->fixups[source].base != NULL; 34414cf11afSPaul Mackerras } 34514cf11afSPaul Mackerras 346c4b22f26SSegher Boessenkool 3471beb6a7dSBenjamin Herrenschmidt static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source) 34814cf11afSPaul Mackerras { 3491beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 35014cf11afSPaul Mackerras 3511beb6a7dSBenjamin Herrenschmidt if (fixup->applebase) { 3521beb6a7dSBenjamin Herrenschmidt unsigned int soff = (fixup->index >> 3) & ~3; 3531beb6a7dSBenjamin Herrenschmidt unsigned int mask = 1U << (fixup->index & 0x1f); 3541beb6a7dSBenjamin Herrenschmidt writel(mask, fixup->applebase + soff); 3551beb6a7dSBenjamin Herrenschmidt } else { 356203041adSThomas Gleixner raw_spin_lock(&mpic->fixup_lock); 3571beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * fixup->index, fixup->base + 2); 358c4b22f26SSegher Boessenkool writel(fixup->data, fixup->base + 4); 359203041adSThomas Gleixner raw_spin_unlock(&mpic->fixup_lock); 36014cf11afSPaul Mackerras } 3611beb6a7dSBenjamin Herrenschmidt } 36214cf11afSPaul Mackerras 3631beb6a7dSBenjamin Herrenschmidt static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, 36424a3f2e8SThomas Gleixner bool level) 3651beb6a7dSBenjamin Herrenschmidt { 3661beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 3671beb6a7dSBenjamin Herrenschmidt unsigned long flags; 3681beb6a7dSBenjamin Herrenschmidt u32 tmp; 36914cf11afSPaul Mackerras 3701beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 3711beb6a7dSBenjamin Herrenschmidt return; 3721beb6a7dSBenjamin Herrenschmidt 37324a3f2e8SThomas Gleixner DBG("startup_ht_interrupt(0x%x) index: %d\n", 37424a3f2e8SThomas Gleixner source, fixup->index); 375203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic->fixup_lock, flags); 3761beb6a7dSBenjamin Herrenschmidt /* Enable and configure */ 3771beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 3781beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 3791beb6a7dSBenjamin Herrenschmidt tmp &= ~(0x23U); 38024a3f2e8SThomas Gleixner if (level) 3811beb6a7dSBenjamin Herrenschmidt tmp |= 0x22; 3821beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 383203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags); 3843669e930SJohannes Berg 3853669e930SJohannes Berg #ifdef CONFIG_PM 3863669e930SJohannes Berg /* use the lowest bit inverted to the actual HW, 3873669e930SJohannes Berg * set if this fixup was enabled, clear otherwise */ 3883669e930SJohannes Berg mpic->save_data[source].fixup_data = tmp | 1; 3893669e930SJohannes Berg #endif 3901beb6a7dSBenjamin Herrenschmidt } 3911beb6a7dSBenjamin Herrenschmidt 39224a3f2e8SThomas Gleixner static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source) 3931beb6a7dSBenjamin Herrenschmidt { 3941beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 3951beb6a7dSBenjamin Herrenschmidt unsigned long flags; 3961beb6a7dSBenjamin Herrenschmidt u32 tmp; 3971beb6a7dSBenjamin Herrenschmidt 3981beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 3991beb6a7dSBenjamin Herrenschmidt return; 4001beb6a7dSBenjamin Herrenschmidt 40124a3f2e8SThomas Gleixner DBG("shutdown_ht_interrupt(0x%x)\n", source); 4021beb6a7dSBenjamin Herrenschmidt 4031beb6a7dSBenjamin Herrenschmidt /* Disable */ 404203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic->fixup_lock, flags); 4051beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 4061beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 40772b13819SSegher Boessenkool tmp |= 1; 4081beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 409203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags); 4103669e930SJohannes Berg 4113669e930SJohannes Berg #ifdef CONFIG_PM 4123669e930SJohannes Berg /* use the lowest bit inverted to the actual HW, 4133669e930SJohannes Berg * set if this fixup was enabled, clear otherwise */ 4143669e930SJohannes Berg mpic->save_data[source].fixup_data = tmp & ~1; 4153669e930SJohannes Berg #endif 4161beb6a7dSBenjamin Herrenschmidt } 4171beb6a7dSBenjamin Herrenschmidt 418812fd1fdSMichael Ellerman #ifdef CONFIG_PCI_MSI 419812fd1fdSMichael Ellerman static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, 420812fd1fdSMichael Ellerman unsigned int devfn) 421812fd1fdSMichael Ellerman { 422812fd1fdSMichael Ellerman u8 __iomem *base; 423812fd1fdSMichael Ellerman u8 pos, flags; 424812fd1fdSMichael Ellerman u64 addr = 0; 425812fd1fdSMichael Ellerman 426812fd1fdSMichael Ellerman for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; 427812fd1fdSMichael Ellerman pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { 428812fd1fdSMichael Ellerman u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); 429812fd1fdSMichael Ellerman if (id == PCI_CAP_ID_HT) { 430812fd1fdSMichael Ellerman id = readb(devbase + pos + 3); 431812fd1fdSMichael Ellerman if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_MSI_MAPPING) 432812fd1fdSMichael Ellerman break; 433812fd1fdSMichael Ellerman } 434812fd1fdSMichael Ellerman } 435812fd1fdSMichael Ellerman 436812fd1fdSMichael Ellerman if (pos == 0) 437812fd1fdSMichael Ellerman return; 438812fd1fdSMichael Ellerman 439812fd1fdSMichael Ellerman base = devbase + pos; 440812fd1fdSMichael Ellerman 441812fd1fdSMichael Ellerman flags = readb(base + HT_MSI_FLAGS); 442812fd1fdSMichael Ellerman if (!(flags & HT_MSI_FLAGS_FIXED)) { 443812fd1fdSMichael Ellerman addr = readl(base + HT_MSI_ADDR_LO) & HT_MSI_ADDR_LO_MASK; 444812fd1fdSMichael Ellerman addr = addr | ((u64)readl(base + HT_MSI_ADDR_HI) << 32); 445812fd1fdSMichael Ellerman } 446812fd1fdSMichael Ellerman 447fe333321SIngo Molnar printk(KERN_DEBUG "mpic: - HT:%02x.%x %s MSI mapping found @ 0x%llx\n", 448812fd1fdSMichael Ellerman PCI_SLOT(devfn), PCI_FUNC(devfn), 449812fd1fdSMichael Ellerman flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled", addr); 450812fd1fdSMichael Ellerman 451812fd1fdSMichael Ellerman if (!(flags & HT_MSI_FLAGS_ENABLE)) 452812fd1fdSMichael Ellerman writeb(flags | HT_MSI_FLAGS_ENABLE, base + HT_MSI_FLAGS); 453812fd1fdSMichael Ellerman } 454812fd1fdSMichael Ellerman #else 455812fd1fdSMichael Ellerman static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, 456812fd1fdSMichael Ellerman unsigned int devfn) 457812fd1fdSMichael Ellerman { 458812fd1fdSMichael Ellerman return; 459812fd1fdSMichael Ellerman } 460812fd1fdSMichael Ellerman #endif 461812fd1fdSMichael Ellerman 4621beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, 4631beb6a7dSBenjamin Herrenschmidt unsigned int devfn, u32 vdid) 46414cf11afSPaul Mackerras { 465c4b22f26SSegher Boessenkool int i, irq, n; 4661beb6a7dSBenjamin Herrenschmidt u8 __iomem *base; 46714cf11afSPaul Mackerras u32 tmp; 468c4b22f26SSegher Boessenkool u8 pos; 46914cf11afSPaul Mackerras 4701beb6a7dSBenjamin Herrenschmidt for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; 4711beb6a7dSBenjamin Herrenschmidt pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { 4721beb6a7dSBenjamin Herrenschmidt u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); 47346ff3463SBrice Goglin if (id == PCI_CAP_ID_HT) { 474c4b22f26SSegher Boessenkool id = readb(devbase + pos + 3); 475beb7cc82SMichael Ellerman if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_IRQ) 476c4b22f26SSegher Boessenkool break; 477c4b22f26SSegher Boessenkool } 478c4b22f26SSegher Boessenkool } 479c4b22f26SSegher Boessenkool if (pos == 0) 480c4b22f26SSegher Boessenkool return; 481c4b22f26SSegher Boessenkool 4821beb6a7dSBenjamin Herrenschmidt base = devbase + pos; 4831beb6a7dSBenjamin Herrenschmidt writeb(0x01, base + 2); 4841beb6a7dSBenjamin Herrenschmidt n = (readl(base + 4) >> 16) & 0xff; 485c4b22f26SSegher Boessenkool 4861beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x" 4871beb6a7dSBenjamin Herrenschmidt " has %d irqs\n", 4881beb6a7dSBenjamin Herrenschmidt devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1); 489c4b22f26SSegher Boessenkool 490c4b22f26SSegher Boessenkool for (i = 0; i <= n; i++) { 4911beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * i, base + 2); 4921beb6a7dSBenjamin Herrenschmidt tmp = readl(base + 4); 49314cf11afSPaul Mackerras irq = (tmp >> 16) & 0xff; 4941beb6a7dSBenjamin Herrenschmidt DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp); 4951beb6a7dSBenjamin Herrenschmidt /* mask it , will be unmasked later */ 4961beb6a7dSBenjamin Herrenschmidt tmp |= 0x1; 4971beb6a7dSBenjamin Herrenschmidt writel(tmp, base + 4); 4981beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].index = i; 4991beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].base = base; 5001beb6a7dSBenjamin Herrenschmidt /* Apple HT PIC has a non-standard way of doing EOIs */ 5011beb6a7dSBenjamin Herrenschmidt if ((vdid & 0xffff) == 0x106b) 5021beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = devbase + 0x60; 5031beb6a7dSBenjamin Herrenschmidt else 5041beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = NULL; 5051beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * i, base + 2); 5061beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].data = readl(base + 4) | 0x80000000; 50714cf11afSPaul Mackerras } 50814cf11afSPaul Mackerras } 50914cf11afSPaul Mackerras 51014cf11afSPaul Mackerras 5111beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 51214cf11afSPaul Mackerras { 51314cf11afSPaul Mackerras unsigned int devfn; 51414cf11afSPaul Mackerras u8 __iomem *cfgspace; 51514cf11afSPaul Mackerras 5161beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n"); 51714cf11afSPaul Mackerras 51814cf11afSPaul Mackerras /* Allocate fixups array */ 519ea96025aSAnton Vorontsov mpic->fixups = kzalloc(128 * sizeof(*mpic->fixups), GFP_KERNEL); 52014cf11afSPaul Mackerras BUG_ON(mpic->fixups == NULL); 52114cf11afSPaul Mackerras 52214cf11afSPaul Mackerras /* Init spinlock */ 523203041adSThomas Gleixner raw_spin_lock_init(&mpic->fixup_lock); 52414cf11afSPaul Mackerras 525c4b22f26SSegher Boessenkool /* Map U3 config space. We assume all IO-APICs are on the primary bus 526c4b22f26SSegher Boessenkool * so we only need to map 64kB. 52714cf11afSPaul Mackerras */ 528c4b22f26SSegher Boessenkool cfgspace = ioremap(0xf2000000, 0x10000); 52914cf11afSPaul Mackerras BUG_ON(cfgspace == NULL); 53014cf11afSPaul Mackerras 5311beb6a7dSBenjamin Herrenschmidt /* Now we scan all slots. We do a very quick scan, we read the header 5321beb6a7dSBenjamin Herrenschmidt * type, vendor ID and device ID only, that's plenty enough 53314cf11afSPaul Mackerras */ 534c4b22f26SSegher Boessenkool for (devfn = 0; devfn < 0x100; devfn++) { 53514cf11afSPaul Mackerras u8 __iomem *devbase = cfgspace + (devfn << 8); 53614cf11afSPaul Mackerras u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); 53714cf11afSPaul Mackerras u32 l = readl(devbase + PCI_VENDOR_ID); 5381beb6a7dSBenjamin Herrenschmidt u16 s; 53914cf11afSPaul Mackerras 54014cf11afSPaul Mackerras DBG("devfn %x, l: %x\n", devfn, l); 54114cf11afSPaul Mackerras 54214cf11afSPaul Mackerras /* If no device, skip */ 54314cf11afSPaul Mackerras if (l == 0xffffffff || l == 0x00000000 || 54414cf11afSPaul Mackerras l == 0x0000ffff || l == 0xffff0000) 54514cf11afSPaul Mackerras goto next; 5461beb6a7dSBenjamin Herrenschmidt /* Check if is supports capability lists */ 5471beb6a7dSBenjamin Herrenschmidt s = readw(devbase + PCI_STATUS); 5481beb6a7dSBenjamin Herrenschmidt if (!(s & PCI_STATUS_CAP_LIST)) 5491beb6a7dSBenjamin Herrenschmidt goto next; 55014cf11afSPaul Mackerras 5511beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pic(mpic, devbase, devfn, l); 552812fd1fdSMichael Ellerman mpic_scan_ht_msi(mpic, devbase, devfn); 55314cf11afSPaul Mackerras 55414cf11afSPaul Mackerras next: 55514cf11afSPaul Mackerras /* next device, if function 0 */ 556c4b22f26SSegher Boessenkool if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0) 55714cf11afSPaul Mackerras devfn += 7; 55814cf11afSPaul Mackerras } 55914cf11afSPaul Mackerras } 56014cf11afSPaul Mackerras 5616cfef5b2SMichael Ellerman #else /* CONFIG_MPIC_U3_HT_IRQS */ 5626e99e458SBenjamin Herrenschmidt 5636e99e458SBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 5646e99e458SBenjamin Herrenschmidt { 5656e99e458SBenjamin Herrenschmidt return 0; 5666e99e458SBenjamin Herrenschmidt } 5676e99e458SBenjamin Herrenschmidt 5686e99e458SBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 5696e99e458SBenjamin Herrenschmidt { 5706e99e458SBenjamin Herrenschmidt } 5716e99e458SBenjamin Herrenschmidt 5726cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 57314cf11afSPaul Mackerras 5743c10c9c4SKumar Gala #ifdef CONFIG_SMP 5752ef613cbSBenjamin Herrenschmidt static int irq_choose_cpu(const struct cpumask *mask) 5763c10c9c4SKumar Gala { 5773c10c9c4SKumar Gala int cpuid; 5783c10c9c4SKumar Gala 57938e1313fSYang Li if (cpumask_equal(mask, cpu_all_mask)) { 5802ef613cbSBenjamin Herrenschmidt static int irq_rover = 0; 581203041adSThomas Gleixner static DEFINE_RAW_SPINLOCK(irq_rover_lock); 5823c10c9c4SKumar Gala unsigned long flags; 5833c10c9c4SKumar Gala 5843c10c9c4SKumar Gala /* Round-robin distribution... */ 5853c10c9c4SKumar Gala do_round_robin: 586203041adSThomas Gleixner raw_spin_lock_irqsave(&irq_rover_lock, flags); 5873c10c9c4SKumar Gala 5882ef613cbSBenjamin Herrenschmidt irq_rover = cpumask_next(irq_rover, cpu_online_mask); 5892ef613cbSBenjamin Herrenschmidt if (irq_rover >= nr_cpu_ids) 5902ef613cbSBenjamin Herrenschmidt irq_rover = cpumask_first(cpu_online_mask); 5912ef613cbSBenjamin Herrenschmidt 5923c10c9c4SKumar Gala cpuid = irq_rover; 5933c10c9c4SKumar Gala 594203041adSThomas Gleixner raw_spin_unlock_irqrestore(&irq_rover_lock, flags); 5953c10c9c4SKumar Gala } else { 59638e1313fSYang Li cpuid = cpumask_first_and(mask, cpu_online_mask); 59738e1313fSYang Li if (cpuid >= nr_cpu_ids) 5983c10c9c4SKumar Gala goto do_round_robin; 5993c10c9c4SKumar Gala } 6003c10c9c4SKumar Gala 6017a0d7940SKumar Gala return get_hard_smp_processor_id(cpuid); 6023c10c9c4SKumar Gala } 6033c10c9c4SKumar Gala #else 6042ef613cbSBenjamin Herrenschmidt static int irq_choose_cpu(const struct cpumask *mask) 6053c10c9c4SKumar Gala { 6063c10c9c4SKumar Gala return hard_smp_processor_id(); 6073c10c9c4SKumar Gala } 6083c10c9c4SKumar Gala #endif 60914cf11afSPaul Mackerras 61014cf11afSPaul Mackerras /* Find an mpic associated with a given linux interrupt */ 611d69a78d7STony Breeds static struct mpic *mpic_find(unsigned int irq) 61214cf11afSPaul Mackerras { 6130ebfff14SBenjamin Herrenschmidt if (irq < NUM_ISA_INTERRUPTS) 61414cf11afSPaul Mackerras return NULL; 6150ebfff14SBenjamin Herrenschmidt 616ec775d0eSThomas Gleixner return irq_get_chip_data(irq); 61714cf11afSPaul Mackerras } 61814cf11afSPaul Mackerras 619d69a78d7STony Breeds /* Determine if the linux irq is an IPI */ 620d69a78d7STony Breeds static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq) 621d69a78d7STony Breeds { 622476eb491SGrant Likely unsigned int src = virq_to_hw(irq); 623d69a78d7STony Breeds 624d69a78d7STony Breeds return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); 625d69a78d7STony Breeds } 626d69a78d7STony Breeds 627d69a78d7STony Breeds 62814cf11afSPaul Mackerras /* Convert a cpu mask from logical to physical cpu numbers. */ 62914cf11afSPaul Mackerras static inline u32 mpic_physmask(u32 cpumask) 63014cf11afSPaul Mackerras { 63114cf11afSPaul Mackerras int i; 63214cf11afSPaul Mackerras u32 mask = 0; 63314cf11afSPaul Mackerras 634ebc04215SMilton Miller for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1) 63514cf11afSPaul Mackerras mask |= (cpumask & 1) << get_hard_smp_processor_id(i); 63614cf11afSPaul Mackerras return mask; 63714cf11afSPaul Mackerras } 63814cf11afSPaul Mackerras 63914cf11afSPaul Mackerras #ifdef CONFIG_SMP 64014cf11afSPaul Mackerras /* Get the mpic structure from the IPI number */ 641835c0553SLennert Buytenhek static inline struct mpic * mpic_from_ipi(struct irq_data *d) 64214cf11afSPaul Mackerras { 643835c0553SLennert Buytenhek return irq_data_get_irq_chip_data(d); 64414cf11afSPaul Mackerras } 64514cf11afSPaul Mackerras #endif 64614cf11afSPaul Mackerras 64714cf11afSPaul Mackerras /* Get the mpic structure from the irq number */ 64814cf11afSPaul Mackerras static inline struct mpic * mpic_from_irq(unsigned int irq) 64914cf11afSPaul Mackerras { 650ec775d0eSThomas Gleixner return irq_get_chip_data(irq); 651835c0553SLennert Buytenhek } 652835c0553SLennert Buytenhek 653835c0553SLennert Buytenhek /* Get the mpic structure from the irq data */ 654835c0553SLennert Buytenhek static inline struct mpic * mpic_from_irq_data(struct irq_data *d) 655835c0553SLennert Buytenhek { 656835c0553SLennert Buytenhek return irq_data_get_irq_chip_data(d); 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 671835c0553SLennert Buytenhek void mpic_unmask_irq(struct irq_data *d) 67214cf11afSPaul Mackerras { 67314cf11afSPaul Mackerras unsigned int loops = 100000; 674835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 675476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 67614cf11afSPaul Mackerras 677835c0553SLennert Buytenhek DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->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--) { 6858bfc5e36SScott Wood printk(KERN_ERR "%s: timeout on hwirq %u\n", 6868bfc5e36SScott Wood __func__, src); 68714cf11afSPaul Mackerras break; 68814cf11afSPaul Mackerras } 6897233593bSZang Roy-r61911 } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK); 6901beb6a7dSBenjamin Herrenschmidt } 6911beb6a7dSBenjamin Herrenschmidt 692835c0553SLennert Buytenhek void mpic_mask_irq(struct irq_data *d) 69314cf11afSPaul Mackerras { 69414cf11afSPaul Mackerras unsigned int loops = 100000; 695835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 696476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 69714cf11afSPaul Mackerras 698835c0553SLennert Buytenhek DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src); 69914cf11afSPaul Mackerras 7007233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 7017233593bSZang Roy-r61911 mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) | 702e5356640SBenjamin Herrenschmidt MPIC_VECPRI_MASK); 70314cf11afSPaul Mackerras 70414cf11afSPaul Mackerras /* make sure mask gets to controller before we return to user */ 70514cf11afSPaul Mackerras do { 70614cf11afSPaul Mackerras if (!loops--) { 7078bfc5e36SScott Wood printk(KERN_ERR "%s: timeout on hwirq %u\n", 7088bfc5e36SScott Wood __func__, src); 70914cf11afSPaul Mackerras break; 71014cf11afSPaul Mackerras } 7117233593bSZang Roy-r61911 } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK)); 71214cf11afSPaul Mackerras } 71314cf11afSPaul Mackerras 714835c0553SLennert Buytenhek void mpic_end_irq(struct irq_data *d) 71514cf11afSPaul Mackerras { 716835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 71714cf11afSPaul Mackerras 7181beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_IRQ 719835c0553SLennert Buytenhek DBG("%s: end_irq: %d\n", mpic->name, d->irq); 7201beb6a7dSBenjamin Herrenschmidt #endif 72114cf11afSPaul Mackerras /* We always EOI on end_irq() even for edge interrupts since that 72214cf11afSPaul Mackerras * should only lower the priority, the MPIC should have properly 72314cf11afSPaul Mackerras * latched another edge interrupt coming in anyway 72414cf11afSPaul Mackerras */ 72514cf11afSPaul Mackerras 72614cf11afSPaul Mackerras mpic_eoi(mpic); 72714cf11afSPaul Mackerras } 72814cf11afSPaul Mackerras 7296cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 730b9e5b4e6SBenjamin Herrenschmidt 731835c0553SLennert Buytenhek static void mpic_unmask_ht_irq(struct irq_data *d) 732b9e5b4e6SBenjamin Herrenschmidt { 733835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 734476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 735b9e5b4e6SBenjamin Herrenschmidt 736835c0553SLennert Buytenhek mpic_unmask_irq(d); 737b9e5b4e6SBenjamin Herrenschmidt 73824a3f2e8SThomas Gleixner if (irqd_is_level_type(d)) 739b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 740b9e5b4e6SBenjamin Herrenschmidt } 741b9e5b4e6SBenjamin Herrenschmidt 742835c0553SLennert Buytenhek static unsigned int mpic_startup_ht_irq(struct irq_data *d) 743b9e5b4e6SBenjamin Herrenschmidt { 744835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 745476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 746b9e5b4e6SBenjamin Herrenschmidt 747835c0553SLennert Buytenhek mpic_unmask_irq(d); 74824a3f2e8SThomas Gleixner mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d)); 749b9e5b4e6SBenjamin Herrenschmidt 750b9e5b4e6SBenjamin Herrenschmidt return 0; 751b9e5b4e6SBenjamin Herrenschmidt } 752b9e5b4e6SBenjamin Herrenschmidt 753835c0553SLennert Buytenhek static void mpic_shutdown_ht_irq(struct irq_data *d) 754b9e5b4e6SBenjamin Herrenschmidt { 755835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 756476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 757b9e5b4e6SBenjamin Herrenschmidt 75824a3f2e8SThomas Gleixner mpic_shutdown_ht_interrupt(mpic, src); 759835c0553SLennert Buytenhek mpic_mask_irq(d); 760b9e5b4e6SBenjamin Herrenschmidt } 761b9e5b4e6SBenjamin Herrenschmidt 762835c0553SLennert Buytenhek static void mpic_end_ht_irq(struct irq_data *d) 763b9e5b4e6SBenjamin Herrenschmidt { 764835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 765476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 766b9e5b4e6SBenjamin Herrenschmidt 767b9e5b4e6SBenjamin Herrenschmidt #ifdef DEBUG_IRQ 768835c0553SLennert Buytenhek DBG("%s: end_irq: %d\n", mpic->name, d->irq); 769b9e5b4e6SBenjamin Herrenschmidt #endif 770b9e5b4e6SBenjamin Herrenschmidt /* We always EOI on end_irq() even for edge interrupts since that 771b9e5b4e6SBenjamin Herrenschmidt * should only lower the priority, the MPIC should have properly 772b9e5b4e6SBenjamin Herrenschmidt * latched another edge interrupt coming in anyway 773b9e5b4e6SBenjamin Herrenschmidt */ 774b9e5b4e6SBenjamin Herrenschmidt 77524a3f2e8SThomas Gleixner if (irqd_is_level_type(d)) 776b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 777b9e5b4e6SBenjamin Herrenschmidt mpic_eoi(mpic); 778b9e5b4e6SBenjamin Herrenschmidt } 7796cfef5b2SMichael Ellerman #endif /* !CONFIG_MPIC_U3_HT_IRQS */ 780b9e5b4e6SBenjamin Herrenschmidt 78114cf11afSPaul Mackerras #ifdef CONFIG_SMP 78214cf11afSPaul Mackerras 783835c0553SLennert Buytenhek static void mpic_unmask_ipi(struct irq_data *d) 78414cf11afSPaul Mackerras { 785835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_ipi(d); 786476eb491SGrant Likely unsigned int src = virq_to_hw(d->irq) - mpic->ipi_vecs[0]; 78714cf11afSPaul Mackerras 788835c0553SLennert Buytenhek DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src); 78914cf11afSPaul Mackerras mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); 79014cf11afSPaul Mackerras } 79114cf11afSPaul Mackerras 792835c0553SLennert Buytenhek static void mpic_mask_ipi(struct irq_data *d) 79314cf11afSPaul Mackerras { 79414cf11afSPaul Mackerras /* NEVER disable an IPI... that's just plain wrong! */ 79514cf11afSPaul Mackerras } 79614cf11afSPaul Mackerras 797835c0553SLennert Buytenhek static void mpic_end_ipi(struct irq_data *d) 79814cf11afSPaul Mackerras { 799835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_ipi(d); 80014cf11afSPaul Mackerras 80114cf11afSPaul Mackerras /* 80214cf11afSPaul Mackerras * IPIs are marked IRQ_PER_CPU. This has the side effect of 80314cf11afSPaul Mackerras * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from 80414cf11afSPaul Mackerras * applying to them. We EOI them late to avoid re-entering. 8056714465eSThomas Gleixner * We mark IPI's with IRQF_DISABLED as they must run with 80614cf11afSPaul Mackerras * irqs disabled. 80714cf11afSPaul Mackerras */ 80814cf11afSPaul Mackerras mpic_eoi(mpic); 80914cf11afSPaul Mackerras } 81014cf11afSPaul Mackerras 81114cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 81214cf11afSPaul Mackerras 813835c0553SLennert Buytenhek int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, 814835c0553SLennert Buytenhek bool force) 81514cf11afSPaul Mackerras { 816835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 817476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 81814cf11afSPaul Mackerras 8193c10c9c4SKumar Gala if (mpic->flags & MPIC_SINGLE_DEST_CPU) { 82038e1313fSYang Li int cpuid = irq_choose_cpu(cpumask); 8213c10c9c4SKumar Gala 8223c10c9c4SKumar Gala mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); 8233c10c9c4SKumar Gala } else { 824*2a116f3dSMilton Miller u32 mask = cpumask_bits(cpumask)[0]; 82514cf11afSPaul Mackerras 826*2a116f3dSMilton Miller mask &= cpumask_bits(cpu_online_mask)[0]; 82714cf11afSPaul Mackerras 8287233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 829*2a116f3dSMilton Miller mpic_physmask(mask)); 83014cf11afSPaul Mackerras } 831d5dedd45SYinghai Lu 832d5dedd45SYinghai Lu return 0; 8333c10c9c4SKumar Gala } 83414cf11afSPaul Mackerras 8357233593bSZang Roy-r61911 static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) 8360ebfff14SBenjamin Herrenschmidt { 8370ebfff14SBenjamin Herrenschmidt /* Now convert sense value */ 8386e99e458SBenjamin Herrenschmidt switch(type & IRQ_TYPE_SENSE_MASK) { 8390ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_RISING: 8407233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 8417233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 8420ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_FALLING: 8436e99e458SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_BOTH: 8447233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 8457233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 8460ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_HIGH: 8477233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 8487233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 8490ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_LOW: 8500ebfff14SBenjamin Herrenschmidt default: 8517233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 8527233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 8530ebfff14SBenjamin Herrenschmidt } 8546e99e458SBenjamin Herrenschmidt } 8556e99e458SBenjamin Herrenschmidt 856835c0553SLennert Buytenhek int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) 8576e99e458SBenjamin Herrenschmidt { 858835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 859476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 8606e99e458SBenjamin Herrenschmidt unsigned int vecpri, vold, vnew; 8616e99e458SBenjamin Herrenschmidt 86206fe98e6SBenjamin Herrenschmidt DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", 863835c0553SLennert Buytenhek mpic, d->irq, src, flow_type); 8646e99e458SBenjamin Herrenschmidt 8656e99e458SBenjamin Herrenschmidt if (src >= mpic->irq_count) 8666e99e458SBenjamin Herrenschmidt return -EINVAL; 8676e99e458SBenjamin Herrenschmidt 8686e99e458SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_NONE) 8696e99e458SBenjamin Herrenschmidt if (mpic->senses && src < mpic->senses_count) 8706e99e458SBenjamin Herrenschmidt flow_type = mpic->senses[src]; 8716e99e458SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_NONE) 8726e99e458SBenjamin Herrenschmidt flow_type = IRQ_TYPE_LEVEL_LOW; 8736e99e458SBenjamin Herrenschmidt 87424a3f2e8SThomas Gleixner irqd_set_trigger_type(d, flow_type); 8756e99e458SBenjamin Herrenschmidt 8766e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, src)) 8776e99e458SBenjamin Herrenschmidt vecpri = MPIC_VECPRI_POLARITY_POSITIVE | 8786e99e458SBenjamin Herrenschmidt MPIC_VECPRI_SENSE_EDGE; 8796e99e458SBenjamin Herrenschmidt else 8807233593bSZang Roy-r61911 vecpri = mpic_type_to_vecpri(mpic, flow_type); 8816e99e458SBenjamin Herrenschmidt 8827233593bSZang Roy-r61911 vold = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 8837233593bSZang Roy-r61911 vnew = vold & ~(MPIC_INFO(VECPRI_POLARITY_MASK) | 8847233593bSZang Roy-r61911 MPIC_INFO(VECPRI_SENSE_MASK)); 8856e99e458SBenjamin Herrenschmidt vnew |= vecpri; 8866e99e458SBenjamin Herrenschmidt if (vold != vnew) 8877233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); 8886e99e458SBenjamin Herrenschmidt 88924a3f2e8SThomas Gleixner return IRQ_SET_MASK_OK_NOCOPY;; 8900ebfff14SBenjamin Herrenschmidt } 8910ebfff14SBenjamin Herrenschmidt 89238958dd9SOlof Johansson void mpic_set_vector(unsigned int virq, unsigned int vector) 89338958dd9SOlof Johansson { 89438958dd9SOlof Johansson struct mpic *mpic = mpic_from_irq(virq); 895476eb491SGrant Likely unsigned int src = virq_to_hw(virq); 89638958dd9SOlof Johansson unsigned int vecpri; 89738958dd9SOlof Johansson 89838958dd9SOlof Johansson DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", 89938958dd9SOlof Johansson mpic, virq, src, vector); 90038958dd9SOlof Johansson 90138958dd9SOlof Johansson if (src >= mpic->irq_count) 90238958dd9SOlof Johansson return; 90338958dd9SOlof Johansson 90438958dd9SOlof Johansson vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 90538958dd9SOlof Johansson vecpri = vecpri & ~MPIC_INFO(VECPRI_VECTOR_MASK); 90638958dd9SOlof Johansson vecpri |= vector; 90738958dd9SOlof Johansson mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); 90838958dd9SOlof Johansson } 90938958dd9SOlof Johansson 910dfec2202SMeador Inge void mpic_set_destination(unsigned int virq, unsigned int cpuid) 911dfec2202SMeador Inge { 912dfec2202SMeador Inge struct mpic *mpic = mpic_from_irq(virq); 913476eb491SGrant Likely unsigned int src = virq_to_hw(virq); 914dfec2202SMeador Inge 915dfec2202SMeador Inge DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", 916dfec2202SMeador Inge mpic, virq, src, cpuid); 917dfec2202SMeador Inge 918dfec2202SMeador Inge if (src >= mpic->irq_count) 919dfec2202SMeador Inge return; 920dfec2202SMeador Inge 921dfec2202SMeador Inge mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); 922dfec2202SMeador Inge } 923dfec2202SMeador Inge 924b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_chip = { 925835c0553SLennert Buytenhek .irq_mask = mpic_mask_irq, 926835c0553SLennert Buytenhek .irq_unmask = mpic_unmask_irq, 927835c0553SLennert Buytenhek .irq_eoi = mpic_end_irq, 928835c0553SLennert Buytenhek .irq_set_type = mpic_set_irq_type, 929b9e5b4e6SBenjamin Herrenschmidt }; 930b9e5b4e6SBenjamin Herrenschmidt 931b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_SMP 932b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_ipi_chip = { 933835c0553SLennert Buytenhek .irq_mask = mpic_mask_ipi, 934835c0553SLennert Buytenhek .irq_unmask = mpic_unmask_ipi, 935835c0553SLennert Buytenhek .irq_eoi = mpic_end_ipi, 936b9e5b4e6SBenjamin Herrenschmidt }; 937b9e5b4e6SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 938b9e5b4e6SBenjamin Herrenschmidt 9396cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 940b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_ht_chip = { 941835c0553SLennert Buytenhek .irq_startup = mpic_startup_ht_irq, 942835c0553SLennert Buytenhek .irq_shutdown = mpic_shutdown_ht_irq, 943835c0553SLennert Buytenhek .irq_mask = mpic_mask_irq, 944835c0553SLennert Buytenhek .irq_unmask = mpic_unmask_ht_irq, 945835c0553SLennert Buytenhek .irq_eoi = mpic_end_ht_irq, 946835c0553SLennert Buytenhek .irq_set_type = mpic_set_irq_type, 947b9e5b4e6SBenjamin Herrenschmidt }; 9486cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 949b9e5b4e6SBenjamin Herrenschmidt 95014cf11afSPaul Mackerras 9510ebfff14SBenjamin Herrenschmidt static int mpic_host_match(struct irq_host *h, struct device_node *node) 9520ebfff14SBenjamin Herrenschmidt { 9530ebfff14SBenjamin Herrenschmidt /* Exact match, unless mpic node is NULL */ 95452964f87SMichael Ellerman return h->of_node == NULL || h->of_node == node; 9550ebfff14SBenjamin Herrenschmidt } 9560ebfff14SBenjamin Herrenschmidt 9570ebfff14SBenjamin Herrenschmidt static int mpic_host_map(struct irq_host *h, unsigned int virq, 9586e99e458SBenjamin Herrenschmidt irq_hw_number_t hw) 9590ebfff14SBenjamin Herrenschmidt { 9600ebfff14SBenjamin Herrenschmidt struct mpic *mpic = h->host_data; 9616e99e458SBenjamin Herrenschmidt struct irq_chip *chip; 9620ebfff14SBenjamin Herrenschmidt 96306fe98e6SBenjamin Herrenschmidt DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw); 9640ebfff14SBenjamin Herrenschmidt 9657df2457dSOlof Johansson if (hw == mpic->spurious_vec) 9660ebfff14SBenjamin Herrenschmidt return -EINVAL; 9677fd72186SBenjamin Herrenschmidt if (mpic->protected && test_bit(hw, mpic->protected)) 9687fd72186SBenjamin Herrenschmidt return -EINVAL; 96906fe98e6SBenjamin Herrenschmidt 9700ebfff14SBenjamin Herrenschmidt #ifdef CONFIG_SMP 9717df2457dSOlof Johansson else if (hw >= mpic->ipi_vecs[0]) { 9720ebfff14SBenjamin Herrenschmidt WARN_ON(!(mpic->flags & MPIC_PRIMARY)); 9730ebfff14SBenjamin Herrenschmidt 97406fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping as IPI\n"); 975ec775d0eSThomas Gleixner irq_set_chip_data(virq, mpic); 976ec775d0eSThomas Gleixner irq_set_chip_and_handler(virq, &mpic->hc_ipi, 9770ebfff14SBenjamin Herrenschmidt handle_percpu_irq); 9780ebfff14SBenjamin Herrenschmidt return 0; 9790ebfff14SBenjamin Herrenschmidt } 9800ebfff14SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 9810ebfff14SBenjamin Herrenschmidt 9820ebfff14SBenjamin Herrenschmidt if (hw >= mpic->irq_count) 9830ebfff14SBenjamin Herrenschmidt return -EINVAL; 9840ebfff14SBenjamin Herrenschmidt 985a7de7c74SMichael Ellerman mpic_msi_reserve_hwirq(mpic, hw); 986a7de7c74SMichael Ellerman 9876e99e458SBenjamin Herrenschmidt /* Default chip */ 9880ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_irq; 9890ebfff14SBenjamin Herrenschmidt 9906cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 9910ebfff14SBenjamin Herrenschmidt /* Check for HT interrupts, override vecpri */ 9926e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, hw)) 9930ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_ht_irq; 9946cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 9950ebfff14SBenjamin Herrenschmidt 99606fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping to irq chip @%p\n", chip); 9970ebfff14SBenjamin Herrenschmidt 998ec775d0eSThomas Gleixner irq_set_chip_data(virq, mpic); 999ec775d0eSThomas Gleixner irq_set_chip_and_handler(virq, chip, handle_fasteoi_irq); 10006e99e458SBenjamin Herrenschmidt 10016e99e458SBenjamin Herrenschmidt /* Set default irq type */ 1002ec775d0eSThomas Gleixner irq_set_irq_type(virq, IRQ_TYPE_NONE); 10036e99e458SBenjamin Herrenschmidt 1004dfec2202SMeador Inge /* If the MPIC was reset, then all vectors have already been 1005dfec2202SMeador Inge * initialized. Otherwise, a per source lazy initialization 1006dfec2202SMeador Inge * is done here. 1007dfec2202SMeador Inge */ 1008dfec2202SMeador Inge if (!mpic_is_ipi(mpic, hw) && (mpic->flags & MPIC_NO_RESET)) { 1009dfec2202SMeador Inge mpic_set_vector(virq, hw); 1010d6a2639bSMeador Inge mpic_set_destination(virq, mpic_processor_id(mpic)); 1011dfec2202SMeador Inge mpic_irq_set_priority(virq, 8); 1012dfec2202SMeador Inge } 1013dfec2202SMeador Inge 10140ebfff14SBenjamin Herrenschmidt return 0; 10150ebfff14SBenjamin Herrenschmidt } 10160ebfff14SBenjamin Herrenschmidt 10170ebfff14SBenjamin Herrenschmidt static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, 101840d50cf7SRoman Fietze const u32 *intspec, unsigned int intsize, 10190ebfff14SBenjamin Herrenschmidt irq_hw_number_t *out_hwirq, unsigned int *out_flags) 10200ebfff14SBenjamin Herrenschmidt 10210ebfff14SBenjamin Herrenschmidt { 10220ebfff14SBenjamin Herrenschmidt static unsigned char map_mpic_senses[4] = { 10230ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_RISING, 10240ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_LOW, 10250ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_HIGH, 10260ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_FALLING, 10270ebfff14SBenjamin Herrenschmidt }; 10280ebfff14SBenjamin Herrenschmidt 10290ebfff14SBenjamin Herrenschmidt *out_hwirq = intspec[0]; 103006fe98e6SBenjamin Herrenschmidt if (intsize > 1) { 103106fe98e6SBenjamin Herrenschmidt u32 mask = 0x3; 103206fe98e6SBenjamin Herrenschmidt 103306fe98e6SBenjamin Herrenschmidt /* Apple invented a new race of encoding on machines with 103406fe98e6SBenjamin Herrenschmidt * an HT APIC. They encode, among others, the index within 103506fe98e6SBenjamin Herrenschmidt * the HT APIC. We don't care about it here since thankfully, 103606fe98e6SBenjamin Herrenschmidt * it appears that they have the APIC already properly 103706fe98e6SBenjamin Herrenschmidt * configured, and thus our current fixup code that reads the 103806fe98e6SBenjamin Herrenschmidt * APIC config works fine. However, we still need to mask out 103906fe98e6SBenjamin Herrenschmidt * bits in the specifier to make sure we only get bit 0 which 104006fe98e6SBenjamin Herrenschmidt * is the level/edge bit (the only sense bit exposed by Apple), 104106fe98e6SBenjamin Herrenschmidt * as their bit 1 means something else. 104206fe98e6SBenjamin Herrenschmidt */ 104306fe98e6SBenjamin Herrenschmidt if (machine_is(powermac)) 104406fe98e6SBenjamin Herrenschmidt mask = 0x1; 104506fe98e6SBenjamin Herrenschmidt *out_flags = map_mpic_senses[intspec[1] & mask]; 104606fe98e6SBenjamin Herrenschmidt } else 10470ebfff14SBenjamin Herrenschmidt *out_flags = IRQ_TYPE_NONE; 10480ebfff14SBenjamin Herrenschmidt 104906fe98e6SBenjamin Herrenschmidt DBG("mpic: xlate (%d cells: 0x%08x 0x%08x) to line 0x%lx sense 0x%x\n", 105006fe98e6SBenjamin Herrenschmidt intsize, intspec[0], intspec[1], *out_hwirq, *out_flags); 105106fe98e6SBenjamin Herrenschmidt 10520ebfff14SBenjamin Herrenschmidt return 0; 10530ebfff14SBenjamin Herrenschmidt } 10540ebfff14SBenjamin Herrenschmidt 10550ebfff14SBenjamin Herrenschmidt static struct irq_host_ops mpic_host_ops = { 10560ebfff14SBenjamin Herrenschmidt .match = mpic_host_match, 10570ebfff14SBenjamin Herrenschmidt .map = mpic_host_map, 10580ebfff14SBenjamin Herrenschmidt .xlate = mpic_host_xlate, 10590ebfff14SBenjamin Herrenschmidt }; 10600ebfff14SBenjamin Herrenschmidt 1061dfec2202SMeador Inge static int mpic_reset_prohibited(struct device_node *node) 1062dfec2202SMeador Inge { 1063dfec2202SMeador Inge return node && of_get_property(node, "pic-no-reset", NULL); 1064dfec2202SMeador Inge } 1065dfec2202SMeador Inge 106614cf11afSPaul Mackerras /* 106714cf11afSPaul Mackerras * Exported functions 106814cf11afSPaul Mackerras */ 106914cf11afSPaul Mackerras 10700ebfff14SBenjamin Herrenschmidt struct mpic * __init mpic_alloc(struct device_node *node, 1071a959ff56SBenjamin Herrenschmidt phys_addr_t phys_addr, 107214cf11afSPaul Mackerras unsigned int flags, 107314cf11afSPaul Mackerras unsigned int isu_size, 107414cf11afSPaul Mackerras unsigned int irq_count, 107514cf11afSPaul Mackerras const char *name) 107614cf11afSPaul Mackerras { 107714cf11afSPaul Mackerras struct mpic *mpic; 1078d9d1063dSJohannes Berg u32 greg_feature; 107914cf11afSPaul Mackerras const char *vers; 108014cf11afSPaul Mackerras int i; 10817df2457dSOlof Johansson int intvec_top; 1082a959ff56SBenjamin Herrenschmidt u64 paddr = phys_addr; 108314cf11afSPaul Mackerras 108485355bb2SKumar Gala mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); 108514cf11afSPaul Mackerras if (mpic == NULL) 108614cf11afSPaul Mackerras return NULL; 108714cf11afSPaul Mackerras 108814cf11afSPaul Mackerras mpic->name = name; 108914cf11afSPaul Mackerras 1090b9e5b4e6SBenjamin Herrenschmidt mpic->hc_irq = mpic_irq_chip; 1091b27df672SThomas Gleixner mpic->hc_irq.name = name; 109214cf11afSPaul Mackerras if (flags & MPIC_PRIMARY) 1093835c0553SLennert Buytenhek mpic->hc_irq.irq_set_affinity = mpic_set_affinity; 10946cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 1095b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq = mpic_irq_ht_chip; 1096b27df672SThomas Gleixner mpic->hc_ht_irq.name = name; 1097b9e5b4e6SBenjamin Herrenschmidt if (flags & MPIC_PRIMARY) 1098835c0553SLennert Buytenhek mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; 10996cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 1100fbf0274eSBenjamin Herrenschmidt 110114cf11afSPaul Mackerras #ifdef CONFIG_SMP 1102b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ipi = mpic_ipi_chip; 1103b27df672SThomas Gleixner mpic->hc_ipi.name = name; 110414cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 110514cf11afSPaul Mackerras 110614cf11afSPaul Mackerras mpic->flags = flags; 110714cf11afSPaul Mackerras mpic->isu_size = isu_size; 110814cf11afSPaul Mackerras mpic->irq_count = irq_count; 110914cf11afSPaul Mackerras mpic->num_sources = 0; /* so far */ 111014cf11afSPaul Mackerras 11117df2457dSOlof Johansson if (flags & MPIC_LARGE_VECTORS) 11127df2457dSOlof Johansson intvec_top = 2047; 11137df2457dSOlof Johansson else 11147df2457dSOlof Johansson intvec_top = 255; 11157df2457dSOlof Johansson 11167df2457dSOlof Johansson mpic->timer_vecs[0] = intvec_top - 8; 11177df2457dSOlof Johansson mpic->timer_vecs[1] = intvec_top - 7; 11187df2457dSOlof Johansson mpic->timer_vecs[2] = intvec_top - 6; 11197df2457dSOlof Johansson mpic->timer_vecs[3] = intvec_top - 5; 11207df2457dSOlof Johansson mpic->ipi_vecs[0] = intvec_top - 4; 11217df2457dSOlof Johansson mpic->ipi_vecs[1] = intvec_top - 3; 11227df2457dSOlof Johansson mpic->ipi_vecs[2] = intvec_top - 2; 11237df2457dSOlof Johansson mpic->ipi_vecs[3] = intvec_top - 1; 11247df2457dSOlof Johansson mpic->spurious_vec = intvec_top; 11257df2457dSOlof Johansson 1126a959ff56SBenjamin Herrenschmidt /* Check for "big-endian" in device-tree */ 1127e2eb6392SStephen Rothwell if (node && of_get_property(node, "big-endian", NULL) != NULL) 1128a959ff56SBenjamin Herrenschmidt mpic->flags |= MPIC_BIG_ENDIAN; 1129a959ff56SBenjamin Herrenschmidt 11307fd72186SBenjamin Herrenschmidt /* Look for protected sources */ 11317fd72186SBenjamin Herrenschmidt if (node) { 1132d9d1063dSJohannes Berg int psize; 1133d9d1063dSJohannes Berg unsigned int bits, mapsize; 11347fd72186SBenjamin Herrenschmidt const u32 *psrc = 11357fd72186SBenjamin Herrenschmidt of_get_property(node, "protected-sources", &psize); 11367fd72186SBenjamin Herrenschmidt if (psrc) { 11377fd72186SBenjamin Herrenschmidt psize /= 4; 11387fd72186SBenjamin Herrenschmidt bits = intvec_top + 1; 11397fd72186SBenjamin Herrenschmidt mapsize = BITS_TO_LONGS(bits) * sizeof(unsigned long); 1140ea96025aSAnton Vorontsov mpic->protected = kzalloc(mapsize, GFP_KERNEL); 11417fd72186SBenjamin Herrenschmidt BUG_ON(mpic->protected == NULL); 11427fd72186SBenjamin Herrenschmidt for (i = 0; i < psize; i++) { 11437fd72186SBenjamin Herrenschmidt if (psrc[i] > intvec_top) 11447fd72186SBenjamin Herrenschmidt continue; 11457fd72186SBenjamin Herrenschmidt __set_bit(psrc[i], mpic->protected); 11467fd72186SBenjamin Herrenschmidt } 11477fd72186SBenjamin Herrenschmidt } 11487fd72186SBenjamin Herrenschmidt } 1149a959ff56SBenjamin Herrenschmidt 11507233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 11517233593bSZang Roy-r61911 mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; 11527233593bSZang Roy-r61911 #endif 11537233593bSZang Roy-r61911 1154fbf0274eSBenjamin Herrenschmidt /* default register type */ 1155fbf0274eSBenjamin Herrenschmidt mpic->reg_type = (flags & MPIC_BIG_ENDIAN) ? 1156fbf0274eSBenjamin Herrenschmidt mpic_access_mmio_be : mpic_access_mmio_le; 1157fbf0274eSBenjamin Herrenschmidt 1158a959ff56SBenjamin Herrenschmidt /* If no physical address is passed in, a device-node is mandatory */ 1159a959ff56SBenjamin Herrenschmidt BUG_ON(paddr == 0 && node == NULL); 1160a959ff56SBenjamin Herrenschmidt 1161a959ff56SBenjamin Herrenschmidt /* If no physical address passed in, check if it's dcr based */ 11620411a5e2SMichael Ellerman if (paddr == 0 && of_get_property(node, "dcr-reg", NULL) != NULL) { 1163fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 11640411a5e2SMichael Ellerman mpic->flags |= MPIC_USES_DCR; 1165fbf0274eSBenjamin Herrenschmidt mpic->reg_type = mpic_access_dcr; 1166fbf0274eSBenjamin Herrenschmidt #else 11670411a5e2SMichael Ellerman BUG(); 1168fbf0274eSBenjamin Herrenschmidt #endif /* CONFIG_PPC_DCR */ 11690411a5e2SMichael Ellerman } 1170fbf0274eSBenjamin Herrenschmidt 1171a959ff56SBenjamin Herrenschmidt /* If the MPIC is not DCR based, and no physical address was passed 1172a959ff56SBenjamin Herrenschmidt * in, try to obtain one 1173a959ff56SBenjamin Herrenschmidt */ 1174a959ff56SBenjamin Herrenschmidt if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) { 1175d9d1063dSJohannes Berg const u32 *reg = of_get_property(node, "reg", NULL); 1176a959ff56SBenjamin Herrenschmidt BUG_ON(reg == NULL); 1177a959ff56SBenjamin Herrenschmidt paddr = of_translate_address(node, reg); 1178a959ff56SBenjamin Herrenschmidt BUG_ON(paddr == OF_BAD_ADDR); 1179a959ff56SBenjamin Herrenschmidt } 1180a959ff56SBenjamin Herrenschmidt 118114cf11afSPaul Mackerras /* Map the global registers */ 11825a2642f6SBenjamin Herrenschmidt mpic_map(mpic, node, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); 11835a2642f6SBenjamin Herrenschmidt mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); 118414cf11afSPaul Mackerras 118514cf11afSPaul Mackerras /* Reset */ 1186dfec2202SMeador Inge 1187dfec2202SMeador Inge /* When using a device-node, reset requests are only honored if the MPIC 1188dfec2202SMeador Inge * is allowed to reset. 1189dfec2202SMeador Inge */ 1190dfec2202SMeador Inge if (mpic_reset_prohibited(node)) 1191dfec2202SMeador Inge mpic->flags |= MPIC_NO_RESET; 1192dfec2202SMeador Inge 1193dfec2202SMeador Inge if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { 1194dfec2202SMeador Inge printk(KERN_DEBUG "mpic: Resetting\n"); 11957233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 11967233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 119714cf11afSPaul Mackerras | MPIC_GREG_GCONF_RESET); 11987233593bSZang Roy-r61911 while( mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 119914cf11afSPaul Mackerras & MPIC_GREG_GCONF_RESET) 120014cf11afSPaul Mackerras mb(); 120114cf11afSPaul Mackerras } 120214cf11afSPaul Mackerras 1203d91e4ea7SKumar Gala /* CoreInt */ 1204d91e4ea7SKumar Gala if (flags & MPIC_ENABLE_COREINT) 1205d91e4ea7SKumar Gala mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1206d91e4ea7SKumar Gala mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1207d91e4ea7SKumar Gala | MPIC_GREG_GCONF_COREINT); 1208d91e4ea7SKumar Gala 1209f365355eSOlof Johansson if (flags & MPIC_ENABLE_MCK) 1210f365355eSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1211f365355eSOlof Johansson mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1212f365355eSOlof Johansson | MPIC_GREG_GCONF_MCK); 1213f365355eSOlof Johansson 121414cf11afSPaul Mackerras /* Read feature register, calculate num CPUs and, for non-ISU 121514cf11afSPaul Mackerras * MPICs, num sources as well. On ISU MPICs, sources are counted 121614cf11afSPaul Mackerras * as ISUs are added 121714cf11afSPaul Mackerras */ 1218d9d1063dSJohannes Berg greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); 1219d9d1063dSJohannes Berg mpic->num_cpus = ((greg_feature & MPIC_GREG_FEATURE_LAST_CPU_MASK) 122014cf11afSPaul Mackerras >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1; 12215073e7eeSAnton Vorontsov if (isu_size == 0) { 1222475ca391SKumar Gala if (flags & MPIC_BROKEN_FRR_NIRQS) 1223475ca391SKumar Gala mpic->num_sources = mpic->irq_count; 1224475ca391SKumar Gala else 1225d9d1063dSJohannes Berg mpic->num_sources = 1226d9d1063dSJohannes Berg ((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) 122714cf11afSPaul Mackerras >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; 12285073e7eeSAnton Vorontsov } 122914cf11afSPaul Mackerras 123014cf11afSPaul Mackerras /* Map the per-CPU registers */ 123114cf11afSPaul Mackerras for (i = 0; i < mpic->num_cpus; i++) { 12325a2642f6SBenjamin Herrenschmidt mpic_map(mpic, node, paddr, &mpic->cpuregs[i], 1233fbf0274eSBenjamin Herrenschmidt MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE), 1234fbf0274eSBenjamin Herrenschmidt 0x1000); 123514cf11afSPaul Mackerras } 123614cf11afSPaul Mackerras 123714cf11afSPaul Mackerras /* Initialize main ISU if none provided */ 123814cf11afSPaul Mackerras if (mpic->isu_size == 0) { 123914cf11afSPaul Mackerras mpic->isu_size = mpic->num_sources; 12405a2642f6SBenjamin Herrenschmidt mpic_map(mpic, node, paddr, &mpic->isus[0], 1241fbf0274eSBenjamin Herrenschmidt MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); 124214cf11afSPaul Mackerras } 124314cf11afSPaul Mackerras mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); 124414cf11afSPaul Mackerras mpic->isu_mask = (1 << mpic->isu_shift) - 1; 124514cf11afSPaul Mackerras 124631207dabSKumar Gala mpic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 124731207dabSKumar Gala isu_size ? isu_size : mpic->num_sources, 124831207dabSKumar Gala &mpic_host_ops, 124931207dabSKumar Gala flags & MPIC_LARGE_VECTORS ? 2048 : 256); 125031207dabSKumar Gala if (mpic->irqhost == NULL) 125131207dabSKumar Gala return NULL; 125231207dabSKumar Gala 125331207dabSKumar Gala mpic->irqhost->host_data = mpic; 125431207dabSKumar Gala 125514cf11afSPaul Mackerras /* Display version */ 1256d9d1063dSJohannes Berg switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) { 125714cf11afSPaul Mackerras case 1: 125814cf11afSPaul Mackerras vers = "1.0"; 125914cf11afSPaul Mackerras break; 126014cf11afSPaul Mackerras case 2: 126114cf11afSPaul Mackerras vers = "1.2"; 126214cf11afSPaul Mackerras break; 126314cf11afSPaul Mackerras case 3: 126414cf11afSPaul Mackerras vers = "1.3"; 126514cf11afSPaul Mackerras break; 126614cf11afSPaul Mackerras default: 126714cf11afSPaul Mackerras vers = "<unknown>"; 126814cf11afSPaul Mackerras break; 126914cf11afSPaul Mackerras } 1270a959ff56SBenjamin Herrenschmidt printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," 1271a959ff56SBenjamin Herrenschmidt " max %d CPUs\n", 1272a959ff56SBenjamin Herrenschmidt name, vers, (unsigned long long)paddr, mpic->num_cpus); 1273a959ff56SBenjamin Herrenschmidt printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", 1274a959ff56SBenjamin Herrenschmidt mpic->isu_size, mpic->isu_shift, mpic->isu_mask); 127514cf11afSPaul Mackerras 127614cf11afSPaul Mackerras mpic->next = mpics; 127714cf11afSPaul Mackerras mpics = mpic; 127814cf11afSPaul Mackerras 12790ebfff14SBenjamin Herrenschmidt if (flags & MPIC_PRIMARY) { 128014cf11afSPaul Mackerras mpic_primary = mpic; 12810ebfff14SBenjamin Herrenschmidt irq_set_default_host(mpic->irqhost); 12820ebfff14SBenjamin Herrenschmidt } 128314cf11afSPaul Mackerras 128414cf11afSPaul Mackerras return mpic; 128514cf11afSPaul Mackerras } 128614cf11afSPaul Mackerras 128714cf11afSPaul Mackerras void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, 1288a959ff56SBenjamin Herrenschmidt phys_addr_t paddr) 128914cf11afSPaul Mackerras { 129014cf11afSPaul Mackerras unsigned int isu_first = isu_num * mpic->isu_size; 129114cf11afSPaul Mackerras 129214cf11afSPaul Mackerras BUG_ON(isu_num >= MPIC_MAX_ISU); 129314cf11afSPaul Mackerras 12945a2642f6SBenjamin Herrenschmidt mpic_map(mpic, mpic->irqhost->of_node, 12955a2642f6SBenjamin Herrenschmidt paddr, &mpic->isus[isu_num], 0, 12967233593bSZang Roy-r61911 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); 12975a2642f6SBenjamin Herrenschmidt 129814cf11afSPaul Mackerras if ((isu_first + mpic->isu_size) > mpic->num_sources) 129914cf11afSPaul Mackerras mpic->num_sources = isu_first + mpic->isu_size; 130014cf11afSPaul Mackerras } 130114cf11afSPaul Mackerras 13020ebfff14SBenjamin Herrenschmidt void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count) 13030ebfff14SBenjamin Herrenschmidt { 13040ebfff14SBenjamin Herrenschmidt mpic->senses = senses; 13050ebfff14SBenjamin Herrenschmidt mpic->senses_count = count; 13060ebfff14SBenjamin Herrenschmidt } 13070ebfff14SBenjamin Herrenschmidt 130814cf11afSPaul Mackerras void __init mpic_init(struct mpic *mpic) 130914cf11afSPaul Mackerras { 131014cf11afSPaul Mackerras int i; 1311cc353c30SArnd Bergmann int cpu; 131214cf11afSPaul Mackerras 131314cf11afSPaul Mackerras BUG_ON(mpic->num_sources == 0); 131414cf11afSPaul Mackerras 131514cf11afSPaul Mackerras printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); 131614cf11afSPaul Mackerras 131714cf11afSPaul Mackerras /* Set current processor priority to max */ 13187233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 131914cf11afSPaul Mackerras 132014cf11afSPaul Mackerras /* Initialize timers: just disable them all */ 132114cf11afSPaul Mackerras for (i = 0; i < 4; i++) { 132214cf11afSPaul Mackerras mpic_write(mpic->tmregs, 13237233593bSZang Roy-r61911 i * MPIC_INFO(TIMER_STRIDE) + 13247233593bSZang Roy-r61911 MPIC_INFO(TIMER_DESTINATION), 0); 132514cf11afSPaul Mackerras mpic_write(mpic->tmregs, 13267233593bSZang Roy-r61911 i * MPIC_INFO(TIMER_STRIDE) + 13277233593bSZang Roy-r61911 MPIC_INFO(TIMER_VECTOR_PRI), 132814cf11afSPaul Mackerras MPIC_VECPRI_MASK | 13297df2457dSOlof Johansson (mpic->timer_vecs[0] + i)); 133014cf11afSPaul Mackerras } 133114cf11afSPaul Mackerras 133214cf11afSPaul Mackerras /* Initialize IPIs to our reserved vectors and mark them disabled for now */ 133314cf11afSPaul Mackerras mpic_test_broken_ipi(mpic); 133414cf11afSPaul Mackerras for (i = 0; i < 4; i++) { 133514cf11afSPaul Mackerras mpic_ipi_write(i, 133614cf11afSPaul Mackerras MPIC_VECPRI_MASK | 133714cf11afSPaul Mackerras (10 << MPIC_VECPRI_PRIORITY_SHIFT) | 13387df2457dSOlof Johansson (mpic->ipi_vecs[0] + i)); 133914cf11afSPaul Mackerras } 134014cf11afSPaul Mackerras 134114cf11afSPaul Mackerras /* Initialize interrupt sources */ 134214cf11afSPaul Mackerras if (mpic->irq_count == 0) 134314cf11afSPaul Mackerras mpic->irq_count = mpic->num_sources; 134414cf11afSPaul Mackerras 13451beb6a7dSBenjamin Herrenschmidt /* Do the HT PIC fixups on U3 broken mpic */ 134614cf11afSPaul Mackerras DBG("MPIC flags: %x\n", mpic->flags); 134705af7bd2SMichael Ellerman if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) { 13481beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pics(mpic); 134905af7bd2SMichael Ellerman mpic_u3msi_init(mpic); 135005af7bd2SMichael Ellerman } 135114cf11afSPaul Mackerras 135238958dd9SOlof Johansson mpic_pasemi_msi_init(mpic); 135338958dd9SOlof Johansson 1354d6a2639bSMeador Inge cpu = mpic_processor_id(mpic); 1355cc353c30SArnd Bergmann 1356dfec2202SMeador Inge if (!(mpic->flags & MPIC_NO_RESET)) { 135714cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources; i++) { 135814cf11afSPaul Mackerras /* start with vector = source number, and masked */ 13596e99e458SBenjamin Herrenschmidt u32 vecpri = MPIC_VECPRI_MASK | i | 13606e99e458SBenjamin Herrenschmidt (8 << MPIC_VECPRI_PRIORITY_SHIFT); 136114cf11afSPaul Mackerras 13627fd72186SBenjamin Herrenschmidt /* check if protected */ 13637fd72186SBenjamin Herrenschmidt if (mpic->protected && test_bit(i, mpic->protected)) 13647fd72186SBenjamin Herrenschmidt continue; 136514cf11afSPaul Mackerras /* init hw */ 13667233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); 1367cc353c30SArnd Bergmann mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); 136814cf11afSPaul Mackerras } 1369dfec2202SMeador Inge } 137014cf11afSPaul Mackerras 13717df2457dSOlof Johansson /* Init spurious vector */ 13727df2457dSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), mpic->spurious_vec); 137314cf11afSPaul Mackerras 13747233593bSZang Roy-r61911 /* Disable 8259 passthrough, if supported */ 13757233593bSZang Roy-r61911 if (!(mpic->flags & MPIC_NO_PTHROU_DIS)) 13767233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 13777233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 137814cf11afSPaul Mackerras | MPIC_GREG_GCONF_8259_PTHROU_DIS); 137914cf11afSPaul Mackerras 1380d87bf3beSOlof Johansson if (mpic->flags & MPIC_NO_BIAS) 1381d87bf3beSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1382d87bf3beSOlof Johansson mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1383d87bf3beSOlof Johansson | MPIC_GREG_GCONF_NO_BIAS); 1384d87bf3beSOlof Johansson 138514cf11afSPaul Mackerras /* Set current processor priority to 0 */ 13867233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 13873669e930SJohannes Berg 13883669e930SJohannes Berg #ifdef CONFIG_PM 13893669e930SJohannes Berg /* allocate memory to save mpic state */ 1390ea96025aSAnton Vorontsov mpic->save_data = kmalloc(mpic->num_sources * sizeof(*mpic->save_data), 1391ea96025aSAnton Vorontsov GFP_KERNEL); 13923669e930SJohannes Berg BUG_ON(mpic->save_data == NULL); 13933669e930SJohannes Berg #endif 139414cf11afSPaul Mackerras } 139514cf11afSPaul Mackerras 1396868ea0c9SMark A. Greer void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) 1397868ea0c9SMark A. Greer { 1398868ea0c9SMark A. Greer u32 v; 139914cf11afSPaul Mackerras 1400868ea0c9SMark A. Greer v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 1401868ea0c9SMark A. Greer v &= ~MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK; 1402868ea0c9SMark A. Greer v |= MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(clock_ratio); 1403868ea0c9SMark A. Greer mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 1404868ea0c9SMark A. Greer } 1405868ea0c9SMark A. Greer 1406868ea0c9SMark A. Greer void __init mpic_set_serial_int(struct mpic *mpic, int enable) 1407868ea0c9SMark A. Greer { 1408ba1826e5SBenjamin Herrenschmidt unsigned long flags; 1409868ea0c9SMark A. Greer u32 v; 1410868ea0c9SMark A. Greer 1411203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic_lock, flags); 1412868ea0c9SMark A. Greer v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 1413868ea0c9SMark A. Greer if (enable) 1414868ea0c9SMark A. Greer v |= MPIC_GREG_GLOBAL_CONF_1_SIE; 1415868ea0c9SMark A. Greer else 1416868ea0c9SMark A. Greer v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE; 1417868ea0c9SMark A. Greer mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 1418203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic_lock, flags); 1419868ea0c9SMark A. Greer } 142014cf11afSPaul Mackerras 142114cf11afSPaul Mackerras void mpic_irq_set_priority(unsigned int irq, unsigned int pri) 142214cf11afSPaul Mackerras { 1423d69a78d7STony Breeds struct mpic *mpic = mpic_find(irq); 1424476eb491SGrant Likely unsigned int src = virq_to_hw(irq); 142514cf11afSPaul Mackerras unsigned long flags; 142614cf11afSPaul Mackerras u32 reg; 142714cf11afSPaul Mackerras 142806a901c5SStephen Rothwell if (!mpic) 142906a901c5SStephen Rothwell return; 143006a901c5SStephen Rothwell 1431203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic_lock, flags); 1432d69a78d7STony Breeds if (mpic_is_ipi(mpic, irq)) { 14337df2457dSOlof Johansson reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) & 1434e5356640SBenjamin Herrenschmidt ~MPIC_VECPRI_PRIORITY_MASK; 14357df2457dSOlof Johansson mpic_ipi_write(src - mpic->ipi_vecs[0], 143614cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 143714cf11afSPaul Mackerras } else { 14387233593bSZang Roy-r61911 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) 1439e5356640SBenjamin Herrenschmidt & ~MPIC_VECPRI_PRIORITY_MASK; 14407233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 144114cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 144214cf11afSPaul Mackerras } 1443203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic_lock, flags); 144414cf11afSPaul Mackerras } 144514cf11afSPaul Mackerras 144614cf11afSPaul Mackerras void mpic_setup_this_cpu(void) 144714cf11afSPaul Mackerras { 144814cf11afSPaul Mackerras #ifdef CONFIG_SMP 144914cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 145014cf11afSPaul Mackerras unsigned long flags; 145114cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 145214cf11afSPaul Mackerras unsigned int i; 145314cf11afSPaul Mackerras 145414cf11afSPaul Mackerras BUG_ON(mpic == NULL); 145514cf11afSPaul Mackerras 145614cf11afSPaul Mackerras DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 145714cf11afSPaul Mackerras 1458203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic_lock, flags); 145914cf11afSPaul Mackerras 146014cf11afSPaul Mackerras /* let the mpic know we want intrs. default affinity is 0xffffffff 146114cf11afSPaul Mackerras * until changed via /proc. That's how it's done on x86. If we want 146214cf11afSPaul Mackerras * it differently, then we should make sure we also change the default 1463a53da52fSIngo Molnar * values of irq_desc[].affinity in irq.c. 146414cf11afSPaul Mackerras */ 146514cf11afSPaul Mackerras if (distribute_irqs) { 146614cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources ; i++) 14677233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 14687233593bSZang Roy-r61911 mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) | msk); 146914cf11afSPaul Mackerras } 147014cf11afSPaul Mackerras 147114cf11afSPaul Mackerras /* Set current processor priority to 0 */ 14727233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 147314cf11afSPaul Mackerras 1474203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic_lock, flags); 147514cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 147614cf11afSPaul Mackerras } 147714cf11afSPaul Mackerras 147814cf11afSPaul Mackerras int mpic_cpu_get_priority(void) 147914cf11afSPaul Mackerras { 148014cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 148114cf11afSPaul Mackerras 14827233593bSZang Roy-r61911 return mpic_cpu_read(MPIC_INFO(CPU_CURRENT_TASK_PRI)); 148314cf11afSPaul Mackerras } 148414cf11afSPaul Mackerras 148514cf11afSPaul Mackerras void mpic_cpu_set_priority(int prio) 148614cf11afSPaul Mackerras { 148714cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 148814cf11afSPaul Mackerras 148914cf11afSPaul Mackerras prio &= MPIC_CPU_TASKPRI_MASK; 14907233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), prio); 149114cf11afSPaul Mackerras } 149214cf11afSPaul Mackerras 149314cf11afSPaul Mackerras void mpic_teardown_this_cpu(int secondary) 149414cf11afSPaul Mackerras { 149514cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 149614cf11afSPaul Mackerras unsigned long flags; 149714cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 149814cf11afSPaul Mackerras unsigned int i; 149914cf11afSPaul Mackerras 150014cf11afSPaul Mackerras BUG_ON(mpic == NULL); 150114cf11afSPaul Mackerras 150214cf11afSPaul Mackerras DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 1503203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic_lock, flags); 150414cf11afSPaul Mackerras 150514cf11afSPaul Mackerras /* let the mpic know we don't want intrs. */ 150614cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources ; i++) 15077233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 15087233593bSZang Roy-r61911 mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) & ~msk); 150914cf11afSPaul Mackerras 151014cf11afSPaul Mackerras /* Set current processor priority to max */ 15117233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 15127132799bSValentine Barshak /* We need to EOI the IPI since not all platforms reset the MPIC 15137132799bSValentine Barshak * on boot and new interrupts wouldn't get delivered otherwise. 15147132799bSValentine Barshak */ 15157132799bSValentine Barshak mpic_eoi(mpic); 151614cf11afSPaul Mackerras 1517203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic_lock, flags); 151814cf11afSPaul Mackerras } 151914cf11afSPaul Mackerras 152014cf11afSPaul Mackerras 1521f365355eSOlof Johansson static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg) 152214cf11afSPaul Mackerras { 15230ebfff14SBenjamin Herrenschmidt u32 src; 152414cf11afSPaul Mackerras 1525f365355eSOlof Johansson src = mpic_cpu_read(reg) & MPIC_INFO(VECPRI_VECTOR_MASK); 15261beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_LOW 1527f365355eSOlof Johansson DBG("%s: get_one_irq(reg 0x%x): %d\n", mpic->name, reg, src); 15281beb6a7dSBenjamin Herrenschmidt #endif 15295cddd2e3SJosh Boyer if (unlikely(src == mpic->spurious_vec)) { 15305cddd2e3SJosh Boyer if (mpic->flags & MPIC_SPV_EOI) 15315cddd2e3SJosh Boyer mpic_eoi(mpic); 15320ebfff14SBenjamin Herrenschmidt return NO_IRQ; 15335cddd2e3SJosh Boyer } 15347fd72186SBenjamin Herrenschmidt if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { 15357fd72186SBenjamin Herrenschmidt if (printk_ratelimit()) 15367fd72186SBenjamin Herrenschmidt printk(KERN_WARNING "%s: Got protected source %d !\n", 15377fd72186SBenjamin Herrenschmidt mpic->name, (int)src); 15387fd72186SBenjamin Herrenschmidt mpic_eoi(mpic); 15397fd72186SBenjamin Herrenschmidt return NO_IRQ; 15407fd72186SBenjamin Herrenschmidt } 15417fd72186SBenjamin Herrenschmidt 15420ebfff14SBenjamin Herrenschmidt return irq_linear_revmap(mpic->irqhost, src); 154314cf11afSPaul Mackerras } 154414cf11afSPaul Mackerras 1545f365355eSOlof Johansson unsigned int mpic_get_one_irq(struct mpic *mpic) 1546f365355eSOlof Johansson { 1547f365355eSOlof Johansson return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_INTACK)); 1548f365355eSOlof Johansson } 1549f365355eSOlof Johansson 155035a84c2fSOlaf Hering unsigned int mpic_get_irq(void) 155114cf11afSPaul Mackerras { 155214cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 155314cf11afSPaul Mackerras 155414cf11afSPaul Mackerras BUG_ON(mpic == NULL); 155514cf11afSPaul Mackerras 155635a84c2fSOlaf Hering return mpic_get_one_irq(mpic); 155714cf11afSPaul Mackerras } 155814cf11afSPaul Mackerras 1559d91e4ea7SKumar Gala unsigned int mpic_get_coreint_irq(void) 1560d91e4ea7SKumar Gala { 1561d91e4ea7SKumar Gala #ifdef CONFIG_BOOKE 1562d91e4ea7SKumar Gala struct mpic *mpic = mpic_primary; 1563d91e4ea7SKumar Gala u32 src; 1564d91e4ea7SKumar Gala 1565d91e4ea7SKumar Gala BUG_ON(mpic == NULL); 1566d91e4ea7SKumar Gala 1567d91e4ea7SKumar Gala src = mfspr(SPRN_EPR); 1568d91e4ea7SKumar Gala 1569d91e4ea7SKumar Gala if (unlikely(src == mpic->spurious_vec)) { 1570d91e4ea7SKumar Gala if (mpic->flags & MPIC_SPV_EOI) 1571d91e4ea7SKumar Gala mpic_eoi(mpic); 1572d91e4ea7SKumar Gala return NO_IRQ; 1573d91e4ea7SKumar Gala } 1574d91e4ea7SKumar Gala if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { 1575d91e4ea7SKumar Gala if (printk_ratelimit()) 1576d91e4ea7SKumar Gala printk(KERN_WARNING "%s: Got protected source %d !\n", 1577d91e4ea7SKumar Gala mpic->name, (int)src); 1578d91e4ea7SKumar Gala return NO_IRQ; 1579d91e4ea7SKumar Gala } 1580d91e4ea7SKumar Gala 1581d91e4ea7SKumar Gala return irq_linear_revmap(mpic->irqhost, src); 1582d91e4ea7SKumar Gala #else 1583d91e4ea7SKumar Gala return NO_IRQ; 1584d91e4ea7SKumar Gala #endif 1585d91e4ea7SKumar Gala } 1586d91e4ea7SKumar Gala 1587f365355eSOlof Johansson unsigned int mpic_get_mcirq(void) 1588f365355eSOlof Johansson { 1589f365355eSOlof Johansson struct mpic *mpic = mpic_primary; 1590f365355eSOlof Johansson 1591f365355eSOlof Johansson BUG_ON(mpic == NULL); 1592f365355eSOlof Johansson 1593f365355eSOlof Johansson return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_MCACK)); 1594f365355eSOlof Johansson } 159514cf11afSPaul Mackerras 159614cf11afSPaul Mackerras #ifdef CONFIG_SMP 159714cf11afSPaul Mackerras void mpic_request_ipis(void) 159814cf11afSPaul Mackerras { 159914cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 160078608dd3SMilton Miller int i; 160114cf11afSPaul Mackerras BUG_ON(mpic == NULL); 160214cf11afSPaul Mackerras 16030ebfff14SBenjamin Herrenschmidt printk(KERN_INFO "mpic: requesting IPIs...\n"); 160414cf11afSPaul Mackerras 16050ebfff14SBenjamin Herrenschmidt for (i = 0; i < 4; i++) { 16060ebfff14SBenjamin Herrenschmidt unsigned int vipi = irq_create_mapping(mpic->irqhost, 16077df2457dSOlof Johansson mpic->ipi_vecs[0] + i); 16080ebfff14SBenjamin Herrenschmidt if (vipi == NO_IRQ) { 160978608dd3SMilton Miller printk(KERN_ERR "Failed to map %s\n", smp_ipi_name[i]); 161078608dd3SMilton Miller continue; 16110ebfff14SBenjamin Herrenschmidt } 161278608dd3SMilton Miller smp_request_message_ipi(vipi, i); 16130ebfff14SBenjamin Herrenschmidt } 161414cf11afSPaul Mackerras } 1615a9c59264SPaul Mackerras 16162ef613cbSBenjamin Herrenschmidt static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask) 16172ef613cbSBenjamin Herrenschmidt { 16182ef613cbSBenjamin Herrenschmidt struct mpic *mpic = mpic_primary; 16192ef613cbSBenjamin Herrenschmidt 16202ef613cbSBenjamin Herrenschmidt BUG_ON(mpic == NULL); 16212ef613cbSBenjamin Herrenschmidt 16222ef613cbSBenjamin Herrenschmidt #ifdef DEBUG_IPI 16232ef613cbSBenjamin Herrenschmidt DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); 16242ef613cbSBenjamin Herrenschmidt #endif 16252ef613cbSBenjamin Herrenschmidt 16262ef613cbSBenjamin Herrenschmidt mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + 16272ef613cbSBenjamin Herrenschmidt ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), 16282ef613cbSBenjamin Herrenschmidt mpic_physmask(cpumask_bits(cpu_mask)[0])); 16292ef613cbSBenjamin Herrenschmidt } 16302ef613cbSBenjamin Herrenschmidt 1631a9c59264SPaul Mackerras void smp_mpic_message_pass(int target, int msg) 1632a9c59264SPaul Mackerras { 16332ef613cbSBenjamin Herrenschmidt cpumask_var_t tmp; 16342ef613cbSBenjamin Herrenschmidt 1635a9c59264SPaul Mackerras /* make sure we're sending something that translates to an IPI */ 1636a9c59264SPaul Mackerras if ((unsigned int)msg > 3) { 1637a9c59264SPaul Mackerras printk("SMP %d: smp_message_pass: unknown msg %d\n", 1638a9c59264SPaul Mackerras smp_processor_id(), msg); 1639a9c59264SPaul Mackerras return; 1640a9c59264SPaul Mackerras } 1641a9c59264SPaul Mackerras switch (target) { 1642a9c59264SPaul Mackerras case MSG_ALL: 16432ef613cbSBenjamin Herrenschmidt mpic_send_ipi(msg, cpu_online_mask); 1644a9c59264SPaul Mackerras break; 1645a9c59264SPaul Mackerras case MSG_ALL_BUT_SELF: 16462ef613cbSBenjamin Herrenschmidt alloc_cpumask_var(&tmp, GFP_NOWAIT); 16472ef613cbSBenjamin Herrenschmidt cpumask_andnot(tmp, cpu_online_mask, 16482ef613cbSBenjamin Herrenschmidt cpumask_of(smp_processor_id())); 16492ef613cbSBenjamin Herrenschmidt mpic_send_ipi(msg, tmp); 16502ef613cbSBenjamin Herrenschmidt free_cpumask_var(tmp); 1651a9c59264SPaul Mackerras break; 1652a9c59264SPaul Mackerras default: 16532ef613cbSBenjamin Herrenschmidt mpic_send_ipi(msg, cpumask_of(target)); 1654a9c59264SPaul Mackerras break; 1655a9c59264SPaul Mackerras } 1656a9c59264SPaul Mackerras } 1657775aeff4SMichael Ellerman 1658775aeff4SMichael Ellerman int __init smp_mpic_probe(void) 1659775aeff4SMichael Ellerman { 1660775aeff4SMichael Ellerman int nr_cpus; 1661775aeff4SMichael Ellerman 1662775aeff4SMichael Ellerman DBG("smp_mpic_probe()...\n"); 1663775aeff4SMichael Ellerman 16642ef613cbSBenjamin Herrenschmidt nr_cpus = cpumask_weight(cpu_possible_mask); 1665775aeff4SMichael Ellerman 1666775aeff4SMichael Ellerman DBG("nr_cpus: %d\n", nr_cpus); 1667775aeff4SMichael Ellerman 1668775aeff4SMichael Ellerman if (nr_cpus > 1) 1669775aeff4SMichael Ellerman mpic_request_ipis(); 1670775aeff4SMichael Ellerman 1671775aeff4SMichael Ellerman return nr_cpus; 1672775aeff4SMichael Ellerman } 1673775aeff4SMichael Ellerman 1674775aeff4SMichael Ellerman void __devinit smp_mpic_setup_cpu(int cpu) 1675775aeff4SMichael Ellerman { 1676775aeff4SMichael Ellerman mpic_setup_this_cpu(); 1677775aeff4SMichael Ellerman } 167866953ebeSMatthew McClintock 167966953ebeSMatthew McClintock void mpic_reset_core(int cpu) 168066953ebeSMatthew McClintock { 168166953ebeSMatthew McClintock struct mpic *mpic = mpic_primary; 168266953ebeSMatthew McClintock u32 pir; 168366953ebeSMatthew McClintock int cpuid = get_hard_smp_processor_id(cpu); 168466953ebeSMatthew McClintock 168566953ebeSMatthew McClintock /* Set target bit for core reset */ 168666953ebeSMatthew McClintock pir = mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); 168766953ebeSMatthew McClintock pir |= (1 << cpuid); 168866953ebeSMatthew McClintock mpic_write(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT), pir); 168966953ebeSMatthew McClintock mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); 169066953ebeSMatthew McClintock 169166953ebeSMatthew McClintock /* Restore target bit after reset complete */ 169266953ebeSMatthew McClintock pir &= ~(1 << cpuid); 169366953ebeSMatthew McClintock mpic_write(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT), pir); 169466953ebeSMatthew McClintock mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); 169566953ebeSMatthew McClintock } 169614cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 16973669e930SJohannes Berg 16983669e930SJohannes Berg #ifdef CONFIG_PM 16993669e930SJohannes Berg static int mpic_suspend(struct sys_device *dev, pm_message_t state) 17003669e930SJohannes Berg { 17013669e930SJohannes Berg struct mpic *mpic = container_of(dev, struct mpic, sysdev); 17023669e930SJohannes Berg int i; 17033669e930SJohannes Berg 17043669e930SJohannes Berg for (i = 0; i < mpic->num_sources; i++) { 17053669e930SJohannes Berg mpic->save_data[i].vecprio = 17063669e930SJohannes Berg mpic_irq_read(i, MPIC_INFO(IRQ_VECTOR_PRI)); 17073669e930SJohannes Berg mpic->save_data[i].dest = 17083669e930SJohannes Berg mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); 17093669e930SJohannes Berg } 17103669e930SJohannes Berg 17113669e930SJohannes Berg return 0; 17123669e930SJohannes Berg } 17133669e930SJohannes Berg 17143669e930SJohannes Berg static int mpic_resume(struct sys_device *dev) 17153669e930SJohannes Berg { 17163669e930SJohannes Berg struct mpic *mpic = container_of(dev, struct mpic, sysdev); 17173669e930SJohannes Berg int i; 17183669e930SJohannes Berg 17193669e930SJohannes Berg for (i = 0; i < mpic->num_sources; i++) { 17203669e930SJohannes Berg mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), 17213669e930SJohannes Berg mpic->save_data[i].vecprio); 17223669e930SJohannes Berg mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 17233669e930SJohannes Berg mpic->save_data[i].dest); 17243669e930SJohannes Berg 17253669e930SJohannes Berg #ifdef CONFIG_MPIC_U3_HT_IRQS 17267c9d9360SAlastair Bridgewater if (mpic->fixups) { 17273669e930SJohannes Berg struct mpic_irq_fixup *fixup = &mpic->fixups[i]; 17283669e930SJohannes Berg 17293669e930SJohannes Berg if (fixup->base) { 17303669e930SJohannes Berg /* we use the lowest bit in an inverted meaning */ 17313669e930SJohannes Berg if ((mpic->save_data[i].fixup_data & 1) == 0) 17323669e930SJohannes Berg continue; 17333669e930SJohannes Berg 17343669e930SJohannes Berg /* Enable and configure */ 17353669e930SJohannes Berg writeb(0x10 + 2 * fixup->index, fixup->base + 2); 17363669e930SJohannes Berg 17373669e930SJohannes Berg writel(mpic->save_data[i].fixup_data & ~1, 17383669e930SJohannes Berg fixup->base + 4); 17393669e930SJohannes Berg } 17403669e930SJohannes Berg } 17413669e930SJohannes Berg #endif 17423669e930SJohannes Berg } /* end for loop */ 17433669e930SJohannes Berg 17443669e930SJohannes Berg return 0; 17453669e930SJohannes Berg } 17463669e930SJohannes Berg #endif 17473669e930SJohannes Berg 17483669e930SJohannes Berg static struct sysdev_class mpic_sysclass = { 17493669e930SJohannes Berg #ifdef CONFIG_PM 17503669e930SJohannes Berg .resume = mpic_resume, 17513669e930SJohannes Berg .suspend = mpic_suspend, 17523669e930SJohannes Berg #endif 1753af5ca3f4SKay Sievers .name = "mpic", 17543669e930SJohannes Berg }; 17553669e930SJohannes Berg 17563669e930SJohannes Berg static int mpic_init_sys(void) 17573669e930SJohannes Berg { 17583669e930SJohannes Berg struct mpic *mpic = mpics; 17593669e930SJohannes Berg int error, id = 0; 17603669e930SJohannes Berg 17613669e930SJohannes Berg error = sysdev_class_register(&mpic_sysclass); 17623669e930SJohannes Berg 17633669e930SJohannes Berg while (mpic && !error) { 17643669e930SJohannes Berg mpic->sysdev.cls = &mpic_sysclass; 17653669e930SJohannes Berg mpic->sysdev.id = id++; 17663669e930SJohannes Berg error = sysdev_register(&mpic->sysdev); 17673669e930SJohannes Berg mpic = mpic->next; 17683669e930SJohannes Berg } 17693669e930SJohannes Berg return error; 17703669e930SJohannes Berg } 17713669e930SJohannes Berg 17723669e930SJohannes Berg device_initcall(mpic_init_sys); 1773