From patchwork Fri Sep 22 16:20:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 143648 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:612c:172:b0:3f2:4152:657d with SMTP id h50csp5852163vqi; Fri, 22 Sep 2023 13:36:42 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEMZ+aLJJjTsu6FX11rebrlmsE3ESY7sBBPDD5LRZggDKkseTeuHGc/tMHTLzSTpei5DiAJ X-Received: by 2002:a17:902:e54c:b0:1c1:ec40:9321 with SMTP id n12-20020a170902e54c00b001c1ec409321mr657013plf.60.1695415001740; Fri, 22 Sep 2023 13:36:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1695415001; cv=none; d=google.com; s=arc-20160816; b=L2LW+udQaGi9TLbFgMANBVMkTMzhFZOOez4YlDsg0Q7BULApuUSTFGbvEItMO5YJM6 jcL6Wqaa9NITmWmol5mt8HAQAA6iB4cxF/PTQjXfUkuhHt0kufG5xXX8Apk6yA5BcI/1 EfnID40kzXQEBrR0diR8yoCMdXLgsjs6SdS/ppSjk3fiLoMHoxC7PospeM2qGBIWdQl8 tI6Yq+TYG+tj9ae4pme6rAS+5MTOiygQSQXIVnew1NeIVmbEP+JrAbS/69zl8lpk1ozu i6ldSk0gyWlFFmHHCn3o8tyyiYEJQxCOsV/Q7vtoHCqlZKvGxq643B0rh8a8/cPwjEQu JbTw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=3n0vwmgGryrUp3/6Ss9kZWLenWVOSWlr6mGiYIMJzv4=; fh=tywAdliBLaC/RMgy7zSP3YxJOfCkdci4rwwkuNbi5gM=; b=tykPkdEqSvxl4q5NS+ubdZ1Yc3WYUod4bz0XbhlGxeouWQVs7kZJs2h+kkDRnoYw1v c8Fw9jeWBrDcef0OYOsSLROOg1BEDrAe6GB98u/gQcPnRdx5A+amYDu/vFQ0bZGTiDXa QqixzSm2GJKWaJV12ptvVA804yaPnBmuZZQQmB8ArSVuhqCKiQ5dmCvYq/PQR6YUYjQ4 rjNlOE/2Osbm9J3olytEsS3pla026A+1pot0e2x5T9gcPj1fWQnatdvDsvmM4U1JEc1T sKWY8QbExztfIqq+D33VLt58jpChnZBtzmV+f2KYGwVWM8meb+oCzAduLbpsia35oyPU 9xRw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@bootlin.com header.s=gm1 header.b="OgKk6S/r"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.35 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bootlin.com Received: from groat.vger.email (groat.vger.email. [23.128.96.35]) by mx.google.com with ESMTPS id kz4-20020a170902f9c400b001c20db25108si4216290plb.41.2023.09.22.13.36.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Sep 2023 13:36:41 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.35 as permitted sender) client-ip=23.128.96.35; Authentication-Results: mx.google.com; dkim=pass header.i=@bootlin.com header.s=gm1 header.b="OgKk6S/r"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.35 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bootlin.com Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by groat.vger.email (Postfix) with ESMTP id 4CEDF83C5BAB; Fri, 22 Sep 2023 09:21:39 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at groat.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231128AbjIVQVM (ORCPT + 29 others); Fri, 22 Sep 2023 12:21:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40604 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229698AbjIVQVL (ORCPT ); Fri, 22 Sep 2023 12:21:11 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3BC50197; Fri, 22 Sep 2023 09:21:04 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPSA id 01453E0004; Fri, 22 Sep 2023 16:21:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1695399662; 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=3n0vwmgGryrUp3/6Ss9kZWLenWVOSWlr6mGiYIMJzv4=; b=OgKk6S/r44Py+XcCLS/dK0iZ3mOTBl8kEguo0y8rjlnZIOUeg+AJfLZHE+qP1QIVhWYOpr tiCwAQ90EUZcIxuCEeBMQf4r+Vxc6uOcIJeorypNBKnmEi5p1NvMBYSjGWtKq/xrmNF7pU /8RrLHLnzrfWld0oPPkOja4xprELWiWQYxQHW12NqGhBFKVC/DOUDl1JECNA5oNfaod5Eo 1ZgBAniOds503plyicEYdnXJ9NvderpZYjKdlmQucX2xNOJClTOrQuhDVV872kwxZfByJ/ tB5u5k0JbKmRI4qWiueDMbVNTTai53ipD59J1+gon96qoPU3ycpv3HbYZoAYrQ== From: Miquel Raynal To: Lizhi Hou , Brian Xu , Raj Kumar Rampelli , Vinod Koul , Michal Simek Cc: dmaengine@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Thomas Petazzoni , , Miquel Raynal Subject: [PATCH v2 1/2] dmaengine: xilinx: xdma: Prepare the introduction of cyclic transfers Date: Fri, 22 Sep 2023 18:20:55 +0200 Message-Id: <20230922162056.594933-2-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230922162056.594933-1-miquel.raynal@bootlin.com> References: <20230922162056.594933-1-miquel.raynal@bootlin.com> MIME-Version: 1.0 X-GND-Sasl: miquel.raynal@bootlin.com X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on groat.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (groat.vger.email [0.0.0.0]); Fri, 22 Sep 2023 09:21:39 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1777771480804777432 X-GMAIL-MSGID: 1777771480804777432 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 e0bfd129d563..09ed13d6666d 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 Fri Sep 22 16:20:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 143542 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:612c:172:b0:3f2:4152:657d with SMTP id h50csp5736870vqi; Fri, 22 Sep 2023 10:04:46 -0700 (PDT) X-Google-Smtp-Source: AGHT+IG3XciJh8u0odeqGiuX3tCcZxKFE3Xij708BquvHszymf0prDQSoasBqPTmNPAEXNArddnb X-Received: by 2002:a05:6a00:14c6:b0:68a:4bef:5f9a with SMTP id w6-20020a056a0014c600b0068a4bef5f9amr56906pfu.0.1695402285911; Fri, 22 Sep 2023 10:04:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1695402285; cv=none; d=google.com; s=arc-20160816; b=E2jMxrTbW3SdYdVDb+DKIUavmn1pE5gRpAoQ4Vs3/D5VGFzUALjd79jx2JhUcycn/G hpIwFRFQ1SKTiSXyJbY+D4Cq4bk5VlgrC7iYw9iQ6wXWEju2/kngQiU5aCdHnWTuaFet th00x0zmO0FdpbtmnTyVYz5EJTsOBwn0kifdgENVCgbQDGy7mZ0quu8ZnISp0MZVLYsD PqQyXQhHQ6atk9kQc4AMVmNdzDmg9jBHLEoK8cX4ZjYFuxcsBwcjRgBbBpu5sZlt5lib 8fWurq6z/A0JsvVFnLcjL1w1HKOen8jKxXq16zuahU7hhBZWnkamHeSfgggIrca3DYnP G09Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=hM/G7GLoJFD2BkQOr/LMeiSdKwvxTEdiVuJVUQHGZ5k=; fh=tywAdliBLaC/RMgy7zSP3YxJOfCkdci4rwwkuNbi5gM=; b=N4ocxpVtAFwgMj3uYsIsz1O8n6pir/4TeB/rVunvG66SQP3XsM/N4tc0cJDpY0ghaS Wj0rkckqiBxdnK28ENsQlTXW/u4AJ+TagBqiqQYBL5yjBAXrEDi/G5pcYGle+A190wCf Z4+InzLwoVmW5T7QzlgUbQGWdfv+JtcoQAA71iWi+62Xz5ZsPNPnIGSby+6u7GGcOdBK apvptMK4DRH7T8AjOjOTz5A/yn7lrjxrB11YfRWBeoiMo3256V7t2ikw2FSkknSMFGx1 Zl6TS3+Wi05Zk0KOyRnrsmV+LszJsxaZH5pVFkcmBYRnJZS0CkP5Ye5iJ2ddWSGt7qxg WPdg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@bootlin.com header.s=gm1 header.b=DqgLRa0e; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.37 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bootlin.com Received: from snail.vger.email (snail.vger.email. [23.128.96.37]) by mx.google.com with ESMTPS id bt8-20020a632908000000b0054fdfd26dffsi4066225pgb.337.2023.09.22.10.04.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Sep 2023 10:04:45 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.37 as permitted sender) client-ip=23.128.96.37; Authentication-Results: mx.google.com; dkim=pass header.i=@bootlin.com header.s=gm1 header.b=DqgLRa0e; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.37 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bootlin.com Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by snail.vger.email (Postfix) with ESMTP id 7750D80C591C; Fri, 22 Sep 2023 09:21:27 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at snail.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231192AbjIVQVT (ORCPT + 29 others); Fri, 22 Sep 2023 12:21:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40624 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231285AbjIVQVN (ORCPT ); Fri, 22 Sep 2023 12:21:13 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5621A122; Fri, 22 Sep 2023 09:21:06 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPSA id 1A09FE0009; Fri, 22 Sep 2023 16:21:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1695399665; 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=hM/G7GLoJFD2BkQOr/LMeiSdKwvxTEdiVuJVUQHGZ5k=; b=DqgLRa0e5okZfd/ObrWO96bmvQsNN1Lyn++po3TQY+w5EHCHa9+WwfA/601N/DB899xsXK WZZVeCYjmA3RONBlWbeUBP2Z3oR9ZadIkTPAlYQ39uVqfWC0uBTLLHg4piTNkhe2p0VJnv CVs019y9QYZvRXV38ZW8pPQxF4dSeke0/0JOU/pdd/5jM1R5qY4qqW5HuntdV1wNlsYZUS VO+SouYeLgdje3B4jGpxe6XgsX3lxAh+L2Ele5KWOND7Ef2lY5aEwlkl7RgoKLPWJkB6Eh EIQBVpACeEbkUOXPPxWjvwWNJzEN5MIe8JcGwYulxxpCpGXhDZSvkc8tPN1Otw== From: Miquel Raynal To: Lizhi Hou , Brian Xu , Raj Kumar Rampelli , Vinod Koul , Michal Simek Cc: dmaengine@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Thomas Petazzoni , , Miquel Raynal Subject: [PATCH v2 2/2] dmaengine: xilinx: xdma: Support cyclic transfers Date: Fri, 22 Sep 2023 18:20:56 +0200 Message-Id: <20230922162056.594933-3-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230922162056.594933-1-miquel.raynal@bootlin.com> References: <20230922162056.594933-1-miquel.raynal@bootlin.com> MIME-Version: 1.0 X-GND-Sasl: miquel.raynal@bootlin.com X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (snail.vger.email [0.0.0.0]); Fri, 22 Sep 2023 09:21:27 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1777758147010819583 X-GMAIL-MSGID: 1777758147010819583 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 | 165 +++++++++++++++++++++++++++++++-- 2 files changed, 161 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 09ed13d6666d..bc9a6ca3353e 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,81 @@ 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; + 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; + + dblk = sw_desc->desc_blocks; + desc = dblk->virt_addr; + + /* fill hardware descriptor */ + for (i = 0; i < periods; i++) { + desc->bytes = cpu_to_le32(period_size); + if (dir == DMA_MEM_TO_DEV) { + desc->src_addr = cpu_to_le64(address + i * period_size); + desc->dst_addr = cpu_to_le64(xdma_chan->cfg.dst_addr); + } else { + desc->src_addr = cpu_to_le64(xdma_chan->cfg.src_addr); + desc->dst_addr = cpu_to_le64(address + i * period_size); + } + + desc++; + } + + 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 +690,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 xdma_desc *desc = NULL; + struct virt_dma_desc *vd; + 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) + 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 +735,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 +754,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 +780,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 +1080,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 +1093,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) {