From f4a718810cf73fa55c85d253634d4a1f9464f6e7 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 9 Jan 2015 11:18:16 +0000 Subject: i40evf: reset on module unload When the module is being unloaded, don't wait for the PF to politely handle all of our admin queue requests, as that might take forever with a lot of VFs enabled. Instead, just stop everything and request a VF reset. When the original shutdown code was written, VF resets were unreliable, so we avoided them. But with production hardware and firmware, and the 1.x PF driver, this is no longer the case. This fixes a potential multi-minute delay on driver unload, VF disable, or system shutdown. Change-ID: Ib43d6d860ef6b9b8f26e8dce0615a0302608c7d9 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net/ethernet/intel/i40evf/i40evf_main.c') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index f946aac1df71..cd71c47732b2 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2423,7 +2423,6 @@ 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); @@ -2432,12 +2431,18 @@ 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"); + /* Shut down all the garbage mashers on the detention level */ adapter->state = __I40EVF_REMOVE; + adapter->aq_required = 0; + adapter->aq_pending = 0; + i40evf_request_reset(adapter); + msleep(20); + /* If the FW isn't responding, kick it once, but only once. */ + if (!i40evf_asq_done(hw)) { + i40evf_request_reset(adapter); + msleep(20); + } if (adapter->msix_entries) { i40evf_misc_irq_disable(adapter); -- cgit v1.2.3 From 8b011ebb5c371f8767e6e813a1aca3b7fc795f94 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 9 Jan 2015 11:18:17 +0000 Subject: i40evf: ignore bogus messages from FW Occasionally on shutdown, the FW will hand us a bunch of messages filled with zeros, which can cause us to spin trying to handle them. Just ignore these and get on with shutting down. Change-ID: I347e9648f7153ad5a7b7e0847b87f7aad5f3e0da Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/ethernet/intel/i40evf/i40evf_main.c') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index cd71c47732b2..38126f5d6fd9 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1631,7 +1631,7 @@ static void i40evf_adminq_task(struct work_struct *work) v_msg = (struct i40e_virtchnl_msg *)&event.desc; do { ret = i40evf_clean_arq_element(hw, &event, &pending); - if (ret) + if (ret || !v_msg->v_opcode) break; /* No event to process or error cleaning ARQ */ i40evf_virtchnl_completion(adapter, v_msg->v_opcode, -- cgit v1.2.3 From 00293fdc4229e493556f8cca403305f3c2124743 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 9 Jan 2015 11:18:18 +0000 Subject: i40evf: stop the watchdog for shutdown Stop the watchdog during shutdown. Failing to do this causes a log full of admin queue errors and the occasional hang when the system is shut down. Change-ID: Ib2fd11213cca2fa589eb68577e86b1000c23c250 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/ethernet/intel/i40evf/i40evf_main.c') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 38126f5d6fd9..8d8c201c63c1 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2213,12 +2213,18 @@ err: static void i40evf_shutdown(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); + struct i40evf_adapter *adapter = netdev_priv(netdev); netif_device_detach(netdev); if (netif_running(netdev)) i40evf_close(netdev); + /* Prevent the watchdog from running. */ + adapter->state = __I40EVF_REMOVE; + adapter->aq_required = 0; + adapter->aq_pending = 0; + #ifdef CONFIG_PM pci_save_state(pdev); -- cgit v1.2.3