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$");
   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 #include "opt_timer.h"
   38 
   39 SLIST_HEAD(et_eventtimers_list, eventtimer);
   40 static struct et_eventtimers_list eventtimers = SLIST_HEAD_INITIALIZER(et_eventtimers);
   41 
   42 struct mtx      et_eventtimers_mtx;
   43 MTX_SYSINIT(et_eventtimers_init, &et_eventtimers_mtx, "et_mtx", MTX_DEF);
   44 
   45 SYSCTL_NODE(_kern, OID_AUTO, eventtimer, CTLFLAG_RW, 0, "Event timers");
   46 static SYSCTL_NODE(_kern_eventtimer, OID_AUTO, et, CTLFLAG_RW, 0, "");
   47 
   48 /*
   49  * Register a new event timer hardware.
   50  */
   51 int
   52 et_register(struct eventtimer *et)
   53 {
   54         struct eventtimer *tmp, *next;
   55 
   56         if (et->et_quality >= 0 || bootverbose) {
   57                 if (et->et_frequency == 0) {
   58                         printf("Event timer \"%s\" quality %d\n",
   59                             et->et_name, et->et_quality);
   60                 } else {
   61                         printf("Event timer \"%s\" "
   62                             "frequency %ju Hz quality %d\n",
   63                             et->et_name, (uintmax_t)et->et_frequency,
   64                             et->et_quality);
   65                 }
   66         }
   67         KASSERT(et->et_start, ("et_register: timer has no start function"));
   68         et->et_sysctl = SYSCTL_ADD_NODE(NULL,
   69             SYSCTL_STATIC_CHILDREN(_kern_eventtimer_et), OID_AUTO, et->et_name,
   70             CTLFLAG_RW, 0, "event timer description");
   71         SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   72             "flags", CTLFLAG_RD, &(et->et_flags), 0,
   73             "Event timer capabilities");
   74         SYSCTL_ADD_UQUAD(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   75             "frequency", CTLFLAG_RD, &(et->et_frequency),
   76             "Event timer base frequency");
   77         SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   78             "quality", CTLFLAG_RD, &(et->et_quality), 0,
   79             "Goodness of event timer");
   80         ET_LOCK();
   81         if (SLIST_EMPTY(&eventtimers) ||
   82             SLIST_FIRST(&eventtimers)->et_quality < et->et_quality) {
   83                 SLIST_INSERT_HEAD(&eventtimers, et, et_all);
   84         } else {
   85                 SLIST_FOREACH(tmp, &eventtimers, et_all) {
   86                         next = SLIST_NEXT(tmp, et_all);
   87                         if (next == NULL || next->et_quality < et->et_quality) {
   88                                 SLIST_INSERT_AFTER(tmp, et, et_all);
   89                                 break;
   90                         }
   91                 }
   92         }
   93         ET_UNLOCK();
   94         return (0);
   95 }
   96 
   97 /*
   98  * Deregister event timer hardware.
   99  */
  100 int
  101 et_deregister(struct eventtimer *et)
  102 {
  103         int err = 0;
  104 
  105         if (et->et_deregister_cb != NULL) {
  106                 if ((err = et->et_deregister_cb(et, et->et_arg)) != 0)
  107                         return (err);
  108         }
  109 
  110         ET_LOCK();
  111         SLIST_REMOVE(&eventtimers, et, eventtimer, et_all);
  112         ET_UNLOCK();
  113         sysctl_remove_oid(et->et_sysctl, 1, 1);
  114         return (0);
  115 }
  116 
  117 /*
  118  * Change the frequency of the given timer.  If it is the active timer,
  119  * reconfigure it on all CPUs (reschedules all current events based on the new
  120  * timer frequency).
  121  */
  122 void
  123 et_change_frequency(struct eventtimer *et, uint64_t newfreq)
  124 {
  125 
  126 #ifndef NO_EVENTTIMERS
  127         cpu_et_frequency(et, newfreq);
  128 #endif
  129 }
  130 
  131 /*
  132  * Find free event timer hardware with specified parameters.
  133  */
  134 struct eventtimer *
  135 et_find(const char *name, int check, int want)
  136 {
  137         struct eventtimer *et = NULL;
  138 
  139         SLIST_FOREACH(et, &eventtimers, et_all) {
  140                 if (et->et_active)
  141                         continue;
  142                 if (name != NULL && strcasecmp(et->et_name, name) != 0)
  143                         continue;
  144                 if (name == NULL && et->et_quality < 0)
  145                         continue;
  146                 if ((et->et_flags & check) != want)
  147                         continue;
  148                 break;
  149         }
  150         return (et);
  151 }
  152 
  153 /*
  154  * Initialize event timer hardware. Set callbacks.
  155  */
  156 int
  157 et_init(struct eventtimer *et, et_event_cb_t *event,
  158     et_deregister_cb_t *deregister, void *arg)
  159 {
  160 
  161         if (event == NULL)
  162                 return (EINVAL);
  163         if (et->et_active)
  164                 return (EBUSY);
  165 
  166         et->et_active = 1;
  167         et->et_event_cb = event;
  168         et->et_deregister_cb = deregister;
  169         et->et_arg = arg;
  170         return (0);
  171 }
  172 
  173 /*
  174  * Start event timer hardware.
  175  * first - delay before first tick.
  176  * period - period of subsequent periodic ticks.
  177  */
  178 int
  179 et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
  180 {
  181 
  182         if (!et->et_active)
  183                 return (ENXIO);
  184         KASSERT(period >= 0, ("et_start: negative period"));
  185         KASSERT((et->et_flags & ET_FLAGS_PERIODIC) || period == 0,
  186                 ("et_start: period specified for oneshot-only timer"));
  187         KASSERT((et->et_flags & ET_FLAGS_ONESHOT) || period != 0,
  188                 ("et_start: period not specified for periodic-only timer"));
  189         if (period != 0) {
  190                 if (period < et->et_min_period)
  191                         period = et->et_min_period;
  192                 else if (period > et->et_max_period)
  193                         period = et->et_max_period;
  194         }
  195         if (period == 0 || first != 0) {
  196                 if (first < et->et_min_period)
  197                         first = et->et_min_period;
  198                 else if (first > et->et_max_period)
  199                         first = et->et_max_period;
  200         }
  201         return (et->et_start(et, first, period));
  202 }
  203 
  204 /* Stop event timer hardware. */
  205 int
  206 et_stop(struct eventtimer *et)
  207 {
  208 
  209         if (!et->et_active)
  210                 return (ENXIO);
  211         if (et->et_stop)
  212                 return (et->et_stop(et));
  213         return (0);
  214 }
  215 
  216 /* Mark event timer hardware as broken. */
  217 int
  218 et_ban(struct eventtimer *et)
  219 {
  220 
  221         et->et_flags &= ~(ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT);
  222         return (0);
  223 }
  224 
  225 /* Free event timer hardware. */
  226 int
  227 et_free(struct eventtimer *et)
  228 {
  229 
  230         if (!et->et_active)
  231                 return (ENXIO);
  232 
  233         et->et_active = 0;
  234         return (0);
  235 }
  236 
  237 /* Report list of supported event timers hardware via sysctl. */
  238 static int
  239 sysctl_kern_eventtimer_choice(SYSCTL_HANDLER_ARGS)
  240 {
  241         char buf[512], *spc;
  242         struct eventtimer *et;
  243         int error, off;
  244 
  245         spc = "";
  246         error = 0;
  247         buf[0] = 0;
  248         off = 0;
  249         ET_LOCK();
  250         SLIST_FOREACH(et, &eventtimers, et_all) {
  251                 off += snprintf(buf + off, sizeof(buf) - off, "%s%s(%d)",
  252                     spc, et->et_name, et->et_quality);
  253                 spc = " ";
  254         }
  255         ET_UNLOCK();
  256         error = SYSCTL_OUT(req, buf, strlen(buf));
  257         return (error);
  258 }
  259 SYSCTL_PROC(_kern_eventtimer, OID_AUTO, choice,
  260     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
  261     0, 0, sysctl_kern_eventtimer_choice, "A", "Present event timers");
  262 

Cache object: 50b38adcad7a956a19d4b819a9593205


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