+static void
+ice_refine_hash_cfg_l234(struct ice_rss_hash_cfg *hash_cfg,
+ uint64_t rss_type)
+{
+ uint32_t *addl_hdrs = &hash_cfg->addl_hdrs;
+ uint64_t *hash_flds = &hash_cfg->hash_flds;
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_ETH) {
+ if (!(rss_type & RTE_ETH_RSS_ETH))
+ *hash_flds &= ~ICE_FLOW_HASH_ETH;
+ if (rss_type & RTE_ETH_RSS_L2_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_DA));
+ else if (rss_type & RTE_ETH_RSS_L2_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_SA));
+ *addl_hdrs &= ~ICE_FLOW_SEG_HDR_ETH;
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_ETH_NON_IP) {
+ if (rss_type & RTE_ETH_RSS_ETH)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_ETH_TYPE);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_VLAN) {
+ if (rss_type & RTE_ETH_RSS_C_VLAN)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_C_VLAN);
+ else if (rss_type & RTE_ETH_RSS_S_VLAN)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_S_VLAN);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_PPPOE) {
+ if (!(rss_type & RTE_ETH_RSS_PPPOE))
+ *hash_flds &= ~ICE_FLOW_HASH_PPPOE_SESS_ID;
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_IPV4) {
+ if (rss_type &
+ (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4 |
+ RTE_ETH_RSS_NONFRAG_IPV4_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV4_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV4_SCTP)) {
+ if (rss_type & RTE_ETH_RSS_FRAG_IPV4) {
+ *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);
+ }
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA));
+ else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA));
+ else if (rss_type &
+ (RTE_ETH_RSS_L4_SRC_ONLY |
+ RTE_ETH_RSS_L4_DST_ONLY))
+ *hash_flds &= ~ICE_FLOW_HASH_IPV4;
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_IPV4;
+ }
+
+ if (rss_type & RTE_ETH_RSS_IPV4_CHKSUM)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_CHKSUM);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_IPV6) {
+ if (rss_type &
+ (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 |
+ RTE_ETH_RSS_NONFRAG_IPV6_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV6_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV6_SCTP)) {
+ if (rss_type & RTE_ETH_RSS_FRAG_IPV6)
+ *hash_flds |=
+ BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_ID);
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA));
+ else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA));
+ else if (rss_type &
+ (RTE_ETH_RSS_L4_SRC_ONLY |
+ RTE_ETH_RSS_L4_DST_ONLY))
+ *hash_flds &= ~ICE_FLOW_HASH_IPV6;
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_IPV6;
+ }
+
+ if (rss_type & RTE_ETH_RSS_L3_PRE32) {
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE32_SA));
+ } else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE32_DA));
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_IPV6;
+ *hash_flds |= ICE_FLOW_HASH_IPV6_PRE32;
+ }
+ }
+ if (rss_type & RTE_ETH_RSS_L3_PRE48) {
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE48_SA));
+ } else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE48_DA));
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_IPV6;
+ *hash_flds |= ICE_FLOW_HASH_IPV6_PRE48;
+ }
+ }
+ if (rss_type & RTE_ETH_RSS_L3_PRE64) {
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_SA));
+ } else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA));
+ *hash_flds |= (BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_PRE64_DA));
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_IPV6;
+ *hash_flds |= ICE_FLOW_HASH_IPV6_PRE64;
+ }
+ }
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_UDP) {
+ if (rss_type &
+ (RTE_ETH_RSS_NONFRAG_IPV4_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV6_UDP)) {
+ if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT));
+ else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT));
+ else if (rss_type &
+ (RTE_ETH_RSS_L3_SRC_ONLY |
+ RTE_ETH_RSS_L3_DST_ONLY))
+ *hash_flds &= ~ICE_FLOW_HASH_UDP_PORT;
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_UDP_PORT;
+ }
+
+ if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_CHKSUM);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_TCP) {
+ if (rss_type &
+ (RTE_ETH_RSS_NONFRAG_IPV4_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV6_TCP)) {
+ if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT));
+ else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT));
+ else if (rss_type &
+ (RTE_ETH_RSS_L3_SRC_ONLY |
+ RTE_ETH_RSS_L3_DST_ONLY))
+ *hash_flds &= ~ICE_FLOW_HASH_TCP_PORT;
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_TCP_PORT;
+ }
+
+ if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_CHKSUM);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_SCTP) {
+ if (rss_type &
+ (RTE_ETH_RSS_NONFRAG_IPV4_SCTP |
+ RTE_ETH_RSS_NONFRAG_IPV6_SCTP)) {
+ if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT));
+ else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY)
+ *hash_flds &= ~(BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT));
+ else if (rss_type &
+ (RTE_ETH_RSS_L3_SRC_ONLY |
+ RTE_ETH_RSS_L3_DST_ONLY))
+ *hash_flds &= ~ICE_FLOW_HASH_SCTP_PORT;
+ } else {
+ *hash_flds &= ~ICE_FLOW_HASH_SCTP_PORT;
+ }
+
+ if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_CHKSUM);
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_L2TPV3) {
+ if (!(rss_type & RTE_ETH_RSS_L2TPV3))
+ *hash_flds &= ~ICE_FLOW_HASH_L2TPV3_SESS_ID;
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_ESP) {
+ if (!(rss_type & RTE_ETH_RSS_ESP))
+ *hash_flds &= ~ICE_FLOW_HASH_ESP_SPI;
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_AH) {
+ if (!(rss_type & RTE_ETH_RSS_AH))
+ *hash_flds &= ~ICE_FLOW_HASH_AH_SPI;
+ }
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_PFCP_SESSION) {
+ if (!(rss_type & RTE_ETH_RSS_PFCP))
+ *hash_flds &= ~ICE_FLOW_HASH_PFCP_SEID;
+ }
+}
+
+static void
+ice_refine_proto_hdrs_by_pattern(struct ice_rss_hash_cfg *hash_cfg,
+ uint64_t phint)
+{
+ uint32_t *addl_hdrs = &hash_cfg->addl_hdrs;
+ if (phint & ICE_PHINT_VLAN)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_VLAN;
+
+ if (phint & ICE_PHINT_PPPOE)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_PPPOE;
+
+ if (phint & ICE_PHINT_GTPU_EH_DWN)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_GTPU_DWN;
+ else if (phint & ICE_PHINT_GTPU_EH_UP)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_GTPU_UP;
+ else if (phint & ICE_PHINT_GTPU_EH)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_GTPU_EH;
+ else if (phint & ICE_PHINT_GTPU)
+ *addl_hdrs |= ICE_FLOW_SEG_HDR_GTPU_IP;
+}
+
+static void
+ice_refine_hash_cfg_gtpu(struct ice_rss_hash_cfg *hash_cfg,
+ uint64_t rss_type)
+{
+ uint32_t *addl_hdrs = &hash_cfg->addl_hdrs;
+ uint64_t *hash_flds = &hash_cfg->hash_flds;
+
+ /* update hash field for gtpu eh/gtpu dwn/gtpu up. */
+ if (!(rss_type & RTE_ETH_RSS_GTPU))
+ return;
+
+ if (*addl_hdrs & ICE_FLOW_SEG_HDR_GTPU_DWN)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_DWN_TEID);
+ else if (*addl_hdrs & ICE_FLOW_SEG_HDR_GTPU_UP)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_UP_TEID);
+ else if (*addl_hdrs & ICE_FLOW_SEG_HDR_GTPU_EH)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_EH_TEID);
+ else if (*addl_hdrs & ICE_FLOW_SEG_HDR_GTPU_IP)
+ *hash_flds |= BIT_ULL(ICE_FLOW_FIELD_IDX_GTPU_IP_TEID);
+}
+
+static void ice_refine_hash_cfg(struct ice_rss_hash_cfg *hash_cfg,
+ uint64_t rss_type, uint64_t phint)
+{
+ ice_refine_proto_hdrs_by_pattern(hash_cfg, phint);
+ ice_refine_hash_cfg_l234(hash_cfg, rss_type);
+ ice_refine_hash_cfg_gtpu(hash_cfg, rss_type);
+}
+
+static uint64_t invalid_rss_comb[] = {
+ RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_UDP,
+ RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_TCP,
+ RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_UDP,
+ RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_TCP,
+ RTE_ETH_RSS_L3_PRE40 |
+ RTE_ETH_RSS_L3_PRE56 |
+ RTE_ETH_RSS_L3_PRE96
+};
+
+struct rss_attr_type {
+ uint64_t attr;
+ uint64_t type;
+};
+
+static struct rss_attr_type rss_attr_to_valid_type[] = {
+ {RTE_ETH_RSS_L2_SRC_ONLY | RTE_ETH_RSS_L2_DST_ONLY, RTE_ETH_RSS_ETH},
+ {RTE_ETH_RSS_L3_SRC_ONLY | RTE_ETH_RSS_L3_DST_ONLY, VALID_RSS_L3},
+ {RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY, VALID_RSS_L4},
+ /* current ipv6 prefix only supports prefix 64 bits*/
+ {RTE_ETH_RSS_L3_PRE32, VALID_RSS_IPV6},
+ {RTE_ETH_RSS_L3_PRE48, VALID_RSS_IPV6},
+ {RTE_ETH_RSS_L3_PRE64, VALID_RSS_IPV6},
+ {INVALID_RSS_ATTR, 0}
+};
+
+static bool
+ice_any_invalid_rss_type(enum rte_eth_hash_function rss_func,
+ uint64_t rss_type, uint64_t allow_rss_type)
+{
+ uint32_t i;
+
+ /**
+ * Check if l3/l4 SRC/DST_ONLY is set for SYMMETRIC_TOEPLITZ
+ * hash function.
+ */
+ if (rss_func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
+ if (rss_type & (RTE_ETH_RSS_L3_SRC_ONLY | RTE_ETH_RSS_L3_DST_ONLY |
+ RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY))
+ return true;
+
+ if (!(rss_type &
+ (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_IPV6 |
+ RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_FRAG_IPV6 |
+ RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV6_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV6_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV4_SCTP | RTE_ETH_RSS_NONFRAG_IPV6_SCTP)))
+ return true;
+ }
+
+ /* check invalid combination */
+ for (i = 0; i < RTE_DIM(invalid_rss_comb); i++) {
+ if (__builtin_popcountll(rss_type & invalid_rss_comb[i]) > 1)
+ return true;
+ }
+
+ /* check invalid RSS attribute */
+ for (i = 0; i < RTE_DIM(rss_attr_to_valid_type); i++) {
+ struct rss_attr_type *rat = &rss_attr_to_valid_type[i];
+
+ if (rat->attr & rss_type && !(rat->type & rss_type))
+ return true;
+ }
+
+ /* check not allowed RSS type */
+ rss_type &= ~VALID_RSS_ATTR;
+
+ return ((rss_type & allow_rss_type) != rss_type);
+}
+