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

Cache object: b57289bad7514fa3eff1dd4210f1f294


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