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