Commit 0750508a authored by Sergei Shtylyov's avatar Sergei Shtylyov Committed by Linus Torvalds

[PATCH] ide_dma_speed() fixes

ide_dma_speed() fails to actually honor the IDE drivers' mode support
masks) because of the bogus checks -- thus, selecting the DMA transfer mode
that the driver explicitly refuses to support is possible.  Additionally,
there is no check for validity of the UltraDMA mode data in the drive ID,
and the function is misdocumented.
Signed-off-by: default avatarSergei Shtylyov <sshtylyov@ru.mvista.com>
Cc: Bartlomiej Zolnierkiewicz <B.Zolnierkiewicz@elka.pw.edu.pl>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 83d7dbc4
...@@ -71,75 +71,96 @@ EXPORT_SYMBOL(ide_xfer_verbose); ...@@ -71,75 +71,96 @@ EXPORT_SYMBOL(ide_xfer_verbose);
/** /**
* ide_dma_speed - compute DMA speed * ide_dma_speed - compute DMA speed
* @drive: drive * @drive: drive
* @mode; intended mode * @mode: modes available
* *
* Checks the drive capabilities and returns the speed to use * Checks the drive capabilities and returns the speed to use
* for the transfer. Returns -1 if the requested mode is unknown * for the DMA transfer. Returns 0 if the drive is incapable
* (eg PIO) * of DMA transfers.
*/ */
u8 ide_dma_speed(ide_drive_t *drive, u8 mode) u8 ide_dma_speed(ide_drive_t *drive, u8 mode)
{ {
struct hd_driveid *id = drive->id; struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive); ide_hwif_t *hwif = HWIF(drive);
u8 ultra_mask, mwdma_mask, swdma_mask;
u8 speed = 0; u8 speed = 0;
if (drive->media != ide_disk && hwif->atapi_dma == 0) if (drive->media != ide_disk && hwif->atapi_dma == 0)
return 0; return 0;
switch(mode) { /* Capable of UltraDMA modes? */
case 0x04: ultra_mask = id->dma_ultra & hwif->ultra_mask;
if ((id->dma_ultra & 0x0040) &&
(id->dma_ultra & hwif->ultra_mask)) if (!(id->field_valid & 4))
{ speed = XFER_UDMA_6; break; } mode = 0; /* fallback to MW/SW DMA if no UltraDMA */
case 0x03:
if ((id->dma_ultra & 0x0020) && switch (mode) {
(id->dma_ultra & hwif->ultra_mask)) case 4:
{ speed = XFER_UDMA_5; break; } if (ultra_mask & 0x40) {
case 0x02: speed = XFER_UDMA_6;
if ((id->dma_ultra & 0x0010) && break;
(id->dma_ultra & hwif->ultra_mask)) }
{ speed = XFER_UDMA_4; break; } case 3:
if ((id->dma_ultra & 0x0008) && if (ultra_mask & 0x20) {
(id->dma_ultra & hwif->ultra_mask)) speed = XFER_UDMA_5;
{ speed = XFER_UDMA_3; break; } break;
case 0x01: }
if ((id->dma_ultra & 0x0004) && case 2:
(id->dma_ultra & hwif->ultra_mask)) if (ultra_mask & 0x10) {
{ speed = XFER_UDMA_2; break; } speed = XFER_UDMA_4;
if ((id->dma_ultra & 0x0002) && break;
(id->dma_ultra & hwif->ultra_mask)) }
{ speed = XFER_UDMA_1; break; } if (ultra_mask & 0x08) {
if ((id->dma_ultra & 0x0001) && speed = XFER_UDMA_3;
(id->dma_ultra & hwif->ultra_mask)) break;
{ speed = XFER_UDMA_0; break; } }
case 0x00: case 1:
if ((id->dma_mword & 0x0004) && if (ultra_mask & 0x04) {
(id->dma_mword & hwif->mwdma_mask)) speed = XFER_UDMA_2;
{ speed = XFER_MW_DMA_2; break; } break;
if ((id->dma_mword & 0x0002) && }
(id->dma_mword & hwif->mwdma_mask)) if (ultra_mask & 0x02) {
{ speed = XFER_MW_DMA_1; break; } speed = XFER_UDMA_1;
if ((id->dma_mword & 0x0001) && break;
(id->dma_mword & hwif->mwdma_mask)) }
{ speed = XFER_MW_DMA_0; break; } if (ultra_mask & 0x01) {
if ((id->dma_1word & 0x0004) && speed = XFER_UDMA_0;
(id->dma_1word & hwif->swdma_mask)) break;
{ speed = XFER_SW_DMA_2; break; } }
if ((id->dma_1word & 0x0002) && case 0:
(id->dma_1word & hwif->swdma_mask)) mwdma_mask = id->dma_mword & hwif->mwdma_mask;
{ speed = XFER_SW_DMA_1; break; }
if ((id->dma_1word & 0x0001) &&
(id->dma_1word & hwif->swdma_mask))
{ speed = XFER_SW_DMA_0; break; }
}
// printk("%s: %s: mode 0x%02x, speed 0x%02x\n", if (mwdma_mask & 0x04) {
// __FUNCTION__, drive->name, mode, speed); speed = XFER_MW_DMA_2;
break;
}
if (mwdma_mask & 0x02) {
speed = XFER_MW_DMA_1;
break;
}
if (mwdma_mask & 0x01) {
speed = XFER_MW_DMA_0;
break;
}
swdma_mask = id->dma_1word & hwif->swdma_mask;
if (swdma_mask & 0x04) {
speed = XFER_SW_DMA_2;
break;
}
if (swdma_mask & 0x02) {
speed = XFER_SW_DMA_1;
break;
}
if (swdma_mask & 0x01) {
speed = XFER_SW_DMA_0;
break;
}
}
return speed; return speed;
} }
EXPORT_SYMBOL(ide_dma_speed); EXPORT_SYMBOL(ide_dma_speed);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment