From patchwork Mon Apr 28 10:49:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Gleixner X-Patchwork-Id: 4076431 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 98B41BFF02 for ; Mon, 28 Apr 2014 10:52:49 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7C00D20251 for ; Mon, 28 Apr 2014 10:52:48 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7826F2021B for ; Mon, 28 Apr 2014 10:52:47 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wej90-0005Ij-2K; Mon, 28 Apr 2014 10:50:42 +0000 Received: from galois.linutronix.de ([2001:470:1f0b:db:abcd:42:0:1]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wej89-0003vX-0S for linux-arm-kernel@lists.infradead.org; Mon, 28 Apr 2014 10:49:50 +0000 Received: from localhost ([127.0.0.1] helo=ionos.tec.linutronix.de) by Galois.linutronix.de with esmtp (Exim 4.80) (envelope-from ) id 1Wej7p-00065x-4x; Mon, 28 Apr 2014 12:49:29 +0200 Message-Id: <20140428104643.319315353@linutronix.de> User-Agent: quilt/0.60-1 Date: Mon, 28 Apr 2014 10:49:44 -0000 From: Thomas Gleixner To: dmaengine@vger.kernel.org Subject: [patch V2 6/6] dma: edma: Provide granular accounting References: <20140428104416.464002156@linutronix.de> Content-Disposition: inline; filename=dma-edma-provide-granular-accounting.patch X-Linutronix-Spam-Score: -1.0 X-Linutronix-Spam-Level: - X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required, ALL_TRUSTED=-1, SHORTCIRCUIT=-0.0001 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140428_034949_281128_AAAEF4A6 X-CRM114-Status: GOOD ( 17.36 ) X-Spam-Score: -0.7 (/) Cc: vinod.koul@intel.com, nsekhar@ti.com, Peter Ujfalusi , joelf@ti.com, dan.j.williams@intel.com, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The first slot in the ParamRAM of EDMA holds the current active subtransfer. Depending on the direction we read either the source or the destination address from there. In the internal psets we have the address of the buffer(s). In the cyclic case we only use the internal pset[0] which holds the start address of the circular buffer and calculate the remaining room to the end of the buffer. In the SG case we read the current address and compare it to the internal psets address and length. - If the current address is outside of this range, the pset has been processed already and we mark it done, update the residue_stat value and process the next set. That avoids that we need to walk all processed psets for every invocation of tx_status. - If its inside the range we know that we look at the current active set and stop the walk. - In case of intermediate transfers we update the stats in the interrupt callback function before starting the next batch of transfers. The tx_status callback and the interrupt callback are serialized via vchan.lock. Signed-off-by: Thomas Gleixner --- drivers/dma/edma.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) Index: linux-2.6/drivers/dma/edma.c =================================================================== --- linux-2.6.orig/drivers/dma/edma.c +++ linux-2.6/drivers/dma/edma.c @@ -71,7 +71,11 @@ struct edma_desc { int absync; int pset_nr; int processed; + int processed_stat; u32 residue; + u32 sg_len; + u32 residue_stat; + struct edma_chan *echan; struct edma_pset pset[0]; }; @@ -144,11 +148,13 @@ static void edma_execute(struct edma_cha /* Find out how many left */ left = edesc->pset_nr - edesc->processed; nslots = min(MAX_NR_SG, left); + edesc->sg_len = 0; /* Write descriptor PaRAM set(s) */ for (i = 0; i < nslots; i++) { j = i + edesc->processed; edma_write_slot(echan->slot[i], &edesc->pset[j].param); + edesc->sg_len += edesc->pset[j].len; dev_dbg(echan->vchan.chan.device->dev, "\n pset[%d]:\n" " chnum\t%d\n" @@ -433,6 +439,7 @@ static struct dma_async_tx_descriptor *e edesc->pset_nr = sg_len; edesc->residue = 0; edesc->direction = direction; + edesc->echan = echan; /* Allocate a PaRAM slot, if needed */ nslots = min_t(unsigned, MAX_NR_SG, sg_len); @@ -478,6 +485,7 @@ static struct dma_async_tx_descriptor *e if (i == sg_len - 1) edesc->pset[i].param.opt |= TCINTEN; } + edesc->residue_stat = edesc->residue; return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags); } @@ -545,8 +553,9 @@ static struct dma_async_tx_descriptor *e edesc->cyclic = 1; edesc->pset_nr = nslots; - edesc->residue = buf_len; + edesc->residue = edesc->residue_stat = buf_len; edesc->direction = direction; + edesc->echan = echan; dev_dbg(dev, "%s: nslots=%d\n", __func__, nslots); dev_dbg(dev, "%s: period_len=%d\n", __func__, period_len); @@ -648,6 +657,12 @@ static void edma_callback(unsigned ch_nu edma_execute(echan); } else { dev_dbg(dev, "Intermediate transfer complete on channel %d\n", ch_num); + + /* Update statistics for tx_status */ + edesc->residue -= edesc->sg_len; + edesc->residue_stat = edesc->residue; + edesc->processed_stat = edesc->processed; + edma_execute(echan); } } @@ -775,6 +790,54 @@ static void edma_issue_pending(struct dm spin_unlock_irqrestore(&echan->vchan.lock, flags); } +static u32 edma_residue(struct edma_desc *edesc) +{ + bool dst = edesc->direction == DMA_DEV_TO_MEM; + struct edma_pset *pset = edesc->pset; + dma_addr_t done, pos; + int i; + + /* + * We always read the dst/src position from the first RamPar + * pset. That's the one which is active now. + */ + pos = edma_get_position(edesc->echan->slot[0], dst); + + /* + * Cyclic is simple. Just subtract pset[0].addr from pos. + * + * We never update edesc->residue in the cyclic case, so we + * can tell the remaining room to the end of the circular + * buffer. + */ + if (edesc->cyclic) { + done = pos - pset->addr; + edesc->residue_stat = edesc->residue - done; + return edesc->residue_stat; + } + + /* + * For SG operation we catch up with the last processed + * status. + */ + pset += edesc->processed_stat; + + for (i = edesc->processed_stat; i < edesc->processed; i++, pset++) { + /* + * If we are inside this pset address range, we know + * this is the active one. Get the current delta and + * stop walking the psets. + */ + if (pos >= pset->addr && pos < pset->addr + pset->len) + return edesc->residue_stat - (pos - pset->addr); + + /* Otherwise mark it done and update residue_stat. */ + edesc->processed_stat++; + edesc->residue_stat -= pset->len; + } + return edesc->residue_stat; +} + /* Check request completion status */ static enum dma_status edma_tx_status(struct dma_chan *chan, dma_cookie_t cookie, @@ -791,7 +854,7 @@ static enum dma_status edma_tx_status(st spin_lock_irqsave(&echan->vchan.lock, flags); if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) - txstate->residue = echan->edesc->residue; + txstate->residue = edma_residue(echan->edesc); else if ((vdesc = vchan_find_desc(&echan->vchan, cookie))) txstate->residue = to_edma_desc(&vdesc->tx)->residue; spin_unlock_irqrestore(&echan->vchan.lock, flags);