The default fields of a received packet are loaded from firmware,
which cannot be modified even users want to use different fields
for RSS or filtering. Here adds a workaround to open more
flexibilities of selecting packet fields for hash calculation or
flow director to users.

Signed-off-by: Helin Zhang <helin.zhang at intel.com>
Signed-off-by: Andrey Chilikin <andrey.chilikin at intel.com>
---
 drivers/net/i40e/i40e_ethdev.c  | 591 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/i40e/i40e_ethdev.h  |   6 +
 drivers/net/i40e/i40e_fdir.c    |  31 +++
 lib/librte_ether/rte_eth_ctrl.h | 106 ++++++-
 4 files changed, 730 insertions(+), 4 deletions(-)

v2 changes:
Solved the compilation issues.

diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 2dd9fdc..e711992 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -113,6 +113,131 @@
 #define I40E_PRTTSYN_TSYNENA  0x80000000
 #define I40E_PRTTSYN_TSYNTYPE 0x0e000000

+#define I40E_PRTQF_FD_INSET(_i, _j)  (0x00250000 + ((_i) * 64 + (_j) * 32))
+#define I40E_GLQF_FD_MSK(_i, _j)     (0x00267200 + ((_i) * 4 + (_j) * 8))
+#define I40E_GLQF_HASH_INSET(_i, _j) (0x00267600 + ((_i) * 4 + (_j) * 8))
+#define I40E_GLQF_HASH_MSK(_i, _j)   (0x00267A00 + ((_i) * 4 + (_j) * 8))
+
+#define I40E_INSET_UNKNOWN        0x00000000000000000ULL
+
+/* FD/Hash filters input set fields */
+#define I40E_INSET_DMAC            0x0000000000000001ULL
+#define I40E_INSET_SMAC            0x0000000000000002ULL
+#define I40E_INSET_VLAN_OUTER      0x0000000000000004ULL
+#define I40E_INSET_VLAN_INNER      0x0000000000000008ULL
+#define I40E_INSET_VLAN_TUNNEL     0x0000000000000010ULL
+
+#define I40E_INSET_IPV4_SRC        0x0000000000000100ULL
+#define I40E_INSET_IPV4_DST        0x0000000000000200ULL
+#define I40E_INSET_IPV6_SRC        0x0000000000000400ULL
+#define I40E_INSET_IPV6_DST        0x0000000000000800ULL
+#define I40E_INSET_SRC_PORT        0x0000000000001000ULL
+#define I40E_INSET_DST_PORT        0x0000000000002000ULL
+#define I40E_INSET_SCTP_VT         0x0000000000004000ULL
+
+/* next 8 fields can be used with masking only; two 16-bit masks per PCTYPE */
+#define I40E_INSET_IPV4_TOS        0x0000000000010000ULL
+#define I40E_INSET_IPV4_PROTO      0x0000000000020000ULL
+#define I40E_INSET_IPV4_TTL        0x0000000000040000ULL
+#define I40E_INSET_IPV6_TC         0x0000000000080000ULL
+#define I40E_INSET_IPV6_FLOW       0x0000000000100000ULL
+#define I40E_INSET_IPV6_NEXT_HDR   0x0000000000200000ULL
+#define I40E_INSET_IPV6_HOP_LIMIT  0x0000000000400000ULL
+#define I40E_INSET_TCP_FLAGS       0x0000000000800000ULL
+
+/* tunnel outer IP, valid only if flexible payload is not defined */
+#define I40E_INSET_TUNNEL_IPV4_DST 0x0000000001000000ULL
+#define I40E_INSET_TUNNEL_IPV6_DST 0x0000000002000000ULL
+#define I40E_INSET_TUNNEL_DMAC     0x0000000004000000ULL
+#define I40E_INSET_TUNNEL_SRC_PORT 0x0000000008000000ULL
+#define I40E_INSET_TUNNEL_DST_PORT 0x0000000010000000ULL
+#define I40E_INSET_TUNNEL_ID       0x0000000020000000ULL
+#define I40E_INSET_GRE_NEXT_PROTO  I40E_INSET_DST_PORT
+
+/* last Ethertype for L2 PCTYPE                       */
+#define I40E_INSET_LAST_ETHER_TYPE 0x0000000100000000ULL
+
+/* 8 words of Flex Payload                            */
+#define I40E_INSET_FLEX_PAYLOAD_W1 0x0000001000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W2 0x0000002000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W3 0x0000004000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W4 0x0000008000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W5 0x0000010000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W6 0x0000020000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W7 0x0000040000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD_W8 0x0000080000000000ULL
+#define I40E_INSET_FLEX_PAYLOAD \
+       (I40E_INSET_FLEX_PAYLOAD_W1 | I40E_INSET_FLEX_PAYLOAD_W2 | \
+       I40E_INSET_FLEX_PAYLOAD_W3 | I40E_INSET_FLEX_PAYLOAD_W3 | \
+       I40E_INSET_FLEX_PAYLOAD_W5 | I40E_INSET_FLEX_PAYLOAD_W6 | \
+       I40E_INSET_FLEX_PAYLOAD_W7 | I40E_INSET_FLEX_PAYLOAD_W8)
+
+#define I40E_INSET_ALL             0xFFFFFFFFFFFFFFFFULL
+
+/**
+ * Below are values for writing un-exposed registers suggested
+ * by silicon experts
+ */
+/* Destination MAC address */
+#define I40E_REG_INSET_L2_DMAC                   0xE000000000000000ULL
+/* Source MAC address */
+#define I40E_REG_INSET_L2_SMAC                   0x1C00000000000000ULL
+/* VLAN tag in the outer L2 header */
+#define I40E_REG_INSET_L2_OUTER_VLAN             0x0000000000800000ULL
+/* VLAN tag in the inner L2 header */
+#define I40E_REG_INSET_L2_INNER_VLAN             0x0000000001000000ULL
+/* Source IPv4 address */
+#define I40E_REG_INSET_L3_SRC_IP4                0x0001800000000000ULL
+/* Destination IPv4 address */
+#define I40E_REG_INSET_L3_DST_IP4                0x0000001800000000ULL
+/* Source IPv6 address */
+#define I40E_REG_INSET_L3_SRC_IP6                0x0007F80000000000ULL
+/* Destination IPv6 address */
+#define I40E_REG_INSET_L3_DST_IP6                0x000007F800000000ULL
+/* Source L4 port */
+#define I40E_REG_INSET_L4_SRC_PORT               0x0000000400000000ULL
+/* Destination L4 port */
+#define I40E_REG_INSET_L4_DST_PORT               0x0000000200000000ULL
+/* SCTP verification tag */
+#define I40E_REG_INSET_L4_SCTP_VERIFICATION_TAG  0x0000000180000000ULL
+/* Inner destination MAC address (MAC-in-UDP/MAC-in-GRE)*/
+#define I40E_REG_INSET_TUNNEL_L2_INNER_DST_MAC   0x0000000001C00000ULL
+/* Source port of tunneling UDP */
+#define I40E_REG_INSET_TUNNEL_L4_UDP_SRC_PORT    0x0000000000200000ULL
+/* Destination port of tunneling UDP */
+#define I40E_REG_INSET_TUNNEL_L4_UDP_DST_PORT    0x0000000000100000ULL
+/* Tunneling UDP keys */
+#define I40E_REG_INSET_TUNNEL_L4_UDP_KEY         0x00000000000F8000ULL
+/* GRE version and protocol type */
+#define I40E_REG_INSET_TUNNEL_GRE_VER_PROTO_TYPE 0x0000000000300000ULL
+/* GRE key */
+#define I40E_REG_INSET_TUNNEL_GRE_KEY            0x00000000000C0000ULL
+/* Last ether type */
+#define I40E_REG_INSET_LAST_ETHER_TYPE           0x0000000000004000ULL
+/* Tunneling outer destination IPv4 address */
+#define I40E_REG_INSET_TUNNEL_L3_DST_IP4         0x00000000000000C0ULL
+/* Tunneling outer destination IPv6 address */
+#define I40E_REG_INSET_TUNNEL_L3_DST_IP6         0x0000000000003FC0ULL
+/* 1st word of flex payload */
+#define I40E_REG_INSET_FLEX_PAYLOAD_WORD1        0x0000000000002000ULL
+/* 2nd word of flex payload */
+#define I40E_REG_INSET_FLEX_PAYLOAD_WORD2        0x0000000000001000ULL
+/* 3rd word of flex payload */
+#define I40E_REG_INSET_FLEX_PAYLOAD_WORD3        0x0000000000000800ULL
+/* 4th word of flex payload */
+#define I40E_REG_INSET_FLEX_PAYLOAD_WORD4        0x0000000000000400ULL
+/* 5th word of flex payload */
+#define I40E_REG_INSET_FLEX_PAYLOAD_WORD5        0x0000000000000200ULL
+/* 6th word of flex payload */
+#define I40E_REG_INSET_FLEX_PAYLOAD_WORD6        0x0000000000000100ULL
+/* 7th word of flex payload */
+#define I40E_REG_INSET_FLEX_PAYLOAD_WORD7        0x0000000000000080ULL
+/* 8th word of flex payload */
+#define I40E_REG_INSET_FLEX_PAYLOAD_WORD8        0x0000000000000040ULL
+#define I40E_REG_INSET_ALL                       0xFFFFFFFFFFFFFFFFULL
+
+#define I40E_REG_INSET_MASK_DEFAULT              0x0000000000000000ULL
+
 static int eth_i40e_dev_init(struct rte_eth_dev *eth_dev);
 static int eth_i40e_dev_uninit(struct rte_eth_dev *eth_dev);
 static int i40e_dev_configure(struct rte_eth_dev *dev);
