summary refs log tree commit diff
path: root/init/calibrate.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2011-05-31 13:10:26 +0900
committerPaul Mundt <lethal@linux-sh.org>2011-05-31 13:10:26 +0900
commit8181d3ef26ed1d9eb21e2cdcac374e1f457fdc06 (patch)
tree1a081f09ebcf2a84de899ddeadd0e4c5e48b50d2 /init/calibrate.c
parent54525552c6ccfd867e819845da14be994e303218 (diff)
parent55922c9d1b84b89cb946c777fddccb3247e7df2c (diff)
downloadlinux-8181d3ef26ed1d9eb21e2cdcac374e1f457fdc06.tar.gz
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into sh-fixes-for-linus
Diffstat (limited to 'init/calibrate.c')
-rw-r--r--init/calibrate.c75
1 files changed, 69 insertions, 6 deletions
diff --git a/init/calibrate.c b/init/calibrate.c
index 76ac9194cbc4..cfd7000c9d71 100644
--- a/init/calibrate.c
+++ b/init/calibrate.c
@@ -38,6 +38,9 @@ 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 max = -1; /* index of measured_times with max/min values or not set */
+	int min = -1;
 	int i;
 
 	if (read_current_timer(&pre_start) < 0 )
@@ -90,18 +93,78 @@ 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_DEBUG "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_NOTICE "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;
+			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;
+
 	}
 
-	if (good_timer_count)
-		return (good_timer_sum/good_timer_count);
+	/*
+	 * 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\n",
+				min, measured_times[min]);
+			measured_times[min] = 0;
+			min = max;
+		} else {
+			printk(KERN_NOTICE "calibrate_delay_direct() dropping "
+					"max bogoMips estimate %d = %lu\n",
+				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;
+		}
+
+	}
 
-	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");
+	printk(KERN_NOTICE "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");
 	return 0;
 }
 #else