ata: pata_of_platform: Allow to use 16-bit wide data transfer
authorAlexander Shiyan <shc_work@mail.ru>
Sat, 19 Jan 2019 04:52:01 +0000 (07:52 +0300)
committerJens Axboe <axboe@kernel.dk>
Fri, 8 Feb 2019 13:42:53 +0000 (06:42 -0700)
In some cases, the system bus can be configured for 16-bit mode,
in this case using read/write functions for 32-bit values
results in two cycles of 16 bits each, which is wrong.
This patch adds the devicetree flag to switch the driver to
use 16-bit mode for I/O transfers.

Acked-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/ata/pata_of_platform.c
drivers/ata/pata_platform.c
include/linux/ata_platform.h

index 01161c1aef4d6d463bd2f6c9648328100a10f8a0..7a0b1759e5f094d0e2b06cf7daa95499eeb0f86e 100644 (file)
@@ -32,6 +32,7 @@ static int pata_of_platform_probe(struct platform_device *ofdev)
        unsigned int reg_shift = 0;
        int pio_mode = 0;
        int pio_mask;
+       bool use16bit;
 
        ret = of_address_to_resource(dn, 0, &io_res);
        if (ret) {
@@ -60,11 +61,14 @@ static int pata_of_platform_probe(struct platform_device *ofdev)
                dev_info(&ofdev->dev, "pio-mode unspecified, assuming PIO0\n");
        }
 
+       use16bit = of_property_read_bool(dn, "ata-generic,use16bit");
+
        pio_mask = 1 << pio_mode;
        pio_mask |= (1 << pio_mode) - 1;
 
        return __pata_platform_probe(&ofdev->dev, &io_res, &ctl_res, irq_res,
-                                    reg_shift, pio_mask, &pata_platform_sht);
+                                    reg_shift, pio_mask, &pata_platform_sht,
+                                    use16bit);
 }
 
 static const struct of_device_id pata_of_platform_match[] = {
index d6f8f540644243fa8accf10b59e145982295b10b..31cd0f39b0a7fa3b380fc80173666b700aac0d09 100644 (file)
@@ -47,13 +47,6 @@ static struct scsi_host_template pata_platform_sht = {
        ATA_PIO_SHT(DRV_NAME),
 };
 
-static struct ata_port_operations pata_platform_port_ops = {
-       .inherits               = &ata_sff_port_ops,
-       .sff_data_xfer          = ata_sff_data_xfer32,
-       .cable_detect           = ata_cable_unknown,
-       .set_mode               = pata_platform_set_mode,
-};
-
 static void pata_platform_setup_port(struct ata_ioports *ioaddr,
                                     unsigned int shift)
 {
@@ -79,6 +72,7 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
  *     @ioport_shift: I/O port shift
  *     @__pio_mask: PIO mask
  *     @sht: scsi_host_template to use when registering
+ *     @use16bit: Flag to indicate 16-bit IO instead of 32-bit
  *
  *     Register a platform bus IDE interface. Such interfaces are PIO and we
  *     assume do not support IRQ sharing.
@@ -101,7 +95,7 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
 int __pata_platform_probe(struct device *dev, struct resource *io_res,
                          struct resource *ctl_res, struct resource *irq_res,
                          unsigned int ioport_shift, int __pio_mask,
-                         struct scsi_host_template *sht)
+                         struct scsi_host_template *sht, bool use16bit)
 {
        struct ata_host *host;
        struct ata_port *ap;
@@ -131,7 +125,15 @@ int __pata_platform_probe(struct device *dev, struct resource *io_res,
                return -ENOMEM;
        ap = host->ports[0];
 
-       ap->ops = &pata_platform_port_ops;
+       ap->ops = devm_kzalloc(dev, sizeof(*ap->ops), GFP_KERNEL);
+       ap->ops->inherits = &ata_sff_port_ops;
+       ap->ops->cable_detect = ata_cable_unknown;
+       ap->ops->set_mode = pata_platform_set_mode;
+       if (use16bit)
+               ap->ops->sff_data_xfer = ata_sff_data_xfer;
+       else
+               ap->ops->sff_data_xfer = ata_sff_data_xfer32;
+
        ap->pio_mask = __pio_mask;
        ap->flags |= ATA_FLAG_SLAVE_POSS;
 
@@ -218,7 +220,7 @@ static int pata_platform_probe(struct platform_device *pdev)
 
        return __pata_platform_probe(&pdev->dev, io_res, ctl_res, irq_res,
                                     pp_info ? pp_info->ioport_shift : 0,
-                                    pio_mask, &pata_platform_sht);
+                                    pio_mask, &pata_platform_sht, false);
 }
 
 static struct platform_driver pata_platform_driver = {
index ff2120215decca77cb0fa1f0fd90c65a54bb2c68..9cafec92282db8516ec606f650e9a6eb37a7010d 100644 (file)
@@ -19,7 +19,8 @@ extern int __pata_platform_probe(struct device *dev,
                                 struct resource *irq_res,
                                 unsigned int ioport_shift,
                                 int __pio_mask,
-                                struct scsi_host_template *sht);
+                                struct scsi_host_template *sht,
+                                bool use16bit);
 
 /*
  * Marvell SATA private data