get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 36895,
    "url": "https://patches.dpdk.org/api/patches/36895/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1522697994-22515-6-git-send-email-erik.g.carrillo@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": "<1522697994-22515-6-git-send-email-erik.g.carrillo@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1522697994-22515-6-git-send-email-erik.g.carrillo@intel.com",
    "date": "2018-04-02T19:39:50",
    "name": "[dpdk-dev,v9,5/9] eventtimer: add default software driver",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "b0bcf09442c062e434a8aa8d2388b22a65aab4db",
    "submitter": {
        "id": 762,
        "url": "https://patches.dpdk.org/api/people/762/?format=api",
        "name": "Carrillo, Erik G",
        "email": "erik.g.carrillo@intel.com"
    },
    "delegate": {
        "id": 310,
        "url": "https://patches.dpdk.org/api/users/310/?format=api",
        "username": "jerin",
        "first_name": "Jerin",
        "last_name": "Jacob",
        "email": "jerinj@marvell.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1522697994-22515-6-git-send-email-erik.g.carrillo@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/36895/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/36895/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 8E5131B3F3;\n\tMon,  2 Apr 2018 21:40:13 +0200 (CEST)",
            "from mga12.intel.com (mga12.intel.com [192.55.52.136])\n\tby dpdk.org (Postfix) with ESMTP id BB62D1B2A7\n\tfor <dev@dpdk.org>; Mon,  2 Apr 2018 21:40:04 +0200 (CEST)",
            "from fmsmga005.fm.intel.com ([10.253.24.32])\n\tby fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t02 Apr 2018 12:40:03 -0700",
            "from txasoft-yocto.an.intel.com (HELO txasoft-yocto.an.intel.com.)\n\t([10.123.72.192])\n\tby fmsmga005.fm.intel.com with ESMTP; 02 Apr 2018 12:40:03 -0700"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.48,396,1517904000\"; d=\"scan'208\";a=\"217040203\"",
        "From": "Erik Gabriel Carrillo <erik.g.carrillo@intel.com>",
        "To": "pbhagavatula@caviumnetworks.com",
        "Cc": "dev@dpdk.org,\n\tjerin.jacob@caviumnetworks.com,\n\themant.agrawal@nxp.com",
        "Date": "Mon,  2 Apr 2018 14:39:50 -0500",
        "Message-Id": "<1522697994-22515-6-git-send-email-erik.g.carrillo@intel.com>",
        "X-Mailer": "git-send-email 1.7.10",
        "In-Reply-To": "<1522697994-22515-1-git-send-email-erik.g.carrillo@intel.com>",
        "References": "<1522358852-3630-1-git-send-email-erik.g.carrillo@intel.com>\n\t<1522697994-22515-1-git-send-email-erik.g.carrillo@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v9 5/9] eventtimer: add default software driver",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://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": "<https://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": "If an eventdev PMD does not wish to provide event timer adapter ops\ndefinitions, the library will fall back to a default software\nimplementation whose entry points are added by this commit.\n\nSigned-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>\n---\n lib/Makefile                                  |   2 +-\n lib/librte_eventdev/Makefile                  |   2 +-\n lib/librte_eventdev/rte_event_timer_adapter.c | 909 ++++++++++++++++++++++++++\n lib/librte_eventdev/rte_event_timer_adapter.h |  57 +-\n 4 files changed, 966 insertions(+), 4 deletions(-)",
    "diff": "diff --git a/lib/Makefile b/lib/Makefile\nindex ec965a6..965be6c 100644\n--- a/lib/Makefile\n+++ b/lib/Makefile\n@@ -31,7 +31,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf\n DEPDIRS-librte_security += librte_ether\n DEPDIRS-librte_security += librte_cryptodev\n DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev\n-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash\n+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool librte_timer\n DIRS-$(CONFIG_RTE_LIBRTE_RAWDEV) += librte_rawdev\n DEPDIRS-librte_rawdev := librte_eal librte_ether\n DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost\ndiff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile\nindex 8b16e3f..297df4a 100644\n--- a/lib/librte_eventdev/Makefile\n+++ b/lib/librte_eventdev/Makefile\n@@ -14,7 +14,7 @@ LIBABIVER := 3\n CFLAGS += -DALLOW_EXPERIMENTAL_API\n CFLAGS += -O3\n CFLAGS += $(WERROR_FLAGS)\n-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash\n+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool -lrte_timer\n \n # library source files\n SRCS-y += rte_eventdev.c\ndiff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c\nindex 75a14ac..24993c1 100644\n--- a/lib/librte_eventdev/rte_event_timer_adapter.c\n+++ b/lib/librte_eventdev/rte_event_timer_adapter.c\n@@ -5,11 +5,20 @@\n \n #include <string.h>\n #include <inttypes.h>\n+#include <stdbool.h>\n+#include <sys/queue.h>\n \n #include <rte_memzone.h>\n #include <rte_memory.h>\n #include <rte_dev.h>\n #include <rte_errno.h>\n+#include <rte_malloc.h>\n+#include <rte_ring.h>\n+#include <rte_mempool.h>\n+#include <rte_common.h>\n+#include <rte_timer.h>\n+#include <rte_service_component.h>\n+#include <rte_cycles.h>\n \n #include \"rte_eventdev.h\"\n #include \"rte_eventdev_pmd.h\"\n@@ -20,9 +29,13 @@\n #define DATA_MZ_NAME_FORMAT \"rte_event_timer_adapter_data_%d\"\n \n static int evtim_logtype;\n+static int evtim_svc_logtype;\n+static int evtim_buffer_logtype;\n \n static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];\n \n+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;\n+\n #define EVTIM_LOG(level, logtype, ...) \\\n \trte_log(RTE_LOG_ ## level, logtype, \\\n \t\tRTE_FMT(\"EVTIMER: %s() line %u: \" RTE_FMT_HEAD(__VA_ARGS__,) \\\n@@ -33,8 +46,14 @@ static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];\n #ifdef RTE_LIBRTE_EVENTDEV_DEBUG\n #define EVTIM_LOG_DBG(...) \\\n \tEVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)\n+#define EVTIM_BUF_LOG_DBG(...) \\\n+\tEVTIM_LOG(DEBUG, evtim_buffer_logtype, __VA_ARGS__)\n+#define EVTIM_SVC_LOG_DBG(...) \\\n+\tEVTIM_LOG(DEBUG, evtim_svc_logtype, __VA_ARGS__)\n #else\n #define EVTIM_LOG_DBG(...) (void)0\n+#define EVTIM_BUF_LOG_DBG(...) (void)0\n+#define EVTIM_SVC_LOG_DBG(...) (void)0\n #endif\n \n static int\n@@ -188,6 +207,12 @@ rte_event_timer_adapter_create_ext(\n \t\t}\n \t}\n \n+\t/* If eventdev PMD did not provide ops, use default software\n+\t * implementation.\n+\t */\n+\tif (adapter->ops == NULL)\n+\t\tadapter->ops = &sw_event_adapter_timer_ops;\n+\n \t/* Allow driver to do some setup */\n \tFUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);\n \tret = adapter->ops->init(adapter);\n@@ -305,6 +330,12 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)\n \t\treturn NULL;\n \t}\n \n+\t/* If eventdev PMD did not provide ops, use default software\n+\t * implementation.\n+\t */\n+\tif (adapter->ops == NULL)\n+\t\tadapter->ops = &sw_event_adapter_timer_ops;\n+\n \t/* Set fast-path function pointers */\n \tadapter->arm_burst = adapter->ops->arm_burst;\n \tadapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;\n@@ -377,6 +408,875 @@ rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)\n \treturn adapter->ops->stats_reset(adapter);\n }\n \n+/*\n+ * Software event timer adapter buffer helper functions\n+ */\n+\n+#define NSECPERSEC 1E9\n+\n+/* Optimizations used to index into the buffer require that the buffer size\n+ * be a power of 2.\n+ */\n+#define EVENT_BUFFER_SZ 4096\n+#define EVENT_BUFFER_BATCHSZ 32\n+#define EVENT_BUFFER_MASK (EVENT_BUFFER_SZ - 1)\n+\n+struct event_buffer {\n+\tuint16_t head;\n+\tuint16_t tail;\n+\tstruct rte_event events[EVENT_BUFFER_SZ];\n+} __rte_cache_aligned;\n+\n+static inline bool\n+event_buffer_full(struct event_buffer *bufp)\n+{\n+\treturn (bufp->head - bufp->tail) == EVENT_BUFFER_SZ;\n+}\n+\n+static inline bool\n+event_buffer_batch_ready(struct event_buffer *bufp)\n+{\n+\treturn (bufp->head - bufp->tail) >= EVENT_BUFFER_BATCHSZ;\n+}\n+\n+static void\n+event_buffer_init(struct event_buffer *bufp)\n+{\n+\tbufp->head = bufp->tail = 0;\n+\tmemset(&bufp->events, 0, sizeof(struct rte_event) * EVENT_BUFFER_SZ);\n+}\n+\n+static int\n+event_buffer_add(struct event_buffer *bufp, struct rte_event *eventp)\n+{\n+\tuint16_t head_idx;\n+\tstruct rte_event *buf_eventp;\n+\n+\tif (event_buffer_full(bufp))\n+\t\treturn -1;\n+\n+\t/* Instead of modulus, bitwise AND with mask to get head_idx. */\n+\thead_idx = bufp->head & EVENT_BUFFER_MASK;\n+\tbuf_eventp = &bufp->events[head_idx];\n+\trte_memcpy(buf_eventp, eventp, sizeof(struct rte_event));\n+\n+\t/* Wrap automatically when overflow occurs. */\n+\tbufp->head++;\n+\n+\treturn 0;\n+}\n+\n+static void\n+event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,\n+\t\t   uint16_t *nb_events_flushed,\n+\t\t   uint16_t *nb_events_inv)\n+{\n+\tuint16_t head_idx, tail_idx, n = 0;\n+\tstruct rte_event *events = bufp->events;\n+\n+\t/* Instead of modulus, bitwise AND with mask to get index. */\n+\thead_idx = bufp->head & EVENT_BUFFER_MASK;\n+\ttail_idx = bufp->tail & EVENT_BUFFER_MASK;\n+\n+\t/* Determine the largest contigous run we can attempt to enqueue to the\n+\t * event device.\n+\t */\n+\tif (head_idx > tail_idx)\n+\t\tn = head_idx - tail_idx;\n+\telse if (head_idx < tail_idx)\n+\t\tn = EVENT_BUFFER_SZ - tail_idx;\n+\telse {\n+\t\t*nb_events_flushed = 0;\n+\t\treturn;\n+\t}\n+\n+\t*nb_events_inv = 0;\n+\t*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,\n+\t\t\t\t\t\t     &events[tail_idx], n);\n+\tif (*nb_events_flushed != n && rte_errno == -EINVAL) {\n+\t\tEVTIM_LOG_ERR(\"failed to enqueue invalid event - dropping it\");\n+\t\t(*nb_events_inv)++;\n+\t}\n+\n+\tbufp->tail = bufp->tail + *nb_events_flushed + *nb_events_inv;\n+}\n+\n+/*\n+ * Software event timer adapter implementation\n+ */\n+\n+struct rte_event_timer_adapter_sw_data {\n+\t/* List of messages for outstanding timers */\n+\tTAILQ_HEAD(, msg) msgs_tailq_head;\n+\t/* Lock to guard tailq and armed count */\n+\trte_spinlock_t msgs_tailq_sl;\n+\t/* Identifier of service executing timer management logic. */\n+\tuint32_t service_id;\n+\t/* The cycle count at which the adapter should next tick */\n+\tuint64_t next_tick_cycles;\n+\t/* Incremented as the service moves through phases of an iteration */\n+\tvolatile int service_phase;\n+\t/* The tick resolution used by adapter instance. May have been\n+\t * adjusted from what user requested\n+\t */\n+\tuint64_t timer_tick_ns;\n+\t/* Maximum timeout in nanoseconds allowed by adapter instance. */\n+\tuint64_t max_tmo_ns;\n+\t/* Ring containing messages to arm or cancel event timers */\n+\tstruct rte_ring *msg_ring;\n+\t/* Mempool containing msg objects */\n+\tstruct rte_mempool *msg_pool;\n+\t/* Buffered timer expiry events to be enqueued to an event device. */\n+\tstruct event_buffer buffer;\n+\t/* Statistics */\n+\tstruct rte_event_timer_adapter_stats stats;\n+\t/* The number of threads currently adding to the message ring */\n+\trte_atomic16_t message_producer_count;\n+};\n+\n+enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};\n+\n+struct msg {\n+\tenum msg_type type;\n+\tstruct rte_event_timer *evtim;\n+\tstruct rte_timer tim;\n+\tTAILQ_ENTRY(msg) msgs;\n+};\n+\n+static void\n+sw_event_timer_cb(struct rte_timer *tim, void *arg)\n+{\n+\tint ret;\n+\tuint16_t nb_evs_flushed = 0;\n+\tuint16_t nb_evs_invalid = 0;\n+\tstruct rte_event_timer *evtim;\n+\tstruct rte_event_timer_adapter *adapter;\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\n+\tevtim = arg;\n+\tadapter = (struct rte_event_timer_adapter *)evtim->impl_opaque[1];\n+\tsw_data = adapter->data->adapter_priv;\n+\n+\tret = event_buffer_add(&sw_data->buffer, &evtim->ev);\n+\tif (ret < 0) {\n+\t\t/* If event buffer is full, put timer back in list with\n+\t\t * immediate expiry value, so that we process it again on the\n+\t\t * next iteration.\n+\t\t */\n+\t\trte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),\n+\t\t\t\t     sw_event_timer_cb, evtim);\n+\n+\t\tsw_data->stats.evtim_retry_count++;\n+\t\tEVTIM_LOG_DBG(\"event buffer full, resetting rte_timer with \"\n+\t\t\t      \"immediate expiry value\");\n+\t} else {\n+\t\tstruct msg *m = container_of(tim, struct msg, tim);\n+\t\tTAILQ_REMOVE(&sw_data->msgs_tailq_head, m, msgs);\n+\t\tEVTIM_BUF_LOG_DBG(\"buffered an event timer expiry event\");\n+\t\tevtim->state = RTE_EVENT_TIMER_NOT_ARMED;\n+\n+\t\t/* Free the msg object containing the rte_timer now that\n+\t\t * we've buffered its event successfully.\n+\t\t */\n+\t\trte_mempool_put(sw_data->msg_pool, m);\n+\n+\t\t/* Bump the count when we successfully add an expiry event to\n+\t\t * the buffer.\n+\t\t */\n+\t\tsw_data->stats.evtim_exp_count++;\n+\t}\n+\n+\tif (event_buffer_batch_ready(&sw_data->buffer)) {\n+\t\tevent_buffer_flush(&sw_data->buffer,\n+\t\t\t\t   adapter->data->event_dev_id,\n+\t\t\t\t   adapter->data->event_port_id,\n+\t\t\t\t   &nb_evs_flushed,\n+\t\t\t\t   &nb_evs_invalid);\n+\n+\t\tsw_data->stats.ev_enq_count += nb_evs_flushed;\n+\t\tsw_data->stats.ev_inv_count += nb_evs_invalid;\n+\t}\n+}\n+\n+static __rte_always_inline uint64_t\n+get_timeout_cycles(struct rte_event_timer *evtim,\n+\t\t   struct rte_event_timer_adapter *adapter)\n+{\n+\tuint64_t timeout_ns;\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\n+\tsw_data = adapter->data->adapter_priv;\n+\ttimeout_ns = evtim->timeout_ticks * sw_data->timer_tick_ns;\n+\treturn timeout_ns * rte_get_timer_hz() / NSECPERSEC;\n+\n+}\n+\n+/* This function returns true if one or more (adapter) ticks have occurred since\n+ * the last time it was called.\n+ */\n+static inline bool\n+adapter_did_tick(struct rte_event_timer_adapter *adapter)\n+{\n+\tuint64_t cycles_per_adapter_tick, start_cycles;\n+\tuint64_t *next_tick_cyclesp;\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\n+\tsw_data = adapter->data->adapter_priv;\n+\tnext_tick_cyclesp = &sw_data->next_tick_cycles;\n+\n+\tcycles_per_adapter_tick = sw_data->timer_tick_ns *\n+\t\t\t(rte_get_timer_hz() / NSECPERSEC);\n+\n+\tstart_cycles = rte_get_timer_cycles();\n+\n+\t/* Note: initially, *next_tick_cyclesp == 0, so the clause below will\n+\t * execute, and set things going.\n+\t */\n+\n+\tif (start_cycles >= *next_tick_cyclesp) {\n+\t\t/* Snap the current cycle count to the preceding adapter tick\n+\t\t * boundary.\n+\t\t */\n+\t\tstart_cycles -= start_cycles % cycles_per_adapter_tick;\n+\n+\t\t*next_tick_cyclesp = start_cycles + cycles_per_adapter_tick;\n+\n+\t\treturn true;\n+\t}\n+\n+\treturn false;\n+}\n+\n+/* Check that event timer timeout value is in range */\n+static __rte_always_inline int\n+check_timeout(struct rte_event_timer *evtim,\n+\t      const struct rte_event_timer_adapter *adapter)\n+{\n+\tuint64_t tmo_nsec;\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\n+\tsw_data = adapter->data->adapter_priv;\n+\ttmo_nsec = evtim->timeout_ticks * sw_data->timer_tick_ns;\n+\n+\tif (tmo_nsec > sw_data->max_tmo_ns)\n+\t\treturn -1;\n+\n+\tif (tmo_nsec < sw_data->timer_tick_ns)\n+\t\treturn -2;\n+\n+\treturn 0;\n+}\n+\n+/* Check that event timer event queue sched type matches destination event queue\n+ * sched type\n+ */\n+static __rte_always_inline int\n+check_destination_event_queue(struct rte_event_timer *evtim,\n+\t\t\t      const struct rte_event_timer_adapter *adapter)\n+{\n+\tint ret;\n+\tuint32_t sched_type;\n+\n+\tret = rte_event_queue_attr_get(adapter->data->event_dev_id,\n+\t\t\t\t       evtim->ev.queue_id,\n+\t\t\t\t       RTE_EVENT_QUEUE_ATTR_SCHEDULE_TYPE,\n+\t\t\t\t       &sched_type);\n+\n+\tif ((ret < 0 && ret != -EOVERFLOW) ||\n+\t    evtim->ev.sched_type != sched_type)\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n+#define NB_OBJS 32\n+static int\n+sw_event_timer_adapter_service_func(void *arg)\n+{\n+\tint ret, i, num_msgs;\n+\tuint64_t cycles;\n+\tuint16_t nb_evs_flushed = 0;\n+\tuint16_t nb_evs_invalid = 0;\n+\tstruct rte_event_timer_adapter *adapter;\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\tstruct rte_event_timer *evtim = NULL;\n+\tstruct rte_timer *tim = NULL;\n+\tstruct msg *msg, *msgs[NB_OBJS];\n+\n+\tRTE_SET_USED(ret);\n+\n+\tadapter = arg;\n+\tsw_data = adapter->data->adapter_priv;\n+\n+\tsw_data->service_phase = 1;\n+\trte_smp_wmb();\n+\n+\twhile (rte_atomic16_read(&sw_data->message_producer_count) > 0 ||\n+\t       !rte_ring_empty(sw_data->msg_ring)) {\n+\n+\t\tnum_msgs = rte_ring_dequeue_burst(sw_data->msg_ring,\n+\t\t\t\t\t\t  (void **)msgs, NB_OBJS, NULL);\n+\n+\t\tfor (i = 0; i < num_msgs; i++) {\n+\t\t\tmsg = msgs[i];\n+\t\t\tevtim = msg->evtim;\n+\n+\t\t\tswitch (msg->type) {\n+\t\t\tcase MSG_TYPE_ARM:\n+\t\t\t\tEVTIM_SVC_LOG_DBG(\"dequeued ARM message from \"\n+\t\t\t\t\t\t  \"ring\");\n+\t\t\t\ttim = &msg->tim;\n+\t\t\t\trte_timer_init(tim);\n+\t\t\t\tcycles = get_timeout_cycles(evtim,\n+\t\t\t\t\t\t\t    adapter);\n+\t\t\t\tret = rte_timer_reset(tim, cycles, SINGLE,\n+\t\t\t\t\t\t      rte_lcore_id(),\n+\t\t\t\t\t\t      sw_event_timer_cb,\n+\t\t\t\t\t\t      evtim);\n+\t\t\t\tRTE_ASSERT(ret == 0);\n+\n+\t\t\t\tevtim->impl_opaque[0] = (uintptr_t)tim;\n+\t\t\t\tevtim->impl_opaque[1] = (uintptr_t)adapter;\n+\n+\t\t\t\tTAILQ_INSERT_TAIL(&sw_data->msgs_tailq_head,\n+\t\t\t\t\t\t  msg,\n+\t\t\t\t\t\t  msgs);\n+\t\t\t\tbreak;\n+\t\t\tcase MSG_TYPE_CANCEL:\n+\t\t\t\tEVTIM_SVC_LOG_DBG(\"dequeued CANCEL message \"\n+\t\t\t\t\t\t  \"from ring\");\n+\t\t\t\ttim = (struct rte_timer *)evtim->impl_opaque[0];\n+\t\t\t\tRTE_ASSERT(tim != NULL);\n+\n+\t\t\t\tret = rte_timer_stop(tim);\n+\t\t\t\tRTE_ASSERT(ret == 0);\n+\n+\t\t\t\t/* Free the msg object for the original arm\n+\t\t\t\t * request.\n+\t\t\t\t */\n+\t\t\t\tstruct msg *m;\n+\t\t\t\tm = container_of(tim, struct msg, tim);\n+\t\t\t\tTAILQ_REMOVE(&sw_data->msgs_tailq_head, m,\n+\t\t\t\t\t     msgs);\n+\t\t\t\trte_mempool_put(sw_data->msg_pool, m);\n+\n+\t\t\t\t/* Free the msg object for the current msg */\n+\t\t\t\trte_mempool_put(sw_data->msg_pool, msg);\n+\n+\t\t\t\tevtim->impl_opaque[0] = 0;\n+\t\t\t\tevtim->impl_opaque[1] = 0;\n+\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tsw_data->service_phase = 2;\n+\trte_smp_wmb();\n+\n+\tif (adapter_did_tick(adapter)) {\n+\t\trte_timer_manage();\n+\n+\t\tevent_buffer_flush(&sw_data->buffer,\n+\t\t\t\t   adapter->data->event_dev_id,\n+\t\t\t\t   adapter->data->event_port_id,\n+\t\t\t\t   &nb_evs_flushed, &nb_evs_invalid);\n+\n+\t\tsw_data->stats.ev_enq_count += nb_evs_flushed;\n+\t\tsw_data->stats.ev_inv_count += nb_evs_invalid;\n+\t\tsw_data->stats.adapter_tick_count++;\n+\t}\n+\n+\tsw_data->service_phase = 0;\n+\trte_smp_wmb();\n+\n+\treturn 0;\n+}\n+\n+/* The adapter initialization function rounds the mempool size up to the next\n+ * power of 2, so we can take the difference between that value and what the\n+ * user requested, and use the space for caches.  This avoids a scenario where a\n+ * user can't arm the number of timers the adapter was configured with because\n+ * mempool objects have been lost to caches.\n+ *\n+ * nb_actual should always be a power of 2, so we can iterate over the powers\n+ * of 2 to see what the largest cache size we can use is.\n+ */\n+static int\n+compute_msg_mempool_cache_size(uint64_t nb_requested, uint64_t nb_actual)\n+{\n+\tint i;\n+\tint size;\n+\tint cache_size = 0;\n+\n+\tfor (i = 0; ; i++) {\n+\t\tsize = 1 << i;\n+\n+\t\tif (RTE_MAX_LCORE * size < (int)(nb_actual - nb_requested) &&\n+\t\t    size < RTE_MEMPOOL_CACHE_MAX_SIZE &&\n+\t\t    size <= nb_actual / 1.5)\n+\t\t\tcache_size = size;\n+\t\telse\n+\t\t\tbreak;\n+\t}\n+\n+\treturn cache_size;\n+}\n+\n+#define SW_MIN_INTERVAL 1E5\n+\n+static int\n+sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)\n+{\n+\tint ret;\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\tuint64_t nb_timers;\n+\tunsigned int flags;\n+\tstruct rte_service_spec service;\n+\tstatic bool timer_subsystem_inited; // static initialized to false\n+\n+\t/* Allocate storage for SW implementation data */\n+\tchar priv_data_name[RTE_RING_NAMESIZE];\n+\tsnprintf(priv_data_name, RTE_RING_NAMESIZE, \"sw_evtim_adap_priv_%\"PRIu8,\n+\t\t adapter->data->id);\n+\tadapter->data->adapter_priv = rte_zmalloc_socket(\n+\t\t\t\tpriv_data_name,\n+\t\t\t\tsizeof(struct rte_event_timer_adapter_sw_data),\n+\t\t\t\tRTE_CACHE_LINE_SIZE,\n+\t\t\t\tadapter->data->socket_id);\n+\tif (adapter->data->adapter_priv == NULL) {\n+\t\tEVTIM_LOG_ERR(\"failed to allocate space for private data\");\n+\t\trte_errno = ENOMEM;\n+\t\treturn -1;\n+\t}\n+\n+\tif (adapter->data->conf.timer_tick_ns < SW_MIN_INTERVAL) {\n+\t\tEVTIM_LOG_ERR(\"failed to create adapter with requested tick \"\n+\t\t\t      \"interval\");\n+\t\trte_errno = EINVAL;\n+\t\treturn -1;\n+\t}\n+\n+\tsw_data = adapter->data->adapter_priv;\n+\n+\tsw_data->timer_tick_ns = adapter->data->conf.timer_tick_ns;\n+\tsw_data->max_tmo_ns = adapter->data->conf.max_tmo_ns;\n+\n+\tTAILQ_INIT(&sw_data->msgs_tailq_head);\n+\trte_spinlock_init(&sw_data->msgs_tailq_sl);\n+\trte_atomic16_init(&sw_data->message_producer_count);\n+\n+\t/* Rings require power of 2, so round up to next such value */\n+\tnb_timers = rte_align64pow2(adapter->data->conf.nb_timers);\n+\n+\tchar msg_ring_name[RTE_RING_NAMESIZE];\n+\tsnprintf(msg_ring_name, RTE_RING_NAMESIZE,\n+\t\t \"sw_evtim_adap_msg_ring_%\"PRIu8, adapter->data->id);\n+\tflags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?\n+\t\tRING_F_SP_ENQ | RING_F_SC_DEQ :\n+\t\tRING_F_SC_DEQ;\n+\tsw_data->msg_ring = rte_ring_create(msg_ring_name, nb_timers,\n+\t\t\t\t\t    adapter->data->socket_id, flags);\n+\tif (sw_data->msg_ring == NULL) {\n+\t\tEVTIM_LOG_ERR(\"failed to create message ring\");\n+\t\trte_errno = ENOMEM;\n+\t\tgoto free_priv_data;\n+\t}\n+\n+\tchar pool_name[RTE_RING_NAMESIZE];\n+\tsnprintf(pool_name, RTE_RING_NAMESIZE, \"sw_evtim_adap_msg_pool_%\"PRIu8,\n+\t\t adapter->data->id);\n+\n+\t/* Both the arming/canceling thread and the service thread will do puts\n+\t * to the mempool, but if the SP_PUT flag is enabled, we can specify\n+\t * single-consumer get for the mempool.\n+\t */\n+\tflags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?\n+\t\tMEMPOOL_F_SC_GET : 0;\n+\n+\t/* The usable size of a ring is count - 1, so subtract one here to\n+\t * make the counts agree.\n+\t */\n+\tint pool_size = nb_timers - 1;\n+\tint cache_size = compute_msg_mempool_cache_size(\n+\t\t\t\tadapter->data->conf.nb_timers, nb_timers);\n+\tsw_data->msg_pool = rte_mempool_create(pool_name, pool_size,\n+\t\t\t\t\t       sizeof(struct msg), cache_size,\n+\t\t\t\t\t       0, NULL, NULL, NULL, NULL,\n+\t\t\t\t\t       adapter->data->socket_id, flags);\n+\tif (sw_data->msg_pool == NULL) {\n+\t\tEVTIM_LOG_ERR(\"failed to create message object mempool\");\n+\t\trte_errno = ENOMEM;\n+\t\tgoto free_msg_ring;\n+\t}\n+\n+\tevent_buffer_init(&sw_data->buffer);\n+\n+\t/* Register a service component to run adapter logic */\n+\tmemset(&service, 0, sizeof(service));\n+\tsnprintf(service.name, RTE_SERVICE_NAME_MAX,\n+\t\t \"sw_evimer_adap_svc_%\"PRIu8, adapter->data->id);\n+\tservice.socket_id = adapter->data->socket_id;\n+\tservice.callback = sw_event_timer_adapter_service_func;\n+\tservice.callback_userdata = adapter;\n+\tservice.capabilities &= ~(RTE_SERVICE_CAP_MT_SAFE);\n+\tret = rte_service_component_register(&service, &sw_data->service_id);\n+\tif (ret < 0) {\n+\t\tEVTIM_LOG_ERR(\"failed to register service %s with id %\"PRIu32\n+\t\t\t      \": err = %d\", service.name, sw_data->service_id,\n+\t\t\t      ret);\n+\n+\t\trte_errno = ENOSPC;\n+\t\tgoto free_msg_pool;\n+\t}\n+\n+\tEVTIM_LOG_DBG(\"registered service %s with id %\"PRIu32, service.name,\n+\t\t      sw_data->service_id);\n+\n+\tadapter->data->service_id = sw_data->service_id;\n+\tadapter->data->service_inited = 1;\n+\n+\tif (!timer_subsystem_inited) {\n+\t\trte_timer_subsystem_init();\n+\t\ttimer_subsystem_inited = true;\n+\t}\n+\n+\treturn 0;\n+\n+free_msg_pool:\n+\trte_mempool_free(sw_data->msg_pool);\n+free_msg_ring:\n+\trte_ring_free(sw_data->msg_ring);\n+free_priv_data:\n+\trte_free(sw_data);\n+\treturn -1;\n+}\n+\n+static int\n+sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)\n+{\n+\tint ret;\n+\tstruct msg *m1, *m2;\n+\tstruct rte_event_timer_adapter_sw_data *sw_data =\n+\t\t\t\t\t\tadapter->data->adapter_priv;\n+\n+\trte_spinlock_lock(&sw_data->msgs_tailq_sl);\n+\n+\t/* Cancel outstanding rte_timers and free msg objects */\n+\tm1 = TAILQ_FIRST(&sw_data->msgs_tailq_head);\n+\twhile (m1 != NULL) {\n+\t\tEVTIM_LOG_DBG(\"freeing outstanding timer\");\n+\t\tm2 = TAILQ_NEXT(m1, msgs);\n+\n+\t\trte_timer_stop_sync(&m1->tim);\n+\t\trte_mempool_put(sw_data->msg_pool, m1);\n+\n+\t\tm1 = m2;\n+\t}\n+\n+\trte_spinlock_unlock(&sw_data->msgs_tailq_sl);\n+\n+\tret = rte_service_component_unregister(sw_data->service_id);\n+\tif (ret < 0) {\n+\t\tEVTIM_LOG_ERR(\"failed to unregister service component\");\n+\t\treturn ret;\n+\t}\n+\n+\trte_ring_free(sw_data->msg_ring);\n+\trte_mempool_free(sw_data->msg_pool);\n+\trte_free(adapter->data->adapter_priv);\n+\n+\treturn 0;\n+}\n+\n+static inline int32_t\n+get_mapped_count_for_service(uint32_t service_id)\n+{\n+\tint32_t core_count, i, mapped_count = 0;\n+\tuint32_t lcore_arr[RTE_MAX_LCORE];\n+\n+\tcore_count = rte_service_lcore_list(lcore_arr, RTE_MAX_LCORE);\n+\n+\tfor (i = 0; i < core_count; i++)\n+\t\tif (rte_service_map_lcore_get(service_id, lcore_arr[i]) == 1)\n+\t\t\tmapped_count++;\n+\n+\treturn mapped_count;\n+}\n+\n+static int\n+sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)\n+{\n+\tint mapped_count;\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\n+\tsw_data = adapter->data->adapter_priv;\n+\n+\t/* Mapping the service to more than one service core can introduce\n+\t * delays while one thread is waiting to acquire a lock, so only allow\n+\t * one core to be mapped to the service.\n+\t */\n+\tmapped_count = get_mapped_count_for_service(sw_data->service_id);\n+\n+\tif (mapped_count == 1)\n+\t\treturn rte_service_component_runstate_set(sw_data->service_id,\n+\t\t\t\t\t\t\t  1);\n+\n+\treturn mapped_count < 1 ? -ENOENT : -ENOTSUP;\n+}\n+\n+static int\n+sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)\n+{\n+\tint ret;\n+\tstruct rte_event_timer_adapter_sw_data *sw_data =\n+\t\t\t\t\t\tadapter->data->adapter_priv;\n+\n+\tret = rte_service_component_runstate_set(sw_data->service_id, 0);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\t/* Wait for the service to complete its final iteration before\n+\t * stopping.\n+\t */\n+\twhile (sw_data->service_phase != 0)\n+\t\trte_pause();\n+\n+\trte_smp_rmb();\n+\n+\treturn 0;\n+}\n+\n+static void\n+sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,\n+\t\tstruct rte_event_timer_adapter_info *adapter_info)\n+{\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\tsw_data = adapter->data->adapter_priv;\n+\n+\tadapter_info->min_resolution_ns = sw_data->timer_tick_ns;\n+\tadapter_info->max_tmo_ns = sw_data->max_tmo_ns;\n+}\n+\n+static int\n+sw_event_timer_adapter_stats_get(const struct rte_event_timer_adapter *adapter,\n+\t\t\t\t struct rte_event_timer_adapter_stats *stats)\n+{\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\tsw_data = adapter->data->adapter_priv;\n+\t*stats = sw_data->stats;\n+\treturn 0;\n+}\n+\n+static int\n+sw_event_timer_adapter_stats_reset(\n+\t\t\t\tconst struct rte_event_timer_adapter *adapter)\n+{\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\tsw_data = adapter->data->adapter_priv;\n+\tmemset(&sw_data->stats, 0, sizeof(sw_data->stats));\n+\treturn 0;\n+}\n+\n+static __rte_always_inline uint16_t\n+__sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,\n+\t\t\t  struct rte_event_timer **evtims,\n+\t\t\t  uint16_t nb_evtims)\n+{\n+\tuint16_t i;\n+\tint ret;\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\tstruct msg *msgs[nb_evtims];\n+\n+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG\n+\t/* Check that the service is running. */\n+\tif (rte_service_runstate_get(adapter->data->service_id) != 1) {\n+\t\trte_errno = EINVAL;\n+\t\treturn 0;\n+\t}\n+#endif\n+\n+\tsw_data = adapter->data->adapter_priv;\n+\n+\tret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);\n+\tif (ret < 0) {\n+\t\trte_errno = ENOSPC;\n+\t\treturn 0;\n+\t}\n+\n+\t/* Let the service know we're producing messages for it to process */\n+\trte_atomic16_inc(&sw_data->message_producer_count);\n+\n+\t/* If the service is managing timers, wait for it to finish */\n+\twhile (sw_data->service_phase == 2)\n+\t\trte_pause();\n+\n+\trte_smp_rmb();\n+\n+\tfor (i = 0; i < nb_evtims; i++) {\n+\t\t/* Don't modify the event timer state in these cases */\n+\t\tif (evtims[i]->state == RTE_EVENT_TIMER_ARMED) {\n+\t\t\trte_errno = EALREADY;\n+\t\t\tbreak;\n+\t\t} else if (!(evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||\n+\t\t    evtims[i]->state == RTE_EVENT_TIMER_CANCELED)) {\n+\t\t\trte_errno = EINVAL;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tret = check_timeout(evtims[i], adapter);\n+\t\tif (ret == -1) {\n+\t\t\tevtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOLATE;\n+\t\t\trte_errno = EINVAL;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (ret == -2) {\n+\t\t\tevtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOEARLY;\n+\t\t\trte_errno = EINVAL;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (check_destination_event_queue(evtims[i], adapter) < 0) {\n+\t\t\tevtims[i]->state = RTE_EVENT_TIMER_ERROR;\n+\t\t\trte_errno = EINVAL;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* Checks passed, set up a message to enqueue */\n+\t\tmsgs[i]->type = MSG_TYPE_ARM;\n+\t\tmsgs[i]->evtim = evtims[i];\n+\n+\t\t/* Set the payload pointer if not set. */\n+\t\tif (evtims[i]->ev.event_ptr == NULL)\n+\t\t\tevtims[i]->ev.event_ptr = evtims[i];\n+\n+\t\t/* msg objects that get enqueued successfully will be freed\n+\t\t * either by a future cancel operation or by the timer\n+\t\t * expiration callback.\n+\t\t */\n+\t\tif (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {\n+\t\t\trte_errno = ENOSPC;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tEVTIM_LOG_DBG(\"enqueued ARM message to ring\");\n+\n+\t\tevtims[i]->state = RTE_EVENT_TIMER_ARMED;\n+\t}\n+\n+\t/* Let the service know we're done producing messages */\n+\trte_atomic16_dec(&sw_data->message_producer_count);\n+\n+\tif (i < nb_evtims)\n+\t\trte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],\n+\t\t\t\t     nb_evtims - i);\n+\n+\treturn i;\n+}\n+\n+static uint16_t\n+sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,\n+\t\t\t struct rte_event_timer **evtims,\n+\t\t\t uint16_t nb_evtims)\n+{\n+\treturn __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);\n+}\n+\n+static uint16_t\n+sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,\n+\t\t\t    struct rte_event_timer **evtims,\n+\t\t\t    uint16_t nb_evtims)\n+{\n+\tuint16_t i;\n+\tint ret;\n+\tstruct rte_event_timer_adapter_sw_data *sw_data;\n+\tstruct msg *msgs[nb_evtims];\n+\n+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG\n+\t/* Check that the service is running. */\n+\tif (rte_service_runstate_get(adapter->data->service_id) != 1) {\n+\t\trte_errno = EINVAL;\n+\t\treturn 0;\n+\t}\n+#endif\n+\n+\tsw_data = adapter->data->adapter_priv;\n+\n+\tret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);\n+\tif (ret < 0) {\n+\t\trte_errno = ENOSPC;\n+\t\treturn 0;\n+\t}\n+\n+\t/* Let the service know we're producing messages for it to process */\n+\trte_atomic16_inc(&sw_data->message_producer_count);\n+\n+\t/* If the service could be modifying event timer states, wait */\n+\twhile (sw_data->service_phase == 2)\n+\t\trte_pause();\n+\n+\trte_smp_rmb();\n+\n+\tfor (i = 0; i < nb_evtims; i++) {\n+\t\t/* Don't modify the event timer state in these cases */\n+\t\tif (evtims[i]->state == RTE_EVENT_TIMER_CANCELED) {\n+\t\t\trte_errno = EALREADY;\n+\t\t\tbreak;\n+\t\t} else if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {\n+\t\t\trte_errno = EINVAL;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tmsgs[i]->type = MSG_TYPE_CANCEL;\n+\t\tmsgs[i]->evtim = evtims[i];\n+\n+\t\tif (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {\n+\t\t\trte_errno = ENOSPC;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tEVTIM_LOG_DBG(\"enqueued CANCEL message to ring\");\n+\n+\t\tevtims[i]->state = RTE_EVENT_TIMER_CANCELED;\n+\t}\n+\n+\t/* Let the service know we're done producing messages */\n+\trte_atomic16_dec(&sw_data->message_producer_count);\n+\n+\tif (i < nb_evtims)\n+\t\trte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],\n+\t\t\t\t     nb_evtims - i);\n+\n+\treturn i;\n+}\n+\n+static uint16_t\n+sw_event_timer_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter,\n+\t\t\t\t  struct rte_event_timer **evtims,\n+\t\t\t\t  uint64_t timeout_ticks,\n+\t\t\t\t  uint16_t nb_evtims)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < nb_evtims; i++)\n+\t\tevtims[i]->timeout_ticks = timeout_ticks;\n+\n+\treturn __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);\n+}\n+\n+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {\n+\t.init = sw_event_timer_adapter_init,\n+\t.uninit = sw_event_timer_adapter_uninit,\n+\t.start = sw_event_timer_adapter_start,\n+\t.stop = sw_event_timer_adapter_stop,\n+\t.get_info = sw_event_timer_adapter_get_info,\n+\t.stats_get = sw_event_timer_adapter_stats_get,\n+\t.stats_reset = sw_event_timer_adapter_stats_reset,\n+\t.arm_burst = sw_event_timer_arm_burst,\n+\t.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,\n+\t.cancel_burst = sw_event_timer_cancel_burst,\n+};\n+\n RTE_INIT(event_timer_adapter_init_log);\n static void\n event_timer_adapter_init_log(void)\n@@ -384,4 +1284,13 @@ event_timer_adapter_init_log(void)\n \tevtim_logtype = rte_log_register(\"lib.eventdev.adapter.timer\");\n \tif (evtim_logtype >= 0)\n \t\trte_log_set_level(evtim_logtype, RTE_LOG_NOTICE);\n+\n+\tevtim_buffer_logtype = rte_log_register(\"lib.eventdev.adapter.timer.\"\n+\t\t\t\t\t\t\"buffer\");\n+\tif (evtim_buffer_logtype >= 0)\n+\t\trte_log_set_level(evtim_buffer_logtype, RTE_LOG_NOTICE);\n+\n+\tevtim_svc_logtype = rte_log_register(\"lib.eventdev.adapter.timer.svc\");\n+\tif (evtim_svc_logtype >= 0)\n+\t\trte_log_set_level(evtim_svc_logtype, RTE_LOG_NOTICE);\n }\ndiff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h\nindex 6a76791..38a314d 100644\n--- a/lib/librte_eventdev/rte_event_timer_adapter.h\n+++ b/lib/librte_eventdev/rte_event_timer_adapter.h\n@@ -280,8 +280,6 @@ rte_event_timer_adapter_create_ext(\n struct rte_event_timer_adapter_info {\n \tuint64_t min_resolution_ns;\n \t/**< Minimum timer adapter resolution in ns */\n-\tuint64_t resolution_ns;\n-\t/**< Actual timer adapter resolution in ns */\n \tuint64_t max_tmo_ns;\n \t/**< Maximum timer timeout(expire) in ns */\n \tstruct rte_event_timer_adapter_conf conf;\n@@ -339,6 +337,8 @@ rte_event_timer_adapter_get_info(\n  *   - 0: Success, adapter started.\n  *   - <0: Error code returned by the driver start function.\n  *   - -EINVAL if adapter identifier invalid\n+ *   - -ENOENT if software adapter but no service core mapped\n+ *   - -ENOTSUP if software adapter and more than one service core mapped\n  */\n int __rte_experimental\n rte_event_timer_adapter_start(\n@@ -465,6 +465,59 @@ int __rte_experimental rte_event_timer_adapter_stats_reset(\n \t\tstruct rte_event_timer_adapter *adapter);\n \n /**\n+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't\n+ * use an rte_service function, this function returns -ESRCH.\n+ *\n+ * @param adapter\n+ *   A pointer to an event timer adapter.\n+ *\n+ * @param [out] service_id\n+ *   A pointer to a uint32_t, to be filled in with the service id.\n+ *\n+ * @return\n+ *   - 0: Success\n+ *   - <0: Error code on failure, if the event dev doesn't use a rte_service\n+ *   function, this function returns -ESRCH.\n+ */\n+int\n+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,\n+\t\t\t\t       uint32_t *service_id);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Retrieve statistics for an event timer adapter instance.\n+ *\n+ * @param adapter\n+ *   A pointer to an event timer adapter structure.\n+ * @param[out] stats\n+ *   A pointer to a structure to fill with statistics.\n+ *\n+ * @return\n+ *   - 0: Successfully retrieved.\n+ *   - <0: Failure; error code returned.\n+ */\n+int rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,\n+\t\t\t\tstruct rte_event_timer_adapter_stats *stats);\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice\n+ *\n+ * Reset statistics for an event timer adapter instance.\n+ *\n+ * @param adapter\n+ *   A pointer to an event timer adapter structure.\n+ *\n+ * @return\n+ *   - 0: Successfully reset;\n+ *   - <0: Failure; error code returned.\n+ */\n+int rte_event_timer_adapter_stats_reset(\n+\t\t\t\tstruct rte_event_timer_adapter *adapter);\n+\n+/**\n  * @warning\n  * @b EXPERIMENTAL: this structure may change without prior notice\n  *\n",
    "prefixes": [
        "dpdk-dev",
        "v9",
        "5/9"
    ]
}