xref: /linux/init/calibrate.c (revision bfe8df3d314bddf30758bd738e0087e80964760c)
11da177e4SLinus Torvalds /* calibrate.c: default delay calibration
21da177e4SLinus Torvalds  *
31da177e4SLinus Torvalds  * Excised from init/main.c
41da177e4SLinus Torvalds  *  Copyright (C) 1991, 1992  Linus Torvalds
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
7cd354f1aSTim Schmielau #include <linux/jiffies.h>
81da177e4SLinus Torvalds #include <linux/delay.h>
91da177e4SLinus Torvalds #include <linux/init.h>
101da177e4SLinus Torvalds 
118a9e1b0fSVenkatesh Pallipadi #include <asm/timex.h>
128a9e1b0fSVenkatesh Pallipadi 
13*bfe8df3dSRandy Dunlap unsigned long preset_lpj;
141da177e4SLinus Torvalds static int __init lpj_setup(char *str)
151da177e4SLinus Torvalds {
161da177e4SLinus Torvalds 	preset_lpj = simple_strtoul(str,NULL,0);
171da177e4SLinus Torvalds 	return 1;
181da177e4SLinus Torvalds }
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds __setup("lpj=", lpj_setup);
211da177e4SLinus Torvalds 
228a9e1b0fSVenkatesh Pallipadi #ifdef ARCH_HAS_READ_CURRENT_TIMER
238a9e1b0fSVenkatesh Pallipadi 
248a9e1b0fSVenkatesh Pallipadi /* This routine uses the read_current_timer() routine and gets the
258a9e1b0fSVenkatesh Pallipadi  * loops per jiffy directly, instead of guessing it using delay().
268a9e1b0fSVenkatesh Pallipadi  * Also, this code tries to handle non-maskable asynchronous events
278a9e1b0fSVenkatesh Pallipadi  * (like SMIs)
288a9e1b0fSVenkatesh Pallipadi  */
298a9e1b0fSVenkatesh Pallipadi #define DELAY_CALIBRATION_TICKS			((HZ < 100) ? 1 : (HZ/100))
308a9e1b0fSVenkatesh Pallipadi #define MAX_DIRECT_CALIBRATION_RETRIES		5
318a9e1b0fSVenkatesh Pallipadi 
328a9e1b0fSVenkatesh Pallipadi static unsigned long __devinit calibrate_delay_direct(void)
338a9e1b0fSVenkatesh Pallipadi {
348a9e1b0fSVenkatesh Pallipadi 	unsigned long pre_start, start, post_start;
358a9e1b0fSVenkatesh Pallipadi 	unsigned long pre_end, end, post_end;
368a9e1b0fSVenkatesh Pallipadi 	unsigned long start_jiffies;
378a9e1b0fSVenkatesh Pallipadi 	unsigned long tsc_rate_min, tsc_rate_max;
388a9e1b0fSVenkatesh Pallipadi 	unsigned long good_tsc_sum = 0;
398a9e1b0fSVenkatesh Pallipadi 	unsigned long good_tsc_count = 0;
408a9e1b0fSVenkatesh Pallipadi 	int i;
418a9e1b0fSVenkatesh Pallipadi 
428a9e1b0fSVenkatesh Pallipadi 	if (read_current_timer(&pre_start) < 0 )
438a9e1b0fSVenkatesh Pallipadi 		return 0;
448a9e1b0fSVenkatesh Pallipadi 
458a9e1b0fSVenkatesh Pallipadi 	/*
468a9e1b0fSVenkatesh Pallipadi 	 * A simple loop like
478a9e1b0fSVenkatesh Pallipadi 	 *	while ( jiffies < start_jiffies+1)
488a9e1b0fSVenkatesh Pallipadi 	 *		start = read_current_timer();
498a9e1b0fSVenkatesh Pallipadi 	 * will not do. As we don't really know whether jiffy switch
508a9e1b0fSVenkatesh Pallipadi 	 * happened first or timer_value was read first. And some asynchronous
518a9e1b0fSVenkatesh Pallipadi 	 * event can happen between these two events introducing errors in lpj.
528a9e1b0fSVenkatesh Pallipadi 	 *
538a9e1b0fSVenkatesh Pallipadi 	 * So, we do
548a9e1b0fSVenkatesh Pallipadi 	 * 1. pre_start <- When we are sure that jiffy switch hasn't happened
558a9e1b0fSVenkatesh Pallipadi 	 * 2. check jiffy switch
568a9e1b0fSVenkatesh Pallipadi 	 * 3. start <- timer value before or after jiffy switch
578a9e1b0fSVenkatesh Pallipadi 	 * 4. post_start <- When we are sure that jiffy switch has happened
588a9e1b0fSVenkatesh Pallipadi 	 *
598a9e1b0fSVenkatesh Pallipadi 	 * Note, we don't know anything about order of 2 and 3.
608a9e1b0fSVenkatesh Pallipadi 	 * Now, by looking at post_start and pre_start difference, we can
618a9e1b0fSVenkatesh Pallipadi 	 * check whether any asynchronous event happened or not
628a9e1b0fSVenkatesh Pallipadi 	 */
638a9e1b0fSVenkatesh Pallipadi 
648a9e1b0fSVenkatesh Pallipadi 	for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) {
658a9e1b0fSVenkatesh Pallipadi 		pre_start = 0;
668a9e1b0fSVenkatesh Pallipadi 		read_current_timer(&start);
678a9e1b0fSVenkatesh Pallipadi 		start_jiffies = jiffies;
688a9e1b0fSVenkatesh Pallipadi 		while (jiffies <= (start_jiffies + 1)) {
698a9e1b0fSVenkatesh Pallipadi 			pre_start = start;
708a9e1b0fSVenkatesh Pallipadi 			read_current_timer(&start);
718a9e1b0fSVenkatesh Pallipadi 		}
728a9e1b0fSVenkatesh Pallipadi 		read_current_timer(&post_start);
738a9e1b0fSVenkatesh Pallipadi 
748a9e1b0fSVenkatesh Pallipadi 		pre_end = 0;
758a9e1b0fSVenkatesh Pallipadi 		end = post_start;
768a9e1b0fSVenkatesh Pallipadi 		while (jiffies <=
778a9e1b0fSVenkatesh Pallipadi 		       (start_jiffies + 1 + DELAY_CALIBRATION_TICKS)) {
788a9e1b0fSVenkatesh Pallipadi 			pre_end = end;
798a9e1b0fSVenkatesh Pallipadi 			read_current_timer(&end);
808a9e1b0fSVenkatesh Pallipadi 		}
818a9e1b0fSVenkatesh Pallipadi 		read_current_timer(&post_end);
828a9e1b0fSVenkatesh Pallipadi 
838a9e1b0fSVenkatesh Pallipadi 		tsc_rate_max = (post_end - pre_start) / DELAY_CALIBRATION_TICKS;
848a9e1b0fSVenkatesh Pallipadi 		tsc_rate_min = (pre_end - post_start) / DELAY_CALIBRATION_TICKS;
858a9e1b0fSVenkatesh Pallipadi 
868a9e1b0fSVenkatesh Pallipadi 		/*
878a9e1b0fSVenkatesh Pallipadi 	 	 * If the upper limit and lower limit of the tsc_rate is
888a9e1b0fSVenkatesh Pallipadi 		 * >= 12.5% apart, redo calibration.
898a9e1b0fSVenkatesh Pallipadi 		 */
908a9e1b0fSVenkatesh Pallipadi 		if (pre_start != 0 && pre_end != 0 &&
918a9e1b0fSVenkatesh Pallipadi 		    (tsc_rate_max - tsc_rate_min) < (tsc_rate_max >> 3)) {
928a9e1b0fSVenkatesh Pallipadi 			good_tsc_count++;
938a9e1b0fSVenkatesh Pallipadi 			good_tsc_sum += tsc_rate_max;
948a9e1b0fSVenkatesh Pallipadi 		}
958a9e1b0fSVenkatesh Pallipadi 	}
968a9e1b0fSVenkatesh Pallipadi 
978a9e1b0fSVenkatesh Pallipadi 	if (good_tsc_count)
988a9e1b0fSVenkatesh Pallipadi 		return (good_tsc_sum/good_tsc_count);
998a9e1b0fSVenkatesh Pallipadi 
1008a9e1b0fSVenkatesh Pallipadi 	printk(KERN_WARNING "calibrate_delay_direct() failed to get a good "
1018a9e1b0fSVenkatesh Pallipadi 	       "estimate for loops_per_jiffy.\nProbably due to long platform interrupts. Consider using \"lpj=\" boot option.\n");
1028a9e1b0fSVenkatesh Pallipadi 	return 0;
1038a9e1b0fSVenkatesh Pallipadi }
1048a9e1b0fSVenkatesh Pallipadi #else
1058a9e1b0fSVenkatesh Pallipadi static unsigned long __devinit calibrate_delay_direct(void) {return 0;}
1068a9e1b0fSVenkatesh Pallipadi #endif
1078a9e1b0fSVenkatesh Pallipadi 
1081da177e4SLinus Torvalds /*
1091da177e4SLinus Torvalds  * This is the number of bits of precision for the loops_per_jiffy.  Each
1101da177e4SLinus Torvalds  * bit takes on average 1.5/HZ seconds.  This (like the original) is a little
1111da177e4SLinus Torvalds  * better than 1%
1121da177e4SLinus Torvalds  */
1131da177e4SLinus Torvalds #define LPS_PREC 8
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds void __devinit calibrate_delay(void)
1161da177e4SLinus Torvalds {
1171da177e4SLinus Torvalds 	unsigned long ticks, loopbit;
1181da177e4SLinus Torvalds 	int lps_precision = LPS_PREC;
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds 	if (preset_lpj) {
1211da177e4SLinus Torvalds 		loops_per_jiffy = preset_lpj;
1221da177e4SLinus Torvalds 		printk("Calibrating delay loop (skipped)... "
1231da177e4SLinus Torvalds 			"%lu.%02lu BogoMIPS preset\n",
1241da177e4SLinus Torvalds 			loops_per_jiffy/(500000/HZ),
1251da177e4SLinus Torvalds 			(loops_per_jiffy/(5000/HZ)) % 100);
1268a9e1b0fSVenkatesh Pallipadi 	} else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) {
1278a9e1b0fSVenkatesh Pallipadi 		printk("Calibrating delay using timer specific routine.. ");
1288a9e1b0fSVenkatesh Pallipadi 		printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",
1298a9e1b0fSVenkatesh Pallipadi 			loops_per_jiffy/(500000/HZ),
1308a9e1b0fSVenkatesh Pallipadi 			(loops_per_jiffy/(5000/HZ)) % 100,
1318a9e1b0fSVenkatesh Pallipadi 			loops_per_jiffy);
1321da177e4SLinus Torvalds 	} else {
1331da177e4SLinus Torvalds 		loops_per_jiffy = (1<<12);
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds 		printk(KERN_DEBUG "Calibrating delay loop... ");
1361da177e4SLinus Torvalds 		while ((loops_per_jiffy <<= 1) != 0) {
1371da177e4SLinus Torvalds 			/* wait for "start of" clock tick */
1381da177e4SLinus Torvalds 			ticks = jiffies;
1391da177e4SLinus Torvalds 			while (ticks == jiffies)
1401da177e4SLinus Torvalds 				/* nothing */;
1411da177e4SLinus Torvalds 			/* Go .. */
1421da177e4SLinus Torvalds 			ticks = jiffies;
1431da177e4SLinus Torvalds 			__delay(loops_per_jiffy);
1441da177e4SLinus Torvalds 			ticks = jiffies - ticks;
1451da177e4SLinus Torvalds 			if (ticks)
1461da177e4SLinus Torvalds 				break;
1471da177e4SLinus Torvalds 		}
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds 		/*
1501da177e4SLinus Torvalds 		 * Do a binary approximation to get loops_per_jiffy set to
1511da177e4SLinus Torvalds 		 * equal one clock (up to lps_precision bits)
1521da177e4SLinus Torvalds 		 */
1531da177e4SLinus Torvalds 		loops_per_jiffy >>= 1;
1541da177e4SLinus Torvalds 		loopbit = loops_per_jiffy;
1551da177e4SLinus Torvalds 		while (lps_precision-- && (loopbit >>= 1)) {
1561da177e4SLinus Torvalds 			loops_per_jiffy |= loopbit;
1571da177e4SLinus Torvalds 			ticks = jiffies;
1581da177e4SLinus Torvalds 			while (ticks == jiffies)
1591da177e4SLinus Torvalds 				/* nothing */;
1601da177e4SLinus Torvalds 			ticks = jiffies;
1611da177e4SLinus Torvalds 			__delay(loops_per_jiffy);
1621da177e4SLinus Torvalds 			if (jiffies != ticks)	/* longer than 1 tick */
1631da177e4SLinus Torvalds 				loops_per_jiffy &= ~loopbit;
1641da177e4SLinus Torvalds 		}
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 		/* Round the value and print it */
1671da177e4SLinus Torvalds 		printk("%lu.%02lu BogoMIPS (lpj=%lu)\n",
1681da177e4SLinus Torvalds 			loops_per_jiffy/(500000/HZ),
1691da177e4SLinus Torvalds 			(loops_per_jiffy/(5000/HZ)) % 100,
1701da177e4SLinus Torvalds 			loops_per_jiffy);
1711da177e4SLinus Torvalds 	}
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds }
174