get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/724788/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 724788,
    "url": "http://patchwork.ozlabs.org/api/patches/724788/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20170206223852.31177-8-jacob.e.keller@intel.com/",
    "project": {
        "id": 46,
        "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api",
        "name": "Intel Wired Ethernet development",
        "link_name": "intel-wired-lan",
        "list_id": "intel-wired-lan.osuosl.org",
        "list_email": "intel-wired-lan@osuosl.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20170206223852.31177-8-jacob.e.keller@intel.com>",
    "list_archive_url": null,
    "date": "2017-02-06T22:38:50",
    "name": "[PART2,7/9] i40e: implement support for flexible word payload",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "bc6109a0dea7e43fed49505cf8a00d37d2909ddb",
    "submitter": {
        "id": 9784,
        "url": "http://patchwork.ozlabs.org/api/people/9784/?format=api",
        "name": "Jacob Keller",
        "email": "jacob.e.keller@intel.com"
    },
    "delegate": {
        "id": 68,
        "url": "http://patchwork.ozlabs.org/api/users/68/?format=api",
        "username": "jtkirshe",
        "first_name": "Jeff",
        "last_name": "Kirsher",
        "email": "jeffrey.t.kirsher@intel.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20170206223852.31177-8-jacob.e.keller@intel.com/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/724788/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/724788/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<intel-wired-lan-bounces@lists.osuosl.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Received": [
            "from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3vHMpf4tNxz9s1y\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue,  7 Feb 2017 09:39:22 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id 3472630A45;\n\tMon,  6 Feb 2017 22:39:21 +0000 (UTC)",
            "from silver.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id UxIspBsZ7+xw; Mon,  6 Feb 2017 22:39:09 +0000 (UTC)",
            "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby silver.osuosl.org (Postfix) with ESMTP id 17F3930A48;\n\tMon,  6 Feb 2017 22:39:02 +0000 (UTC)",
            "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\tby ash.osuosl.org (Postfix) with ESMTP id AAD9D1BFF07\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon,  6 Feb 2017 22:38:57 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id A6F5089EF6\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon,  6 Feb 2017 22:38:57 +0000 (UTC)",
            "from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id mHOgkXuoMfaP for <intel-wired-lan@lists.osuosl.org>;\n\tMon,  6 Feb 2017 22:38:55 +0000 (UTC)",
            "from mga11.intel.com (mga11.intel.com [192.55.52.93])\n\tby hemlock.osuosl.org (Postfix) with ESMTPS id B094189EF2\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon,  6 Feb 2017 22:38:55 +0000 (UTC)",
            "from fmsmga005.fm.intel.com ([10.253.24.32])\n\tby fmsmga102.fm.intel.com with ESMTP; 06 Feb 2017 14:38:54 -0800",
            "from jekeller-desk.amr.corp.intel.com (HELO\n\tjekeller-desk.jekeller.internal) ([10.166.35.174])\n\tby fmsmga005.fm.intel.com with ESMTP; 06 Feb 2017 14:38:54 -0800"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.33,342,1477983600\"; d=\"scan'208\";a=\"61907701\"",
        "From": "Jacob Keller <jacob.e.keller@intel.com>",
        "To": "Intel Wired LAN <intel-wired-lan@lists.osuosl.org>",
        "Date": "Mon,  6 Feb 2017 14:38:50 -0800",
        "Message-Id": "<20170206223852.31177-8-jacob.e.keller@intel.com>",
        "X-Mailer": "git-send-email 2.12.0.rc0.151.g8a5726c42288",
        "In-Reply-To": "<20170206223852.31177-1-jacob.e.keller@intel.com>",
        "References": "<20170206223852.31177-1-jacob.e.keller@intel.com>",
        "Subject": "[Intel-wired-lan] [PART2 PATCH 7/9] i40e: implement support for\n\tflexible word payload",
        "X-BeenThere": "intel-wired-lan@lists.osuosl.org",
        "X-Mailman-Version": "2.1.18-1",
        "Precedence": "list",
        "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.lists.osuosl.org>",
        "List-Unsubscribe": "<http://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@lists.osuosl.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>",
        "List-Post": "<mailto:intel-wired-lan@lists.osuosl.org>",
        "List-Help": "<mailto:intel-wired-lan-request@lists.osuosl.org?subject=help>",
        "List-Subscribe": "<http://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@lists.osuosl.org?subject=subscribe>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "intel-wired-lan-bounces@lists.osuosl.org",
        "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@lists.osuosl.org>"
    },
    "content": "Add support for flexible payloads passed via ethtool user-def field.\nThis support is somewhat limited due to hardware design. The input set\ncan only be programmed once per filter type, and the flexible offset is\npart of this filter input set. This means that the user cannot program\nboth a regular and a flexible filter at the same time for a given flow\ntype. Additionally, the user may not program two flexible filters of the\nsame flow type with different offsets, although they are allowed to\nconfigure different values at that offset location.\n\nWe support a single flexible word (2byte) value per protocol type, and\nwe handle the FLX_PIT register using a list of flexible entries so that\neach flow type may be configured separately.\n\nDue to hardware implementation, the flexible data is offset from the\nstart of the packet payload, and thus may not be in part of the header\ndata. For this reason, the offset provided by the user defined data is\ninterpreted as a byte offset from the start of the matching payload.\nPrevious implementations have tried to represent the offset as from the\nstart of the frame, but this is not feasible because header sizes may\nchange due to options.\n\nTesting-hints:\n  Need to ensure that multiple filters with same flex offset behave\n  correctly, and ensure that different L4 protocols inter-operate\n  correctly. README changes for this will be forth-coming.\n\nSigned-off-by: Jacob Keller <jacob.e.keller@intel.com>\nChange-Id: 36ed27995e97de63f9aea5ade5778ff038d6f811\n---\n drivers/net/ethernet/intel/i40e/i40e.h         |  83 +++++\n drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 494 ++++++++++++++++++++++++-\n drivers/net/ethernet/intel/i40e/i40e_main.c    |  16 +\n drivers/net/ethernet/intel/i40e/i40e_txrx.c    |  27 ++\n 4 files changed, 608 insertions(+), 12 deletions(-)",
    "diff": "diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h\nindex bffcfc1041e7..f218a5bb7a16 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e.h\n@@ -226,6 +226,12 @@ struct i40e_fdir_filter {\n \t__be16 src_port;\n \t__be16 dst_port;\n \t__be32 sctp_v_tag;\n+\n+\t/* Flexible data to match within the packet payload */\n+\t__be16 flex_word;\n+\tu16 flex_offset;\n+\tbool flex_filter;\n+\n \t/* filter control */\n \tu16 q_index;\n \tu8  flex_off;\n@@ -262,6 +268,75 @@ struct i40e_udp_port_config {\n \tu8 type;\n };\n \n+/* macros related to FLX_PIT */\n+#define I40E_FLEX_SET_FSIZE(fsize) (((fsize) << \\\n+\t\t\t\t    I40E_PRTQF_FLX_PIT_FSIZE_SHIFT) & \\\n+\t\t\t\t    I40E_PRTQF_FLX_PIT_FSIZE_MASK)\n+#define I40E_FLEX_SET_DST_WORD(dst) (((dst) << \\\n+\t\t\t\t     I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT) & \\\n+\t\t\t\t     I40E_PRTQF_FLX_PIT_DEST_OFF_MASK)\n+#define I40E_FLEX_SET_SRC_WORD(src) (((src) << \\\n+\t\t\t\t     I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT) & \\\n+\t\t\t\t     I40E_PRTQF_FLX_PIT_SOURCE_OFF_MASK)\n+#define I40E_FLEX_PREP_VAL(dst, fsize, src) (I40E_FLEX_SET_DST_WORD(dst) | \\\n+\t\t\t\t\t     I40E_FLEX_SET_FSIZE(fsize) | \\\n+\t\t\t\t\t     I40E_FLEX_SET_SRC_WORD(src))\n+\n+#define I40E_FLEX_PIT_GET_SRC(flex) (((flex) & \\\n+\t\t\t\t     I40E_PRTQF_FLX_PIT_SOURCE_OFF_MASK) >> \\\n+\t\t\t\t     I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT)\n+#define I40E_FLEX_PIT_GET_DST(flex) (((flex) & \\\n+\t\t\t\t     I40E_PRTQF_FLX_PIT_DEST_OFF_MASK) >> \\\n+\t\t\t\t     I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT)\n+#define I40E_FLEX_PIT_GET_FSIZE(flex) (((flex) & \\\n+\t\t\t\t       I40E_PRTQF_FLX_PIT_FSIZE_MASK) >> \\\n+\t\t\t\t       I40E_PRTQF_FLX_PIT_FSIZE_SHIFT)\n+\n+#define I40E_MAX_FLEX_SRC_OFFSET 0x1F\n+\n+/* macros related to GLQF_ORT */\n+#define I40E_ORT_SET_IDX(idx)\t\t(((idx) << \\\n+\t\t\t\t\t  I40E_GLQF_ORT_PIT_INDX_SHIFT) & \\\n+\t\t\t\t\t I40E_GLQF_ORT_PIT_INDX_MASK)\n+\n+#define I40E_ORT_SET_COUNT(count)\t(((count) << \\\n+\t\t\t\t\t  I40E_GLQF_ORT_FIELD_CNT_SHIFT) & \\\n+\t\t\t\t\t I40E_GLQF_ORT_FIELD_CNT_MASK)\n+\n+#define I40E_ORT_SET_PAYLOAD(payload)\t(((payload) << \\\n+\t\t\t\t\t  I40E_GLQF_ORT_FLX_PAYLOAD_SHIFT) & \\\n+\t\t\t\t\t I40E_GLQF_ORT_FLX_PAYLOAD_MASK)\n+\n+#define I40E_ORT_PREP_VAL(idx, count, payload) (I40E_ORT_SET_IDX(idx) | \\\n+\t\t\t\t\t\tI40E_ORT_SET_COUNT(count) | \\\n+\t\t\t\t\t\tI40E_ORT_SET_PAYLOAD(payload))\n+\n+#define I40E_L3_GLQF_ORT_IDX\t\t34\n+#define I40E_L4_GLQF_ORT_IDX\t\t35\n+\n+/* Flex PIT register index */\n+#define I40E_FLEX_PIT_IDX_START_L2\t0\n+#define I40E_FLEX_PIT_IDX_START_L3\t3\n+#define I40E_FLEX_PIT_IDX_START_L4\t6\n+\n+#define I40E_FLEX_PIT_TABLE_SIZE\t3\n+\n+#define I40E_FLEX_DEST_UNUSED\t\t63\n+\n+#define I40E_FLEX_INDEX_ENTRIES\t\t8\n+\n+/* Flex MASK to disable all flexible entries */\n+#define I40E_FLEX_INPUT_MASK\t(I40E_FLEX_50_MASK | I40E_FLEX_51_MASK | \\\n+\t\t\t\t I40E_FLEX_52_MASK | I40E_FLEX_53_MASK | \\\n+\t\t\t\t I40E_FLEX_54_MASK | I40E_FLEX_55_MASK | \\\n+\t\t\t\t I40E_FLEX_56_MASK | I40E_FLEX_57_MASK)\n+\n+struct i40e_flex_pit {\n+\tstruct list_head list;\n+\tu16 src_offset;\n+\tu8 pit_index;\n+};\n+\n /* struct that defines the Ethernet device */\n struct i40e_pf {\n \tstruct pci_dev *pdev;\n@@ -308,6 +383,14 @@ struct i40e_pf {\n \tu16 fd_udp4_filter_cnt;\n \tu16 fd_ip4_filter_cnt;\n \n+\t/* Flexible filter table values that need to be programmed into\n+\t * hardware, which expects L3 and L4 to be programmed separately. We\n+\t * need to ensure that the values are in ascended order and don't have\n+\t * duplicates, so we track each L3 and L4 values in separate lists.\n+\t */\n+\tstruct list_head l3_flex_pit_list;\n+\tstruct list_head l4_flex_pit_list;\n+\n \tstruct i40e_udp_port_config udp_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];\n \tu16 pending_udp_bitmap;\n \ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c\nindex 56adffa049d6..2dce5f5a486e 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c\n@@ -2525,6 +2525,12 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,\n \t\t}\n \t}\n \n+\tif (rule->flex_filter) {\n+\t\tuserdef.flex_filter = true;\n+\t\tuserdef.flex_word = be16_to_cpu(rule->flex_word);\n+\t\tuserdef.flex_offset = rule->flex_offset;\n+\t}\n+\n \ti40e_fill_rx_flow_user_data(fsp, &userdef);\n \n \treturn 0;\n@@ -2789,6 +2795,68 @@ static int i40e_update_ethtool_fdir_entry(struct i40e_vsi *vsi,\n \treturn 0;\n }\n \n+/** i40e_prune_flex_pit_list - Cleanup unused entries in FLX_PIT table\n+ * @pf: pointer to PF structure\n+ *\n+ * This function searches the list of filters and determines which FLX_PIT\n+ * entries are still required. It will prune any entries which are no longer\n+ * in use after the deletion.\n+ */\n+static void i40e_prune_flex_pit_list(struct i40e_pf *pf)\n+{\n+\tstruct i40e_flex_pit *entry, *tmp;\n+\tstruct i40e_fdir_filter *rule;\n+\n+\t/* First, we'll check the l3 table */\n+\tlist_for_each_entry_safe(entry, tmp, &pf->l3_flex_pit_list, list) {\n+\t\tbool found = false;\n+\n+\t\thlist_for_each_entry(rule, &pf->fdir_filter_list, fdir_node) {\n+\t\t\tif (rule->flow_type != IP_USER_FLOW)\n+\t\t\t\tcontinue;\n+\t\t\tif (rule->flex_filter &&\n+\t\t\t    rule->flex_offset == entry->src_offset) {\n+\t\t\t\tfound = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* If we didn't find the filter, then we can prune this entry\n+\t\t * from the list.\n+\t\t */\n+\t\tif (!found) {\n+\t\t\tlist_del(&entry->list);\n+\t\t\tkfree(entry);\n+\t\t}\n+\t}\n+\n+\t/* Followed by the L4 table */\n+\tlist_for_each_entry_safe(entry, tmp, &pf->l4_flex_pit_list, list) {\n+\t\tbool found = false;\n+\n+\t\thlist_for_each_entry(rule, &pf->fdir_filter_list, fdir_node) {\n+\t\t\t/* Skip this filter if it's L3, since we already\n+\t\t\t * checked those in the above loop\n+\t\t\t */\n+\t\t\tif (rule->flow_type == IP_USER_FLOW)\n+\t\t\t\tcontinue;\n+\t\t\tif (rule->flex_filter &&\n+\t\t\t    rule->flex_offset == entry->src_offset) {\n+\t\t\t\tfound = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* If we didn't find the filter, then we can prune this entry\n+\t\t * from the list.\n+\t\t */\n+\t\tif (!found) {\n+\t\t\tlist_del(&entry->list);\n+\t\t\tkfree(entry);\n+\t\t}\n+\t}\n+}\n+\n /**\n  * i40e_del_fdir_entry - Deletes a Flow Director filter entry\n  * @vsi: Pointer to the targeted VSI\n@@ -2816,10 +2884,249 @@ static int i40e_del_fdir_entry(struct i40e_vsi *vsi,\n \n \tret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd);\n \n+\ti40e_prune_flex_pit_list(pf);\n+\n \ti40e_fdir_check_and_reenable(pf);\n \treturn ret;\n }\n \n+/* i40e_unused_pit_index - Find an unused PIT index for given list\n+ * @pf: the PF data structure\n+ *\n+ * Find the first unused flexible PIT index entry. We search both the L3 and\n+ * L4 flexible PIT lists so that the returned index is unique and unused by\n+ * either currently programmed L3 or L4 filters. We use a bit field as storage\n+ * to track which indexes are already used.\n+ */\n+static u8 i40e_unused_pit_index(struct i40e_pf *pf)\n+{\n+\tunsigned long available_index = 0xFF;\n+\tstruct i40e_flex_pit *entry;\n+\n+\t/* We need to make sure that the new index isn't in use by either L3\n+\t * or L4 filters so that IP_USER_FLOW filters can program both L3 and\n+\t * L4 to use the same index.\n+\t */\n+\n+\tlist_for_each_entry(entry, &pf->l4_flex_pit_list, list)\n+\t\tclear_bit(entry->pit_index, &available_index);\n+\n+\tlist_for_each_entry(entry, &pf->l3_flex_pit_list, list)\n+\t\tclear_bit(entry->pit_index, &available_index);\n+\n+\treturn find_first_bit(&available_index, 8);\n+}\n+\n+/* i40e_find_flex_offset - Find an existing flex src_offset\n+ * @flex_pit_list: L3 or L4 flex PIT list\n+ * @src_offset: new src_offset to find\n+ *\n+ * Searches the flex_pit_list for an existing offset. If no offset is\n+ * currently programmed, then this will return an ERR_PTR if there is no space\n+ * to add a new offset, otherwise it returns NULL.\n+ */\n+static\n+struct i40e_flex_pit *i40e_find_flex_offset(struct list_head *flex_pit_list,\n+\t\t\t\t\t    u16 src_offset)\n+{\n+\tstruct i40e_flex_pit *entry;\n+\tint size = 0;\n+\n+\t/* Search for the src_offset first. If we find a matching entry\n+\t * already programmed, we can simply re-use it.\n+\t */\n+\tlist_for_each_entry(entry, flex_pit_list, list) {\n+\t\tsize++;\n+\t\tif (entry->src_offset == src_offset)\n+\t\t\treturn entry;\n+\t}\n+\n+\t/* If we haven't found an entry yet, then the provided src offset has\n+\t * not yet been programmed. We will program the src offset later on,\n+\t * but we need to indicate whether there is enough space to do so\n+\t * here. We'll make use of ERR_PTR for this purpose.\n+\t */\n+\tif (size >= I40E_FLEX_PIT_TABLE_SIZE)\n+\t\treturn ERR_PTR(-ENOSPC);\n+\n+\treturn NULL;\n+}\n+\n+/* i40e_add_flex_offset - Add src_offset to flex PIT table list\n+ * @flex_pit_list: L3 or L4 flex PIT list\n+ * @src_offset: new src_offset to add\n+ * @pit_index: the PIT index to program\n+ *\n+ * This function programs the new src_offset to the list. It is expected that\n+ * i40e_find_flex_offset has already been tried and returned NULL, indicating\n+ * that this offset is not programmed, and that the list has enough space to\n+ * store another offset.\n+ *\n+ * Returns 0 on success, and negative value on error.\n+ */\n+static int i40e_add_flex_offset(struct list_head *flex_pit_list,\n+\t\t\t\tu16 src_offset,\n+\t\t\t\tu8 pit_index)\n+{\n+\tstruct i40e_flex_pit *new_pit, *entry;\n+\n+\tnew_pit = kzalloc(sizeof(*entry), GFP_KERNEL);\n+\tif (!new_pit)\n+\t\treturn -ENOMEM;\n+\n+\tnew_pit->src_offset = src_offset;\n+\tnew_pit->pit_index = pit_index;\n+\n+\t/* We need to insert this item such that the list is sorted by\n+\t * src_offset in ascending order.\n+\t */\n+\tlist_for_each_entry(entry, flex_pit_list, list) {\n+\t\tif (new_pit->src_offset < entry->src_offset) {\n+\t\t\tlist_add_tail(&new_pit->list, &entry->list);\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\t/* If we found an entry with our offset already programmed we\n+\t\t * can simply return here, after freeing the memory. However,\n+\t\t * if the pit_index does not match we need to report an error.\n+\t\t */\n+\t\tif (new_pit->src_offset == entry->src_offset) {\n+\t\t\tint err = 0;\n+\n+\t\t\t/* If the PIT index is not the same we can't re-use\n+\t\t\t * the entry, so we must report an error.\n+\t\t\t */\n+\t\t\tif (new_pit->pit_index != entry->pit_index)\n+\t\t\t\terr = -EINVAL;\n+\n+\t\t\tkfree(new_pit);\n+\t\t\treturn err;\n+\t\t}\n+\t}\n+\n+\t/* If we reached here, then we haven't yet added the item. This means\n+\t * that we should add the item at the end of the list.\n+\t */\n+\tlist_add_tail(&new_pit->list, flex_pit_list);\n+\treturn 0;\n+}\n+\n+/**\n+ * __i40e_reprogram_flex_pit - Re-program specific FLX_PIT table\n+ * @pf: Pointer to the PF structure\n+ * @flex_pit_list: list of flexible src offsets in use\n+ * #flex_pit_start: index to first entry for this section of the table\n+ *\n+ * In order to handle flexible data, the hardware uses a table of values\n+ * called the FLX_PIT table. This table is used to indicate which sections of\n+ * the input correspond to what PIT index values. Unfortunately, hardware is\n+ * very restrictive about programming this table. Entries must be ordered by\n+ * src_offset in ascending order, without duplicates. Additionally, unused\n+ * entries must be set to the unused index value, and must have valid size and\n+ * length according to the src_offset ordering.\n+ *\n+ * This function will reprogram the FLX_PIT register from a book-keeping\n+ * structure that we guarantee is already ordered correctly, and has no more\n+ * than 3 entries.\n+ *\n+ * To make things easier, we only support flexible values of one word length,\n+ * rather than allowing variable length flexible values.\n+ **/\n+static void __i40e_reprogram_flex_pit(struct i40e_pf *pf,\n+\t\t\t\t      struct list_head *flex_pit_list,\n+\t\t\t\t      int flex_pit_start)\n+{\n+\tstruct i40e_flex_pit *entry = NULL;\n+\tu16 last_offset = 0;\n+\tint i = 0, j = 0;\n+\n+\t/* First, loop over the list of flex PIT entries, and reprogram the\n+\t * registers.\n+\t */\n+\tlist_for_each_entry(entry, flex_pit_list, list) {\n+\t\t/* We have to be careful when programming values for the\n+\t\t * largest SRC_OFFSET value. It is possible that adding\n+\t\t * additional empty values at the end would overflow the space\n+\t\t * for the SRC_OFFSET in the FLX_PIT register. To avoid this,\n+\t\t * we check here and add the empty values prior to adding the\n+\t\t * largest value.\n+\t\t *\n+\t\t * To determine this, we will use a loop from i+1 to 3, which\n+\t\t * will determine whether the unused entries would have valid\n+\t\t * SRC_OFFSET. Note that there cannot be extra entries past\n+\t\t * this value, because the only valid values would have been\n+\t\t * larger than I40E_MAX_FLEX_SRC_OFFSET, and thus would not\n+\t\t * have been added to the list in the first place.\n+\t\t */\n+\t\tfor (j = i + 1; j < 3; j++) {\n+\t\t\tu16 offset = entry->src_offset + j;\n+\t\t\tint index = flex_pit_start + i;\n+\t\t\tu32 value = I40E_FLEX_PREP_VAL(I40E_FLEX_DEST_UNUSED,\n+\t\t\t\t\t\t       1,\n+\t\t\t\t\t\t       offset - 3);\n+\n+\t\t\tif (offset > I40E_MAX_FLEX_SRC_OFFSET) {\n+\t\t\t\ti40e_write_rx_ctl(&pf->hw,\n+\t\t\t\t\t\t  I40E_PRTQF_FLX_PIT(index),\n+\t\t\t\t\t\t  value);\n+\t\t\t\ti++;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Now, we can program the actual value into the table */\n+\t\ti40e_write_rx_ctl(&pf->hw,\n+\t\t\t\t  I40E_PRTQF_FLX_PIT(flex_pit_start + i),\n+\t\t\t\t  I40E_FLEX_PREP_VAL(entry->pit_index + 50,\n+\t\t\t\t\t\t     1,\n+\t\t\t\t\t\t     entry->src_offset));\n+\t\ti++;\n+\t}\n+\n+\t/* In order to program the last entries in the table, we need to\n+\t * determine the valid offset. If the list is empty, we'll just start\n+\t * with 0. Otherwise, we'll start with the last item offset and add 1.\n+\t * This ensures that all entries have valid sizes. If we don't do this\n+\t * correctly, the hardware will disable flexible field parsing.\n+\t */\n+\tif (!list_empty(flex_pit_list))\n+\t\tlast_offset = list_prev_entry(entry, list)->src_offset + 1;\n+\n+\tfor (; i < 3; i++, last_offset++) {\n+\t\ti40e_write_rx_ctl(&pf->hw,\n+\t\t\t\t  I40E_PRTQF_FLX_PIT(flex_pit_start + i),\n+\t\t\t\t  I40E_FLEX_PREP_VAL(I40E_FLEX_DEST_UNUSED,\n+\t\t\t\t\t\t     1,\n+\t\t\t\t\t\t     last_offset));\n+\t}\n+}\n+\n+/**\n+ * i40e_reprogram_flex_pit - Reprogram all FLX_PIT tables after input set change\n+ * @pf: pointer to the PF structure\n+ *\n+ * This function reprograms both the L3 and L4 FLX_PIT tables. See the\n+ * internal helper function for implementation details.\n+ */\n+static void i40e_reprogram_flex_pit(struct i40e_pf *pf)\n+{\n+\t__i40e_reprogram_flex_pit(pf, &pf->l3_flex_pit_list,\n+\t\t\t\t  I40E_FLEX_PIT_IDX_START_L3);\n+\n+\t__i40e_reprogram_flex_pit(pf, &pf->l4_flex_pit_list,\n+\t\t\t\t  I40E_FLEX_PIT_IDX_START_L4);\n+\n+\t/* We also need to program the L3 and L4 GLQF ORT register */\n+\ti40e_write_rx_ctl(&pf->hw,\n+\t\t\t  I40E_GLQF_ORT(I40E_L3_GLQF_ORT_IDX),\n+\t\t\t  I40E_ORT_PREP_VAL(I40E_FLEX_PIT_IDX_START_L3,\n+\t\t\t\t\t    3, 1));\n+\n+\ti40e_write_rx_ctl(&pf->hw,\n+\t\t\t  I40E_GLQF_ORT(I40E_L4_GLQF_ORT_IDX),\n+\t\t\t  I40E_ORT_PREP_VAL(I40E_FLEX_PIT_IDX_START_L4,\n+\t\t\t\t\t    3, 1));\n+}\n+\n /**\n  * i40e_flow_str - Converts a flow_type into a human readable string\n  * @flow_type: the flow type from a flow specification\n@@ -2843,6 +3150,36 @@ static const char *i40e_flow_str(struct ethtool_rx_flow_spec *fsp)\n \t}\n }\n \n+/* i40e_pit_index_to_mask - Return the FLEX mask for a given PIT index\n+ * @pit_index: PIT index to convert\n+ *\n+ * Returns the mask for a given PIT index. Will return 0 if the pit_index is\n+ * of range.\n+ */\n+static u64 i40e_pit_index_to_mask(int pit_index)\n+{\n+\tswitch (pit_index) {\n+\tcase 0:\n+\t\treturn I40E_FLEX_50_MASK;\n+\tcase 1:\n+\t\treturn I40E_FLEX_51_MASK;\n+\tcase 2:\n+\t\treturn I40E_FLEX_52_MASK;\n+\tcase 3:\n+\t\treturn I40E_FLEX_53_MASK;\n+\tcase 4:\n+\t\treturn I40E_FLEX_54_MASK;\n+\tcase 5:\n+\t\treturn I40E_FLEX_55_MASK;\n+\tcase 6:\n+\t\treturn I40E_FLEX_56_MASK;\n+\tcase 7:\n+\t\treturn I40E_FLEX_57_MASK;\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+}\n+\n /**\n  * i40e_print_input_set - Show changes between two input sets\n  * @vsi: the vsi being configured\n@@ -2857,6 +3194,7 @@ static void i40e_print_input_set(struct i40e_vsi *vsi, u64 old, u64 new)\n {\n \tstruct i40e_pf *pf = vsi->back;\n \tbool old_value, new_value;\n+\tint i;\n \n \told_value = !!(old & I40E_L3_SRC_MASK);\n \tnew_value = !!(new & I40E_L3_SRC_MASK);\n@@ -2893,6 +3231,19 @@ static void i40e_print_input_set(struct i40e_vsi *vsi, u64 old, u64 new)\n \t\t\t   old_value ? \"ON\" : \"OFF\",\n \t\t\t   new_value ? \"ON\" : \"OFF\");\n \n+\t/* Show change of flexible filter entries */\n+\tfor (i = 0; i < I40E_FLEX_INDEX_ENTRIES; i++) {\n+\t\tu64 flex_mask = i40e_pit_index_to_mask(i);\n+\n+\t\told_value = !!(old & flex_mask);\n+\t\tnew_value = !!(new & flex_mask);\n+\t\tif (old_value != new_value)\n+\t\t\tnetif_info(pf, drv, vsi->netdev, \"FLEX index %d: %s -> %s\\n\",\n+\t\t\t\t   i,\n+\t\t\t\t   old_value ? \"ON\" : \"OFF\",\n+\t\t\t\t   new_value ? \"ON\" : \"OFF\");\n+\t}\n+\n \tnetif_info(pf, drv, vsi->netdev, \"  Current input set: %0llx\\n\",\n \t\t   old);\n \tnetif_info(pf, drv, vsi->netdev, \"Requested input set: %0llx\\n\",\n@@ -2903,6 +3254,7 @@ static void i40e_print_input_set(struct i40e_vsi *vsi, u64 old, u64 new)\n  * i40e_check_fdir_input_set - Check that a given rx_flow_spec mask is valid\n  * @vsi: pointer to the targeted VSI\n  * @fsp: pointer to Rx flow specification\n+ * @userdef: userdefined data from flow specification\n  *\n  * Ensures that a given ethtool_rx_flow_spec has a valid mask. Some support\n  * for partial matches exists with a few limitations. First, hardware only\n@@ -2924,14 +3276,19 @@ static void i40e_print_input_set(struct i40e_vsi *vsi, u64 old, u64 new)\n  * failure.\n  **/\n static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,\n-\t\t\t\t     struct ethtool_rx_flow_spec *fsp)\n+\t\t\t\t     struct ethtool_rx_flow_spec *fsp,\n+\t\t\t\t     struct i40e_rx_flow_userdef *userdef)\n {\n \tstruct i40e_pf *pf = vsi->back;\n \tstruct ethtool_tcpip4_spec *tcp_ip4_spec;\n \tstruct ethtool_usrip4_spec *usr_ip4_spec;\n \tu64 current_mask, new_mask;\n+\tbool new_flex_offset = false;\n+\tbool flex_l3 = false;\n \tu16 *fdir_filter_count;\n-\tu16 index;\n+\tu16 index, src_offset = 0;\n+\tu8 pit_index = 0;\n+\tint err;\n \n \tswitch (fsp->flow_type & ~FLOW_EXT) {\n \tcase TCP_V4_FLOW:\n@@ -2945,6 +3302,7 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,\n \tcase IP_USER_FLOW:\n \t\tindex = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;\n \t\tfdir_filter_count = &pf->fd_ip4_filter_cnt;\n+\t\tflex_l3 = true;\n \t\tbreak;\n \tdefault:\n \t\treturn -EOPNOTSUPP;\n@@ -3036,11 +3394,11 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,\n \t\tif (usr_ip4_spec->tos)\n \t\t\treturn -EOPNOTSUPP;\n \n-\t\t/* IP version does not have a mask field. */\n+\t\t/* Filtering on IP version is not supported */\n \t\tif (usr_ip4_spec->ip_ver)\n \t\t\treturn -EINVAL;\n \n-\t\t/* L4 protocol doesn't have a mask field. */\n+\t\t/* Filtering on L4 protocol is not supported */\n \t\tif (usr_ip4_spec->proto)\n \t\t\treturn -EINVAL;\n \n@@ -3049,15 +3407,107 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,\n \t\treturn -EOPNOTSUPP;\n \t}\n \n-\t/* If the input set doesn't need any changes then this filter is safe\n-\t * to apply.\n+\t/* First, clear all flexible filter entries */\n+\tnew_mask &= ~I40E_FLEX_INPUT_MASK;\n+\n+\t/* If we have a flexible filter, try to add this offset to the correct\n+\t * flexible filter PIT list. Once finished, we can update the mask.\n+\t * If the src_offset changed, we will get a new mask value which will\n+\t * trigger an input set change.\n \t */\n-\tif (new_mask == current_mask)\n+\tif (userdef->flex_filter) {\n+\t\tstruct i40e_flex_pit *l3_flex_pit = NULL, *flex_pit = NULL;\n+\n+\t\t/* Flexible offset must be even, since the flexible payload\n+\t\t * must be aligned on 2-byte boundary.\n+\t\t */\n+\t\tif (userdef->flex_offset & 0x1) {\n+\t\t\tdev_warn(&pf->pdev->dev,\n+\t\t\t\t \"Flexible data offset must be 2-byte aligned\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tsrc_offset = userdef->flex_offset >> 1;\n+\n+\t\t/* FLX_PIT source offset value is only so large */\n+\t\tif (src_offset > I40E_MAX_FLEX_SRC_OFFSET) {\n+\t\t\tdev_warn(&pf->pdev->dev,\n+\t\t\t\t \"Flexible data must reside within first 64 bytes of the packet payload\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\t/* See if this offset has already been programmed. If we get\n+\t\t * an ERR_PTR, then the filter is not safe to add. Otherwise,\n+\t\t * if we get a NULL pointer, this means we will need to add\n+\t\t * the offset.\n+\t\t */\n+\t\tflex_pit = i40e_find_flex_offset(&pf->l4_flex_pit_list,\n+\t\t\t\t\t\t src_offset);\n+\t\tif (IS_ERR(flex_pit))\n+\t\t\treturn PTR_ERR(flex_pit);\n+\n+\t\t/* IP_USER_FLOW filters match both L4 (ICMP) and L3 (unknown)\n+\t\t * packet types, and thus we need to program both L3 and L4\n+\t\t * flexible values. These must have identical flexible index,\n+\t\t * as otherwise we can't correctly program the input set. So\n+\t\t * we'll find both an L3 and L4 index and make sure they are\n+\t\t * the same.\n+\t\t */\n+\t\tif (flex_l3) {\n+\t\t\tl3_flex_pit =\n+\t\t\t\ti40e_find_flex_offset(&pf->l3_flex_pit_list,\n+\t\t\t\t\t\t      src_offset);\n+\t\t\tif (IS_ERR(l3_flex_pit))\n+\t\t\t\treturn PTR_ERR(l3_flex_pit);\n+\n+\t\t\tif (flex_pit) {\n+\t\t\t\t/* If we already had a matching L4 entry, we\n+\t\t\t\t * need to make sure that the L3 entry we\n+\t\t\t\t * obtained uses the same index.\n+\t\t\t\t */\n+\t\t\t\tif (l3_flex_pit) {\n+\t\t\t\t\tif (l3_flex_pit->pit_index !=\n+\t\t\t\t\t    flex_pit->pit_index) {\n+\t\t\t\t\t\treturn -EINVAL;\n+\t\t\t\t\t}\n+\t\t\t\t} else {\n+\t\t\t\t\tnew_flex_offset = true;\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tflex_pit = l3_flex_pit;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* If we didn't find an existing flex offset, we need to\n+\t\t * program a new one. However, we don't immediately program it\n+\t\t * here because we will wait to program until after we check\n+\t\t * that it is safe to change the input set.\n+\t\t */\n+\t\tif (!flex_pit) {\n+\t\t\tnew_flex_offset = true;\n+\t\t\tpit_index = i40e_unused_pit_index(pf);\n+\t\t} else {\n+\t\t\tpit_index = flex_pit->pit_index;\n+\t\t}\n+\n+\t\t/* Update the mask with the new offset */\n+\t\tnew_mask |= i40e_pit_index_to_mask(pit_index);\n+\t}\n+\n+\t/* If the mask and flexible filter offsets for this filter match the\n+\t * currently programmed values we don't need any input set change, so\n+\t * this filter is safe to install.\n+\t */\n+\tif (new_mask == current_mask && !new_flex_offset)\n \t\treturn 0;\n \n \tnetif_info(pf, drv, vsi->netdev, \"Input set change requested for %s flows:\\n\",\n \t\t   i40e_flow_str(fsp));\n \ti40e_print_input_set(vsi, current_mask, new_mask);\n+\tif (new_flex_offset) {\n+\t\tnetif_info(pf, drv, vsi->netdev, \"FLEX index %d: Offset -> %d\",\n+\t\t\t   pit_index, src_offset);\n+\t}\n \n \t/* Hardware input sets are global across multiple ports, so even the\n \t * main port cannot change them when in MFP mode as this would impact\n@@ -3086,6 +3536,24 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,\n \n \ti40e_write_fd_input_set(pf, index, new_mask);\n \n+\t/* Add the new offset and update table, if necessary */\n+\tif (new_flex_offset) {\n+\t\terr = i40e_add_flex_offset(&pf->l4_flex_pit_list, src_offset,\n+\t\t\t\t\t   pit_index);\n+\t\tif (err)\n+\t\t\treturn err;\n+\n+\t\tif (flex_l3) {\n+\t\t\terr = i40e_add_flex_offset(&pf->l3_flex_pit_list,\n+\t\t\t\t\t\t   src_offset,\n+\t\t\t\t\t\t   pit_index);\n+\t\t\tif (err)\n+\t\t\t\treturn err;\n+\t\t}\n+\n+\t\ti40e_reprogram_flex_pit(pf);\n+\t}\n+\n \treturn 0;\n }\n \n@@ -3131,15 +3599,11 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,\n \tif (i40e_parse_rx_flow_user_data(fsp, &userdef))\n \t\treturn -EINVAL;\n \n-\t/* Flexible filters not yet supported */\n-\tif (userdef.flex_filter)\n-\t\treturn -EOPNOTSUPP;\n-\n \t/* Extended MAC field is not supported */\n \tif (fsp->flow_type & FLOW_MAC_EXT)\n \t\treturn -EINVAL;\n \n-\tret = i40e_check_fdir_input_set(vsi, fsp);\n+\tret = i40e_check_fdir_input_set(vsi, fsp, &userdef);\n \tif (ret)\n \t\treturn ret;\n \n@@ -3199,6 +3663,12 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,\n \tinput->dst_ip = fsp->h_u.tcp_ip4_spec.ip4src;\n \tinput->src_ip = fsp->h_u.tcp_ip4_spec.ip4dst;\n \n+\tif (userdef.flex_filter) {\n+\t\tinput->flex_filter = true;\n+\t\tinput->flex_word = cpu_to_be16(userdef.flex_word);\n+\t\tinput->flex_offset = userdef.flex_offset;\n+\t}\n+\n \tret = i40e_add_del_fdir(vsi, input, true);\n \tif (ret)\n \t\tgoto free_input;\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c\nindex 2c3a427f5b75..a2cd3979b81a 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_main.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c\n@@ -5888,6 +5888,7 @@ int i40e_vsi_open(struct i40e_vsi *vsi)\n static void i40e_fdir_filter_exit(struct i40e_pf *pf)\n {\n \tstruct i40e_fdir_filter *filter;\n+\tstruct i40e_flex_pit *pit_entry, *tmp;\n \tstruct hlist_node *node2;\n \n \thlist_for_each_entry_safe(filter, node2,\n@@ -5896,6 +5897,18 @@ static void i40e_fdir_filter_exit(struct i40e_pf *pf)\n \t\tkfree(filter);\n \t}\n \n+\tlist_for_each_entry_safe(pit_entry, tmp, &pf->l3_flex_pit_list, list) {\n+\t\tlist_del(&pit_entry->list);\n+\t\tkfree(pit_entry);\n+\t}\n+\tINIT_LIST_HEAD(&pf->l3_flex_pit_list);\n+\n+\tlist_for_each_entry_safe(pit_entry, tmp, &pf->l4_flex_pit_list, list) {\n+\t\tlist_del(&pit_entry->list);\n+\t\tkfree(pit_entry);\n+\t}\n+\tINIT_LIST_HEAD(&pf->l4_flex_pit_list);\n+\n \tpf->fdir_pf_active_filters = 0;\n \tpf->fd_tcp4_filter_cnt = 0;\n \tpf->fd_udp4_filter_cnt = 0;\n@@ -11524,6 +11537,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n \thw->bus.bus_id = pdev->bus->number;\n \tpf->instance = pfs_found;\n \n+\tINIT_LIST_HEAD(&pf->l3_flex_pit_list);\n+\tINIT_LIST_HEAD(&pf->l4_flex_pit_list);\n+\n \t/* set up the locks for the AQ, do this only once in probe\n \t * and destroy them only once in remove\n \t */\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c\nindex 55ac87c1e40b..cb38a248c38f 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c\n@@ -72,6 +72,9 @@ static void i40e_fdir(struct i40e_ring *tx_ring,\n \tflex_ptype |= I40E_TXD_FLTR_QW0_PCTYPE_MASK &\n \t\t      (fdata->pctype << I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);\n \n+\tflex_ptype |= I40E_TXD_FLTR_QW0_PCTYPE_MASK &\n+\t\t      (fdata->flex_offset << I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT);\n+\n \t/* Use LAN VSI Id if not programmed by user */\n \tflex_ptype |= I40E_TXD_FLTR_QW0_DEST_VSI_MASK &\n \t\t      ((u32)(fdata->dest_vsi ? : pf->vsi[pf->lan_vsi]->id) <<\n@@ -224,6 +227,14 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,\n \tip->saddr = fd_data->src_ip;\n \tudp->source = fd_data->src_port;\n \n+\tif (fd_data->flex_filter) {\n+\t\tu8 *payload = raw_packet + I40E_UDPIP_DUMMY_PACKET_LEN;\n+\t\t__be16 pattern = fd_data->flex_word;\n+\t\tu16 off = fd_data->flex_offset;\n+\n+\t\t*((__force __be16 *)(payload + off)) = pattern;\n+\t}\n+\n \tfd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;\n \tret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);\n \tif (ret) {\n@@ -290,6 +301,14 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,\n \tip->saddr = fd_data->src_ip;\n \ttcp->source = fd_data->src_port;\n \n+\tif (fd_data->flex_filter) {\n+\t\tu8 *payload = raw_packet + I40E_TCPIP_DUMMY_PACKET_LEN;\n+\t\t__be16 pattern = fd_data->flex_word;\n+\t\tu16 off = fd_data->flex_offset;\n+\n+\t\t*((__force __be16 *)(payload + off)) = pattern;\n+\t}\n+\n \tfd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;\n \tret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);\n \tif (ret) {\n@@ -363,6 +382,14 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,\n \t\tip->daddr = fd_data->dst_ip;\n \t\tip->protocol = 0;\n \n+\t\tif (fd_data->flex_filter) {\n+\t\t\tu8 *payload = raw_packet + I40E_IP_DUMMY_PACKET_LEN;\n+\t\t\t__be16 pattern = fd_data->flex_word;\n+\t\t\tu16 off = fd_data->flex_offset;\n+\n+\t\t\t*((__force __be16 *)(payload + off)) = pattern;\n+\t\t}\n+\n \t\tfd_data->pctype = i;\n \t\tret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);\n \t\tif (ret) {\n",
    "prefixes": [
        "PART2",
        "7/9"
    ]
}