|
@@ -45,8 +45,8 @@ static const char i40evf_driver_string[] =
|
|
#define DRV_KERN "-k"
|
|
#define DRV_KERN "-k"
|
|
|
|
|
|
#define DRV_VERSION_MAJOR 3
|
|
#define DRV_VERSION_MAJOR 3
|
|
-#define DRV_VERSION_MINOR 0
|
|
|
|
-#define DRV_VERSION_BUILD 1
|
|
|
|
|
|
+#define DRV_VERSION_MINOR 2
|
|
|
|
+#define DRV_VERSION_BUILD 2
|
|
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
|
|
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
|
|
__stringify(DRV_VERSION_MINOR) "." \
|
|
__stringify(DRV_VERSION_MINOR) "." \
|
|
__stringify(DRV_VERSION_BUILD) \
|
|
__stringify(DRV_VERSION_BUILD) \
|
|
@@ -276,37 +276,7 @@ void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask)
|
|
if (mask & BIT(i - 1)) {
|
|
if (mask & BIT(i - 1)) {
|
|
wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1),
|
|
wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1),
|
|
I40E_VFINT_DYN_CTLN1_INTENA_MASK |
|
|
I40E_VFINT_DYN_CTLN1_INTENA_MASK |
|
|
- I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK |
|
|
|
|
- I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * i40evf_fire_sw_int - Generate SW interrupt for specified vectors
|
|
|
|
- * @adapter: board private structure
|
|
|
|
- * @mask: bitmap of vectors to trigger
|
|
|
|
- **/
|
|
|
|
-static void i40evf_fire_sw_int(struct i40evf_adapter *adapter, u32 mask)
|
|
|
|
-{
|
|
|
|
- struct i40e_hw *hw = &adapter->hw;
|
|
|
|
- int i;
|
|
|
|
- u32 dyn_ctl;
|
|
|
|
-
|
|
|
|
- if (mask & 1) {
|
|
|
|
- dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTL01);
|
|
|
|
- dyn_ctl |= I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK |
|
|
|
|
- I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK |
|
|
|
|
- I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK;
|
|
|
|
- wr32(hw, I40E_VFINT_DYN_CTL01, dyn_ctl);
|
|
|
|
- }
|
|
|
|
- for (i = 1; i < adapter->num_msix_vectors; i++) {
|
|
|
|
- if (mask & BIT(i)) {
|
|
|
|
- dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTLN1(i - 1));
|
|
|
|
- dyn_ctl |= I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK |
|
|
|
|
- I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK |
|
|
|
|
- I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK;
|
|
|
|
- wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), dyn_ctl);
|
|
|
|
|
|
+ I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -337,15 +307,10 @@ static irqreturn_t i40evf_msix_aq(int irq, void *data)
|
|
struct net_device *netdev = data;
|
|
struct net_device *netdev = data;
|
|
struct i40evf_adapter *adapter = netdev_priv(netdev);
|
|
struct i40evf_adapter *adapter = netdev_priv(netdev);
|
|
struct i40e_hw *hw = &adapter->hw;
|
|
struct i40e_hw *hw = &adapter->hw;
|
|
- u32 val;
|
|
|
|
|
|
|
|
/* handle non-queue interrupts, these reads clear the registers */
|
|
/* handle non-queue interrupts, these reads clear the registers */
|
|
- val = rd32(hw, I40E_VFINT_ICR01);
|
|
|
|
- val = rd32(hw, I40E_VFINT_ICR0_ENA1);
|
|
|
|
-
|
|
|
|
- val = rd32(hw, I40E_VFINT_DYN_CTL01) |
|
|
|
|
- I40E_VFINT_DYN_CTL01_CLEARPBA_MASK;
|
|
|
|
- wr32(hw, I40E_VFINT_DYN_CTL01, val);
|
|
|
|
|
|
+ rd32(hw, I40E_VFINT_ICR01);
|
|
|
|
+ rd32(hw, I40E_VFINT_ICR0_ENA1);
|
|
|
|
|
|
/* schedule work on the private workqueue */
|
|
/* schedule work on the private workqueue */
|
|
schedule_work(&adapter->adminq_task);
|
|
schedule_work(&adapter->adminq_task);
|
|
@@ -706,7 +671,8 @@ static void i40evf_configure_rx(struct i40evf_adapter *adapter)
|
|
* @adapter: board private structure
|
|
* @adapter: board private structure
|
|
* @vlan: vlan tag
|
|
* @vlan: vlan tag
|
|
*
|
|
*
|
|
- * Returns ptr to the filter object or NULL
|
|
|
|
|
|
+ * Returns ptr to the filter object or NULL. Must be called while holding the
|
|
|
|
+ * mac_vlan_list_lock.
|
|
**/
|
|
**/
|
|
static struct
|
|
static struct
|
|
i40evf_vlan_filter *i40evf_find_vlan(struct i40evf_adapter *adapter, u16 vlan)
|
|
i40evf_vlan_filter *i40evf_find_vlan(struct i40evf_adapter *adapter, u16 vlan)
|
|
@@ -731,14 +697,8 @@ static struct
|
|
i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan)
|
|
i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan)
|
|
{
|
|
{
|
|
struct i40evf_vlan_filter *f = NULL;
|
|
struct i40evf_vlan_filter *f = NULL;
|
|
- int count = 50;
|
|
|
|
|
|
|
|
- while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
|
|
|
|
- &adapter->crit_section)) {
|
|
|
|
- udelay(1);
|
|
|
|
- if (--count == 0)
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
|
|
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
|
|
f = i40evf_find_vlan(adapter, vlan);
|
|
f = i40evf_find_vlan(adapter, vlan);
|
|
if (!f) {
|
|
if (!f) {
|
|
@@ -755,8 +715,7 @@ i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan)
|
|
}
|
|
}
|
|
|
|
|
|
clearout:
|
|
clearout:
|
|
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
|
|
-out:
|
|
|
|
|
|
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
|
return f;
|
|
return f;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -768,21 +727,16 @@ out:
|
|
static void i40evf_del_vlan(struct i40evf_adapter *adapter, u16 vlan)
|
|
static void i40evf_del_vlan(struct i40evf_adapter *adapter, u16 vlan)
|
|
{
|
|
{
|
|
struct i40evf_vlan_filter *f;
|
|
struct i40evf_vlan_filter *f;
|
|
- int count = 50;
|
|
|
|
|
|
|
|
- while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
|
|
|
|
- &adapter->crit_section)) {
|
|
|
|
- udelay(1);
|
|
|
|
- if (--count == 0)
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
|
|
f = i40evf_find_vlan(adapter, vlan);
|
|
f = i40evf_find_vlan(adapter, vlan);
|
|
if (f) {
|
|
if (f) {
|
|
f->remove = true;
|
|
f->remove = true;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
|
|
}
|
|
}
|
|
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
|
|
|
|
+
|
|
|
|
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -824,7 +778,8 @@ static int i40evf_vlan_rx_kill_vid(struct net_device *netdev,
|
|
* @adapter: board private structure
|
|
* @adapter: board private structure
|
|
* @macaddr: the MAC address
|
|
* @macaddr: the MAC address
|
|
*
|
|
*
|
|
- * Returns ptr to the filter object or NULL
|
|
|
|
|
|
+ * Returns ptr to the filter object or NULL. Must be called while holding the
|
|
|
|
+ * mac_vlan_list_lock.
|
|
**/
|
|
**/
|
|
static struct
|
|
static struct
|
|
i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
|
|
i40evf_mac_filter *i40evf_find_filter(struct i40evf_adapter *adapter,
|
|
@@ -854,26 +809,17 @@ i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter,
|
|
u8 *macaddr)
|
|
u8 *macaddr)
|
|
{
|
|
{
|
|
struct i40evf_mac_filter *f;
|
|
struct i40evf_mac_filter *f;
|
|
- int count = 50;
|
|
|
|
|
|
|
|
if (!macaddr)
|
|
if (!macaddr)
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
- while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
|
|
|
|
- &adapter->crit_section)) {
|
|
|
|
- udelay(1);
|
|
|
|
- if (--count == 0)
|
|
|
|
- return NULL;
|
|
|
|
- }
|
|
|
|
|
|
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
|
|
f = i40evf_find_filter(adapter, macaddr);
|
|
f = i40evf_find_filter(adapter, macaddr);
|
|
if (!f) {
|
|
if (!f) {
|
|
f = kzalloc(sizeof(*f), GFP_ATOMIC);
|
|
f = kzalloc(sizeof(*f), GFP_ATOMIC);
|
|
- if (!f) {
|
|
|
|
- clear_bit(__I40EVF_IN_CRITICAL_TASK,
|
|
|
|
- &adapter->crit_section);
|
|
|
|
- return NULL;
|
|
|
|
- }
|
|
|
|
|
|
+ if (!f)
|
|
|
|
+ goto clearout;
|
|
|
|
|
|
ether_addr_copy(f->macaddr, macaddr);
|
|
ether_addr_copy(f->macaddr, macaddr);
|
|
|
|
|
|
@@ -884,7 +830,8 @@ i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter,
|
|
f->remove = false;
|
|
f->remove = false;
|
|
}
|
|
}
|
|
|
|
|
|
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
|
|
|
|
+clearout:
|
|
|
|
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
|
return f;
|
|
return f;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -911,12 +858,16 @@ static int i40evf_set_mac(struct net_device *netdev, void *p)
|
|
if (adapter->flags & I40EVF_FLAG_ADDR_SET_BY_PF)
|
|
if (adapter->flags & I40EVF_FLAG_ADDR_SET_BY_PF)
|
|
return -EPERM;
|
|
return -EPERM;
|
|
|
|
|
|
|
|
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
+
|
|
f = i40evf_find_filter(adapter, hw->mac.addr);
|
|
f = i40evf_find_filter(adapter, hw->mac.addr);
|
|
if (f) {
|
|
if (f) {
|
|
f->remove = true;
|
|
f->remove = true;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
+
|
|
f = i40evf_add_filter(adapter, addr->sa_data);
|
|
f = i40evf_add_filter(adapter, addr->sa_data);
|
|
if (f) {
|
|
if (f) {
|
|
ether_addr_copy(hw->mac.addr, addr->sa_data);
|
|
ether_addr_copy(hw->mac.addr, addr->sa_data);
|
|
@@ -937,7 +888,6 @@ static void i40evf_set_rx_mode(struct net_device *netdev)
|
|
struct netdev_hw_addr *uca;
|
|
struct netdev_hw_addr *uca;
|
|
struct netdev_hw_addr *mca;
|
|
struct netdev_hw_addr *mca;
|
|
struct netdev_hw_addr *ha;
|
|
struct netdev_hw_addr *ha;
|
|
- int count = 50;
|
|
|
|
|
|
|
|
/* add addr if not already in the filter list */
|
|
/* add addr if not already in the filter list */
|
|
netdev_for_each_uc_addr(uca, netdev) {
|
|
netdev_for_each_uc_addr(uca, netdev) {
|
|
@@ -947,16 +897,8 @@ static void i40evf_set_rx_mode(struct net_device *netdev)
|
|
i40evf_add_filter(adapter, mca->addr);
|
|
i40evf_add_filter(adapter, mca->addr);
|
|
}
|
|
}
|
|
|
|
|
|
- while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
|
|
|
|
- &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 */
|
|
|
|
|
|
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
+
|
|
list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
|
|
list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
|
|
netdev_for_each_mc_addr(mca, netdev)
|
|
netdev_for_each_mc_addr(mca, netdev)
|
|
if (ether_addr_equal(mca->addr, f->macaddr))
|
|
if (ether_addr_equal(mca->addr, f->macaddr))
|
|
@@ -995,7 +937,7 @@ bottom_of_search_loop:
|
|
adapter->flags & I40EVF_FLAG_ALLMULTI_ON)
|
|
adapter->flags & I40EVF_FLAG_ALLMULTI_ON)
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_RELEASE_ALLMULTI;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_RELEASE_ALLMULTI;
|
|
|
|
|
|
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
|
|
|
|
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1058,6 +1000,8 @@ static void i40evf_configure(struct i40evf_adapter *adapter)
|
|
/**
|
|
/**
|
|
* i40evf_up_complete - Finish the last steps of bringing up a connection
|
|
* i40evf_up_complete - Finish the last steps of bringing up a connection
|
|
* @adapter: board private structure
|
|
* @adapter: board private structure
|
|
|
|
+ *
|
|
|
|
+ * Expects to be called while holding the __I40EVF_IN_CRITICAL_TASK bit lock.
|
|
**/
|
|
**/
|
|
static void i40evf_up_complete(struct i40evf_adapter *adapter)
|
|
static void i40evf_up_complete(struct i40evf_adapter *adapter)
|
|
{
|
|
{
|
|
@@ -1075,6 +1019,8 @@ static void i40evf_up_complete(struct i40evf_adapter *adapter)
|
|
/**
|
|
/**
|
|
* i40e_down - Shutdown the connection processing
|
|
* i40e_down - Shutdown the connection processing
|
|
* @adapter: board private structure
|
|
* @adapter: board private structure
|
|
|
|
+ *
|
|
|
|
+ * Expects to be called while holding the __I40EVF_IN_CRITICAL_TASK bit lock.
|
|
**/
|
|
**/
|
|
void i40evf_down(struct i40evf_adapter *adapter)
|
|
void i40evf_down(struct i40evf_adapter *adapter)
|
|
{
|
|
{
|
|
@@ -1084,16 +1030,14 @@ void i40evf_down(struct i40evf_adapter *adapter)
|
|
if (adapter->state <= __I40EVF_DOWN_PENDING)
|
|
if (adapter->state <= __I40EVF_DOWN_PENDING)
|
|
return;
|
|
return;
|
|
|
|
|
|
- while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
|
|
|
|
- &adapter->crit_section))
|
|
|
|
- usleep_range(500, 1000);
|
|
|
|
-
|
|
|
|
netif_carrier_off(netdev);
|
|
netif_carrier_off(netdev);
|
|
netif_tx_disable(netdev);
|
|
netif_tx_disable(netdev);
|
|
adapter->link_up = false;
|
|
adapter->link_up = false;
|
|
i40evf_napi_disable_all(adapter);
|
|
i40evf_napi_disable_all(adapter);
|
|
i40evf_irq_disable(adapter);
|
|
i40evf_irq_disable(adapter);
|
|
|
|
|
|
|
|
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
+
|
|
/* remove all MAC filters */
|
|
/* remove all MAC filters */
|
|
list_for_each_entry(f, &adapter->mac_filter_list, list) {
|
|
list_for_each_entry(f, &adapter->mac_filter_list, list) {
|
|
f->remove = true;
|
|
f->remove = true;
|
|
@@ -1102,6 +1046,9 @@ void i40evf_down(struct i40evf_adapter *adapter)
|
|
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
|
|
list_for_each_entry(f, &adapter->vlan_filter_list, list) {
|
|
f->remove = true;
|
|
f->remove = true;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
+
|
|
if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) &&
|
|
if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) &&
|
|
adapter->state != __I40EVF_RESETTING) {
|
|
adapter->state != __I40EVF_RESETTING) {
|
|
/* cancel any current operation */
|
|
/* cancel any current operation */
|
|
@@ -1115,7 +1062,6 @@ void i40evf_down(struct i40evf_adapter *adapter)
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES;
|
|
}
|
|
}
|
|
|
|
|
|
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
|
|
mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
|
|
mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1770,13 +1716,6 @@ static void i40evf_watchdog_task(struct work_struct *work)
|
|
if (adapter->state == __I40EVF_RUNNING)
|
|
if (adapter->state == __I40EVF_RUNNING)
|
|
i40evf_request_stats(adapter);
|
|
i40evf_request_stats(adapter);
|
|
watchdog_done:
|
|
watchdog_done:
|
|
- if (adapter->state == __I40EVF_RUNNING) {
|
|
|
|
- i40evf_irq_enable_queues(adapter, ~0);
|
|
|
|
- i40evf_fire_sw_int(adapter, 0xFF);
|
|
|
|
- } else {
|
|
|
|
- i40evf_fire_sw_int(adapter, 0x1);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
restart_watchdog:
|
|
restart_watchdog:
|
|
if (adapter->state == __I40EVF_REMOVE)
|
|
if (adapter->state == __I40EVF_REMOVE)
|
|
@@ -1796,7 +1735,11 @@ static void i40evf_disable_vf(struct i40evf_adapter *adapter)
|
|
|
|
|
|
adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
|
|
adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
|
|
|
|
|
|
- if (netif_running(adapter->netdev)) {
|
|
|
|
|
|
+ /* We don't use netif_running() because it may be true prior to
|
|
|
|
+ * ndo_open() returning, so we can't assume it means all our open
|
|
|
|
+ * tasks have finished, since we're not holding the rtnl_lock here.
|
|
|
|
+ */
|
|
|
|
+ if (adapter->state == __I40EVF_RUNNING) {
|
|
set_bit(__I40E_VSI_DOWN, adapter->vsi.state);
|
|
set_bit(__I40E_VSI_DOWN, adapter->vsi.state);
|
|
netif_carrier_off(adapter->netdev);
|
|
netif_carrier_off(adapter->netdev);
|
|
netif_tx_disable(adapter->netdev);
|
|
netif_tx_disable(adapter->netdev);
|
|
@@ -1808,6 +1751,8 @@ static void i40evf_disable_vf(struct i40evf_adapter *adapter)
|
|
i40evf_free_all_rx_resources(adapter);
|
|
i40evf_free_all_rx_resources(adapter);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
+
|
|
/* Delete all of the filters, both MAC and VLAN. */
|
|
/* Delete all of the filters, both MAC and VLAN. */
|
|
list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
|
|
list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
|
|
list_del(&f->list);
|
|
list_del(&f->list);
|
|
@@ -1819,6 +1764,8 @@ static void i40evf_disable_vf(struct i40evf_adapter *adapter)
|
|
kfree(fv);
|
|
kfree(fv);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
+
|
|
i40evf_free_misc_irq(adapter);
|
|
i40evf_free_misc_irq(adapter);
|
|
i40evf_reset_interrupt_capability(adapter);
|
|
i40evf_reset_interrupt_capability(adapter);
|
|
i40evf_free_queues(adapter);
|
|
i40evf_free_queues(adapter);
|
|
@@ -1854,6 +1801,7 @@ static void i40evf_reset_task(struct work_struct *work)
|
|
struct i40evf_mac_filter *f;
|
|
struct i40evf_mac_filter *f;
|
|
u32 reg_val;
|
|
u32 reg_val;
|
|
int i = 0, err;
|
|
int i = 0, err;
|
|
|
|
+ bool running;
|
|
|
|
|
|
while (test_and_set_bit(__I40EVF_IN_CLIENT_TASK,
|
|
while (test_and_set_bit(__I40EVF_IN_CLIENT_TASK,
|
|
&adapter->crit_section))
|
|
&adapter->crit_section))
|
|
@@ -1913,7 +1861,13 @@ static void i40evf_reset_task(struct work_struct *work)
|
|
}
|
|
}
|
|
|
|
|
|
continue_reset:
|
|
continue_reset:
|
|
- if (netif_running(netdev)) {
|
|
|
|
|
|
+ /* We don't use netif_running() because it may be true prior to
|
|
|
|
+ * ndo_open() returning, so we can't assume it means all our open
|
|
|
|
+ * tasks have finished, since we're not holding the rtnl_lock here.
|
|
|
|
+ */
|
|
|
|
+ running = (adapter->state == __I40EVF_RUNNING);
|
|
|
|
+
|
|
|
|
+ if (running) {
|
|
netif_carrier_off(netdev);
|
|
netif_carrier_off(netdev);
|
|
netif_tx_stop_all_queues(netdev);
|
|
netif_tx_stop_all_queues(netdev);
|
|
adapter->link_up = false;
|
|
adapter->link_up = false;
|
|
@@ -1948,6 +1902,8 @@ continue_reset:
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_GET_CONFIG;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_GET_CONFIG;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS;
|
|
|
|
|
|
|
|
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
+
|
|
/* re-add all MAC filters */
|
|
/* re-add all MAC filters */
|
|
list_for_each_entry(f, &adapter->mac_filter_list, list) {
|
|
list_for_each_entry(f, &adapter->mac_filter_list, list) {
|
|
f->add = true;
|
|
f->add = true;
|
|
@@ -1956,15 +1912,19 @@ continue_reset:
|
|
list_for_each_entry(vlf, &adapter->vlan_filter_list, list) {
|
|
list_for_each_entry(vlf, &adapter->vlan_filter_list, list) {
|
|
vlf->add = true;
|
|
vlf->add = true;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
+
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
|
|
adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER;
|
|
- clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
|
|
- clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section);
|
|
|
|
i40evf_misc_irq_enable(adapter);
|
|
i40evf_misc_irq_enable(adapter);
|
|
|
|
|
|
mod_timer(&adapter->watchdog_timer, jiffies + 2);
|
|
mod_timer(&adapter->watchdog_timer, jiffies + 2);
|
|
|
|
|
|
- if (netif_running(adapter->netdev)) {
|
|
|
|
|
|
+ /* We were running when the reset started, so we need to restore some
|
|
|
|
+ * state here.
|
|
|
|
+ */
|
|
|
|
+ if (running) {
|
|
/* allocate transmit descriptors */
|
|
/* allocate transmit descriptors */
|
|
err = i40evf_setup_all_tx_resources(adapter);
|
|
err = i40evf_setup_all_tx_resources(adapter);
|
|
if (err)
|
|
if (err)
|
|
@@ -1993,9 +1953,13 @@ continue_reset:
|
|
adapter->state = __I40EVF_DOWN;
|
|
adapter->state = __I40EVF_DOWN;
|
|
wake_up(&adapter->down_waitqueue);
|
|
wake_up(&adapter->down_waitqueue);
|
|
}
|
|
}
|
|
|
|
+ clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section);
|
|
|
|
+ clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
|
|
|
|
return;
|
|
return;
|
|
reset_err:
|
|
reset_err:
|
|
|
|
+ clear_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section);
|
|
|
|
+ clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n");
|
|
dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n");
|
|
i40evf_close(netdev);
|
|
i40evf_close(netdev);
|
|
}
|
|
}
|
|
@@ -2239,8 +2203,14 @@ static int i40evf_open(struct net_device *netdev)
|
|
return -EIO;
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
|
|
- if (adapter->state != __I40EVF_DOWN)
|
|
|
|
- return -EBUSY;
|
|
|
|
|
|
+ while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
|
|
|
|
+ &adapter->crit_section))
|
|
|
|
+ usleep_range(500, 1000);
|
|
|
|
+
|
|
|
|
+ if (adapter->state != __I40EVF_DOWN) {
|
|
|
|
+ err = -EBUSY;
|
|
|
|
+ goto err_unlock;
|
|
|
|
+ }
|
|
|
|
|
|
/* allocate transmit descriptors */
|
|
/* allocate transmit descriptors */
|
|
err = i40evf_setup_all_tx_resources(adapter);
|
|
err = i40evf_setup_all_tx_resources(adapter);
|
|
@@ -2264,6 +2234,8 @@ static int i40evf_open(struct net_device *netdev)
|
|
|
|
|
|
i40evf_irq_enable(adapter, true);
|
|
i40evf_irq_enable(adapter, true);
|
|
|
|
|
|
|
|
+ clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
err_req_irq:
|
|
err_req_irq:
|
|
@@ -2273,6 +2245,8 @@ err_setup_rx:
|
|
i40evf_free_all_rx_resources(adapter);
|
|
i40evf_free_all_rx_resources(adapter);
|
|
err_setup_tx:
|
|
err_setup_tx:
|
|
i40evf_free_all_tx_resources(adapter);
|
|
i40evf_free_all_tx_resources(adapter);
|
|
|
|
+err_unlock:
|
|
|
|
+ clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
|
|
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
@@ -2296,6 +2270,9 @@ static int i40evf_close(struct net_device *netdev)
|
|
if (adapter->state <= __I40EVF_DOWN_PENDING)
|
|
if (adapter->state <= __I40EVF_DOWN_PENDING)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
|
|
|
|
+ &adapter->crit_section))
|
|
|
|
+ usleep_range(500, 1000);
|
|
|
|
|
|
set_bit(__I40E_VSI_DOWN, adapter->vsi.state);
|
|
set_bit(__I40E_VSI_DOWN, adapter->vsi.state);
|
|
if (CLIENT_ENABLED(adapter))
|
|
if (CLIENT_ENABLED(adapter))
|
|
@@ -2305,6 +2282,8 @@ static int i40evf_close(struct net_device *netdev)
|
|
adapter->state = __I40EVF_DOWN_PENDING;
|
|
adapter->state = __I40EVF_DOWN_PENDING;
|
|
i40evf_free_traffic_irqs(adapter);
|
|
i40evf_free_traffic_irqs(adapter);
|
|
|
|
|
|
|
|
+ clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
|
|
+
|
|
/* We explicitly don't free resources here because the hardware is
|
|
/* We explicitly don't free resources here because the hardware is
|
|
* still active and can DMA into memory. Resources are cleared in
|
|
* still active and can DMA into memory. Resources are cleared in
|
|
* i40evf_virtchnl_completion() after we get confirmation from the PF
|
|
* i40evf_virtchnl_completion() after we get confirmation from the PF
|
|
@@ -2943,6 +2922,8 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
mutex_init(&hw->aq.asq_mutex);
|
|
mutex_init(&hw->aq.asq_mutex);
|
|
mutex_init(&hw->aq.arq_mutex);
|
|
mutex_init(&hw->aq.arq_mutex);
|
|
|
|
|
|
|
|
+ spin_lock_init(&adapter->mac_vlan_list_lock);
|
|
|
|
+
|
|
INIT_LIST_HEAD(&adapter->mac_filter_list);
|
|
INIT_LIST_HEAD(&adapter->mac_filter_list);
|
|
INIT_LIST_HEAD(&adapter->vlan_filter_list);
|
|
INIT_LIST_HEAD(&adapter->vlan_filter_list);
|
|
|
|
|
|
@@ -2985,6 +2966,10 @@ static int i40evf_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
|
|
|
|
netif_device_detach(netdev);
|
|
netif_device_detach(netdev);
|
|
|
|
|
|
|
|
+ while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
|
|
|
|
+ &adapter->crit_section))
|
|
|
|
+ usleep_range(500, 1000);
|
|
|
|
+
|
|
if (netif_running(netdev)) {
|
|
if (netif_running(netdev)) {
|
|
rtnl_lock();
|
|
rtnl_lock();
|
|
i40evf_down(adapter);
|
|
i40evf_down(adapter);
|
|
@@ -2993,6 +2978,8 @@ static int i40evf_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
i40evf_free_misc_irq(adapter);
|
|
i40evf_free_misc_irq(adapter);
|
|
i40evf_reset_interrupt_capability(adapter);
|
|
i40evf_reset_interrupt_capability(adapter);
|
|
|
|
|
|
|
|
+ clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
|
|
|
|
+
|
|
retval = pci_save_state(pdev);
|
|
retval = pci_save_state(pdev);
|
|
if (retval)
|
|
if (retval)
|
|
return retval;
|
|
return retval;
|
|
@@ -3118,6 +3105,7 @@ static void i40evf_remove(struct pci_dev *pdev)
|
|
i40evf_free_all_rx_resources(adapter);
|
|
i40evf_free_all_rx_resources(adapter);
|
|
i40evf_free_queues(adapter);
|
|
i40evf_free_queues(adapter);
|
|
kfree(adapter->vf_res);
|
|
kfree(adapter->vf_res);
|
|
|
|
+ spin_lock_bh(&adapter->mac_vlan_list_lock);
|
|
/* If we got removed before an up/down sequence, we've got a filter
|
|
/* If we got removed before an up/down sequence, we've got a filter
|
|
* hanging out there that we need to get rid of.
|
|
* hanging out there that we need to get rid of.
|
|
*/
|
|
*/
|
|
@@ -3130,6 +3118,8 @@ static void i40evf_remove(struct pci_dev *pdev)
|
|
kfree(f);
|
|
kfree(f);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ spin_unlock_bh(&adapter->mac_vlan_list_lock);
|
|
|
|
+
|
|
free_netdev(netdev);
|
|
free_netdev(netdev);
|
|
|
|
|
|
pci_disable_pcie_error_reporting(pdev);
|
|
pci_disable_pcie_error_reporting(pdev);
|