All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
To: davem@davemloft.net
Cc: Jacob Keller <jacob.e.keller@intel.com>,
	netdev@vger.kernel.org, nhorman@redhat.com, sassmann@redhat.com,
	jogreene@redhat.com, guru.anbalagane@oracle.com,
	Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Subject: [net-next 09/20] fm10k: wait for queues to drain if stop_hw() fails once
Date: Wed, 20 Jul 2016 15:23:47 -0700	[thread overview]
Message-ID: <1469053438-85381-10-git-send-email-jeffrey.t.kirsher@intel.com> (raw)
In-Reply-To: <1469053438-85381-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Jacob Keller <jacob.e.keller@intel.com>

It turns out that sometimes during a reset the Tx queues will be
temporarily stuck longer than .stop_hw() expects. Work around this issue
by attempting to .stop_hw() first. If it tails, wait a number of
attempts until the Tx queues appear to be drained. After this, attempt
stop_hw() again. This ensures that we avoid waiting if we don't need to,
such as during the first initialization of a VF, and give the proper
amount of time necessary to recover from most situations. It is possible
that the hardware is actually stuck. For PFs, this is usually fixed by
a datapath reset. Unfortunately the VF cannot request a similar reset
for itself.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Krishneil Singh <Krishneil.k.singh@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/fm10k/fm10k.h      |  1 +
 drivers/net/ethernet/intel/fm10k/fm10k_main.c |  2 +-
 drivers/net/ethernet/intel/fm10k/fm10k_pci.c  | 44 +++++++++++++++++++++++----
 3 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/intel/fm10k/fm10k.h b/drivers/net/ethernet/intel/fm10k/fm10k.h
index c8d0817..c4cf08d 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k.h
+++ b/drivers/net/ethernet/intel/fm10k/fm10k.h
@@ -458,6 +458,7 @@ __be16 fm10k_tx_encap_offload(struct sk_buff *skb);
 netdev_tx_t fm10k_xmit_frame_ring(struct sk_buff *skb,
 				  struct fm10k_ring *tx_ring);
 void fm10k_tx_timeout_reset(struct fm10k_intfc *interface);
+u64 fm10k_get_tx_pending(struct fm10k_ring *ring);
 bool fm10k_check_tx_hang(struct fm10k_ring *tx_ring);
 void fm10k_alloc_rx_buffers(struct fm10k_ring *rx_ring, u16 cleaned_count);
 
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
index c6a4645..c85fc9894 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
@@ -1128,7 +1128,7 @@ static u64 fm10k_get_tx_completed(struct fm10k_ring *ring)
 	return ring->stats.packets;
 }
 
