Commit 9904e1ee authored by David S. Miller's avatar David S. Miller
Browse files


Tony Nguyen says:

====================
100GbE Intel Wired LAN Driver Updates 2021-04-22

This series contains updates to virtchnl header file, ice, and iavf
drivers.

Vignesh adds support to warn about potentially malicious VFs; those that
are overflowing the mailbox for the ice driver.

Michal adds support for an allowlist/denylist of VF commands based on
supported capabilities for the ice driver.

Brett adds support for iavf UDP segmentation offload by adding the
capability bit to virtchnl, advertising support in the ice driver, and
enabling it in the iavf driver. He also adds a helper function for
getting the VF VSI for ice.

Colin Ian King removes an unneeded pointer assignment.

Qi enables support in the ice driver to support virtchnl requests from
the iavf to configure its own RSS input set. This includes adding new
capability bits, structures, and commands to virtchnl header file.

Haiyue enables configuring RSS flow hash via ethtool to support TCP, UDP
and SCTP protocols in iavf.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3197a98c e41985f0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12,4 +12,5 @@ subdir-ccflags-y += -I$(src)
obj-$(CONFIG_IAVF) += iavf.o

iavf-objs := iavf_main.o iavf_ethtool.o iavf_virtchnl.o iavf_fdir.o \
	     iavf_adv_rss.o \
	     iavf_txrx.o iavf_common.o iavf_adminq.o iavf_client.o
+10 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include <linux/avf/virtchnl.h>
#include "iavf_txrx.h"
#include "iavf_fdir.h"
#include "iavf_adv_rss.h"

#define DEFAULT_DEBUG_LEVEL_SHIFT 3
#define PFX "iavf: "
@@ -303,6 +304,8 @@ struct iavf_adapter {
#define IAVF_FLAG_AQ_DEL_CLOUD_FILTER		BIT(24)
#define IAVF_FLAG_AQ_ADD_FDIR_FILTER		BIT(25)
#define IAVF_FLAG_AQ_DEL_FDIR_FILTER		BIT(26)
#define IAVF_FLAG_AQ_ADD_ADV_RSS_CFG		BIT(27)
#define IAVF_FLAG_AQ_DEL_ADV_RSS_CFG		BIT(28)

	/* OS defined structs */
	struct net_device *netdev;
@@ -345,6 +348,8 @@ struct iavf_adapter {
			      VIRTCHNL_VF_CAP_ADV_LINK_SPEED)
#define FDIR_FLTR_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \
			       VIRTCHNL_VF_OFFLOAD_FDIR_PF)
#define ADV_RSS_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \
			     VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF)
	struct virtchnl_vf_resource *vf_res; /* incl. all VSIs */
	struct virtchnl_vsi_resource *vsi_res; /* our LAN VSI */
	struct virtchnl_version_info pf_version;
@@ -372,6 +377,9 @@ struct iavf_adapter {
	u16 fdir_active_fltr;
	struct list_head fdir_list_head;
	spinlock_t fdir_fltr_lock;	/* protect the Flow Director filter list */

	struct list_head adv_rss_list_head;
	spinlock_t adv_rss_lock;	/* protect the RSS management list */
};


@@ -444,6 +452,8 @@ void iavf_add_cloud_filter(struct iavf_adapter *adapter);
void iavf_del_cloud_filter(struct iavf_adapter *adapter);
void iavf_add_fdir_filter(struct iavf_adapter *adapter);
void iavf_del_fdir_filter(struct iavf_adapter *adapter);
void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter);
void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter);
struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
					const u8 *macaddr);
#endif /* _IAVF_H_ */
+218 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2021, Intel Corporation. */

/* advanced RSS configuration ethtool support for iavf */

#include "iavf.h"

/**
 * iavf_fill_adv_rss_ip4_hdr - fill the IPv4 RSS protocol header
 * @hdr: the virtchnl message protocol header data structure
 * @hash_flds: the RSS configuration protocol hash fields
 */
static void
iavf_fill_adv_rss_ip4_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
{
	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4);

	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV4_SA)
		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC);

	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV4_DA)
		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST);
}

/**
 * iavf_fill_adv_rss_ip6_hdr - fill the IPv6 RSS protocol header
 * @hdr: the virtchnl message protocol header data structure
 * @hash_flds: the RSS configuration protocol hash fields
 */
static void
iavf_fill_adv_rss_ip6_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
{
	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6);

	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV6_SA)
		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC);

	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV6_DA)
		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST);
}

/**
 * iavf_fill_adv_rss_tcp_hdr - fill the TCP RSS protocol header
 * @hdr: the virtchnl message protocol header data structure
 * @hash_flds: the RSS configuration protocol hash fields
 */
