1 /* $OpenBSD: subr_suspend.c,v 1.8 2022/02/16 06:41:27 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> 4 * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/buf.h> 22 #include <sys/malloc.h> 23 #include <sys/pool.h> 24 #include <sys/reboot.h> 25 #include <sys/proc.h> 26 #include <sys/sensors.h> 27 #include <sys/sysctl.h> 28 #include <sys/mount.h> 29 #include <sys/syscallargs.h> 30 #include <dev/wscons/wsdisplayvar.h> 31 #ifdef HIBERNATE 32 #include <sys/hibernate.h> 33 #endif 34 35 #include "softraid.h" 36 #include "wsdisplay.h" 37 38 int 39 sleep_state(void *v, int sleepmode) 40 { 41 int error = ENXIO; 42 extern int perflevel; 43 size_t rndbuflen = 0; 44 char *rndbuf = NULL; 45 int s; 46 #if NSOFTRAID > 0 47 extern void sr_quiesce(void); 48 #endif 49 50 if (sleep_showstate(v, sleepmode)) 51 return EOPNOTSUPP; 52 53 #if NWSDISPLAY > 0 54 wsdisplay_suspend(); 55 #endif 56 57 stop_periodic_resettodr(); 58 59 #ifdef HIBERNATE 60 if (sleepmode == SLEEP_HIBERNATE) { 61 /* 62 * Discard useless memory to reduce fragmentation, 63 * and attempt to create a hibernate work area 64 */ 65 hibernate_suspend_bufcache(); 66 uvmpd_hibernate(); 67 if (hibernate_alloc()) { 68 printf("failed to allocate hibernate memory\n"); 69 sleep_abort(v); 70 goto fail_alloc; 71 } 72 } 73 #endif /* HIBERNATE */ 74 75 sensor_quiesce(); 76 if (config_suspend_all(DVACT_QUIESCE)) { 77 sleep_abort(v); 78 goto fail_quiesce; 79 } 80 81 vfs_stall(curproc, 1); 82 #if NSOFTRAID > 0 83 sr_quiesce(); 84 #endif 85 bufq_quiesce(); 86 87 88 #ifdef MULTIPROCESSOR 89 sched_stop_secondary_cpus(); 90 KASSERT(CPU_IS_PRIMARY(curcpu())); 91 sleep_mp(); 92 #endif 93 94 #ifdef HIBERNATE 95 if (sleepmode == SLEEP_HIBERNATE) { 96 /* 97 * We've just done various forms of syncing to disk 98 * churned lots of memory dirty. We don't need to 99 * save that dirty memory to hibernate, so release it. 100 */ 101 hibernate_suspend_bufcache(); 102 uvmpd_hibernate(); 103 } 104 #endif /* HIBERNATE */ 105 106 resettodr(); 107 108 s = splhigh(); 109 intr_disable(); /* PSL_I for resume; PIC/APIC broken until repair */ 110 cold = 2; /* Force other code to delay() instead of tsleep() */ 111 112 if (config_suspend_all(DVACT_SUSPEND) != 0) { 113 sleep_abort(v); 114 goto fail_suspend; 115 } 116 117 suspend_randomness(); 118 119 if (sleep_setstate(v)) { 120 sleep_abort(v); 121 goto fail_pts; 122 } 123 124 if (sleepmode == SLEEP_SUSPEND) { 125 /* 126 * XXX 127 * Flag to disk drivers that they should "power down" the disk 128 * when we get to DVACT_POWERDOWN. 129 */ 130 boothowto |= RB_POWERDOWN; 131 config_suspend_all(DVACT_POWERDOWN); 132 boothowto &= ~RB_POWERDOWN; 133 } 134 135 error = gosleep(v); 136 137 #ifdef HIBERNATE 138 if (sleepmode == SLEEP_HIBERNATE) { 139 uvm_pmr_dirty_everything(); 140 hib_getentropy(&rndbuf, &rndbuflen); 141 } 142 #endif /* HIBERNATE */ 143 144 fail_pts: 145 config_suspend_all(DVACT_RESUME); 146 147 fail_suspend: 148 cold = 0; 149 intr_enable(); 150 splx(s); 151 152 inittodr(gettime()); 153 154 sleep_resume(v); 155 156 /* force RNG upper level reseed */ 157 resume_randomness(rndbuf, rndbuflen); 158 159 #ifdef MULTIPROCESSOR 160 resume_mp(); 161 sched_start_secondary_cpus(); 162 #endif 163 164 vfs_stall(curproc, 0); 165 bufq_restart(); 166 167 fail_quiesce: 168 config_suspend_all(DVACT_WAKEUP); 169 sensor_restart(); 170 171 #ifdef HIBERNATE 172 if (sleepmode == SLEEP_HIBERNATE) { 173 hibernate_free(); 174 fail_alloc: 175 hibernate_resume_bufcache(); 176 } 177 #endif /* HIBERNATE */ 178 179 start_periodic_resettodr(); 180 181 #if NWSDISPLAY > 0 182 wsdisplay_resume(); 183 #endif 184 sys_sync(curproc, NULL, NULL); 185 186 /* Restore hw.setperf */ 187 if (cpu_setperf != NULL) 188 cpu_setperf(perflevel); 189 190 suspend_finish(v); 191 192 return (error); 193 } 194