/* clear next_to_watch to prevent false hangs */
tx_buffer->next_to_watch = NULL;
+ /* free the skb */
+ dev_kfree_skb_any(tx_buffer->skb);
+
+ /* clear tx_buffer data */
+ tx_buffer->skb = NULL;
+
do {
ixgbe_unmap_tx_resource(tx_ring, tx_buffer);
if (likely(tx_desc == eop_desc)) {
eop_desc = NULL;
- dev_kfree_skb_any(tx_buffer->skb);
- tx_buffer->skb = NULL;
total_bytes += tx_buffer->bytecount;
total_packets += tx_buffer->gso_segs;
context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
}
-static int ixgbe_tso(struct ixgbe_ring *tx_ring, struct sk_buff *skb,
+static int ixgbe_tso(struct ixgbe_ring *tx_ring,
+ struct ixgbe_tx_buffer *first,
u32 tx_flags, __be16 protocol, u8 *hdr_len)
{
+ struct sk_buff *skb = first->skb;
int err;
u32 vlan_macip_lens, type_tucmd;
u32 mss_l4len_idx, l4len;
}
static bool ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
- struct sk_buff *skb, u32 tx_flags,
- __be16 protocol)
+ struct ixgbe_tx_buffer *first,
+ u32 tx_flags, __be16 protocol)
{
+ struct sk_buff *skb = first->skb;
u32 vlan_macip_lens = 0;
u32 mss_l4len_idx = 0;
u32 type_tucmd = 0;
IXGBE_TXD_CMD_RS)
static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
- struct sk_buff *skb,
struct ixgbe_tx_buffer *first,
u32 tx_flags,
const u8 hdr_len)
{
+ struct sk_buff *skb = first->skb;
struct device *dev = tx_ring->dev;
struct ixgbe_tx_buffer *tx_buffer_info;
union ixgbe_adv_tx_desc *tx_desc;
/* multiply data chunks by size of headers */
tx_buffer_info->bytecount = paylen + (gso_segs * hdr_len);
tx_buffer_info->gso_segs = gso_segs;
- tx_buffer_info->skb = skb;
netdev_tx_sent_queue(txring_txq(tx_ring), tx_buffer_info->bytecount);
/* clear dma mappings for failed tx_buffer_info map */
for (;;) {
tx_buffer_info = &tx_ring->tx_buffer_info[i];
- ixgbe_unmap_tx_resource(tx_ring, tx_buffer_info);
+ ixgbe_unmap_and_free_tx_resource(tx_ring, tx_buffer_info);
if (tx_buffer_info == first)
break;
if (i == 0)
i--;
}
- dev_kfree_skb_any(skb);
-
tx_ring->next_to_use = i;
}
-static void ixgbe_atr(struct ixgbe_ring *ring, struct sk_buff *skb,
+static void ixgbe_atr(struct ixgbe_ring *ring,
+ struct ixgbe_tx_buffer *first,
u32 tx_flags, __be16 protocol)
{
struct ixgbe_q_vector *q_vector = ring->q_vector;
ring->atr_count++;
/* snag network header to get L4 type and address */
- hdr.network = skb_network_header(skb);
+ hdr.network = skb_network_header(first->skb);
/* Currently only IPv4/IPv6 with TCP is supported */
if ((protocol != __constant_htons(ETH_P_IPV6) ||
hdr.ipv4->protocol != IPPROTO_TCP))
return;
- th = tcp_hdr(skb);
+ th = tcp_hdr(first->skb);
/* skip this packet since it is invalid or the socket is closing */
if (!th || th->fin)
return NETDEV_TX_BUSY;
}
+ /* record the location of the first descriptor for this packet */
+ first = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
+ first->skb = skb;
+
/* if we have a HW VLAN tag being added default to the HW one */
if (vlan_tx_tag_present(skb)) {
tx_flags |= vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT;
}
}
- /* record the location of the first descriptor for this packet */
- first = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
-
#ifdef IXGBE_FCOE
/* setup tx offload for FCoE */
if ((protocol == __constant_htons(ETH_P_FCOE)) &&
(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) {
- tso = ixgbe_fso(tx_ring, skb, tx_flags, &hdr_len);
+ tso = ixgbe_fso(tx_ring, first, tx_flags, &hdr_len);
if (tso < 0)
goto out_drop;
else if (tso)
if (protocol == __constant_htons(ETH_P_IP))
tx_flags |= IXGBE_TX_FLAGS_IPV4;
- tso = ixgbe_tso(tx_ring, skb, tx_flags, protocol, &hdr_len);
+ tso = ixgbe_tso(tx_ring, first, tx_flags, protocol, &hdr_len);
if (tso < 0)
goto out_drop;
else if (tso)
tx_flags |= IXGBE_TX_FLAGS_TSO | IXGBE_TX_FLAGS_CSUM;
- else if (ixgbe_tx_csum(tx_ring, skb, tx_flags, protocol))
+ else if (ixgbe_tx_csum(tx_ring, first, tx_flags, protocol))
tx_flags |= IXGBE_TX_FLAGS_CSUM;
/* add the ATR filter if ATR is on */
if (test_bit(__IXGBE_TX_FDIR_INIT_DONE, &tx_ring->state))
- ixgbe_atr(tx_ring, skb, tx_flags, protocol);
+ ixgbe_atr(tx_ring, first, tx_flags, protocol);
#ifdef IXGBE_FCOE
xmit_fcoe:
#endif /* IXGBE_FCOE */
- ixgbe_tx_map(tx_ring, skb, first, tx_flags, hdr_len);
+ ixgbe_tx_map(tx_ring, first, tx_flags, hdr_len);
ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
return NETDEV_TX_OK;
out_drop:
- dev_kfree_skb_any(skb);
+ dev_kfree_skb_any(first->skb);
+ first->skb = NULL;
+
return NETDEV_TX_OK;
}