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