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

Commit 67359c3c authored by Mark Rustad's avatar Mark Rustad Committed by Jeff Kirsher
Browse files

ixgbe: Add support for VXLAN RX offloads



Add support for VXLAN RX offloads for the X55x devices that support
them.

Signed-off-by: default avatarMark Rustad <mark.d.rustad@intel.com>
Tested-by: default avatarPhil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent f467bc06
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -630,6 +630,7 @@ struct ixgbe_adapter {
#define IXGBE_FLAG_FCOE_ENABLED                 (u32)(1 << 21)
#define IXGBE_FLAG_SRIOV_CAPABLE                (u32)(1 << 22)
#define IXGBE_FLAG_SRIOV_ENABLED                (u32)(1 << 23)
#define IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE	BIT(24)

	u32 flags2;
#define IXGBE_FLAG2_RSC_CAPABLE                 (u32)(1 << 0)
@@ -644,6 +645,9 @@ struct ixgbe_adapter {
#define IXGBE_FLAG2_RSS_FIELD_IPV6_UDP		(u32)(1 << 9)
#define IXGBE_FLAG2_PTP_PPS_ENABLED		(u32)(1 << 10)
#define IXGBE_FLAG2_PHY_INTERRUPT		(u32)(1 << 11)
#ifdef CONFIG_IXGBE_VXLAN
#define IXGBE_FLAG2_VXLAN_REREG_NEEDED		BIT(12)
#endif

	/* Tx fast path data */
	int num_tx_queues;
@@ -757,7 +761,9 @@ struct ixgbe_adapter {
	u32 timer_event_accumulator;
	u32 vferr_refcount;
	struct ixgbe_mac_addr *mac_table;
#ifdef CONFIG_IXGBE_VXLAN
	u16 vxlan_port;
#endif
	struct kobject *info_kobj;
#ifdef CONFIG_IXGBE_HWMON
	struct hwmon_buff *ixgbe_hwmon_buff;
+14 −4
Original line number Diff line number Diff line
@@ -1519,6 +1519,9 @@ static u32 ixgbe_atr_compute_sig_hash_82599(union ixgbe_atr_hash_dword input,
 *  @input: unique input dword
 *  @common: compressed common input dword
 *  @queue: queue index to direct traffic to
 *
 * Note that the tunnel bit in input must not be set when the hardware
 * tunneling support does not exist.
 **/
s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
					  union ixgbe_atr_hash_dword input,
@@ -1526,13 +1529,18 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
					  u8 queue)
{
	u64 fdirhashcmd;
	u8 flow_type;
	bool tunnel;
	u32 fdircmd;

	/*
	 * Get the flow_type in order to program FDIRCMD properly
	 * lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6
	 */
	switch (input.formatted.flow_type) {
	tunnel = !!(input.formatted.flow_type & IXGBE_ATR_L4TYPE_TUNNEL_MASK);
	flow_type = input.formatted.flow_type &
		    (IXGBE_ATR_L4TYPE_TUNNEL_MASK - 1);
	switch (flow_type) {
	case IXGBE_ATR_FLOW_TYPE_TCPV4:
	case IXGBE_ATR_FLOW_TYPE_UDPV4:
	case IXGBE_ATR_FLOW_TYPE_SCTPV4:
@@ -1548,8 +1556,10 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
	/* configure FDIRCMD register */
	fdircmd = IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE |
		  IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN;
	fdircmd |= input.formatted.flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT;
	fdircmd |= (u32)flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT;
	fdircmd |= (u32)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT;
	if (tunnel)
		fdircmd |= IXGBE_FDIRCMD_TUNNEL_FILTER;

	/*
	 * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits
+98 −21
Original line number Diff line number Diff line
/*******************************************************************************

  Intel 10 Gigabit PCI Express Linux driver
  Copyright(c) 1999 - 2014 Intel Corporation.
  Copyright(c) 1999 - 2015 Intel Corporation.

  This program is free software; you can redistribute it and/or modify it
  under the terms and conditions of the GNU General Public License,
@@ -65,6 +65,9 @@
#include "ixgbe_common.h"
#include "ixgbe_dcb_82599.h"
#include "ixgbe_sriov.h"
#ifdef CONFIG_IXGBE_VXLAN
#include <net/vxlan.h>
#endif

char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
@@ -79,7 +82,7 @@ static char ixgbe_default_device_descr[] =
#define DRV_VERSION "4.0.1-k"
const char ixgbe_driver_version[] = DRV_VERSION;
static const char ixgbe_copyright[] =
				"Copyright (c) 1999-2014 Intel Corporation.";
				"Copyright (c) 1999-2015 Intel Corporation.";

static const char ixgbe_overheat_msg[] = "Network adapter has been stopped because it has over heated. Restart the computer. If the problem persists, power off the system and replace the adapter";

@@ -1430,7 +1433,6 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring,
	    (hdr_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_TUNNEL >> 16))) {
		encap_pkt = true;
		skb->encapsulation = 1;
		skb->ip_summed = CHECKSUM_NONE;
	}

	/* if IP and error */
@@ -4261,6 +4263,21 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter)
	}
}

static void ixgbe_clear_vxlan_port(struct ixgbe_adapter *adapter)
{
	switch (adapter->hw.mac.type) {
	case ixgbe_mac_X550:
	case ixgbe_mac_X550EM_x:
		IXGBE_WRITE_REG(&adapter->hw, IXGBE_VXLANCTRL, 0);
#ifdef CONFIG_IXGBE_VXLAN
		adapter->vxlan_port = 0;
#endif
		break;
	default:
		break;
	}
}

#ifdef CONFIG_IXGBE_DCB
/**
 * ixgbe_configure_dcb - Configure DCB hardware
@@ -5301,6 +5318,9 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
	case ixgbe_mac_X550:
#ifdef CONFIG_IXGBE_DCA
		adapter->flags &= ~IXGBE_FLAG_DCA_CAPABLE;
#endif
#ifdef CONFIG_IXGBE_VXLAN
		adapter->flags |= IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE;
#endif
		break;
	default:
@@ -5753,10 +5773,11 @@ static int ixgbe_open(struct net_device *netdev)

	ixgbe_up_complete(adapter);

#if IS_ENABLED(CONFIG_IXGBE_VXLAN)
	ixgbe_clear_vxlan_port(adapter);
#ifdef CONFIG_IXGBE_VXLAN
	vxlan_get_rx_port(netdev);

#endif

	return 0;

err_set_queues:
@@ -6816,6 +6837,12 @@ static void ixgbe_service_task(struct work_struct *work)
		ixgbe_service_event_complete(adapter);
		return;
	}
#ifdef CONFIG_IXGBE_VXLAN
	if (adapter->flags2 & IXGBE_FLAG2_VXLAN_REREG_NEEDED) {
		adapter->flags2 &= ~IXGBE_FLAG2_VXLAN_REREG_NEEDED;
		vxlan_get_rx_port(adapter->netdev);
	}
#endif /* CONFIG_IXGBE_VXLAN */
	ixgbe_reset_subtask(adapter);
	ixgbe_phy_interrupt_subtask(adapter);
	ixgbe_sfp_detection_subtask(adapter);
@@ -7240,6 +7267,10 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
		struct ipv6hdr *ipv6;
	} hdr;
	struct tcphdr *th;
	struct sk_buff *skb;
#ifdef CONFIG_IXGBE_VXLAN
	u8 encap = false;
#endif /* CONFIG_IXGBE_VXLAN */
	__be16 vlan_id;

	/* if ring doesn't have a interrupt vector, cannot perform ATR */
@@ -7253,16 +7284,36 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
	ring->atr_count++;

	/* snag network header to get L4 type and address */
	hdr.network = skb_network_header(first->skb);
	skb = first->skb;
	hdr.network = skb_network_header(skb);
	if (skb->encapsulation) {
#ifdef CONFIG_IXGBE_VXLAN
		struct ixgbe_adapter *adapter = q_vector->adapter;

		if (!adapter->vxlan_port)
			return;
		if (first->protocol != htons(ETH_P_IP) ||
		    hdr.ipv4->version != IPVERSION ||
		    hdr.ipv4->protocol != IPPROTO_UDP) {
			return;
		}
		if (ntohs(udp_hdr(skb)->dest) != adapter->vxlan_port)
			return;
		encap = true;
		hdr.network = skb_inner_network_header(skb);
		th = inner_tcp_hdr(skb);
#else
		return;
#endif /* CONFIG_IXGBE_VXLAN */
	} else {
		/* Currently only IPv4/IPv6 with TCP is supported */
		if ((first->protocol != htons(ETH_P_IPV6) ||
		     hdr.ipv6->nexthdr != IPPROTO_TCP) &&
		    (first->protocol != htons(ETH_P_IP) ||
		     hdr.ipv4->protocol != IPPROTO_TCP))
			return;

	th = tcp_hdr(first->skb);
		th = tcp_hdr(skb);
	}

	/* skip this packet since it is invalid or the socket is closing */
	if (!th || th->fin)
@@ -7311,6 +7362,11 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
			     hdr.ipv6->daddr.s6_addr32[3];
	}

#ifdef CONFIG_IXGBE_VXLAN
	if (encap)
		input.formatted.flow_type |= IXGBE_ATR_L4TYPE_TUNNEL_MASK;
#endif /* CONFIG_IXGBE_VXLAN */

	/* This assumes the Rx queue and Tx queue are bound to the same CPU */
	ixgbe_fdir_add_signature_filter_82599(&q_vector->adapter->hw,
					      input, common, ring->queue_index);
@@ -7937,12 +7993,23 @@ static int ixgbe_set_features(struct net_device *netdev,
		need_reset = true;

	netdev->features = features;

#ifdef CONFIG_IXGBE_VXLAN
	if ((adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE)) {
		if (features & NETIF_F_RXCSUM)
			adapter->flags2 |= IXGBE_FLAG2_VXLAN_REREG_NEEDED;
		else
			ixgbe_clear_vxlan_port(adapter);
	}
#endif /* CONFIG_IXGBE_VXLAN */

	if (need_reset)
		ixgbe_do_reset(netdev);

	return 0;
}

#ifdef CONFIG_IXGBE_VXLAN
/**
 * ixgbe_add_vxlan_port - Get notifications about VXLAN ports that come up
 * @dev: The port's netdev
@@ -7956,17 +8023,18 @@ static void ixgbe_add_vxlan_port(struct net_device *dev, sa_family_t sa_family,
	struct ixgbe_hw *hw = &adapter->hw;
	u16 new_port = ntohs(port);

	if (!(adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
		return;

	if (sa_family == AF_INET6)
		return;

	if (adapter->vxlan_port == new_port) {
		netdev_info(dev, "Port %d already offloaded\n", new_port);
	if (adapter->vxlan_port == new_port)
		return;
	}

	if (adapter->vxlan_port) {
		netdev_info(dev,
			    "Hit Max num of UDP ports, not adding port %d\n",
			    "Hit Max num of VXLAN ports, not adding port %d\n",
			    new_port);
		return;
	}
@@ -7985,9 +8053,11 @@ static void ixgbe_del_vxlan_port(struct net_device *dev, sa_family_t sa_family,
				 __be16 port)
{
	struct ixgbe_adapter *adapter = netdev_priv(dev);
	struct ixgbe_hw *hw = &adapter->hw;
	u16 new_port = ntohs(port);

	if (!(adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
		return;

	if (sa_family == AF_INET6)
		return;

@@ -7997,9 +8067,10 @@ static void ixgbe_del_vxlan_port(struct net_device *dev, sa_family_t sa_family,
		return;
	}

	adapter->vxlan_port = 0;
	IXGBE_WRITE_REG(hw, IXGBE_VXLANCTRL, 0);
	ixgbe_clear_vxlan_port(adapter);
	adapter->flags2 |= IXGBE_FLAG2_VXLAN_REREG_NEEDED;
}
#endif /* CONFIG_IXGBE_VXLAN */

static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
			     struct net_device *dev,
@@ -8290,8 +8361,10 @@ static const struct net_device_ops ixgbe_netdev_ops = {
	.ndo_bridge_getlink	= ixgbe_ndo_bridge_getlink,
	.ndo_dfwd_add_station	= ixgbe_fwd_add,
	.ndo_dfwd_del_station	= ixgbe_fwd_del,
#ifdef CONFIG_IXGBE_VXLAN
	.ndo_add_vxlan_port	= ixgbe_add_vxlan_port,
	.ndo_del_vxlan_port	= ixgbe_del_vxlan_port,
#endif /* CONFIG_IXGBE_VXLAN */
	.ndo_features_check	= ixgbe_features_check,
};

@@ -8658,14 +8731,18 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
	netdev->priv_flags |= IFF_UNICAST_FLT;
	netdev->priv_flags |= IFF_SUPP_NOFCS;

#ifdef CONFIG_IXGBE_VXLAN
	switch (adapter->hw.mac.type) {
	case ixgbe_mac_X550:
	case ixgbe_mac_X550EM_x:
		netdev->hw_enc_features |= NETIF_F_RXCSUM;
		netdev->hw_enc_features |= NETIF_F_RXCSUM |
					   NETIF_F_IP_CSUM |
					   NETIF_F_IPV6_CSUM;
		break;
	default:
		break;
	}
#endif /* CONFIG_IXGBE_VXLAN */

#ifdef CONFIG_IXGBE_DCB
	netdev->dcbnl_ops = &dcbnl_ops;
+9 −6
Original line number Diff line number Diff line
@@ -2540,9 +2540,11 @@ enum ixgbe_fdir_pballoc_type {
#define IXGBE_FDIRCMD_QUEUE_EN                  0x00008000
#define IXGBE_FDIRCMD_FLOW_TYPE_SHIFT           5
#define IXGBE_FDIRCMD_RX_QUEUE_SHIFT            16
#define IXGBE_FDIRCMD_RX_TUNNEL_FILTER_SHIFT	23
#define IXGBE_FDIRCMD_VT_POOL_SHIFT             24
#define IXGBE_FDIR_INIT_DONE_POLL               10
#define IXGBE_FDIRCMD_CMD_POLL                  10
#define IXGBE_FDIRCMD_TUNNEL_FILTER		0x00800000

#define IXGBE_FDIR_DROP_QUEUE                   127

@@ -2839,6 +2841,7 @@ typedef u32 ixgbe_link_speed;
#define IXGBE_ATR_L4TYPE_TCP		0x2
#define IXGBE_ATR_L4TYPE_SCTP		0x3
#define IXGBE_ATR_L4TYPE_IPV6_MASK	0x4
#define IXGBE_ATR_L4TYPE_TUNNEL_MASK	0x10
enum ixgbe_atr_flow_type {
	IXGBE_ATR_FLOW_TYPE_IPV4   = 0x0,
	IXGBE_ATR_FLOW_TYPE_UDPV4  = 0x1,