#include <sys/types.h>
#include <sys/errno.h>
#include <sys/callb.h>
#include <sys/processor.h>
#include <sys/machsystm.h>
#include <sys/clock.h>
#include <sys/vfs.h>
#include <sys/kmem.h>
#include <nfs/lm.h>
#include <sys/systm.h>
#include <sys/cpr.h>
#include <sys/bootconf.h>
#include <sys/cyclic.h>
#include <sys/filio.h>
#include <sys/fs/ufs_filio.h>
#include <sys/epm.h>
#include <sys/modctl.h>
#include <sys/reboot.h>
#include <sys/kdi.h>
#include <sys/promif.h>
#include <sys/srn.h>
#include <sys/cpr_impl.h>
#define PPM(dip) ((dev_info_t *)DEVI(dip)->devi_pm_ppm)
extern struct cpr_terminator cpr_term;
extern int cpr_alloc_statefile(int);
extern void cpr_start_kernel_threads(void);
extern void cpr_abbreviate_devpath(char *, char *);
extern void cpr_convert_promtime(cpr_time_t *);
extern void cpr_send_notice(void);
extern void cpr_set_bitmap_size(void);
extern void cpr_stat_init();
extern void cpr_statef_close(void);
extern void flush_windows(void);
extern void (*srn_signal)(int, int);
extern void init_cpu_syscall(struct cpu *);
extern void i_cpr_pre_resume_cpus();
extern void i_cpr_post_resume_cpus();
extern int cpr_is_ufs(struct vfs *);
extern int pm_powering_down;
extern kmutex_t srn_clone_lock;
extern int srn_inuse;
static int cpr_suspend(int);
static int cpr_resume(int);
static void cpr_suspend_init(int);
#if defined(__x86)
static int cpr_suspend_cpus(void);
static void cpr_resume_cpus(void);
#endif
static int cpr_all_online(void);
static void cpr_restore_offline(void);
cpr_time_t wholecycle_tv;
int cpr_suspend_succeeded;
pfn_t curthreadpfn;
int curthreadremapped;
extern cpuset_t cpu_ready_set;
extern processorid_t i_cpr_bootcpuid(void);
extern cpu_t *i_cpr_bootcpu(void);
extern void tsc_adjust_delta(hrtime_t tdelta);
extern void tsc_resume(void);
extern int tsc_resume_in_cyclic;
int cpr_resume_uniproc = 0;
static void
cpr_sae(int stash)
{
static int saved_ae = -1;
if (stash) {
saved_ae = abort_enable;
abort_enable = 0;
} else if (saved_ae != -1) {
abort_enable = saved_ae;
saved_ae = -1;
}
}
int
cpr_main(int sleeptype)
{
int rc, rc2;
label_t saveq;
klwp_t *tlwp = ttolwp(curthread);
if (sleeptype == CPR_TODISK) {
if ((rc = cpr_default_setup(1)) != 0)
return (rc);
ASSERT(tlwp);
saveq = tlwp->lwp_qsav;
}
if (sleeptype == CPR_TORAM) {
rc = cpr_suspend(sleeptype);
PMD(PMD_SX, ("cpr_suspend rets %x\n", rc))
if (rc == 0) {
int i_cpr_power_down(int sleeptype);
ASSERT(cpus_paused());
rc = i_cpr_power_down(sleeptype);
if (rc == 0) {
PMD(PMD_SX, ("back from successful suspend\n"))
}
rc2 = cpr_resume(sleeptype);
if (rc2 != 0) {
ASSERT(cpr_test_point > 0);
cmn_err(CE_NOTE,
"cpr_resume returned non-zero: %d\n", rc2);
PMD(PMD_SX, ("cpr_resume rets %x\n", rc2))
}
ASSERT(!cpus_paused());
} else {
PMD(PMD_SX, ("failed suspend, resuming\n"))
rc = cpr_resume(sleeptype);
}
return (rc);
}
if (!setjmp(&tlwp->lwp_qsav)) {
rc = cpr_suspend(sleeptype);
if (rc || cpr_reusable_mode) {
PMD(PMD_SX, ("failed suspend, resuming\n"))
(void) cpr_resume(sleeptype);
PMD(PMD_SX, ("back from failed suspend resume\n"))
}
} else {
ASSERT(sleeptype == CPR_TODISK);
tlwp->lwp_qsav = saveq;
CPR->c_flags &= ~C_SUSPENDING;
CPR->c_flags |= C_RESUMING;
rc = cpr_resume(sleeptype);
PMD(PMD_SX, ("back from successful suspend; resume rets %x\n",
rc))
}
(void) cpr_default_setup(0);
return (rc);
}
#if defined(__sparc)
static void
cpr_log_status(int enable, int *svstat, vnode_t *vp)
{
int cmd, status, error;
char *str, *able;
fiolog_t fl;
refstr_t *mntpt;
str = "cpr_log_status";
bzero(&fl, sizeof (fl));
fl.error = FIOLOG_ENONE;
if (enable == 0) {
if (error = VOP_IOCTL(vp, _FIOISLOG,
(uintptr_t)&status, FKIOCTL, CRED(), NULL, NULL)) {
mntpt = vfs_getmntpoint(vp->v_vfsp);
prom_printf("%s: \"%s\", cant get logging "
"status, error %d\n", str, refstr_value(mntpt),
error);
refstr_rele(mntpt);
return;
}
*svstat = status;
if (cpr_debug & CPR_DEBUG5) {
mntpt = vfs_getmntpoint(vp->v_vfsp);
errp("%s: \"%s\", logging status = %d\n",
str, refstr_value(mntpt), status);
refstr_rele(mntpt);
};
able = "disable";
cmd = _FIOLOGDISABLE;
} else {
able = "enable";
cmd = _FIOLOGENABLE;
}
if (*svstat == 1) {
error = VOP_IOCTL(vp, cmd, (uintptr_t)&fl,
FKIOCTL, CRED(), NULL, NULL);
if (error) {
mntpt = vfs_getmntpoint(vp->v_vfsp);
prom_printf("%s: \"%s\", cant %s logging, error %d\n",
str, refstr_value(mntpt), able, error);
refstr_rele(mntpt);
} else {
if (cpr_debug & CPR_DEBUG5) {
mntpt = vfs_getmntpoint(vp->v_vfsp);
errp("%s: \"%s\", logging is now %sd\n",
str, refstr_value(mntpt), able);
refstr_rele(mntpt);
};
}
}
if (enable)
*svstat = -1;
}
static int
cpr_ufs_logging(int enable)
{
static int def_status = -1, sf_status = -1;
struct vfs *vfsp;
char *fname;
vnode_t *vp;
int error;
if (cpr_reusable_mode)
return (0);
if (error = cpr_open_deffile(FREAD, &vp))
return (error);
vfsp = vp->v_vfsp;
if (!cpr_is_ufs(vfsp)) {
(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (0);
}
cpr_log_status(enable, &def_status, vp);
(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
fname = cpr_build_statefile_path();
if (fname == NULL)
return (ENOENT);
if (error = vn_open(fname, UIO_SYSSPACE, FCREAT|FWRITE,
0600, &vp, CRCREAT, 0)) {
prom_printf("cpr_ufs_logging: cant open/create \"%s\", "
"error %d\n", fname, error);
return (error);
}
if (vp->v_vfsp != vfsp && vp->v_type == VREG)
cpr_log_status(enable, &sf_status, vp);
(void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
VN_RELE(vp);
return (0);
}
#endif
static void
cpr_lock_mgr(void (*service)(void))
{
if (mod_find_by_filename(NULL, "misc/klmmod") != NULL)
(*service)();
}
int
cpr_suspend_cpus(void)
{
int ret = 0;
extern void *i_cpr_save_context(void *arg);
mutex_enter(&cpu_lock);
ASSERT(i_cpr_bootcpu() != NULL);
if ((ret = cpr_all_online())) {
mutex_exit(&cpu_lock);
return (ret);
}
affinity_set(i_cpr_bootcpuid());
ASSERT(CPU->cpu_id == 0);
PMD(PMD_SX, ("curthread running on bootcpu\n"))
pause_cpus(NULL, i_cpr_save_context);
mutex_exit(&cpu_lock);
return (0);
}
static int
cpr_suspend(int sleeptype)
{
#if defined(__sparc)
int sf_realloc, nverr;
#endif
int rc = 0;
int skt_rc = 0;
PMD(PMD_SX, ("cpr_suspend %x\n", sleeptype))
cpr_set_substate(C_ST_SUSPEND_BEGIN);
cpr_suspend_init(sleeptype);
cpr_save_time();
cpr_tod_get(&wholecycle_tv);
CPR_STAT_EVENT_START("Suspend Total");
i_cpr_alloc_cpus();
#if defined(__sparc)
ASSERT(sleeptype == CPR_TODISK);
if (!cpr_reusable_mode) {
if (rc = cpr_validate_definfo(0))
return (rc);
}
i_cpr_save_machdep_info();
#endif
PMD(PMD_SX, ("cpr_suspend: stop scans\n"))
(void) callb_execute_class(CB_CL_CPR_PM, CB_CODE_CPR_CHKPT);
pm_dispatch_to_dep_thread(PM_DEP_WK_CPR_SUSPEND,
NULL, NULL, PM_DEP_WAIT, NULL, 0);
#if defined(__sparc)
ASSERT(sleeptype == CPR_TODISK);
cpr_set_substate(C_ST_MP_OFFLINE);
if (rc = cpr_mp_offline())
return (rc);
#endif
mutex_enter(&srn_clone_lock);
if (srn_signal) {
PMD(PMD_SX, ("cpr_suspend: (*srn_signal)(..., "
"SRN_SUSPEND_REQ)\n"))
srn_inuse = 1;
(*srn_signal)(SRN_TYPE_APM, SRN_SUSPEND_REQ);
srn_inuse = 0;
} else {
PMD(PMD_SX, ("cpr_suspend: srn_signal NULL\n"))
}
mutex_exit(&srn_clone_lock);
CPR_DEBUG(CPR_DEBUG1, "\nstopping user threads...");
CPR_STAT_EVENT_START(" stop users");
cpr_set_substate(C_ST_STOP_USER_THREADS);
PMD(PMD_SX, ("cpr_suspend: stop user threads\n"))
if (rc = cpr_stop_user_threads())
return (rc);
CPR_STAT_EVENT_END(" stop users");
CPR_DEBUG(CPR_DEBUG1, "done\n");
PMD(PMD_SX, ("cpr_suspend: save direct levels\n"))
pm_save_direct_levels();
(void) callb_execute_class(CB_CL_CPR_PROMPRINTF, CB_CODE_CPR_CHKPT);
PMD(PMD_SX, ("cpr_suspend: send notice\n"))
#ifndef DEBUG
cpr_send_notice();
if (cpr_debug)
prom_printf("\n");
#endif
PMD(PMD_SX, ("cpr_suspend: POST USER callback\n"))
(void) callb_execute_class(CB_CL_CPR_POST_USER, CB_CODE_CPR_CHKPT);
cpr_set_substate(C_ST_PM_REATTACH_NOINVOL);
PMD(PMD_SX, ("cpr_suspend: reattach noinvol\n"))
if (!pm_reattach_noinvol())
return (ENXIO);
#if defined(__sparc)
ASSERT(sleeptype == CPR_TODISK);
cpr_set_substate(C_ST_DISABLE_UFS_LOGGING);
if (rc = cpr_ufs_logging(0))
return (rc);
CPR_STAT_EVENT_START(" swapout upages");
vfs_sync(SYNC_ALL);
CPR_STAT_EVENT_END(" swapout upages");
cpr_set_bitmap_size();
alloc_statefile:
sf_realloc = (CPR->c_substate == C_ST_DUMP_NOSPC) ? 1 : 0;
CPR_STAT_EVENT_START(" alloc statefile");
cpr_set_substate(C_ST_STATEF_ALLOC);
if (rc = cpr_alloc_statefile(sf_realloc)) {
if (sf_realloc)
errp("realloc failed\n");
return (rc);
}
CPR_STAT_EVENT_END(" alloc statefile");
sync();
CPR_STAT_EVENT_START(" clean pages");
CPR_DEBUG(CPR_DEBUG1, ("cleaning up mapped pages..."));
(void) callb_execute_class(CB_CL_CPR_VM, CB_CODE_CPR_CHKPT);
CPR_DEBUG(CPR_DEBUG1, ("done\n"));
CPR_STAT_EVENT_END(" clean pages");
#endif
PMD(PMD_SX, ("cpr_suspend: lock mgr\n"))
cpr_lock_mgr(lm_cprsuspend);
CPR_STAT_EVENT_START(" stop drivers");
CPR_DEBUG(CPR_DEBUG1, "suspending drivers...");
cpr_set_substate(C_ST_SUSPEND_DEVICES);
pm_powering_down = 1;
PMD(PMD_SX, ("cpr_suspend: suspending devices\n"))
rc = cpr_suspend_devices(ddi_root_node());
pm_powering_down = 0;
if (rc)
return (rc);
CPR_DEBUG(CPR_DEBUG1, "done\n");
CPR_STAT_EVENT_END(" stop drivers");
cpr_set_substate(C_ST_STOP_KERNEL_THREADS);
PMD(PMD_SX, ("cpr_suspend: stopping kernel threads\n"))
if (skt_rc = cpr_stop_kernel_threads())
return (skt_rc);
PMD(PMD_SX, ("cpr_suspend: POST KERNEL callback\n"))
(void) callb_execute_class(CB_CL_CPR_POST_KERNEL, CB_CODE_CPR_CHKPT);
PMD(PMD_SX, ("cpr_suspend: reattach noinvol fini\n"))
pm_reattach_noinvol_fini();
cpr_sae(1);
PMD(PMD_SX, ("cpr_suspend: CPR CALLOUT callback\n"))
(void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_CHKPT);
if (sleeptype == CPR_TODISK) {
CPR_STAT_EVENT_START(" write statefile");
}
PMD(PMD_SX, ("cpr_suspend: handle xc\n"))
i_cpr_handle_xc(1);
mutex_enter(&cpu_lock);
PMD(PMD_SX, ("cpr_suspend: cyclic suspend\n"))
cyclic_suspend();
mutex_exit(&cpu_lock);
#if defined(__x86)
PMD(PMD_SX, ("pause aux cpus\n"))
cpr_set_substate(C_ST_MP_PAUSED);
if ((rc = cpr_suspend_cpus()) != 0)
return (rc);
#endif
PMD(PMD_SX, ("cpr_suspend: stop intr\n"))
i_cpr_stop_intr();
CPR_DEBUG(CPR_DEBUG1, "interrupt is stopped\n");
ASSERT(pm_cfb_is_up());
PMD(PMD_SX, ("cpr_suspend: prom suspend prepost\n"))
prom_suspend_prepost();
#if defined(__sparc)
flush_windows();
#endif
if (sleeptype == CPR_TORAM) {
PMD(PMD_SX, ("cpr_suspend rets %x\n", rc))
cpr_set_substate(C_ST_NODUMP);
return (rc);
}
#if defined(__sparc)
if (cpr_reusable_mode) {
cpr_set_substate(C_ST_SETPROPS_1);
if (nverr = cpr_set_properties(1))
return (nverr);
}
cpr_set_substate(C_ST_DUMP);
rc = cpr_dump(C_VP);
if (rc && cpr_reusable_mode) {
cpr_set_substate(C_ST_SETPROPS_0);
if (nverr = cpr_set_properties(0))
return (nverr);
}
if (rc == ENOSPC) {
cpr_set_substate(C_ST_DUMP_NOSPC);
(void) cpr_resume(sleeptype);
goto alloc_statefile;
} else if (rc == 0) {
if (cpr_reusable_mode) {
cpr_set_substate(C_ST_REUSABLE);
longjmp(&ttolwp(curthread)->lwp_qsav);
} else
rc = cpr_set_properties(1);
}
#endif
PMD(PMD_SX, ("cpr_suspend: return %d\n", rc))
return (rc);
}
void
cpr_resume_cpus(void)
{
#if defined(__x86)
init_cpu_syscall(CPU);
#endif
i_cpr_pre_resume_cpus();
mutex_enter(&cpu_lock);
start_cpus();
mutex_exit(&cpu_lock);
i_cpr_post_resume_cpus();
mutex_enter(&cpu_lock);
affinity_clear();
cpr_restore_offline();
mutex_exit(&cpu_lock);
}
void
cpr_unpause_cpus(void)
{
PMD(PMD_SX, ("cpr_unpause_cpus: restoring system\n"))
mutex_enter(&cpu_lock);
start_cpus();
affinity_clear();
cpr_restore_offline();
mutex_exit(&cpu_lock);
}
static int
cpr_resume(int sleeptype)
{
cpr_time_t pwron_tv, *ctp;
char *str;
int rc = 0;
CPR_DEBUG(CPR_DEBUG1, "\nEntering cpr_resume...\n");
PMD(PMD_SX, ("cpr_resume %x\n", sleeptype))
switch (CPR->c_substate) {
#if defined(__sparc)
case C_ST_DUMP:
ASSERT(sleeptype == CPR_TODISK);
break;
case C_ST_REUSABLE:
case C_ST_DUMP_NOSPC:
case C_ST_SETPROPS_0:
case C_ST_SETPROPS_1:
ASSERT(sleeptype == CPR_TODISK);
goto rb_dump;
#endif
case C_ST_NODUMP:
PMD(PMD_SX, ("cpr_resume: NODUMP\n"))
goto rb_nodump;
case C_ST_STOP_KERNEL_THREADS:
PMD(PMD_SX, ("cpr_resume: STOP_KERNEL_THREADS\n"))
goto rb_stop_kernel_threads;
case C_ST_SUSPEND_DEVICES:
PMD(PMD_SX, ("cpr_resume: SUSPEND_DEVICES\n"))
goto rb_suspend_devices;
#if defined(__sparc)
case C_ST_STATEF_ALLOC:
ASSERT(sleeptype == CPR_TODISK);
goto rb_statef_alloc;
case C_ST_DISABLE_UFS_LOGGING:
ASSERT(sleeptype == CPR_TODISK);
goto rb_disable_ufs_logging;
#endif
case C_ST_PM_REATTACH_NOINVOL:
PMD(PMD_SX, ("cpr_resume: REATTACH_NOINVOL\n"))
goto rb_pm_reattach_noinvol;
case C_ST_STOP_USER_THREADS:
PMD(PMD_SX, ("cpr_resume: STOP_USER_THREADS\n"))
goto rb_stop_user_threads;
#if defined(__sparc)
case C_ST_MP_OFFLINE:
PMD(PMD_SX, ("cpr_resume: MP_OFFLINE\n"))
goto rb_mp_offline;
#endif
#if defined(__x86)
case C_ST_MP_PAUSED:
PMD(PMD_SX, ("cpr_resume: MP_PAUSED\n"))
goto rb_mp_paused;
#endif
default:
PMD(PMD_SX, ("cpr_resume: others\n"))
goto rb_others;
}
#if defined(__sparc)
if (cpr_suspend_succeeded)
i_cpr_machdep_setup();
rb_dump:
#endif
rb_nodump:
PMD(PMD_SX, ("cpr_resume: CPR DMA callback\n"))
(void) callb_execute_class(CB_CL_CPR_DMA, CB_CODE_CPR_RESUME);
if (cpr_suspend_succeeded) {
PMD(PMD_SX, ("cpr_resume: CPR RPC callback\n"))
(void) callb_execute_class(CB_CL_CPR_RPC, CB_CODE_CPR_RESUME);
}
prom_resume_prepost();
#if !defined(__sparc)
if (tsc_resume_in_cyclic == 0)
tsc_resume();
#endif
#if defined(__sparc)
if (cpr_suspend_succeeded && (boothowto & RB_DEBUG))
kdi_dvec_cpr_restart();
#endif
#if defined(__x86)
rb_mp_paused:
PT(PT_RMPO);
PMD(PMD_SX, ("resume aux cpus\n"))
if (cpr_suspend_succeeded) {
cpr_resume_cpus();
} else {
cpr_unpause_cpus();
}
#endif
PMD(PMD_SX, ("cpr_resume: CPR CALLOUT callback\n"))
(void) callb_execute_class(CB_CL_CPR_CALLOUT, CB_CODE_CPR_RESUME);
i_cpr_enable_intr();
mutex_enter(&cpu_lock);
PMD(PMD_SX, ("cpr_resume: cyclic resume\n"))
cyclic_resume();
mutex_exit(&cpu_lock);
PMD(PMD_SX, ("cpr_resume: handle xc\n"))
i_cpr_handle_xc(0);
PMD(PMD_SX, ("cpr_resume: CPR POST KERNEL callback\n"))
(void) callb_execute_class(CB_CL_CPR_POST_KERNEL, CB_CODE_CPR_RESUME);
if (cpr_suspend_succeeded) {
cpr_tod_status_set(TOD_CPR_RESUME_DONE);
cpr_convert_promtime(&pwron_tv);
ctp = &cpr_term.tm_shutdown;
if (sleeptype == CPR_TODISK)
CPR_STAT_EVENT_END_TMZ(" write statefile", ctp);
CPR_STAT_EVENT_END_TMZ("Suspend Total", ctp);
CPR_STAT_EVENT_START_TMZ("Resume Total", &pwron_tv);
str = " prom time";
CPR_STAT_EVENT_START_TMZ(str, &pwron_tv);
ctp = &cpr_term.tm_cprboot_start;
CPR_STAT_EVENT_END_TMZ(str, ctp);
str = " read statefile";
CPR_STAT_EVENT_START_TMZ(str, ctp);
ctp = &cpr_term.tm_cprboot_end;
CPR_STAT_EVENT_END_TMZ(str, ctp);
}
rb_stop_kernel_threads:
PMD(PMD_SX, ("cpr_resume: modunload disable\n"))
modunload_disable();
PMD(PMD_SX, ("cpr_resume: start kernel threads\n"))
cpr_start_kernel_threads();
rb_suspend_devices:
CPR_DEBUG(CPR_DEBUG1, "resuming devices...");
CPR_STAT_EVENT_START(" start drivers");
PMD(PMD_SX,
("cpr_resume: rb_suspend_devices: cpr_resume_uniproc = %d\n",
cpr_resume_uniproc))
#if defined(__x86)
if (cpr_resume_uniproc) {
mutex_enter(&cpu_lock);
pause_cpus(NULL, NULL);
mutex_exit(&cpu_lock);
}
#endif
PMD(PMD_SX, ("cpr_resume: resume devices\n"))
rc = cpr_resume_devices(ddi_root_node(), 0);
cpr_sae(0);
str = "Failed to resume one or more devices.";
if (rc) {
if (CPR->c_substate == C_ST_DUMP ||
(sleeptype == CPR_TORAM &&
CPR->c_substate == C_ST_NODUMP)) {
if (cpr_test_point == FORCE_SUSPEND_TO_RAM) {
PMD(PMD_SX, ("cpr_resume: resume device "
"warn\n"))
cpr_err(CE_WARN, str);
} else {
PMD(PMD_SX, ("cpr_resume: resume device "
"panic\n"))
cpr_err(CE_PANIC, str);
}
} else {
PMD(PMD_SX, ("cpr_resume: resume device warn\n"))
cpr_err(CE_WARN, str);
}
}
CPR_STAT_EVENT_END(" start drivers");
CPR_DEBUG(CPR_DEBUG1, "done\n");
#if defined(__x86)
if (cpr_resume_uniproc) {
mutex_enter(&cpu_lock);
start_cpus();
mutex_exit(&cpu_lock);
}
#endif
if (CPR->c_substate != C_ST_SUSPEND_DEVICES) {
PMD(PMD_SX, ("cpr_resume: modload enable\n"))
modunload_enable();
}
PMD(PMD_SX, ("cpr_resume: lock mgr\n"))
cpr_lock_mgr(lm_cprresume);
#if defined(__sparc)
if (CPR->c_substate == C_ST_DUMP_NOSPC) {
return (0);
}
if (sleeptype == CPR_TODISK) {
rb_statef_alloc:
cpr_statef_close();
rb_disable_ufs_logging:
(void) cpr_ufs_logging(1);
}
#endif
rb_pm_reattach_noinvol:
if (CPR->c_substate == C_ST_DISABLE_UFS_LOGGING ||
CPR->c_substate == C_ST_STATEF_ALLOC ||
CPR->c_substate == C_ST_SUSPEND_DEVICES ||
CPR->c_substate == C_ST_STOP_KERNEL_THREADS) {
PMD(PMD_SX, ("cpr_resume: reattach noinvol fini\n"))
pm_reattach_noinvol_fini();
}
PMD(PMD_SX, ("cpr_resume: CPR POST USER callback\n"))
(void) callb_execute_class(CB_CL_CPR_POST_USER, CB_CODE_CPR_RESUME);
PMD(PMD_SX, ("cpr_resume: CPR PROMPRINTF callback\n"))
(void) callb_execute_class(CB_CL_CPR_PROMPRINTF, CB_CODE_CPR_RESUME);
PMD(PMD_SX, ("cpr_resume: restore direct levels\n"))
pm_restore_direct_levels();
rb_stop_user_threads:
CPR_DEBUG(CPR_DEBUG1, "starting user threads...");
PMD(PMD_SX, ("cpr_resume: starting user threads\n"))
cpr_start_user_threads();
CPR_DEBUG(CPR_DEBUG1, "done\n");
mutex_enter(&srn_clone_lock);
if (srn_signal) {
PMD(PMD_SX, ("cpr_suspend: (*srn_signal)(..., "
"SRN_NORMAL_RESUME)\n"))
srn_inuse = 1;
(*srn_signal)(SRN_TYPE_APM, SRN_NORMAL_RESUME);
srn_inuse = 0;
} else {
PMD(PMD_SX, ("cpr_suspend: srn_signal NULL\n"))
}
mutex_exit(&srn_clone_lock);
#if defined(__sparc)
rb_mp_offline:
if (cpr_mp_online())
cpr_err(CE_WARN, "Failed to online all the processors.");
#endif
rb_others:
PMD(PMD_SX, ("cpr_resume: dep thread\n"))
pm_dispatch_to_dep_thread(PM_DEP_WK_CPR_RESUME, NULL, NULL,
PM_DEP_WAIT, NULL, 0);
PMD(PMD_SX, ("cpr_resume: CPR PM callback\n"))
(void) callb_execute_class(CB_CL_CPR_PM, CB_CODE_CPR_RESUME);
if (cpr_suspend_succeeded) {
cpr_stat_record_events();
}
#if defined(__sparc)
if (sleeptype == CPR_TODISK && !cpr_reusable_mode)
cpr_clear_definfo();
#endif
i_cpr_free_cpus();
CPR_DEBUG(CPR_DEBUG1, "Sending SIGTHAW...");
PMD(PMD_SX, ("cpr_resume: SIGTHAW\n"))
cpr_signal_user(SIGTHAW);
CPR_DEBUG(CPR_DEBUG1, "done\n");
CPR_STAT_EVENT_END("Resume Total");
CPR_STAT_EVENT_START_TMZ("WHOLE CYCLE", &wholecycle_tv);
CPR_STAT_EVENT_END("WHOLE CYCLE");
if (cpr_debug & CPR_DEBUG1)
cmn_err(CE_CONT, "\nThe system is back where you left!\n");
CPR_STAT_EVENT_START("POST CPR DELAY");
#ifdef CPR_STAT
ctp = &cpr_term.tm_shutdown;
CPR_STAT_EVENT_START_TMZ("PWROFF TIME", ctp);
CPR_STAT_EVENT_END_TMZ("PWROFF TIME", &pwron_tv);
CPR_STAT_EVENT_PRINT();
#endif
PMD(PMD_SX, ("cpr_resume returns %x\n", rc))
return (rc);
}
static void
cpr_suspend_init(int sleeptype)
{
cpr_time_t *ctp;
cpr_stat_init();
cpr_term.real_statef_size = 0;
ctp = &cpr_term.tm_shutdown;
bzero(ctp, sizeof (*ctp));
ctp = &cpr_term.tm_cprboot_start;
bzero(ctp, sizeof (*ctp));
ctp = &cpr_term.tm_cprboot_end;
bzero(ctp, sizeof (*ctp));
if (sleeptype == CPR_TODISK) {
curthreadpfn = hat_getpfnum(kas.a_hat, (caddr_t)curthread);
ASSERT(curthreadpfn != PFN_INVALID);
ASSERT(curthreadpfn == hat_getpfnum(kas.a_hat,
(caddr_t)curthread + sizeof (kthread_t) - 1));
}
cpr_suspend_succeeded = 0;
}
static int
cpr_all_online(void)
{
int rc = 0;
#ifdef __sparc
#else
cpu_t *cp;
ASSERT(MUTEX_HELD(&cpu_lock));
cp = cpu_list;
do {
cp->cpu_cpr_flags &= ~CPU_CPR_ONLINE;
if (!CPU_ACTIVE(cp)) {
if ((rc = cpu_online(cp, 0)) != 0)
break;
CPU_SET_CPR_FLAGS(cp, CPU_CPR_ONLINE);
}
} while ((cp = cp->cpu_next) != cpu_list);
if (rc) {
cpr_restore_offline();
}
#endif
return (rc);
}
static void
cpr_restore_offline(void)
{
#ifdef __sparc
#else
cpu_t *cp;
int rc = 0;
ASSERT(MUTEX_HELD(&cpu_lock));
cp = cpu_list;
do {
if (CPU_CPR_IS_ONLINE(cp)) {
rc = cpu_offline(cp, 0);
ASSERT(rc == 0);
cp->cpu_cpr_flags &= ~CPU_CPR_ONLINE;
}
} while ((cp = cp->cpu_next) != cpu_list);
#endif
}