| @@ -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 | |
85 | static kmutex_t tmutex; /* Protects volatile variables, below */ | | 85 | static 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 | */ |
90 | static volatile uint64_t vcpu_system_time[MAXCPUS]; | | 90 | static 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 | */ |
97 | static volatile uint64_t xen_clock_bias; | | 97 | static 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. */ |
101 | int xen_timepush_ticks = 0; | | 101 | int xen_timepush_ticks = 0; |
102 | static callout_t xen_timepush_co; | | 102 | static 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 */ |
415 | u_int | | 415 | u_int |
416 | xen_get_timecount(struct timecounter *tc) | | 416 | xen_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 | |
432 | static struct evcnt hardclock_called[MAXCPUS]; | | 433 | static struct evcnt hardclock_called[MAXCPUS]; |
433 | | | 434 | |
434 | | | 435 | |
435 | | | 436 | |
436 | void | | 437 | void |
437 | xen_initclocks(void) | | 438 | xen_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 */ |
501 | static int | | 507 | static int |
502 | xen_timer_handler(void *arg, struct intrframe *regs) | | 508 | xen_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; |
| | | 514 | again: |
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 | |
532 | void | | 547 | void |
533 | setstatclockrate(int arg) | | 548 | setstatclockrate(int arg) |
534 | { | | 549 | { |
535 | } | | 550 | } |
536 | | | 551 | |
537 | void | | 552 | void |
538 | idle_block(void) | | 553 | idle_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 | } |