Subject: [PATCH 2/3] nvmem: zynqmp_nvmem: Use streaming DMA with single kmalloc block

From: Harsh Jain <[email-masked]>
Date: Thu, 28 May 2026 12:13:22 +0530

From: Harish Ediga <[email-masked]>

Coherent buffers are required only when the device and host update
memory in parallel, which is not the case here. Replace the coherent
buffer with the streaming DMA API and combine the two allocations
into a single kmalloc block.

Signed-off-by: Harish Ediga <[email-masked]>
Co-developed-by: Harsh Jain <[email-masked]>
Signed-off-by: Harsh Jain <[email-masked]>
---
 drivers/nvmem/zynqmp_nvmem.c | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c
index 6be00a2be9e4..e8ab4ce23fb9 100644
--- a/drivers/nvmem/zynqmp_nvmem.c
+++ b/drivers/nvmem/zynqmp_nvmem.c
@@ -60,14 +60,13 @@ static int zynqmp_efuse_access(void *context, unsigned int offset,
 			       void *val, size_t bytes, enum efuse_access flag,
 			       unsigned int pufflag)
 {
+	size_t words = bytes / WORD_INBYTES;
 	struct device *dev = context;
 	struct xilinx_efuse *efuse;
 	dma_addr_t dma_addr;
-	dma_addr_t dma_buf;
-	size_t words = bytes / WORD_INBYTES;
-	int ret;
 	unsigned int value;
 	char *data;
+	int ret;
 
 	if (bytes % WORD_INBYTES != 0) {
 		dev_err(dev, "Bytes requested should be word aligned\n");
@@ -95,18 +94,18 @@ static int zynqmp_efuse_access(void *context, unsigned int offset,
 		}
 	}
 
-	efuse = dma_alloc_coherent(dev, sizeof(struct xilinx_efuse),
-				   &dma_addr, GFP_KERNEL);
+	efuse = kmalloc(sizeof(*efuse) + bytes, GFP_KERNEL);
 	if (!efuse)
 		return -ENOMEM;
 
-	data = dma_alloc_coherent(dev, bytes,
-				  &dma_buf, GFP_KERNEL);
-	if (!data) {
-		ret = -ENOMEM;
-		goto efuse_data_fail;
+	dma_addr = dma_map_single(dev, efuse, sizeof(*efuse) + bytes,
+				  DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(dev, dma_addr)) {
+		kfree(efuse);
+		return -ENOMEM;
 	}
 
+	data = (char *)efuse + sizeof(*efuse);
 	if (flag == EFUSE_WRITE) {
 		memcpy(data, val, bytes);
 		efuse->flag = EFUSE_WRITE;
@@ -114,12 +113,18 @@ static int zynqmp_efuse_access(void *context, unsigned int offset,
 		efuse->flag = EFUSE_READ;
 	}
 
-	efuse->src = dma_buf;
+	efuse->src = dma_addr + sizeof(*efuse);
 	efuse->size = words;
 	efuse->offset = offset;
 	efuse->pufuserfuse = pufflag;
 
+	/* Sync DMA address updated after mapping*/
+	dma_sync_single_for_device(dev, dma_addr, sizeof(*efuse) + bytes,
+				   DMA_BIDIRECTIONAL);
 	zynqmp_pm_efuse_access(dma_addr, (u32 *)&ret);
+	dma_unmap_single(dev, dma_addr, sizeof(*efuse) + bytes,
+			 DMA_BIDIRECTIONAL);
+
 	if (ret != 0) {
 		if (ret == EFUSE_NOT_ENABLED) {
 			dev_err(dev, "efuse access is not enabled\n");
@@ -133,12 +138,9 @@ static int zynqmp_efuse_access(void *context, unsigned int offset,
 
 	if (flag == EFUSE_READ)
 		memcpy(val, data, bytes);
+
 efuse_access_err:
-	dma_free_coherent(dev, bytes,
-			  data, dma_buf);
-efuse_data_fail:
-	dma_free_coherent(dev, sizeof(struct xilinx_efuse),
-			  efuse, dma_addr);
+	kfree(efuse);
 
 	return ret;
 }
-- 
2.34.1