@@ -5451,6 +5576,466 @@ out:
        return 0;
 }

+/**
+ * Validate if the input set is allowed for a specific PCTYPE
+ */
+static int
+i40e_validate_input_set(enum i40e_filter_pctype pctype, uint64_t inset)
+{
+       static const uint64_t valid_inset_table[] = {
+               [I40E_FILTER_PCTYPE_FRAG_IPV4] =
+                       I40E_INSET_DMAC | I40E_INSET_SMAC |
+                       I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
+                       I40E_INSET_VLAN_TUNNEL | I40E_INSET_IPV4_SRC |
+                       I40E_INSET_IPV4_DST | I40E_INSET_IPV4_TOS |
+                       I40E_INSET_IPV4_PROTO | I40E_INSET_IPV4_TTL |
+                       I40E_INSET_TUNNEL_DMAC | I40E_INSET_TUNNEL_ID |
+                       I40E_INSET_FLEX_PAYLOAD,
+               [I40E_FILTER_PCTYPE_NONF_IPV4_UDP] =
+                       I40E_INSET_DMAC | I40E_INSET_SMAC |
+                       I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
+                       I40E_INSET_VLAN_TUNNEL | I40E_INSET_IPV4_TOS |
+                       I40E_INSET_IPV4_PROTO | I40E_INSET_IPV4_TTL |
+                       I40E_INSET_TUNNEL_DMAC | I40E_INSET_TUNNEL_ID |
+                       I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+                       I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
+                       I40E_INSET_FLEX_PAYLOAD,
+               [I40E_FILTER_PCTYPE_NONF_IPV4_TCP] =
+                       I40E_INSET_DMAC | I40E_INSET_SMAC |
+                       I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
+                       I40E_INSET_VLAN_TUNNEL | I40E_INSET_IPV4_TOS |
+                       I40E_INSET_IPV4_PROTO | I40E_INSET_IPV4_TTL |
+                       I40E_INSET_TUNNEL_DMAC | I40E_INSET_TUNNEL_ID |
+                       I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+                       I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
+                       I40E_INSET_TCP_FLAGS | I40E_INSET_FLEX_PAYLOAD,
+               [I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] =
+                       I40E_INSET_DMAC | I40E_INSET_SMAC |
+                       I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
+                       I40E_INSET_VLAN_TUNNEL | I40E_INSET_IPV4_TOS |
+                       I40E_INSET_IPV4_PROTO | I40E_INSET_IPV4_TTL |
+                       I40E_INSET_TUNNEL_DMAC | I40E_INSET_TUNNEL_ID |
+                       I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+                       I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
+                       I40E_INSET_SCTP_VT | I40E_INSET_FLEX_PAYLOAD,
+               [I40E_FILTER_PCTYPE_NONF_IPV4_OTHER] =
+                       I40E_INSET_DMAC | I40E_INSET_SMAC |
+                       I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
+                       I40E_INSET_VLAN_TUNNEL | I40E_INSET_IPV4_TOS |
+                       I40E_INSET_IPV4_PROTO | I40E_INSET_IPV4_TTL |
+                       I40E_INSET_TUNNEL_DMAC | I40E_INSET_TUNNEL_ID |
+                       I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+                       I40E_INSET_FLEX_PAYLOAD,
+               [I40E_FILTER_PCTYPE_FRAG_IPV6] =
+                       I40E_INSET_DMAC | I40E_INSET_SMAC |
+                       I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
+                       I40E_INSET_VLAN_TUNNEL | I40E_INSET_IPV6_TC |
+                       I40E_INSET_IPV6_FLOW | I40E_INSET_IPV6_NEXT_HDR |
+                       I40E_INSET_IPV6_HOP_LIMIT | I40E_INSET_TUNNEL_DMAC |
+                       I40E_INSET_TUNNEL_ID | I40E_INSET_IPV6_SRC |
+                       I40E_INSET_IPV6_DST | I40E_INSET_FLEX_PAYLOAD,
+               [I40E_FILTER_PCTYPE_NONF_IPV6_UDP] =
+                       I40E_INSET_DMAC | I40E_INSET_SMAC |
+                       I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
+                       I40E_INSET_VLAN_TUNNEL | I40E_INSET_IPV6_TC |
+                       I40E_INSET_IPV6_FLOW | I40E_INSET_IPV6_NEXT_HDR |
+                       I40E_INSET_IPV6_HOP_LIMIT | I40E_INSET_IPV6_SRC |
+                       I40E_INSET_IPV6_DST | I40E_INSET_SRC_PORT |
+                       I40E_INSET_DST_PORT | I40E_INSET_FLEX_PAYLOAD,
+               [I40E_FILTER_PCTYPE_NONF_IPV6_TCP] =
+                       I40E_INSET_DMAC | I40E_INSET_SMAC |
+                       I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
+                       I40E_INSET_VLAN_TUNNEL | I40E_INSET_IPV6_TC |
+                       I40E_INSET_IPV6_FLOW | I40E_INSET_IPV6_NEXT_HDR |
+                       I40E_INSET_IPV6_HOP_LIMIT | I40E_INSET_IPV6_SRC |
+                       I40E_INSET_IPV6_DST | I40E_INSET_SRC_PORT |
+                       I40E_INSET_DST_PORT | I40E_INSET_TCP_FLAGS |
+                       I40E_INSET_FLEX_PAYLOAD,
+               [I40E_FILTER_PCTYPE_NONF_IPV6_SCTP] =
+                       I40E_INSET_DMAC | I40E_INSET_SMAC |
+                       I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
+                       I40E_INSET_VLAN_TUNNEL | I40E_INSET_IPV6_TC |
+                       I40E_INSET_IPV6_FLOW | I40E_INSET_IPV6_NEXT_HDR |
+                       I40E_INSET_IPV6_HOP_LIMIT | I40E_INSET_IPV6_SRC |
+                       I40E_INSET_IPV6_DST | I40E_INSET_SRC_PORT |
+                       I40E_INSET_DST_PORT | I40E_INSET_SCTP_VT |
+                       I40E_INSET_FLEX_PAYLOAD,
+               [I40E_FILTER_PCTYPE_NONF_IPV6_OTHER] =
+                       I40E_INSET_DMAC | I40E_INSET_SMAC |
+                       I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
+                       I40E_INSET_VLAN_TUNNEL | I40E_INSET_IPV6_TC |
+                       I40E_INSET_IPV6_FLOW | I40E_INSET_IPV6_NEXT_HDR |
+                       I40E_INSET_IPV6_HOP_LIMIT | I40E_INSET_IPV6_SRC |
+                       I40E_INSET_IPV6_DST | I40E_INSET_FLEX_PAYLOAD,
+               [I40E_FILTER_PCTYPE_L2_PAYLOAD] =
+                       I40E_INSET_DMAC | I40E_INSET_SMAC |
+                       I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
+                       I40E_INSET_VLAN_TUNNEL | I40E_INSET_LAST_ETHER_TYPE |
+                       I40E_INSET_FLEX_PAYLOAD,
+       };
+
+       if (pctype > I40E_FILTER_PCTYPE_L2_PAYLOAD)
+               return -EINVAL;
+
+       if ((inset != I40E_INSET_ALL) && (inset &
+               (~valid_inset_table[pctype])))
+               return -EINVAL;
+
+       return 0;
+}
+
+/* default input set fields combination per pctype */
+static uint64_t
+i40e_get_default_input_set(uint16_t pctype)
+{
+       static const uint64_t default_inset_table[] = {
+               [I40E_FILTER_PCTYPE_FRAG_IPV4] =
+                       I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST,
+               [I40E_FILTER_PCTYPE_NONF_IPV4_UDP] =
+                       I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+                       I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
+               [I40E_FILTER_PCTYPE_NONF_IPV4_TCP] =
+                       I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+                       I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
+               [I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] =
+                       I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+                       I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
+                       I40E_INSET_SCTP_VT,
+               [I40E_FILTER_PCTYPE_NONF_IPV4_OTHER] =
+                       I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST,
+               [I40E_FILTER_PCTYPE_FRAG_IPV6] =
+                       I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST,
+               [I40E_FILTER_PCTYPE_NONF_IPV6_UDP] =
+                       I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
+                       I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
+               [I40E_FILTER_PCTYPE_NONF_IPV6_TCP] =
+                       I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
+                       I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
+               [I40E_FILTER_PCTYPE_NONF_IPV6_SCTP] =
+                       I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
+                       I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
+                       I40E_INSET_SCTP_VT,
+               [I40E_FILTER_PCTYPE_NONF_IPV6_OTHER] =
+                       I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST,
+               [I40E_FILTER_PCTYPE_L2_PAYLOAD] =
+                       I40E_INSET_LAST_ETHER_TYPE,
+       };
+
+       if (pctype > I40E_FILTER_PCTYPE_L2_PAYLOAD)
+               return 0;
+
+       return default_inset_table[pctype];
+}
+
+/**
+ * Parse the input set from index to logical bit masks
+ */
+static uint64_t
+i40e_parse_input_set(enum i40e_filter_pctype pctype,
+                    enum rte_eth_input_set_field *field,
+                    uint16_t size)
+{
+       uint64_t inset = 0;
+       uint16_t i, j;
+
+       static const struct {
+               enum rte_eth_input_set_field field;
+               uint64_t inset;
+       } inset_convert_table[] = {
+               {RTE_ETH_INPUT_SET_L2_SRC_MAC, I40E_INSET_SMAC},
+               {RTE_ETH_INPUT_SET_L2_DST_MAC, I40E_INSET_DMAC},
+               {RTE_ETH_INPUT_SET_L2_OUTER_VLAN, I40E_INSET_VLAN_OUTER},
+               {RTE_ETH_INPUT_SET_L2_INNER_VLAN, I40E_INSET_VLAN_INNER},
+               {RTE_ETH_INPUT_SET_L2_ETHERTYPE, I40E_INSET_LAST_ETHER_TYPE},
+               {RTE_ETH_INPUT_SET_L3_SRC_IP4, I40E_INSET_IPV4_SRC},
+               {RTE_ETH_INPUT_SET_L3_DST_IP4, I40E_INSET_IPV4_DST},
+               {RTE_ETH_INPUT_SET_L3_IP4_TOS, I40E_INSET_IPV4_TOS},
+               {RTE_ETH_INPUT_SET_L3_IP4_PROTO, I40E_INSET_IPV4_PROTO},
+               {RTE_ETH_INPUT_SET_L3_SRC_IP6, I40E_INSET_IPV6_SRC},
+               {RTE_ETH_INPUT_SET_L3_DST_IP6, I40E_INSET_IPV6_DST},
+               {RTE_ETH_INPUT_SET_L3_IP6_TC, I40E_INSET_IPV6_TC},
+               {RTE_ETH_INPUT_SET_L3_IP6_NEXT_HEADER,
+                       I40E_INSET_IPV6_NEXT_HDR},
+               {RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT, I40E_INSET_SRC_PORT},
+               {RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT, I40E_INSET_SRC_PORT},
+               {RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT, I40E_INSET_SRC_PORT},
+               {RTE_ETH_INPUT_SET_L4_UDP_DST_PORT, I40E_INSET_DST_PORT},
+               {RTE_ETH_INPUT_SET_L4_TCP_DST_PORT, I40E_INSET_DST_PORT},
+               {RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT, I40E_INSET_DST_PORT},
+               {RTE_ETH_INPUT_SET_L4_SCTP_VERIFICATION_TAG,
+                       I40E_INSET_SCTP_VT},
+               {RTE_ETH_INPUT_SET_TUNNEL_L2_INNER_DST_MAC,
+                       I40E_INSET_TUNNEL_DMAC},
+               {RTE_ETH_INPUT_SET_TUNNEL_L2_INNER_VLAN,
+                       I40E_INSET_VLAN_TUNNEL},
+               {RTE_ETH_INPUT_SET_TUNNEL_L4_UDP_KEY, I40E_INSET_TUNNEL_ID},
+               {RTE_ETH_INPUT_SET_TUNNEL_GRE_KEY, I40E_INSET_TUNNEL_ID},
+               {RTE_ETH_INPUT_SET_ALL, I40E_INSET_ALL},
+       };
+
+       if (!field || size > RTE_ETH_INSET_SIZE_MAX)
+               return 0;
+
+       /* Only one item allowed for default or all */
+       if (size == 1) {
+               if (field[0] == RTE_ETH_INPUT_SET_DEFAULT)
+                       return i40e_get_default_input_set(pctype);
+               else if (field[0] == RTE_ETH_INPUT_SET_ALL)
+                       return I40E_INSET_ALL;
+       }
+
+       for (i = 0; i < size; i++) {
+               for (j = 0; j < RTE_DIM(inset_convert_table); j++) {
+                       if (field[i] == inset_convert_table[j].field) {
+                               inset |= inset_convert_table[j].inset;
+                               break;
+                       }
+               }
+
+               /* It contains unsupported input set, return 0 immediately */
+               if (j == RTE_DIM(inset_convert_table))
+                       return 0;
+       }
+
+       return inset;
+}
+
+/**
+ * Translate the input set from bit masks to register aware bit masks
+ */
+static uint64_t
+i40e_translate_input_set_reg(uint64_t inset)
+{
+       uint64_t val = 0;
+       uint16_t i;
+
+       static const struct {
+               uint64_t inset;
+               uint64_t inset_reg;
+       } inset_map[] = {
+               {I40E_INSET_DMAC, I40E_REG_INSET_L2_DMAC},
+               {I40E_INSET_SMAC, I40E_REG_INSET_L2_SMAC},
+               {I40E_INSET_VLAN_OUTER, I40E_REG_INSET_L2_OUTER_VLAN},
+               {I40E_INSET_VLAN_INNER, I40E_REG_INSET_L2_INNER_VLAN},
+               {I40E_INSET_LAST_ETHER_TYPE, I40E_REG_INSET_LAST_ETHER_TYPE},
+               {I40E_INSET_IPV4_SRC, I40E_REG_INSET_L3_SRC_IP4},
+               {I40E_INSET_IPV4_DST, I40E_REG_INSET_L3_DST_IP4},
+               {I40E_INSET_IPV6_SRC, I40E_REG_INSET_L3_SRC_IP6},
+               {I40E_INSET_IPV6_DST, I40E_REG_INSET_L3_DST_IP6},
+               {I40E_INSET_SRC_PORT, I40E_REG_INSET_L4_SRC_PORT},
+               {I40E_INSET_DST_PORT, I40E_REG_INSET_L4_DST_PORT},
+               {I40E_INSET_SCTP_VT, I40E_REG_INSET_L4_SCTP_VERIFICATION_TAG},
+               {I40E_INSET_TUNNEL_ID, I40E_REG_INSET_TUNNEL_GRE_KEY},
+               {I40E_INSET_TUNNEL_DMAC,
+                       I40E_REG_INSET_TUNNEL_L2_INNER_DST_MAC},
+               {I40E_INSET_TUNNEL_IPV4_DST, I40E_REG_INSET_TUNNEL_L3_DST_IP4},
+               {I40E_INSET_TUNNEL_IPV6_DST, I40E_REG_INSET_TUNNEL_L3_DST_IP6},
+               {I40E_INSET_TUNNEL_SRC_PORT,
+                       I40E_REG_INSET_TUNNEL_L4_UDP_SRC_PORT},
+               {I40E_INSET_TUNNEL_DST_PORT,
+                       I40E_REG_INSET_TUNNEL_L4_UDP_DST_PORT},
+               {I40E_INSET_FLEX_PAYLOAD_W1, I40E_REG_INSET_FLEX_PAYLOAD_WORD1},
+               {I40E_INSET_FLEX_PAYLOAD_W2, I40E_REG_INSET_FLEX_PAYLOAD_WORD2},
+               {I40E_INSET_FLEX_PAYLOAD_W3, I40E_REG_INSET_FLEX_PAYLOAD_WORD3},
+               {I40E_INSET_FLEX_PAYLOAD_W4, I40E_REG_INSET_FLEX_PAYLOAD_WORD4},
+               {I40E_INSET_FLEX_PAYLOAD_W5, I40E_REG_INSET_FLEX_PAYLOAD_WORD5},
+               {I40E_INSET_FLEX_PAYLOAD_W6, I40E_REG_INSET_FLEX_PAYLOAD_WORD6},
+               {I40E_INSET_FLEX_PAYLOAD_W7, I40E_REG_INSET_FLEX_PAYLOAD_WORD7},
+               {I40E_INSET_FLEX_PAYLOAD_W8, I40E_REG_INSET_FLEX_PAYLOAD_WORD8},
+       };
+
+       if (inset == I40E_INSET_ALL)
+               return I40E_REG_INSET_ALL;
+
+       for (i = 0; i < RTE_DIM(inset_map); i++) {
+               if (inset & inset_map[i].inset)
+                       val |= inset_map[i].inset_reg;
+       }
+
+       return val;
+}
+
+static int
+i40e_generate_inset_mask_reg(uint64_t inset, uint64_t *mask)
+{
+       uint8_t idx = 0;
+
+       if (!mask)
+               return -EINVAL;
+
+       *mask = I40E_REG_INSET_MASK_DEFAULT;
+       if (inset & I40E_INSET_IPV4_TOS) {
+               *mask |= (0x0009FF00 << (idx * 32));
+               idx++;
+       }
+       if (inset & I40E_INSET_IPV4_PROTO) {
+               *mask |= (0x000DFF00 << (idx * 32));
+               idx++;
+       }
+
+       return idx;
+}
+
+static void
+i40e_check_modify_reg(struct i40e_hw *hw, uint32_t addr,
+                           uint32_t val, uint8_t enable)
+{
+       uint32_t reg, reg_o = I40E_READ_REG(hw, addr);
+
+       PMD_DRV_LOG(DEBUG, "[0x%08x] original: 0x%08x\n", addr, reg_o);
+       if (enable)
+               reg = reg_o | val;
+       else
+               reg = reg_o & ~val;
+       if (reg != reg_o)
+               I40E_WRITE_REG(hw, addr, reg);
+       PMD_DRV_LOG(DEBUG, "[0x%08x] after: 0x%08x\n", addr,
+                   (uint32_t)I40E_READ_REG(hw, addr));
+}
+
+static void
+i40e_check_write_reg(struct i40e_hw *hw, uint32_t addr, uint32_t val)
+{
+       uint32_t reg = I40E_READ_REG(hw, addr);
+
+       PMD_DRV_LOG(DEBUG, "[0x%08x] original: 0x%08x\n", addr, reg);
+       if (reg != val)
+               I40E_WRITE_REG(hw, addr, val);
+       PMD_DRV_LOG(DEBUG, "[0x%08x] after: 0x%08x\n", addr,
+                   (uint32_t)I40E_READ_REG(hw, addr));
+}
+
+static int
+i40e_check_write_mask_reg(struct i40e_hw *hw, uint32_t addr, uint32_t val)
+{
+       uint32_t reg = I40E_READ_REG(hw, addr);
+
+       PMD_DRV_LOG(DEBUG, "[0x%08x] original: 0x%08x\n", addr, reg);
+       if (reg != 0)
+               return -EINVAL;
+       I40E_WRITE_REG(hw, addr, val);
+       PMD_DRV_LOG(DEBUG, "[0x%08x] after: 0x%08x\n", addr,
+                   (uint32_t)I40E_READ_REG(hw, addr));
+
+       return 0;
+}
+
+int
+i40e_filter_inset_select(struct i40e_hw *hw,
+                         struct rte_eth_input_set_conf *conf,
+                         enum rte_filter_type filter)
+{
+       enum i40e_filter_pctype pctype;
+       uint64_t inset_reg, mask_reg;
+       uint64_t input_set;
+       uint32_t reg;
+       int num, i;
+
+       if (!hw || !conf) {
+               PMD_DRV_LOG(ERR, "Invalid pointer");
+               return -EFAULT;
+       }
+       pctype = i40e_flowtype_to_pctype(conf->flow_type);
+       if (pctype == 0 ||
+               pctype > I40E_FILTER_PCTYPE_L2_PAYLOAD || (filter !=
+               RTE_ETH_FILTER_HASH && filter != RTE_ETH_FILTER_FDIR)) {
+               return -EINVAL;
+       }
+
+       input_set = i40e_parse_input_set(pctype, conf->field,
+                                        conf->inset_size);
+       if (!input_set)
+               return -EINVAL;
+
+       if (i40e_validate_input_set(pctype, input_set) != 0)
+               return -EINVAL;
+
+       if (input_set == I40E_INSET_ALL && conf->enable) {
+               /* Return with failure if trying to enable all */
+               return -EINVAL;
+       } else if (input_set == I40E_INSET_ALL && !conf->enable) {
+               /* Clear all registers if trying to disable all */
+               if (filter == RTE_ETH_FILTER_HASH) {
+                       i40e_check_write_reg(hw,
+                                            I40E_GLQF_HASH_INSET(0, pctype),
+                                            0x0);
+                       i40e_check_write_reg(hw,
+                                            I40E_GLQF_HASH_INSET(1, pctype),
+                                            0x0);
+                       i40e_check_write_reg(hw,
+                                            I40E_GLQF_HASH_MSK(0, pctype),
+                                            0x0);
+                       i40e_check_write_reg(hw,
+                                            I40E_GLQF_HASH_MSK(1, pctype),
+                                            0x0);
+               } else if (filter == RTE_ETH_FILTER_FDIR) {
+                       i40e_check_write_reg(hw,
+                                            I40E_PRTQF_FD_INSET(pctype, 0),
+                                            0x0);
+                       i40e_check_write_reg(hw,
+                                            I40E_PRTQF_FD_INSET(pctype, 1),
+                                            0x0);
+                       i40e_check_write_reg(hw, I40E_PRTQF_FD_MSK(pctype, 0),
+                                            0x0);
+                       i40e_check_write_reg(hw, I40E_PRTQF_FD_MSK(pctype, 1),
+                                            0x0);
+               }
+               I40E_WRITE_FLUSH(hw);
+
+               return 0;
+       }
+
+       inset_reg = i40e_translate_input_set_reg(input_set);
+       if (!inset_reg)
+               return -EINVAL;
+
+       num = i40e_generate_inset_mask_reg(input_set, &mask_reg);
+       if (num < 0 || num > 2)
+               return -EINVAL;
+
+       if (filter == RTE_ETH_FILTER_HASH) {
+               i40e_check_modify_reg(hw, I40E_GLQF_HASH_INSET(0, pctype),
+                                     (uint32_t)(inset_reg & 0xFFFFFFFF),
+                                     conf->enable);
+               i40e_check_modify_reg(hw, I40E_GLQF_HASH_INSET(1, pctype),
+                                     (uint32_t)((inset_reg >> 32) &
+                                     0xFFFFFFFF), conf->enable);
+
+               for (i = 0; i < num; i++) {
+                       reg = (uint32_t)(mask_reg >> (i * 32));
+                       if (i40e_check_write_mask_reg(hw,
+                                                     I40E_GLQF_HASH_MSK(0,
+                                                     pctype), reg) == 0)
+                               continue;
+                       if (i40e_check_write_mask_reg(hw,
+                                                     I40E_GLQF_HASH_MSK(1,
+                                                     pctype), reg) < 0)
+                               return -EINVAL;
+               }
+       } else if (filter == RTE_ETH_FILTER_FDIR) {
+               i40e_check_modify_reg(hw, I40E_PRTQF_FD_INSET(pctype, 0),
+                                     (uint32_t)(inset_reg & 0xFFFFFFFF),
+                                     conf->enable);
+               i40e_check_modify_reg(hw, I40E_PRTQF_FD_INSET(pctype, 1),
+                                     (uint32_t)((inset_reg >> 32) &
+                                     0xFFFFFFFF), conf->enable);
+               for (i = 0; i < num; i++) {
+                       reg = (uint32_t)(mask_reg >> (i * 32));
+                       if (i40e_check_write_mask_reg(hw,
+                               I40E_PRTQF_FD_MSK(pctype, 0), reg) == 0)
+                               continue;
+                       if (i40e_check_write_mask_reg(hw,
+                               I40E_PRTQF_FD_MSK(pctype, 1), reg) < 0)
+                               return -EINVAL;
+               }
+       } else {
+               return -EINVAL;
+       }
+       I40E_WRITE_FLUSH(hw);
+
+       return 0;
+}
+
 static int
 i40e_hash_filter_get(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
 {
@@ -5498,6 +6083,12 @@ i40e_hash_filter_set(struct i40e_hw *hw, struct 
rte_eth_hash_filter_info *info)
                ret = i40e_set_hash_filter_global_config(hw,
                                &(info->info.global_conf));
                break;
+       case RTE_ETH_HASH_FILTER_INPUT_SET_SELECT:
+               ret = i40e_filter_inset_select(hw,
+                                              &(info->info.input_set_conf),
+                                              RTE_ETH_FILTER_HASH);
+               break;
+
        default:
                PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
                                                        info->info_type);
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 6185657..a997a08 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -501,6 +501,12 @@ uint16_t i40e_pctype_to_flowtype(enum i40e_filter_pctype 
pctype);
 int i40e_fdir_ctrl_func(struct rte_eth_dev *dev,
                          enum rte_filter_op filter_op,
                          void *arg);
+int i40e_select_filter_input_set(struct i40e_hw *hw,
+                                struct rte_eth_input_set_conf *conf,
+                                enum rte_filter_type filter);
+int i40e_filter_inset_select(struct i40e_hw *hw,
+                            struct rte_eth_input_set_conf *conf,
+                            enum rte_filter_type filter);

 /* I40E_DEV_PRIVATE_TO */
 #define I40E_DEV_PRIVATE_TO_PF(adapter) \
diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c
index c9ce98f..ba18c9d 100644
--- a/drivers/net/i40e/i40e_fdir.c
+++ b/drivers/net/i40e/i40e_fdir.c
@@ -1342,6 +1342,33 @@ i40e_fdir_stats_get(struct rte_eth_dev *dev, struct 
rte_eth_fdir_stats *stat)
                            I40E_PFQF_FDSTAT_BEST_CNT_SHIFT);
 }

