Module Name: src Committed By: jmcneill Date: Sun Apr 19 23:12:21 UTC 2015
Modified Files: src/sys/arch/arm/amlogic: amlogic_sdio.c Log Message: Like SDHC, SDIO also doesn't support SG DMA. Remove the DMA capability flag and do transfers through a MAXPHYS-sized buffer instead. This lets us do larger transfers and even with the memcpy, still a significant win for performance. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/amlogic/amlogic_sdio.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/arch/arm/amlogic/amlogic_sdio.c diff -u src/sys/arch/arm/amlogic/amlogic_sdio.c:1.1 src/sys/arch/arm/amlogic/amlogic_sdio.c:1.2 --- src/sys/arch/arm/amlogic/amlogic_sdio.c:1.1 Sun Apr 19 18:54:52 2015 +++ src/sys/arch/arm/amlogic/amlogic_sdio.c Sun Apr 19 23:12:21 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: amlogic_sdio.c,v 1.1 2015/04/19 18:54:52 jmcneill Exp $ */ +/* $NetBSD: amlogic_sdio.c,v 1.2 2015/04/19 23:12:21 jmcneill Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -29,7 +29,7 @@ #include "locators.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: amlogic_sdio.c,v 1.1 2015/04/19 18:54:52 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: amlogic_sdio.c,v 1.2 2015/04/19 23:12:21 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -68,6 +68,10 @@ struct amlogic_sdio_softc { kcondvar_t sc_intr_cv; uint32_t sc_intr_irqs; + + bus_dmamap_t sc_dmamap; + bus_dma_segment_t sc_segs[1]; + void *sc_bbuf; }; CFATTACH_DECL_NEW(amlogic_sdio, sizeof(struct amlogic_sdio_softc), @@ -90,6 +94,8 @@ static void amlogic_sdio_card_intr_ack(s static int amlogic_sdio_set_clock(struct amlogic_sdio_softc *, u_int); static int amlogic_sdio_wait_irqs(struct amlogic_sdio_softc *, uint32_t, int); +static void amlogic_sdio_dmainit(struct amlogic_sdio_softc *); + static struct sdmmc_chip_functions amlogic_sdio_chip_functions = { .host_reset = amlogic_sdio_host_reset, .host_ocr = amlogic_sdio_host_ocr, @@ -159,6 +165,8 @@ amlogic_sdio_attach(device_t parent, dev sc->sc_bus_freq = amlogic_get_rate_clk81(); aprint_debug_dev(self, "CLK81 rate: %u Hz\n", sc->sc_bus_freq); + amlogic_sdio_dmainit(sc); + config_interrupts(self, amlogic_sdio_attach_i); } @@ -179,10 +187,10 @@ amlogic_sdio_attach_i(device_t self) saa.saa_sch = sc; saa.saa_clkmin = 400; saa.saa_clkmax = 50000; + /* Do not advertise DMA capabilities, we handle DMA ourselves */ saa.saa_caps = SMC_CAPS_4BIT_MODE| SMC_CAPS_SD_HIGHSPEED| - SMC_CAPS_MMC_HIGHSPEED| - SMC_CAPS_DMA; + SMC_CAPS_MMC_HIGHSPEED; sc->sc_sdmmc_dev = config_found(self, &saa, NULL); } @@ -193,13 +201,45 @@ amlogic_sdio_intr(void *priv) struct amlogic_sdio_softc *sc = priv; mutex_enter(&sc->sc_intr_lock); - sc->sc_intr_irqs |= SDIO_READ(sc, SDIO_IRQS_REG); - cv_broadcast(&sc->sc_intr_cv); + const u_int irqs = SDIO_READ(sc, SDIO_IRQS_REG); + if (irqs & SDIO_IRQS_CLEAR) { + SDIO_WRITE(sc, SDIO_IRQS_REG, irqs); + sc->sc_intr_irqs |= irqs; + cv_broadcast(&sc->sc_intr_cv); + } mutex_exit(&sc->sc_intr_lock); return 1; } +static void +amlogic_sdio_dmainit(struct amlogic_sdio_softc *sc) +{ + int error, rseg; + + error = bus_dmamem_alloc(sc->sc_dmat, MAXPHYS, PAGE_SIZE, MAXPHYS, + sc->sc_segs, 1, &rseg, BUS_DMA_WAITOK); + if (error) { + device_printf(sc->sc_dev, "bus_dmamem_alloc failed\n"); + return; + } + KASSERT(rseg == 1); + + error = bus_dmamem_map(sc->sc_dmat, sc->sc_segs, rseg, MAXPHYS, + &sc->sc_bbuf, BUS_DMA_WAITOK); + if (error) { + device_printf(sc->sc_dev, "bus_dmamem_map failed\n"); + return; + } + + error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, 1, MAXPHYS, 0, + BUS_DMA_WAITOK, &sc->sc_dmamap); + if (error) { + device_printf(sc->sc_dev, "bus_dmamap_create failed\n"); + return; + } +} + static int amlogic_sdio_set_clock(struct amlogic_sdio_softc *sc, u_int freq) { @@ -337,6 +377,7 @@ amlogic_sdio_exec_command(sdmmc_chipset_ { struct amlogic_sdio_softc *sc = sch; uint32_t send, ext, mult, addr; + bool use_bbuf = false; int i; KASSERT(cmd->c_blklen <= 512); @@ -386,10 +427,22 @@ amlogic_sdio_exec_command(sdmmc_chipset_ send |= SDIO_SEND_COMMAND_HAS_DATA; } - KASSERT(cmd->c_dmamap->dm_nsegs == 1); - KASSERT(cmd->c_dmamap->dm_segs[0].ds_len >= cmd->c_datalen); - - addr = cmd->c_dmamap->dm_segs[0].ds_addr; + cmd->c_error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, + sc->sc_bbuf, MAXPHYS, NULL, BUS_DMA_WAITOK); + if (cmd->c_error) { + device_printf(sc->sc_dev, "bus_dmamap_load failed\n"); + goto done; + } + if (ISSET(cmd->c_flags, SCF_CMD_READ)) { + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0, + MAXPHYS, BUS_DMASYNC_PREREAD); + } else { + memcpy(sc->sc_bbuf, cmd->c_data, cmd->c_datalen); + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0, + MAXPHYS, BUS_DMASYNC_PREWRITE); + } + addr = sc->sc_dmamap->dm_segs[0].ds_addr; + use_bbuf = true; } send |= __SHIFTIN(cmd->c_opcode | 0x40, SDIO_SEND_COMMAND_INDEX); @@ -411,18 +464,17 @@ amlogic_sdio_exec_command(sdmmc_chipset_ if (cmd->c_error) { goto done; } - SDIO_WRITE(sc, SDIO_IRQS_REG, SDIO_IRQS_CLEAR); if (SDIO_READ(sc, SDIO_IRQS_REG) & SDIO_IRQS_CMD_BUSY) { int retry; - for (retry = 20000; retry > 0; retry--) { + for (retry = 10000; retry > 0; retry--) { const uint32_t irqs = SDIO_READ(sc, SDIO_IRQS_REG); if ((irqs & SDIO_IRQS_CMD_BUSY) == 0) break; delay(100); } if (retry == 0) { - device_printf(sc->sc_dev, + aprint_debug_dev(sc->sc_dev, "busy timeout, opcode %d flags %#x datalen %d\n", cmd->c_opcode, cmd->c_flags, cmd->c_datalen); cmd->c_error = ETIMEDOUT; @@ -463,6 +515,19 @@ amlogic_sdio_exec_command(sdmmc_chipset_ } done: + if (use_bbuf) { + if (ISSET(cmd->c_flags, SCF_CMD_READ)) { + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0, + MAXPHYS, BUS_DMASYNC_POSTREAD); + } else { + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0, + MAXPHYS, BUS_DMASYNC_POSTWRITE); + } + bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap); + if (ISSET(cmd->c_flags, SCF_CMD_READ)) { + memcpy(cmd->c_data, sc->sc_bbuf, cmd->c_datalen); + } + } cmd->c_flags |= SCF_ITSDONE; SDIO_WRITE(sc, SDIO_IRQC_REG, 0);