]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/i386/xen/clock.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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/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), "0" (__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