Hi,

the attached diff allows sdmmc(4) to use DMA for all commands instead of just
mem_read and mem_write. 

There were problems in the past with some controllers not liking small DMA
transfers, so it would be nice to get this tested thorougly on different
hardware.  So far I have successfully tested it on a Raspberry Pi 3 B.
 
Test results and comments welcome :)

diff --git a/sys/dev/sdmmc/sdmmc.c b/sys/dev/sdmmc/sdmmc.c
index 588bbaf8f94..12f73f52995 100644
--- a/sys/dev/sdmmc/sdmmc.c
+++ b/sys/dev/sdmmc/sdmmc.c
@@ -627,8 +627,35 @@ sdmmc_mmc_command(struct sdmmc_softc *sc, struct 
sdmmc_command *cmd)
 
        rw_assert_wrlock(&sc->sc_lock);
 
+       if (cmd->c_data != NULL && ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+               error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmap,
+                   cmd->c_data, cmd->c_datalen, NULL, BUS_DMA_NOWAIT |
+                   (ISSET(cmd->c_flags, SCF_CMD_READ) ?
+                    BUS_DMA_READ : BUS_DMA_WRITE));
+               if (error)
+                       return (error);
+
+               bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap,
+                   0, sc->sc_dmap->dm_mapsize,
+                   (ISSET(cmd->c_flags, SCF_CMD_READ) ?
+                    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE));
+
+               cmd->c_dmamap = sc->sc_dmap;
+       }
+
        sdmmc_chip_exec_command(sc->sct, sc->sch, cmd);
 
+       if (cmd->c_dmamap != NULL) {
+               bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap,
+                   0, sc->sc_dmap->dm_mapsize,
+                   (ISSET(cmd->c_flags, SCF_CMD_READ) ?
+                    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE));
+
+               bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
+
+               cmd->c_dmamap = NULL;
+       }
+
 #ifdef SDMMC_DEBUG
        sdmmc_dump_command(sc, cmd);
 #endif
diff --git a/sys/dev/sdmmc/sdmmc_mem.c b/sys/dev/sdmmc/sdmmc_mem.c
index 9412593de04..4bf66c1eb81 100644
--- a/sys/dev/sdmmc/sdmmc_mem.c
+++ b/sys/dev/sdmmc/sdmmc_mem.c
@@ -23,6 +23,8 @@
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/pool.h>
 
 #include <dev/sdmmc/sdmmcchip.h>
 #include <dev/sdmmc/sdmmcreg.h>
@@ -57,11 +59,11 @@ int sdmmc_mem_sd_init(struct sdmmc_softc *, struct 
sdmmc_function *);
 int    sdmmc_mem_mmc_init(struct sdmmc_softc *, struct sdmmc_function *);
 int    sdmmc_mem_single_read_block(struct sdmmc_function *, int, u_char *,
        size_t);
