114cf11afSPaul Mackerras /* 214cf11afSPaul Mackerras * arch/powerpc/kernel/mpic.c 314cf11afSPaul Mackerras * 414cf11afSPaul Mackerras * Driver for interrupt controllers following the OpenPIC standard, the 514cf11afSPaul Mackerras * common implementation beeing IBM's MPIC. This driver also can deal 614cf11afSPaul Mackerras * with various broken implementations of this HW. 714cf11afSPaul Mackerras * 814cf11afSPaul Mackerras * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. 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/bootmem.h> 2814cf11afSPaul Mackerras #include <linux/spinlock.h> 2914cf11afSPaul Mackerras #include <linux/pci.h> 305a0e3ad6STejun Heo #include <linux/slab.h> 31f5a592f7SRafael J. Wysocki #include <linux/syscore_ops.h> 3276462232SChristian Dietrich #include <linux/ratelimit.h> 3314cf11afSPaul Mackerras 3414cf11afSPaul Mackerras #include <asm/ptrace.h> 3514cf11afSPaul Mackerras #include <asm/signal.h> 3614cf11afSPaul Mackerras #include <asm/io.h> 3714cf11afSPaul Mackerras #include <asm/pgtable.h> 3814cf11afSPaul Mackerras #include <asm/irq.h> 3914cf11afSPaul Mackerras #include <asm/machdep.h> 4014cf11afSPaul Mackerras #include <asm/mpic.h> 4114cf11afSPaul Mackerras #include <asm/smp.h> 4214cf11afSPaul Mackerras 43a7de7c74SMichael Ellerman #include "mpic.h" 44a7de7c74SMichael Ellerman 4514cf11afSPaul Mackerras #ifdef DEBUG 4614cf11afSPaul Mackerras #define DBG(fmt...) printk(fmt) 4714cf11afSPaul Mackerras #else 4814cf11afSPaul Mackerras #define DBG(fmt...) 4914cf11afSPaul Mackerras #endif 5014cf11afSPaul Mackerras 519e6f31a9SDongsheng.wang@freescale.com struct bus_type mpic_subsys = { 529e6f31a9SDongsheng.wang@freescale.com .name = "mpic", 539e6f31a9SDongsheng.wang@freescale.com .dev_name = "mpic", 549e6f31a9SDongsheng.wang@freescale.com }; 559e6f31a9SDongsheng.wang@freescale.com EXPORT_SYMBOL_GPL(mpic_subsys); 569e6f31a9SDongsheng.wang@freescale.com 5714cf11afSPaul Mackerras static struct mpic *mpics; 5814cf11afSPaul Mackerras static struct mpic *mpic_primary; 59203041adSThomas Gleixner static DEFINE_RAW_SPINLOCK(mpic_lock); 6014cf11afSPaul Mackerras 61c0c0d996SPaul Mackerras #ifdef CONFIG_PPC32 /* XXX for now */ 62e40c7f02SAndy Whitcroft #ifdef CONFIG_IRQ_ALL_CPUS 63e242114aSchenhui zhao #define distribute_irqs (1) 64e40c7f02SAndy Whitcroft #else 65e40c7f02SAndy Whitcroft #define distribute_irqs (0) 66e40c7f02SAndy Whitcroft #endif 67c0c0d996SPaul Mackerras #endif 6814cf11afSPaul Mackerras 697233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 707233593bSZang Roy-r61911 static u32 mpic_infos[][MPIC_IDX_END] = { 717233593bSZang Roy-r61911 [0] = { /* Original OpenPIC compatible MPIC */ 727233593bSZang Roy-r61911 MPIC_GREG_BASE, 737233593bSZang Roy-r61911 MPIC_GREG_FEATURE_0, 747233593bSZang Roy-r61911 MPIC_GREG_GLOBAL_CONF_0, 757233593bSZang Roy-r61911 MPIC_GREG_VENDOR_ID, 767233593bSZang Roy-r61911 MPIC_GREG_IPI_VECTOR_PRI_0, 777233593bSZang Roy-r61911 MPIC_GREG_IPI_STRIDE, 787233593bSZang Roy-r61911 MPIC_GREG_SPURIOUS, 797233593bSZang Roy-r61911 MPIC_GREG_TIMER_FREQ, 807233593bSZang Roy-r61911 817233593bSZang Roy-r61911 MPIC_TIMER_BASE, 827233593bSZang Roy-r61911 MPIC_TIMER_STRIDE, 837233593bSZang Roy-r61911 MPIC_TIMER_CURRENT_CNT, 847233593bSZang Roy-r61911 MPIC_TIMER_BASE_CNT, 857233593bSZang Roy-r61911 MPIC_TIMER_VECTOR_PRI, 867233593bSZang Roy-r61911 MPIC_TIMER_DESTINATION, 877233593bSZang Roy-r61911 887233593bSZang Roy-r61911 MPIC_CPU_BASE, 897233593bSZang Roy-r61911 MPIC_CPU_STRIDE, 907233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_0, 917233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_STRIDE, 927233593bSZang Roy-r61911 MPIC_CPU_CURRENT_TASK_PRI, 937233593bSZang Roy-r61911 MPIC_CPU_WHOAMI, 947233593bSZang Roy-r61911 MPIC_CPU_INTACK, 957233593bSZang Roy-r61911 MPIC_CPU_EOI, 96f365355eSOlof Johansson MPIC_CPU_MCACK, 977233593bSZang Roy-r61911 987233593bSZang Roy-r61911 MPIC_IRQ_BASE, 997233593bSZang Roy-r61911 MPIC_IRQ_STRIDE, 1007233593bSZang Roy-r61911 MPIC_IRQ_VECTOR_PRI, 1017233593bSZang Roy-r61911 MPIC_VECPRI_VECTOR_MASK, 1027233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_POSITIVE, 1037233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_NEGATIVE, 1047233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_LEVEL, 1057233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_EDGE, 1067233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_MASK, 1077233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_MASK, 1087233593bSZang Roy-r61911 MPIC_IRQ_DESTINATION 1097233593bSZang Roy-r61911 }, 1107233593bSZang Roy-r61911 [1] = { /* Tsi108/109 PIC */ 1117233593bSZang Roy-r61911 TSI108_GREG_BASE, 1127233593bSZang Roy-r61911 TSI108_GREG_FEATURE_0, 1137233593bSZang Roy-r61911 TSI108_GREG_GLOBAL_CONF_0, 1147233593bSZang Roy-r61911 TSI108_GREG_VENDOR_ID, 1157233593bSZang Roy-r61911 TSI108_GREG_IPI_VECTOR_PRI_0, 1167233593bSZang Roy-r61911 TSI108_GREG_IPI_STRIDE, 1177233593bSZang Roy-r61911 TSI108_GREG_SPURIOUS, 1187233593bSZang Roy-r61911 TSI108_GREG_TIMER_FREQ, 1197233593bSZang Roy-r61911 1207233593bSZang Roy-r61911 TSI108_TIMER_BASE, 1217233593bSZang Roy-r61911 TSI108_TIMER_STRIDE, 1227233593bSZang Roy-r61911 TSI108_TIMER_CURRENT_CNT, 1237233593bSZang Roy-r61911 TSI108_TIMER_BASE_CNT, 1247233593bSZang Roy-r61911 TSI108_TIMER_VECTOR_PRI, 1257233593bSZang Roy-r61911 TSI108_TIMER_DESTINATION, 1267233593bSZang Roy-r61911 1277233593bSZang Roy-r61911 TSI108_CPU_BASE, 1287233593bSZang Roy-r61911 TSI108_CPU_STRIDE, 1297233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_0, 1307233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_STRIDE, 1317233593bSZang Roy-r61911 TSI108_CPU_CURRENT_TASK_PRI, 1327233593bSZang Roy-r61911 TSI108_CPU_WHOAMI, 1337233593bSZang Roy-r61911 TSI108_CPU_INTACK, 1347233593bSZang Roy-r61911 TSI108_CPU_EOI, 135f365355eSOlof Johansson TSI108_CPU_MCACK, 1367233593bSZang Roy-r61911 1377233593bSZang Roy-r61911 TSI108_IRQ_BASE, 1387233593bSZang Roy-r61911 TSI108_IRQ_STRIDE, 1397233593bSZang Roy-r61911 TSI108_IRQ_VECTOR_PRI, 1407233593bSZang Roy-r61911 TSI108_VECPRI_VECTOR_MASK, 1417233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_POSITIVE, 1427233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_NEGATIVE, 1437233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_LEVEL, 1447233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_EDGE, 1457233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_MASK, 1467233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_MASK, 1477233593bSZang Roy-r61911 TSI108_IRQ_DESTINATION 1487233593bSZang Roy-r61911 }, 1497233593bSZang Roy-r61911 }; 1507233593bSZang Roy-r61911 1517233593bSZang Roy-r61911 #define MPIC_INFO(name) mpic->hw_set[MPIC_IDX_##name] 1527233593bSZang Roy-r61911 1537233593bSZang Roy-r61911 #else /* CONFIG_MPIC_WEIRD */ 1547233593bSZang Roy-r61911 1557233593bSZang Roy-r61911 #define MPIC_INFO(name) MPIC_##name 1567233593bSZang Roy-r61911 1577233593bSZang Roy-r61911 #endif /* CONFIG_MPIC_WEIRD */ 1587233593bSZang Roy-r61911 159d6a2639bSMeador Inge static inline unsigned int mpic_processor_id(struct mpic *mpic) 160d6a2639bSMeador Inge { 161d6a2639bSMeador Inge unsigned int cpu = 0; 162d6a2639bSMeador Inge 163be8bec56SKyle Moffett if (!(mpic->flags & MPIC_SECONDARY)) 164d6a2639bSMeador Inge cpu = hard_smp_processor_id(); 165d6a2639bSMeador Inge 166d6a2639bSMeador Inge return cpu; 167d6a2639bSMeador Inge } 168d6a2639bSMeador Inge 16914cf11afSPaul Mackerras /* 17014cf11afSPaul Mackerras * Register accessor functions 17114cf11afSPaul Mackerras */ 17214cf11afSPaul Mackerras 17314cf11afSPaul Mackerras 174fbf0274eSBenjamin Herrenschmidt static inline u32 _mpic_read(enum mpic_reg_type type, 175fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, 17614cf11afSPaul Mackerras unsigned int reg) 17714cf11afSPaul Mackerras { 178fbf0274eSBenjamin Herrenschmidt switch(type) { 179fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 180fbf0274eSBenjamin Herrenschmidt case mpic_access_dcr: 18183f34df4SMichael Ellerman return dcr_read(rb->dhost, reg); 182fbf0274eSBenjamin Herrenschmidt #endif 183fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_be: 184fbf0274eSBenjamin Herrenschmidt return in_be32(rb->base + (reg >> 2)); 185fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_le: 186fbf0274eSBenjamin Herrenschmidt default: 187fbf0274eSBenjamin Herrenschmidt return in_le32(rb->base + (reg >> 2)); 188fbf0274eSBenjamin Herrenschmidt } 18914cf11afSPaul Mackerras } 19014cf11afSPaul Mackerras 191fbf0274eSBenjamin Herrenschmidt static inline void _mpic_write(enum mpic_reg_type type, 192fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, 19314cf11afSPaul Mackerras unsigned int reg, u32 value) 19414cf11afSPaul Mackerras { 195fbf0274eSBenjamin Herrenschmidt switch(type) { 196fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 197fbf0274eSBenjamin Herrenschmidt case mpic_access_dcr: 198d9d1063dSJohannes Berg dcr_write(rb->dhost, reg, value); 199d9d1063dSJohannes Berg break; 200fbf0274eSBenjamin Herrenschmidt #endif 201fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_be: 202d9d1063dSJohannes Berg out_be32(rb->base + (reg >> 2), value); 203d9d1063dSJohannes Berg break; 204fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_le: 205fbf0274eSBenjamin Herrenschmidt default: 206d9d1063dSJohannes Berg out_le32(rb->base + (reg >> 2), value); 207d9d1063dSJohannes Berg break; 208fbf0274eSBenjamin Herrenschmidt } 20914cf11afSPaul Mackerras } 21014cf11afSPaul Mackerras 21114cf11afSPaul Mackerras static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) 21214cf11afSPaul Mackerras { 213fbf0274eSBenjamin Herrenschmidt enum mpic_reg_type type = mpic->reg_type; 2147233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 2157233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 21614cf11afSPaul Mackerras 217fbf0274eSBenjamin Herrenschmidt if ((mpic->flags & MPIC_BROKEN_IPI) && type == mpic_access_mmio_le) 218fbf0274eSBenjamin Herrenschmidt type = mpic_access_mmio_be; 219fbf0274eSBenjamin Herrenschmidt return _mpic_read(type, &mpic->gregs, offset); 22014cf11afSPaul Mackerras } 22114cf11afSPaul Mackerras 22214cf11afSPaul Mackerras static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) 22314cf11afSPaul Mackerras { 2247233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 2257233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 22614cf11afSPaul Mackerras 227fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); 22814cf11afSPaul Mackerras } 22914cf11afSPaul Mackerras 23003bcb7e3SVarun Sethi static inline unsigned int mpic_tm_offset(struct mpic *mpic, unsigned int tm) 23103bcb7e3SVarun Sethi { 23203bcb7e3SVarun Sethi return (tm >> 2) * MPIC_TIMER_GROUP_STRIDE + 23303bcb7e3SVarun Sethi (tm & 3) * MPIC_INFO(TIMER_STRIDE); 23403bcb7e3SVarun Sethi } 23503bcb7e3SVarun Sethi 236ea94187fSScott Wood static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm) 237ea94187fSScott Wood { 23803bcb7e3SVarun Sethi unsigned int offset = mpic_tm_offset(mpic, tm) + 23903bcb7e3SVarun Sethi MPIC_INFO(TIMER_VECTOR_PRI); 240ea94187fSScott Wood 241ea94187fSScott Wood return _mpic_read(mpic->reg_type, &mpic->tmregs, offset); 242ea94187fSScott Wood } 243ea94187fSScott Wood 244ea94187fSScott Wood static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value) 245ea94187fSScott Wood { 24603bcb7e3SVarun Sethi unsigned int offset = mpic_tm_offset(mpic, tm) + 24703bcb7e3SVarun Sethi MPIC_INFO(TIMER_VECTOR_PRI); 248ea94187fSScott Wood 249ea94187fSScott Wood _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value); 250ea94187fSScott Wood } 251ea94187fSScott Wood 25214cf11afSPaul Mackerras static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) 25314cf11afSPaul Mackerras { 254d6a2639bSMeador Inge unsigned int cpu = mpic_processor_id(mpic); 25514cf11afSPaul Mackerras 256fbf0274eSBenjamin Herrenschmidt return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg); 25714cf11afSPaul Mackerras } 25814cf11afSPaul Mackerras 25914cf11afSPaul Mackerras static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) 26014cf11afSPaul Mackerras { 261d6a2639bSMeador Inge unsigned int cpu = mpic_processor_id(mpic); 26214cf11afSPaul Mackerras 263fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value); 26414cf11afSPaul Mackerras } 26514cf11afSPaul Mackerras 26614cf11afSPaul Mackerras static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) 26714cf11afSPaul Mackerras { 26814cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 26914cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 27011a6b292SMichael Ellerman unsigned int val; 27114cf11afSPaul Mackerras 27211a6b292SMichael Ellerman val = _mpic_read(mpic->reg_type, &mpic->isus[isu], 27311a6b292SMichael Ellerman reg + (idx * MPIC_INFO(IRQ_STRIDE))); 2740d72ba93SOlof Johansson #ifdef CONFIG_MPIC_BROKEN_REGREAD 2750d72ba93SOlof Johansson if (reg == 0) 27611a6b292SMichael Ellerman val = (val & (MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY)) | 27711a6b292SMichael Ellerman mpic->isu_reg0_shadow[src_no]; 2780d72ba93SOlof Johansson #endif 27911a6b292SMichael Ellerman return val; 28014cf11afSPaul Mackerras } 28114cf11afSPaul Mackerras 28214cf11afSPaul Mackerras static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, 28314cf11afSPaul Mackerras unsigned int reg, u32 value) 28414cf11afSPaul Mackerras { 28514cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 28614cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 28714cf11afSPaul Mackerras 288fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->isus[isu], 2897233593bSZang Roy-r61911 reg + (idx * MPIC_INFO(IRQ_STRIDE)), value); 2900d72ba93SOlof Johansson 2910d72ba93SOlof Johansson #ifdef CONFIG_MPIC_BROKEN_REGREAD 2920d72ba93SOlof Johansson if (reg == 0) 29311a6b292SMichael Ellerman mpic->isu_reg0_shadow[src_no] = 29411a6b292SMichael Ellerman value & ~(MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY); 2950d72ba93SOlof Johansson #endif 29614cf11afSPaul Mackerras } 29714cf11afSPaul Mackerras 298fbf0274eSBenjamin Herrenschmidt #define mpic_read(b,r) _mpic_read(mpic->reg_type,&(b),(r)) 299fbf0274eSBenjamin Herrenschmidt #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) 30014cf11afSPaul Mackerras #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) 30114cf11afSPaul Mackerras #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) 302ea94187fSScott Wood #define mpic_tm_read(i) _mpic_tm_read(mpic,(i)) 303ea94187fSScott Wood #define mpic_tm_write(i,v) _mpic_tm_write(mpic,(i),(v)) 30414cf11afSPaul Mackerras #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) 30514cf11afSPaul Mackerras #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) 30614cf11afSPaul Mackerras #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) 30714cf11afSPaul Mackerras #define mpic_irq_write(s,r,v) _mpic_irq_write(mpic,(s),(r),(v)) 30814cf11afSPaul Mackerras 30914cf11afSPaul Mackerras 31014cf11afSPaul Mackerras /* 31114cf11afSPaul Mackerras * Low level utility functions 31214cf11afSPaul Mackerras */ 31314cf11afSPaul Mackerras 31414cf11afSPaul Mackerras 315c51a3fdcSBecky Bruce static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr, 316fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, unsigned int offset, 317fbf0274eSBenjamin Herrenschmidt unsigned int size) 318fbf0274eSBenjamin Herrenschmidt { 319fbf0274eSBenjamin Herrenschmidt rb->base = ioremap(phys_addr + offset, size); 320fbf0274eSBenjamin Herrenschmidt BUG_ON(rb->base == NULL); 321fbf0274eSBenjamin Herrenschmidt } 322fbf0274eSBenjamin Herrenschmidt 323fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 324c51242e7SKyle Moffett static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb, 325fbf0274eSBenjamin Herrenschmidt unsigned int offset, unsigned int size) 326fbf0274eSBenjamin Herrenschmidt { 327c51242e7SKyle Moffett phys_addr_t phys_addr = dcr_resource_start(mpic->node, 0); 328e62b7601SKyle Moffett rb->dhost = dcr_map(mpic->node, phys_addr + offset, size); 329fbf0274eSBenjamin Herrenschmidt BUG_ON(!DCR_MAP_OK(rb->dhost)); 330fbf0274eSBenjamin Herrenschmidt } 331fbf0274eSBenjamin Herrenschmidt 332c51242e7SKyle Moffett static inline void mpic_map(struct mpic *mpic, 3335a2642f6SBenjamin Herrenschmidt phys_addr_t phys_addr, struct mpic_reg_bank *rb, 3345a2642f6SBenjamin Herrenschmidt unsigned int offset, unsigned int size) 335fbf0274eSBenjamin Herrenschmidt { 336fbf0274eSBenjamin Herrenschmidt if (mpic->flags & MPIC_USES_DCR) 337c51242e7SKyle Moffett _mpic_map_dcr(mpic, rb, offset, size); 338fbf0274eSBenjamin Herrenschmidt else 339fbf0274eSBenjamin Herrenschmidt _mpic_map_mmio(mpic, phys_addr, rb, offset, size); 340fbf0274eSBenjamin Herrenschmidt } 341fbf0274eSBenjamin Herrenschmidt #else /* CONFIG_PPC_DCR */ 342c51242e7SKyle Moffett #define mpic_map(m,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) 343fbf0274eSBenjamin Herrenschmidt #endif /* !CONFIG_PPC_DCR */ 344fbf0274eSBenjamin Herrenschmidt 345fbf0274eSBenjamin Herrenschmidt 34614cf11afSPaul Mackerras 34714cf11afSPaul Mackerras /* Check if we have one of those nice broken MPICs with a flipped endian on 34814cf11afSPaul Mackerras * reads from IPI registers 34914cf11afSPaul Mackerras */ 35014cf11afSPaul Mackerras static void __init mpic_test_broken_ipi(struct mpic *mpic) 35114cf11afSPaul Mackerras { 35214cf11afSPaul Mackerras u32 r; 35314cf11afSPaul Mackerras 3547233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0), MPIC_VECPRI_MASK); 3557233593bSZang Roy-r61911 r = mpic_read(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0)); 35614cf11afSPaul Mackerras 35714cf11afSPaul Mackerras if (r == le32_to_cpu(MPIC_VECPRI_MASK)) { 35814cf11afSPaul Mackerras printk(KERN_INFO "mpic: Detected reversed IPI registers\n"); 35914cf11afSPaul Mackerras mpic->flags |= MPIC_BROKEN_IPI; 36014cf11afSPaul Mackerras } 36114cf11afSPaul Mackerras } 36214cf11afSPaul Mackerras 3636cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 36414cf11afSPaul Mackerras 36514cf11afSPaul Mackerras /* Test if an interrupt is sourced from HyperTransport (used on broken U3s) 36614cf11afSPaul Mackerras * to force the edge setting on the MPIC and do the ack workaround. 36714cf11afSPaul Mackerras */ 3681beb6a7dSBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 36914cf11afSPaul Mackerras { 3701beb6a7dSBenjamin Herrenschmidt if (source >= 128 || !mpic->fixups) 37114cf11afSPaul Mackerras return 0; 3721beb6a7dSBenjamin Herrenschmidt return mpic->fixups[source].base != NULL; 37314cf11afSPaul Mackerras } 37414cf11afSPaul Mackerras 375c4b22f26SSegher Boessenkool 3761beb6a7dSBenjamin Herrenschmidt static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source) 37714cf11afSPaul Mackerras { 3781beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 37914cf11afSPaul Mackerras 3801beb6a7dSBenjamin Herrenschmidt if (fixup->applebase) { 3811beb6a7dSBenjamin Herrenschmidt unsigned int soff = (fixup->index >> 3) & ~3; 3821beb6a7dSBenjamin Herrenschmidt unsigned int mask = 1U << (fixup->index & 0x1f); 3831beb6a7dSBenjamin Herrenschmidt writel(mask, fixup->applebase + soff); 3841beb6a7dSBenjamin Herrenschmidt } else { 385203041adSThomas Gleixner raw_spin_lock(&mpic->fixup_lock); 3861beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * fixup->index, fixup->base + 2); 387c4b22f26SSegher Boessenkool writel(fixup->data, fixup->base + 4); 388203041adSThomas Gleixner raw_spin_unlock(&mpic->fixup_lock); 38914cf11afSPaul Mackerras } 3901beb6a7dSBenjamin Herrenschmidt } 39114cf11afSPaul Mackerras 3921beb6a7dSBenjamin Herrenschmidt static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, 39324a3f2e8SThomas Gleixner bool level) 3941beb6a7dSBenjamin Herrenschmidt { 3951beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 3961beb6a7dSBenjamin Herrenschmidt unsigned long flags; 3971beb6a7dSBenjamin Herrenschmidt u32 tmp; 39814cf11afSPaul Mackerras 3991beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 4001beb6a7dSBenjamin Herrenschmidt return; 4011beb6a7dSBenjamin Herrenschmidt 40224a3f2e8SThomas Gleixner DBG("startup_ht_interrupt(0x%x) index: %d\n", 40324a3f2e8SThomas Gleixner source, fixup->index); 404203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic->fixup_lock, flags); 4051beb6a7dSBenjamin Herrenschmidt /* Enable and configure */ 4061beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 4071beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 4081beb6a7dSBenjamin Herrenschmidt tmp &= ~(0x23U); 40924a3f2e8SThomas Gleixner if (level) 4101beb6a7dSBenjamin Herrenschmidt tmp |= 0x22; 4111beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 412203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags); 4133669e930SJohannes Berg 4143669e930SJohannes Berg #ifdef CONFIG_PM 4153669e930SJohannes Berg /* use the lowest bit inverted to the actual HW, 4163669e930SJohannes Berg * set if this fixup was enabled, clear otherwise */ 4173669e930SJohannes Berg mpic->save_data[source].fixup_data = tmp | 1; 4183669e930SJohannes Berg #endif 4191beb6a7dSBenjamin Herrenschmidt } 4201beb6a7dSBenjamin Herrenschmidt 42124a3f2e8SThomas Gleixner static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source) 4221beb6a7dSBenjamin Herrenschmidt { 4231beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 4241beb6a7dSBenjamin Herrenschmidt unsigned long flags; 4251beb6a7dSBenjamin Herrenschmidt u32 tmp; 4261beb6a7dSBenjamin Herrenschmidt 4271beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 4281beb6a7dSBenjamin Herrenschmidt return; 4291beb6a7dSBenjamin Herrenschmidt 43024a3f2e8SThomas Gleixner DBG("shutdown_ht_interrupt(0x%x)\n", source); 4311beb6a7dSBenjamin Herrenschmidt 4321beb6a7dSBenjamin Herrenschmidt /* Disable */ 433203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic->fixup_lock, flags); 4341beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 4351beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 43672b13819SSegher Boessenkool tmp |= 1; 4371beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 438203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags); 4393669e930SJohannes Berg 4403669e930SJohannes Berg #ifdef CONFIG_PM 4413669e930SJohannes Berg /* use the lowest bit inverted to the actual HW, 4423669e930SJohannes Berg * set if this fixup was enabled, clear otherwise */ 4433669e930SJohannes Berg mpic->save_data[source].fixup_data = tmp & ~1; 4443669e930SJohannes Berg #endif 4451beb6a7dSBenjamin Herrenschmidt } 4461beb6a7dSBenjamin Herrenschmidt 447812fd1fdSMichael Ellerman #ifdef CONFIG_PCI_MSI 448812fd1fdSMichael Ellerman static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, 449812fd1fdSMichael Ellerman unsigned int devfn) 450812fd1fdSMichael Ellerman { 451812fd1fdSMichael Ellerman u8 __iomem *base; 452812fd1fdSMichael Ellerman u8 pos, flags; 453812fd1fdSMichael Ellerman u64 addr = 0; 454812fd1fdSMichael Ellerman 455812fd1fdSMichael Ellerman for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; 456812fd1fdSMichael Ellerman pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { 457812fd1fdSMichael Ellerman u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); 458812fd1fdSMichael Ellerman if (id == PCI_CAP_ID_HT) { 459812fd1fdSMichael Ellerman id = readb(devbase + pos + 3); 460812fd1fdSMichael Ellerman if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_MSI_MAPPING) 461812fd1fdSMichael Ellerman break; 462812fd1fdSMichael Ellerman } 463812fd1fdSMichael Ellerman } 464812fd1fdSMichael Ellerman 465812fd1fdSMichael Ellerman if (pos == 0) 466812fd1fdSMichael Ellerman return; 467812fd1fdSMichael Ellerman 468812fd1fdSMichael Ellerman base = devbase + pos; 469812fd1fdSMichael Ellerman 470812fd1fdSMichael Ellerman flags = readb(base + HT_MSI_FLAGS); 471812fd1fdSMichael Ellerman if (!(flags & HT_MSI_FLAGS_FIXED)) { 472812fd1fdSMichael Ellerman addr = readl(base + HT_MSI_ADDR_LO) & HT_MSI_ADDR_LO_MASK; 473812fd1fdSMichael Ellerman addr = addr | ((u64)readl(base + HT_MSI_ADDR_HI) << 32); 474812fd1fdSMichael Ellerman } 475812fd1fdSMichael Ellerman 476fe333321SIngo Molnar printk(KERN_DEBUG "mpic: - HT:%02x.%x %s MSI mapping found @ 0x%llx\n", 477812fd1fdSMichael Ellerman PCI_SLOT(devfn), PCI_FUNC(devfn), 478812fd1fdSMichael Ellerman flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled", addr); 479812fd1fdSMichael Ellerman 480812fd1fdSMichael Ellerman if (!(flags & HT_MSI_FLAGS_ENABLE)) 481812fd1fdSMichael Ellerman writeb(flags | HT_MSI_FLAGS_ENABLE, base + HT_MSI_FLAGS); 482812fd1fdSMichael Ellerman } 483812fd1fdSMichael Ellerman #else 484812fd1fdSMichael Ellerman static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase, 485812fd1fdSMichael Ellerman unsigned int devfn) 486812fd1fdSMichael Ellerman { 487812fd1fdSMichael Ellerman return; 488812fd1fdSMichael Ellerman } 489812fd1fdSMichael Ellerman #endif 490812fd1fdSMichael Ellerman 4911beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, 4921beb6a7dSBenjamin Herrenschmidt unsigned int devfn, u32 vdid) 49314cf11afSPaul Mackerras { 494c4b22f26SSegher Boessenkool int i, irq, n; 4951beb6a7dSBenjamin Herrenschmidt u8 __iomem *base; 49614cf11afSPaul Mackerras u32 tmp; 497c4b22f26SSegher Boessenkool u8 pos; 49814cf11afSPaul Mackerras 4991beb6a7dSBenjamin Herrenschmidt for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; 5001beb6a7dSBenjamin Herrenschmidt pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { 5011beb6a7dSBenjamin Herrenschmidt u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); 50246ff3463SBrice Goglin if (id == PCI_CAP_ID_HT) { 503c4b22f26SSegher Boessenkool id = readb(devbase + pos + 3); 504beb7cc82SMichael Ellerman if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_IRQ) 505c4b22f26SSegher Boessenkool break; 506c4b22f26SSegher Boessenkool } 507c4b22f26SSegher Boessenkool } 508c4b22f26SSegher Boessenkool if (pos == 0) 509c4b22f26SSegher Boessenkool return; 510c4b22f26SSegher Boessenkool 5111beb6a7dSBenjamin Herrenschmidt base = devbase + pos; 5121beb6a7dSBenjamin Herrenschmidt writeb(0x01, base + 2); 5131beb6a7dSBenjamin Herrenschmidt n = (readl(base + 4) >> 16) & 0xff; 514c4b22f26SSegher Boessenkool 5151beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x" 5161beb6a7dSBenjamin Herrenschmidt " has %d irqs\n", 5171beb6a7dSBenjamin Herrenschmidt devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1); 518c4b22f26SSegher Boessenkool 519c4b22f26SSegher Boessenkool for (i = 0; i <= n; i++) { 5201beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * i, base + 2); 5211beb6a7dSBenjamin Herrenschmidt tmp = readl(base + 4); 52214cf11afSPaul Mackerras irq = (tmp >> 16) & 0xff; 5231beb6a7dSBenjamin Herrenschmidt DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp); 5241beb6a7dSBenjamin Herrenschmidt /* mask it , will be unmasked later */ 5251beb6a7dSBenjamin Herrenschmidt tmp |= 0x1; 5261beb6a7dSBenjamin Herrenschmidt writel(tmp, base + 4); 5271beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].index = i; 5281beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].base = base; 5291beb6a7dSBenjamin Herrenschmidt /* Apple HT PIC has a non-standard way of doing EOIs */ 5301beb6a7dSBenjamin Herrenschmidt if ((vdid & 0xffff) == 0x106b) 5311beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = devbase + 0x60; 5321beb6a7dSBenjamin Herrenschmidt else 5331beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = NULL; 5341beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * i, base + 2); 5351beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].data = readl(base + 4) | 0x80000000; 53614cf11afSPaul Mackerras } 53714cf11afSPaul Mackerras } 53814cf11afSPaul Mackerras 53914cf11afSPaul Mackerras 5401beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 54114cf11afSPaul Mackerras { 54214cf11afSPaul Mackerras unsigned int devfn; 54314cf11afSPaul Mackerras u8 __iomem *cfgspace; 54414cf11afSPaul Mackerras 5451beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n"); 54614cf11afSPaul Mackerras 54714cf11afSPaul Mackerras /* Allocate fixups array */ 548ea96025aSAnton Vorontsov mpic->fixups = kzalloc(128 * sizeof(*mpic->fixups), GFP_KERNEL); 54914cf11afSPaul Mackerras BUG_ON(mpic->fixups == NULL); 55014cf11afSPaul Mackerras 55114cf11afSPaul Mackerras /* Init spinlock */ 552203041adSThomas Gleixner raw_spin_lock_init(&mpic->fixup_lock); 55314cf11afSPaul Mackerras 554c4b22f26SSegher Boessenkool /* Map U3 config space. We assume all IO-APICs are on the primary bus 555c4b22f26SSegher Boessenkool * so we only need to map 64kB. 55614cf11afSPaul Mackerras */ 557c4b22f26SSegher Boessenkool cfgspace = ioremap(0xf2000000, 0x10000); 55814cf11afSPaul Mackerras BUG_ON(cfgspace == NULL); 55914cf11afSPaul Mackerras 5601beb6a7dSBenjamin Herrenschmidt /* Now we scan all slots. We do a very quick scan, we read the header 5611beb6a7dSBenjamin Herrenschmidt * type, vendor ID and device ID only, that's plenty enough 56214cf11afSPaul Mackerras */ 563c4b22f26SSegher Boessenkool for (devfn = 0; devfn < 0x100; devfn++) { 56414cf11afSPaul Mackerras u8 __iomem *devbase = cfgspace + (devfn << 8); 56514cf11afSPaul Mackerras u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); 56614cf11afSPaul Mackerras u32 l = readl(devbase + PCI_VENDOR_ID); 5671beb6a7dSBenjamin Herrenschmidt u16 s; 56814cf11afSPaul Mackerras 56914cf11afSPaul Mackerras DBG("devfn %x, l: %x\n", devfn, l); 57014cf11afSPaul Mackerras 57114cf11afSPaul Mackerras /* If no device, skip */ 57214cf11afSPaul Mackerras if (l == 0xffffffff || l == 0x00000000 || 57314cf11afSPaul Mackerras l == 0x0000ffff || l == 0xffff0000) 57414cf11afSPaul Mackerras goto next; 5751beb6a7dSBenjamin Herrenschmidt /* Check if is supports capability lists */ 5761beb6a7dSBenjamin Herrenschmidt s = readw(devbase + PCI_STATUS); 5771beb6a7dSBenjamin Herrenschmidt if (!(s & PCI_STATUS_CAP_LIST)) 5781beb6a7dSBenjamin Herrenschmidt goto next; 57914cf11afSPaul Mackerras 5801beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pic(mpic, devbase, devfn, l); 581812fd1fdSMichael Ellerman mpic_scan_ht_msi(mpic, devbase, devfn); 58214cf11afSPaul Mackerras 58314cf11afSPaul Mackerras next: 58414cf11afSPaul Mackerras /* next device, if function 0 */ 585c4b22f26SSegher Boessenkool if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0) 58614cf11afSPaul Mackerras devfn += 7; 58714cf11afSPaul Mackerras } 58814cf11afSPaul Mackerras } 58914cf11afSPaul Mackerras 5906cfef5b2SMichael Ellerman #else /* CONFIG_MPIC_U3_HT_IRQS */ 5916e99e458SBenjamin Herrenschmidt 5926e99e458SBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 5936e99e458SBenjamin Herrenschmidt { 5946e99e458SBenjamin Herrenschmidt return 0; 5956e99e458SBenjamin Herrenschmidt } 5966e99e458SBenjamin Herrenschmidt 5976e99e458SBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 5986e99e458SBenjamin Herrenschmidt { 5996e99e458SBenjamin Herrenschmidt } 6006e99e458SBenjamin Herrenschmidt 6016cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 60214cf11afSPaul Mackerras 60314cf11afSPaul Mackerras /* Find an mpic associated with a given linux interrupt */ 604d69a78d7STony Breeds static struct mpic *mpic_find(unsigned int irq) 60514cf11afSPaul Mackerras { 6060ebfff14SBenjamin Herrenschmidt if (irq < NUM_ISA_INTERRUPTS) 60714cf11afSPaul Mackerras return NULL; 6080ebfff14SBenjamin Herrenschmidt 609ec775d0eSThomas Gleixner return irq_get_chip_data(irq); 61014cf11afSPaul Mackerras } 61114cf11afSPaul Mackerras 612d69a78d7STony Breeds /* Determine if the linux irq is an IPI */ 6133a2b4f7cSBenjamin Herrenschmidt static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int src) 614d69a78d7STony Breeds { 615d69a78d7STony Breeds return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); 616d69a78d7STony Breeds } 617d69a78d7STony Breeds 618ea94187fSScott Wood /* Determine if the linux irq is a timer */ 6193a2b4f7cSBenjamin Herrenschmidt static unsigned int mpic_is_tm(struct mpic *mpic, unsigned int src) 620ea94187fSScott Wood { 621ea94187fSScott Wood return (src >= mpic->timer_vecs[0] && src <= mpic->timer_vecs[7]); 622ea94187fSScott Wood } 623d69a78d7STony Breeds 62414cf11afSPaul Mackerras /* Convert a cpu mask from logical to physical cpu numbers. */ 62514cf11afSPaul Mackerras static inline u32 mpic_physmask(u32 cpumask) 62614cf11afSPaul Mackerras { 62714cf11afSPaul Mackerras int i; 62814cf11afSPaul Mackerras u32 mask = 0; 62914cf11afSPaul Mackerras 630ebc04215SMilton Miller for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1) 63114cf11afSPaul Mackerras mask |= (cpumask & 1) << get_hard_smp_processor_id(i); 63214cf11afSPaul Mackerras return mask; 63314cf11afSPaul Mackerras } 63414cf11afSPaul Mackerras 63514cf11afSPaul Mackerras #ifdef CONFIG_SMP 63614cf11afSPaul Mackerras /* Get the mpic structure from the IPI number */ 637835c0553SLennert Buytenhek static inline struct mpic * mpic_from_ipi(struct irq_data *d) 63814cf11afSPaul Mackerras { 639835c0553SLennert Buytenhek return irq_data_get_irq_chip_data(d); 64014cf11afSPaul Mackerras } 64114cf11afSPaul Mackerras #endif 64214cf11afSPaul Mackerras 64314cf11afSPaul Mackerras /* Get the mpic structure from the irq number */ 64414cf11afSPaul Mackerras static inline struct mpic * mpic_from_irq(unsigned int irq) 64514cf11afSPaul Mackerras { 646ec775d0eSThomas Gleixner return irq_get_chip_data(irq); 647835c0553SLennert Buytenhek } 648835c0553SLennert Buytenhek 649835c0553SLennert Buytenhek /* Get the mpic structure from the irq data */ 650835c0553SLennert Buytenhek static inline struct mpic * mpic_from_irq_data(struct irq_data *d) 651835c0553SLennert Buytenhek { 652835c0553SLennert Buytenhek return irq_data_get_irq_chip_data(d); 65314cf11afSPaul Mackerras } 65414cf11afSPaul Mackerras 65514cf11afSPaul Mackerras /* Send an EOI */ 65614cf11afSPaul Mackerras static inline void mpic_eoi(struct mpic *mpic) 65714cf11afSPaul Mackerras { 6587233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_EOI), 0); 6597233593bSZang Roy-r61911 (void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI)); 66014cf11afSPaul Mackerras } 66114cf11afSPaul Mackerras 66214cf11afSPaul Mackerras /* 66314cf11afSPaul Mackerras * Linux descriptor level callbacks 66414cf11afSPaul Mackerras */ 66514cf11afSPaul Mackerras 66614cf11afSPaul Mackerras 667835c0553SLennert Buytenhek void mpic_unmask_irq(struct irq_data *d) 66814cf11afSPaul Mackerras { 66914cf11afSPaul Mackerras unsigned int loops = 100000; 670835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 671476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 67214cf11afSPaul Mackerras 673835c0553SLennert Buytenhek DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->irq, src); 67414cf11afSPaul Mackerras 6757233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 6767233593bSZang Roy-r61911 mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & 677e5356640SBenjamin Herrenschmidt ~MPIC_VECPRI_MASK); 67814cf11afSPaul Mackerras /* make sure mask gets to controller before we return to user */ 67914cf11afSPaul Mackerras do { 68014cf11afSPaul Mackerras if (!loops--) { 6818bfc5e36SScott Wood printk(KERN_ERR "%s: timeout on hwirq %u\n", 6828bfc5e36SScott Wood __func__, src); 68314cf11afSPaul Mackerras break; 68414cf11afSPaul Mackerras } 6857233593bSZang Roy-r61911 } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK); 6861beb6a7dSBenjamin Herrenschmidt } 6871beb6a7dSBenjamin Herrenschmidt 688835c0553SLennert Buytenhek void mpic_mask_irq(struct irq_data *d) 68914cf11afSPaul Mackerras { 69014cf11afSPaul Mackerras unsigned int loops = 100000; 691835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 692476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 69314cf11afSPaul Mackerras 694835c0553SLennert Buytenhek DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src); 69514cf11afSPaul Mackerras 6967233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 6977233593bSZang Roy-r61911 mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) | 698e5356640SBenjamin Herrenschmidt MPIC_VECPRI_MASK); 69914cf11afSPaul Mackerras 70014cf11afSPaul Mackerras /* make sure mask gets to controller before we return to user */ 70114cf11afSPaul Mackerras do { 70214cf11afSPaul Mackerras if (!loops--) { 7038bfc5e36SScott Wood printk(KERN_ERR "%s: timeout on hwirq %u\n", 7048bfc5e36SScott Wood __func__, src); 70514cf11afSPaul Mackerras break; 70614cf11afSPaul Mackerras } 7077233593bSZang Roy-r61911 } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK)); 70814cf11afSPaul Mackerras } 70914cf11afSPaul Mackerras 710835c0553SLennert Buytenhek void mpic_end_irq(struct irq_data *d) 71114cf11afSPaul Mackerras { 712835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 71314cf11afSPaul Mackerras 7141beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_IRQ 715835c0553SLennert Buytenhek DBG("%s: end_irq: %d\n", mpic->name, d->irq); 7161beb6a7dSBenjamin Herrenschmidt #endif 71714cf11afSPaul Mackerras /* We always EOI on end_irq() even for edge interrupts since that 71814cf11afSPaul Mackerras * should only lower the priority, the MPIC should have properly 71914cf11afSPaul Mackerras * latched another edge interrupt coming in anyway 72014cf11afSPaul Mackerras */ 72114cf11afSPaul Mackerras 72214cf11afSPaul Mackerras mpic_eoi(mpic); 72314cf11afSPaul Mackerras } 72414cf11afSPaul Mackerras 7256cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 726b9e5b4e6SBenjamin Herrenschmidt 727835c0553SLennert Buytenhek static void mpic_unmask_ht_irq(struct irq_data *d) 728b9e5b4e6SBenjamin Herrenschmidt { 729835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 730476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 731b9e5b4e6SBenjamin Herrenschmidt 732835c0553SLennert Buytenhek mpic_unmask_irq(d); 733b9e5b4e6SBenjamin Herrenschmidt 73424a3f2e8SThomas Gleixner if (irqd_is_level_type(d)) 735b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 736b9e5b4e6SBenjamin Herrenschmidt } 737b9e5b4e6SBenjamin Herrenschmidt 738835c0553SLennert Buytenhek static unsigned int mpic_startup_ht_irq(struct irq_data *d) 739b9e5b4e6SBenjamin Herrenschmidt { 740835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 741476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 742b9e5b4e6SBenjamin Herrenschmidt 743835c0553SLennert Buytenhek mpic_unmask_irq(d); 74424a3f2e8SThomas Gleixner mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d)); 745b9e5b4e6SBenjamin Herrenschmidt 746b9e5b4e6SBenjamin Herrenschmidt return 0; 747b9e5b4e6SBenjamin Herrenschmidt } 748b9e5b4e6SBenjamin Herrenschmidt 749835c0553SLennert Buytenhek static void mpic_shutdown_ht_irq(struct irq_data *d) 750b9e5b4e6SBenjamin Herrenschmidt { 751835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 752476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 753b9e5b4e6SBenjamin Herrenschmidt 75424a3f2e8SThomas Gleixner mpic_shutdown_ht_interrupt(mpic, src); 755835c0553SLennert Buytenhek mpic_mask_irq(d); 756b9e5b4e6SBenjamin Herrenschmidt } 757b9e5b4e6SBenjamin Herrenschmidt 758835c0553SLennert Buytenhek static void mpic_end_ht_irq(struct irq_data *d) 759b9e5b4e6SBenjamin Herrenschmidt { 760835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 761476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 762b9e5b4e6SBenjamin Herrenschmidt 763b9e5b4e6SBenjamin Herrenschmidt #ifdef DEBUG_IRQ 764835c0553SLennert Buytenhek DBG("%s: end_irq: %d\n", mpic->name, d->irq); 765b9e5b4e6SBenjamin Herrenschmidt #endif 766b9e5b4e6SBenjamin Herrenschmidt /* We always EOI on end_irq() even for edge interrupts since that 767b9e5b4e6SBenjamin Herrenschmidt * should only lower the priority, the MPIC should have properly 768b9e5b4e6SBenjamin Herrenschmidt * latched another edge interrupt coming in anyway 769b9e5b4e6SBenjamin Herrenschmidt */ 770b9e5b4e6SBenjamin Herrenschmidt 77124a3f2e8SThomas Gleixner if (irqd_is_level_type(d)) 772b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 773b9e5b4e6SBenjamin Herrenschmidt mpic_eoi(mpic); 774b9e5b4e6SBenjamin Herrenschmidt } 7756cfef5b2SMichael Ellerman #endif /* !CONFIG_MPIC_U3_HT_IRQS */ 776b9e5b4e6SBenjamin Herrenschmidt 77714cf11afSPaul Mackerras #ifdef CONFIG_SMP 77814cf11afSPaul Mackerras 779835c0553SLennert Buytenhek static void mpic_unmask_ipi(struct irq_data *d) 78014cf11afSPaul Mackerras { 781835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_ipi(d); 782476eb491SGrant Likely unsigned int src = virq_to_hw(d->irq) - mpic->ipi_vecs[0]; 78314cf11afSPaul Mackerras 784835c0553SLennert Buytenhek DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src); 78514cf11afSPaul Mackerras mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); 78614cf11afSPaul Mackerras } 78714cf11afSPaul Mackerras 788835c0553SLennert Buytenhek static void mpic_mask_ipi(struct irq_data *d) 78914cf11afSPaul Mackerras { 79014cf11afSPaul Mackerras /* NEVER disable an IPI... that's just plain wrong! */ 79114cf11afSPaul Mackerras } 79214cf11afSPaul Mackerras 793835c0553SLennert Buytenhek static void mpic_end_ipi(struct irq_data *d) 79414cf11afSPaul Mackerras { 795835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_ipi(d); 79614cf11afSPaul Mackerras 79714cf11afSPaul Mackerras /* 79814cf11afSPaul Mackerras * IPIs are marked IRQ_PER_CPU. This has the side effect of 79914cf11afSPaul Mackerras * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from 80014cf11afSPaul Mackerras * applying to them. We EOI them late to avoid re-entering. 80114cf11afSPaul Mackerras */ 80214cf11afSPaul Mackerras mpic_eoi(mpic); 80314cf11afSPaul Mackerras } 80414cf11afSPaul Mackerras 80514cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 80614cf11afSPaul Mackerras 807ea94187fSScott Wood static void mpic_unmask_tm(struct irq_data *d) 808ea94187fSScott Wood { 809ea94187fSScott Wood struct mpic *mpic = mpic_from_irq_data(d); 810ea94187fSScott Wood unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; 811ea94187fSScott Wood 81277ef4899SDmitry Eremin-Solenikov DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, d->irq, src); 813ea94187fSScott Wood mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK); 814ea94187fSScott Wood mpic_tm_read(src); 815ea94187fSScott Wood } 816ea94187fSScott Wood 817ea94187fSScott Wood static void mpic_mask_tm(struct irq_data *d) 818ea94187fSScott Wood { 819ea94187fSScott Wood struct mpic *mpic = mpic_from_irq_data(d); 820ea94187fSScott Wood unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; 821ea94187fSScott Wood 822ea94187fSScott Wood mpic_tm_write(src, mpic_tm_read(src) | MPIC_VECPRI_MASK); 823ea94187fSScott Wood mpic_tm_read(src); 824ea94187fSScott Wood } 825ea94187fSScott Wood 826835c0553SLennert Buytenhek int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, 827835c0553SLennert Buytenhek bool force) 82814cf11afSPaul Mackerras { 829835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 830476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 83114cf11afSPaul Mackerras 8323c10c9c4SKumar Gala if (mpic->flags & MPIC_SINGLE_DEST_CPU) { 83338e1313fSYang Li int cpuid = irq_choose_cpu(cpumask); 8343c10c9c4SKumar Gala 8353c10c9c4SKumar Gala mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); 8363c10c9c4SKumar Gala } else { 8372a116f3dSMilton Miller u32 mask = cpumask_bits(cpumask)[0]; 83814cf11afSPaul Mackerras 8392a116f3dSMilton Miller mask &= cpumask_bits(cpu_online_mask)[0]; 84014cf11afSPaul Mackerras 8417233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 8422a116f3dSMilton Miller mpic_physmask(mask)); 84314cf11afSPaul Mackerras } 844d5dedd45SYinghai Lu 845dcb615aeSAlexander Gordeev return IRQ_SET_MASK_OK; 8463c10c9c4SKumar Gala } 84714cf11afSPaul Mackerras 8487233593bSZang Roy-r61911 static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) 8490ebfff14SBenjamin Herrenschmidt { 8500ebfff14SBenjamin Herrenschmidt /* Now convert sense value */ 8516e99e458SBenjamin Herrenschmidt switch(type & IRQ_TYPE_SENSE_MASK) { 8520ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_RISING: 8537233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 8547233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 8550ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_FALLING: 8566e99e458SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_BOTH: 8577233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 8587233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 8590ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_HIGH: 8607233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 8617233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 8620ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_LOW: 8630ebfff14SBenjamin Herrenschmidt default: 8647233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 8657233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 8660ebfff14SBenjamin Herrenschmidt } 8676e99e458SBenjamin Herrenschmidt } 8686e99e458SBenjamin Herrenschmidt 869835c0553SLennert Buytenhek int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) 8706e99e458SBenjamin Herrenschmidt { 871835c0553SLennert Buytenhek struct mpic *mpic = mpic_from_irq_data(d); 872476eb491SGrant Likely unsigned int src = irqd_to_hwirq(d); 8736e99e458SBenjamin Herrenschmidt unsigned int vecpri, vold, vnew; 8746e99e458SBenjamin Herrenschmidt 87506fe98e6SBenjamin Herrenschmidt DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", 876835c0553SLennert Buytenhek mpic, d->irq, src, flow_type); 8776e99e458SBenjamin Herrenschmidt 8785019609fSKyle Moffett if (src >= mpic->num_sources) 8796e99e458SBenjamin Herrenschmidt return -EINVAL; 8806e99e458SBenjamin Herrenschmidt 881446f6d06SBenjamin Herrenschmidt vold = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 8826e99e458SBenjamin Herrenschmidt 883446f6d06SBenjamin Herrenschmidt /* We don't support "none" type */ 884446f6d06SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_NONE) 885446f6d06SBenjamin Herrenschmidt flow_type = IRQ_TYPE_DEFAULT; 886446f6d06SBenjamin Herrenschmidt 887446f6d06SBenjamin Herrenschmidt /* Default: read HW settings */ 888446f6d06SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_DEFAULT) { 8890215b4aaSPaul Gortmaker int vold_ps; 8900215b4aaSPaul Gortmaker 8910215b4aaSPaul Gortmaker vold_ps = vold & (MPIC_INFO(VECPRI_POLARITY_MASK) | 8920215b4aaSPaul Gortmaker MPIC_INFO(VECPRI_SENSE_MASK)); 8930215b4aaSPaul Gortmaker 8940215b4aaSPaul Gortmaker if (vold_ps == (MPIC_INFO(VECPRI_SENSE_EDGE) | 8950215b4aaSPaul Gortmaker MPIC_INFO(VECPRI_POLARITY_POSITIVE))) 896446f6d06SBenjamin Herrenschmidt flow_type = IRQ_TYPE_EDGE_RISING; 8970215b4aaSPaul Gortmaker else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_EDGE) | 8980215b4aaSPaul Gortmaker MPIC_INFO(VECPRI_POLARITY_NEGATIVE))) 899446f6d06SBenjamin Herrenschmidt flow_type = IRQ_TYPE_EDGE_FALLING; 9000215b4aaSPaul Gortmaker else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_LEVEL) | 9010215b4aaSPaul Gortmaker MPIC_INFO(VECPRI_POLARITY_POSITIVE))) 902446f6d06SBenjamin Herrenschmidt flow_type = IRQ_TYPE_LEVEL_HIGH; 9030215b4aaSPaul Gortmaker else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_LEVEL) | 9040215b4aaSPaul Gortmaker MPIC_INFO(VECPRI_POLARITY_NEGATIVE))) 905446f6d06SBenjamin Herrenschmidt flow_type = IRQ_TYPE_LEVEL_LOW; 9060215b4aaSPaul Gortmaker else 9070215b4aaSPaul Gortmaker WARN_ONCE(1, "mpic: unknown IRQ type %d\n", vold); 908446f6d06SBenjamin Herrenschmidt } 909446f6d06SBenjamin Herrenschmidt 910446f6d06SBenjamin Herrenschmidt /* Apply to irq desc */ 91124a3f2e8SThomas Gleixner irqd_set_trigger_type(d, flow_type); 9126e99e458SBenjamin Herrenschmidt 913446f6d06SBenjamin Herrenschmidt /* Apply to HW */ 9146e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, src)) 9156e99e458SBenjamin Herrenschmidt vecpri = MPIC_VECPRI_POLARITY_POSITIVE | 9166e99e458SBenjamin Herrenschmidt MPIC_VECPRI_SENSE_EDGE; 9176e99e458SBenjamin Herrenschmidt else 9187233593bSZang Roy-r61911 vecpri = mpic_type_to_vecpri(mpic, flow_type); 9196e99e458SBenjamin Herrenschmidt 9207233593bSZang Roy-r61911 vnew = vold & ~(MPIC_INFO(VECPRI_POLARITY_MASK) | 9217233593bSZang Roy-r61911 MPIC_INFO(VECPRI_SENSE_MASK)); 9226e99e458SBenjamin Herrenschmidt vnew |= vecpri; 9236e99e458SBenjamin Herrenschmidt if (vold != vnew) 9247233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); 9256e99e458SBenjamin Herrenschmidt 926e075cd70SJustin P. Mattock return IRQ_SET_MASK_OK_NOCOPY; 9270ebfff14SBenjamin Herrenschmidt } 9280ebfff14SBenjamin Herrenschmidt 9295ff04b72SDongsheng.wang@freescale.com static int mpic_irq_set_wake(struct irq_data *d, unsigned int on) 9305ff04b72SDongsheng.wang@freescale.com { 9315ff04b72SDongsheng.wang@freescale.com struct irq_desc *desc = container_of(d, struct irq_desc, irq_data); 9325ff04b72SDongsheng.wang@freescale.com struct mpic *mpic = mpic_from_irq_data(d); 9335ff04b72SDongsheng.wang@freescale.com 9345ff04b72SDongsheng.wang@freescale.com if (!(mpic->flags & MPIC_FSL)) 9355ff04b72SDongsheng.wang@freescale.com return -ENXIO; 9365ff04b72SDongsheng.wang@freescale.com 9375ff04b72SDongsheng.wang@freescale.com if (on) 9385ff04b72SDongsheng.wang@freescale.com desc->action->flags |= IRQF_NO_SUSPEND; 9395ff04b72SDongsheng.wang@freescale.com else 9405ff04b72SDongsheng.wang@freescale.com desc->action->flags &= ~IRQF_NO_SUSPEND; 9415ff04b72SDongsheng.wang@freescale.com 9425ff04b72SDongsheng.wang@freescale.com return 0; 9435ff04b72SDongsheng.wang@freescale.com } 9445ff04b72SDongsheng.wang@freescale.com 94538958dd9SOlof Johansson void mpic_set_vector(unsigned int virq, unsigned int vector) 94638958dd9SOlof Johansson { 94738958dd9SOlof Johansson struct mpic *mpic = mpic_from_irq(virq); 948476eb491SGrant Likely unsigned int src = virq_to_hw(virq); 94938958dd9SOlof Johansson unsigned int vecpri; 95038958dd9SOlof Johansson 95138958dd9SOlof Johansson DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", 95238958dd9SOlof Johansson mpic, virq, src, vector); 95338958dd9SOlof Johansson 9545019609fSKyle Moffett if (src >= mpic->num_sources) 95538958dd9SOlof Johansson return; 95638958dd9SOlof Johansson 95738958dd9SOlof Johansson vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 95838958dd9SOlof Johansson vecpri = vecpri & ~MPIC_INFO(VECPRI_VECTOR_MASK); 95938958dd9SOlof Johansson vecpri |= vector; 96038958dd9SOlof Johansson mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); 96138958dd9SOlof Johansson } 96238958dd9SOlof Johansson 963*e51df2c1SAnton Blanchard static void mpic_set_destination(unsigned int virq, unsigned int cpuid) 964dfec2202SMeador Inge { 965dfec2202SMeador Inge struct mpic *mpic = mpic_from_irq(virq); 966476eb491SGrant Likely unsigned int src = virq_to_hw(virq); 967dfec2202SMeador Inge 968dfec2202SMeador Inge DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", 969dfec2202SMeador Inge mpic, virq, src, cpuid); 970dfec2202SMeador Inge 9715019609fSKyle Moffett if (src >= mpic->num_sources) 972dfec2202SMeador Inge return; 973dfec2202SMeador Inge 974dfec2202SMeador Inge mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); 975dfec2202SMeador Inge } 976dfec2202SMeador Inge 977b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_chip = { 978835c0553SLennert Buytenhek .irq_mask = mpic_mask_irq, 979835c0553SLennert Buytenhek .irq_unmask = mpic_unmask_irq, 980835c0553SLennert Buytenhek .irq_eoi = mpic_end_irq, 981835c0553SLennert Buytenhek .irq_set_type = mpic_set_irq_type, 9825ff04b72SDongsheng.wang@freescale.com .irq_set_wake = mpic_irq_set_wake, 983b9e5b4e6SBenjamin Herrenschmidt }; 984b9e5b4e6SBenjamin Herrenschmidt 985b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_SMP 986b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_ipi_chip = { 987835c0553SLennert Buytenhek .irq_mask = mpic_mask_ipi, 988835c0553SLennert Buytenhek .irq_unmask = mpic_unmask_ipi, 989835c0553SLennert Buytenhek .irq_eoi = mpic_end_ipi, 990b9e5b4e6SBenjamin Herrenschmidt }; 991b9e5b4e6SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 992b9e5b4e6SBenjamin Herrenschmidt 993ea94187fSScott Wood static struct irq_chip mpic_tm_chip = { 994ea94187fSScott Wood .irq_mask = mpic_mask_tm, 995ea94187fSScott Wood .irq_unmask = mpic_unmask_tm, 996ea94187fSScott Wood .irq_eoi = mpic_end_irq, 9975ff04b72SDongsheng.wang@freescale.com .irq_set_wake = mpic_irq_set_wake, 998ea94187fSScott Wood }; 999ea94187fSScott Wood 10006cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 1001b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_ht_chip = { 1002835c0553SLennert Buytenhek .irq_startup = mpic_startup_ht_irq, 1003835c0553SLennert Buytenhek .irq_shutdown = mpic_shutdown_ht_irq, 1004835c0553SLennert Buytenhek .irq_mask = mpic_mask_irq, 1005835c0553SLennert Buytenhek .irq_unmask = mpic_unmask_ht_irq, 1006835c0553SLennert Buytenhek .irq_eoi = mpic_end_ht_irq, 1007835c0553SLennert Buytenhek .irq_set_type = mpic_set_irq_type, 1008b9e5b4e6SBenjamin Herrenschmidt }; 10096cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 1010b9e5b4e6SBenjamin Herrenschmidt 101114cf11afSPaul Mackerras 1012bae1d8f1SGrant Likely static int mpic_host_match(struct irq_domain *h, struct device_node *node) 10130ebfff14SBenjamin Herrenschmidt { 10140ebfff14SBenjamin Herrenschmidt /* Exact match, unless mpic node is NULL */ 101552964f87SMichael Ellerman return h->of_node == NULL || h->of_node == node; 10160ebfff14SBenjamin Herrenschmidt } 10170ebfff14SBenjamin Herrenschmidt 1018bae1d8f1SGrant Likely static int mpic_host_map(struct irq_domain *h, unsigned int virq, 10196e99e458SBenjamin Herrenschmidt irq_hw_number_t hw) 10200ebfff14SBenjamin Herrenschmidt { 10210ebfff14SBenjamin Herrenschmidt struct mpic *mpic = h->host_data; 10226e99e458SBenjamin Herrenschmidt struct irq_chip *chip; 10230ebfff14SBenjamin Herrenschmidt 102406fe98e6SBenjamin Herrenschmidt DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw); 10250ebfff14SBenjamin Herrenschmidt 10267df2457dSOlof Johansson if (hw == mpic->spurious_vec) 10270ebfff14SBenjamin Herrenschmidt return -EINVAL; 10285fe0c1f2SBenjamin Herrenschmidt if (mpic->protected && test_bit(hw, mpic->protected)) { 10295fe0c1f2SBenjamin Herrenschmidt pr_warning("mpic: Mapping of source 0x%x failed, " 10305fe0c1f2SBenjamin Herrenschmidt "source protected by firmware !\n",\ 10315fe0c1f2SBenjamin Herrenschmidt (unsigned int)hw); 10325fe0c1f2SBenjamin Herrenschmidt return -EPERM; 10335fe0c1f2SBenjamin Herrenschmidt } 103406fe98e6SBenjamin Herrenschmidt 10350ebfff14SBenjamin Herrenschmidt #ifdef CONFIG_SMP 10367df2457dSOlof Johansson else if (hw >= mpic->ipi_vecs[0]) { 1037be8bec56SKyle Moffett WARN_ON(mpic->flags & MPIC_SECONDARY); 10380ebfff14SBenjamin Herrenschmidt 103906fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping as IPI\n"); 1040ec775d0eSThomas Gleixner irq_set_chip_data(virq, mpic); 1041ec775d0eSThomas Gleixner irq_set_chip_and_handler(virq, &mpic->hc_ipi, 10420ebfff14SBenjamin Herrenschmidt handle_percpu_irq); 10430ebfff14SBenjamin Herrenschmidt return 0; 10440ebfff14SBenjamin Herrenschmidt } 10450ebfff14SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 10460ebfff14SBenjamin Herrenschmidt 1047ea94187fSScott Wood if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) { 1048be8bec56SKyle Moffett WARN_ON(mpic->flags & MPIC_SECONDARY); 1049ea94187fSScott Wood 1050ea94187fSScott Wood DBG("mpic: mapping as timer\n"); 1051ea94187fSScott Wood irq_set_chip_data(virq, mpic); 1052ea94187fSScott Wood irq_set_chip_and_handler(virq, &mpic->hc_tm, 1053ea94187fSScott Wood handle_fasteoi_irq); 1054ea94187fSScott Wood return 0; 1055ea94187fSScott Wood } 1056ea94187fSScott Wood 10570a408164SVarun Sethi if (mpic_map_error_int(mpic, virq, hw)) 10580a408164SVarun Sethi return 0; 10590a408164SVarun Sethi 10605fe0c1f2SBenjamin Herrenschmidt if (hw >= mpic->num_sources) { 10615fe0c1f2SBenjamin Herrenschmidt pr_warning("mpic: Mapping of source 0x%x failed, " 10625fe0c1f2SBenjamin Herrenschmidt "source out of range !\n",\ 10635fe0c1f2SBenjamin Herrenschmidt (unsigned int)hw); 10640ebfff14SBenjamin Herrenschmidt return -EINVAL; 10655fe0c1f2SBenjamin Herrenschmidt } 10660ebfff14SBenjamin Herrenschmidt 1067a7de7c74SMichael Ellerman mpic_msi_reserve_hwirq(mpic, hw); 1068a7de7c74SMichael Ellerman 10696e99e458SBenjamin Herrenschmidt /* Default chip */ 10700ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_irq; 10710ebfff14SBenjamin Herrenschmidt 10726cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 10730ebfff14SBenjamin Herrenschmidt /* Check for HT interrupts, override vecpri */ 10746e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, hw)) 10750ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_ht_irq; 10766cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 10770ebfff14SBenjamin Herrenschmidt 107806fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping to irq chip @%p\n", chip); 10790ebfff14SBenjamin Herrenschmidt 1080ec775d0eSThomas Gleixner irq_set_chip_data(virq, mpic); 1081ec775d0eSThomas Gleixner irq_set_chip_and_handler(virq, chip, handle_fasteoi_irq); 10826e99e458SBenjamin Herrenschmidt 10836e99e458SBenjamin Herrenschmidt /* Set default irq type */ 1084446f6d06SBenjamin Herrenschmidt irq_set_irq_type(virq, IRQ_TYPE_DEFAULT); 10856e99e458SBenjamin Herrenschmidt 1086dfec2202SMeador Inge /* If the MPIC was reset, then all vectors have already been 1087dfec2202SMeador Inge * initialized. Otherwise, a per source lazy initialization 1088dfec2202SMeador Inge * is done here. 1089dfec2202SMeador Inge */ 1090dfec2202SMeador Inge if (!mpic_is_ipi(mpic, hw) && (mpic->flags & MPIC_NO_RESET)) { 109132dda05fSScott Wood int cpu; 109232dda05fSScott Wood 109332dda05fSScott Wood preempt_disable(); 109432dda05fSScott Wood cpu = mpic_processor_id(mpic); 109532dda05fSScott Wood preempt_enable(); 109632dda05fSScott Wood 1097dfec2202SMeador Inge mpic_set_vector(virq, hw); 109832dda05fSScott Wood mpic_set_destination(virq, cpu); 1099dfec2202SMeador Inge mpic_irq_set_priority(virq, 8); 1100dfec2202SMeador Inge } 1101dfec2202SMeador Inge 11020ebfff14SBenjamin Herrenschmidt return 0; 11030ebfff14SBenjamin Herrenschmidt } 11040ebfff14SBenjamin Herrenschmidt 1105bae1d8f1SGrant Likely static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct, 110640d50cf7SRoman Fietze const u32 *intspec, unsigned int intsize, 11070ebfff14SBenjamin Herrenschmidt irq_hw_number_t *out_hwirq, unsigned int *out_flags) 11080ebfff14SBenjamin Herrenschmidt 11090ebfff14SBenjamin Herrenschmidt { 111022d168ceSScott Wood struct mpic *mpic = h->host_data; 11110ebfff14SBenjamin Herrenschmidt static unsigned char map_mpic_senses[4] = { 11120ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_RISING, 11130ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_LOW, 11140ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_HIGH, 11150ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_FALLING, 11160ebfff14SBenjamin Herrenschmidt }; 11170ebfff14SBenjamin Herrenschmidt 11180ebfff14SBenjamin Herrenschmidt *out_hwirq = intspec[0]; 111922d168ceSScott Wood if (intsize >= 4 && (mpic->flags & MPIC_FSL)) { 112022d168ceSScott Wood /* 112122d168ceSScott Wood * Freescale MPIC with extended intspec: 112222d168ceSScott Wood * First two cells are as usual. Third specifies 112322d168ceSScott Wood * an "interrupt type". Fourth is type-specific data. 112422d168ceSScott Wood * 112522d168ceSScott Wood * See Documentation/devicetree/bindings/powerpc/fsl/mpic.txt 112622d168ceSScott Wood */ 112722d168ceSScott Wood switch (intspec[2]) { 112822d168ceSScott Wood case 0: 11290a408164SVarun Sethi break; 11300a408164SVarun Sethi case 1: 11310a408164SVarun Sethi if (!(mpic->flags & MPIC_FSL_HAS_EIMR)) 11320a408164SVarun Sethi break; 11330a408164SVarun Sethi 11340a408164SVarun Sethi if (intspec[3] >= ARRAY_SIZE(mpic->err_int_vecs)) 11350a408164SVarun Sethi return -EINVAL; 11360a408164SVarun Sethi 11370a408164SVarun Sethi *out_hwirq = mpic->err_int_vecs[intspec[3]]; 11380a408164SVarun Sethi 113922d168ceSScott Wood break; 114022d168ceSScott Wood case 2: 114122d168ceSScott Wood if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs)) 114222d168ceSScott Wood return -EINVAL; 114322d168ceSScott Wood 114422d168ceSScott Wood *out_hwirq = mpic->ipi_vecs[intspec[0]]; 114522d168ceSScott Wood break; 114622d168ceSScott Wood case 3: 114722d168ceSScott Wood if (intspec[0] >= ARRAY_SIZE(mpic->timer_vecs)) 114822d168ceSScott Wood return -EINVAL; 114922d168ceSScott Wood 115022d168ceSScott Wood *out_hwirq = mpic->timer_vecs[intspec[0]]; 115122d168ceSScott Wood break; 115222d168ceSScott Wood default: 115322d168ceSScott Wood pr_debug("%s: unknown irq type %u\n", 115422d168ceSScott Wood __func__, intspec[2]); 115522d168ceSScott Wood return -EINVAL; 115622d168ceSScott Wood } 115722d168ceSScott Wood 115822d168ceSScott Wood *out_flags = map_mpic_senses[intspec[1] & 3]; 115922d168ceSScott Wood } else if (intsize > 1) { 116006fe98e6SBenjamin Herrenschmidt u32 mask = 0x3; 116106fe98e6SBenjamin Herrenschmidt 116206fe98e6SBenjamin Herrenschmidt /* Apple invented a new race of encoding on machines with 116306fe98e6SBenjamin Herrenschmidt * an HT APIC. They encode, among others, the index within 116406fe98e6SBenjamin Herrenschmidt * the HT APIC. We don't care about it here since thankfully, 116506fe98e6SBenjamin Herrenschmidt * it appears that they have the APIC already properly 116606fe98e6SBenjamin Herrenschmidt * configured, and thus our current fixup code that reads the 116706fe98e6SBenjamin Herrenschmidt * APIC config works fine. However, we still need to mask out 116806fe98e6SBenjamin Herrenschmidt * bits in the specifier to make sure we only get bit 0 which 116906fe98e6SBenjamin Herrenschmidt * is the level/edge bit (the only sense bit exposed by Apple), 117006fe98e6SBenjamin Herrenschmidt * as their bit 1 means something else. 117106fe98e6SBenjamin Herrenschmidt */ 117206fe98e6SBenjamin Herrenschmidt if (machine_is(powermac)) 117306fe98e6SBenjamin Herrenschmidt mask = 0x1; 117406fe98e6SBenjamin Herrenschmidt *out_flags = map_mpic_senses[intspec[1] & mask]; 117506fe98e6SBenjamin Herrenschmidt } else 11760ebfff14SBenjamin Herrenschmidt *out_flags = IRQ_TYPE_NONE; 11770ebfff14SBenjamin Herrenschmidt 117806fe98e6SBenjamin Herrenschmidt DBG("mpic: xlate (%d cells: 0x%08x 0x%08x) to line 0x%lx sense 0x%x\n", 117906fe98e6SBenjamin Herrenschmidt intsize, intspec[0], intspec[1], *out_hwirq, *out_flags); 118006fe98e6SBenjamin Herrenschmidt 11810ebfff14SBenjamin Herrenschmidt return 0; 11820ebfff14SBenjamin Herrenschmidt } 11830ebfff14SBenjamin Herrenschmidt 118409dc34a9SKyle Moffett /* IRQ handler for a secondary MPIC cascaded from another IRQ controller */ 118509dc34a9SKyle Moffett static void mpic_cascade(unsigned int irq, struct irq_desc *desc) 118609dc34a9SKyle Moffett { 118709dc34a9SKyle Moffett struct irq_chip *chip = irq_desc_get_chip(desc); 118809dc34a9SKyle Moffett struct mpic *mpic = irq_desc_get_handler_data(desc); 118909dc34a9SKyle Moffett unsigned int virq; 119009dc34a9SKyle Moffett 119109dc34a9SKyle Moffett BUG_ON(!(mpic->flags & MPIC_SECONDARY)); 119209dc34a9SKyle Moffett 119309dc34a9SKyle Moffett virq = mpic_get_one_irq(mpic); 1194bae1d8f1SGrant Likely if (virq) 119509dc34a9SKyle Moffett generic_handle_irq(virq); 119609dc34a9SKyle Moffett 119709dc34a9SKyle Moffett chip->irq_eoi(&desc->irq_data); 119809dc34a9SKyle Moffett } 119909dc34a9SKyle Moffett 1200bae1d8f1SGrant Likely static struct irq_domain_ops mpic_host_ops = { 12010ebfff14SBenjamin Herrenschmidt .match = mpic_host_match, 12020ebfff14SBenjamin Herrenschmidt .map = mpic_host_map, 12030ebfff14SBenjamin Herrenschmidt .xlate = mpic_host_xlate, 12040ebfff14SBenjamin Herrenschmidt }; 12050ebfff14SBenjamin Herrenschmidt 120686d37969SHongtao Jia static u32 fsl_mpic_get_version(struct mpic *mpic) 120786d37969SHongtao Jia { 120886d37969SHongtao Jia u32 brr1; 120986d37969SHongtao Jia 121086d37969SHongtao Jia if (!(mpic->flags & MPIC_FSL)) 121186d37969SHongtao Jia return 0; 121286d37969SHongtao Jia 121386d37969SHongtao Jia brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs, 121486d37969SHongtao Jia MPIC_FSL_BRR1); 121586d37969SHongtao Jia 121686d37969SHongtao Jia return brr1 & MPIC_FSL_BRR1_VER; 121786d37969SHongtao Jia } 121886d37969SHongtao Jia 121914cf11afSPaul Mackerras /* 122014cf11afSPaul Mackerras * Exported functions 122114cf11afSPaul Mackerras */ 122214cf11afSPaul Mackerras 122386d37969SHongtao Jia u32 fsl_mpic_primary_get_version(void) 122486d37969SHongtao Jia { 122586d37969SHongtao Jia struct mpic *mpic = mpic_primary; 122686d37969SHongtao Jia 122786d37969SHongtao Jia if (mpic) 122886d37969SHongtao Jia return fsl_mpic_get_version(mpic); 122986d37969SHongtao Jia 123086d37969SHongtao Jia return 0; 123186d37969SHongtao Jia } 123286d37969SHongtao Jia 12330ebfff14SBenjamin Herrenschmidt struct mpic * __init mpic_alloc(struct device_node *node, 1234a959ff56SBenjamin Herrenschmidt phys_addr_t phys_addr, 123514cf11afSPaul Mackerras unsigned int flags, 123614cf11afSPaul Mackerras unsigned int isu_size, 123714cf11afSPaul Mackerras unsigned int irq_count, 123814cf11afSPaul Mackerras const char *name) 123914cf11afSPaul Mackerras { 12405bdb6f2eSKyle Moffett int i, psize, intvec_top; 124114cf11afSPaul Mackerras struct mpic *mpic; 1242d9d1063dSJohannes Berg u32 greg_feature; 124314cf11afSPaul Mackerras const char *vers; 12445bdb6f2eSKyle Moffett const u32 *psrc; 1245c1b8d45dSKyle Moffett u32 last_irq; 12467c509ee0SScott Wood u32 fsl_version = 0; 12478bf41568SKyle Moffett 1248996983b7SKyle Moffett /* Default MPIC search parameters */ 1249996983b7SKyle Moffett static const struct of_device_id __initconst mpic_device_id[] = { 1250996983b7SKyle Moffett { .type = "open-pic", }, 1251996983b7SKyle Moffett { .compatible = "open-pic", }, 1252996983b7SKyle Moffett {}, 1253996983b7SKyle Moffett }; 1254996983b7SKyle Moffett 1255996983b7SKyle Moffett /* 1256996983b7SKyle Moffett * If we were not passed a device-tree node, then perform the default 1257996983b7SKyle Moffett * search for standardized a standardized OpenPIC. 1258996983b7SKyle Moffett */ 1259996983b7SKyle Moffett if (node) { 1260996983b7SKyle Moffett node = of_node_get(node); 1261996983b7SKyle Moffett } else { 1262996983b7SKyle Moffett node = of_find_matching_node(NULL, mpic_device_id); 1263996983b7SKyle Moffett if (!node) 1264996983b7SKyle Moffett return NULL; 1265996983b7SKyle Moffett } 12668bf41568SKyle Moffett 12675bdb6f2eSKyle Moffett /* Pick the physical address from the device tree if unspecified */ 12685bdb6f2eSKyle Moffett if (!phys_addr) { 12698bf41568SKyle Moffett /* Check if it is DCR-based */ 12708bf41568SKyle Moffett if (of_get_property(node, "dcr-reg", NULL)) { 12718bf41568SKyle Moffett flags |= MPIC_USES_DCR; 12728bf41568SKyle Moffett } else { 12738bf41568SKyle Moffett struct resource r; 12748bf41568SKyle Moffett if (of_address_to_resource(node, 0, &r)) 1275996983b7SKyle Moffett goto err_of_node_put; 12768bf41568SKyle Moffett phys_addr = r.start; 12778bf41568SKyle Moffett } 12788bf41568SKyle Moffett } 127914cf11afSPaul Mackerras 12803a7a7176SKyle Moffett /* Read extra device-tree properties into the flags variable */ 12813a7a7176SKyle Moffett if (of_get_property(node, "big-endian", NULL)) 12823a7a7176SKyle Moffett flags |= MPIC_BIG_ENDIAN; 12833a7a7176SKyle Moffett if (of_get_property(node, "pic-no-reset", NULL)) 12843a7a7176SKyle Moffett flags |= MPIC_NO_RESET; 12859ca163c8SKyle Moffett if (of_get_property(node, "single-cpu-affinity", NULL)) 12869ca163c8SKyle Moffett flags |= MPIC_SINGLE_DEST_CPU; 12873a7a7176SKyle Moffett if (of_device_is_compatible(node, "fsl,mpic")) 12885a271fe7SVarun Sethi flags |= MPIC_FSL | MPIC_LARGE_VECTORS; 12893a7a7176SKyle Moffett 129085355bb2SKumar Gala mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); 129114cf11afSPaul Mackerras if (mpic == NULL) 1292996983b7SKyle Moffett goto err_of_node_put; 129314cf11afSPaul Mackerras 129414cf11afSPaul Mackerras mpic->name = name; 1295c51242e7SKyle Moffett mpic->node = node; 1296e7a98675SKyle Moffett mpic->paddr = phys_addr; 12973a7a7176SKyle Moffett mpic->flags = flags; 129814cf11afSPaul Mackerras 1299b9e5b4e6SBenjamin Herrenschmidt mpic->hc_irq = mpic_irq_chip; 1300b27df672SThomas Gleixner mpic->hc_irq.name = name; 13013a7a7176SKyle Moffett if (!(mpic->flags & MPIC_SECONDARY)) 1302835c0553SLennert Buytenhek mpic->hc_irq.irq_set_affinity = mpic_set_affinity; 13036cfef5b2SMichael Ellerman #ifdef CONFIG_MPIC_U3_HT_IRQS 1304b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq = mpic_irq_ht_chip; 1305b27df672SThomas Gleixner mpic->hc_ht_irq.name = name; 13063a7a7176SKyle Moffett if (!(mpic->flags & MPIC_SECONDARY)) 1307835c0553SLennert Buytenhek mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; 13086cfef5b2SMichael Ellerman #endif /* CONFIG_MPIC_U3_HT_IRQS */ 1309fbf0274eSBenjamin Herrenschmidt 131014cf11afSPaul Mackerras #ifdef CONFIG_SMP 1311b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ipi = mpic_ipi_chip; 1312b27df672SThomas Gleixner mpic->hc_ipi.name = name; 131314cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 131414cf11afSPaul Mackerras 1315ea94187fSScott Wood mpic->hc_tm = mpic_tm_chip; 1316ea94187fSScott Wood mpic->hc_tm.name = name; 1317ea94187fSScott Wood 131814cf11afSPaul Mackerras mpic->num_sources = 0; /* so far */ 131914cf11afSPaul Mackerras 13203a7a7176SKyle Moffett if (mpic->flags & MPIC_LARGE_VECTORS) 13217df2457dSOlof Johansson intvec_top = 2047; 13227df2457dSOlof Johansson else 13237df2457dSOlof Johansson intvec_top = 255; 13247df2457dSOlof Johansson 1325ea94187fSScott Wood mpic->timer_vecs[0] = intvec_top - 12; 1326ea94187fSScott Wood mpic->timer_vecs[1] = intvec_top - 11; 1327ea94187fSScott Wood mpic->timer_vecs[2] = intvec_top - 10; 1328ea94187fSScott Wood mpic->timer_vecs[3] = intvec_top - 9; 1329ea94187fSScott Wood mpic->timer_vecs[4] = intvec_top - 8; 1330ea94187fSScott Wood mpic->timer_vecs[5] = intvec_top - 7; 1331ea94187fSScott Wood mpic->timer_vecs[6] = intvec_top - 6; 1332ea94187fSScott Wood mpic->timer_vecs[7] = intvec_top - 5; 13337df2457dSOlof Johansson mpic->ipi_vecs[0] = intvec_top - 4; 13347df2457dSOlof Johansson mpic->ipi_vecs[1] = intvec_top - 3; 13357df2457dSOlof Johansson mpic->ipi_vecs[2] = intvec_top - 2; 13367df2457dSOlof Johansson mpic->ipi_vecs[3] = intvec_top - 1; 13377df2457dSOlof Johansson mpic->spurious_vec = intvec_top; 13387df2457dSOlof Johansson 13397fd72186SBenjamin Herrenschmidt /* Look for protected sources */ 1340c51242e7SKyle Moffett psrc = of_get_property(mpic->node, "protected-sources", &psize); 13417fd72186SBenjamin Herrenschmidt if (psrc) { 13425bdb6f2eSKyle Moffett /* Allocate a bitmap with one bit per interrupt */ 13435bdb6f2eSKyle Moffett unsigned int mapsize = BITS_TO_LONGS(intvec_top + 1); 13445bdb6f2eSKyle Moffett mpic->protected = kzalloc(mapsize*sizeof(long), GFP_KERNEL); 13457fd72186SBenjamin Herrenschmidt BUG_ON(mpic->protected == NULL); 13465bdb6f2eSKyle Moffett for (i = 0; i < psize/sizeof(u32); i++) { 13477fd72186SBenjamin Herrenschmidt if (psrc[i] > intvec_top) 13487fd72186SBenjamin Herrenschmidt continue; 13497fd72186SBenjamin Herrenschmidt __set_bit(psrc[i], mpic->protected); 13507fd72186SBenjamin Herrenschmidt } 13517fd72186SBenjamin Herrenschmidt } 1352a959ff56SBenjamin Herrenschmidt 13537233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 13543a7a7176SKyle Moffett mpic->hw_set = mpic_infos[MPIC_GET_REGSET(mpic->flags)]; 13557233593bSZang Roy-r61911 #endif 13567233593bSZang Roy-r61911 1357fbf0274eSBenjamin Herrenschmidt /* default register type */ 13583a7a7176SKyle Moffett if (mpic->flags & MPIC_BIG_ENDIAN) 13598bf41568SKyle Moffett mpic->reg_type = mpic_access_mmio_be; 13608bf41568SKyle Moffett else 13618bf41568SKyle Moffett mpic->reg_type = mpic_access_mmio_le; 1362fbf0274eSBenjamin Herrenschmidt 13638bf41568SKyle Moffett /* 13648bf41568SKyle Moffett * An MPIC with a "dcr-reg" property must be accessed that way, but 13658bf41568SKyle Moffett * only if the kernel includes DCR support. 13668bf41568SKyle Moffett */ 1367fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 13683a7a7176SKyle Moffett if (mpic->flags & MPIC_USES_DCR) 1369fbf0274eSBenjamin Herrenschmidt mpic->reg_type = mpic_access_dcr; 1370fbf0274eSBenjamin Herrenschmidt #else 13713a7a7176SKyle Moffett BUG_ON(mpic->flags & MPIC_USES_DCR); 13728bf41568SKyle Moffett #endif 1373a959ff56SBenjamin Herrenschmidt 137414cf11afSPaul Mackerras /* Map the global registers */ 1375c51242e7SKyle Moffett mpic_map(mpic, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); 1376c51242e7SKyle Moffett mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); 137714cf11afSPaul Mackerras 137803bcb7e3SVarun Sethi if (mpic->flags & MPIC_FSL) { 13790a408164SVarun Sethi int ret; 13800a408164SVarun Sethi 138103bcb7e3SVarun Sethi /* 138203bcb7e3SVarun Sethi * Yes, Freescale really did put global registers in the 138303bcb7e3SVarun Sethi * magic per-cpu area -- and they don't even show up in the 138403bcb7e3SVarun Sethi * non-magic per-cpu copies that this driver normally uses. 138503bcb7e3SVarun Sethi */ 138603bcb7e3SVarun Sethi mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs, 138703bcb7e3SVarun Sethi MPIC_CPU_THISBASE, 0x1000); 13880a408164SVarun Sethi 138986d37969SHongtao Jia fsl_version = fsl_mpic_get_version(mpic); 13900a408164SVarun Sethi 13910a408164SVarun Sethi /* Error interrupt mask register (EIMR) is required for 13920a408164SVarun Sethi * handling individual device error interrupts. EIMR 13930a408164SVarun Sethi * was added in MPIC version 4.1. 13940a408164SVarun Sethi * 13950a408164SVarun Sethi * Over here we reserve vector number space for error 13960a408164SVarun Sethi * interrupt vectors. This space is stolen from the 13970a408164SVarun Sethi * global vector number space, as in case of ipis 13980a408164SVarun Sethi * and timer interrupts. 13990a408164SVarun Sethi * 14000a408164SVarun Sethi * Available vector space = intvec_top - 12, where 12 14010a408164SVarun Sethi * is the number of vectors which have been consumed by 14020a408164SVarun Sethi * ipis and timer interrupts. 14030a408164SVarun Sethi */ 14047c509ee0SScott Wood if (fsl_version >= 0x401) { 14050a408164SVarun Sethi ret = mpic_setup_error_int(mpic, intvec_top - 12); 14060a408164SVarun Sethi if (ret) 14070a408164SVarun Sethi return NULL; 14080a408164SVarun Sethi } 14097c509ee0SScott Wood 14107c509ee0SScott Wood } 14117c509ee0SScott Wood 14127c509ee0SScott Wood /* 14137c509ee0SScott Wood * EPR is only available starting with v4.0. To support 14147c509ee0SScott Wood * platforms that don't know the MPIC version at compile-time, 14157c509ee0SScott Wood * such as qemu-e500, turn off coreint if this MPIC doesn't 14167c509ee0SScott Wood * support it. Note that we never enable it if it wasn't 14177c509ee0SScott Wood * requested in the first place. 14187c509ee0SScott Wood * 14197c509ee0SScott Wood * This is done outside the MPIC_FSL check, so that we 14207c509ee0SScott Wood * also disable coreint if the MPIC node doesn't have 14217c509ee0SScott Wood * an "fsl,mpic" compatible at all. This will be the case 14227c509ee0SScott Wood * with device trees generated by older versions of QEMU. 14237c509ee0SScott Wood * fsl_version will be zero if MPIC_FSL is not set. 14247c509ee0SScott Wood */ 14257c509ee0SScott Wood if (fsl_version < 0x400 && (flags & MPIC_ENABLE_COREINT)) { 14267c509ee0SScott Wood WARN_ON(ppc_md.get_irq != mpic_get_coreint_irq); 14277c509ee0SScott Wood ppc_md.get_irq = mpic_get_irq; 142803bcb7e3SVarun Sethi } 142903bcb7e3SVarun Sethi 143014cf11afSPaul Mackerras /* Reset */ 1431dfec2202SMeador Inge 1432dfec2202SMeador Inge /* When using a device-node, reset requests are only honored if the MPIC 1433dfec2202SMeador Inge * is allowed to reset. 1434dfec2202SMeador Inge */ 1435e55d7f73SKyle Moffett if (!(mpic->flags & MPIC_NO_RESET)) { 1436dfec2202SMeador Inge printk(KERN_DEBUG "mpic: Resetting\n"); 14377233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 14387233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 143914cf11afSPaul Mackerras | MPIC_GREG_GCONF_RESET); 14407233593bSZang Roy-r61911 while( mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 144114cf11afSPaul Mackerras & MPIC_GREG_GCONF_RESET) 144214cf11afSPaul Mackerras mb(); 144314cf11afSPaul Mackerras } 144414cf11afSPaul Mackerras 1445d91e4ea7SKumar Gala /* CoreInt */ 14463a7a7176SKyle Moffett if (mpic->flags & MPIC_ENABLE_COREINT) 1447d91e4ea7SKumar Gala mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1448d91e4ea7SKumar Gala mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1449d91e4ea7SKumar Gala | MPIC_GREG_GCONF_COREINT); 1450d91e4ea7SKumar Gala 14513a7a7176SKyle Moffett if (mpic->flags & MPIC_ENABLE_MCK) 1452f365355eSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1453f365355eSOlof Johansson mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1454f365355eSOlof Johansson | MPIC_GREG_GCONF_MCK); 1455f365355eSOlof Johansson 145614b92470STimur Tabi /* 145714b92470STimur Tabi * The MPIC driver will crash if there are more cores than we 145814b92470STimur Tabi * can initialize, so we may as well catch that problem here. 145914b92470STimur Tabi */ 146014b92470STimur Tabi BUG_ON(num_possible_cpus() > MPIC_MAX_CPUS); 146114b92470STimur Tabi 146214cf11afSPaul Mackerras /* Map the per-CPU registers */ 146314b92470STimur Tabi for_each_possible_cpu(i) { 146414b92470STimur Tabi unsigned int cpu = get_hard_smp_processor_id(i); 146514b92470STimur Tabi 1466c51242e7SKyle Moffett mpic_map(mpic, mpic->paddr, &mpic->cpuregs[cpu], 146714b92470STimur Tabi MPIC_INFO(CPU_BASE) + cpu * MPIC_INFO(CPU_STRIDE), 1468fbf0274eSBenjamin Herrenschmidt 0x1000); 146914cf11afSPaul Mackerras } 147014cf11afSPaul Mackerras 1471c1b8d45dSKyle Moffett /* 1472c1b8d45dSKyle Moffett * Read feature register. For non-ISU MPICs, num sources as well. On 1473c1b8d45dSKyle Moffett * ISU MPICs, sources are counted as ISUs are added 1474c1b8d45dSKyle Moffett */ 1475c1b8d45dSKyle Moffett greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); 1476c1b8d45dSKyle Moffett 1477c1b8d45dSKyle Moffett /* 1478c1b8d45dSKyle Moffett * By default, the last source number comes from the MPIC, but the 1479c1b8d45dSKyle Moffett * device-tree and board support code can override it on buggy hw. 1480fe83364fSBenjamin Herrenschmidt * If we get passed an isu_size (multi-isu MPIC) then we use that 1481fe83364fSBenjamin Herrenschmidt * as a default instead of the value read from the HW. 1482c1b8d45dSKyle Moffett */ 1483c1b8d45dSKyle Moffett last_irq = (greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) 1484c1b8d45dSKyle Moffett >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT; 1485fe83364fSBenjamin Herrenschmidt if (isu_size) 1486fe83364fSBenjamin Herrenschmidt last_irq = isu_size * MPIC_MAX_ISU - 1; 1487c1b8d45dSKyle Moffett of_property_read_u32(mpic->node, "last-interrupt-source", &last_irq); 1488c1b8d45dSKyle Moffett if (irq_count) 1489c1b8d45dSKyle Moffett last_irq = irq_count - 1; 1490c1b8d45dSKyle Moffett 149114cf11afSPaul Mackerras /* Initialize main ISU if none provided */ 1492c1b8d45dSKyle Moffett if (!isu_size) { 1493c1b8d45dSKyle Moffett isu_size = last_irq + 1; 1494c1b8d45dSKyle Moffett mpic->num_sources = isu_size; 1495c51242e7SKyle Moffett mpic_map(mpic, mpic->paddr, &mpic->isus[0], 1496c1b8d45dSKyle Moffett MPIC_INFO(IRQ_BASE), 1497c1b8d45dSKyle Moffett MPIC_INFO(IRQ_STRIDE) * isu_size); 149814cf11afSPaul Mackerras } 1499c1b8d45dSKyle Moffett 1500c1b8d45dSKyle Moffett mpic->isu_size = isu_size; 150114cf11afSPaul Mackerras mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); 150214cf11afSPaul Mackerras mpic->isu_mask = (1 << mpic->isu_shift) - 1; 150314cf11afSPaul Mackerras 1504a8db8cf0SGrant Likely mpic->irqhost = irq_domain_add_linear(mpic->node, 1505574ce79cSBenjamin Herrenschmidt intvec_top, 1506a8db8cf0SGrant Likely &mpic_host_ops, mpic); 1507996983b7SKyle Moffett 1508996983b7SKyle Moffett /* 1509996983b7SKyle Moffett * FIXME: The code leaks the MPIC object and mappings here; this 1510996983b7SKyle Moffett * is very unlikely to fail but it ought to be fixed anyways. 1511996983b7SKyle Moffett */ 151231207dabSKumar Gala if (mpic->irqhost == NULL) 151331207dabSKumar Gala return NULL; 151431207dabSKumar Gala 151514cf11afSPaul Mackerras /* Display version */ 1516d9d1063dSJohannes Berg switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) { 151714cf11afSPaul Mackerras case 1: 151814cf11afSPaul Mackerras vers = "1.0"; 151914cf11afSPaul Mackerras break; 152014cf11afSPaul Mackerras case 2: 152114cf11afSPaul Mackerras vers = "1.2"; 152214cf11afSPaul Mackerras break; 152314cf11afSPaul Mackerras case 3: 152414cf11afSPaul Mackerras vers = "1.3"; 152514cf11afSPaul Mackerras break; 152614cf11afSPaul Mackerras default: 152714cf11afSPaul Mackerras vers = "<unknown>"; 152814cf11afSPaul Mackerras break; 152914cf11afSPaul Mackerras } 1530a959ff56SBenjamin Herrenschmidt printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," 1531a959ff56SBenjamin Herrenschmidt " max %d CPUs\n", 1532e7a98675SKyle Moffett name, vers, (unsigned long long)mpic->paddr, num_possible_cpus()); 1533a959ff56SBenjamin Herrenschmidt printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", 1534a959ff56SBenjamin Herrenschmidt mpic->isu_size, mpic->isu_shift, mpic->isu_mask); 153514cf11afSPaul Mackerras 153614cf11afSPaul Mackerras mpic->next = mpics; 153714cf11afSPaul Mackerras mpics = mpic; 153814cf11afSPaul Mackerras 15393a7a7176SKyle Moffett if (!(mpic->flags & MPIC_SECONDARY)) { 154014cf11afSPaul Mackerras mpic_primary = mpic; 15410ebfff14SBenjamin Herrenschmidt irq_set_default_host(mpic->irqhost); 15420ebfff14SBenjamin Herrenschmidt } 154314cf11afSPaul Mackerras 154414cf11afSPaul Mackerras return mpic; 1545996983b7SKyle Moffett 1546996983b7SKyle Moffett err_of_node_put: 1547996983b7SKyle Moffett of_node_put(node); 1548996983b7SKyle Moffett return NULL; 154914cf11afSPaul Mackerras } 155014cf11afSPaul Mackerras 155114cf11afSPaul Mackerras void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, 1552a959ff56SBenjamin Herrenschmidt phys_addr_t paddr) 155314cf11afSPaul Mackerras { 155414cf11afSPaul Mackerras unsigned int isu_first = isu_num * mpic->isu_size; 155514cf11afSPaul Mackerras 155614cf11afSPaul Mackerras BUG_ON(isu_num >= MPIC_MAX_ISU); 155714cf11afSPaul Mackerras 1558c51242e7SKyle Moffett mpic_map(mpic, 15595a2642f6SBenjamin Herrenschmidt paddr, &mpic->isus[isu_num], 0, 15607233593bSZang Roy-r61911 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); 15615a2642f6SBenjamin Herrenschmidt 156214cf11afSPaul Mackerras if ((isu_first + mpic->isu_size) > mpic->num_sources) 156314cf11afSPaul Mackerras mpic->num_sources = isu_first + mpic->isu_size; 156414cf11afSPaul Mackerras } 156514cf11afSPaul Mackerras 156614cf11afSPaul Mackerras void __init mpic_init(struct mpic *mpic) 156714cf11afSPaul Mackerras { 156809dc34a9SKyle Moffett int i, cpu; 156903bcb7e3SVarun Sethi int num_timers = 4; 157014cf11afSPaul Mackerras 157114cf11afSPaul Mackerras BUG_ON(mpic->num_sources == 0); 157214cf11afSPaul Mackerras 157314cf11afSPaul Mackerras printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); 157414cf11afSPaul Mackerras 157514cf11afSPaul Mackerras /* Set current processor priority to max */ 15767233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 157714cf11afSPaul Mackerras 157803bcb7e3SVarun Sethi if (mpic->flags & MPIC_FSL) { 157986d37969SHongtao Jia u32 version = fsl_mpic_get_version(mpic); 158003bcb7e3SVarun Sethi 158103bcb7e3SVarun Sethi /* 158203bcb7e3SVarun Sethi * Timer group B is present at the latest in MPIC 3.1 (e.g. 158303bcb7e3SVarun Sethi * mpc8536). It is not present in MPIC 2.0 (e.g. mpc8544). 158403bcb7e3SVarun Sethi * I don't know about the status of intermediate versions (or 158503bcb7e3SVarun Sethi * whether they even exist). 158603bcb7e3SVarun Sethi */ 158703bcb7e3SVarun Sethi if (version >= 0x0301) 158803bcb7e3SVarun Sethi num_timers = 8; 158903bcb7e3SVarun Sethi } 159003bcb7e3SVarun Sethi 1591ea94187fSScott Wood /* Initialize timers to our reserved vectors and mask them for now */ 159203bcb7e3SVarun Sethi for (i = 0; i < num_timers; i++) { 159303bcb7e3SVarun Sethi unsigned int offset = mpic_tm_offset(mpic, i); 159403bcb7e3SVarun Sethi 159514cf11afSPaul Mackerras mpic_write(mpic->tmregs, 159603bcb7e3SVarun Sethi offset + MPIC_INFO(TIMER_DESTINATION), 1597ea94187fSScott Wood 1 << hard_smp_processor_id()); 159814cf11afSPaul Mackerras mpic_write(mpic->tmregs, 159903bcb7e3SVarun Sethi offset + MPIC_INFO(TIMER_VECTOR_PRI), 160014cf11afSPaul Mackerras MPIC_VECPRI_MASK | 1601ea94187fSScott Wood (9 << MPIC_VECPRI_PRIORITY_SHIFT) | 16027df2457dSOlof Johansson (mpic->timer_vecs[0] + i)); 160314cf11afSPaul Mackerras } 160414cf11afSPaul Mackerras 160514cf11afSPaul Mackerras /* Initialize IPIs to our reserved vectors and mark them disabled for now */ 160614cf11afSPaul Mackerras mpic_test_broken_ipi(mpic); 160714cf11afSPaul Mackerras for (i = 0; i < 4; i++) { 160814cf11afSPaul Mackerras mpic_ipi_write(i, 160914cf11afSPaul Mackerras MPIC_VECPRI_MASK | 161014cf11afSPaul Mackerras (10 << MPIC_VECPRI_PRIORITY_SHIFT) | 16117df2457dSOlof Johansson (mpic->ipi_vecs[0] + i)); 161214cf11afSPaul Mackerras } 161314cf11afSPaul Mackerras 16141beb6a7dSBenjamin Herrenschmidt /* Do the HT PIC fixups on U3 broken mpic */ 161514cf11afSPaul Mackerras DBG("MPIC flags: %x\n", mpic->flags); 1616be8bec56SKyle Moffett if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) { 16171beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pics(mpic); 161805af7bd2SMichael Ellerman mpic_u3msi_init(mpic); 161905af7bd2SMichael Ellerman } 162014cf11afSPaul Mackerras 162138958dd9SOlof Johansson mpic_pasemi_msi_init(mpic); 162238958dd9SOlof Johansson 1623d6a2639bSMeador Inge cpu = mpic_processor_id(mpic); 1624cc353c30SArnd Bergmann 1625dfec2202SMeador Inge if (!(mpic->flags & MPIC_NO_RESET)) { 162614cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources; i++) { 162714cf11afSPaul Mackerras /* start with vector = source number, and masked */ 16286e99e458SBenjamin Herrenschmidt u32 vecpri = MPIC_VECPRI_MASK | i | 16296e99e458SBenjamin Herrenschmidt (8 << MPIC_VECPRI_PRIORITY_SHIFT); 163014cf11afSPaul Mackerras 16317fd72186SBenjamin Herrenschmidt /* check if protected */ 16327fd72186SBenjamin Herrenschmidt if (mpic->protected && test_bit(i, mpic->protected)) 16337fd72186SBenjamin Herrenschmidt continue; 163414cf11afSPaul Mackerras /* init hw */ 16357233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); 1636cc353c30SArnd Bergmann mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu); 163714cf11afSPaul Mackerras } 1638dfec2202SMeador Inge } 163914cf11afSPaul Mackerras 16407df2457dSOlof Johansson /* Init spurious vector */ 16417df2457dSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), mpic->spurious_vec); 164214cf11afSPaul Mackerras 16437233593bSZang Roy-r61911 /* Disable 8259 passthrough, if supported */ 16447233593bSZang Roy-r61911 if (!(mpic->flags & MPIC_NO_PTHROU_DIS)) 16457233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 16467233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 164714cf11afSPaul Mackerras | MPIC_GREG_GCONF_8259_PTHROU_DIS); 164814cf11afSPaul Mackerras 1649d87bf3beSOlof Johansson if (mpic->flags & MPIC_NO_BIAS) 1650d87bf3beSOlof Johansson mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1651d87bf3beSOlof Johansson mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1652d87bf3beSOlof Johansson | MPIC_GREG_GCONF_NO_BIAS); 1653d87bf3beSOlof Johansson 165414cf11afSPaul Mackerras /* Set current processor priority to 0 */ 16557233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 16563669e930SJohannes Berg 16573669e930SJohannes Berg #ifdef CONFIG_PM 16583669e930SJohannes Berg /* allocate memory to save mpic state */ 1659ea96025aSAnton Vorontsov mpic->save_data = kmalloc(mpic->num_sources * sizeof(*mpic->save_data), 1660ea96025aSAnton Vorontsov GFP_KERNEL); 16613669e930SJohannes Berg BUG_ON(mpic->save_data == NULL); 16623669e930SJohannes Berg #endif 166309dc34a9SKyle Moffett 166409dc34a9SKyle Moffett /* Check if this MPIC is chained from a parent interrupt controller */ 166509dc34a9SKyle Moffett if (mpic->flags & MPIC_SECONDARY) { 166609dc34a9SKyle Moffett int virq = irq_of_parse_and_map(mpic->node, 0); 166709dc34a9SKyle Moffett if (virq != NO_IRQ) { 166809dc34a9SKyle Moffett printk(KERN_INFO "%s: hooking up to IRQ %d\n", 166909dc34a9SKyle Moffett mpic->node->full_name, virq); 167009dc34a9SKyle Moffett irq_set_handler_data(virq, mpic); 167109dc34a9SKyle Moffett irq_set_chained_handler(virq, &mpic_cascade); 167209dc34a9SKyle Moffett } 167309dc34a9SKyle Moffett } 1674aa80581dSScott Wood 1675aa80581dSScott Wood /* FSL mpic error interrupt intialization */ 1676aa80581dSScott Wood if (mpic->flags & MPIC_FSL_HAS_EIMR) 1677aa80581dSScott Wood mpic_err_int_init(mpic, MPIC_FSL_ERR_INT); 167814cf11afSPaul Mackerras } 167914cf11afSPaul Mackerras 1680868ea0c9SMark A. Greer void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) 1681868ea0c9SMark A. Greer { 1682868ea0c9SMark A. Greer u32 v; 168314cf11afSPaul Mackerras 1684868ea0c9SMark A. Greer v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 1685868ea0c9SMark A. Greer v &= ~MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK; 1686868ea0c9SMark A. Greer v |= MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(clock_ratio); 1687868ea0c9SMark A. Greer mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 1688868ea0c9SMark A. Greer } 1689868ea0c9SMark A. Greer 1690868ea0c9SMark A. Greer void __init mpic_set_serial_int(struct mpic *mpic, int enable) 1691868ea0c9SMark A. Greer { 1692ba1826e5SBenjamin Herrenschmidt unsigned long flags; 1693868ea0c9SMark A. Greer u32 v; 1694868ea0c9SMark A. Greer 1695203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic_lock, flags); 1696868ea0c9SMark A. Greer v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 1697868ea0c9SMark A. Greer if (enable) 1698868ea0c9SMark A. Greer v |= MPIC_GREG_GLOBAL_CONF_1_SIE; 1699868ea0c9SMark A. Greer else 1700868ea0c9SMark A. Greer v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE; 1701868ea0c9SMark A. Greer mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 1702203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic_lock, flags); 1703868ea0c9SMark A. Greer } 170414cf11afSPaul Mackerras 170514cf11afSPaul Mackerras void mpic_irq_set_priority(unsigned int irq, unsigned int pri) 170614cf11afSPaul Mackerras { 1707d69a78d7STony Breeds struct mpic *mpic = mpic_find(irq); 1708476eb491SGrant Likely unsigned int src = virq_to_hw(irq); 170914cf11afSPaul Mackerras unsigned long flags; 171014cf11afSPaul Mackerras u32 reg; 171114cf11afSPaul Mackerras 171206a901c5SStephen Rothwell if (!mpic) 171306a901c5SStephen Rothwell return; 171406a901c5SStephen Rothwell 1715203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic_lock, flags); 17163a2b4f7cSBenjamin Herrenschmidt if (mpic_is_ipi(mpic, src)) { 17177df2457dSOlof Johansson reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) & 1718e5356640SBenjamin Herrenschmidt ~MPIC_VECPRI_PRIORITY_MASK; 17197df2457dSOlof Johansson mpic_ipi_write(src - mpic->ipi_vecs[0], 172014cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 17213a2b4f7cSBenjamin Herrenschmidt } else if (mpic_is_tm(mpic, src)) { 1722ea94187fSScott Wood reg = mpic_tm_read(src - mpic->timer_vecs[0]) & 1723ea94187fSScott Wood ~MPIC_VECPRI_PRIORITY_MASK; 1724ea94187fSScott Wood mpic_tm_write(src - mpic->timer_vecs[0], 1725ea94187fSScott Wood reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 172614cf11afSPaul Mackerras } else { 17277233593bSZang Roy-r61911 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) 1728e5356640SBenjamin Herrenschmidt & ~MPIC_VECPRI_PRIORITY_MASK; 17297233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 173014cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 173114cf11afSPaul Mackerras } 1732203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic_lock, flags); 173314cf11afSPaul Mackerras } 173414cf11afSPaul Mackerras 173514cf11afSPaul Mackerras void mpic_setup_this_cpu(void) 173614cf11afSPaul Mackerras { 173714cf11afSPaul Mackerras #ifdef CONFIG_SMP 173814cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 173914cf11afSPaul Mackerras unsigned long flags; 174014cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 174114cf11afSPaul Mackerras unsigned int i; 174214cf11afSPaul Mackerras 174314cf11afSPaul Mackerras BUG_ON(mpic == NULL); 174414cf11afSPaul Mackerras 174514cf11afSPaul Mackerras DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 174614cf11afSPaul Mackerras 1747203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic_lock, flags); 174814cf11afSPaul Mackerras 174914cf11afSPaul Mackerras /* let the mpic know we want intrs. default affinity is 0xffffffff 175014cf11afSPaul Mackerras * until changed via /proc. That's how it's done on x86. If we want 175114cf11afSPaul Mackerras * it differently, then we should make sure we also change the default 1752a53da52fSIngo Molnar * values of irq_desc[].affinity in irq.c. 175314cf11afSPaul Mackerras */ 1754e242114aSchenhui zhao if (distribute_irqs && !(mpic->flags & MPIC_SINGLE_DEST_CPU)) { 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 176014cf11afSPaul Mackerras /* Set current processor priority to 0 */ 17617233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 176214cf11afSPaul Mackerras 1763203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic_lock, flags); 176414cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 176514cf11afSPaul Mackerras } 176614cf11afSPaul Mackerras 176714cf11afSPaul Mackerras int mpic_cpu_get_priority(void) 176814cf11afSPaul Mackerras { 176914cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 177014cf11afSPaul Mackerras 17717233593bSZang Roy-r61911 return mpic_cpu_read(MPIC_INFO(CPU_CURRENT_TASK_PRI)); 177214cf11afSPaul Mackerras } 177314cf11afSPaul Mackerras 177414cf11afSPaul Mackerras void mpic_cpu_set_priority(int prio) 177514cf11afSPaul Mackerras { 177614cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 177714cf11afSPaul Mackerras 177814cf11afSPaul Mackerras prio &= MPIC_CPU_TASKPRI_MASK; 17797233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), prio); 178014cf11afSPaul Mackerras } 178114cf11afSPaul Mackerras 178214cf11afSPaul Mackerras void mpic_teardown_this_cpu(int secondary) 178314cf11afSPaul Mackerras { 178414cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 178514cf11afSPaul Mackerras unsigned long flags; 178614cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 178714cf11afSPaul Mackerras unsigned int i; 178814cf11afSPaul Mackerras 178914cf11afSPaul Mackerras BUG_ON(mpic == NULL); 179014cf11afSPaul Mackerras 179114cf11afSPaul Mackerras DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 1792203041adSThomas Gleixner raw_spin_lock_irqsave(&mpic_lock, flags); 179314cf11afSPaul Mackerras 179414cf11afSPaul Mackerras /* let the mpic know we don't want intrs. */ 179514cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources ; i++) 17967233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 17977233593bSZang Roy-r61911 mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) & ~msk); 179814cf11afSPaul Mackerras 179914cf11afSPaul Mackerras /* Set current processor priority to max */ 18007233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 18017132799bSValentine Barshak /* We need to EOI the IPI since not all platforms reset the MPIC 18027132799bSValentine Barshak * on boot and new interrupts wouldn't get delivered otherwise. 18037132799bSValentine Barshak */ 18047132799bSValentine Barshak mpic_eoi(mpic); 180514cf11afSPaul Mackerras 1806203041adSThomas Gleixner raw_spin_unlock_irqrestore(&mpic_lock, flags); 180714cf11afSPaul Mackerras } 180814cf11afSPaul Mackerras 180914cf11afSPaul Mackerras 1810f365355eSOlof Johansson static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg) 181114cf11afSPaul Mackerras { 18120ebfff14SBenjamin Herrenschmidt u32 src; 181314cf11afSPaul Mackerras 1814f365355eSOlof Johansson src = mpic_cpu_read(reg) & MPIC_INFO(VECPRI_VECTOR_MASK); 18151beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_LOW 1816f365355eSOlof Johansson DBG("%s: get_one_irq(reg 0x%x): %d\n", mpic->name, reg, src); 18171beb6a7dSBenjamin Herrenschmidt #endif 18185cddd2e3SJosh Boyer if (unlikely(src == mpic->spurious_vec)) { 18195cddd2e3SJosh Boyer if (mpic->flags & MPIC_SPV_EOI) 18205cddd2e3SJosh Boyer mpic_eoi(mpic); 18210ebfff14SBenjamin Herrenschmidt return NO_IRQ; 18225cddd2e3SJosh Boyer } 18237fd72186SBenjamin Herrenschmidt if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { 182476462232SChristian Dietrich printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n", 18257fd72186SBenjamin Herrenschmidt mpic->name, (int)src); 18267fd72186SBenjamin Herrenschmidt mpic_eoi(mpic); 18277fd72186SBenjamin Herrenschmidt return NO_IRQ; 18287fd72186SBenjamin Herrenschmidt } 18297fd72186SBenjamin Herrenschmidt 18300ebfff14SBenjamin Herrenschmidt return irq_linear_revmap(mpic->irqhost, src); 183114cf11afSPaul Mackerras } 183214cf11afSPaul Mackerras 1833f365355eSOlof Johansson unsigned int mpic_get_one_irq(struct mpic *mpic) 1834f365355eSOlof Johansson { 1835f365355eSOlof Johansson return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_INTACK)); 1836f365355eSOlof Johansson } 1837f365355eSOlof Johansson 183835a84c2fSOlaf Hering unsigned int mpic_get_irq(void) 183914cf11afSPaul Mackerras { 184014cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 184114cf11afSPaul Mackerras 184214cf11afSPaul Mackerras BUG_ON(mpic == NULL); 184314cf11afSPaul Mackerras 184435a84c2fSOlaf Hering return mpic_get_one_irq(mpic); 184514cf11afSPaul Mackerras } 184614cf11afSPaul Mackerras 1847d91e4ea7SKumar Gala unsigned int mpic_get_coreint_irq(void) 1848d91e4ea7SKumar Gala { 1849d91e4ea7SKumar Gala #ifdef CONFIG_BOOKE 1850d91e4ea7SKumar Gala struct mpic *mpic = mpic_primary; 1851d91e4ea7SKumar Gala u32 src; 1852d91e4ea7SKumar Gala 1853d91e4ea7SKumar Gala BUG_ON(mpic == NULL); 1854d91e4ea7SKumar Gala 1855d91e4ea7SKumar Gala src = mfspr(SPRN_EPR); 1856d91e4ea7SKumar Gala 1857d91e4ea7SKumar Gala if (unlikely(src == mpic->spurious_vec)) { 1858d91e4ea7SKumar Gala if (mpic->flags & MPIC_SPV_EOI) 1859d91e4ea7SKumar Gala mpic_eoi(mpic); 1860d91e4ea7SKumar Gala return NO_IRQ; 1861d91e4ea7SKumar Gala } 1862d91e4ea7SKumar Gala if (unlikely(mpic->protected && test_bit(src, mpic->protected))) { 186376462232SChristian Dietrich printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n", 1864d91e4ea7SKumar Gala mpic->name, (int)src); 1865d91e4ea7SKumar Gala return NO_IRQ; 1866d91e4ea7SKumar Gala } 1867d91e4ea7SKumar Gala 1868d91e4ea7SKumar Gala return irq_linear_revmap(mpic->irqhost, src); 1869d91e4ea7SKumar Gala #else 1870d91e4ea7SKumar Gala return NO_IRQ; 1871d91e4ea7SKumar Gala #endif 1872d91e4ea7SKumar Gala } 1873d91e4ea7SKumar Gala 1874f365355eSOlof Johansson unsigned int mpic_get_mcirq(void) 1875f365355eSOlof Johansson { 1876f365355eSOlof Johansson struct mpic *mpic = mpic_primary; 1877f365355eSOlof Johansson 1878f365355eSOlof Johansson BUG_ON(mpic == NULL); 1879f365355eSOlof Johansson 1880f365355eSOlof Johansson return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_MCACK)); 1881f365355eSOlof Johansson } 188214cf11afSPaul Mackerras 188314cf11afSPaul Mackerras #ifdef CONFIG_SMP 188414cf11afSPaul Mackerras void mpic_request_ipis(void) 188514cf11afSPaul Mackerras { 188614cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 188778608dd3SMilton Miller int i; 188814cf11afSPaul Mackerras BUG_ON(mpic == NULL); 188914cf11afSPaul Mackerras 18900ebfff14SBenjamin Herrenschmidt printk(KERN_INFO "mpic: requesting IPIs...\n"); 189114cf11afSPaul Mackerras 18920ebfff14SBenjamin Herrenschmidt for (i = 0; i < 4; i++) { 18930ebfff14SBenjamin Herrenschmidt unsigned int vipi = irq_create_mapping(mpic->irqhost, 18947df2457dSOlof Johansson mpic->ipi_vecs[0] + i); 18950ebfff14SBenjamin Herrenschmidt if (vipi == NO_IRQ) { 189678608dd3SMilton Miller printk(KERN_ERR "Failed to map %s\n", smp_ipi_name[i]); 189778608dd3SMilton Miller continue; 18980ebfff14SBenjamin Herrenschmidt } 189978608dd3SMilton Miller smp_request_message_ipi(vipi, i); 19000ebfff14SBenjamin Herrenschmidt } 190114cf11afSPaul Mackerras } 1902a9c59264SPaul Mackerras 19033caba98fSMilton Miller void smp_mpic_message_pass(int cpu, int msg) 19042ef613cbSBenjamin Herrenschmidt { 19052ef613cbSBenjamin Herrenschmidt struct mpic *mpic = mpic_primary; 19063caba98fSMilton Miller u32 physmask; 19072ef613cbSBenjamin Herrenschmidt 19082ef613cbSBenjamin Herrenschmidt BUG_ON(mpic == NULL); 19092ef613cbSBenjamin Herrenschmidt 1910a9c59264SPaul Mackerras /* make sure we're sending something that translates to an IPI */ 1911a9c59264SPaul Mackerras if ((unsigned int)msg > 3) { 1912a9c59264SPaul Mackerras printk("SMP %d: smp_message_pass: unknown msg %d\n", 1913a9c59264SPaul Mackerras smp_processor_id(), msg); 1914a9c59264SPaul Mackerras return; 1915a9c59264SPaul Mackerras } 19163caba98fSMilton Miller 19173caba98fSMilton Miller #ifdef DEBUG_IPI 19183caba98fSMilton Miller DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, msg); 19193caba98fSMilton Miller #endif 19203caba98fSMilton Miller 19213caba98fSMilton Miller physmask = 1 << get_hard_smp_processor_id(cpu); 19223caba98fSMilton Miller 19233caba98fSMilton Miller mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + 19243caba98fSMilton Miller msg * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), physmask); 1925a9c59264SPaul Mackerras } 1926775aeff4SMichael Ellerman 1927775aeff4SMichael Ellerman int __init smp_mpic_probe(void) 1928775aeff4SMichael Ellerman { 1929775aeff4SMichael Ellerman int nr_cpus; 1930775aeff4SMichael Ellerman 1931775aeff4SMichael Ellerman DBG("smp_mpic_probe()...\n"); 1932775aeff4SMichael Ellerman 19332ef613cbSBenjamin Herrenschmidt nr_cpus = cpumask_weight(cpu_possible_mask); 1934775aeff4SMichael Ellerman 1935775aeff4SMichael Ellerman DBG("nr_cpus: %d\n", nr_cpus); 1936775aeff4SMichael Ellerman 1937775aeff4SMichael Ellerman if (nr_cpus > 1) 1938775aeff4SMichael Ellerman mpic_request_ipis(); 1939775aeff4SMichael Ellerman 1940775aeff4SMichael Ellerman return nr_cpus; 1941775aeff4SMichael Ellerman } 1942775aeff4SMichael Ellerman 1943cad5cef6SGreg Kroah-Hartman void smp_mpic_setup_cpu(int cpu) 1944775aeff4SMichael Ellerman { 1945775aeff4SMichael Ellerman mpic_setup_this_cpu(); 1946775aeff4SMichael Ellerman } 194766953ebeSMatthew McClintock 194866953ebeSMatthew McClintock void mpic_reset_core(int cpu) 194966953ebeSMatthew McClintock { 195066953ebeSMatthew McClintock struct mpic *mpic = mpic_primary; 195166953ebeSMatthew McClintock u32 pir; 195266953ebeSMatthew McClintock int cpuid = get_hard_smp_processor_id(cpu); 195344f16fcfSMatthew McClintock int i; 195466953ebeSMatthew McClintock 195566953ebeSMatthew McClintock /* Set target bit for core reset */ 195666953ebeSMatthew McClintock pir = mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); 195766953ebeSMatthew McClintock pir |= (1 << cpuid); 195866953ebeSMatthew McClintock mpic_write(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT), pir); 195966953ebeSMatthew McClintock mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); 196066953ebeSMatthew McClintock 196166953ebeSMatthew McClintock /* Restore target bit after reset complete */ 196266953ebeSMatthew McClintock pir &= ~(1 << cpuid); 196366953ebeSMatthew McClintock mpic_write(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT), pir); 196466953ebeSMatthew McClintock mpic_read(mpic->gregs, MPIC_INFO(GREG_PROCESSOR_INIT)); 196544f16fcfSMatthew McClintock 196644f16fcfSMatthew McClintock /* Perform 15 EOI on each reset core to clear pending interrupts. 196744f16fcfSMatthew McClintock * This is required for FSL CoreNet based devices */ 196844f16fcfSMatthew McClintock if (mpic->flags & MPIC_FSL) { 196944f16fcfSMatthew McClintock for (i = 0; i < 15; i++) { 197044f16fcfSMatthew McClintock _mpic_write(mpic->reg_type, &mpic->cpuregs[cpuid], 197144f16fcfSMatthew McClintock MPIC_CPU_EOI, 0); 197244f16fcfSMatthew McClintock } 197344f16fcfSMatthew McClintock } 197466953ebeSMatthew McClintock } 197514cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 19763669e930SJohannes Berg 19773669e930SJohannes Berg #ifdef CONFIG_PM 1978f5a592f7SRafael J. Wysocki static void mpic_suspend_one(struct mpic *mpic) 19793669e930SJohannes Berg { 19803669e930SJohannes Berg int i; 19813669e930SJohannes Berg 19823669e930SJohannes Berg for (i = 0; i < mpic->num_sources; i++) { 19833669e930SJohannes Berg mpic->save_data[i].vecprio = 19843669e930SJohannes Berg mpic_irq_read(i, MPIC_INFO(IRQ_VECTOR_PRI)); 19853669e930SJohannes Berg mpic->save_data[i].dest = 19863669e930SJohannes Berg mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)); 19873669e930SJohannes Berg } 1988f5a592f7SRafael J. Wysocki } 1989f5a592f7SRafael J. Wysocki 1990f5a592f7SRafael J. Wysocki static int mpic_suspend(void) 1991f5a592f7SRafael J. Wysocki { 1992f5a592f7SRafael J. Wysocki struct mpic *mpic = mpics; 1993f5a592f7SRafael J. Wysocki 1994f5a592f7SRafael J. Wysocki while (mpic) { 1995f5a592f7SRafael J. Wysocki mpic_suspend_one(mpic); 1996f5a592f7SRafael J. Wysocki mpic = mpic->next; 1997f5a592f7SRafael J. Wysocki } 19983669e930SJohannes Berg 19993669e930SJohannes Berg return 0; 20003669e930SJohannes Berg } 20013669e930SJohannes Berg 2002f5a592f7SRafael J. Wysocki static void mpic_resume_one(struct mpic *mpic) 20033669e930SJohannes Berg { 20043669e930SJohannes Berg int i; 20053669e930SJohannes Berg 20063669e930SJohannes Berg for (i = 0; i < mpic->num_sources; i++) { 20073669e930SJohannes Berg mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), 20083669e930SJohannes Berg mpic->save_data[i].vecprio); 20093669e930SJohannes Berg mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 20103669e930SJohannes Berg mpic->save_data[i].dest); 20113669e930SJohannes Berg 20123669e930SJohannes Berg #ifdef CONFIG_MPIC_U3_HT_IRQS 20137c9d9360SAlastair Bridgewater if (mpic->fixups) { 20143669e930SJohannes Berg struct mpic_irq_fixup *fixup = &mpic->fixups[i]; 20153669e930SJohannes Berg 20163669e930SJohannes Berg if (fixup->base) { 20173669e930SJohannes Berg /* we use the lowest bit in an inverted meaning */ 20183669e930SJohannes Berg if ((mpic->save_data[i].fixup_data & 1) == 0) 20193669e930SJohannes Berg continue; 20203669e930SJohannes Berg 20213669e930SJohannes Berg /* Enable and configure */ 20223669e930SJohannes Berg writeb(0x10 + 2 * fixup->index, fixup->base + 2); 20233669e930SJohannes Berg 20243669e930SJohannes Berg writel(mpic->save_data[i].fixup_data & ~1, 20253669e930SJohannes Berg fixup->base + 4); 20263669e930SJohannes Berg } 20273669e930SJohannes Berg } 20283669e930SJohannes Berg #endif 20293669e930SJohannes Berg } /* end for loop */ 20303669e930SJohannes Berg } 20313669e930SJohannes Berg 2032f5a592f7SRafael J. Wysocki static void mpic_resume(void) 2033f5a592f7SRafael J. Wysocki { 2034f5a592f7SRafael J. Wysocki struct mpic *mpic = mpics; 2035f5a592f7SRafael J. Wysocki 2036f5a592f7SRafael J. Wysocki while (mpic) { 2037f5a592f7SRafael J. Wysocki mpic_resume_one(mpic); 2038f5a592f7SRafael J. Wysocki mpic = mpic->next; 2039f5a592f7SRafael J. Wysocki } 2040f5a592f7SRafael J. Wysocki } 2041f5a592f7SRafael J. Wysocki 2042f5a592f7SRafael J. Wysocki static struct syscore_ops mpic_syscore_ops = { 20433669e930SJohannes Berg .resume = mpic_resume, 20443669e930SJohannes Berg .suspend = mpic_suspend, 20453669e930SJohannes Berg }; 20463669e930SJohannes Berg 20473669e930SJohannes Berg static int mpic_init_sys(void) 20483669e930SJohannes Berg { 2049f5a592f7SRafael J. Wysocki register_syscore_ops(&mpic_syscore_ops); 20509e6f31a9SDongsheng.wang@freescale.com subsys_system_register(&mpic_subsys, NULL); 20519e6f31a9SDongsheng.wang@freescale.com 2052f5a592f7SRafael J. Wysocki return 0; 20533669e930SJohannes Berg } 20543669e930SJohannes Berg 20553669e930SJohannes Berg device_initcall(mpic_init_sys); 2056f5a592f7SRafael J. Wysocki #endif 2057