@@ -1090,7 +1090,7 @@ static void apic_send_ipi(struct kvm_lapic *apic)
1090
1090
1091
1091
static u32 apic_get_tmcct (struct kvm_lapic * apic )
1092
1092
{
1093
- ktime_t remaining ;
1093
+ ktime_t remaining , now ;
1094
1094
s64 ns ;
1095
1095
u32 tmcct ;
1096
1096
@@ -1101,7 +1101,8 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
1101
1101
apic -> lapic_timer .period == 0 )
1102
1102
return 0 ;
1103
1103
1104
- remaining = hrtimer_get_remaining (& apic -> lapic_timer .timer );
1104
+ now = apic -> lapic_timer .timer .base -> get_time ();
1105
+ remaining = ktime_sub (apic -> lapic_timer .target_expiration , now );
1105
1106
if (ktime_to_ns (remaining ) < 0 )
1106
1107
remaining = ktime_set (0 , 0 );
1107
1108
@@ -1348,16 +1349,34 @@ static void start_sw_tscdeadline(struct kvm_lapic *apic)
1348
1349
}
1349
1350
1350
1351
static void start_sw_period (struct kvm_lapic * apic )
1352
+ {
1353
+ if (!apic -> lapic_timer .period )
1354
+ return ;
1355
+
1356
+ if (apic_lvtt_oneshot (apic ) &&
1357
+ ktime_after (apic -> lapic_timer .timer .base -> get_time (),
1358
+ apic -> lapic_timer .target_expiration )) {
1359
+ apic_timer_expired (apic );
1360
+ return ;
1361
+ }
1362
+
1363
+ hrtimer_start (& apic -> lapic_timer .timer ,
1364
+ apic -> lapic_timer .target_expiration ,
1365
+ HRTIMER_MODE_ABS_PINNED );
1366
+ }
1367
+
1368
+ static bool set_target_expiration (struct kvm_lapic * apic )
1351
1369
{
1352
1370
ktime_t now ;
1371
+ u64 tscl = rdtsc ();
1353
1372
1354
- /* lapic timer in oneshot or periodic mode */
1355
1373
now = apic -> lapic_timer .timer .base -> get_time ();
1356
1374
apic -> lapic_timer .period = (u64 )kvm_lapic_get_reg (apic , APIC_TMICT )
1357
- * APIC_BUS_CYCLE_NS * apic -> divide_count ;
1375
+ * APIC_BUS_CYCLE_NS * apic -> divide_count ;
1358
1376
1359
1377
if (!apic -> lapic_timer .period )
1360
- return ;
1378
+ return false;
1379
+
1361
1380
/*
1362
1381
* Do not allow the guest to program periodic timers with small
1363
1382
* interval, since the hrtimers are not throttled by the host
@@ -1376,10 +1395,6 @@ static void start_sw_period(struct kvm_lapic *apic)
1376
1395
}
1377
1396
}
1378
1397
1379
- hrtimer_start (& apic -> lapic_timer .timer ,
1380
- ktime_add_ns (now , apic -> lapic_timer .period ),
1381
- HRTIMER_MODE_ABS_PINNED );
1382
-
1383
1398
apic_debug ("%s: bus cycle is %" PRId64 "ns, now 0x%016"
1384
1399
PRIx64 ", "
1385
1400
"timer initial count 0x%x, period %lldns, "
@@ -1389,6 +1404,21 @@ static void start_sw_period(struct kvm_lapic *apic)
1389
1404
apic -> lapic_timer .period ,
1390
1405
ktime_to_ns (ktime_add_ns (now ,
1391
1406
apic -> lapic_timer .period )));
1407
+
1408
+ apic -> lapic_timer .tscdeadline = kvm_read_l1_tsc (apic -> vcpu , tscl ) +
1409
+ nsec_to_cycles (apic -> vcpu , apic -> lapic_timer .period );
1410
+ apic -> lapic_timer .target_expiration = ktime_add_ns (now , apic -> lapic_timer .period );
1411
+
1412
+ return true;
1413
+ }
1414
+
1415
+ static void advance_periodic_target_expiration (struct kvm_lapic * apic )
1416
+ {
1417
+ apic -> lapic_timer .tscdeadline +=
1418
+ nsec_to_cycles (apic -> vcpu , apic -> lapic_timer .period );
1419
+ apic -> lapic_timer .target_expiration =
1420
+ ktime_add_ns (apic -> lapic_timer .target_expiration ,
1421
+ apic -> lapic_timer .period );
1392
1422
}
1393
1423
1394
1424
bool kvm_lapic_hv_timer_in_use (struct kvm_vcpu * vcpu )
@@ -1406,22 +1436,12 @@ static void cancel_hv_timer(struct kvm_lapic *apic)
1406
1436
apic -> lapic_timer .hv_timer_in_use = false;
1407
1437
}
1408
1438
1409
- void kvm_lapic_expired_hv_timer (struct kvm_vcpu * vcpu )
1410
- {
1411
- struct kvm_lapic * apic = vcpu -> arch .apic ;
1412
-
1413
- WARN_ON (!apic -> lapic_timer .hv_timer_in_use );
1414
- WARN_ON (swait_active (& vcpu -> wq ));
1415
- cancel_hv_timer (apic );
1416
- apic_timer_expired (apic );
1417
- }
1418
- EXPORT_SYMBOL_GPL (kvm_lapic_expired_hv_timer );
1419
-
1420
1439
static bool start_hv_timer (struct kvm_lapic * apic )
1421
1440
{
1422
1441
u64 tscdeadline = apic -> lapic_timer .tscdeadline ;
1423
1442
1424
- if (atomic_read (& apic -> lapic_timer .pending ) ||
1443
+ if ((atomic_read (& apic -> lapic_timer .pending ) &&
1444
+ !apic_lvtt_period (apic )) ||
1425
1445
kvm_x86_ops -> set_hv_timer (apic -> vcpu , tscdeadline )) {
1426
1446
if (apic -> lapic_timer .hv_timer_in_use )
1427
1447
cancel_hv_timer (apic );
@@ -1430,22 +1450,39 @@ static bool start_hv_timer(struct kvm_lapic *apic)
1430
1450
hrtimer_cancel (& apic -> lapic_timer .timer );
1431
1451
1432
1452
/* In case the sw timer triggered in the window */
1433
- if (atomic_read (& apic -> lapic_timer .pending ))
1453
+ if (atomic_read (& apic -> lapic_timer .pending ) &&
1454
+ !apic_lvtt_period (apic ))
1434
1455
cancel_hv_timer (apic );
1435
1456
}
1436
1457
trace_kvm_hv_timer_state (apic -> vcpu -> vcpu_id ,
1437
1458
apic -> lapic_timer .hv_timer_in_use );
1438
1459
return apic -> lapic_timer .hv_timer_in_use ;
1439
1460
}
1440
1461
1462
+ void kvm_lapic_expired_hv_timer (struct kvm_vcpu * vcpu )
1463
+ {
1464
+ struct kvm_lapic * apic = vcpu -> arch .apic ;
1465
+
1466
+ WARN_ON (!apic -> lapic_timer .hv_timer_in_use );
1467
+ WARN_ON (swait_active (& vcpu -> wq ));
1468
+ cancel_hv_timer (apic );
1469
+ apic_timer_expired (apic );
1470
+
1471
+ if (apic_lvtt_period (apic ) && apic -> lapic_timer .period ) {
1472
+ advance_periodic_target_expiration (apic );
1473
+ if (!start_hv_timer (apic ))
1474
+ start_sw_period (apic );
1475
+ }
1476
+ }
1477
+ EXPORT_SYMBOL_GPL (kvm_lapic_expired_hv_timer );
1478
+
1441
1479
void kvm_lapic_switch_to_hv_timer (struct kvm_vcpu * vcpu )
1442
1480
{
1443
1481
struct kvm_lapic * apic = vcpu -> arch .apic ;
1444
1482
1445
1483
WARN_ON (apic -> lapic_timer .hv_timer_in_use );
1446
1484
1447
- if (apic_lvtt_tscdeadline (apic ))
1448
- start_hv_timer (apic );
1485
+ start_hv_timer (apic );
1449
1486
}
1450
1487
EXPORT_SYMBOL_GPL (kvm_lapic_switch_to_hv_timer );
1451
1488
@@ -1462,17 +1499,22 @@ void kvm_lapic_switch_to_sw_timer(struct kvm_vcpu *vcpu)
1462
1499
if (atomic_read (& apic -> lapic_timer .pending ))
1463
1500
return ;
1464
1501
1465
- start_sw_tscdeadline (apic );
1502
+ if (apic_lvtt_period (apic ) || apic_lvtt_oneshot (apic ))
1503
+ start_sw_period (apic );
1504
+ else if (apic_lvtt_tscdeadline (apic ))
1505
+ start_sw_tscdeadline (apic );
1466
1506
}
1467
1507
EXPORT_SYMBOL_GPL (kvm_lapic_switch_to_sw_timer );
1468
1508
1469
1509
static void start_apic_timer (struct kvm_lapic * apic )
1470
1510
{
1471
1511
atomic_set (& apic -> lapic_timer .pending , 0 );
1472
1512
1473
- if (apic_lvtt_period (apic ) || apic_lvtt_oneshot (apic ))
1474
- start_sw_period (apic );
1475
- else if (apic_lvtt_tscdeadline (apic )) {
1513
+ if (apic_lvtt_period (apic ) || apic_lvtt_oneshot (apic )) {
1514
+ if (set_target_expiration (apic ) &&
1515
+ !(kvm_x86_ops -> set_hv_timer && start_hv_timer (apic )))
1516
+ start_sw_period (apic );
1517
+ } else if (apic_lvtt_tscdeadline (apic )) {
1476
1518
if (!(kvm_x86_ops -> set_hv_timer && start_hv_timer (apic )))
1477
1519
start_sw_tscdeadline (apic );
1478
1520
}
@@ -1923,6 +1965,7 @@ static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
1923
1965
apic_timer_expired (apic );
1924
1966
1925
1967
if (lapic_is_periodic (apic )) {
1968
+ advance_periodic_target_expiration (apic );
1926
1969
hrtimer_add_expires_ns (& ktimer -> timer , ktimer -> period );
1927
1970
return HRTIMER_RESTART ;
1928
1971
} else
@@ -2007,6 +2050,10 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
2007
2050
kvm_apic_local_deliver (apic , APIC_LVTT );
2008
2051
if (apic_lvtt_tscdeadline (apic ))
2009
2052
apic -> lapic_timer .tscdeadline = 0 ;
2053
+ if (apic_lvtt_oneshot (apic )) {
2054
+ apic -> lapic_timer .tscdeadline = 0 ;
2055
+ apic -> lapic_timer .target_expiration = ktime_set (0 , 0 );
2056
+ }
2010
2057
atomic_set (& apic -> lapic_timer .pending , 0 );
2011
2058
}
2012
2059
}
0 commit comments