Commit 3b64bb0c authored by Jeff Garzik's avatar Jeff Garzik

[libata] set up some of the per-command data beforehand

The data transfer mode and the set of read/write commands we generate
during normal operation remains constant until we change the data
transfer mode.

This removes a series of branches in the read/write fast path,
and in general cleans up that particular spot of code.
parent afca2f69
......@@ -439,6 +439,62 @@ u8 ata_check_status_mmio(struct ata_port *ap)
return readb((void *) ap->ioaddr.status_addr);
}
static int ata_prot_to_cmd(int protocol, int lba48)
{
int rcmd = 0, wcmd = 0;
switch (protocol) {
case ATA_PROT_PIO_READ:
case ATA_PROT_PIO_WRITE:
if (lba48) {
rcmd = ATA_CMD_PIO_READ_EXT;
wcmd = ATA_CMD_PIO_WRITE_EXT;
} else {
rcmd = ATA_CMD_PIO_READ;
wcmd = ATA_CMD_PIO_WRITE;
}
break;
case ATA_PROT_DMA_READ:
case ATA_PROT_DMA_WRITE:
if (lba48) {
rcmd = ATA_CMD_READ_EXT;
wcmd = ATA_CMD_WRITE_EXT;
} else {
rcmd = ATA_CMD_READ;
wcmd = ATA_CMD_WRITE;
}
break;
default:
return -1;
}
return rcmd | (wcmd << 8);
}
static void ata_dev_set_protocol(struct ata_device *dev)
{
int pio = (dev->flags & ATA_DFLAG_PIO);
int lba48 = (dev->flags & ATA_DFLAG_LBA48);
int proto, cmd;
if (pio) {
proto = dev->r_protocol = ATA_PROT_PIO_READ;
dev->w_protocol = ATA_PROT_PIO_WRITE;
} else {
proto = dev->r_protocol = ATA_PROT_DMA_READ;
dev->w_protocol = ATA_PROT_DMA_WRITE;
}
cmd = ata_prot_to_cmd(proto, lba48);
if (cmd < 0)
BUG();
dev->read_cmd = cmd & 0xff;
dev->write_cmd = (cmd >> 8) & 0xff;
}
static const char * udma_str[] = {
"UDMA/16",
"UDMA/25",
......@@ -1129,7 +1185,7 @@ void ata_port_disable(struct ata_port *ap)
*/
static void ata_set_mode(struct ata_port *ap)
{
unsigned int force_pio;
unsigned int force_pio, i;
ata_host_set_pio(ap);
if (ap->flags & ATA_FLAG_PORT_DISABLED)
......@@ -1148,19 +1204,21 @@ static void ata_set_mode(struct ata_port *ap)
if (force_pio) {
ata_dev_set_pio(ap, 0);
ata_dev_set_pio(ap, 1);
if (ap->flags & ATA_FLAG_PORT_DISABLED)
return;
} else {
ata_dev_set_udma(ap, 0);
ata_dev_set_udma(ap, 1);
}
if (ap->flags & ATA_FLAG_PORT_DISABLED)
return;
}
if (ap->ops->post_set_mode)
ap->ops->post_set_mode(ap);
for (i = 0; i < 2; i++) {
struct ata_device *dev = &ap->device[i];
ata_dev_set_protocol(dev);
}
}
/**
......
......@@ -172,7 +172,6 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd,
{
struct ata_taskfile *tf = &qc->tf;
unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
unsigned int dma = qc->flags & ATA_QCFLAG_DMA;
qc->cursect = qc->cursg = qc->cursg_ofs = 0;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
......@@ -183,35 +182,13 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd,
if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
scsicmd[0] == READ_16) {
if (likely(dma)) {
if (lba48)
tf->command = ATA_CMD_READ_EXT;
else
tf->command = ATA_CMD_READ;
tf->protocol = ATA_PROT_DMA_READ;
} else {
if (lba48)
tf->command = ATA_CMD_PIO_READ_EXT;
else
tf->command = ATA_CMD_PIO_READ;
tf->protocol = ATA_PROT_PIO_READ;
}
tf->command = qc->dev->read_cmd;
tf->protocol = qc->dev->r_protocol;
qc->flags &= ~ATA_QCFLAG_WRITE;
VPRINTK("reading\n");
} else {
if (likely(dma)) {
if (lba48)
tf->command = ATA_CMD_WRITE_EXT;
else
tf->command = ATA_CMD_WRITE;
tf->protocol = ATA_PROT_DMA_WRITE;
} else {
if (lba48)
tf->command = ATA_CMD_PIO_WRITE_EXT;
else
tf->command = ATA_CMD_PIO_WRITE;
tf->protocol = ATA_PROT_PIO_WRITE;
}
tf->command = qc->dev->write_cmd;
tf->protocol = qc->dev->w_protocol;
qc->flags |= ATA_QCFLAG_WRITE;
VPRINTK("writing\n");
}
......
......@@ -293,6 +293,12 @@ struct ata_device {
* ATAPI7 spec size, 40 ASCII
* characters
*/
/* cache info about current transfer mode */
u8 r_protocol; /* taskfile read protocol */
u8 w_protocol; /* taskfile write protocol */
u8 read_cmd; /* opcode to use on read */
u8 write_cmd; /* opcode to use on write */
};
struct ata_engine {
......
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