-static u64 fm10k_get_tx_pending(struct fm10k_ring *ring)
+u64 fm10k_get_tx_pending(struct fm10k_ring *ring)
 {
 	struct fm10k_intfc *interface = ring->q_vector->interface;
 	struct fm10k_hw *hw = &interface->hw;
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
index 4dfd128..7c9b20c 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c
@@ -1613,7 +1613,7 @@ void fm10k_down(struct fm10k_intfc *interface)
 {
 	struct net_device *netdev = interface->netdev;
 	struct fm10k_hw *hw = &interface->hw;
-	int err;
+	int err, i = 0, count = 0;
 
 	/* signal that we are down to the interrupt handler and service task */
 	if (test_and_set_bit(__FM10K_DOWN, &interface->state))
@@ -1629,9 +1629,6 @@ void fm10k_down(struct fm10k_intfc *interface)
 	/* reset Rx filters */
 	fm10k_reset_rx_state(interface);
 
-	/* allow 10ms for device to quiesce */
-	usleep_range(10000, 20000);
-
 	/* disable polling routines */
 	fm10k_napi_disable_all(interface);
 
@@ -1642,11 +1639,46 @@ void fm10k_down(struct fm10k_intfc *interface)
 	while (test_and_set_bit(__FM10K_UPDATING_STATS, &interface->state))
 		usleep_range(1000, 2000);
 
+	/* skip waiting for TX DMA if we lost PCIe link */
+	if (FM10K_REMOVED(hw->hw_addr))
+		goto skip_tx_dma_drain;
+
+	/* In some rare circumstances it can take a while for Tx queues to
+	 * quiesce and be fully disabled. Attempt to .stop_hw() first, and
+	 * then if we get ERR_REQUESTS_PENDING, go ahead and wait in a loop
+	 * until the Tx queues have emptied, or until a number of retries. If
+	 * we fail to clear within the retry loop, we will issue a warning
+	 * indicating that Tx DMA is probably hung. Note this means we call
+	 * .stop_hw() twice but this shouldn't cause any problems.
+	 */
+	err = hw->mac.ops.stop_hw(hw);
+	if (err != FM10K_ERR_REQUESTS_PENDING)
+		goto skip_tx_dma_drain;
+
+#define TX_DMA_DRAIN_RETRIES 25
+	for (count = 0; count < TX_DMA_DRAIN_RETRIES; count++) {
+		usleep_range(10000, 20000);
+
+		/* start checking at the last ring to have pending Tx */
+		for (; i < interface->num_tx_queues; i++)
+			if (fm10k_get_tx_pending(interface->tx_ring[i]))
+				break;
+
+		/* if all the queues are drained, we can break now */
+		if (i == interface->num_tx_queues)
+			break;
+	}
+
+	if (count >= TX_DMA_DRAIN_RETRIES)
+		dev_err(&interface->pdev->dev,
+			"Tx queues failed to drain after %d tries. Tx DMA is probably hung.\n",
+			count);
+skip_tx_dma_drain:
 	/* Disable DMA engine for Tx/Rx */
 	err = hw->mac.ops.stop_hw(hw);
 	if (err == FM10K_ERR_REQUESTS_PENDING)
-		dev_info(&interface->pdev->dev,
-			 "due to pending requests hw was not shut down gracefully\n");
+		dev_err(&interface->pdev->dev,
+			"due to pending requests hw was not shut down gracefully\n");
 	else if (err)
 		dev_err(&interface->pdev->dev, "stop_hw failed: %d\n", err);
 
-- 
2.5.5

  parent reply	other threads:[~2016-07-20 22:24 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-20 22:23 [net-next 00/20][pull request] 100GbE Intel Wired LAN Driver Updates 2016-07-20 Jeff Kirsher
2016-07-20 22:23 ` [net-next 01/20] fm10k: no need to continue in fm10k_down if __FM10K_DOWN already set Jeff Kirsher
2016-07-20 22:23 ` [net-next 02/20] fm10k: avoid possible null pointer dereference in fm10k_update_stats Jeff Kirsher
2016-07-20 22:23 ` [net-next 03/20] fm10k: prevent multiple threads updating statistics Jeff Kirsher
2016-07-20 22:23 ` [net-next 04/20] fm10k: Reset mailbox global interrupts Jeff Kirsher
2016-07-20 22:23 ` [net-next 05/20] fm10k: don't stop reset due to FM10K_ERR_REQUESTS_PENDING Jeff Kirsher
2016-07-20 22:23 ` [net-next 06/20] fm10k: perform data path reset even when switch is not ready Jeff Kirsher
2016-07-20 22:23 ` [net-next 07/20] fm10k: use actual hardware registers when checking for pending Tx Jeff Kirsher
2016-07-20 22:23 ` [net-next 08/20] fm10k: only warn when stop_hw fails with FM10K_ERR_REQUESTS_PENDING Jeff Kirsher
2016-07-20 22:23 ` Jeff Kirsher [this message]
2016-07-20 22:23 ` [net-next 10/20] fm10k: split fm10k_reinit into two functions Jeff Kirsher
2016-07-20 22:23 ` [net-next 11/20] fm10k: implement prepare_suspend and handle_resume Jeff Kirsher
2016-07-20 22:23 ` [net-next 12/20] fm10k: use common reset flow when handling io errors from PCI stack Jeff Kirsher
2016-07-20 22:23 ` [net-next 13/20] fm10k: implement reset_notify handler for PCIe FLR events Jeff Kirsher
2016-07-20 22:23 ` [net-next 14/20] fm10k: use common flow for suspend and resume Jeff Kirsher
2016-07-20 22:23 ` [net-next 15/20] fm10k: enable bus master after every reset Jeff Kirsher
2016-07-20 22:23 ` [net-next 16/20] fm10k: check if PCIe link is restored Jeff Kirsher
2016-07-21 10:51   ` Sergei Shtylyov
2016-07-21 20:13     ` ~~ Keller, Jacob E
2016-07-20 22:23 ` [net-next 17/20] fm10k: implement request_lport_map pointer Jeff Kirsher
2016-07-20 22:23 ` [net-next 18/20] fm10k: force link to remain down for at least a second on resume events Jeff Kirsher
2016-07-20 22:23 ` [net-next 19/20] fm10k: return proper error code when pci_enable_msix_range fails Jeff Kirsher
2016-07-20 22:23 ` [net-next 20/20] fm10k: bump version number Jeff Kirsher
2016-07-21  5:05 ` [net-next 00/20][pull request] 100GbE Intel Wired LAN Driver Updates 2016-07-20 David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1469053438-85381-10-git-send-email-jeffrey.t.kirsher@intel.com \
    --to=jeffrey.t.kirsher@intel.com \
    --cc=davem@davemloft.net \
    --cc=guru.anbalagane@oracle.com \
    --cc=jacob.e.keller@intel.com \
    --cc=jogreene@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=nhorman@redhat.com \
    --cc=sassmann@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.