Commit 525d9e824018cd7cc8d8d44832ddcd363abfe6e1

Authored by Daniel Pieczko
Committed by Ben Hutchings
1 parent 876be083b6

sfc: Work-around flush timeout when flushes have completed

We sometimes hit a "failed to flush" timeout on some TX queues, but the
flushes have completed and the flush completion events seem to go missing.
In this case, we can check the TX_DESC_PTR_TBL register and drain the
queues if the flushes had finished.

[bwh: Minor fixes to coding style]
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>

Showing 2 changed files with 53 additions and 4 deletions Side-by-side Diff

drivers/net/ethernet/sfc/net_driver.h
... ... @@ -200,6 +200,7 @@
200 200 /* Members shared between paths and sometimes updated */
201 201 unsigned int empty_read_count ____cacheline_aligned_in_smp;
202 202 #define EFX_EMPTY_COUNT_VALID 0x80000000
  203 + atomic_t flush_outstanding;
203 204 };
204 205  
205 206 /**
drivers/net/ethernet/sfc/nic.c
... ... @@ -73,6 +73,8 @@
73 73 _EFX_CHANNEL_MAGIC(_EFX_CHANNEL_MAGIC_TX_DRAIN, \
74 74 (_tx_queue)->queue)
75 75  
  76 +static void efx_magic_event(struct efx_channel *channel, u32 magic);
  77 +
76 78 /**************************************************************************
77 79 *
78 80 * Solarstorm hardware access
... ... @@ -491,6 +493,9 @@
491 493 struct efx_nic *efx = tx_queue->efx;
492 494 efx_oword_t tx_flush_descq;
493 495  
  496 + WARN_ON(atomic_read(&tx_queue->flush_outstanding));
  497 + atomic_set(&tx_queue->flush_outstanding, 1);
  498 +
494 499 EFX_POPULATE_OWORD_2(tx_flush_descq,
495 500 FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
496 501 FRF_AZ_TX_FLUSH_DESCQ, tx_queue->queue);
... ... @@ -666,6 +671,47 @@
666 671 && atomic_read(&efx->rxq_flush_pending) > 0));
667 672 }
668 673  
  674 +static bool efx_check_tx_flush_complete(struct efx_nic *efx)
  675 +{
  676 + bool i = true;
  677 + efx_oword_t txd_ptr_tbl;
  678 + struct efx_channel *channel;
  679 + struct efx_tx_queue *tx_queue;
  680 +
  681 + efx_for_each_channel(channel, efx) {
  682 + efx_for_each_channel_tx_queue(tx_queue, channel) {
  683 + efx_reado_table(efx, &txd_ptr_tbl,
  684 + FR_BZ_TX_DESC_PTR_TBL, tx_queue->queue);
  685 + if (EFX_OWORD_FIELD(txd_ptr_tbl,
  686 + FRF_AZ_TX_DESCQ_FLUSH) ||
  687 + EFX_OWORD_FIELD(txd_ptr_tbl,
  688 + FRF_AZ_TX_DESCQ_EN)) {
  689 + netif_dbg(efx, hw, efx->net_dev,
  690 + "flush did not complete on TXQ %d\n",
  691 + tx_queue->queue);
  692 + i = false;
  693 + } else if (atomic_cmpxchg(&tx_queue->flush_outstanding,
  694 + 1, 0)) {
  695 + /* The flush is complete, but we didn't
  696 + * receive a flush completion event
  697 + */
  698 + netif_dbg(efx, hw, efx->net_dev,
  699 + "flush complete on TXQ %d, so drain "
  700 + "the queue\n", tx_queue->queue);
  701 + /* Don't need to increment drain_pending as it
  702 + * has already been incremented for the queues
  703 + * which did not drain
  704 + */
  705 + efx_magic_event(channel,
  706 + EFX_CHANNEL_MAGIC_TX_DRAIN(
  707 + tx_queue));
  708 + }
  709 + }
  710 + }
  711 +
  712 + return i;
  713 +}
  714 +
669 715 /* Flush all the transmit queues, and continue flushing receive queues until
670 716 * they're all flushed. Wait for the DRAIN events to be recieved so that there
671 717 * are no more RX and TX events left on any channel. */
... ... @@ -726,7 +772,8 @@
726 772 timeout);
727 773 }
728 774  
729   - if (atomic_read(&efx->drain_pending)) {
  775 + if (atomic_read(&efx->drain_pending) &&
  776 + !efx_check_tx_flush_complete(efx)) {
730 777 netif_err(efx, hw, efx->net_dev, "failed to flush %d queues "
731 778 "(rx %d+%d)\n", atomic_read(&efx->drain_pending),
732 779 atomic_read(&efx->rxq_flush_outstanding),
... ... @@ -1018,9 +1065,10 @@
1018 1065 if (qid < EFX_TXQ_TYPES * efx->n_tx_channels) {
1019 1066 tx_queue = efx_get_tx_queue(efx, qid / EFX_TXQ_TYPES,
1020 1067 qid % EFX_TXQ_TYPES);
1021   -
1022   - efx_magic_event(tx_queue->channel,
1023   - EFX_CHANNEL_MAGIC_TX_DRAIN(tx_queue));
  1068 + if (atomic_cmpxchg(&tx_queue->flush_outstanding, 1, 0)) {
  1069 + efx_magic_event(tx_queue->channel,
  1070 + EFX_CHANNEL_MAGIC_TX_DRAIN(tx_queue));
  1071 + }
1024 1072 }
1025 1073 }
1026 1074