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-2013 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: releng/10.0/sys/kern/kern_et.c 248230 2013-03-13 06:42:01Z mav $");
   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         KASSERT(et->et_start, ("et_register: timer has no start function"));
   66         et->et_sysctl = SYSCTL_ADD_NODE(NULL,
   67             SYSCTL_STATIC_CHILDREN(_kern_eventtimer_et), OID_AUTO, et->et_name,
   68             CTLFLAG_RW, 0, "event timer description");
   69         SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   70             "flags", CTLFLAG_RD, &(et->et_flags), 0,
   71             "Event timer capabilities");
   72         SYSCTL_ADD_UQUAD(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   73             "frequency", CTLFLAG_RD, &(et->et_frequency),
   74             "Event timer base frequency");
   75         SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   76             "quality", CTLFLAG_RD, &(et->et_quality), 0,
   77             "Goodness of event timer");
   78         ET_LOCK();
   79         if (SLIST_EMPTY(&eventtimers) ||
   80             SLIST_FIRST(&eventtimers)->et_quality < et->et_quality) {
   81                 SLIST_INSERT_HEAD(&eventtimers, et, et_all);
   82         } else {
   83                 SLIST_FOREACH(tmp, &eventtimers, et_all) {
   84                         next = SLIST_NEXT(tmp, et_all);
   85                         if (next == NULL || next->et_quality < et->et_quality) {
   86                                 SLIST_INSERT_AFTER(tmp, et, et_all);
   87                                 break;
   88                         }
   89                 }
   90         }
   91         ET_UNLOCK();
   92         return (0);
   93 }
   94 
   95 /*
   96  * Deregister event timer hardware.
   97  */
   98 int
   99 et_deregister(struct eventtimer *et)
  100 {
  101         int err = 0;
  102 
  103         if (et->et_deregister_cb != NULL) {
  104                 if ((err = et->et_deregister_cb(et, et->et_arg)) != 0)
  105                         return (err);
  106         }
  107 
  108         ET_LOCK();
  109         SLIST_REMOVE(&eventtimers, et, eventtimer, et_all);
  110         ET_UNLOCK();
  111         sysctl_remove_oid(et->et_sysctl, 1, 1);
  112         return (0);
  113 }
  114 
  115 /*
  116  * Find free event timer hardware with specified parameters.
  117  */
  118 struct eventtimer *
  119 et_find(const char *name, int check, int want)
  120 {
  121         struct eventtimer *et = NULL;
  122 
  123         SLIST_FOREACH(et, &eventtimers, et_all) {
  124                 if (et->et_active)
  125                         continue;
  126                 if (name != NULL && strcasecmp(et->et_name, name) != 0)
  127                         continue;
  128                 if (name == NULL && et->et_quality < 0)
  129                         continue;
  130                 if ((et->et_flags & check) != want)
  131                         continue;
  132                 break;
  133         }
  134         return (et);
  135 }
  136 
  137 /*
  138  * Initialize event timer hardware. Set callbacks.
  139  */
  140 int
  141 et_init(struct eventtimer *et, et_event_cb_t *event,
  142     et_deregister_cb_t *deregister, void *arg)
  143 {
  144 
  145         if (event == NULL)
  146                 return (EINVAL);
  147         if (et->et_active)
  148                 return (EBUSY);
  149 
  150         et->et_active = 1;
  151         et->et_event_cb = event;
  152         et->et_deregister_cb = deregister;
  153         et->et_arg = arg;
  154         return (0);
  155 }
  156 
  157 /*
  158  * Start event timer hardware.
  159  * first - delay before first tick.
  160  * period - period of subsequent periodic ticks.
  161  */
  162 int
  163 et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
  164 {
  165 
  166         if (!et->et_active)
  167                 return (ENXIO);
  168         KASSERT(period >= 0, ("et_start: negative period"));
  169         KASSERT((et->et_flags & ET_FLAGS_PERIODIC) || period == 0,
  170                 ("et_start: period specified for oneshot-only timer"));
  171         KASSERT((et->et_flags & ET_FLAGS_ONESHOT) || period != 0,
  172                 ("et_start: period not specified for periodic-only timer"));
  173         if (period != 0) {
  174                 if (period < et->et_min_period)
  175                         period = et->et_min_period;
  176                 else if (period > et->et_max_period)
  177                         period = et->et_max_period;
  178         }
  179         if (period == 0 || first != 0) {
  180                 if (first < et->et_min_period)
  181                         first = et->et_min_period;
  182                 else if (first > et->et_max_period)
  183                         first = et->et_max_period;
  184         }
  185         return (et->et_start(et, first, period));
  186 }
  187 
  188 /* Stop event timer hardware. */
  189 int
  190 et_stop(struct eventtimer *et)
  191 {
  192 
  193         if (!et->et_active)
  194                 return (ENXIO);
  195         if (et->et_stop)
  196                 return (et->et_stop(et));
  197         return (0);
  198 }
  199 
  200 /* Mark event timer hardware as broken. */
  201 int
  202 et_ban(struct eventtimer *et)
  203 {
  204 
  205         et->et_flags &= ~(ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT);
  206         return (0);
  207 }
  208 
  209 /* Free event timer hardware. */
  210 int
  211 et_free(struct eventtimer *et)
  212 {
  213 
  214         if (!et->et_active)
  215                 return (ENXIO);
  216 
  217         et->et_active = 0;
  218         return (0);
  219 }
  220 
  221 /* Report list of supported event timers hardware via sysctl. */
  222 static int
  223 sysctl_kern_eventtimer_choice(SYSCTL_HANDLER_ARGS)
  224 {
  225         char buf[512], *spc;
  226         struct eventtimer *et;
  227         int error, off;
  228 
  229         spc = "";
  230         error = 0;
  231         buf[0] = 0;
  232         off = 0;
  233         ET_LOCK();
  234         SLIST_FOREACH(et, &eventtimers, et_all) {
  235                 off += snprintf(buf + off, sizeof(buf) - off, "%s%s(%d)",
  236                     spc, et->et_name, et->et_quality);
  237                 spc = " ";
  238         }
  239         ET_UNLOCK();
  240         error = SYSCTL_OUT(req, buf, strlen(buf));
  241         return (error);
  242 }
  243 SYSCTL_PROC(_kern_eventtimer, OID_AUTO, choice,
  244     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
  245     0, 0, sysctl_kern_eventtimer_choice, "A", "Present event timers");
  246 

Cache object: 8ee9d5a160ea72e8fed0e681add6c566


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