diff mbox series

[v2,1/3] mwait-idle: add support for using halt

Message ID 20190328150426.7295-2-brian.woods@amd.com (mailing list archive)
State New, archived
Headers show
Series mwait support for AMD processors | expand

Commit Message

Woods, Brian March 28, 2019, 3:04 p.m. UTC
From: Brian Woods <brian.woods@amd.com>

Some AMD processors can use a mixture of mwait and halt for accessing
various c-states.  In preparation for adding support for AMD processors,
update the mwait-idle driver to optionally use halt.

Signed-off-by: Brian Woods <brian.woods@amd.com>
---
 xen/arch/x86/acpi/cpu_idle.c  |  2 +-
 xen/arch/x86/cpu/mwait-idle.c | 19 +++++++++++++------
 xen/include/asm-x86/cpuidle.h |  1 +
 3 files changed, 15 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c
index 654de24f40..b45824d343 100644
--- a/xen/arch/x86/acpi/cpu_idle.c
+++ b/xen/arch/x86/acpi/cpu_idle.c
@@ -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();
 
diff --git a/xen/arch/x86/cpu/mwait-idle.c b/xen/arch/x86/cpu/mwait-idle.c
index f89c52f256..b9c7f75882 100644
--- a/xen/arch/x86/cpu/mwait-idle.c
+++ b/xen/arch/x86/cpu/mwait-idle.c
@@ -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;
diff --git a/xen/include/asm-x86/cpuidle.h b/xen/include/asm-x86/cpuidle.h
index 08da01803f..33c8cf1593 100644
--- a/xen/include/asm-x86/cpuidle.h
+++ b/xen/include/asm-x86/cpuidle.h
@@ -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);