Re: [PATCH] nvme: make firmware activation poll interval configurable
From: guzebing
Date: Mon Jul 06 2026 - 03:24:10 EST
Hi Keith, Jens, Christoph, Sagi,
Gentle ping.
The motivation is to reduce the extra time I/O queues remain quiesced
after the controller has finished online firmware activation. In our
Gen5 NVMe SSD update test, using a 10 ms poll interval instead of the
current 100 ms interval reduced the observed completion detection time
from 311 ms to 266 ms.
Could you advise whether this is a latency issue worth addressing
upstream now? If so, would you prefer a fixed shorter polling interval
instead of a module parameter?
If the current benefit is not compelling enough, would it be better to
defer this until firmware activation times become shorter on more
devices, where the fixed 100 ms polling interval would account for a
larger part of the I/O quiesce time?
Thanks,
Guzebing
On 6/27/26 9:06 AM, guzebing wrote:
> From: Guzebing <guzebing@xxxxxxxxxxxxx>
>
> nvme_fw_act_work() polls the controller processing-paused status every
> 100 ms while firmware activation is pending. Some devices can complete
> online activation in only a few hundred milliseconds, so the fixed
> interval can add noticeable latency before the driver observes
> completion.
>
> Add an nvme_core.fw_act_poll_interval_ms module parameter to make the
> poll interval tunable. Keep the default at 100 ms to preserve existing
> behavior, and accept values from 10 ms to 100 ms so systems that need
> faster completion detection can opt in to a shorter interval.
>
> Signed-off-by: Guzebing <guzebing@xxxxxxxxxxxxx>
> ---
> We recently observed this issue while performing online firmware
> updates for Gen5 NVMe SSDs in a production environment.
>
> During firmware activation, the kernel quiesces I/O. Detecting the end
> of firmware activation earlier lets the driver unquiesce I/O earlier,
> which is important for the long-tail I/O latency of production
> workloads.
>
> Operation steps:
> nvme fw-download /dev/nvme13n1 \
> -f ./Inventec_G238B_NVME_LDD5902Q_MZWL61T9HFLT-00B07.bin
> nvme fw-commit /dev/nvme13n1 -s 0 -a 3
> nvme fw-log /dev/nvme13n1
>
> Operation device:
> Samsung PM9D3a Gen5 NVMe SSD, model MZWL67T6HBLC-00B07
> Firmware update: LDD5702Q -> LDD5902Q
>
> Operation results:
> 100 ms polling interval: 3 polls, 311 ms
> 10 ms polling interval: 24 polls, 266 ms
>
> drivers/nvme/host/core.c | 24 +++++++++++++++++++++++-
> 1 file changed, 23 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index 3b7a8f7a35426..784da06fee559 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -58,6 +58,21 @@ module_param_named(io_timeout, nvme_io_timeout, uint, 0644);
> MODULE_PARM_DESC(io_timeout, "timeout in seconds for I/O");
> EXPORT_SYMBOL_GPL(nvme_io_timeout);
>
> +#define NVME_FW_ACT_POLL_INTERVAL_MIN_MS 10
> +#define NVME_FW_ACT_POLL_INTERVAL_MAX_MS 100
> +static int fw_act_poll_interval_ms_set(const char *val,
> + const struct kernel_param *kp);
> +static const struct kernel_param_ops fw_act_poll_interval_ms_ops = {
> + .set = fw_act_poll_interval_ms_set,
> + .get = param_get_uint,
> +};
> +
> +static unsigned int fw_act_poll_interval_ms = 100;
> +module_param_cb(fw_act_poll_interval_ms, &fw_act_poll_interval_ms_ops,
> + &fw_act_poll_interval_ms, 0644);
> +MODULE_PARM_DESC(fw_act_poll_interval_ms,
> + "firmware activation polling interval in ms (10-100)");
> +
> static unsigned char shutdown_timeout = 5;
> module_param(shutdown_timeout, byte, 0644);
> MODULE_PARM_DESC(shutdown_timeout, "timeout in seconds for controller shutdown");
> @@ -106,6 +121,13 @@ module_param(disable_pi_offsets, bool, 0444);
> MODULE_PARM_DESC(disable_pi_offsets,
> "disable protection information if it has an offset");
>
> +static int fw_act_poll_interval_ms_set(const char *val,
> + const struct kernel_param *kp)
> +{
> + return param_set_uint_minmax(val, kp, NVME_FW_ACT_POLL_INTERVAL_MIN_MS,
> + NVME_FW_ACT_POLL_INTERVAL_MAX_MS);
> +}
> +
> /*
> * nvme_wq - hosts nvme related works that are not reset or delete
> * nvme_reset_wq - hosts nvme reset works
> @@ -4798,7 +4820,7 @@ static void nvme_fw_act_work(struct work_struct *work)
> nvme_try_sched_reset(ctrl);
> return;
> }
> - msleep(100);
> + msleep(READ_ONCE(fw_act_poll_interval_ms));
> }
>
> if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_CONNECTING) ||