diff options
| author | Radim Krčmář <rkrcmar@redhat.com> | 2015-06-05 14:57:41 -0400 |
|---|---|---|
| committer | Marcelo Tosatti <mtosatti@redhat.com> | 2015-06-16 00:01:10 -0400 |
| commit | b6ac069532218027f2991cba01d7a72a200688b0 (patch) | |
| tree | 20fe5cec8209421ed53c1e74b905e94e1057c6b9 /arch/x86 | |
| parent | d4a4f75cd8f29cd9464a5a32e9224a91571d6649 (diff) | |
KVM: x86: fix lapic.timer_mode on restore
lapic.timer_mode was not properly initialized after migration, which
broke few useful things, like login, by making every sleep eternal.
Fix this by calling apic_update_lvtt in kvm_apic_post_state_restore.
There are other slowpaths that update lvtt, so this patch makes sure
something similar doesn't happen again by calling apic_update_lvtt
after every modification.
Cc: stable@vger.kernel.org
Fixes: f30ebc312ca9 ("KVM: x86: optimize some accesses to LVTT and SPIV")
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86')
| -rw-r--r-- | arch/x86/kvm/lapic.c | 26 |
1 files changed, 16 insertions, 10 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 629af0f1c5c4..4c7deb4f78a1 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
| @@ -1090,6 +1090,17 @@ static void update_divide_count(struct kvm_lapic *apic) | |||
| 1090 | apic->divide_count); | 1090 | apic->divide_count); |
| 1091 | } | 1091 | } |
| 1092 | 1092 | ||
| 1093 | static void apic_update_lvtt(struct kvm_lapic *apic) | ||
| 1094 | { | ||
| 1095 | u32 timer_mode = kvm_apic_get_reg(apic, APIC_LVTT) & | ||
| 1096 | apic->lapic_timer.timer_mode_mask; | ||
| 1097 | |||
| 1098 | if (apic->lapic_timer.timer_mode != timer_mode) { | ||
| 1099 | apic->lapic_timer.timer_mode = timer_mode; | ||
| 1100 | hrtimer_cancel(&apic->lapic_timer.timer); | ||
| 1101 | } | ||
| 1102 | } | ||
| 1103 | |||
| 1093 | static void apic_timer_expired(struct kvm_lapic *apic) | 1104 | static void apic_timer_expired(struct kvm_lapic *apic) |
| 1094 | { | 1105 | { |
| 1095 | struct kvm_vcpu *vcpu = apic->vcpu; | 1106 | struct kvm_vcpu *vcpu = apic->vcpu; |
| @@ -1298,6 +1309,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) | |||
| 1298 | apic_set_reg(apic, APIC_LVTT + 0x10 * i, | 1309 | apic_set_reg(apic, APIC_LVTT + 0x10 * i, |
| 1299 | lvt_val | APIC_LVT_MASKED); | 1310 | lvt_val | APIC_LVT_MASKED); |
| 1300 | } | 1311 | } |
| 1312 | apic_update_lvtt(apic); | ||
| 1301 | atomic_set(&apic->lapic_timer.pending, 0); | 1313 | atomic_set(&apic->lapic_timer.pending, 0); |
| 1302 | 1314 | ||
| 1303 | } | 1315 | } |
| @@ -1330,20 +1342,13 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) | |||
| 1330 | 1342 | ||
| 1331 | break; | 1343 | break; |
| 1332 | 1344 | ||
| 1333 | case APIC_LVTT: { | 1345 | case APIC_LVTT: |
| 1334 | u32 timer_mode = val & apic->lapic_timer.timer_mode_mask; | ||
| 1335 | |||
| 1336 | if (apic->lapic_timer.timer_mode != timer_mode) { | ||
| 1337 | apic->lapic_timer.timer_mode = timer_mode; | ||
| 1338 | hrtimer_cancel(&apic->lapic_timer.timer); | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | if (!kvm_apic_sw_enabled(apic)) | 1346 | if (!kvm_apic_sw_enabled(apic)) |
| 1342 | val |= APIC_LVT_MASKED; | 1347 | val |= APIC_LVT_MASKED; |
| 1343 | val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask); | 1348 | val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask); |
| 1344 | apic_set_reg(apic, APIC_LVTT, val); | 1349 | apic_set_reg(apic, APIC_LVTT, val); |
| 1350 | apic_update_lvtt(apic); | ||
| 1345 | break; | 1351 | break; |
| 1346 | } | ||
| 1347 | 1352 | ||
| 1348 | case APIC_TMICT: | 1353 | case APIC_TMICT: |
| 1349 | if (apic_lvtt_tscdeadline(apic)) | 1354 | if (apic_lvtt_tscdeadline(apic)) |
| @@ -1576,7 +1581,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) | |||
| 1576 | 1581 | ||
| 1577 | for (i = 0; i < APIC_LVT_NUM; i++) | 1582 | for (i = 0; i < APIC_LVT_NUM; i++) |
| 1578 | apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); | 1583 | apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); |
| 1579 | apic->lapic_timer.timer_mode = 0; | 1584 | apic_update_lvtt(apic); |
| 1580 | apic_set_reg(apic, APIC_LVT0, | 1585 | apic_set_reg(apic, APIC_LVT0, |
| 1581 | SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); | 1586 | SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); |
| 1582 | 1587 | ||
| @@ -1802,6 +1807,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu, | |||
| 1802 | 1807 | ||
| 1803 | apic_update_ppr(apic); | 1808 | apic_update_ppr(apic); |
| 1804 | hrtimer_cancel(&apic->lapic_timer.timer); | 1809 | hrtimer_cancel(&apic->lapic_timer.timer); |
| 1810 | apic_update_lvtt(apic); | ||
| 1805 | update_divide_count(apic); | 1811 | update_divide_count(apic); |
| 1806 | start_apic_timer(apic); | 1812 | start_apic_timer(apic); |
| 1807 | apic->irr_pending = true; | 1813 | apic->irr_pending = true; |
