1 /* $OpenBSD: subr_suspend.c,v 1.1 2022/02/08 17:25:12 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/proc.h> 25 #include <sys/sensors.h> 26 #include <sys/sysctl.h> 27 #include <sys/mount.h> 28 #include <sys/syscallargs.h> 29 #include <dev/wscons/wsdisplayvar.h> 30 #ifdef HIBERNATE 31 #include <sys/hibernate.h> 32 #endif 33 34 #include "softraid.h" 35 36 int 37 sleep_state(void *v, int sleepmode) 38 { 39 int error = ENXIO; 40 extern int perflevel; 41 size_t rndbuflen = 0; 42 char *rndbuf = NULL; 43 int s; 44 #if NSOFTRAID > 0 45 extern void sr_quiesce(void); 46 #endif 47 48 if (sleep_showstate(v, sleepmode)) 49 return EOPNOTSUPP; 50 51 display_suspend(v); 52 53 stop_periodic_resettodr(); 54 55 #ifdef HIBERNATE 56 if (sleepmode == SLEEP_HIBERNATE) { 57 /* 58 * Discard useless memory to reduce fragmentation, 59 * and attempt to create a hibernate work area 60 */ 61 hibernate_suspend_bufcache(); 62 uvmpd_hibernate(); 63 if (hibernate_alloc()) { 64 printf("failed to allocate hibernate memory\n"); 65 goto fail_alloc; 66 } 67 } 68 #endif /* HIBERNATE */ 69 70 sensor_quiesce(); 71 if (config_suspend_all(DVACT_QUIESCE)) 72 goto fail_quiesce; 73 74 vfs_stall(curproc, 1); 75 #if NSOFTRAID > 0 76 sr_quiesce(); 77 #endif 78 bufq_quiesce(); 79 80 81 #ifdef MULTIPROCESSOR 82 sleep_mp(); 83 #endif 84 85 #ifdef HIBERNATE 86 if (sleepmode == SLEEP_HIBERNATE) { 87 /* 88 * We've just done various forms of syncing to disk 89 * churned lots of memory dirty. We don't need to 90 * save that dirty memory to hibernate, so release it. 91 */ 92 hibernate_suspend_bufcache(); 93 uvmpd_hibernate(); 94 } 95 #endif /* HIBERNATE */ 96 97 resettodr(); 98 99 s = splhigh(); 100 intr_disable(); /* PSL_I for resume; PIC/APIC broken until repair */ 101 cold = 2; /* Force other code to delay() instead of tsleep() */ 102 103 if (config_suspend_all(DVACT_SUSPEND) != 0) 104 goto fail_suspend; 105 sleep_clocks(v); 106 107 suspend_randomness(); 108 109 if (sleep_setstate(v)) 110 goto fail_pts; 111 112 gosleep(v); 113 114 #ifdef HIBERNATE 115 if (sleepmode == SLEEP_HIBERNATE) { 116 uvm_pmr_dirty_everything(); 117 hib_getentropy(&rndbuf, &rndbuflen); 118 } 119 #endif /* HIBERNATE */ 120 121 fail_pts: 122 config_suspend_all(DVACT_RESUME); 123 124 fail_suspend: 125 cold = 0; 126 intr_enable(); 127 splx(s); 128 129 disable_lid_wakeups(v); 130 131 inittodr(gettime()); 132 133 sleep_resume(v); 134 135 /* force RNG upper level reseed */ 136 resume_randomness(rndbuf, rndbuflen); 137 138 #ifdef MULTIPROCESSOR 139 resume_mp(); 140 #endif 141 142 vfs_stall(curproc, 0); 143 bufq_restart(); 144 145 fail_quiesce: 146 config_suspend_all(DVACT_WAKEUP); 147 sensor_restart(); 148 149 #ifdef HIBERNATE 150 if (sleepmode == SLEEP_HIBERNATE) { 151 hibernate_free(); 152 fail_alloc: 153 hibernate_resume_bufcache(); 154 } 155 #endif /* HIBERNATE */ 156 157 start_periodic_resettodr(); 158 159 display_resume(v); 160 161 sys_sync(curproc, NULL, NULL); 162 163 /* Restore hw.setperf */ 164 if (cpu_setperf != NULL) 165 cpu_setperf(perflevel); 166 167 suspend_finish(v); 168 169 return (error); 170 } 171