|
@@ -727,48 +727,71 @@ static u16 skb_ip_proto(struct sk_buff *skb)
|
|
|
ip_hdr(skb)->protocol : ipv6_hdr(skb)->nexthdr;
|
|
|
}
|
|
|
|
|
|
-static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
|
|
|
- struct sk_buff *skb, u32 wrb_cnt, u32 len,
|
|
|
- bool skip_hw_vlan)
|
|
|
+static void be_get_wrb_params_from_skb(struct be_adapter *adapter,
|
|
|
+ struct sk_buff *skb,
|
|
|
+ struct be_wrb_params *wrb_params)
|
|
|
{
|
|
|
- u16 vlan_tag, proto;
|
|
|
-
|
|
|
- memset(hdr, 0, sizeof(*hdr));
|
|
|
-
|
|
|
- SET_TX_WRB_HDR_BITS(crc, hdr, 1);
|
|
|
+ u16 proto;
|
|
|
|
|
|
if (skb_is_gso(skb)) {
|
|
|
- SET_TX_WRB_HDR_BITS(lso, hdr, 1);
|
|
|
- SET_TX_WRB_HDR_BITS(lso_mss, hdr, skb_shinfo(skb)->gso_size);
|
|
|
+ BE_WRB_F_SET(wrb_params->features, LSO, 1);
|
|
|
+ wrb_params->lso_mss = skb_shinfo(skb)->gso_size;
|
|
|
if (skb_is_gso_v6(skb) && !lancer_chip(adapter))
|
|
|
- SET_TX_WRB_HDR_BITS(lso6, hdr, 1);
|
|
|
+ BE_WRB_F_SET(wrb_params->features, LSO6, 1);
|
|
|
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
|
|
if (skb->encapsulation) {
|
|
|
- SET_TX_WRB_HDR_BITS(ipcs, hdr, 1);
|
|
|
+ BE_WRB_F_SET(wrb_params->features, IPCS, 1);
|
|
|
proto = skb_inner_ip_proto(skb);
|
|
|
} else {
|
|
|
proto = skb_ip_proto(skb);
|
|
|
}
|
|
|
if (proto == IPPROTO_TCP)
|
|
|
- SET_TX_WRB_HDR_BITS(tcpcs, hdr, 1);
|
|
|
+ BE_WRB_F_SET(wrb_params->features, TCPCS, 1);
|
|
|
else if (proto == IPPROTO_UDP)
|
|
|
- SET_TX_WRB_HDR_BITS(udpcs, hdr, 1);
|
|
|
+ BE_WRB_F_SET(wrb_params->features, UDPCS, 1);
|
|
|
}
|
|
|
|
|
|
if (skb_vlan_tag_present(skb)) {
|
|
|
- SET_TX_WRB_HDR_BITS(vlan, hdr, 1);
|
|
|
- vlan_tag = be_get_tx_vlan_tag(adapter, skb);
|
|
|
- SET_TX_WRB_HDR_BITS(vlan_tag, hdr, vlan_tag);
|
|
|
+ BE_WRB_F_SET(wrb_params->features, VLAN, 1);
|
|
|
+ wrb_params->vlan_tag = be_get_tx_vlan_tag(adapter, skb);
|
|
|
}
|
|
|
|
|
|
- SET_TX_WRB_HDR_BITS(num_wrb, hdr, wrb_cnt);
|
|
|
- SET_TX_WRB_HDR_BITS(len, hdr, len);
|
|
|
+ BE_WRB_F_SET(wrb_params->features, CRC, 1);
|
|
|
+}
|
|
|
+
|
|
|
+static void wrb_fill_hdr(struct be_adapter *adapter,
|
|
|
+ struct be_eth_hdr_wrb *hdr,
|
|
|
+ struct be_wrb_params *wrb_params,
|
|
|
+ struct sk_buff *skb)
|
|
|
+{
|
|
|
+ memset(hdr, 0, sizeof(*hdr));
|
|
|
|
|
|
- /* Hack to skip HW VLAN tagging needs evt = 1, compl = 0
|
|
|
- * When this hack is not needed, the evt bit is set while ringing DB
|
|
|
+ SET_TX_WRB_HDR_BITS(crc, hdr,
|
|
|
+ BE_WRB_F_GET(wrb_params->features, CRC));
|
|
|
+ SET_TX_WRB_HDR_BITS(ipcs, hdr,
|
|
|
+ BE_WRB_F_GET(wrb_params->features, IPCS));
|
|
|
+ SET_TX_WRB_HDR_BITS(tcpcs, hdr,
|
|
|
+ BE_WRB_F_GET(wrb_params->features, TCPCS));
|
|
|
+ SET_TX_WRB_HDR_BITS(udpcs, hdr,
|
|
|
+ BE_WRB_F_GET(wrb_params->features, UDPCS));
|
|
|
+
|
|
|
+ SET_TX_WRB_HDR_BITS(lso, hdr,
|
|
|
+ BE_WRB_F_GET(wrb_params->features, LSO));
|
|
|
+ SET_TX_WRB_HDR_BITS(lso6, hdr,
|
|
|
+ BE_WRB_F_GET(wrb_params->features, LSO6));
|
|
|
+ SET_TX_WRB_HDR_BITS(lso_mss, hdr, wrb_params->lso_mss);
|
|
|
+
|
|
|
+ /* Hack to skip HW VLAN tagging needs evt = 1, compl = 0. When this
|
|
|
+ * hack is not needed, the evt bit is set while ringing DB.
|
|
|
*/
|
|
|
- if (skip_hw_vlan)
|
|
|
- SET_TX_WRB_HDR_BITS(event, hdr, 1);
|
|
|
+ SET_TX_WRB_HDR_BITS(event, hdr,
|
|
|
+ BE_WRB_F_GET(wrb_params->features, VLAN_SKIP_HW));
|
|
|
+ SET_TX_WRB_HDR_BITS(vlan, hdr,
|
|
|
+ BE_WRB_F_GET(wrb_params->features, VLAN));
|
|
|
+ SET_TX_WRB_HDR_BITS(vlan_tag, hdr, wrb_params->vlan_tag);
|
|
|
+
|
|
|
+ SET_TX_WRB_HDR_BITS(num_wrb, hdr, skb_wrb_cnt(skb));
|
|
|
+ SET_TX_WRB_HDR_BITS(len, hdr, skb->len);
|
|
|
}
|
|
|
|
|
|
static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb,
|
|
@@ -790,7 +813,8 @@ static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb,
|
|
|
|
|
|
/* Returns the number of WRBs used up by the skb */
|
|
|
static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo,
|
|
|
- struct sk_buff *skb, bool skip_hw_vlan)
|
|
|
+ struct sk_buff *skb,
|
|
|
+ struct be_wrb_params *wrb_params)
|
|
|
{
|
|
|
u32 i, copied = 0, wrb_cnt = skb_wrb_cnt(skb);
|
|
|
struct device *dev = &adapter->pdev->dev;
|
|
@@ -802,7 +826,7 @@ static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo,
|
|
|
u16 head = txq->head;
|
|
|
|
|
|
hdr = queue_head_node(txq);
|
|
|
- wrb_fill_hdr(adapter, hdr, skb, wrb_cnt, skb->len, skip_hw_vlan);
|
|
|
+ wrb_fill_hdr(adapter, hdr, wrb_params, skb);
|
|
|
be_dws_cpu_to_le(hdr, sizeof(*hdr));
|
|
|
|
|
|
queue_head_inc(txq);
|
|
@@ -869,7 +893,8 @@ static inline int qnq_async_evt_rcvd(struct be_adapter *adapter)
|
|
|
|
|
|
static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
|
|
|
struct sk_buff *skb,
|
|
|
- bool *skip_hw_vlan)
|
|
|
+ struct be_wrb_params
|
|
|
+ *wrb_params)
|
|
|
{
|
|
|
u16 vlan_tag = 0;
|
|
|
|
|
@@ -886,8 +911,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
|
|
|
/* f/w workaround to set skip_hw_vlan = 1, informs the F/W to
|
|
|
* skip VLAN insertion
|
|
|
*/
|
|
|
- if (skip_hw_vlan)
|
|
|
- *skip_hw_vlan = true;
|
|
|
+ BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1);
|
|
|
}
|
|
|
|
|
|
if (vlan_tag) {
|
|
@@ -905,8 +929,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
|
|
|
vlan_tag);
|
|
|
if (unlikely(!skb))
|
|
|
return skb;
|
|
|
- if (skip_hw_vlan)
|
|
|
- *skip_hw_vlan = true;
|
|
|
+ BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1);
|
|
|
}
|
|
|
|
|
|
return skb;
|
|
@@ -946,7 +969,8 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *skb)
|
|
|
|
|
|
static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
|
|
|
struct sk_buff *skb,
|
|
|
- bool *skip_hw_vlan)
|
|
|
+ struct be_wrb_params
|
|
|
+ *wrb_params)
|
|
|
{
|
|
|
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
|
|
|
unsigned int eth_hdr_len;
|
|
@@ -970,7 +994,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
|
|
|
*/
|
|
|
if (be_pvid_tagging_enabled(adapter) &&
|
|
|
veh->h_vlan_proto == htons(ETH_P_8021Q))
|
|
|
- *skip_hw_vlan = true;
|
|
|
+ BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1);
|
|
|
|
|
|
/* HW has a bug wherein it will calculate CSUM for VLAN
|
|
|
* pkts even though it is disabled.
|
|
@@ -978,7 +1002,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
|
|
|
*/
|
|
|
if (skb->ip_summed != CHECKSUM_PARTIAL &&
|
|
|
skb_vlan_tag_present(skb)) {
|
|
|
- skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
|
|
|
+ skb = be_insert_vlan_in_pkt(adapter, skb, wrb_params);
|
|
|
if (unlikely(!skb))
|
|
|
goto err;
|
|
|
}
|
|
@@ -1000,7 +1024,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
|
|
|
*/
|
|
|
if (be_ipv6_tx_stall_chk(adapter, skb) &&
|
|
|
be_vlan_tag_tx_chk(adapter, skb)) {
|
|
|
- skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
|
|
|
+ skb = be_insert_vlan_in_pkt(adapter, skb, wrb_params);
|
|
|
if (unlikely(!skb))
|
|
|
goto err;
|
|
|
}
|
|
@@ -1014,7 +1038,7 @@ err:
|
|
|
|
|
|
static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
|
|
|
struct sk_buff *skb,
|
|
|
- bool *skip_hw_vlan)
|
|
|
+ struct be_wrb_params *wrb_params)
|
|
|
{
|
|
|
/* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or
|
|
|
* less may cause a transmit stall on that port. So the work-around is
|
|
@@ -1026,7 +1050,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
|
|
|
}
|
|
|
|
|
|
if (BEx_chip(adapter) || lancer_chip(adapter)) {
|
|
|
- skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan);
|
|
|
+ skb = be_lancer_xmit_workarounds(adapter, skb, wrb_params);
|
|
|
if (!skb)
|
|
|
return NULL;
|
|
|
}
|
|
@@ -1060,18 +1084,21 @@ static void be_xmit_flush(struct be_adapter *adapter, struct be_tx_obj *txo)
|
|
|
|
|
|
static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|
|
{
|
|
|
- bool skip_hw_vlan = false, flush = !skb->xmit_more;
|
|
|
struct be_adapter *adapter = netdev_priv(netdev);
|
|
|
u16 q_idx = skb_get_queue_mapping(skb);
|
|
|
struct be_tx_obj *txo = &adapter->tx_obj[q_idx];
|
|
|
+ struct be_wrb_params wrb_params = { 0 };
|
|
|
struct be_queue_info *txq = &txo->q;
|
|
|
+ bool flush = !skb->xmit_more;
|
|
|
u16 wrb_cnt;
|
|
|
|
|
|
- skb = be_xmit_workarounds(adapter, skb, &skip_hw_vlan);
|
|
|
+ skb = be_xmit_workarounds(adapter, skb, &wrb_params);
|
|
|
if (unlikely(!skb))
|
|
|
goto drop;
|
|
|
|
|
|
- wrb_cnt = be_xmit_enqueue(adapter, txo, skb, skip_hw_vlan);
|
|
|
+ be_get_wrb_params_from_skb(adapter, skb, &wrb_params);
|
|
|
+
|
|
|
+ wrb_cnt = be_xmit_enqueue(adapter, txo, skb, &wrb_params);
|
|
|
if (unlikely(!wrb_cnt)) {
|
|
|
dev_kfree_skb_any(skb);
|
|
|
goto drop;
|