Files
linux/drivers/net/ethernet/intel/ice/virt/rss.c
Linus Torvalds bf4afc53b7 Convert 'alloc_obj' family to use the new default GFP_KERNEL argument
This was done entirely with mindless brute force, using

    git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
        xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'

to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.

Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.

For the same reason the 'flex' versions will be done as a separate
conversion.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-02-21 17:09:51 -08:00

1923 lines
58 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2022, Intel Corporation. */
#include "rss.h"
#include "ice_vf_lib_private.h"
#include "ice.h"
#define FIELD_SELECTOR(proto_hdr_field) \
BIT((proto_hdr_field) & PROTO_HDR_FIELD_MASK)
struct ice_vc_hdr_match_type {
u32 vc_hdr; /* virtchnl headers (VIRTCHNL_PROTO_HDR_XXX) */
u32 ice_hdr; /* ice headers (ICE_FLOW_SEG_HDR_XXX) */
};
static const struct ice_vc_hdr_match_type ice_vc_hdr_list[] = {
{VIRTCHNL_PROTO_HDR_NONE, ICE_FLOW_SEG_HDR_NONE},
{VIRTCHNL_PROTO_HDR_ETH, ICE_FLOW_SEG_HDR_ETH},
{VIRTCHNL_PROTO_HDR_S_VLAN, ICE_FLOW_SEG_HDR_VLAN},
{VIRTCHNL_PROTO_HDR_C_VLAN, ICE_FLOW_SEG_HDR_VLAN},
{VIRTCHNL_PROTO_HDR_IPV4, ICE_FLOW_SEG_HDR_IPV4 |
ICE_FLOW_SEG_HDR_IPV_OTHER},
{VIRTCHNL_PROTO_HDR_IPV6, ICE_FLOW_SEG_HDR_IPV6 |
ICE_FLOW_SEG_HDR_IPV_OTHER},
{VIRTCHNL_PROTO_HDR_TCP, ICE_FLOW_SEG_HDR_TCP},
{VIRTCHNL_PROTO_HDR_UDP, ICE_FLOW_SEG_HDR_UDP},
{VIRTCHNL_PROTO_HDR_SCTP, ICE_FLOW_SEG_HDR_SCTP},
{VIRTCHNL_PROTO_HDR_PPPOE, ICE_FLOW_SEG_HDR_PPPOE},
{VIRTCHNL_PROTO_HDR_GTPU_IP, ICE_FLOW_SEG_HDR_GTPU_IP},
{VIRTCHNL_PROTO_HDR_GTPU_EH, ICE_FLOW_SEG_HDR_GTPU_EH},
{VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_DWN,
ICE_FLOW_SEG_HDR_GTPU_DWN},
{VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_UP,
ICE_FLOW_SEG_HDR_GTPU_UP},
{VIRTCHNL_PROTO_HDR_L2TPV3, ICE_FLOW_SEG_HDR_L2TPV3},
{VIRTCHNL_PROTO_HDR_ESP, ICE_FLOW_SEG_HDR_ESP},
{VIRTCHNL_PROTO_HDR_AH, ICE_FLOW_SEG_HDR_AH},
{VIRTCHNL_PROTO_HDR_PFCP, ICE_FLOW_SEG_HDR_PFCP_SESSION},
{VIRTCHNL_PROTO_HDR_GTPC, ICE_FLOW_SEG_HDR_GTPC},
{VIRTCHNL_PROTO_HDR_L2TPV2, ICE_FLOW_SEG_HDR_L2TPV2},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG, ICE_FLOW_SEG_HDR_IPV_FRAG},
{VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG, ICE_FLOW_SEG_HDR_IPV_FRAG},
{VIRTCHNL_PROTO_HDR_GRE, ICE_FLOW_SEG_HDR_GRE},
};
struct ice_vc_hash_field_match_type {
u32 vc_hdr; /* virtchnl headers
* (VIRTCHNL_PROTO_HDR_XXX)
*/
u32 vc_hash_field; /* virtchnl hash fields selector
* FIELD_SELECTOR((VIRTCHNL_PROTO_HDR_ETH_XXX))
*/
u64 ice_hash_field; /* ice hash fields
* (BIT_ULL(ICE_FLOW_FIELD_IDX_XXX))
*/
};
static const struct
ice_vc_hash_field_match_type ice_vc_hash_field_list[] = {
{VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_SRC),
BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_SA)},
{VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_DST),
BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_DA)},
{VIRTCHNL_PROTO_HDR_ETH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_DST),
ICE_FLOW_HASH_ETH},
{VIRTCHNL_PROTO_HDR_ETH,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ETH_ETHERTYPE),
BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_TYPE)},
{VIRTCHNL_PROTO_HDR_S_VLAN,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_S_VLAN_ID),
BIT_ULL(ICE_FLOW_FIELD_IDX_S_VLAN)},
{VIRTCHNL_PROTO_HDR_C_VLAN,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_C_VLAN_ID),
BIT_ULL(ICE_FLOW_FIELD_IDX_C_VLAN)},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA)},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA)},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST),
ICE_FLOW_HASH_IPV4},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
ICE_FLOW_HASH_IPV4 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
{VIRTCHNL_PROTO_HDR_IPV4,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_FRAG_PKID),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_ID)},
{VIRTCHNL_PROTO_HDR_IPV4,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
ICE_FLOW_HASH_IPV4 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
ICE_FLOW_HASH_IPV4 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST),
ICE_FLOW_HASH_IPV4},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
ICE_FLOW_HASH_IPV4 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_FRAG_PKID),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_ID)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
ICE_FLOW_HASH_IPV4 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
ICE_FLOW_HASH_IPV4 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV4_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_PROT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV4_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_PROT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM)},
{VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA)},
{VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA)},
{VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST),
ICE_FLOW_HASH_IPV6},
{VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
{VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
{VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT),
ICE_FLOW_HASH_IPV6 | BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
{VIRTCHNL_PROTO_HDR_IPV6, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
{VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG_PKID),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_ID)},
{VIRTCHNL_PROTO_HDR_IPV6,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_DST),
ICE_FLOW_HASH_IPV6_PRE64},
{VIRTCHNL_PROTO_HDR_IPV6,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_SRC),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_SA)},
{VIRTCHNL_PROTO_HDR_IPV6,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_DST),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_DA)},
{VIRTCHNL_PROTO_HDR_IPV6,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT),
ICE_FLOW_HASH_IPV6_PRE64 |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
{VIRTCHNL_PROTO_HDR_IPV6,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_SRC) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_SA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
{VIRTCHNL_PROTO_HDR_IPV6,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PREFIX64_DST) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_IPV6_PROT),
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_DA) |
BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PROT)},
{VIRTCHNL_PROTO_HDR_TCP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT),
BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT)},
{VIRTCHNL_PROTO_HDR_TCP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT),
BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT)},
{VIRTCHNL_PROTO_HDR_TCP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT),
ICE_FLOW_HASH_TCP_PORT},
{VIRTCHNL_PROTO_HDR_TCP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_TCP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_TCP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_TCP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_SRC_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_DST_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_TCP_CHKSUM),
ICE_FLOW_HASH_TCP_PORT |
BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_UDP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT),
BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT)},
{VIRTCHNL_PROTO_HDR_UDP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT),
BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT)},
{VIRTCHNL_PROTO_HDR_UDP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT),
ICE_FLOW_HASH_UDP_PORT},
{VIRTCHNL_PROTO_HDR_UDP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_UDP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_UDP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_UDP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_SRC_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_DST_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_UDP_CHKSUM),
ICE_FLOW_HASH_UDP_PORT |
BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_SCTP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT),
BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT)},
{VIRTCHNL_PROTO_HDR_SCTP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT),
BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT)},
{VIRTCHNL_PROTO_HDR_SCTP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT),
ICE_FLOW_HASH_SCTP_PORT},
{VIRTCHNL_PROTO_HDR_SCTP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_SCTP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_SCTP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_CHKSUM),
BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT) |
BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_SCTP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_DST_PORT) |
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_SCTP_CHKSUM),
ICE_FLOW_HASH_SCTP_PORT |
BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_CHKSUM)},
{VIRTCHNL_PROTO_HDR_PPPOE,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_PPPOE_SESS_ID),
BIT_ULL(ICE_FLOW_FIELD_IDX_PPPOE_SESS_ID)},
{VIRTCHNL_PROTO_HDR_GTPU_IP,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_GTPU_IP_TEID),
BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_IP_TEID)},
{VIRTCHNL_PROTO_HDR_L2TPV3,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_L2TPV3_SESS_ID),
BIT_ULL(ICE_FLOW_FIELD_IDX_L2TPV3_SESS_ID)},
{VIRTCHNL_PROTO_HDR_ESP, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_ESP_SPI),
BIT_ULL(ICE_FLOW_FIELD_IDX_ESP_SPI)},
{VIRTCHNL_PROTO_HDR_AH, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_AH_SPI),
BIT_ULL(ICE_FLOW_FIELD_IDX_AH_SPI)},
{VIRTCHNL_PROTO_HDR_PFCP, FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_PFCP_SEID),
BIT_ULL(ICE_FLOW_FIELD_IDX_PFCP_SEID)},
{VIRTCHNL_PROTO_HDR_GTPC,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_GTPC_TEID),
BIT_ULL(ICE_FLOW_FIELD_IDX_GTPC_TEID)},
{VIRTCHNL_PROTO_HDR_L2TPV2,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_L2TPV2_SESS_ID),
BIT_ULL(ICE_FLOW_FIELD_IDX_L2TPV2_SESS_ID)},
{VIRTCHNL_PROTO_HDR_L2TPV2,
FIELD_SELECTOR(VIRTCHNL_PROTO_HDR_L2TPV2_LEN_SESS_ID),
BIT_ULL(ICE_FLOW_FIELD_IDX_L2TPV2_LEN_SESS_ID)},
};
static int
ice_vc_rss_hash_update(struct ice_hw *hw, struct ice_vsi *vsi, u8 hash_type)
{
struct ice_vsi_ctx *ctx;
int ret;
ctx = kzalloc_obj(*ctx);
if (!ctx)
return -ENOMEM;
/* clear previous hash_type */
ctx->info.q_opt_rss = vsi->info.q_opt_rss &
~ICE_AQ_VSI_Q_OPT_RSS_HASH_M;
/* hash_type is passed in as ICE_AQ_VSI_Q_OPT_RSS_<XOR|TPLZ|SYM_TPLZ */
ctx->info.q_opt_rss |= FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M,
hash_type);
/* Preserve existing queueing option setting */
ctx->info.q_opt_tc = vsi->info.q_opt_tc;
ctx->info.q_opt_flags = vsi->info.q_opt_flags;
ctx->info.valid_sections =
cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID);
ret = ice_update_vsi(hw, vsi->idx, ctx, NULL);
if (ret) {
dev_err(ice_hw_to_dev(hw), "update VSI for RSS failed, err %d aq_err %s\n",
ret, libie_aq_str(hw->adminq.sq_last_status));
} else {
vsi->info.q_opt_rss = ctx->info.q_opt_rss;
}
kfree(ctx);
return ret;
}
/**
* ice_vc_validate_pattern
* @vf: pointer to the VF info
* @proto: virtchnl protocol headers
*
* validate the pattern is supported or not.
*
* Return: true on success, false on error.
*/
bool
ice_vc_validate_pattern(struct ice_vf *vf, struct virtchnl_proto_hdrs *proto)
{
bool is_ipv4 = false;
bool is_ipv6 = false;
bool is_udp = false;
u16 ptype = -1;
int i = 0;
while (i < proto->count &&
proto->proto_hdr[i].type != VIRTCHNL_PROTO_HDR_NONE) {
switch (proto->proto_hdr[i].type) {
case VIRTCHNL_PROTO_HDR_ETH:
ptype = ICE_PTYPE_MAC_PAY;
break;
case VIRTCHNL_PROTO_HDR_IPV4:
ptype = ICE_PTYPE_IPV4_PAY;
is_ipv4 = true;
break;
case VIRTCHNL_PROTO_HDR_IPV6:
ptype = ICE_PTYPE_IPV6_PAY;
is_ipv6 = true;
break;
case VIRTCHNL_PROTO_HDR_UDP:
if (is_ipv4)
ptype = ICE_PTYPE_IPV4_UDP_PAY;
else if (is_ipv6)
ptype = ICE_PTYPE_IPV6_UDP_PAY;
is_udp = true;
break;
case VIRTCHNL_PROTO_HDR_TCP:
if (is_ipv4)
ptype = ICE_PTYPE_IPV4_TCP_PAY;
else if (is_ipv6)
ptype = ICE_PTYPE_IPV6_TCP_PAY;
break;
case VIRTCHNL_PROTO_HDR_SCTP:
if (is_ipv4)
ptype = ICE_PTYPE_IPV4_SCTP_PAY;
else if (is_ipv6)
ptype = ICE_PTYPE_IPV6_SCTP_PAY;
break;
case VIRTCHNL_PROTO_HDR_GTPU_IP:
case VIRTCHNL_PROTO_HDR_GTPU_EH:
if (is_ipv4)
ptype = ICE_MAC_IPV4_GTPU;
else if (is_ipv6)
ptype = ICE_MAC_IPV6_GTPU;
goto out;
case VIRTCHNL_PROTO_HDR_L2TPV3:
if (is_ipv4)
ptype = ICE_MAC_IPV4_L2TPV3;
else if (is_ipv6)
ptype = ICE_MAC_IPV6_L2TPV3;
goto out;
case VIRTCHNL_PROTO_HDR_ESP:
if (is_ipv4)
ptype = is_udp ? ICE_MAC_IPV4_NAT_T_ESP :
ICE_MAC_IPV4_ESP;
else if (is_ipv6)
ptype = is_udp ? ICE_MAC_IPV6_NAT_T_ESP :
ICE_MAC_IPV6_ESP;
goto out;
case VIRTCHNL_PROTO_HDR_AH:
if (is_ipv4)
ptype = ICE_MAC_IPV4_AH;
else if (is_ipv6)
ptype = ICE_MAC_IPV6_AH;
goto out;
case VIRTCHNL_PROTO_HDR_PFCP:
if (is_ipv4)
ptype = ICE_MAC_IPV4_PFCP_SESSION;
else if (is_ipv6)
ptype = ICE_MAC_IPV6_PFCP_SESSION;
goto out;
default:
break;
}
i++;
}
out:
return ice_hw_ptype_ena(&vf->pf->hw, ptype);
}
/**
* ice_vc_parse_rss_cfg - parses hash fields and headers from
* a specific virtchnl RSS cfg
* @hw: pointer to the hardware
* @rss_cfg: pointer to the virtchnl RSS cfg
* @hash_cfg: pointer to the HW hash configuration
*
* Return true if all the protocol header and hash fields in the RSS cfg could
* be parsed, else return false
*
* This function parses the virtchnl RSS cfg to be the intended
* hash fields and the intended header for RSS configuration
*/
static bool ice_vc_parse_rss_cfg(struct ice_hw *hw,
struct virtchnl_rss_cfg *rss_cfg,
struct ice_rss_hash_cfg *hash_cfg)
{
const struct ice_vc_hash_field_match_type *hf_list;
const struct ice_vc_hdr_match_type *hdr_list;
int i, hf_list_len, hdr_list_len;
bool outer_ipv4 = false;
bool outer_ipv6 = false;
bool inner_hdr = false;
bool has_gre = false;
u32 *addl_hdrs = &hash_cfg->addl_hdrs;
u64 *hash_flds = &hash_cfg->hash_flds;
/* set outer layer RSS as default */
hash_cfg->hdr_type = ICE_RSS_OUTER_HEADERS;
if (rss_cfg->rss_algorithm == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC)
hash_cfg->symm = true;
else
hash_cfg->symm = false;
hf_list = ice_vc_hash_field_list;
hf_list_len = ARRAY_SIZE(ice_vc_hash_field_list);
hdr_list = ice_vc_hdr_list;
hdr_list_len = ARRAY_SIZE(ice_vc_hdr_list);
for (i = 0; i < rss_cfg->proto_hdrs.count; i++) {
struct virtchnl_proto_hdr *proto_hdr =
&rss_cfg->proto_hdrs.proto_hdr[i];
u32 hdr_found = 0;
int j;
/* Find matched ice headers according to virtchnl headers.
* Also figure out the outer type of GTPU headers.
*/
for (j = 0; j < hdr_list_len; j++) {
struct ice_vc_hdr_match_type hdr_map = hdr_list[j];
if (proto_hdr->type == hdr_map.vc_hdr)
hdr_found = hdr_map.ice_hdr;
}
if (!hdr_found)
return false;
/* Find matched ice hash fields according to
* virtchnl hash fields.
*/
for (j = 0; j < hf_list_len; j++) {
struct ice_vc_hash_field_match_type hf_map = hf_list[j];
if (proto_hdr->type == hf_map.vc_hdr &&
proto_hdr->field_selector == hf_map.vc_hash_field) {
*hash_flds |= hf_map.ice_hash_field;
break;
}
}
if (proto_hdr->type == VIRTCHNL_PROTO_HDR_IPV4 && !inner_hdr)
outer_ipv4 = true;
else if (proto_hdr->type == VIRTCHNL_PROTO_HDR_IPV6 &&
!inner_hdr)
outer_ipv6 = true;
/* for GRE and L2TPv2, take inner header as input set if no
* any field is selected from outer headers.
* for GTPU, take inner header and GTPU teid as input set.
*/
else if ((proto_hdr->type == VIRTCHNL_PROTO_HDR_GTPU_IP ||
proto_hdr->type == VIRTCHNL_PROTO_HDR_GTPU_EH ||
proto_hdr->type == VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_DWN ||
proto_hdr->type ==
VIRTCHNL_PROTO_HDR_GTPU_EH_PDU_UP) ||
((proto_hdr->type == VIRTCHNL_PROTO_HDR_L2TPV2 ||
proto_hdr->type == VIRTCHNL_PROTO_HDR_GRE) &&
*hash_flds == 0)) {
/* set inner_hdr flag, and clean up outer header */
inner_hdr = true;
/* clear outer headers */
*addl_hdrs = 0;
if (outer_ipv4 && outer_ipv6)
return false;
if (outer_ipv4)
hash_cfg->hdr_type = ICE_RSS_INNER_HEADERS_W_OUTER_IPV4;
else if (outer_ipv6)
hash_cfg->hdr_type = ICE_RSS_INNER_HEADERS_W_OUTER_IPV6;
else
hash_cfg->hdr_type = ICE_RSS_INNER_HEADERS;
if (has_gre && outer_ipv4)
hash_cfg->hdr_type =
ICE_RSS_INNER_HEADERS_W_OUTER_IPV4_GRE;
if (has_gre && outer_ipv6)
hash_cfg->hdr_type =
ICE_RSS_INNER_HEADERS_W_OUTER_IPV6_GRE;
if (proto_hdr->type == VIRTCHNL_PROTO_HDR_GRE)
has_gre = true;
}
*addl_hdrs |= hdr_found;
/* refine hash hdrs and fields for IP fragment */
if (VIRTCHNL_TEST_PROTO_HDR_FIELD(proto_hdr,
VIRTCHNL_PROTO_HDR_IPV4_FRAG_PKID) &&
proto_hdr->type == VIRTCHNL_PROTO_HDR_IPV4_FRAG) {
*addl_hdrs |= ICE_FLOW_SEG_HDR_IPV_FRAG;
*addl_hdrs &= ~(ICE_FLOW_SEG_HDR_IPV_OTHER);
*hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_ID);
VIRTCHNL_DEL_PROTO_HDR_FIELD(proto_hdr,
VIRTCHNL_PROTO_HDR_IPV4_FRAG_PKID);
}
if (VIRTCHNL_TEST_PROTO_HDR_FIELD(proto_hdr,
VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG_PKID) &&
proto_hdr->type == VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG) {
*addl_hdrs |= ICE_FLOW_SEG_HDR_IPV_FRAG;
*addl_hdrs &= ~(ICE_FLOW_SEG_HDR_IPV_OTHER);
*hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_ID);
VIRTCHNL_DEL_PROTO_HDR_FIELD(proto_hdr,
VIRTCHNL_PROTO_HDR_IPV6_EH_FRAG_PKID);
}
}
/* refine gtpu header if we take outer as input set for a no inner
* ip gtpu flow.
*/
if (hash_cfg->hdr_type == ICE_RSS_OUTER_HEADERS &&
*addl_hdrs & ICE_FLOW_SEG_HDR_GTPU_IP) {
*addl_hdrs &= ~(ICE_FLOW_SEG_HDR_GTPU_IP);
*addl_hdrs |= ICE_FLOW_SEG_HDR_GTPU_NON_IP;
}
/* refine hash field for esp and nat-t-esp. */
if ((*addl_hdrs & ICE_FLOW_SEG_HDR_UDP) &&
(*addl_hdrs & ICE_FLOW_SEG_HDR_ESP)) {
*addl_hdrs &= ~(ICE_FLOW_SEG_HDR_ESP | ICE_FLOW_SEG_HDR_UDP);
*addl_hdrs |= ICE_FLOW_SEG_HDR_NAT_T_ESP;
*hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_ESP_SPI));
*hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_NAT_T_ESP_SPI);
}
/* refine hash hdrs for L4 udp/tcp/sctp. */
if (*addl_hdrs & (ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP |
ICE_FLOW_SEG_HDR_SCTP) &&
*addl_hdrs & ICE_FLOW_SEG_HDR_IPV_OTHER)
*addl_hdrs &= ~ICE_FLOW_SEG_HDR_IPV_OTHER;
return true;
}
/**
* ice_vf_adv_rss_offload_ena - determine if capabilities support advanced
* RSS offloads
* @caps: VF driver negotiated capabilities
*
* Return true if VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF capability is set,
* else return false
*/
static bool ice_vf_adv_rss_offload_ena(u32 caps)
{
return !!(caps & VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF);
}
/**
* ice_is_hash_cfg_valid - Check whether an RSS hash context is valid
* @cfg: RSS hash configuration to test
*
* Return: true if both @cfg->hash_flds and @cfg->addl_hdrs are non-zero; false otherwise.
*/
static bool ice_is_hash_cfg_valid(struct ice_rss_hash_cfg *cfg)
{
return cfg->hash_flds && cfg->addl_hdrs;
}
/**
* ice_hash_cfg_reset - Reset an RSS hash context
* @cfg: RSS hash configuration to reset
*
* Reset fields of @cfg that store the active rule information.
*/
static void ice_hash_cfg_reset(struct ice_rss_hash_cfg *cfg)
{
cfg->hash_flds = 0;
cfg->addl_hdrs = 0;
cfg->hdr_type = ICE_RSS_OUTER_HEADERS;
cfg->symm = 0;
}
/**
* ice_hash_cfg_record - Record an RSS hash context
* @ctx: destination (global) RSS hash configuration
* @cfg: source RSS hash configuration to record
*
* Copy the active rule information from @cfg into @ctx.
*/
static void ice_hash_cfg_record(struct ice_rss_hash_cfg *ctx,
struct ice_rss_hash_cfg *cfg)
{
ctx->hash_flds = cfg->hash_flds;
ctx->addl_hdrs = cfg->addl_hdrs;
ctx->hdr_type = cfg->hdr_type;
ctx->symm = cfg->symm;
}
/**
* ice_hash_moveout - Delete an RSS configuration (keep context)
* @vf: VF pointer
* @cfg: RSS hash configuration
*
* Return: 0 on success (including when already absent); -ENOENT if @cfg is
* invalid or VSI is missing; -EBUSY on hardware removal failure.
*/
static int
ice_hash_moveout(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
{
struct device *dev = ice_pf_to_dev(vf->pf);
struct ice_vsi *vsi = ice_get_vf_vsi(vf);
struct ice_hw *hw = &vf->pf->hw;
int ret;
if (!ice_is_hash_cfg_valid(cfg) || !vsi)
return -ENOENT;
ret = ice_rem_rss_cfg(hw, vsi->idx, cfg);
if (ret && ret != -ENOENT) {
dev_err(dev, "ice_rem_rss_cfg failed for VF %d, VSI %d, error:%d\n",
vf->vf_id, vf->lan_vsi_idx, ret);
return -EBUSY;
}
return 0;
}
/**
* ice_hash_moveback - Add an RSS hash configuration for a VF
* @vf: VF pointer
* @cfg: RSS hash configuration to apply
*
* Add @cfg to @vf if the context is valid and VSI exists; programs HW.
*
* Return:
* * 0 on success
* * -ENOENT if @cfg is invalid or VSI is missing
* * -EBUSY if hardware programming fails
*/
static int
ice_hash_moveback(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
{
struct device *dev = ice_pf_to_dev(vf->pf);
struct ice_vsi *vsi = ice_get_vf_vsi(vf);
struct ice_hw *hw = &vf->pf->hw;
int ret;
if (!ice_is_hash_cfg_valid(cfg) || !vsi)
return -ENOENT;
ret = ice_add_rss_cfg(hw, vsi, cfg);
if (ret) {
dev_err(dev, "ice_add_rss_cfg failed for VF %d, VSI %d, error:%d\n",
vf->vf_id, vf->lan_vsi_idx, ret);
return -EBUSY;
}
return 0;
}
/**
* ice_hash_remove - remove a RSS configuration
* @vf: pointer to the VF info
* @cfg: pointer to the RSS hash configuration
*
* This function will delete a RSS hash configuration and also delete the
* hash context which stores the rule info.
*
* Return: 0 on success, or a negative error code on failure.
*/
static int
ice_hash_remove(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
{
int ret;
ret = ice_hash_moveout(vf, cfg);
if (ret && ret != -ENOENT)
return ret;
ice_hash_cfg_reset(cfg);
return 0;
}
struct ice_gtpu_ctx_action {
u32 ctx_idx;
const u32 *remove_list;
int remove_count;
const u32 *moveout_list;
int moveout_count;
};
/**
* ice_add_rss_cfg_pre_gtpu - Pre-process the GTPU RSS configuration
* @vf: pointer to the VF info
* @ctx: pointer to the context of the GTPU hash
* @ctx_idx: index of the hash context
*
* Pre-processes the GTPU hash configuration before adding a new
* hash context. It removes or reorders existing hash configurations that may
* conflict with the new one. For example, if a GTPU_UP or GTPU_DWN rule is
* configured after a GTPU_EH rule, the GTPU_EH hash will be matched first due
* to TCAM write and match order (top-down). In such cases, the GTPU_EH rule
* must be moved after the GTPU_UP/DWN rule. Conversely, if a GTPU_EH rule is
* configured after a GTPU_UP/DWN rule, the UP/DWN rules should be removed to
* avoid conflict.
*
* Return: 0 on success or a negative error code on failure
*/
static int ice_add_rss_cfg_pre_gtpu(struct ice_vf *vf,
struct ice_vf_hash_gtpu_ctx *ctx,
u32 ctx_idx)
{
int ret, i;
static const u32 remove_eh_ip[] = {
ICE_HASH_GTPU_CTX_EH_IP_UDP, ICE_HASH_GTPU_CTX_EH_IP_TCP,
ICE_HASH_GTPU_CTX_UP_IP, ICE_HASH_GTPU_CTX_UP_IP_UDP,
ICE_HASH_GTPU_CTX_UP_IP_TCP, ICE_HASH_GTPU_CTX_DW_IP,
ICE_HASH_GTPU_CTX_DW_IP_UDP, ICE_HASH_GTPU_CTX_DW_IP_TCP,
};
static const u32 remove_eh_ip_udp[] = {
ICE_HASH_GTPU_CTX_UP_IP_UDP,
ICE_HASH_GTPU_CTX_DW_IP_UDP,
};
static const u32 moveout_eh_ip_udp[] = {
ICE_HASH_GTPU_CTX_UP_IP,
ICE_HASH_GTPU_CTX_UP_IP_TCP,
ICE_HASH_GTPU_CTX_DW_IP,
ICE_HASH_GTPU_CTX_DW_IP_TCP,
};
static const u32 remove_eh_ip_tcp[] = {
ICE_HASH_GTPU_CTX_UP_IP_TCP,
ICE_HASH_GTPU_CTX_DW_IP_TCP,
};
static const u32 moveout_eh_ip_tcp[] = {
ICE_HASH_GTPU_CTX_UP_IP,
ICE_HASH_GTPU_CTX_UP_IP_UDP,
ICE_HASH_GTPU_CTX_DW_IP,
ICE_HASH_GTPU_CTX_DW_IP_UDP,
};
static const u32 remove_up_ip[] = {
ICE_HASH_GTPU_CTX_UP_IP_UDP,
ICE_HASH_GTPU_CTX_UP_IP_TCP,
};
static const u32 moveout_up_ip[] = {
ICE_HASH_GTPU_CTX_EH_IP,
ICE_HASH_GTPU_CTX_EH_IP_UDP,
ICE_HASH_GTPU_CTX_EH_IP_TCP,
};
static const u32 moveout_up_ip_udp_tcp[] = {
ICE_HASH_GTPU_CTX_EH_IP,
ICE_HASH_GTPU_CTX_EH_IP_UDP,
ICE_HASH_GTPU_CTX_EH_IP_TCP,
};
static const u32 remove_dw_ip[] = {
ICE_HASH_GTPU_CTX_DW_IP_UDP,
ICE_HASH_GTPU_CTX_DW_IP_TCP,
};
static const u32 moveout_dw_ip[] = {
ICE_HASH_GTPU_CTX_EH_IP,
ICE_HASH_GTPU_CTX_EH_IP_UDP,
ICE_HASH_GTPU_CTX_EH_IP_TCP,
};
static const struct ice_gtpu_ctx_action actions[] = {
{ ICE_HASH_GTPU_CTX_EH_IP, remove_eh_ip,
ARRAY_SIZE(remove_eh_ip), NULL, 0 },
{ ICE_HASH_GTPU_CTX_EH_IP_UDP, remove_eh_ip_udp,
ARRAY_SIZE(remove_eh_ip_udp), moveout_eh_ip_udp,
ARRAY_SIZE(moveout_eh_ip_udp) },
{ ICE_HASH_GTPU_CTX_EH_IP_TCP, remove_eh_ip_tcp,
ARRAY_SIZE(remove_eh_ip_tcp), moveout_eh_ip_tcp,
ARRAY_SIZE(moveout_eh_ip_tcp) },
{ ICE_HASH_GTPU_CTX_UP_IP, remove_up_ip,
ARRAY_SIZE(remove_up_ip), moveout_up_ip,
ARRAY_SIZE(moveout_up_ip) },
{ ICE_HASH_GTPU_CTX_UP_IP_UDP, NULL, 0, moveout_up_ip_udp_tcp,
ARRAY_SIZE(moveout_up_ip_udp_tcp) },
{ ICE_HASH_GTPU_CTX_UP_IP_TCP, NULL, 0, moveout_up_ip_udp_tcp,
ARRAY_SIZE(moveout_up_ip_udp_tcp) },
{ ICE_HASH_GTPU_CTX_DW_IP, remove_dw_ip,
ARRAY_SIZE(remove_dw_ip), moveout_dw_ip,
ARRAY_SIZE(moveout_dw_ip) },
{ ICE_HASH_GTPU_CTX_DW_IP_UDP, NULL, 0, moveout_dw_ip,
ARRAY_SIZE(moveout_dw_ip) },
{ ICE_HASH_GTPU_CTX_DW_IP_TCP, NULL, 0, moveout_dw_ip,
ARRAY_SIZE(moveout_dw_ip) },
};
for (i = 0; i < ARRAY_SIZE(actions); i++) {
if (actions[i].ctx_idx != ctx_idx)
continue;
if (actions[i].remove_list) {
for (int j = 0; j < actions[i].remove_count; j++) {
u16 rm = actions[i].remove_list[j];
ret = ice_hash_remove(vf, &ctx->ctx[rm]);
if (ret && ret != -ENOENT)
return ret;
}
}
if (actions[i].moveout_list) {
for (int j = 0; j < actions[i].moveout_count; j++) {
u16 mv = actions[i].moveout_list[j];
ret = ice_hash_moveout(vf, &ctx->ctx[mv]);
if (ret && ret != -ENOENT)
return ret;
}
}
break;
}
return 0;
}
/**
* ice_add_rss_cfg_pre_ip - Pre-process IP-layer RSS configuration
* @vf: VF pointer
* @ctx: IP L4 hash context (ESP/UDP-ESP/AH/PFCP and UDP/TCP/SCTP)
*
* Remove covered/recorded IP RSS configurations prior to adding a new one.
*
* Return: 0 on success; negative error code on failure.
*/
static int
ice_add_rss_cfg_pre_ip(struct ice_vf *vf, struct ice_vf_hash_ip_ctx *ctx)
{
int i, ret;
for (i = 1; i < ICE_HASH_IP_CTX_MAX; i++)
if (ice_is_hash_cfg_valid(&ctx->ctx[i])) {
ret = ice_hash_remove(vf, &ctx->ctx[i]);
if (ret)
return ret;
}
return 0;
}
/**
* ice_calc_gtpu_ctx_idx - Calculate GTPU hash context index
* @hdrs: Bitmask of protocol headers prefixed with ICE_FLOW_SEG_HDR_*
*
* Determine the GTPU hash context index based on the combination of
* encapsulation headers (GTPU_EH, GTPU_UP, GTPU_DWN) and transport
* protocols (UDP, TCP) within IPv4 or IPv6 flows.
*
* Return: A valid context index (0-8) if the header combination is supported,
* or ICE_HASH_GTPU_CTX_MAX if the combination is invalid.
*/
static enum ice_hash_gtpu_ctx_type ice_calc_gtpu_ctx_idx(u32 hdrs)
{
u32 eh_idx, ip_idx;
if (hdrs & ICE_FLOW_SEG_HDR_GTPU_EH)
eh_idx = 0;
else if (hdrs & ICE_FLOW_SEG_HDR_GTPU_UP)
eh_idx = 1;
else if (hdrs & ICE_FLOW_SEG_HDR_GTPU_DWN)
eh_idx = 2;
else
return ICE_HASH_GTPU_CTX_MAX;
ip_idx = 0;
if (hdrs & ICE_FLOW_SEG_HDR_UDP)
ip_idx = 1;
else if (hdrs & ICE_FLOW_SEG_HDR_TCP)
ip_idx = 2;
if (hdrs & (ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6))
return eh_idx * 3 + ip_idx;
else
return ICE_HASH_GTPU_CTX_MAX;
}
/**
* ice_map_ip_ctx_idx - map the index of the IP L4 hash context
* @hdrs: protocol headers prefix with ICE_FLOW_SEG_HDR_XXX.
*
* The IP L4 hash context use the index to classify for IPv4/IPv6 with
* ESP/UDP_ESP/AH/PFCP and non-tunnel UDP/TCP/SCTP
* this function map the index based on the protocol headers.
*
* Return: The mapped IP context index on success, or ICE_HASH_IP_CTX_MAX
* if no matching context is found.
*/
static u8 ice_map_ip_ctx_idx(u32 hdrs)
{
u8 i;
static struct {
u32 hdrs;
u8 ctx_idx;
} ip_ctx_idx_map[] = {
{ ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV_OTHER |
ICE_FLOW_SEG_HDR_ESP,
ICE_HASH_IP_CTX_IP_ESP },
{ ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV_OTHER |
ICE_FLOW_SEG_HDR_NAT_T_ESP,
ICE_HASH_IP_CTX_IP_UDP_ESP },
{ ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV_OTHER |
ICE_FLOW_SEG_HDR_AH,
ICE_HASH_IP_CTX_IP_AH },
{ ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV_OTHER |
ICE_FLOW_SEG_HDR_PFCP_SESSION,
ICE_HASH_IP_CTX_IP_PFCP },
{ ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_UDP,
ICE_HASH_IP_CTX_IP_UDP },
{ ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_TCP,
ICE_HASH_IP_CTX_IP_TCP },
{ ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_SCTP,
ICE_HASH_IP_CTX_IP_SCTP },
{ ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV_OTHER,
ICE_HASH_IP_CTX_IP },
{ ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_IPV_OTHER |
ICE_FLOW_SEG_HDR_ESP,
ICE_HASH_IP_CTX_IP_ESP },
{ ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_IPV_OTHER |
ICE_FLOW_SEG_HDR_NAT_T_ESP,
ICE_HASH_IP_CTX_IP_UDP_ESP },
{ ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_IPV_OTHER |
ICE_FLOW_SEG_HDR_AH,
ICE_HASH_IP_CTX_IP_AH },
{ ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_IPV_OTHER |
ICE_FLOW_SEG_HDR_PFCP_SESSION,
ICE_HASH_IP_CTX_IP_PFCP },
{ ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_UDP,
ICE_HASH_IP_CTX_IP_UDP },
{ ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_TCP,
ICE_HASH_IP_CTX_IP_TCP },
{ ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_SCTP,
ICE_HASH_IP_CTX_IP_SCTP },
{ ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN |
ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_IPV_OTHER,
ICE_HASH_IP_CTX_IP },
/* the remaining mappings are used for default RSS */
{ ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_UDP,
ICE_HASH_IP_CTX_IP_UDP },
{ ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_TCP,
ICE_HASH_IP_CTX_IP_TCP },
{ ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_SCTP,
ICE_HASH_IP_CTX_IP_SCTP },
{ ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV_OTHER,
ICE_HASH_IP_CTX_IP },
{ ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_UDP,
ICE_HASH_IP_CTX_IP_UDP },
{ ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_TCP,
ICE_HASH_IP_CTX_IP_TCP },
{ ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_SCTP,
ICE_HASH_IP_CTX_IP_SCTP },
{ ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_IPV_OTHER,
ICE_HASH_IP_CTX_IP },
};
for (i = 0; i < ARRAY_SIZE(ip_ctx_idx_map); i++) {
if (hdrs == ip_ctx_idx_map[i].hdrs)
return ip_ctx_idx_map[i].ctx_idx;
}
return ICE_HASH_IP_CTX_MAX;
}
/**
* ice_add_rss_cfg_pre - Prepare RSS configuration context for a VF
* @vf: pointer to the VF structure
* @cfg: pointer to the RSS hash configuration
*
* Prepare the RSS hash context for a given VF based on the additional
* protocol headers specified in @cfg. This includes pre-configuration
* for IP and GTPU-based flows.
*
* If the configuration matches a known IP context, the function sets up
* the appropriate IP hash context. If the configuration includes GTPU
* headers, it prepares the GTPU-specific context accordingly.
*
* Return: 0 on success, or a negative error code on failure.
*/
static int
ice_add_rss_cfg_pre(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
{
u32 ice_gtpu_ctx_idx = ice_calc_gtpu_ctx_idx(cfg->addl_hdrs);
u8 ip_ctx_idx = ice_map_ip_ctx_idx(cfg->addl_hdrs);
if (ip_ctx_idx == ICE_HASH_IP_CTX_IP) {
int ret = 0;
if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4)
ret = ice_add_rss_cfg_pre_ip(vf, &vf->hash_ctx.v4);
else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6)
ret = ice_add_rss_cfg_pre_ip(vf, &vf->hash_ctx.v6);
if (ret)
return ret;
}
if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4) {
return ice_add_rss_cfg_pre_gtpu(vf, &vf->hash_ctx.ipv4,
ice_gtpu_ctx_idx);
} else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6) {
return ice_add_rss_cfg_pre_gtpu(vf, &vf->hash_ctx.ipv6,
ice_gtpu_ctx_idx);
}
return 0;
}
/**
* ice_add_rss_cfg_post_gtpu - Post-process GTPU RSS configuration
* @vf: pointer to the VF info
* @ctx: pointer to the context of the GTPU hash
* @cfg: pointer to the RSS hash configuration
* @ctx_idx: index of the hash context
*
* Post-processes the GTPU hash configuration after a new hash
* context has been successfully added. It updates the context with the new
* configuration and restores any previously removed hash contexts that need
* to be re-applied. This ensures proper TCAM rule ordering and avoids
* conflicts between overlapping GTPU rules.
*
* Return: 0 on success or a negative error code on failure
*/
static int ice_add_rss_cfg_post_gtpu(struct ice_vf *vf,
struct ice_vf_hash_gtpu_ctx *ctx,
struct ice_rss_hash_cfg *cfg, u32 ctx_idx)
{
/* GTPU hash moveback lookup table indexed by context ID.
* Each entry is a bitmap indicating which contexts need moveback
* operations when the corresponding context index is processed.
*/
static const unsigned long
ice_gtpu_moveback_tbl[ICE_HASH_GTPU_CTX_MAX] = {
[ICE_HASH_GTPU_CTX_EH_IP] = 0,
[ICE_HASH_GTPU_CTX_EH_IP_UDP] =
BIT(ICE_HASH_GTPU_CTX_UP_IP) |
BIT(ICE_HASH_GTPU_CTX_UP_IP_TCP) |
BIT(ICE_HASH_GTPU_CTX_DW_IP) |
BIT(ICE_HASH_GTPU_CTX_DW_IP_TCP),
[ICE_HASH_GTPU_CTX_EH_IP_TCP] =
BIT(ICE_HASH_GTPU_CTX_UP_IP) |
BIT(ICE_HASH_GTPU_CTX_UP_IP_UDP) |
BIT(ICE_HASH_GTPU_CTX_DW_IP) |
BIT(ICE_HASH_GTPU_CTX_DW_IP_UDP),
[ICE_HASH_GTPU_CTX_UP_IP] =
BIT(ICE_HASH_GTPU_CTX_EH_IP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
[ICE_HASH_GTPU_CTX_UP_IP_UDP] =
BIT(ICE_HASH_GTPU_CTX_EH_IP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
[ICE_HASH_GTPU_CTX_UP_IP_TCP] =
BIT(ICE_HASH_GTPU_CTX_EH_IP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
[ICE_HASH_GTPU_CTX_DW_IP] =
BIT(ICE_HASH_GTPU_CTX_EH_IP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
[ICE_HASH_GTPU_CTX_DW_IP_UDP] =
BIT(ICE_HASH_GTPU_CTX_EH_IP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
[ICE_HASH_GTPU_CTX_DW_IP_TCP] =
BIT(ICE_HASH_GTPU_CTX_EH_IP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_UDP) |
BIT(ICE_HASH_GTPU_CTX_EH_IP_TCP),
};
unsigned long moveback_mask;
int ret;
int i;
if (unlikely(ctx_idx >= ICE_HASH_GTPU_CTX_MAX))
return 0;
ctx->ctx[ctx_idx].addl_hdrs = cfg->addl_hdrs;
ctx->ctx[ctx_idx].hash_flds = cfg->hash_flds;
ctx->ctx[ctx_idx].hdr_type = cfg->hdr_type;
ctx->ctx[ctx_idx].symm = cfg->symm;
moveback_mask = ice_gtpu_moveback_tbl[ctx_idx];
for_each_set_bit(i, &moveback_mask, ICE_HASH_GTPU_CTX_MAX) {
ret = ice_hash_moveback(vf, &ctx->ctx[i]);
if (ret && ret != -ENOENT)
return ret;
}
return 0;
}
static int
ice_add_rss_cfg_post(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
{
u32 ice_gtpu_ctx_idx = ice_calc_gtpu_ctx_idx(cfg->addl_hdrs);
u8 ip_ctx_idx = ice_map_ip_ctx_idx(cfg->addl_hdrs);
if (ip_ctx_idx && ip_ctx_idx < ICE_HASH_IP_CTX_MAX) {
if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4)
ice_hash_cfg_record(&vf->hash_ctx.v4.ctx[ip_ctx_idx], cfg);
else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6)
ice_hash_cfg_record(&vf->hash_ctx.v6.ctx[ip_ctx_idx], cfg);
}
if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4) {
return ice_add_rss_cfg_post_gtpu(vf, &vf->hash_ctx.ipv4,
cfg, ice_gtpu_ctx_idx);
} else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6) {
return ice_add_rss_cfg_post_gtpu(vf, &vf->hash_ctx.ipv6,
cfg, ice_gtpu_ctx_idx);
}
return 0;
}
/**
* ice_rem_rss_cfg_post - post-process the RSS configuration
* @vf: pointer to the VF info
* @cfg: pointer to the RSS hash configuration
*
* Post process the RSS hash configuration after deleting a hash
* config. Such as, it will reset the hash context for the GTPU hash.
*/
static void
ice_rem_rss_cfg_post(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
{
u32 ice_gtpu_ctx_idx = ice_calc_gtpu_ctx_idx(cfg->addl_hdrs);
u8 ip_ctx_idx = ice_map_ip_ctx_idx(cfg->addl_hdrs);
if (ip_ctx_idx && ip_ctx_idx < ICE_HASH_IP_CTX_MAX) {
if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4)
ice_hash_cfg_reset(&vf->hash_ctx.v4.ctx[ip_ctx_idx]);
else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6)
ice_hash_cfg_reset(&vf->hash_ctx.v6.ctx[ip_ctx_idx]);
}
if (ice_gtpu_ctx_idx >= ICE_HASH_GTPU_CTX_MAX)
return;
if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV4)
ice_hash_cfg_reset(&vf->hash_ctx.ipv4.ctx[ice_gtpu_ctx_idx]);
else if (cfg->addl_hdrs & ICE_FLOW_SEG_HDR_IPV6)
ice_hash_cfg_reset(&vf->hash_ctx.ipv6.ctx[ice_gtpu_ctx_idx]);
}
/**
* ice_rem_rss_cfg_wrap - Wrapper for deleting an RSS configuration
* @vf: pointer to the VF info
* @cfg: pointer to the RSS hash configuration
*
* Wrapper function to delete a flow profile base on an RSS configuration,
* and also post process the hash context base on the rollback mechanism
* which handle some rules conflict by ice_add_rss_cfg_wrap.
*
* Return: 0 on success; negative error code on failure.
*/
static int
ice_rem_rss_cfg_wrap(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
{
struct device *dev = ice_pf_to_dev(vf->pf);
struct ice_vsi *vsi = ice_get_vf_vsi(vf);
struct ice_hw *hw = &vf->pf->hw;
int ret;
ret = ice_rem_rss_cfg(hw, vsi->idx, cfg);
/* We just ignore -ENOENT, because if two configurations share the same
* profile remove one of them actually removes both, since the
* profile is deleted.
*/
if (ret && ret != -ENOENT) {
dev_err(dev, "ice_rem_rss_cfg failed for VF %d, VSI %d, error:%d\n",
vf->vf_id, vf->lan_vsi_idx, ret);
return ret;
}
ice_rem_rss_cfg_post(vf, cfg);
return 0;
}
/**
* ice_add_rss_cfg_wrap - Wrapper for adding an RSS configuration
* @vf: pointer to the VF info
* @cfg: pointer to the RSS hash configuration
*
* Add a flow profile based on an RSS configuration. Use a rollback
* mechanism to handle rule conflicts due to TCAM
* write sequence from top to down.
*
* Return: 0 on success; negative error code on failure.
*/
static int
ice_add_rss_cfg_wrap(struct ice_vf *vf, struct ice_rss_hash_cfg *cfg)
{
struct device *dev = ice_pf_to_dev(vf->pf);
struct ice_vsi *vsi = ice_get_vf_vsi(vf);
struct ice_hw *hw = &vf->pf->hw;
int ret;
if (ice_add_rss_cfg_pre(vf, cfg))
return -EINVAL;
ret = ice_add_rss_cfg(hw, vsi, cfg);
if (ret) {
dev_err(dev, "ice_add_rss_cfg failed for VF %d, VSI %d, error:%d\n",
vf->vf_id, vf->lan_vsi_idx, ret);
return ret;
}
if (ice_add_rss_cfg_post(vf, cfg))
ret = -EINVAL;
return ret;
}
/**
* ice_parse_raw_rss_pattern - Parse raw pattern spec and mask for RSS
* @vf: pointer to the VF info
* @proto: pointer to the virtchnl protocol header
* @raw_cfg: pointer to the RSS raw pattern configuration
*
* Parser function to get spec and mask from virtchnl message, and parse
* them to get the corresponding profile and offset. The profile is used
* to add RSS configuration.
*
* Return: 0 on success; negative error code on failure.
*/
static int
ice_parse_raw_rss_pattern(struct ice_vf *vf, struct virtchnl_proto_hdrs *proto,
struct ice_rss_raw_cfg *raw_cfg)
{
struct ice_parser_result pkt_parsed;
struct ice_hw *hw = &vf->pf->hw;
struct ice_parser_profile prof;
struct ice_parser *psr;
u8 *pkt_buf, *msk_buf;
u16 pkt_len;
int ret = 0;
pkt_len = proto->raw.pkt_len;
if (!pkt_len)
return -EINVAL;
if (pkt_len > VIRTCHNL_MAX_SIZE_RAW_PACKET)
pkt_len = VIRTCHNL_MAX_SIZE_RAW_PACKET;
pkt_buf = kzalloc(pkt_len, GFP_KERNEL);
msk_buf = kzalloc(pkt_len, GFP_KERNEL);
if (!pkt_buf || !msk_buf) {
ret = -ENOMEM;
goto free_alloc;
}
memcpy(pkt_buf, proto->raw.spec, pkt_len);
memcpy(msk_buf, proto->raw.mask, pkt_len);
psr = ice_parser_create(hw);
if (IS_ERR(psr)) {
ret = PTR_ERR(psr);
goto free_alloc;
}
ret = ice_parser_run(psr, pkt_buf, pkt_len, &pkt_parsed);
if (ret)
goto parser_destroy;
ret = ice_parser_profile_init(&pkt_parsed, pkt_buf, msk_buf,
pkt_len, ICE_BLK_RSS, &prof);
if (ret)
goto parser_destroy;
memcpy(&raw_cfg->prof, &prof, sizeof(prof));
parser_destroy:
ice_parser_destroy(psr);
free_alloc:
kfree(pkt_buf);
kfree(msk_buf);
return ret;
}
/**
* ice_add_raw_rss_cfg - add RSS configuration for raw pattern
* @vf: pointer to the VF info
* @cfg: pointer to the RSS raw pattern configuration
*
* This function adds the RSS configuration for raw pattern.
* Check if current profile is matched. If not, remove the old
* one and add the new profile to HW directly. Update the symmetric
* hash configuration as well.
*
* Return: 0 on success; negative error code on failure.
*/
static int
ice_add_raw_rss_cfg(struct ice_vf *vf, struct ice_rss_raw_cfg *cfg)
{
struct ice_parser_profile *prof = &cfg->prof;
struct device *dev = ice_pf_to_dev(vf->pf);
struct ice_rss_prof_info *rss_prof;
struct ice_hw *hw = &vf->pf->hw;
int i, ptg, ret = 0;
u16 vsi_handle;
u64 id;
vsi_handle = vf->lan_vsi_idx;
id = find_first_bit(prof->ptypes, ICE_FLOW_PTYPE_MAX);
ptg = hw->blk[ICE_BLK_RSS].xlt1.t[id];
rss_prof = &vf->rss_prof_info[ptg];
/* check if ptg already has a profile */
if (rss_prof->prof.fv_num) {
for (i = 0; i < ICE_MAX_FV_WORDS; i++) {
if (rss_prof->prof.fv[i].proto_id !=
prof->fv[i].proto_id ||
rss_prof->prof.fv[i].offset !=
prof->fv[i].offset)
break;
}
/* current profile is matched, check symmetric hash */
if (i == ICE_MAX_FV_WORDS) {
if (rss_prof->symm != cfg->symm)
goto update_symm;
return ret;
}
/* current profile is not matched, remove it */
ret =
ice_rem_prof_id_flow(hw, ICE_BLK_RSS,
ice_get_hw_vsi_num(hw, vsi_handle),
id);
if (ret) {
dev_err(dev, "remove RSS flow failed\n");
return ret;
}
ret = ice_rem_prof(hw, ICE_BLK_RSS, id);
if (ret) {
dev_err(dev, "remove RSS profile failed\n");
return ret;
}
}
/* add new profile */
ret = ice_flow_set_parser_prof(hw, vsi_handle, 0, prof, ICE_BLK_RSS);
if (ret) {
dev_err(dev, "HW profile add failed\n");
return ret;
}
memcpy(&rss_prof->prof, prof, sizeof(struct ice_parser_profile));
update_symm:
rss_prof->symm = cfg->symm;
ice_rss_update_raw_symm(hw, cfg, id);
return ret;
}
/**
* ice_rem_raw_rss_cfg - remove RSS configuration for raw pattern
* @vf: pointer to the VF info
* @cfg: pointer to the RSS raw pattern configuration
*
* This function removes the RSS configuration for raw pattern.
* Check if vsi group is already removed first. If not, remove the
* profile.
*
* Return: 0 on success; negative error code on failure.
*/
static int
ice_rem_raw_rss_cfg(struct ice_vf *vf, struct ice_rss_raw_cfg *cfg)
{
struct ice_parser_profile *prof = &cfg->prof;
struct device *dev = ice_pf_to_dev(vf->pf);
struct ice_hw *hw = &vf->pf->hw;
int ptg, ret = 0;
u16 vsig, vsi;
u64 id;
id = find_first_bit(prof->ptypes, ICE_FLOW_PTYPE_MAX);
ptg = hw->blk[ICE_BLK_RSS].xlt1.t[id];
memset(&vf->rss_prof_info[ptg], 0,
sizeof(struct ice_rss_prof_info));
/* check if vsig is already removed */
vsi = ice_get_hw_vsi_num(hw, vf->lan_vsi_idx);
if (vsi >= ICE_MAX_VSI) {
ret = -EINVAL;
goto err;
}
vsig = hw->blk[ICE_BLK_RSS].xlt2.vsis[vsi].vsig;
if (vsig) {
ret = ice_rem_prof_id_flow(hw, ICE_BLK_RSS, vsi, id);
if (ret)
goto err;
ret = ice_rem_prof(hw, ICE_BLK_RSS, id);
if (ret)
goto err;
}
return ret;
err:
dev_err(dev, "HW profile remove failed\n");
return ret;
}
/**
* ice_vc_handle_rss_cfg
* @vf: pointer to the VF info
* @msg: pointer to the message buffer
* @add: add a RSS config if true, otherwise delete a RSS config
*
* This function adds/deletes a RSS config
*/
int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8 *msg, bool add)
{
u32 v_opcode = add ? VIRTCHNL_OP_ADD_RSS_CFG : VIRTCHNL_OP_DEL_RSS_CFG;
struct virtchnl_rss_cfg *rss_cfg = (struct virtchnl_rss_cfg *)msg;
enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
struct device *dev = ice_pf_to_dev(vf->pf);
struct ice_hw *hw = &vf->pf->hw;
struct ice_vsi *vsi;
u8 hash_type;
bool symm;
int ret;
if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) {
dev_dbg(dev, "VF %d attempting to configure RSS, but RSS is not supported by the PF\n",
vf->vf_id);
v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED;
goto error_param;
}
if (!ice_vf_adv_rss_offload_ena(vf->driver_caps)) {
dev_dbg(dev, "VF %d attempting to configure RSS, but Advanced RSS offload is not supported\n",
vf->vf_id);
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (rss_cfg->proto_hdrs.count > VIRTCHNL_MAX_NUM_PROTO_HDRS ||
rss_cfg->rss_algorithm < VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC ||
rss_cfg->rss_algorithm > VIRTCHNL_RSS_ALG_XOR_SYMMETRIC) {
dev_dbg(dev, "VF %d attempting to configure RSS, but RSS configuration is not valid\n",
vf->vf_id);
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
vsi = ice_get_vf_vsi(vf);
if (!vsi) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (rss_cfg->rss_algorithm == VIRTCHNL_RSS_ALG_R_ASYMMETRIC) {
hash_type = add ? ICE_AQ_VSI_Q_OPT_RSS_HASH_XOR :
ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
ret = ice_vc_rss_hash_update(hw, vsi, hash_type);
if (ret)
v_ret = ice_err_to_virt_err(ret);
goto error_param;
}
hash_type = add ? ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ :
ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
ret = ice_vc_rss_hash_update(hw, vsi, hash_type);
if (ret) {
v_ret = ice_err_to_virt_err(ret);
goto error_param;
}
symm = rss_cfg->rss_algorithm == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC;
/* Configure RSS hash for raw pattern */
if (rss_cfg->proto_hdrs.tunnel_level == 0 &&
rss_cfg->proto_hdrs.count == 0) {
struct ice_rss_raw_cfg raw_cfg;
if (ice_parse_raw_rss_pattern(vf, &rss_cfg->proto_hdrs,
&raw_cfg)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (add) {
raw_cfg.symm = symm;
if (ice_add_raw_rss_cfg(vf, &raw_cfg))
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
} else {
if (ice_rem_raw_rss_cfg(vf, &raw_cfg))
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
}
} else {
struct ice_rss_hash_cfg cfg;
/* Only check for none raw pattern case */
if (!ice_vc_validate_pattern(vf, &rss_cfg->proto_hdrs)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
cfg.addl_hdrs = ICE_FLOW_SEG_HDR_NONE;
cfg.hash_flds = ICE_HASH_INVALID;
cfg.hdr_type = ICE_RSS_ANY_HEADERS;
if (!ice_vc_parse_rss_cfg(hw, rss_cfg, &cfg)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (add) {
cfg.symm = symm;
if (ice_add_rss_cfg_wrap(vf, &cfg))
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
} else {
if (ice_rem_rss_cfg_wrap(vf, &cfg))
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
}
}
error_param:
return ice_vc_send_msg_to_vf(vf, v_opcode, v_ret, NULL, 0);
}
/**
* ice_vc_config_rss_key
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
*
* Configure the VF's RSS key
*/
int ice_vc_config_rss_key(struct ice_vf *vf, u8 *msg)
{
enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
struct virtchnl_rss_key *vrk =
(struct virtchnl_rss_key *)msg;
struct ice_vsi *vsi;
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (!ice_vc_isvalid_vsi_id(vf, vrk->vsi_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (vrk->key_len != ICE_VSIQF_HKEY_ARRAY_SIZE) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
vsi = ice_get_vf_vsi(vf);
if (!vsi) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (ice_set_rss_key(vsi, vrk->key))
v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
error_param:
return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_KEY, v_ret,
NULL, 0);
}
/**
* ice_vc_config_rss_lut
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
*
* Configure the VF's RSS LUT
*/
int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg)
{
struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg;
enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
struct ice_vsi *vsi;
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (!ice_vc_isvalid_vsi_id(vf, vrl->vsi_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (vrl->lut_entries != ICE_LUT_VSI_SIZE) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
vsi = ice_get_vf_vsi(vf);
if (!vsi) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (ice_set_rss_lut(vsi, vrl->lut, ICE_LUT_VSI_SIZE))
v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
error_param:
return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT, v_ret,
NULL, 0);
}
/**
* ice_vc_config_rss_hfunc
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
*
* Configure the VF's RSS Hash function
*/
int ice_vc_config_rss_hfunc(struct ice_vf *vf, u8 *msg)
{
struct virtchnl_rss_hfunc *vrh = (struct virtchnl_rss_hfunc *)msg;
enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
u8 hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
struct ice_vsi *vsi;
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (!ice_vc_isvalid_vsi_id(vf, vrh->vsi_id)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
vsi = ice_get_vf_vsi(vf);
if (!vsi) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (vrh->rss_algorithm == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC)
hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ;
if (ice_set_rss_hfunc(vsi, hfunc))
v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
error_param:
return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_HFUNC, v_ret,
NULL, 0);
}
/**
* ice_vc_get_rss_hashcfg - return the RSS Hash configuration
* @vf: pointer to the VF info
*/
int ice_vc_get_rss_hashcfg(struct ice_vf *vf)
{
enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
struct virtchnl_rss_hashcfg *vrh = NULL;
int len = 0, ret;
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto err;
}
if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) {
dev_err(ice_pf_to_dev(vf->pf), "RSS not supported by PF\n");
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto err;
}
len = sizeof(struct virtchnl_rss_hashcfg);
vrh = kzalloc(len, GFP_KERNEL);
if (!vrh) {
v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
len = 0;
goto err;
}
vrh->hashcfg = ICE_DEFAULT_RSS_HASHCFG;
err:
/* send the response back to the VF */
ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_RSS_HASHCFG_CAPS, v_ret,
(u8 *)vrh, len);
kfree(vrh);
return ret;
}
/**
* ice_vc_set_rss_hashcfg - set RSS Hash configuration bits for the VF
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
*/
int ice_vc_set_rss_hashcfg(struct ice_vf *vf, u8 *msg)
{
struct virtchnl_rss_hashcfg *vrh = (struct virtchnl_rss_hashcfg *)msg;
enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
struct ice_pf *pf = vf->pf;
struct ice_vsi *vsi;
struct device *dev;
int status;
dev = ice_pf_to_dev(pf);
if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto err;
}
if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {
dev_err(dev, "RSS not supported by PF\n");
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto err;
}
vsi = ice_get_vf_vsi(vf);
if (!vsi) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto err;
}
/* clear all previously programmed RSS configuration to allow VF drivers
* the ability to customize the RSS configuration and/or completely
* disable RSS
*/
status = ice_rem_vsi_rss_cfg(&pf->hw, vsi->idx);
if (status && !vrh->hashcfg) {
/* only report failure to clear the current RSS configuration if
* that was clearly the VF's intention (i.e. vrh->hashcfg = 0)
*/
v_ret = ice_err_to_virt_err(status);
goto err;
} else if (status) {
/* allow the VF to update the RSS configuration even on failure
* to clear the current RSS confguration in an attempt to keep
* RSS in a working state
*/
dev_warn(dev, "Failed to clear the RSS configuration for VF %u\n",
vf->vf_id);
}
if (vrh->hashcfg) {
status = ice_add_avf_rss_cfg(&pf->hw, vsi, vrh->hashcfg);
v_ret = ice_err_to_virt_err(status);
}
/* save the requested VF configuration */
if (!v_ret)
vf->rss_hashcfg = vrh->hashcfg;
/* send the response to the VF */
err:
return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_SET_RSS_HASHCFG, v_ret,
NULL, 0);
}