On 5/19/26 05:56, Prashant Kamble wrote:
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.

Signed-off-by: Prashant Kamble <[email protected]>
---
  drivers/nvme/nvme.c | 9 +++++----
  1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index 4f9473367d3..298010de536 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -456,6 +456,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 +474,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));
+       invalidate_dcache_range(orig_dma_addr,
+                               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));
+               invalidate_dcache_range(orig_dma_addr,
+                                       orig_dma_addr + sizeof(struct 
nvme_id_ctrl));

The fix is good, but I think this is not enough, the page_size used in this 
function is
the NVMe page_size, not the host CPU cacheline size, so the dma_addr could not 
be aligned
on a proper page boundary and the invalidate op could be a no-op.

The proper way to do that is like I added into dwc3:
static inline void dwc3_invalidate_cache(uintptr_t addr, int length)
{
        uintptr_t start_addr = (uintptr_t)addr & ~(CACHELINE_SIZE - 1);
        uintptr_t end_addr = ALIGN((uintptr_t)addr + length, CACHELINE_SIZE);

        invalidate_dcache_range((unsigned long)start_addr, (unsigned 
long)end_addr);
}

Neil

return ret;
  }

Reply via email to