^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 1999-2001 Vojtech Pavlik
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2007-2008 Bartlomiej Zolnierkiewicz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Should you need to contact me, the author, you can do so either by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/ide.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * These were taken from ATA/ATAPI-6 standard, rev 0a, except
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * for PIO 5, which is a nonstandard extension and UDMA6, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * is currently supported only by Maxtor drives.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static struct ide_timing ide_timing[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) { 0xff }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct ide_timing *ide_timing_find_mode(u8 speed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct ide_timing *t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) for (t = ide_timing; t->mode != speed; t++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (t->mode == 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) EXPORT_SYMBOL_GPL(ide_timing_find_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u16 *id = drive->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) u16 cycle = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (id[ATA_ID_FIELD_VALID] & 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (ata_id_has_iordy(drive->id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) cycle = id[ATA_ID_EIDE_PIO_IORDY];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) cycle = id[ATA_ID_EIDE_PIO];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* conservative "downgrade" for all pre-ATA2 drives */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (pio < 3 && cycle < t->cycle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) cycle = 0; /* use standard timing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /* Use the standard timing for the CF specific modes too */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (pio > 4 && ata_id_is_cfa(id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) cycle = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return cycle ? cycle : t->cycle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) EXPORT_SYMBOL_GPL(ide_pio_cycle_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define ENOUGH(v, unit) (((v) - 1) / (unit) + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define EZ(v, unit) ((v) ? ENOUGH((v) * 1000, unit) : 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) int T, int UT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) q->setup = EZ(t->setup, T);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) q->act8b = EZ(t->act8b, T);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) q->rec8b = EZ(t->rec8b, T);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) q->cyc8b = EZ(t->cyc8b, T);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) q->active = EZ(t->active, T);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) q->recover = EZ(t->recover, T);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) q->cycle = EZ(t->cycle, T);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) q->udma = EZ(t->udma, UT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) void ide_timing_merge(struct ide_timing *a, struct ide_timing *b,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct ide_timing *m, unsigned int what)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (what & IDE_TIMING_SETUP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) m->setup = max(a->setup, b->setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if (what & IDE_TIMING_ACT8B)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) m->act8b = max(a->act8b, b->act8b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (what & IDE_TIMING_REC8B)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) m->rec8b = max(a->rec8b, b->rec8b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (what & IDE_TIMING_CYC8B)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) m->cyc8b = max(a->cyc8b, b->cyc8b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (what & IDE_TIMING_ACTIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) m->active = max(a->active, b->active);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (what & IDE_TIMING_RECOVER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) m->recover = max(a->recover, b->recover);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (what & IDE_TIMING_CYCLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) m->cycle = max(a->cycle, b->cycle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (what & IDE_TIMING_UDMA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) m->udma = max(a->udma, b->udma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) EXPORT_SYMBOL_GPL(ide_timing_merge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) int ide_timing_compute(ide_drive_t *drive, u8 speed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct ide_timing *t, int T, int UT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) u16 *id = drive->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) struct ide_timing *s, p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * Find the mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) s = ide_timing_find_mode(speed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (s == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * Copy the timing from the table.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) *t = *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * If the drive is an EIDE drive, it can tell us it needs extended
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * PIO/MWDMA cycle timing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) memset(&p, 0, sizeof(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (speed >= XFER_PIO_0 && speed < XFER_SW_DMA_0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (speed <= XFER_PIO_2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) else if ((speed <= XFER_PIO_4) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) p.cycle = id[ATA_ID_EIDE_DMA_MIN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * Convert the timing to bus clock counts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) ide_timing_quantize(t, t, T, UT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * S.M.A.R.T and some other commands. We have to ensure that the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * DMA cycle timing is slower/equal than the current PIO timing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (speed >= XFER_SW_DMA_0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) ide_timing_compute(drive, drive->pio_mode, &p, T, UT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * Lengthen active & recovery time so that cycle time is correct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (t->act8b + t->rec8b < t->cyc8b) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) t->rec8b = t->cyc8b - t->act8b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (t->active + t->recover < t->cycle) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) t->active += (t->cycle - (t->active + t->recover)) / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) t->recover = t->cycle - t->active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) EXPORT_SYMBOL_GPL(ide_timing_compute);