|
@@ -1549,14 +1549,16 @@ out:
|
|
|
|
|
|
/**
|
|
|
* i40e_tso - set up the tso context descriptor
|
|
|
- * @skb: ptr to the skb we're sending
|
|
|
+ * @first: pointer to first Tx buffer for xmit
|
|
|
* @hdr_len: ptr to the size of the packet header
|
|
|
* @cd_type_cmd_tso_mss: Quad Word 1
|
|
|
*
|
|
|
* Returns 0 if no TSO can happen, 1 if tso is going, or error
|
|
|
**/
|
|
|
-static int i40e_tso(struct sk_buff *skb, u8 *hdr_len, u64 *cd_type_cmd_tso_mss)
|
|
|
+static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len,
|
|
|
+ u64 *cd_type_cmd_tso_mss)
|
|
|
{
|
|
|
+ struct sk_buff *skb = first->skb;
|
|
|
u64 cd_cmd, cd_tso_len, cd_mss;
|
|
|
union {
|
|
|
struct iphdr *v4;
|
|
@@ -1569,6 +1571,7 @@ static int i40e_tso(struct sk_buff *skb, u8 *hdr_len, u64 *cd_type_cmd_tso_mss)
|
|
|
unsigned char *hdr;
|
|
|
} l4;
|
|
|
u32 paylen, l4_offset;
|
|
|
+ u16 gso_segs, gso_size;
|
|
|
int err;
|
|
|
|
|
|
if (skb->ip_summed != CHECKSUM_PARTIAL)
|
|
@@ -1633,10 +1636,18 @@ static int i40e_tso(struct sk_buff *skb, u8 *hdr_len, u64 *cd_type_cmd_tso_mss)
|
|
|
/* compute length of segmentation header */
|
|
|
*hdr_len = (l4.tcp->doff * 4) + l4_offset;
|
|
|
|
|
|
+ /* pull values out of skb_shinfo */
|
|
|
+ gso_size = skb_shinfo(skb)->gso_size;
|
|
|
+ gso_segs = skb_shinfo(skb)->gso_segs;
|
|
|
+
|
|
|
+ /* update GSO size and bytecount with header size */
|
|
|
+ first->gso_segs = gso_segs;
|
|
|
+ first->bytecount += (first->gso_segs - 1) * *hdr_len;
|
|
|
+
|
|
|
/* find the field values */
|
|
|
cd_cmd = I40E_TX_CTX_DESC_TSO;
|
|
|
cd_tso_len = skb->len - *hdr_len;
|
|
|
- cd_mss = skb_shinfo(skb)->gso_size;
|
|
|
+ cd_mss = gso_size;
|
|
|
*cd_type_cmd_tso_mss |= (cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
|
|
|
(cd_tso_len << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
|
|
|
(cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
|
|
@@ -1949,7 +1960,6 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
|
|
|
u16 i = tx_ring->next_to_use;
|
|
|
u32 td_tag = 0;
|
|
|
dma_addr_t dma;
|
|
|
- u16 gso_segs;
|
|
|
u16 desc_count = 1;
|
|
|
|
|
|
if (tx_flags & I40E_TX_FLAGS_HW_VLAN) {
|
|
@@ -1958,15 +1968,6 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
|
|
|
I40E_TX_FLAGS_VLAN_SHIFT;
|
|
|
}
|
|
|
|
|
|
- if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO))
|
|
|
- gso_segs = skb_shinfo(skb)->gso_segs;
|
|
|
- else
|
|
|
- gso_segs = 1;
|
|
|
-
|
|
|
- /* multiply data chunks by size of headers */
|
|
|
- first->bytecount = skb->len - hdr_len + (gso_segs * hdr_len);
|
|
|
- first->gso_segs = gso_segs;
|
|
|
- first->skb = skb;
|
|
|
first->tx_flags = tx_flags;
|
|
|
|
|
|
dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE);
|
|
@@ -2151,8 +2152,10 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
|
|
|
|
|
|
count = i40e_xmit_descriptor_count(skb);
|
|
|
if (i40e_chk_linearize(skb, count)) {
|
|
|
- if (__skb_linearize(skb))
|
|
|
- goto out_drop;
|
|
|
+ if (__skb_linearize(skb)) {
|
|
|
+ dev_kfree_skb_any(skb);
|
|
|
+ return NETDEV_TX_OK;
|
|
|
+ }
|
|
|
count = i40e_txd_use_count(skb->len);
|
|
|
tx_ring->tx_stats.tx_linearize++;
|
|
|
}
|
|
@@ -2168,6 +2171,12 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
|
|
|
return NETDEV_TX_BUSY;
|
|
|
}
|
|
|
|
|
|
+ /* record the location of the first descriptor for this packet */
|
|
|
+ first = &tx_ring->tx_bi[tx_ring->next_to_use];
|
|
|
+ first->skb = skb;
|
|
|
+ first->bytecount = skb->len;
|
|
|
+ first->gso_segs = 1;
|
|
|
+
|
|
|
/* prepare the xmit flags */
|
|
|
if (i40evf_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
|
|
|
goto out_drop;
|
|
@@ -2175,16 +2184,13 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
|
|
|
/* obtain protocol of skb */
|
|
|
protocol = vlan_get_protocol(skb);
|
|
|
|
|
|
- /* record the location of the first descriptor for this packet */
|
|
|
- first = &tx_ring->tx_bi[tx_ring->next_to_use];
|
|
|
-
|
|
|
/* setup IPv4/IPv6 offloads */
|
|
|
if (protocol == htons(ETH_P_IP))
|
|
|
tx_flags |= I40E_TX_FLAGS_IPV4;
|
|
|
else if (protocol == htons(ETH_P_IPV6))
|
|
|
tx_flags |= I40E_TX_FLAGS_IPV6;
|
|
|
|
|
|
- tso = i40e_tso(skb, &hdr_len, &cd_type_cmd_tso_mss);
|
|
|
+ tso = i40e_tso(first, &hdr_len, &cd_type_cmd_tso_mss);
|
|
|
|
|
|
if (tso < 0)
|
|
|
goto out_drop;
|
|
@@ -2211,7 +2217,8 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
|
|
|
return NETDEV_TX_OK;
|
|
|
|
|
|
out_drop:
|
|
|
- dev_kfree_skb_any(skb);
|
|
|
+ dev_kfree_skb_any(first->skb);
|
|
|
+ first->skb = NULL;
|
|
|
return NETDEV_TX_OK;
|
|
|
}
|
|
|
|