-int    sdmmc_mem_read_block_subr(struct sdmmc_function *, bus_dmamap_t,
+int    sdmmc_mem_read_block_subr(struct sdmmc_function *,
        int, u_char *, size_t);
 int    sdmmc_mem_single_write_block(struct sdmmc_function *, int, u_char *,
        size_t);
-int    sdmmc_mem_write_block_subr(struct sdmmc_function *, bus_dmamap_t,
+int    sdmmc_mem_write_block_subr(struct sdmmc_function *,
        int, u_char *, size_t);
 
 #ifdef SDMMC_DEBUG
@@ -359,9 +361,9 @@ sdmmc_mem_send_scr(struct sdmmc_softc *sc, uint32_t *scr)
        int datalen = 8;
        int error = 0;
 
-       ptr = malloc(datalen, M_DEVBUF, M_NOWAIT | M_ZERO);
+       ptr = dma_alloc(datalen, PR_NOWAIT | PR_ZERO);
        if (ptr == NULL)
-               goto out;
+               return (ENOMEM);
 
        memset(&cmd, 0, sizeof(cmd));
        cmd.c_data = ptr;
@@ -375,9 +377,7 @@ sdmmc_mem_send_scr(struct sdmmc_softc *sc, uint32_t *scr)
        if (error == 0)
                memcpy(scr, ptr, datalen);
 
-out:
-       if (ptr != NULL)
-               free(ptr, M_DEVBUF, datalen);
+       dma_free(ptr, datalen);
 
        return error;
 }
@@ -422,11 +422,9 @@ sdmmc_mem_send_cxd_data(struct sdmmc_softc *sc, int 
opcode, void *data,
        void *ptr = NULL;
        int error = 0;
 
-       ptr = malloc(datalen, M_DEVBUF, M_NOWAIT | M_ZERO);
-       if (ptr == NULL) {
-               error = ENOMEM;
-               goto out;
-       }
+       ptr = dma_alloc(datalen, PR_NOWAIT | PR_ZERO);
+       if (ptr == NULL)
+               return (ENOMEM);
 
        memset(&cmd, 0, sizeof(cmd));
        cmd.c_data = ptr;
@@ -444,9 +442,7 @@ sdmmc_mem_send_cxd_data(struct sdmmc_softc *sc, int opcode, 
void *data,
        if (error == 0)
                memcpy(data, ptr, datalen);
 
-out:
-       if (ptr != NULL)
-               free(ptr, M_DEVBUF, datalen);
+       dma_free(ptr, datalen);
 
        return error;
 }
@@ -501,9 +497,9 @@ sdmmc_mem_sd_switch(struct sdmmc_function *sf, int mode, 
int group,
 
        gsft = (group - 1) << 2;
 
-       ptr = malloc(statlen, M_DEVBUF, M_NOWAIT | M_ZERO);
+       ptr = dma_alloc(statlen, PR_NOWAIT | PR_ZERO);
        if (ptr == NULL)
-               goto out;
+               return (ENOMEM);
 
        memset(&cmd, 0, sizeof(cmd));
        cmd.c_data = ptr;
@@ -515,15 +511,12 @@ sdmmc_mem_sd_switch(struct sdmmc_function *sf, int mode, 
int group,
        cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1;
 
        error = sdmmc_mmc_command(sc, &cmd);
-       if (error == 0)
+       if (error == 0) {
                memcpy(status, ptr, statlen);
-
-out:
-       if (ptr != NULL)
-               free(ptr, M_DEVBUF, statlen);
-
-       if (error == 0)
                sdmmc_be512_to_bitfield512(status);
+       }
+
+       dma_free(ptr, statlen);
 
        return error;
 }
@@ -886,7 +879,7 @@ sdmmc_mem_set_blocklen(struct sdmmc_softc *sc, struct 
sdmmc_function *sf)
 }
 
 int
-sdmmc_mem_read_block_subr(struct sdmmc_function *sf, bus_dmamap_t dmap,
+sdmmc_mem_read_block_subr(struct sdmmc_function *sf,
     int blkno, u_char *data, size_t datalen)
 {
        struct sdmmc_softc *sc = sf->sc;
@@ -908,7 +901,6 @@ sdmmc_mem_read_block_subr(struct sdmmc_function *sf, 
bus_dmamap_t dmap,
        else
                cmd.c_arg = blkno << 9;
        cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1;
-       cmd.c_dmamap = dmap;
 
        error = sdmmc_mmc_command(sc, &cmd);
        if (error != 0)
@@ -948,7 +940,7 @@ sdmmc_mem_single_read_block(struct sdmmc_function *sf, int 
blkno, u_char *data,
        int i;
 
        for (i = 0; i < datalen / sf->csd.sector_size; i++) {
-               error = sdmmc_mem_read_block_subr(sf, NULL,  blkno + i,
+               error = sdmmc_mem_read_block_subr(sf, blkno + i,
                    data + i * sf->csd.sector_size, sf->csd.sector_size);
                if (error)
                        break;
@@ -971,30 +963,7 @@ sdmmc_mem_read_block(struct sdmmc_function *sf, int blkno, 
u_char *data,
                goto out;
        }
 
-       if (!ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
-               error = sdmmc_mem_read_block_subr(sf, NULL, blkno,
-                   data, datalen);
-               goto out;
-       }
-
-       /* DMA transfer */
-       error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, data, datalen,
-           NULL, BUS_DMA_NOWAIT|BUS_DMA_READ);
-       if (error)
-               goto out;
-
-       bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
-           BUS_DMASYNC_PREREAD);
-
-       error = sdmmc_mem_read_block_subr(sf, sc->sc_dmap, blkno, data,
-           datalen);
-       if (error)
-               goto unload;
-
-       bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
-           BUS_DMASYNC_POSTREAD);
-unload:
-       bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
+       error = sdmmc_mem_read_block_subr(sf, blkno, data, datalen);
 
 out:
        rw_exit(&sc->sc_lock);
@@ -1002,7 +971,7 @@ out:
 }
 
 int
-sdmmc_mem_write_block_subr(struct sdmmc_function *sf, bus_dmamap_t dmap,
+sdmmc_mem_write_block_subr(struct sdmmc_function *sf,
     int blkno, u_char *data, size_t datalen)
 {
        struct sdmmc_softc *sc = sf->sc;
@@ -1023,7 +992,6 @@ sdmmc_mem_write_block_subr(struct sdmmc_function *sf, 
bus_dmamap_t dmap,
        else
                cmd.c_arg = blkno << 9;
        cmd.c_flags = SCF_CMD_ADTC | SCF_RSP_R1;
-       cmd.c_dmamap = dmap;
 
        error = sdmmc_mmc_command(sc, &cmd);
        if (error != 0)
@@ -1062,7 +1030,7 @@ sdmmc_mem_single_write_block(struct sdmmc_function *sf, 
int blkno, u_char *data,
        int i;
 
        for (i = 0; i < datalen / sf->csd.sector_size; i++) {
-               error = sdmmc_mem_write_block_subr(sf, NULL, blkno + i,
+               error = sdmmc_mem_write_block_subr(sf, blkno + i,
                    data + i * sf->csd.sector_size, sf->csd.sector_size);
                if (error)
                        break;
@@ -1085,30 +1053,8 @@ sdmmc_mem_write_block(struct sdmmc_function *sf, int 
blkno, u_char *data,
                goto out;
        }
 
-       if (!ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
-               error = sdmmc_mem_write_block_subr(sf, NULL, blkno,
-                   data, datalen);
-               goto out;
-       }
-
-       /* DMA transfer */
-       error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, data, datalen,
-           NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE);
-       if (error)
-               goto out;
-
-       bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
-           BUS_DMASYNC_PREWRITE);
-
-       error = sdmmc_mem_write_block_subr(sf, sc->sc_dmap, blkno, data,
+       error = sdmmc_mem_write_block_subr(sf, blkno, data,
            datalen);
-       if (error)
-               goto unload;
-
-       bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
-           BUS_DMASYNC_POSTWRITE);
-unload:
-       bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
 
 out:
        rw_exit(&sc->sc_lock);

Reply via email to