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 #include "opt_timer.h"
   41 
   42 SLIST_HEAD(et_eventtimers_list, eventtimer);
   43 static struct et_eventtimers_list eventtimers = SLIST_HEAD_INITIALIZER(et_eventtimers);
   44 
   45 struct mtx      et_eventtimers_mtx;
   46 MTX_SYSINIT(et_eventtimers_init, &et_eventtimers_mtx, "et_mtx", MTX_DEF);
   47 
   48 SYSCTL_NODE(_kern, OID_AUTO, eventtimer, CTLFLAG_RW, 0, "Event timers");
   49 static SYSCTL_NODE(_kern_eventtimer, OID_AUTO, et, CTLFLAG_RW, 0, "");
   50 
   51 /*
   52  * Register a new event timer hardware.
   53  */
   54 int
   55 et_register(struct eventtimer *et)
   56 {
   57         struct eventtimer *tmp, *next;
   58 
   59         if (et->et_quality >= 0 || bootverbose) {
   60                 if (et->et_frequency == 0) {
   61                         printf("Event timer \"%s\" quality %d\n",
   62                             et->et_name, et->et_quality);
   63                 } else {
   64                         printf("Event timer \"%s\" "
   65                             "frequency %ju Hz quality %d\n",
   66                             et->et_name, (uintmax_t)et->et_frequency,
   67                             et->et_quality);
   68                 }
   69         }
   70         KASSERT(et->et_start, ("et_register: timer has no start function"));
   71         et->et_sysctl = SYSCTL_ADD_NODE_WITH_LABEL(NULL,
   72             SYSCTL_STATIC_CHILDREN(_kern_eventtimer_et), OID_AUTO, et->et_name,
   73             CTLFLAG_RW, 0, "event timer description", "eventtimer");
   74         SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   75             "flags", CTLFLAG_RD, &(et->et_flags), 0,
   76             "Event timer capabilities");
   77         SYSCTL_ADD_UQUAD(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   78             "frequency", CTLFLAG_RD, &(et->et_frequency),
   79             "Event timer base frequency");
   80         SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(et->et_sysctl), OID_AUTO,
   81             "quality", CTLFLAG_RD, &(et->et_quality), 0,
   82             "Goodness of event timer");
   83         ET_LOCK();
   84         if (SLIST_EMPTY(&eventtimers) ||
   85             SLIST_FIRST(&eventtimers)->et_quality < et->et_quality) {
   86                 SLIST_INSERT_HEAD(&eventtimers, et, et_all);
   87         } else {
   88                 SLIST_FOREACH(tmp, &eventtimers, et_all) {
   89                         next = SLIST_NEXT(tmp, et_all);
   90                         if (next == NULL || next->et_quality < et->et_quality) {
   91                                 SLIST_INSERT_AFTER(tmp, et, et_all);
   92                                 break;
   93                         }
   94                 }
   95         }
   96         ET_UNLOCK();
   97         return (0);
   98 }
   99 
  100 /*
  101  * Deregister event timer hardware.
  102  */
  103 int
  104 et_deregister(struct eventtimer *et)
  105 {
  106         int err = 0;
  107 
  108         if (et->et_deregister_cb != NULL) {
  109                 if ((err = et->et_deregister_cb(et, et->et_arg)) != 0)
  110                         return (err);
  111         }
  112 
  113         ET_LOCK();
  114         SLIST_REMOVE(&eventtimers, et, eventtimer, et_all);
  115         ET_UNLOCK();
  116         sysctl_remove_oid(et->et_sysctl, 1, 1);
  117         return (0);
  118 }
  119 
  120 /*
  121  * Change the frequency of the given timer.  If it is the active timer,
  122  * reconfigure it on all CPUs (reschedules all current events based on the new
  123  * timer frequency).
  124  */
  125 void
  126 et_change_frequency(struct eventtimer *et, uint64_t newfreq)
  127 {
  128 
  129 #ifndef NO_EVENTTIMERS
  130         cpu_et_frequency(et, newfreq);
  131 #endif
  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");
  267 

Cache object: 84f7b76da3232070c8091bfb5279faf1


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