114cf11afSPaul Mackerras /* 214cf11afSPaul Mackerras * arch/powerpc/kernel/mpic.c 314cf11afSPaul Mackerras * 414cf11afSPaul Mackerras * Driver for interrupt controllers following the OpenPIC standard, the 5446957baSAdam Buchbinder * common implementation being 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. 903bcb7e3SVarun Sethi * Copyright 2010-2012 Freescale Semiconductor, Inc. 1014cf11afSPaul Mackerras * 1114cf11afSPaul Mackerras * This file is subject to the terms and conditions of the GNU General Public 1214cf11afSPaul Mackerras * License. See the file COPYING in the main directory of this archive 1314cf11afSPaul Mackerras * for more details. 1414cf11afSPaul Mackerras */ 1514cf11afSPaul Mackerras 1614cf11afSPaul Mackerras #undef DEBUG 171beb6a7dSBenjamin Herrenschmidt #undef DEBUG_IPI 181beb6a7dSBenjamin Herrenschmidt #undef DEBUG_IRQ 191beb6a7dSBenjamin Herrenschmidt #undef DEBUG_LOW 2014cf11afSPaul Mackerras 2114cf11afSPaul Mackerras #include <linux/types.h> 2214cf11afSPaul Mackerras #include <linux/kernel.h> 2314cf11afSPaul Mackerras #include <linux/init.h> 2414cf11afSPaul Mackerras #include <linux/irq.h> 2514cf11afSPaul Mackerras #include <linux/smp.h> 2614cf11afSPaul Mackerras #include <linux/interrupt.h> 2714cf11afSPaul Mackerras #include <linux/spinlock.h> 2814cf11afSPaul Mackerras #include <linux/pci.h> 295a0e3ad6STejun Heo #include <linux/slab.h> 30f5a592f7SRafael J. Wysocki #include <linux/syscore_ops.h> 3176462232SChristian Dietrich #include <linux/ratelimit.h> 3214cf11afSPaul Mackerras 3314cf11afSPaul Mackerras #include <asm/ptrace.h> 3414cf11afSPaul Mackerras #include <asm/signal.h> 3514cf11afSPaul Mackerras #include <asm/io.h> 3614cf11afSPaul Mackerras #include <asm/pgtable.h> 3714cf11afSPaul Mackerras #include <asm/irq.h> 3814cf11afSPaul Mackerras #include <asm/machdep.h> 3914cf11afSPaul Mackerras #include <asm/mpic.h> 4014cf11afSPaul Mackerras #include <asm/smp.h> 4114cf11afSPaul Mackerras 42a7de7c74SMichael Ellerman #include "mpic.h" 43a7de7c74SMichael Ellerman 4414cf11afSPaul Mackerras #ifdef DEBUG 4514cf11afSPaul Mackerras #define DBG(fmt...) printk(fmt) 4614cf11afSPaul Mackerras #else 4714cf11afSPaul Mackerras #define DBG(fmt...) 4814cf11afSPaul Mackerras #endif 4914cf11afSPaul Mackerras 509e6f31a9SDongsheng.wang@freescale.com struct bus_type mpic_subsys = { 519e6f31a9SDongsheng.wang@freescale.com .name = "mpic", 529e6f31a9SDongsheng.wang@freescale.com .dev_name = "mpic", 539e6f31a9SDongsheng.wang@freescale.com }; 549e6f31a9SDongsheng.wang@freescale.com EXPORT_SYMBOL_GPL(mpic_subsys); 559e6f31a9SDongsheng.wang@freescale.com 5614cf11afSPaul Mackerras static struct mpic *mpics; 5714cf11afSPaul Mackerras static struct mpic *mpic_primary; 58203041adSThomas Gleixner static DEFINE_RAW_SPINLOCK(mpic_lock); 5914cf11afSPaul Mackerras 60c0c0d996SPaul Mackerras #ifdef CONFIG_PPC32 /* XXX for now */ 61e40c7f02SAndy Whitcroft #ifdef CONFIG_IRQ_ALL_CPUS 62e242114aSchenhui zhao #define distribute_irqs (1) 63e40c7f02SAndy Whitcroft #else 64e40c7f02SAndy Whitcroft #define distribute_irqs (0) 65e40c7f02SAndy Whitcroft #endif 66c0c0d996SPaul Mackerras #endif 6714cf11afSPaul Mackerras 687233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 697233593bSZang Roy-r61911 static u32 mpic_infos[][MPIC_IDX_END] = { 707233593bSZang Roy-r61911 [0] = { /* Original OpenPIC compatible MPIC */ 717233593bSZang Roy-r61911 MPIC_GREG_BASE, 727233593bSZang Roy-r61911 MPIC_GREG_FEATURE_0, 737233593bSZang Roy-r61911 MPIC_GREG_GLOBAL_CONF_0, 747233593bSZang Roy-r61911 MPIC_GREG_VENDOR_ID, 757233593bSZang Roy-r61911 MPIC_GREG_IPI_VECTOR_PRI_0, 767233593bSZang Roy-r61911 MPIC_GREG_IPI_STRIDE, 777233593bSZang Roy-r61911 MPIC_GREG_SPURIOUS, 787233593bSZang Roy-r61911 MPIC_GREG_TIMER_FREQ, 797233593bSZang Roy-r61911 807233593bSZang Roy-r61911 MPIC_TIMER_BASE, 817233593bSZang Roy-r61911 MPIC_TIMER_STRIDE, 827233593bSZang Roy-r61911 MPIC_TIMER_CURRENT_CNT, 837233593bSZang Roy-r61911 MPIC_TIMER_BASE_CNT, 847233593bSZang Roy-r61911 MPIC_TIMER_VECTOR_PRI, 857233593bSZang Roy-r61911 MPIC_TIMER_DESTINATION, 867233593bSZang Roy-r61911 877233593bSZang Roy-r61911 MPIC_CPU_BASE, 887233593bSZang Roy-r61911 MPIC_CPU_STRIDE, 897233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_0, 907233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_STRIDE, 917233593bSZang Roy-r61911 MPIC_CPU_CURRENT_TASK_PRI, 927233593bSZang Roy-r61911 MPIC_CPU_WHOAMI, 937233593bSZang Roy-r61911 MPIC_CPU_INTACK, 947233593bSZang Roy-r61911 MPIC_CPU_EOI, 95f365355eSOlof Johansson MPIC_CPU_MCACK, 967233593bSZang Roy-r61911 977233593bSZang Roy-r61911 MPIC_IRQ_BASE, 987233593bSZang Roy-r61911 MPIC_IRQ_STRIDE, 997233593bSZang Roy-r61911 MPIC_IRQ_VECTOR_PRI, 1007233593bSZang Roy-r61911 MPIC_VECPRI_VECTOR_MASK, 1017233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_POSITIVE, 1027233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_NEGATIVE, 1037233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_LEVEL, 1047233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_EDGE, 1057233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_MASK, 1067233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_MASK, 1077233593bSZang Roy-r61911 MPIC_IRQ_DESTINATION 1087233593bSZang Roy-r61911 }, 1097233593bSZang Roy-r61911 [1] = { /* Tsi108/109 PIC */ 1107233593bSZang Roy-r61911 TSI108_GREG_BASE, 1117233593bSZang Roy-r61911 TSI108_GREG_FEATURE_0, 1127233593bSZang Roy-r61911 TSI108_GREG_GLOBAL_CONF_0, 1137233593bSZang Roy-r61911 TSI108_GREG_VENDOR_ID, 1147233593bSZang Roy-r61911 TSI108_GREG_IPI_VECTOR_PRI_0, 1157233593bSZang Roy-r61911 TSI108_GREG_IPI_STRIDE, 1167233593bSZang Roy-r61911 TSI108_GREG_SPURIOUS, 1177233593bSZang Roy-r61911 TSI108_GREG_TIMER_FREQ, 1187233593bSZang Roy-r61911 1197233593bSZang Roy-r61911 TSI108_TIMER_BASE, 1207233593bSZang Roy-r61911 TSI108_TIMER_STRIDE, 1217233593bSZang Roy-r61911 TSI108_TIMER_CURRENT_CNT, 1227233593bSZang Roy-r61911 TSI108_TIMER_BASE_CNT, 1237233593bSZang Roy-r61911 TSI108_TIMER_VECTOR_PRI, 1247233593bSZang Roy-r61911 TSI108_TIMER_DESTINATION, 1257233593bSZang Roy-r61911 1267233593bSZang Roy-r61911 TSI108_CPU_BASE, 1277233593bSZang Roy-r61911 TSI108_CPU_STRIDE, 1287233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_0, 1297233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_STRIDE, 1307233593bSZang Roy-r61911 TSI108_CPU_CURRENT_TASK_PRI, 1317233593bSZang Roy-r61911 TSI108_CPU_WHOAMI, 1327233593bSZang Roy-r61911 TSI108_CPU_INTACK, 1337233593bSZang Roy-r61911 TSI108_CPU_EOI, 134f365355eSOlof Johansson TSI108_CPU_MCACK, 1357233593bSZang Roy-r61911 1367233593bSZang Roy-r61911 TSI108_IRQ_BASE, 1377233593bSZang Roy-r61911 TSI108_IRQ_STRIDE, 1387233593bSZang Roy-r61911 TSI108_IRQ_VECTOR_PRI, 1397233593bSZang Roy-r61911 TSI108_VECPRI_VECTOR_MASK, 1407233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_POSITIVE, 1417233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_NEGATIVE, 1427233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_LEVEL, 1437233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_EDGE, 1447233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_MASK, 1457233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_MASK, 1467233593bSZang Roy-r61911 TSI108_IRQ_DESTINATION 1477233593bSZang Roy-r61911 }, 1487233593bSZang Roy-r61911 }; 1497233593bSZang Roy-r61911 1507233593bSZang Roy-r61911 #define MPIC_INFO(name) mpic->hw_set[MPIC_IDX_##name] 1517233593bSZang Roy-r61911 1527233593bSZang Roy-r61911 #else /* CONFIG_MPIC_WEIRD */ 1537233593bSZang Roy-r61911 1547233593bSZang Roy-r61911 #define MPIC_INFO(name) MPIC_##name 1557233593bSZang Roy-r61911 1567233593bSZang Roy-r61911 #endif /* CONFIG_MPIC_WEIRD */ 1577233593bSZang Roy-r61911 158d6a2639bSMeador Inge static inline unsigned int mpic_processor_id(struct mpic *mpic) 159d6a2639bSMeador Inge { 160d6a2639bSMeador Inge unsigned int cpu = 0; 161d6a2639bSMeador Inge 162be8bec56SKyle Moffett if (!(mpic->flags & MPIC_SECONDARY)) 163d6a2639bSMeador Inge cpu = hard_smp_processor_id(); 164d6a2639bSMeador Inge 165d6a2639bSMeador Inge return cpu; 166d6a2639bSMeador Inge } 167d6a2639bSMeador Inge 16814cf11afSPaul Mackerras /* 16914cf11afSPaul Mackerras * Register accessor functions 17014cf11afSPaul Mackerras */ 17114cf11afSPaul Mackerras 17214cf11afSPaul Mackerras 173fbf0274eSBenjamin Herrenschmidt static inline u32 _mpic_read(enum mpic_reg_type type, 174fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, 17514cf11afSPaul Mackerras unsigned int reg) 17614cf11afSPaul Mackerras { 177fbf0274eSBenjamin Herrenschmidt switch(type) { 178fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 179fbf0274eSBenjamin Herrenschmidt case mpic_access_dcr: 18083f34df4SMichael Ellerman return dcr_read(rb->dhost, reg); 181fbf0274eSBenjamin Herrenschmidt #endif 182fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_be: 183fbf0274eSBenjamin Herrenschmidt return in_be32(rb->base + (reg >> 2)); 184fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_le: 185fbf0274eSBenjamin Herrenschmidt default: 186fbf0274eSBenjamin Herrenschmidt return in_le32(rb->base + (reg >> 2)); 187fbf0274eSBenjamin Herrenschmidt } 18814cf11afSPaul Mackerras } 18914cf11afSPaul Mackerras 190fbf0274eSBenjamin Herrenschmidt static inline void _mpic_write(enum mpic_reg_type type, 191fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, 19214cf11afSPaul Mackerras unsigned int reg, u32 value) 19314cf11afSPaul Mackerras { 194fbf0274eSBenjamin Herrenschmidt switch(type) { 195fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 196fbf0274eSBenjamin Herrenschmidt case mpic_access_dcr: 197d9d1063dSJohannes Berg dcr_write(rb->dhost, reg, value); 198d9d1063dSJohannes Berg break; 199fbf0274eSBenjamin Herrenschmidt #endif 200fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_be: 201d9d1063dSJohannes Berg out_be32(rb->base + (reg >> 2), value); 202d9d1063dSJohannes Berg break; 203fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_le: 204fbf0274eSBenjamin Herrenschmidt default: 205d9d1063dSJohannes Berg out_le32(rb->base + (reg >> 2), value); 206d9d1063dSJohannes Berg break; 207fbf0274eSBenjamin Herrenschmidt } 20814cf11afSPaul Mackerras } 20914cf11afSPaul Mackerras 21014cf11afSPaul Mackerras static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) 21114cf11afSPaul Mackerras { 212fbf0274eSBenjamin Herrenschmidt enum mpic_reg_type type = mpic->reg_type; 2137233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 2147233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 21514cf11afSPaul Mackerras 216fbf0274eSBenjamin Herrenschmidt if ((mpic->flags & MPIC_BROKEN_IPI) && type == mpic_access_mmio_le) 217fbf0274eSBenjamin Herrenschmidt type = mpic_access_mmio_be; 218fbf0274eSBenjamin Herrenschmidt return _mpic_read(type, &mpic->gregs, offset); 21914cf11afSPaul Mackerras } 22014cf11afSPaul Mackerras 22114cf11afSPaul Mackerras static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) 22214cf11afSPaul Mackerras { 2237233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 2247233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 22514cf11afSPaul Mackerras 226fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); 22714cf11afSPaul Mackerras } 22814cf11afSPaul Mackerras 22903bcb7e3SVarun Sethi static inline unsigned int mpic_tm_offset(struct mpic *mpic, unsigned int tm) 23003bcb7e3SVarun Sethi { 23103bcb7e3SVarun Sethi return (tm >> 2) * MPIC_TIMER_GROUP_STRIDE + 23203bcb7e3SVarun Sethi (tm & 3) * MPIC_INFO(TIMER_STRIDE); 23303bcb7e3SVarun Sethi } 23403bcb7e3SVarun Sethi 235ea94187fSScott Wood static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm) 236ea94187fSScott Wood { 23703bcb7e3SVarun Sethi unsigned int offset = mpic_tm_offset(mpic, tm) + 23803bcb7e3SVarun Sethi MPIC_INFO(TIMER_VECTOR_PRI); 239ea94187fSScott Wood 240ea94187fSScott Wood return _mpic_read(mpic->reg_type, &mpic->tmregs, offset); 241ea94187fSScott Wood } 242ea94187fSScott Wood 243ea94187fSScott Wood static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value) 244ea94187fSScott Wood { 24503bcb7e3SVarun Sethi unsigned int offset = mpic_tm_offset(mpic, tm) + 24603bcb7e3SVarun Sethi MPIC_INFO(TIMER_VECTOR_PRI); 247ea94187fSScott Wood 248ea94187fSScott Wood _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value); 249ea94187fSScott Wood } 250ea94187fSScott Wood 25114cf11afSPaul Mackerras static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) 25214cf11afSPaul Mackerras { 253d6a2639bSMeador Inge unsigned int cpu = mpic_processor_id(mpic); 25414cf11afSPaul Mackerras 255fbf0274eSBenjamin Herrenschmidt return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg); 25614cf11afSPaul Mackerras } 25714cf11afSPaul Mackerras 25814cf11afSPaul Mackerras static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) 25914cf11afSPaul Mackerras { 260d6a2639bSMeador Inge unsigned int cpu = mpic_processor_id(mpic); 26114cf11afSPaul Mackerras 262fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value); 26314cf11afSPaul Mackerras } 26414cf11afSPaul Mackerras 26514cf11afSPaul Mackerras static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) 26614cf11afSPaul Mackerras { 26714cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 26814cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 26911a6b292SMichael Ellerman unsigned int val; 27014cf11afSPaul Mackerras 27111a6b292SMichael Ellerman val = _mpic_read(mpic->reg_type, &mpic->isus[isu], 27211a6b292SMichael Ellerman reg + (idx * MPIC_INFO(IRQ_STRIDE))); 2730d72ba93SOlof Johansson #ifdef CONFIG_MPIC_BROKEN_REGREAD 2740d72ba93SOlof Johansson if (reg == 0) 27511a6b292SMichael Ellerman val = (val & (MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY)) | 27611a6b292SMichael Ellerman mpic->isu_reg0_shadow[src_no]; 2770d72ba93SOlof Johansson #endif 27811a6b292SMichael Ellerman return val; 27914cf11afSPaul Mackerras } 28014cf11afSPaul Mackerras 28114cf11afSPaul Mackerras static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, 28214cf11afSPaul Mackerras unsigned int reg, u32 value) 28314cf11afSPaul Mackerras { 28414cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 28514cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 28614cf11afSPaul Mackerras 287fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->isus[isu], 2887233593bSZang Roy-r61911 reg + (idx * MPIC_INFO(IRQ_STRIDE)), value); 2890d72ba93SOlof Johansson 2900d72ba93SOlof Johansson #ifdef CONFIG_MPIC_BROKEN_REGREAD 2910d72ba93SOlof Johansson if (reg == 0) 29211a6b292SMichael Ellerman mpic->isu_reg0_shadow[src_no] = 29311a6b292SMichael Ellerman value & ~(MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY); 2940d72ba93SOlof Johansson #endif 29514cf11afSPaul Mackerras } 29614cf11afSPaul Mackerras 297fbf0274eSBenjamin Herrenschmidt #define mpic_read(b,r) _mpic_read(mpic->reg_type,&(b),(r)) 298fbf0274eSBenjamin Herrenschmidt #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) 29914cf11afSPaul Mackerras #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) 30014cf11afSPaul Mackerras #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) 301ea94187fSScott Wood #define mpic_tm_read(i) _mpic_tm_read(mpic,(i)) 302ea94187fSScott Wood #define mpic_tm_write(i,v) _mpic_tm_write(mpic,(i),(v)) 30314cf11afSPaul Mackerras #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) 30414cf11afSPaul Mackerras #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) 30514cf11afSPaul Mackerras #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) 30614cf11afSPaul Mackerras #define mpic_irq_write(s,r,v) _mpic_irq_write(mpic,(s),(r),(v)) 30714cf11afSPaul Mackerras 30814cf11afSPaul Mackerras 30914cf11afSPaul Mackerras /* 31014cf11afSPaul Mackerras * Low level utility functions 31114cf11afSPaul Mackerras */ 31214cf11afSPaul Mackerras 31314cf11afSPaul Mackerras 314c51a3fdcSBecky Bruce static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr, 315fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, unsigned int offset, 316fbf0274eSBenjamin Herrenschmidt unsigned int size) 317fbf0274eSBenjamin Herrenschmidt { 318fbf0274eSBenjamin Herrenschmidt rb->base = ioremap(phys_addr + offset, size); 319fbf0274eSBenjamin Herrenschmidt BUG_ON(rb->base == NULL); 320fbf0274eSBenjamin Herrenschmidt } 321fbf0274eSBenjamin Herrenschmidt 322fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 323c51242e7SKyle Moffett static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb, 324fbf0274eSBenjamin Herrenschmidt unsigned int offset, unsigned int size) 325fbf0274eSBenjamin Herrenschmidt { 326c51242e7SKyle Moffett phys_addr_t phys_addr = dcr_resource_start(mpic->node, 0); 327e62b7601SKyle Moffett rb->dhost = dcr_map(mpic->node, phys_addr + offset, size); 328fbf0274eSBenjamin Herrenschmidt BUG_ON(!DCR_MAP_OK(rb->dhost)); 329fbf0274eSBenjamin Herrenschmidt } 330fbf0274eSBenjamin Herrenschmidt 331c51242e7SKyle Moffett static inline void mpic_map(struct mpic *mpic, 3325a2642f6SBenjamin Herrenschmidt phys_addr_t phys_addr, struct mpic_reg_bank *rb, 3335a2642f6SBenjamin Herrenschmidt unsigned int offset, unsigned int size) 334fbf0274eSBenjamin Herrenschmidt { 335fbf0274eSBenjamin Herrenschmidt if (mpic->flags & MPIC_USES_DCR) 336c51242e7SKyle Moffett _mpic_map_dcr(mpic, rb, offset, size); 337fbf0274eSBenjamin Herrenschmidt else 338fbf0274eSBenjamin Herrenschmidt _mpic_map_mmio(mpic, phys_addr, rb, offset, size); 339fbf0274eSBenjamin Herrenschmidt } 340fbf0274eSBenjamin Herrenschmidt #else /* CONFIG_PPC_DCR */ 341c51242e7SKyle Moffett #define mpic_map(m,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) 342fbf0274eSBenjamin Herrenschmidt #endif /* !CONFIG_PPC_DCR */ 343fbf0274eSBenjamin Herrenschmidt 344fbf0274eSBenjamin Herrenschmidt 34514cf11afSPaul Mackerras 34614cf11afSPaul Mackerras /* Check if we have one of those nice broken MPICs with a flipped endian on 34714cf11afSPaul Mackerras * reads from IPI registers 34814cf11afSPaul Mackerras */ 34914cf11afSPaul Mackerras static void __init mpic_test_broken_ipi(struct mpic *mpic) 35014cf11afSPaul Mackerras { 35114cf11afSPaul Mackerras u32 r; 35214cf11afSPaul Mackerras 3537233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0), MPIC_VECPRI_MASK); 3547233593bSZang Roy-r61911 r = mpic_read(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0)); 35514cf11afSPaul Mackerras 35614cf11afSPaul Mackerras if (r == le32_to_cpu(MPIC_VECPRI_MASK)) { 35714cf11afSPaul Mackerras printk(KERN_INFO "mpic: Detected reversed IPI registers\n"); 35814cf11afSPaul Mackerras mpic->flags |= MPIC_BROKEN_IPI; 35914cf11afSPaul Mackerras } 36014cf11afSPaul Mackerras } 36114cf11afSPaul Mackerras 3626cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 36314cf11afSPaul Mackerras 36414cf11afSPaul Mackerras /* Test if an interrupt is sourced from HyperTransport (used on broken U3s) 36514cf11afSPaul Mackerras * to force the edge setting on the MPIC and do the ack workaround. 36614cf11afSPaul Mackerras */ 3671beb6a7dSBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 36814cf11afSPaul Mackerras { 3691beb6a7dSBenjamin Herrenschmidt if (source >= 128 || !mpic->fixups) 37014cf11afSPaul Mackerras return 0; 3711beb6a7dSBenjamin Herrenschmidt return mpic->fixups[source].base != NULL; 37214cf11afSPaul Mackerras } 37314cf11afSPaul Mackerras 374c4b22f26SSegher Boessenkool 3751beb6a7dSBenjamin Herrenschmidt static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source) 37614cf11afSPaul Mackerras { 3771beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 37814cf11afSPaul Mackerras 3791beb6a7dSBenjamin Herrenschmidt if (fixup->applebase) { 3801beb6a7dSBenjamin Herrenschmidt unsigned int soff = (fixup->index >> 3) & ~3; 3811beb6a7dSBenjamin Herrenschmidt unsigned int mask = 1U << (fixup->index & 0x1f); 3821beb6a7dSBenjamin Herrenschmidt writel(mask, fixup->applebase + soff); 3831beb6a7dSBenjamin Herrenschmidt } else { 384203041adSThomas Gleixner raw_spin_lock(&mpic->fixup_lock); 3851beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * fixup->index, fixup->base + 2); 386c4b22f26SSegher Boessenkool writel(fixup->data, fixup->base + 4); 387203041adSThomas Gleixner raw_spin_unlock(&mpic->fixup_lock); 38814cf11afSPaul Mackerras } 3891beb6a7dSBenjamin Herrenschmidt } 39014cf11afSPaul Mackerras 3911beb6a7dSBenjamin Herrenschmidt static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, 39224a3f2e8SThomas Gleixner bool level) 3931beb6a7dSBenjamin Herrenschmidt { 3941beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 3951beb6a7dSBenjamin Herrenschmidt unsigned long flags; 3961beb6a7dSBenjamin Herrenschmidt u32 tmp; 39714cf11afSPaul Mackerras 3981beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 3991beb6a7dSBenjamin Herrenschmidt return; 4001beb6a7dSBenjamin Herrenschmidt 40124a3f2e8SThomas Gleixner DBG("startup_ht_interrupt(0x%x) index: %d\n", 40224a3f2e8SThomas Gleixner source, fixup->index); 403203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic->fixup_lock, flags); 4041beb6a7dSBenjamin Herrenschmidt /* Enable and configure */ 4051beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 4061beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 4071beb6a7dSBenjamin Herrenschmidt tmp &= ~(0x23U); 40824a3f2e8SThomas Gleixner if (level) 4091beb6a7dSBenjamin Herrenschmidt tmp |= 0x22; 4101beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 411203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags); 4123669e930SJohannes Berg 4133669e930SJohannes Berg #ifdef CONFIG_PM 4143669e930SJohannes Berg /* use the lowest bit inverted to the actual HW, 4153669e930SJohannes Berg * set if this fixup was enabled, clear otherwise */ 4163669e930SJohannes Berg mpic->save_data[source].fixup_data = tmp | 1; 4173669e930SJohannes Berg #endif 4181beb6a7dSBenjamin Herrenschmidt } 4191beb6a7dSBenjamin Herrenschmidt 42024a3f2e8SThomas Gleixner static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source) 4211beb6a7dSBenjamin Herrenschmidt { 4221beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 4231beb6a7dSBenjamin Herrenschmidt unsigned long flags; 4241beb6a7dSBenjamin Herrenschmidt u32 tmp; 4251beb6a7dSBenjamin Herrenschmidt 4261beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 4271beb6a7dSBenjamin Herrenschmidt return; 4281beb6a7dSBenjamin Herrenschmidt 42924a3f2e8SThomas Gleixner DBG("shutdown_ht_interrupt(0x%x)\n", source); 4301beb6a7dSBenjamin Herrenschmidt 4311beb6a7dSBenjamin Herrenschmidt /* Disable */ 432203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic->fixup_lock, flags); 4331beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 4341beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 43572b13819SSegher Boessenkool tmp |= 1; 4361beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 437203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags); 4383669e930SJohannes Berg 4393669e930SJohannes Berg #ifdef CONFIG_PM 4403669e930SJohannes Berg /* use the lowest bit inverted to the actual HW, 4413669e930SJohannes Berg * set if this fixup was enabled, clear otherwise */ 4423669e930SJohannes Berg mpic->save_data[source].fixup_data = tmp & ~1; 4433669e930SJohannes Berg #endif 4441beb6a7dSBenjamin Herrenschmidt } 4451beb6a7dSBenjamin Herrenschmidt 446812fd1fdSMichael Ellerman #ifdef CONFIG_PCI_MSI 447812fd1fdSMichael Ellerman static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, 448812fd1fdSMichael Ellerman unsigned int devfn) 449812fd1fdSMichael Ellerman { 450812fd1fdSMichael Ellerman u8 __iomem *base; 451812fd1fdSMichael Ellerman u8 pos, flags; 452812fd1fdSMichael Ellerman u64 addr = 0; 453812fd1fdSMichael Ellerman 454812fd1fdSMichael Ellerman for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; 455812fd1fdSMichael Ellerman pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { 456812fd1fdSMichael Ellerman u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); 457812fd1fdSMichael Ellerman if (id == PCI_CAP_ID_HT) { 458812fd1fdSMichael Ellerman id = readb(devbase + pos + 3); 459812fd1fdSMichael Ellerman if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_MSI_MAPPING) 460812fd1fdSMichael Ellerman break; 461812fd1fdSMichael Ellerman } 462812fd1fdSMichael Ellerman } 463812fd1fdSMichael Ellerman 464812fd1fdSMichael Ellerman if (pos == 0) 465812fd1fdSMichael Ellerman return; 466812fd1fdSMichael Ellerman 467812fd1fdSMichael Ellerman base = devbase + pos; 468812fd1fdSMichael Ellerman 469812fd1fdSMichael Ellerman flags = readb(base + HT_MSI_FLAGS); 470812fd1fdSMichael Ellerman if (!(flags & HT_MSI_FLAGS_FIXED)) { 471812fd1fdSMichael Ellerman addr = readl(base + HT_MSI_ADDR_LO) & HT_MSI_ADDR_LO_MASK; 472812fd1fdSMichael Ellerman addr = addr | ((u64)readl(base + HT_MSI_ADDR_HI) << 32); 473812fd1fdSMichael Ellerman } 474812fd1fdSMichael Ellerman 475fe333321SIngo Molnar printk(KERN_DEBUG "mpic: - HT:%02x.%x %s MSI mapping found @ 0x%llx\n", 476812fd1fdSMichael Ellerman PCI_SLOT(devfn), PCI_FUNC(devfn), 477812fd1fdSMichael Ellerman flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled", addr); 478812fd1fdSMichael Ellerman 479812fd1fdSMichael Ellerman if (!(flags & HT_MSI_FLAGS_ENABLE)) 480812fd1fdSMichael Ellerman writeb(flags | HT_MSI_FLAGS_ENABLE, base + HT_MSI_FLAGS); 481812fd1fdSMichael Ellerman } 482812fd1fdSMichael Ellerman #else 483812fd1fdSMichael Ellerman static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, 484812fd1fdSMichael Ellerman unsigned int devfn) 485812fd1fdSMichael Ellerman { 486812fd1fdSMichael Ellerman return; 487812fd1fdSMichael Ellerman } 488812fd1fdSMichael Ellerman #endif 489812fd1fdSMichael Ellerman 4901beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, 4911beb6a7dSBenjamin Herrenschmidt unsigned int devfn, u32 vdid) 49214cf11afSPaul Mackerras { 493c4b22f26SSegher Boessenkool int i, irq, n; 4941beb6a7dSBenjamin Herrenschmidt u8 __iomem *base; 49514cf11afSPaul Mackerras u32 tmp; 496c4b22f26SSegher Boessenkool u8 pos; 49714cf11afSPaul Mackerras 4981beb6a7dSBenjamin Herrenschmidt for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; 4991beb6a7dSBenjamin Herrenschmidt pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { 5001beb6a7dSBenjamin Herrenschmidt u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); 50146ff3463SBrice Goglin if (id == PCI_CAP_ID_HT) { 502c4b22f26SSegher Boessenkool id = readb(devbase + pos + 3); 503beb7cc82SMichael Ellerman if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_IRQ) 504c4b22f26SSegher Boessenkool break; 505c4b22f26SSegher Boessenkool } 506c4b22f26SSegher Boessenkool } 507c4b22f26SSegher Boessenkool if (pos == 0) 508c4b22f26SSegher Boessenkool return; 509c4b22f26SSegher Boessenkool 5101beb6a7dSBenjamin Herrenschmidt base = devbase + pos; 5111beb6a7dSBenjamin Herrenschmidt writeb(0x01, base + 2); 5121beb6a7dSBenjamin Herrenschmidt n = (readl(base + 4) >> 16) & 0xff; 513c4b22f26SSegher Boessenkool 5141beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x" 5151beb6a7dSBenjamin Herrenschmidt " has %d irqs\n", 5161beb6a7dSBenjamin Herrenschmidt devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1); 517c4b22f26SSegher Boessenkool 518c4b22f26SSegher Boessenkool for (i = 0; i <= n; i++) { 5191beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * i, base + 2); 5201beb6a7dSBenjamin Herrenschmidt tmp = readl(base + 4); 52114cf11afSPaul Mackerras irq = (tmp >> 16) & 0xff; 5221beb6a7dSBenjamin Herrenschmidt DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp); 5231beb6a7dSBenjamin Herrenschmidt /* mask it , will be unmasked later */ 5241beb6a7dSBenjamin Herrenschmidt tmp |= 0x1; 5251beb6a7dSBenjamin Herrenschmidt writel(tmp, base + 4); 5261beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].index = i; 5271beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].base = base; 5281beb6a7dSBenjamin Herrenschmidt /* Apple HT PIC has a non-standard way of doing EOIs */ 5291beb6a7dSBenjamin Herrenschmidt if ((vdid & 0xffff) == 0x106b) 5301beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = devbase + 0x60; 5311beb6a7dSBenjamin Herrenschmidt else 5321beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = NULL; 5331beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * i, base + 2); 5341beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].data = readl(base + 4) | 0x80000000; 53514cf11afSPaul Mackerras } 53614cf11afSPaul Mackerras } 53714cf11afSPaul Mackerras 53814cf11afSPaul Mackerras 5391beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 54014cf11afSPaul Mackerras { 54114cf11afSPaul Mackerras unsigned int devfn; 54214cf11afSPaul Mackerras u8 __iomem *cfgspace; 54314cf11afSPaul Mackerras 5441beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n"); 54514cf11afSPaul Mackerras 54614cf11afSPaul Mackerras /* Allocate fixups array */ 547ea96025aSAnton Vorontsov mpic->fixups = kzalloc(128 * sizeof(*mpic->fixups), GFP_KERNEL); 54814cf11afSPaul Mackerras BUG_ON(mpic->fixups == NULL); 54914cf11afSPaul Mackerras 55014cf11afSPaul Mackerras /* Init spinlock */ 551203041adSThomas Gleixner raw_spin_lock_init(&mpic->fixup_lock); 55214cf11afSPaul Mackerras 553c4b22f26SSegher Boessenkool /* Map U3 config space. We assume all IO-APICs are on the primary bus 554c4b22f26SSegher Boessenkool * so we only need to map 64kB. 55514cf11afSPaul Mackerras */ 556c4b22f26SSegher Boessenkool cfgspace = ioremap(0xf2000000, 0x10000); 55714cf11afSPaul Mackerras BUG_ON(cfgspace == NULL); 55814cf11afSPaul Mackerras 5591beb6a7dSBenjamin Herrenschmidt /* Now we scan all slots. We do a very quick scan, we read the header 5601beb6a7dSBenjamin Herrenschmidt * type, vendor ID and device ID only, that's plenty enough 56114cf11afSPaul Mackerras */ 562c4b22f26SSegher Boessenkool for (devfn = 0; devfn < 0x100; devfn++) { 56314cf11afSPaul Mackerras u8 __iomem *devbase = cfgspace + (devfn << 8); 56414cf11afSPaul Mackerras u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); 56514cf11afSPaul Mackerras u32 l = readl(devbase + PCI_VENDOR_ID); 5661beb6a7dSBenjamin Herrenschmidt u16 s; 56714cf11afSPaul Mackerras 56814cf11afSPaul Mackerras DBG("devfn %x, l: %x\n", devfn, l); 56914cf11afSPaul Mackerras 57014cf11afSPaul Mackerras /* If no device, skip */ 57114cf11afSPaul Mackerras if (l == 0xffffffff || l == 0x00000000 || 57214cf11afSPaul Mackerras l == 0x0000ffff || l == 0xffff0000) 57314cf11afSPaul Mackerras goto next; 5741beb6a7dSBenjamin Herrenschmidt /* Check if is supports capability lists */ 5751beb6a7dSBenjamin Herrenschmidt s = readw(devbase + PCI_STATUS); 5761beb6a7dSBenjamin Herrenschmidt if (!(s & PCI_STATUS_CAP_LIST)) 5771beb6a7dSBenjamin Herrenschmidt goto next; 57814cf11afSPaul Mackerras 5791beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pic(mpic, devbase, devfn, l); 580812fd1fdSMichael Ellerman mpic_scan_ht_msi(mpic, devbase, devfn); 58114cf11afSPaul Mackerras 58214cf11afSPaul Mackerras next: 58314cf11afSPaul Mackerras /* next device, if function 0 */ 584c4b22f26SSegher Boessenkool if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0) 58514cf11afSPaul Mackerras devfn += 7; 58614cf11afSPaul Mackerras } 58714cf11afSPaul Mackerras } 58814cf11afSPaul Mackerras 5896cfef5b2SMichael Ellerman #else /* CONFIG_MPIC_U3_HT_IRQS */ 5906e99e458SBenjamin Herrenschmidt 5916e99e458SBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 5926e99e458SBenjamin Herrenschmidt { 5936e99e458SBenjamin Herrenschmidt return 0; 5946e99e458SBenjamin Herrenschmidt } 5956e99e458SBenjamin Herrenschmidt 5966e99e458SBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 5976e99e458SBenjamin Herrenschmidt { 5986e99e458SBenjamin Herrenschmidt } 5996e99e458SBenjamin Herrenschmidt 6006cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 60114cf11afSPaul Mackerras 60214cf11afSPaul Mackerras /* Find an mpic associated with a given linux interrupt */ 603d69a78d7STony Breeds static struct mpic *mpic_find(unsigned int irq) 60414cf11afSPaul Mackerras { 6050ebfff14SBenjamin Herrenschmidt if (irq < NUM_ISA_INTERRUPTS) 60614cf11afSPaul Mackerras return NULL; 6070ebfff14SBenjamin Herrenschmidt 608ec775d0eSThomas Gleixner return irq_get_chip_data(irq); 60914cf11afSPaul Mackerras } 61014cf11afSPaul Mackerras 611d69a78d7STony Breeds /* Determine if the linux irq is an IPI */ 6123a2b4f7cSBenjamin Herrenschmidt static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int src) 613d69a78d7STony Breeds { 614d69a78d7STony Breeds return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); 615d69a78d7STony Breeds } 616d69a78d7STony Breeds 617ea94187fSScott Wood /* Determine if the linux irq is a timer */ 6183a2b4f7cSBenjamin Herrenschmidt static unsigned int mpic_is_tm(struct mpic *mpic, unsigned int src) 619ea94187fSScott Wood { 620ea94187fSScott Wood return (src >= mpic->timer_vecs[0] && src <= mpic->timer_vecs[7]); 621ea94187fSScott Wood } 622d69a78d7STony Breeds 62314cf11afSPaul Mackerras /* Convert a cpu mask from logical to physical cpu numbers. */ 62414cf11afSPaul Mackerras static inline u32 mpic_physmask(u32 cpumask) 62514cf11afSPaul Mackerras { 62614cf11afSPaul Mackerras int i; 62714cf11afSPaul Mackerras u32 mask = 0; 62814cf11afSPaul Mackerras 629ebc04215SMilton Miller for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1) 63014cf11afSPaul Mackerras mask |= (cpumask & 1) << get_hard_smp_processor_id(i); 63114cf11afSPaul Mackerras return mask; 63214cf11afSPaul Mackerras } 63314cf11afSPaul Mackerras 63414cf11afSPaul Mackerras #ifdef CONFIG_SMP 63514cf11afSPaul Mackerras /* Get the mpic structure from the IPI number */ 636835c0553SLennert Buytenhek static inline struct mpic * mpic_from_ipi(struct irq_data *d) 63714cf11afSPaul Mackerras { 638835c0553SLennert Buytenhek return irq_data_get_irq_chip_data(d); 63914cf11afSPaul Mackerras } 64014cf11afSPaul Mackerras #endif 64114cf11afSPaul Mackerras 64214cf11afSPaul Mackerras /* Get the mpic structure from the irq number */ 64314cf11afSPaul Mackerras static inline struct mpic * mpic_from_irq(unsigned int irq) 64414cf11afSPaul Mackerras { 645ec775d0eSThomas Gleixner return irq_get_chip_data(irq); 646835c0553SLennert Buytenhek } 647835c0553SLennert Buytenhek 648835c0553SLennert Buytenhek /* Get the mpic structure from the irq data */ 649835c0553SLennert Buytenhek static inline struct mpic * mpic_from_irq_data(struct irq_data *d) 650835c0553SLennert Buytenhek { 651835c0553SLennert Buytenhek return irq_data_get_irq_chip_data(d); 65214cf11afSPaul Mackerras } 65314cf11afSPaul Mackerras 65414cf11afSPaul Mackerras /* Send an EOI */ 65514cf11afSPaul Mackerras static inline void mpic_eoi(struct mpic *mpic) 65614cf11afSPaul Mackerras { 6577233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_EOI), 0); 65814cf11afSPaul Mackerras } 65914cf11afSPaul Mackerras 66014cf11afSPaul Mackerras /* 66114cf11afSPaul Mackerras * Linux descriptor level callbacks 66214cf11afSPaul Mackerras */ 66314cf11afSPaul Mackerras 66414cf11afSPaul Mackerras 665835c0553SLennert Buytenhek void mpic_unmask_irq(struct irq_data *d) 66614cf11afSPaul Mackerras { 66714cf11afSPaul Mackerras unsigned int loops = 100000; 668835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 669476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 67014cf11afSPaul Mackerras 671835c0553SLennert Buytenhek DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->irq, src); 67214cf11afSPaul Mackerras 6737233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 6747233593bSZang Roy-r61911 mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & 675e5356640SBenjamin Herrenschmidt ~MPIC_VECPRI_MASK); 67614cf11afSPaul Mackerras /* make sure mask gets to controller before we return to user */ 67714cf11afSPaul Mackerras do { 67814cf11afSPaul Mackerras if (!loops--) { 6798bfc5e36SScott Wood printk(KERN_ERR "%s: timeout on hwirq %u\n", 6808bfc5e36SScott Wood __func__, src); 68114cf11afSPaul Mackerras break; 68214cf11afSPaul Mackerras } 6837233593bSZang Roy-r61911 } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK); 6841beb6a7dSBenjamin Herrenschmidt } 6851beb6a7dSBenjamin Herrenschmidt 686835c0553SLennert Buytenhek void mpic_mask_irq(struct irq_data *d) 68714cf11afSPaul Mackerras { 68814cf11afSPaul Mackerras unsigned int loops = 100000; 689835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 690476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 69114cf11afSPaul Mackerras 692835c0553SLennert Buytenhek DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src); 69314cf11afSPaul Mackerras 6947233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 6957233593bSZang Roy-r61911 mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) | 696e5356640SBenjamin Herrenschmidt MPIC_VECPRI_MASK); 69714cf11afSPaul Mackerras 69814cf11afSPaul Mackerras /* make sure mask gets to controller before we return to user */ 69914cf11afSPaul Mackerras do { 70014cf11afSPaul Mackerras if (!loops--) { 7018bfc5e36SScott Wood printk(KERN_ERR "%s: timeout on hwirq %u\n", 7028bfc5e36SScott Wood __func__, src); 70314cf11afSPaul Mackerras break; 70414cf11afSPaul Mackerras } 7057233593bSZang Roy-r61911 } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK)); 70614cf11afSPaul Mackerras } 70714cf11afSPaul Mackerras 708835c0553SLennert Buytenhek void mpic_end_irq(struct irq_data *d) 70914cf11afSPaul Mackerras { 710835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 71114cf11afSPaul Mackerras 7121beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_IRQ 713835c0553SLennert Buytenhek DBG("%s: end_irq: %d\n", mpic->name, d->irq); 7141beb6a7dSBenjamin Herrenschmidt #endif 71514cf11afSPaul Mackerras /* We always EOI on end_irq() even for edge interrupts since that 71614cf11afSPaul Mackerras * should only lower the priority, the MPIC should have properly 71714cf11afSPaul Mackerras * latched another edge interrupt coming in anyway 71814cf11afSPaul Mackerras */ 71914cf11afSPaul Mackerras 72014cf11afSPaul Mackerras mpic_eoi(mpic); 72114cf11afSPaul Mackerras } 72214cf11afSPaul Mackerras 7236cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 724b9e5b4e6SBenjamin Herrenschmidt 725835c0553SLennert Buytenhek static void mpic_unmask_ht_irq(struct irq_data *d) 726b9e5b4e6SBenjamin Herrenschmidt { 727835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 728476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 729b9e5b4e6SBenjamin Herrenschmidt 730835c0553SLennert Buytenhek mpic_unmask_irq(d); 731b9e5b4e6SBenjamin Herrenschmidt 73224a3f2e8SThomas Gleixner if (irqd_is_level_type(d)) 733b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 734b9e5b4e6SBenjamin Herrenschmidt } 735b9e5b4e6SBenjamin Herrenschmidt 736835c0553SLennert Buytenhek static unsigned int mpic_startup_ht_irq(struct irq_data *d) 737b9e5b4e6SBenjamin Herrenschmidt { 738835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 739476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 740b9e5b4e6SBenjamin Herrenschmidt 741835c0553SLennert Buytenhek mpic_unmask_irq(d); 74224a3f2e8SThomas Gleixner mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d)); 743b9e5b4e6SBenjamin Herrenschmidt 744b9e5b4e6SBenjamin Herrenschmidt return 0; 745b9e5b4e6SBenjamin Herrenschmidt } 746b9e5b4e6SBenjamin Herrenschmidt 747835c0553SLennert Buytenhek static void mpic_shutdown_ht_irq(struct irq_data *d) 748b9e5b4e6SBenjamin Herrenschmidt { 749835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 750476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 751b9e5b4e6SBenjamin Herrenschmidt 75224a3f2e8SThomas Gleixner mpic_shutdown_ht_interrupt(mpic, src); 753835c0553SLennert Buytenhek mpic_mask_irq(d); 754b9e5b4e6SBenjamin Herrenschmidt } 755b9e5b4e6SBenjamin Herrenschmidt 756835c0553SLennert Buytenhek static void mpic_end_ht_irq(struct irq_data *d) 757b9e5b4e6SBenjamin Herrenschmidt { 758835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 759476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 760b9e5b4e6SBenjamin Herrenschmidt 761b9e5b4e6SBenjamin Herrenschmidt #ifdef DEBUG_IRQ 762835c0553SLennert Buytenhek DBG("%s: end_irq: %d\n", mpic->name, d->irq); 763b9e5b4e6SBenjamin Herrenschmidt #endif 764b9e5b4e6SBenjamin Herrenschmidt /* We always EOI on end_irq() even for edge interrupts since that 765b9e5b4e6SBenjamin Herrenschmidt * should only lower the priority, the MPIC should have properly 766b9e5b4e6SBenjamin Herrenschmidt * latched another edge interrupt coming in anyway 767b9e5b4e6SBenjamin Herrenschmidt */ 768b9e5b4e6SBenjamin Herrenschmidt 76924a3f2e8SThomas Gleixner if (irqd_is_level_type(d)) 770b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 771b9e5b4e6SBenjamin Herrenschmidt mpic_eoi(mpic); 772b9e5b4e6SBenjamin Herrenschmidt } 7736cfef5b2SMichael Ellerman #endif /* !CONFIG_MPIC_U3_HT_IRQS */ 774b9e5b4e6SBenjamin Herrenschmidt 77514cf11afSPaul Mackerras #ifdef CONFIG_SMP 77614cf11afSPaul Mackerras 777835c0553SLennert Buytenhek static void mpic_unmask_ipi(struct irq_data *d) 77814cf11afSPaul Mackerras { 779835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_ipi(d); 780476eb491SGrant Likely unsigned int src = virq_to_hw(d->irq) - mpic->ipi_vecs[0]; 78114cf11afSPaul Mackerras 782835c0553SLennert Buytenhek DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src); 78314cf11afSPaul Mackerras mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); 78414cf11afSPaul Mackerras } 78514cf11afSPaul Mackerras 786835c0553SLennert Buytenhek static void mpic_mask_ipi(struct irq_data *d) 78714cf11afSPaul Mackerras { 78814cf11afSPaul Mackerras /* NEVER disable an IPI... that's just plain wrong! */ 78914cf11afSPaul Mackerras } 79014cf11afSPaul Mackerras 791835c0553SLennert Buytenhek static void mpic_end_ipi(struct irq_data *d) 79214cf11afSPaul Mackerras { 793835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_ipi(d); 79414cf11afSPaul Mackerras 79514cf11afSPaul Mackerras /* 79614cf11afSPaul Mackerras * IPIs are marked IRQ_PER_CPU. This has the side effect of 79714cf11afSPaul Mackerras * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from 79814cf11afSPaul Mackerras * applying to them. We EOI them late to avoid re-entering. 79914cf11afSPaul Mackerras */ 80014cf11afSPaul Mackerras mpic_eoi(mpic); 80114cf11afSPaul Mackerras } 80214cf11afSPaul Mackerras 80314cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 80414cf11afSPaul Mackerras 805ea94187fSScott Wood static void mpic_unmask_tm(struct irq_data *d) 806ea94187fSScott Wood { 807ea94187fSScott Wood struct mpic *mpic = mpic_from_irq_data(d); 808ea94187fSScott Wood unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; 809ea94187fSScott Wood 81077ef4899SDmitry Eremin-Solenikov DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, d->irq, src); 811ea94187fSScott Wood mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK); 812ea94187fSScott Wood mpic_tm_read(src); 813ea94187fSScott Wood } 814ea94187fSScott Wood 815ea94187fSScott Wood static void mpic_mask_tm(struct irq_data *d) 816ea94187fSScott Wood { 817ea94187fSScott Wood struct mpic *mpic = mpic_from_irq_data(d); 818ea94187fSScott Wood unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; 819ea94187fSScott Wood 820ea94187fSScott Wood mpic_tm_write(src, mpic_tm_read(src) | MPIC_VECPRI_MASK); 821ea94187fSScott Wood mpic_tm_read(src); 822ea94187fSScott Wood } 823ea94187fSScott Wood 824835c0553SLennert Buytenhek int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, 825835c0553SLennert Buytenhek bool force) 82614cf11afSPaul Mackerras { 827835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 828476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 82914cf11afSPaul Mackerras 8303c10c9c4SKumar Gala if (mpic->flags & MPIC_SINGLE_DEST_CPU) { 83138e1313fSYang Li int cpuid = irq_choose_cpu(cpumask); 8323c10c9c4SKumar Gala 8333c10c9c4SKumar Gala mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); 8343c10c9c4SKumar Gala } else { 8352a116f3dSMilton Miller u32 mask = cpumask_bits(cpumask)[0]; 83614cf11afSPaul Mackerras 8372a116f3dSMilton Miller mask &= cpumask_bits(cpu_online_mask)[0]; 83814cf11afSPaul Mackerras 8397233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 8402a116f3dSMilton Miller mpic_physmask(mask)); 84114cf11afSPaul Mackerras } 842d5dedd45SYinghai Lu 843dcb615aeSAlexander Gordeev return IRQ_SET_MASK_OK; 8443c10c9c4SKumar Gala } 84514cf11afSPaul Mackerras 8467233593bSZang Roy-r61911 static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) 8470ebfff14SBenjamin Herrenschmidt { 8480ebfff14SBenjamin Herrenschmidt /* Now convert sense value */ 8496e99e458SBenjamin Herrenschmidt switch(type & IRQ_TYPE_SENSE_MASK) { 8500ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_RISING: 8517233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 8527233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 8530ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_FALLING: 8546e99e458SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_BOTH: 8557233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 8567233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 8570ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_HIGH: 8587233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 8597233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 8600ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_LOW: 8610ebfff14SBenjamin Herrenschmidt default: 8627233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 8637233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 8640ebfff14SBenjamin Herrenschmidt } 8656e99e458SBenjamin Herrenschmidt } 8666e99e458SBenjamin Herrenschmidt 867835c0553SLennert Buytenhek int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) 8686e99e458SBenjamin Herrenschmidt { 869835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 870476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 8716e99e458SBenjamin Herrenschmidt unsigned int vecpri, vold, vnew; 8726e99e458SBenjamin Herrenschmidt 87306fe98e6SBenjamin Herrenschmidt DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", 874835c0553SLennert Buytenhek mpic, d->irq, src, flow_type); 8756e99e458SBenjamin Herrenschmidt 8765019609fSKyle Moffett if (src >= mpic->num_sources) 8776e99e458SBenjamin Herrenschmidt return -EINVAL; 8786e99e458SBenjamin Herrenschmidt 879446f6d06SBenjamin Herrenschmidt vold = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 8806e99e458SBenjamin Herrenschmidt 881446f6d06SBenjamin Herrenschmidt /* We don't support "none" type */ 882446f6d06SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_NONE) 883446f6d06SBenjamin Herrenschmidt flow_type = IRQ_TYPE_DEFAULT; 884446f6d06SBenjamin Herrenschmidt 885446f6d06SBenjamin Herrenschmidt /* Default: read HW settings */ 886446f6d06SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_DEFAULT) { 8870215b4aaSPaul Gortmaker int vold_ps; 8880215b4aaSPaul Gortmaker 8890215b4aaSPaul Gortmaker vold_ps = vold & (MPIC_INFO(VECPRI_POLARITY_MASK) | 8900215b4aaSPaul Gortmaker MPIC_INFO(VECPRI_SENSE_MASK)); 8910215b4aaSPaul Gortmaker 8920215b4aaSPaul Gortmaker if (vold_ps == (MPIC_INFO(VECPRI_SENSE_EDGE) | 8930215b4aaSPaul Gortmaker MPIC_INFO(VECPRI_POLARITY_POSITIVE))) 894446f6d06SBenjamin Herrenschmidt flow_type = IRQ_TYPE_EDGE_RISING; 8950215b4aaSPaul Gortmaker else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_EDGE) | 8960215b4aaSPaul Gortmaker MPIC_INFO(VECPRI_POLARITY_NEGATIVE))) 897446f6d06SBenjamin Herrenschmidt flow_type = IRQ_TYPE_EDGE_FALLING; 8980215b4aaSPaul Gortmaker else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_LEVEL) | 8990215b4aaSPaul Gortmaker MPIC_INFO(VECPRI_POLARITY_POSITIVE))) 900446f6d06SBenjamin Herrenschmidt flow_type = IRQ_TYPE_LEVEL_HIGH; 9010215b4aaSPaul Gortmaker else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_LEVEL) | 9020215b4aaSPaul Gortmaker MPIC_INFO(VECPRI_POLARITY_NEGATIVE))) 903446f6d06SBenjamin Herrenschmidt flow_type = IRQ_TYPE_LEVEL_LOW; 9040215b4aaSPaul Gortmaker else 9050215b4aaSPaul Gortmaker WARN_ONCE(1, "mpic: unknown IRQ type %d\n", vold); 906446f6d06SBenjamin Herrenschmidt } 907446f6d06SBenjamin Herrenschmidt 908446f6d06SBenjamin Herrenschmidt /* Apply to irq desc */ 90924a3f2e8SThomas Gleixner irqd_set_trigger_type(d, flow_type); 9106e99e458SBenjamin Herrenschmidt 911446f6d06SBenjamin Herrenschmidt /* Apply to HW */ 9126e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, src)) 9136e99e458SBenjamin Herrenschmidt vecpri = MPIC_VECPRI_POLARITY_POSITIVE | 9146e99e458SBenjamin Herrenschmidt MPIC_VECPRI_SENSE_EDGE; 9156e99e458SBenjamin Herrenschmidt else 9167233593bSZang Roy-r61911 vecpri = mpic_type_to_vecpri(mpic, flow_type); 9176e99e458SBenjamin Herrenschmidt 9187233593bSZang Roy-r61911 vnew = vold & ~(MPIC_INFO(VECPRI_POLARITY_MASK) | 9197233593bSZang Roy-r61911 MPIC_INFO(VECPRI_SENSE_MASK)); 9206e99e458SBenjamin Herrenschmidt vnew |= vecpri; 9216e99e458SBenjamin Herrenschmidt if (vold != vnew) 9227233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); 9236e99e458SBenjamin Herrenschmidt 924e075cd70SJustin P. Mattock return IRQ_SET_MASK_OK_NOCOPY; 9250ebfff14SBenjamin Herrenschmidt } 9260ebfff14SBenjamin Herrenschmidt 92738958dd9SOlof Johansson void mpic_set_vector(unsigned int virq, unsigned int vector) 92838958dd9SOlof Johansson { 92938958dd9SOlof Johansson struct mpic *mpic = mpic_from_irq(virq); 930476eb491SGrant Likely unsigned int src = virq_to_hw(virq); 93138958dd9SOlof Johansson unsigned int vecpri; 93238958dd9SOlof Johansson 93338958dd9SOlof Johansson DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", 93438958dd9SOlof Johansson mpic, virq, src, vector); 93538958dd9SOlof Johansson 9365019609fSKyle Moffett if (src >= mpic->num_sources) 93738958dd9SOlof Johansson return; 93838958dd9SOlof Johansson 93938958dd9SOlof Johansson vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 94038958dd9SOlof Johansson vecpri = vecpri & ~MPIC_INFO(VECPRI_VECTOR_MASK); 94138958dd9SOlof Johansson vecpri |= vector; 94238958dd9SOlof Johansson mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); 94338958dd9SOlof Johansson } 94438958dd9SOlof Johansson 945e51df2c1SAnton Blanchard static void mpic_set_destination(unsigned int virq, unsigned int cpuid) 946dfec2202SMeador Inge { 947dfec2202SMeador Inge struct mpic *mpic = mpic_from_irq(virq); 948476eb491SGrant Likely unsigned int src = virq_to_hw(virq); 949dfec2202SMeador Inge 950dfec2202SMeador Inge DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", 951dfec2202SMeador Inge mpic, virq, src, cpuid); 952dfec2202SMeador Inge 9535019609fSKyle Moffett if (src >= mpic->num_sources) 954dfec2202SMeador Inge return; 955dfec2202SMeador Inge 956dfec2202SMeador Inge mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); 957dfec2202SMeador Inge } 958dfec2202SMeador Inge 959b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_chip = { 960835c0553SLennert Buytenhek .irq_mask = mpic_mask_irq, 961835c0553SLennert Buytenhek .irq_unmask = mpic_unmask_irq, 962835c0553SLennert Buytenhek .irq_eoi = mpic_end_irq, 963835c0553SLennert Buytenhek .irq_set_type = mpic_set_irq_type, 964b9e5b4e6SBenjamin Herrenschmidt }; 965b9e5b4e6SBenjamin Herrenschmidt 966b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_SMP 967b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_ipi_chip = { 968835c0553SLennert Buytenhek .irq_mask = mpic_mask_ipi, 969835c0553SLennert Buytenhek .irq_unmask = mpic_unmask_ipi, 970835c0553SLennert Buytenhek .irq_eoi = mpic_end_ipi, 971b9e5b4e6SBenjamin Herrenschmidt }; 972b9e5b4e6SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 973b9e5b4e6SBenjamin Herrenschmidt 974ea94187fSScott Wood static struct irq_chip mpic_tm_chip = { 975ea94187fSScott Wood .irq_mask = mpic_mask_tm, 976ea94187fSScott Wood .irq_unmask = mpic_unmask_tm, 977ea94187fSScott Wood .irq_eoi = mpic_end_irq, 978ea94187fSScott Wood }; 979ea94187fSScott Wood 9806cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 981b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_ht_chip = { 982835c0553SLennert Buytenhek .irq_startup = mpic_startup_ht_irq, 983835c0553SLennert Buytenhek .irq_shutdown = mpic_shutdown_ht_irq, 984835c0553SLennert Buytenhek .irq_mask = mpic_mask_irq, 985835c0553SLennert Buytenhek .irq_unmask = mpic_unmask_ht_irq, 986835c0553SLennert Buytenhek .irq_eoi = mpic_end_ht_irq, 987835c0553SLennert Buytenhek .irq_set_type = mpic_set_irq_type, 988b9e5b4e6SBenjamin Herrenschmidt }; 9896cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 990b9e5b4e6SBenjamin Herrenschmidt 99114cf11afSPaul Mackerras 992ad3aedfbSMarc Zyngier static int mpic_host_match(struct irq_domain *h, struct device_node *node, 993ad3aedfbSMarc Zyngier enum irq_domain_bus_token bus_token) 9940ebfff14SBenjamin Herrenschmidt { 9950ebfff14SBenjamin Herrenschmidt /* Exact match, unless mpic node is NULL */ 9965d4c9bc7SMarc Zyngier struct device_node *of_node = irq_domain_get_of_node(h); 9975d4c9bc7SMarc Zyngier return of_node == NULL || of_node == node; 9980ebfff14SBenjamin Herrenschmidt } 9990ebfff14SBenjamin Herrenschmidt 1000bae1d8f1SGrant Likely static int mpic_host_map(struct irq_domain *h, unsigned int virq, 10016e99e458SBenjamin Herrenschmidt irq_hw_number_t hw) 10020ebfff14SBenjamin Herrenschmidt { 10030ebfff14SBenjamin Herrenschmidt struct mpic *mpic = h->host_data; 10046e99e458SBenjamin Herrenschmidt struct irq_chip *chip; 10050ebfff14SBenjamin Herrenschmidt 100606fe98e6SBenjamin Herrenschmidt DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw); 10070ebfff14SBenjamin Herrenschmidt 10087df2457dSOlof Johansson if (hw == mpic->spurious_vec) 10090ebfff14SBenjamin Herrenschmidt return -EINVAL; 10105fe0c1f2SBenjamin Herrenschmidt if (mpic->protected && test_bit(hw, mpic->protected)) { 10115fe0c1f2SBenjamin Herrenschmidt pr_warning("mpic: Mapping of source 0x%x failed, " 10125fe0c1f2SBenjamin Herrenschmidt "source protected by firmware !\n",\ 10135fe0c1f2SBenjamin Herrenschmidt (unsigned int)hw); 10145fe0c1f2SBenjamin Herrenschmidt return -EPERM; 10155fe0c1f2SBenjamin Herrenschmidt } 101606fe98e6SBenjamin Herrenschmidt 10170ebfff14SBenjamin Herrenschmidt #ifdef CONFIG_SMP 10187df2457dSOlof Johansson else if (hw >= mpic->ipi_vecs[0]) { 1019be8bec56SKyle Moffett WARN_ON(mpic->flags & MPIC_SECONDARY); 10200ebfff14SBenjamin Herrenschmidt 102106fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping as IPI\n"); 1022ec775d0eSThomas Gleixner irq_set_chip_data(virq, mpic); 1023ec775d0eSThomas Gleixner irq_set_chip_and_handler(virq, &mpic->hc_ipi, 10240ebfff14SBenjamin Herrenschmidt handle_percpu_irq); 10250ebfff14SBenjamin Herrenschmidt return 0; 10260ebfff14SBenjamin Herrenschmidt } 10270ebfff14SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 10280ebfff14SBenjamin Herrenschmidt 1029ea94187fSScott Wood if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) { 1030be8bec56SKyle Moffett WARN_ON(mpic->flags & MPIC_SECONDARY); 1031ea94187fSScott Wood 1032ea94187fSScott Wood DBG("mpic: mapping as timer\n"); 1033ea94187fSScott Wood irq_set_chip_data(virq, mpic); 1034ea94187fSScott Wood irq_set_chip_and_handler(virq, &mpic->hc_tm, 1035ea94187fSScott Wood handle_fasteoi_irq); 1036ea94187fSScott Wood return 0; 1037ea94187fSScott Wood } 1038ea94187fSScott Wood 10390a408164SVarun Sethi if (mpic_map_error_int(mpic, virq, hw)) 10400a408164SVarun Sethi return 0; 10410a408164SVarun Sethi 10425fe0c1f2SBenjamin Herrenschmidt if (hw >= mpic->num_sources) { 10435fe0c1f2SBenjamin Herrenschmidt pr_warning("mpic: Mapping of source 0x%x failed, " 10445fe0c1f2SBenjamin Herrenschmidt "source out of range !\n",\ 10455fe0c1f2SBenjamin Herrenschmidt (unsigned int)hw); 10460ebfff14SBenjamin Herrenschmidt return -EINVAL; 10475fe0c1f2SBenjamin Herrenschmidt } 10480ebfff14SBenjamin Herrenschmidt 1049a7de7c74SMichael Ellerman mpic_msi_reserve_hwirq(mpic, hw); 1050a7de7c74SMichael Ellerman 10516e99e458SBenjamin Herrenschmidt /* Default chip */ 10520ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_irq; 10530ebfff14SBenjamin Herrenschmidt 10546cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 10550ebfff14SBenjamin Herrenschmidt /* Check for HT interrupts, override vecpri */ 10566e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, hw)) 10570ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_ht_irq; 10586cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 10590ebfff14SBenjamin Herrenschmidt 106006fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping to irq chip @%p\n", chip); 10610ebfff14SBenjamin Herrenschmidt 1062ec775d0eSThomas Gleixner irq_set_chip_data(virq, mpic); 1063ec775d0eSThomas Gleixner irq_set_chip_and_handler(virq, chip, handle_fasteoi_irq); 10646e99e458SBenjamin Herrenschmidt 10656e99e458SBenjamin Herrenschmidt /* Set default irq type */ 1066446f6d06SBenjamin Herrenschmidt irq_set_irq_type(virq, IRQ_TYPE_DEFAULT); 10676e99e458SBenjamin Herrenschmidt 1068dfec2202SMeador Inge /* If the MPIC was reset, then all vectors have already been 1069dfec2202SMeador Inge * initialized. Otherwise, a per source lazy initialization 1070dfec2202SMeador Inge * is done here. 1071dfec2202SMeador Inge */ 1072dfec2202SMeador Inge if (!mpic_is_ipi(mpic, hw) && (mpic->flags & MPIC_NO_RESET)) { 107332dda05fSScott Wood int cpu; 107432dda05fSScott Wood 107532dda05fSScott Wood preempt_disable(); 107632dda05fSScott Wood cpu = mpic_processor_id(mpic); 107732dda05fSScott Wood preempt_enable(); 107832dda05fSScott Wood 1079dfec2202SMeador Inge mpic_set_vector(virq, hw); 108032dda05fSScott Wood mpic_set_destination(virq, cpu); 1081dfec2202SMeador Inge mpic_irq_set_priority(virq, 8); 1082dfec2202SMeador Inge } 1083dfec2202SMeador Inge 10840ebfff14SBenjamin Herrenschmidt return 0; 10850ebfff14SBenjamin Herrenschmidt } 10860ebfff14SBenjamin Herrenschmidt 1087bae1d8f1SGrant Likely static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct, 108840d50cf7SRoman Fietze const u32 *intspec, unsigned int intsize, 10890ebfff14SBenjamin Herrenschmidt irq_hw_number_t *out_hwirq, unsigned int *out_flags) 10900ebfff14SBenjamin Herrenschmidt 10910ebfff14SBenjamin Herrenschmidt { 109222d168ceSScott Wood struct mpic *mpic = h->host_data; 10930ebfff14SBenjamin Herrenschmidt static unsigned char map_mpic_senses[4] = { 10940ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_RISING, 10950ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_LOW, 10960ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_HIGH, 10970ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_FALLING, 10980ebfff14SBenjamin Herrenschmidt }; 10990ebfff14SBenjamin Herrenschmidt 11000ebfff14SBenjamin Herrenschmidt *out_hwirq = intspec[0]; 110122d168ceSScott Wood if (intsize >= 4 && (mpic->flags & MPIC_FSL)) { 110222d168ceSScott Wood /* 110322d168ceSScott Wood * Freescale MPIC with extended intspec: 110422d168ceSScott Wood * First two cells are as usual. Third specifies 110522d168ceSScott Wood * an "interrupt type". Fourth is type-specific data. 110622d168ceSScott Wood * 110722d168ceSScott Wood * See Documentation/devicetree/bindings/powerpc/fsl/mpic.txt 110822d168ceSScott Wood */ 110922d168ceSScott Wood switch (intspec[2]) { 111022d168ceSScott Wood case 0: 11110a408164SVarun Sethi break; 11120a408164SVarun Sethi case 1: 11130a408164SVarun Sethi if (!(mpic->flags & MPIC_FSL_HAS_EIMR)) 11140a408164SVarun Sethi break; 11150a408164SVarun Sethi 11160a408164SVarun Sethi if (intspec[3] >= ARRAY_SIZE(mpic->err_int_vecs)) 11170a408164SVarun Sethi return -EINVAL; 11180a408164SVarun Sethi 11190a408164SVarun Sethi *out_hwirq = mpic->err_int_vecs[intspec[3]]; 11200a408164SVarun Sethi 112122d168ceSScott Wood break; 112222d168ceSScott Wood case 2: 112322d168ceSScott Wood if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs)) 112422d168ceSScott Wood return -EINVAL; 112522d168ceSScott Wood 112622d168ceSScott Wood *out_hwirq = mpic->ipi_vecs[intspec[0]]; 112722d168ceSScott Wood break; 112822d168ceSScott Wood case 3: 112922d168ceSScott Wood if (intspec[0] >= ARRAY_SIZE(mpic->timer_vecs)) 113022d168ceSScott Wood return -EINVAL; 113122d168ceSScott Wood 113222d168ceSScott Wood *out_hwirq = mpic->timer_vecs[intspec[0]]; 113322d168ceSScott Wood break; 113422d168ceSScott Wood default: 113522d168ceSScott Wood pr_debug("%s: unknown irq type %u\n", 113622d168ceSScott Wood __func__, intspec[2]); 113722d168ceSScott Wood return -EINVAL; 113822d168ceSScott Wood } 113922d168ceSScott Wood 114022d168ceSScott Wood *out_flags = map_mpic_senses[intspec[1] & 3]; 114122d168ceSScott Wood } else if (intsize > 1) { 114206fe98e6SBenjamin Herrenschmidt u32 mask = 0x3; 114306fe98e6SBenjamin Herrenschmidt 114406fe98e6SBenjamin Herrenschmidt /* Apple invented a new race of encoding on machines with 114506fe98e6SBenjamin Herrenschmidt * an HT APIC. They encode, among others, the index within 114606fe98e6SBenjamin Herrenschmidt * the HT APIC. We don't care about it here since thankfully, 114706fe98e6SBenjamin Herrenschmidt * it appears that they have the APIC already properly 114806fe98e6SBenjamin Herrenschmidt * configured, and thus our current fixup code that reads the 114906fe98e6SBenjamin Herrenschmidt * APIC config works fine. However, we still need to mask out 115006fe98e6SBenjamin Herrenschmidt * bits in the specifier to make sure we only get bit 0 which 115106fe98e6SBenjamin Herrenschmidt * is the level/edge bit (the only sense bit exposed by Apple), 115206fe98e6SBenjamin Herrenschmidt * as their bit 1 means something else. 115306fe98e6SBenjamin Herrenschmidt */ 115406fe98e6SBenjamin Herrenschmidt if (machine_is(powermac)) 115506fe98e6SBenjamin Herrenschmidt mask = 0x1; 115606fe98e6SBenjamin Herrenschmidt *out_flags = map_mpic_senses[intspec[1] & mask]; 115706fe98e6SBenjamin Herrenschmidt } else 11580ebfff14SBenjamin Herrenschmidt *out_flags = IRQ_TYPE_NONE; 11590ebfff14SBenjamin Herrenschmidt 116006fe98e6SBenjamin Herrenschmidt DBG("mpic: xlate (%d cells: 0x%08x 0x%08x) to line 0x%lx sense 0x%x\n", 116106fe98e6SBenjamin Herrenschmidt intsize, intspec[0], intspec[1], *out_hwirq, *out_flags); 116206fe98e6SBenjamin Herrenschmidt 11630ebfff14SBenjamin Herrenschmidt return 0; 11640ebfff14SBenjamin Herrenschmidt } 11650ebfff14SBenjamin Herrenschmidt 116609dc34a9SKyle Moffett /* IRQ handler for a secondary MPIC cascaded from another IRQ controller */ 1167bd0b9ac4SThomas Gleixner static void mpic_cascade(struct irq_desc *desc) 116809dc34a9SKyle Moffett { 116909dc34a9SKyle Moffett struct irq_chip *chip = irq_desc_get_chip(desc); 117009dc34a9SKyle Moffett struct mpic *mpic = irq_desc_get_handler_data(desc); 117109dc34a9SKyle Moffett unsigned int virq; 117209dc34a9SKyle Moffett 117309dc34a9SKyle Moffett BUG_ON(!(mpic->flags & MPIC_SECONDARY)); 117409dc34a9SKyle Moffett 117509dc34a9SKyle Moffett virq = mpic_get_one_irq(mpic); 1176bae1d8f1SGrant Likely if (virq) 117709dc34a9SKyle Moffett generic_handle_irq(virq); 117809dc34a9SKyle Moffett 117909dc34a9SKyle Moffett chip->irq_eoi(&desc->irq_data); 118009dc34a9SKyle Moffett } 118109dc34a9SKyle Moffett 1182202648a6SKrzysztof Kozlowski static const struct irq_domain_ops mpic_host_ops = { 11830ebfff14SBenjamin Herrenschmidt .match = mpic_host_match, 11840ebfff14SBenjamin Herrenschmidt .map = mpic_host_map, 11850ebfff14SBenjamin Herrenschmidt .xlate = mpic_host_xlate, 11860ebfff14SBenjamin Herrenschmidt }; 11870ebfff14SBenjamin Herrenschmidt 118886d37969SHongtao Jia static u32 fsl_mpic_get_version(struct mpic *mpic) 118986d37969SHongtao Jia { 119086d37969SHongtao Jia u32 brr1; 119186d37969SHongtao Jia 119286d37969SHongtao Jia if (!(mpic->flags & MPIC_FSL)) 119386d37969SHongtao Jia return 0; 119486d37969SHongtao Jia 119586d37969SHongtao Jia brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs, 119686d37969SHongtao Jia MPIC_FSL_BRR1); 119786d37969SHongtao Jia 119886d37969SHongtao Jia return brr1 & MPIC_FSL_BRR1_VER; 119986d37969SHongtao Jia } 120086d37969SHongtao Jia 120114cf11afSPaul Mackerras /* 120214cf11afSPaul Mackerras * Exported functions 120314cf11afSPaul Mackerras */ 120414cf11afSPaul Mackerras 1205807d38b7SHongtao Jia u32 fsl_mpic_primary_get_version(void) 1206807d38b7SHongtao Jia { 1207807d38b7SHongtao Jia struct mpic *mpic = mpic_primary; 1208807d38b7SHongtao Jia 1209807d38b7SHongtao Jia if (mpic) 1210807d38b7SHongtao Jia return fsl_mpic_get_version(mpic); 1211807d38b7SHongtao Jia 1212807d38b7SHongtao Jia return 0; 1213807d38b7SHongtao Jia } 1214807d38b7SHongtao Jia 12150ebfff14SBenjamin Herrenschmidt struct mpic * __init mpic_alloc(struct device_node *node, 1216a959ff56SBenjamin Herrenschmidt phys_addr_t phys_addr, 121714cf11afSPaul Mackerras unsigned int flags, 121814cf11afSPaul Mackerras unsigned int isu_size, 121914cf11afSPaul Mackerras unsigned int irq_count, 122014cf11afSPaul Mackerras const char *name) 122114cf11afSPaul Mackerras { 12225bdb6f2eSKyle Moffett int i, psize, intvec_top; 122314cf11afSPaul Mackerras struct mpic *mpic; 1224d9d1063dSJohannes Berg u32 greg_feature; 122514cf11afSPaul Mackerras const char *vers; 12265bdb6f2eSKyle Moffett const u32 *psrc; 1227c1b8d45dSKyle Moffett u32 last_irq; 12287c509ee0SScott Wood u32 fsl_version = 0; 12298bf41568SKyle Moffett 1230996983b7SKyle Moffett /* Default MPIC search parameters */ 1231996983b7SKyle Moffett static const struct of_device_id __initconst mpic_device_id[] = { 1232996983b7SKyle Moffett { .type = "open-pic", }, 1233996983b7SKyle Moffett { .compatible = "open-pic", }, 1234996983b7SKyle Moffett {}, 1235996983b7SKyle Moffett }; 1236996983b7SKyle Moffett 1237996983b7SKyle Moffett /* 1238996983b7SKyle Moffett * If we were not passed a device-tree node, then perform the default 1239996983b7SKyle Moffett * search for standardized a standardized OpenPIC. 1240996983b7SKyle Moffett */ 1241996983b7SKyle Moffett if (node) { 1242996983b7SKyle Moffett node = of_node_get(node); 1243996983b7SKyle Moffett } else { 1244996983b7SKyle Moffett node = of_find_matching_node(NULL, mpic_device_id); 1245996983b7SKyle Moffett if (!node) 1246996983b7SKyle Moffett return NULL; 1247996983b7SKyle Moffett } 12488bf41568SKyle Moffett 12495bdb6f2eSKyle Moffett /* Pick the physical address from the device tree if unspecified */ 12505bdb6f2eSKyle Moffett if (!phys_addr) { 12518bf41568SKyle Moffett /* Check if it is DCR-based */ 1252*1fadfe9eSJulia Lawall if (of_property_read_bool(node, "dcr-reg")) { 12538bf41568SKyle Moffett flags |= MPIC_USES_DCR; 12548bf41568SKyle Moffett } else { 12558bf41568SKyle Moffett struct resource r; 12568bf41568SKyle Moffett if (of_address_to_resource(node, 0, &r)) 1257996983b7SKyle Moffett goto err_of_node_put; 12588bf41568SKyle Moffett phys_addr = r.start; 12598bf41568SKyle Moffett } 12608bf41568SKyle Moffett } 126114cf11afSPaul Mackerras 12623a7a7176SKyle Moffett /* Read extra device-tree properties into the flags variable */ 12633a7a7176SKyle Moffett if (of_get_property(node, "big-endian", NULL)) 12643a7a7176SKyle Moffett flags |= MPIC_BIG_ENDIAN; 12653a7a7176SKyle Moffett if (of_get_property(node, "pic-no-reset", NULL)) 12663a7a7176SKyle Moffett flags |= MPIC_NO_RESET; 12679ca163c8SKyle Moffett if (of_get_property(node, "single-cpu-affinity", NULL)) 12689ca163c8SKyle Moffett flags |= MPIC_SINGLE_DEST_CPU; 12699100d20cSSudeep Holla if (of_device_is_compatible(node, "fsl,mpic")) { 12705a271fe7SVarun Sethi flags |= MPIC_FSL | MPIC_LARGE_VECTORS; 12719100d20cSSudeep Holla mpic_irq_chip.flags |= IRQCHIP_SKIP_SET_WAKE; 12729100d20cSSudeep Holla mpic_tm_chip.flags |= IRQCHIP_SKIP_SET_WAKE; 12739100d20cSSudeep Holla } 12743a7a7176SKyle Moffett 127585355bb2SKumar Gala mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); 127614cf11afSPaul Mackerras if (mpic == NULL) 1277996983b7SKyle Moffett goto err_of_node_put; 127814cf11afSPaul Mackerras 127914cf11afSPaul Mackerras mpic->name = name; 1280c51242e7SKyle Moffett mpic->node = node; 1281e7a98675SKyle Moffett mpic->paddr = phys_addr; 12823a7a7176SKyle Moffett mpic->flags = flags; 128314cf11afSPaul Mackerras 1284b9e5b4e6SBenjamin Herrenschmidt mpic->hc_irq = mpic_irq_chip; 1285b27df672SThomas Gleixner mpic->hc_irq.name = name; 12863a7a7176SKyle Moffett if (!(mpic->flags & MPIC_SECONDARY)) 1287835c0553SLennert Buytenhek mpic->hc_irq.irq_set_affinity = mpic_set_affinity; 12886cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 1289b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq = mpic_irq_ht_chip; 1290b27df672SThomas Gleixner mpic->hc_ht_irq.name = name; 12913a7a7176SKyle Moffett if (!(mpic->flags & MPIC_SECONDARY)) 1292835c0553SLennert Buytenhek mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; 12936cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 1294fbf0274eSBenjamin Herrenschmidt 129514cf11afSPaul Mackerras #ifdef CONFIG_SMP 1296b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ipi = mpic_ipi_chip; 1297b27df672SThomas Gleixner mpic->hc_ipi.name = name; 129814cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 129914cf11afSPaul Mackerras 1300ea94187fSScott Wood mpic->hc_tm = mpic_tm_chip; 1301ea94187fSScott Wood mpic->hc_tm.name = name; 1302ea94187fSScott Wood 130314cf11afSPaul Mackerras mpic->num_sources = 0; /* so far */ 130414cf11afSPaul Mackerras 13053a7a7176SKyle Moffett if (mpic->flags & MPIC_LARGE_VECTORS) 13067df2457dSOlof Johansson intvec_top = 2047; 13077df2457dSOlof Johansson else 13087df2457dSOlof Johansson intvec_top = 255; 13097df2457dSOlof Johansson 1310ea94187fSScott Wood mpic->timer_vecs[0] = intvec_top - 12; 1311ea94187fSScott Wood mpic->timer_vecs[1] = intvec_top - 11; 1312ea94187fSScott Wood mpic->timer_vecs[2] = intvec_top - 10; 1313ea94187fSScott Wood mpic->timer_vecs[3] = intvec_top - 9; 1314ea94187fSScott Wood mpic->timer_vecs[4] = intvec_top - 8; 1315ea94187fSScott Wood mpic->timer_vecs[5] = intvec_top - 7; 1316ea94187fSScott Wood mpic->timer_vecs[6] = intvec_top - 6; 1317ea94187fSScott Wood mpic->timer_vecs[7] = intvec_top - 5; 13187df2457dSOlof Johansson mpic->ipi_vecs[0] = intvec_top - 4; 13197df2457dSOlof Johansson mpic->ipi_vecs[1] = intvec_top - 3; 13207df2457dSOlof Johansson mpic->ipi_vecs[2] = intvec_top - 2; 13217df2457dSOlof Johansson mpic->ipi_vecs[3] = intvec_top - 1; 13227df2457dSOlof Johansson mpic->spurious_vec = intvec_top; 13237df2457dSOlof Johansson 13247fd72186SBenjamin Herrenschmidt /* Look for protected sources */ 1325c51242e7SKyle Moffett psrc = of_get_property(mpic->node, "protected-sources", &psize); 13267fd72186SBenjamin Herrenschmidt if (psrc) { 13275bdb6f2eSKyle Moffett /* Allocate a bitmap with one bit per interrupt */ 13285bdb6f2eSKyle Moffett unsigned int mapsize = BITS_TO_LONGS(intvec_top + 1); 13295bdb6f2eSKyle Moffett mpic->protected = kzalloc(mapsize*sizeof(long), GFP_KERNEL); 13307fd72186SBenjamin Herrenschmidt BUG_ON(mpic->protected == NULL); 13315bdb6f2eSKyle Moffett for (i = 0; i < psize/sizeof(u32); i++) { 13327fd72186SBenjamin Herrenschmidt if (psrc[i] > intvec_top) 13337fd72186SBenjamin Herrenschmidt continue; 13347fd72186SBenjamin Herrenschmidt __set_bit(psrc[i], mpic->protected); 13357fd72186SBenjamin Herrenschmidt } 13367fd72186SBenjamin Herrenschmidt } 1337a959ff56SBenjamin Herrenschmidt 13387233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 13393a7a7176SKyle Moffett mpic->hw_set = mpic_infos[MPIC_GET_REGSET(mpic->flags)]; 13407233593bSZang Roy-r61911 #endif 13417233593bSZang Roy-r61911 1342fbf0274eSBenjamin Herrenschmidt /* default register type */ 13433a7a7176SKyle Moffett if (mpic->flags & MPIC_BIG_ENDIAN) 13448bf41568SKyle Moffett mpic->reg_type = mpic_access_mmio_be; 13458bf41568SKyle Moffett else 13468bf41568SKyle Moffett mpic->reg_type = mpic_access_mmio_le; 1347fbf0274eSBenjamin Herrenschmidt 13488bf41568SKyle Moffett /* 13498bf41568SKyle Moffett * An MPIC with a "dcr-reg" property must be accessed that way, but 13508bf41568SKyle Moffett * only if the kernel includes DCR support. 13518bf41568SKyle Moffett */ 1352fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 13533a7a7176SKyle Moffett if (mpic->flags & MPIC_USES_DCR) 1354fbf0274eSBenjamin Herrenschmidt mpic->reg_type = mpic_access_dcr; 1355fbf0274eSBenjamin Herrenschmidt #else 13563a7a7176SKyle Moffett BUG_ON(mpic->flags & MPIC_USES_DCR); 13578bf41568SKyle Moffett #endif 1358a959ff56SBenjamin Herrenschmidt 135914cf11afSPaul Mackerras /* Map the global registers */ 1360c51242e7SKyle Moffett mpic_map(mpic, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); 1361c51242e7SKyle Moffett mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); 136214cf11afSPaul Mackerras 136303bcb7e3SVarun Sethi if (mpic->flags & MPIC_FSL) { 13640a408164SVarun Sethi int ret; 13650a408164SVarun Sethi 136603bcb7e3SVarun Sethi /* 136703bcb7e3SVarun Sethi * Yes, Freescale really did put global registers in the 136803bcb7e3SVarun Sethi * magic per-cpu area -- and they don't even show up in the 136903bcb7e3SVarun Sethi * non-magic per-cpu copies that this driver normally uses. 137003bcb7e3SVarun Sethi */ 137103bcb7e3SVarun Sethi mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs, 137203bcb7e3SVarun Sethi MPIC_CPU_THISBASE, 0x1000); 13730a408164SVarun Sethi 137486d37969SHongtao Jia fsl_version = fsl_mpic_get_version(mpic); 13750a408164SVarun Sethi 13760a408164SVarun Sethi /* Error interrupt mask register (EIMR) is required for 13770a408164SVarun Sethi * handling individual device error interrupts. EIMR 13780a408164SVarun Sethi * was added in MPIC version 4.1. 13790a408164SVarun Sethi * 13800a408164SVarun Sethi * Over here we reserve vector number space for error 13810a408164SVarun Sethi * interrupt vectors. This space is stolen from the 13820a408164SVarun Sethi * global vector number space, as in case of ipis 13830a408164SVarun Sethi * and timer interrupts. 13840a408164SVarun Sethi * 13850a408164SVarun Sethi * Available vector space = intvec_top - 12, where 12 13860a408164SVarun Sethi * is the number of vectors which have been consumed by 13870a408164SVarun Sethi * ipis and timer interrupts. 13880a408164SVarun Sethi */ 13897c509ee0SScott Wood if (fsl_version >= 0x401) { 13900a408164SVarun Sethi ret = mpic_setup_error_int(mpic, intvec_top - 12); 13910a408164SVarun Sethi if (ret) 13920a408164SVarun Sethi return NULL; 13930a408164SVarun Sethi } 13947c509ee0SScott Wood 13957c509ee0SScott Wood } 13967c509ee0SScott Wood 13977c509ee0SScott Wood /* 13987c509ee0SScott Wood * EPR is only available starting with v4.0. To support 13997c509ee0SScott Wood * platforms that don't know the MPIC version at compile-time, 14007c509ee0SScott Wood * such as qemu-e500, turn off coreint if this MPIC doesn't 14017c509ee0SScott Wood * support it. Note that we never enable it if it wasn't 14027c509ee0SScott Wood * requested in the first place. 14037c509ee0SScott Wood * 14047c509ee0SScott Wood * This is done outside the MPIC_FSL check, so that we 14057c509ee0SScott Wood * also disable coreint if the MPIC node doesn't have 14067c509ee0SScott Wood * an "fsl,mpic" compatible at all. This will be the case 14077c509ee0SScott Wood * with device trees generated by older versions of QEMU. 14087c509ee0SScott Wood * fsl_version will be zero if MPIC_FSL is not set. 14097c509ee0SScott Wood */ 14107c509ee0SScott Wood if (fsl_version < 0x400 && (flags & MPIC_ENABLE_COREINT)) { 14117c509ee0SScott Wood WARN_ON(ppc_md.get_irq != mpic_get_coreint_irq); 14127c509ee0SScott Wood ppc_md.get_irq = mpic_get_irq; 141303bcb7e3SVarun Sethi } 141403bcb7e3SVarun Sethi 141514cf11afSPaul Mackerras /* Reset */ 1416dfec2202SMeador Inge 1417dfec2202SMeador Inge /* When using a device-node, reset requests are only honored if the MPIC 1418dfec2202SMeador Inge * is allowed to reset. 1419dfec2202SMeador Inge */ 1420e55d7f73SKyle Moffett if (!(mpic->flags & MPIC_NO_RESET)) { 1421dfec2202SMeador Inge printk(KERN_DEBUG "mpic: Resetting\n"); 14227233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 14237233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 142414cf11afSPaul Mackerras | MPIC_GREG_GCONF_RESET); 14257233593bSZang Roy-r61911 while( mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 142614cf11afSPaul Mackerras & MPIC_GREG_GCONF_RESET) 142714cf11afSPaul Mackerras mb(); 142814cf11afSPaul Mackerras } 142914cf11afSPaul Mackerras 1430d91e4ea7SKumar Gala /* CoreInt */ 14313a7a7176SKyle Moffett if (mpic->flags & MPIC_ENABLE_COREINT) 1432d91e4ea7SKumar Gala mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1433d91e4ea7SKumar Gala mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1434d91e4ea7SKumar Gala | MPIC_GREG_GCONF_COREINT); 1435d91e4ea7SKumar Gala 14363a7a7176SKyle Moffett if (mpic->flags & MPIC_ENABLE_MCK) 1437f365355eSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1438f365355eSOlof Johansson mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1439f365355eSOlof Johansson | MPIC_GREG_GCONF_MCK); 1440f365355eSOlof Johansson 144114b92470STimur Tabi /* 144214b92470STimur Tabi * The MPIC driver will crash if there are more cores than we 144314b92470STimur Tabi * can initialize, so we may as well catch that problem here. 144414b92470STimur Tabi */ 144514b92470STimur Tabi BUG_ON(num_possible_cpus() > MPIC_MAX_CPUS); 144614b92470STimur Tabi 144714cf11afSPaul Mackerras /* Map the per-CPU registers */ 144814b92470STimur Tabi for_each_possible_cpu(i) { 144914b92470STimur Tabi unsigned int cpu = get_hard_smp_processor_id(i); 145014b92470STimur Tabi 1451c51242e7SKyle Moffett mpic_map(mpic, mpic->paddr, &mpic->cpuregs[cpu], 145214b92470STimur Tabi MPIC_INFO(CPU_BASE) + cpu * MPIC_INFO(CPU_STRIDE), 1453fbf0274eSBenjamin Herrenschmidt 0x1000); 145414cf11afSPaul Mackerras } 145514cf11afSPaul Mackerras 1456c1b8d45dSKyle Moffett /* 1457c1b8d45dSKyle Moffett * Read feature register. For non-ISU MPICs, num sources as well. On 1458c1b8d45dSKyle Moffett * ISU MPICs, sources are counted as ISUs are added 1459c1b8d45dSKyle Moffett */ 1460c1b8d45dSKyle Moffett greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); 1461c1b8d45dSKyle Moffett 1462c1b8d45dSKyle Moffett /* 1463c1b8d45dSKyle Moffett * By default, the last source number comes from the MPIC, but the 1464c1b8d45dSKyle Moffett * device-tree and board support code can override it on buggy hw. 1465fe83364fSBenjamin Herrenschmidt * If we get passed an isu_size (multi-isu MPIC) then we use that 1466fe83364fSBenjamin Herrenschmidt * as a default instead of the value read from the HW. 1467c1b8d45dSKyle Moffett */ 1468c1b8d45dSKyle Moffett last_irq = (greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) 1469c1b8d45dSKyle Moffett >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT; 1470fe83364fSBenjamin Herrenschmidt if (isu_size) 1471fe83364fSBenjamin Herrenschmidt last_irq = isu_size * MPIC_MAX_ISU - 1; 1472c1b8d45dSKyle Moffett of_property_read_u32(mpic->node, "last-interrupt-source", &last_irq); 1473c1b8d45dSKyle Moffett if (irq_count) 1474c1b8d45dSKyle Moffett last_irq = irq_count - 1; 1475c1b8d45dSKyle Moffett 147614cf11afSPaul Mackerras /* Initialize main ISU if none provided */ 1477c1b8d45dSKyle Moffett if (!isu_size) { 1478c1b8d45dSKyle Moffett isu_size = last_irq + 1; 1479c1b8d45dSKyle Moffett mpic->num_sources = isu_size; 1480c51242e7SKyle Moffett mpic_map(mpic, mpic->paddr, &mpic->isus[0], 1481c1b8d45dSKyle Moffett MPIC_INFO(IRQ_BASE), 1482c1b8d45dSKyle Moffett MPIC_INFO(IRQ_STRIDE) * isu_size); 148314cf11afSPaul Mackerras } 1484c1b8d45dSKyle Moffett 1485c1b8d45dSKyle Moffett mpic->isu_size = isu_size; 148614cf11afSPaul Mackerras mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); 148714cf11afSPaul Mackerras mpic->isu_mask = (1 << mpic->isu_shift) - 1; 148814cf11afSPaul Mackerras 1489a8db8cf0SGrant Likely mpic->irqhost = irq_domain_add_linear(mpic->node, 1490574ce79cSBenjamin Herrenschmidt intvec_top, 1491a8db8cf0SGrant Likely &mpic_host_ops, mpic); 1492996983b7SKyle Moffett 1493996983b7SKyle Moffett /* 1494996983b7SKyle Moffett * FIXME: The code leaks the MPIC object and mappings here; this 1495996983b7SKyle Moffett * is very unlikely to fail but it ought to be fixed anyways. 1496996983b7SKyle Moffett */ 149731207dabSKumar Gala if (mpic->irqhost == NULL) 149831207dabSKumar Gala return NULL; 149931207dabSKumar Gala 150014cf11afSPaul Mackerras /* Display version */ 1501d9d1063dSJohannes Berg switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) { 150214cf11afSPaul Mackerras case 1: 150314cf11afSPaul Mackerras vers = "1.0"; 150414cf11afSPaul Mackerras break; 150514cf11afSPaul Mackerras case 2: 150614cf11afSPaul Mackerras vers = "1.2"; 150714cf11afSPaul Mackerras break; 150814cf11afSPaul Mackerras case 3: 150914cf11afSPaul Mackerras vers = "1.3"; 151014cf11afSPaul Mackerras break; 151114cf11afSPaul Mackerras default: 151214cf11afSPaul Mackerras vers = "<unknown>"; 151314cf11afSPaul Mackerras break; 151414cf11afSPaul Mackerras } 1515a959ff56SBenjamin Herrenschmidt printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," 1516a959ff56SBenjamin Herrenschmidt " max %d CPUs\n", 1517e7a98675SKyle Moffett name, vers, (unsigned long long)mpic->paddr, num_possible_cpus()); 1518a959ff56SBenjamin Herrenschmidt printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", 1519a959ff56SBenjamin Herrenschmidt mpic->isu_size, mpic->isu_shift, mpic->isu_mask); 152014cf11afSPaul Mackerras 152114cf11afSPaul Mackerras mpic->next = mpics; 152214cf11afSPaul Mackerras mpics = mpic; 152314cf11afSPaul Mackerras 15243a7a7176SKyle Moffett if (!(mpic->flags & MPIC_SECONDARY)) { 152514cf11afSPaul Mackerras mpic_primary = mpic; 15260ebfff14SBenjamin Herrenschmidt irq_set_default_host(mpic->irqhost); 15270ebfff14SBenjamin Herrenschmidt } 152814cf11afSPaul Mackerras 152914cf11afSPaul Mackerras return mpic; 1530996983b7SKyle Moffett 1531996983b7SKyle Moffett err_of_node_put: 1532996983b7SKyle Moffett of_node_put(node); 1533996983b7SKyle Moffett return NULL; 153414cf11afSPaul Mackerras } 153514cf11afSPaul Mackerras 153614cf11afSPaul Mackerras void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, 1537a959ff56SBenjamin Herrenschmidt phys_addr_t paddr) 153814cf11afSPaul Mackerras { 153914cf11afSPaul Mackerras unsigned int isu_first = isu_num * mpic->isu_size; 154014cf11afSPaul Mackerras 154114cf11afSPaul Mackerras BUG_ON(isu_num >= MPIC_MAX_ISU); 154214cf11afSPaul Mackerras 1543c51242e7SKyle Moffett mpic_map(mpic, 15445a2642f6SBenjamin Herrenschmidt paddr, &mpic->isus[isu_num], 0, 15457233593bSZang Roy-r61911 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); 15465a2642f6SBenjamin Herrenschmidt 154714cf11afSPaul Mackerras if ((isu_first + mpic->isu_size) > mpic->num_sources) 154814cf11afSPaul Mackerras mpic->num_sources = isu_first + mpic->isu_size; 154914cf11afSPaul Mackerras } 155014cf11afSPaul Mackerras 155114cf11afSPaul Mackerras void __init mpic_init(struct mpic *mpic) 155214cf11afSPaul Mackerras { 155309dc34a9SKyle Moffett int i, cpu; 155403bcb7e3SVarun Sethi int num_timers = 4; 155514cf11afSPaul Mackerras 155614cf11afSPaul Mackerras BUG_ON(mpic->num_sources == 0); 155714cf11afSPaul Mackerras 155814cf11afSPaul Mackerras printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); 155914cf11afSPaul Mackerras 156014cf11afSPaul Mackerras /* Set current processor priority to max */ 15617233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 156214cf11afSPaul Mackerras 156303bcb7e3SVarun Sethi if (mpic->flags & MPIC_FSL) { 156486d37969SHongtao Jia u32 version = fsl_mpic_get_version(mpic); 156503bcb7e3SVarun Sethi 156603bcb7e3SVarun Sethi /* 156703bcb7e3SVarun Sethi * Timer group B is present at the latest in MPIC 3.1 (e.g. 156803bcb7e3SVarun Sethi * mpc8536). It is not present in MPIC 2.0 (e.g. mpc8544). 156903bcb7e3SVarun Sethi * I don't know about the status of intermediate versions (or 157003bcb7e3SVarun Sethi * whether they even exist). 157103bcb7e3SVarun Sethi */ 157203bcb7e3SVarun Sethi if (version >= 0x0301) 157303bcb7e3SVarun Sethi num_timers = 8; 157403bcb7e3SVarun Sethi } 157503bcb7e3SVarun Sethi 1576ea94187fSScott Wood /* Initialize timers to our reserved vectors and mask them for now */ 157703bcb7e3SVarun Sethi for (i = 0; i < num_timers; i++) { 157803bcb7e3SVarun Sethi unsigned int offset = mpic_tm_offset(mpic, i); 157903bcb7e3SVarun Sethi 158014cf11afSPaul Mackerras mpic_write(mpic->tmregs, 158103bcb7e3SVarun Sethi offset + MPIC_INFO(TIMER_DESTINATION), 1582ea94187fSScott Wood 1 << hard_smp_processor_id()); 158314cf11afSPaul Mackerras mpic_write(mpic->tmregs, 158403bcb7e3SVarun Sethi offset + MPIC_INFO(TIMER_VECTOR_PRI), 158514cf11afSPaul Mackerras MPIC_VECPRI_MASK | 1586ea94187fSScott Wood (9 << MPIC_VECPRI_PRIORITY_SHIFT) | 15877df2457dSOlof Johansson (mpic->timer_vecs[0] + i)); 158814cf11afSPaul Mackerras } 158914cf11afSPaul Mackerras 159014cf11afSPaul Mackerras /* Initialize IPIs to our reserved vectors and mark them disabled for now */ 159114cf11afSPaul Mackerras mpic_test_broken_ipi(mpic); 159214cf11afSPaul Mackerras for (i = 0; i < 4; i++) { 159314cf11afSPaul Mackerras mpic_ipi_write(i, 159414cf11afSPaul Mackerras MPIC_VECPRI_MASK | 159514cf11afSPaul Mackerras (10 << MPIC_VECPRI_PRIORITY_SHIFT) | 15967df2457dSOlof Johansson (mpic->ipi_vecs[0] + i)); 159714cf11afSPaul Mackerras } 159814cf11afSPaul Mackerras 15991beb6a7dSBenjamin Herrenschmidt /* Do the HT PIC fixups on U3 broken mpic */ 160014cf11afSPaul Mackerras DBG("MPIC flags: %x\n", mpic->flags); 1601be8bec56SKyle Moffett if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) { 16021beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pics(mpic); 160305af7bd2SMichael Ellerman mpic_u3msi_init(mpic); 160405af7bd2SMichael Ellerman } 160514cf11afSPaul Mackerras 160638958dd9SOlof Johansson mpic_pasemi_msi_init(mpic); 160738958dd9SOlof Johansson 1608d6a2639bSMeador Inge cpu = mpic_processor_id(mpic); 1609cc353c30SArnd Bergmann 1610dfec2202SMeador Inge if (!(mpic->flags & MPIC_NO_RESET)) { 161114cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources; i++) { 161214cf11afSPaul Mackerras /* start with vector = source number, and masked */ 16136e99e458SBenjamin Herrenschmidt u32 vecpri = MPIC_VECPRI_MASK | i | 16146e99e458SBenjamin Herrenschmidt (8 << MPIC_VECPRI_PRIORITY_SHIFT); 161514cf11afSPaul Mackerras 16167fd72186SBenjamin Herrenschmidt /* check if protected */ 16177fd72186SBenjamin Herrenschmidt if (mpic->protected && test_bit(i, mpic->protected)) 16187fd72186SBenjamin Herrenschmidt continue; 161914cf11afSPaul Mackerras /* init hw */ 16207233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); 1621cc353c30SArnd Bergmann mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); 162214cf11afSPaul Mackerras } 1623dfec2202SMeador Inge } 162414cf11afSPaul Mackerras 16257df2457dSOlof Johansson /* Init spurious vector */ 16267df2457dSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), mpic->spurious_vec); 162714cf11afSPaul Mackerras 16287233593bSZang Roy-r61911 /* Disable 8259 passthrough, if supported */ 16297233593bSZang Roy-r61911 if (!(mpic->flags & MPIC_NO_PTHROU_DIS)) 16307233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 16317233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 163214cf11afSPaul Mackerras | MPIC_GREG_GCONF_8259_PTHROU_DIS); 163314cf11afSPaul Mackerras 1634d87bf3beSOlof Johansson if (mpic->flags & MPIC_NO_BIAS) 1635d87bf3beSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1636d87bf3beSOlof Johansson mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1637d87bf3beSOlof Johansson | MPIC_GREG_GCONF_NO_BIAS); 1638d87bf3beSOlof Johansson 163914cf11afSPaul Mackerras /* Set current processor priority to 0 */ 16407233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 16413669e930SJohannes Berg 16423669e930SJohannes Berg #ifdef CONFIG_PM 16433669e930SJohannes Berg /* allocate memory to save mpic state */ 1644ea96025aSAnton Vorontsov mpic->save_data = kmalloc(mpic->num_sources * sizeof(*mpic->save_data), 1645ea96025aSAnton Vorontsov GFP_KERNEL); 16463669e930SJohannes Berg BUG_ON(mpic->save_data == NULL); 16473669e930SJohannes Berg #endif 164809dc34a9SKyle Moffett 164909dc34a9SKyle Moffett /* Check if this MPIC is chained from a parent interrupt controller */ 165009dc34a9SKyle Moffett if (mpic->flags & MPIC_SECONDARY) { 165109dc34a9SKyle Moffett int virq = irq_of_parse_and_map(mpic->node, 0); 1652ef24ba70SMichael Ellerman if (virq) { 165309dc34a9SKyle Moffett printk(KERN_INFO "%s: hooking up to IRQ %d\n", 165409dc34a9SKyle Moffett mpic->node->full_name, virq); 165509dc34a9SKyle Moffett irq_set_handler_data(virq, mpic); 165609dc34a9SKyle Moffett irq_set_chained_handler(virq, &mpic_cascade); 165709dc34a9SKyle Moffett } 165809dc34a9SKyle Moffett } 1659aa80581dSScott Wood 1660446957baSAdam Buchbinder /* FSL mpic error interrupt initialization */ 1661aa80581dSScott Wood if (mpic->flags & MPIC_FSL_HAS_EIMR) 1662aa80581dSScott Wood mpic_err_int_init(mpic, MPIC_FSL_ERR_INT); 166314cf11afSPaul Mackerras } 166414cf11afSPaul Mackerras 166514cf11afSPaul Mackerras void mpic_irq_set_priority(unsigned int irq, unsigned int pri) 166614cf11afSPaul Mackerras { 1667d69a78d7STony Breeds struct mpic *mpic = mpic_find(irq); 1668476eb491SGrant Likely unsigned int src = virq_to_hw(irq); 166914cf11afSPaul Mackerras unsigned long flags; 167014cf11afSPaul Mackerras u32 reg; 167114cf11afSPaul Mackerras 167206a901c5SStephen Rothwell if (!mpic) 167306a901c5SStephen Rothwell return; 167406a901c5SStephen Rothwell 1675203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic_lock, flags); 16763a2b4f7cSBenjamin Herrenschmidt if (mpic_is_ipi(mpic, src)) { 16777df2457dSOlof Johansson reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) & 1678e5356640SBenjamin Herrenschmidt ~MPIC_VECPRI_PRIORITY_MASK; 16797df2457dSOlof Johansson mpic_ipi_write(src - mpic->ipi_vecs[0], 168014cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 16813a2b4f7cSBenjamin Herrenschmidt } else if (mpic_is_tm(mpic, src)) { 1682ea94187fSScott Wood reg = mpic_tm_read(src - mpic->timer_vecs[0]) & 1683ea94187fSScott Wood ~MPIC_VECPRI_PRIORITY_MASK; 1684ea94187fSScott Wood mpic_tm_write(src - mpic->timer_vecs[0], 1685ea94187fSScott Wood reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 168614cf11afSPaul Mackerras } else { 16877233593bSZang Roy-r61911 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) 1688e5356640SBenjamin Herrenschmidt & ~MPIC_VECPRI_PRIORITY_MASK; 16897233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 169014cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 169114cf11afSPaul Mackerras } 1692203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic_lock, flags); 169314cf11afSPaul Mackerras } 169414cf11afSPaul Mackerras 169514cf11afSPaul Mackerras void mpic_setup_this_cpu(void) 169614cf11afSPaul Mackerras { 169714cf11afSPaul Mackerras #ifdef CONFIG_SMP 169814cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 169914cf11afSPaul Mackerras unsigned long flags; 170014cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 170114cf11afSPaul Mackerras unsigned int i; 170214cf11afSPaul Mackerras 170314cf11afSPaul Mackerras BUG_ON(mpic == NULL); 170414cf11afSPaul Mackerras 170514cf11afSPaul Mackerras DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 170614cf11afSPaul Mackerras 1707203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic_lock, flags); 170814cf11afSPaul Mackerras 170914cf11afSPaul Mackerras /* let the mpic know we want intrs. default affinity is 0xffffffff 171014cf11afSPaul Mackerras * until changed via /proc. That's how it's done on x86. If we want 171114cf11afSPaul Mackerras * it differently, then we should make sure we also change the default 1712a53da52fSIngo Molnar * values of irq_desc[].affinity in irq.c. 171314cf11afSPaul Mackerras */ 1714e242114aSchenhui zhao if (distribute_irqs && !(mpic->flags & MPIC_SINGLE_DEST_CPU)) { 171514cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources ; i++) 17167233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 17177233593bSZang Roy-r61911 mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) | msk); 171814cf11afSPaul Mackerras } 171914cf11afSPaul Mackerras 172014cf11afSPaul Mackerras /* Set current processor priority to 0 */ 17217233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 172214cf11afSPaul Mackerras 1723203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic_lock, flags); 172414cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 172514cf11afSPaul Mackerras } 172614cf11afSPaul Mackerras 172714cf11afSPaul Mackerras int mpic_cpu_get_priority(void) 172814cf11afSPaul Mackerras { 172914cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 173014cf11afSPaul Mackerras 17317233593bSZang Roy-r61911 return mpic_cpu_read(MPIC_INFO(CPU_CURRENT_TASK_PRI)); 173214cf11afSPaul Mackerras } 173314cf11afSPaul Mackerras 173414cf11afSPaul Mackerras void mpic_cpu_set_priority(int prio) 173514cf11afSPaul Mackerras { 173614cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 173714cf11afSPaul Mackerras 173814cf11afSPaul Mackerras prio &= MPIC_CPU_TASKPRI_MASK; 17397233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), prio); 174014cf11afSPaul Mackerras } 174114cf11afSPaul Mackerras 174214cf11afSPaul Mackerras void mpic_teardown_this_cpu(int secondary) 174314cf11afSPaul Mackerras { 174414cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 174514cf11afSPaul Mackerras unsigned long flags; 174614cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 174714cf11afSPaul Mackerras unsigned int i; 174814cf11afSPaul Mackerras 174914cf11afSPaul Mackerras BUG_ON(mpic == NULL); 175014cf11afSPaul Mackerras 175114cf11afSPaul Mackerras DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 1752203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic_lock, flags); 175314cf11afSPaul Mackerras 175414cf11afSPaul Mackerras /* let the mpic know we don't want intrs. */ 175514cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources ; i++) 17567233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 17577233593bSZang Roy-r61911 mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) & ~msk); 175814cf11afSPaul Mackerras 175914cf11afSPaul Mackerras /* Set current processor priority to max */ 17607233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 17617132799bSValentine Barshak /* We need to EOI the IPI since not all platforms reset the MPIC 17627132799bSValentine Barshak * on boot and new interrupts wouldn't get delivered otherwise. 17637132799bSValentine Barshak */ 17647132799bSValentine Barshak mpic_eoi(mpic); 176514cf11afSPaul Mackerras 1766203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic_lock, flags); 176714cf11afSPaul Mackerras } 176814cf11afSPaul Mackerras 176914cf11afSPaul Mackerras 1770f365355eSOlof Johansson static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg) 177114cf11afSPaul Mackerras { 17720ebfff14SBenjamin Herrenschmidt u32 src; 177314cf11afSPaul Mackerras 1774f365355eSOlof Johansson src = mpic_cpu_read(reg) & MPIC_INFO(VECPRI_VECTOR_MASK); 17751beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_LOW 1776f365355eSOlof Johansson DBG("%s: get_one_irq(reg 0x%x): %d\n", mpic->name, reg, src); 17771beb6a7dSBenjamin Herrenschmidt #endif 17785cddd2e3SJosh Boyer if (unlikely(src == mpic->spurious_vec)) { 17795cddd2e3SJosh Boyer if (mpic->flags & MPIC_SPV_EOI) 17805cddd2e3SJosh Boyer mpic_eoi(mpic); 1781ef24ba70SMichael Ellerman return 0; 17825cddd2e3SJosh Boyer } 17837fd72186SBenjamin Herrenschmidt if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { 178476462232SChristian Dietrich printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n", 17857fd72186SBenjamin Herrenschmidt mpic->name, (int)src); 17867fd72186SBenjamin Herrenschmidt mpic_eoi(mpic); 1787ef24ba70SMichael Ellerman return 0; 17887fd72186SBenjamin Herrenschmidt } 17897fd72186SBenjamin Herrenschmidt 17900ebfff14SBenjamin Herrenschmidt return irq_linear_revmap(mpic->irqhost, src); 179114cf11afSPaul Mackerras } 179214cf11afSPaul Mackerras 1793f365355eSOlof Johansson unsigned int mpic_get_one_irq(struct mpic *mpic) 1794f365355eSOlof Johansson { 1795f365355eSOlof Johansson return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_INTACK)); 1796f365355eSOlof Johansson } 1797f365355eSOlof Johansson 179835a84c2fSOlaf Hering unsigned int mpic_get_irq(void) 179914cf11afSPaul Mackerras { 180014cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 180114cf11afSPaul Mackerras 180214cf11afSPaul Mackerras BUG_ON(mpic == NULL); 180314cf11afSPaul Mackerras 180435a84c2fSOlaf Hering return mpic_get_one_irq(mpic); 180514cf11afSPaul Mackerras } 180614cf11afSPaul Mackerras 1807d91e4ea7SKumar Gala unsigned int mpic_get_coreint_irq(void) 1808d91e4ea7SKumar Gala { 1809d91e4ea7SKumar Gala #ifdef CONFIG_BOOKE 1810d91e4ea7SKumar Gala struct mpic *mpic = mpic_primary; 1811d91e4ea7SKumar Gala u32 src; 1812d91e4ea7SKumar Gala 1813d91e4ea7SKumar Gala BUG_ON(mpic == NULL); 1814d91e4ea7SKumar Gala 1815d91e4ea7SKumar Gala src = mfspr(SPRN_EPR); 1816d91e4ea7SKumar Gala 1817d91e4ea7SKumar Gala if (unlikely(src == mpic->spurious_vec)) { 1818d91e4ea7SKumar Gala if (mpic->flags & MPIC_SPV_EOI) 1819d91e4ea7SKumar Gala mpic_eoi(mpic); 1820ef24ba70SMichael Ellerman return 0; 1821d91e4ea7SKumar Gala } 1822d91e4ea7SKumar Gala if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { 182376462232SChristian Dietrich printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n", 1824d91e4ea7SKumar Gala mpic->name, (int)src); 1825ef24ba70SMichael Ellerman return 0; 1826d91e4ea7SKumar Gala } 1827d91e4ea7SKumar Gala 1828d91e4ea7SKumar Gala return irq_linear_revmap(mpic->irqhost, src); 1829d91e4ea7SKumar Gala #else 1830ef24ba70SMichael Ellerman return 0; 1831d91e4ea7SKumar Gala #endif 1832d91e4ea7SKumar Gala } 1833d91e4ea7SKumar Gala 1834f365355eSOlof Johansson unsigned int mpic_get_mcirq(void) 1835f365355eSOlof Johansson { 1836f365355eSOlof Johansson struct mpic *mpic = mpic_primary; 1837f365355eSOlof Johansson 1838f365355eSOlof Johansson BUG_ON(mpic == NULL); 1839f365355eSOlof Johansson 1840f365355eSOlof Johansson return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_MCACK)); 1841f365355eSOlof Johansson } 184214cf11afSPaul Mackerras 184314cf11afSPaul Mackerras #ifdef CONFIG_SMP 184414cf11afSPaul Mackerras void mpic_request_ipis(void) 184514cf11afSPaul Mackerras { 184614cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 184778608dd3SMilton Miller int i; 184814cf11afSPaul Mackerras BUG_ON(mpic == NULL); 184914cf11afSPaul Mackerras 18500ebfff14SBenjamin Herrenschmidt printk(KERN_INFO "mpic: requesting IPIs...\n"); 185114cf11afSPaul Mackerras 18520ebfff14SBenjamin Herrenschmidt for (i = 0; i < 4; i++) { 18530ebfff14SBenjamin Herrenschmidt unsigned int vipi = irq_create_mapping(mpic->irqhost, 18547df2457dSOlof Johansson mpic->ipi_vecs[0] + i); 1855ef24ba70SMichael Ellerman if (!vipi) { 185678608dd3SMilton Miller printk(KERN_ERR "Failed to map %s\n", smp_ipi_name[i]); 185778608dd3SMilton Miller continue; 18580ebfff14SBenjamin Herrenschmidt } 185978608dd3SMilton Miller smp_request_message_ipi(vipi, i); 18600ebfff14SBenjamin Herrenschmidt } 186114cf11afSPaul Mackerras } 1862a9c59264SPaul Mackerras 18633caba98fSMilton Miller void smp_mpic_message_pass(int cpu, int msg) 18642ef613cbSBenjamin Herrenschmidt { 18652ef613cbSBenjamin Herrenschmidt struct mpic *mpic = mpic_primary; 18663caba98fSMilton Miller u32 physmask; 18672ef613cbSBenjamin Herrenschmidt 18682ef613cbSBenjamin Herrenschmidt BUG_ON(mpic == NULL); 18692ef613cbSBenjamin Herrenschmidt 1870a9c59264SPaul Mackerras /* make sure we're sending something that translates to an IPI */ 1871a9c59264SPaul Mackerras if ((unsigned int)msg > 3) { 1872a9c59264SPaul Mackerras printk("SMP %d: smp_message_pass: unknown msg %d\n", 1873a9c59264SPaul Mackerras smp_processor_id(), msg); 1874a9c59264SPaul Mackerras return; 1875a9c59264SPaul Mackerras } 18763caba98fSMilton Miller 18773caba98fSMilton Miller #ifdef DEBUG_IPI 18783caba98fSMilton Miller DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, msg); 18793caba98fSMilton Miller #endif 18803caba98fSMilton Miller 18813caba98fSMilton Miller physmask = 1 << get_hard_smp_processor_id(cpu); 18823caba98fSMilton Miller 18833caba98fSMilton Miller mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + 18843caba98fSMilton Miller msg * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), physmask); 1885a9c59264SPaul Mackerras } 1886775aeff4SMichael Ellerman 1887a7f4ee1fSMichael Ellerman void __init smp_mpic_probe(void) 1888775aeff4SMichael Ellerman { 1889775aeff4SMichael Ellerman int nr_cpus; 1890775aeff4SMichael Ellerman 1891775aeff4SMichael Ellerman DBG("smp_mpic_probe()...\n"); 1892775aeff4SMichael Ellerman 189353a448c3SEmil Medve nr_cpus = num_possible_cpus(); 1894775aeff4SMichael Ellerman 1895775aeff4SMichael Ellerman DBG("nr_cpus: %d\n", nr_cpus); 1896775aeff4SMichael Ellerman 1897775aeff4SMichael Ellerman if (nr_cpus > 1) 1898775aeff4SMichael Ellerman mpic_request_ipis(); 1899775aeff4SMichael Ellerman } 1900775aeff4SMichael Ellerman 1901cad5cef6SGreg Kroah-Hartman void smp_mpic_setup_cpu(int cpu) 1902775aeff4SMichael Ellerman { 1903775aeff4SMichael Ellerman mpic_setup_this_cpu(); 1904775aeff4SMichael Ellerman } 190566953ebeSMatthew McClintock 190666953ebeSMatthew McClintock void mpic_reset_core(int cpu) 190766953ebeSMatthew McClintock { 190866953ebeSMatthew McClintock struct mpic *mpic = mpic_primary; 190966953ebeSMatthew McClintock u32 pir; 191066953ebeSMatthew McClintock int cpuid = get_hard_smp_processor_id(cpu); 191144f16fcfSMatthew McClintock int i; 191266953ebeSMatthew McClintock 191366953ebeSMatthew McClintock /* Set target bit for core reset */ 191466953ebeSMatthew McClintock pir = mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); 191566953ebeSMatthew McClintock pir |= (1 << cpuid); 191666953ebeSMatthew McClintock mpic_write(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT), pir); 191766953ebeSMatthew McClintock mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); 191866953ebeSMatthew McClintock 191966953ebeSMatthew McClintock /* Restore target bit after reset complete */ 192066953ebeSMatthew McClintock pir &= ~(1 << cpuid); 192166953ebeSMatthew McClintock mpic_write(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT), pir); 192266953ebeSMatthew McClintock mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); 192344f16fcfSMatthew McClintock 192444f16fcfSMatthew McClintock /* Perform 15 EOI on each reset core to clear pending interrupts. 192544f16fcfSMatthew McClintock * This is required for FSL CoreNet based devices */ 192644f16fcfSMatthew McClintock if (mpic->flags & MPIC_FSL) { 192744f16fcfSMatthew McClintock for (i = 0; i < 15; i++) { 192844f16fcfSMatthew McClintock _mpic_write(mpic->reg_type, &mpic->cpuregs[cpuid], 192944f16fcfSMatthew McClintock MPIC_CPU_EOI, 0); 193044f16fcfSMatthew McClintock } 193144f16fcfSMatthew McClintock } 193266953ebeSMatthew McClintock } 193314cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 19343669e930SJohannes Berg 19353669e930SJohannes Berg #ifdef CONFIG_PM 1936f5a592f7SRafael J. Wysocki static void mpic_suspend_one(struct mpic *mpic) 19373669e930SJohannes Berg { 19383669e930SJohannes Berg int i; 19393669e930SJohannes Berg 19403669e930SJohannes Berg for (i = 0; i < mpic->num_sources; i++) { 19413669e930SJohannes Berg mpic->save_data[i].vecprio = 19423669e930SJohannes Berg mpic_irq_read(i, MPIC_INFO(IRQ_VECTOR_PRI)); 19433669e930SJohannes Berg mpic->save_data[i].dest = 19443669e930SJohannes Berg mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); 19453669e930SJohannes Berg } 1946f5a592f7SRafael J. Wysocki } 1947f5a592f7SRafael J. Wysocki 1948f5a592f7SRafael J. Wysocki static int mpic_suspend(void) 1949f5a592f7SRafael J. Wysocki { 1950f5a592f7SRafael J. Wysocki struct mpic *mpic = mpics; 1951f5a592f7SRafael J. Wysocki 1952f5a592f7SRafael J. Wysocki while (mpic) { 1953f5a592f7SRafael J. Wysocki mpic_suspend_one(mpic); 1954f5a592f7SRafael J. Wysocki mpic = mpic->next; 1955f5a592f7SRafael J. Wysocki } 19563669e930SJohannes Berg 19573669e930SJohannes Berg return 0; 19583669e930SJohannes Berg } 19593669e930SJohannes Berg 1960f5a592f7SRafael J. Wysocki static void mpic_resume_one(struct mpic *mpic) 19613669e930SJohannes Berg { 19623669e930SJohannes Berg int i; 19633669e930SJohannes Berg 19643669e930SJohannes Berg for (i = 0; i < mpic->num_sources; i++) { 19653669e930SJohannes Berg mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), 19663669e930SJohannes Berg mpic->save_data[i].vecprio); 19673669e930SJohannes Berg mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 19683669e930SJohannes Berg mpic->save_data[i].dest); 19693669e930SJohannes Berg 19703669e930SJohannes Berg #ifdef CONFIG_MPIC_U3_HT_IRQS 19717c9d9360SAlastair Bridgewater if (mpic->fixups) { 19723669e930SJohannes Berg struct mpic_irq_fixup *fixup = &mpic->fixups[i]; 19733669e930SJohannes Berg 19743669e930SJohannes Berg if (fixup->base) { 19753669e930SJohannes Berg /* we use the lowest bit in an inverted meaning */ 19763669e930SJohannes Berg if ((mpic->save_data[i].fixup_data & 1) == 0) 19773669e930SJohannes Berg continue; 19783669e930SJohannes Berg 19793669e930SJohannes Berg /* Enable and configure */ 19803669e930SJohannes Berg writeb(0x10 + 2 * fixup->index, fixup->base + 2); 19813669e930SJohannes Berg 19823669e930SJohannes Berg writel(mpic->save_data[i].fixup_data & ~1, 19833669e930SJohannes Berg fixup->base + 4); 19843669e930SJohannes Berg } 19853669e930SJohannes Berg } 19863669e930SJohannes Berg #endif 19873669e930SJohannes Berg } /* end for loop */ 19883669e930SJohannes Berg } 19893669e930SJohannes Berg 1990f5a592f7SRafael J. Wysocki static void mpic_resume(void) 1991f5a592f7SRafael J. Wysocki { 1992f5a592f7SRafael J. Wysocki struct mpic *mpic = mpics; 1993f5a592f7SRafael J. Wysocki 1994f5a592f7SRafael J. Wysocki while (mpic) { 1995f5a592f7SRafael J. Wysocki mpic_resume_one(mpic); 1996f5a592f7SRafael J. Wysocki mpic = mpic->next; 1997f5a592f7SRafael J. Wysocki } 1998f5a592f7SRafael J. Wysocki } 1999f5a592f7SRafael J. Wysocki 2000f5a592f7SRafael J. Wysocki static struct syscore_ops mpic_syscore_ops = { 20013669e930SJohannes Berg .resume = mpic_resume, 20023669e930SJohannes Berg .suspend = mpic_suspend, 20033669e930SJohannes Berg }; 20043669e930SJohannes Berg 20053669e930SJohannes Berg static int mpic_init_sys(void) 20063669e930SJohannes Berg { 20074ad5e883SAndrew Donnellan int rc; 20084ad5e883SAndrew Donnellan 2009f5a592f7SRafael J. Wysocki register_syscore_ops(&mpic_syscore_ops); 20104ad5e883SAndrew Donnellan rc = subsys_system_register(&mpic_subsys, NULL); 20114ad5e883SAndrew Donnellan if (rc) { 20124ad5e883SAndrew Donnellan unregister_syscore_ops(&mpic_syscore_ops); 20134ad5e883SAndrew Donnellan pr_err("mpic: Failed to register subsystem!\n"); 20144ad5e883SAndrew Donnellan return rc; 20154ad5e883SAndrew Donnellan } 20169e6f31a9SDongsheng.wang@freescale.com 2017f5a592f7SRafael J. Wysocki return 0; 20183669e930SJohannes Berg } 20193669e930SJohannes Berg 20203669e930SJohannes Berg device_initcall(mpic_init_sys); 2021f5a592f7SRafael J. Wysocki #endif 2022