static void
iavf_fill_adv_rss_tcp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
{
	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP);

	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT)
		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT);

	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT)
		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT);
}

/**
 * iavf_fill_adv_rss_udp_hdr - fill the UDP RSS protocol header
 * @hdr: the virtchnl message protocol header data structure
 * @hash_flds: the RSS configuration protocol hash fields
 */
static void
iavf_fill_adv_rss_udp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
{
	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP);

	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT)
		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT);

	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT)
		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT);
}

/**
 * iavf_fill_adv_rss_sctp_hdr - fill the SCTP RSS protocol header
 * @hdr: the virtchnl message protocol header data structure
 * @hash_flds: the RSS configuration protocol hash fields
 */
static void
iavf_fill_adv_rss_sctp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
{
	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP);

	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT)
		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT);

	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT)
		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT);
}

/**
 * iavf_fill_adv_rss_cfg_msg - fill the RSS configuration into virtchnl message
 * @rss_cfg: the virtchnl message to be filled with RSS configuration setting
 * @packet_hdrs: the RSS configuration protocol header types
 * @hash_flds: the RSS configuration protocol hash fields
 *
 * Returns 0 if the RSS configuration virtchnl message is filled successfully
 */
int
iavf_fill_adv_rss_cfg_msg(struct virtchnl_rss_cfg *rss_cfg,
			  u32 packet_hdrs, u64 hash_flds)
{
	struct virtchnl_proto_hdrs *proto_hdrs = &rss_cfg->proto_hdrs;
	struct virtchnl_proto_hdr *hdr;

	rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC;

	proto_hdrs->tunnel_level = 0;	/* always outer layer */

	hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
	switch (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_L3) {
	case IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4:
		iavf_fill_adv_rss_ip4_hdr(hdr, hash_flds);
		break;
	case IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6:
		iavf_fill_adv_rss_ip6_hdr(hdr, hash_flds);
		break;
	default:
		return -EINVAL;
	}

	hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
	switch (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_L4) {
	case IAVF_ADV_RSS_FLOW_SEG_HDR_TCP:
		iavf_fill_adv_rss_tcp_hdr(hdr, hash_flds);
		break;
	case IAVF_ADV_RSS_FLOW_SEG_HDR_UDP:
		iavf_fill_adv_rss_udp_hdr(hdr, hash_flds);
		break;
	case IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP:
		iavf_fill_adv_rss_sctp_hdr(hdr, hash_flds);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

/**
 * iavf_find_adv_rss_cfg_by_hdrs - find RSS configuration with header type
 * @adapter: pointer to the VF adapter structure
 * @packet_hdrs: protocol header type to find.
 *
 * Returns pointer to advance RSS configuration if found or null
 */
struct iavf_adv_rss *
iavf_find_adv_rss_cfg_by_hdrs(struct iavf_adapter *adapter, u32 packet_hdrs)
{
	struct iavf_adv_rss *rss;

	list_for_each_entry(rss, &adapter->adv_rss_list_head, list)
		if (rss->packet_hdrs == packet_hdrs)
			return rss;

	return NULL;
}

/**
 * iavf_print_adv_rss_cfg
 * @adapter: pointer to the VF adapter structure
 * @rss: pointer to the advance RSS configuration to print
 * @action: the string description about how to handle the RSS
 * @result: the string description about the virtchnl result
 *
 * Print the advance RSS configuration
 **/
void
iavf_print_adv_rss_cfg(struct iavf_adapter *adapter, struct iavf_adv_rss *rss,
		       const char *action, const char *result)
{
	u32 packet_hdrs = rss->packet_hdrs;
	u64 hash_flds = rss->hash_flds;
	static char hash_opt[300];
	const char *proto;

	if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_TCP)
		proto = "TCP";
	else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_UDP)
		proto = "UDP";
	else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP)
		proto = "SCTP";
	else
		return;

	memset(hash_opt, 0, sizeof(hash_opt));

	strcat(hash_opt, proto);
	if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4)
		strcat(hash_opt, "v4 ");
	else
		strcat(hash_opt, "v6 ");

	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_SA |
			 IAVF_ADV_RSS_HASH_FLD_IPV6_SA))
		strcat(hash_opt, "IP SA,");
	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_DA |
			 IAVF_ADV_RSS_HASH_FLD_IPV6_DA))
		strcat(hash_opt, "IP DA,");
	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT |
			 IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT |
			 IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT))
		strcat(hash_opt, "src port,");
	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT |
			 IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT |
			 IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT))
		strcat(hash_opt, "dst port,");

	if (!action)
		action = "";

	if (!result)
		result = "";

	dev_info(&adapter->pdev->dev, "%s %s %s\n", action, hash_opt, result);
}
+95 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2021, Intel Corporation. */

