get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 886532,
    "url": "http://patchwork.ozlabs.org/api/patches/886532/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20180315234802.31336-12-anirudh.venkataramanan@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": "<20180315234802.31336-12-anirudh.venkataramanan@intel.com>",
    "list_archive_url": null,
    "date": "2018-03-15T23:47:58",
    "name": "[v2,11/15] ice: Add support for VLANs and offloads",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "5c19f98f6d1998c1fe2ce3d2424f8319bc583456",
    "submitter": {
        "id": 73601,
        "url": "http://patchwork.ozlabs.org/api/people/73601/?format=api",
        "name": "Anirudh Venkataramanan",
        "email": "anirudh.venkataramanan@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/20180315234802.31336-12-anirudh.venkataramanan@intel.com/mbox/",
    "series": [
        {
            "id": 34096,
            "url": "http://patchwork.ozlabs.org/api/series/34096/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=34096",
            "date": "2018-03-15T23:47:47",
            "name": "Add ice driver",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/34096/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/886532/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/886532/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;\n\tspf=pass (mailfrom) smtp.mailfrom=osuosl.org\n\t(client-ip=140.211.166.136; helo=silver.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org;\n\tdmarc=none (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 AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 402QJn0VCdz9sVp\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 16 Mar 2018 10:48:24 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id 48EED22118;\n\tThu, 15 Mar 2018 23:48:23 +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 703JvH1ImhkQ; Thu, 15 Mar 2018 23:48:14 +0000 (UTC)",
            "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby silver.osuosl.org (Postfix) with ESMTP id 8618A22649;\n\tThu, 15 Mar 2018 23:48:14 +0000 (UTC)",
            "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\tby ash.osuosl.org (Postfix) with ESMTP id 54A101C0359\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 15 Mar 2018 23:48:12 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 4ED908A26E\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 15 Mar 2018 23:48:12 +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 JtdDB3Q-Gwzp for <intel-wired-lan@lists.osuosl.org>;\n\tThu, 15 Mar 2018 23:48:07 +0000 (UTC)",
            "from mga05.intel.com (mga05.intel.com [192.55.52.43])\n\tby hemlock.osuosl.org (Postfix) with ESMTPS id 07D298A267\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 15 Mar 2018 23:48:06 +0000 (UTC)",
            "from fmsmga004.fm.intel.com ([10.253.24.48])\n\tby fmsmga105.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t15 Mar 2018 16:48:05 -0700",
            "from shasta.jf.intel.com ([10.166.241.32])\n\tby fmsmga004.fm.intel.com with ESMTP; 15 Mar 2018 16:48:05 -0700"
        ],
        "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.48,313,1517904000\"; d=\"scan'208\";a=\"37836796\"",
        "From": "Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>",
        "To": "intel-wired-lan@lists.osuosl.org",
        "Date": "Thu, 15 Mar 2018 16:47:58 -0700",
        "Message-Id": "<20180315234802.31336-12-anirudh.venkataramanan@intel.com>",
        "X-Mailer": "git-send-email 2.14.3",
        "In-Reply-To": "<20180315234802.31336-1-anirudh.venkataramanan@intel.com>",
        "References": "<20180315234802.31336-1-anirudh.venkataramanan@intel.com>",
        "Subject": "[Intel-wired-lan] [PATCH v2 11/15] ice: Add support for VLANs and\n\toffloads",
        "X-BeenThere": "intel-wired-lan@osuosl.org",
        "X-Mailman-Version": "2.1.24",
        "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>",
        "Cc": "netdev@vger.kernel.org",
        "MIME-Version": "1.0",
        "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": "This patch adds support for VLANs. When a VLAN is created a switch filter\nis added to direct the VLAN traffic to the corresponding VSI. When a VLAN\nis deleted, the filter is deleted as well.\n\nThis patch also adds support for the following hardware offloads.\n    1) VLAN tag insertion/stripping\n    2) Receive Side Scaling (RSS)\n    3) Tx checksum and TCP segmentation\n    4) Rx checksum\n\nSigned-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>\n---\n drivers/net/ethernet/intel/ice/ice.h            |  19 +\n drivers/net/ethernet/intel/ice/ice_adminq_cmd.h |  62 +++\n drivers/net/ethernet/intel/ice/ice_common.c     | 188 ++++++++\n drivers/net/ethernet/intel/ice/ice_common.h     |  13 +\n drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h  | 169 +++++++\n drivers/net/ethernet/intel/ice/ice_main.c       | 601 +++++++++++++++++++++++-\n drivers/net/ethernet/intel/ice/ice_switch.c     | 169 +++++++\n drivers/net/ethernet/intel/ice/ice_switch.h     |   4 +\n drivers/net/ethernet/intel/ice/ice_txrx.c       | 405 +++++++++++++++-\n drivers/net/ethernet/intel/ice/ice_txrx.h       |  17 +\n 10 files changed, 1631 insertions(+), 16 deletions(-)",
    "diff": "diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h\nindex 7998e57994bf..f10ae53cc4ac 100644\n--- a/drivers/net/ethernet/intel/ice/ice.h\n+++ b/drivers/net/ethernet/intel/ice/ice.h\n@@ -37,7 +37,10 @@\n #include <linux/delay.h>\n #include <linux/bitmap.h>\n #include <linux/log2.h>\n+#include <linux/ip.h>\n+#include <linux/ipv6.h>\n #include <linux/if_bridge.h>\n+#include <net/ipv6.h>\n #include \"ice_devids.h\"\n #include \"ice_type.h\"\n #include \"ice_txrx.h\"\n@@ -61,6 +64,8 @@\n #define ICE_MAX_SCATTER_RXQS\t16\n #define ICE_Q_WAIT_RETRY_LIMIT\t10\n #define ICE_Q_WAIT_MAX_RETRY\t(5 * ICE_Q_WAIT_RETRY_LIMIT)\n+#define ICE_MAX_LG_RSS_QS\t256\n+#define ICE_MAX_SMALL_RSS_QS\t8\n #define ICE_RES_VALID_BIT\t0x8000\n #define ICE_RES_MISC_VEC_ID\t(ICE_RES_VALID_BIT - 1)\n #define ICE_INVAL_Q_INDEX\t0xffff\n@@ -76,6 +81,7 @@\n \n #define ICE_TX_DESC(R, i) (&(((struct ice_tx_desc *)((R)->desc))[i]))\n #define ICE_RX_DESC(R, i) (&(((union ice_32b_rx_flex_desc *)((R)->desc))[i]))\n+#define ICE_TX_CTX_DESC(R, i) (&(((struct ice_tx_ctx_desc *)((R)->desc))[i]))\n \n #define ice_for_each_txq(vsi, i) \\\n \tfor ((i) = 0; (i) < (vsi)->num_txq; (i)++)\n@@ -127,6 +133,7 @@ struct ice_vsi {\n \tirqreturn_t (*irq_handler)(int irq, void *data);\n \n \tDECLARE_BITMAP(state, __ICE_STATE_NBITS);\n+\tunsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];\n \tint num_q_vectors;\n \tint base_vector;\n \tenum ice_vsi_type type;\n@@ -136,6 +143,13 @@ struct ice_vsi {\n \t/* Interrupt thresholds */\n \tu16 work_lmt;\n \n+\t/* RSS config */\n+\tu16 rss_table_size;\t/* HW RSS table size */\n+\tu16 rss_size;\t\t/* Allocated RSS queues */\n+\tu8 *rss_hkey_user;\t/* User configured hash keys */\n+\tu8 *rss_lut_user;\t/* User configured lookup table entries */\n+\tu8 rss_lut_type;\t/* used to configure Get/Set RSS LUT AQ call */\n+\n \tu16 max_frame;\n \tu16 rx_buf_len;\n \n@@ -195,6 +209,7 @@ struct ice_pf {\n \tstruct mutex avail_q_mutex;\t/* protects access to avail_[rx|tx]qs */\n \tstruct mutex sw_mutex;\t\t/* lock for protecting VSI alloc flow */\n \tu32 msg_enable;\n+\tu32 hw_csum_rx_error;\n \tu32 oicr_idx;\t\t/* Other interrupt cause vector index */\n \tu32 num_lan_msix;\t/* Total MSIX vectors for base driver */\n \tu32 num_avail_msix;\t/* remaining MSIX vectors left unclaimed */\n@@ -238,4 +253,8 @@ static inline void ice_irq_dynamic_ena(struct ice_hw *hw, struct ice_vsi *vsi,\n \twr32(hw, GLINT_DYN_CTL(vector), val);\n }\n \n+int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);\n+int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);\n+void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size);\n+\n #endif /* _ICE_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\nindex 358a482630db..49102817f0a9 100644\n--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n@@ -982,6 +982,60 @@ struct ice_aqc_nvm {\n \t__le32\taddr_low;\n };\n \n+/* Get/Set RSS key (indirect 0x0B04/0x0B02) */\n+struct ice_aqc_get_set_rss_key {\n+#define ICE_AQC_GSET_RSS_KEY_VSI_VALID\tBIT(15)\n+#define ICE_AQC_GSET_RSS_KEY_VSI_ID_S\t0\n+#define ICE_AQC_GSET_RSS_KEY_VSI_ID_M\t(0x3FF << ICE_AQC_GSET_RSS_KEY_VSI_ID_S)\n+\t__le16 vsi_id;\n+\tu8 reserved[6];\n+\t__le32 addr_high;\n+\t__le32 addr_low;\n+};\n+\n+#define ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE\t0x28\n+#define ICE_AQC_GET_SET_RSS_KEY_DATA_HASH_KEY_SIZE\t0xC\n+\n+struct ice_aqc_get_set_rss_keys {\n+\tu8 standard_rss_key[ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE];\n+\tu8 extended_hash_key[ICE_AQC_GET_SET_RSS_KEY_DATA_HASH_KEY_SIZE];\n+};\n+\n+/* Get/Set RSS LUT (indirect 0x0B05/0x0B03) */\n+struct  ice_aqc_get_set_rss_lut {\n+#define ICE_AQC_GSET_RSS_LUT_VSI_VALID\tBIT(15)\n+#define ICE_AQC_GSET_RSS_LUT_VSI_ID_S\t0\n+#define ICE_AQC_GSET_RSS_LUT_VSI_ID_M\t(0x1FF << ICE_AQC_GSET_RSS_LUT_VSI_ID_S)\n+\t__le16 vsi_id;\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_S\t0\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_M\t\\\n+\t\t\t\t(0x3 << ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_S)\n+\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI\t 0\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF\t 1\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_GLOBAL\t 2\n+\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S\t 2\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M\t \\\n+\t\t\t\t(0x3 << ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S)\n+\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128\t 128\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128_FLAG 0\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512\t 512\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512_FLAG 1\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K\t 2048\n+#define ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K_FLAG\t 2\n+\n+#define ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_S\t 4\n+#define ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_M\t \\\n+\t\t\t\t(0xF << ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_S)\n+\n+\t__le16 flags;\n+\t__le32 reserved;\n+\t__le32 addr_high;\n+\t__le32 addr_low;\n+};\n+\n /* Add TX LAN Queues (indirect 0x0C30) */\n struct ice_aqc_add_txqs {\n \tu8 num_qgrps;\n@@ -1103,6 +1157,8 @@ struct ice_aq_desc {\n \t\tstruct ice_aqc_query_txsched_res query_sched_res;\n \t\tstruct ice_aqc_add_move_delete_elem add_move_delete_elem;\n \t\tstruct ice_aqc_nvm nvm;\n+\t\tstruct ice_aqc_get_set_rss_lut get_set_rss_lut;\n+\t\tstruct ice_aqc_get_set_rss_key get_set_rss_key;\n \t\tstruct ice_aqc_add_txqs add_txqs;\n \t\tstruct ice_aqc_dis_txqs dis_txqs;\n \t\tstruct ice_aqc_add_get_update_free_vsi vsi_cmd;\n@@ -1185,6 +1241,12 @@ enum ice_adminq_opc {\n \t/* NVM commands */\n \tice_aqc_opc_nvm_read\t\t\t\t= 0x0701,\n \n+\t/* RSS commands */\n+\tice_aqc_opc_set_rss_key\t\t\t\t= 0x0B02,\n+\tice_aqc_opc_set_rss_lut\t\t\t\t= 0x0B03,\n+\tice_aqc_opc_get_rss_key\t\t\t\t= 0x0B04,\n+\tice_aqc_opc_get_rss_lut\t\t\t\t= 0x0B05,\n+\n \t/* TX queue handling commands/events */\n \tice_aqc_opc_add_txqs\t\t\t\t= 0x0C30,\n \tice_aqc_opc_dis_txqs\t\t\t\t= 0x0C31,\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c\nindex 640edf485d50..ed329c4b4c52 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.c\n+++ b/drivers/net/ethernet/intel/ice/ice_common.c\n@@ -1275,6 +1275,194 @@ void ice_clear_pxe_mode(struct ice_hw *hw)\n \t\tice_aq_clear_pxe_mode(hw);\n }\n \n+/**\n+ * __ice_aq_get_set_rss_lut\n+ * @hw: pointer to the hardware structure\n+ * @vsi_id: VSI FW index\n+ * @lut_type: LUT table type\n+ * @lut: pointer to the LUT buffer provided by the caller\n+ * @lut_size: size of the LUT buffer\n+ * @glob_lut_idx: global LUT index\n+ * @set: set true to set the table, false to get the table\n+ *\n+ * Internal function to get (0x0B05) or set (0x0B03) RSS look up table\n+ */\n+static enum ice_status\n+__ice_aq_get_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,\n+\t\t\t u16 lut_size, u8 glob_lut_idx, bool set)\n+{\n+\tstruct ice_aqc_get_set_rss_lut *cmd_resp;\n+\tstruct ice_aq_desc desc;\n+\tenum ice_status status;\n+\tu16 flags = 0;\n+\n+\tcmd_resp = &desc.params.get_set_rss_lut;\n+\n+\tif (set) {\n+\t\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_rss_lut);\n+\t\tdesc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);\n+\t} else {\n+\t\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_rss_lut);\n+\t}\n+\n+\tcmd_resp->vsi_id = cpu_to_le16(((vsi_id <<\n+\t\t\t\t\t ICE_AQC_GSET_RSS_LUT_VSI_ID_S) &\n+\t\t\t\t\tICE_AQC_GSET_RSS_LUT_VSI_ID_M) |\n+\t\t\t\t       ICE_AQC_GSET_RSS_LUT_VSI_VALID);\n+\n+\tswitch (lut_type) {\n+\tcase ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_VSI:\n+\tcase ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF:\n+\tcase ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_GLOBAL:\n+\t\tflags |= ((lut_type << ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_S) &\n+\t\t\t  ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_M);\n+\t\tbreak;\n+\tdefault:\n+\t\tstatus = ICE_ERR_PARAM;\n+\t\tgoto ice_aq_get_set_rss_lut_exit;\n+\t}\n+\n+\tif (lut_type == ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_GLOBAL) {\n+\t\tflags |= ((glob_lut_idx << ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_S) &\n+\t\t\t  ICE_AQC_GSET_RSS_LUT_GLOBAL_IDX_M);\n+\n+\t\tif (!set)\n+\t\t\tgoto ice_aq_get_set_rss_lut_send;\n+\t} else if (lut_type == ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF) {\n+\t\tif (!set)\n+\t\t\tgoto ice_aq_get_set_rss_lut_send;\n+\t} else {\n+\t\tgoto ice_aq_get_set_rss_lut_send;\n+\t}\n+\n+\t/* LUT size is only valid for Global and PF table types */\n+\tif (lut_size == ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128) {\n+\t\tflags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_128_FLAG <<\n+\t\t\t  ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) &\n+\t\t\t ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M;\n+\t} else if (lut_size == ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512) {\n+\t\tflags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_512_FLAG <<\n+\t\t\t  ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) &\n+\t\t\t ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M;\n+\t} else if ((lut_size == ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K) &&\n+\t\t   (lut_type == ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF)) {\n+\t\tflags |= (ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_2K_FLAG <<\n+\t\t\t  ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_S) &\n+\t\t\t ICE_AQC_GSET_RSS_LUT_TABLE_SIZE_M;\n+\t} else {\n+\t\tstatus = ICE_ERR_PARAM;\n+\t\tgoto ice_aq_get_set_rss_lut_exit;\n+\t}\n+\n+ice_aq_get_set_rss_lut_send:\n+\tcmd_resp->flags = cpu_to_le16(flags);\n+\tstatus = ice_aq_send_cmd(hw, &desc, lut, lut_size, NULL);\n+\n+ice_aq_get_set_rss_lut_exit:\n+\treturn status;\n+}\n+\n+/**\n+ * ice_aq_get_rss_lut\n+ * @hw: pointer to the hardware structure\n+ * @vsi_id: VSI FW index\n+ * @lut_type: LUT table type\n+ * @lut: pointer to the LUT buffer provided by the caller\n+ * @lut_size: size of the LUT buffer\n+ *\n+ * get the RSS lookup table, PF or VSI type\n+ */\n+enum ice_status\n+ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,\n+\t\t   u16 lut_size)\n+{\n+\treturn __ice_aq_get_set_rss_lut(hw, vsi_id, lut_type, lut, lut_size, 0,\n+\t\t\t\t\tfalse);\n+}\n+\n+/**\n+ * ice_aq_set_rss_lut\n+ * @hw: pointer to the hardware structure\n+ * @vsi_id: VSI FW index\n+ * @lut_type: LUT table type\n+ * @lut: pointer to the LUT buffer provided by the caller\n+ * @lut_size: size of the LUT buffer\n+ *\n+ * set the RSS lookup table, PF or VSI type\n+ */\n+enum ice_status\n+ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,\n+\t\t   u16 lut_size)\n+{\n+\treturn __ice_aq_get_set_rss_lut(hw, vsi_id, lut_type, lut, lut_size, 0,\n+\t\t\t\t\ttrue);\n+}\n+\n+/**\n+ * __ice_aq_get_set_rss_key\n+ * @hw: pointer to the hw struct\n+ * @vsi_id: VSI FW index\n+ * @key: pointer to key info struct\n+ * @set: set true to set the key, false to get the key\n+ *\n+ * get (0x0B04) or set (0x0B02) the RSS key per VSI\n+ */\n+static enum\n+ice_status __ice_aq_get_set_rss_key(struct ice_hw *hw, u16 vsi_id,\n+\t\t\t\t    struct ice_aqc_get_set_rss_keys *key,\n+\t\t\t\t    bool set)\n+{\n+\tstruct ice_aqc_get_set_rss_key *cmd_resp;\n+\tu16 key_size = sizeof(*key);\n+\tstruct ice_aq_desc desc;\n+\n+\tcmd_resp = &desc.params.get_set_rss_key;\n+\n+\tif (set) {\n+\t\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_rss_key);\n+\t\tdesc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);\n+\t} else {\n+\t\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_rss_key);\n+\t}\n+\n+\tcmd_resp->vsi_id = cpu_to_le16(((vsi_id <<\n+\t\t\t\t\t ICE_AQC_GSET_RSS_KEY_VSI_ID_S) &\n+\t\t\t\t\tICE_AQC_GSET_RSS_KEY_VSI_ID_M) |\n+\t\t\t\t       ICE_AQC_GSET_RSS_KEY_VSI_VALID);\n+\n+\treturn ice_aq_send_cmd(hw, &desc, key, key_size, NULL);\n+}\n+\n+/**\n+ * ice_aq_get_rss_key\n+ * @hw: pointer to the hw struct\n+ * @vsi_id: VSI FW index\n+ * @key: pointer to key info struct\n+ *\n+ * get the RSS key per VSI\n+ */\n+enum ice_status\n+ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_id,\n+\t\t   struct ice_aqc_get_set_rss_keys *key)\n+{\n+\treturn __ice_aq_get_set_rss_key(hw, vsi_id, key, false);\n+}\n+\n+/**\n+ * ice_aq_set_rss_key\n+ * @hw: pointer to the hw struct\n+ * @vsi_id: VSI FW index\n+ * @keys: pointer to key info struct\n+ *\n+ * set the RSS key per VSI\n+ */\n+enum ice_status\n+ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_id,\n+\t\t   struct ice_aqc_get_set_rss_keys *keys)\n+{\n+\treturn __ice_aq_get_set_rss_key(hw, vsi_id, keys, true);\n+}\n+\n /**\n  * ice_aq_add_lan_txq\n  * @hw: pointer to the hardware structure\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h\nindex 199199afaa28..5de509394e21 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.h\n+++ b/drivers/net/ethernet/intel/ice/ice_common.h\n@@ -47,6 +47,19 @@ enum ice_status ice_get_caps(struct ice_hw *hw);\n enum ice_status\n ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,\n \t\t  u32 rxq_index);\n+\n+enum ice_status\n+ice_aq_get_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,\n+\t\t   u16 lut_size);\n+enum ice_status\n+ice_aq_set_rss_lut(struct ice_hw *hw, u16 vsi_id, u8 lut_type, u8 *lut,\n+\t\t   u16 lut_size);\n+enum ice_status\n+ice_aq_get_rss_key(struct ice_hw *hw, u16 vsi_id,\n+\t\t   struct ice_aqc_get_set_rss_keys *keys);\n+enum ice_status\n+ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_id,\n+\t\t   struct ice_aqc_get_set_rss_keys *keys);\n bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq);\n enum ice_status ice_aq_q_shutdown(struct ice_hw *hw, bool unloading);\n void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h\nindex c930f3e06ecc..b1f38624da21 100644\n--- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h\n+++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h\n@@ -54,6 +54,65 @@ union ice_32byte_rx_desc {\n \t} wb; /* writeback */\n };\n \n+struct ice_rx_ptype_decoded {\n+\tu32 ptype:10;\n+\tu32 known:1;\n+\tu32 outer_ip:1;\n+\tu32 outer_ip_ver:2;\n+\tu32 outer_frag:1;\n+\tu32 tunnel_type:3;\n+\tu32 tunnel_end_prot:2;\n+\tu32 tunnel_end_frag:1;\n+\tu32 inner_prot:4;\n+\tu32 payload_layer:3;\n+};\n+\n+enum ice_rx_ptype_outer_ip {\n+\tICE_RX_PTYPE_OUTER_L2\t= 0,\n+\tICE_RX_PTYPE_OUTER_IP\t= 1,\n+};\n+\n+enum ice_rx_ptype_outer_ip_ver {\n+\tICE_RX_PTYPE_OUTER_NONE\t= 0,\n+\tICE_RX_PTYPE_OUTER_IPV4\t= 1,\n+\tICE_RX_PTYPE_OUTER_IPV6\t= 2,\n+};\n+\n+enum ice_rx_ptype_outer_fragmented {\n+\tICE_RX_PTYPE_NOT_FRAG\t= 0,\n+\tICE_RX_PTYPE_FRAG\t= 1,\n+};\n+\n+enum ice_rx_ptype_tunnel_type {\n+\tICE_RX_PTYPE_TUNNEL_NONE\t\t= 0,\n+\tICE_RX_PTYPE_TUNNEL_IP_IP\t\t= 1,\n+\tICE_RX_PTYPE_TUNNEL_IP_GRENAT\t\t= 2,\n+\tICE_RX_PTYPE_TUNNEL_IP_GRENAT_MAC\t= 3,\n+\tICE_RX_PTYPE_TUNNEL_IP_GRENAT_MAC_VLAN\t= 4,\n+};\n+\n+enum ice_rx_ptype_tunnel_end_prot {\n+\tICE_RX_PTYPE_TUNNEL_END_NONE\t= 0,\n+\tICE_RX_PTYPE_TUNNEL_END_IPV4\t= 1,\n+\tICE_RX_PTYPE_TUNNEL_END_IPV6\t= 2,\n+};\n+\n+enum ice_rx_ptype_inner_prot {\n+\tICE_RX_PTYPE_INNER_PROT_NONE\t\t= 0,\n+\tICE_RX_PTYPE_INNER_PROT_UDP\t\t= 1,\n+\tICE_RX_PTYPE_INNER_PROT_TCP\t\t= 2,\n+\tICE_RX_PTYPE_INNER_PROT_SCTP\t\t= 3,\n+\tICE_RX_PTYPE_INNER_PROT_ICMP\t\t= 4,\n+\tICE_RX_PTYPE_INNER_PROT_TIMESYNC\t= 5,\n+};\n+\n+enum ice_rx_ptype_payload_layer {\n+\tICE_RX_PTYPE_PAYLOAD_LAYER_NONE\t= 0,\n+\tICE_RX_PTYPE_PAYLOAD_LAYER_PAY2\t= 1,\n+\tICE_RX_PTYPE_PAYLOAD_LAYER_PAY3\t= 2,\n+\tICE_RX_PTYPE_PAYLOAD_LAYER_PAY4\t= 3,\n+};\n+\n /* RX Flex Descriptor\n  * This descriptor is used instead of the legacy version descriptor when\n  * ice_rlan_ctx.adv_desc is set\n@@ -102,6 +161,41 @@ union ice_32b_rx_flex_desc {\n \t} wb; /* writeback */\n };\n \n+/* Rx Flex Descriptor NIC Profile\n+ * This descriptor corresponds to RxDID 2 which contains\n+ * metadata fields for RSS, flow id and timestamp info\n+ */\n+struct ice_32b_rx_flex_desc_nic {\n+\t/* Qword 0 */\n+\tu8 rxdid;\n+\tu8 mir_id_umb_cast;\n+\t__le16 ptype_flexi_flags0;\n+\t__le16 pkt_len;\n+\t__le16 hdr_len_sph_flex_flags1;\n+\n+\t/* Qword 1 */\n+\t__le16 status_error0;\n+\t__le16 l2tag1;\n+\t__le32 rss_hash;\n+\n+\t/* Qword 2 */\n+\t__le16 status_error1;\n+\tu8 flexi_flags2;\n+\tu8 ts_low;\n+\t__le16 l2tag2_1st;\n+\t__le16 l2tag2_2nd;\n+\n+\t/* Qword 3 */\n+\t__le32 flow_id;\n+\tunion {\n+\t\tstruct {\n+\t\t\t__le16 vlan_id;\n+\t\t\t__le16 flow_id_ipv6;\n+\t\t} flex;\n+\t\t__le32 ts_high;\n+\t} flex_ts;\n+};\n+\n /* Receive Flex Descriptor profile IDs: There are a total\n  * of 64 profiles where profile IDs 0/1 are for legacy; and\n  * profiles 2-63 are flex profiles that can be programmed\n@@ -255,12 +349,56 @@ enum ice_tx_desc_dtype_value {\n enum ice_tx_desc_cmd_bits {\n \tICE_TX_DESC_CMD_EOP\t\t\t= 0x0001,\n \tICE_TX_DESC_CMD_RS\t\t\t= 0x0002,\n+\tICE_TX_DESC_CMD_IL2TAG1\t\t\t= 0x0008,\n+\tICE_TX_DESC_CMD_IIPT_IPV6\t\t= 0x0020, /* 2 BITS */\n+\tICE_TX_DESC_CMD_IIPT_IPV4\t\t= 0x0040, /* 2 BITS */\n+\tICE_TX_DESC_CMD_IIPT_IPV4_CSUM\t\t= 0x0060, /* 2 BITS */\n+\tICE_TX_DESC_CMD_L4T_EOFT_TCP\t\t= 0x0100, /* 2 BITS */\n+\tICE_TX_DESC_CMD_L4T_EOFT_UDP\t\t= 0x0300, /* 2 BITS */\n };\n \n #define ICE_TXD_QW1_OFFSET_S\t16\n+#define ICE_TXD_QW1_OFFSET_M\t(0x3FFFFULL << ICE_TXD_QW1_OFFSET_S)\n+\n+enum ice_tx_desc_len_fields {\n+\t/* Note: These are predefined bit offsets */\n+\tICE_TX_DESC_LEN_MACLEN_S\t= 0, /* 7 BITS */\n+\tICE_TX_DESC_LEN_IPLEN_S\t= 7, /* 7 BITS */\n+\tICE_TX_DESC_LEN_L4_LEN_S\t= 14 /* 4 BITS */\n+};\n+\n #define ICE_TXD_QW1_TX_BUF_SZ_S\t34\n #define ICE_TXD_QW1_L2TAG1_S\t48\n \n+/* Context descriptors */\n+struct ice_tx_ctx_desc {\n+\t__le32 tunneling_params;\n+\t__le16 l2tag2;\n+\t__le16 rsvd;\n+\t__le64 qw1;\n+};\n+\n+#define ICE_TXD_CTX_QW1_CMD_S\t4\n+#define ICE_TXD_CTX_QW1_CMD_M\t(0x7FUL << ICE_TXD_CTX_QW1_CMD_S)\n+\n+#define ICE_TXD_CTX_QW1_TSO_LEN_S\t30\n+#define ICE_TXD_CTX_QW1_TSO_LEN_M\t\\\n+\t\t\t(0x3FFFFULL << ICE_TXD_CTX_QW1_TSO_LEN_S)\n+\n+#define ICE_TXD_CTX_QW1_MSS_S\t50\n+\n+enum ice_tx_ctx_desc_cmd_bits {\n+\tICE_TX_CTX_DESC_TSO\t\t= 0x01,\n+\tICE_TX_CTX_DESC_TSYN\t\t= 0x02,\n+\tICE_TX_CTX_DESC_IL2TAG2\t\t= 0x04,\n+\tICE_TX_CTX_DESC_IL2TAG2_IL2H\t= 0x08,\n+\tICE_TX_CTX_DESC_SWTCH_NOTAG\t= 0x00,\n+\tICE_TX_CTX_DESC_SWTCH_UPLINK\t= 0x10,\n+\tICE_TX_CTX_DESC_SWTCH_LOCAL\t= 0x20,\n+\tICE_TX_CTX_DESC_SWTCH_VSI\t= 0x30,\n+\tICE_TX_CTX_DESC_RESERVED\t= 0x40\n+};\n+\n #define ICE_LAN_TXQ_MAX_QGRPS\t127\n #define ICE_LAN_TXQ_MAX_QDIS\t1023\n \n@@ -303,4 +441,35 @@ struct ice_tlan_ctx {\n \tu8  pkt_shaper_prof_idx;\n \tu8  int_q_state;\t/* width not needed - internal do not write */\n };\n+\n+/* macro to make the table lines short */\n+#define ICE_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\\\n+\t{\tPTYPE, \\\n+\t\t1, \\\n+\t\tICE_RX_PTYPE_OUTER_##OUTER_IP, \\\n+\t\tICE_RX_PTYPE_OUTER_##OUTER_IP_VER, \\\n+\t\tICE_RX_PTYPE_##OUTER_FRAG, \\\n+\t\tICE_RX_PTYPE_TUNNEL_##T, \\\n+\t\tICE_RX_PTYPE_TUNNEL_END_##TE, \\\n+\t\tICE_RX_PTYPE_##TEF, \\\n+\t\tICE_RX_PTYPE_INNER_PROT_##I, \\\n+\t\tICE_RX_PTYPE_PAYLOAD_LAYER_##PL }\n+\n+#define ICE_PTT_UNUSED_ENTRY(PTYPE) { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }\n+\n+/* shorter macros makes the table fit but are terse */\n+#define ICE_RX_PTYPE_NOF\t\tICE_RX_PTYPE_NOT_FRAG\n+\n+/* Lookup table mapping the HW PTYPE to the bit field for decoding */\n+static const struct ice_rx_ptype_decoded ice_ptype_lkup[] = {\n+\t/* L2 Packet types */\n+\tICE_PTT_UNUSED_ENTRY(0),\n+\tICE_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),\n+\tICE_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),\n+};\n+\n+static inline struct ice_rx_ptype_decoded ice_decode_rx_desc_ptype(u16 ptype)\n+{\n+\treturn ice_ptype_lkup[ptype];\n+}\n #endif /* _ICE_LAN_TX_RX_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c\nindex b802cac8376c..f966d783ec63 100644\n--- a/drivers/net/ethernet/intel/ice/ice_main.c\n+++ b/drivers/net/ethernet/intel/ice/ice_main.c\n@@ -677,6 +677,35 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename)\n \treturn err;\n }\n \n+/**\n+ * ice_vsi_set_rss_params - Setup RSS capabilities per VSI type\n+ * @vsi: the VSI being configured\n+ */\n+static void ice_vsi_set_rss_params(struct ice_vsi *vsi)\n+{\n+\tstruct ice_hw_common_caps *cap;\n+\tstruct ice_pf *pf = vsi->back;\n+\n+\tif (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {\n+\t\tvsi->rss_size = 1;\n+\t\treturn;\n+\t}\n+\n+\tcap = &pf->hw.func_caps.common_cap;\n+\tswitch (vsi->type) {\n+\tcase ICE_VSI_PF:\n+\t\t/* PF VSI will inherit RSS instance of PF */\n+\t\tvsi->rss_table_size = cap->rss_table_size;\n+\t\tvsi->rss_size = min_t(int, num_online_cpus(),\n+\t\t\t\t      BIT(cap->rss_table_entry_width));\n+\t\tvsi->rss_lut_type = ICE_AQC_GSET_RSS_LUT_TABLE_TYPE_PF;\n+\t\tbreak;\n+\tdefault:\n+\t\tdev_warn(&pf->pdev->dev, \"Unknown VSI type %d\\n\", vsi->type);\n+\t\tbreak;\n+\t}\n+}\n+\n /**\n  * ice_vsi_setup_q_map - Setup a VSI queue map\n  * @vsi: the VSI being configured\n@@ -684,7 +713,8 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename)\n  */\n static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)\n {\n-\tu16 offset = 0, qmap = 0, pow = 0, qcount;\n+\tu16 offset = 0, qmap = 0, numq_tc;\n+\tu16 pow = 0, max_rss = 0, qcount;\n \tu16 qcount_tx = vsi->alloc_txq;\n \tu16 qcount_rx = vsi->alloc_rxq;\n \tbool ena_tc0 = false;\n@@ -703,13 +733,7 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)\n \t\tvsi->tc_cfg.ena_tc |= 1;\n \t}\n \n-\tqcount = qcount_rx / vsi->tc_cfg.numtc;\n-\n-\t/* find higher power-of-2 of qcount */\n-\tpow = ilog2(qcount);\n-\n-\tif (!is_power_of_2(qcount))\n-\t\tpow++;\n+\tnumq_tc = qcount_rx / vsi->tc_cfg.numtc;\n \n \t/* TC mapping is a function of the number of Rx queues assigned to the\n \t * VSI for each traffic class and the offset of these queues.\n@@ -722,6 +746,26 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)\n \t *\n \t * Setup number and offset of Rx queues for all TCs for the VSI\n \t */\n+\n+\t/* qcount will change if RSS is enabled */\n+\tif (test_bit(ICE_FLAG_RSS_ENA, vsi->back->flags)) {\n+\t\tif (vsi->type == ICE_VSI_PF)\n+\t\t\tmax_rss = ICE_MAX_LG_RSS_QS;\n+\t\telse\n+\t\t\tmax_rss = ICE_MAX_SMALL_RSS_QS;\n+\n+\t\tqcount = min_t(int, numq_tc, max_rss);\n+\t\tqcount = min_t(int, qcount, vsi->rss_size);\n+\t} else {\n+\t\tqcount = numq_tc;\n+\t}\n+\n+\t/* find higher power-of-2 of qcount */\n+\tpow = ilog2(qcount);\n+\n+\tif (!is_power_of_2(qcount))\n+\t\tpow++;\n+\n \tfor (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) {\n \t\tif (!(vsi->tc_cfg.ena_tc & BIT(i))) {\n \t\t\t/* TC is not enabled */\n@@ -797,6 +841,33 @@ static void ice_set_dflt_vsi_ctx(struct ice_vsi_ctx *ctxt)\n \t/* No Outer tag support outer_tag_flags remains to zero */\n }\n \n+/**\n+ * ice_set_rss_vsi_ctx - Set RSS VSI context before adding a VSI\n+ * @ctxt: the VSI context being set\n+ * @vsi: the VSI being configured\n+ */\n+static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)\n+{\n+\tu8 lut_type, hash_type;\n+\n+\tswitch (vsi->type) {\n+\tcase ICE_VSI_PF:\n+\t\t/* PF VSI will inherit RSS instance of PF */\n+\t\tlut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF;\n+\t\thash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ;\n+\t\tbreak;\n+\tdefault:\n+\t\tdev_warn(&vsi->back->pdev->dev, \"Unknown VSI type %d\\n\",\n+\t\t\t vsi->type);\n+\t\treturn;\n+\t}\n+\n+\tctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) &\n+\t\t\t\tICE_AQ_VSI_Q_OPT_RSS_LUT_M) |\n+\t\t\t\t((hash_type << ICE_AQ_VSI_Q_OPT_RSS_HASH_S) &\n+\t\t\t\t ICE_AQ_VSI_Q_OPT_RSS_HASH_M);\n+}\n+\n /**\n  * ice_vsi_add - Create a new VSI or fetch preallocated VSI\n  * @vsi: the VSI being configured\n@@ -824,6 +895,10 @@ static int ice_vsi_add(struct ice_vsi *vsi)\n \tif (vsi->vsw->bridge_mode == BRIDGE_MODE_VEB)\n \t\tctxt.info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB;\n \n+\t/* Set LUT type and HASH type if RSS is enabled */\n+\tif (test_bit(ICE_FLAG_RSS_ENA, pf->flags))\n+\t\tice_set_rss_vsi_ctx(&ctxt, vsi);\n+\n \tctxt.info.sw_id = vsi->port_info->sw_id;\n \tice_vsi_setup_q_map(vsi, &ctxt);\n \n@@ -1643,6 +1718,10 @@ static void ice_vsi_free_q_vectors(struct ice_vsi *vsi)\n  */\n static int ice_cfg_netdev(struct ice_vsi *vsi)\n {\n+\tnetdev_features_t csumo_features;\n+\tnetdev_features_t vlano_features;\n+\tnetdev_features_t dflt_features;\n+\tnetdev_features_t tso_features;\n \tstruct ice_netdev_priv *np;\n \tstruct net_device *netdev;\n \tu8 mac_addr[ETH_ALEN];\n@@ -1656,13 +1735,31 @@ static int ice_cfg_netdev(struct ice_vsi *vsi)\n \tnp = netdev_priv(netdev);\n \tnp->vsi = vsi;\n \n+\tdflt_features = NETIF_F_SG\t|\n+\t\t\tNETIF_F_HIGHDMA\t|\n+\t\t\tNETIF_F_RXHASH;\n+\n+\tcsumo_features = NETIF_F_RXCSUM\t  |\n+\t\t\t NETIF_F_IP_CSUM  |\n+\t\t\t NETIF_F_IPV6_CSUM;\n+\n+\tvlano_features = NETIF_F_HW_VLAN_CTAG_FILTER |\n+\t\t\t NETIF_F_HW_VLAN_CTAG_TX     |\n+\t\t\t NETIF_F_HW_VLAN_CTAG_RX;\n+\n+\ttso_features = NETIF_F_TSO;\n+\n \t/* set features that user can change */\n-\tnetdev->hw_features = NETIF_F_SG\t|\n-\t\t\t      NETIF_F_HIGHDMA\t|\n-\t\t\t      NETIF_F_RXHASH;\n+\tnetdev->hw_features = dflt_features | csumo_features |\n+\t\t\t      vlano_features | tso_features;\n \n \t/* enable features */\n \tnetdev->features |= netdev->hw_features;\n+\t/* encap and VLAN devices inherit default, csumo and tso features */\n+\tnetdev->hw_enc_features |= dflt_features | csumo_features |\n+\t\t\t\t   tso_features;\n+\tnetdev->vlan_features |= dflt_features | csumo_features |\n+\t\t\t\t tso_features;\n \n \tif (vsi->type == ICE_VSI_PF) {\n \t\tSET_NETDEV_DEV(netdev, &vsi->back->pdev->dev);\n@@ -1876,6 +1973,83 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi)\n \treturn 0;\n }\n \n+/**\n+ * ice_fill_rss_lut - Fill the RSS lookup table with default values\n+ * @lut: Lookup table\n+ * @rss_table_size: Lookup table size\n+ * @rss_size: Range of queue number for hashing\n+ */\n+void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size)\n+{\n+\tu16 i;\n+\n+\tfor (i = 0; i < rss_table_size; i++)\n+\t\tlut[i] = i % rss_size;\n+}\n+\n+/**\n+ * ice_vsi_cfg_rss - Configure RSS params for a VSI\n+ * @vsi: VSI to be configured\n+ */\n+static int ice_vsi_cfg_rss(struct ice_vsi *vsi)\n+{\n+\tu8 seed[ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE];\n+\tstruct ice_aqc_get_set_rss_keys *key;\n+\tstruct ice_pf *pf = vsi->back;\n+\tenum ice_status status;\n+\tint err = 0;\n+\tu8 *lut;\n+\n+\tvsi->rss_size = min_t(int, vsi->rss_size, vsi->num_rxq);\n+\n+\tlut = devm_kzalloc(&pf->pdev->dev, vsi->rss_table_size, GFP_KERNEL);\n+\tif (!lut)\n+\t\treturn -ENOMEM;\n+\n+\tif (vsi->rss_lut_user)\n+\t\tmemcpy(lut, vsi->rss_lut_user, vsi->rss_table_size);\n+\telse\n+\t\tice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size);\n+\n+\tstatus = ice_aq_set_rss_lut(&pf->hw, vsi->vsi_num, vsi->rss_lut_type,\n+\t\t\t\t    lut, vsi->rss_table_size);\n+\n+\tif (status) {\n+\t\tdev_err(&vsi->back->pdev->dev,\n+\t\t\t\"set_rss_lut failed, error %d\\n\", status);\n+\t\terr = -EIO;\n+\t\tgoto ice_vsi_cfg_rss_exit;\n+\t}\n+\n+\tkey = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*key), GFP_KERNEL);\n+\tif (!key) {\n+\t\terr = -ENOMEM;\n+\t\tgoto ice_vsi_cfg_rss_exit;\n+\t}\n+\n+\tif (vsi->rss_hkey_user)\n+\t\tmemcpy(seed, vsi->rss_hkey_user,\n+\t\t       ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);\n+\telse\n+\t\tnetdev_rss_key_fill((void *)seed,\n+\t\t\t\t    ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);\n+\tmemcpy(&key->standard_rss_key, seed,\n+\t       ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE);\n+\n+\tstatus = ice_aq_set_rss_key(&pf->hw, vsi->vsi_num, key);\n+\n+\tif (status) {\n+\t\tdev_err(&vsi->back->pdev->dev, \"set_rss_key failed, error %d\\n\",\n+\t\t\tstatus);\n+\t\terr = -EIO;\n+\t}\n+\n+\tdevm_kfree(&pf->pdev->dev, key);\n+ice_vsi_cfg_rss_exit:\n+\tdevm_kfree(&pf->pdev->dev, lut);\n+\treturn err;\n+}\n+\n /**\n  * ice_vsi_setup - Set up a VSI by a given type\n  * @pf: board private structure\n@@ -1911,6 +2085,9 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,\n \t\tgoto err_get_qs;\n \t}\n \n+\t/* set RSS capabilities */\n+\tice_vsi_set_rss_params(vsi);\n+\n \t/* create the VSI */\n \tret = ice_vsi_add(vsi);\n \tif (ret)\n@@ -1946,6 +2123,12 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,\n \n \t\tice_vsi_map_rings_to_vectors(vsi);\n \n+\t\t/* Do not exit if configuring RSS had an issue, at least\n+\t\t * receive traffic on first queue. Hence no need to capture\n+\t\t * return value\n+\t\t */\n+\t\tif (test_bit(ICE_FLAG_RSS_ENA, pf->flags))\n+\t\t\tice_vsi_cfg_rss(vsi);\n \t\tbreak;\n \tdefault:\n \t\t/* if vsi type is not recognized, clean up the resources and\n@@ -1980,6 +2163,140 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,\n \treturn NULL;\n }\n \n+/**\n+ * ice_vsi_add_vlan - Add vsi membership for given vlan\n+ * @vsi: the vsi being configured\n+ * @vid: vlan id to be added\n+ */\n+static int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid)\n+{\n+\tstruct ice_fltr_list_entry *tmp;\n+\tstruct ice_pf *pf = vsi->back;\n+\tLIST_HEAD(tmp_add_list);\n+\tenum ice_status status;\n+\tint err = 0;\n+\n+\ttmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_KERNEL);\n+\tif (!tmp)\n+\t\treturn -ENOMEM;\n+\n+\ttmp->fltr_info.lkup_type = ICE_SW_LKUP_VLAN;\n+\ttmp->fltr_info.fltr_act = ICE_FWD_TO_VSI;\n+\ttmp->fltr_info.flag = ICE_FLTR_TX;\n+\ttmp->fltr_info.src = vsi->vsi_num;\n+\ttmp->fltr_info.fwd_id.vsi_id = vsi->vsi_num;\n+\ttmp->fltr_info.l_data.vlan.vlan_id = vid;\n+\n+\tINIT_LIST_HEAD(&tmp->list_entry);\n+\tlist_add(&tmp->list_entry, &tmp_add_list);\n+\n+\tstatus = ice_add_vlan(&pf->hw, &tmp_add_list);\n+\tif (status) {\n+\t\terr = -ENODEV;\n+\t\tdev_err(&pf->pdev->dev, \"Failure Adding VLAN %d on VSI %i\\n\",\n+\t\t\tvid, vsi->vsi_num);\n+\t}\n+\n+\tice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);\n+\treturn err;\n+}\n+\n+/**\n+ * ice_vlan_rx_add_vid - Add a vlan id filter to HW offload\n+ * @netdev: network interface to be adjusted\n+ * @proto: unused protocol\n+ * @vid: vlan id to be added\n+ *\n+ * net_device_ops implementation for adding vlan ids\n+ */\n+static int ice_vlan_rx_add_vid(struct net_device *netdev,\n+\t\t\t       __always_unused __be16 proto, u16 vid)\n+{\n+\tstruct ice_netdev_priv *np = netdev_priv(netdev);\n+\tstruct ice_vsi *vsi = np->vsi;\n+\tint ret = 0;\n+\n+\tif (vid >= VLAN_N_VID) {\n+\t\tnetdev_err(netdev, \"VLAN id requested %d is out of range %d\\n\",\n+\t\t\t   vid, VLAN_N_VID);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (vsi->info.pvid)\n+\t\treturn -EINVAL;\n+\n+\t/* Add all VLAN ids including 0 to the switch filter. VLAN id 0 is\n+\t * needed to continue allowing all untagged packets since VLAN prune\n+\t * list is applied to all packets by the switch\n+\t */\n+\tret = ice_vsi_add_vlan(vsi, vid);\n+\n+\tif (!ret)\n+\t\tset_bit(vid, vsi->active_vlans);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * ice_vsi_kill_vlan - Remove VSI membership for a given VLAN\n+ * @vsi: the VSI being configured\n+ * @vid: VLAN id to be removed\n+ */\n+static void ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid)\n+{\n+\tstruct ice_fltr_list_entry *list;\n+\tstruct ice_pf *pf = vsi->back;\n+\tLIST_HEAD(tmp_add_list);\n+\n+\tlist = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL);\n+\tif (!list)\n+\t\treturn;\n+\n+\tlist->fltr_info.lkup_type = ICE_SW_LKUP_VLAN;\n+\tlist->fltr_info.fwd_id.vsi_id = vsi->vsi_num;\n+\tlist->fltr_info.fltr_act = ICE_FWD_TO_VSI;\n+\tlist->fltr_info.l_data.vlan.vlan_id = vid;\n+\tlist->fltr_info.flag = ICE_FLTR_TX;\n+\tlist->fltr_info.src = vsi->vsi_num;\n+\n+\tINIT_LIST_HEAD(&list->list_entry);\n+\tlist_add(&list->list_entry, &tmp_add_list);\n+\n+\tif (ice_remove_vlan(&pf->hw, &tmp_add_list))\n+\t\tdev_err(&pf->pdev->dev, \"Error removing VLAN %d on vsi %i\\n\",\n+\t\t\tvid, vsi->vsi_num);\n+\n+\tice_free_fltr_list(&pf->pdev->dev, &tmp_add_list);\n+}\n+\n+/**\n+ * ice_vlan_rx_kill_vid - Remove a vlan id filter from HW offload\n+ * @netdev: network interface to be adjusted\n+ * @proto: unused protocol\n+ * @vid: vlan id to be removed\n+ *\n+ * net_device_ops implementation for removing vlan ids\n+ */\n+static int ice_vlan_rx_kill_vid(struct net_device *netdev,\n+\t\t\t\t__always_unused __be16 proto, u16 vid)\n+{\n+\tstruct ice_netdev_priv *np = netdev_priv(netdev);\n+\tstruct ice_vsi *vsi = np->vsi;\n+\n+\tif (vsi->info.pvid)\n+\t\treturn -EINVAL;\n+\n+\t/* return code is ignored as there is nothing a user\n+\t * can do about failure to remove and a log message was\n+\t * already printed from the other function\n+\t */\n+\tice_vsi_kill_vlan(vsi, vid);\n+\n+\tclear_bit(vid, vsi->active_vlans);\n+\n+\treturn 0;\n+}\n+\n /**\n  * ice_setup_pf_sw - Setup the HW switch on startup or after reset\n  * @pf: board private structure\n@@ -2061,9 +2378,14 @@ static void ice_determine_q_usage(struct ice_pf *pf)\n \tq_left_tx = pf->hw.func_caps.common_cap.num_txq;\n \tq_left_rx = pf->hw.func_caps.common_cap.num_rxq;\n \n-\t/* initial support for only 1 tx and 1 rx queue */\n+\t/* initial support for only 1 tx queue */\n \tpf->num_lan_tx = 1;\n-\tpf->num_lan_rx = 1;\n+\n+\t/* only 1 rx queue unless RSS is enabled */\n+\tif (!test_bit(ICE_FLAG_RSS_ENA, pf->flags))\n+\t\tpf->num_lan_rx = 1;\n+\telse\n+\t\tpf->num_lan_rx = min_t(int, q_left_rx, num_online_cpus());\n \n \tpf->q_left_tx = q_left_tx - pf->num_lan_tx;\n \tpf->q_left_rx = q_left_rx - pf->num_lan_rx;\n@@ -2101,6 +2423,9 @@ static void ice_init_pf(struct ice_pf *pf)\n \tbitmap_zero(pf->avail_rxqs, ICE_MAX_RXQS);\n \tmutex_unlock(&pf->avail_q_mutex);\n \n+\tif (pf->hw.func_caps.common_cap.rss_table_size)\n+\t\tset_bit(ICE_FLAG_RSS_ENA, pf->flags);\n+\n \t/* setup service timer and periodic service task */\n \ttimer_setup(&pf->serv_tmr, ice_service_timer, 0);\n \tpf->serv_tmr_period = HZ;\n@@ -2497,6 +2822,144 @@ static void __exit ice_module_exit(void)\n }\n module_exit(ice_module_exit);\n \n+/**\n+ * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx\n+ * @vsi: the vsi being changed\n+ */\n+static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi)\n+{\n+\tstruct device *dev = &vsi->back->pdev->dev;\n+\tstruct ice_hw *hw = &vsi->back->hw;\n+\tstruct ice_vsi_ctx ctxt = { 0 };\n+\tenum ice_status status;\n+\n+\t/* Here we are configuring the VSI to let the driver add VLAN tags by\n+\t * setting port_vlan_flags to ICE_AQ_VSI_PVLAN_MODE_ALL. The actual VLAN\n+\t * tag insertion happens in the Tx hot path, in ice_tx_map.\n+\t */\n+\tctxt.info.port_vlan_flags = ICE_AQ_VSI_PVLAN_MODE_ALL;\n+\n+\tctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);\n+\tctxt.vsi_num = vsi->vsi_num;\n+\n+\tstatus = ice_aq_update_vsi(hw, &ctxt, NULL);\n+\tif (status) {\n+\t\tdev_err(dev, \"update VSI for VLAN insert failed, err %d aq_err %d\\n\",\n+\t\t\tstatus, hw->adminq.sq_last_status);\n+\t\treturn -EIO;\n+\t}\n+\n+\tvsi->info.port_vlan_flags = ctxt.info.port_vlan_flags;\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx\n+ * @vsi: the vsi being changed\n+ * @ena: boolean value indicating if this is a enable or disable request\n+ */\n+static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena)\n+{\n+\tstruct device *dev = &vsi->back->pdev->dev;\n+\tstruct ice_hw *hw = &vsi->back->hw;\n+\tstruct ice_vsi_ctx ctxt = { 0 };\n+\tenum ice_status status;\n+\n+\t/* Here we are configuring what the VSI should do with the VLAN tag in\n+\t * the Rx packet. We can either leave the tag in the packet or put it in\n+\t * the Rx descriptor.\n+\t */\n+\tif (ena) {\n+\t\t/* Strip VLAN tag from Rx packet and put it in the desc */\n+\t\tctxt.info.port_vlan_flags = ICE_AQ_VSI_PVLAN_EMOD_STR_BOTH;\n+\t} else {\n+\t\t/* Disable stripping. Leave tag in packet */\n+\t\tctxt.info.port_vlan_flags = ICE_AQ_VSI_PVLAN_EMOD_NOTHING;\n+\t}\n+\n+\tctxt.info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);\n+\tctxt.vsi_num = vsi->vsi_num;\n+\n+\tstatus = ice_aq_update_vsi(hw, &ctxt, NULL);\n+\tif (status) {\n+\t\tdev_err(dev, \"update VSI for VALN strip failed, ena = %d err %d aq_err %d\\n\",\n+\t\t\tena, status, hw->adminq.sq_last_status);\n+\t\treturn -EIO;\n+\t}\n+\n+\tvsi->info.port_vlan_flags = ctxt.info.port_vlan_flags;\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_set_features - set the netdev feature flags\n+ * @netdev: ptr to the netdev being adjusted\n+ * @features: the feature set that the stack is suggesting\n+ */\n+static int ice_set_features(struct net_device *netdev,\n+\t\t\t    netdev_features_t features)\n+{\n+\tstruct ice_netdev_priv *np = netdev_priv(netdev);\n+\tstruct ice_vsi *vsi = np->vsi;\n+\tint ret = 0;\n+\n+\tif ((features & NETIF_F_HW_VLAN_CTAG_RX) &&\n+\t    !(netdev->features & NETIF_F_HW_VLAN_CTAG_RX))\n+\t\tret = ice_vsi_manage_vlan_stripping(vsi, true);\n+\telse if (!(features & NETIF_F_HW_VLAN_CTAG_RX) &&\n+\t\t (netdev->features & NETIF_F_HW_VLAN_CTAG_RX))\n+\t\tret = ice_vsi_manage_vlan_stripping(vsi, false);\n+\telse if ((features & NETIF_F_HW_VLAN_CTAG_TX) &&\n+\t\t !(netdev->features & NETIF_F_HW_VLAN_CTAG_TX))\n+\t\tret = ice_vsi_manage_vlan_insertion(vsi);\n+\telse if (!(features & NETIF_F_HW_VLAN_CTAG_TX) &&\n+\t\t (netdev->features & NETIF_F_HW_VLAN_CTAG_TX))\n+\t\tret = ice_vsi_manage_vlan_insertion(vsi);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * ice_vsi_vlan_setup - Setup vlan offload properties on a VSI\n+ * @vsi: VSI to setup vlan properties for\n+ */\n+static int ice_vsi_vlan_setup(struct ice_vsi *vsi)\n+{\n+\tint ret = 0;\n+\n+\tif (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)\n+\t\tret = ice_vsi_manage_vlan_stripping(vsi, true);\n+\tif (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)\n+\t\tret = ice_vsi_manage_vlan_insertion(vsi);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * ice_restore_vlan - Reinstate VLANs when vsi/netdev comes back up\n+ * @vsi: the VSI being brought back up\n+ */\n+static int ice_restore_vlan(struct ice_vsi *vsi)\n+{\n+\tint err;\n+\tu16 vid;\n+\n+\tif (!vsi->netdev)\n+\t\treturn -EINVAL;\n+\n+\terr = ice_vsi_vlan_setup(vsi);\n+\tif (err)\n+\t\treturn err;\n+\n+\tfor_each_set_bit(vid, vsi->active_vlans, VLAN_N_VID) {\n+\t\terr = ice_vlan_rx_add_vid(vsi->netdev, htons(ETH_P_8021Q), vid);\n+\t\tif (err)\n+\t\t\tbreak;\n+\t}\n+\n+\treturn err;\n+}\n+\n /**\n  * ice_setup_tx_ctx - setup a struct ice_tlan_ctx instance\n  * @ring: The Tx ring to configure\n@@ -2749,6 +3212,10 @@ static int ice_vsi_cfg(struct ice_vsi *vsi)\n {\n \tint err;\n \n+\terr = ice_restore_vlan(vsi);\n+\tif (err)\n+\t\treturn err;\n+\n \terr = ice_vsi_cfg_txqs(vsi);\n \tif (!err)\n \t\terr = ice_vsi_cfg_rxqs(vsi);\n@@ -3227,6 +3694,22 @@ static void ice_vsi_close(struct ice_vsi *vsi)\n \tice_vsi_free_rx_rings(vsi);\n }\n \n+/**\n+ * ice_rss_clean - Delete RSS related VSI structures that hold user inputs\n+ * @vsi: the VSI being removed\n+ */\n+static void ice_rss_clean(struct ice_vsi *vsi)\n+{\n+\tstruct ice_pf *pf;\n+\n+\tpf = vsi->back;\n+\n+\tif (vsi->rss_hkey_user)\n+\t\tdevm_kfree(&pf->pdev->dev, vsi->rss_hkey_user);\n+\tif (vsi->rss_lut_user)\n+\t\tdevm_kfree(&pf->pdev->dev, vsi->rss_lut_user);\n+}\n+\n /**\n  * ice_vsi_release - Delete a VSI and free its resources\n  * @vsi: the VSI being removed\n@@ -3247,6 +3730,10 @@ static int ice_vsi_release(struct ice_vsi *vsi)\n \t\tvsi->netdev = NULL;\n \t}\n \n+\tif (test_bit(ICE_FLAG_RSS_ENA, pf->flags))\n+\t\tice_rss_clean(vsi);\n+\n+\t/* Disable VSI and free resources */\n \tice_vsi_dis_irq(vsi);\n \tice_vsi_close(vsi);\n \n@@ -3268,6 +3755,91 @@ static int ice_vsi_release(struct ice_vsi *vsi)\n \treturn 0;\n }\n \n+/**\n+ * ice_set_rss - Set RSS keys and lut\n+ * @vsi: Pointer to VSI structure\n+ * @seed: RSS hash seed\n+ * @lut: Lookup table\n+ * @lut_size: Lookup table size\n+ *\n+ * Returns 0 on success, negative on failure\n+ */\n+int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)\n+{\n+\tstruct ice_pf *pf = vsi->back;\n+\tstruct ice_hw *hw = &pf->hw;\n+\tenum ice_status status;\n+\n+\tif (seed) {\n+\t\tstruct ice_aqc_get_set_rss_keys *buf =\n+\t\t\t\t  (struct ice_aqc_get_set_rss_keys *)seed;\n+\n+\t\tstatus = ice_aq_set_rss_key(hw, vsi->vsi_num, buf);\n+\n+\t\tif (status) {\n+\t\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\t\"Cannot set RSS key, err %d aq_err %d\\n\",\n+\t\t\t\tstatus, hw->adminq.rq_last_status);\n+\t\t\treturn -EIO;\n+\t\t}\n+\t}\n+\n+\tif (lut) {\n+\t\tstatus = ice_aq_set_rss_lut(hw, vsi->vsi_num,\n+\t\t\t\t\t    vsi->rss_lut_type, lut, lut_size);\n+\t\tif (status) {\n+\t\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\t\"Cannot set RSS lut, err %d aq_err %d\\n\",\n+\t\t\t\tstatus, hw->adminq.rq_last_status);\n+\t\t\treturn -EIO;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_get_rss - Get RSS keys and lut\n+ * @vsi: Pointer to VSI structure\n+ * @seed: Buffer to store the keys\n+ * @lut: Buffer to store the lookup table entries\n+ * @lut_size: Size of buffer to store the lookup table entries\n+ *\n+ * Returns 0 on success, negative on failure\n+ */\n+int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)\n+{\n+\tstruct ice_pf *pf = vsi->back;\n+\tstruct ice_hw *hw = &pf->hw;\n+\tenum ice_status status;\n+\n+\tif (seed) {\n+\t\tstruct ice_aqc_get_set_rss_keys *buf =\n+\t\t\t\t  (struct ice_aqc_get_set_rss_keys *)seed;\n+\n+\t\tstatus = ice_aq_get_rss_key(hw, vsi->vsi_num, buf);\n+\t\tif (status) {\n+\t\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\t\"Cannot get RSS key, err %d aq_err %d\\n\",\n+\t\t\t\tstatus, hw->adminq.rq_last_status);\n+\t\t\treturn -EIO;\n+\t\t}\n+\t}\n+\n+\tif (lut) {\n+\t\tstatus = ice_aq_get_rss_lut(hw, vsi->vsi_num,\n+\t\t\t\t\t    vsi->rss_lut_type, lut, lut_size);\n+\t\tif (status) {\n+\t\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\t\"Cannot get RSS lut, err %d aq_err %d\\n\",\n+\t\t\t\tstatus, hw->adminq.rq_last_status);\n+\t\t\treturn -EIO;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n /**\n  * ice_open - Called when a network interface becomes active\n  * @netdev: network interface device structure\n@@ -3320,4 +3892,7 @@ static const struct net_device_ops ice_netdev_ops = {\n \t.ndo_open = ice_open,\n \t.ndo_stop = ice_stop,\n \t.ndo_start_xmit = ice_start_xmit,\n+\t.ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid,\n+\t.ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid,\n+\t.ndo_set_features = ice_set_features,\n };\ndiff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c\nindex dd396db664f0..424090f598c3 100644\n--- a/drivers/net/ethernet/intel/ice/ice_switch.c\n+++ b/drivers/net/ethernet/intel/ice/ice_switch.c\n@@ -1231,6 +1231,117 @@ ice_add_mac(struct ice_hw *hw, struct list_head *m_list)\n \treturn status;\n }\n \n+/**\n+ * ice_find_vlan_entry\n+ * @hw: pointer to the hardware structure\n+ * @vlan_id: VLAN id to search for\n+ *\n+ * Helper function to search for a VLAN entry using a given VLAN id\n+ * Returns pointer to the entry if found.\n+ */\n+static struct ice_fltr_mgmt_list_entry *\n+ice_find_vlan_entry(struct ice_hw *hw, u16 vlan_id)\n+{\n+\tstruct ice_fltr_mgmt_list_entry *vlan_list_itr, *vlan_ret = NULL;\n+\tstruct ice_switch_info *sw = hw->switch_info;\n+\n+\tmutex_lock(&sw->vlan_list_lock);\n+\tlist_for_each_entry(vlan_list_itr, &sw->vlan_list_head, list_entry)\n+\t\tif (vlan_list_itr->fltr_info.l_data.vlan.vlan_id == vlan_id) {\n+\t\t\tvlan_ret = vlan_list_itr;\n+\t\t\tbreak;\n+\t\t}\n+\n+\tmutex_unlock(&sw->vlan_list_lock);\n+\treturn vlan_ret;\n+}\n+\n+/**\n+ * ice_add_vlan_internal - Add one VLAN based filter rule\n+ * @hw: pointer to the hardware structure\n+ * @f_entry: filter entry containing one VLAN information\n+ */\n+static enum ice_status\n+ice_add_vlan_internal(struct ice_hw *hw, struct ice_fltr_list_entry *f_entry)\n+{\n+\tstruct ice_fltr_info *new_fltr, *cur_fltr;\n+\tstruct ice_fltr_mgmt_list_entry *v_list_itr;\n+\tu16 vlan_id;\n+\n+\tnew_fltr = &f_entry->fltr_info;\n+\t/* VLAN id should only be 12 bits */\n+\tif (new_fltr->l_data.vlan.vlan_id > ICE_MAX_VLAN_ID)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tvlan_id = new_fltr->l_data.vlan.vlan_id;\n+\tv_list_itr = ice_find_vlan_entry(hw, vlan_id);\n+\tif (!v_list_itr) {\n+\t\tu16 vsi_id = ICE_VSI_INVAL_ID;\n+\t\tenum ice_status status;\n+\t\tu16 vsi_list_id = 0;\n+\n+\t\tif (new_fltr->fltr_act == ICE_FWD_TO_VSI) {\n+\t\t\tenum ice_sw_lkup_type lkup_type = new_fltr->lkup_type;\n+\n+\t\t\t/* All VLAN pruning rules use a VSI list.\n+\t\t\t * Convert the action to forwarding to a VSI list.\n+\t\t\t */\n+\t\t\tvsi_id = new_fltr->fwd_id.vsi_id;\n+\t\t\tstatus = ice_create_vsi_list_rule(hw, &vsi_id, 1,\n+\t\t\t\t\t\t\t  &vsi_list_id,\n+\t\t\t\t\t\t\t  lkup_type);\n+\t\t\tif (status)\n+\t\t\t\treturn status;\n+\t\t\tnew_fltr->fltr_act = ICE_FWD_TO_VSI_LIST;\n+\t\t\tnew_fltr->fwd_id.vsi_list_id = vsi_list_id;\n+\t\t}\n+\n+\t\tstatus = ice_create_pkt_fwd_rule(hw, f_entry);\n+\t\tif (!status && vsi_id != ICE_VSI_INVAL_ID) {\n+\t\t\tv_list_itr = ice_find_vlan_entry(hw, vlan_id);\n+\t\t\tif (!v_list_itr)\n+\t\t\t\treturn ICE_ERR_DOES_NOT_EXIST;\n+\t\t\tv_list_itr->vsi_list_info =\n+\t\t\t\tice_create_vsi_list_map(hw, &vsi_id, 1,\n+\t\t\t\t\t\t\tvsi_list_id);\n+\t\t}\n+\n+\t\treturn status;\n+\t}\n+\n+\tcur_fltr = &v_list_itr->fltr_info;\n+\treturn ice_handle_vsi_list_mgmt(hw, v_list_itr, cur_fltr, new_fltr);\n+}\n+\n+/**\n+ * ice_add_vlan - Add VLAN based filter rule\n+ * @hw: pointer to the hardware structure\n+ * @v_list: list of VLAN entries and forwarding information\n+ */\n+enum ice_status\n+ice_add_vlan(struct ice_hw *hw, struct list_head *v_list)\n+{\n+\tstruct ice_fltr_list_entry *v_list_itr;\n+\n+\tif (!v_list || !hw)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tlist_for_each_entry(v_list_itr, v_list, list_entry) {\n+\t\tenum ice_status status;\n+\n+\t\tif (v_list_itr->fltr_info.lkup_type != ICE_SW_LKUP_VLAN)\n+\t\t\treturn ICE_ERR_PARAM;\n+\n+\t\tstatus = ice_add_vlan_internal(hw, v_list_itr);\n+\t\tif (status) {\n+\t\t\tv_list_itr->status = ICE_FLTR_STATUS_FW_FAIL;\n+\t\t\treturn status;\n+\t\t}\n+\t\tv_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS;\n+\t}\n+\treturn 0;\n+}\n+\n /**\n  * ice_remove_vsi_list_rule\n  * @hw: pointer to the hardware structure\n@@ -1529,6 +1640,54 @@ ice_remove_mac(struct ice_hw *hw, struct list_head *m_list)\n \treturn status;\n }\n \n+/**\n+ * ice_remove_vlan_internal - Remove one VLAN based filter rule\n+ * @hw: pointer to the hardware structure\n+ * @f_entry: filter entry containing one VLAN information\n+ */\n+static enum ice_status\n+ice_remove_vlan_internal(struct ice_hw *hw,\n+\t\t\t struct ice_fltr_list_entry *f_entry)\n+{\n+\tstruct ice_fltr_info *new_fltr;\n+\tstruct ice_fltr_mgmt_list_entry *v_list_elem;\n+\tu16 vsi_id;\n+\n+\tnew_fltr = &f_entry->fltr_info;\n+\n+\tv_list_elem = ice_find_vlan_entry(hw, new_fltr->l_data.vlan.vlan_id);\n+\tif (!v_list_elem)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tvsi_id = f_entry->fltr_info.fwd_id.vsi_id;\n+\treturn ice_handle_rem_vsi_list_mgmt(hw, vsi_id, v_list_elem);\n+}\n+\n+/**\n+ * ice_remove_vlan - Remove VLAN based filter rule\n+ * @hw: pointer to the hardware structure\n+ * @v_list: list of VLAN entries and forwarding information\n+ */\n+enum ice_status\n+ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list)\n+{\n+\tstruct ice_fltr_list_entry *v_list_itr;\n+\tenum ice_status status = 0;\n+\n+\tif (!v_list || !hw)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tlist_for_each_entry(v_list_itr, v_list, list_entry) {\n+\t\tstatus = ice_remove_vlan_internal(hw, v_list_itr);\n+\t\tif (status) {\n+\t\t\tv_list_itr->status = ICE_FLTR_STATUS_FW_FAIL;\n+\t\t\treturn status;\n+\t\t}\n+\t\tv_list_itr->status = ICE_FLTR_STATUS_FW_SUCCESS;\n+\t}\n+\treturn status;\n+}\n+\n /**\n  * ice_add_to_vsi_fltr_list - Add VSI filters to the list\n  * @hw: pointer to the hardware structure\n@@ -1614,6 +1773,16 @@ ice_remove_vsi_lkup_fltr(struct ice_hw *hw, u16 vsi_id,\n \t\t}\n \t\tbreak;\n \tcase ICE_SW_LKUP_VLAN:\n+\t\tmutex_lock(&sw->vlan_list_lock);\n+\t\tstatus = ice_add_to_vsi_fltr_list(hw, vsi_id,\n+\t\t\t\t\t\t  &sw->vlan_list_head,\n+\t\t\t\t\t\t  &remove_list_head);\n+\t\tmutex_unlock(&sw->vlan_list_lock);\n+\t\tif (!status) {\n+\t\t\tice_remove_vlan(hw, &remove_list_head);\n+\t\t\tgoto free_fltr_list;\n+\t\t}\n+\t\tbreak;\n \tcase ICE_SW_LKUP_MAC_VLAN:\n \tcase ICE_SW_LKUP_ETHERTYPE:\n \tcase ICE_SW_LKUP_ETHERTYPE_MAC:\ndiff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h\nindex 8039a8e38331..60c63264a393 100644\n--- a/drivers/net/ethernet/intel/ice/ice_switch.h\n+++ b/drivers/net/ethernet/intel/ice/ice_switch.h\n@@ -22,6 +22,7 @@\n \n #define ICE_SW_CFG_MAX_BUF_LEN 2048\n #define ICE_DFLT_VSI_INVAL 0xff\n+#define ICE_VSI_INVAL_ID 0xffff\n \n /* VSI context structure for add/get/update/free operations */\n struct ice_vsi_ctx {\n@@ -166,4 +167,7 @@ enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw);\n enum ice_status ice_add_mac(struct ice_hw *hw, struct list_head *m_lst);\n enum ice_status ice_remove_mac(struct ice_hw *hw, struct list_head *m_lst);\n void ice_remove_vsi_fltr(struct ice_hw *hw, u16 vsi_id);\n+enum ice_status ice_add_vlan(struct ice_hw *hw, struct list_head *m_list);\n+enum ice_status ice_remove_vlan(struct ice_hw *hw, struct list_head *v_list);\n+\n #endif /* _ICE_SWITCH_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c\nindex 5775cdde57e3..06b418e0b629 100644\n--- a/drivers/net/ethernet/intel/ice/ice_txrx.c\n+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c\n@@ -810,6 +810,134 @@ static bool ice_is_non_eop(struct ice_ring *rx_ring,\n \treturn true;\n }\n \n+/**\n+ * ice_ptype_to_htype - get a hash type\n+ * @ptype: the ptype value from the descriptor\n+ *\n+ * Returns a hash type to be used by skb_set_hash\n+ */\n+static enum pkt_hash_types ice_ptype_to_htype(u8 __always_unused ptype)\n+{\n+\treturn PKT_HASH_TYPE_NONE;\n+}\n+\n+/**\n+ * ice_rx_hash - set the hash value in the skb\n+ * @rx_ring: descriptor ring\n+ * @rx_desc: specific descriptor\n+ * @skb: pointer to current skb\n+ * @rx_ptype: the ptype value from the descriptor\n+ */\n+static void\n+ice_rx_hash(struct ice_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc,\n+\t    struct sk_buff *skb, u8 rx_ptype)\n+{\n+\tstruct ice_32b_rx_flex_desc_nic *nic_mdid;\n+\tu32 hash;\n+\n+\tif (!(rx_ring->netdev->features & NETIF_F_RXHASH))\n+\t\treturn;\n+\n+\tif (rx_desc->wb.rxdid != ICE_RXDID_FLEX_NIC)\n+\t\treturn;\n+\n+\tnic_mdid = (struct ice_32b_rx_flex_desc_nic *)rx_desc;\n+\thash = le32_to_cpu(nic_mdid->rss_hash);\n+\tskb_set_hash(skb, hash, ice_ptype_to_htype(rx_ptype));\n+}\n+\n+/**\n+ * ice_rx_csum - Indicate in skb if checksum is good\n+ * @vsi: the VSI we care about\n+ * @skb: skb currently being received and modified\n+ * @rx_desc: the receive descriptor\n+ * @ptype: the packet type decoded by hardware\n+ *\n+ * skb->protocol must be set before this function is called\n+ */\n+static void ice_rx_csum(struct ice_vsi *vsi, struct sk_buff *skb,\n+\t\t\tunion ice_32b_rx_flex_desc *rx_desc, u8 ptype)\n+{\n+\tstruct ice_rx_ptype_decoded decoded;\n+\tu32 rx_error, rx_status;\n+\tbool ipv4, ipv6;\n+\n+\trx_status = le16_to_cpu(rx_desc->wb.status_error0);\n+\trx_error = rx_status;\n+\n+\tdecoded = ice_decode_rx_desc_ptype(ptype);\n+\n+\t/* Start with CHECKSUM_NONE and by default csum_level = 0 */\n+\tskb->ip_summed = CHECKSUM_NONE;\n+\tskb_checksum_none_assert(skb);\n+\n+\t/* check if Rx checksum is enabled */\n+\tif (!(vsi->netdev->features & NETIF_F_RXCSUM))\n+\t\treturn;\n+\n+\t/* check if HW has decoded the packet and checksum */\n+\tif (!(rx_status & BIT(ICE_RX_FLEX_DESC_STATUS0_L3L4P_S)))\n+\t\treturn;\n+\n+\tif (!(decoded.known && decoded.outer_ip))\n+\t\treturn;\n+\n+\tipv4 = (decoded.outer_ip == ICE_RX_PTYPE_OUTER_IP) &&\n+\t       (decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV4);\n+\tipv6 = (decoded.outer_ip == ICE_RX_PTYPE_OUTER_IP) &&\n+\t       (decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV6);\n+\n+\tif (ipv4 && (rx_error & (BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_IPE_S) |\n+\t\t\t\t BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_EIPE_S))))\n+\t\tgoto checksum_fail;\n+\telse if (ipv6 && (rx_status &\n+\t\t (BIT(ICE_RX_FLEX_DESC_STATUS0_IPV6EXADD_S))))\n+\t\tgoto checksum_fail;\n+\n+\t/* check for L4 errors and handle packets that were not able to be\n+\t * checksummed due to arrival speed\n+\t */\n+\tif (rx_error & BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_L4E_S))\n+\t\tgoto checksum_fail;\n+\n+\t/* Only report checksum unnecessary for TCP, UDP, or SCTP */\n+\tswitch (decoded.inner_prot) {\n+\tcase ICE_RX_PTYPE_INNER_PROT_TCP:\n+\tcase ICE_RX_PTYPE_INNER_PROT_UDP:\n+\tcase ICE_RX_PTYPE_INNER_PROT_SCTP:\n+\t\tskb->ip_summed = CHECKSUM_UNNECESSARY;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\treturn;\n+\n+checksum_fail:\n+\tvsi->back->hw_csum_rx_error++;\n+}\n+\n+/**\n+ * ice_process_skb_fields - Populate skb header fields from Rx descriptor\n+ * @rx_ring: rx descriptor ring packet is being transacted on\n+ * @rx_desc: pointer to the EOP Rx descriptor\n+ * @skb: pointer to current skb being populated\n+ * @ptype: the packet type decoded by hardware\n+ *\n+ * This function checks the ring, descriptor, and packet information in\n+ * order to populate the hash, checksum, VLAN, protocol, and\n+ * other fields within the skb.\n+ */\n+static void ice_process_skb_fields(struct ice_ring *rx_ring,\n+\t\t\t\t   union ice_32b_rx_flex_desc *rx_desc,\n+\t\t\t\t   struct sk_buff *skb, u8 ptype)\n+{\n+\tice_rx_hash(rx_ring, rx_desc, skb, ptype);\n+\n+\t/* modifies the skb - consumes the enet header */\n+\tskb->protocol = eth_type_trans(skb, rx_ring->netdev);\n+\n+\tice_rx_csum(rx_ring->vsi, skb, rx_desc, ptype);\n+}\n+\n /**\n  * ice_receive_skb - Send a completed packet up the stack\n  * @rx_ring: rx ring in play\n@@ -853,6 +981,7 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)\n \t\tstruct sk_buff *skb;\n \t\tu16 stat_err_bits;\n \t\tu16 vlan_tag = 0;\n+\t\tu8 rx_ptype;\n \n \t\t/* return some buffers to hardware, one at a time is too slow */\n \t\tif (cleaned_count >= ICE_RX_BUF_WRITE) {\n@@ -896,6 +1025,9 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)\n \t\t\tcontinue;\n \t\t}\n \n+\t\trx_ptype = le16_to_cpu(rx_desc->wb.ptype_flex_flags0) &\n+\t\t\tICE_RX_FLEX_DESC_PTYPE_M;\n+\n \t\tstat_err_bits = BIT(ICE_RX_FLEX_DESC_STATUS0_L2TAG1P_S);\n \t\tif (ice_test_staterr(rx_desc, stat_err_bits))\n \t\t\tvlan_tag = le16_to_cpu(rx_desc->wb.l2tag1);\n@@ -911,6 +1043,9 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)\n \t\t/* probably a little skewed due to removing CRC */\n \t\ttotal_rx_bytes += skb->len;\n \n+\t\t/* populate checksum, VLAN, and protocol */\n+\t\tice_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);\n+\n \t\t/* send completed skb up the stack */\n \t\tice_receive_skb(rx_ring, skb, vlan_tag);\n \n@@ -1040,14 +1175,17 @@ static int ice_maybe_stop_tx(struct ice_ring *tx_ring, unsigned int size)\n  * ice_tx_map - Build the Tx descriptor\n  * @tx_ring: ring to send buffer on\n  * @first: first buffer info buffer to use\n+ * @off: pointer to struct that holds offload parameters\n  *\n  * This function loops over the skb data pointed to by *first\n  * and gets a physical address for each memory location and programs\n  * it and the length into the transmit descriptor.\n  */\n-static void ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first)\n+static void\n+ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first,\n+\t   struct ice_tx_offload_params *off)\n {\n-\tu64 td_offset = 0, td_tag = 0, td_cmd = 0;\n+\tu64 td_offset, td_tag, td_cmd;\n \tu16 i = tx_ring->next_to_use;\n \tstruct skb_frag_struct *frag;\n \tunsigned int data_len, size;\n@@ -1056,6 +1194,9 @@ static void ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first)\n \tstruct sk_buff *skb;\n \tdma_addr_t dma;\n \n+\ttd_tag = off->td_l2tag1;\n+\ttd_cmd = off->td_cmd;\n+\ttd_offset = off->td_offset;\n \tskb = first->skb;\n \n \tdata_len = skb->data_len;\n@@ -1063,6 +1204,12 @@ static void ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first)\n \n \ttx_desc = ICE_TX_DESC(tx_ring, i);\n \n+\tif (first->tx_flags & ICE_TX_FLAGS_HW_VLAN) {\n+\t\ttd_cmd |= (u64)ICE_TX_DESC_CMD_IL2TAG1;\n+\t\ttd_tag = (first->tx_flags & ICE_TX_FLAGS_VLAN_M) >>\n+\t\t\t  ICE_TX_FLAGS_VLAN_S;\n+\t}\n+\n \tdma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE);\n \n \ttx_buf = first;\n@@ -1183,6 +1330,223 @@ static void ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first)\n \ttx_ring->next_to_use = i;\n }\n \n+/**\n+ * ice_tx_csum - Enable Tx checksum offloads\n+ * @first: pointer to the first descriptor\n+ * @off: pointer to struct that holds offload parameters\n+ *\n+ * Returns 0 or error (negative) if checksum offload can't happen, 1 otherwise.\n+ */\n+static\n+int ice_tx_csum(struct ice_tx_buf *first, struct ice_tx_offload_params *off)\n+{\n+\tu32 l4_len = 0, l3_len = 0, l2_len = 0;\n+\tstruct sk_buff *skb = first->skb;\n+\tunion {\n+\t\tstruct iphdr *v4;\n+\t\tstruct ipv6hdr *v6;\n+\t\tunsigned char *hdr;\n+\t} ip;\n+\tunion {\n+\t\tstruct tcphdr *tcp;\n+\t\tunsigned char *hdr;\n+\t} l4;\n+\t__be16 frag_off, protocol;\n+\tunsigned char *exthdr;\n+\tu32 offset, cmd = 0;\n+\tu8 l4_proto = 0;\n+\n+\tif (skb->ip_summed != CHECKSUM_PARTIAL)\n+\t\treturn 0;\n+\n+\tip.hdr = skb_network_header(skb);\n+\tl4.hdr = skb_transport_header(skb);\n+\n+\t/* compute outer L2 header size */\n+\tl2_len = ip.hdr - skb->data;\n+\toffset = (l2_len / 2) << ICE_TX_DESC_LEN_MACLEN_S;\n+\n+\tif (skb->encapsulation)\n+\t\treturn -1;\n+\n+\t/* Enable IP checksum offloads */\n+\tprotocol = vlan_get_protocol(skb);\n+\tif (protocol == htons(ETH_P_IP)) {\n+\t\tl4_proto = ip.v4->protocol;\n+\t\t/* the stack computes the IP header already, the only time we\n+\t\t * need the hardware to recompute it is in the case of TSO.\n+\t\t */\n+\t\tif (first->tx_flags & ICE_TX_FLAGS_TSO)\n+\t\t\tcmd |= ICE_TX_DESC_CMD_IIPT_IPV4_CSUM;\n+\t\telse\n+\t\t\tcmd |= ICE_TX_DESC_CMD_IIPT_IPV4;\n+\n+\t} else if (protocol == htons(ETH_P_IPV6)) {\n+\t\tcmd |= ICE_TX_DESC_CMD_IIPT_IPV6;\n+\t\texthdr = ip.hdr + sizeof(*ip.v6);\n+\t\tl4_proto = ip.v6->nexthdr;\n+\t\tif (l4.hdr != exthdr)\n+\t\t\tipv6_skip_exthdr(skb, exthdr - skb->data, &l4_proto,\n+\t\t\t\t\t &frag_off);\n+\t} else {\n+\t\treturn -1;\n+\t}\n+\n+\t/* compute inner L3 header size */\n+\tl3_len = l4.hdr - ip.hdr;\n+\toffset |= (l3_len / 4) << ICE_TX_DESC_LEN_IPLEN_S;\n+\n+\t/* Enable L4 checksum offloads */\n+\tswitch (l4_proto) {\n+\tcase IPPROTO_TCP:\n+\t\t/* enable checksum offloads */\n+\t\tcmd |= ICE_TX_DESC_CMD_L4T_EOFT_TCP;\n+\t\tl4_len = l4.tcp->doff;\n+\t\toffset |= l4_len << ICE_TX_DESC_LEN_L4_LEN_S;\n+\t\tbreak;\n+\tcase IPPROTO_UDP:\n+\t\t/* enable UDP checksum offload */\n+\t\tcmd |= ICE_TX_DESC_CMD_L4T_EOFT_UDP;\n+\t\tl4_len = (sizeof(struct udphdr) >> 2);\n+\t\toffset |= l4_len << ICE_TX_DESC_LEN_L4_LEN_S;\n+\t\tbreak;\n+\tcase IPPROTO_SCTP:\n+\tdefault:\n+\t\tif (first->tx_flags & ICE_TX_FLAGS_TSO)\n+\t\t\treturn -1;\n+\t\tskb_checksum_help(skb);\n+\t\treturn 0;\n+\t}\n+\n+\toff->td_cmd |= cmd;\n+\toff->td_offset |= offset;\n+\treturn 1;\n+}\n+\n+/**\n+ * ice_tx_prepare_vlan_flags - prepare generic TX VLAN tagging flags for HW\n+ * @tx_ring: ring to send buffer on\n+ * @first: pointer to struct ice_tx_buf\n+ *\n+ * Checks the skb and set up correspondingly several generic transmit flags\n+ * related to VLAN tagging for the HW, such as VLAN, DCB, etc.\n+ *\n+ * Returns error code indicate the frame should be dropped upon error and the\n+ * otherwise returns 0 to indicate the flags has been set properly.\n+ */\n+static int\n+ice_tx_prepare_vlan_flags(struct ice_ring *tx_ring, struct ice_tx_buf *first)\n+{\n+\tstruct sk_buff *skb = first->skb;\n+\t__be16 protocol = skb->protocol;\n+\n+\tif (protocol == htons(ETH_P_8021Q) &&\n+\t    !(tx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) {\n+\t\t/* when HW VLAN acceleration is turned off by the user the\n+\t\t * stack sets the protocol to 8021q so that the driver\n+\t\t * can take any steps required to support the SW only\n+\t\t * VLAN handling. In our case the driver doesn't need\n+\t\t * to take any further steps so just set the protocol\n+\t\t * to the encapsulated ethertype.\n+\t\t */\n+\t\tskb->protocol = vlan_get_protocol(skb);\n+\t\tgoto out;\n+\t}\n+\n+\t/* if we have a HW VLAN tag being added, default to the HW one */\n+\tif (skb_vlan_tag_present(skb)) {\n+\t\tfirst->tx_flags |= skb_vlan_tag_get(skb) << ICE_TX_FLAGS_VLAN_S;\n+\t\tfirst->tx_flags |= ICE_TX_FLAGS_HW_VLAN;\n+\t} else if (protocol == htons(ETH_P_8021Q)) {\n+\t\tstruct vlan_hdr *vhdr, _vhdr;\n+\n+\t\t/* for SW VLAN, check the next protocol and store the tag */\n+\t\tvhdr = (struct vlan_hdr *)skb_header_pointer(skb, ETH_HLEN,\n+\t\t\t\t\t\t\t     sizeof(_vhdr),\n+\t\t\t\t\t\t\t     &_vhdr);\n+\t\tif (!vhdr)\n+\t\t\treturn -EINVAL;\n+\n+\t\tfirst->tx_flags |= ntohs(vhdr->h_vlan_TCI) <<\n+\t\t\t\t   ICE_TX_FLAGS_VLAN_S;\n+\t\tfirst->tx_flags |= ICE_TX_FLAGS_SW_VLAN;\n+\t}\n+\n+out:\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_tso - computes mss and TSO length to prepare for TSO\n+ * @first: pointer to struct ice_tx_buf\n+ * @off: pointer to struct that holds offload parameters\n+ *\n+ * Returns 0 or error (negative) if TSO can't happen, 1 otherwise.\n+ */\n+static\n+int ice_tso(struct ice_tx_buf *first, struct ice_tx_offload_params *off)\n+{\n+\tstruct sk_buff *skb = first->skb;\n+\tunion {\n+\t\tstruct iphdr *v4;\n+\t\tstruct ipv6hdr *v6;\n+\t\tunsigned char *hdr;\n+\t} ip;\n+\tunion {\n+\t\tstruct tcphdr *tcp;\n+\t\tunsigned char *hdr;\n+\t} l4;\n+\tu64 cd_mss, cd_tso_len;\n+\tu32 paylen, l4_start;\n+\tint err;\n+\n+\tif (skb->ip_summed != CHECKSUM_PARTIAL)\n+\t\treturn 0;\n+\n+\tif (!skb_is_gso(skb))\n+\t\treturn 0;\n+\n+\terr = skb_cow_head(skb, 0);\n+\tif (err < 0)\n+\t\treturn err;\n+\n+\tip.hdr = skb_network_header(skb);\n+\tl4.hdr = skb_transport_header(skb);\n+\n+\t/* initialize outer IP header fields */\n+\tif (ip.v4->version == 4) {\n+\t\tip.v4->tot_len = 0;\n+\t\tip.v4->check = 0;\n+\t} else {\n+\t\tip.v6->payload_len = 0;\n+\t}\n+\n+\t/* determine offset of transport header */\n+\tl4_start = l4.hdr - skb->data;\n+\n+\t/* remove payload length from checksum */\n+\tpaylen = skb->len - l4_start;\n+\tcsum_replace_by_diff(&l4.tcp->check, (__force __wsum)htonl(paylen));\n+\n+\t/* compute length of segmentation header */\n+\toff->header_len = (l4.tcp->doff * 4) + l4_start;\n+\n+\t/* update gso_segs and bytecount */\n+\tfirst->gso_segs = skb_shinfo(skb)->gso_segs;\n+\tfirst->bytecount = (first->gso_segs - 1) * off->header_len;\n+\n+\tcd_tso_len = skb->len - off->header_len;\n+\tcd_mss = skb_shinfo(skb)->gso_size;\n+\n+\t/* record cdesc_qw1 with TSO parameters */\n+\toff->cd_qw1 |= ICE_TX_DESC_DTYPE_CTX |\n+\t\t\t (ICE_TX_CTX_DESC_TSO << ICE_TXD_CTX_QW1_CMD_S) |\n+\t\t\t (cd_tso_len << ICE_TXD_CTX_QW1_TSO_LEN_S) |\n+\t\t\t (cd_mss << ICE_TXD_CTX_QW1_MSS_S);\n+\tfirst->tx_flags |= ICE_TX_FLAGS_TSO;\n+\treturn 1;\n+}\n+\n /**\n  * ice_txd_use_count  - estimate the number of descriptors needed for Tx\n  * @size: transmit request size in bytes\n@@ -1336,8 +1700,10 @@ static bool ice_chk_linearize(struct sk_buff *skb, unsigned int count)\n static netdev_tx_t\n ice_xmit_frame_ring(struct sk_buff *skb, struct ice_ring *tx_ring)\n {\n+\tstruct ice_tx_offload_params offload = { 0 };\n \tstruct ice_tx_buf *first;\n \tunsigned int count;\n+\tint tso, csum;\n \n \tcount = ice_xmit_desc_count(skb);\n \tif (ice_chk_linearize(skb, count)) {\n@@ -1358,13 +1724,46 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_ring *tx_ring)\n \t\treturn NETDEV_TX_BUSY;\n \t}\n \n+\toffload.tx_ring = tx_ring;\n+\n \t/* record the location of the first descriptor for this packet */\n \tfirst = &tx_ring->tx_buf[tx_ring->next_to_use];\n \tfirst->skb = skb;\n \tfirst->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN);\n \tfirst->gso_segs = 1;\n+\tfirst->tx_flags = 0;\n+\n+\t/* prepare the VLAN tagging flags for Tx */\n+\tif (ice_tx_prepare_vlan_flags(tx_ring, first))\n+\t\tgoto out_drop;\n+\n+\t/* set up TSO offload */\n+\ttso = ice_tso(first, &offload);\n+\tif (tso < 0)\n+\t\tgoto out_drop;\n+\n+\t/* always set up Tx checksum offload */\n+\tcsum = ice_tx_csum(first, &offload);\n+\tif (csum < 0)\n+\t\tgoto out_drop;\n+\n+\tif (tso || offload.cd_tunnel_params) {\n+\t\tstruct ice_tx_ctx_desc *cdesc;\n+\t\tint i = tx_ring->next_to_use;\n+\n+\t\t/* grab the next descriptor */\n+\t\tcdesc = ICE_TX_CTX_DESC(tx_ring, i);\n+\t\ti++;\n+\t\ttx_ring->next_to_use = (i < tx_ring->count) ? i : 0;\n+\n+\t\t/* setup context descriptor */\n+\t\tcdesc->tunneling_params = cpu_to_le32(offload.cd_tunnel_params);\n+\t\tcdesc->l2tag2 = cpu_to_le16(offload.cd_l2tag2);\n+\t\tcdesc->rsvd = cpu_to_le16(0);\n+\t\tcdesc->qw1 = cpu_to_le64(offload.cd_qw1);\n+\t}\n \n-\tice_tx_map(tx_ring, first);\n+\tice_tx_map(tx_ring, first, &offload);\n \treturn NETDEV_TX_OK;\n \n out_drop:\ndiff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h\nindex 4bcdb79ef181..eb19d8c5822b 100644\n--- a/drivers/net/ethernet/intel/ice/ice_txrx.h\n+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h\n@@ -42,6 +42,12 @@\n \t((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \\\n \t(R)->next_to_clean - (R)->next_to_use - 1)\n \n+#define ICE_TX_FLAGS_TSO\tBIT(0)\n+#define ICE_TX_FLAGS_HW_VLAN\tBIT(1)\n+#define ICE_TX_FLAGS_SW_VLAN\tBIT(2)\n+#define ICE_TX_FLAGS_VLAN_M\t0xffff0000\n+#define ICE_TX_FLAGS_VLAN_S\t16\n+\n struct ice_tx_buf {\n \tstruct ice_tx_desc *next_to_watch;\n \tstruct sk_buff *skb;\n@@ -52,6 +58,17 @@ struct ice_tx_buf {\n \tDEFINE_DMA_UNMAP_LEN(len);\n };\n \n+struct ice_tx_offload_params {\n+\tu8 header_len;\n+\tu32 td_cmd;\n+\tu32 td_offset;\n+\tu32 td_l2tag1;\n+\tu16 cd_l2tag2;\n+\tu32 cd_tunnel_params;\n+\tu64 cd_qw1;\n+\tstruct ice_ring *tx_ring;\n+};\n+\n struct ice_rx_buf {\n \tstruct sk_buff *skb;\n \tdma_addr_t dma;\n",
    "prefixes": [
        "v2",
        "11/15"
    ]
}