i40evf: Don't schedule reset_task when device is being removed
authorAvinash Dayanand <avinash.dayanand@intel.com>
Mon, 18 Dec 2017 10:16:43 +0000 (05:16 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 26 Apr 2018 09:02:10 +0000 (11:02 +0200)
[ Upstream commit 06aa040f039404a0039a5158cd12f41187487a1f ]

When a host disables and enables a PF device, all the associated
VFs are removed and added back in. It also generates a PFR which in turn
resets all the connected VFs. This behaviour is different from that of
Linux guest on Linux host. Hence we end up in a situation where there's
a PFR and device removal at the same time. And watchdog doesn't have a
clue about this and schedules a reset_task. This patch adds code to send
signal to reset_task that the device is currently being removed.

Signed-off-by: Avinash Dayanand <avinash.dayanand@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/net/ethernet/intel/i40evf/i40evf.h
drivers/net/ethernet/intel/i40evf/i40evf_main.c

index 82f69031e5cdbc23827e8b743ff8d69b2072a211..2ef32ab1dfae89ab26803f74bed36a76cc29dc88 100644 (file)
@@ -186,6 +186,7 @@ enum i40evf_state_t {
 enum i40evf_critical_section_t {
        __I40EVF_IN_CRITICAL_TASK,      /* cannot be interrupted */
        __I40EVF_IN_CLIENT_TASK,
+       __I40EVF_IN_REMOVE_TASK,        /* device being removed */
 };
 
 /* board specific private data structure */
index 4eb6ff60e8fca54a4883fdcabeb0ff6f8e5a87a9..1b5d204c57c141cc05efb6432148efb2d9983b57 100644 (file)
@@ -1839,6 +1839,12 @@ static void i40evf_reset_task(struct work_struct *work)
        int i = 0, err;
        bool running;
 
+       /* When device is being removed it doesn't make sense to run the reset
+        * task, just return in such a case.
+        */
+       if (test_bit(__I40EVF_IN_REMOVE_TASK, &adapter->crit_section))
+               return;
+
        while (test_and_set_bit(__I40EVF_IN_CLIENT_TASK,
                                &adapter->crit_section))
                usleep_range(500, 1000);
@@ -3022,7 +3028,8 @@ static void i40evf_remove(struct pci_dev *pdev)
        struct i40evf_mac_filter *f, *ftmp;
        struct i40e_hw *hw = &adapter->hw;
        int err;
-
+       /* Indicate we are in remove and not to run reset_task */
+       set_bit(__I40EVF_IN_REMOVE_TASK, &adapter->crit_section);
        cancel_delayed_work_sync(&adapter->init_task);
        cancel_work_sync(&adapter->reset_task);
        cancel_delayed_work_sync(&adapter->client_task);