Commit 804abcdb authored by Sriharsha Basavapatna's avatar Sriharsha Basavapatna Committed by David S. Miller

be2net: Refactor wrb_fill_hdr() routine

The WRB header is setup by wrb_fill_hdr() routine. This routine currently
gets some of the WRB params as args and figures out rest of the WRB params
by looking at various fields in skb (like gso, checksum, vlan-tag etc).
All these params could instead be retrieved from the skb into a structure
and passed to this routine. This separates wrb_fill_hdr() to only provide
chip-specific code to fill the WRB. This also makes it simple to support
chips with different WRB formats.
Signed-off-by: default avatarSriharsha Basavapatna <sriharsha.basavapatna@emulex.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 69994d17
...@@ -417,6 +417,39 @@ struct rss_info { ...@@ -417,6 +417,39 @@ struct rss_info {
u8 rss_hkey[RSS_HASH_KEY_LEN]; u8 rss_hkey[RSS_HASH_KEY_LEN];
}; };
/* Macros to read/write the 'features' word of be_wrb_params structure.
*/
#define BE_WRB_F_BIT(name) BE_WRB_F_##name##_BIT
#define BE_WRB_F_MASK(name) BIT_MASK(BE_WRB_F_##name##_BIT)
#define BE_WRB_F_GET(word, name) \
(((word) & (BE_WRB_F_MASK(name))) >> BE_WRB_F_BIT(name))
#define BE_WRB_F_SET(word, name, val) \
((word) |= (((val) << BE_WRB_F_BIT(name)) & BE_WRB_F_MASK(name)))
/* Feature/offload bits */
enum {
BE_WRB_F_CRC_BIT, /* Ethernet CRC */
BE_WRB_F_IPCS_BIT, /* IP csum */
BE_WRB_F_TCPCS_BIT, /* TCP csum */
BE_WRB_F_UDPCS_BIT, /* UDP csum */
BE_WRB_F_LSO_BIT, /* LSO */
BE_WRB_F_LSO6_BIT, /* LSO6 */
BE_WRB_F_VLAN_BIT, /* VLAN */
BE_WRB_F_VLAN_SKIP_HW_BIT /* Skip VLAN tag (workaround) */
};
/* The structure below provides a HW-agnostic abstraction of WRB params
* retrieved from a TX skb. This is in turn passed to chip specific routines
* during transmit, to set the corresponding params in the WRB.
*/
struct be_wrb_params {
u32 features; /* Feature bits */
u16 vlan_tag; /* VLAN tag */
u16 lso_mss; /* MSS for LSO */
};
struct be_adapter { struct be_adapter {
struct pci_dev *pdev; struct pci_dev *pdev;
struct net_device *netdev; struct net_device *netdev;
......
...@@ -727,48 +727,71 @@ static u16 skb_ip_proto(struct sk_buff *skb) ...@@ -727,48 +727,71 @@ static u16 skb_ip_proto(struct sk_buff *skb)
ip_hdr(skb)->protocol : ipv6_hdr(skb)->nexthdr; ip_hdr(skb)->protocol : ipv6_hdr(skb)->nexthdr;
} }
static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, static void be_get_wrb_params_from_skb(struct be_adapter *adapter,
struct sk_buff *skb, u32 wrb_cnt, u32 len, struct sk_buff *skb,
bool skip_hw_vlan) struct be_wrb_params *wrb_params)
{ {
u16 vlan_tag, proto; u16 proto;
memset(hdr, 0, sizeof(*hdr));
SET_TX_WRB_HDR_BITS(crc, hdr, 1);
if (skb_is_gso(skb)) { if (skb_is_gso(skb)) {
SET_TX_WRB_HDR_BITS(lso, hdr, 1); BE_WRB_F_SET(wrb_params->features, LSO, 1);
SET_TX_WRB_HDR_BITS(lso_mss, hdr, skb_shinfo(skb)->gso_size); wrb_params->lso_mss = skb_shinfo(skb)->gso_size;
if (skb_is_gso_v6(skb) && !lancer_chip(adapter)) 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) { } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (skb->encapsulation) { 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); proto = skb_inner_ip_proto(skb);
} else { } else {
proto = skb_ip_proto(skb); proto = skb_ip_proto(skb);
} }
if (proto == IPPROTO_TCP) 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) 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)) { if (skb_vlan_tag_present(skb)) {
SET_TX_WRB_HDR_BITS(vlan, hdr, 1); BE_WRB_F_SET(wrb_params->features, VLAN, 1);
vlan_tag = be_get_tx_vlan_tag(adapter, skb); wrb_params->vlan_tag = be_get_tx_vlan_tag(adapter, skb);
SET_TX_WRB_HDR_BITS(vlan_tag, hdr, vlan_tag);
} }
SET_TX_WRB_HDR_BITS(num_wrb, hdr, wrb_cnt); BE_WRB_F_SET(wrb_params->features, CRC, 1);
SET_TX_WRB_HDR_BITS(len, hdr, len); }
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 SET_TX_WRB_HDR_BITS(crc, hdr,
* When this hack is not needed, the evt bit is set while ringing DB 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,
SET_TX_WRB_HDR_BITS(event, hdr, 1); 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, 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, ...@@ -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 */ /* Returns the number of WRBs used up by the skb */
static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, 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); u32 i, copied = 0, wrb_cnt = skb_wrb_cnt(skb);
struct device *dev = &adapter->pdev->dev; struct device *dev = &adapter->pdev->dev;
...@@ -802,7 +826,7 @@ static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo, ...@@ -802,7 +826,7 @@ static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo,
u16 head = txq->head; u16 head = txq->head;
hdr = queue_head_node(txq); 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)); be_dws_cpu_to_le(hdr, sizeof(*hdr));
queue_head_inc(txq); queue_head_inc(txq);
...@@ -869,7 +893,8 @@ static inline int qnq_async_evt_rcvd(struct be_adapter *adapter) ...@@ -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, static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
struct sk_buff *skb, struct sk_buff *skb,
bool *skip_hw_vlan) struct be_wrb_params
*wrb_params)
{ {
u16 vlan_tag = 0; u16 vlan_tag = 0;
...@@ -886,8 +911,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, ...@@ -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 /* f/w workaround to set skip_hw_vlan = 1, informs the F/W to
* skip VLAN insertion * skip VLAN insertion
*/ */
if (skip_hw_vlan) BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1);
*skip_hw_vlan = true;
} }
if (vlan_tag) { if (vlan_tag) {
...@@ -905,8 +929,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, ...@@ -905,8 +929,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
vlan_tag); vlan_tag);
if (unlikely(!skb)) if (unlikely(!skb))
return skb; return skb;
if (skip_hw_vlan) BE_WRB_F_SET(wrb_params->features, VLAN_SKIP_HW, 1);
*skip_hw_vlan = true;
} }
return skb; return skb;
...@@ -946,7 +969,8 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *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, static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
struct sk_buff *skb, struct sk_buff *skb,
bool *skip_hw_vlan) struct be_wrb_params
*wrb_params)
{ {
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
unsigned int eth_hdr_len; unsigned int eth_hdr_len;
...@@ -970,7 +994,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, ...@@ -970,7 +994,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
*/ */
if (be_pvid_tagging_enabled(adapter) && if (be_pvid_tagging_enabled(adapter) &&
veh->h_vlan_proto == htons(ETH_P_8021Q)) 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 /* HW has a bug wherein it will calculate CSUM for VLAN
* pkts even though it is disabled. * pkts even though it is disabled.
...@@ -978,7 +1002,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, ...@@ -978,7 +1002,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
*/ */
if (skb->ip_summed != CHECKSUM_PARTIAL && if (skb->ip_summed != CHECKSUM_PARTIAL &&
skb_vlan_tag_present(skb)) { 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)) if (unlikely(!skb))
goto err; goto err;
} }
...@@ -1000,7 +1024,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, ...@@ -1000,7 +1024,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
*/ */
if (be_ipv6_tx_stall_chk(adapter, skb) && if (be_ipv6_tx_stall_chk(adapter, skb) &&
be_vlan_tag_tx_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)) if (unlikely(!skb))
goto err; goto err;
} }
...@@ -1014,7 +1038,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, ...@@ -1014,7 +1038,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
struct sk_buff *skb, 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 /* 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 * 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, ...@@ -1026,7 +1050,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
} }
if (BEx_chip(adapter) || lancer_chip(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) if (!skb)
return NULL; return NULL;
} }
...@@ -1060,18 +1084,21 @@ static void be_xmit_flush(struct be_adapter *adapter, struct be_tx_obj *txo) ...@@ -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) 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); struct be_adapter *adapter = netdev_priv(netdev);
u16 q_idx = skb_get_queue_mapping(skb); u16 q_idx = skb_get_queue_mapping(skb);
struct be_tx_obj *txo = &adapter->tx_obj[q_idx]; struct be_tx_obj *txo = &adapter->tx_obj[q_idx];
struct be_wrb_params wrb_params = { 0 };
struct be_queue_info *txq = &txo->q; struct be_queue_info *txq = &txo->q;
bool flush = !skb->xmit_more;
u16 wrb_cnt; u16 wrb_cnt;
skb = be_xmit_workarounds(adapter, skb, &skip_hw_vlan); skb = be_xmit_workarounds(adapter, skb, &wrb_params);
if (unlikely(!skb)) if (unlikely(!skb))
goto drop; 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)) { if (unlikely(!wrb_cnt)) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
goto drop; goto drop;
......
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