15295Srandyf /* 25295Srandyf * CDDL HEADER START 35295Srandyf * 45295Srandyf * The contents of this file are subject to the terms of the 55295Srandyf * Common Development and Distribution License (the "License"). 65295Srandyf * You may not use this file except in compliance with the License. 75295Srandyf * 85295Srandyf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95295Srandyf * or http://www.opensolaris.org/os/licensing. 105295Srandyf * See the License for the specific language governing permissions 115295Srandyf * and limitations under the License. 125295Srandyf * 135295Srandyf * When distributing Covered Code, include this CDDL HEADER in each 145295Srandyf * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155295Srandyf * If applicable, add the following below this CDDL HEADER, with the 165295Srandyf * fields enclosed by brackets "[]" replaced with your own identifying 175295Srandyf * information: Portions Copyright [yyyy] [name of copyright owner] 185295Srandyf * 195295Srandyf * CDDL HEADER END 205295Srandyf */ 215295Srandyf /* 22*5817Sjan * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235295Srandyf * Use is subject to license terms. 245295Srandyf */ 255295Srandyf 265295Srandyf #pragma ident "%Z%%M% %I% %E% SMI" 275295Srandyf 285295Srandyf /* 295295Srandyf * Platform specific implementation code 305295Srandyf * Currently only suspend to RAM is supported (ACPI S3) 315295Srandyf */ 325295Srandyf 335295Srandyf #define SUNDDI_IMPL 345295Srandyf 355295Srandyf #include <sys/types.h> 365295Srandyf #include <sys/promif.h> 375295Srandyf #include <sys/prom_isa.h> 385295Srandyf #include <sys/prom_plat.h> 395295Srandyf #include <sys/cpuvar.h> 405295Srandyf #include <sys/pte.h> 415295Srandyf #include <vm/hat.h> 425295Srandyf #include <vm/page.h> 435295Srandyf #include <vm/as.h> 445295Srandyf #include <sys/cpr.h> 455295Srandyf #include <sys/kmem.h> 465295Srandyf #include <sys/clock.h> 475295Srandyf #include <sys/kmem.h> 485295Srandyf #include <sys/panic.h> 495295Srandyf #include <vm/seg_kmem.h> 505295Srandyf #include <sys/cpu_module.h> 515295Srandyf #include <sys/callb.h> 525295Srandyf #include <sys/machsystm.h> 535295Srandyf #include <sys/vmsystm.h> 545295Srandyf #include <sys/systm.h> 555295Srandyf #include <sys/archsystm.h> 565295Srandyf #include <sys/stack.h> 575295Srandyf #include <sys/fs/ufs_fs.h> 585295Srandyf #include <sys/memlist.h> 595295Srandyf #include <sys/bootconf.h> 605295Srandyf #include <sys/thread.h> 615295Srandyf #include <sys/x_call.h> 625295Srandyf #include <sys/smp_impldefs.h> 635295Srandyf #include <vm/vm_dep.h> 645295Srandyf #include <sys/psm.h> 655295Srandyf #include <sys/epm.h> 665295Srandyf #include <sys/cpr_wakecode.h> 675295Srandyf #include <sys/x86_archext.h> 685295Srandyf #include <sys/reboot.h> 695295Srandyf #include <sys/acpi/acpi.h> 705295Srandyf #include <sys/acpica.h> 715295Srandyf 725295Srandyf #define AFMT "%lx" 735295Srandyf 745295Srandyf extern int flushes_require_xcalls; 755295Srandyf extern cpuset_t cpu_ready_set; 765295Srandyf 775295Srandyf #if defined(__amd64) 785295Srandyf extern void *wc_long_mode_64(void); 795295Srandyf #endif /* __amd64 */ 805295Srandyf extern int tsc_gethrtime_enable; 815295Srandyf extern void i_cpr_start_cpu(void); 825295Srandyf 835295Srandyf ushort_t cpr_mach_type = CPR_MACHTYPE_X86; 845295Srandyf void (*cpr_start_cpu_func)(void) = i_cpr_start_cpu; 855295Srandyf 865295Srandyf static wc_cpu_t *wc_other_cpus = NULL; 875295Srandyf static cpuset_t procset = 1; 885295Srandyf 895295Srandyf static void 905295Srandyf init_real_mode_platter(int cpun, uint32_t offset, uint_t cr4, wc_desctbr_t gdt); 915295Srandyf 925295Srandyf static int i_cpr_platform_alloc(psm_state_request_t *req); 935295Srandyf static void i_cpr_platform_free(psm_state_request_t *req); 945295Srandyf static int i_cpr_save_apic(psm_state_request_t *req); 955295Srandyf static int i_cpr_restore_apic(psm_state_request_t *req); 96*5817Sjan static int wait_for_set(cpuset_t *set, int who); 975295Srandyf 985295Srandyf #if defined(__amd64) 995295Srandyf static void restore_stack(wc_cpu_t *cpup); 1005295Srandyf static void save_stack(wc_cpu_t *cpup); 1015295Srandyf void (*save_stack_func)(wc_cpu_t *) = save_stack; 1025295Srandyf #endif /* __amd64 */ 1035295Srandyf 1045295Srandyf /* 1055295Srandyf * restart paused slave cpus 1065295Srandyf */ 1075295Srandyf void 1085295Srandyf i_cpr_machdep_setup(void) 1095295Srandyf { 1105295Srandyf if (ncpus > 1) { 1115295Srandyf CPR_DEBUG(CPR_DEBUG1, ("MP restarted...\n")); 1125295Srandyf mutex_enter(&cpu_lock); 1135295Srandyf start_cpus(); 1145295Srandyf mutex_exit(&cpu_lock); 1155295Srandyf } 1165295Srandyf } 1175295Srandyf 1185295Srandyf 1195295Srandyf /* 1205295Srandyf * Stop all interrupt activities in the system 1215295Srandyf */ 1225295Srandyf void 1235295Srandyf i_cpr_stop_intr(void) 1245295Srandyf { 1255295Srandyf (void) spl7(); 1265295Srandyf } 1275295Srandyf 1285295Srandyf /* 1295295Srandyf * Set machine up to take interrupts 1305295Srandyf */ 1315295Srandyf void 1325295Srandyf i_cpr_enable_intr(void) 1335295Srandyf { 1345295Srandyf (void) spl0(); 1355295Srandyf } 1365295Srandyf 1375295Srandyf /* 1385295Srandyf * Save miscellaneous information which needs to be written to the 1395295Srandyf * state file. This information is required to re-initialize 1405295Srandyf * kernel/prom handshaking. 1415295Srandyf */ 1425295Srandyf void 1435295Srandyf i_cpr_save_machdep_info(void) 1445295Srandyf { 1455295Srandyf int notcalled = 0; 1465295Srandyf ASSERT(notcalled); 1475295Srandyf } 1485295Srandyf 1495295Srandyf 1505295Srandyf void 1515295Srandyf i_cpr_set_tbr(void) 1525295Srandyf { 1535295Srandyf } 1545295Srandyf 1555295Srandyf 1565295Srandyf processorid_t 1575295Srandyf i_cpr_bootcpuid(void) 1585295Srandyf { 1595295Srandyf return (0); 1605295Srandyf } 1615295Srandyf 1625295Srandyf /* 1635295Srandyf * cpu0 should contain bootcpu info 1645295Srandyf */ 1655295Srandyf cpu_t * 1665295Srandyf i_cpr_bootcpu(void) 1675295Srandyf { 1685295Srandyf ASSERT(MUTEX_HELD(&cpu_lock)); 1695295Srandyf 1705295Srandyf return (cpu_get(i_cpr_bootcpuid())); 1715295Srandyf } 1725295Srandyf 1735295Srandyf /* 1745295Srandyf * Save context for the specified CPU 1755295Srandyf */ 1765295Srandyf void * 1775295Srandyf i_cpr_save_context(void *arg) 1785295Srandyf { 1795295Srandyf long index = (long)arg; 1805295Srandyf psm_state_request_t *papic_state; 1815295Srandyf int resuming; 1825295Srandyf int ret; 1835295Srandyf 1845295Srandyf PMD(PMD_SX, ("i_cpr_save_context() index = %ld\n", index)) 1855295Srandyf 1865295Srandyf ASSERT(index < NCPU); 1875295Srandyf 1885295Srandyf papic_state = &(wc_other_cpus + index)->wc_apic_state; 1895295Srandyf 1905295Srandyf ret = i_cpr_platform_alloc(papic_state); 1915295Srandyf ASSERT(ret == 0); 1925295Srandyf 1935295Srandyf ret = i_cpr_save_apic(papic_state); 1945295Srandyf ASSERT(ret == 0); 1955295Srandyf 1965295Srandyf /* 1975295Srandyf * wc_save_context returns twice, once when susending and 1985295Srandyf * once when resuming, wc_save_context() returns 0 when 1995295Srandyf * suspending and non-zero upon resume 2005295Srandyf */ 2015295Srandyf resuming = (wc_save_context(wc_other_cpus + index) == 0); 2025295Srandyf 2035295Srandyf PMD(PMD_SX, ("i_cpr_save_context: wc_save_context returns %d\n", 2045295Srandyf resuming)) 2055295Srandyf 2065295Srandyf /* 2075295Srandyf * do NOT call any functions after this point, because doing so 2085295Srandyf * will modify the stack that we are running on 2095295Srandyf */ 2105295Srandyf 2115295Srandyf if (resuming) { 2125295Srandyf 2135295Srandyf ret = i_cpr_restore_apic(papic_state); 2145295Srandyf ASSERT(ret == 0); 2155295Srandyf 2165295Srandyf i_cpr_platform_free(papic_state); 2175295Srandyf 2185295Srandyf /* 2195295Srandyf * Setting the bit in cpu_ready_set must be the last operation 2205295Srandyf * in processor initialization; the boot CPU will continue to 2215295Srandyf * boot once it sees this bit set for all active CPUs. 2225295Srandyf */ 2235295Srandyf CPUSET_ATOMIC_ADD(cpu_ready_set, CPU->cpu_id); 2245295Srandyf 2255295Srandyf PMD(PMD_SX, 2265295Srandyf ("cpu_release() cpu_ready_set = %lx, CPU->cpu_id = %d\n", 2275295Srandyf cpu_ready_set, CPU->cpu_id)) 2285295Srandyf } 2295295Srandyf return (NULL); 2305295Srandyf } 2315295Srandyf 2325295Srandyf static ushort_t *warm_reset_vector = NULL; 2335295Srandyf 2345295Srandyf static ushort_t * 2355295Srandyf map_warm_reset_vector() 2365295Srandyf { 2375295Srandyf /*LINTED*/ 2385295Srandyf if (!(warm_reset_vector = (ushort_t *)psm_map_phys(WARM_RESET_VECTOR, 2395295Srandyf sizeof (ushort_t *), PROT_READ|PROT_WRITE))) 2405295Srandyf return (NULL); 2415295Srandyf 2425295Srandyf /* 2435295Srandyf * setup secondary cpu bios boot up vector 2445295Srandyf */ 2455295Srandyf *warm_reset_vector = (ushort_t)((caddr_t) 2465295Srandyf /*LINTED*/ 2475295Srandyf ((struct rm_platter *)rm_platter_va)->rm_code - rm_platter_va 2485295Srandyf + ((ulong_t)rm_platter_va & 0xf)); 2495295Srandyf warm_reset_vector++; 2505295Srandyf *warm_reset_vector = (ushort_t)(rm_platter_pa >> 4); 2515295Srandyf 2525295Srandyf --warm_reset_vector; 2535295Srandyf return (warm_reset_vector); 2545295Srandyf } 2555295Srandyf 2565295Srandyf void 2575295Srandyf i_cpr_pre_resume_cpus() 2585295Srandyf { 2595295Srandyf /* 2605295Srandyf * this is a cut down version of start_other_cpus() 2615295Srandyf * just do the initialization to wake the other cpus 2625295Srandyf */ 2635295Srandyf unsigned who; 264*5817Sjan int boot_cpuid = i_cpr_bootcpuid(); 2655295Srandyf uint32_t code_length = 0; 2665295Srandyf caddr_t wakevirt = rm_platter_va; 2675295Srandyf /*LINTED*/ 2685295Srandyf wakecode_t *wp = (wakecode_t *)wakevirt; 2695295Srandyf char *str = "i_cpr_pre_resume_cpus"; 2705295Srandyf extern int get_tsc_ready(); 2715295Srandyf int err; 2725295Srandyf 2735295Srandyf /*LINTED*/ 2745295Srandyf rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va; 2755295Srandyf 2765295Srandyf /* 2775295Srandyf * Copy the real mode code at "real_mode_start" to the 2785295Srandyf * page at rm_platter_va. 2795295Srandyf */ 2805295Srandyf warm_reset_vector = map_warm_reset_vector(); 2815295Srandyf if (warm_reset_vector == NULL) { 2825295Srandyf PMD(PMD_SX, ("i_cpr_pre_resume_cpus() returning #2\n")) 2835295Srandyf return; 2845295Srandyf } 2855295Srandyf 2865295Srandyf flushes_require_xcalls = 1; 2875295Srandyf 2885295Srandyf /* 2895295Srandyf * We lock our affinity to the master CPU to ensure that all slave CPUs 2905295Srandyf * do their TSC syncs with the same CPU. 2915295Srandyf */ 2925295Srandyf 2935295Srandyf affinity_set(CPU_CURRENT); 2945295Srandyf 295*5817Sjan /* 296*5817Sjan * mark the boot cpu as being ready, since we are running on that cpu 297*5817Sjan */ 298*5817Sjan CPUSET_ONLY(cpu_ready_set, boot_cpuid); 2995295Srandyf 3005295Srandyf for (who = 0; who < ncpus; who++) { 3015295Srandyf 3025295Srandyf wc_cpu_t *cpup = wc_other_cpus + who; 3035295Srandyf wc_desctbr_t gdt; 3045295Srandyf 305*5817Sjan if (who == boot_cpuid) 3065295Srandyf continue; 3075295Srandyf 3085295Srandyf if (!CPU_IN_SET(mp_cpus, who)) 3095295Srandyf continue; 3105295Srandyf 3115295Srandyf PMD(PMD_SX, ("%s() waking up %d cpu\n", str, who)) 3125295Srandyf 3135295Srandyf bcopy(cpup, &(wp->wc_cpu), sizeof (wc_cpu_t)); 3145295Srandyf 3155295Srandyf gdt.base = cpup->wc_gdt_base; 3165295Srandyf gdt.limit = cpup->wc_gdt_limit; 3175295Srandyf 3185295Srandyf #if defined(__amd64) 3195295Srandyf code_length = (uint32_t)wc_long_mode_64 - (uint32_t)wc_rm_start; 3205295Srandyf #else 3215295Srandyf code_length = 0; 3225295Srandyf #endif 3235295Srandyf 3245295Srandyf init_real_mode_platter(who, code_length, cpup->wc_cr4, gdt); 3255295Srandyf 3265295Srandyf if ((err = mach_cpuid_start(who, rm_platter_va)) != 0) { 3275295Srandyf cmn_err(CE_WARN, "cpu%d: failed to start during " 3285295Srandyf "suspend/resume error %d", who, err); 3295295Srandyf continue; 3305295Srandyf } 3315295Srandyf 3325295Srandyf PMD(PMD_SX, ("%s() #1 waiting for procset 0x%lx\n", str, 3335295Srandyf (ulong_t)procset)) 3345295Srandyf 335*5817Sjan if (!wait_for_set(&procset, who)) 336*5817Sjan continue; 3375295Srandyf 3385295Srandyf PMD(PMD_SX, ("%s() %d cpu started\n", str, who)) 3395295Srandyf 340*5817Sjan PMD(PMD_SX, ("%s() tsc_ready = %d\n", str, get_tsc_ready())) 3415295Srandyf 3425295Srandyf if (tsc_gethrtime_enable) { 3435295Srandyf PMD(PMD_SX, ("%s() calling tsc_sync_master\n", str)) 3445295Srandyf tsc_sync_master(who); 3455295Srandyf } 3465295Srandyf 3475295Srandyf PMD(PMD_SX, ("%s() waiting for cpu_ready_set %ld\n", str, 3485295Srandyf cpu_ready_set)) 3495295Srandyf /* 3505295Srandyf * Wait for cpu to declare that it is ready, we want the 3515295Srandyf * cpus to start serially instead of in parallel, so that 3525295Srandyf * they do not contend with each other in wc_rm_start() 3535295Srandyf */ 354*5817Sjan if (!wait_for_set(&cpu_ready_set, who)) 355*5817Sjan continue; 3565295Srandyf 3575295Srandyf /* 3585295Srandyf * do not need to re-initialize dtrace using dtrace_cpu_init 3595295Srandyf * function 3605295Srandyf */ 3615295Srandyf PMD(PMD_SX, ("%s() cpu %d now ready\n", str, who)) 3625295Srandyf } 3635295Srandyf 3645295Srandyf affinity_clear(); 3655295Srandyf 3665295Srandyf PMD(PMD_SX, ("%s() all cpus now ready\n", str)) 367*5817Sjan 3685295Srandyf } 3695295Srandyf 3705295Srandyf static void 3715295Srandyf unmap_warm_reset_vector(ushort_t *warm_reset_vector) 3725295Srandyf { 3735295Srandyf psm_unmap_phys((caddr_t)warm_reset_vector, sizeof (ushort_t *)); 3745295Srandyf } 3755295Srandyf 3765295Srandyf /* 3775295Srandyf * We need to setup a 1:1 (virtual to physical) mapping for the 3785295Srandyf * page containing the wakeup code. 3795295Srandyf */ 3805295Srandyf static struct as *save_as; /* when switching to kas */ 3815295Srandyf 3825295Srandyf static void 3835295Srandyf unmap_wakeaddr_1to1(uint64_t wakephys) 3845295Srandyf { 3855295Srandyf uintptr_t wp = (uintptr_t)wakephys; 3865295Srandyf hat_setup(save_as->a_hat, 0); /* switch back from kernel hat */ 3875295Srandyf hat_unload(kas.a_hat, (caddr_t)wp, PAGESIZE, HAT_UNLOAD); 3885295Srandyf } 3895295Srandyf 3905295Srandyf void 3915295Srandyf i_cpr_post_resume_cpus() 3925295Srandyf { 3935295Srandyf uint64_t wakephys = rm_platter_pa; 3945295Srandyf 3955295Srandyf if (warm_reset_vector != NULL) 3965295Srandyf unmap_warm_reset_vector(warm_reset_vector); 3975295Srandyf 3985295Srandyf hat_unload(kas.a_hat, (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE, 3995295Srandyf HAT_UNLOAD); 4005295Srandyf 4015295Srandyf /* 4025295Srandyf * cmi_post_mpstartup() is only required upon boot not upon 4035295Srandyf * resume from RAM 4045295Srandyf */ 4055295Srandyf 4065295Srandyf PT(PT_UNDO1to1); 4075295Srandyf /* Tear down 1:1 mapping for wakeup code */ 4085295Srandyf unmap_wakeaddr_1to1(wakephys); 4095295Srandyf } 4105295Srandyf 4115295Srandyf /* ARGSUSED */ 4125295Srandyf void 4135295Srandyf i_cpr_handle_xc(int flag) 4145295Srandyf { 4155295Srandyf } 4165295Srandyf 4175295Srandyf int 4185295Srandyf i_cpr_reusable_supported(void) 4195295Srandyf { 4205295Srandyf return (0); 4215295Srandyf } 4225295Srandyf static void 4235295Srandyf map_wakeaddr_1to1(uint64_t wakephys) 4245295Srandyf { 4255295Srandyf uintptr_t wp = (uintptr_t)wakephys; 4265295Srandyf hat_devload(kas.a_hat, (caddr_t)wp, PAGESIZE, btop(wakephys), 4275295Srandyf (PROT_READ|PROT_WRITE|PROT_EXEC|HAT_STORECACHING_OK|HAT_NOSYNC), 4285295Srandyf HAT_LOAD); 4295295Srandyf save_as = curthread->t_procp->p_as; 4305295Srandyf hat_setup(kas.a_hat, 0); /* switch to kernel-only hat */ 4315295Srandyf } 4325295Srandyf 4335295Srandyf 4345295Srandyf void 4355295Srandyf prt_other_cpus() 4365295Srandyf { 4375295Srandyf int who; 4385295Srandyf 4395295Srandyf if (ncpus == 1) { 4405295Srandyf PMD(PMD_SX, ("prt_other_cpus() other cpu table empty for " 4415295Srandyf "uniprocessor machine\n")) 4425295Srandyf return; 4435295Srandyf } 4445295Srandyf 4455295Srandyf for (who = 0; who < ncpus; who++) { 4465295Srandyf 4475295Srandyf wc_cpu_t *cpup = wc_other_cpus + who; 4485295Srandyf 4495295Srandyf PMD(PMD_SX, ("prt_other_cpus() who = %d, gdt=%p:%x, " 4505295Srandyf "idt=%p:%x, ldt=%lx, tr=%lx, kgsbase=" 4515295Srandyf AFMT ", sp=%lx\n", who, 4525295Srandyf (void *)cpup->wc_gdt_base, cpup->wc_gdt_limit, 4535295Srandyf (void *)cpup->wc_idt_base, cpup->wc_idt_limit, 4545295Srandyf (long)cpup->wc_ldt, (long)cpup->wc_tr, 4555295Srandyf (long)cpup->wc_kgsbase, (long)cpup->wc_rsp)) 4565295Srandyf } 4575295Srandyf } 4585295Srandyf 4595295Srandyf /* 4605295Srandyf * Power down the system. 4615295Srandyf */ 4625295Srandyf int 4635295Srandyf i_cpr_power_down(int sleeptype) 4645295Srandyf { 4655295Srandyf caddr_t wakevirt = rm_platter_va; 4665295Srandyf uint64_t wakephys = rm_platter_pa; 4675295Srandyf uint_t saved_intr; 4685295Srandyf uint32_t code_length = 0; 4695295Srandyf wc_desctbr_t gdt; 4705295Srandyf /*LINTED*/ 4715295Srandyf wakecode_t *wp = (wakecode_t *)wakevirt; 4725295Srandyf /*LINTED*/ 4735295Srandyf rm_platter_t *wcpp = (rm_platter_t *)wakevirt; 4745295Srandyf wc_cpu_t *cpup = &(wp->wc_cpu); 4755295Srandyf dev_info_t *ppm; 4765295Srandyf int ret = 0; 4775295Srandyf power_req_t power_req; 4785295Srandyf char *str = "i_cpr_power_down"; 4795295Srandyf #if defined(__amd64) 4805295Srandyf /*LINTED*/ 4815295Srandyf rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va; 4825295Srandyf #endif 4835295Srandyf extern int cpr_suspend_succeeded; 4845295Srandyf extern void kernel_wc_code(); 4855295Srandyf extern ulong_t intr_clear(void); 4865295Srandyf extern void intr_restore(ulong_t); 4875295Srandyf 4885295Srandyf ASSERT(sleeptype == CPR_TORAM); 4895295Srandyf ASSERT(CPU->cpu_id == 0); 4905295Srandyf 4915295Srandyf if ((ppm = PPM(ddi_root_node())) == NULL) { 4925295Srandyf PMD(PMD_SX, ("%s: root node not claimed\n", str)) 4935295Srandyf return (ENOTTY); 4945295Srandyf } 4955295Srandyf 4965295Srandyf PMD(PMD_SX, ("Entering %s()\n", str)) 4975295Srandyf 4985295Srandyf PT(PT_IC); 4995295Srandyf saved_intr = intr_clear(); 5005295Srandyf 5015295Srandyf PT(PT_1to1); 5025295Srandyf /* Setup 1:1 mapping for wakeup code */ 5035295Srandyf map_wakeaddr_1to1(wakephys); 5045295Srandyf 5055295Srandyf PMD(PMD_SX, ("ncpus=%d\n", ncpus)) 5065295Srandyf 5075295Srandyf PMD(PMD_SX, ("wc_rm_end - wc_rm_start=%lx WC_CODESIZE=%x\n", 5085295Srandyf ((size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)), WC_CODESIZE)) 5095295Srandyf 5105295Srandyf PMD(PMD_SX, ("wakevirt=%p, wakephys=%x\n", 5115295Srandyf (void *)wakevirt, (uint_t)wakephys)) 5125295Srandyf 5135295Srandyf ASSERT(((size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)) < 5145295Srandyf WC_CODESIZE); 5155295Srandyf 5165295Srandyf bzero(wakevirt, PAGESIZE); 5175295Srandyf 5185295Srandyf /* Copy code to rm_platter */ 5195295Srandyf bcopy((caddr_t)wc_rm_start, wakevirt, 5205295Srandyf (size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)); 5215295Srandyf 5225295Srandyf prt_other_cpus(); 5235295Srandyf 5245295Srandyf #if defined(__amd64) 5255295Srandyf 5265295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n", 5275295Srandyf (ulong_t)real_mode_platter->rm_cr4, (ulong_t)getcr4())) 5285295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n", 5295295Srandyf (ulong_t)real_mode_platter->rm_pdbr, getcr3())) 5305295Srandyf 5315295Srandyf real_mode_platter->rm_cr4 = getcr4(); 5325295Srandyf real_mode_platter->rm_pdbr = getcr3(); 5335295Srandyf 5345295Srandyf rmp_gdt_init(real_mode_platter); 5355295Srandyf 5365295Srandyf /* 5375295Srandyf * Since the CPU needs to jump to protected mode using an identity 5385295Srandyf * mapped address, we need to calculate it here. 5395295Srandyf */ 5405295Srandyf real_mode_platter->rm_longmode64_addr = rm_platter_pa + 5415295Srandyf ((uint32_t)wc_long_mode_64 - (uint32_t)wc_rm_start); 5425295Srandyf 5435295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n", 5445295Srandyf (ulong_t)real_mode_platter->rm_cr4, getcr4())) 5455295Srandyf 5465295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n", 5475295Srandyf (ulong_t)real_mode_platter->rm_pdbr, getcr3())) 5485295Srandyf 5495295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_longmode64_addr=%lx\n", 5505295Srandyf (ulong_t)real_mode_platter->rm_longmode64_addr)) 5515295Srandyf 5525295Srandyf #endif 5535295Srandyf 5545295Srandyf PMD(PMD_SX, ("mp_cpus=%lx\n", (ulong_t)mp_cpus)) 5555295Srandyf 5565295Srandyf PT(PT_SC); 5575295Srandyf if (wc_save_context(cpup)) { 5585295Srandyf 5595295Srandyf ret = i_cpr_platform_alloc(&(wc_other_cpus->wc_apic_state)); 5605295Srandyf if (ret != 0) 5615295Srandyf return (ret); 5625295Srandyf 5635295Srandyf ret = i_cpr_save_apic(&(wc_other_cpus->wc_apic_state)); 5645295Srandyf PMD(PMD_SX, ("%s: i_cpr_save_apic() returned %d\n", str, ret)) 5655295Srandyf if (ret != 0) 5665295Srandyf return (ret); 5675295Srandyf 5685295Srandyf PMD(PMD_SX, ("wakephys=%x, kernel_wc_code=%p\n", 5695295Srandyf (uint_t)wakephys, (void *)&kernel_wc_code)) 5705295Srandyf PMD(PMD_SX, ("virtaddr=%lx, retaddr=%lx\n", 5715295Srandyf (long)cpup->wc_virtaddr, (long)cpup->wc_retaddr)) 5725295Srandyf PMD(PMD_SX, ("ebx=%x, edi=%x, esi=%x, ebp=%x, esp=%x\n", 5735295Srandyf cpup->wc_ebx, cpup->wc_edi, cpup->wc_esi, cpup->wc_ebp, 5745295Srandyf cpup->wc_esp)) 5755295Srandyf PMD(PMD_SX, ("cr0=%lx, cr3=%lx, cr4=%lx\n", 5765295Srandyf (long)cpup->wc_cr0, (long)cpup->wc_cr3, 5775295Srandyf (long)cpup->wc_cr4)) 5785295Srandyf PMD(PMD_SX, ("cs=%x, ds=%x, es=%x, ss=%x, fs=%lx, gs=%lx, " 5795295Srandyf "flgs=%lx\n", cpup->wc_cs, cpup->wc_ds, cpup->wc_es, 5805295Srandyf cpup->wc_ss, (long)cpup->wc_fs, (long)cpup->wc_gs, 5815295Srandyf (long)cpup->wc_eflags)) 5825295Srandyf 5835295Srandyf PMD(PMD_SX, ("gdt=%p:%x, idt=%p:%x, ldt=%lx, tr=%lx, " 5845295Srandyf "kgbase=%lx\n", (void *)cpup->wc_gdt_base, 5855295Srandyf cpup->wc_gdt_limit, (void *)cpup->wc_idt_base, 5865295Srandyf cpup->wc_idt_limit, (long)cpup->wc_ldt, 5875295Srandyf (long)cpup->wc_tr, (long)cpup->wc_kgsbase)) 5885295Srandyf 5895295Srandyf gdt.base = cpup->wc_gdt_base; 5905295Srandyf gdt.limit = cpup->wc_gdt_limit; 5915295Srandyf 5925295Srandyf #if defined(__amd64) 5935295Srandyf code_length = (uint32_t)wc_long_mode_64 - 5945295Srandyf (uint32_t)wc_rm_start; 5955295Srandyf #else 5965295Srandyf code_length = 0; 5975295Srandyf #endif 5985295Srandyf 5995295Srandyf init_real_mode_platter(0, code_length, cpup->wc_cr4, gdt); 6005295Srandyf 6015295Srandyf #if defined(__amd64) 6025295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n", 6035295Srandyf (ulong_t)wcpp->rm_cr4, getcr4())) 6045295Srandyf 6055295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n", 6065295Srandyf (ulong_t)wcpp->rm_pdbr, getcr3())) 6075295Srandyf 6085295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_longmode64_addr=%lx\n", 6095295Srandyf (ulong_t)wcpp->rm_longmode64_addr)) 6105295Srandyf 6115295Srandyf PMD(PMD_SX, 6125295Srandyf ("real_mode_platter->rm_temp_gdt[TEMPGDT_KCODE64]=%lx\n", 6135295Srandyf (ulong_t)wcpp->rm_temp_gdt[TEMPGDT_KCODE64])) 6145295Srandyf #endif 6155295Srandyf 6165295Srandyf PMD(PMD_SX, ("gdt=%p:%x, idt=%p:%x, ldt=%lx, tr=%lx, " 6175295Srandyf "kgsbase=%lx\n", (void *)wcpp->rm_gdt_base, 6185295Srandyf wcpp->rm_gdt_lim, (void *)wcpp->rm_idt_base, 6195295Srandyf wcpp->rm_idt_lim, (long)cpup->wc_ldt, (long)cpup->wc_tr, 6205295Srandyf (long)cpup->wc_kgsbase)) 6215295Srandyf 6225295Srandyf power_req.request_type = PMR_PPM_ENTER_SX; 6235295Srandyf power_req.req.ppm_power_enter_sx_req.sx_state = S3; 6245295Srandyf power_req.req.ppm_power_enter_sx_req.test_point = 6255295Srandyf cpr_test_point; 6265295Srandyf power_req.req.ppm_power_enter_sx_req.wakephys = wakephys; 6275295Srandyf 6285295Srandyf PMD(PMD_SX, ("%s: pm_ctlops PMR_PPM_ENTER_SX\n", str)) 6295295Srandyf PT(PT_PPMCTLOP); 6305295Srandyf (void) pm_ctlops(ppm, ddi_root_node(), DDI_CTLOPS_POWER, 6315295Srandyf &power_req, &ret); 6325295Srandyf PMD(PMD_SX, ("%s: returns %d\n", str, ret)) 6335295Srandyf 6345295Srandyf /* 6355295Srandyf * If it works, we get control back to the else branch below 6365295Srandyf * If we get control back here, it didn't work. 6375295Srandyf * XXX return EINVAL here? 6385295Srandyf */ 6395295Srandyf 6405295Srandyf unmap_wakeaddr_1to1(wakephys); 6415295Srandyf intr_restore(saved_intr); 6425295Srandyf 6435295Srandyf return (ret); 6445295Srandyf } else { 6455295Srandyf cpr_suspend_succeeded = 1; 6465295Srandyf 6475295Srandyf power_req.request_type = PMR_PPM_EXIT_SX; 6485295Srandyf power_req.req.ppm_power_enter_sx_req.sx_state = S3; 6495295Srandyf 6505295Srandyf PMD(PMD_SX, ("%s: pm_ctlops PMR_PPM_EXIT_SX\n", str)) 6515295Srandyf PT(PT_PPMCTLOP); 6525295Srandyf (void) pm_ctlops(ppm, ddi_root_node(), DDI_CTLOPS_POWER, 6535295Srandyf &power_req, &ret); 6545295Srandyf PMD(PMD_SX, ("%s: returns %d\n", str, ret)) 6555295Srandyf 6565295Srandyf ret = i_cpr_restore_apic(&(wc_other_cpus->wc_apic_state)); 6575295Srandyf /* 6585295Srandyf * the restore should never fail, if the saved suceeded 6595295Srandyf */ 6605295Srandyf ASSERT(ret == 0); 6615295Srandyf 6625295Srandyf i_cpr_platform_free(&(wc_other_cpus->wc_apic_state)); 6635295Srandyf 6645295Srandyf PT(PT_INTRRESTORE); 6655295Srandyf intr_restore(saved_intr); 6665295Srandyf PT(PT_CPU); 6675295Srandyf 6685295Srandyf return (ret); 6695295Srandyf } 6705295Srandyf } 6715295Srandyf 6725295Srandyf /* 6735295Srandyf * Stop all other cpu's before halting or rebooting. We pause the cpu's 6745295Srandyf * instead of sending a cross call. 6755295Srandyf * Stolen from sun4/os/mp_states.c 6765295Srandyf */ 6775295Srandyf 6785295Srandyf static int cpu_are_paused; /* sic */ 6795295Srandyf 6805295Srandyf void 6815295Srandyf i_cpr_stop_other_cpus(void) 6825295Srandyf { 6835295Srandyf mutex_enter(&cpu_lock); 6845295Srandyf if (cpu_are_paused) { 6855295Srandyf mutex_exit(&cpu_lock); 6865295Srandyf return; 6875295Srandyf } 6885295Srandyf pause_cpus(NULL); 6895295Srandyf cpu_are_paused = 1; 6905295Srandyf 6915295Srandyf mutex_exit(&cpu_lock); 6925295Srandyf } 6935295Srandyf 6945295Srandyf int 6955295Srandyf i_cpr_is_supported(int sleeptype) 6965295Srandyf { 6975295Srandyf extern int cpr_supported_override; 6985295Srandyf extern int cpr_platform_enable; 6995295Srandyf extern int pm_S3_enabled; 7005295Srandyf 7015295Srandyf if (sleeptype != CPR_TORAM) 7025295Srandyf return (0); 7035295Srandyf 7045295Srandyf /* 7055295Srandyf * The next statement tests if a specific platform has turned off 7065295Srandyf * cpr support. 7075295Srandyf */ 7085295Srandyf if (cpr_supported_override) 7095295Srandyf return (0); 7105295Srandyf 7115295Srandyf /* 7125295Srandyf * If a platform has specifically turned on cpr support ... 7135295Srandyf */ 7145295Srandyf if (cpr_platform_enable) 7155295Srandyf return (1); 7165295Srandyf 7175295Srandyf return (pm_S3_enabled); 7185295Srandyf } 7195295Srandyf 7205295Srandyf void 7215295Srandyf i_cpr_bitmap_cleanup(void) 7225295Srandyf { 7235295Srandyf } 7245295Srandyf 7255295Srandyf void 7265295Srandyf i_cpr_free_memory_resources(void) 7275295Srandyf { 7285295Srandyf } 7295295Srandyf 7305295Srandyf /* 7315295Srandyf * Needed only for S3 so far 7325295Srandyf */ 7335295Srandyf static int 7345295Srandyf i_cpr_platform_alloc(psm_state_request_t *req) 7355295Srandyf { 7365295Srandyf char *str = "i_cpr_platform_alloc"; 7375295Srandyf 7385295Srandyf PMD(PMD_SX, ("cpu = %d, %s(%p) \n", CPU->cpu_id, str, (void *)req)) 7395295Srandyf 7405295Srandyf if (ncpus == 1) { 7415295Srandyf PMD(PMD_SX, ("%s() : ncpus == 1\n", str)) 7425295Srandyf return (0); 7435295Srandyf } 7445295Srandyf 7455295Srandyf req->psr_cmd = PSM_STATE_ALLOC; 7465295Srandyf return ((*psm_state)(req)); 7475295Srandyf } 7485295Srandyf 7495295Srandyf /* 7505295Srandyf * Needed only for S3 so far 7515295Srandyf */ 7525295Srandyf static void 7535295Srandyf i_cpr_platform_free(psm_state_request_t *req) 7545295Srandyf { 7555295Srandyf char *str = "i_cpr_platform_free"; 7565295Srandyf 7575295Srandyf PMD(PMD_SX, ("cpu = %d, %s(%p) \n", CPU->cpu_id, str, (void *)req)) 7585295Srandyf 7595295Srandyf if (ncpus == 1) { 7605295Srandyf PMD(PMD_SX, ("%s() : ncpus == 1\n", str)) 7615295Srandyf } 7625295Srandyf 7635295Srandyf req->psr_cmd = PSM_STATE_FREE; 7645295Srandyf (void) (*psm_state)(req); 7655295Srandyf } 7665295Srandyf 7675295Srandyf static int 7685295Srandyf i_cpr_save_apic(psm_state_request_t *req) 7695295Srandyf { 7705295Srandyf char *str = "i_cpr_save_apic"; 7715295Srandyf 7725295Srandyf if (ncpus == 1) { 7735295Srandyf PMD(PMD_SX, ("%s() : ncpus == 1\n", str)) 7745295Srandyf return (0); 7755295Srandyf } 7765295Srandyf 7775295Srandyf req->psr_cmd = PSM_STATE_SAVE; 7785295Srandyf return ((*psm_state)(req)); 7795295Srandyf } 7805295Srandyf 7815295Srandyf static int 7825295Srandyf i_cpr_restore_apic(psm_state_request_t *req) 7835295Srandyf { 7845295Srandyf char *str = "i_cpr_restore_apic"; 7855295Srandyf 7865295Srandyf if (ncpus == 1) { 7875295Srandyf PMD(PMD_SX, ("%s() : ncpus == 1\n", str)) 7885295Srandyf return (0); 7895295Srandyf } 7905295Srandyf 7915295Srandyf req->psr_cmd = PSM_STATE_RESTORE; 7925295Srandyf return ((*psm_state)(req)); 7935295Srandyf } 7945295Srandyf 7955295Srandyf 7965295Srandyf /* stop lint complaining about offset not being used in 32bit mode */ 7975295Srandyf #if !defined(__amd64) 7985295Srandyf /*ARGSUSED*/ 7995295Srandyf #endif 8005295Srandyf static void 8015295Srandyf init_real_mode_platter(int cpun, uint32_t offset, uint_t cr4, wc_desctbr_t gdt) 8025295Srandyf { 8035295Srandyf /*LINTED*/ 8045295Srandyf rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va; 8055295Srandyf 8065295Srandyf /* 8075295Srandyf * Fill up the real mode platter to make it easy for real mode code to 8085295Srandyf * kick it off. This area should really be one passed by boot to kernel 8095295Srandyf * and guaranteed to be below 1MB and aligned to 16 bytes. Should also 8105295Srandyf * have identical physical and virtual address in paged mode. 8115295Srandyf */ 8125295Srandyf 8135295Srandyf real_mode_platter->rm_pdbr = getcr3(); 8145295Srandyf real_mode_platter->rm_cpu = cpun; 8155295Srandyf real_mode_platter->rm_cr4 = cr4; 8165295Srandyf 8175295Srandyf real_mode_platter->rm_gdt_base = gdt.base; 8185295Srandyf real_mode_platter->rm_gdt_lim = gdt.limit; 8195295Srandyf 8205295Srandyf #if defined(__amd64) 8215295Srandyf real_mode_platter->rm_x86feature = x86_feature; 8225295Srandyf 8235295Srandyf if (getcr3() > 0xffffffffUL) 8245295Srandyf panic("Cannot initialize CPUs; kernel's 64-bit page tables\n" 8255295Srandyf "located above 4G in physical memory (@ 0x%llx).", 8265295Srandyf (unsigned long long)getcr3()); 8275295Srandyf 8285295Srandyf /* 8295295Srandyf * Setup pseudo-descriptors for temporary GDT and IDT for use ONLY 8305295Srandyf * by code in real_mode_start(): 8315295Srandyf * 8325295Srandyf * GDT[0]: NULL selector 8335295Srandyf * GDT[1]: 64-bit CS: Long = 1, Present = 1, bits 12, 11 = 1 8345295Srandyf * 8355295Srandyf * Clear the IDT as interrupts will be off and a limit of 0 will cause 8365295Srandyf * the CPU to triple fault and reset on an NMI, seemingly as reasonable 8375295Srandyf * a course of action as any other, though it may cause the entire 8385295Srandyf * platform to reset in some cases... 8395295Srandyf */ 8405295Srandyf real_mode_platter->rm_temp_gdt[0] = 0ULL; 8415295Srandyf real_mode_platter->rm_temp_gdt[TEMPGDT_KCODE64] = 0x20980000000000ULL; 8425295Srandyf 8435295Srandyf real_mode_platter->rm_temp_gdt_lim = (ushort_t) 8445295Srandyf (sizeof (real_mode_platter->rm_temp_gdt) - 1); 8455295Srandyf real_mode_platter->rm_temp_gdt_base = rm_platter_pa + 8465295Srandyf (uint32_t)(&((rm_platter_t *)0)->rm_temp_gdt); 8475295Srandyf 8485295Srandyf real_mode_platter->rm_temp_idt_lim = 0; 8495295Srandyf real_mode_platter->rm_temp_idt_base = 0; 8505295Srandyf 8515295Srandyf /* 8525295Srandyf * Since the CPU needs to jump to protected mode using an identity 8535295Srandyf * mapped address, we need to calculate it here. 8545295Srandyf */ 8555295Srandyf real_mode_platter->rm_longmode64_addr = rm_platter_pa + offset; 8565295Srandyf #endif /* __amd64 */ 8575295Srandyf 8585295Srandyf /* return; */ 8595295Srandyf } 8605295Srandyf 8615295Srandyf void 8625295Srandyf i_cpr_start_cpu(void) 8635295Srandyf { 8645295Srandyf 8655295Srandyf struct cpu *cp = CPU; 8665295Srandyf 8675295Srandyf char *str = "i_cpr_start_cpu"; 8685295Srandyf extern void init_cpu_syscall(struct cpu *cp); 8695295Srandyf 8705295Srandyf #if defined(__amd64) 8715295Srandyf wc_cpu_t *cpup = wc_other_cpus + cp->cpu_id; 8725295Srandyf #endif /* __amd64 */ 8735295Srandyf 8745295Srandyf PMD(PMD_SX, ("%s() called\n", str)) 8755295Srandyf 8765295Srandyf PMD(PMD_SX, ("%s() #0 cp->cpu_base_spl %d\n", str, 8775295Srandyf cp->cpu_base_spl)) 8785295Srandyf 8795295Srandyf mutex_enter(&cpu_lock); 8805295Srandyf if (cp == i_cpr_bootcpu()) { 8815295Srandyf mutex_exit(&cpu_lock); 8825295Srandyf PMD(PMD_SX, 8835295Srandyf ("%s() called on bootcpu nothing to do!\n", str)) 8845295Srandyf return; 8855295Srandyf } 8865295Srandyf mutex_exit(&cpu_lock); 8875295Srandyf 8885295Srandyf /* 8895295Srandyf * We need to Sync PAT with cpu0's PAT. We have to do 8905295Srandyf * this with interrupts disabled. 8915295Srandyf */ 8925295Srandyf if (x86_feature & X86_PAT) 8935295Srandyf pat_sync(); 8945295Srandyf 8955295Srandyf /* 8965295Srandyf * Initialize this CPU's syscall handlers 8975295Srandyf */ 8985295Srandyf init_cpu_syscall(cp); 8995295Srandyf 9005295Srandyf PMD(PMD_SX, ("%s() #1 cp->cpu_base_spl %d\n", str, cp->cpu_base_spl)) 9015295Srandyf 9025295Srandyf /* 9035295Srandyf * Do not need to call cpuid_pass2(), cpuid_pass3(), cpuid_pass4() or 9045295Srandyf * init_cpu_info(), since the work that they do is only needed to 9055295Srandyf * be done once at boot time 9065295Srandyf */ 9075295Srandyf 9085295Srandyf 9095295Srandyf mutex_enter(&cpu_lock); 9105295Srandyf 9115295Srandyf #if defined(__amd64) 9125295Srandyf restore_stack(cpup); 9135295Srandyf #endif /* __amd64 */ 9145295Srandyf 9155295Srandyf CPUSET_ADD(procset, cp->cpu_id); 9165295Srandyf mutex_exit(&cpu_lock); 9175295Srandyf 9185295Srandyf PMD(PMD_SX, ("%s() #2 cp->cpu_base_spl %d\n", str, 9195295Srandyf cp->cpu_base_spl)) 9205295Srandyf 9215295Srandyf /* XXX remove before integration */ 9225295Srandyf PMD(PMD_SX, ("%s() procset 0x%lx\n", str, (ulong_t)procset)) 9235295Srandyf 9245295Srandyf if (tsc_gethrtime_enable) { 9255295Srandyf PMD(PMD_SX, ("%s() calling tsc_sync_slave\n", str)) 9265295Srandyf tsc_sync_slave(); 9275295Srandyf } 9285295Srandyf 9295295Srandyf PMD(PMD_SX, ("%s() cp->cpu_id %d, cp->cpu_intr_actv %d\n", str, 9305295Srandyf cp->cpu_id, cp->cpu_intr_actv)) 9315295Srandyf PMD(PMD_SX, ("%s() #3 cp->cpu_base_spl %d\n", str, 9325295Srandyf cp->cpu_base_spl)) 9335295Srandyf 9345295Srandyf (void) spl0(); /* enable interrupts */ 9355295Srandyf 9365295Srandyf PMD(PMD_SX, ("%s() #4 cp->cpu_base_spl %d\n", str, 9375295Srandyf cp->cpu_base_spl)) 9385295Srandyf 9395295Srandyf /* 9405295Srandyf * Set up the CPU module for this CPU. This can't be done before 9415295Srandyf * this CPU is made CPU_READY, because we may (in heterogeneous systems) 9425295Srandyf * need to go load another CPU module. The act of attempting to load 9435295Srandyf * a module may trigger a cross-call, which will ASSERT unless this 9445295Srandyf * cpu is CPU_READY. 9455295Srandyf */ 9465295Srandyf 9475295Srandyf /* 9485295Srandyf * cmi already been init'd (during boot), so do not need to do it again 9495295Srandyf */ 9505295Srandyf #ifdef PM_REINITMCAONRESUME 9515295Srandyf if (x86_feature & X86_MCA) 9525295Srandyf cmi_mca_init(); 9535295Srandyf #endif 9545295Srandyf 9555295Srandyf PMD(PMD_SX, ("%s() returning\n", str)) 9565295Srandyf 9575295Srandyf /* return; */ 9585295Srandyf } 9595295Srandyf 9605295Srandyf #if defined(__amd64) 9615295Srandyf /* 9625295Srandyf * we only need to do this for amd64! 9635295Srandyf */ 9645295Srandyf 9655295Srandyf /* 9665295Srandyf * save the stack 9675295Srandyf */ 9685295Srandyf void 9695295Srandyf save_stack(wc_cpu_t *cpup) 9705295Srandyf { 9715295Srandyf char *str = "save_stack"; 9725295Srandyf caddr_t base = curthread->t_stk; 9735295Srandyf caddr_t sp = (caddr_t)cpup->wc_rsp; 9745295Srandyf 9755295Srandyf 9765295Srandyf PMD(PMD_SX, ("%s() CPU->cpu_id %d\n", str, CPU->cpu_id)) 9775295Srandyf PMD(PMD_SX, ("save_stack() curthread->t_stk = %p, sp = %p\n", 9785295Srandyf (void *)base, (void *)sp)) 9795295Srandyf 9805295Srandyf ASSERT(base > sp); 9815295Srandyf /*LINTED*/ 9825295Srandyf bcopy(sp, cpup->wc_stack, base - sp); 9835295Srandyf 9845295Srandyf } 9855295Srandyf 9865295Srandyf /* 9875295Srandyf * restore the stack 9885295Srandyf */ 9895295Srandyf static void 9905295Srandyf restore_stack(wc_cpu_t *cpup) 9915295Srandyf { 9925295Srandyf /* 9935295Srandyf * we only need to do this for amd64! 9945295Srandyf */ 9955295Srandyf 9965295Srandyf char *str = "restore_stack"; 9975295Srandyf caddr_t base = curthread->t_stk; 9985295Srandyf caddr_t sp = (caddr_t)cpup->wc_rsp; 9995295Srandyf 10005295Srandyf PMD(PMD_SX, ("%s() CPU->cpu_id %d\n", str, CPU->cpu_id)) 10015295Srandyf PMD(PMD_SX, ("%s() curthread->t_stk = %p, sp = %p\n", str, 10025295Srandyf (void *)base, (void *)sp)) 10035295Srandyf 10045295Srandyf ASSERT(base > sp); 10055295Srandyf /*LINTED*/ 10065295Srandyf bcopy(cpup->wc_stack, sp, base - sp); 10075295Srandyf 10085295Srandyf } 10095295Srandyf 10105295Srandyf #endif /* __amd64 */ 10115295Srandyf 10125295Srandyf 10135295Srandyf void 10145295Srandyf i_cpr_alloc_cpus(void) 10155295Srandyf { 10165295Srandyf char *str = "i_cpr_alloc_cpus"; 10175295Srandyf 10185295Srandyf PMD(PMD_SX, ("%s() CPU->cpu_id %d\n", str, CPU->cpu_id)) 10195295Srandyf /* 10205295Srandyf * we allocate this only when we actually need it to save on 10215295Srandyf * kernel memory 10225295Srandyf */ 10235295Srandyf 10245295Srandyf if (wc_other_cpus == NULL) { 10255295Srandyf wc_other_cpus = kmem_zalloc(ncpus * sizeof (wc_cpu_t), 10265295Srandyf KM_SLEEP); 10275295Srandyf } 10285295Srandyf 10295295Srandyf } 10305295Srandyf 10315295Srandyf void 10325295Srandyf i_cpr_free_cpus(void) 10335295Srandyf { 10345295Srandyf if (wc_other_cpus != NULL) { 10355295Srandyf kmem_free((void *) wc_other_cpus, ncpus * sizeof (wc_cpu_t)); 10365295Srandyf wc_other_cpus = NULL; 10375295Srandyf } 10385295Srandyf } 10395295Srandyf 10405295Srandyf /* 10415295Srandyf * wrapper for acpica_ddi_save_resources() 10425295Srandyf */ 10435295Srandyf void 10445295Srandyf i_cpr_save_configuration(dev_info_t *dip) 10455295Srandyf { 10465295Srandyf acpica_ddi_save_resources(dip); 10475295Srandyf } 10485295Srandyf 10495295Srandyf /* 10505295Srandyf * wrapper for acpica_ddi_restore_resources() 10515295Srandyf */ 10525295Srandyf void 10535295Srandyf i_cpr_restore_configuration(dev_info_t *dip) 10545295Srandyf { 10555295Srandyf acpica_ddi_restore_resources(dip); 10565295Srandyf } 1057*5817Sjan 1058*5817Sjan static int 1059*5817Sjan wait_for_set(cpuset_t *set, int who) 1060*5817Sjan { 1061*5817Sjan int delays; 1062*5817Sjan char *str = "wait_for_set"; 1063*5817Sjan 1064*5817Sjan for (delays = 0; !CPU_IN_SET(*set, who); delays++) { 1065*5817Sjan if (delays == 500) { 1066*5817Sjan /* 1067*5817Sjan * After five seconds, things are probably 1068*5817Sjan * looking a bit bleak - explain the hang. 1069*5817Sjan */ 1070*5817Sjan cmn_err(CE_NOTE, "cpu%d: started, " 1071*5817Sjan "but not running in the kernel yet", who); 1072*5817Sjan PMD(PMD_SX, ("%s() %d cpu started " 1073*5817Sjan "but not running in the kernel yet\n", 1074*5817Sjan str, who)) 1075*5817Sjan } else if (delays > 2000) { 1076*5817Sjan /* 1077*5817Sjan * We waited at least 20 seconds, bail .. 1078*5817Sjan */ 1079*5817Sjan cmn_err(CE_WARN, "cpu%d: timed out", who); 1080*5817Sjan PMD(PMD_SX, ("%s() %d cpu timed out\n", 1081*5817Sjan str, who)) 1082*5817Sjan return (0); 1083*5817Sjan } 1084*5817Sjan 1085*5817Sjan /* 1086*5817Sjan * wait at least 10ms, then check again.. 1087*5817Sjan */ 1088*5817Sjan drv_usecwait(10000); 1089*5817Sjan } 1090*5817Sjan 1091*5817Sjan return (1); 1092*5817Sjan } 1093