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