From: Mohammad Heib i40e_down() expects its caller to set __I40E_VSI_DOWN before calling it, as noted in the comment at the top of the function. All callers do this except i40e_vsi_reinit_locked(), which calls i40e_down() directly without setting the flag. Normally this doesn't cause problems because NAPI drains cleanly on its own. But when the hardware is in a bad state, like during an NVM firmware update, the ring descriptors can contain garbage that i40e_napi_poll() sees as real work. Since __I40E_VSI_DOWN isn't set, the poll function has no reason to bail out. It keeps returning budget, napi_disable() keeps waiting, and the whole thing hangs. The thread stuck in napi_disable() is usually NetworkManager, and because it holds the RTNL lock, the system can end up completely frozen. Set __I40E_VSI_DOWN in i40e_vsi_reinit_locked() before calling i40e_down(). i40e_up_complete() already clears the flag when the VSI comes back up, so no additional cleanup is needed. Fixes: 41c445ff0f48 ("i40e: main driver core") Signed-off-by: Mohammad Heib Reviewed-by: Joe Damato Tested-by: Alexander Nowlin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index abbc71e815ae..dd729776c64d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7461,6 +7461,8 @@ static void i40e_vsi_reinit_locked(struct i40e_vsi *vsi) while (test_and_set_bit(__I40E_CONFIG_BUSY, pf->state)) usleep_range(1000, 2000); + /* required by i40e_down() */ + set_bit(__I40E_VSI_DOWN, vsi->state); i40e_down(vsi); i40e_up(vsi); -- 2.47.1 From: Filip Balluch When ethtool -G is used to change ring buffer sizes while the interface is up, i40e_set_ringparam() allocates temporary TX and RX rings. If the RX ring allocation fails, the error path at the free_tx label incorrectly calls i40e_free_tx_resources(vsi->tx_rings[i]), freeing the live TX rings instead of the temporary tx_rings[i]. Since the interface is still up, the next TX completion interrupt causes i40e_clean_tx_irq() to dereference the freed ring descriptors, resulting in a NULL pointer dereference in IRQ context and a kernel panic. This can be reproduced on systems with Intel X710 NICs under memory pressure, where the second port's DMA allocation fails after the first port succeeds. Fix by freeing the temporary tx_rings[i] in the error path instead of the live vsi->tx_rings[i]. Fixes: 74608d17fe29 ("i40e: add support for XDP_TX action") Signed-off-by: Filip Balluch Reviewed-by: Aleksandr Loktionov Tested-by: Alexander Nowlin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 6a992df06fa1..ef756487d668 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2249,7 +2249,7 @@ static int i40e_set_ringparam(struct net_device *netdev, if (tx_rings) { for (i = 0; i < tx_alloc_queue_pairs; i++) { if (i40e_active_tx_ring_index(vsi, i)) - i40e_free_tx_resources(vsi->tx_rings[i]); + i40e_free_tx_resources(&tx_rings[i]); } kfree(tx_rings); tx_rings = NULL; -- 2.47.1 From: Aleksandr Loktionov Temporary Tx rings built by i40e_set_ringparam() while resizing descriptor counts are shallow struct copies of the live vsi->tx_rings[] entries, so they retain the same ring->netdev and ring->queue_index as the live ring they are staged to replace. If an error path frees one of these clones with i40e_free_tx_resources() before i40e_down() has run - either the i40e_setup_tx_descriptors() failure unwind loop, or the free_tx: error label - i40e_clean_tx_ring() will call netdev_tx_reset_queue() on txring_txq(tx_ring), which resolves to the *same* netdev_queue as the live ring because netdev/queue_index alias. That call resets the queue's BQL/dql state (dql_reset(): num_queued = num_completed = 0) while the live ring is still actively transmitting and completing Tx on that same queue. The next time the live ring reports completions for bytes that were queued before the reset, dql_completed() can underflow its own sanity check and hit: BUG_ON(count > num_queued - dql->num_completed); i.e. a guaranteed kernel panic, not just a warning, given a queue with outstanding (queued but not yet completed) Tx traffic at the moment the clone is freed. Reproduced on real hardware by forcing i40e_setup_tx_descriptors() to fail partway through building tx_rings[] while flooding real Tx traffic on the affected queues: kernel BUG at lib/dynamic_queue_limits.c:99! RIP: 0010:dql_completed+0x285/0x2a0 Call Trace: i40e_napi_poll+0x74b/0x1700 [i40e] __napi_poll+0x10a/0x200 net_rx_action+0x2f7/0x380 handle_softirqs+0xcc/0x270 Confirmed the same trigger no longer panics with this fix applied, including repeated resize/traffic cycles. Clear the clone ring netdev before freeing it in both error paths, so i40e_clean_tx_ring()'s existing `if (!tx_ring->netdev) return;` guard skips the netdev_tx_reset_queue() call for the clone. This mirrors the same idiom i40e already uses for XDP Tx rings, which also have no netdev_queue of their own (ring->netdev = NULL in i40e_vsi_setup_tx()). Only the temporary, about-to-be-freed clone is touched; the live ring in vsi->tx_rings[] keeps its netdev. Fixes: 9f65e15b4f98 ("i40e: Move rings from pointer to array to array of pointers") Cc: stable@vger.kernel.org Signed-off-by: Aleksandr Loktionov Tested-by: Alexander Nowlin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index ef756487d668..58d842d67642 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2143,6 +2143,8 @@ static int i40e_set_ringparam(struct net_device *netdev, i--; if (!i40e_active_tx_ring_index(vsi, i)) continue; + /* not live yet, skip its BQL reset on free */ + tx_rings[i].netdev = NULL; i40e_free_tx_resources(&tx_rings[i]); } kfree(tx_rings); @@ -2248,8 +2250,11 @@ static int i40e_set_ringparam(struct net_device *netdev, /* error cleanup if the Rx allocations failed after getting Tx */ if (tx_rings) { for (i = 0; i < tx_alloc_queue_pairs; i++) { - if (i40e_active_tx_ring_index(vsi, i)) + if (i40e_active_tx_ring_index(vsi, i)) { + /* not live yet, skip its BQL reset on free */ + tx_rings[i].netdev = NULL; i40e_free_tx_resources(&tx_rings[i]); + } } kfree(tx_rings); tx_rings = NULL; -- 2.47.1 From: Xuanqiang Luo Commit 4c1a457cb8b0 ("iavf: add support to exchange qos capabilities") allocates adapter->qos_caps during probe, but iavf_remove() does not free it. This leaks the allocation whenever an iavf device is removed. Free adapter->qos_caps in iavf_remove(). Fixes: 4c1a457cb8b0 ("iavf: add support to exchange qos capabilities") Cc: stable@vger.kernel.org Reviewed-by: Jedrzej Jagielski Signed-off-by: Xuanqiang Luo Reviewed-by: Aleksandr Loktionov Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/iavf/iavf_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 2f8a80a11336..4de3ea8525b3 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -5638,6 +5638,7 @@ static void iavf_remove(struct pci_dev *pdev) iounmap(hw->hw_addr); pci_release_regions(pdev); kfree(adapter->vf_res); + kfree(adapter->qos_caps); spin_lock_bh(&adapter->mac_vlan_list_lock); /* If we got removed before an up/down sequence, we've got a filter * hanging out there that we need to get rid of. -- 2.47.1 From: Xuanqiang Luo iavf_alloc_adminq_asq_ring() allocates cmd_buf before the remaining ASQ resources. If iavf_alloc_asq_bufs() or iavf_config_asq_regs() fails, the unwind path elides cmd_buf while freeing the other allocations. The ASQ count is not set until initialization succeeds, so the shutdown path cannot reclaim the buffer. Free cmd_buf in the common unwind path. Fixes: d358aa9a7a2d ("i40evf: init code and hardware support") Cc: stable@vger.kernel.org Signed-off-by: Xuanqiang Luo Reviewed-by: Jedrzej Jagielski Reviewed-by: Aleksandr Loktionov Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/iavf/iavf_adminq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/iavf/iavf_adminq.c b/drivers/net/ethernet/intel/iavf/iavf_adminq.c index 6937b7dd44cb..40f76f9507f4 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_adminq.c +++ b/drivers/net/ethernet/intel/iavf/iavf_adminq.c @@ -60,6 +60,7 @@ static enum iavf_status iavf_alloc_adminq_arq_ring(struct iavf_hw *hw) **/ static void iavf_free_adminq_asq(struct iavf_hw *hw) { + iavf_free_virt_mem(hw, &hw->aq.asq.cmd_buf); iavf_free_dma_mem(hw, &hw->aq.asq.desc_buf); } -- 2.47.1 From: Xuanqiang Luo The PTP hardware clock documentation requires drivers to implement all callbacks and return -EOPNOTSUPP for unsupported features. The iavf driver registers a PHC without adjtime or adjfine callbacks. A userspace clock_adjtime(2) request reaches ptp_clock_adjtime(), where ADJ_SETOFFSET calls adjtime and ADJ_FREQUENCY calls adjfine. The missing callbacks can therefore cause a NULL dereference. Provide both callbacks and return -EOPNOTSUPP for the unsupported operations. Fixes: d734223b2f0d ("iavf: add initial framework for registering PTP clock") Link: https://docs.kernel.org/driver-api/ptp.html#writing-clock-drivers Link: https://lore.kernel.org/all/20260826101004.100979-1-xuanqiang.luo@linux.dev/ Cc: stable@vger.kernel.org Signed-off-by: Xuanqiang Luo Reviewed-by: Vadim Fedorenko Acked-by: Jacob Keller Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/iavf/iavf_ptp.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/ethernet/intel/iavf/iavf_ptp.c b/drivers/net/ethernet/intel/iavf/iavf_ptp.c index 87b97e09df14..fcb273828bc1 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_ptp.c +++ b/drivers/net/ethernet/intel/iavf/iavf_ptp.c @@ -252,6 +252,16 @@ static int iavf_ptp_gettimex64(struct ptp_clock_info *info, return iavf_read_phc_indirect(adapter, ts, sts); } +static int iavf_ptp_adjfine(struct ptp_clock_info *info, long scaled_ppm) +{ + return -EOPNOTSUPP; +} + +static int iavf_ptp_adjtime(struct ptp_clock_info *info, s64 delta) +{ + return -EOPNOTSUPP; +} + static int iavf_ptp_settime64(struct ptp_clock_info *info, const struct timespec64 *ts) { @@ -326,6 +336,8 @@ static int iavf_ptp_register_clock(struct iavf_adapter *adapter) KBUILD_MODNAME, dev_name(dev)); ptp_info->owner = THIS_MODULE; ptp_info->gettimex64 = iavf_ptp_gettimex64; + ptp_info->adjfine = iavf_ptp_adjfine; + ptp_info->adjtime = iavf_ptp_adjtime; ptp_info->settime64 = iavf_ptp_settime64; ptp_info->do_aux_work = iavf_ptp_do_aux_work; -- 2.47.1