|
@@ -585,6 +585,20 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * i40e_get_head - Retrieve head from head writeback
|
|
|
|
|
+ * @tx_ring: tx ring to fetch head of
|
|
|
|
|
+ *
|
|
|
|
|
+ * Returns value of Tx ring head based on value stored
|
|
|
|
|
+ * in head write-back location
|
|
|
|
|
+ **/
|
|
|
|
|
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
|
|
|
|
|
+{
|
|
|
|
|
+ void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
|
|
|
|
|
+
|
|
|
|
|
+ return le32_to_cpu(*(volatile __le32 *)head);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* i40e_get_tx_pending - how many tx descriptors not processed
|
|
* i40e_get_tx_pending - how many tx descriptors not processed
|
|
|
* @tx_ring: the ring of descriptors
|
|
* @tx_ring: the ring of descriptors
|
|
@@ -594,10 +608,16 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
|
|
|
**/
|
|
**/
|
|
|
static u32 i40e_get_tx_pending(struct i40e_ring *ring)
|
|
static u32 i40e_get_tx_pending(struct i40e_ring *ring)
|
|
|
{
|
|
{
|
|
|
- u32 ntu = ((ring->next_to_clean <= ring->next_to_use)
|
|
|
|
|
- ? ring->next_to_use
|
|
|
|
|
- : ring->next_to_use + ring->count);
|
|
|
|
|
- return ntu - ring->next_to_clean;
|
|
|
|
|
|
|
+ u32 head, tail;
|
|
|
|
|
+
|
|
|
|
|
+ head = i40e_get_head(ring);
|
|
|
|
|
+ tail = readl(ring->tail);
|
|
|
|
|
+
|
|
|
|
|
+ if (head != tail)
|
|
|
|
|
+ return (head < tail) ?
|
|
|
|
|
+ tail - head : (tail + ring->count - head);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -606,6 +626,8 @@ static u32 i40e_get_tx_pending(struct i40e_ring *ring)
|
|
|
**/
|
|
**/
|
|
|
static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
|
|
static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
|
|
|
{
|
|
{
|
|
|
|
|
+ u32 tx_done = tx_ring->stats.packets;
|
|
|
|
|
+ u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
|
|
|
u32 tx_pending = i40e_get_tx_pending(tx_ring);
|
|
u32 tx_pending = i40e_get_tx_pending(tx_ring);
|
|
|
struct i40e_pf *pf = tx_ring->vsi->back;
|
|
struct i40e_pf *pf = tx_ring->vsi->back;
|
|
|
bool ret = false;
|
|
bool ret = false;
|
|
@@ -623,41 +645,25 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
|
|
|
* run the check_tx_hang logic with a transmit completion
|
|
* run the check_tx_hang logic with a transmit completion
|
|
|
* pending but without time to complete it yet.
|
|
* pending but without time to complete it yet.
|
|
|
*/
|
|
*/
|
|
|
- if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
|
|
|
|
|
- (tx_pending >= I40E_MIN_DESC_PENDING)) {
|
|
|
|
|
|
|
+ if ((tx_done_old == tx_done) && tx_pending) {
|
|
|
/* make sure it is true for two checks in a row */
|
|
/* make sure it is true for two checks in a row */
|
|
|
ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
|
|
ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
|
|
|
&tx_ring->state);
|
|
&tx_ring->state);
|
|
|
- } else if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
|
|
|
|
|
- (tx_pending < I40E_MIN_DESC_PENDING) &&
|
|
|
|
|
- (tx_pending > 0)) {
|
|
|
|
|
|
|
+ } else if (tx_done_old == tx_done &&
|
|
|
|
|
+ (tx_pending < I40E_MIN_DESC_PENDING) && (tx_pending > 0)) {
|
|
|
if (I40E_DEBUG_FLOW & pf->hw.debug_mask)
|
|
if (I40E_DEBUG_FLOW & pf->hw.debug_mask)
|
|
|
dev_info(tx_ring->dev, "HW needs some more descs to do a cacheline flush. tx_pending %d, queue %d",
|
|
dev_info(tx_ring->dev, "HW needs some more descs to do a cacheline flush. tx_pending %d, queue %d",
|
|
|
tx_pending, tx_ring->queue_index);
|
|
tx_pending, tx_ring->queue_index);
|
|
|
pf->tx_sluggish_count++;
|
|
pf->tx_sluggish_count++;
|
|
|
} else {
|
|
} else {
|
|
|
/* update completed stats and disarm the hang check */
|
|
/* update completed stats and disarm the hang check */
|
|
|
- tx_ring->tx_stats.tx_done_old = tx_ring->stats.packets;
|
|
|
|
|
|
|
+ tx_ring->tx_stats.tx_done_old = tx_done;
|
|
|
clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
|
|
clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/**
|
|
|
|
|
- * i40e_get_head - Retrieve head from head writeback
|
|
|
|
|
- * @tx_ring: tx ring to fetch head of
|
|
|
|
|
- *
|
|
|
|
|
- * Returns value of Tx ring head based on value stored
|
|
|
|
|
- * in head write-back location
|
|
|
|
|
- **/
|
|
|
|
|
-static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
|
|
|
|
|
-{
|
|
|
|
|
- void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
|
|
|
|
|
-
|
|
|
|
|
- return le32_to_cpu(*(volatile __le32 *)head);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
#define WB_STRIDE 0x3
|
|
#define WB_STRIDE 0x3
|
|
|
|
|
|
|
|
/**
|
|
/**
|