| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: cpu.c,v 1.214 2009/05/18 01:36:11 mrg Exp $ */ | | 1 | /* $NetBSD: cpu.c,v 1.215 2009/05/27 02:19:49 mrg Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1996 | | 4 | * Copyright (c) 1996 |
5 | * The President and Fellows of Harvard College. All rights reserved. | | 5 | * The President and Fellows of Harvard College. All rights reserved. |
6 | * Copyright (c) 1992, 1993 | | 6 | * Copyright (c) 1992, 1993 |
7 | * The Regents of the University of California. All rights reserved. | | 7 | * The Regents of the University of California. All rights reserved. |
8 | * | | 8 | * |
9 | * This software was developed by the Computer Systems Engineering group | | 9 | * This software was developed by the Computer Systems Engineering group |
10 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | | 10 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and |
11 | * contributed to Berkeley. | | 11 | * contributed to Berkeley. |
12 | * | | 12 | * |
13 | * All advertising materials mentioning features or use of this software | | 13 | * All advertising materials mentioning features or use of this software |
14 | * must display the following acknowledgement: | | 14 | * must display the following acknowledgement: |
| @@ -42,27 +42,27 @@ | | | @@ -42,27 +42,27 @@ |
42 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 42 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
43 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 43 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
44 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 44 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
45 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 45 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
46 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 46 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
47 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 47 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
48 | * SUCH DAMAGE. | | 48 | * SUCH DAMAGE. |
49 | * | | 49 | * |
50 | * @(#)cpu.c 8.5 (Berkeley) 11/23/93 | | 50 | * @(#)cpu.c 8.5 (Berkeley) 11/23/93 |
51 | * | | 51 | * |
52 | */ | | 52 | */ |
53 | | | 53 | |
54 | #include <sys/cdefs.h> | | 54 | #include <sys/cdefs.h> |
55 | __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.214 2009/05/18 01:36:11 mrg Exp $"); | | 55 | __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.215 2009/05/27 02:19:49 mrg Exp $"); |
56 | | | 56 | |
57 | #include "opt_multiprocessor.h" | | 57 | #include "opt_multiprocessor.h" |
58 | #include "opt_lockdebug.h" | | 58 | #include "opt_lockdebug.h" |
59 | #include "opt_ddb.h" | | 59 | #include "opt_ddb.h" |
60 | #include "opt_sparc_arch.h" | | 60 | #include "opt_sparc_arch.h" |
61 | | | 61 | |
62 | #include <sys/param.h> | | 62 | #include <sys/param.h> |
63 | #include <sys/systm.h> | | 63 | #include <sys/systm.h> |
64 | #include <sys/device.h> | | 64 | #include <sys/device.h> |
65 | #include <sys/malloc.h> | | 65 | #include <sys/malloc.h> |
66 | #include <sys/simplelock.h> | | 66 | #include <sys/simplelock.h> |
67 | #include <sys/kernel.h> | | 67 | #include <sys/kernel.h> |
68 | | | 68 | |
| @@ -92,30 +92,27 @@ __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.21 | | | @@ -92,30 +92,27 @@ __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.21 |
92 | struct cpu_softc { | | 92 | struct cpu_softc { |
93 | struct device sc_dev; /* generic device info */ | | 93 | struct device sc_dev; /* generic device info */ |
94 | struct cpu_info *sc_cpuinfo; | | 94 | struct cpu_info *sc_cpuinfo; |
95 | }; | | 95 | }; |
96 | | | 96 | |
97 | /* The following are used externally (sysctl_hw). */ | | 97 | /* The following are used externally (sysctl_hw). */ |
98 | char machine[] = MACHINE; /* from <machine/param.h> */ | | 98 | char machine[] = MACHINE; /* from <machine/param.h> */ |
99 | char machine_arch[] = MACHINE_ARCH; /* from <machine/param.h> */ | | 99 | char machine_arch[] = MACHINE_ARCH; /* from <machine/param.h> */ |
100 | int cpu_arch; /* sparc architecture version */ | | 100 | int cpu_arch; /* sparc architecture version */ |
101 | char cpu_model[100]; /* machine model (primary CPU) */ | | 101 | char cpu_model[100]; /* machine model (primary CPU) */ |
102 | extern char machine_model[]; | | 102 | extern char machine_model[]; |
103 | | | 103 | |
104 | int sparc_ncpus; /* # of CPUs detected by PROM */ | | 104 | int sparc_ncpus; /* # of CPUs detected by PROM */ |
105 | #ifdef MULTIPROCESSOR | | 105 | struct cpu_info *cpus[_MAXNCPU]; /* we only support 4 CPUs. */ |
106 | struct cpu_info *cpus[4]; /* we only support 4 CPUs. */ | | | |
107 | u_int cpu_ready_mask; /* the set of CPUs marked as READY */ | | | |
108 | #endif | | | |
109 | | | 106 | |
110 | /* The CPU configuration driver. */ | | 107 | /* The CPU configuration driver. */ |
111 | static void cpu_mainbus_attach(struct device *, struct device *, void *); | | 108 | static void cpu_mainbus_attach(struct device *, struct device *, void *); |
112 | int cpu_mainbus_match(struct device *, struct cfdata *, void *); | | 109 | int cpu_mainbus_match(struct device *, struct cfdata *, void *); |
113 | | | 110 | |
114 | CFATTACH_DECL(cpu_mainbus, sizeof(struct cpu_softc), | | 111 | CFATTACH_DECL(cpu_mainbus, sizeof(struct cpu_softc), |
115 | cpu_mainbus_match, cpu_mainbus_attach, NULL, NULL); | | 112 | cpu_mainbus_match, cpu_mainbus_attach, NULL, NULL); |
116 | | | 113 | |
117 | #if defined(SUN4D) | | 114 | #if defined(SUN4D) |
118 | static int cpu_cpuunit_match(struct device *, struct cfdata *, void *); | | 115 | static int cpu_cpuunit_match(struct device *, struct cfdata *, void *); |
119 | static void cpu_cpuunit_attach(struct device *, struct device *, void *); | | 116 | static void cpu_cpuunit_attach(struct device *, struct device *, void *); |
120 | | | 117 | |
121 | CFATTACH_DECL(cpu_cpuunit, sizeof(struct cpu_softc), | | 118 | CFATTACH_DECL(cpu_cpuunit, sizeof(struct cpu_softc), |
| @@ -126,89 +123,67 @@ static void cpu_attach(struct cpu_softc | | | @@ -126,89 +123,67 @@ static void cpu_attach(struct cpu_softc |
126 | | | 123 | |
127 | static const char *fsrtoname(int, int, int); | | 124 | static const char *fsrtoname(int, int, int); |
128 | void cache_print(struct cpu_softc *); | | 125 | void cache_print(struct cpu_softc *); |
129 | void cpu_setup(void); | | 126 | void cpu_setup(void); |
130 | void fpu_init(struct cpu_info *); | | 127 | void fpu_init(struct cpu_info *); |
131 | | | 128 | |
132 | #define IU_IMPL(psr) ((u_int)(psr) >> 28) | | 129 | #define IU_IMPL(psr) ((u_int)(psr) >> 28) |
133 | #define IU_VERS(psr) (((psr) >> 24) & 0xf) | | 130 | #define IU_VERS(psr) (((psr) >> 24) & 0xf) |
134 | | | 131 | |
135 | #define SRMMU_IMPL(mmusr) ((u_int)(mmusr) >> 28) | | 132 | #define SRMMU_IMPL(mmusr) ((u_int)(mmusr) >> 28) |
136 | #define SRMMU_VERS(mmusr) (((mmusr) >> 24) & 0xf) | | 133 | #define SRMMU_VERS(mmusr) (((mmusr) >> 24) & 0xf) |
137 | | | 134 | |
138 | int bootmid; /* Module ID of boot CPU */ | | 135 | int bootmid; /* Module ID of boot CPU */ |
139 | #if defined(MULTIPROCESSOR) | | | |
140 | void cpu_spinup(struct cpu_info *); | | | |
141 | static void init_cpuinfo(struct cpu_info *, int); | | | |
142 | | | | |
143 | int go_smp_cpus = 0; /* non-primary CPUs wait for this to go */ | | | |
144 | | | | |
145 | /* lock this to send IPI's */ | | | |
146 | struct simplelock xpmsg_lock = SIMPLELOCK_INITIALIZER; | | | |
147 | | | | |
148 | static void | | | |
149 | init_cpuinfo(struct cpu_info *cpi, int node) | | | |
150 | { | | | |
151 | vaddr_t intstack, va; | | | |
152 | | | | |
153 | /* | | | |
154 | * Finish initialising this cpu_info. | | | |
155 | */ | | | |
156 | getcpuinfo(cpi, node); | | | |
157 | | | | |
158 | /* | | | |
159 | * Arrange interrupt stack. This cpu will also abuse the bottom | | | |
160 | * half of the interrupt stack before it gets to run its idle LWP. | | | |
161 | */ | | | |
162 | intstack = uvm_km_alloc(kernel_map, INT_STACK_SIZE, 0, UVM_KMF_WIRED); | | | |
163 | if (intstack == 0) | | | |
164 | panic("%s: no uspace/intstack", __func__); | | | |
165 | cpi->eintstack = (void*)(intstack + INT_STACK_SIZE); | | | |
166 | | | | |
167 | /* Allocate virtual space for pmap page_copy/page_zero */ | | | |
168 | va = uvm_km_alloc(kernel_map, 2*PAGE_SIZE, 0, UVM_KMF_VAONLY); | | | |
169 | if (va == 0) | | | |
170 | panic("%s: no virtual space", __func__); | | | |
171 | | | | |
172 | cpi->vpage[0] = (void *)(va + 0); | | | |
173 | cpi->vpage[1] = (void *)(va + PAGE_SIZE); | | | |
174 | } | | | |
175 | #endif /* MULTIPROCESSOR */ | | | |
176 | | | 136 | |
177 | #ifdef notdef | | 137 | #ifdef notdef |
178 | /* | | 138 | /* |
179 | * IU implementations are parceled out to vendors (with some slight | | 139 | * IU implementations are parceled out to vendors (with some slight |
180 | * glitches). Printing these is cute but takes too much space. | | 140 | * glitches). Printing these is cute but takes too much space. |
181 | */ | | 141 | */ |
182 | static char *iu_vendor[16] = { | | 142 | static char *iu_vendor[16] = { |
183 | "Fujitsu", /* and also LSI Logic */ | | 143 | "Fujitsu", /* and also LSI Logic */ |
184 | "ROSS", /* ROSS (ex-Cypress) */ | | 144 | "ROSS", /* ROSS (ex-Cypress) */ |
185 | "BIT", | | 145 | "BIT", |
186 | "LSIL", /* LSI Logic finally got their own */ | | 146 | "LSIL", /* LSI Logic finally got their own */ |
187 | "TI", /* Texas Instruments */ | | 147 | "TI", /* Texas Instruments */ |
188 | "Matsushita", | | 148 | "Matsushita", |
189 | "Philips", | | 149 | "Philips", |
190 | "Harvest", /* Harvest VLSI Design Center */ | | 150 | "Harvest", /* Harvest VLSI Design Center */ |
191 | "SPEC", /* Systems and Processes Engineering Corporation */ | | 151 | "SPEC", /* Systems and Processes Engineering Corporation */ |
192 | "Weitek", | | 152 | "Weitek", |
193 | "vendor#10", | | 153 | "vendor#10", |
194 | "vendor#11", | | 154 | "vendor#11", |
195 | "vendor#12", | | 155 | "vendor#12", |
196 | "vendor#13", | | 156 | "vendor#13", |
197 | "vendor#14", | | 157 | "vendor#14", |
198 | "vendor#15" | | 158 | "vendor#15" |
199 | }; | | 159 | }; |
200 | #endif | | 160 | #endif |
201 | | | 161 | |
| | | 162 | #if defined(MULTIPROCESSOR) |
| | | 163 | u_int cpu_ready_mask; /* the set of CPUs marked as READY */ |
| | | 164 | void cpu_spinup(struct cpu_info *); |
| | | 165 | static void cpu_attach_non_boot(struct cpu_softc *, struct cpu_info *, int); |
| | | 166 | |
| | | 167 | int go_smp_cpus = 0; /* non-primary CPUs wait for this to go */ |
| | | 168 | |
| | | 169 | /* |
| | | 170 | * This must be locked around all message transactions to ensure only |
| | | 171 | * one CPU is generating them. |
| | | 172 | */ |
| | | 173 | static kmutex_t xpmsg_mutex; |
| | | 174 | |
| | | 175 | #endif /* MULTIPROCESSOR */ |
| | | 176 | |
202 | /* | | 177 | /* |
203 | * 4/110 comment: the 4/110 chops off the top 4 bits of an OBIO address. | | 178 | * 4/110 comment: the 4/110 chops off the top 4 bits of an OBIO address. |
204 | * this confuses autoconf. for example, if you try and map | | 179 | * this confuses autoconf. for example, if you try and map |
205 | * 0xfe000000 in obio space on a 4/110 it actually maps 0x0e000000. | | 180 | * 0xfe000000 in obio space on a 4/110 it actually maps 0x0e000000. |
206 | * this is easy to verify with the PROM. this causes problems | | 181 | * this is easy to verify with the PROM. this causes problems |
207 | * with devices like "esp0 at obio0 addr 0xfa000000" because the | | 182 | * with devices like "esp0 at obio0 addr 0xfa000000" because the |
208 | * 4/110 treats it as esp0 at obio0 addr 0x0a000000" which is the | | 183 | * 4/110 treats it as esp0 at obio0 addr 0x0a000000" which is the |
209 | * address of the 4/110's "sw0" scsi chip. the same thing happens | | 184 | * address of the 4/110's "sw0" scsi chip. the same thing happens |
210 | * between zs1 and zs2. since the sun4 line is "closed" and | | 185 | * between zs1 and zs2. since the sun4 line is "closed" and |
211 | * we know all the "obio" devices that will ever be on it we just | | 186 | * we know all the "obio" devices that will ever be on it we just |
212 | * put in some special case "if"'s in the match routines of esp, | | 187 | * put in some special case "if"'s in the match routines of esp, |
213 | * dma, and zs. | | 188 | * dma, and zs. |
214 | */ | | 189 | */ |
| @@ -316,150 +291,188 @@ cpu_cpuunit_attach(struct device *parent | | | @@ -316,150 +291,188 @@ cpu_cpuunit_attach(struct device *parent |
316 | cpu_attach((struct cpu_softc *)self, cpua->cpua_node, | | 291 | cpu_attach((struct cpu_softc *)self, cpua->cpua_node, |
317 | cpua->cpua_device_id); | | 292 | cpua->cpua_device_id); |
318 | } | | 293 | } |
319 | #endif /* SUN4D */ | | 294 | #endif /* SUN4D */ |
320 | | | 295 | |
321 | /* | | 296 | /* |
322 | * Attach the CPU. | | 297 | * Attach the CPU. |
323 | * Discover interesting goop about the virtual address cache | | 298 | * Discover interesting goop about the virtual address cache |
324 | * (slightly funny place to do it, but this is where it is to be found). | | 299 | * (slightly funny place to do it, but this is where it is to be found). |
325 | */ | | 300 | */ |
326 | static void | | 301 | static void |
327 | cpu_attach(struct cpu_softc *sc, int node, int mid) | | 302 | cpu_attach(struct cpu_softc *sc, int node, int mid) |
328 | { | | 303 | { |
| | | 304 | char buf[100]; |
329 | struct cpu_info *cpi; | | 305 | struct cpu_info *cpi; |
330 | int idx; | | 306 | int idx; |
331 | static int cpu_attach_count = 0; | | 307 | static int cpu_attach_count = 0; |
332 | | | 308 | |
333 | /* | | 309 | /* |
334 | * The first CPU we're attaching must be the boot CPU. | | 310 | * The first CPU we're attaching must be the boot CPU. |
335 | * (see autoconf.c and cpuunit.c) | | 311 | * (see autoconf.c and cpuunit.c) |
336 | */ | | 312 | */ |
337 | idx = cpu_attach_count++; | | 313 | idx = cpu_attach_count++; |
338 | if (cpu_attach_count == 1) { | | | |
339 | getcpuinfo(&cpuinfo, node); | | | |
340 | | | | |
341 | #if defined(MULTIPROCESSOR) | | | |
342 | cpi = sc->sc_cpuinfo = cpus[idx]; | | | |
343 | #else | | | |
344 | /* The `local' VA is global for uniprocessor. */ | | | |
345 | cpi = sc->sc_cpuinfo = (struct cpu_info *)CPUINFO_VA; | | | |
346 | #endif | | | |
347 | cpi->master = 1; | | | |
348 | cpi->eintstack = eintstack; | | | |
349 | /* Note: `curpcb' is set to `proc0' in locore */ | | | |
350 | | | | |
351 | /* | | | |
352 | * If we haven't been able to determine the Id of the | | | |
353 | * boot CPU, set it now. In this case we can only boot | | | |
354 | * from CPU #0 (see also the CPU attach code in autoconf.c) | | | |
355 | */ | | | |
356 | if (bootmid == 0) | | | |
357 | bootmid = mid; | | | |
358 | } else { | | | |
359 | #if defined(MULTIPROCESSOR) | | | |
360 | int error; | | | |
361 | | | | |
362 | /* | | | |
363 | * Initialise this cpu's cpu_info. | | | |
364 | */ | | | |
365 | cpi = sc->sc_cpuinfo = cpus[idx]; | | | |
366 | init_cpuinfo(cpi, node); | | | |
367 | | | 314 | |
368 | /* | | 315 | #if !defined(MULTIPROCESSOR) |
369 | * Call the MI attach which creates an idle LWP for us. | | 316 | if (cpu_attach_count > 1) { |
370 | */ | | | |
371 | error = mi_cpu_attach(cpi); | | | |
372 | if (error != 0) { | | | |
373 | aprint_normal("\n"); | | | |
374 | aprint_error("%s: mi_cpu_attach failed with %d\n", | | | |
375 | sc->sc_dev.dv_xname, error); | | | |
376 | return; | | | |
377 | } | | | |
378 | | | | |
379 | /* | | | |
380 | * Note: `eintstack' is set in init_cpuinfo() above. | | | |
381 | * The %wim register will be initialized in cpu_hatch(). | | | |
382 | */ | | | |
383 | cpi->ci_curlwp = cpi->ci_data.cpu_idlelwp; | | | |
384 | cpi->curpcb = (struct pcb *)cpi->ci_curlwp->l_addr; | | | |
385 | cpi->curpcb->pcb_wim = 1; | | | |
386 | | | | |
387 | #else | | | |
388 | sc->sc_cpuinfo = NULL; | | | |
389 | printf(": no SMP support in kernel\n"); | | 317 | printf(": no SMP support in kernel\n"); |
390 | return; | | 318 | return; |
391 | #endif | | | |
392 | } | | 319 | } |
393 | | | | |
394 | #ifdef DEBUG | | | |
395 | cpi->redzone = (void *)((long)cpi->eintstack + REDSIZE); | | | |
396 | #endif | | 320 | #endif |
397 | | | 321 | |
| | | 322 | /* |
| | | 323 | * Initialise this cpu's cpu_info. |
| | | 324 | */ |
| | | 325 | cpi = sc->sc_cpuinfo = cpus[idx]; |
| | | 326 | getcpuinfo(cpi, node); |
| | | 327 | |
398 | cpi->ci_cpuid = idx; | | 328 | cpi->ci_cpuid = idx; |
399 | cpi->mid = mid; | | 329 | cpi->mid = mid; |
400 | cpi->node = node; | | 330 | cpi->node = node; |
| | | 331 | #ifdef DEBUG |
| | | 332 | cpi->redzone = (void *)((long)cpi->eintstack + REDSIZE); |
| | | 333 | #endif |
401 | | | 334 | |
402 | if (sparc_ncpus > 1) { | | 335 | if (sparc_ncpus > 1) { |
403 | printf(": mid %d", mid); | | 336 | printf(": mid %d", mid); |
404 | if (mid == 0 && !CPU_ISSUN4D) | | 337 | if (mid == 0 && !CPU_ISSUN4D) |
405 | printf(" [WARNING: mid should not be 0]"); | | 338 | printf(" [WARNING: mid should not be 0]"); |
406 | } | | 339 | } |
407 | | | 340 | |
| | | 341 | #if defined(MULTIPROCESSOR) |
| | | 342 | if (cpu_attach_count > 1) { |
| | | 343 | cpu_attach_non_boot(sc, cpi, node); |
| | | 344 | return; |
| | | 345 | } |
| | | 346 | #endif /* MULTIPROCESSOR */ |
| | | 347 | |
| | | 348 | /* Stuff to only run on the boot CPU */ |
| | | 349 | cpu_setup(); |
| | | 350 | snprintf(buf, sizeof buf, "%s @ %s MHz, %s FPU", |
| | | 351 | cpi->cpu_name, clockfreq(cpi->hz), cpi->fpu_name); |
| | | 352 | snprintf(cpu_model, sizeof cpu_model, "%s (%s)", |
| | | 353 | machine_model, buf); |
| | | 354 | printf(": %s\n", buf); |
| | | 355 | cache_print(sc); |
| | | 356 | |
| | | 357 | cpi->master = 1; |
| | | 358 | cpi->eintstack = eintstack; |
| | | 359 | |
| | | 360 | /* |
| | | 361 | * If we haven't been able to determine the Id of the |
| | | 362 | * boot CPU, set it now. In this case we can only boot |
| | | 363 | * from CPU #0 (see also the CPU attach code in autoconf.c) |
| | | 364 | */ |
| | | 365 | if (bootmid == 0) |
| | | 366 | bootmid = mid; |
| | | 367 | } |
| | | 368 | |
| | | 369 | /* |
| | | 370 | * Finish CPU attach. |
| | | 371 | * Must be run by the CPU which is being attached. |
| | | 372 | */ |
| | | 373 | void |
| | | 374 | cpu_setup(void) |
| | | 375 | { |
| | | 376 | if (cpuinfo.hotfix) |
| | | 377 | (*cpuinfo.hotfix)(&cpuinfo); |
| | | 378 | |
| | | 379 | /* Initialize FPU */ |
| | | 380 | fpu_init(&cpuinfo); |
| | | 381 | |
| | | 382 | /* Enable the cache */ |
| | | 383 | cpuinfo.cache_enable(); |
| | | 384 | |
| | | 385 | cpuinfo.flags |= CPUFLG_HATCHED; |
| | | 386 | } |
| | | 387 | |
| | | 388 | #if defined(MULTIPROCESSOR) |
| | | 389 | /* |
| | | 390 | * Perform most of the tasks needed for a non-boot CPU. |
| | | 391 | */ |
| | | 392 | static void |
| | | 393 | cpu_attach_non_boot(struct cpu_softc *sc, struct cpu_info *cpi, int node) |
| | | 394 | { |
| | | 395 | vaddr_t intstack, va; |
| | | 396 | int error; |
| | | 397 | |
| | | 398 | /* |
| | | 399 | * Arrange interrupt stack. This cpu will also abuse the bottom |
| | | 400 | * half of the interrupt stack before it gets to run its idle LWP. |
| | | 401 | */ |
| | | 402 | intstack = uvm_km_alloc(kernel_map, INT_STACK_SIZE, 0, UVM_KMF_WIRED); |
| | | 403 | if (intstack == 0) |
| | | 404 | panic("%s: no uspace/intstack", __func__); |
| | | 405 | cpi->eintstack = (void*)(intstack + INT_STACK_SIZE); |
408 | | | 406 | |
409 | if (cpi->master) { | | 407 | /* Allocate virtual space for pmap page_copy/page_zero */ |
410 | char buf[100]; | | 408 | va = uvm_km_alloc(kernel_map, 2*PAGE_SIZE, 0, UVM_KMF_VAONLY); |
| | | 409 | if (va == 0) |
| | | 410 | panic("%s: no virtual space", __func__); |
411 | | | 411 | |
412 | cpu_setup(); | | 412 | cpi->vpage[0] = (void *)(va + 0); |
413 | snprintf(buf, sizeof buf, "%s @ %s MHz, %s FPU", | | 413 | cpi->vpage[1] = (void *)(va + PAGE_SIZE); |
414 | cpi->cpu_name, clockfreq(cpi->hz), cpi->fpu_name); | | 414 | |
415 | snprintf(cpu_model, sizeof cpu_model, "%s (%s)", | | 415 | /* |
416 | machine_model, buf); | | 416 | * Call the MI attach which creates an idle LWP for us. |
417 | printf(": %s\n", buf); | | 417 | */ |
418 | cache_print(sc); | | 418 | error = mi_cpu_attach(cpi); |
| | | 419 | if (error != 0) { |
| | | 420 | aprint_normal("\n"); |
| | | 421 | aprint_error("%s: mi_cpu_attach failed with %d\n", |
| | | 422 | sc->sc_dev.dv_xname, error); |
419 | return; | | 423 | return; |
420 | } | | 424 | } |
421 | | | 425 | |
422 | #if defined(MULTIPROCESSOR) | | 426 | /* |
| | | 427 | * Note: `eintstack' is set in init_cpuinfo() above. |
| | | 428 | * The %wim register will be initialized in cpu_hatch(). |
| | | 429 | */ |
| | | 430 | cpi->ci_curlwp = cpi->ci_data.cpu_idlelwp; |
| | | 431 | cpi->curpcb = (struct pcb *)cpi->ci_curlwp->l_addr; |
| | | 432 | cpi->curpcb->pcb_wim = 1; |
| | | 433 | |
423 | /* for now use the fixed virtual addresses setup in autoconf.c */ | | 434 | /* for now use the fixed virtual addresses setup in autoconf.c */ |
424 | cpi->intreg_4m = (struct icr_pi *) | | 435 | cpi->intreg_4m = (struct icr_pi *) |
425 | (PI_INTR_VA + (_MAXNBPG * CPU_MID2CPUNO(mid))); | | 436 | (PI_INTR_VA + (_MAXNBPG * CPU_MID2CPUNO(cpi->mid))); |
426 | | | 437 | |
427 | /* Now start this CPU */ | | 438 | /* Now start this CPU */ |
428 | cpu_spinup(cpi); | | 439 | cpu_spinup(cpi); |
429 | printf(": %s @ %s MHz, %s FPU\n", cpi->cpu_name, | | 440 | printf(": %s @ %s MHz, %s FPU\n", cpi->cpu_name, |
430 | clockfreq(cpi->hz), cpi->fpu_name); | | 441 | clockfreq(cpi->hz), cpi->fpu_name); |
431 | | | 442 | |
432 | cache_print(sc); | | 443 | cache_print(sc); |
433 | | | 444 | |
434 | if (sparc_ncpus > 1 && idx == sparc_ncpus-1) { | | 445 | /* |
| | | 446 | * Now we're on the last CPU to be attaching. |
| | | 447 | */ |
| | | 448 | if (sparc_ncpus > 1 && cpi->ci_cpuid == sparc_ncpus - 1) { |
435 | CPU_INFO_ITERATOR n; | | 449 | CPU_INFO_ITERATOR n; |
436 | /* | | 450 | /* |
437 | * Install MP cache flush functions, unless the | | 451 | * Install MP cache flush functions, unless the |
438 | * single-processor versions are no-ops. | | 452 | * single-processor versions are no-ops. |
439 | */ | | 453 | */ |
440 | for (CPU_INFO_FOREACH(n, cpi)) { | | 454 | for (CPU_INFO_FOREACH(n, cpi)) { |
441 | #define SET_CACHE_FUNC(x) \ | | 455 | #define SET_CACHE_FUNC(x) \ |
442 | if (cpi->x != __CONCAT(noop_,x)) cpi->x = __CONCAT(smp_,x) | | 456 | if (cpi->x != __CONCAT(noop_,x)) cpi->x = __CONCAT(smp_,x) |
443 | SET_CACHE_FUNC(vcache_flush_page); | | 457 | SET_CACHE_FUNC(vcache_flush_page); |
444 | SET_CACHE_FUNC(vcache_flush_segment); | | 458 | SET_CACHE_FUNC(vcache_flush_segment); |
445 | SET_CACHE_FUNC(vcache_flush_region); | | 459 | SET_CACHE_FUNC(vcache_flush_region); |
446 | SET_CACHE_FUNC(vcache_flush_context); | | 460 | SET_CACHE_FUNC(vcache_flush_context); |
447 | } | | 461 | } |
448 | } | | 462 | } |
449 | #endif /* MULTIPROCESSOR */ | | 463 | #undef SET_CACHE_FUNC |
450 | } | | 464 | } |
451 | | | 465 | |
452 | #if defined(MULTIPROCESSOR) | | | |
453 | /* | | 466 | /* |
454 | * Start secondary processors in motion. | | 467 | * Start secondary processors in motion. |
455 | */ | | 468 | */ |
456 | void | | 469 | void |
457 | cpu_boot_secondary_processors(void) | | 470 | cpu_boot_secondary_processors(void) |
458 | { | | 471 | { |
459 | CPU_INFO_ITERATOR n; | | 472 | CPU_INFO_ITERATOR n; |
460 | struct cpu_info *cpi; | | 473 | struct cpu_info *cpi; |
461 | | | 474 | |
462 | printf("cpu0: booting secondary processors:"); | | 475 | printf("cpu0: booting secondary processors:"); |
463 | for (CPU_INFO_FOREACH(n, cpi)) { | | 476 | for (CPU_INFO_FOREACH(n, cpi)) { |
464 | if (cpuinfo.mid == cpi->mid || | | 477 | if (cpuinfo.mid == cpi->mid || |
465 | (cpi->flags & CPUFLG_HATCHED) == 0) | | 478 | (cpi->flags & CPUFLG_HATCHED) == 0) |
| @@ -469,61 +482,50 @@ cpu_boot_secondary_processors(void) | | | @@ -469,61 +482,50 @@ cpu_boot_secondary_processors(void) |
469 | cpi->flags |= CPUFLG_READY; | | 482 | cpi->flags |= CPUFLG_READY; |
470 | cpu_ready_mask |= (1 << n); | | 483 | cpu_ready_mask |= (1 << n); |
471 | } | | 484 | } |
472 | | | 485 | |
473 | /* Mark the boot CPU as ready */ | | 486 | /* Mark the boot CPU as ready */ |
474 | cpuinfo.flags |= CPUFLG_READY; | | 487 | cpuinfo.flags |= CPUFLG_READY; |
475 | cpu_ready_mask |= (1 << 0); | | 488 | cpu_ready_mask |= (1 << 0); |
476 | | | 489 | |
477 | /* Tell the other CPU's to start up. */ | | 490 | /* Tell the other CPU's to start up. */ |
478 | go_smp_cpus = 1; | | 491 | go_smp_cpus = 1; |
479 | | | 492 | |
480 | printf("\n"); | | 493 | printf("\n"); |
481 | } | | 494 | } |
482 | #endif /* MULTIPROCESSOR */ | | | |
483 | | | 495 | |
484 | /* | | 496 | /* |
485 | * Finish CPU attach. | | 497 | * Early initialisation, before main(). |
486 | * Must be run by the CPU which is being attached. | | | |
487 | */ | | 498 | */ |
488 | void | | 499 | void |
489 | cpu_setup(void) | | 500 | cpu_init_system(void) |
490 | { | | 501 | { |
491 | if (cpuinfo.hotfix) | | | |
492 | (*cpuinfo.hotfix)(&cpuinfo); | | | |
493 | | | | |
494 | /* Initialize FPU */ | | | |
495 | fpu_init(&cpuinfo); | | | |
496 | | | 502 | |
497 | /* Enable the cache */ | | 503 | mutex_init(&xpmsg_mutex, MUTEX_SPIN, IPL_VM); |
498 | cpuinfo.cache_enable(); | | | |
499 | | | | |
500 | cpuinfo.flags |= CPUFLG_HATCHED; | | | |
501 | } | | 504 | } |
502 | | | 505 | |
503 | #if defined(MULTIPROCESSOR) | | | |
504 | | | | |
505 | extern void cpu_hatch(void); /* in locore.s */ | | | |
506 | | | | |
507 | /* | | 506 | /* |
508 | * Allocate per-CPU data, then start up this CPU using PROM. | | 507 | * Allocate per-CPU data, then start up this CPU using PROM. |
509 | */ | | 508 | */ |
510 | void | | 509 | void |
511 | cpu_spinup(struct cpu_info *cpi) | | 510 | cpu_spinup(struct cpu_info *cpi) |
512 | { | | 511 | { |
| | | 512 | extern void cpu_hatch(void); /* in locore.s */ |
513 | struct openprom_addr oa; | | 513 | struct openprom_addr oa; |
514 | void *pc = (void *)cpu_hatch; | | 514 | void *pc; |
515 | int n; | | 515 | int n; |
516 | | | 516 | |
| | | 517 | pc = (void *)cpu_hatch; |
| | | 518 | |
517 | /* Setup CPU-specific MMU tables */ | | 519 | /* Setup CPU-specific MMU tables */ |
518 | pmap_alloc_cpu(cpi); | | 520 | pmap_alloc_cpu(cpi); |
519 | | | 521 | |
520 | cpi->flags &= ~CPUFLG_HATCHED; | | 522 | cpi->flags &= ~CPUFLG_HATCHED; |
521 | | | 523 | |
522 | /* | | 524 | /* |
523 | * The physical address of the context table is passed to | | 525 | * The physical address of the context table is passed to |
524 | * the PROM in a "physical address descriptor". | | 526 | * the PROM in a "physical address descriptor". |
525 | */ | | 527 | */ |
526 | oa.oa_space = 0; | | 528 | oa.oa_space = 0; |
527 | oa.oa_base = (uint32_t)cpi->ctx_tbl_pa; | | 529 | oa.oa_base = (uint32_t)cpi->ctx_tbl_pa; |
528 | oa.oa_size = cpi->mmu_ncontext * sizeof(cpi->ctx_tbl[0]); /*???*/ | | 530 | oa.oa_size = cpi->mmu_ncontext * sizeof(cpi->ctx_tbl[0]); /*???*/ |
529 | | | 531 | |
| @@ -546,62 +548,40 @@ cpu_spinup(struct cpu_info *cpi) | | | @@ -546,62 +548,40 @@ cpu_spinup(struct cpu_info *cpi) |
546 | } | | 548 | } |
547 | printf("CPU did not spin up\n"); | | 549 | printf("CPU did not spin up\n"); |
548 | } | | 550 | } |
549 | | | 551 | |
550 | /* | | 552 | /* |
551 | * Call a function on some CPUs. `cpuset' can be set to CPUSET_ALL | | 553 | * Call a function on some CPUs. `cpuset' can be set to CPUSET_ALL |
552 | * to call every CPU, or `1 << cpi->ci_cpuid' for each CPU to call. | | 554 | * to call every CPU, or `1 << cpi->ci_cpuid' for each CPU to call. |
553 | */ | | 555 | */ |
554 | void | | 556 | void |
555 | xcall(xcall_func_t func, xcall_trap_t trap, int arg0, int arg1, int arg2, | | 557 | xcall(xcall_func_t func, xcall_trap_t trap, int arg0, int arg1, int arg2, |
556 | u_int cpuset) | | 558 | u_int cpuset) |
557 | { | | 559 | { |
558 | struct cpu_info *cpi; | | 560 | struct cpu_info *cpi; |
559 | int s, n, i, done, callself, mybit; | | 561 | int n, i, done, callself, mybit; |
560 | volatile struct xpmsg_func *p; | | 562 | volatile struct xpmsg_func *p; |
561 | int fasttrap; | | 563 | int fasttrap; |
562 | | | 564 | int is_noop = func == (xcall_func_t)sparc_noop; |
563 | /* XXX - note p->retval is probably no longer useful */ | | | |
564 | | | 565 | |
565 | mybit = (1 << cpuinfo.ci_cpuid); | | 566 | mybit = (1 << cpuinfo.ci_cpuid); |
566 | callself = func && (cpuset & mybit) != 0; | | 567 | callself = func && (cpuset & mybit) != 0; |
567 | cpuset &= ~mybit; | | 568 | cpuset &= ~mybit; |
568 | | | 569 | |
569 | /* | | | |
570 | * If no cpus are configured yet, just call ourselves. | | | |
571 | */ | | | |
572 | if (cpus == NULL) { | | | |
573 | p = &cpuinfo.msg.u.xpmsg_func; | | | |
574 | if (callself) | | | |
575 | p->retval = (*func)(arg0, arg1, arg2); | | | |
576 | return; | | | |
577 | } | | | |
578 | | | | |
579 | /* Mask any CPUs that are not ready */ | | 570 | /* Mask any CPUs that are not ready */ |
580 | cpuset &= cpu_ready_mask; | | 571 | cpuset &= cpu_ready_mask; |
581 | | | 572 | |
582 | /* prevent interrupts that grab the kernel lock */ | | 573 | /* prevent interrupts that grab the kernel lock */ |
583 | s = splsched(); | | 574 | mutex_spin_enter(&xpmsg_mutex); |
584 | #ifdef DEBUG | | | |
585 | if (!cold) { | | | |
586 | u_int pc, lvl = ((u_int)s & PSR_PIL) >> 8; | | | |
587 | if (lvl > IPL_SCHED) { | | | |
588 | __asm("mov %%i7, %0" : "=r" (pc) : ); | | | |
589 | printf_nolog("%d: xcall at lvl %u from 0x%x\n", | | | |
590 | cpu_number(), lvl, pc); | | | |
591 | } | | | |
592 | } | | | |
593 | #endif | | | |
594 | LOCK_XPMSG(); | | | |
595 | | | 575 | |
596 | /* | | 576 | /* |
597 | * Firstly, call each CPU. We do this so that they might have | | 577 | * Firstly, call each CPU. We do this so that they might have |
598 | * finished by the time we start looking. | | 578 | * finished by the time we start looking. |
599 | */ | | 579 | */ |
600 | fasttrap = trap != NULL ? 1 : 0; | | 580 | fasttrap = trap != NULL ? 1 : 0; |
601 | for (CPU_INFO_FOREACH(n, cpi)) { | | 581 | for (CPU_INFO_FOREACH(n, cpi)) { |
602 | | | 582 | |
603 | /* Note: n == cpi->ci_cpuid */ | | 583 | /* Note: n == cpi->ci_cpuid */ |
604 | if ((cpuset & (1 << n)) == 0) | | 584 | if ((cpuset & (1 << n)) == 0) |
605 | continue; | | 585 | continue; |
606 | | | 586 | |
607 | cpi->msg.tag = XPMSG_FUNC; | | 587 | cpi->msg.tag = XPMSG_FUNC; |
| @@ -611,174 +591,158 @@ xcall(xcall_func_t func, xcall_trap_t tr | | | @@ -611,174 +591,158 @@ xcall(xcall_func_t func, xcall_trap_t tr |
611 | p->trap = trap; | | 591 | p->trap = trap; |
612 | p->arg0 = arg0; | | 592 | p->arg0 = arg0; |
613 | p->arg1 = arg1; | | 593 | p->arg1 = arg1; |
614 | p->arg2 = arg2; | | 594 | p->arg2 = arg2; |
615 | /* Fast cross calls use interrupt level 14 */ | | 595 | /* Fast cross calls use interrupt level 14 */ |
616 | raise_ipi(cpi,13+fasttrap);/*xcall_cookie->pil*/ | | 596 | raise_ipi(cpi,13+fasttrap);/*xcall_cookie->pil*/ |
617 | } | | 597 | } |
618 | | | 598 | |
619 | /* | | 599 | /* |
620 | * Second, call ourselves. | | 600 | * Second, call ourselves. |
621 | */ | | 601 | */ |
622 | p = &cpuinfo.msg.u.xpmsg_func; | | 602 | p = &cpuinfo.msg.u.xpmsg_func; |
623 | if (callself) | | 603 | if (callself) |
624 | p->retval = (*func)(arg0, arg1, arg2); | | 604 | (*func)(arg0, arg1, arg2); |
625 | | | 605 | |
626 | /* | | 606 | /* |
627 | * Lastly, start looping, waiting for all CPUs to register that they | | 607 | * Lastly, start looping, waiting for all CPUs to register that they |
628 | * have completed (bailing if it takes "too long", being loud about | | 608 | * have completed (bailing if it takes "too long", being loud about |
629 | * this in the process). | | 609 | * this in the process). |
630 | */ | | 610 | */ |
631 | done = 0; | | 611 | done = is_noop; |
632 | i = 100000; /* time-out, not too long, but still an _AGE_ */ | | 612 | i = 100000; /* time-out, not too long, but still an _AGE_ */ |
633 | while (!done) { | | 613 | while (!done) { |
634 | if (--i < 0) { | | 614 | if (--i < 0) { |
635 | printf_nolog("xcall(cpu%d,%p): couldn't ping cpus:", | | 615 | printf_nolog("xcall(cpu%d,%p): couldn't ping cpus:", |
636 | cpu_number(), func); | | 616 | cpu_number(), func); |
637 | } | | 617 | } |
638 | | | 618 | |
639 | done = 1; | | 619 | done = 1; |
640 | for (CPU_INFO_FOREACH(n, cpi)) { | | 620 | for (CPU_INFO_FOREACH(n, cpi)) { |
641 | if ((cpuset & (1 << n)) == 0) | | 621 | if ((cpuset & (1 << n)) == 0) |
642 | continue; | | 622 | continue; |
643 | | | 623 | |
644 | if (cpi->msg.complete == 0) { | | 624 | if (cpi->msg.complete == 0) { |
645 | if (i < 0) { | | 625 | if (i < 0) { |
646 | printf_nolog(" cpu%d", cpi->ci_cpuid); | | 626 | printf_nolog(" cpu%d", cpi->ci_cpuid); |
647 | } else { | | 627 | } else { |
648 | done = 0; | | 628 | done = 0; |
649 | break; | | 629 | break; |
650 | } | | 630 | } |
651 | } | | 631 | } |
652 | } | | 632 | } |
653 | } | | 633 | } |
654 | if (i < 0) | | 634 | if (i < 0) |
655 | printf_nolog("\n"); | | 635 | printf_nolog("\n"); |
656 | | | 636 | |
657 | UNLOCK_XPMSG(); | | 637 | mutex_spin_exit(&xpmsg_mutex); |
658 | splx(s); | | | |
659 | } | | 638 | } |
660 | | | 639 | |
661 | /* | | 640 | /* |
662 | * Tell all CPUs other than the current one to enter the PROM idle loop. | | 641 | * Tell all CPUs other than the current one to enter the PROM idle loop. |
663 | */ | | 642 | */ |
664 | void | | 643 | void |
665 | mp_pause_cpus(void) | | 644 | mp_pause_cpus(void) |
666 | { | | 645 | { |
667 | CPU_INFO_ITERATOR n; | | 646 | CPU_INFO_ITERATOR n; |
668 | struct cpu_info *cpi; | | 647 | struct cpu_info *cpi; |
669 | | | 648 | |
670 | if (cpus == NULL) | | | |
671 | return; | | | |
672 | | | | |
673 | for (CPU_INFO_FOREACH(n, cpi)) { | | 649 | for (CPU_INFO_FOREACH(n, cpi)) { |
674 | if (cpuinfo.mid == cpi->mid || | | 650 | if (cpuinfo.mid == cpi->mid || |
675 | (cpi->flags & CPUFLG_HATCHED) == 0) | | 651 | (cpi->flags & CPUFLG_HATCHED) == 0) |
676 | continue; | | 652 | continue; |
677 | | | 653 | |
678 | /* | | 654 | /* |
679 | * This PROM utility will put the OPENPROM_MBX_ABORT | | 655 | * This PROM utility will put the OPENPROM_MBX_ABORT |
680 | * message (0xfc) in the target CPU's mailbox and then | | 656 | * message (0xfc) in the target CPU's mailbox and then |
681 | * send it a level 15 soft interrupt. | | 657 | * send it a level 15 soft interrupt. |
682 | */ | | 658 | */ |
683 | if (prom_cpuidle(cpi->node) != 0) | | 659 | if (prom_cpuidle(cpi->node) != 0) |
684 | printf("cpu%d could not be paused\n", cpi->ci_cpuid); | | 660 | printf("cpu%d could not be paused\n", cpi->ci_cpuid); |
685 | } | | 661 | } |
686 | } | | 662 | } |
687 | | | 663 | |
688 | /* | | 664 | /* |
689 | * Resume all idling CPUs. | | 665 | * Resume all idling CPUs. |
690 | */ | | 666 | */ |
691 | void | | 667 | void |
692 | mp_resume_cpus(void) | | 668 | mp_resume_cpus(void) |
693 | { | | 669 | { |
694 | CPU_INFO_ITERATOR n; | | 670 | CPU_INFO_ITERATOR n; |
695 | struct cpu_info *cpi; | | 671 | struct cpu_info *cpi; |
696 | | | 672 | |
697 | if (cpus == NULL) | | | |
698 | return; | | | |
699 | | | | |
700 | for (CPU_INFO_FOREACH(n, cpi)) { | | 673 | for (CPU_INFO_FOREACH(n, cpi)) { |
701 | if (cpuinfo.mid == cpi->mid || | | 674 | if (cpuinfo.mid == cpi->mid || |
702 | (cpi->flags & CPUFLG_HATCHED) == 0) | | 675 | (cpi->flags & CPUFLG_HATCHED) == 0) |
703 | continue; | | 676 | continue; |
704 | | | 677 | |
705 | /* | | 678 | /* |
706 | * This PROM utility makes the target CPU return | | 679 | * This PROM utility makes the target CPU return |
707 | * from its prom_cpuidle(0) call (see intr.c:nmi_soft()). | | 680 | * from its prom_cpuidle(0) call (see intr.c:nmi_soft()). |
708 | */ | | 681 | */ |
709 | if (prom_cpuresume(cpi->node) != 0) | | 682 | if (prom_cpuresume(cpi->node) != 0) |
710 | printf("cpu%d could not be resumed\n", cpi->ci_cpuid); | | 683 | printf("cpu%d could not be resumed\n", cpi->ci_cpuid); |
711 | } | | 684 | } |
712 | } | | 685 | } |
713 | | | 686 | |
714 | /* | | 687 | /* |
715 | * Tell all CPUs except the current one to hurry back into the prom | | 688 | * Tell all CPUs except the current one to hurry back into the prom |
716 | */ | | 689 | */ |
717 | void | | 690 | void |
718 | mp_halt_cpus(void) | | 691 | mp_halt_cpus(void) |
719 | { | | 692 | { |
720 | CPU_INFO_ITERATOR n; | | 693 | CPU_INFO_ITERATOR n; |
721 | struct cpu_info *cpi; | | 694 | struct cpu_info *cpi; |
722 | | | 695 | |
723 | if (cpus == NULL) | | | |
724 | return; | | | |
725 | | | | |
726 | for (CPU_INFO_FOREACH(n, cpi)) { | | 696 | for (CPU_INFO_FOREACH(n, cpi)) { |
727 | int r; | | 697 | int r; |
728 | | | 698 | |
729 | if (cpuinfo.mid == cpi->mid) | | 699 | if (cpuinfo.mid == cpi->mid) |
730 | continue; | | 700 | continue; |
731 | | | 701 | |
732 | /* | | 702 | /* |
733 | * This PROM utility will put the OPENPROM_MBX_STOP | | 703 | * This PROM utility will put the OPENPROM_MBX_STOP |
734 | * message (0xfb) in the target CPU's mailbox and then | | 704 | * message (0xfb) in the target CPU's mailbox and then |
735 | * send it a level 15 soft interrupt. | | 705 | * send it a level 15 soft interrupt. |
736 | */ | | 706 | */ |
737 | r = prom_cpustop(cpi->node); | | 707 | r = prom_cpustop(cpi->node); |
738 | printf("cpu%d %shalted\n", cpi->ci_cpuid, | | 708 | printf("cpu%d %shalted\n", cpi->ci_cpuid, |
739 | r == 0 ? "" : "(boot CPU?) can not be "); | | 709 | r == 0 ? "" : "(boot CPU?) can not be "); |
740 | } | | 710 | } |
741 | } | | 711 | } |
742 | | | 712 | |
743 | #if defined(DDB) | | 713 | #if defined(DDB) |
744 | void | | 714 | void |
745 | mp_pause_cpus_ddb(void) | | 715 | mp_pause_cpus_ddb(void) |
746 | { | | 716 | { |
747 | CPU_INFO_ITERATOR n; | | 717 | CPU_INFO_ITERATOR n; |
748 | struct cpu_info *cpi; | | 718 | struct cpu_info *cpi; |
749 | | | 719 | |
750 | if (cpus == NULL) | | | |
751 | return; | | | |
752 | | | | |
753 | for (CPU_INFO_FOREACH(n, cpi)) { | | 720 | for (CPU_INFO_FOREACH(n, cpi)) { |
754 | if (cpi == NULL || cpi->mid == cpuinfo.mid || | | 721 | if (cpi == NULL || cpi->mid == cpuinfo.mid || |
755 | (cpi->flags & CPUFLG_HATCHED) == 0) | | 722 | (cpi->flags & CPUFLG_HATCHED) == 0) |
756 | continue; | | 723 | continue; |
757 | | | 724 | |
758 | cpi->msg_lev15.tag = XPMSG15_PAUSECPU; | | 725 | cpi->msg_lev15.tag = XPMSG15_PAUSECPU; |
759 | raise_ipi(cpi,15); /* high priority intr */ | | 726 | raise_ipi(cpi,15); /* high priority intr */ |
760 | } | | 727 | } |
761 | } | | 728 | } |
762 | | | 729 | |
763 | void | | 730 | void |
764 | mp_resume_cpus_ddb(void) | | 731 | mp_resume_cpus_ddb(void) |
765 | { | | 732 | { |
766 | CPU_INFO_ITERATOR n; | | 733 | CPU_INFO_ITERATOR n; |
767 | struct cpu_info *cpi; | | 734 | struct cpu_info *cpi; |
768 | | | 735 | |
769 | if (cpus == NULL) | | | |
770 | return; | | | |
771 | | | | |
772 | for (CPU_INFO_FOREACH(n, cpi)) { | | 736 | for (CPU_INFO_FOREACH(n, cpi)) { |
773 | if (cpi == NULL || cpuinfo.mid == cpi->mid || | | 737 | if (cpi == NULL || cpuinfo.mid == cpi->mid || |
774 | (cpi->flags & CPUFLG_PAUSED) == 0) | | 738 | (cpi->flags & CPUFLG_PAUSED) == 0) |
775 | continue; | | 739 | continue; |
776 | | | 740 | |
777 | /* tell it to continue */ | | 741 | /* tell it to continue */ |
778 | cpi->flags &= ~CPUFLG_PAUSED; | | 742 | cpi->flags &= ~CPUFLG_PAUSED; |
779 | } | | 743 | } |
780 | } | | 744 | } |
781 | #endif /* DDB */ | | 745 | #endif /* DDB */ |
782 | #endif /* MULTIPROCESSOR */ | | 746 | #endif /* MULTIPROCESSOR */ |
783 | | | 747 | |
784 | /* | | 748 | /* |