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>
This commit is contained in:
Mitch Williams 2015-03-27 00:12:09 -07:00 committed by Jeff Kirsher
parent ae24b4095c
commit e284fc88df
3 changed files with 14 additions and 13 deletions

View 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);

View 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

View 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);