root/drivers/char/ftape/calibr.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. timestamp
  2. timediff
  3. time_inb
  4. fix_clock
  5. calibrate

   1 /* Yo, Emacs! we're -*- Linux-C -*-
   2  *
   3  *      Copyright (C) 1993-1995 Bas Laarhoven.
   4 
   5  This program is free software; you can redistribute it and/or modify
   6  it under the terms of the GNU General Public License as published by
   7  the Free Software Foundation; either version 2, or (at your option)
   8  any later version.
   9 
  10  This program is distributed in the hope that it will be useful,
  11  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13  GNU General Public License for more details.
  14 
  15  You should have received a copy of the GNU General Public License
  16  along with this program; see the file COPYING.  If not, write to
  17  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18 
  19  *      GP calibration routine for processor speed dependent
  20  *      functions.
  21  */
  22 
  23 #include <linux/module.h>
  24 #include <linux/errno.h>
  25 #include <linux/sched.h>
  26 #include <linux/ftape.h>
  27 #include <asm/system.h>
  28 #include <asm/io.h>
  29 
  30 #include "tracing.h"
  31 #include "calibr.h"
  32 #include "fdc-io.h"
  33 
  34 #undef DEBUG
  35 
  36 unsigned timestamp(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  37 {
  38         unsigned count;
  39         unsigned long flags;
  40 
  41         save_flags(flags);
  42         cli();
  43         outb_p(0x00, 0x43);     /* latch the count ASAP */
  44         count = inb_p(0x40);    /* read the latched count */
  45         count |= inb(0x40) << 8;
  46         restore_flags(flags);
  47         return (LATCH - count); /* normal: downcounter */
  48 }
  49 
  50 int timediff(int t0, int t1)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52         /*  Calculate difference in usec for timestamp results t0 & t1.
  53          *  Note that the maximum timespan allowed is 1/HZ or we'll lose ticks!
  54          */
  55         if (t1 < t0) {
  56                 t1 += LATCH;
  57         }
  58         return (1000 * (t1 - t0)) / ((CLOCK_TICK_RATE + 500) / 1000);
  59 }
  60 
  61 /*      To get an indication of the I/O performance,
  62  *      measure the duration of the inb() function.
  63  */
  64 void time_inb(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  65 {
  66         TRACE_FUN(8, "time_inb");
  67         int i;
  68         int t0, t1;
  69         unsigned long flags;
  70         int status;
  71 
  72         save_flags(flags);
  73         cli();
  74         t0 = timestamp();
  75         for (i = 0; i < 1000; ++i) {
  76                 status = inb(fdc.msr);
  77         }
  78         t1 = timestamp();
  79         restore_flags(flags);
  80         if (t1 - t0 <= 0) {
  81                 t1 += LATCH;
  82         }
  83         TRACEx1(4, "inb() duration: %d nsec", timediff(t0, t1));
  84         TRACE_EXIT;
  85 }
  86 
  87 /*  Haven't studied on why, but there sometimes is a problem
  88  *  with the tick timer readout. The two bytes get swapped.
  89  *  This hack solves that problem by doing one extra input.
  90  */
  91 void fix_clock(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93         TRACE_FUN(8, "fix_clock");
  94         int t;
  95         int i;
  96 
  97         for (i = 0; i < 1000; ++i) {
  98                 t = timestamp();
  99                 if (t < 0) {
 100                         inb_p(0x40);    /* get in sync again */
 101                         TRACE(2, "clock counter fixed");
 102                         break;
 103                 }
 104         }
 105         TRACE_EXIT;
 106 }
 107 
 108 /*
 109  *      Input:  function taking int count as parameter.
 110  *              pointers to calculated calibration variables.
 111  */
 112 int calibrate(char *name, void (*fun) (int), int *calibr_count, int *calibr_time)
     /* [previous][next][first][last][top][bottom][index][help] */
 113 {
 114         TRACE_FUN(5, "calibrate");
 115         static int first_time = 1;
 116         int i;
 117         int old_tc = 0;
 118         int old_count = 1;
 119         int old_time = 1;
 120 
 121         if (first_time) {       /* get idea of I/O performance */
 122                 fix_clock();
 123                 time_inb();
 124                 first_time = 0;
 125         }
 126         /*    value of timeout must be set so that on very slow systems
 127          *    it will give a time less than one jiffy, and on
 128          *    very fast systems it'll give reasonable precision.
 129          */
 130 
 131         *calibr_count = 10;
 132         for (i = 0; i < 15; ++i) {
 133                 int t0, t1;
 134                 unsigned long flags;
 135                 int once;
 136                 int multiple;
 137                 int tc;
 138 
 139                 *calibr_time = *calibr_count;   /* set TC to 1 */
 140                 fun(0);         /* dummy, get code into cache */
 141                 save_flags(flags);
 142                 cli();
 143                 t0 = timestamp();
 144                 fun(0);         /* overhead + one test */
 145                 t1 = timestamp();
 146                 if (t1 < t0) {
 147                         t1 += LATCH;
 148                 }
 149                 once = t1 - t0;
 150                 t0 = timestamp();
 151                 fun(*calibr_count);     /* overhead + multiple tests */
 152                 t1 = timestamp();
 153                 if (t1 < t0) {
 154                         t1 += LATCH;
 155                 }
 156                 multiple = t1 - t0;
 157                 restore_flags(flags);
 158                 *calibr_time = (10000 * (multiple - once)) / (CLOCK_TICK_RATE / 100);
 159                 --*calibr_count;        /* because delta corresponds to this count */
 160                 tc = (1000 * *calibr_time) / *calibr_count;
 161                 TRACEx4(8, "once:%4d us,%5d times:%6d us, TC:%5d ns",
 162                         (10000 * once) / (CLOCK_TICK_RATE / 100),
 163                         *calibr_count,
 164                         (10000 * multiple) / (CLOCK_TICK_RATE / 100),
 165                         tc);
 166                 /*
 167                  * increase the count until the resulting time nears 2/HZ,
 168                  * then the tc will drop sharply because we lose LATCH counts.
 169                  */
 170                 if (tc <= old_tc / 2) {
 171                         *calibr_time = old_time;
 172                         *calibr_count = old_count;
 173                         break;
 174                 }
 175                 old_tc = tc;
 176                 old_count = *calibr_count;
 177                 old_time = *calibr_time;
 178                 *calibr_count *= 2;
 179         }
 180         TRACEx3(4, "TC for `%s()' = %d nsec (at %d counts)",
 181              name, (1000 * *calibr_time) / *calibr_count, *calibr_count);
 182         TRACE_EXIT;
 183         return 0;
 184 }

/* [previous][next][first][last][top][bottom][index][help] */