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 /*
2212826Skuriakose.kuruvilla@oracle.com * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235295Srandyf */
245295Srandyf
255295Srandyf /*
265295Srandyf * Platform specific implementation code
275295Srandyf * Currently only suspend to RAM is supported (ACPI S3)
285295Srandyf */
295295Srandyf
305295Srandyf #define SUNDDI_IMPL
315295Srandyf
325295Srandyf #include <sys/types.h>
335295Srandyf #include <sys/promif.h>
345295Srandyf #include <sys/prom_isa.h>
355295Srandyf #include <sys/prom_plat.h>
365295Srandyf #include <sys/cpuvar.h>
375295Srandyf #include <sys/pte.h>
385295Srandyf #include <vm/hat.h>
395295Srandyf #include <vm/page.h>
405295Srandyf #include <vm/as.h>
415295Srandyf #include <sys/cpr.h>
425295Srandyf #include <sys/kmem.h>
435295Srandyf #include <sys/clock.h>
445295Srandyf #include <sys/kmem.h>
455295Srandyf #include <sys/panic.h>
465295Srandyf #include <vm/seg_kmem.h>
475295Srandyf #include <sys/cpu_module.h>
485295Srandyf #include <sys/callb.h>
495295Srandyf #include <sys/machsystm.h>
505295Srandyf #include <sys/vmsystm.h>
515295Srandyf #include <sys/systm.h>
525295Srandyf #include <sys/archsystm.h>
535295Srandyf #include <sys/stack.h>
545295Srandyf #include <sys/fs/ufs_fs.h>
555295Srandyf #include <sys/memlist.h>
565295Srandyf #include <sys/bootconf.h>
575295Srandyf #include <sys/thread.h>
585295Srandyf #include <sys/x_call.h>
595295Srandyf #include <sys/smp_impldefs.h>
605295Srandyf #include <vm/vm_dep.h>
615295Srandyf #include <sys/psm.h>
625295Srandyf #include <sys/epm.h>
635295Srandyf #include <sys/cpr_wakecode.h>
645295Srandyf #include <sys/x86_archext.h>
655295Srandyf #include <sys/reboot.h>
665295Srandyf #include <sys/acpi/acpi.h>
675295Srandyf #include <sys/acpica.h>
68*13134Skuriakose.kuruvilla@oracle.com #include <sys/fp.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
969989SJoseph.Townsend@Sun.COM static void i_cpr_save_stack(kthread_t *t, wc_cpu_t *wc_cpu);
979989SJoseph.Townsend@Sun.COM void i_cpr_restore_stack(kthread_t *t, greg_t *save_stack);
989989SJoseph.Townsend@Sun.COM
999989SJoseph.Townsend@Sun.COM #ifdef STACK_GROWTH_DOWN
1009989SJoseph.Townsend@Sun.COM #define CPR_GET_STACK_START(t) ((t)->t_stkbase)
1019989SJoseph.Townsend@Sun.COM #define CPR_GET_STACK_END(t) ((t)->t_stk)
1029989SJoseph.Townsend@Sun.COM #else
1039989SJoseph.Townsend@Sun.COM #define CPR_GET_STACK_START(t) ((t)->t_stk)
1049989SJoseph.Townsend@Sun.COM #define CPR_GET_STACK_END(t) ((t)->t_stkbase)
1059989SJoseph.Townsend@Sun.COM #endif /* STACK_GROWTH_DOWN */
1069989SJoseph.Townsend@Sun.COM
1075295Srandyf /*
1085295Srandyf * restart paused slave cpus
1095295Srandyf */
1105295Srandyf void
i_cpr_machdep_setup(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
i_cpr_stop_intr(void)1265295Srandyf i_cpr_stop_intr(void)
1275295Srandyf {
1285295Srandyf (void) spl7();
1295295Srandyf }
1305295Srandyf
1315295Srandyf /*
1325295Srandyf * Set machine up to take interrupts
1335295Srandyf */
1345295Srandyf void
i_cpr_enable_intr(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
i_cpr_save_machdep_info(void)1465295Srandyf i_cpr_save_machdep_info(void)
1475295Srandyf {
1485295Srandyf int notcalled = 0;
1495295Srandyf ASSERT(notcalled);
1505295Srandyf }
1515295Srandyf
1525295Srandyf
1535295Srandyf void
i_cpr_set_tbr(void)1545295Srandyf i_cpr_set_tbr(void)
1555295Srandyf {
1565295Srandyf }
1575295Srandyf
1585295Srandyf
1595295Srandyf processorid_t
i_cpr_bootcpuid(void)1605295Srandyf i_cpr_bootcpuid(void)
1615295Srandyf {
1625295Srandyf return (0);
1635295Srandyf }
1645295Srandyf
1655295Srandyf /*
1665295Srandyf * cpu0 should contain bootcpu info
1675295Srandyf */
1685295Srandyf cpu_t *
i_cpr_bootcpu(void)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 *
i_cpr_save_context(void * arg)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;
1869989SJoseph.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
1929989SJoseph.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
2009989SJoseph.Townsend@Sun.COM i_cpr_save_stack(curthread, wc_cpu);
2019989SJoseph.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 */
2079989SJoseph.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 *
map_warm_reset_vector()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
i_cpr_pre_resume_cpus()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
34012004Sjiang.liu@intel.com for (who = 0; who < max_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
36612004Sjiang.liu@intel.com mutex_enter(&cpu_lock);
36712004Sjiang.liu@intel.com err = mach_cpuid_start(who, rm_platter_va);
36812004Sjiang.liu@intel.com mutex_exit(&cpu_lock);
36912004Sjiang.liu@intel.com if (err != 0) {
3705295Srandyf cmn_err(CE_WARN, "cpu%d: failed to start during "
3715295Srandyf "suspend/resume error %d", who, err);
3725295Srandyf continue;
3735295Srandyf }
3745295Srandyf
3756336Sbholler PMD(PMD_SX, ("%s() #1 waiting for %d in procset\n", str, who))
3765295Srandyf
3775817Sjan if (!wait_for_set(&procset, who))
3785817Sjan continue;
3795295Srandyf
3805295Srandyf PMD(PMD_SX, ("%s() %d cpu started\n", str, who))
3815295Srandyf
3825817Sjan PMD(PMD_SX, ("%s() tsc_ready = %d\n", str, get_tsc_ready()))
3835295Srandyf
3845295Srandyf if (tsc_gethrtime_enable) {
3855295Srandyf PMD(PMD_SX, ("%s() calling tsc_sync_master\n", str))
3865295Srandyf tsc_sync_master(who);
3875295Srandyf }
3885295Srandyf
3896336Sbholler PMD(PMD_SX, ("%s() waiting for %d in cpu_ready_set\n", str,
3906336Sbholler who))
3915295Srandyf /*
3925295Srandyf * Wait for cpu to declare that it is ready, we want the
3935295Srandyf * cpus to start serially instead of in parallel, so that
3945295Srandyf * they do not contend with each other in wc_rm_start()
3955295Srandyf */
3965817Sjan if (!wait_for_set(&cpu_ready_set, who))
3975817Sjan continue;
3985295Srandyf
3995295Srandyf /*
4005295Srandyf * do not need to re-initialize dtrace using dtrace_cpu_init
4015295Srandyf * function
4025295Srandyf */
4035295Srandyf PMD(PMD_SX, ("%s() cpu %d now ready\n", str, who))
4045295Srandyf }
4055295Srandyf
4065295Srandyf affinity_clear();
4075295Srandyf
4085295Srandyf PMD(PMD_SX, ("%s() all cpus now ready\n", str))
4095817Sjan
4105295Srandyf }
4115295Srandyf
4125295Srandyf static void
unmap_warm_reset_vector(ushort_t * warm_reset_vector)4135295Srandyf unmap_warm_reset_vector(ushort_t *warm_reset_vector)
4145295Srandyf {
4155295Srandyf psm_unmap_phys((caddr_t)warm_reset_vector, sizeof (ushort_t *));
4165295Srandyf }
4175295Srandyf
4185295Srandyf /*
4195295Srandyf * We need to setup a 1:1 (virtual to physical) mapping for the
4205295Srandyf * page containing the wakeup code.
4215295Srandyf */
4225295Srandyf static struct as *save_as; /* when switching to kas */
4235295Srandyf
4245295Srandyf static void
unmap_wakeaddr_1to1(uint64_t wakephys)4255295Srandyf unmap_wakeaddr_1to1(uint64_t wakephys)
4265295Srandyf {
4275295Srandyf uintptr_t wp = (uintptr_t)wakephys;
4285295Srandyf hat_setup(save_as->a_hat, 0); /* switch back from kernel hat */
4295295Srandyf hat_unload(kas.a_hat, (caddr_t)wp, PAGESIZE, HAT_UNLOAD);
4305295Srandyf }
4315295Srandyf
4325295Srandyf void
i_cpr_post_resume_cpus()4335295Srandyf i_cpr_post_resume_cpus()
4345295Srandyf {
4355295Srandyf uint64_t wakephys = rm_platter_pa;
4365295Srandyf
4375295Srandyf if (warm_reset_vector != NULL)
4385295Srandyf unmap_warm_reset_vector(warm_reset_vector);
4395295Srandyf
4405295Srandyf hat_unload(kas.a_hat, (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE,
4415295Srandyf HAT_UNLOAD);
4425295Srandyf
4435295Srandyf /*
4445295Srandyf * cmi_post_mpstartup() is only required upon boot not upon
4455295Srandyf * resume from RAM
4465295Srandyf */
4475295Srandyf
4485295Srandyf PT(PT_UNDO1to1);
4495295Srandyf /* Tear down 1:1 mapping for wakeup code */
4505295Srandyf unmap_wakeaddr_1to1(wakephys);
4515295Srandyf }
4525295Srandyf
4535295Srandyf /* ARGSUSED */
4545295Srandyf void
i_cpr_handle_xc(int flag)4555295Srandyf i_cpr_handle_xc(int flag)
4565295Srandyf {
4575295Srandyf }
4585295Srandyf
4595295Srandyf int
i_cpr_reusable_supported(void)4605295Srandyf i_cpr_reusable_supported(void)
4615295Srandyf {
4625295Srandyf return (0);
4635295Srandyf }
4645295Srandyf static void
map_wakeaddr_1to1(uint64_t wakephys)4655295Srandyf map_wakeaddr_1to1(uint64_t wakephys)
4665295Srandyf {
4675295Srandyf uintptr_t wp = (uintptr_t)wakephys;
4685295Srandyf hat_devload(kas.a_hat, (caddr_t)wp, PAGESIZE, btop(wakephys),
4695295Srandyf (PROT_READ|PROT_WRITE|PROT_EXEC|HAT_STORECACHING_OK|HAT_NOSYNC),
4705295Srandyf HAT_LOAD);
4715295Srandyf save_as = curthread->t_procp->p_as;
4725295Srandyf hat_setup(kas.a_hat, 0); /* switch to kernel-only hat */
4735295Srandyf }
4745295Srandyf
4755295Srandyf
4765295Srandyf void
prt_other_cpus()4775295Srandyf prt_other_cpus()
4785295Srandyf {
4795295Srandyf int who;
4805295Srandyf
4815295Srandyf if (ncpus == 1) {
4825295Srandyf PMD(PMD_SX, ("prt_other_cpus() other cpu table empty for "
4835295Srandyf "uniprocessor machine\n"))
4845295Srandyf return;
4855295Srandyf }
4865295Srandyf
48712004Sjiang.liu@intel.com for (who = 0; who < max_ncpus; who++) {
4885295Srandyf
4895295Srandyf wc_cpu_t *cpup = wc_other_cpus + who;
4905295Srandyf
49112004Sjiang.liu@intel.com if (!CPU_IN_SET(mp_cpus, who))
49212004Sjiang.liu@intel.com continue;
49312004Sjiang.liu@intel.com
4945295Srandyf PMD(PMD_SX, ("prt_other_cpus() who = %d, gdt=%p:%x, "
4955295Srandyf "idt=%p:%x, ldt=%lx, tr=%lx, kgsbase="
4965295Srandyf AFMT ", sp=%lx\n", who,
4975295Srandyf (void *)cpup->wc_gdt_base, cpup->wc_gdt_limit,
4985295Srandyf (void *)cpup->wc_idt_base, cpup->wc_idt_limit,
4995295Srandyf (long)cpup->wc_ldt, (long)cpup->wc_tr,
5005295Srandyf (long)cpup->wc_kgsbase, (long)cpup->wc_rsp))
5015295Srandyf }
5025295Srandyf }
5035295Srandyf
5045295Srandyf /*
5055295Srandyf * Power down the system.
5065295Srandyf */
5075295Srandyf int
i_cpr_power_down(int sleeptype)5085295Srandyf i_cpr_power_down(int sleeptype)
5095295Srandyf {
5105295Srandyf caddr_t wakevirt = rm_platter_va;
5115295Srandyf uint64_t wakephys = rm_platter_pa;
5126336Sbholler ulong_t saved_intr;
5135295Srandyf uint32_t code_length = 0;
5145295Srandyf wc_desctbr_t gdt;
5155295Srandyf /*LINTED*/
5165295Srandyf wakecode_t *wp = (wakecode_t *)wakevirt;
5175295Srandyf /*LINTED*/
5185295Srandyf rm_platter_t *wcpp = (rm_platter_t *)wakevirt;
5195295Srandyf wc_cpu_t *cpup = &(wp->wc_cpu);
5205295Srandyf dev_info_t *ppm;
5215295Srandyf int ret = 0;
5225295Srandyf power_req_t power_req;
5235295Srandyf char *str = "i_cpr_power_down";
5245295Srandyf #if defined(__amd64)
5255295Srandyf /*LINTED*/
5265295Srandyf rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va;
5275295Srandyf #endif
5285295Srandyf extern int cpr_suspend_succeeded;
5295295Srandyf extern void kernel_wc_code();
5305295Srandyf
5315295Srandyf ASSERT(sleeptype == CPR_TORAM);
5325295Srandyf ASSERT(CPU->cpu_id == 0);
5335295Srandyf
5345295Srandyf if ((ppm = PPM(ddi_root_node())) == NULL) {
5355295Srandyf PMD(PMD_SX, ("%s: root node not claimed\n", str))
5365295Srandyf return (ENOTTY);
5375295Srandyf }
5385295Srandyf
5395295Srandyf PMD(PMD_SX, ("Entering %s()\n", str))
5405295Srandyf
5415295Srandyf PT(PT_IC);
5425295Srandyf saved_intr = intr_clear();
5435295Srandyf
5445295Srandyf PT(PT_1to1);
5455295Srandyf /* Setup 1:1 mapping for wakeup code */
5465295Srandyf map_wakeaddr_1to1(wakephys);
5475295Srandyf
5485295Srandyf PMD(PMD_SX, ("ncpus=%d\n", ncpus))
5495295Srandyf
5505295Srandyf PMD(PMD_SX, ("wc_rm_end - wc_rm_start=%lx WC_CODESIZE=%x\n",
5515295Srandyf ((size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)), WC_CODESIZE))
5525295Srandyf
5535295Srandyf PMD(PMD_SX, ("wakevirt=%p, wakephys=%x\n",
5545295Srandyf (void *)wakevirt, (uint_t)wakephys))
5555295Srandyf
5565295Srandyf ASSERT(((size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start)) <
5575295Srandyf WC_CODESIZE);
5585295Srandyf
5595295Srandyf bzero(wakevirt, PAGESIZE);
5605295Srandyf
5615295Srandyf /* Copy code to rm_platter */
5625295Srandyf bcopy((caddr_t)wc_rm_start, wakevirt,
5635295Srandyf (size_t)((uint_t)wc_rm_end - (uint_t)wc_rm_start));
5645295Srandyf
5655295Srandyf prt_other_cpus();
5665295Srandyf
5675295Srandyf #if defined(__amd64)
5685295Srandyf
5695295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n",
5705295Srandyf (ulong_t)real_mode_platter->rm_cr4, (ulong_t)getcr4()))
5715295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n",
5725295Srandyf (ulong_t)real_mode_platter->rm_pdbr, getcr3()))
5735295Srandyf
5745295Srandyf real_mode_platter->rm_cr4 = getcr4();
5755295Srandyf real_mode_platter->rm_pdbr = getcr3();
5765295Srandyf
5775295Srandyf rmp_gdt_init(real_mode_platter);
5785295Srandyf
5795295Srandyf /*
5805295Srandyf * Since the CPU needs to jump to protected mode using an identity
5815295Srandyf * mapped address, we need to calculate it here.
5825295Srandyf */
5835295Srandyf real_mode_platter->rm_longmode64_addr = rm_platter_pa +
5845295Srandyf ((uint32_t)wc_long_mode_64 - (uint32_t)wc_rm_start);
5855295Srandyf
5865295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n",
5875295Srandyf (ulong_t)real_mode_platter->rm_cr4, getcr4()))
5885295Srandyf
5895295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n",
5905295Srandyf (ulong_t)real_mode_platter->rm_pdbr, getcr3()))
5915295Srandyf
5925295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_longmode64_addr=%lx\n",
5935295Srandyf (ulong_t)real_mode_platter->rm_longmode64_addr))
5945295Srandyf
5955295Srandyf #endif
5965295Srandyf
5975295Srandyf PT(PT_SC);
5985295Srandyf if (wc_save_context(cpup)) {
5995295Srandyf
6005295Srandyf ret = i_cpr_platform_alloc(&(wc_other_cpus->wc_apic_state));
6015295Srandyf if (ret != 0)
6025295Srandyf return (ret);
6035295Srandyf
6045295Srandyf ret = i_cpr_save_apic(&(wc_other_cpus->wc_apic_state));
6055295Srandyf PMD(PMD_SX, ("%s: i_cpr_save_apic() returned %d\n", str, ret))
6065295Srandyf if (ret != 0)
6075295Srandyf return (ret);
6085295Srandyf
6095295Srandyf PMD(PMD_SX, ("wakephys=%x, kernel_wc_code=%p\n",
6105295Srandyf (uint_t)wakephys, (void *)&kernel_wc_code))
6115295Srandyf PMD(PMD_SX, ("virtaddr=%lx, retaddr=%lx\n",
6125295Srandyf (long)cpup->wc_virtaddr, (long)cpup->wc_retaddr))
6135295Srandyf PMD(PMD_SX, ("ebx=%x, edi=%x, esi=%x, ebp=%x, esp=%x\n",
6145295Srandyf cpup->wc_ebx, cpup->wc_edi, cpup->wc_esi, cpup->wc_ebp,
6155295Srandyf cpup->wc_esp))
6165295Srandyf PMD(PMD_SX, ("cr0=%lx, cr3=%lx, cr4=%lx\n",
6175295Srandyf (long)cpup->wc_cr0, (long)cpup->wc_cr3,
6185295Srandyf (long)cpup->wc_cr4))
6195295Srandyf PMD(PMD_SX, ("cs=%x, ds=%x, es=%x, ss=%x, fs=%lx, gs=%lx, "
6205295Srandyf "flgs=%lx\n", cpup->wc_cs, cpup->wc_ds, cpup->wc_es,
6215295Srandyf cpup->wc_ss, (long)cpup->wc_fs, (long)cpup->wc_gs,
6225295Srandyf (long)cpup->wc_eflags))
6235295Srandyf
6245295Srandyf PMD(PMD_SX, ("gdt=%p:%x, idt=%p:%x, ldt=%lx, tr=%lx, "
6255295Srandyf "kgbase=%lx\n", (void *)cpup->wc_gdt_base,
6265295Srandyf cpup->wc_gdt_limit, (void *)cpup->wc_idt_base,
6275295Srandyf cpup->wc_idt_limit, (long)cpup->wc_ldt,
6285295Srandyf (long)cpup->wc_tr, (long)cpup->wc_kgsbase))
6295295Srandyf
6305295Srandyf gdt.base = cpup->wc_gdt_base;
6315295Srandyf gdt.limit = cpup->wc_gdt_limit;
6325295Srandyf
6335295Srandyf #if defined(__amd64)
6345295Srandyf code_length = (uint32_t)wc_long_mode_64 -
6355295Srandyf (uint32_t)wc_rm_start;
6365295Srandyf #else
6375295Srandyf code_length = 0;
6385295Srandyf #endif
6395295Srandyf
6405295Srandyf init_real_mode_platter(0, code_length, cpup->wc_cr4, gdt);
6415295Srandyf
6425295Srandyf #if defined(__amd64)
6435295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_cr4=%lx, getcr4()=%lx\n",
6445295Srandyf (ulong_t)wcpp->rm_cr4, getcr4()))
6455295Srandyf
6465295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_pdbr=%lx, getcr3()=%lx\n",
6475295Srandyf (ulong_t)wcpp->rm_pdbr, getcr3()))
6485295Srandyf
6495295Srandyf PMD(PMD_SX, ("real_mode_platter->rm_longmode64_addr=%lx\n",
6505295Srandyf (ulong_t)wcpp->rm_longmode64_addr))
6515295Srandyf
6525295Srandyf PMD(PMD_SX,
6535295Srandyf ("real_mode_platter->rm_temp_gdt[TEMPGDT_KCODE64]=%lx\n",
6545295Srandyf (ulong_t)wcpp->rm_temp_gdt[TEMPGDT_KCODE64]))
6555295Srandyf #endif
6565295Srandyf
6575295Srandyf PMD(PMD_SX, ("gdt=%p:%x, idt=%p:%x, ldt=%lx, tr=%lx, "
6585295Srandyf "kgsbase=%lx\n", (void *)wcpp->rm_gdt_base,
6595295Srandyf wcpp->rm_gdt_lim, (void *)wcpp->rm_idt_base,
6605295Srandyf wcpp->rm_idt_lim, (long)cpup->wc_ldt, (long)cpup->wc_tr,
6615295Srandyf (long)cpup->wc_kgsbase))
6625295Srandyf
6635295Srandyf power_req.request_type = PMR_PPM_ENTER_SX;
6645295Srandyf power_req.req.ppm_power_enter_sx_req.sx_state = S3;
6655295Srandyf power_req.req.ppm_power_enter_sx_req.test_point =
6665295Srandyf cpr_test_point;
6675295Srandyf power_req.req.ppm_power_enter_sx_req.wakephys = wakephys;
6685295Srandyf
6695295Srandyf PMD(PMD_SX, ("%s: pm_ctlops PMR_PPM_ENTER_SX\n", str))
6705295Srandyf PT(PT_PPMCTLOP);
6715295Srandyf (void) pm_ctlops(ppm, ddi_root_node(), DDI_CTLOPS_POWER,
6725295Srandyf &power_req, &ret);
6735295Srandyf PMD(PMD_SX, ("%s: returns %d\n", str, ret))
6745295Srandyf
6755295Srandyf /*
6765295Srandyf * If it works, we get control back to the else branch below
6775295Srandyf * If we get control back here, it didn't work.
6785295Srandyf * XXX return EINVAL here?
6795295Srandyf */
6805295Srandyf
6815295Srandyf unmap_wakeaddr_1to1(wakephys);
6825295Srandyf intr_restore(saved_intr);
6835295Srandyf
6845295Srandyf return (ret);
6855295Srandyf } else {
6865295Srandyf cpr_suspend_succeeded = 1;
6875295Srandyf
6885295Srandyf power_req.request_type = PMR_PPM_EXIT_SX;
6895295Srandyf power_req.req.ppm_power_enter_sx_req.sx_state = S3;
6905295Srandyf
6915295Srandyf PMD(PMD_SX, ("%s: pm_ctlops PMR_PPM_EXIT_SX\n", str))
6925295Srandyf PT(PT_PPMCTLOP);
6935295Srandyf (void) pm_ctlops(ppm, ddi_root_node(), DDI_CTLOPS_POWER,
6945295Srandyf &power_req, &ret);
6955295Srandyf PMD(PMD_SX, ("%s: returns %d\n", str, ret))
6965295Srandyf
6975295Srandyf ret = i_cpr_restore_apic(&(wc_other_cpus->wc_apic_state));
6985295Srandyf /*
6995295Srandyf * the restore should never fail, if the saved suceeded
7005295Srandyf */
7015295Srandyf ASSERT(ret == 0);
7025295Srandyf
7035295Srandyf i_cpr_platform_free(&(wc_other_cpus->wc_apic_state));
7045295Srandyf
7057113Sbholler /*
7067113Sbholler * Enable interrupts on boot cpu.
7077113Sbholler */
7087113Sbholler ASSERT(CPU->cpu_id == i_cpr_bootcpuid());
7097113Sbholler mutex_enter(&cpu_lock);
7107113Sbholler cpu_enable_intr(CPU);
7117113Sbholler mutex_exit(&cpu_lock);
7127113Sbholler
7135295Srandyf PT(PT_INTRRESTORE);
7145295Srandyf intr_restore(saved_intr);
7155295Srandyf PT(PT_CPU);
7165295Srandyf
7175295Srandyf return (ret);
7185295Srandyf }
7195295Srandyf }
7205295Srandyf
7215295Srandyf /*
7225295Srandyf * Stop all other cpu's before halting or rebooting. We pause the cpu's
7235295Srandyf * instead of sending a cross call.
7245295Srandyf * Stolen from sun4/os/mp_states.c
7255295Srandyf */
7265295Srandyf
7275295Srandyf static int cpu_are_paused; /* sic */
7285295Srandyf
7295295Srandyf void
i_cpr_stop_other_cpus(void)7305295Srandyf i_cpr_stop_other_cpus(void)
7315295Srandyf {
7325295Srandyf mutex_enter(&cpu_lock);
7335295Srandyf if (cpu_are_paused) {
7345295Srandyf mutex_exit(&cpu_lock);
7355295Srandyf return;
7365295Srandyf }
7375295Srandyf pause_cpus(NULL);
7385295Srandyf cpu_are_paused = 1;
7395295Srandyf
7405295Srandyf mutex_exit(&cpu_lock);
7415295Srandyf }
7425295Srandyf
7435295Srandyf int
i_cpr_is_supported(int sleeptype)7445295Srandyf i_cpr_is_supported(int sleeptype)
7455295Srandyf {
7465295Srandyf extern int cpr_supported_override;
7475295Srandyf extern int cpr_platform_enable;
7485295Srandyf extern int pm_S3_enabled;
7495295Srandyf
7505295Srandyf if (sleeptype != CPR_TORAM)
7515295Srandyf return (0);
7525295Srandyf
7535295Srandyf /*
7545295Srandyf * The next statement tests if a specific platform has turned off
7555295Srandyf * cpr support.
7565295Srandyf */
7575295Srandyf if (cpr_supported_override)
7585295Srandyf return (0);
7595295Srandyf
7605295Srandyf /*
7615295Srandyf * If a platform has specifically turned on cpr support ...
7625295Srandyf */
7635295Srandyf if (cpr_platform_enable)
7645295Srandyf return (1);
7655295Srandyf
7665295Srandyf return (pm_S3_enabled);
7675295Srandyf }
7685295Srandyf
7695295Srandyf void
i_cpr_bitmap_cleanup(void)7705295Srandyf i_cpr_bitmap_cleanup(void)
7715295Srandyf {
7725295Srandyf }
7735295Srandyf
7745295Srandyf void
i_cpr_free_memory_resources(void)7755295Srandyf i_cpr_free_memory_resources(void)
7765295Srandyf {
7775295Srandyf }
7785295Srandyf
7795295Srandyf /*
7805295Srandyf * Needed only for S3 so far
7815295Srandyf */
7825295Srandyf static int
i_cpr_platform_alloc(psm_state_request_t * req)7835295Srandyf i_cpr_platform_alloc(psm_state_request_t *req)
7845295Srandyf {
7857515SSeth.Goldberg@Sun.COM #ifdef DEBUG
7865295Srandyf char *str = "i_cpr_platform_alloc";
7877515SSeth.Goldberg@Sun.COM #endif
7885295Srandyf
7895295Srandyf PMD(PMD_SX, ("cpu = %d, %s(%p) \n", CPU->cpu_id, str, (void *)req))
7905295Srandyf
7917515SSeth.Goldberg@Sun.COM if (psm_state == NULL) {
7927515SSeth.Goldberg@Sun.COM PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
7935295Srandyf return (0);
7945295Srandyf }
7955295Srandyf
7965295Srandyf req->psr_cmd = PSM_STATE_ALLOC;
7975295Srandyf return ((*psm_state)(req));
7985295Srandyf }
7995295Srandyf
8005295Srandyf /*
8015295Srandyf * Needed only for S3 so far
8025295Srandyf */
8035295Srandyf static void
i_cpr_platform_free(psm_state_request_t * req)8045295Srandyf i_cpr_platform_free(psm_state_request_t *req)
8055295Srandyf {
8067515SSeth.Goldberg@Sun.COM #ifdef DEBUG
8075295Srandyf char *str = "i_cpr_platform_free";
8087515SSeth.Goldberg@Sun.COM #endif
8095295Srandyf
8105295Srandyf PMD(PMD_SX, ("cpu = %d, %s(%p) \n", CPU->cpu_id, str, (void *)req))
8115295Srandyf
8127515SSeth.Goldberg@Sun.COM if (psm_state == NULL) {
8137515SSeth.Goldberg@Sun.COM PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
8147515SSeth.Goldberg@Sun.COM return;
8155295Srandyf }
8165295Srandyf
8175295Srandyf req->psr_cmd = PSM_STATE_FREE;
8185295Srandyf (void) (*psm_state)(req);
8195295Srandyf }
8205295Srandyf
8215295Srandyf static int
i_cpr_save_apic(psm_state_request_t * req)8225295Srandyf i_cpr_save_apic(psm_state_request_t *req)
8235295Srandyf {
8247515SSeth.Goldberg@Sun.COM #ifdef DEBUG
8255295Srandyf char *str = "i_cpr_save_apic";
8267515SSeth.Goldberg@Sun.COM #endif
8275295Srandyf
8287515SSeth.Goldberg@Sun.COM if (psm_state == NULL) {
8297515SSeth.Goldberg@Sun.COM PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
8305295Srandyf return (0);
8315295Srandyf }
8325295Srandyf
8335295Srandyf req->psr_cmd = PSM_STATE_SAVE;
8345295Srandyf return ((*psm_state)(req));
8355295Srandyf }
8365295Srandyf
8375295Srandyf static int
i_cpr_restore_apic(psm_state_request_t * req)8385295Srandyf i_cpr_restore_apic(psm_state_request_t *req)
8395295Srandyf {
8407515SSeth.Goldberg@Sun.COM #ifdef DEBUG
8415295Srandyf char *str = "i_cpr_restore_apic";
8427515SSeth.Goldberg@Sun.COM #endif
8435295Srandyf
8447515SSeth.Goldberg@Sun.COM if (psm_state == NULL) {
8457515SSeth.Goldberg@Sun.COM PMD(PMD_SX, ("%s() : psm_state == NULL\n", str))
8465295Srandyf return (0);
8475295Srandyf }
8485295Srandyf
8495295Srandyf req->psr_cmd = PSM_STATE_RESTORE;
8505295Srandyf return ((*psm_state)(req));
8515295Srandyf }
8525295Srandyf
8535295Srandyf
8545295Srandyf /* stop lint complaining about offset not being used in 32bit mode */
8555295Srandyf #if !defined(__amd64)
8565295Srandyf /*ARGSUSED*/
8575295Srandyf #endif
8585295Srandyf static void
init_real_mode_platter(int cpun,uint32_t offset,uint_t cr4,wc_desctbr_t gdt)8595295Srandyf init_real_mode_platter(int cpun, uint32_t offset, uint_t cr4, wc_desctbr_t gdt)
8605295Srandyf {
8615295Srandyf /*LINTED*/
8625295Srandyf rm_platter_t *real_mode_platter = (rm_platter_t *)rm_platter_va;
8635295Srandyf
8645295Srandyf /*
8655295Srandyf * Fill up the real mode platter to make it easy for real mode code to
8665295Srandyf * kick it off. This area should really be one passed by boot to kernel
8675295Srandyf * and guaranteed to be below 1MB and aligned to 16 bytes. Should also
8685295Srandyf * have identical physical and virtual address in paged mode.
8695295Srandyf */
8705295Srandyf
8715295Srandyf real_mode_platter->rm_pdbr = getcr3();
8725295Srandyf real_mode_platter->rm_cpu = cpun;
8735295Srandyf real_mode_platter->rm_cr4 = cr4;
8745295Srandyf
8755295Srandyf real_mode_platter->rm_gdt_base = gdt.base;
8765295Srandyf real_mode_platter->rm_gdt_lim = gdt.limit;
8775295Srandyf
8785295Srandyf #if defined(__amd64)
8795295Srandyf if (getcr3() > 0xffffffffUL)
8805295Srandyf panic("Cannot initialize CPUs; kernel's 64-bit page tables\n"
8815295Srandyf "located above 4G in physical memory (@ 0x%llx).",
8825295Srandyf (unsigned long long)getcr3());
8835295Srandyf
8845295Srandyf /*
8855295Srandyf * Setup pseudo-descriptors for temporary GDT and IDT for use ONLY
8865295Srandyf * by code in real_mode_start():
8875295Srandyf *
8885295Srandyf * GDT[0]: NULL selector
8895295Srandyf * GDT[1]: 64-bit CS: Long = 1, Present = 1, bits 12, 11 = 1
8905295Srandyf *
8915295Srandyf * Clear the IDT as interrupts will be off and a limit of 0 will cause
8925295Srandyf * the CPU to triple fault and reset on an NMI, seemingly as reasonable
8935295Srandyf * a course of action as any other, though it may cause the entire
8945295Srandyf * platform to reset in some cases...
8955295Srandyf */
8965295Srandyf real_mode_platter->rm_temp_gdt[0] = 0ULL;
8975295Srandyf real_mode_platter->rm_temp_gdt[TEMPGDT_KCODE64] = 0x20980000000000ULL;
8985295Srandyf
8995295Srandyf real_mode_platter->rm_temp_gdt_lim = (ushort_t)
9005295Srandyf (sizeof (real_mode_platter->rm_temp_gdt) - 1);
9015295Srandyf real_mode_platter->rm_temp_gdt_base = rm_platter_pa +
9025295Srandyf (uint32_t)(&((rm_platter_t *)0)->rm_temp_gdt);
9035295Srandyf
9045295Srandyf real_mode_platter->rm_temp_idt_lim = 0;
9055295Srandyf real_mode_platter->rm_temp_idt_base = 0;
9065295Srandyf
9075295Srandyf /*
9085295Srandyf * Since the CPU needs to jump to protected mode using an identity
9095295Srandyf * mapped address, we need to calculate it here.
9105295Srandyf */
9115295Srandyf real_mode_platter->rm_longmode64_addr = rm_platter_pa + offset;
9125295Srandyf #endif /* __amd64 */
9135295Srandyf
9145295Srandyf /* return; */
9155295Srandyf }
9165295Srandyf
9175295Srandyf void
i_cpr_start_cpu(void)9185295Srandyf i_cpr_start_cpu(void)
9195295Srandyf {
9205295Srandyf
9215295Srandyf struct cpu *cp = CPU;
9225295Srandyf
9235295Srandyf char *str = "i_cpr_start_cpu";
9245295Srandyf extern void init_cpu_syscall(struct cpu *cp);
9255295Srandyf
9265295Srandyf PMD(PMD_SX, ("%s() called\n", str))
9275295Srandyf
9285295Srandyf PMD(PMD_SX, ("%s() #0 cp->cpu_base_spl %d\n", str,
9295295Srandyf cp->cpu_base_spl))
9305295Srandyf
9315295Srandyf mutex_enter(&cpu_lock);
9325295Srandyf if (cp == i_cpr_bootcpu()) {
9335295Srandyf mutex_exit(&cpu_lock);
9345295Srandyf PMD(PMD_SX,
9355295Srandyf ("%s() called on bootcpu nothing to do!\n", str))
9365295Srandyf return;
9375295Srandyf }
9385295Srandyf mutex_exit(&cpu_lock);
9395295Srandyf
9405295Srandyf /*
9415295Srandyf * We need to Sync PAT with cpu0's PAT. We have to do
9425295Srandyf * this with interrupts disabled.
9435295Srandyf */
94412826Skuriakose.kuruvilla@oracle.com if (is_x86_feature(x86_featureset, X86FSET_PAT))
9455295Srandyf pat_sync();
9465295Srandyf
9475295Srandyf /*
948*13134Skuriakose.kuruvilla@oracle.com * If we use XSAVE, we need to restore XFEATURE_ENABLE_MASK register.
949*13134Skuriakose.kuruvilla@oracle.com */
950*13134Skuriakose.kuruvilla@oracle.com if (fp_save_mech == FP_XSAVE) {
951*13134Skuriakose.kuruvilla@oracle.com setup_xfem();
952*13134Skuriakose.kuruvilla@oracle.com }
953*13134Skuriakose.kuruvilla@oracle.com
954*13134Skuriakose.kuruvilla@oracle.com /*
9555295Srandyf * Initialize this CPU's syscall handlers
9565295Srandyf */
9575295Srandyf init_cpu_syscall(cp);
9585295Srandyf
9595295Srandyf PMD(PMD_SX, ("%s() #1 cp->cpu_base_spl %d\n", str, cp->cpu_base_spl))
9605295Srandyf
9615295Srandyf /*
9625295Srandyf * Do not need to call cpuid_pass2(), cpuid_pass3(), cpuid_pass4() or
9635295Srandyf * init_cpu_info(), since the work that they do is only needed to
9645295Srandyf * be done once at boot time
9655295Srandyf */
9665295Srandyf
9675295Srandyf
9685295Srandyf mutex_enter(&cpu_lock);
9695295Srandyf CPUSET_ADD(procset, cp->cpu_id);
9705295Srandyf mutex_exit(&cpu_lock);
9715295Srandyf
9725295Srandyf PMD(PMD_SX, ("%s() #2 cp->cpu_base_spl %d\n", str,
9735295Srandyf cp->cpu_base_spl))
9745295Srandyf
9755295Srandyf if (tsc_gethrtime_enable) {
9765295Srandyf PMD(PMD_SX, ("%s() calling tsc_sync_slave\n", str))
9775295Srandyf tsc_sync_slave();
9785295Srandyf }
9795295Srandyf
9805295Srandyf PMD(PMD_SX, ("%s() cp->cpu_id %d, cp->cpu_intr_actv %d\n", str,
9815295Srandyf cp->cpu_id, cp->cpu_intr_actv))
9825295Srandyf PMD(PMD_SX, ("%s() #3 cp->cpu_base_spl %d\n", str,
9835295Srandyf cp->cpu_base_spl))
9845295Srandyf
9855295Srandyf (void) spl0(); /* enable interrupts */
9865295Srandyf
9875295Srandyf PMD(PMD_SX, ("%s() #4 cp->cpu_base_spl %d\n", str,
9885295Srandyf cp->cpu_base_spl))
9895295Srandyf
9905295Srandyf /*
9915295Srandyf * Set up the CPU module for this CPU. This can't be done before
9925295Srandyf * this CPU is made CPU_READY, because we may (in heterogeneous systems)
9935295Srandyf * need to go load another CPU module. The act of attempting to load
9945295Srandyf * a module may trigger a cross-call, which will ASSERT unless this
9955295Srandyf * cpu is CPU_READY.
9965295Srandyf */
9975295Srandyf
9985295Srandyf /*
9995295Srandyf * cmi already been init'd (during boot), so do not need to do it again
10005295Srandyf */
10015295Srandyf #ifdef PM_REINITMCAONRESUME
100212826Skuriakose.kuruvilla@oracle.com if (is_x86_feature(x86_featureset, X86FSET_MCA))
10035295Srandyf cmi_mca_init();
10045295Srandyf #endif
10055295Srandyf
10065295Srandyf PMD(PMD_SX, ("%s() returning\n", str))
10075295Srandyf
10085295Srandyf /* return; */
10095295Srandyf }
10105295Srandyf
10115295Srandyf void
i_cpr_alloc_cpus(void)10125295Srandyf i_cpr_alloc_cpus(void)
10135295Srandyf {
10145295Srandyf char *str = "i_cpr_alloc_cpus";
10155295Srandyf
10165295Srandyf PMD(PMD_SX, ("%s() CPU->cpu_id %d\n", str, CPU->cpu_id))
10175295Srandyf /*
10185295Srandyf * we allocate this only when we actually need it to save on
10195295Srandyf * kernel memory
10205295Srandyf */
10215295Srandyf
10225295Srandyf if (wc_other_cpus == NULL) {
102312004Sjiang.liu@intel.com wc_other_cpus = kmem_zalloc(max_ncpus * sizeof (wc_cpu_t),
10245295Srandyf KM_SLEEP);
10255295Srandyf }
10265295Srandyf
10275295Srandyf }
10285295Srandyf
10295295Srandyf void
i_cpr_free_cpus(void)10305295Srandyf i_cpr_free_cpus(void)
10315295Srandyf {
103211316SJoseph.Townsend@Sun.COM int index;
103311316SJoseph.Townsend@Sun.COM wc_cpu_t *wc_cpu;
103411316SJoseph.Townsend@Sun.COM
10355295Srandyf if (wc_other_cpus != NULL) {
103612004Sjiang.liu@intel.com for (index = 0; index < max_ncpus; index++) {
103711316SJoseph.Townsend@Sun.COM wc_cpu = wc_other_cpus + index;
103811316SJoseph.Townsend@Sun.COM if (wc_cpu->wc_saved_stack != NULL) {
103911316SJoseph.Townsend@Sun.COM kmem_free(wc_cpu->wc_saved_stack,
104011316SJoseph.Townsend@Sun.COM wc_cpu->wc_saved_stack_size);
104111316SJoseph.Townsend@Sun.COM }
104211316SJoseph.Townsend@Sun.COM }
104311316SJoseph.Townsend@Sun.COM
104412004Sjiang.liu@intel.com kmem_free((void *) wc_other_cpus,
104512004Sjiang.liu@intel.com max_ncpus * sizeof (wc_cpu_t));
10465295Srandyf wc_other_cpus = NULL;
10475295Srandyf }
10485295Srandyf }
10495295Srandyf
10505295Srandyf /*
10515295Srandyf * wrapper for acpica_ddi_save_resources()
10525295Srandyf */
10535295Srandyf void
i_cpr_save_configuration(dev_info_t * dip)10545295Srandyf i_cpr_save_configuration(dev_info_t *dip)
10555295Srandyf {
10565295Srandyf acpica_ddi_save_resources(dip);
10575295Srandyf }
10585295Srandyf
10595295Srandyf /*
10605295Srandyf * wrapper for acpica_ddi_restore_resources()
10615295Srandyf */
10625295Srandyf void
i_cpr_restore_configuration(dev_info_t * dip)10635295Srandyf i_cpr_restore_configuration(dev_info_t *dip)
10645295Srandyf {
10655295Srandyf acpica_ddi_restore_resources(dip);
10665295Srandyf }
10675817Sjan
10685817Sjan static int
wait_for_set(cpuset_t * set,int who)10695817Sjan wait_for_set(cpuset_t *set, int who)
10705817Sjan {
10715817Sjan int delays;
10725817Sjan char *str = "wait_for_set";
10735817Sjan
10745817Sjan for (delays = 0; !CPU_IN_SET(*set, who); delays++) {
10755817Sjan if (delays == 500) {
10765817Sjan /*
10775817Sjan * After five seconds, things are probably
10785817Sjan * looking a bit bleak - explain the hang.
10795817Sjan */
10805817Sjan cmn_err(CE_NOTE, "cpu%d: started, "
10815817Sjan "but not running in the kernel yet", who);
10825817Sjan PMD(PMD_SX, ("%s() %d cpu started "
10835817Sjan "but not running in the kernel yet\n",
10845817Sjan str, who))
10855817Sjan } else if (delays > 2000) {
10865817Sjan /*
10875817Sjan * We waited at least 20 seconds, bail ..
10885817Sjan */
10895817Sjan cmn_err(CE_WARN, "cpu%d: timed out", who);
10905817Sjan PMD(PMD_SX, ("%s() %d cpu timed out\n",
10915817Sjan str, who))
10925817Sjan return (0);
10935817Sjan }
10945817Sjan
10955817Sjan /*
10965817Sjan * wait at least 10ms, then check again..
10975817Sjan */
10985817Sjan drv_usecwait(10000);
10995817Sjan }
11005817Sjan
11015817Sjan return (1);
11025817Sjan }
11039989SJoseph.Townsend@Sun.COM
11049989SJoseph.Townsend@Sun.COM static void
i_cpr_save_stack(kthread_t * t,wc_cpu_t * wc_cpu)11059989SJoseph.Townsend@Sun.COM i_cpr_save_stack(kthread_t *t, wc_cpu_t *wc_cpu)
11069989SJoseph.Townsend@Sun.COM {
11079989SJoseph.Townsend@Sun.COM size_t stack_size; /* size of stack */
11089989SJoseph.Townsend@Sun.COM caddr_t start = CPR_GET_STACK_START(t); /* stack start */
11099989SJoseph.Townsend@Sun.COM caddr_t end = CPR_GET_STACK_END(t); /* stack end */
11109989SJoseph.Townsend@Sun.COM
11119989SJoseph.Townsend@Sun.COM stack_size = (size_t)end - (size_t)start;
11129989SJoseph.Townsend@Sun.COM
11139989SJoseph.Townsend@Sun.COM if (wc_cpu->wc_saved_stack_size < stack_size) {
11149989SJoseph.Townsend@Sun.COM if (wc_cpu->wc_saved_stack != NULL) {
11159989SJoseph.Townsend@Sun.COM kmem_free(wc_cpu->wc_saved_stack,
11169989SJoseph.Townsend@Sun.COM wc_cpu->wc_saved_stack_size);
11179989SJoseph.Townsend@Sun.COM }
11189989SJoseph.Townsend@Sun.COM wc_cpu->wc_saved_stack = kmem_zalloc(stack_size, KM_SLEEP);
11199989SJoseph.Townsend@Sun.COM wc_cpu->wc_saved_stack_size = stack_size;
11209989SJoseph.Townsend@Sun.COM }
11219989SJoseph.Townsend@Sun.COM
11229989SJoseph.Townsend@Sun.COM bcopy(start, wc_cpu->wc_saved_stack, stack_size);
11239989SJoseph.Townsend@Sun.COM }
11249989SJoseph.Townsend@Sun.COM
11259989SJoseph.Townsend@Sun.COM void
i_cpr_restore_stack(kthread_t * t,greg_t * save_stack)11269989SJoseph.Townsend@Sun.COM i_cpr_restore_stack(kthread_t *t, greg_t *save_stack)
11279989SJoseph.Townsend@Sun.COM {
11289989SJoseph.Townsend@Sun.COM size_t stack_size; /* size of stack */
11299989SJoseph.Townsend@Sun.COM caddr_t start = CPR_GET_STACK_START(t); /* stack start */
11309989SJoseph.Townsend@Sun.COM caddr_t end = CPR_GET_STACK_END(t); /* stack end */
11319989SJoseph.Townsend@Sun.COM
11329989SJoseph.Townsend@Sun.COM stack_size = (size_t)end - (size_t)start;
11339989SJoseph.Townsend@Sun.COM
11349989SJoseph.Townsend@Sun.COM bcopy(save_stack, start, stack_size);
11359989SJoseph.Townsend@Sun.COM }
1136