From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D3AE52D2B0; Fri, 18 Sep 2026 21:25:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789766713; cv=none; b=bpEFhnPHuhSKv2tJLnXFTIXTPNfcAgseS0G7KLNQTNlQiFyvSCubeesZMt5P2O39ZIf4DkCHjy1wunVPBwnMihdD0NQrz3YL1ntVexIDqV5kcuM0Eitn3k+lcFE3XgOJNDI1gGnqqOsTnyBKDEWAY6CjBF88lPvZAXVbZ551sJo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789766713; c=relaxed/simple; bh=G+qs214tpQ8TyMdX1uOAAIs99jrpPfghTU6Q0VeCX9Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=I+6GYaWVUeDjUoBEJL6N+MLK9xvztdh3XU0lUZl+jPGarjhIuAjDblFQ1NkvmFajp1bPRBCKyQ8n9KrbrXxbcYFMqbiIx3JPg6va/q2POZnfeGrSO6Coxt/73SD/DiU5EHZvYacM8FHe09j7mdwH3H9WRlFNdOGqOXa1pPWVjnk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=K58MQzS9; arc=none smtp.client-ip=192.198.163.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="K58MQzS9" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1789766710; x=1821302710; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=G+qs214tpQ8TyMdX1uOAAIs99jrpPfghTU6Q0VeCX9Y=; b=K58MQzS9P0xy1R7CjeQYuoT7MiyyVvvoUZZ3E2WC8HZYmQNJ9kuWH6BA 9hoC+n5q8a3MAdizC20g1ZZ2sTa+oajiTOCxbol7hVh/gubt5soJKXD3W 8ZzbwbANxc4I/NkF0zUVsek47sOK6VO4P9zcpRPlGWdF/bJDeWpCq/i31 oTSzWmFZM57vbcOAXDp91xO9vGxq3+4CFpzMQk37AfftfJPHUdapAF3cw ipFc60Aj0NZD6FDja+n42coBLMuzz7KfVomj5cPYaZX3EwtFJLfbxa9AE SLA9tJYx7VrIuw2yPrV5Z/lRPpIRjVAEfHwh3y1rObkel4hbEyDOThUuM Q==; X-CSE-ConnectionGUID: cwBtIBvsQLG2051OnoTKYA== X-CSE-MsgGUID: vPi7a6LeTvetS7i/FR26QA== X-IronPort-AV: E=McAfee;i="6800,10657,11909"; a="89436280" X-IronPort-AV: E=Sophos;i="6.27,109,1787036400"; d="scan'208";a="89436280" Received: from fmviesa007.fm.intel.com ([10.60.135.147]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Sep 2026 14:25:08 -0700 X-CSE-ConnectionGUID: 3U76s+/RTzWlErULRitSbg== X-CSE-MsgGUID: lJ1BTKnQTl+YTi6JMXRqgA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.27,109,1787036400"; d="scan'208";a="271251426" Received: from anguy11-upstream.jf.intel.com ([10.166.9.133]) by fmviesa007.fm.intel.com with ESMTP; 18 Sep 2026 14:25:07 -0700 From: Tony Nguyen To: davem@davemloft.net, kuba@kernel.org, pabeni@redhat.com, edumazet@google.com, andrew+netdev@lunn.ch, netdev@vger.kernel.org Cc: Maciej Fijalkowski , anthony.l.nguyen@intel.com, zhaochenguang@kylinos.cn, magnus.karlsson@intel.com, jacob.e.keller@intel.com, przemyslaw.kitszel@intel.com, jbrandeb@kernel.org, horms@kernel.org, kerneljasonxing@gmail.com, ast@kernel.org, daniel@iogearbox.net, hawk@kernel.org, john.fastabend@gmail.com, sdf@fomichev.me, bpf@vger.kernel.org, Sunitha Mekala Subject: [PATCH net 7/8] i40e: keep q_vectors array in sync with channel count changes Date: Fri, 18 Sep 2026 14:24:54 -0700 Message-ID: <20260918212458.550425-8-anthony.l.nguyen@intel.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20260918212458.550425-1-anthony.l.nguyen@intel.com> References: <20260918212458.550425-1-anthony.l.nguyen@intel.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Maciej Fijalkowski 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//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. Also do not touch irq_pile when rebuilding vectors. Selftest napi_threaded.py was originally used when Jakub reported hang on /sys/class/net//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 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 Tested-by: Sunitha Mekala (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e_main.c | 69 +++++++++++++-------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 82037faf960f..32c0cb6caa17 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -11400,10 +11400,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(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); @@ -11411,7 +11415,7 @@ 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 = clamp(qps, 1, pf->num_lan_msix); else vsi->num_q_vectors = 1; @@ -11463,12 +11467,11 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi) /** * i40e_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the vsi * @vsi: VSI pointer - * @alloc_qvectors: a bool to specify if q_vectors need to be allocated. * * On error: returns error code (negative) * On success: returns 0 **/ -static int i40e_vsi_alloc_arrays(struct i40e_vsi *vsi, bool alloc_qvectors) +static int i40e_vsi_alloc_arrays(struct i40e_vsi *vsi) { struct i40e_ring **next_rings; int size; @@ -11487,19 +11490,20 @@ static int i40e_vsi_alloc_arrays(struct i40e_vsi *vsi, bool alloc_qvectors) } vsi->rx_rings = next_rings; - if (alloc_qvectors) { - /* allocate memory for q_vector pointers */ - size = sizeof(struct i40e_q_vector *) * vsi->num_q_vectors; - vsi->q_vectors = kzalloc(size, GFP_KERNEL); - if (!vsi->q_vectors) { - ret = -ENOMEM; - goto err_vectors; - } + /* allocate memory for q_vector pointers */ + size = sizeof(struct i40e_q_vector *) * vsi->num_q_vectors; + vsi->q_vectors = kzalloc(size, GFP_KERNEL); + if (!vsi->q_vectors) { + ret = -ENOMEM; + goto err_vectors; } return ret; err_vectors: kfree(vsi->tx_rings); + vsi->tx_rings = NULL; + vsi->rx_rings = NULL; + vsi->xdp_rings = NULL; return ret; } @@ -11572,7 +11576,7 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type) if (ret) goto err_rings; - ret = i40e_vsi_alloc_arrays(vsi, true); + ret = i40e_vsi_alloc_arrays(vsi); if (ret) goto err_rings; @@ -11597,18 +11601,15 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type) /** * i40e_vsi_free_arrays - Free queue and vector pointer arrays for the VSI * @vsi: VSI pointer - * @free_qvectors: a bool to specify if q_vectors need to be freed. * * On error: returns error code (negative) * On success: returns 0 **/ -static void i40e_vsi_free_arrays(struct i40e_vsi *vsi, bool free_qvectors) +static void i40e_vsi_free_arrays(struct i40e_vsi *vsi) { /* free the ring and vector containers */ - if (free_qvectors) { - kfree(vsi->q_vectors); - vsi->q_vectors = NULL; - } + kfree(vsi->q_vectors); + vsi->q_vectors = NULL; kfree(vsi->tx_rings); vsi->tx_rings = NULL; vsi->rx_rings = NULL; @@ -11668,7 +11669,7 @@ static int i40e_vsi_clear(struct i40e_vsi *vsi) i40e_put_lump(pf->irq_pile, vsi->base_vector, vsi->idx); bitmap_free(vsi->af_xdp_zc_qps); - i40e_vsi_free_arrays(vsi, true); + i40e_vsi_free_arrays(vsi); i40e_clear_rss_config_user(vsi); pf->vsi[vsi->idx] = NULL; @@ -12042,7 +12043,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; @@ -14197,8 +14199,9 @@ int i40e_vsi_release(struct i40e_vsi *vsi) **/ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi) { - int ret = -ENOENT; struct i40e_pf *pf = vsi->back; + bool reuse_irq_lump = false; + int ret = -ENOENT; if (vsi->q_vectors[0]) { dev_info(&pf->pdev->dev, "VSI %d has existing q_vectors\n", @@ -14206,7 +14209,10 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi) return -EEXIST; } - if (vsi->base_vector) { + if (vsi->type == I40E_VSI_MAIN && vsi->base_vector) + reuse_irq_lump = true; + + if (vsi->base_vector && !reuse_irq_lump) { dev_info(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n", vsi->seid, vsi->base_vector); return -EEXIST; @@ -14226,6 +14232,10 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi) */ if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) return ret; + + if (reuse_irq_lump) + return ret; + if (vsi->num_q_vectors) vsi->base_vector = i40e_get_lump(pf, pf->irq_pile, vsi->num_q_vectors, vsi->idx); @@ -14266,11 +14276,20 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi, pf = vsi->back; i40e_put_lump(pf->qp_pile, vsi->base_queue, vsi->idx); + i40e_vsi_free_q_vectors(vsi); i40e_vsi_clear_rings(vsi); + i40e_vsi_free_arrays(vsi); - i40e_vsi_free_arrays(vsi, false); i40e_set_num_rings_in_vsi(vsi); - ret = i40e_vsi_alloc_arrays(vsi, false); + ret = i40e_vsi_alloc_arrays(vsi); + if (ret) + goto err_netdev; + + /* 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_netdev; @@ -14282,7 +14301,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_netdev; + goto err_rings; } vsi->base_queue = ret; -- 2.47.1