diff options
-rw-r--r-- | drivers/idle/intel_idle.c | 59 |
1 files changed, 37 insertions, 22 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 938c17f25d94..aa2d19db2b1d 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -66,8 +66,9 @@ static struct cpuidle_driver intel_idle_driver = { }; /* intel_idle.max_cstate=0 disables driver */ static int max_cstate = CPUIDLE_STATE_MAX - 1; -static unsigned int disabled_states_mask; -static unsigned int preferred_states_mask; +static unsigned int disabled_states_mask __read_mostly; +static unsigned int preferred_states_mask __read_mostly; +static bool force_irq_on __read_mostly; static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; @@ -1838,9 +1839,6 @@ static bool __init intel_idle_verify_cstate(unsigned int mwait_hint) return true; } -static bool force_irq_on __read_mostly; -module_param(force_irq_on, bool, 0444); - static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv) { int cstate; @@ -1871,6 +1869,7 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv) } for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { + struct cpuidle_state *state; unsigned int mwait_hint; if (intel_idle_max_cstate_reached(cstate)) @@ -1893,29 +1892,39 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv) /* Structure copy. */ drv->states[drv->state_count] = cpuidle_state_table[cstate]; - - if ((cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE) || force_irq_on) { - printk("intel_idle: forced intel_idle_irq for state %d\n", cstate); - drv->states[drv->state_count].enter = intel_idle_irq; - } - - if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) && - cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IBRS) { - WARN_ON_ONCE(cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE); - drv->states[drv->state_count].enter = intel_idle_ibrs; + state = &drv->states[drv->state_count]; + + if (state->flags & CPUIDLE_FLAG_INIT_XSTATE) { + /* + * Combining with XSTATE with IBRS or IRQ_ENABLE flags + * is not currently supported but this driver. + */ + WARN_ON_ONCE(state->flags & CPUIDLE_FLAG_IBRS); + WARN_ON_ONCE(state->flags & CPUIDLE_FLAG_IRQ_ENABLE); + state->enter = intel_idle_xstate; + } else if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) && + state->flags & CPUIDLE_FLAG_IBRS) { + /* + * IBRS mitigation requires that C-states are entered + * with interrupts disabled. + */ + WARN_ON_ONCE(state->flags & CPUIDLE_FLAG_IRQ_ENABLE); + state->enter = intel_idle_ibrs; + } else if (state->flags & CPUIDLE_FLAG_IRQ_ENABLE) { + state->enter = intel_idle_irq; + } else if (force_irq_on) { + pr_info("forced intel_idle_irq for state %d\n", cstate); + state->enter = intel_idle_irq; } - if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_INIT_XSTATE) - drv->states[drv->state_count].enter = intel_idle_xstate; - if ((disabled_states_mask & BIT(drv->state_count)) || ((icpu->use_acpi || force_use_acpi) && intel_idle_off_by_default(mwait_hint) && - !(cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_ALWAYS_ENABLE))) - drv->states[drv->state_count].flags |= CPUIDLE_FLAG_OFF; + !(state->flags & CPUIDLE_FLAG_ALWAYS_ENABLE))) + state->flags |= CPUIDLE_FLAG_OFF; - if (intel_idle_state_needs_timer_stop(&drv->states[drv->state_count])) - drv->states[drv->state_count].flags |= CPUIDLE_FLAG_TIMER_STOP; + if (intel_idle_state_needs_timer_stop(state)) + state->flags |= CPUIDLE_FLAG_TIMER_STOP; drv->state_count++; } @@ -2146,3 +2155,9 @@ MODULE_PARM_DESC(states_off, "Mask of disabled idle states"); */ module_param_named(preferred_cstates, preferred_states_mask, uint, 0444); MODULE_PARM_DESC(preferred_cstates, "Mask of preferred idle states"); +/* + * Debugging option that forces the driver to enter all C-states with + * interrupts enabled. Does not apply to C-states with + * 'CPUIDLE_FLAG_INIT_XSTATE' and 'CPUIDLE_FLAG_IBRS' flags. + */ +module_param(force_irq_on, bool, 0444); |