[patch 2/2] x86: put offline CPUs into deepest mwait cstate_subcstate

From: venkatesh . pallipadi
Date: Fri May 22 2009 - 19:25:51 EST


Offline CPUs can save power by going into deepest cstate, subcstate
instead of hlt loop.

Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@xxxxxxxxx>
---
arch/x86/kernel/acpi/cstate.c | 51 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 51 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c
index bbbe4bb..5b0988a 100644
--- a/arch/x86/kernel/acpi/cstate.c
+++ b/arch/x86/kernel/acpi/cstate.c
@@ -150,6 +150,54 @@ void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
}
EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_enter);

+static unsigned long mwait_play_dead_eax;
+
+static void mwait_play_dead(void)
+{
+ if (boot_cpu_data.x86 >= 4)
+ wbinvd();
+
+ while (1) {
+ __monitor((void *)&current_thread_info()->flags, 0, 0);
+ smp_mb();
+ __mwait(mwait_play_dead_eax, 0);
+ }
+}
+
+static void mwait_play_dead_init(void *unused)
+{
+ unsigned int eax, ebx, ecx, edx;
+ unsigned int highest_cstate = 0;
+ unsigned int highest_subcstate = 0;
+ int i;
+
+ if (!boot_cpu_has(X86_FEATURE_MWAIT))
+ return;
+
+ if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
+ return;
+
+ pm_play_dead = mwait_play_dead;
+
+ cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
+ /*
+ * mwait_play_dead_eax will be 0 if EDX enumeration is not valid.
+ * Initialized below to cstate, sub_cstate value when EDX is valid.
+ */
+ if (!(ecx & 0x1))
+ return;
+
+ edx >>= MWAIT_SUBSTATE_SIZE;
+ for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
+ if (edx & MWAIT_SUBSTATE_MASK) {
+ highest_cstate = i;
+ highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
+ }
+ }
+ mwait_play_dead_eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
+ (highest_subcstate - 1);
+}
+
static int __init ffh_cstate_init(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
@@ -157,6 +205,9 @@ static int __init ffh_cstate_init(void)
return -1;

cpu_cstate_entry = alloc_percpu(struct cstate_entry);
+
+ smp_call_function_single(0, mwait_play_dead_init, NULL, 1);
+
return 0;
}

--
1.6.0.6

--

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/