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_et.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 /*-
    2  * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer,
   10  *    without modification, immediately at the beginning of the file.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/kernel.h>
   32 #include <sys/sysctl.h>
   33 #include <sys/systm.h>
   34 #include <sys/queue.h>
   35 #include <sys/timeet.h>
   36 
   37 SLIST_HEAD(et_eventtimers_list, eventtimer);
   38 static struct et_eventtimers_list eventtimers = SLIST_HEAD_INITIALIZER(et_eventtimers);
   39 
   40 struct mtx      et_eventtimers_mtx;
   41 MTX_SYSINIT(et_eventtimers_init, &et_eventtimers_mtx, "et_mtx", MTX_DEF);
   42 
   43 SYSCTL_NODE(_kern, OID_AUTO, eventtimer, CTLFLAG_RW, 0, "Event timers");
   44 static SYSCTL_NODE(_kern_eventtimer, OID_AUTO, et, CTLFLAG_RW, 0, "");
   45 
   46 /*
   47  * Register a new event timer hardware.
   48  */
   49 int
   50 et_register(struct eventtimer *et)
   51 {
   52         struct eventtimer *tmp, *next;
   53 
   54         if (et->et_quality >= 0 || bootverbose) {
   55                 if (et->et_frequency == 0) {
   56                         printf("Event timer \"%s\" quality %d\n",
   57                             et->et_name, et->et_quality);
   58                 } else {
   59                         printf("Event timer \"%s\" "
   60                             "frequency %ju Hz quality %d\n",
   61                             et->et_name, (uintmax_t)et->et_frequency,
   62                             et->et_quality);
   63                 }
   64         }
   65         et->et_sysctl = SYSCTL_ADD_NODE(NULL,
   66             SYSCTL_STATIC_CHILDREN(_kern_eventtimer_et), OID_AUTO, et->et_name,
   67             CTLFLAG_RW, 0, "event timer description");
   68         SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   69             "flags", CTLFLAG_RD, &(et->et_flags), 0,
   70             "Event timer capabilities");
   71         SYSCTL_ADD_UQUAD(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   72             "frequency", CTLFLAG_RD, &(et->et_frequency),
   73             "Event timer base frequency");
   74         SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   75             "quality", CTLFLAG_RD, &(et->et_quality), 0,
   76             "Goodness of event timer");
   77         ET_LOCK();
   78         if (SLIST_EMPTY(&eventtimers) ||
   79             SLIST_FIRST(&eventtimers)->et_quality < et->et_quality) {
   80                 SLIST_INSERT_HEAD(&eventtimers, et, et_all);
   81         } else {
   82                 SLIST_FOREACH(tmp, &eventtimers, et_all) {
   83                         next = SLIST_NEXT(tmp, et_all);
   84                         if (next == NULL || next->et_quality < et->et_quality) {
   85                                 SLIST_INSERT_AFTER(tmp, et, et_all);
   86                                 break;
   87                         }
   88                 }
   89         }
   90         ET_UNLOCK();
   91         return (0);
   92 }
   93 
   94 /*
   95  * Deregister event timer hardware.
   96  */
   97 int
   98 et_deregister(struct eventtimer *et)
   99 {
  100         int err = 0;
  101 
  102         if (et->et_deregister_cb != NULL) {
  103                 if ((err = et->et_deregister_cb(et, et->et_arg)) != 0)
  104                         return (err);
  105         }
  106 
  107         ET_LOCK();
  108         SLIST_REMOVE(&eventtimers, et, eventtimer, et_all);
  109         ET_UNLOCK();
  110         sysctl_remove_oid(et->et_sysctl, 1, 1);
  111         return (0);
  112 }
  113 
  114 /*
  115  * Find free event timer hardware with specified parameters.
  116  */
  117 struct eventtimer *
  118 et_find(const char *name, int check, int want)
  119 {
  120         struct eventtimer *et = NULL;
  121 
  122         SLIST_FOREACH(et, &eventtimers, et_all) {
  123                 if (et->et_active)
  124                         continue;
  125                 if (name != NULL && strcasecmp(et->et_name, name) != 0)
  126                         continue;
  127                 if (name == NULL && et->et_quality < 0)
  128                         continue;
  129                 if ((et->et_flags & check) != want)
  130                         continue;
  131                 break;
  132         }
  133         return (et);
  134 }
  135 
  136 /*
  137  * Initialize event timer hardware. Set callbacks.
  138  */
  139 int
  140 et_init(struct eventtimer *et, et_event_cb_t *event,
  141     et_deregister_cb_t *deregister, void *arg)
  142 {
  143 
  144         if (event == NULL)
  145                 return (EINVAL);
  146         if (et->et_active)
  147                 return (EBUSY);
  148 
  149         et->et_active = 1;
  150         et->et_event_cb = event;
  151         et->et_deregister_cb = deregister;
  152         et->et_arg = arg;
  153         return (0);
  154 }
  155 
  156 /*
  157  * Start event timer hardware.
  158  * first - delay before first tick.
  159  * period - period of subsequent periodic ticks.
  160  */
  161 int
  162 et_start(struct eventtimer *et,
  163     struct bintime *first, struct bintime *period)
  164 {
  165 
  166         if (!et->et_active)
  167                 return (ENXIO);
  168         if (first == NULL && period == NULL)
  169                 return (EINVAL);
  170         if ((et->et_flags & ET_FLAGS_PERIODIC) == 0 &&
  171             period != NULL)
  172                 return (ENODEV);
  173         if ((et->et_flags & ET_FLAGS_ONESHOT) == 0 &&
  174             period == NULL)
  175                 return (ENODEV);
  176         if (first != NULL) {
  177                 if (first->sec < et->et_min_period.sec ||
  178                     (first->sec == et->et_min_period.sec &&
  179                      first->frac < et->et_min_period.frac))
  180                         first = &et->et_min_period;
  181                 if (first->sec > et->et_max_period.sec ||
  182                     (first->sec == et->et_max_period.sec &&
  183                      first->frac > et->et_max_period.frac))
  184                         first = &et->et_max_period;
  185         }
  186         if (period != NULL) {
  187                 if (period->sec < et->et_min_period.sec ||
  188                     (period->sec == et->et_min_period.sec &&
  189                      period->frac < et->et_min_period.frac))
  190                         period = &et->et_min_period;
  191                 if (period->sec > et->et_max_period.sec ||
  192                     (period->sec == et->et_max_period.sec &&
  193                      period->frac > et->et_max_period.frac))
  194                         period = &et->et_max_period;
  195         }
  196         if (et->et_start)
  197                 return (et->et_start(et, first, period));
  198         return (0);
  199 }
  200 
  201 /* Stop event timer hardware. */
  202 int
  203 et_stop(struct eventtimer *et)
  204 {
  205 
  206         if (!et->et_active)
  207                 return (ENXIO);
  208         if (et->et_stop)
  209                 return (et->et_stop(et));
  210         return (0);
  211 }
  212 
  213 /* Mark event timer hardware as broken. */
  214 int
  215 et_ban(struct eventtimer *et)
  216 {
  217 
  218         et->et_flags &= ~(ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT);
  219         return (0);
  220 }
  221 
  222 /* Free event timer hardware. */
  223 int
  224 et_free(struct eventtimer *et)
  225 {
  226 
  227         if (!et->et_active)
  228                 return (ENXIO);
  229 
  230         et->et_active = 0;
  231         return (0);
  232 }
  233 
  234 /* Report list of supported event timers hardware via sysctl. */
  235 static int
  236 sysctl_kern_eventtimer_choice(SYSCTL_HANDLER_ARGS)
  237 {
  238         char buf[512], *spc;
  239         struct eventtimer *et;
  240         int error, off;
  241 
  242         spc = "";
  243         error = 0;
  244         buf[0] = 0;
  245         off = 0;
  246         ET_LOCK();
  247         SLIST_FOREACH(et, &eventtimers, et_all) {
  248                 off += snprintf(buf + off, sizeof(buf) - off, "%s%s(%d)",
  249                     spc, et->et_name, et->et_quality);
  250                 spc = " ";
  251         }
  252         ET_UNLOCK();
  253         error = SYSCTL_OUT(req, buf, strlen(buf));
  254         return (error);
  255 }
  256 SYSCTL_PROC(_kern_eventtimer, OID_AUTO, choice,
  257     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
  258     0, 0, sysctl_kern_eventtimer_choice, "A", "Present event timers");
  259 

Cache object: 5a248b146a0e956f5069703100d07a4a


[ 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.