#ifndef _IAVF_ADV_RSS_H_
#define _IAVF_ADV_RSS_H_

struct iavf_adapter;

/* State of advanced RSS configuration */
enum iavf_adv_rss_state_t {
	IAVF_ADV_RSS_ADD_REQUEST,	/* User requests to add RSS */
	IAVF_ADV_RSS_ADD_PENDING,	/* RSS pending add by the PF */
	IAVF_ADV_RSS_DEL_REQUEST,	/* Driver requests to delete RSS */
	IAVF_ADV_RSS_DEL_PENDING,	/* RSS pending delete by the PF */
	IAVF_ADV_RSS_ACTIVE,		/* RSS configuration is active */
};

enum iavf_adv_rss_flow_seg_hdr {
	IAVF_ADV_RSS_FLOW_SEG_HDR_NONE	= 0x00000000,
	IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4	= 0x00000001,
	IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6	= 0x00000002,
	IAVF_ADV_RSS_FLOW_SEG_HDR_TCP	= 0x00000004,
	IAVF_ADV_RSS_FLOW_SEG_HDR_UDP	= 0x00000008,
	IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP	= 0x00000010,
};

#define IAVF_ADV_RSS_FLOW_SEG_HDR_L3		\
	(IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4	|	\
	 IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6)

#define IAVF_ADV_RSS_FLOW_SEG_HDR_L4		\
	(IAVF_ADV_RSS_FLOW_SEG_HDR_TCP |	\
	 IAVF_ADV_RSS_FLOW_SEG_HDR_UDP |	\
	 IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP)

enum iavf_adv_rss_flow_field {
	/* L3 */
	IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV4_SA,
	IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV4_DA,
	IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV6_SA,
	IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV6_DA,
	/* L4 */
	IAVF_ADV_RSS_FLOW_FIELD_IDX_TCP_SRC_PORT,
	IAVF_ADV_RSS_FLOW_FIELD_IDX_TCP_DST_PORT,
	IAVF_ADV_RSS_FLOW_FIELD_IDX_UDP_SRC_PORT,
	IAVF_ADV_RSS_FLOW_FIELD_IDX_UDP_DST_PORT,
	IAVF_ADV_RSS_FLOW_FIELD_IDX_SCTP_SRC_PORT,
	IAVF_ADV_RSS_FLOW_FIELD_IDX_SCTP_DST_PORT,

	/* The total number of enums must not exceed 64 */
	IAVF_ADV_RSS_FLOW_FIELD_IDX_MAX
};

#define IAVF_ADV_RSS_HASH_INVALID	0
#define IAVF_ADV_RSS_HASH_FLD_IPV4_SA	\
	BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV4_SA)
#define IAVF_ADV_RSS_HASH_FLD_IPV6_SA	\
	BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV6_SA)
#define IAVF_ADV_RSS_HASH_FLD_IPV4_DA	\
	BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV4_DA)
#define IAVF_ADV_RSS_HASH_FLD_IPV6_DA	\
	BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_IPV6_DA)
#define IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT	\
	BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_TCP_SRC_PORT)
#define IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT	\
	BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_TCP_DST_PORT)
#define IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT	\
	BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_UDP_SRC_PORT)
#define IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT	\
	BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_UDP_DST_PORT)
#define IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT	\
	BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_SCTP_SRC_PORT)
#define IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT	\
	BIT_ULL(IAVF_ADV_RSS_FLOW_FIELD_IDX_SCTP_DST_PORT)

/* bookkeeping of advanced RSS configuration */
struct iavf_adv_rss {
	enum iavf_adv_rss_state_t state;
	struct list_head list;

	u32 packet_hdrs;
	u64 hash_flds;

	struct virtchnl_rss_cfg cfg_msg;
};

int
iavf_fill_adv_rss_cfg_msg(struct virtchnl_rss_cfg *rss_cfg,
			  u32 packet_hdrs, u64 hash_flds);
struct iavf_adv_rss *
iavf_find_adv_rss_cfg_by_hdrs(struct iavf_adapter *adapter, u32 packet_hdrs);
void
iavf_print_adv_rss_cfg(struct iavf_adapter *adapter, struct iavf_adv_rss *rss,
		       const char *action, const char *result);
#endif /* _IAVF_ADV_RSS_H_ */
+250 −2
Original line number Diff line number Diff line
@@ -1418,6 +1418,252 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
	return err;
}

