From patchwork Mon Jul 31 10:14:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 13334240 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 09B98C41513 for ; Mon, 31 Jul 2023 10:14:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229723AbjGaKOu (ORCPT ); Mon, 31 Jul 2023 06:14:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52380 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229854AbjGaKOt (ORCPT ); Mon, 31 Jul 2023 06:14:49 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B27BEE5A; Mon, 31 Jul 2023 03:14:48 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPSA id 06CCB1BF20C; Mon, 31 Jul 2023 10:14:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1690798487; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pk8udpJ2M7pKGiqvni22vLIqee3xOn8qP+AR1XeBzeg=; b=nhgtgOEAp2Ka9sIunlLyncFOSrqdEp9ZMLYSt7wd6EiMI84MRkrp5DfZOvkns1YGCxUwZp WRlaag9tAhod7M/EJRl24LvM3nD5GLq1tWOPcVtUu7j1Hl4BirzBA5QfP+bPXtvCXQA7Jr Cp0T/MLh5Qg+JSkndDoyooebc0/bm/noEpZEguG6H+j8KuHGB1h3ELxxDtjUqm7PaOZcOQ MjUqO3Ic6J2c8mBIJBnojGdMX4TBmuq9nHh5SGk2M44obnaPUwpu/ZFVJIYfYsJ2xvkLBe NEjp3OCB8UewtZ8cZzqXuorOhZaL4hZeMC7Rc3F/AhtB3ra979ZwhUyW8IDhlg== From: Miquel Raynal To: Lizhi Hou , Brian Xu , Raj Kumar Rampelli , Vinod Koul Cc: Michal Simek , Max Zhen , Sonal Santan , dmaengine@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Thomas Petazzoni , Miquel Raynal , stable@vger.kernel.org Subject: [PATCH 1/4] dmaengine: xilinx: xdma: Fix interrupt vector setting Date: Mon, 31 Jul 2023 12:14:39 +0200 Message-Id: <20230731101442.792514-2-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230731101442.792514-1-miquel.raynal@bootlin.com> References: <20230731101442.792514-1-miquel.raynal@bootlin.com> MIME-Version: 1.0 X-GND-Sasl: miquel.raynal@bootlin.com Precedence: bulk List-ID: X-Mailing-List: dmaengine@vger.kernel.org A couple of hardware registers need to be set to reflect which interrupts have been allocated to the device. Each register is 32-bit wide and can receive four 8-bit values. If we provide any other interrupt number than four, the irq_num variable will never be 0 within the while check and the while block will loop forever. There is an easy way to prevent this: just break the for loop when we reach "irq_num == 0", which anyway means all interrupts have been processed. Cc: stable@vger.kernel.org Fixes: 17ce252266c7 ("dmaengine: xilinx: xdma: Add xilinx xdma driver") Signed-off-by: Miquel Raynal Acked-by: Lizhi Hou --- drivers/dma/xilinx/xdma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 93ee298d52b8..359123526dd0 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -668,6 +668,8 @@ static int xdma_set_vector_reg(struct xdma_device *xdev, u32 vec_tbl_start, val |= irq_start << shift; irq_start++; irq_num--; + if (!irq_num) + break; } /* write IRQ register */ From patchwork Mon Jul 31 10:14:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 13334241 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C427EC001DE for ; Mon, 31 Jul 2023 10:14:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229661AbjGaKOw (ORCPT ); Mon, 31 Jul 2023 06:14:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52392 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231567AbjGaKOv (ORCPT ); Mon, 31 Jul 2023 06:14:51 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 48AD8E3 for ; Mon, 31 Jul 2023 03:14:50 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPSA id ACE4B1BF209; Mon, 31 Jul 2023 10:14:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1690798489; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6dHh+33T/p3O910tAiQDRaPdGhqm/kMGZdU0Eay9+h4=; b=SN4TFl8B2PELsl2XPp24QRdL1/mJKIRG5/BxqpTjyYG41ok9789F5eM3Wr9CGq5iCzewIM eXIRB1YSJ/uCnh+Uo+KwP7sb/9KzBJHYkMCwequVM+rcfceW498eRQXxwo83+37PYeEj02 hxKGgJiNgwM3sC3LqMSn2n0JOP/uIWTP3/jXz48OLbFo9ILoiSvudoj4Fom2f38vNxlZdJ o3vaXubMGRMhWIGP0y4BXKGK6VLhic1OX29BjkDtPx5GklzC2pK9Bv17rTBuT+XrLmNh9I t++36TXuBJSQGXeGPHMKRDoRRKQREG8IObFtgatndAEkWGuxTlzwrA3cqKuvng== From: Miquel Raynal To: Lizhi Hou , Brian Xu , Raj Kumar Rampelli , Vinod Koul Cc: Michal Simek , Max Zhen , Sonal Santan , dmaengine@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Thomas Petazzoni , Miquel Raynal Subject: [PATCH 2/4] dmaengine: xilinx: xdma: Fix typo Date: Mon, 31 Jul 2023 12:14:40 +0200 Message-Id: <20230731101442.792514-3-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230731101442.792514-1-miquel.raynal@bootlin.com> References: <20230731101442.792514-1-miquel.raynal@bootlin.com> MIME-Version: 1.0 X-GND-Sasl: miquel.raynal@bootlin.com Precedence: bulk List-ID: X-Mailing-List: dmaengine@vger.kernel.org Probably a copy/paste error with the previous block, here we are actually managing C2H IRQs. Fixes: 17ce252266c7 ("dmaengine: xilinx: xdma: Add xilinx xdma driver") Signed-off-by: Miquel Raynal --- drivers/dma/xilinx/xdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 359123526dd0..5cdb19bd80a7 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -717,7 +717,7 @@ static int xdma_irq_init(struct xdma_device *xdev) ret = request_irq(irq, xdma_channel_isr, 0, "xdma-c2h-channel", &xdev->c2h_chans[j]); if (ret) { - xdma_err(xdev, "H2C channel%d request irq%d failed: %d", + xdma_err(xdev, "C2H channel%d request irq%d failed: %d", j, irq, ret); goto failed_init_c2h; } From patchwork Mon Jul 31 10:14:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 13334242 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3D004C001DC for ; Mon, 31 Jul 2023 10:14:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231259AbjGaKOy (ORCPT ); Mon, 31 Jul 2023 06:14:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52398 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229622AbjGaKOx (ORCPT ); Mon, 31 Jul 2023 06:14:53 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B6658E3 for ; Mon, 31 Jul 2023 03:14:51 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPSA id 3BC2A1BF20D; Mon, 31 Jul 2023 10:14:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1690798490; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CIavbQJuk5XuT1JU98DnGK6D45Tl57BY5MxbsyHMO6Y=; b=kZfiT2+59PQezD7Br+7it6zEPSFx53fI8cBJwOJfUJgVdI85hKDCvNIIrFqjhW9ShvifWH oNpGz45DUgfE4NiI6m2t2cjaabdrK3NL0Ahu0aMa1xT06KIKihhT13sbkf+wJ2OZfrBSPA 14+rqKcvhoT7UQY3NUNesq78XqbeEYRSO7kNpjiilRCLXxAJYMiyWvhX7xyxBCplwyg8F5 c1Onh6AG7mbfVRl72Aug8LLQCO5lDaHsN3Tjx1/kJHo09YR2qXlr8eam2TWzXCXjskLf4b 4qshnrzIw/3tKt8j3z/+Iwm6zbvBVIndomhXn/3BylyOZUaNZaudX2MLmHOsfQ== From: Miquel Raynal To: Lizhi Hou , Brian Xu , Raj Kumar Rampelli , Vinod Koul Cc: Michal Simek , Max Zhen , Sonal Santan , dmaengine@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Thomas Petazzoni , Miquel Raynal Subject: [PATCH 3/4] dmaengine: xilinx: xdma: Prepare the introduction of cyclic transfers Date: Mon, 31 Jul 2023 12:14:41 +0200 Message-Id: <20230731101442.792514-4-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230731101442.792514-1-miquel.raynal@bootlin.com> References: <20230731101442.792514-1-miquel.raynal@bootlin.com> MIME-Version: 1.0 X-GND-Sasl: miquel.raynal@bootlin.com Precedence: bulk List-ID: X-Mailing-List: dmaengine@vger.kernel.org In order to reduce and clarify the diff when introducing cyclic transfers support, let's first prepare the driver a bit. There is no functional change. Signed-off-by: Miquel Raynal --- drivers/dma/xilinx/xdma.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 5cdb19bd80a7..40983d9355c4 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -137,10 +137,10 @@ static inline void *xdma_blk_last_desc(struct xdma_desc_block *block) } /** - * xdma_link_desc_blocks - Link descriptor blocks for DMA transfer + * xdma_link_sg_desc_blocks - Link SG descriptor blocks for DMA transfer * @sw_desc: Tx descriptor pointer */ -static void xdma_link_desc_blocks(struct xdma_desc *sw_desc) +static void xdma_link_sg_desc_blocks(struct xdma_desc *sw_desc) { struct xdma_desc_block *block; u32 last_blk_desc, desc_control; @@ -239,6 +239,7 @@ xdma_alloc_desc(struct xdma_chan *chan, u32 desc_num) struct xdma_hw_desc *desc; dma_addr_t dma_addr; u32 dblk_num; + u32 control; void *addr; int i, j; @@ -254,6 +255,8 @@ xdma_alloc_desc(struct xdma_chan *chan, u32 desc_num) if (!sw_desc->desc_blocks) goto failed; + control = XDMA_DESC_CONTROL(1, 0); + sw_desc->dblk_num = dblk_num; for (i = 0; i < sw_desc->dblk_num; i++) { addr = dma_pool_alloc(chan->desc_pool, GFP_NOWAIT, &dma_addr); @@ -263,10 +266,10 @@ xdma_alloc_desc(struct xdma_chan *chan, u32 desc_num) sw_desc->desc_blocks[i].virt_addr = addr; sw_desc->desc_blocks[i].dma_addr = dma_addr; for (j = 0, desc = addr; j < XDMA_DESC_ADJACENT; j++) - desc[j].control = cpu_to_le32(XDMA_DESC_CONTROL(1, 0)); + desc[j].control = cpu_to_le32(control); } - xdma_link_desc_blocks(sw_desc); + xdma_link_sg_desc_blocks(sw_desc); return sw_desc; @@ -577,6 +580,12 @@ static int xdma_alloc_chan_resources(struct dma_chan *chan) return 0; } +static enum dma_status xdma_tx_status(struct dma_chan *chan, dma_cookie_t cookie, + struct dma_tx_state *state) +{ + return dma_cookie_status(chan, cookie, state); +} + /** * xdma_channel_isr - XDMA channel interrupt handler * @irq: IRQ number @@ -925,7 +934,7 @@ static int xdma_probe(struct platform_device *pdev) xdev->dma_dev.dev = &pdev->dev; xdev->dma_dev.device_free_chan_resources = xdma_free_chan_resources; xdev->dma_dev.device_alloc_chan_resources = xdma_alloc_chan_resources; - xdev->dma_dev.device_tx_status = dma_cookie_status; + xdev->dma_dev.device_tx_status = xdma_tx_status; xdev->dma_dev.device_prep_slave_sg = xdma_prep_device_sg; xdev->dma_dev.device_config = xdma_device_config; xdev->dma_dev.device_issue_pending = xdma_issue_pending; From patchwork Mon Jul 31 10:14:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 13334243 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 24940C001DE for ; Mon, 31 Jul 2023 10:14:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229854AbjGaKO4 (ORCPT ); Mon, 31 Jul 2023 06:14:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52418 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229622AbjGaKOz (ORCPT ); Mon, 31 Jul 2023 06:14:55 -0400 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7D628E3 for ; Mon, 31 Jul 2023 03:14:53 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPSA id AEA141BF20B; Mon, 31 Jul 2023 10:14:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1690798492; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wyIVp2VgL/tBradJgpUuBL6aJbFDiTgjJIfXbvfYapI=; b=ba8WpySRb50TInnYrR/2wOhOh1Z3cN4N2ZBcH5+IlD/mgTJS0+3Fy4YCDw350OCpJxOMv6 ofFVNVwO9shYJOQlxDzP7SjTh+TfKO3RAGeDNWd6/PHGaoBFcpgI0BkQwho8Ys1zfq4ge+ niXmoGQZSU4wgKXGlTcdBhrxzzMjlEcRMR7KGDf2SVvAJyob5Q/CtI0czXPTD6TdPMwCal NqPKoylpafR8EWiA3PoWuIzJI8IL4KYA/bkSDSasWzG+/+M57WqOKLk/iOYQCZuZfwxmCu lR8AFbfPADEWyj4APAFTTyODz83Pp9CgTAu04LOA15+EXN6qaWQzbkdfA1ljEw== From: Miquel Raynal To: Lizhi Hou , Brian Xu , Raj Kumar Rampelli , Vinod Koul Cc: Michal Simek , Max Zhen , Sonal Santan , dmaengine@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Thomas Petazzoni , Miquel Raynal Subject: [PATCH 4/4] dmaengine: xilinx: xdma: Support cyclic transfers Date: Mon, 31 Jul 2023 12:14:42 +0200 Message-Id: <20230731101442.792514-5-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230731101442.792514-1-miquel.raynal@bootlin.com> References: <20230731101442.792514-1-miquel.raynal@bootlin.com> MIME-Version: 1.0 X-GND-Sasl: miquel.raynal@bootlin.com Precedence: bulk List-ID: X-Mailing-List: dmaengine@vger.kernel.org In order to use this dmaengine with sound devices, let's add cyclic transfers support. Most of the code is reused from the existing scatter-gather implementation, only the final linking between descriptors, the control fields (to trigger interrupts more often) and the interrupt handling are really different. This controller supports up to 32 adjacent descriptors, we assume this is way more than enough for the purpose of cyclic transfers and limit to 32 the number of cycled descriptors. This way, we simplify a lot the overall handling of the descriptors. Signed-off-by: Miquel Raynal --- drivers/dma/xilinx/xdma-regs.h | 2 + drivers/dma/xilinx/xdma.c | 173 +++++++++++++++++++++++++++++++-- 2 files changed, 169 insertions(+), 6 deletions(-) diff --git a/drivers/dma/xilinx/xdma-regs.h b/drivers/dma/xilinx/xdma-regs.h index dd98b4526b90..e641a5083e14 100644 --- a/drivers/dma/xilinx/xdma-regs.h +++ b/drivers/dma/xilinx/xdma-regs.h @@ -44,6 +44,8 @@ FIELD_PREP(XDMA_DESC_FLAGS_BITS, (flag))) #define XDMA_DESC_CONTROL_LAST \ XDMA_DESC_CONTROL(1, XDMA_DESC_STOPPED | XDMA_DESC_COMPLETED) +#define XDMA_DESC_CONTROL_CYCLIC \ + XDMA_DESC_CONTROL(1, XDMA_DESC_COMPLETED) /* * Descriptor for a single contiguous memory block transfer. diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 40983d9355c4..be3a212be30c 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -83,6 +83,9 @@ struct xdma_chan { * @dblk_num: Number of hardware descriptor blocks * @desc_num: Number of hardware descriptors * @completed_desc_num: Completed hardware descriptors + * @cyclic: Cyclic transfer vs. scatter-gather + * @periods: Number of periods in the cyclic transfer + * @period_size: Size of a period in bytes in cyclic transfers */ struct xdma_desc { struct virt_dma_desc vdesc; @@ -93,6 +96,9 @@ struct xdma_desc { u32 dblk_num; u32 desc_num; u32 completed_desc_num; + bool cyclic; + u32 periods; + u32 period_size; }; #define XDMA_DEV_STATUS_REG_DMA BIT(0) @@ -174,6 +180,25 @@ static void xdma_link_sg_desc_blocks(struct xdma_desc *sw_desc) desc->control = cpu_to_le32(XDMA_DESC_CONTROL_LAST); } +/** + * xdma_link_cyclic_desc_blocks - Link cyclic descriptor blocks for DMA transfer + * @sw_desc: Tx descriptor pointer + */ +static void xdma_link_cyclic_desc_blocks(struct xdma_desc *sw_desc) +{ + struct xdma_desc_block *block; + struct xdma_hw_desc *desc; + int i; + + block = sw_desc->desc_blocks; + for (i = 0; i < sw_desc->desc_num - 1; i++) { + desc = block->virt_addr + i * XDMA_DESC_SIZE; + desc->next_desc = cpu_to_le64(block->dma_addr + ((i + 1) * XDMA_DESC_SIZE)); + } + desc = block->virt_addr + i * XDMA_DESC_SIZE; + desc->next_desc = cpu_to_le64(block->dma_addr); +} + static inline struct xdma_chan *to_xdma_chan(struct dma_chan *chan) { return container_of(chan, struct xdma_chan, vchan.chan); @@ -233,7 +258,7 @@ static void xdma_free_desc(struct virt_dma_desc *vdesc) * @desc_num: Number of hardware descriptors */ static struct xdma_desc * -xdma_alloc_desc(struct xdma_chan *chan, u32 desc_num) +xdma_alloc_desc(struct xdma_chan *chan, u32 desc_num, bool cyclic) { struct xdma_desc *sw_desc; struct xdma_hw_desc *desc; @@ -249,13 +274,17 @@ xdma_alloc_desc(struct xdma_chan *chan, u32 desc_num) sw_desc->chan = chan; sw_desc->desc_num = desc_num; + sw_desc->cyclic = cyclic; dblk_num = DIV_ROUND_UP(desc_num, XDMA_DESC_ADJACENT); sw_desc->desc_blocks = kcalloc(dblk_num, sizeof(*sw_desc->desc_blocks), GFP_NOWAIT); if (!sw_desc->desc_blocks) goto failed; - control = XDMA_DESC_CONTROL(1, 0); + if (cyclic) + control = XDMA_DESC_CONTROL_CYCLIC; + else + control = XDMA_DESC_CONTROL(1, 0); sw_desc->dblk_num = dblk_num; for (i = 0; i < sw_desc->dblk_num; i++) { @@ -269,7 +298,10 @@ xdma_alloc_desc(struct xdma_chan *chan, u32 desc_num) desc[j].control = cpu_to_le32(control); } - xdma_link_sg_desc_blocks(sw_desc); + if (cyclic) + xdma_link_cyclic_desc_blocks(sw_desc); + else + xdma_link_sg_desc_blocks(sw_desc); return sw_desc; @@ -469,7 +501,7 @@ xdma_prep_device_sg(struct dma_chan *chan, struct scatterlist *sgl, for_each_sg(sgl, sg, sg_len, i) desc_num += DIV_ROUND_UP(sg_dma_len(sg), XDMA_DESC_BLEN_MAX); - sw_desc = xdma_alloc_desc(xdma_chan, desc_num); + sw_desc = xdma_alloc_desc(xdma_chan, desc_num, false); if (!sw_desc) return NULL; sw_desc->dir = dir; @@ -524,6 +556,89 @@ xdma_prep_device_sg(struct dma_chan *chan, struct scatterlist *sgl, return NULL; } +/** + * xdma_prep_dma_cyclic - prepare for cyclic DMA transactions + * @chan: DMA channel pointer + * @address: Device DMA address to access + * @size: Total length to transfer + * @period_size: Period size to use for each transfer + * @dir: Transfer direction + * @flags: Transfer ack flags + */ +static struct dma_async_tx_descriptor * +xdma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t address, + size_t size, size_t period_size, + enum dma_transfer_direction dir, + unsigned long flags) +{ + struct xdma_chan *xdma_chan = to_xdma_chan(chan); + struct xdma_device *xdev = xdma_chan->xdev_hdl; + unsigned int periods = size / period_size; + struct dma_async_tx_descriptor *tx_desc; + u64 addr, dev_addr, *src, *dst; + struct xdma_desc_block *dblk; + struct xdma_hw_desc *desc; + struct xdma_desc *sw_desc; + unsigned int i; + + /* + * Simplify the whole logic by preventing an abnormally high number of + * periods and periods size. + */ + if (period_size > XDMA_DESC_BLEN_MAX) { + xdma_err(xdev, "period size limited to %lu bytes\n", XDMA_DESC_BLEN_MAX); + return NULL; + } + + if (periods > XDMA_DESC_ADJACENT) { + xdma_err(xdev, "number of periods limited to %u\n", XDMA_DESC_ADJACENT); + return NULL; + } + + sw_desc = xdma_alloc_desc(xdma_chan, periods, true); + if (!sw_desc) + return NULL; + + sw_desc->periods = periods; + sw_desc->period_size = period_size; + sw_desc->dir = dir; + + if (dir == DMA_MEM_TO_DEV) { + dev_addr = xdma_chan->cfg.dst_addr; + src = &addr; + dst = &dev_addr; + } else { + dev_addr = xdma_chan->cfg.src_addr; + src = &dev_addr; + dst = &addr; + } + + dblk = sw_desc->desc_blocks; + desc = dblk->virt_addr; + for (i = 0; i < periods; i++) { + addr = address; + + /* fill hardware descriptor */ + desc->bytes = cpu_to_le32(period_size); + desc->src_addr = cpu_to_le64(*src); + desc->dst_addr = cpu_to_le64(*dst); + + desc++; + address += period_size; + } + + tx_desc = vchan_tx_prep(&xdma_chan->vchan, &sw_desc->vdesc, flags); + if (!tx_desc) + goto failed; + + return tx_desc; + +failed: + xdma_free_desc(&sw_desc->vdesc); + + return NULL; +} + /** * xdma_device_config - Configure the DMA channel * @chan: DMA channel @@ -583,7 +698,36 @@ static int xdma_alloc_chan_resources(struct dma_chan *chan) static enum dma_status xdma_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct dma_tx_state *state) { - return dma_cookie_status(chan, cookie, state); + struct xdma_chan *xdma_chan = to_xdma_chan(chan); + struct virt_dma_desc *vd; + struct xdma_desc *desc; + enum dma_status ret; + unsigned long flags; + unsigned int period_idx; + u32 residue = 0; + + ret = dma_cookie_status(chan, cookie, state); + if (ret == DMA_COMPLETE || !state) + return ret; + + spin_lock_irqsave(&xdma_chan->vchan.lock, flags); + + vd = vchan_find_desc(&xdma_chan->vchan, cookie); + if (vd) + desc = to_xdma_desc(vd); + if (!desc || !desc->cyclic) { + spin_unlock_irqrestore(&xdma_chan->vchan.lock, flags); + return ret; + } + + period_idx = desc->completed_desc_num % desc->periods; + residue = (desc->periods - period_idx) * desc->period_size; + + spin_unlock_irqrestore(&xdma_chan->vchan.lock, flags); + + dma_set_residue(state, residue); + + return ret; } /** @@ -599,6 +743,7 @@ static irqreturn_t xdma_channel_isr(int irq, void *dev_id) struct virt_dma_desc *vd; struct xdma_desc *desc; int ret; + u32 st; spin_lock(&xchan->vchan.lock); @@ -617,6 +762,19 @@ static irqreturn_t xdma_channel_isr(int irq, void *dev_id) goto out; desc->completed_desc_num += complete_desc_num; + + if (desc->cyclic) { + ret = regmap_read(xdev->rmap, xchan->base + XDMA_CHAN_STATUS, + &st); + if (ret) + goto out; + + regmap_write(xdev->rmap, xchan->base + XDMA_CHAN_STATUS, st); + + vchan_cyclic_callback(vd); + goto out; + } + /* * if all data blocks are transferred, remove and complete the request */ @@ -630,7 +788,7 @@ static irqreturn_t xdma_channel_isr(int irq, void *dev_id) complete_desc_num != XDMA_DESC_BLOCK_NUM * XDMA_DESC_ADJACENT) goto out; - /* transfer the rest of data */ + /* transfer the rest of data (SG only) */ xdma_xfer_start(xchan); out: @@ -930,8 +1088,10 @@ static int xdma_probe(struct platform_device *pdev) dma_cap_set(DMA_SLAVE, xdev->dma_dev.cap_mask); dma_cap_set(DMA_PRIVATE, xdev->dma_dev.cap_mask); + dma_cap_set(DMA_CYCLIC, xdev->dma_dev.cap_mask); xdev->dma_dev.dev = &pdev->dev; + xdev->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; xdev->dma_dev.device_free_chan_resources = xdma_free_chan_resources; xdev->dma_dev.device_alloc_chan_resources = xdma_alloc_chan_resources; xdev->dma_dev.device_tx_status = xdma_tx_status; @@ -941,6 +1101,7 @@ static int xdma_probe(struct platform_device *pdev) xdev->dma_dev.filter.map = pdata->device_map; xdev->dma_dev.filter.mapcnt = pdata->device_map_cnt; xdev->dma_dev.filter.fn = xdma_filter_fn; + xdev->dma_dev.device_prep_dma_cyclic = xdma_prep_dma_cyclic; ret = dma_async_device_register(&xdev->dma_dev); if (ret) {