kern_pmf.c revision 1.36
1/* $NetBSD: kern_pmf.c,v 1.36 2012/11/13 14:08:07 chs Exp $ */ 2 3/*- 4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.36 2012/11/13 14:08:07 chs Exp $"); 31 32#include <sys/types.h> 33#include <sys/param.h> 34#include <sys/kmem.h> 35#include <sys/buf.h> 36#include <sys/callout.h> 37#include <sys/kernel.h> 38#include <sys/device.h> 39#include <sys/pmf.h> 40#include <sys/queue.h> 41#include <sys/sched.h> 42#include <sys/workqueue.h> 43#include <prop/proplib.h> 44#include <sys/condvar.h> 45#include <sys/mutex.h> 46#include <sys/proc.h> 47#include <sys/reboot.h> /* for RB_NOSYNC */ 48#include <sys/sched.h> 49#include <sys/vfs_syscalls.h> 50 51/* XXX ugly special case, but for now the only client */ 52#include "wsdisplay.h" 53#if NWSDISPLAY > 0 54#include <dev/wscons/wsdisplayvar.h> 55#endif 56 57#ifndef PMF_DEBUG 58#define PMF_DEBUG 59#endif 60 61#ifdef PMF_DEBUG 62int pmf_debug_event; 63int pmf_debug_suspend; 64int pmf_debug_suspensor; 65int pmf_debug_idle; 66int pmf_debug_transition; 67 68#define PMF_SUSPENSOR_PRINTF(x) if (pmf_debug_suspensor) printf x 69#define PMF_SUSPEND_PRINTF(x) if (pmf_debug_suspend) printf x 70#define PMF_EVENT_PRINTF(x) if (pmf_debug_event) printf x 71#define PMF_IDLE_PRINTF(x) if (pmf_debug_idle) printf x 72#define PMF_TRANSITION_PRINTF(x) if (pmf_debug_transition) printf x 73#define PMF_TRANSITION_PRINTF2(y,x) if (pmf_debug_transition>y) printf x 74#else 75#define PMF_SUSPENSOR_PRINTF(x) do { } while (0) 76#define PMF_SUSPEND_PRINTF(x) do { } while (0) 77#define PMF_EVENT_PRINTF(x) do { } while (0) 78#define PMF_IDLE_PRINTF(x) do { } while (0) 79#define PMF_TRANSITION_PRINTF(x) do { } while (0) 80#define PMF_TRANSITION_PRINTF2(y,x) do { } while (0) 81#endif 82 83/* #define PMF_DEBUG */ 84 85#include <sys/mallocvar.h> 86MALLOC_DEFINE(M_PMF, "pmf", "device pmf messaging memory"); 87 88static prop_dictionary_t pmf_platform = NULL; 89static struct workqueue *pmf_event_workqueue; 90static struct workqueue *pmf_suspend_workqueue; 91 92typedef struct pmf_event_handler { 93 TAILQ_ENTRY(pmf_event_handler) pmf_link; 94 pmf_generic_event_t pmf_event; 95 void (*pmf_handler)(device_t); 96 device_t pmf_device; 97 bool pmf_global; 98} pmf_event_handler_t; 99 100static TAILQ_HEAD(, pmf_event_handler) pmf_all_events = 101 TAILQ_HEAD_INITIALIZER(pmf_all_events); 102 103typedef struct pmf_event_workitem { 104 struct work pew_work; 105 pmf_generic_event_t pew_event; 106 device_t pew_device; 107} pmf_event_workitem_t; 108 109typedef struct pmf_suspend_workitem { 110 struct work psw_work; 111 device_t psw_dev; 112 pmf_qual_t psw_qual; 113} pmf_suspend_workitem_t; 114 115static struct pool pew_pl; 116 117static pmf_event_workitem_t *pmf_event_workitem_get(void); 118static void pmf_event_workitem_put(pmf_event_workitem_t *); 119 120bool pmf_device_resume_locked(device_t, const pmf_qual_t *); 121bool pmf_device_suspend_locked(device_t, const pmf_qual_t *); 122static bool device_pmf_any_suspensor(device_t, devact_level_t); 123 124static bool 125complete_suspension(device_t dev, const device_suspensor_t **susp, 126 const pmf_qual_t *pqp) 127{ 128 int i; 129 pmf_qual_t pq; 130 const device_suspensor_t *ds; 131 132 ds = pmf_qual_suspension(pqp); 133 KASSERT(ds->ds_delegator != NULL); 134 135 pq = *pqp; 136 pq.pq_suspensor = ds->ds_delegator; 137 138 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 139 if (susp[i] != ds) 140 continue; 141 if (!pmf_device_suspend(dev, &pq)) 142 return false; 143 } 144 return true; 145} 146 147static void 148pmf_suspend_worker(struct work *wk, void *dummy) 149{ 150 pmf_suspend_workitem_t *psw; 151 deviter_t di; 152 device_t dev; 153 154 psw = (void *)wk; 155 KASSERT(wk == &psw->psw_work); 156 KASSERT(psw != NULL); 157 158 for (dev = deviter_first(&di, 0); dev != NULL; 159 dev = deviter_next(&di)) { 160 if (dev == psw->psw_dev && device_pmf_lock(dev)) 161 break; 162 } 163 deviter_release(&di); 164 165 if (dev == NULL) 166 return; 167 168 switch (pmf_qual_depth(&psw->psw_qual)) { 169 case DEVACT_LEVEL_FULL: 170 if (!complete_suspension(dev, dev->dv_class_suspensors, 171 &psw->psw_qual)) 172 break; 173 /*FALLTHROUGH*/ 174 case DEVACT_LEVEL_DRIVER: 175 if (!complete_suspension(dev, dev->dv_driver_suspensors, 176 &psw->psw_qual)) 177 break; 178 /*FALLTHROUGH*/ 179 case DEVACT_LEVEL_BUS: 180 if (!complete_suspension(dev, dev->dv_bus_suspensors, 181 &psw->psw_qual)) 182 break; 183 } 184 device_pmf_unlock(dev); 185 kmem_free(psw, sizeof(*psw)); 186} 187 188static void 189pmf_event_worker(struct work *wk, void *dummy) 190{ 191 pmf_event_workitem_t *pew; 192 pmf_event_handler_t *event; 193 194 pew = (void *)wk; 195 KASSERT(wk == &pew->pew_work); 196 KASSERT(pew != NULL); 197 198 TAILQ_FOREACH(event, &pmf_all_events, pmf_link) { 199 if (event->pmf_event != pew->pew_event) 200 continue; 201 if (event->pmf_device == pew->pew_device || event->pmf_global) 202 (*event->pmf_handler)(event->pmf_device); 203 } 204 205 pmf_event_workitem_put(pew); 206} 207 208static bool 209pmf_check_system_drivers(void) 210{ 211 device_t curdev; 212 bool unsupported_devs; 213 deviter_t di; 214 215 unsupported_devs = false; 216 for (curdev = deviter_first(&di, 0); curdev != NULL; 217 curdev = deviter_next(&di)) { 218 if (device_pmf_is_registered(curdev)) 219 continue; 220 if (!unsupported_devs) 221 printf("Devices without power management support:"); 222 printf(" %s", device_xname(curdev)); 223 unsupported_devs = true; 224 } 225 deviter_release(&di); 226 if (unsupported_devs) { 227 printf("\n"); 228 return false; 229 } 230 return true; 231} 232 233bool 234pmf_system_bus_resume(const pmf_qual_t *qual) 235{ 236 bool rv; 237 device_t curdev; 238 deviter_t di; 239 240 aprint_debug("Powering devices:"); 241 /* D0 handlers are run in order */ 242 rv = true; 243 for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); curdev != NULL; 244 curdev = deviter_next(&di)) { 245 if (!device_pmf_is_registered(curdev)) 246 continue; 247 if (device_is_active(curdev) || 248 !device_is_enabled(curdev)) 249 continue; 250 251 aprint_debug(" %s", device_xname(curdev)); 252 253 if (!device_pmf_bus_resume(curdev, qual)) { 254 rv = false; 255 aprint_debug("(failed)"); 256 } 257 } 258 deviter_release(&di); 259 aprint_debug("\n"); 260 261 return rv; 262} 263 264bool 265pmf_system_resume(const pmf_qual_t *qual) 266{ 267 bool rv; 268 device_t curdev, parent; 269 deviter_t di; 270 271 if (!pmf_check_system_drivers()) 272 return false; 273 274 aprint_debug("Resuming devices:"); 275 /* D0 handlers are run in order */ 276 rv = true; 277 for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); curdev != NULL; 278 curdev = deviter_next(&di)) { 279 if (device_is_active(curdev) || 280 !device_is_enabled(curdev)) 281 continue; 282 parent = device_parent(curdev); 283 if (parent != NULL && 284 !device_is_active(parent)) 285 continue; 286 287 aprint_debug(" %s", device_xname(curdev)); 288 289 if (!pmf_device_resume(curdev, qual)) { 290 rv = false; 291 aprint_debug("(failed)"); 292 } 293 } 294 deviter_release(&di); 295 aprint_debug(".\n"); 296 297 KERNEL_UNLOCK_ONE(0); 298#if NWSDISPLAY > 0 299 if (rv) 300 wsdisplay_handlex(1); 301#endif 302 return rv; 303} 304 305bool 306pmf_system_suspend(const pmf_qual_t *qual) 307{ 308 device_t curdev; 309 deviter_t di; 310 311 if (!pmf_check_system_drivers()) 312 return false; 313#if NWSDISPLAY > 0 314 if (wsdisplay_handlex(0)) 315 return false; 316#endif 317 KERNEL_LOCK(1, NULL); 318 319 /* 320 * Flush buffers only if the shutdown didn't do so 321 * already and if there was no panic. 322 */ 323 if (doing_shutdown == 0 && panicstr == NULL) { 324 printf("Flushing disk caches: "); 325 do_sys_sync(&lwp0); 326 if (buf_syncwait() != 0) 327 printf("giving up\n"); 328 else 329 printf("done\n"); 330 } 331 332 aprint_debug("Suspending devices:"); 333 334 for (curdev = deviter_first(&di, DEVITER_F_LEAVES_FIRST); 335 curdev != NULL; 336 curdev = deviter_next(&di)) { 337 if (!device_is_active(curdev)) 338 continue; 339 340 aprint_debug(" %s", device_xname(curdev)); 341 342 /* XXX joerg check return value and abort suspend */ 343 if (!pmf_device_suspend(curdev, qual)) 344 aprint_debug("(failed)"); 345 } 346 deviter_release(&di); 347 348 aprint_debug(".\n"); 349 350 return true; 351} 352 353static bool 354shutdown_all(int how) 355{ 356 static struct shutdown_state s; 357 device_t curdev; 358 bool progress = false; 359 360 for (curdev = shutdown_first(&s); curdev != NULL; 361 curdev = shutdown_next(&s)) { 362 aprint_debug(" shutting down %s, ", device_xname(curdev)); 363 if (!device_pmf_is_registered(curdev)) 364 aprint_debug("skipped."); 365#if 0 /* needed? */ 366 else if (!device_pmf_class_shutdown(curdev, how)) 367 aprint_debug("failed."); 368#endif 369 else if (!device_pmf_driver_shutdown(curdev, how)) 370 aprint_debug("failed."); 371 else if (!device_pmf_bus_shutdown(curdev, how)) 372 aprint_debug("failed."); 373 else { 374 progress = true; 375 aprint_debug("success."); 376 } 377 } 378 return progress; 379} 380 381void 382pmf_system_shutdown(int how) 383{ 384 385 if (panicstr != NULL) 386 return; 387 388 aprint_debug("Shutting down devices:"); 389 shutdown_all(how); 390} 391 392bool 393pmf_set_platform(const char *key, const char *value) 394{ 395 if (pmf_platform == NULL) 396 pmf_platform = prop_dictionary_create(); 397 if (pmf_platform == NULL) 398 return false; 399 400 return prop_dictionary_set_cstring(pmf_platform, key, value); 401} 402 403const char * 404pmf_get_platform(const char *key) 405{ 406 const char *value; 407 408 if (pmf_platform == NULL) 409 return NULL; 410 411 if (!prop_dictionary_get_cstring_nocopy(pmf_platform, key, &value)) 412 return NULL; 413 414 return value; 415} 416 417bool 418pmf_device_register1(device_t dev, 419 bool (*suspend)(device_t, const pmf_qual_t *), 420 bool (*resume)(device_t, const pmf_qual_t *), 421 bool (*shutdown)(device_t, int)) 422{ 423 if (!device_pmf_driver_register(dev, suspend, resume, shutdown)) 424 return false; 425 426 if (!device_pmf_driver_child_register(dev)) { 427 device_pmf_driver_deregister(dev); 428 return false; 429 } 430 431 return true; 432} 433 434void 435pmf_device_deregister(device_t dev) 436{ 437 device_pmf_class_deregister(dev); 438 device_pmf_bus_deregister(dev); 439 device_pmf_driver_deregister(dev); 440} 441 442static const device_suspensor_t _device_suspensor_drvctl = { 443 .ds_delegator = NULL 444 , .ds_name = "drvctl" 445}; 446 447static const device_suspensor_t _device_suspensor_self = { 448 .ds_delegator = NULL 449 , .ds_name = "self" 450}; 451 452#if 0 453static const device_suspensor_t _device_suspensor_self_delegate = { 454 .ds_delegator = &_device_suspensor_self 455 , .ds_name = "self delegate" 456}; 457#endif 458 459static const device_suspensor_t _device_suspensor_system = { 460 .ds_delegator = NULL 461 , .ds_name = "system" 462}; 463 464const device_suspensor_t 465 * const device_suspensor_self = &_device_suspensor_self, 466#if 0 467 * const device_suspensor_self_delegate = &_device_suspensor_self_delegate, 468#endif 469 * const device_suspensor_system = &_device_suspensor_system, 470 * const device_suspensor_drvctl = &_device_suspensor_drvctl; 471 472static const pmf_qual_t _pmf_qual_system = { 473 .pq_actlvl = DEVACT_LEVEL_FULL 474 , .pq_suspensor = &_device_suspensor_system 475}; 476 477static const pmf_qual_t _pmf_qual_drvctl = { 478 .pq_actlvl = DEVACT_LEVEL_FULL 479 , .pq_suspensor = &_device_suspensor_drvctl 480}; 481 482static const pmf_qual_t _pmf_qual_self = { 483 .pq_actlvl = DEVACT_LEVEL_DRIVER 484 , .pq_suspensor = &_device_suspensor_self 485}; 486 487const pmf_qual_t 488 * const PMF_Q_DRVCTL = &_pmf_qual_drvctl, 489 * const PMF_Q_NONE = &_pmf_qual_system, 490 * const PMF_Q_SELF = &_pmf_qual_self; 491 492static bool 493device_suspensor_delegates_to(const device_suspensor_t *ds, 494 const device_suspensor_t *delegate) 495{ 496 const device_suspensor_t *iter; 497 498 for (iter = delegate->ds_delegator; iter != NULL; 499 iter = iter->ds_delegator) { 500 if (ds == iter) 501 return true; 502 } 503 return false; 504} 505 506static bool 507add_suspensor(device_t dev, const char *kind, const device_suspensor_t **susp, 508 const device_suspensor_t *ds) 509{ 510 int i; 511 512 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 513 if (susp[i] == NULL) 514 continue; 515 if (ds == susp[i]) { 516 PMF_SUSPENSOR_PRINTF(( 517 "%s: %s-suspended by %s (delegator %s) already\n", 518 device_xname(dev), kind, 519 susp[i]->ds_name, 520 (susp[i]->ds_delegator != NULL) ? 521 susp[i]->ds_delegator->ds_name : "<none>")); 522 return true; 523 } 524 if (device_suspensor_delegates_to(ds, susp[i])) { 525 PMF_SUSPENSOR_PRINTF(( 526 "%s: %s assumes %s-suspension by %s " 527 "(delegator %s)\n", 528 device_xname(dev), ds->ds_name, kind, 529 susp[i]->ds_name, 530 (susp[i]->ds_delegator != NULL) ? 531 susp[i]->ds_delegator->ds_name : "<none>")); 532 susp[i] = ds; 533 return true; 534 } 535 } 536 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 537 if (susp[i] == NULL) { 538 susp[i] = ds; 539 PMF_SUSPENSOR_PRINTF(( 540 "%s: newly %s-suspended by %s (delegator %s)\n", 541 device_xname(dev), kind, 542 susp[i]->ds_name, 543 (susp[i]->ds_delegator != NULL) ? 544 susp[i]->ds_delegator->ds_name : "<none>")); 545 return true; 546 } 547 } 548 return false; 549} 550 551static bool 552device_pmf_add_suspensor(device_t dev, const pmf_qual_t *pq) 553{ 554 const device_suspensor_t *ds; 555 556 KASSERT(pq != NULL); 557 558 ds = pmf_qual_suspension(pq); 559 560 KASSERT(ds != NULL); 561 562 if (!add_suspensor(dev, "class", dev->dv_class_suspensors, ds)) 563 return false; 564 if (!add_suspensor(dev, "driver", dev->dv_driver_suspensors, ds)) 565 return false; 566 if (!add_suspensor(dev, "bus", dev->dv_bus_suspensors, ds)) 567 return false; 568 return true; 569} 570 571#if 0 572static bool 573device_pmf_has_suspension(device_t dev, const device_suspensor_t *ds) 574{ 575 int i; 576 577 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 578 if (dev->dv_suspensions[i] == ds) 579 return true; 580 if (device_suspensor_delegates_to(dev->dv_suspensions[i], ds)) 581 return true; 582 } 583 return false; 584} 585#endif 586 587static bool 588any_suspensor(device_t dev, const char *kind, const device_suspensor_t **susp) 589{ 590 int i; 591 bool suspended = false; 592 593 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 594 if (susp[i] != NULL) { 595 PMF_SUSPENSOR_PRINTF(("%s: %s is suspended by %s " 596 "(delegator %s)\n", 597 device_xname(dev), kind, 598 susp[i]->ds_name, 599 (susp[i]->ds_delegator != NULL) ? 600 susp[i]->ds_delegator->ds_name : "<none>")); 601 suspended = true; 602 } 603 } 604 return suspended; 605} 606 607static bool 608device_pmf_any_suspensor(device_t dev, devact_level_t depth) 609{ 610 switch (depth) { 611 case DEVACT_LEVEL_FULL: 612 if (any_suspensor(dev, "class", dev->dv_class_suspensors)) 613 return true; 614 /*FALLTHROUGH*/ 615 case DEVACT_LEVEL_DRIVER: 616 if (any_suspensor(dev, "driver", dev->dv_driver_suspensors)) 617 return true; 618 /*FALLTHROUGH*/ 619 case DEVACT_LEVEL_BUS: 620 if (any_suspensor(dev, "bus", dev->dv_bus_suspensors)) 621 return true; 622 } 623 return false; 624} 625 626static bool 627remove_suspensor(device_t dev, const char *kind, 628 const device_suspensor_t **susp, const device_suspensor_t *ds) 629{ 630 int i; 631 632 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 633 if (susp[i] == NULL) 634 continue; 635 if (ds == susp[i] || 636 device_suspensor_delegates_to(ds, susp[i])) { 637 PMF_SUSPENSOR_PRINTF(("%s: %s suspension %s " 638 "(delegator %s) removed by %s\n", 639 device_xname(dev), kind, 640 susp[i]->ds_name, 641 (susp[i]->ds_delegator != NULL) 642 ? susp[i]->ds_delegator->ds_name 643 : "<none>", 644 ds->ds_name)); 645 susp[i] = NULL; 646 return true; 647 } 648 } 649 return false; 650} 651 652static bool 653device_pmf_remove_suspensor(device_t dev, const pmf_qual_t *pq) 654{ 655 const device_suspensor_t *ds; 656 657 KASSERT(pq != NULL); 658 659 ds = pmf_qual_suspension(pq); 660 661 KASSERT(ds != NULL); 662 663 if (!remove_suspensor(dev, "class", dev->dv_class_suspensors, ds)) 664 return false; 665 if (!remove_suspensor(dev, "driver", dev->dv_driver_suspensors, ds)) 666 return false; 667 if (!remove_suspensor(dev, "bus", dev->dv_bus_suspensors, ds)) 668 return false; 669 670 return true; 671} 672 673void 674pmf_self_suspensor_init(device_t dev, device_suspensor_t *ds, 675 pmf_qual_t *pq) 676{ 677 ds->ds_delegator = device_suspensor_self; 678 snprintf(ds->ds_name, sizeof(ds->ds_name), "%s-self", 679 device_xname(dev)); 680 pq->pq_actlvl = DEVACT_LEVEL_DRIVER; 681 pq->pq_suspensor = ds; 682} 683 684bool 685pmf_device_suspend(device_t dev, const pmf_qual_t *qual) 686{ 687 bool rc; 688 689 PMF_TRANSITION_PRINTF(("%s: suspend enter\n", device_xname(dev))); 690 if (!device_pmf_is_registered(dev)) 691 return false; 692 693 if (!device_pmf_lock(dev)) 694 return false; 695 696 rc = pmf_device_suspend_locked(dev, qual); 697 698 device_pmf_unlock(dev); 699 700 PMF_TRANSITION_PRINTF(("%s: suspend exit\n", device_xname(dev))); 701 return rc; 702} 703 704bool 705pmf_device_suspend_locked(device_t dev, const pmf_qual_t *qual) 706{ 707 if (!device_pmf_add_suspensor(dev, qual)) 708 return false; 709 710 PMF_TRANSITION_PRINTF2(1, ("%s: class suspend\n", device_xname(dev))); 711 if (!device_pmf_class_suspend(dev, qual)) 712 return false; 713 714 PMF_TRANSITION_PRINTF2(1, ("%s: driver suspend\n", device_xname(dev))); 715 if (!device_pmf_driver_suspend(dev, qual)) 716 return false; 717 718 PMF_TRANSITION_PRINTF2(1, ("%s: bus suspend\n", device_xname(dev))); 719 if (!device_pmf_bus_suspend(dev, qual)) 720 return false; 721 722 return true; 723} 724 725bool 726pmf_device_resume(device_t dev, const pmf_qual_t *qual) 727{ 728 bool rc; 729 730 PMF_TRANSITION_PRINTF(("%s: resume enter\n", device_xname(dev))); 731 if (!device_pmf_is_registered(dev)) 732 return false; 733 734 if (!device_pmf_lock(dev)) 735 return false; 736 737 rc = pmf_device_resume_locked(dev, qual); 738 739 device_pmf_unlock(dev); 740 741 PMF_TRANSITION_PRINTF(("%s: resume exit\n", device_xname(dev))); 742 return rc; 743} 744 745bool 746pmf_device_resume_locked(device_t dev, const pmf_qual_t *qual) 747{ 748 device_pmf_remove_suspensor(dev, qual); 749 750 if (device_pmf_any_suspensor(dev, DEVACT_LEVEL_FULL)) 751 return true; 752 753 PMF_TRANSITION_PRINTF2(1, ("%s: bus resume\n", device_xname(dev))); 754 if (!device_pmf_bus_resume(dev, qual)) 755 return false; 756 757 PMF_TRANSITION_PRINTF2(1, ("%s: driver resume\n", device_xname(dev))); 758 if (!device_pmf_driver_resume(dev, qual)) 759 return false; 760 761 PMF_TRANSITION_PRINTF2(1, ("%s: class resume\n", device_xname(dev))); 762 if (!device_pmf_class_resume(dev, qual)) 763 return false; 764 765 return true; 766} 767 768bool 769pmf_device_recursive_suspend(device_t dv, const pmf_qual_t *qual) 770{ 771 bool rv = true; 772 device_t curdev; 773 deviter_t di; 774 pmf_qual_t pq; 775 776 pmf_qual_recursive_copy(&pq, qual); 777 778 for (curdev = deviter_first(&di, 0); curdev != NULL; 779 curdev = deviter_next(&di)) { 780 if (device_parent(curdev) != dv) 781 continue; 782 if (!pmf_device_recursive_suspend(curdev, &pq)) { 783 rv = false; 784 break; 785 } 786 } 787 deviter_release(&di); 788 789 return rv && pmf_device_suspend(dv, qual); 790} 791 792void 793pmf_qual_recursive_copy(pmf_qual_t *dst, const pmf_qual_t *src) 794{ 795 *dst = *src; 796 dst->pq_actlvl = DEVACT_LEVEL_FULL; 797} 798 799bool 800pmf_device_recursive_resume(device_t dv, const pmf_qual_t *qual) 801{ 802 device_t parent; 803 pmf_qual_t pq; 804 805 if (device_is_active(dv)) 806 return true; 807 808 pmf_qual_recursive_copy(&pq, qual); 809 810 parent = device_parent(dv); 811 if (parent != NULL) { 812 if (!pmf_device_recursive_resume(parent, &pq)) 813 return false; 814 } 815 816 return pmf_device_resume(dv, qual); 817} 818 819bool 820pmf_device_descendants_release(device_t dv, const pmf_qual_t *qual) 821{ 822 bool rv = true; 823 device_t curdev; 824 deviter_t di; 825 826 for (curdev = deviter_first(&di, 0); curdev != NULL; 827 curdev = deviter_next(&di)) { 828 if (device_parent(curdev) != dv) 829 continue; 830 device_pmf_remove_suspensor(curdev, qual); 831 if (!pmf_device_descendants_release(curdev, qual)) { 832 rv = false; 833 break; 834 } 835 } 836 deviter_release(&di); 837 return rv; 838} 839 840bool 841pmf_device_descendants_resume(device_t dv, const pmf_qual_t *qual) 842{ 843 bool rv = true; 844 device_t curdev; 845 deviter_t di; 846 847 KASSERT(pmf_qual_descend_ok(qual)); 848 849 for (curdev = deviter_first(&di, 0); curdev != NULL; 850 curdev = deviter_next(&di)) { 851 if (device_parent(curdev) != dv) 852 continue; 853 if (!pmf_device_resume(curdev, qual) || 854 !pmf_device_descendants_resume(curdev, qual)) { 855 rv = false; 856 break; 857 } 858 } 859 deviter_release(&di); 860 return rv; 861} 862 863bool 864pmf_device_subtree_release(device_t dv, const pmf_qual_t *qual) 865{ 866 pmf_qual_t pq; 867 868 device_pmf_remove_suspensor(dv, qual); 869 870 pmf_qual_recursive_copy(&pq, qual); 871 872 return pmf_device_descendants_release(dv, &pq); 873} 874 875bool 876pmf_device_subtree_resume(device_t dv, const pmf_qual_t *qual) 877{ 878 pmf_qual_t pq; 879 880 if (!pmf_device_subtree_release(dv, qual)) 881 return false; 882 883 if (!pmf_device_recursive_resume(dv, qual)) 884 return false; 885 886 pmf_qual_recursive_copy(&pq, qual); 887 888 return pmf_device_descendants_resume(dv, &pq); 889} 890 891#include <net/if.h> 892 893static bool 894pmf_class_network_suspend(device_t dev, const pmf_qual_t *qual) 895{ 896 struct ifnet *ifp = device_pmf_class_private(dev); 897 int s; 898 899 s = splnet(); 900 (*ifp->if_stop)(ifp, 0); 901 splx(s); 902 903 return true; 904} 905 906static bool 907pmf_class_network_resume(device_t dev, const pmf_qual_t *qual) 908{ 909 struct ifnet *ifp = device_pmf_class_private(dev); 910 int s; 911 912 s = splnet(); 913 if (ifp->if_flags & IFF_UP) { 914 ifp->if_flags &= ~IFF_RUNNING; 915 if ((*ifp->if_init)(ifp) != 0) 916 aprint_normal_ifnet(ifp, "resume failed\n"); 917 (*ifp->if_start)(ifp); 918 } 919 splx(s); 920 921 return true; 922} 923 924void 925pmf_class_network_register(device_t dev, struct ifnet *ifp) 926{ 927 device_pmf_class_register(dev, ifp, pmf_class_network_suspend, 928 pmf_class_network_resume, NULL); 929} 930 931bool 932pmf_event_inject(device_t dv, pmf_generic_event_t ev) 933{ 934 pmf_event_workitem_t *pew; 935 936 pew = pmf_event_workitem_get(); 937 if (pew == NULL) { 938 PMF_EVENT_PRINTF(("%s: PMF event %d dropped (no memory)\n", 939 dv ? device_xname(dv) : "<anonymous>", ev)); 940 return false; 941 } 942 943 pew->pew_event = ev; 944 pew->pew_device = dv; 945 946 workqueue_enqueue(pmf_event_workqueue, &pew->pew_work, NULL); 947 PMF_EVENT_PRINTF(("%s: PMF event %d injected\n", 948 dv ? device_xname(dv) : "<anonymous>", ev)); 949 950 return true; 951} 952 953bool 954pmf_event_register(device_t dv, pmf_generic_event_t ev, 955 void (*handler)(device_t), bool global) 956{ 957 pmf_event_handler_t *event; 958 959 event = kmem_alloc(sizeof(*event), KM_SLEEP); 960 event->pmf_event = ev; 961 event->pmf_handler = handler; 962 event->pmf_device = dv; 963 event->pmf_global = global; 964 TAILQ_INSERT_TAIL(&pmf_all_events, event, pmf_link); 965 966 return true; 967} 968 969void 970pmf_event_deregister(device_t dv, pmf_generic_event_t ev, 971 void (*handler)(device_t), bool global) 972{ 973 pmf_event_handler_t *event; 974 975 TAILQ_FOREACH(event, &pmf_all_events, pmf_link) { 976 if (event->pmf_event != ev) 977 continue; 978 if (event->pmf_device != dv) 979 continue; 980 if (event->pmf_global != global) 981 continue; 982 if (event->pmf_handler != handler) 983 continue; 984 TAILQ_REMOVE(&pmf_all_events, event, pmf_link); 985 kmem_free(event, sizeof(*event)); 986 return; 987 } 988} 989 990struct display_class_softc { 991 TAILQ_ENTRY(display_class_softc) dc_link; 992 device_t dc_dev; 993}; 994 995static TAILQ_HEAD(, display_class_softc) all_displays; 996static callout_t global_idle_counter; 997static int idle_timeout = 30; 998 999static void 1000input_idle(void *dummy) 1001{ 1002 PMF_IDLE_PRINTF(("Input idle handler called\n")); 1003 pmf_event_inject(NULL, PMFE_DISPLAY_OFF); 1004} 1005 1006static void 1007input_activity_handler(device_t dv, devactive_t type) 1008{ 1009 if (!TAILQ_EMPTY(&all_displays)) 1010 callout_schedule(&global_idle_counter, idle_timeout * hz); 1011} 1012 1013static void 1014pmf_class_input_deregister(device_t dv) 1015{ 1016 device_active_deregister(dv, input_activity_handler); 1017} 1018 1019bool 1020pmf_class_input_register(device_t dv) 1021{ 1022 if (!device_active_register(dv, input_activity_handler)) 1023 return false; 1024 1025 device_pmf_class_register(dv, NULL, NULL, NULL, 1026 pmf_class_input_deregister); 1027 1028 return true; 1029} 1030 1031static void 1032pmf_class_display_deregister(device_t dv) 1033{ 1034 struct display_class_softc *sc = device_pmf_class_private(dv); 1035 int s; 1036 1037 s = splsoftclock(); 1038 TAILQ_REMOVE(&all_displays, sc, dc_link); 1039 if (TAILQ_EMPTY(&all_displays)) 1040 callout_stop(&global_idle_counter); 1041 splx(s); 1042 1043 kmem_free(sc, sizeof(*sc)); 1044} 1045 1046bool 1047pmf_class_display_register(device_t dv) 1048{ 1049 struct display_class_softc *sc; 1050 int s; 1051 1052 sc = kmem_alloc(sizeof(*sc), KM_SLEEP); 1053 1054 s = splsoftclock(); 1055 if (TAILQ_EMPTY(&all_displays)) 1056 callout_schedule(&global_idle_counter, idle_timeout * hz); 1057 1058 TAILQ_INSERT_HEAD(&all_displays, sc, dc_link); 1059 splx(s); 1060 1061 device_pmf_class_register(dv, sc, NULL, NULL, 1062 pmf_class_display_deregister); 1063 1064 return true; 1065} 1066 1067static void 1068pmf_event_workitem_put(pmf_event_workitem_t *pew) 1069{ 1070 1071 KASSERT(pew != NULL); 1072 pool_put(&pew_pl, pew); 1073} 1074 1075static pmf_event_workitem_t * 1076pmf_event_workitem_get(void) 1077{ 1078 1079 return pool_get(&pew_pl, PR_NOWAIT); 1080} 1081 1082void 1083pmf_init(void) 1084{ 1085 int err; 1086 1087 pool_init(&pew_pl, sizeof(pmf_event_workitem_t), 0, 0, 0, 1088 "pewpl", NULL, IPL_HIGH); 1089 pool_setlowat(&pew_pl, 1); 1090 pool_sethiwat(&pew_pl, 8); 1091 1092 KASSERT(pmf_event_workqueue == NULL); 1093 err = workqueue_create(&pmf_event_workqueue, "pmfevent", 1094 pmf_event_worker, NULL, PRI_NONE, IPL_VM, 0); 1095 if (err) 1096 panic("couldn't create pmfevent workqueue"); 1097 1098 KASSERT(pmf_suspend_workqueue == NULL); 1099 err = workqueue_create(&pmf_suspend_workqueue, "pmfsuspend", 1100 pmf_suspend_worker, NULL, PRI_NONE, IPL_VM, 0); 1101 if (err) 1102 panic("couldn't create pmfsuspend workqueue"); 1103 1104 1105 callout_init(&global_idle_counter, 0); 1106 callout_setfunc(&global_idle_counter, input_idle, NULL); 1107} 1108