Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/sunxi SDIO IO_RW_EXTENDED (CMD53) commands have...
details: https://anonhg.NetBSD.org/src/rev/67782c284a68
branches: trunk
changeset: 357023:67782c284a68
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Mon Oct 23 13:11:17 2017 +0000
description:
SDIO IO_RW_EXTENDED (CMD53) commands have datalen set but no dmamap. Setup
and use a bounce buffer to service these requests.
diffstat:
sys/arch/arm/sunxi/sunxi_mmc.c | 96 ++++++++++++++++++++++++++++++++++++++---
1 files changed, 87 insertions(+), 9 deletions(-)
diffs (174 lines):
diff -r 23b434763c9b -r 67782c284a68 sys/arch/arm/sunxi/sunxi_mmc.c
--- a/sys/arch/arm/sunxi/sunxi_mmc.c Mon Oct 23 12:55:26 2017 +0000
+++ b/sys/arch/arm/sunxi/sunxi_mmc.c Mon Oct 23 13:11:17 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_mmc.c,v 1.13 2017/10/23 11:06:31 jmcneill Exp $ */
+/* $NetBSD: sunxi_mmc.c,v 1.14 2017/10/23 13:11:17 jmcneill Exp $ */
/*-
* Copyright (c) 2014-2017 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
#include "opt_sunximmc.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sunxi_mmc.c,v 1.13 2017/10/23 11:06:31 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sunxi_mmc.c,v 1.14 2017/10/23 13:11:17 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -96,6 +96,7 @@
static void sunxi_mmc_attach_i(device_t);
static int sunxi_mmc_intr(void *);
+static int sunxi_mmc_dmabounce_setup(struct sunxi_mmc_softc *);
static int sunxi_mmc_idma_setup(struct sunxi_mmc_softc *);
static int sunxi_mmc_host_reset(sdmmc_chipset_handle_t);
@@ -165,6 +166,10 @@
int sc_idma_ndesc;
void *sc_idma_desc;
+ bus_dmamap_t sc_dmabounce_map;
+ void *sc_dmabounce_buf;
+ size_t sc_dmabounce_buflen;
+
uint32_t sc_intr_rint;
uint32_t sc_idma_idst;
@@ -321,7 +326,8 @@
sc->sc_gpio_cd_inverted = of_hasprop(phandle, "cd-inverted") ? 0 : 1;
sc->sc_gpio_wp_inverted = of_hasprop(phandle, "wp-inverted") ? 0 : 1;
- if (sunxi_mmc_idma_setup(sc) != 0) {
+ if (sunxi_mmc_dmabounce_setup(sc) != 0 ||
+ sunxi_mmc_idma_setup(sc) != 0) {
aprint_error_dev(self, "failed to setup DMA\n");
return;
}
@@ -344,6 +350,42 @@
}
static int
+sunxi_mmc_dmabounce_setup(struct sunxi_mmc_softc *sc)
+{
+ bus_dma_segment_t ds[1];
+ int error, rseg;
+
+ sc->sc_dmabounce_buflen = sunxi_mmc_host_maxblklen(sc);
+ error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmabounce_buflen, 0,
+ sc->sc_dmabounce_buflen, ds, 1, &rseg, BUS_DMA_WAITOK);
+ if (error)
+ return error;
+ error = bus_dmamem_map(sc->sc_dmat, ds, 1, sc->sc_dmabounce_buflen,
+ &sc->sc_dmabounce_buf, BUS_DMA_WAITOK);
+ if (error)
+ goto free;
+ error = bus_dmamap_create(sc->sc_dmat, sc->sc_dmabounce_buflen, 1,
+ sc->sc_dmabounce_buflen, 0, BUS_DMA_WAITOK, &sc->sc_dmabounce_map);
+ if (error)
+ goto unmap;
+ error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmabounce_map,
+ sc->sc_dmabounce_buf, sc->sc_dmabounce_buflen, NULL,
+ BUS_DMA_WAITOK);
+ if (error)
+ goto destroy;
+ return 0;
+
+destroy:
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmabounce_map);
+unmap:
+ bus_dmamem_unmap(sc->sc_dmat, sc->sc_dmabounce_buf,
+ sc->sc_dmabounce_buflen);
+free:
+ bus_dmamem_free(sc->sc_dmat, ds, rseg);
+ return error;
+}
+
+static int
sunxi_mmc_idma_setup(struct sunxi_mmc_softc *sc)
{
int error;
@@ -798,14 +840,38 @@
{
struct sunxi_mmc_idma_descriptor *dma = sc->sc_idma_desc;
bus_addr_t desc_paddr = sc->sc_idma_map->dm_segs[0].ds_addr;
+ bus_dmamap_t map;
bus_size_t off;
int desc, resid, seg;
uint32_t val;
+ /*
+ * If the command includes a dma map use it, otherwise we need to
+ * bounce. This can happen for SDIO IO_RW_EXTENDED (CMD53) commands.
+ */
+ if (cmd->c_dmamap) {
+ map = cmd->c_dmamap;
+ } else {
+ if (cmd->c_datalen > sc->sc_dmabounce_buflen)
+ return E2BIG;
+ map = sc->sc_dmabounce_map;
+
+ if (!ISSET(cmd->c_flags, SCF_CMD_READ)) {
+ memcpy(sc->sc_dmabounce_buf, cmd->c_data,
+ cmd->c_datalen);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmabounce_map,
+ 0, cmd->c_datalen, BUS_DMASYNC_PREWRITE);
+ } else {
+ memset(sc->sc_dmabounce_buf, 0, cmd->c_datalen);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmabounce_map,
+ 0, cmd->c_datalen, BUS_DMASYNC_PREREAD);
+ }
+ }
+
desc = 0;
- for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) {
- bus_addr_t paddr = cmd->c_dmamap->dm_segs[seg].ds_addr;
- bus_size_t len = cmd->c_dmamap->dm_segs[seg].ds_len;
+ for (seg = 0; seg < map->dm_nsegs; seg++) {
+ bus_addr_t paddr = map->dm_segs[seg].ds_addr;
+ bus_size_t len = map->dm_segs[seg].ds_len;
resid = min(len, cmd->c_resid);
off = 0;
while (resid > 0) {
@@ -859,7 +925,7 @@
SUNXI_MMC_DMAC_IDMA_ON|SUNXI_MMC_DMAC_FIX_BURST);
val = MMC_READ(sc, SUNXI_MMC_IDIE);
val &= ~(SUNXI_MMC_IDST_RECEIVE_INT|SUNXI_MMC_IDST_TRANSMIT_INT);
- if (cmd->c_flags & SCF_CMD_READ)
+ if (ISSET(cmd->c_flags, SCF_CMD_READ))
val |= SUNXI_MMC_IDST_RECEIVE_INT;
else
val |= SUNXI_MMC_IDST_TRANSMIT_INT;
@@ -871,10 +937,22 @@
}
static void
-sunxi_mmc_dma_complete(struct sunxi_mmc_softc *sc)
+sunxi_mmc_dma_complete(struct sunxi_mmc_softc *sc, struct sdmmc_command *cmd)
{
bus_dmamap_sync(sc->sc_dmat, sc->sc_idma_map, 0,
sc->sc_idma_size, BUS_DMASYNC_POSTWRITE);
+
+ if (cmd->c_dmamap == NULL) {
+ if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmabounce_map,
+ 0, cmd->c_datalen, BUS_DMASYNC_POSTWRITE);
+ memcpy(cmd->c_data, sc->sc_dmabounce_buf,
+ cmd->c_datalen);
+ } else {
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dmabounce_map,
+ 0, cmd->c_datalen, BUS_DMASYNC_POSTREAD);
+ }
+ }
}
static void
@@ -949,7 +1027,7 @@
&sc->sc_intr_lock, hz);
}
}
- sunxi_mmc_dma_complete(sc);
+ sunxi_mmc_dma_complete(sc, cmd);
if (sc->sc_idma_idst & SUNXI_MMC_IDST_ERROR) {
cmd->c_error = EIO;
} else if (!(sc->sc_idma_idst & SUNXI_MMC_IDST_COMPLETE)) {
Home |
Main Index |
Thread Index |
Old Index