mp_cpudep.c revision 190681
1/*- 2 * Copyright (c) 2008 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/powerpc/aim/mp_cpudep.c 190681 2009-04-04 00:22:44Z nwhitehorn $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/kernel.h> 33#include <sys/bus.h> 34#include <sys/pcpu.h> 35#include <sys/proc.h> 36#include <sys/smp.h> 37 38#include <machine/bus.h> 39#include <machine/cpu.h> 40#include <machine/hid.h> 41#include <machine/intr_machdep.h> 42#include <machine/pcb.h> 43#include <machine/psl.h> 44#include <machine/smp.h> 45#include <machine/spr.h> 46#include <machine/trap_aim.h> 47 48#include <dev/ofw/openfirm.h> 49#include <machine/ofw_machdep.h> 50 51extern void *rstcode; 52extern register_t l2cr_config; 53extern register_t l3cr_config; 54 55void *ap_pcpu; 56 57static int 58powerpc_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu) 59{ 60 int cpuid, res; 61 62 cpuref->cr_hwref = cpu; 63 res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 64 if (res < 0) 65 return (ENOENT); 66 67 cpuref->cr_cpuid = cpuid & 0xff; 68 return (0); 69} 70 71int 72powerpc_smp_first_cpu(struct cpuref *cpuref) 73{ 74 char buf[8]; 75 phandle_t cpu, dev, root; 76 int res; 77 78 root = OF_peer(0); 79 80 dev = OF_child(root); 81 while (dev != 0) { 82 res = OF_getprop(dev, "name", buf, sizeof(buf)); 83 if (res > 0 && strcmp(buf, "cpus") == 0) 84 break; 85 dev = OF_peer(dev); 86 } 87 if (dev == 0) 88 return (ENOENT); 89 90 cpu = OF_child(dev); 91 while (cpu != 0) { 92 res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 93 if (res > 0 && strcmp(buf, "cpu") == 0) 94 break; 95 cpu = OF_peer(cpu); 96 } 97 if (cpu == 0) 98 return (ENOENT); 99 100 return (powerpc_smp_fill_cpuref(cpuref, cpu)); 101} 102 103int 104powerpc_smp_next_cpu(struct cpuref *cpuref) 105{ 106 char buf[8]; 107 phandle_t cpu; 108 int res; 109 110 cpu = OF_peer(cpuref->cr_hwref); 111 while (cpu != 0) { 112 res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 113 if (res > 0 && strcmp(buf, "cpu") == 0) 114 break; 115 cpu = OF_peer(cpu); 116 } 117 if (cpu == 0) 118 return (ENOENT); 119 120 return (powerpc_smp_fill_cpuref(cpuref, cpu)); 121} 122 123int 124powerpc_smp_get_bsp(struct cpuref *cpuref) 125{ 126 ihandle_t inst; 127 phandle_t bsp, chosen; 128 int res; 129 130 chosen = OF_finddevice("/chosen"); 131 if (chosen == 0) 132 return (ENXIO); 133 134 res = OF_getprop(chosen, "cpu", &inst, sizeof(inst)); 135 if (res < 0) 136 return (ENXIO); 137 138 bsp = OF_instance_to_package(inst); 139 return (powerpc_smp_fill_cpuref(cpuref, bsp)); 140} 141 142static register_t 143l2_enable(void) 144{ 145 register_t ccr; 146 147 ccr = mfspr(SPR_L2CR); 148 if (ccr & L2CR_L2E) 149 return (ccr); 150 151 /* Configure L2 cache. */ 152 ccr = l2cr_config & ~L2CR_L2E; 153 mtspr(SPR_L2CR, ccr | L2CR_L2I); 154 do { 155 ccr = mfspr(SPR_L2CR); 156 } while (ccr & L2CR_L2I); 157 powerpc_sync(); 158 mtspr(SPR_L2CR, l2cr_config); 159 powerpc_sync(); 160 161 return (l2cr_config); 162} 163 164static register_t 165l3_enable(void) 166{ 167 register_t ccr; 168 169 ccr = mfspr(SPR_L3CR); 170 if (ccr & L3CR_L3E) 171 return (ccr); 172 173 /* Configure L3 cache. */ 174 ccr = l3cr_config & ~(L3CR_L3E | L3CR_L3I | L3CR_L3PE | L3CR_L3CLKEN); 175 mtspr(SPR_L3CR, ccr); 176 ccr |= 0x4000000; /* Magic, but documented. */ 177 mtspr(SPR_L3CR, ccr); 178 ccr |= L3CR_L3CLKEN; 179 mtspr(SPR_L3CR, ccr); 180 mtspr(SPR_L3CR, ccr | L3CR_L3I); 181 while (mfspr(SPR_L3CR) & L3CR_L3I) 182 ; 183 mtspr(SPR_L3CR, ccr & ~L3CR_L3CLKEN); 184 powerpc_sync(); 185 DELAY(100); 186 mtspr(SPR_L3CR, ccr); 187 powerpc_sync(); 188 DELAY(100); 189 ccr |= L3CR_L3E; 190 mtspr(SPR_L3CR, ccr); 191 powerpc_sync(); 192 193 return(ccr); 194} 195 196static register_t 197l1d_enable(void) 198{ 199 register_t hid; 200 201 hid = mfspr(SPR_HID0); 202 if (hid & HID0_DCE) 203 return (hid); 204 205 /* Enable L1 D-cache */ 206 hid |= HID0_DCE; 207 powerpc_sync(); 208 mtspr(SPR_HID0, hid | HID0_DCFI); 209 powerpc_sync(); 210 211 return (hid); 212} 213 214static register_t 215l1i_enable(void) 216{ 217 register_t hid; 218 219 hid = mfspr(SPR_HID0); 220 if (hid & HID0_ICE) 221 return (hid); 222 223 /* Enable L1 I-cache */ 224 hid |= HID0_ICE; 225 isync(); 226 mtspr(SPR_HID0, hid | HID0_ICFI); 227 isync(); 228 229 return (hid); 230} 231 232uint32_t 233cpudep_ap_bootstrap(void) 234{ 235 uint32_t hid, msr, reg, sp; 236 237 // reg = mfspr(SPR_MSSCR0); 238 // mtspr(SPR_MSSCR0, reg | 0x3); 239 240 __asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu)); 241 powerpc_sync(); 242 243 __asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid))); 244 __asm __volatile("mfspr %0,1023" : "=r"(pcpup->pc_pir)); 245 246 msr = PSL_FP | PSL_IR | PSL_DR | PSL_ME | PSL_RI; 247 powerpc_sync(); 248 isync(); 249 mtmsr(msr); 250 isync(); 251 252 if (l3cr_config != 0) 253 reg = l3_enable(); 254 if (l2cr_config != 0) 255 reg = l2_enable(); 256 reg = l1d_enable(); 257 reg = l1i_enable(); 258 259 hid = mfspr(SPR_HID0); 260 hid &= ~(HID0_DOZE | HID0_SLEEP); 261 hid |= HID0_NAP | HID0_DPM; 262 mtspr(SPR_HID0, hid); 263 isync(); 264 265 pcpup->pc_curthread = pcpup->pc_idlethread; 266 pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb; 267 sp = pcpup->pc_curpcb->pcb_sp; 268 269 return (sp); 270} 271 272int 273powerpc_smp_start_cpu(struct pcpu *pc) 274{ 275 phandle_t cpu; 276 volatile uint8_t *rstvec; 277 int res, reset, timeout; 278 279 cpu = pc->pc_hwref; 280 res = OF_getprop(cpu, "soft-reset", &reset, sizeof(reset)); 281 if (res < 0) 282 return (ENXIO); 283 284 ap_pcpu = pc; 285 286 rstvec = (uint8_t *)(0x80000000 + reset); 287 288 *rstvec = 4; 289 powerpc_sync(); 290 DELAY(1); 291 *rstvec = 0; 292 powerpc_sync(); 293 294 timeout = 1000; 295 while (!pc->pc_awake && timeout--) 296 DELAY(100); 297 298 return ((pc->pc_awake) ? 0 : EBUSY); 299} 300