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