Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 10373
b: refs/heads/master
c: 452503f
h: refs/heads/master
i:
  10371: 941a55a
v: v3
  • Loading branch information
Alan Cox authored and Jeff Garzik committed Oct 21, 2005
1 parent a3ce1f5 commit aa43caf
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 11e29e21514517f3022a1f30998ac4c7b1197658
refs/heads/master: 452503f993feffe96e8cc9fbff4888b96e2c5e40
149 changes: 149 additions & 0 deletions trunk/drivers/scsi/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1538,6 +1538,152 @@ void ata_port_disable(struct ata_port *ap)
ap->flags |= ATA_FLAG_PORT_DISABLED;
}

/*
* This mode timing computation functionality is ported over from
* drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik
*/
/*
* PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
* These were taken from ATA/ATAPI-6 standard, rev 0a, except
* for PIO 5, which is a nonstandard extension and UDMA6, which
* is currently supported only by Maxtor drives.
*/

static const struct ata_timing ata_timing[] = {

{ XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 },
{ XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 },
{ XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 },
{ XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 },

{ XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 },
{ XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 },
{ XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 },

/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */

{ XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 },
{ XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 },
{ XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 },

{ XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 },
{ XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
{ XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },

/* { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, */
{ XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 },
{ XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 },

{ XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 },
{ XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 },
{ XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 },

/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */

{ 0xFF }
};

#define ENOUGH(v,unit) (((v)-1)/(unit)+1)
#define EZ(v,unit) ((v)?ENOUGH(v,unit):0)

static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT)
{
q->setup = EZ(t->setup * 1000, T);
q->act8b = EZ(t->act8b * 1000, T);
q->rec8b = EZ(t->rec8b * 1000, T);
q->cyc8b = EZ(t->cyc8b * 1000, T);
q->active = EZ(t->active * 1000, T);
q->recover = EZ(t->recover * 1000, T);
q->cycle = EZ(t->cycle * 1000, T);
q->udma = EZ(t->udma * 1000, UT);
}

void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
struct ata_timing *m, unsigned int what)
{
if (what & ATA_TIMING_SETUP ) m->setup = max(a->setup, b->setup);
if (what & ATA_TIMING_ACT8B ) m->act8b = max(a->act8b, b->act8b);
if (what & ATA_TIMING_REC8B ) m->rec8b = max(a->rec8b, b->rec8b);
if (what & ATA_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b);
if (what & ATA_TIMING_ACTIVE ) m->active = max(a->active, b->active);
if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover);
if (what & ATA_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle);
if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma);
}

static const struct ata_timing* ata_timing_find_mode(unsigned short speed)
{
const struct ata_timing *t;

for (t = ata_timing; t->mode != speed; t++)
if (t->mode != 0xFF)
return NULL;
return t;
}

int ata_timing_compute(struct ata_device *adev, unsigned short speed,
struct ata_timing *t, int T, int UT)
{
const struct ata_timing *s;
struct ata_timing p;

/*
* Find the mode.
*/

if (!(s = ata_timing_find_mode(speed)))
return -EINVAL;

/*
* If the drive is an EIDE drive, it can tell us it needs extended
* PIO/MW_DMA cycle timing.
*/

if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
memset(&p, 0, sizeof(p));
if(speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) {
if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO];
else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY];
} else if(speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) {
p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN];
}
ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B);
}

/*
* Convert the timing to bus clock counts.
*/

ata_timing_quantize(s, t, T, UT);

/*
* Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T
* and some other commands. We have to ensure that the DMA cycle timing is
* slower/equal than the fastest PIO timing.
*/

if (speed > XFER_PIO_4) {
ata_timing_compute(adev, adev->pio_mode, &p, T, UT);
ata_timing_merge(&p, t, t, ATA_TIMING_ALL);
}

/*
* Lenghten active & recovery time so that cycle time is correct.
*/

if (t->act8b + t->rec8b < t->cyc8b) {
t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
t->rec8b = t->cyc8b - t->act8b;
}

if (t->active + t->recover < t->cycle) {
t->active += (t->cycle - (t->active + t->recover)) / 2;
t->recover = t->cycle - t->active;
}

return 0;
}

static struct {
unsigned int shift;
u8 base;
Expand Down Expand Up @@ -4764,6 +4910,9 @@ EXPORT_SYMBOL_GPL(ata_dev_id_string);
EXPORT_SYMBOL_GPL(ata_dev_config);
EXPORT_SYMBOL_GPL(ata_scsi_simulate);

EXPORT_SYMBOL_GPL(ata_timing_compute);
EXPORT_SYMBOL_GPL(ata_timing_merge);

#ifdef CONFIG_PCI
EXPORT_SYMBOL_GPL(pci_test_config_bits);
EXPORT_SYMBOL_GPL(ata_pci_host_stop);
Expand Down
39 changes: 39 additions & 0 deletions trunk/include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,19 @@ struct ata_port_info {
struct ata_port_operations *port_ops;
};

struct ata_timing {
unsigned short mode; /* ATA mode */
unsigned short setup; /* t1 */
unsigned short act8b; /* t2 for 8-bit I/O */
unsigned short rec8b; /* t2i for 8-bit I/O */
unsigned short cyc8b; /* t0 for 8-bit I/O */
unsigned short active; /* t2 or tD */
unsigned short recover; /* t2i or tK */
unsigned short cycle; /* t0 */
unsigned short udma; /* t2CYCTYP/2 */
};

#define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin)

extern void ata_port_probe(struct ata_port *);
extern void __sata_phy_reset(struct ata_port *ap);
Expand Down Expand Up @@ -451,6 +464,32 @@ extern int ata_std_bios_param(struct scsi_device *sdev,
sector_t capacity, int geom[]);
extern int ata_scsi_slave_config(struct scsi_device *sdev);

/*
* Timing helpers
*/
extern int ata_timing_compute(struct ata_device *, unsigned short,
struct ata_timing *, int, int);
extern void ata_timing_merge(const struct ata_timing *,
const struct ata_timing *, struct ata_timing *,
unsigned int);

enum {
ATA_TIMING_SETUP = (1 << 0),
ATA_TIMING_ACT8B = (1 << 1),
ATA_TIMING_REC8B = (1 << 2),
ATA_TIMING_CYC8B = (1 << 3),
ATA_TIMING_8BIT = ATA_TIMING_ACT8B | ATA_TIMING_REC8B |
ATA_TIMING_CYC8B,
ATA_TIMING_ACTIVE = (1 << 4),
ATA_TIMING_RECOVER = (1 << 5),
ATA_TIMING_CYCLE = (1 << 6),
ATA_TIMING_UDMA = (1 << 7),
ATA_TIMING_ALL = ATA_TIMING_SETUP | ATA_TIMING_ACT8B |
ATA_TIMING_REC8B | ATA_TIMING_CYC8B |
ATA_TIMING_ACTIVE | ATA_TIMING_RECOVER |
ATA_TIMING_CYCLE | ATA_TIMING_UDMA,
};


#ifdef CONFIG_PCI
struct pci_bits {
Expand Down

0 comments on commit aa43caf

Please sign in to comment.