Blame view

init/calibrate.c 8.31 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /* calibrate.c: default delay calibration
   *
   * Excised from init/main.c
   *  Copyright (C) 1991, 1992  Linus Torvalds
   */
cd354f1ae   Tim Schmielau   [PATCH] remove ma...
6
  #include <linux/jiffies.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
  #include <linux/delay.h>
  #include <linux/init.h>
941e492bd   Andrew Morton   read_current_time...
9
  #include <linux/timex.h>
3da757daf   Alok Kataria   x86: use cpu_khz ...
10
  #include <linux/smp.h>
7afe1845d   Sameer Nanda   init: skip calibr...
11
  #include <linux/percpu.h>
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
12

f3f3149f3   Alok Kataria   x86: use cpu_khz ...
13
  unsigned long lpj_fine;
bfe8df3d3   Randy Dunlap   slow down printk ...
14
  unsigned long preset_lpj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
19
20
21
  static int __init lpj_setup(char *str)
  {
  	preset_lpj = simple_strtoul(str,NULL,0);
  	return 1;
  }
  
  __setup("lpj=", lpj_setup);
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
22
23
24
25
26
27
28
29
30
  #ifdef ARCH_HAS_READ_CURRENT_TIMER
  
  /* This routine uses the read_current_timer() routine and gets the
   * loops per jiffy directly, instead of guessing it using delay().
   * Also, this code tries to handle non-maskable asynchronous events
   * (like SMIs)
   */
  #define DELAY_CALIBRATION_TICKS			((HZ < 100) ? 1 : (HZ/100))
  #define MAX_DIRECT_CALIBRATION_RETRIES		5
6c81c32f9   Adrian Bunk   calibrate_delay()...
31
  static unsigned long __cpuinit calibrate_delay_direct(void)
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
32
33
34
35
  {
  	unsigned long pre_start, start, post_start;
  	unsigned long pre_end, end, post_end;
  	unsigned long start_jiffies;
f3f3149f3   Alok Kataria   x86: use cpu_khz ...
36
37
38
  	unsigned long timer_rate_min, timer_rate_max;
  	unsigned long good_timer_sum = 0;
  	unsigned long good_timer_count = 0;
d2b463135   Andrew Worsley   init/calibrate.c:...
39
40
41
  	unsigned long measured_times[MAX_DIRECT_CALIBRATION_RETRIES];
  	int max = -1; /* index of measured_times with max/min values or not set */
  	int min = -1;
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  	int i;
  
  	if (read_current_timer(&pre_start) < 0 )
  		return 0;
  
  	/*
  	 * A simple loop like
  	 *	while ( jiffies < start_jiffies+1)
  	 *		start = read_current_timer();
  	 * will not do. As we don't really know whether jiffy switch
  	 * happened first or timer_value was read first. And some asynchronous
  	 * event can happen between these two events introducing errors in lpj.
  	 *
  	 * So, we do
  	 * 1. pre_start <- When we are sure that jiffy switch hasn't happened
  	 * 2. check jiffy switch
  	 * 3. start <- timer value before or after jiffy switch
  	 * 4. post_start <- When we are sure that jiffy switch has happened
  	 *
  	 * Note, we don't know anything about order of 2 and 3.
  	 * Now, by looking at post_start and pre_start difference, we can
  	 * check whether any asynchronous event happened or not
  	 */
  
  	for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) {
  		pre_start = 0;
  		read_current_timer(&start);
  		start_jiffies = jiffies;
70a062286   Tim Deegan   fix jiffy calcula...
70
  		while (time_before_eq(jiffies, start_jiffies + 1)) {
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
71
72
73
74
75
76
77
  			pre_start = start;
  			read_current_timer(&start);
  		}
  		read_current_timer(&post_start);
  
  		pre_end = 0;
  		end = post_start;
70a062286   Tim Deegan   fix jiffy calcula...
78
79
  		while (time_before_eq(jiffies, start_jiffies + 1 +
  					       DELAY_CALIBRATION_TICKS)) {
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
80
81
82
83
  			pre_end = end;
  			read_current_timer(&end);
  		}
  		read_current_timer(&post_end);
f3f3149f3   Alok Kataria   x86: use cpu_khz ...
84
85
86
87
  		timer_rate_max = (post_end - pre_start) /
  					DELAY_CALIBRATION_TICKS;
  		timer_rate_min = (pre_end - post_start) /
  					DELAY_CALIBRATION_TICKS;
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
88
89
  
  		/*
f3f3149f3   Alok Kataria   x86: use cpu_khz ...
90
  		 * If the upper limit and lower limit of the timer_rate is
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
91
92
  		 * >= 12.5% apart, redo calibration.
  		 */
d2b463135   Andrew Worsley   init/calibrate.c:...
93
94
95
96
97
98
99
  		if (start >= post_end)
  			printk(KERN_NOTICE "calibrate_delay_direct() ignoring "
  					"timer_rate as we had a TSC wrap around"
  					" start=%lu >=post_end=%lu
  ",
  				start, post_end);
  		if (start < post_end && pre_start != 0 && pre_end != 0 &&
f3f3149f3   Alok Kataria   x86: use cpu_khz ...
100
101
102
  		    (timer_rate_max - timer_rate_min) < (timer_rate_max >> 3)) {
  			good_timer_count++;
  			good_timer_sum += timer_rate_max;
d2b463135   Andrew Worsley   init/calibrate.c:...
103
104
105
106
107
108
109
  			measured_times[i] = timer_rate_max;
  			if (max < 0 || timer_rate_max > measured_times[max])
  				max = i;
  			if (min < 0 || timer_rate_max < measured_times[min])
  				min = i;
  		} else
  			measured_times[i] = 0;
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
110
  	}
