Commit 7f5acea7 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue

Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2023-07-17 (iavf)

This series contains updates to iavf driver only.

Ding Hui fixes use-after-free issue by calling netif_napi_del() for all
allocated q_vectors. He also resolves out-of-bounds issue by not
updating to new values when timeout is encountered.

Marcin and Ahmed change the way resets are handled so that the callback
operating under the RTNL lock will wait for the reset to finish, the
rtnl_lock sensitive functions in reset flow will schedule the netdev update
for later in order to remove circular dependency with the critical lock.

* '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue:
  iavf: fix reset task race with iavf_remove()
  iavf: fix a deadlock caused by rtnl and driver's lock circular dependencies
  Revert "iavf: Do not restart Tx queues after reset task failure"
  Revert "iavf: Detach device during reset task"
  iavf: Wait for reset in callbacks which trigger it
  iavf: use internal state to free traffic IRQs
  iavf: Fix out-of-bounds when setting channels on remove
  iavf: Fix use-after-free in free_netdev
====================

Link: https://lore.kernel.org/r/20230717175205.3217774-1-anthony.l.nguyen@intel.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents e9b2bd96 c34743da
...@@ -255,8 +255,10 @@ struct iavf_adapter { ...@@ -255,8 +255,10 @@ struct iavf_adapter {
struct workqueue_struct *wq; struct workqueue_struct *wq;
struct work_struct reset_task; struct work_struct reset_task;
struct work_struct adminq_task; struct work_struct adminq_task;
struct work_struct finish_config;
struct delayed_work client_task; struct delayed_work client_task;
wait_queue_head_t down_waitqueue; wait_queue_head_t down_waitqueue;
wait_queue_head_t reset_waitqueue;
wait_queue_head_t vc_waitqueue; wait_queue_head_t vc_waitqueue;
struct iavf_q_vector *q_vectors; struct iavf_q_vector *q_vectors;
struct list_head vlan_filter_list; struct list_head vlan_filter_list;
...@@ -518,8 +520,9 @@ int iavf_up(struct iavf_adapter *adapter); ...@@ -518,8 +520,9 @@ int iavf_up(struct iavf_adapter *adapter);
void iavf_down(struct iavf_adapter *adapter); void iavf_down(struct iavf_adapter *adapter);
int iavf_process_config(struct iavf_adapter *adapter); int iavf_process_config(struct iavf_adapter *adapter);
int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter); int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter);
void iavf_schedule_reset(struct iavf_adapter *adapter); void iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags);
void iavf_schedule_request_stats(struct iavf_adapter *adapter); void iavf_schedule_request_stats(struct iavf_adapter *adapter);
void iavf_schedule_finish_config(struct iavf_adapter *adapter);
void iavf_reset(struct iavf_adapter *adapter); void iavf_reset(struct iavf_adapter *adapter);
void iavf_set_ethtool_ops(struct net_device *netdev); void iavf_set_ethtool_ops(struct net_device *netdev);
void iavf_update_stats(struct iavf_adapter *adapter); void iavf_update_stats(struct iavf_adapter *adapter);
...@@ -582,4 +585,5 @@ void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter); ...@@ -582,4 +585,5 @@ void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter);
void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter); void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter);
struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter, struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
const u8 *macaddr); const u8 *macaddr);
int iavf_wait_for_reset(struct iavf_adapter *adapter);
#endif /* _IAVF_H_ */ #endif /* _IAVF_H_ */
...@@ -484,6 +484,7 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags) ...@@ -484,6 +484,7 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags)
{ {
struct iavf_adapter *adapter = netdev_priv(netdev); struct iavf_adapter *adapter = netdev_priv(netdev);
u32 orig_flags, new_flags, changed_flags; u32 orig_flags, new_flags, changed_flags;
int ret = 0;
u32 i; u32 i;
orig_flags = READ_ONCE(adapter->flags); orig_flags = READ_ONCE(adapter->flags);
...@@ -531,12 +532,14 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags) ...@@ -531,12 +532,14 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags)
/* issue a reset to force legacy-rx change to take effect */ /* issue a reset to force legacy-rx change to take effect */
if (changed_flags & IAVF_FLAG_LEGACY_RX) { if (changed_flags & IAVF_FLAG_LEGACY_RX) {
if (netif_running(netdev)) { if (netif_running(netdev)) {
adapter->flags |= IAVF_FLAG_RESET_NEEDED; iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
queue_work(adapter->wq, &adapter->reset_task); ret = iavf_wait_for_reset(adapter);
if (ret)
netdev_warn(netdev, "Changing private flags timeout or interrupted waiting for reset");
} }
} }
return 0; return ret;
} }
/** /**
...@@ -627,6 +630,7 @@ static int iavf_set_ringparam(struct net_device *netdev, ...@@ -627,6 +630,7 @@ static int iavf_set_ringparam(struct net_device *netdev,
{ {
struct iavf_adapter *adapter = netdev_priv(netdev); struct iavf_adapter *adapter = netdev_priv(netdev);
u32 new_rx_count, new_tx_count; u32 new_rx_count, new_tx_count;
int ret = 0;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL; return -EINVAL;
...@@ -671,11 +675,13 @@ static int iavf_set_ringparam(struct net_device *netdev, ...@@ -671,11 +675,13 @@ static int iavf_set_ringparam(struct net_device *netdev,
} }
if (netif_running(netdev)) { if (netif_running(netdev)) {
adapter->flags |= IAVF_FLAG_RESET_NEEDED; iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
queue_work(adapter->wq, &adapter->reset_task); ret = iavf_wait_for_reset(adapter);
if (ret)
netdev_warn(netdev, "Changing ring parameters timeout or interrupted waiting for reset");
} }
return 0; return ret;
} }
/** /**
...@@ -1830,7 +1836,7 @@ static int iavf_set_channels(struct net_device *netdev, ...@@ -1830,7 +1836,7 @@ static int iavf_set_channels(struct net_device *netdev,
{ {
struct iavf_adapter *adapter = netdev_priv(netdev); struct iavf_adapter *adapter = netdev_priv(netdev);
u32 num_req = ch->combined_count; u32 num_req = ch->combined_count;
int i; int ret = 0;
if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) && if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
adapter->num_tc) { adapter->num_tc) {
...@@ -1852,22 +1858,13 @@ static int iavf_set_channels(struct net_device *netdev, ...@@ -1852,22 +1858,13 @@ static int iavf_set_channels(struct net_device *netdev,
adapter->num_req_queues = num_req; adapter->num_req_queues = num_req;
adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED; adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
iavf_schedule_reset(adapter); iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
/* wait for the reset is done */ ret = iavf_wait_for_reset(adapter);
for (i = 0; i < IAVF_RESET_WAIT_COMPLETE_COUNT; i++) { if (ret)
msleep(IAVF_RESET_WAIT_MS); netdev_warn(netdev, "Changing channel count timeout or interrupted waiting for reset");
if (adapter->flags & IAVF_FLAG_RESET_PENDING)
continue;
break;
}
if (i == IAVF_RESET_WAIT_COMPLETE_COUNT) {
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
adapter->num_active_queues = num_req;
return -EOPNOTSUPP;
}
return 0; return ret;
} }
/** /**
......
...@@ -166,6 +166,45 @@ static struct iavf_adapter *iavf_pdev_to_adapter(struct pci_dev *pdev) ...@@ -166,6 +166,45 @@ static struct iavf_adapter *iavf_pdev_to_adapter(struct pci_dev *pdev)
return netdev_priv(pci_get_drvdata(pdev)); return netdev_priv(pci_get_drvdata(pdev));
} }
/**
* iavf_is_reset_in_progress - Check if a reset is in progress
* @adapter: board private structure
*/
static bool iavf_is_reset_in_progress(struct iavf_adapter *adapter)
{
if (adapter->state == __IAVF_RESETTING ||
adapter->flags & (IAVF_FLAG_RESET_PENDING |
IAVF_FLAG_RESET_NEEDED))
return true;
return false;
}
/**
* iavf_wait_for_reset - Wait for reset to finish.
* @adapter: board private structure
*
* Returns 0 if reset finished successfully, negative on timeout or interrupt.
*/
int iavf_wait_for_reset(struct iavf_adapter *adapter)
{
int ret = wait_event_interruptible_timeout(adapter->reset_waitqueue,
!iavf_is_reset_in_progress(adapter),
msecs_to_jiffies(5000));
/* If ret < 0 then it means wait was interrupted.
* If ret == 0 then it means we got a timeout while waiting
* for reset to finish.
* If ret > 0 it means reset has finished.
*/
if (ret > 0)
return 0;
else if (ret < 0)
return -EINTR;
else
return -EBUSY;
}
/** /**
* iavf_allocate_dma_mem_d - OS specific memory alloc for shared code * iavf_allocate_dma_mem_d - OS specific memory alloc for shared code
* @hw: pointer to the HW structure * @hw: pointer to the HW structure
...@@ -262,12 +301,14 @@ static int iavf_lock_timeout(struct mutex *lock, unsigned int msecs) ...@@ -262,12 +301,14 @@ static int iavf_lock_timeout(struct mutex *lock, unsigned int msecs)
/** /**
* iavf_schedule_reset - Set the flags and schedule a reset event * iavf_schedule_reset - Set the flags and schedule a reset event
* @adapter: board private structure * @adapter: board private structure
* @flags: IAVF_FLAG_RESET_PENDING or IAVF_FLAG_RESET_NEEDED
**/ **/
void iavf_schedule_reset(struct iavf_adapter *adapter) void iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags)
{ {
if (!(adapter->flags & if (!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section) &&
!(adapter->flags &
(IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) { (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) {
adapter->flags |= IAVF_FLAG_RESET_NEEDED; adapter->flags |= flags;
queue_work(adapter->wq, &adapter->reset_task); queue_work(adapter->wq, &adapter->reset_task);
} }
} }
...@@ -295,7 +336,7 @@ static void iavf_tx_timeout(struct net_device *netdev, unsigned int txqueue) ...@@ -295,7 +336,7 @@ static void iavf_tx_timeout(struct net_device *netdev, unsigned int txqueue)
struct iavf_adapter *adapter = netdev_priv(netdev); struct iavf_adapter *adapter = netdev_priv(netdev);
adapter->tx_timeout_count++; adapter->tx_timeout_count++;
iavf_schedule_reset(adapter); iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
} }
/** /**
...@@ -1651,10 +1692,10 @@ static int iavf_set_interrupt_capability(struct iavf_adapter *adapter) ...@@ -1651,10 +1692,10 @@ static int iavf_set_interrupt_capability(struct iavf_adapter *adapter)
adapter->msix_entries[vector].entry = vector; adapter->msix_entries[vector].entry = vector;
err = iavf_acquire_msix_vectors(adapter, v_budget); err = iavf_acquire_msix_vectors(adapter, v_budget);
if (!err)
iavf_schedule_finish_config(adapter);
out: out:
netif_set_real_num_rx_queues(adapter->netdev, pairs);
netif_set_real_num_tx_queues(adapter->netdev, pairs);
return err; return err;
} }
...@@ -1828,18 +1869,15 @@ static int iavf_alloc_q_vectors(struct iavf_adapter *adapter) ...@@ -1828,18 +1869,15 @@ static int iavf_alloc_q_vectors(struct iavf_adapter *adapter)
static void iavf_free_q_vectors(struct iavf_adapter *adapter) static void iavf_free_q_vectors(struct iavf_adapter *adapter)
{ {
int q_idx, num_q_vectors; int q_idx, num_q_vectors;
int napi_vectors;
if (!adapter->q_vectors) if (!adapter->q_vectors)
return; return;
num_q_vectors = adapter->num_msix_vectors - NONQ_VECS; num_q_vectors = adapter->num_msix_vectors - NONQ_VECS;
napi_vectors = adapter->num_active_queues;
for (q_idx = 0; q_idx < num_q_vectors; q_idx++) { for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
struct iavf_q_vector *q_vector = &adapter->q_vectors[q_idx]; struct iavf_q_vector *q_vector = &adapter->q_vectors[q_idx];
if (q_idx < napi_vectors)
netif_napi_del(&q_vector->napi); netif_napi_del(&q_vector->napi);
} }
kfree(adapter->q_vectors); kfree(adapter->q_vectors);
...@@ -1877,9 +1915,7 @@ static int iavf_init_interrupt_scheme(struct iavf_adapter *adapter) ...@@ -1877,9 +1915,7 @@ static int iavf_init_interrupt_scheme(struct iavf_adapter *adapter)
goto err_alloc_queues; goto err_alloc_queues;
} }
rtnl_lock();
err = iavf_set_interrupt_capability(adapter); err = iavf_set_interrupt_capability(adapter);
rtnl_unlock();
if (err) { if (err) {
dev_err(&adapter->pdev->dev, dev_err(&adapter->pdev->dev,
"Unable to setup interrupt capabilities\n"); "Unable to setup interrupt capabilities\n");
...@@ -1932,15 +1968,16 @@ static void iavf_free_rss(struct iavf_adapter *adapter) ...@@ -1932,15 +1968,16 @@ static void iavf_free_rss(struct iavf_adapter *adapter)
/** /**
* iavf_reinit_interrupt_scheme - Reallocate queues and vectors * iavf_reinit_interrupt_scheme - Reallocate queues and vectors
* @adapter: board private structure * @adapter: board private structure
* @running: true if adapter->state == __IAVF_RUNNING
* *
* Returns 0 on success, negative on failure * Returns 0 on success, negative on failure
**/ **/
static int iavf_reinit_interrupt_scheme(struct iavf_adapter *adapter) static int iavf_reinit_interrupt_scheme(struct iavf_adapter *adapter, bool running)
{ {
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
int err; int err;
if (netif_running(netdev)) if (running)
iavf_free_traffic_irqs(adapter); iavf_free_traffic_irqs(adapter);
iavf_free_misc_irq(adapter); iavf_free_misc_irq(adapter);
iavf_reset_interrupt_capability(adapter); iavf_reset_interrupt_capability(adapter);
...@@ -1964,6 +2001,78 @@ static int iavf_reinit_interrupt_scheme(struct iavf_adapter *adapter) ...@@ -1964,6 +2001,78 @@ static int iavf_reinit_interrupt_scheme(struct iavf_adapter *adapter)
return err; return err;
} }
/**
* iavf_finish_config - do all netdev work that needs RTNL
* @work: our work_struct
*
* Do work that needs both RTNL and crit_lock.
**/
static void iavf_finish_config(struct work_struct *work)
{
struct iavf_adapter *adapter;
int pairs, err;
adapter = container_of(work, struct iavf_adapter, finish_config);
/* Always take RTNL first to prevent circular lock dependency */
rtnl_lock();
mutex_lock(&adapter->crit_lock);
if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES) &&
adapter->netdev_registered &&
!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) {
netdev_update_features(adapter->netdev);
adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES;
}
switch (adapter->state) {
case __IAVF_DOWN:
if (!adapter->netdev_registered) {
err = register_netdevice(adapter->netdev);
if (err) {
dev_err(&adapter->pdev->dev, "Unable to register netdev (%d)\n",
err);
/* go back and try again.*/
iavf_free_rss(adapter);
iavf_free_misc_irq(adapter);
iavf_reset_interrupt_capability(adapter);
iavf_change_state(adapter,
__IAVF_INIT_CONFIG_ADAPTER);
goto out;
}
adapter->netdev_registered = true;
}
/* Set the real number of queues when reset occurs while
* state == __IAVF_DOWN
*/
fallthrough;
case __IAVF_RUNNING:
pairs = adapter->num_active_queues;
netif_set_real_num_rx_queues(adapter->netdev, pairs);
netif_set_real_num_tx_queues(adapter->netdev, pairs);
break;
default:
break;
}
out:
mutex_unlock(&adapter->crit_lock);
rtnl_unlock();
}
/**
* iavf_schedule_finish_config - Set the flags and schedule a reset event
* @adapter: board private structure
**/
void iavf_schedule_finish_config(struct iavf_adapter *adapter)
{
if (!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section))
queue_work(adapter->wq, &adapter->finish_config);
}
/** /**
* iavf_process_aq_command - process aq_required flags * iavf_process_aq_command - process aq_required flags
* and sends aq command * and sends aq command
...@@ -2371,7 +2480,7 @@ int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter) ...@@ -2371,7 +2480,7 @@ int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter)
adapter->vsi_res->num_queue_pairs); adapter->vsi_res->num_queue_pairs);
adapter->flags |= IAVF_FLAG_REINIT_MSIX_NEEDED; adapter->flags |= IAVF_FLAG_REINIT_MSIX_NEEDED;
adapter->num_req_queues = adapter->vsi_res->num_queue_pairs; adapter->num_req_queues = adapter->vsi_res->num_queue_pairs;
iavf_schedule_reset(adapter); iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
return -EAGAIN; return -EAGAIN;
} }
...@@ -2601,22 +2710,8 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter) ...@@ -2601,22 +2710,8 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
netif_carrier_off(netdev); netif_carrier_off(netdev);
adapter->link_up = false; adapter->link_up = false;
/* set the semaphore to prevent any callbacks after device registration
* up to time when state of driver will be set to __IAVF_DOWN
*/
rtnl_lock();
if (!adapter->netdev_registered) {
err = register_netdevice(netdev);
if (err) {
rtnl_unlock();
goto err_register;
}
}
adapter->netdev_registered = true;
netif_tx_stop_all_queues(netdev); netif_tx_stop_all_queues(netdev);
if (CLIENT_ALLOWED(adapter)) { if (CLIENT_ALLOWED(adapter)) {
err = iavf_lan_add_device(adapter); err = iavf_lan_add_device(adapter);
if (err) if (err)
...@@ -2629,7 +2724,6 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter) ...@@ -2629,7 +2724,6 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
iavf_change_state(adapter, __IAVF_DOWN); iavf_change_state(adapter, __IAVF_DOWN);
set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
rtnl_unlock();
iavf_misc_irq_enable(adapter); iavf_misc_irq_enable(adapter);
wake_up(&adapter->down_waitqueue); wake_up(&adapter->down_waitqueue);
...@@ -2649,10 +2743,11 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter) ...@@ -2649,10 +2743,11 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
/* request initial VLAN offload settings */ /* request initial VLAN offload settings */
iavf_set_vlan_offload_features(adapter, 0, netdev->features); iavf_set_vlan_offload_features(adapter, 0, netdev->features);
iavf_schedule_finish_config(adapter);
return; return;
err_mem: err_mem:
iavf_free_rss(adapter); iavf_free_rss(adapter);
err_register:
iavf_free_misc_irq(adapter); iavf_free_misc_irq(adapter);
err_sw_init: err_sw_init:
iavf_reset_interrupt_capability(adapter); iavf_reset_interrupt_capability(adapter);
...@@ -2679,26 +2774,9 @@ static void iavf_watchdog_task(struct work_struct *work) ...@@ -2679,26 +2774,9 @@ static void iavf_watchdog_task(struct work_struct *work)
goto restart_watchdog; goto restart_watchdog;
} }
if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES) &&
adapter->netdev_registered &&
!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section) &&
rtnl_trylock()) {
netdev_update_features(adapter->netdev);
rtnl_unlock();
adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES;
}
if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
iavf_change_state(adapter, __IAVF_COMM_FAILED); iavf_change_state(adapter, __IAVF_COMM_FAILED);
if (adapter->flags & IAVF_FLAG_RESET_NEEDED) {
adapter->aq_required = 0;
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
mutex_unlock(&adapter->crit_lock);
queue_work(adapter->wq, &adapter->reset_task);
return;
}
switch (adapter->state) { switch (adapter->state) {
case __IAVF_STARTUP: case __IAVF_STARTUP:
iavf_startup(adapter); iavf_startup(adapter);
...@@ -2826,11 +2904,10 @@ static void iavf_watchdog_task(struct work_struct *work) ...@@ -2826,11 +2904,10 @@ static void iavf_watchdog_task(struct work_struct *work)
/* check for hw reset */ /* check for hw reset */
reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK; reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK;
if (!reg_val) { if (!reg_val) {
adapter->flags |= IAVF_FLAG_RESET_PENDING;
adapter->aq_required = 0; adapter->aq_required = 0;
adapter->current_op = VIRTCHNL_OP_UNKNOWN; adapter->current_op = VIRTCHNL_OP_UNKNOWN;
dev_err(&adapter->pdev->dev, "Hardware reset detected\n"); dev_err(&adapter->pdev->dev, "Hardware reset detected\n");
queue_work(adapter->wq, &adapter->reset_task); iavf_schedule_reset(adapter, IAVF_FLAG_RESET_PENDING);
mutex_unlock(&adapter->crit_lock); mutex_unlock(&adapter->crit_lock);
queue_delayed_work(adapter->wq, queue_delayed_work(adapter->wq,
&adapter->watchdog_task, HZ * 2); &adapter->watchdog_task, HZ * 2);
...@@ -2940,11 +3017,6 @@ static void iavf_reset_task(struct work_struct *work) ...@@ -2940,11 +3017,6 @@ static void iavf_reset_task(struct work_struct *work)
int i = 0, err; int i = 0, err;
bool running; bool running;
/* Detach interface to avoid subsequent NDO callbacks */
rtnl_lock();
netif_device_detach(netdev);
rtnl_unlock();
/* When device is being removed it doesn't make sense to run the reset /* When device is being removed it doesn't make sense to run the reset
* task, just return in such a case. * task, just return in such a case.
*/ */
...@@ -2952,7 +3024,7 @@ static void iavf_reset_task(struct work_struct *work) ...@@ -2952,7 +3024,7 @@ static void iavf_reset_task(struct work_struct *work)
if (adapter->state != __IAVF_REMOVE) if (adapter->state != __IAVF_REMOVE)
queue_work(adapter->wq, &adapter->reset_task); queue_work(adapter->wq, &adapter->reset_task);
goto reset_finish; return;
} }
while (!mutex_trylock(&adapter->client_lock)) while (!mutex_trylock(&adapter->client_lock))
...@@ -3010,11 +3082,6 @@ static void iavf_reset_task(struct work_struct *work) ...@@ -3010,11 +3082,6 @@ static void iavf_reset_task(struct work_struct *work)
iavf_disable_vf(adapter); iavf_disable_vf(adapter);
mutex_unlock(&adapter->client_lock); mutex_unlock(&adapter->client_lock);
mutex_unlock(&adapter->crit_lock); mutex_unlock(&adapter->crit_lock);
if (netif_running(netdev)) {
rtnl_lock();
dev_close(netdev);
rtnl_unlock();
}
return; /* Do not attempt to reinit. It's dead, Jim. */ return; /* Do not attempt to reinit. It's dead, Jim. */
} }
...@@ -3056,7 +3123,7 @@ static void iavf_reset_task(struct work_struct *work) ...@@ -3056,7 +3123,7 @@ static void iavf_reset_task(struct work_struct *work)
if ((adapter->flags & IAVF_FLAG_REINIT_MSIX_NEEDED) || if ((adapter->flags & IAVF_FLAG_REINIT_MSIX_NEEDED) ||
(adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED)) { (adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED)) {
err = iavf_reinit_interrupt_scheme(adapter); err = iavf_reinit_interrupt_scheme(adapter, running);
if (err) if (err)
goto reset_err; goto reset_err;
} }
...@@ -3151,10 +3218,11 @@ static void iavf_reset_task(struct work_struct *work) ...@@ -3151,10 +3218,11 @@ static void iavf_reset_task(struct work_struct *work)
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED; adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
wake_up(&adapter->reset_waitqueue);
mutex_unlock(&adapter->client_lock); mutex_unlock(&adapter->client_lock);
mutex_unlock(&adapter->crit_lock); mutex_unlock(&adapter->crit_lock);
goto reset_finish; return;
reset_err: reset_err:
if (running) { if (running) {
set_bit(__IAVF_VSI_DOWN, adapter->vsi.state); set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
...@@ -3164,21 +3232,7 @@ static void iavf_reset_task(struct work_struct *work) ...@@ -3164,21 +3232,7 @@ static void iavf_reset_task(struct work_struct *work)
mutex_unlock(&adapter->client_lock); mutex_unlock(&adapter->client_lock);
mutex_unlock(&adapter->crit_lock); mutex_unlock(&adapter->crit_lock);
if (netif_running(netdev)) {
/* Close device to ensure that Tx queues will not be started
* during netif_device_attach() at the end of the reset task.
*/
rtnl_lock();
dev_close(netdev);
rtnl_unlock();
}
dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n"); dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n");
reset_finish:
rtnl_lock();
netif_device_attach(netdev);
rtnl_unlock();
} }
/** /**
...@@ -3227,9 +3281,7 @@ static void iavf_adminq_task(struct work_struct *work) ...@@ -3227,9 +3281,7 @@ static void iavf_adminq_task(struct work_struct *work)
} while (pending); } while (pending);
mutex_unlock(&adapter->crit_lock); mutex_unlock(&adapter->crit_lock);
if ((adapter->flags & if (iavf_is_reset_in_progress(adapter))
(IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) ||
adapter->state == __IAVF_RESETTING)
goto freedom; goto freedom;
/* check for error indications */ /* check for error indications */
...@@ -4315,6 +4367,7 @@ static int iavf_close(struct net_device *netdev) ...@@ -4315,6 +4367,7 @@ static int iavf_close(struct net_device *netdev)
static int iavf_change_mtu(struct net_device *netdev, int new_mtu) static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
{ {
struct iavf_adapter *adapter = netdev_priv(netdev); struct iavf_adapter *adapter = netdev_priv(netdev);
int ret = 0;
netdev_dbg(netdev, "changing MTU from %d to %d\n", netdev_dbg(netdev, "changing MTU from %d to %d\n",
netdev->mtu, new_mtu); netdev->mtu, new_mtu);
...@@ -4325,11 +4378,15 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu) ...@@ -4325,11 +4378,15 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
} }
if (netif_running(netdev)) { if (netif_running(netdev)) {
adapter->flags |= IAVF_FLAG_RESET_NEEDED; iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
queue_work(adapter->wq, &adapter->reset_task); ret = iavf_wait_for_reset(adapter);
if (ret < 0)
netdev_warn(netdev, "MTU change interrupted waiting for reset");
else if (ret)
netdev_warn(netdev, "MTU change timed out waiting for reset");
} }
return 0; return ret;
} }
#define NETIF_VLAN_OFFLOAD_FEATURES (NETIF_F_HW_VLAN_CTAG_RX | \ #define NETIF_VLAN_OFFLOAD_FEATURES (NETIF_F_HW_VLAN_CTAG_RX | \
...@@ -4922,6 +4979,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -4922,6 +4979,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_WORK(&adapter->reset_task, iavf_reset_task); INIT_WORK(&adapter->reset_task, iavf_reset_task);
INIT_WORK(&adapter->adminq_task, iavf_adminq_task); INIT_WORK(&adapter->adminq_task, iavf_adminq_task);
INIT_WORK(&adapter->finish_config, iavf_finish_config);
INIT_DELAYED_WORK(&adapter->watchdog_task, iavf_watchdog_task); INIT_DELAYED_WORK(&adapter->watchdog_task, iavf_watchdog_task);
INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task); INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task);
queue_delayed_work(adapter->wq, &adapter->watchdog_task, queue_delayed_work(adapter->wq, &adapter->watchdog_task,
...@@ -4930,6 +4988,9 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -4930,6 +4988,9 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Setup the wait queue for indicating transition to down status */ /* Setup the wait queue for indicating transition to down status */
init_waitqueue_head(&adapter->down_waitqueue); init_waitqueue_head(&adapter->down_waitqueue);
/* Setup the wait queue for indicating transition to running state */
init_waitqueue_head(&adapter->reset_waitqueue);
/* Setup the wait queue for indicating virtchannel events */ /* Setup the wait queue for indicating virtchannel events */
init_waitqueue_head(&adapter->vc_waitqueue); init_waitqueue_head(&adapter->vc_waitqueue);
...@@ -5061,13 +5122,15 @@ static void iavf_remove(struct pci_dev *pdev) ...@@ -5061,13 +5122,15 @@ static void iavf_remove(struct pci_dev *pdev)
usleep_range(500, 1000); usleep_range(500, 1000);
} }
cancel_delayed_work_sync(&adapter->watchdog_task); cancel_delayed_work_sync(&adapter->watchdog_task);
cancel_work_sync(&adapter->finish_config);
if (adapter->netdev_registered) {
rtnl_lock(); rtnl_lock();
if (adapter->netdev_registered) {
unregister_netdevice(netdev); unregister_netdevice(netdev);
adapter->netdev_registered = false; adapter->netdev_registered = false;
rtnl_unlock();
} }
rtnl_unlock();
if (CLIENT_ALLOWED(adapter)) { if (CLIENT_ALLOWED(adapter)) {
err = iavf_lan_del_device(adapter); err = iavf_lan_del_device(adapter);
if (err) if (err)
......
...@@ -1961,9 +1961,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, ...@@ -1961,9 +1961,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
case VIRTCHNL_EVENT_RESET_IMPENDING: case VIRTCHNL_EVENT_RESET_IMPENDING:
dev_info(&adapter->pdev->dev, "Reset indication received from the PF\n"); dev_info(&adapter->pdev->dev, "Reset indication received from the PF\n");
if (!(adapter->flags & IAVF_FLAG_RESET_PENDING)) { if (!(adapter->flags & IAVF_FLAG_RESET_PENDING)) {
adapter->flags |= IAVF_FLAG_RESET_PENDING;
dev_info(&adapter->pdev->dev, "Scheduling reset task\n"); dev_info(&adapter->pdev->dev, "Scheduling reset task\n");
queue_work(adapter->wq, &adapter->reset_task); iavf_schedule_reset(adapter, IAVF_FLAG_RESET_PENDING);
} }
break; break;
default: default:
...@@ -2237,6 +2236,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, ...@@ -2237,6 +2236,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
iavf_process_config(adapter); iavf_process_config(adapter);
adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES; adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES;
iavf_schedule_finish_config(adapter);
iavf_set_queue_vlan_tag_loc(adapter); iavf_set_queue_vlan_tag_loc(adapter);
...@@ -2285,6 +2285,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, ...@@ -2285,6 +2285,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
case VIRTCHNL_OP_ENABLE_QUEUES: case VIRTCHNL_OP_ENABLE_QUEUES:
/* enable transmits */ /* enable transmits */
iavf_irq_enable(adapter, true); iavf_irq_enable(adapter, true);
wake_up(&adapter->reset_waitqueue);
adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED; adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED;
break; break;
case VIRTCHNL_OP_DISABLE_QUEUES: case VIRTCHNL_OP_DISABLE_QUEUES:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment