summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/i40evf
diff options
context:
space:
mode:
authorMitch Williams <mitch.a.williams@intel.com>2015-03-27 00:12:09 -0700
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2015-03-27 02:57:03 -0700
commite284fc88dfb6ceb69c547abb8d78b9fde6b9dc85 (patch)
tree47f1394bf5181d256f3b17323349621751e7ad3b /drivers/net/ethernet/intel/i40evf
parentae24b4095c2f9547d0f2ab2845155aabe4e564d0 (diff)
i40evf: delay releasing rings
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>
Diffstat (limited to 'drivers/net/ethernet/intel/i40evf')
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf.h2
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_main.c23
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c2
3 files changed, 14 insertions, 13 deletions
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h
index 981224743c73..34c8565031f6 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf.h
+++ b/drivers/net/ethernet/intel/i40evf/i40evf.h
@@ -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);
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index 812b1200f35c..da901f4b9c18 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -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
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
index 3f0c85ecbca6..4240a496dc50 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
@@ -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);