[PATCH v1 2/5] drivers: nvme: Implement NVMe flush command (0x0)
dmukhin at ford.com
dmukhin at ford.com
Thu May 28 03:20:53 CEST 2026
From: Denis Mukhin <dmukhin at ford.com>
Add flush command implementation along with a high-level
disk_blk_flush() API to be called at certain checkpoints
during the boot (e.g. updating custom bootflow flags stored
on NVMe).
Signed-off-by: Denis Mukhin <dmukhin at ford.com>
---
disk/disk-uclass.c | 6 ++++++
drivers/block/blk-uclass.c | 18 ++++++++++++++++++
drivers/nvme/nvme.c | 20 ++++++++++++++++++++
include/blk.h | 28 ++++++++++++++++++++++++++++
include/part.h | 8 ++++++++
5 files changed, 80 insertions(+)
diff --git a/disk/disk-uclass.c b/disk/disk-uclass.c
index ee3cc4407d76..b04b6306e5f2 100644
--- a/disk/disk-uclass.c
+++ b/disk/disk-uclass.c
@@ -122,6 +122,11 @@ unsigned long disk_blk_erase(struct udevice *dev, lbaint_t start,
blkcnt);
}
+unsigned long disk_blk_flush(struct udevice *dev)
+{
+ return blk_flush(dev_get_parent(dev));
+}
+
UCLASS_DRIVER(partition) = {
.id = UCLASS_PARTITION,
.per_device_plat_auto = sizeof(struct disk_part),
@@ -132,6 +137,7 @@ static const struct blk_ops blk_part_ops = {
.read = disk_blk_read,
.write = disk_blk_write,
.erase = disk_blk_erase,
+ .flush = disk_blk_flush,
};
U_BOOT_DRIVER(blk_partition) = {
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index 73c24fd91763..0be1fdab1ba5 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -514,6 +514,19 @@ long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
return ops->erase(dev, start, blkcnt);
}
+long blk_flush(struct udevice *dev)
+{
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
+ const struct blk_ops *ops = blk_get_ops(dev);
+
+ if (!ops->flush)
+ return -ENOSYS;
+
+ blkcache_invalidate(desc->uclass_id, desc->devnum);
+
+ return ops->flush(dev);
+}
+
ulong blk_dread(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
void *buffer)
{
@@ -531,6 +544,11 @@ ulong blk_derase(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt)
return blk_erase(desc->bdev, start, blkcnt);
}
+ulong blk_dflush(struct blk_desc *desc)
+{
+ return blk_flush(desc->bdev);
+}
+
int blk_find_from_parent(struct udevice *parent, struct udevice **devp)
{
struct udevice *dev;
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index c3c44e50f19a..d9f099a11593 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -819,9 +819,29 @@ static ulong nvme_blk_write(struct udevice *udev, lbaint_t blknr,
return nvme_blk_rw(udev, blknr, blkcnt, (void *)buffer, false);
}
+/*
+ * NVM Flush command (opcode 0x00).
+ *
+ * Applies to a single namespace; the controller must commit all dirty
+ * data for that namespace to storage before completing the command.
+ */
+static ulong nvme_blk_flush(struct udevice *udev)
+{
+ struct nvme_ns *ns = dev_get_priv(udev);
+ struct nvme_dev *dev = ns->dev;
+ struct nvme_command c;
+
+ memset(&c, 0, sizeof(c));
+ c.common.opcode = nvme_cmd_flush;
+ c.common.nsid = cpu_to_le32(ns->ns_id);
+
+ return nvme_submit_sync_cmd(dev->queues[NVME_IO_Q], &c, NULL, IO_TIMEOUT);
+}
+
static const struct blk_ops nvme_blk_ops = {
.read = nvme_blk_read,
.write = nvme_blk_write,
+ .flush = nvme_blk_flush,
};
U_BOOT_DRIVER(nvme_blk) = {
diff --git a/include/blk.h b/include/blk.h
index 8d1b70cabd31..3e2160a1ae4d 100644
--- a/include/blk.h
+++ b/include/blk.h
@@ -99,6 +99,7 @@ struct blk_desc {
unsigned long (*block_erase)(struct blk_desc *block_dev,
lbaint_t start,
lbaint_t blkcnt);
+ unsigned long (*block_flush)(struct blk_desc *block_dev);
void *priv; /* driver private struct pointer */
#endif
};
@@ -275,6 +276,14 @@ struct blk_ops {
*/
int (*buffer_aligned)(struct udevice *dev, struct bounce_buffer *state);
#endif /* CONFIG_BOUNCE_BUFFER */
+
+ /**
+ * flush() - commit all dirty data to storage
+ *
+ * @dev: Device to flush
+ * @return 0 if OK, -ve on error
+ */
+ unsigned long (*flush)(struct udevice *dev);
};
#if CONFIG_IS_ENABLED(BLK)
@@ -291,6 +300,7 @@ unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
lbaint_t blkcnt, const void *buffer);
unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
lbaint_t blkcnt);
+unsigned long blk_dflush(struct blk_desc *block_dev);
#endif /* BLK */
@@ -331,6 +341,14 @@ long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
*/
long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt);
+/**
+ * blk_flush() - Commit data to a block device
+ *
+ * @dev: Device to flush
+ * @return 0 if operation succeeded, or -ve on error.
+ */
+long blk_flush(struct udevice *dev);
+
/**
* blk_find_device() - Find a block device
*
@@ -559,6 +577,16 @@ static inline ulong blk_derase(struct blk_desc *block_dev, lbaint_t start,
return block_dev->block_erase(block_dev, start, blkcnt);
}
+static inline ulong blk_dflush(struct blk_desc *block_dev)
+{
+ blkcache_invalidate(block_dev->uclass_id, block_dev->devnum);
+
+ if (block_dev->block_flush)
+ return block_dev->block_flush(block_dev);
+
+ return 0;
+}
+
/**
* struct blk_driver - Driver for block interface types
*
diff --git a/include/part.h b/include/part.h
index 15daacd7faaa..63982d7b9370 100644
--- a/include/part.h
+++ b/include/part.h
@@ -454,6 +454,14 @@ ulong disk_blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
*/
ulong disk_blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt);
+/**
+ * disk_blk_flush() - commit data to a disk
+ *
+ * @dev: Device to flush
+ * Return: 0 success, or -ve error number (see the IS_ERR_VALUE() macro
+ */
+ulong disk_blk_flush(struct udevice *dev);
+
/*
* We don't support printing partition information in SPL and only support
* getting partition information in a few cases.
--
2.54.0
More information about the U-Boot
mailing list