1
2
3
4
5
6
7#include <linux/jiffies.h>
8#include <linux/delay.h>
9#include <linux/init.h>
10#include <linux/timex.h>
11
12unsigned long preset_lpj;
13static int __init lpj_setup(char *str)
14{
15 preset_lpj = simple_strtoul(str,NULL,0);
16 return 1;
17}
18
19__setup("lpj=", lpj_setup);
20
21#ifdef ARCH_HAS_READ_CURRENT_TIMER
22
23
24
25
26
27
28#define DELAY_CALIBRATION_TICKS ((HZ < 100) ? 1 : (HZ/100))
29#define MAX_DIRECT_CALIBRATION_RETRIES 5
30
31static unsigned long __cpuinit calibrate_delay_direct(void)
32{
33 unsigned long pre_start, start, post_start;
34 unsigned long pre_end, end, post_end;
35 unsigned long start_jiffies;
36 unsigned long tsc_rate_min, tsc_rate_max;
37 unsigned long good_tsc_sum = 0;
38 unsigned long good_tsc_count = 0;
39 int i;
40
41 if (read_current_timer(&pre_start) < 0 )
42 return 0;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) {
64 pre_start = 0;
65 read_current_timer(&start);
66 start_jiffies = jiffies;
67 while (jiffies <= (start_jiffies + 1)) {
68 pre_start = start;
69 read_current_timer(&start);
70 }
71 read_current_timer(&post_start);
72
73 pre_end = 0;
74 end = post_start;
75 while (jiffies <=
76 (start_jiffies + 1 + DELAY_CALIBRATION_TICKS)) {
77 pre_end = end;
78 read_current_timer(&end);
79 }
80 read_current_timer(&post_end);
81
82 tsc_rate_max = (post_end - pre_start) / DELAY_CALIBRATION_TICKS;
83 tsc_rate_min = (pre_end - post_start) / DELAY_CALIBRATION_TICKS;
84
85
86
87
88
89 if (pre_start != 0 && pre_end != 0 &&
90 (tsc_rate_max - tsc_rate_min) < (tsc_rate_max >> 3)) {
91 good_tsc_count++;
92 good_tsc_sum += tsc_rate_max;
93 }
94 }
95
96 if (good_tsc_count)
97 return (good_tsc_sum/good_tsc_count);
98
99 printk(KERN_WARNING "calibrate_delay_direct() failed to get a good "
100 "estimate for loops_per_jiffy.\nProbably due to long platform interrupts. Consider using \"lpj=\" boot option.\n");
101 return 0;
102}
103#else
104static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;}
105#endif
106
107
108
109
110
111
112#define LPS_PREC 8
113
114void __cpuinit calibrate_delay(void)
115{
116 unsigned long ticks, loopbit;
117 int lps_precision = LPS_PREC;
118
119 if (preset_lpj) {
120 loops_per_jiffy = preset_lpj;
121 printk("Calibrating delay loop (skipped)... "
122 "%lu.%02lu BogoMIPS preset\n",
123 loops_per_jiffy/(500000/HZ),
124 (loops_per_jiffy/(5000/HZ)) % 100);
125 } else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) {
126 printk("Calibrating delay using timer specific routine.. ");
127 printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",
128 loops_per_jiffy/(500000/HZ),
129 (loops_per_jiffy/(5000/HZ)) % 100,
130 loops_per_jiffy);
131 } else {
132 loops_per_jiffy = (1<<12);
133
134 printk(KERN_DEBUG "Calibrating delay loop... ");
135 while ((loops_per_jiffy <<= 1) != 0) {
136
137 ticks = jiffies;
138 while (ticks == jiffies)
139 ;
140
141 ticks = jiffies;
142 __delay(loops_per_jiffy);
143 ticks = jiffies - ticks;
144 if (ticks)
145 break;
146 }
147
148
149
150
151
152 loops_per_jiffy >>= 1;
153 loopbit = loops_per_jiffy;
154 while (lps_precision-- && (loopbit >>= 1)) {
155 loops_per_jiffy |= loopbit;
156 ticks = jiffies;
157 while (ticks == jiffies)
158 ;
159 ticks = jiffies;
160 __delay(loops_per_jiffy);
161 if (jiffies != ticks)
162 loops_per_jiffy &= ~loopbit;
163 }
164
165
166 printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",
167 loops_per_jiffy/(500000/HZ),
168 (loops_per_jiffy/(5000/HZ)) % 100,
169 loops_per_jiffy);
170 }
171
172}
173