Source-Changes-HG archive

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

[src/netbsd-7]: src/sys/arch/arm/omap Pull up following revision(s) (requeste...



details:   https://anonhg.NetBSD.org/src/rev/53d8b1c57610
branches:  netbsd-7
changeset: 799711:53d8b1c57610
user:      riz <riz%NetBSD.org@localhost>
date:      Tue Nov 17 19:21:14 2015 +0000

description:
Pull up following revision(s) (requested by jmcneill in ticket #1017):
        sys/arch/arm/omap/omap3_sdhc.c: revision 1.18
AM335x EDMA3 has an alignment restriction for both SAM and DAM in constant
addressing mode. In these cases, the physical address must be aligned to
256-bits. To handle this, pre-allocate a MAXPHYS sized bounce buffer and
use it for unaligned transfers.
Fixes &quot;edma errint!&quot; problem mentioned in port-arm/50288.

diffstat:

 sys/arch/arm/omap/omap3_sdhc.c |  126 ++++++++++++++++++++++++++++++++++++----
 1 files changed, 112 insertions(+), 14 deletions(-)

diffs (218 lines):

diff -r 5790ef7e9b35 -r 53d8b1c57610 sys/arch/arm/omap/omap3_sdhc.c
--- a/sys/arch/arm/omap/omap3_sdhc.c    Tue Nov 17 19:18:19 2015 +0000
+++ b/sys/arch/arm/omap/omap3_sdhc.c    Tue Nov 17 19:21:14 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: omap3_sdhc.c,v 1.14.4.2 2015/11/08 01:22:54 riz Exp $  */
+/*     $NetBSD: omap3_sdhc.c,v 1.14.4.3 2015/11/17 19:21:14 riz Exp $  */
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: omap3_sdhc.c,v 1.14.4.2 2015/11/08 01:22:54 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: omap3_sdhc.c,v 1.14.4.3 2015/11/17 19:21:14 riz Exp $");
 
 #include "opt_omap.h"
 #include "edma.h"
@@ -109,13 +109,17 @@
        kcondvar_t              sc_edma_cv;
        bus_addr_t              sc_edma_fifo;
        bool                    sc_edma_pending;
+       bus_dmamap_t            sc_edma_dmamap;
+       bus_dma_segment_t       sc_edma_segs[1];
+       void                    *sc_edma_bbuf;
 #endif
 };
 
 #if NEDMA > 0
-static void obiosdhc_edma_init(struct obiosdhc_softc *, unsigned int);
+static int obiosdhc_edma_init(struct obiosdhc_softc *, unsigned int);
 static int obiosdhc_edma_xfer_data(struct sdhc_softc *, struct sdmmc_command *);
 static void obiosdhc_edma_done(void *);
+static int obiosdhc_edma_transfer(struct sdhc_softc *, struct sdmmc_command *);
 #endif
 
 #ifdef TI_AM335X
@@ -252,11 +256,13 @@
 
 #if NEDMA > 0
        if (oa->obio_edmabase != -1) {
+               if (obiosdhc_edma_init(sc, oa->obio_edmabase) != 0)
+                       goto no_dma;
+
                mutex_init(&sc->sc_edma_lock, MUTEX_DEFAULT, IPL_SCHED);
                cv_init(&sc->sc_edma_cv, "sdhcedma");
                sc->sc_edma_fifo = oa->obio_addr +
                    OMAP3_SDMMC_SDHC_OFFSET + SDHC_DATA;
-               obiosdhc_edma_init(sc, oa->obio_edmabase);
                sc->sc.sc_flags |= SDHC_FLAG_USE_DMA;
                sc->sc.sc_flags |= SDHC_FLAG_EXTERNAL_DMA;
                sc->sc.sc_flags |= SDHC_FLAG_EXTDMA_DMAEN;
@@ -264,6 +270,7 @@
                sc->sc.sc_vendor_transfer_data_dma = obiosdhc_edma_xfer_data;
                transfer_mode = "EDMA";
        }
+no_dma:
 #endif
 
        aprint_naive("\n");
@@ -494,10 +501,10 @@
 }
 
 #if NEDMA > 0
