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/i386/xen/clock.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) 1990 The Regents of the University of California.
    3  * All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * William Jolitz and Don Ahn.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   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  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by the University of
   19  *      California, Berkeley and its contributors.
   20  * 4. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      from: @(#)clock.c       7.2 (Berkeley) 5/12/91
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __FBSDID("$FreeBSD: releng/10.4/sys/i386/xen/clock.c 255046 2013-08-29 23:11:58Z gibbs $");
   41 
   42 /* #define DELAYDEBUG */
   43 /*
   44  * Routines to handle clock hardware.
   45  */
   46 
   47 #include "opt_ddb.h"
   48 #include "opt_clock.h"
   49 
   50 #include <sys/param.h>
   51 #include <sys/systm.h>
   52 #include <sys/bus.h>
   53 #include <sys/clock.h>
   54 #include <sys/lock.h>
   55 #include <sys/mutex.h>
   56 #include <sys/proc.h>
   57 #include <sys/time.h>
   58 #include <sys/timeet.h>
   59 #include <sys/timetc.h>
   60 #include <sys/kernel.h>
   61 #include <sys/limits.h>
   62 #include <sys/sysctl.h>
   63 #include <sys/cons.h>
   64 #include <sys/power.h>
   65 
   66 #include <machine/clock.h>
   67 #include <machine/cputypes.h>
   68 #include <machine/frame.h>
   69 #include <machine/intr_machdep.h>
   70 #include <machine/md_var.h>
   71 #include <machine/psl.h>
   72 #if defined(SMP)
   73 #include <machine/smp.h>
   74 #endif
   75 #include <machine/specialreg.h>
   76 #include <machine/timerreg.h>
   77 
   78 #include <x86/isa/icu.h>
   79 #include <x86/isa/isa.h>
   80 #include <isa/rtc.h>
   81 
   82 #include <vm/vm.h>
   83 #include <vm/pmap.h>
   84 #include <machine/pmap.h>
   85 #include <xen/hypervisor.h>
   86 #include <xen/xen-os.h>
   87 #include <machine/xen/xenfunc.h>
   88 #include <xen/interface/vcpu.h>
   89 #include <machine/cpu.h>
   90 #include <xen/xen_intr.h>
   91 
   92 /*
   93  * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
   94  * can use a simple formula for leap years.
   95  */
   96 #define LEAPYEAR(y)     (!((y) % 4))
   97 #define DAYSPERYEAR     (28+30*4+31*7)
   98 
   99 #ifndef TIMER_FREQ
  100 #define TIMER_FREQ      1193182
  101 #endif
  102 
  103 #ifdef CYC2NS_SCALE_FACTOR
  104 #undef  CYC2NS_SCALE_FACTOR
  105 #endif
  106 #define CYC2NS_SCALE_FACTOR     10
  107 
  108 /* Values for timerX_state: */
  109 #define RELEASED        0
  110 #define RELEASE_PENDING 1
  111 #define ACQUIRED        2
  112 #define ACQUIRE_PENDING 3
  113 
  114 struct mtx clock_lock;
  115 #define RTC_LOCK_INIT                                                   \
  116         mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE)
  117 #define RTC_LOCK        mtx_lock_spin(&clock_lock)
  118 #define RTC_UNLOCK      mtx_unlock_spin(&clock_lock)
  119 #define NS_PER_TICK     (1000000000ULL/hz)
  120 
  121 int adjkerntz;          /* local offset from GMT in seconds */
  122 int clkintr_pending;
  123 int pscnt = 1;
  124 int psdiv = 1;
  125 int wall_cmos_clock;
  126 u_int timer_freq = TIMER_FREQ;
  127 static u_long cyc2ns_scale; 
  128 static uint64_t processed_system_time;  /* stime (ns) at last processing. */
  129 
  130 extern volatile uint64_t xen_timer_last_time;
  131 
  132 #define do_div(n,base) ({ \
  133         unsigned long __upper, __low, __high, __mod, __base; \
  134         __base = (base); \
  135         __asm("":"=a" (__low), "=d" (__high):"A" (n)); \
  136         __upper = __high; \
  137         if (__high) { \
  138                 __upper = __high % (__base); \
  139                 __high = __high / (__base); \
  140         } \
  141         __asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "" (__low), "1" (__upper)); \
  142         __asm("":"=A" (n):"a" (__low),"d" (__high)); \
  143         __mod; \
  144 })
  145 
  146 
  147 /* convert from cycles(64bits) => nanoseconds (64bits)
  148  *  basic equation:
  149  *              ns = cycles / (freq / ns_per_sec)
  150  *              ns = cycles * (ns_per_sec / freq)
  151  *              ns = cycles * (10^9 / (cpu_mhz * 10^6))
  152  *              ns = cycles * (10^3 / cpu_mhz)
  153  *
  154  *      Then we use scaling math (suggested by george@mvista.com) to get:
  155  *              ns = cycles * (10^3 * SC / cpu_mhz) / SC
  156  *              ns = cycles * cyc2ns_scale / SC
  157  *
  158  *      And since SC is a constant power of two, we can convert the div
  159  *  into a shift.   
  160  *                      -johnstul@us.ibm.com "math is hard, lets go shopping!"
  161  */
  162 static inline void set_cyc2ns_scale(unsigned long cpu_mhz)
  163 {
  164         cyc2ns_scale = (1000 << CYC2NS_SCALE_FACTOR)/cpu_mhz;
  165 }
  166 
  167 static inline unsigned long long cycles_2_ns(unsigned long long cyc)
  168 {
  169         return ((cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR);
  170 }
  171 
  172 static uint32_t
  173 getit(void)
  174 {
  175         return (xen_timer_last_time);
  176 }
  177 
  178 
  179 /*
  180  * XXX: timer needs more SMP work.
  181  */
  182 void
  183 i8254_init(void)
  184 {
  185 
  186         RTC_LOCK_INIT;
  187 }
  188 
  189 /*
  190  * Wait "n" microseconds.
  191  * Relies on timer 1 counting down from (timer_freq / hz)
  192  * Note: timer had better have been programmed before this is first used!
  193  */
  194 void
  195 DELAY(int n)
  196 {
  197         int delta, ticks_left;
  198         uint32_t tick, prev_tick;
  199 #ifdef DELAYDEBUG
  200         int getit_calls = 1;
  201         int n1;
  202         static int state = 0;
  203 
  204         if (state == 0) {
  205                 state = 1;
  206                 for (n1 = 1; n1 <= 10000000; n1 *= 10)
  207                         DELAY(n1);
  208                 state = 2;
  209         }
  210         if (state == 1)
  211                 printf("DELAY(%d)...", n);
  212 #endif
  213         /*
  214          * Read the counter first, so that the rest of the setup overhead is
  215          * counted.  Guess the initial overhead is 20 usec (on most systems it
  216          * takes about 1.5 usec for each of the i/o's in getit().  The loop
  217          * takes about 6 usec on a 486/33 and 13 usec on a 386/20.  The
  218          * multiplications and divisions to scale the count take a while).
  219          *
  220          * However, if ddb is active then use a fake counter since reading
  221          * the i8254 counter involves acquiring a lock.  ddb must not go
  222          * locking for many reasons, but it calls here for at least atkbd
  223          * input.
  224          */
  225         prev_tick = getit();
  226 
  227         n -= 0;                 /* XXX actually guess no initial overhead */
  228         /*
  229          * Calculate (n * (timer_freq / 1e6)) without using floating point
  230          * and without any avoidable overflows.
  231          */
  232         if (n <= 0)
  233                 ticks_left = 0;
  234         else if (n < 256)
  235                 /*
  236                  * Use fixed point to avoid a slow division by 1000000.
  237                  * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
  238                  * 2^15 is the first power of 2 that gives exact results
  239                  * for n between 0 and 256.
  240                  */
  241                 ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15;
  242         else
  243                 /*
  244                  * Don't bother using fixed point, although gcc-2.7.2
  245                  * generates particularly poor code for the long long
  246                  * division, since even the slow way will complete long
  247                  * before the delay is up (unless we're interrupted).
  248                  */
  249                 ticks_left = ((u_int)n * (long long)timer_freq + 999999)
  250                         / 1000000;
  251 
  252         while (ticks_left > 0) {
  253                 tick = getit();
  254 #ifdef DELAYDEBUG
  255                 ++getit_calls;
  256 #endif
  257                 delta = tick - prev_tick;
  258                 prev_tick = tick;
  259                 if (delta < 0) {
  260                         /*
  261                          * Guard against timer0_max_count being wrong.
  262                          * This shouldn't happen in normal operation,
  263                          * but it may happen if set_timer_freq() is
  264                          * traced.
  265                          */
  266                         /* delta += timer0_max_count; ??? */
  267                         if (delta < 0)
  268                                 delta = 0;
  269                 }
  270                 ticks_left -= delta;
  271         }
  272 #ifdef DELAYDEBUG
  273         if (state == 1)
  274                 printf(" %d calls to getit() at %d usec each\n",
  275                        getit_calls, (n + 5) / getit_calls);
  276 #endif
  277 }
  278 
  279 void
  280 startrtclock()
  281 {
  282         uint64_t __cpu_khz;
  283         uint32_t cpu_khz;
  284         struct vcpu_time_info *info;
  285 
  286         __cpu_khz = 1000000ULL << 32;
  287         info = &HYPERVISOR_shared_info->vcpu_info[0].time;
  288 
  289         (void)do_div(__cpu_khz, info->tsc_to_system_mul);
  290         if ( info->tsc_shift < 0 )
  291                 cpu_khz = __cpu_khz << -info->tsc_shift;
  292         else
  293                 cpu_khz = __cpu_khz >> info->tsc_shift;
  294 
  295         printf("Xen reported: %u.%03u MHz processor.\n", 
  296                cpu_khz / 1000, cpu_khz % 1000);
  297 
  298         /* (10^6 * 2^32) / cpu_hz = (10^3 * 2^32) / cpu_khz =
  299            (2^32 * 1 / (clocks/us)) */
  300 
  301         set_cyc2ns_scale(cpu_khz/1000);
  302         tsc_freq = cpu_khz * 1000;
  303 }
  304 
  305 /*
  306  * RTC support routines
  307  */
  308 
  309 
  310 static __inline int
  311 readrtc(int port)
  312 {
  313         return(bcd2bin(rtcin(port)));
  314 }
  315 
  316 
  317 #ifdef XEN_PRIVILEGED_GUEST
  318 
  319 /*
  320  * Initialize the time of day register, based on the time base which is, e.g.
  321  * from a filesystem.
  322  */
  323 static void
  324 domu_inittodr(time_t base)
  325 {
  326         unsigned long   sec;
  327         int             s, y;
  328         struct timespec ts;
  329 
  330         update_wallclock();
  331         add_uptime_to_wallclock();
  332         
  333         RTC_LOCK;
  334         
  335         if (base) {
  336                 ts.tv_sec = base;
  337                 ts.tv_nsec = 0;
  338                 tc_setclock(&ts);
  339         }
  340 
  341         sec += tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
  342 
  343         y = time_second - shadow_tv.tv_sec;
  344         if (y <= -2 || y >= 2) {
  345                 /* badly off, adjust it */
  346                 tc_setclock(&shadow_tv);
  347         }
  348         RTC_UNLOCK;
  349 }
  350 
  351 /*
  352  * Write system time back to RTC.  
  353  */
  354 static void
  355 domu_resettodr(void)
  356 {
  357         unsigned long tm;
  358         int s;
  359         dom0_op_t op;
  360         struct shadow_time_info *shadow;
  361         struct pcpu *pc;
  362 
  363         pc = pcpu_find(smp_processor_id());
  364         shadow = &pc->pc_shadow_time;
  365         if (xen_disable_rtc_set)
  366                 return;
  367         
  368         s = splclock();
  369         tm = time_second;
  370         splx(s);
  371         
  372         tm -= tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
  373         
  374         if ((xen_start_info->flags & SIF_INITDOMAIN) &&
  375             !independent_wallclock)
  376         {
  377                 op.cmd = DOM0_SETTIME;
  378                 op.u.settime.secs        = tm;
  379                 op.u.settime.nsecs       = 0;
  380                 op.u.settime.system_time = shadow->system_timestamp;
  381                 HYPERVISOR_dom0_op(&op);
  382                 update_wallclock();
  383                 add_uptime_to_wallclock();
  384         } else if (independent_wallclock) {
  385                 /* notyet */
  386                 ;
  387         }               
  388 }
  389 
  390 /*
  391  * Initialize the time of day register, based on the time base which is, e.g.
  392  * from a filesystem.
  393  */
  394 void
  395 inittodr(time_t base)
  396 {
  397         unsigned long   sec, days;
  398         int             year, month;
  399         int             y, m, s;
  400         struct timespec ts;
  401 
  402         if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
  403                 domu_inittodr(base);
  404                 return;
  405         }
  406 
  407         if (base) {
  408                 s = splclock();
  409                 ts.tv_sec = base;
  410                 ts.tv_nsec = 0;
  411                 tc_setclock(&ts);
  412                 splx(s);
  413         }
  414 
  415         /* Look if we have a RTC present and the time is valid */
  416         if (!(rtcin(RTC_STATUSD) & RTCSD_PWR))
  417                 goto wrong_time;
  418 
  419         /* wait for time update to complete */
  420         /* If RTCSA_TUP is zero, we have at least 244us before next update */
  421         s = splhigh();
  422         while (rtcin(RTC_STATUSA) & RTCSA_TUP) {
  423                 splx(s);
  424                 s = splhigh();
  425         }
  426 
  427         days = 0;
  428 #ifdef USE_RTC_CENTURY
  429         year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100;
  430 #else
  431         year = readrtc(RTC_YEAR) + 1900;
  432         if (year < 1970)
  433                 year += 100;
  434 #endif
  435         if (year < 1970) {
  436                 splx(s);
  437                 goto wrong_time;
  438         }
  439         month = readrtc(RTC_MONTH);
  440         for (m = 1; m < month; m++)
  441                 days += daysinmonth[m-1];
  442         if ((month > 2) && LEAPYEAR(year))
  443                 days ++;
  444         days += readrtc(RTC_DAY) - 1;
  445         for (y = 1970; y < year; y++)
  446                 days += DAYSPERYEAR + LEAPYEAR(y);
  447         sec = ((( days * 24 +
  448                   readrtc(RTC_HRS)) * 60 +
  449                 readrtc(RTC_MIN)) * 60 +
  450                readrtc(RTC_SEC));
  451         /* sec now contains the number of seconds, since Jan 1 1970,
  452            in the local time zone */
  453 
  454         sec += tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
  455 
  456         y = time_second - sec;
  457         if (y <= -2 || y >= 2) {
  458                 /* badly off, adjust it */
  459                 ts.tv_sec = sec;
  460                 ts.tv_nsec = 0;
  461                 tc_setclock(&ts);
  462         }
  463         splx(s);
  464         return;
  465 
  466  wrong_time:
  467         printf("Invalid time in real time clock.\n");
  468         printf("Check and reset the date immediately!\n");
  469 }
  470 
  471 
  472 /*
  473  * Write system time back to RTC
  474  */
  475 void
  476 resettodr()
  477 {
  478         unsigned long   tm;
  479         int             y, m, s;
  480 
  481         if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
  482                 domu_resettodr();
  483                 return;
  484         }
  485                
  486         if (xen_disable_rtc_set)
  487                 return;
  488 
  489         s = splclock();
  490         tm = time_second;
  491         splx(s);
  492 
  493         /* Disable RTC updates and interrupts. */
  494         writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR);
  495 
  496         /* Calculate local time to put in RTC */
  497 
  498         tm -= tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
  499 
  500         writertc(RTC_SEC, bin2bcd(tm%60)); tm /= 60;    /* Write back Seconds */
  501         writertc(RTC_MIN, bin2bcd(tm%60)); tm /= 60;    /* Write back Minutes */
  502         writertc(RTC_HRS, bin2bcd(tm%24)); tm /= 24;    /* Write back Hours   */
  503 
  504         /* We have now the days since 01-01-1970 in tm */
  505         writertc(RTC_WDAY, (tm + 4) % 7 + 1);           /* Write back Weekday */
  506         for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y);
  507              tm >= m;
  508              y++,      m = DAYSPERYEAR + LEAPYEAR(y))
  509                 tm -= m;
  510 
  511         /* Now we have the years in y and the day-of-the-year in tm */
  512         writertc(RTC_YEAR, bin2bcd(y%100));             /* Write back Year    */
  513 #ifdef USE_RTC_CENTURY
  514         writertc(RTC_CENTURY, bin2bcd(y/100));          /* ... and Century    */
  515 #endif
  516         for (m = 0; ; m++) {
  517                 int ml;
  518 
  519                 ml = daysinmonth[m];
  520                 if (m == 1 && LEAPYEAR(y))
  521                         ml++;
  522                 if (tm < ml)
  523                         break;
  524                 tm -= ml;
  525         }
  526 
  527         writertc(RTC_MONTH, bin2bcd(m + 1));            /* Write back Month   */
  528         writertc(RTC_DAY, bin2bcd(tm + 1));             /* Write back Month Day */
  529 
  530         /* Reenable RTC updates and interrupts. */
  531         writertc(RTC_STATUSB, RTCSB_24HR);
  532         rtcin(RTC_INTR);
  533 }
  534 #endif
  535 
  536 /*
  537  * Start clocks running.
  538  */
  539 void
  540 cpu_initclocks(void)
  541 {
  542         cpu_initclocks_bsp();
  543 }
  544 
  545 /* Return system time offset by ticks */
  546 uint64_t
  547 get_system_time(int ticks)
  548 {
  549     return (processed_system_time + (ticks * NS_PER_TICK));
  550 }
  551 
  552 int
  553 timer_spkr_acquire(void)
  554 {
  555 
  556         return (0);
  557 }
  558 
  559 int
  560 timer_spkr_release(void)
  561 {
  562 
  563         return (0);
  564 }
  565 
  566 void
  567 timer_spkr_setfreq(int freq)
  568 {
  569 
  570 }
  571 

Cache object: af6bbf20ef7420c1bbedb52b1588057e


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