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

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