Module Name:    src
Committed By:   jakllsch
Date:           Thu Jul 12 17:27:42 UTC 2012

Modified Files:
        src/sys/dev/sdmmc: sdhc.c

Log Message:
Completely rework (and enable) SDHC 1.0 DMA data transfer.

While without a large physically-contiguous buffer the performance
suffers severly, this should still be better than PIO.


To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 src/sys/dev/sdmmc/sdhc.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/sdmmc/sdhc.c
diff -u src/sys/dev/sdmmc/sdhc.c:1.18 src/sys/dev/sdmmc/sdhc.c:1.19
--- src/sys/dev/sdmmc/sdhc.c:1.18	Thu Jul 12 17:15:27 2012
+++ src/sys/dev/sdmmc/sdhc.c	Thu Jul 12 17:27:42 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdhc.c,v 1.18 2012/07/12 17:15:27 jakllsch Exp $	*/
+/*	$NetBSD: sdhc.c,v 1.19 2012/07/12 17:27:42 jakllsch Exp $	*/
 /*	$OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $	*/
 
 /*
@@ -23,7 +23,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.18 2012/07/12 17:15:27 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.19 2012/07/12 17:27:42 jakllsch Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -296,7 +296,6 @@ sdhc_host_found(struct sdhc_softc *sc, b
 	caps = HREAD4(hp, SDHC_CAPABILITIES);
 	mutex_exit(&hp->host_mtx);
 
-#if notyet
 	/* Use DMA if the host system and the controller support it. */
 	if (ISSET(sc->sc_flags, SDHC_FLAG_FORCE_DMA)
 	 || ((ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA)
@@ -304,7 +303,6 @@ sdhc_host_found(struct sdhc_softc *sc, b
 		SET(hp->flags, SHF_USE_DMA);
 		aprint_normal_dev(sc->sc_dev, "using DMA transfer\n");
 	}
-#endif
 
 	/*
 	 * Determine the base clock frequency. (2.2.24)
@@ -401,10 +399,8 @@ sdhc_host_found(struct sdhc_softc *sc, b
 		saa.saa_caps |= SMC_CAPS_8BIT_MODE;
 	if (ISSET(caps, SDHC_HIGH_SPEED_SUPP))
 		saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED;
-#if notyet
 	if (ISSET(hp->flags, SHF_USE_DMA))
-		saa.saa_caps |= SMC_CAPS_DMA;
-#endif
+		saa.saa_caps |= SMC_CAPS_DMA | SMC_CAPS_MULTI_SEG_DMA;
 	hp->sdmmc = config_found(sc->sc_dev, &saa, sdhc_cfprint);
 
 	return 0;
@@ -1037,19 +1033,6 @@ sdhc_exec_command(sdmmc_chipset_handle_t
 		sdhc_transfer_data(hp, cmd);
 
 out:
-#if 0
-	if (cmd->c_dmamap != NULL && cmd->c_error == 0
-	    && ISSET(hp->flags, SHF_USE_DMA)
-	    && ISSET(cmd->c_flags, SCF_CMD_READ) {                           
-		if (((uintptr_t)cmd->c_data & PAGE_MASK) + cmd->c_datalen > PAGE_SIZE) {
-			memcpy(cmd->c_data,
-			    (void *)hp->sc->dma_map->dm_segs[0].ds_addr,
-			    cmd->c_datalen);
-		}
-		bus_dmamap_unload(hp->sc->dt, hp->sc->dma_map);
-	}
-#endif
-
 	if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)
 	    && !ISSET(hp->sc->sc_flags, SDHC_FLAG_NO_LED_ON)) {
 		mutex_enter(&hp->host_mtx);
@@ -1111,11 +1094,7 @@ sdhc_start_command(struct sdhc_host *hp,
 		mode |= SDHC_AUTO_CMD12_ENABLE;
 	}
 	if (cmd->c_dmamap != NULL && cmd->c_datalen > 0) {
-		if (cmd->c_dmamap->dm_nsegs == 1) {
-			mode |= SDHC_DMA_ENABLE;
-		} else {
-			cmd->c_dmamap = NULL;
-		}
+		mode |= SDHC_DMA_ENABLE;
 	}
 
 	/*
@@ -1147,6 +1126,9 @@ sdhc_start_command(struct sdhc_host *hp,
 	DPRINTF(1,("%s: writing cmd: blksize=%d blkcnt=%d mode=%04x cmd=%04x\n",
 	    HDEVNAME(hp), blksize, blkcount, mode, command));
 
+	blksize |= (MAX(0, PAGE_SHIFT - 12) & SDHC_DMA_BOUNDARY_MASK) <<
+	    SDHC_DMA_BOUNDARY_SHIFT;	/* PAGE_SIZE DMA boundary */
+
 	mutex_enter(&hp->host_mtx);
 
 	if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
@@ -1212,11 +1194,13 @@ sdhc_transfer_data(struct sdhc_host *hp,
 static int
 sdhc_transfer_data_dma(struct sdhc_host *hp, struct sdmmc_command *cmd)
 {
-	bus_dmamap_t dmap = cmd->c_dmamap;
-	uint16_t blklen = cmd->c_blklen;
-	uint16_t blkcnt = cmd->c_datalen / blklen;
-	uint16_t remain;
+	bus_dma_segment_t *dm_segs = cmd->c_dmamap->dm_segs;
+	bus_addr_t posaddr;
+	bus_addr_t segaddr;
+	bus_size_t seglen;
+	u_int seg = 0;
 	int error = 0;
+	int status;
 
 	KASSERT(HREAD2(hp, SDHC_NINTR_STATUS_EN) & SDHC_DMA_INTERRUPT);
 	KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_DMA_INTERRUPT);
@@ -1224,32 +1208,41 @@ sdhc_transfer_data_dma(struct sdhc_host 
 	KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_TRANSFER_COMPLETE);
 
 	for (;;) {
-		if (!sdhc_wait_intr(hp,
+		status = sdhc_wait_intr(hp,
 		    SDHC_DMA_INTERRUPT|SDHC_TRANSFER_COMPLETE,
-		    SDHC_DMA_TIMEOUT)) {
+		    SDHC_DMA_TIMEOUT);
+
+		if (status & SDHC_TRANSFER_COMPLETE) {
+			break;
+		}
+		if (!status) {
 			error = ETIMEDOUT;
 			break;
 		}
+		if ((status & SDHC_DMA_INTERRUPT) == 0) {
+			continue;
+		}
 
-		/* single block mode */
-		if (blkcnt == 1)
-			break;
+		/* DMA Interrupt (boundary crossing) */
 
-		/* multi block mode */
-		remain = HREAD2(hp, SDHC_BLOCK_COUNT);
-		if (remain == 0)
-			break;
+		segaddr = dm_segs[seg].ds_addr;
+		seglen = dm_segs[seg].ds_len;
+		mutex_enter(&hp->host_mtx);
+		posaddr = HREAD4(hp, SDHC_DMA_ADDR);
+		mutex_exit(&hp->host_mtx);
 
-		HWRITE4(hp, SDHC_DMA_ADDR,
-		    dmap->dm_segs[0].ds_addr + (blkcnt - remain) * blklen);
+		if ((seg == (cmd->c_dmamap->dm_nsegs-1)) && (posaddr == (segaddr + seglen))) {
+			break;
+		}
+		mutex_enter(&hp->host_mtx);
+		if ((posaddr >= segaddr) && (posaddr < (segaddr + seglen)))
+			HWRITE4(hp, SDHC_DMA_ADDR, posaddr);
+		else if ((posaddr >= segaddr) && (posaddr == (segaddr + seglen)) && (seg + 1) < cmd->c_dmamap->dm_nsegs)
+			HWRITE4(hp, SDHC_DMA_ADDR, dm_segs[++seg].ds_addr);
+		mutex_exit(&hp->host_mtx);
+		KASSERT(seg < cmd->c_dmamap->dm_nsegs);
 	}
 
-#if 0
-	if (error == 0 && !sdhc_wait_intr(hp, SDHC_TRANSFER_COMPLETE,
-	    SDHC_TRANSFER_TIMEOUT))
-		error = ETIMEDOUT;
-#endif
-
 	return error;
 }
 

Reply via email to