@@ -475,6 +475,26 @@ static int lapic_next_deadline(unsigned long delta,
return 0;
}
+static bool lapic_event_expired(struct clock_event_device *evt)
+{
+ u32 cct;
+
+ cct = apic_read(APIC_TMCCT);
+ return cct == 0;
+}
+
+static bool lapic_deadline_expired(struct clock_event_device *evt)
+{
+ u64 msr;
+
+ /*
+ * When the timer interrupt is triggered, the register is cleared, so a
+ * non-zero value indicates a pending timer event.
+ */
+ rdmsrl(MSR_IA32_TSC_DEADLINE, msr);
+ return msr == 0;
+}
+
static int lapic_timer_shutdown(struct clock_event_device *evt)
{
unsigned int v;
@@ -529,12 +549,14 @@ static struct clock_event_device lapic_clockevent = {
.name = "lapic",
.features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP
- | CLOCK_EVT_FEAT_DUMMY,
+ | CLOCK_EVT_FEAT_DUMMY |
+ CLOCK_EVT_FEAT_FREEZE,
.shift = 32,
.set_state_shutdown = lapic_timer_shutdown,
.set_state_periodic = lapic_timer_set_periodic,
.set_state_oneshot = lapic_timer_set_oneshot,
.set_next_event = lapic_next_event,
+ .event_expired = lapic_event_expired,
.broadcast = lapic_timer_broadcast,
.rating = 100,
.irq = -1,
@@ -562,6 +584,7 @@ static void setup_APIC_timer(void)
levt->features &= ~(CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_DUMMY);
levt->set_next_event = lapic_next_deadline;
+ levt->event_expired = lapic_deadline_expired;
clockevents_config_and_register(levt,
(tsc_khz / TSC_DIVISOR) * 1000,
0xF, ~0UL);