linux-old/drivers/ide/ide-timing.h
<<
>>
Prefs
   1#ifndef _IDE_TIMING_H
   2#define _IDE_TIMING_H
   3
   4/*
   5 * $Id: ide-timing.h,v 1.6 2001/12/23 22:47:56 vojtech Exp $
   6 *
   7 *  Copyright (c) 1999-2001 Vojtech Pavlik
   8 */
   9
  10/*
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24 *
  25 * Should you need to contact me, the author, you can do so either by
  26 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  27 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  28 */
  29
  30#include <linux/hdreg.h>
  31
  32#define XFER_PIO_5              0x0d
  33#define XFER_UDMA_SLOW          0x4f
  34
  35struct ide_timing {
  36        short mode;
  37        short setup;    /* t1 */
  38        short act8b;    /* t2 for 8-bit io */
  39        short rec8b;    /* t2i for 8-bit io */
  40        short cyc8b;    /* t0 for 8-bit io */
  41        short active;   /* t2 or tD */
  42        short recover;  /* t2i or tK */
  43        short cycle;    /* t0 */
  44        short udma;     /* t2CYCTYP/2 */
  45};
  46
  47/*
  48 * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
  49 * These were taken from ATA/ATAPI-6 standard, rev 0a, except
  50 * for PIO 5, which is a nonstandard extension and UDMA6, which
  51 * is currently supported only by Maxtor drives. 
  52 */
  53
  54static struct ide_timing ide_timing[] = {
  55
  56        { XFER_UDMA_6,     0,   0,   0,   0,   0,   0,   0,  15 },
  57        { XFER_UDMA_5,     0,   0,   0,   0,   0,   0,   0,  20 },
  58        { XFER_UDMA_4,     0,   0,   0,   0,   0,   0,   0,  30 },
  59        { XFER_UDMA_3,     0,   0,   0,   0,   0,   0,   0,  45 },
  60
  61        { XFER_UDMA_2,     0,   0,   0,   0,   0,   0,   0,  60 },
  62        { XFER_UDMA_1,     0,   0,   0,   0,   0,   0,   0,  80 },
  63        { XFER_UDMA_0,     0,   0,   0,   0,   0,   0,   0, 120 },
  64
  65        { XFER_UDMA_SLOW,  0,   0,   0,   0,   0,   0,   0, 150 },
  66                                          
  67        { XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 120,   0 },
  68        { XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 150,   0 },
  69        { XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 480,   0 },
  70                                          
  71        { XFER_SW_DMA_2,  60,   0,   0,   0, 120, 120, 240,   0 },
  72        { XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 480,   0 },
  73        { XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 960,   0 },
  74
  75        { XFER_PIO_5,     20,  50,  30, 100,  50,  30, 100,   0 },
  76        { XFER_PIO_4,     25,  70,  25, 120,  70,  25, 120,   0 },
  77        { XFER_PIO_3,     30,  80,  70, 180,  80,  70, 180,   0 },
  78
  79        { XFER_PIO_2,     30, 290,  40, 330, 100,  90, 240,   0 },
  80        { XFER_PIO_1,     50, 290,  93, 383, 125, 100, 383,   0 },
  81        { XFER_PIO_0,     70, 290, 240, 600, 165, 150, 600,   0 },
  82
  83        { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960,   0 },
  84
  85        { -1 }
  86};
  87
  88#define IDE_TIMING_SETUP        0x01
  89#define IDE_TIMING_ACT8B        0x02
  90#define IDE_TIMING_REC8B        0x04
  91#define IDE_TIMING_CYC8B        0x08
  92#define IDE_TIMING_8BIT         0x0e
  93#define IDE_TIMING_ACTIVE       0x10
  94#define IDE_TIMING_RECOVER      0x20
  95#define IDE_TIMING_CYCLE        0x40
  96#define IDE_TIMING_UDMA         0x80
  97#define IDE_TIMING_ALL          0xff
  98
  99#define MIN(a,b)        ((a)<(b)?(a):(b))
 100#define MAX(a,b)        ((a)>(b)?(a):(b))
 101#define FIT(v,min,max)  MAX(MIN(v,max),min)
 102#define ENOUGH(v,unit)  (((v)-1)/(unit)+1)
 103#define EZ(v,unit)      ((v)?ENOUGH(v,unit):0)
 104
 105#define XFER_MODE       0xf0
 106#define XFER_UDMA_133   0x48
 107#define XFER_UDMA_100   0x44
 108#define XFER_UDMA_66    0x42
 109#define XFER_UDMA       0x40
 110#define XFER_MWDMA      0x20
 111#define XFER_SWDMA      0x10
 112#define XFER_EPIO       0x01
 113#define XFER_PIO        0x00
 114
 115static short ide_find_best_mode(ide_drive_t *drive, int map)
 116{
 117        struct hd_driveid *id = drive->id;
 118        short best = 0;
 119
 120        if (!id)
 121                return XFER_PIO_SLOW;
 122
 123        if ((map & XFER_UDMA) && (id->field_valid & 4)) {       /* Want UDMA and UDMA bitmap valid */
 124
 125                if ((map & XFER_UDMA_133) == XFER_UDMA_133)
 126                        if ((best = (id->dma_ultra & 0x0040) ? XFER_UDMA_6 : 0)) return best;
 127
 128                if ((map & XFER_UDMA_100) == XFER_UDMA_100)
 129                        if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best;
 130
 131                if ((map & XFER_UDMA_66) == XFER_UDMA_66)
 132                        if ((best = (id->dma_ultra & 0x0010) ? XFER_UDMA_4 :
 133                                    (id->dma_ultra & 0x0008) ? XFER_UDMA_3 : 0)) return best;
 134
 135                if ((best = (id->dma_ultra & 0x0004) ? XFER_UDMA_2 :
 136                            (id->dma_ultra & 0x0002) ? XFER_UDMA_1 :
 137                            (id->dma_ultra & 0x0001) ? XFER_UDMA_0 : 0)) return best;
 138        }
 139
 140        if ((map & XFER_MWDMA) && (id->field_valid & 2)) {      /* Want MWDMA and drive has EIDE fields */
 141
 142                if ((best = (id->dma_mword & 0x0004) ? XFER_MW_DMA_2 :
 143                            (id->dma_mword & 0x0002) ? XFER_MW_DMA_1 :
 144                            (id->dma_mword & 0x0001) ? XFER_MW_DMA_0 : 0)) return best;
 145        }
 146
 147        if (map & XFER_SWDMA) {                                 /* Want SWDMA */
 148
 149                if (id->field_valid & 2) {                      /* EIDE SWDMA */
 150
 151                        if ((best = (id->dma_1word & 0x0004) ? XFER_SW_DMA_2 :
 152                                    (id->dma_1word & 0x0002) ? XFER_SW_DMA_1 :
 153                                    (id->dma_1word & 0x0001) ? XFER_SW_DMA_0 : 0)) return best;
 154                }
 155
 156                if (id->capability & 1) {                       /* Pre-EIDE style SWDMA */
 157
 158                        if ((best = (id->tDMA == 2) ? XFER_SW_DMA_2 :
 159                                    (id->tDMA == 1) ? XFER_SW_DMA_1 :
 160                                    (id->tDMA == 0) ? XFER_SW_DMA_0 : 0)) return best;
 161                }
 162        }
 163
 164
 165        if ((map & XFER_EPIO) && (id->field_valid & 2)) {       /* EIDE PIO modes */
 166
 167                if ((best = (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 :
 168                            (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 :
 169                            (drive->id->eide_pio_modes & 1) ? XFER_PIO_3 : 0)) return best;
 170        }
 171        
 172        return  (drive->id->tPIO == 2) ? XFER_PIO_2 :
 173                (drive->id->tPIO == 1) ? XFER_PIO_1 :
 174                (drive->id->tPIO == 0) ? XFER_PIO_0 : XFER_PIO_SLOW;
 175}
 176
 177static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT)
 178{
 179        q->setup   = EZ(t->setup   * 1000,  T);
 180        q->act8b   = EZ(t->act8b   * 1000,  T);
 181        q->rec8b   = EZ(t->rec8b   * 1000,  T);
 182        q->cyc8b   = EZ(t->cyc8b   * 1000,  T);
 183        q->active  = EZ(t->active  * 1000,  T);
 184        q->recover = EZ(t->recover * 1000,  T);
 185        q->cycle   = EZ(t->cycle   * 1000,  T);
 186        q->udma    = EZ(t->udma    * 1000, UT);
 187}
 188
 189static void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, struct ide_timing *m, unsigned int what)
 190{
 191        if (what & IDE_TIMING_SETUP  ) m->setup   = MAX(a->setup,   b->setup);
 192        if (what & IDE_TIMING_ACT8B  ) m->act8b   = MAX(a->act8b,   b->act8b);
 193        if (what & IDE_TIMING_REC8B  ) m->rec8b   = MAX(a->rec8b,   b->rec8b);
 194        if (what & IDE_TIMING_CYC8B  ) m->cyc8b   = MAX(a->cyc8b,   b->cyc8b);
 195        if (what & IDE_TIMING_ACTIVE ) m->active  = MAX(a->active,  b->active);
 196        if (what & IDE_TIMING_RECOVER) m->recover = MAX(a->recover, b->recover);
 197        if (what & IDE_TIMING_CYCLE  ) m->cycle   = MAX(a->cycle,   b->cycle);
 198        if (what & IDE_TIMING_UDMA   ) m->udma    = MAX(a->udma,    b->udma);
 199}
 200
 201static struct ide_timing* ide_timing_find_mode(short speed)
 202{
 203        struct ide_timing *t;
 204
 205        for (t = ide_timing; t->mode != speed; t++)
 206                if (t->mode < 0)
 207                        return NULL;
 208        return t; 
 209}
 210
 211static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing *t, int T, int UT)
 212{
 213        struct hd_driveid *id = drive->id;
 214        struct ide_timing *s, p;
 215
 216/*
 217 * Find the mode.
 218 */
 219
 220        if (!(s = ide_timing_find_mode(speed)))
 221                return -EINVAL;
 222
 223/*
 224 * If the drive is an EIDE drive, it can tell us it needs extended
 225 * PIO/MWDMA cycle timing.
 226 */
 227
 228        if (id && id->field_valid & 2) {        /* EIDE drive */
 229
 230                memset(&p, 0, sizeof(p));
 231
 232                switch (speed & XFER_MODE) {
 233
 234                        case XFER_PIO:
 235                                if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = id->eide_pio;
 236                                                    else p.cycle = p.cyc8b = id->eide_pio_iordy;
 237                                break;
 238
 239                        case XFER_MWDMA:
 240                                p.cycle = id->eide_dma_min;
 241                                break;
 242                }
 243
 244                ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B);
 245        }
 246
 247/*
 248 * Convert the timing to bus clock counts.
 249 */
 250
 251        ide_timing_quantize(s, t, T, UT);
 252
 253/*
 254 * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T
 255 * and some other commands. We have to ensure that the DMA cycle timing is
 256 * slower/equal than the fastest PIO timing.
 257 */
 258
 259        if ((speed & XFER_MODE) != XFER_PIO) {
 260                ide_timing_compute(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO), &p, T, UT);
 261                ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
 262        }
 263
 264/*
 265 * Lenghten active & recovery time so that cycle time is correct.
 266 */
 267
 268        if (t->act8b + t->rec8b < t->cyc8b) {
 269                t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
 270                t->rec8b = t->cyc8b - t->act8b;
 271        }
 272
 273        if (t->active + t->recover < t->cycle) {
 274                t->active += (t->cycle - (t->active + t->recover)) / 2;
 275                t->recover = t->cycle - t->active;
 276        }
 277
 278        return 0;
 279}
 280
 281#endif
 282
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.