aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/lib
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-09-13 05:25:35 -0400
committerIngo Molnar <mingo@kernel.org>2015-09-13 05:25:35 -0400
commitd2bb1d42b95fa88f092623bbb8ed533f316b6a3c (patch)
treefb796db809a266906fa358f24f1c07ced4df33f0 /arch/x86/lib
parent3bd7617596df560e2cb22ad97888cb42dae39d02 (diff)
parent6ff33f3902c3b1c5d0db6b1e2c70b6d76fba357f (diff)
Merge tag 'v4.3-rc1' into perf/core, to refresh the tree
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/lib')
-rw-r--r--arch/x86/lib/delay.c60
1 files changed, 51 insertions, 9 deletions
diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c
index 39d6a3db0b96..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>
@@ -49,16 +50,14 @@ static void delay_loop(unsigned long loops)
49/* TSC based delay: */ 50/* TSC based delay: */
50static void delay_tsc(unsigned long __loops) 51static void delay_tsc(unsigned long __loops)
51{ 52{
52 u32 bclock, now, loops = __loops; 53 u64 bclock, now, loops = __loops;
53 int cpu; 54 int cpu;
54 55
55 preempt_disable(); 56 preempt_disable();
56 cpu = smp_processor_id(); 57 cpu = smp_processor_id();
57 rdtsc_barrier(); 58 bclock = rdtsc_ordered();
58 rdtscl(bclock);
59 for (;;) { 59 for (;;) {
60 rdtsc_barrier(); 60 now = rdtsc_ordered();
61 rdtscl(now);
62 if ((now - bclock) >= loops) 61 if ((now - bclock) >= loops)
63 break; 62 break;
64 63
@@ -79,14 +78,51 @@ static void delay_tsc(unsigned long __loops)
79 if (unlikely(cpu != smp_processor_id())) { 78 if (unlikely(cpu != smp_processor_id())) {
80 loops -= (now - bclock); 79 loops -= (now - bclock);
81 cpu = smp_processor_id(); 80 cpu = smp_processor_id();
82 rdtsc_barrier(); 81 bclock = rdtsc_ordered();
83 rdtscl(bclock);
84 } 82 }
85 } 83 }
86 preempt_enable(); 84 preempt_enable();
87} 85}
88 86
89/* 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/*
90 * Since we calibrate only once at boot, this 126 * Since we calibrate only once at boot, this
91 * function should be set once at boot and not changed 127 * function should be set once at boot and not changed
92 */ 128 */
@@ -94,13 +130,19 @@ static void (*delay_fn)(unsigned long) = delay_loop;
94 130
95void use_tsc_delay(void) 131void use_tsc_delay(void)
96{ 132{
97 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;
98} 140}
99 141
100int read_current_timer(unsigned long *timer_val) 142int read_current_timer(unsigned long *timer_val)
101{ 143{
102 if (delay_fn == delay_tsc) { 144 if (delay_fn == delay_tsc) {
103 rdtscll(*timer_val); 145 *timer_val = rdtsc();
104 return 0; 146 return 0;
105 } 147 }
106 return -1; 148 return -1;