Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/arm/sunxi Implement support for multi-segment trans...



details:   https://anonhg.NetBSD.org/src/rev/6ce424784de8
branches:  trunk
changeset: 449290:6ce424784de8
user:      jakllsch <jakllsch%NetBSD.org@localhost>
date:      Sat Mar 02 03:21:17 2019 +0000

description:
Implement support for multi-segment transfers.
Make more efficent use of DMA descriptor table memory.

diffstat:

 sys/arch/arm/sunxi/sun6i_dma.c |  106 +++++++++++++++++++++++-----------------
 1 files changed, 61 insertions(+), 45 deletions(-)

diffs (186 lines):

diff -r 08c200335c08 -r 6ce424784de8 sys/arch/arm/sunxi/sun6i_dma.c
--- a/sys/arch/arm/sunxi/sun6i_dma.c    Sat Mar 02 01:01:20 2019 +0000
+++ b/sys/arch/arm/sunxi/sun6i_dma.c    Sat Mar 02 03:21:17 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sun6i_dma.c,v 1.6 2018/11/17 20:35:41 jmcneill Exp $ */
+/* $NetBSD: sun6i_dma.c,v 1.7 2019/03/02 03:21:17 jakllsch Exp $ */
 
 /*-
  * Copyright (c) 2014-2017 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
 #include "opt_ddb.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sun6i_dma.c,v 1.6 2018/11/17 20:35:41 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sun6i_dma.c,v 1.7 2019/03/02 03:21:17 jakllsch Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -140,11 +140,7 @@
        void                    (*ch_callback)(void *);
        void                    *ch_callbackarg;
        u_int                   ch_portid;
-
-       bus_dma_segment_t       ch_dmasegs[1];
-       bus_dmamap_t            ch_dmamap;
        void                    *ch_dmadesc;
-       bus_size_t              ch_dmadesclen;
 };
 
 struct sun6idma_softc {
@@ -161,6 +157,11 @@
 
        struct sun6idma_channel *sc_chan;
        u_int                   sc_nchan;
+       u_int                   sc_ndesc_ch;
+
+       bus_dma_segment_t       sc_dmasegs[1];
+       bus_dmamap_t            sc_dmamap;
+       void                    *sc_dmadescs;
 };
 
 #define DMA_READ(sc, reg)              \
@@ -168,6 +169,14 @@
 #define DMA_WRITE(sc, reg, val)                \
     bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
 
+#define DESC_NUM                       ((MAXPHYS / MIN_PAGE_SIZE + 1) + 1)
+#define DESC_LEN(n)                    \
+    (sizeof(struct sun6idma_desc) * (n))
+#define DESC_OFFS(ch, n)               \
+    ((ch) * roundup2(DESC_LEN(DESC_NUM), COHERENCY_UNIT) + DESC_LEN(n))
+#define DESC_ADDR(sc, chp, n)          \
+    ((sc)->sc_dmamap->dm_segs[0].ds_addr + DESC_OFFS((chp)->ch_index, (n)))
+
 static void *
 sun6idma_acquire(device_t dev, const void *data, size_t len,
     void (*cb)(void *), void *cbarg)
@@ -247,7 +256,7 @@
        uint32_t src, dst, len, cfg, mem_cfg, dev_cfg;
        uint32_t mem_width, dev_width, mem_burst, dev_burst;
 
-       if (req->dreq_nsegs != 1)
+       if (req->dreq_nsegs > sc->sc_ndesc_ch)
                return EINVAL;
 
        mem_width = DMA_CFG_DATA_WIDTH(req->dreq_mem_opt.opt_bus_width);
@@ -264,29 +273,34 @@
            __SHIFTIN(DMA_CFG_ADDR_MODE_IO, DMA_CFG_SRC_ADDR_MODE) |
            __SHIFTIN(ch->ch_portid, DMA_CFG_SRC_DRQ_TYPE);
 
-       if (req->dreq_dir == FDT_DMA_READ) {
-               src = req->dreq_dev_phys;
-               dst = req->dreq_segs[0].ds_addr;
-               cfg = mem_cfg << 16 | dev_cfg;
-       } else {
-               src = req->dreq_segs[0].ds_addr;
-               dst = req->dreq_dev_phys;
-               cfg = dev_cfg << 16 | mem_cfg;
+       for (size_t j = 0; j < req->dreq_nsegs; j++) {
+               if (req->dreq_dir == FDT_DMA_READ) {
+                       src = req->dreq_dev_phys;
+                       dst = req->dreq_segs[j].ds_addr;
+                       cfg = mem_cfg << 16 | dev_cfg;
+               } else {
+                       src = req->dreq_segs[j].ds_addr;
+                       dst = req->dreq_dev_phys;
+                       cfg = dev_cfg << 16 | mem_cfg;
+               }
+               len = req->dreq_segs[j].ds_len;
+
+               desc[j].dma_config = htole32(cfg);
+               desc[j].dma_srcaddr = htole32(src);
+               desc[j].dma_dstaddr = htole32(dst);
+               desc[j].dma_bcnt = htole32(len);
+               desc[j].dma_para = htole32(0);
+               if (j < req->dreq_nsegs - 1)
+                       desc[j].dma_next = htole32(DESC_ADDR(sc, ch, j + 1));
+               else
+                       desc[j].dma_next = htole32(DMA_NULL);
        }
-       len = req->dreq_segs[0].ds_len;
 
-       desc->dma_config = htole32(cfg);
-       desc->dma_srcaddr = htole32(src);
-       desc->dma_dstaddr = htole32(dst);
-       desc->dma_bcnt = htole32(len);
-       desc->dma_para = htole32(0);
-       desc->dma_next = htole32(DMA_NULL);
-
-       bus_dmamap_sync(sc->sc_dmat, ch->ch_dmamap, 0, ch->ch_dmadesclen,
-           BUS_DMASYNC_PREWRITE);
+       bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, DESC_OFFS(ch->ch_index, 0),
+           DESC_LEN(req->dreq_nsegs), BUS_DMASYNC_PREWRITE);
 
        DMA_WRITE(sc, DMA_START_ADDR_REG(ch->ch_index),
-           ch->ch_dmamap->dm_segs[0].ds_addr);
+           DESC_ADDR(sc, ch, 0));
        DMA_WRITE(sc, DMA_EN_REG(ch->ch_index), DMA_EN_EN);
 
        if ((DMA_READ(sc, DMA_EN_REG(ch->ch_index)) & DMA_EN_EN) == 0) {
@@ -360,7 +374,7 @@
        struct sun6idma_softc * const sc = device_private(self);
        struct fdt_attach_args * const faa = aux;
        const int phandle = faa->faa_phandle;
-       const size_t desclen = sizeof(struct sun6idma_desc);
+       size_t desclen;
        const struct sun6idma_config *conf;
        struct fdtbus_reset *rst;
        struct clk *clk;
@@ -406,6 +420,8 @@
        sc->sc_burst_mask = conf->burst_mask;
        sc->sc_nchan = conf->num_channels;
        sc->sc_chan = kmem_alloc(sizeof(*sc->sc_chan) * sc->sc_nchan, KM_SLEEP);
+       desclen = DESC_OFFS(sc->sc_nchan, 0);
+       sc->sc_ndesc_ch = DESC_OFFS(1, 0) / sizeof(struct sun6idma_desc);
 
        aprint_naive("\n");
        aprint_normal(": DMA controller (%u channels)\n", sc->sc_nchan);
@@ -415,29 +431,29 @@
        DMA_WRITE(sc, DMA_IRQ_PEND_REG0_REG, ~0);
        DMA_WRITE(sc, DMA_IRQ_PEND_REG1_REG, ~0);
 
+       error = bus_dmamem_alloc(sc->sc_dmat, desclen, 0, 0,
+           sc->sc_dmasegs, 1, &nsegs, BUS_DMA_WAITOK);
+       if (error)
+               panic("bus_dmamem_alloc failed: %d", error);
+       error = bus_dmamem_map(sc->sc_dmat, sc->sc_dmasegs, nsegs,
+           desclen, (void **)&sc->sc_dmadescs, BUS_DMA_WAITOK);
+       if (error)
+               panic("bus_dmamem_map failed: %d", error);
+       error = bus_dmamap_create(sc->sc_dmat, desclen, 1, desclen, 0,
+           BUS_DMA_WAITOK, &sc->sc_dmamap);
+       if (error)
+               panic("bus_dmamap_create failed: %d", error);
+       error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap,
+           sc->sc_dmadescs, desclen, NULL, BUS_DMA_WAITOK);
+       if (error)
+               panic("bus_dmamap_load failed: %d", error);
+
        for (index = 0; index < sc->sc_nchan; index++) {
                struct sun6idma_channel *ch = &sc->sc_chan[index];
                ch->ch_index = index;
+               ch->ch_dmadesc = (void *)((uintptr_t)sc->sc_dmadescs + DESC_OFFS(index, 0));
                ch->ch_callback = NULL;
                ch->ch_callbackarg = NULL;
-               ch->ch_dmadesclen = desclen;
-
-               error = bus_dmamem_alloc(sc->sc_dmat, desclen, 0, 0,
-                   ch->ch_dmasegs, 1, &nsegs, BUS_DMA_WAITOK);
-               if (error)
-                       panic("bus_dmamem_alloc failed: %d", error);
-               error = bus_dmamem_map(sc->sc_dmat, ch->ch_dmasegs, nsegs,
-                   desclen, &ch->ch_dmadesc, BUS_DMA_WAITOK);
-               if (error)
-                       panic("bus_dmamem_map failed: %d", error);
-               error = bus_dmamap_create(sc->sc_dmat, desclen, 1, desclen, 0,
-                   BUS_DMA_WAITOK, &ch->ch_dmamap);
-               if (error)
-                       panic("bus_dmamap_create failed: %d", error);
-               error = bus_dmamap_load(sc->sc_dmat, ch->ch_dmamap,
-                   ch->ch_dmadesc, desclen, NULL, BUS_DMA_WAITOK);
-               if (error)
-                       panic("bus_dmamap_load failed: %d", error);
 
                DMA_WRITE(sc, DMA_EN_REG(index), 0);
        }



Home | Main Index | Thread Index | Old Index