From: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
To: <intel-wired-lan@lists.osuosl.org>
Cc: <netdev@vger.kernel.org>, <magnus.karlsson@intel.com>,
<kuba@kernel.org>, <pabeni@redhat.com>, <horms@kernel.org>,
<przemyslaw.kitszel@intel.com>, <jacob.e.keller@intel.com>
Subject: Re: [Intel-wired-lan] [PATCH iwl-net] i40e: keep q_vectors array in sync with channel count changes
Date: Thu, 16 Apr 2026 13:12:53 +0200 [thread overview]
Message-ID: <aeDENQXk8Mz1elXb@boxer> (raw)
In-Reply-To: <20260414121405.631092-1-maciej.fijalkowski@intel.com>
On Tue, Apr 14, 2026 at 02:14:05PM +0200, Maciej Fijalkowski wrote:
> For the main VSI, i40e_set_num_rings_in_vsi() always derives
> num_q_vectors from pf->num_lan_msix. At the same time, ethtool -L stores
> the user requested channel count in vsi->req_queue_pairs and the queue
> setup path uses that value for the effective number of queue pairs.
>
> This leaves queue and vector counts out of sync after shrinking channel
> count via ethtool -L. The active queue configuration is reduced, but the
> VSI still keeps the full PF-sized q_vector topology.
>
> That mismatch breaks reconfiguration flows which rely on vector/NAPI
> state matching the effective channel configuration. In particular,
> toggling /sys/class/net/<dev>/threaded after reducing the channel count
> can hang, and later channel-count changes can fail because VSI reinit
> does not rebuild q_vectors to match the new vector count.
>
> Fix this by making the main VSI num_q_vectors follow the effective
> requested channel count, capped by the available MSI-X vectors. Update
> i40e_vsi_reinit_setup() to rebuild q_vectors during VSI reinit so the
> vector topology is refreshed together with the ring arrays when channel
> count changes.
>
> Keep alloc_queue_pairs unchanged and based on pf->num_lan_qps so the VSI
> retains its full queue capacity.
>
> Selftest napi_threaded.py was originally used when Jakub reported hang
> on /sys/class/net/<dev>/threaded toggle. In order to make it pass on
> i40e, use persistent NAPI configuration for q_vector NAPIs so NAPI
> identity and threaded settings survive q_vector reallocation across
> channel-count changes. This is achieved by using netif_napi_add_config()
> when configuring q_vectors.
>
> $ export NETIF=ens259f1np1
> $ sudo -E env PATH="$PATH" ./tools/testing/selftests/drivers/net/napi_threaded.py
> TAP version 13
> 1..3
> ok 1 napi_threaded.napi_init
> ok 2 napi_threaded.change_num_queues
> ok 3 napi_threaded.enable_dev_threaded_disable_napi_threaded
> Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0
>
> Reported-by: Jakub Kicinski <kuba@kernel.org>
> Closes: https://lore.kernel.org/intel-wired-lan/20260316133100.6054a11f@kernel.org/
> Fixes: d2a69fefd756 ("i40e: Fix changing previously set num_queue_pairs for PFs")
> Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> ---
> drivers/net/ethernet/intel/i40e/i40e_main.c | 34 +++++++++++++++++----
> 1 file changed, 28 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
> index 926d001b2150..5636ad71f940 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
> @@ -11403,10 +11403,14 @@ static void i40e_service_timer(struct timer_list *t)
> static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi)
> {
> struct i40e_pf *pf = vsi->back;
> + u16 qps;
>
> switch (vsi->type) {
> case I40E_VSI_MAIN:
> vsi->alloc_queue_pairs = pf->num_lan_qps;
> + qps = vsi->req_queue_pairs ?
> + min_t(u16, vsi->req_queue_pairs, pf->num_lan_qps) :
> + pf->num_lan_qps;
> if (!vsi->num_tx_desc)
> vsi->num_tx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
> I40E_REQ_DESCRIPTOR_MULTIPLE);
> @@ -11414,7 +11418,8 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi)
> vsi->num_rx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
> I40E_REQ_DESCRIPTOR_MULTIPLE);
> if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
> - vsi->num_q_vectors = pf->num_lan_msix;
> + vsi->num_q_vectors = max_t(int, 1,
> + min_t(int, qps, pf->num_lan_msix));
> else
> vsi->num_q_vectors = 1;
>
> @@ -12043,7 +12048,8 @@ static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx)
> cpumask_copy(&q_vector->affinity_mask, cpu_possible_mask);
>
> if (vsi->netdev)
> - netif_napi_add(vsi->netdev, &q_vector->napi, i40e_napi_poll);
> + netif_napi_add_config(vsi->netdev, &q_vector->napi,
> + i40e_napi_poll, v_idx);
>
> /* tie q_vector and vsi together */
> vsi->q_vectors[v_idx] = q_vector;
> @@ -14265,12 +14271,27 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
>
> pf = vsi->back;
>
> + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
> + i40e_put_lump(pf->irq_pile, vsi->base_vector, vsi->idx);
> + vsi->base_vector = 0;
> + }
> +
> i40e_put_lump(pf->qp_pile, vsi->base_queue, vsi->idx);
> i40e_vsi_clear_rings(vsi);
>
> - i40e_vsi_free_arrays(vsi, false);
> + i40e_vsi_free_q_vectors(vsi);
> + i40e_vsi_free_arrays(vsi, true);
> i40e_set_num_rings_in_vsi(vsi);
> - ret = i40e_vsi_alloc_arrays(vsi, false);
> +
> + ret = i40e_vsi_alloc_arrays(vsi, true);
> + if (ret)
> + goto err_vsi;
Sashiko warns about potential double-free on vsi->tx_rings. I will send a
v2 where I include NULLing this ptr in i40e_vsi_alloc_arrays().
Thanks,
Maciej
> +
> + /* Rebuild q_vectors during VSI reinit because the effective channel
> + * count may change num_q_vectors. Keep vector topology aligned with the
> + * queue configuration after ethtool's .set_channels() callback.
> + */
> + ret = i40e_vsi_setup_vectors(vsi);
> if (ret)
> goto err_vsi;
>
> @@ -14282,7 +14303,7 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
> dev_info(&pf->pdev->dev,
> "failed to get tracking for %d queues for VSI %d err %d\n",
> alloc_queue_pairs, vsi->seid, ret);
> - goto err_vsi;
> + goto err_lump;
> }
> vsi->base_queue = ret;
>
> @@ -14306,7 +14327,6 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
> return vsi;
>
> err_rings:
> - i40e_vsi_free_q_vectors(vsi);
> if (vsi->netdev_registered) {
> vsi->netdev_registered = false;
> unregister_netdev(vsi->netdev);
> @@ -14316,6 +14336,8 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
> if (vsi->type == I40E_VSI_MAIN)
> i40e_devlink_destroy_port(pf);
> i40e_aq_delete_element(&pf->hw, vsi->seid, NULL);
> +err_lump:
> + i40e_vsi_free_q_vectors(vsi);
> err_vsi:
> i40e_vsi_clear(vsi);
> return NULL;
> --
> 2.43.0
>
WARNING: multiple messages have this Message-ID (diff)
From: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
To: <intel-wired-lan@lists.osuosl.org>
Cc: <netdev@vger.kernel.org>, <magnus.karlsson@intel.com>,
<kuba@kernel.org>, <pabeni@redhat.com>, <horms@kernel.org>,
<przemyslaw.kitszel@intel.com>, <jacob.e.keller@intel.com>
Subject: Re: [PATCH iwl-net] i40e: keep q_vectors array in sync with channel count changes
Date: Thu, 16 Apr 2026 13:12:53 +0200 [thread overview]
Message-ID: <aeDENQXk8Mz1elXb@boxer> (raw)
In-Reply-To: <20260414121405.631092-1-maciej.fijalkowski@intel.com>
On Tue, Apr 14, 2026 at 02:14:05PM +0200, Maciej Fijalkowski wrote:
> For the main VSI, i40e_set_num_rings_in_vsi() always derives
> num_q_vectors from pf->num_lan_msix. At the same time, ethtool -L stores
> the user requested channel count in vsi->req_queue_pairs and the queue
> setup path uses that value for the effective number of queue pairs.
>
> This leaves queue and vector counts out of sync after shrinking channel
> count via ethtool -L. The active queue configuration is reduced, but the
> VSI still keeps the full PF-sized q_vector topology.
>
> That mismatch breaks reconfiguration flows which rely on vector/NAPI
> state matching the effective channel configuration. In particular,
> toggling /sys/class/net/<dev>/threaded after reducing the channel count
> can hang, and later channel-count changes can fail because VSI reinit
> does not rebuild q_vectors to match the new vector count.
>
> Fix this by making the main VSI num_q_vectors follow the effective
> requested channel count, capped by the available MSI-X vectors. Update
> i40e_vsi_reinit_setup() to rebuild q_vectors during VSI reinit so the
> vector topology is refreshed together with the ring arrays when channel
> count changes.
>
> Keep alloc_queue_pairs unchanged and based on pf->num_lan_qps so the VSI
> retains its full queue capacity.
>
> Selftest napi_threaded.py was originally used when Jakub reported hang
> on /sys/class/net/<dev>/threaded toggle. In order to make it pass on
> i40e, use persistent NAPI configuration for q_vector NAPIs so NAPI
> identity and threaded settings survive q_vector reallocation across
> channel-count changes. This is achieved by using netif_napi_add_config()
> when configuring q_vectors.
>
> $ export NETIF=ens259f1np1
> $ sudo -E env PATH="$PATH" ./tools/testing/selftests/drivers/net/napi_threaded.py
> TAP version 13
> 1..3
> ok 1 napi_threaded.napi_init
> ok 2 napi_threaded.change_num_queues
> ok 3 napi_threaded.enable_dev_threaded_disable_napi_threaded
> Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0
>
> Reported-by: Jakub Kicinski <kuba@kernel.org>
> Closes: https://lore.kernel.org/intel-wired-lan/20260316133100.6054a11f@kernel.org/
> Fixes: d2a69fefd756 ("i40e: Fix changing previously set num_queue_pairs for PFs")
> Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> ---
> drivers/net/ethernet/intel/i40e/i40e_main.c | 34 +++++++++++++++++----
> 1 file changed, 28 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
> index 926d001b2150..5636ad71f940 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
> @@ -11403,10 +11403,14 @@ static void i40e_service_timer(struct timer_list *t)
> static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi)
> {
> struct i40e_pf *pf = vsi->back;
> + u16 qps;
>
> switch (vsi->type) {
> case I40E_VSI_MAIN:
> vsi->alloc_queue_pairs = pf->num_lan_qps;
> + qps = vsi->req_queue_pairs ?
> + min_t(u16, vsi->req_queue_pairs, pf->num_lan_qps) :
> + pf->num_lan_qps;
> if (!vsi->num_tx_desc)
> vsi->num_tx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
> I40E_REQ_DESCRIPTOR_MULTIPLE);
> @@ -11414,7 +11418,8 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi)
> vsi->num_rx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
> I40E_REQ_DESCRIPTOR_MULTIPLE);
> if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
> - vsi->num_q_vectors = pf->num_lan_msix;
> + vsi->num_q_vectors = max_t(int, 1,
> + min_t(int, qps, pf->num_lan_msix));
> else
> vsi->num_q_vectors = 1;
>
> @@ -12043,7 +12048,8 @@ static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx)
> cpumask_copy(&q_vector->affinity_mask, cpu_possible_mask);
>
> if (vsi->netdev)
> - netif_napi_add(vsi->netdev, &q_vector->napi, i40e_napi_poll);
> + netif_napi_add_config(vsi->netdev, &q_vector->napi,
> + i40e_napi_poll, v_idx);
>
> /* tie q_vector and vsi together */
> vsi->q_vectors[v_idx] = q_vector;
> @@ -14265,12 +14271,27 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
>
> pf = vsi->back;
>
> + if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
> + i40e_put_lump(pf->irq_pile, vsi->base_vector, vsi->idx);
> + vsi->base_vector = 0;
> + }
> +
> i40e_put_lump(pf->qp_pile, vsi->base_queue, vsi->idx);
> i40e_vsi_clear_rings(vsi);
>
> - i40e_vsi_free_arrays(vsi, false);
> + i40e_vsi_free_q_vectors(vsi);
> + i40e_vsi_free_arrays(vsi, true);
> i40e_set_num_rings_in_vsi(vsi);
> - ret = i40e_vsi_alloc_arrays(vsi, false);
> +
> + ret = i40e_vsi_alloc_arrays(vsi, true);
> + if (ret)
> + goto err_vsi;
Sashiko warns about potential double-free on vsi->tx_rings. I will send a
v2 where I include NULLing this ptr in i40e_vsi_alloc_arrays().
Thanks,
Maciej
> +
> + /* Rebuild q_vectors during VSI reinit because the effective channel
> + * count may change num_q_vectors. Keep vector topology aligned with the
> + * queue configuration after ethtool's .set_channels() callback.
> + */
> + ret = i40e_vsi_setup_vectors(vsi);
> if (ret)
> goto err_vsi;
>
> @@ -14282,7 +14303,7 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
> dev_info(&pf->pdev->dev,
> "failed to get tracking for %d queues for VSI %d err %d\n",
> alloc_queue_pairs, vsi->seid, ret);
> - goto err_vsi;
> + goto err_lump;
> }
> vsi->base_queue = ret;
>
> @@ -14306,7 +14327,6 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
> return vsi;
>
> err_rings:
> - i40e_vsi_free_q_vectors(vsi);
> if (vsi->netdev_registered) {
> vsi->netdev_registered = false;
> unregister_netdev(vsi->netdev);
> @@ -14316,6 +14336,8 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
> if (vsi->type == I40E_VSI_MAIN)
> i40e_devlink_destroy_port(pf);
> i40e_aq_delete_element(&pf->hw, vsi->seid, NULL);
> +err_lump:
> + i40e_vsi_free_q_vectors(vsi);
> err_vsi:
> i40e_vsi_clear(vsi);
> return NULL;
> --
> 2.43.0
>
next prev parent reply other threads:[~2026-04-16 11:14 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-14 12:14 [Intel-wired-lan] [PATCH iwl-net] i40e: keep q_vectors array in sync with channel count changes Maciej Fijalkowski
2026-04-14 12:14 ` Maciej Fijalkowski
2026-04-16 11:12 ` Maciej Fijalkowski [this message]
2026-04-16 11:12 ` Maciej Fijalkowski
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=aeDENQXk8Mz1elXb@boxer \
--to=maciej.fijalkowski@intel.com \
--cc=horms@kernel.org \
--cc=intel-wired-lan@lists.osuosl.org \
--cc=jacob.e.keller@intel.com \
--cc=kuba@kernel.org \
--cc=magnus.karlsson@intel.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=przemyslaw.kitszel@intel.com \
/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 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.