mirror of https://gitee.com/openkylin/linux.git
be2net: workaround to fix a bug in BE
disable Tx vlan offloading in certain cases. Signed-off-by: Ajit Khaparde <ajit.khaparde@emulex.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
02fe702796
commit
1ded132d4c
|
@ -552,11 +552,26 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
|
||||||
wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
|
wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
u8 vlan_prio;
|
||||||
|
u16 vlan_tag;
|
||||||
|
|
||||||
|
vlan_tag = vlan_tx_tag_get(skb);
|
||||||
|
vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
|
||||||
|
/* If vlan priority provided by OS is NOT in available bmap */
|
||||||
|
if (!(adapter->vlan_prio_bmap & (1 << vlan_prio)))
|
||||||
|
vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) |
|
||||||
|
adapter->recommended_prio;
|
||||||
|
|
||||||
|
return vlan_tag;
|
||||||
|
}
|
||||||
|
|
||||||
static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
|
static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
|
||||||
struct sk_buff *skb, u32 wrb_cnt, u32 len)
|
struct sk_buff *skb, u32 wrb_cnt, u32 len)
|
||||||
{
|
{
|
||||||
u8 vlan_prio = 0;
|
u16 vlan_tag;
|
||||||
u16 vlan_tag = 0;
|
|
||||||
|
|
||||||
memset(hdr, 0, sizeof(*hdr));
|
memset(hdr, 0, sizeof(*hdr));
|
||||||
|
|
||||||
|
@ -587,12 +602,7 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
|
||||||
|
|
||||||
if (vlan_tx_tag_present(skb)) {
|
if (vlan_tx_tag_present(skb)) {
|
||||||
AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1);
|
AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1);
|
||||||
vlan_tag = vlan_tx_tag_get(skb);
|
vlan_tag = be_get_tx_vlan_tag(adapter, skb);
|
||||||
vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
|
|
||||||
/* If vlan priority provided by OS is NOT in available bmap */
|
|
||||||
if (!(adapter->vlan_prio_bmap & (1 << vlan_prio)))
|
|
||||||
vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) |
|
|
||||||
adapter->recommended_prio;
|
|
||||||
AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag);
|
AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,6 +705,25 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
|
||||||
u32 start = txq->head;
|
u32 start = txq->head;
|
||||||
bool dummy_wrb, stopped = false;
|
bool dummy_wrb, stopped = false;
|
||||||
|
|
||||||
|
/* For vlan tagged pkts, BE
|
||||||
|
* 1) calculates checksum even when CSO is not requested
|
||||||
|
* 2) calculates checksum wrongly for padded pkt less than
|
||||||
|
* 60 bytes long.
|
||||||
|
* As a workaround disable TX vlan offloading in such cases.
|
||||||
|
*/
|
||||||
|
if (unlikely(vlan_tx_tag_present(skb) &&
|
||||||
|
(skb->ip_summed != CHECKSUM_PARTIAL || skb->len <= 60))) {
|
||||||
|
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||||
|
if (unlikely(!skb))
|
||||||
|
goto tx_drop;
|
||||||
|
|
||||||
|
skb = __vlan_put_tag(skb, be_get_tx_vlan_tag(adapter, skb));
|
||||||
|
if (unlikely(!skb))
|
||||||
|
goto tx_drop;
|
||||||
|
|
||||||
|
skb->vlan_tci = 0;
|
||||||
|
}
|
||||||
|
|
||||||
wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);
|
wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);
|
||||||
|
|
||||||
copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb);
|
copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb);
|
||||||
|
@ -722,6 +751,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
|
||||||
txq->head = start;
|
txq->head = start;
|
||||||
dev_kfree_skb_any(skb);
|
dev_kfree_skb_any(skb);
|
||||||
}
|
}
|
||||||
|
tx_drop:
|
||||||
return NETDEV_TX_OK;
|
return NETDEV_TX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue