@@ -130,6 +130,11 @@ static unsigned int mwait_substates __initdata;
#define flg2MWAIT(flags) (((flags) >> 24) & 0xFF)
#define MWAIT2flg(eax) ((eax & 0xFF) << 24)
+/*
+ * The maximum possible 'umwait' deadline value.
+ */
+#define UMWAIT_MAX_DEADLINE (~((u64)0))
+
static __always_inline int __intel_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
@@ -263,6 +268,32 @@ static __cpuidle int intel_idle_s2idle(struct cpuidle_device *dev,
return 0;
}
+/**
+ * intel_idle_umwait_irq - Request C0.x using the 'umwait' instruction.
+ * @dev: cpuidle device of the target CPU.
+ * @drv: cpuidle driver (assumed to point to intel_idle_driver).
+ * @index: Target idle state index.
+ *
+ * Request C0.1 or C0.2 using 'umwait' instruction with interrupts enabled.
+ */
+static __cpuidle int intel_idle_umwait_irq(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ u32 state = flg2MWAIT(drv->states[index].flags);
+
+ raw_local_irq_enable();
+ /*
+ * Use the maximum possible deadline value. This means that 'C0.x'
+ * residency will be limited by the global limit in
+ * 'IA32_UMWAIT_CONTROL'.
+ */
+ umwait_idle(UMWAIT_MAX_DEADLINE, state);
+ raw_local_irq_disable();
+
+ return index;
+}
+
/*
* States are indexed by the cstate number,
* which is also the index into the MWAIT hint array.
@@ -1006,6 +1037,13 @@ static struct cpuidle_state adl_n_cstates[] __initdata = {
};
static struct cpuidle_state spr_cstates[] __initdata = {
+ {
+ .name = "C0.2",
+ .desc = "UMWAIT C0.2",
+ .flags = MWAIT2flg(TPAUSE_C02_STATE) | CPUIDLE_FLAG_IRQ_ENABLE,
+ .exit_latency_ns = 200,
+ .target_residency_ns = 200,
+ .enter = &intel_idle_umwait_irq, },
{
.name = "C1",
.desc = "MWAIT 0x00",
@@ -1904,7 +1942,9 @@ static void state_update_enter_method(struct cpuidle_state *state, int cstate)
}
return;
}
- if (state->enter == intel_idle_hlt_irq_on)
+
+ if (state->enter == intel_idle_hlt_irq_on ||
+ state->enter == intel_idle_umwait_irq)
return; /* no update scenarios */
if (state->flags & CPUIDLE_FLAG_INIT_XSTATE) {
@@ -1959,6 +1999,8 @@ static bool should_verify_mwait(struct cpuidle_state *state)
return false;
if (state->enter == intel_idle_hlt_irq_on)
return false;
+ if (state->enter == intel_idle_umwait_irq)
+ return false;
return true;
}