linux/init/calibrate.c
<<
>>
Prefs
   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#include <linux/smp.h>
  12#include <linux/percpu.h>
  13
  14unsigned long lpj_fine;
  15unsigned long preset_lpj;
  16static int __init lpj_setup(char *str)
  17{
  18        preset_lpj = simple_strtoul(str,NULL,0);
  19        return 1;
  20}
  21
  22__setup("lpj=", lpj_setup);
  23
  24#ifdef ARCH_HAS_READ_CURRENT_TIMER
  25
  26/* This routine uses the read_current_timer() routine and gets the
  27 * loops per jiffy directly, instead of guessing it using delay().
  28 * Also, this code tries to handle non-maskable asynchronous events
  29 * (like SMIs)
  30 */
  31#define DELAY_CALIBRATION_TICKS                 ((HZ < 100) ? 1 : (HZ/100))
  32#define MAX_DIRECT_CALIBRATION_RETRIES          5
  33
  34static unsigned long __cpuinit calibrate_delay_direct(void)
  35{
  36        unsigned long pre_start, start, post_start;
  37        unsigned long pre_end, end, post_end;
  38        unsigned long start_jiffies;
  39        unsigned long timer_rate_min, timer_rate_max;
  40        unsigned long good_timer_sum = 0;
  41        unsigned long good_timer_count = 0;
  42        unsigned long measured_times[MAX_DIRECT_CALIBRATION_RETRIES];
  43        int max = -1; /* index of measured_times with max/min values or not set */
  44        int min = -1;
  45        int i;
  46
  47        if (read_current_timer(&pre_start) < 0 )
  48                return 0;
  49
  50        /*
  51         * A simple loop like
  52         *      while ( jiffies < start_jiffies+1)
  53         *              start = read_current_timer();
  54         * will not do. As we don't really know whether jiffy switch
  55         * happened first or timer_value was read first. And some asynchronous
  56         * event can happen between these two events introducing errors in lpj.
  57         *
  58         * So, we do
  59         * 1. pre_start <- When we are sure that jiffy switch hasn't happened
  60         * 2. check jiffy switch
  61         * 3. start <- timer value before or after jiffy switch
  62         * 4. post_start <- When we are sure that jiffy switch has happened
  63         *
  64         * Note, we don't know anything about order of 2 and 3.
  65         * Now, by looking at post_start and pre_start difference, we can
  66         * check whether any asynchronous event happened or not
  67         */
  68
  69        for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) {
  70                pre_start = 0;
  71                read_current_timer(&start);
  72                start_jiffies = jiffies;
  73                while (time_before_eq(jiffies, start_jiffies + 1)) {
  74                        pre_start = start;
  75                        read_current_timer(&start);
  76                }
  77                read_current_timer(&post_start);
  78
  79                pre_end = 0;
  80                end = post_start;
  81                while (time_before_eq(jiffies, start_jiffies + 1 +
  82                                               DELAY_CALIBRATION_TICKS)) {
  83                        pre_end = end;
  84                        read_current_timer(&end);
  85                }
  86                read_current_timer(&post_end);
  87
  88                timer_rate_max = (post_end - pre_start) /
  89                                        DELAY_CALIBRATION_TICKS;
  90                timer_rate_min = (pre_end - post_start) /
  91                                        DELAY_CALIBRATION_TICKS;
  92
  93                /*
  94                 * If the upper limit and lower limit of the timer_rate is
  95                 * >= 12.5% apart, redo calibration.
  96                 */
  97                if (start >= post_end)
  98                        printk(KERN_NOTICE "calibrate_delay_direct() ignoring "
  99                                        "timer_rate as we had a TSC wrap around"
 100                                        " start=%lu >=post_end=%lu\n",
 101                                start, post_end);
 102                if (start < post_end && pre_start != 0 && pre_end != 0 &&
 103                    (timer_rate_max - timer_rate_min) < (timer_rate_max >> 3)) {
 104                        good_timer_count++;
 105                        good_timer_sum += timer_rate_max;
 106                        measured_times[i] = timer_rate_max;
 107                        if (max < 0 || timer_rate_max > measured_times[max])
 108                                max = i;
 109                        if (min < 0 || timer_rate_max < measured_times[min])
 110                                min = i;
 111                } else
 112                        measured_times[i] = 0;
 113
 114        }
 115
 116        /*
 117         * Find the maximum & minimum - if they differ too much throw out the
 118         * one with the largest difference from the mean and try again...
 119         */
 120        while (good_timer_count > 1) {
 121                unsigned long estimate;
 122                unsigned long maxdiff;
 123
 124                /* compute the estimate */
 125                estimate = (good_timer_sum/good_timer_count);
 126                maxdiff = estimate >> 3;
 127
 128                /* if range is within 12% let's take it */
 129                if ((measured_times[max] - measured_times[min]) < maxdiff)
 130                        return estimate;
 131
 132                /* ok - drop the worse value and try again... */
 133                good_timer_sum = 0;
 134                good_timer_count = 0;
 135                if ((measured_times[max] - estimate) <
 136                                (estimate - measured_times[min])) {
 137                        printk(KERN_NOTICE "calibrate_delay_direct() dropping "
 138                                        "min bogoMips estimate %d = %lu\n",
 139                                min, measured_times[min]);
 140                        measured_times[min] = 0;
 141                        min = max;
 142                } else {
 143                        printk(KERN_NOTICE "calibrate_delay_direct() dropping "
 144                                        "max bogoMips estimate %d = %lu\n",
 145                                max, measured_times[max]);
 146                        measured_times[max] = 0;
 147                        max = min;
 148                }
 149
 150                for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) {
 151                        if (measured_times[i] == 0)
 152                                continue;
 153                        good_timer_count++;
 154                        good_timer_sum += measured_times[i];
 155                        if (measured_times[i] < measured_times[min])
 156                                min = i;
 157                        if (measured_times[i] > measured_times[max])
 158                                max = i;
 159                }
 160
 161        }
 162
 163        printk(KERN_NOTICE "calibrate_delay_direct() failed to get a good "
 164               "estimate for loops_per_jiffy.\nProbably due to long platform "
 165                "interrupts. Consider using \"lpj=\" boot option.\n");
 166        return 0;
 167}
 168#else
 169static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;}
 170#endif
 171
 172/*
 173 * This is the number of bits of precision for the loops_per_jiffy.  Each
 174 * time we refine our estimate after the first takes 1.5/HZ seconds, so try
 175 * to start with a good estimate.
 176 * For the boot cpu we can skip the delay calibration and assign it a value
 177 * calculated based on the timer frequency.
 178 * For the rest of the CPUs we cannot assume that the timer frequency is same as
 179 * the cpu frequency, hence do the calibration for those.
 180 */
 181#define LPS_PREC 8
 182
 183static unsigned long __cpuinit calibrate_delay_converge(void)
 184{
 185        /* First stage - slowly accelerate to find initial bounds */
 186        unsigned long lpj, lpj_base, ticks, loopadd, loopadd_base, chop_limit;
 187        int trials = 0, band = 0, trial_in_band = 0;
 188
 189        lpj = (1<<12);
 190
 191        /* wait for "start of" clock tick */
 192        ticks = jiffies;
 193        while (ticks == jiffies)
 194                ; /* nothing */
 195        /* Go .. */
 196        ticks = jiffies;
 197        do {
 198                if (++trial_in_band == (1<<band)) {
 199                        ++band;
 200                        trial_in_band = 0;
 201                }
 202                __delay(lpj * band);
 203                trials += band;
 204        } while (ticks == jiffies);
 205        /*
 206         * We overshot, so retreat to a clear underestimate. Then estimate
 207         * the largest likely undershoot. This defines our chop bounds.
 208         */
 209        trials -= band;
 210        loopadd_base = lpj * band;
 211        lpj_base = lpj * trials;
 212
 213recalibrate:
 214        lpj = lpj_base;
 215        loopadd = loopadd_base;
 216
 217        /*
 218         * Do a binary approximation to get lpj set to
 219         * equal one clock (up to LPS_PREC bits)
 220         */
 221        chop_limit = lpj >> LPS_PREC;
 222        while (loopadd > chop_limit) {
 223                lpj += loopadd;
 224                ticks = jiffies;
 225                while (ticks == jiffies)
 226                        ; /* nothing */
 227                ticks = jiffies;
 228                __delay(lpj);
 229                if (jiffies != ticks)   /* longer than 1 tick */
 230                        lpj -= loopadd;
 231                loopadd >>= 1;
 232        }
 233        /*
 234         * If we incremented every single time possible, presume we've
 235         * massively underestimated initially, and retry with a higher
 236         * start, and larger range. (Only seen on x86_64, due to SMIs)
 237         */
 238        if (lpj + loopadd * 2 == lpj_base + loopadd_base * 2) {
 239                lpj_base = lpj;
 240                loopadd_base <<= 2;
 241                goto recalibrate;
 242        }
 243
 244        return lpj;
 245}
 246
 247static DEFINE_PER_CPU(unsigned long, cpu_loops_per_jiffy) = { 0 };
 248
 249void __cpuinit calibrate_delay(void)
 250{
 251        unsigned long lpj;
 252        static bool printed;
 253        int this_cpu = smp_processor_id();
 254
 255        if (per_cpu(cpu_loops_per_jiffy, this_cpu)) {
 256                lpj = per_cpu(cpu_loops_per_jiffy, this_cpu);
 257                pr_info("Calibrating delay loop (skipped) "
 258                                "already calibrated this CPU");
 259        } else if (preset_lpj) {
 260                lpj = preset_lpj;
 261                if (!printed)
 262                        pr_info("Calibrating delay loop (skipped) "
 263                                "preset value.. ");
 264        } else if ((!printed) && lpj_fine) {
 265                lpj = lpj_fine;
 266                pr_info("Calibrating delay loop (skipped), "
 267                        "value calculated using timer frequency.. ");
 268        } else if ((lpj = calibrate_delay_direct()) != 0) {
 269                if (!printed)
 270                        pr_info("Calibrating delay using timer "
 271                                "specific routine.. ");
 272        } else {
 273                if (!printed)
 274                        pr_info("Calibrating delay loop... ");
 275                lpj = calibrate_delay_converge();
 276        }
 277        per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj;
 278        if (!printed)
 279                pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
 280                        lpj/(500000/HZ),
 281                        (lpj/(5000/HZ)) % 100, lpj);
 282
 283        loops_per_jiffy = lpj;
 284        printed = true;
 285}
 286
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.