Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6.git] / drivers / ata / pata_bf54x.c
index eea275a..c4b47a3 100644 (file)
@@ -356,7 +356,6 @@ static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev)
  *     bfin_set_dmamode - Initialize host controller PATA DMA timings
  *     @ap: Port whose timings we are configuring
  *     @adev: um
- *     @udma: udma mode, 0 - 6
  *
  *     Set UDMA mode for device.
  *
@@ -674,7 +673,7 @@ static void read_atapi_data(void __iomem *base,
  *     @ap: Port to which output is sent
  *     @tf: ATA taskfile register set
  *
- *     Note: Original code is ata_tf_load().
+ *     Note: Original code is ata_sff_tf_load().
  */
 
 static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
@@ -745,7 +744,7 @@ static u8 bfin_check_status(struct ata_port *ap)
  *     @ap: Port from which input is read
  *     @tf: ATA taskfile register set for storing input
  *
- *     Note: Original code is ata_tf_read().
+ *     Note: Original code is ata_sff_tf_read().
  */
 
 static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
@@ -775,7 +774,7 @@ static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
  *     @ap: port to which command is being issued
  *     @tf: ATA taskfile register set
  *
- *     Note: Original code is ata_exec_command().
+ *     Note: Original code is ata_sff_exec_command().
  */
 
 static void bfin_exec_command(struct ata_port *ap,
@@ -785,7 +784,7 @@ static void bfin_exec_command(struct ata_port *ap,
        dev_dbg(ap->dev, "ata%u: cmd 0x%X\n", ap->print_id, tf->command);
 
        write_atapi_register(base, ATA_REG_CMD, tf->command);
-       ata_pause(ap);
+       ata_sff_pause(ap);
 }
 
 /**
@@ -800,14 +799,14 @@ static u8 bfin_check_altstatus(struct ata_port *ap)
 }
 
 /**
- *     bfin_std_dev_select - Select device 0/1 on ATA bus
+ *     bfin_dev_select - Select device 0/1 on ATA bus
  *     @ap: ATA channel to manipulate
  *     @device: ATA device (numbered from zero) to select
  *
- *     Note: Original code is ata_std_dev_select().
+ *     Note: Original code is ata_sff_dev_select().
  */
 
-static void bfin_std_dev_select(struct ata_port *ap, unsigned int device)
+static void bfin_dev_select(struct ata_port *ap, unsigned int device)
 {
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
        u8 tmp;
@@ -818,7 +817,7 @@ static void bfin_std_dev_select(struct ata_port *ap, unsigned int device)
                tmp = ATA_DEVICE_OBS | ATA_DEV1;
 
        write_atapi_register(base, ATA_REG_DEVICE, tmp);
-       ata_pause(ap);
+       ata_sff_pause(ap);
 }
 
 /**
@@ -911,7 +910,10 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
        /* Reset all transfer count */
        ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
 
-               /* Set transfer length to buffer len */
+       /* Set ATAPI state machine contorl in terminate sequence */
+       ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | END_ON_TERM);
+
+       /* Set transfer length to buffer len */
        for_each_sg(qc->sg, sg, qc->n_elem, si) {
                ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
        }
@@ -977,7 +979,7 @@ static unsigned int bfin_devchk(struct ata_port *ap,
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
        u8 nsect, lbal;
 
-       bfin_std_dev_select(ap, device);
+       bfin_dev_select(ap, device);
 
        write_atapi_register(base, ATA_REG_NSECT, 0x55);
        write_atapi_register(base, ATA_REG_LBAL, 0xaa);
@@ -1008,41 +1010,41 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
        unsigned int dev0 = devmask & (1 << 0);
        unsigned int dev1 = devmask & (1 << 1);
-       unsigned long timeout;
+       unsigned long deadline;
 
        /* if device 0 was found in ata_devchk, wait for its
         * BSY bit to clear
         */
        if (dev0)
-               ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+               ata_sff_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
 
        /* if device 1 was found in ata_devchk, wait for
         * register access, then wait for BSY to clear
         */
-       timeout = jiffies + ATA_TMOUT_BOOT;
+       deadline = ata_deadline(jiffies, ATA_TMOUT_BOOT);
        while (dev1) {
                u8 nsect, lbal;
 
-               bfin_std_dev_select(ap, 1);
+               bfin_dev_select(ap, 1);
                nsect = read_atapi_register(base, ATA_REG_NSECT);
                lbal = read_atapi_register(base, ATA_REG_LBAL);
                if ((nsect == 1) && (lbal == 1))
                        break;
-               if (time_after(jiffies, timeout)) {
+               if (time_after(jiffies, deadline)) {
                        dev1 = 0;
                        break;
                }
                msleep(50);     /* give drive a breather */
        }
        if (dev1)
-               ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+               ata_sff_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
 
        /* is all this really necessary? */
-       bfin_std_dev_select(ap, 0);
+       bfin_dev_select(ap, 0);
        if (dev1)
-               bfin_std_dev_select(ap, 1);
+               bfin_dev_select(ap, 1);
        if (dev0)
-               bfin_std_dev_select(ap, 0);
+               bfin_dev_select(ap, 0);
 }
 
 /**
@@ -1088,26 +1090,21 @@ static unsigned int bfin_bus_softreset(struct ata_port *ap,
 }
 
 /**
- *     bfin_std_softreset - reset host port via ATA SRST
+ *     bfin_softreset - reset host port via ATA SRST
  *     @ap: port to reset
  *     @classes: resulting classes of attached devices
  *
- *     Note: Original code is ata_std_softreset().
+ *     Note: Original code is ata_sff_softreset().
  */
 
-static int bfin_std_softreset(struct ata_link *link, unsigned int *classes,
-               unsigned long deadline)
+static int bfin_softreset(struct ata_link *link, unsigned int *classes,
+                         unsigned long deadline)
 {
        struct ata_port *ap = link->ap;
        unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
        unsigned int devmask = 0, err_mask;
        u8 err;
 
-       if (ata_link_offline(link)) {
-               classes[0] = ATA_DEV_NONE;
-               goto out;
-       }
-
        /* determine if device 0/1 are present */
        if (bfin_devchk(ap, 0))
                devmask |= (1 << 0);
@@ -1115,7 +1112,7 @@ static int bfin_std_softreset(struct ata_link *link, unsigned int *classes,
                devmask |= (1 << 1);
 
        /* select device 0 again */
-       bfin_std_dev_select(ap, 0);
+       bfin_dev_select(ap, 0);
 
        /* issue bus reset */
        err_mask = bfin_bus_softreset(ap, devmask);
@@ -1126,13 +1123,12 @@ static int bfin_std_softreset(struct ata_link *link, unsigned int *classes,
        }
 
        /* determine by signature whether we have ATA or ATAPI devices */
-       classes[0] = ata_dev_try_classify(&ap->link.device[0],
+       classes[0] = ata_sff_dev_classify(&ap->link.device[0],
                                devmask & (1 << 0), &err);
        if (slave_possible && err != 0x81)
-               classes[1] = ata_dev_try_classify(&ap->link.device[1],
+               classes[1] = ata_sff_dev_classify(&ap->link.device[1],
                                        devmask & (1 << 1), &err);
 
- out:
        return 0;
 }
 
@@ -1167,7 +1163,7 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
  *     @buflen: buffer length
  *     @write_data: read/write
  *
- *     Note: Original code is ata_data_xfer().
+ *     Note: Original code is ata_sff_data_xfer().
  */
 
 static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf,
@@ -1206,7 +1202,7 @@ static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf,
  *     bfin_irq_clear - Clear ATAPI interrupt.
  *     @ap: Port associated with this ATA transaction.
  *
- *     Note: Original code is ata_bmdma_irq_clear().
+ *     Note: Original code is ata_sff_irq_clear().
  */
 
 static void bfin_irq_clear(struct ata_port *ap)
@@ -1223,7 +1219,7 @@ static void bfin_irq_clear(struct ata_port *ap)
  *     bfin_irq_on - Enable interrupts on a port.
  *     @ap: Port on which interrupts are enabled.
  *
- *     Note: Original code is ata_irq_on().
+ *     Note: Original code is ata_sff_irq_on().
  */
 
 static unsigned char bfin_irq_on(struct ata_port *ap)
@@ -1244,13 +1240,13 @@ static unsigned char bfin_irq_on(struct ata_port *ap)
 }
 
 /**
- *     bfin_bmdma_freeze - Freeze DMA controller port
+ *     bfin_freeze - Freeze DMA controller port
  *     @ap: port to freeze
  *
- *     Note: Original code is ata_bmdma_freeze().
+ *     Note: Original code is ata_sff_freeze().
  */
 
-static void bfin_bmdma_freeze(struct ata_port *ap)
+static void bfin_freeze(struct ata_port *ap)
 {
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
 
@@ -1264,34 +1260,34 @@ static void bfin_bmdma_freeze(struct ata_port *ap)
         * ATA_NIEN manipulation.  Also, many controllers fail to mask
         * previously pending IRQ on ATA_NIEN assertion.  Clear it.
         */
-       ata_chk_status(ap);
+       ap->ops->sff_check_status(ap);
 
        bfin_irq_clear(ap);
 }
 
 /**
- *     bfin_bmdma_thaw - Thaw DMA controller port
+ *     bfin_thaw - Thaw DMA controller port
  *     @ap: port to thaw
  *
- *     Note: Original code is ata_bmdma_thaw().
+ *     Note: Original code is ata_sff_thaw().
  */
 
-void bfin_bmdma_thaw(struct ata_port *ap)
+void bfin_thaw(struct ata_port *ap)
 {
+       dev_dbg(ap->dev, "in atapi dma thaw\n");
        bfin_check_status(ap);
-       bfin_irq_clear(ap);
        bfin_irq_on(ap);
 }
 
 /**
- *     bfin_std_postreset - standard postreset callback
+ *     bfin_postreset - standard postreset callback
  *     @ap: the target ata_port
  *     @classes: classes of attached devices
  *
- *     Note: Original code is ata_std_postreset().
+ *     Note: Original code is ata_sff_postreset().
  */
 
-static void bfin_std_postreset(struct ata_link *link, unsigned int *classes)
+static void bfin_postreset(struct ata_link *link, unsigned int *classes)
 {
        struct ata_port *ap = link->ap;
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
@@ -1301,9 +1297,9 @@ static void bfin_std_postreset(struct ata_link *link, unsigned int *classes)
 
        /* is double-select really necessary? */
        if (classes[0] != ATA_DEV_NONE)
-               bfin_std_dev_select(ap, 1);
+               bfin_dev_select(ap, 1);
        if (classes[1] != ATA_DEV_NONE)
-               bfin_std_dev_select(ap, 0);
+               bfin_dev_select(ap, 0);
 
        /* bail out if no device is present */
        if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
@@ -1345,41 +1341,157 @@ static int bfin_port_start(struct ata_port *ap)
        return 0;
 }
 
+static unsigned int bfin_ata_host_intr(struct ata_port *ap,
+                                  struct ata_queued_cmd *qc)
+{
+       struct ata_eh_info *ehi = &ap->link.eh_info;
+       u8 status, host_stat = 0;
+
+       VPRINTK("ata%u: protocol %d task_state %d\n",
+               ap->print_id, qc->tf.protocol, ap->hsm_task_state);
+
+       /* Check whether we are expecting interrupt in this state */
+       switch (ap->hsm_task_state) {
+       case HSM_ST_FIRST:
+               /* Some pre-ATAPI-4 devices assert INTRQ
+                * at this state when ready to receive CDB.
+                */
+
+               /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+                * The flag was turned on only for atapi devices.
+                * No need to check is_atapi_taskfile(&qc->tf) again.
+                */
+               if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+                       goto idle_irq;
+               break;
+       case HSM_ST_LAST:
+               if (qc->tf.protocol == ATA_PROT_DMA ||
+                   qc->tf.protocol == ATAPI_PROT_DMA) {
+                       /* check status of DMA engine */
+                       host_stat = ap->ops->bmdma_status(ap);
+                       VPRINTK("ata%u: host_stat 0x%X\n",
+                               ap->print_id, host_stat);
+
+                       /* if it's not our irq... */
+                       if (!(host_stat & ATA_DMA_INTR))
+                               goto idle_irq;
+
+                       /* before we do anything else, clear DMA-Start bit */
+                       ap->ops->bmdma_stop(qc);
+
+                       if (unlikely(host_stat & ATA_DMA_ERR)) {
+                               /* error when transfering data to/from memory */
+                               qc->err_mask |= AC_ERR_HOST_BUS;
+                               ap->hsm_task_state = HSM_ST_ERR;
+                       }
+               }
+               break;
+       case HSM_ST:
+               break;
+       default:
+               goto idle_irq;
+       }
+
+       /* check altstatus */
+       status = ap->ops->sff_check_altstatus(ap);
+       if (status & ATA_BUSY)
+               goto busy_ata;
+
+       /* check main status, clearing INTRQ */
+       status = ap->ops->sff_check_status(ap);
+       if (unlikely(status & ATA_BUSY))
+               goto busy_ata;
+
+       /* ack bmdma irq events */
+       ap->ops->sff_irq_clear(ap);
+
+       ata_sff_hsm_move(ap, qc, status, 0);
+
+       if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
+                                      qc->tf.protocol == ATAPI_PROT_DMA))
+               ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+
+busy_ata:
+       return 1;       /* irq handled */
+
+idle_irq:
+       ap->stats.idle_irq++;
+
+#ifdef ATA_IRQ_TRAP
+       if ((ap->stats.idle_irq % 1000) == 0) {
+               ap->ops->irq_ack(ap, 0); /* debug trap */
+               ata_port_printk(ap, KERN_WARNING, "irq trap\n");
+               return 1;
+       }
+#endif
+       return 0;       /* irq not handled */
+}
+
+static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance)
+{
+       struct ata_host *host = dev_instance;
+       unsigned int i;
+       unsigned int handled = 0;
+       unsigned long flags;
+
+       /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+       spin_lock_irqsave(&host->lock, flags);
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap;
+
+               ap = host->ports[i];
+               if (ap &&
+                   !(ap->flags & ATA_FLAG_DISABLED)) {
+                       struct ata_queued_cmd *qc;
+
+                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
+                       if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
+                           (qc->flags & ATA_QCFLAG_ACTIVE))
+                               handled |= bfin_ata_host_intr(ap, qc);
+               }
+       }
+
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       return IRQ_RETVAL(handled);
+}
+
+
 static struct scsi_host_template bfin_sht = {
        ATA_BASE_SHT(DRV_NAME),
        .sg_tablesize           = SG_NONE,
        .dma_boundary           = ATA_DMA_BOUNDARY,
 };
 
