114cf11afSPaul Mackerras /* 214cf11afSPaul Mackerras * arch/powerpc/kernel/mpic.c 314cf11afSPaul Mackerras * 414cf11afSPaul Mackerras * Driver for interrupt controllers following the OpenPIC standard, the 514cf11afSPaul Mackerras * common implementation beeing IBM's MPIC. This driver also can deal 614cf11afSPaul Mackerras * with various broken implementations of this HW. 714cf11afSPaul Mackerras * 814cf11afSPaul Mackerras * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. 914cf11afSPaul Mackerras * 1014cf11afSPaul Mackerras * This file is subject to the terms and conditions of the GNU General Public 1114cf11afSPaul Mackerras * License. See the file COPYING in the main directory of this archive 1214cf11afSPaul Mackerras * for more details. 1314cf11afSPaul Mackerras */ 1414cf11afSPaul Mackerras 1514cf11afSPaul Mackerras #undef DEBUG 161beb6a7dSBenjamin Herrenschmidt #undef DEBUG_IPI 171beb6a7dSBenjamin Herrenschmidt #undef DEBUG_IRQ 181beb6a7dSBenjamin Herrenschmidt #undef DEBUG_LOW 1914cf11afSPaul Mackerras 2014cf11afSPaul Mackerras #include <linux/types.h> 2114cf11afSPaul Mackerras #include <linux/kernel.h> 2214cf11afSPaul Mackerras #include <linux/init.h> 2314cf11afSPaul Mackerras #include <linux/irq.h> 2414cf11afSPaul Mackerras #include <linux/smp.h> 2514cf11afSPaul Mackerras #include <linux/interrupt.h> 2614cf11afSPaul Mackerras #include <linux/bootmem.h> 2714cf11afSPaul Mackerras #include <linux/spinlock.h> 2814cf11afSPaul Mackerras #include <linux/pci.h> 2914cf11afSPaul Mackerras 3014cf11afSPaul Mackerras #include <asm/ptrace.h> 3114cf11afSPaul Mackerras #include <asm/signal.h> 3214cf11afSPaul Mackerras #include <asm/io.h> 3314cf11afSPaul Mackerras #include <asm/pgtable.h> 3414cf11afSPaul Mackerras #include <asm/irq.h> 3514cf11afSPaul Mackerras #include <asm/machdep.h> 3614cf11afSPaul Mackerras #include <asm/mpic.h> 3714cf11afSPaul Mackerras #include <asm/smp.h> 3814cf11afSPaul Mackerras 3914cf11afSPaul Mackerras #ifdef DEBUG 4014cf11afSPaul Mackerras #define DBG(fmt...) printk(fmt) 4114cf11afSPaul Mackerras #else 4214cf11afSPaul Mackerras #define DBG(fmt...) 4314cf11afSPaul Mackerras #endif 4414cf11afSPaul Mackerras 4514cf11afSPaul Mackerras static struct mpic *mpics; 4614cf11afSPaul Mackerras static struct mpic *mpic_primary; 4714cf11afSPaul Mackerras static DEFINE_SPINLOCK(mpic_lock); 4814cf11afSPaul Mackerras 49c0c0d996SPaul Mackerras #ifdef CONFIG_PPC32 /* XXX for now */ 50e40c7f02SAndy Whitcroft #ifdef CONFIG_IRQ_ALL_CPUS 51e40c7f02SAndy Whitcroft #define distribute_irqs (1) 52e40c7f02SAndy Whitcroft #else 53e40c7f02SAndy Whitcroft #define distribute_irqs (0) 54e40c7f02SAndy Whitcroft #endif 55c0c0d996SPaul Mackerras #endif 5614cf11afSPaul Mackerras 577233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 587233593bSZang Roy-r61911 static u32 mpic_infos[][MPIC_IDX_END] = { 597233593bSZang Roy-r61911 [0] = { /* Original OpenPIC compatible MPIC */ 607233593bSZang Roy-r61911 MPIC_GREG_BASE, 617233593bSZang Roy-r61911 MPIC_GREG_FEATURE_0, 627233593bSZang Roy-r61911 MPIC_GREG_GLOBAL_CONF_0, 637233593bSZang Roy-r61911 MPIC_GREG_VENDOR_ID, 647233593bSZang Roy-r61911 MPIC_GREG_IPI_VECTOR_PRI_0, 657233593bSZang Roy-r61911 MPIC_GREG_IPI_STRIDE, 667233593bSZang Roy-r61911 MPIC_GREG_SPURIOUS, 677233593bSZang Roy-r61911 MPIC_GREG_TIMER_FREQ, 687233593bSZang Roy-r61911 697233593bSZang Roy-r61911 MPIC_TIMER_BASE, 707233593bSZang Roy-r61911 MPIC_TIMER_STRIDE, 717233593bSZang Roy-r61911 MPIC_TIMER_CURRENT_CNT, 727233593bSZang Roy-r61911 MPIC_TIMER_BASE_CNT, 737233593bSZang Roy-r61911 MPIC_TIMER_VECTOR_PRI, 747233593bSZang Roy-r61911 MPIC_TIMER_DESTINATION, 757233593bSZang Roy-r61911 767233593bSZang Roy-r61911 MPIC_CPU_BASE, 777233593bSZang Roy-r61911 MPIC_CPU_STRIDE, 787233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_0, 797233593bSZang Roy-r61911 MPIC_CPU_IPI_DISPATCH_STRIDE, 807233593bSZang Roy-r61911 MPIC_CPU_CURRENT_TASK_PRI, 817233593bSZang Roy-r61911 MPIC_CPU_WHOAMI, 827233593bSZang Roy-r61911 MPIC_CPU_INTACK, 837233593bSZang Roy-r61911 MPIC_CPU_EOI, 847233593bSZang Roy-r61911 857233593bSZang Roy-r61911 MPIC_IRQ_BASE, 867233593bSZang Roy-r61911 MPIC_IRQ_STRIDE, 877233593bSZang Roy-r61911 MPIC_IRQ_VECTOR_PRI, 887233593bSZang Roy-r61911 MPIC_VECPRI_VECTOR_MASK, 897233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_POSITIVE, 907233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_NEGATIVE, 917233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_LEVEL, 927233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_EDGE, 937233593bSZang Roy-r61911 MPIC_VECPRI_POLARITY_MASK, 947233593bSZang Roy-r61911 MPIC_VECPRI_SENSE_MASK, 957233593bSZang Roy-r61911 MPIC_IRQ_DESTINATION 967233593bSZang Roy-r61911 }, 977233593bSZang Roy-r61911 [1] = { /* Tsi108/109 PIC */ 987233593bSZang Roy-r61911 TSI108_GREG_BASE, 997233593bSZang Roy-r61911 TSI108_GREG_FEATURE_0, 1007233593bSZang Roy-r61911 TSI108_GREG_GLOBAL_CONF_0, 1017233593bSZang Roy-r61911 TSI108_GREG_VENDOR_ID, 1027233593bSZang Roy-r61911 TSI108_GREG_IPI_VECTOR_PRI_0, 1037233593bSZang Roy-r61911 TSI108_GREG_IPI_STRIDE, 1047233593bSZang Roy-r61911 TSI108_GREG_SPURIOUS, 1057233593bSZang Roy-r61911 TSI108_GREG_TIMER_FREQ, 1067233593bSZang Roy-r61911 1077233593bSZang Roy-r61911 TSI108_TIMER_BASE, 1087233593bSZang Roy-r61911 TSI108_TIMER_STRIDE, 1097233593bSZang Roy-r61911 TSI108_TIMER_CURRENT_CNT, 1107233593bSZang Roy-r61911 TSI108_TIMER_BASE_CNT, 1117233593bSZang Roy-r61911 TSI108_TIMER_VECTOR_PRI, 1127233593bSZang Roy-r61911 TSI108_TIMER_DESTINATION, 1137233593bSZang Roy-r61911 1147233593bSZang Roy-r61911 TSI108_CPU_BASE, 1157233593bSZang Roy-r61911 TSI108_CPU_STRIDE, 1167233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_0, 1177233593bSZang Roy-r61911 TSI108_CPU_IPI_DISPATCH_STRIDE, 1187233593bSZang Roy-r61911 TSI108_CPU_CURRENT_TASK_PRI, 1197233593bSZang Roy-r61911 TSI108_CPU_WHOAMI, 1207233593bSZang Roy-r61911 TSI108_CPU_INTACK, 1217233593bSZang Roy-r61911 TSI108_CPU_EOI, 1227233593bSZang Roy-r61911 1237233593bSZang Roy-r61911 TSI108_IRQ_BASE, 1247233593bSZang Roy-r61911 TSI108_IRQ_STRIDE, 1257233593bSZang Roy-r61911 TSI108_IRQ_VECTOR_PRI, 1267233593bSZang Roy-r61911 TSI108_VECPRI_VECTOR_MASK, 1277233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_POSITIVE, 1287233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_NEGATIVE, 1297233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_LEVEL, 1307233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_EDGE, 1317233593bSZang Roy-r61911 TSI108_VECPRI_POLARITY_MASK, 1327233593bSZang Roy-r61911 TSI108_VECPRI_SENSE_MASK, 1337233593bSZang Roy-r61911 TSI108_IRQ_DESTINATION 1347233593bSZang Roy-r61911 }, 1357233593bSZang Roy-r61911 }; 1367233593bSZang Roy-r61911 1377233593bSZang Roy-r61911 #define MPIC_INFO(name) mpic->hw_set[MPIC_IDX_##name] 1387233593bSZang Roy-r61911 1397233593bSZang Roy-r61911 #else /* CONFIG_MPIC_WEIRD */ 1407233593bSZang Roy-r61911 1417233593bSZang Roy-r61911 #define MPIC_INFO(name) MPIC_##name 1427233593bSZang Roy-r61911 1437233593bSZang Roy-r61911 #endif /* CONFIG_MPIC_WEIRD */ 1447233593bSZang Roy-r61911 14514cf11afSPaul Mackerras /* 14614cf11afSPaul Mackerras * Register accessor functions 14714cf11afSPaul Mackerras */ 14814cf11afSPaul Mackerras 14914cf11afSPaul Mackerras 150fbf0274eSBenjamin Herrenschmidt static inline u32 _mpic_read(enum mpic_reg_type type, 151fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, 15214cf11afSPaul Mackerras unsigned int reg) 15314cf11afSPaul Mackerras { 154fbf0274eSBenjamin Herrenschmidt switch(type) { 155fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 156fbf0274eSBenjamin Herrenschmidt case mpic_access_dcr: 157fbf0274eSBenjamin Herrenschmidt return dcr_read(rb->dhost, 158fbf0274eSBenjamin Herrenschmidt rb->dbase + reg + rb->doff); 159fbf0274eSBenjamin Herrenschmidt #endif 160fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_be: 161fbf0274eSBenjamin Herrenschmidt return in_be32(rb->base + (reg >> 2)); 162fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_le: 163fbf0274eSBenjamin Herrenschmidt default: 164fbf0274eSBenjamin Herrenschmidt return in_le32(rb->base + (reg >> 2)); 165fbf0274eSBenjamin Herrenschmidt } 16614cf11afSPaul Mackerras } 16714cf11afSPaul Mackerras 168fbf0274eSBenjamin Herrenschmidt static inline void _mpic_write(enum mpic_reg_type type, 169fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, 17014cf11afSPaul Mackerras unsigned int reg, u32 value) 17114cf11afSPaul Mackerras { 172fbf0274eSBenjamin Herrenschmidt switch(type) { 173fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 174fbf0274eSBenjamin Herrenschmidt case mpic_access_dcr: 175fbf0274eSBenjamin Herrenschmidt return dcr_write(rb->dhost, 176fbf0274eSBenjamin Herrenschmidt rb->dbase + reg + rb->doff, value); 177fbf0274eSBenjamin Herrenschmidt #endif 178fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_be: 179fbf0274eSBenjamin Herrenschmidt return out_be32(rb->base + (reg >> 2), value); 180fbf0274eSBenjamin Herrenschmidt case mpic_access_mmio_le: 181fbf0274eSBenjamin Herrenschmidt default: 182fbf0274eSBenjamin Herrenschmidt return out_le32(rb->base + (reg >> 2), value); 183fbf0274eSBenjamin Herrenschmidt } 18414cf11afSPaul Mackerras } 18514cf11afSPaul Mackerras 18614cf11afSPaul Mackerras static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) 18714cf11afSPaul Mackerras { 188fbf0274eSBenjamin Herrenschmidt enum mpic_reg_type type = mpic->reg_type; 1897233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 1907233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 19114cf11afSPaul Mackerras 192fbf0274eSBenjamin Herrenschmidt if ((mpic->flags & MPIC_BROKEN_IPI) && type == mpic_access_mmio_le) 193fbf0274eSBenjamin Herrenschmidt type = mpic_access_mmio_be; 194fbf0274eSBenjamin Herrenschmidt return _mpic_read(type, &mpic->gregs, offset); 19514cf11afSPaul Mackerras } 19614cf11afSPaul Mackerras 19714cf11afSPaul Mackerras static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) 19814cf11afSPaul Mackerras { 1997233593bSZang Roy-r61911 unsigned int offset = MPIC_INFO(GREG_IPI_VECTOR_PRI_0) + 2007233593bSZang Roy-r61911 (ipi * MPIC_INFO(GREG_IPI_STRIDE)); 20114cf11afSPaul Mackerras 202fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); 20314cf11afSPaul Mackerras } 20414cf11afSPaul Mackerras 20514cf11afSPaul Mackerras static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) 20614cf11afSPaul Mackerras { 20714cf11afSPaul Mackerras unsigned int cpu = 0; 20814cf11afSPaul Mackerras 20914cf11afSPaul Mackerras if (mpic->flags & MPIC_PRIMARY) 21014cf11afSPaul Mackerras cpu = hard_smp_processor_id(); 211fbf0274eSBenjamin Herrenschmidt return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg); 21214cf11afSPaul Mackerras } 21314cf11afSPaul Mackerras 21414cf11afSPaul Mackerras static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) 21514cf11afSPaul Mackerras { 21614cf11afSPaul Mackerras unsigned int cpu = 0; 21714cf11afSPaul Mackerras 21814cf11afSPaul Mackerras if (mpic->flags & MPIC_PRIMARY) 21914cf11afSPaul Mackerras cpu = hard_smp_processor_id(); 22014cf11afSPaul Mackerras 221fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value); 22214cf11afSPaul Mackerras } 22314cf11afSPaul Mackerras 22414cf11afSPaul Mackerras static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) 22514cf11afSPaul Mackerras { 22614cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 22714cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 22814cf11afSPaul Mackerras 229fbf0274eSBenjamin Herrenschmidt return _mpic_read(mpic->reg_type, &mpic->isus[isu], 2307233593bSZang Roy-r61911 reg + (idx * MPIC_INFO(IRQ_STRIDE))); 23114cf11afSPaul Mackerras } 23214cf11afSPaul Mackerras 23314cf11afSPaul Mackerras static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, 23414cf11afSPaul Mackerras unsigned int reg, u32 value) 23514cf11afSPaul Mackerras { 23614cf11afSPaul Mackerras unsigned int isu = src_no >> mpic->isu_shift; 23714cf11afSPaul Mackerras unsigned int idx = src_no & mpic->isu_mask; 23814cf11afSPaul Mackerras 239fbf0274eSBenjamin Herrenschmidt _mpic_write(mpic->reg_type, &mpic->isus[isu], 2407233593bSZang Roy-r61911 reg + (idx * MPIC_INFO(IRQ_STRIDE)), value); 24114cf11afSPaul Mackerras } 24214cf11afSPaul Mackerras 243fbf0274eSBenjamin Herrenschmidt #define mpic_read(b,r) _mpic_read(mpic->reg_type,&(b),(r)) 244fbf0274eSBenjamin Herrenschmidt #define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v)) 24514cf11afSPaul Mackerras #define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) 24614cf11afSPaul Mackerras #define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) 24714cf11afSPaul Mackerras #define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) 24814cf11afSPaul Mackerras #define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) 24914cf11afSPaul Mackerras #define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) 25014cf11afSPaul Mackerras #define mpic_irq_write(s,r,v) _mpic_irq_write(mpic,(s),(r),(v)) 25114cf11afSPaul Mackerras 25214cf11afSPaul Mackerras 25314cf11afSPaul Mackerras /* 25414cf11afSPaul Mackerras * Low level utility functions 25514cf11afSPaul Mackerras */ 25614cf11afSPaul Mackerras 25714cf11afSPaul Mackerras 258fbf0274eSBenjamin Herrenschmidt static void _mpic_map_mmio(struct mpic *mpic, unsigned long phys_addr, 259fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, unsigned int offset, 260fbf0274eSBenjamin Herrenschmidt unsigned int size) 261fbf0274eSBenjamin Herrenschmidt { 262fbf0274eSBenjamin Herrenschmidt rb->base = ioremap(phys_addr + offset, size); 263fbf0274eSBenjamin Herrenschmidt BUG_ON(rb->base == NULL); 264fbf0274eSBenjamin Herrenschmidt } 265fbf0274eSBenjamin Herrenschmidt 266fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 267fbf0274eSBenjamin Herrenschmidt static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb, 268fbf0274eSBenjamin Herrenschmidt unsigned int offset, unsigned int size) 269fbf0274eSBenjamin Herrenschmidt { 270fbf0274eSBenjamin Herrenschmidt rb->dbase = mpic->dcr_base; 271fbf0274eSBenjamin Herrenschmidt rb->doff = offset; 272fbf0274eSBenjamin Herrenschmidt rb->dhost = dcr_map(mpic->of_node, rb->dbase + rb->doff, size); 273fbf0274eSBenjamin Herrenschmidt BUG_ON(!DCR_MAP_OK(rb->dhost)); 274fbf0274eSBenjamin Herrenschmidt } 275fbf0274eSBenjamin Herrenschmidt 276fbf0274eSBenjamin Herrenschmidt static inline void mpic_map(struct mpic *mpic, unsigned long phys_addr, 277fbf0274eSBenjamin Herrenschmidt struct mpic_reg_bank *rb, unsigned int offset, 278fbf0274eSBenjamin Herrenschmidt unsigned int size) 279fbf0274eSBenjamin Herrenschmidt { 280fbf0274eSBenjamin Herrenschmidt if (mpic->flags & MPIC_USES_DCR) 281fbf0274eSBenjamin Herrenschmidt _mpic_map_dcr(mpic, rb, offset, size); 282fbf0274eSBenjamin Herrenschmidt else 283fbf0274eSBenjamin Herrenschmidt _mpic_map_mmio(mpic, phys_addr, rb, offset, size); 284fbf0274eSBenjamin Herrenschmidt } 285fbf0274eSBenjamin Herrenschmidt #else /* CONFIG_PPC_DCR */ 286fbf0274eSBenjamin Herrenschmidt #define mpic_map(m,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) 287fbf0274eSBenjamin Herrenschmidt #endif /* !CONFIG_PPC_DCR */ 288fbf0274eSBenjamin Herrenschmidt 289fbf0274eSBenjamin Herrenschmidt 29014cf11afSPaul Mackerras 29114cf11afSPaul Mackerras /* Check if we have one of those nice broken MPICs with a flipped endian on 29214cf11afSPaul Mackerras * reads from IPI registers 29314cf11afSPaul Mackerras */ 29414cf11afSPaul Mackerras static void __init mpic_test_broken_ipi(struct mpic *mpic) 29514cf11afSPaul Mackerras { 29614cf11afSPaul Mackerras u32 r; 29714cf11afSPaul Mackerras 2987233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0), MPIC_VECPRI_MASK); 2997233593bSZang Roy-r61911 r = mpic_read(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0)); 30014cf11afSPaul Mackerras 30114cf11afSPaul Mackerras if (r == le32_to_cpu(MPIC_VECPRI_MASK)) { 30214cf11afSPaul Mackerras printk(KERN_INFO "mpic: Detected reversed IPI registers\n"); 30314cf11afSPaul Mackerras mpic->flags |= MPIC_BROKEN_IPI; 30414cf11afSPaul Mackerras } 30514cf11afSPaul Mackerras } 30614cf11afSPaul Mackerras 30714cf11afSPaul Mackerras #ifdef CONFIG_MPIC_BROKEN_U3 30814cf11afSPaul Mackerras 30914cf11afSPaul Mackerras /* Test if an interrupt is sourced from HyperTransport (used on broken U3s) 31014cf11afSPaul Mackerras * to force the edge setting on the MPIC and do the ack workaround. 31114cf11afSPaul Mackerras */ 3121beb6a7dSBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 31314cf11afSPaul Mackerras { 3141beb6a7dSBenjamin Herrenschmidt if (source >= 128 || !mpic->fixups) 31514cf11afSPaul Mackerras return 0; 3161beb6a7dSBenjamin Herrenschmidt return mpic->fixups[source].base != NULL; 31714cf11afSPaul Mackerras } 31814cf11afSPaul Mackerras 319c4b22f26SSegher Boessenkool 3201beb6a7dSBenjamin Herrenschmidt static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source) 32114cf11afSPaul Mackerras { 3221beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 32314cf11afSPaul Mackerras 3241beb6a7dSBenjamin Herrenschmidt if (fixup->applebase) { 3251beb6a7dSBenjamin Herrenschmidt unsigned int soff = (fixup->index >> 3) & ~3; 3261beb6a7dSBenjamin Herrenschmidt unsigned int mask = 1U << (fixup->index & 0x1f); 3271beb6a7dSBenjamin Herrenschmidt writel(mask, fixup->applebase + soff); 3281beb6a7dSBenjamin Herrenschmidt } else { 32914cf11afSPaul Mackerras spin_lock(&mpic->fixup_lock); 3301beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * fixup->index, fixup->base + 2); 331c4b22f26SSegher Boessenkool writel(fixup->data, fixup->base + 4); 33214cf11afSPaul Mackerras spin_unlock(&mpic->fixup_lock); 33314cf11afSPaul Mackerras } 3341beb6a7dSBenjamin Herrenschmidt } 33514cf11afSPaul Mackerras 3361beb6a7dSBenjamin Herrenschmidt static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source, 3371beb6a7dSBenjamin Herrenschmidt unsigned int irqflags) 3381beb6a7dSBenjamin Herrenschmidt { 3391beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 3401beb6a7dSBenjamin Herrenschmidt unsigned long flags; 3411beb6a7dSBenjamin Herrenschmidt u32 tmp; 34214cf11afSPaul Mackerras 3431beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 3441beb6a7dSBenjamin Herrenschmidt return; 3451beb6a7dSBenjamin Herrenschmidt 34606fe98e6SBenjamin Herrenschmidt DBG("startup_ht_interrupt(0x%x, 0x%x) index: %d\n", 3471beb6a7dSBenjamin Herrenschmidt source, irqflags, fixup->index); 3481beb6a7dSBenjamin Herrenschmidt spin_lock_irqsave(&mpic->fixup_lock, flags); 3491beb6a7dSBenjamin Herrenschmidt /* Enable and configure */ 3501beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 3511beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 3521beb6a7dSBenjamin Herrenschmidt tmp &= ~(0x23U); 3531beb6a7dSBenjamin Herrenschmidt if (irqflags & IRQ_LEVEL) 3541beb6a7dSBenjamin Herrenschmidt tmp |= 0x22; 3551beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 3561beb6a7dSBenjamin Herrenschmidt spin_unlock_irqrestore(&mpic->fixup_lock, flags); 3571beb6a7dSBenjamin Herrenschmidt } 3581beb6a7dSBenjamin Herrenschmidt 3591beb6a7dSBenjamin Herrenschmidt static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source, 3601beb6a7dSBenjamin Herrenschmidt unsigned int irqflags) 3611beb6a7dSBenjamin Herrenschmidt { 3621beb6a7dSBenjamin Herrenschmidt struct mpic_irq_fixup *fixup = &mpic->fixups[source]; 3631beb6a7dSBenjamin Herrenschmidt unsigned long flags; 3641beb6a7dSBenjamin Herrenschmidt u32 tmp; 3651beb6a7dSBenjamin Herrenschmidt 3661beb6a7dSBenjamin Herrenschmidt if (fixup->base == NULL) 3671beb6a7dSBenjamin Herrenschmidt return; 3681beb6a7dSBenjamin Herrenschmidt 36906fe98e6SBenjamin Herrenschmidt DBG("shutdown_ht_interrupt(0x%x, 0x%x)\n", source, irqflags); 3701beb6a7dSBenjamin Herrenschmidt 3711beb6a7dSBenjamin Herrenschmidt /* Disable */ 3721beb6a7dSBenjamin Herrenschmidt spin_lock_irqsave(&mpic->fixup_lock, flags); 3731beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * fixup->index, fixup->base + 2); 3741beb6a7dSBenjamin Herrenschmidt tmp = readl(fixup->base + 4); 37572b13819SSegher Boessenkool tmp |= 1; 3761beb6a7dSBenjamin Herrenschmidt writel(tmp, fixup->base + 4); 3771beb6a7dSBenjamin Herrenschmidt spin_unlock_irqrestore(&mpic->fixup_lock, flags); 3781beb6a7dSBenjamin Herrenschmidt } 3791beb6a7dSBenjamin Herrenschmidt 3801beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, 3811beb6a7dSBenjamin Herrenschmidt unsigned int devfn, u32 vdid) 38214cf11afSPaul Mackerras { 383c4b22f26SSegher Boessenkool int i, irq, n; 3841beb6a7dSBenjamin Herrenschmidt u8 __iomem *base; 38514cf11afSPaul Mackerras u32 tmp; 386c4b22f26SSegher Boessenkool u8 pos; 38714cf11afSPaul Mackerras 3881beb6a7dSBenjamin Herrenschmidt for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; 3891beb6a7dSBenjamin Herrenschmidt pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { 3901beb6a7dSBenjamin Herrenschmidt u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); 39146ff3463SBrice Goglin if (id == PCI_CAP_ID_HT) { 392c4b22f26SSegher Boessenkool id = readb(devbase + pos + 3); 393*beb7cc82SMichael Ellerman if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_IRQ) 394c4b22f26SSegher Boessenkool break; 395c4b22f26SSegher Boessenkool } 396c4b22f26SSegher Boessenkool } 397c4b22f26SSegher Boessenkool if (pos == 0) 398c4b22f26SSegher Boessenkool return; 399c4b22f26SSegher Boessenkool 4001beb6a7dSBenjamin Herrenschmidt base = devbase + pos; 4011beb6a7dSBenjamin Herrenschmidt writeb(0x01, base + 2); 4021beb6a7dSBenjamin Herrenschmidt n = (readl(base + 4) >> 16) & 0xff; 403c4b22f26SSegher Boessenkool 4041beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: - HT:%02x.%x [0x%02x] vendor %04x device %04x" 4051beb6a7dSBenjamin Herrenschmidt " has %d irqs\n", 4061beb6a7dSBenjamin Herrenschmidt devfn >> 3, devfn & 0x7, pos, vdid & 0xffff, vdid >> 16, n + 1); 407c4b22f26SSegher Boessenkool 408c4b22f26SSegher Boessenkool for (i = 0; i <= n; i++) { 4091beb6a7dSBenjamin Herrenschmidt writeb(0x10 + 2 * i, base + 2); 4101beb6a7dSBenjamin Herrenschmidt tmp = readl(base + 4); 41114cf11afSPaul Mackerras irq = (tmp >> 16) & 0xff; 4121beb6a7dSBenjamin Herrenschmidt DBG("HT PIC index 0x%x, irq 0x%x, tmp: %08x\n", i, irq, tmp); 4131beb6a7dSBenjamin Herrenschmidt /* mask it , will be unmasked later */ 4141beb6a7dSBenjamin Herrenschmidt tmp |= 0x1; 4151beb6a7dSBenjamin Herrenschmidt writel(tmp, base + 4); 4161beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].index = i; 4171beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].base = base; 4181beb6a7dSBenjamin Herrenschmidt /* Apple HT PIC has a non-standard way of doing EOIs */ 4191beb6a7dSBenjamin Herrenschmidt if ((vdid & 0xffff) == 0x106b) 4201beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = devbase + 0x60; 4211beb6a7dSBenjamin Herrenschmidt else 4221beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].applebase = NULL; 4231beb6a7dSBenjamin Herrenschmidt writeb(0x11 + 2 * i, base + 2); 4241beb6a7dSBenjamin Herrenschmidt mpic->fixups[irq].data = readl(base + 4) | 0x80000000; 42514cf11afSPaul Mackerras } 42614cf11afSPaul Mackerras } 42714cf11afSPaul Mackerras 42814cf11afSPaul Mackerras 4291beb6a7dSBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 43014cf11afSPaul Mackerras { 43114cf11afSPaul Mackerras unsigned int devfn; 43214cf11afSPaul Mackerras u8 __iomem *cfgspace; 43314cf11afSPaul Mackerras 4341beb6a7dSBenjamin Herrenschmidt printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n"); 43514cf11afSPaul Mackerras 43614cf11afSPaul Mackerras /* Allocate fixups array */ 43714cf11afSPaul Mackerras mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); 43814cf11afSPaul Mackerras BUG_ON(mpic->fixups == NULL); 43914cf11afSPaul Mackerras memset(mpic->fixups, 0, 128 * sizeof(struct mpic_irq_fixup)); 44014cf11afSPaul Mackerras 44114cf11afSPaul Mackerras /* Init spinlock */ 44214cf11afSPaul Mackerras spin_lock_init(&mpic->fixup_lock); 44314cf11afSPaul Mackerras 444c4b22f26SSegher Boessenkool /* Map U3 config space. We assume all IO-APICs are on the primary bus 445c4b22f26SSegher Boessenkool * so we only need to map 64kB. 44614cf11afSPaul Mackerras */ 447c4b22f26SSegher Boessenkool cfgspace = ioremap(0xf2000000, 0x10000); 44814cf11afSPaul Mackerras BUG_ON(cfgspace == NULL); 44914cf11afSPaul Mackerras 4501beb6a7dSBenjamin Herrenschmidt /* Now we scan all slots. We do a very quick scan, we read the header 4511beb6a7dSBenjamin Herrenschmidt * type, vendor ID and device ID only, that's plenty enough 45214cf11afSPaul Mackerras */ 453c4b22f26SSegher Boessenkool for (devfn = 0; devfn < 0x100; devfn++) { 45414cf11afSPaul Mackerras u8 __iomem *devbase = cfgspace + (devfn << 8); 45514cf11afSPaul Mackerras u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); 45614cf11afSPaul Mackerras u32 l = readl(devbase + PCI_VENDOR_ID); 4571beb6a7dSBenjamin Herrenschmidt u16 s; 45814cf11afSPaul Mackerras 45914cf11afSPaul Mackerras DBG("devfn %x, l: %x\n", devfn, l); 46014cf11afSPaul Mackerras 46114cf11afSPaul Mackerras /* If no device, skip */ 46214cf11afSPaul Mackerras if (l == 0xffffffff || l == 0x00000000 || 46314cf11afSPaul Mackerras l == 0x0000ffff || l == 0xffff0000) 46414cf11afSPaul Mackerras goto next; 4651beb6a7dSBenjamin Herrenschmidt /* Check if is supports capability lists */ 4661beb6a7dSBenjamin Herrenschmidt s = readw(devbase + PCI_STATUS); 4671beb6a7dSBenjamin Herrenschmidt if (!(s & PCI_STATUS_CAP_LIST)) 4681beb6a7dSBenjamin Herrenschmidt goto next; 46914cf11afSPaul Mackerras 4701beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pic(mpic, devbase, devfn, l); 47114cf11afSPaul Mackerras 47214cf11afSPaul Mackerras next: 47314cf11afSPaul Mackerras /* next device, if function 0 */ 474c4b22f26SSegher Boessenkool if (PCI_FUNC(devfn) == 0 && (hdr_type & 0x80) == 0) 47514cf11afSPaul Mackerras devfn += 7; 47614cf11afSPaul Mackerras } 47714cf11afSPaul Mackerras } 47814cf11afSPaul Mackerras 4796e99e458SBenjamin Herrenschmidt #else /* CONFIG_MPIC_BROKEN_U3 */ 4806e99e458SBenjamin Herrenschmidt 4816e99e458SBenjamin Herrenschmidt static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source) 4826e99e458SBenjamin Herrenschmidt { 4836e99e458SBenjamin Herrenschmidt return 0; 4846e99e458SBenjamin Herrenschmidt } 4856e99e458SBenjamin Herrenschmidt 4866e99e458SBenjamin Herrenschmidt static void __init mpic_scan_ht_pics(struct mpic *mpic) 4876e99e458SBenjamin Herrenschmidt { 4886e99e458SBenjamin Herrenschmidt } 4896e99e458SBenjamin Herrenschmidt 49014cf11afSPaul Mackerras #endif /* CONFIG_MPIC_BROKEN_U3 */ 49114cf11afSPaul Mackerras 49214cf11afSPaul Mackerras 4930ebfff14SBenjamin Herrenschmidt #define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) 4940ebfff14SBenjamin Herrenschmidt 49514cf11afSPaul Mackerras /* Find an mpic associated with a given linux interrupt */ 49614cf11afSPaul Mackerras static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) 49714cf11afSPaul Mackerras { 4980ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 49914cf11afSPaul Mackerras 5000ebfff14SBenjamin Herrenschmidt if (irq < NUM_ISA_INTERRUPTS) 50114cf11afSPaul Mackerras return NULL; 5020ebfff14SBenjamin Herrenschmidt if (is_ipi) 5030ebfff14SBenjamin Herrenschmidt *is_ipi = (src >= MPIC_VEC_IPI_0 && src <= MPIC_VEC_IPI_3); 5040ebfff14SBenjamin Herrenschmidt 5050ebfff14SBenjamin Herrenschmidt return irq_desc[irq].chip_data; 50614cf11afSPaul Mackerras } 50714cf11afSPaul Mackerras 50814cf11afSPaul Mackerras /* Convert a cpu mask from logical to physical cpu numbers. */ 50914cf11afSPaul Mackerras static inline u32 mpic_physmask(u32 cpumask) 51014cf11afSPaul Mackerras { 51114cf11afSPaul Mackerras int i; 51214cf11afSPaul Mackerras u32 mask = 0; 51314cf11afSPaul Mackerras 51414cf11afSPaul Mackerras for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1) 51514cf11afSPaul Mackerras mask |= (cpumask & 1) << get_hard_smp_processor_id(i); 51614cf11afSPaul Mackerras return mask; 51714cf11afSPaul Mackerras } 51814cf11afSPaul Mackerras 51914cf11afSPaul Mackerras #ifdef CONFIG_SMP 52014cf11afSPaul Mackerras /* Get the mpic structure from the IPI number */ 52114cf11afSPaul Mackerras static inline struct mpic * mpic_from_ipi(unsigned int ipi) 52214cf11afSPaul Mackerras { 523b9e5b4e6SBenjamin Herrenschmidt return irq_desc[ipi].chip_data; 52414cf11afSPaul Mackerras } 52514cf11afSPaul Mackerras #endif 52614cf11afSPaul Mackerras 52714cf11afSPaul Mackerras /* Get the mpic structure from the irq number */ 52814cf11afSPaul Mackerras static inline struct mpic * mpic_from_irq(unsigned int irq) 52914cf11afSPaul Mackerras { 530b9e5b4e6SBenjamin Herrenschmidt return irq_desc[irq].chip_data; 53114cf11afSPaul Mackerras } 53214cf11afSPaul Mackerras 53314cf11afSPaul Mackerras /* Send an EOI */ 53414cf11afSPaul Mackerras static inline void mpic_eoi(struct mpic *mpic) 53514cf11afSPaul Mackerras { 5367233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_EOI), 0); 5377233593bSZang Roy-r61911 (void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI)); 53814cf11afSPaul Mackerras } 53914cf11afSPaul Mackerras 54014cf11afSPaul Mackerras #ifdef CONFIG_SMP 5417d12e780SDavid Howells static irqreturn_t mpic_ipi_action(int irq, void *dev_id) 54214cf11afSPaul Mackerras { 5437d12e780SDavid Howells smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0); 54414cf11afSPaul Mackerras return IRQ_HANDLED; 54514cf11afSPaul Mackerras } 54614cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 54714cf11afSPaul Mackerras 54814cf11afSPaul Mackerras /* 54914cf11afSPaul Mackerras * Linux descriptor level callbacks 55014cf11afSPaul Mackerras */ 55114cf11afSPaul Mackerras 55214cf11afSPaul Mackerras 553b9e5b4e6SBenjamin Herrenschmidt static void mpic_unmask_irq(unsigned int irq) 55414cf11afSPaul Mackerras { 55514cf11afSPaul Mackerras unsigned int loops = 100000; 55614cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 5570ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 55814cf11afSPaul Mackerras 559bd561c79SPaul Mackerras DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); 56014cf11afSPaul Mackerras 5617233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 5627233593bSZang Roy-r61911 mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & 563e5356640SBenjamin Herrenschmidt ~MPIC_VECPRI_MASK); 56414cf11afSPaul Mackerras /* make sure mask gets to controller before we return to user */ 56514cf11afSPaul Mackerras do { 56614cf11afSPaul Mackerras if (!loops--) { 56714cf11afSPaul Mackerras printk(KERN_ERR "mpic_enable_irq timeout\n"); 56814cf11afSPaul Mackerras break; 56914cf11afSPaul Mackerras } 5707233593bSZang Roy-r61911 } while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK); 5711beb6a7dSBenjamin Herrenschmidt } 5721beb6a7dSBenjamin Herrenschmidt 573b9e5b4e6SBenjamin Herrenschmidt static void mpic_mask_irq(unsigned int irq) 57414cf11afSPaul Mackerras { 57514cf11afSPaul Mackerras unsigned int loops = 100000; 57614cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 5770ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 57814cf11afSPaul Mackerras 57914cf11afSPaul Mackerras DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); 58014cf11afSPaul Mackerras 5817233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 5827233593bSZang Roy-r61911 mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) | 583e5356640SBenjamin Herrenschmidt MPIC_VECPRI_MASK); 58414cf11afSPaul Mackerras 58514cf11afSPaul Mackerras /* make sure mask gets to controller before we return to user */ 58614cf11afSPaul Mackerras do { 58714cf11afSPaul Mackerras if (!loops--) { 58814cf11afSPaul Mackerras printk(KERN_ERR "mpic_enable_irq timeout\n"); 58914cf11afSPaul Mackerras break; 59014cf11afSPaul Mackerras } 5917233593bSZang Roy-r61911 } while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK)); 59214cf11afSPaul Mackerras } 59314cf11afSPaul Mackerras 59414cf11afSPaul Mackerras static void mpic_end_irq(unsigned int irq) 59514cf11afSPaul Mackerras { 59614cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 59714cf11afSPaul Mackerras 5981beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_IRQ 59914cf11afSPaul Mackerras DBG("%s: end_irq: %d\n", mpic->name, irq); 6001beb6a7dSBenjamin Herrenschmidt #endif 60114cf11afSPaul Mackerras /* We always EOI on end_irq() even for edge interrupts since that 60214cf11afSPaul Mackerras * should only lower the priority, the MPIC should have properly 60314cf11afSPaul Mackerras * latched another edge interrupt coming in anyway 60414cf11afSPaul Mackerras */ 60514cf11afSPaul Mackerras 60614cf11afSPaul Mackerras mpic_eoi(mpic); 60714cf11afSPaul Mackerras } 60814cf11afSPaul Mackerras 609b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_MPIC_BROKEN_U3 610b9e5b4e6SBenjamin Herrenschmidt 611b9e5b4e6SBenjamin Herrenschmidt static void mpic_unmask_ht_irq(unsigned int irq) 612b9e5b4e6SBenjamin Herrenschmidt { 613b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 6140ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 615b9e5b4e6SBenjamin Herrenschmidt 616b9e5b4e6SBenjamin Herrenschmidt mpic_unmask_irq(irq); 617b9e5b4e6SBenjamin Herrenschmidt 618b9e5b4e6SBenjamin Herrenschmidt if (irq_desc[irq].status & IRQ_LEVEL) 619b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 620b9e5b4e6SBenjamin Herrenschmidt } 621b9e5b4e6SBenjamin Herrenschmidt 622b9e5b4e6SBenjamin Herrenschmidt static unsigned int mpic_startup_ht_irq(unsigned int irq) 623b9e5b4e6SBenjamin Herrenschmidt { 624b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 6250ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 626b9e5b4e6SBenjamin Herrenschmidt 627b9e5b4e6SBenjamin Herrenschmidt mpic_unmask_irq(irq); 628b9e5b4e6SBenjamin Herrenschmidt mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); 629b9e5b4e6SBenjamin Herrenschmidt 630b9e5b4e6SBenjamin Herrenschmidt return 0; 631b9e5b4e6SBenjamin Herrenschmidt } 632b9e5b4e6SBenjamin Herrenschmidt 633b9e5b4e6SBenjamin Herrenschmidt static void mpic_shutdown_ht_irq(unsigned int irq) 634b9e5b4e6SBenjamin Herrenschmidt { 635b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 6360ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 637b9e5b4e6SBenjamin Herrenschmidt 638b9e5b4e6SBenjamin Herrenschmidt mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); 639b9e5b4e6SBenjamin Herrenschmidt mpic_mask_irq(irq); 640b9e5b4e6SBenjamin Herrenschmidt } 641b9e5b4e6SBenjamin Herrenschmidt 642b9e5b4e6SBenjamin Herrenschmidt static void mpic_end_ht_irq(unsigned int irq) 643b9e5b4e6SBenjamin Herrenschmidt { 644b9e5b4e6SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(irq); 6450ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 646b9e5b4e6SBenjamin Herrenschmidt 647b9e5b4e6SBenjamin Herrenschmidt #ifdef DEBUG_IRQ 648b9e5b4e6SBenjamin Herrenschmidt DBG("%s: end_irq: %d\n", mpic->name, irq); 649b9e5b4e6SBenjamin Herrenschmidt #endif 650b9e5b4e6SBenjamin Herrenschmidt /* We always EOI on end_irq() even for edge interrupts since that 651b9e5b4e6SBenjamin Herrenschmidt * should only lower the priority, the MPIC should have properly 652b9e5b4e6SBenjamin Herrenschmidt * latched another edge interrupt coming in anyway 653b9e5b4e6SBenjamin Herrenschmidt */ 654b9e5b4e6SBenjamin Herrenschmidt 655b9e5b4e6SBenjamin Herrenschmidt if (irq_desc[irq].status & IRQ_LEVEL) 656b9e5b4e6SBenjamin Herrenschmidt mpic_ht_end_irq(mpic, src); 657b9e5b4e6SBenjamin Herrenschmidt mpic_eoi(mpic); 658b9e5b4e6SBenjamin Herrenschmidt } 6596e99e458SBenjamin Herrenschmidt #endif /* !CONFIG_MPIC_BROKEN_U3 */ 660b9e5b4e6SBenjamin Herrenschmidt 66114cf11afSPaul Mackerras #ifdef CONFIG_SMP 66214cf11afSPaul Mackerras 663b9e5b4e6SBenjamin Herrenschmidt static void mpic_unmask_ipi(unsigned int irq) 66414cf11afSPaul Mackerras { 66514cf11afSPaul Mackerras struct mpic *mpic = mpic_from_ipi(irq); 6660ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0; 66714cf11afSPaul Mackerras 66814cf11afSPaul Mackerras DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); 66914cf11afSPaul Mackerras mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); 67014cf11afSPaul Mackerras } 67114cf11afSPaul Mackerras 672b9e5b4e6SBenjamin Herrenschmidt static void mpic_mask_ipi(unsigned int irq) 67314cf11afSPaul Mackerras { 67414cf11afSPaul Mackerras /* NEVER disable an IPI... that's just plain wrong! */ 67514cf11afSPaul Mackerras } 67614cf11afSPaul Mackerras 67714cf11afSPaul Mackerras static void mpic_end_ipi(unsigned int irq) 67814cf11afSPaul Mackerras { 67914cf11afSPaul Mackerras struct mpic *mpic = mpic_from_ipi(irq); 68014cf11afSPaul Mackerras 68114cf11afSPaul Mackerras /* 68214cf11afSPaul Mackerras * IPIs are marked IRQ_PER_CPU. This has the side effect of 68314cf11afSPaul Mackerras * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from 68414cf11afSPaul Mackerras * applying to them. We EOI them late to avoid re-entering. 6856714465eSThomas Gleixner * We mark IPI's with IRQF_DISABLED as they must run with 68614cf11afSPaul Mackerras * irqs disabled. 68714cf11afSPaul Mackerras */ 68814cf11afSPaul Mackerras mpic_eoi(mpic); 68914cf11afSPaul Mackerras } 69014cf11afSPaul Mackerras 69114cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 69214cf11afSPaul Mackerras 69314cf11afSPaul Mackerras static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) 69414cf11afSPaul Mackerras { 69514cf11afSPaul Mackerras struct mpic *mpic = mpic_from_irq(irq); 6960ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 69714cf11afSPaul Mackerras 69814cf11afSPaul Mackerras cpumask_t tmp; 69914cf11afSPaul Mackerras 70014cf11afSPaul Mackerras cpus_and(tmp, cpumask, cpu_online_map); 70114cf11afSPaul Mackerras 7027233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 70314cf11afSPaul Mackerras mpic_physmask(cpus_addr(tmp)[0])); 70414cf11afSPaul Mackerras } 70514cf11afSPaul Mackerras 7067233593bSZang Roy-r61911 static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type) 7070ebfff14SBenjamin Herrenschmidt { 7080ebfff14SBenjamin Herrenschmidt /* Now convert sense value */ 7096e99e458SBenjamin Herrenschmidt switch(type & IRQ_TYPE_SENSE_MASK) { 7100ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_RISING: 7117233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 7127233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 7130ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_FALLING: 7146e99e458SBenjamin Herrenschmidt case IRQ_TYPE_EDGE_BOTH: 7157233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_EDGE) | 7167233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 7170ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_HIGH: 7187233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 7197233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_POSITIVE); 7200ebfff14SBenjamin Herrenschmidt case IRQ_TYPE_LEVEL_LOW: 7210ebfff14SBenjamin Herrenschmidt default: 7227233593bSZang Roy-r61911 return MPIC_INFO(VECPRI_SENSE_LEVEL) | 7237233593bSZang Roy-r61911 MPIC_INFO(VECPRI_POLARITY_NEGATIVE); 7240ebfff14SBenjamin Herrenschmidt } 7256e99e458SBenjamin Herrenschmidt } 7266e99e458SBenjamin Herrenschmidt 7276e99e458SBenjamin Herrenschmidt static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) 7286e99e458SBenjamin Herrenschmidt { 7296e99e458SBenjamin Herrenschmidt struct mpic *mpic = mpic_from_irq(virq); 7306e99e458SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(virq); 7316e99e458SBenjamin Herrenschmidt struct irq_desc *desc = get_irq_desc(virq); 7326e99e458SBenjamin Herrenschmidt unsigned int vecpri, vold, vnew; 7336e99e458SBenjamin Herrenschmidt 73406fe98e6SBenjamin Herrenschmidt DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", 7356e99e458SBenjamin Herrenschmidt mpic, virq, src, flow_type); 7366e99e458SBenjamin Herrenschmidt 7376e99e458SBenjamin Herrenschmidt if (src >= mpic->irq_count) 7386e99e458SBenjamin Herrenschmidt return -EINVAL; 7396e99e458SBenjamin Herrenschmidt 7406e99e458SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_NONE) 7416e99e458SBenjamin Herrenschmidt if (mpic->senses && src < mpic->senses_count) 7426e99e458SBenjamin Herrenschmidt flow_type = mpic->senses[src]; 7436e99e458SBenjamin Herrenschmidt if (flow_type == IRQ_TYPE_NONE) 7446e99e458SBenjamin Herrenschmidt flow_type = IRQ_TYPE_LEVEL_LOW; 7456e99e458SBenjamin Herrenschmidt 7466e99e458SBenjamin Herrenschmidt desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); 7476e99e458SBenjamin Herrenschmidt desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; 7486e99e458SBenjamin Herrenschmidt if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) 7496e99e458SBenjamin Herrenschmidt desc->status |= IRQ_LEVEL; 7506e99e458SBenjamin Herrenschmidt 7516e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, src)) 7526e99e458SBenjamin Herrenschmidt vecpri = MPIC_VECPRI_POLARITY_POSITIVE | 7536e99e458SBenjamin Herrenschmidt MPIC_VECPRI_SENSE_EDGE; 7546e99e458SBenjamin Herrenschmidt else 7557233593bSZang Roy-r61911 vecpri = mpic_type_to_vecpri(mpic, flow_type); 7566e99e458SBenjamin Herrenschmidt 7577233593bSZang Roy-r61911 vold = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 7587233593bSZang Roy-r61911 vnew = vold & ~(MPIC_INFO(VECPRI_POLARITY_MASK) | 7597233593bSZang Roy-r61911 MPIC_INFO(VECPRI_SENSE_MASK)); 7606e99e458SBenjamin Herrenschmidt vnew |= vecpri; 7616e99e458SBenjamin Herrenschmidt if (vold != vnew) 7627233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); 7636e99e458SBenjamin Herrenschmidt 7646e99e458SBenjamin Herrenschmidt return 0; 7650ebfff14SBenjamin Herrenschmidt } 7660ebfff14SBenjamin Herrenschmidt 767b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_chip = { 768b9e5b4e6SBenjamin Herrenschmidt .mask = mpic_mask_irq, 769b9e5b4e6SBenjamin Herrenschmidt .unmask = mpic_unmask_irq, 770b9e5b4e6SBenjamin Herrenschmidt .eoi = mpic_end_irq, 7716e99e458SBenjamin Herrenschmidt .set_type = mpic_set_irq_type, 772b9e5b4e6SBenjamin Herrenschmidt }; 773b9e5b4e6SBenjamin Herrenschmidt 774b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_SMP 775b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_ipi_chip = { 776b9e5b4e6SBenjamin Herrenschmidt .mask = mpic_mask_ipi, 777b9e5b4e6SBenjamin Herrenschmidt .unmask = mpic_unmask_ipi, 778b9e5b4e6SBenjamin Herrenschmidt .eoi = mpic_end_ipi, 779b9e5b4e6SBenjamin Herrenschmidt }; 780b9e5b4e6SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 781b9e5b4e6SBenjamin Herrenschmidt 782b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_MPIC_BROKEN_U3 783b9e5b4e6SBenjamin Herrenschmidt static struct irq_chip mpic_irq_ht_chip = { 784b9e5b4e6SBenjamin Herrenschmidt .startup = mpic_startup_ht_irq, 785b9e5b4e6SBenjamin Herrenschmidt .shutdown = mpic_shutdown_ht_irq, 786b9e5b4e6SBenjamin Herrenschmidt .mask = mpic_mask_irq, 787b9e5b4e6SBenjamin Herrenschmidt .unmask = mpic_unmask_ht_irq, 788b9e5b4e6SBenjamin Herrenschmidt .eoi = mpic_end_ht_irq, 7896e99e458SBenjamin Herrenschmidt .set_type = mpic_set_irq_type, 790b9e5b4e6SBenjamin Herrenschmidt }; 791b9e5b4e6SBenjamin Herrenschmidt #endif /* CONFIG_MPIC_BROKEN_U3 */ 792b9e5b4e6SBenjamin Herrenschmidt 79314cf11afSPaul Mackerras 7940ebfff14SBenjamin Herrenschmidt static int mpic_host_match(struct irq_host *h, struct device_node *node) 7950ebfff14SBenjamin Herrenschmidt { 7960ebfff14SBenjamin Herrenschmidt struct mpic *mpic = h->host_data; 7970ebfff14SBenjamin Herrenschmidt 7980ebfff14SBenjamin Herrenschmidt /* Exact match, unless mpic node is NULL */ 7990ebfff14SBenjamin Herrenschmidt return mpic->of_node == NULL || mpic->of_node == node; 8000ebfff14SBenjamin Herrenschmidt } 8010ebfff14SBenjamin Herrenschmidt 8020ebfff14SBenjamin Herrenschmidt static int mpic_host_map(struct irq_host *h, unsigned int virq, 8036e99e458SBenjamin Herrenschmidt irq_hw_number_t hw) 8040ebfff14SBenjamin Herrenschmidt { 8050ebfff14SBenjamin Herrenschmidt struct mpic *mpic = h->host_data; 8066e99e458SBenjamin Herrenschmidt struct irq_chip *chip; 8070ebfff14SBenjamin Herrenschmidt 80806fe98e6SBenjamin Herrenschmidt DBG("mpic: map virq %d, hwirq 0x%lx\n", virq, hw); 8090ebfff14SBenjamin Herrenschmidt 8100ebfff14SBenjamin Herrenschmidt if (hw == MPIC_VEC_SPURRIOUS) 8110ebfff14SBenjamin Herrenschmidt return -EINVAL; 81206fe98e6SBenjamin Herrenschmidt 8130ebfff14SBenjamin Herrenschmidt #ifdef CONFIG_SMP 8140ebfff14SBenjamin Herrenschmidt else if (hw >= MPIC_VEC_IPI_0) { 8150ebfff14SBenjamin Herrenschmidt WARN_ON(!(mpic->flags & MPIC_PRIMARY)); 8160ebfff14SBenjamin Herrenschmidt 81706fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping as IPI\n"); 8180ebfff14SBenjamin Herrenschmidt set_irq_chip_data(virq, mpic); 8190ebfff14SBenjamin Herrenschmidt set_irq_chip_and_handler(virq, &mpic->hc_ipi, 8200ebfff14SBenjamin Herrenschmidt handle_percpu_irq); 8210ebfff14SBenjamin Herrenschmidt return 0; 8220ebfff14SBenjamin Herrenschmidt } 8230ebfff14SBenjamin Herrenschmidt #endif /* CONFIG_SMP */ 8240ebfff14SBenjamin Herrenschmidt 8250ebfff14SBenjamin Herrenschmidt if (hw >= mpic->irq_count) 8260ebfff14SBenjamin Herrenschmidt return -EINVAL; 8270ebfff14SBenjamin Herrenschmidt 8286e99e458SBenjamin Herrenschmidt /* Default chip */ 8290ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_irq; 8300ebfff14SBenjamin Herrenschmidt 8310ebfff14SBenjamin Herrenschmidt #ifdef CONFIG_MPIC_BROKEN_U3 8320ebfff14SBenjamin Herrenschmidt /* Check for HT interrupts, override vecpri */ 8336e99e458SBenjamin Herrenschmidt if (mpic_is_ht_interrupt(mpic, hw)) 8340ebfff14SBenjamin Herrenschmidt chip = &mpic->hc_ht_irq; 8356e99e458SBenjamin Herrenschmidt #endif /* CONFIG_MPIC_BROKEN_U3 */ 8360ebfff14SBenjamin Herrenschmidt 83706fe98e6SBenjamin Herrenschmidt DBG("mpic: mapping to irq chip @%p\n", chip); 8380ebfff14SBenjamin Herrenschmidt 8390ebfff14SBenjamin Herrenschmidt set_irq_chip_data(virq, mpic); 8400ebfff14SBenjamin Herrenschmidt set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); 8416e99e458SBenjamin Herrenschmidt 8426e99e458SBenjamin Herrenschmidt /* Set default irq type */ 8436e99e458SBenjamin Herrenschmidt set_irq_type(virq, IRQ_TYPE_NONE); 8446e99e458SBenjamin Herrenschmidt 8450ebfff14SBenjamin Herrenschmidt return 0; 8460ebfff14SBenjamin Herrenschmidt } 8470ebfff14SBenjamin Herrenschmidt 8480ebfff14SBenjamin Herrenschmidt static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, 8490ebfff14SBenjamin Herrenschmidt u32 *intspec, unsigned int intsize, 8500ebfff14SBenjamin Herrenschmidt irq_hw_number_t *out_hwirq, unsigned int *out_flags) 8510ebfff14SBenjamin Herrenschmidt 8520ebfff14SBenjamin Herrenschmidt { 8530ebfff14SBenjamin Herrenschmidt static unsigned char map_mpic_senses[4] = { 8540ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_RISING, 8550ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_LOW, 8560ebfff14SBenjamin Herrenschmidt IRQ_TYPE_LEVEL_HIGH, 8570ebfff14SBenjamin Herrenschmidt IRQ_TYPE_EDGE_FALLING, 8580ebfff14SBenjamin Herrenschmidt }; 8590ebfff14SBenjamin Herrenschmidt 8600ebfff14SBenjamin Herrenschmidt *out_hwirq = intspec[0]; 86106fe98e6SBenjamin Herrenschmidt if (intsize > 1) { 86206fe98e6SBenjamin Herrenschmidt u32 mask = 0x3; 86306fe98e6SBenjamin Herrenschmidt 86406fe98e6SBenjamin Herrenschmidt /* Apple invented a new race of encoding on machines with 86506fe98e6SBenjamin Herrenschmidt * an HT APIC. They encode, among others, the index within 86606fe98e6SBenjamin Herrenschmidt * the HT APIC. We don't care about it here since thankfully, 86706fe98e6SBenjamin Herrenschmidt * it appears that they have the APIC already properly 86806fe98e6SBenjamin Herrenschmidt * configured, and thus our current fixup code that reads the 86906fe98e6SBenjamin Herrenschmidt * APIC config works fine. However, we still need to mask out 87006fe98e6SBenjamin Herrenschmidt * bits in the specifier to make sure we only get bit 0 which 87106fe98e6SBenjamin Herrenschmidt * is the level/edge bit (the only sense bit exposed by Apple), 87206fe98e6SBenjamin Herrenschmidt * as their bit 1 means something else. 87306fe98e6SBenjamin Herrenschmidt */ 87406fe98e6SBenjamin Herrenschmidt if (machine_is(powermac)) 87506fe98e6SBenjamin Herrenschmidt mask = 0x1; 87606fe98e6SBenjamin Herrenschmidt *out_flags = map_mpic_senses[intspec[1] & mask]; 87706fe98e6SBenjamin Herrenschmidt } else 8780ebfff14SBenjamin Herrenschmidt *out_flags = IRQ_TYPE_NONE; 8790ebfff14SBenjamin Herrenschmidt 88006fe98e6SBenjamin Herrenschmidt DBG("mpic: xlate (%d cells: 0x%08x 0x%08x) to line 0x%lx sense 0x%x\n", 88106fe98e6SBenjamin Herrenschmidt intsize, intspec[0], intspec[1], *out_hwirq, *out_flags); 88206fe98e6SBenjamin Herrenschmidt 8830ebfff14SBenjamin Herrenschmidt return 0; 8840ebfff14SBenjamin Herrenschmidt } 8850ebfff14SBenjamin Herrenschmidt 8860ebfff14SBenjamin Herrenschmidt static struct irq_host_ops mpic_host_ops = { 8870ebfff14SBenjamin Herrenschmidt .match = mpic_host_match, 8880ebfff14SBenjamin Herrenschmidt .map = mpic_host_map, 8890ebfff14SBenjamin Herrenschmidt .xlate = mpic_host_xlate, 8900ebfff14SBenjamin Herrenschmidt }; 8910ebfff14SBenjamin Herrenschmidt 89214cf11afSPaul Mackerras /* 89314cf11afSPaul Mackerras * Exported functions 89414cf11afSPaul Mackerras */ 89514cf11afSPaul Mackerras 8960ebfff14SBenjamin Herrenschmidt struct mpic * __init mpic_alloc(struct device_node *node, 897a959ff56SBenjamin Herrenschmidt phys_addr_t phys_addr, 89814cf11afSPaul Mackerras unsigned int flags, 89914cf11afSPaul Mackerras unsigned int isu_size, 90014cf11afSPaul Mackerras unsigned int irq_count, 90114cf11afSPaul Mackerras const char *name) 90214cf11afSPaul Mackerras { 90314cf11afSPaul Mackerras struct mpic *mpic; 90414cf11afSPaul Mackerras u32 reg; 90514cf11afSPaul Mackerras const char *vers; 90614cf11afSPaul Mackerras int i; 907a959ff56SBenjamin Herrenschmidt u64 paddr = phys_addr; 90814cf11afSPaul Mackerras 90914cf11afSPaul Mackerras mpic = alloc_bootmem(sizeof(struct mpic)); 91014cf11afSPaul Mackerras if (mpic == NULL) 91114cf11afSPaul Mackerras return NULL; 91214cf11afSPaul Mackerras 91314cf11afSPaul Mackerras memset(mpic, 0, sizeof(struct mpic)); 91414cf11afSPaul Mackerras mpic->name = name; 9150ebfff14SBenjamin Herrenschmidt mpic->of_node = node ? of_node_get(node) : NULL; 91614cf11afSPaul Mackerras 9170ebfff14SBenjamin Herrenschmidt mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 256, 9180ebfff14SBenjamin Herrenschmidt &mpic_host_ops, 9190ebfff14SBenjamin Herrenschmidt MPIC_VEC_SPURRIOUS); 9200ebfff14SBenjamin Herrenschmidt if (mpic->irqhost == NULL) { 9210ebfff14SBenjamin Herrenschmidt of_node_put(node); 9220ebfff14SBenjamin Herrenschmidt return NULL; 9230ebfff14SBenjamin Herrenschmidt } 9240ebfff14SBenjamin Herrenschmidt 9250ebfff14SBenjamin Herrenschmidt mpic->irqhost->host_data = mpic; 926b9e5b4e6SBenjamin Herrenschmidt mpic->hc_irq = mpic_irq_chip; 92714cf11afSPaul Mackerras mpic->hc_irq.typename = name; 92814cf11afSPaul Mackerras if (flags & MPIC_PRIMARY) 92914cf11afSPaul Mackerras mpic->hc_irq.set_affinity = mpic_set_affinity; 930b9e5b4e6SBenjamin Herrenschmidt #ifdef CONFIG_MPIC_BROKEN_U3 931b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq = mpic_irq_ht_chip; 932b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq.typename = name; 933b9e5b4e6SBenjamin Herrenschmidt if (flags & MPIC_PRIMARY) 934b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ht_irq.set_affinity = mpic_set_affinity; 935b9e5b4e6SBenjamin Herrenschmidt #endif /* CONFIG_MPIC_BROKEN_U3 */ 936fbf0274eSBenjamin Herrenschmidt 93714cf11afSPaul Mackerras #ifdef CONFIG_SMP 938b9e5b4e6SBenjamin Herrenschmidt mpic->hc_ipi = mpic_ipi_chip; 9390ebfff14SBenjamin Herrenschmidt mpic->hc_ipi.typename = name; 94014cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 94114cf11afSPaul Mackerras 94214cf11afSPaul Mackerras mpic->flags = flags; 94314cf11afSPaul Mackerras mpic->isu_size = isu_size; 94414cf11afSPaul Mackerras mpic->irq_count = irq_count; 94514cf11afSPaul Mackerras mpic->num_sources = 0; /* so far */ 94614cf11afSPaul Mackerras 947a959ff56SBenjamin Herrenschmidt /* Check for "big-endian" in device-tree */ 948a959ff56SBenjamin Herrenschmidt if (node && get_property(node, "big-endian", NULL) != NULL) 949a959ff56SBenjamin Herrenschmidt mpic->flags |= MPIC_BIG_ENDIAN; 950a959ff56SBenjamin Herrenschmidt 951a959ff56SBenjamin Herrenschmidt 9527233593bSZang Roy-r61911 #ifdef CONFIG_MPIC_WEIRD 9537233593bSZang Roy-r61911 mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; 9547233593bSZang Roy-r61911 #endif 9557233593bSZang Roy-r61911 956fbf0274eSBenjamin Herrenschmidt /* default register type */ 957fbf0274eSBenjamin Herrenschmidt mpic->reg_type = (flags & MPIC_BIG_ENDIAN) ? 958fbf0274eSBenjamin Herrenschmidt mpic_access_mmio_be : mpic_access_mmio_le; 959fbf0274eSBenjamin Herrenschmidt 960a959ff56SBenjamin Herrenschmidt /* If no physical address is passed in, a device-node is mandatory */ 961a959ff56SBenjamin Herrenschmidt BUG_ON(paddr == 0 && node == NULL); 962a959ff56SBenjamin Herrenschmidt 963a959ff56SBenjamin Herrenschmidt /* If no physical address passed in, check if it's dcr based */ 964a959ff56SBenjamin Herrenschmidt if (paddr == 0 && get_property(node, "dcr-reg", NULL) != NULL) 965a959ff56SBenjamin Herrenschmidt mpic->flags |= MPIC_USES_DCR; 966a959ff56SBenjamin Herrenschmidt 967fbf0274eSBenjamin Herrenschmidt #ifdef CONFIG_PPC_DCR 968fbf0274eSBenjamin Herrenschmidt if (mpic->flags & MPIC_USES_DCR) { 969fbf0274eSBenjamin Herrenschmidt const u32 *dbasep; 970a959ff56SBenjamin Herrenschmidt dbasep = get_property(node, "dcr-reg", NULL); 971fbf0274eSBenjamin Herrenschmidt BUG_ON(dbasep == NULL); 972fbf0274eSBenjamin Herrenschmidt mpic->dcr_base = *dbasep; 973fbf0274eSBenjamin Herrenschmidt mpic->reg_type = mpic_access_dcr; 974fbf0274eSBenjamin Herrenschmidt } 975fbf0274eSBenjamin Herrenschmidt #else 976fbf0274eSBenjamin Herrenschmidt BUG_ON (mpic->flags & MPIC_USES_DCR); 977fbf0274eSBenjamin Herrenschmidt #endif /* CONFIG_PPC_DCR */ 978fbf0274eSBenjamin Herrenschmidt 979a959ff56SBenjamin Herrenschmidt /* If the MPIC is not DCR based, and no physical address was passed 980a959ff56SBenjamin Herrenschmidt * in, try to obtain one 981a959ff56SBenjamin Herrenschmidt */ 982a959ff56SBenjamin Herrenschmidt if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) { 983a959ff56SBenjamin Herrenschmidt const u32 *reg; 984a959ff56SBenjamin Herrenschmidt reg = get_property(node, "reg", NULL); 985a959ff56SBenjamin Herrenschmidt BUG_ON(reg == NULL); 986a959ff56SBenjamin Herrenschmidt paddr = of_translate_address(node, reg); 987a959ff56SBenjamin Herrenschmidt BUG_ON(paddr == OF_BAD_ADDR); 988a959ff56SBenjamin Herrenschmidt } 989a959ff56SBenjamin Herrenschmidt 99014cf11afSPaul Mackerras /* Map the global registers */ 991a959ff56SBenjamin Herrenschmidt mpic_map(mpic, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); 992a959ff56SBenjamin Herrenschmidt mpic_map(mpic, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); 99314cf11afSPaul Mackerras 99414cf11afSPaul Mackerras /* Reset */ 99514cf11afSPaul Mackerras if (flags & MPIC_WANTS_RESET) { 9967233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 9977233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 99814cf11afSPaul Mackerras | MPIC_GREG_GCONF_RESET); 9997233593bSZang Roy-r61911 while( mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 100014cf11afSPaul Mackerras & MPIC_GREG_GCONF_RESET) 100114cf11afSPaul Mackerras mb(); 100214cf11afSPaul Mackerras } 100314cf11afSPaul Mackerras 100414cf11afSPaul Mackerras /* Read feature register, calculate num CPUs and, for non-ISU 100514cf11afSPaul Mackerras * MPICs, num sources as well. On ISU MPICs, sources are counted 100614cf11afSPaul Mackerras * as ISUs are added 100714cf11afSPaul Mackerras */ 10087233593bSZang Roy-r61911 reg = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); 100914cf11afSPaul Mackerras mpic->num_cpus = ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK) 101014cf11afSPaul Mackerras >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1; 101114cf11afSPaul Mackerras if (isu_size == 0) 101214cf11afSPaul Mackerras mpic->num_sources = ((reg & MPIC_GREG_FEATURE_LAST_SRC_MASK) 101314cf11afSPaul Mackerras >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; 101414cf11afSPaul Mackerras 101514cf11afSPaul Mackerras /* Map the per-CPU registers */ 101614cf11afSPaul Mackerras for (i = 0; i < mpic->num_cpus; i++) { 1017a959ff56SBenjamin Herrenschmidt mpic_map(mpic, paddr, &mpic->cpuregs[i], 1018fbf0274eSBenjamin Herrenschmidt MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE), 1019fbf0274eSBenjamin Herrenschmidt 0x1000); 102014cf11afSPaul Mackerras } 102114cf11afSPaul Mackerras 102214cf11afSPaul Mackerras /* Initialize main ISU if none provided */ 102314cf11afSPaul Mackerras if (mpic->isu_size == 0) { 102414cf11afSPaul Mackerras mpic->isu_size = mpic->num_sources; 1025a959ff56SBenjamin Herrenschmidt mpic_map(mpic, paddr, &mpic->isus[0], 1026fbf0274eSBenjamin Herrenschmidt MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); 102714cf11afSPaul Mackerras } 102814cf11afSPaul Mackerras mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); 102914cf11afSPaul Mackerras mpic->isu_mask = (1 << mpic->isu_shift) - 1; 103014cf11afSPaul Mackerras 103114cf11afSPaul Mackerras /* Display version */ 103214cf11afSPaul Mackerras switch (reg & MPIC_GREG_FEATURE_VERSION_MASK) { 103314cf11afSPaul Mackerras case 1: 103414cf11afSPaul Mackerras vers = "1.0"; 103514cf11afSPaul Mackerras break; 103614cf11afSPaul Mackerras case 2: 103714cf11afSPaul Mackerras vers = "1.2"; 103814cf11afSPaul Mackerras break; 103914cf11afSPaul Mackerras case 3: 104014cf11afSPaul Mackerras vers = "1.3"; 104114cf11afSPaul Mackerras break; 104214cf11afSPaul Mackerras default: 104314cf11afSPaul Mackerras vers = "<unknown>"; 104414cf11afSPaul Mackerras break; 104514cf11afSPaul Mackerras } 1046a959ff56SBenjamin Herrenschmidt printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," 1047a959ff56SBenjamin Herrenschmidt " max %d CPUs\n", 1048a959ff56SBenjamin Herrenschmidt name, vers, (unsigned long long)paddr, mpic->num_cpus); 1049a959ff56SBenjamin Herrenschmidt printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", 1050a959ff56SBenjamin Herrenschmidt mpic->isu_size, mpic->isu_shift, mpic->isu_mask); 105114cf11afSPaul Mackerras 105214cf11afSPaul Mackerras mpic->next = mpics; 105314cf11afSPaul Mackerras mpics = mpic; 105414cf11afSPaul Mackerras 10550ebfff14SBenjamin Herrenschmidt if (flags & MPIC_PRIMARY) { 105614cf11afSPaul Mackerras mpic_primary = mpic; 10570ebfff14SBenjamin Herrenschmidt irq_set_default_host(mpic->irqhost); 10580ebfff14SBenjamin Herrenschmidt } 105914cf11afSPaul Mackerras 106014cf11afSPaul Mackerras return mpic; 106114cf11afSPaul Mackerras } 106214cf11afSPaul Mackerras 106314cf11afSPaul Mackerras void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, 1064a959ff56SBenjamin Herrenschmidt phys_addr_t paddr) 106514cf11afSPaul Mackerras { 106614cf11afSPaul Mackerras unsigned int isu_first = isu_num * mpic->isu_size; 106714cf11afSPaul Mackerras 106814cf11afSPaul Mackerras BUG_ON(isu_num >= MPIC_MAX_ISU); 106914cf11afSPaul Mackerras 1070a959ff56SBenjamin Herrenschmidt mpic_map(mpic, paddr, &mpic->isus[isu_num], 0, 10717233593bSZang Roy-r61911 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); 107214cf11afSPaul Mackerras if ((isu_first + mpic->isu_size) > mpic->num_sources) 107314cf11afSPaul Mackerras mpic->num_sources = isu_first + mpic->isu_size; 107414cf11afSPaul Mackerras } 107514cf11afSPaul Mackerras 10760ebfff14SBenjamin Herrenschmidt void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count) 10770ebfff14SBenjamin Herrenschmidt { 10780ebfff14SBenjamin Herrenschmidt mpic->senses = senses; 10790ebfff14SBenjamin Herrenschmidt mpic->senses_count = count; 10800ebfff14SBenjamin Herrenschmidt } 10810ebfff14SBenjamin Herrenschmidt 108214cf11afSPaul Mackerras void __init mpic_init(struct mpic *mpic) 108314cf11afSPaul Mackerras { 108414cf11afSPaul Mackerras int i; 108514cf11afSPaul Mackerras 108614cf11afSPaul Mackerras BUG_ON(mpic->num_sources == 0); 10870ebfff14SBenjamin Herrenschmidt WARN_ON(mpic->num_sources > MPIC_VEC_IPI_0); 10880ebfff14SBenjamin Herrenschmidt 10890ebfff14SBenjamin Herrenschmidt /* Sanitize source count */ 10900ebfff14SBenjamin Herrenschmidt if (mpic->num_sources > MPIC_VEC_IPI_0) 10910ebfff14SBenjamin Herrenschmidt mpic->num_sources = MPIC_VEC_IPI_0; 109214cf11afSPaul Mackerras 109314cf11afSPaul Mackerras printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); 109414cf11afSPaul Mackerras 109514cf11afSPaul Mackerras /* Set current processor priority to max */ 10967233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 109714cf11afSPaul Mackerras 109814cf11afSPaul Mackerras /* Initialize timers: just disable them all */ 109914cf11afSPaul Mackerras for (i = 0; i < 4; i++) { 110014cf11afSPaul Mackerras mpic_write(mpic->tmregs, 11017233593bSZang Roy-r61911 i * MPIC_INFO(TIMER_STRIDE) + 11027233593bSZang Roy-r61911 MPIC_INFO(TIMER_DESTINATION), 0); 110314cf11afSPaul Mackerras mpic_write(mpic->tmregs, 11047233593bSZang Roy-r61911 i * MPIC_INFO(TIMER_STRIDE) + 11057233593bSZang Roy-r61911 MPIC_INFO(TIMER_VECTOR_PRI), 110614cf11afSPaul Mackerras MPIC_VECPRI_MASK | 110714cf11afSPaul Mackerras (MPIC_VEC_TIMER_0 + i)); 110814cf11afSPaul Mackerras } 110914cf11afSPaul Mackerras 111014cf11afSPaul Mackerras /* Initialize IPIs to our reserved vectors and mark them disabled for now */ 111114cf11afSPaul Mackerras mpic_test_broken_ipi(mpic); 111214cf11afSPaul Mackerras for (i = 0; i < 4; i++) { 111314cf11afSPaul Mackerras mpic_ipi_write(i, 111414cf11afSPaul Mackerras MPIC_VECPRI_MASK | 111514cf11afSPaul Mackerras (10 << MPIC_VECPRI_PRIORITY_SHIFT) | 111614cf11afSPaul Mackerras (MPIC_VEC_IPI_0 + i)); 111714cf11afSPaul Mackerras } 111814cf11afSPaul Mackerras 111914cf11afSPaul Mackerras /* Initialize interrupt sources */ 112014cf11afSPaul Mackerras if (mpic->irq_count == 0) 112114cf11afSPaul Mackerras mpic->irq_count = mpic->num_sources; 112214cf11afSPaul Mackerras 11231beb6a7dSBenjamin Herrenschmidt /* Do the HT PIC fixups on U3 broken mpic */ 112414cf11afSPaul Mackerras DBG("MPIC flags: %x\n", mpic->flags); 112514cf11afSPaul Mackerras if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) 11261beb6a7dSBenjamin Herrenschmidt mpic_scan_ht_pics(mpic); 112714cf11afSPaul Mackerras 112814cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources; i++) { 112914cf11afSPaul Mackerras /* start with vector = source number, and masked */ 11306e99e458SBenjamin Herrenschmidt u32 vecpri = MPIC_VECPRI_MASK | i | 11316e99e458SBenjamin Herrenschmidt (8 << MPIC_VECPRI_PRIORITY_SHIFT); 113214cf11afSPaul Mackerras 113314cf11afSPaul Mackerras /* init hw */ 11347233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); 11357233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 113614cf11afSPaul Mackerras 1 << hard_smp_processor_id()); 113714cf11afSPaul Mackerras } 113814cf11afSPaul Mackerras 113914cf11afSPaul Mackerras /* Init spurrious vector */ 11407233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS), MPIC_VEC_SPURRIOUS); 114114cf11afSPaul Mackerras 11427233593bSZang Roy-r61911 /* Disable 8259 passthrough, if supported */ 11437233593bSZang Roy-r61911 if (!(mpic->flags & MPIC_NO_PTHROU_DIS)) 11447233593bSZang Roy-r61911 mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 11457233593bSZang Roy-r61911 mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 114614cf11afSPaul Mackerras | MPIC_GREG_GCONF_8259_PTHROU_DIS); 114714cf11afSPaul Mackerras 114814cf11afSPaul Mackerras /* Set current processor priority to 0 */ 11497233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 115014cf11afSPaul Mackerras } 115114cf11afSPaul Mackerras 1152868ea0c9SMark A. Greer void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio) 1153868ea0c9SMark A. Greer { 1154868ea0c9SMark A. Greer u32 v; 115514cf11afSPaul Mackerras 1156868ea0c9SMark A. Greer v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 1157868ea0c9SMark A. Greer v &= ~MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK; 1158868ea0c9SMark A. Greer v |= MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO(clock_ratio); 1159868ea0c9SMark A. Greer mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 1160868ea0c9SMark A. Greer } 1161868ea0c9SMark A. Greer 1162868ea0c9SMark A. Greer void __init mpic_set_serial_int(struct mpic *mpic, int enable) 1163868ea0c9SMark A. Greer { 1164ba1826e5SBenjamin Herrenschmidt unsigned long flags; 1165868ea0c9SMark A. Greer u32 v; 1166868ea0c9SMark A. Greer 1167ba1826e5SBenjamin Herrenschmidt spin_lock_irqsave(&mpic_lock, flags); 1168868ea0c9SMark A. Greer v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1); 1169868ea0c9SMark A. Greer if (enable) 1170868ea0c9SMark A. Greer v |= MPIC_GREG_GLOBAL_CONF_1_SIE; 1171868ea0c9SMark A. Greer else 1172868ea0c9SMark A. Greer v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE; 1173868ea0c9SMark A. Greer mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v); 1174ba1826e5SBenjamin Herrenschmidt spin_unlock_irqrestore(&mpic_lock, flags); 1175868ea0c9SMark A. Greer } 117614cf11afSPaul Mackerras 117714cf11afSPaul Mackerras void mpic_irq_set_priority(unsigned int irq, unsigned int pri) 117814cf11afSPaul Mackerras { 117914cf11afSPaul Mackerras int is_ipi; 118014cf11afSPaul Mackerras struct mpic *mpic = mpic_find(irq, &is_ipi); 11810ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 118214cf11afSPaul Mackerras unsigned long flags; 118314cf11afSPaul Mackerras u32 reg; 118414cf11afSPaul Mackerras 118514cf11afSPaul Mackerras spin_lock_irqsave(&mpic_lock, flags); 118614cf11afSPaul Mackerras if (is_ipi) { 11870ebfff14SBenjamin Herrenschmidt reg = mpic_ipi_read(src - MPIC_VEC_IPI_0) & 1188e5356640SBenjamin Herrenschmidt ~MPIC_VECPRI_PRIORITY_MASK; 11890ebfff14SBenjamin Herrenschmidt mpic_ipi_write(src - MPIC_VEC_IPI_0, 119014cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 119114cf11afSPaul Mackerras } else { 11927233593bSZang Roy-r61911 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) 1193e5356640SBenjamin Herrenschmidt & ~MPIC_VECPRI_PRIORITY_MASK; 11947233593bSZang Roy-r61911 mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), 119514cf11afSPaul Mackerras reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); 119614cf11afSPaul Mackerras } 119714cf11afSPaul Mackerras spin_unlock_irqrestore(&mpic_lock, flags); 119814cf11afSPaul Mackerras } 119914cf11afSPaul Mackerras 120014cf11afSPaul Mackerras unsigned int mpic_irq_get_priority(unsigned int irq) 120114cf11afSPaul Mackerras { 120214cf11afSPaul Mackerras int is_ipi; 120314cf11afSPaul Mackerras struct mpic *mpic = mpic_find(irq, &is_ipi); 12040ebfff14SBenjamin Herrenschmidt unsigned int src = mpic_irq_to_hw(irq); 120514cf11afSPaul Mackerras unsigned long flags; 120614cf11afSPaul Mackerras u32 reg; 120714cf11afSPaul Mackerras 120814cf11afSPaul Mackerras spin_lock_irqsave(&mpic_lock, flags); 120914cf11afSPaul Mackerras if (is_ipi) 12100ebfff14SBenjamin Herrenschmidt reg = mpic_ipi_read(src = MPIC_VEC_IPI_0); 121114cf11afSPaul Mackerras else 12127233593bSZang Roy-r61911 reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); 121314cf11afSPaul Mackerras spin_unlock_irqrestore(&mpic_lock, flags); 121414cf11afSPaul Mackerras return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT; 121514cf11afSPaul Mackerras } 121614cf11afSPaul Mackerras 121714cf11afSPaul Mackerras void mpic_setup_this_cpu(void) 121814cf11afSPaul Mackerras { 121914cf11afSPaul Mackerras #ifdef CONFIG_SMP 122014cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 122114cf11afSPaul Mackerras unsigned long flags; 122214cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 122314cf11afSPaul Mackerras unsigned int i; 122414cf11afSPaul Mackerras 122514cf11afSPaul Mackerras BUG_ON(mpic == NULL); 122614cf11afSPaul Mackerras 122714cf11afSPaul Mackerras DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 122814cf11afSPaul Mackerras 122914cf11afSPaul Mackerras spin_lock_irqsave(&mpic_lock, flags); 123014cf11afSPaul Mackerras 123114cf11afSPaul Mackerras /* let the mpic know we want intrs. default affinity is 0xffffffff 123214cf11afSPaul Mackerras * until changed via /proc. That's how it's done on x86. If we want 123314cf11afSPaul Mackerras * it differently, then we should make sure we also change the default 1234a53da52fSIngo Molnar * values of irq_desc[].affinity in irq.c. 123514cf11afSPaul Mackerras */ 123614cf11afSPaul Mackerras if (distribute_irqs) { 123714cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources ; i++) 12387233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 12397233593bSZang Roy-r61911 mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) | msk); 124014cf11afSPaul Mackerras } 124114cf11afSPaul Mackerras 124214cf11afSPaul Mackerras /* Set current processor priority to 0 */ 12437233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); 124414cf11afSPaul Mackerras 124514cf11afSPaul Mackerras spin_unlock_irqrestore(&mpic_lock, flags); 124614cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 124714cf11afSPaul Mackerras } 124814cf11afSPaul Mackerras 124914cf11afSPaul Mackerras int mpic_cpu_get_priority(void) 125014cf11afSPaul Mackerras { 125114cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 125214cf11afSPaul Mackerras 12537233593bSZang Roy-r61911 return mpic_cpu_read(MPIC_INFO(CPU_CURRENT_TASK_PRI)); 125414cf11afSPaul Mackerras } 125514cf11afSPaul Mackerras 125614cf11afSPaul Mackerras void mpic_cpu_set_priority(int prio) 125714cf11afSPaul Mackerras { 125814cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 125914cf11afSPaul Mackerras 126014cf11afSPaul Mackerras prio &= MPIC_CPU_TASKPRI_MASK; 12617233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), prio); 126214cf11afSPaul Mackerras } 126314cf11afSPaul Mackerras 126414cf11afSPaul Mackerras /* 126514cf11afSPaul Mackerras * XXX: someone who knows mpic should check this. 126614cf11afSPaul Mackerras * do we need to eoi the ipi including for kexec cpu here (see xics comments)? 126714cf11afSPaul Mackerras * or can we reset the mpic in the new kernel? 126814cf11afSPaul Mackerras */ 126914cf11afSPaul Mackerras void mpic_teardown_this_cpu(int secondary) 127014cf11afSPaul Mackerras { 127114cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 127214cf11afSPaul Mackerras unsigned long flags; 127314cf11afSPaul Mackerras u32 msk = 1 << hard_smp_processor_id(); 127414cf11afSPaul Mackerras unsigned int i; 127514cf11afSPaul Mackerras 127614cf11afSPaul Mackerras BUG_ON(mpic == NULL); 127714cf11afSPaul Mackerras 127814cf11afSPaul Mackerras DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); 127914cf11afSPaul Mackerras spin_lock_irqsave(&mpic_lock, flags); 128014cf11afSPaul Mackerras 128114cf11afSPaul Mackerras /* let the mpic know we don't want intrs. */ 128214cf11afSPaul Mackerras for (i = 0; i < mpic->num_sources ; i++) 12837233593bSZang Roy-r61911 mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 12847233593bSZang Roy-r61911 mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) & ~msk); 128514cf11afSPaul Mackerras 128614cf11afSPaul Mackerras /* Set current processor priority to max */ 12877233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); 128814cf11afSPaul Mackerras 128914cf11afSPaul Mackerras spin_unlock_irqrestore(&mpic_lock, flags); 129014cf11afSPaul Mackerras } 129114cf11afSPaul Mackerras 129214cf11afSPaul Mackerras 129314cf11afSPaul Mackerras void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) 129414cf11afSPaul Mackerras { 129514cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 129614cf11afSPaul Mackerras 129714cf11afSPaul Mackerras BUG_ON(mpic == NULL); 129814cf11afSPaul Mackerras 12991beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_IPI 130014cf11afSPaul Mackerras DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); 13011beb6a7dSBenjamin Herrenschmidt #endif 130214cf11afSPaul Mackerras 13037233593bSZang Roy-r61911 mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) + 13047233593bSZang Roy-r61911 ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), 130514cf11afSPaul Mackerras mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); 130614cf11afSPaul Mackerras } 130714cf11afSPaul Mackerras 130835a84c2fSOlaf Hering unsigned int mpic_get_one_irq(struct mpic *mpic) 130914cf11afSPaul Mackerras { 13100ebfff14SBenjamin Herrenschmidt u32 src; 131114cf11afSPaul Mackerras 13127233593bSZang Roy-r61911 src = mpic_cpu_read(MPIC_INFO(CPU_INTACK)) & MPIC_INFO(VECPRI_VECTOR_MASK); 13131beb6a7dSBenjamin Herrenschmidt #ifdef DEBUG_LOW 13140ebfff14SBenjamin Herrenschmidt DBG("%s: get_one_irq(): %d\n", mpic->name, src); 13151beb6a7dSBenjamin Herrenschmidt #endif 13160ebfff14SBenjamin Herrenschmidt if (unlikely(src == MPIC_VEC_SPURRIOUS)) 13170ebfff14SBenjamin Herrenschmidt return NO_IRQ; 13180ebfff14SBenjamin Herrenschmidt return irq_linear_revmap(mpic->irqhost, src); 131914cf11afSPaul Mackerras } 132014cf11afSPaul Mackerras 132135a84c2fSOlaf Hering unsigned int mpic_get_irq(void) 132214cf11afSPaul Mackerras { 132314cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 132414cf11afSPaul Mackerras 132514cf11afSPaul Mackerras BUG_ON(mpic == NULL); 132614cf11afSPaul Mackerras 132735a84c2fSOlaf Hering return mpic_get_one_irq(mpic); 132814cf11afSPaul Mackerras } 132914cf11afSPaul Mackerras 133014cf11afSPaul Mackerras 133114cf11afSPaul Mackerras #ifdef CONFIG_SMP 133214cf11afSPaul Mackerras void mpic_request_ipis(void) 133314cf11afSPaul Mackerras { 133414cf11afSPaul Mackerras struct mpic *mpic = mpic_primary; 13350ebfff14SBenjamin Herrenschmidt int i; 13360ebfff14SBenjamin Herrenschmidt static char *ipi_names[] = { 13370ebfff14SBenjamin Herrenschmidt "IPI0 (call function)", 13380ebfff14SBenjamin Herrenschmidt "IPI1 (reschedule)", 13390ebfff14SBenjamin Herrenschmidt "IPI2 (unused)", 13400ebfff14SBenjamin Herrenschmidt "IPI3 (debugger break)", 13410ebfff14SBenjamin Herrenschmidt }; 134214cf11afSPaul Mackerras BUG_ON(mpic == NULL); 134314cf11afSPaul Mackerras 13440ebfff14SBenjamin Herrenschmidt printk(KERN_INFO "mpic: requesting IPIs ... \n"); 134514cf11afSPaul Mackerras 13460ebfff14SBenjamin Herrenschmidt for (i = 0; i < 4; i++) { 13470ebfff14SBenjamin Herrenschmidt unsigned int vipi = irq_create_mapping(mpic->irqhost, 13486e99e458SBenjamin Herrenschmidt MPIC_VEC_IPI_0 + i); 13490ebfff14SBenjamin Herrenschmidt if (vipi == NO_IRQ) { 13500ebfff14SBenjamin Herrenschmidt printk(KERN_ERR "Failed to map IPI %d\n", i); 13510ebfff14SBenjamin Herrenschmidt break; 13520ebfff14SBenjamin Herrenschmidt } 13530ebfff14SBenjamin Herrenschmidt request_irq(vipi, mpic_ipi_action, IRQF_DISABLED, 13540ebfff14SBenjamin Herrenschmidt ipi_names[i], mpic); 13550ebfff14SBenjamin Herrenschmidt } 135614cf11afSPaul Mackerras } 1357a9c59264SPaul Mackerras 1358a9c59264SPaul Mackerras void smp_mpic_message_pass(int target, int msg) 1359a9c59264SPaul Mackerras { 1360a9c59264SPaul Mackerras /* make sure we're sending something that translates to an IPI */ 1361a9c59264SPaul Mackerras if ((unsigned int)msg > 3) { 1362a9c59264SPaul Mackerras printk("SMP %d: smp_message_pass: unknown msg %d\n", 1363a9c59264SPaul Mackerras smp_processor_id(), msg); 1364a9c59264SPaul Mackerras return; 1365a9c59264SPaul Mackerras } 1366a9c59264SPaul Mackerras switch (target) { 1367a9c59264SPaul Mackerras case MSG_ALL: 1368a9c59264SPaul Mackerras mpic_send_ipi(msg, 0xffffffff); 1369a9c59264SPaul Mackerras break; 1370a9c59264SPaul Mackerras case MSG_ALL_BUT_SELF: 1371a9c59264SPaul Mackerras mpic_send_ipi(msg, 0xffffffff & ~(1 << smp_processor_id())); 1372a9c59264SPaul Mackerras break; 1373a9c59264SPaul Mackerras default: 1374a9c59264SPaul Mackerras mpic_send_ipi(msg, 1 << target); 1375a9c59264SPaul Mackerras break; 1376a9c59264SPaul Mackerras } 1377a9c59264SPaul Mackerras } 137814cf11afSPaul Mackerras #endif /* CONFIG_SMP */ 1379