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