-static const struct ata_port_operations bfin_pata_ops = {
+static struct ata_port_operations bfin_pata_ops = {
        .inherits               = &ata_sff_port_ops,
 
        .set_piomode            = bfin_set_piomode,
        .set_dmamode            = bfin_set_dmamode,
 
-       .tf_load                = bfin_tf_load,
-       .tf_read                = bfin_tf_read,
-       .exec_command           = bfin_exec_command,
-       .check_status           = bfin_check_status,
-       .check_altstatus        = bfin_check_altstatus,
-       .dev_select             = bfin_std_dev_select,
+       .sff_tf_load            = bfin_tf_load,
+       .sff_tf_read            = bfin_tf_read,
+       .sff_exec_command       = bfin_exec_command,
+       .sff_check_status       = bfin_check_status,
+       .sff_check_altstatus    = bfin_check_altstatus,
+       .sff_dev_select         = bfin_dev_select,
 
        .bmdma_setup            = bfin_bmdma_setup,
        .bmdma_start            = bfin_bmdma_start,
        .bmdma_stop             = bfin_bmdma_stop,
        .bmdma_status           = bfin_bmdma_status,
-       .data_xfer              = bfin_data_xfer,
+       .sff_data_xfer          = bfin_data_xfer,
 
        .qc_prep                = ata_noop_qc_prep,
 
-       .freeze                 = bfin_bmdma_freeze,
-       .thaw                   = bfin_bmdma_thaw,
-       .softreset              = bfin_std_softreset,
-       .postreset              = bfin_std_postreset,
-       .post_internal_cmd      = bfin_bmdma_stop,
+       .freeze                 = bfin_freeze,
+       .thaw                   = bfin_thaw,
+       .softreset              = bfin_softreset,
+       .postreset              = bfin_postreset,
 
-       .irq_clear              = bfin_irq_clear,
-       .irq_on                 = bfin_irq_on,
+       .sff_irq_clear          = bfin_irq_clear,
+       .sff_irq_on             = bfin_irq_on,
 
        .port_start             = bfin_port_start,
        .port_stop              = bfin_port_stop,
@@ -1390,7 +1502,7 @@ static struct ata_port_info bfin_port_info[] = {
                .flags          = ATA_FLAG_SLAVE_POSS
                                | ATA_FLAG_MMIO
                                | ATA_FLAG_NO_LEGACY,
-               .pio_mask       = 0x1f, /* pio0-4 */
+               .pio_mask       = ATA_PIO4,
                .mwdma_mask     = 0,
                .udma_mask      = 0,
                .port_ops       = &bfin_pata_ops,
@@ -1423,7 +1535,7 @@ static int bfin_reset_controller(struct ata_host *host)
        count = 10000000;
        do {
                status = read_atapi_register(base, ATA_REG_STATUS);
-       } while (count-- && (status & ATA_BUSY));
+       } while (--count && (status & ATA_BUSY));
 
        /* Enable only ATAPI Device interrupt */
        ATAPI_SET_INT_MASK(base, 1);
@@ -1513,12 +1625,14 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)
        }
 
        if (ata_host_activate(host, platform_get_irq(pdev, 0),
-               ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
+               bfin_ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
                peripheral_free_list(atapi_io_port);
                dev_err(&pdev->dev, "Fail to attach ATAPI device\n");
                return -ENODEV;
        }
 
+       dev_set_drvdata(&pdev->dev, host);
+
        return 0;
 }
 
