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_tc.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 /* $NetBSD: kern_tc.c,v 1.16 2006/11/01 10:17:58 yamt Exp $ */
    2 
    3 /*-
    4  * ----------------------------------------------------------------------------
    5  * "THE BEER-WARE LICENSE" (Revision 42):
    6  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
    7  * can do whatever you want with this stuff. If we meet some day, and you think
    8  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
    9  * ---------------------------------------------------------------------------
   10  */
   11 
   12 #include <sys/cdefs.h>
   13 /* __FBSDID("$FreeBSD: src/sys/kern/kern_tc.c,v 1.166 2005/09/19 22:16:31 andre Exp $"); */
   14 __KERNEL_RCSID(0, "$NetBSD: kern_tc.c,v 1.16 2006/11/01 10:17:58 yamt Exp $");
   15 
   16 #include "opt_ntp.h"
   17 
   18 #include <sys/param.h>
   19 #ifdef __HAVE_TIMECOUNTER       /* XXX */
   20 #include <sys/kernel.h>
   21 #include <sys/reboot.h> /* XXX just to get AB_VERBOSE */
   22 #include <sys/sysctl.h>
   23 #include <sys/syslog.h>
   24 #include <sys/systm.h>
   25 #include <sys/timepps.h>
   26 #include <sys/timetc.h>
   27 #include <sys/timex.h>
   28 #include <sys/evcnt.h>
   29 #include <sys/kauth.h>
   30 
   31 /*
   32  * A large step happens on boot.  This constant detects such steps.
   33  * It is relatively small so that ntp_update_second gets called enough
   34  * in the typical 'missed a couple of seconds' case, but doesn't loop
   35  * forever when the time step is large.
   36  */
   37 #define LARGE_STEP      200
   38 
   39 /*
   40  * Implement a dummy timecounter which we can use until we get a real one
   41  * in the air.  This allows the console and other early stuff to use
   42  * time services.
   43  */
   44 
   45 static u_int
   46 dummy_get_timecount(struct timecounter *tc)
   47 {
   48         static u_int now;
   49 
   50         return (++now);
   51 }
   52 
   53 static struct timecounter dummy_timecounter = {
   54         dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000, NULL, NULL,
   55 };
   56 
   57 struct timehands {
   58         /* These fields must be initialized by the driver. */
   59         struct timecounter      *th_counter;
   60         int64_t                 th_adjustment;
   61         u_int64_t               th_scale;
   62         u_int                   th_offset_count;
   63         struct bintime          th_offset;
   64         struct timeval          th_microtime;
   65         struct timespec         th_nanotime;
   66         /* Fields not to be copied in tc_windup start with th_generation. */
   67         volatile u_int          th_generation;
   68         struct timehands        *th_next;
   69 };
   70 
   71 static struct timehands th0;
   72 static struct timehands th9 = { .th_next = &th0, };
   73 static struct timehands th8 = { .th_next = &th9, };
   74 static struct timehands th7 = { .th_next = &th8, };
   75 static struct timehands th6 = { .th_next = &th7, };
   76 static struct timehands th5 = { .th_next = &th6, };
   77 static struct timehands th4 = { .th_next = &th5, };
   78 static struct timehands th3 = { .th_next = &th4, };
   79 static struct timehands th2 = { .th_next = &th3, };
   80 static struct timehands th1 = { .th_next = &th2, };
   81 static struct timehands th0 = {
   82         .th_counter = &dummy_timecounter,
   83         .th_scale = (uint64_t)-1 / 1000000,
   84         .th_offset = { .sec = 1, .frac = 0 },
   85         .th_generation = 1,
   86         .th_next = &th1,
   87 };
   88 
   89 static struct timehands *volatile timehands = &th0;
   90 struct timecounter *timecounter = &dummy_timecounter;
   91 static struct timecounter *timecounters = &dummy_timecounter;
   92 
   93 time_t time_second = 1;
   94 time_t time_uptime = 1;
   95 
   96 static struct bintime timebasebin;
   97 
   98 static int timestepwarnings;
   99 
  100 #ifdef __FreeBSD__
  101 SYSCTL_INT(_kern_timecounter, OID_AUTO, stepwarnings, CTLFLAG_RW,
  102     &timestepwarnings, 0, "");
  103 #endif /* __FreeBSD__ */
  104 
  105 /*
  106  * sysctl helper routine for kern.timercounter.current
  107  */
  108 static int
  109 sysctl_kern_timecounter_hardware(SYSCTLFN_ARGS)
  110 {
  111         struct sysctlnode node;
  112         int error;
  113         char newname[MAX_TCNAMELEN];
  114         struct timecounter *newtc, *tc;
  115 
  116         tc = timecounter;
  117 
  118         strlcpy(newname, tc->tc_name, sizeof(newname));
  119 
  120         node = *rnode;
  121         node.sysctl_data = newname;
  122         node.sysctl_size = sizeof(newname);
  123 
  124         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  125 
  126         if (error ||
  127             newp == NULL ||
  128             strncmp(newname, tc->tc_name, sizeof(newname)) == 0)
  129                 return error;
  130 
  131         if (l != NULL && (error = kauth_authorize_generic(l->l_cred, 
  132             KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0)
  133                 return (error);
  134 
  135         /* XXX locking */
  136 
  137         for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) {
  138                 if (strcmp(newname, newtc->tc_name) != 0)
  139                         continue;
  140 
  141                 /* Warm up new timecounter. */
  142                 (void)newtc->tc_get_timecount(newtc);
  143                 (void)newtc->tc_get_timecount(newtc);
  144 
  145                 timecounter = newtc;
  146 
  147                 /* XXX unlock */
  148 
  149                 return (0);
  150         }
  151 
  152         /* XXX unlock */
  153 
  154         return (EINVAL);
  155 }
  156 
  157 static int
  158 sysctl_kern_timecounter_choice(SYSCTLFN_ARGS)
  159 {
  160         char buf[MAX_TCNAMELEN+48];
  161         char *where = oldp;
  162         const char *spc;
  163         struct timecounter *tc;
  164         size_t needed, left, slen;
  165         int error;
  166 
  167         if (newp != NULL)
  168                 return (EPERM);
  169         if (namelen != 0)
  170                 return (EINVAL);
  171 
  172         spc = "";
  173         error = 0;
  174         needed = 0;
  175         left = *oldlenp;
  176 
  177         /* XXX locking */
  178 
  179         for (tc = timecounters; error == 0 && tc != NULL; tc = tc->tc_next) {
  180                 if (where == NULL) {
  181                         needed += sizeof(buf);  /* be conservative */
  182                 } else {
  183                         slen = snprintf(buf, sizeof(buf), "%s%s(q=%d, f=%" PRId64
  184                                         " Hz)", spc, tc->tc_name, tc->tc_quality,
  185                                         tc->tc_frequency);
  186                         if (left < slen + 1)
  187                                 break;
  188                         /* XXX use sysctl_copyout? (from sysctl_hw_disknames) */
  189                         error = copyout(buf, where, slen + 1);
  190                         spc = " ";
  191                         where += slen;
  192                         needed += slen;
  193                         left -= slen;
  194                 }
  195         }
  196 
  197         /* XXX unlock */
  198 
  199         *oldlenp = needed;
  200         return (error);
  201 }
  202 
  203 SYSCTL_SETUP(sysctl_timecounter_setup, "sysctl timecounter setup")
  204 {
  205         const struct sysctlnode *node;
  206 
  207         sysctl_createv(clog, 0, NULL, &node,
  208                        CTLFLAG_PERMANENT,
  209                        CTLTYPE_NODE, "timecounter",
  210                        SYSCTL_DESCR("time counter information"),
  211                        NULL, 0, NULL, 0,
  212                        CTL_KERN, CTL_CREATE, CTL_EOL);
  213 
  214         if (node != NULL) {
  215                 sysctl_createv(clog, 0, NULL, NULL,
  216                                CTLFLAG_PERMANENT,
  217                                CTLTYPE_STRING, "choice",
  218                                SYSCTL_DESCR("available counters"),
  219                                sysctl_kern_timecounter_choice, 0, NULL, 0,
  220                                CTL_KERN, node->sysctl_num, CTL_CREATE, CTL_EOL);
  221 
  222                 sysctl_createv(clog, 0, NULL, NULL,
  223                                CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  224                                CTLTYPE_STRING, "hardware",
  225                                SYSCTL_DESCR("currently active time counter"),
  226                                sysctl_kern_timecounter_hardware, 0, NULL, MAX_TCNAMELEN,
  227                                CTL_KERN, node->sysctl_num, CTL_CREATE, CTL_EOL);
  228 
  229                 sysctl_createv(clog, 0, NULL, NULL,
  230                                CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  231                                CTLTYPE_INT, "timestepwarnings",
  232                                SYSCTL_DESCR("log time steps"),
  233                                NULL, 0, &timestepwarnings, 0,
  234                                CTL_KERN, node->sysctl_num, CTL_CREATE, CTL_EOL);
  235         }
  236 }
  237 
  238 #define TC_STATS(name)                                                  \
  239 static struct evcnt n##name =                                           \
  240     EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "timecounter", #name);     \
  241 EVCNT_ATTACH_STATIC(n##name)
  242 
  243 TC_STATS(binuptime);    TC_STATS(nanouptime);    TC_STATS(microuptime);
  244 TC_STATS(bintime);      TC_STATS(nanotime);      TC_STATS(microtime);
  245 TC_STATS(getbinuptime); TC_STATS(getnanouptime); TC_STATS(getmicrouptime);
  246 TC_STATS(getbintime);   TC_STATS(getnanotime);   TC_STATS(getmicrotime);
  247 TC_STATS(setclock);
  248 
  249 #undef TC_STATS
  250 
  251 static void tc_windup(void);
  252 
  253 /*
  254  * Return the difference between the timehands' counter value now and what
  255  * was when we copied it to the timehands' offset_count.
  256  */
  257 static __inline u_int
  258 tc_delta(struct timehands *th)
  259 {
  260         struct timecounter *tc;
  261 
  262         tc = th->th_counter;
  263         return ((tc->tc_get_timecount(tc) - 
  264                  th->th_offset_count) & tc->tc_counter_mask);
  265 }
  266 
  267 /*
  268  * Functions for reading the time.  We have to loop until we are sure that
  269  * the timehands that we operated on was not updated under our feet.  See
  270  * the comment in <sys/time.h> for a description of these 12 functions.
  271  */
  272 
  273 void
  274 binuptime(struct bintime *bt)
  275 {
  276         struct timehands *th;
  277         u_int gen;
  278 
  279         nbinuptime.ev_count++;
  280         do {
  281                 th = timehands;
  282                 gen = th->th_generation;
  283                 *bt = th->th_offset;
  284                 bintime_addx(bt, th->th_scale * tc_delta(th));
  285         } while (gen == 0 || gen != th->th_generation);
  286 }
  287 
  288 void
  289 nanouptime(struct timespec *tsp)
  290 {
  291         struct bintime bt;
  292 
  293         nnanouptime.ev_count++;
  294         binuptime(&bt);
  295         bintime2timespec(&bt, tsp);
  296 }
  297 
  298 void
  299 microuptime(struct timeval *tvp)
  300 {
  301         struct bintime bt;
  302 
  303         nmicrouptime.ev_count++;
  304         binuptime(&bt);
  305         bintime2timeval(&bt, tvp);
  306 }
  307 
  308 void
  309 bintime(struct bintime *bt)
  310 {
  311 
  312         nbintime.ev_count++;
  313         binuptime(bt);
  314         bintime_add(bt, &timebasebin);
  315 }
  316 
  317 void
  318 nanotime(struct timespec *tsp)
  319 {
  320         struct bintime bt;
  321 
  322         nnanotime.ev_count++;
  323         bintime(&bt);
  324         bintime2timespec(&bt, tsp);
  325 }
  326 
  327 void
  328 microtime(struct timeval *tvp)
  329 {
  330         struct bintime bt;
  331 
  332         nmicrotime.ev_count++;
  333         bintime(&bt);
  334         bintime2timeval(&bt, tvp);
  335 }
  336 
  337 void
  338 getbinuptime(struct bintime *bt)
  339 {
  340         struct timehands *th;
  341         u_int gen;
  342 
  343         ngetbinuptime.ev_count++;
  344         do {
  345                 th = timehands;
  346                 gen = th->th_generation;
  347                 *bt = th->th_offset;
  348         } while (gen == 0 || gen != th->th_generation);
  349 }
  350 
  351 void
  352 getnanouptime(struct timespec *tsp)
  353 {
  354         struct timehands *th;
  355         u_int gen;
  356 
  357         ngetnanouptime.ev_count++;
  358         do {
  359                 th = timehands;
  360                 gen = th->th_generation;
  361                 bintime2timespec(&th->th_offset, tsp);
  362         } while (gen == 0 || gen != th->th_generation);
  363 }
  364 
  365 void
  366 getmicrouptime(struct timeval *tvp)
  367 {
  368         struct timehands *th;
  369         u_int gen;
  370 
  371         ngetmicrouptime.ev_count++;
  372         do {
  373                 th = timehands;
  374                 gen = th->th_generation;
  375                 bintime2timeval(&th->th_offset, tvp);
  376         } while (gen == 0 || gen != th->th_generation);
  377 }
  378 
  379 void
  380 getbintime(struct bintime *bt)
  381 {
  382         struct timehands *th;
  383         u_int gen;
  384 
  385         ngetbintime.ev_count++;
  386         do {
  387                 th = timehands;
  388                 gen = th->th_generation;
  389                 *bt = th->th_offset;
  390         } while (gen == 0 || gen != th->th_generation);
  391         bintime_add(bt, &timebasebin);
  392 }
  393 
  394 void
  395 getnanotime(struct timespec *tsp)
  396 {
  397         struct timehands *th;
  398         u_int gen;
  399 
  400         ngetnanotime.ev_count++;
  401         do {
  402                 th = timehands;
  403                 gen = th->th_generation;
  404                 *tsp = th->th_nanotime;
  405         } while (gen == 0 || gen != th->th_generation);
  406 }
  407 
  408 void
  409 getmicrotime(struct timeval *tvp)
  410 {
  411         struct timehands *th;
  412         u_int gen;
  413 
  414         ngetmicrotime.ev_count++;
  415         do {
  416                 th = timehands;
  417                 gen = th->th_generation;
  418                 *tvp = th->th_microtime;
  419         } while (gen == 0 || gen != th->th_generation);
  420 }
  421 
  422 /*
  423  * Initialize a new timecounter and possibly use it.
  424  */
  425 void
  426 tc_init(struct timecounter *tc)
  427 {
  428         u_int u;
  429         int s;
  430 
  431         u = tc->tc_frequency / tc->tc_counter_mask;
  432         /* XXX: We need some margin here, 10% is a guess */
  433         u *= 11;
  434         u /= 10;
  435         if (u > hz && tc->tc_quality >= 0) {
  436                 tc->tc_quality = -2000;
  437                 if (bootverbose) {
  438                         printf("timecounter: Timecounter \"%s\" frequency %ju Hz",
  439                             tc->tc_name, (uintmax_t)tc->tc_frequency);
  440                         printf(" -- Insufficient hz, needs at least %u\n", u);
  441                 }
  442         } else if (tc->tc_quality >= 0 || bootverbose) {
  443                 printf("timecounter: Timecounter \"%s\" frequency %ju Hz quality %d\n",
  444                     tc->tc_name, (uintmax_t)tc->tc_frequency,
  445                     tc->tc_quality);
  446         }
  447 
  448         s = splclock();
  449 
  450         tc->tc_next = timecounters;
  451         timecounters = tc;
  452         /*
  453          * Never automatically use a timecounter with negative quality.
  454          * Even though we run on the dummy counter, switching here may be
  455          * worse since this timecounter may not be monotonous.
  456          */
  457         if (tc->tc_quality < 0)
  458                 goto out;
  459         if (tc->tc_quality < timecounter->tc_quality)
  460                 goto out;
  461         if (tc->tc_quality == timecounter->tc_quality &&
  462             tc->tc_frequency < timecounter->tc_frequency)
  463                 goto out;
  464         (void)tc->tc_get_timecount(tc);
  465         (void)tc->tc_get_timecount(tc);
  466         timecounter = tc;
  467         tc_windup();
  468 
  469  out:
  470         splx(s);
  471 }
  472 
  473 /* Report the frequency of the current timecounter. */
  474 u_int64_t
  475 tc_getfrequency(void)
  476 {
  477 
  478         return (timehands->th_counter->tc_frequency);
  479 }
  480 
  481 /*
  482  * Step our concept of UTC.  This is done by modifying our estimate of
  483  * when we booted.
  484  * XXX: not locked.
  485  */
  486 void
  487 tc_setclock(struct timespec *ts)
  488 {
  489         struct timespec ts2;
  490         struct bintime bt, bt2;
  491 
  492         nsetclock.ev_count++;
  493         binuptime(&bt2);
  494         timespec2bintime(ts, &bt);
  495         bintime_sub(&bt, &bt2);
  496         bintime_add(&bt2, &timebasebin);
  497         timebasebin = bt;
  498 
  499         /* XXX fiddle all the little crinkly bits around the fiords... */
  500         tc_windup();
  501         if (timestepwarnings) {
  502                 bintime2timespec(&bt2, &ts2);
  503                 log(LOG_INFO, "Time stepped from %jd.%09ld to %jd.%09ld\n",
  504                     (intmax_t)ts2.tv_sec, ts2.tv_nsec,
  505                     (intmax_t)ts->tv_sec, ts->tv_nsec);
  506         }
  507 }
  508 
  509 /*
  510  * Initialize the next struct timehands in the ring and make
  511  * it the active timehands.  Along the way we might switch to a different
  512  * timecounter and/or do seconds processing in NTP.  Slightly magic.
  513  */
  514 static void
  515 tc_windup(void)
  516 {
  517         struct bintime bt;
  518         struct timehands *th, *tho;
  519         u_int64_t scale;
  520         u_int delta, ncount, ogen;
  521         int i, s_update;
  522         time_t t;
  523 
  524         s_update = 0;
  525         /*
  526          * Make the next timehands a copy of the current one, but do not
  527          * overwrite the generation or next pointer.  While we update
  528          * the contents, the generation must be zero.
  529          */
  530         tho = timehands;
  531         th = tho->th_next;
  532         ogen = th->th_generation;
  533         th->th_generation = 0;
  534         bcopy(tho, th, offsetof(struct timehands, th_generation));
  535 
  536         /*
  537          * Capture a timecounter delta on the current timecounter and if
  538          * changing timecounters, a counter value from the new timecounter.
  539          * Update the offset fields accordingly.
  540          */
  541         delta = tc_delta(th);
  542         if (th->th_counter != timecounter)
  543                 ncount = timecounter->tc_get_timecount(timecounter);
  544         else
  545                 ncount = 0;
  546         th->th_offset_count += delta;
  547         th->th_offset_count &= th->th_counter->tc_counter_mask;
  548         bintime_addx(&th->th_offset, th->th_scale * delta);
  549 
  550         /*
  551          * Hardware latching timecounters may not generate interrupts on
  552          * PPS events, so instead we poll them.  There is a finite risk that
  553          * the hardware might capture a count which is later than the one we
  554          * got above, and therefore possibly in the next NTP second which might
  555          * have a different rate than the current NTP second.  It doesn't
  556          * matter in practice.
  557          */
  558         if (tho->th_counter->tc_poll_pps)
  559                 tho->th_counter->tc_poll_pps(tho->th_counter);
  560 
  561         /*
  562          * Deal with NTP second processing.  The for loop normally
  563          * iterates at most once, but in extreme situations it might
  564          * keep NTP sane if timeouts are not run for several seconds.
  565          * At boot, the time step can be large when the TOD hardware
  566          * has been read, so on really large steps, we call
  567          * ntp_update_second only twice.  We need to call it twice in
  568          * case we missed a leap second.
  569          * If NTP is not compiled in ntp_update_second still calculates
  570          * the adjustment resulting from adjtime() calls.
  571          */
  572         bt = th->th_offset;
  573         bintime_add(&bt, &timebasebin);
  574         i = bt.sec - tho->th_microtime.tv_sec;
  575         if (i > LARGE_STEP)
  576                 i = 2;
  577         for (; i > 0; i--) {
  578                 t = bt.sec;
  579                 ntp_update_second(&th->th_adjustment, &bt.sec);
  580                 s_update = 1;
  581                 if (bt.sec != t)
  582                         timebasebin.sec += bt.sec - t;
  583         }
  584 
  585         /* Update the UTC timestamps used by the get*() functions. */
  586         /* XXX shouldn't do this here.  Should force non-`get' versions. */
  587         bintime2timeval(&bt, &th->th_microtime);
  588         bintime2timespec(&bt, &th->th_nanotime);
  589 
  590         /* Now is a good time to change timecounters. */
  591         if (th->th_counter != timecounter) {
  592                 th->th_counter = timecounter;
  593                 th->th_offset_count = ncount;
  594                 s_update = 1;
  595         }
  596 
  597         /*-
  598          * Recalculate the scaling factor.  We want the number of 1/2^64
  599          * fractions of a second per period of the hardware counter, taking
  600          * into account the th_adjustment factor which the NTP PLL/adjtime(2)
  601          * processing provides us with.
  602          *
  603          * The th_adjustment is nanoseconds per second with 32 bit binary
  604          * fraction and we want 64 bit binary fraction of second:
  605          *
  606          *       x = a * 2^32 / 10^9 = a * 4.294967296
  607          *
  608          * The range of th_adjustment is +/- 5000PPM so inside a 64bit int
  609          * we can only multiply by about 850 without overflowing, but that
  610          * leaves suitably precise fractions for multiply before divide.
  611          *
  612          * Divide before multiply with a fraction of 2199/512 results in a
  613          * systematic undercompensation of 10PPM of th_adjustment.  On a
  614          * 5000PPM adjustment this is a 0.05PPM error.  This is acceptable.
  615          *
  616          * We happily sacrifice the lowest of the 64 bits of our result
  617          * to the goddess of code clarity.
  618          *
  619          */
  620         if (s_update) {
  621                 scale = (u_int64_t)1 << 63;
  622                 scale += (th->th_adjustment / 1024) * 2199;
  623                 scale /= th->th_counter->tc_frequency;
  624                 th->th_scale = scale * 2;
  625         }
  626         /*
  627          * Now that the struct timehands is again consistent, set the new
  628          * generation number, making sure to not make it zero.
  629          */
  630         if (++ogen == 0)
  631                 ogen = 1;
  632         th->th_generation = ogen;
  633 
  634         /* Go live with the new struct timehands. */
  635         time_second = th->th_microtime.tv_sec;
  636         time_uptime = th->th_offset.sec;
  637         timehands = th;
  638 }
  639 
  640 #ifdef __FreeBSD__
  641 /* Report or change the active timecounter hardware. */
  642 static int
  643 sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS)
  644 {
  645         char newname[32];
  646         struct timecounter *newtc, *tc;
  647         int error;
  648 
  649         tc = timecounter;
  650         strlcpy(newname, tc->tc_name, sizeof(newname));
  651 
  652         error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req);
  653         if (error != 0 || req->newptr == NULL ||
  654             strcmp(newname, tc->tc_name) == 0)
  655                 return (error);
  656 
  657         for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) {
  658                 if (strcmp(newname, newtc->tc_name) != 0)
  659                         continue;
  660 
  661                 /* Warm up new timecounter. */
  662                 (void)newtc->tc_get_timecount(newtc);
  663                 (void)newtc->tc_get_timecount(newtc);
  664 
  665                 timecounter = newtc;
  666                 return (0);
  667         }
  668         return (EINVAL);
  669 }
  670 
  671 SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW,
  672     0, 0, sysctl_kern_timecounter_hardware, "A", "");
  673 
  674 
  675 /* Report or change the active timecounter hardware. */
  676 static int
  677 sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS)
  678 {
  679         char buf[32], *spc;
  680         struct timecounter *tc;
  681         int error;
  682 
  683         spc = "";
  684         error = 0;
  685         for (tc = timecounters; error == 0 && tc != NULL; tc = tc->tc_next) {
  686                 sprintf(buf, "%s%s(%d)",
  687                     spc, tc->tc_name, tc->tc_quality);
  688                 error = SYSCTL_OUT(req, buf, strlen(buf));
  689                 spc = " ";
  690         }
  691         return (error);
  692 }
  693 
  694 SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD,
  695     0, 0, sysctl_kern_timecounter_choice, "A", "");
  696 #endif /* __FreeBSD__ */
  697 
  698 /*
  699  * RFC 2783 PPS-API implementation.
  700  */
  701 
  702 int
  703 pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps)
  704 {
  705         pps_params_t *app;
  706         pps_info_t *pipi;
  707 #ifdef PPS_SYNC
  708         int *epi;
  709 #endif
  710 
  711         KASSERT(pps != NULL); /* XXX ("NULL pps pointer in pps_ioctl") */
  712         switch (cmd) {
  713         case PPS_IOC_CREATE:
  714                 return (0);
  715         case PPS_IOC_DESTROY:
  716                 return (0);
  717         case PPS_IOC_SETPARAMS:
  718                 app = (pps_params_t *)data;
  719                 if (app->mode & ~pps->ppscap)
  720                         return (EINVAL);
  721                 pps->ppsparam = *app;
  722                 return (0);
  723         case PPS_IOC_GETPARAMS:
  724                 app = (pps_params_t *)data;
  725                 *app = pps->ppsparam;
  726                 app->api_version = PPS_API_VERS_1;
  727                 return (0);
  728         case PPS_IOC_GETCAP:
  729                 *(int*)data = pps->ppscap;
  730                 return (0);
  731         case PPS_IOC_FETCH:
  732                 pipi = (pps_info_t *)data;
  733                 pps->ppsinfo.current_mode = pps->ppsparam.mode;
  734                 *pipi = pps->ppsinfo;
  735                 return (0);
  736         case PPS_IOC_KCBIND:
  737 #ifdef PPS_SYNC
  738                 epi = (int *)data;
  739                 /* XXX Only root should be able to do this */
  740                 if (*epi & ~pps->ppscap)
  741                         return (EINVAL);
  742                 pps->kcmode = *epi;
  743                 return (0);
  744 #else
  745                 return (EOPNOTSUPP);
  746 #endif
  747         default:
  748                 return (EPASSTHROUGH);
  749         }
  750 }
  751 
  752 void
  753 pps_init(struct pps_state *pps)
  754 {
  755         pps->ppscap |= PPS_TSFMT_TSPEC;
  756         if (pps->ppscap & PPS_CAPTUREASSERT)
  757                 pps->ppscap |= PPS_OFFSETASSERT;
  758         if (pps->ppscap & PPS_CAPTURECLEAR)
  759                 pps->ppscap |= PPS_OFFSETCLEAR;
  760 }
  761 
  762 void
  763 pps_capture(struct pps_state *pps)
  764 {
  765         struct timehands *th;
  766 
  767         KASSERT(pps != NULL); /* XXX ("NULL pps pointer in pps_capture") */
  768         th = timehands;
  769         pps->capgen = th->th_generation;
  770         pps->capth = th;
  771         pps->capcount = th->th_counter->tc_get_timecount(th->th_counter);
  772         if (pps->capgen != th->th_generation)
  773                 pps->capgen = 0;
  774 }
  775 
  776 void
  777 pps_event(struct pps_state *pps, int event)
  778 {
  779         struct bintime bt;
  780         struct timespec ts, *tsp, *osp;
  781         u_int tcount, *pcount;
  782         int foff, fhard;
  783         pps_seq_t *pseq;
  784 
  785         KASSERT(pps != NULL); /* XXX ("NULL pps pointer in pps_event") */
  786         /* If the timecounter was wound up underneath us, bail out. */
  787         if (pps->capgen == 0 || pps->capgen != pps->capth->th_generation)
  788                 return;
  789 
  790         /* Things would be easier with arrays. */
  791         if (event == PPS_CAPTUREASSERT) {
  792                 tsp = &pps->ppsinfo.assert_timestamp;
  793                 osp = &pps->ppsparam.assert_offset;
  794                 foff = pps->ppsparam.mode & PPS_OFFSETASSERT;
  795                 fhard = pps->kcmode & PPS_CAPTUREASSERT;
  796                 pcount = &pps->ppscount[0];
  797                 pseq = &pps->ppsinfo.assert_sequence;
  798         } else {
  799                 tsp = &pps->ppsinfo.clear_timestamp;
  800                 osp = &pps->ppsparam.clear_offset;
  801                 foff = pps->ppsparam.mode & PPS_OFFSETCLEAR;
  802                 fhard = pps->kcmode & PPS_CAPTURECLEAR;
  803                 pcount = &pps->ppscount[1];
  804                 pseq = &pps->ppsinfo.clear_sequence;
  805         }
  806 
  807         /*
  808          * If the timecounter changed, we cannot compare the count values, so
  809          * we have to drop the rest of the PPS-stuff until the next event.
  810          */
  811         if (pps->ppstc != pps->capth->th_counter) {
  812                 pps->ppstc = pps->capth->th_counter;
  813                 *pcount = pps->capcount;
  814                 pps->ppscount[2] = pps->capcount;
  815                 return;
  816         }
  817 
  818         /* Convert the count to a timespec. */
  819         tcount = pps->capcount - pps->capth->th_offset_count;
  820         tcount &= pps->capth->th_counter->tc_counter_mask;
  821         bt = pps->capth->th_offset;
  822         bintime_addx(&bt, pps->capth->th_scale * tcount);
  823         bintime_add(&bt, &timebasebin);
  824         bintime2timespec(&bt, &ts);
  825 
  826         /* If the timecounter was wound up underneath us, bail out. */
  827         if (pps->capgen != pps->capth->th_generation)
  828                 return;
  829 
  830         *pcount = pps->capcount;
  831         (*pseq)++;
  832         *tsp = ts;
  833 
  834         if (foff) {
  835                 timespecadd(tsp, osp, tsp);
  836                 if (tsp->tv_nsec < 0) {
  837                         tsp->tv_nsec += 1000000000;
  838                         tsp->tv_sec -= 1;
  839                 }
  840         }
  841 #ifdef PPS_SYNC
  842         if (fhard) {
  843                 u_int64_t scale;
  844 
  845                 /*
  846                  * Feed the NTP PLL/FLL.
  847                  * The FLL wants to know how many (hardware) nanoseconds
  848                  * elapsed since the previous event.
  849                  */
  850                 tcount = pps->capcount - pps->ppscount[2];
  851                 pps->ppscount[2] = pps->capcount;
  852                 tcount &= pps->capth->th_counter->tc_counter_mask;
  853                 scale = (u_int64_t)1 << 63;
  854                 scale /= pps->capth->th_counter->tc_frequency;
  855                 scale *= 2;
  856                 bt.sec = 0;
  857                 bt.frac = 0;
  858                 bintime_addx(&bt, scale * tcount);
  859                 bintime2timespec(&bt, &ts);
  860                 hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec);
  861         }
  862 #endif
  863 }
  864 
  865 /*
  866  * Timecounters need to be updated every so often to prevent the hardware
  867  * counter from overflowing.  Updating also recalculates the cached values
  868  * used by the get*() family of functions, so their precision depends on
  869  * the update frequency.
  870  */
  871 
  872 static int tc_tick;
  873 #ifdef __FreeBSD__
  874 SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tc_tick, 0, "");
  875 #endif /* __FreeBSD__ */
  876 
  877 void
  878 tc_ticktock(void)
  879 {
  880         static int count;
  881 
  882         if (++count < tc_tick)
  883                 return;
  884         count = 0;
  885         tc_windup();
  886 }
  887 
  888 void
  889 inittimecounter(void)
  890 {
  891         u_int p;
  892 
  893         /*
  894          * Set the initial timeout to
  895          * max(1, <approx. number of hardclock ticks in a millisecond>).
  896          * People should probably not use the sysctl to set the timeout
  897          * to smaller than its inital value, since that value is the
  898          * smallest reasonable one.  If they want better timestamps they
  899          * should use the non-"get"* functions.
  900          */
  901         if (hz > 1000)
  902                 tc_tick = (hz + 500) / 1000;
  903         else
  904                 tc_tick = 1;
  905         p = (tc_tick * 1000000) / hz;
  906         printf("timecounter: Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000);
  907 
  908         /* warm up new timecounter (again) and get rolling. */
  909         (void)timecounter->tc_get_timecount(timecounter);
  910         (void)timecounter->tc_get_timecount(timecounter);
  911 }
  912 
  913 #ifdef __FreeBSD__
  914 SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL)
  915 #endif /* __FreeBSD__ */
  916 #endif /* __HAVE_TIMECOUNTER */

Cache object: 366c8747b3a095391165f673172671db


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