Module Name: src Committed By: jakllsch Date: Sat Mar 2 03:21:17 UTC 2019
Modified Files: src/sys/arch/arm/sunxi: sun6i_dma.c Log Message: Implement support for multi-segment transfers. Make more efficent use of DMA descriptor table memory. To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/sunxi/sun6i_dma.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/sunxi/sun6i_dma.c diff -u src/sys/arch/arm/sunxi/sun6i_dma.c:1.6 src/sys/arch/arm/sunxi/sun6i_dma.c:1.7 --- src/sys/arch/arm/sunxi/sun6i_dma.c:1.6 Sat Nov 17 20:35:41 2018 +++ src/sys/arch/arm/sunxi/sun6i_dma.c Sat Mar 2 03:21:17 2019 @@ -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 <jmcne...@invisible.ca> @@ -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 @@ struct sun6idma_channel { 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_softc { 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 @@ struct sun6idma_softc { #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 @@ sun6idma_transfer(device_t dev, void *pr 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 @@ sun6idma_transfer(device_t dev, void *pr __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; - } - 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); + 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); + } - 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 @@ sun6idma_attach(device_t parent, device_ 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 @@ sun6idma_attach(device_t parent, device_ 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 @@ sun6idma_attach(device_t parent, device_ 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); }