From nobody Fri Oct 3 23:02:51 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6255D2E888B; Sat, 23 Aug 2025 15:58:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755964681; cv=none; b=E24sm36YvfamarzEvWhAhgUqI5tCVu2UxcO9bsIBG1+X/L0UzVd8P9uYoAdkNgP0WBVjJgbDUtp0wd6w7FXGyRdGJDC1jiN58pNMmTMFRKaq7BUoZPZjL7zoDbYlVJ10tf61+Tcml62lXBG7xnt30aZ6EGsyqNbuGv4NNNQyofA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755964681; c=relaxed/simple; bh=eRF0y8k9gBqSWRmWw3RnFEXQjPJyHVaqp9mzsJmVrLg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=C4yWlV8azvbimhkfdRpAqatHcsDyzh/hIp/gtJ7JnGlEol6rIbjUZPjbFAdObhV+oXdJmo13vYobHYLrNvPla09U519bvu3LVjyf48MU/hC5NfonmFNuTChnfikZl0V/WffJx6ZIUyEDBBi1I0TH/yfr/Ls82d7OqhbmOrWAD14= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=CeF86+0y; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="CeF86+0y" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 437F9C116B1; Sat, 23 Aug 2025 15:57:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1755964681; bh=eRF0y8k9gBqSWRmWw3RnFEXQjPJyHVaqp9mzsJmVrLg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CeF86+0yhUk+/N7XRTd+EFTcLdsIqcBniToNywamiSlQP1uXKp/0hQsEkvclMka1D tdhju8kL5Kn202gKepoh9ZWI3HUVsWs1saxwlFc/YNJrO+5v3xBxqk9jOKcN0fbyUc nNp438NTCjsObF4kh/pTJrkRNQ7ucIiMyBmrcID1SjD/IcLkrwaPzjw4Sx7P4sLtT8 2HWroMI6+Ub+zSjinWZ5ATbQplQDvP9/Kae1D21yKpj4em7gbjqdK+O/YzrKTnT8YL gRKJOOp3m2B/oS+ryY1i2JaLSssdNYhnSVoKtIe4PDjz+989OkmCRnjQKr4NV7yRK2 2dJuTypWkffRA== From: Jisheng Zhang To: Vinod Koul , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Robin Murphy Cc: dmaengine@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 10/14] dmaengine: dma350: Alloc command[] from dma pool Date: Sat, 23 Aug 2025 23:40:05 +0800 Message-ID: <20250823154009.25992-11-jszhang@kernel.org> X-Mailer: git-send-email 2.50.0 In-Reply-To: <20250823154009.25992-1-jszhang@kernel.org> References: <20250823154009.25992-1-jszhang@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, the command[] is allocated with kzalloc(), but dma350 may be used on dma-non-coherent platforms, to prepare the support of peripheral and scatter-gather chaining on both dma-coherent and dma-non-coherent platforms, let's alloc them from dma pool. Signed-off-by: Jisheng Zhang --- drivers/dma/arm-dma350.c | 143 +++++++++++++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 30 deletions(-) diff --git a/drivers/dma/arm-dma350.c b/drivers/dma/arm-dma350.c index 72067518799e..3d26a1f020df 100644 --- a/drivers/dma/arm-dma350.c +++ b/drivers/dma/arm-dma350.c @@ -4,6 +4,7 @@ =20 #include #include +#include #include #include #include @@ -143,6 +144,7 @@ #define LINK_LINKADDR BIT(30) #define LINK_LINKADDRHI BIT(31) =20 +#define D350_MAX_CMDS 16 =20 enum ch_ctrl_donetype { CH_CTRL_DONETYPE_NONE =3D 0, @@ -169,18 +171,25 @@ enum ch_cfg_memattr { MEMATTR_WB =3D 0xff }; =20 -struct d350_desc { - struct virt_dma_desc vd; - u32 command[16]; +struct d350_sg { + u32 *command; + dma_addr_t phys; u16 xsize; u16 xsizehi; u8 tsz; }; =20 +struct d350_desc { + struct virt_dma_desc vd; + u32 sglen; + struct d350_sg sg[] __counted_by(sglen); +}; + struct d350_chan { struct virt_dma_chan vc; struct d350_desc *desc; void __iomem *base; + struct dma_pool *cmd_pool; int irq; enum dma_status status; dma_cookie_t cookie; @@ -210,7 +219,14 @@ static inline struct d350_desc *to_d350_desc(struct vi= rt_dma_desc *vd) =20 static void d350_desc_free(struct virt_dma_desc *vd) { - kfree(to_d350_desc(vd)); + struct d350_chan *dch =3D to_d350_chan(vd->tx.chan); + struct d350_desc *desc =3D to_d350_desc(vd); + int i; + + for (i =3D 0; i < desc->sglen; i++) + dma_pool_free(dch->cmd_pool, desc->sg[i].command, desc->sg[i].phys); + + kfree(desc); } =20 static struct dma_async_tx_descriptor *d350_prep_memcpy(struct dma_chan *c= han, @@ -218,22 +234,32 @@ static struct dma_async_tx_descriptor *d350_prep_memc= py(struct dma_chan *chan, { struct d350_chan *dch =3D to_d350_chan(chan); struct d350_desc *desc; + struct d350_sg *sg; + dma_addr_t phys; u32 *cmd; =20 - desc =3D kzalloc(sizeof(*desc), GFP_NOWAIT); + desc =3D kzalloc(struct_size(desc, sg, 1), GFP_NOWAIT); if (!desc) return NULL; =20 - desc->tsz =3D __ffs(len | dest | src | (1 << dch->tsz)); - desc->xsize =3D lower_16_bits(len >> desc->tsz); - desc->xsizehi =3D upper_16_bits(len >> desc->tsz); + sg =3D &desc->sg[0]; + sg->command =3D dma_pool_zalloc(dch->cmd_pool, GFP_NOWAIT, &phys); + if (unlikely(!sg->command)) { + kfree(desc); + return NULL; + } + sg->phys =3D phys; + + sg->tsz =3D __ffs(len | dest | src | (1 << dch->tsz)); + sg->xsize =3D lower_16_bits(len >> sg->tsz); + sg->xsizehi =3D upper_16_bits(len >> sg->tsz); =20 - cmd =3D desc->command; + cmd =3D sg->command; cmd[0] =3D LINK_CTRL | LINK_SRCADDR | LINK_SRCADDRHI | LINK_DESADDR | LINK_DESADDRHI | LINK_XSIZE | LINK_XSIZEHI | LINK_SRCTRANSCFG | LINK_DESTRANSCFG | LINK_XADDRINC | LINK_LINKADDR; =20 - cmd[1] =3D FIELD_PREP(CH_CTRL_TRANSIZE, desc->tsz) | + cmd[1] =3D FIELD_PREP(CH_CTRL_TRANSIZE, sg->tsz) | FIELD_PREP(CH_CTRL_XTYPE, CH_CTRL_XTYPE_CONTINUE) | FIELD_PREP(CH_CTRL_DONETYPE, CH_CTRL_DONETYPE_CMD); =20 @@ -241,13 +267,15 @@ static struct dma_async_tx_descriptor *d350_prep_memc= py(struct dma_chan *chan, cmd[3] =3D upper_32_bits(src); cmd[4] =3D lower_32_bits(dest); cmd[5] =3D upper_32_bits(dest); - cmd[6] =3D FIELD_PREP(CH_XY_SRC, desc->xsize) | FIELD_PREP(CH_XY_DES, des= c->xsize); - cmd[7] =3D FIELD_PREP(CH_XY_SRC, desc->xsizehi) | FIELD_PREP(CH_XY_DES, d= esc->xsizehi); + cmd[6] =3D FIELD_PREP(CH_XY_SRC, sg->xsize) | FIELD_PREP(CH_XY_DES, sg->x= size); + cmd[7] =3D FIELD_PREP(CH_XY_SRC, sg->xsizehi) | FIELD_PREP(CH_XY_DES, sg-= >xsizehi); cmd[8] =3D dch->coherent ? TRANSCFG_WB : TRANSCFG_NC; cmd[9] =3D dch->coherent ? TRANSCFG_WB : TRANSCFG_NC; cmd[10] =3D FIELD_PREP(CH_XY_SRC, 1) | FIELD_PREP(CH_XY_DES, 1); cmd[11] =3D 0; =20 + mb(); + return vchan_tx_prep(&dch->vc, &desc->vd, flags); } =20 @@ -256,34 +284,46 @@ static struct dma_async_tx_descriptor *d350_prep_mems= et(struct dma_chan *chan, { struct d350_chan *dch =3D to_d350_chan(chan); struct d350_desc *desc; + struct d350_sg *sg; + dma_addr_t phys; u32 *cmd; =20 - desc =3D kzalloc(sizeof(*desc), GFP_NOWAIT); + desc =3D kzalloc(struct_size(desc, sg, 1), GFP_NOWAIT); if (!desc) return NULL; =20 - desc->tsz =3D __ffs(len | dest | (1 << dch->tsz)); - desc->xsize =3D lower_16_bits(len >> desc->tsz); - desc->xsizehi =3D upper_16_bits(len >> desc->tsz); + sg =3D &desc->sg[0]; + sg->command =3D dma_pool_zalloc(dch->cmd_pool, GFP_NOWAIT, &phys); + if (unlikely(!sg->command)) { + kfree(desc); + return NULL; + } + sg->phys =3D phys; + + sg->tsz =3D __ffs(len | dest | (1 << dch->tsz)); + sg->xsize =3D lower_16_bits(len >> sg->tsz); + sg->xsizehi =3D upper_16_bits(len >> sg->tsz); =20 - cmd =3D desc->command; + cmd =3D sg->command; cmd[0] =3D LINK_CTRL | LINK_DESADDR | LINK_DESADDRHI | LINK_XSIZE | LINK_XSIZEHI | LINK_DESTRANSCFG | LINK_XADDRINC | LINK_FILLVAL | LINK_LINKADDR; =20 - cmd[1] =3D FIELD_PREP(CH_CTRL_TRANSIZE, desc->tsz) | + cmd[1] =3D FIELD_PREP(CH_CTRL_TRANSIZE, sg->tsz) | FIELD_PREP(CH_CTRL_XTYPE, CH_CTRL_XTYPE_FILL) | FIELD_PREP(CH_CTRL_DONETYPE, CH_CTRL_DONETYPE_CMD); =20 cmd[2] =3D lower_32_bits(dest); cmd[3] =3D upper_32_bits(dest); - cmd[4] =3D FIELD_PREP(CH_XY_DES, desc->xsize); - cmd[5] =3D FIELD_PREP(CH_XY_DES, desc->xsizehi); + cmd[4] =3D FIELD_PREP(CH_XY_DES, sg->xsize); + cmd[5] =3D FIELD_PREP(CH_XY_DES, sg->xsizehi); cmd[6] =3D dch->coherent ? TRANSCFG_WB : TRANSCFG_NC; cmd[7] =3D FIELD_PREP(CH_XY_DES, 1); cmd[8] =3D (u8)value * 0x01010101; cmd[9] =3D 0; =20 + mb(); + return vchan_tx_prep(&dch->vc, &desc->vd, flags); } =20 @@ -319,8 +359,9 @@ static int d350_resume(struct dma_chan *chan) =20 static u32 d350_get_residue(struct d350_chan *dch) { - u32 res, xsize, xsizehi, hi_new; - int retries =3D 3; /* 1st time unlucky, 2nd improbable, 3rd just broken */ + u32 res, xsize, xsizehi, linkaddr, linkaddrhi, hi_new; + int i, sgcur, retries =3D 3; /* 1st time unlucky, 2nd improbable, 3rd jus= t broken */ + struct d350_desc *desc =3D dch->desc; =20 hi_new =3D readl_relaxed(dch->base + CH_XSIZEHI); do { @@ -329,10 +370,26 @@ static u32 d350_get_residue(struct d350_chan *dch) hi_new =3D readl_relaxed(dch->base + CH_XSIZEHI); } while (xsizehi !=3D hi_new && --retries); =20 + hi_new =3D readl_relaxed(dch->base + CH_LINKADDRHI); + do { + linkaddrhi =3D hi_new; + linkaddr =3D readl_relaxed(dch->base + CH_LINKADDR); + hi_new =3D readl_relaxed(dch->base + CH_LINKADDRHI); + } while (linkaddrhi !=3D hi_new && --retries); + + for (i =3D 0; i < desc->sglen; i++) { + if (desc->sg[i].phys =3D=3D (((u64)linkaddrhi << 32) | (linkaddr & ~CH_L= INKADDR_EN))) + sgcur =3D i; + } + res =3D FIELD_GET(CH_XY_DES, xsize); res |=3D FIELD_GET(CH_XY_DES, xsizehi) << 16; + res <<=3D desc->sg[sgcur].tsz; + + for (i =3D sgcur + 1; i < desc->sglen; i++) + res +=3D (((u32)desc->sg[i].xsizehi << 16 | desc->sg[i].xsize) << desc->= sg[i].tsz); =20 - return res << dch->desc->tsz; + return res; } =20 static int d350_terminate_all(struct dma_chan *chan) @@ -365,7 +422,13 @@ static void d350_synchronize(struct dma_chan *chan) =20 static u32 d350_desc_bytes(struct d350_desc *desc) { - return ((u32)desc->xsizehi << 16 | desc->xsize) << desc->tsz; + int i; + u32 bytes =3D 0; + + for (i =3D 0; i < desc->sglen; i++) + bytes +=3D (((u32)desc->sg[i].xsizehi << 16 | desc->sg[i].xsize) << desc= ->sg[i].tsz); + + return bytes; } =20 static enum dma_status d350_tx_status(struct dma_chan *chan, dma_cookie_t = cookie, @@ -415,8 +478,8 @@ static void d350_start_next(struct d350_chan *dch) dch->cookie =3D dch->desc->vd.tx.cookie; dch->residue =3D d350_desc_bytes(dch->desc); =20 - hdr =3D dch->desc->command[0]; - reg =3D &dch->desc->command[1]; + hdr =3D dch->desc->sg[0].command[0]; + reg =3D &dch->desc->sg[0].command[1]; =20 if (hdr & LINK_INTREN) writel_relaxed(*reg++, dch->base + CH_INTREN); @@ -512,11 +575,29 @@ static irqreturn_t d350_irq(int irq, void *data) static int d350_alloc_chan_resources(struct dma_chan *chan) { struct d350_chan *dch =3D to_d350_chan(chan); - int ret =3D request_irq(dch->irq, d350_irq, IRQF_SHARED, - dev_name(&dch->vc.chan.dev->device), dch); - if (!ret) - writel_relaxed(CH_INTREN_DONE | CH_INTREN_ERR, dch->base + CH_INTREN); + int ret; + + dch->cmd_pool =3D dma_pool_create(dma_chan_name(chan), + chan->device->dev, + D350_MAX_CMDS * sizeof(u32), + sizeof(u32), 0); + if (!dch->cmd_pool) { + dev_err(chan->device->dev, "No memory for cmd pool\n"); + return -ENOMEM; + } + + ret =3D request_irq(dch->irq, d350_irq, 0, + dev_name(&dch->vc.chan.dev->device), dch); + if (ret < 0) + goto err_irq; + + writel_relaxed(CH_INTREN_DONE | CH_INTREN_ERR, dch->base + CH_INTREN); + + return 0; =20 +err_irq: + dma_pool_destroy(dch->cmd_pool); + dch->cmd_pool =3D NULL; return ret; } =20 @@ -527,6 +608,8 @@ static void d350_free_chan_resources(struct dma_chan *c= han) writel_relaxed(0, dch->base + CH_INTREN); free_irq(dch->irq, dch); vchan_free_chan_resources(&dch->vc); + dma_pool_destroy(dch->cmd_pool); + dch->cmd_pool =3D NULL; } =20 static int d350_probe(struct platform_device *pdev) --=20 2.50.0