Skip to content

Commit c2ed240

Browse files
Marcin Szycikanguy11
authored andcommitted
iavf: Wait for reset in callbacks which trigger it
There was a fail when trying to add the interface to bonding right after changing the MTU on the interface. It was caused by bonding interface unable to open the interface due to interface being in __RESETTING state because of MTU change. Add new reset_waitqueue to indicate that reset has finished. Add waiting for reset to finish in callbacks which trigger hw reset: iavf_set_priv_flags(), iavf_change_mtu() and iavf_set_ringparam(). We use a 5000ms timeout period because on Hyper-V based systems, this operation takes around 3000-4000ms. In normal circumstances, it doesn't take more than 500ms to complete. Add a function iavf_wait_for_reset() to reuse waiting for reset code and use it also in iavf_set_channels(), which already waits for reset. We don't use error handling in iavf_set_channels() as this could cause the device to be in incorrect state if the reset was scheduled but hit timeout or the waitng function was interrupted by a signal. Fixes: 4e5e6b5 ("iavf: Fix return of set the new channel count") Signed-off-by: Marcin Szycik <[email protected]> Co-developed-by: Dawid Wesierski <[email protected]> Signed-off-by: Dawid Wesierski <[email protected]> Signed-off-by: Sylwester Dziedziuch <[email protected]> Signed-off-by: Kamil Maziarz <[email protected]> Signed-off-by: Mateusz Palczewski <[email protected]> Tested-by: Rafal Romanowski <[email protected]> Signed-off-by: Tony Nguyen <[email protected]>
1 parent a77ed5c commit c2ed240

File tree

4 files changed

+68
-17
lines changed

4 files changed

+68
-17
lines changed

drivers/net/ethernet/intel/iavf/iavf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ struct iavf_adapter {
257257
struct work_struct adminq_task;
258258
struct delayed_work client_task;
259259
wait_queue_head_t down_waitqueue;
260+
wait_queue_head_t reset_waitqueue;
260261
wait_queue_head_t vc_waitqueue;
261262
struct iavf_q_vector *q_vectors;
262263
struct list_head vlan_filter_list;
@@ -582,4 +583,5 @@ void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter);
582583
void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter);
583584
struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
584585
const u8 *macaddr);
586+
int iavf_wait_for_reset(struct iavf_adapter *adapter);
585587
#endif /* _IAVF_H_ */

drivers/net/ethernet/intel/iavf/iavf_ethtool.c

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags)
484484
{
485485
struct iavf_adapter *adapter = netdev_priv(netdev);
486486
u32 orig_flags, new_flags, changed_flags;
487+
int ret = 0;
487488
u32 i;
488489

489490
orig_flags = READ_ONCE(adapter->flags);
@@ -533,10 +534,13 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags)
533534
if (netif_running(netdev)) {
534535
adapter->flags |= IAVF_FLAG_RESET_NEEDED;
535536
queue_work(adapter->wq, &adapter->reset_task);
537+
ret = iavf_wait_for_reset(adapter);
538+
if (ret)
539+
netdev_warn(netdev, "Changing private flags timeout or interrupted waiting for reset");
536540
}
537541
}
538542

539-
return 0;
543+
return ret;
540544
}
541545

542546
/**
@@ -627,6 +631,7 @@ static int iavf_set_ringparam(struct net_device *netdev,
627631
{
628632
struct iavf_adapter *adapter = netdev_priv(netdev);
629633
u32 new_rx_count, new_tx_count;
634+
int ret = 0;
630635

631636
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
632637
return -EINVAL;
@@ -673,9 +678,12 @@ static int iavf_set_ringparam(struct net_device *netdev,
673678
if (netif_running(netdev)) {
674679
adapter->flags |= IAVF_FLAG_RESET_NEEDED;
675680
queue_work(adapter->wq, &adapter->reset_task);
681+
ret = iavf_wait_for_reset(adapter);
682+
if (ret)
683+
netdev_warn(netdev, "Changing ring parameters timeout or interrupted waiting for reset");
676684
}
677685

678-
return 0;
686+
return ret;
679687
}
680688

681689
/**
@@ -1830,7 +1838,7 @@ static int iavf_set_channels(struct net_device *netdev,
18301838
{
18311839
struct iavf_adapter *adapter = netdev_priv(netdev);
18321840
u32 num_req = ch->combined_count;
1833-
int i;
1841+
int ret = 0;
18341842

18351843
if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
18361844
adapter->num_tc) {
@@ -1854,20 +1862,11 @@ static int iavf_set_channels(struct net_device *netdev,
18541862
adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
18551863
iavf_schedule_reset(adapter);
18561864

1857-
/* wait for the reset is done */
1858-
for (i = 0; i < IAVF_RESET_WAIT_COMPLETE_COUNT; i++) {
1859-
msleep(IAVF_RESET_WAIT_MS);
1860-
if (adapter->flags & IAVF_FLAG_RESET_PENDING)
1861-
continue;
1862-
break;
1863-
}
1864-
if (i == IAVF_RESET_WAIT_COMPLETE_COUNT) {
1865-
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
1866-
adapter->num_req_queues = 0;
1867-
return -EOPNOTSUPP;
1868-
}
1865+
ret = iavf_wait_for_reset(adapter);
1866+
if (ret)
1867+
netdev_warn(netdev, "Changing channel count timeout or interrupted waiting for reset");
18691868

