Commit 74ef402e authored by Huazhong Tan's avatar Huazhong Tan Committed by David S. Miller

net: hns3: fix for fraglist SKB headlen not handling correctly

When the fraglist SKB headlen is larger than zero, current code
still handle the fraglist SKB linear data as frag data, which may
cause TX error.

This patch adds a new DESC_TYPE_FRAGLIST_SKB type to handle the
mapping and unmapping of the fraglist SKB linear data buffer.

Fixes: 8ae10cfb ("net: hns3: support tx-scatter-gather-fraglist feature")
Signed-off-by: default avatarYunsheng Lin <linyunsheng@huawei.com>
Signed-off-by: default avatarHuazhong Tan <tanhuazhong@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 16deaef2
...@@ -78,6 +78,7 @@ ...@@ -78,6 +78,7 @@
enum hns_desc_type { enum hns_desc_type {
DESC_TYPE_SKB, DESC_TYPE_SKB,
DESC_TYPE_FRAGLIST_SKB,
DESC_TYPE_PAGE, DESC_TYPE_PAGE,
}; };
......
...@@ -1106,6 +1106,10 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, ...@@ -1106,6 +1106,10 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
if (unlikely(ret < 0)) if (unlikely(ret < 0))
return ret; return ret;
dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
} else if (type == DESC_TYPE_FRAGLIST_SKB) {
struct sk_buff *skb = (struct sk_buff *)priv;
dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE); dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
} else { } else {
frag = (skb_frag_t *)priv; frag = (skb_frag_t *)priv;
...@@ -1144,8 +1148,9 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, ...@@ -1144,8 +1148,9 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
/* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */ /* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */
desc_cb->priv = priv; desc_cb->priv = priv;
desc_cb->dma = dma + HNS3_MAX_BD_SIZE * k; desc_cb->dma = dma + HNS3_MAX_BD_SIZE * k;
desc_cb->type = (type == DESC_TYPE_SKB && !k) ? desc_cb->type = ((type == DESC_TYPE_FRAGLIST_SKB ||
DESC_TYPE_SKB : DESC_TYPE_PAGE; type == DESC_TYPE_SKB) && !k) ?
type : DESC_TYPE_PAGE;
/* now, fill the descriptor */ /* now, fill the descriptor */
desc->addr = cpu_to_le64(dma + HNS3_MAX_BD_SIZE * k); desc->addr = cpu_to_le64(dma + HNS3_MAX_BD_SIZE * k);
...@@ -1354,7 +1359,9 @@ static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig) ...@@ -1354,7 +1359,9 @@ static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig)
ring_ptr_move_bw(ring, next_to_use); ring_ptr_move_bw(ring, next_to_use);
/* unmap the descriptor dma address */ /* unmap the descriptor dma address */
if (ring->desc_cb[ring->next_to_use].type == DESC_TYPE_SKB) if (ring->desc_cb[ring->next_to_use].type == DESC_TYPE_SKB ||
ring->desc_cb[ring->next_to_use].type ==
DESC_TYPE_FRAGLIST_SKB)
dma_unmap_single(dev, dma_unmap_single(dev,
ring->desc_cb[ring->next_to_use].dma, ring->desc_cb[ring->next_to_use].dma,
ring->desc_cb[ring->next_to_use].length, ring->desc_cb[ring->next_to_use].length,
...@@ -1447,7 +1454,8 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -1447,7 +1454,8 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
goto out; goto out;
skb_walk_frags(skb, frag_skb) { skb_walk_frags(skb, frag_skb) {
ret = hns3_fill_skb_to_desc(ring, frag_skb, DESC_TYPE_PAGE); ret = hns3_fill_skb_to_desc(ring, frag_skb,
DESC_TYPE_FRAGLIST_SKB);
if (unlikely(ret < 0)) if (unlikely(ret < 0))
goto fill_err; goto fill_err;
...@@ -2356,7 +2364,7 @@ static int hns3_map_buffer(struct hns3_enet_ring *ring, struct hns3_desc_cb *cb) ...@@ -2356,7 +2364,7 @@ static int hns3_map_buffer(struct hns3_enet_ring *ring, struct hns3_desc_cb *cb)
static void hns3_unmap_buffer(struct hns3_enet_ring *ring, static void hns3_unmap_buffer(struct hns3_enet_ring *ring,
struct hns3_desc_cb *cb) struct hns3_desc_cb *cb)
{ {
if (cb->type == DESC_TYPE_SKB) if (cb->type == DESC_TYPE_SKB || cb->type == DESC_TYPE_FRAGLIST_SKB)
dma_unmap_single(ring_to_dev(ring), cb->dma, cb->length, dma_unmap_single(ring_to_dev(ring), cb->dma, cb->length,
ring_to_dma_dir(ring)); ring_to_dma_dir(ring));
else if (cb->length) else if (cb->length)
......
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