i40evf: don't wait forever
authorMitch Williams <mitch.a.williams@intel.com>
Thu, 29 Jan 2015 07:17:20 +0000 (07:17 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Tue, 24 Feb 2015 01:13:21 +0000 (17:13 -0800)
Under rare circumstances, after a reset, set_rx_mode might get called
while the watchdog is running, which will cause a deadlock on the
critical section lock. To correct this, add a counter and give up trying
to get the lock after fifty tries. Log a message if this happens but
don't take any other action. Because this happens after a reset, all of
the Rx filters are still in place and the device won't lose
connectivity.

We can also get stuck during shutdown, if the PF has stopped communicating
with us, or if a reset is occurring. If we can't get the lock after a reasonable
amount of time, just error out. Something else bad is happening anyway, so
adding this filter is the least of our concern right now.

Change-ID: I159731e2a82a06b389ee31b34ce336548e05baa0
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_main.c

index 1257577148ea3c2f394299ca00a4b4782541d0ef..e089e8f98413c386a7bf3b7607e29baf9b286701 100644 (file)
@@ -761,13 +761,17 @@ i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter,
                                     u8 *macaddr)
 {
        struct i40evf_mac_filter *f;
+       int count = 50;
 
        if (!macaddr)
                return NULL;
 
        while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
-                               &adapter->crit_section))
+                               &adapter->crit_section)) {
                udelay(1);
+               if (--count == 0)
+                       return NULL;
+       }
 
        f = i40evf_find_filter(adapter, macaddr);
        if (!f) {
@@ -828,6 +832,7 @@ static void i40evf_set_rx_mode(struct net_device *netdev)
        struct i40evf_mac_filter *f, *ftmp;
        struct netdev_hw_addr *uca;
        struct netdev_hw_addr *mca;
+       int count = 50;
 
        /* add addr if not already in the filter list */
        netdev_for_each_uc_addr(uca, netdev) {
@@ -838,8 +843,14 @@ static void i40evf_set_rx_mode(struct net_device *netdev)
        }
 
        while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
-                               &adapter->crit_section))
+                               &adapter->crit_section)) {
                udelay(1);
+               if (--count == 0) {
+                       dev_err(&adapter->pdev->dev,
+                               "Failed to get lock in %s\n", __func__);
+                       return;
+               }
+       }
        /* remove filter if not in netdev list */
        list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
                bool found = false;