1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/spinlock.h>
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/smp.h>
21#include <linux/nmi.h>
22#include <asm/tsc.h>
23
24
25
26
27
28static __cpuinitdata atomic_t start_count;
29static __cpuinitdata atomic_t stop_count;
30
31
32
33
34
35
36static __cpuinitdata raw_spinlock_t sync_lock = __RAW_SPIN_LOCK_UNLOCKED;
37static __cpuinitdata cycles_t last_tsc;
38static __cpuinitdata cycles_t max_warp;
39static __cpuinitdata int nr_warps;
40
41
42
43
44static __cpuinit void check_tsc_warp(void)
45{
46 cycles_t start, now, prev, end;
47 int i;
48
49 rdtsc_barrier();
50 start = get_cycles();
51 rdtsc_barrier();
52
53
54
55 end = start + tsc_khz * 20ULL;
56 now = start;
57
58 for (i = 0; ; i++) {
59
60
61
62
63
64 __raw_spin_lock(&sync_lock);
65 prev = last_tsc;
66 rdtsc_barrier();
67 now = get_cycles();
68 rdtsc_barrier();
69 last_tsc = now;
70 __raw_spin_unlock(&sync_lock);
71
72
73
74
75
76
77
78 if (unlikely(!(i & 7))) {
79 if (now > end || i > 10000000)
80 break;
81 cpu_relax();
82 touch_nmi_watchdog();
83 }
84
85
86
87
88 if (unlikely(prev > now)) {
89 __raw_spin_lock(&sync_lock);
90 max_warp = max(max_warp, prev - now);
91 nr_warps++;
92 __raw_spin_unlock(&sync_lock);
93 }
94 }
95 WARN(!(now-start),
96 "Warning: zero tsc calibration delta: %Ld [max: %Ld]\n",
97 now-start, end-start);
98}
99
100
101
102
103
104void __cpuinit check_tsc_sync_source(int cpu)
105{
106 int cpus = 2;
107
108
109
110
111
112 if (unsynchronized_tsc())
113 return;
114
115 printk(KERN_INFO "checking TSC synchronization [CPU#%d -> CPU#%d]:",
116 smp_processor_id(), cpu);
117
118
119
120
121 atomic_set(&stop_count, 0);
122
123
124
125
126 while (atomic_read(&start_count) != cpus-1)
127 cpu_relax();
128
129
130
131 atomic_inc(&start_count);
132
133 check_tsc_warp();
134
135 while (atomic_read(&stop_count) != cpus-1)
136 cpu_relax();
137
138 if (nr_warps) {
139 printk("\n");
140 printk(KERN_WARNING "Measured %Ld cycles TSC warp between CPUs,"
141 " turning off TSC clock.\n", max_warp);
142 mark_tsc_unstable("check_tsc_sync_source failed");
143 } else {
144 printk(" passed.\n");
145 }
146
147
148
149
150 atomic_set(&start_count, 0);
151 nr_warps = 0;
152 max_warp = 0;
153 last_tsc = 0;
154
155
156
157
158 atomic_inc(&stop_count);
159}
160
161
162
163
164void __cpuinit check_tsc_sync_target(void)
165{
166 int cpus = 2;
167
168 if (unsynchronized_tsc())
169 return;
170
171
172
173
174
175 atomic_inc(&start_count);
176 while (atomic_read(&start_count) != cpus)
177 cpu_relax();
178
179 check_tsc_warp();
180
181
182
183
184 atomic_inc(&stop_count);
185
186
187
188
189 while (atomic_read(&stop_count) != cpus)
190 cpu_relax();
191}
192#undef NR_LOOPS
193
194