kern_pmf.c revision 1.31
1/* $NetBSD: kern_pmf.c,v 1.31 2010/01/08 20:07:14 dyoung Exp $ */ 2 3/*- 4 * Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.31 2010/01/08 20:07:14 dyoung Exp $"); 31 32#include <sys/types.h> 33#include <sys/param.h> 34#include <sys/kmem.h> 35#include <sys/buf.h> 36#include <sys/callout.h> 37#include <sys/kernel.h> 38#include <sys/device.h> 39#include <sys/pmf.h> 40#include <sys/queue.h> 41#include <sys/sched.h> 42#include <sys/syscallargs.h> /* for sys_sync */ 43#include <sys/workqueue.h> 44#include <prop/proplib.h> 45#include <sys/condvar.h> 46#include <sys/mutex.h> 47#include <sys/proc.h> 48#include <sys/reboot.h> /* for RB_NOSYNC */ 49#include <sys/sched.h> 50 51/* XXX ugly special case, but for now the only client */ 52#include "wsdisplay.h" 53#if NWSDISPLAY > 0 54#include <dev/wscons/wsdisplayvar.h> 55#endif 56 57#ifndef PMF_DEBUG 58#define PMF_DEBUG 59#endif 60 61#ifdef PMF_DEBUG 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 83/* #define PMF_DEBUG */ 84 85MALLOC_DEFINE(M_PMF, "pmf", "device pmf messaging memory"); 86 87static prop_dictionary_t pmf_platform = NULL; 88static struct workqueue *pmf_event_workqueue; 89static struct workqueue *pmf_suspend_workqueue; 90 91typedef struct pmf_event_handler { 92 TAILQ_ENTRY(pmf_event_handler) pmf_link; 93 pmf_generic_event_t pmf_event; 94 void (*pmf_handler)(device_t); 95 device_t pmf_device; 96 bool pmf_global; 97} pmf_event_handler_t; 98 99static TAILQ_HEAD(, pmf_event_handler) pmf_all_events = 100 TAILQ_HEAD_INITIALIZER(pmf_all_events); 101 102typedef struct pmf_event_workitem { 103 struct work pew_work; 104 pmf_generic_event_t pew_event; 105 device_t pew_device; 106} pmf_event_workitem_t; 107 108typedef struct pmf_suspend_workitem { 109 struct work psw_work; 110 device_t psw_dev; 111 struct pmf_qual psw_qual; 112} pmf_suspend_workitem_t; 113 114static struct pool pew_pl; 115 116static pmf_event_workitem_t *pmf_event_workitem_get(void); 117static void pmf_event_workitem_put(pmf_event_workitem_t *); 118 119bool pmf_device_resume_locked(device_t, pmf_qual_t); 120bool pmf_device_suspend_locked(device_t, pmf_qual_t); 121static bool device_pmf_any_suspensor(device_t, devact_level_t); 122 123static bool 124complete_suspension(device_t dev, device_suspensor_t *susp, pmf_qual_t pqp) 125{ 126 int i; 127 struct pmf_qual pq; 128 device_suspensor_t ds; 129 130 ds = pmf_qual_suspension(pqp); 131 KASSERT(ds->ds_delegator != NULL); 132 133 pq = *pqp; 134 pq.pq_suspensor = ds->ds_delegator; 135 136 for (i = 0; i < DEVICE_SUSPENSORS_MAX; i++) { 137 if (susp[i] != ds) 138 continue; 139 if (!pmf_device_suspend(dev, &pq)) 140 return false; 141 } 142 return true; 143} 144 145static void 146pmf_suspend_worker(struct work *wk, void *dummy) 147{ 148 pmf_suspend_workitem_t *psw; 149 deviter_t di; 150 device_t dev; 151 152 psw = (void *)wk; 153 KASSERT(wk == &psw->psw_work); 154 KASSERT(psw != NULL); 155 156 for (dev = deviter_first(&di, 0); dev != NULL; 157 dev = deviter_next(&di)) { 158 if (dev == psw->psw_dev && device_pmf_lock(dev)) 159 break; 160 } 161 deviter_release(&di); 162 163 if (dev == NULL) 164 return; 165 166 switch (pmf_qual_depth(&psw->psw_qual)) { 167 case DEVACT_LEVEL_FULL: 168 if (!complete_suspension(dev, dev->dv_class_suspensors, 169 &psw->psw_qual)) 170 break; 171 /*FALLTHROUGH*/ 172 case DEVACT_LEVEL_DRIVER: 173 if (!complete_suspension(dev, dev->dv_driver_suspensors, 174 &psw->psw_qual)) 175 break; 176 /*FALLTHROUGH*/ 177 case DEVACT_LEVEL_BUS: 178 if (!complete_suspension(dev, dev->dv_bus_suspensors, 179 &psw->psw_qual)) 180 break; 181 } 182 device_pmf_unlock(dev); 183 kmem_free(psw, sizeof(*psw)); 184} 185 186static void 187pmf_event_worker(struct work *wk, void *dummy) 188{ 189 pmf_event_workitem_t *pew; 190 pmf_event_handler_t *event; 191 192 pew = (void *)wk; 193 KASSERT(wk == &pew->pew_work); 194 KASSERT(pew != NULL); 195 196 TAILQ_FOREACH(event, &pmf_all_events, pmf_link) { 197 if (event->pmf_event != pew->pew_event) 198 continue; 199 if (event->pmf_device == pew->pew_device || event->pmf_global) 200 (*event->pmf_handler)(event->pmf_device); 201 } 202 203 pmf_event_workitem_put(pew); 204} 205 206static bool 207pmf_check_system_drivers(void) 208{ 209 device_t curdev; 210 bool unsupported_devs; 211 deviter_t di; 212 213 unsupported_devs = false; 214 for (curdev = deviter_first(&di, 0); curdev != NULL; 215 curdev = deviter_next(&di)) { 216 if (device_pmf_is_registered(curdev)) 217 continue; 218 if (!unsupported_devs) 219 printf("Devices without power management support:"); 220 printf(" %s", device_xname(curdev)); 221 unsupported_devs = true; 222 } 223 deviter_release(&di); 224 if (unsupported_devs) { 225 printf("\n"); 226 return false; 227 } 228 return true; 229} 230 231bool 232pmf_system_bus_resume(pmf_qual_t qual) 233{ 234 bool rv; 235 device_t curdev; 236 deviter_t di; 237 238 aprint_debug("Powering devices:"); 239 /* D0 handlers are run in order */ 240 rv = true; 241 for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); curdev != NULL; 242 curdev = deviter_next(&di)) { 243 if (!device_pmf_is_registered(curdev)) 244 continue; 245 if (device_is_active(curdev) || 246 !device_is_enabled(curdev)) 247 continue; 248 249 aprint_debug(" %s", device_xname(curdev)); 250 251 if (!device_pmf_bus_resume(curdev, qual)) { 252 rv = false; 253 aprint_debug("(failed)"); 254 } 255 } 256 deviter_release(&di); 257 aprint_debug("\n"); 258 259 return rv; 260} 261 262bool 263pmf_system_resume(pmf_qual_t qual) 264{ 265 bool rv; 266 device_t curdev, parent; 267 deviter_t di; 268 269 if (!pmf_check_system_drivers()) 270 return false; 271 272 aprint_debug("Resuming devices:"); 273 /* D0 handlers are run in order */ 274 rv = true; 275 for (curdev = deviter_first(&di, DEVITER_F_ROOT_FIRST); curdev != NULL; 276 curdev = deviter_next(&di)) { 277 if (device_is_active(curdev) || 278 !device_is_enabled(curdev)) 279 continue; 280 parent = device_parent(curdev); 281 if (parent != NULL && 282 !device_is_active(parent)) 283 continue; 284 285 aprint_debug(" %s", device_xname(curdev)); 286 287 if (!pmf_device_resume(curdev, qual)) { 288 rv = false; 289 aprint_debug("(failed)"); 290 } 291 } 292 deviter_release(&di); 293 aprint_debug(".\n"); 294 295 KERNEL_UNLOCK_ONE(0); 296#if NWSDISPLAY > 0 297 if (rv) 298 wsdisplay_handlex(1); 299#endif 300 return rv; 301} 302 303bool 304pmf_system_suspend(pmf_qual_t qual) 305{ 306 device_t curdev; 307 deviter_t di; 308 309 if (!pmf_check_system_drivers()) 310 return false; 311#if NWSDISPLAY > 0 312 if (wsdisplay_handlex(0)) 313 return false; 314#endif 315 KERNEL_LOCK(1, NULL); 316 317 /* 318 * Flush buffers only if the shutdown didn't do so 319 * already and if there was no panic. 320 */ 321 if (doing_shutdown == 0 && panicstr == NULL) { 322 printf("Flushing disk caches: "); 323 sys_sync(NULL, NULL, NULL); 324 if (buf_syncwait() != 0) 325 printf("giving up\n"); 326 else 327 printf("done\n"); 328 } 329 330 aprint_debug("Suspending devices:"); 331 332 for (curdev = deviter_first(&di, DEVITER_F_LEAVES_FIRST); 333 curdev != NULL; 334 curdev = deviter_next(&di)) { 335 if (!device_is_active(curdev)) 336 continue; 337 338 aprint_debug(" %s", device_xname(curdev)); 339 340 /* XXX joerg check return value and abort suspend */ 341 if (!pmf_device_suspend(curdev, qual)) 342 aprint_debug("(failed)"); 343 } 344 deviter_release(&di); 345 346 aprint_debug(".\n"); 347 348 return true; 349} 350 351static bool 352shutdown_all(int how) 353{ 354 static struct shutdown_state s; 355 device_t curdev; 356 bool progress = false; 357 358 for (curdev = shutdown_first(&s); curdev != NULL; 359 curdev = shutdown_next(&s)) { 360 aprint_debug(" shutting down %s, ", device_xname(curdev)); 361 if (!device_pmf_is_registered(curdev)) 362 aprint_debug("skipped."); 363#if 0 /* needed? */ 364 else if (!device_pmf_class_shutdown(curdev, how)) 365 aprint_debug("failed."); 366#endif 367 else if (!device_pmf_driver_shutdown(curdev, how)) 368 aprint_debug("failed."); 369 else if (!device_pmf_bus_shutdown(curdev, how)) 370 aprint_debug("failed."); 371 else { 372 progress = true; 373 aprint_debug("success."); 374 } 375 } 376 return progress; 377} 378 379void 380pmf_system_shutdown(int how) 381{ 382 aprint_debug("Shutting down devices:"); 383 shutdown_all(how); 384} 385 386bool 387pmf_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 397const char * 398pmf_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 411bool 412pmf_device_register1(device_t dev, 413 bool (*suspend)(device_t, pmf_qual_t), 414 bool (*resume)(device_t, 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 428void 429pmf_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 436static const struct device_suspensor _device_suspensor_drvctl = { 437 .ds_delegator = NULL 438 , .ds_name = "drvctl" 439}; 440 441static const struct device_suspensor _device_suspensor_self = { 442 .ds_delegator = NULL 443 , .ds_name = "self" 444}; 445 446#if 0 447static const struct device_suspensor _device_suspensor_self_delegate = { 448 .ds_delegator = &_device_suspensor_self 449 , .ds_name = "self delegate" 450}; 451#endif 452 453static const struct device_suspensor _device_suspensor_system = { 454 .ds_delegator = NULL 455 , .ds_name = "system" 456}; 457 458const struct device_suspensor 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 struct pmf_qual _pmf_qual_system = { 467 .pq_actlvl = DEVACT_LEVEL_FULL 468 , .pq_suspensor = &_device_suspensor_system 469}; 470 471static const struct pmf_qual _pmf_qual_drvctl = { 472 .pq_actlvl = DEVACT_LEVEL_FULL 473 , .pq_suspensor = &_device_suspensor_drvctl 474}; 475 476static const struct pmf_qual _pmf_qual_self = { 477 .pq_actlvl = DEVACT_LEVEL_DRIVER 478 , .pq_suspensor = &_device_suspensor_self 479}; 480 481const struct pmf_qual 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(device_suspensor_t ds, 488 device_suspensor_t delegate) 489{ 490 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, device_suspensor_t *susp, 502 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, pmf_qual_t pq) 547{ 548 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, 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, 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, device_suspensor_t *susp, 622 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, pmf_qual_t pq) 648{ 649 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, struct device_suspensor *ds, 669 struct pmf_qual *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 678bool 679pmf_device_suspend(device_t dev, 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 698bool 699pmf_device_suspend_locked(device_t dev, 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 719bool 720pmf_device_resume(device_t dev, 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 739bool 740pmf_device_resume_locked(device_t dev, 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 762bool 763pmf_device_recursive_suspend(device_t dv, pmf_qual_t qual) 764{ 765 bool rv = true; 766 device_t curdev; 767 deviter_t di; 768 struct pmf_qual 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 786void 787pmf_qual_recursive_copy(struct pmf_qual *dst, pmf_qual_t src) 788{ 789 *dst = *src; 790 dst->pq_actlvl = DEVACT_LEVEL_FULL; 791} 792 793bool 794pmf_device_recursive_resume(device_t dv, pmf_qual_t qual) 795{ 796 device_t parent; 797 struct pmf_qual 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 813bool 814pmf_device_descendants_release(device_t dv, 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 834bool 835pmf_device_descendants_resume(device_t dv, 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 857bool 858pmf_device_subtree_release(device_t dv, pmf_qual_t qual) 859{ 860 struct pmf_qual pq; 861 862 device_pmf_remove_suspensor(dv, qual); 863 864 return pmf_device_descendants_release(dv, &pq); 865} 866 867bool 868pmf_device_subtree_resume(device_t dv, pmf_qual_t qual) 869{ 870 struct pmf_qual pq; 871 872 if (!pmf_device_subtree_release(dv, qual)) 873 return false; 874 875 if (!pmf_device_recursive_resume(dv, qual)) 876 return false; 877 878 pmf_qual_recursive_copy(&pq, qual); 879 880 return pmf_device_descendants_resume(dv, &pq); 881} 882 883#include <net/if.h> 884 885static bool 886pmf_class_network_suspend(device_t dev, pmf_qual_t qual) 887{ 888 struct ifnet *ifp = device_pmf_class_private(dev); 889 int s; 890 891 s = splnet(); 892 (*ifp->if_stop)(ifp, 0); 893 splx(s); 894 895 return true; 896} 897 898static bool 899pmf_class_network_resume(device_t dev, pmf_qual_t qual) 900{ 901 struct ifnet *ifp = device_pmf_class_private(dev); 902 int s; 903 904 s = splnet(); 905 if (ifp->if_flags & IFF_UP) { 906 ifp->if_flags &= ~IFF_RUNNING; 907 if ((*ifp->if_init)(ifp) != 0) 908 aprint_normal_ifnet(ifp, "resume failed\n"); 909 (*ifp->if_start)(ifp); 910 } 911 splx(s); 912 913 return true; 914} 915 916void 917pmf_class_network_register(device_t dev, struct ifnet *ifp) 918{ 919 device_pmf_class_register(dev, ifp, pmf_class_network_suspend, 920 pmf_class_network_resume, NULL); 921} 922 923bool 924pmf_event_inject(device_t dv, pmf_generic_event_t ev) 925{ 926 pmf_event_workitem_t *pew; 927 928 pew = pmf_event_workitem_get(); 929 if (pew == NULL) { 930 PMF_EVENT_PRINTF(("%s: PMF event %d dropped (no memory)\n", 931 dv ? device_xname(dv) : "<anonymous>", ev)); 932 return false; 933 } 934 935 pew->pew_event = ev; 936 pew->pew_device = dv; 937 938 workqueue_enqueue(pmf_event_workqueue, &pew->pew_work, NULL); 939 PMF_EVENT_PRINTF(("%s: PMF event %d injected\n", 940 dv ? device_xname(dv) : "<anonymous>", ev)); 941 942 return true; 943} 944 945bool 946pmf_event_register(device_t dv, pmf_generic_event_t ev, 947 void (*handler)(device_t), bool global) 948{ 949 pmf_event_handler_t *event; 950 951 event = kmem_alloc(sizeof(*event), KM_SLEEP); 952 event->pmf_event = ev; 953 event->pmf_handler = handler; 954 event->pmf_device = dv; 955 event->pmf_global = global; 956 TAILQ_INSERT_TAIL(&pmf_all_events, event, pmf_link); 957 958 return true; 959} 960 961void 962pmf_event_deregister(device_t dv, pmf_generic_event_t ev, 963 void (*handler)(device_t), bool global) 964{ 965 pmf_event_handler_t *event; 966 967 TAILQ_FOREACH(event, &pmf_all_events, pmf_link) { 968 if (event->pmf_event != ev) 969 continue; 970 if (event->pmf_device != dv) 971 continue; 972 if (event->pmf_global != global) 973 continue; 974 if (event->pmf_handler != handler) 975 continue; 976 TAILQ_REMOVE(&pmf_all_events, event, pmf_link); 977 kmem_free(event, sizeof(*event)); 978 return; 979 } 980} 981 982struct display_class_softc { 983 TAILQ_ENTRY(display_class_softc) dc_link; 984 device_t dc_dev; 985}; 986 987static TAILQ_HEAD(, display_class_softc) all_displays; 988static callout_t global_idle_counter; 989static int idle_timeout = 30; 990 991static void 992input_idle(void *dummy) 993{ 994 PMF_IDLE_PRINTF(("Input idle handler called\n")); 995 pmf_event_inject(NULL, PMFE_DISPLAY_OFF); 996} 997 998static void 999input_activity_handler(device_t dv, devactive_t type) 1000{ 1001 if (!TAILQ_EMPTY(&all_displays)) 1002 callout_schedule(&global_idle_counter, idle_timeout * hz); 1003} 1004 1005static void 1006pmf_class_input_deregister(device_t dv) 1007{ 1008 device_active_deregister(dv, input_activity_handler); 1009} 1010 1011bool 1012pmf_class_input_register(device_t dv) 1013{ 1014 if (!device_active_register(dv, input_activity_handler)) 1015 return false; 1016 1017 device_pmf_class_register(dv, NULL, NULL, NULL, 1018 pmf_class_input_deregister); 1019 1020 return true; 1021} 1022 1023static void 1024pmf_class_display_deregister(device_t dv) 1025{ 1026 struct display_class_softc *sc = device_pmf_class_private(dv); 1027 int s; 1028 1029 s = splsoftclock(); 1030 TAILQ_REMOVE(&all_displays, sc, dc_link); 1031 if (TAILQ_EMPTY(&all_displays)) 1032 callout_stop(&global_idle_counter); 1033 splx(s); 1034 1035 kmem_free(sc, sizeof(*sc)); 1036} 1037 1038bool 1039pmf_class_display_register(device_t dv) 1040{ 1041 struct display_class_softc *sc; 1042 int s; 1043 1044 sc = kmem_alloc(sizeof(*sc), KM_SLEEP); 1045 1046 s = splsoftclock(); 1047 if (TAILQ_EMPTY(&all_displays)) 1048 callout_schedule(&global_idle_counter, idle_timeout * hz); 1049 1050 TAILQ_INSERT_HEAD(&all_displays, sc, dc_link); 1051 splx(s); 1052 1053 device_pmf_class_register(dv, sc, NULL, NULL, 1054 pmf_class_display_deregister); 1055 1056 return true; 1057} 1058 1059static void 1060pmf_event_workitem_put(pmf_event_workitem_t *pew) 1061{ 1062 1063 KASSERT(pew != NULL); 1064 pool_put(&pew_pl, pew); 1065} 1066 1067static pmf_event_workitem_t * 1068pmf_event_workitem_get(void) 1069{ 1070 1071 return pool_get(&pew_pl, PR_NOWAIT); 1072} 1073 1074void 1075pmf_init(void) 1076{ 1077 int err; 1078 1079 pool_init(&pew_pl, sizeof(pmf_event_workitem_t), 0, 0, 0, 1080 "pewpl", NULL, IPL_HIGH); 1081 pool_setlowat(&pew_pl, 1); 1082 pool_sethiwat(&pew_pl, 8); 1083 1084 KASSERT(pmf_event_workqueue == NULL); 1085 err = workqueue_create(&pmf_event_workqueue, "pmfevent", 1086 pmf_event_worker, NULL, PRI_NONE, IPL_VM, 0); 1087 if (err) 1088 panic("couldn't create pmfevent workqueue"); 1089 1090 KASSERT(pmf_suspend_workqueue == NULL); 1091 err = workqueue_create(&pmf_suspend_workqueue, "pmfsuspend", 1092 pmf_suspend_worker, NULL, PRI_NONE, IPL_VM, 0); 1093 if (err) 1094 panic("couldn't create pmfsuspend workqueue"); 1095 1096 1097 callout_init(&global_idle_counter, 0); 1098 callout_setfunc(&global_idle_counter, input_idle, NULL); 1099} 1100