xref: /illumos-gate/usr/src/uts/i86pc/os/cpr_impl.c (revision b2b3ca14)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Platform specific implementation code
28  * Currently only suspend to RAM is supported (ACPI S3)
29  */
30 
31 #define	SUNDDI_IMPL
32 
33 #include <sys/types.h>
34 #include <sys/promif.h>
35 #include <sys/prom_isa.h>
36 #include <sys/prom_plat.h>
37 #include <sys/cpuvar.h>
38 #include <sys/pte.h>
39 #include <vm/hat.h>
40 #include <vm/page.h>
41 #include <vm/as.h>
42 #include <sys/cpr.h>
43 #include <sys/kmem.h>
44 #include <sys/clock.h>
45 #include <sys/kmem.h>
46 #include <sys/panic.h>
47 #include <vm/seg_kmem.h>
48 #include <sys/cpu_module.h>
49 #include <sys/callb.h>
50 #include <sys/machsystm.h>
51 #include <sys/vmsystm.h>
52 #include <sys/systm.h>
53 #include <sys/archsystm.h>
54 #include <sys/stack.h>
55 #include <sys/fs/ufs_fs.h>
56 #include <sys/memlist.h>
57 #include <sys/bootconf.h>
58 #include <sys/thread.h>
59 #include <sys/x_call.h>
60 #include <sys/smp_impldefs.h>
61 #include <vm/vm_dep.h>
62 #include <sys/psm.h>
63 #include <sys/epm.h>
64 #include <sys/cpr_wakecode.h>
65 #include <sys/x86_archext.h>
66 #include <sys/reboot.h>
67 #include <sys/acpi/acpi.h>
68 #include <sys/acpica.h>
69 
70 #define	AFMT	"%lx"
71 
72 extern int	flushes_require_xcalls;
73 extern cpuset_t	cpu_ready_set;
74 
75 #if defined(__amd64)
76 extern void	*wc_long_mode_64(void);
77 #endif	/* __amd64 */
78 extern int	tsc_gethrtime_enable;
79 extern	void	i_cpr_start_cpu(void);
80 
81 ushort_t	cpr_mach_type = CPR_MACHTYPE_X86;
82 void		(*cpr_start_cpu_func)(void) = i_cpr_start_cpu;
83 
84 static wc_cpu_t	*wc_other_cpus = NULL;
85 static cpuset_t procset;
86 
87 static void
88 init_real_mode_platter(int cpun, uint32_t offset, uint_t cr4, wc_desctbr_t gdt);
89 
90 static int i_cpr_platform_alloc(psm_state_request_t *req);
91 static void i_cpr_platform_free(psm_state_request_t *req);
92 static int i_cpr_save_apic(psm_state_request_t *req);
93 static int i_cpr_restore_apic(psm_state_request_t *req);
94 static int wait_for_set(cpuset_t *set, int who);
95 
96 /*
97  * restart paused slave cpus
98  */
99 void
100 i_cpr_machdep_setup(void)
101 {
102 	if (ncpus > 1) {
103 		CPR_DEBUG(CPR_DEBUG1, ("MP restarted...\n"));
104 		mutex_enter(&cpu_lock);
105 		start_cpus();
106 		mutex_exit(&cpu_lock);
107 	}
108 }
109 
110 
111 /*
112  * Stop all interrupt activities in the system
113  */
114 void
115 i_cpr_stop_intr(void)
116 {
117 	(void) spl7();
118 }
119 
120 /*
121  * Set machine up to take interrupts
122  */
123 void
124 i_cpr_enable_intr(void)
125 {
126 	(void) spl0();
127 }
128 
129 /*
130  * Save miscellaneous information which needs to be written to the
131  * state file.  This information is required to re-initialize
132  * kernel/prom handshaking.
133  */
134 void
135 i_cpr_save_machdep_info(void)
136 {
137 	int notcalled = 0;
138 	ASSERT(notcalled);
139 }
140 
141 
142 void
143 i_cpr_set_tbr(void)
144 {
145 }
146 
147 
148 processorid_t
149 i_cpr_bootcpuid(void)
150 {
151 	return (0);
152 }
153 
154 /*
155  * cpu0 should contain bootcpu info
156  */
157 cpu_t *
158 i_cpr_bootcpu(void)
159 {
160 	ASSERT(MUTEX_HELD(&cpu_lock));
161 
162 	return (cpu_get(i_cpr_bootcpuid()));
163 }
164 
165 /*
166  *	Save context for the specified CPU
167  */
168 void *
169 i_cpr_save_context(void *arg)
170 {
171 	long	index = (long)arg;
172 	psm_state_request_t *papic_state;
173 	int resuming;
174 	int	ret;
175 
176 	PMD(PMD_SX, ("i_cpr_save_context() index = %ld\n", index))
177 
178 	ASSERT(index < NCPU);
179 
180 	papic_state = &(wc_other_cpus + index)->wc_apic_state;
181 
182 	ret = i_cpr_platform_alloc(papic_state);
183 	ASSERT(ret == 0);
184 
185 	ret = i_cpr_save_apic(papic_state);
186 	ASSERT(ret == 0);
187 
188 	/*
189 	 * wc_save_context returns twice, once when susending and
190 	 * once when resuming,  wc_save_context() returns 0 when
191 	 * suspending and non-zero upon resume
192 	 */
193 	resuming = (wc_save_context(wc_other_cpus + index) == 0);
194 
195 	/*
196 	 * do NOT call any functions after this point, because doing so
197 	 * will modify the stack that we are running on
198 	 */
199 
200 	if (resuming) {
201 
202 		ret = i_cpr_restore_apic(papic_state);
203 		ASSERT(ret == 0);
204 
205 		i_cpr_platform_free(papic_state);
206 
207 		/*
208 		 * Enable interrupts on this cpu.
209 		 * Do not bind interrupts to this CPU's local APIC until
210 		 * the CPU is ready to receive interrupts.
211 		 */
212 		ASSERT(CPU->cpu_id != i_cpr_bootcpuid());
213 		mutex_enter(&cpu_lock);
214 		cpu_enable_intr(CPU);
215 		mutex_exit(&cpu_lock);
216 
217 		/*
218 		 * Setting the bit in cpu_ready_set must be the last operation
219 		 * in processor initialization; the boot CPU will continue to
220 		 * boot once it sees this bit set for all active CPUs.
221 		 */
222 		CPUSET_ATOMIC_ADD(cpu_ready_set, CPU->cpu_id);
223 
224 		PMD(PMD_SX,
225 		    ("i_cpr_save_context() resuming cpu %d in cpu_ready_set\n",
226 		    CPU->cpu_id))
227 	} else {
228 		/*
229 		 * Disable interrupts on this CPU so that PSM knows not to bind
230 		 * interrupts here on resume until the CPU has executed
231 		 * cpu_enable_intr() (above) in the resume path.
232 		 * We explicitly do not grab cpu_lock here because at this point
233 		 * in the suspend process, the boot cpu owns cpu_lock and all
234 		 * other cpus are also executing in the pause thread (only
235 		 * modifying their respective CPU structure).
236 		 */
237 		(void) cpu_disable_intr(CPU);
238 	}
239 
240 	PMD(PMD_SX, ("i_cpr_save_context: wc_save_context returns %d\n",
241 	    resuming))
242 
243 	return (NULL);
244 }
245 
246 static ushort_t *warm_reset_vector = NULL;
247 
248 static ushort_t *
249 map_warm_reset_vector()
250 {
251 	/*LINTED*/
252 	if (!(warm_reset_vector = (ushort_t *)psm_map_phys(WARM_RESET_VECTOR,
253 	    sizeof (ushort_t *), PROT_READ|PROT_WRITE)))
254 		return (NULL);
255 
256 	/*
257 	 * setup secondary cpu bios boot up vector
258 	 */
259 	*warm_reset_vector = (ushort_t)((caddr_t)
260 	    /*LINTED*/
261 	    ((struct rm_platter *)rm_platter_va)->rm_code - rm_platter_va
262 	    + ((ulong_t)rm_platter_va & 0xf));
263 	warm_reset_vector++;
264 	*warm_reset_vector = (ushort_t)(rm_platter_pa >> 4);
265 
266 	--warm_reset_vector;
267 	return (warm_reset_vector);
268 }
269 
270 void
271 i_cpr_pre_resume_cpus()
272 {
273 	/*
274 	 * this is a cut down version of start_other_cpus()
275 	 * just do the initialization to wake the other cpus
276 	 */
277 	unsigned who;
278 	int boot_cpuid = i_cpr_bootcpuid();
279 	uint32_t		code_length = 0;
280 	caddr_t			wakevirt = rm_platter_va;
281 	/*LINTED*/
282 	wakecode_t		*wp = (wakecode_t *)wakevirt;
283 	char *str = "i_cpr_pre_resume_cpus";
284 	extern int get_tsc_ready();
285 	int err;
286 
287 	/*LINTED*/
288 	rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va;
289 
290 	/*
291 	 * If startup wasn't able to find a page under 1M, we cannot
292 	 * proceed.
293 	 */
294 	if (rm_platter_va == 0) {
295 		cmn_err(CE_WARN, "Cannot suspend the system because no "
296 		    "memory below 1M could be found for processor startup");
297 		return;
298 	}
299 
300 	/*
301 	 * Copy the real mode code at "real_mode_start" to the
302 	 * page at rm_platter_va.
303 	 */
304 	warm_reset_vector = map_warm_reset_vector();
305 	if (warm_reset_vector == NULL) {
306 		PMD(PMD_SX, ("i_cpr_pre_resume_cpus() returning #2\n"))
307 		return;
308 	}
309 
310 	flushes_require_xcalls = 1;
311 
312 	/*
313 	 * We lock our affinity to the master CPU to ensure that all slave CPUs
314 	 * do their TSC syncs with the same CPU.
315 	 */
316 
317 	affinity_set(CPU_CURRENT);
318 
319 	/*
320 	 * Mark the boot cpu as being ready and in the procset, since we are
321 	 * running on that cpu.
322 	 */
323 	CPUSET_ONLY(cpu_ready_set, boot_cpuid);
324 	CPUSET_ONLY(procset, boot_cpuid);
325 
326 	for (who = 0; who < ncpus; who++) {
327 
328 		wc_cpu_t	*cpup = wc_other_cpus + who;
329 		wc_desctbr_t	gdt;
330 
331 		if (who == boot_cpuid)
332 			continue;
333 
334 		if (!CPU_IN_SET(mp_cpus, who))
335 			continue;
336 
337 		PMD(PMD_SX, ("%s() waking up %d cpu\n", str, who))
338 
339 		bcopy(cpup, &(wp->wc_cpu), sizeof (wc_cpu_t));
340 
341 		gdt.base = cpup->wc_gdt_base;
342 		gdt.limit = cpup->wc_gdt_limit;
343 
344 #if defined(__amd64)
345 		code_length = (uint32_t)wc_long_mode_64 - (uint32_t)wc_rm_start;
346 #else
347 		code_length = 0;
348 #endif
349 
350 		init_real_mode_platter(who, code_length, cpup->wc_cr4, gdt);
351 
352 		if ((err = mach_cpuid_start(who, rm_platter_va)) != 0) {
353 			cmn_err(CE_WARN, "cpu%d: failed to start during "
354 			    "suspend/resume error %d", who, err);
355 			continue;
356 		}
357 
358 		PMD(PMD_SX, ("%s() #1 waiting for %d in procset\n", str, who))
359 
360 		if (!wait_for_set(&procset, who))
361 			continue;
362 
363 		PMD(PMD_SX, ("%s() %d cpu started\n", str, who))
364 
365 		PMD(PMD_SX, ("%s() tsc_ready = %d\n", str, get_tsc_ready()))
366 
367 		if (tsc_gethrtime_enable) {
368 			PMD(PMD_SX, ("%s() calling tsc_sync_master\n", str))
369 			tsc_sync_master(who);
370 		}
371 
372 		PMD(PMD_SX, ("%s() waiting for %d in cpu_ready_set\n", str,
373 		    who))
374 		/*
375 		 * Wait for cpu to declare that it is ready, we want the
376 		 * cpus to start serially instead of in parallel, so that
377 		 * they do not contend with each other in wc_rm_start()
378 		 */
379 		if (!wait_for_set(&cpu_ready_set, who))
380 			continue;
381 
382 		/*
383 		 * do not need to re-initialize dtrace using dtrace_cpu_init
384 		 * function
385 		 */
386 		PMD(PMD_SX, ("%s() cpu %d now ready\n", str, who))
387 	}
388 
389 	affinity_clear();
390 
391 	PMD(PMD_SX, ("%s() all cpus now ready\n", str))
392 
393 }
394 
395 static void
396 unmap_warm_reset_vector(ushort_t *warm_reset_vector)
397 {
398 	psm_unmap_phys((caddr_t)warm_reset_vector, sizeof (ushort_t *));
399 }
400 
401 /*
402  * We need to setup a 1:1 (virtual to physical) mapping for the
403  * page containing the wakeup code.
404  */
405 static struct as *save_as;	/* when switching to kas */
406 
407 static void
408 unmap_wakeaddr_1to1(uint64_t wakephys)
409 {
410 	uintptr_t	wp = (uintptr_t)wakephys;
411 	hat_setup(save_as->a_hat, 0);	/* switch back from kernel hat */
412 	hat_unload(kas.a_hat, (caddr_t)wp, PAGESIZE, HAT_UNLOAD);
413 }
414 
415 void
416 i_cpr_post_resume_cpus()
417 {
418 	uint64_t	wakephys = rm_platter_pa;
419 
420 	if (warm_reset_vector != NULL)
421 		unmap_warm_reset_vector(warm_reset_vector);
422 
423 	hat_unload(kas.a_hat, (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE,
424 	    HAT_UNLOAD);
425 
426 	/*
427 	 * cmi_post_mpstartup() is only required upon boot not upon
428 	 * resume from RAM
429 	 */
430 
431 	PT(PT_UNDO1to1);
432 	/* Tear down 1:1 mapping for wakeup code */
433 	unmap_wakeaddr_1to1(wakephys);
434 }
435 
436 /* ARGSUSED */
437 void
438 i_cpr_handle_xc(int flag)
439 {
440 }
441 
442 int
443 i_cpr_reusable_supported(void)
444 {
445 	return (0);
446 }
447 static void
448 map_wakeaddr_1to1(uint64_t wakephys)
449 {
450 	uintptr_t	wp = (uintptr_t)wakephys;
451 	hat_devload(kas.a_hat, (caddr_t)wp, PAGESIZE, btop(wakephys),
452 	    (PROT_READ|PROT_WRITE|PROT_EXEC|HAT_STORECACHING_OK|HAT_NOSYNC),
453 	    HAT_LOAD);
454 	save_as = curthread->t_procp->p_as;
455 	hat_setup(kas.a_hat, 0);	/* switch to kernel-only hat */
456 }
457 
458 
459 void
460 prt_other_cpus()
461 {
462 	int	who;
463 
464 	if (ncpus == 1) {
465 		PMD(PMD_SX, ("prt_other_cpus() other cpu table empty for "
466 		    "uniprocessor machine\n"))
467 		return;
468 	}
469 
470 	for (who = 0; who < ncpus; who++) {
471 
472 		wc_cpu_t	*cpup = wc_other_cpus + who;
473 
474 		PMD(PMD_SX, ("prt_other_cpus() who = %d, gdt=%p:%x, "
475 		    "idt=%p:%x, ldt=%lx, tr=%lx, kgsbase="
476 		    AFMT ", sp=%lx\n", who,
477 		    (void *)cpup->wc_gdt_base, cpup->wc_gdt_limit,
478 		    (void *)cpup->wc_idt_base, cpup->wc_idt_limit,
479 		    (long)cpup->wc_ldt, (long)cpup->wc_tr,
480 		    (long)cpup->wc_kgsbase, (long)cpup->wc_rsp))
481 	}
482 }
483 
484 /*
485  * Power down the system.
486  */
487 int
488 i_cpr_power_down(int sleeptype)
489 {
490 	caddr_t		wakevirt = rm_platter_va;
491 	uint64_t	wakephys = rm_platter_pa;
492 	ulong_t		saved_intr;
493 	uint32_t	code_length = 0;
494 	wc_desctbr_t	gdt;
495 	/*LINTED*/
496 	wakecode_t	*wp = (wakecode_t *)wakevirt;
497 	/*LINTED*/
498 	rm_platter_t	*wcpp = (rm_platter_t *)wakevirt;
499 	wc_cpu_t	*cpup = &(wp->wc_cpu);
500 	dev_info_t	*ppm;
501 	int		ret = 0;
502 	power_req_t	power_req;
503 	char *str =	"i_cpr_power_down";
504 #if defined(__amd64)
505 	/*LINTED*/
506 	rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va;
507 #endif
508 	extern int	cpr_suspend_succeeded;
509 	extern void	kernel_wc_code();
510 
511 	ASSERT(sleeptype == CPR_TORAM);
512 	ASSERT(CPU->cpu_id == 0);
513 
514 	if ((ppm = PPM(ddi_root_node())) == NULL) {
515 		PMD(PMD_SX, ("%s: root node not claimed\n", str))
516 		return (ENOTTY);
517 	}
518 
519 	PMD(PMD_SX, ("Entering %s()\n", str))
520 
521 	PT(PT_IC);
522 	saved_intr = intr_clear();
523 
524 	PT(PT_1to1);
525 	/* Setup 1:1 mapping for wakeup code */
526 	map_wakeaddr_1to1(wakephys);
527 
528 	PMD(PMD_SX, ("ncpus=%d\n", ncpus))
529 
530 	PMD(PMD_SX, ("wc_rm_end - wc_rm_start=%lx WC_CODESIZE=%x\n",
531 	    ((size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)), WC_CODESIZE))
532 
533 	PMD(PMD_SX, ("wakevirt=%p, wakephys=%x\n",
534 	    (void *)wakevirt, (uint_t)wakephys))
535 
536 	ASSERT(((size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)) <
537 	    WC_CODESIZE);
538 
539 	bzero(wakevirt, PAGESIZE);
540 
541 	/* Copy code to rm_platter */
542 	bcopy((caddr_t)wc_rm_start, wakevirt,
543 	    (size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start));
544 
545 	prt_other_cpus();
546 
547 #if defined(__amd64)
548 
549 	PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n",
550 	    (ulong_t)real_mode_platter->rm_cr4, (ulong_t)getcr4()))
551 	PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n",
552 	    (ulong_t)real_mode_platter->rm_pdbr, getcr3()))
553 
554 	real_mode_platter->rm_cr4 = getcr4();
555 	real_mode_platter->rm_pdbr = getcr3();
556 
557 	rmp_gdt_init(real_mode_platter);
558 
559 	/*
560 	 * Since the CPU needs to jump to protected mode using an identity
561 	 * mapped address, we need to calculate it here.
562 	 */
563 	real_mode_platter->rm_longmode64_addr = rm_platter_pa +
564 	    ((uint32_t)wc_long_mode_64 - (uint32_t)wc_rm_start);
565 
566 	PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n",
567 	    (ulong_t)real_mode_platter->rm_cr4, getcr4()))
568 
569 	PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n",
570 	    (ulong_t)real_mode_platter->rm_pdbr, getcr3()))
571 
572 	PMD(PMD_SX, ("real_mode_platter->rm_longmode64_addr=%lx\n",
573 	    (ulong_t)real_mode_platter->rm_longmode64_addr))
574 
575 #endif
576 
577 	PT(PT_SC);
578 	if (wc_save_context(cpup)) {
579 
580 		ret = i_cpr_platform_alloc(&(wc_other_cpus->wc_apic_state));
581 		if (ret != 0)
582 			return (ret);
583 
584 		ret = i_cpr_save_apic(&(wc_other_cpus->wc_apic_state));
585 		PMD(PMD_SX, ("%s: i_cpr_save_apic() returned %d\n", str, ret))
586 		if (ret != 0)
587 			return (ret);
588 
589 		PMD(PMD_SX, ("wakephys=%x, kernel_wc_code=%p\n",
590 		    (uint_t)wakephys, (void *)&kernel_wc_code))
591 		PMD(PMD_SX, ("virtaddr=%lx, retaddr=%lx\n",
592 		    (long)cpup->wc_virtaddr, (long)cpup->wc_retaddr))
593 		PMD(PMD_SX, ("ebx=%x, edi=%x, esi=%x, ebp=%x, esp=%x\n",
594 		    cpup->wc_ebx, cpup->wc_edi, cpup->wc_esi, cpup->wc_ebp,
595 		    cpup->wc_esp))
596 		PMD(PMD_SX, ("cr0=%lx, cr3=%lx, cr4=%lx\n",
597 		    (long)cpup->wc_cr0, (long)cpup->wc_cr3,
598 		    (long)cpup->wc_cr4))
599 		PMD(PMD_SX, ("cs=%x, ds=%x, es=%x, ss=%x, fs=%lx, gs=%lx, "
600 		    "flgs=%lx\n", cpup->wc_cs, cpup->wc_ds, cpup->wc_es,
601 		    cpup->wc_ss, (long)cpup->wc_fs, (long)cpup->wc_gs,
602 		    (long)cpup->wc_eflags))
603 
604 		PMD(PMD_SX, ("gdt=%p:%x, idt=%p:%x, ldt=%lx, tr=%lx, "
605 		    "kgbase=%lx\n", (void *)cpup->wc_gdt_base,
606 		    cpup->wc_gdt_limit, (void *)cpup->wc_idt_base,
607 		    cpup->wc_idt_limit, (long)cpup->wc_ldt,
608 		    (long)cpup->wc_tr, (long)cpup->wc_kgsbase))
609 
610 		gdt.base = cpup->wc_gdt_base;
611 		gdt.limit = cpup->wc_gdt_limit;
612 
613 #if defined(__amd64)
614 		code_length = (uint32_t)wc_long_mode_64 -
615 		    (uint32_t)wc_rm_start;
616 #else
617 		code_length = 0;
618 #endif
619 
620 		init_real_mode_platter(0, code_length, cpup->wc_cr4, gdt);
621 
622 #if defined(__amd64)
623 		PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n",
624 		    (ulong_t)wcpp->rm_cr4, getcr4()))
625 
626 		PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n",
627 		    (ulong_t)wcpp->rm_pdbr, getcr3()))
628 
629 		PMD(PMD_SX, ("real_mode_platter->rm_longmode64_addr=%lx\n",
630 		    (ulong_t)wcpp->rm_longmode64_addr))
631 
632 		PMD(PMD_SX,
633 		    ("real_mode_platter->rm_temp_gdt[TEMPGDT_KCODE64]=%lx\n",
634 		    (ulong_t)wcpp->rm_temp_gdt[TEMPGDT_KCODE64]))
635 #endif
636 
637 		PMD(PMD_SX, ("gdt=%p:%x, idt=%p:%x, ldt=%lx, tr=%lx, "
638 		    "kgsbase=%lx\n", (void *)wcpp->rm_gdt_base,
639 		    wcpp->rm_gdt_lim, (void *)wcpp->rm_idt_base,
640 		    wcpp->rm_idt_lim, (long)cpup->wc_ldt, (long)cpup->wc_tr,
641 		    (long)cpup->wc_kgsbase))
642 
643 		power_req.request_type = PMR_PPM_ENTER_SX;
644 		power_req.req.ppm_power_enter_sx_req.sx_state = S3;
645 		power_req.req.ppm_power_enter_sx_req.test_point =
646 		    cpr_test_point;
647 		power_req.req.ppm_power_enter_sx_req.wakephys = wakephys;
648 
649 		PMD(PMD_SX, ("%s: pm_ctlops PMR_PPM_ENTER_SX\n", str))
650 		PT(PT_PPMCTLOP);
651 		(void) pm_ctlops(ppm, ddi_root_node(), DDI_CTLOPS_POWER,
652 		    &power_req, &ret);
653 		PMD(PMD_SX, ("%s: returns %d\n", str, ret))
654 
655 		/*
656 		 * If it works, we get control back to the else branch below
657 		 * If we get control back here, it didn't work.
658 		 * XXX return EINVAL here?
659 		 */
660 
661 		unmap_wakeaddr_1to1(wakephys);
662 		intr_restore(saved_intr);
663 
664 		return (ret);
665 	} else {
666 		cpr_suspend_succeeded = 1;
667 
668 		power_req.request_type = PMR_PPM_EXIT_SX;
669 		power_req.req.ppm_power_enter_sx_req.sx_state = S3;
670 
671 		PMD(PMD_SX, ("%s: pm_ctlops PMR_PPM_EXIT_SX\n", str))
672 		PT(PT_PPMCTLOP);
673 		(void) pm_ctlops(ppm, ddi_root_node(), DDI_CTLOPS_POWER,
674 		    &power_req, &ret);
675 		PMD(PMD_SX, ("%s: returns %d\n", str, ret))
676 
677 		ret = i_cpr_restore_apic(&(wc_other_cpus->wc_apic_state));
678 		/*
679 		 * the restore should never fail, if the saved suceeded
680 		 */
681 		ASSERT(ret == 0);
682 
683 		i_cpr_platform_free(&(wc_other_cpus->wc_apic_state));
684 
685 		/*
686 		 * Enable interrupts on boot cpu.
687 		 */
688 		ASSERT(CPU->cpu_id == i_cpr_bootcpuid());
689 		mutex_enter(&cpu_lock);
690 		cpu_enable_intr(CPU);
691 		mutex_exit(&cpu_lock);
692 
693 		PT(PT_INTRRESTORE);
694 		intr_restore(saved_intr);
695 		PT(PT_CPU);
696 
697 		return (ret);
698 	}
699 }
700 
701 /*
702  * Stop all other cpu's before halting or rebooting. We pause the cpu's
703  * instead of sending a cross call.
704  * Stolen from sun4/os/mp_states.c
705  */
706 
707 static int cpu_are_paused;	/* sic */
708 
709 void
710 i_cpr_stop_other_cpus(void)
711 {
712 	mutex_enter(&cpu_lock);
713 	if (cpu_are_paused) {
714 		mutex_exit(&cpu_lock);
715 		return;
716 	}
717 	pause_cpus(NULL);
718 	cpu_are_paused = 1;
719 
720 	mutex_exit(&cpu_lock);
721 }
722 
723 int
724 i_cpr_is_supported(int sleeptype)
725 {
726 	extern int cpr_supported_override;
727 	extern int cpr_platform_enable;
728 	extern int pm_S3_enabled;
729 
730 	if (sleeptype != CPR_TORAM)
731 		return (0);
732 
733 	/*
734 	 * The next statement tests if a specific platform has turned off
735 	 * cpr support.
736 	 */
737 	if (cpr_supported_override)
738 		return (0);
739 
740 	/*
741 	 * If a platform has specifically turned on cpr support ...
742 	 */
743 	if (cpr_platform_enable)
744 		return (1);
745 
746 	return (pm_S3_enabled);
747 }
748 
749 void
750 i_cpr_bitmap_cleanup(void)
751 {
752 }
753 
754 void
755 i_cpr_free_memory_resources(void)
756 {
757 }
758 
759 /*
760  * Needed only for S3 so far
761  */
762 static int
763 i_cpr_platform_alloc(psm_state_request_t *req)
764 {
765 #ifdef DEBUG
766 	char	*str = "i_cpr_platform_alloc";
767 #endif
768 
769 	PMD(PMD_SX, ("cpu = %d, %s(%p) \n", CPU->cpu_id, str, (void *)req))
770 
771 	if (psm_state == NULL) {
772 		PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
773 		return (0);
774 	}
775 
776 	req->psr_cmd = PSM_STATE_ALLOC;
777 	return ((*psm_state)(req));
778 }
779 
780 /*
781  * Needed only for S3 so far
782  */
783 static void
784 i_cpr_platform_free(psm_state_request_t *req)
785 {
786 #ifdef DEBUG
787 	char	*str = "i_cpr_platform_free";
788 #endif
789 
790 	PMD(PMD_SX, ("cpu = %d, %s(%p) \n", CPU->cpu_id, str, (void *)req))
791 
792 	if (psm_state == NULL) {
793 		PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
794 		return;
795 	}
796 
797 	req->psr_cmd = PSM_STATE_FREE;
798 	(void) (*psm_state)(req);
799 }
800 
801 static int
802 i_cpr_save_apic(psm_state_request_t *req)
803 {
804 #ifdef DEBUG
805 	char	*str = "i_cpr_save_apic";
806 #endif
807 
808 	if (psm_state == NULL) {
809 		PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
810 		return (0);
811 	}
812 
813 	req->psr_cmd = PSM_STATE_SAVE;
814 	return ((*psm_state)(req));
815 }
816 
817 static int
818 i_cpr_restore_apic(psm_state_request_t *req)
819 {
820 #ifdef DEBUG
821 	char	*str = "i_cpr_restore_apic";
822 #endif
823 
824 	if (psm_state == NULL) {
825 		PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
826 		return (0);
827 	}
828 
829 	req->psr_cmd = PSM_STATE_RESTORE;
830 	return ((*psm_state)(req));
831 }
832 
833 
834 /* stop lint complaining about offset not being used in 32bit mode */
835 #if !defined(__amd64)
836 /*ARGSUSED*/
837 #endif
838 static void
839 init_real_mode_platter(int cpun, uint32_t offset, uint_t cr4, wc_desctbr_t gdt)
840 {
841 	/*LINTED*/
842 	rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va;
843 
844 	/*
845 	 * Fill up the real mode platter to make it easy for real mode code to
846 	 * kick it off. This area should really be one passed by boot to kernel
847 	 * and guaranteed to be below 1MB and aligned to 16 bytes. Should also
848 	 * have identical physical and virtual address in paged mode.
849 	 */
850 
851 	real_mode_platter->rm_pdbr = getcr3();
852 	real_mode_platter->rm_cpu = cpun;
853 	real_mode_platter->rm_cr4 = cr4;
854 
855 	real_mode_platter->rm_gdt_base = gdt.base;
856 	real_mode_platter->rm_gdt_lim = gdt.limit;
857 
858 #if defined(__amd64)
859 	real_mode_platter->rm_x86feature = x86_feature;
860 
861 	if (getcr3() > 0xffffffffUL)
862 		panic("Cannot initialize CPUs; kernel's 64-bit page tables\n"
863 		    "located above 4G in physical memory (@ 0x%llx).",
864 		    (unsigned long long)getcr3());
865 
866 	/*
867 	 * Setup pseudo-descriptors for temporary GDT and IDT for use ONLY
868 	 * by code in real_mode_start():
869 	 *
870 	 * GDT[0]:  NULL selector
871 	 * GDT[1]:  64-bit CS: Long = 1, Present = 1, bits 12, 11 = 1
872 	 *
873 	 * Clear the IDT as interrupts will be off and a limit of 0 will cause
874 	 * the CPU to triple fault and reset on an NMI, seemingly as reasonable
875 	 * a course of action as any other, though it may cause the entire
876 	 * platform to reset in some cases...
877 	 */
878 	real_mode_platter->rm_temp_gdt[0] = 0ULL;
879 	real_mode_platter->rm_temp_gdt[TEMPGDT_KCODE64] = 0x20980000000000ULL;
880 
881 	real_mode_platter->rm_temp_gdt_lim = (ushort_t)
882 	    (sizeof (real_mode_platter->rm_temp_gdt) - 1);
883 	real_mode_platter->rm_temp_gdt_base = rm_platter_pa +
884 	    (uint32_t)(&((rm_platter_t *)0)->rm_temp_gdt);
885 
886 	real_mode_platter->rm_temp_idt_lim = 0;
887 	real_mode_platter->rm_temp_idt_base = 0;
888 
889 	/*
890 	 * Since the CPU needs to jump to protected mode using an identity
891 	 * mapped address, we need to calculate it here.
892 	 */
893 	real_mode_platter->rm_longmode64_addr = rm_platter_pa + offset;
894 #endif	/* __amd64 */
895 
896 	/* return; */
897 }
898 
899 void
900 i_cpr_start_cpu(void)
901 {
902 
903 	struct cpu *cp = CPU;
904 
905 	char *str = "i_cpr_start_cpu";
906 	extern void init_cpu_syscall(struct cpu *cp);
907 
908 	PMD(PMD_SX, ("%s() called\n", str))
909 
910 	PMD(PMD_SX, ("%s() #0 cp->cpu_base_spl %d\n", str,
911 	    cp->cpu_base_spl))
912 
913 	mutex_enter(&cpu_lock);
914 	if (cp == i_cpr_bootcpu()) {
915 		mutex_exit(&cpu_lock);
916 		PMD(PMD_SX,
917 		    ("%s() called on bootcpu nothing to do!\n", str))
918 		return;
919 	}
920 	mutex_exit(&cpu_lock);
921 
922 	/*
923 	 * We need to Sync PAT with cpu0's PAT. We have to do
924 	 * this with interrupts disabled.
925 	 */
926 	if (x86_feature & X86_PAT)
927 		pat_sync();
928 
929 	/*
930 	 * Initialize this CPU's syscall handlers
931 	 */
932 	init_cpu_syscall(cp);
933 
934 	PMD(PMD_SX, ("%s() #1 cp->cpu_base_spl %d\n", str, cp->cpu_base_spl))
935 
936 	/*
937 	 * Do not need to call cpuid_pass2(), cpuid_pass3(), cpuid_pass4() or
938 	 * init_cpu_info(), since the work that they do is only needed to
939 	 * be done once at boot time
940 	 */
941 
942 
943 	mutex_enter(&cpu_lock);
944 	CPUSET_ADD(procset, cp->cpu_id);
945 	mutex_exit(&cpu_lock);
946 
947 	PMD(PMD_SX, ("%s() #2 cp->cpu_base_spl %d\n", str,
948 	    cp->cpu_base_spl))
949 
950 	if (tsc_gethrtime_enable) {
951 		PMD(PMD_SX, ("%s() calling tsc_sync_slave\n", str))
952 		tsc_sync_slave();
953 	}
954 
955 	PMD(PMD_SX, ("%s() cp->cpu_id %d, cp->cpu_intr_actv %d\n", str,
956 	    cp->cpu_id, cp->cpu_intr_actv))
957 	PMD(PMD_SX, ("%s() #3 cp->cpu_base_spl %d\n", str,
958 	    cp->cpu_base_spl))
959 
960 	(void) spl0();		/* enable interrupts */
961 
962 	PMD(PMD_SX, ("%s() #4 cp->cpu_base_spl %d\n", str,
963 	    cp->cpu_base_spl))
964 
965 	/*
966 	 * Set up the CPU module for this CPU.  This can't be done before
967 	 * this CPU is made CPU_READY, because we may (in heterogeneous systems)
968 	 * need to go load another CPU module.  The act of attempting to load
969 	 * a module may trigger a cross-call, which will ASSERT unless this
970 	 * cpu is CPU_READY.
971 	 */
972 
973 	/*
974 	 * cmi already been init'd (during boot), so do not need to do it again
975 	 */
976 #ifdef PM_REINITMCAONRESUME
977 	if (x86_feature & X86_MCA)
978 		cmi_mca_init();
979 #endif
980 
981 	PMD(PMD_SX, ("%s() returning\n", str))
982 
983 	/* return; */
984 }
985 
986 void
987 i_cpr_alloc_cpus(void)
988 {
989 	char *str = "i_cpr_alloc_cpus";
990 
991 	PMD(PMD_SX, ("%s() CPU->cpu_id %d\n", str, CPU->cpu_id))
992 	/*
993 	 * we allocate this only when we actually need it to save on
994 	 * kernel memory
995 	 */
996 
997 	if (wc_other_cpus == NULL) {
998 		wc_other_cpus = kmem_zalloc(ncpus * sizeof (wc_cpu_t),
999 		    KM_SLEEP);
1000 	}
1001 
1002 }
1003 
1004 void
1005 i_cpr_free_cpus(void)
1006 {
1007 	if (wc_other_cpus != NULL) {
1008 		kmem_free((void *) wc_other_cpus, ncpus * sizeof (wc_cpu_t));
1009 		wc_other_cpus = NULL;
1010 	}
1011 }
1012 
1013 /*
1014  * wrapper for acpica_ddi_save_resources()
1015  */
1016 void
1017 i_cpr_save_configuration(dev_info_t *dip)
1018 {
1019 	acpica_ddi_save_resources(dip);
1020 }
1021 
1022 /*
1023  * wrapper for acpica_ddi_restore_resources()
1024  */
1025 void
1026 i_cpr_restore_configuration(dev_info_t *dip)
1027 {
1028 	acpica_ddi_restore_resources(dip);
1029 }
1030 
1031 static int
1032 wait_for_set(cpuset_t *set, int who)
1033 {
1034 	int delays;
1035 	char *str = "wait_for_set";
1036 
1037 	for (delays = 0; !CPU_IN_SET(*set, who); delays++) {
1038 		if (delays == 500) {
1039 			/*
1040 			 * After five seconds, things are probably
1041 			 * looking a bit bleak - explain the hang.
1042 			 */
1043 			cmn_err(CE_NOTE, "cpu%d: started, "
1044 			    "but not running in the kernel yet", who);
1045 			PMD(PMD_SX, ("%s() %d cpu started "
1046 			    "but not running in the kernel yet\n",
1047 			    str, who))
1048 		} else if (delays > 2000) {
1049 			/*
1050 			 * We waited at least 20 seconds, bail ..
1051 			 */
1052 			cmn_err(CE_WARN, "cpu%d: timed out", who);
1053 			PMD(PMD_SX, ("%s() %d cpu timed out\n",
1054 			    str, who))
1055 			return (0);
1056 		}
1057 
1058 		/*
1059 		 * wait at least 10ms, then check again..
1060 		 */
1061 		drv_usecwait(10000);
1062 	}
1063 
1064 	return (1);
1065 }
1066