Commit b03a8c1f authored by Kiran Patil's avatar Kiran Patil Committed by Jeff Kirsher

i40e/i40evf: refactor tx timeout logic

This patch modifies the driver timeout logic by issuing a writeback
request via a software interrupt to the hardware the first time the
driver detects a hang. The driver was too aggressive in resetting a hung
queue, so back that off by removing logic to down the netdevice after
too many hangs, and move the function to the service task.

Change-ID: Ife100b9d124cd08cbdb81ab659008c1b9abbedea
Signed-off-by: default avatarKiran Patil <kiran.patil@intel.com>
Signed-off-by: default avatarShannon Nelson <shannon.nelson@intel.com>
Signed-off-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 1e6d6f8c
...@@ -243,7 +243,6 @@ struct i40e_pf { ...@@ -243,7 +243,6 @@ struct i40e_pf {
struct pci_dev *pdev; struct pci_dev *pdev;
struct i40e_hw hw; struct i40e_hw hw;
unsigned long state; unsigned long state;
unsigned long link_check_timeout;
struct msix_entry *msix_entries; struct msix_entry *msix_entries;
bool fc_autoneg_status; bool fc_autoneg_status;
......
This diff is collapsed.
...@@ -600,7 +600,6 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring) ...@@ -600,7 +600,6 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
} }
} }
/** /**
* 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
...@@ -608,7 +607,7 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring) ...@@ -608,7 +607,7 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
* Since there is no access to the ring head register * Since there is no access to the ring head register
* in XL710, we need to use our local copies * in XL710, we need to use our local copies
**/ **/
static u32 i40e_get_tx_pending(struct i40e_ring *ring) u32 i40e_get_tx_pending(struct i40e_ring *ring)
{ {
u32 head, tail; u32 head, tail;
...@@ -622,50 +621,6 @@ static u32 i40e_get_tx_pending(struct i40e_ring *ring) ...@@ -622,50 +621,6 @@ static u32 i40e_get_tx_pending(struct i40e_ring *ring)
return 0; return 0;
} }
/**
* i40e_check_tx_hang - Is there a hang in the Tx queue
* @tx_ring: the ring of descriptors
**/
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);
struct i40e_pf *pf = tx_ring->vsi->back;
bool ret = false;
clear_check_for_tx_hang(tx_ring);
/* Check for a hung queue, but be thorough. This verifies
* that a transmit has been completed since the previous
* check AND there is at least one packet pending. The
* ARMED bit is set to indicate a potential hang. The
* bit is cleared if a pause frame is received to remove
* false hang detection due to PFC or 802.3x frames. By
* requiring this to fail twice we avoid races with
* PFC clearing the ARMED bit and conditions where we
* run the check_tx_hang logic with a transmit completion
* pending but without time to complete it yet.
*/
if ((tx_done_old == tx_done) && tx_pending) {
/* make sure it is true for two checks in a row */
ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
&tx_ring->state);
} else if (tx_done_old == tx_done &&
(tx_pending < I40E_MIN_DESC_PENDING) && (tx_pending > 0)) {
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",
tx_pending, tx_ring->queue_index);
pf->tx_sluggish_count++;
} else {
/* update completed stats and disarm the hang check */
tx_ring->tx_stats.tx_done_old = tx_done;
clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
}
return ret;
}
#define WB_STRIDE 0x3 #define WB_STRIDE 0x3
/** /**
...@@ -783,32 +738,6 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) ...@@ -783,32 +738,6 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
else else
tx_ring->arm_wb = false; tx_ring->arm_wb = false;
if (check_for_tx_hang(tx_ring) && i40e_check_tx_hang(tx_ring)) {
/* schedule immediate reset if we believe we hung */
dev_info(tx_ring->dev, "Detected Tx Unit Hang\n"
" VSI <%d>\n"
" Tx Queue <%d>\n"
" next_to_use <%x>\n"
" next_to_clean <%x>\n",
tx_ring->vsi->seid,
tx_ring->queue_index,
tx_ring->next_to_use, i);
netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
dev_info(tx_ring->dev,
"tx hang detected on queue %d, reset requested\n",
tx_ring->queue_index);
/* do not fire the reset immediately, wait for the stack to
* decide we are truly stuck, also prevents every queue from
* simultaneously requesting a reset
*/
/* the adapter is about to reset, no point in enabling polling */
budget = 1;
}
netdev_tx_completed_queue(netdev_get_tx_queue(tx_ring->netdev, netdev_tx_completed_queue(netdev_get_tx_queue(tx_ring->netdev,
tx_ring->queue_index), tx_ring->queue_index),
total_packets, total_bytes); total_packets, total_bytes);
...@@ -838,7 +767,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) ...@@ -838,7 +767,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
* @q_vector: the vector on which to force writeback * @q_vector: the vector on which to force writeback
* *
**/ **/
static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
{ {
u16 flags = q_vector->tx.ring[0].flags; u16 flags = q_vector->tx.ring[0].flags;
......
...@@ -199,8 +199,6 @@ struct i40e_rx_queue_stats { ...@@ -199,8 +199,6 @@ struct i40e_rx_queue_stats {
enum i40e_ring_state_t { enum i40e_ring_state_t {
__I40E_TX_FDIR_INIT_DONE, __I40E_TX_FDIR_INIT_DONE,
__I40E_TX_XPS_INIT_DONE, __I40E_TX_XPS_INIT_DONE,
__I40E_TX_DETECT_HANG,
__I40E_HANG_CHECK_ARMED,
__I40E_RX_PS_ENABLED, __I40E_RX_PS_ENABLED,
__I40E_RX_16BYTE_DESC_ENABLED, __I40E_RX_16BYTE_DESC_ENABLED,
}; };
...@@ -211,12 +209,6 @@ enum i40e_ring_state_t { ...@@ -211,12 +209,6 @@ enum i40e_ring_state_t {
set_bit(__I40E_RX_PS_ENABLED, &(ring)->state) set_bit(__I40E_RX_PS_ENABLED, &(ring)->state)
#define clear_ring_ps_enabled(ring) \ #define clear_ring_ps_enabled(ring) \
clear_bit(__I40E_RX_PS_ENABLED, &(ring)->state) clear_bit(__I40E_RX_PS_ENABLED, &(ring)->state)
#define check_for_tx_hang(ring) \
test_bit(__I40E_TX_DETECT_HANG, &(ring)->state)
#define set_check_for_tx_hang(ring) \
set_bit(__I40E_TX_DETECT_HANG, &(ring)->state)
#define clear_check_for_tx_hang(ring) \
clear_bit(__I40E_TX_DETECT_HANG, &(ring)->state)
#define ring_is_16byte_desc_enabled(ring) \ #define ring_is_16byte_desc_enabled(ring) \
test_bit(__I40E_RX_16BYTE_DESC_ENABLED, &(ring)->state) test_bit(__I40E_RX_16BYTE_DESC_ENABLED, &(ring)->state)
#define set_ring_16byte_desc_enabled(ring) \ #define set_ring_16byte_desc_enabled(ring) \
...@@ -326,6 +318,8 @@ int i40e_xmit_descriptor_count(struct sk_buff *skb, struct i40e_ring *tx_ring); ...@@ -326,6 +318,8 @@ int i40e_xmit_descriptor_count(struct sk_buff *skb, struct i40e_ring *tx_ring);
int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
struct i40e_ring *tx_ring, u32 *flags); struct i40e_ring *tx_ring, u32 *flags);
#endif #endif
void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);
u32 i40e_get_tx_pending(struct i40e_ring *ring);
/** /**
* i40e_get_head - Retrieve head from head writeback * i40e_get_head - Retrieve head from head writeback
......
...@@ -140,65 +140,6 @@ static inline u32 i40e_get_head(struct i40e_ring *tx_ring) ...@@ -140,65 +140,6 @@ static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
return le32_to_cpu(*(volatile __le32 *)head); return le32_to_cpu(*(volatile __le32 *)head);
} }
/**
* i40e_get_tx_pending - how many tx descriptors not processed
* @tx_ring: the ring of descriptors
*
* Since there is no access to the ring head register
* in XL710, we need to use our local copies
**/
static u32 i40e_get_tx_pending(struct i40e_ring *ring)
{
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;
}
/**
* i40e_check_tx_hang - Is there a hang in the Tx queue
* @tx_ring: the ring of descriptors
**/
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);
bool ret = false;
clear_check_for_tx_hang(tx_ring);
/* Check for a hung queue, but be thorough. This verifies
* that a transmit has been completed since the previous
* check AND there is at least one packet pending. The
* ARMED bit is set to indicate a potential hang. The
* bit is cleared if a pause frame is received to remove
* false hang detection due to PFC or 802.3x frames. By
* requiring this to fail twice we avoid races with
* PFC clearing the ARMED bit and conditions where we
* run the check_tx_hang logic with a transmit completion
* pending but without time to complete it yet.
*/
if ((tx_done_old == tx_done) && tx_pending) {
/* make sure it is true for two checks in a row */
ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
&tx_ring->state);
} else if (tx_done_old == tx_done &&
(tx_pending < I40E_MIN_DESC_PENDING) && (tx_pending > 0)) {
/* update completed stats and disarm the hang check */
tx_ring->tx_stats.tx_done_old = tx_done;
clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
}
return ret;
}
#define WB_STRIDE 0x3 #define WB_STRIDE 0x3
/** /**
...@@ -304,6 +245,10 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) ...@@ -304,6 +245,10 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
tx_ring->q_vector->tx.total_bytes += total_bytes; tx_ring->q_vector->tx.total_bytes += total_bytes;
tx_ring->q_vector->tx.total_packets += total_packets; tx_ring->q_vector->tx.total_packets += total_packets;
/* check to see if there are any non-cache aligned descriptors
* waiting to be written back, and kick the hardware to force
* them to be written back in case of napi polling
*/
if (budget && if (budget &&
!((i & WB_STRIDE) == WB_STRIDE) && !((i & WB_STRIDE) == WB_STRIDE) &&
!test_bit(__I40E_DOWN, &tx_ring->vsi->state) && !test_bit(__I40E_DOWN, &tx_ring->vsi->state) &&
...@@ -312,29 +257,6 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) ...@@ -312,29 +257,6 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
else else
tx_ring->arm_wb = false; tx_ring->arm_wb = false;
if (check_for_tx_hang(tx_ring) && i40e_check_tx_hang(tx_ring)) {
/* schedule immediate reset if we believe we hung */
dev_info(tx_ring->dev, "Detected Tx Unit Hang\n"
" VSI <%d>\n"
" Tx Queue <%d>\n"
" next_to_use <%x>\n"
" next_to_clean <%x>\n",
tx_ring->vsi->seid,
tx_ring->queue_index,
tx_ring->next_to_use, i);
netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
dev_info(tx_ring->dev,
"tx hang detected on queue %d, resetting adapter\n",
tx_ring->queue_index);
tx_ring->netdev->netdev_ops->ndo_tx_timeout(tx_ring->netdev);
/* the adapter is about to reset, no point in enabling stuff */
return true;
}
netdev_tx_completed_queue(netdev_get_tx_queue(tx_ring->netdev, netdev_tx_completed_queue(netdev_get_tx_queue(tx_ring->netdev,
tx_ring->queue_index), tx_ring->queue_index),
total_packets, total_bytes); total_packets, total_bytes);
...@@ -355,16 +277,16 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) ...@@ -355,16 +277,16 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
} }
} }
return budget > 0; return !!budget;
} }
/** /**
* i40e_force_wb -Arm hardware to do a wb on noncache aligned descriptors * i40evf_force_wb -Arm hardware to do a wb on noncache aligned descriptors
* @vsi: the VSI we care about * @vsi: the VSI we care about
* @q_vector: the vector on which to force writeback * @q_vector: the vector on which to force writeback
* *
**/ **/
static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) static void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
{ {
u16 flags = q_vector->tx.ring[0].flags; u16 flags = q_vector->tx.ring[0].flags;
...@@ -1385,7 +1307,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget) ...@@ -1385,7 +1307,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
/* If work not completed, return budget and polling will return */ /* If work not completed, return budget and polling will return */
if (!clean_complete) { if (!clean_complete) {
if (arm_wb) if (arm_wb)
i40e_force_wb(vsi, q_vector); i40evf_force_wb(vsi, q_vector);
return budget; return budget;
} }
......
...@@ -198,8 +198,6 @@ struct i40e_rx_queue_stats { ...@@ -198,8 +198,6 @@ struct i40e_rx_queue_stats {
enum i40e_ring_state_t { enum i40e_ring_state_t {
__I40E_TX_FDIR_INIT_DONE, __I40E_TX_FDIR_INIT_DONE,
__I40E_TX_XPS_INIT_DONE, __I40E_TX_XPS_INIT_DONE,
__I40E_TX_DETECT_HANG,
__I40E_HANG_CHECK_ARMED,
__I40E_RX_PS_ENABLED, __I40E_RX_PS_ENABLED,
__I40E_RX_16BYTE_DESC_ENABLED, __I40E_RX_16BYTE_DESC_ENABLED,
}; };
...@@ -210,12 +208,6 @@ enum i40e_ring_state_t { ...@@ -210,12 +208,6 @@ enum i40e_ring_state_t {
set_bit(__I40E_RX_PS_ENABLED, &(ring)->state) set_bit(__I40E_RX_PS_ENABLED, &(ring)->state)
#define clear_ring_ps_enabled(ring) \ #define clear_ring_ps_enabled(ring) \
clear_bit(__I40E_RX_PS_ENABLED, &(ring)->state) clear_bit(__I40E_RX_PS_ENABLED, &(ring)->state)
#define check_for_tx_hang(ring) \
test_bit(__I40E_TX_DETECT_HANG, &(ring)->state)
#define set_check_for_tx_hang(ring) \
set_bit(__I40E_TX_DETECT_HANG, &(ring)->state)
#define clear_check_for_tx_hang(ring) \
clear_bit(__I40E_TX_DETECT_HANG, &(ring)->state)
#define ring_is_16byte_desc_enabled(ring) \ #define ring_is_16byte_desc_enabled(ring) \
test_bit(__I40E_RX_16BYTE_DESC_ENABLED, &(ring)->state) test_bit(__I40E_RX_16BYTE_DESC_ENABLED, &(ring)->state)
#define set_ring_16byte_desc_enabled(ring) \ #define set_ring_16byte_desc_enabled(ring) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment