Print this page
XXXX pass in cpu_pause_func via pause_cpus
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86pc/os/mp_pc.c
+++ new/usr/src/uts/i86pc/os/mp_pc.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24 /*
25 25 * Copyright (c) 2010, Intel Corporation.
26 26 * All rights reserved.
27 27 */
28 28 /*
29 29 * Copyright 2011 Joyent, Inc. All rights reserved.
30 30 */
31 31
32 32 /*
33 33 * Welcome to the world of the "real mode platter".
34 34 * See also startup.c, mpcore.s and apic.c for related routines.
35 35 */
36 36
37 37 #include <sys/types.h>
38 38 #include <sys/systm.h>
39 39 #include <sys/cpuvar.h>
40 40 #include <sys/cpu_module.h>
41 41 #include <sys/kmem.h>
42 42 #include <sys/archsystm.h>
43 43 #include <sys/machsystm.h>
44 44 #include <sys/controlregs.h>
45 45 #include <sys/x86_archext.h>
46 46 #include <sys/smp_impldefs.h>
47 47 #include <sys/sysmacros.h>
48 48 #include <sys/mach_mmu.h>
49 49 #include <sys/promif.h>
50 50 #include <sys/cpu.h>
51 51 #include <sys/cpu_event.h>
52 52 #include <sys/sunndi.h>
53 53 #include <sys/fs/dv_node.h>
54 54 #include <vm/hat_i86.h>
55 55 #include <vm/as.h>
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
56 56
57 57 extern cpuset_t cpu_ready_set;
58 58
59 59 extern int mp_start_cpu_common(cpu_t *cp, boolean_t boot);
60 60 extern void real_mode_start_cpu(void);
61 61 extern void real_mode_start_cpu_end(void);
62 62 extern void real_mode_stop_cpu_stage1(void);
63 63 extern void real_mode_stop_cpu_stage1_end(void);
64 64 extern void real_mode_stop_cpu_stage2(void);
65 65 extern void real_mode_stop_cpu_stage2_end(void);
66 -extern void *(*cpu_pause_func)(void *);
67 66
68 67 void rmp_gdt_init(rm_platter_t *);
69 68
70 69 /*
71 70 * Fill up the real mode platter to make it easy for real mode code to
72 71 * kick it off. This area should really be one passed by boot to kernel
73 72 * and guaranteed to be below 1MB and aligned to 16 bytes. Should also
74 73 * have identical physical and virtual address in paged mode.
75 74 */
76 75 static ushort_t *warm_reset_vector = NULL;
77 76
78 77 int
79 78 mach_cpucontext_init(void)
80 79 {
81 80 ushort_t *vec;
82 81 ulong_t addr;
83 82 struct rm_platter *rm = (struct rm_platter *)rm_platter_va;
84 83
85 84 if (!(vec = (ushort_t *)psm_map_phys(WARM_RESET_VECTOR,
86 85 sizeof (vec), PROT_READ | PROT_WRITE)))
87 86 return (-1);
88 87
89 88 /*
90 89 * setup secondary cpu bios boot up vector
91 90 * Write page offset to 0x467 and page frame number to 0x469.
92 91 */
93 92 addr = (ulong_t)((caddr_t)rm->rm_code - (caddr_t)rm) + rm_platter_pa;
94 93 vec[0] = (ushort_t)(addr & PAGEOFFSET);
95 94 vec[1] = (ushort_t)((addr & (0xfffff & PAGEMASK)) >> 4);
96 95 warm_reset_vector = vec;
97 96
98 97 /* Map real mode platter into kas so kernel can access it. */
99 98 hat_devload(kas.a_hat,
100 99 (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE,
101 100 btop(rm_platter_pa), PROT_READ | PROT_WRITE | PROT_EXEC,
102 101 HAT_LOAD_NOCONSIST);
103 102
104 103 /* Copy CPU startup code to rm_platter if it's still during boot. */
105 104 if (!plat_dr_enabled()) {
106 105 ASSERT((size_t)real_mode_start_cpu_end -
107 106 (size_t)real_mode_start_cpu <= RM_PLATTER_CODE_SIZE);
108 107 bcopy((caddr_t)real_mode_start_cpu, (caddr_t)rm->rm_code,
109 108 (size_t)real_mode_start_cpu_end -
110 109 (size_t)real_mode_start_cpu);
111 110 }
112 111
113 112 return (0);
114 113 }
115 114
116 115 void
117 116 mach_cpucontext_fini(void)
118 117 {
119 118 if (warm_reset_vector)
120 119 psm_unmap_phys((caddr_t)warm_reset_vector,
121 120 sizeof (warm_reset_vector));
122 121 hat_unload(kas.a_hat, (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE,
123 122 HAT_UNLOAD);
124 123 }
125 124
126 125 #if defined(__amd64)
127 126 extern void *long_mode_64(void);
128 127 #endif /* __amd64 */
129 128
130 129 /*ARGSUSED*/
131 130 void
132 131 rmp_gdt_init(rm_platter_t *rm)
133 132 {
134 133
135 134 #if defined(__amd64)
136 135 /* Use the kas address space for the CPU startup thread. */
137 136 if (MAKECR3(kas.a_hat->hat_htable->ht_pfn) > 0xffffffffUL)
138 137 panic("Cannot initialize CPUs; kernel's 64-bit page tables\n"
139 138 "located above 4G in physical memory (@ 0x%lx)",
140 139 MAKECR3(kas.a_hat->hat_htable->ht_pfn));
141 140
142 141 /*
143 142 * Setup pseudo-descriptors for temporary GDT and IDT for use ONLY
144 143 * by code in real_mode_start_cpu():
145 144 *
146 145 * GDT[0]: NULL selector
147 146 * GDT[1]: 64-bit CS: Long = 1, Present = 1, bits 12, 11 = 1
148 147 *
149 148 * Clear the IDT as interrupts will be off and a limit of 0 will cause
150 149 * the CPU to triple fault and reset on an NMI, seemingly as reasonable
151 150 * a course of action as any other, though it may cause the entire
152 151 * platform to reset in some cases...
153 152 */
154 153 rm->rm_temp_gdt[0] = 0;
155 154 rm->rm_temp_gdt[TEMPGDT_KCODE64] = 0x20980000000000ULL;
156 155
157 156 rm->rm_temp_gdt_lim = (ushort_t)(sizeof (rm->rm_temp_gdt) - 1);
158 157 rm->rm_temp_gdt_base = rm_platter_pa +
159 158 (uint32_t)offsetof(rm_platter_t, rm_temp_gdt);
160 159 rm->rm_temp_idt_lim = 0;
161 160 rm->rm_temp_idt_base = 0;
162 161
163 162 /*
164 163 * Since the CPU needs to jump to protected mode using an identity
165 164 * mapped address, we need to calculate it here.
166 165 */
167 166 rm->rm_longmode64_addr = rm_platter_pa +
168 167 (uint32_t)((uintptr_t)long_mode_64 -
169 168 (uintptr_t)real_mode_start_cpu);
170 169 #endif /* __amd64 */
171 170 }
172 171
173 172 static void *
174 173 mach_cpucontext_alloc_tables(struct cpu *cp)
175 174 {
176 175 tss_t *ntss;
177 176 struct cpu_tables *ct;
178 177
179 178 /*
180 179 * Allocate space for stack, tss, gdt and idt. We round the size
181 180 * allotted for cpu_tables up, so that the TSS is on a unique page.
182 181 * This is more efficient when running in virtual machines.
183 182 */
184 183 ct = kmem_zalloc(P2ROUNDUP(sizeof (*ct), PAGESIZE), KM_SLEEP);
185 184 if ((uintptr_t)ct & PAGEOFFSET)
186 185 panic("mach_cpucontext_alloc_tables: cpu%d misaligned tables",
187 186 cp->cpu_id);
188 187
189 188 ntss = cp->cpu_tss = &ct->ct_tss;
190 189
191 190 #if defined(__amd64)
192 191
193 192 /*
194 193 * #DF (double fault).
195 194 */
196 195 ntss->tss_ist1 = (uint64_t)&ct->ct_stack[sizeof (ct->ct_stack)];
197 196
198 197 #elif defined(__i386)
199 198
200 199 ntss->tss_esp0 = ntss->tss_esp1 = ntss->tss_esp2 = ntss->tss_esp =
201 200 (uint32_t)&ct->ct_stack[sizeof (ct->ct_stack)];
202 201
203 202 ntss->tss_ss0 = ntss->tss_ss1 = ntss->tss_ss2 = ntss->tss_ss = KDS_SEL;
204 203
205 204 ntss->tss_eip = (uint32_t)cp->cpu_thread->t_pc;
206 205
207 206 ntss->tss_cs = KCS_SEL;
208 207 ntss->tss_ds = ntss->tss_es = KDS_SEL;
209 208 ntss->tss_fs = KFS_SEL;
210 209 ntss->tss_gs = KGS_SEL;
211 210
212 211 #endif /* __i386 */
213 212
214 213 /*
215 214 * Set I/O bit map offset equal to size of TSS segment limit
216 215 * for no I/O permission map. This will cause all user I/O
217 216 * instructions to generate #gp fault.
218 217 */
219 218 ntss->tss_bitmapbase = sizeof (*ntss);
220 219
221 220 /*
222 221 * Setup kernel tss.
223 222 */
224 223 set_syssegd((system_desc_t *)&cp->cpu_gdt[GDT_KTSS], cp->cpu_tss,
225 224 sizeof (*cp->cpu_tss) - 1, SDT_SYSTSS, SEL_KPL);
226 225
227 226 return (ct);
228 227 }
229 228
230 229 void *
231 230 mach_cpucontext_xalloc(struct cpu *cp, int optype)
232 231 {
233 232 size_t len;
234 233 struct cpu_tables *ct;
235 234 rm_platter_t *rm = (rm_platter_t *)rm_platter_va;
236 235 static int cpu_halt_code_ready;
237 236
238 237 if (optype == MACH_CPUCONTEXT_OP_STOP) {
239 238 ASSERT(plat_dr_enabled());
240 239
241 240 /*
242 241 * The WARM_RESET_VECTOR has a limitation that the physical
243 242 * address written to it must be page-aligned. To work around
244 243 * this limitation, the CPU stop code has been splitted into
245 244 * two stages.
246 245 * The stage 2 code, which implements the real logic to halt
247 246 * CPUs, is copied to the rm_cpu_halt_code field in the real
248 247 * mode platter. The stage 1 code, which simply jumps to the
249 248 * stage 2 code in the rm_cpu_halt_code field, is copied to
250 249 * rm_code field in the real mode platter and it may be
251 250 * overwritten after the CPU has been stopped.
252 251 */
253 252 if (!cpu_halt_code_ready) {
254 253 /*
255 254 * The rm_cpu_halt_code field in the real mode platter
256 255 * is used by the CPU stop code only. So only copy the
257 256 * CPU stop stage 2 code into the rm_cpu_halt_code
258 257 * field on the first call.
259 258 */
260 259 len = (size_t)real_mode_stop_cpu_stage2_end -
261 260 (size_t)real_mode_stop_cpu_stage2;
262 261 ASSERT(len <= RM_PLATTER_CPU_HALT_CODE_SIZE);
263 262 bcopy((caddr_t)real_mode_stop_cpu_stage2,
264 263 (caddr_t)rm->rm_cpu_halt_code, len);
265 264 cpu_halt_code_ready = 1;
266 265 }
267 266
268 267 /*
269 268 * The rm_code field in the real mode platter is shared by
270 269 * the CPU start, CPU stop, CPR and fast reboot code. So copy
271 270 * the CPU stop stage 1 code into the rm_code field every time.
272 271 */
273 272 len = (size_t)real_mode_stop_cpu_stage1_end -
274 273 (size_t)real_mode_stop_cpu_stage1;
275 274 ASSERT(len <= RM_PLATTER_CODE_SIZE);
276 275 bcopy((caddr_t)real_mode_stop_cpu_stage1,
277 276 (caddr_t)rm->rm_code, len);
278 277 rm->rm_cpu_halted = 0;
279 278
280 279 return (cp->cpu_m.mcpu_mach_ctx_ptr);
281 280 } else if (optype != MACH_CPUCONTEXT_OP_START) {
282 281 return (NULL);
283 282 }
284 283
285 284 /*
286 285 * Only need to allocate tables when starting CPU.
287 286 * Tables allocated when starting CPU will be reused when stopping CPU.
288 287 */
289 288 ct = mach_cpucontext_alloc_tables(cp);
290 289 if (ct == NULL) {
291 290 return (NULL);
292 291 }
293 292
294 293 /* Copy CPU startup code to rm_platter for CPU hot-add operations. */
295 294 if (plat_dr_enabled()) {
296 295 bcopy((caddr_t)real_mode_start_cpu, (caddr_t)rm->rm_code,
297 296 (size_t)real_mode_start_cpu_end -
298 297 (size_t)real_mode_start_cpu);
299 298 }
300 299
301 300 /*
302 301 * Now copy all that we've set up onto the real mode platter
303 302 * for the real mode code to digest as part of starting the cpu.
304 303 */
305 304 rm->rm_idt_base = cp->cpu_idt;
306 305 rm->rm_idt_lim = sizeof (*cp->cpu_idt) * NIDT - 1;
307 306 rm->rm_gdt_base = cp->cpu_gdt;
308 307 rm->rm_gdt_lim = sizeof (*cp->cpu_gdt) * NGDT - 1;
309 308
310 309 /*
311 310 * CPU needs to access kernel address space after powering on.
312 311 * When hot-adding CPU at runtime, directly use top level page table
313 312 * of kas other than the return value of getcr3(). getcr3() returns
314 313 * current process's top level page table, which may be different from
315 314 * the one of kas.
316 315 */
317 316 rm->rm_pdbr = MAKECR3(kas.a_hat->hat_htable->ht_pfn);
318 317 rm->rm_cpu = cp->cpu_id;
319 318
320 319 /*
321 320 * For hot-adding CPU at runtime, Machine Check and Performance Counter
322 321 * should be disabled. They will be enabled on demand after CPU powers
323 322 * on successfully
324 323 */
325 324 rm->rm_cr4 = getcr4();
326 325 rm->rm_cr4 &= ~(CR4_MCE | CR4_PCE);
327 326
328 327 rmp_gdt_init(rm);
329 328
330 329 return (ct);
331 330 }
332 331
333 332 void
334 333 mach_cpucontext_xfree(struct cpu *cp, void *arg, int err, int optype)
335 334 {
336 335 struct cpu_tables *ct = arg;
337 336
338 337 ASSERT(&ct->ct_tss == cp->cpu_tss);
339 338 if (optype == MACH_CPUCONTEXT_OP_START) {
340 339 switch (err) {
341 340 case 0:
342 341 /*
343 342 * Save pointer for reuse when stopping CPU.
344 343 */
345 344 cp->cpu_m.mcpu_mach_ctx_ptr = arg;
346 345 break;
347 346 case ETIMEDOUT:
348 347 /*
349 348 * The processor was poked, but failed to start before
350 349 * we gave up waiting for it. In case it starts later,
351 350 * don't free anything.
352 351 */
353 352 cp->cpu_m.mcpu_mach_ctx_ptr = arg;
354 353 break;
355 354 default:
356 355 /*
357 356 * Some other, passive, error occurred.
358 357 */
359 358 kmem_free(ct, P2ROUNDUP(sizeof (*ct), PAGESIZE));
360 359 cp->cpu_tss = NULL;
361 360 break;
362 361 }
363 362 } else if (optype == MACH_CPUCONTEXT_OP_STOP) {
364 363 switch (err) {
365 364 case 0:
366 365 /*
367 366 * Free resources allocated when starting CPU.
368 367 */
369 368 kmem_free(ct, P2ROUNDUP(sizeof (*ct), PAGESIZE));
370 369 cp->cpu_tss = NULL;
371 370 cp->cpu_m.mcpu_mach_ctx_ptr = NULL;
372 371 break;
373 372 default:
374 373 /*
375 374 * Don't touch table pointer in case of failure.
376 375 */
377 376 break;
378 377 }
379 378 } else {
380 379 ASSERT(0);
381 380 }
382 381 }
383 382
384 383 void *
385 384 mach_cpucontext_alloc(struct cpu *cp)
386 385 {
387 386 return (mach_cpucontext_xalloc(cp, MACH_CPUCONTEXT_OP_START));
388 387 }
389 388
390 389 void
391 390 mach_cpucontext_free(struct cpu *cp, void *arg, int err)
392 391 {
393 392 mach_cpucontext_xfree(cp, arg, err, MACH_CPUCONTEXT_OP_START);
394 393 }
395 394
396 395 /*
397 396 * "Enter monitor." Called via cross-call from stop_other_cpus().
398 397 */
399 398 void
400 399 mach_cpu_halt(char *msg)
401 400 {
402 401 if (msg)
403 402 prom_printf("%s\n", msg);
404 403
405 404 /*CONSTANTCONDITION*/
406 405 while (1)
407 406 ;
408 407 }
409 408
410 409 void
411 410 mach_cpu_idle(void)
412 411 {
413 412 i86_halt();
414 413 }
415 414
416 415 void
417 416 mach_cpu_pause(volatile char *safe)
418 417 {
419 418 /*
420 419 * This cpu is now safe.
421 420 */
422 421 *safe = PAUSE_WAIT;
423 422 membar_enter(); /* make sure stores are flushed */
424 423
425 424 /*
426 425 * Now we wait. When we are allowed to continue, safe
427 426 * will be set to PAUSE_IDLE.
428 427 */
429 428 while (*safe != PAUSE_IDLE)
430 429 SMT_PAUSE();
431 430 }
432 431
433 432 /*
434 433 * Power on the target CPU.
435 434 */
436 435 int
437 436 mp_cpu_poweron(struct cpu *cp)
438 437 {
439 438 int error;
440 439 cpuset_t tempset;
441 440 processorid_t cpuid;
442 441
443 442 ASSERT(cp != NULL);
444 443 cpuid = cp->cpu_id;
445 444 if (use_mp == 0 || plat_dr_support_cpu() == 0) {
446 445 return (ENOTSUP);
447 446 } else if (cpuid < 0 || cpuid >= max_ncpus) {
448 447 return (EINVAL);
449 448 }
450 449
451 450 /*
452 451 * The currrent x86 implementaiton of mp_cpu_configure() and
453 452 * mp_cpu_poweron() have a limitation that mp_cpu_poweron() could only
454 453 * be called once after calling mp_cpu_configure() for a specific CPU.
455 454 * It's because mp_cpu_poweron() will destroy data structure created
456 455 * by mp_cpu_configure(). So reject the request if the CPU has already
457 456 * been powered on once after calling mp_cpu_configure().
458 457 * This limitaiton only affects the p_online syscall and the DR driver
459 458 * won't be affected because the DR driver always invoke public CPU
460 459 * management interfaces in the predefined order:
461 460 * cpu_configure()->cpu_poweron()...->cpu_poweroff()->cpu_unconfigure()
462 461 */
463 462 if (cpuid_checkpass(cp, 4) || cp->cpu_thread == cp->cpu_idle_thread) {
464 463 return (ENOTSUP);
465 464 }
466 465
467 466 /*
468 467 * Check if there's at least a Mbyte of kmem available
469 468 * before attempting to start the cpu.
470 469 */
471 470 if (kmem_avail() < 1024 * 1024) {
472 471 /*
473 472 * Kick off a reap in case that helps us with
474 473 * later attempts ..
475 474 */
476 475 kmem_reap();
477 476 return (ENOMEM);
478 477 }
479 478
480 479 affinity_set(CPU->cpu_id);
481 480
482 481 /*
483 482 * Start the target CPU. No need to call mach_cpucontext_fini()
484 483 * if mach_cpucontext_init() fails.
485 484 */
486 485 if ((error = mach_cpucontext_init()) == 0) {
487 486 error = mp_start_cpu_common(cp, B_FALSE);
488 487 mach_cpucontext_fini();
489 488 }
490 489 if (error != 0) {
491 490 affinity_clear();
492 491 return (error);
493 492 }
494 493
495 494 /* Wait for the target cpu to reach READY state. */
496 495 tempset = cpu_ready_set;
497 496 while (!CPU_IN_SET(tempset, cpuid)) {
498 497 delay(1);
499 498 tempset = *((volatile cpuset_t *)&cpu_ready_set);
500 499 }
501 500
502 501 /* Mark the target CPU as available for mp operation. */
503 502 CPUSET_ATOMIC_ADD(mp_cpus, cpuid);
504 503
505 504 /* Free the space allocated to hold the microcode file */
506 505 ucode_cleanup();
507 506
508 507 affinity_clear();
509 508
510 509 return (0);
511 510 }
512 511
513 512 #define MP_CPU_DETACH_MAX_TRIES 5
514 513 #define MP_CPU_DETACH_DELAY 100
515 514
516 515 static int
517 516 mp_cpu_detach_driver(dev_info_t *dip)
518 517 {
519 518 int i;
520 519 int rv = EBUSY;
521 520 dev_info_t *pdip;
522 521
523 522 pdip = ddi_get_parent(dip);
524 523 ASSERT(pdip != NULL);
525 524 /*
526 525 * Check if caller holds pdip busy - can cause deadlocks in
527 526 * e_ddi_branch_unconfigure(), which calls devfs_clean().
528 527 */
529 528 if (DEVI_BUSY_OWNED(pdip)) {
530 529 return (EDEADLOCK);
531 530 }
532 531
533 532 for (i = 0; i < MP_CPU_DETACH_MAX_TRIES; i++) {
534 533 if (e_ddi_branch_unconfigure(dip, NULL, 0) == 0) {
535 534 rv = 0;
536 535 break;
537 536 }
538 537 DELAY(MP_CPU_DETACH_DELAY);
539 538 }
540 539
541 540 return (rv);
542 541 }
543 542
544 543 /*
545 544 * Power off the target CPU.
546 545 * Note: cpu_lock will be released and then reacquired.
547 546 */
548 547 int
549 548 mp_cpu_poweroff(struct cpu *cp)
550 549 {
551 550 int rv = 0;
552 551 void *ctx;
553 552 dev_info_t *dip = NULL;
554 553 rm_platter_t *rm = (rm_platter_t *)rm_platter_va;
555 554 extern void cpupm_start(cpu_t *);
556 555 extern void cpupm_stop(cpu_t *);
557 556
558 557 ASSERT(cp != NULL);
559 558 ASSERT((cp->cpu_flags & CPU_OFFLINE) != 0);
560 559 ASSERT((cp->cpu_flags & CPU_QUIESCED) != 0);
561 560
562 561 if (use_mp == 0 || plat_dr_support_cpu() == 0) {
563 562 return (ENOTSUP);
564 563 }
565 564 /*
566 565 * There is no support for powering off cpu0 yet.
567 566 * There are many pieces of code which have a hard dependency on cpu0.
568 567 */
569 568 if (cp->cpu_id == 0) {
570 569 return (ENOTSUP);
571 570 };
572 571
573 572 if (mach_cpu_get_device_node(cp, &dip) != PSM_SUCCESS) {
574 573 return (ENXIO);
575 574 }
576 575 ASSERT(dip != NULL);
577 576 if (mp_cpu_detach_driver(dip) != 0) {
578 577 rv = EBUSY;
579 578 goto out_online;
580 579 }
581 580
582 581 /* Allocate CPU context for stopping */
583 582 if (mach_cpucontext_init() != 0) {
584 583 rv = ENXIO;
585 584 goto out_online;
586 585 }
587 586 ctx = mach_cpucontext_xalloc(cp, MACH_CPUCONTEXT_OP_STOP);
588 587 if (ctx == NULL) {
589 588 rv = ENXIO;
590 589 goto out_context_fini;
591 590 }
592 591
593 592 cpupm_stop(cp);
594 593 cpu_event_fini_cpu(cp);
595 594
596 595 if (cp->cpu_m.mcpu_cmi_hdl != NULL) {
597 596 cmi_fini(cp->cpu_m.mcpu_cmi_hdl);
598 597 cp->cpu_m.mcpu_cmi_hdl = NULL;
599 598 }
600 599
601 600 rv = mach_cpu_stop(cp, ctx);
602 601 if (rv != 0) {
603 602 goto out_enable_cmi;
604 603 }
605 604
606 605 /* Wait until the target CPU has been halted. */
607 606 while (*(volatile ushort_t *)&(rm->rm_cpu_halted) != 0xdead) {
608 607 delay(1);
609 608 }
610 609 rm->rm_cpu_halted = 0xffff;
611 610
612 611 /* CPU_READY has been cleared by mach_cpu_stop. */
613 612 ASSERT((cp->cpu_flags & CPU_READY) == 0);
614 613 ASSERT((cp->cpu_flags & CPU_RUNNING) == 0);
615 614 cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF;
616 615 CPUSET_ATOMIC_DEL(mp_cpus, cp->cpu_id);
617 616
618 617 mach_cpucontext_xfree(cp, ctx, 0, MACH_CPUCONTEXT_OP_STOP);
619 618 mach_cpucontext_fini();
620 619
621 620 return (0);
622 621
623 622 out_enable_cmi:
624 623 {
625 624 cmi_hdl_t hdl;
626 625
627 626 if ((hdl = cmi_init(CMI_HDL_NATIVE, cmi_ntv_hwchipid(cp),
628 627 cmi_ntv_hwcoreid(cp), cmi_ntv_hwstrandid(cp))) != NULL) {
629 628 if (is_x86_feature(x86_featureset, X86FSET_MCA))
630 629 cmi_mca_init(hdl);
631 630 cp->cpu_m.mcpu_cmi_hdl = hdl;
632 631 }
633 632 }
634 633 cpu_event_init_cpu(cp);
635 634 cpupm_start(cp);
636 635 mach_cpucontext_xfree(cp, ctx, rv, MACH_CPUCONTEXT_OP_STOP);
637 636
638 637 out_context_fini:
639 638 mach_cpucontext_fini();
640 639
641 640 out_online:
642 641 (void) e_ddi_branch_configure(dip, NULL, 0);
643 642
644 643 if (rv != EAGAIN && rv != ETIME) {
645 644 rv = ENXIO;
646 645 }
647 646
648 647 return (rv);
649 648 }
650 649
651 650 /*
652 651 * Return vcpu state, since this could be a virtual environment that we
653 652 * are unaware of, return "unknown".
654 653 */
655 654 /* ARGSUSED */
656 655 int
657 656 vcpu_on_pcpu(processorid_t cpu)
658 657 {
659 658 return (VCPU_STATE_UNKNOWN);
660 659 }
↓ open down ↓ |
584 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX