0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/jiffies.h>
0009 #include <linux/delay.h>
0010 #include <linux/init.h>
0011 #include <linux/timex.h>
0012 #include <linux/smp.h>
0013 #include <linux/percpu.h>
0014
0015 unsigned long lpj_fine;
0016 unsigned long preset_lpj;
0017 static int __init lpj_setup(char *str)
0018 {
0019 preset_lpj = simple_strtoul(str,NULL,0);
0020 return 1;
0021 }
0022
0023 __setup("lpj=", lpj_setup);
0024
0025 #ifdef ARCH_HAS_READ_CURRENT_TIMER
0026
0027
0028
0029
0030
0031
0032 #define DELAY_CALIBRATION_TICKS ((HZ < 100) ? 1 : (HZ/100))
0033 #define MAX_DIRECT_CALIBRATION_RETRIES 5
0034
0035 static unsigned long calibrate_delay_direct(void)
0036 {
0037 unsigned long pre_start, start, post_start;
0038 unsigned long pre_end, end, post_end;
0039 unsigned long start_jiffies;
0040 unsigned long timer_rate_min, timer_rate_max;
0041 unsigned long good_timer_sum = 0;
0042 unsigned long good_timer_count = 0;
0043 unsigned long measured_times[MAX_DIRECT_CALIBRATION_RETRIES];
0044 int max = -1;
0045 int min = -1;
0046 int i;
0047
0048 if (read_current_timer(&pre_start) < 0 )
0049 return 0;
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) {
0071 pre_start = 0;
0072 read_current_timer(&start);
0073 start_jiffies = jiffies;
0074 while (time_before_eq(jiffies, start_jiffies + 1)) {
0075 pre_start = start;
0076 read_current_timer(&start);
0077 }
0078 read_current_timer(&post_start);
0079
0080 pre_end = 0;
0081 end = post_start;
0082 while (time_before_eq(jiffies, start_jiffies + 1 +
0083 DELAY_CALIBRATION_TICKS)) {
0084 pre_end = end;
0085 read_current_timer(&end);
0086 }
0087 read_current_timer(&post_end);
0088
0089 timer_rate_max = (post_end - pre_start) /
0090 DELAY_CALIBRATION_TICKS;
0091 timer_rate_min = (pre_end - post_start) /
0092 DELAY_CALIBRATION_TICKS;
0093
0094
0095
0096
0097
0098 if (start >= post_end)
0099 printk(KERN_NOTICE "calibrate_delay_direct() ignoring "
0100 "timer_rate as we had a TSC wrap around"
0101 " start=%lu >=post_end=%lu\n",
0102 start, post_end);
0103 if (start < post_end && pre_start != 0 && pre_end != 0 &&
0104 (timer_rate_max - timer_rate_min) < (timer_rate_max >> 3)) {
0105 good_timer_count++;
0106 good_timer_sum += timer_rate_max;
0107 measured_times[i] = timer_rate_max;
0108 if (max < 0 || timer_rate_max > measured_times[max])
0109 max = i;
0110 if (min < 0 || timer_rate_max < measured_times[min])
0111 min = i;
0112 } else
0113 measured_times[i] = 0;
0114
0115 }
0116
0117
0118
0119
0120
0121 while (good_timer_count > 1) {
0122 unsigned long estimate;
0123 unsigned long maxdiff;
0124
0125
0126 estimate = (good_timer_sum/good_timer_count);
0127 maxdiff = estimate >> 3;
0128
0129
0130 if ((measured_times[max] - measured_times[min]) < maxdiff)
0131 return estimate;
0132
0133
0134 good_timer_sum = 0;
0135 good_timer_count = 0;
0136 if ((measured_times[max] - estimate) <
0137 (estimate - measured_times[min])) {
0138 printk(KERN_NOTICE "calibrate_delay_direct() dropping "
0139 "min bogoMips estimate %d = %lu\n",
0140 min, measured_times[min]);
0141 measured_times[min] = 0;
0142 min = max;
0143 } else {
0144 printk(KERN_NOTICE "calibrate_delay_direct() dropping "
0145 "max bogoMips estimate %d = %lu\n",
0146 max, measured_times[max]);
0147 measured_times[max] = 0;
0148 max = min;
0149 }
0150
0151 for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) {
0152 if (measured_times[i] == 0)
0153 continue;
0154 good_timer_count++;
0155 good_timer_sum += measured_times[i];
0156 if (measured_times[i] < measured_times[min])
0157 min = i;
0158 if (measured_times[i] > measured_times[max])
0159 max = i;
0160 }
0161
0162 }
0163
0164 printk(KERN_NOTICE "calibrate_delay_direct() failed to get a good "
0165 "estimate for loops_per_jiffy.\nProbably due to long platform "
0166 "interrupts. Consider using \"lpj=\" boot option.\n");
0167 return 0;
0168 }
0169 #else
0170 static unsigned long calibrate_delay_direct(void)
0171 {
0172 return 0;
0173 }
0174 #endif
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185 #define LPS_PREC 8
0186
0187 static unsigned long calibrate_delay_converge(void)
0188 {
0189
0190 unsigned long lpj, lpj_base, ticks, loopadd, loopadd_base, chop_limit;
0191 int trials = 0, band = 0, trial_in_band = 0;
0192
0193 lpj = (1<<12);
0194
0195
0196 ticks = jiffies;
0197 while (ticks == jiffies)
0198 ;
0199
0200 ticks = jiffies;
0201 do {
0202 if (++trial_in_band == (1<<band)) {
0203 ++band;
0204 trial_in_band = 0;
0205 }
0206 __delay(lpj * band);
0207 trials += band;
0208 } while (ticks == jiffies);
0209
0210
0211
0212
0213 trials -= band;
0214 loopadd_base = lpj * band;
0215 lpj_base = lpj * trials;
0216
0217 recalibrate:
0218 lpj = lpj_base;
0219 loopadd = loopadd_base;
0220
0221
0222
0223
0224
0225 chop_limit = lpj >> LPS_PREC;
0226 while (loopadd > chop_limit) {
0227 lpj += loopadd;
0228 ticks = jiffies;
0229 while (ticks == jiffies)
0230 ;
0231 ticks = jiffies;
0232 __delay(lpj);
0233 if (jiffies != ticks)
0234 lpj -= loopadd;
0235 loopadd >>= 1;
0236 }
0237
0238
0239
0240
0241
0242 if (lpj + loopadd * 2 == lpj_base + loopadd_base * 2) {
0243 lpj_base = lpj;
0244 loopadd_base <<= 2;
0245 goto recalibrate;
0246 }
0247
0248 return lpj;
0249 }
0250
0251 static DEFINE_PER_CPU(unsigned long, cpu_loops_per_jiffy) = { 0 };
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261 unsigned long __attribute__((weak)) calibrate_delay_is_known(void)
0262 {
0263 return 0;
0264 }
0265
0266
0267
0268
0269
0270
0271 void __attribute__((weak)) calibration_delay_done(void)
0272 {
0273 }
0274
0275 void calibrate_delay(void)
0276 {
0277 unsigned long lpj;
0278 static bool printed;
0279 int this_cpu = smp_processor_id();
0280
0281 if (per_cpu(cpu_loops_per_jiffy, this_cpu)) {
0282 lpj = per_cpu(cpu_loops_per_jiffy, this_cpu);
0283 if (!printed)
0284 pr_info("Calibrating delay loop (skipped) "
0285 "already calibrated this CPU");
0286 } else if (preset_lpj) {
0287 lpj = preset_lpj;
0288 if (!printed)
0289 pr_info("Calibrating delay loop (skipped) "
0290 "preset value.. ");
0291 } else if ((!printed) && lpj_fine) {
0292 lpj = lpj_fine;
0293 pr_info("Calibrating delay loop (skipped), "
0294 "value calculated using timer frequency.. ");
0295 } else if ((lpj = calibrate_delay_is_known())) {
0296 ;
0297 } else if ((lpj = calibrate_delay_direct()) != 0) {
0298 if (!printed)
0299 pr_info("Calibrating delay using timer "
0300 "specific routine.. ");
0301 } else {
0302 if (!printed)
0303 pr_info("Calibrating delay loop... ");
0304 lpj = calibrate_delay_converge();
0305 }
0306 per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj;
0307 if (!printed)
0308 pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
0309 lpj/(500000/HZ),
0310 (lpj/(5000/HZ)) % 100, lpj);
0311
0312 loops_per_jiffy = lpj;
0313 printed = true;
0314
0315 calibration_delay_done();
0316 }