diff options
author | Marcelo Tosatti <mtosatti@redhat.com> | 2009-04-08 12:14:19 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-06-10 04:48:39 -0400 |
commit | ede2ccc51742059d356d419260460cbbf3e36273 (patch) | |
tree | 9a38010c1d6c2fcdb3d566b2d154d5f8f6a14680 /arch/x86/kvm/i8254.c | |
parent | 2906e79f21a559e49611e1e188c4993cd45d9ce1 (diff) |
KVM: PIT: fix count read and mode 0 handling
Commit 46ee278652f4cbd51013471b64c7897ba9bcd1b1 causes Solaris 10
to hang on boot.
Assuming that PIT counter reads should return 0 for an expired timer
is wrong: when it is active, the counter never stops (see comment on
__kpit_elapsed).
Also arm a one shot timer for mode 0.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/i8254.c')
-rw-r--r-- | arch/x86/kvm/i8254.c | 26 |
1 files changed, 15 insertions, 11 deletions
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index cf09bb64f14..4d6f0d293ee 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c | |||
@@ -104,13 +104,18 @@ static s64 __kpit_elapsed(struct kvm *kvm) | |||
104 | ktime_t remaining; | 104 | ktime_t remaining; |
105 | struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; | 105 | struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; |
106 | 106 | ||
107 | /* | ||
108 | * The Counter does not stop when it reaches zero. In | ||
109 | * Modes 0, 1, 4, and 5 the Counter ``wraps around'' to | ||
110 | * the highest count, either FFFF hex for binary counting | ||
111 | * or 9999 for BCD counting, and continues counting. | ||
112 | * Modes 2 and 3 are periodic; the Counter reloads | ||
113 | * itself with the initial count and continues counting | ||
114 | * from there. | ||
115 | */ | ||
107 | remaining = hrtimer_expires_remaining(&ps->pit_timer.timer); | 116 | remaining = hrtimer_expires_remaining(&ps->pit_timer.timer); |
108 | if (ktime_to_ns(remaining) < 0) | 117 | elapsed = ps->pit_timer.period - ktime_to_ns(remaining); |
109 | remaining = ktime_set(0, 0); | 118 | elapsed = mod_64(elapsed, ps->pit_timer.period); |
110 | |||
111 | elapsed = ps->pit_timer.period; | ||
112 | if (ktime_to_ns(remaining) <= ps->pit_timer.period) | ||
113 | elapsed = ps->pit_timer.period - ktime_to_ns(remaining); | ||
114 | 119 | ||
115 | return elapsed; | 120 | return elapsed; |
116 | } | 121 | } |
@@ -280,7 +285,7 @@ static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period) | |||
280 | 285 | ||
281 | /* TODO The new value only affected after the retriggered */ | 286 | /* TODO The new value only affected after the retriggered */ |
282 | hrtimer_cancel(&pt->timer); | 287 | hrtimer_cancel(&pt->timer); |
283 | pt->period = (is_period == 0) ? 0 : interval; | 288 | pt->period = interval; |
284 | ps->is_periodic = is_period; | 289 | ps->is_periodic = is_period; |
285 | 290 | ||
286 | pt->timer.function = kvm_timer_fn; | 291 | pt->timer.function = kvm_timer_fn; |
@@ -304,10 +309,8 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val) | |||
304 | pr_debug("pit: load_count val is %d, channel is %d\n", val, channel); | 309 | pr_debug("pit: load_count val is %d, channel is %d\n", val, channel); |
305 | 310 | ||
306 | /* | 311 | /* |
307 | * Though spec said the state of 8254 is undefined after power-up, | 312 | * The largest possible initial count is 0; this is equivalent |
308 | * seems some tricky OS like Windows XP depends on IRQ0 interrupt | 313 | * to 216 for binary counting and 104 for BCD counting. |
309 | * when booting up. | ||
310 | * So here setting initialize rate for it, and not a specific number | ||
311 | */ | 314 | */ |
312 | if (val == 0) | 315 | if (val == 0) |
313 | val = 0x10000; | 316 | val = 0x10000; |
@@ -322,6 +325,7 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val) | |||
322 | /* Two types of timer | 325 | /* Two types of timer |
323 | * mode 1 is one shot, mode 2 is period, otherwise del timer */ | 326 | * mode 1 is one shot, mode 2 is period, otherwise del timer */ |
324 | switch (ps->channels[0].mode) { | 327 | switch (ps->channels[0].mode) { |
328 | case 0: | ||
325 | case 1: | 329 | case 1: |
326 | /* FIXME: enhance mode 4 precision */ | 330 | /* FIXME: enhance mode 4 precision */ |
327 | case 4: | 331 | case 4: |