Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[pandora-kernel.git] / drivers / ata / pata_bf54x.c
index a75de06..d393290 100644 (file)
@@ -911,7 +911,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));
        }
@@ -1008,7 +1011,7 @@ 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
@@ -1019,7 +1022,7 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
        /* 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;
 
@@ -1028,7 +1031,7 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
                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;
                }
@@ -1272,8 +1275,8 @@ static void bfin_freeze(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);
 }
 
@@ -1339,13 +1342,130 @@ 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,
@@ -1370,7 +1490,6 @@ static const struct ata_port_operations bfin_pata_ops = {
        .thaw                   = bfin_thaw,
        .softreset              = bfin_softreset,
        .postreset              = bfin_postreset,
-       .post_internal_cmd      = bfin_bmdma_stop,
 
        .sff_irq_clear          = bfin_irq_clear,
        .sff_irq_on             = bfin_irq_on,
@@ -1507,7 +1626,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)
        }
 
        if (ata_host_activate(host, platform_get_irq(pdev, 0),
-               ata_sff_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;