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

Cache object: c96b43e89eb18971b22d36505a2c4ad9


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