| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 1 | /* | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 2 | *  This program is free software; you can distribute it and/or modify it | 
|  | 3 | *  under the terms of the GNU General Public License (Version 2) as | 
|  | 4 | *  published by the Free Software Foundation. | 
|  | 5 | * | 
|  | 6 | *  This program is distributed in the hope it will be useful, but WITHOUT | 
|  | 7 | *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|  | 8 | *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|  | 9 | *  for more details. | 
|  | 10 | * | 
|  | 11 | *  You should have received a copy of the GNU General Public License along | 
|  | 12 | *  with this program; if not, write to the Free Software Foundation, Inc., | 
|  | 13 | *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 
|  | 14 | * | 
| Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 15 | * Copyright (C) 2004, 05, 06 MIPS Technologies, Inc. | 
|  | 16 | *    Elizabeth Clarke (beth@mips.com) | 
|  | 17 | *    Ralf Baechle (ralf@linux-mips.org) | 
|  | 18 | * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org) | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 19 | */ | 
|  | 20 | #include <linux/kernel.h> | 
|  | 21 | #include <linux/sched.h> | 
|  | 22 | #include <linux/cpumask.h> | 
|  | 23 | #include <linux/interrupt.h> | 
|  | 24 | #include <linux/compiler.h> | 
|  | 25 |  | 
|  | 26 | #include <asm/atomic.h> | 
| Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 27 | #include <asm/cacheflush.h> | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 28 | #include <asm/cpu.h> | 
|  | 29 | #include <asm/processor.h> | 
|  | 30 | #include <asm/system.h> | 
|  | 31 | #include <asm/hardirq.h> | 
|  | 32 | #include <asm/mmu_context.h> | 
|  | 33 | #include <asm/smp.h> | 
|  | 34 | #include <asm/time.h> | 
|  | 35 | #include <asm/mipsregs.h> | 
|  | 36 | #include <asm/mipsmtregs.h> | 
| Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 37 | #include <asm/mips_mt.h> | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 38 |  | 
|  | 39 | #define MIPS_CPU_IPI_RESCHED_IRQ 0 | 
|  | 40 | #define MIPS_CPU_IPI_CALL_IRQ 1 | 
|  | 41 |  | 
|  | 42 | static int cpu_ipi_resched_irq, cpu_ipi_call_irq; | 
|  | 43 |  | 
|  | 44 | #if 0 | 
|  | 45 | static void dump_mtregisters(int vpe, int tc) | 
|  | 46 | { | 
|  | 47 | printk("vpe %d tc %d\n", vpe, tc); | 
|  | 48 |  | 
|  | 49 | settc(tc); | 
|  | 50 |  | 
|  | 51 | printk("  c0 status  0x%lx\n", read_vpe_c0_status()); | 
|  | 52 | printk("  vpecontrol 0x%lx\n", read_vpe_c0_vpecontrol()); | 
|  | 53 | printk("  vpeconf0    0x%lx\n", read_vpe_c0_vpeconf0()); | 
|  | 54 | printk("  tcstatus 0x%lx\n", read_tc_c0_tcstatus()); | 
|  | 55 | printk("  tcrestart 0x%lx\n", read_tc_c0_tcrestart()); | 
|  | 56 | printk("  tcbind 0x%lx\n", read_tc_c0_tcbind()); | 
|  | 57 | printk("  tchalt 0x%lx\n", read_tc_c0_tchalt()); | 
|  | 58 | } | 
|  | 59 | #endif | 
|  | 60 |  | 
|  | 61 | void __init sanitize_tlb_entries(void) | 
|  | 62 | { | 
|  | 63 | int i, tlbsiz; | 
|  | 64 | unsigned long mvpconf0, ncpu; | 
|  | 65 |  | 
|  | 66 | if (!cpu_has_mipsmt) | 
|  | 67 | return; | 
|  | 68 |  | 
| Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 69 | /* Enable VPC */ | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 70 | set_c0_mvpcontrol(MVPCONTROL_VPC); | 
|  | 71 |  | 
| Ralf Baechle | fdc9bb1 | 2006-02-10 14:25:16 +0000 | [diff] [blame] | 72 | back_to_back_c0_hazard(); | 
|  | 73 |  | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 74 | /* Disable TLB sharing */ | 
|  | 75 | clear_c0_mvpcontrol(MVPCONTROL_STLB); | 
|  | 76 |  | 
|  | 77 | mvpconf0 = read_c0_mvpconf0(); | 
|  | 78 |  | 
|  | 79 | printk(KERN_INFO "MVPConf0 0x%lx TLBS %lx PTLBE %ld\n", mvpconf0, | 
|  | 80 | (mvpconf0 & MVPCONF0_TLBS) >> MVPCONF0_TLBS_SHIFT, | 
|  | 81 | (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT); | 
|  | 82 |  | 
|  | 83 | tlbsiz = (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT; | 
|  | 84 | ncpu = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; | 
|  | 85 |  | 
|  | 86 | printk(" tlbsiz %d ncpu %ld\n", tlbsiz, ncpu); | 
|  | 87 |  | 
|  | 88 | if (tlbsiz > 0) { | 
|  | 89 | /* share them out across the vpe's */ | 
|  | 90 | tlbsiz /= ncpu; | 
|  | 91 |  | 
|  | 92 | printk(KERN_INFO "setting Config1.MMU_size to %d\n", tlbsiz); | 
|  | 93 |  | 
|  | 94 | for (i = 0; i < ncpu; i++) { | 
|  | 95 | settc(i); | 
|  | 96 |  | 
|  | 97 | if (i == 0) | 
|  | 98 | write_c0_config1((read_c0_config1() & ~(0x3f << 25)) | (tlbsiz << 25)); | 
|  | 99 | else | 
|  | 100 | write_vpe_c0_config1((read_vpe_c0_config1() & ~(0x3f << 25)) | | 
|  | 101 | (tlbsiz << 25)); | 
|  | 102 | } | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | clear_c0_mvpcontrol(MVPCONTROL_VPC); | 
|  | 106 | } | 
|  | 107 |  | 
| Ralf Baechle | 937a801 | 2006-10-07 19:44:33 +0100 | [diff] [blame] | 108 | static void ipi_resched_dispatch(void) | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 109 | { | 
| Atsushi Nemoto | 97dcb82 | 2007-01-08 02:14:29 +0900 | [diff] [blame] | 110 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 111 | } | 
|  | 112 |  | 
| Ralf Baechle | 937a801 | 2006-10-07 19:44:33 +0100 | [diff] [blame] | 113 | static void ipi_call_dispatch(void) | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 114 | { | 
| Atsushi Nemoto | 97dcb82 | 2007-01-08 02:14:29 +0900 | [diff] [blame] | 115 | do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 116 | } | 
|  | 117 |  | 
| Ralf Baechle | 937a801 | 2006-10-07 19:44:33 +0100 | [diff] [blame] | 118 | static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 119 | { | 
|  | 120 | return IRQ_HANDLED; | 
|  | 121 | } | 
|  | 122 |  | 
| Ralf Baechle | 937a801 | 2006-10-07 19:44:33 +0100 | [diff] [blame] | 123 | static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 124 | { | 
|  | 125 | smp_call_function_interrupt(); | 
|  | 126 |  | 
|  | 127 | return IRQ_HANDLED; | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | static struct irqaction irq_resched = { | 
|  | 131 | .handler	= ipi_resched_interrupt, | 
| Chris Dearman | ffe9ee4 | 2007-05-24 22:24:20 +0100 | [diff] [blame] | 132 | .flags		= IRQF_DISABLED|IRQF_PERCPU, | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 133 | .name		= "IPI_resched" | 
|  | 134 | }; | 
|  | 135 |  | 
|  | 136 | static struct irqaction irq_call = { | 
|  | 137 | .handler	= ipi_call_interrupt, | 
| Chris Dearman | ffe9ee4 | 2007-05-24 22:24:20 +0100 | [diff] [blame] | 138 | .flags		= IRQF_DISABLED|IRQF_PERCPU, | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 139 | .name		= "IPI_call" | 
|  | 140 | }; | 
|  | 141 |  | 
| Ralf Baechle | 781b0f8 | 2006-10-31 18:25:10 +0000 | [diff] [blame] | 142 | static void __init smp_copy_vpe_config(void) | 
|  | 143 | { | 
|  | 144 | write_vpe_c0_status( | 
|  | 145 | (read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0); | 
|  | 146 |  | 
|  | 147 | /* set config to be the same as vpe0, particularly kseg0 coherency alg */ | 
|  | 148 | write_vpe_c0_config( read_c0_config()); | 
|  | 149 |  | 
|  | 150 | /* make sure there are no software interrupts pending */ | 
|  | 151 | write_vpe_c0_cause(0); | 
|  | 152 |  | 
|  | 153 | /* Propagate Config7 */ | 
|  | 154 | write_vpe_c0_config7(read_c0_config7()); | 
| Ralf Baechle | 70e46f4 | 2006-10-31 18:33:09 +0000 | [diff] [blame] | 155 |  | 
|  | 156 | write_vpe_c0_count(read_c0_count()); | 
| Ralf Baechle | 781b0f8 | 2006-10-31 18:25:10 +0000 | [diff] [blame] | 157 | } | 
|  | 158 |  | 
|  | 159 | static unsigned int __init smp_vpe_init(unsigned int tc, unsigned int mvpconf0, | 
|  | 160 | unsigned int ncpu) | 
|  | 161 | { | 
|  | 162 | if (tc > ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)) | 
|  | 163 | return ncpu; | 
|  | 164 |  | 
|  | 165 | /* Deactivate all but VPE 0 */ | 
|  | 166 | if (tc != 0) { | 
|  | 167 | unsigned long tmp = read_vpe_c0_vpeconf0(); | 
|  | 168 |  | 
|  | 169 | tmp &= ~VPECONF0_VPA; | 
|  | 170 |  | 
|  | 171 | /* master VPE */ | 
|  | 172 | tmp |= VPECONF0_MVP; | 
|  | 173 | write_vpe_c0_vpeconf0(tmp); | 
|  | 174 |  | 
|  | 175 | /* Record this as available CPU */ | 
|  | 176 | cpu_set(tc, phys_cpu_present_map); | 
|  | 177 | __cpu_number_map[tc]	= ++ncpu; | 
|  | 178 | __cpu_logical_map[ncpu]	= tc; | 
|  | 179 | } | 
|  | 180 |  | 
|  | 181 | /* Disable multi-threading with TC's */ | 
|  | 182 | write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); | 
|  | 183 |  | 
|  | 184 | if (tc != 0) | 
|  | 185 | smp_copy_vpe_config(); | 
|  | 186 |  | 
|  | 187 | return ncpu; | 
|  | 188 | } | 
|  | 189 |  | 
|  | 190 | static void __init smp_tc_init(unsigned int tc, unsigned int mvpconf0) | 
|  | 191 | { | 
|  | 192 | unsigned long tmp; | 
|  | 193 |  | 
|  | 194 | if (!tc) | 
|  | 195 | return; | 
|  | 196 |  | 
|  | 197 | /* bind a TC to each VPE, May as well put all excess TC's | 
|  | 198 | on the last VPE */ | 
|  | 199 | if (tc >= (((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)+1)) | 
|  | 200 | write_tc_c0_tcbind(read_tc_c0_tcbind() | ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)); | 
|  | 201 | else { | 
|  | 202 | write_tc_c0_tcbind(read_tc_c0_tcbind() | tc); | 
|  | 203 |  | 
|  | 204 | /* and set XTC */ | 
|  | 205 | write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (tc << VPECONF0_XTC_SHIFT)); | 
|  | 206 | } | 
|  | 207 |  | 
|  | 208 | tmp = read_tc_c0_tcstatus(); | 
|  | 209 |  | 
|  | 210 | /* mark not allocated and not dynamically allocatable */ | 
|  | 211 | tmp &= ~(TCSTATUS_A | TCSTATUS_DA); | 
|  | 212 | tmp |= TCSTATUS_IXMT;		/* interrupt exempt */ | 
|  | 213 | write_tc_c0_tcstatus(tmp); | 
|  | 214 |  | 
|  | 215 | write_tc_c0_tchalt(TCHALT_H); | 
|  | 216 | } | 
|  | 217 |  | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 218 | /* | 
|  | 219 | * Common setup before any secondaries are started | 
|  | 220 | * Make sure all CPU's are in a sensible state before we boot any of the | 
|  | 221 | * secondarys | 
|  | 222 | */ | 
| Ralf Baechle | 781b0f8 | 2006-10-31 18:25:10 +0000 | [diff] [blame] | 223 | void __init plat_smp_setup(void) | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 224 | { | 
| Ralf Baechle | 781b0f8 | 2006-10-31 18:25:10 +0000 | [diff] [blame] | 225 | unsigned int mvpconf0, ntc, tc, ncpu = 0; | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 226 |  | 
| Ralf Baechle | f088fc8 | 2006-04-05 09:45:47 +0100 | [diff] [blame] | 227 | #ifdef CONFIG_MIPS_MT_FPAFF | 
|  | 228 | /* If we have an FPU, enroll ourselves in the FPU-full mask */ | 
|  | 229 | if (cpu_has_fpu) | 
|  | 230 | cpu_set(0, mt_fpu_cpumask); | 
|  | 231 | #endif /* CONFIG_MIPS_MT_FPAFF */ | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 232 | if (!cpu_has_mipsmt) | 
|  | 233 | return; | 
|  | 234 |  | 
|  | 235 | /* disable MT so we can configure */ | 
|  | 236 | dvpe(); | 
|  | 237 | dmt(); | 
|  | 238 |  | 
|  | 239 | /* Put MVPE's into 'configuration state' */ | 
|  | 240 | set_c0_mvpcontrol(MVPCONTROL_VPC); | 
|  | 241 |  | 
| Ralf Baechle | 781b0f8 | 2006-10-31 18:25:10 +0000 | [diff] [blame] | 242 | mvpconf0 = read_c0_mvpconf0(); | 
|  | 243 | ntc = (mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT; | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 244 |  | 
|  | 245 | /* we'll always have more TC's than VPE's, so loop setting everything | 
|  | 246 | to a sensible state */ | 
| Ralf Baechle | 781b0f8 | 2006-10-31 18:25:10 +0000 | [diff] [blame] | 247 | for (tc = 0; tc <= ntc; tc++) { | 
|  | 248 | settc(tc); | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 249 |  | 
| Ralf Baechle | 781b0f8 | 2006-10-31 18:25:10 +0000 | [diff] [blame] | 250 | smp_tc_init(tc, mvpconf0); | 
|  | 251 | ncpu = smp_vpe_init(tc, mvpconf0, ncpu); | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 252 | } | 
|  | 253 |  | 
|  | 254 | /* Release config state */ | 
|  | 255 | clear_c0_mvpcontrol(MVPCONTROL_VPC); | 
|  | 256 |  | 
|  | 257 | /* We'll wait until starting the secondaries before starting MVPE */ | 
|  | 258 |  | 
| Ralf Baechle | 781b0f8 | 2006-10-31 18:25:10 +0000 | [diff] [blame] | 259 | printk(KERN_INFO "Detected %i available secondary CPU(s)\n", ncpu); | 
| Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 260 | } | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 261 |  | 
| Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 262 | void __init plat_prepare_cpus(unsigned int max_cpus) | 
|  | 263 | { | 
| Ralf Baechle | 8c976e3 | 2007-07-03 18:25:58 +0200 | [diff] [blame] | 264 | mips_mt_set_cpuoptions(); | 
|  | 265 |  | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 266 | /* set up ipi interrupts */ | 
|  | 267 | if (cpu_has_vint) { | 
| Ralf Baechle | 937a801 | 2006-10-07 19:44:33 +0100 | [diff] [blame] | 268 | set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); | 
|  | 269 | set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 270 | } | 
|  | 271 |  | 
| Atsushi Nemoto | 97dcb82 | 2007-01-08 02:14:29 +0900 | [diff] [blame] | 272 | cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ; | 
|  | 273 | cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ; | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 274 |  | 
|  | 275 | setup_irq(cpu_ipi_resched_irq, &irq_resched); | 
|  | 276 | setup_irq(cpu_ipi_call_irq, &irq_call); | 
|  | 277 |  | 
| Atsushi Nemoto | 1417836 | 2006-11-14 01:13:18 +0900 | [diff] [blame] | 278 | set_irq_handler(cpu_ipi_resched_irq, handle_percpu_irq); | 
| Atsushi Nemoto | 1417836 | 2006-11-14 01:13:18 +0900 | [diff] [blame] | 279 | set_irq_handler(cpu_ipi_call_irq, handle_percpu_irq); | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 280 | } | 
|  | 281 |  | 
|  | 282 | /* | 
|  | 283 | * Setup the PC, SP, and GP of a secondary processor and start it | 
|  | 284 | * running! | 
|  | 285 | * smp_bootstrap is the place to resume from | 
|  | 286 | * __KSTK_TOS(idle) is apparently the stack pointer | 
|  | 287 | * (unsigned long)idle->thread_info the gp | 
|  | 288 | * assumes a 1:1 mapping of TC => VPE | 
|  | 289 | */ | 
| Ralf Baechle | 428ab28 | 2007-08-06 14:02:12 +0100 | [diff] [blame] | 290 | void __cpuinit prom_boot_secondary(int cpu, struct task_struct *idle) | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 291 | { | 
| Al Viro | dc8f602 | 2006-01-12 01:06:07 -0800 | [diff] [blame] | 292 | struct thread_info *gp = task_thread_info(idle); | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 293 | dvpe(); | 
|  | 294 | set_c0_mvpcontrol(MVPCONTROL_VPC); | 
|  | 295 |  | 
|  | 296 | settc(cpu); | 
|  | 297 |  | 
|  | 298 | /* restart */ | 
|  | 299 | write_tc_c0_tcrestart((unsigned long)&smp_bootstrap); | 
|  | 300 |  | 
|  | 301 | /* enable the tc this vpe/cpu will be running */ | 
|  | 302 | write_tc_c0_tcstatus((read_tc_c0_tcstatus() & ~TCSTATUS_IXMT) | TCSTATUS_A); | 
|  | 303 |  | 
|  | 304 | write_tc_c0_tchalt(0); | 
|  | 305 |  | 
|  | 306 | /* enable the VPE */ | 
|  | 307 | write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); | 
|  | 308 |  | 
|  | 309 | /* stack pointer */ | 
|  | 310 | write_tc_gpr_sp( __KSTK_TOS(idle)); | 
|  | 311 |  | 
|  | 312 | /* global pointer */ | 
| Al Viro | dc8f602 | 2006-01-12 01:06:07 -0800 | [diff] [blame] | 313 | write_tc_gpr_gp((unsigned long)gp); | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 314 |  | 
| Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 315 | flush_icache_range((unsigned long)gp, | 
|  | 316 | (unsigned long)(gp + sizeof(struct thread_info))); | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 317 |  | 
|  | 318 | /* finally out of configuration and into chaos */ | 
|  | 319 | clear_c0_mvpcontrol(MVPCONTROL_VPC); | 
|  | 320 |  | 
|  | 321 | evpe(EVPE_ENABLE); | 
|  | 322 | } | 
|  | 323 |  | 
| Ralf Baechle | 428ab28 | 2007-08-06 14:02:12 +0100 | [diff] [blame] | 324 | void __cpuinit prom_init_secondary(void) | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 325 | { | 
| Chris Dearman | ffe9ee4 | 2007-05-24 22:24:20 +0100 | [diff] [blame] | 326 | /* Enable per-cpu interrupts */ | 
|  | 327 |  | 
|  | 328 | /* This is Malta specific: IPI,performance and timer inetrrupts */ | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 329 | write_c0_status((read_c0_status() & ~ST0_IM ) | | 
| Chris Dearman | ffe9ee4 | 2007-05-24 22:24:20 +0100 | [diff] [blame] | 330 | (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP6 | STATUSF_IP7)); | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 331 | } | 
|  | 332 |  | 
| Ralf Baechle | 428ab28 | 2007-08-06 14:02:12 +0100 | [diff] [blame] | 333 | void __cpuinit prom_smp_finish(void) | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 334 | { | 
|  | 335 | write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ)); | 
|  | 336 |  | 
| Ralf Baechle | f088fc8 | 2006-04-05 09:45:47 +0100 | [diff] [blame] | 337 | #ifdef CONFIG_MIPS_MT_FPAFF | 
|  | 338 | /* If we have an FPU, enroll ourselves in the FPU-full mask */ | 
|  | 339 | if (cpu_has_fpu) | 
|  | 340 | cpu_set(smp_processor_id(), mt_fpu_cpumask); | 
|  | 341 | #endif /* CONFIG_MIPS_MT_FPAFF */ | 
|  | 342 |  | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 343 | local_irq_enable(); | 
|  | 344 | } | 
|  | 345 |  | 
|  | 346 | void prom_cpus_done(void) | 
|  | 347 | { | 
|  | 348 | } | 
|  | 349 |  | 
|  | 350 | void core_send_ipi(int cpu, unsigned int action) | 
|  | 351 | { | 
|  | 352 | int i; | 
|  | 353 | unsigned long flags; | 
|  | 354 | int vpflags; | 
|  | 355 |  | 
| Ralf Baechle | 49a89ef | 2007-10-11 23:46:15 +0100 | [diff] [blame] | 356 | local_irq_save(flags); | 
| Ralf Baechle | 340ee4b | 2005-08-17 17:44:08 +0000 | [diff] [blame] | 357 |  | 
|  | 358 | vpflags = dvpe();	/* cant access the other CPU's registers whilst MVPE enabled */ | 
|  | 359 |  | 
|  | 360 | switch (action) { | 
|  | 361 | case SMP_CALL_FUNCTION: | 
|  | 362 | i = C_SW1; | 
|  | 363 | break; | 
|  | 364 |  | 
|  | 365 | case SMP_RESCHEDULE_YOURSELF: | 
|  | 366 | default: | 
|  | 367 | i = C_SW0; | 
|  | 368 | break; | 
|  | 369 | } | 
|  | 370 |  | 
|  | 371 | /* 1:1 mapping of vpe and tc... */ | 
|  | 372 | settc(cpu); | 
|  | 373 | write_vpe_c0_cause(read_vpe_c0_cause() | i); | 
|  | 374 | evpe(vpflags); | 
|  | 375 |  | 
|  | 376 | local_irq_restore(flags); | 
|  | 377 | } |