diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/acpi/sdhc_acpi.c | 7 | ||||
-rw-r--r-- | sys/dev/pci/sdhc_pci.c | 3 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdhc.c | 111 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdhcreg.h | 57 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdhcvar.h | 4 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc.c | 17 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_mem.c | 86 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcchip.h | 5 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcvar.h | 10 |
9 files changed, 267 insertions, 33 deletions
diff --git a/sys/dev/acpi/sdhc_acpi.c b/sys/dev/acpi/sdhc_acpi.c index 421c73fd716..f141cd628fd 100644 --- a/sys/dev/acpi/sdhc_acpi.c +++ b/sys/dev/acpi/sdhc_acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdhc_acpi.c,v 1.7 2016/04/26 19:10:10 kettenis Exp $ */ +/* $OpenBSD: sdhc_acpi.c,v 1.8 2016/04/30 11:32:23 kettenis Exp $ */ /* * Copyright (c) 2016 Mark Kettenis * @@ -29,6 +29,8 @@ #include <dev/sdmmc/sdhcvar.h> #include <dev/sdmmc/sdmmcvar.h> +extern struct bus_dma_tag pci_bus_dma_tag; + struct sdhc_acpi_softc { struct sdhc_softc sc; struct acpi_softc *sc_acpi; @@ -134,7 +136,8 @@ sdhc_acpi_attach(struct device *parent, struct device *self, void *aux) printf("\n"); sc->sc.sc_host = &sc->sc_host; - sdhc_host_found(&sc->sc, sc->sc_memt, sc->sc_memh, sc->sc_size, 0, 0); + sc->sc.sc_dmat = &pci_bus_dma_tag; + sdhc_host_found(&sc->sc, sc->sc_memt, sc->sc_memh, sc->sc_size, 1, 0); } int diff --git a/sys/dev/pci/sdhc_pci.c b/sys/dev/pci/sdhc_pci.c index 4f5b8c19e10..d1b6688f573 100644 --- a/sys/dev/pci/sdhc_pci.c +++ b/sys/dev/pci/sdhc_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdhc_pci.c,v 1.19 2015/11/24 19:38:01 kettenis Exp $ */ +/* $OpenBSD: sdhc_pci.c,v 1.20 2016/04/30 11:32:23 kettenis Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -149,6 +149,7 @@ sdhc_pci_attach(struct device *parent, struct device *self, void *aux) /* Enable use of DMA if supported by the interface. */ usedma = PCI_INTERFACE(pa->pa_class) == SDHC_PCI_INTERFACE_DMA; + sc->sc.sc_dmat = pa->pa_dmat; /* * Map and attach all hosts supported by the host controller. 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) */ |