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$"); 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/bat.h> 39 #include <machine/bus.h> 40 #include <machine/cpu.h> 41 #include <machine/hid.h> 42 #include <machine/intr_machdep.h> 43 #include <machine/pcb.h> 44 #include <machine/psl.h> 45 #include <machine/smp.h> 46 #include <machine/spr.h> 47 #include <machine/trap_aim.h> 48 49 #include <dev/ofw/openfirm.h> 50 #include <machine/ofw_machdep.h> 51 52 extern void *rstcode; 53 54 void *ap_pcpu; 55 56 static int 57 powerpc_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu) 58 { 59 int cpuid, res; 60 61 cpuref->cr_hwref = cpu; 62 res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 63 if (res < 0) 64 return (ENOENT); 65 66 cpuref->cr_cpuid = cpuid & 0xff; 67 return (0); 68 } 69 70 int 71 powerpc_smp_first_cpu(struct cpuref *cpuref) 72 { 73 char buf[8]; 74 phandle_t cpu, dev, root; 75 int res; 76 77 root = OF_peer(0); 78 79 dev = OF_child(root); 80 while (dev != 0) { 81 res = OF_getprop(dev, "name", buf, sizeof(buf)); 82 if (res > 0 && strcmp(buf, "cpus") == 0) 83 break; 84 dev = OF_peer(dev); 85 } 86 if (dev == 0) 87 return (ENOENT); 88 89 cpu = OF_child(dev); 90 while (cpu != 0) { 91 res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 92 if (res > 0 && strcmp(buf, "cpu") == 0) 93 break; 94 cpu = OF_peer(cpu); 95 } 96 if (cpu == 0) 97 return (ENOENT); 98 99 return (powerpc_smp_fill_cpuref(cpuref, cpu)); 100 } 101 102 int 103 powerpc_smp_next_cpu(struct cpuref *cpuref) 104 { 105 char buf[8]; 106 phandle_t cpu; 107 int res; 108 109 cpu = OF_peer(cpuref->cr_hwref); 110 while (cpu != 0) { 111 res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 112 if (res > 0 && strcmp(buf, "cpu") == 0) 113 break; 114 cpu = OF_peer(cpu); 115 } 116 if (cpu == 0) 117 return (ENOENT); 118 119 return (powerpc_smp_fill_cpuref(cpuref, cpu)); 120 } 121 122 int 123 powerpc_smp_get_bsp(struct cpuref *cpuref) 124 { 125 ihandle_t inst; 126 phandle_t bsp, chosen; 127 int res; 128 129 chosen = OF_finddevice("/chosen"); 130 if (chosen == 0) 131 return (ENXIO); 132 133 res = OF_getprop(chosen, "cpu", &inst, sizeof(inst)); 134 if (res < 0) 135 return (ENXIO); 136 137 bsp = OF_instance_to_package(inst); 138 return (powerpc_smp_fill_cpuref(cpuref, bsp)); 139 } 140 141 uint32_t 142 cpudep_ap_bootstrap(volatile uint32_t *trcp) 143 { 144 uint32_t hid, msr, sp; 145 146 trcp[0] = 0x2000; 147 trcp[1] = (uint32_t)&cpudep_ap_bootstrap; 148 149 __asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu)); 150 __asm __volatile("sync"); 151 152 trcp[0] = 0x2001; 153 trcp[1] = (uint32_t)pcpup; 154 155 hid = mfspr(SPR_HID0); 156 hid &= ~(HID0_ICE | HID0_DCE); 157 hid &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); 158 mtspr(SPR_HID0, hid); 159 isync(); 160 161 trcp[0] = 0x2002; 162 trcp[1] = hid; 163 164 hid |= HID0_ICFI | HID0_DCFI; 165 hid |= HID0_ICE | HID0_DCE; 166 mtspr(SPR_HID0, hid); 167 isync(); 168 169 trcp[0] = 0x2003; 170 trcp[1] = hid; 171 172 msr = PSL_IR | PSL_DR | PSL_ME | PSL_RI; 173 mtmsr(msr); 174 isync(); 175 176 trcp[0] = 0x2004; 177 trcp[1] = msr; 178 179 hid |= HID0_NAP | HID0_DPM; 180 mtspr(SPR_HID0, hid); 181 isync(); 182 183 trcp[0] = 0x2005; 184 trcp[1] = hid; 185 186 pcpup->pc_curthread = pcpup->pc_idlethread; 187 pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb; 188 sp = pcpup->pc_curpcb->pcb_sp; 189 190 trcp[0] = 0x2006; 191 trcp[1] = sp; 192 193 return (sp); 194 } 195 196 int 197 powerpc_smp_start_cpu(struct pcpu *pc) 198 { 199 phandle_t cpu; 200 volatile uint32_t *trcp; 201 volatile uint8_t *rstvec; 202 uint32_t trace; 203 int res, reset, timeout; 204 205 cpu = pc->pc_hwref; 206 res = OF_getprop(cpu, "soft-reset", &reset, sizeof(reset)); 207 if (res < 0) 208 return (ENXIO); 209 210 trcp = (uint32_t *)(EXC_RST + 4); 211 trace = *trcp; 212 213 ap_pcpu = pc; 214 215 rstvec = (uint8_t *)(0x80000000 + reset); 216 217 *rstvec = 4; 218 __asm __volatile("sync"); 219 DELAY(1); 220 *rstvec = 0; 221 __asm __volatile("sync"); 222 223 timeout = 1000; 224 while (!pc->pc_awake && timeout--) 225 DELAY(100); 226 227 if (!pc->pc_awake) 228 printf("XXX: timeout (trace=%x; data=%x)\n", trcp[0], trcp[1]); 229 230 return (0); 231 } 232