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