+static int
+i40e_fdir_filter_set(struct rte_eth_dev *dev,
+                    struct rte_eth_hash_filter_info *info)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+       int ret = 0;
+
+       if (!info) {
+               PMD_DRV_LOG(ERR, "Invalid pointer");
+               return -EFAULT;
+       }
+
+       switch (info->info_type) {
+       case RTE_ETH_FDIR_FILTER_INPUT_SET_SELECT:
+               ret = i40e_filter_inset_select(hw,
+                       &(info->info.input_set_conf), RTE_ETH_FILTER_FDIR);
+               break;
+       default:
+               PMD_DRV_LOG(ERR, "FD filter info type (%d) not supported",
+                           info->info_type);
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
 /*
  * i40e_fdir_ctrl_func - deal with all operations on flow director.
  * @pf: board private structure
@@ -1382,6 +1409,10 @@ i40e_fdir_ctrl_func(struct rte_eth_dev *dev,
        case RTE_ETH_FILTER_INFO:
                i40e_fdir_info_get(dev, (struct rte_eth_fdir_info *)arg);
                break;
+       case RTE_ETH_FILTER_SET:
+               ret = i40e_fdir_filter_set(dev,
+                       (struct rte_eth_hash_filter_info *)arg);
+               break;
        case RTE_ETH_FILTER_STATS:
                i40e_fdir_stats_get(dev, (struct rte_eth_fdir_stats *)arg);
                break;
diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index 26b7b33..2a1eb36 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -295,7 +295,73 @@ struct rte_eth_tunnel_filter_conf {
        uint16_t queue_id;      /** < queue number. */
 };