-static void
+static int
 obiosdhc_edma_init(struct obiosdhc_softc *sc, unsigned int edmabase)
 {
-       int i;
+       int i, error, rseg;
 
        /* Request tx and rx DMA channels */
        sc->sc_edma_tx = edma_channel_alloc(EDMA_TYPE_DMA, edmabase + 0,
@@ -521,18 +528,98 @@
                KASSERT(sc->sc_edma_param_rx[i] != 0xffff);
        }
 
-       return;
+       /* Setup bounce buffer */
+       error = bus_dmamem_alloc(sc->sc.sc_dmat, MAXPHYS, 32, MAXPHYS,
+           sc->sc_edma_segs, 1, &rseg, BUS_DMA_WAITOK);
+       if (error) {
+               aprint_error_dev(sc->sc.sc_dev,
+                   "couldn't allocate dmamem: %d\n", error);
+               return error;
+       }
+       KASSERT(rseg == 1);
+       error = bus_dmamem_map(sc->sc.sc_dmat, sc->sc_edma_segs, rseg, MAXPHYS,
+           &sc->sc_edma_bbuf, BUS_DMA_WAITOK);
+       if (error) {
+               aprint_error_dev(sc->sc.sc_dev, "couldn't map dmamem: %d\n",
+                   error);
+               return error;
+       }
+       error = bus_dmamap_create(sc->sc.sc_dmat, MAXPHYS, 1, MAXPHYS, 0,
+           BUS_DMA_WAITOK, &sc->sc_edma_dmamap);
+       if (error) {
+               aprint_error_dev(sc->sc.sc_dev, "couldn't create dmamap: %d\n",
+                   error);
+               return error;
+       }
+
+       return error;
 }
 
 static int
 obiosdhc_edma_xfer_data(struct sdhc_softc *sdhc_sc, struct sdmmc_command *cmd)
 {
        struct obiosdhc_softc *sc = device_private(sdhc_sc->sc_dev);
+       const bus_dmamap_t map = cmd->c_dmamap;
+       int seg, error;
+       bool bounce;
+
+       for (bounce = false, seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) {
+               if ((cmd->c_dmamap->dm_segs[seg].ds_addr & 0x1f) != 0) {
+                       bounce = true;
+                       break;
+               }
+       }
+
+       if (bounce) {
+               error = bus_dmamap_load(sc->sc.sc_dmat, sc->sc_edma_dmamap,
+                   sc->sc_edma_bbuf, MAXPHYS, NULL, BUS_DMA_WAITOK);
+               if (error) {
+                       device_printf(sc->sc.sc_dev,
+                           "[bounce] bus_dmamap_load failed: %d\n", error);
+                       return error;
+               }
+               if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
+                       bus_dmamap_sync(sc->sc.sc_dmat, sc->sc_edma_dmamap, 0,
+                           MAXPHYS, BUS_DMASYNC_PREREAD);
+               } else {
+                       memcpy(sc->sc_edma_bbuf, cmd->c_data, cmd->c_datalen);
+                       bus_dmamap_sync(sc->sc.sc_dmat, sc->sc_edma_dmamap, 0,
+                           MAXPHYS, BUS_DMASYNC_PREWRITE);
+               }
+
+               cmd->c_dmamap = sc->sc_edma_dmamap;
+       }
+
+       error = obiosdhc_edma_transfer(sdhc_sc, cmd);
+
+       if (bounce) {
+               if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
+                       bus_dmamap_sync(sc->sc.sc_dmat, sc->sc_edma_dmamap, 0,
+                           MAXPHYS, BUS_DMASYNC_POSTREAD);
+               } else {
+                       bus_dmamap_sync(sc->sc.sc_dmat, sc->sc_edma_dmamap, 0,
+                           MAXPHYS, BUS_DMASYNC_POSTWRITE);
+               }
+               bus_dmamap_unload(sc->sc.sc_dmat, sc->sc_edma_dmamap);
+               if (ISSET(cmd->c_flags, SCF_CMD_READ) && error == 0) {
+                       memcpy(cmd->c_data, sc->sc_edma_bbuf, cmd->c_datalen);
+               }
+
+               cmd->c_dmamap = map;
+       }
+
+       return error;
+}
+
+static int
+obiosdhc_edma_transfer(struct sdhc_softc *sdhc_sc, struct sdmmc_command *cmd)
+{
+       struct obiosdhc_softc *sc = device_private(sdhc_sc->sc_dev);
        struct edma_channel *edma;
        uint16_t *edma_param;
        struct edma_param ep;
        size_t seg;
-       int error;
+       int error, resid = cmd->c_datalen;
        int blksize = MIN(cmd->c_datalen, cmd->c_blklen);
 
        edma = ISSET(cmd->c_flags, SCF_CMD_READ) ?
@@ -548,6 +635,13 @@
        }
 
        for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) {
+               KASSERT(resid > 0);
+               const int xferlen = min(resid,
+                   cmd->c_dmamap->dm_segs[seg].ds_len);
+               KASSERT(xferlen == cmd->c_dmamap->dm_segs[seg].ds_len ||
+                       seg == cmd->c_dmamap->dm_nsegs - 1);
+               resid -= xferlen;
+               KASSERT((xferlen & 0x3) == 0);
                ep.ep_opt = __SHIFTIN(2, EDMA_PARAM_OPT_FWID) /* 32-bit */;
                ep.ep_opt |= __SHIFTIN(edma_channel_index(edma),
                                       EDMA_PARAM_OPT_TCC);
@@ -567,7 +661,13 @@
                        ep.ep_dst = sc->sc_edma_fifo;
                }
 
-               KASSERT(cmd->c_dmamap->dm_segs[seg].ds_len <= 65536 * 4);
+               KASSERT(xferlen <= 65536 * 4);
+
+               /*
+                * In constant addressing mode, the address must be aligned
+                * to 256-bits.
+                */
+               KASSERT((cmd->c_dmamap->dm_segs[seg].ds_addr & 0x1f) == 0);
 
                 /*
                 * For unknown reason, the A-DMA transfers never completes for
@@ -576,11 +676,9 @@
                 */
                ep.ep_bcntrld = 0;      /* not used for AB-synchronous mode */
                ep.ep_opt |= EDMA_PARAM_OPT_SYNCDIM;
-               ep.ep_acnt = min(cmd->c_dmamap->dm_segs[seg].ds_len, 64);
-               ep.ep_bcnt = min(cmd->c_dmamap->dm_segs[seg].ds_len, blksize) /
-                            ep.ep_acnt;
-               ep.ep_ccnt = cmd->c_dmamap->dm_segs[seg].ds_len /
-                            (ep.ep_acnt * ep.ep_bcnt);
+               ep.ep_acnt = min(xferlen, 64);
+               ep.ep_bcnt = min(xferlen, blksize) / ep.ep_acnt;
+               ep.ep_ccnt = xferlen / (ep.ep_acnt * ep.ep_bcnt);
                ep.ep_srcbidx = ep.ep_dstbidx = 0;
                ep.ep_srccidx = ep.ep_dstcidx = 0;
                if (ISSET(cmd->c_flags, SCF_CMD_READ)) {



Home | Main Index | Thread Index | Old Index