libata: Add 32bit PIO support
Alan Cox [Mon, 5 Jan 2009 14:16:39 +0000 (14:16 +0000)]
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>

drivers/ata/ata_piix.c
drivers/ata/libata-sff.c
drivers/ata/pata_ali.c
drivers/ata/pata_amd.c
drivers/ata/pata_mpiix.c
drivers/ata/pata_sil680.c
include/linux/libata.h

index 7865954..887d8f4 100644 (file)
@@ -310,7 +310,7 @@ static struct scsi_host_template piix_sht = {
 };
 
 static struct ata_port_operations piix_pata_ops = {
-       .inherits               = &ata_bmdma_port_ops,
+       .inherits               = &ata_bmdma32_port_ops,
        .cable_detect           = ata_cable_40wire,
        .set_piomode            = piix_set_piomode,
        .set_dmamode            = piix_set_dmamode,
index 9033d16..b58549f 100644 (file)
@@ -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
index a4f9e39..a7999c1 100644 (file)
@@ -151,8 +151,7 @@ static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int o
 
        pci_read_config_byte(pdev, pio_fifo, &fifo);
        fifo &= ~(0x0F << shift);
-       if (on)
-               fifo |= (on << shift);
+       fifo |= (on << shift);
        pci_write_config_byte(pdev, pio_fifo, fifo);
 }
 
@@ -370,10 +369,11 @@ static struct ata_port_operations ali_early_port_ops = {
        .inherits       = &ata_sff_port_ops,
        .cable_detect   = ata_cable_40wire,
        .set_piomode    = ali_set_piomode,
+       .sff_data_xfer  = ata_sff_data_xfer32,
 };
 
 static const struct ata_port_operations ali_dma_base_ops = {
-       .inherits       = &ata_bmdma_port_ops,
+       .inherits       = &ata_bmdma32_port_ops,
        .set_piomode    = ali_set_piomode,
        .set_dmamode    = ali_set_dmamode,
 };
index 0ec9c7d..63719ab 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.3.10"
+#define DRV_VERSION "0.3.11"
 
 /**
  *     timing_setup            -       shared timing computation and load
@@ -345,7 +345,7 @@ static struct scsi_host_template amd_sht = {
 };
 
 static const struct ata_port_operations amd_base_port_ops = {
-       .inherits       = &ata_bmdma_port_ops,
+       .inherits       = &ata_bmdma32_port_ops,
        .prereset       = amd_pre_reset,
 };
 
index 7c8faa4..aa576ca 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_mpiix"
-#define DRV_VERSION "0.7.6"
+#define DRV_VERSION "0.7.7"
 
 enum {
        IDETIM = 0x6C,          /* IDE control register */
@@ -146,6 +146,7 @@ static struct ata_port_operations mpiix_port_ops = {
        .cable_detect   = ata_cable_40wire,
        .set_piomode    = mpiix_set_piomode,
        .prereset       = mpiix_pre_reset,
+       .sff_data_xfer  = ata_sff_data_xfer32,
 };
 
 static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index 83580a5..9e764e5 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_sil680"
-#define DRV_VERSION "0.4.8"
+#define DRV_VERSION "0.4.9"
 
 #define SIL680_MMIO_BAR                5
 
@@ -195,7 +195,7 @@ static struct scsi_host_template sil680_sht = {
 };
 
 static struct ata_port_operations sil680_port_ops = {
-       .inherits       = &ata_bmdma_port_ops,
+       .inherits       = &ata_bmdma32_port_ops,
        .cable_detect   = sil680_cable_detect,
        .set_piomode    = sil680_set_piomode,
        .set_dmamode    = sil680_set_dmamode,
index 3449de5..4f7c8fb 100644 (file)
@@ -1518,6 +1518,7 @@ extern void sata_pmp_error_handler(struct ata_port *ap);
 
 extern const struct ata_port_operations ata_sff_port_ops;
 extern const struct ata_port_operations ata_bmdma_port_ops;
+extern const struct ata_port_operations ata_bmdma32_port_ops;
 
 /* PIO only, sg_tablesize and dma_boundary limits can be removed */
 #define ATA_PIO_SHT(drv_name)                                  \
@@ -1545,6 +1546,8 @@ extern void ata_sff_exec_command(struct ata_port *ap,
                                 const struct ata_taskfile *tf);
 extern unsigned int ata_sff_data_xfer(struct ata_device *dev,
                        unsigned char *buf, unsigned int buflen, int rw);
+extern unsigned int ata_sff_data_xfer32(struct ata_device *dev,
+                       unsigned char *buf, unsigned int buflen, int rw);
 extern unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev,
                        unsigned char *buf, unsigned int buflen, int rw);
 extern u8 ata_sff_irq_on(struct ata_port *ap);