i40evf: delay releasing rings
authorMitch Williams <mitch.a.williams@intel.com>
Fri, 27 Mar 2015 07:12:09 +0000 (00:12 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 27 Mar 2015 09:57:03 +0000 (02:57 -0700)
When the VF interface is closed, we cannot immediately free our rings
and RX buffers, because the hardware hasn't yet stopped accessing this
memory. This shows up as a panic or memory corruption when the device is
brought down while under heavy stress.

To fix this, delay releasing resources until we receive acknowledgment
from the PF driver that the rings have indeed been stopped. Because of
this delay, we also need to check to make sure that all of our admin
queue requests have been handled before allowing the device to be
opened.

Change-ID: I44edd35529ce2fa2a9512437a3a8e6f14ed8ed63
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Tested-by: Jim Young <james.m.young@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40evf/i40evf.h
drivers/net/ethernet/intel/i40evf/i40evf_main.c
drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c

index 9812247..34c8565 100644 (file)
@@ -272,6 +272,8 @@ void i40evf_update_stats(struct i40evf_adapter *adapter);
 void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter);
 int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter);
 void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask);
+void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter);
+void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter);
 
 void i40e_napi_add_all(struct i40evf_adapter *adapter);
 void i40e_napi_del_all(struct i40evf_adapter *adapter);
index 812b120..da901f4 100644 (file)
@@ -28,8 +28,6 @@
 #include "i40e_prototype.h"
 static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter);
 static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter);
-static void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter);
-static void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter);
 static int i40evf_close(struct net_device *netdev);
 
 char i40evf_driver_name[] = "i40evf";
@@ -1358,6 +1356,11 @@ static void i40evf_watchdog_task(struct work_struct *work)
                goto watchdog_done;
        }
 
+       if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_QUEUES) {
+               i40evf_disable_queues(adapter);
+               goto watchdog_done;
+       }
+
        if (adapter->aq_required & I40EVF_FLAG_AQ_MAP_VECTORS) {
                i40evf_map_queues(adapter);
                goto watchdog_done;
@@ -1383,11 +1386,6 @@ static void i40evf_watchdog_task(struct work_struct *work)
                goto watchdog_done;
        }
 
-       if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_QUEUES) {
-               i40evf_disable_queues(adapter);
-               goto watchdog_done;
-       }
-
        if (adapter->aq_required & I40EVF_FLAG_AQ_CONFIGURE_QUEUES) {
                i40evf_configure_queues(adapter);
                goto watchdog_done;
@@ -1724,7 +1722,7 @@ out:
  *
  * Free all transmit software resources
  **/
-static void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter)
+void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter)
 {
        int i;
 
@@ -1794,7 +1792,7 @@ static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter)
  *
  * Free all receive software resources
  **/
-static void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter)
+void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter)
 {
        int i;
 
@@ -1824,7 +1822,7 @@ static int i40evf_open(struct net_device *netdev)
                dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n");
                return -EIO;
        }
-       if (adapter->state != __I40EVF_DOWN)
+       if (adapter->state != __I40EVF_DOWN || adapter->aq_required)
                return -EBUSY;
 
        /* allocate transmit descriptors */
@@ -1888,9 +1886,6 @@ static int i40evf_close(struct net_device *netdev)
        adapter->state = __I40EVF_DOWN;
        i40evf_free_traffic_irqs(adapter);
 
-       i40evf_free_all_tx_resources(adapter);
-       i40evf_free_all_rx_resources(adapter);
-
        return 0;
 }
 
@@ -2504,6 +2499,8 @@ static void i40evf_remove(struct pci_dev *pdev)
        iounmap(hw->hw_addr);
        pci_release_regions(pdev);
 
+       i40evf_free_all_tx_resources(adapter);
+       i40evf_free_all_rx_resources(adapter);
        i40evf_free_queues(adapter);
        kfree(adapter->vf_res);
        /* If we got removed before an up/down sequence, we've got a filter
index 3f0c85e..4240a49 100644 (file)
@@ -761,6 +761,8 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
                break;
        case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
                adapter->aq_pending &= ~(I40EVF_FLAG_AQ_DISABLE_QUEUES);
+               i40evf_free_all_tx_resources(adapter);
+               i40evf_free_all_rx_resources(adapter);
                break;
        case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
                adapter->aq_pending &= ~(I40EVF_FLAG_AQ_CONFIGURE_QUEUES);