summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKartik Rajput <kkartik@nvidia.com>2026-04-22 09:41:34 +0300
committerVinod Koul <vkoul@kernel.org>2026-06-08 15:13:48 +0300
commit4651df83b6c796daead3447e8fd874322918ee4f (patch)
tree354eb7fd314266a789c6d132a7c9ae6d93ab1b62
parentb2d44b3ea95e10315559d8deedd8af2977c7f534 (diff)
downloadlinux-4651df83b6c796daead3447e8fd874322918ee4f.tar.xz
dmaengine: tegra: Fix burst size calculation
Currently, the Tegra GPC DMA hardware requires the transfer length to be a multiple of the max burst size configured for the channel. When a client requests a transfer where the length is not evenly divisible by the configured max burst size, the DMA hangs with partial burst at the end. Fix this by reducing the burst size to the largest power-of-2 value that evenly divides the transfer length. For example, a 40-byte transfer with a 16-byte max burst will now use an 8-byte burst (40 / 8 = 5 complete bursts) instead of causing a hang. This issue was observed with the PL011 UART driver where TX DMA transfers of arbitrary lengths were stuck. Fixes: ee17028009d4 ("dmaengine: tegra: Add tegra gpcdma driver") Cc: stable@vger.kernel.org Signed-off-by: Kartik Rajput <kkartik@nvidia.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Reviewed-by: Jon Hunter <jonathanh@nvidia.com> Link: https://patch.msgid.link/20260422064134.1323610-1-kkartik@nvidia.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
-rw-r--r--drivers/dma/tegra186-gpc-dma.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
index c364c278a8b0..64cedef1050a 100644
--- a/drivers/dma/tegra186-gpc-dma.c
+++ b/drivers/dma/tegra186-gpc-dma.c
@@ -835,6 +835,13 @@ static unsigned int get_burst_size(struct tegra_dma_channel *tdc,
* len to calculate the optimum burst size
*/
burst_byte = burst_size ? burst_size * slave_bw : len;
+
+ /*
+ * Find the largest burst size that evenly divides the transfer length.
+ * The hardware requires the transfer length to be a multiple of the
+ * burst size - partial bursts are not supported.
+ */
+ burst_byte = min(burst_byte, 1U << __ffs(len));
burst_mmio_width = burst_byte / 4;
if (burst_mmio_width < TEGRA_GPCDMA_MMIOSEQ_BURST_MIN)