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 76ac9194cbc..cfd7000c9d7 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 |