@@ -1535,6 +1649,7 @@ static int __devexit bfin_atapi_remove(struct platform_device *pdev)
        struct ata_host *host = dev_get_drvdata(dev);
 
        ata_host_detach(host);
+       dev_set_drvdata(&pdev->dev, NULL);
 
        peripheral_free_list(atapi_io_port);
 
@@ -1542,27 +1657,44 @@ static int __devexit bfin_atapi_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
+static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       return 0;
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       if (host)
+               return ata_host_suspend(host, state);
+       else
+               return 0;
 }
 
-int bfin_atapi_resume(struct platform_device *pdev)
+static int bfin_atapi_resume(struct platform_device *pdev)
 {
+       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       int ret;
+
+       if (host) {
+               ret = bfin_reset_controller(host);
+               if (ret) {
+                       printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+                       return ret;
+               }
+               ata_host_resume(host);
+       }
+
        return 0;
 }
+#else
+#define bfin_atapi_suspend NULL
+#define bfin_atapi_resume NULL
 #endif
 
 static struct platform_driver bfin_atapi_driver = {
        .probe                  = bfin_atapi_probe,
        .remove                 = __devexit_p(bfin_atapi_remove),
+       .suspend                = bfin_atapi_suspend,
+       .resume                 = bfin_atapi_resume,
        .driver = {
                .name           = DRV_NAME,
                .owner          = THIS_MODULE,
-#ifdef CONFIG_PM
-               .suspend        = bfin_atapi_suspend,
-               .resume         = bfin_atapi_resume,
-#endif
        },
 };
 
@@ -1607,3 +1739,4 @@ MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
 MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);