summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-06-04 10:06:42 -0600
committerTom Rini <[email protected]>2026-06-04 10:06:42 -0600
commit74007f24a3aca13b70da6a2c098b830ad9e60804 (patch)
tree3232d1f6c40a47689bfa62e329020a44761d58a6
parent31c2bb0cd1832f1030c42fbf588e7c4911e619dc (diff)
parent389363d287585d8135a554c4419a4f580346b9f8 (diff)
Merge tag 'u-boot-nvme-fixes-20260604' of https://source.denx.de/u-boot/custodians/u-boot-ufsHEADmaster
- fix dcache invalidation range in identify command - avoid deleting uncreated queues - free prp_pool on nvme_init() failure paths - Log I/O timeouts
-rw-r--r--drivers/nvme/nvme.c50
1 files changed, 33 insertions, 17 deletions
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index 0631b190b97..147a104149e 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;
@@ -182,8 +199,10 @@ static int nvme_submit_sync_cmd(struct nvme_queue *nvmeq,
if ((status & 0x01) == phase)
break;
if (timeout_us > 0 && (timer_get_us() - start_time)
- >= timeout_us)
+ >= timeout_us) {
+ pr_warn("nvme: cmd %#x timed out\n", cmd->common.command_id);
return -ETIMEDOUT;
+ }
}
ops = (struct nvme_ops *)nvmeq->dev->udev->driver->ops;
@@ -281,11 +300,6 @@ static int nvme_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id)
return nvme_submit_admin_cmd(dev, &c, NULL);
}
-static int nvme_delete_sq(struct nvme_dev *dev, u16 sqid)
-{
- return nvme_delete_queue(dev, nvme_admin_delete_sq, sqid);
-}
-
static int nvme_delete_cq(struct nvme_dev *dev, u16 cqid)
{
return nvme_delete_queue(dev, nvme_admin_delete_cq, cqid);
@@ -456,6 +470,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 +488,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;
}
@@ -545,20 +560,19 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
nvmeq->cq_vector = qid - 1;
result = nvme_alloc_cq(dev, qid, nvmeq);
if (result < 0)
- goto release_cq;
+ goto release_ret;
result = nvme_alloc_sq(dev, qid, nvmeq);
if (result < 0)
- goto release_sq;
+ goto release_cq;
nvme_init_queue(nvmeq, qid);
return result;
- release_sq:
- nvme_delete_sq(dev, qid);
release_cq:
nvme_delete_cq(dev, qid);
+ release_ret:
return result;
}
@@ -868,14 +882,14 @@ int nvme_init(struct udevice *udev)
if (!ndev->prp_pool) {
ret = -ENOMEM;
printf("Error: %s: Out of memory!\n", udev->name);
- goto free_nvme;
+ goto free_queue;
}
ndev->prp_entry_num = MAX_PRP_POOL >> 3;
ret = nvme_setup_io_queues(ndev);
if (ret) {
log_debug("Unable to setup I/O queues(err=%dE)\n", ret);
- goto free_queue;
+ goto free_prp_pool;
}
nvme_get_info_from_identify(ndev);
@@ -885,7 +899,7 @@ int nvme_init(struct udevice *udev)
id = memalign(ndev->page_size, sizeof(struct nvme_id_ns));
if (!id) {
ret = -ENOMEM;
- goto free_queue;
+ goto free_prp_pool;
}
for (int i = 1; i <= ndev->nn; i++) {
@@ -930,6 +944,8 @@ int nvme_init(struct udevice *udev)
free_id:
free(id);
+free_prp_pool:
+ free((void *)ndev->prp_pool);
free_queue:
free((void *)ndev->queues);
free_nvme: