diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kvm/i8254.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 3eddae692c05..09ae841ff462 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c | |||
@@ -98,6 +98,32 @@ static int pit_get_gate(struct kvm *kvm, int channel) | |||
98 | return kvm->arch.vpit->pit_state.channels[channel].gate; | 98 | return kvm->arch.vpit->pit_state.channels[channel].gate; |
99 | } | 99 | } |
100 | 100 | ||
101 | static s64 __kpit_elapsed(struct kvm *kvm) | ||
102 | { | ||
103 | s64 elapsed; | ||
104 | ktime_t remaining; | ||
105 | struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; | ||
106 | |||
107 | remaining = hrtimer_expires_remaining(&ps->pit_timer.timer); | ||
108 | if (ktime_to_ns(remaining) < 0) | ||
109 | remaining = ktime_set(0, 0); | ||
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 | |||
115 | return elapsed; | ||
116 | } | ||
117 | |||
118 | static s64 kpit_elapsed(struct kvm *kvm, struct kvm_kpit_channel_state *c, | ||
119 | int channel) | ||
120 | { | ||
121 | if (channel == 0) | ||
122 | return __kpit_elapsed(kvm); | ||
123 | |||
124 | return ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time)); | ||
125 | } | ||
126 | |||
101 | static int pit_get_count(struct kvm *kvm, int channel) | 127 | static int pit_get_count(struct kvm *kvm, int channel) |
102 | { | 128 | { |
103 | struct kvm_kpit_channel_state *c = | 129 | struct kvm_kpit_channel_state *c = |
@@ -107,7 +133,7 @@ static int pit_get_count(struct kvm *kvm, int channel) | |||
107 | 133 | ||
108 | WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); | 134 | WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); |
109 | 135 | ||
110 | t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time)); | 136 | t = kpit_elapsed(kvm, c, channel); |
111 | d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC); | 137 | d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC); |
112 | 138 | ||
113 | switch (c->mode) { | 139 | switch (c->mode) { |
@@ -137,7 +163,7 @@ static int pit_get_out(struct kvm *kvm, int channel) | |||
137 | 163 | ||
138 | WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); | 164 | WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock)); |
139 | 165 | ||
140 | t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time)); | 166 | t = kpit_elapsed(kvm, c, channel); |
141 | d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC); | 167 | d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC); |
142 | 168 | ||
143 | switch (c->mode) { | 169 | switch (c->mode) { |
@@ -208,8 +234,6 @@ static int __pit_timer_fn(struct kvm_kpit_state *ps) | |||
208 | wake_up_interruptible(&vcpu0->wq); | 234 | wake_up_interruptible(&vcpu0->wq); |
209 | 235 | ||
210 | hrtimer_add_expires_ns(&pt->timer, pt->period); | 236 | hrtimer_add_expires_ns(&pt->timer, pt->period); |
211 | if (pt->period) | ||
212 | ps->channels[0].count_load_time = ktime_get(); | ||
213 | 237 | ||
214 | return (pt->period == 0 ? 0 : 1); | 238 | return (pt->period == 0 ? 0 : 1); |
215 | } | 239 | } |
@@ -305,11 +329,12 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val) | |||
305 | if (val == 0) | 329 | if (val == 0) |
306 | val = 0x10000; | 330 | val = 0x10000; |
307 | 331 | ||
308 | ps->channels[channel].count_load_time = ktime_get(); | ||
309 | ps->channels[channel].count = val; | 332 | ps->channels[channel].count = val; |
310 | 333 | ||
311 | if (channel != 0) | 334 | if (channel != 0) { |
335 | ps->channels[channel].count_load_time = ktime_get(); | ||
312 | return; | 336 | return; |
337 | } | ||
313 | 338 | ||
314 | /* Two types of timer | 339 | /* Two types of timer |
315 | * mode 1 is one shot, mode 2 is period, otherwise del timer */ | 340 | * mode 1 is one shot, mode 2 is period, otherwise del timer */ |