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