aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/lapic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r--arch/x86/kvm/lapic.c91
1 files changed, 70 insertions, 21 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 36c90d631096..943acbf00c69 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1301,14 +1301,42 @@ static void update_divide_count(struct kvm_lapic *apic)
1301 apic->divide_count); 1301 apic->divide_count);
1302} 1302}
1303 1303
1304static void limit_periodic_timer_frequency(struct kvm_lapic *apic)
1305{
1306 /*
1307 * Do not allow the guest to program periodic timers with small
1308 * interval, since the hrtimers are not throttled by the host
1309 * scheduler.
1310 */
1311 if (apic_lvtt_period(apic) && apic->lapic_timer.period) {
1312 s64 min_period = min_timer_period_us * 1000LL;
1313
1314 if (apic->lapic_timer.period < min_period) {
1315 pr_info_ratelimited(
1316 "kvm: vcpu %i: requested %lld ns "
1317 "lapic timer period limited to %lld ns\n",
1318 apic->vcpu->vcpu_id,
1319 apic->lapic_timer.period, min_period);
1320 apic->lapic_timer.period = min_period;
1321 }
1322 }
1323}
1324
1304static void apic_update_lvtt(struct kvm_lapic *apic) 1325static void apic_update_lvtt(struct kvm_lapic *apic)
1305{ 1326{
1306 u32 timer_mode = kvm_lapic_get_reg(apic, APIC_LVTT) & 1327 u32 timer_mode = kvm_lapic_get_reg(apic, APIC_LVTT) &
1307 apic->lapic_timer.timer_mode_mask; 1328 apic->lapic_timer.timer_mode_mask;
1308 1329
1309 if (apic->lapic_timer.timer_mode != timer_mode) { 1330 if (apic->lapic_timer.timer_mode != timer_mode) {
1331 if (apic_lvtt_tscdeadline(apic) != (timer_mode ==
1332 APIC_LVT_TIMER_TSCDEADLINE)) {
1333 hrtimer_cancel(&apic->lapic_timer.timer);
1334 kvm_lapic_set_reg(apic, APIC_TMICT, 0);
1335 apic->lapic_timer.period = 0;
1336 apic->lapic_timer.tscdeadline = 0;
1337 }
1310 apic->lapic_timer.timer_mode = timer_mode; 1338 apic->lapic_timer.timer_mode = timer_mode;
1311 hrtimer_cancel(&apic->lapic_timer.timer); 1339 limit_periodic_timer_frequency(apic);
1312 } 1340 }
1313} 1341}
1314 1342
@@ -1430,6 +1458,30 @@ static void start_sw_period(struct kvm_lapic *apic)
1430 HRTIMER_MODE_ABS_PINNED); 1458 HRTIMER_MODE_ABS_PINNED);
1431} 1459}
1432 1460
1461static void update_target_expiration(struct kvm_lapic *apic, uint32_t old_divisor)
1462{
1463 ktime_t now, remaining;
1464 u64 ns_remaining_old, ns_remaining_new;
1465
1466 apic->lapic_timer.period = (u64)kvm_lapic_get_reg(apic, APIC_TMICT)
1467 * APIC_BUS_CYCLE_NS * apic->divide_count;
1468 limit_periodic_timer_frequency(apic);
1469
1470 now = ktime_get();
1471 remaining = ktime_sub(apic->lapic_timer.target_expiration, now);
1472 if (ktime_to_ns(remaining) < 0)
1473 remaining = 0;
1474
1475 ns_remaining_old = ktime_to_ns(remaining);
1476 ns_remaining_new = mul_u64_u32_div(ns_remaining_old,
1477 apic->divide_count, old_divisor);
1478
1479 apic->lapic_timer.tscdeadline +=
1480 nsec_to_cycles(apic->vcpu, ns_remaining_new) -
1481 nsec_to_cycles(apic->vcpu, ns_remaining_old);
1482 apic->lapic_timer.target_expiration = ktime_add_ns(now, ns_remaining_new);
1483}
1484
1433static bool set_target_expiration(struct kvm_lapic *apic) 1485static bool set_target_expiration(struct kvm_lapic *apic)
1434{ 1486{
1435 ktime_t now; 1487 ktime_t now;
@@ -1439,27 +1491,13 @@ static bool set_target_expiration(struct kvm_lapic *apic)
1439 apic->lapic_timer.period = (u64)kvm_lapic_get_reg(apic, APIC_TMICT) 1491 apic->lapic_timer.period = (u64)kvm_lapic_get_reg(apic, APIC_TMICT)
1440 * APIC_BUS_CYCLE_NS * apic->divide_count; 1492 * APIC_BUS_CYCLE_NS * apic->divide_count;
1441 1493
1442 if (!apic->lapic_timer.period) 1494 if (!apic->lapic_timer.period) {
1495 apic->lapic_timer.tscdeadline = 0;
1443 return false; 1496 return false;
1444
1445 /*
1446 * Do not allow the guest to program periodic timers with small
1447 * interval, since the hrtimers are not throttled by the host
1448 * scheduler.
1449 */
1450 if (apic_lvtt_period(apic)) {
1451 s64 min_period = min_timer_period_us * 1000LL;
1452
1453 if (apic->lapic_timer.period < min_period) {
1454 pr_info_ratelimited(
1455 "kvm: vcpu %i: requested %lld ns "
1456 "lapic timer period limited to %lld ns\n",
1457 apic->vcpu->vcpu_id,
1458 apic->lapic_timer.period, min_period);
1459 apic->lapic_timer.period = min_period;
1460 }
1461 } 1497 }
1462 1498
1499 limit_periodic_timer_frequency(apic);
1500
1463 apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" 1501 apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
1464 PRIx64 ", " 1502 PRIx64 ", "
1465 "timer initial count 0x%x, period %lldns, " 1503 "timer initial count 0x%x, period %lldns, "
@@ -1515,6 +1553,9 @@ static bool start_hv_timer(struct kvm_lapic *apic)
1515 if (!apic_lvtt_period(apic) && atomic_read(&ktimer->pending)) 1553 if (!apic_lvtt_period(apic) && atomic_read(&ktimer->pending))
1516 return false; 1554 return false;
1517 1555
1556 if (!ktimer->tscdeadline)
1557 return false;
1558
1518 r = kvm_x86_ops->set_hv_timer(apic->vcpu, ktimer->tscdeadline); 1559 r = kvm_x86_ops->set_hv_timer(apic->vcpu, ktimer->tscdeadline);
1519 if (r < 0) 1560 if (r < 0)
1520 return false; 1561 return false;
@@ -1738,13 +1779,21 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
1738 start_apic_timer(apic); 1779 start_apic_timer(apic);
1739 break; 1780 break;
1740 1781
1741 case APIC_TDCR: 1782 case APIC_TDCR: {
1783 uint32_t old_divisor = apic->divide_count;
1784
1742 if (val & 4) 1785 if (val & 4)
1743 apic_debug("KVM_WRITE:TDCR %x\n", val); 1786 apic_debug("KVM_WRITE:TDCR %x\n", val);
1744 kvm_lapic_set_reg(apic, APIC_TDCR, val); 1787 kvm_lapic_set_reg(apic, APIC_TDCR, val);
1745 update_divide_count(apic); 1788 update_divide_count(apic);
1789 if (apic->divide_count != old_divisor &&
1790 apic->lapic_timer.period) {
1791 hrtimer_cancel(&apic->lapic_timer.timer);
1792 update_target_expiration(apic, old_divisor);
1793 restart_apic_timer(apic);
1794 }
1746 break; 1795 break;
1747 1796 }
1748 case APIC_ESR: 1797 case APIC_ESR:
1749 if (apic_x2apic_mode(apic) && val != 0) { 1798 if (apic_x2apic_mode(apic) && val != 0) {
1750 apic_debug("KVM_WRITE:ESR not zero %x\n", val); 1799 apic_debug("KVM_WRITE:ESR not zero %x\n", val);