1 /* calibrate.c: default delay calibration 2 * 3 * Excised from init/main.c 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 */ 6 7 #include <linux/jiffies.h> 8 #include <linux/delay.h> 9 #include <linux/init.h> 10 #include <linux/timex.h> 11 12 unsigned long preset_lpj; 13 static int __init lpj_setup(char *str) 14 { 15 preset_lpj = simple_strtoul(str,NULL,0); 16 return 1; 17 } 18 19 __setup("lpj=", lpj_setup); 20 21 #ifdef ARCH_HAS_READ_CURRENT_TIMER 22 23 /* This routine uses the read_current_timer() routine and gets the 24 * loops per jiffy directly, instead of guessing it using delay(). 25 * Also, this code tries to handle non-maskable asynchronous events 26 * (like SMIs) 27 */ 28 #define DELAY_CALIBRATION_TICKS ((HZ < 100) ? 1 : (HZ/100)) 29 #define MAX_DIRECT_CALIBRATION_RETRIES 5 30 31 static unsigned long __cpuinit calibrate_delay_direct(void) 32 { 33 unsigned long pre_start, start, post_start; 34 unsigned long pre_end, end, post_end; 35 unsigned long start_jiffies; 36 unsigned long tsc_rate_min, tsc_rate_max; 37 unsigned long good_tsc_sum = 0; 38 unsigned long good_tsc_count = 0; 39 int i; 40 41 if (read_current_timer(&pre_start) < 0 ) 42 return 0; 43 44 /* 45 * A simple loop like 46 * while ( jiffies < start_jiffies+1) 47 * start = read_current_timer(); 48 * will not do. As we don't really know whether jiffy switch 49 * happened first or timer_value was read first. And some asynchronous 50 * event can happen between these two events introducing errors in lpj. 51 * 52 * So, we do 53 * 1. pre_start <- When we are sure that jiffy switch hasn't happened 54 * 2. check jiffy switch 55 * 3. start <- timer value before or after jiffy switch 56 * 4. post_start <- When we are sure that jiffy switch has happened 57 * 58 * Note, we don't know anything about order of 2 and 3. 59 * Now, by looking at post_start and pre_start difference, we can 60 * check whether any asynchronous event happened or not 61 */ 62 63 for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) { 64 pre_start = 0; 65 read_current_timer(&start); 66 start_jiffies = jiffies; 67 while (jiffies <= (start_jiffies + 1)) { 68 pre_start = start; 69 read_current_timer(&start); 70 } 71 read_current_timer(&post_start); 72 73 pre_end = 0; 74 end = post_start; 75 while (jiffies <= 76 (start_jiffies + 1 + DELAY_CALIBRATION_TICKS)) { 77 pre_end = end; 78 read_current_timer(&end); 79 } 80 read_current_timer(&post_end); 81 82 tsc_rate_max = (post_end - pre_start) / DELAY_CALIBRATION_TICKS; 83 tsc_rate_min = (pre_end - post_start) / DELAY_CALIBRATION_TICKS; 84 85 /* 86 * If the upper limit and lower limit of the tsc_rate is 87 * >= 12.5% apart, redo calibration. 88 */ 89 if (pre_start != 0 && pre_end != 0 && 90 (tsc_rate_max - tsc_rate_min) < (tsc_rate_max >> 3)) { 91 good_tsc_count++; 92 good_tsc_sum += tsc_rate_max; 93 } 94 } 95 96 if (good_tsc_count) 97 return (good_tsc_sum/good_tsc_count); 98 99 printk(KERN_WARNING "calibrate_delay_direct() failed to get a good " 100 "estimate for loops_per_jiffy.\nProbably due to long platform interrupts. Consider using \"lpj=\" boot option.\n"); 101 return 0; 102 } 103 #else 104 static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;} 105 #endif 106 107 /* 108 * This is the number of bits of precision for the loops_per_jiffy. Each 109 * bit takes on average 1.5/HZ seconds. This (like the original) is a little 110 * better than 1% 111 */ 112 #define LPS_PREC 8 113 114 void __cpuinit calibrate_delay(void) 115 { 116 unsigned long ticks, loopbit; 117 int lps_precision = LPS_PREC; 118 119 if (preset_lpj) { 120 loops_per_jiffy = preset_lpj; 121 printk("Calibrating delay loop (skipped)... " 122 "%lu.%02lu BogoMIPS preset\n", 123 loops_per_jiffy/(500000/HZ), 124 (loops_per_jiffy/(5000/HZ)) % 100); 125 } else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) { 126 printk("Calibrating delay using timer specific routine.. "); 127 printk("%lu.%02lu BogoMIPS (lpj=%lu)\n", 128 loops_per_jiffy/(500000/HZ), 129 (loops_per_jiffy/(5000/HZ)) % 100, 130 loops_per_jiffy); 131 } else { 132 loops_per_jiffy = (1<<12); 133 134 printk(KERN_DEBUG "Calibrating delay loop... "); 135 while ((loops_per_jiffy <<= 1) != 0) { 136 /* wait for "start of" clock tick */ 137 ticks = jiffies; 138 while (ticks == jiffies) 139 /* nothing */; 140 /* Go .. */ 141 ticks = jiffies; 142 __delay(loops_per_jiffy); 143 ticks = jiffies - ticks; 144 if (ticks) 145 break; 146 } 147 148 /* 149 * Do a binary approximation to get loops_per_jiffy set to 150 * equal one clock (up to lps_precision bits) 151 */ 152 loops_per_jiffy >>= 1; 153 loopbit = loops_per_jiffy; 154 while (lps_precision-- && (loopbit >>= 1)) { 155 loops_per_jiffy |= loopbit; 156 ticks = jiffies; 157 while (ticks == jiffies) 158 /* nothing */; 159 ticks = jiffies; 160 __delay(loops_per_jiffy); 161 if (jiffies != ticks) /* longer than 1 tick */ 162 loops_per_jiffy &= ~loopbit; 163 } 164 165 /* Round the value and print it */ 166 printk("%lu.%02lu BogoMIPS (lpj=%lu)\n", 167 loops_per_jiffy/(500000/HZ), 168 (loops_per_jiffy/(5000/HZ)) % 100, 169 loops_per_jiffy); 170 } 171 172 } 173