Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dma: dma-axi-dmac: support bigger than 32bits addresses

In some supported platforms as ARCH_ZYNQMP, part of the memory is mapped
above 32bit addresses and since the DMA mask, by default, is set to 32bits,
we would need to rely on swiotlb (which incurs a performance penalty)
for the DMA mappings. Thus, we can write either the SRC or DEST high
addresses with 1's and read them back. The last bit set on the return
value will reflect the IP address bus width and so we can update the
device DMA mask accordingly.

While at it, support bigger that 32 bits transfers in IP without HW
scatter gather support.

Signed-off-by: Nuno Sá <nuno.sa@analog.com>
base-commit: 398035178503bf662281bbffb4bebce1460a4bc5
change-id: 20251104-axi-dmac-fixes-and-improvs-e3ad512a329c
Acked-by: Michael Hennerich <michael.hennerich@analog.com>
Link: https://patch.msgid.link/20251104-axi-dmac-fixes-and-improvs-v1-3-3e6fd9328f72@analog.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Nuno Sá and committed by
Vinod Koul
b2440442 bbcbafb9

+24
+24
drivers/dma/dma-axi-dmac.c
··· 69 69 #define AXI_DMAC_REG_START_TRANSFER 0x408 70 70 #define AXI_DMAC_REG_FLAGS 0x40c 71 71 #define AXI_DMAC_REG_DEST_ADDRESS 0x410 72 + #define AXI_DMAC_REG_DEST_ADDRESS_HIGH 0x490 72 73 #define AXI_DMAC_REG_SRC_ADDRESS 0x414 74 + #define AXI_DMAC_REG_SRC_ADDRESS_HIGH 0x494 73 75 #define AXI_DMAC_REG_X_LENGTH 0x418 74 76 #define AXI_DMAC_REG_Y_LENGTH 0x41c 75 77 #define AXI_DMAC_REG_DEST_STRIDE 0x420 ··· 273 271 if (!chan->hw_sg) { 274 272 if (axi_dmac_dest_is_mem(chan)) { 275 273 axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, sg->hw->dest_addr); 274 + axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS_HIGH, 275 + sg->hw->dest_addr >> 32); 276 276 axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, sg->hw->dst_stride); 277 277 } 278 278 279 279 if (axi_dmac_src_is_mem(chan)) { 280 280 axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, sg->hw->src_addr); 281 + axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS_HIGH, sg->hw->src_addr >> 32); 281 282 axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, sg->hw->src_stride); 282 283 } 283 284 } ··· 995 990 static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version) 996 991 { 997 992 struct axi_dmac_chan *chan = &dmac->chan; 993 + struct device *dev = dmac->dma_dev.dev; 994 + u32 mask; 995 + int ret; 998 996 999 997 axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, AXI_DMAC_FLAG_CYCLIC); 1000 998 if (axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS) == AXI_DMAC_FLAG_CYCLIC) ··· 1030 1022 dev_err(dmac->dma_dev.dev, 1031 1023 "Source memory-mapped interface not supported."); 1032 1024 return -ENODEV; 1025 + } 1026 + 1027 + if (axi_dmac_dest_is_mem(chan)) { 1028 + axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS_HIGH, 0xffffffff); 1029 + mask = axi_dmac_read(dmac, AXI_DMAC_REG_DEST_ADDRESS_HIGH); 1030 + } else { 1031 + axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS_HIGH, 0xffffffff); 1032 + mask = axi_dmac_read(dmac, AXI_DMAC_REG_SRC_ADDRESS_HIGH); 1033 + } 1034 + 1035 + mask = 32 + fls(mask); 1036 + 1037 + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(mask)); 1038 + if (ret) { 1039 + dev_err(dev, "DMA mask set error %d\n", ret); 1040 + return ret; 1033 1041 } 1034 1042 1035 1043 if (version >= ADI_AXI_PCORE_VER(4, 2, 'a'))