1/* $NetBSD: kern_pmf.c,v 1.51 2022/08/24 11:41:39 riastradh 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.51 2022/08/24 11:41:39 riastradh 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/device_impl.h> 40#include <sys/pmf.h> 41#include <sys/queue.h> 42#include <sys/sched.h> 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#include <sys/sysctl.h> 51#include <sys/vfs_syscalls.h> 52 53/* XXX ugly special case, but for now the only client */ 54#include "wsdisplay.h" 55#if NWSDISPLAY > 0 56#include <dev/wscons/wsdisplayvar.h> 57#endif 58 59#define PMF_DEBUG 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 83static prop_dictionary_t pmf_platform = NULL; 84static struct workqueue *pmf_event_workqueue; 85static struct workqueue *pmf_suspend_workqueue; 86 87typedef struct pmf_event_handler { 88 TAILQ_ENTRY(pmf_event_handler) pmf_link; 89 pmf_generic_event_t pmf_event; 90 void (*pmf_handler)(device_t); 91 device_t pmf_device; 92 bool pmf_global; 93} pmf_event_handler_t; 94 95static TAILQ_HEAD(, pmf_event_handler) pmf_all_events = 96 TAILQ_HEAD_INITIALIZER(pmf_all_events); 97 98typedef struct pmf_event_workitem { 99 struct work pew_work; 100 pmf_generic_event_t pew_event; 101 device_t pew_device; 102} pmf_event_workitem_t; 103 104typedef struct pmf_suspend_workitem { 105 struct work psw_work; 106 device_t psw_dev; 107 pmf_qual_t psw_qual; 108} pmf_suspend_workitem_t; 109 110static struct pool pew_pl; 111 112static pmf_event_workitem_t *pmf_event_workitem_get(void); 113static void pmf_event_workitem_put(pmf_event_workitem_t *); 114 115static bool pmf_device_resume_locked(device_t, const pmf_qual_t *); 116static bool pmf_device_suspend_locked(device_t, const pmf_qual_t *); 117static bool device_pmf_any_suspensor(device_t, devact_level_t); 118 119static bool 120complete_suspension(device_t dev, const device_suspensor_t **susp, 121 const pmf_qual_t *pqp) 122{ 123 int i; 124 pmf_qual_t pq; 125 const device_suspensor_t *ds; 126 127 ds = pmf_qual_suspension(pqp); 128 KASSERT(ds->ds_delegator != NULL); 129 130 pq = *pqp; 131 pq.pq_suspensor = ds->ds_delegator; 132 133 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 134 if (susp[i] != ds) 135 continue; 136 if (!pmf_device_suspend(dev, &pq)) 137 return false; 138 } 139 return true; 140} 141 142static void 143pmf_suspend_worker(struct work *wk, void *dummy) 144{ 145 pmf_suspend_workitem_t *psw; 146 deviter_t di; 147 device_t dev; 148 149 psw = (void *)wk; 150 KASSERT(wk == &psw->psw_work); 151 KASSERT(psw != NULL); 152 153 for (dev = deviter_first(&di, 0); dev != NULL; 154 dev = deviter_next(&di)) { 155 if (dev == psw->psw_dev && device_pmf_lock(dev)) 156 break; 157 } 158 deviter_release(&di); 159 160 if (dev == NULL) 161 return; 162 163 switch (pmf_qual_depth(&psw->psw_qual)) { 164 case DEVACT_LEVEL_FULL: 165 if (!complete_suspension(dev, dev->dv_class_suspensors, 166 &psw->psw_qual)) 167 break; 168 /*FALLTHROUGH*/ 169 case DEVACT_LEVEL_DRIVER: 170 if (!complete_suspension(dev, dev->dv_driver_suspensors, 171 &psw->psw_qual)) 172 break; 173 /*FALLTHROUGH*/ 174 case DEVACT_LEVEL_BUS: 175 if (!complete_suspension(dev, dev->dv_bus_suspensors, 176 &psw->psw_qual)) 177 break; 178 } 179 device_pmf_unlock(dev); 180 kmem_free(psw, sizeof(*psw)); 181} 182 183static void 184pmf_event_worker(struct work *wk, void *dummy) 185{ 186 pmf_event_workitem_t *pew; 187 pmf_event_handler_t *event; 188 189 pew = (void *)wk; 190 KASSERT(wk == &pew->pew_work); 191 KASSERT(pew != NULL); 192 193 TAILQ_FOREACH(event, &pmf_all_events, pmf_link) { 194 if (event->pmf_event != pew->pew_event) 195 continue; 196 if (event->pmf_device == pew->pew_device || event->pmf_global) 197 (*event->pmf_handler)(event->pmf_device); 198 } 199 200 pmf_event_workitem_put(pew); 201} 202 203static bool 204pmf_check_system_drivers(void) 205{ 206 device_t curdev; 207 bool unsupported_devs; 208 deviter_t di; 209 210 unsupported_devs = false; 211 for (curdev = deviter_first(&di, 0); curdev != NULL; 212 curdev = deviter_next(&di)) { 213 if (device_pmf_is_registered(curdev)) 214 continue; 215 if (!unsupported_devs) 216 printf("Devices without power management support:"); 217 printf(" %s", device_xname(curdev)); 218 unsupported_devs = true; 219 } 220 deviter_release(&di); 221 if (unsupported_devs) { 222 printf("\n"); 223 return false; 224 } 225 return true; 226} 227 228bool 229pmf_system_bus_resume(const pmf_qual_t *qual) 230{ 231 bool rv; 232 device_t curdev; 233 deviter_t di; 234 235 aprint_debug("Powering devices:"); 236 /* D0 handlers are run in order */ 237 rv = true; 238 for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); curdev != NULL; 239 curdev = deviter_next(&di)) { 240 if (!device_pmf_is_registered(curdev)) 241 continue; 242 if (device_is_active(curdev) || 243 !device_is_enabled(curdev)) 244 continue; 245 246 aprint_debug(" %s", device_xname(curdev)); 247 248 if (!device_pmf_bus_resume(curdev, qual)) { 249 rv = false; 250 aprint_debug("(failed)"); 251 } 252 } 253 deviter_release(&di); 254 aprint_debug("\n"); 255 256 return rv; 257} 258 259bool 260pmf_system_resume(const pmf_qual_t *qual) 261{ 262 bool rv; 263 device_t curdev, parent; 264 deviter_t di; 265 266 if (!pmf_check_system_drivers()) 267 return false; 268 269 aprint_debug("Resuming devices:"); 270 /* D0 handlers are run in order */ 271 rv = true; 272 for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); curdev != NULL; 273 curdev = deviter_next(&di)) { 274 if (device_is_active(curdev) || 275 !device_is_enabled(curdev)) 276 continue; 277 parent = device_parent(curdev); 278 if (parent != NULL && 279 !device_is_active(parent)) 280 continue; 281 282 aprint_debug(" %s", device_xname(curdev)); 283 284 if (!pmf_device_resume(curdev, qual)) { 285 rv = false; 286 aprint_debug("(failed)"); 287 } 288 } 289 deviter_release(&di); 290 aprint_debug(".\n"); 291 292 KERNEL_UNLOCK_ONE(0); 293#if NWSDISPLAY > 0 294 if (rv) 295 wsdisplay_handlex(1); 296#endif 297 return rv; 298} 299 300bool 301pmf_system_suspend(const pmf_qual_t *qual) 302{ 303 device_t curdev; 304 deviter_t di; 305 306 if (!pmf_check_system_drivers()) 307 return false; 308#if NWSDISPLAY > 0 309 if (wsdisplay_handlex(0)) 310 return false; 311#endif 312 KERNEL_LOCK(1, NULL); 313 314 /* 315 * Flush buffers only if the shutdown didn't do so 316 * already and if there was no panic. 317 */ 318 if (doing_shutdown == 0 && panicstr == NULL) { 319 printf("Flushing disk caches: "); 320 do_sys_sync(&lwp0); 321 if (vfs_syncwait() != 0) 322 printf("giving up\n"); 323 else 324 printf("done\n"); 325 } 326 327 aprint_debug("Suspending devices:"); 328 329 for (curdev = deviter_first(&di, DEVITER_F_LEAVES_FIRST); 330 curdev != NULL; 331 curdev = deviter_next(&di)) { 332 if (!device_is_active(curdev)) 333 continue; 334 335 aprint_debug(" %s", device_xname(curdev)); 336 337 /* XXX joerg check return value and abort suspend */ 338 if (!pmf_device_suspend(curdev, qual)) 339 aprint_debug("(failed)"); 340 } 341 deviter_release(&di); 342 343 aprint_debug(".\n"); 344 345 return true; 346} 347 348static bool 349shutdown_all(int how) 350{ 351 static struct shutdown_state s; 352 device_t curdev; 353 bool progress = false; 354 355 KERNEL_LOCK(1, NULL); 356 for (curdev = shutdown_first(&s); curdev != NULL; 357 curdev = shutdown_next(&s)) { 358 aprint_debug(" shutting down %s, ", device_xname(curdev)); 359 if (!device_pmf_is_registered(curdev)) 360 aprint_debug("skipped."); 361#if 0 /* needed? */ 362 else if (!device_pmf_class_shutdown(curdev, how)) 363 aprint_debug("failed."); 364#endif 365 else if (!device_pmf_driver_shutdown(curdev, how)) 366 aprint_debug("failed."); 367 else if (!device_pmf_bus_shutdown(curdev, how)) 368 aprint_debug("failed."); 369 else { 370 progress = true; 371 aprint_debug("success."); 372 } 373 } 374 KERNEL_UNLOCK_ONE(NULL); 375 return progress; 376} 377 378void 379pmf_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 389bool 390pmf_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_string(pmf_platform, key, value); 398} 399 400const char * 401pmf_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_string(pmf_platform, key, &value)) 409 return NULL; 410 411 return value; 412} 413 414bool 415pmf_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 421 device_pmf_driver_register(dev, suspend, resume, shutdown); 422 device_pmf_driver_child_register(dev); 423 424 return true; 425} 426 427void 428pmf_device_deregister(device_t dev) 429{ 430 431 device_pmf_class_deregister(dev); 432 device_pmf_bus_deregister(dev); 433 device_pmf_driver_deregister(dev); 434} 435 436static const device_suspensor_t _device_suspensor_drvctl = { 437 .ds_delegator = NULL, 438 .ds_name = "drvctl", 439}; 440 441static const device_suspensor_t _device_suspensor_self = { 442 .ds_delegator = NULL, 443 .ds_name = "self", 444}; 445 446#if 0 447static const device_suspensor_t _device_suspensor_self_delegate = { 448 .ds_delegator = &_device_suspensor_self, 449 .ds_name = "self delegate", 450}; 451#endif 452 453static const device_suspensor_t _device_suspensor_system = { 454 .ds_delegator = NULL, 455 .ds_name = "system", 456}; 457 458const 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 466static const pmf_qual_t _pmf_qual_system = { 467 .pq_actlvl = DEVACT_LEVEL_FULL, 468 .pq_suspensor = &_device_suspensor_system, 469}; 470 471static const pmf_qual_t _pmf_qual_drvctl = { 472 .pq_actlvl = DEVACT_LEVEL_FULL, 473 .pq_suspensor = &_device_suspensor_drvctl, 474}; 475 476static const pmf_qual_t _pmf_qual_self = { 477 .pq_actlvl = DEVACT_LEVEL_DRIVER, 478 .pq_suspensor = &_device_suspensor_self, 479}; 480 481const 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 486static bool 487device_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 500static bool 501add_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 545static bool 546device_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 566static bool 567device_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 581static bool 582any_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 601static bool 602device_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 620static bool 621remove_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 646static bool 647device_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 667void 668pmf_self_suspensor_init(device_t dev, device_suspensor_t *ds, 669 pmf_qual_t *pq) 670{ 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 679bool 680pmf_device_suspend(device_t dev, const pmf_qual_t *qual) 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, qual); 692 693 device_pmf_unlock(dev); 694 695 PMF_TRANSITION_PRINTF(("%s: suspend exit\n", device_xname(dev))); 696 return rc; 697} 698 699bool 700pmf_device_suspend_locked(device_t dev, const pmf_qual_t *qual) 701{ 702 703 if (!device_pmf_add_suspensor(dev, qual)) 704 return false; 705 706 PMF_TRANSITION_PRINTF2(1, ("%s: class suspend\n", device_xname(dev))); 707 if (!device_pmf_class_suspend(dev, qual)) 708 return false; 709 710 PMF_TRANSITION_PRINTF2(1, ("%s: driver suspend\n", device_xname(dev))); 711 if (!device_pmf_driver_suspend(dev, qual)) 712 return false; 713 714 PMF_TRANSITION_PRINTF2(1, ("%s: bus suspend\n", device_xname(dev))); 715 if (!device_pmf_bus_suspend(dev, qual)) 716 return false; 717 718 return true; 719} 720 721bool 722pmf_device_resume(device_t dev, const pmf_qual_t *qual) 723{ 724 bool rc; 725 726 PMF_TRANSITION_PRINTF(("%s: resume enter\n", device_xname(dev))); 727 if (!device_pmf_is_registered(dev)) 728 return false; 729 730 if (!device_pmf_lock(dev)) 731 return false; 732 733 rc = pmf_device_resume_locked(dev, qual); 734 735 device_pmf_unlock(dev); 736 737 PMF_TRANSITION_PRINTF(("%s: resume exit\n", device_xname(dev))); 738 return rc; 739} 740 741bool 742pmf_device_resume_locked(device_t dev, const pmf_qual_t *qual) 743{ 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 765bool 766pmf_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 789void 790pmf_qual_recursive_copy(pmf_qual_t *dst, const pmf_qual_t *src) 791{ 792 793 *dst = *src; 794 dst->pq_actlvl = DEVACT_LEVEL_FULL; 795} 796 797bool 798pmf_device_recursive_resume(device_t dv, const pmf_qual_t *qual) 799{ 800 device_t parent; 801 pmf_qual_t pq; 802 803 if (device_is_active(dv)) 804 return true; 805 806 pmf_qual_recursive_copy(&pq, qual); 807 808 parent = device_parent(dv); 809 if (parent != NULL) { 810 if (!pmf_device_recursive_resume(parent, &pq)) 811 return false; 812 } 813 814 return pmf_device_resume(dv, qual); 815} 816 817bool 818pmf_device_descendants_release(device_t dv, const pmf_qual_t *qual) 819{ 820 bool rv = true; 821 device_t curdev; 822 deviter_t di; 823 824 for (curdev = deviter_first(&di, 0); curdev != NULL; 825 curdev = deviter_next(&di)) { 826 if (device_parent(curdev) != dv) 827 continue; 828 device_pmf_remove_suspensor(curdev, qual); 829 if (!pmf_device_descendants_release(curdev, qual)) { 830 rv = false; 831 break; 832 } 833 } 834 deviter_release(&di); 835 return rv; 836} 837 838bool 839pmf_device_descendants_resume(device_t dv, const pmf_qual_t *qual) 840{ 841 bool rv = true; 842 device_t curdev; 843 deviter_t di; 844 845 KASSERT(pmf_qual_descend_ok(qual)); 846 847 for (curdev = deviter_first(&di, 0); curdev != NULL; 848 curdev = deviter_next(&di)) { 849 if (device_parent(curdev) != dv) 850 continue; 851 if (!pmf_device_resume(curdev, qual) || 852 !pmf_device_descendants_resume(curdev, qual)) { 853 rv = false; 854 break; 855 } 856 } 857 deviter_release(&di); 858 return rv; 859} 860 861bool 862pmf_device_subtree_release(device_t dv, const pmf_qual_t *qual) 863{ 864 pmf_qual_t pq; 865 866 device_pmf_remove_suspensor(dv, qual); 867 868 pmf_qual_recursive_copy(&pq, qual); 869 870 return pmf_device_descendants_release(dv, &pq); 871} 872 873bool 874pmf_device_subtree_resume(device_t dv, const pmf_qual_t *qual) 875{ 876 pmf_qual_t pq; 877 878 if (!pmf_device_subtree_release(dv, qual)) 879 return false; 880 881 if (!pmf_device_recursive_resume(dv, qual)) 882 return false; 883 884 pmf_qual_recursive_copy(&pq, qual); 885 886 return pmf_device_descendants_resume(dv, &pq); 887} 888 889#include <net/if.h> 890 891static bool 892pmf_class_network_suspend(device_t dev, const pmf_qual_t *qual) 893{ 894 struct ifnet *ifp = device_pmf_class_private(dev); 895 int s; 896 897 s = splnet(); 898 IFNET_LOCK(ifp); 899 (*ifp->if_stop)(ifp, 0); 900 IFNET_UNLOCK(ifp); 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 bool restart = false; 912 913 s = splnet(); 914 IFNET_LOCK(ifp); 915 if (ifp->if_flags & IFF_UP) { 916 ifp->if_flags &= ~IFF_RUNNING; 917 if ((*ifp->if_init)(ifp) != 0) 918 aprint_normal_ifnet(ifp, "resume failed\n"); 919 restart = true; 920 } 921 IFNET_UNLOCK(ifp); 922 923 if (restart) 924 if_start_lock(ifp); 925 926 splx(s); 927 928 return true; 929} 930 931void 932pmf_class_network_register(device_t dev, struct ifnet *ifp) 933{ 934 935 device_pmf_class_register(dev, ifp, pmf_class_network_suspend, 936 pmf_class_network_resume, NULL); 937} 938 939bool 940pmf_event_inject(device_t dv, pmf_generic_event_t ev) 941{ 942 pmf_event_workitem_t *pew; 943 944 pew = pmf_event_workitem_get(); 945 if (pew == NULL) { 946 PMF_EVENT_PRINTF(("%s: PMF event %d dropped (no memory)\n", 947 dv ? device_xname(dv) : "<anonymous>", ev)); 948 return false; 949 } 950 951 pew->pew_event = ev; 952 pew->pew_device = dv; 953 954 workqueue_enqueue(pmf_event_workqueue, &pew->pew_work, NULL); 955 PMF_EVENT_PRINTF(("%s: PMF event %d injected\n", 956 dv ? device_xname(dv) : "<anonymous>", ev)); 957 958 return true; 959} 960 961bool 962pmf_event_register(device_t dv, pmf_generic_event_t ev, 963 void (*handler)(device_t), bool global) 964{ 965 pmf_event_handler_t *event; 966 967 event = kmem_alloc(sizeof(*event), KM_SLEEP); 968 event->pmf_event = ev; 969 event->pmf_handler = handler; 970 event->pmf_device = dv; 971 event->pmf_global = global; 972 TAILQ_INSERT_TAIL(&pmf_all_events, event, pmf_link); 973 974 return true; 975} 976 977void 978pmf_event_deregister(device_t dv, pmf_generic_event_t ev, 979 void (*handler)(device_t), bool global) 980{ 981 pmf_event_handler_t *event; 982 983 TAILQ_FOREACH(event, &pmf_all_events, pmf_link) { 984 if (event->pmf_event != ev) 985 continue; 986 if (event->pmf_device != dv) 987 continue; 988 if (event->pmf_global != global) 989 continue; 990 if (event->pmf_handler != handler) 991 continue; 992 TAILQ_REMOVE(&pmf_all_events, event, pmf_link); 993 kmem_free(event, sizeof(*event)); 994 return; 995 } 996} 997 998struct display_class_softc { 999 TAILQ_ENTRY(display_class_softc) dc_link; 1000 device_t dc_dev; 1001}; 1002 1003static TAILQ_HEAD(, display_class_softc) all_displays; 1004static callout_t global_idle_counter; 1005static int idle_timeout = 30; 1006 1007static void 1008input_idle(void *dummy) 1009{ 1010 1011 PMF_IDLE_PRINTF(("Input idle handler called\n")); 1012 pmf_event_inject(NULL, PMFE_DISPLAY_OFF); 1013} 1014 1015static void 1016input_activity_handler(device_t dv, devactive_t type) 1017{ 1018 1019 if (!TAILQ_EMPTY(&all_displays)) 1020 callout_schedule(&global_idle_counter, idle_timeout * hz); 1021} 1022 1023static void 1024pmf_class_input_deregister(device_t dv) 1025{ 1026 1027 device_active_deregister(dv, input_activity_handler); 1028} 1029 1030bool 1031pmf_class_input_register(device_t dv) 1032{ 1033 1034 if (!device_active_register(dv, input_activity_handler)) 1035 return false; 1036 1037 device_pmf_class_register(dv, NULL, NULL, NULL, 1038 pmf_class_input_deregister); 1039 1040 return true; 1041} 1042 1043static void 1044pmf_class_display_deregister(device_t dv) 1045{ 1046 struct display_class_softc *sc = device_pmf_class_private(dv); 1047 int s; 1048 1049 s = splsoftclock(); 1050 TAILQ_REMOVE(&all_displays, sc, dc_link); 1051 if (TAILQ_EMPTY(&all_displays)) 1052 callout_stop(&global_idle_counter); 1053 splx(s); 1054 1055 kmem_free(sc, sizeof(*sc)); 1056} 1057 1058bool 1059pmf_class_display_register(device_t dv) 1060{ 1061 struct display_class_softc *sc; 1062 int s; 1063 1064 sc = kmem_alloc(sizeof(*sc), KM_SLEEP); 1065 1066 s = splsoftclock(); 1067 if (TAILQ_EMPTY(&all_displays)) 1068 callout_schedule(&global_idle_counter, idle_timeout * hz); 1069 1070 TAILQ_INSERT_HEAD(&all_displays, sc, dc_link); 1071 splx(s); 1072 1073 device_pmf_class_register(dv, sc, NULL, NULL, 1074 pmf_class_display_deregister); 1075 1076 return true; 1077} 1078 1079static void 1080pmf_event_workitem_put(pmf_event_workitem_t *pew) 1081{ 1082 1083 KASSERT(pew != NULL); 1084 pool_put(&pew_pl, pew); 1085} 1086 1087static pmf_event_workitem_t * 1088pmf_event_workitem_get(void) 1089{ 1090 1091 return pool_get(&pew_pl, PR_NOWAIT); 1092} 1093 1094SYSCTL_SETUP(sysctl_pmf_setup, "PMF subtree setup") 1095{ 1096 const struct sysctlnode *node = NULL; 1097 1098 sysctl_createv(clog, 0, NULL, &node, 1099 CTLFLAG_PERMANENT, 1100 CTLTYPE_NODE, "pmf", 1101 SYSCTL_DESCR("pmf controls"), 1102 NULL, 0, NULL, 0, 1103 CTL_KERN, CTL_CREATE, CTL_EOL); 1104 1105#ifdef PMF_DEBUG 1106 sysctl_createv(clog, 0, &node, &node, 1107 CTLFLAG_PERMANENT, 1108 CTLTYPE_NODE, "debug", 1109 SYSCTL_DESCR("debug levels"), 1110 NULL, 0, NULL, 0, 1111 CTL_CREATE, CTL_EOL); 1112 1113 sysctl_createv(clog, 0, &node, NULL, 1114 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 1115 CTLTYPE_INT, "event", 1116 SYSCTL_DESCR("event"), 1117 NULL, 0, &pmf_debug_event, sizeof(pmf_debug_event), 1118 CTL_CREATE, CTL_EOL); 1119 sysctl_createv(clog, 0, &node, NULL, 1120 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 1121 CTLTYPE_INT, "suspend", 1122 SYSCTL_DESCR("suspend"), 1123 NULL, 0, &pmf_debug_suspend, sizeof(pmf_debug_suspend), 1124 CTL_CREATE, CTL_EOL); 1125 sysctl_createv(clog, 0, &node, NULL, 1126 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 1127 CTLTYPE_INT, "suspensor", 1128 SYSCTL_DESCR("suspensor"), 1129 NULL, 0, &pmf_debug_suspensor, sizeof(pmf_debug_suspensor), 1130 CTL_CREATE, CTL_EOL); 1131 sysctl_createv(clog, 0, &node, NULL, 1132 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 1133 CTLTYPE_INT, "idle", 1134 SYSCTL_DESCR("idle"), 1135 NULL, 0, &pmf_debug_idle, sizeof(pmf_debug_idle), 1136 CTL_CREATE, CTL_EOL); 1137 sysctl_createv(clog, 0, &node, NULL, 1138 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 1139 CTLTYPE_INT, "transition", 1140 SYSCTL_DESCR("event"), 1141 NULL, 0, &pmf_debug_transition, sizeof(pmf_debug_transition), 1142 CTL_CREATE, CTL_EOL); 1143#endif 1144} 1145 1146void 1147pmf_init(void) 1148{ 1149 int err; 1150 1151 pool_init(&pew_pl, sizeof(pmf_event_workitem_t), 0, 0, 0, 1152 "pewpl", NULL, IPL_HIGH); 1153 pool_setlowat(&pew_pl, 1); 1154 pool_sethiwat(&pew_pl, 8); 1155 1156 KASSERT(pmf_event_workqueue == NULL); 1157 err = workqueue_create(&pmf_event_workqueue, "pmfevent", 1158 pmf_event_worker, NULL, PRI_NONE, IPL_VM, 0); 1159 if (err) 1160 panic("couldn't create pmfevent workqueue"); 1161 1162 KASSERT(pmf_suspend_workqueue == NULL); 1163 err = workqueue_create(&pmf_suspend_workqueue, "pmfsuspend", 1164 pmf_suspend_worker, NULL, PRI_NONE, IPL_VM, 0); 1165 if (err) 1166 panic("couldn't create pmfsuspend workqueue"); 1167 1168 callout_init(&global_idle_counter, 0); 1169 callout_setfunc(&global_idle_counter, input_idle, NULL); 1170} 1171