Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/886534/?format=api
{ "id": 886534, "url": "http://patchwork.ozlabs.org/api/patches/886534/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20180315234802.31336-14-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-14-anirudh.venkataramanan@intel.com>", "list_archive_url": null, "date": "2018-03-15T23:48:00", "name": "[v2,13/15] ice: Update Tx scheduler tree for VSI multi-Tx queue support", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "7c40dbad08242cd09f584396f872ae1c07c16591", "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-14-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/886534/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/886534/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.137; helo=fraxinus.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 fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\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 402QJr0PzFz9sVp\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 16 Mar 2018 10:48:27 +1100 (AEDT)", "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 8EE6D87699;\n\tThu, 15 Mar 2018 23:48:26 +0000 (UTC)", "from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id S4hR8moZLPYa; Thu, 15 Mar 2018 23:48:20 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 0212687618;\n\tThu, 15 Mar 2018 23:48:20 +0000 (UTC)", "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\tby ash.osuosl.org (Postfix) with ESMTP id ABEE91C0359\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 15 Mar 2018 23:48:13 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id A7ED98A2B5\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 15 Mar 2018 23:48:13 +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 rME8Ao6HsI6E 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 27DE28A269\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 15 Mar 2018 23:48:07 +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:06 -0700", "from shasta.jf.intel.com ([10.166.241.32])\n\tby fmsmga004.fm.intel.com with ESMTP; 15 Mar 2018 16:48:06 -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=\"37836800\"", "From": "Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>", "To": "intel-wired-lan@lists.osuosl.org", "Date": "Thu, 15 Mar 2018 16:48:00 -0700", "Message-Id": "<20180315234802.31336-14-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 13/15] ice: Update Tx scheduler tree\n\tfor VSI multi-Tx queue support", "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 the ability for a VSI to use multiple Tx queues. More\nspecifically, the patch\n 1) Provides the ability to update the Tx scheduler tree in the\n firmware. The driver can configure the Tx scheduler tree by\n adding/removing multiple Tx queues per TC per VSI.\n\n 2) Allows a VSI to reconfigure its Tx queues during runtime.\n\n 3) Synchronizes the Tx scheduler update operations using locks.\n\nSigned-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>\n---\n drivers/net/ethernet/intel/ice/ice.h | 7 +\n drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 28 +\n drivers/net/ethernet/intel/ice/ice_common.c | 54 ++\n drivers/net/ethernet/intel/ice/ice_common.h | 3 +\n drivers/net/ethernet/intel/ice/ice_main.c | 20 +-\n drivers/net/ethernet/intel/ice/ice_sched.c | 886 ++++++++++++++++++++++++\n drivers/net/ethernet/intel/ice/ice_sched.h | 4 +\n drivers/net/ethernet/intel/ice/ice_type.h | 7 +\n 8 files changed, 1006 insertions(+), 3 deletions(-)", "diff": "diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h\nindex 6014ef9c36e1..cb1e8a127af1 100644\n--- a/drivers/net/ethernet/intel/ice/ice.h\n+++ b/drivers/net/ethernet/intel/ice/ice.h\n@@ -56,6 +56,7 @@ extern const char ice_drv_ver[];\n #define ICE_MIN_NUM_DESC\t8\n #define ICE_MAX_NUM_DESC\t8160\n #define ICE_REQ_DESC_MULTIPLE\t32\n+#define ICE_DFLT_TRAFFIC_CLASS\tBIT(0)\n #define ICE_INT_NAME_STR_LEN\t(IFNAMSIZ + 16)\n #define ICE_ETHTOOL_FWVER_LEN\t32\n #define ICE_AQ_LEN\t\t64\n@@ -275,6 +276,12 @@ 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+static inline void ice_vsi_set_tc_cfg(struct ice_vsi *vsi)\n+{\n+\tvsi->tc_cfg.ena_tc = ICE_DFLT_TRAFFIC_CLASS;\n+\tvsi->tc_cfg.numtc = 1;\n+}\n+\n void ice_set_ethtool_ops(struct net_device *netdev);\n int ice_up(struct ice_vsi *vsi);\n int ice_down(struct ice_vsi *vsi);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\nindex 2c8d8533f87d..62509635fc5e 100644\n--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n@@ -645,6 +645,25 @@ struct ice_aqc_get_topo {\n \t__le32 addr_low;\n };\n \n+/* Update TSE (indirect 0x0403)\n+ * Get TSE (indirect 0x0404)\n+ */\n+struct ice_aqc_get_cfg_elem {\n+\t__le16 num_elem_req;\t/* Used by commands */\n+\t__le16 num_elem_resp;\t/* Used by responses */\n+\t__le32 reserved;\n+\t__le32 addr_high;\n+\t__le32 addr_low;\n+};\n+\n+/* This is the buffer for:\n+ * Suspend Nodes (indirect 0x0409)\n+ * Resume Nodes (indirect 0x040A)\n+ */\n+struct ice_aqc_suspend_resume_elem {\n+\t__le32 teid[1];\n+};\n+\n /* Add TSE (indirect 0x0401)\n * Delete TSE (indirect 0x040F)\n * Move TSE (indirect 0x0408)\n@@ -705,6 +724,11 @@ struct ice_aqc_txsched_topo_grp_info_hdr {\n \t__le16 reserved2;\n };\n \n+struct ice_aqc_add_elem {\n+\tstruct ice_aqc_txsched_topo_grp_info_hdr hdr;\n+\tstruct ice_aqc_txsched_elem_data generic[1];\n+};\n+\n struct ice_aqc_get_topo_elem {\n \tstruct ice_aqc_txsched_topo_grp_info_hdr hdr;\n \tstruct ice_aqc_txsched_elem_data\n@@ -1195,6 +1219,7 @@ struct ice_aq_desc {\n \t\tstruct ice_aqc_get_sw_cfg get_sw_conf;\n \t\tstruct ice_aqc_sw_rules sw_rules;\n \t\tstruct ice_aqc_get_topo get_topo;\n+\t\tstruct ice_aqc_get_cfg_elem get_update_elem;\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@@ -1272,6 +1297,9 @@ enum ice_adminq_opc {\n \n \t/* transmit scheduler commands */\n \tice_aqc_opc_get_dflt_topo\t\t\t= 0x0400,\n+\tice_aqc_opc_add_sched_elems\t\t\t= 0x0401,\n+\tice_aqc_opc_suspend_sched_elems\t\t\t= 0x0409,\n+\tice_aqc_opc_resume_sched_elems\t\t\t= 0x040A,\n \tice_aqc_opc_delete_sched_elems\t\t\t= 0x040F,\n \tice_aqc_opc_query_sched_res\t\t\t= 0x0412,\n \ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c\nindex 43cca9370444..958161a21115 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.c\n+++ b/drivers/net/ethernet/intel/ice/ice_common.c\n@@ -2103,3 +2103,57 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids,\n \tmutex_unlock(&pi->sched_lock);\n \treturn status;\n }\n+\n+/**\n+ * ice_cfg_vsi_qs - configure the new/exisiting VSI queues\n+ * @pi: port information structure\n+ * @vsi_id: VSI Id\n+ * @tc_bitmap: TC bitmap\n+ * @maxqs: max queues array per TC\n+ * @owner: lan or rdma\n+ *\n+ * This function adds/updates the VSI queues per TC.\n+ */\n+static enum ice_status\n+ice_cfg_vsi_qs(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap,\n+\t u16 *maxqs, u8 owner)\n+{\n+\tenum ice_status status = 0;\n+\tu8 i;\n+\n+\tif (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)\n+\t\treturn ICE_ERR_CFG;\n+\n+\tmutex_lock(&pi->sched_lock);\n+\n+\tfor (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) {\n+\t\t/* configuration is possible only if TC node is present */\n+\t\tif (!ice_sched_get_tc_node(pi, i))\n+\t\t\tcontinue;\n+\n+\t\tstatus = ice_sched_cfg_vsi(pi, vsi_id, i, maxqs[i], owner,\n+\t\t\t\t\t ice_is_tc_ena(tc_bitmap, i));\n+\t\tif (status)\n+\t\t\tbreak;\n+\t}\n+\n+\tmutex_unlock(&pi->sched_lock);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_cfg_vsi_lan - configure VSI lan queues\n+ * @pi: port information structure\n+ * @vsi_id: VSI Id\n+ * @tc_bitmap: TC bitmap\n+ * @max_lanqs: max lan queues array per TC\n+ *\n+ * This function adds/updates the VSI lan queues per TC.\n+ */\n+enum ice_status\n+ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap,\n+\t\tu16 *max_lanqs)\n+{\n+\treturn ice_cfg_vsi_qs(pi, vsi_id, tc_bitmap, max_lanqs,\n+\t\t\t ICE_SCHED_NODE_OWNER_LAN);\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h\nindex bc52b7bcc78c..3e33a47cb61a 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.h\n+++ b/drivers/net/ethernet/intel/ice/ice_common.h\n@@ -83,6 +83,9 @@ enum ice_status\n ice_dis_vsi_txq(struct ice_port_info *pi, u8 num_queues, u16 *q_ids,\n \t\tu32 *q_teids, struct ice_sq_cd *cmd_details);\n enum ice_status\n+ice_cfg_vsi_lan(struct ice_port_info *pi, u16 vsi_id, u8 tc_bitmap,\n+\t\tu16 *max_lanqs);\n+enum ice_status\n ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_id, u8 tc, u8 num_qgrps,\n \t\tstruct ice_aqc_add_tx_qgrp *buf, u16 buf_size,\n \t\tstruct ice_sq_cd *cd);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c\nindex 1dbe510e80fa..8eef9a4c1d13 100644\n--- a/drivers/net/ethernet/intel/ice/ice_main.c\n+++ b/drivers/net/ethernet/intel/ice/ice_main.c\n@@ -2099,10 +2099,11 @@ static struct ice_vsi *\n ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,\n \t struct ice_port_info *pi)\n {\n+\tu16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };\n \tstruct device *dev = &pf->pdev->dev;\n \tstruct ice_vsi_ctx ctxt = { 0 };\n \tstruct ice_vsi *vsi;\n-\tint ret;\n+\tint ret, i;\n \n \tvsi = ice_vsi_alloc(pf, type);\n \tif (!vsi) {\n@@ -2170,6 +2171,20 @@ ice_vsi_setup(struct ice_pf *pf, enum ice_vsi_type type,\n \t\t */\n \t\tgoto err_rings;\n \t}\n+\n+\tice_vsi_set_tc_cfg(vsi);\n+\n+\t/* configure VSI nodes based on number of queues and TC's */\n+\tfor (i = 0; i < vsi->tc_cfg.numtc; i++)\n+\t\tmax_txqs[i] = vsi->num_txq;\n+\n+\tret = ice_cfg_vsi_lan(vsi->port_info, vsi->vsi_num,\n+\t\t\t vsi->tc_cfg.ena_tc, max_txqs);\n+\tif (ret) {\n+\t\tdev_info(&pf->pdev->dev, \"Failed VSI lan queue config\\n\");\n+\t\tgoto err_rings;\n+\t}\n+\n \treturn vsi;\n \n err_rings:\n@@ -2412,8 +2427,7 @@ 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 queue */\n-\tpf->num_lan_tx = 1;\n+\tpf->num_lan_tx = min_t(int, q_left_tx, num_online_cpus());\n \n \t/* only 1 rx queue unless RSS is enabled */\n \tif (!test_bit(ICE_FLAG_RSS_ENA, pf->flags))\ndiff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c\nindex 74dbdb3d5df2..57d678eed61e 100644\n--- a/drivers/net/ethernet/intel/ice/ice_sched.c\n+++ b/drivers/net/ethernet/intel/ice/ice_sched.c\n@@ -373,6 +373,110 @@ ice_aq_get_dflt_topo(struct ice_hw *hw, u8 lport,\n \treturn status;\n }\n \n+/**\n+ * ice_aq_add_sched_elems - adds scheduling element\n+ * @hw: pointer to the hw struct\n+ * @grps_req: the number of groups that are requested to be added\n+ * @buf: pointer to buffer\n+ * @buf_size: buffer size in bytes\n+ * @grps_added: returns total number of groups added\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Add scheduling elements (0x0401)\n+ */\n+static enum ice_status\n+ice_aq_add_sched_elems(struct ice_hw *hw, u16 grps_req,\n+\t\t struct ice_aqc_add_elem *buf, u16 buf_size,\n+\t\t u16 *grps_added, struct ice_sq_cd *cd)\n+{\n+\tstruct ice_aqc_add_move_delete_elem *cmd;\n+\tstruct ice_aq_desc desc;\n+\tenum ice_status status;\n+\n+\tcmd = &desc.params.add_move_delete_elem;\n+\tice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_add_sched_elems);\n+\tdesc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);\n+\n+\tcmd->num_grps_req = cpu_to_le16(grps_req);\n+\tstatus = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);\n+\tif (!status && grps_added)\n+\t\t*grps_added = le16_to_cpu(cmd->num_grps_updated);\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_suspend_resume_elems - suspend/resume scheduler elements\n+ * @hw: pointer to the hw struct\n+ * @elems_req: number of elements to suspend\n+ * @buf: pointer to buffer\n+ * @buf_size: buffer size in bytes\n+ * @elems_ret: returns total number of elements suspended\n+ * @cd: pointer to command details structure or NULL\n+ * @cmd_code: command code for suspend or resume\n+ *\n+ * suspend/resume scheduler elements\n+ */\n+static enum ice_status\n+ice_suspend_resume_elems(struct ice_hw *hw, u16 elems_req,\n+\t\t\t struct ice_aqc_suspend_resume_elem *buf, u16 buf_size,\n+\t\t\t u16 *elems_ret, struct ice_sq_cd *cd,\n+\t\t\t enum ice_adminq_opc cmd_code)\n+{\n+\tstruct ice_aqc_get_cfg_elem *cmd;\n+\tstruct ice_aq_desc desc;\n+\tenum ice_status status;\n+\n+\tcmd = &desc.params.get_update_elem;\n+\tice_fill_dflt_direct_cmd_desc(&desc, cmd_code);\n+\tcmd->num_elem_req = cpu_to_le16(elems_req);\n+\tdesc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);\n+\tstatus = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);\n+\tif (!status && elems_ret)\n+\t\t*elems_ret = le16_to_cpu(cmd->num_elem_resp);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_aq_suspend_sched_elems - suspend scheduler elements\n+ * @hw: pointer to the hw struct\n+ * @elems_req: number of elements to suspend\n+ * @buf: pointer to buffer\n+ * @buf_size: buffer size in bytes\n+ * @elems_ret: returns total number of elements suspended\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * Suspend scheduling elements (0x0409)\n+ */\n+static enum ice_status\n+ice_aq_suspend_sched_elems(struct ice_hw *hw, u16 elems_req,\n+\t\t\t struct ice_aqc_suspend_resume_elem *buf,\n+\t\t\t u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd)\n+{\n+\treturn ice_suspend_resume_elems(hw, elems_req, buf, buf_size, elems_ret,\n+\t\t\t\t\tcd, ice_aqc_opc_suspend_sched_elems);\n+}\n+\n+/**\n+ * ice_aq_resume_sched_elems - resume scheduler elements\n+ * @hw: pointer to the hw struct\n+ * @elems_req: number of elements to resume\n+ * @buf: pointer to buffer\n+ * @buf_size: buffer size in bytes\n+ * @elems_ret: returns total number of elements resumed\n+ * @cd: pointer to command details structure or NULL\n+ *\n+ * resume scheduling elements (0x040A)\n+ */\n+static enum ice_status\n+ice_aq_resume_sched_elems(struct ice_hw *hw, u16 elems_req,\n+\t\t\t struct ice_aqc_suspend_resume_elem *buf,\n+\t\t\t u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd)\n+{\n+\treturn ice_suspend_resume_elems(hw, elems_req, buf, buf_size, elems_ret,\n+\t\t\t\t\tcd, ice_aqc_opc_resume_sched_elems);\n+}\n+\n /**\n * ice_aq_query_sched_res - query scheduler resource\n * @hw: pointer to the hw struct\n@@ -393,6 +497,46 @@ ice_aq_query_sched_res(struct ice_hw *hw, u16 buf_size,\n \treturn ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);\n }\n \n+/**\n+ * ice_sched_suspend_resume_elems - suspend or resume hw nodes\n+ * @hw: pointer to the hw struct\n+ * @num_nodes: number of nodes\n+ * @node_teids: array of node teids to be suspended or resumed\n+ * @suspend: true means suspend / false means resume\n+ *\n+ * This function suspends or resumes hw nodes\n+ */\n+static enum ice_status\n+ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids,\n+\t\t\t bool suspend)\n+{\n+\tstruct ice_aqc_suspend_resume_elem *buf;\n+\tu16 i, buf_size, num_elem_ret = 0;\n+\tenum ice_status status;\n+\n+\tbuf_size = sizeof(*buf) * num_nodes;\n+\tbuf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL);\n+\tif (!buf)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tfor (i = 0; i < num_nodes; i++)\n+\t\tbuf->teid[i] = cpu_to_le32(node_teids[i]);\n+\n+\tif (suspend)\n+\t\tstatus = ice_aq_suspend_sched_elems(hw, num_nodes, buf,\n+\t\t\t\t\t\t buf_size, &num_elem_ret,\n+\t\t\t\t\t\t NULL);\n+\telse\n+\t\tstatus = ice_aq_resume_sched_elems(hw, num_nodes, buf,\n+\t\t\t\t\t\t buf_size, &num_elem_ret,\n+\t\t\t\t\t\t NULL);\n+\tif (status || num_elem_ret != num_nodes)\n+\t\tice_debug(hw, ICE_DBG_SCHED, \"suspend/resume failed\\n\");\n+\n+\tdevm_kfree(ice_hw_to_dev(hw), buf);\n+\treturn status;\n+}\n+\n /**\n * ice_sched_clear_tx_topo - clears the schduler tree nodes\n * @pi: port information structure\n@@ -476,6 +620,215 @@ void ice_sched_cleanup_all(struct ice_hw *hw)\n \thw->max_cgds = 0;\n }\n \n+/**\n+ * ice_sched_create_vsi_info_entry - create an empty new VSI entry\n+ * @pi: port information structure\n+ * @vsi_id: VSI Id\n+ *\n+ * This function creates a new VSI entry and adds it to list\n+ */\n+static struct ice_sched_vsi_info *\n+ice_sched_create_vsi_info_entry(struct ice_port_info *pi, u16 vsi_id)\n+{\n+\tstruct ice_sched_vsi_info *vsi_elem;\n+\n+\tif (!pi)\n+\t\treturn NULL;\n+\n+\tvsi_elem = devm_kzalloc(ice_hw_to_dev(pi->hw), sizeof(*vsi_elem),\n+\t\t\t\tGFP_KERNEL);\n+\tif (!vsi_elem)\n+\t\treturn NULL;\n+\n+\tlist_add(&vsi_elem->list_entry, &pi->vsi_info_list);\n+\tvsi_elem->vsi_id = vsi_id;\n+\treturn vsi_elem;\n+}\n+\n+/**\n+ * ice_sched_add_elems - add nodes to hw and SW DB\n+ * @pi: port information structure\n+ * @tc_node: pointer to the branch node\n+ * @parent: pointer to the parent node\n+ * @layer: layer number to add nodes\n+ * @num_nodes: number of nodes\n+ * @num_nodes_added: pointer to num nodes added\n+ * @first_node_teid: if new nodes are added then return the teid of first node\n+ *\n+ * This function add nodes to hw as well as to SW DB for a given layer\n+ */\n+static enum ice_status\n+ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,\n+\t\t struct ice_sched_node *parent, u8 layer, u16 num_nodes,\n+\t\t u16 *num_nodes_added, u32 *first_node_teid)\n+{\n+\tstruct ice_sched_node *prev, *new_node;\n+\tstruct ice_aqc_add_elem *buf;\n+\tu16 i, num_groups_added = 0;\n+\tenum ice_status status = 0;\n+\tstruct ice_hw *hw = pi->hw;\n+\tu16 buf_size;\n+\tu32 teid;\n+\n+\tbuf_size = sizeof(*buf) + sizeof(*buf->generic) * (num_nodes - 1);\n+\tbuf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL);\n+\tif (!buf)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tbuf->hdr.parent_teid = parent->info.node_teid;\n+\tbuf->hdr.num_elems = cpu_to_le16(num_nodes);\n+\tfor (i = 0; i < num_nodes; i++) {\n+\t\tbuf->generic[i].parent_teid = parent->info.node_teid;\n+\t\tbuf->generic[i].data.elem_type = ICE_AQC_ELEM_TYPE_SE_GENERIC;\n+\t\tbuf->generic[i].data.valid_sections =\n+\t\t\tICE_AQC_ELEM_VALID_GENERIC | ICE_AQC_ELEM_VALID_CIR |\n+\t\t\tICE_AQC_ELEM_VALID_EIR;\n+\t\tbuf->generic[i].data.generic = 0;\n+\t\tbuf->generic[i].data.cir_bw.bw_profile_idx =\n+\t\t\tICE_SCHED_DFLT_RL_PROF_ID;\n+\t\tbuf->generic[i].data.eir_bw.bw_profile_idx =\n+\t\t\tICE_SCHED_DFLT_RL_PROF_ID;\n+\t}\n+\n+\tstatus = ice_aq_add_sched_elems(hw, 1, buf, buf_size,\n+\t\t\t\t\t&num_groups_added, NULL);\n+\tif (status || num_groups_added != 1) {\n+\t\tice_debug(hw, ICE_DBG_SCHED, \"add elements failed\\n\");\n+\t\tdevm_kfree(ice_hw_to_dev(hw), buf);\n+\t\treturn ICE_ERR_CFG;\n+\t}\n+\n+\t*num_nodes_added = num_nodes;\n+\t/* add nodes to the SW DB */\n+\tfor (i = 0; i < num_nodes; i++) {\n+\t\tstatus = ice_sched_add_node(pi, layer, &buf->generic[i]);\n+\t\tif (status) {\n+\t\t\tice_debug(hw, ICE_DBG_SCHED,\n+\t\t\t\t \"add nodes in SW DB failed status =%d\\n\",\n+\t\t\t\t status);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tteid = le32_to_cpu(buf->generic[i].node_teid);\n+\t\tnew_node = ice_sched_find_node_by_teid(parent, teid);\n+\n+\t\tif (!new_node) {\n+\t\t\tice_debug(hw, ICE_DBG_SCHED,\n+\t\t\t\t \"Node is missing for teid =%d\\n\", teid);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tnew_node->sibling = NULL;\n+\t\tnew_node->tc_num = tc_node->tc_num;\n+\n+\t\t/* add it to previous node sibling pointer */\n+\t\t/* Note: siblings are not linked across branches */\n+\t\tprev = ice_sched_get_first_node(hw, tc_node, layer);\n+\n+\t\tif (prev && prev != new_node) {\n+\t\t\twhile (prev->sibling)\n+\t\t\t\tprev = prev->sibling;\n+\t\t\tprev->sibling = new_node;\n+\t\t}\n+\n+\t\tif (i == 0)\n+\t\t\t*first_node_teid = teid;\n+\t}\n+\n+\tdevm_kfree(ice_hw_to_dev(hw), buf);\n+\treturn status;\n+}\n+\n+/**\n+ * ice_sched_add_nodes_to_layer - Add nodes to a given layer\n+ * @pi: port information structure\n+ * @tc_node: pointer to TC node\n+ * @parent: pointer to parent node\n+ * @layer: layer number to add nodes\n+ * @num_nodes: number of nodes to be added\n+ * @first_node_teid: pointer to the first node teid\n+ * @num_nodes_added: pointer to number of nodes added\n+ *\n+ * This function add nodes to a given layer.\n+ */\n+static enum ice_status\n+ice_sched_add_nodes_to_layer(struct ice_port_info *pi,\n+\t\t\t struct ice_sched_node *tc_node,\n+\t\t\t struct ice_sched_node *parent, u8 layer,\n+\t\t\t u16 num_nodes, u32 *first_node_teid,\n+\t\t\t u16 *num_nodes_added)\n+{\n+\tu32 *first_teid_ptr = first_node_teid;\n+\tu16 new_num_nodes, max_child_nodes;\n+\tenum ice_status status = 0;\n+\tstruct ice_hw *hw = pi->hw;\n+\tu16 num_added = 0;\n+\tu32 temp;\n+\n+\tif (!num_nodes)\n+\t\treturn status;\n+\n+\tif (!parent || layer < hw->sw_entry_point_layer)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\t*num_nodes_added = 0;\n+\n+\t/* max children per node per layer */\n+\tmax_child_nodes =\n+\t le16_to_cpu(hw->layer_info[parent->tx_sched_layer].max_children);\n+\n+\t/* current number of children + required nodes exceed max children ? */\n+\tif ((parent->num_children + num_nodes) > max_child_nodes) {\n+\t\t/* Fail if the parent is a TC node */\n+\t\tif (parent == tc_node)\n+\t\t\treturn ICE_ERR_CFG;\n+\n+\t\t/* utilize all the spaces if the parent is not full */\n+\t\tif (parent->num_children < max_child_nodes) {\n+\t\t\tnew_num_nodes = max_child_nodes - parent->num_children;\n+\t\t\t/* this recursion is intentional, and wouldn't\n+\t\t\t * go more than 2 calls\n+\t\t\t */\n+\t\t\tstatus = ice_sched_add_nodes_to_layer(pi, tc_node,\n+\t\t\t\t\t\t\t parent, layer,\n+\t\t\t\t\t\t\t new_num_nodes,\n+\t\t\t\t\t\t\t first_node_teid,\n+\t\t\t\t\t\t\t &num_added);\n+\t\t\tif (status)\n+\t\t\t\treturn status;\n+\n+\t\t\t*num_nodes_added += num_added;\n+\t\t}\n+\t\t/* Don't modify the first node teid memory if the first node was\n+\t\t * added already in the above call. Instead send some temp\n+\t\t * memory for all other recursive calls.\n+\t\t */\n+\t\tif (num_added)\n+\t\t\tfirst_teid_ptr = &temp;\n+\n+\t\tnew_num_nodes = num_nodes - num_added;\n+\n+\t\t/* This parent is full, try the next sibling */\n+\t\tparent = parent->sibling;\n+\n+\t\t/* this recursion is intentional, for 1024 queues\n+\t\t * per VSI, it goes max of 16 iterations.\n+\t\t * 1024 / 8 = 128 layer 8 nodes\n+\t\t * 128 /8 = 16 (add 8 nodes per iteration)\n+\t\t */\n+\t\tstatus = ice_sched_add_nodes_to_layer(pi, tc_node, parent,\n+\t\t\t\t\t\t layer, new_num_nodes,\n+\t\t\t\t\t\t first_teid_ptr,\n+\t\t\t\t\t\t &num_added);\n+\t\t*num_nodes_added += num_added;\n+\t\treturn status;\n+\t}\n+\n+\tstatus = ice_sched_add_elems(pi, tc_node, parent, layer, num_nodes,\n+\t\t\t\t num_nodes_added, first_node_teid);\n+\treturn status;\n+}\n+\n /**\n * ice_sched_get_qgrp_layer - get the current queue group layer number\n * @hw: pointer to the hw struct\n@@ -488,6 +841,101 @@ static u8 ice_sched_get_qgrp_layer(struct ice_hw *hw)\n \treturn hw->num_tx_sched_layers - ICE_QGRP_LAYER_OFFSET;\n }\n \n+/**\n+ * ice_sched_get_vsi_layer - get the current VSI layer number\n+ * @hw: pointer to the hw struct\n+ *\n+ * This function returns the current VSI layer number\n+ */\n+static u8 ice_sched_get_vsi_layer(struct ice_hw *hw)\n+{\n+\t/* Num Layers VSI layer\n+\t * 9 6\n+\t * 7 4\n+\t * 5 or less sw_entry_point_layer\n+\t */\n+\t/* calculate the vsi layer based on number of layers. */\n+\tif (hw->num_tx_sched_layers > ICE_VSI_LAYER_OFFSET + 1) {\n+\t\tu8 layer = hw->num_tx_sched_layers - ICE_VSI_LAYER_OFFSET;\n+\n+\t\tif (layer > hw->sw_entry_point_layer)\n+\t\t\treturn layer;\n+\t}\n+\treturn hw->sw_entry_point_layer;\n+}\n+\n+/**\n+ * ice_sched_get_num_nodes_per_layer - Get the total number of nodes per layer\n+ * @pi: pointer to the port info struct\n+ * @layer: layer number\n+ *\n+ * This function calculates the number of nodes present in the scheduler tree\n+ * including all the branches for a given layer\n+ */\n+static u16\n+ice_sched_get_num_nodes_per_layer(struct ice_port_info *pi, u8 layer)\n+{\n+\tstruct ice_hw *hw;\n+\tu16 num_nodes = 0;\n+\tu8 i;\n+\n+\tif (!pi)\n+\t\treturn num_nodes;\n+\n+\thw = pi->hw;\n+\n+\t/* Calculate the number of nodes for all TCs */\n+\tfor (i = 0; i < pi->root->num_children; i++) {\n+\t\tstruct ice_sched_node *tc_node, *node;\n+\n+\t\ttc_node = pi->root->children[i];\n+\n+\t\t/* Get the first node */\n+\t\tnode = ice_sched_get_first_node(hw, tc_node, layer);\n+\t\tif (!node)\n+\t\t\tcontinue;\n+\n+\t\t/* count the siblings */\n+\t\twhile (node) {\n+\t\t\tnum_nodes++;\n+\t\t\tnode = node->sibling;\n+\t\t}\n+\t}\n+\n+\treturn num_nodes;\n+}\n+\n+/**\n+ * ice_sched_val_max_nodes - check max number of nodes reached or not\n+ * @pi: port information structure\n+ * @new_num_nodes_per_layer: pointer to the new number of nodes array\n+ *\n+ * This function checks whether the scheduler tree layers have enough space to\n+ * add new nodes\n+ */\n+static enum ice_status\n+ice_sched_validate_for_max_nodes(struct ice_port_info *pi,\n+\t\t\t\t u16 *new_num_nodes_per_layer)\n+{\n+\tstruct ice_hw *hw = pi->hw;\n+\tu8 i, qg_layer;\n+\tu16 num_nodes;\n+\n+\tqg_layer = ice_sched_get_qgrp_layer(hw);\n+\n+\t/* walk through all the layers from SW entry point to qgroup layer */\n+\tfor (i = hw->sw_entry_point_layer; i <= qg_layer; i++) {\n+\t\tnum_nodes = ice_sched_get_num_nodes_per_layer(pi, i);\n+\t\tif (num_nodes + new_num_nodes_per_layer[i] >\n+\t\t le16_to_cpu(hw->layer_info[i].max_pf_nodes)) {\n+\t\t\tice_debug(hw, ICE_DBG_SCHED,\n+\t\t\t\t \"max nodes reached for layer = %d\\n\", i);\n+\t\t\treturn ICE_ERR_CFG;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n /**\n * ice_rm_dflt_leaf_node - remove the default leaf node in the tree\n * @pi: port information structure\n@@ -530,6 +978,7 @@ ice_sched_rm_dflt_nodes(struct ice_port_info *pi)\n \tstruct ice_sched_node *node;\n \n \tice_rm_dflt_leaf_node(pi);\n+\n \t/* remove the default nodes except TC and root nodes */\n \tnode = pi->root;\n \twhile (node) {\n@@ -539,6 +988,7 @@ ice_sched_rm_dflt_nodes(struct ice_port_info *pi)\n \t\t\tice_free_sched_node(pi, node);\n \t\t\tbreak;\n \t\t}\n+\n \t\tif (!node->num_children)\n \t\t\tbreak;\n \t\tnode = node->children[0];\n@@ -734,8 +1184,10 @@ ice_sched_find_node_in_subtree(struct ice_hw *hw, struct ice_sched_node *base,\n \n \t\tif (node == child)\n \t\t\treturn true;\n+\n \t\tif (child->tx_sched_layer > node->tx_sched_layer)\n \t\t\treturn false;\n+\n \t\t/* this recursion is intentional, and wouldn't\n \t\t * go more than 8 calls\n \t\t */\n@@ -765,13 +1217,17 @@ ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_id, u8 tc,\n \n \tqgrp_layer = ice_sched_get_qgrp_layer(pi->hw);\n \tmax_children = le16_to_cpu(pi->hw->layer_info[qgrp_layer].max_children);\n+\n \tlist_elem = ice_sched_get_vsi_info_entry(pi, vsi_id);\n \tif (!list_elem)\n \t\tgoto lan_q_exit;\n+\n \tvsi_node = list_elem->vsi_node[tc];\n+\n \t/* validate invalid VSI id */\n \tif (!vsi_node)\n \t\tgoto lan_q_exit;\n+\n \t/* get the first q group node from VSI sub-tree */\n \tqgrp_node = ice_sched_get_first_node(pi->hw, vsi_node, qgrp_layer);\n \twhile (qgrp_node) {\n@@ -782,6 +1238,436 @@ ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_id, u8 tc,\n \t\t\t\tbreak;\n \t\tqgrp_node = qgrp_node->sibling;\n \t}\n+\n lan_q_exit:\n \treturn qgrp_node;\n }\n+\n+/**\n+ * ice_sched_get_vsi_node - Get a VSI node based on VSI id\n+ * @hw: pointer to the hw struct\n+ * @tc_node: pointer to the TC node\n+ * @vsi_id: VSI id\n+ *\n+ * This function retrieves a VSI node for a given VSI id from a given\n+ * TC branch\n+ */\n+static struct ice_sched_node *\n+ice_sched_get_vsi_node(struct ice_hw *hw, struct ice_sched_node *tc_node,\n+\t\t u16 vsi_id)\n+{\n+\tstruct ice_sched_node *node;\n+\tu8 vsi_layer;\n+\n+\tvsi_layer = ice_sched_get_vsi_layer(hw);\n+\tnode = ice_sched_get_first_node(hw, tc_node, vsi_layer);\n+\n+\t/* Check whether it already exists */\n+\twhile (node) {\n+\t\tif (node->vsi_id == vsi_id)\n+\t\t\treturn node;\n+\t\tnode = node->sibling;\n+\t}\n+\n+\treturn node;\n+}\n+\n+/**\n+ * ice_sched_calc_vsi_child_nodes - calculate number of VSI child nodes\n+ * @hw: pointer to the hw struct\n+ * @num_qs: number of queues\n+ * @num_nodes: num nodes array\n+ *\n+ * This function calculates the number of VSI child nodes based on the\n+ * number of queues.\n+ */\n+static void\n+ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes)\n+{\n+\tu16 num = num_qs;\n+\tu8 i, qgl, vsil;\n+\n+\tqgl = ice_sched_get_qgrp_layer(hw);\n+\tvsil = ice_sched_get_vsi_layer(hw);\n+\n+\t/* calculate num nodes from q group to VSI layer */\n+\tfor (i = qgl; i > vsil; i--) {\n+\t\tu16 max_children = le16_to_cpu(hw->layer_info[i].max_children);\n+\n+\t\t/* round to the next integer if there is a remainder */\n+\t\tnum = DIV_ROUND_UP(num, max_children);\n+\n+\t\t/* need at least one node */\n+\t\tnum_nodes[i] = num ? num : 1;\n+\t}\n+}\n+\n+/**\n+ * ice_sched_add_vsi_child_nodes - add VSI child nodes to tree\n+ * @pi: port information structure\n+ * @vsi_id: VSI id\n+ * @tc_node: pointer to the TC node\n+ * @num_nodes: pointer to the num nodes that needs to be added per layer\n+ * @owner: node owner (lan or rdma)\n+ *\n+ * This function adds the VSI child nodes to tree. It gets called for\n+ * lan and rdma separately.\n+ */\n+static enum ice_status\n+ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id,\n+\t\t\t struct ice_sched_node *tc_node, u16 *num_nodes,\n+\t\t\t u8 owner)\n+{\n+\tstruct ice_sched_node *parent, *node;\n+\tstruct ice_hw *hw = pi->hw;\n+\tenum ice_status status;\n+\tu32 first_node_teid;\n+\tu16 num_added = 0;\n+\tu8 i, qgl, vsil;\n+\n+\tstatus = ice_sched_validate_for_max_nodes(pi, num_nodes);\n+\tif (status)\n+\t\treturn status;\n+\n+\tqgl = ice_sched_get_qgrp_layer(hw);\n+\tvsil = ice_sched_get_vsi_layer(hw);\n+\tparent = ice_sched_get_vsi_node(hw, tc_node, vsi_id);\n+\tfor (i = vsil + 1; i <= qgl; i++) {\n+\t\tif (!parent)\n+\t\t\treturn ICE_ERR_CFG;\n+\t\tstatus = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,\n+\t\t\t\t\t\t num_nodes[i],\n+\t\t\t\t\t\t &first_node_teid,\n+\t\t\t\t\t\t &num_added);\n+\t\tif (status || num_nodes[i] != num_added)\n+\t\t\treturn ICE_ERR_CFG;\n+\n+\t\t/* The newly added node can be a new parent for the next\n+\t\t * layer nodes\n+\t\t */\n+\t\tif (num_added) {\n+\t\t\tparent = ice_sched_find_node_by_teid(tc_node,\n+\t\t\t\t\t\t\t first_node_teid);\n+\t\t\tnode = parent;\n+\t\t\twhile (node) {\n+\t\t\t\tnode->owner = owner;\n+\t\t\t\tnode = node->sibling;\n+\t\t\t}\n+\t\t} else {\n+\t\t\tparent = parent->children[0];\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_sched_rm_vsi_child_nodes - remove VSI child nodes from the tree\n+ * @pi: port information structure\n+ * @vsi_node: pointer to the VSI node\n+ * @num_nodes: pointer to the num nodes that needs to be removed per layer\n+ * @owner: node owner (lan or rdma)\n+ *\n+ * This function removes the VSI child nodes from the tree. It gets called for\n+ * lan and rdma separately.\n+ */\n+static void\n+ice_sched_rm_vsi_child_nodes(struct ice_port_info *pi,\n+\t\t\t struct ice_sched_node *vsi_node, u16 *num_nodes,\n+\t\t\t u8 owner)\n+{\n+\tstruct ice_sched_node *node, *next;\n+\tu8 i, qgl, vsil;\n+\tu16 num;\n+\n+\tqgl = ice_sched_get_qgrp_layer(pi->hw);\n+\tvsil = ice_sched_get_vsi_layer(pi->hw);\n+\n+\tfor (i = qgl; i > vsil; i--) {\n+\t\tnum = num_nodes[i];\n+\t\tnode = ice_sched_get_first_node(pi->hw, vsi_node, i);\n+\t\twhile (node && num) {\n+\t\t\tnext = node->sibling;\n+\t\t\tif (node->owner == owner && !node->num_children) {\n+\t\t\t\tice_free_sched_node(pi, node);\n+\t\t\t\tnum--;\n+\t\t\t}\n+\t\t\tnode = next;\n+\t\t}\n+\t}\n+}\n+\n+/**\n+ * ice_sched_calc_vsi_support_nodes - calculate number of VSI support nodes\n+ * @hw: pointer to the hw struct\n+ * @tc_node: pointer to TC node\n+ * @num_nodes: pointer to num nodes array\n+ *\n+ * This function calculates the number of supported nodes needed to add this\n+ * VSI into tx tree including the VSI, parent and intermediate nodes in below\n+ * layers\n+ */\n+static void\n+ice_sched_calc_vsi_support_nodes(struct ice_hw *hw,\n+\t\t\t\t struct ice_sched_node *tc_node, u16 *num_nodes)\n+{\n+\tstruct ice_sched_node *node;\n+\tu16 max_child;\n+\tu8 i, vsil;\n+\n+\tvsil = ice_sched_get_vsi_layer(hw);\n+\tfor (i = vsil; i >= hw->sw_entry_point_layer; i--)\n+\t\t/* Add intermediate nodes if TC has no children and\n+\t\t * need at least one node for VSI\n+\t\t */\n+\t\tif (!tc_node->num_children || i == vsil) {\n+\t\t\tnum_nodes[i]++;\n+\t\t} else {\n+\t\t\t/* If intermediate nodes are reached max children\n+\t\t\t * then add a new one.\n+\t\t\t */\n+\t\t\tnode = ice_sched_get_first_node(hw, tc_node, i);\n+\t\t\tmax_child = le16_to_cpu(hw->layer_info[i].max_children);\n+\n+\t\t\t/* scan all the siblings */\n+\t\t\twhile (node) {\n+\t\t\t\tif (node->num_children < max_child)\n+\t\t\t\t\tbreak;\n+\t\t\t\tnode = node->sibling;\n+\t\t\t}\n+\n+\t\t\t/* all the nodes are full, allocate a new one */\n+\t\t\tif (!node)\n+\t\t\t\tnum_nodes[i]++;\n+\t\t}\n+}\n+\n+/**\n+ * ice_sched_add_vsi_support_nodes - add VSI supported nodes into tx tree\n+ * @pi: port information structure\n+ * @vsi_id: VSI Id\n+ * @tc_node: pointer to TC node\n+ * @num_nodes: pointer to num nodes array\n+ *\n+ * This function adds the VSI supported nodes into tx tree including the\n+ * VSI, its parent and intermediate nodes in below layers\n+ */\n+static enum ice_status\n+ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_id,\n+\t\t\t\tstruct ice_sched_node *tc_node, u16 *num_nodes)\n+{\n+\tstruct ice_sched_node *parent = tc_node;\n+\tenum ice_status status;\n+\tu32 first_node_teid;\n+\tu16 num_added = 0;\n+\tu8 i, vsil;\n+\n+\tif (!pi)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tstatus = ice_sched_validate_for_max_nodes(pi, num_nodes);\n+\tif (status)\n+\t\treturn status;\n+\n+\tvsil = ice_sched_get_vsi_layer(pi->hw);\n+\tfor (i = pi->hw->sw_entry_point_layer; i <= vsil; i++) {\n+\t\tstatus = ice_sched_add_nodes_to_layer(pi, tc_node, parent,\n+\t\t\t\t\t\t i, num_nodes[i],\n+\t\t\t\t\t\t &first_node_teid,\n+\t\t\t\t\t\t &num_added);\n+\t\tif (status || num_nodes[i] != num_added)\n+\t\t\treturn ICE_ERR_CFG;\n+\n+\t\t/* The newly added node can be a new parent for the next\n+\t\t * layer nodes\n+\t\t */\n+\t\tif (num_added)\n+\t\t\tparent = ice_sched_find_node_by_teid(tc_node,\n+\t\t\t\t\t\t\t first_node_teid);\n+\t\telse\n+\t\t\tparent = parent->children[0];\n+\n+\t\tif (!parent)\n+\t\t\treturn ICE_ERR_CFG;\n+\n+\t\tif (i == vsil)\n+\t\t\tparent->vsi_id = vsi_id;\n+\t}\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_sched_add_vsi_to_topo - add a new VSI into tree\n+ * @pi: port information structure\n+ * @vsi_id: VSI Id\n+ * @tc: TC number\n+ *\n+ * This function adds a new VSI into scheduler tree\n+ */\n+static enum ice_status\n+ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_id, u8 tc)\n+{\n+\tu16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };\n+\tstruct ice_sched_node *tc_node;\n+\tstruct ice_hw *hw = pi->hw;\n+\n+\ttc_node = ice_sched_get_tc_node(pi, tc);\n+\tif (!tc_node)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\t/* calculate number of supported nodes needed for this VSI */\n+\tice_sched_calc_vsi_support_nodes(hw, tc_node, num_nodes);\n+\n+\t/* add vsi supported nodes to tc subtree */\n+\treturn ice_sched_add_vsi_support_nodes(pi, vsi_id, tc_node, num_nodes);\n+}\n+\n+/**\n+ * ice_sched_update_vsi_child_nodes - update VSI child nodes\n+ * @pi: port information structure\n+ * @vsi_id: VSI Id\n+ * @tc: TC number\n+ * @new_numqs: new number of max queues\n+ * @owner: owner of this subtree\n+ *\n+ * This function updates the VSI child nodes based on the number of queues\n+ */\n+static enum ice_status\n+ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_id, u8 tc,\n+\t\t\t\t u16 new_numqs, u8 owner)\n+{\n+\tu16 prev_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };\n+\tu16 new_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };\n+\tstruct ice_sched_node *vsi_node;\n+\tstruct ice_sched_node *tc_node;\n+\tstruct ice_sched_vsi_info *vsi;\n+\tenum ice_status status = 0;\n+\tstruct ice_hw *hw = pi->hw;\n+\tu16 prev_numqs;\n+\tu8 i;\n+\n+\ttc_node = ice_sched_get_tc_node(pi, tc);\n+\tif (!tc_node)\n+\t\treturn ICE_ERR_CFG;\n+\n+\tvsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id);\n+\tif (!vsi_node)\n+\t\treturn ICE_ERR_CFG;\n+\n+\tvsi = ice_sched_get_vsi_info_entry(pi, vsi_id);\n+\tif (!vsi)\n+\t\treturn ICE_ERR_CFG;\n+\n+\tif (owner == ICE_SCHED_NODE_OWNER_LAN)\n+\t\tprev_numqs = vsi->max_lanq[tc];\n+\telse\n+\t\treturn ICE_ERR_PARAM;\n+\n+\t/* num queues are not changed */\n+\tif (prev_numqs == new_numqs)\n+\t\treturn status;\n+\n+\t/* calculate number of nodes based on prev/new number of qs */\n+\tif (prev_numqs)\n+\t\tice_sched_calc_vsi_child_nodes(hw, prev_numqs, prev_num_nodes);\n+\n+\tif (new_numqs)\n+\t\tice_sched_calc_vsi_child_nodes(hw, new_numqs, new_num_nodes);\n+\n+\tif (prev_numqs > new_numqs) {\n+\t\tfor (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++)\n+\t\t\tnew_num_nodes[i] = prev_num_nodes[i] - new_num_nodes[i];\n+\n+\t\tice_sched_rm_vsi_child_nodes(pi, vsi_node, new_num_nodes,\n+\t\t\t\t\t owner);\n+\t} else {\n+\t\tfor (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++)\n+\t\t\tnew_num_nodes[i] -= prev_num_nodes[i];\n+\n+\t\tstatus = ice_sched_add_vsi_child_nodes(pi, vsi_id, tc_node,\n+\t\t\t\t\t\t new_num_nodes, owner);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\n+\tif (owner == ICE_SCHED_NODE_OWNER_LAN)\n+\t\tvsi->max_lanq[tc] = new_numqs;\n+\n+\treturn status;\n+}\n+\n+/**\n+ * ice_sched_cfg_vsi - configure the new/exisiting VSI\n+ * @pi: port information structure\n+ * @vsi_id: VSI Id\n+ * @tc: TC number\n+ * @maxqs: max number of queues\n+ * @owner: lan or rdma\n+ * @enable: TC enabled or disabled\n+ *\n+ * This function adds/updates VSI nodes based on the number of queues. If TC is\n+ * enabled and VSI is in suspended state then resume the VSI back. If TC is\n+ * disabled then suspend the VSI if it is not already.\n+ */\n+enum ice_status\n+ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs,\n+\t\t u8 owner, bool enable)\n+{\n+\tstruct ice_sched_node *vsi_node, *tc_node;\n+\tstruct ice_sched_vsi_info *vsi;\n+\tenum ice_status status = 0;\n+\tstruct ice_hw *hw = pi->hw;\n+\n+\ttc_node = ice_sched_get_tc_node(pi, tc);\n+\tif (!tc_node)\n+\t\treturn ICE_ERR_PARAM;\n+\n+\tvsi = ice_sched_get_vsi_info_entry(pi, vsi_id);\n+\tif (!vsi)\n+\t\tvsi = ice_sched_create_vsi_info_entry(pi, vsi_id);\n+\tif (!vsi)\n+\t\treturn ICE_ERR_NO_MEMORY;\n+\n+\tvsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id);\n+\n+\t/* suspend the VSI if tc is not enabled */\n+\tif (!enable) {\n+\t\tif (vsi_node && vsi_node->in_use) {\n+\t\t\tu32 teid = le32_to_cpu(vsi_node->info.node_teid);\n+\n+\t\t\tstatus = ice_sched_suspend_resume_elems(hw, 1, &teid,\n+\t\t\t\t\t\t\t\ttrue);\n+\t\t\tif (!status)\n+\t\t\t\tvsi_node->in_use = false;\n+\t\t}\n+\t\treturn status;\n+\t}\n+\n+\t/* TC is enabled, if it is a new VSI then add it to the tree */\n+\tif (!vsi_node) {\n+\t\tstatus = ice_sched_add_vsi_to_topo(pi, vsi_id, tc);\n+\t\tif (status)\n+\t\t\treturn status;\n+\t\tvsi_node = ice_sched_get_vsi_node(hw, tc_node, vsi_id);\n+\t\tif (!vsi_node)\n+\t\t\treturn ICE_ERR_CFG;\n+\t\tvsi->vsi_node[tc] = vsi_node;\n+\t\tvsi_node->in_use = true;\n+\t}\n+\n+\t/* update the VSI child nodes */\n+\tstatus = ice_sched_update_vsi_child_nodes(pi, vsi_id, tc, maxqs, owner);\n+\tif (status)\n+\t\treturn status;\n+\n+\t/* TC is enabled, resume the VSI if it is in the suspend state */\n+\tif (!vsi_node->in_use) {\n+\t\tu32 teid = le32_to_cpu(vsi_node->info.node_teid);\n+\n+\t\tstatus = ice_sched_suspend_resume_elems(hw, 1, &teid, false);\n+\t\tif (!status)\n+\t\t\tvsi_node->in_use = true;\n+\t}\n+\n+\treturn status;\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_sched.h b/drivers/net/ethernet/intel/ice/ice_sched.h\nindex a3a9fc14603a..a17ca145c8bc 100644\n--- a/drivers/net/ethernet/intel/ice/ice_sched.h\n+++ b/drivers/net/ethernet/intel/ice/ice_sched.h\n@@ -21,6 +21,7 @@\n #include \"ice_common.h\"\n \n #define ICE_QGRP_LAYER_OFFSET\t2\n+#define ICE_VSI_LAYER_OFFSET\t4\n \n struct ice_sched_agg_vsi_info {\n \tstruct list_head list_entry;\n@@ -50,4 +51,7 @@ struct ice_sched_node *ice_sched_get_tc_node(struct ice_port_info *pi, u8 tc);\n struct ice_sched_node *\n ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_id, u8 tc,\n \t\t\t u8 owner);\n+enum ice_status\n+ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_id, u8 tc, u16 maxqs,\n+\t\t u8 owner, bool enable);\n #endif /* _ICE_SCHED_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h\nindex a576d173b07d..ce091e83b60a 100644\n--- a/drivers/net/ethernet/intel/ice/ice_type.h\n+++ b/drivers/net/ethernet/intel/ice/ice_type.h\n@@ -24,6 +24,11 @@\n #include \"ice_controlq.h\"\n #include \"ice_lan_tx_rx.h\"\n \n+static inline bool ice_is_tc_ena(u8 bitmap, u8 tc)\n+{\n+\treturn test_bit(tc, (unsigned long *)&bitmap);\n+}\n+\n /* debug masks - set these bits in hw->debug_mask to control output */\n #define ICE_DBG_INIT\t\tBIT_ULL(1)\n #define ICE_DBG_QCTX\t\tBIT_ULL(6)\n@@ -208,6 +213,8 @@ enum ice_agg_type {\n \tICE_AGG_TYPE_QG\n };\n \n+#define ICE_SCHED_DFLT_RL_PROF_ID\t0\n+\n /* vsi type list entry to locate corresponding vsi/ag nodes */\n struct ice_sched_vsi_info {\n \tstruct ice_sched_node *vsi_node[ICE_MAX_TRAFFIC_CLASS];\n", "prefixes": [ "v2", "13/15" ] }