get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 90322,
    "url": "https://patches.dpdk.org/api/patches/90322/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20210401094739.22714-34-ndabilpuram@marvell.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20210401094739.22714-34-ndabilpuram@marvell.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210401094739.22714-34-ndabilpuram@marvell.com",
    "date": "2021-04-01T09:47:20",
    "name": "[v2,33/52] common/cnxk: add nix tm support to add/delete node",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "dc67dc079307fef0c7910d2cd2a7c6eff2bbee1e",
    "submitter": {
        "id": 1202,
        "url": "https://patches.dpdk.org/api/people/1202/?format=api",
        "name": "Nithin Dabilpuram",
        "email": "ndabilpuram@marvell.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20210401094739.22714-34-ndabilpuram@marvell.com/mbox/",
    "series": [
        {
            "id": 16050,
            "url": "https://patches.dpdk.org/api/series/16050/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=16050",
            "date": "2021-04-01T09:46:47",
            "name": "Add Marvell CNXK common driver",
            "version": 2,
            "mbox": "https://patches.dpdk.org/series/16050/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/90322/comments/",
    "check": "success",
    "checks": "https://patches.dpdk.org/api/patches/90322/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 2EE73A0548;\n\tThu,  1 Apr 2021 11:52:34 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 10F07140F30;\n\tThu,  1 Apr 2021 11:49:49 +0200 (CEST)",
            "from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com\n [67.231.148.174])\n by mails.dpdk.org (Postfix) with ESMTP id 80CBE140F30\n for <dev@dpdk.org>; Thu,  1 Apr 2021 11:49:47 +0200 (CEST)",
            "from pps.filterd (m0045849.ppops.net [127.0.0.1])\n by mx0a-0016f401.pphosted.com (8.16.0.43/8.16.0.43) with SMTP id\n 1319fTtv015004 for <dev@dpdk.org>; Thu, 1 Apr 2021 02:49:46 -0700",
            "from dc5-exch01.marvell.com ([199.233.59.181])\n by mx0a-0016f401.pphosted.com with ESMTP id 37n28j1wyk-1\n (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT)\n for <dev@dpdk.org>; Thu, 01 Apr 2021 02:49:46 -0700",
            "from DC5-EXCH01.marvell.com (10.69.176.38) by DC5-EXCH01.marvell.com\n (10.69.176.38) with Microsoft SMTP Server (TLS) id 15.0.1497.2;\n Thu, 1 Apr 2021 02:49:45 -0700",
            "from maili.marvell.com (10.69.176.80) by DC5-EXCH01.marvell.com\n (10.69.176.38) with Microsoft SMTP Server id 15.0.1497.2 via Frontend\n Transport; Thu, 1 Apr 2021 02:49:44 -0700",
            "from hyd1588t430.marvell.com (unknown [10.29.52.204])\n by maili.marvell.com (Postfix) with ESMTP id 32B173F703F;\n Thu,  1 Apr 2021 02:49:41 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com;\n h=from : to : cc :\n subject : date : message-id : in-reply-to : references : mime-version :\n content-type; s=pfpt0220; bh=ZEbVdbOQLp8Do/ND9OHe8l72F4tvj5oQ2y5zkJHiPoI=;\n b=Jjq432ujJjQgcrkxCtgKuIeJAklr4hE5LOYsL0V2fsGRAbLSH+7g/b72zVdQdW9qMiZO\n 9fm6kKaDT9xgmaM3yE/j1KirQm1M17LzGpwLitsLWKzIBsFkzbIPp9XAuwVfDeQ872dm\n 7XokWJoAwe80dFpCNVqGMi4cGAG9zVA+BHh8KON7YLi99OrKoJXp3akQwfFTsS+T4npc\n 7tX1XharzckeOM6sJ1P9t1AsUy7jJ9CheLxsn7+UoOxofmfNw7mMrM2d/gva1FKgiVcv\n e7IbaZiRh7QimU/XeRG5MSm5VjfzbhvaEna3egM2xJQmzoCPN815ZWoWR5YSsA4Id/An eQ==",
        "From": "Nithin Dabilpuram <ndabilpuram@marvell.com>",
        "To": "<dev@dpdk.org>",
        "CC": "<jerinj@marvell.com>, <skori@marvell.com>, <skoteshwar@marvell.com>,\n <pbhagavatula@marvell.com>, <kirankumark@marvell.com>,\n <psatheesh@marvell.com>, <asekhar@marvell.com>, Nithin Dabilpuram\n <ndabilpuram@marvell.com>",
        "Date": "Thu, 1 Apr 2021 15:17:20 +0530",
        "Message-ID": "<20210401094739.22714-34-ndabilpuram@marvell.com>",
        "X-Mailer": "git-send-email 2.8.4",
        "In-Reply-To": "<20210401094739.22714-1-ndabilpuram@marvell.com>",
        "References": "<20210305133918.8005-1-ndabilpuram@marvell.com>\n <20210401094739.22714-1-ndabilpuram@marvell.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Proofpoint-ORIG-GUID": "smrCJUjvjNWoVmgGty6HnOzqNSAgzhSY",
        "X-Proofpoint-GUID": "smrCJUjvjNWoVmgGty6HnOzqNSAgzhSY",
        "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10434:6.0.369, 18.0.761\n definitions=2021-04-01_04:2021-03-31,\n 2021-04-01 signatures=0",
        "Subject": "[dpdk-dev] [PATCH v2 33/52] common/cnxk: add nix tm support to\n add/delete node",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Add support to add/delete nodes in a hierarchy.\nThis patch also adds misc utils to get node name,\nwalk through nodes etc.\n\nSigned-off-by: Nithin Dabilpuram <ndabilpuram@marvell.com>\nSigned-off-by: Satha Rao <skoteshwar@marvell.com>\n---\n drivers/common/cnxk/roc_nix.h          |  42 +++++++\n drivers/common/cnxk/roc_nix_priv.h     |  14 +++\n drivers/common/cnxk/roc_nix_tm.c       | 205 +++++++++++++++++++++++++++++++\n drivers/common/cnxk/roc_nix_tm_ops.c   |  88 ++++++++++++++\n drivers/common/cnxk/roc_nix_tm_utils.c | 212 +++++++++++++++++++++++++++++++++\n drivers/common/cnxk/version.map        |   7 ++\n 6 files changed, 568 insertions(+)",
    "diff": "diff --git a/drivers/common/cnxk/roc_nix.h b/drivers/common/cnxk/roc_nix.h\nindex 1ad0e72..d656909 100644\n--- a/drivers/common/cnxk/roc_nix.h\n+++ b/drivers/common/cnxk/roc_nix.h\n@@ -307,6 +307,8 @@ void __roc_api roc_nix_unregister_cq_irqs(struct roc_nix *roc_nix);\n \n /* Traffic Management */\n #define ROC_NIX_TM_MAX_SCHED_WT\t       ((uint8_t)~0)\n+#define ROC_NIX_TM_SHAPER_PROFILE_NONE UINT32_MAX\n+#define ROC_NIX_TM_NODE_ID_INVALID     UINT32_MAX\n \n enum roc_nix_tm_tree {\n \tROC_NIX_TM_DEFAULT = 0,\n@@ -331,6 +333,46 @@ enum roc_tm_node_level {\n int __roc_api roc_nix_tm_sq_aura_fc(struct roc_nix_sq *sq, bool enable);\n int __roc_api roc_nix_tm_sq_flush_spin(struct roc_nix_sq *sq);\n \n+/*\n+ * TM User hierarchy API.\n+ */\n+\n+struct roc_nix_tm_node {\n+#define ROC_NIX_TM_NODE_SZ (128)\n+\tuint8_t reserved[ROC_NIX_TM_NODE_SZ];\n+\n+\tuint32_t id;\n+\tuint32_t parent_id;\n+\tuint32_t priority;\n+\tuint32_t weight;\n+\tuint32_t shaper_profile_id;\n+\tuint16_t lvl;\n+\tbool pkt_mode;\n+\tbool pkt_mode_set;\n+\t/* Function to free this memory */\n+\tvoid (*free_fn)(void *node);\n+};\n+\n+int __roc_api roc_nix_tm_node_add(struct roc_nix *roc_nix,\n+\t\t\t\t  struct roc_nix_tm_node *roc_node);\n+int __roc_api roc_nix_tm_node_delete(struct roc_nix *roc_nix, uint32_t node_id,\n+\t\t\t\t     bool free);\n+int __roc_api roc_nix_tm_node_pkt_mode_update(struct roc_nix *roc_nix,\n+\t\t\t\t\t      uint32_t node_id, bool pkt_mode);\n+\n+struct roc_nix_tm_node *__roc_api roc_nix_tm_node_get(struct roc_nix *roc_nix,\n+\t\t\t\t\t\t      uint32_t node_id);\n+struct roc_nix_tm_node *__roc_api\n+roc_nix_tm_node_next(struct roc_nix *roc_nix, struct roc_nix_tm_node *__prev);\n+\n+/*\n+ * TM utilities API.\n+ */\n+int __roc_api roc_nix_tm_node_lvl(struct roc_nix *roc_nix, uint32_t node_id);\n+int __roc_api roc_nix_tm_node_name_get(struct roc_nix *roc_nix,\n+\t\t\t\t       uint32_t node_id, char *buf,\n+\t\t\t\t       size_t buflen);\n+\n /* MAC */\n int __roc_api roc_nix_mac_rxtx_start_stop(struct roc_nix *roc_nix, bool start);\n int __roc_api roc_nix_mac_link_event_start_stop(struct roc_nix *roc_nix,\ndiff --git a/drivers/common/cnxk/roc_nix_priv.h b/drivers/common/cnxk/roc_nix_priv.h\nindex edc3ff1..3b11090 100644\n--- a/drivers/common/cnxk/roc_nix_priv.h\n+++ b/drivers/common/cnxk/roc_nix_priv.h\n@@ -326,14 +326,28 @@ int nix_tm_leaf_data_get(struct nix *nix, uint16_t sq, uint32_t *rr_quantum,\n int nix_tm_sq_flush_pre(struct roc_nix_sq *sq);\n int nix_tm_sq_flush_post(struct roc_nix_sq *sq);\n int nix_tm_smq_xoff(struct nix *nix, struct nix_tm_node *node, bool enable);\n+int nix_tm_node_add(struct roc_nix *roc_nix, struct nix_tm_node *node);\n+int nix_tm_node_delete(struct roc_nix *roc_nix, uint32_t node_id,\n+\t\t       enum roc_nix_tm_tree tree, bool free);\n+int nix_tm_free_node_resource(struct nix *nix, struct nix_tm_node *node);\n int nix_tm_clear_path_xoff(struct nix *nix, struct nix_tm_node *node);\n \n /*\n  * TM priv utils.\n  */\n+uint16_t nix_tm_lvl2nix(struct nix *nix, uint32_t lvl);\n+uint16_t nix_tm_lvl2nix_tl1_root(uint32_t lvl);\n+uint16_t nix_tm_lvl2nix_tl2_root(uint32_t lvl);\n+uint16_t nix_tm_resource_avail(struct nix *nix, uint8_t hw_lvl, bool contig);\n+int nix_tm_validate_prio(struct nix *nix, uint32_t lvl, uint32_t parent_id,\n+\t\t\t uint32_t priority, enum roc_nix_tm_tree tree);\n struct nix_tm_node *nix_tm_node_search(struct nix *nix, uint32_t node_id,\n \t\t\t\t       enum roc_nix_tm_tree tree);\n+struct nix_tm_shaper_profile *nix_tm_shaper_profile_search(struct nix *nix,\n+\t\t\t\t\t\t\t   uint32_t id);\n uint8_t nix_tm_sw_xoff_prep(struct nix_tm_node *node, bool enable,\n \t\t\t    volatile uint64_t *reg, volatile uint64_t *regval);\n+struct nix_tm_node *nix_tm_node_alloc(void);\n+void nix_tm_node_free(struct nix_tm_node *node);\n \n #endif /* _ROC_NIX_PRIV_H_ */\ndiff --git a/drivers/common/cnxk/roc_nix_tm.c b/drivers/common/cnxk/roc_nix_tm.c\nindex 4cafc0f..f103e02 100644\n--- a/drivers/common/cnxk/roc_nix_tm.c\n+++ b/drivers/common/cnxk/roc_nix_tm.c\n@@ -5,6 +5,100 @@\n #include \"roc_api.h\"\n #include \"roc_priv.h\"\n \n+int\n+nix_tm_node_add(struct roc_nix *roc_nix, struct nix_tm_node *node)\n+{\n+\tstruct nix *nix = roc_nix_to_nix_priv(roc_nix);\n+\tstruct nix_tm_shaper_profile *profile;\n+\tuint32_t node_id, parent_id, lvl;\n+\tstruct nix_tm_node *parent_node;\n+\tuint32_t priority, profile_id;\n+\tuint8_t hw_lvl, exp_next_lvl;\n+\tenum roc_nix_tm_tree tree;\n+\tint rc;\n+\n+\tnode_id = node->id;\n+\tpriority = node->priority;\n+\tparent_id = node->parent_id;\n+\tprofile_id = node->shaper_profile_id;\n+\tlvl = node->lvl;\n+\ttree = node->tree;\n+\n+\tplt_tm_dbg(\"Add node %s lvl %u id %u, prio 0x%x weight 0x%x \"\n+\t\t   \"parent %u profile 0x%x tree %u\",\n+\t\t   nix_tm_hwlvl2str(nix_tm_lvl2nix(nix, lvl)), lvl, node_id,\n+\t\t   priority, node->weight, parent_id, profile_id, tree);\n+\n+\tif (tree >= ROC_NIX_TM_TREE_MAX)\n+\t\treturn NIX_ERR_PARAM;\n+\n+\t/* Translate sw level id's to nix hw level id's */\n+\thw_lvl = nix_tm_lvl2nix(nix, lvl);\n+\tif (hw_lvl == NIX_TXSCH_LVL_CNT && !nix_tm_is_leaf(nix, lvl))\n+\t\treturn NIX_ERR_TM_INVALID_LVL;\n+\n+\t/* Leaf nodes have to be same priority */\n+\tif (nix_tm_is_leaf(nix, lvl) && priority != 0)\n+\t\treturn NIX_ERR_TM_INVALID_PRIO;\n+\n+\tparent_node = nix_tm_node_search(nix, parent_id, tree);\n+\n+\tif (node_id < nix->nb_tx_queues)\n+\t\texp_next_lvl = NIX_TXSCH_LVL_SMQ;\n+\telse\n+\t\texp_next_lvl = hw_lvl + 1;\n+\n+\t/* Check if there is no parent node yet */\n+\tif (hw_lvl != nix->tm_root_lvl &&\n+\t    (!parent_node || parent_node->hw_lvl != exp_next_lvl))\n+\t\treturn NIX_ERR_TM_INVALID_PARENT;\n+\n+\t/* Check if a node already exists */\n+\tif (nix_tm_node_search(nix, node_id, tree))\n+\t\treturn NIX_ERR_TM_NODE_EXISTS;\n+\n+\tprofile = nix_tm_shaper_profile_search(nix, profile_id);\n+\tif (!nix_tm_is_leaf(nix, lvl)) {\n+\t\t/* Check if shaper profile exists for non leaf node */\n+\t\tif (!profile && profile_id != ROC_NIX_TM_SHAPER_PROFILE_NONE)\n+\t\t\treturn NIX_ERR_TM_INVALID_SHAPER_PROFILE;\n+\n+\t\t/* Packet mode in profile should match with that of tm node */\n+\t\tif (profile && profile->pkt_mode != node->pkt_mode)\n+\t\t\treturn NIX_ERR_TM_PKT_MODE_MISMATCH;\n+\t}\n+\n+\t/* Check if there is second DWRR already in siblings or holes in prio */\n+\trc = nix_tm_validate_prio(nix, lvl, parent_id, priority, tree);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\tif (node->weight > ROC_NIX_TM_MAX_SCHED_WT)\n+\t\treturn NIX_ERR_TM_WEIGHT_EXCEED;\n+\n+\t/* Maintain minimum weight */\n+\tif (!node->weight)\n+\t\tnode->weight = 1;\n+\n+\tnode->hw_lvl = nix_tm_lvl2nix(nix, lvl);\n+\tnode->rr_prio = 0xF;\n+\tnode->max_prio = UINT32_MAX;\n+\tnode->hw_id = NIX_TM_HW_ID_INVALID;\n+\tnode->flags = 0;\n+\n+\tif (profile)\n+\t\tprofile->ref_cnt++;\n+\n+\tnode->parent = parent_node;\n+\tif (parent_node)\n+\t\tparent_node->child_realloc = true;\n+\tnode->parent_hw_id = NIX_TM_HW_ID_INVALID;\n+\n+\tTAILQ_INSERT_TAIL(&nix->trees[tree], node, node);\n+\tplt_tm_dbg(\"Added node %s lvl %u id %u (%p)\",\n+\t\t   nix_tm_hwlvl2str(node->hw_lvl), lvl, node_id, node);\n+\treturn 0;\n+}\n \n int\n nix_tm_clear_path_xoff(struct nix *nix, struct nix_tm_node *node)\n@@ -321,6 +415,115 @@ nix_tm_sq_flush_post(struct roc_nix_sq *sq)\n }\n \n int\n+nix_tm_free_node_resource(struct nix *nix, struct nix_tm_node *node)\n+{\n+\tstruct mbox *mbox = (&nix->dev)->mbox;\n+\tstruct nix_txsch_free_req *req;\n+\tstruct plt_bitmap *bmp;\n+\tuint16_t avail, hw_id;\n+\tuint8_t hw_lvl;\n+\tint rc = -ENOSPC;\n+\n+\thw_lvl = node->hw_lvl;\n+\thw_id = node->hw_id;\n+\tbmp = nix->schq_bmp[hw_lvl];\n+\t/* Free specific HW resource */\n+\tplt_tm_dbg(\"Free hwres %s(%u) lvl %u id %u (%p)\",\n+\t\t   nix_tm_hwlvl2str(node->hw_lvl), hw_id, node->lvl, node->id,\n+\t\t   node);\n+\n+\tavail = nix_tm_resource_avail(nix, hw_lvl, false);\n+\t/* Always for now free to discontiguous queue when avail\n+\t * is not sufficient.\n+\t */\n+\tif (nix->discontig_rsvd[hw_lvl] &&\n+\t    avail < nix->discontig_rsvd[hw_lvl]) {\n+\t\tPLT_ASSERT(hw_id < NIX_TM_MAX_HW_TXSCHQ);\n+\t\tPLT_ASSERT(plt_bitmap_get(bmp, hw_id) == 0);\n+\t\tplt_bitmap_set(bmp, hw_id);\n+\t\tnode->hw_id = NIX_TM_HW_ID_INVALID;\n+\t\tnode->flags &= ~NIX_TM_NODE_HWRES;\n+\t\treturn 0;\n+\t}\n+\n+\t/* Free to AF */\n+\treq = mbox_alloc_msg_nix_txsch_free(mbox);\n+\tif (req == NULL)\n+\t\treturn rc;\n+\treq->flags = 0;\n+\treq->schq_lvl = node->hw_lvl;\n+\treq->schq = hw_id;\n+\trc = mbox_process(mbox);\n+\tif (rc) {\n+\t\tplt_err(\"failed to release hwres %s(%u) rc %d\",\n+\t\t\tnix_tm_hwlvl2str(node->hw_lvl), hw_id, rc);\n+\t\treturn rc;\n+\t}\n+\n+\t/* Mark parent as dirty for reallocing it's children */\n+\tif (node->parent)\n+\t\tnode->parent->child_realloc = true;\n+\n+\tnode->hw_id = NIX_TM_HW_ID_INVALID;\n+\tnode->flags &= ~NIX_TM_NODE_HWRES;\n+\tplt_tm_dbg(\"Released hwres %s(%u) to af\",\n+\t\t   nix_tm_hwlvl2str(node->hw_lvl), hw_id);\n+\treturn 0;\n+}\n+\n+int\n+nix_tm_node_delete(struct roc_nix *roc_nix, uint32_t node_id,\n+\t\t   enum roc_nix_tm_tree tree, bool free)\n+{\n+\tstruct nix *nix = roc_nix_to_nix_priv(roc_nix);\n+\tstruct nix_tm_shaper_profile *profile;\n+\tstruct nix_tm_node *node, *child;\n+\tstruct nix_tm_node_list *list;\n+\tuint32_t profile_id;\n+\tint rc;\n+\n+\tplt_tm_dbg(\"Delete node id %u tree %u\", node_id, tree);\n+\n+\tnode = nix_tm_node_search(nix, node_id, tree);\n+\tif (!node)\n+\t\treturn NIX_ERR_TM_INVALID_NODE;\n+\n+\tlist = nix_tm_node_list(nix, tree);\n+\t/* Check for any existing children */\n+\tTAILQ_FOREACH(child, list, node) {\n+\t\tif (child->parent == node)\n+\t\t\treturn NIX_ERR_TM_CHILD_EXISTS;\n+\t}\n+\n+\t/* Remove shaper profile reference */\n+\tprofile_id = node->shaper_profile_id;\n+\tprofile = nix_tm_shaper_profile_search(nix, profile_id);\n+\n+\t/* Free hw resource locally */\n+\tif (node->flags & NIX_TM_NODE_HWRES) {\n+\t\trc = nix_tm_free_node_resource(nix, node);\n+\t\tif (rc)\n+\t\t\treturn rc;\n+\t}\n+\n+\tif (profile)\n+\t\tprofile->ref_cnt--;\n+\n+\tTAILQ_REMOVE(list, node, node);\n+\n+\tplt_tm_dbg(\"Deleted node %s lvl %u id %u, prio 0x%x weight 0x%x \"\n+\t\t   \"parent %u profile 0x%x tree %u (%p)\",\n+\t\t   nix_tm_hwlvl2str(node->hw_lvl), node->lvl, node->id,\n+\t\t   node->priority, node->weight,\n+\t\t   node->parent ? node->parent->id : UINT32_MAX,\n+\t\t   node->shaper_profile_id, tree, node);\n+\t/* Free only if requested */\n+\tif (free)\n+\t\tnix_tm_node_free(node);\n+\treturn 0;\n+}\n+\n+int\n nix_tm_conf_init(struct roc_nix *roc_nix)\n {\n \tstruct nix *nix = roc_nix_to_nix_priv(roc_nix);\n@@ -328,6 +531,8 @@ nix_tm_conf_init(struct roc_nix *roc_nix)\n \tvoid *bmp_mem;\n \tint rc, i;\n \n+\tPLT_STATIC_ASSERT(sizeof(struct nix_tm_node) <= ROC_NIX_TM_NODE_SZ);\n+\n \tnix->tm_flags = 0;\n \tfor (i = 0; i < ROC_NIX_TM_TREE_MAX; i++)\n \t\tTAILQ_INIT(&nix->trees[i]);\ndiff --git a/drivers/common/cnxk/roc_nix_tm_ops.c b/drivers/common/cnxk/roc_nix_tm_ops.c\nindex e2b6d02..d0941c0 100644\n--- a/drivers/common/cnxk/roc_nix_tm_ops.c\n+++ b/drivers/common/cnxk/roc_nix_tm_ops.c\n@@ -65,3 +65,91 @@ roc_nix_tm_sq_aura_fc(struct roc_nix_sq *sq, bool enable)\n \tplt_wmb();\n \treturn 0;\n }\n+\n+int\n+roc_nix_tm_node_add(struct roc_nix *roc_nix, struct roc_nix_tm_node *roc_node)\n+{\n+\tstruct nix_tm_node *node;\n+\n+\tnode = (struct nix_tm_node *)&roc_node->reserved;\n+\tnode->id = roc_node->id;\n+\tnode->priority = roc_node->priority;\n+\tnode->weight = roc_node->weight;\n+\tnode->lvl = roc_node->lvl;\n+\tnode->parent_id = roc_node->parent_id;\n+\tnode->shaper_profile_id = roc_node->shaper_profile_id;\n+\tnode->pkt_mode = roc_node->pkt_mode;\n+\tnode->pkt_mode_set = roc_node->pkt_mode_set;\n+\tnode->free_fn = roc_node->free_fn;\n+\tnode->tree = ROC_NIX_TM_USER;\n+\n+\treturn nix_tm_node_add(roc_nix, node);\n+}\n+\n+int\n+roc_nix_tm_node_pkt_mode_update(struct roc_nix *roc_nix, uint32_t node_id,\n+\t\t\t\tbool pkt_mode)\n+{\n+\tstruct nix *nix = roc_nix_to_nix_priv(roc_nix);\n+\tstruct nix_tm_node *node, *child;\n+\tstruct nix_tm_node_list *list;\n+\tint num_children = 0;\n+\n+\tnode = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER);\n+\tif (!node)\n+\t\treturn NIX_ERR_TM_INVALID_NODE;\n+\n+\tif (node->pkt_mode == pkt_mode) {\n+\t\tnode->pkt_mode_set = true;\n+\t\treturn 0;\n+\t}\n+\n+\t/* Check for any existing children, if there are any,\n+\t * then we cannot update the pkt mode as children's quantum\n+\t * are already taken in.\n+\t */\n+\tlist = nix_tm_node_list(nix, ROC_NIX_TM_USER);\n+\tTAILQ_FOREACH(child, list, node) {\n+\t\tif (child->parent == node)\n+\t\t\tnum_children++;\n+\t}\n+\n+\t/* Cannot update mode if it has children or tree is enabled */\n+\tif ((nix->tm_flags & NIX_TM_HIERARCHY_ENA) && num_children)\n+\t\treturn -EBUSY;\n+\n+\tif (node->pkt_mode_set && num_children)\n+\t\treturn NIX_ERR_TM_PKT_MODE_MISMATCH;\n+\n+\tnode->pkt_mode = pkt_mode;\n+\tnode->pkt_mode_set = true;\n+\n+\treturn 0;\n+}\n+\n+int\n+roc_nix_tm_node_name_get(struct roc_nix *roc_nix, uint32_t node_id, char *buf,\n+\t\t\t size_t buflen)\n+{\n+\tstruct nix *nix = roc_nix_to_nix_priv(roc_nix);\n+\tstruct nix_tm_node *node;\n+\n+\tnode = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER);\n+\tif (!node) {\n+\t\tplt_strlcpy(buf, \"???\", buflen);\n+\t\treturn NIX_ERR_TM_INVALID_NODE;\n+\t}\n+\n+\tif (node->hw_lvl == NIX_TXSCH_LVL_CNT)\n+\t\tsnprintf(buf, buflen, \"SQ_%d\", node->id);\n+\telse\n+\t\tsnprintf(buf, buflen, \"%s_%d\", nix_tm_hwlvl2str(node->hw_lvl),\n+\t\t\t node->hw_id);\n+\treturn 0;\n+}\n+\n+int\n+roc_nix_tm_node_delete(struct roc_nix *roc_nix, uint32_t node_id, bool free)\n+{\n+\treturn nix_tm_node_delete(roc_nix, node_id, ROC_NIX_TM_USER, free);\n+}\ndiff --git a/drivers/common/cnxk/roc_nix_tm_utils.c b/drivers/common/cnxk/roc_nix_tm_utils.c\nindex a3f683e..bea23be 100644\n--- a/drivers/common/cnxk/roc_nix_tm_utils.c\n+++ b/drivers/common/cnxk/roc_nix_tm_utils.c\n@@ -5,6 +5,64 @@\n #include \"roc_api.h\"\n #include \"roc_priv.h\"\n \n+uint16_t\n+nix_tm_lvl2nix_tl1_root(uint32_t lvl)\n+{\n+\tswitch (lvl) {\n+\tcase ROC_TM_LVL_ROOT:\n+\t\treturn NIX_TXSCH_LVL_TL1;\n+\tcase ROC_TM_LVL_SCH1:\n+\t\treturn NIX_TXSCH_LVL_TL2;\n+\tcase ROC_TM_LVL_SCH2:\n+\t\treturn NIX_TXSCH_LVL_TL3;\n+\tcase ROC_TM_LVL_SCH3:\n+\t\treturn NIX_TXSCH_LVL_TL4;\n+\tcase ROC_TM_LVL_SCH4:\n+\t\treturn NIX_TXSCH_LVL_SMQ;\n+\tdefault:\n+\t\treturn NIX_TXSCH_LVL_CNT;\n+\t}\n+}\n+\n+uint16_t\n+nix_tm_lvl2nix_tl2_root(uint32_t lvl)\n+{\n+\tswitch (lvl) {\n+\tcase ROC_TM_LVL_ROOT:\n+\t\treturn NIX_TXSCH_LVL_TL2;\n+\tcase ROC_TM_LVL_SCH1:\n+\t\treturn NIX_TXSCH_LVL_TL3;\n+\tcase ROC_TM_LVL_SCH2:\n+\t\treturn NIX_TXSCH_LVL_TL4;\n+\tcase ROC_TM_LVL_SCH3:\n+\t\treturn NIX_TXSCH_LVL_SMQ;\n+\tdefault:\n+\t\treturn NIX_TXSCH_LVL_CNT;\n+\t}\n+}\n+\n+uint16_t\n+nix_tm_lvl2nix(struct nix *nix, uint32_t lvl)\n+{\n+\tif (nix_tm_have_tl1_access(nix))\n+\t\treturn nix_tm_lvl2nix_tl1_root(lvl);\n+\telse\n+\t\treturn nix_tm_lvl2nix_tl2_root(lvl);\n+}\n+\n+\n+struct nix_tm_shaper_profile *\n+nix_tm_shaper_profile_search(struct nix *nix, uint32_t id)\n+{\n+\tstruct nix_tm_shaper_profile *profile;\n+\n+\tTAILQ_FOREACH(profile, &nix->shaper_profile_list, shaper) {\n+\t\tif (profile->id == id)\n+\t\t\treturn profile;\n+\t}\n+\treturn NULL;\n+}\n+\n struct nix_tm_node *\n nix_tm_node_search(struct nix *nix, uint32_t node_id, enum roc_nix_tm_tree tree)\n {\n@@ -19,6 +77,70 @@ nix_tm_node_search(struct nix *nix, uint32_t node_id, enum roc_nix_tm_tree tree)\n \treturn NULL;\n }\n \n+static uint16_t\n+nix_tm_max_prio(struct nix *nix, uint16_t hw_lvl)\n+{\n+\tif (hw_lvl >= NIX_TXSCH_LVL_CNT)\n+\t\treturn 0;\n+\n+\t/* MDQ does not support SP */\n+\tif (hw_lvl == NIX_TXSCH_LVL_MDQ)\n+\t\treturn 0;\n+\n+\t/* PF's TL1 with VF's enabled does not support SP */\n+\tif (hw_lvl == NIX_TXSCH_LVL_TL1 && (!nix_tm_have_tl1_access(nix) ||\n+\t\t\t\t\t    (nix->tm_flags & NIX_TM_TL1_NO_SP)))\n+\t\treturn 0;\n+\n+\treturn NIX_TM_TLX_SP_PRIO_MAX - 1;\n+}\n+\n+int\n+nix_tm_validate_prio(struct nix *nix, uint32_t lvl, uint32_t parent_id,\n+\t\t     uint32_t priority, enum roc_nix_tm_tree tree)\n+{\n+\tuint8_t priorities[NIX_TM_TLX_SP_PRIO_MAX];\n+\tstruct nix_tm_node_list *list;\n+\tstruct nix_tm_node *node;\n+\tuint32_t rr_num = 0;\n+\tint i;\n+\n+\tlist = nix_tm_node_list(nix, tree);\n+\t/* Validate priority against max */\n+\tif (priority > nix_tm_max_prio(nix, nix_tm_lvl2nix(nix, lvl - 1)))\n+\t\treturn NIX_ERR_TM_PRIO_EXCEEDED;\n+\n+\tif (parent_id == ROC_NIX_TM_NODE_ID_INVALID)\n+\t\treturn 0;\n+\n+\tmemset(priorities, 0, sizeof(priorities));\n+\tpriorities[priority] = 1;\n+\n+\tTAILQ_FOREACH(node, list, node) {\n+\t\tif (!node->parent)\n+\t\t\tcontinue;\n+\n+\t\tif (node->parent->id != parent_id)\n+\t\t\tcontinue;\n+\n+\t\tpriorities[node->priority]++;\n+\t}\n+\n+\tfor (i = 0; i < NIX_TM_TLX_SP_PRIO_MAX; i++)\n+\t\tif (priorities[i] > 1)\n+\t\t\trr_num++;\n+\n+\t/* At max, one rr groups per parent */\n+\tif (rr_num > 1)\n+\t\treturn NIX_ERR_TM_MULTIPLE_RR_GROUPS;\n+\n+\t/* Check for previous priority to avoid holes in priorities */\n+\tif (priority && !priorities[priority - 1])\n+\t\treturn NIX_ERR_TM_PRIO_ORDER;\n+\n+\treturn 0;\n+}\n+\n uint8_t\n nix_tm_sw_xoff_prep(struct nix_tm_node *node, bool enable,\n \t\t    volatile uint64_t *reg, volatile uint64_t *regval)\n@@ -60,3 +182,93 @@ nix_tm_sw_xoff_prep(struct nix_tm_node *node, bool enable,\n \n \treturn k;\n }\n+\n+uint16_t\n+nix_tm_resource_avail(struct nix *nix, uint8_t hw_lvl, bool contig)\n+{\n+\tuint32_t pos = 0, start_pos = 0;\n+\tstruct plt_bitmap *bmp;\n+\tuint16_t count = 0;\n+\tuint64_t slab = 0;\n+\n+\tbmp = contig ? nix->schq_contig_bmp[hw_lvl] : nix->schq_bmp[hw_lvl];\n+\tplt_bitmap_scan_init(bmp);\n+\n+\tif (!plt_bitmap_scan(bmp, &pos, &slab))\n+\t\treturn count;\n+\n+\t/* Count bit set */\n+\tstart_pos = pos;\n+\tdo {\n+\t\tcount += __builtin_popcountll(slab);\n+\t\tif (!plt_bitmap_scan(bmp, &pos, &slab))\n+\t\t\tbreak;\n+\t} while (pos != start_pos);\n+\n+\treturn count;\n+}\n+\n+int\n+roc_nix_tm_node_lvl(struct roc_nix *roc_nix, uint32_t node_id)\n+{\n+\tstruct nix *nix = roc_nix_to_nix_priv(roc_nix);\n+\tstruct nix_tm_node *node;\n+\n+\tnode = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER);\n+\tif (!node)\n+\t\treturn NIX_ERR_TM_INVALID_NODE;\n+\n+\treturn node->lvl;\n+}\n+\n+struct roc_nix_tm_node *\n+roc_nix_tm_node_get(struct roc_nix *roc_nix, uint32_t node_id)\n+{\n+\tstruct nix *nix = roc_nix_to_nix_priv(roc_nix);\n+\tstruct nix_tm_node *node;\n+\n+\tnode = nix_tm_node_search(nix, node_id, ROC_NIX_TM_USER);\n+\treturn (struct roc_nix_tm_node *)node;\n+}\n+\n+struct roc_nix_tm_node *\n+roc_nix_tm_node_next(struct roc_nix *roc_nix, struct roc_nix_tm_node *__prev)\n+{\n+\tstruct nix_tm_node *prev = (struct nix_tm_node *)__prev;\n+\tstruct nix *nix = roc_nix_to_nix_priv(roc_nix);\n+\tstruct nix_tm_node_list *list;\n+\n+\tlist = nix_tm_node_list(nix, ROC_NIX_TM_USER);\n+\n+\t/* HEAD of the list */\n+\tif (!prev)\n+\t\treturn (struct roc_nix_tm_node *)TAILQ_FIRST(list);\n+\n+\t/* Next entry */\n+\tif (prev->tree != ROC_NIX_TM_USER)\n+\t\treturn NULL;\n+\n+\treturn (struct roc_nix_tm_node *)TAILQ_NEXT(prev, node);\n+}\n+\n+struct nix_tm_node *\n+nix_tm_node_alloc(void)\n+{\n+\tstruct nix_tm_node *node;\n+\n+\tnode = plt_zmalloc(sizeof(struct nix_tm_node), 0);\n+\tif (!node)\n+\t\treturn NULL;\n+\n+\tnode->free_fn = plt_free;\n+\treturn node;\n+}\n+\n+void\n+nix_tm_node_free(struct nix_tm_node *node)\n+{\n+\tif (!node || node->free_fn == NULL)\n+\t\treturn;\n+\n+\t(node->free_fn)(node);\n+}\ndiff --git a/drivers/common/cnxk/version.map b/drivers/common/cnxk/version.map\nindex 5b99467..dec0ad0 100644\n--- a/drivers/common/cnxk/version.map\n+++ b/drivers/common/cnxk/version.map\n@@ -104,6 +104,13 @@ INTERNAL {\n \troc_nix_xstats_names_get;\n \troc_nix_switch_hdr_set;\n \troc_nix_eeprom_info_get;\n+\troc_nix_tm_node_add;\n+\troc_nix_tm_node_delete;\n+\troc_nix_tm_node_get;\n+\troc_nix_tm_node_lvl;\n+\troc_nix_tm_node_name_get;\n+\troc_nix_tm_node_next;\n+\troc_nix_tm_node_pkt_mode_update;\n \troc_nix_tm_sq_aura_fc;\n \troc_nix_tm_sq_flush_spin;\n \troc_nix_unregister_cq_irqs;\n",
    "prefixes": [
        "v2",
        "33/52"
    ]
}