patch-2.4.13 linux/arch/arm/mach-sa1100/dma-sa1100.c

Next file: linux/arch/arm/mach-sa1100/dma-sa1111.c
Previous file: linux/arch/arm/mach-sa1100/cpu-sa1110.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.12/linux/arch/arm/mach-sa1100/dma-sa1100.c linux/arch/arm/mach-sa1100/dma-sa1100.c
@@ -68,26 +68,30 @@
 {
 	dma_regs_t *regs = dma->regs;
 	int status;
-	int use_bufa;
 
 	status = regs->RdDCSR;
 
 	/* If both DMA buffers are started, there's nothing else we can do. */
-	if ((status & DCSR_STRTA) && (status & DCSR_STRTB)) {
+	if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) {
 		DPRINTK("start: st %#x busy\n", status);
 		return -EBUSY;
 	}
 
-	use_bufa = (((status & DCSR_BIU) && (status & DCSR_STRTB)) ||
-		    (!(status & DCSR_BIU) && !(status & DCSR_STRTA)));
-	if (use_bufa) {
-		regs->ClrDCSR = DCSR_DONEA | DCSR_STRTA;
+	if (((status & DCSR_BIU) && (status & DCSR_STRTB)) ||
+	    (!(status & DCSR_BIU) && !(status & DCSR_STRTA))) {
+		if (status & DCSR_DONEA) {
+			/* give a chance for the interrupt to be processed */
+			goto irq_pending;
+		}
 		regs->DBSA = dma_ptr;
 		regs->DBTA = size;
 		regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN;
 		DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size);
 	} else {
-		regs->ClrDCSR = DCSR_DONEB | DCSR_STRTB;
+		if (status & DCSR_DONEB) {
+			/* give a chance for the interrupt to be processed */
+			goto irq_pending;
+		}
 		regs->DBSB = dma_ptr;
 		regs->DBTB = size;
 		regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN;
@@ -95,6 +99,9 @@
 	}
 
 	return 0;
+
+irq_pending:
+	return -EAGAIN;
 }
 
 
@@ -204,11 +211,16 @@
 
 	DPRINTK("IRQ: b=%#x st=%#x\n", (int) dma->curr->id, status);
 
-	dma->regs->ClrDCSR = DCSR_ERROR | DCSR_DONEA | DCSR_DONEB;
-	if (!(status & (DCSR_DONEA | DCSR_DONEB)))
-		return;
+	if (status & (DCSR_ERROR)) {
+		printk(KERN_ERR "DMA on \"%s\" caused an error\n", dma->device_id);
+		dma->regs->ClrDCSR = DCSR_ERROR;
+	}
 
-	sa1100_dma_done (dma);
+	dma->regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB);
+	if (status & DCSR_DONEA)
+		sa1100_dma_done (dma);
+	if (status & DCSR_DONEB)
+		sa1100_dma_done (dma);
 }
 
 
@@ -435,7 +447,7 @@
 		dma->curr = NULL;
 	}
 	dma->spin_ref = 0;
-	dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB;
+	dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_DONEA|DCSR_DONEB;
 	process_dma(dma);
 	local_irq_restore(flags);
 	return 0;
@@ -455,7 +467,6 @@
 	if (dma->stopped) {
 		int flags;
 		save_flags_cli(flags);
-		dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_RUN|DCSR_IE;
 		dma->stopped = 0;
 		dma->spin_ref = 0;
 		process_dma(dma);
@@ -478,7 +489,7 @@
 	if (channel_is_sa1111_sac(channel))
 		sa1111_reset_sac_dma(channel);
 	else
-		dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_RUN|DCSR_IE;
+		dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_DONEA|DCSR_DONEB|DCSR_RUN|DCSR_IE;
 	buf = dma->curr;
 	if (!buf)
 		buf = dma->tail;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)