[PATCH iwl-net v2 3/5] i40e: synchronize reset recovery with device removal

[email protected]
Newsgroups org.kernel.vger.netdev,org.osuosl.intel-wired-lan
Message-ID <[email protected]>
From: Xuanqiang Luo <[email protected]>

i40e_remove() currently tears down PTP and device resources before
claiming RESET_RECOVERY_PENDING. A service task can pass its initial state
check before removal starts and continue into reset recovery after the
remove path has begun teardown. This can make i40e_reset_and_rebuild()
access or recreate resources that are being released.

Stop the service timer and disable the service work before claiming reset
ownership. disable_work_sync() drains the current service task and rejects
later queue_work() attempts, including those from interrupts. Claim the
reset bit before starting teardown so an existing reset owner completes
first.

Fixes: 6533e558c650 ("i40e: Fix reset path while removing the driver")
Signed-off-by: Xuanqiang Luo <[email protected]>
---
 drivers/net/ethernet/intel/i40e/i40e_main.c | 28 ++++++++++-----------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 8c28788ac634f..5922f83f324ae 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -16159,6 +16159,20 @@ static void i40e_remove(struct pci_dev *pdev)
 
 	i40e_devlink_unregister(pf);
 
+	/* Interrupts can queue the service task until __I40E_DOWN is set.
+	 * Disable it so no service work can outlive the PF.
+	 */
+	set_bit(__I40E_SUSPENDED, pf->state);
+	if (pf->service_timer.function)
+		timer_shutdown_sync(&pf->service_timer);
+	if (pf->service_task.func)
+		disable_work_sync(&pf->service_task);
+
+	/* Wait for any reset owner before tearing down device resources. */
+	while (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
+		usleep_range(1000, 2000);
+	set_bit(__I40E_IN_REMOVE, pf->state);
+
 	i40e_dbg_pf_exit(pf);
 
 	i40e_ptp_stop(pf);
@@ -16167,26 +16181,12 @@ static void i40e_remove(struct pci_dev *pdev)
 	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), 0);
 	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), 0);
 
-	/* Grab __I40E_RESET_RECOVERY_PENDING and set __I40E_IN_REMOVE
-	 * flags, once they are set, i40e_rebuild should not be called as
-	 * i40e_prep_for_reset always returns early.
-	 */
-	while (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
-		usleep_range(1000, 2000);
-	set_bit(__I40E_IN_REMOVE, pf->state);
-
 	if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags)) {
 		set_bit(__I40E_VF_RESETS_DISABLED, pf->state);
 		i40e_free_vfs(pf);
 		clear_bit(I40E_FLAG_SRIOV_ENA, pf->flags);
 	}
-	/* no more scheduling of any task */
-	set_bit(__I40E_SUSPENDED, pf->state);
 	set_bit(__I40E_DOWN, pf->state);
-	if (pf->service_timer.function)
-		timer_shutdown_sync(&pf->service_timer);
-	if (pf->service_task.func)
-		cancel_work_sync(&pf->service_task);
 
 	if (test_bit(__I40E_RECOVERY_MODE, pf->state)) {
 		struct i40e_vsi *vsi = pf->vsi[0];
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.