From patchwork Tue Sep 22 07:26:09 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Zhang, Helin" X-Patchwork-Id: 7115 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 6C77E8DAE; Tue, 22 Sep 2015 09:26:26 +0200 (CEST) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by dpdk.org (Postfix) with ESMTP id 471478DAC for ; Tue, 22 Sep 2015 09:26:24 +0200 (CEST) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga103.jf.intel.com with ESMTP; 22 Sep 2015 00:26:23 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.17,571,1437462000"; d="scan'208";a="566063814" Received: from shvmail01.sh.intel.com ([10.239.29.42]) by FMSMGA003.fm.intel.com with ESMTP; 22 Sep 2015 00:26:21 -0700 Received: from shecgisg004.sh.intel.com (shecgisg004.sh.intel.com [10.239.29.89]) by shvmail01.sh.intel.com with ESMTP id t8M7QIv5008109; Tue, 22 Sep 2015 15:26:18 +0800 Received: from shecgisg004.sh.intel.com (localhost [127.0.0.1]) by shecgisg004.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP id t8M7QE9Y018846; Tue, 22 Sep 2015 15:26:16 +0800 Received: (from hzhan75@localhost) by shecgisg004.sh.intel.com (8.13.6/8.13.6/Submit) id t8M7QESM018842; Tue, 22 Sep 2015 15:26:14 +0800 From: Helin Zhang To: dev@dpdk.org Date: Tue, 22 Sep 2015 15:26:09 +0800 Message-Id: <1442906770-18805-2-git-send-email-helin.zhang@intel.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1442906770-18805-1-git-send-email-helin.zhang@intel.com> References: <1442903547-18198-1-git-send-email-helin.zhang@intel.com> <1442906770-18805-1-git-send-email-helin.zhang@intel.com> Cc: yulong.pei@intel.com Subject: [dpdk-dev] [PATCH v2 1/2] i40e: add RSS granularity configuration X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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 Signed-off-by: Andrey Chilikin --- 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; };