#define IDE_PMAC_DEBUG
-#define DMA_WAIT_TIMEOUT 100
+#define DMA_WAIT_TIMEOUT 50
typedef struct pmac_ide_hwif {
unsigned long regbase;
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;
}
/*
{
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;
* - 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.
*/
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