d2b463135   Andrew Worsley   init/calibrate.c:...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  	/*
  	 * Find the maximum & minimum - if they differ too much throw out the
  	 * one with the largest difference from the mean and try again...
  	 */
  	while (good_timer_count > 1) {
  		unsigned long estimate;
  		unsigned long maxdiff;
  
  		/* compute the estimate */
  		estimate = (good_timer_sum/good_timer_count);
  		maxdiff = estimate >> 3;
  
  		/* if range is within 12% let's take it */
  		if ((measured_times[max] - measured_times[min]) < maxdiff)
  			return estimate;
  
  		/* ok - drop the worse value and try again... */
  		good_timer_sum = 0;
  		good_timer_count = 0;
  		if ((measured_times[max] - estimate) <
  				(estimate - measured_times[min])) {
  			printk(KERN_NOTICE "calibrate_delay_direct() dropping "
  					"min bogoMips estimate %d = %lu
  ",
  				min, measured_times[min]);
  			measured_times[min] = 0;
  			min = max;
  		} else {
  			printk(KERN_NOTICE "calibrate_delay_direct() dropping "
  					"max bogoMips estimate %d = %lu
  ",
  				max, measured_times[max]);
  			measured_times[max] = 0;
  			max = min;
  		}
  
  		for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) {
  			if (measured_times[i] == 0)
  				continue;
  			good_timer_count++;
  			good_timer_sum += measured_times[i];
  			if (measured_times[i] < measured_times[min])
  				min = i;
  			if (measured_times[i] > measured_times[max])
  				max = i;
  		}
  
  	}
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
159

d2b463135   Andrew Worsley   init/calibrate.c:...
160
161
162
163
164
  	printk(KERN_NOTICE "calibrate_delay_direct() failed to get a good "
  	       "estimate for loops_per_jiffy.
  Probably due to long platform "
  		"interrupts. Consider using \"lpj=\" boot option.
  ");
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
165
166
167
  	return 0;
  }
  #else
6c81c32f9   Adrian Bunk   calibrate_delay()...
168
  static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;}
