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$");
   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 <xen/xen_intr.h>
   83 #include <vm/vm.h>
   84 #include <vm/pmap.h>
   85 #include <machine/pmap.h>
   86 #include <xen/hypervisor.h>
   87 #include <machine/xen/xen-os.h>
   88 #include <machine/xen/xenfunc.h>
   89 #include <xen/interface/vcpu.h>
   90 #include <machine/cpu.h>
   91 #include <machine/xen/xen_clock_util.h>
   92 
   93 /*
   94  * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
   95  * can use a simple formula for leap years.
   96  */
   97 #define LEAPYEAR(y)     (!((y) % 4))
   98 #define DAYSPERYEAR     (28+30*4+31*7)
   99 
  100 #ifndef TIMER_FREQ
  101 #define TIMER_FREQ      1193182
  102 #endif
  103 
  104 #ifdef CYC2NS_SCALE_FACTOR
  105 #undef  CYC2NS_SCALE_FACTOR
  106 #endif
  107 #define CYC2NS_SCALE_FACTOR     10
  108 
  109 /* Values for timerX_state: */
  110 #define RELEASED        0
  111 #define RELEASE_PENDING 1
  112 #define ACQUIRED        2
  113 #define ACQUIRE_PENDING 3
  114 
  115 struct mtx clock_lock;
  116 #define RTC_LOCK_INIT                                                   \
  117         mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE)
  118 #define RTC_LOCK        mtx_lock_spin(&clock_lock)
  119 #define RTC_UNLOCK      mtx_unlock_spin(&clock_lock)
  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 int independent_wallclock;
  128 static int xen_disable_rtc_set;
  129 static u_long cyc2ns_scale; 
  130 static struct timespec shadow_tv;
  131 static uint32_t shadow_tv_version;      /* XXX: lazy locking */
  132 static uint64_t processed_system_time;  /* stime (ns) at last processing. */
  133 
  134 static  const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
  135 
  136 SYSCTL_INT(_machdep, OID_AUTO, independent_wallclock,
  137     CTLFLAG_RW, &independent_wallclock, 0, "");
  138 SYSCTL_INT(_machdep, OID_AUTO, xen_disable_rtc_set,
  139     CTLFLAG_RW, &xen_disable_rtc_set, 1, "");
  140 
  141 
  142 #define do_div(n,base) ({ \
  143         unsigned long __upper, __low, __high, __mod, __base; \
  144         __base = (base); \
  145         __asm("":"=a" (__low), "=d" (__high):"A" (n)); \
  146         __upper = __high; \
  147         if (__high) { \
  148                 __upper = __high % (__base); \
  149                 __high = __high / (__base); \
  150         } \
  151         __asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "" (__low), "1" (__upper)); \
  152         __asm("":"=A" (n):"a" (__low),"d" (__high)); \
  153         __mod; \
  154 })
  155 
  156 
  157 #define NS_PER_TICK (1000000000ULL/hz)
  158 
  159 #define rdtscll(val) \
  160     __asm__ __volatile__("rdtsc" : "=A" (val))
  161 
  162 
  163 /* convert from cycles(64bits) => nanoseconds (64bits)
  164  *  basic equation:
  165  *              ns = cycles / (freq / ns_per_sec)
  166  *              ns = cycles * (ns_per_sec / freq)
  167  *              ns = cycles * (10^9 / (cpu_mhz * 10^6))
  168  *              ns = cycles * (10^3 / cpu_mhz)
  169  *
  170  *      Then we use scaling math (suggested by george@mvista.com) to get:
  171  *              ns = cycles * (10^3 * SC / cpu_mhz) / SC
  172  *              ns = cycles * cyc2ns_scale / SC
  173  *
  174  *      And since SC is a constant power of two, we can convert the div
  175  *  into a shift.   
  176  *                      -johnstul@us.ibm.com "math is hard, lets go shopping!"
  177  */
  178 static inline void set_cyc2ns_scale(unsigned long cpu_mhz)
  179 {
  180         cyc2ns_scale = (1000 << CYC2NS_SCALE_FACTOR)/cpu_mhz;
  181 }
  182 
  183 static inline unsigned long long cycles_2_ns(unsigned long long cyc)
  184 {
  185         return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
  186 }
  187 
  188 /*
  189  * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
  190  * yielding a 64-bit result.
  191  */
  192 static inline uint64_t 
  193 scale_delta(uint64_t delta, uint32_t mul_frac, int shift)
  194 {
  195         uint64_t product;
  196         uint32_t tmp1, tmp2;
  197 
  198         if ( shift < 0 )
  199                 delta >>= -shift;
  200         else
  201                 delta <<= shift;
  202 
  203         __asm__ (
  204                 "mul  %5       ; "
  205                 "mov  %4,%%eax ; "
  206                 "mov  %%edx,%4 ; "
  207                 "mul  %5       ; "
  208                 "xor  %5,%5    ; "
  209                 "add  %4,%%eax ; "
  210                 "adc  %5,%%edx ; "
  211                 : "=A" (product), "=r" (tmp1), "=r" (tmp2)
  212                 : "a" ((uint32_t)delta), "1" ((uint32_t)(delta >> 32)), "2" (mul_frac) );
  213 
  214         return product;
  215 }
  216 
  217 static uint64_t
  218 get_nsec_offset(struct shadow_time_info *shadow)
  219 {
  220         uint64_t now, delta;
  221         rdtscll(now);
  222         delta = now - shadow->tsc_timestamp;
  223         return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
  224 }
  225 
  226 static void update_wallclock(void)
  227 {
  228         shared_info_t *s = HYPERVISOR_shared_info;
  229 
  230         do {
  231                 shadow_tv_version = s->wc_version;
  232                 rmb();
  233                 shadow_tv.tv_sec  = s->wc_sec;
  234                 shadow_tv.tv_nsec = s->wc_nsec;
  235                 rmb();
  236         }
  237         while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version));
  238 
  239 }
  240 
  241 static void
  242 add_uptime_to_wallclock(void)
  243 {
  244         struct timespec ut;
  245 
  246         xen_fetch_uptime(&ut);
  247         timespecadd(&shadow_tv, &ut);
  248 }
  249 
  250 /*
  251  * Reads a consistent set of time-base values from Xen, into a shadow data
  252  * area. Must be called with the xtime_lock held for writing.
  253  */
  254 static void __get_time_values_from_xen(void)
  255 {
  256         shared_info_t           *s = HYPERVISOR_shared_info;
  257         struct vcpu_time_info   *src;
  258         struct shadow_time_info *dst;
  259         uint32_t pre_version, post_version;
  260 
  261         src = &s->vcpu_info[smp_processor_id()].time;
  262         dst = &per_cpu(shadow_time, smp_processor_id());
  263 
  264         spinlock_enter();
  265         do {
  266                 pre_version = dst->version = src->version;
  267                 rmb();
  268                 dst->tsc_timestamp     = src->tsc_timestamp;
  269                 dst->system_timestamp  = src->system_time;
  270                 dst->tsc_to_nsec_mul   = src->tsc_to_system_mul;
  271                 dst->tsc_shift         = src->tsc_shift;
  272                 rmb();
  273                 post_version = src->version;
  274         }
  275         while ((pre_version & 1) | (pre_version ^ post_version));
  276 
  277         dst->tsc_to_usec_mul = dst->tsc_to_nsec_mul / 1000;
  278         spinlock_exit();
  279 }
  280 
  281 
  282 static inline int time_values_up_to_date(int cpu)
  283 {
  284         struct vcpu_time_info   *src;
  285         struct shadow_time_info *dst;
  286 
  287         src = &HYPERVISOR_shared_info->vcpu_info[cpu].time; 
  288         dst = &per_cpu(shadow_time, cpu); 
  289 
  290         rmb();
  291         return (dst->version == src->version);
  292 }
  293 
  294 static  unsigned xen_get_timecount(struct timecounter *tc);
  295 
  296 static struct timecounter xen_timecounter = {
  297         xen_get_timecount,      /* get_timecount */
  298         0,                      /* no poll_pps */
  299         ~0u,                    /* counter_mask */
  300         0,                      /* frequency */
  301         "ixen",                 /* name */
  302         0                       /* quality */
  303 };
  304 
  305 static struct eventtimer xen_et;
  306 
  307 struct xen_et_state {
  308         int             mode;
  309 #define MODE_STOP       0
  310 #define MODE_PERIODIC   1
  311 #define MODE_ONESHOT    2
  312         int64_t         period;
  313         int64_t         next;
  314 };
  315 
  316 static DPCPU_DEFINE(struct xen_et_state, et_state);
  317 
  318 static int
  319 clkintr(void *arg)
  320 {
  321         int64_t now;
  322         int cpu = smp_processor_id();
  323         struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu);
  324         struct xen_et_state *state = DPCPU_PTR(et_state);
  325 
  326         do {
  327                 __get_time_values_from_xen();
  328                 now = shadow->system_timestamp + get_nsec_offset(shadow);
  329         } while (!time_values_up_to_date(cpu));
  330 
  331         /* Process elapsed ticks since last call. */
  332         processed_system_time = now;
  333         if (state->mode == MODE_PERIODIC) {
  334                 while (now >= state->next) {
  335                         state->next += state->period;
  336                         if (xen_et.et_active)
  337                                 xen_et.et_event_cb(&xen_et, xen_et.et_arg);
  338                 }
  339                 HYPERVISOR_set_timer_op(state->next + 50000);
  340         } else if (state->mode == MODE_ONESHOT) {
  341                 if (xen_et.et_active)
  342                         xen_et.et_event_cb(&xen_et, xen_et.et_arg);
  343         }
  344         /*
  345          * Take synchronised time from Xen once a minute if we're not
  346          * synchronised ourselves, and we haven't chosen to keep an independent
  347          * time base.
  348          */
  349         
  350         if (shadow_tv_version != HYPERVISOR_shared_info->wc_version &&
  351             !independent_wallclock) {
  352                 printf("[XEN] hypervisor wallclock nudged; nudging TOD.\n");
  353                 update_wallclock();
  354                 add_uptime_to_wallclock();
  355                 tc_setclock(&shadow_tv);
  356         }
  357         
  358         /* XXX TODO */
  359         return (FILTER_HANDLED);
  360 }
  361 static uint32_t
  362 getit(void)
  363 {
  364         struct shadow_time_info *shadow;
  365         uint64_t time;
  366         uint32_t local_time_version;
  367 
  368         shadow = &per_cpu(shadow_time, smp_processor_id());
  369 
  370         do {
  371           local_time_version = shadow->version;
  372           barrier();
  373           time = shadow->system_timestamp + get_nsec_offset(shadow);
  374           if (!time_values_up_to_date(smp_processor_id()))
  375             __get_time_values_from_xen(/*cpu */);
  376           barrier();
  377         } while (local_time_version != shadow->version);
  378 
  379           return (time);
  380 }
  381 
  382 
  383 /*
  384  * XXX: timer needs more SMP work.
  385  */
  386 void
  387 i8254_init(void)
  388 {
  389 
  390         RTC_LOCK_INIT;
  391 }
  392 
  393 /*
  394  * Wait "n" microseconds.
  395  * Relies on timer 1 counting down from (timer_freq / hz)
  396  * Note: timer had better have been programmed before this is first used!
  397  */
  398 void
  399 DELAY(int n)
  400 {
  401         int delta, ticks_left;
  402         uint32_t tick, prev_tick;
  403 #ifdef DELAYDEBUG
  404         int getit_calls = 1;
  405         int n1;
  406         static int state = 0;
  407 
  408         if (state == 0) {
  409                 state = 1;
  410                 for (n1 = 1; n1 <= 10000000; n1 *= 10)
  411                         DELAY(n1);
  412                 state = 2;
  413         }
  414         if (state == 1)
  415                 printf("DELAY(%d)...", n);
  416 #endif
  417         /*
  418          * Read the counter first, so that the rest of the setup overhead is
  419          * counted.  Guess the initial overhead is 20 usec (on most systems it
  420          * takes about 1.5 usec for each of the i/o's in getit().  The loop
  421          * takes about 6 usec on a 486/33 and 13 usec on a 386/20.  The
  422          * multiplications and divisions to scale the count take a while).
  423          *
  424          * However, if ddb is active then use a fake counter since reading
  425          * the i8254 counter involves acquiring a lock.  ddb must not go
  426          * locking for many reasons, but it calls here for at least atkbd
  427          * input.
  428          */
  429         prev_tick = getit();
  430 
  431         n -= 0;                 /* XXX actually guess no initial overhead */
  432         /*
  433          * Calculate (n * (timer_freq / 1e6)) without using floating point
  434          * and without any avoidable overflows.
  435          */
  436         if (n <= 0)
  437                 ticks_left = 0;
  438         else if (n < 256)
  439                 /*
  440                  * Use fixed point to avoid a slow division by 1000000.
  441                  * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
  442                  * 2^15 is the first power of 2 that gives exact results
  443                  * for n between 0 and 256.
  444                  */
  445                 ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15;
  446         else
  447                 /*
  448                  * Don't bother using fixed point, although gcc-2.7.2
  449                  * generates particularly poor code for the long long
  450                  * division, since even the slow way will complete long
  451                  * before the delay is up (unless we're interrupted).
  452                  */
  453                 ticks_left = ((u_int)n * (long long)timer_freq + 999999)
  454                         / 1000000;
  455 
  456         while (ticks_left > 0) {
  457                 tick = getit();
  458 #ifdef DELAYDEBUG
  459                 ++getit_calls;
  460 #endif
  461                 delta = tick - prev_tick;
  462                 prev_tick = tick;
  463                 if (delta < 0) {
  464                         /*
  465                          * Guard against timer0_max_count being wrong.
  466                          * This shouldn't happen in normal operation,
  467                          * but it may happen if set_timer_freq() is
  468                          * traced.
  469                          */
  470                         /* delta += timer0_max_count; ??? */
  471                         if (delta < 0)
  472                                 delta = 0;
  473                 }
  474                 ticks_left -= delta;
  475         }
  476 #ifdef DELAYDEBUG
  477         if (state == 1)
  478                 printf(" %d calls to getit() at %d usec each\n",
  479                        getit_calls, (n + 5) / getit_calls);
  480 #endif
  481 }
  482 
  483 
  484 /*
  485  * Restore all the timers non-atomically (XXX: should be atomically).
  486  *
  487  * This function is called from pmtimer_resume() to restore all the timers.
  488  * This should not be necessary, but there are broken laptops that do not
  489  * restore all the timers on resume.
  490  */
  491 void
  492 timer_restore(void)
  493 {
  494         struct xen_et_state *state = DPCPU_PTR(et_state);
  495 
  496         /* Get timebases for new environment. */ 
  497         __get_time_values_from_xen();
  498 
  499         /* Reset our own concept of passage of system time. */
  500         processed_system_time = per_cpu(shadow_time, 0).system_timestamp;
  501         state->next = processed_system_time;
  502 }
  503 
  504 void
  505 startrtclock()
  506 {
  507         unsigned long long alarm;
  508         uint64_t __cpu_khz;
  509         uint32_t cpu_khz;
  510         struct vcpu_time_info *info;
  511 
  512         /* initialize xen values */
  513         __get_time_values_from_xen();
  514         processed_system_time = per_cpu(shadow_time, 0).system_timestamp;
  515 
  516         __cpu_khz = 1000000ULL << 32;
  517         info = &HYPERVISOR_shared_info->vcpu_info[0].time;
  518 
  519         (void)do_div(__cpu_khz, info->tsc_to_system_mul);
  520         if ( info->tsc_shift < 0 )
  521                 cpu_khz = __cpu_khz << -info->tsc_shift;
  522         else
  523                 cpu_khz = __cpu_khz >> info->tsc_shift;
  524 
  525         printf("Xen reported: %u.%03u MHz processor.\n", 
  526                cpu_khz / 1000, cpu_khz % 1000);
  527 
  528         /* (10^6 * 2^32) / cpu_hz = (10^3 * 2^32) / cpu_khz =
  529            (2^32 * 1 / (clocks/us)) */
  530 
  531         set_cyc2ns_scale(cpu_khz/1000);
  532         tsc_freq = cpu_khz * 1000;
  533 
  534         timer_freq = 1000000000LL;
  535         xen_timecounter.tc_frequency = timer_freq >> 9;
  536         tc_init(&xen_timecounter);
  537 
  538         rdtscll(alarm);
  539 }
  540 
  541 /*
  542  * RTC support routines
  543  */
  544 
  545 
  546 static __inline int
  547 readrtc(int port)
  548 {
  549         return(bcd2bin(rtcin(port)));
  550 }
  551 
  552 
  553 #ifdef XEN_PRIVILEGED_GUEST
  554 
  555 /*
  556  * Initialize the time of day register, based on the time base which is, e.g.
  557  * from a filesystem.
  558  */
  559 static void
  560 domu_inittodr(time_t base)
  561 {
  562         unsigned long   sec;
  563         int             s, y;
  564         struct timespec ts;
  565 
  566         update_wallclock();
  567         add_uptime_to_wallclock();
  568         
  569         RTC_LOCK;
  570         
  571         if (base) {
  572                 ts.tv_sec = base;
  573                 ts.tv_nsec = 0;
  574                 tc_setclock(&ts);
  575         }
  576 
  577         sec += tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
  578 
  579         y = time_second - shadow_tv.tv_sec;
  580         if (y <= -2 || y >= 2) {
  581                 /* badly off, adjust it */
  582                 tc_setclock(&shadow_tv);
  583         }
  584         RTC_UNLOCK;
  585 }
  586 
  587 /*
  588  * Write system time back to RTC.  
  589  */
  590 static void
  591 domu_resettodr(void)
  592 {
  593         unsigned long tm;
  594         int s;
  595         dom0_op_t op;
  596         struct shadow_time_info *shadow;
  597 
  598         shadow = &per_cpu(shadow_time, smp_processor_id());
  599         if (xen_disable_rtc_set)
  600                 return;
  601         
  602         s = splclock();
  603         tm = time_second;
  604         splx(s);
  605         
  606         tm -= tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
  607         
  608         if ((xen_start_info->flags & SIF_INITDOMAIN) &&
  609             !independent_wallclock)
  610         {
  611                 op.cmd = DOM0_SETTIME;
  612                 op.u.settime.secs        = tm;
  613                 op.u.settime.nsecs       = 0;
  614                 op.u.settime.system_time = shadow->system_timestamp;
  615                 HYPERVISOR_dom0_op(&op);
  616                 update_wallclock();
  617                 add_uptime_to_wallclock();
  618         } else if (independent_wallclock) {
  619                 /* notyet */
  620                 ;
  621         }               
  622 }
  623 
  624 /*
  625  * Initialize the time of day register, based on the time base which is, e.g.
  626  * from a filesystem.
  627  */
  628 void
  629 inittodr(time_t base)
  630 {
  631         unsigned long   sec, days;
  632         int             year, month;
  633         int             y, m, s;
  634         struct timespec ts;
  635 
  636         if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
  637                 domu_inittodr(base);
  638                 return;
  639         }
  640 
  641         if (base) {
  642                 s = splclock();
  643                 ts.tv_sec = base;
  644                 ts.tv_nsec = 0;
  645                 tc_setclock(&ts);
  646                 splx(s);
  647         }
  648 
  649         /* Look if we have a RTC present and the time is valid */
  650         if (!(rtcin(RTC_STATUSD) & RTCSD_PWR))
  651                 goto wrong_time;
  652 
  653         /* wait for time update to complete */
  654         /* If RTCSA_TUP is zero, we have at least 244us before next update */
  655         s = splhigh();
  656         while (rtcin(RTC_STATUSA) & RTCSA_TUP) {
  657                 splx(s);
  658                 s = splhigh();
  659         }
  660 
  661         days = 0;
  662 #ifdef USE_RTC_CENTURY
  663         year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100;
  664 #else
  665         year = readrtc(RTC_YEAR) + 1900;
  666         if (year < 1970)
  667                 year += 100;
  668 #endif
  669         if (year < 1970) {
  670                 splx(s);
  671                 goto wrong_time;
  672         }
  673         month = readrtc(RTC_MONTH);
  674         for (m = 1; m < month; m++)
  675                 days += daysinmonth[m-1];
  676         if ((month > 2) && LEAPYEAR(year))
  677                 days ++;
  678         days += readrtc(RTC_DAY) - 1;
  679         for (y = 1970; y < year; y++)
  680                 days += DAYSPERYEAR + LEAPYEAR(y);
  681         sec = ((( days * 24 +
  682                   readrtc(RTC_HRS)) * 60 +
  683                 readrtc(RTC_MIN)) * 60 +
  684                readrtc(RTC_SEC));
  685         /* sec now contains the number of seconds, since Jan 1 1970,
  686            in the local time zone */
  687 
  688         sec += tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
  689 
  690         y = time_second - sec;
  691         if (y <= -2 || y >= 2) {
  692                 /* badly off, adjust it */
  693                 ts.tv_sec = sec;
  694                 ts.tv_nsec = 0;
  695                 tc_setclock(&ts);
  696         }
  697         splx(s);
  698         return;
  699 
  700  wrong_time:
  701         printf("Invalid time in real time clock.\n");
  702         printf("Check and reset the date immediately!\n");
  703 }
  704 
  705 
  706 /*
  707  * Write system time back to RTC
  708  */
  709 void
  710 resettodr()
  711 {
  712         unsigned long   tm;
  713         int             y, m, s;
  714 
  715         if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
  716                 domu_resettodr();
  717                 return;
  718         }
  719                
  720         if (xen_disable_rtc_set)
  721                 return;
  722 
  723         s = splclock();
  724         tm = time_second;
  725         splx(s);
  726 
  727         /* Disable RTC updates and interrupts. */
  728         writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR);
  729 
  730         /* Calculate local time to put in RTC */
  731 
  732         tm -= tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
  733 
  734         writertc(RTC_SEC, bin2bcd(tm%60)); tm /= 60;    /* Write back Seconds */
  735         writertc(RTC_MIN, bin2bcd(tm%60)); tm /= 60;    /* Write back Minutes */
  736         writertc(RTC_HRS, bin2bcd(tm%24)); tm /= 24;    /* Write back Hours   */
  737 
  738         /* We have now the days since 01-01-1970 in tm */
  739         writertc(RTC_WDAY, (tm + 4) % 7 + 1);           /* Write back Weekday */
  740         for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y);
  741              tm >= m;
  742              y++,      m = DAYSPERYEAR + LEAPYEAR(y))
  743                 tm -= m;
  744 
  745         /* Now we have the years in y and the day-of-the-year in tm */
  746         writertc(RTC_YEAR, bin2bcd(y%100));             /* Write back Year    */
  747 #ifdef USE_RTC_CENTURY
  748         writertc(RTC_CENTURY, bin2bcd(y/100));          /* ... and Century    */
  749 #endif
  750         for (m = 0; ; m++) {
  751                 int ml;
  752 
  753                 ml = daysinmonth[m];
  754                 if (m == 1 && LEAPYEAR(y))
  755                         ml++;
  756                 if (tm < ml)
  757                         break;
  758                 tm -= ml;
  759         }
  760 
  761         writertc(RTC_MONTH, bin2bcd(m + 1));            /* Write back Month   */
  762         writertc(RTC_DAY, bin2bcd(tm + 1));             /* Write back Month Day */
  763 
  764         /* Reenable RTC updates and interrupts. */
  765         writertc(RTC_STATUSB, RTCSB_24HR);
  766         rtcin(RTC_INTR);
  767 }
  768 #endif
  769 
  770 static int
  771 xen_et_start(struct eventtimer *et,
  772     struct bintime *first, struct bintime *period)
  773 {
  774         struct xen_et_state *state = DPCPU_PTR(et_state);
  775         struct shadow_time_info *shadow;
  776         int64_t fperiod;
  777 
  778         __get_time_values_from_xen();
  779 
  780         if (period != NULL) {
  781                 state->mode = MODE_PERIODIC;
  782                 state->period = (1000000000LL *
  783                     (uint32_t)(period->frac >> 32)) >> 32;
  784                 if (period->sec != 0)
  785                         state->period += 1000000000LL * period->sec;
  786         } else {
  787                 state->mode = MODE_ONESHOT;
  788                 state->period = 0;
  789         }
  790         if (first != NULL) {
  791                 fperiod = (1000000000LL * (uint32_t)(first->frac >> 32)) >> 32;
  792                 if (first->sec != 0)
  793                         fperiod += 1000000000LL * first->sec;
  794         } else
  795                 fperiod = state->period;
  796 
  797         shadow = &per_cpu(shadow_time, smp_processor_id());
  798         state->next = shadow->system_timestamp + get_nsec_offset(shadow);
  799         state->next += fperiod;
  800         HYPERVISOR_set_timer_op(state->next + 50000);
  801         return (0);
  802 }
  803 
  804 static int
  805 xen_et_stop(struct eventtimer *et)
  806 {
  807         struct xen_et_state *state = DPCPU_PTR(et_state);
  808 
  809         state->mode = MODE_STOP;
  810         HYPERVISOR_set_timer_op(0);
  811         return (0);
  812 }
  813 
  814 /*
  815  * Start clocks running.
  816  */
  817 void
  818 cpu_initclocks(void)
  819 {
  820         unsigned int time_irq;
  821         int error;
  822 
  823         HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, 0, NULL);
  824         error = bind_virq_to_irqhandler(VIRQ_TIMER, 0, "cpu0:timer",
  825             clkintr, NULL, NULL, INTR_TYPE_CLK, &time_irq);
  826         if (error)
  827                 panic("failed to register clock interrupt\n");
  828         /* should fast clock be enabled ? */
  829 
  830         bzero(&xen_et, sizeof(xen_et));
  831         xen_et.et_name = "ixen";
  832         xen_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
  833             ET_FLAGS_PERCPU;
  834         xen_et.et_quality = 600;
  835         xen_et.et_frequency = 0;
  836         xen_et.et_min_period.sec = 0;
  837         xen_et.et_min_period.frac = 0x00400000LL << 32;
  838         xen_et.et_max_period.sec = 2;
  839         xen_et.et_max_period.frac = 0;
  840         xen_et.et_start = xen_et_start;
  841         xen_et.et_stop = xen_et_stop;
  842         xen_et.et_priv = NULL;
  843         et_register(&xen_et);
  844 
  845         cpu_initclocks_bsp();
  846 }
  847 
  848 int
  849 ap_cpu_initclocks(int cpu)
  850 {
  851         char buf[MAXCOMLEN + 1];
  852         unsigned int time_irq;
  853         int error;
  854 
  855         HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL);
  856         snprintf(buf, sizeof(buf), "cpu%d:timer", cpu);
  857         error = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, buf,
  858             clkintr, NULL, NULL, INTR_TYPE_CLK, &time_irq);
  859         if (error)
  860                 panic("failed to register clock interrupt\n");
  861 
  862         return (0);
  863 }
  864 
  865 static uint32_t
  866 xen_get_timecount(struct timecounter *tc)
  867 {       
  868         uint64_t clk;
  869         struct shadow_time_info *shadow;
  870         shadow = &per_cpu(shadow_time, smp_processor_id());
  871 
  872         __get_time_values_from_xen();
  873         
  874         clk = shadow->system_timestamp + get_nsec_offset(shadow);
  875 
  876         return (uint32_t)(clk >> 9);
  877 
  878 }
  879 
  880 /* Return system time offset by ticks */
  881 uint64_t
  882 get_system_time(int ticks)
  883 {
  884     return processed_system_time + (ticks * NS_PER_TICK);
  885 }
  886 
  887 void
  888 idle_block(void)
  889 {
  890 
  891         HYPERVISOR_sched_op(SCHEDOP_block, 0);
  892 }
  893 
  894 int
  895 timer_spkr_acquire(void)
  896 {
  897 
  898         return (0);
  899 }
  900 
  901 int
  902 timer_spkr_release(void)
  903 {
  904 
  905         return (0);
  906 }
  907 
  908 void
  909 timer_spkr_setfreq(int freq)
  910 {
  911 
  912 }
  913 

Cache object: 8443d518e22f9cc6400d25cc4cabaa2d


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