Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/amlogic The Amlogic SDHC controller doesn't sup...



details:   https://anonhg.NetBSD.org/src/rev/19a3a03462e9
branches:  trunk
changeset: 807697:19a3a03462e9
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sun Apr 19 21:23:01 2015 +0000

description:
The Amlogic SDHC controller doesn't support SG DMA. When we advertise
DMA but not SG DMA support, the sdmmc layer breaks up transfers into
multiple PAGE_SIZE (8KB here) transfers.

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.

Before: 134217728 bytes transferred in 15.301 secs (8771827 bytes/sec)
After:  134217728 bytes transferred in 8.834 secs (15193313 bytes/sec)

diffstat:

 sys/arch/arm/amlogic/amlogic_sdhc.c |  79 +++++++++++++++++++++++++++++++++---
 1 files changed, 72 insertions(+), 7 deletions(-)

diffs (153 lines):

diff -r 47b03c696808 -r 19a3a03462e9 sys/arch/arm/amlogic/amlogic_sdhc.c
--- a/sys/arch/arm/amlogic/amlogic_sdhc.c       Sun Apr 19 21:09:02 2015 +0000
+++ b/sys/arch/arm/amlogic/amlogic_sdhc.c       Sun Apr 19 21:23:01 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: amlogic_sdhc.c,v 1.4 2015/04/17 18:36:15 jmcneill Exp $ */
+/* $NetBSD: amlogic_sdhc.c,v 1.5 2015/04/19 21:23:01 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
 #include "locators.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: amlogic_sdhc.c,v 1.4 2015/04/17 18:36:15 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: amlogic_sdhc.c,v 1.5 2015/04/19 21:23:01 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -64,6 +64,10 @@
        kcondvar_t              sc_intr_cv;
 
        uint32_t                sc_intr_ista;
+
+       bus_dmamap_t            sc_dmamap;
+       bus_dma_segment_t       sc_segs[1];
+       void                    *sc_bbuf;
 };
 
 CFATTACH_DECL_NEW(amlogic_sdhc, sizeof(struct amlogic_sdhc_softc),
@@ -87,6 +91,8 @@
 static int     amlogic_sdhc_wait_idle(struct amlogic_sdhc_softc *);
 static int     amlogic_sdhc_wait_ista(struct amlogic_sdhc_softc *, uint32_t, int);
 
+static void    amlogic_sdhc_dmainit(struct amlogic_sdhc_softc *);
+
 static struct sdmmc_chip_functions amlogic_sdhc_chip_functions = {
        .host_reset = amlogic_sdhc_host_reset,
        .host_ocr = amlogic_sdhc_host_ocr,
@@ -152,6 +158,8 @@
        }
        aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr);
 
+       amlogic_sdhc_dmainit(sc);
+
        config_interrupts(self, amlogic_sdhc_attach_i);
 }
 
@@ -171,12 +179,12 @@
        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_8BIT_MODE|
                       SMC_CAPS_SD_HIGHSPEED|
                       SMC_CAPS_MMC_HIGHSPEED|
-                      SMC_CAPS_AUTO_STOP|
-                      SMC_CAPS_DMA;
+                      SMC_CAPS_AUTO_STOP;
 
        sc->sc_sdmmc_dev = config_found(self, &saa, NULL);
 }
@@ -205,6 +213,35 @@
        return 1;
 }
 
+static void
+amlogic_sdhc_dmainit(struct amlogic_sdhc_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: %d\n", error);
+               return;
+       }
+       KASSERT(rseg == 1);
+
+       error = bus_dmamem_map(sc->sc_dmat, sc->sc_segs, rseg, PAGE_SIZE,
+           &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_sdhc_set_clock(struct amlogic_sdhc_softc *sc, u_int freq)
 {
@@ -437,6 +474,7 @@
 {
        struct amlogic_sdhc_softc *sc = sch;
        uint32_t cmdval = 0, cntl, srst, pdma, ictl;
+       bool use_bbuf = false;
        int i;
 
        KASSERT(cmd->c_blklen <= 512);
@@ -516,9 +554,22 @@
        }
 
        if (cmd->c_datalen > 0) {
-               KASSERT(cmd->c_dmamap->dm_nsegs == 1);
-               KASSERT(cmd->c_dmamap->dm_segs[0].ds_len >= cmd->c_datalen);
-               SDHC_WRITE(sc, SD_ADDR_REG, 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);
+               }
+               SDHC_WRITE(sc, SD_ADDR_REG, sc->sc_dmamap->dm_segs[0].ds_addr);
+               use_bbuf = true;
        }
 
        cmd->c_resid = cmd->c_datalen;
@@ -582,6 +633,20 @@
        }
 
 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;
 
        SDHC_WRITE(sc, SD_ISTA_REG, SD_INT_CLEAR);



Home | Main Index | Thread Index | Old Index