1870-
return 0;
1869+
return ret;
18711870
}
18721871

18731872
/**

drivers/net/ethernet/intel/iavf/iavf_main.c

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,45 @@ static struct iavf_adapter *iavf_pdev_to_adapter(struct pci_dev *pdev)
166166
return netdev_priv(pci_get_drvdata(pdev));
167167
}
168168

169+
/**
170+
* iavf_is_reset_in_progress - Check if a reset is in progress
171+
* @adapter: board private structure
172+
*/
173+
static bool iavf_is_reset_in_progress(struct iavf_adapter *adapter)
174+
{
175+
if (adapter->state == __IAVF_RESETTING ||
176+
adapter->flags & (IAVF_FLAG_RESET_PENDING |
177+
IAVF_FLAG_RESET_NEEDED))
178+
return true;
179+
180+
return false;
181+
}
182+
183+
/**
184+
* iavf_wait_for_reset - Wait for reset to finish.
185+
* @adapter: board private structure
186+
*
187+
* Returns 0 if reset finished successfully, negative on timeout or interrupt.
188+
*/
189+
int iavf_wait_for_reset(struct iavf_adapter *adapter)
190+
{
191+
int ret = wait_event_interruptible_timeout(adapter->reset_waitqueue,
192+
!iavf_is_reset_in_progress(adapter),
193+
msecs_to_jiffies(5000));
194+
195+
/* If ret < 0 then it means wait was interrupted.
196+
* If ret == 0 then it means we got a timeout while waiting
197+
* for reset to finish.
198+
* If ret > 0 it means reset has finished.
199+
*/
200+
if (ret > 0)
201+
return 0;
202+
else if (ret < 0)
203+
return -EINTR;
204+
else
205+
return -EBUSY;
206+
}
207+
169208
/**
170209
* iavf_allocate_dma_mem_d - OS specific memory alloc for shared code
171210
* @hw: pointer to the HW structure
@@ -3149,6 +3188,7 @@ static void iavf_reset_task(struct work_struct *work)
31493188

31503189
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
31513190

3191+
wake_up(&adapter->reset_waitqueue);
31523192
mutex_unlock(&adapter->client_lock);
31533193
mutex_unlock(&adapter->crit_lock);
31543194

@@ -4313,6 +4353,7 @@ static int iavf_close(struct net_device *netdev)
43134353
static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
43144354
{
43154355
struct iavf_adapter *adapter = netdev_priv(netdev);
4356+
int ret = 0;
43164357

43174358
netdev_dbg(netdev, "changing MTU from %d to %d\n",
43184359
netdev->mtu, new_mtu);
@@ -4325,9 +4366,14 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
43254366
if (netif_running(netdev)) {
43264367
adapter->flags |= IAVF_FLAG_RESET_NEEDED;
43274368
queue_work(adapter->wq, &adapter->reset_task);
4369+
ret = iavf_wait_for_reset(adapter);
4370+
if (ret < 0)
4371+
netdev_warn(netdev, "MTU change interrupted waiting for reset");
4372+
else if (ret)
4373+
netdev_warn(netdev, "MTU change timed out waiting for reset");
43284374
}
43294375

4330-
return 0;
4376+
return ret;
43314377
}
43324378

43334379
#define NETIF_VLAN_OFFLOAD_FEATURES (NETIF_F_HW_VLAN_CTAG_RX | \
@@ -4928,6 +4974,9 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
49284974
/* Setup the wait queue for indicating transition to down status */
49294975
init_waitqueue_head(&adapter->down_waitqueue);
49304976

4977+
/* Setup the wait queue for indicating transition to running state */
4978+
init_waitqueue_head(&adapter->reset_waitqueue);
4979+
49314980
/* Setup the wait queue for indicating virtchannel events */
49324981
init_waitqueue_head(&adapter->vc_waitqueue);
49334982

drivers/net/ethernet/intel/iavf/iavf_virtchnl.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,6 +2285,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
22852285
case VIRTCHNL_OP_ENABLE_QUEUES:
22862286
/* enable transmits */
22872287
iavf_irq_enable(adapter, true);
2288+
wake_up(&adapter->reset_waitqueue);
22882289
adapter->flags &= ~IAVF_FLAG_QUEUES_DISABLED;
22892290
break;
22902291
case VIRTCHNL_OP_DISABLE_QUEUES:

0 commit comments

Comments
 (0)