aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Brady <alan.brady@intel.com>2018-02-12 09:16:59 -0500
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2018-02-26 15:33:27 -0500
commit04d4105174349dceccf9545a3e5e421c18f2cc56 (patch)
tree72b598ef1d8f56760acd7892d0c7daa56e99f548
parent8cd5fe62cc5a2aca1c698c28baa46ac6931ba11f (diff)
i40e/i40evf: use SW variables for hang detection
The i40e_detect_recover_hung function uses the i40e_get_tx_pending function to determine if there are packets stalled on the ring. i40e_get_tx_pending calculates the pending packets using the head writeback value and HW tail. If the queue is stopped and we lose the interrupt to update our next_to_clean then we a) won't get another interrupt to clean because queue is stopped b) we won't catch the problem with i40e_detect_recover_hung because the HW values look like there's no packets waiting to be transmitted. Using the SW values we can catch the issue because next_to_clean will be out of sync with head writeback. This has the added benefit being less CPU intensive because we don't need to reach into the hardware to get the values. Signed-off-by: Alan Brady <alan.brady@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c16
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.h2
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_txrx.c2
3 files changed, 13 insertions, 7 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 1ec9b1d8023d..97cfe944b568 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -708,16 +708,22 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
708/** 708/**
709 * i40e_get_tx_pending - how many tx descriptors not processed 709 * i40e_get_tx_pending - how many tx descriptors not processed
710 * @tx_ring: the ring of descriptors 710 * @tx_ring: the ring of descriptors
711 * @in_sw: use SW variables
711 * 712 *
712 * Since there is no access to the ring head register 713 * Since there is no access to the ring head register
713 * in XL710, we need to use our local copies 714 * in XL710, we need to use our local copies
714 **/ 715 **/
715u32 i40e_get_tx_pending(struct i40e_ring *ring) 716u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw)
716{ 717{
717 u32 head, tail; 718 u32 head, tail;
718 719
719 head = i40e_get_head(ring); 720 if (!in_sw) {
720 tail = readl(ring->tail); 721 head = i40e_get_head(ring);
722 tail = readl(ring->tail);
723 } else {
724 head = ring->next_to_clean;
725 tail = ring->next_to_use;
726 }
721 727
722 if (head != tail) 728 if (head != tail)
723 return (head < tail) ? 729 return (head < tail) ?
@@ -774,7 +780,7 @@ void i40e_detect_recover_hung(struct i40e_vsi *vsi)
774 */ 780 */
775 smp_rmb(); 781 smp_rmb();
776 tx_ring->tx_stats.prev_pkt_ctr = 782 tx_ring->tx_stats.prev_pkt_ctr =
777 i40e_get_tx_pending(tx_ring) ? packets : -1; 783 i40e_get_tx_pending(tx_ring, true) ? packets : -1;
778 } 784 }
779 } 785 }
780} 786}
@@ -898,7 +904,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
898 * them to be written back in case we stay in NAPI. 904 * them to be written back in case we stay in NAPI.
899 * In this mode on X722 we do not enable Interrupt. 905 * In this mode on X722 we do not enable Interrupt.
900 */ 906 */
901 unsigned int j = i40e_get_tx_pending(tx_ring); 907 unsigned int j = i40e_get_tx_pending(tx_ring, false);
902 908
903 if (budget && 909 if (budget &&
904 ((j / WB_STRIDE) == 0) && (j > 0) && 910 ((j / WB_STRIDE) == 0) && (j > 0) &&
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index f75a8fe68fcf..3c80ea784389 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -505,7 +505,7 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring);
505void i40e_free_rx_resources(struct i40e_ring *rx_ring); 505void i40e_free_rx_resources(struct i40e_ring *rx_ring);
506int i40e_napi_poll(struct napi_struct *napi, int budget); 506int i40e_napi_poll(struct napi_struct *napi, int budget);
507void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector); 507void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);
508u32 i40e_get_tx_pending(struct i40e_ring *ring); 508u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw);
509void i40e_detect_recover_hung(struct i40e_vsi *vsi); 509void i40e_detect_recover_hung(struct i40e_vsi *vsi);
510int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size); 510int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
511bool __i40e_chk_linearize(struct sk_buff *skb); 511bool __i40e_chk_linearize(struct sk_buff *skb);
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
index eb8f3e327f6b..e088d23eb083 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
@@ -196,7 +196,7 @@ void i40evf_detect_recover_hung(struct i40e_vsi *vsi)
196 */ 196 */
197 smp_rmb(); 197 smp_rmb();
198 tx_ring->tx_stats.prev_pkt_ctr = 198 tx_ring->tx_stats.prev_pkt_ctr =
199 i40evf_get_tx_pending(tx_ring, false) ? packets : -1; 199 i40evf_get_tx_pending(tx_ring, true) ? packets : -1;
200 } 200 }
201 } 201 }
202} 202}