Commit 74344e32 authored by Jacob Keller's avatar Jacob Keller Committed by Jeff Kirsher

igb: avoid permanent lock of *_PTP_TX_IN_PROGRESS

The igb driver uses a state bit lock to avoid handling more than one Tx
timestamp request at once. This is required because hardware is limited
to a single set of registers for Tx timestamps.

The state bit lock is not properly cleaned up during
igb_xmit_frame_ring() if the transmit fails such as due to DMA or TSO
failure. In some hardware this results in blocking timestamps until the
service task times out. In other hardware this results in a permanent
lock of the timestamp bit because we never receive an interrupt
indicating the timestamp occurred, since indeed the packet was never
transmitted.

Fix this by checking for DMA and TSO errors in igb_xmit_frame_ring() and
properly cleaning up after ourselves when these occur.
Reported-by: default avatarReported-by: David Mirabito <davidm@metamako.com>
Signed-off-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 4ccdc013
...@@ -5197,9 +5197,9 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size) ...@@ -5197,9 +5197,9 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
return __igb_maybe_stop_tx(tx_ring, size); return __igb_maybe_stop_tx(tx_ring, size);
} }
static void igb_tx_map(struct igb_ring *tx_ring, static int igb_tx_map(struct igb_ring *tx_ring,
struct igb_tx_buffer *first, struct igb_tx_buffer *first,
const u8 hdr_len) const u8 hdr_len)
{ {
struct sk_buff *skb = first->skb; struct sk_buff *skb = first->skb;
struct igb_tx_buffer *tx_buffer; struct igb_tx_buffer *tx_buffer;
...@@ -5310,7 +5310,7 @@ static void igb_tx_map(struct igb_ring *tx_ring, ...@@ -5310,7 +5310,7 @@ static void igb_tx_map(struct igb_ring *tx_ring,
*/ */
mmiowb(); mmiowb();
} }
return; return 0;
dma_error: dma_error:
dev_err(tx_ring->dev, "TX DMA map failed\n"); dev_err(tx_ring->dev, "TX DMA map failed\n");
...@@ -5341,6 +5341,8 @@ static void igb_tx_map(struct igb_ring *tx_ring, ...@@ -5341,6 +5341,8 @@ static void igb_tx_map(struct igb_ring *tx_ring,
tx_buffer->skb = NULL; tx_buffer->skb = NULL;
tx_ring->next_to_use = i; tx_ring->next_to_use = i;
return -1;
} }
netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
...@@ -5406,13 +5408,24 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, ...@@ -5406,13 +5408,24 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
else if (!tso) else if (!tso)
igb_tx_csum(tx_ring, first); igb_tx_csum(tx_ring, first);
igb_tx_map(tx_ring, first, hdr_len); if (igb_tx_map(tx_ring, first, hdr_len))
goto cleanup_tx_tstamp;
return NETDEV_TX_OK; return NETDEV_TX_OK;
out_drop: out_drop:
dev_kfree_skb_any(first->skb); dev_kfree_skb_any(first->skb);
first->skb = NULL; first->skb = NULL;
cleanup_tx_tstamp:
if (unlikely(tx_flags & IGB_TX_FLAGS_TSTAMP)) {
struct igb_adapter *adapter = netdev_priv(tx_ring->netdev);
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
if (adapter->hw.mac.type == e1000_82576)
cancel_work_sync(&adapter->ptp_tx_work);
clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
}
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
......
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