Commit 8144f0f7 authored by Joseph Gasparakis's avatar Joseph Gasparakis Committed by Jeff Kirsher

i40e: Rx checksum offload for VXLAN

This implements receive offload for VXLAN for i40e.  The hardware
supports checksum offload/verification of the inner/outer header.

Change-Id: I450db300af6713f2044fef1191a0d1d294c13369
Signed-off-by: default avatarJoseph Gasparakis <joseph.gasparakis@intel.com>
Signed-off-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent a1c9a9d9
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#define _I40E_H_ #define _I40E_H_
#include <net/tcp.h> #include <net/tcp.h>
#include <net/udp.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
......
...@@ -860,12 +860,25 @@ static void i40e_receive_skb(struct i40e_ring *rx_ring, ...@@ -860,12 +860,25 @@ static void i40e_receive_skb(struct i40e_ring *rx_ring,
* @skb: skb currently being received and modified * @skb: skb currently being received and modified
* @rx_status: status value of last descriptor in packet * @rx_status: status value of last descriptor in packet
* @rx_error: error value of last descriptor in packet * @rx_error: error value of last descriptor in packet
* @rx_ptype: ptype value of last descriptor in packet
**/ **/
static inline void i40e_rx_checksum(struct i40e_vsi *vsi, static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
struct sk_buff *skb, struct sk_buff *skb,
u32 rx_status, u32 rx_status,
u32 rx_error) u32 rx_error,
u16 rx_ptype)
{ {
bool ipv4_tunnel, ipv6_tunnel;
__wsum rx_udp_csum;
__sum16 csum;
struct iphdr *iph;
ipv4_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
(rx_ptype < I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
ipv6_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
(rx_ptype < I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
skb->encapsulation = ipv4_tunnel || ipv6_tunnel;
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
/* Rx csum enabled and ip headers found? */ /* Rx csum enabled and ip headers found? */
...@@ -873,13 +886,43 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -873,13 +886,43 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
return; return;
/* IP or L4 checksum error */ /* IP or L4 or outmost IP checksum error */
if (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | if (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) |
(1 << I40E_RX_DESC_ERROR_L4E_SHIFT))) { (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) |
(1 << I40E_RX_DESC_ERROR_EIPE_SHIFT))) {
vsi->back->hw_csum_rx_error++; vsi->back->hw_csum_rx_error++;
return; return;
} }
if (ipv4_tunnel &&
!(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) {
/* If VXLAN traffic has an outer UDPv4 checksum we need to check
* it in the driver, hardware does not do it for us.
* Since L3L4P bit was set we assume a valid IHL value (>=5)
* so the total length of IPv4 header is IHL*4 bytes
*/
skb->transport_header = skb->mac_header +
sizeof(struct ethhdr) +
(ip_hdr(skb)->ihl * 4);
/* Add 4 bytes for VLAN tagged packets */
skb->transport_header += (skb->protocol == htons(ETH_P_8021Q) ||
skb->protocol == htons(ETH_P_8021AD))
? VLAN_HLEN : 0;
rx_udp_csum = udp_csum(skb);
iph = ip_hdr(skb);
csum = csum_tcpudp_magic(
iph->saddr, iph->daddr,
(skb->len - skb_transport_offset(skb)),
IPPROTO_UDP, rx_udp_csum);
if (udp_hdr(skb)->check != csum) {
vsi->back->hw_csum_rx_error++;
return;
}
}
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
} }
...@@ -920,6 +963,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) ...@@ -920,6 +963,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
union i40e_rx_desc *rx_desc; union i40e_rx_desc *rx_desc;
u32 rx_error, rx_status; u32 rx_error, rx_status;
u64 qword; u64 qword;
u16 rx_ptype;
rx_desc = I40E_RX_DESC(rx_ring, i); rx_desc = I40E_RX_DESC(rx_ring, i);
qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
...@@ -952,6 +996,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) ...@@ -952,6 +996,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
rx_hbo = rx_error & (1 << I40E_RX_DESC_ERROR_HBO_SHIFT); rx_hbo = rx_error & (1 << I40E_RX_DESC_ERROR_HBO_SHIFT);
rx_error &= ~(1 << I40E_RX_DESC_ERROR_HBO_SHIFT); rx_error &= ~(1 << I40E_RX_DESC_ERROR_HBO_SHIFT);
rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
I40E_RXD_QW1_PTYPE_SHIFT;
rx_bi->skb = NULL; rx_bi->skb = NULL;
/* This memory barrier is needed to keep us from reading /* This memory barrier is needed to keep us from reading
...@@ -1032,13 +1078,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) ...@@ -1032,13 +1078,14 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
} }
skb->rxhash = i40e_rx_hash(rx_ring, rx_desc); skb->rxhash = i40e_rx_hash(rx_ring, rx_desc);
i40e_rx_checksum(vsi, skb, rx_status, rx_error);
/* probably a little skewed due to removing CRC */ /* probably a little skewed due to removing CRC */
total_rx_bytes += skb->len; total_rx_bytes += skb->len;
total_rx_packets++; total_rx_packets++;
skb->protocol = eth_type_trans(skb, rx_ring->netdev); skb->protocol = eth_type_trans(skb, rx_ring->netdev);
i40e_rx_checksum(vsi, skb, rx_status, rx_error, rx_ptype);
vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)
? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1)
: 0; : 0;
......
...@@ -513,7 +513,8 @@ enum i40e_rx_desc_status_bits { ...@@ -513,7 +513,8 @@ enum i40e_rx_desc_status_bits {
I40E_RX_DESC_STATUS_UMBCAST_SHIFT = 9, /* 2 BITS */ I40E_RX_DESC_STATUS_UMBCAST_SHIFT = 9, /* 2 BITS */
I40E_RX_DESC_STATUS_FLM_SHIFT = 11, I40E_RX_DESC_STATUS_FLM_SHIFT = 11,
I40E_RX_DESC_STATUS_FLTSTAT_SHIFT = 12, /* 2 BITS */ I40E_RX_DESC_STATUS_FLTSTAT_SHIFT = 12, /* 2 BITS */
I40E_RX_DESC_STATUS_LPBK_SHIFT = 14 I40E_RX_DESC_STATUS_LPBK_SHIFT = 14,
I40E_RX_DESC_STATUS_UDP_0_SHIFT = 16
}; };
#define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT I40E_RX_DESC_STATUS_TSYNINDX_SHIFT #define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT I40E_RX_DESC_STATUS_TSYNINDX_SHIFT
...@@ -559,28 +560,32 @@ enum i40e_rx_desc_error_l3l4e_fcoe_masks { ...@@ -559,28 +560,32 @@ enum i40e_rx_desc_error_l3l4e_fcoe_masks {
/* Packet type non-ip values */ /* Packet type non-ip values */
enum i40e_rx_l2_ptype { enum i40e_rx_l2_ptype {
I40E_RX_PTYPE_L2_RESERVED = 0, I40E_RX_PTYPE_L2_RESERVED = 0,
I40E_RX_PTYPE_L2_MAC_PAY2 = 1, I40E_RX_PTYPE_L2_MAC_PAY2 = 1,
I40E_RX_PTYPE_L2_TIMESYNC_PAY2 = 2, I40E_RX_PTYPE_L2_TIMESYNC_PAY2 = 2,
I40E_RX_PTYPE_L2_FIP_PAY2 = 3, I40E_RX_PTYPE_L2_FIP_PAY2 = 3,
I40E_RX_PTYPE_L2_OUI_PAY2 = 4, I40E_RX_PTYPE_L2_OUI_PAY2 = 4,
I40E_RX_PTYPE_L2_MACCNTRL_PAY2 = 5, I40E_RX_PTYPE_L2_MACCNTRL_PAY2 = 5,
I40E_RX_PTYPE_L2_LLDP_PAY2 = 6, I40E_RX_PTYPE_L2_LLDP_PAY2 = 6,
I40E_RX_PTYPE_L2_ECP_PAY2 = 7, I40E_RX_PTYPE_L2_ECP_PAY2 = 7,
I40E_RX_PTYPE_L2_EVB_PAY2 = 8, I40E_RX_PTYPE_L2_EVB_PAY2 = 8,
I40E_RX_PTYPE_L2_QCN_PAY2 = 9, I40E_RX_PTYPE_L2_QCN_PAY2 = 9,
I40E_RX_PTYPE_L2_EAPOL_PAY2 = 10, I40E_RX_PTYPE_L2_EAPOL_PAY2 = 10,
I40E_RX_PTYPE_L2_ARP = 11, I40E_RX_PTYPE_L2_ARP = 11,
I40E_RX_PTYPE_L2_FCOE_PAY3 = 12, I40E_RX_PTYPE_L2_FCOE_PAY3 = 12,
I40E_RX_PTYPE_L2_FCOE_FCDATA_PAY3 = 13, I40E_RX_PTYPE_L2_FCOE_FCDATA_PAY3 = 13,
I40E_RX_PTYPE_L2_FCOE_FCRDY_PAY3 = 14, I40E_RX_PTYPE_L2_FCOE_FCRDY_PAY3 = 14,
I40E_RX_PTYPE_L2_FCOE_FCRSP_PAY3 = 15, I40E_RX_PTYPE_L2_FCOE_FCRSP_PAY3 = 15,
I40E_RX_PTYPE_L2_FCOE_FCOTHER_PA = 16, I40E_RX_PTYPE_L2_FCOE_FCOTHER_PA = 16,
I40E_RX_PTYPE_L2_FCOE_VFT_PAY3 = 17, I40E_RX_PTYPE_L2_FCOE_VFT_PAY3 = 17,
I40E_RX_PTYPE_L2_FCOE_VFT_FCDATA = 18, I40E_RX_PTYPE_L2_FCOE_VFT_FCDATA = 18,
I40E_RX_PTYPE_L2_FCOE_VFT_FCRDY = 19, I40E_RX_PTYPE_L2_FCOE_VFT_FCRDY = 19,
I40E_RX_PTYPE_L2_FCOE_VFT_FCRSP = 20, I40E_RX_PTYPE_L2_FCOE_VFT_FCRSP = 20,
I40E_RX_PTYPE_L2_FCOE_VFT_FCOTHER = 21 I40E_RX_PTYPE_L2_FCOE_VFT_FCOTHER = 21,
I40E_RX_PTYPE_GRENAT4_MAC_PAY3 = 58,
I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4 = 87,
I40E_RX_PTYPE_GRENAT6_MAC_PAY3 = 124,
I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4 = 153
}; };
struct i40e_rx_ptype_decoded { struct i40e_rx_ptype_decoded {
......
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