summaryrefslogtreecommitdiff
path: root/sys/dev/sdmmc
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2016-04-30 11:32:24 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2016-04-30 11:32:24 +0000
commit8b7825f07a90ab9de5e477caf9c60a0a426d5b66 (patch)
tree850893dd63ff9eeeb3102bbc7eba53e48336513b /sys/dev/sdmmc
parentecef7a2ce61bca18b808b58acff08fc034626f37 (diff)
Implement DMA support. Bits and pieces taken from NetBSD, but we only
support ADMA2. The older SDMA mode has too many limitations to be really usable. Gives us only moderate speed improvements, bus reduces the CPU load considerably. We will reap the full benefits once we implement wider bus widths and high speed modes. There is a remining issue with simultanious use of eMMC and external SD card on (some) Intel Bay Trail hardware. Still under investigation. ok patrick@, stsp@, deraadt@
Diffstat (limited to 'sys/dev/sdmmc')
-rw-r--r--sys/dev/sdmmc/sdhc.c111
-rw-r--r--sys/dev/sdmmc/sdhcreg.h57
-rw-r--r--sys/dev/sdmmc/sdhcvar.h4
-rw-r--r--sys/dev/sdmmc/sdmmc.c17
-rw-r--r--sys/dev/sdmmc/sdmmc_mem.c86
-rw-r--r--sys/dev/sdmmc/sdmmcchip.h5
-rw-r--r--sys/dev/sdmmc/sdmmcvar.h10
7 files changed, 260 insertions, 30 deletions
diff --git a/sys/dev/sdmmc/sdhc.c b/sys/dev/sdmmc/sdhc.c
index f033593b5ee..3e8f1868476 100644
--- a/sys/dev/sdmmc/sdhc.c
+++ b/sys/dev/sdmmc/sdhc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdhc.c,v 1.43 2016/03/30 09:58:01 kettenis Exp $ */
+/* $OpenBSD: sdhc.c,v 1.44 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -36,6 +36,7 @@
#define SDHC_COMMAND_TIMEOUT hz
#define SDHC_BUFFER_TIMEOUT hz
#define SDHC_TRANSFER_TIMEOUT hz
+#define SDHC_DMA_TIMEOUT (hz*3)
struct sdhc_host {
struct sdhc_softc *sc; /* host controller device */
@@ -50,6 +51,10 @@ struct sdhc_host {
u_int8_t regs[14]; /* host controller state */
u_int16_t intr_status; /* soft interrupt status */
u_int16_t intr_error_status; /* soft error status */
+
+ bus_dmamap_t adma_map;
+ bus_dma_segment_t adma_segs[1];
+ caddr_t adma2;
};
/* flag values */
@@ -174,7 +179,7 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
caps = HREAD4(hp, SDHC_CAPABILITIES);
/* Use DMA if the host system and the controller support it. */
- if (usedma && ISSET(caps, SDHC_DMA_SUPPORT))
+ if (usedma && ISSET(caps, SDHC_ADMA2_SUPP))
SET(hp->flags, SHF_USE_DMA);
/*
@@ -236,6 +241,46 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
break;
}
+ if (ISSET(hp->flags, SHF_USE_DMA)) {
+ int rseg;
+
+ /* Allocate ADMA2 descriptor memory */
+ error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE,
+ PAGE_SIZE, hp->adma_segs, 1, &rseg,
+ BUS_DMA_WAITOK | BUS_DMA_ZERO);
+ if (error)
+ goto adma_done;
+ error = bus_dmamem_map(sc->sc_dmat, hp->adma_segs, rseg,
+ PAGE_SIZE, &hp->adma2, BUS_DMA_WAITOK);
+ if (error) {
+ bus_dmamem_free(sc->sc_dmat, hp->adma_segs, rseg);
+ goto adma_done;
+ }
+ error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
+ 0, BUS_DMA_WAITOK, &hp->adma_map);
+ if (error) {
+ bus_dmamem_unmap(sc->sc_dmat, hp->adma2, PAGE_SIZE);
+ bus_dmamem_free(sc->sc_dmat, hp->adma_segs, rseg);
+ goto adma_done;
+ }
+ error = bus_dmamap_load(sc->sc_dmat, hp->adma_map,
+ hp->adma2, PAGE_SIZE, NULL,
+ BUS_DMA_WAITOK | BUS_DMA_WRITE);
+ if (error) {
+ bus_dmamap_destroy(sc->sc_dmat, hp->adma_map);
+ bus_dmamem_unmap(sc->sc_dmat, hp->adma2, PAGE_SIZE);
+ bus_dmamem_free(sc->sc_dmat, hp->adma_segs, rseg);
+ goto adma_done;
+ }
+
+ adma_done:
+ if (error) {
+ printf("%s: can't allocate DMA descriptor table\n",
+ DEVNAME(hp->sc));
+ CLR(hp->flags, SHF_USE_DMA);
+ }
+ }
+
/*
* Attach the generic SD/MMC bus driver. (The bus driver must
* not invoke any chipset functions before it is attached.)
@@ -244,6 +289,9 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
saa.saa_busname = "sdmmc";
saa.sct = &sdhc_functions;
saa.sch = hp;
+ saa.dmat = sc->sc_dmat;
+ if (ISSET(hp->flags, SHF_USE_DMA))
+ saa.caps |= SMC_CAPS_DMA;
hp->sdmmc = config_found(&sc->sc_dev, &saa, NULL);
if (hp->sdmmc == NULL) {
@@ -641,11 +689,14 @@ sdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
int
sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
{
+ struct sdhc_adma2_descriptor32 *desc = (void *)hp->adma2;
+ struct sdhc_softc *sc = hp->sc;
u_int16_t blksize = 0;
u_int16_t blkcount = 0;
u_int16_t mode;
u_int16_t command;
int error;
+ int seg;
int s;
DPRINTF(1,("%s: start cmd %u arg=%#x data=%#x dlen=%d flags=%#x "
@@ -688,10 +739,9 @@ sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
mode |= SDHC_AUTO_CMD12_ENABLE;
}
}
-#ifdef notyet
- if (ISSET(hp->flags, SHF_USE_DMA))
+ if (cmd->c_dmamap && cmd->c_datalen > 0 &&
+ ISSET(hp->flags, SHF_USE_DMA))
mode |= SDHC_DMA_ENABLE;
-#endif
/*
* Prepare command register value. (2.2.6)
@@ -724,7 +774,36 @@ sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
/* Alert the user not to remove the card. */
HSET1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
- /* XXX: Set DMA start address if SHF_USE_DMA is set. */
+ /* Set DMA start address if SHF_USE_DMA is set. */
+ if (cmd->c_dmamap && ISSET(hp->flags, SHF_USE_DMA)) {
+ for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) {
+ bus_addr_t paddr =
+ cmd->c_dmamap->dm_segs[seg].ds_addr;
+ uint16_t len =
+ cmd->c_dmamap->dm_segs[seg].ds_len == 65536 ?
+ 0 : cmd->c_dmamap->dm_segs[seg].ds_len;
+ uint16_t attr;
+
+ attr = SDHC_ADMA2_VALID | SDHC_ADMA2_ACT_TRANS;
+ if (seg == cmd->c_dmamap->dm_nsegs - 1)
+ attr |= SDHC_ADMA2_END;
+
+ desc[seg].attribute = htole16(attr);
+ desc[seg].length = htole16(len);
+ desc[seg].address = htole32(paddr);
+ }
+
+ desc[cmd->c_dmamap->dm_nsegs].attribute = htole16(0);
+
+ bus_dmamap_sync(sc->sc_dmat, hp->adma_map, 0, PAGE_SIZE,
+ BUS_DMASYNC_PREWRITE);
+
+ HCLR1(hp, SDHC_HOST_CTL, SDHC_DMA_SELECT);
+ HSET1(hp, SDHC_HOST_CTL, SDHC_DMA_SELECT_ADMA2);
+
+ HWRITE4(hp, SDHC_ADMA_SYSTEM_ADDR,
+ hp->adma_map->dm_segs[0].ds_addr);
+ }
DPRINTF(1,("%s: cmd=%#x mode=%#x blksize=%d blkcount=%d\n",
DEVNAME(hp->sc), command, mode, blksize, blkcount));
@@ -752,6 +831,25 @@ sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd)
int mask;
int error;
+ if (cmd->c_dmamap) {
+ int status;
+
+ error = 0;
+ for (;;) {
+ status = sdhc_wait_intr(hp,
+ SDHC_DMA_INTERRUPT|SDHC_TRANSFER_COMPLETE,
+ SDHC_DMA_TIMEOUT);
+ if (status & SDHC_TRANSFER_COMPLETE)
+ break;
+ if (!status) {
+ error = ETIMEDOUT;
+ break;
+ }
+ }
+
+ goto done;
+ }
+
mask = ISSET(cmd->c_flags, SCF_CMD_READ) ?
SDHC_BUFFER_READ_ENABLE : SDHC_BUFFER_WRITE_ENABLE;
error = 0;
@@ -792,6 +890,7 @@ sdhc_transfer_data(struct sdhc_host *hp, struct sdmmc_command *cmd)
SDHC_TRANSFER_TIMEOUT))
error = ETIMEDOUT;
+done:
if (error != 0)
cmd->c_error = error;
SET(cmd->c_flags, SCF_ITSDONE);
diff --git a/sys/dev/sdmmc/sdhcreg.h b/sys/dev/sdmmc/sdhcreg.h
index c7e9bc85764..300d14a1c38 100644
--- a/sys/dev/sdmmc/sdhcreg.h
+++ b/sys/dev/sdmmc/sdhcreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdhcreg.h,v 1.5 2016/01/11 06:54:53 kettenis Exp $ */
+/* $OpenBSD: sdhcreg.h,v 1.6 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -80,6 +80,10 @@
#define SDHC_CMD_INHIBIT_CMD (1<<0)
#define SDHC_CMD_INHIBIT_MASK 0x0003
#define SDHC_HOST_CTL 0x28
+#define SDHC_8BIT_MODE (1<<5)
+#define SDHC_DMA_SELECT (3<<3)
+#define SDHC_DMA_SELECT_SDMA (0<<3)
+#define SDHC_DMA_SELECT_ADMA2 (2<<3)
#define SDHC_HIGH_SPEED (1<<2)
#define SDHC_4BIT_MODE (1<<1)
#define SDHC_LED_ON (1<<0)
@@ -137,12 +141,25 @@
#define SDHC_EINTR_SIGNAL_EN 0x3a
#define SDHC_EINTR_SIGNAL_MASK 0x01ff /* excluding vendor signals */
#define SDHC_CMD12_ERROR_STATUS 0x3c
+#define SDHC_HOST_CTL2 0x3e
+#define SDHC_SAMPLING_CLOCK_SEL (1<<7)
+#define SDHC_EXECUTE_TUNING (1<<6)
+#define SDHC_1_8V_SIGNAL_EN (1<<3)
+#define SDHC_UHS_MODE_SELECT_SHIFT 0
+#define SDHC_UHS_MODE_SELECT_MASK 0x7
+#define SDHC_UHS_MODE_SELECT_SDR12 0
+#define SDHC_UHS_MODE_SELECT_SDR25 1
+#define SDHC_UHS_MODE_SELECT_SDR50 2
+#define SDHC_UHS_MODE_SELECT_SDR104 3
+#define SDHC_UHS_MODE_SELECT_DDR50 4
#define SDHC_CAPABILITIES 0x40
#define SDHC_VOLTAGE_SUPP_1_8V (1<<26)
#define SDHC_VOLTAGE_SUPP_3_0V (1<<25)
#define SDHC_VOLTAGE_SUPP_3_3V (1<<24)
-#define SDHC_DMA_SUPPORT (1<<22)
+#define SDHC_SDMA_SUPP (1<<22)
#define SDHC_HIGH_SPEED_SUPP (1<<21)
+#define SDHC_ADMA2_SUPP (1<<19)
+#define SDHC_8BIT_MODE_SUPP (1<<18)
#define SDHC_MAX_BLK_LEN_512 0
#define SDHC_MAX_BLK_LEN_1024 1
#define SDHC_MAX_BLK_LEN_2048 2
@@ -154,7 +171,27 @@
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
#define SDHC_TIMEOUT_FREQ_SHIFT 0
#define SDHC_TIMEOUT_FREQ_MASK 0x1f
-#define SDHC_CAPABILITIES_1 0x44
+#define SDHC_CAPABILITIES2 0x44
+#define SDHC_SDR50_SUPP (1<<0)
+#define SDHC_SDR104_SUPP (1<<1)
+#define SDHC_DDR50_SUPP (1<<2)
+#define SDHC_DRIVER_TYPE_A (1<<4)
+#define SDHC_DRIVER_TYPE_C (1<<5)
+#define SDHC_DRIVER_TYPE_D (1<<6)
+#define SDHC_TIMER_COUNT_SHIFT 8
+#define SDHC_TIMER_COUNT_MASK 0xf
+#define SDHC_TUNING_SDR50 (1<<13)
+#define SDHC_RETUNING_MODES_SHIFT 14
+#define SDHC_RETUNING_MODES_MASK 0x3
+#define SDHC_RETUNING_MODE_1 (0 << SDHC_RETUNING_MODES_SHIFT)
+#define SDHC_RETUNING_MODE_2 (1 << SDHC_RETUNING_MODES_SHIFT)
+#define SDHC_RETUNING_MODE_3 (2 << SDHC_RETUNING_MODES_SHIFT)
+#define SDHC_CLOCK_MULTIPLIER_SHIFT 16
+#define SDHC_CLOCK_MULTIPLIER_MASK 0xff
+#define SDHC_ADMA_ERROR_STATUS 0x54
+#define SDHC_ADMA_LENGTH_MISMATCH (1<<2)
+#define SDHC_ADMA_ERROR_STATE (3<<0)
+#define SDHC_ADMA_SYSTEM_ADDR 0x58
#define SDHC_MAX_CAPABILITIES 0x48
#define SDHC_SLOT_INTR_STATUS 0xfc
#define SDHC_HOST_CTL_VERSION 0xfe
@@ -202,4 +239,18 @@
#define SDHC_CAPABILITIES_BITS \
"\20\33Vdd1.8V\32Vdd3.0V\31Vdd3.3V\30SUSPEND\27DMA\26HIGHSPEED"
+#define SDHC_ADMA2_VALID (1<<0)
+#define SDHC_ADMA2_END (1<<1)
+#define SDHC_ADMA2_INT (1<<2)
+#define SDHC_ADMA2_ACT (3<<4)
+#define SDHC_ADMA2_ACT_NOP (0<<4)
+#define SDHC_ADMA2_ACT_TRANS (2<<4)
+#define SDHC_ADMA2_ACT_LINK (3<<4)
+
+struct sdhc_adma2_descriptor32 {
+ uint16_t attribute;
+ uint16_t length;
+ uint32_t address;
+} __packed;
+
#endif
diff --git a/sys/dev/sdmmc/sdhcvar.h b/sys/dev/sdmmc/sdhcvar.h
index edd1c27f1f7..e6a419e2719 100644
--- a/sys/dev/sdmmc/sdhcvar.h
+++ b/sys/dev/sdmmc/sdhcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdhcvar.h,v 1.8 2016/03/30 09:58:01 kettenis Exp $ */
+/* $OpenBSD: sdhcvar.h,v 1.9 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -29,6 +29,8 @@ struct sdhc_softc {
int sc_nhosts;
u_int sc_flags;
+ bus_dma_tag_t sc_dmat;
+
int (*sc_card_detect)(struct sdhc_softc *);
};
diff --git a/sys/dev/sdmmc/sdmmc.c b/sys/dev/sdmmc/sdmmc.c
index 2adfce82d69..4ba2b65e1e3 100644
--- a/sys/dev/sdmmc/sdmmc.c
+++ b/sys/dev/sdmmc/sdmmc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmc.c,v 1.39 2016/03/19 11:41:56 mpi Exp $ */
+/* $OpenBSD: sdmmc.c,v 1.40 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -97,15 +97,26 @@ sdmmc_attach(struct device *parent, struct device *self, void *aux)
{
struct sdmmc_softc *sc = (struct sdmmc_softc *)self;
struct sdmmcbus_attach_args *saa = aux;
+ int error;
printf("\n");
sc->sct = saa->sct;
sc->sch = saa->sch;
+ sc->sc_dmat = saa->dmat;
sc->sc_flags = saa->flags;
sc->sc_caps = saa->caps;
sc->sc_max_xfer = saa->max_xfer;
+ if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+ error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SDMMC_MAXNSEGS,
+ MAXPHYS, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &sc->sc_dmap);
+ if (error) {
+ printf("%s: can't create DMA map\n", DEVNAME(sc));
+ return;
+ }
+ }
+
SIMPLEQ_INIT(&sc->sf_head);
TAILQ_INIT(&sc->sc_tskq);
TAILQ_INIT(&sc->sc_intrq);
@@ -138,6 +149,10 @@ sdmmc_detach(struct device *self, int flags)
wakeup(&sc->sc_tskq);
tsleep(sc, PWAIT, "mmcdie", 0);
}
+
+ if (sc->sc_dmap)
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
+
return 0;
}
diff --git a/sys/dev/sdmmc/sdmmc_mem.c b/sys/dev/sdmmc/sdmmc_mem.c
index da2d4c042a0..188d3392d5b 100644
--- a/sys/dev/sdmmc/sdmmc_mem.c
+++ b/sys/dev/sdmmc/sdmmc_mem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmc_mem.c,v 1.22 2015/11/08 12:10:27 jsg Exp $ */
+/* $OpenBSD: sdmmc_mem.c,v 1.23 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -44,12 +44,12 @@ 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 *, int, u_char *,
- size_t);
+int sdmmc_mem_read_block_subr(struct sdmmc_function *, bus_dmamap_t,
+ 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 *, int, u_char *,
- size_t);
+int sdmmc_mem_write_block_subr(struct sdmmc_function *, bus_dmamap_t,
+ int, u_char *, size_t);
#ifdef SDMMC_DEBUG
#define DPRINTF(s) printf s
@@ -566,8 +566,8 @@ sdmmc_mem_set_blocklen(struct sdmmc_softc *sc, struct sdmmc_function *sf)
}
int
-sdmmc_mem_read_block_subr(struct sdmmc_function *sf, int blkno, u_char *data,
- size_t datalen)
+sdmmc_mem_read_block_subr(struct sdmmc_function *sf, bus_dmamap_t dmap,
+ int blkno, u_char *data, size_t datalen)
{
struct sdmmc_softc *sc = sf->sc;
struct sdmmc_command cmd;
@@ -588,6 +588,7 @@ sdmmc_mem_read_block_subr(struct sdmmc_function *sf, int blkno, u_char *data,
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)
@@ -627,8 +628,8 @@ 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, blkno + i, data + i *
- sf->csd.sector_size, sf->csd.sector_size);
+ error = sdmmc_mem_read_block_subr(sf, NULL, blkno + i,
+ data + i * sf->csd.sector_size, sf->csd.sector_size);
if (error)
break;
}
@@ -647,17 +648,42 @@ sdmmc_mem_read_block(struct sdmmc_function *sf, int blkno, u_char *data,
if (ISSET(sc->sc_caps, SMC_CAPS_SINGLE_ONLY)) {
error = sdmmc_mem_single_read_block(sf, blkno, data, datalen);
- } else {
- error = sdmmc_mem_read_block_subr(sf, blkno, data, datalen);
+ 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);
+
+out:
rw_exit(&sc->sc_lock);
return (error);
}
int
-sdmmc_mem_write_block_subr(struct sdmmc_function *sf, int blkno, u_char *data,
- size_t datalen)
+sdmmc_mem_write_block_subr(struct sdmmc_function *sf, bus_dmamap_t dmap,
+ int blkno, u_char *data, size_t datalen)
{
struct sdmmc_softc *sc = sf->sc;
struct sdmmc_command cmd;
@@ -677,6 +703,7 @@ sdmmc_mem_write_block_subr(struct sdmmc_function *sf, int blkno, u_char *data,
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)
@@ -715,8 +742,8 @@ 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, blkno + i, data + i *
- sf->csd.sector_size, sf->csd.sector_size);
+ error = sdmmc_mem_write_block_subr(sf, NULL, blkno + i,
+ data + i * sf->csd.sector_size, sf->csd.sector_size);
if (error)
break;
}
@@ -735,10 +762,35 @@ sdmmc_mem_write_block(struct sdmmc_function *sf, int blkno, u_char *data,
if (ISSET(sc->sc_caps, SMC_CAPS_SINGLE_ONLY)) {
error = sdmmc_mem_single_write_block(sf, blkno, data, datalen);
- } else {
- error = sdmmc_mem_write_block_subr(sf, blkno, data, datalen);
+ 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,
+ 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);
return (error);
}
diff --git a/sys/dev/sdmmc/sdmmcchip.h b/sys/dev/sdmmc/sdmmcchip.h
index 14c772fafb1..4b7eedd5296 100644
--- a/sys/dev/sdmmc/sdmmcchip.h
+++ b/sys/dev/sdmmc/sdmmcchip.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmcchip.h,v 1.5 2013/09/12 11:54:04 rapha Exp $ */
+/* $OpenBSD: sdmmcchip.h,v 1.6 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -19,6 +19,8 @@
#ifndef _SDMMC_CHIP_H_
#define _SDMMC_CHIP_H_
+#include <machine/bus.h>
+
struct sdmmc_command;
typedef struct sdmmc_chip_functions *sdmmc_chipset_tag_t;
@@ -77,6 +79,7 @@ struct sdmmcbus_attach_args {
const char *saa_busname;
sdmmc_chipset_tag_t sct;
sdmmc_chipset_handle_t sch;
+ bus_dma_tag_t dmat;
int flags;
int caps;
long max_xfer;
diff --git a/sys/dev/sdmmc/sdmmcvar.h b/sys/dev/sdmmc/sdmmcvar.h
index 1da8de541fa..d2d929ed6da 100644
--- a/sys/dev/sdmmc/sdmmcvar.h
+++ b/sys/dev/sdmmc/sdmmcvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdmmcvar.h,v 1.22 2013/09/12 11:54:04 rapha Exp $ */
+/* $OpenBSD: sdmmcvar.h,v 1.23 2016/04/30 11:32:23 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -22,6 +22,8 @@
#include <sys/queue.h>
#include <sys/rwlock.h>
+#include <machine/bus.h>
+
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
@@ -72,6 +74,7 @@ struct sdmmc_command {
u_int16_t c_opcode; /* SD or MMC command index */
u_int32_t c_arg; /* SD/MMC command argument */
sdmmc_response c_resp; /* response buffer */
+ bus_dmamap_t c_dmamap;
void *c_data; /* buffer to send or read into */
int c_datalen; /* length of data buffer */
int c_blklen; /* block length */
@@ -156,6 +159,11 @@ struct sdmmc_softc {
#define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
sdmmc_chipset_tag_t sct; /* host controller chipset tag */
sdmmc_chipset_handle_t sch; /* host controller chipset handle */
+
+ bus_dma_tag_t sc_dmat;
+ bus_dmamap_t sc_dmap;
+#define SDMMC_MAXNSEGS ((MAXPHYS / PAGE_SIZE) + 1)
+
int sc_flags;
#define SMF_SD_MODE 0x0001 /* host in SD mode (MMC otherwise) */
#define SMF_IO_MODE 0x0002 /* host in I/O mode (SD mode only) */