Commit 66f32a8b authored by Alexander Duyck's avatar Alexander Duyck Committed by Jeff Kirsher

ixgbe: Cleanup FCOE and VLAN handling in xmit_frame_ring

This change is meant to further cleanup the transmit path by streamlining
some of the VLAN and FCOE/DCB tasks in the transmit path.  In addition it
adds code for support software VLANs in the event that they are used in
conjunction with DCB and/or FCOE.
Signed-off-by: default avatarAlexander Duyck <alexander.h.duyck@intel.com>
Tested-by: default avatarRoss Brattain <ross.b.brattain@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 971060b1
...@@ -91,14 +91,16 @@ ...@@ -91,14 +91,16 @@
#define IXGBE_RX_BUFFER_WRITE 16 /* Must be power of 2 */ #define IXGBE_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define IXGBE_TX_FLAGS_CSUM (u32)(1) #define IXGBE_TX_FLAGS_CSUM (u32)(1)
#define IXGBE_TX_FLAGS_VLAN (u32)(1 << 1) #define IXGBE_TX_FLAGS_HW_VLAN (u32)(1 << 1)
#define IXGBE_TX_FLAGS_TSO (u32)(1 << 2) #define IXGBE_TX_FLAGS_SW_VLAN (u32)(1 << 2)
#define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3) #define IXGBE_TX_FLAGS_TSO (u32)(1 << 3)
#define IXGBE_TX_FLAGS_FCOE (u32)(1 << 4) #define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 4)
#define IXGBE_TX_FLAGS_FSO (u32)(1 << 5) #define IXGBE_TX_FLAGS_FCOE (u32)(1 << 5)
#define IXGBE_TX_FLAGS_MAPPED_AS_PAGE (u32)(1 << 6) #define IXGBE_TX_FLAGS_FSO (u32)(1 << 6)
#define IXGBE_TX_FLAGS_MAPPED_AS_PAGE (u32)(1 << 7)
#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000
#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000 #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000
#define IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT 29
#define IXGBE_TX_FLAGS_VLAN_SHIFT 16 #define IXGBE_TX_FLAGS_VLAN_SHIFT 16
#define IXGBE_MAX_RSC_INT_RATE 162760 #define IXGBE_MAX_RSC_INT_RATE 162760
......
...@@ -6369,7 +6369,7 @@ static bool ixgbe_tx_csum(struct ixgbe_ring *tx_ring, ...@@ -6369,7 +6369,7 @@ static bool ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
u32 type_tucmd = 0; u32 type_tucmd = 0;
if (skb->ip_summed != CHECKSUM_PARTIAL) { if (skb->ip_summed != CHECKSUM_PARTIAL) {
if (!(tx_flags & IXGBE_TX_FLAGS_VLAN)) if (!(tx_flags & IXGBE_TX_FLAGS_HW_VLAN))
return false; return false;
} else { } else {
u8 l4_hdr = 0; u8 l4_hdr = 0;
...@@ -6434,7 +6434,7 @@ static __le32 ixgbe_tx_cmd_type(u32 tx_flags) ...@@ -6434,7 +6434,7 @@ static __le32 ixgbe_tx_cmd_type(u32 tx_flags)
IXGBE_ADVTXD_DCMD_DEXT); IXGBE_ADVTXD_DCMD_DEXT);
/* set HW vlan bit if vlan is present */ /* set HW vlan bit if vlan is present */
if (tx_flags & IXGBE_TX_FLAGS_VLAN) if (tx_flags & IXGBE_TX_FLAGS_HW_VLAN)
cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_VLE); cmd_type |= cpu_to_le32(IXGBE_ADVTXD_DCMD_VLE);
/* set segmentation enable bits for TSO/FSO */ /* set segmentation enable bits for TSO/FSO */
...@@ -6670,8 +6670,8 @@ static void ixgbe_atr(struct ixgbe_ring *ring, struct sk_buff *skb, ...@@ -6670,8 +6670,8 @@ static void ixgbe_atr(struct ixgbe_ring *ring, struct sk_buff *skb,
th = tcp_hdr(skb); th = tcp_hdr(skb);
/* skip this packet since the socket is closing */ /* skip this packet since it is invalid or the socket is closing */
if (th->fin) if (!th || th->fin)
return; return;
/* sample on all syn packets or once every atr sample count */ /* sample on all syn packets or once every atr sample count */
...@@ -6696,7 +6696,7 @@ static void ixgbe_atr(struct ixgbe_ring *ring, struct sk_buff *skb, ...@@ -6696,7 +6696,7 @@ static void ixgbe_atr(struct ixgbe_ring *ring, struct sk_buff *skb,
* since src port and flex bytes occupy the same word XOR them together * since src port and flex bytes occupy the same word XOR them together
* and write the value to source port portion of compressed dword * and write the value to source port portion of compressed dword
*/ */
if (vlan_id) if (tx_flags & (IXGBE_TX_FLAGS_SW_VLAN | IXGBE_TX_FLAGS_HW_VLAN))
common.port.src ^= th->dest ^ __constant_htons(ETH_P_8021Q); common.port.src ^= th->dest ^ __constant_htons(ETH_P_8021Q);
else else
common.port.src ^= th->dest ^ protocol; common.port.src ^= th->dest ^ protocol;
...@@ -6785,7 +6785,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, ...@@ -6785,7 +6785,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
unsigned short f; unsigned short f;
#endif #endif
u16 count = TXD_USE_COUNT(skb_headlen(skb)); u16 count = TXD_USE_COUNT(skb_headlen(skb));
__be16 protocol; __be16 protocol = skb->protocol;
u8 hdr_len = 0; u8 hdr_len = 0;
/* /*
...@@ -6806,46 +6806,64 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, ...@@ -6806,46 +6806,64 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
protocol = vlan_get_protocol(skb); /* if we have a HW VLAN tag being added default to the HW one */
if (vlan_tx_tag_present(skb)) { if (vlan_tx_tag_present(skb)) {
tx_flags |= vlan_tx_tag_get(skb); tx_flags |= vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT;
if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { tx_flags |= IXGBE_TX_FLAGS_HW_VLAN;
tx_flags &= ~IXGBE_TX_FLAGS_VLAN_PRIO_MASK; /* else if it is a SW VLAN check the next protocol and store the tag */
tx_flags |= tx_ring->dcb_tc << 13; } else if (protocol == __constant_htons(ETH_P_8021Q)) {
struct vlan_hdr *vhdr, _vhdr;
vhdr = skb_header_pointer(skb, ETH_HLEN, sizeof(_vhdr), &_vhdr);
if (!vhdr)
goto out_drop;
protocol = vhdr->h_vlan_encapsulated_proto;
tx_flags |= ntohs(vhdr->h_vlan_TCI) << IXGBE_TX_FLAGS_VLAN_SHIFT;
tx_flags |= IXGBE_TX_FLAGS_SW_VLAN;
} }
tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
tx_flags |= IXGBE_TX_FLAGS_VLAN; if ((adapter->flags & IXGBE_FLAG_DCB_ENABLED) &&
} else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED &&
skb->priority != TC_PRIO_CONTROL) { skb->priority != TC_PRIO_CONTROL) {
tx_flags |= tx_ring->dcb_tc << 13; tx_flags &= ~IXGBE_TX_FLAGS_VLAN_PRIO_MASK;
tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= tx_ring->dcb_tc <<
tx_flags |= IXGBE_TX_FLAGS_VLAN; IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT;
if (tx_flags & IXGBE_TX_FLAGS_SW_VLAN) {
struct vlan_ethhdr *vhdr;
if (skb_header_cloned(skb) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
goto out_drop;
vhdr = (struct vlan_ethhdr *)skb->data;
vhdr->h_vlan_TCI = htons(tx_flags >>
IXGBE_TX_FLAGS_VLAN_SHIFT);
} else {
tx_flags |= IXGBE_TX_FLAGS_HW_VLAN;
}
} }
#ifdef IXGBE_FCOE
/* for FCoE with DCB, we force the priority to what
* was specified by the switch */
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED &&
(protocol == htons(ETH_P_FCOE)))
tx_flags |= IXGBE_TX_FLAGS_FCOE;
#endif
/* record the location of the first descriptor for this packet */ /* record the location of the first descriptor for this packet */
first = &tx_ring->tx_buffer_info[tx_ring->next_to_use]; first = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
if (tx_flags & IXGBE_TX_FLAGS_FCOE) {
#ifdef IXGBE_FCOE #ifdef IXGBE_FCOE
/* setup tx offload for FCoE */ /* setup tx offload for FCoE */
if ((protocol == __constant_htons(ETH_P_FCOE)) &&
(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) {
tso = ixgbe_fso(tx_ring, skb, tx_flags, &hdr_len); tso = ixgbe_fso(tx_ring, skb, tx_flags, &hdr_len);
if (tso < 0) if (tso < 0)
goto out_drop; goto out_drop;
else if (tso) else if (tso)
tx_flags |= IXGBE_TX_FLAGS_FSO; tx_flags |= IXGBE_TX_FLAGS_FSO |
IXGBE_TX_FLAGS_FCOE;
else
tx_flags |= IXGBE_TX_FLAGS_FCOE;
goto xmit_fcoe;
}
#endif /* IXGBE_FCOE */ #endif /* IXGBE_FCOE */
} else { /* setup IPv4/IPv6 offloads */
if (protocol == htons(ETH_P_IP)) if (protocol == __constant_htons(ETH_P_IP))
tx_flags |= IXGBE_TX_FLAGS_IPV4; tx_flags |= IXGBE_TX_FLAGS_IPV4;
tso = ixgbe_tso(tx_ring, skb, tx_flags, protocol, &hdr_len); tso = ixgbe_tso(tx_ring, skb, tx_flags, protocol, &hdr_len);
if (tso < 0) if (tso < 0)
goto out_drop; goto out_drop;
...@@ -6857,8 +6875,10 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, ...@@ -6857,8 +6875,10 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
/* add the ATR filter if ATR is on */ /* add the ATR filter if ATR is on */
if (test_bit(__IXGBE_TX_FDIR_INIT_DONE, &tx_ring->state)) if (test_bit(__IXGBE_TX_FDIR_INIT_DONE, &tx_ring->state))
ixgbe_atr(tx_ring, skb, tx_flags, protocol); ixgbe_atr(tx_ring, skb, tx_flags, protocol);
}
#ifdef IXGBE_FCOE
xmit_fcoe:
#endif /* IXGBE_FCOE */
ixgbe_tx_map(tx_ring, skb, first, tx_flags, hdr_len); ixgbe_tx_map(tx_ring, skb, first, tx_flags, hdr_len);
ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED); ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
......
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