summaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-sff.c
diff options
context:
space:
mode:
authorAlan Cox2009-01-05 15:16:39 +0100
committerJeff Garzik2009-01-08 22:34:27 +0100
commit871af1210f13966ab911ed2166e4ab2ce775b99d (patch)
treef17f0016f6e966d54a379a3de6e6bbde3b9359fe /drivers/ata/libata-sff.c
parent[libata] ahci: Withdraw IGN_SERR_INTERNAL for SB800 SATA (diff)
downloadkernel-qcow2-linux-871af1210f13966ab911ed2166e4ab2ce775b99d.tar.gz
kernel-qcow2-linux-871af1210f13966ab911ed2166e4ab2ce775b99d.tar.xz
kernel-qcow2-linux-871af1210f13966ab911ed2166e4ab2ce775b99d.zip
libata: Add 32bit PIO support
This matters for some controllers and in one or two cases almost doubles PIO performance. Add a bmdma32 operations set we can inherit and activate it for some controllers Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/libata-sff.c')
-rw-r--r--drivers/ata/libata-sff.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 9033d164c4ec..b58549fac460 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -78,6 +78,13 @@ const struct ata_port_operations ata_bmdma_port_ops = {
.bmdma_status = ata_bmdma_status,
};
+const struct ata_port_operations ata_bmdma32_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+
+ .sff_data_xfer = ata_sff_data_xfer32,
+};
+EXPORT_SYMBOL_GPL(ata_bmdma32_port_ops);
+
/**
* ata_fill_sg - Fill PCI IDE PRD table
* @qc: Metadata associated with taskfile to be transferred
@@ -719,6 +726,52 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf,
}
/**
+ * ata_sff_data_xfer32 - Transfer data by PIO
+ * @dev: device to target
+ * @buf: data buffer
+ * @buflen: buffer length
+ * @rw: read/write
+ *
+ * Transfer data from/to the device data register by PIO using 32bit
+ * I/O operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * Bytes consumed.
+ */
+
+unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned int words = buflen >> 2;
+ int slop = buflen & 3;
+
+ /* Transfer multiple of 4 bytes */
+ if (rw == READ)
+ ioread32_rep(data_addr, buf, words);
+ else
+ iowrite32_rep(data_addr, buf, words);
+
+ if (unlikely(slop)) {
+ __le32 pad;
+ if (rw == READ) {
+ pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
+ memcpy(buf + buflen - slop, &pad, slop);
+ } else {
+ memcpy(&pad, buf + buflen - slop, slop);
+ iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ }
+ words++;
+ }
+ return words << 2;
+}
+EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
+
+/**
* ata_sff_data_xfer_noirq - Transfer data by PIO
* @dev: device to target
* @buf: data buffer