+- add patches.fixes/linux-post-2.6.3-20040220
[linux-flexiantxendom0-3.2.10.git] / drivers / ide / ppc / pmac.c
index 4668cfb..2abbffa 100644 (file)
@@ -55,7 +55,7 @@ extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
 
 #define IDE_PMAC_DEBUG
 
-#define DMA_WAIT_TIMEOUT       100
+#define DMA_WAIT_TIMEOUT       50
 
 typedef struct pmac_ide_hwif {
        unsigned long                   regbase;
@@ -2026,8 +2026,11 @@ pmac_ide_dma_end (ide_drive_t *drive)
        dstat = readl(&dma->status);
        writel(((RUN|WAKE|DEAD) << 16), &dma->control);
        pmac_ide_destroy_dmatable(drive);
-       /* verify good dma status */
-       return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
+       /* verify good dma status. we don't check for ACTIVE beeing 0. We should...
+        * in theory, but with ATAPI decices doing buffer underruns, that would
+        * cause us to disable DMA, which isn't what we want
+        */
+       return (dstat & (RUN|DEAD)) != RUN;
 }
 
 /*
@@ -2041,7 +2044,7 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
 {
        pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
        volatile struct dbdma_regs *dma;
-       unsigned long status;
+       unsigned long status, timeout;
 
        if (pmif == NULL)
                return 0;
@@ -2057,17 +2060,8 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
         * - The dbdma fifo hasn't yet finished flushing to
         * to system memory when the disk interrupt occurs.
         * 
-        * The trick here is to increment drive->waiting_for_dma,
-        * and return as if no interrupt occurred. If the counter
-        * reach a certain timeout value, we then return 1. If
-        * we really got the interrupt, it will happen right away
-        * again.
-        * Apple's solution here may be more elegant. They issue
-        * a DMA channel interrupt (a separate irq line) via a DBDMA
-        * NOP command just before the STOP, and wait for both the
-        * disk and DBDMA interrupts to have completed.
         */
+
        /* If ACTIVE is cleared, the STOP command have passed and
         * transfer is complete.
         */
@@ -2079,15 +2073,26 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
                        called while not waiting\n", HWIF(drive)->index);
 
        /* If dbdma didn't execute the STOP command yet, the
-        * active bit is still set */
-       drive->waiting_for_dma++;
-       if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
-               printk(KERN_WARNING "ide%d, timeout waiting \
-                       for dbdma command stop\n", HWIF(drive)->index);
-               return 1;
-       }
-       udelay(5);
-       return 0;
+        * active bit is still set. We consider that we aren't
+        * sharing interrupts (which is hopefully the case with
+        * those controllers) and so we just try to flush the
+        * channel for pending data in the fifo
+        */
+       udelay(1);
+       writel((FLUSH << 16) | FLUSH, &dma->control);
+       timeout = 0;
+       for (;;) {
+               udelay(1);
+               status = readl(&dma->status);
+               if ((status & FLUSH) == 0)
+                       break;
+               if (++timeout > 100) {
+                       printk(KERN_WARNING "ide%d, ide_dma_test_irq \
+                       timeout flushing channel\n", HWIF(drive)->index);
+                       break;
+               }
+       }       
+       return 1;
 }
 
 static int __pmac