diff options
Diffstat (limited to 'init/calibrate.c')
-rw-r--r-- | init/calibrate.c | 75 |
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) | |||
38 | unsigned long timer_rate_min, timer_rate_max; | 38 | unsigned long timer_rate_min, timer_rate_max; |
39 | unsigned long good_timer_sum = 0; | 39 | unsigned long good_timer_sum = 0; |
40 | unsigned long good_timer_count = 0; | 40 | unsigned long good_timer_count = 0; |
41 | unsigned long measured_times[MAX_DIRECT_CALIBRATION_RETRIES]; | ||
42 | int max = -1; /* index of measured_times with max/min values or not set */ | ||
43 | int min = -1; | ||
41 | int i; | 44 | int i; |
42 | 45 | ||
43 | if (read_current_timer(&pre_start) < 0 ) | 46 | if (read_current_timer(&pre_start) < 0 ) |
@@ -90,18 +93,78 @@ static unsigned long __cpuinit calibrate_delay_direct(void) | |||
90 | * If the upper limit and lower limit of the timer_rate is | 93 | * If the upper limit and lower limit of the timer_rate is |
91 | * >= 12.5% apart, redo calibration. | 94 | * >= 12.5% apart, redo calibration. |
92 | */ | 95 | */ |
93 | if (pre_start != 0 && pre_end != 0 && | 96 | printk(KERN_DEBUG "calibrate_delay_direct() timer_rate_max=%lu " |
97 | "timer_rate_min=%lu pre_start=%lu pre_end=%lu\n", | ||
98 | timer_rate_max, timer_rate_min, pre_start, pre_end); | ||
99 | if (start >= post_end) | ||
100 | printk(KERN_NOTICE "calibrate_delay_direct() ignoring " | ||
101 | "timer_rate as we had a TSC wrap around" | ||
102 | " start=%lu >=post_end=%lu\n", | ||
103 | start, post_end); | ||
104 | if (start < post_end && pre_start != 0 && pre_end != 0 && | ||
94 | (timer_rate_max - timer_rate_min) < (timer_rate_max >> 3)) { | 105 | (timer_rate_max - timer_rate_min) < (timer_rate_max >> 3)) { |
95 | good_timer_count++; | 106 | good_timer_count++; |
96 | good_timer_sum += timer_rate_max; | 107 | good_timer_sum += timer_rate_max; |
97 | } | 108 | measured_times[i] = timer_rate_max; |
109 | if (max < 0 || timer_rate_max > measured_times[max]) | ||
110 | max = i; | ||
111 | if (min < 0 || timer_rate_max < measured_times[min]) | ||
112 | min = i; | ||
113 | } else | ||
114 | measured_times[i] = 0; | ||
115 | |||
98 | } | 116 | } |
99 | 117 | ||
100 | if (good_timer_count) | 118 | /* |
101 | return (good_timer_sum/good_timer_count); | 119 | * Find the maximum & minimum - if they differ too much throw out the |
120 | * one with the largest difference from the mean and try again... | ||
121 | */ | ||
122 | while (good_timer_count > 1) { | ||
123 | unsigned long estimate; | ||
124 | unsigned long maxdiff; | ||
125 | |||
126 | /* compute the estimate */ | ||
127 | estimate = (good_timer_sum/good_timer_count); | ||
128 | maxdiff = estimate >> 3; | ||
129 | |||
130 | /* if range is within 12% let's take it */ | ||
131 | if ((measured_times[max] - measured_times[min]) < maxdiff) | ||
132 | return estimate; | ||
133 | |||
134 | /* ok - drop the worse value and try again... */ | ||
135 | good_timer_sum = 0; | ||
136 | good_timer_count = 0; | ||
137 | if ((measured_times[max] - estimate) < | ||
138 | (estimate - measured_times[min])) { | ||
139 | printk(KERN_NOTICE "calibrate_delay_direct() dropping " | ||
140 | "min bogoMips estimate %d = %lu\n", | ||
141 | min, measured_times[min]); | ||
142 | measured_times[min] = 0; | ||
143 | min = max; | ||
144 | } else { | ||
145 | printk(KERN_NOTICE "calibrate_delay_direct() dropping " | ||
146 | "max bogoMips estimate %d = %lu\n", | ||
147 | max, measured_times[max]); | ||
148 | measured_times[max] = 0; | ||
149 | max = min; | ||
150 | } | ||
151 | |||
152 | for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) { | ||
153 | if (measured_times[i] == 0) | ||
154 | continue; | ||
155 | good_timer_count++; | ||
156 | good_timer_sum += measured_times[i]; | ||
157 | if (measured_times[i] < measured_times[min]) | ||
158 | min = i; | ||
159 | if (measured_times[i] > measured_times[max]) | ||
160 | max = i; | ||
161 | } | ||
162 | |||
163 | } | ||
102 | 164 | ||
103 | printk(KERN_WARNING "calibrate_delay_direct() failed to get a good " | 165 | printk(KERN_NOTICE "calibrate_delay_direct() failed to get a good " |
104 | "estimate for loops_per_jiffy.\nProbably due to long platform interrupts. Consider using \"lpj=\" boot option.\n"); | 166 | "estimate for loops_per_jiffy.\nProbably due to long platform " |
167 | "interrupts. Consider using \"lpj=\" boot option.\n"); | ||
105 | return 0; | 168 | return 0; |
106 | } | 169 | } |
107 | #else | 170 | #else |