aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/lib
diff options
context:
space:
mode:
authorHuang Rui <ray.huang@amd.com>2015-08-10 06:19:54 -0400
committerIngo Molnar <mingo@kernel.org>2015-08-22 08:52:16 -0400
commitb466bdb614823aaaa7188e85516177d2850f4782 (patch)
tree7ff33b9f498f7bd98c1edef07da63a09ef9710c9 /arch/x86/lib
parentf96756746c7909de37db3d03ac5fd5cfb2757f38 (diff)
x86/asm/delay: Introduce an MWAITX-based delay with a configurable timer
MWAITX can enable a timer and a corresponding timer value specified in SW P0 clocks. The SW P0 frequency is the same as TSC. The timer provides an upper bound on how long the instruction waits before exiting. This way, a delay function in the kernel can leverage that MWAITX timer of MWAITX. When a CPU core executes MWAITX, it will be quiesced in a waiting phase, diminishing its power consumption. This way, we can save power in comparison to our default TSC-based delays. A simple test shows that: $ cat /sys/bus/pci/devices/0000\:00\:18.4/hwmon/hwmon0/power1_acc $ sleep 10000s $ cat /sys/bus/pci/devices/0000\:00\:18.4/hwmon/hwmon0/power1_acc Results: * TSC-based default delay: 485115 uWatts average power * MWAITX-based delay: 252738 uWatts average power Thus, that's about 240 milliWatts less power consumption. The test method relies on the support of AMD CPU accumulated power algorithm in fam15h_power for which patches are forthcoming. Suggested-by: Andy Lutomirski <luto@amacapital.net> Suggested-by: Borislav Petkov <bp@suse.de> Suggested-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Huang Rui <ray.huang@amd.com> [ Fix delay truncation. ] Signed-off-by: Borislav Petkov <bp@suse.de> Cc: Aaron Lu <aaron.lu@intel.com> Cc: Andreas Herrmann <herrmann.der.user@gmail.com> Cc: Aravind Gopalakrishnan <Aravind.Gopalakrishnan@amd.com> Cc: Fengguang Wu <fengguang.wu@intel.com> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Hector Marco-Gisbert <hecmargi@upv.es> Cc: Jacob Shin <jacob.w.shin@gmail.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: John Stultz <john.stultz@linaro.org> Cc: Len Brown <lenb@kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Li <tony.li@amd.com> Link: http://lkml.kernel.org/r/1438744732-1459-3-git-send-email-ray.huang@amd.com Link: http://lkml.kernel.org/r/1439201994-28067-4-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/lib')
-rw-r--r--arch/x86/lib/delay.c47
1 files changed, 46 insertions, 1 deletions
diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c
index 4453d52a143d..e912b2f6d36e 100644
--- a/arch/x86/lib/delay.c
+++ b/arch/x86/lib/delay.c
@@ -20,6 +20,7 @@
20#include <asm/processor.h> 20#include <asm/processor.h>
21#include <asm/delay.h> 21#include <asm/delay.h>
22#include <asm/timer.h> 22#include <asm/timer.h>
23#include <asm/mwait.h>
23 24
24#ifdef CONFIG_SMP 25#ifdef CONFIG_SMP
25# include <asm/smp.h> 26# include <asm/smp.h>
@@ -84,6 +85,44 @@ static void delay_tsc(unsigned long __loops)
84} 85}
85 86
86/* 87/*
88 * On some AMD platforms, MWAITX has a configurable 32-bit timer, that
89 * counts with TSC frequency. The input value is the loop of the
90 * counter, it will exit when the timer expires.
91 */
92static void delay_mwaitx(unsigned long __loops)
93{
94 u64 start, end, delay, loops = __loops;
95
96 start = rdtsc_ordered();
97
98 for (;;) {
99 delay = min_t(u64, MWAITX_MAX_LOOPS, loops);
100
101 /*
102 * Use cpu_tss as a cacheline-aligned, seldomly
103 * accessed per-cpu variable as the monitor target.
104 */
105 __monitorx(this_cpu_ptr(&cpu_tss), 0, 0);
106
107 /*
108 * AMD, like Intel, supports the EAX hint and EAX=0xf
109 * means, do not enter any deep C-state and we use it
110 * here in delay() to minimize wakeup latency.
111 */
112 __mwaitx(MWAITX_DISABLE_CSTATES, delay, MWAITX_ECX_TIMER_ENABLE);
113
114 end = rdtsc_ordered();
115
116 if (loops <= end - start)
117 break;
118
119 loops -= end - start;
120
121 start = end;
122 }
123}
124
125/*
87 * Since we calibrate only once at boot, this 126 * Since we calibrate only once at boot, this
88 * function should be set once at boot and not changed 127 * function should be set once at boot and not changed
89 */ 128 */
@@ -91,7 +130,13 @@ static void (*delay_fn)(unsigned long) = delay_loop;
91 130
92void use_tsc_delay(void) 131void use_tsc_delay(void)
93{ 132{
94 delay_fn = delay_tsc; 133 if (delay_fn == delay_loop)
134 delay_fn = delay_tsc;
135}
136
137void use_mwaitx_delay(void)
138{
139 delay_fn = delay_mwaitx;
95} 140}
96 141
97int read_current_timer(unsigned long *timer_val) 142int read_current_timer(unsigned long *timer_val)