net/mlx5e: When RXFCS is set, add FCS data into checksum calculation

When RXFCS feature is enabled, the HW do not strip the FCS data,
however it is not present in the checksum calculated by the HW.

Fix that by manually calculating the FCS checksum and adding it to the SKB
checksum field.

Add helper function to find the FCS data for all SKB forms (linear,
one fragment or more).

Fixes: 102722fc68 ("net/mlx5e: Add support for RXFCS feature flag")
Signed-off-by: Eran Ben Elisha <eranbe@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
This commit is contained in:
Eran Ben Elisha 2018-05-01 16:25:07 +03:00 committed by Saeed Mahameed
parent d546b67cda
commit 902a545904

View file

@ -615,6 +615,45 @@ static inline bool is_last_ethertype_ip(struct sk_buff *skb, int *network_depth)
return (ethertype == htons(ETH_P_IP) || ethertype == htons(ETH_P_IPV6));
}
static __be32 mlx5e_get_fcs(struct sk_buff *skb)
{
int last_frag_sz, bytes_in_prev, nr_frags;
u8 *fcs_p1, *fcs_p2;
skb_frag_t *last_frag;
__be32 fcs_bytes;
if (!skb_is_nonlinear(skb))
return *(__be32 *)(skb->data + skb->len - ETH_FCS_LEN);
nr_frags = skb_shinfo(skb)->nr_frags;
last_frag = &skb_shinfo(skb)->frags[nr_frags - 1];
last_frag_sz = skb_frag_size(last_frag);
/* If all FCS data is in last frag */
if (last_frag_sz >= ETH_FCS_LEN)
return *(__be32 *)(skb_frag_address(last_frag) +
last_frag_sz - ETH_FCS_LEN);
fcs_p2 = (u8 *)skb_frag_address(last_frag);
bytes_in_prev = ETH_FCS_LEN - last_frag_sz;
/* Find where the other part of the FCS is - Linear or another frag */
if (nr_frags == 1) {
fcs_p1 = skb_tail_pointer(skb);
} else {
skb_frag_t *prev_frag = &skb_shinfo(skb)->frags[nr_frags - 2];
fcs_p1 = skb_frag_address(prev_frag) +
skb_frag_size(prev_frag);
}
fcs_p1 -= bytes_in_prev;
memcpy(&fcs_bytes, fcs_p1, bytes_in_prev);
memcpy(((u8 *)&fcs_bytes) + bytes_in_prev, fcs_p2, last_frag_sz);
return fcs_bytes;
}
static inline void mlx5e_handle_csum(struct net_device *netdev,
struct mlx5_cqe64 *cqe,
struct mlx5e_rq *rq,
@ -643,6 +682,9 @@ static inline void mlx5e_handle_csum(struct net_device *netdev,
skb->csum = csum_partial(skb->data + ETH_HLEN,
network_depth - ETH_HLEN,
skb->csum);
if (unlikely(netdev->features & NETIF_F_RXFCS))
skb->csum = csum_add(skb->csum,
(__force __wsum)mlx5e_get_fcs(skb));
rq->stats.csum_complete++;
return;
}