get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 1225079,
    "url": "http://patchwork.ozlabs.org/api/patches/1225079/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20200117153919.50321-3-anthony.l.nguyen@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": "<20200117153919.50321-3-anthony.l.nguyen@intel.com>",
    "list_archive_url": null,
    "date": "2020-01-17T15:39:14",
    "name": "[S36,3/8] ice: Populate TCAM filter software structures",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "6d9c577149f8d8084c67e9fdd14576c90aa478d0",
    "submitter": {
        "id": 68875,
        "url": "http://patchwork.ozlabs.org/api/people/68875/?format=api",
        "name": "Tony Nguyen",
        "email": "anthony.l.nguyen@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/20200117153919.50321-3-anthony.l.nguyen@intel.com/mbox/",
    "series": [
        {
            "id": 153932,
            "url": "http://patchwork.ozlabs.org/api/series/153932/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=153932",
            "date": "2020-01-17T15:39:19",
            "name": "[S36,1/8] ice: Enable writing hardware filtering tables",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/153932/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1225079/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/1225079/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<intel-wired-lan-bounces@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"
        ],
        "Authentication-Results": [
            "ozlabs.org; spf=pass (sender SPF authorized)\n\tsmtp.mailfrom=osuosl.org (client-ip=140.211.166.136;\n\thelo=silver.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org;\n\tdmarc=fail (p=none dis=none) header.from=intel.com"
        ],
        "Received": [
            "from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 47zz000L51z9s1x\n\tfor <incoming@patchwork.ozlabs.org>;\n\tSat, 18 Jan 2020 11:12:32 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id 88B78221B1;\n\tSat, 18 Jan 2020 00:12:30 +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 c-PRStO07kwX; Sat, 18 Jan 2020 00:12:12 +0000 (UTC)",
            "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby silver.osuosl.org (Postfix) with ESMTP id 5F6D12263C;\n\tSat, 18 Jan 2020 00:12:08 +0000 (UTC)",
            "from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\tby ash.osuosl.org (Postfix) with ESMTP id B4AD11BF846\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tSat, 18 Jan 2020 00:12:04 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id A22EB221B1\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tSat, 18 Jan 2020 00:12:04 +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 B+3X4R6-2tWE for <intel-wired-lan@lists.osuosl.org>;\n\tSat, 18 Jan 2020 00:11:57 +0000 (UTC)",
            "from mga01.intel.com (mga01.intel.com [192.55.52.88])\n\tby silver.osuosl.org (Postfix) with ESMTPS id D817F221AF\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tSat, 18 Jan 2020 00:11:56 +0000 (UTC)",
            "from orsmga005.jf.intel.com ([10.7.209.41])\n\tby fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t17 Jan 2020 16:11:56 -0800",
            "from unknown (HELO localhost.jf.intel.com) ([10.166.244.174])\n\tby orsmga005.jf.intel.com with ESMTP; 17 Jan 2020 16:11:55 -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-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.70,332,1574150400\"; d=\"scan'208\";a=\"398818584\"",
        "From": "Tony Nguyen <anthony.l.nguyen@intel.com>",
        "To": "intel-wired-lan@lists.osuosl.org",
        "Date": "Fri, 17 Jan 2020 07:39:14 -0800",
        "Message-Id": "<20200117153919.50321-3-anthony.l.nguyen@intel.com>",
        "X-Mailer": "git-send-email 2.20.1",
        "In-Reply-To": "<20200117153919.50321-1-anthony.l.nguyen@intel.com>",
        "References": "<20200117153919.50321-1-anthony.l.nguyen@intel.com>",
        "MIME-Version": "1.0",
        "Subject": "[Intel-wired-lan] [PATCH S36 3/8] ice: Populate TCAM filter\n\tsoftware structures",
        "X-BeenThere": "intel-wired-lan@osuosl.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>",
        "List-Unsubscribe": "<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>",
        "List-Post": "<mailto:intel-wired-lan@osuosl.org>",
        "List-Help": "<mailto:intel-wired-lan-request@osuosl.org?subject=help>",
        "List-Subscribe": "<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "intel-wired-lan-bounces@osuosl.org",
        "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>"
    },
    "content": "Store the TCAM entry with the profile data and the VSI group in the\nrespective SW structures. This will be subsequently used to write out\nthe tables to hardware.\n\nSigned-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>\nSigned-off-by: Henry Tieman <henry.w.tieman@intel.com>\n---\n .../net/ethernet/intel/ice/ice_adminq_cmd.h   |    1 +\n drivers/net/ethernet/intel/ice/ice_common.c   |   33 +\n drivers/net/ethernet/intel/ice/ice_common.h   |    2 +\n .../net/ethernet/intel/ice/ice_flex_pipe.c    | 1318 +++++++++++++++++\n .../net/ethernet/intel/ice/ice_flex_pipe.h    |    2 +\n .../net/ethernet/intel/ice/ice_flex_type.h    |   51 +\n drivers/net/ethernet/intel/ice/ice_flow.c     |   61 +-\n drivers/net/ethernet/intel/ice/ice_status.h   |    1 +\n 8 files changed, 1459 insertions(+), 10 deletions(-)",
    "diff": "diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\nindex 6a45bbffbbbb..f5d5d38a7cc6 100644\n--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n@@ -234,6 +234,7 @@ struct ice_aqc_get_sw_cfg_resp {\n #define ICE_AQC_RES_TYPE_VSI_LIST_REP\t\t\t0x03\n #define ICE_AQC_RES_TYPE_VSI_LIST_PRUNE\t\t\t0x04\n #define ICE_AQC_RES_TYPE_HASH_PROF_BLDR_PROFID\t\t0x60\n+#define ICE_AQC_RES_TYPE_HASH_PROF_BLDR_TCAM\t\t0x61\n \n #define ICE_AQC_RES_TYPE_FLAG_SCAN_BOTTOM\t\tBIT(12)\n #define ICE_AQC_RES_TYPE_FLAG_IGNORE_INDEX\t\tBIT(13)\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c\nindex 463b1f25e261..50909ec7afa2 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.c\n+++ b/drivers/net/ethernet/intel/ice/ice_common.c\n@@ -1572,6 +1572,39 @@ ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool btm, u16 *res)\n \treturn status;\n }\n \n+/**\n+ * ice_free_hw_res - free allocated HW resource\n+ * @hw: pointer to the HW struct\n+ * @type: type of resource to free\n+ * @num: number of resources\n+ * @res: pointer to array that contains the resources to free\n+ */\n+enum ice_status\n+ice_free_hw_res(struct ice_hw *hw, u16 type, u16 num, u16 *res)\n+{\n+\tstruct ice_aqc_alloc_free_res_elem *buf;\n+\tenum ice_status status;\n+\tsize_t buf_len;\n+\n+\tbuf_len = struct_size(buf, elem, num - 1);\n+\tbuf = kzalloc(buf_len, GFP_KERNEL);\n+\tif (!buf)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\t/* Prepare buffer to free resource. */\n+\tbuf->num_elems = cpu_to_le16(num);\n+\tbuf->res_type = cpu_to_le16(type);\n+\tmemcpy(buf->elem, res, sizeof(buf->elem) * num);\n+\n+\tstatus = ice_aq_alloc_free_res(hw, num, buf, buf_len,\n+\t\t\t\t       ice_aqc_opc_free_res, NULL);\n+\tif (status)\n+\t\tice_debug(hw, ICE_DBG_SW, \"CQ CMD Buffer:\\n\");\n+\n+\tkfree(buf);\n+\treturn status;\n+}\n+\n /**\n  * ice_get_num_per_func - determine number of resources per PF\n  * @hw: pointer to the HW structure\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h\nindex 00de178c9f52..dfec1105fd06 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.h\n+++ b/drivers/net/ethernet/intel/ice/ice_common.h\n@@ -36,6 +36,8 @@ ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,\n void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res);\n enum ice_status\n ice_alloc_hw_res(struct ice_hw *hw, u16 type, u16 num, bool btm, u16 *res);\n+enum ice_status\n+ice_free_hw_res(struct ice_hw *hw, u16 type, u16 num, u16 *res);\n enum ice_status ice_init_nvm(struct ice_hw *hw);\n enum ice_status\n ice_read_sr_buf(struct ice_hw *hw, u16 offset, u16 *words, u16 *data);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c\nindex 5c09d3105b8b..8c93c303a4a5 100644\n--- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c\n+++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c\n@@ -159,6 +159,176 @@ ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state,\n \treturn state->sect;\n }\n \n+/* Key creation */\n+\n+#define ICE_DC_KEY\t0x1\t/* don't care */\n+#define ICE_DC_KEYINV\t0x1\n+#define ICE_NM_KEY\t0x0\t/* never match */\n+#define ICE_NM_KEYINV\t0x0\n+#define ICE_0_KEY\t0x1\t/* match 0 */\n+#define ICE_0_KEYINV\t0x0\n+#define ICE_1_KEY\t0x0\t/* match 1 */\n+#define ICE_1_KEYINV\t0x1\n+\n+/**\n+ * ice_gen_key_word - generate 16-bits of a key/mask word\n+ * @val: the value\n+ * @valid: valid bits mask (change only the valid bits)\n+ * @dont_care: don't care mask\n+ * @nvr_mtch: never match mask\n+ * @key: pointer to an array of where the resulting key portion\n+ * @key_inv: pointer to an array of where the resulting key invert portion\n+ *\n+ * This function generates 16-bits from a 8-bit value, an 8-bit don't care mask\n+ * and an 8-bit never match mask. The 16-bits of output are divided into 8 bits\n+ * of key and 8 bits of key invert.\n+ *\n+ *     '0' =    b01, always match a 0 bit\n+ *     '1' =    b10, always match a 1 bit\n+ *     '?' =    b11, don't care bit (always matches)\n+ *     '~' =    b00, never match bit\n+ *\n+ * Input:\n+ *          val:         b0  1  0  1  0  1\n+ *          dont_care:   b0  0  1  1  0  0\n+ *          never_mtch:  b0  0  0  0  1  1\n+ *          ------------------------------\n+ * Result:  key:        b01 10 11 11 00 00\n+ */\n+static enum ice_status\n+ice_gen_key_word(u8 val, u8 valid, u8 dont_care, u8 nvr_mtch, u8 *key,\n+\t\t u8 *key_inv)\n+{\n+\tu8 in_key = *key, in_key_inv = *key_inv;\n+\tu8 i;\n+\n+\t/* 'dont_care' and 'nvr_mtch' masks cannot overlap */\n+\tif ((dont_care ^ nvr_mtch) != (dont_care | nvr_mtch))\n+\t\treturn ICE_ERR_CFG;\n+\n+\t*key = 0;\n+\t*key_inv = 0;\n+\n+\t/* encode the 8 bits into 8-bit key and 8-bit key invert */\n+\tfor (i = 0; i < 8; i++) {\n+\t\t*key >>= 1;\n+\t\t*key_inv >>= 1;\n+\n+\t\tif (!(valid & 0x1)) { /* change only valid bits */\n+\t\t\t*key |= (in_key & 0x1) << 7;\n+\t\t\t*key_inv |= (in_key_inv & 0x1) << 7;\n+\t\t} else if (dont_care & 0x1) { /* don't care bit */\n+\t\t\t*key |= ICE_DC_KEY << 7;\n+\t\t\t*key_inv |= ICE_DC_KEYINV << 7;\n+\t\t} else if (nvr_mtch & 0x1) { /* never match bit */\n+\t\t\t*key |= ICE_NM_KEY << 7;\n+\t\t\t*key_inv |= ICE_NM_KEYINV << 7;\n+\t\t} else if (val & 0x01) { /* exact 1 match */\n+\t\t\t*key |= ICE_1_KEY << 7;\n+\t\t\t*key_inv |= ICE_1_KEYINV << 7;\n+\t\t} else { /* exact 0 match */\n+\t\t\t*key |= ICE_0_KEY << 7;\n+\t\t\t*key_inv |= ICE_0_KEYINV << 7;\n+\t\t}\n+\n+\t\tdont_care >>= 1;\n+\t\tnvr_mtch >>= 1;\n+\t\tvalid >>= 1;\n+\t\tval >>= 1;\n+\t\tin_key >>= 1;\n+\t\tin_key_inv >>= 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_bits_max_set - determine if the number of bits set is within a maximum\n+ * @mask: pointer to the byte array which is the mask\n+ * @size: the number of bytes in the mask\n+ * @max: the max number of set bits\n+ *\n+ * This function determines if there are at most 'max' number of bits set in an\n+ * array. Returns true if the number for bits set is <= max or will return false\n+ * otherwise.\n+ */\n+static bool ice_bits_max_set(const u8 *mask, u16 size, u16 max)\n+{\n+\tu16 count = 0;\n+\tu16 i;\n+\n+\t/* check each byte */\n+\tfor (i = 0; i < size; i++) {\n+\t\t/* if 0, go to next byte */\n+\t\tif (!mask[i])\n+\t\t\tcontinue;\n+\n+\t\t/* We know there is at least one set bit in this byte because of\n+\t\t * the above check; if we already have found 'max' number of\n+\t\t * bits set, then we can return failure now.\n+\t\t */\n+\t\tif (count == max)\n+\t\t\treturn false;\n+\n+\t\t/* count the bits in this byte, checking threshold */\n+\t\tcount += hweight8(mask[i]);\n+\t\tif (count > max)\n+\t\t\treturn false;\n+\t}\n+\n+\treturn true;\n+}\n+\n+/**\n+ * ice_set_key - generate a variable sized key with multiples of 16-bits\n+ * @key: pointer to where the key will be stored\n+ * @size: the size of the complete key in bytes (must be even)\n+ * @val: array of 8-bit values that makes up the value portion of the key\n+ * @upd: array of 8-bit masks that determine what key portion to update\n+ * @dc: array of 8-bit masks that make up the don't care mask\n+ * @nm: array of 8-bit masks that make up the never match mask\n+ * @off: the offset of the first byte in the key to update\n+ * @len: the number of bytes in the key update\n+ *\n+ * This function generates a key from a value, a don't care mask and a never\n+ * match mask.\n+ * upd, dc, and nm are optional parameters, and can be NULL:\n+ *\tupd == NULL --> udp mask is all 1's (update all bits)\n+ *\tdc == NULL --> dc mask is all 0's (no don't care bits)\n+ *\tnm == NULL --> nm mask is all 0's (no never match bits)\n+ */\n+static enum ice_status\n+ice_set_key(u8 *key, u16 size, u8 *val, u8 *upd, u8 *dc, u8 *nm, u16 off,\n+\t    u16 len)\n+{\n+\tu16 half_size;\n+\tu16 i;\n+\n+\t/* size must be a multiple of 2 bytes. */\n+\tif (size % 2)\n+\t\treturn ICE_ERR_CFG;\n+\n+\thalf_size = size / 2;\n+\tif (off + len > half_size)\n+\t\treturn ICE_ERR_CFG;\n+\n+\t/* Make sure at most one bit is set in the never match mask. Having more\n+\t * than one never match mask bit set will cause HW to consume excessive\n+\t * power otherwise; this is a power management efficiency check.\n+\t */\n+#define ICE_NVR_MTCH_BITS_MAX\t1\n+\tif (nm && !ice_bits_max_set(nm, len, ICE_NVR_MTCH_BITS_MAX))\n+\t\treturn ICE_ERR_CFG;\n+\n+\tfor (i = 0; i < len; i++)\n+\t\tif (ice_gen_key_word(val[i], upd ? upd[i] : 0xff,\n+\t\t\t\t     dc ? dc[i] : 0, nm ? nm[i] : 0,\n+\t\t\t\t     key + off + i, key + half_size + off + i))\n+\t\t\treturn ICE_ERR_CFG;\n+\n+\treturn 0;\n+}\n+\n /**\n  * ice_acquire_global_cfg_lock\n  * @hw: pointer to the HW structure\n@@ -952,6 +1122,48 @@ enum ice_sid_all {\n \tICE_SID_OFF_COUNT,\n };\n \n+/* Characteristic handling */\n+\n+/**\n+ * ice_match_prop_lst - determine if properties of two lists match\n+ * @list1: first properties list\n+ * @list2: second properties list\n+ *\n+ * Count, cookies and the order must match in order to be considered equivalent.\n+ */\n+static bool\n+ice_match_prop_lst(struct list_head *list1, struct list_head *list2)\n+{\n+\tstruct ice_vsig_prof *tmp1;\n+\tstruct ice_vsig_prof *tmp2;\n+\tu16 chk_count = 0;\n+\tu16 count = 0;\n+\n+\t/* compare counts */\n+\tlist_for_each_entry(tmp1, list1, list)\n+\t\tcount++;\n+\tlist_for_each_entry(tmp2, list2, list)\n+\t\tchk_count++;\n+\tif (!count || count != chk_count)\n+\t\treturn false;\n+\n+\ttmp1 = list_first_entry(list1, struct ice_vsig_prof, list);\n+\ttmp2 = list_first_entry(list2, struct ice_vsig_prof, list);\n+\n+\t/* profile cookies must compare, and in the exact same order to take\n+\t * into account priority\n+\t */\n+\twhile (count--) {\n+\t\tif (tmp2->profile_cookie != tmp1->profile_cookie)\n+\t\t\treturn false;\n+\n+\t\ttmp1 = list_next_entry(tmp1, list);\n+\t\ttmp2 = list_next_entry(tmp2, list);\n+\t}\n+\n+\treturn true;\n+}\n+\n /* VSIG Management */\n \n /**\n@@ -999,6 +1211,117 @@ static u16 ice_vsig_alloc_val(struct ice_hw *hw, enum ice_block blk, u16 vsig)\n \treturn ICE_VSIG_VALUE(idx, hw->pf_id);\n }\n \n+/**\n+ * ice_vsig_alloc - Finds a free entry and allocates a new VSIG\n+ * @hw: pointer to the hardware structure\n+ * @blk: HW block\n+ *\n+ * This function will iterate through the VSIG list and mark the first\n+ * unused entry for the new VSIG entry as used and return that value.\n+ */\n+static u16 ice_vsig_alloc(struct ice_hw *hw, enum ice_block blk)\n+{\n+\tu16 i;\n+\n+\tfor (i = 1; i < ICE_MAX_VSIGS; i++)\n+\t\tif (!hw->blk[blk].xlt2.vsig_tbl[i].in_use)\n+\t\t\treturn ice_vsig_alloc_val(hw, blk, i);\n+\n+\treturn ICE_DEFAULT_VSIG;\n+}\n+\n+/**\n+ * ice_find_dup_props_vsig - find VSI group with a specified set of properties\n+ * @hw: pointer to the hardware structure\n+ * @blk: HW block\n+ * @chs: characteristic list\n+ * @vsig: returns the VSIG with the matching profiles, if found\n+ *\n+ * Each VSIG is associated with a characteristic set; i.e. all VSIs under\n+ * a group have the same characteristic set. To check if there exists a VSIG\n+ * which has the same characteristics as the input characteristics; this\n+ * function will iterate through the XLT2 list and return the VSIG that has a\n+ * matching configuration. In order to make sure that priorities are accounted\n+ * for, the list must match exactly, including the order in which the\n+ * characteristics are listed.\n+ */\n+static enum ice_status\n+ice_find_dup_props_vsig(struct ice_hw *hw, enum ice_block blk,\n+\t\t\tstruct list_head *chs, u16 *vsig)\n+{\n+\tstruct ice_xlt2 *xlt2 = &hw->blk[blk].xlt2;\n+\tu16 i;\n+\n+\tfor (i = 0; i < xlt2->count; i++)\n+\t\tif (xlt2->vsig_tbl[i].in_use &&\n+\t\t    ice_match_prop_lst(chs, &xlt2->vsig_tbl[i].prop_lst)) {\n+\t\t\t*vsig = ICE_VSIG_VALUE(i, hw->pf_id);\n+\t\t\treturn 0;\n+\t\t}\n+\n+\treturn ICE_ERR_DOES_NOT_EXIST;\n+}\n+\n+/**\n+ * ice_vsig_free - free VSI group\n+ * @hw: pointer to the hardware structure\n+ * @blk: HW block\n+ * @vsig: VSIG to remove\n+ *\n+ * The function will remove all VSIs associated with the input VSIG and move\n+ * them to the DEFAULT_VSIG and mark the VSIG available.\n+ */\n+static enum ice_status\n+ice_vsig_free(struct ice_hw *hw, enum ice_block blk, u16 vsig)\n+{\n+\tstruct ice_vsig_prof *dtmp, *del;\n+\tstruct ice_vsig_vsi *vsi_cur;\n+\tu16 idx;\n+\n+\tidx = vsig & ICE_VSIG_IDX_M;\n+\tif (idx >= ICE_MAX_VSIGS)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tif (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use)\n+\t\treturn ICE_ERR_DOES_NOT_EXIST;\n+\n+\thw->blk[blk].xlt2.vsig_tbl[idx].in_use = false;\n+\n+\tvsi_cur = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;\n+\t/* If the VSIG has at least 1 VSI then iterate through the\n+\t * list and remove the VSIs before deleting the group.\n+\t */\n+\tif (vsi_cur) {\n+\t\t/* remove all vsis associated with this VSIG XLT2 entry */\n+\t\tdo {\n+\t\t\tstruct ice_vsig_vsi *tmp = vsi_cur->next_vsi;\n+\n+\t\t\tvsi_cur->vsig = ICE_DEFAULT_VSIG;\n+\t\t\tvsi_cur->changed = 1;\n+\t\t\tvsi_cur->next_vsi = NULL;\n+\t\t\tvsi_cur = tmp;\n+\t\t} while (vsi_cur);\n+\n+\t\t/* NULL terminate head of VSI list */\n+\t\thw->blk[blk].xlt2.vsig_tbl[idx].first_vsi = NULL;\n+\t}\n+\n+\t/* free characteristic list */\n+\tlist_for_each_entry_safe(del, dtmp,\n+\t\t\t\t &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,\n+\t\t\t\t list) {\n+\t\tlist_del(&del->list);\n+\t\tdevm_kfree(ice_hw_to_dev(hw), del);\n+\t}\n+\n+\t/* if VSIG characteristic list was cleared for reset\n+\t * re-initialize the list head\n+\t */\n+\tINIT_LIST_HEAD(&hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst);\n+\n+\treturn 0;\n+}\n+\n /**\n  * ice_vsig_remove_vsi - remove VSI from VSIG\n  * @hw: pointer to the hardware structure\n@@ -1162,6 +1485,62 @@ static bool ice_prof_id_rsrc_type(enum ice_block blk, u16 *rsrc_type)\n \treturn true;\n }\n \n+/**\n+ * ice_tcam_ent_rsrc_type - get TCAM entry resource type for a block type\n+ * @blk: the block type\n+ * @rsrc_type: pointer to variable to receive the resource type\n+ */\n+static bool ice_tcam_ent_rsrc_type(enum ice_block blk, u16 *rsrc_type)\n+{\n+\tswitch (blk) {\n+\tcase ICE_BLK_RSS:\n+\t\t*rsrc_type = ICE_AQC_RES_TYPE_HASH_PROF_BLDR_TCAM;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn false;\n+\t}\n+\treturn true;\n+}\n+\n+/**\n+ * ice_alloc_tcam_ent - allocate hardware TCAM entry\n+ * @hw: pointer to the HW struct\n+ * @blk: the block to allocate the TCAM for\n+ * @tcam_idx: pointer to variable to receive the TCAM entry\n+ *\n+ * This function allocates a new entry in a Profile ID TCAM for a specific\n+ * block.\n+ */\n+static enum ice_status\n+ice_alloc_tcam_ent(struct ice_hw *hw, enum ice_block blk, u16 *tcam_idx)\n+{\n+\tu16 res_type;\n+\n+\tif (!ice_tcam_ent_rsrc_type(blk, &res_type))\n+\t\treturn ICE_ERR_PARAM;\n+\n+\treturn ice_alloc_hw_res(hw, res_type, 1, true, tcam_idx);\n+}\n+\n+/**\n+ * ice_free_tcam_ent - free hardware TCAM entry\n+ * @hw: pointer to the HW struct\n+ * @blk: the block from which to free the TCAM entry\n+ * @tcam_idx: the TCAM entry to free\n+ *\n+ * This function frees an entry in a Profile ID TCAM for a specific block.\n+ */\n+static enum ice_status\n+ice_free_tcam_ent(struct ice_hw *hw, enum ice_block blk, u16 tcam_idx)\n+{\n+\tu16 res_type;\n+\n+\tif (!ice_tcam_ent_rsrc_type(blk, &res_type))\n+\t\treturn ICE_ERR_PARAM;\n+\n+\treturn ice_free_hw_res(hw, res_type, 1, &tcam_idx);\n+}\n+\n /**\n  * ice_alloc_prof_id - allocate profile ID\n  * @hw: pointer to the HW struct\n@@ -1688,6 +2067,146 @@ enum ice_status ice_init_hw_tbls(struct ice_hw *hw)\n \treturn ICE_ERR_NO_MEMORY;\n }\n \n+/**\n+ * ice_prof_gen_key - generate profile ID key\n+ * @hw: pointer to the HW struct\n+ * @blk: the block in which to write profile ID to\n+ * @ptg: packet type group (PTG) portion of key\n+ * @vsig: VSIG portion of key\n+ * @cdid: CDID portion of key\n+ * @flags: flag portion of key\n+ * @vl_msk: valid mask\n+ * @dc_msk: don't care mask\n+ * @nm_msk: never match mask\n+ * @key: output of profile ID key\n+ */\n+static enum ice_status\n+ice_prof_gen_key(struct ice_hw *hw, enum ice_block blk, u8 ptg, u16 vsig,\n+\t\t u8 cdid, u16 flags, u8 vl_msk[ICE_TCAM_KEY_VAL_SZ],\n+\t\t u8 dc_msk[ICE_TCAM_KEY_VAL_SZ], u8 nm_msk[ICE_TCAM_KEY_VAL_SZ],\n+\t\t u8 key[ICE_TCAM_KEY_SZ])\n+{\n+\tstruct ice_prof_id_key inkey;\n+\n+\tinkey.xlt1 = ptg;\n+\tinkey.xlt2_cdid = cpu_to_le16(vsig);\n+\tinkey.flags = cpu_to_le16(flags);\n+\n+\tswitch (hw->blk[blk].prof.cdid_bits) {\n+\tcase 0:\n+\t\tbreak;\n+\tcase 2:\n+#define ICE_CD_2_M 0xC000U\n+#define ICE_CD_2_S 14\n+\t\tinkey.xlt2_cdid &= ~cpu_to_le16(ICE_CD_2_M);\n+\t\tinkey.xlt2_cdid |= cpu_to_le16(BIT(cdid) << ICE_CD_2_S);\n+\t\tbreak;\n+\tcase 4:\n+#define ICE_CD_4_M 0xF000U\n+#define ICE_CD_4_S 12\n+\t\tinkey.xlt2_cdid &= ~cpu_to_le16(ICE_CD_4_M);\n+\t\tinkey.xlt2_cdid |= cpu_to_le16(BIT(cdid) << ICE_CD_4_S);\n+\t\tbreak;\n+\tcase 8:\n+#define ICE_CD_8_M 0xFF00U\n+#define ICE_CD_8_S 16\n+\t\tinkey.xlt2_cdid &= ~cpu_to_le16(ICE_CD_8_M);\n+\t\tinkey.xlt2_cdid |= cpu_to_le16(BIT(cdid) << ICE_CD_8_S);\n+\t\tbreak;\n+\tdefault:\n+\t\tice_debug(hw, ICE_DBG_PKG, \"Error in profile config\\n\");\n+\t\tbreak;\n+\t}\n+\n+\treturn ice_set_key(key, ICE_TCAM_KEY_SZ, (u8 *)&inkey, vl_msk, dc_msk,\n+\t\t\t   nm_msk, 0, ICE_TCAM_KEY_SZ / 2);\n+}\n+\n+/**\n+ * ice_tcam_write_entry - write TCAM entry\n+ * @hw: pointer to the HW struct\n+ * @blk: the block in which to write profile ID to\n+ * @idx: the entry index to write to\n+ * @prof_id: profile ID\n+ * @ptg: packet type group (PTG) portion of key\n+ * @vsig: VSIG portion of key\n+ * @cdid: CDID portion of key\n+ * @flags: flag portion of key\n+ * @vl_msk: valid mask\n+ * @dc_msk: don't care mask\n+ * @nm_msk: never match mask\n+ */\n+static enum ice_status\n+ice_tcam_write_entry(struct ice_hw *hw, enum ice_block blk, u16 idx,\n+\t\t     u8 prof_id, u8 ptg, u16 vsig, u8 cdid, u16 flags,\n+\t\t     u8 vl_msk[ICE_TCAM_KEY_VAL_SZ],\n+\t\t     u8 dc_msk[ICE_TCAM_KEY_VAL_SZ],\n+\t\t     u8 nm_msk[ICE_TCAM_KEY_VAL_SZ])\n+{\n+\tstruct ice_prof_tcam_entry;\n+\tenum ice_status status;\n+\n+\tstatus = ice_prof_gen_key(hw, blk, ptg, vsig, cdid, flags, vl_msk,\n+\t\t\t\t  dc_msk, nm_msk, hw->blk[blk].prof.t[idx].key);\n+\tif (!status) {\n+\t\thw->blk[blk].prof.t[idx].addr = cpu_to_le16(idx);\n+\t\thw->blk[blk].prof.t[idx].prof_id = prof_id;\n+\t}\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_vsig_get_ref - returns number of VSIs belong to a VSIG\n+ * @hw: pointer to the hardware structure\n+ * @blk: HW block\n+ * @vsig: VSIG to query\n+ * @refs: pointer to variable to receive the reference count\n+ */\n+static enum ice_status\n+ice_vsig_get_ref(struct ice_hw *hw, enum ice_block blk, u16 vsig, u16 *refs)\n+{\n+\tu16 idx = vsig & ICE_VSIG_IDX_M;\n+\tstruct ice_vsig_vsi *ptr;\n+\n+\t*refs = 0;\n+\n+\tif (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use)\n+\t\treturn ICE_ERR_DOES_NOT_EXIST;\n+\n+\tptr = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;\n+\twhile (ptr) {\n+\t\t(*refs)++;\n+\t\tptr = ptr->next_vsi;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_has_prof_vsig - check to see if VSIG has a specific profile\n+ * @hw: pointer to the hardware structure\n+ * @blk: HW block\n+ * @vsig: VSIG to check against\n+ * @hdl: profile handle\n+ */\n+static bool\n+ice_has_prof_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl)\n+{\n+\tu16 idx = vsig & ICE_VSIG_IDX_M;\n+\tstruct ice_vsig_prof *ent;\n+\n+\tlist_for_each_entry(ent, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,\n+\t\t\t    list)\n+\t\tif (ent->profile_cookie == hdl)\n+\t\t\treturn true;\n+\n+\tice_debug(hw, ICE_DBG_INIT,\n+\t\t  \"Characteristic list for VSI group %d not found.\\n\",\n+\t\t  vsig);\n+\treturn false;\n+}\n+\n /**\n  * ice_add_prof - add profile\n  * @hw: pointer to the HW struct\n@@ -1792,3 +2311,802 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],\n \tmutex_unlock(&hw->blk[blk].es.prof_map_lock);\n \treturn status;\n }\n+\n+/**\n+ * ice_search_prof_id_low - Search for a profile tracking ID low level\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @id: profile tracking ID\n+ *\n+ * This will search for a profile tracking ID which was previously added. This\n+ * version assumes that the caller has already acquired the prof map lock.\n+ */\n+static struct ice_prof_map *\n+ice_search_prof_id_low(struct ice_hw *hw, enum ice_block blk, u64 id)\n+{\n+\tstruct ice_prof_map *entry = NULL;\n+\tstruct ice_prof_map *map;\n+\n+\tlist_for_each_entry(map, &hw->blk[blk].es.prof_map, list)\n+\t\tif (map->profile_cookie == id) {\n+\t\t\tentry = map;\n+\t\t\tbreak;\n+\t\t}\n+\n+\treturn entry;\n+}\n+\n+/**\n+ * ice_search_prof_id - Search for a profile tracking ID\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @id: profile tracking ID\n+ *\n+ * This will search for a profile tracking ID which was previously added.\n+ */\n+static struct ice_prof_map *\n+ice_search_prof_id(struct ice_hw *hw, enum ice_block blk, u64 id)\n+{\n+\tstruct ice_prof_map *entry;\n+\n+\tmutex_lock(&hw->blk[blk].es.prof_map_lock);\n+\tentry = ice_search_prof_id_low(hw, blk, id);\n+\tmutex_unlock(&hw->blk[blk].es.prof_map_lock);\n+\n+\treturn entry;\n+}\n+\n+/**\n+ * ice_rel_tcam_idx - release a TCAM index\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @idx: the index to release\n+ */\n+static enum ice_status\n+ice_rel_tcam_idx(struct ice_hw *hw, enum ice_block blk, u16 idx)\n+{\n+\t/* Masks to invoke a never match entry */\n+\tu8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };\n+\tu8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF };\n+\tu8 nm_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x01, 0x00, 0x00, 0x00, 0x00 };\n+\tenum ice_status status;\n+\n+\t/* write the TCAM entry */\n+\tstatus = ice_tcam_write_entry(hw, blk, idx, 0, 0, 0, 0, 0, vl_msk,\n+\t\t\t\t      dc_msk, nm_msk);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* release the TCAM entry */\n+\tstatus = ice_free_tcam_ent(hw, blk, idx);\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_rem_prof_id - remove one profile from a VSIG\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @prof: pointer to profile structure to remove\n+ */\n+static enum ice_status\n+ice_rem_prof_id(struct ice_hw *hw, enum ice_block blk,\n+\t\tstruct ice_vsig_prof *prof)\n+{\n+\tenum ice_status status;\n+\tu16 i;\n+\n+\tfor (i = 0; i < prof->tcam_count; i++)\n+\t\tif (prof->tcam[i].in_use) {\n+\t\t\tprof->tcam[i].in_use = false;\n+\t\t\tstatus = ice_rel_tcam_idx(hw, blk,\n+\t\t\t\t\t\t  prof->tcam[i].tcam_idx);\n+\t\t\tif (status)\n+\t\t\t\treturn ICE_ERR_HW_TABLE;\n+\t\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_rem_vsig - remove VSIG\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @vsig: the VSIG to remove\n+ * @chg: the change list\n+ */\n+static enum ice_status\n+ice_rem_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig,\n+\t     struct list_head *chg)\n+{\n+\tu16 idx = vsig & ICE_VSIG_IDX_M;\n+\tstruct ice_vsig_vsi *vsi_cur;\n+\tstruct ice_vsig_prof *d, *t;\n+\tenum ice_status status;\n+\n+\t/* remove TCAM entries */\n+\tlist_for_each_entry_safe(d, t,\n+\t\t\t\t &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,\n+\t\t\t\t list) {\n+\t\tstatus = ice_rem_prof_id(hw, blk, d);\n+\t\tif (status)\n+\t\t\treturn status;\n+\n+\t\tlist_del(&d->list);\n+\t\tdevm_kfree(ice_hw_to_dev(hw), d);\n+\t}\n+\n+\t/* Move all VSIS associated with this VSIG to the default VSIG */\n+\tvsi_cur = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;\n+\t/* If the VSIG has at least 1 VSI then iterate through the list\n+\t * and remove the VSIs before deleting the group.\n+\t */\n+\tif (vsi_cur)\n+\t\tdo {\n+\t\t\tstruct ice_vsig_vsi *tmp = vsi_cur->next_vsi;\n+\t\t\tstruct ice_chs_chg *p;\n+\n+\t\t\tp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*p),\n+\t\t\t\t\t GFP_KERNEL);\n+\t\t\tif (!p)\n+\t\t\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\t\t\tp->type = ICE_VSIG_REM;\n+\t\t\tp->orig_vsig = vsig;\n+\t\t\tp->vsig = ICE_DEFAULT_VSIG;\n+\t\t\tp->vsi = vsi_cur - hw->blk[blk].xlt2.vsis;\n+\n+\t\t\tlist_add(&p->list_entry, chg);\n+\n+\t\t\tvsi_cur = tmp;\n+\t\t} while (vsi_cur);\n+\n+\treturn ice_vsig_free(hw, blk, vsig);\n+}\n+\n+/**\n+ * ice_get_prof - get profile\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @hdl: profile handle\n+ * @chg: change list\n+ */\n+static enum ice_status\n+ice_get_prof(struct ice_hw *hw, enum ice_block blk, u64 hdl,\n+\t     struct list_head *chg)\n+{\n+\tstruct ice_prof_map *map;\n+\tstruct ice_chs_chg *p;\n+\tu16 i;\n+\n+\t/* Get the details on the profile specified by the handle ID */\n+\tmap = ice_search_prof_id(hw, blk, hdl);\n+\tif (!map)\n+\t\treturn ICE_ERR_DOES_NOT_EXIST;\n+\n+\tfor (i = 0; i < map->ptg_cnt; i++)\n+\t\tif (!hw->blk[blk].es.written[map->prof_id]) {\n+\t\t\t/* add ES to change list */\n+\t\t\tp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*p),\n+\t\t\t\t\t GFP_KERNEL);\n+\t\t\tif (!p)\n+\t\t\t\tgoto err_ice_get_prof;\n+\n+\t\t\tp->type = ICE_PTG_ES_ADD;\n+\t\t\tp->ptype = 0;\n+\t\t\tp->ptg = map->ptg[i];\n+\t\t\tp->add_ptg = 0;\n+\n+\t\t\tp->add_prof = 1;\n+\t\t\tp->prof_id = map->prof_id;\n+\n+\t\t\thw->blk[blk].es.written[map->prof_id] = true;\n+\n+\t\t\tlist_add(&p->list_entry, chg);\n+\t\t}\n+\n+\treturn 0;\n+\n+err_ice_get_prof:\n+\t/* let caller clean up the change list */\n+\treturn ICE_ERR_NO_MEMORY;\n+}\n+\n+/**\n+ * ice_get_profs_vsig - get a copy of the list of profiles from a VSIG\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @vsig: VSIG from which to copy the list\n+ * @lst: output list\n+ *\n+ * This routine makes a copy of the list of profiles in the specified VSIG.\n+ */\n+static enum ice_status\n+ice_get_profs_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig,\n+\t\t   struct list_head *lst)\n+{\n+\tstruct ice_vsig_prof *ent1, *ent2;\n+\tu16 idx = vsig & ICE_VSIG_IDX_M;\n+\n+\tlist_for_each_entry(ent1, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,\n+\t\t\t    list) {\n+\t\tstruct ice_vsig_prof *p;\n+\n+\t\t/* copy to the input list */\n+\t\tp = devm_kmemdup(ice_hw_to_dev(hw), ent1, sizeof(*p),\n+\t\t\t\t GFP_KERNEL);\n+\t\tif (!p)\n+\t\t\tgoto err_ice_get_profs_vsig;\n+\n+\t\tlist_add_tail(&p->list, lst);\n+\t}\n+\n+\treturn 0;\n+\n+err_ice_get_profs_vsig:\n+\tlist_for_each_entry_safe(ent1, ent2, lst, list) {\n+\t\tlist_del(&ent1->list);\n+\t\tdevm_kfree(ice_hw_to_dev(hw), ent1);\n+\t}\n+\n+\treturn ICE_ERR_NO_MEMORY;\n+}\n+\n+/**\n+ * ice_add_prof_to_lst - add profile entry to a list\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @lst: the list to be added to\n+ * @hdl: profile handle of entry to add\n+ */\n+static enum ice_status\n+ice_add_prof_to_lst(struct ice_hw *hw, enum ice_block blk,\n+\t\t    struct list_head *lst, u64 hdl)\n+{\n+\tstruct ice_prof_map *map;\n+\tstruct ice_vsig_prof *p;\n+\tu16 i;\n+\n+\tmap = ice_search_prof_id(hw, blk, hdl);\n+\tif (!map)\n+\t\treturn ICE_ERR_DOES_NOT_EXIST;\n+\n+\tp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*p), GFP_KERNEL);\n+\tif (!p)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tp->profile_cookie = map->profile_cookie;\n+\tp->prof_id = map->prof_id;\n+\tp->tcam_count = map->ptg_cnt;\n+\n+\tfor (i = 0; i < map->ptg_cnt; i++) {\n+\t\tp->tcam[i].prof_id = map->prof_id;\n+\t\tp->tcam[i].tcam_idx = ICE_INVALID_TCAM;\n+\t\tp->tcam[i].ptg = map->ptg[i];\n+\t}\n+\n+\tlist_add(&p->list, lst);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_move_vsi - move VSI to another VSIG\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @vsi: the VSI to move\n+ * @vsig: the VSIG to move the VSI to\n+ * @chg: the change list\n+ */\n+static enum ice_status\n+ice_move_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig,\n+\t     struct list_head *chg)\n+{\n+\tenum ice_status status;\n+\tstruct ice_chs_chg *p;\n+\tu16 orig_vsig;\n+\n+\tp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*p), GFP_KERNEL);\n+\tif (!p)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tstatus = ice_vsig_find_vsi(hw, blk, vsi, &orig_vsig);\n+\tif (!status)\n+\t\tstatus = ice_vsig_add_mv_vsi(hw, blk, vsi, vsig);\n+\n+\tif (status) {\n+\t\tdevm_kfree(ice_hw_to_dev(hw), p);\n+\t\treturn status;\n+\t}\n+\n+\tp->type = ICE_VSI_MOVE;\n+\tp->vsi = vsi;\n+\tp->orig_vsig = orig_vsig;\n+\tp->vsig = vsig;\n+\n+\tlist_add(&p->list_entry, chg);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_prof_tcam_ena_dis - add enable or disable TCAM change\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @enable: true to enable, false to disable\n+ * @vsig: the VSIG of the TCAM entry\n+ * @tcam: pointer the TCAM info structure of the TCAM to disable\n+ * @chg: the change list\n+ *\n+ * This function appends an enable or disable TCAM entry in the change log\n+ */\n+static enum ice_status\n+ice_prof_tcam_ena_dis(struct ice_hw *hw, enum ice_block blk, bool enable,\n+\t\t      u16 vsig, struct ice_tcam_inf *tcam,\n+\t\t      struct list_head *chg)\n+{\n+\tenum ice_status status;\n+\tstruct ice_chs_chg *p;\n+\n+\t/* Default: enable means change the low flag bit to don't care */\n+\tu8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x01, 0x00, 0x00, 0x00, 0x00 };\n+\tu8 nm_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x00, 0x00, 0x00, 0x00, 0x00 };\n+\tu8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x01, 0x00, 0x00, 0x00, 0x00 };\n+\n+\t/* if disabling, free the TCAM */\n+\tif (!enable) {\n+\t\tstatus = ice_free_tcam_ent(hw, blk, tcam->tcam_idx);\n+\t\ttcam->tcam_idx = 0;\n+\t\ttcam->in_use = 0;\n+\t\treturn status;\n+\t}\n+\n+\t/* for re-enabling, reallocate a TCAM */\n+\tstatus = ice_alloc_tcam_ent(hw, blk, &tcam->tcam_idx);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* add TCAM to change list */\n+\tp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*p), GFP_KERNEL);\n+\tif (!p)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tstatus = ice_tcam_write_entry(hw, blk, tcam->tcam_idx, tcam->prof_id,\n+\t\t\t\t      tcam->ptg, vsig, 0, 0, vl_msk, dc_msk,\n+\t\t\t\t      nm_msk);\n+\tif (status)\n+\t\tgoto err_ice_prof_tcam_ena_dis;\n+\n+\ttcam->in_use = 1;\n+\n+\tp->type = ICE_TCAM_ADD;\n+\tp->add_tcam_idx = true;\n+\tp->prof_id = tcam->prof_id;\n+\tp->ptg = tcam->ptg;\n+\tp->vsig = 0;\n+\tp->tcam_idx = tcam->tcam_idx;\n+\n+\t/* log change */\n+\tlist_add(&p->list_entry, chg);\n+\n+\treturn 0;\n+\n+err_ice_prof_tcam_ena_dis:\n+\tdevm_kfree(ice_hw_to_dev(hw), p);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_adj_prof_priorities - adjust profile based on priorities\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @vsig: the VSIG for which to adjust profile priorities\n+ * @chg: the change list\n+ */\n+static enum ice_status\n+ice_adj_prof_priorities(struct ice_hw *hw, enum ice_block blk, u16 vsig,\n+\t\t\tstruct list_head *chg)\n+{\n+\tDECLARE_BITMAP(ptgs_used, ICE_XLT1_CNT);\n+\tstruct ice_vsig_prof *t;\n+\tenum ice_status status;\n+\tu16 idx;\n+\n+\tbitmap_zero(ptgs_used, ICE_XLT1_CNT);\n+\tidx = vsig & ICE_VSIG_IDX_M;\n+\n+\t/* Priority is based on the order in which the profiles are added. The\n+\t * newest added profile has highest priority and the oldest added\n+\t * profile has the lowest priority. Since the profile property list for\n+\t * a VSIG is sorted from newest to oldest, this code traverses the list\n+\t * in order and enables the first of each PTG that it finds (that is not\n+\t * already enabled); it also disables any duplicate PTGs that it finds\n+\t * in the older profiles (that are currently enabled).\n+\t */\n+\n+\tlist_for_each_entry(t, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,\n+\t\t\t    list) {\n+\t\tu16 i;\n+\n+\t\tfor (i = 0; i < t->tcam_count; i++) {\n+\t\t\t/* Scan the priorities from newest to oldest.\n+\t\t\t * Make sure that the newest profiles take priority.\n+\t\t\t */\n+\t\t\tif (test_bit(t->tcam[i].ptg, ptgs_used) &&\n+\t\t\t    t->tcam[i].in_use) {\n+\t\t\t\t/* need to mark this PTG as never match, as it\n+\t\t\t\t * was already in use and therefore duplicate\n+\t\t\t\t * (and lower priority)\n+\t\t\t\t */\n+\t\t\t\tstatus = ice_prof_tcam_ena_dis(hw, blk, false,\n+\t\t\t\t\t\t\t       vsig,\n+\t\t\t\t\t\t\t       &t->tcam[i],\n+\t\t\t\t\t\t\t       chg);\n+\t\t\t\tif (status)\n+\t\t\t\t\treturn status;\n+\t\t\t} else if (!test_bit(t->tcam[i].ptg, ptgs_used) &&\n+\t\t\t\t   !t->tcam[i].in_use) {\n+\t\t\t\t/* need to enable this PTG, as it in not in use\n+\t\t\t\t * and not enabled (highest priority)\n+\t\t\t\t */\n+\t\t\t\tstatus = ice_prof_tcam_ena_dis(hw, blk, true,\n+\t\t\t\t\t\t\t       vsig,\n+\t\t\t\t\t\t\t       &t->tcam[i],\n+\t\t\t\t\t\t\t       chg);\n+\t\t\t\tif (status)\n+\t\t\t\t\treturn status;\n+\t\t\t}\n+\n+\t\t\t/* keep track of used ptgs */\n+\t\t\tset_bit(t->tcam[i].ptg, ptgs_used);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_add_prof_id_vsig - add profile to VSIG\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @vsig: the VSIG to which this profile is to be added\n+ * @hdl: the profile handle indicating the profile to add\n+ * @chg: the change list\n+ */\n+static enum ice_status\n+ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl,\n+\t\t     struct list_head *chg)\n+{\n+\t/* Masks that ignore flags */\n+\tu8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };\n+\tu8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0x00, 0x00, 0x00 };\n+\tu8 nm_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x00, 0x00, 0x00, 0x00, 0x00 };\n+\tstruct ice_prof_map *map;\n+\tstruct ice_vsig_prof *t;\n+\tstruct ice_chs_chg *p;\n+\tu16 i;\n+\n+\t/* Get the details on the profile specified by the handle ID */\n+\tmap = ice_search_prof_id(hw, blk, hdl);\n+\tif (!map)\n+\t\treturn ICE_ERR_DOES_NOT_EXIST;\n+\n+\t/* Error, if this VSIG already has this profile */\n+\tif (ice_has_prof_vsig(hw, blk, vsig, hdl))\n+\t\treturn ICE_ERR_ALREADY_EXISTS;\n+\n+\t/* new VSIG profile structure */\n+\tt = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*t), GFP_KERNEL);\n+\tif (!t)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tt->profile_cookie = map->profile_cookie;\n+\tt->prof_id = map->prof_id;\n+\tt->tcam_count = map->ptg_cnt;\n+\n+\t/* create TCAM entries */\n+\tfor (i = 0; i < map->ptg_cnt; i++) {\n+\t\tenum ice_status status;\n+\t\tu16 tcam_idx;\n+\n+\t\t/* add TCAM to change list */\n+\t\tp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*p), GFP_KERNEL);\n+\t\tif (!p)\n+\t\t\tgoto err_ice_add_prof_id_vsig;\n+\n+\t\t/* allocate the TCAM entry index */\n+\t\tstatus = ice_alloc_tcam_ent(hw, blk, &tcam_idx);\n+\t\tif (status) {\n+\t\t\tdevm_kfree(ice_hw_to_dev(hw), p);\n+\t\t\tgoto err_ice_add_prof_id_vsig;\n+\t\t}\n+\n+\t\tt->tcam[i].ptg = map->ptg[i];\n+\t\tt->tcam[i].prof_id = map->prof_id;\n+\t\tt->tcam[i].tcam_idx = tcam_idx;\n+\t\tt->tcam[i].in_use = true;\n+\n+\t\tp->type = ICE_TCAM_ADD;\n+\t\tp->add_tcam_idx = true;\n+\t\tp->prof_id = t->tcam[i].prof_id;\n+\t\tp->ptg = t->tcam[i].ptg;\n+\t\tp->vsig = vsig;\n+\t\tp->tcam_idx = t->tcam[i].tcam_idx;\n+\n+\t\t/* write the TCAM entry */\n+\t\tstatus = ice_tcam_write_entry(hw, blk, t->tcam[i].tcam_idx,\n+\t\t\t\t\t      t->tcam[i].prof_id,\n+\t\t\t\t\t      t->tcam[i].ptg, vsig, 0, 0,\n+\t\t\t\t\t      vl_msk, dc_msk, nm_msk);\n+\t\tif (status)\n+\t\t\tgoto err_ice_add_prof_id_vsig;\n+\n+\t\t/* log change */\n+\t\tlist_add(&p->list_entry, chg);\n+\t}\n+\n+\t/* add profile to VSIG */\n+\tlist_add(&t->list,\n+\t\t &hw->blk[blk].xlt2.vsig_tbl[(vsig & ICE_VSIG_IDX_M)].prop_lst);\n+\n+\treturn 0;\n+\n+err_ice_add_prof_id_vsig:\n+\t/* let caller clean up the change list */\n+\tdevm_kfree(ice_hw_to_dev(hw), t);\n+\treturn ICE_ERR_NO_MEMORY;\n+}\n+\n+/**\n+ * ice_create_prof_id_vsig - add a new VSIG with a single profile\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @vsi: the initial VSI that will be in VSIG\n+ * @hdl: the profile handle of the profile that will be added to the VSIG\n+ * @chg: the change list\n+ */\n+static enum ice_status\n+ice_create_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl,\n+\t\t\tstruct list_head *chg)\n+{\n+\tenum ice_status status;\n+\tstruct ice_chs_chg *p;\n+\tu16 new_vsig;\n+\n+\tp = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*p), GFP_KERNEL);\n+\tif (!p)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tnew_vsig = ice_vsig_alloc(hw, blk);\n+\tif (!new_vsig) {\n+\t\tstatus = ICE_ERR_HW_TABLE;\n+\t\tgoto err_ice_create_prof_id_vsig;\n+\t}\n+\n+\tstatus = ice_move_vsi(hw, blk, vsi, new_vsig, chg);\n+\tif (status)\n+\t\tgoto err_ice_create_prof_id_vsig;\n+\n+\tstatus = ice_add_prof_id_vsig(hw, blk, new_vsig, hdl, chg);\n+\tif (status)\n+\t\tgoto err_ice_create_prof_id_vsig;\n+\n+\tp->type = ICE_VSIG_ADD;\n+\tp->vsi = vsi;\n+\tp->orig_vsig = ICE_DEFAULT_VSIG;\n+\tp->vsig = new_vsig;\n+\n+\tlist_add(&p->list_entry, chg);\n+\n+\treturn 0;\n+\n+err_ice_create_prof_id_vsig:\n+\t/* let caller clean up the change list */\n+\tdevm_kfree(ice_hw_to_dev(hw), p);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_create_vsig_from_lst - create a new VSIG with a list of profiles\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @vsi: the initial VSI that will be in VSIG\n+ * @lst: the list of profile that will be added to the VSIG\n+ * @chg: the change list\n+ */\n+static enum ice_status\n+ice_create_vsig_from_lst(struct ice_hw *hw, enum ice_block blk, u16 vsi,\n+\t\t\t struct list_head *lst, struct list_head *chg)\n+{\n+\tstruct ice_vsig_prof *t;\n+\tenum ice_status status;\n+\tu16 vsig;\n+\n+\tvsig = ice_vsig_alloc(hw, blk);\n+\tif (!vsig)\n+\t\treturn ICE_ERR_HW_TABLE;\n+\n+\tstatus = ice_move_vsi(hw, blk, vsi, vsig, chg);\n+\tif (status)\n+\t\treturn status;\n+\n+\tlist_for_each_entry(t, lst, list) {\n+\t\tstatus = ice_add_prof_id_vsig(hw, blk, vsig, t->profile_cookie,\n+\t\t\t\t\t      chg);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_find_prof_vsig - find a VSIG with a specific profile handle\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @hdl: the profile handle of the profile to search for\n+ * @vsig: returns the VSIG with the matching profile\n+ */\n+static bool\n+ice_find_prof_vsig(struct ice_hw *hw, enum ice_block blk, u64 hdl, u16 *vsig)\n+{\n+\tstruct ice_vsig_prof *t;\n+\tenum ice_status status;\n+\tstruct list_head lst;\n+\n+\tINIT_LIST_HEAD(&lst);\n+\n+\tt = kzalloc(sizeof(*t), GFP_KERNEL);\n+\tif (!t)\n+\t\treturn false;\n+\n+\tt->profile_cookie = hdl;\n+\tlist_add(&t->list, &lst);\n+\n+\tstatus = ice_find_dup_props_vsig(hw, blk, &lst, vsig);\n+\n+\tlist_del(&t->list);\n+\tkfree(t);\n+\n+\treturn !status;\n+}\n+\n+/**\n+ * ice_add_prof_id_flow - add profile flow\n+ * @hw: pointer to the HW struct\n+ * @blk: hardware block\n+ * @vsi: the VSI to enable with the profile specified by ID\n+ * @hdl: profile handle\n+ *\n+ * Calling this function will update the hardware tables to enable the\n+ * profile indicated by the ID parameter for the VSIs specified in the VSI\n+ * array. Once successfully called, the flow will be enabled.\n+ */\n+enum ice_status\n+ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl)\n+{\n+\tstruct ice_vsig_prof *tmp1, *del1;\n+\tstruct ice_chs_chg *tmp, *del;\n+\tstruct list_head union_lst;\n+\tenum ice_status status;\n+\tstruct list_head chg;\n+\tu16 vsig;\n+\n+\tINIT_LIST_HEAD(&union_lst);\n+\tINIT_LIST_HEAD(&chg);\n+\n+\t/* Get profile */\n+\tstatus = ice_get_prof(hw, blk, hdl, &chg);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* determine if VSI is already part of a VSIG */\n+\tstatus = ice_vsig_find_vsi(hw, blk, vsi, &vsig);\n+\tif (!status && vsig) {\n+\t\tbool only_vsi;\n+\t\tu16 or_vsig;\n+\t\tu16 ref;\n+\n+\t\t/* found in VSIG */\n+\t\tor_vsig = vsig;\n+\n+\t\t/* make sure that there is no overlap/conflict between the new\n+\t\t * characteristics and the existing ones; we don't support that\n+\t\t * scenario\n+\t\t */\n+\t\tif (ice_has_prof_vsig(hw, blk, vsig, hdl)) {\n+\t\t\tstatus = ICE_ERR_ALREADY_EXISTS;\n+\t\t\tgoto err_ice_add_prof_id_flow;\n+\t\t}\n+\n+\t\t/* last VSI in the VSIG? */\n+\t\tstatus = ice_vsig_get_ref(hw, blk, vsig, &ref);\n+\t\tif (status)\n+\t\t\tgoto err_ice_add_prof_id_flow;\n+\t\tonly_vsi = (ref == 1);\n+\n+\t\t/* create a union of the current profiles and the one being\n+\t\t * added\n+\t\t */\n+\t\tstatus = ice_get_profs_vsig(hw, blk, vsig, &union_lst);\n+\t\tif (status)\n+\t\t\tgoto err_ice_add_prof_id_flow;\n+\n+\t\tstatus = ice_add_prof_to_lst(hw, blk, &union_lst, hdl);\n+\t\tif (status)\n+\t\t\tgoto err_ice_add_prof_id_flow;\n+\n+\t\t/* search for an existing VSIG with an exact charc match */\n+\t\tstatus = ice_find_dup_props_vsig(hw, blk, &union_lst, &vsig);\n+\t\tif (!status) {\n+\t\t\t/* move VSI to the VSIG that matches */\n+\t\t\tstatus = ice_move_vsi(hw, blk, vsi, vsig, &chg);\n+\t\t\tif (status)\n+\t\t\t\tgoto err_ice_add_prof_id_flow;\n+\n+\t\t\t/* VSI has been moved out of or_vsig. If the or_vsig had\n+\t\t\t * only that VSI it is now empty and can be removed.\n+\t\t\t */\n+\t\t\tif (only_vsi) {\n+\t\t\t\tstatus = ice_rem_vsig(hw, blk, or_vsig, &chg);\n+\t\t\t\tif (status)\n+\t\t\t\t\tgoto err_ice_add_prof_id_flow;\n+\t\t\t}\n+\t\t} else if (only_vsi) {\n+\t\t\t/* If the original VSIG only contains one VSI, then it\n+\t\t\t * will be the requesting VSI. In this case the VSI is\n+\t\t\t * not sharing entries and we can simply add the new\n+\t\t\t * profile to the VSIG.\n+\t\t\t */\n+\t\t\tstatus = ice_add_prof_id_vsig(hw, blk, vsig, hdl, &chg);\n+\t\t\tif (status)\n+\t\t\t\tgoto err_ice_add_prof_id_flow;\n+\n+\t\t\t/* Adjust priorities */\n+\t\t\tstatus = ice_adj_prof_priorities(hw, blk, vsig, &chg);\n+\t\t\tif (status)\n+\t\t\t\tgoto err_ice_add_prof_id_flow;\n+\t\t} else {\n+\t\t\t/* No match, so we need a new VSIG */\n+\t\t\tstatus = ice_create_vsig_from_lst(hw, blk, vsi,\n+\t\t\t\t\t\t\t  &union_lst, &chg);\n+\t\t\tif (status)\n+\t\t\t\tgoto err_ice_add_prof_id_flow;\n+\n+\t\t\t/* Adjust priorities */\n+\t\t\tstatus = ice_adj_prof_priorities(hw, blk, vsig, &chg);\n+\t\t\tif (status)\n+\t\t\t\tgoto err_ice_add_prof_id_flow;\n+\t\t}\n+\t} else {\n+\t\t/* need to find or add a VSIG */\n+\t\t/* search for an existing VSIG with an exact charc match */\n+\t\tif (ice_find_prof_vsig(hw, blk, hdl, &vsig)) {\n+\t\t\t/* found an exact match */\n+\t\t\t/* add or move VSI to the VSIG that matches */\n+\t\t\tstatus = ice_move_vsi(hw, blk, vsi, vsig, &chg);\n+\t\t\tif (status)\n+\t\t\t\tgoto err_ice_add_prof_id_flow;\n+\t\t} else {\n+\t\t\t/* we did not find an exact match */\n+\t\t\t/* we need to add a VSIG */\n+\t\t\tstatus = ice_create_prof_id_vsig(hw, blk, vsi, hdl,\n+\t\t\t\t\t\t\t &chg);\n+\t\t\tif (status)\n+\t\t\t\tgoto err_ice_add_prof_id_flow;\n+\t\t}\n+\t}\n+\n+err_ice_add_prof_id_flow:\n+\tlist_for_each_entry_safe(del, tmp, &chg, list_entry) {\n+\t\tlist_del(&del->list_entry);\n+\t\tdevm_kfree(ice_hw_to_dev(hw), del);\n+\t}\n+\n+\tlist_for_each_entry_safe(del1, tmp1, &union_lst, list) {\n+\t\tlist_del(&del1->list);\n+\t\tdevm_kfree(ice_hw_to_dev(hw), del1);\n+\t}\n+\n+\treturn status;\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.h b/drivers/net/ethernet/intel/ice/ice_flex_pipe.h\nindex 8cb7d7f09e0b..33e4510da24c 100644\n--- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.h\n+++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.h\n@@ -21,6 +21,8 @@\n enum ice_status\n ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],\n \t     struct ice_fv_word *es);\n+enum ice_status\n+ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl);\n enum ice_status ice_init_pkg(struct ice_hw *hw, u8 *buff, u32 len);\n enum ice_status\n ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, u32 len);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_flex_type.h b/drivers/net/ethernet/intel/ice/ice_flex_type.h\nindex 3005f111fb3b..9d95d51bc760 100644\n--- a/drivers/net/ethernet/intel/ice/ice_flex_type.h\n+++ b/drivers/net/ethernet/intel/ice/ice_flex_type.h\n@@ -283,6 +283,7 @@ struct ice_ptg_ptype {\n \tu8 ptg;\n };\n \n+#define ICE_MAX_TCAM_PER_PROFILE\t32\n #define ICE_MAX_PTG_PER_PROFILE\t\t32\n \n struct ice_prof_map {\n@@ -294,6 +295,23 @@ struct ice_prof_map {\n \tu8 ptg[ICE_MAX_PTG_PER_PROFILE];\n };\n \n+#define ICE_INVALID_TCAM\t0xFFFF\n+\n+struct ice_tcam_inf {\n+\tu16 tcam_idx;\n+\tu8 ptg;\n+\tu8 prof_id;\n+\tu8 in_use;\n+};\n+\n+struct ice_vsig_prof {\n+\tstruct list_head list;\n+\tu64 profile_cookie;\n+\tu8 prof_id;\n+\tu8 tcam_count;\n+\tstruct ice_tcam_inf tcam[ICE_MAX_TCAM_PER_PROFILE];\n+};\n+\n struct ice_vsig_entry {\n \tstruct list_head prop_lst;\n \tstruct ice_vsig_vsi *first_vsi;\n@@ -343,6 +361,13 @@ struct ice_xlt2 {\n \tu16 count;\n };\n \n+/* Profile ID Management */\n+struct ice_prof_id_key {\n+\t__le16 flags;\n+\tu8 xlt1;\n+\t__le16 xlt2_cdid;\n+} __packed;\n+\n /* Keys are made up of two values, each one-half the size of the key.\n  * For TCAM, the entire key is 80 bits wide (or 2, 40-bit wide values)\n  */\n@@ -385,5 +410,31 @@ struct ice_blk_info {\n \tu8 is_list_init;\n };\n \n+enum ice_chg_type {\n+\tICE_TCAM_NONE = 0,\n+\tICE_PTG_ES_ADD,\n+\tICE_TCAM_ADD,\n+\tICE_VSIG_ADD,\n+\tICE_VSIG_REM,\n+\tICE_VSI_MOVE,\n+};\n+\n+struct ice_chs_chg {\n+\tstruct list_head list_entry;\n+\tenum ice_chg_type type;\n+\n+\tu8 add_ptg;\n+\tu8 add_vsig;\n+\tu8 add_tcam_idx;\n+\tu8 add_prof;\n+\tu16 ptype;\n+\tu8 ptg;\n+\tu8 prof_id;\n+\tu16 vsi;\n+\tu16 vsig;\n+\tu16 orig_vsig;\n+\tu16 tcam_idx;\n+};\n+\n #define ICE_FLOW_PTYPE_MAX\t\tICE_XLT1_CNT\n #endif /* _ICE_FLEX_TYPE_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_flow.c b/drivers/net/ethernet/intel/ice/ice_flow.c\nindex 24fe04f8baa2..1bbf4b6ed7d2 100644\n--- a/drivers/net/ethernet/intel/ice/ice_flow.c\n+++ b/drivers/net/ethernet/intel/ice/ice_flow.c\n@@ -450,6 +450,38 @@ ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,\n \treturn status;\n }\n \n+/**\n+ * ice_flow_assoc_prof - associate a VSI with a flow profile\n+ * @hw: pointer to the hardware structure\n+ * @blk: classification stage\n+ * @prof: pointer to flow profile\n+ * @vsi_handle: software VSI handle\n+ *\n+ * Assumption: the caller has acquired the lock to the profile list\n+ * and the software VSI handle has been validated\n+ */\n+static enum ice_status\n+ice_flow_assoc_prof(struct ice_hw *hw, enum ice_block blk,\n+\t\t    struct ice_flow_prof *prof, u16 vsi_handle)\n+{\n+\tenum ice_status status = 0;\n+\n+\tif (!test_bit(vsi_handle, prof->vsis)) {\n+\t\tstatus = ice_add_prof_id_flow(hw, blk,\n+\t\t\t\t\t      ice_get_hw_vsi_num(hw,\n+\t\t\t\t\t\t\t\t vsi_handle),\n+\t\t\t\t\t      prof->id);\n+\t\tif (!status)\n+\t\t\tset_bit(vsi_handle, prof->vsis);\n+\t\telse\n+\t\t\tice_debug(hw, ICE_DBG_FLOW,\n+\t\t\t\t  \"HW profile add failed, %d\\n\",\n+\t\t\t\t  status);\n+\t}\n+\n+\treturn status;\n+}\n+\n /**\n  * ice_flow_add_prof - Add a flow profile for packet segments and matched fields\n  * @hw: pointer to the HW struct\n@@ -458,12 +490,13 @@ ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,\n  * @prof_id: unique ID to identify this flow profile\n  * @segs: array of one or more packet segments that describe the flow\n  * @segs_cnt: number of packet segments provided\n+ * @prof: stores the returned flow profile added\n  */\n static enum ice_status\n ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,\n-\t\t  u64 prof_id, struct ice_flow_seg_info *segs, u8 segs_cnt)\n+\t\t  u64 prof_id, struct ice_flow_seg_info *segs, u8 segs_cnt,\n+\t\t  struct ice_flow_prof **prof)\n {\n-\tstruct ice_flow_prof *prof = NULL;\n \tenum ice_status status;\n \n \tif (segs_cnt > ICE_FLOW_SEG_MAX)\n@@ -482,9 +515,9 @@ ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,\n \tmutex_lock(&hw->fl_profs_locks[blk]);\n \n \tstatus = ice_flow_add_prof_sync(hw, blk, dir, prof_id, segs, segs_cnt,\n-\t\t\t\t\t&prof);\n+\t\t\t\t\tprof);\n \tif (!status)\n-\t\tlist_add(&prof->l_entry, &hw->fl_profs[blk]);\n+\t\tlist_add(&(*prof)->l_entry, &hw->fl_profs[blk]);\n \n \tmutex_unlock(&hw->fl_profs_locks[blk]);\n \n@@ -634,6 +667,7 @@ ice_flow_set_rss_seg_info(struct ice_flow_seg_info *segs, u64 hash_fields,\n /**\n  * ice_add_rss_cfg_sync - add an RSS configuration\n  * @hw: pointer to the hardware structure\n+ * @vsi_handle: software VSI handle\n  * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure\n  * @addl_hdrs: protocol header fields\n  * @segs_cnt: packet segment count\n@@ -641,9 +675,11 @@ ice_flow_set_rss_seg_info(struct ice_flow_seg_info *segs, u64 hash_fields,\n  * Assumption: lock has already been acquired for RSS list\n  */\n static enum ice_status\n-ice_add_rss_cfg_sync(struct ice_hw *hw, u64 hashed_flds, u32 addl_hdrs,\n-\t\t     u8 segs_cnt)\n+ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,\n+\t\t     u32 addl_hdrs, u8 segs_cnt)\n {\n+\tconst enum ice_block blk = ICE_BLK_RSS;\n+\tstruct ice_flow_prof *prof = NULL;\n \tstruct ice_flow_seg_info *segs;\n \tenum ice_status status;\n \n@@ -663,11 +699,15 @@ ice_add_rss_cfg_sync(struct ice_hw *hw, u64 hashed_flds, u32 addl_hdrs,\n \t/* Create a new flow profile with generated profile and packet\n \t * segment information.\n \t */\n-\tstatus = ice_flow_add_prof(hw, ICE_BLK_RSS, ICE_FLOW_RX,\n+\tstatus = ice_flow_add_prof(hw, blk, ICE_FLOW_RX,\n \t\t\t\t   ICE_FLOW_GEN_PROFID(hashed_flds,\n \t\t\t\t\t\t       segs[segs_cnt - 1].hdrs,\n \t\t\t\t\t\t       segs_cnt),\n-\t\t\t\t   segs, segs_cnt);\n+\t\t\t\t   segs, segs_cnt, &prof);\n+\tif (status)\n+\t\tgoto exit;\n+\n+\tstatus = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);\n \n exit:\n \tkfree(segs);\n@@ -696,7 +736,7 @@ ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,\n \t\treturn ICE_ERR_PARAM;\n \n \tmutex_lock(&hw->rss_locks);\n-\tstatus = ice_add_rss_cfg_sync(hw, hashed_flds, addl_hdrs,\n+\tstatus = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs,\n \t\t\t\t      ICE_RSS_OUTER_HEADERS);\n \tmutex_unlock(&hw->rss_locks);\n \n@@ -719,7 +759,8 @@ enum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle)\n \tmutex_lock(&hw->rss_locks);\n \tlist_for_each_entry(r, &hw->rss_list_head, l_entry) {\n \t\tif (test_bit(vsi_handle, r->vsis)) {\n-\t\t\tstatus = ice_add_rss_cfg_sync(hw, r->hashed_flds,\n+\t\t\tstatus = ice_add_rss_cfg_sync(hw, vsi_handle,\n+\t\t\t\t\t\t      r->hashed_flds,\n \t\t\t\t\t\t      r->packet_hdr,\n \t\t\t\t\t\t      ICE_RSS_OUTER_HEADERS);\n \t\t\tif (status)\ndiff --git a/drivers/net/ethernet/intel/ice/ice_status.h b/drivers/net/ethernet/intel/ice/ice_status.h\nindex c01597885629..a9a8bc3aca42 100644\n--- a/drivers/net/ethernet/intel/ice/ice_status.h\n+++ b/drivers/net/ethernet/intel/ice/ice_status.h\n@@ -26,6 +26,7 @@ enum ice_status {\n \tICE_ERR_IN_USE\t\t\t\t= -16,\n \tICE_ERR_MAX_LIMIT\t\t\t= -17,\n \tICE_ERR_RESET_ONGOING\t\t\t= -18,\n+\tICE_ERR_HW_TABLE\t\t\t= -19,\n \tICE_ERR_NVM_CHECKSUM\t\t\t= -51,\n \tICE_ERR_BUF_TOO_SHORT\t\t\t= -52,\n \tICE_ERR_NVM_BLANK_MODE\t\t\t= -53,\n",
    "prefixes": [
        "S36",
        "3/8"
    ]
}