8a9e1b0f5   Venkatesh Pallipadi   [PATCH] Platform ...
169
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
  /*
   * This is the number of bits of precision for the loops_per_jiffy.  Each
191e56880   Phil Carmody   calibrate: home i...
172
173
   * time we refine our estimate after the first takes 1.5/HZ seconds, so try
   * to start with a good estimate.
3da757daf   Alok Kataria   x86: use cpu_khz ...
174
   * For the boot cpu we can skip the delay calibration and assign it a value
f3f3149f3   Alok Kataria   x86: use cpu_khz ...
175
176
   * calculated based on the timer frequency.
   * For the rest of the CPUs we cannot assume that the timer frequency is same as
3da757daf   Alok Kataria   x86: use cpu_khz ...
177
   * the cpu frequency, hence do the calibration for those.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
   */
  #define LPS_PREC 8
71c696b1d   Phil Carmody   calibrate: extrac...
180
  static unsigned long __cpuinit calibrate_delay_converge(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  {
191e56880   Phil Carmody   calibrate: home i...
182
  	/* First stage - slowly accelerate to find initial bounds */
b1b5f65e5   Phil Carmody   calibrate: retry ...
183
  	unsigned long lpj, lpj_base, ticks, loopadd, loopadd_base, chop_limit;
191e56880   Phil Carmody   calibrate: home i...
184
  	int trials = 0, band = 0, trial_in_band = 0;
71c696b1d   Phil Carmody   calibrate: extrac...
185
186
  
  	lpj = (1<<12);
191e56880   Phil Carmody   calibrate: home i...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  
  	/* wait for "start of" clock tick */
  	ticks = jiffies;
  	while (ticks == jiffies)
  		; /* nothing */
  	/* Go .. */
  	ticks = jiffies;
  	do {
  		if (++trial_in_band == (1<<band)) {
  			++band;
  			trial_in_band = 0;
  		}
  		__delay(lpj * band);
  		trials += band;
  	} while (ticks == jiffies);
  	/*
  	 * We overshot, so retreat to a clear underestimate. Then estimate
  	 * the largest likely undershoot. This defines our chop bounds.
  	 */
  	trials -= band;
b1b5f65e5   Phil Carmody   calibrate: retry ...
207
208
209
210
211
212
  	loopadd_base = lpj * band;
  	lpj_base = lpj * trials;
  
  recalibrate:
  	lpj = lpj_base;
  	loopadd = loopadd_base;
71c696b1d   Phil Carmody   calibrate: extrac...
213
214
215
  
  	/*
  	 * Do a binary approximation to get lpj set to
191e56880   Phil Carmody   calibrate: home i...
216
  	 * equal one clock (up to LPS_PREC bits)
71c696b1d   Phil Carmody   calibrate: extrac...
217
  	 */
b1b5f65e5   Phil Carmody   calibrate: retry ...
218
  	chop_limit = lpj >> LPS_PREC;
191e56880   Phil Carmody   calibrate: home i...
219
220
  	while (loopadd > chop_limit) {
  		lpj += loopadd;
71c696b1d   Phil Carmody   calibrate: extrac...
221
222
  		ticks = jiffies;
  		while (ticks == jiffies)
191e56880   Phil Carmody   calibrate: home i...
223
  			; /* nothing */
71c696b1d   Phil Carmody   calibrate: extrac...
224
225
226
  		ticks = jiffies;
  		__delay(lpj);
  		if (jiffies != ticks)	/* longer than 1 tick */
191e56880   Phil Carmody   calibrate: home i...
227
228
  			lpj -= loopadd;
  		loopadd >>= 1;
71c696b1d   Phil Carmody   calibrate: extrac...
229
  	}
b1b5f65e5   Phil Carmody   calibrate: retry ...
230
231
232
233
234
235
236
237
238
239
  	/*
  	 * If we incremented every single time possible, presume we've
  	 * massively underestimated initially, and retry with a higher
  	 * start, and larger range. (Only seen on x86_64, due to SMIs)
  	 */
  	if (lpj + loopadd * 2 == lpj_base + loopadd_base * 2) {
  		lpj_base = lpj;
  		loopadd_base <<= 2;
  		goto recalibrate;
  	}
71c696b1d   Phil Carmody   calibrate: extrac...
240
241
242
  
  	return lpj;
  }
7afe1845d   Sameer Nanda   init: skip calibr...
243
  static DEFINE_PER_CPU(unsigned long, cpu_loops_per_jiffy) = { 0 };
b565201cf   Jack Steiner   x86: Reduce clock...
244
245
246
247
248
249
250
251
252
253
254
255
  /*
   * Check if cpu calibration delay is already known. For example,
   * some processors with multi-core sockets may have all cores
   * with the same calibration delay.
   *
   * Architectures should override this function if a faster calibration
   * method is available.
   */
  unsigned long __attribute__((weak)) __cpuinit calibrate_delay_is_known(void)
  {
  	return 0;
  }
71c696b1d   Phil Carmody   calibrate: extrac...
256
257
  void __cpuinit calibrate_delay(void)
  {
1b19ca9f0   Russell King   Fix CPU spinlock ...
258
  	unsigned long lpj;
feae3203d   Mike Travis   timers, init: Lim...
259
  	static bool printed;
7afe1845d   Sameer Nanda   init: skip calibr...
260
  	int this_cpu = smp_processor_id();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261

7afe1845d   Sameer Nanda   init: skip calibr...
262
263
264
265
266
  	if (per_cpu(cpu_loops_per_jiffy, this_cpu)) {
  		lpj = per_cpu(cpu_loops_per_jiffy, this_cpu);
  		pr_info("Calibrating delay loop (skipped) "
  				"already calibrated this CPU");
  	} else if (preset_lpj) {
1b19ca9f0   Russell King   Fix CPU spinlock ...
267
  		lpj = preset_lpj;
feae3203d   Mike Travis   timers, init: Lim...
268
269
270
271
  		if (!printed)
  			pr_info("Calibrating delay loop (skipped) "
  				"preset value.. ");
  	} else if ((!printed) && lpj_fine) {
1b19ca9f0   Russell King   Fix CPU spinlock ...
272
  		lpj = lpj_fine;
feae3203d   Mike Travis   timers, init: Lim...
273
  		pr_info("Calibrating delay loop (skipped), "
f3f3149f3   Alok Kataria   x86: use cpu_khz ...
274
  			"value calculated using timer frequency.. ");
b565201cf   Jack Steiner   x86: Reduce clock...
275
276
  	} else if ((lpj = calibrate_delay_is_known())) {
  		;
1b19ca9f0   Russell King   Fix CPU spinlock ...
277
  	} else if ((lpj = calibrate_delay_direct()) != 0) {
feae3203d   Mike Travis   timers, init: Lim...
278
279
280
  		if (!printed)
  			pr_info("Calibrating delay using timer "
  				"specific routine.. ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  	} else {
feae3203d   Mike Travis   timers, init: Lim...
282
283
  		if (!printed)
  			pr_info("Calibrating delay loop... ");
1b19ca9f0   Russell King   Fix CPU spinlock ...
284
  		lpj = calibrate_delay_converge();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  	}
7afe1845d   Sameer Nanda   init: skip calibr...
286
  	per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj;
feae3203d   Mike Travis   timers, init: Lim...
287
288
289
  	if (!printed)
  		pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)
  ",
1b19ca9f0   Russell King   Fix CPU spinlock ...
290
291
  			lpj/(500000/HZ),
  			(lpj/(5000/HZ)) % 100, lpj);
feae3203d   Mike Travis   timers, init: Lim...
292

1b19ca9f0   Russell King   Fix CPU spinlock ...
293
  	loops_per_jiffy = lpj;
feae3203d   Mike Travis   timers, init: Lim...
294
  	printed = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  }