Commit 2bb19d6e authored by Brett Creeley's avatar Brett Creeley Committed by Jeff Kirsher

ice: Fix transmit for all software offloaded VLANs

Currently the driver does not recognize when there is an 802.1AD VLAN
tag right after the dmac/smac (outermost VLAN tag). If any DCB map is
applied and/or DCB is enabled this is causing the hardware to insert a
VLAN 0 tag after the 802.1AD VLAN tag that is already in the packet.
Fix this by preventing VLAN tag 0 from being added when any VLAN is
already present after dmac/smac (software offloaded) or skb (hardware
offloaded).
Signed-off-by: default avatarBrett Creeley <brett.creeley@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent c1636a6e
...@@ -791,39 +791,31 @@ void ice_update_dcb_stats(struct ice_pf *pf) ...@@ -791,39 +791,31 @@ void ice_update_dcb_stats(struct ice_pf *pf)
* ice_tx_prepare_vlan_flags_dcb - prepare VLAN tagging for DCB * ice_tx_prepare_vlan_flags_dcb - prepare VLAN tagging for DCB
* @tx_ring: ring to send buffer on * @tx_ring: ring to send buffer on
* @first: pointer to struct ice_tx_buf * @first: pointer to struct ice_tx_buf
*
* This should not be called if the outer VLAN is software offloaded as the VLAN
* tag will already be configured with the correct ID and priority bits
*/ */
int void
ice_tx_prepare_vlan_flags_dcb(struct ice_ring *tx_ring, ice_tx_prepare_vlan_flags_dcb(struct ice_ring *tx_ring,
struct ice_tx_buf *first) struct ice_tx_buf *first)
{ {
struct sk_buff *skb = first->skb; struct sk_buff *skb = first->skb;
if (!test_bit(ICE_FLAG_DCB_ENA, tx_ring->vsi->back->flags)) if (!test_bit(ICE_FLAG_DCB_ENA, tx_ring->vsi->back->flags))
return 0; return;
/* Insert 802.1p priority into VLAN header */ /* Insert 802.1p priority into VLAN header */
if ((first->tx_flags & (ICE_TX_FLAGS_HW_VLAN | ICE_TX_FLAGS_SW_VLAN)) || if ((first->tx_flags & ICE_TX_FLAGS_HW_VLAN) ||
skb->priority != TC_PRIO_CONTROL) { skb->priority != TC_PRIO_CONTROL) {
first->tx_flags &= ~ICE_TX_FLAGS_VLAN_PR_M; first->tx_flags &= ~ICE_TX_FLAGS_VLAN_PR_M;
/* Mask the lower 3 bits to set the 802.1p priority */ /* Mask the lower 3 bits to set the 802.1p priority */
first->tx_flags |= (skb->priority & 0x7) << first->tx_flags |= (skb->priority & 0x7) <<
ICE_TX_FLAGS_VLAN_PR_S; ICE_TX_FLAGS_VLAN_PR_S;
if (first->tx_flags & ICE_TX_FLAGS_SW_VLAN) { /* if this is not already set it means a VLAN 0 + priority needs
struct vlan_ethhdr *vhdr; * to be offloaded
int rc; */
rc = skb_cow_head(skb, 0);
if (rc < 0)
return rc;
vhdr = (struct vlan_ethhdr *)skb->data;
vhdr->h_vlan_TCI = htons(first->tx_flags >>
ICE_TX_FLAGS_VLAN_S);
} else {
first->tx_flags |= ICE_TX_FLAGS_HW_VLAN; first->tx_flags |= ICE_TX_FLAGS_HW_VLAN;
} }
}
return 0;
} }
/** /**
......
...@@ -27,7 +27,7 @@ void ice_pf_dcb_recfg(struct ice_pf *pf); ...@@ -27,7 +27,7 @@ void ice_pf_dcb_recfg(struct ice_pf *pf);
void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi); void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi);
int ice_init_pf_dcb(struct ice_pf *pf, bool locked); int ice_init_pf_dcb(struct ice_pf *pf, bool locked);
void ice_update_dcb_stats(struct ice_pf *pf); void ice_update_dcb_stats(struct ice_pf *pf);
int void
ice_tx_prepare_vlan_flags_dcb(struct ice_ring *tx_ring, ice_tx_prepare_vlan_flags_dcb(struct ice_ring *tx_ring,
struct ice_tx_buf *first); struct ice_tx_buf *first);
void void
......
...@@ -2053,49 +2053,25 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off) ...@@ -2053,49 +2053,25 @@ int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)
* *
* Checks the skb and set up correspondingly several generic transmit flags * Checks the skb and set up correspondingly several generic transmit flags
* related to VLAN tagging for the HW, such as VLAN, DCB, etc. * related to VLAN tagging for the HW, such as VLAN, DCB, etc.
*
* Returns error code indicate the frame should be dropped upon error and the
* otherwise returns 0 to indicate the flags has been set properly.
*/ */
static int static void
ice_tx_prepare_vlan_flags(struct ice_ring *tx_ring, struct ice_tx_buf *first) ice_tx_prepare_vlan_flags(struct ice_ring *tx_ring, struct ice_tx_buf *first)
{ {
struct sk_buff *skb = first->skb; struct sk_buff *skb = first->skb;
__be16 protocol = skb->protocol;
if (protocol == htons(ETH_P_8021Q) &&
!(tx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) {
/* when HW VLAN acceleration is turned off by the user the
* stack sets the protocol to 8021q so that the driver
* can take any steps required to support the SW only
* VLAN handling. In our case the driver doesn't need
* to take any further steps so just set the protocol
* to the encapsulated ethertype.
*/
skb->protocol = vlan_get_protocol(skb);
return 0;
}
/* if we have a HW VLAN tag being added, default to the HW one */ /* nothing left to do, software offloaded VLAN */
if (!skb_vlan_tag_present(skb) && eth_type_vlan(skb->protocol))
return;
/* currently, we always assume 802.1Q for VLAN insertion as VLAN
* insertion for 802.1AD is not supported
*/
if (skb_vlan_tag_present(skb)) { if (skb_vlan_tag_present(skb)) {
first->tx_flags |= skb_vlan_tag_get(skb) << ICE_TX_FLAGS_VLAN_S; first->tx_flags |= skb_vlan_tag_get(skb) << ICE_TX_FLAGS_VLAN_S;
first->tx_flags |= ICE_TX_FLAGS_HW_VLAN; first->tx_flags |= ICE_TX_FLAGS_HW_VLAN;
} else if (protocol == htons(ETH_P_8021Q)) {
struct vlan_hdr *vhdr, _vhdr;
/* for SW VLAN, check the next protocol and store the tag */
vhdr = (struct vlan_hdr *)skb_header_pointer(skb, ETH_HLEN,
sizeof(_vhdr),
&_vhdr);
if (!vhdr)
return -EINVAL;
first->tx_flags |= ntohs(vhdr->h_vlan_TCI) <<
ICE_TX_FLAGS_VLAN_S;
first->tx_flags |= ICE_TX_FLAGS_SW_VLAN;
} }
return ice_tx_prepare_vlan_flags_dcb(tx_ring, first); ice_tx_prepare_vlan_flags_dcb(tx_ring, first);
} }
/** /**
...@@ -2403,8 +2379,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_ring *tx_ring) ...@@ -2403,8 +2379,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_ring *tx_ring)
first->tx_flags = 0; first->tx_flags = 0;
/* prepare the VLAN tagging flags for Tx */ /* prepare the VLAN tagging flags for Tx */
if (ice_tx_prepare_vlan_flags(tx_ring, first)) ice_tx_prepare_vlan_flags(tx_ring, first);
goto out_drop;
/* set up TSO offload */ /* set up TSO offload */
tso = ice_tso(first, &offload); tso = ice_tso(first, &offload);
......
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