]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/i386/xen/clock.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / i386 / xen / clock.c
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/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), "0" (__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                 printf("[XEN] hypervisor wallclock nudged; nudging TOD.\n");
345                 update_wallclock();
346                 add_uptime_to_wallclock();
347                 tc_setclock(&shadow_tv);
348         }
349         
350         /* XXX TODO */
351         return (FILTER_HANDLED);
352 }
353 static uint32_t
354 getit(void)
355 {
356         struct shadow_time_info *shadow;
357         uint64_t time;
358         uint32_t local_time_version;
359
360         shadow = &per_cpu(shadow_time, smp_processor_id());
361
362         do {
363           local_time_version = shadow->version;
364           barrier();
365           time = shadow->system_timestamp + get_nsec_offset(shadow);
366           if (!time_values_up_to_date(smp_processor_id()))
367             __get_time_values_from_xen(/*cpu */);
368           barrier();
369         } while (local_time_version != shadow->version);
370
371           return (time);
372 }
373
374
375 /*
376  * XXX: timer needs more SMP work.
377  */
378 void
379 i8254_init(void)
380 {
381
382         RTC_LOCK_INIT;
383 }
384
385 /*
386  * Wait "n" microseconds.
387  * Relies on timer 1 counting down from (timer_freq / hz)
388  * Note: timer had better have been programmed before this is first used!
389  */
390 void
391 DELAY(int n)
392 {
393         int delta, ticks_left;
394         uint32_t tick, prev_tick;
395 #ifdef DELAYDEBUG
396         int getit_calls = 1;
397         int n1;
398         static int state = 0;
399
400         if (state == 0) {
401                 state = 1;
402                 for (n1 = 1; n1 <= 10000000; n1 *= 10)
403                         DELAY(n1);
404                 state = 2;
405         }
406         if (state == 1)
407                 printf("DELAY(%d)...", n);
408 #endif
409         /*
410          * Read the counter first, so that the rest of the setup overhead is
411          * counted.  Guess the initial overhead is 20 usec (on most systems it
412          * takes about 1.5 usec for each of the i/o's in getit().  The loop
413          * takes about 6 usec on a 486/33 and 13 usec on a 386/20.  The
414          * multiplications and divisions to scale the count take a while).
415          *
416          * However, if ddb is active then use a fake counter since reading
417          * the i8254 counter involves acquiring a lock.  ddb must not go
418          * locking for many reasons, but it calls here for at least atkbd
419          * input.
420          */
421         prev_tick = getit();
422
423         n -= 0;                 /* XXX actually guess no initial overhead */
424         /*
425          * Calculate (n * (timer_freq / 1e6)) without using floating point
426          * and without any avoidable overflows.
427          */
428         if (n <= 0)
429                 ticks_left = 0;
430         else if (n < 256)
431                 /*
432                  * Use fixed point to avoid a slow division by 1000000.
433                  * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
434                  * 2^15 is the first power of 2 that gives exact results
435                  * for n between 0 and 256.
436                  */
437                 ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15;
438         else
439                 /*
440                  * Don't bother using fixed point, although gcc-2.7.2
441                  * generates particularly poor code for the long long
442                  * division, since even the slow way will complete long
443                  * before the delay is up (unless we're interrupted).
444                  */
445                 ticks_left = ((u_int)n * (long long)timer_freq + 999999)
446                         / 1000000;
447
448         while (ticks_left > 0) {
449                 tick = getit();
450 #ifdef DELAYDEBUG
451                 ++getit_calls;
452 #endif
453                 delta = tick - prev_tick;
454                 prev_tick = tick;
455                 if (delta < 0) {
456                         /*
457                          * Guard against timer0_max_count being wrong.
458                          * This shouldn't happen in normal operation,
459                          * but it may happen if set_timer_freq() is
460                          * traced.
461                          */
462                         /* delta += timer0_max_count; ??? */
463                         if (delta < 0)
464                                 delta = 0;
465                 }
466                 ticks_left -= delta;
467         }
468 #ifdef DELAYDEBUG
469         if (state == 1)
470                 printf(" %d calls to getit() at %d usec each\n",
471                        getit_calls, (n + 5) / getit_calls);
472 #endif
473 }
474
475
476 /*
477  * Restore all the timers non-atomically (XXX: should be atomically).
478  *
479  * This function is called from pmtimer_resume() to restore all the timers.
480  * This should not be necessary, but there are broken laptops that do not
481  * restore all the timers on resume.
482  */
483 void
484 timer_restore(void)
485 {
486         /* Get timebases for new environment. */ 
487         __get_time_values_from_xen();
488
489         /* Reset our own concept of passage of system time. */
490         processed_system_time = per_cpu(shadow_time, 0).system_timestamp;
491         per_cpu(processed_system_time, 0) = processed_system_time;
492 }
493
494 void
495 startrtclock()
496 {
497         unsigned long long alarm;
498         uint64_t __cpu_khz;
499         uint32_t cpu_khz;
500         struct vcpu_time_info *info;
501
502         /* initialize xen values */
503         __get_time_values_from_xen();
504         processed_system_time = per_cpu(shadow_time, 0).system_timestamp;
505         per_cpu(processed_system_time, 0) = processed_system_time;
506
507         __cpu_khz = 1000000ULL << 32;
508         info = &HYPERVISOR_shared_info->vcpu_info[0].time;
509
510         do_div(__cpu_khz, info->tsc_to_system_mul);
511         if ( info->tsc_shift < 0 )
512                 cpu_khz = __cpu_khz << -info->tsc_shift;
513         else
514                 cpu_khz = __cpu_khz >> info->tsc_shift;
515
516         printf("Xen reported: %u.%03u MHz processor.\n", 
517                cpu_khz / 1000, cpu_khz % 1000);
518
519         /* (10^6 * 2^32) / cpu_hz = (10^3 * 2^32) / cpu_khz =
520            (2^32 * 1 / (clocks/us)) */
521
522         set_cyc2ns_scale(cpu_khz/1000);
523         tsc_freq = cpu_khz * 1000;
524
525         timer_freq = xen_timecounter.tc_frequency = 1000000000LL;
526         tc_init(&xen_timecounter);
527
528         rdtscll(alarm);
529 }
530
531 /*
532  * RTC support routines
533  */
534
535
536 static __inline int
537 readrtc(int port)
538 {
539         return(bcd2bin(rtcin(port)));
540 }
541
542
543 #ifdef XEN_PRIVILEGED_GUEST
544
545 /*
546  * Initialize the time of day register, based on the time base which is, e.g.
547  * from a filesystem.
548  */
549 static void
550 domu_inittodr(time_t base)
551 {
552         unsigned long   sec;
553         int             s, y;
554         struct timespec ts;
555
556         update_wallclock();
557         add_uptime_to_wallclock();
558         
559         RTC_LOCK;
560         
561         if (base) {
562                 ts.tv_sec = base;
563                 ts.tv_nsec = 0;
564                 tc_setclock(&ts);
565         }
566
567         sec += tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
568
569         y = time_second - shadow_tv.tv_sec;
570         if (y <= -2 || y >= 2) {
571                 /* badly off, adjust it */
572                 tc_setclock(&shadow_tv);
573         }
574         RTC_UNLOCK;
575 }
576
577 /*
578  * Write system time back to RTC.  
579  */
580 static void
581 domu_resettodr(void)
582 {
583         unsigned long tm;
584         int s;
585         dom0_op_t op;
586         struct shadow_time_info *shadow;
587
588         shadow = &per_cpu(shadow_time, smp_processor_id());
589         if (xen_disable_rtc_set)
590                 return;
591         
592         s = splclock();
593         tm = time_second;
594         splx(s);
595         
596         tm -= tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
597         
598         if ((xen_start_info->flags & SIF_INITDOMAIN) &&
599             !independent_wallclock)
600         {
601                 op.cmd = DOM0_SETTIME;
602                 op.u.settime.secs        = tm;
603                 op.u.settime.nsecs       = 0;
604                 op.u.settime.system_time = shadow->system_timestamp;
605                 HYPERVISOR_dom0_op(&op);
606                 update_wallclock();
607                 add_uptime_to_wallclock();
608         } else if (independent_wallclock) {
609                 /* notyet */
610                 ;
611         }               
612 }
613
614 /*
615  * Initialize the time of day register, based on the time base which is, e.g.
616  * from a filesystem.
617  */
618 void
619 inittodr(time_t base)
620 {
621         unsigned long   sec, days;
622         int             year, month;
623         int             y, m, s;
624         struct timespec ts;
625
626         if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
627                 domu_inittodr(base);
628                 return;
629         }
630
631         if (base) {
632                 s = splclock();
633                 ts.tv_sec = base;
634                 ts.tv_nsec = 0;
635                 tc_setclock(&ts);
636                 splx(s);
637         }
638
639         /* Look if we have a RTC present and the time is valid */
640         if (!(rtcin(RTC_STATUSD) & RTCSD_PWR))
641                 goto wrong_time;
642
643         /* wait for time update to complete */
644         /* If RTCSA_TUP is zero, we have at least 244us before next update */
645         s = splhigh();
646         while (rtcin(RTC_STATUSA) & RTCSA_TUP) {
647                 splx(s);
648                 s = splhigh();
649         }
650
651         days = 0;
652 #ifdef USE_RTC_CENTURY
653         year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100;
654 #else
655         year = readrtc(RTC_YEAR) + 1900;
656         if (year < 1970)
657                 year += 100;
658 #endif
659         if (year < 1970) {
660                 splx(s);
661                 goto wrong_time;
662         }
663         month = readrtc(RTC_MONTH);
664         for (m = 1; m < month; m++)
665                 days += daysinmonth[m-1];
666         if ((month > 2) && LEAPYEAR(year))
667                 days ++;
668         days += readrtc(RTC_DAY) - 1;
669         for (y = 1970; y < year; y++)
670                 days += DAYSPERYEAR + LEAPYEAR(y);
671         sec = ((( days * 24 +
672                   readrtc(RTC_HRS)) * 60 +
673                 readrtc(RTC_MIN)) * 60 +
674                readrtc(RTC_SEC));
675         /* sec now contains the number of seconds, since Jan 1 1970,
676            in the local time zone */
677
678         sec += tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
679
680         y = time_second - sec;
681         if (y <= -2 || y >= 2) {
682                 /* badly off, adjust it */
683                 ts.tv_sec = sec;
684                 ts.tv_nsec = 0;
685                 tc_setclock(&ts);
686         }
687         splx(s);
688         return;
689
690  wrong_time:
691         printf("Invalid time in real time clock.\n");
692         printf("Check and reset the date immediately!\n");
693 }
694
695
696 /*
697  * Write system time back to RTC
698  */
699 void
700 resettodr()
701 {
702         unsigned long   tm;
703         int             y, m, s;
704
705         if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
706                 domu_resettodr();
707                 return;
708         }
709                
710         if (xen_disable_rtc_set)
711                 return;
712
713         s = splclock();
714         tm = time_second;
715         splx(s);
716
717         /* Disable RTC updates and interrupts. */
718         writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR);
719
720         /* Calculate local time to put in RTC */
721
722         tm -= tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0);
723
724         writertc(RTC_SEC, bin2bcd(tm%60)); tm /= 60;    /* Write back Seconds */
725         writertc(RTC_MIN, bin2bcd(tm%60)); tm /= 60;    /* Write back Minutes */
726         writertc(RTC_HRS, bin2bcd(tm%24)); tm /= 24;    /* Write back Hours   */
727
728         /* We have now the days since 01-01-1970 in tm */
729         writertc(RTC_WDAY, (tm + 4) % 7 + 1);           /* Write back Weekday */
730         for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y);
731              tm >= m;
732              y++,      m = DAYSPERYEAR + LEAPYEAR(y))
733                 tm -= m;
734
735         /* Now we have the years in y and the day-of-the-year in tm */
736         writertc(RTC_YEAR, bin2bcd(y%100));             /* Write back Year    */
737 #ifdef USE_RTC_CENTURY
738         writertc(RTC_CENTURY, bin2bcd(y/100));          /* ... and Century    */
739 #endif
740         for (m = 0; ; m++) {
741                 int ml;
742
743                 ml = daysinmonth[m];
744                 if (m == 1 && LEAPYEAR(y))
745                         ml++;
746                 if (tm < ml)
747                         break;
748                 tm -= ml;
749         }
750
751         writertc(RTC_MONTH, bin2bcd(m + 1));            /* Write back Month   */
752         writertc(RTC_DAY, bin2bcd(tm + 1));             /* Write back Month Day */
753
754         /* Reenable RTC updates and interrupts. */
755         writertc(RTC_STATUSB, RTCSB_24HR);
756         rtcin(RTC_INTR);
757 }
758 #endif
759
760 static struct vcpu_set_periodic_timer xen_set_periodic_tick;
761
762 /*
763  * Start clocks running.
764  */
765 void
766 cpu_initclocks(void)
767 {
768         unsigned int time_irq;
769         int error;
770
771         xen_set_periodic_tick.period_ns = NS_PER_TICK;
772         
773         HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, 0,
774                            &xen_set_periodic_tick);
775         
776         error = bind_virq_to_irqhandler(VIRQ_TIMER, 0, "clk", 
777             clkintr, NULL, NULL,
778             INTR_TYPE_CLK | INTR_FAST, &time_irq);
779         if (error)
780                 panic("failed to register clock interrupt\n");
781         /* should fast clock be enabled ? */
782         
783 }
784
785 int
786 ap_cpu_initclocks(int cpu)
787 {
788         unsigned int time_irq;
789         int error;
790
791         xen_set_periodic_tick.period_ns = NS_PER_TICK;
792
793         HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu,
794                            &xen_set_periodic_tick);
795         error = bind_virq_to_irqhandler(VIRQ_TIMER, 0, "clk", 
796             clkintr, NULL, NULL,
797             INTR_TYPE_CLK | INTR_FAST, &time_irq);
798         if (error)
799                 panic("failed to register clock interrupt\n");
800
801
802         return (0);
803 }
804
805
806 void
807 cpu_startprofclock(void)
808 {
809
810         printf("cpu_startprofclock: profiling clock is not supported\n");
811 }
812
813 void
814 cpu_stopprofclock(void)
815 {
816
817         printf("cpu_stopprofclock: profiling clock is not supported\n");
818 }
819 #define NSEC_PER_USEC 1000
820
821 static uint32_t
822 xen_get_timecount(struct timecounter *tc)
823 {       
824         uint64_t clk;
825         struct shadow_time_info *shadow;
826         shadow = &per_cpu(shadow_time, smp_processor_id());
827
828         __get_time_values_from_xen();
829         
830         clk = shadow->system_timestamp + get_nsec_offset(shadow);
831
832         return (uint32_t)((clk / NS_PER_TICK) * NS_PER_TICK);
833
834 }
835
836 /* Return system time offset by ticks */
837 uint64_t
838 get_system_time(int ticks)
839 {
840     return processed_system_time + (ticks * NS_PER_TICK);
841 }
842
843 /*
844  * Track behavior of cur_timer->get_offset() functionality in timer_tsc.c
845  */
846
847
848 /* Convert jiffies to system time. */
849 static uint64_t 
850 ticks_to_system_time(int newticks)
851 {
852         int delta;
853         uint64_t st;
854
855         delta = newticks - ticks;
856         if (delta < 1) {
857                 /* Triggers in some wrap-around cases,
858                  * but that's okay:
859                  * we just end up with a shorter timeout. */
860                 st = processed_system_time + NS_PER_TICK;
861         } else if (((unsigned int)delta >> (BITS_PER_LONG-3)) != 0) {
862                 /* Very long timeout means there is no pending timer.
863                  * We indicate this to Xen by passing zero timeout. */
864                 st = 0;
865         } else {
866                 st = processed_system_time + delta * (uint64_t)NS_PER_TICK;
867         }
868
869         return (st);
870 }
871
872 void
873 idle_block(void)
874 {
875   uint64_t timeout;
876
877   timeout = ticks_to_system_time(ticks + 1) + NS_PER_TICK/2;
878
879   __get_time_values_from_xen();
880   PANIC_IF(HYPERVISOR_set_timer_op(timeout) != 0);
881   HYPERVISOR_sched_op(SCHEDOP_block, 0);
882 }
883
884 int
885 timer_spkr_acquire(void)
886 {
887
888         return (0);
889 }
890
891 int
892 timer_spkr_release(void)
893 {
894
895         return (0);
896 }
897
898 void
899 timer_spkr_setfreq(int freq)
900 {
901
902 }
903
904
905         
906