/**
 * iavf_adv_rss_parse_hdrs - parses headers from RSS hash input
 * @cmd: ethtool rxnfc command
 *
 * This function parses the rxnfc command and returns intended
 * header types for RSS configuration
 */
static u32 iavf_adv_rss_parse_hdrs(struct ethtool_rxnfc *cmd)
{
	u32 hdrs = IAVF_ADV_RSS_FLOW_SEG_HDR_NONE;

	switch (cmd->flow_type) {
	case TCP_V4_FLOW:
		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_TCP |
			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4;
		break;
	case UDP_V4_FLOW:
		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_UDP |
			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4;
		break;
	case SCTP_V4_FLOW:
		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP |
			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4;
		break;
	case TCP_V6_FLOW:
		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_TCP |
			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6;
		break;
	case UDP_V6_FLOW:
		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_UDP |
			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6;
		break;
	case SCTP_V6_FLOW:
		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP |
			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6;
		break;
	default:
		break;
	}

	return hdrs;
}

/**
 * iavf_adv_rss_parse_hash_flds - parses hash fields from RSS hash input
 * @cmd: ethtool rxnfc command
 *
 * This function parses the rxnfc command and returns intended hash fields for
 * RSS configuration
 */
static u64 iavf_adv_rss_parse_hash_flds(struct ethtool_rxnfc *cmd)
{
	u64 hfld = IAVF_ADV_RSS_HASH_INVALID;

	if (cmd->data & RXH_IP_SRC || cmd->data & RXH_IP_DST) {
		switch (cmd->flow_type) {
		case TCP_V4_FLOW:
		case UDP_V4_FLOW:
		case SCTP_V4_FLOW:
			if (cmd->data & RXH_IP_SRC)
				hfld |= IAVF_ADV_RSS_HASH_FLD_IPV4_SA;
			if (cmd->data & RXH_IP_DST)
				hfld |= IAVF_ADV_RSS_HASH_FLD_IPV4_DA;
			break;
		case TCP_V6_FLOW:
		case UDP_V6_FLOW:
		case SCTP_V6_FLOW:
			if (cmd->data & RXH_IP_SRC)
				hfld |= IAVF_ADV_RSS_HASH_FLD_IPV6_SA;
			if (cmd->data & RXH_IP_DST)
				hfld |= IAVF_ADV_RSS_HASH_FLD_IPV6_DA;
			break;
		default:
			break;
		}
	}

	if (cmd->data & RXH_L4_B_0_1 || cmd->data & RXH_L4_B_2_3) {
		switch (cmd->flow_type) {
		case TCP_V4_FLOW:
		case TCP_V6_FLOW:
			if (cmd->data & RXH_L4_B_0_1)
				hfld |= IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT;
			if (cmd->data & RXH_L4_B_2_3)
				hfld |= IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT;
			break;
		case UDP_V4_FLOW:
		case UDP_V6_FLOW:
			if (cmd->data & RXH_L4_B_0_1)
				hfld |= IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT;
			if (cmd->data & RXH_L4_B_2_3)
				hfld |= IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT;
			break;
		case SCTP_V4_FLOW:
		case SCTP_V6_FLOW:
			if (cmd->data & RXH_L4_B_0_1)
				hfld |= IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT;
			if (cmd->data & RXH_L4_B_2_3)
				hfld |= IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT;
			break;
		default:
			break;
		}
	}

	return hfld;
}

/**
 * iavf_set_adv_rss_hash_opt - Enable/Disable flow types for RSS hash
 * @adapter: pointer to the VF adapter structure
 * @cmd: ethtool rxnfc command
 *
 * Returns Success if the flow input set is supported.
 */
static int
iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter,
			  struct ethtool_rxnfc *cmd)
{
	struct iavf_adv_rss *rss_old, *rss_new;
	bool rss_new_add = false;
	int count = 50, err = 0;
	u64 hash_flds;
	u32 hdrs;

	if (!ADV_RSS_SUPPORT(adapter))
		return -EOPNOTSUPP;

	hdrs = iavf_adv_rss_parse_hdrs(cmd);
	if (hdrs == IAVF_ADV_RSS_FLOW_SEG_HDR_NONE)
		return -EINVAL;

	hash_flds = iavf_adv_rss_parse_hash_flds(cmd);
	if (hash_flds == IAVF_ADV_RSS_HASH_INVALID)
		return -EINVAL;

	rss_new = kzalloc(sizeof(*rss_new), GFP_KERNEL);
	if (!rss_new)
		return -ENOMEM;

