diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 6c73acf7d2d9..d3392569485c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -958,6 +958,12 @@ void i40evf_down(struct i40evf_adapter *adapter) if (adapter->state == __I40EVF_DOWN) return; + while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, + &adapter->crit_section)) + usleep_range(500, 1000); + + i40evf_irq_disable(adapter); + /* remove all MAC filters */ list_for_each_entry(f, &adapter->mac_filter_list, list) { f->remove = true; @@ -968,22 +974,27 @@ void i40evf_down(struct i40evf_adapter *adapter) } if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) && adapter->state != __I40EVF_RESETTING) { - adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; + /* cancel any current operation */ + adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + adapter->aq_pending = 0; + /* Schedule operations to close down the HW. Don't wait + * here for this to complete. The watchdog is still running + * and it will take care of this. + */ + adapter->aq_required = I40EVF_FLAG_AQ_DEL_MAC_FILTER; adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER; - /* disable receives */ adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES; - mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); - msleep(20); } netif_tx_disable(netdev); netif_tx_stop_all_queues(netdev); - i40evf_irq_disable(adapter); - i40evf_napi_disable_all(adapter); + msleep(20); + netif_carrier_off(netdev); + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); } /** @@ -2408,6 +2419,7 @@ static void i40evf_remove(struct pci_dev *pdev) struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40evf_mac_filter *f, *ftmp; struct i40e_hw *hw = &adapter->hw; + int count = 50; cancel_delayed_work_sync(&adapter->init_task); cancel_work_sync(&adapter->reset_task); @@ -2416,6 +2428,11 @@ static void i40evf_remove(struct pci_dev *pdev) unregister_netdev(netdev); adapter->netdev_registered = false; } + while (count-- && adapter->aq_required) + msleep(50); + + if (count < 0) + dev_err(&pdev->dev, "Timed out waiting for PF driver.\n"); adapter->state = __I40EVF_REMOVE; if (adapter->msix_entries) {