get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 28817,
    "url": "https://patches.dpdk.org/api/patches/28817/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20170918091015.82824-3-jasvinder.singh@intel.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": "<20170918091015.82824-3-jasvinder.singh@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20170918091015.82824-3-jasvinder.singh@intel.com",
    "date": "2017-09-18T09:10:13",
    "name": "[dpdk-dev,v4,2/4] net/softnic: add traffic management support",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "601f493e0e4a36a6fadf8d9d0d328e001e72cfe4",
    "submitter": {
        "id": 285,
        "url": "https://patches.dpdk.org/api/people/285/?format=api",
        "name": "Jasvinder Singh",
        "email": "jasvinder.singh@intel.com"
    },
    "delegate": null,
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20170918091015.82824-3-jasvinder.singh@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/28817/comments/",
    "check": "success",
    "checks": "https://patches.dpdk.org/api/patches/28817/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id A086A199B6;\n\tMon, 18 Sep 2017 10:58:22 +0200 (CEST)",
            "from mga07.intel.com (mga07.intel.com [134.134.136.100])\n\tby dpdk.org (Postfix) with ESMTP id D87C7325A\n\tfor <dev@dpdk.org>; Mon, 18 Sep 2017 10:58:17 +0200 (CEST)",
            "from orsmga003.jf.intel.com ([10.7.209.27])\n\tby orsmga105.jf.intel.com with ESMTP; 18 Sep 2017 01:58:17 -0700",
            "from silpixa00381635.ir.intel.com (HELO\n\tsilpixa00381635.ger.corp.intel.com) ([10.237.222.149])\n\tby orsmga003.jf.intel.com with ESMTP; 18 Sep 2017 01:58:15 -0700"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos; i=\"5.42,412,1500966000\"; d=\"scan'208\";\n\ta=\"1015532523\"",
        "From": "Jasvinder Singh <jasvinder.singh@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "cristian.dumitrescu@intel.com, ferruh.yigit@intel.com,\n\tthomas@monjalon.net",
        "Date": "Mon, 18 Sep 2017 10:10:13 +0100",
        "Message-Id": "<20170918091015.82824-3-jasvinder.singh@intel.com>",
        "X-Mailer": "git-send-email 2.9.3",
        "In-Reply-To": "<20170918091015.82824-1-jasvinder.singh@intel.com>",
        "References": "<20170811124929.118564-2-jasvinder.singh@intel.com>\n\t<20170918091015.82824-1-jasvinder.singh@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v4 2/4] net/softnic: add traffic management\n\tsupport",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Add ethdev Traffic Management API support to SoftNIC PMD.\n\nSigned-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>\nSigned-off-by: Jasvinder Singh <jasvinder.singh@intel.com>\n---\nv3 changes:\n- add more confguration parameters (tm rate, tm queue sizes)\n\n drivers/net/softnic/Makefile                    |   1 +\n drivers/net/softnic/rte_eth_softnic.c           | 252 +++++++++++++++++++++++-\n drivers/net/softnic/rte_eth_softnic.h           |  16 ++\n drivers/net/softnic/rte_eth_softnic_internals.h | 106 +++++++++-\n drivers/net/softnic/rte_eth_softnic_tm.c        | 181 +++++++++++++++++\n 5 files changed, 553 insertions(+), 3 deletions(-)\n create mode 100644 drivers/net/softnic/rte_eth_softnic_tm.c",
    "diff": "diff --git a/drivers/net/softnic/Makefile b/drivers/net/softnic/Makefile\nindex c2f42ef..8b848a9 100644\n--- a/drivers/net/softnic/Makefile\n+++ b/drivers/net/softnic/Makefile\n@@ -47,6 +47,7 @@ LIBABIVER := 1\n # all source are stored in SRCS-y\n #\n SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic.c\n+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SOFTNIC) += rte_eth_softnic_tm.c\n \n #\n # Export include files\ndiff --git a/drivers/net/softnic/rte_eth_softnic.c b/drivers/net/softnic/rte_eth_softnic.c\nindex 792e7ea..28b5155 100644\n--- a/drivers/net/softnic/rte_eth_softnic.c\n+++ b/drivers/net/softnic/rte_eth_softnic.c\n@@ -42,6 +42,7 @@\n #include <rte_kvargs.h>\n #include <rte_errno.h>\n #include <rte_ring.h>\n+#include <rte_sched.h>\n \n #include \"rte_eth_softnic.h\"\n #include \"rte_eth_softnic_internals.h\"\n@@ -49,10 +50,29 @@\n #define PRIV_TO_HARD_DEV(p)\t\t\t\t\t\\\n \t(&rte_eth_devices[p->hard.port_id])\n \n+#define PMD_PARAM_SOFT_TM\t\t\t\t\t\"soft_tm\"\n+#define PMD_PARAM_SOFT_TM_RATE\t\t\t\t\"soft_tm_rate\"\n+#define PMD_PARAM_SOFT_TM_NB_QUEUES\t\t\t\"soft_tm_nb_queues\"\n+#define PMD_PARAM_SOFT_TM_QSIZE0\t\t\t\"soft_tm_qsize0\"\n+#define PMD_PARAM_SOFT_TM_QSIZE1\t\t\t\"soft_tm_qsize1\"\n+#define PMD_PARAM_SOFT_TM_QSIZE2\t\t\t\"soft_tm_qsize2\"\n+#define PMD_PARAM_SOFT_TM_QSIZE3\t\t\t\"soft_tm_qsize3\"\n+#define PMD_PARAM_SOFT_TM_ENQ_BSZ\t\t\t\"soft_tm_enq_bsz\"\n+#define PMD_PARAM_SOFT_TM_DEQ_BSZ\t\t\t\"soft_tm_deq_bsz\"\n+\n #define PMD_PARAM_HARD_NAME\t\t\t\t\t\"hard_name\"\n #define PMD_PARAM_HARD_TX_QUEUE_ID\t\t\t\"hard_tx_queue_id\"\n \n static const char *pmd_valid_args[] = {\n+\tPMD_PARAM_SOFT_TM,\n+\tPMD_PARAM_SOFT_TM_RATE,\n+\tPMD_PARAM_SOFT_TM_NB_QUEUES,\n+\tPMD_PARAM_SOFT_TM_QSIZE0,\n+\tPMD_PARAM_SOFT_TM_QSIZE1,\n+\tPMD_PARAM_SOFT_TM_QSIZE2,\n+\tPMD_PARAM_SOFT_TM_QSIZE3,\n+\tPMD_PARAM_SOFT_TM_ENQ_BSZ,\n+\tPMD_PARAM_SOFT_TM_DEQ_BSZ,\n \tPMD_PARAM_HARD_NAME,\n \tPMD_PARAM_HARD_TX_QUEUE_ID,\n \tNULL\n@@ -157,6 +177,13 @@ pmd_dev_start(struct rte_eth_dev *dev)\n {\n \tstruct pmd_internals *p = dev->data->dev_private;\n \n+\tif (tm_used(dev)) {\n+\t\tint status = tm_start(p);\n+\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\n \tdev->data->dev_link.link_status = ETH_LINK_UP;\n \n \tif (p->params.soft.intrusive) {\n@@ -172,7 +199,12 @@ pmd_dev_start(struct rte_eth_dev *dev)\n static void\n pmd_dev_stop(struct rte_eth_dev *dev)\n {\n+\tstruct pmd_internals *p = dev->data->dev_private;\n+\n \tdev->data->dev_link.link_status = ETH_LINK_DOWN;\n+\n+\tif (tm_used(dev))\n+\t\ttm_stop(p);\n }\n \n static void\n@@ -293,6 +325,77 @@ rte_pmd_softnic_run_default(struct rte_eth_dev *dev)\n \treturn 0;\n }\n \n+static __rte_always_inline int\n+rte_pmd_softnic_run_tm(struct rte_eth_dev *dev)\n+{\n+\tstruct pmd_internals *p = dev->data->dev_private;\n+\n+\t/* Persistent context: Read Only (update not required) */\n+\tstruct rte_sched_port *sched = p->soft.tm.sched;\n+\tstruct rte_mbuf **pkts_enq = p->soft.tm.pkts_enq;\n+\tstruct rte_mbuf **pkts_deq = p->soft.tm.pkts_deq;\n+\tuint32_t enq_bsz = p->params.soft.tm.enq_bsz;\n+\tuint32_t deq_bsz = p->params.soft.tm.deq_bsz;\n+\tuint16_t nb_tx_queues = dev->data->nb_tx_queues;\n+\n+\t/* Persistent context: Read - Write (update required) */\n+\tuint32_t txq_pos = p->soft.tm.txq_pos;\n+\tuint32_t pkts_enq_len = p->soft.tm.pkts_enq_len;\n+\tuint32_t flush_count = p->soft.tm.flush_count;\n+\n+\t/* Not part of the persistent context */\n+\tuint32_t pkts_deq_len, pos;\n+\tuint16_t i;\n+\n+\t/* Soft device TXQ read, TM enqueue */\n+\tfor (i = 0; i < nb_tx_queues; i++) {\n+\t\tstruct rte_ring *txq = dev->data->tx_queues[txq_pos];\n+\n+\t\t/* Read TXQ burst to packet enqueue buffer */\n+\t\tpkts_enq_len += rte_ring_sc_dequeue_burst(txq,\n+\t\t\t(void **)&pkts_enq[pkts_enq_len],\n+\t\t\tenq_bsz,\n+\t\t\tNULL);\n+\n+\t\t/* Increment TXQ */\n+\t\ttxq_pos++;\n+\t\tif (txq_pos >= nb_tx_queues)\n+\t\t\ttxq_pos = 0;\n+\n+\t\t/* TM enqueue when complete burst is available */\n+\t\tif (pkts_enq_len >= enq_bsz) {\n+\t\t\trte_sched_port_enqueue(sched, pkts_enq, pkts_enq_len);\n+\n+\t\t\tpkts_enq_len = 0;\n+\t\t\tflush_count = 0;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (flush_count >= FLUSH_COUNT_THRESHOLD) {\n+\t\tif (pkts_enq_len)\n+\t\t\trte_sched_port_enqueue(sched, pkts_enq, pkts_enq_len);\n+\n+\t\tpkts_enq_len = 0;\n+\t\tflush_count = 0;\n+\t}\n+\n+\tp->soft.tm.txq_pos = txq_pos;\n+\tp->soft.tm.pkts_enq_len = pkts_enq_len;\n+\tp->soft.tm.flush_count = flush_count + 1;\n+\n+\t/* TM dequeue, Hard device TXQ write */\n+\tpkts_deq_len = rte_sched_port_dequeue(sched, pkts_deq, deq_bsz);\n+\n+\tfor (pos = 0; pos < pkts_deq_len; )\n+\t\tpos += rte_eth_tx_burst(p->hard.port_id,\n+\t\t\tp->params.hard.tx_queue_id,\n+\t\t\t&pkts_deq[pos],\n+\t\t\t(uint16_t)(pkts_deq_len - pos));\n+\n+\treturn 0;\n+}\n+\n int\n rte_pmd_softnic_run(uint8_t port_id)\n {\n@@ -302,7 +405,9 @@ rte_pmd_softnic_run(uint8_t port_id)\n \tRTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);\n #endif\n \n-\treturn rte_pmd_softnic_run_default(dev);\n+\treturn (tm_used(dev)) ?\n+\t\trte_pmd_softnic_run_tm(dev) :\n+\t\trte_pmd_softnic_run_default(dev);\n }\n \n static struct ether_addr eth_addr = { .addr_bytes = {0} };\n@@ -383,12 +488,25 @@ pmd_init(struct pmd_params *params, int numa_node)\n \t\treturn NULL;\n \t}\n \n+\t/* Traffic Management (TM)*/\n+\tif (params->soft.flags & PMD_FEATURE_TM) {\n+\t\tstatus = tm_init(p, params, numa_node);\n+\t\tif (status) {\n+\t\t\tdefault_free(p);\n+\t\t\trte_free(p);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n \treturn p;\n }\n \n static void\n pmd_free(struct pmd_internals *p)\n {\n+\tif (p->params.soft.flags & PMD_FEATURE_TM)\n+\t\ttm_free(p);\n+\n \tdefault_free(p);\n \n \trte_free(p);\n@@ -468,7 +586,7 @@ static int\n pmd_parse_args(struct pmd_params *p, const char *name, const char *params)\n {\n \tstruct rte_kvargs *kvlist;\n-\tint ret;\n+\tint i, ret;\n \n \tkvlist = rte_kvargs_parse(params, pmd_valid_args);\n \tif (kvlist == NULL)\n@@ -478,8 +596,120 @@ pmd_parse_args(struct pmd_params *p, const char *name, const char *params)\n \tmemset(p, 0, sizeof(*p));\n \tp->soft.name = name;\n \tp->soft.intrusive = INTRUSIVE;\n+\tp->soft.tm.rate = 0;\n+\tp->soft.tm.nb_queues = SOFTNIC_SOFT_TM_NB_QUEUES;\n+\tfor (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)\n+\t\tp->soft.tm.qsize[i] = SOFTNIC_SOFT_TM_QUEUE_SIZE;\n+\tp->soft.tm.enq_bsz = SOFTNIC_SOFT_TM_ENQ_BSZ;\n+\tp->soft.tm.deq_bsz = SOFTNIC_SOFT_TM_DEQ_BSZ;\n \tp->hard.tx_queue_id = SOFTNIC_HARD_TX_QUEUE_ID;\n \n+\t/* SOFT: TM (optional) */\n+\tif (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM) == 1) {\n+\t\tchar *s;\n+\n+\t\tret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM,\n+\t\t\t&get_string, &s);\n+\t\tif (ret < 0)\n+\t\t\tgoto out_free;\n+\n+\t\tif (strcmp(s, \"on\") == 0)\n+\t\t\tp->soft.flags |= PMD_FEATURE_TM;\n+\t\telse if (strcmp(s, \"off\") == 0)\n+\t\t\tp->soft.flags &= ~PMD_FEATURE_TM;\n+\t\telse\n+\t\t\tgoto out_free;\n+\t}\n+\n+\t/* SOFT: TM rate (measured in bytes/second) (optional) */\n+\tif (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_RATE) == 1) {\n+\t\tret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_RATE,\n+\t\t\t&get_uint32, &p->soft.tm.rate);\n+\t\tif (ret < 0)\n+\t\t\tgoto out_free;\n+\n+\t\tp->soft.flags |= PMD_FEATURE_TM;\n+\t}\n+\n+\t/* SOFT: TM number of queues (optional) */\n+\tif (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_NB_QUEUES) == 1) {\n+\t\tret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_NB_QUEUES,\n+\t\t\t&get_uint32, &p->soft.tm.nb_queues);\n+\t\tif (ret < 0)\n+\t\t\tgoto out_free;\n+\n+\t\tp->soft.flags |= PMD_FEATURE_TM;\n+\t}\n+\n+\t/* SOFT: TM queue size 0 .. 3 (optional) */\n+\tif (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_QSIZE0) == 1) {\n+\t\tuint32_t qsize;\n+\n+\t\tret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_QSIZE0,\n+\t\t\t&get_uint32, &qsize);\n+\t\tif (ret < 0)\n+\t\t\tgoto out_free;\n+\n+\t\tp->soft.tm.qsize[0] = (uint16_t)qsize;\n+\t\tp->soft.flags |= PMD_FEATURE_TM;\n+\t}\n+\n+\tif (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_QSIZE1) == 1) {\n+\t\tuint32_t qsize;\n+\n+\t\tret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_QSIZE1,\n+\t\t\t&get_uint32, &qsize);\n+\t\tif (ret < 0)\n+\t\t\tgoto out_free;\n+\n+\t\tp->soft.tm.qsize[1] = (uint16_t)qsize;\n+\t\tp->soft.flags |= PMD_FEATURE_TM;\n+\t}\n+\n+\tif (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_QSIZE2) == 1) {\n+\t\tuint32_t qsize;\n+\n+\t\tret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_QSIZE2,\n+\t\t\t&get_uint32, &qsize);\n+\t\tif (ret < 0)\n+\t\t\tgoto out_free;\n+\n+\t\tp->soft.tm.qsize[2] = (uint16_t)qsize;\n+\t\tp->soft.flags |= PMD_FEATURE_TM;\n+\t}\n+\n+\tif (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_QSIZE3) == 1) {\n+\t\tuint32_t qsize;\n+\n+\t\tret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_QSIZE3,\n+\t\t\t&get_uint32, &qsize);\n+\t\tif (ret < 0)\n+\t\t\tgoto out_free;\n+\n+\t\tp->soft.tm.qsize[3] = (uint16_t)qsize;\n+\t\tp->soft.flags |= PMD_FEATURE_TM;\n+\t}\n+\n+\t/* SOFT: TM enqueue burst size (optional) */\n+\tif (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_ENQ_BSZ) == 1) {\n+\t\tret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_ENQ_BSZ,\n+\t\t\t&get_uint32, &p->soft.tm.enq_bsz);\n+\t\tif (ret < 0)\n+\t\t\tgoto out_free;\n+\n+\t\tp->soft.flags |= PMD_FEATURE_TM;\n+\t}\n+\n+\t/* SOFT: TM dequeue burst size (optional) */\n+\tif (rte_kvargs_count(kvlist, PMD_PARAM_SOFT_TM_DEQ_BSZ) == 1) {\n+\t\tret = rte_kvargs_process(kvlist, PMD_PARAM_SOFT_TM_DEQ_BSZ,\n+\t\t\t&get_uint32, &p->soft.tm.deq_bsz);\n+\t\tif (ret < 0)\n+\t\t\tgoto out_free;\n+\n+\t\tp->soft.flags |= PMD_FEATURE_TM;\n+\t}\n+\n \t/* HARD: name (mandatory) */\n \tif (rte_kvargs_count(kvlist, PMD_PARAM_HARD_NAME) == 1) {\n \t\tret = rte_kvargs_process(kvlist, PMD_PARAM_HARD_NAME,\n@@ -512,6 +742,7 @@ pmd_probe(struct rte_vdev_device *vdev)\n \tint status;\n \n \tstruct rte_eth_dev_info hard_info;\n+\tuint32_t hard_speed;\n \tuint8_t hard_port_id;\n \tint numa_node;\n \tvoid *dev_private;\n@@ -534,11 +765,19 @@ pmd_probe(struct rte_vdev_device *vdev)\n \t\treturn -EINVAL;\n \n \trte_eth_dev_info_get(hard_port_id, &hard_info);\n+\thard_speed = eth_dev_speed_max_mbps(hard_info.speed_capa);\n \tnuma_node = rte_eth_dev_socket_id(hard_port_id);\n \n \tif (p.hard.tx_queue_id >= hard_info.max_tx_queues)\n \t\treturn -EINVAL;\n \n+\tif (p.soft.flags & PMD_FEATURE_TM) {\n+\t\tstatus = tm_params_check(&p, hard_speed);\n+\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\n \t/* Allocate and initialize soft ethdev private data */\n \tdev_private = pmd_init(&p, numa_node);\n \tif (dev_private == NULL)\n@@ -591,5 +830,14 @@ static struct rte_vdev_driver pmd_softnic_drv = {\n \n RTE_PMD_REGISTER_VDEV(net_softnic, pmd_softnic_drv);\n RTE_PMD_REGISTER_PARAM_STRING(net_softnic,\n+\tPMD_PARAM_SOFT_TM\t \"=on|off \"\n+\tPMD_PARAM_SOFT_TM_RATE \"=<int> \"\n+\tPMD_PARAM_SOFT_TM_NB_QUEUES \"=<int> \"\n+\tPMD_PARAM_SOFT_TM_QSIZE0 \"=<int> \"\n+\tPMD_PARAM_SOFT_TM_QSIZE1 \"=<int> \"\n+\tPMD_PARAM_SOFT_TM_QSIZE2 \"=<int> \"\n+\tPMD_PARAM_SOFT_TM_QSIZE3 \"=<int> \"\n+\tPMD_PARAM_SOFT_TM_ENQ_BSZ \"=<int> \"\n+\tPMD_PARAM_SOFT_TM_DEQ_BSZ \"=<int> \"\n \tPMD_PARAM_HARD_NAME \"=<string> \"\n \tPMD_PARAM_HARD_TX_QUEUE_ID \"=<int>\");\ndiff --git a/drivers/net/softnic/rte_eth_softnic.h b/drivers/net/softnic/rte_eth_softnic.h\nindex e6996f3..517b96a 100644\n--- a/drivers/net/softnic/rte_eth_softnic.h\n+++ b/drivers/net/softnic/rte_eth_softnic.h\n@@ -40,6 +40,22 @@\n extern \"C\" {\n #endif\n \n+#ifndef SOFTNIC_SOFT_TM_NB_QUEUES\n+#define SOFTNIC_SOFT_TM_NB_QUEUES\t\t\t65536\n+#endif\n+\n+#ifndef SOFTNIC_SOFT_TM_QUEUE_SIZE\n+#define SOFTNIC_SOFT_TM_QUEUE_SIZE\t\t\t64\n+#endif\n+\n+#ifndef SOFTNIC_SOFT_TM_ENQ_BSZ\n+#define SOFTNIC_SOFT_TM_ENQ_BSZ\t\t\t\t32\n+#endif\n+\n+#ifndef SOFTNIC_SOFT_TM_DEQ_BSZ\n+#define SOFTNIC_SOFT_TM_DEQ_BSZ\t\t\t\t24\n+#endif\n+\n #ifndef SOFTNIC_HARD_TX_QUEUE_ID\n #define SOFTNIC_HARD_TX_QUEUE_ID\t\t\t0\n #endif\ndiff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h\nindex 96995b5..f9e2177 100644\n--- a/drivers/net/softnic/rte_eth_softnic_internals.h\n+++ b/drivers/net/softnic/rte_eth_softnic_internals.h\n@@ -37,10 +37,19 @@\n #include <stdint.h>\n \n #include <rte_mbuf.h>\n+#include <rte_sched.h>\n #include <rte_ethdev.h>\n \n #include \"rte_eth_softnic.h\"\n \n+/**\n+ * PMD Parameters\n+ */\n+\n+enum pmd_feature {\n+\tPMD_FEATURE_TM = 1, /**< Traffic Management (TM) */\n+};\n+\n #ifndef INTRUSIVE\n #define INTRUSIVE\t\t\t\t\t0\n #endif\n@@ -57,6 +66,16 @@ struct pmd_params {\n \t\t *      (potentially faster).\n \t\t */\n \t\tint intrusive;\n+\n+\t\t/** Traffic Management (TM) */\n+\t\tstruct {\n+\t\t\tuint32_t rate; /**< Rate (bytes/second) */\n+\t\t\tuint32_t nb_queues; /**< Number of queues */\n+\t\t\tuint16_t qsize[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];\n+\t\t\t/**< Queue size per traffic class */\n+\t\t\tuint32_t enq_bsz; /**< Enqueue burst size */\n+\t\t\tuint32_t deq_bsz; /**< Dequeue burst size */\n+\t\t} tm;\n \t} soft;\n \n \t/** Parameters for the hard device (existing) */\n@@ -75,7 +94,7 @@ struct pmd_params {\n #endif\n \n #ifndef FLUSH_COUNT_THRESHOLD\n-#define FLUSH_COUNT_THRESHOLD\t\t\t(1 << 17)\n+#define FLUSH_COUNT_THRESHOLD\t\t\t\t(1 << 17)\n #endif\n \n struct default_internals {\n@@ -86,6 +105,66 @@ struct default_internals {\n };\n \n /**\n+ * Traffic Management (TM) Internals\n+ */\n+\n+#ifndef TM_MAX_SUBPORTS\n+#define TM_MAX_SUBPORTS\t\t\t\t\t8\n+#endif\n+\n+#ifndef TM_MAX_PIPES_PER_SUBPORT\n+#define TM_MAX_PIPES_PER_SUBPORT\t\t\t4096\n+#endif\n+\n+struct tm_params {\n+\tstruct rte_sched_port_params port_params;\n+\n+\tstruct rte_sched_subport_params subport_params[TM_MAX_SUBPORTS];\n+\n+\tstruct rte_sched_pipe_params\n+\t\tpipe_profiles[RTE_SCHED_PIPE_PROFILES_PER_PORT];\n+\tuint32_t n_pipe_profiles;\n+\tuint32_t pipe_to_profile[TM_MAX_SUBPORTS * TM_MAX_PIPES_PER_SUBPORT];\n+};\n+\n+/* TM Levels */\n+enum tm_node_level {\n+\tTM_NODE_LEVEL_PORT = 0,\n+\tTM_NODE_LEVEL_SUBPORT,\n+\tTM_NODE_LEVEL_PIPE,\n+\tTM_NODE_LEVEL_TC,\n+\tTM_NODE_LEVEL_QUEUE,\n+\tTM_NODE_LEVEL_MAX,\n+};\n+\n+/* TM Hierarchy Specification */\n+struct tm_hierarchy {\n+\tuint32_t n_tm_nodes[TM_NODE_LEVEL_MAX];\n+};\n+\n+struct tm_internals {\n+\t/** Hierarchy specification\n+\t *\n+\t *     -Hierarchy is unfrozen at init and when port is stopped.\n+\t *     -Hierarchy is frozen on successful hierarchy commit.\n+\t *     -Run-time hierarchy changes are not allowed, therefore it makes\n+\t *      sense to keep the hierarchy frozen after the port is started.\n+\t */\n+\tstruct tm_hierarchy h;\n+\n+\t/** Blueprints */\n+\tstruct tm_params params;\n+\n+\t/** Run-time */\n+\tstruct rte_sched_port *sched;\n+\tstruct rte_mbuf **pkts_enq;\n+\tstruct rte_mbuf **pkts_deq;\n+\tuint32_t pkts_enq_len;\n+\tuint32_t txq_pos;\n+\tuint32_t flush_count;\n+};\n+\n+/**\n  * PMD Internals\n  */\n struct pmd_internals {\n@@ -95,6 +174,7 @@ struct pmd_internals {\n \t/** Soft device */\n \tstruct {\n \t\tstruct default_internals def; /**< Default */\n+\t\tstruct tm_internals tm; /**< Traffic Management */\n \t} soft;\n \n \t/** Hard device */\n@@ -111,4 +191,28 @@ struct pmd_rx_queue {\n \t} hard;\n };\n \n+int\n+tm_params_check(struct pmd_params *params, uint32_t hard_rate);\n+\n+int\n+tm_init(struct pmd_internals *p, struct pmd_params *params, int numa_node);\n+\n+void\n+tm_free(struct pmd_internals *p);\n+\n+int\n+tm_start(struct pmd_internals *p);\n+\n+void\n+tm_stop(struct pmd_internals *p);\n+\n+static inline int\n+tm_used(struct rte_eth_dev *dev)\n+{\n+\tstruct pmd_internals *p = dev->data->dev_private;\n+\n+\treturn (p->params.soft.flags & PMD_FEATURE_TM) &&\n+\t\tp->soft.tm.h.n_tm_nodes[TM_NODE_LEVEL_PORT];\n+}\n+\n #endif /* __INCLUDE_RTE_ETH_SOFTNIC_INTERNALS_H__ */\ndiff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c\nnew file mode 100644\nindex 0000000..bb28798\n--- /dev/null\n+++ b/drivers/net/softnic/rte_eth_softnic_tm.c\n@@ -0,0 +1,181 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <stdint.h>\n+#include <stdlib.h>\n+#include <string.h>\n+\n+#include <rte_malloc.h>\n+\n+#include \"rte_eth_softnic_internals.h\"\n+#include \"rte_eth_softnic.h\"\n+\n+#define BYTES_IN_MBPS (1000 * 1000 / 8)\n+\n+int\n+tm_params_check(struct pmd_params *params, uint32_t hard_rate)\n+{\n+\tuint64_t hard_rate_bytes_per_sec = hard_rate * BYTES_IN_MBPS;\n+\tuint32_t i;\n+\n+\t/* rate */\n+\tif (params->soft.tm.rate) {\n+\t\tif (params->soft.tm.rate > hard_rate_bytes_per_sec)\n+\t\t\treturn -EINVAL;\n+\t} else {\n+\t\tparams->soft.tm.rate =\n+\t\t\t(hard_rate_bytes_per_sec > UINT32_MAX) ?\n+\t\t\t\tUINT32_MAX : hard_rate_bytes_per_sec;\n+\t}\n+\n+\t/* nb_queues */\n+\tif (params->soft.tm.nb_queues == 0)\n+\t\treturn -EINVAL;\n+\n+\tif (params->soft.tm.nb_queues < RTE_SCHED_QUEUES_PER_PIPE)\n+\t\tparams->soft.tm.nb_queues = RTE_SCHED_QUEUES_PER_PIPE;\n+\n+\tparams->soft.tm.nb_queues =\n+\t\trte_align32pow2(params->soft.tm.nb_queues);\n+\n+\t/* qsize */\n+\tfor (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {\n+\t\tif (params->soft.tm.qsize[i] == 0)\n+\t\t\treturn -EINVAL;\n+\n+\t\tparams->soft.tm.qsize[i] =\n+\t\t\trte_align32pow2(params->soft.tm.qsize[i]);\n+\t}\n+\n+\t/* enq_bsz, deq_bsz */\n+\tif ((params->soft.tm.enq_bsz == 0) ||\n+\t\t(params->soft.tm.deq_bsz == 0) ||\n+\t\t(params->soft.tm.deq_bsz >= params->soft.tm.enq_bsz))\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n+int\n+tm_init(struct pmd_internals *p,\n+\tstruct pmd_params *params,\n+\tint numa_node)\n+{\n+\tuint32_t enq_bsz = params->soft.tm.enq_bsz;\n+\tuint32_t deq_bsz = params->soft.tm.deq_bsz;\n+\n+\tp->soft.tm.pkts_enq = rte_zmalloc_socket(params->soft.name,\n+\t\t2 * enq_bsz * sizeof(struct rte_mbuf *),\n+\t\t0,\n+\t\tnuma_node);\n+\n+\tif (p->soft.tm.pkts_enq == NULL)\n+\t\treturn -ENOMEM;\n+\n+\tp->soft.tm.pkts_deq = rte_zmalloc_socket(params->soft.name,\n+\t\tdeq_bsz * sizeof(struct rte_mbuf *),\n+\t\t0,\n+\t\tnuma_node);\n+\n+\tif (p->soft.tm.pkts_deq == NULL) {\n+\t\trte_free(p->soft.tm.pkts_enq);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void\n+tm_free(struct pmd_internals *p)\n+{\n+\trte_free(p->soft.tm.pkts_enq);\n+\trte_free(p->soft.tm.pkts_deq);\n+}\n+\n+int\n+tm_start(struct pmd_internals *p)\n+{\n+\tstruct tm_params *t = &p->soft.tm.params;\n+\tuint32_t n_subports, subport_id;\n+\tint status;\n+\n+\t/* Port */\n+\tp->soft.tm.sched = rte_sched_port_config(&t->port_params);\n+\tif (p->soft.tm.sched == NULL)\n+\t\treturn -1;\n+\n+\t/* Subport */\n+\tn_subports = t->port_params.n_subports_per_port;\n+\tfor (subport_id = 0; subport_id < n_subports; subport_id++) {\n+\t\tuint32_t n_pipes_per_subport =\n+\t\t\tt->port_params.n_pipes_per_subport;\n+\t\tuint32_t pipe_id;\n+\n+\t\tstatus = rte_sched_subport_config(p->soft.tm.sched,\n+\t\t\tsubport_id,\n+\t\t\t&t->subport_params[subport_id]);\n+\t\tif (status) {\n+\t\t\trte_sched_port_free(p->soft.tm.sched);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\t/* Pipe */\n+\t\tn_pipes_per_subport = t->port_params.n_pipes_per_subport;\n+\t\tfor (pipe_id = 0; pipe_id < n_pipes_per_subport; pipe_id++) {\n+\t\t\tint pos = subport_id * TM_MAX_PIPES_PER_SUBPORT +\n+\t\t\t\tpipe_id;\n+\t\t\tint profile_id = t->pipe_to_profile[pos];\n+\n+\t\t\tif (profile_id < 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\tstatus = rte_sched_pipe_config(p->soft.tm.sched,\n+\t\t\t\tsubport_id,\n+\t\t\t\tpipe_id,\n+\t\t\t\tprofile_id);\n+\t\t\tif (status) {\n+\t\t\t\trte_sched_port_free(p->soft.tm.sched);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void\n+tm_stop(struct pmd_internals *p)\n+{\n+\tif (p->soft.tm.sched)\n+\t\trte_sched_port_free(p->soft.tm.sched);\n+}\n",
    "prefixes": [
        "dpdk-dev",
        "v4",
        "2/4"
    ]
}