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 981224743c73e472791136fea44bef6d02aff965..34c8565031f62e9a612b0c5c3d8a364a78fcf929 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 812b1200f35c6ffce48a70a345e5000a9d5a7663..da901f4b9c18c16fd613fec4ae0c13343e065e5d 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 3f0c85ecbca68c997aeec7bd53f66bc7c1736d95..4240a496dc502193242be05561135d25b3598f66 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);