get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 126670,
    "url": "https://patches.dpdk.org/api/patches/126670/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20230503113840.11010-1-david.coyle@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": "<20230503113840.11010-1-david.coyle@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20230503113840.11010-1-david.coyle@intel.com",
    "date": "2023-05-03T11:38:40",
    "name": "[RFC] ring: adding TPAUSE instruction to ring dequeue",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "5fb7453fb86e1bbad709e4f4dc295adee3d86f66",
    "submitter": {
        "id": 961,
        "url": "https://patches.dpdk.org/api/people/961/?format=api",
        "name": "Coyle, David",
        "email": "david.coyle@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20230503113840.11010-1-david.coyle@intel.com/mbox/",
    "series": [
        {
            "id": 27919,
            "url": "https://patches.dpdk.org/api/series/27919/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=27919",
            "date": "2023-05-03T11:38:40",
            "name": "[RFC] ring: adding TPAUSE instruction to ring dequeue",
            "version": 1,
            "mbox": "https://patches.dpdk.org/series/27919/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/126670/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/126670/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 1FFBE42A4E;\n\tWed,  3 May 2023 13:39:17 +0200 (CEST)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id EFA5F4114B;\n\tWed,  3 May 2023 13:39:16 +0200 (CEST)",
            "from mga18.intel.com (mga18.intel.com [134.134.136.126])\n by mails.dpdk.org (Postfix) with ESMTP id 765F741144\n for <dev@dpdk.org>; Wed,  3 May 2023 13:39:14 +0200 (CEST)",
            "from orsmga008.jf.intel.com ([10.7.209.65])\n by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 03 May 2023 04:39:13 -0700",
            "from silpixa00399912.ir.intel.com (HELO\n silpixa00399912.ger.corp.intel.com) ([10.237.222.169])\n by orsmga008.jf.intel.com with ESMTP; 03 May 2023 04:39:11 -0700"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple;\n d=intel.com; i=@intel.com; q=dns/txt; s=Intel;\n t=1683113954; x=1714649954;\n h=from:to:cc:subject:date:message-id:mime-version:\n content-transfer-encoding;\n bh=jNAmPHs/kKZ0vOgcOwRUqaz/+gvc8T24lZ9StjvRfz8=;\n b=VtbhnQ8Tvk6iAr57qZjFPF3m/bfSOt3IYXtQiU6BEUMAk27Hmnikg5PM\n 5Iyy04Y5s8rp0tAZrr1cx/Ck8wXYoHLUrTcsE+wepRHcp0RjenBApsjRu\n 59B46zzqIJWKINy8NiT8Z157pDHtEAoHCt4ZFINnEAYBlDMTOLcsomsbn\n Rz43QIUWDjkT7Eg+q3lEJdfmKMypwfhLN3cQhPfi4MAuelfDdeg2bz3jk\n fqcK8R4iQ/Q1kH8opUtlWl0VJjjduhJAi5esD8YPLcGVaRL+MiDxrX95V\n iV/7+ZDa3wfSrYtkzPRMTL7t+AAhMGgYfkGgAF0zXKscEKuOcZ+ce98R7 A==;",
        "X-IronPort-AV": [
            "E=McAfee;i=\"6600,9927,10698\"; a=\"332996089\"",
            "E=Sophos;i=\"5.99,247,1677571200\"; d=\"scan'208\";a=\"332996089\"",
            "E=McAfee;i=\"6600,9927,10698\"; a=\"727109556\"",
            "E=Sophos;i=\"5.99,247,1677571200\"; d=\"scan'208\";a=\"727109556\""
        ],
        "X-ExtLoop1": "1",
        "From": "David Coyle <david.coyle@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "honnappa.nagarahalli@arm.com, konstantin.v.ananyev@yandex.ru,\n rory.sexton@intel.com, David Coyle <david.coyle@intel.com>",
        "Subject": "[RFC PATCH] ring: adding TPAUSE instruction to ring dequeue",
        "Date": "Wed,  3 May 2023 11:38:40 +0000",
        "Message-Id": "<20230503113840.11010-1-david.coyle@intel.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "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"
    },
    "content": "This is NOT for upstreaming. This is being submitted to allow early\ncomparison testing with the preferred solution, which will add TAPUSE\npower management support to the ring library through the addition of\ncallbacks. Initial stages of the preferred solution are available at\nhttp://dpdk.org/patch/125454.\n\nThis patch adds functionality directly to rte_ring_dequeue functions to\nmonitor the empty reads of the ring. When a configurable number of\nempty reads is reached, a TPAUSE instruction is triggered by using\nrte_power_pause() on supported architectures. rte_pause() is used on\nother architectures. The functionality can be included or excluded at\ncompilation time using the RTE_RING_PMGMT flag. If included, the new\nAPI can be used to enable/disable the feature on a per-ring basis.\nOther related settings can also be configured using the API.\n\nSigned-off-by: David Coyle <david.coyle@intel.com>\n---\n lib/ring/meson.build      |   4 +-\n lib/ring/rte_ring.h       |  13 +-\n lib/ring/rte_ring_pmgmt.c | 367 ++++++++++++++++++++++++++++++++++++++\n lib/ring/rte_ring_pmgmt.h | 149 ++++++++++++++++\n lib/ring/version.map      |  12 ++\n 5 files changed, 539 insertions(+), 6 deletions(-)\n create mode 100644 lib/ring/rte_ring_pmgmt.c\n create mode 100644 lib/ring/rte_ring_pmgmt.h",
    "diff": "diff --git a/lib/ring/meson.build b/lib/ring/meson.build\nindex c20685c689..087028542c 100644\n--- a/lib/ring/meson.build\n+++ b/lib/ring/meson.build\n@@ -1,8 +1,8 @@\n # SPDX-License-Identifier: BSD-3-Clause\n # Copyright(c) 2017 Intel Corporation\n \n-sources = files('rte_ring.c')\n-headers = files('rte_ring.h')\n+sources = files('rte_ring.c', 'rte_ring_pmgmt.c')\n+headers = files('rte_ring.h', 'rte_ring_pmgmt.h')\n # most sub-headers are not for direct inclusion\n indirect_headers += files (\n         'rte_ring_core.h',\ndiff --git a/lib/ring/rte_ring.h b/lib/ring/rte_ring.h\nindex 7e4cd60650..64dbb5bca2 100644\n--- a/lib/ring/rte_ring.h\n+++ b/lib/ring/rte_ring.h\n@@ -41,6 +41,7 @@ extern \"C\" {\n \n #include <rte_ring_core.h>\n #include <rte_ring_elem.h>\n+#include <rte_ring_pmgmt.h>\n \n /**\n  * Calculate the memory size needed for a ring\n@@ -412,8 +413,10 @@ static __rte_always_inline unsigned int\n rte_ring_dequeue_bulk(struct rte_ring *r, void **obj_table, unsigned int n,\n \t\tunsigned int *available)\n {\n-\treturn rte_ring_dequeue_bulk_elem(r, obj_table, sizeof(void *),\n-\t\t\tn, available);\n+\tuint32_t nb_rx = rte_ring_dequeue_bulk_elem(r, obj_table, sizeof(void *),\n+\t\t\t\t\t\t    n, available);\n+\tRTE_RING_PMGMT_IMPL(nb_rx, r->name);\n+\treturn nb_rx;\n }\n \n /**\n@@ -812,8 +815,10 @@ static __rte_always_inline unsigned int\n rte_ring_dequeue_burst(struct rte_ring *r, void **obj_table,\n \t\tunsigned int n, unsigned int *available)\n {\n-\treturn rte_ring_dequeue_burst_elem(r, obj_table, sizeof(void *),\n-\t\t\tn, available);\n+\tuint32_t nb_rx = rte_ring_dequeue_burst_elem(r, obj_table, sizeof(void *),\n+\t\t\t\t\t\t     n, available);\n+\tRTE_RING_PMGMT_IMPL(nb_rx, r->name);\n+\treturn nb_rx;\n }\n \n #ifdef __cplusplus\ndiff --git a/lib/ring/rte_ring_pmgmt.c b/lib/ring/rte_ring_pmgmt.c\nnew file mode 100644\nindex 0000000000..25d64736d0\n--- /dev/null\n+++ b/lib/ring/rte_ring_pmgmt.c\n@@ -0,0 +1,367 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2020 Intel Corporation\n+ */\n+\n+#include <rte_lcore.h>\n+#include <rte_cycles.h>\n+#include <rte_cpuflags.h>\n+#include <rte_malloc.h>\n+#include <rte_power_intrinsics.h>\n+#include <rte_string_fns.h>\n+\n+#include <rte_ring.h>\n+#include \"rte_ring_pmgmt.h\"\n+\n+static unsigned int emptypoll_max;\n+static unsigned int pause_duration;\n+\n+/* store some internal state */\n+static struct ring_conf_data {\n+\t/** what do we support? */\n+\tstruct rte_cpu_intrinsics intrinsics_support;\n+\t/** pre-calculated tsc diff for 1us */\n+\tuint64_t tsc_per_us;\n+\t/** how many rte_pause can we fit in a microsecond? */\n+\tuint64_t pause_per_us;\n+} global_data;\n+\n+/**\n+ * Possible power management states of a rte ring.\n+ */\n+enum ring_mgmt_state {\n+\t/** Device power management is disabled. */\n+\tRING_MGMT_DISABLED = 0,\n+\t/** Device power management is enabled. */\n+\tRING_MGMT_ENABLED\n+};\n+\n+struct ring {\n+\tchar name[RTE_RING_NAMESIZE] __rte_cache_aligned;\n+};\n+\n+struct ring_list_entry {\n+\tTAILQ_ENTRY(ring_list_entry) next;\n+\tstruct ring ring;\n+\tuint64_t n_empty_polls;\n+\tuint64_t n_sleeps;\n+};\n+\n+struct ring_core_cfg {\n+\tTAILQ_HEAD(ring_list_head, ring_list_entry) head;\n+\t/**< List of rings associated with this lcore */\n+\tsize_t n_rings;\n+\t/**< How many rings are in the list? */\n+\tvolatile enum ring_mgmt_state pwr_mgmt_state;\n+\t/**< State of power management for this ring */\n+\tuint64_t n_rings_ready_to_sleep;\n+\t/**< Number of rings ready to enter power optimized state */\n+\tuint64_t sleep_target;\n+\t/**< Prevent a ring from triggering sleep multiple times */\n+} __rte_cache_aligned;\n+static struct ring_core_cfg lcore_cfgs[RTE_MAX_LCORE];\n+\n+static struct ring_list_entry *\n+ring_list_find(const struct ring_core_cfg *cfg, struct ring *r)\n+{\n+\tstruct ring_list_entry *cur;\n+\n+\tTAILQ_FOREACH(cur, &cfg->head, next) {\n+\t\tif (strcmp(cur->ring.name, r->name) == 0)\n+\t\t\treturn cur;\n+\t}\n+\treturn NULL;\n+}\n+\n+static int\n+ring_list_add(struct ring_core_cfg *cfg, struct ring *r)\n+{\n+\tstruct ring_list_entry *rle;\n+\n+\t/* is it already in the list? */\n+\tif (ring_list_find(cfg, r) != NULL)\n+\t\treturn -EEXIST;\n+\n+\trle = malloc(sizeof(*rle));\n+\tif (rle == NULL)\n+\t\treturn -ENOMEM;\n+\tmemset(rle, 0, sizeof(*rle));\n+\n+\trte_strscpy(rle->ring.name, r->name, sizeof(r->name));\n+\tTAILQ_INSERT_TAIL(&cfg->head, rle, next);\n+\tcfg->n_rings++;\n+\n+\treturn 0;\n+}\n+\n+static struct ring_list_entry *\n+ring_list_take(struct ring_core_cfg *cfg, struct ring *r)\n+{\n+\tstruct ring_list_entry *found;\n+\n+\tfound = ring_list_find(cfg, r);\n+\tif (found == NULL)\n+\t\treturn NULL;\n+\n+\tTAILQ_REMOVE(&cfg->head, found, next);\n+\tcfg->n_rings--;\n+\n+\t/* freeing is responsibility of the caller */\n+\treturn found;\n+}\n+\n+static void\n+calc_tsc(void)\n+{\n+\tconst uint64_t hz = rte_get_timer_hz();\n+\tconst uint64_t tsc_per_us = hz / US_PER_S; /* 1us */\n+\n+\tglobal_data.tsc_per_us = tsc_per_us;\n+\n+\t/* only do this if we don't have tpause */\n+\tif (!global_data.intrinsics_support.power_pause) {\n+\t\tconst uint64_t start = rte_rdtsc_precise();\n+\t\tconst uint32_t n_pauses = 10000;\n+\t\tdouble us, us_per_pause;\n+\t\tuint64_t end;\n+\t\tunsigned int i;\n+\n+\t\t/* estimate number of rte_pause() calls per us */\n+\t\tfor (i = 0; i < n_pauses; i++)\n+\t\t\trte_pause();\n+\n+\t\tend = rte_rdtsc_precise();\n+\t\tus = (end - start) / (double)tsc_per_us;\n+\t\tus_per_pause = us / n_pauses;\n+\n+\t\tglobal_data.pause_per_us = (uint64_t)(1.0 / us_per_pause);\n+\t}\n+}\n+\n+static inline void\n+ring_reset(struct ring_core_cfg *cfg, struct ring_list_entry *rcfg)\n+{\n+\tconst bool is_ready_to_sleep = rcfg->n_sleeps == cfg->sleep_target;\n+\n+\t/* reset empty poll counter for this ring */\n+\trcfg->n_empty_polls = 0;\n+\t/* reset the ring sleep counter as well */\n+\trcfg->n_sleeps = 0;\n+\t/* remove the ring from list of rings ready to sleep */\n+\tif (is_ready_to_sleep)\n+\t\tcfg->n_rings_ready_to_sleep--;\n+\t/*\n+\t * no need change the lcore sleep target counter because this lcore will\n+\t * reach the n_sleeps anyway, and the other cores are already counted so\n+\t * there's no need to do anything else.\n+\t */\n+}\n+\n+static inline bool\n+ring_can_sleep(struct ring_core_cfg *cfg, struct ring_list_entry *rcfg)\n+{\n+\t/* this function is called - that means we have an empty poll */\n+\trcfg->n_empty_polls++;\n+\n+\t/* if we haven't reached threshold for empty polls, we can't sleep */\n+\tif (rcfg->n_empty_polls <= emptypoll_max)\n+\t\treturn false;\n+\n+\t/*\n+\t * we've reached a point where we are able to sleep, but we still need\n+\t * to check if this ring has already been marked for sleeping.\n+\t */\n+\tif (rcfg->n_sleeps == cfg->sleep_target)\n+\t\treturn true;\n+\n+\t/* mark this ring as ready for sleep */\n+\trcfg->n_sleeps = cfg->sleep_target;\n+\tcfg->n_rings_ready_to_sleep++;\n+\n+\treturn true;\n+}\n+\n+static inline bool\n+lcore_can_sleep(struct ring_core_cfg *cfg)\n+{\n+\t/* are all rings ready to sleep? */\n+\tif (cfg->n_rings_ready_to_sleep != cfg->n_rings)\n+\t\treturn false;\n+\n+\t/* we've reached an iteration where we can sleep, reset sleep counter */\n+\tcfg->n_rings_ready_to_sleep = 0;\n+\tcfg->sleep_target++;\n+\t/*\n+\t * we do not reset any individual ring empty poll counters, because\n+\t * we want to keep sleeping on every poll until we actually get traffic.\n+\t */\n+\n+\treturn true;\n+}\n+\n+static void\n+pause_implement(uint32_t nb_rx, char *ring_name)\n+{\n+\tconst unsigned int lcore = rte_lcore_id();\n+\tstruct ring_list_entry *rle;\n+\tstruct ring_core_cfg *lcore_conf;\n+\tconst bool empty = nb_rx == 0;\n+\tuint32_t pause_duration = rte_ring_pmgmt_get_pause_duration();\n+\tstruct ring r;\n+\n+\tlcore_conf = &lcore_cfgs[lcore];\n+\trte_strscpy(r.name, ring_name, sizeof(ring_name));\n+\trle = ring_list_find(lcore_conf, &r);\n+\tif (rle == NULL)\n+\t\treturn;\n+\n+\tif (likely(!empty)) {\n+\t\t/* early exit */\n+\t\tring_reset(lcore_conf, rle);\n+\t} else {\n+\t\t/* can this ring sleep? */\n+\t\tif (!ring_can_sleep(lcore_conf, rle))\n+\t\t\treturn;\n+\n+\t\t/* can this lcore sleep? */\n+\t\tif (!lcore_can_sleep(lcore_conf))\n+\t\t\treturn;\n+\n+\t\t/* sleep for pause_duration microseconds, use tpause if we have it */\n+\t\tif (global_data.intrinsics_support.power_pause) {\n+\t\t\tconst uint64_t cur = rte_rdtsc();\n+\t\t\tconst uint64_t wait_tsc =\n+\t\t\t\t\tcur + global_data.tsc_per_us * pause_duration;\n+\t\t\trte_power_pause(wait_tsc);\n+\t\t} else {\n+\t\t\tuint64_t i;\n+\t\t\tfor (i = 0; i < global_data.pause_per_us * pause_duration; i++)\n+\t\t\t\trte_pause();\n+\t\t}\n+\t}\n+}\n+\n+int\n+rte_ring_pmgmt_ring_enable(unsigned int lcore_id, char *ring_name)\n+{\n+\tstruct ring_core_cfg *lcore_conf;\n+\tstruct ring r;\n+\tint ret;\n+\n+\tif (lcore_id >= RTE_MAX_LCORE)\n+\t\treturn -EINVAL;\n+\n+\tlcore_conf = &lcore_cfgs[lcore_id];\n+\n+\t/* we need this in various places */\n+\trte_cpu_get_intrinsics_support(&global_data.intrinsics_support);\n+\n+\t/* figure out various time-to-tsc conversions */\n+\tif (global_data.tsc_per_us == 0)\n+\t\tcalc_tsc();\n+\n+\t/* add this ring to the list */\n+\trte_strscpy(r.name, ring_name, sizeof(ring_name));\n+\tret = ring_list_add(lcore_conf, &r);\n+\tif (ret < 0) {\n+\t\tRTE_LOG(DEBUG, POWER, \"Failed to add ring to list: %s\\n\",\n+\t\t\t\tstrerror(-ret));\n+\t\treturn ret;\n+\t}\n+\t/* new ring is always added last */\n+\tTAILQ_LAST(&lcore_conf->head, ring_list_head);\n+\n+\t/* when enabling first ring, ensure sleep target is not 0 */\n+\tif (lcore_conf->n_rings == 1 && lcore_conf->sleep_target == 0)\n+\t\tlcore_conf->sleep_target = 1;\n+\n+\t/* initialize data before enabling the callback */\n+\tif (lcore_conf->n_rings == 1)\n+\t\tlcore_conf->pwr_mgmt_state = RING_MGMT_ENABLED;\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_ring_pmgmt_ring_disable(unsigned int lcore_id, char *ring_name)\n+{\n+\tstruct ring_list_entry *rle;\n+\tstruct ring_core_cfg *lcore_conf;\n+\tstruct ring r;\n+\n+\tif (lcore_id >= RTE_MAX_LCORE)\n+\t\treturn -EINVAL;\n+\n+\tlcore_conf = &lcore_cfgs[lcore_id];\n+\n+\tif (lcore_conf->pwr_mgmt_state != RING_MGMT_ENABLED)\n+\t\treturn -EINVAL;\n+\n+\t/*\n+\t * There is no good/easy way to do this without race conditions, so we\n+\t * are just going to throw our hands in the air and hope that the user\n+\t * has read the documentation and has ensured that ring is not being\n+\t * used at the time we enter the API functions.\n+\t */\n+\trte_strscpy(r.name, ring_name, sizeof(ring_name));\n+\trle = ring_list_take(lcore_conf, &r);\n+\tif (rle == NULL)\n+\t\treturn -ENOENT;\n+\n+\t/* if we've removed all rings from the lists, set state to disabled */\n+\tif (lcore_conf->n_rings == 0)\n+\t\tlcore_conf->pwr_mgmt_state = RING_MGMT_DISABLED;\n+\n+\tfree(rle);\n+\n+\treturn 0;\n+}\n+\n+void\n+rte_ring_pmgmt_set_emptypoll_max(unsigned int max)\n+{\n+\temptypoll_max = max;\n+}\n+\n+unsigned int\n+rte_ring_pmgmt_get_emptypoll_max(void)\n+{\n+\treturn emptypoll_max;\n+}\n+\n+int\n+rte_ring_pmgmt_set_pause_duration(unsigned int duration)\n+{\n+\tif (duration == 0) {\n+\t\tRTE_LOG(ERR, POWER, \"Pause duration must be greater than 0, value unchanged\");\n+\t\treturn -EINVAL;\n+\t}\n+\tpause_duration = duration;\n+\n+\treturn 0;\n+}\n+\n+unsigned int\n+rte_ring_pmgmt_get_pause_duration(void)\n+{\n+\treturn pause_duration;\n+}\n+\n+void\n+rte_ring_pmgmt_impl(uint32_t nb_rx, char *ring_name)\n+{\n+\tpause_implement(nb_rx, ring_name);\n+}\n+\n+RTE_INIT(rte_ring_pmgmt_init) {\n+\tsize_t i;\n+\n+\t/* initialize all tailqs */\n+\tfor (i = 0; i < RTE_DIM(lcore_cfgs); i++) {\n+\t\tstruct ring_core_cfg *cfg = &lcore_cfgs[i];\n+\t\tTAILQ_INIT(&cfg->head);\n+\t}\n+\n+\t/* initialize config defaults */\n+\temptypoll_max = 512;\n+\tpause_duration = 1;\n+}\ndiff --git a/lib/ring/rte_ring_pmgmt.h b/lib/ring/rte_ring_pmgmt.h\nnew file mode 100644\nindex 0000000000..faa0515e5b\n--- /dev/null\n+++ b/lib/ring/rte_ring_pmgmt.h\n@@ -0,0 +1,149 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2020 Intel Corporation\n+ */\n+\n+#ifndef _RTE_RING_PMGMT_H\n+#define _RTE_RING_PMGMT_H\n+\n+/**\n+ * @file\n+ * Ring Power Management\n+ */\n+\n+#include <stdint.h>\n+\n+#include <rte_log.h>\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+/** Enable/disable ring power management */\n+#define RTE_RING_PMGMT 1\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice.\n+ *\n+ * Enable power management on a specified ring and lcore.\n+ *\n+ * @note This function is not thread-safe.\n+ *\n+ * @note Only pause mode is currently supported.\n+ *\n+ * @param lcore_id\n+ *   The lcore the Rx queue will be polled from.\n+ * @param ring_name\n+ *   The name of the ring.\n+ * @return\n+ *   0 on success\n+ *   <0 on error\n+ */\n+__rte_experimental\n+int\n+rte_ring_pmgmt_ring_enable(unsigned int lcore_id, char *ring_name);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice.\n+ *\n+ * Disable power management on a specified ring and lcore.\n+ *\n+ * @note This function is not thread-safe.\n+ *\n+ * @param lcore_id\n+ *   The lcore the Rx queue is polled from.\n+ * @param ring_name\n+ *   The name of the ring.\n+ * @return\n+ *   0 on success\n+ *   <0 on error\n+ */\n+__rte_experimental\n+int\n+rte_ring_pmgmt_ring_disable(unsigned int lcore_id, char *ring_name);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice.\n+ *\n+ * Set a emptypoll_max to specified value. Used to specify the number of empty\n+ * polls to wait before invoking the power management.\n+ *\n+ * @param max\n+ *   The value to set emptypoll_max to.\n+ */\n+__rte_experimental\n+void\n+rte_ring_pmgmt_set_emptypoll_max(unsigned int max);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice.\n+ *\n+ * Get the current value of emptypoll_max.\n+ *\n+ * @return\n+ *   The current emptypoll_max value\n+ */\n+__rte_experimental\n+unsigned int\n+rte_ring_pmgmt_get_emptypoll_max(void);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice.\n+ *\n+ * Set the pause_duration. Used to adjust the pause mode callback duration.\n+ *\n+ * @note Duration must be greater than zero.\n+ *\n+ * @param duration\n+ *   The value to set pause_duration to.\n+ * @return\n+ *   0 on success\n+ *   <0 on error\n+ */\n+__rte_experimental\n+int\n+rte_ring_pmgmt_set_pause_duration(unsigned int duration);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice.\n+ *\n+ * Get the current value of pause_duration.\n+ *\n+ * @return\n+ *   The current pause_duration value.\n+ */\n+__rte_experimental\n+unsigned int\n+rte_ring_pmgmt_get_pause_duration(void);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice.\n+ *\n+ * Runs the power management algorithm for the specified ring.\n+ *\n+ * @param nb_rx\n+ *   The number of packets read from the ring.\n+ * @param ring_name\n+ *   The name of the ring.\n+ */\n+__rte_experimental\n+void\n+rte_ring_pmgmt_impl(uint32_t nb_rx, char *ring_name);\n+\n+#ifdef RTE_RING_PMGMT\n+#define RTE_RING_PMGMT_IMPL(nb_rx, r) rte_ring_pmgmt_impl(nb_rx, r)\n+#else\n+#define RTE_RING_PMGMT_IMPL(nb_rx, r)\n+#endif\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif\ndiff --git a/lib/ring/version.map b/lib/ring/version.map\nindex 4d7c27a6d9..471ba9514e 100644\n--- a/lib/ring/version.map\n+++ b/lib/ring/version.map\n@@ -14,3 +14,15 @@ DPDK_23 {\n \n \tlocal: *;\n };\n+\n+EXPERIMENTAL {\n+\tglobal:\n+\n+\trte_ring_pmgmt_ring_enable;\n+\trte_ring_pmgmt_ring_disable;\n+\trte_ring_pmgmt_set_emptypoll_max;\n+\trte_ring_pmgmt_get_emptypoll_max;\n+\trte_ring_pmgmt_set_pause_duration;\n+\trte_ring_pmgmt_get_pause_duration;\n+\trte_ring_pmgmt_impl;\n+};\n",
    "prefixes": [
        "RFC"
    ]
}