From owner-p4-projects@FreeBSD.ORG Mon Jul 5 21:17:31 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 85DED1065670; Mon, 5 Jul 2010 21:17:31 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 49C96106566C for ; Mon, 5 Jul 2010 21:17:31 +0000 (UTC) (envelope-from jceel@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 35EF98FC1B for ; Mon, 5 Jul 2010 21:17:31 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id o65LHVgC077687 for ; Mon, 5 Jul 2010 21:17:31 GMT (envelope-from jceel@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id o65LHViM077685 for perforce@freebsd.org; Mon, 5 Jul 2010 21:17:31 GMT (envelope-from jceel@freebsd.org) Date: Mon, 5 Jul 2010 21:17:31 GMT Message-Id: <201007052117.o65LHViM077685@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to jceel@freebsd.org using -f From: Jakub Wojciech Klama To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 180502 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 05 Jul 2010 21:17:32 -0000 http://p4web.freebsd.org/@@180502?ac=10 Change 180502 by jceel@jceel on 2010/07/05 21:17:11 * Add support for linked transfers in EDMA3 driver * Some cosmeting and style(9) changes Affected files ... .. //depot/projects/soc2010/jceel_dma/sys/arm/davinci/davinci_edma.c#4 edit .. //depot/projects/soc2010/jceel_dma/sys/arm/davinci/davinci_edmareg.h#4 edit Differences ... ==== //depot/projects/soc2010/jceel_dma/sys/arm/davinci/davinci_edma.c#4 (text+ko) ==== @@ -86,8 +86,11 @@ int dc_chno; int dc_status; #define CHANNEL_ACTIVE 1 +#define CHANNEL_ACTIVE_LINKED 2 #define CHANNEL_IDLE 0 + int dc_laststatus; struct dmae_transfer * dc_xfer; + struct dmae_transfer * dc_linkxfer; }; struct davinci_edma_softc { @@ -131,6 +134,9 @@ static void davinci_edma_intr_tcerr1(void *); static void davinci_edma_tcerr(struct davinci_edma_softc *, int); +static int davinci_edma_setupdesc(struct dmae_transfer *, + struct davinci_edma_desc *); +static uint64_t ffs64(uint64_t); #define davinci_edma_lock(sc) \ mtx_lock(&sc->ds_mtx) @@ -246,66 +252,36 @@ { struct davinci_edma_softc *sc = device_get_softc(dev); struct davinci_edma_channel *ch; - struct davinci_edma_desc param_desc; - uint32_t acnt, bcnt, srcbidx, dstbidx; - - debugf("setup channel: chno=%d, xfer=%p", chno, xfer); - debugf("srcbuf=0x%08lx, dstbuf=0x%08lx length=%ld", - xfer->dt_src.db_addr, xfer->dt_dst.db_addr, - xfer->dt_dst.db_length); + struct davinci_edma_desc param_desc, link_desc; + int ret; if (chno < 0 || chno > DAVINCI_EDMA_NCHANNELS) return (EINVAL); + + ch = &sc->ds_channels[chno]; + ch->dc_xfer = xfer; - if (xfer->dt_src.db_type == DMAEBUF_FRAME || - xfer->dt_dst.db_type == DMAEBUF_FRAME) { - if (xfer->dt_src.db_type == DMAEBUF_FRAME && - xfer->dt_dst.db_type == DMAEBUF_FRAME && - xfer->dt_src.db_stride_width != - xfer->dt_dst.db_stride_width) - return (EINVAL); + /* Allow at most one linked transfer */ + if (xfer->dt_next != NULL && xfer->dt_next->dt_next != NULL) + return (EINVAL); - acnt = (xfer->dt_src.db_type == DMAEBUF_FRAME - ? xfer->dt_src.db_stride_width - : xfer->dt_dst.db_stride_width); - bcnt = (xfer->dt_src.db_type == DMAEBUF_FRAME - ? xfer->dt_src.db_length / - (acnt + xfer->dt_src.db_stride_spacing) - : xfer->dt_dst.db_length / - (acnt + xfer->dt_dst.db_stride_spacing)); - - srcbidx = dstbidx = acnt; + /* Setup transfer descriptor */ + ret = davinci_edma_setupdesc(xfer, ¶m_desc); + if (ret) + return (ret); - if (xfer->dt_src.db_type == DMAEBUF_FRAME) - srcbidx += xfer->dt_src.db_stride_spacing; + davinci_edma_copydesc(sc, ¶m_desc, chno); - if (xfer->dt_dst.db_type == DMAEBUF_FRAME) - dstbidx += xfer->dt_dst.db_stride_spacing; - } else { - acnt = xfer->dt_dst.db_length; - bcnt = 1; - srcbidx = 0; - dstbidx = 0; + /* Setup linked descriptor (if present) */ + if (xfer->dt_next != NULL) { + ch->dc_linkxfer = xfer->dt_next; + ret = davinci_edma_setupdesc(xfer->dt_next, &link_desc); + if (ret) + return (ret); + printf("calling davinci_edma_copydesc(&link_desc=%p, chno=%d)\n", &link_desc, chno + 64); + davinci_edma_copydesc(sc, &link_desc, chno + 64); } - ch = &sc->ds_channels[chno]; - ch->dc_xfer = xfer; - - /* Set up DMA descriptor */ - param_desc.edma_src = xfer->dt_src.db_addr; - param_desc.edma_dst = xfer->dt_dst.db_addr; - param_desc.edma_opt = - DAVINCI_EDMA_OPT_TCINTEN | - DAVINCI_EDMA_OPT_ITCINTEN | - DAVINCI_EDMA_OPT_SYNCDIM | - (chno << DAVINCI_EDMA_OPT_TCCSHIFT); - param_desc.edma_abcnt = (bcnt << 16) | acnt; - param_desc.edma_bidx = (dstbidx << 16) | srcbidx; - param_desc.edma_cidx = 0; - param_desc.edma_ccnt = 1; - - davinci_edma_copydesc(sc, ¶m_desc, chno); - /* Enable channel interrupts */ // if ((xfer->dt_flags & DMAE_TRANSFER_EXTTRIG) == 0) // davinci_edma_enable_channel(sc, chno); @@ -375,7 +351,27 @@ static int davinci_edma_poll_channel(device_t dev, int chno, int *status) { - return (0); + struct davinci_edma_softc *sc = device_get_softc(dev); + struct davinci_edma_channel *ch; + uint32_t ipr; + int active = 0; + + ch = &sc->ds_channels[chno]; + + if (chno < 32) { + ipr = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_IPR); + if (ipr & (1 << chno)) + active = 1; + } else { + ipr = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_IPRH); + if (ipr & (1 << (chno-32))) + active = 1; + } + + if (active) + return (DMAE_TRANSFER_INPROGRESS); + else + return (ch->dc_laststatus); } static void @@ -384,54 +380,46 @@ struct davinci_edma_softc *sc = (struct davinci_edma_softc *)arg; struct davinci_edma_channel *ch; struct dmae_transfer *xfer = NULL; - uint32_t ipr, iprh; + uint64_t ipr; + uint32_t iprl, iprh; int chno; debugf("transfer completion interrupt"); while (1) { - ipr = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_IPR); + iprl = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_IPR); iprh = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_IPRH); + ipr = (uint64_t)iprh << 32 | iprl; - if (ipr == 0 && iprh == 0) + if (ipr == 0) return; - while ((chno = (ffs(ipr) - 1)) != -1) { + while ((chno = (ffs64(ipr) - 1)) != -1) { ch = &sc->ds_channels[chno]; xfer = ch->dc_xfer; debugf("interrupt on channel %d", chno); - KASSERT(ch->dc_status == CHANNEL_ACTIVE, "edma spurious interrupt"); + KASSERT(ch->dc_status != CHANNEL_IDLE, ("invalid channel state")); if (xfer->dt_callback != NULL) { - xfer->dt_callback(DMAE_TRANSFER_COMPLETED, - xfer->dt_callback_arg); + xfer->dt_callback(DMAE_TRANSFER_COMPLETED, + xfer->dt_callback_arg); } + + if (chno > 32) + davinci_write_edmacc_4(sc, DAVINCI_EDMACC_ICRH, (1 << (chno - 32))); + else + davinci_write_edmacc_4(sc, DAVINCI_EDMACC_ICR, (1 << chno)); - ch->dc_status = 0; - - davinci_write_edmacc_4(sc, DAVINCI_EDMACC_ICR, (1 << chno)); - ipr &= ~(1 << chno); - } + ipr &= ~(1ULL << chno); + ch->dc_status = CHANNEL_IDLE; - while ((chno = (ffs(iprh) + 31)) != 31) { - ch = &sc->ds_channels[chno]; - xfer = ch->dc_xfer; - - KASSERT(ch->dc_status == CHANNEL_ACTIVE, "edma spurious interrupt"); - - debugf("interrupt on channel %d", chno); - - if (xfer->dt_callback != NULL) { - xfer->dt_callback(DMAE_TRANSFER_COMPLETED, - - xfer->dt_callback_arg); + if (xfer->dt_next != NULL) { + ch->dc_xfer = xfer->dt_next; + davinci_edma_start_channel(sc->ds_dev, chno); + return; } - - ch->dc_status = 0; - davinci_write_edmacc_4(sc, DAVINCI_EDMACC_ICRH, (1 << (chno-32))); - iprh &= ~(1 << (chno - 32)); } } } @@ -442,48 +430,38 @@ struct davinci_edma_softc *sc = (struct davinci_edma_softc *)arg; struct davinci_edma_channel *ch; struct dmae_transfer *xfer = NULL; - uint32_t emr, emrh; + uint64_t emr; + uint32_t emrl, emrh; int chno; - emr = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_EMR); + emrl = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_EMR); emrh = davinci_read_edmacc_4(sc, DAVINCI_EDMACC_EMRH); + emr = (uint64_t)emrh << 32 | emrl; - if (emr == 0 && emrh == 0) + if (emr == 0) return; - while ((chno = (ffs(emr) - 1)) != -1) { + while ((chno = (ffs64(emr) - 1)) != -1) { ch = &sc->ds_channels[chno]; xfer = ch->dc_xfer; debugf("error interrupt on channel %d", chno); - KASSERT(ch->dc_status == CHANNEL_ACTIVE, "edma spurious interrupt"); + KASSERT(ch->dc_status != CHANNEL_IDLE, ("invalid channel state")); if (xfer->dt_callback != NULL) { xfer->dt_callback(DMAE_TRANSFER_ERROR, xfer->dt_callback_arg); } - ch->dc_status = 0; - - davinci_write_edmacc_4(sc, DAVINCI_EDMACC_EMR, (1 << chno)); - emr &= ~(1 << chno); - } + ch->dc_status = CHANNEL_IDLE; + + if (chno >= 32) + davinci_write_edmacc_4(sc, DAVINCI_EDMACC_EMRH, (1 << (chno - 32))); + else + davinci_write_edmacc_4(sc, DAVINCI_EDMACC_EMR, (1 << chno)); - while ((chno = (ffs(emrh) + 31)) != 31) { - ch = &sc->ds_channels[chno]; - KASSERT(ch->dc_status == CHANNEL_ACTIVE, "edma spurious interrupt"); - - debugf("error interrupt on channel %d", chno); - - if (xfer->dt_callback != NULL) { - xfer->dt_callback(DMAE_TRANSFER_ERROR, - xfer->dt_callback_arg); - } - - ch->dc_status = 0; - davinci_write_edmacc_4(sc, DAVINCI_EDMACC_EMRH, (1 << (chno-32))); - emr &= ~(1 << (chno - 32)); + emr &= ~(1ULL << chno); } } @@ -523,7 +501,7 @@ DAVINCI_EDMATC_ERRDET_TCCMASK; ch = &sc->ds_channels[chno]; - xfer = dc->dc_xfer; + xfer = ch->dc_xfer; if (xfer->dt_callback != NULL) { xfer->dt_callback(DMAE_TRANSFER_ERROR, @@ -531,6 +509,87 @@ } } +static int +davinci_edma_setupdesc(struct dmae_transfer *xfer, + struct davinci_edma_desc *desc) +{ + int chno; + uint32_t acnt, bcnt, srcbidx, dstbidx; + + chno = rman_get_start(xfer->dt_res); + + debugf("setup desc: chno=%d, xfer=%p", chno, xfer); + debugf("srcbuf=0x%08lx, dstbuf=0x%08lx length=%ld", + xfer->dt_src.db_addr, xfer->dt_dst.db_addr, + xfer->dt_dst.db_length); + + if (xfer->dt_src.db_length == 0 || xfer->dt_dst.db_length == 0) + return (EINVAL); + + if (xfer->dt_src.db_type == DMAEBUF_FRAME || + xfer->dt_dst.db_type == DMAEBUF_FRAME) { + if (xfer->dt_src.db_type == DMAEBUF_FRAME && + xfer->dt_dst.db_type == DMAEBUF_FRAME && + xfer->dt_src.db_stride_width != + xfer->dt_dst.db_stride_width) + return (EINVAL); + + acnt = (xfer->dt_src.db_type == DMAEBUF_FRAME + ? xfer->dt_src.db_stride_width + : xfer->dt_dst.db_stride_width); + bcnt = (xfer->dt_src.db_type == DMAEBUF_FRAME + ? xfer->dt_src.db_length / + (acnt + xfer->dt_src.db_stride_spacing) + : xfer->dt_dst.db_length / + (acnt + xfer->dt_dst.db_stride_spacing)); + + srcbidx = dstbidx = acnt; + + if (xfer->dt_src.db_type == DMAEBUF_FRAME) + srcbidx += xfer->dt_src.db_stride_spacing; + + if (xfer->dt_dst.db_type == DMAEBUF_FRAME) + dstbidx += xfer->dt_dst.db_stride_spacing; + } else { + acnt = xfer->dt_dst.db_length; + bcnt = 1; + srcbidx = 0; + dstbidx = 0; + } + + /* Set up DMA descriptor */ + desc->edma_src = xfer->dt_src.db_addr; + desc->edma_dst = xfer->dt_dst.db_addr; + desc->edma_opt = + DAVINCI_EDMA_OPT_TCINTEN | + /* DAVINCI_EDMA_OPT_ITCINTEN | */ + DAVINCI_EDMA_OPT_SYNCDIM | + (chno << DAVINCI_EDMA_OPT_TCCSHIFT); + desc->edma_abcnt = (bcnt << 16) | acnt; + desc->edma_bidx = (dstbidx << 16) | srcbidx; + desc->edma_cidx = 0; + desc->edma_ccnt = 1; + desc->edma_link = (xfer->dt_next != NULL) + ? ((chno + 64) * sizeof(*desc)) + 0x4000 + : 0xffff; + + return (0); +} + +static __inline uint64_t +ffs64(uint64_t mask) +{ + uint64_t bit; + + if (mask == 0) + return (0); + + for (bit = 1; (mask & 1UL) == 0; bit++) + mask >>= 1UL; + + return (bit); +} + static device_method_t davinci_edma_methods[] = { /* Device methods */ DEVMETHOD(device_probe, davinci_edma_probe), ==== //depot/projects/soc2010/jceel_dma/sys/arm/davinci/davinci_edmareg.h#4 (text+ko) ==== @@ -143,6 +143,6 @@ } __packed; #define DAVINCI_EDMA_PARAM_BASE 0x4000 -#define DAVINCI_EDMA_PARAM(_n) (DAVINCI_EDMA_PARAM_BASE + (_n * sizeof(struct davinci_edma_desc))) +#define DAVINCI_EDMA_PARAM(_n) (DAVINCI_EDMA_PARAM_BASE + ((_n) * sizeof(struct davinci_edma_desc))) #endif /* _ARM_DAVINCI_DAVINCI_EDMAREG_H */