From: Joel Granados <joel.granados@kernel.org>
To: Keith Busch <kbusch@kernel.org>, Jens Axboe <axboe@kernel.dk>,
Christoph Hellwig <hch@lst.de>, Sagi Grimberg <sagi@grimberg.me>,
Chaitanya Kulkarni <chaitanyak@nvidia.com>,
Jason Gunthorpe <jgg@ziepe.ca>
Cc: linux-nvme@lists.infradead.org, linux-kernel@vger.kernel.org,
Joel Granados <joel.granados@kernel.org>
Subject: [PATCH RFC v2 12/14] nvme: Update the controller with the CDQ set-feature cmd
Date: Fri, 24 Jul 2026 13:11:06 +0200 [thread overview]
Message-ID: <20260724-jag-cdq-lkml-v2-12-659a7449e849@kernel.org> (raw)
In-Reply-To: <20260724-jag-cdq-lkml-v2-0-659a7449e849@kernel.org>
After advancing the queue head, send the new head position to the
controller using an NVMe set feature command. Avoid unnecessary wait on
the read by not waiting for command completion.
sf_lock serializes reads that finish before the in-flight set feature has
completed; in these cases the cmd will be resent after completion of the
previous one.
Also, re-send the set feature command right after returning and seeing
that the host head has actually moved forward since the last time the
command was sent.
Signed-off-by: Joel Granados <joel.granados@kernel.org>
---
drivers/nvme/host/cdq.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++
drivers/nvme/host/cdq.h | 14 ++++++++
2 files changed, 106 insertions(+)
diff --git a/drivers/nvme/host/cdq.c b/drivers/nvme/host/cdq.c
index 36107cf2fe11ff212d5b02dd5513fe02e3ae8f81..8e59c16ddf63df4977e1bd869be1e3a7ad19b9c5 100644
--- a/drivers/nvme/host/cdq.c
+++ b/drivers/nvme/host/cdq.c
@@ -202,6 +202,90 @@ static size_t nvme_advance_cdq(struct cdq_nvme_queue *cdq, size_t max_nrbyte)
return target_nbyte;
}
+static void nvme_submit_sfcmd_cdq(struct cdq_nvme_queue *cdq);
+
+/* updates cntl_head, exits sf_inflight and re-arms if needed */
+static enum rq_end_io_ret nvme_endio_sfcmd_cdq(struct request *rq,
+ blk_status_t status,
+ const struct io_comp_batch *iob)
+{
+ struct cdq_nvme_queue *cdq = rq->end_io_data;
+ unsigned long flags;
+ bool rearm = false;
+
+ WRITE_ONCE(cdq->cntl_head, cdq->sent_head);
+ blk_mq_free_request(rq);
+
+ spin_lock_irqsave(&cdq->sf_lock, flags);
+ cdq->sf_inflight = false;
+ /* cntl_head was just written above, plain read under the lock. */
+ if (READ_ONCE(cdq->host_head) != cdq->cntl_head) {
+ cdq->sf_inflight = true;
+ rearm = true;
+ }
+ spin_unlock_irqrestore(&cdq->sf_lock, flags);
+
+ /* Re-arm (takes its own ref) before dropping ours, so cdq stays alive. */
+ if (rearm)
+ nvme_submit_sfcmd_cdq(cdq);
+
+ nvme_cdq_put(cdq);
+ return RQ_END_IO_NONE;
+}
+
+/* Inform ctrl that head as advance by sending a CDQ set-feature command*/
+static void nvme_submit_sfcmd_cdq(struct cdq_nvme_queue *cdq)
+{
+ struct nvme_command c = { };
+ struct request *rq;
+ unsigned long flags;
+ u32 head = READ_ONCE(cdq->host_head);
+
+ c.features.opcode = nvme_admin_set_features;
+ c.features.fid = cpu_to_le32(NVME_FEAT_CDQ);
+ c.features.dword11 = cpu_to_le32(cdq->id & NVME_FEAT_CDQ_ID_MASK);
+ c.features.dword12 = cpu_to_le32(head);
+
+ rq = blk_mq_alloc_request(cdq->ctrl->admin_q, nvme_req_op(&c),
+ BLK_MQ_REQ_NOWAIT);
+ if (IS_ERR(rq)) {
+ /*
+ * No admin tag right now and we cannot sleep. Drop the slot; the
+ * next read() will re-arm.
+ */
+ spin_lock_irqsave(&cdq->sf_lock, flags);
+ cdq->sf_inflight = false;
+ spin_unlock_irqrestore(&cdq->sf_lock, flags);
+ return;
+ }
+
+ cdq->sent_head = head;
+ nvme_init_request(rq, &c);
+ rq->end_io = nvme_endio_sfcmd_cdq;
+ rq->end_io_data = cdq;
+
+ /* Pin cdq for the lifetime of the command */
+ nvme_cdq_get(cdq);
+ blk_execute_rq_nowait(rq, false);
+}
+
+/* submit set feature if none are in-flight */
+static void nvme_kick_cdq(struct cdq_nvme_queue *cdq)
+{
+ unsigned long flags;
+ bool submit = false;
+
+ spin_lock_irqsave(&cdq->sf_lock, flags);
+ if (!cdq->sf_inflight) {
+ cdq->sf_inflight = true;
+ submit = true;
+ }
+ spin_unlock_irqrestore(&cdq->sf_lock, flags);
+
+ if (submit)
+ nvme_submit_sfcmd_cdq(cdq);
+}
+
static ssize_t nvme_traversecopy_cdq(struct cdq_nvme_queue *cdq, size_t max_nrbyte,
void *priv_data)
{
@@ -231,6 +315,13 @@ static ssize_t nvme_traversecopy_cdq(struct cdq_nvme_queue *cdq, size_t max_nrby
}
out:
+ /*
+ * host_head advanced past consumed entries; tell the controller its head
+ * can move up. Decoupled from this read: the set-feature admin
+ * round-trip must not delay the data path.
+ */
+ if (copied_nbyte)
+ nvme_kick_cdq(cdq);
return copied_nbyte;
err_out:
@@ -416,6 +507,7 @@ int nvme_create_cdq(struct nvme_ctrl *ctrl, const u32 entry_nr, const u16 mc_id)
cdq->mc_id = mc_id;
cdq->ctrl = ctrl;
cdq->size_nbyte = (u32)size_nbyte;
+ spin_lock_init(&cdq->sf_lock);
ret = nvme_create_cdq_backing(cdq);
if (ret) {
diff --git a/drivers/nvme/host/cdq.h b/drivers/nvme/host/cdq.h
index 96f208264c6144d26aa4ffc34854bb16d3f19af9..893aeefb2dfc2c25f390e43eb508067b34dce31f 100644
--- a/drivers/nvme/host/cdq.h
+++ b/drivers/nvme/host/cdq.h
@@ -50,8 +50,22 @@ struct cdq_nvme_queue {
/* How far the CDQ was consumed by the host */
u32 host_head;
+
+ /*
+ * Value sent by the in-flight set-feature cmd
+ * Differs from cntl_head until set-feature cmd completes
+ */
+ u32 sent_head;
+
+ /* Last acked CDQ head update. Trails host_head.*/
+ u32 cntl_head;
+
u8 phase_bit;
+ /* sf_* controlls if the feature set cmd is done or is still inflight */
+ spinlock_t sf_lock;
+ bool sf_inflight;
+
/* Manage refs for read FD and controller xarray */
struct kref ref;
};
--
2.50.1
next prev parent reply other threads:[~2026-07-24 11:11 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-24 11:10 [PATCH RFC v2 00/14] nvme: Controller Data Queue (CDQ) support Joel Granados
2026-07-24 11:10 ` [PATCH RFC v2 01/14] nvme: Add NVME_AER_ONE_SHOT callback handler Joel Granados
2026-07-24 11:10 ` [PATCH RFC v2 02/14] nvme: Add NVMe Controller Data Queue command Joel Granados
2026-07-24 11:10 ` [PATCH RFC v2 03/14] nvme: Add track send command Joel Granados
2026-07-24 11:10 ` [PATCH RFC v2 04/14] nvme: Add CDQ to xarray and define delete path Joel Granados
2026-07-24 11:10 ` [PATCH RFC v2 05/14] nvme: Allocate CDQ backing memory from coherent DMA chunks Joel Granados
2026-07-24 11:11 ` [PATCH RFC v2 06/14] nvme: Add file descriptor to read CDQs Joel Granados
2026-07-24 11:11 ` [PATCH RFC v2 07/14] nvme: Add the create CDQ functionality Joel Granados
2026-07-24 11:11 ` [PATCH RFC v2 08/14] nvme: Submit track send command to start/stop the CDQ Joel Granados
2026-07-24 11:11 ` [PATCH RFC v2 09/14] nvme: Coordinate CDQ backing mem and CDQ FD Joel Granados
2026-07-24 11:11 ` [PATCH RFC v2 10/14] nvme: Pin a ctrl ref to every CDQ Joel Granados
2026-07-24 11:11 ` [PATCH RFC v2 11/14] nvme: Implement CDQ traversal on the read path Joel Granados
2026-07-24 11:11 ` Joel Granados [this message]
2026-07-24 11:11 ` [PATCH RFC v2 13/14] nvme: Use eventfd for CDQ Tail pointer triggers Joel Granados
2026-07-24 11:11 ` [PATCH RFC v2 14/14] nvme: Add NVME_IOCTL_CDQ to create/delete migration CDQs Joel Granados
2026-07-29 23:48 ` [PATCH RFC v2 00/14] nvme: Controller Data Queue (CDQ) support Chaitanya Kulkarni
2026-08-03 12:38 ` Joel Granados
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260724-jag-cdq-lkml-v2-12-659a7449e849@kernel.org \
--to=joel.granados@kernel.org \
--cc=axboe@kernel.dk \
--cc=chaitanyak@nvidia.com \
--cc=hch@lst.de \
--cc=jgg@ziepe.ca \
--cc=kbusch@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=sagi@grimberg.me \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®