From: Prashant Kamble Date: Sun, 24 May 2026 10:06:21 +0000 (+0530) Subject: nvme: fix dcache invalidation range in identify command X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=29c40bb2a13ed1c294497044e2299cc0a511ce32;p=thirdparty%2Fu-boot.git nvme: fix dcache invalidation range in identify command When the identify buffer crosses a page boundary, PRP2 is used and dma_addr is advanced to the second page: dma_addr += (page_size - offset); The subsequent invalidate_dcache_range() calls then use the modified dma_addr instead of the original buffer start address. As a result, the beginning of the identify buffer is not invalidated and the invalidation range extends past the end of the buffer. Fix this by preserving the original DMA buffer address for cache invalidation. Suggested-by: Neil Armstrong Signed-off-by: Prashant Kamble Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20260524100625.11135-1-prashant.kamble223@gmail.com Signed-off-by: Neil Armstrong --- diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index 0631b190b97..da7dad9f52b 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -27,6 +27,23 @@ #define IO_TIMEOUT 30 #define MAX_PRP_POOL 512 +/** + * nvme_invalidate_cache_aligned() - invalidate cache with proper alignment + * + * Aligns cache invalidation to cacheline boundaries to ensure correct + * behavior even when the DMA buffer is not aligned to page boundaries. + * + * @addr: The start address of the buffer + * @length: The length of the buffer in bytes + */ +static inline void nvme_invalidate_cache_aligned(uintptr_t addr, int length) +{ + uintptr_t start_addr = addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN(addr + length, ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start_addr, end_addr); +} + static int nvme_wait_csts(struct nvme_dev *dev, u32 mask, u32 val) { int timeout; @@ -456,6 +473,7 @@ int nvme_identify(struct nvme_dev *dev, unsigned nsid, u32 page_size = dev->page_size; int offset = dma_addr & (page_size - 1); int length = sizeof(struct nvme_id_ctrl); + dma_addr_t orig_dma_addr = dma_addr; int ret; memset(&c, 0, sizeof(c)); @@ -473,13 +491,13 @@ int nvme_identify(struct nvme_dev *dev, unsigned nsid, c.identify.cns = cpu_to_le32(cns); - invalidate_dcache_range(dma_addr, - dma_addr + sizeof(struct nvme_id_ctrl)); + nvme_invalidate_cache_aligned((uintptr_t)orig_dma_addr, + sizeof(struct nvme_id_ctrl)); ret = nvme_submit_admin_cmd(dev, &c, NULL); if (!ret) - invalidate_dcache_range(dma_addr, - dma_addr + sizeof(struct nvme_id_ctrl)); + nvme_invalidate_cache_aligned((uintptr_t)orig_dma_addr, + sizeof(struct nvme_id_ctrl)); return ret; }