Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 10 Jan 2007 07:03:04 GMT
From:      Warner Losh <imp@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 112701 for review
Message-ID:  <200701100703.l0A734xi068010@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=112701

Change 112701 by imp@imp_lighthouse on 2007/01/10 07:02:04

	Add a comment about why we need to do the dance we do with enabling
	the PDC, along with a simplified version of the code.

Affected files ...

.. //depot/projects/arm/src/sys/arm/at91/at91_mci.c#30 edit

Differences ...

==== //depot/projects/arm/src/sys/arm/at91/at91_mci.c#30 (text+ko) ====

@@ -402,16 +402,27 @@
 		}
 	}
 //	printf("CMDR %x ARGR %x with data\n", cmdr, cmd->arg);
+	/*
+	 * For Reads, we need to enable the DMA buffer before we send
+	 * the command.  For writes, alas, it has to be enabled after
+	 * we send the command.  If enabled after the CMDR write for
+	 * reads, fast SD parts could win the race that's present and
+	 * the result would be corrupted data because the ENDRX bit
+	 * would be set, but the dma wouldn't have started yet.  When
+	 * that interrupt returned, we'd enable DMA.  We'd then get a
+	 * RXBUFF interrupt and then a CMDRDY interrupt.  We'd process
+	 * things int he ISR.  But since the DMA started after we got
+	 * the ENDRX and RXBUFF interrupts, when we got the CMDRDY
+	 * interrupt the data would still be in flight, leading to
+	 * corruption.  This race was 'hard' to trigger for slow parts,
+	 * but easy to trigger for faster ones.
+	 */
 	WR4(sc, MCI_ARGR, cmd->arg);
-	if (cmdr & MCI_CMDR_TRCMD_START) {
-		if (cmdr & MCI_CMDR_TRDIR) {
-			WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN);
-			WR4(sc, MCI_CMDR, cmdr);
-		} else {
-			WR4(sc, MCI_CMDR, cmdr);
-			WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN);
-		}
-	}
+	if ((cmdr & MCI_CMDR_TRCMD_START) && (cmdr & MCI_CMDR_TRDIR))
+		WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN);
+	WR4(sc, MCI_CMDR, cmdr);
+	if ((cmdr & MCI_CMDR_TRCMD_START) && !(cmdr & MCI_CMDR_TRDIR))
+		WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN);
 	WR4(sc, MCI_IER, MCI_SR_ERROR | ier);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200701100703.l0A734xi068010>