diff --git a/init/calibrate.c b/init/calibrate.c index a379c90..5602f4f 100644 --- a/init/calibrate.c +++ b/init/calibrate.c @@ -38,6 +38,7 @@ static unsigned long __cpuinit calibrate_delay_direct(void) unsigned long timer_rate_min, timer_rate_max; unsigned long good_timer_sum = 0; unsigned long good_timer_count = 0; + unsigned long measured_times[MAX_DIRECT_CALIBRATION_RETRIES]; int i; if (read_current_timer(&pre_start) < 0 ) @@ -66,7 +67,7 @@ static unsigned long __cpuinit calibrate_delay_direct(void) pre_start = 0; read_current_timer(&start); start_jiffies = jiffies; - while (jiffies <= (start_jiffies + 1)) { + while (time_before_eq(jiffies, start_jiffies + 1)) { pre_start = start; read_current_timer(&start); } @@ -74,8 +75,8 @@ static unsigned long __cpuinit calibrate_delay_direct(void) pre_end = 0; end = post_start; - while (jiffies <= - (start_jiffies + 1 + DELAY_CALIBRATION_TICKS)) { + while (time_before_eq(jiffies, start_jiffies + 1 + + DELAY_CALIBRATION_TICKS)) { pre_end = end; read_current_timer(&end); } @@ -90,15 +91,50 @@ static unsigned long __cpuinit calibrate_delay_direct(void) * If the upper limit and lower limit of the timer_rate is * >= 12.5% apart, redo calibration. */ - if (pre_start != 0 && pre_end != 0 && + printk(KERN_WARNING +"calibrate_delay_direct() timer_rate_max=%lu timer_rate_min=%lu pre_start=%lu pre_end=%lu\n", + timer_rate_max, timer_rate_min, pre_start, pre_end); + if (start >= post_end) + printk(KERN_WARNING + "calibrate_delay_direct() ignoring timer_rate as we had a TSC wrap around start=%lu >=post_end=%lu\n", + start, post_end); + if (start < post_end && pre_start != 0 && pre_end != 0 && (timer_rate_max - timer_rate_min) < (timer_rate_max >> 3)) { good_timer_count++; good_timer_sum += timer_rate_max; - } + measured_times[i] = timer_rate_max; + } else + measured_times[i] = 0; + } - if (good_timer_count) - return (good_timer_sum/good_timer_count); + if (good_timer_count) { + unsigned long estimate = (good_timer_sum/good_timer_count); + unsigned long maxdiff = estimate >> 3; + + good_timer_sum = 0; + good_timer_count = 0; + for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) { + if (measured_times[i] == 0) + continue; + if (measured_times[i] > estimate) { + if ((measured_times[i] - estimate) > maxdiff) { + printk(KERN_WARNING + "calibrate_delay_direct() dropping bad bogoMips estimate %d = %lu\n", i, measured_times[i]); + continue; + } + } else if ((estimate - measured_times[i]) > maxdiff) { + printk(KERN_WARNING + "calibrate_delay_direct() dropping bad bogoMips estimate %d = %lu\n", i, measured_times[i]); + continue; + } + good_timer_count++; + good_timer_sum += timer_rate_max; + } + + if (good_timer_count) + return (good_timer_sum/good_timer_count); + } printk(KERN_WARNING "calibrate_delay_direct() failed to get a good " "estimate for loops_per_jiffy.\nProbably due to long platform interrupts. Consider using \"lpj=\" boot option.\n");