Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#define _I40E_H_

#include <net/tcp.h>
#include <net/udp.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
+52 −5
Original line number Diff line number Diff line
@@ -860,12 +860,25 @@ static void i40e_receive_skb(struct i40e_ring *rx_ring,
 * @skb: skb currently being received and modified
 * @rx_status: status 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,
				    struct sk_buff *skb,
				    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;

	/* Rx csum enabled and ip headers found? */
@@ -873,12 +886,42 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
	      rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
		return;

	/* IP or L4 checksum error */
	/* IP or L4 or outmost IP checksum error */
	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++;
		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;
}
@@ -920,6 +963,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
	union i40e_rx_desc *rx_desc;
	u32 rx_error, rx_status;
	u64 qword;
	u16 rx_ptype;

	rx_desc = I40E_RX_DESC(rx_ring, i);
	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)
		rx_hbo = 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;

		/* 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)
		}

		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 */
		total_rx_bytes += skb->len;
		total_rx_packets++;

		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)
			 ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1)
			 : 0;
+28 −23
Original line number Diff line number Diff line
@@ -513,7 +513,8 @@ enum i40e_rx_desc_status_bits {
	I40E_RX_DESC_STATUS_UMBCAST_SHIFT	= 9, /* 2 BITS */
	I40E_RX_DESC_STATUS_FLM_SHIFT		= 11,
	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
@@ -580,7 +581,11 @@ enum i40e_rx_l2_ptype {
	I40E_RX_PTYPE_L2_FCOE_VFT_FCDATA		= 18,
	I40E_RX_PTYPE_L2_FCOE_VFT_FCRDY			= 19,
	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 {