* [PATCH v2 0/4] nvme pci-epf target and tcp host fixes
@ 2025-02-10 22:06 Damien Le Moal
2025-02-10 22:06 ` [PATCH v2 1/4] nvmet: pci-epf: Correctly initialize CSTS when enabling the controller Damien Le Moal
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Damien Le Moal @ 2025-02-10 22:06 UTC (permalink / raw)
To: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg
All,
4 patches in this series to fix some issues with the PCI endpoint
function target driver and a trivial fix for a compilation warning with
the tcp fabrics host driver.
Changes from v1:
- Added patch 3 to fixe RCU stalls under heavy workload with the
pci-epf target driver
Damien Le Moal (4):
nvmet: pci-epf: Correctly initialize CSTS when enabling the controller
nvmet: pci-epf: Do not uselessly write the CSTS register
nvmet: pci-epf: Avoid RCU stalls under heavy workload
nvme: tcp: Fix compilation warning with W=1
drivers/nvme/host/tcp.c | 2 +-
drivers/nvme/target/pci-epf.c | 39 ++++++++++++++++++++++++++---------
2 files changed, 30 insertions(+), 11 deletions(-)
--
2.48.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/4] nvmet: pci-epf: Correctly initialize CSTS when enabling the controller
2025-02-10 22:06 [PATCH v2 0/4] nvme pci-epf target and tcp host fixes Damien Le Moal
@ 2025-02-10 22:06 ` Damien Le Moal
2025-02-10 22:06 ` [PATCH v2 2/4] nvmet: pci-epf: Do not uselessly write the CSTS register Damien Le Moal
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Damien Le Moal @ 2025-02-10 22:06 UTC (permalink / raw)
To: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg
The function nvmet_pci_epf_poll_cc_work() sets the NVME_CSTS_RDY bit of
the controller status register (CSTS) when nvmet_pci_epf_enable_ctrl()
returns success. However, since this function can be called several
times (e.g. if the host reboots), instead of setting the bit in
ctrl->csts, initialize this field to only have NVME_CSTS_RDY set.
Conversely, if nvmet_pci_epf_enable_ctrl() fails, make sure to clear all
bits from ctrl->csts.
To simplify nvmet_pci_epf_poll_cc_work(), initialize ctrl->csts to
NVME_CSTS_RDY directly inside nvmet_pci_epf_enable_ctrl() and clear this
field in that function as well in case of a failure. To be consistent,
move clearing the NVME_CSTS_RDY bit from ctrl->csts when the controller
is being disabled from nvmet_pci_epf_poll_cc_work() into
nvmet_pci_epf_disable_ctrl().
Fixes: 0faa0fe6f90e ("nvmet: New NVMe PCI endpoint function target driver")
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
---
drivers/nvme/target/pci-epf.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index ac30b42cc622..efd4623fb002 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -1822,14 +1822,14 @@ static int nvmet_pci_epf_enable_ctrl(struct nvmet_pci_epf_ctrl *ctrl)
if (ctrl->io_sqes < sizeof(struct nvme_command)) {
dev_err(ctrl->dev, "Unsupported I/O SQES %zu (need %zu)\n",
ctrl->io_sqes, sizeof(struct nvme_command));
- return -EINVAL;
+ goto err;
}
ctrl->io_cqes = 1UL << nvmet_cc_iocqes(ctrl->cc);
if (ctrl->io_cqes < sizeof(struct nvme_completion)) {
dev_err(ctrl->dev, "Unsupported I/O CQES %zu (need %zu)\n",
ctrl->io_sqes, sizeof(struct nvme_completion));
- return -EINVAL;
+ goto err;
}
/* Create the admin queue. */
@@ -1844,7 +1844,7 @@ static int nvmet_pci_epf_enable_ctrl(struct nvmet_pci_epf_ctrl *ctrl)
qsize, pci_addr, 0);
if (status != NVME_SC_SUCCESS) {
dev_err(ctrl->dev, "Failed to create admin completion queue\n");
- return -EINVAL;
+ goto err;
}
qsize = aqa & 0x00000fff;
@@ -1854,17 +1854,22 @@ static int nvmet_pci_epf_enable_ctrl(struct nvmet_pci_epf_ctrl *ctrl)
if (status != NVME_SC_SUCCESS) {
dev_err(ctrl->dev, "Failed to create admin submission queue\n");
nvmet_pci_epf_delete_cq(ctrl->tctrl, 0);
- return -EINVAL;
+ goto err;
}
ctrl->sq_ab = NVMET_PCI_EPF_SQ_AB;
ctrl->irq_vector_threshold = NVMET_PCI_EPF_IV_THRESHOLD;
ctrl->enabled = true;
+ ctrl->csts = NVME_CSTS_RDY;
/* Start polling the controller SQs. */
schedule_delayed_work(&ctrl->poll_sqs, 0);
return 0;
+
+err:
+ ctrl->csts = 0;
+ return -EINVAL;
}
static void nvmet_pci_epf_disable_ctrl(struct nvmet_pci_epf_ctrl *ctrl)
@@ -1889,6 +1894,8 @@ static void nvmet_pci_epf_disable_ctrl(struct nvmet_pci_epf_ctrl *ctrl)
/* Delete the admin queue last. */
nvmet_pci_epf_delete_sq(ctrl->tctrl, 0);
nvmet_pci_epf_delete_cq(ctrl->tctrl, 0);
+
+ ctrl->csts &= ~NVME_CSTS_RDY;
}
static void nvmet_pci_epf_poll_cc_work(struct work_struct *work)
@@ -1909,13 +1916,10 @@ static void nvmet_pci_epf_poll_cc_work(struct work_struct *work)
ret = nvmet_pci_epf_enable_ctrl(ctrl);
if (ret)
return;
- ctrl->csts |= NVME_CSTS_RDY;
}
- if (!nvmet_cc_en(new_cc) && nvmet_cc_en(old_cc)) {
+ if (!nvmet_cc_en(new_cc) && nvmet_cc_en(old_cc))
nvmet_pci_epf_disable_ctrl(ctrl);
- ctrl->csts &= ~NVME_CSTS_RDY;
- }
if (nvmet_cc_shn(new_cc) && !nvmet_cc_shn(old_cc)) {
nvmet_pci_epf_disable_ctrl(ctrl);
--
2.48.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/4] nvmet: pci-epf: Do not uselessly write the CSTS register
2025-02-10 22:06 [PATCH v2 0/4] nvme pci-epf target and tcp host fixes Damien Le Moal
2025-02-10 22:06 ` [PATCH v2 1/4] nvmet: pci-epf: Correctly initialize CSTS when enabling the controller Damien Le Moal
@ 2025-02-10 22:06 ` Damien Le Moal
2025-02-10 22:06 ` [PATCH v2 3/4] nvmet: pci-epf: Avoid RCU stalls under heavy workload Damien Le Moal
2025-02-10 22:06 ` [PATCH v2 4/4] nvme: tcp: Fix compilation warning with W=1 Damien Le Moal
3 siblings, 0 replies; 7+ messages in thread
From: Damien Le Moal @ 2025-02-10 22:06 UTC (permalink / raw)
To: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg
The function nvmet_pci_epf_poll_cc_work() will do nothing if there are
no changes to the controller configuration (CC) register. However, even
for such case, this function still calls nvmet_update_cc() and uselessly
writes the CSTS register. Avoid this by simply rescheduling the poll_cc
work if the CC register has not changed.
Also reschedule the poll_cc work if the function
nvmet_pci_epf_enable_ctrl() fails to allow the host the chance to try
again enabling the controller.
While at it, since there is no point in trying to handle the CC register
as quickly as possible, change the poll_cc work scheduling interval to
10 ms (from 5ms), to avoid excessive read accesses to that register.
Fixes: 0faa0fe6f90e ("nvmet: New NVMe PCI endpoint function target driver")
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
---
drivers/nvme/target/pci-epf.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index efd4623fb002..b646a8f468ea 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -46,7 +46,7 @@ static DEFINE_MUTEX(nvmet_pci_epf_ports_mutex);
/*
* BAR CC register and SQ polling intervals.
*/
-#define NVMET_PCI_EPF_CC_POLL_INTERVAL msecs_to_jiffies(5)
+#define NVMET_PCI_EPF_CC_POLL_INTERVAL msecs_to_jiffies(10)
#define NVMET_PCI_EPF_SQ_POLL_INTERVAL msecs_to_jiffies(5)
#define NVMET_PCI_EPF_SQ_POLL_IDLE msecs_to_jiffies(5000)
@@ -1910,12 +1910,15 @@ static void nvmet_pci_epf_poll_cc_work(struct work_struct *work)
old_cc = ctrl->cc;
new_cc = nvmet_pci_epf_bar_read32(ctrl, NVME_REG_CC);
+ if (new_cc == old_cc)
+ goto reschedule_work;
+
ctrl->cc = new_cc;
if (nvmet_cc_en(new_cc) && !nvmet_cc_en(old_cc)) {
ret = nvmet_pci_epf_enable_ctrl(ctrl);
if (ret)
- return;
+ goto reschedule_work;
}
if (!nvmet_cc_en(new_cc) && nvmet_cc_en(old_cc))
@@ -1932,6 +1935,7 @@ static void nvmet_pci_epf_poll_cc_work(struct work_struct *work)
nvmet_update_cc(ctrl->tctrl, ctrl->cc);
nvmet_pci_epf_bar_write32(ctrl, NVME_REG_CSTS, ctrl->csts);
+reschedule_work:
schedule_delayed_work(&ctrl->poll_cc, NVMET_PCI_EPF_CC_POLL_INTERVAL);
}
--
2.48.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 3/4] nvmet: pci-epf: Avoid RCU stalls under heavy workload
2025-02-10 22:06 [PATCH v2 0/4] nvme pci-epf target and tcp host fixes Damien Le Moal
2025-02-10 22:06 ` [PATCH v2 1/4] nvmet: pci-epf: Correctly initialize CSTS when enabling the controller Damien Le Moal
2025-02-10 22:06 ` [PATCH v2 2/4] nvmet: pci-epf: Do not uselessly write the CSTS register Damien Le Moal
@ 2025-02-10 22:06 ` Damien Le Moal
2025-02-13 6:09 ` Christoph Hellwig
2025-02-17 7:49 ` Sagi Grimberg
2025-02-10 22:06 ` [PATCH v2 4/4] nvme: tcp: Fix compilation warning with W=1 Damien Le Moal
3 siblings, 2 replies; 7+ messages in thread
From: Damien Le Moal @ 2025-02-10 22:06 UTC (permalink / raw)
To: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg
The delayed work item function nvmet_pci_epf_poll_sqs_work() polls all
submission queues and keeps running in a loop as long as commands are
being submitted by the host. Depending on the preemption configuration
of the kernel, under heavy command workload, this function can thus run
for more than RCU_CPU_STALL_TIMEOUT seconds, leading to a RCU stall:
rcu: INFO: rcu_sched self-detected stall on CPU
rcu: 5-....: (20998 ticks this GP) idle=4244/1/0x4000000000000000 softirq=301/301 fqs=5132
rcu: (t=21000 jiffies g=-443 q=12 ncpus=8)
CPU: 5 UID: 0 PID: 82 Comm: kworker/5:1 Not tainted 6.14.0-rc2 #1
Hardware name: Radxa ROCK 5B (DT)
Workqueue: events nvmet_pci_epf_poll_sqs_work [nvmet_pci_epf]
pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : dw_edma_device_tx_status+0xb8/0x130
lr : dw_edma_device_tx_status+0x9c/0x130
sp : ffff800080b5bbb0
x29: ffff800080b5bbb0 x28: ffff0331c5c78400 x27: ffff0331c1cd1960
x26: ffff0331c0e39010 x25: ffff0331c20e4000 x24: ffff0331c20e4a90
x23: 0000000000000000 x22: 0000000000000001 x21: 00000000005aca33
x20: ffff800080b5bc30 x19: ffff0331c123e370 x18: 000000000ab29e62
x17: ffffb2a878c9c118 x16: ffff0335bde82040 x15: 0000000000000000
x14: 000000000000017b x13: 00000000ee601780 x12: 0000000000000018
x11: 0000000000000000 x10: 0000000000000001 x9 : 0000000000000040
x8 : 00000000ee601780 x7 : 0000000105c785c0 x6 : ffff0331c1027d80
x5 : 0000000001ee7ad6 x4 : ffff0335bdea16c0 x3 : ffff0331c123e438
x2 : 00000000005aca33 x1 : 0000000000000000 x0 : ffff0331c123e410
Call trace:
dw_edma_device_tx_status+0xb8/0x130 (P)
dma_sync_wait+0x60/0xbc
nvmet_pci_epf_dma_transfer+0x128/0x264 [nvmet_pci_epf]
nvmet_pci_epf_poll_sqs_work+0x2a0/0x2e0 [nvmet_pci_epf]
process_one_work+0x144/0x390
worker_thread+0x27c/0x458
kthread+0xe8/0x19c
ret_from_fork+0x10/0x20
The solution for this is simply to explicitly allow rescheduling using
cond_resched(). Howerver, since doing so for every loop of
nvmet_pci_epf_poll_sqs_work() significantly degrades performance
(for 4K random reads using 4 I/O queues, the maximum IOPS goes down from
137 KIOPS to 110 KIOPS), call cond_resched() every second to avoid the
RCU stalls.
Fixes: 0faa0fe6f90e ("nvmet: New NVMe PCI endpoint function target driver")
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
---
drivers/nvme/target/pci-epf.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index b646a8f468ea..565d2bd36dcd 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -1694,6 +1694,7 @@ static void nvmet_pci_epf_poll_sqs_work(struct work_struct *work)
struct nvmet_pci_epf_ctrl *ctrl =
container_of(work, struct nvmet_pci_epf_ctrl, poll_sqs.work);
struct nvmet_pci_epf_queue *sq;
+ unsigned long limit = jiffies;
unsigned long last = 0;
int i, nr_sqs;
@@ -1708,6 +1709,16 @@ static void nvmet_pci_epf_poll_sqs_work(struct work_struct *work)
nr_sqs++;
}
+ /*
+ * If we have been running for a while, reschedule to let other
+ * tasks run and to avoid RCU stalls.
+ */
+ if (time_is_before_jiffies(limit + secs_to_jiffies(1))) {
+ cond_resched();
+ limit = jiffies;
+ continue;
+ }
+
if (nr_sqs) {
last = jiffies;
continue;
--
2.48.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 4/4] nvme: tcp: Fix compilation warning with W=1
2025-02-10 22:06 [PATCH v2 0/4] nvme pci-epf target and tcp host fixes Damien Le Moal
` (2 preceding siblings ...)
2025-02-10 22:06 ` [PATCH v2 3/4] nvmet: pci-epf: Avoid RCU stalls under heavy workload Damien Le Moal
@ 2025-02-10 22:06 ` Damien Le Moal
3 siblings, 0 replies; 7+ messages in thread
From: Damien Le Moal @ 2025-02-10 22:06 UTC (permalink / raw)
To: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg
When compiling with W=1, a warning result for the function
nvme_tcp_set_queue_io_cpu():
host/tcp.c:1578: warning: Function parameter or struct member 'queue'
not described in 'nvme_tcp_set_queue_io_cpu'
host/tcp.c:1578: warning: expecting prototype for Track the number of
queues assigned to each cpu using a global per(). Prototype was for
nvme_tcp_set_queue_io_cpu() instead
Avoid this warning by using the regular comment format for the function
nvme_tcp_set_queue_io_cpu() instead of the kdoc comment format.
Fixes: 32193789878c ("nvme-tcp: Fix I/O queue cpu spreading for multiple controllers")
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
---
drivers/nvme/host/tcp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 841238f38fdd..4162893d4939 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -1565,7 +1565,7 @@ static bool nvme_tcp_poll_queue(struct nvme_tcp_queue *queue)
ctrl->io_queues[HCTX_TYPE_POLL];
}
-/**
+/*
* Track the number of queues assigned to each cpu using a global per-cpu
* counter and select the least used cpu from the mq_map. Our goal is to spread
* different controllers I/O threads across different cpu cores.
--
2.48.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 3/4] nvmet: pci-epf: Avoid RCU stalls under heavy workload
2025-02-10 22:06 ` [PATCH v2 3/4] nvmet: pci-epf: Avoid RCU stalls under heavy workload Damien Le Moal
@ 2025-02-13 6:09 ` Christoph Hellwig
2025-02-17 7:49 ` Sagi Grimberg
1 sibling, 0 replies; 7+ messages in thread
From: Christoph Hellwig @ 2025-02-13 6:09 UTC (permalink / raw)
To: Damien Le Moal; +Cc: linux-nvme, Keith Busch, Christoph Hellwig, Sagi Grimberg
On Tue, Feb 11, 2025 at 07:06:56AM +0900, Damien Le Moal wrote:
> The solution for this is simply to explicitly allow rescheduling using
> cond_resched(). Howerver, since doing so for every loop of
s/Howerver/However/
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 3/4] nvmet: pci-epf: Avoid RCU stalls under heavy workload
2025-02-10 22:06 ` [PATCH v2 3/4] nvmet: pci-epf: Avoid RCU stalls under heavy workload Damien Le Moal
2025-02-13 6:09 ` Christoph Hellwig
@ 2025-02-17 7:49 ` Sagi Grimberg
1 sibling, 0 replies; 7+ messages in thread
From: Sagi Grimberg @ 2025-02-17 7:49 UTC (permalink / raw)
To: Damien Le Moal, linux-nvme, Keith Busch, Christoph Hellwig
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-02-17 7:49 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-10 22:06 [PATCH v2 0/4] nvme pci-epf target and tcp host fixes Damien Le Moal
2025-02-10 22:06 ` [PATCH v2 1/4] nvmet: pci-epf: Correctly initialize CSTS when enabling the controller Damien Le Moal
2025-02-10 22:06 ` [PATCH v2 2/4] nvmet: pci-epf: Do not uselessly write the CSTS register Damien Le Moal
2025-02-10 22:06 ` [PATCH v2 3/4] nvmet: pci-epf: Avoid RCU stalls under heavy workload Damien Le Moal
2025-02-13 6:09 ` Christoph Hellwig
2025-02-17 7:49 ` Sagi Grimberg
2025-02-10 22:06 ` [PATCH v2 4/4] nvme: tcp: Fix compilation warning with W=1 Damien Le Moal
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.