Sat Oct 22 19:26:16 2011 UTC ()
Various clock fixes:
- xen_get_timecount() is CPU specific, so get the time from this
  virtual CPU and not VCPU0. Also keep xen_clock_bias per-cpu.
- The periodic timer looks buggy, we stop receiving events after a (short)
  while. Linux is using the one-shoot timer so use it too (and disable
  the periodic timer), but rearm it from the event handler, not idle_block()
  as the later may not be called if the CPU is busy, resulting it clock
  event loss.
- use  HYPERVISOR_block() in idle_block() again, now that interrupts are
  working properly.


(bouyer)
diff -r1.54.6.4 -r1.54.6.5 src/sys/arch/xen/xen/clock.c

cvs diff -r1.54.6.4 -r1.54.6.5 src/sys/arch/xen/xen/Attic/clock.c (expand / switch to unified diff)

--- src/sys/arch/xen/xen/Attic/clock.c 2011/09/18 18:54:32 1.54.6.4
+++ src/sys/arch/xen/xen/Attic/clock.c 2011/10/22 19:26:16 1.54.6.5
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: clock.c,v 1.54.6.4 2011/09/18 18:54:32 cherry Exp $ */ 1/* $NetBSD: clock.c,v 1.54.6.5 2011/10/22 19:26:16 bouyer Exp $ */
2 2
3/* 3/*
4 * 4 *
5 * Copyright (c) 2004 Christian Limpach. 5 * Copyright (c) 2004 Christian Limpach.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
@@ -19,27 +19,27 @@ @@ -19,27 +19,27 @@
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29#include "opt_xen.h" 29#include "opt_xen.h"
30 30
31#include <sys/cdefs.h> 31#include <sys/cdefs.h>
32__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.54.6.4 2011/09/18 18:54:32 cherry Exp $"); 32__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.54.6.5 2011/10/22 19:26:16 bouyer Exp $");
33 33
34#include <sys/param.h> 34#include <sys/param.h>
35#include <sys/cpu.h> 35#include <sys/cpu.h>
36#include <sys/systm.h> 36#include <sys/systm.h>
37#include <sys/time.h> 37#include <sys/time.h>
38#include <sys/timetc.h> 38#include <sys/timetc.h>
39#include <sys/timevar.h> 39#include <sys/timevar.h>
40#include <sys/kernel.h> 40#include <sys/kernel.h>
41#include <sys/mutex.h> 41#include <sys/mutex.h>
42#include <sys/device.h> 42#include <sys/device.h>
43#include <sys/sysctl.h> 43#include <sys/sysctl.h>
44 44
45#include <xen/xen.h> 45#include <xen/xen.h>
@@ -84,27 +84,27 @@ static volatile struct shadow ci_shadow[ @@ -84,27 +84,27 @@ static volatile struct shadow ci_shadow[
84 84
85static kmutex_t tmutex; /* Protects volatile variables, below */ 85static kmutex_t tmutex; /* Protects volatile variables, below */
86 86
87/* The time when the last hardclock(9) call should have taken place, 87/* The time when the last hardclock(9) call should have taken place,
88 * per cpu. 88 * per cpu.
89 */ 89 */
90static volatile uint64_t vcpu_system_time[MAXCPUS]; 90static volatile uint64_t vcpu_system_time[MAXCPUS];
91 91
92/* 92/*
93 * The clock (as returned by xen_get_timecount) may need to be held 93 * The clock (as returned by xen_get_timecount) may need to be held
94 * back to maintain the illusion that hardclock(9) was called when it 94 * back to maintain the illusion that hardclock(9) was called when it
95 * was supposed to be, not when Xen got around to scheduling us. 95 * was supposed to be, not when Xen got around to scheduling us.
96 */ 96 */
97static volatile uint64_t xen_clock_bias; 97static volatile uint64_t xen_clock_bias[MAXCPUS];
98 98
99#ifdef DOM0OPS 99#ifdef DOM0OPS
100/* If we're dom0, send our time to Xen every minute or so. */ 100/* If we're dom0, send our time to Xen every minute or so. */
101int xen_timepush_ticks = 0; 101int xen_timepush_ticks = 0;
102static callout_t xen_timepush_co; 102static callout_t xen_timepush_co;
103#endif 103#endif
104 104
105#define NS_PER_TICK (1000000000ULL/hz) 105#define NS_PER_TICK (1000000000ULL/hz)
106 106
107/* 107/*
108 * Reads a consistent set of time-base values from Xen, into a shadow data 108 * Reads a consistent set of time-base values from Xen, into a shadow data
109 * area. Must be called at splhigh (per timecounter requirements). 109 * area. Must be called at splhigh (per timecounter requirements).
110 */ 110 */
@@ -406,84 +406,90 @@ sysctl_xen_timepush(SYSCTLFN_ARGS) @@ -406,84 +406,90 @@ sysctl_xen_timepush(SYSCTLFN_ARGS)
406 callout_stop(&xen_timepush_co); 406 callout_stop(&xen_timepush_co);
407 } 407 }
408 408
409 return 0; 409 return 0;
410} 410}
411#endif 411#endif
412 412
413/* ARGSUSED */ 413/* ARGSUSED */
414/* SMP note: Timecounter uses vcpu0's clock */ 414/* SMP note: Timecounter uses vcpu0's clock */
415u_int 415u_int
416xen_get_timecount(struct timecounter *tc) 416xen_get_timecount(struct timecounter *tc)
417{ 417{
418 uint64_t ns; 418 uint64_t ns;
 419 struct cpu_info *ci = curcpu();
419 420
420 mutex_enter(&tmutex); 421 mutex_enter(&tmutex);
421 ns = get_system_time() - xen_clock_bias; 422 ns = get_vcpu_time(ci) - xen_clock_bias[ci->ci_cpuid];
422 mutex_exit(&tmutex); 423 mutex_exit(&tmutex);
423 424
424 return (u_int)ns; 425 return (u_int)ns;
425} 426}
426 427
427/*  428/*
428 * Needs to be called per-cpu, from the local cpu, since VIRQ_TIMER is 429 * Needs to be called per-cpu, from the local cpu, since VIRQ_TIMER is
429 * bound per-cpu 430 * bound per-cpu
430 */ 431 */
431 432
432static struct evcnt hardclock_called[MAXCPUS]; 433static struct evcnt hardclock_called[MAXCPUS];
433 434
434 435
435 436
436void 437void
437xen_initclocks(void) 438xen_initclocks(void)
438{ 439{
439 int err, evtch; 440 int err, evtch;
440 static bool tcdone = false; 441 static bool tcdone = false;
441 442
442 struct vcpu_set_periodic_timer hardclock_period = { NS_PER_TICK }; 
443 
444 struct cpu_info *ci = curcpu(); 443 struct cpu_info *ci = curcpu();
445 volatile struct shadow *shadow = &ci_shadow[ci->ci_cpuid]; 444 volatile struct shadow *shadow = &ci_shadow[ci->ci_cpuid];
446 445
447 xen_clock_bias = 0; 446 xen_clock_bias[ci->ci_cpuid] = 0;
448 447
449 evcnt_attach_dynamic(&hardclock_called[ci->ci_cpuid], 448 evcnt_attach_dynamic(&hardclock_called[ci->ci_cpuid],
450 EVCNT_TYPE_INTR, 449 EVCNT_TYPE_INTR,
451 NULL, 450 NULL,
452 device_xname(ci->ci_dev), 451 device_xname(ci->ci_dev),
453 "hardclock"); 452 "hardclock");
454 453
455#ifdef DOM0OPS 454#ifdef DOM0OPS
456 if (!tcdone) { /* Do this only once */ 455 if (!tcdone) { /* Do this only once */
457 callout_init(&xen_timepush_co, 0); 456 callout_init(&xen_timepush_co, 0);
458 } 457 }
459#endif 458#endif
460 evtch = bind_virq_to_evtch(VIRQ_TIMER); 459 evtch = bind_virq_to_evtch(VIRQ_TIMER);
461 aprint_verbose("Xen clock: using event channel %d\n", evtch); 460 aprint_verbose("Xen clock: using event channel %d\n", evtch);
462 461
463 get_time_values_from_xen(ci); 462 get_time_values_from_xen(ci);
464 vcpu_system_time[ci->ci_cpuid] = shadow->system_time; 463 vcpu_system_time[ci->ci_cpuid] = shadow->system_time;
465 if (!tcdone) { /* Do this only once */ 464 if (!tcdone) { /* Do this only once */
466 mutex_init(&tmutex, MUTEX_DEFAULT, IPL_CLOCK); 465 mutex_init(&tmutex, MUTEX_DEFAULT, IPL_CLOCK);
467 tc_init(&xen_timecounter); 466 tc_init(&xen_timecounter);
468 } 467 }
469 /* The splhigh requirements start here. */ 468 /* The splhigh requirements start here. */
470 469
471 /* Set hardclock() frequency */ 470 /*
472 err = HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, 471 * The periodic timer looks buggy, we stop receiving events
 472 * after a while. Use the one-shot timer every NS_PER_TICK
 473 * and rearm it from the event handler.
 474 */
 475 err = HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer,
473 ci->ci_cpuid, 476 ci->ci_cpuid,
474 &hardclock_period); 477 NULL);
475 478
476 KASSERT(err == 0); 479 KASSERT(err == 0);
 480 err = HYPERVISOR_set_timer_op(
 481 vcpu_system_time[ci->ci_cpuid] + NS_PER_TICK);
 482 KASSERT(err == 0);