-#define RTE_ETH_FDIR_MAX_FLEXLEN         16 /** < Max length of flexbytes. */
+#define RTE_ETH_FDIR_MAX_FLEXLEN 16 /** < Max length of flexbytes. */
+#define RTE_ETH_INSET_SIZE_MAX   128 /** < Max length of input set. */
+
+/**
+ * Input set fields for Flow Director and Hash filters
+ */
+enum rte_eth_input_set_field {
+       RTE_ETH_INPUT_SET_UNKNOWN = 0,
+
+       /* L2 */
+       RTE_ETH_INPUT_SET_L2_SRC_MAC = 1,
+       RTE_ETH_INPUT_SET_L2_DST_MAC,
+       RTE_ETH_INPUT_SET_L2_OUTER_VLAN,
+       RTE_ETH_INPUT_SET_L2_INNER_VLAN,
+       RTE_ETH_INPUT_SET_L2_ETHERTYPE,
+
+       /* L3 */
+       RTE_ETH_INPUT_SET_L3_SRC_IP4 = 129,
+       RTE_ETH_INPUT_SET_L3_DST_IP4,
+       RTE_ETH_INPUT_SET_L3_SRC_IP6,
+       RTE_ETH_INPUT_SET_L3_DST_IP6,
+       RTE_ETH_INPUT_SET_L3_IP4_TOS,
+       RTE_ETH_INPUT_SET_L3_IP4_PROTO,
+       RTE_ETH_INPUT_SET_L3_IP6_TC,
+       RTE_ETH_INPUT_SET_L3_IP6_NEXT_HEADER,
+
+       /* L4 */
+       RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT = 257,
+       RTE_ETH_INPUT_SET_L4_UDP_DST_PORT,
+       RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT,
+       RTE_ETH_INPUT_SET_L4_TCP_DST_PORT,
+       RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT,
+       RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT,
+       RTE_ETH_INPUT_SET_L4_SCTP_VERIFICATION_TAG,
+
+       /* Tunnel */
+       RTE_ETH_INPUT_SET_TUNNEL_L2_INNER_DST_MAC = 385,
+       RTE_ETH_INPUT_SET_TUNNEL_L2_INNER_SRC_MAC,
+       RTE_ETH_INPUT_SET_TUNNEL_L2_INNER_VLAN,
+       RTE_ETH_INPUT_SET_TUNNEL_L4_UDP_KEY,
+       RTE_ETH_INPUT_SET_TUNNEL_GRE_KEY,
+
+       /* Flexible Payload */
+       RTE_ETH_INPUT_SET_FLEX_PAYLOAD_1ST_WORD = 641,
+       RTE_ETH_INPUT_SET_FLEX_PAYLOAD_2ND_WORD,
+       RTE_ETH_INPUT_SET_FLEX_PAYLOAD_3RD_WORD,
+       RTE_ETH_INPUT_SET_FLEX_PAYLOAD_4TH_WORD,
+       RTE_ETH_INPUT_SET_FLEX_PAYLOAD_5TH_WORD,
+       RTE_ETH_INPUT_SET_FLEX_PAYLOAD_6TH_WORD,
+       RTE_ETH_INPUT_SET_FLEX_PAYLOAD_7TH_WORD,
+       RTE_ETH_INPUT_SET_FLEX_PAYLOAD_8TH_WORD,
+
+       RTE_ETH_INPUT_SET_DEFAULT = 65533,
+       RTE_ETH_INPUT_SET_ALL = 65534,
+       RTE_ETH_INPUT_SET_MAX = 65535,
+};
+
+/**
+ * A structure used to define the input set configuration for
+ * flow director and hash filters
+ */
+struct rte_eth_input_set_conf {
+       uint16_t flow_type;
+       uint16_t inset_size;
+       enum rte_eth_input_set_field field[RTE_ETH_INSET_SIZE_MAX];
+       uint8_t enable;
+};

 /**
  * A structure used to define the input for L2 flow
@@ -504,7 +570,7 @@ struct rte_eth_fdir_flex_mask {

 /**
  * A structure used to define all flexible payload related setting
- * include flexpay load and flex mask
+ * include flex payload and flex mask
  */
 struct rte_eth_fdir_flex_conf {
        uint16_t nb_payloads;  /**< The number of following payload cfg */
@@ -582,12 +648,40 @@ struct rte_eth_fdir_stats {
 };

 /**
+ * Flow Director filter information types.
+ */
+enum rte_eth_fdir_filter_info_type {
+       RTE_ETH_FDIR_FILTER_INFO_TYPE_UNKNOWN = 0,
+       /** Flow Director filter input set configuration */
+       RTE_ETH_FDIR_FILTER_INPUT_SET_SELECT,
+       RTE_ETH_FDIR_FILTER_INFO_TYPE_MAX,
+};
+
+/**
+ * A structure used to set or get hash filter information, to support filter
+ * type of 'RTE_ETH_FILTER_FDIR' RTE_ETH_FILTER_SET operation.
+ */
+/**
+ * A structure used to support Flow Director RTE_ETH_FILTER_SET operations
+  */
+struct rte_eth_fdir_filter_info {
+       enum rte_eth_fdir_filter_info_type info_type; /**< Information type */
+       /** Details of fdir filter information */
+       union {
+               /** Flow Director input set configuration per port */
+               struct rte_eth_input_set_conf input_set_conf;
+       } info;
+};
+
+/**
  * Hash filter information types.
  * - RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT is for getting/setting the
  *   information/configuration of 'symmetric hash enable' per port.
  * - RTE_ETH_HASH_FILTER_GLOBAL_CONFIG is for getting/setting the global
  *   configurations of hash filters. Those global configurations are valid
  *   for all ports of the same NIC.
+ * - RTE_ETH_HASH_FILTER_INPUT_SET_SELECT is for setting the global
+ *   hash input set fields
  */
 enum rte_eth_hash_filter_info_type {
        RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
@@ -595,6 +689,8 @@ enum rte_eth_hash_filter_info_type {
        RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT,
        /** Configure globally for hash filter */
        RTE_ETH_HASH_FILTER_GLOBAL_CONFIG,
+       /** Global Hash filter input set configuration */
+       RTE_ETH_HASH_FILTER_INPUT_SET_SELECT,
        RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
 };

@@ -614,7 +710,7 @@ enum rte_eth_hash_function {
  * A structure used to set or get global hash function configurations which
  * include symmetric hash enable per flow type and hash function type.
  * Each bit in sym_hash_enable_mask[] indicates if the symmetric hash of the
- * coresponding flow type is enabled or not.
+ * corresponding flow type is enabled or not.
  * Each bit in valid_bit_mask[] indicates if the corresponding bit in
  * sym_hash_enable_mask[] is valid or not. For the configurations gotten, it
  * also means if the flow type is supported by hardware or not.
@@ -639,6 +735,8 @@ struct rte_eth_hash_filter_info {
                uint8_t enable;
                /** Global configurations of hash filter */
                struct rte_eth_hash_global_conf global_conf;
+               /** Global configurations of hash filter input set */
+               struct rte_eth_input_set_conf input_set_conf;
        } info;
 };

-- 
1.9.3

Reply via email to