@@ -439,7 +439,7 @@ static void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
mwait_idle_with_hints(cx->address, MWAIT_ECX_INTERRUPT_BREAK);
}
-static void acpi_idle_do_entry(struct acpi_processor_cx *cx)
+void acpi_idle_do_entry(struct acpi_processor_cx *cx)
{
struct cpu_info *info = get_cpu_info();
@@ -103,6 +103,11 @@ static const struct cpuidle_state {
#define CPUIDLE_FLAG_DISABLED 0x1
/*
+ * On certain AMD families that support mwait, only c1 can be reached by
+ * mwait and to reach c2, halt has to be used.
+ */
+#define CPUIDLE_FLAG_USE_HALT 0x2
+/*
* Set this flag for states where the HW flushes the TLB for us
* and so we don't need cross-calls to keep it consistent.
* If this flag is set, SW flushes the TLB, so even if the
@@ -784,7 +789,7 @@ static void mwait_idle(void)
update_last_cx_stat(power, cx, before);
if (cpu_is_haltable(cpu))
- mwait_idle_with_hints(eax, MWAIT_ECX_INTERRUPT_BREAK);
+ acpi_idle_do_entry(cx);
after = cpuidle_get_tick();
@@ -1184,8 +1189,9 @@ static int mwait_idle_cpu_init(struct notifier_block *nfb,
for (cstate = 0; cpuidle_state_table[cstate].target_residency; ++cstate) {
unsigned int num_substates, hint, state;
struct acpi_processor_cx *cx;
+ const unsigned int cflags = cpuidle_state_table[cstate].flags;
- hint = flg2MWAIT(cpuidle_state_table[cstate].flags);
+ hint = flg2MWAIT(cflags);
state = MWAIT_HINT2CSTATE(hint) + 1;
if (state > max_cstate) {
@@ -1196,13 +1202,13 @@ static int mwait_idle_cpu_init(struct notifier_block *nfb,
/* Number of sub-states for this state in CPUID.MWAIT. */
num_substates = (mwait_substates >> (state * 4))
& MWAIT_SUBSTATE_MASK;
+
/* If NO sub-states for this state in CPUID, skip it. */
- if (num_substates == 0)
+ if (num_substates == 0 && !(cflags & CPUIDLE_FLAG_USE_HALT))
continue;
/* if state marked as disabled, skip it */
- if (cpuidle_state_table[cstate].flags &
- CPUIDLE_FLAG_DISABLED) {
+ if (cflags & CPUIDLE_FLAG_DISABLED) {
printk(XENLOG_DEBUG PREFIX "state %s is disabled",
cpuidle_state_table[cstate].name);
continue;
@@ -1221,7 +1227,8 @@ static int mwait_idle_cpu_init(struct notifier_block *nfb,
cx = dev->states + dev->count;
cx->type = state;
cx->address = hint;
- cx->entry_method = ACPI_CSTATE_EM_FFH;
+ cx->entry_method = cflags & CPUIDLE_FLAG_USE_HALT ?
+ ACPI_CSTATE_EM_HALT : ACPI_CSTATE_EM_FFH;
cx->latency = cpuidle_state_table[cstate].exit_latency;
cx->target_residency =
cpuidle_state_table[cstate].target_residency;
@@ -18,6 +18,7 @@ extern uint64_t (*cpuidle_get_tick)(void);
int mwait_idle_init(struct notifier_block *);
int cpuidle_init_cpu(unsigned int cpu);
+void acpi_idle_do_entry(struct acpi_processor_cx *cx);
void default_dead_idle(void);
void acpi_dead_idle(void);
void trace_exit_reason(u32 *irq_traced);