The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_pmf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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
   62 int  pmf_debug_event;
   63 int  pmf_debug_suspend;
   64 int  pmf_debug_suspensor;
   65 int  pmf_debug_idle;
   66 int  pmf_debug_transition;
   67 
   68 #define PMF_SUSPENSOR_PRINTF(x)         if (pmf_debug_suspensor) printf x
   69 #define PMF_SUSPEND_PRINTF(x)           if (pmf_debug_suspend) printf x
   70 #define PMF_EVENT_PRINTF(x)             if (pmf_debug_event) printf x
   71 #define PMF_IDLE_PRINTF(x)              if (pmf_debug_idle) printf x
   72 #define PMF_TRANSITION_PRINTF(x)        if (pmf_debug_transition) printf x
   73 #define PMF_TRANSITION_PRINTF2(y,x)     if (pmf_debug_transition>y) printf x
   74 #else
   75 #define PMF_SUSPENSOR_PRINTF(x)         do { } while (0)
   76 #define PMF_SUSPEND_PRINTF(x)           do { } while (0)
   77 #define PMF_EVENT_PRINTF(x)             do { } while (0)
   78 #define PMF_IDLE_PRINTF(x)              do { } while (0)
   79 #define PMF_TRANSITION_PRINTF(x)        do { } while (0)
   80 #define PMF_TRANSITION_PRINTF2(y,x)     do { } while (0)
   81 #endif
   82 
   83 static prop_dictionary_t pmf_platform = NULL;
   84 static struct workqueue *pmf_event_workqueue;
   85 static struct workqueue *pmf_suspend_workqueue;
   86 
   87 typedef 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 
   95 static TAILQ_HEAD(, pmf_event_handler) pmf_all_events =
   96     TAILQ_HEAD_INITIALIZER(pmf_all_events);
   97 
   98 typedef 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 
  104 typedef 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 
  110 static struct pool pew_pl;
  111 
  112 static pmf_event_workitem_t *pmf_event_workitem_get(void);
  113 static void pmf_event_workitem_put(pmf_event_workitem_t *);
  114 
  115 static bool pmf_device_resume_locked(device_t, const pmf_qual_t *);
  116 static bool pmf_device_suspend_locked(device_t, const pmf_qual_t *);
  117 static bool device_pmf_any_suspensor(device_t, devact_level_t);
  118 
  119 static bool
  120 complete_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 
  142 static void
  143 pmf_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 
  183 static void
  184 pmf_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 
  203 static bool
  204 pmf_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 
  228 bool
  229 pmf_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 
  259 bool
  260 pmf_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 
  300 bool
  301 pmf_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 
  348 static bool
  349 shutdown_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 
  378 void
  379 pmf_system_shutdown(int how)
  380 {
  381 
  382         if (panicstr != NULL)
  383                 return;
  384 
  385         aprint_debug("Shutting down devices:");
  386         shutdown_all(how);
  387 }
  388 
  389 bool
  390 pmf_set_platform(const char *key, const char *value)
  391 {
  392         if (pmf_platform == NULL)
  393                 pmf_platform = prop_dictionary_create();
  394         if (pmf_platform == NULL)
  395                 return false;
  396 
  397         return prop_dictionary_set_string(pmf_platform, key, value);
  398 }
  399 
  400 const char *
  401 pmf_get_platform(const char *key)
  402 {
  403         const char *value;
  404 
  405         if (pmf_platform == NULL)
  406                 return NULL;
  407 
  408         if (!prop_dictionary_get_string(pmf_platform, key, &value))
  409                 return NULL;
  410 
  411         return value;
  412 }
  413 
  414 bool
  415 pmf_device_register1(device_t dev,
  416     bool (*suspend)(device_t, const pmf_qual_t *),
  417     bool (*resume)(device_t, const pmf_qual_t *),
  418     bool (*shutdown)(device_t, int))
  419 {
  420 
  421         device_pmf_driver_register(dev, suspend, resume, shutdown);
  422         device_pmf_driver_child_register(dev);
  423 
  424         return true;
  425 }
  426 
  427 void
  428 pmf_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 
  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 
  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 
  679 bool
  680 pmf_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 
  699 bool
  700 pmf_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 
  721 bool
  722 pmf_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 
  741 bool
  742 pmf_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 
  765 bool
  766 pmf_device_recursive_suspend(device_t dv, const pmf_qual_t *qual)
  767 {
  768         bool rv = true;
  769         device_t curdev;
  770         deviter_t di;
  771         pmf_qual_t pq;
  772 
  773         pmf_qual_recursive_copy(&pq, qual);
  774 
  775         for (curdev = deviter_first(&di, 0); curdev != NULL;
  776              curdev = deviter_next(&di)) {
  777                 if (device_parent(curdev) != dv)
  778                         continue;
  779                 if (!pmf_device_recursive_suspend(curdev, &pq)) {
  780                         rv = false;
  781                         break;
  782                 }
  783         }
  784         deviter_release(&di);
  785 
  786         return rv && pmf_device_suspend(dv, qual);
  787 }
  788 
  789 void
  790 pmf_qual_recursive_copy(pmf_qual_t *dst, const pmf_qual_t *src)
  791 {
  792 
  793         *dst = *src;
  794         dst->pq_actlvl = DEVACT_LEVEL_FULL;
  795 }
  796 
  797 bool
  798 pmf_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 
  817 bool
  818 pmf_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 
  838 bool
  839 pmf_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 
  861 bool
  862 pmf_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 
  873 bool
  874 pmf_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 
  891 static bool
  892 pmf_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 
  906 static bool
  907 pmf_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 
  931 void
  932 pmf_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 
  939 bool
  940 pmf_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 
  961 bool
  962 pmf_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 
  977 void
  978 pmf_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 
  998 struct display_class_softc {
  999         TAILQ_ENTRY(display_class_softc) dc_link;
 1000         device_t dc_dev;
 1001 };
 1002 
 1003 static TAILQ_HEAD(, display_class_softc) all_displays;
 1004 static callout_t global_idle_counter;
 1005 static int idle_timeout = 30;
 1006 
 1007 static void
 1008 input_idle(void *dummy)
 1009 {
 1010 
 1011         PMF_IDLE_PRINTF(("Input idle handler called\n"));
 1012         pmf_event_inject(NULL, PMFE_DISPLAY_OFF);
 1013 }
 1014 
 1015 static void
 1016 input_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 
 1023 static void
 1024 pmf_class_input_deregister(device_t dv)
 1025 {
 1026 
 1027         device_active_deregister(dv, input_activity_handler);
 1028 }
 1029 
 1030 bool
 1031 pmf_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 
 1043 static void
 1044 pmf_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 
 1058 bool
 1059 pmf_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 
 1079 static void
 1080 pmf_event_workitem_put(pmf_event_workitem_t *pew)
 1081 {
 1082 
 1083         KASSERT(pew != NULL);
 1084         pool_put(&pew_pl, pew);
 1085 }
 1086 
 1087 static pmf_event_workitem_t *
 1088 pmf_event_workitem_get(void)
 1089 {
 1090 
 1091         return pool_get(&pew_pl, PR_NOWAIT);
 1092 }
 1093 
 1094 SYSCTL_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 void
 1147 pmf_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 }

Cache object: 5c1cbf508d0589943d423fa5eea043d6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.