#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/clockintr.h>
#include <sys/reboot.h>
#include <sys/sensors.h>
#include <sys/sysctl.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <dev/wscons/wsdisplayvar.h>
#ifdef GPROF
#include <sys/gmon.h>
#endif
#ifdef HIBERNATE
#include <sys/hibernate.h>
#endif
#include "softraid.h"
#include "wsdisplay.h"
u_int wakeup_devices;
time_t resume_time;
void
device_register_wakeup(struct device *dev)
{
wakeup_devices++;
}
int
sleep_state(void *v, int sleepmode)
{
int error, s;
extern int perflevel;
size_t rndbuflen;
char *rndbuf;
#ifdef GPROF
int gmon_state;
#endif
#if NSOFTRAID > 0
extern void sr_quiesce(void);
#endif
top:
error = ENXIO;
rndbuf = NULL;
rndbuflen = 0;
if (sleepmode == SLEEP_SUSPEND && wakeup_devices == 0)
return EOPNOTSUPP;
if (sleep_showstate(v, sleepmode))
return EOPNOTSUPP;
#if NWSDISPLAY > 0
wsdisplay_suspend();
#endif
stop_periodic_resettodr();
#ifdef HIBERNATE
if (sleepmode == SLEEP_HIBERNATE) {
hibernate_suspend_bufcache();
uvmpd_hibernate();
if (hibernate_alloc()) {
printf("failed to allocate hibernate memory\n");
error = ENOMEM;
goto fail_hiballoc;
}
}
#endif
sensor_quiesce();
if (config_suspend_all(DVACT_QUIESCE)) {
error = EIO;
goto fail_quiesce;
}
vfs_stall(curproc, 1);
#if NSOFTRAID > 0
sr_quiesce();
#endif
bufq_quiesce();
#ifdef MULTIPROCESSOR
sched_stop_secondary_cpus();
KASSERT(CPU_IS_PRIMARY(curcpu()));
#endif
#ifdef GPROF
gmon_state = gmoninit;
gmoninit = 0;
#endif
#ifdef MULTIPROCESSOR
sleep_mp();
#endif
#ifdef HIBERNATE
if (sleepmode == SLEEP_HIBERNATE) {
hibernate_suspend_bufcache();
uvmpd_hibernate();
}
#endif
resettodr();
s = splhigh();
intr_disable();
cold = 2;
intr_enable_wakeup();
if (config_suspend_all(DVACT_SUSPEND) != 0) {
error = EDEADLK;
goto fail_suspend;
}
suspend_randomness();
if (sleep_setstate(v)) {
error = ENOTBLK;
goto fail_pts;
}
if (sleepmode == SLEEP_SUSPEND) {
boothowto |= RB_POWERDOWN;
config_suspend_all(DVACT_POWERDOWN);
boothowto &= ~RB_POWERDOWN;
if (cpu_setperf != NULL)
cpu_setperf(0);
}
error = gosleep(v);
#ifdef HIBERNATE
if (sleepmode == SLEEP_HIBERNATE) {
uvm_pmr_dirty_everything();
hib_getentropy(&rndbuf, &rndbuflen);
}
#endif
fail_pts:
config_suspend_all(DVACT_RESUME);
fail_suspend:
intr_disable_wakeup();
cold = 0;
intr_enable();
splx(s);
inittodr(gettime());
clockintr_cpu_init(NULL);
clockintr_trigger();
resume_time = getuptime();
sleep_resume(v);
resume_randomness(rndbuf, rndbuflen);
#ifdef MULTIPROCESSOR
resume_mp();
#endif
#ifdef GPROF
gmoninit = gmon_state;
#endif
#ifdef MULTIPROCESSOR
sched_start_secondary_cpus();
#endif
vfs_stall(curproc, 0);
bufq_restart();
fail_quiesce:
config_suspend_all(DVACT_WAKEUP);
sensor_restart();
#ifdef HIBERNATE
if (sleepmode == SLEEP_HIBERNATE) {
hibernate_free();
fail_hiballoc:
hibernate_resume_bufcache();
}
#endif
start_periodic_resettodr();
#if NWSDISPLAY > 0
wsdisplay_resume();
#endif
sys_sync(curproc, NULL, NULL);
if (cpu_setperf != NULL)
cpu_setperf(perflevel);
sleepmode = suspend_finish(v);
if (sleepmode != SLEEP_RESUME)
goto top;
resume_time = getuptime();
return (error);
}
int
resuming(void)
{
return (getuptime() < resume_time + 10);
}