	if (iavf_fill_adv_rss_cfg_msg(&rss_new->cfg_msg, hdrs, hash_flds)) {
		kfree(rss_new);
		return -EINVAL;
	}

	while (test_and_set_bit(__IAVF_IN_CRITICAL_TASK,
				&adapter->crit_section)) {
		if (--count == 0) {
			kfree(rss_new);
			return -EINVAL;
		}

		udelay(1);
	}

	spin_lock_bh(&adapter->adv_rss_lock);
	rss_old = iavf_find_adv_rss_cfg_by_hdrs(adapter, hdrs);
	if (rss_old) {
		if (rss_old->state != IAVF_ADV_RSS_ACTIVE) {
			err = -EBUSY;
		} else if (rss_old->hash_flds != hash_flds) {
			rss_old->state = IAVF_ADV_RSS_ADD_REQUEST;
			rss_old->hash_flds = hash_flds;
			memcpy(&rss_old->cfg_msg, &rss_new->cfg_msg,
			       sizeof(rss_new->cfg_msg));
			adapter->aq_required |= IAVF_FLAG_AQ_ADD_ADV_RSS_CFG;
		} else {
			err = -EEXIST;
		}
	} else {
		rss_new_add = true;
		rss_new->state = IAVF_ADV_RSS_ADD_REQUEST;
		rss_new->packet_hdrs = hdrs;
		rss_new->hash_flds = hash_flds;
		list_add_tail(&rss_new->list, &adapter->adv_rss_list_head);
		adapter->aq_required |= IAVF_FLAG_AQ_ADD_ADV_RSS_CFG;
	}
	spin_unlock_bh(&adapter->adv_rss_lock);

	if (!err)
		mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);

	clear_bit(__IAVF_IN_CRITICAL_TASK, &adapter->crit_section);

	if (!rss_new_add)
		kfree(rss_new);

	return err;
}

/**
 * iavf_get_adv_rss_hash_opt - Retrieve hash fields for a given flow-type
 * @adapter: pointer to the VF adapter structure
 * @cmd: ethtool rxnfc command
 *
 * Returns Success if the flow input set is supported.
 */
static int
iavf_get_adv_rss_hash_opt(struct iavf_adapter *adapter,
			  struct ethtool_rxnfc *cmd)
{
	struct iavf_adv_rss *rss;
	u64 hash_flds;
	u32 hdrs;

	if (!ADV_RSS_SUPPORT(adapter))
		return -EOPNOTSUPP;

	cmd->data = 0;

	hdrs = iavf_adv_rss_parse_hdrs(cmd);
	if (hdrs == IAVF_ADV_RSS_FLOW_SEG_HDR_NONE)
		return -EINVAL;

	spin_lock_bh(&adapter->adv_rss_lock);
	rss = iavf_find_adv_rss_cfg_by_hdrs(adapter, hdrs);
	if (rss)
		hash_flds = rss->hash_flds;
	else
		hash_flds = IAVF_ADV_RSS_HASH_INVALID;
	spin_unlock_bh(&adapter->adv_rss_lock);

	if (hash_flds == IAVF_ADV_RSS_HASH_INVALID)
		return -EINVAL;

	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_SA |
			 IAVF_ADV_RSS_HASH_FLD_IPV6_SA))
		cmd->data |= (u64)RXH_IP_SRC;

	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_DA |
			 IAVF_ADV_RSS_HASH_FLD_IPV6_DA))
		cmd->data |= (u64)RXH_IP_DST;

	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT |
			 IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT |
			 IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT))
		cmd->data |= (u64)RXH_L4_B_0_1;

	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT |
			 IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT |
			 IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT))
		cmd->data |= (u64)RXH_L4_B_2_3;

	return 0;
}

/**
 * iavf_set_rxnfc - command to set Rx flow rules.
 * @netdev: network interface device structure
@@ -1437,6 +1683,9 @@ static int iavf_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
	case ETHTOOL_SRXCLSRLDEL:
		ret = iavf_del_fdir_ethtool(adapter, cmd);
		break;
	case ETHTOOL_SRXFH:
		ret = iavf_set_adv_rss_hash_opt(adapter, cmd);
		break;
	default:
		break;
	}
@@ -1477,8 +1726,7 @@ static int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
		ret = iavf_get_fdir_fltr_ids(adapter, cmd, (u32 *)rule_locs);
		break;
	case ETHTOOL_GRXFH:
		netdev_info(netdev,
			    "RSS hash info is not available to vf, use pf.\n");
		ret = iavf_get_adv_rss_hash_opt(adapter, cmd);
		break;
	default:
		break;
Loading