kern_pmf.c revision 1.46
1/* $NetBSD: kern_pmf.c,v 1.46 2021/06/30 21:52:16 blymn 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.46 2021/06/30 21:52:16 blymn 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 61int pmf_debug_event; 62int pmf_debug_suspend; 63int pmf_debug_suspensor; 64int pmf_debug_idle; 65int 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 82static prop_dictionary_t pmf_platform = NULL; 83static struct workqueue *pmf_event_workqueue; 84static struct workqueue *pmf_suspend_workqueue; 85 86typedef 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 94static TAILQ_HEAD(, pmf_event_handler) pmf_all_events = 95 TAILQ_HEAD_INITIALIZER(pmf_all_events); 96 97typedef 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 103typedef 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 109static struct pool pew_pl; 110 111static pmf_event_workitem_t *pmf_event_workitem_get(void); 112static void pmf_event_workitem_put(pmf_event_workitem_t *); 113 114bool pmf_device_resume_locked(device_t, const pmf_qual_t *); 115bool pmf_device_suspend_locked(device_t, const pmf_qual_t *); 116static bool device_pmf_any_suspensor(device_t, devact_level_t); 117 118static bool 119complete_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 141static void 142pmf_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 182static void 183pmf_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 202static bool 203pmf_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 227bool 228pmf_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 258bool 259pmf_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 299bool 300pmf_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 (vfs_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 347static bool 348shutdown_all(int how) 349{ 350 static struct shutdown_state s; 351 device_t curdev; 352 bool progress = false; 353 354 KERNEL_LOCK(1, NULL); 355 for (curdev = shutdown_first(&s); curdev != NULL; 356 curdev = shutdown_next(&s)) { 357 aprint_debug(" shutting down %s, ", device_xname(curdev)); 358 if (!device_pmf_is_registered(curdev)) 359 aprint_debug("skipped."); 360#if 0 /* needed? */ 361 else if (!device_pmf_class_shutdown(curdev, how)) 362 aprint_debug("failed."); 363#endif 364 else if (!device_pmf_driver_shutdown(curdev, how)) 365 aprint_debug("failed."); 366 else if (!device_pmf_bus_shutdown(curdev, how)) 367 aprint_debug("failed."); 368 else { 369 progress = true; 370 aprint_debug("success."); 371 } 372 } 373 KERNEL_UNLOCK_ONE(NULL); 374 return progress; 375} 376 377void 378pmf_system_shutdown(int how) 379{ 380 381 if (panicstr != NULL) 382 return; 383 384 aprint_debug("Shutting down devices:"); 385 shutdown_all(how); 386} 387 388bool 389pmf_set_platform(const char *key, const char *value) 390{ 391 if (pmf_platform == NULL) 392 pmf_platform = prop_dictionary_create(); 393 if (pmf_platform == NULL) 394 return false; 395 396 return prop_dictionary_set_string(pmf_platform, key, value); 397} 398 399const char * 400pmf_get_platform(const char *key) 401{ 402 const char *value; 403 404 if (pmf_platform == NULL) 405 return NULL; 406 407 if (!prop_dictionary_get_string(pmf_platform, key, &value)) 408 return NULL; 409 410 return value; 411} 412 413bool 414pmf_device_register1(device_t dev, 415 bool (*suspend)(device_t, const pmf_qual_t *), 416 bool (*resume)(device_t, const pmf_qual_t *), 417 bool (*shutdown)(device_t, int)) 418{ 419 if (!device_pmf_driver_register(dev, suspend, resume, shutdown)) 420 return false; 421 422 if (!device_pmf_driver_child_register(dev)) { 423 device_pmf_driver_deregister(dev); 424 return false; 425 } 426 427 return true; 428} 429 430void 431pmf_device_deregister(device_t dev) 432{ 433 device_pmf_class_deregister(dev); 434 device_pmf_bus_deregister(dev); 435 device_pmf_driver_deregister(dev); 436} 437 438static const device_suspensor_t _device_suspensor_drvctl = { 439 .ds_delegator = NULL 440 , .ds_name = "drvctl" 441}; 442 443static const device_suspensor_t _device_suspensor_self = { 444 .ds_delegator = NULL 445 , .ds_name = "self" 446}; 447 448#if 0 449static const device_suspensor_t _device_suspensor_self_delegate = { 450 .ds_delegator = &_device_suspensor_self 451 , .ds_name = "self delegate" 452}; 453#endif 454 455static const device_suspensor_t _device_suspensor_system = { 456 .ds_delegator = NULL 457 , .ds_name = "system" 458}; 459 460const device_suspensor_t 461 * const device_suspensor_self = &_device_suspensor_self, 462#if 0 463 * const device_suspensor_self_delegate = &_device_suspensor_self_delegate, 464#endif 465 * const device_suspensor_system = &_device_suspensor_system, 466 * const device_suspensor_drvctl = &_device_suspensor_drvctl; 467 468static const pmf_qual_t _pmf_qual_system = { 469 .pq_actlvl = DEVACT_LEVEL_FULL 470 , .pq_suspensor = &_device_suspensor_system 471}; 472 473static const pmf_qual_t _pmf_qual_drvctl = { 474 .pq_actlvl = DEVACT_LEVEL_FULL 475 , .pq_suspensor = &_device_suspensor_drvctl 476}; 477 478static const pmf_qual_t _pmf_qual_self = { 479 .pq_actlvl = DEVACT_LEVEL_DRIVER 480 , .pq_suspensor = &_device_suspensor_self 481}; 482 483const pmf_qual_t 484 * const PMF_Q_DRVCTL = &_pmf_qual_drvctl, 485 * const PMF_Q_NONE = &_pmf_qual_system, 486 * const PMF_Q_SELF = &_pmf_qual_self; 487 488static bool 489device_suspensor_delegates_to(const device_suspensor_t *ds, 490 const device_suspensor_t *delegate) 491{ 492 const device_suspensor_t *iter; 493 494 for (iter = delegate->ds_delegator; iter != NULL; 495 iter = iter->ds_delegator) { 496 if (ds == iter) 497 return true; 498 } 499 return false; 500} 501 502static bool 503add_suspensor(device_t dev, const char *kind, const device_suspensor_t **susp, 504 const device_suspensor_t *ds) 505{ 506 int i; 507 508 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 509 if (susp[i] == NULL) 510 continue; 511 if (ds == susp[i]) { 512 PMF_SUSPENSOR_PRINTF(( 513 "%s: %s-suspended by %s (delegator %s) already\n", 514 device_xname(dev), kind, 515 susp[i]->ds_name, 516 (susp[i]->ds_delegator != NULL) ? 517 susp[i]->ds_delegator->ds_name : "<none>")); 518 return true; 519 } 520 if (device_suspensor_delegates_to(ds, susp[i])) { 521 PMF_SUSPENSOR_PRINTF(( 522 "%s: %s assumes %s-suspension by %s " 523 "(delegator %s)\n", 524 device_xname(dev), ds->ds_name, kind, 525 susp[i]->ds_name, 526 (susp[i]->ds_delegator != NULL) ? 527 susp[i]->ds_delegator->ds_name : "<none>")); 528 susp[i] = ds; 529 return true; 530 } 531 } 532 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 533 if (susp[i] == NULL) { 534 susp[i] = ds; 535 PMF_SUSPENSOR_PRINTF(( 536 "%s: newly %s-suspended by %s (delegator %s)\n", 537 device_xname(dev), kind, 538 susp[i]->ds_name, 539 (susp[i]->ds_delegator != NULL) ? 540 susp[i]->ds_delegator->ds_name : "<none>")); 541 return true; 542 } 543 } 544 return false; 545} 546 547static bool 548device_pmf_add_suspensor(device_t dev, const pmf_qual_t *pq) 549{ 550 const device_suspensor_t *ds; 551 552 KASSERT(pq != NULL); 553 554 ds = pmf_qual_suspension(pq); 555 556 KASSERT(ds != NULL); 557 558 if (!add_suspensor(dev, "class", dev->dv_class_suspensors, ds)) 559 return false; 560 if (!add_suspensor(dev, "driver", dev->dv_driver_suspensors, ds)) 561 return false; 562 if (!add_suspensor(dev, "bus", dev->dv_bus_suspensors, ds)) 563 return false; 564 return true; 565} 566 567#if 0 568static bool 569device_pmf_has_suspension(device_t dev, const device_suspensor_t *ds) 570{ 571 int i; 572 573 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 574 if (dev->dv_suspensions[i] == ds) 575 return true; 576 if (device_suspensor_delegates_to(dev->dv_suspensions[i], ds)) 577 return true; 578 } 579 return false; 580} 581#endif 582 583static bool 584any_suspensor(device_t dev, const char *kind, const device_suspensor_t **susp) 585{ 586 int i; 587 bool suspended = false; 588 589 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 590 if (susp[i] != NULL) { 591 PMF_SUSPENSOR_PRINTF(("%s: %s is suspended by %s " 592 "(delegator %s)\n", 593 device_xname(dev), kind, 594 susp[i]->ds_name, 595 (susp[i]->ds_delegator != NULL) ? 596 susp[i]->ds_delegator->ds_name : "<none>")); 597 suspended = true; 598 } 599 } 600 return suspended; 601} 602 603static bool 604device_pmf_any_suspensor(device_t dev, devact_level_t depth) 605{ 606 switch (depth) { 607 case DEVACT_LEVEL_FULL: 608 if (any_suspensor(dev, "class", dev->dv_class_suspensors)) 609 return true; 610 /*FALLTHROUGH*/ 611 case DEVACT_LEVEL_DRIVER: 612 if (any_suspensor(dev, "driver", dev->dv_driver_suspensors)) 613 return true; 614 /*FALLTHROUGH*/ 615 case DEVACT_LEVEL_BUS: 616 if (any_suspensor(dev, "bus", dev->dv_bus_suspensors)) 617 return true; 618 } 619 return false; 620} 621 622static bool 623remove_suspensor(device_t dev, const char *kind, 624 const device_suspensor_t **susp, const device_suspensor_t *ds) 625{ 626 int i; 627 628 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 629 if (susp[i] == NULL) 630 continue; 631 if (ds == susp[i] || 632 device_suspensor_delegates_to(ds, susp[i])) { 633 PMF_SUSPENSOR_PRINTF(("%s: %s suspension %s " 634 "(delegator %s) removed by %s\n", 635 device_xname(dev), kind, 636 susp[i]->ds_name, 637 (susp[i]->ds_delegator != NULL) 638 ? susp[i]->ds_delegator->ds_name 639 : "<none>", 640 ds->ds_name)); 641 susp[i] = NULL; 642 return true; 643 } 644 } 645 return false; 646} 647 648static bool 649device_pmf_remove_suspensor(device_t dev, const pmf_qual_t *pq) 650{ 651 const device_suspensor_t *ds; 652 653 KASSERT(pq != NULL); 654 655 ds = pmf_qual_suspension(pq); 656 657 KASSERT(ds != NULL); 658 659 if (!remove_suspensor(dev, "class", dev->dv_class_suspensors, ds)) 660 return false; 661 if (!remove_suspensor(dev, "driver", dev->dv_driver_suspensors, ds)) 662 return false; 663 if (!remove_suspensor(dev, "bus", dev->dv_bus_suspensors, ds)) 664 return false; 665 666 return true; 667} 668 669void 670pmf_self_suspensor_init(device_t dev, device_suspensor_t *ds, 671 pmf_qual_t *pq) 672{ 673 ds->ds_delegator = device_suspensor_self; 674 snprintf(ds->ds_name, sizeof(ds->ds_name), "%s-self", 675 device_xname(dev)); 676 pq->pq_actlvl = DEVACT_LEVEL_DRIVER; 677 pq->pq_suspensor = ds; 678} 679 680bool 681pmf_device_suspend(device_t dev, const pmf_qual_t *qual) 682{ 683 bool rc; 684 685 PMF_TRANSITION_PRINTF(("%s: suspend enter\n", device_xname(dev))); 686 if (!device_pmf_is_registered(dev)) 687 return false; 688 689 if (!device_pmf_lock(dev)) 690 return false; 691 692 rc = pmf_device_suspend_locked(dev, qual); 693 694 device_pmf_unlock(dev); 695 696 PMF_TRANSITION_PRINTF(("%s: suspend exit\n", device_xname(dev))); 697 return rc; 698} 699 700bool 701pmf_device_suspend_locked(device_t dev, const pmf_qual_t *qual) 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 device_pmf_remove_suspensor(dev, qual); 745 746 if (device_pmf_any_suspensor(dev, DEVACT_LEVEL_FULL)) 747 return true; 748 749 PMF_TRANSITION_PRINTF2(1, ("%s: bus resume\n", device_xname(dev))); 750 if (!device_pmf_bus_resume(dev, qual)) 751 return false; 752 753 PMF_TRANSITION_PRINTF2(1, ("%s: driver resume\n", device_xname(dev))); 754 if (!device_pmf_driver_resume(dev, qual)) 755 return false; 756 757 PMF_TRANSITION_PRINTF2(1, ("%s: class resume\n", device_xname(dev))); 758 if (!device_pmf_class_resume(dev, qual)) 759 return false; 760 761 return true; 762} 763 764bool 765pmf_device_recursive_suspend(device_t dv, const pmf_qual_t *qual) 766{ 767 bool rv = true; 768 device_t curdev; 769 deviter_t di; 770 pmf_qual_t pq; 771 772 pmf_qual_recursive_copy(&pq, qual); 773 774 for (curdev = deviter_first(&di, 0); curdev != NULL; 775 curdev = deviter_next(&di)) { 776 if (device_parent(curdev) != dv) 777 continue; 778 if (!pmf_device_recursive_suspend(curdev, &pq)) { 779 rv = false; 780 break; 781 } 782 } 783 deviter_release(&di); 784 785 return rv && pmf_device_suspend(dv, qual); 786} 787 788void 789pmf_qual_recursive_copy(pmf_qual_t *dst, const pmf_qual_t *src) 790{ 791 *dst = *src; 792 dst->pq_actlvl = DEVACT_LEVEL_FULL; 793} 794 795bool 796pmf_device_recursive_resume(device_t dv, const pmf_qual_t *qual) 797{ 798 device_t parent; 799 pmf_qual_t pq; 800 801 if (device_is_active(dv)) 802 return true; 803 804 pmf_qual_recursive_copy(&pq, qual); 805 806 parent = device_parent(dv); 807 if (parent != NULL) { 808 if (!pmf_device_recursive_resume(parent, &pq)) 809 return false; 810 } 811 812 return pmf_device_resume(dv, qual); 813} 814 815bool 816pmf_device_descendants_release(device_t dv, const pmf_qual_t *qual) 817{ 818 bool rv = true; 819 device_t curdev; 820 deviter_t di; 821 822 for (curdev = deviter_first(&di, 0); curdev != NULL; 823 curdev = deviter_next(&di)) { 824 if (device_parent(curdev) != dv) 825 continue; 826 device_pmf_remove_suspensor(curdev, qual); 827 if (!pmf_device_descendants_release(curdev, qual)) { 828 rv = false; 829 break; 830 } 831 } 832 deviter_release(&di); 833 return rv; 834} 835 836bool 837pmf_device_descendants_resume(device_t dv, const pmf_qual_t *qual) 838{ 839 bool rv = true; 840 device_t curdev; 841 deviter_t di; 842 843 KASSERT(pmf_qual_descend_ok(qual)); 844 845 for (curdev = deviter_first(&di, 0); curdev != NULL; 846 curdev = deviter_next(&di)) { 847 if (device_parent(curdev) != dv) 848 continue; 849 if (!pmf_device_resume(curdev, qual) || 850 !pmf_device_descendants_resume(curdev, qual)) { 851 rv = false; 852 break; 853 } 854 } 855 deviter_release(&di); 856 return rv; 857} 858 859bool 860pmf_device_subtree_release(device_t dv, const pmf_qual_t *qual) 861{ 862 pmf_qual_t pq; 863 864 device_pmf_remove_suspensor(dv, qual); 865 866 pmf_qual_recursive_copy(&pq, qual); 867 868 return pmf_device_descendants_release(dv, &pq); 869} 870 871bool 872pmf_device_subtree_resume(device_t dv, const pmf_qual_t *qual) 873{ 874 pmf_qual_t pq; 875 876 if (!pmf_device_subtree_release(dv, qual)) 877 return false; 878 879 if (!pmf_device_recursive_resume(dv, qual)) 880 return false; 881 882 pmf_qual_recursive_copy(&pq, qual); 883 884 return pmf_device_descendants_resume(dv, &pq); 885} 886 887#include <net/if.h> 888 889static bool 890pmf_class_network_suspend(device_t dev, const pmf_qual_t *qual) 891{ 892 struct ifnet *ifp = device_pmf_class_private(dev); 893 int s; 894 895 if (ifp == NULL) 896 return true; 897 898 if ((*ifp->if_stop) == NULL) 899 printf("device %s has no if_stop\n", ifp->if_xname); 900 else { 901 s = splnet(); 902 IFNET_LOCK(ifp); 903 (*ifp->if_stop)(ifp, 0); 904 IFNET_UNLOCK(ifp); 905 splx(s); 906 } 907 908 return true; 909} 910 911static bool 912pmf_class_network_resume(device_t dev, const pmf_qual_t *qual) 913{ 914 struct ifnet *ifp = device_pmf_class_private(dev); 915 int s; 916 bool restart = false; 917 918 s = splnet(); 919 IFNET_LOCK(ifp); 920 if (ifp->if_flags & IFF_UP) { 921 ifp->if_flags &= ~IFF_RUNNING; 922 if ((*ifp->if_init)(ifp) != 0) 923 aprint_normal_ifnet(ifp, "resume failed\n"); 924 restart = true; 925 } 926 IFNET_UNLOCK(ifp); 927 928 if (restart) 929 if_start_lock(ifp); 930 931 splx(s); 932 933 return true; 934} 935 936void 937pmf_class_network_register(device_t dev, struct ifnet *ifp) 938{ 939 device_pmf_class_register(dev, ifp, pmf_class_network_suspend, 940 pmf_class_network_resume, NULL); 941} 942 943bool 944pmf_event_inject(device_t dv, pmf_generic_event_t ev) 945{ 946 pmf_event_workitem_t *pew; 947 948 pew = pmf_event_workitem_get(); 949 if (pew == NULL) { 950 PMF_EVENT_PRINTF(("%s: PMF event %d dropped (no memory)\n", 951 dv ? device_xname(dv) : "<anonymous>", ev)); 952 return false; 953 } 954 955 pew->pew_event = ev; 956 pew->pew_device = dv; 957 958 workqueue_enqueue(pmf_event_workqueue, &pew->pew_work, NULL); 959 PMF_EVENT_PRINTF(("%s: PMF event %d injected\n", 960 dv ? device_xname(dv) : "<anonymous>", ev)); 961 962 return true; 963} 964 965bool 966pmf_event_register(device_t dv, pmf_generic_event_t ev, 967 void (*handler)(device_t), bool global) 968{ 969 pmf_event_handler_t *event; 970 971 event = kmem_alloc(sizeof(*event), KM_SLEEP); 972 event->pmf_event = ev; 973 event->pmf_handler = handler; 974 event->pmf_device = dv; 975 event->pmf_global = global; 976 TAILQ_INSERT_TAIL(&pmf_all_events, event, pmf_link); 977 978 return true; 979} 980 981void 982pmf_event_deregister(device_t dv, pmf_generic_event_t ev, 983 void (*handler)(device_t), bool global) 984{ 985 pmf_event_handler_t *event; 986 987 TAILQ_FOREACH(event, &pmf_all_events, pmf_link) { 988 if (event->pmf_event != ev) 989 continue; 990 if (event->pmf_device != dv) 991 continue; 992 if (event->pmf_global != global) 993 continue; 994 if (event->pmf_handler != handler) 995 continue; 996 TAILQ_REMOVE(&pmf_all_events, event, pmf_link); 997 kmem_free(event, sizeof(*event)); 998 return; 999 } 1000} 1001 1002struct display_class_softc { 1003 TAILQ_ENTRY(display_class_softc) dc_link; 1004 device_t dc_dev; 1005}; 1006 1007static TAILQ_HEAD(, display_class_softc) all_displays; 1008static callout_t global_idle_counter; 1009static int idle_timeout = 30; 1010 1011static void 1012input_idle(void *dummy) 1013{ 1014 PMF_IDLE_PRINTF(("Input idle handler called\n")); 1015 pmf_event_inject(NULL, PMFE_DISPLAY_OFF); 1016} 1017 1018static void 1019input_activity_handler(device_t dv, devactive_t type) 1020{ 1021 if (!TAILQ_EMPTY(&all_displays)) 1022 callout_schedule(&global_idle_counter, idle_timeout * hz); 1023} 1024 1025static void 1026pmf_class_input_deregister(device_t dv) 1027{ 1028 device_active_deregister(dv, input_activity_handler); 1029} 1030 1031bool 1032pmf_class_input_register(device_t dv) 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 1146 1147void 1148pmf_init(void) 1149{ 1150 int err; 1151 1152 pool_init(&pew_pl, sizeof(pmf_event_workitem_t), 0, 0, 0, 1153 "pewpl", NULL, IPL_HIGH); 1154 pool_setlowat(&pew_pl, 1); 1155 pool_sethiwat(&pew_pl, 8); 1156 1157 KASSERT(pmf_event_workqueue == NULL); 1158 err = workqueue_create(&pmf_event_workqueue, "pmfevent", 1159 pmf_event_worker, NULL, PRI_NONE, IPL_VM, 0); 1160 if (err) 1161 panic("couldn't create pmfevent workqueue"); 1162 1163 KASSERT(pmf_suspend_workqueue == NULL); 1164 err = workqueue_create(&pmf_suspend_workqueue, "pmfsuspend", 1165 pmf_suspend_worker, NULL, PRI_NONE, IPL_VM, 0); 1166 if (err) 1167 panic("couldn't create pmfsuspend workqueue"); 1168 1169 1170 callout_init(&global_idle_counter, 0); 1171 callout_setfunc(&global_idle_counter, input_idle, NULL); 1172} 1173