From f6313ae5c4877cd6777ef7210e2ff7497c3c1026 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Wed, 8 Jul 2026 16:10:21 +0300 Subject: [PATCH] nvmed: multiple I/O queue pairs + Set Features / Number of Queues Replaced single I/O queue pair with dynamic allocation of up to 8 pairs using NVMe Set Features command (Feature ID 0x07, Number of Queues). Cross-referenced with Linux 7.1 nvme_set_queue_count() in drivers/nvme/host/core.c. Controller advertises max SQ/CQ count; driver creates min(requested, allocated, 8) queue pairs for parallel I/O submission. Each pair gets a unique interrupt vector (round-robin across 4 MSI-X vectors). Previous behavior: hardcoded qid=1 only. New behavior: qid 1..N based on controller capabilities. Improves I/O throughput on multi-core systems by enabling concurrent command submission across queues. --- drivers/storage/nvmed/src/nvme/cmd.rs | 18 +++++++++++ drivers/storage/nvmed/src/nvme/mod.rs | 45 ++++++++++++++++++--------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/drivers/storage/nvmed/src/nvme/cmd.rs b/drivers/storage/nvmed/src/nvme/cmd.rs index b3567d9923..80aad3d250 100644 --- a/drivers/storage/nvmed/src/nvme/cmd.rs +++ b/drivers/storage/nvmed/src/nvme/cmd.rs @@ -159,4 +159,22 @@ impl NvmeCmd { cdw15: 0, } } + + pub fn set_features_num_queues(cid: u16, nsid: u32, ncqr: u16, nsqr: u16) -> Self { + Self { + opcode: 9, // Set Features + flags: 0, + cid, + nsid, + _rsvd: 0, + mptr: 0, + dptr: [0, 0], + cdw10: 0x07, // Feature ID: Number of Queues + cdw11: ((ncqr as u32) << 16) | (nsqr as u32), + cdw12: 0, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } } diff --git a/drivers/storage/nvmed/src/nvme/mod.rs b/drivers/storage/nvmed/src/nvme/mod.rs index 682ee93329..2bd517e5ea 100644 --- a/drivers/storage/nvmed/src/nvme/mod.rs +++ b/drivers/storage/nvmed/src/nvme/mod.rs @@ -423,21 +423,36 @@ impl Nvme { namespaces.insert(nsid, self.identify_namespace(nsid).await); } - // TODO: Multiple queues - let cq = self.create_io_completion_queue(1, Some(0)).await; - log::trace!("created compq"); - let sq = self.create_io_submission_queue(1, 1).await; - log::trace!("created subq"); - self.thread_ctxts - .read() - .get(&0) - .unwrap() - .lock() - .queues - .borrow_mut() - .insert(1, (sq, cq)); - self.sq_ivs.write().insert(1, 0); - self.cq_ivs.write().insert(1, 0); + // NVMe Set Features / Number of Queues (Feature ID 0x07). + // Linux 7.1 reference: drivers/nvme/host/core.c nvme_set_queue_count(). + // Request max I/O queues from controller, allocate up to + // min(requested, allocated, CPU_COUNT) queue pairs. + let nvme_queue_count = self + .submit_and_complete_admin_command(|cid| { + NvmeCmd::set_features_num_queues(cid, 0, 64, 64) + }) + .await; + let ncqr = nvme_queue_count.command_specific; + let nsqr = ncqr >> 16; + let ncqr = ncqr & 0xFFFF; + let n_queues = (nsqr.min(ncqr) as usize).min(8).max(1); + log::info!("nvmed: controller supports {} SQ / {} CQ, creating {} I/O queue pairs", nsqr, ncqr, n_queues); + + for qid in 1..=n_queues as u16 { + let cq = self.create_io_completion_queue(qid, Some((qid - 1) as u16 % 4)).await; + let sq = self.create_io_submission_queue(qid, qid).await; + log::trace!("nvmed: created I/O queue pair qid={}", qid); + self.thread_ctxts + .read() + .get(&0) + .unwrap() + .lock() + .queues + .borrow_mut() + .insert(qid, (sq, cq)); + self.sq_ivs.write().insert(qid, (qid - 1) as u16 % 4); + self.cq_ivs.write().insert(qid, (qid - 1) as u16 % 4); + } namespaces }