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