kern_pmf.c revision 1.10.4.5 1 1.10.4.5 yamt /* $NetBSD: kern_pmf.c,v 1.10.4.5 2008/03/17 09:15:33 yamt Exp $ */
2 1.10.4.2 yamt
3 1.10.4.2 yamt /*-
4 1.10.4.2 yamt * Copyright (c) 2007 Jared D. McNeill <jmcneill (at) invisible.ca>
5 1.10.4.2 yamt * All rights reserved.
6 1.10.4.2 yamt *
7 1.10.4.2 yamt * Redistribution and use in source and binary forms, with or without
8 1.10.4.2 yamt * modification, are permitted provided that the following conditions
9 1.10.4.2 yamt * are met:
10 1.10.4.2 yamt * 1. Redistributions of source code must retain the above copyright
11 1.10.4.2 yamt * notice, this list of conditions and the following disclaimer.
12 1.10.4.2 yamt * 2. Redistributions in binary form must reproduce the above copyright
13 1.10.4.2 yamt * notice, this list of conditions and the following disclaimer in the
14 1.10.4.2 yamt * documentation and/or other materials provided with the distribution.
15 1.10.4.2 yamt * 3. All advertising materials mentioning features or use of this software
16 1.10.4.2 yamt * must display the following acknowledgement:
17 1.10.4.2 yamt * This product includes software developed by Jared D. McNeill.
18 1.10.4.2 yamt * 4. Neither the name of The NetBSD Foundation nor the names of its
19 1.10.4.2 yamt * contributors may be used to endorse or promote products derived
20 1.10.4.2 yamt * from this software without specific prior written permission.
21 1.10.4.2 yamt *
22 1.10.4.2 yamt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 1.10.4.2 yamt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 1.10.4.2 yamt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 1.10.4.2 yamt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 1.10.4.2 yamt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 1.10.4.2 yamt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 1.10.4.2 yamt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 1.10.4.2 yamt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 1.10.4.2 yamt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 1.10.4.2 yamt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 1.10.4.2 yamt * POSSIBILITY OF SUCH DAMAGE.
33 1.10.4.2 yamt */
34 1.10.4.2 yamt
35 1.10.4.2 yamt #include <sys/cdefs.h>
36 1.10.4.5 yamt __KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.10.4.5 2008/03/17 09:15:33 yamt Exp $");
37 1.10.4.2 yamt
38 1.10.4.2 yamt #include <sys/types.h>
39 1.10.4.2 yamt #include <sys/param.h>
40 1.10.4.2 yamt #include <sys/malloc.h>
41 1.10.4.2 yamt #include <sys/buf.h>
42 1.10.4.2 yamt #include <sys/callout.h>
43 1.10.4.2 yamt #include <sys/kernel.h>
44 1.10.4.2 yamt #include <sys/device.h>
45 1.10.4.2 yamt #include <sys/pmf.h>
46 1.10.4.2 yamt #include <sys/queue.h>
47 1.10.4.2 yamt #include <sys/syscallargs.h> /* for sys_sync */
48 1.10.4.2 yamt #include <sys/workqueue.h>
49 1.10.4.2 yamt #include <prop/proplib.h>
50 1.10.4.5 yamt #include <sys/condvar.h>
51 1.10.4.5 yamt #include <sys/mutex.h>
52 1.10.4.5 yamt #include <sys/proc.h>
53 1.10.4.5 yamt #include <sys/reboot.h> /* for RB_NOSYNC */
54 1.10.4.5 yamt #include <sys/sched.h>
55 1.10.4.2 yamt
56 1.10.4.4 yamt /* XXX ugly special case, but for now the only client */
57 1.10.4.4 yamt #include "wsdisplay.h"
58 1.10.4.4 yamt #if NWSDISPLAY > 0
59 1.10.4.4 yamt #include <dev/wscons/wsdisplayvar.h>
60 1.10.4.4 yamt #endif
61 1.10.4.4 yamt
62 1.10.4.2 yamt #ifdef PMF_DEBUG
63 1.10.4.2 yamt int pmf_debug_event;
64 1.10.4.2 yamt int pmf_debug_idle;
65 1.10.4.2 yamt int pmf_debug_transition;
66 1.10.4.2 yamt
67 1.10.4.2 yamt #define PMF_EVENT_PRINTF(x) if (pmf_debug_event) printf x
68 1.10.4.2 yamt #define PMF_IDLE_PRINTF(x) if (pmf_debug_idle) printf x
69 1.10.4.2 yamt #define PMF_TRANSITION_PRINTF(x) if (pmf_debug_transition) printf x
70 1.10.4.2 yamt #define PMF_TRANSITION_PRINTF2(y,x) if (pmf_debug_transition>y) printf x
71 1.10.4.2 yamt #else
72 1.10.4.2 yamt #define PMF_EVENT_PRINTF(x) do { } while (0)
73 1.10.4.2 yamt #define PMF_IDLE_PRINTF(x) do { } while (0)
74 1.10.4.2 yamt #define PMF_TRANSITION_PRINTF(x) do { } while (0)
75 1.10.4.2 yamt #define PMF_TRANSITION_PRINTF2(y,x) do { } while (0)
76 1.10.4.2 yamt #endif
77 1.10.4.2 yamt
78 1.10.4.2 yamt /* #define PMF_DEBUG */
79 1.10.4.2 yamt
80 1.10.4.2 yamt MALLOC_DEFINE(M_PMF, "pmf", "device pmf messaging memory");
81 1.10.4.2 yamt
82 1.10.4.2 yamt static prop_dictionary_t pmf_platform = NULL;
83 1.10.4.2 yamt static struct workqueue *pmf_event_workqueue;
84 1.10.4.2 yamt
85 1.10.4.2 yamt typedef struct pmf_event_handler {
86 1.10.4.2 yamt TAILQ_ENTRY(pmf_event_handler) pmf_link;
87 1.10.4.2 yamt pmf_generic_event_t pmf_event;
88 1.10.4.2 yamt void (*pmf_handler)(device_t);
89 1.10.4.2 yamt device_t pmf_device;
90 1.10.4.2 yamt bool pmf_global;
91 1.10.4.2 yamt } pmf_event_handler_t;
92 1.10.4.2 yamt
93 1.10.4.2 yamt static TAILQ_HEAD(, pmf_event_handler) pmf_all_events =
94 1.10.4.2 yamt TAILQ_HEAD_INITIALIZER(pmf_all_events);
95 1.10.4.2 yamt
96 1.10.4.2 yamt typedef struct pmf_event_workitem {
97 1.10.4.2 yamt struct work pew_work;
98 1.10.4.2 yamt pmf_generic_event_t pew_event;
99 1.10.4.2 yamt device_t pew_device;
100 1.10.4.2 yamt } pmf_event_workitem_t;
101 1.10.4.2 yamt
102 1.10.4.5 yamt struct shutdown_state {
103 1.10.4.5 yamt bool initialized;
104 1.10.4.5 yamt deviter_t di;
105 1.10.4.5 yamt };
106 1.10.4.5 yamt
107 1.10.4.5 yamt static device_t shutdown_first(struct shutdown_state *);
108 1.10.4.5 yamt static device_t shutdown_next(struct shutdown_state *);
109 1.10.4.5 yamt
110 1.10.4.5 yamt static bool pmf_device_resume_locked(device_t PMF_FN_PROTO);
111 1.10.4.5 yamt static bool pmf_device_suspend_locked(device_t PMF_FN_PROTO);
112 1.10.4.5 yamt
113 1.10.4.2 yamt static void
114 1.10.4.2 yamt pmf_event_worker(struct work *wk, void *dummy)
115 1.10.4.2 yamt {
116 1.10.4.2 yamt pmf_event_workitem_t *pew;
117 1.10.4.2 yamt pmf_event_handler_t *event;
118 1.10.4.2 yamt
119 1.10.4.2 yamt pew = (void *)wk;
120 1.10.4.2 yamt KASSERT(wk == &pew->pew_work);
121 1.10.4.2 yamt KASSERT(pew != NULL);
122 1.10.4.2 yamt
123 1.10.4.2 yamt TAILQ_FOREACH(event, &pmf_all_events, pmf_link) {
124 1.10.4.2 yamt if (event->pmf_event != pew->pew_event)
125 1.10.4.2 yamt continue;
126 1.10.4.2 yamt if (event->pmf_device == pew->pew_device || event->pmf_global)
127 1.10.4.2 yamt (*event->pmf_handler)(event->pmf_device);
128 1.10.4.2 yamt }
129 1.10.4.2 yamt
130 1.10.4.2 yamt free(pew, M_TEMP);
131 1.10.4.2 yamt
132 1.10.4.2 yamt return;
133 1.10.4.2 yamt }
134 1.10.4.2 yamt
135 1.10.4.2 yamt static bool
136 1.10.4.2 yamt pmf_check_system_drivers(void)
137 1.10.4.2 yamt {
138 1.10.4.2 yamt device_t curdev;
139 1.10.4.2 yamt bool unsupported_devs;
140 1.10.4.5 yamt deviter_t di;
141 1.10.4.2 yamt
142 1.10.4.2 yamt unsupported_devs = false;
143 1.10.4.5 yamt for (curdev = deviter_first(&di, 0); curdev != NULL;
144 1.10.4.5 yamt curdev = deviter_next(&di)) {
145 1.10.4.2 yamt if (device_pmf_is_registered(curdev))
146 1.10.4.2 yamt continue;
147 1.10.4.2 yamt if (!unsupported_devs)
148 1.10.4.2 yamt printf("Devices without power management support:");
149 1.10.4.2 yamt printf(" %s", device_xname(curdev));
150 1.10.4.2 yamt unsupported_devs = true;
151 1.10.4.2 yamt }
152 1.10.4.5 yamt deviter_release(&di);
153 1.10.4.2 yamt if (unsupported_devs) {
154 1.10.4.2 yamt printf("\n");
155 1.10.4.2 yamt return false;
156 1.10.4.2 yamt }
157 1.10.4.2 yamt return true;
158 1.10.4.2 yamt }
159 1.10.4.2 yamt
160 1.10.4.2 yamt bool
161 1.10.4.5 yamt pmf_system_bus_resume(PMF_FN_ARGS1)
162 1.10.4.2 yamt {
163 1.10.4.2 yamt bool rv;
164 1.10.4.2 yamt device_t curdev;
165 1.10.4.5 yamt deviter_t di;
166 1.10.4.2 yamt
167 1.10.4.2 yamt aprint_debug("Powering devices:");
168 1.10.4.2 yamt /* D0 handlers are run in order */
169 1.10.4.2 yamt rv = true;
170 1.10.4.5 yamt for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); curdev != NULL;
171 1.10.4.5 yamt curdev = deviter_next(&di)) {
172 1.10.4.5 yamt if (!device_pmf_is_registered(curdev))
173 1.10.4.5 yamt continue;
174 1.10.4.5 yamt if (device_is_active(curdev) ||
175 1.10.4.5 yamt !device_is_enabled(curdev))
176 1.10.4.5 yamt continue;
177 1.10.4.2 yamt
178 1.10.4.5 yamt aprint_debug(" %s", device_xname(curdev));
179 1.10.4.2 yamt
180 1.10.4.5 yamt if (!device_pmf_bus_resume(curdev PMF_FN_CALL)) {
181 1.10.4.5 yamt rv = false;
182 1.10.4.5 yamt aprint_debug("(failed)");
183 1.10.4.2 yamt }
184 1.10.4.2 yamt }
185 1.10.4.5 yamt deviter_release(&di);
186 1.10.4.2 yamt aprint_debug("\n");
187 1.10.4.2 yamt
188 1.10.4.2 yamt return rv;
189 1.10.4.2 yamt }
190 1.10.4.2 yamt
191 1.10.4.2 yamt bool
192 1.10.4.5 yamt pmf_system_resume(PMF_FN_ARGS1)
193 1.10.4.2 yamt {
194 1.10.4.2 yamt bool rv;
195 1.10.4.2 yamt device_t curdev, parent;
196 1.10.4.5 yamt deviter_t di;
197 1.10.4.2 yamt
198 1.10.4.2 yamt if (!pmf_check_system_drivers())
199 1.10.4.2 yamt return false;
200 1.10.4.2 yamt
201 1.10.4.2 yamt aprint_debug("Resuming devices:");
202 1.10.4.2 yamt /* D0 handlers are run in order */
203 1.10.4.2 yamt rv = true;
204 1.10.4.5 yamt for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); curdev != NULL;
205 1.10.4.5 yamt curdev = deviter_next(&di)) {
206 1.10.4.5 yamt if (device_is_active(curdev) ||
207 1.10.4.5 yamt !device_is_enabled(curdev))
208 1.10.4.5 yamt continue;
209 1.10.4.5 yamt parent = device_parent(curdev);
210 1.10.4.5 yamt if (parent != NULL &&
211 1.10.4.5 yamt !device_is_active(parent))
212 1.10.4.5 yamt continue;
213 1.10.4.5 yamt
214 1.10.4.5 yamt aprint_debug(" %s", device_xname(curdev));
215 1.10.4.5 yamt
216 1.10.4.5 yamt if (!pmf_device_resume(curdev PMF_FN_CALL)) {
217 1.10.4.5 yamt rv = false;
218 1.10.4.5 yamt aprint_debug("(failed)");
219 1.10.4.2 yamt }
220 1.10.4.2 yamt }
221 1.10.4.5 yamt deviter_release(&di);
222 1.10.4.2 yamt aprint_debug(".\n");
223 1.10.4.2 yamt
224 1.10.4.4 yamt KERNEL_UNLOCK_ONE(0);
225 1.10.4.4 yamt #if NWSDISPLAY > 0
226 1.10.4.4 yamt if (rv)
227 1.10.4.4 yamt wsdisplay_handlex(1);
228 1.10.4.4 yamt #endif
229 1.10.4.2 yamt return rv;
230 1.10.4.2 yamt }
231 1.10.4.2 yamt
232 1.10.4.2 yamt bool
233 1.10.4.5 yamt pmf_system_suspend(PMF_FN_ARGS1)
234 1.10.4.2 yamt {
235 1.10.4.2 yamt device_t curdev;
236 1.10.4.5 yamt deviter_t di;
237 1.10.4.2 yamt
238 1.10.4.2 yamt if (!pmf_check_system_drivers())
239 1.10.4.2 yamt return false;
240 1.10.4.4 yamt #if NWSDISPLAY > 0
241 1.10.4.4 yamt if (wsdisplay_handlex(0))
242 1.10.4.4 yamt return false;
243 1.10.4.4 yamt #endif
244 1.10.4.4 yamt KERNEL_LOCK(1, 0);
245 1.10.4.2 yamt
246 1.10.4.2 yamt /*
247 1.10.4.2 yamt * Flush buffers only if the shutdown didn't do so
248 1.10.4.2 yamt * already and if there was no panic.
249 1.10.4.2 yamt */
250 1.10.4.2 yamt if (doing_shutdown == 0 && panicstr == NULL) {
251 1.10.4.2 yamt printf("Flushing disk caches: ");
252 1.10.4.2 yamt sys_sync(NULL, NULL, NULL);
253 1.10.4.2 yamt if (buf_syncwait() != 0)
254 1.10.4.2 yamt printf("giving up\n");
255 1.10.4.2 yamt else
256 1.10.4.2 yamt printf("done\n");
257 1.10.4.2 yamt }
258 1.10.4.2 yamt
259 1.10.4.2 yamt aprint_debug("Suspending devices:");
260 1.10.4.2 yamt
261 1.10.4.5 yamt for (curdev = deviter_first(&di, DEVITER_F_LEAVES_FIRST);
262 1.10.4.5 yamt curdev != NULL;
263 1.10.4.5 yamt curdev = deviter_next(&di)) {
264 1.10.4.5 yamt if (!device_is_active(curdev))
265 1.10.4.5 yamt continue;
266 1.10.4.5 yamt
267 1.10.4.5 yamt aprint_debug(" %s", device_xname(curdev));
268 1.10.4.5 yamt
269 1.10.4.5 yamt /* XXX joerg check return value and abort suspend */
270 1.10.4.5 yamt if (!pmf_device_suspend(curdev PMF_FN_CALL))
271 1.10.4.5 yamt aprint_debug("(failed)");
272 1.10.4.2 yamt }
273 1.10.4.5 yamt deviter_release(&di);
274 1.10.4.2 yamt
275 1.10.4.2 yamt aprint_debug(".\n");
276 1.10.4.2 yamt
277 1.10.4.2 yamt return true;
278 1.10.4.2 yamt }
279 1.10.4.2 yamt
280 1.10.4.5 yamt static device_t
281 1.10.4.5 yamt shutdown_first(struct shutdown_state *s)
282 1.10.4.5 yamt {
283 1.10.4.5 yamt if (!s->initialized) {
284 1.10.4.5 yamt deviter_init(&s->di, DEVITER_F_SHUTDOWN|DEVITER_F_LEAVES_FIRST);
285 1.10.4.5 yamt s->initialized = true;
286 1.10.4.5 yamt }
287 1.10.4.5 yamt return shutdown_next(s);
288 1.10.4.5 yamt }
289 1.10.4.5 yamt
290 1.10.4.5 yamt static device_t
291 1.10.4.5 yamt shutdown_next(struct shutdown_state *s)
292 1.10.4.5 yamt {
293 1.10.4.5 yamt device_t dv;
294 1.10.4.5 yamt
295 1.10.4.5 yamt while ((dv = deviter_next(&s->di)) != NULL && !device_is_active(dv))
296 1.10.4.5 yamt ;
297 1.10.4.5 yamt
298 1.10.4.5 yamt return dv;
299 1.10.4.5 yamt }
300 1.10.4.5 yamt
301 1.10.4.2 yamt void
302 1.10.4.5 yamt pmf_system_shutdown(int how)
303 1.10.4.2 yamt {
304 1.10.4.5 yamt static struct shutdown_state s;
305 1.10.4.2 yamt device_t curdev;
306 1.10.4.2 yamt
307 1.10.4.2 yamt aprint_debug("Shutting down devices:");
308 1.10.4.2 yamt
309 1.10.4.5 yamt for (curdev = shutdown_first(&s); curdev != NULL;
310 1.10.4.5 yamt curdev = shutdown_next(&s)) {
311 1.10.4.5 yamt aprint_debug(" attempting %s shutdown",
312 1.10.4.5 yamt device_xname(curdev));
313 1.10.4.5 yamt if (!device_pmf_is_registered(curdev))
314 1.10.4.5 yamt aprint_debug("(skipped)");
315 1.10.4.5 yamt #if 0 /* needed? */
316 1.10.4.5 yamt else if (!device_pmf_class_shutdown(curdev, how))
317 1.10.4.5 yamt aprint_debug("(failed)");
318 1.10.4.5 yamt #endif
319 1.10.4.5 yamt else if (!device_pmf_driver_shutdown(curdev, how))
320 1.10.4.5 yamt aprint_debug("(failed)");
321 1.10.4.5 yamt else if (!device_pmf_bus_shutdown(curdev, how))
322 1.10.4.5 yamt aprint_debug("(failed)");
323 1.10.4.2 yamt }
324 1.10.4.2 yamt
325 1.10.4.2 yamt aprint_debug(".\n");
326 1.10.4.2 yamt }
327 1.10.4.2 yamt
328 1.10.4.2 yamt bool
329 1.10.4.2 yamt pmf_set_platform(const char *key, const char *value)
330 1.10.4.2 yamt {
331 1.10.4.2 yamt if (pmf_platform == NULL)
332 1.10.4.2 yamt pmf_platform = prop_dictionary_create();
333 1.10.4.2 yamt if (pmf_platform == NULL)
334 1.10.4.2 yamt return false;
335 1.10.4.2 yamt
336 1.10.4.2 yamt return prop_dictionary_set_cstring(pmf_platform, key, value);
337 1.10.4.2 yamt }
338 1.10.4.2 yamt
339 1.10.4.2 yamt const char *
340 1.10.4.2 yamt pmf_get_platform(const char *key)
341 1.10.4.2 yamt {
342 1.10.4.2 yamt const char *value;
343 1.10.4.2 yamt
344 1.10.4.2 yamt if (pmf_platform == NULL)
345 1.10.4.2 yamt return NULL;
346 1.10.4.2 yamt
347 1.10.4.2 yamt if (!prop_dictionary_get_cstring_nocopy(pmf_platform, key, &value))
348 1.10.4.2 yamt return NULL;
349 1.10.4.2 yamt
350 1.10.4.2 yamt return value;
351 1.10.4.2 yamt }
352 1.10.4.2 yamt
353 1.10.4.2 yamt bool
354 1.10.4.5 yamt pmf_device_register1(device_t dev,
355 1.10.4.5 yamt bool (*suspend)(device_t PMF_FN_PROTO),
356 1.10.4.5 yamt bool (*resume)(device_t PMF_FN_PROTO),
357 1.10.4.5 yamt bool (*shutdown)(device_t, int))
358 1.10.4.2 yamt {
359 1.10.4.5 yamt if (!device_pmf_driver_register(dev, suspend, resume, shutdown))
360 1.10.4.5 yamt return false;
361 1.10.4.2 yamt
362 1.10.4.2 yamt if (!device_pmf_driver_child_register(dev)) {
363 1.10.4.2 yamt device_pmf_driver_deregister(dev);
364 1.10.4.2 yamt return false;
365 1.10.4.2 yamt }
366 1.10.4.2 yamt
367 1.10.4.2 yamt return true;
368 1.10.4.2 yamt }
369 1.10.4.2 yamt
370 1.10.4.2 yamt void
371 1.10.4.2 yamt pmf_device_deregister(device_t dev)
372 1.10.4.2 yamt {
373 1.10.4.2 yamt device_pmf_class_deregister(dev);
374 1.10.4.2 yamt device_pmf_bus_deregister(dev);
375 1.10.4.2 yamt device_pmf_driver_deregister(dev);
376 1.10.4.2 yamt }
377 1.10.4.2 yamt
378 1.10.4.2 yamt bool
379 1.10.4.5 yamt pmf_device_suspend_self(device_t dev)
380 1.10.4.2 yamt {
381 1.10.4.5 yamt return pmf_device_suspend(dev, PMF_F_SELF);
382 1.10.4.5 yamt }
383 1.10.4.5 yamt
384 1.10.4.5 yamt bool
385 1.10.4.5 yamt pmf_device_suspend(device_t dev PMF_FN_ARGS)
386 1.10.4.5 yamt {
387 1.10.4.5 yamt bool rc;
388 1.10.4.5 yamt
389 1.10.4.2 yamt PMF_TRANSITION_PRINTF(("%s: suspend enter\n", device_xname(dev)));
390 1.10.4.2 yamt if (!device_pmf_is_registered(dev))
391 1.10.4.2 yamt return false;
392 1.10.4.5 yamt
393 1.10.4.5 yamt if (!device_pmf_lock(dev PMF_FN_CALL))
394 1.10.4.5 yamt return false;
395 1.10.4.5 yamt
396 1.10.4.5 yamt rc = pmf_device_suspend_locked(dev PMF_FN_CALL);
397 1.10.4.5 yamt
398 1.10.4.5 yamt device_pmf_unlock(dev PMF_FN_CALL);
399 1.10.4.5 yamt
400 1.10.4.5 yamt PMF_TRANSITION_PRINTF(("%s: suspend exit\n", device_xname(dev)));
401 1.10.4.5 yamt return rc;
402 1.10.4.5 yamt }
403 1.10.4.5 yamt
404 1.10.4.5 yamt static bool
405 1.10.4.5 yamt pmf_device_suspend_locked(device_t dev PMF_FN_ARGS)
406 1.10.4.5 yamt {
407 1.10.4.5 yamt PMF_TRANSITION_PRINTF2(1, ("%s: self suspend\n", device_xname(dev)));
408 1.10.4.5 yamt device_pmf_self_suspend(dev, flags);
409 1.10.4.2 yamt PMF_TRANSITION_PRINTF2(1, ("%s: class suspend\n", device_xname(dev)));
410 1.10.4.5 yamt if (!device_pmf_class_suspend(dev PMF_FN_CALL))
411 1.10.4.2 yamt return false;
412 1.10.4.2 yamt PMF_TRANSITION_PRINTF2(1, ("%s: driver suspend\n", device_xname(dev)));
413 1.10.4.5 yamt if (!device_pmf_driver_suspend(dev PMF_FN_CALL))
414 1.10.4.2 yamt return false;
415 1.10.4.2 yamt PMF_TRANSITION_PRINTF2(1, ("%s: bus suspend\n", device_xname(dev)));
416 1.10.4.5 yamt if (!device_pmf_bus_suspend(dev PMF_FN_CALL))
417 1.10.4.2 yamt return false;
418 1.10.4.5 yamt
419 1.10.4.2 yamt return true;
420 1.10.4.2 yamt }
421 1.10.4.2 yamt
422 1.10.4.2 yamt bool
423 1.10.4.5 yamt pmf_device_resume_self(device_t dev)
424 1.10.4.2 yamt {
425 1.10.4.5 yamt return pmf_device_resume(dev, PMF_F_SELF);
426 1.10.4.5 yamt }
427 1.10.4.5 yamt
428 1.10.4.5 yamt bool
429 1.10.4.5 yamt pmf_device_resume(device_t dev PMF_FN_ARGS)
430 1.10.4.5 yamt {
431 1.10.4.5 yamt bool rc;
432 1.10.4.5 yamt
433 1.10.4.2 yamt PMF_TRANSITION_PRINTF(("%s: resume enter\n", device_xname(dev)));
434 1.10.4.2 yamt if (!device_pmf_is_registered(dev))
435 1.10.4.2 yamt return false;
436 1.10.4.5 yamt
437 1.10.4.5 yamt if (!device_pmf_lock(dev PMF_FN_CALL))
438 1.10.4.5 yamt return false;
439 1.10.4.5 yamt
440 1.10.4.5 yamt rc = pmf_device_resume_locked(dev PMF_FN_CALL);
441 1.10.4.5 yamt
442 1.10.4.5 yamt device_pmf_unlock(dev PMF_FN_CALL);
443 1.10.4.5 yamt
444 1.10.4.5 yamt PMF_TRANSITION_PRINTF(("%s: resume exit\n", device_xname(dev)));
445 1.10.4.5 yamt return rc;
446 1.10.4.5 yamt }
447 1.10.4.5 yamt
448 1.10.4.5 yamt static bool
449 1.10.4.5 yamt pmf_device_resume_locked(device_t dev PMF_FN_ARGS)
450 1.10.4.5 yamt {
451 1.10.4.2 yamt PMF_TRANSITION_PRINTF2(1, ("%s: bus resume\n", device_xname(dev)));
452 1.10.4.5 yamt if (!device_pmf_bus_resume(dev PMF_FN_CALL))
453 1.10.4.2 yamt return false;
454 1.10.4.2 yamt PMF_TRANSITION_PRINTF2(1, ("%s: driver resume\n", device_xname(dev)));
455 1.10.4.5 yamt if (!device_pmf_driver_resume(dev PMF_FN_CALL))
456 1.10.4.2 yamt return false;
457 1.10.4.2 yamt PMF_TRANSITION_PRINTF2(1, ("%s: class resume\n", device_xname(dev)));
458 1.10.4.5 yamt if (!device_pmf_class_resume(dev PMF_FN_CALL))
459 1.10.4.2 yamt return false;
460 1.10.4.5 yamt PMF_TRANSITION_PRINTF2(1, ("%s: self resume\n", device_xname(dev)));
461 1.10.4.5 yamt device_pmf_self_resume(dev, flags);
462 1.10.4.5 yamt
463 1.10.4.2 yamt return true;
464 1.10.4.2 yamt }
465 1.10.4.2 yamt
466 1.10.4.2 yamt bool
467 1.10.4.5 yamt pmf_device_recursive_suspend(device_t dv PMF_FN_ARGS)
468 1.10.4.2 yamt {
469 1.10.4.5 yamt bool rv = true;
470 1.10.4.2 yamt device_t curdev;
471 1.10.4.5 yamt deviter_t di;
472 1.10.4.2 yamt
473 1.10.4.2 yamt if (!device_is_active(dv))
474 1.10.4.2 yamt return true;
475 1.10.4.2 yamt
476 1.10.4.5 yamt for (curdev = deviter_first(&di, 0); curdev != NULL;
477 1.10.4.5 yamt curdev = deviter_next(&di)) {
478 1.10.4.2 yamt if (device_parent(curdev) != dv)
479 1.10.4.2 yamt continue;
480 1.10.4.5 yamt if (!pmf_device_recursive_suspend(curdev PMF_FN_CALL)) {
481 1.10.4.5 yamt rv = false;
482 1.10.4.5 yamt break;
483 1.10.4.5 yamt }
484 1.10.4.2 yamt }
485 1.10.4.5 yamt deviter_release(&di);
486 1.10.4.2 yamt
487 1.10.4.5 yamt return rv && pmf_device_suspend(dv PMF_FN_CALL);
488 1.10.4.2 yamt }
489 1.10.4.2 yamt
490 1.10.4.2 yamt bool
491 1.10.4.5 yamt pmf_device_recursive_resume(device_t dv PMF_FN_ARGS)
492 1.10.4.2 yamt {
493 1.10.4.2 yamt device_t parent;
494 1.10.4.2 yamt
495 1.10.4.2 yamt if (device_is_active(dv))
496 1.10.4.2 yamt return true;
497 1.10.4.2 yamt
498 1.10.4.2 yamt parent = device_parent(dv);
499 1.10.4.2 yamt if (parent != NULL) {
500 1.10.4.5 yamt if (!pmf_device_recursive_resume(parent PMF_FN_CALL))
501 1.10.4.2 yamt return false;
502 1.10.4.2 yamt }
503 1.10.4.2 yamt
504 1.10.4.5 yamt return pmf_device_resume(dv PMF_FN_CALL);
505 1.10.4.2 yamt }
506 1.10.4.2 yamt
507 1.10.4.2 yamt bool
508 1.10.4.5 yamt pmf_device_resume_subtree(device_t dv PMF_FN_ARGS)
509 1.10.4.2 yamt {
510 1.10.4.5 yamt bool rv = true;
511 1.10.4.2 yamt device_t curdev;
512 1.10.4.5 yamt deviter_t di;
513 1.10.4.2 yamt
514 1.10.4.5 yamt if (!pmf_device_recursive_resume(dv PMF_FN_CALL))
515 1.10.4.2 yamt return false;
516 1.10.4.2 yamt
517 1.10.4.5 yamt for (curdev = deviter_first(&di, 0); curdev != NULL;
518 1.10.4.5 yamt curdev = deviter_next(&di)) {
519 1.10.4.2 yamt if (device_parent(curdev) != dv)
520 1.10.4.2 yamt continue;
521 1.10.4.5 yamt if (!pmf_device_resume_subtree(curdev PMF_FN_CALL)) {
522 1.10.4.5 yamt rv = false;
523 1.10.4.5 yamt break;
524 1.10.4.5 yamt }
525 1.10.4.2 yamt }
526 1.10.4.5 yamt deviter_release(&di);
527 1.10.4.5 yamt return rv;
528 1.10.4.2 yamt }
529 1.10.4.2 yamt
530 1.10.4.2 yamt #include <net/if.h>
531 1.10.4.2 yamt
532 1.10.4.2 yamt static bool
533 1.10.4.5 yamt pmf_class_network_suspend(device_t dev PMF_FN_ARGS)
534 1.10.4.2 yamt {
535 1.10.4.2 yamt struct ifnet *ifp = device_pmf_class_private(dev);
536 1.10.4.2 yamt int s;
537 1.10.4.2 yamt
538 1.10.4.2 yamt s = splnet();
539 1.10.4.5 yamt (*ifp->if_stop)(ifp, 0);
540 1.10.4.2 yamt splx(s);
541 1.10.4.2 yamt
542 1.10.4.2 yamt return true;
543 1.10.4.2 yamt }
544 1.10.4.2 yamt
545 1.10.4.2 yamt static bool
546 1.10.4.5 yamt pmf_class_network_resume(device_t dev PMF_FN_ARGS)
547 1.10.4.2 yamt {
548 1.10.4.2 yamt struct ifnet *ifp = device_pmf_class_private(dev);
549 1.10.4.2 yamt int s;
550 1.10.4.2 yamt
551 1.10.4.5 yamt if ((flags & PMF_F_SELF) != 0)
552 1.10.4.5 yamt return true;
553 1.10.4.5 yamt
554 1.10.4.2 yamt s = splnet();
555 1.10.4.2 yamt if (ifp->if_flags & IFF_UP) {
556 1.10.4.2 yamt ifp->if_flags &= ~IFF_RUNNING;
557 1.10.4.2 yamt (*ifp->if_init)(ifp);
558 1.10.4.2 yamt (*ifp->if_start)(ifp);
559 1.10.4.2 yamt }
560 1.10.4.2 yamt splx(s);
561 1.10.4.2 yamt
562 1.10.4.2 yamt return true;
563 1.10.4.2 yamt }
564 1.10.4.2 yamt
565 1.10.4.2 yamt void
566 1.10.4.2 yamt pmf_class_network_register(device_t dev, struct ifnet *ifp)
567 1.10.4.2 yamt {
568 1.10.4.2 yamt device_pmf_class_register(dev, ifp, pmf_class_network_suspend,
569 1.10.4.2 yamt pmf_class_network_resume, NULL);
570 1.10.4.2 yamt }
571 1.10.4.2 yamt
572 1.10.4.2 yamt bool
573 1.10.4.2 yamt pmf_event_inject(device_t dv, pmf_generic_event_t ev)
574 1.10.4.2 yamt {
575 1.10.4.2 yamt pmf_event_workitem_t *pew;
576 1.10.4.2 yamt
577 1.10.4.2 yamt pew = malloc(sizeof(pmf_event_workitem_t), M_TEMP, M_NOWAIT);
578 1.10.4.2 yamt if (pew == NULL) {
579 1.10.4.2 yamt PMF_EVENT_PRINTF(("%s: PMF event %d dropped (no memory)\n",
580 1.10.4.2 yamt dv ? device_xname(dv) : "<anonymous>", ev));
581 1.10.4.2 yamt return false;
582 1.10.4.2 yamt }
583 1.10.4.2 yamt
584 1.10.4.2 yamt pew->pew_event = ev;
585 1.10.4.2 yamt pew->pew_device = dv;
586 1.10.4.2 yamt
587 1.10.4.2 yamt workqueue_enqueue(pmf_event_workqueue, (void *)pew, NULL);
588 1.10.4.2 yamt PMF_EVENT_PRINTF(("%s: PMF event %d injected\n",
589 1.10.4.2 yamt dv ? device_xname(dv) : "<anonymous>", ev));
590 1.10.4.2 yamt
591 1.10.4.2 yamt return true;
592 1.10.4.2 yamt }
593 1.10.4.2 yamt
594 1.10.4.2 yamt bool
595 1.10.4.2 yamt pmf_event_register(device_t dv, pmf_generic_event_t ev,
596 1.10.4.2 yamt void (*handler)(device_t), bool global)
597 1.10.4.2 yamt {
598 1.10.4.2 yamt pmf_event_handler_t *event;
599 1.10.4.2 yamt
600 1.10.4.2 yamt event = malloc(sizeof(*event), M_DEVBUF, M_WAITOK);
601 1.10.4.2 yamt event->pmf_event = ev;
602 1.10.4.2 yamt event->pmf_handler = handler;
603 1.10.4.2 yamt event->pmf_device = dv;
604 1.10.4.2 yamt event->pmf_global = global;
605 1.10.4.2 yamt TAILQ_INSERT_TAIL(&pmf_all_events, event, pmf_link);
606 1.10.4.2 yamt
607 1.10.4.2 yamt return true;
608 1.10.4.2 yamt }
609 1.10.4.2 yamt
610 1.10.4.2 yamt void
611 1.10.4.2 yamt pmf_event_deregister(device_t dv, pmf_generic_event_t ev,
612 1.10.4.2 yamt void (*handler)(device_t), bool global)
613 1.10.4.2 yamt {
614 1.10.4.2 yamt pmf_event_handler_t *event;
615 1.10.4.2 yamt
616 1.10.4.2 yamt TAILQ_FOREACH(event, &pmf_all_events, pmf_link) {
617 1.10.4.2 yamt if (event->pmf_event != ev)
618 1.10.4.2 yamt continue;
619 1.10.4.2 yamt if (event->pmf_device != dv)
620 1.10.4.2 yamt continue;
621 1.10.4.2 yamt if (event->pmf_global != global)
622 1.10.4.2 yamt continue;
623 1.10.4.2 yamt if (event->pmf_handler != handler)
624 1.10.4.2 yamt continue;
625 1.10.4.2 yamt TAILQ_REMOVE(&pmf_all_events, event, pmf_link);
626 1.10.4.3 yamt free(event, M_DEVBUF);
627 1.10.4.2 yamt return;
628 1.10.4.2 yamt }
629 1.10.4.2 yamt }
630 1.10.4.2 yamt
631 1.10.4.2 yamt struct display_class_softc {
632 1.10.4.2 yamt TAILQ_ENTRY(display_class_softc) dc_link;
633 1.10.4.2 yamt device_t dc_dev;
634 1.10.4.2 yamt };
635 1.10.4.2 yamt
636 1.10.4.2 yamt static TAILQ_HEAD(, display_class_softc) all_displays;
637 1.10.4.2 yamt static callout_t global_idle_counter;
638 1.10.4.2 yamt static int idle_timeout = 30;
639 1.10.4.2 yamt
640 1.10.4.2 yamt static void
641 1.10.4.2 yamt input_idle(void *dummy)
642 1.10.4.2 yamt {
643 1.10.4.2 yamt PMF_IDLE_PRINTF(("Input idle handler called\n"));
644 1.10.4.2 yamt pmf_event_inject(NULL, PMFE_DISPLAY_OFF);
645 1.10.4.2 yamt }
646 1.10.4.2 yamt
647 1.10.4.2 yamt static void
648 1.10.4.2 yamt input_activity_handler(device_t dv, devactive_t type)
649 1.10.4.2 yamt {
650 1.10.4.2 yamt if (!TAILQ_EMPTY(&all_displays))
651 1.10.4.2 yamt callout_schedule(&global_idle_counter, idle_timeout * hz);
652 1.10.4.2 yamt }
653 1.10.4.2 yamt
654 1.10.4.2 yamt static void
655 1.10.4.2 yamt pmf_class_input_deregister(device_t dv)
656 1.10.4.2 yamt {
657 1.10.4.2 yamt device_active_deregister(dv, input_activity_handler);
658 1.10.4.2 yamt }
659 1.10.4.2 yamt
660 1.10.4.2 yamt bool
661 1.10.4.2 yamt pmf_class_input_register(device_t dv)
662 1.10.4.2 yamt {
663 1.10.4.2 yamt if (!device_active_register(dv, input_activity_handler))
664 1.10.4.2 yamt return false;
665 1.10.4.2 yamt
666 1.10.4.2 yamt device_pmf_class_register(dv, NULL, NULL, NULL,
667 1.10.4.2 yamt pmf_class_input_deregister);
668 1.10.4.2 yamt
669 1.10.4.2 yamt return true;
670 1.10.4.2 yamt }
671 1.10.4.2 yamt
672 1.10.4.2 yamt static void
673 1.10.4.2 yamt pmf_class_display_deregister(device_t dv)
674 1.10.4.2 yamt {
675 1.10.4.2 yamt struct display_class_softc *sc = device_pmf_class_private(dv);
676 1.10.4.2 yamt int s;
677 1.10.4.2 yamt
678 1.10.4.2 yamt s = splsoftclock();
679 1.10.4.2 yamt TAILQ_REMOVE(&all_displays, sc, dc_link);
680 1.10.4.2 yamt if (TAILQ_EMPTY(&all_displays))
681 1.10.4.2 yamt callout_stop(&global_idle_counter);
682 1.10.4.2 yamt splx(s);
683 1.10.4.2 yamt
684 1.10.4.2 yamt free(sc, M_DEVBUF);
685 1.10.4.2 yamt }
686 1.10.4.2 yamt
687 1.10.4.2 yamt bool
688 1.10.4.2 yamt pmf_class_display_register(device_t dv)
689 1.10.4.2 yamt {
690 1.10.4.2 yamt struct display_class_softc *sc;
691 1.10.4.2 yamt int s;
692 1.10.4.2 yamt
693 1.10.4.2 yamt sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK);
694 1.10.4.2 yamt
695 1.10.4.2 yamt s = splsoftclock();
696 1.10.4.2 yamt if (TAILQ_EMPTY(&all_displays))
697 1.10.4.2 yamt callout_schedule(&global_idle_counter, idle_timeout * hz);
698 1.10.4.2 yamt
699 1.10.4.2 yamt TAILQ_INSERT_HEAD(&all_displays, sc, dc_link);
700 1.10.4.2 yamt splx(s);
701 1.10.4.2 yamt
702 1.10.4.2 yamt device_pmf_class_register(dv, sc, NULL, NULL,
703 1.10.4.2 yamt pmf_class_display_deregister);
704 1.10.4.2 yamt
705 1.10.4.2 yamt return true;
706 1.10.4.2 yamt }
707 1.10.4.2 yamt
708 1.10.4.2 yamt void
709 1.10.4.2 yamt pmf_init(void)
710 1.10.4.2 yamt {
711 1.10.4.2 yamt int err;
712 1.10.4.2 yamt
713 1.10.4.2 yamt KASSERT(pmf_event_workqueue == NULL);
714 1.10.4.2 yamt err = workqueue_create(&pmf_event_workqueue, "pmfevent",
715 1.10.4.2 yamt pmf_event_worker, NULL, PRI_NONE, IPL_VM, 0);
716 1.10.4.2 yamt if (err)
717 1.10.4.2 yamt panic("couldn't create pmfevent workqueue");
718 1.10.4.2 yamt
719 1.10.4.2 yamt callout_init(&global_idle_counter, 0);
720 1.10.4.2 yamt callout_setfunc(&global_idle_counter, input_idle, NULL);
721 1.10.4.2 yamt }
722