mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 13:41:51 +00:00
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.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
7f5acea727
@ -255,8 +255,10 @@ struct iavf_adapter {
|
||||
struct workqueue_struct *wq;
|
||||
struct work_struct reset_task;
|
||||
struct work_struct adminq_task;
|
||||
struct work_struct finish_config;
|
||||
struct delayed_work client_task;
|
||||
wait_queue_head_t down_waitqueue;
|
||||
wait_queue_head_t reset_waitqueue;
|
||||
wait_queue_head_t vc_waitqueue;
|
||||
struct iavf_q_vector *q_vectors;
|
||||
struct list_head vlan_filter_list;
|
||||
@ -518,8 +520,9 @@ int iavf_up(struct iavf_adapter *adapter);
|
||||
void iavf_down(struct iavf_adapter *adapter);
|
||||
int iavf_process_config(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_finish_config(struct iavf_adapter *adapter);
|
||||
void iavf_reset(struct iavf_adapter *adapter);
|
||||
void iavf_set_ethtool_ops(struct net_device *netdev);
|
||||
void iavf_update_stats(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);
|
||||
struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
|
||||
const u8 *macaddr);
|
||||
int iavf_wait_for_reset(struct iavf_adapter *adapter);
|
||||
#endif /* _IAVF_H_ */
|
||||
|
@ -484,6 +484,7 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags)
|
||||
{
|
||||
struct iavf_adapter *adapter = netdev_priv(netdev);
|
||||
u32 orig_flags, new_flags, changed_flags;
|
||||
int ret = 0;
|
||||
u32 i;
|
||||
|
||||
orig_flags = READ_ONCE(adapter->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 */
|
||||
if (changed_flags & IAVF_FLAG_LEGACY_RX) {
|
||||
if (netif_running(netdev)) {
|
||||
adapter->flags |= IAVF_FLAG_RESET_NEEDED;
|
||||
queue_work(adapter->wq, &adapter->reset_task);
|
||||
iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
|
||||
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,
|
||||
{
|
||||
struct iavf_adapter *adapter = netdev_priv(netdev);
|
||||
u32 new_rx_count, new_tx_count;
|
||||
int ret = 0;
|
||||
|
||||
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
|
||||
return -EINVAL;
|
||||
@ -671,11 +675,13 @@ static int iavf_set_ringparam(struct net_device *netdev,
|
||||
}
|
||||
|
||||
if (netif_running(netdev)) {
|
||||
adapter->flags |= IAVF_FLAG_RESET_NEEDED;
|
||||
queue_work(adapter->wq, &adapter->reset_task);
|
||||
iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
|
||||
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,
|
||||
{
|
||||
struct iavf_adapter *adapter = netdev_priv(netdev);
|
||||
u32 num_req = ch->combined_count;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
|
||||
adapter->num_tc) {
|
||||
@ -1852,22 +1858,13 @@ static int iavf_set_channels(struct net_device *netdev,
|
||||
|
||||
adapter->num_req_queues = num_req;
|
||||
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 */
|
||||
for (i = 0; i < IAVF_RESET_WAIT_COMPLETE_COUNT; i++) {
|
||||
msleep(IAVF_RESET_WAIT_MS);
|
||||
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;
|
||||
}
|
||||
ret = iavf_wait_for_reset(adapter);
|
||||
if (ret)
|
||||
netdev_warn(netdev, "Changing channel count timeout or interrupted waiting for reset");
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -166,6 +166,45 @@ static struct iavf_adapter *iavf_pdev_to_adapter(struct pci_dev *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
|
||||
* @hw: pointer to the HW structure
|
||||
@ -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
|
||||
* @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 &
|
||||
(IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) {
|
||||
adapter->flags |= IAVF_FLAG_RESET_NEEDED;
|
||||
if (!test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section) &&
|
||||
!(adapter->flags &
|
||||
(IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) {
|
||||
adapter->flags |= flags;
|
||||
queue_work(adapter->wq, &adapter->reset_task);
|
||||
}
|
||||
}
|
||||
@ -295,7 +336,7 @@ static void iavf_tx_timeout(struct net_device *netdev, unsigned int txqueue)
|
||||
struct iavf_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
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)
|
||||
adapter->msix_entries[vector].entry = vector;
|
||||
|
||||
err = iavf_acquire_msix_vectors(adapter, v_budget);
|
||||
if (!err)
|
||||
iavf_schedule_finish_config(adapter);
|
||||
|
||||
out:
|
||||
netif_set_real_num_rx_queues(adapter->netdev, pairs);
|
||||
netif_set_real_num_tx_queues(adapter->netdev, pairs);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1828,19 +1869,16 @@ static int iavf_alloc_q_vectors(struct iavf_adapter *adapter)
|
||||
static void iavf_free_q_vectors(struct iavf_adapter *adapter)
|
||||
{
|
||||
int q_idx, num_q_vectors;
|
||||
int napi_vectors;
|
||||
|
||||
if (!adapter->q_vectors)
|
||||
return;
|
||||
|
||||
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++) {
|
||||
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);
|
||||
adapter->q_vectors = NULL;
|
||||
@ -1877,9 +1915,7 @@ static int iavf_init_interrupt_scheme(struct iavf_adapter *adapter)
|
||||
goto err_alloc_queues;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = iavf_set_interrupt_capability(adapter);
|
||||
rtnl_unlock();
|
||||
if (err) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"Unable to setup interrupt capabilities\n");
|
||||
@ -1932,15 +1968,16 @@ static void iavf_free_rss(struct iavf_adapter *adapter)
|
||||
/**
|
||||
* iavf_reinit_interrupt_scheme - Reallocate queues and vectors
|
||||
* @adapter: board private structure
|
||||
* @running: true if adapter->state == __IAVF_RUNNING
|
||||
*
|
||||
* 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;
|
||||
int err;
|
||||
|
||||
if (netif_running(netdev))
|
||||
if (running)
|
||||
iavf_free_traffic_irqs(adapter);
|
||||
iavf_free_misc_irq(adapter);
|
||||
iavf_reset_interrupt_capability(adapter);
|
||||
@ -1964,6 +2001,78 @@ 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
|
||||
* and sends aq command
|
||||
@ -2371,7 +2480,7 @@ int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter)
|
||||
adapter->vsi_res->num_queue_pairs);
|
||||
adapter->flags |= IAVF_FLAG_REINIT_MSIX_NEEDED;
|
||||
adapter->num_req_queues = adapter->vsi_res->num_queue_pairs;
|
||||
iavf_schedule_reset(adapter);
|
||||
iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
@ -2601,22 +2710,8 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
|
||||
|
||||
netif_carrier_off(netdev);
|
||||
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);
|
||||
|
||||
if (CLIENT_ALLOWED(adapter)) {
|
||||
err = iavf_lan_add_device(adapter);
|
||||
if (err)
|
||||
@ -2629,7 +2724,6 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
|
||||
|
||||
iavf_change_state(adapter, __IAVF_DOWN);
|
||||
set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
|
||||
rtnl_unlock();
|
||||
|
||||
iavf_misc_irq_enable(adapter);
|
||||
wake_up(&adapter->down_waitqueue);
|
||||
@ -2649,10 +2743,11 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
|
||||
/* request initial VLAN offload settings */
|
||||
iavf_set_vlan_offload_features(adapter, 0, netdev->features);
|
||||
|
||||
iavf_schedule_finish_config(adapter);
|
||||
return;
|
||||
|
||||
err_mem:
|
||||
iavf_free_rss(adapter);
|
||||
err_register:
|
||||
iavf_free_misc_irq(adapter);
|
||||
err_sw_init:
|
||||
iavf_reset_interrupt_capability(adapter);
|
||||
@ -2679,26 +2774,9 @@ static void iavf_watchdog_task(struct work_struct *work)
|
||||
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)
|
||||
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) {
|
||||
case __IAVF_STARTUP:
|
||||
iavf_startup(adapter);
|
||||
@ -2826,11 +2904,10 @@ static void iavf_watchdog_task(struct work_struct *work)
|
||||
/* check for hw reset */
|
||||
reg_val = rd32(hw, IAVF_VF_ARQLEN1) & IAVF_VF_ARQLEN1_ARQENABLE_MASK;
|
||||
if (!reg_val) {
|
||||
adapter->flags |= IAVF_FLAG_RESET_PENDING;
|
||||
adapter->aq_required = 0;
|
||||
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
|
||||
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);
|
||||
queue_delayed_work(adapter->wq,
|
||||
&adapter->watchdog_task, HZ * 2);
|
||||
@ -2940,11 +3017,6 @@ static void iavf_reset_task(struct work_struct *work)
|
||||
int i = 0, err;
|
||||
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
|
||||
* task, just return in such a case.
|
||||
*/
|
||||
@ -2952,7 +3024,7 @@ static void iavf_reset_task(struct work_struct *work)
|
||||
if (adapter->state != __IAVF_REMOVE)
|
||||
queue_work(adapter->wq, &adapter->reset_task);
|
||||
|
||||
goto reset_finish;
|
||||
return;
|
||||
}
|
||||
|
||||
while (!mutex_trylock(&adapter->client_lock))
|
||||
@ -3010,11 +3082,6 @@ static void iavf_reset_task(struct work_struct *work)
|
||||
iavf_disable_vf(adapter);
|
||||
mutex_unlock(&adapter->client_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. */
|
||||
}
|
||||
|
||||
@ -3056,7 +3123,7 @@ continue_reset:
|
||||
|
||||
if ((adapter->flags & IAVF_FLAG_REINIT_MSIX_NEEDED) ||
|
||||
(adapter->flags & IAVF_FLAG_REINIT_ITR_NEEDED)) {
|
||||
err = iavf_reinit_interrupt_scheme(adapter);
|
||||
err = iavf_reinit_interrupt_scheme(adapter, running);
|
||||
if (err)
|
||||
goto reset_err;
|
||||
}
|
||||
@ -3151,10 +3218,11 @@ continue_reset:
|
||||
|
||||
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
|
||||
|
||||
wake_up(&adapter->reset_waitqueue);
|
||||
mutex_unlock(&adapter->client_lock);
|
||||
mutex_unlock(&adapter->crit_lock);
|
||||
|
||||
goto reset_finish;
|
||||
return;
|
||||
reset_err:
|
||||
if (running) {
|
||||
set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
|
||||
@ -3164,21 +3232,7 @@ reset_err:
|
||||
|
||||
mutex_unlock(&adapter->client_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");
|
||||
reset_finish:
|
||||
rtnl_lock();
|
||||
netif_device_attach(netdev);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3227,9 +3281,7 @@ static void iavf_adminq_task(struct work_struct *work)
|
||||
} while (pending);
|
||||
mutex_unlock(&adapter->crit_lock);
|
||||
|
||||
if ((adapter->flags &
|
||||
(IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) ||
|
||||
adapter->state == __IAVF_RESETTING)
|
||||
if (iavf_is_reset_in_progress(adapter))
|
||||
goto freedom;
|
||||
|
||||
/* check for error indications */
|
||||
@ -4315,6 +4367,7 @@ static int iavf_close(struct net_device *netdev)
|
||||
static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
|
||||
{
|
||||
struct iavf_adapter *adapter = netdev_priv(netdev);
|
||||
int ret = 0;
|
||||
|
||||
netdev_dbg(netdev, "changing MTU from %d to %d\n",
|
||||
netdev->mtu, new_mtu);
|
||||
@ -4325,11 +4378,15 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
|
||||
}
|
||||
|
||||
if (netif_running(netdev)) {
|
||||
adapter->flags |= IAVF_FLAG_RESET_NEEDED;
|
||||
queue_work(adapter->wq, &adapter->reset_task);
|
||||
iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
|
||||
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 | \
|
||||
@ -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->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->client_task, iavf_client_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)
|
||||
/* Setup the wait queue for indicating transition to down status */
|
||||
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 */
|
||||
init_waitqueue_head(&adapter->vc_waitqueue);
|
||||
|
||||
@ -5061,13 +5122,15 @@ static void iavf_remove(struct pci_dev *pdev)
|
||||
usleep_range(500, 1000);
|
||||
}
|
||||
cancel_delayed_work_sync(&adapter->watchdog_task);
|
||||
cancel_work_sync(&adapter->finish_config);
|
||||
|
||||
rtnl_lock();
|
||||
if (adapter->netdev_registered) {
|
||||
rtnl_lock();
|
||||
unregister_netdevice(netdev);
|
||||
adapter->netdev_registered = false;
|
||||
rtnl_unlock();
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
if (CLIENT_ALLOWED(adapter)) {
|
||||
err = iavf_lan_del_device(adapter);
|
||||
if (err)
|
||||
|
@ -1961,9 +1961,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
|
||||
case VIRTCHNL_EVENT_RESET_IMPENDING:
|
||||
dev_info(&adapter->pdev->dev, "Reset indication received from the PF\n");
|
||||
if (!(adapter->flags & IAVF_FLAG_RESET_PENDING)) {
|
||||
adapter->flags |= IAVF_FLAG_RESET_PENDING;
|
||||
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;
|
||||
default:
|
||||
@ -2237,6 +2236,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
|
||||
|
||||
iavf_process_config(adapter);
|
||||
adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES;
|
||||
iavf_schedule_finish_config(adapter);
|
||||
|
||||
iavf_set_queue_vlan_tag_loc(adapter);
|
||||
|
||||
@ -2285,6 +2285,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
|
||||
case VIRTCHNL_OP_ENABLE_QUEUES:
|
||||
/* enable transmits */
|
||||
iavf_irq_enable(adapter, true);
|
||||
wake_up(&adapter->reset_waitqueue);
|
||||
adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED;
|
||||
break;
|
||||
case VIRTCHNL_OP_DISABLE_QUEUES:
|
||||
|
Loading…
Reference in New Issue
Block a user