]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - init/calibrate.c
[SCSI] use default attributes for scsi_host
[linux-2.6.git] / init / calibrate.c
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 }