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*9989SJoseph.Townsend@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235295Srandyf * Use is subject to license terms. 245295Srandyf */ 255295Srandyf 265295Srandyf /* 275295Srandyf * Platform specific implementation code 285295Srandyf * Currently only suspend to RAM is supported (ACPI S3) 295295Srandyf */ 305295Srandyf 315295Srandyf #define SUNDDI_IMPL 325295Srandyf 335295Srandyf #include <sys/types.h> 345295Srandyf #include <sys/promif.h> 355295Srandyf #include <sys/prom_isa.h> 365295Srandyf #include <sys/prom_plat.h> 375295Srandyf #include <sys/cpuvar.h> 385295Srandyf #include <sys/pte.h> 395295Srandyf #include <vm/hat.h> 405295Srandyf #include <vm/page.h> 415295Srandyf #include <vm/as.h> 425295Srandyf #include <sys/cpr.h> 435295Srandyf #include <sys/kmem.h> 445295Srandyf #include <sys/clock.h> 455295Srandyf #include <sys/kmem.h> 465295Srandyf #include <sys/panic.h> 475295Srandyf #include <vm/seg_kmem.h> 485295Srandyf #include <sys/cpu_module.h> 495295Srandyf #include <sys/callb.h> 505295Srandyf #include <sys/machsystm.h> 515295Srandyf #include <sys/vmsystm.h> 525295Srandyf #include <sys/systm.h> 535295Srandyf #include <sys/archsystm.h> 545295Srandyf #include <sys/stack.h> 555295Srandyf #include <sys/fs/ufs_fs.h> 565295Srandyf #include <sys/memlist.h> 575295Srandyf #include <sys/bootconf.h> 585295Srandyf #include <sys/thread.h> 595295Srandyf #include <sys/x_call.h> 605295Srandyf #include <sys/smp_impldefs.h> 615295Srandyf #include <vm/vm_dep.h> 625295Srandyf #include <sys/psm.h> 635295Srandyf #include <sys/epm.h> 645295Srandyf #include <sys/cpr_wakecode.h> 655295Srandyf #include <sys/x86_archext.h> 665295Srandyf #include <sys/reboot.h> 675295Srandyf #include <sys/acpi/acpi.h> 685295Srandyf #include <sys/acpica.h> 695295Srandyf 705295Srandyf #define AFMT "%lx" 715295Srandyf 725295Srandyf extern int flushes_require_xcalls; 735295Srandyf extern cpuset_t cpu_ready_set; 745295Srandyf 755295Srandyf #if defined(__amd64) 765295Srandyf extern void *wc_long_mode_64(void); 775295Srandyf #endif /* __amd64 */ 785295Srandyf extern int tsc_gethrtime_enable; 795295Srandyf extern void i_cpr_start_cpu(void); 805295Srandyf 815295Srandyf ushort_t cpr_mach_type = CPR_MACHTYPE_X86; 825295Srandyf void (*cpr_start_cpu_func)(void) = i_cpr_start_cpu; 835295Srandyf 845295Srandyf static wc_cpu_t *wc_other_cpus = NULL; 856336Sbholler static cpuset_t procset; 865295Srandyf 875295Srandyf static void 885295Srandyf init_real_mode_platter(int cpun, uint32_t offset, uint_t cr4, wc_desctbr_t gdt); 895295Srandyf 905295Srandyf static int i_cpr_platform_alloc(psm_state_request_t *req); 915295Srandyf static void i_cpr_platform_free(psm_state_request_t *req); 925295Srandyf static int i_cpr_save_apic(psm_state_request_t *req); 935295Srandyf static int i_cpr_restore_apic(psm_state_request_t *req); 945817Sjan static int wait_for_set(cpuset_t *set, int who); 955295Srandyf 96*9989SJoseph.Townsend@Sun.COM static void i_cpr_save_stack(kthread_t *t, wc_cpu_t *wc_cpu); 97*9989SJoseph.Townsend@Sun.COM void i_cpr_restore_stack(kthread_t *t, greg_t *save_stack); 98*9989SJoseph.Townsend@Sun.COM 99*9989SJoseph.Townsend@Sun.COM #ifdef STACK_GROWTH_DOWN 100*9989SJoseph.Townsend@Sun.COM #define CPR_GET_STACK_START(t) ((t)->t_stkbase) 101*9989SJoseph.Townsend@Sun.COM #define CPR_GET_STACK_END(t) ((t)->t_stk) 102*9989SJoseph.Townsend@Sun.COM #else 103*9989SJoseph.Townsend@Sun.COM #define CPR_GET_STACK_START(t) ((t)->t_stk) 104*9989SJoseph.Townsend@Sun.COM #define CPR_GET_STACK_END(t) ((t)->t_stkbase) 105*9989SJoseph.Townsend@Sun.COM #endif /* STACK_GROWTH_DOWN */ 106*9989SJoseph.Townsend@Sun.COM 1075295Srandyf /* 1085295Srandyf * restart paused slave cpus 1095295Srandyf */ 1105295Srandyf void 1115295Srandyf i_cpr_machdep_setup(void) 1125295Srandyf { 1135295Srandyf if (ncpus > 1) { 1145295Srandyf CPR_DEBUG(CPR_DEBUG1, ("MP restarted...\n")); 1155295Srandyf mutex_enter(&cpu_lock); 1165295Srandyf start_cpus(); 1175295Srandyf mutex_exit(&cpu_lock); 1185295Srandyf } 1195295Srandyf } 1205295Srandyf 1215295Srandyf 1225295Srandyf /* 1235295Srandyf * Stop all interrupt activities in the system 1245295Srandyf */ 1255295Srandyf void 1265295Srandyf i_cpr_stop_intr(void) 1275295Srandyf { 1285295Srandyf (void) spl7(); 1295295Srandyf } 1305295Srandyf 1315295Srandyf /* 1325295Srandyf * Set machine up to take interrupts 1335295Srandyf */ 1345295Srandyf void 1355295Srandyf i_cpr_enable_intr(void) 1365295Srandyf { 1375295Srandyf (void) spl0(); 1385295Srandyf } 1395295Srandyf 1405295Srandyf /* 1415295Srandyf * Save miscellaneous information which needs to be written to the 1425295Srandyf * state file. This information is required to re-initialize 1435295Srandyf * kernel/prom handshaking. 1445295Srandyf */ 1455295Srandyf void 1465295Srandyf i_cpr_save_machdep_info(void) 1475295Srandyf { 1485295Srandyf int notcalled = 0; 1495295Srandyf ASSERT(notcalled); 1505295Srandyf } 1515295Srandyf 1525295Srandyf 1535295Srandyf void 1545295Srandyf i_cpr_set_tbr(void) 1555295Srandyf { 1565295Srandyf } 1575295Srandyf 1585295Srandyf 1595295Srandyf processorid_t 1605295Srandyf i_cpr_bootcpuid(void) 1615295Srandyf { 1625295Srandyf return (0); 1635295Srandyf } 1645295Srandyf 1655295Srandyf /* 1665295Srandyf * cpu0 should contain bootcpu info 1675295Srandyf */ 1685295Srandyf cpu_t * 1695295Srandyf i_cpr_bootcpu(void) 1705295Srandyf { 1715295Srandyf ASSERT(MUTEX_HELD(&cpu_lock)); 1725295Srandyf 1735295Srandyf return (cpu_get(i_cpr_bootcpuid())); 1745295Srandyf } 1755295Srandyf 1765295Srandyf /* 1775295Srandyf * Save context for the specified CPU 1785295Srandyf */ 1795295Srandyf void * 1805295Srandyf i_cpr_save_context(void *arg) 1815295Srandyf { 1825295Srandyf long index = (long)arg; 1835295Srandyf psm_state_request_t *papic_state; 1845295Srandyf int resuming; 1855295Srandyf int ret; 186*9989SJoseph.Townsend@Sun.COM wc_cpu_t *wc_cpu = wc_other_cpus + index; 1875295Srandyf 1885295Srandyf PMD(PMD_SX, ("i_cpr_save_context() index = %ld\n", index)) 1895295Srandyf 1905295Srandyf ASSERT(index < NCPU); 1915295Srandyf 192*9989SJoseph.Townsend@Sun.COM papic_state = &(wc_cpu)->wc_apic_state; 1935295Srandyf 1945295Srandyf ret = i_cpr_platform_alloc(papic_state); 1955295Srandyf ASSERT(ret == 0); 1965295Srandyf 1975295Srandyf ret = i_cpr_save_apic(papic_state); 1985295Srandyf ASSERT(ret == 0); 1995295Srandyf 200*9989SJoseph.Townsend@Sun.COM i_cpr_save_stack(curthread, wc_cpu); 201*9989SJoseph.Townsend@Sun.COM 2025295Srandyf /* 2035295Srandyf * wc_save_context returns twice, once when susending and 2045295Srandyf * once when resuming, wc_save_context() returns 0 when 2055295Srandyf * suspending and non-zero upon resume 2065295Srandyf */ 207*9989SJoseph.Townsend@Sun.COM resuming = (wc_save_context(wc_cpu) == 0); 2085295Srandyf 2095295Srandyf /* 2105295Srandyf * do NOT call any functions after this point, because doing so 2115295Srandyf * will modify the stack that we are running on 2125295Srandyf */ 2135295Srandyf 2145295Srandyf if (resuming) { 2155295Srandyf 2165295Srandyf ret = i_cpr_restore_apic(papic_state); 2175295Srandyf ASSERT(ret == 0); 2185295Srandyf 2195295Srandyf i_cpr_platform_free(papic_state); 2205295Srandyf 2215295Srandyf /* 2227113Sbholler * Enable interrupts on this cpu. 2237113Sbholler * Do not bind interrupts to this CPU's local APIC until 2247515SSeth.Goldberg@Sun.COM * the CPU is ready to receive interrupts. 2257113Sbholler */ 2267113Sbholler ASSERT(CPU->cpu_id != i_cpr_bootcpuid()); 2277113Sbholler mutex_enter(&cpu_lock); 2287113Sbholler cpu_enable_intr(CPU); 2297113Sbholler mutex_exit(&cpu_lock); 2307113Sbholler 2317113Sbholler /* 2325295Srandyf * Setting the bit in cpu_ready_set must be the last operation 2335295Srandyf * in processor initialization; the boot CPU will continue to 2345295Srandyf * boot once it sees this bit set for all active CPUs. 2355295Srandyf */ 2365295Srandyf CPUSET_ATOMIC_ADD(cpu_ready_set, CPU->cpu_id); 2375295Srandyf 2385295Srandyf PMD(PMD_SX, 2396336Sbholler ("i_cpr_save_context() resuming cpu %d in cpu_ready_set\n", 2406336Sbholler CPU->cpu_id)) 2417515SSeth.Goldberg@Sun.COM } else { 2427515SSeth.Goldberg@Sun.COM /* 2437515SSeth.Goldberg@Sun.COM * Disable interrupts on this CPU so that PSM knows not to bind 2447515SSeth.Goldberg@Sun.COM * interrupts here on resume until the CPU has executed 2457515SSeth.Goldberg@Sun.COM * cpu_enable_intr() (above) in the resume path. 2467515SSeth.Goldberg@Sun.COM * We explicitly do not grab cpu_lock here because at this point 2477515SSeth.Goldberg@Sun.COM * in the suspend process, the boot cpu owns cpu_lock and all 2487515SSeth.Goldberg@Sun.COM * other cpus are also executing in the pause thread (only 2497515SSeth.Goldberg@Sun.COM * modifying their respective CPU structure). 2507515SSeth.Goldberg@Sun.COM */ 2517515SSeth.Goldberg@Sun.COM (void) cpu_disable_intr(CPU); 2525295Srandyf } 2537515SSeth.Goldberg@Sun.COM 2547515SSeth.Goldberg@Sun.COM PMD(PMD_SX, ("i_cpr_save_context: wc_save_context returns %d\n", 2557515SSeth.Goldberg@Sun.COM resuming)) 2567515SSeth.Goldberg@Sun.COM 2575295Srandyf return (NULL); 2585295Srandyf } 2595295Srandyf 2605295Srandyf static ushort_t *warm_reset_vector = NULL; 2615295Srandyf 2625295Srandyf static ushort_t * 2635295Srandyf map_warm_reset_vector() 2645295Srandyf { 2655295Srandyf /*LINTED*/ 2665295Srandyf if (!(warm_reset_vector = (ushort_t *)psm_map_phys(WARM_RESET_VECTOR, 2675295Srandyf sizeof (ushort_t *), PROT_READ|PROT_WRITE))) 2685295Srandyf return (NULL); 2695295Srandyf 2705295Srandyf /* 2715295Srandyf * setup secondary cpu bios boot up vector 2725295Srandyf */ 2735295Srandyf *warm_reset_vector = (ushort_t)((caddr_t) 2745295Srandyf /*LINTED*/ 2755295Srandyf ((struct rm_platter *)rm_platter_va)->rm_code - rm_platter_va 2765295Srandyf + ((ulong_t)rm_platter_va & 0xf)); 2775295Srandyf warm_reset_vector++; 2785295Srandyf *warm_reset_vector = (ushort_t)(rm_platter_pa >> 4); 2795295Srandyf 2805295Srandyf --warm_reset_vector; 2815295Srandyf return (warm_reset_vector); 2825295Srandyf } 2835295Srandyf 2845295Srandyf void 2855295Srandyf i_cpr_pre_resume_cpus() 2865295Srandyf { 2875295Srandyf /* 2885295Srandyf * this is a cut down version of start_other_cpus() 2895295Srandyf * just do the initialization to wake the other cpus 2905295Srandyf */ 2915295Srandyf unsigned who; 2925817Sjan int boot_cpuid = i_cpr_bootcpuid(); 2935295Srandyf uint32_t code_length = 0; 2945295Srandyf caddr_t wakevirt = rm_platter_va; 2955295Srandyf /*LINTED*/ 2965295Srandyf wakecode_t *wp = (wakecode_t *)wakevirt; 2975295Srandyf char *str = "i_cpr_pre_resume_cpus"; 2985295Srandyf extern int get_tsc_ready(); 2995295Srandyf int err; 3005295Srandyf 3015295Srandyf /*LINTED*/ 3025295Srandyf rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va; 3035295Srandyf 3045295Srandyf /* 3057515SSeth.Goldberg@Sun.COM * If startup wasn't able to find a page under 1M, we cannot 3067515SSeth.Goldberg@Sun.COM * proceed. 3077515SSeth.Goldberg@Sun.COM */ 3087515SSeth.Goldberg@Sun.COM if (rm_platter_va == 0) { 3097515SSeth.Goldberg@Sun.COM cmn_err(CE_WARN, "Cannot suspend the system because no " 3107515SSeth.Goldberg@Sun.COM "memory below 1M could be found for processor startup"); 3117515SSeth.Goldberg@Sun.COM return; 3127515SSeth.Goldberg@Sun.COM } 3137515SSeth.Goldberg@Sun.COM 3147515SSeth.Goldberg@Sun.COM /* 3155295Srandyf * Copy the real mode code at "real_mode_start" to the 3165295Srandyf * page at rm_platter_va. 3175295Srandyf */ 3185295Srandyf warm_reset_vector = map_warm_reset_vector(); 3195295Srandyf if (warm_reset_vector == NULL) { 3205295Srandyf PMD(PMD_SX, ("i_cpr_pre_resume_cpus() returning #2\n")) 3215295Srandyf return; 3225295Srandyf } 3235295Srandyf 3245295Srandyf flushes_require_xcalls = 1; 3255295Srandyf 3265295Srandyf /* 3275295Srandyf * We lock our affinity to the master CPU to ensure that all slave CPUs 3285295Srandyf * do their TSC syncs with the same CPU. 3295295Srandyf */ 3305295Srandyf 3315295Srandyf affinity_set(CPU_CURRENT); 3325295Srandyf 3335817Sjan /* 3346336Sbholler * Mark the boot cpu as being ready and in the procset, since we are 3356336Sbholler * running on that cpu. 3365817Sjan */ 3375817Sjan CPUSET_ONLY(cpu_ready_set, boot_cpuid); 3386336Sbholler CPUSET_ONLY(procset, boot_cpuid); 3395295Srandyf 3405295Srandyf for (who = 0; who < ncpus; who++) { 3415295Srandyf 3425295Srandyf wc_cpu_t *cpup = wc_other_cpus + who; 3435295Srandyf wc_desctbr_t gdt; 3445295Srandyf 3455817Sjan if (who == boot_cpuid) 3465295Srandyf continue; 3475295Srandyf 3485295Srandyf if (!CPU_IN_SET(mp_cpus, who)) 3495295Srandyf continue; 3505295Srandyf 3515295Srandyf PMD(PMD_SX, ("%s() waking up %d cpu\n", str, who)) 3525295Srandyf 3535295Srandyf bcopy(cpup, &(wp->wc_cpu), sizeof (wc_cpu_t)); 3545295Srandyf 3555295Srandyf gdt.base = cpup->wc_gdt_base; 3565295Srandyf gdt.limit = cpup->wc_gdt_limit; 3575295Srandyf 3585295Srandyf #if defined(__amd64) 3595295Srandyf code_length = (uint32_t)wc_long_mode_64 - (uint32_t)wc_rm_start; 3605295Srandyf #else 3615295Srandyf code_length = 0; 3625295Srandyf #endif 3635295Srandyf 3645295Srandyf init_real_mode_platter(who, code_length, cpup->wc_cr4, gdt); 3655295Srandyf 3665295Srandyf if ((err = mach_cpuid_start(who, rm_platter_va)) != 0) { 3675295Srandyf cmn_err(CE_WARN, "cpu%d: failed to start during " 3685295Srandyf "suspend/resume error %d", who, err); 3695295Srandyf continue; 3705295Srandyf } 3715295Srandyf 3726336Sbholler PMD(PMD_SX, ("%s() #1 waiting for %d in procset\n", str, who)) 3735295Srandyf 3745817Sjan if (!wait_for_set(&procset, who)) 3755817Sjan continue; 3765295Srandyf 3775295Srandyf PMD(PMD_SX, ("%s() %d cpu started\n", str, who)) 3785295Srandyf 3795817Sjan PMD(PMD_SX, ("%s() tsc_ready = %d\n", str, get_tsc_ready())) 3805295Srandyf 3815295Srandyf if (tsc_gethrtime_enable) { 3825295Srandyf PMD(PMD_SX, ("%s() calling tsc_sync_master\n", str)) 3835295Srandyf tsc_sync_master(who); 3845295Srandyf } 3855295Srandyf 3866336Sbholler PMD(PMD_SX, ("%s() waiting for %d in cpu_ready_set\n", str, 3876336Sbholler who)) 3885295Srandyf /* 3895295Srandyf * Wait for cpu to declare that it is ready, we want the 3905295Srandyf * cpus to start serially instead of in parallel, so that 3915295Srandyf * they do not contend with each other in wc_rm_start() 3925295Srandyf */ 3935817Sjan if (!wait_for_set(&cpu_ready_set, who)) 3945817Sjan continue; 3955295Srandyf 3965295Srandyf /* 3975295Srandyf * do not need to re-initialize dtrace using dtrace_cpu_init 3985295Srandyf * function 3995295Srandyf */ 4005295Srandyf PMD(PMD_SX, ("%s() cpu %d now ready\n", str, who)) 4015295Srandyf } 4025295Srandyf 4035295Srandyf affinity_clear(); 4045295Srandyf 4055295Srandyf PMD(PMD_SX, ("%s() all cpus now ready\n", str)) 4065817Sjan 4075295Srandyf } 4085295Srandyf 4095295Srandyf static void 4105295Srandyf unmap_warm_reset_vector(ushort_t *warm_reset_vector) 4115295Srandyf { 4125295Srandyf psm_unmap_phys((caddr_t)warm_reset_vector, sizeof (ushort_t *)); 4135295Srandyf } 4145295Srandyf 4155295Srandyf /* 4165295Srandyf * We need to setup a 1:1 (virtual to physical) mapping for the 4175295Srandyf * page containing the wakeup code. 4185295Srandyf */ 4195295Srandyf static struct as *save_as; /* when switching to kas */ 4205295Srandyf 4215295Srandyf static void 4225295Srandyf unmap_wakeaddr_1to1(uint64_t wakephys) 4235295Srandyf { 4245295Srandyf uintptr_t wp = (uintptr_t)wakephys; 4255295Srandyf hat_setup(save_as->a_hat, 0); /* switch back from kernel hat */ 4265295Srandyf hat_unload(kas.a_hat, (caddr_t)wp, PAGESIZE, HAT_UNLOAD); 4275295Srandyf } 4285295Srandyf 4295295Srandyf void 4305295Srandyf i_cpr_post_resume_cpus() 4315295Srandyf { 4325295Srandyf uint64_t wakephys = rm_platter_pa; 4335295Srandyf 4345295Srandyf if (warm_reset_vector != NULL) 4355295Srandyf unmap_warm_reset_vector(warm_reset_vector); 4365295Srandyf 4375295Srandyf hat_unload(kas.a_hat, (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE, 4385295Srandyf HAT_UNLOAD); 4395295Srandyf 4405295Srandyf /* 4415295Srandyf * cmi_post_mpstartup() is only required upon boot not upon 4425295Srandyf * resume from RAM 4435295Srandyf */ 4445295Srandyf 4455295Srandyf PT(PT_UNDO1to1); 4465295Srandyf /* Tear down 1:1 mapping for wakeup code */ 4475295Srandyf unmap_wakeaddr_1to1(wakephys); 4485295Srandyf } 4495295Srandyf 4505295Srandyf /* ARGSUSED */ 4515295Srandyf void 4525295Srandyf i_cpr_handle_xc(int flag) 4535295Srandyf { 4545295Srandyf } 4555295Srandyf 4565295Srandyf int 4575295Srandyf i_cpr_reusable_supported(void) 4585295Srandyf { 4595295Srandyf return (0); 4605295Srandyf } 4615295Srandyf static void 4625295Srandyf map_wakeaddr_1to1(uint64_t wakephys) 4635295Srandyf { 4645295Srandyf uintptr_t wp = (uintptr_t)wakephys; 4655295Srandyf hat_devload(kas.a_hat, (caddr_t)wp, PAGESIZE, btop(wakephys), 4665295Srandyf (PROT_READ|PROT_WRITE|PROT_EXEC|HAT_STORECACHING_OK|HAT_NOSYNC), 4675295Srandyf HAT_LOAD); 4685295Srandyf save_as = curthread->t_procp->p_as; 4695295Srandyf hat_setup(kas.a_hat, 0); /* switch to kernel-only hat */ 4705295Srandyf } 4715295Srandyf 4725295Srandyf 4735295Srandyf void 4745295Srandyf prt_other_cpus() 4755295Srandyf { 4765295Srandyf int who; 4775295Srandyf 4785295Srandyf if (ncpus == 1) { 4795295Srandyf PMD(PMD_SX, ("prt_other_cpus() other cpu table empty for " 4805295Srandyf "uniprocessor machine\n")) 4815295Srandyf return; 4825295Srandyf } 4835295Srandyf 4845295Srandyf for (who = 0; who < ncpus; who++) { 4855295Srandyf 4865295Srandyf wc_cpu_t *cpup = wc_other_cpus + who; 4875295Srandyf 4885295Srandyf PMD(PMD_SX, ("prt_other_cpus() who = %d, gdt=%p:%x, " 4895295Srandyf "idt=%p:%x, ldt=%lx, tr=%lx, kgsbase=" 4905295Srandyf AFMT ", sp=%lx\n", who, 4915295Srandyf (void *)cpup->wc_gdt_base, cpup->wc_gdt_limit, 4925295Srandyf (void *)cpup->wc_idt_base, cpup->wc_idt_limit, 4935295Srandyf (long)cpup->wc_ldt, (long)cpup->wc_tr, 4945295Srandyf (long)cpup->wc_kgsbase, (long)cpup->wc_rsp)) 4955295Srandyf } 4965295Srandyf } 4975295Srandyf 4985295Srandyf /* 4995295Srandyf * Power down the system. 5005295Srandyf */ 5015295Srandyf int 5025295Srandyf i_cpr_power_down(int sleeptype) 5035295Srandyf { 5045295Srandyf caddr_t wakevirt = rm_platter_va; 5055295Srandyf uint64_t wakephys = rm_platter_pa; 5066336Sbholler ulong_t saved_intr; 5075295Srandyf uint32_t code_length = 0; 5085295Srandyf wc_desctbr_t gdt; 5095295Srandyf /*LINTED*/ 5105295Srandyf wakecode_t *wp = (wakecode_t *)wakevirt; 5115295Srandyf /*LINTED*/ 5125295Srandyf rm_platter_t *wcpp = (rm_platter_t *)wakevirt; 5135295Srandyf wc_cpu_t *cpup = &(wp->wc_cpu); 5145295Srandyf dev_info_t *ppm; 5155295Srandyf int ret = 0; 5165295Srandyf power_req_t power_req; 5175295Srandyf char *str = "i_cpr_power_down"; 5185295Srandyf #if defined(__amd64) 5195295Srandyf /*LINTED*/ 5205295Srandyf rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va; 5215295Srandyf #endif 5225295Srandyf extern int cpr_suspend_succeeded; 5235295Srandyf extern void kernel_wc_code(); 5245295Srandyf 5255295Srandyf ASSERT(sleeptype == CPR_TORAM); 5265295Srandyf ASSERT(CPU->cpu_id == 0); 5275295Srandyf 5285295Srandyf if ((ppm = PPM(ddi_root_node())) == NULL) { 5295295Srandyf PMD(PMD_SX, ("%s: root node not claimed\n", str)) 5305295Srandyf return (ENOTTY); 5315295Srandyf } 5325295Srandyf 5335295Srandyf PMD(PMD_SX, ("Entering %s()\n", str)) 5345295Srandyf 5355295Srandyf PT(PT_IC); 5365295Srandyf saved_intr = intr_clear(); 5375295Srandyf 5385295Srandyf PT(PT_1to1); 5395295Srandyf /* Setup 1:1 mapping for wakeup code */ 5405295Srandyf map_wakeaddr_1to1(wakephys); 5415295Srandyf 5425295Srandyf PMD(PMD_SX, ("ncpus=%d\n", ncpus)) 5435295Srandyf 5445295Srandyf PMD(PMD_SX, ("wc_rm_end - wc_rm_start=%lx WC_CODESIZE=%x\n", 5455295Srandyf ((size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)), WC_CODESIZE)) 5465295Srandyf 5475295Srandyf PMD(PMD_SX, ("wakevirt=%p, wakephys=%x\n", 5485295Srandyf (void *)wakevirt, (uint_t)wakephys)) 5495295Srandyf 5505295Srandyf ASSERT(((size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)) < 5515295Srandyf WC_CODESIZE); 5525295Srandyf 5535295Srandyf bzero(wakevirt, PAGESIZE); 5545295Srandyf 5555295Srandyf /* Copy code to rm_platter */ 5565295Srandyf bcopy((caddr_t)wc_rm_start, wakevirt, 5575295Srandyf (size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)); 5585295Srandyf 5595295Srandyf prt_other_cpus(); 5605295Srandyf 5615295Srandyf #if defined(__amd64) 5625295Srandyf 5635295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n", 5645295Srandyf (ulong_t)real_mode_platter->rm_cr4, (ulong_t)getcr4())) 5655295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n", 5665295Srandyf (ulong_t)real_mode_platter->rm_pdbr, getcr3())) 5675295Srandyf 5685295Srandyf real_mode_platter->rm_cr4 = getcr4(); 5695295Srandyf real_mode_platter->rm_pdbr = getcr3(); 5705295Srandyf 5715295Srandyf rmp_gdt_init(real_mode_platter); 5725295Srandyf 5735295Srandyf /* 5745295Srandyf * Since the CPU needs to jump to protected mode using an identity 5755295Srandyf * mapped address, we need to calculate it here. 5765295Srandyf */ 5775295Srandyf real_mode_platter->rm_longmode64_addr = rm_platter_pa + 5785295Srandyf ((uint32_t)wc_long_mode_64 - (uint32_t)wc_rm_start); 5795295Srandyf 5805295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n", 5815295Srandyf (ulong_t)real_mode_platter->rm_cr4, getcr4())) 5825295Srandyf 5835295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n", 5845295Srandyf (ulong_t)real_mode_platter->rm_pdbr, getcr3())) 5855295Srandyf 5865295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_longmode64_addr=%lx\n", 5875295Srandyf (ulong_t)real_mode_platter->rm_longmode64_addr)) 5885295Srandyf 5895295Srandyf #endif 5905295Srandyf 5915295Srandyf PT(PT_SC); 5925295Srandyf if (wc_save_context(cpup)) { 5935295Srandyf 5945295Srandyf ret = i_cpr_platform_alloc(&(wc_other_cpus->wc_apic_state)); 5955295Srandyf if (ret != 0) 5965295Srandyf return (ret); 5975295Srandyf 5985295Srandyf ret = i_cpr_save_apic(&(wc_other_cpus->wc_apic_state)); 5995295Srandyf PMD(PMD_SX, ("%s: i_cpr_save_apic() returned %d\n", str, ret)) 6005295Srandyf if (ret != 0) 6015295Srandyf return (ret); 6025295Srandyf 6035295Srandyf PMD(PMD_SX, ("wakephys=%x, kernel_wc_code=%p\n", 6045295Srandyf (uint_t)wakephys, (void *)&kernel_wc_code)) 6055295Srandyf PMD(PMD_SX, ("virtaddr=%lx, retaddr=%lx\n", 6065295Srandyf (long)cpup->wc_virtaddr, (long)cpup->wc_retaddr)) 6075295Srandyf PMD(PMD_SX, ("ebx=%x, edi=%x, esi=%x, ebp=%x, esp=%x\n", 6085295Srandyf cpup->wc_ebx, cpup->wc_edi, cpup->wc_esi, cpup->wc_ebp, 6095295Srandyf cpup->wc_esp)) 6105295Srandyf PMD(PMD_SX, ("cr0=%lx, cr3=%lx, cr4=%lx\n", 6115295Srandyf (long)cpup->wc_cr0, (long)cpup->wc_cr3, 6125295Srandyf (long)cpup->wc_cr4)) 6135295Srandyf PMD(PMD_SX, ("cs=%x, ds=%x, es=%x, ss=%x, fs=%lx, gs=%lx, " 6145295Srandyf "flgs=%lx\n", cpup->wc_cs, cpup->wc_ds, cpup->wc_es, 6155295Srandyf cpup->wc_ss, (long)cpup->wc_fs, (long)cpup->wc_gs, 6165295Srandyf (long)cpup->wc_eflags)) 6175295Srandyf 6185295Srandyf PMD(PMD_SX, ("gdt=%p:%x, idt=%p:%x, ldt=%lx, tr=%lx, " 6195295Srandyf "kgbase=%lx\n", (void *)cpup->wc_gdt_base, 6205295Srandyf cpup->wc_gdt_limit, (void *)cpup->wc_idt_base, 6215295Srandyf cpup->wc_idt_limit, (long)cpup->wc_ldt, 6225295Srandyf (long)cpup->wc_tr, (long)cpup->wc_kgsbase)) 6235295Srandyf 6245295Srandyf gdt.base = cpup->wc_gdt_base; 6255295Srandyf gdt.limit = cpup->wc_gdt_limit; 6265295Srandyf 6275295Srandyf #if defined(__amd64) 6285295Srandyf code_length = (uint32_t)wc_long_mode_64 - 6295295Srandyf (uint32_t)wc_rm_start; 6305295Srandyf #else 6315295Srandyf code_length = 0; 6325295Srandyf #endif 6335295Srandyf 6345295Srandyf init_real_mode_platter(0, code_length, cpup->wc_cr4, gdt); 6355295Srandyf 6365295Srandyf #if defined(__amd64) 6375295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n", 6385295Srandyf (ulong_t)wcpp->rm_cr4, getcr4())) 6395295Srandyf 6405295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n", 6415295Srandyf (ulong_t)wcpp->rm_pdbr, getcr3())) 6425295Srandyf 6435295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_longmode64_addr=%lx\n", 6445295Srandyf (ulong_t)wcpp->rm_longmode64_addr)) 6455295Srandyf 6465295Srandyf PMD(PMD_SX, 6475295Srandyf ("real_mode_platter->rm_temp_gdt[TEMPGDT_KCODE64]=%lx\n", 6485295Srandyf (ulong_t)wcpp->rm_temp_gdt[TEMPGDT_KCODE64])) 6495295Srandyf #endif 6505295Srandyf 6515295Srandyf PMD(PMD_SX, ("gdt=%p:%x, idt=%p:%x, ldt=%lx, tr=%lx, " 6525295Srandyf "kgsbase=%lx\n", (void *)wcpp->rm_gdt_base, 6535295Srandyf wcpp->rm_gdt_lim, (void *)wcpp->rm_idt_base, 6545295Srandyf wcpp->rm_idt_lim, (long)cpup->wc_ldt, (long)cpup->wc_tr, 6555295Srandyf (long)cpup->wc_kgsbase)) 6565295Srandyf 6575295Srandyf power_req.request_type = PMR_PPM_ENTER_SX; 6585295Srandyf power_req.req.ppm_power_enter_sx_req.sx_state = S3; 6595295Srandyf power_req.req.ppm_power_enter_sx_req.test_point = 6605295Srandyf cpr_test_point; 6615295Srandyf power_req.req.ppm_power_enter_sx_req.wakephys = wakephys; 6625295Srandyf 6635295Srandyf PMD(PMD_SX, ("%s: pm_ctlops PMR_PPM_ENTER_SX\n", str)) 6645295Srandyf PT(PT_PPMCTLOP); 6655295Srandyf (void) pm_ctlops(ppm, ddi_root_node(), DDI_CTLOPS_POWER, 6665295Srandyf &power_req, &ret); 6675295Srandyf PMD(PMD_SX, ("%s: returns %d\n", str, ret)) 6685295Srandyf 6695295Srandyf /* 6705295Srandyf * If it works, we get control back to the else branch below 6715295Srandyf * If we get control back here, it didn't work. 6725295Srandyf * XXX return EINVAL here? 6735295Srandyf */ 6745295Srandyf 6755295Srandyf unmap_wakeaddr_1to1(wakephys); 6765295Srandyf intr_restore(saved_intr); 6775295Srandyf 6785295Srandyf return (ret); 6795295Srandyf } else { 6805295Srandyf cpr_suspend_succeeded = 1; 6815295Srandyf 6825295Srandyf power_req.request_type = PMR_PPM_EXIT_SX; 6835295Srandyf power_req.req.ppm_power_enter_sx_req.sx_state = S3; 6845295Srandyf 6855295Srandyf PMD(PMD_SX, ("%s: pm_ctlops PMR_PPM_EXIT_SX\n", str)) 6865295Srandyf PT(PT_PPMCTLOP); 6875295Srandyf (void) pm_ctlops(ppm, ddi_root_node(), DDI_CTLOPS_POWER, 6885295Srandyf &power_req, &ret); 6895295Srandyf PMD(PMD_SX, ("%s: returns %d\n", str, ret)) 6905295Srandyf 6915295Srandyf ret = i_cpr_restore_apic(&(wc_other_cpus->wc_apic_state)); 6925295Srandyf /* 6935295Srandyf * the restore should never fail, if the saved suceeded 6945295Srandyf */ 6955295Srandyf ASSERT(ret == 0); 6965295Srandyf 6975295Srandyf i_cpr_platform_free(&(wc_other_cpus->wc_apic_state)); 6985295Srandyf 6997113Sbholler /* 7007113Sbholler * Enable interrupts on boot cpu. 7017113Sbholler */ 7027113Sbholler ASSERT(CPU->cpu_id == i_cpr_bootcpuid()); 7037113Sbholler mutex_enter(&cpu_lock); 7047113Sbholler cpu_enable_intr(CPU); 7057113Sbholler mutex_exit(&cpu_lock); 7067113Sbholler 7075295Srandyf PT(PT_INTRRESTORE); 7085295Srandyf intr_restore(saved_intr); 7095295Srandyf PT(PT_CPU); 7105295Srandyf 7115295Srandyf return (ret); 7125295Srandyf } 7135295Srandyf } 7145295Srandyf 7155295Srandyf /* 7165295Srandyf * Stop all other cpu's before halting or rebooting. We pause the cpu's 7175295Srandyf * instead of sending a cross call. 7185295Srandyf * Stolen from sun4/os/mp_states.c 7195295Srandyf */ 7205295Srandyf 7215295Srandyf static int cpu_are_paused; /* sic */ 7225295Srandyf 7235295Srandyf void 7245295Srandyf i_cpr_stop_other_cpus(void) 7255295Srandyf { 7265295Srandyf mutex_enter(&cpu_lock); 7275295Srandyf if (cpu_are_paused) { 7285295Srandyf mutex_exit(&cpu_lock); 7295295Srandyf return; 7305295Srandyf } 7315295Srandyf pause_cpus(NULL); 7325295Srandyf cpu_are_paused = 1; 7335295Srandyf 7345295Srandyf mutex_exit(&cpu_lock); 7355295Srandyf } 7365295Srandyf 7375295Srandyf int 7385295Srandyf i_cpr_is_supported(int sleeptype) 7395295Srandyf { 7405295Srandyf extern int cpr_supported_override; 7415295Srandyf extern int cpr_platform_enable; 7425295Srandyf extern int pm_S3_enabled; 7435295Srandyf 7445295Srandyf if (sleeptype != CPR_TORAM) 7455295Srandyf return (0); 7465295Srandyf 7475295Srandyf /* 7485295Srandyf * The next statement tests if a specific platform has turned off 7495295Srandyf * cpr support. 7505295Srandyf */ 7515295Srandyf if (cpr_supported_override) 7525295Srandyf return (0); 7535295Srandyf 7545295Srandyf /* 7555295Srandyf * If a platform has specifically turned on cpr support ... 7565295Srandyf */ 7575295Srandyf if (cpr_platform_enable) 7585295Srandyf return (1); 7595295Srandyf 7605295Srandyf return (pm_S3_enabled); 7615295Srandyf } 7625295Srandyf 7635295Srandyf void 7645295Srandyf i_cpr_bitmap_cleanup(void) 7655295Srandyf { 7665295Srandyf } 7675295Srandyf 7685295Srandyf void 7695295Srandyf i_cpr_free_memory_resources(void) 7705295Srandyf { 7715295Srandyf } 7725295Srandyf 7735295Srandyf /* 7745295Srandyf * Needed only for S3 so far 7755295Srandyf */ 7765295Srandyf static int 7775295Srandyf i_cpr_platform_alloc(psm_state_request_t *req) 7785295Srandyf { 7797515SSeth.Goldberg@Sun.COM #ifdef DEBUG 7805295Srandyf char *str = "i_cpr_platform_alloc"; 7817515SSeth.Goldberg@Sun.COM #endif 7825295Srandyf 7835295Srandyf PMD(PMD_SX, ("cpu = %d, %s(%p) \n", CPU->cpu_id, str, (void *)req)) 7845295Srandyf 7857515SSeth.Goldberg@Sun.COM if (psm_state == NULL) { 7867515SSeth.Goldberg@Sun.COM PMD(PMD_SX, ("%s() : psm_state == NULL\n", str)) 7875295Srandyf return (0); 7885295Srandyf } 7895295Srandyf 7905295Srandyf req->psr_cmd = PSM_STATE_ALLOC; 7915295Srandyf return ((*psm_state)(req)); 7925295Srandyf } 7935295Srandyf 7945295Srandyf /* 7955295Srandyf * Needed only for S3 so far 7965295Srandyf */ 7975295Srandyf static void 7985295Srandyf i_cpr_platform_free(psm_state_request_t *req) 7995295Srandyf { 8007515SSeth.Goldberg@Sun.COM #ifdef DEBUG 8015295Srandyf char *str = "i_cpr_platform_free"; 8027515SSeth.Goldberg@Sun.COM #endif 8035295Srandyf 8045295Srandyf PMD(PMD_SX, ("cpu = %d, %s(%p) \n", CPU->cpu_id, str, (void *)req)) 8055295Srandyf 8067515SSeth.Goldberg@Sun.COM if (psm_state == NULL) { 8077515SSeth.Goldberg@Sun.COM PMD(PMD_SX, ("%s() : psm_state == NULL\n", str)) 8087515SSeth.Goldberg@Sun.COM return; 8095295Srandyf } 8105295Srandyf 8115295Srandyf req->psr_cmd = PSM_STATE_FREE; 8125295Srandyf (void) (*psm_state)(req); 8135295Srandyf } 8145295Srandyf 8155295Srandyf static int 8165295Srandyf i_cpr_save_apic(psm_state_request_t *req) 8175295Srandyf { 8187515SSeth.Goldberg@Sun.COM #ifdef DEBUG 8195295Srandyf char *str = "i_cpr_save_apic"; 8207515SSeth.Goldberg@Sun.COM #endif 8215295Srandyf 8227515SSeth.Goldberg@Sun.COM if (psm_state == NULL) { 8237515SSeth.Goldberg@Sun.COM PMD(PMD_SX, ("%s() : psm_state == NULL\n", str)) 8245295Srandyf return (0); 8255295Srandyf } 8265295Srandyf 8275295Srandyf req->psr_cmd = PSM_STATE_SAVE; 8285295Srandyf return ((*psm_state)(req)); 8295295Srandyf } 8305295Srandyf 8315295Srandyf static int 8325295Srandyf i_cpr_restore_apic(psm_state_request_t *req) 8335295Srandyf { 8347515SSeth.Goldberg@Sun.COM #ifdef DEBUG 8355295Srandyf char *str = "i_cpr_restore_apic"; 8367515SSeth.Goldberg@Sun.COM #endif 8375295Srandyf 8387515SSeth.Goldberg@Sun.COM if (psm_state == NULL) { 8397515SSeth.Goldberg@Sun.COM PMD(PMD_SX, ("%s() : psm_state == NULL\n", str)) 8405295Srandyf return (0); 8415295Srandyf } 8425295Srandyf 8435295Srandyf req->psr_cmd = PSM_STATE_RESTORE; 8445295Srandyf return ((*psm_state)(req)); 8455295Srandyf } 8465295Srandyf 8475295Srandyf 8485295Srandyf /* stop lint complaining about offset not being used in 32bit mode */ 8495295Srandyf #if !defined(__amd64) 8505295Srandyf /*ARGSUSED*/ 8515295Srandyf #endif 8525295Srandyf static void 8535295Srandyf init_real_mode_platter(int cpun, uint32_t offset, uint_t cr4, wc_desctbr_t gdt) 8545295Srandyf { 8555295Srandyf /*LINTED*/ 8565295Srandyf rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va; 8575295Srandyf 8585295Srandyf /* 8595295Srandyf * Fill up the real mode platter to make it easy for real mode code to 8605295Srandyf * kick it off. This area should really be one passed by boot to kernel 8615295Srandyf * and guaranteed to be below 1MB and aligned to 16 bytes. Should also 8625295Srandyf * have identical physical and virtual address in paged mode. 8635295Srandyf */ 8645295Srandyf 8655295Srandyf real_mode_platter->rm_pdbr = getcr3(); 8665295Srandyf real_mode_platter->rm_cpu = cpun; 8675295Srandyf real_mode_platter->rm_cr4 = cr4; 8685295Srandyf 8695295Srandyf real_mode_platter->rm_gdt_base = gdt.base; 8705295Srandyf real_mode_platter->rm_gdt_lim = gdt.limit; 8715295Srandyf 8725295Srandyf #if defined(__amd64) 8735295Srandyf real_mode_platter->rm_x86feature = x86_feature; 8745295Srandyf 8755295Srandyf if (getcr3() > 0xffffffffUL) 8765295Srandyf panic("Cannot initialize CPUs; kernel's 64-bit page tables\n" 8775295Srandyf "located above 4G in physical memory (@ 0x%llx).", 8785295Srandyf (unsigned long long)getcr3()); 8795295Srandyf 8805295Srandyf /* 8815295Srandyf * Setup pseudo-descriptors for temporary GDT and IDT for use ONLY 8825295Srandyf * by code in real_mode_start(): 8835295Srandyf * 8845295Srandyf * GDT[0]: NULL selector 8855295Srandyf * GDT[1]: 64-bit CS: Long = 1, Present = 1, bits 12, 11 = 1 8865295Srandyf * 8875295Srandyf * Clear the IDT as interrupts will be off and a limit of 0 will cause 8885295Srandyf * the CPU to triple fault and reset on an NMI, seemingly as reasonable 8895295Srandyf * a course of action as any other, though it may cause the entire 8905295Srandyf * platform to reset in some cases... 8915295Srandyf */ 8925295Srandyf real_mode_platter->rm_temp_gdt[0] = 0ULL; 8935295Srandyf real_mode_platter->rm_temp_gdt[TEMPGDT_KCODE64] = 0x20980000000000ULL; 8945295Srandyf 8955295Srandyf real_mode_platter->rm_temp_gdt_lim = (ushort_t) 8965295Srandyf (sizeof (real_mode_platter->rm_temp_gdt) - 1); 8975295Srandyf real_mode_platter->rm_temp_gdt_base = rm_platter_pa + 8985295Srandyf (uint32_t)(&((rm_platter_t *)0)->rm_temp_gdt); 8995295Srandyf 9005295Srandyf real_mode_platter->rm_temp_idt_lim = 0; 9015295Srandyf real_mode_platter->rm_temp_idt_base = 0; 9025295Srandyf 9035295Srandyf /* 9045295Srandyf * Since the CPU needs to jump to protected mode using an identity 9055295Srandyf * mapped address, we need to calculate it here. 9065295Srandyf */ 9075295Srandyf real_mode_platter->rm_longmode64_addr = rm_platter_pa + offset; 9085295Srandyf #endif /* __amd64 */ 9095295Srandyf 9105295Srandyf /* return; */ 9115295Srandyf } 9125295Srandyf 9135295Srandyf void 9145295Srandyf i_cpr_start_cpu(void) 9155295Srandyf { 9165295Srandyf 9175295Srandyf struct cpu *cp = CPU; 9185295Srandyf 9195295Srandyf char *str = "i_cpr_start_cpu"; 9205295Srandyf extern void init_cpu_syscall(struct cpu *cp); 9215295Srandyf 9225295Srandyf PMD(PMD_SX, ("%s() called\n", str)) 9235295Srandyf 9245295Srandyf PMD(PMD_SX, ("%s() #0 cp->cpu_base_spl %d\n", str, 9255295Srandyf cp->cpu_base_spl)) 9265295Srandyf 9275295Srandyf mutex_enter(&cpu_lock); 9285295Srandyf if (cp == i_cpr_bootcpu()) { 9295295Srandyf mutex_exit(&cpu_lock); 9305295Srandyf PMD(PMD_SX, 9315295Srandyf ("%s() called on bootcpu nothing to do!\n", str)) 9325295Srandyf return; 9335295Srandyf } 9345295Srandyf mutex_exit(&cpu_lock); 9355295Srandyf 9365295Srandyf /* 9375295Srandyf * We need to Sync PAT with cpu0's PAT. We have to do 9385295Srandyf * this with interrupts disabled. 9395295Srandyf */ 9405295Srandyf if (x86_feature & X86_PAT) 9415295Srandyf pat_sync(); 9425295Srandyf 9435295Srandyf /* 9445295Srandyf * Initialize this CPU's syscall handlers 9455295Srandyf */ 9465295Srandyf init_cpu_syscall(cp); 9475295Srandyf 9485295Srandyf PMD(PMD_SX, ("%s() #1 cp->cpu_base_spl %d\n", str, cp->cpu_base_spl)) 9495295Srandyf 9505295Srandyf /* 9515295Srandyf * Do not need to call cpuid_pass2(), cpuid_pass3(), cpuid_pass4() or 9525295Srandyf * init_cpu_info(), since the work that they do is only needed to 9535295Srandyf * be done once at boot time 9545295Srandyf */ 9555295Srandyf 9565295Srandyf 9575295Srandyf mutex_enter(&cpu_lock); 9585295Srandyf CPUSET_ADD(procset, cp->cpu_id); 9595295Srandyf mutex_exit(&cpu_lock); 9605295Srandyf 9615295Srandyf PMD(PMD_SX, ("%s() #2 cp->cpu_base_spl %d\n", str, 9625295Srandyf cp->cpu_base_spl)) 9635295Srandyf 9645295Srandyf if (tsc_gethrtime_enable) { 9655295Srandyf PMD(PMD_SX, ("%s() calling tsc_sync_slave\n", str)) 9665295Srandyf tsc_sync_slave(); 9675295Srandyf } 9685295Srandyf 9695295Srandyf PMD(PMD_SX, ("%s() cp->cpu_id %d, cp->cpu_intr_actv %d\n", str, 9705295Srandyf cp->cpu_id, cp->cpu_intr_actv)) 9715295Srandyf PMD(PMD_SX, ("%s() #3 cp->cpu_base_spl %d\n", str, 9725295Srandyf cp->cpu_base_spl)) 9735295Srandyf 9745295Srandyf (void) spl0(); /* enable interrupts */ 9755295Srandyf 9765295Srandyf PMD(PMD_SX, ("%s() #4 cp->cpu_base_spl %d\n", str, 9775295Srandyf cp->cpu_base_spl)) 9785295Srandyf 9795295Srandyf /* 9805295Srandyf * Set up the CPU module for this CPU. This can't be done before 9815295Srandyf * this CPU is made CPU_READY, because we may (in heterogeneous systems) 9825295Srandyf * need to go load another CPU module. The act of attempting to load 9835295Srandyf * a module may trigger a cross-call, which will ASSERT unless this 9845295Srandyf * cpu is CPU_READY. 9855295Srandyf */ 9865295Srandyf 9875295Srandyf /* 9885295Srandyf * cmi already been init'd (during boot), so do not need to do it again 9895295Srandyf */ 9905295Srandyf #ifdef PM_REINITMCAONRESUME 9915295Srandyf if (x86_feature & X86_MCA) 9925295Srandyf cmi_mca_init(); 9935295Srandyf #endif 9945295Srandyf 9955295Srandyf PMD(PMD_SX, ("%s() returning\n", str)) 9965295Srandyf 9975295Srandyf /* return; */ 9985295Srandyf } 9995295Srandyf 10005295Srandyf void 10015295Srandyf i_cpr_alloc_cpus(void) 10025295Srandyf { 10035295Srandyf char *str = "i_cpr_alloc_cpus"; 10045295Srandyf 10055295Srandyf PMD(PMD_SX, ("%s() CPU->cpu_id %d\n", str, CPU->cpu_id)) 10065295Srandyf /* 10075295Srandyf * we allocate this only when we actually need it to save on 10085295Srandyf * kernel memory 10095295Srandyf */ 10105295Srandyf 10115295Srandyf if (wc_other_cpus == NULL) { 10125295Srandyf wc_other_cpus = kmem_zalloc(ncpus * sizeof (wc_cpu_t), 10135295Srandyf KM_SLEEP); 10145295Srandyf } 10155295Srandyf 10165295Srandyf } 10175295Srandyf 10185295Srandyf void 10195295Srandyf i_cpr_free_cpus(void) 10205295Srandyf { 10215295Srandyf if (wc_other_cpus != NULL) { 10225295Srandyf kmem_free((void *) wc_other_cpus, ncpus * sizeof (wc_cpu_t)); 10235295Srandyf wc_other_cpus = NULL; 10245295Srandyf } 10255295Srandyf } 10265295Srandyf 10275295Srandyf /* 10285295Srandyf * wrapper for acpica_ddi_save_resources() 10295295Srandyf */ 10305295Srandyf void 10315295Srandyf i_cpr_save_configuration(dev_info_t *dip) 10325295Srandyf { 10335295Srandyf acpica_ddi_save_resources(dip); 10345295Srandyf } 10355295Srandyf 10365295Srandyf /* 10375295Srandyf * wrapper for acpica_ddi_restore_resources() 10385295Srandyf */ 10395295Srandyf void 10405295Srandyf i_cpr_restore_configuration(dev_info_t *dip) 10415295Srandyf { 10425295Srandyf acpica_ddi_restore_resources(dip); 10435295Srandyf } 10445817Sjan 10455817Sjan static int 10465817Sjan wait_for_set(cpuset_t *set, int who) 10475817Sjan { 10485817Sjan int delays; 10495817Sjan char *str = "wait_for_set"; 10505817Sjan 10515817Sjan for (delays = 0; !CPU_IN_SET(*set, who); delays++) { 10525817Sjan if (delays == 500) { 10535817Sjan /* 10545817Sjan * After five seconds, things are probably 10555817Sjan * looking a bit bleak - explain the hang. 10565817Sjan */ 10575817Sjan cmn_err(CE_NOTE, "cpu%d: started, " 10585817Sjan "but not running in the kernel yet", who); 10595817Sjan PMD(PMD_SX, ("%s() %d cpu started " 10605817Sjan "but not running in the kernel yet\n", 10615817Sjan str, who)) 10625817Sjan } else if (delays > 2000) { 10635817Sjan /* 10645817Sjan * We waited at least 20 seconds, bail .. 10655817Sjan */ 10665817Sjan cmn_err(CE_WARN, "cpu%d: timed out", who); 10675817Sjan PMD(PMD_SX, ("%s() %d cpu timed out\n", 10685817Sjan str, who)) 10695817Sjan return (0); 10705817Sjan } 10715817Sjan 10725817Sjan /* 10735817Sjan * wait at least 10ms, then check again.. 10745817Sjan */ 10755817Sjan drv_usecwait(10000); 10765817Sjan } 10775817Sjan 10785817Sjan return (1); 10795817Sjan } 1080*9989SJoseph.Townsend@Sun.COM 1081*9989SJoseph.Townsend@Sun.COM static void 1082*9989SJoseph.Townsend@Sun.COM i_cpr_save_stack(kthread_t *t, wc_cpu_t *wc_cpu) 1083*9989SJoseph.Townsend@Sun.COM { 1084*9989SJoseph.Townsend@Sun.COM size_t stack_size; /* size of stack */ 1085*9989SJoseph.Townsend@Sun.COM caddr_t start = CPR_GET_STACK_START(t); /* stack start */ 1086*9989SJoseph.Townsend@Sun.COM caddr_t end = CPR_GET_STACK_END(t); /* stack end */ 1087*9989SJoseph.Townsend@Sun.COM 1088*9989SJoseph.Townsend@Sun.COM stack_size = (size_t)end - (size_t)start; 1089*9989SJoseph.Townsend@Sun.COM 1090*9989SJoseph.Townsend@Sun.COM if (wc_cpu->wc_saved_stack_size < stack_size) { 1091*9989SJoseph.Townsend@Sun.COM if (wc_cpu->wc_saved_stack != NULL) { 1092*9989SJoseph.Townsend@Sun.COM kmem_free(wc_cpu->wc_saved_stack, 1093*9989SJoseph.Townsend@Sun.COM wc_cpu->wc_saved_stack_size); 1094*9989SJoseph.Townsend@Sun.COM } 1095*9989SJoseph.Townsend@Sun.COM wc_cpu->wc_saved_stack = kmem_zalloc(stack_size, KM_SLEEP); 1096*9989SJoseph.Townsend@Sun.COM wc_cpu->wc_saved_stack_size = stack_size; 1097*9989SJoseph.Townsend@Sun.COM } 1098*9989SJoseph.Townsend@Sun.COM 1099*9989SJoseph.Townsend@Sun.COM bcopy(start, wc_cpu->wc_saved_stack, stack_size); 1100*9989SJoseph.Townsend@Sun.COM } 1101*9989SJoseph.Townsend@Sun.COM 1102*9989SJoseph.Townsend@Sun.COM void 1103*9989SJoseph.Townsend@Sun.COM i_cpr_restore_stack(kthread_t *t, greg_t *save_stack) 1104*9989SJoseph.Townsend@Sun.COM { 1105*9989SJoseph.Townsend@Sun.COM size_t stack_size; /* size of stack */ 1106*9989SJoseph.Townsend@Sun.COM caddr_t start = CPR_GET_STACK_START(t); /* stack start */ 1107*9989SJoseph.Townsend@Sun.COM caddr_t end = CPR_GET_STACK_END(t); /* stack end */ 1108*9989SJoseph.Townsend@Sun.COM 1109*9989SJoseph.Townsend@Sun.COM stack_size = (size_t)end - (size_t)start; 1110*9989SJoseph.Townsend@Sun.COM 1111*9989SJoseph.Townsend@Sun.COM bcopy(save_stack, start, stack_size); 1112*9989SJoseph.Townsend@Sun.COM } 1113