summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/i40e/i40e_main.c
diff options
context:
space:
mode:
authorAnjali Singhai <anjali.singhai@intel.com>2015-09-28 13:37:12 -0700
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2015-09-28 17:43:23 -0700
commit30e2561b95295258890b4e0366ce867e04d34a97 (patch)
tree1c47ee8a4e8de32e665a72a73ec059dc0b388d90 /drivers/net/ethernet/intel/i40e/i40e_main.c
parent5804474311912c1b80601a1afee052e8df962cd4 (diff)
i40e: Fix for recursive RTNL lock during PROMISC change
The sync_vsi_filters function can be called directly under RTNL or through the timer subtask without one. This was causing a deadlock. If sync_vsi_filters is called from a thread which held the lock, and in another thread the PROMISC setting got changed we would be executing the PROMISC change in the thread which already held the lock alongside the other filter update. The PROMISC change requires a reset if we are on a VEB, which requires it to be called under RTNL. Earlier the driver would call reset for PROMISC change without checking if we were already under RTNL and would try to grab it causing a deadlock. This patch changes the flow to see if we are already under RTNL before trying to grab it. Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com> Signed-off-by: Kiran Patil <kiran.patil@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/i40e/i40e_main.c')
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c19
1 files changed, 12 insertions, 7 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index c246dca5de71..52e58f304b21 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -1527,7 +1527,7 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
f->is_laa = true;
}
- i40e_sync_vsi_filters(vsi);
+ i40e_sync_vsi_filters(vsi, false);
ether_addr_copy(netdev->dev_addr, addr->sa_data);
return 0;
@@ -1764,12 +1764,13 @@ static void i40e_set_rx_mode(struct net_device *netdev)
/**
* i40e_sync_vsi_filters - Update the VSI filter list to the HW
* @vsi: ptr to the VSI
+ * @grab_rtnl: whether RTNL needs to be grabbed
*
* Push any outstanding VSI filter changes through the AdminQ.
*
* Returns 0 or error value
**/
-int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
+int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl)
{
struct i40e_mac_filter *f, *ftmp;
bool promisc_forced_on = false;
@@ -1958,7 +1959,11 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
*/
if (pf->cur_promisc != cur_promisc) {
pf->cur_promisc = cur_promisc;
- i40e_do_reset_safe(pf,
+ if (grab_rtnl)
+ i40e_do_reset_safe(pf,
+ BIT(__I40E_PF_RESET_REQUESTED));
+ else
+ i40e_do_reset(pf,
BIT(__I40E_PF_RESET_REQUESTED));
}
} else {
@@ -2009,7 +2014,7 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf)
for (v = 0; v < pf->num_alloc_vsi; v++) {
if (pf->vsi[v] &&
(pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED))
- i40e_sync_vsi_filters(pf->vsi[v]);
+ i40e_sync_vsi_filters(pf->vsi[v], true);
}
}
@@ -2216,7 +2221,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
return 0;
- return i40e_sync_vsi_filters(vsi);
+ return i40e_sync_vsi_filters(vsi, false);
}
/**
@@ -2288,7 +2293,7 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
return 0;
- return i40e_sync_vsi_filters(vsi);
+ return i40e_sync_vsi_filters(vsi, false);
}
/**
@@ -8821,7 +8826,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list)
i40e_del_filter(vsi, f->macaddr, f->vlan,
f->is_vf, f->is_netdev);
- i40e_sync_vsi_filters(vsi);
+ i40e_sync_vsi_filters(vsi, false);
i40e_vsi_delete(vsi);
i40e_vsi_free_q_vectors(vsi);