aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMitch Williams <mitch.a.williams@intel.com>2015-03-27 03:12:09 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2015-03-27 05:57:03 -0400
commite284fc88dfb6ceb69c547abb8d78b9fde6b9dc85 (patch)
tree47f1394bf5181d256f3b17323349621751e7ad3b
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>
-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);
272void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter); 272void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter);
273int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter); 273int i40evf_init_interrupt_scheme(struct i40evf_adapter *adapter);
274void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask); 274void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask);
275void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter);
276void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter);
275 277
276void i40e_napi_add_all(struct i40evf_adapter *adapter); 278void i40e_napi_add_all(struct i40evf_adapter *adapter);
277void i40e_napi_del_all(struct i40evf_adapter *adapter); 279void 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 @@
28#include "i40e_prototype.h" 28#include "i40e_prototype.h"
29static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter); 29static int i40evf_setup_all_tx_resources(struct i40evf_adapter *adapter);
30static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter); 30static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter);
31static void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter);
32static void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter);
33static int i40evf_close(struct net_device *netdev); 31static int i40evf_close(struct net_device *netdev);
34 32
35char i40evf_driver_name[] = "i40evf"; 33char i40evf_driver_name[] = "i40evf";
@@ -1358,6 +1356,11 @@ static void i40evf_watchdog_task(struct work_struct *work)
1358 goto watchdog_done; 1356 goto watchdog_done;
1359 } 1357 }
1360 1358
1359 if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_QUEUES) {
1360 i40evf_disable_queues(adapter);
1361 goto watchdog_done;
1362 }
1363
1361 if (adapter->aq_required & I40EVF_FLAG_AQ_MAP_VECTORS) { 1364 if (adapter->aq_required & I40EVF_FLAG_AQ_MAP_VECTORS) {
1362 i40evf_map_queues(adapter); 1365 i40evf_map_queues(adapter);
1363 goto watchdog_done; 1366 goto watchdog_done;
@@ -1383,11 +1386,6 @@ static void i40evf_watchdog_task(struct work_struct *work)
1383 goto watchdog_done; 1386 goto watchdog_done;
1384 } 1387 }
1385 1388
1386 if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_QUEUES) {
1387 i40evf_disable_queues(adapter);
1388 goto watchdog_done;
1389 }
1390
1391 if (adapter->aq_required & I40EVF_FLAG_AQ_CONFIGURE_QUEUES) { 1389 if (adapter->aq_required & I40EVF_FLAG_AQ_CONFIGURE_QUEUES) {
1392 i40evf_configure_queues(adapter); 1390 i40evf_configure_queues(adapter);
1393 goto watchdog_done; 1391 goto watchdog_done;
@@ -1724,7 +1722,7 @@ out:
1724 * 1722 *
1725 * Free all transmit software resources 1723 * Free all transmit software resources
1726 **/ 1724 **/
1727static void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter) 1725void i40evf_free_all_tx_resources(struct i40evf_adapter *adapter)
1728{ 1726{
1729 int i; 1727 int i;
1730 1728
@@ -1794,7 +1792,7 @@ static int i40evf_setup_all_rx_resources(struct i40evf_adapter *adapter)
1794 * 1792 *
1795 * Free all receive software resources 1793 * Free all receive software resources
1796 **/ 1794 **/
1797static void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter) 1795void i40evf_free_all_rx_resources(struct i40evf_adapter *adapter)
1798{ 1796{
1799 int i; 1797 int i;
1800 1798
@@ -1824,7 +1822,7 @@ static int i40evf_open(struct net_device *netdev)
1824 dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n"); 1822 dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n");
1825 return -EIO; 1823 return -EIO;
1826 } 1824 }
1827 if (adapter->state != __I40EVF_DOWN) 1825 if (adapter->state != __I40EVF_DOWN || adapter->aq_required)
1828 return -EBUSY; 1826 return -EBUSY;
1829 1827
1830 /* allocate transmit descriptors */ 1828 /* allocate transmit descriptors */
@@ -1888,9 +1886,6 @@ static int i40evf_close(struct net_device *netdev)
1888 adapter->state = __I40EVF_DOWN; 1886 adapter->state = __I40EVF_DOWN;
1889 i40evf_free_traffic_irqs(adapter); 1887 i40evf_free_traffic_irqs(adapter);
1890 1888
1891 i40evf_free_all_tx_resources(adapter);
1892 i40evf_free_all_rx_resources(adapter);
1893
1894 return 0; 1889 return 0;
1895} 1890}
1896 1891
@@ -2504,6 +2499,8 @@ static void i40evf_remove(struct pci_dev *pdev)
2504 iounmap(hw->hw_addr); 2499 iounmap(hw->hw_addr);
2505 pci_release_regions(pdev); 2500 pci_release_regions(pdev);
2506 2501
2502 i40evf_free_all_tx_resources(adapter);
2503 i40evf_free_all_rx_resources(adapter);
2507 i40evf_free_queues(adapter); 2504 i40evf_free_queues(adapter);
2508 kfree(adapter->vf_res); 2505 kfree(adapter->vf_res);
2509 /* If we got removed before an up/down sequence, we've got a filter 2506 /* 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,
761 break; 761 break;
762 case I40E_VIRTCHNL_OP_DISABLE_QUEUES: 762 case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
763 adapter->aq_pending &= ~(I40EVF_FLAG_AQ_DISABLE_QUEUES); 763 adapter->aq_pending &= ~(I40EVF_FLAG_AQ_DISABLE_QUEUES);
764 i40evf_free_all_tx_resources(adapter);
765 i40evf_free_all_rx_resources(adapter);
764 break; 766 break;
765 case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES: 767 case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
766 adapter->aq_pending &= ~(I40EVF_FLAG_AQ_CONFIGURE_QUEUES); 768 adapter->aq_pending &= ~(I40EVF_FLAG_AQ_CONFIGURE_QUEUES);