477 483
478 event_set_handler(evtch, (int (*)(void *))xen_timer_handler, 484 event_set_handler(evtch, (int (*)(void *))xen_timer_handler,
479 ci, IPL_CLOCK, "clock"); 485 ci, IPL_CLOCK, "clock");
480 hypervisor_enable_event(evtch); 486 hypervisor_enable_event(evtch);
481 487
482#ifdef DOM0OPS 488#ifdef DOM0OPS
483 if (!tcdone) { /* Do this only once */ 489 if (!tcdone) { /* Do this only once */
484 490
485 xen_timepush_ticks = 53 * hz + 3; /* avoid exact # of min/sec */ 491 xen_timepush_ticks = 53 * hz + 3; /* avoid exact # of min/sec */
486 if (xendomain_is_privileged()) { 492 if (xendomain_is_privileged()) {
487 sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_READWRITE, 493 sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_READWRITE,
488 CTLTYPE_INT, "xen_timepush_ticks", SYSCTL_DESCR("How often" 494 CTLTYPE_INT, "xen_timepush_ticks", SYSCTL_DESCR("How often"
489 " to update the hypervisor's time-of-day; 0 to disable"), 495 " to update the hypervisor's time-of-day; 0 to disable"),
@@ -494,49 +500,70 @@ xen_initclocks(void) @@ -494,49 +500,70 @@ xen_initclocks(void)
494 } 500 }
495 } 501 }
496#endif 502#endif
497 tcdone = true; 503 tcdone = true;
498} 504}
499 505
500/* ARGSUSED */ 506/* ARGSUSED */
501static int 507static int
502xen_timer_handler(void *arg, struct intrframe *regs) 508xen_timer_handler(void *arg, struct intrframe *regs)
503{ 509{
504 int64_t delta; 510 int64_t delta;
505 struct cpu_info *ci = curcpu(); 511 struct cpu_info *ci = curcpu();
506 KASSERT(arg == ci); 512 KASSERT(arg == ci);
 513 int err;
 514again:
507 mutex_enter(&tmutex); 515 mutex_enter(&tmutex);
508 
509 delta = (int64_t)(get_vcpu_time(ci) - vcpu_system_time[ci->ci_cpuid]); 516 delta = (int64_t)(get_vcpu_time(ci) - vcpu_system_time[ci->ci_cpuid]);
510 
511 mutex_exit(&tmutex); 517 mutex_exit(&tmutex);
512 518
513 /* Several ticks may have passed without our being run; catch up. */ 519 /* Several ticks may have passed without our being run; catch up. */
514 while (delta >= (int64_t)NS_PER_TICK) { 520 while (delta >= (int64_t)NS_PER_TICK) {
515 mutex_enter(&tmutex); 521 mutex_enter(&tmutex);
516 vcpu_system_time[ci->ci_cpuid] += NS_PER_TICK; 522 vcpu_system_time[ci->ci_cpuid] += NS_PER_TICK;
517 xen_clock_bias = (delta -= NS_PER_TICK); 523 xen_clock_bias[ci->ci_cpuid] = (delta -= NS_PER_TICK);
518 mutex_exit(&tmutex); 524 mutex_exit(&tmutex);
519 hardclock((struct clockframe *)regs); 525 hardclock((struct clockframe *)regs);
520 hardclock_called[ci->ci_cpuid].ev_count++; 526 hardclock_called[ci->ci_cpuid].ev_count++;
521 } 527 }
 528
 529 /*
 530 * rearm the timer. If it fails it's probably because the date
 531 * is in the past, update our local time and try again.
 532 */
 533 err = HYPERVISOR_set_timer_op(
 534 vcpu_system_time[ci->ci_cpuid] + NS_PER_TICK);
 535 if (err)
 536 goto again;
522  537
523 if (xen_clock_bias) { 538 if (xen_clock_bias[ci->ci_cpuid]) {
524 mutex_enter(&tmutex); 539 mutex_enter(&tmutex);
525 xen_clock_bias = 0; 540 xen_clock_bias[ci->ci_cpuid] = 0;
526 mutex_exit(&tmutex); 541 mutex_exit(&tmutex);
527 } 542 }
528 543
529 return 0; 544 return 0;
530} 545}
531 546
532void 547void
533setstatclockrate(int arg) 548setstatclockrate(int arg)
534{ 549{
535} 550}
536 551
537void 552void
538idle_block(void) 553idle_block(void)
539{ 554{
 555#ifdef MULTIPROCESSOR
540 HYPERVISOR_yield(); 556 HYPERVISOR_yield();
541 __sti(); 557 __sti();
 558#else
 559 struct cpu_info *ci = curcpu();
 560 int r;
 561
 562 r = HYPERVISOR_set_timer_op(
 563 vcpu_system_time[ci->ci_cpuid] + NS_PER_TICK);
 564 if (r == 0)
 565 HYPERVISOR_block();
 566 else
 567 __sti();
 568#endif
542} 569}