diff options
| author | Tom Rini <[email protected]> | 2026-06-04 10:06:42 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-06-04 10:06:42 -0600 |
| commit | 74007f24a3aca13b70da6a2c098b830ad9e60804 (patch) | |
| tree | 3232d1f6c40a47689bfa62e329020a44761d58a6 | |
| parent | 31c2bb0cd1832f1030c42fbf588e7c4911e619dc (diff) | |
| parent | 389363d287585d8135a554c4419a4f580346b9f8 (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.c | 50 |
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: |
