All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v5 0/5] eventtimer: introduce event timer adapter
       [not found] <1511890148-22295-1-git-send-email-erik.g.carrillo@intel.com>
@ 2017-12-01 20:00 ` Erik Gabriel Carrillo
  2017-12-01 20:00   ` [RFC PATCH v5 1/5] " Erik Gabriel Carrillo
                     ` (5 more replies)
  0 siblings, 6 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2017-12-01 20:00 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

This set of RFC patches contains a reworked version of the "front-end" of 
the event timer adapter, i.e., the API and common logic.

This patch set produces the following checkpatch warning: 
"macro with flow control". I have left the macros in since such usage seems
common in DPDK.

v5
- Addressed comments on previous version from Pavan:
  - renamed rte_event_timer_adapter_driver.h to rte_event_timer_adapter_pmd.h
  - moved contents of sw_event_timer_adapter.c into rte_event_timer_adapter.c
  - added flags parameter to timer_adapter_caps_get() call
  - added DEBUG config variable to conditionally compile run-time checks on
    datapath
  - fixed license text and file description
- Also added a config variable to enable/disable compilation of event timer
  adapter - feedback on whether this is desirable is appreciated

v4
- Split changes into multiple patches for easier review

v3
- Reworked allocation and ops organization in common code based on feedback
  received from Jerin and Pavan. This will allow fast-path function pointers to 
  be dereferenced with one level of indirection with pointers valid in primary
  and secondary processes.
- Moved default software implementation from sw_evdev directory to eventdev
  library directory, which will allow it to be used by any eventdev PMD as an
  alternative to providing its own definitions.
- Reverted occurrences of id back to pointer to adapter struct in library API
- Added rte_event_timer_adapter_lookup() function back in

v2
- Added ops structure and stubbed out plugin for SW impl
- Added unit test stubs
- Replaced occurrences of "wheel" in API with "adapter"
- Replaced occurrences of pointer to struct rte_event_timer_adapter with ids
- Removed rte_event_timer_adapter_lookup() function
- Replaced RTE_EVENT_TIMER_SUCCESS_{ARM,CANCEL} states with
  RTE_EVENT_TIMER_ARMED

Erik Gabriel Carrillo (4):
  eventtimer: introduce event timer adapter
  eventtimer: add common code
  eventtimer: add config variable for adapter
  eventtimer: add default software implementation stub
  test: add event timer adapter auto-test

 config/common_base                                |   2 +
 doc/api/doxy-api-index.md                         |   1 +
 drivers/event/sw/sw_evdev.c                       |  22 +
 lib/librte_eventdev/Makefile                      |   3 +
 lib/librte_eventdev/rte_event_timer_adapter.c     | 514 +++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h     | 518 ++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 159 +++++++
 lib/librte_eventdev/rte_eventdev.h                |   7 +-
 lib/librte_eventdev/rte_eventdev_pmd.h            |  41 ++
 lib/librte_eventdev/rte_eventdev_version.map      |  15 +-
 test/test/Makefile                                |   1 +
 test/test/test_event_timer_adapter.c              | 249 +++++++++++
 12 files changed, 1529 insertions(+), 3 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h
 create mode 100644 test/test/test_event_timer_adapter.c

-- 
2.6.4

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [RFC PATCH v5 1/5] eventtimer: introduce event timer adapter
  2017-12-01 20:00 ` [RFC PATCH v5 0/5] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
@ 2017-12-01 20:00   ` Erik Gabriel Carrillo
  2017-12-06 15:17     ` Jerin Jacob
  2017-12-01 20:00   ` [RFC PATCH v5 2/5] eventtimer: add common code Erik Gabriel Carrillo
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2017-12-01 20:00 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 doc/api/doxy-api-index.md                     |   1 +
 lib/librte_eventdev/Makefile                  |   1 +
 lib/librte_eventdev/rte_event_timer_adapter.h | 518 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_eventdev.h            |   4 +-
 4 files changed, 522 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 3492702..3110658 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -46,6 +46,7 @@ The public API headers are grouped by topics:
   [security]           (@ref rte_security.h),
   [eventdev]           (@ref rte_eventdev.h),
   [event_eth_rx_adapter]   (@ref rte_event_eth_rx_adapter.h),
+  [event_timer_adapter]    (@ref rte_event_timer_adapter.h),
   [metrics]            (@ref rte_metrics.h),
   [bitrate]            (@ref rte_bitrate.h),
   [latency]            (@ref rte_latencystats.h),
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 5ac22cd..6ef7c1c 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -53,6 +53,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
new file mode 100644
index 0000000..2a16a77
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -0,0 +1,518 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 Cavium, Inc.
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ * @file
+ *
+ * RTE Event Timer Adapter
+ *
+ * An event timer adapter has the following abstract working model:
+ *
+ *                               timer_tick_ns
+ *                                   +
+ *                      +-------+    |
+ *                      |       |    |
+ *              +-------+ bkt 0 +----v---+
+ *              |       |       |        |
+ *              |       +-------+        |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *          |       |                |       |  |   |   |   |   |
+ *          | bkt n |                | bkt 1 |<-> t0| t1| t2| tn|
+ *          |       |                |       |  |   |   |   |   |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *              |     Timer adapter      |
+ *          +---+---+                +---+---+
+ *          |       |                |       |
+ *          | bkt 4 |                | bkt 2 |<--- Current bucket
+ *          |       |                |       |
+ *          +---+---+                +---+---+
+ *               |      +-------+       |
+ *               |      |       |       |
+ *               +------+ bkt 3 +-------+
+ *                      |       |
+ *                      +-------+
+ *
+ * - It has a virtual monotonically increasing 64-bit timer adapter clock based
+ *   on *enum rte_event_timer_adapter_clk_src* clock source. The clock source
+ *   could be a CPU clock, or a platform depended external clock.
+ *
+ * - Application creates a timer adapter instance with given clock source,
+ *   the total number of event timers, resolution(expressed in ns) to traverse
+ *   between the buckets.
+ *
+ * - Each timer adapter may have 0 to n buckets based on the configured
+ *   max timeout(max_tmo_ns) and resolution(timer_tick_ns). On timer adapter
+ *   start, the timer starts ticking at *timer_tick_ns* resolution.
+ *
+ * - Application arms an event timer to be expired at the number of
+ *   *timer_tick_ns* from now.
+ *
+ * - Application can cancel the existing armed timer if required.
+ *
+ * - If not canceled by the application and the timer expires then the library
+ *   injects the timer expiry event to the designated event queue.
+ *
+ * - The timer expiry event will be received through *rte_event_dequeue_burst*
+ *
+ * - Application frees the created timer adapter instance.
+ *
+ * Multiple timer adapters can be created with a varying level of resolution
+ * for various expiry use cases that run in parallel.
+ *
+ * Before using the timer adapter, the application has to create and configure
+ * an event device along with the event ports. Based on the event device
+ * capability it might require creating an additional event port to be used
+ * by the timer adapter.
+ *
+ * The application creates the event timer adapter using the
+ * ``rte_event_timer_adapter_create()``. The event device id is passed to this
+ * function, inside this function the event device capability is checked,
+ * and if an in-built port is absent the application uses the default
+ * function to create a new producer port.
+ *
+ * The application may also use the function
+ * ``rte_event_timer_adapter_create_ext()`` to have granular control over
+ * producer port creation in a case where the in-built port is absent.
+ *
+ * After creating the timer adapter, the application has to start it
+ * using ``rte_event_timer_adapter_start()``. The buckets are traversed from
+ * 0 to n, the list per each bucket is processed, and the expired timer events
+ * are sent to the designated event queue.
+ *
+ * The application can arm one or more event timers using the
+ * ``rte_event_timer_arm_burst()``. The *timeout_ticks* represents the number
+ * of *timer_tick_ns* after which the timer has to expire. The timeout at
+ * which the timers expire can be grouped or be independent of each
+ * event timer instance. ``rte_event_timer_arm_tmo_tick_burst()`` address the
+ * former case and ``rte_event_timer_arm_burst()`` address the latter case.
+ *
+ * The application can cancel the timers from expiring using the
+ * ``rte_event_timer_cancel_burst()``.
+ *
+ * On the secondary process, ``rte_event_timer_adapter_lookup()`` can be used
+ * to get the timer adapter pointer from its id and use it to invoke fastpath
+ * operations such as arm and cancel.
+ *
+ * Some of the use cases of event timer adapter are Beacon Timers,
+ * Generic SW Timeout, Wireless MAC Scheduling, 3G Frame Protocols,
+ * Packet Scheduling, Protocol Retransmission Timers, Supervision Timers.
+ * All these use cases require high resolution and low time drift.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_spinlock.h>
+#include <rte_memory.h>
+
+#include "rte_eventdev.h"
+
+#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 64
+
+/**
+ * Timer adapter clock source
+ */
+enum rte_event_timer_adapter_clk_src {
+	RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+	/**< Use CPU clock as the clock source. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK0,
+	/**< Platform dependent external clock source 0. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK1,
+	/**< Platform dependent external clock source 1. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK2,
+	/**< Platform dependent external clock source 2. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK3,
+	/**< Platform dependent external clock source 3. */
+};
+
+#define RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES	(1ULL << 0)
+/**< The event timer adapter implementation may have constraints on the
+ * resolution (timer_tick_ns) and maximum timer expiry timeout(max_tmo_ns)
+ * based on the given timer adapter or system.  If this flag is set, the
+ * implementation adjusts the resolution and maximum timeout to the best
+ * possible configuration. On successful timer adapter creation, the
+ * application can get the configured resolution and max timeout with
+ * ``rte_event_timer_adapter_get_info()``.
+ */
+#define RTE_EVENT_TIMER_ADAPTER_F_SP_PUT	(1ULL << 1)
+/**< ``rte_event_timer_arm_burst()`` API to be used in single producer mode.
+ *
+ * @see struct rte_event_timer_adapter_conf::flags
+ */
+
+/*
+ * Timer adapter configuration structure
+ */
+struct rte_event_timer_adapter_conf {
+	uint8_t event_dev_id;
+	/**< Event device identifier */
+	uint16_t timer_adapter_id;
+	/**< Event timer adapter identifier */
+	uint32_t socket_id;
+	/**< Identifer of socket from which to allocate memory for adapter */
+	enum rte_event_timer_adapter_clk_src clk_src;
+	/**< Clock source for timer adapter */
+	uint64_t timer_tick_ns;
+	/**< Timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expiry) in ns */
+	uint64_t nb_timers;
+	/**< Total number of timers per adapter */
+	uint64_t flags;
+	/**< Timer adapter config flags (RTE_EVENT_TIMER_ADAPTER_F_*) */
+};
+
+struct rte_event_timer_adapter;
+
+/*
+ * Callback function type for producer port creation.
+ */
+typedef int (*rte_event_timer_adapter_port_conf_cb_t)(uint16_t id,
+						      uint8_t event_dev_id,
+						      uint8_t *event_port_id,
+						      void *conf_arg);
+
+/*
+ * Create an event timer adapter.
+ *
+ * This function must be invoked first before any other function in the API.
+ *
+ * @param conf
+ *   The event timer adapter configuration structure.
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ */
+struct rte_event_timer_adapter *rte_event_timer_adapter_create(
+			const struct rte_event_timer_adapter_conf *conf);
+
+/*
+ * Create a timer adapter with the supplied callback.
+ *
+ * This function can be used to have a more granular control over the timer
+ * adapter creation.  If a built-in port is absent, then the function uses the
+ * callback provided to create and get the port id to be used as a producer
+ * port.
+ *
+ * @param conf
+ *   The timer adapter configuration structure
+ * @param conf_cb
+ *   The port config callback function.
+ * @param conf_arg
+ *   Opaque pointer to the argument for the callback function
+ * @param id_ptr[out]
+ *   Address of variable to store adapter identifier in
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ */
+struct rte_event_timer_adapter *rte_event_timer_adapter_create_ext(
+			const struct rte_event_timer_adapter_conf *conf,
+			rte_event_timer_adapter_port_conf_cb_t conf_cb,
+			void *conf_arg);
+
+/*
+ * Timer adapter info structure.
+ */
+struct rte_event_timer_adapter_info {
+	uint64_t min_resolution_ns;
+	/**< Minimum timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expire) in ns */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configured timer adapter attributes */
+	uint32_t caps;
+	/**< Event timer adapter capabilities */
+	int16_t event_dev_port_id;
+	/**< Event device port ID, if applicable */
+	int32_t service_id;
+	/**< Service ID, if applicable */
+};
+
+/**
+ * Retrieve the contextual information of an event timer adapter.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @param[out] adapter_info
+ *   A pointer to a structure of type *rte_event_timer_adapter_info* to be
+ *   filled with the contextual information of the adapter.
+ *
+ * @return
+ *   - 0: Success, driver updates the contextual information of the
+ *   timer adapter
+ *   - <0: Error code returned by the driver info get function.
+ *   - -EINVAL if adapter identifier invalid
+ *
+ * @see RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES,
+ *   struct rte_event_timer_adapter_info
+ *
+ */
+int rte_event_timer_adapter_get_info(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+
+/**
+ * Start a timer adapter.
+ *
+ * The adapter start step is the last one and consists of setting the timer
+ * adapter to start accepting the timers and schedules to event queues.
+ *
+ * On success, all basic functions exported by the API (timer arm,
+ * timer cancel and so on) can be invoked.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter started.
+ *   - <0: Error code returned by the driver start function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int rte_event_timer_adapter_start(
+		const struct rte_event_timer_adapter *adapter);
+
+/**
+ * Stop an event timer adapter.
+ *
+ * The adapter can be restarted with a call to
+ * ``rte_event_timer_adapter_start()``.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter stopped.
+ *   - <0: Error code returned by the driver stop function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter);
+
+/*
+ * Lookup an event timer adapter using its identifier.
+ *
+ * If an event timer adapter was created in another process with the same
+ * identifier, this function will locate its state and set up access to it
+ * so that it can be used in this process.
+ *
+ * @param adapter_id
+ *  The event timer adapter identifier.
+ *
+ * @return
+ *  A pointer to the event timer adapter matching the identifier on success.
+ *  NULL on error with rte_errno set appropriately.
+ *  Possible rte_errno values include:
+ *   - ENOENT - required entry not available to return.
+ */
+struct rte_event_timer_adapter *rte_event_timer_adapter_lookup(
+							uint16_t adapter_id);
+
+/*
+ * Free an event timer adapter.
+ *
+ * Destroy an event timer adapter, freeing all resources.
+ *
+ * Before invoking this function, the application must wait for all the
+ * armed timers to expire or cancel the outstanding armed timers.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully freed the event timer adapter resources.
+ *   - <0: Failed to free the event timer adapter resources.
+ *   - -EAGAIN:  adapter is busy; timers outstanding
+ *   - -EBUSY: stop hasn't been called for this adapter yet
+ *   - -EINVAL: adapter id invalid, or adapter invalid
+ */
+int rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter);
+
+/**
+ * Event timer state.
+ */
+enum rte_event_timer_state {
+	RTE_EVENT_TIMER_NOT_ARMED = 0,
+	/**< Event timer is in not armed state.*/
+	RTE_EVENT_TIMER_ARMED = 1,
+	/**< Event timer successfully armed.*/
+	RTE_EVENT_TIMER_ERROR = -1,
+	/**< Generic event timer error.*/
+	RTE_EVENT_TIMER_ERROR_TOOEARLY = -2,
+	/**< Event timer timeout tick is too little to add to the adapter. */
+	RTE_EVENT_TIMER_ERROR_TOOLATE = -3,
+	/**< Event timer timeout tick is greater than the maximum timeout.*/
+};
+
+/**
+ * The generic *rte_event_timer* structure to hold the event timer attributes
+ * for arm and cancel operations.
+ */
+RTE_STD_C11
+struct rte_event_timer {
+	struct rte_event ev;
+	/**<
+	 * Expiry event attributes.  On successful event timer timeout,
+	 * the following attributes will be used to inject the expiry event to
+	 * the eventdev:
+	 *  - event_queue_id: Targeted event queue id for expiry events.
+	 *  - event_priority: Event priority of the event expiry event in the
+	 *  event queue relative to other events.
+	 *  - sched_type: Scheduling type of the expiry event.
+	 *  - flow_id: Flow id of the expiry event.
+	 *  - op: RTE_EVENT_OP_NEW
+	 *  - event_type: RTE_EVENT_TYPE_TIMER
+	 */
+	enum rte_event_timer_state state;
+	/**< State of the event timer. */
+	uint64_t timeout_ticks;
+	/**< Expiry timer ticks expressed in number of *timer_ticks_ns* from
+	 * now.
+	 * @see struct rte_event_timer_adapter_info::adapter_conf::timer_tick_ns
+	 */
+	uint64_t impl_opaque[2];
+	/**< Implementation-specific opaque data.
+	 * An event timer adapter implementation use this field to hold
+	 * implementation specific values to share between the arm and cancel
+	 * operations.  The application should not modify this field.
+	 */
+	uint8_t user_meta[];
+	/**< Memory to store user specific metadata.
+	 * The event timer adapter implementation should not modify this area.
+	 */
+} __rte_cache_aligned;
+
+/**
+ * Arm a burst of event timers with separate expiration timeout tick for each
+ * event timer.
+ *
+ * Before calling this function, the application allocates
+ * ``struct rte_event_timer`` objects from mempool or huge page backed
+ * application buffers of desired size. On successful allocation,
+ * application updates the `struct rte_event_timer`` attributes such as
+ * expiry event attributes, timeout ticks from now.
+ * This function submits the event timer arm requests to the event timer adapter
+ * and on expiry, the events will be injected to designated event queue.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param event_timers
+ *   Pointer to an array of objects of type *rte_event_timer* structure.
+ * @param nb_event_timers
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_timers* parameter. If the return value is less
+ *   than *nb_events*, the remaining event timers at the end of *tim*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - -EINVAL  Invalid timer adapter identifier, expiry event queue ID is
+ *   invalid, or an expiry event's sched type doesn't match the capabilities of
+ *   the destination event queue.
+ *   - -EAGAIN Specified timer adapter is not running
+ */
+int rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			      struct rte_event_timer **event_timers,
+			      uint16_t nb_event_timers);
+
+/**
+ * Arm a burst of event timers with same expiration timeout tick.
+ *
+ * Provides the same functionality as ``rte_event_timer_arm_burst()``, except
+ * that application can use this API when all the event timers have the
+ * same timeout expiration tick. This specialized function can provide the
+ * additional hint to the adapter implementation and optimize if possible.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param event_timers
+ *   Points to an array of objects of type *rte_event_timer* structure.
+ * @param timeout_ticks
+ *   The number of ticks in which the timers should expire.
+ * @param nb_event_timers
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_timers* parameter. If the return value is less
+ *   than *nb_events*, the remaining event timers at the end of *tim*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - -EINVAL  Invalid timer adapter identifier, expiry event queue ID is
+ *   invalid, or an expiry event's sched type doesn't match the capabilities of
+ *   the destination event queue.
+ *   - -EAGAIN Specified event timer adapter is not running
+ */
+int rte_event_timer_arm_tmo_tick_burst(
+			const struct rte_event_timer_adapter *adapter,
+			struct rte_event_timer **event_timers,
+			const uint64_t timeout_ticks,
+			const uint16_t nb_event_timers);
+
+/**
+ * Cancel a burst of event timer from being scheduled to the event device.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param event_timers
+ *   Points to an array of objects of type *rte_event_timer* structure
+ * @param nb_event_timers
+ *   Number of event timer instances in the supplied array.
+ *
+ * @return
+ *   The number of successfully canceled event timers. The return value can be
+ *   less than the value of the *nb_timers* parameter. If the return value is
+ *   less than *nb_events*, the remaining event timers at the end of *tim*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - -EINVAL  Invalid timer adapter identifier
+ *   - -EAGAIN  Specified timer adapter is not running
+ */
+int rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+				 struct rte_event_timer **event_timers,
+				 uint16_t nb_event_timers);
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index f1949ff..a650f7a 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -875,8 +875,8 @@ rte_event_dev_close(uint8_t dev_id);
 /**< The event generated from ethdev subsystem */
 #define RTE_EVENT_TYPE_CRYPTODEV        0x1
 /**< The event generated from crypodev subsystem */
-#define RTE_EVENT_TYPE_TIMERDEV         0x2
-/**< The event generated from timerdev subsystem */
+#define RTE_EVENT_TYPE_TIMER		0x2
+/**< The event generated from event timer adapter */
 #define RTE_EVENT_TYPE_CPU              0x3
 /**< The event generated from cpu for pipelining.
  * Application may use *sub_event_type* to further classify the event
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [RFC PATCH v5 2/5] eventtimer: add common code
  2017-12-01 20:00 ` [RFC PATCH v5 0/5] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  2017-12-01 20:00   ` [RFC PATCH v5 1/5] " Erik Gabriel Carrillo
@ 2017-12-01 20:00   ` Erik Gabriel Carrillo
  2017-12-06 15:35     ` Jerin Jacob
  2017-12-01 20:00   ` [RFC PATCH v5 3/5] eventtimer: add config variable for adapter Erik Gabriel Carrillo
                     ` (3 subsequent siblings)
  5 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2017-12-01 20:00 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

This commit adds the logic that is shared by all event timer adapter
drivers; the common code handles instance allocation and some
initialization.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 config/common_base                                |   1 +
 drivers/event/sw/sw_evdev.c                       |  18 +
 lib/librte_eventdev/Makefile                      |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c     | 407 ++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 159 +++++++++
 lib/librte_eventdev/rte_eventdev.h                |   3 +
 lib/librte_eventdev/rte_eventdev_pmd.h            |  35 ++
 lib/librte_eventdev/rte_eventdev_version.map      |  15 +-
 8 files changed, 639 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h

diff --git a/config/common_base b/config/common_base
index e74febe..91a2f0f 100644
--- a/config/common_base
+++ b/config/common_base
@@ -574,6 +574,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
 CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
 CONFIG_RTE_EVENT_MAX_DEVS=16
 CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER_DEBUG=n
 
 #
 # Compile PMD for skeleton event device
diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index fd11079..94da675 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -435,6 +435,22 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
 	return 0;
 }
 
+static int
+sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
+			  uint64_t flags,
+			  uint32_t *caps,
+			  const struct rte_event_timer_adapter_ops **ops)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(flags);
+	*caps = 0;
+
+	/* Use default SW ops */
+	*ops = NULL;
+
+	return 0;
+}
+
 static void
 sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
 {
@@ -755,6 +771,8 @@ sw_probe(struct rte_vdev_device *vdev)
 
 			.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
 
+			.timer_adapter_caps_get = sw_timer_adapter_caps_get,
+
 			.xstats_get = sw_xstats_get,
 			.xstats_get_names = sw_xstats_get_names,
 			.xstats_get_by_name = sw_xstats_get_by_name,
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 6ef7c1c..f3f05c2 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -45,6 +45,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
 SRCS-y += rte_eventdev.c
 SRCS-y += rte_event_ring.c
 SRCS-y += rte_event_eth_rx_adapter.c
+SRCS-y += rte_event_timer_adapter.c
 
 # export include files
 SYMLINK-y-include += rte_eventdev.h
@@ -54,6 +55,7 @@ SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
 SYMLINK-y-include += rte_event_timer_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter_pmd.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
new file mode 100644
index 0000000..5315058
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -0,0 +1,407 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include <rte_memzone.h>
+#include <rte_memory.h>
+#include <rte_dev.h>
+#include <rte_errno.h>
+
+#include "rte_eventdev.h"
+#include "rte_eventdev_pmd.h"
+#include "rte_event_timer_adapter.h"
+#include "rte_event_timer_adapter_pmd.h"
+
+#define MAX_EVENT_TIMER_ADAPTERS 64
+#define DATA_MZ_NAME_MAX_LEN 64
+#define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
+
+static struct rte_event_timer_adapter adapters[MAX_EVENT_TIMER_ADAPTERS];
+
+static inline int
+adapter_valid(const struct rte_event_timer_adapter *adapter)
+{
+	return adapter != NULL && adapter->allocated == 1;
+}
+
+#define ADAPTER_VALID_OR_ERR_RET(adapter, retval) do { \
+	if (!adapter_valid(adapter))		       \
+		return retval;			       \
+} while (0)
+
+#define FUNC_PTR_OR_ERR_RET(func, errval) do { \
+	if ((func) == NULL)		       \
+		return errval;		       \
+} while (0)
+
+#define FUNC_PTR_OR_NULL_RET_WITH_ERRNO(func, errval) do { \
+	if ((func) == NULL) {				   \
+		rte_errno = errval;			   \
+		return NULL;				   \
+	}						   \
+} while (0)
+
+static int
+default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		     void *conf_arg)
+{
+	struct rte_event_timer_adapter *adapter;
+	struct rte_eventdev *dev;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	int started;
+	uint8_t port_id;
+	uint8_t dev_id;
+	int ret;
+
+	RTE_SET_USED(event_dev_id);
+
+	adapter = &adapters[id];
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+	dev_id = dev->data->dev_id;
+	dev_conf = dev->data->dev_conf;
+
+	started = dev->data->dev_started;
+	if (started)
+		rte_event_dev_stop(dev_id);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports += 1;
+	ret = rte_event_dev_configure(dev_id, &dev_conf);
+	if (ret < 0) {
+		if (started)
+			rte_event_dev_start(dev_id);
+
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(dev_id, port_id, port_conf);
+	if (ret < 0)
+		return ret;
+
+	*event_port_id = port_id;
+
+	if (started)
+		rte_event_dev_start(dev_id);
+
+	return 0;
+}
+
+struct rte_event_timer_adapter *
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf)
+{
+	return rte_event_timer_adapter_create_ext(conf, default_port_conf_cb,
+						  NULL);
+}
+
+struct rte_event_timer_adapter *
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg)
+{
+	uint16_t adapter_id;
+	struct rte_event_timer_adapter *adapter;
+	const struct rte_memzone *mz;
+	char mz_name[DATA_MZ_NAME_MAX_LEN];
+	int n, ret;
+	struct rte_eventdev *dev;
+
+	if (conf == NULL) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	/* Check eventdev ID */
+	if (!rte_event_pmd_is_valid_dev(conf->event_dev_id)) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+	dev = &rte_eventdevs[conf->event_dev_id];
+
+	adapter_id = conf->timer_adapter_id;
+
+	/* Check adapter ID not already allocated */
+	adapter = &adapters[adapter_id];
+	if (adapter->allocated) {
+		rte_errno = -EEXIST;
+		return NULL;
+	}
+
+	/* Create shared data area. */
+	n = snprintf(mz_name, sizeof(mz_name), DATA_MZ_NAME_FORMAT, adapter_id);
+	if (n >= (int)sizeof(mz_name)) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+	mz = rte_memzone_reserve(mz_name,
+				 sizeof(struct rte_event_timer_adapter_data),
+				 conf->socket_id, 0);
+	if (mz == NULL)
+		/* rte_errno set by rte_memzone_reserve */
+		return NULL;
+
+	adapter->data = mz->addr;
+	memset(adapter->data, 0, sizeof(struct rte_event_timer_adapter_data));
+
+	adapter->data->mz = mz;
+	adapter->data->event_dev_id = conf->event_dev_id;
+	adapter->data->id = adapter_id;
+	adapter->data->socket_id = conf->socket_id;
+	adapter->data->conf = *conf;  /* copy conf structure */
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	if (!(adapter->data->caps &
+	      RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+		FUNC_PTR_OR_NULL_RET_WITH_ERRNO(conf_cb, -EINVAL);
+		ret = conf_cb(adapter->data->id, adapter->data->event_dev_id,
+			      &adapter->data->event_port_id, conf_arg);
+		if (ret < 0) {
+			rte_errno = -EINVAL;
+			return NULL;
+		}
+	}
+
+	/* Allow driver to do some setup */
+	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
+	ret = adapter->ops->init(adapter);
+	if (ret < 0) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+}
+
+int
+rte_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->ops->get_info)
+		/* let driver set values it knows */
+		adapter->ops->get_info(adapter, adapter_info);
+
+	/* Set common values */
+	adapter_info->conf = adapter->data->conf;
+	adapter_info->event_dev_port_id = adapter->data->event_port_id;
+	adapter_info->caps = adapter->data->caps;
+
+	return 0;
+}
+
+int
+rte_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->start, -EINVAL);
+
+	ret = adapter->ops->start(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 1;
+
+	return 0;
+}
+
+int
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stop, -EINVAL);
+
+	ret = adapter->ops->stop(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 0;
+
+	return 0;
+}
+
+struct rte_event_timer_adapter *
+rte_event_timer_adapter_lookup(uint16_t adapter_id)
+{
+	char name[DATA_MZ_NAME_MAX_LEN];
+	const struct rte_memzone *mz;
+	struct rte_event_timer_adapter_data *data;
+	struct rte_event_timer_adapter *adapter;
+	int ret;
+	struct rte_eventdev *dev;
+
+	if (adapters[adapter_id].allocated)
+		return &adapters[adapter_id]; /* Adapter is already loaded */
+
+	snprintf(name, DATA_MZ_NAME_MAX_LEN, DATA_MZ_NAME_FORMAT, adapter_id);
+	mz = rte_memzone_lookup(name);
+	if (mz == NULL) {
+		rte_errno = -ENOENT;
+		return NULL;
+	}
+
+	data = mz->addr;
+
+	adapter = &adapters[data->id];
+	adapter->data = data;
+
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+}
+
+int
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->uninit, -EINVAL);
+
+	/* free impl priv data */
+	ret = adapter->ops->uninit(adapter);
+	if (ret < 0)
+		return ret;
+
+	/* free shared data area */
+	ret = rte_memzone_free(adapter->data->mz);
+	if (ret < 0)
+		return ret;
+
+	adapter->data = NULL;
+	adapter->allocated = 0;
+
+	return 0;
+}
+
+int
+rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **event_timers,
+			  uint16_t nb_event_timers)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_burst, -EINVAL);
+#endif
+
+	if (!adapter->data->started)
+		return -EAGAIN;
+
+	return adapter->arm_burst(adapter, event_timers, nb_event_timers);
+}
+
+int
+rte_event_timer_arm_tmo_tick_burst(
+			const struct rte_event_timer_adapter *adapter,
+			struct rte_event_timer **event_timers,
+			const uint64_t timeout_ticks,
+			const uint16_t nb_event_timers)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_tmo_tick_burst, -EINVAL);
+#endif
+
+	if (!adapter->data->started)
+		return -EAGAIN;
+
+	for (int i = 0; i < nb_event_timers; i++)
+		event_timers[i]->timeout_ticks = timeout_ticks;
+
+	return adapter->arm_tmo_tick_burst(adapter, event_timers, timeout_ticks,
+					  nb_event_timers);
+}
+
+int
+rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			     struct rte_event_timer **event_timers,
+			     uint16_t nb_event_timers)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->cancel_burst, -EINVAL);
+#endif
+
+	if (!adapter->data->started)
+		return -EAGAIN;
+
+	return adapter->cancel_burst(adapter, event_timers, nb_event_timers);
+}
diff --git a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
new file mode 100644
index 0000000..485fad1
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
@@ -0,0 +1,159 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_DRIVER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_DRIVER_H__
+
+/**
+ * @file
+ *
+ * Description
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "rte_event_timer_adapter.h"
+
+/*
+ * Definitions of functions exported by an event timer adapter implementation
+ * through *rte_event_timer_adapter_ops* structure supplied in the
+ * *rte_event_timer_adapter* structure associated with an event timer adapter.
+ */
+
+typedef int (*rte_event_timer_adapter_init_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation setup */
+typedef int (*rte_event_timer_adapter_uninit_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation teardown */
+typedef int (*rte_event_timer_adapter_start_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Start running event timer adapter */
+typedef int (*rte_event_timer_adapter_stop_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Stop running event timer adapter */
+typedef void (*rte_event_timer_adapter_get_info_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+/**< @internal Get contextual information for event timer adapter */
+typedef int (*rte_event_timer_arm_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Enable event timers to enqueue timer events upon expiry */
+typedef int (*rte_event_timer_arm_tmo_tick_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint64_t timeout_tick,
+		uint16_t nb_tims);
+/**< @internal Enable event timers with common expiration time */
+typedef int (*rte_event_timer_cancel_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Prevent event timers from enqueuing timer events */
+
+/**
+ * @internal Structure containing the functions exported by an event timer
+ * adapter implementation.
+ */
+struct rte_event_timer_adapter_ops {
+	rte_event_timer_adapter_init_t		init;  /**< Set up adapter */
+	rte_event_timer_adapter_uninit_t	uninit;/**< Tear down adapter */
+	rte_event_timer_adapter_start_t		start; /**< Start adapter */
+	rte_event_timer_adapter_stop_t		stop;  /**< Stop adapter */
+	rte_event_timer_adapter_get_info_t	get_info;
+	/**< Get info from driver */
+	rte_event_timer_arm_burst_t		arm_burst;
+	/**< Arm one or more event timers */
+	rte_event_timer_arm_tmo_tick_burst_t	arm_tmo_tick_burst;
+	/**< Arm event timers with same expiration time */
+	rte_event_timer_cancel_burst_t		cancel_burst;
+	/**< Cancel one or more event timers */
+};
+
+/**
+ * @internal Adapter data; structure to be placed in shared memory to be
+ * accessible by various processes in a multi-process configuration.
+ */
+struct rte_event_timer_adapter_data {
+	uint8_t id;
+	/**< Event timer adapter ID */
+	uint8_t event_dev_id;
+	/**< Event device ID */
+	uint32_t socket_id;
+	/**< Socket ID where memory is allocated */
+	uint8_t event_port_id;
+	/**< Optional: event port ID used when the inbuilt port is absent */
+	const struct rte_memzone *mz;
+	/**< Event timer adapter memzone pointer */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configuration used to configure the adapter. */
+	uint32_t caps;
+	/**< Adapter capabilities */
+	void *adapter_priv;
+	/**< Timer adapter private data*/
+
+	RTE_STD_C11
+	uint8_t started : 1;
+	/**< Flag to indicate adapter started. */
+} __rte_cache_aligned;
+
+/**
+ * @internal Data structure associated with each event timer adapter.
+ */
+struct rte_event_timer_adapter {
+	rte_event_timer_arm_burst_t arm_burst;
+	/**< Pointer to driver arm_burst function. */
+	rte_event_timer_arm_tmo_tick_burst_t arm_tmo_tick_burst;
+	/**< Pointer to driver arm_tmo_tick_burst function. */
+	rte_event_timer_cancel_burst_t cancel_burst;
+	/**< Pointer to driver cancel function. */
+
+	struct rte_event_timer_adapter_data *data;
+	/**< Pointer to shared adapter data */
+	const struct rte_event_timer_adapter_ops *ops;
+	/**< Functions exported by adapter driver */
+
+	RTE_STD_C11
+	uint8_t allocated : 1;
+	/**< Flag to indicate that this adapter has been allocated */
+} __rte_cache_aligned;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_DRIVER_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index a650f7a..e72da76 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -1025,6 +1025,9 @@ struct rte_event {
  * @see struct rte_event_eth_rx_adapter_queue_conf::rx_queue_flags
  */
 
+#define RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT (1ULL << 1)
+/**< This flag is set when the timer mechanism is in HW. */
+
 /**
  * Retrieve the event device's ethdev Rx adapter capabilities for the
  * specified ethernet port
diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h b/lib/librte_eventdev/rte_eventdev_pmd.h
index 7a206c5..321aef2 100644
--- a/lib/librte_eventdev/rte_eventdev_pmd.h
+++ b/lib/librte_eventdev/rte_eventdev_pmd.h
@@ -52,6 +52,7 @@ extern "C" {
 #include <rte_malloc.h>
 
 #include "rte_eventdev.h"
+#include "rte_event_timer_adapter_pmd.h"
 
 /* Logging Macros */
 #define RTE_EDEV_LOG_ERR(...) \
@@ -467,6 +468,37 @@ typedef int (*eventdev_eth_rx_adapter_caps_get_t)
 struct rte_event_eth_rx_adapter_queue_conf *queue_conf;
 
 /**
+ * Retrieve the event device's timer adapter capabilities, as well as the ops
+ * structure that an event timer adapter should call through to enter the
+ * driver
+ *
+ * @param dev
+ *   Event device pointer
+ *
+ * @param flags
+ *   Flags that can be used to determine how to select an event timer
+ *   adapter ops structure
+ *
+ * @param[out] caps
+ *   A pointer to memory filled with Rx event adapter capabilities.
+ *
+ * @param[out] ops
+ *   A pointer to the ops pointer to set with the address of the desired ops
+ *   structure
+ *
+ * @return
+ *   - 0: Success, driver provides Rx event adapter capabilities for the
+ *	ethernet device.
+ *   - <0: Error code returned by the driver function.
+ *
+ */
+typedef int (*eventdev_timer_adapter_caps_get_t)(
+				const struct rte_eventdev *dev,
+				uint64_t flags,
+				uint32_t *caps,
+				const struct rte_event_timer_adapter_ops **ops);
+
+/**
  * Add ethernet Rx queues to event device. This callback is invoked if
  * the caps returned from rte_eventdev_eth_rx_adapter_caps_get(, eth_port_id)
  * has RTE_EVENT_ETH_RX_ADAPTER_CAP_INTERNAL_PORT set.
@@ -650,6 +682,9 @@ struct rte_eventdev_ops {
 	/**< Get ethernet Rx stats */
 	eventdev_eth_rx_adapter_stats_reset eth_rx_adapter_stats_reset;
 	/**< Reset ethernet Rx stats */
+
+	eventdev_timer_adapter_caps_get_t timer_adapter_caps_get;
+	/**< Get timer adapter capabilities */
 };
 
 /**
diff --git a/lib/librte_eventdev/rte_eventdev_version.map b/lib/librte_eventdev/rte_eventdev_version.map
index 108ae61..f56ca0f 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -66,5 +66,18 @@ DPDK_17.11 {
 	rte_event_eth_rx_adapter_stats_get;
 	rte_event_eth_rx_adapter_stats_reset;
 	rte_event_eth_rx_adapter_stop;
-
 } DPDK_17.08;
+
+DPDK_18.02 {
+	global:
+
+	rte_event_timer_adapter_create;
+	rte_event_timer_adapter_create_ext;
+	rte_event_timer_adapter_free;
+	rte_event_timer_adapter_get_info;
+	rte_event_timer_adapter_start;
+	rte_event_timer_adapter_stop;
+	rte_event_timer_arm_burst;
+	rte_event_timer_arm_tmo_tick_burst;
+	rte_event_timer_cancel_burst;
+} DPDK_17.11;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [RFC PATCH v5 3/5] eventtimer: add config variable for adapter
  2017-12-01 20:00 ` [RFC PATCH v5 0/5] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  2017-12-01 20:00   ` [RFC PATCH v5 1/5] " Erik Gabriel Carrillo
  2017-12-01 20:00   ` [RFC PATCH v5 2/5] eventtimer: add common code Erik Gabriel Carrillo
@ 2017-12-01 20:00   ` Erik Gabriel Carrillo
  2017-12-06 15:41     ` Jerin Jacob
  2017-12-01 20:00   ` [RFC PATCH v5 4/5] eventtimer: add default software implementation stub Erik Gabriel Carrillo
                     ` (2 subsequent siblings)
  5 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2017-12-01 20:00 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

This commit introduces a configuration variable that can
be used to enable or disable compilation of the event timer
adapter.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 config/common_base                     | 1 +
 drivers/event/sw/sw_evdev.c            | 4 ++++
 lib/librte_eventdev/Makefile           | 6 +++---
 lib/librte_eventdev/rte_eventdev_pmd.h | 6 ++++++
 4 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/config/common_base b/config/common_base
index 91a2f0f..09d2a62 100644
--- a/config/common_base
+++ b/config/common_base
@@ -574,6 +574,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
 CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
 CONFIG_RTE_EVENT_MAX_DEVS=16
 CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER=y
 CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER_DEBUG=n
 
 #
diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index 94da675..69050cf 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -435,6 +435,7 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
 	return 0;
 }
 
+#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
 static int
 sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
 			  uint64_t flags,
@@ -450,6 +451,7 @@ sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
 
 	return 0;
 }
+#endif
 
 static void
 sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
@@ -771,7 +773,9 @@ sw_probe(struct rte_vdev_device *vdev)
 
 			.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
 
+#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
 			.timer_adapter_caps_get = sw_timer_adapter_caps_get,
+#endif
 
 			.xstats_get = sw_xstats_get,
 			.xstats_get_names = sw_xstats_get_names,
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index f3f05c2..2e47fa5 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -45,7 +45,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
 SRCS-y += rte_eventdev.c
 SRCS-y += rte_event_ring.c
 SRCS-y += rte_event_eth_rx_adapter.c
-SRCS-y += rte_event_timer_adapter.c
+SRCS-$(CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER) += rte_event_timer_adapter.c
 
 # export include files
 SYMLINK-y-include += rte_eventdev.h
@@ -54,8 +54,8 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
-SYMLINK-y-include += rte_event_timer_adapter.h
-SYMLINK-y-include += rte_event_timer_adapter_pmd.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER)-include += rte_event_timer_adapter.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER)-include += rte_event_timer_adapter_pmd.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h b/lib/librte_eventdev/rte_eventdev_pmd.h
index 321aef2..91e1f47 100644
--- a/lib/librte_eventdev/rte_eventdev_pmd.h
+++ b/lib/librte_eventdev/rte_eventdev_pmd.h
@@ -52,7 +52,9 @@ extern "C" {
 #include <rte_malloc.h>
 
 #include "rte_eventdev.h"
+#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
 #include "rte_event_timer_adapter_pmd.h"
+#endif
 
 /* Logging Macros */
 #define RTE_EDEV_LOG_ERR(...) \
@@ -467,6 +469,7 @@ typedef int (*eventdev_eth_rx_adapter_caps_get_t)
 
 struct rte_event_eth_rx_adapter_queue_conf *queue_conf;
 
+#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
 /**
  * Retrieve the event device's timer adapter capabilities, as well as the ops
  * structure that an event timer adapter should call through to enter the
@@ -497,6 +500,7 @@ typedef int (*eventdev_timer_adapter_caps_get_t)(
 				uint64_t flags,
 				uint32_t *caps,
 				const struct rte_event_timer_adapter_ops **ops);
+#endif
 
 /**
  * Add ethernet Rx queues to event device. This callback is invoked if
@@ -683,8 +687,10 @@ struct rte_eventdev_ops {
 	eventdev_eth_rx_adapter_stats_reset eth_rx_adapter_stats_reset;
 	/**< Reset ethernet Rx stats */
 
+#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
 	eventdev_timer_adapter_caps_get_t timer_adapter_caps_get;
 	/**< Get timer adapter capabilities */
+#endif
 };
 
 /**
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [RFC PATCH v5 4/5] eventtimer: add default software implementation stub
  2017-12-01 20:00 ` [RFC PATCH v5 0/5] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                     ` (2 preceding siblings ...)
  2017-12-01 20:00   ` [RFC PATCH v5 3/5] eventtimer: add config variable for adapter Erik Gabriel Carrillo
@ 2017-12-01 20:00   ` Erik Gabriel Carrillo
  2017-12-01 20:00   ` [RFC PATCH v5 5/5] test: add event timer adapter auto-test Erik Gabriel Carrillo
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  5 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2017-12-01 20:00 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

If an eventdev PMD does not wish to provide event timer adapter ops
definitions, the library will fall back to a default software
implementation whose entry points are added by this commit.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 107 ++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 5315058..d5a58ff 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -48,6 +48,8 @@
 
 static struct rte_event_timer_adapter adapters[MAX_EVENT_TIMER_ADAPTERS];
 
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+
 static inline int
 adapter_valid(const struct rte_event_timer_adapter *adapter)
 {
@@ -211,6 +213,12 @@ rte_event_timer_adapter_create_ext(
 		}
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Allow driver to do some setup */
 	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
 	ret = adapter->ops->init(adapter);
@@ -318,6 +326,12 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
 		return NULL;
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Set fast-path function pointers */
 	adapter->arm_burst = adapter->ops->arm_burst;
 	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
@@ -405,3 +419,96 @@ rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
 
 	return adapter->cancel_burst(adapter, event_timers, nb_event_timers);
 }
+
+/*
+ * Software event timer adapter ops definitions
+ */
+
+static int
+sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
+{
+	RTE_SET_USED(adapter);
+
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)
+{
+	RTE_SET_USED(adapter);
+
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	RTE_SET_USED(adapter);
+
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	RTE_SET_USED(adapter);
+
+	return 0;
+}
+
+static void
+sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+			struct rte_event_timer_adapter_info *adapter_info)
+{
+	RTE_SET_USED(adapter);
+	RTE_SET_USED(adapter_info);
+}
+
+static int
+sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			 struct rte_event_timer **evtims,
+			 uint16_t nb_evtims)
+{
+	RTE_SET_USED(adapter);
+	RTE_SET_USED(evtims);
+	RTE_SET_USED(nb_evtims);
+
+	return 0;
+}
+
+static int
+sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			    struct rte_event_timer **evtims,
+			    uint16_t nb_evtims)
+{
+	RTE_SET_USED(adapter);
+	RTE_SET_USED(evtims);
+	RTE_SET_USED(nb_evtims);
+
+	return 0;
+}
+
+static int
+sw_event_timer_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer **tims,
+				  uint64_t timeout_tick,
+				  uint16_t nb_tims)
+{
+	RTE_SET_USED(adapter);
+	RTE_SET_USED(tims);
+	RTE_SET_USED(timeout_tick);
+	RTE_SET_USED(nb_tims);
+
+	return 0;
+}
+
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
+	.init = sw_event_timer_adapter_init,
+	.uninit = sw_event_timer_adapter_uninit,
+	.start = sw_event_timer_adapter_start,
+	.stop = sw_event_timer_adapter_stop,
+	.get_info = sw_event_timer_adapter_get_info,
+	.arm_burst = sw_event_timer_arm_burst,
+	.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
+	.cancel_burst = sw_event_timer_cancel_burst,
+};
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [RFC PATCH v5 5/5] test: add event timer adapter auto-test
  2017-12-01 20:00 ` [RFC PATCH v5 0/5] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                     ` (3 preceding siblings ...)
  2017-12-01 20:00   ` [RFC PATCH v5 4/5] eventtimer: add default software implementation stub Erik Gabriel Carrillo
@ 2017-12-01 20:00   ` Erik Gabriel Carrillo
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  5 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2017-12-01 20:00 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

This commit adds enough test infrastructure to exercise the
allocation/deallocation routines of the event timer adapter library
minimally.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 test/test/Makefile                   |   1 +
 test/test/test_event_timer_adapter.c | 249 +++++++++++++++++++++++++++++++++++
 2 files changed, 250 insertions(+)
 create mode 100644 test/test/test_event_timer_adapter.c

diff --git a/test/test/Makefile b/test/test/Makefile
index bb54c98..9448aef 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -210,6 +210,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
 SRCS-y += test_eventdev.c
 SRCS-y += test_event_ring.c
 SRCS-y += test_event_eth_rx_adapter.c
+SRCS-y += test_event_timer_adapter.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV) += test_eventdev_sw.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF) += test_eventdev_octeontx.c
 endif
diff --git a/test/test/test_event_timer_adapter.c b/test/test/test_event_timer_adapter.c
new file mode 100644
index 0000000..d0ea066
--- /dev/null
+++ b/test/test/test_event_timer_adapter.c
@@ -0,0 +1,249 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include <rte_eventdev.h>
+#include <rte_dev.h>
+#include <rte_bus_vdev.h>
+#include <rte_event_timer_adapter.h>
+#include <rte_mempool.h>
+#include <rte_errno.h>
+#include <rte_service_component.h>
+
+#include "test.h"
+
+/* Example from RFC */
+#define NB_TEST_EVENT_TIMERS 40000
+
+static int evdev;
+//struct rte_event_timer_adapter *g_adapter;
+struct rte_event_timer *g_evtimer;
+struct rte_mempool *g_event_timer_pool;
+
+static inline void
+devconf_set_default_sane_values(struct rte_event_dev_config *dev_conf,
+			struct rte_event_dev_info *info)
+{
+	memset(dev_conf, 0, sizeof(struct rte_event_dev_config));
+	dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns;
+	/* Leave a port for the adapter to allocate */
+	dev_conf->nb_event_ports = info->max_event_ports - 1;
+	dev_conf->nb_event_queues = info->max_event_queues;
+	dev_conf->nb_event_queue_flows = info->max_event_queue_flows;
+	dev_conf->nb_event_port_dequeue_depth =
+			info->max_event_port_dequeue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+			info->max_event_port_enqueue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+			info->max_event_port_enqueue_depth;
+	dev_conf->nb_events_limit =
+			info->max_num_events;
+}
+
+static int
+configure_event_dev(void)
+{
+	struct rte_event_dev_config devconf;
+	int ret;
+	const char *eventdev_name = "event_sw0";
+	struct rte_event_dev_info info;
+	int i;
+
+	evdev = rte_event_dev_get_dev_id(eventdev_name);
+	if (evdev < 0) {
+		if (rte_vdev_init(eventdev_name, NULL) < 0) {
+			printf("Error creating eventdev\n");
+			return TEST_FAILED;
+		}
+		evdev = rte_event_dev_get_dev_id(eventdev_name);
+		if (evdev < 0) {
+			printf("Error finding newly created eventdev\n");
+			return TEST_FAILED;
+		}
+	}
+
+	ret = rte_event_dev_info_get(evdev, &info);
+	TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info");
+
+	devconf_set_default_sane_values(&devconf, &info);
+
+	ret = rte_event_dev_configure(evdev, &devconf);
+	TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev");
+
+	/* Map the event_sw0 service to a service core */
+	ret = rte_service_start_with_defaults();
+	TEST_ASSERT_SUCCESS(ret, "Failed to start sw_evdev service");
+
+	/* Set up event queues */
+	uint32_t queue_count;
+	TEST_ASSERT_SUCCESS(rte_event_dev_attr_get(evdev,
+			    RTE_EVENT_DEV_ATTR_QUEUE_COUNT, &queue_count),
+			    "Queue count get failed");
+
+	for (i = 0; i < (int)queue_count; i++) {
+		ret = rte_event_queue_setup(evdev, i, NULL);
+		TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", i);
+	}
+
+	/* Set up event ports */
+	uint32_t port_count;
+	TEST_ASSERT_SUCCESS(rte_event_dev_attr_get(evdev,
+			    RTE_EVENT_DEV_ATTR_PORT_COUNT,
+			    &port_count), "Port count get failed");
+
+	for (i = 0; i < (int)port_count; i++) {
+		ret = rte_event_port_setup(evdev, i, NULL);
+		TEST_ASSERT_SUCCESS(ret, "Failed to setup port=%d", i);
+		/* Link each queues to all ports */
+		ret = rte_event_port_link(evdev, i, NULL, NULL, 0);
+		TEST_ASSERT(ret >= 0, "Failed to link all queues port=%d", i);
+	}
+
+	/* Start the event device */
+	ret = rte_event_dev_start(evdev);
+	TEST_ASSERT_SUCCESS(ret, "Failed to start device");
+
+	return TEST_SUCCESS;
+}
+
+static int
+testsuite_setup(void)
+{
+	int ret;
+
+	/* Setup and start event device. */
+	ret = configure_event_dev();
+	if (ret) {
+		printf("Failed to configure event dev\n");
+		return TEST_FAILED;
+	}
+
+	/* Create a mempool of event timers. */
+	g_event_timer_pool = rte_mempool_create("event_timer_mempool",
+						NB_TEST_EVENT_TIMERS,
+						sizeof(struct rte_event_timer),
+						0,
+						0,
+						NULL,
+						NULL,
+						NULL,
+						NULL,
+						rte_socket_id(),
+						0);
+	if (g_event_timer_pool == NULL) {
+		/* Failed to create event timer mempool. */
+		printf("Failed to configure event timer mempool: %s\n",
+		       rte_strerror(rte_errno));
+		return TEST_FAILED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static void
+testsuite_teardown(void)
+{
+	/* TODO: tear down adapter and evdev */
+
+	rte_mempool_free(g_event_timer_pool);
+}
+
+#define NSECPERSEC 1E9  // No of ns for 1 sec
+
+static int
+adapter_create_free(void)
+{
+	int ret;
+	int adapter_id = 0;
+	struct rte_event_timer_adapter *adapter;
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev,
+		.timer_adapter_id = adapter_id,
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,  // 100 milliseconds
+		.max_tmo_ns = 180 * NSECPERSEC,  // 2 minutes
+		.nb_timers = NB_TEST_EVENT_TIMERS,
+		.flags = 0,
+	};
+
+	adapter = rte_event_timer_adapter_create(&conf);
+	if (adapter == NULL) {
+		printf("Failed to create adapter\n");
+		return TEST_FAILED;
+	}
+
+	/* Move to separate tests later; just verify plugin connections for
+	 * now
+	 */
+
+	struct rte_event_timer_adapter_info adapter_info;
+	ret = rte_event_timer_adapter_get_info(adapter, &adapter_info);
+	if (ret < 0)
+		return TEST_FAILED;
+
+	ret = rte_event_timer_adapter_start(adapter);
+	if (ret < 0)
+		return TEST_FAILED;
+
+	ret = rte_event_timer_adapter_stop(adapter);
+	if (ret < 0)
+		return TEST_FAILED;
+
+	ret = rte_event_timer_adapter_free(adapter);
+	if (ret) {
+		printf("Failed to free adapter\n");
+		return TEST_FAILED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static struct unit_test_suite adapter_tests  = {
+	.suite_name = "event timer adapter test suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE(adapter_create_free),
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+static int
+test_event_timer_adapter_common(void)
+{
+	return unit_test_suite_runner(&adapter_tests);
+}
+
+REGISTER_TEST_COMMAND(event_timer_adapter_autotest,
+		      test_event_timer_adapter_common);
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [RFC PATCH v5 1/5] eventtimer: introduce event timer adapter
  2017-12-01 20:00   ` [RFC PATCH v5 1/5] " Erik Gabriel Carrillo
@ 2017-12-06 15:17     ` Jerin Jacob
  2017-12-06 16:23       ` Carrillo, Erik G
  0 siblings, 1 reply; 133+ messages in thread
From: Jerin Jacob @ 2017-12-06 15:17 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal

-----Original Message-----
> Date: Fri, 1 Dec 2017 14:00:54 -0600
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com,
>  hemant.agrawal@nxp.com
> Subject: [RFC PATCH v5 1/5] eventtimer: introduce event timer adapter
> X-Mailer: git-send-email 1.7.10
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>

Feel free to add my Signed-off-by as this patch is mostly based on initial RFC.

> ---
>  doc/api/doxy-api-index.md                     |   1 +
>  lib/librte_eventdev/Makefile                  |   1 +
>  lib/librte_eventdev/rte_event_timer_adapter.h | 518 ++++++++++++++++++++++++++
>  lib/librte_eventdev/rte_eventdev.h            |   4 +-
>  4 files changed, 522 insertions(+), 2 deletions(-)
>  create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h
> 
> + * Event timer state.
> + */
> +enum rte_event_timer_state {
> +	RTE_EVENT_TIMER_NOT_ARMED = 0,
> +	/**< Event timer is in not armed state.*/
> +	RTE_EVENT_TIMER_ARMED = 1,
> +	/**< Event timer successfully armed.*/

How about adding a state called RTE_EVENT_TIMER_CANCELED?, Which
will updated by the driver on rte_event_timer_arm_burst().
This will enable application to get the state of the rte_event_timer object 
in latter time.

> +	RTE_EVENT_TIMER_ERROR = -1,
> +	/**< Generic event timer error.*/
> +	RTE_EVENT_TIMER_ERROR_TOOEARLY = -2,
> +	/**< Event timer timeout tick is too little to add to the adapter. */
> +	RTE_EVENT_TIMER_ERROR_TOOLATE = -3,
> +	/**< Event timer timeout tick is greater than the maximum timeout.*/
> +};
> +
> +/**

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [RFC PATCH v5 2/5] eventtimer: add common code
  2017-12-01 20:00   ` [RFC PATCH v5 2/5] eventtimer: add common code Erik Gabriel Carrillo
@ 2017-12-06 15:35     ` Jerin Jacob
  0 siblings, 0 replies; 133+ messages in thread
From: Jerin Jacob @ 2017-12-06 15:35 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal

-----Original Message-----
> Date: Fri, 1 Dec 2017 14:00:55 -0600
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com,
>  hemant.agrawal@nxp.com
> Subject: [RFC PATCH v5 2/5] eventtimer: add common code
> X-Mailer: git-send-email 1.7.10
> 
> This commit adds the logic that is shared by all event timer adapter
> drivers; the common code handles instance allocation and some
> initialization.
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  config/common_base                                |   1 +
>  drivers/event/sw/sw_evdev.c                       |  18 +
>  lib/librte_eventdev/Makefile                      |   2 +
>  lib/librte_eventdev/rte_event_timer_adapter.c     | 407 ++++++++++++++++++++++
>  lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 159 +++++++++
>  lib/librte_eventdev/rte_eventdev.h                |   3 +
>  lib/librte_eventdev/rte_eventdev_pmd.h            |  35 ++
>  lib/librte_eventdev/rte_eventdev_version.map      |  15 +-
>  8 files changed, 639 insertions(+), 1 deletion(-)
>  create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
>  create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h
> 
> diff --git a/config/common_base b/config/common_base
> index e74febe..91a2f0f 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -574,6 +574,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
>  CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
>  CONFIG_RTE_EVENT_MAX_DEVS=16
>  CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
> +CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER_DEBUG=n
>  
>  #
> +rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
> +			  struct rte_event_timer **event_timers,
> +			  uint16_t nb_event_timers)
> +{
> +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER_DEBUG
> +	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
> +	FUNC_PTR_OR_ERR_RET(adapter->arm_burst, -EINVAL);
> +#endif
> +
> +	if (!adapter->data->started)
> +		return -EAGAIN;

Other subsystems like ethdev, cryptodev, eventdev does not
have this check in fastpath as it is costly. IMO, We can remove this check.

> +
> +	return adapter->arm_burst(adapter, event_timers, nb_event_timers);
> +}
> +
> +int
> +rte_event_timer_arm_tmo_tick_burst(
> +			const struct rte_event_timer_adapter *adapter,
> +			struct rte_event_timer **event_timers,
> +			const uint64_t timeout_ticks,
> +			const uint16_t nb_event_timers)
> +{
> +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER_DEBUG
> +	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
> +	FUNC_PTR_OR_ERR_RET(adapter->arm_tmo_tick_burst, -EINVAL);
> +#endif
> +
> +	if (!adapter->data->started)
> +		return -EAGAIN;

Same as above.

> +
> +	for (int i = 0; i < nb_event_timers; i++)
> +		event_timers[i]->timeout_ticks = timeout_ticks;

IMO, We can push this to driver as driver may be in a position to
to do better driver specific optimization.

> +
> +	return adapter->arm_tmo_tick_burst(adapter, event_timers, timeout_ticks,
> +					  nb_event_timers);
> +}
> +
> +int
> +rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
> +			     struct rte_event_timer **event_timers,
> +			     uint16_t nb_event_timers)
> +{
> +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER_DEBUG
> +	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
> +	FUNC_PTR_OR_ERR_RET(adapter->cancel_burst, -EINVAL);
> +#endif
> +
> +	if (!adapter->data->started)
> +		return -EAGAIN;

Same as above.

> +
> +	return adapter->cancel_burst(adapter, event_timers, nb_event_timers);
> +}
>   */
>  

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [RFC PATCH v5 3/5] eventtimer: add config variable for adapter
  2017-12-01 20:00   ` [RFC PATCH v5 3/5] eventtimer: add config variable for adapter Erik Gabriel Carrillo
@ 2017-12-06 15:41     ` Jerin Jacob
  2017-12-06 20:01       ` Carrillo, Erik G
  0 siblings, 1 reply; 133+ messages in thread
From: Jerin Jacob @ 2017-12-06 15:41 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal

-----Original Message-----
> Date: Fri, 1 Dec 2017 14:00:56 -0600
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com,
>  hemant.agrawal@nxp.com
> Subject: [RFC PATCH v5 3/5] eventtimer: add config variable for adapter
> X-Mailer: git-send-email 1.7.10
> 
> This commit introduces a configuration variable that can
> be used to enable or disable compilation of the event timer
> adapter.
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  config/common_base                     | 1 +
>  drivers/event/sw/sw_evdev.c            | 4 ++++
>  lib/librte_eventdev/Makefile           | 6 +++---
>  lib/librte_eventdev/rte_eventdev_pmd.h | 6 ++++++
>  4 files changed, 14 insertions(+), 3 deletions(-)
> 
> diff --git a/config/common_base b/config/common_base
> index 91a2f0f..09d2a62 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -574,6 +574,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
>  CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
>  CONFIG_RTE_EVENT_MAX_DEVS=16
>  CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
> +CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER=y

IMO, We can remove this option to remove conditional compilation
code introduced in this patch.

>  CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER_DEBUG=n

How about reusing CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG to support
the above comment. Rx adapter does the same thing, IMO, It is worth to
follow that.

>  
>  #
> diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
> index 94da675..69050cf 100644
> --- a/drivers/event/sw/sw_evdev.c
> +++ b/drivers/event/sw/sw_evdev.c
> @@ -435,6 +435,7 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
>  	return 0;
>  }
>  
> +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
>  static int
>  sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
>  			  uint64_t flags,
> @@ -450,6 +451,7 @@ sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
>  
>  	return 0;
>  }
> +#endif
>  
>  static void
>  sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
> @@ -771,7 +773,9 @@ sw_probe(struct rte_vdev_device *vdev)
>  
>  			.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
>  
> +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
>  			.timer_adapter_caps_get = sw_timer_adapter_caps_get,
> +#endif
>  
>  			.xstats_get = sw_xstats_get,
>  			.xstats_get_names = sw_xstats_get_names,
> diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
> index f3f05c2..2e47fa5 100644
> --- a/lib/librte_eventdev/Makefile
> +++ b/lib/librte_eventdev/Makefile
> @@ -45,7 +45,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
>  SRCS-y += rte_eventdev.c
>  SRCS-y += rte_event_ring.c
>  SRCS-y += rte_event_eth_rx_adapter.c
> -SRCS-y += rte_event_timer_adapter.c
> +SRCS-$(CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER) += rte_event_timer_adapter.c
>  
>  # export include files
>  SYMLINK-y-include += rte_eventdev.h
> @@ -54,8 +54,8 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
>  SYMLINK-y-include += rte_eventdev_pmd_vdev.h
>  SYMLINK-y-include += rte_event_ring.h
>  SYMLINK-y-include += rte_event_eth_rx_adapter.h
> -SYMLINK-y-include += rte_event_timer_adapter.h
> -SYMLINK-y-include += rte_event_timer_adapter_pmd.h
> +SYMLINK-$(CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER)-include += rte_event_timer_adapter.h
> +SYMLINK-$(CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER)-include += rte_event_timer_adapter_pmd.h
>  
>  # versioning export map
>  EXPORT_MAP := rte_eventdev_version.map
> diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h b/lib/librte_eventdev/rte_eventdev_pmd.h
> index 321aef2..91e1f47 100644
> --- a/lib/librte_eventdev/rte_eventdev_pmd.h
> +++ b/lib/librte_eventdev/rte_eventdev_pmd.h
> @@ -52,7 +52,9 @@ extern "C" {
>  #include <rte_malloc.h>
>  
>  #include "rte_eventdev.h"
> +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
>  #include "rte_event_timer_adapter_pmd.h"
> +#endif
>  
>  /* Logging Macros */
>  #define RTE_EDEV_LOG_ERR(...) \
> @@ -467,6 +469,7 @@ typedef int (*eventdev_eth_rx_adapter_caps_get_t)
>  
>  struct rte_event_eth_rx_adapter_queue_conf *queue_conf;
>  
> +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
>  /**
>   * Retrieve the event device's timer adapter capabilities, as well as the ops
>   * structure that an event timer adapter should call through to enter the
> @@ -497,6 +500,7 @@ typedef int (*eventdev_timer_adapter_caps_get_t)(
>  				uint64_t flags,
>  				uint32_t *caps,
>  				const struct rte_event_timer_adapter_ops **ops);
> +#endif
>  
>  /**
>   * Add ethernet Rx queues to event device. This callback is invoked if
> @@ -683,8 +687,10 @@ struct rte_eventdev_ops {
>  	eventdev_eth_rx_adapter_stats_reset eth_rx_adapter_stats_reset;
>  	/**< Reset ethernet Rx stats */
>  
> +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
>  	eventdev_timer_adapter_caps_get_t timer_adapter_caps_get;
>  	/**< Get timer adapter capabilities */
> +#endif
>  };
>  
>  /**
> -- 
> 2.6.4
> 

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [RFC PATCH v5 1/5] eventtimer: introduce event timer adapter
  2017-12-06 15:17     ` Jerin Jacob
@ 2017-12-06 16:23       ` Carrillo, Erik G
  0 siblings, 0 replies; 133+ messages in thread
From: Carrillo, Erik G @ 2017-12-06 16:23 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal



> -----Original Message-----
> From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> Sent: Wednesday, December 6, 2017 9:18 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>
> Cc: pbhagavatula@caviumnetworks.com; dev@dpdk.org;
> nipun.gupta@nxp.com; hemant.agrawal@nxp.com
> Subject: Re: [RFC PATCH v5 1/5] eventtimer: introduce event timer adapter
> 
> -----Original Message-----
> > Date: Fri, 1 Dec 2017 14:00:54 -0600
> > From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > To: pbhagavatula@caviumnetworks.com
> > CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com,
> nipun.gupta@nxp.com,
> > hemant.agrawal@nxp.com
> > Subject: [RFC PATCH v5 1/5] eventtimer: introduce event timer adapter
> > X-Mailer: git-send-email 1.7.10
> >
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> 
> Feel free to add my Signed-off-by as this patch is mostly based on initial RFC.

Ok, thanks.  Pavan, I'll add yours back as well... if you'd rather I don't, just let me know.

> 
> > ---
> >  doc/api/doxy-api-index.md                     |   1 +
> >  lib/librte_eventdev/Makefile                  |   1 +
> >  lib/librte_eventdev/rte_event_timer_adapter.h | 518
> ++++++++++++++++++++++++++
> >  lib/librte_eventdev/rte_eventdev.h            |   4 +-
> >  4 files changed, 522 insertions(+), 2 deletions(-)  create mode
> > 100644 lib/librte_eventdev/rte_event_timer_adapter.h
> >
> > + * Event timer state.
> > + */
> > +enum rte_event_timer_state {
> > +	RTE_EVENT_TIMER_NOT_ARMED = 0,
> > +	/**< Event timer is in not armed state.*/
> > +	RTE_EVENT_TIMER_ARMED = 1,
> > +	/**< Event timer successfully armed.*/
> 
> How about adding a state called RTE_EVENT_TIMER_CANCELED?, Which will
> updated by the driver on rte_event_timer_arm_burst().
> This will enable application to get the state of the rte_event_timer object in
> latter time.

Good catch - I didn't realize that state had been dropped.  I'll add it back in.

Thanks,
Gabriel

> 
> > +	RTE_EVENT_TIMER_ERROR = -1,
> > +	/**< Generic event timer error.*/
> > +	RTE_EVENT_TIMER_ERROR_TOOEARLY = -2,
> > +	/**< Event timer timeout tick is too little to add to the adapter. */
> > +	RTE_EVENT_TIMER_ERROR_TOOLATE = -3,
> > +	/**< Event timer timeout tick is greater than the maximum
> timeout.*/
> > +};
> > +
> > +/**

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [RFC PATCH v5 3/5] eventtimer: add config variable for adapter
  2017-12-06 15:41     ` Jerin Jacob
@ 2017-12-06 20:01       ` Carrillo, Erik G
  0 siblings, 0 replies; 133+ messages in thread
From: Carrillo, Erik G @ 2017-12-06 20:01 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal

Thanks, Jerin.  I'll make the changes suggested below and the changes suggested for the preceding patch in the next version of the series that is posted.

Regards,
Gabriel

> -----Original Message-----
> From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> Sent: Wednesday, December 6, 2017 9:42 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>
> Cc: pbhagavatula@caviumnetworks.com; dev@dpdk.org;
> nipun.gupta@nxp.com; hemant.agrawal@nxp.com
> Subject: Re: [RFC PATCH v5 3/5] eventtimer: add config variable for adapter
> 
> -----Original Message-----
> > Date: Fri, 1 Dec 2017 14:00:56 -0600
> > From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > To: pbhagavatula@caviumnetworks.com
> > CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com,
> nipun.gupta@nxp.com,
> > hemant.agrawal@nxp.com
> > Subject: [RFC PATCH v5 3/5] eventtimer: add config variable for
> > adapter
> > X-Mailer: git-send-email 1.7.10
> >
> > This commit introduces a configuration variable that can be used to
> > enable or disable compilation of the event timer adapter.
> >
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > ---
> >  config/common_base                     | 1 +
> >  drivers/event/sw/sw_evdev.c            | 4 ++++
> >  lib/librte_eventdev/Makefile           | 6 +++---
> >  lib/librte_eventdev/rte_eventdev_pmd.h | 6 ++++++
> >  4 files changed, 14 insertions(+), 3 deletions(-)
> >
> > diff --git a/config/common_base b/config/common_base index
> > 91a2f0f..09d2a62 100644
> > --- a/config/common_base
> > +++ b/config/common_base
> > @@ -574,6 +574,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
> > CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
> >  CONFIG_RTE_EVENT_MAX_DEVS=16
> >  CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
> > +CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER=y
> 
> IMO, We can remove this option to remove conditional compilation code
> introduced in this patch.
> 
> >  CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER_DEBUG=n
> 
> How about reusing CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG to support the
> above comment. Rx adapter does the same thing, IMO, It is worth to follow
> that.
> 
> >
> >  #
> > diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
> > index 94da675..69050cf 100644
> > --- a/drivers/event/sw/sw_evdev.c
> > +++ b/drivers/event/sw/sw_evdev.c
> > @@ -435,6 +435,7 @@ sw_eth_rx_adapter_caps_get(const struct
> rte_eventdev *dev,
> >  	return 0;
> >  }
> >
> > +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
> >  static int
> >  sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
> >  			  uint64_t flags,
> > @@ -450,6 +451,7 @@ sw_timer_adapter_caps_get(const struct
> > rte_eventdev *dev,
> >
> >  	return 0;
> >  }
> > +#endif
> >
> >  static void
> >  sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info
> > *info) @@ -771,7 +773,9 @@ sw_probe(struct rte_vdev_device *vdev)
> >
> >  			.eth_rx_adapter_caps_get =
> sw_eth_rx_adapter_caps_get,
> >
> > +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
> >  			.timer_adapter_caps_get =
> sw_timer_adapter_caps_get,
> > +#endif
> >
> >  			.xstats_get = sw_xstats_get,
> >  			.xstats_get_names = sw_xstats_get_names, diff --git
> > a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile index
> > f3f05c2..2e47fa5 100644
> > --- a/lib/librte_eventdev/Makefile
> > +++ b/lib/librte_eventdev/Makefile
> > @@ -45,7 +45,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev
> > -lrte_hash  SRCS-y += rte_eventdev.c  SRCS-y += rte_event_ring.c
> > SRCS-y += rte_event_eth_rx_adapter.c -SRCS-y +=
> > rte_event_timer_adapter.c
> > +SRCS-$(CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER) +=
> > +rte_event_timer_adapter.c
> >
> >  # export include files
> >  SYMLINK-y-include += rte_eventdev.h
> > @@ -54,8 +54,8 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
> > SYMLINK-y-include += rte_eventdev_pmd_vdev.h  SYMLINK-y-include +=
> > rte_event_ring.h  SYMLINK-y-include += rte_event_eth_rx_adapter.h
> > -SYMLINK-y-include += rte_event_timer_adapter.h -SYMLINK-y-include +=
> > rte_event_timer_adapter_pmd.h
> > +SYMLINK-$(CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER)-include
> +=
> > +rte_event_timer_adapter.h
> > +SYMLINK-$(CONFIG_RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER)-include
> +=
> > +rte_event_timer_adapter_pmd.h
> >
> >  # versioning export map
> >  EXPORT_MAP := rte_eventdev_version.map diff --git
> > a/lib/librte_eventdev/rte_eventdev_pmd.h
> > b/lib/librte_eventdev/rte_eventdev_pmd.h
> > index 321aef2..91e1f47 100644
> > --- a/lib/librte_eventdev/rte_eventdev_pmd.h
> > +++ b/lib/librte_eventdev/rte_eventdev_pmd.h
> > @@ -52,7 +52,9 @@ extern "C" {
> >  #include <rte_malloc.h>
> >
> >  #include "rte_eventdev.h"
> > +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
> >  #include "rte_event_timer_adapter_pmd.h"
> > +#endif
> >
> >  /* Logging Macros */
> >  #define RTE_EDEV_LOG_ERR(...) \
> > @@ -467,6 +469,7 @@ typedef int
> (*eventdev_eth_rx_adapter_caps_get_t)
> >
> >  struct rte_event_eth_rx_adapter_queue_conf *queue_conf;
> >
> > +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
> >  /**
> >   * Retrieve the event device's timer adapter capabilities, as well as the ops
> >   * structure that an event timer adapter should call through to enter
> > the @@ -497,6 +500,7 @@ typedef int
> (*eventdev_timer_adapter_caps_get_t)(
> >  				uint64_t flags,
> >  				uint32_t *caps,
> >  				const struct rte_event_timer_adapter_ops
> **ops);
> > +#endif
> >
> >  /**
> >   * Add ethernet Rx queues to event device. This callback is invoked
> > if @@ -683,8 +687,10 @@ struct rte_eventdev_ops {
> >  	eventdev_eth_rx_adapter_stats_reset eth_rx_adapter_stats_reset;
> >  	/**< Reset ethernet Rx stats */
> >
> > +#ifdef RTE_LIBRTE_EVENTDEV_TIMER_ADAPTER
> >  	eventdev_timer_adapter_caps_get_t timer_adapter_caps_get;
> >  	/**< Get timer adapter capabilities */
> > +#endif
> >  };
> >
> >  /**
> > --
> > 2.6.4
> >

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v6 00/23] eventtimer: introduce event timer adapter
  2017-12-01 20:00 ` [RFC PATCH v5 0/5] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                     ` (4 preceding siblings ...)
  2017-12-01 20:00   ` [RFC PATCH v5 5/5] test: add event timer adapter auto-test Erik Gabriel Carrillo
@ 2018-01-11  0:20   ` Erik Gabriel Carrillo
  2018-01-11  0:20     ` [PATCH v6 01/23] eventtimer: add event timer adapter API Erik Gabriel Carrillo
                       ` (23 more replies)
  5 siblings, 24 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:20 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

This patch set adds an initial implementation of the software driver
for the event timer adapter library, adds some unit tests, and adds
documentation.  More testing is needed, but I'd like to get feedback on the
current state.

This patch set produces the following checkpatch warning: 
"macro with flow control". I have left the macros in since such usage seems
common in DPDK.

The tests also depend on the following patch to pass:
http://dpdk.org/ml/archives/dev/2018-January/085209.html

v6
- Addressed comments on previous versin from Jerin:
  - Added RTE_EVENT_TIMER_CANCELED event timer state back in
  - remove check for started adapter in timer arm/cancel functions 
  - reuse CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG instead of adding new config option
- Added initial version of software driver implementation
- Added stats APIs
- Added API to retrieve adapter service ID
- Added API to initialize event timer
- Added entry to Programmer's Guide in documentation
- Added new unit tests to auto-test

v5
- Addressed comments on previous version from Pavan:
  - renamed rte_event_timer_adapter_driver.h to rte_event_timer_adapter_pmd.h
  - moved contents of sw_event_timer_adapter.c into rte_event_timer_adapter.c
  - added flags parameter to timer_adapter_caps_get() call
  - added DEBUG config variable to conditionally compile run-time checks on
    datapath
  - fixed license text and file description
- Also added a config variable to enable/disable compilation of event timer
  adapter - feedback on whether this is desirable is appreciated

v4
- Split changes into multiple patches for easier review

v3
- Reworked allocation and ops organization in common code based on feedback
  received from Jerin and Pavan. This will allow fast-path function pointers to 
  be dereferenced with one level of indirection with pointers valid in primary
  and secondary processes.
- Moved default software implementation from sw_evdev directory to eventdev
  library directory, which will allow it to be used by any eventdev PMD as an
  alternative to providing its own definitions.
- Reverted occurrences of id back to pointer to adapter struct in library API
- Added rte_event_timer_adapter_lookup() function back in

v2
- Added ops structure and stubbed out plugin for SW impl
- Added unit test stubs
- Replaced occurrences of "wheel" in API with "adapter"
- Replaced occurrences of pointer to struct rte_event_timer_adapter with ids
- Removed rte_event_timer_adapter_lookup() function
- Replaced RTE_EVENT_TIMER_SUCCESS_{ARM,CANCEL} states with
  RTE_EVENT_TIMER_ARMED

Erik Gabriel Carrillo (23):
  eventtimer: add event timer adapter API
  eventtimer: add common code
  eventtimer: add default software driver stub
  test: add event timer adapter auto-test
  eventtimer: add adapter allocation definitions
  test: exercise event timer adapter allocation functions
  eventtimer: add adapter get info function definition
  eventtimer: add adapter start/stop definitions
  eventtimer: add API to get service id
  eventtimer: remove service id entry from info structure
  test: exercise event timer adapter start/stop functions
  eventtimer: add event timer arm/cancel function definitions
  eventtimer: add adapter service definition
  eventtimer: add event timer initializer function
  eventtimer: add buffering of timer expiry events
  eventtimer: add stats to API
  eventtimer: add support for single-producer put mode
  eventtimer: add non-blocking mode for event timer operations
  test: exercise event timer arm and expiry
  maintainers: add event timer adapter section
  doc: add event timer adapter to API index
  doc: add event timer adapter section to programmer's guide
  doc: add event timer adapter to release notes

 MAINTAINERS                                       |    6 +
 doc/api/doxy-api-index.md                         |    1 +
 doc/guides/prog_guide/event_timer_adapter.rst     |  301 ++++++
 doc/guides/prog_guide/index.rst                   |    1 +
 doc/guides/rel_notes/release_18_02.rst            |    6 +
 drivers/event/sw/sw_evdev.c                       |   18 +
 lib/Makefile                                      |    2 +-
 lib/librte_eventdev/Makefile                      |    5 +-
 lib/librte_eventdev/rte_event_timer_adapter.c     | 1147 +++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h     |  651 ++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h |  174 ++++
 lib/librte_eventdev/rte_eventdev.h                |    7 +-
 lib/librte_eventdev/rte_eventdev_pmd.h            |   35 +
 lib/librte_eventdev/rte_eventdev_version.map      |   19 +-
 mk/rte.app.mk                                     |    2 +-
 test/test/Makefile                                |    1 +
 test/test/test_event_timer_adapter.c              |  446 ++++++++
 17 files changed, 2816 insertions(+), 6 deletions(-)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h
 create mode 100644 test/test/test_event_timer_adapter.c

-- 
2.6.4

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v6 01/23] eventtimer: add event timer adapter API
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
@ 2018-01-11  0:20     ` Erik Gabriel Carrillo
  2018-01-11 11:10       ` Pavan Nikhilesh
  2018-01-11  0:20     ` [PATCH v6 02/23] eventtimer: add common code Erik Gabriel Carrillo
                       ` (22 subsequent siblings)
  23 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:20 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/Makefile                  |   1 +
 lib/librte_eventdev/rte_event_timer_adapter.h | 566 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_eventdev.h            |   4 +-
 3 files changed, 569 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h

diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 7fd78c7..685b474 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -27,6 +27,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
new file mode 100644
index 0000000..7d967e6
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -0,0 +1,566 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 Cavium, Inc.
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ * @file
+ *
+ * RTE Event Timer Adapter
+ *
+ * An event timer adapter has the following abstract working model:
+ *
+ *                               timer_tick_ns
+ *                                   +
+ *                      +-------+    |
+ *                      |       |    |
+ *              +-------+ bkt 0 +----v---+
+ *              |       |       |        |
+ *              |       +-------+        |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *          |       |                |       |  |   |   |   |   |
+ *          | bkt n |                | bkt 1 |<-> t0| t1| t2| tn|
+ *          |       |                |       |  |   |   |   |   |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *              |     Timer adapter      |
+ *          +---+---+                +---+---+
+ *          |       |                |       |
+ *          | bkt 4 |                | bkt 2 |<--- Current bucket
+ *          |       |                |       |
+ *          +---+---+                +---+---+
+ *               |      +-------+       |
+ *               |      |       |       |
+ *               +------+ bkt 3 +-------+
+ *                      |       |
+ *                      +-------+
+ *
+ * - It has a virtual monotonically increasing 64-bit timer adapter clock based
+ *   on *enum rte_event_timer_adapter_clk_src* clock source. The clock source
+ *   could be a CPU clock, or a platform depended external clock.
+ *
+ * - Application creates a timer adapter instance with given clock source,
+ *   the total number of event timers, resolution(expressed in ns) to traverse
+ *   between the buckets.
+ *
+ * - Each timer adapter may have 0 to n buckets based on the configured
+ *   max timeout(max_tmo_ns) and resolution(timer_tick_ns). On timer adapter
+ *   start, the timer starts ticking at *timer_tick_ns* resolution.
+ *
+ * - Application arms an event timer to be expired at the number of
+ *   *timer_tick_ns* from now.
+ *
+ * - Application can cancel the existing armed timer if required.
+ *
+ * - If not canceled by the application and the timer expires then the library
+ *   injects the timer expiry event to the designated event queue.
+ *
+ * - The timer expiry event will be received through *rte_event_dequeue_burst*
+ *
+ * - Application frees the created timer adapter instance.
+ *
+ * Multiple timer adapters can be created with a varying level of resolution
+ * for various expiry use cases that run in parallel.
+ *
+ * Before using the timer adapter, the application has to create and configure
+ * an event device along with the event ports. Based on the event device
+ * capability it might require creating an additional event port to be used
+ * by the timer adapter.
+ *
+ * The application creates the event timer adapter using the
+ * ``rte_event_timer_adapter_create()``. The event device id is passed to this
+ * function, inside this function the event device capability is checked,
+ * and if an in-built port is absent the application uses the default
+ * function to create a new producer port.
+ *
+ * The application may also use the function
+ * ``rte_event_timer_adapter_create_ext()`` to have granular control over
+ * producer port creation in a case where the in-built port is absent.
+ *
+ * After creating the timer adapter, the application has to start it
+ * using ``rte_event_timer_adapter_start()``. The buckets are traversed from
+ * 0 to n, the list per each bucket is processed, and the expired timer events
+ * are sent to the designated event queue.
+ *
+ * The application can arm one or more event timers using the
+ * ``rte_event_timer_arm_burst()``. The *timeout_ticks* represents the number
+ * of *timer_tick_ns* after which the timer has to expire. The timeout at
+ * which the timers expire can be grouped or be independent of each
+ * event timer instance. ``rte_event_timer_arm_tmo_tick_burst()`` address the
+ * former case and ``rte_event_timer_arm_burst()`` address the latter case.
+ *
+ * The application can cancel the timers from expiring using the
+ * ``rte_event_timer_cancel_burst()``.
+ *
+ * On the secondary process, ``rte_event_timer_adapter_lookup()`` can be used
+ * to get the timer adapter pointer from its id and use it to invoke fastpath
+ * operations such as arm and cancel.
+ *
+ * Some of the use cases of event timer adapter are Beacon Timers,
+ * Generic SW Timeout, Wireless MAC Scheduling, 3G Frame Protocols,
+ * Packet Scheduling, Protocol Retransmission Timers, Supervision Timers.
+ * All these use cases require high resolution and low time drift.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_spinlock.h>
+#include <rte_memory.h>
+
+#include "rte_eventdev.h"
+
+#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 64
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this enum may change without prior notice
+ *
+ * Timer adapter clock source
+ */
+enum rte_event_timer_adapter_clk_src {
+	RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+	/**< Use CPU clock as the clock source. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK0,
+	/**< Platform dependent external clock source 0. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK1,
+	/**< Platform dependent external clock source 1. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK2,
+	/**< Platform dependent external clock source 2. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK3,
+	/**< Platform dependent external clock source 3. */
+};
+
+#define RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES	(1ULL << 0)
+/**< The event timer adapter implementation may have constraints on the
+ * resolution (timer_tick_ns) and maximum timer expiry timeout(max_tmo_ns)
+ * based on the given timer adapter or system.  If this flag is set, the
+ * implementation adjusts the resolution and maximum timeout to the best
+ * possible configuration. On successful timer adapter creation, the
+ * application can get the configured resolution and max timeout with
+ * ``rte_event_timer_adapter_get_info()``.
+ */
+#define RTE_EVENT_TIMER_ADAPTER_F_SP_PUT	(1ULL << 1)
+/**< ``rte_event_timer_arm_burst()`` API to be used in single producer mode.
+ *
+ * @see struct rte_event_timer_adapter_conf::flags
+ */
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter configuration structure
+ */
+struct rte_event_timer_adapter_conf {
+	uint8_t event_dev_id;
+	/**< Event device identifier */
+	uint16_t timer_adapter_id;
+	/**< Event timer adapter identifier */
+	uint32_t socket_id;
+	/**< Identifer of socket from which to allocate memory for adapter */
+	enum rte_event_timer_adapter_clk_src clk_src;
+	/**< Clock source for timer adapter */
+	uint64_t timer_tick_ns;
+	/**< Timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expiry) in ns */
+	uint64_t nb_timers;
+	/**< Total number of timers per adapter */
+	uint64_t flags;
+	/**< Timer adapter config flags (RTE_EVENT_TIMER_ADAPTER_F_*) */
+};
+
+struct rte_event_timer_adapter;
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Callback function type for producer port creation.
+ */
+typedef int (*rte_event_timer_adapter_port_conf_cb_t)(uint16_t id,
+						      uint8_t event_dev_id,
+						      uint8_t *event_port_id,
+						      void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create an event timer adapter.
+ *
+ * This function must be invoked first before any other function in the API.
+ *
+ * @param conf
+ *   The event timer adapter configuration structure.
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ */
+struct rte_event_timer_adapter *rte_event_timer_adapter_create(
+			const struct rte_event_timer_adapter_conf *conf);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create a timer adapter with the supplied callback.
+ *
+ * This function can be used to have a more granular control over the timer
+ * adapter creation.  If a built-in port is absent, then the function uses the
+ * callback provided to create and get the port id to be used as a producer
+ * port.
+ *
+ * @param conf
+ *   The timer adapter configuration structure
+ * @param conf_cb
+ *   The port config callback function.
+ * @param conf_arg
+ *   Opaque pointer to the argument for the callback function
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ */
+struct rte_event_timer_adapter *rte_event_timer_adapter_create_ext(
+			const struct rte_event_timer_adapter_conf *conf,
+			rte_event_timer_adapter_port_conf_cb_t conf_cb,
+			void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter info structure.
+ */
+struct rte_event_timer_adapter_info {
+	uint64_t min_resolution_ns;
+	/**< Minimum timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expire) in ns */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configured timer adapter attributes */
+	uint32_t caps;
+	/**< Event timer adapter capabilities */
+	int16_t event_dev_port_id;
+	/**< Event device port ID, if applicable */
+	int32_t service_id;
+	/**< Service ID, if applicable */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve the contextual information of an event timer adapter.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @param[out] adapter_info
+ *   A pointer to a structure of type *rte_event_timer_adapter_info* to be
+ *   filled with the contextual information of the adapter.
+ *
+ * @return
+ *   - 0: Success, driver updates the contextual information of the
+ *   timer adapter
+ *   - <0: Error code returned by the driver info get function.
+ *   - -EINVAL if adapter identifier invalid
+ *
+ * @see RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES,
+ *   struct rte_event_timer_adapter_info
+ *
+ */
+int rte_event_timer_adapter_get_info(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Start a timer adapter.
+ *
+ * The adapter start step is the last one and consists of setting the timer
+ * adapter to start accepting the timers and schedules to event queues.
+ *
+ * On success, all basic functions exported by the API (timer arm,
+ * timer cancel and so on) can be invoked.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter started.
+ *   - <0: Error code returned by the driver start function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int rte_event_timer_adapter_start(
+		const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Stop an event timer adapter.
+ *
+ * The adapter can be restarted with a call to
+ * ``rte_event_timer_adapter_start()``.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter stopped.
+ *   - <0: Error code returned by the driver stop function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Lookup an event timer adapter using its identifier.
+ *
+ * If an event timer adapter was created in another process with the same
+ * identifier, this function will locate its state and set up access to it
+ * so that it can be used in this process.
+ *
+ * @param adapter_id
+ *  The event timer adapter identifier.
+ *
+ * @return
+ *  A pointer to the event timer adapter matching the identifier on success.
+ *  NULL on error with rte_errno set appropriately.
+ *  Possible rte_errno values include:
+ *   - ENOENT - required entry not available to return.
+ */
+struct rte_event_timer_adapter *rte_event_timer_adapter_lookup(
+							uint16_t adapter_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Free an event timer adapter.
+ *
+ * Destroy an event timer adapter, freeing all resources.
+ *
+ * Before invoking this function, the application must wait for all the
+ * armed timers to expire or cancel the outstanding armed timers.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully freed the event timer adapter resources.
+ *   - <0: Failed to free the event timer adapter resources.
+ *   - -EAGAIN:  adapter is busy; timers outstanding
+ *   - -EBUSY: stop hasn't been called for this adapter yet
+ *   - -EINVAL: adapter id invalid, or adapter invalid
+ */
+int rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer state.
+ */
+enum rte_event_timer_state {
+	RTE_EVENT_TIMER_NOT_ARMED = 0,
+	/**< Event timer is in not armed state. */
+	RTE_EVENT_TIMER_ARMED = 1,
+	/**< Event timer successfully armed. */
+	RTE_EVENT_TIMER_CANCELED = 2,
+	/**< Event timer successfully canceled. */
+	RTE_EVENT_TIMER_ERROR = -1,
+	/**< Generic event timer error. */
+	RTE_EVENT_TIMER_ERROR_TOOEARLY = -2,
+	/**< Event timer timeout tick is too small to add to the adapter. */
+	RTE_EVENT_TIMER_ERROR_TOOLATE = -3,
+	/**< Event timer timeout tick is greater than the maximum timeout.*/
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * The generic *rte_event_timer* structure to hold the event timer attributes
+ * for arm and cancel operations.
+ */
+RTE_STD_C11
+struct rte_event_timer {
+	struct rte_event ev;
+	/**<
+	 * Expiry event attributes.  On successful event timer timeout,
+	 * the following attributes will be used to inject the expiry event to
+	 * the eventdev:
+	 *  - event_queue_id: Targeted event queue id for expiry events.
+	 *  - event_priority: Event priority of the event expiry event in the
+	 *  event queue relative to other events.
+	 *  - sched_type: Scheduling type of the expiry event.
+	 *  - flow_id: Flow id of the expiry event.
+	 *  - op: RTE_EVENT_OP_NEW
+	 *  - event_type: RTE_EVENT_TYPE_TIMER
+	 */
+	enum rte_event_timer_state state;
+	/**< State of the event timer. */
+	uint64_t timeout_ticks;
+	/**< Expiry timer ticks expressed in number of *timer_ticks_ns* from
+	 * now.
+	 * @see struct rte_event_timer_adapter_info::adapter_conf::timer_tick_ns
+	 */
+	uint64_t impl_opaque[2];
+	/**< Implementation-specific opaque data.
+	 * An event timer adapter implementation use this field to hold
+	 * implementation specific values to share between the arm and cancel
+	 * operations.  The application should not modify this field.
+	 */
+	uint8_t user_meta[];
+	/**< Memory to store user specific metadata.
+	 * The event timer adapter implementation should not modify this area.
+	 */
+} __rte_cache_aligned;
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with separate expiration timeout tick for each
+ * event timer.
+ *
+ * Before calling this function, the application allocates
+ * ``struct rte_event_timer`` objects from mempool or huge page backed
+ * application buffers of desired size. On successful allocation,
+ * application updates the `struct rte_event_timer`` attributes such as
+ * expiry event attributes, timeout ticks from now.
+ * This function submits the event timer arm requests to the event timer adapter
+ * and on expiry, the events will be injected to designated event queue.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Pointer to an array of objects of type *rte_event_timer* structure.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_timers* parameter. If the return value is less
+ *   than *nb_events*, the remaining event timers at the end of *tim*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - -EINVAL  Invalid timer adapter identifier, expiry event queue ID is
+ *   invalid, or an expiry event's sched type doesn't match the capabilities of
+ *   the destination event queue.
+ *   - -EAGAIN Specified timer adapter is not running
+ */
+int rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			      struct rte_event_timer **evtims,
+			      uint16_t nb_evtims);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with same expiration timeout tick.
+ *
+ * Provides the same functionality as ``rte_event_timer_arm_burst()``, except
+ * that application can use this API when all the event timers have the
+ * same timeout expiration tick. This specialized function can provide the
+ * additional hint to the adapter implementation and optimize if possible.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Points to an array of objects of type *rte_event_timer* structure.
+ * @param timeout_ticks
+ *   The number of ticks in which the timers should expire.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_timers* parameter. If the return value is less
+ *   than *nb_events*, the remaining event timers at the end of *tim*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - -EINVAL  Invalid timer adapter identifier, expiry event queue ID is
+ *   invalid, or an expiry event's sched type doesn't match the capabilities of
+ *   the destination event queue.
+ *   - -EAGAIN Specified event timer adapter is not running
+ */
+int rte_event_timer_arm_tmo_tick_burst(
+			const struct rte_event_timer_adapter *adapter,
+			struct rte_event_timer **evtims,
+			const uint64_t timeout_ticks,
+			const uint16_t nb_evtims);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Cancel a burst of event timer from being scheduled to the event device.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param event_timers
+ *   Points to an array of objects of type *rte_event_timer* structure
+ * @param nb_event_timers
+ *   Number of event timer instances in the supplied array.
+ *
+ * @return
+ *   The number of successfully canceled event timers. The return value can be
+ *   less than the value of the *nb_timers* parameter. If the return value is
+ *   less than *nb_events*, the remaining event timers at the end of *tim*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - -EINVAL  Invalid timer adapter identifier
+ *   - -EAGAIN  Specified timer adapter is not running
+ */
+int rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+				 struct rte_event_timer **event_timers,
+				 uint16_t nb_event_timers);
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index f1949ff..a650f7a 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -875,8 +875,8 @@ rte_event_dev_close(uint8_t dev_id);
 /**< The event generated from ethdev subsystem */
 #define RTE_EVENT_TYPE_CRYPTODEV        0x1
 /**< The event generated from crypodev subsystem */
-#define RTE_EVENT_TYPE_TIMERDEV         0x2
-/**< The event generated from timerdev subsystem */
+#define RTE_EVENT_TYPE_TIMER		0x2
+/**< The event generated from event timer adapter */
 #define RTE_EVENT_TYPE_CPU              0x3
 /**< The event generated from cpu for pipelining.
  * Application may use *sub_event_type* to further classify the event
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 02/23] eventtimer: add common code
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  2018-01-11  0:20     ` [PATCH v6 01/23] eventtimer: add event timer adapter API Erik Gabriel Carrillo
@ 2018-01-11  0:20     ` Erik Gabriel Carrillo
  2018-01-11  0:20     ` [PATCH v6 03/23] eventtimer: add default software driver stub Erik Gabriel Carrillo
                       ` (21 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:20 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

This commit adds the logic that is shared by all event timer adapter
drivers; the common code handles instance allocation and some
initialization.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 drivers/event/sw/sw_evdev.c                       |  18 +
 lib/librte_eventdev/Makefile                      |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c     | 395 ++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 159 +++++++++
 lib/librte_eventdev/rte_eventdev.h                |   3 +
 lib/librte_eventdev/rte_eventdev_pmd.h            |  35 ++
 lib/librte_eventdev/rte_eventdev_version.map      |  15 +-
 7 files changed, 626 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h

diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index 74976c0..c3291c8 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -407,6 +407,22 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
 	return 0;
 }
 
+static int
+sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
+			  uint64_t flags,
+			  uint32_t *caps,
+			  const struct rte_event_timer_adapter_ops **ops)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(flags);
+	*caps = 0;
+
+	/* Use default SW ops */
+	*ops = NULL;
+
+	return 0;
+}
+
 static void
 sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
 {
@@ -727,6 +743,8 @@ sw_probe(struct rte_vdev_device *vdev)
 
 			.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
 
+			.timer_adapter_caps_get = sw_timer_adapter_caps_get,
+
 			.xstats_get = sw_xstats_get,
 			.xstats_get_names = sw_xstats_get_names,
 			.xstats_get_by_name = sw_xstats_get_by_name,
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 685b474..8f11a79 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -19,6 +19,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
 SRCS-y += rte_eventdev.c
 SRCS-y += rte_event_ring.c
 SRCS-y += rte_event_eth_rx_adapter.c
+SRCS-y += rte_event_timer_adapter.c
 
 # export include files
 SYMLINK-y-include += rte_eventdev.h
@@ -28,6 +29,7 @@ SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
 SYMLINK-y-include += rte_event_timer_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter_pmd.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
new file mode 100644
index 0000000..3e58db4
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -0,0 +1,395 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include <rte_memzone.h>
+#include <rte_memory.h>
+#include <rte_dev.h>
+#include <rte_errno.h>
+
+#include "rte_eventdev.h"
+#include "rte_eventdev_pmd.h"
+#include "rte_event_timer_adapter.h"
+#include "rte_event_timer_adapter_pmd.h"
+
+#define MAX_EVENT_TIMER_ADAPTERS 64
+#define DATA_MZ_NAME_MAX_LEN 64
+#define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
+
+static struct rte_event_timer_adapter adapters[MAX_EVENT_TIMER_ADAPTERS];
+
+static inline int
+adapter_valid(const struct rte_event_timer_adapter *adapter)
+{
+	return adapter != NULL && adapter->allocated == 1;
+}
+
+#define ADAPTER_VALID_OR_ERR_RET(adapter, retval) do { \
+	if (!adapter_valid(adapter))		       \
+		return retval;			       \
+} while (0)
+
+#define FUNC_PTR_OR_ERR_RET(func, errval) do { \
+	if ((func) == NULL)		       \
+		return errval;		       \
+} while (0)
+
+#define FUNC_PTR_OR_NULL_RET_WITH_ERRNO(func, errval) do { \
+	if ((func) == NULL) {				   \
+		rte_errno = errval;			   \
+		return NULL;				   \
+	}						   \
+} while (0)
+
+static int
+default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		     void *conf_arg)
+{
+	struct rte_event_timer_adapter *adapter;
+	struct rte_eventdev *dev;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	int started;
+	uint8_t port_id;
+	uint8_t dev_id;
+	int ret;
+
+	RTE_SET_USED(event_dev_id);
+
+	adapter = &adapters[id];
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+	dev_id = dev->data->dev_id;
+	dev_conf = dev->data->dev_conf;
+
+	started = dev->data->dev_started;
+	if (started)
+		rte_event_dev_stop(dev_id);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports += 1;
+	ret = rte_event_dev_configure(dev_id, &dev_conf);
+	if (ret < 0) {
+		if (started)
+			rte_event_dev_start(dev_id);
+
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(dev_id, port_id, port_conf);
+	if (ret < 0)
+		return ret;
+
+	*event_port_id = port_id;
+
+	if (started)
+		rte_event_dev_start(dev_id);
+
+	return 0;
+}
+
+struct rte_event_timer_adapter *
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf)
+{
+	return rte_event_timer_adapter_create_ext(conf, default_port_conf_cb,
+						  NULL);
+}
+
+struct rte_event_timer_adapter *
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg)
+{
+	uint16_t adapter_id;
+	struct rte_event_timer_adapter *adapter;
+	const struct rte_memzone *mz;
+	char mz_name[DATA_MZ_NAME_MAX_LEN];
+	int n, ret;
+	struct rte_eventdev *dev;
+
+	if (conf == NULL) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	/* Check eventdev ID */
+	if (!rte_event_pmd_is_valid_dev(conf->event_dev_id)) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+	dev = &rte_eventdevs[conf->event_dev_id];
+
+	adapter_id = conf->timer_adapter_id;
+
+	/* Check adapter ID not already allocated */
+	adapter = &adapters[adapter_id];
+	if (adapter->allocated) {
+		rte_errno = -EEXIST;
+		return NULL;
+	}
+
+	/* Create shared data area. */
+	n = snprintf(mz_name, sizeof(mz_name), DATA_MZ_NAME_FORMAT, adapter_id);
+	if (n >= (int)sizeof(mz_name)) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+	mz = rte_memzone_reserve(mz_name,
+				 sizeof(struct rte_event_timer_adapter_data),
+				 conf->socket_id, 0);
+	if (mz == NULL)
+		/* rte_errno set by rte_memzone_reserve */
+		return NULL;
+
+	adapter->data = mz->addr;
+	memset(adapter->data, 0, sizeof(struct rte_event_timer_adapter_data));
+
+	adapter->data->mz = mz;
+	adapter->data->event_dev_id = conf->event_dev_id;
+	adapter->data->id = adapter_id;
+	adapter->data->socket_id = conf->socket_id;
+	adapter->data->conf = *conf;  /* copy conf structure */
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	if (!(adapter->data->caps &
+	      RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+		FUNC_PTR_OR_NULL_RET_WITH_ERRNO(conf_cb, -EINVAL);
+		ret = conf_cb(adapter->data->id, adapter->data->event_dev_id,
+			      &adapter->data->event_port_id, conf_arg);
+		if (ret < 0) {
+			rte_errno = -EINVAL;
+			return NULL;
+		}
+	}
+
+	/* Allow driver to do some setup */
+	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
+	ret = adapter->ops->init(adapter);
+	if (ret < 0) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+}
+
+int
+rte_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->ops->get_info)
+		/* let driver set values it knows */
+		adapter->ops->get_info(adapter, adapter_info);
+
+	/* Set common values */
+	adapter_info->conf = adapter->data->conf;
+	adapter_info->event_dev_port_id = adapter->data->event_port_id;
+	adapter_info->caps = adapter->data->caps;
+
+	return 0;
+}
+
+int
+rte_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->start, -EINVAL);
+
+	ret = adapter->ops->start(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 1;
+
+	return 0;
+}
+
+int
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stop, -EINVAL);
+
+	ret = adapter->ops->stop(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 0;
+
+	return 0;
+}
+
+struct rte_event_timer_adapter *
+rte_event_timer_adapter_lookup(uint16_t adapter_id)
+{
+	char name[DATA_MZ_NAME_MAX_LEN];
+	const struct rte_memzone *mz;
+	struct rte_event_timer_adapter_data *data;
+	struct rte_event_timer_adapter *adapter;
+	int ret;
+	struct rte_eventdev *dev;
+
+	if (adapters[adapter_id].allocated)
+		return &adapters[adapter_id]; /* Adapter is already loaded */
+
+	snprintf(name, DATA_MZ_NAME_MAX_LEN, DATA_MZ_NAME_FORMAT, adapter_id);
+	mz = rte_memzone_lookup(name);
+	if (mz == NULL) {
+		rte_errno = -ENOENT;
+		return NULL;
+	}
+
+	data = mz->addr;
+
+	adapter = &adapters[data->id];
+	adapter->data = data;
+
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+}
+
+int
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->uninit, -EINVAL);
+
+	/* free impl priv data */
+	ret = adapter->ops->uninit(adapter);
+	if (ret < 0)
+		return ret;
+
+	/* free shared data area */
+	ret = rte_memzone_free(adapter->data->mz);
+	if (ret < 0)
+		return ret;
+
+	adapter->data = NULL;
+	adapter->allocated = 0;
+
+	return 0;
+}
+
+int
+rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **evtims,
+			  uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_burst, -EINVAL);
+#endif
+
+	return adapter->arm_burst(adapter, evtims, nb_evtims);
+}
+
+int
+rte_event_timer_arm_tmo_tick_burst(
+			const struct rte_event_timer_adapter *adapter,
+			struct rte_event_timer **evtims,
+			const uint64_t timeout_ticks,
+			const uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_tmo_tick_burst, -EINVAL);
+#endif
+
+	return adapter->arm_tmo_tick_burst(adapter, evtims, timeout_ticks,
+					   nb_evtims);
+}
+
+int
+rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			     struct rte_event_timer **evtims,
+			     uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->cancel_burst, -EINVAL);
+#endif
+
+	return adapter->cancel_burst(adapter, evtims, nb_evtims);
+}
diff --git a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
new file mode 100644
index 0000000..485fad1
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
@@ -0,0 +1,159 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_DRIVER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_DRIVER_H__
+
+/**
+ * @file
+ *
+ * Description
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "rte_event_timer_adapter.h"
+
+/*
+ * Definitions of functions exported by an event timer adapter implementation
+ * through *rte_event_timer_adapter_ops* structure supplied in the
+ * *rte_event_timer_adapter* structure associated with an event timer adapter.
+ */
+
+typedef int (*rte_event_timer_adapter_init_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation setup */
+typedef int (*rte_event_timer_adapter_uninit_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation teardown */
+typedef int (*rte_event_timer_adapter_start_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Start running event timer adapter */
+typedef int (*rte_event_timer_adapter_stop_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Stop running event timer adapter */
+typedef void (*rte_event_timer_adapter_get_info_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+/**< @internal Get contextual information for event timer adapter */
+typedef int (*rte_event_timer_arm_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Enable event timers to enqueue timer events upon expiry */
+typedef int (*rte_event_timer_arm_tmo_tick_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint64_t timeout_tick,
+		uint16_t nb_tims);
+/**< @internal Enable event timers with common expiration time */
+typedef int (*rte_event_timer_cancel_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Prevent event timers from enqueuing timer events */
+
+/**
+ * @internal Structure containing the functions exported by an event timer
+ * adapter implementation.
+ */
+struct rte_event_timer_adapter_ops {
+	rte_event_timer_adapter_init_t		init;  /**< Set up adapter */
+	rte_event_timer_adapter_uninit_t	uninit;/**< Tear down adapter */
+	rte_event_timer_adapter_start_t		start; /**< Start adapter */
+	rte_event_timer_adapter_stop_t		stop;  /**< Stop adapter */
+	rte_event_timer_adapter_get_info_t	get_info;
+	/**< Get info from driver */
+	rte_event_timer_arm_burst_t		arm_burst;
+	/**< Arm one or more event timers */
+	rte_event_timer_arm_tmo_tick_burst_t	arm_tmo_tick_burst;
+	/**< Arm event timers with same expiration time */
+	rte_event_timer_cancel_burst_t		cancel_burst;
+	/**< Cancel one or more event timers */
+};
+
+/**
+ * @internal Adapter data; structure to be placed in shared memory to be
+ * accessible by various processes in a multi-process configuration.
+ */
+struct rte_event_timer_adapter_data {
+	uint8_t id;
+	/**< Event timer adapter ID */
+	uint8_t event_dev_id;
+	/**< Event device ID */
+	uint32_t socket_id;
+	/**< Socket ID where memory is allocated */
+	uint8_t event_port_id;
+	/**< Optional: event port ID used when the inbuilt port is absent */
+	const struct rte_memzone *mz;
+	/**< Event timer adapter memzone pointer */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configuration used to configure the adapter. */
+	uint32_t caps;
+	/**< Adapter capabilities */
+	void *adapter_priv;
+	/**< Timer adapter private data*/
+
+	RTE_STD_C11
+	uint8_t started : 1;
+	/**< Flag to indicate adapter started. */
+} __rte_cache_aligned;
+
+/**
+ * @internal Data structure associated with each event timer adapter.
+ */
+struct rte_event_timer_adapter {
+	rte_event_timer_arm_burst_t arm_burst;
+	/**< Pointer to driver arm_burst function. */
+	rte_event_timer_arm_tmo_tick_burst_t arm_tmo_tick_burst;
+	/**< Pointer to driver arm_tmo_tick_burst function. */
+	rte_event_timer_cancel_burst_t cancel_burst;
+	/**< Pointer to driver cancel function. */
+
+	struct rte_event_timer_adapter_data *data;
+	/**< Pointer to shared adapter data */
+	const struct rte_event_timer_adapter_ops *ops;
+	/**< Functions exported by adapter driver */
+
+	RTE_STD_C11
+	uint8_t allocated : 1;
+	/**< Flag to indicate that this adapter has been allocated */
+} __rte_cache_aligned;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_DRIVER_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index a650f7a..e72da76 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -1025,6 +1025,9 @@ struct rte_event {
  * @see struct rte_event_eth_rx_adapter_queue_conf::rx_queue_flags
  */
 
+#define RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT (1ULL << 1)
+/**< This flag is set when the timer mechanism is in HW. */
+
 /**
  * Retrieve the event device's ethdev Rx adapter capabilities for the
  * specified ethernet port
diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h b/lib/librte_eventdev/rte_eventdev_pmd.h
index c2fd09c..b71196a 100644
--- a/lib/librte_eventdev/rte_eventdev_pmd.h
+++ b/lib/librte_eventdev/rte_eventdev_pmd.h
@@ -25,6 +25,7 @@ extern "C" {
 #include <rte_malloc.h>
 
 #include "rte_eventdev.h"
+#include "rte_event_timer_adapter_pmd.h"
 
 /* Logging Macros */
 #define RTE_EDEV_LOG_ERR(...) \
@@ -440,6 +441,37 @@ typedef int (*eventdev_eth_rx_adapter_caps_get_t)
 struct rte_event_eth_rx_adapter_queue_conf *queue_conf;
 
 /**
+ * Retrieve the event device's timer adapter capabilities, as well as the ops
+ * structure that an event timer adapter should call through to enter the
+ * driver
+ *
+ * @param dev
+ *   Event device pointer
+ *
+ * @param flags
+ *   Flags that can be used to determine how to select an event timer
+ *   adapter ops structure
+ *
+ * @param[out] caps
+ *   A pointer to memory filled with Rx event adapter capabilities.
+ *
+ * @param[out] ops
+ *   A pointer to the ops pointer to set with the address of the desired ops
+ *   structure
+ *
+ * @return
+ *   - 0: Success, driver provides Rx event adapter capabilities for the
+ *	ethernet device.
+ *   - <0: Error code returned by the driver function.
+ *
+ */
+typedef int (*eventdev_timer_adapter_caps_get_t)(
+				const struct rte_eventdev *dev,
+				uint64_t flags,
+				uint32_t *caps,
+				const struct rte_event_timer_adapter_ops **ops);
+
+/**
  * Add ethernet Rx queues to event device. This callback is invoked if
  * the caps returned from rte_eventdev_eth_rx_adapter_caps_get(, eth_port_id)
  * has RTE_EVENT_ETH_RX_ADAPTER_CAP_INTERNAL_PORT set.
@@ -623,6 +655,9 @@ struct rte_eventdev_ops {
 	/**< Get ethernet Rx stats */
 	eventdev_eth_rx_adapter_stats_reset eth_rx_adapter_stats_reset;
 	/**< Reset ethernet Rx stats */
+
+	eventdev_timer_adapter_caps_get_t timer_adapter_caps_get;
+	/**< Get timer adapter capabilities */
 };
 
 /**
diff --git a/lib/librte_eventdev/rte_eventdev_version.map b/lib/librte_eventdev/rte_eventdev_version.map
index 108ae61..f56ca0f 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -66,5 +66,18 @@ DPDK_17.11 {
 	rte_event_eth_rx_adapter_stats_get;
 	rte_event_eth_rx_adapter_stats_reset;
 	rte_event_eth_rx_adapter_stop;
-
 } DPDK_17.08;
+
+DPDK_18.02 {
+	global:
+
+	rte_event_timer_adapter_create;
+	rte_event_timer_adapter_create_ext;
+	rte_event_timer_adapter_free;
+	rte_event_timer_adapter_get_info;
+	rte_event_timer_adapter_start;
+	rte_event_timer_adapter_stop;
+	rte_event_timer_arm_burst;
+	rte_event_timer_arm_tmo_tick_burst;
+	rte_event_timer_cancel_burst;
+} DPDK_17.11;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 03/23] eventtimer: add default software driver stub
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  2018-01-11  0:20     ` [PATCH v6 01/23] eventtimer: add event timer adapter API Erik Gabriel Carrillo
  2018-01-11  0:20     ` [PATCH v6 02/23] eventtimer: add common code Erik Gabriel Carrillo
@ 2018-01-11  0:20     ` Erik Gabriel Carrillo
  2018-01-11  0:20     ` [PATCH v6 04/23] test: add event timer adapter auto-test Erik Gabriel Carrillo
                       ` (20 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:20 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

If an eventdev PMD does not wish to provide event timer adapter ops
definitions, the library will fall back to a default software
implementation whose entry points are added by this commit.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 107 ++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 3e58db4..540be95 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -48,6 +48,8 @@
 
 static struct rte_event_timer_adapter adapters[MAX_EVENT_TIMER_ADAPTERS];
 
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+
 static inline int
 adapter_valid(const struct rte_event_timer_adapter *adapter)
 {
@@ -211,6 +213,12 @@ rte_event_timer_adapter_create_ext(
 		}
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Allow driver to do some setup */
 	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
 	ret = adapter->ops->init(adapter);
@@ -318,6 +326,12 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
 		return NULL;
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Set fast-path function pointers */
 	adapter->arm_burst = adapter->ops->arm_burst;
 	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
@@ -393,3 +407,96 @@ rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
 
 	return adapter->cancel_burst(adapter, evtims, nb_evtims);
 }
+
+/*
+ * Software event timer adapter ops definitions
+ */
+
+static int
+sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
+{
+	RTE_SET_USED(adapter);
+
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)
+{
+	RTE_SET_USED(adapter);
+
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	RTE_SET_USED(adapter);
+
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	RTE_SET_USED(adapter);
+
+	return 0;
+}
+
+static void
+sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+			struct rte_event_timer_adapter_info *adapter_info)
+{
+	RTE_SET_USED(adapter);
+	RTE_SET_USED(adapter_info);
+}
+
+static int
+sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			 struct rte_event_timer **evtims,
+			 uint16_t nb_evtims)
+{
+	RTE_SET_USED(adapter);
+	RTE_SET_USED(evtims);
+	RTE_SET_USED(nb_evtims);
+
+	return 0;
+}
+
+static int
+sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			    struct rte_event_timer **evtims,
+			    uint16_t nb_evtims)
+{
+	RTE_SET_USED(adapter);
+	RTE_SET_USED(evtims);
+	RTE_SET_USED(nb_evtims);
+
+	return 0;
+}
+
+static int
+sw_event_timer_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer **tims,
+				  uint64_t timeout_tick,
+				  uint16_t nb_tims)
+{
+	RTE_SET_USED(adapter);
+	RTE_SET_USED(tims);
+	RTE_SET_USED(timeout_tick);
+	RTE_SET_USED(nb_tims);
+
+	return 0;
+}
+
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
+	.init = sw_event_timer_adapter_init,
+	.uninit = sw_event_timer_adapter_uninit,
+	.start = sw_event_timer_adapter_start,
+	.stop = sw_event_timer_adapter_stop,
+	.get_info = sw_event_timer_adapter_get_info,
+	.arm_burst = sw_event_timer_arm_burst,
+	.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
+	.cancel_burst = sw_event_timer_cancel_burst,
+};
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 04/23] test: add event timer adapter auto-test
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (2 preceding siblings ...)
  2018-01-11  0:20     ` [PATCH v6 03/23] eventtimer: add default software driver stub Erik Gabriel Carrillo
@ 2018-01-11  0:20     ` Erik Gabriel Carrillo
  2018-01-11  0:20     ` [PATCH v6 05/23] eventtimer: add adapter allocation definitions Erik Gabriel Carrillo
                       ` (19 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:20 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Add initial infrastructure for event timer adapter auto-test.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 test/test/Makefile                   |   1 +
 test/test/test_event_timer_adapter.c | 177 +++++++++++++++++++++++++++++++++++
 2 files changed, 178 insertions(+)
 create mode 100644 test/test/test_event_timer_adapter.c

diff --git a/test/test/Makefile b/test/test/Makefile
index e7818dc..573e394 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -182,6 +182,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
 SRCS-y += test_eventdev.c
 SRCS-y += test_event_ring.c
 SRCS-y += test_event_eth_rx_adapter.c
+SRCS-y += test_event_timer_adapter.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV) += test_eventdev_sw.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF) += test_eventdev_octeontx.c
 endif
diff --git a/test/test/test_event_timer_adapter.c b/test/test/test_event_timer_adapter.c
new file mode 100644
index 0000000..cbd206a
--- /dev/null
+++ b/test/test/test_event_timer_adapter.c
@@ -0,0 +1,177 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include <rte_eventdev.h>
+#include <rte_dev.h>
+#include <rte_bus_vdev.h>
+#include <rte_event_timer_adapter.h>
+#include <rte_mempool.h>
+#include <rte_errno.h>
+#include <rte_service_component.h>
+#include <rte_cycles.h>
+
+#include "test.h"
+
+#define NB_TEST_EVENT_TIMERS	40000
+#define NB_TEST_PORTS		1
+#define NB_TEST_QUEUES		1
+#define TEST_PORT_ID		0
+#define TEST_QUEUE_ID		0
+
+static int evdev;
+struct rte_mempool *g_event_timer_pool;
+
+static inline void
+devconf_set_test_values(struct rte_event_dev_config *dev_conf,
+				  struct rte_event_dev_info *info)
+{
+	memset(dev_conf, 0, sizeof(struct rte_event_dev_config));
+	dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns;
+	dev_conf->nb_event_ports = NB_TEST_PORTS;
+	dev_conf->nb_event_queues = NB_TEST_QUEUES;
+	dev_conf->nb_event_queue_flows = info->max_event_queue_flows;
+	dev_conf->nb_event_port_dequeue_depth =
+			info->max_event_port_dequeue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+			info->max_event_port_enqueue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+			info->max_event_port_enqueue_depth;
+	dev_conf->nb_events_limit =
+			info->max_num_events;
+}
+
+static int
+configure_event_dev(void)
+{
+	const char *eventdev_name = "event_sw0";
+	int ret;
+	struct rte_event_dev_config devconf;
+	struct rte_event_dev_info info;
+
+	evdev = rte_event_dev_get_dev_id(eventdev_name);
+	if (evdev < 0) {
+		if (rte_vdev_init(eventdev_name, NULL) < 0) {
+			printf("Error creating eventdev\n");
+			return TEST_FAILED;
+		}
+		evdev = rte_event_dev_get_dev_id(eventdev_name);
+		if (evdev < 0) {
+			printf("Error finding newly created eventdev\n");
+			return TEST_FAILED;
+		}
+	}
+
+	ret = rte_event_dev_info_get(evdev, &info);
+	TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info");
+
+	devconf_set_test_values(&devconf, &info);
+
+	ret = rte_event_dev_configure(evdev, &devconf);
+	TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev");
+
+	/* Set up event queue */
+	uint32_t queue_count;
+	TEST_ASSERT_SUCCESS(rte_event_dev_attr_get(evdev,
+			    RTE_EVENT_DEV_ATTR_QUEUE_COUNT, &queue_count),
+			    "Queue count get failed");
+	TEST_ASSERT_EQUAL(queue_count, 1, "Unexpected queue count");
+	ret = rte_event_queue_setup(evdev, TEST_QUEUE_ID, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", TEST_PORT_ID);
+
+	/* Set up event port */
+	uint32_t port_count;
+	uint8_t qid = TEST_QUEUE_ID;
+	TEST_ASSERT_SUCCESS(rte_event_dev_attr_get(evdev,
+			    RTE_EVENT_DEV_ATTR_PORT_COUNT,
+			    &port_count), "Port count get failed");
+	TEST_ASSERT_EQUAL(port_count, 1, "Unexpected port count");
+	ret = rte_event_port_setup(evdev, TEST_PORT_ID, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup port=%d", TEST_PORT_ID);
+	ret = rte_event_port_link(evdev, TEST_PORT_ID, &qid, NULL, 1);
+	TEST_ASSERT(ret >= 0, "Failed to link queue port=%d", TEST_PORT_ID);
+
+	return TEST_SUCCESS;
+}
+
+static int
+testsuite_setup(void)
+{
+	int ret;
+
+	/* Setup and start event device. */
+	ret = configure_event_dev();
+	if (ret) {
+		printf("Failed to configure event dev\n");
+		return TEST_FAILED;
+	}
+
+	/* Create a mempool of event timers. */
+	g_event_timer_pool = rte_mempool_create("event_timer_mempool",
+						NB_TEST_EVENT_TIMERS,
+						sizeof(struct rte_event_timer),
+						32, 0, NULL, NULL, NULL, NULL,
+						rte_socket_id(), 0);
+	if (g_event_timer_pool == NULL) {
+		/* Failed to create event timer mempool. */
+		printf("Failed to configure event timer mempool: %s\n",
+		       rte_strerror(rte_errno));
+		return TEST_FAILED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static void
+testsuite_teardown(void)
+{
+	rte_mempool_free(g_event_timer_pool);
+}
+
+static struct unit_test_suite adapter_tests  = {
+	.suite_name = "event timer adapter test suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+static int
+test_event_timer_adapter_common(void)
+{
+	return unit_test_suite_runner(&adapter_tests);
+}
+
+REGISTER_TEST_COMMAND(event_timer_adapter_autotest,
+		      test_event_timer_adapter_common);
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 05/23] eventtimer: add adapter allocation definitions
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (3 preceding siblings ...)
  2018-01-11  0:20     ` [PATCH v6 04/23] test: add event timer adapter auto-test Erik Gabriel Carrillo
@ 2018-01-11  0:20     ` Erik Gabriel Carrillo
  2018-01-11 11:18       ` Pavan Nikhilesh
  2018-01-11  0:20     ` [PATCH v6 06/23] test: exercise event timer adapter allocation functions Erik Gabriel Carrillo
                       ` (18 subsequent siblings)
  23 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:20 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Add definitions for the functions that allocate and deallocate adapter
instances in the default software implementation.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/Makefile                                  |   2 +-
 lib/librte_eventdev/Makefile                  |   2 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 138 +++++++++++++++++++++++++-
 lib/librte_eventdev/rte_event_timer_adapter.h |   2 +-
 4 files changed, 139 insertions(+), 5 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index 4202702..4c53f8c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -29,7 +29,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
 DEPDIRS-librte_security += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash
+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
 DEPDIRS-librte_vhost := librte_eal librte_mempool librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 8f11a79..e68f888 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -13,7 +13,7 @@ LIBABIVER := 3
 # build flags
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool
 
 # library source files
 SRCS-y += rte_eventdev.c
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 540be95..9c4ba1c 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -31,11 +31,17 @@
  */
 
 #include <string.h>
+#include <stdbool.h>
 
 #include <rte_memzone.h>
 #include <rte_memory.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_timer.h>
+#include <rte_service_component.h>
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -163,6 +169,11 @@ rte_event_timer_adapter_create_ext(
 
 	adapter_id = conf->timer_adapter_id;
 
+	if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) {
+		rte_errno = -EINVAL;
+		return NULL;
+	}
+
 	/* Check adapter ID not already allocated */
 	adapter = &adapters[adapter_id];
 	if (adapter->allocated) {
@@ -412,18 +423,141 @@ rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
  * Software event timer adapter ops definitions
  */
 
+struct rte_event_timer_adapter_sw_data {
+	/* Number of outstanding timers managed by event adapter. */
+	int nb_armed_evtims;
+	/* Identifier of service executing timer management logic. */
+	uint32_t service_id;
+	/* Ring containing messages to arm or cancel event timers */
+	struct rte_ring *msg_ring;
+	/* Mempool containing msg objects */
+	struct rte_mempool *msg_pool;
+	/* Mempool containing timer objects */
+	struct rte_mempool *tim_pool;
+};
+
+enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
+
+struct msg {
+	enum msg_type type;
+	struct rte_event_timer *evtim;
+};
+
+static int
+sw_event_timer_adapter_service_func(void *arg)
+{
+	RTE_SET_USED(arg);
+	return 0;
+}
+
 static int
 sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
 {
-	RTE_SET_USED(adapter);
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	uint64_t nb_timers;
+	struct rte_service_spec service;
+
+	/* Allocate storage for SW implementation data */
+	char priv_data_name[RTE_RING_NAMESIZE];
+	snprintf(priv_data_name, RTE_RING_NAMESIZE, "sw_evtim_adap_priv_%"PRIu8,
+		 adapter->data->id);
+	adapter->data->adapter_priv = rte_zmalloc_socket(
+				priv_data_name,
+				sizeof(struct rte_event_timer_adapter_sw_data),
+				RTE_CACHE_LINE_SIZE,
+				adapter->data->socket_id);
+	if (adapter->data->adapter_priv == NULL) {
+		rte_errno = ENOMEM;
+		return -1;
+	}
+
+	sw_data = adapter->data->adapter_priv;
+
+	/* Rings require power of 2, so round up to next such value */
+	nb_timers = rte_align64pow2(adapter->data->conf.nb_timers);
+
+	char msg_ring_name[RTE_RING_NAMESIZE];
+	snprintf(msg_ring_name, RTE_RING_NAMESIZE,
+		 "sw_evtim_adap_msg_ring_%"PRIu8, adapter->data->id);
+	sw_data->msg_ring = rte_ring_create(msg_ring_name, nb_timers,
+					    adapter->data->socket_id, 0);
+	if (sw_data->msg_ring == NULL) {
+		rte_errno = ENOMEM;
+		return -1;
+	}
+
+	char pool_name[RTE_RING_NAMESIZE];
+	snprintf(pool_name, RTE_RING_NAMESIZE, "sw_evtim_adap_msg_pool_%"PRIu8,
+		 adapter->data->id);
+	sw_data->msg_pool = rte_mempool_create(pool_name, nb_timers,
+					       sizeof(struct msg), 32, 0, NULL,
+					       NULL, NULL, NULL,
+					       adapter->data->socket_id, 0);
+	if (sw_data->msg_pool == NULL) {
+		rte_errno = ENOMEM;
+		return -1;
+	}
+
+	snprintf(pool_name, RTE_RING_NAMESIZE, "sw_evtim_adap_tim_pool_%"PRIu8,
+		 adapter->data->id);
+	sw_data->tim_pool = rte_mempool_create(pool_name, nb_timers,
+					       sizeof(struct rte_timer), 32, 0,
+					       NULL, NULL, NULL, NULL,
+					       adapter->data->socket_id, 0);
+	if (sw_data->tim_pool == NULL) {
+		printf("Could not allocate tim mempool\n");
+		return -1;
+	}
+
+	/* Register a service component */
+	memset(&service, 0, sizeof(service));
+	snprintf(service.name, RTE_SERVICE_NAME_MAX,
+		 "sw_evimer_adap_svc_%"PRIu8, adapter->data->id);
+	service.socket_id = adapter->data->socket_id;
+	service.callback = sw_event_timer_adapter_service_func;
+	service.callback_userdata = adapter;
+	ret = rte_service_component_register(&service, &sw_data->service_id);
+	if (ret < 0)
+		return ret;
 
 	return 0;
 }
 
+static inline bool
+adapter_busy(struct rte_event_timer_adapter_sw_data *sw_data)
+{
+	return rte_ring_count(sw_data->msg_ring) > 0 ||
+		sw_data->nb_armed_evtims > 0;
+}
+
 static int
 sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)
 {
-	RTE_SET_USED(adapter);
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data =
+						adapter->data->adapter_priv;
+
+	if (adapter_busy(sw_data))
+		return -EAGAIN;
+
+	ret = rte_service_component_runstate_set(sw_data->service_id, 0);
+	if (ret < 0)
+		return ret;
+
+	/* If this returns EBUSY, then the adapter hasn't been stopped yet. */
+	ret = rte_service_component_unregister(sw_data->service_id);
+	if (ret < 0)
+		return ret;
+
+	rte_ring_free(sw_data->msg_ring);
+
+	rte_mempool_free(sw_data->msg_pool);
+	rte_mempool_free(sw_data->tim_pool);
+
+	/* TODO: unconfigure event port? */
+
+	rte_free(adapter->data->adapter_priv);
 
 	return 0;
 }
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index 7d967e6..d1e4d18 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -140,7 +140,7 @@ extern "C" {
 
 #include "rte_eventdev.h"
 
-#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 64
+#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 32
 
 /**
  * @warning
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 06/23] test: exercise event timer adapter allocation functions
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (4 preceding siblings ...)
  2018-01-11  0:20     ` [PATCH v6 05/23] eventtimer: add adapter allocation definitions Erik Gabriel Carrillo
@ 2018-01-11  0:20     ` Erik Gabriel Carrillo
  2018-01-11  0:20     ` [PATCH v6 07/23] eventtimer: add adapter get info function definition Erik Gabriel Carrillo
                       ` (17 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:20 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Exercise the create and free functions in the event timer adapter
auto-test.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 test/test/test_event_timer_adapter.c | 88 ++++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/test/test/test_event_timer_adapter.c b/test/test/test_event_timer_adapter.c
index cbd206a..c8623aa 100644
--- a/test/test/test_event_timer_adapter.c
+++ b/test/test/test_event_timer_adapter.c
@@ -158,11 +158,99 @@ testsuite_teardown(void)
 	rte_mempool_free(g_event_timer_pool);
 }
 
+#define NSECPERSEC 1E9
+static int
+adapter_create_free(void)
+{
+	int adapter_id = 0;
+	uint32_t svc_start_count, svc_end_count;
+	struct rte_event_timer_adapter *adapters[
+					RTE_EVENT_TIMER_ADAPTER_NUM_MAX + 1];
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev + 1,  // invalid event dev id
+		.timer_adapter_id = adapter_id,
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = NB_TEST_EVENT_TIMERS,
+		.flags = 0,
+	};
+
+	svc_start_count = rte_service_get_count();
+
+	/* Test create */
+
+	/* Test invalid conf */
+	adapters[0] = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT(adapters[0] == NULL, "Erroneously created adapter with "
+		    "invalid event device id");
+	/* TODO: Should errno values be negative? */
+	TEST_ASSERT(rte_errno == -EINVAL, "Incorrect errno value for invalid "
+		    "event device id");
+
+	/* Test valid conf */
+	conf.event_dev_id = evdev;
+	adapters[0] = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT(adapters[0] != NULL, "Failed to create adapter with valid "
+		    "configuration");
+
+	/* Test existing id */
+	adapters[1] = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT(adapters[1] == NULL, "Erroneusly created adapter with "
+		    "existing id");
+	TEST_ASSERT(rte_errno == -EEXIST, "Incorrect errno value for existing "
+		    "id");
+
+	/* Test instance limit */
+	int i;
+	for (i = adapter_id + 1; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) {
+		conf.timer_adapter_id = i;
+		adapters[i] = rte_event_timer_adapter_create(&conf);
+		TEST_ASSERT(adapters[i] != NULL, "Failed to create adapter "
+			    "with valid configuration");
+	}
+	conf.timer_adapter_id = i;
+	adapters[i] = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT(adapters[i] == NULL, "Erroneously created excess adapters");
+
+	/* Check that at least RTE_EVENT_TIMER_ADAPTER_NUM_MAX services
+	 * have been created
+	 */
+	svc_end_count = rte_service_get_count();
+	TEST_ASSERT(svc_end_count - svc_start_count ==
+		    RTE_EVENT_TIMER_ADAPTER_NUM_MAX,
+		    "Failed to create expected number of services");
+
+	/* Test free */
+
+	int ret;
+	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) {
+		ret = rte_event_timer_adapter_free(adapters[i]);
+		TEST_ASSERT(ret == 0, "Failed to free adapter %d, ret = %d", i,
+			    ret);
+	}
+
+	/* Test free of already freed adapter */
+	ret = rte_event_timer_adapter_free(adapters[0]);
+	TEST_ASSERT(ret < 0, "Erroneously freed adapter that was previously "
+		    "freed");
+
+	/* Test free of null adapter */
+	adapters[0] = NULL;
+	ret = rte_event_timer_adapter_free(adapters[0]);
+	TEST_ASSERT(ret < 0, "Erroneously freed adapter that was previously "
+		    "freed");
+
+	return TEST_SUCCESS;
+}
+
 static struct unit_test_suite adapter_tests  = {
 	.suite_name = "event timer adapter test suite",
 	.setup = testsuite_setup,
 	.teardown = testsuite_teardown,
 	.unit_test_cases = {
+		TEST_CASE(adapter_create_free),
 		TEST_CASES_END() /**< NULL terminate unit test array */
 	}
 };
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 07/23] eventtimer: add adapter get info function definition
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (5 preceding siblings ...)
  2018-01-11  0:20     ` [PATCH v6 06/23] test: exercise event timer adapter allocation functions Erik Gabriel Carrillo
@ 2018-01-11  0:20     ` Erik Gabriel Carrillo
  2018-01-11  0:20     ` [PATCH v6 08/23] eventtimer: add adapter start/stop definitions Erik Gabriel Carrillo
                       ` (16 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:20 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Add a definition to the default software implementation for the entry
point that can fill out driver-specific information in the info struct.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 9c4ba1c..38f4dcf 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -582,8 +582,9 @@ static void
 sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
 			struct rte_event_timer_adapter_info *adapter_info)
 {
-	RTE_SET_USED(adapter);
-	RTE_SET_USED(adapter_info);
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	adapter_info->service_id = sw_data->service_id;
 }
 
 static int
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 08/23] eventtimer: add adapter start/stop definitions
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (6 preceding siblings ...)
  2018-01-11  0:20     ` [PATCH v6 07/23] eventtimer: add adapter get info function definition Erik Gabriel Carrillo
@ 2018-01-11  0:20     ` Erik Gabriel Carrillo
  2018-01-11 17:28       ` Pavan Nikhilesh
  2018-01-11  0:21     ` [PATCH v6 09/23] eventtimer: add API to get service id Erik Gabriel Carrillo
                       ` (15 subsequent siblings)
  23 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:20 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Add definitions to the default software implementation for the functions
that start and stop adapter instances.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 38f4dcf..27e6226 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -565,7 +565,18 @@ sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)
 static int
 sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
 {
-	RTE_SET_USED(adapter);
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+
+	ret = rte_service_component_runstate_set(sw_data->service_id, 1);
+	if (ret < 0)
+		return ret;
+
+	/* If no service core is mapped to the service, fail */
+	if (!rte_service_runstate_get(sw_data->service_id))
+		return -ENOENT;
 
 	return 0;
 }
@@ -573,9 +584,9 @@ sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
 static int
 sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
 {
-	RTE_SET_USED(adapter);
-
-	return 0;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	return rte_service_component_runstate_set(sw_data->service_id, 0);
 }
 
 static void
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 09/23] eventtimer: add API to get service id
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (7 preceding siblings ...)
  2018-01-11  0:20     ` [PATCH v6 08/23] eventtimer: add adapter start/stop definitions Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11  0:21     ` [PATCH v6 10/23] eventtimer: remove service id entry from info structure Erik Gabriel Carrillo
                       ` (14 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

When the event timer adapter uses a software implementation, timer
management is performed on a service core using a service registered at
the time of adapter creation.  This commit adds a helper function to get
the service id that can be used by an application to assign an lcore for
the service to run on.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c     | 20 ++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h     | 19 +++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h |  4 ++++
 lib/librte_eventdev/rte_eventdev_version.map      |  1 +
 4 files changed, 44 insertions(+)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 27e6226..68748be 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -378,6 +378,23 @@ rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter)
 }
 
 int
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (service_id == NULL)
+		return -EINVAL;
+
+	if (adapter->data->service_inited) {
+		*service_id = adapter->data->service_id;
+		return 0;
+	}
+
+	return -ESRCH;
+}
+
+int
 rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
 			  struct rte_event_timer **evtims,
 			  uint16_t nb_evtims)
@@ -521,6 +538,9 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
 	if (ret < 0)
 		return ret;
 
+	adapter->data->service_id = sw_data->service_id;
+	adapter->data->service_inited = 1;
+
 	return 0;
 }
 
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index d1e4d18..84d3c39 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -402,6 +402,25 @@ struct rte_event_timer_adapter *rte_event_timer_adapter_lookup(
 int rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter);
 
 /**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure, if the event dev doesn't use a rte_service
+ *   function, this function returns -ESRCH.
+ */
+int
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id);
+
+/**
  * @warning
  * @b EXPERIMENTAL: this structure may change without prior notice
  *
diff --git a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
index 485fad1..6c65c36 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
@@ -125,6 +125,10 @@ struct rte_event_timer_adapter_data {
 	/**< Adapter capabilities */
 	void *adapter_priv;
 	/**< Timer adapter private data*/
+	uint8_t service_inited;
+	/**< Service initialization state */
+	uint32_t service_id;
+	/**< Service ID*/
 
 	RTE_STD_C11
 	uint8_t started : 1;
diff --git a/lib/librte_eventdev/rte_eventdev_version.map b/lib/librte_eventdev/rte_eventdev_version.map
index f56ca0f..a35a668 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -75,6 +75,7 @@ DPDK_18.02 {
 	rte_event_timer_adapter_create_ext;
 	rte_event_timer_adapter_free;
 	rte_event_timer_adapter_get_info;
+	rte_event_timer_adapter_service_id_get;
 	rte_event_timer_adapter_start;
 	rte_event_timer_adapter_stop;
 	rte_event_timer_arm_burst;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 10/23] eventtimer: remove service id entry from info structure
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (8 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 09/23] eventtimer: add API to get service id Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11 11:34       ` Pavan Nikhilesh
  2018-01-11  0:21     ` [PATCH v6 11/23] test: exercise event timer adapter start/stop functions Erik Gabriel Carrillo
                       ` (13 subsequent siblings)
  23 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 11 +----------
 lib/librte_eventdev/rte_event_timer_adapter.h |  2 --
 2 files changed, 1 insertion(+), 12 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 68748be..a4c8012 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -609,15 +609,6 @@ sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
 	return rte_service_component_runstate_set(sw_data->service_id, 0);
 }
 
-static void
-sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
-			struct rte_event_timer_adapter_info *adapter_info)
-{
-	struct rte_event_timer_adapter_sw_data *sw_data;
-	sw_data = adapter->data->adapter_priv;
-	adapter_info->service_id = sw_data->service_id;
-}
-
 static int
 sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
 			 struct rte_event_timer **evtims,
@@ -661,7 +652,7 @@ const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
 	.uninit = sw_event_timer_adapter_uninit,
 	.start = sw_event_timer_adapter_start,
 	.stop = sw_event_timer_adapter_stop,
-	.get_info = sw_event_timer_adapter_get_info,
+	.get_info = NULL,
 	.arm_burst = sw_event_timer_arm_burst,
 	.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
 	.cancel_burst = sw_event_timer_cancel_burst,
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index 84d3c39..8d29cfc 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -283,8 +283,6 @@ struct rte_event_timer_adapter_info {
 	/**< Event timer adapter capabilities */
 	int16_t event_dev_port_id;
 	/**< Event device port ID, if applicable */
-	int32_t service_id;
-	/**< Service ID, if applicable */
 };
 
 /**
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 11/23] test: exercise event timer adapter start/stop functions
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (9 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 10/23] eventtimer: remove service id entry from info structure Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11  0:21     ` [PATCH v6 12/23] eventtimer: add event timer arm/cancel function definitions Erik Gabriel Carrillo
                       ` (12 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 test/test/test_event_timer_adapter.c | 77 +++++++++++++++++++++++++++++++++++-
 1 file changed, 76 insertions(+), 1 deletion(-)

diff --git a/test/test/test_event_timer_adapter.c b/test/test/test_event_timer_adapter.c
index c8623aa..58cbaba 100644
--- a/test/test/test_event_timer_adapter.c
+++ b/test/test/test_event_timer_adapter.c
@@ -49,8 +49,11 @@
 #define TEST_PORT_ID		0
 #define TEST_QUEUE_ID		0
 
+#define NSECPERSEC		1E9
+
 static int evdev;
 struct rte_mempool *g_event_timer_pool;
+struct rte_event_timer_adapter *g_adapter;
 
 static inline void
 devconf_set_test_values(struct rte_event_dev_config *dev_conf,
@@ -158,7 +161,33 @@ testsuite_teardown(void)
 	rte_mempool_free(g_event_timer_pool);
 }
 
-#define NSECPERSEC 1E9
+static int
+adapter_create(void)
+{
+	int adapter_id = 0;
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = 0,
+		.timer_adapter_id = adapter_id,
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = NB_TEST_EVENT_TIMERS,
+		.flags = 0,
+	};
+
+	g_adapter = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT(g_adapter != NULL, "Failed to create event timer adapter");
+
+	return TEST_SUCCESS;
+}
+
+static void
+adapter_free(void)
+{
+	(void) rte_event_timer_adapter_free(g_adapter);
+}
+
 static int
 adapter_create_free(void)
 {
@@ -245,12 +274,58 @@ adapter_create_free(void)
 	return TEST_SUCCESS;
 }
 
+/* TODO: test multiple starts */
+static int
+adapter_start_stop(void)
+{
+	int ret;
+	uint32_t service_id;
+	struct rte_event_timer_adapter *l_adapter = NULL;
+
+	ret = rte_event_timer_adapter_start(l_adapter);
+	TEST_ASSERT(ret < 0, "Erroneously started null adapter, ret = %d", ret);
+
+	/* Check that we fail when no service core is mapped */
+	ret = rte_event_timer_adapter_start(g_adapter);
+	TEST_ASSERT(ret == -ENOENT, "Erroneously started adapter with no "
+		    "service core mapped");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(g_adapter,
+								   &service_id),
+			    "Failed to get event timer adapter service id");
+
+	TEST_ASSERT(rte_service_lcore_count() > 0, "Need one or more service "
+		    "cores to perform this test");
+
+	/* Could map using service_id, but just do default mapping */
+	ret = rte_service_start_with_defaults();
+	TEST_ASSERT(ret == 0, "Failed to start services");
+
+	ret = rte_event_timer_adapter_start(g_adapter);
+	TEST_ASSERT(ret == 0, "Failed to start adapter");
+
+	ret = rte_event_timer_adapter_start(g_adapter);
+	TEST_ASSERT(ret == 0, "Failed to repeatedly start adapter");
+
+	ret = rte_event_timer_adapter_stop(g_adapter);
+	TEST_ASSERT(ret == 0, "Failed to stop event adapter, ret = %d", ret);
+
+	ret = rte_event_timer_adapter_stop(l_adapter);
+	TEST_ASSERT(ret < 0, "Erroneously stopped event adapter, ret = %d",
+		    ret);
+
+	rte_service_lcore_reset_all();
+
+	return TEST_SUCCESS;
+}
+
 static struct unit_test_suite adapter_tests  = {
 	.suite_name = "event timer adapter test suite",
 	.setup = testsuite_setup,
 	.teardown = testsuite_teardown,
 	.unit_test_cases = {
 		TEST_CASE(adapter_create_free),
+		TEST_CASE_ST(adapter_create, adapter_free, adapter_start_stop),
 		TEST_CASES_END() /**< NULL terminate unit test array */
 	}
 };
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 12/23] eventtimer: add event timer arm/cancel function definitions
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (10 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 11/23] test: exercise event timer adapter start/stop functions Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11 11:38       ` Pavan Nikhilesh
  2018-01-11  0:21     ` [PATCH v6 13/23] eventtimer: add adapter service definition Erik Gabriel Carrillo
                       ` (11 subsequent siblings)
  23 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/Makefile                                  |   2 +-
 lib/librte_eventdev/Makefile                  |   2 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 155 +++++++++++++++++++++++---
 mk/rte.app.mk                                 |   2 +-
 4 files changed, 141 insertions(+), 20 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index 4c53f8c..c2bee80 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -29,7 +29,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
 DEPDIRS-librte_security += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool
+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
 DEPDIRS-librte_vhost := librte_eal librte_mempool librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index e68f888..6e95528 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -13,7 +13,7 @@ LIBABIVER := 3
 # build flags
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool
+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool -lrte_timer
 
 # library source files
 SRCS-y += rte_eventdev.c
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index a4c8012..38e52cb 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -609,16 +609,91 @@ sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
 	return rte_service_component_runstate_set(sw_data->service_id, 0);
 }
 
+static __rte_always_inline void
+swap(struct rte_event_timer **evtims, int i, int j)
+{
+	struct rte_event_timer *tmp;
+
+	tmp = evtims[i];
+	evtims[i] = evtims[j];
+	evtims[j] = tmp;
+}
+
+static __rte_always_inline int
+__sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			   struct rte_event_timer **evtims,
+			   uint16_t nb_evtims)
+{
+	int i, n, mark, nb_fails = 0;
+	int fails[nb_evtims];
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct msg *msgs[nb_evtims];
+	struct rte_timer *tims[nb_evtims];
+
+	sw_data = adapter->data->adapter_priv;
+
+	n = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (n < 0) {
+		rte_errno = ENOMEM;
+		return 0;
+	}
+
+	n = rte_mempool_get_bulk(sw_data->tim_pool, (void **)tims, nb_evtims);
+	if (n < 0) {
+		rte_errno = ENOMEM;
+		return 0;
+	}
+
+	for (i = 0; i < nb_evtims; i++) {
+		rte_timer_init(tims[i]);
+		evtims[i]->impl_opaque[0] = (uintptr_t)tims[i];
+		evtims[i]->impl_opaque[1] = (uintptr_t)adapter;
+
+		msgs[i]->evtim = evtims[i];
+		msgs[i]->type = MSG_TYPE_ARM;
+	}
+
+	n = rte_ring_enqueue_burst(sw_data->msg_ring, (void **)msgs, nb_evtims,
+				   NULL);
+	if (n < nb_evtims) {
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[n],
+				     nb_evtims - n);
+		rte_mempool_put_bulk(sw_data->tim_pool, (void **)&tims[n],
+				     nb_evtims - n);
+	}
+
+	for (i = 0; i < n; i++) {
+		/* Wait until state is updated */
+		while (evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
+		       evtims[i]->state == RTE_EVENT_TIMER_CANCELED)
+			;
+
+		/* Note any failures */
+		if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
+			fails[nb_fails++] = i;
+			rte_errno = EINVAL;
+		}
+
+		/* TODO: handle the case of consecutive arm requests;  the
+		 * second request can erroneously see success from the first
+		 */
+	}
+
+	/* Move the failures to the end of the array */
+	for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
+		swap(evtims, fails[i], mark);
+
+	n = mark + 1;
+
+	return n;
+}
+
 static int
 sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
 			 struct rte_event_timer **evtims,
 			 uint16_t nb_evtims)
 {
-	RTE_SET_USED(adapter);
-	RTE_SET_USED(evtims);
-	RTE_SET_USED(nb_evtims);
-
-	return 0;
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
 }
 
 static int
@@ -626,25 +701,71 @@ sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
 			    struct rte_event_timer **evtims,
 			    uint16_t nb_evtims)
 {
-	RTE_SET_USED(adapter);
-	RTE_SET_USED(evtims);
-	RTE_SET_USED(nb_evtims);
+	int i, n, mark, nb_fails = 0;
+	int fails[nb_evtims];
+	struct msg *msg, *msgs[nb_evtims];
+	struct rte_event_timer_adapter_sw_data *sw_data;
 
-	return 0;
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	/* TODO: verify that service is running to avoid hanging if in block
+	 * mode
+	 */
+#endif
+
+	sw_data = adapter->data->adapter_priv;
+
+	n = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (n < 0) {
+		rte_errno = ENOMEM;
+		return 0;
+	}
+
+	/* Set up the messages */
+	for (i = 0; i < nb_evtims; i++) {
+		msg = msgs[i];
+		msg->type = MSG_TYPE_CANCEL;
+		msg->evtim = evtims[i];
+	}
+
+	n = rte_ring_enqueue_burst(sw_data->msg_ring, (void **)msgs, nb_evtims,
+				   NULL);
+	if (n < nb_evtims)
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[n],
+				     nb_evtims - n);
+
+	for (i = 0; i < n; i++) {
+		/* Wait until state is updated */
+		while (evtims[i]->state == RTE_EVENT_TIMER_ARMED)
+			;
+
+		/* Note any failures */
+		if (evtims[i]->state != RTE_EVENT_TIMER_CANCELED) {
+			fails[nb_fails++] = i;
+			rte_errno = EINVAL;
+		}
+	}
+
+	/* Move the failures to the end of the array */
+	for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
+		swap(evtims, fails[i], mark);
+
+	n = mark + 1;
+
+	return n;
 }
 
 static int
 sw_event_timer_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter,
-				  struct rte_event_timer **tims,
-				  uint64_t timeout_tick,
-				  uint16_t nb_tims)
+				  struct rte_event_timer **evtims,
+				  uint64_t timeout_ticks,
+				  uint16_t nb_evtims)
 {
-	RTE_SET_USED(adapter);
-	RTE_SET_USED(tims);
-	RTE_SET_USED(timeout_tick);
-	RTE_SET_USED(nb_tims);
+	int i;
 
-	return 0;
+	for (i = 0; i < nb_evtims; i++)
+		evtims[i]->timeout_ticks = timeout_ticks;
+
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
 }
 
 const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 6a6a745..3dd95f5 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)        += -lrte_bitratestats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
 
-_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
 
 _LDLIBS-y += --whole-archive
@@ -96,6 +95,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lrte_ethdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)       += -lrte_security
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 13/23] eventtimer: add adapter service definition
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (11 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 12/23] eventtimer: add event timer arm/cancel function definitions Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11 12:03       ` Pavan Nikhilesh
  2018-01-11  0:21     ` [PATCH v6 14/23] eventtimer: add event timer initializer function Erik Gabriel Carrillo
                       ` (10 subsequent siblings)
  23 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Define the callback function for the service that corresponds to an
adapter instance, as well as the callback for expired timers that the
service manages.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 198 +++++++++++++++++++++++++-
 lib/librte_eventdev/rte_event_timer_adapter.h |   2 +-
 2 files changed, 198 insertions(+), 2 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 38e52cb..0266ad5 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -40,8 +40,10 @@
 #include <rte_malloc.h>
 #include <rte_ring.h>
 #include <rte_mempool.h>
+#include <rte_common.h>
 #include <rte_timer.h>
 #include <rte_service_component.h>
+#include <rte_cycles.h>
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -460,10 +462,198 @@ struct msg {
 	struct rte_event_timer *evtim;
 };
 
+static void
+sw_event_timer_cb(struct rte_timer *tim, void *arg)
+{
+	uint16_t n;
+	struct rte_event_timer *evtim;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	evtim = arg;
+	adapter = (struct rte_event_timer_adapter *)evtim->impl_opaque[1];
+	sw_data = adapter->data->adapter_priv;
+
+	n = rte_event_enqueue_burst(adapter->data->event_dev_id,
+				    adapter->data->event_port_id,
+				    &evtim->ev,
+				    1);
+	if (n != 1 && rte_errno == -ENOSPC) {
+		/* If we couldn't enqueue because the event port was
+		 * backpressured, put the timer back in the skiplist with an
+		 * immediate expiry value so we can process it again on the
+		 * next iteration.
+		 */
+		rte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),
+				     sw_event_timer_cb, evtim);
+	} else {
+		sw_data->nb_armed_evtims--;
+		rte_wmb();
+		evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+		rte_mempool_put(sw_data->tim_pool, (void **)&tim);
+	}
+}
+
+static __rte_always_inline uint64_t
+get_timeout_cycles(struct rte_event_timer *evtim,
+		   struct rte_event_timer_adapter *adapter)
+{
+	uint64_t timeout_ns;
+
+	timeout_ns = evtim->timeout_ticks * adapter->data->conf.timer_tick_ns;
+#define NSECPERSEC 1E9
+	return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
+
+}
+
+/* Check that event timer timeout value is in range */
+static __rte_always_inline int
+check_timeout(struct rte_event_timer *evtim,
+	      const struct rte_event_timer_adapter *adapter)
+{
+	uint64_t tmo_nsec = evtim->timeout_ticks *
+		adapter->data->conf.timer_tick_ns;
+
+	return  (tmo_nsec > adapter->data->conf.max_tmo_ns) ? -1
+		: (tmo_nsec < adapter->data->conf.timer_tick_ns) ? -2
+		: 0;
+}
+
+/* Check that event timer event queue sched type matches destination event queue
+ * sched type
+ */
+static __rte_always_inline int
+check_destination_event_queue(struct rte_event_timer *evtim,
+			      const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	uint32_t sched_type;
+
+	ret = rte_event_queue_attr_get(adapter->data->event_dev_id,
+				       evtim->ev.queue_id,
+				       RTE_EVENT_QUEUE_ATTR_SCHEDULE_TYPE,
+				       &sched_type);
+
+	if (ret < 0 || evtim->ev.sched_type != sched_type)
+		return -1;
+
+	return 0;
+}
+
+/* We can't correctly block on the state of a timer that is currently armed,
+ * so disallow it.
+ */
+static __rte_always_inline int
+check_state_for_arm(struct rte_event_timer *evtim)
+{
+	return evtim->state != RTE_EVENT_TIMER_ARMED ? 0 : -1;
+}
+
+static inline int
+validate_event_timer(struct rte_event_timer *evtim,
+		     struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	if (check_state_for_arm(evtim) < 0) {
+		evtim->state = RTE_EVENT_TIMER_ERROR;
+		return -1;
+	}
+
+	ret = check_timeout(evtim, adapter);
+	switch (ret) {
+	case -1:
+		evtim->state = RTE_EVENT_TIMER_ERROR_TOOLATE;
+		return -1;
+	case -2:
+		evtim->state = RTE_EVENT_TIMER_ERROR_TOOEARLY;
+		return -1;
+	}
+
+	if (check_destination_event_queue(evtim, adapter) < 0) {
+		evtim->state = RTE_EVENT_TIMER_ERROR;
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#define NB_OBJS 32
 static int
 sw_event_timer_adapter_service_func(void *arg)
 {
-	RTE_SET_USED(arg);
+	int i, num_msgs, ret;
+	uint64_t cycles;
+	uint16_t nb_events;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_timer *tim = NULL;
+	struct msg *msg, *msgs[NB_OBJS];
+
+	adapter = arg;
+	sw_data = adapter->data->adapter_priv;
+
+	while (!rte_ring_empty(sw_data->msg_ring)) {
+		num_msgs = rte_ring_dequeue_burst(sw_data->msg_ring,
+						  (void **)msgs, NB_OBJS, NULL);
+
+		for (i = 0; i < num_msgs; i++) {
+			msg = msgs[i];
+			evtim = msg->evtim;
+
+			tim = (struct rte_timer *)evtim->impl_opaque[0];
+			RTE_ASSERT(tim != NULL);
+
+			switch (msg->type) {
+			case MSG_TYPE_ARM:
+				if (validate_event_timer(evtim, adapter) < 0) {
+					rte_mempool_put(sw_data->tim_pool,
+							(void **)&tim);
+					continue;
+				}
+
+				/* Checks passed; set an rte_timer */
+				cycles = get_timeout_cycles(msg->evtim,
+							    adapter);
+				rte_timer_reset_sync(tim, cycles, SINGLE,
+						     rte_lcore_id(),
+						     sw_event_timer_cb,
+						     msg->evtim);
+
+				sw_data->nb_armed_evtims++;
+				rte_wmb();
+				evtim->state = RTE_EVENT_TIMER_ARMED;
+				break;
+			case MSG_TYPE_CANCEL:
+				/* The event timer was either not armed or it
+				 * fired after this cancel request was queued
+				 * and before the request was processed.
+				 */
+				if (evtim->state != RTE_EVENT_TIMER_ARMED)
+					continue;
+
+				rte_timer_stop_sync(tim);
+				rte_mempool_put(sw_data->tim_pool,
+						(void **)&tim);
+				sw_data->nb_armed_evtims--;
+				rte_wmb();
+				msg->evtim->state = RTE_EVENT_TIMER_CANCELED;
+				break;
+			}
+		}
+
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)msgs,
+				     num_msgs);
+	}
+
+	rte_timer_manage();
+
+	/* Could use for stats */
+	RTE_SET_USED(nb_events);
+	RTE_SET_USED(ret);
+
 	return 0;
 }
 
@@ -474,6 +664,7 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
 	struct rte_event_timer_adapter_sw_data *sw_data;
 	uint64_t nb_timers;
 	struct rte_service_spec service;
+	static bool timer_subsystem_inited; // static initialized to false
 
 	/* Allocate storage for SW implementation data */
 	char priv_data_name[RTE_RING_NAMESIZE];
@@ -541,6 +732,11 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
 	adapter->data->service_id = sw_data->service_id;
 	adapter->data->service_inited = 1;
 
+	if (!timer_subsystem_inited) {
+		rte_timer_subsystem_init();
+		timer_subsystem_inited = true;
+	}
+
 	return 0;
 }
 
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index 8d29cfc..bbbe7b9 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -461,7 +461,7 @@ struct rte_event_timer {
 	 *  - op: RTE_EVENT_OP_NEW
 	 *  - event_type: RTE_EVENT_TYPE_TIMER
 	 */
-	enum rte_event_timer_state state;
+	volatile enum rte_event_timer_state state;
 	/**< State of the event timer. */
 	uint64_t timeout_ticks;
 	/**< Expiry timer ticks expressed in number of *timer_ticks_ns* from
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 14/23] eventtimer: add event timer initializer function
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (12 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 13/23] eventtimer: add adapter service definition Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11  0:21     ` [PATCH v6 15/23] eventtimer: add buffering of timer expiry events Erik Gabriel Carrillo
                       ` (9 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Add a function that can be used to initialize event timers so that they
are in a known state before being used for arm or cancel operations.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c |  8 ++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h | 11 +++++++++++
 lib/librte_eventdev/rte_eventdev_version.map  |  1 +
 3 files changed, 20 insertions(+)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 0266ad5..8bd9ebc 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -396,6 +396,14 @@ rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
 	return -ESRCH;
 }
 
+void
+rte_event_timer_init(struct rte_event_timer *evtim)
+{
+	evtim->ev.op = RTE_EVENT_OP_NEW;
+	evtim->ev.event_type = RTE_EVENT_TYPE_TIMER;
+	evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+}
+
 int
 rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
 			  struct rte_event_timer **evtims,
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index bbbe7b9..3488488 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -484,6 +484,17 @@ struct rte_event_timer {
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice
  *
+ * Set an event timer's initial state and initialize the event it carries.
+ *
+ * @param evtim
+ *   A pointer to an event timer structure.
+ */
+void rte_event_timer_init(struct rte_event_timer *evtim);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
  * Arm a burst of event timers with separate expiration timeout tick for each
  * event timer.
  *
diff --git a/lib/librte_eventdev/rte_eventdev_version.map b/lib/librte_eventdev/rte_eventdev_version.map
index a35a668..c4bc946 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -78,6 +78,7 @@ DPDK_18.02 {
 	rte_event_timer_adapter_service_id_get;
 	rte_event_timer_adapter_start;
 	rte_event_timer_adapter_stop;
+	rte_event_timer_init;
 	rte_event_timer_arm_burst;
 	rte_event_timer_arm_tmo_tick_burst;
 	rte_event_timer_cancel_burst;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 15/23] eventtimer: add buffering of timer expiry events
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (13 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 14/23] eventtimer: add event timer initializer function Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11 12:18       ` Pavan Nikhilesh
  2018-01-11  0:21     ` [PATCH v6 16/23] eventtimer: add stats to API Erik Gabriel Carrillo
                       ` (8 subsequent siblings)
  23 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Buffer timer expiry events generated while walking a "run list"
in rte_timer_manage, and burst enqueue them to an event device
to the extent possible.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 118 +++++++++++++++++++++++---
 1 file changed, 108 insertions(+), 10 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 8bd9ebc..176cc5b 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -447,7 +447,93 @@ rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
 }
 
 /*
- * Software event timer adapter ops definitions
+ * Software event timer adapter buffer helper functions
+ */
+
+#define EVENT_BUFFER_SZ 1024
+#if EVENT_BUFFER_SZ < 1 || EVENT_BUFFER_SZ > 65536
+#error "EVENT_BUFFER_SZ must be between 1 and 65536"
+#endif
+
+#define EVENT_BUFFER_BATCHSZ 32
+
+struct event_buffer {
+	uint16_t head;
+	uint16_t tail;
+	uint16_t count;
+	struct rte_event events[EVENT_BUFFER_SZ];
+} __rte_cache_aligned;
+
+static inline bool
+event_buffer_full(struct event_buffer *bufp)
+{
+	return (bufp->tail + 1) % EVENT_BUFFER_SZ == bufp->head;
+}
+
+static inline bool
+event_buffer_batch_ready(struct event_buffer *bufp)
+{
+	return bufp->count >= EVENT_BUFFER_BATCHSZ;
+}
+
+static void
+event_buffer_init(struct event_buffer *bufp)
+{
+	bufp->head = bufp->tail = bufp->count = 0;
+	memset(&bufp->events, 0, sizeof(struct rte_event) * EVENT_BUFFER_SZ);
+}
+
+static int
+event_buffer_add(struct event_buffer *bufp, struct rte_event *eventp)
+{
+	uint16_t *tailp = &bufp->tail;
+	struct rte_event *buf_eventp;
+
+	if (event_buffer_full(bufp))
+		return -1;
+
+	buf_eventp = &bufp->events[*tailp];
+	rte_memcpy(buf_eventp, eventp, sizeof(struct rte_event));
+
+	*tailp = (*tailp + 1) % EVENT_BUFFER_SZ;
+	bufp->count++;
+
+	return 0;
+}
+
+static void
+event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,
+		   uint16_t *nb_events_flushed)
+{
+	uint16_t n = 0;
+	uint16_t *headp = &bufp->head;
+	uint16_t *tailp = &bufp->tail;
+	struct rte_event *events = bufp->events;
+
+	if (*tailp > *headp)
+		n = *tailp - *headp;
+	else if (*tailp < *headp)
+		n = EVENT_BUFFER_SZ - *headp;
+	else {  /* buffer empty */
+		*nb_events_flushed = 0;
+		return;
+	}
+
+	*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
+						     &events[*headp], n);
+	if (*nb_events_flushed != n && rte_errno == -EINVAL) {
+		/* We must have hit a bad event...skip it to ensure we don't
+		 * hang on it.
+		 */
+		(*nb_events_flushed)++;
+	}
+
+	*headp = (*headp + *nb_events_flushed) % EVENT_BUFFER_SZ;
+	bufp->count -= *nb_events_flushed;
+}
+
+/*
+ * Software event timer adapter implementation
  */
 
 struct rte_event_timer_adapter_sw_data {
@@ -461,6 +547,8 @@ struct rte_event_timer_adapter_sw_data {
 	struct rte_mempool *msg_pool;
 	/* Mempool containing timer objects */
 	struct rte_mempool *tim_pool;
+	/* Buffered timer expiry events to be enqueued to an event device. */
+	struct event_buffer buffer;
 };
 
 enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
@@ -473,7 +561,8 @@ struct msg {
 static void
 sw_event_timer_cb(struct rte_timer *tim, void *arg)
 {
-	uint16_t n;
+	uint16_t nb_evs_flushed;
+	int ret;
 	struct rte_event_timer *evtim;
 	struct rte_event_timer_adapter *adapter;
 	struct rte_event_timer_adapter_sw_data *sw_data;
@@ -482,14 +571,10 @@ sw_event_timer_cb(struct rte_timer *tim, void *arg)
 	adapter = (struct rte_event_timer_adapter *)evtim->impl_opaque[1];
 	sw_data = adapter->data->adapter_priv;
 
-	n = rte_event_enqueue_burst(adapter->data->event_dev_id,
-				    adapter->data->event_port_id,
-				    &evtim->ev,
-				    1);
-	if (n != 1 && rte_errno == -ENOSPC) {
-		/* If we couldn't enqueue because the event port was
-		 * backpressured, put the timer back in the skiplist with an
-		 * immediate expiry value so we can process it again on the
+	ret = event_buffer_add(&sw_data->buffer, &evtim->ev);
+	if (ret < 0) {
+		/* If event buffer is full, put timer back in list with
+		 * immediate expiry value, so that we process it again on the
 		 * next iteration.
 		 */
 		rte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),
@@ -500,6 +585,13 @@ sw_event_timer_cb(struct rte_timer *tim, void *arg)
 		evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
 		rte_mempool_put(sw_data->tim_pool, (void **)&tim);
 	}
+
+	if (event_buffer_batch_ready(&sw_data->buffer)) {
+		event_buffer_flush(&sw_data->buffer,
+				   adapter->data->event_dev_id,
+				   adapter->data->event_port_id,
+				   &nb_evs_flushed);
+	}
 }
 
 static __rte_always_inline uint64_t
@@ -658,10 +750,14 @@ sw_event_timer_adapter_service_func(void *arg)
 
 	rte_timer_manage();
 
+	event_buffer_flush(&sw_data->buffer, adapter->data->event_dev_id,
+			   adapter->data->event_port_id, &nb_events);
+
 	/* Could use for stats */
 	RTE_SET_USED(nb_events);
 	RTE_SET_USED(ret);
 
+
 	return 0;
 }
 
@@ -726,6 +822,8 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
 		return -1;
 	}
 
+	event_buffer_init(&sw_data->buffer);
+
 	/* Register a service component */
 	memset(&service, 0, sizeof(service));
 	snprintf(service.name, RTE_SERVICE_NAME_MAX,
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 16/23] eventtimer: add stats to API
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (14 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 15/23] eventtimer: add buffering of timer expiry events Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11  0:21     ` [PATCH v6 17/23] eventtimer: add support for single-producer put mode Erik Gabriel Carrillo
                       ` (7 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Add interfaces to support the collection, retrieval and resetting of
per-adapter statistics.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c     | 79 +++++++++++++++++++----
 lib/librte_eventdev/rte_event_timer_adapter.h     | 51 +++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 11 ++++
 lib/librte_eventdev/rte_eventdev_version.map      |  2 +
 4 files changed, 130 insertions(+), 13 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 176cc5b..ebc6124 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -405,6 +405,26 @@ rte_event_timer_init(struct rte_event_timer *evtim)
 }
 
 int
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer_adapter_stats *stats)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_get, -EINVAL);
+	if (stats == NULL)
+		return -EINVAL;
+
+	return adapter->ops->stats_get(adapter, stats);
+}
+
+int
+rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_reset, -EINVAL);
+	return adapter->ops->stats_reset(adapter);
+}
+
+int
 rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
 			  struct rte_event_timer **evtims,
 			  uint16_t nb_evtims)
@@ -503,7 +523,8 @@ event_buffer_add(struct event_buffer *bufp, struct rte_event *eventp)
 
 static void
 event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,
-		   uint16_t *nb_events_flushed)
+		   uint16_t *nb_events_flushed,
+		   uint16_t *nb_events_inv)
 {
 	uint16_t n = 0;
 	uint16_t *headp = &bufp->head;
@@ -519,17 +540,19 @@ event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,
 		return;
 	}
 
+	*nb_events_inv = 0;
 	*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
 						     &events[*headp], n);
 	if (*nb_events_flushed != n && rte_errno == -EINVAL) {
 		/* We must have hit a bad event...skip it to ensure we don't
 		 * hang on it.
 		 */
-		(*nb_events_flushed)++;
+		nb_events_inv++;
 	}
 
-	*headp = (*headp + *nb_events_flushed) % EVENT_BUFFER_SZ;
-	bufp->count -= *nb_events_flushed;
+	*headp = (*headp + *nb_events_flushed + *nb_events_inv) %
+		EVENT_BUFFER_SZ;
+	bufp->count -= (*nb_events_flushed + *nb_events_inv);
 }
 
 /*
@@ -549,6 +572,8 @@ struct rte_event_timer_adapter_sw_data {
 	struct rte_mempool *tim_pool;
 	/* Buffered timer expiry events to be enqueued to an event device. */
 	struct event_buffer buffer;
+	/* Statistics */
+	struct rte_event_timer_adapter_stats stats;
 };
 
 enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
@@ -561,7 +586,7 @@ struct msg {
 static void
 sw_event_timer_cb(struct rte_timer *tim, void *arg)
 {
-	uint16_t nb_evs_flushed;
+	uint16_t nb_evs_flushed, nb_evs_invalid;
 	int ret;
 	struct rte_event_timer *evtim;
 	struct rte_event_timer_adapter *adapter;
@@ -579,6 +604,8 @@ sw_event_timer_cb(struct rte_timer *tim, void *arg)
 		 */
 		rte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),
 				     sw_event_timer_cb, evtim);
+
+		sw_data->stats.evtim_retry_count++;
 	} else {
 		sw_data->nb_armed_evtims--;
 		rte_wmb();
@@ -590,7 +617,11 @@ sw_event_timer_cb(struct rte_timer *tim, void *arg)
 		event_buffer_flush(&sw_data->buffer,
 				   adapter->data->event_dev_id,
 				   adapter->data->event_port_id,
-				   &nb_evs_flushed);
+				   &nb_evs_flushed,
+				   &nb_evs_invalid);
+
+		sw_data->stats.ev_enq_count += nb_evs_flushed;
+		sw_data->stats.ev_inv_count += nb_evs_invalid;
 	}
 }
 
@@ -683,9 +714,9 @@ validate_event_timer(struct rte_event_timer *evtim,
 static int
 sw_event_timer_adapter_service_func(void *arg)
 {
-	int i, num_msgs, ret;
+	int i, num_msgs;
 	uint64_t cycles;
-	uint16_t nb_events;
+	uint16_t nb_evs_flushed, nb_evs_invalid;
 	struct rte_event_timer_adapter *adapter;
 	struct rte_event_timer_adapter_sw_data *sw_data;
 	struct rte_event_timer *evtim = NULL;
@@ -751,12 +782,12 @@ sw_event_timer_adapter_service_func(void *arg)
 	rte_timer_manage();
 
 	event_buffer_flush(&sw_data->buffer, adapter->data->event_dev_id,
-			   adapter->data->event_port_id, &nb_events);
-
-	/* Could use for stats */
-	RTE_SET_USED(nb_events);
-	RTE_SET_USED(ret);
+			   adapter->data->event_port_id, &nb_evs_flushed,
+			   &nb_evs_invalid);
 
+	sw_data->stats.ev_enq_count += nb_evs_flushed;
+	sw_data->stats.ev_inv_count += nb_evs_invalid;
+	sw_data->stats.svc_run_count++;
 
 	return 0;
 }
@@ -911,6 +942,26 @@ sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
 	return rte_service_component_runstate_set(sw_data->service_id, 0);
 }
 
+static int
+sw_event_timer_adapter_stats_get(const struct rte_event_timer_adapter *adapter,
+				 struct rte_event_timer_adapter_stats *stats)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	*stats = sw_data->stats;
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_stats_reset(
+				const struct rte_event_timer_adapter *adapter)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	memset(&sw_data->stats, 0, sizeof(sw_data->stats));
+	return 0;
+}
+
 static __rte_always_inline void
 swap(struct rte_event_timer **evtims, int i, int j)
 {
@@ -1076,6 +1127,8 @@ const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
 	.start = sw_event_timer_adapter_start,
 	.stop = sw_event_timer_adapter_stop,
 	.get_info = NULL,
+	.stats_get = sw_event_timer_adapter_stats_get,
+	.stats_reset = sw_event_timer_adapter_stats_reset,
 	.arm_burst = sw_event_timer_arm_burst,
 	.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
 	.cancel_burst = sw_event_timer_cancel_burst,
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index 3488488..a4b16a7 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -201,6 +201,23 @@ struct rte_event_timer_adapter_conf {
 	/**< Timer adapter config flags (RTE_EVENT_TIMER_ADAPTER_F_*) */
 };
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer adapter stats structure
+ */
+struct rte_event_timer_adapter_stats {
+	uint64_t ev_enq_count;
+	/**< Eventdev enqueue count */
+	uint64_t ev_inv_count;
+	/**< Invalid expiry event count */
+	uint64_t evtim_retry_count;
+	/**< Event timer retry count */
+	uint64_t svc_run_count;
+	/**< Service run count */
+};
+
 struct rte_event_timer_adapter;
 
 /**
@@ -420,6 +437,40 @@ rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
 
 /**
  * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param[out] stats
+ *   A pointer to a structure to fill with statistics.
+ *
+ * @return
+ *   - 0: Successfully retrieved.
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				struct rte_event_timer_adapter_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully reset;
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_reset(
+				struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
  * @b EXPERIMENTAL: this structure may change without prior notice
  *
  * Event timer state.
diff --git a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
index 6c65c36..a8c068f 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
@@ -68,6 +68,13 @@ typedef void (*rte_event_timer_adapter_get_info_t)(
 		const struct rte_event_timer_adapter *adapter,
 		struct rte_event_timer_adapter_info *adapter_info);
 /**< @internal Get contextual information for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_get_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_stats *stats);
+/**< @internal Get statistics for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_reset_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Reset statistics for event timer adapter */
 typedef int (*rte_event_timer_arm_burst_t)(
 		const struct rte_event_timer_adapter *adapter,
 		struct rte_event_timer **tims,
@@ -96,6 +103,10 @@ struct rte_event_timer_adapter_ops {
 	rte_event_timer_adapter_stop_t		stop;  /**< Stop adapter */
 	rte_event_timer_adapter_get_info_t	get_info;
 	/**< Get info from driver */
+	rte_event_timer_adapter_stats_get_t	stats_get;
+	/**< Get adapter statistics */
+	rte_event_timer_adapter_stats_reset_t	stats_reset;
+	/**< Reset adapter statistics */
 	rte_event_timer_arm_burst_t		arm_burst;
 	/**< Arm one or more event timers */
 	rte_event_timer_arm_tmo_tick_burst_t	arm_tmo_tick_burst;
diff --git a/lib/librte_eventdev/rte_eventdev_version.map b/lib/librte_eventdev/rte_eventdev_version.map
index c4bc946..6a98840 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -77,6 +77,8 @@ DPDK_18.02 {
 	rte_event_timer_adapter_get_info;
 	rte_event_timer_adapter_service_id_get;
 	rte_event_timer_adapter_start;
+	rte_event_timer_adapter_stats_get;
+	rte_event_timer_adapter_stats_reset;
 	rte_event_timer_adapter_stop;
 	rte_event_timer_init;
 	rte_event_timer_arm_burst;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 17/23] eventtimer: add support for single-producer put mode
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (15 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 16/23] eventtimer: add stats to API Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11  0:21     ` [PATCH v6 18/23] eventtimer: add non-blocking mode for event timer operations Erik Gabriel Carrillo
                       ` (6 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Add support for the RTE_EVENT_TIMER_ADAPTER_F_SP_PUT flag, which indicates
that the API should be used in single-producer put mode.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index ebc6124..0af68b2 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -798,6 +798,7 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
 	int ret;
 	struct rte_event_timer_adapter_sw_data *sw_data;
 	uint64_t nb_timers;
+	unsigned int flags;
 	struct rte_service_spec service;
 	static bool timer_subsystem_inited; // static initialized to false
 
@@ -823,8 +824,11 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
 	char msg_ring_name[RTE_RING_NAMESIZE];
 	snprintf(msg_ring_name, RTE_RING_NAMESIZE,
 		 "sw_evtim_adap_msg_ring_%"PRIu8, adapter->data->id);
+	flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+		RING_F_SP_ENQ | RING_F_SC_DEQ :
+		RING_F_SC_DEQ;
 	sw_data->msg_ring = rte_ring_create(msg_ring_name, nb_timers,
-					    adapter->data->socket_id, 0);
+					    adapter->data->socket_id, flags);
 	if (sw_data->msg_ring == NULL) {
 		rte_errno = ENOMEM;
 		return -1;
@@ -833,10 +837,13 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
 	char pool_name[RTE_RING_NAMESIZE];
 	snprintf(pool_name, RTE_RING_NAMESIZE, "sw_evtim_adap_msg_pool_%"PRIu8,
 		 adapter->data->id);
+	flags = (adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT) ?
+		 MEMPOOL_F_SP_PUT | MEMPOOL_F_SC_GET :
+		 MEMPOOL_F_SC_GET;
 	sw_data->msg_pool = rte_mempool_create(pool_name, nb_timers,
 					       sizeof(struct msg), 32, 0, NULL,
 					       NULL, NULL, NULL,
-					       adapter->data->socket_id, 0);
+					       adapter->data->socket_id, flags);
 	if (sw_data->msg_pool == NULL) {
 		rte_errno = ENOMEM;
 		return -1;
@@ -847,7 +854,7 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
 	sw_data->tim_pool = rte_mempool_create(pool_name, nb_timers,
 					       sizeof(struct rte_timer), 32, 0,
 					       NULL, NULL, NULL, NULL,
-					       adapter->data->socket_id, 0);
+					       adapter->data->socket_id, flags);
 	if (sw_data->tim_pool == NULL) {
 		printf("Could not allocate tim mempool\n");
 		return -1;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 18/23] eventtimer: add non-blocking mode for event timer operations
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (16 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 17/23] eventtimer: add support for single-producer put mode Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11  0:21     ` [PATCH v6 19/23] test: exercise event timer arm and expiry Erik Gabriel Carrillo
                       ` (5 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Add a mode to the event timer adapter that allows the event timer arm
and cancel APIs to return immediately, rather than waiting for the service
to update the state of each timer.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 69 ++++++++++++++-------------
 lib/librte_eventdev/rte_event_timer_adapter.h |  6 +++
 2 files changed, 43 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 0af68b2..624cc36 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -1022,28 +1022,31 @@ __sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
 				     nb_evtims - n);
 	}
 
-	for (i = 0; i < n; i++) {
-		/* Wait until state is updated */
-		while (evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
-		       evtims[i]->state == RTE_EVENT_TIMER_CANCELED)
-			;
-
-		/* Note any failures */
-		if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
-			fails[nb_fails++] = i;
-			rte_errno = EINVAL;
-		}
+	if (!(adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_NB_ARM)) {
+		for (i = 0; i < n; i++) {
+			/* Wait until state is updated */
+			while (evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
+			       evtims[i]->state == RTE_EVENT_TIMER_CANCELED)
+				;
+
+			/* Note any failures */
+			if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
+				fails[nb_fails++] = i;
+				rte_errno = EINVAL;
+			}
 
-		/* TODO: handle the case of consecutive arm requests;  the
-		 * second request can erroneously see success from the first
-		 */
-	}
+			/* TODO: handle the case of consecutive arm requests;
+			 * the second request can erroneously see success from
+			 * the first
+			 */
+		}
 
-	/* Move the failures to the end of the array */
-	for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
-		swap(evtims, fails[i], mark);
+		/* Move the failures to the end of the array */
+		for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
+			swap(evtims, fails[i], mark);
 
-	n = mark + 1;
+		n = mark + 1;
+	}
 
 	return n;
 }
@@ -1093,23 +1096,25 @@ sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
 		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[n],
 				     nb_evtims - n);
 
-	for (i = 0; i < n; i++) {
-		/* Wait until state is updated */
-		while (evtims[i]->state == RTE_EVENT_TIMER_ARMED)
-			;
+	if (!(adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_NB_ARM)) {
+		for (i = 0; i < n; i++) {
+			/* Wait until state is updated */
+			while (evtims[i]->state == RTE_EVENT_TIMER_ARMED)
+				;
 
-		/* Note any failures */
-		if (evtims[i]->state != RTE_EVENT_TIMER_CANCELED) {
-			fails[nb_fails++] = i;
-			rte_errno = EINVAL;
+			/* Note any failures */
+			if (evtims[i]->state != RTE_EVENT_TIMER_CANCELED) {
+				fails[nb_fails++] = i;
+				rte_errno = EINVAL;
+			}
 		}
-	}
 
-	/* Move the failures to the end of the array */
-	for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
-		swap(evtims, fails[i], mark);
+		/* Move the failures to the end of the array */
+		for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
+			swap(evtims, fails[i], mark);
 
-	n = mark + 1;
+		n = mark + 1;
+	}
 
 	return n;
 }
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index a4b16a7..2a69455 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -175,6 +175,12 @@ enum rte_event_timer_adapter_clk_src {
  *
  * @see struct rte_event_timer_adapter_conf::flags
  */
+#define RTE_EVENT_TIMER_ADAPTER_F_NB_ARM	(1ULL << 2)
+/**< ``rte_event_timer_arm_burst()`` API to be used in non-blocking/
+ * asynchronous mode
+ *
+ * @see struct rte_event_timer_adapter_conf::flags
+ */
 
 /**
  * @warning
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 19/23] test: exercise event timer arm and expiry
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (17 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 18/23] eventtimer: add non-blocking mode for event timer operations Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11 12:26       ` Pavan Nikhilesh
  2018-01-11  0:21     ` [PATCH v6 20/23] maintainers: add event timer adapter section Erik Gabriel Carrillo
                       ` (4 subsequent siblings)
  23 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Add a test that creates an event timer and detects the generation of a
timer expiry event being scheduled through the software event device.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 test/test/test_event_timer_adapter.c | 106 +++++++++++++++++++++++++++++++++++
 1 file changed, 106 insertions(+)

diff --git a/test/test/test_event_timer_adapter.c b/test/test/test_event_timer_adapter.c
index 58cbaba..3a16cce 100644
--- a/test/test/test_event_timer_adapter.c
+++ b/test/test/test_event_timer_adapter.c
@@ -319,6 +319,111 @@ adapter_start_stop(void)
 	return TEST_SUCCESS;
 }
 
+#define BATCH_SIZE 16
+static int
+event_timer_expiry(void)
+{
+	uint16_t n;
+	uint32_t evdev_service_id, adapter_service_id;
+	int ret;
+	struct rte_event_timer_adapter *adapter = g_adapter;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event_timer *evtim2 = NULL;
+	struct rte_event evs[BATCH_SIZE];
+
+	TEST_ASSERT_SUCCESS(rte_event_dev_service_id_get(evdev,
+					&evdev_service_id), "Failed to get "
+					"event device service id");
+
+	TEST_ASSERT(rte_service_lcore_count() > 0, "Need one or more service "
+		    "cores to perform this test");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(g_adapter,
+					&adapter_service_id), "Failed to get "
+					"event timer adapter service id");
+
+	/* Could map using service_id, but just do default mapping */
+	ret = rte_service_start_with_defaults();
+	TEST_ASSERT_SUCCESS(ret, "Failed to start services");
+
+	if (rte_event_dev_start(evdev) < 0) {
+		printf("Failed to start event device\n");
+		return TEST_FAILED;
+	}
+
+	ret = rte_event_timer_adapter_start(adapter);
+	if (ret < 0) {
+		printf("Failed to start adapter\n");
+		return TEST_FAILED;
+	}
+
+	/* Set up an event timer */
+	rte_mempool_get(g_event_timer_pool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	rte_event_timer_init(evtim);
+
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.queue_id = TEST_QUEUE_ID;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	if (ret != 1) {
+		printf("Failed to arm event timer: %s\n",
+		       rte_strerror(rte_errno));
+		return TEST_FAILED;
+	}
+
+	rte_delay_ms(2999);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event");
+
+	/* Delay 1 more millisecond and run the services again - should let us
+	 * dequeue one event
+	 */
+	rte_delay_ms(1);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	if (n == 0) {
+		printf("Failed to dequeue timer expiry event\n");
+		return TEST_FAILED;
+	}
+
+	if (n > 1) {
+		printf("Dequeued incorrect number (%d) of timer expiry "
+		       "events\n", n);
+		return TEST_FAILED;
+	}
+
+	if (evs[0].event_type != RTE_EVENT_TYPE_TIMER) {
+		printf("Dequeued unexpected type of event\n");
+		return TEST_FAILED;
+	}
+
+	/* Check that we recover the original event timer and then free it */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+	rte_mempool_put(g_event_timer_pool, evtim2);
+
+	ret = rte_event_timer_adapter_stop(adapter);
+	if (ret < 0) {
+		printf("Failed to stop event adapter\n");
+		return TEST_FAILED;
+	}
+
+	rte_event_dev_stop(evdev);
+
+	rte_service_lcore_reset_all();
+
+	return TEST_SUCCESS;
+}
+
 static struct unit_test_suite adapter_tests  = {
 	.suite_name = "event timer adapter test suite",
 	.setup = testsuite_setup,
@@ -326,6 +431,7 @@ static struct unit_test_suite adapter_tests  = {
 	.unit_test_cases = {
 		TEST_CASE(adapter_create_free),
 		TEST_CASE_ST(adapter_create, adapter_free, adapter_start_stop),
+		TEST_CASE_ST(adapter_create, adapter_free, event_timer_expiry),
 		TEST_CASES_END() /**< NULL terminate unit test array */
 	}
 };
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 20/23] maintainers: add event timer adapter section
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (18 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 19/23] test: exercise event timer arm and expiry Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11  0:21     ` [PATCH v6 21/23] doc: add event timer adapter to API index Erik Gabriel Carrillo
                       ` (3 subsequent siblings)
  23 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 MAINTAINERS | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b51c2d0..55581c8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -291,6 +291,12 @@ F: lib/librte_eventdev/*eth_rx_adapter*
 F: test/test/test_event_eth_rx_adapter.c
 F: doc/guides/prog_guide/event_ethernet_rx_adapter.rst
 
+Eventdev Timer Adapter API - EXPERIMENTAL
+M: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
+T: git://dpdk.org/next/dpdk-next-eventdev
+F: lib/librte_eventdev/*timer_adapter*
+F: test/test/test_event_timer_adapter.c
+F: doc/guides/prog_guide/event_timer_adapter.rst
 
 Bus Drivers
 -----------
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 21/23] doc: add event timer adapter to API index
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (19 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 20/23] maintainers: add event timer adapter section Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-12 11:12       ` Kovacevic, Marko
  2018-01-11  0:21     ` [PATCH v6 22/23] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
                       ` (2 subsequent siblings)
  23 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 doc/api/doxy-api-index.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 3492702..3110658 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -46,6 +46,7 @@ The public API headers are grouped by topics:
   [security]           (@ref rte_security.h),
   [eventdev]           (@ref rte_eventdev.h),
   [event_eth_rx_adapter]   (@ref rte_event_eth_rx_adapter.h),
+  [event_timer_adapter]    (@ref rte_event_timer_adapter.h),
   [metrics]            (@ref rte_metrics.h),
   [bitrate]            (@ref rte_bitrate.h),
   [latency]            (@ref rte_latencystats.h),
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 22/23] doc: add event timer adapter section to programmer's guide
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (20 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 21/23] doc: add event timer adapter to API index Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-11 15:26       ` Kovacevic, Marko
  2018-01-11  0:21     ` [PATCH v6 23/23] doc: add event timer adapter to release notes Erik Gabriel Carrillo
  2018-03-08 21:53     ` [PATCH v7 0/7] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  23 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 doc/guides/prog_guide/event_timer_adapter.rst | 301 ++++++++++++++++++++++++++
 doc/guides/prog_guide/index.rst               |   1 +
 2 files changed, 302 insertions(+)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst

diff --git a/doc/guides/prog_guide/event_timer_adapter.rst b/doc/guides/prog_guide/event_timer_adapter.rst
new file mode 100644
index 0000000..47418a2
--- /dev/null
+++ b/doc/guides/prog_guide/event_timer_adapter.rst
@@ -0,0 +1,301 @@
+..  BSD LICENSE
+    Copyright(c) 2017 Intel Corporation. All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+    * Neither the name of Intel Corporation nor the names of its
+    contributors may be used to endorse or promote products derived
+    from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Event Timer Adapter Library
+=================================
+
+The DPDK
+`Event Device library <http://dpdk.org/doc/guides/prog_guide/eventdev.html>`_
+introduces an event driven programming model which presents applications with
+an alternative to the polling model traditionally used in DPDK
+applications. Event devices can be coupled with arbitrary components to provide
+new event sources by using **event adapters**. The Event Timer Adapter is one
+such adapter; it bridges event devices and timer mechanisms.
+
+The Event Timer Adapter library extends the event driven model
+by introducing a :ref:`new type of event <timer_expiry_event>` that represents
+a timer expiration, and providing an API with which adapters can be created or
+destroyed, and :ref:`event timers <event_timer>` can be armed and canceled.
+
+The Event Timer Adapter library is designed to interface with hardware or
+software implementations of the timer mechanism; it will query an eventdev PMD
+to determine which implementation should be used.  The default software
+implementation manages timers using the DPDK
+`Timer library <http://dpdk.org/doc/guides/prog_guide/timer_lib.html>`_.
+
+Examples of using the API are presented in the `API Overview`_ and
+`Processing Timer Expiry Events`_ sections.  Code samples are abstracted and
+are based on the example of handling a TCP retransmission.
+
+.. _event_timer:
+
+Event Timer struct
+------------------
+Event timers are timers that enqueue a timer expiration event to an event
+device upon firing.
+
+The Event Timer Adapter API represents each event timer with a generic struct,
+which contains an event and user metadata.  The ``rte_event_timer`` struct is
+defined in ``lib/librte_event/librte_event_timer_adapter.h``.
+
+.. _timer_expiry_event:
+
+Timer Expiry Event
+~~~~~~~~~~~~~~~~~~
+
+The event contained by an event timer is enqueued in the event device when the
+timer expires, and the event device uses the attributes below when scheduling
+it:
+
+* ``event_queue_id`` - Application should set this to specify an event queue to
+  which the timer expiry event should be enqueued
+* ``event_priority`` - Application can set this to indicate the priority of the
+  timer expiry event in the event queue relative to other events
+* ``sched_type`` - Application can set this to specify the scheduling type of
+  the timer expiry event
+* ``flow_id`` - Application can set this to indicate which flow this timer
+  expiry event corresponds to
+* ``op`` - Will be set to ``RTE_EVENT_OP_NEW`` by the event timer adapter
+* ``event_type`` - Will be set to ``RTE_EVENT_TYPE_TIMER`` by the event timer
+  adapter
+
+Timeout Ticks
+~~~~~~~~~~~~~
+
+The number of ticks from now in which the timer will expire. The ticks value
+has a resolution (``timer_tick_ns``) that is specified in the event timer
+adapter configuration.
+
+User Metadata
+~~~~~~~~~~~~~
+
+Memory to store user specific metadata.  The event timer adapter implementation
+will not modify this area.
+
+API Overview
+----------------
+
+This section will introduce the reader to the event timer adapter API, showing
+how to create and configure an event timer adapter and use it to manage event
+timers.
+
+From a high level, the setup steps are:
+
+* rte_event_timer_adapter_create()
+* rte_event_timer_adapter_start()
+
+And to start and stop timers:
+
+* rte_event_timer_arm_burst()
+* rte_event_timer_cancel_burst()
+
+Create and Configure an Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To create an event timer adapter instance, initialize an
+``rte_event_timer_adapter_conf`` struct with the desired values, and pass it
+to ``rte_event_timer_adapter_create()``.
+
+.. code-block:: c
+
+	#define NSECPERSEC 1E9 // No of ns for 1 sec
+	const struct rte_event_timer_adapter_config adapter_config = {
+                .event_dev_id = event_dev_id,
+                .timer_adapter_id = 0,
+                .clk_src = RTE_EVENT_TIMER_WHEEL_CPU_CLK,
+                .timer_tick_ns = NSECPERSEC / 10, // 100 milliseconds
+                .max_tmo_nsec = 180 * NSECPERSEC // 2 minutes
+                .nb_timers = 40000, // Number of timers the adapter can hold.
+                .timer_adapter_flags = 0,
+	};
+
+	struct rte_event_timer_adapter *adapter = NULL;
+	adapter = rte_event_timer_adapter_create(&adapter_config);
+
+	if (adapter == NULL) { ... };
+
+Before creating an instance of a timer adapter, the application should create
+and configure an event device along with the event ports. Based on the event
+device capability, it might require creating an additional event port to be
+used by the timer adapter.  If required, the
+``rte_event_timer_adapter_create()`` function will use a default method to
+configure an event port; it will examine the current event device configuration,
+determine the next available port identifier number, and create a new event
+port with a default port configuration.
+
+If the application desires to have finer control of event port allocation
+and setup, it can use the ``rte_event_timer_adapter_create_ext()`` function.
+This function is passed a callback function that will be invoked if the
+adapter needs to create an event port, giving the application the opportunity
+to control how it is done.
+
+Retrieve Event Timer Adapter Contextual Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The event timer adapter implementation may have constraints on tick resolution
+or maximum timer expiry timeout based on the given event timer adapter or
+system.  In this case, the implementation may adjust the tick resolution or
+maximum timeout to the best possible configuration.
+
+Upon successful event timer adapter creation, the application can get the
+configured resolution and max timeout with
+``rte_event_timer_adapter_get_info()``. This function will return an
+``rte_event_timer_adapter_info`` struct, which contains the following members:
+
+* ``min_resolution_ns`` - Minimum timer adapter tick resolution in ns.
+* ``max_tmo_ns`` - Maximum timer timeout(expiry) in ns.
+* ``adapter_conf`` - Configured event timer adapter attributes
+
+Configuring the Service Component
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the adapter uses a service component, the application is required to map
+the service to a service core before starting the adapter:
+
+.. code-block:: c
+
+        uint32_t service_id;
+
+        if (rte_event_timer_adapter_service_id_get(adapter, &service_id) == 0)
+                rte_service_map_lcore_set(service_id, RX_CORE_ID);
+
+An event timer adapter uses a service component if the event device PMD
+indicates that the adapter should use a software implementation.
+
+Starting the Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The application should call ``rte_event_timer_adapter_start()`` to start
+running the event timer adapter. This function calls the start callbacks
+defined by eventdev PMDs for hardware implementations or sets a service
+component into the running state in the default software implementation.
+
+Arming Event Timers
+~~~~~~~~~~~~~~~~~~~~~
+
+Once an event timer adapter has been started, an application can begin to
+manage event timers with it.
+
+The application should allocate ``struct rte_event_timer`` objects from a
+mempool or huge-page backed application buffers of required size. Upon
+successful allocation, the application should initialize the event timer, and
+then set any of the necessary event attributes described in the
+`Timer Expiry Event`_ section. In the following example, assume ``conn``
+represents a TCP connection and that ``event_timer_pool`` is a mempool that
+was created previously:
+
+.. code-block:: c
+
+	rte_mempool_get(event_timer_pool, (void **)&conn->evtim);
+	if (conn->evtim == NULL) { ... }
+
+        rte_event_timer_init(&conn->evtim);
+
+	/* Set up the timer event. */
+	conn->evtim->ev.event_ptr = conn;
+	conn->evtim->ev.queue_id = event_queue_id;
+	...
+	conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns)
+
+Note that we have saved a pointer to the ``conn`` object in the timer's event
+payload. This will allow us to locate the connection object again once we
+dequeue the timer expiry event from the event device later.
+
+Now we can arm the event timer with ``rte_event_timer_arm_burst()``:
+
+.. code-block:: c
+
+	ret = rte_event_timer_arm_burst(adapter, &conn->evtim, 1);
+	if (ret != 1) { ... }
+
+Multiple Event Timers with Same Expiry Value
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the special case that there is a set of event timers that should all expire
+at the same time, the application may call
+``rte_event_timer_arm_tmo_tick_burst()``, which allows the implementation to
+optimize the operation if possible.
+
+Canceling Event Timers
+~~~~~~~~~~~~~~~~~~~~~~~
+
+An event timer that has been armed as described in `Arming Event Timers`_ can
+be canceled by calling ``rte_event_timer_cancel_burst()``:
+
+.. code-block:: c
+
+	/* Ack for the previous tcp data packet has been received.*/
+	/* cancel the retransmission timer*/
+	rte_event_timer_cancel_burst(wheel, &conn->timer, 1);
+
+Processing Timer Expiry Events
+------------------------------
+
+Once an event timer has successfully enqueued a timer expiry event in the event
+device, the application will subsequently dequeue it from the event device.
+The application can use the event payload to retrieve a pointer to the object
+associated with the event timer. It can then re-arm the event timer or free the
+event timer object as desired:
+
+.. code-block:: c
+
+	void
+	event_processing_loop(...)
+	{
+		while (...) {
+			/* Receive events from the configured event port. */
+			rte_event_dequeue_burst(event_dev_id, event_port, &ev, 1, 0);
+			...
+			switch(ev.event_type) {
+				...
+				case RTE_EVENT_TYPE_TIMER:
+					process_timer_event(ev);
+					...
+					break;
+			}
+		}
+	}
+
+	uint8_t
+	process_timer_event(...)
+	{
+		/* A retransmission timeout for the connection has been received. */
+		conn = ev.event_ptr;
+		/* Retransmit last packet (e.g. TCP segment). */
+		...
+		/* Re-arm timer using original values. */
+		rte_event_timer_arm_burst(wheel_id, &conn->timer, 1);
+	}
+
+Summary
+-------
+
+The Event Timer Adapter library extends the DPDK event-based programming model
+by representing timer expirations as events in the system and allowing
+applications to use existing event processing loops to arm and cancel event
+timers or handle timer expiry events.
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index c4beb34..9a85d18 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -67,6 +67,7 @@ Programmer's Guide
     thread_safety_dpdk_functions
     eventdev
     event_ethernet_rx_adapter
+    event_timer_adapter
     qos_framework
     power_man
     packet_classif_access_ctrl
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v6 23/23] doc: add event timer adapter to release notes
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (21 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 22/23] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
@ 2018-01-11  0:21     ` Erik Gabriel Carrillo
  2018-01-12 10:48       ` Kovacevic, Marko
  2018-03-08 21:53     ` [PATCH v7 0/7] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  23 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-01-11  0:21 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 doc/guides/rel_notes/release_18_02.rst | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/guides/rel_notes/release_18_02.rst b/doc/guides/rel_notes/release_18_02.rst
index 24b67bb..8eafcd3 100644
--- a/doc/guides/rel_notes/release_18_02.rst
+++ b/doc/guides/rel_notes/release_18_02.rst
@@ -41,6 +41,12 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+    * **Added the Event Timer Adapter Library.**
+
+      Added the Event Timer Adapter Library.  This library extends the
+      event-based model by introducing APIs that allow applications to
+      generate timer expiry events that are scheduled by an event device
+      along with existing types of events.
 
 API Changes
 -----------
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 01/23] eventtimer: add event timer adapter API
  2018-01-11  0:20     ` [PATCH v6 01/23] eventtimer: add event timer adapter API Erik Gabriel Carrillo
@ 2018-01-11 11:10       ` Pavan Nikhilesh
  2018-01-11 16:56         ` Carrillo, Erik G
  0 siblings, 1 reply; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-01-11 11:10 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

On Wed, Jan 10, 2018 at 06:20:52PM -0600, Erik Gabriel Carrillo wrote:
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>

Consider giving credit to the original authors.

> ---
>  lib/librte_eventdev/Makefile                  |   1 +
>  lib/librte_eventdev/rte_event_timer_adapter.h | 566 ++++++++++++++++++++++++++
>  lib/librte_eventdev/rte_eventdev.h            |   4 +-
>  3 files changed, 569 insertions(+), 2 deletions(-)
>  create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h
>
> diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
> index 7fd78c7..685b474 100644
> --- a/lib/librte_eventdev/Makefile
> +++ b/lib/librte_eventdev/Makefile
> @@ -27,6 +27,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
>  SYMLINK-y-include += rte_eventdev_pmd_vdev.h
>  SYMLINK-y-include += rte_event_ring.h
>  SYMLINK-y-include += rte_event_eth_rx_adapter.h
> +SYMLINK-y-include += rte_event_timer_adapter.h
>
>  # versioning export map
>  EXPORT_MAP := rte_eventdev_version.map
> diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
> new file mode 100644
> index 0000000..7d967e6
> --- /dev/null
> +++ b/lib/librte_eventdev/rte_event_timer_adapter.h
> @@ -0,0 +1,566 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright 2017 Cavium, Inc.
> + *   Copyright(c) 2017 Intel Corporation. All rights reserved.
> + *
> + *   Redistribution and use in source and binary forms, with or without
> + *   modification, are permitted provided that the following conditions
> + *   are met:
> + *
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above copyright
> + *       notice, this list of conditions and the following disclaimer in
> + *       the documentation and/or other materials provided with the
> + *       distribution.
> + *     * Neither the name of Intel Corporation nor the names of its
> + *       contributors may be used to endorse or promote products derived
> + *       from this software without specific prior written permission.
> + *
> + *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */

Use SPDX licence tags

> +#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
> +#define __RTE_EVENT_TIMER_ADAPTER_H__
> +
> +/**
> + * @file
> + *
> + * RTE Event Timer Adapter
<snip>
> + */
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <rte_spinlock.h>
> +#include <rte_memory.h>
> +
> +#include "rte_eventdev.h"
> +
> +#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 64
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this enum may change without prior notice

Please make sure that Experimental tags usage is inline with the new tool
http://dpdk.org/dev/patchwork/patch/32234.

Cheers,
Pavan

> + *
> + * Timer adapter clock source
> + */
> +enum rte_event_timer_adapter_clk_src {
> +	RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
> +	/**< Use CPU clock as the clock source. */
> +	RTE_EVENT_TIMER_ADAPTER_EXT_CLK0,
> +	/**< Platform dependent external clock source 0. */
> +	RTE_EVENT_TIMER_ADAPTER_EXT_CLK1,
> +	/**< Platform dependent external clock source 1. */
> +	RTE_EVENT_TIMER_ADAPTER_EXT_CLK2,
> +	/**< Platform dependent external clock source 2. */
> +	RTE_EVENT_TIMER_ADAPTER_EXT_CLK3,
> +	/**< Platform dependent external clock source 3. */
> +};
> +
<snip>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 05/23] eventtimer: add adapter allocation definitions
  2018-01-11  0:20     ` [PATCH v6 05/23] eventtimer: add adapter allocation definitions Erik Gabriel Carrillo
@ 2018-01-11 11:18       ` Pavan Nikhilesh
  0 siblings, 0 replies; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-01-11 11:18 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

On Wed, Jan 10, 2018 at 06:20:56PM -0600, Erik Gabriel Carrillo wrote:
> Add definitions for the functions that allocate and deallocate adapter
> instances in the default software implementation.
>
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  lib/Makefile                                  |   2 +-
>  lib/librte_eventdev/Makefile                  |   2 +-
>  lib/librte_eventdev/rte_event_timer_adapter.c | 138 +++++++++++++++++++++++++-
>  lib/librte_eventdev/rte_event_timer_adapter.h |   2 +-
>  4 files changed, 139 insertions(+), 5 deletions(-)
>
> diff --git a/lib/Makefile b/lib/Makefile
> index 4202702..4c53f8c 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -29,7 +29,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf
>  DEPDIRS-librte_security += librte_ether
>  DEPDIRS-librte_security += librte_cryptodev
>  DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
> -DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash
> +DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool
>  DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
>  DEPDIRS-librte_vhost := librte_eal librte_mempool librte_mbuf librte_ether
>  DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
> diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
> index 8f11a79..e68f888 100644
> --- a/lib/librte_eventdev/Makefile
> +++ b/lib/librte_eventdev/Makefile
> @@ -13,7 +13,7 @@ LIBABIVER := 3
>  # build flags
>  CFLAGS += -O3
>  CFLAGS += $(WERROR_FLAGS)
> -LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
> +LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool
>
>  # library source files
>  SRCS-y += rte_eventdev.c
> diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
> index 540be95..9c4ba1c 100644
> --- a/lib/librte_eventdev/rte_event_timer_adapter.c
> +++ b/lib/librte_eventdev/rte_event_timer_adapter.c
> @@ -31,11 +31,17 @@
>   */
>
>  #include <string.h>
> +#include <stdbool.h>
>
>  #include <rte_memzone.h>
>  #include <rte_memory.h>
>  #include <rte_dev.h>
>  #include <rte_errno.h>
> +#include <rte_malloc.h>
> +#include <rte_ring.h>
> +#include <rte_mempool.h>
> +#include <rte_timer.h>
> +#include <rte_service_component.h>
>
>  #include "rte_eventdev.h"
>  #include "rte_eventdev_pmd.h"
> @@ -163,6 +169,11 @@ rte_event_timer_adapter_create_ext(
>
>  	adapter_id = conf->timer_adapter_id;
>
> +	if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) {
> +		rte_errno = -EINVAL;
> +		return NULL;
> +	}
> +
>  	/* Check adapter ID not already allocated */
>  	adapter = &adapters[adapter_id];
>  	if (adapter->allocated) {
> @@ -412,18 +423,141 @@ rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
>   * Software event timer adapter ops definitions
>   */
>
> +struct rte_event_timer_adapter_sw_data {
> +	/* Number of outstanding timers managed by event adapter. */
> +	int nb_armed_evtims;
> +	/* Identifier of service executing timer management logic. */
> +	uint32_t service_id;
> +	/* Ring containing messages to arm or cancel event timers */
> +	struct rte_ring *msg_ring;
> +	/* Mempool containing msg objects */
> +	struct rte_mempool *msg_pool;
> +	/* Mempool containing timer objects */
> +	struct rte_mempool *tim_pool;
> +};

Don't use rte_ prefix for internal data.

> +
> +enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
> +
> +struct msg {
> +	enum msg_type type;
> +	struct rte_event_timer *evtim;
> +};
> +
> +static int
> +sw_event_timer_adapter_service_func(void *arg)
> +{
> +	RTE_SET_USED(arg);
> +	return 0;
> +}
> +
>  static int
>  sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
>  {
> -	RTE_SET_USED(adapter);
> +	int ret;
> +	struct rte_event_timer_adapter_sw_data *sw_data;
> +	uint64_t nb_timers;
<snip>
> +
> +	char pool_name[RTE_RING_NAMESIZE];
> +	snprintf(pool_name, RTE_RING_NAMESIZE, "sw_evtim_adap_msg_pool_%"PRIu8,
> +		 adapter->data->id);
> +	sw_data->msg_pool = rte_mempool_create(pool_name, nb_timers,
> +					       sizeof(struct msg), 32, 0, NULL,
> +					       NULL, NULL, NULL,
> +					       adapter->data->socket_id, 0);
> +	if (sw_data->msg_pool == NULL) {
> +		rte_errno = ENOMEM;
> +		return -1;
> +	}
> +
> +	snprintf(pool_name, RTE_RING_NAMESIZE, "sw_evtim_adap_tim_pool_%"PRIu8,
> +		 adapter->data->id);
> +	sw_data->tim_pool = rte_mempool_create(pool_name, nb_timers,
> +					       sizeof(struct rte_timer), 32, 0,
> +					       NULL, NULL, NULL, NULL,
> +					       adapter->data->socket_id, 0);
> +	if (sw_data->tim_pool == NULL) {
> +		printf("Could not allocate tim mempool\n");
> +		return -1;
> +	}

Any specific reason for having seperate mempool for msg and timers?
You could have a internal structure as a wrapper for both.

> +
> +	/* Register a service component */
> +	memset(&service, 0, sizeof(service));
> +	snprintf(service.name, RTE_SERVICE_NAME_MAX,
> +		 "sw_evimer_adap_svc_%"PRIu8, adapter->data->id);
> +	service.socket_id = adapter->data->socket_id;
> +	service.callback = sw_event_timer_adapter_service_func;
> +	service.callback_userdata = adapter;
> +	ret = rte_service_component_register(&service, &sw_data->service_id);
> +	if (ret < 0)
> +		return ret;
>
>  	return 0;
>  }
>
> -#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 64
> +#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 32

Any specific reason for this change?
maybe make it compile-time configurable

>
>  /**
>   * @warning
> --
> 2.6.4
>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 10/23] eventtimer: remove service id entry from info structure
  2018-01-11  0:21     ` [PATCH v6 10/23] eventtimer: remove service id entry from info structure Erik Gabriel Carrillo
@ 2018-01-11 11:34       ` Pavan Nikhilesh
  0 siblings, 0 replies; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-01-11 11:34 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

On Wed, Jan 10, 2018 at 06:21:01PM -0600, Erik Gabriel Carrillo wrote:
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  lib/librte_eventdev/rte_event_timer_adapter.c | 11 +----------
>  lib/librte_eventdev/rte_event_timer_adapter.h |  2 --
>  2 files changed, 1 insertion(+), 12 deletions(-)
>
> diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
> index 68748be..a4c8012 100644
> --- a/lib/librte_eventdev/rte_event_timer_adapter.c
> +++ b/lib/librte_eventdev/rte_event_timer_adapter.c
> @@ -609,15 +609,6 @@ sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
>  	return rte_service_component_runstate_set(sw_data->service_id, 0);
>  }
>
> -static void
> -sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
> -			struct rte_event_timer_adapter_info *adapter_info)
> -{
> -	struct rte_event_timer_adapter_sw_data *sw_data;
> -	sw_data = adapter->data->adapter_priv;
> -	adapter_info->service_id = sw_data->service_id;
> -}
> -

Removing get_info is not a good idea, the application using event timer might
need some info about capabilities.
Thinking form sw_event_timer perspective I think we need to have a caps to check
if it supports DISTRIBUTED scheduling similar to sw event dev (or) expose
RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT.

>  static int
>  sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
>  			 struct rte_event_timer **evtims,
> @@ -661,7 +652,7 @@ const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
>  	.uninit = sw_event_timer_adapter_uninit,
>  	.start = sw_event_timer_adapter_start,
>  	.stop = sw_event_timer_adapter_stop,
> -	.get_info = sw_event_timer_adapter_get_info,
> +	.get_info = NULL,
>  	.arm_burst = sw_event_timer_arm_burst,
>  	.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
>  	.cancel_burst = sw_event_timer_cancel_burst,
> diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
> index 84d3c39..8d29cfc 100644
> --- a/lib/librte_eventdev/rte_event_timer_adapter.h
> +++ b/lib/librte_eventdev/rte_event_timer_adapter.h
> @@ -283,8 +283,6 @@ struct rte_event_timer_adapter_info {
>  	/**< Event timer adapter capabilities */
>  	int16_t event_dev_port_id;
>  	/**< Event device port ID, if applicable */
> -	int32_t service_id;
> -	/**< Service ID, if applicable */
>  };
>
>  /**
> --
> 2.6.4
>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 12/23] eventtimer: add event timer arm/cancel function definitions
  2018-01-11  0:21     ` [PATCH v6 12/23] eventtimer: add event timer arm/cancel function definitions Erik Gabriel Carrillo
@ 2018-01-11 11:38       ` Pavan Nikhilesh
  0 siblings, 0 replies; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-01-11 11:38 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

On Wed, Jan 10, 2018 at 06:21:03PM -0600, Erik Gabriel Carrillo wrote:
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  lib/Makefile                                  |   2 +-
>  lib/librte_eventdev/Makefile                  |   2 +-
>  lib/librte_eventdev/rte_event_timer_adapter.c | 155 +++++++++++++++++++++++---
>  mk/rte.app.mk                                 |   2 +-
>  4 files changed, 141 insertions(+), 20 deletions(-)
>
> diff --git a/lib/Makefile b/lib/Makefile
> index 4c53f8c..c2bee80 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -29,7 +29,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf
>  DEPDIRS-librte_security += librte_ether
>  DEPDIRS-librte_security += librte_cryptodev
>  DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
> -DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool
> +DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool librte_timer
>  DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
>  DEPDIRS-librte_vhost := librte_eal librte_mempool librte_mbuf librte_ether
>  DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
> diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
> index e68f888..6e95528 100644
> --- a/lib/librte_eventdev/Makefile
> +++ b/lib/librte_eventdev/Makefile
> @@ -13,7 +13,7 @@ LIBABIVER := 3
>  # build flags
>  CFLAGS += -O3
>  CFLAGS += $(WERROR_FLAGS)
> -LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool
> +LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool -lrte_timer
>
>  # library source files
>  SRCS-y += rte_eventdev.c
> diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
> index a4c8012..38e52cb 100644
> --- a/lib/librte_eventdev/rte_event_timer_adapter.c
> +++ b/lib/librte_eventdev/rte_event_timer_adapter.c
> @@ -609,16 +609,91 @@ sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
>  	return rte_service_component_runstate_set(sw_data->service_id, 0);
>  }
>
> +static __rte_always_inline void
> +swap(struct rte_event_timer **evtims, int i, int j)
> +{
> +	struct rte_event_timer *tmp;
> +
> +	tmp = evtims[i];
> +	evtims[i] = evtims[j];
> +	evtims[j] = tmp;
> +}
> +
> +static __rte_always_inline int
> +__sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
> +			   struct rte_event_timer **evtims,
> +			   uint16_t nb_evtims)
> +{
> +	int i, n, mark, nb_fails = 0;
> +	int fails[nb_evtims];
> +	struct rte_event_timer_adapter_sw_data *sw_data;
> +	struct msg *msgs[nb_evtims];
> +	struct rte_timer *tims[nb_evtims];
> +
> +	sw_data = adapter->data->adapter_priv;
> +
> +	n = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
> +	if (n < 0) {
> +		rte_errno = ENOMEM;
> +		return 0;
> +	}
> +
> +	n = rte_mempool_get_bulk(sw_data->tim_pool, (void **)tims, nb_evtims);
> +	if (n < 0) {
> +		rte_errno = ENOMEM;

Need to free msg objs that were dequeued prior (Although this has a very low
chance of happening.)
As mentioned before consider having a single pool.

> +		return 0;
> +	}
> +
> +	for (i = 0; i < nb_evtims; i++) {
> +		rte_timer_init(tims[i]);
> +		evtims[i]->impl_opaque[0] = (uintptr_t)tims[i];
> +		evtims[i]->impl_opaque[1] = (uintptr_t)adapter;
> +
> +		msgs[i]->evtim = evtims[i];
> +		msgs[i]->type = MSG_TYPE_ARM;
> +	}
> +
> +	n = rte_ring_enqueue_burst(sw_data->msg_ring, (void **)msgs, nb_evtims,
> +				   NULL);
> +	if (n < nb_evtims) {
> +		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[n],
> +				     nb_evtims - n);
> +		rte_mempool_put_bulk(sw_data->tim_pool, (void **)&tims[n],
> +				     nb_evtims - n);
> +	}
> +
> +	for (i = 0; i < n; i++) {
> +		/* Wait until state is updated */
> +		while (evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
> +		       evtims[i]->state == RTE_EVENT_TIMER_CANCELED)
> +			;
> +
> +		/* Note any failures */
> +		if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
> +			fails[nb_fails++] = i;
> +			rte_errno = EINVAL;
> +		}
> +
> +		/* TODO: handle the case of consecutive arm requests;  the
> +		 * second request can erroneously see success from the first
> +		 */
> +	}
> +
> +	/* Move the failures to the end of the array */
> +	for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
> +		swap(evtims, fails[i], mark);
> +
> +	n = mark + 1;
> +
> +	return n;
> +}
> +
>  static int
>  sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
>  			 struct rte_event_timer **evtims,
>  			 uint16_t nb_evtims)
>  {
> -	RTE_SET_USED(adapter);
> -	RTE_SET_USED(evtims);
> -	RTE_SET_USED(nb_evtims);
> -
> -	return 0;
> +	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
>  }
>
>  static int
> @@ -626,25 +701,71 @@ sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
>  			    struct rte_event_timer **evtims,
>  			    uint16_t nb_evtims)
>  {
> -	RTE_SET_USED(adapter);
> -	RTE_SET_USED(evtims);
> -	RTE_SET_USED(nb_evtims);
> +	int i, n, mark, nb_fails = 0;
> +	int fails[nb_evtims];
> +	struct msg *msg, *msgs[nb_evtims];
> +	struct rte_event_timer_adapter_sw_data *sw_data;
>
> -	return 0;
> +#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
> +	/* TODO: verify that service is running to avoid hanging if in block
> +	 * mode
> +	 */
> +#endif
> +
> +	sw_data = adapter->data->adapter_priv;
> +
> +	n = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
> +	if (n < 0) {
> +		rte_errno = ENOMEM;
> +		return 0;
> +	}
> +
> +	/* Set up the messages */
> +	for (i = 0; i < nb_evtims; i++) {
> +		msg = msgs[i];
> +		msg->type = MSG_TYPE_CANCEL;
> +		msg->evtim = evtims[i];
> +	}
> +
> +	n = rte_ring_enqueue_burst(sw_data->msg_ring, (void **)msgs, nb_evtims,
> +				   NULL);
> +	if (n < nb_evtims)
> +		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[n],
> +				     nb_evtims - n);
> +
> +	for (i = 0; i < n; i++) {
> +		/* Wait until state is updated */
> +		while (evtims[i]->state == RTE_EVENT_TIMER_ARMED)
> +			;
> +
> +		/* Note any failures */
> +		if (evtims[i]->state != RTE_EVENT_TIMER_CANCELED) {
> +			fails[nb_fails++] = i;
> +			rte_errno = EINVAL;
> +		}
> +	}
> +
> +	/* Move the failures to the end of the array */
> +	for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
> +		swap(evtims, fails[i], mark);
> +
> +	n = mark + 1;
> +
> +	return n;
>  }
>
>  static int
>  sw_event_timer_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter,
> -				  struct rte_event_timer **tims,
> -				  uint64_t timeout_tick,
> -				  uint16_t nb_tims)
> +				  struct rte_event_timer **evtims,
> +				  uint64_t timeout_ticks,
> +				  uint16_t nb_evtims)
>  {
> -	RTE_SET_USED(adapter);
> -	RTE_SET_USED(tims);
> -	RTE_SET_USED(timeout_tick);
> -	RTE_SET_USED(nb_tims);
> +	int i;
>
> -	return 0;
> +	for (i = 0; i < nb_evtims; i++)
> +		evtims[i]->timeout_ticks = timeout_ticks;
> +
> +	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
>  }
>
>  const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index 6a6a745..3dd95f5 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)        += -lrte_bitratestats
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
>
> -_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
>
>  _LDLIBS-y += --whole-archive
> @@ -96,6 +95,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lrte_ethdev
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)       += -lrte_security
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
>  _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
> --
> 2.6.4
>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 13/23] eventtimer: add adapter service definition
  2018-01-11  0:21     ` [PATCH v6 13/23] eventtimer: add adapter service definition Erik Gabriel Carrillo
@ 2018-01-11 12:03       ` Pavan Nikhilesh
  0 siblings, 0 replies; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-01-11 12:03 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

On Wed, Jan 10, 2018 at 06:21:04PM -0600, Erik Gabriel Carrillo wrote:
> Define the callback function for the service that corresponds to an
> adapter instance, as well as the callback for expired timers that the
> service manages.
>
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  lib/librte_eventdev/rte_event_timer_adapter.c | 198 +++++++++++++++++++++++++-
>  lib/librte_eventdev/rte_event_timer_adapter.h |   2 +-
>  2 files changed, 198 insertions(+), 2 deletions(-)
>
> diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
> index 38e52cb..0266ad5 100644
> --- a/lib/librte_eventdev/rte_event_timer_adapter.c
> +++ b/lib/librte_eventdev/rte_event_timer_adapter.c
> @@ -40,8 +40,10 @@
>  #include <rte_malloc.h>
>  #include <rte_ring.h>
>  #include <rte_mempool.h>
> +#include <rte_common.h>
>  #include <rte_timer.h>
>  #include <rte_service_component.h>
> +#include <rte_cycles.h>
>
>  #include "rte_eventdev.h"
>  #include "rte_eventdev_pmd.h"
> @@ -460,10 +462,198 @@ struct msg {
>  	struct rte_event_timer *evtim;
>  };
<snip>
> +	if (n != 1 && rte_errno == -ENOSPC) {
> +		/* If we couldn't enqueue because the event port was
> +		 * backpressured, put the timer back in the skiplist with an
> +		 * immediate expiry value so we can process it again on the
> +		 * next iteration.
> +		 */
> +		rte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),
> +				     sw_event_timer_cb, evtim);
> +	} else {
> +		sw_data->nb_armed_evtims--;
> +		rte_wmb();

Any reason for using barrier here?. IMO smp_wmb() would be more than sufficient
or use atomics.

> +		evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
> +		rte_mempool_put(sw_data->tim_pool, (void **)&tim);
> +	}
> +}
> +
> +static __rte_always_inline uint64_t
> +get_timeout_cycles(struct rte_event_timer *evtim,
> +		   struct rte_event_timer_adapter *adapter)
> +{
> +	uint64_t timeout_ns;
> +
> +	timeout_ns = evtim->timeout_ticks * adapter->data->conf.timer_tick_ns;
> +#define NSECPERSEC 1E9
> +	return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
> +
> +}
> +
> +/* Check that event timer timeout value is in range */
> +static __rte_always_inline int
> +check_timeout(struct rte_event_timer *evtim,
> +	      const struct rte_event_timer_adapter *adapter)
> +{
> +	uint64_t tmo_nsec = evtim->timeout_ticks *
> +		adapter->data->conf.timer_tick_ns;
> +
> +	return  (tmo_nsec > adapter->data->conf.max_tmo_ns) ? -1
> +		: (tmo_nsec < adapter->data->conf.timer_tick_ns) ? -2
> +		: 0;

Consider simplifying this for readability.

> +}
> +
> +/* Check that event timer event queue sched type matches destination event queue
> + * sched type
> + */
> +static __rte_always_inline int
> +check_destination_event_queue(struct rte_event_timer *evtim,
> +			      const struct rte_event_timer_adapter *adapter)

<snip>
> +
> +#define NB_OBJS 32
>  static int
>  sw_event_timer_adapter_service_func(void *arg)
>  {
> -	RTE_SET_USED(arg);
> +	int i, num_msgs, ret;
> +	uint64_t cycles;
> +	uint16_t nb_events;
> +	struct rte_event_timer_adapter *adapter;
> +	struct rte_event_timer_adapter_sw_data *sw_data;
> +	struct rte_event_timer *evtim = NULL;
> +	struct rte_timer *tim = NULL;
> +	struct msg *msg, *msgs[NB_OBJS];
> +
> +	adapter = arg;
> +	sw_data = adapter->data->adapter_priv;
> +
> +	while (!rte_ring_empty(sw_data->msg_ring)) {
> +		num_msgs = rte_ring_dequeue_burst(sw_data->msg_ring,
> +						  (void **)msgs, NB_OBJS, NULL);
> +
> +		for (i = 0; i < num_msgs; i++) {
> +			msg = msgs[i];
> +			evtim = msg->evtim;
> +
> +			tim = (struct rte_timer *)evtim->impl_opaque[0];
> +			RTE_ASSERT(tim != NULL);
> +
> +			switch (msg->type) {
> +			case MSG_TYPE_ARM:
> +				if (validate_event_timer(evtim, adapter) < 0) {
> +					rte_mempool_put(sw_data->tim_pool,
> +							(void **)&tim);
> +					continue;
> +				}
> +
> +				/* Checks passed; set an rte_timer */
> +				cycles = get_timeout_cycles(msg->evtim,
> +							    adapter);
> +				rte_timer_reset_sync(tim, cycles, SINGLE,
> +						     rte_lcore_id(),
> +						     sw_event_timer_cb,
> +						     msg->evtim);
> +
> +				sw_data->nb_armed_evtims++;
> +				rte_wmb();

Same as above comment.

> +				evtim->state = RTE_EVENT_TIMER_ARMED;
> +				break;
> +			case MSG_TYPE_CANCEL:
> +				/* The event timer was either not armed or it
> +				 * fired after this cancel request was queued
> +				 * and before the request was processed.
> +				 */
> +				if (evtim->state != RTE_EVENT_TIMER_ARMED)
> +					continue;
> +
> +				rte_timer_stop_sync(tim);
> +				rte_mempool_put(sw_data->tim_pool,
> +						(void **)&tim);
> +				sw_data->nb_armed_evtims--;
> +				rte_wmb();

Same as above comment.

> +				msg->evtim->state = RTE_EVENT_TIMER_CANCELED;
> +				break;
> +			}
> +		}
> +
> +		rte_mempool_put_bulk(sw_data->msg_pool, (void **)msgs,
> +				     num_msgs);
> +	}
> +
> +	rte_timer_manage();

Consider calling rte_timer_manage() before ARM new set of timers also, poll it
based on the timeout interval configured.

> +
> +	/* Could use for stats */
> +	RTE_SET_USED(nb_events);
> +	RTE_SET_USED(ret);
> +
>  	return 0;
>  }
>
<snip>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 15/23] eventtimer: add buffering of timer expiry events
  2018-01-11  0:21     ` [PATCH v6 15/23] eventtimer: add buffering of timer expiry events Erik Gabriel Carrillo
@ 2018-01-11 12:18       ` Pavan Nikhilesh
  2018-01-18 23:07         ` Carrillo, Erik G
  0 siblings, 1 reply; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-01-11 12:18 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

On Wed, Jan 10, 2018 at 06:21:06PM -0600, Erik Gabriel Carrillo wrote:
> Buffer timer expiry events generated while walking a "run list"
> in rte_timer_manage, and burst enqueue them to an event device
> to the extent possible.
>

IMO in some cases this adds a lot of delay between expiries and events being
published to event dev. For example, having long expiry interval (default 300
seconds for mac expiry) the expired entries would remain in the buffer till 32
other entries expire.


> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  lib/librte_eventdev/rte_event_timer_adapter.c | 118 +++++++++++++++++++++++---
>  1 file changed, 108 insertions(+), 10 deletions(-)
>
<snip>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 19/23] test: exercise event timer arm and expiry
  2018-01-11  0:21     ` [PATCH v6 19/23] test: exercise event timer arm and expiry Erik Gabriel Carrillo
@ 2018-01-11 12:26       ` Pavan Nikhilesh
  0 siblings, 0 replies; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-01-11 12:26 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

On Wed, Jan 10, 2018 at 06:21:10PM -0600, Erik Gabriel Carrillo wrote:
> Add a test that creates an event timer and detects the generation of a
> timer expiry event being scheduled through the software event device.
>
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  test/test/test_event_timer_adapter.c | 106 +++++++++++++++++++++++++++++++++++
>  1 file changed, 106 insertions(+)
>

Please consider following common_code -> sw_dev -> test -> doc so that it would
be easy to review. Some patches could be squashed into one.

<snip>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 22/23] doc: add event timer adapter section to programmer's guide
  2018-01-11  0:21     ` [PATCH v6 22/23] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
@ 2018-01-11 15:26       ` Kovacevic, Marko
  0 siblings, 0 replies; 133+ messages in thread
From: Kovacevic, Marko @ 2018-01-11 15:26 UTC (permalink / raw)
  To: Carrillo, Erik G, pbhagavatula, dev
  Cc: jerin.jacob, nipun.gupta, hemant.agrawal

> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  doc/guides/prog_guide/event_timer_adapter.rst | 301
> ++++++++++++++++++++++++++
>  doc/guides/prog_guide/index.rst               |   1 +
>  2 files changed, 302 insertions(+)
>  create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst

<...> 

Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 01/23] eventtimer: add event timer adapter API
  2018-01-11 11:10       ` Pavan Nikhilesh
@ 2018-01-11 16:56         ` Carrillo, Erik G
  2018-01-11 17:31           ` Pavan Nikhilesh
  0 siblings, 1 reply; 133+ messages in thread
From: Carrillo, Erik G @ 2018-01-11 16:56 UTC (permalink / raw)
  To: Pavan Nikhilesh; +Cc: dev


> -----Original Message-----
> From: Pavan Nikhilesh [mailto:pbhagavatula@caviumnetworks.com]
> Sent: Thursday, January 11, 2018 5:11 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>;
> jerin.jacob@caviumnetworks.com; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: dev@dpdk.org
> Subject: Re: [PATCH v6 01/23] eventtimer: add event timer adapter API
> 
> On Wed, Jan 10, 2018 at 06:20:52PM -0600, Erik Gabriel Carrillo wrote:
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> 
> Consider giving credit to the original authors.
> 

Hi Pavan,

Sorry about that!  The additional Signed-off lines must have been dropped when I amended the commit without my noticing.  I'll certainly add them back in.  Thanks for the other good comments;  I'll go through them in the next few days.

Regards,
Gabriel

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 08/23] eventtimer: add adapter start/stop definitions
  2018-01-11  0:20     ` [PATCH v6 08/23] eventtimer: add adapter start/stop definitions Erik Gabriel Carrillo
@ 2018-01-11 17:28       ` Pavan Nikhilesh
  2018-01-18 23:57         ` Carrillo, Erik G
  0 siblings, 1 reply; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-01-11 17:28 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

On Wed, Jan 10, 2018 at 06:20:59PM -0600, Erik Gabriel Carrillo wrote:
> Add definitions to the default software implementation for the functions
> that start and stop adapter instances.
>
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  lib/librte_eventdev/rte_event_timer_adapter.c | 19 +++++++++++++++----
>  1 file changed, 15 insertions(+), 4 deletions(-)
>
> diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
> index 38f4dcf..27e6226 100644
> --- a/lib/librte_eventdev/rte_event_timer_adapter.c
> +++ b/lib/librte_eventdev/rte_event_timer_adapter.c
> @@ -565,7 +565,18 @@ sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)
>  static int
>  sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
>  {
> -	RTE_SET_USED(adapter);
> +	int ret;
> +	struct rte_event_timer_adapter_sw_data *sw_data;
> +
> +	sw_data = adapter->data->adapter_priv;
> +
> +	ret = rte_service_component_runstate_set(sw_data->service_id, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* If no service core is mapped to the service, fail */
> +	if (!rte_service_runstate_get(sw_data->service_id))
> +		return -ENOENT;

If a service is mapped to more than one service core then the service is
executed in parallel if it is multi thread safe else every core takes a lock
and executes the service callback.

Now in case of timer adapter the following piece of code arms the timer on
the service core that currently runs the service.
	rte_timer_reset_sync(tim, cycles, SINGLE,
				     rte_lcore_id(),
				     sw_event_timer_cb,
				     msg->evtim);
This might lead to delay in timer expiry being called as rte_timer_manage() has
to be scheduled on the same service core again.

The immediate solution that comes to my mind is to limit the number of service
cores mapped to 1.

Thoughts?

Cheers,
Pavan.

>
>  	return 0;
>  }
> @@ -573,9 +584,9 @@ sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
>  static int
>  sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
>  {
> -	RTE_SET_USED(adapter);
> -
> -	return 0;
> +	struct rte_event_timer_adapter_sw_data *sw_data;
> +	sw_data = adapter->data->adapter_priv;
> +	return rte_service_component_runstate_set(sw_data->service_id, 0);
>  }
>
>  static void
> --
> 2.6.4
>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 01/23] eventtimer: add event timer adapter API
  2018-01-11 16:56         ` Carrillo, Erik G
@ 2018-01-11 17:31           ` Pavan Nikhilesh
  0 siblings, 0 replies; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-01-11 17:31 UTC (permalink / raw)
  To: Carrillo, Erik G; +Cc: dev

On Thu, Jan 11, 2018 at 04:56:40PM +0000, Carrillo, Erik G wrote:
>
> > -----Original Message-----
> > From: Pavan Nikhilesh [mailto:pbhagavatula@caviumnetworks.com]
> > Sent: Thursday, January 11, 2018 5:11 AM
> > To: Carrillo, Erik G <erik.g.carrillo@intel.com>;
> > jerin.jacob@caviumnetworks.com; nipun.gupta@nxp.com;
> > hemant.agrawal@nxp.com
> > Cc: dev@dpdk.org
> > Subject: Re: [PATCH v6 01/23] eventtimer: add event timer adapter API
> >
> > On Wed, Jan 10, 2018 at 06:20:52PM -0600, Erik Gabriel Carrillo wrote:
> > > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> >
> > Consider giving credit to the original authors.
> >
>
> Hi Pavan,
>
> Sorry about that!  The additional Signed-off lines must have been dropped when I amended the commit without my noticing.  I'll certainly add them back in.  Thanks for the other good comments;  I'll go through them in the next few days.

No problem! just a reminder.

>
> Regards,
> Gabriel

Thanks,
Pavan.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 23/23] doc: add event timer adapter to release notes
  2018-01-11  0:21     ` [PATCH v6 23/23] doc: add event timer adapter to release notes Erik Gabriel Carrillo
@ 2018-01-12 10:48       ` Kovacevic, Marko
  0 siblings, 0 replies; 133+ messages in thread
From: Kovacevic, Marko @ 2018-01-12 10:48 UTC (permalink / raw)
  To: Carrillo, Erik G, pbhagavatula
  Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
>  doc/guides/rel_notes/release_18_02.rst | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/doc/guides/rel_notes/release_18_02.rst
> b/doc/guides/rel_notes/release_18_02.rst
> index 24b67bb..8eafcd3 100644
> --- a/doc/guides/rel_notes/release_18_02.rst
> +++ b/doc/guides/rel_notes/release_18_02.rst

Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 21/23] doc: add event timer adapter to API index
  2018-01-11  0:21     ` [PATCH v6 21/23] doc: add event timer adapter to API index Erik Gabriel Carrillo
@ 2018-01-12 11:12       ` Kovacevic, Marko
  0 siblings, 0 replies; 133+ messages in thread
From: Kovacevic, Marko @ 2018-01-12 11:12 UTC (permalink / raw)
  To: Carrillo, Erik G, pbhagavatula, dev
  Cc: jerin.jacob, nipun.gupta, hemant.agrawal


> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>


>  doc/api/doxy-api-index.md | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index
> 3492702..3110658 100644
> --- a/doc/api/doxy-api-index.md
> +++ b/doc/api/doxy-api-index.md

Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 15/23] eventtimer: add buffering of timer expiry events
  2018-01-11 12:18       ` Pavan Nikhilesh
@ 2018-01-18 23:07         ` Carrillo, Erik G
  2018-01-20  8:55           ` Pavan Nikhilesh
  0 siblings, 1 reply; 133+ messages in thread
From: Carrillo, Erik G @ 2018-01-18 23:07 UTC (permalink / raw)
  To: Pavan Nikhilesh, jerin.jacob; +Cc: dev

> -----Original Message-----
> From: Pavan Nikhilesh [mailto:pbhagavatula@caviumnetworks.com]
> Sent: Thursday, January 11, 2018 6:19 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>;
> jerin.jacob@caviumnetworks.com; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: dev@dpdk.org
> Subject: Re: [PATCH v6 15/23] eventtimer: add buffering of timer expiry
> events
> 
> On Wed, Jan 10, 2018 at 06:21:06PM -0600, Erik Gabriel Carrillo wrote:
> > Buffer timer expiry events generated while walking a "run list"
> > in rte_timer_manage, and burst enqueue them to an event device to the
> > extent possible.
> >
> 
> IMO in some cases this adds a lot of delay between expiries and events being
> published to event dev. For example, having long expiry interval (default 300
> seconds for mac expiry) the expired entries would remain in the buffer till 32
> other entries expire.
> 

The service function invokes rte_timer_manage to handle expired timers, and as it does so, the buffer will be flushed under two conditions:  the buffer is full of expired timer events, or the buffer is not full but there are no more expired timers to handle for this iteration of the service.  The latter condition will flush the buffer even if only one event has been buffered after walking the list of expired rte_timers.  

So, there could be some delay for the events that got buffered earliest, but it seems like the throughput benefit outweighs the small delay there.  Thoughts?

We could also make the buffer size configurable.  

> 
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > ---
> >  lib/librte_eventdev/rte_event_timer_adapter.c | 118
> > +++++++++++++++++++++++---
> >  1 file changed, 108 insertions(+), 10 deletions(-)
> >
> <snip>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 08/23] eventtimer: add adapter start/stop definitions
  2018-01-11 17:28       ` Pavan Nikhilesh
@ 2018-01-18 23:57         ` Carrillo, Erik G
  0 siblings, 0 replies; 133+ messages in thread
From: Carrillo, Erik G @ 2018-01-18 23:57 UTC (permalink / raw)
  To: Pavan Nikhilesh, jerin.jacob; +Cc: dev



> -----Original Message-----
> From: Pavan Nikhilesh [mailto:pbhagavatula@caviumnetworks.com]
> Sent: Thursday, January 11, 2018 11:29 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>;
> jerin.jacob@caviumnetworks.com; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: dev@dpdk.org
> Subject: Re: [PATCH v6 08/23] eventtimer: add adapter start/stop definitions
> 
> On Wed, Jan 10, 2018 at 06:20:59PM -0600, Erik Gabriel Carrillo wrote:
> > Add definitions to the default software implementation for the
> > functions that start and stop adapter instances.
> >
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > ---
> >  lib/librte_eventdev/rte_event_timer_adapter.c | 19
> > +++++++++++++++----
> >  1 file changed, 15 insertions(+), 4 deletions(-)
> >
> > diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c
> > b/lib/librte_eventdev/rte_event_timer_adapter.c
> > index 38f4dcf..27e6226 100644
> > --- a/lib/librte_eventdev/rte_event_timer_adapter.c
> > +++ b/lib/librte_eventdev/rte_event_timer_adapter.c
> > @@ -565,7 +565,18 @@ sw_event_timer_adapter_uninit(struct
> > rte_event_timer_adapter *adapter)  static int
> > sw_event_timer_adapter_start(const struct rte_event_timer_adapter
> > *adapter)  {
> > -	RTE_SET_USED(adapter);
> > +	int ret;
> > +	struct rte_event_timer_adapter_sw_data *sw_data;
> > +
> > +	sw_data = adapter->data->adapter_priv;
> > +
> > +	ret = rte_service_component_runstate_set(sw_data->service_id, 1);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	/* If no service core is mapped to the service, fail */
> > +	if (!rte_service_runstate_get(sw_data->service_id))
> > +		return -ENOENT;
> 
> If a service is mapped to more than one service core then the service is
> executed in parallel if it is multi thread safe else every core takes a lock and
> executes the service callback.
> 
> Now in case of timer adapter the following piece of code arms the timer on
> the service core that currently runs the service.
> 	rte_timer_reset_sync(tim, cycles, SINGLE,
> 				     rte_lcore_id(),
> 				     sw_event_timer_cb,
> 				     msg->evtim);
> This might lead to delay in timer expiry being called as rte_timer_manage()
> has to be scheduled on the same service core again.
> 
> The immediate solution that comes to my mind is to limit the number of
> service cores mapped to 1.
> 
> Thoughts?

Yes, good catch.  This service is not MT-safe and if it gets mapped to multiple lcores,  each such lcore will be unable to run the service function while other cores are running it, which would introduce delays unnecessarily since rte_timer_manage gets called less frequently.   I agree that the number of mapped service cores should be limited to 1 while the service is MT-unsafe.  If we do that, we can also put the message ring into single-consumer mode.

In a future change, I can also look at making the service MT-safe.

> 
> Cheers,
> Pavan.
> 
> >
> >  	return 0;
> >  }
> > @@ -573,9 +584,9 @@ sw_event_timer_adapter_start(const struct
> > rte_event_timer_adapter *adapter)  static int
> > sw_event_timer_adapter_stop(const struct rte_event_timer_adapter
> > *adapter)  {
> > -	RTE_SET_USED(adapter);
> > -
> > -	return 0;
> > +	struct rte_event_timer_adapter_sw_data *sw_data;
> > +	sw_data = adapter->data->adapter_priv;
> > +	return rte_service_component_runstate_set(sw_data->service_id,
> 0);
> >  }
> >
> >  static void
> > --
> > 2.6.4
> >

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v6 15/23] eventtimer: add buffering of timer expiry events
  2018-01-18 23:07         ` Carrillo, Erik G
@ 2018-01-20  8:55           ` Pavan Nikhilesh
  0 siblings, 0 replies; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-01-20  8:55 UTC (permalink / raw)
  To: Carrillo, Erik G, jerin.jacob; +Cc: dev

On Thu, Jan 18, 2018 at 11:07:52PM +0000, Carrillo, Erik G wrote:
> > -----Original Message-----
> > From: Pavan Nikhilesh [mailto:pbhagavatula@caviumnetworks.com]
> > Sent: Thursday, January 11, 2018 6:19 AM
> > To: Carrillo, Erik G <erik.g.carrillo@intel.com>;
> > jerin.jacob@caviumnetworks.com; nipun.gupta@nxp.com;
> > hemant.agrawal@nxp.com
> > Cc: dev@dpdk.org
> > Subject: Re: [PATCH v6 15/23] eventtimer: add buffering of timer expiry
> > events
> >
> > On Wed, Jan 10, 2018 at 06:21:06PM -0600, Erik Gabriel Carrillo wrote:
> > > Buffer timer expiry events generated while walking a "run list"
> > > in rte_timer_manage, and burst enqueue them to an event device to the
> > > extent possible.
> > >
> >
> > IMO in some cases this adds a lot of delay between expiries and events being
> > published to event dev. For example, having long expiry interval (default 300
> > seconds for mac expiry) the expired entries would remain in the buffer till 32
> > other entries expire.
> >
>
> The service function invokes rte_timer_manage to handle expired timers, and as it does so, the buffer will be flushed under two conditions:  the buffer is full of expired timer events, or the buffer is not full but there are no more expired timers to handle for this iteration of the service.  The latter condition will flush the buffer even if only one event has been buffered after walking the list of expired rte_timers.

Ah, I missed the flush call after timer_manage().

>
> So, there could be some delay for the events that got buffered earliest, but it seems like the throughput benefit outweighs the small delay there.  Thoughts?
>
> We could also make the buffer size configurable.

Maybe make it compile time configurable i.e. in config/common_base.

>
> >
> > > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > > ---
> > >  lib/librte_eventdev/rte_event_timer_adapter.c | 118
> > > +++++++++++++++++++++++---
> > >  1 file changed, 108 insertions(+), 10 deletions(-)
> > >
> > <snip>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v7 0/7] eventtimer: introduce event timer adapter
  2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                       ` (22 preceding siblings ...)
  2018-01-11  0:21     ` [PATCH v6 23/23] doc: add event timer adapter to release notes Erik Gabriel Carrillo
@ 2018-03-08 21:53     ` Erik Gabriel Carrillo
  2018-03-08 21:54       ` [PATCH v7 1/7] eventtimer: add event timer adapter API Erik Gabriel Carrillo
                         ` (7 more replies)
  23 siblings, 8 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-08 21:53 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

This patch series contains the next iteration of the Event Timer Adapter
library, which abstracts timer mechanisms that are tightly coupled with event
devices, and extends the event based programming model so that timer
expirations are represented as an event.

v7
- Addressed comments on previous patch series from Pavan:
  - Use SPDX license tags
  - Squash various commits to make series easier to review
  - Tag experimental functions as such
  - Use one mempool for messages and timers in sw driver 
  - Limit service cores mapped to sw driver's service to one
  - Use smp memory barriers
  - In service function, invoke rte_timer_manage() with frequency matching the
    resolution the adapter was configured with
- Reworked synchronization in sw driver between threads producing messages
  and service thread that consumes them.  The new approach avoids a situation
  where event timers couldn't be armed/canceled from the same lcore the service
  was running on.
- Updated logging facility
- Added more unit tests
- Added support for meson build

v6
- Addressed comments on previous version from Jerin:
  - Added RTE_EVENT_TIMER_CANCELED event timer state back in
  - remove check for started adapter in timer arm/cancel functions 
  - reuse CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG instead of adding new config option
- Added initial version of software driver implementation
- Added stats APIs
- Added API to retrieve adapter service ID
- Added API to initialize event timer
- Added entry to Programmer's Guide in documentation
- Added new unit tests to auto-test

v5
- Addressed comments on previous version from Pavan:
  - renamed rte_event_timer_adapter_driver.h to rte_event_timer_adapter_pmd.h
  - moved contents of sw_event_timer_adapter.c into rte_event_timer_adapter.c
  - added flags parameter to timer_adapter_caps_get() call
  - added DEBUG config variable to conditionally compile run-time checks on
    datapath
  - fixed license text and file description
- Also added a config variable to enable/disable compilation of event timer
  adapter - feedback on whether this is desirable is appreciated

v4
- Split changes into multiple patches for easier review

v3
- Reworked allocation and ops organization in common code based on feedback
  received from Jerin and Pavan. This will allow fast-path function pointers to 
  be dereferenced with one level of indirection with pointers valid in primary
  and secondary processes.
- Moved default software implementation from sw_evdev directory to eventdev
  library directory, which will allow it to be used by any eventdev PMD as an
  alternative to providing its own definitions.
- Reverted occurrences of id back to pointer to adapter struct in library API
- Added rte_event_timer_adapter_lookup() function back in

v2
- Added ops structure and stubbed out plugin for SW impl
- Added unit test stubs
- Replaced occurrences of "wheel" in API with "adapter"
- Replaced occurrences of pointer to struct rte_event_timer_adapter with ids
- Removed rte_event_timer_adapter_lookup() function
- Replaced RTE_EVENT_TIMER_SUCCESS_{ARM,CANCEL} states with
  RTE_EVENT_TIMER_ARMED

Erik Gabriel Carrillo (7):
  eventtimer: add event timer adapter API
  eventtimer: add common code
  eventtimer: add default software driver
  eventtimer: add support for meson build system
  test: add event timer adapter auto-test
  doc: add event timer adapter section to programmer's guide
  doc: add event timer adapter documentation

 MAINTAINERS                                       |    7 +
 config/common_base                                |    1 +
 config/rte_config.h                               |    1 +
 doc/api/doxy-api-index.md                         |   32 +-
 doc/guides/prog_guide/event_timer_adapter.rst     |  277 +++++
 doc/guides/prog_guide/index.rst                   |    1 +
 doc/guides/rel_notes/release_18_05.rst            |    5 +
 drivers/event/sw/sw_evdev.c                       |   18 +
 lib/Makefile                                      |    2 +-
 lib/librte_eventdev/Makefile                      |    5 +-
 lib/librte_eventdev/meson.build                   |    9 +-
 lib/librte_eventdev/rte_event_timer_adapter.c     | 1333 +++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h     |  700 +++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h |  150 +++
 lib/librte_eventdev/rte_eventdev.h                |   44 +-
 lib/librte_eventdev/rte_eventdev_pmd.h            |   35 +
 lib/librte_eventdev/rte_eventdev_version.map      |   20 +
 lib/meson.build                                   |    3 +-
 mk/rte.app.mk                                     |    2 +-
 test/test/Makefile                                |    1 +
 test/test/test_event_timer_adapter.c              | 1234 +++++++++++++++++++
 21 files changed, 3810 insertions(+), 70 deletions(-)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h
 create mode 100644 test/test/test_event_timer_adapter.c

-- 
2.6.4

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v7 1/7] eventtimer: add event timer adapter API
  2018-03-08 21:53     ` [PATCH v7 0/7] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
@ 2018-03-08 21:54       ` Erik Gabriel Carrillo
  2018-03-12  7:53         ` Jerin Jacob
  2018-03-08 21:54       ` [PATCH v7 2/7] eventtimer: add common code Erik Gabriel Carrillo
                         ` (6 subsequent siblings)
  7 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-08 21:54 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/Makefile                  |   1 +
 lib/librte_eventdev/rte_event_timer_adapter.h | 645 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_eventdev.h            |  41 +-
 3 files changed, 653 insertions(+), 34 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h

diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index d27dd07..549b182 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -28,6 +28,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
new file mode 100644
index 0000000..1c8a45b
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -0,0 +1,645 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc.
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ * @file
+ *
+ * RTE Event Timer Adapter
+ *
+ * An event timer adapter has the following abstract working model:
+ *
+ *                               timer_tick_ns
+ *                                   +
+ *                      +-------+    |
+ *                      |       |    |
+ *              +-------+ bkt 0 +----v---+
+ *              |       |       |        |
+ *              |       +-------+        |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *          |       |                |       |  |   |   |   |   |
+ *          | bkt n |                | bkt 1 |<-> t0| t1| t2| tn|
+ *          |       |                |       |  |   |   |   |   |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *              |     Timer adapter      |
+ *          +---+---+                +---+---+
+ *          |       |                |       |
+ *          | bkt 4 |                | bkt 2 |<--- Current bucket
+ *          |       |                |       |
+ *          +---+---+                +---+---+
+ *               |      +-------+       |
+ *               |      |       |       |
+ *               +------+ bkt 3 +-------+
+ *                      |       |
+ *                      +-------+
+ *
+ * - It has a virtual monotonically increasing 64-bit timer adapter clock based
+ *   on *enum rte_event_timer_adapter_clk_src* clock source. The clock source
+ *   could be a CPU clock, or a platform dependent external clock.
+ *
+ * - The application creates a timer adapter instance with given the clock
+ *   source, the total number of event timers, and a resolution(expressed in ns)
+ *   to traverse between the buckets.
+ *
+ * - Each timer adapter may have 0 to n buckets based on the configured
+ *   max timeout(max_tmo_ns) and resolution(timer_tick_ns). Upon starting the
+ *   timer adapter, the adapter starts ticking at *timer_tick_ns* resolution.
+ *
+ * - The application arms an event timer that will expire *timer_tick_ns*
+ *   from now.
+ *
+ * - The application can cancel an armed timer and no timer expiry event will be
+ *   generated.
+ *
+ * - If a timer expires then the library injects the timer expiry event in
+ *   the designated event queue.
+ *
+ * - The timer expiry event will be received through *rte_event_dequeue_burst*.
+ *
+ * - The application frees the timer adapter instance.
+ *
+ * Multiple timer adapters can be created with a varying level of resolution
+ * for various expiry use cases that run in parallel.
+ *
+ * Before using the timer adapter, the application has to create and configure
+ * an event device along with the event port. Based on the event device
+ * capability it might require creating an additional event port to be used
+ * by the timer adapter.
+ *
+ * The application creates the event timer adapter using the
+ * ``rte_event_timer_adapter_create()``. The event device id is passed to this
+ * function, inside this function the event device capability is checked,
+ * and if an in-built port is absent the application uses the default
+ * function to create a new producer port.
+ *
+ * The application may also use the function
+ * ``rte_event_timer_adapter_create_ext()`` to have granular control over
+ * producer port creation in a case where the in-built port is absent.
+ *
+ * After creating the timer adapter, the application has to start it
+ * using ``rte_event_timer_adapter_start()``. The buckets are traversed from
+ * 0 to n; when the adapter ticks, the next bucket is visited. Each time,
+ * the list per bucket is processed, and timer expiry events are sent to the
+ * designated event queue.
+ *
+ * The application can arm one or more event timers using the
+ * ``rte_event_timer_arm_burst()``. The *timeout_ticks* represents the number
+ * of *timer_tick_ns* after which the timer has to expire. The timeout at
+ * which the timers expire can be grouped or be independent of each
+ * event timer instance. ``rte_event_timer_arm_tmo_tick_burst()`` addresses the
+ * former case and ``rte_event_timer_arm_burst()`` addresses the latter case.
+ *
+ * The application can cancel the timers from expiring using the
+ * ``rte_event_timer_cancel_burst()``.
+ *
+ * On the secondary process, ``rte_event_timer_adapter_lookup()`` can be used
+ * to get the timer adapter pointer from its id and use it to invoke fastpath
+ * operations such as arm and cancel.
+ *
+ * Some of the use cases of event timer adapter are Beacon Timers,
+ * Generic SW Timeout, Wireless MAC Scheduling, 3G Frame Protocols,
+ * Packet Scheduling, Protocol Retransmission Timers, Supervision Timers.
+ * All these use cases require high resolution and low time drift.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_spinlock.h>
+#include <rte_memory.h>
+
+#include "rte_eventdev.h"
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this enum may change without prior notice
+ *
+ * Timer adapter clock source
+ */
+enum rte_event_timer_adapter_clk_src {
+	RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+	/**< Use CPU clock as the clock source. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK0,
+	/**< Platform dependent external clock source 0. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK1,
+	/**< Platform dependent external clock source 1. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK2,
+	/**< Platform dependent external clock source 2. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK3,
+	/**< Platform dependent external clock source 3. */
+};
+
+#define RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES	(1ULL << 0)
+/**< The event timer adapter implementation may have constraints on the
+ * resolution (timer_tick_ns) and maximum timer expiry timeout(max_tmo_ns)
+ * based on the given timer adapter or system.  If this flag is set, the
+ * implementation adjusts the resolution and maximum timeout to the best
+ * possible configuration. On successful timer adapter creation, the
+ * application can get the configured resolution and max timeout with
+ * ``rte_event_timer_adapter_get_info()``.
+ *
+ * @see struct rte_event_timer_adapter_info::min_resolution_ns
+ * @see struct rte_event_timer_adapter_info::max_tmo_ns
+ */
+#define RTE_EVENT_TIMER_ADAPTER_F_SP_PUT	(1ULL << 1)
+/**< ``rte_event_timer_arm_burst()`` API to be used in single producer mode.
+ *
+ * @see struct rte_event_timer_adapter_conf::flags
+ */
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter configuration structure
+ */
+struct rte_event_timer_adapter_conf {
+	uint8_t event_dev_id;
+	/**< Event device identifier */
+	uint16_t timer_adapter_id;
+	/**< Event timer adapter identifier */
+	uint32_t socket_id;
+	/**< Identifer of socket from which to allocate memory for adapter */
+	enum rte_event_timer_adapter_clk_src clk_src;
+	/**< Clock source for timer adapter */
+	uint64_t timer_tick_ns;
+	/**< Timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expiry) in ns */
+	uint64_t nb_timers;
+	/**< Total number of timers per adapter */
+	uint64_t flags;
+	/**< Timer adapter config flags (RTE_EVENT_TIMER_ADAPTER_F_*) */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer adapter stats structure
+ */
+struct rte_event_timer_adapter_stats {
+	uint64_t ev_enq_count;
+	/**< Eventdev enqueue count */
+	uint64_t ev_inv_count;
+	/**< Invalid expiry event count */
+	uint64_t evtim_retry_count;
+	/**< Event timer retry count */
+	uint64_t adapter_tick_count;
+	/**< Tick count for the adapter, at its resolution */
+};
+
+struct rte_event_timer_adapter;
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Callback function type for producer port creation.
+ */
+typedef int (*rte_event_timer_adapter_port_conf_cb_t)(uint16_t id,
+						      uint8_t event_dev_id,
+						      uint8_t *event_port_id,
+						      void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create an event timer adapter.
+ *
+ * This function must be invoked first before any other function in the API.
+ *
+ * @param conf
+ *   The event timer adapter configuration structure.
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ *   - EIO: event device reconfiguration and restart error.  The adapter
+ *   reconfigures the event device with an additional port by default if it is
+ *   required to use a service to manage timers. If the device had been started
+ *   before this call, this error code indicates an error in restart following
+ *   an error in reconfiguration, i.e., a combination of the two error codes.
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create a timer adapter with the supplied callback.
+ *
+ * This function can be used to have a more granular control over the timer
+ * adapter creation.  If a built-in port is absent, then the function uses the
+ * callback provided to create and get the port id to be used as a producer
+ * port.
+ *
+ * @param conf
+ *   The timer adapter configuration structure
+ * @param conf_cb
+ *   The port config callback function.
+ * @param conf_arg
+ *   Opaque pointer to the argument for the callback function
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter info structure.
+ */
+struct rte_event_timer_adapter_info {
+	uint64_t min_resolution_ns;
+	/**< Minimum timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expire) in ns */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configured timer adapter attributes */
+	uint32_t caps;
+	/**< Event timer adapter capabilities */
+	int16_t event_dev_port_id;
+	/**< Event device port ID, if applicable */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve the contextual information of an event timer adapter.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @param[out] adapter_info
+ *   A pointer to a structure of type *rte_event_timer_adapter_info* to be
+ *   filled with the contextual information of the adapter.
+ *
+ * @return
+ *   - 0: Success, driver updates the contextual information of the
+ *   timer adapter
+ *   - <0: Error code returned by the driver info get function.
+ *   - -EINVAL: adapter identifier invalid
+ *
+ * @see RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES,
+ *   struct rte_event_timer_adapter_info
+ *
+ */
+int __rte_experimental
+rte_event_timer_adapter_get_info(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Start a timer adapter.
+ *
+ * The adapter start step is the last one and consists of setting the timer
+ * adapter to start accepting the timers and schedules to event queues.
+ *
+ * On success, all basic functions exported by the API (timer arm,
+ * timer cancel and so on) can be invoked.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter started.
+ *   - <0: Error code returned by the driver start function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_start(
+		const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Stop an event timer adapter.
+ *
+ * The adapter can be restarted with a call to
+ * ``rte_event_timer_adapter_start()``.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter stopped.
+ *   - <0: Error code returned by the driver stop function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Lookup an event timer adapter using its identifier.
+ *
+ * If an event timer adapter was created in another process with the same
+ * identifier, this function will locate its state and set up access to it
+ * so that it can be used in this process.
+ *
+ * @param adapter_id
+ *  The event timer adapter identifier.
+ *
+ * @return
+ *  A pointer to the event timer adapter matching the identifier on success.
+ *  NULL on error with rte_errno set appropriately.
+ *  Possible rte_errno values include:
+ *   - ENOENT - requested entry not available to return.
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_lookup(uint16_t adapter_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Free an event timer adapter.
+ *
+ * Destroy an event timer adapter, freeing all resources.
+ *
+ * Before invoking this function, the application must wait for all the
+ * armed timers to expire or cancel the outstanding armed timers.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully freed the event timer adapter resources.
+ *   - <0: Failed to free the event timer adapter resources.
+ *   - -EAGAIN:  adapter is busy; timers outstanding
+ *   - -EBUSY: stop hasn't been called for this adapter yet
+ *   - -EINVAL: adapter id invalid, or adapter invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter);
+
+/**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure
+ *   - -ESRCH: the adapter does not require a service to operate
+ */
+int __rte_experimental
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param[out] stats
+ *   A pointer to a structure to fill with statistics.
+ *
+ * @return
+ *   - 0: Successfully retrieved.
+ *   - <0: Failure; error code returned.
+ */
+int __rte_experimental
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully reset;
+ *   - <0: Failure; error code returned.
+ */
+int __rte_experimental rte_event_timer_adapter_stats_reset(
+		struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer state.
+ */
+enum rte_event_timer_state {
+	RTE_EVENT_TIMER_NOT_ARMED	= 0,
+	/**< Event timer not armed. */
+	RTE_EVENT_TIMER_ARMED		= 1,
+	/**< Event timer successfully armed. */
+	RTE_EVENT_TIMER_CANCELED	= 2,
+	/**< Event timer successfully canceled. */
+	RTE_EVENT_TIMER_ERROR		= -1,
+	/**< Generic event timer error. */
+	RTE_EVENT_TIMER_ERROR_TOOEARLY	= -2,
+	/**< Event timer timeout tick value is too small for the adapter to
+	 * handle, given its configured resolution.
+	 */
+	RTE_EVENT_TIMER_ERROR_TOOLATE	= -3,
+	/**< Event timer timeout tick is greater than the maximum timeout.*/
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * The generic *rte_event_timer* structure to hold the event timer attributes
+ * for arm and cancel operations.
+ */
+RTE_STD_C11
+struct rte_event_timer {
+	struct rte_event ev;
+	/**<
+	 * Expiry event attributes.  On successful event timer timeout,
+	 * the following attributes will be used to inject the expiry event to
+	 * the eventdev:
+	 *  - event_queue_id: Targeted event queue id for expiry events.
+	 *  - event_priority: Event priority of the event expiry event in the
+	 *  event queue relative to other events.
+	 *  - sched_type: Scheduling type of the expiry event.
+	 *  - flow_id: Flow id of the expiry event.
+	 *  - op: RTE_EVENT_OP_NEW
+	 *  - event_type: RTE_EVENT_TYPE_TIMER
+	 */
+	volatile enum rte_event_timer_state state;
+	/**< State of the event timer. */
+	uint64_t timeout_ticks;
+	/**< Expiry timer ticks expressed in number of *timer_ticks_ns* from
+	 * now.
+	 * @see struct rte_event_timer_adapter_info::adapter_conf::timer_tick_ns
+	 */
+	uint64_t impl_opaque[2];
+	/**< Implementation-specific opaque data.
+	 * An event timer adapter implementation use this field to hold
+	 * implementation specific values to share between the arm and cancel
+	 * operations.  The application should not modify this field.
+	 */
+	uint8_t user_meta[];
+	/**< Memory to store user specific metadata.
+	 * The event timer adapter implementation should not modify this area.
+	 */
+} __rte_cache_aligned;
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Set an event timer's initial state and initialize the event it carries.
+ *
+ * @param evtim
+ *   A pointer to an event timer structure.
+ */
+void __rte_experimental
+rte_event_timer_init(struct rte_event_timer *evtim);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with separate expiration timeout tick for each
+ * event timer.
+ *
+ * Before calling this function, the application allocates
+ * ``struct rte_event_timer`` objects from mempool or huge page backed
+ * application buffers of desired size. On successful allocation,
+ * application updates the `struct rte_event_timer`` attributes such as
+ * expiry event attributes, timeout ticks from now.
+ * This function submits the event timer arm requests to the event timer adapter
+ * and on expiry, the events will be injected to designated event queue.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Pointer to an array of objects of type *rte_event_timer* structure.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_evtims* parameter. If the return value is less
+ *   than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
+ *   expiry event's sched type doesn't match the capabilities of the
+ *   destination event queue.
+ *   - EAGAIN Specified timer adapter is not running
+ *   - EALREADY A timer was encountered that was already armed
+ */
+int __rte_experimental
+rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **evtims,
+		uint16_t nb_evtims);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with same expiration timeout tick.
+ *
+ * Provides the same functionality as ``rte_event_timer_arm_burst()``, except
+ * that application can use this API when all the event timers have the
+ * same timeout expiration tick. This specialized function can provide the
+ * additional hint to the adapter implementation and optimize if possible.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Points to an array of objects of type *rte_event_timer* structure.
+ * @param timeout_ticks
+ *   The number of ticks in which the timers should expire.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_evtims* parameter. If the return value is less
+ *   than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
+ *   expiry event's sched type doesn't match the capabilities of the
+ *   destination event queue.
+ *   - EAGAIN Specified event timer adapter is not running
+ *   - EALREADY A timer was encountered that was already armed
+ */
+int __rte_experimental
+rte_event_timer_arm_tmo_tick_burst(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **evtims,
+		const uint64_t timeout_ticks,
+		const uint16_t nb_evtims);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Cancel a burst of event timers from being scheduled to the event device.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Points to an array of objects of type *rte_event_timer* structure
+ * @param nb_evtims
+ *   Number of event timer instances in the supplied array.
+ *
+ * @return
+ *   The number of successfully canceled event timers. The return value can be
+ *   less than the value of the *nb_evtims* parameter. If the return value is
+ *   less than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter identifier
+ *   - EAGAIN Specified timer adapter is not running
+ *   - EALREADY  A timer was encountered that was already canceled
+ */
+int __rte_experimental
+rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **evtims,
+		uint16_t nb_evtims);
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index b21c271..f9ad71e 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -1,35 +1,8 @@
-/*
- *   BSD LICENSE
- *
- *   Copyright 2016 Cavium, Inc.
- *   Copyright 2016 Intel Corporation.
- *   Copyright 2016 NXP.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Cavium, Inc nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2016 Cavium, Inc.
+ * Copyright(c) 2016-2018 Intel Corporation.
+ * Copyright(c) 2016 NXP.
+ * All rights reserved.
  */
 
 #ifndef _RTE_EVENTDEV_H_
@@ -923,8 +896,8 @@ rte_event_dev_close(uint8_t dev_id);
 /**< The event generated from ethdev subsystem */
 #define RTE_EVENT_TYPE_CRYPTODEV        0x1
 /**< The event generated from crypodev subsystem */
-#define RTE_EVENT_TYPE_TIMERDEV         0x2
-/**< The event generated from timerdev subsystem */
+#define RTE_EVENT_TYPE_TIMER		0x2
+/**< The event generated from event timer adapter */
 #define RTE_EVENT_TYPE_CPU              0x3
 /**< The event generated from cpu for pipelining.
  * Application may use *sub_event_type* to further classify the event
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 2/7] eventtimer: add common code
  2018-03-08 21:53     ` [PATCH v7 0/7] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  2018-03-08 21:54       ` [PATCH v7 1/7] eventtimer: add event timer adapter API Erik Gabriel Carrillo
@ 2018-03-08 21:54       ` Erik Gabriel Carrillo
  2018-03-12  8:11         ` Jerin Jacob
  2018-03-08 21:54       ` [PATCH v7 3/7] eventtimer: add default software driver Erik Gabriel Carrillo
                         ` (5 subsequent siblings)
  7 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-08 21:54 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

This commit adds the logic that is shared by all event timer adapter
drivers; the common code handles instance allocation and some
initialization.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 config/common_base                                |   1 +
 drivers/event/sw/sw_evdev.c                       |  18 +
 lib/librte_eventdev/Makefile                      |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c     | 459 ++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 150 +++++++
 lib/librte_eventdev/rte_eventdev.h                |   3 +
 lib/librte_eventdev/rte_eventdev_pmd.h            |  35 ++
 lib/librte_eventdev/rte_eventdev_version.map      |  20 +
 8 files changed, 688 insertions(+)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h

diff --git a/config/common_base b/config/common_base
index ad03cf4..286df74 100644
--- a/config/common_base
+++ b/config/common_base
@@ -546,6 +546,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
 CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
 CONFIG_RTE_EVENT_MAX_DEVS=16
 CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32
 
 #
 # Compile PMD for skeleton event device
diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index 6672fd8..0847547 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -464,6 +464,22 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
 	return 0;
 }
 
+static int
+sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
+			  uint64_t flags,
+			  uint32_t *caps,
+			  const struct rte_event_timer_adapter_ops **ops)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(flags);
+	*caps = 0;
+
+	/* Use default SW ops */
+	*ops = NULL;
+
+	return 0;
+}
+
 static void
 sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
 {
@@ -791,6 +807,8 @@ sw_probe(struct rte_vdev_device *vdev)
 
 			.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
 
+			.timer_adapter_caps_get = sw_timer_adapter_caps_get,
+
 			.xstats_get = sw_xstats_get,
 			.xstats_get_names = sw_xstats_get_names,
 			.xstats_get_by_name = sw_xstats_get_by_name,
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 549b182..8b16e3f 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -20,6 +20,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
 SRCS-y += rte_eventdev.c
 SRCS-y += rte_event_ring.c
 SRCS-y += rte_event_eth_rx_adapter.c
+SRCS-y += rte_event_timer_adapter.c
 
 # export include files
 SYMLINK-y-include += rte_eventdev.h
@@ -29,6 +30,7 @@ SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
 SYMLINK-y-include += rte_event_timer_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter_pmd.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
new file mode 100644
index 0000000..711d6b9
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -0,0 +1,459 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#include <string.h>
+
+#include <rte_memzone.h>
+#include <rte_memory.h>
+#include <rte_dev.h>
+#include <rte_errno.h>
+
+#include "rte_eventdev.h"
+#include "rte_eventdev_pmd.h"
+#include "rte_event_timer_adapter.h"
+#include "rte_event_timer_adapter_pmd.h"
+
+#define DATA_MZ_NAME_MAX_LEN 64
+#define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
+
+static int evtim_logtype;
+
+static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
+
+static inline int
+adapter_valid(const struct rte_event_timer_adapter *adapter)
+{
+	return adapter != NULL && adapter->allocated == 1;
+}
+
+#define EVTIM_LOG(level, logtype, ...) \
+	rte_log(RTE_LOG_ ## level, logtype, \
+		RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
+			"\n", __func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__,)))
+
+#define EVTIM_LOG_ERR(...) EVTIM_LOG(ERR, evtim_logtype, __VA_ARGS__)
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+#define EVTIM_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#else
+#define EVTIM_LOG_DBG(...) (void)0
+#endif
+
+#define ADAPTER_VALID_OR_ERR_RET(adapter, retval) do { \
+	if (!adapter_valid(adapter))		       \
+		return retval;			       \
+} while (0)
+
+#define FUNC_PTR_OR_ERR_RET(func, errval) do { \
+	if ((func) == NULL)		       \
+		return errval;		       \
+} while (0)
+
+#define FUNC_PTR_OR_NULL_RET_WITH_ERRNO(func, errval) do { \
+	if ((func) == NULL) {				   \
+		rte_errno = errval;			   \
+		return NULL;				   \
+	}						   \
+} while (0)
+
+static int
+default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		     void *conf_arg)
+{
+	struct rte_event_timer_adapter *adapter;
+	struct rte_eventdev *dev;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	int started;
+	uint8_t port_id;
+	uint8_t dev_id;
+	int ret;
+
+	RTE_SET_USED(event_dev_id);
+
+	adapter = &adapters[id];
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+	dev_id = dev->data->dev_id;
+	dev_conf = dev->data->dev_conf;
+
+	started = dev->data->dev_started;
+	if (started)
+		rte_event_dev_stop(dev_id);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports += 1;
+	ret = rte_event_dev_configure(dev_id, &dev_conf);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to configure event dev %u\n", dev_id);
+		if (started)
+			if (rte_event_dev_start(dev_id))
+				return -EIO;
+
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(dev_id, port_id, port_conf);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to setup event port %u on event dev %u\n",
+			      port_id, dev_id);
+		return ret;
+	}
+
+	*event_port_id = port_id;
+
+	if (started)
+		ret = rte_event_dev_start(dev_id);
+
+	return ret;
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf)
+{
+	return rte_event_timer_adapter_create_ext(conf, default_port_conf_cb,
+						  NULL);
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg)
+{
+	uint16_t adapter_id;
+	struct rte_event_timer_adapter *adapter;
+	const struct rte_memzone *mz;
+	char mz_name[DATA_MZ_NAME_MAX_LEN];
+	int n, ret;
+	struct rte_eventdev *dev;
+
+	if (conf == NULL) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Check eventdev ID */
+	if (!rte_event_pmd_is_valid_dev(conf->event_dev_id)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	dev = &rte_eventdevs[conf->event_dev_id];
+
+	adapter_id = conf->timer_adapter_id;
+
+	/* Check that adapter_id is in range */
+	if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Check adapter ID not already allocated */
+	adapter = &adapters[adapter_id];
+	if (adapter->allocated) {
+		rte_errno = EEXIST;
+		return NULL;
+	}
+
+	/* Create shared data area. */
+	n = snprintf(mz_name, sizeof(mz_name), DATA_MZ_NAME_FORMAT, adapter_id);
+	if (n >= (int)sizeof(mz_name)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	mz = rte_memzone_reserve(mz_name,
+				 sizeof(struct rte_event_timer_adapter_data),
+				 conf->socket_id, 0);
+	if (mz == NULL)
+		/* rte_errno set by rte_memzone_reserve */
+		return NULL;
+
+	adapter->data = mz->addr;
+	memset(adapter->data, 0, sizeof(struct rte_event_timer_adapter_data));
+
+	adapter->data->mz = mz;
+	adapter->data->event_dev_id = conf->event_dev_id;
+	adapter->data->id = adapter_id;
+	adapter->data->socket_id = conf->socket_id;
+	adapter->data->conf = *conf;  /* copy conf structure */
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = ret;
+		goto free_memzone;
+	}
+
+	if (!(adapter->data->caps &
+	      RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+		FUNC_PTR_OR_NULL_RET_WITH_ERRNO(conf_cb, -EINVAL);
+		ret = conf_cb(adapter->data->id, adapter->data->event_dev_id,
+			      &adapter->data->event_port_id, conf_arg);
+		if (ret < 0) {
+			rte_errno = ret;
+			goto free_memzone;
+		}
+	}
+
+	/* Allow driver to do some setup */
+	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
+	ret = adapter->ops->init(adapter);
+	if (ret < 0) {
+		rte_errno = ret;
+		goto free_memzone;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+
+free_memzone:
+	rte_memzone_free(adapter->data->mz);
+	return NULL;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->ops->get_info)
+		/* let driver set values it knows */
+		adapter->ops->get_info(adapter, adapter_info);
+
+	/* Set common values */
+	adapter_info->conf = adapter->data->conf;
+	adapter_info->event_dev_port_id = adapter->data->event_port_id;
+	adapter_info->caps = adapter->data->caps;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->start, -EINVAL);
+
+	ret = adapter->ops->start(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 1;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stop, -EINVAL);
+
+	if (adapter->data->started == 0) {
+		EVTIM_LOG_ERR("event timer adapter %hu already stopped",
+			      adapter->data->id);
+		return 0;
+	}
+
+	ret = adapter->ops->stop(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 0;
+
+	return 0;
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_lookup(uint16_t adapter_id)
+{
+	char name[DATA_MZ_NAME_MAX_LEN];
+	const struct rte_memzone *mz;
+	struct rte_event_timer_adapter_data *data;
+	struct rte_event_timer_adapter *adapter;
+	int ret;
+	struct rte_eventdev *dev;
+
+	if (adapters[adapter_id].allocated)
+		return &adapters[adapter_id]; /* Adapter is already loaded */
+
+	snprintf(name, DATA_MZ_NAME_MAX_LEN, DATA_MZ_NAME_FORMAT, adapter_id);
+	mz = rte_memzone_lookup(name);
+	if (mz == NULL) {
+		rte_errno = ENOENT;
+		return NULL;
+	}
+
+	data = mz->addr;
+
+	adapter = &adapters[data->id];
+	adapter->data = data;
+
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->uninit, -EINVAL);
+
+	if (adapter->data->started == 1) {
+		EVTIM_LOG_ERR("event timer adapter %hu must be stopped "
+			      "before freeing", adapter->data->id);
+		return -EBUSY;
+	}
+
+	/* free impl priv data */
+	ret = adapter->ops->uninit(adapter);
+	if (ret < 0)
+		return ret;
+
+	/* free shared data area */
+	ret = rte_memzone_free(adapter->data->mz);
+	if (ret < 0)
+		return ret;
+
+	adapter->data = NULL;
+	adapter->allocated = 0;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->data->service_inited && service_id != NULL)
+		*service_id = adapter->data->service_id;
+
+	return adapter->data->service_inited ? 0 : -ESRCH;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer_adapter_stats *stats)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_get, -EINVAL);
+	if (stats == NULL)
+		return -EINVAL;
+
+	return adapter->ops->stats_get(adapter, stats);
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_reset, -EINVAL);
+	return adapter->ops->stats_reset(adapter);
+}
+
+void __rte_experimental
+rte_event_timer_init(struct rte_event_timer *evtim)
+{
+	evtim->ev.op = RTE_EVENT_OP_NEW;
+	evtim->ev.event_type = RTE_EVENT_TYPE_TIMER;
+	evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+}
+
+int __rte_experimental
+rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **evtims,
+			  uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_burst, -EINVAL);
+#endif
+
+	return adapter->arm_burst(adapter, evtims, nb_evtims);
+}
+
+int __rte_experimental
+rte_event_timer_arm_tmo_tick_burst(
+			const struct rte_event_timer_adapter *adapter,
+			struct rte_event_timer **evtims,
+			const uint64_t timeout_ticks,
+			const uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_tmo_tick_burst, -EINVAL);
+#endif
+
+	return adapter->arm_tmo_tick_burst(adapter, evtims, timeout_ticks,
+					   nb_evtims);
+}
+
+int __rte_experimental
+rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			     struct rte_event_timer **evtims,
+			     uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->cancel_burst, -EINVAL);
+#endif
+
+	return adapter->cancel_burst(adapter, evtims, nb_evtims);
+}
+
+RTE_INIT(event_timer_adapter_init_log);
+static void
+event_timer_adapter_init_log(void)
+{
+	evtim_logtype = rte_log_register("lib.eventdev.adapter.timer");
+	if (evtim_logtype >= 0)
+		rte_log_set_level(evtim_logtype, RTE_LOG_NOTICE);
+}
diff --git a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
new file mode 100644
index 0000000..db044c8
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_PMD_H__
+#define __RTE_EVENT_TIMER_ADAPTER_PMD_H__
+
+/**
+ * @file
+ * RTE Event Timer Adapter API (PMD Side)
+ *
+ * @note
+ * This file provides implementation helpers for internal use by PMDs.  They
+ * are not intended to be exposed to applications and are not subject to ABI
+ * versioning.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "rte_event_timer_adapter.h"
+
+/*
+ * Definitions of functions exported by an event timer adapter implementation
+ * through *rte_event_timer_adapter_ops* structure supplied in the
+ * *rte_event_timer_adapter* structure associated with an event timer adapter.
+ */
+
+typedef int (*rte_event_timer_adapter_init_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation setup */
+typedef int (*rte_event_timer_adapter_uninit_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation teardown */
+typedef int (*rte_event_timer_adapter_start_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Start running event timer adapter */
+typedef int (*rte_event_timer_adapter_stop_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Stop running event timer adapter */
+typedef void (*rte_event_timer_adapter_get_info_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+/**< @internal Get contextual information for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_get_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_stats *stats);
+/**< @internal Get statistics for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_reset_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Reset statistics for event timer adapter */
+typedef int (*rte_event_timer_arm_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Enable event timers to enqueue timer events upon expiry */
+typedef int (*rte_event_timer_arm_tmo_tick_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint64_t timeout_tick,
+		uint16_t nb_tims);
+/**< @internal Enable event timers with common expiration time */
+typedef int (*rte_event_timer_cancel_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Prevent event timers from enqueuing timer events */
+
+/**
+ * @internal Structure containing the functions exported by an event timer
+ * adapter implementation.
+ */
+struct rte_event_timer_adapter_ops {
+	rte_event_timer_adapter_init_t		init;  /**< Set up adapter */
+	rte_event_timer_adapter_uninit_t	uninit;/**< Tear down adapter */
+	rte_event_timer_adapter_start_t		start; /**< Start adapter */
+	rte_event_timer_adapter_stop_t		stop;  /**< Stop adapter */
+	rte_event_timer_adapter_get_info_t	get_info;
+	/**< Get info from driver */
+	rte_event_timer_adapter_stats_get_t	stats_get;
+	/**< Get adapter statistics */
+	rte_event_timer_adapter_stats_reset_t	stats_reset;
+	/**< Reset adapter statistics */
+	rte_event_timer_arm_burst_t		arm_burst;
+	/**< Arm one or more event timers */
+	rte_event_timer_arm_tmo_tick_burst_t	arm_tmo_tick_burst;
+	/**< Arm event timers with same expiration time */
+	rte_event_timer_cancel_burst_t		cancel_burst;
+	/**< Cancel one or more event timers */
+};
+
+/**
+ * @internal Adapter data; structure to be placed in shared memory to be
+ * accessible by various processes in a multi-process configuration.
+ */
+struct rte_event_timer_adapter_data {
+	uint8_t id;
+	/**< Event timer adapter ID */
+	uint8_t event_dev_id;
+	/**< Event device ID */
+	uint32_t socket_id;
+	/**< Socket ID where memory is allocated */
+	uint8_t event_port_id;
+	/**< Optional: event port ID used when the inbuilt port is absent */
+	const struct rte_memzone *mz;
+	/**< Event timer adapter memzone pointer */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configuration used to configure the adapter. */
+	uint32_t caps;
+	/**< Adapter capabilities */
+	void *adapter_priv;
+	/**< Timer adapter private data*/
+	uint8_t service_inited;
+	/**< Service initialization state */
+	uint32_t service_id;
+	/**< Service ID*/
+
+	RTE_STD_C11
+	uint8_t started : 1;
+	/**< Flag to indicate adapter started. */
+} __rte_cache_aligned;
+
+/**
+ * @internal Data structure associated with each event timer adapter.
+ */
+struct rte_event_timer_adapter {
+	rte_event_timer_arm_burst_t arm_burst;
+	/**< Pointer to driver arm_burst function. */
+	rte_event_timer_arm_tmo_tick_burst_t arm_tmo_tick_burst;
+	/**< Pointer to driver arm_tmo_tick_burst function. */
+	rte_event_timer_cancel_burst_t cancel_burst;
+	/**< Pointer to driver cancel function. */
+	struct rte_event_timer_adapter_data *data;
+	/**< Pointer to shared adapter data */
+	const struct rte_event_timer_adapter_ops *ops;
+	/**< Functions exported by adapter driver */
+
+	RTE_STD_C11
+	uint8_t allocated : 1;
+	/**< Flag to indicate that this adapter has been allocated */
+} __rte_cache_aligned;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_PMD_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index f9ad71e..888bcf1 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -1046,6 +1046,9 @@ struct rte_event {
  * @see struct rte_event_eth_rx_adapter_queue_conf::rx_queue_flags
  */
 
+#define RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT (1ULL << 1)
+/**< This flag is set when the timer mechanism is in HW. */
+
 /**
  * Retrieve the event device's ethdev Rx adapter capabilities for the
  * specified ethernet port
diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h b/lib/librte_eventdev/rte_eventdev_pmd.h
index 31343b5..0e37f1c 100644
--- a/lib/librte_eventdev/rte_eventdev_pmd.h
+++ b/lib/librte_eventdev/rte_eventdev_pmd.h
@@ -26,6 +26,7 @@ extern "C" {
 #include <rte_malloc.h>
 
 #include "rte_eventdev.h"
+#include "rte_event_timer_adapter_pmd.h"
 
 /* Logging Macros */
 #define RTE_EDEV_LOG_ERR(...) \
@@ -449,6 +450,37 @@ typedef int (*eventdev_eth_rx_adapter_caps_get_t)
 struct rte_event_eth_rx_adapter_queue_conf *queue_conf;
 
 /**
+ * Retrieve the event device's timer adapter capabilities, as well as the ops
+ * structure that an event timer adapter should call through to enter the
+ * driver
+ *
+ * @param dev
+ *   Event device pointer
+ *
+ * @param flags
+ *   Flags that can be used to determine how to select an event timer
+ *   adapter ops structure
+ *
+ * @param[out] caps
+ *   A pointer to memory filled with Rx event adapter capabilities.
+ *
+ * @param[out] ops
+ *   A pointer to the ops pointer to set with the address of the desired ops
+ *   structure
+ *
+ * @return
+ *   - 0: Success, driver provides Rx event adapter capabilities for the
+ *	ethernet device.
+ *   - <0: Error code returned by the driver function.
+ *
+ */
+typedef int (*eventdev_timer_adapter_caps_get_t)(
+				const struct rte_eventdev *dev,
+				uint64_t flags,
+				uint32_t *caps,
+				const struct rte_event_timer_adapter_ops **ops);
+
+/**
  * Add ethernet Rx queues to event device. This callback is invoked if
  * the caps returned from rte_eventdev_eth_rx_adapter_caps_get(, eth_port_id)
  * has RTE_EVENT_ETH_RX_ADAPTER_CAP_INTERNAL_PORT set.
@@ -640,6 +672,9 @@ struct rte_eventdev_ops {
 	eventdev_eth_rx_adapter_stats_reset eth_rx_adapter_stats_reset;
 	/**< Reset ethernet Rx stats */
 
+	eventdev_timer_adapter_caps_get_t timer_adapter_caps_get;
+	/**< Get timer adapter capabilities */
+
 	eventdev_selftest dev_selftest;
 	/**< Start eventdev Selftest */
 };
diff --git a/lib/librte_eventdev/rte_eventdev_version.map b/lib/librte_eventdev/rte_eventdev_version.map
index 2aef470..345b0b1 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -74,3 +74,23 @@ DPDK_18.02 {
 
 	rte_event_dev_selftest;
 } DPDK_17.11;
+
+EXPERIMENTAL {
+	global:
+
+	rte_event_timer_adapter_create;
+	rte_event_timer_adapter_create_ext;
+	rte_event_timer_adapter_free;
+	rte_event_timer_adapter_get_info;
+	rte_event_timer_adapter_lookup;
+	rte_event_timer_adapter_service_id_get;
+	rte_event_timer_adapter_service_id_get;
+	rte_event_timer_adapter_start;
+	rte_event_timer_adapter_stats_get;
+	rte_event_timer_adapter_stats_reset;
+	rte_event_timer_adapter_stop;
+	rte_event_timer_init;
+	rte_event_timer_arm_burst;
+	rte_event_timer_arm_tmo_tick_burst;
+	rte_event_timer_cancel_burst;
+} DPDK_18.02;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 3/7] eventtimer: add default software driver
  2018-03-08 21:53     ` [PATCH v7 0/7] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  2018-03-08 21:54       ` [PATCH v7 1/7] eventtimer: add event timer adapter API Erik Gabriel Carrillo
  2018-03-08 21:54       ` [PATCH v7 2/7] eventtimer: add common code Erik Gabriel Carrillo
@ 2018-03-08 21:54       ` Erik Gabriel Carrillo
  2018-03-12  8:45         ` Jerin Jacob
  2018-03-08 21:54       ` [PATCH v7 4/7] eventtimer: add support for meson build system Erik Gabriel Carrillo
                         ` (4 subsequent siblings)
  7 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-08 21:54 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

If an eventdev PMD does not wish to provide event timer adapter ops
definitions, the library will fall back to a default software
implementation whose entry points are added by this commit.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/Makefile                                  |   2 +-
 lib/librte_eventdev/Makefile                  |   2 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 874 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h |  55 ++
 mk/rte.app.mk                                 |   2 +-
 5 files changed, 932 insertions(+), 3 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a6..965be6c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -31,7 +31,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
 DEPDIRS-librte_security += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash
+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_RAWDEV) += librte_rawdev
 DEPDIRS-librte_rawdev := librte_eal librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 8b16e3f..297df4a 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -14,7 +14,7 @@ LIBABIVER := 3
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool -lrte_timer
 
 # library source files
 SRCS-y += rte_eventdev.c
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 711d6b9..a35f233 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -4,11 +4,20 @@
  */
 
 #include <string.h>
+#include <stdbool.h>
+#include <sys/queue.h>
 
 #include <rte_memzone.h>
 #include <rte_memory.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_common.h>
+#include <rte_timer.h>
+#include <rte_service_component.h>
+#include <rte_cycles.h>
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -19,9 +28,13 @@
 #define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
 
 static int evtim_logtype;
+static int evtim_svc_logtype;
+static int evtim_buffer_logtype;
 
 static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+
 static inline int
 adapter_valid(const struct rte_event_timer_adapter *adapter)
 {
@@ -38,8 +51,14 @@ adapter_valid(const struct rte_event_timer_adapter *adapter)
 #ifdef RTE_LIBRTE_EVENTDEV_DEBUG
 #define EVTIM_LOG_DBG(...) \
 	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#define EVTIM_BUF_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_buffer_logtype, __VA_ARGS__)
+#define EVTIM_SVC_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_svc_logtype, __VA_ARGS__)
 #else
 #define EVTIM_LOG_DBG(...) (void)0
+#define EVTIM_BUF_LOG_DBG(...) (void)0
+#define EVTIM_SVC_LOG_DBG(...) (void)0
 #endif
 
 #define ADAPTER_VALID_OR_ERR_RET(adapter, retval) do { \
@@ -210,6 +229,12 @@ rte_event_timer_adapter_create_ext(
 		}
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Allow driver to do some setup */
 	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
 	ret = adapter->ops->init(adapter);
@@ -327,6 +352,12 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
 		return NULL;
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Set fast-path function pointers */
 	adapter->arm_burst = adapter->ops->arm_burst;
 	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
@@ -449,6 +480,840 @@ rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
 	return adapter->cancel_burst(adapter, evtims, nb_evtims);
 }
 
+/*
+ * Software event timer adapter buffer helper functions
+ */
+
+#define NSECPERSEC 1E9
+
+/* Optimizations used to index into the buffer require that the buffer size
+ * be a power of 2.
+ */
+#define EVENT_BUFFER_SZ	1024
+
+#define EVENT_BUFFER_BATCHSZ 32
+
+struct event_buffer {
+	uint16_t head;
+	uint16_t tail;
+	struct rte_event events[EVENT_BUFFER_SZ];
+} __rte_cache_aligned;
+
+static inline bool
+event_buffer_full(struct event_buffer *bufp)
+{
+	return (bufp->head - bufp->tail) == EVENT_BUFFER_SZ;
+}
+
+static inline bool
+event_buffer_batch_ready(struct event_buffer *bufp)
+{
+	return (bufp->head - bufp->tail) >= EVENT_BUFFER_BATCHSZ;
+}
+
+static void
+event_buffer_init(struct event_buffer *bufp)
+{
+	bufp->head = bufp->tail = 0;
+	memset(&bufp->events, 0, sizeof(struct rte_event) * EVENT_BUFFER_SZ);
+}
+
+static int
+event_buffer_add(struct event_buffer *bufp, struct rte_event *eventp)
+{
+	uint16_t offset;
+	struct rte_event *buf_eventp;
+
+	if (event_buffer_full(bufp))
+		return -1;
+
+	/* Instead of modulus, bitwise AND with mask to get offset. */
+	offset = bufp->head & (EVENT_BUFFER_SZ - 1);
+	buf_eventp = &bufp->events[offset];
+	rte_memcpy(buf_eventp, eventp, sizeof(struct rte_event));
+
+	/* Wrap automatically when overflow occurs. */
+	bufp->head++;
+
+	return 0;
+}
+
+static void
+event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,
+		   uint16_t *nb_events_flushed,
+		   uint16_t *nb_events_inv)
+{
+	uint16_t tail_offset, n = 0;
+	uint16_t *tailp = &bufp->tail;
+	uint16_t *headp = &bufp->head;
+	struct rte_event *events = bufp->events;
+
+	/* Instead of modulus, bitwise AND with mask to get offset. */
+	tail_offset = *tailp & (EVENT_BUFFER_SZ - 1);
+
+	/* Determine the largest contigous run we can attempt to enqueue to the
+	 * event device.
+	 */
+	if (*headp > *tailp)
+		n = *headp - *tailp;
+	else if (*headp < *tailp)
+		n = EVENT_BUFFER_SZ - tail_offset;
+	else {  /* buffer empty */
+		*nb_events_flushed = 0;
+		return;
+	}
+
+	*nb_events_inv = 0;
+	*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
+						     &events[tail_offset], n);
+	if (*nb_events_flushed != n && rte_errno == -EINVAL) {
+		EVTIM_LOG_ERR("failed to enqueue invalid event - dropping it");
+		nb_events_inv++;
+	}
+
+	EVTIM_BUF_LOG_DBG("event buffer flush: tried = %"PRIu16", "
+			  "succeeded = %"PRIu16, n, *nb_events_flushed);
+
+	/* Wrap automatically when overflow occurs */
+	*tailp = *tailp + *nb_events_flushed + *nb_events_inv;
+}
+
+/*
+ * Software event timer adapter implementation
+ */
+
+struct rte_event_timer_adapter_sw_data {
+	/* List of messages for outstanding timers */
+	TAILQ_HEAD(, msg) msgs_tailq_head;
+	/* Lock to guard tailq and armed count */
+	rte_spinlock_t msgs_tailq_sl;
+	/* Identifier of service executing timer management logic. */
+	uint32_t service_id;
+	/* The cycle count at which the adapter should next tick */
+	uint64_t next_tick_cycles;
+	/* Ring containing messages to arm or cancel event timers */
+	struct rte_ring *msg_ring;
+	/* Mempool containing msg objects */
+	struct rte_mempool *msg_pool;
+	/* Buffered timer expiry events to be enqueued to an event device. */
+	struct event_buffer buffer;
+	/* Statistics */
+	struct rte_event_timer_adapter_stats stats;
+	/* Incremented as the service moves through phases of an iteration */
+	volatile int service_phase;
+	/* The number of threads currently adding to the message ring */
+	rte_atomic16_t message_producer_count;
+};
+
+enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
+
+struct msg {
+	enum msg_type type;
+	struct rte_event_timer *evtim;
+	struct rte_timer tim;
+	TAILQ_ENTRY(msg) msgs;
+};
+
+static void
+sw_event_timer_cb(struct rte_timer *tim, void *arg)
+{
+	uint16_t nb_evs_flushed, nb_evs_invalid;
+	int ret;
+	struct rte_event_timer *evtim;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	evtim = arg;
+	adapter = (struct rte_event_timer_adapter *)evtim->impl_opaque[1];
+	sw_data = adapter->data->adapter_priv;
+
+	ret = event_buffer_add(&sw_data->buffer, &evtim->ev);
+	if (ret < 0) {
+		/* If event buffer is full, put timer back in list with
+		 * immediate expiry value, so that we process it again on the
+		 * next iteration.
+		 */
+		rte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),
+				     sw_event_timer_cb, evtim);
+
+		sw_data->stats.evtim_retry_count++;
+		EVTIM_LOG_DBG("event buffer full, resetting rte_timer with "
+			      "immediate expiry value");
+	} else {
+		struct msg *m = container_of(tim, struct msg, tim);
+		TAILQ_REMOVE(&sw_data->msgs_tailq_head, m, msgs);
+		EVTIM_BUF_LOG_DBG("buffered an event timer expiry event");
+		evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+
+		/* Free the msg object containing the rte_timer now that
+		 * we've buffered its event successfully.
+		 */
+		rte_mempool_put(sw_data->msg_pool, m);
+	}
+
+	if (event_buffer_batch_ready(&sw_data->buffer)) {
+		event_buffer_flush(&sw_data->buffer,
+				   adapter->data->event_dev_id,
+				   adapter->data->event_port_id,
+				   &nb_evs_flushed,
+				   &nb_evs_invalid);
+
+		sw_data->stats.ev_enq_count += nb_evs_flushed;
+		sw_data->stats.ev_inv_count += nb_evs_invalid;
+	}
+}
+
+static __rte_always_inline uint64_t
+get_timeout_cycles(struct rte_event_timer *evtim,
+		   struct rte_event_timer_adapter *adapter)
+{
+	uint64_t timeout_ns;
+
+	timeout_ns = evtim->timeout_ticks * adapter->data->conf.timer_tick_ns;
+	return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
+
+}
+
+/* This function returns true if one or more (adapter) ticks have occured since
+ * the last time it was called.
+ */
+static inline bool
+adapter_did_tick(struct rte_event_timer_adapter *adapter)
+{
+	uint64_t cycles_per_adapter_tick, start_cycles;
+	uint64_t *next_tick_cyclesp;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	next_tick_cyclesp = &sw_data->next_tick_cycles;
+
+	cycles_per_adapter_tick = adapter->data->conf.timer_tick_ns *
+			(rte_get_timer_hz() / NSECPERSEC);
+
+	start_cycles = rte_get_timer_cycles();
+
+	/* Note: initially, *next_tick_cyclesp == 0, so the clause below will
+	 * execute, and set things going.
+	 */
+
+	if (start_cycles >= *next_tick_cyclesp) {
+		/* Snap the current cycle count to the preceding adapter tick
+		 * boundary.
+		 */
+		start_cycles -= start_cycles % cycles_per_adapter_tick;
+
+		*next_tick_cyclesp = start_cycles + cycles_per_adapter_tick;
+
+		return true;
+	}
+
+	return false;
+}
+
+/* Check that event timer timeout value is in range */
+static __rte_always_inline int
+check_timeout(struct rte_event_timer *evtim,
+	      const struct rte_event_timer_adapter *adapter)
+{
+	uint64_t tmo_nsec = evtim->timeout_ticks *
+		adapter->data->conf.timer_tick_ns;
+
+	if (tmo_nsec > adapter->data->conf.max_tmo_ns)
+		return -1;
+
+	if (tmo_nsec < adapter->data->conf.timer_tick_ns)
+		return -2;
+
+	return 0;
+}
+
+/* Check that event timer event queue sched type matches destination event queue
+ * sched type
+ */
+static __rte_always_inline int
+check_destination_event_queue(struct rte_event_timer *evtim,
+			      const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	uint32_t sched_type;
+
+	ret = rte_event_queue_attr_get(adapter->data->event_dev_id,
+				       evtim->ev.queue_id,
+				       RTE_EVENT_QUEUE_ATTR_SCHEDULE_TYPE,
+				       &sched_type);
+
+	if ((ret < 0 && ret != -EOVERFLOW) ||
+	    evtim->ev.sched_type != sched_type)
+		return -1;
+
+	return 0;
+}
+
+#define NB_OBJS 32
+static int
+sw_event_timer_adapter_service_func(void *arg)
+{
+	int ret, i, num_msgs;
+	uint64_t cycles;
+	uint16_t nb_evs_flushed, nb_evs_invalid;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_timer *tim = NULL;
+	struct msg *msg, *msgs[NB_OBJS];
+
+	RTE_SET_USED(ret);
+
+	adapter = arg;
+	sw_data = adapter->data->adapter_priv;
+
+	sw_data->service_phase = 1;
+	rte_smp_wmb();
+
+	while (rte_atomic16_read(&sw_data->message_producer_count) > 0 ||
+	       !rte_ring_empty(sw_data->msg_ring)) {
+		num_msgs = rte_ring_dequeue_burst(sw_data->msg_ring,
+						  (void **)msgs, NB_OBJS, NULL);
+
+		for (i = 0; i < num_msgs; i++) {
+			msg = msgs[i];
+			evtim = msg->evtim;
+
+			switch (msg->type) {
+			case MSG_TYPE_ARM:
+				EVTIM_SVC_LOG_DBG("dequeued ARM message from "
+						  "ring");
+				tim = &msg->tim;
+				rte_timer_init(tim);
+				cycles = get_timeout_cycles(evtim,
+							    adapter);
+				ret = rte_timer_reset(tim, cycles, SINGLE,
+						      rte_lcore_id(),
+						      sw_event_timer_cb,
+						      evtim);
+				RTE_ASSERT(ret == 0);
+
+				evtim->impl_opaque[0] = (uintptr_t)tim;
+				evtim->impl_opaque[1] = (uintptr_t)adapter;
+
+				TAILQ_INSERT_TAIL(&sw_data->msgs_tailq_head,
+						  msg,
+						  msgs);
+				break;
+			case MSG_TYPE_CANCEL:
+				EVTIM_SVC_LOG_DBG("dequeued CANCEL message "
+						  "from ring");
+				tim = (struct rte_timer *)evtim->impl_opaque[0];
+				RTE_ASSERT(tim != NULL);
+
+				ret = rte_timer_stop(tim);
+				RTE_ASSERT(ret == 0);
+
+				/* Free the msg object for the original arm
+				 * request.
+				 */
+				struct msg *m;
+				m = container_of(tim, struct msg, tim);
+				TAILQ_REMOVE(&sw_data->msgs_tailq_head, m,
+					     msgs);
+				rte_mempool_put(sw_data->msg_pool, m);
+
+				/* Free the msg object for the current msg */
+				rte_mempool_put(sw_data->msg_pool, msg);
+
+				evtim->impl_opaque[0] = 0;
+				evtim->impl_opaque[1] = 0;
+
+				break;
+			}
+		}
+	}
+
+	sw_data->service_phase = 2;
+	rte_smp_wmb();
+
+	if (adapter_did_tick(adapter)) {
+		rte_timer_manage();
+
+		event_buffer_flush(&sw_data->buffer,
+				   adapter->data->event_dev_id,
+				   adapter->data->event_port_id,
+				   &nb_evs_flushed, &nb_evs_invalid);
+
+		sw_data->stats.ev_enq_count += nb_evs_flushed;
+		sw_data->stats.ev_inv_count += nb_evs_invalid;
+		sw_data->stats.adapter_tick_count++;
+	}
+
+	sw_data->service_phase = 0;
+	rte_smp_wmb();
+
+	return 0;
+}
+
+/* The adapter initialization function rounds the mempool size up to the next
+ * power of 2, so we can take the difference between that value and what the
+ * user requested, and use the space for caches.  This avoids a scenario where a
+ * user can't arm the number of timers the adapter was configured with because
+ * mempool objects have been lost to caches.
+ *
+ * nb_actual should always be a power of 2, so we can iterate over the powers
+ * of 2 to see what the largest cache size we can use is.
+ */
+static inline int
+compute_msg_mempool_cache_size(uint64_t nb_requested, uint64_t nb_actual) {
+	int i;
+	int size;
+	int cache_size = 0;
+
+	for (i = 0; ; i++) {
+		size = 1 << i;
+
+		if (RTE_MAX_LCORE * size < (int)(nb_actual - nb_requested) &&
+		    size < RTE_MEMPOOL_CACHE_MAX_SIZE &&
+		    size <= nb_actual / 1.5)
+			cache_size = size;
+		else
+			break;
+	}
+
+	return cache_size;
+}
+
+static int
+sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	uint64_t nb_timers;
+	unsigned int flags;
+	struct rte_service_spec service;
+	static bool timer_subsystem_inited; // static initialized to false
+
+	/* Allocate storage for SW implementation data */
+	char priv_data_name[RTE_RING_NAMESIZE];
+	snprintf(priv_data_name, RTE_RING_NAMESIZE, "sw_evtim_adap_priv_%"PRIu8,
+		 adapter->data->id);
+	adapter->data->adapter_priv = rte_zmalloc_socket(
+				priv_data_name,
+				sizeof(struct rte_event_timer_adapter_sw_data),
+				RTE_CACHE_LINE_SIZE,
+				adapter->data->socket_id);
+	if (adapter->data->adapter_priv == NULL) {
+		EVTIM_LOG_ERR("failed to allocate space for private data");
+		rte_errno = ENOMEM;
+		return -1;
+	}
+
+	sw_data = adapter->data->adapter_priv;
+
+	TAILQ_INIT(&sw_data->msgs_tailq_head);
+	rte_spinlock_init(&sw_data->msgs_tailq_sl);
+	rte_atomic16_init(&sw_data->message_producer_count);
+
+	/* Rings require power of 2, so round up to next such value */
+	nb_timers = rte_align64pow2(adapter->data->conf.nb_timers);
+
+	char msg_ring_name[RTE_RING_NAMESIZE];
+	snprintf(msg_ring_name, RTE_RING_NAMESIZE,
+		 "sw_evtim_adap_msg_ring_%"PRIu8, adapter->data->id);
+	flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+		RING_F_SP_ENQ | RING_F_SC_DEQ :
+		RING_F_SC_DEQ;
+	sw_data->msg_ring = rte_ring_create(msg_ring_name, nb_timers,
+					    adapter->data->socket_id, flags);
+	if (sw_data->msg_ring == NULL) {
+		EVTIM_LOG_ERR("failed to create message ring");
+		rte_errno = ENOMEM;
+		goto free_priv_data;
+	}
+
+	char pool_name[RTE_RING_NAMESIZE];
+	snprintf(pool_name, RTE_RING_NAMESIZE, "sw_evtim_adap_msg_pool_%"PRIu8,
+		 adapter->data->id);
+
+	/* Both the arming/canceling thread and the service thread will do puts
+	 * to the mempool, but if the SP_PUT flag is enabled, we can specify
+	 * single-consumer get for the mempool.
+	 */
+	flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+		MEMPOOL_F_SC_GET : 0;
+
+	/* The usable size of a ring is count - 1, so subtract one here to
+	 * make the counts agree.
+	 */
+	int pool_size = nb_timers - 1;
+	int cache_size = compute_msg_mempool_cache_size(
+				adapter->data->conf.nb_timers, nb_timers);
+	sw_data->msg_pool = rte_mempool_create(pool_name, pool_size,
+					       sizeof(struct msg), cache_size,
+					       0, NULL, NULL, NULL, NULL,
+					       adapter->data->socket_id, flags);
+	if (sw_data->msg_pool == NULL) {
+		EVTIM_LOG_ERR("failed to create message object mempool");
+		rte_errno = ENOMEM;
+		goto free_msg_ring;
+	}
+
+	event_buffer_init(&sw_data->buffer);
+
+	/* Register a service component to run adapter logic */
+	memset(&service, 0, sizeof(service));
+	snprintf(service.name, RTE_SERVICE_NAME_MAX,
+		 "sw_evimer_adap_svc_%"PRIu8, adapter->data->id);
+	service.socket_id = adapter->data->socket_id;
+	service.callback = sw_event_timer_adapter_service_func;
+	service.callback_userdata = adapter;
+	service.capabilities &= ~(RTE_SERVICE_CAP_MT_SAFE);
+	ret = rte_service_component_register(&service, &sw_data->service_id);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to register service %s with id %"PRIu32
+			      ": err = %d", service.name, sw_data->service_id,
+			      ret);
+
+		rte_errno = ENOSPC;
+		goto free_msg_pool;
+	}
+
+	EVTIM_LOG_DBG("registered service %s with id %"PRIu32, service.name,
+		      sw_data->service_id);
+
+	adapter->data->service_id = sw_data->service_id;
+	adapter->data->service_inited = 1;
+
+	if (!timer_subsystem_inited) {
+		rte_timer_subsystem_init();
+		timer_subsystem_inited = true;
+	}
+
+	return 0;
+
+free_msg_pool:
+	rte_mempool_free(sw_data->msg_pool);
+free_msg_ring:
+	rte_ring_free(sw_data->msg_ring);
+free_priv_data:
+	rte_free(sw_data);
+	return -1;
+}
+
+static int
+sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct msg *m1, *m2;
+	struct rte_event_timer_adapter_sw_data *sw_data =
+						adapter->data->adapter_priv;
+
+	rte_spinlock_lock(&sw_data->msgs_tailq_sl);
+
+	/* Cancel outstanding rte_timers and free msg objects */
+	m1 = TAILQ_FIRST(&sw_data->msgs_tailq_head);
+	while (m1 != NULL) {
+		EVTIM_LOG_DBG("freeing outstanding timer");
+		m2 = TAILQ_NEXT(m1, msgs);
+
+		rte_timer_stop_sync(&m1->tim);
+		rte_mempool_put(sw_data->msg_pool, m1);
+
+		m1 = m2;
+	}
+
+	rte_spinlock_unlock(&sw_data->msgs_tailq_sl);
+
+	ret = rte_service_component_unregister(sw_data->service_id);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to unregister service component");
+		return ret;
+	}
+
+	rte_ring_free(sw_data->msg_ring);
+	rte_mempool_free(sw_data->msg_pool);
+	rte_free(adapter->data->adapter_priv);
+
+	return 0;
+}
+
+static inline int32_t
+get_mapped_count_for_service(uint32_t service_id)
+{
+	int32_t core_count, i, mapped_count = 0;
+	uint32_t lcore_arr[RTE_MAX_LCORE];
+
+	core_count = rte_service_lcore_list(lcore_arr, RTE_MAX_LCORE);
+
+	for (i = 0; i < core_count; i++)
+		if (rte_service_map_lcore_get(service_id, lcore_arr[i]) == 1)
+			mapped_count++;
+
+	return mapped_count;
+}
+
+static int
+sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int mapped_count;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+
+	/* Mapping the service to more than one service core can introduce
+	 * delays while one thread is waiting to acquire a lock, so only allow
+	 * one core to be mapped to the service.
+	 */
+	mapped_count = get_mapped_count_for_service(sw_data->service_id);
+
+	if (mapped_count == 1)
+		return rte_service_component_runstate_set(sw_data->service_id,
+							  1);
+
+	return mapped_count < 1 ? -ENOENT : -ENOTSUP;
+}
+
+static int
+sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data =
+						adapter->data->adapter_priv;
+
+	ret = rte_service_component_runstate_set(sw_data->service_id, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Wait for the service to complete its final iteration before
+	 * stopping.
+	 */
+	while (sw_data->service_phase != 0)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	return 0;
+}
+
+static void
+sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	RTE_SET_USED(adapter);
+	RTE_SET_USED(adapter_info);
+	/* nothing for now */
+}
+
+static int
+sw_event_timer_adapter_stats_get(const struct rte_event_timer_adapter *adapter,
+				 struct rte_event_timer_adapter_stats *stats)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	*stats = sw_data->stats;
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_stats_reset(
+				const struct rte_event_timer_adapter *adapter)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	memset(&sw_data->stats, 0, sizeof(sw_data->stats));
+	return 0;
+}
+
+static __rte_always_inline int
+__sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **evtims,
+			  uint16_t nb_evtims)
+{
+	int i, ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct msg *msgs[nb_evtims];
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	/* Check that the service is running. */
+	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
+		rte_errno = EINVAL;
+		return 0;
+	}
+#endif
+
+	sw_data = adapter->data->adapter_priv;
+
+	ret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (ret < 0) {
+		rte_errno = ENOSPC;
+		return 0;
+	}
+
+	/* Let the service know we're producing messages for it to process */
+	rte_atomic16_inc(&sw_data->message_producer_count);
+
+	/* If the service is managing timers, wait for it to finish */
+	while (sw_data->service_phase == 2)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	for (i = 0; i < nb_evtims; i++) {
+		/* Don't modify the event timer state in these cases */
+		if (evtims[i]->state == RTE_EVENT_TIMER_ARMED) {
+			rte_errno = EALREADY;
+			break;
+		} else if (!(evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
+		    evtims[i]->state == RTE_EVENT_TIMER_CANCELED)) {
+			rte_errno = EINVAL;
+			break;
+		}
+
+		ret = check_timeout(evtims[i], adapter);
+		if (ret == -1) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOLATE;
+			rte_errno = EINVAL;
+			break;
+		}
+		if (ret == -2) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOEARLY;
+			rte_errno = EINVAL;
+			break;
+		}
+
+		if (check_destination_event_queue(evtims[i], adapter) < 0) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR;
+			rte_errno = EINVAL;
+			break;
+		}
+
+		/* Checks passed, set up a message to enqueue */
+		msgs[i]->type = MSG_TYPE_ARM;
+		msgs[i]->evtim = evtims[i];
+
+		/* msg objects that get enqueued successfully will be freed
+		 * either by a future cancel operation or by the timer
+		 * expiration callback.
+		 */
+		if (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {
+			rte_errno = ENOSPC;
+			break;
+		}
+
+		EVTIM_LOG_DBG("enqueued ARM message to ring");
+
+		evtims[i]->state = RTE_EVENT_TIMER_ARMED;
+	}
+
+	/* Let the service know we're done producing messages */
+	rte_atomic16_dec(&sw_data->message_producer_count);
+
+	if (i < nb_evtims)
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],
+				     nb_evtims - i);
+
+	return i;
+}
+
+static int
+sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			 struct rte_event_timer **evtims,
+			 uint16_t nb_evtims)
+{
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
+}
+
+static int
+sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			    struct rte_event_timer **evtims,
+			    uint16_t nb_evtims)
+{
+	int i, ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct msg *msgs[nb_evtims];
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	/* Check that the service is running. */
+	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
+		rte_errno = EINVAL;
+		return 0;
+	}
+#endif
+
+	sw_data = adapter->data->adapter_priv;
+
+	ret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (ret < 0) {
+		rte_errno = ENOSPC;
+		return 0;
+	}
+
+	/* Let the service know we're producing messages for it to process */
+	rte_atomic16_inc(&sw_data->message_producer_count);
+
+	/* If the service could be modifying event timer states, wait */
+	while (sw_data->service_phase == 2)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	for (i = 0; i < nb_evtims; i++) {
+		/* Don't modify the event timer state in these cases */
+		if (evtims[i]->state == RTE_EVENT_TIMER_CANCELED) {
+			rte_errno = EALREADY;
+			break;
+		} else if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
+			rte_errno = EINVAL;
+			break;
+		}
+
+		msgs[i]->type = MSG_TYPE_CANCEL;
+		msgs[i]->evtim = evtims[i];
+
+		if (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {
+			rte_errno = ENOSPC;
+			break;
+		}
+
+		EVTIM_LOG_DBG("enqueued CANCEL message to ring");
+
+		evtims[i]->state = RTE_EVENT_TIMER_CANCELED;
+	}
+
+	/* Let the service know we're done producing messages */
+	rte_atomic16_dec(&sw_data->message_producer_count);
+
+	if (i < nb_evtims)
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],
+				     nb_evtims - i);
+
+	return i;
+}
+
+static int
+sw_event_timer_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer **evtims,
+				  uint64_t timeout_ticks,
+				  uint16_t nb_evtims)
+{
+	int i;
+
+	for (i = 0; i < nb_evtims; i++)
+		evtims[i]->timeout_ticks = timeout_ticks;
+
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
+}
+
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
+	.init = sw_event_timer_adapter_init,
+	.uninit = sw_event_timer_adapter_uninit,
+	.start = sw_event_timer_adapter_start,
+	.stop = sw_event_timer_adapter_stop,
+	.get_info = sw_event_timer_adapter_get_info,
+	.stats_get = sw_event_timer_adapter_stats_get,
+	.stats_reset = sw_event_timer_adapter_stats_reset,
+	.arm_burst = sw_event_timer_arm_burst,
+	.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
+	.cancel_burst = sw_event_timer_cancel_burst,
+};
+
 RTE_INIT(event_timer_adapter_init_log);
 static void
 event_timer_adapter_init_log(void)
@@ -456,4 +1321,13 @@ event_timer_adapter_init_log(void)
 	evtim_logtype = rte_log_register("lib.eventdev.adapter.timer");
 	if (evtim_logtype >= 0)
 		rte_log_set_level(evtim_logtype, RTE_LOG_NOTICE);
+
+	evtim_buffer_logtype = rte_log_register("lib.eventdev.adapter.timer."
+						"buffer");
+	if (evtim_buffer_logtype >= 0)
+		rte_log_set_level(evtim_buffer_logtype, RTE_LOG_NOTICE);
+
+	evtim_svc_logtype = rte_log_register("lib.eventdev.adapter.timer.svc");
+	if (evtim_svc_logtype >= 0)
+		rte_log_set_level(evtim_svc_logtype, RTE_LOG_NOTICE);
 }
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index 1c8a45b..5c223d6 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -335,6 +335,8 @@ rte_event_timer_adapter_get_info(
  *   - 0: Success, adapter started.
  *   - <0: Error code returned by the driver start function.
  *   - -EINVAL if adapter identifier invalid
+ *   - -ENOENT if software adapter but no service core mapped
+ *   - -ENOTSUP if software adapter and more than one service core mapped
  */
 int __rte_experimental
 rte_event_timer_adapter_start(
@@ -461,6 +463,59 @@ int __rte_experimental rte_event_timer_adapter_stats_reset(
 		struct rte_event_timer_adapter *adapter);
 
 /**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure, if the event dev doesn't use a rte_service
+ *   function, this function returns -ESRCH.
+ */
+int
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param[out] stats
+ *   A pointer to a structure to fill with statistics.
+ *
+ * @return
+ *   - 0: Successfully retrieved.
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				struct rte_event_timer_adapter_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully reset;
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_reset(
+				struct rte_event_timer_adapter *adapter);
+
+/**
  * @warning
  * @b EXPERIMENTAL: this structure may change without prior notice
  *
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 3eb41d1..83660df 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)        += -lrte_bitratestats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
 
-_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
 
 _LDLIBS-y += --whole-archive
@@ -98,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)       += -lrte_security
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV)         += -lrte_rawdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 4/7] eventtimer: add support for meson build system
  2018-03-08 21:53     ` [PATCH v7 0/7] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                         ` (2 preceding siblings ...)
  2018-03-08 21:54       ` [PATCH v7 3/7] eventtimer: add default software driver Erik Gabriel Carrillo
@ 2018-03-08 21:54       ` Erik Gabriel Carrillo
  2018-03-08 21:54       ` [PATCH v7 5/7] test: add event timer adapter auto-test Erik Gabriel Carrillo
                         ` (3 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-08 21:54 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 config/rte_config.h             | 1 +
 lib/librte_eventdev/meson.build | 9 ++++++---
 lib/meson.build                 | 3 ++-
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/config/rte_config.h b/config/rte_config.h
index 699878a..823fd79 100644
--- a/config/rte_config.h
+++ b/config/rte_config.h
@@ -55,6 +55,7 @@
 /* eventdev defines */
 #define RTE_EVENT_MAX_DEVS 16
 #define RTE_EVENT_MAX_QUEUES_PER_DEV 64
+#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 32
 
 /* ip_fragmentation defines */
 #define RTE_LIBRTE_IP_FRAG_MAX_FRAG 4
diff --git a/lib/librte_eventdev/meson.build b/lib/librte_eventdev/meson.build
index d1a9960..e73c7cf 100644
--- a/lib/librte_eventdev/meson.build
+++ b/lib/librte_eventdev/meson.build
@@ -4,11 +4,14 @@
 allow_experimental_apis = true
 sources = files('rte_eventdev.c',
 		'rte_event_ring.c',
-		'rte_event_eth_rx_adapter.c')
+		'rte_event_eth_rx_adapter.c',
+		'rte_event_timer_adapter.c')
 headers = files('rte_eventdev.h',
 		'rte_eventdev_pmd.h',
 		'rte_eventdev_pmd_pci.h',
 		'rte_eventdev_pmd_vdev.h',
 		'rte_event_ring.h',
-		'rte_event_eth_rx_adapter.h')
-deps += ['ring', 'ethdev', 'hash']
+		'rte_event_eth_rx_adapter.h',
+		'rte_event_timer_adapter.h',
+		'rte_event_timer_adapter_pmd.h')
+deps += ['ring', 'ethdev', 'hash', 'mempool', 'timer']
diff --git a/lib/meson.build b/lib/meson.build
index ef61591..b1ad35f 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -13,13 +13,14 @@ libraries = [ 'compat', # just a header, used for versioning
 	'metrics', # bitrate/latency stats depends on this
 	'hash',    # efd depends on this
 	'kvargs',  # cryptodev depends on this
+	'timer',   # eventdev depends on this
 	'acl', 'bbdev', 'bitratestats', 'cfgfile',
 	'cmdline', 'cryptodev',
 	'distributor', 'efd', 'eventdev',
 	'gro', 'gso', 'ip_frag', 'jobstats',
 	'kni', 'latencystats', 'lpm', 'member',
 	'meter', 'power', 'pdump',
-	'reorder', 'sched', 'security', 'timer', 'vhost',
+	'reorder', 'sched', 'security', 'vhost',
 	# add pkt framework libs which use other libs from above
 	'port', 'table', 'pipeline',
 	# flow_classify lib depends on pkt framework table lib
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 5/7] test: add event timer adapter auto-test
  2018-03-08 21:53     ` [PATCH v7 0/7] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                         ` (3 preceding siblings ...)
  2018-03-08 21:54       ` [PATCH v7 4/7] eventtimer: add support for meson build system Erik Gabriel Carrillo
@ 2018-03-08 21:54       ` Erik Gabriel Carrillo
  2018-03-14 12:52         ` Pavan Nikhilesh
  2018-03-14 13:31         ` Pavan Nikhilesh
  2018-03-08 21:54       ` [PATCH v7 6/7] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
                         ` (2 subsequent siblings)
  7 siblings, 2 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-08 21:54 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 test/test/Makefile                   |    1 +
 test/test/test_event_timer_adapter.c | 1234 ++++++++++++++++++++++++++++++++++
 2 files changed, 1235 insertions(+)
 create mode 100644 test/test/test_event_timer_adapter.c

diff --git a/test/test/Makefile b/test/test/Makefile
index a88cc38..c9c007c9 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -185,6 +185,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
 SRCS-y += test_eventdev.c
 SRCS-y += test_event_ring.c
 SRCS-y += test_event_eth_rx_adapter.c
+SRCS-y += test_event_timer_adapter.c
 endif
 
 ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y)
diff --git a/test/test/test_event_timer_adapter.c b/test/test/test_event_timer_adapter.c
new file mode 100644
index 0000000..936e662
--- /dev/null
+++ b/test/test/test_event_timer_adapter.c
@@ -0,0 +1,1234 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Intel Corporation
+ */
+
+#include <string.h>
+#include <math.h>
+#include <stdbool.h>
+
+#include <rte_eventdev.h>
+#include <rte_dev.h>
+#include <rte_bus_vdev.h>
+#include <rte_event_timer_adapter.h>
+#include <rte_mempool.h>
+#include <rte_errno.h>
+#include <rte_service_component.h>
+#include <rte_cycles.h>
+
+#include "test.h"
+
+#define NB_TEST_EVENT_TIMERS    2050
+#define NB_TEST_PORTS		1
+#define NB_TEST_QUEUES		1
+#define TEST_PORT_ID		0
+#define ADAPTER_PORT_ID		1
+#define TEST_QUEUE_ID		0
+#define TEST_ADAPTER_ID		0
+
+#define NSECPERSEC		1E9
+
+#define BATCH_SIZE 16
+
+/* Handle log statements in same manner as test macros */
+#define LOG_DBG(...)	RTE_LOG(DEBUG, EAL, __VA_ARGS__)
+
+static int evdev;
+static struct rte_mempool *g_event_timer_pool;
+static struct rte_event_timer_adapter *g_adapter;
+static uint32_t slcore_id;
+
+static struct rte_event_timer_adapter_conf g_adapter_conf = {
+	.event_dev_id = 0,
+	.timer_adapter_id = TEST_ADAPTER_ID,
+	.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+	.timer_tick_ns = NSECPERSEC / 10,  // 100 milliseconds, 10 ticks/sec
+	.max_tmo_ns = 180 * NSECPERSEC,	   // 2 minutes
+	.nb_timers = NB_TEST_EVENT_TIMERS,
+	.flags = 0,
+};
+
+static inline void
+devconf_set_test_values(struct rte_event_dev_config *dev_conf,
+				  struct rte_event_dev_info *info)
+{
+	memset(dev_conf, 0, sizeof(struct rte_event_dev_config));
+	dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns;
+	dev_conf->nb_event_ports = NB_TEST_PORTS;
+	dev_conf->nb_event_queues = NB_TEST_QUEUES;
+	dev_conf->nb_event_queue_flows = info->max_event_queue_flows;
+	dev_conf->nb_event_port_dequeue_depth =
+			info->max_event_port_dequeue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+			info->max_event_port_enqueue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+			info->max_event_port_enqueue_depth;
+	dev_conf->nb_events_limit =
+			info->max_num_events;
+}
+
+static int
+configure_event_dev(void)
+{
+	const char *eventdev_name = "event_sw0";
+	int ret;
+	struct rte_event_dev_config devconf;
+	struct rte_event_dev_info info;
+
+	evdev = rte_event_dev_get_dev_id(eventdev_name);
+	if (evdev < 0) {
+		if (rte_vdev_init(eventdev_name, NULL) < 0) {
+			LOG_DBG("Error creating eventdev\n");
+			return TEST_FAILED;
+		}
+		evdev = rte_event_dev_get_dev_id(eventdev_name);
+		if (evdev < 0) {
+			LOG_DBG("Error finding newly created eventdev\n");
+			return TEST_FAILED;
+		}
+	}
+
+	ret = rte_event_dev_info_get(evdev, &info);
+	TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info");
+
+	devconf_set_test_values(&devconf, &info);
+
+	ret = rte_event_dev_configure(evdev, &devconf);
+	TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev");
+
+	/* Set up event queue */
+	uint32_t queue_count;
+	TEST_ASSERT_SUCCESS(rte_event_dev_attr_get(evdev,
+			    RTE_EVENT_DEV_ATTR_QUEUE_COUNT, &queue_count),
+			    "Queue count get failed");
+	TEST_ASSERT_EQUAL(queue_count, 1, "Unexpected queue count");
+	ret = rte_event_queue_setup(evdev, TEST_QUEUE_ID, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", TEST_QUEUE_ID);
+
+	/* Set up event port */
+	uint32_t port_count;
+	uint8_t qid = TEST_QUEUE_ID;
+	TEST_ASSERT_SUCCESS(rte_event_dev_attr_get(evdev,
+			    RTE_EVENT_DEV_ATTR_PORT_COUNT,
+			    &port_count), "Port count get failed");
+	TEST_ASSERT_EQUAL(port_count, 1, "Unexpected port count");
+	ret = rte_event_port_setup(evdev, TEST_PORT_ID, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup port=%d", TEST_PORT_ID);
+	ret = rte_event_port_link(evdev, TEST_PORT_ID, &qid, NULL, 1);
+	TEST_ASSERT(ret >= 0, "Failed to link queue port=%d", TEST_PORT_ID);
+
+	return TEST_SUCCESS;
+}
+
+/* ----------------    Setup / Teardown   --------------------*/
+
+static int
+testsuite_setup(void)
+{
+	slcore_id = rte_get_next_lcore(-1, 1, 0);
+
+	TEST_ASSERT_NOT_EQUAL(slcore_id, RTE_MAX_LCORE, "At least 2 lcores "
+			"are required to run this autotest");
+
+	/* Setup and start event device. */
+	TEST_ASSERT_SUCCESS(configure_event_dev(), "Failed to configure event "
+			"dev");
+
+	/* Create a mempool of event timers. */
+	g_event_timer_pool = rte_mempool_create("event_timer_mempool",
+			NB_TEST_EVENT_TIMERS * 2,
+			sizeof(struct rte_event_timer), 0, 0, NULL, NULL, NULL,
+			NULL, rte_socket_id(), 0);
+
+	TEST_ASSERT_NOT_NULL(g_event_timer_pool, "Failed to configure event "
+			"timer mempool: %s\n", rte_strerror(rte_errno));
+
+	return TEST_SUCCESS;
+}
+
+static void
+testsuite_teardown(void)
+{
+	rte_mempool_free(g_event_timer_pool);
+}
+
+static int
+g_adapter_create(void)
+{
+	uint8_t event_dev_id;
+	int ret, started;
+	struct rte_eventdev *event_dev;
+	struct rte_event_dev_config event_dev_conf;
+
+	/* Re-configure the event device ports to release ports allocated by
+	 * previous instantiations of event timer adapters.
+	 */
+	event_dev = &rte_eventdevs[g_adapter_conf.event_dev_id];
+	event_dev_id = event_dev->data->dev_id;
+	event_dev_conf = event_dev->data->dev_conf;
+
+	started = event_dev->data->dev_started;
+	if (started)
+		rte_event_dev_stop(event_dev_id);
+
+	event_dev_conf.nb_event_ports = NB_TEST_PORTS;
+	ret = rte_event_dev_configure(event_dev_id, &event_dev_conf);
+
+	if (started) {
+		ret = rte_event_dev_start(event_dev_id);
+		if (ret < 0) {
+			LOG_DBG("failed to start event device after "
+				"reconfiguration\n");
+			return TEST_FAILED;
+		}
+	}
+
+	/* Now create adapter with default port creation callback */
+	g_adapter = rte_event_timer_adapter_create(&g_adapter_conf);
+	TEST_ASSERT_NOT_NULL(g_adapter, "Failed to create event timer adapter");
+
+	return TEST_SUCCESS;
+}
+static void
+g_adapter_free(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event evs[BATCH_SIZE];
+
+	ret = rte_event_timer_adapter_free(g_adapter);
+	if (ret != 0)
+		LOG_DBG("%s: Failed to free adapter\n", __func__);
+
+	/* Drain the eventdev of events, so subsequent tests are not affected */
+	while ((n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
+					    RTE_DIM(evs), 0)) > 0)
+		rte_delay_ms(10);
+}
+
+static int
+g_adapter_create_start(void)
+{
+	uint32_t evdev_service_id, adapter_service_id;
+
+	g_adapter_create();
+
+	/* retrieve service ids */
+	TEST_ASSERT_SUCCESS(rte_event_dev_service_id_get(evdev,
+			&evdev_service_id), "Failed to get event device "
+			"service id");
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(g_adapter,
+			&adapter_service_id), "Failed to get event timer "
+			"adapter service id");
+
+	/* add a service core and start it */
+	TEST_ASSERT_SUCCESS(rte_service_lcore_add(slcore_id),
+			"Failed to add service core");
+	TEST_ASSERT_SUCCESS(rte_service_lcore_start(slcore_id),
+			"Failed to start service core");
+
+	/* map services to it */
+	TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(evdev_service_id,
+			slcore_id, 1), "Failed to map evdev service");
+	TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(adapter_service_id,
+			slcore_id, 1), "Failed to map adapter service");
+
+	/* set services to running */
+	TEST_ASSERT_SUCCESS(rte_service_runstate_set(evdev_service_id, 1),
+			"Failed to start evdev service");
+	TEST_ASSERT_SUCCESS(rte_service_runstate_set(adapter_service_id, 1),
+			"Failed to start event timer adapter service");
+
+	/* start the eventdev */
+	TEST_ASSERT_SUCCESS(rte_event_dev_start(evdev),
+			"Failed to start event device");
+
+	/* start the timer event adapter */
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_start(g_adapter),
+			"Failed to start event timer adapter");
+
+	return TEST_SUCCESS;
+}
+
+static void
+g_adapter_stop_free(void)
+{
+	int ret;
+	uint32_t evdev_service_id, adapter_service_id;
+
+	/* Stop the event timer adapter */
+	ret = rte_event_timer_adapter_stop(g_adapter);
+	if (ret != 0)
+		LOG_DBG("%s: Failed to stop adapter, ret = %d\n", __func__,
+			ret);
+
+	/* Stop the eventdev */
+	rte_event_dev_stop(evdev);
+
+	/* set services to stopped */
+	ret = rte_event_dev_service_id_get(evdev, &evdev_service_id);
+	if (ret != 0)
+		LOG_DBG("%s: Failed to get event device service id\n",
+			__func__);
+
+	ret = rte_event_timer_adapter_service_id_get(g_adapter,
+						     &adapter_service_id);
+	if (ret != 0)
+		LOG_DBG("%s: Failed to get event timer adapter service id\n",
+		       __func__);
+
+	ret = rte_service_runstate_set(evdev_service_id, 0);
+	if (ret != 0)
+		LOG_DBG("%s: Failed to stop evdev service\n", __func__);
+
+	ret = rte_service_runstate_set(adapter_service_id, 0);
+	if (ret != 0)
+		LOG_DBG("%s: Failed to stop event timer adapter service\n",
+		       __func__);
+
+	g_adapter_free();
+
+	/* unmap all the services and service cores */
+	rte_service_lcore_reset_all();
+}
+
+/* ----------------    Tests  --------------------*/
+
+/* Check that the adapter can be created correctly */
+static int
+adapter_create(void)
+{
+	int adapter_id = 0;
+	struct rte_event_timer_adapter *adapter, *adapter2;
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev + 1,  // invalid event dev id
+		.timer_adapter_id = adapter_id,
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = NB_TEST_EVENT_TIMERS,
+		.flags = 0,
+	};
+
+	/* Test invalid conf */
+	adapter = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapter, "Created adapter with invalid "
+			"event device id");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Incorrect errno value for "
+			"invalid event device id");
+
+	/* Test valid conf */
+	conf.event_dev_id = evdev;
+	adapter = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NOT_NULL(adapter, "Failed to create adapter with valid "
+			"configuration");
+
+	/* Test existing id */
+	adapter2 = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapter2, "Created adapter with in-use id");
+	TEST_ASSERT(rte_errno == EEXIST, "Incorrect errno value for existing "
+			"id");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapter),
+			"Failed to free adapter");
+
+	return TEST_SUCCESS;
+}
+
+/* This port conf callback is used by the max adapter instance creation test.
+ * Because that test may be limited by the number of ports available in the
+ * event device, this callback allocates just one port and returns it each
+ * time a port is requested.
+ */
+static int
+test_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		  void *conf_arg)
+{
+	struct rte_eventdev *dev;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	int started;
+	static int port_allocated;
+	static uint8_t port_id;
+	uint8_t dev_id;
+	int ret;
+
+	if (port_allocated) {
+		*event_port_id = port_id;
+		return 0;
+	}
+
+	RTE_SET_USED(id);
+
+	dev = &rte_eventdevs[event_dev_id];
+	dev_id = dev->data->dev_id;
+	dev_conf = dev->data->dev_conf;
+
+	started = dev->data->dev_started;
+	if (started)
+		rte_event_dev_stop(dev_id);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports += 1;
+	ret = rte_event_dev_configure(dev_id, &dev_conf);
+	if (ret < 0) {
+		if (started)
+			rte_event_dev_start(dev_id);
+
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(dev_id, port_id, port_conf);
+	if (ret < 0)
+		return ret;
+
+	*event_port_id = port_id;
+
+	if (started)
+		rte_event_dev_start(dev_id);
+
+	port_allocated = 1;
+
+	return 0;
+}
+
+static int
+adapter_create_max(void)
+{
+	int i;
+	uint32_t svc_start_count, svc_end_count;
+	struct rte_event_timer_adapter *adapters[
+					RTE_EVENT_TIMER_ADAPTER_NUM_MAX + 1];
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev,
+		// timer_adapter_id set in loop
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = NB_TEST_EVENT_TIMERS,
+		.flags = 0,
+	};
+
+	svc_start_count = rte_service_get_count();
+
+	/* This test expects that there are sufficient service IDs available
+	 * to be allocated. I.e., RTE_EVENT_TIMER_ADAPTER_NUM_MAX may need to
+	 * be less than RTE_SERVICE_NUM_MAX if anything else uses a service
+	 * (the SW event device, for example).
+	 */
+	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) {
+		conf.timer_adapter_id = i;
+		adapters[i] = rte_event_timer_adapter_create_ext(&conf,
+				test_port_conf_cb, NULL);
+		TEST_ASSERT_NOT_NULL(adapters[i], "Failed to create adapter "
+				"%d", i);
+	}
+
+	conf.timer_adapter_id = i;
+	adapters[i] = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapters[i], "Created too many adapters");
+
+	/* Check that at least RTE_EVENT_TIMER_ADAPTER_NUM_MAX services
+	 * have been created
+	 */
+	svc_end_count = rte_service_get_count();
+	TEST_ASSERT_EQUAL(svc_end_count - svc_start_count,
+			RTE_EVENT_TIMER_ADAPTER_NUM_MAX,
+			"Failed to create expected number of services");
+
+	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++)
+		TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapters[i]),
+				"Failed to free adapter %d", i);
+
+	/* Check that service count is back to where it was at start */
+	svc_end_count = rte_service_get_count();
+	TEST_ASSERT_EQUAL(svc_start_count, svc_end_count, "Failed to release "
+			  "correct number of services");
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter can be freed correctly. */
+static int
+adapter_free(void)
+{
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(g_adapter),
+			"Failed to free valid adapter");
+
+	/* Test free of already freed adapter */
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_free(g_adapter),
+			"Freed adapter that was already freed");
+
+	/* Test free of null adapter */
+	g_adapter = NULL;
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_free(g_adapter),
+			"Freed null adapter");
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter info can be retrieved and is correct. */
+static int
+adapter_get_info(void)
+{
+	struct rte_event_timer_adapter_info info;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_get_info(g_adapter, &info),
+			"Failed to get adapter info");
+
+	TEST_ASSERT_EQUAL(info.event_dev_port_id, 1, "Expected port id = 1,"
+			"got port id = %d", info.event_dev_port_id);
+
+	return TEST_SUCCESS;
+}
+
+/* Test adapter lookup via adapter ID. */
+static int
+adapter_lookup(void)
+{
+	struct rte_event_timer_adapter *adapter;
+
+	adapter = rte_event_timer_adapter_lookup(TEST_ADAPTER_ID);
+	TEST_ASSERT_NOT_NULL(adapter, "Failed to lookup adapter");
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter starts correctly. */
+static int
+adapter_start(void)
+{
+	uint32_t evdev_service_id, adapter_service_id;
+	struct rte_event_timer_adapter *l_adapter = NULL;
+
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_start(l_adapter),
+			 "Erroneously started null adapter");
+
+	/* Check that we fail when no service core is mapped */
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_start(g_adapter),
+			 "Erroneously started adapter with no service core "
+			 "mapped");
+
+	/* retrieve service ids */
+	TEST_ASSERT_SUCCESS(rte_event_dev_service_id_get(evdev,
+			&evdev_service_id), "Failed to get event device "
+			"service id");
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(g_adapter,
+			&adapter_service_id), "Failed to get event timer "
+			"adapter service id");
+
+	/* add a service core and start it */
+	TEST_ASSERT_SUCCESS(rte_service_lcore_add(slcore_id),
+			"Failed to add service core");
+	TEST_ASSERT_SUCCESS(rte_service_lcore_start(slcore_id),
+			"Failed to start service core");
+
+	/* map services to it */
+	TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(evdev_service_id,
+			slcore_id, 1), "Failed to map evdev service");
+	TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(adapter_service_id,
+			slcore_id, 1), "Failed to map adapter service");
+
+	/* set services to running */
+	TEST_ASSERT_SUCCESS(rte_service_runstate_set(evdev_service_id, 1),
+			"Failed to start evdev service");
+	TEST_ASSERT_SUCCESS(rte_service_runstate_set(adapter_service_id, 1),
+			"Failed to start event timer adapter service");
+
+	/* start the eventdev */
+	TEST_ASSERT_SUCCESS(rte_event_dev_start(evdev),
+			"Failed to start event device");
+
+	/* test adapter start */
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_start(g_adapter),
+			"Failed to start event timer adapter");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_start(g_adapter),
+			"Failed to repeatedly start adapter");
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter stops correctly. */
+static int
+adapter_stop(void)
+{
+	uint32_t evdev_service_id, adapter_service_id;
+	struct rte_event_timer_adapter *l_adapter = NULL;
+
+	/* retrieve service ids */
+	TEST_ASSERT_SUCCESS(rte_event_dev_service_id_get(evdev,
+			&evdev_service_id), "Failed to get event device "
+			"service id");
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(g_adapter,
+			&adapter_service_id), "Failed to get event timer "
+			"adapter service id");
+
+	/* Test adapter stop */
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stop(g_adapter),
+			"Failed to stop event adapter");
+
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_stop(l_adapter),
+			"Erroneously stopped null event adapter");
+
+	/* Stop the eventdev */
+	rte_event_dev_stop(evdev);
+
+	/* set services to stopped */
+	TEST_ASSERT_SUCCESS(rte_service_runstate_set(evdev_service_id, 0),
+			"Failed to stop evdev service");
+	TEST_ASSERT_SUCCESS(rte_service_runstate_set(adapter_service_id, 0),
+			"Failed to stop event timer adapter service");
+
+	/* Undo all service and core mappings */
+	rte_service_lcore_reset_all();
+
+	return TEST_SUCCESS;
+}
+
+/* Test increment and reset of ev_enq_count stat */
+static int
+stat_inc_reset_ev_enq(void)
+{
+	int ret, i, n;
+	int num_evtims = NB_TEST_EVENT_TIMERS;
+	struct rte_event_timer *evtims[num_evtims];
+	struct rte_event evs[BATCH_SIZE];
+	struct rte_event_timer_adapter_stats stats;
+
+	ret = rte_mempool_get_bulk(g_event_timer_pool, (void **)evtims,
+				   num_evtims);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
+			  ret);
+
+	for (i = 0; i < num_evtims; i++) {
+		rte_event_timer_init(evtims[i]);
+		evtims[i]->ev.event_ptr = evtims[i];
+		evtims[i]->ev.queue_id = TEST_QUEUE_ID;
+		evtims[i]->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+		evtims[i]->timeout_ticks = 5;  // expire in .5 sec
+	}
+
+	ret = rte_event_timer_adapter_stats_get(g_adapter, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0, "Stats not clear at "
+			  "startup");
+
+	/* Test with the max value for the adapter */
+	ret = rte_event_timer_arm_burst(g_adapter, evtims, num_evtims);
+	TEST_ASSERT_EQUAL(ret, num_evtims,
+			  "Failed to arm all event timers: attempted = %d, "
+			  "succeeded = %d, rte_errno = %s",
+			  num_evtims, ret, rte_strerror(rte_errno));
+
+	rte_delay_ms(1000);
+
+#define MAX_TRIES 1000
+	int sum = 0;
+	int tries = 0;
+	bool done = false;
+	while (!done) {
+		sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
+					       RTE_DIM(evs), 10);
+		if (sum >= num_evtims || ++tries >= MAX_TRIES)
+			done = true;
+
+		rte_delay_ms(10);
+	}
+
+	TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
+			  "got %d", num_evtims, sum);
+
+	TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");
+
+	rte_delay_ms(100);
+
+	/* Make sure the eventdev is still empty */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
+				      10);
+
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
+			  "events from event device");
+
+	/* Check stats again */
+	ret = rte_event_timer_adapter_stats_get(g_adapter, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, num_evtims,
+			  "Expected enqueue stat = %d; got %d", num_evtims,
+			  (int)stats.ev_enq_count);
+
+	/* Reset and check again */
+	ret = rte_event_timer_adapter_stats_reset(g_adapter);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to reset stats");
+
+	ret = rte_event_timer_adapter_stats_get(g_adapter, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0,
+			  "Expected enqueue stat = %d; got %d", 0,
+			  (int)stats.ev_enq_count);
+
+	rte_mempool_put_bulk(g_event_timer_pool, (void **)evtims, num_evtims);
+
+	return TEST_SUCCESS;
+}
+
+/* Test various cases in arming timers */
+static int
+event_timer_arm(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = g_adapter;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+
+	rte_mempool_get(g_event_timer_pool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	rte_event_timer_init(evtim);
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.queue_id = TEST_QUEUE_ID;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+	evtim->timeout_ticks = 5;  // expire in 0.5 sec
+
+	/* Test single timer arm succeeds */
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event timer "
+			  "in incorrect state");
+
+	/* Test arm of armed timer fails */
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "expected return value from "
+			  "rte_event_timer_arm_burst: 0, got: %d", ret);
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after arming already armed timer");
+
+	/* Let timer expire */
+	rte_delay_ms(1000);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	rte_mempool_put(g_event_timer_pool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* This test checks that repeated references to the same event timer in the
+ * arm request work as expected; only the first one through should succeed.
+ */
+static int
+event_timer_arm_double(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = g_adapter;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+
+	rte_mempool_get(g_event_timer_pool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	rte_event_timer_init(evtim);
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.queue_id = TEST_QUEUE_ID;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+	evtim->timeout_ticks = 5;  // expire in 0.5 sec
+
+	struct rte_event_timer *evtim_arr[] = {evtim, evtim};
+	ret = rte_event_timer_arm_burst(adapter, evtim_arr, RTE_DIM(evtim_arr));
+	TEST_ASSERT_EQUAL(ret, 1, "Unexpected return value from "
+			  "rte_event_timer_arm_burst");
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after double-arm");
+
+	/* Let timer expire */
+	rte_delay_ms(600);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number of expiry events - "
+			  "expected: 1, actual: %d", n);
+
+	rte_mempool_put(g_event_timer_pool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Test the timer expiry event is generated at the expected time.  */
+static int
+event_timer_arm_expiry(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = g_adapter;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event_timer *evtim2 = NULL;
+	struct rte_event evs[BATCH_SIZE];
+
+	/* Set up an event timer */
+	rte_mempool_get(g_event_timer_pool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	rte_event_timer_init(evtim);
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.queue_id = TEST_QUEUE_ID;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event "
+			  "timer in incorrect state");
+
+	rte_delay_ms(2999);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event");
+
+	/* Delay 100 ms to account for the adapter tick window - should let us
+	 * dequeue one event
+	 */
+	rte_delay_ms(100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number (%d) of timer "
+			  "expiry events", n);
+	TEST_ASSERT_EQUAL(evs[0].event_type, RTE_EVENT_TYPE_TIMER,
+			  "Dequeued unexpected type of event");
+
+	/* Check that we recover the original event timer and then free it */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_NOT_ARMED, "Event "
+			  "timer in incorrect state");
+	rte_mempool_put(g_event_timer_pool, evtim2);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that rearming a timer works as expected. */
+static int
+event_timer_arm_rearm(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event_timer *evtim2 = NULL;
+	struct rte_event evs[BATCH_SIZE];
+
+	rte_mempool_get(g_event_timer_pool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	rte_event_timer_init(evtim);
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.queue_id = TEST_QUEUE_ID;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+	evtim->timeout_ticks = 1;  // expire in 0.1 sec
+
+	/* Arm it */
+	ret = rte_event_timer_arm_burst(g_adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+
+	/* Add 100ms to account for the adapter tick window */
+	rte_delay_ms(100 + 100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	/* Recover the timer through the event that was dequeued. */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+
+	/* Rearm it */
+	ret = rte_event_timer_arm_burst(g_adapter, &evtim2, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+
+	/* Add 100ms to account for the adapter tick window */
+	rte_delay_ms(100 + 100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	/* Free it */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+	rte_mempool_put(g_event_timer_pool, evtim2);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that creating an event timer with incorrect event sched type fails. */
+static int
+event_timer_arm_invalid_sched_type(void)
+{
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+
+	rte_mempool_get(g_event_timer_pool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	rte_event_timer_init(evtim);
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.queue_id = TEST_QUEUE_ID;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_PARALLEL; // bad sched type
+	evtim->timeout_ticks = 5;  // expire in 0.5 sec
+
+	ret = rte_event_timer_arm_burst(g_adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "sched type, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid queue");
+
+	rte_mempool_put(g_event_timer_pool, &evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that creating an event timer with a timeout value that is too small or
+ * too big fails.
+ */
+static int
+event_timer_arm_invalid_timeout(void)
+{
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+
+	rte_mempool_get(g_event_timer_pool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	rte_event_timer_init(evtim);
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.queue_id = TEST_QUEUE_ID;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+	evtim->timeout_ticks = 0;  // timeout too small
+
+	ret = rte_event_timer_arm_burst(g_adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "timeout, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid timeout");
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOEARLY,
+			  "Unexpected event timer state");
+
+	rte_event_timer_init(evtim);
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.queue_id = TEST_QUEUE_ID;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+	evtim->timeout_ticks = 1801;  // timeout too big
+
+	ret = rte_event_timer_arm_burst(g_adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "timeout, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid timeout");
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOLATE,
+			  "Unexpected event timer state");
+
+	rte_mempool_put(g_event_timer_pool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that the adapter handles the max specified number of timers as
+ * expected.
+ */
+static int
+event_timer_arm_max(void)
+{
+	int ret, i, n;
+	int num_evtims = NB_TEST_EVENT_TIMERS;
+	struct rte_event_timer *evtims[num_evtims];
+	struct rte_event evs[BATCH_SIZE];
+
+	ret = rte_mempool_get_bulk(g_event_timer_pool, (void **)evtims,
+				   num_evtims);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
+			  ret);
+
+	for (i = 0; i < num_evtims; i++) {
+		rte_event_timer_init(evtims[i]);
+		evtims[i]->ev.event_ptr = evtims[i];
+		evtims[i]->ev.queue_id = TEST_QUEUE_ID;
+		evtims[i]->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+		evtims[i]->timeout_ticks = 5;  // expire in .5 sec
+	}
+
+	/* Test with the max value for the adapter */
+	ret = rte_event_timer_arm_burst(g_adapter, evtims, num_evtims);
+	TEST_ASSERT_EQUAL(ret, num_evtims,
+			  "Failed to arm all event timers: attempted = %d, "
+			  "succeeded = %d, rte_errno = %s",
+			  num_evtims, ret, rte_strerror(rte_errno));
+
+	rte_delay_ms(1000);
+
+#define MAX_TRIES 1000
+	int sum = 0;
+	int tries = 0;
+	bool done = false;
+	while (!done) {
+		sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
+					       RTE_DIM(evs), 10);
+		if (sum >= num_evtims || ++tries >= MAX_TRIES)
+			done = true;
+
+		rte_delay_ms(10);
+	}
+
+	TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
+			  "got %d", num_evtims, sum);
+
+	TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");
+
+	rte_delay_ms(100);
+
+	/* Make sure the eventdev is still empty */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
+				      10);
+
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
+			  "events from event device");
+
+	rte_mempool_put_bulk(g_event_timer_pool, (void **)evtims, num_evtims);
+
+	return TEST_SUCCESS;
+}
+
+static int
+event_timer_cancel(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = g_adapter;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+
+	rte_mempool_get(g_event_timer_pool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Check that cancelling an uninited timer fails */
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling "
+			  "uninited timer");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after "
+			  "cancelling uninited timer");
+
+	/* Set up a timer */
+	rte_event_timer_init(evtim);
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.queue_id = TEST_QUEUE_ID;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	/* Check that cancelling an inited but unarmed timer fails */
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling "
+			  "unarmed timer");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after "
+			  "cancelling unarmed timer");
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED,
+			  "evtim in incorrect state");
+
+	/* Delay 1 sec */
+	rte_delay_ms(1000);
+
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to cancel event_timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_CANCELED,
+			  "evtim in incorrect state");
+
+	rte_delay_ms(3000);
+
+	/* Make sure that no expiry event was generated */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");
+
+	return TEST_SUCCESS;
+}
+
+static int
+event_timer_cancel_double(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = g_adapter;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+
+	rte_mempool_get(g_event_timer_pool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	rte_event_timer_init(evtim);
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.queue_id = TEST_QUEUE_ID;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED,
+			  "timer in unexpected state");
+
+	/* Now, test that referencing the same timer twice in the same call
+	 * fails
+	 */
+	struct rte_event_timer *evtim_arr[] = {evtim, evtim};
+	ret = rte_event_timer_cancel_burst(adapter, evtim_arr,
+					   RTE_DIM(evtim_arr));
+
+	/* Two requests to cancel same timer, only one should succeed */
+	TEST_ASSERT_EQUAL(ret, 1, "Succeeded unexpectedly in canceling timer "
+			  "twice");
+
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after double-cancel: rte_errno = %d", rte_errno);
+
+	rte_delay_ms(3000);
+
+	/* Still make sure that no expiry event was generated */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");
+
+	return TEST_SUCCESS;
+}
+
+/* Check that event timer adapter tick resolution works as expected by testing
+ * the number of adapter ticks that occur within a particular time interval.
+ */
+static int
+adapter_tick_resolution(void)
+{
+	struct rte_event_timer_adapter_stats stats;
+	uint64_t adapter_tick_count;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(g_adapter,
+			&stats), "Failed to get adapter stats");
+	TEST_ASSERT_EQUAL(stats.adapter_tick_count, 0, "Adapter tick count "
+			"not zeroed out");
+
+	/* Delay 1 second; should let at least 10 ticks occur with the default
+	 * adapter configuration used by this test.
+	 */
+	rte_delay_ms(1000);
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(g_adapter,
+			&stats), "Failed to get adapter stats");
+
+	adapter_tick_count = stats.adapter_tick_count;
+	TEST_ASSERT(adapter_tick_count >= 10 && adapter_tick_count <= 12,
+			"Expected 10-12 adapter ticks, got %"PRIu64"\n",
+			adapter_tick_count);
+
+	return TEST_SUCCESS;
+}
+
+static struct unit_test_suite adapter_tests  = {
+	.suite_name = "event timer adapter test suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE(adapter_create),
+		TEST_CASE_ST(g_adapter_create, NULL, adapter_free),
+		TEST_CASE_ST(g_adapter_create, g_adapter_free,
+				adapter_get_info),
+		TEST_CASE_ST(g_adapter_create, g_adapter_free,
+				adapter_lookup),
+		TEST_CASE_ST(g_adapter_create, g_adapter_stop_free,
+				adapter_start),
+		TEST_CASE_ST(g_adapter_create_start, g_adapter_free,
+				adapter_stop),
+		TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free,
+				stat_inc_reset_ev_enq),
+		TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free,
+				event_timer_arm),
+		TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free,
+				event_timer_arm_double),
+		TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free,
+				event_timer_arm_expiry),
+		TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free,
+				event_timer_arm_rearm),
+		TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free,
+				event_timer_arm_max),
+		TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free,
+				event_timer_arm_invalid_sched_type),
+		TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free,
+				event_timer_arm_invalid_timeout),
+		TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free,
+				event_timer_cancel),
+		TEST_CASE_ST(g_adapter_create_start, g_adapter_stop_free,
+				event_timer_cancel_double),
+		TEST_CASE_ST(g_adapter_create_start,
+				g_adapter_stop_free,
+				adapter_tick_resolution),
+		/* This test is last because it can influence tests that follow
+		 * it
+		 */
+		TEST_CASE(adapter_create_max),
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+static int
+test_event_timer_adapter_common(void)
+{
+	return unit_test_suite_runner(&adapter_tests);
+}
+
+REGISTER_TEST_COMMAND(event_timer_adapter_autotest,
+		      test_event_timer_adapter_common);
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 6/7] doc: add event timer adapter section to programmer's guide
  2018-03-08 21:53     ` [PATCH v7 0/7] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                         ` (4 preceding siblings ...)
  2018-03-08 21:54       ` [PATCH v7 5/7] test: add event timer adapter auto-test Erik Gabriel Carrillo
@ 2018-03-08 21:54       ` Erik Gabriel Carrillo
  2018-03-12 11:21         ` Jerin Jacob
  2018-03-08 21:54       ` [PATCH v7 7/7] doc: add event timer adapter documentation Erik Gabriel Carrillo
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  7 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-08 21:54 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
---
 doc/guides/prog_guide/event_timer_adapter.rst | 277 ++++++++++++++++++++++++++
 doc/guides/prog_guide/index.rst               |   1 +
 2 files changed, 278 insertions(+)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst

diff --git a/doc/guides/prog_guide/event_timer_adapter.rst b/doc/guides/prog_guide/event_timer_adapter.rst
new file mode 100644
index 0000000..423b91d
--- /dev/null
+++ b/doc/guides/prog_guide/event_timer_adapter.rst
@@ -0,0 +1,277 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(c) 2017 Intel Corporation. All rights reserved.
+
+Event Timer Adapter Library
+=================================
+
+The DPDK
+`Event Device library <http://dpdk.org/doc/guides/prog_guide/eventdev.html>`_
+introduces an event driven programming model which presents applications with
+an alternative to the polling model traditionally used in DPDK
+applications. Event devices can be coupled with arbitrary components to provide
+new event sources by using **event adapters**. The Event Timer Adapter is one
+such adapter; it bridges event devices and timer mechanisms.
+
+The Event Timer Adapter library extends the event driven model
+by introducing a :ref:`new type of event <timer_expiry_event>` that represents
+a timer expiration, and providing an API with which adapters can be created or
+destroyed, and :ref:`event timers <event_timer>` can be armed and canceled.
+
+The Event Timer Adapter library is designed to interface with hardware or
+software implementations of the timer mechanism; it will query an eventdev PMD
+to determine which implementation should be used.  The default software
+implementation manages timers using the DPDK
+`Timer library <http://dpdk.org/doc/guides/prog_guide/timer_lib.html>`_.
+
+Examples of using the API are presented in the `API Overview`_ and
+`Processing Timer Expiry Events`_ sections.  Code samples are abstracted and
+are based on the example of handling a TCP retransmission.
+
+.. _event_timer:
+
+Event Timer struct
+------------------
+Event timers are timers that enqueue a timer expiration event to an event
+device upon firing.
+
+The Event Timer Adapter API represents each event timer with a generic struct,
+which contains an event and user metadata.  The ``rte_event_timer`` struct is
+defined in ``lib/librte_event/librte_event_timer_adapter.h``.
+
+.. _timer_expiry_event:
+
+Timer Expiry Event
+~~~~~~~~~~~~~~~~~~
+
+The event contained by an event timer is enqueued in the event device when the
+timer expires, and the event device uses the attributes below when scheduling
+it:
+
+* ``event_queue_id`` - Application should set this to specify an event queue to
+  which the timer expiry event should be enqueued
+* ``event_priority`` - Application can set this to indicate the priority of the
+  timer expiry event in the event queue relative to other events
+* ``sched_type`` - Application can set this to specify the scheduling type of
+  the timer expiry event
+* ``flow_id`` - Application can set this to indicate which flow this timer
+  expiry event corresponds to
+* ``op`` - Will be set to ``RTE_EVENT_OP_NEW`` by the event timer adapter
+* ``event_type`` - Will be set to ``RTE_EVENT_TYPE_TIMER`` by the event timer
+  adapter
+
+Timeout Ticks
+~~~~~~~~~~~~~
+
+The number of ticks from now in which the timer will expire. The ticks value
+has a resolution (``timer_tick_ns``) that is specified in the event timer
+adapter configuration.
+
+User Metadata
+~~~~~~~~~~~~~
+
+Memory to store user specific metadata.  The event timer adapter implementation
+will not modify this area.
+
+API Overview
+----------------
+
+This section will introduce the reader to the event timer adapter API, showing
+how to create and configure an event timer adapter and use it to manage event
+timers.
+
+From a high level, the setup steps are:
+
+* rte_event_timer_adapter_create()
+* rte_event_timer_adapter_start()
+
+And to start and stop timers:
+
+* rte_event_timer_init()
+* rte_event_timer_arm_burst()
+* rte_event_timer_cancel_burst()
+
+Create and Configure an Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To create an event timer adapter instance, initialize an
+``rte_event_timer_adapter_conf`` struct with the desired values, and pass it
+to ``rte_event_timer_adapter_create()``.
+
+.. code-block:: c
+
+	#define NSECPERSEC 1E9 // No of ns in 1 sec
+	const struct rte_event_timer_adapter_config adapter_config = {
+                .event_dev_id = event_dev_id,
+                .timer_adapter_id = 0,
+                .clk_src = RTE_EVENT_TIMER_WHEEL_CPU_CLK,
+                .timer_tick_ns = NSECPERSEC / 10, // 100 milliseconds
+                .max_tmo_nsec = 180 * NSECPERSEC // 2 minutes
+                .nb_timers = 40000,
+                .timer_adapter_flags = 0,
+	};
+
+	struct rte_event_timer_adapter *adapter = NULL;
+	adapter = rte_event_timer_adapter_create(&adapter_config);
+
+	if (adapter == NULL) { ... };
+
+Before creating an instance of a timer adapter, the application should create
+and configure an event device along with its event ports. Based on the event
+device capability, it might require creating an additional event port to be
+used by the timer adapter.  If required, the
+``rte_event_timer_adapter_create()`` function will use a default method to
+configure an event port;  it will examine the current event device
+configuration, determine the next available port identifier number, and create
+a new event port with a default port configuration.
+
+If the application desires to have finer control of event port allocation
+and setup, it can use the ``rte_event_timer_adapter_create_ext()`` function.
+This function is passed a callback function that will be invoked if the
+adapter needs to create an event port, giving the application the opportunity
+to control how it is done.
+
+Retrieve Event Timer Adapter Contextual Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The event timer adapter implementation may have constraints on tick resolution
+or maximum timer expiry timeout based on the given event timer adapter or
+system.  In this case, the implementation may adjust the tick resolution or
+maximum timeout to the best possible configuration.
+
+Upon successful event timer adapter creation, the application can get the
+configured resolution and max timeout with
+``rte_event_timer_adapter_get_info()``. This function will return an
+``rte_event_timer_adapter_info`` struct, which contains the following members:
+
+* ``min_resolution_ns`` - Minimum timer adapter tick resolution in ns.
+* ``max_tmo_ns`` - Maximum timer timeout(expiry) in ns.
+* ``adapter_conf`` - Configured event timer adapter attributes
+
+Configuring the Service Component
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the adapter uses a service component, the application is required to map
+the service to a service core before starting the adapter:
+
+.. code-block:: c
+
+        uint32_t service_id;
+
+        if (rte_event_timer_adapter_service_id_get(adapter, &service_id) == 0)
+                rte_service_map_lcore_set(service_id, EVTIM_CORE_ID);
+
+An event timer adapter uses a service component if the event device PMD
+indicates that the adapter should use a software implementation.
+
+Starting the Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The application should call ``rte_event_timer_adapter_start()`` to start
+running the event timer adapter. This function calls the start entry points
+defined by eventdev PMDs for hardware implementations or puts a service
+component into the running state in the software implementation.
+
+Arming Event Timers
+~~~~~~~~~~~~~~~~~~~~~
+
+Once an event timer adapter has been started, an application can begin to
+manage event timers with it.
+
+The application should allocate ``struct rte_event_timer`` objects from a
+mempool or huge-page backed application buffers of required size. Upon
+successful allocation, the application should initialize the event timer, and
+then set any of the necessary event attributes described in the
+`Timer Expiry Event`_ section. In the following example, assume ``conn``
+represents a TCP connection and that ``event_timer_pool`` is a mempool that
+was created previously:
+
+.. code-block:: c
+
+	rte_mempool_get(event_timer_pool, (void **)&conn->evtim);
+	if (conn->evtim == NULL) { ... }
+
+        rte_event_timer_init(&conn->evtim);
+
+	/* Set up the expiry event. */
+	conn->evtim->ev.event_ptr = conn;
+	conn->evtim->ev.queue_id = event_queue_id;
+	...
+	conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns)
+
+Note that we have saved a pointer to the ``conn`` object in the timer's event
+payload. This will allow us to locate the connection object again once we
+dequeue the timer expiry event from the event device later.
+
+Now we can arm the event timer with ``rte_event_timer_arm_burst()``:
+
+.. code-block:: c
+
+	ret = rte_event_timer_arm_burst(adapter, &conn->evtim, 1);
+	if (ret != 1) { ... }
+
+Multiple Event Timers with Same Expiry Value
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the special case that there is a set of event timers that should all expire
+at the same time, the application may call
+``rte_event_timer_arm_tmo_tick_burst()``, which allows the implementation to
+optimize the operation if possible.
+
+Canceling Event Timers
+~~~~~~~~~~~~~~~~~~~~~~~
+
+An event timer that has been armed as described in `Arming Event Timers`_ can
+be canceled by calling ``rte_event_timer_cancel_burst()``:
+
+.. code-block:: c
+
+	/* Ack for the previous tcp data packet has been received;
+	 * cancel the retransmission timer
+         */
+	rte_event_timer_cancel_burst(adapter, &conn->timer, 1);
+
+Processing Timer Expiry Events
+------------------------------
+
+Once an event timer has successfully enqueued a timer expiry event in the event
+device, the application will subsequently dequeue it from the event device.
+The application can use the event payload to retrieve a pointer to the object
+associated with the event timer. It can then re-arm the event timer or free the
+event timer object as desired:
+
+.. code-block:: c
+
+	void
+	event_processing_loop(...)
+	{
+		while (...) {
+			/* Receive events from the configured event port. */
+			rte_event_dequeue_burst(event_dev_id, event_port, &ev, 1, 0);
+			...
+			switch(ev.event_type) {
+				...
+				case RTE_EVENT_TYPE_TIMER:
+					process_timer_event(ev);
+					...
+					break;
+			}
+		}
+	}
+
+	uint8_t
+	process_timer_event(...)
+	{
+		/* A retransmission timeout for the connection has been received. */
+		conn = ev.event_ptr;
+		/* Retransmit last packet (e.g. TCP segment). */
+		...
+		/* Re-arm timer using original values. */
+		rte_event_timer_arm_burst(wheel_id, &conn->timer, 1);
+	}
+
+Summary
+-------
+
+The Event Timer Adapter library extends the DPDK event-based programming model
+by representing timer expirations as events in the system and allowing
+applications to use existing event processing loops to arm and cancel event
+timers or handle timer expiry events.
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index bbbe789..589c05d 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -42,6 +42,7 @@ Programmer's Guide
     thread_safety_dpdk_functions
     eventdev
     event_ethernet_rx_adapter
+    event_timer_adapter
     qos_framework
     power_man
     packet_classif_access_ctrl
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v7 7/7] doc: add event timer adapter documentation
  2018-03-08 21:53     ` [PATCH v7 0/7] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                         ` (5 preceding siblings ...)
  2018-03-08 21:54       ` [PATCH v7 6/7] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
@ 2018-03-08 21:54       ` Erik Gabriel Carrillo
  2018-03-12 11:28         ` Jerin Jacob
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  7 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-08 21:54 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 MAINTAINERS                            |  7 +++++++
 doc/api/doxy-api-index.md              | 32 +++-----------------------------
 doc/guides/rel_notes/release_18_05.rst |  5 +++++
 3 files changed, 15 insertions(+), 29 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index a646ca3..abebf6d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -317,6 +317,13 @@ F: lib/librte_eventdev/*eth_rx_adapter*
 F: test/test/test_event_eth_rx_adapter.c
 F: doc/guides/prog_guide/event_ethernet_rx_adapter.rst
 
+Eventdev Timer Adapter API - EXPERIMENTAL
+M: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
+T: git://dpdk.org/next/dpdk-next-eventdev
+F: lib/librte_eventdev/*timer_adapter*
+F: test/test/test_event_timer_adapter.c
+F: doc/guides/prog_guide/event_timer_adapter.rst
+
 Raw device API - EXPERIMENTAL
 M: Shreyansh Jain <shreyansh.jain@nxp.com>
 M: Hemant Agrawal <hemant.agrawal@nxp.com>
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..5c6cd51 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -2,35 +2,8 @@ API {#index}
 ===
 
 <!--
-  BSD LICENSE
-
-  Copyright 2013-2017 6WIND S.A.
-
-  Redistribution and use in source and binary forms, with or without
-  modification, are permitted provided that the following conditions
-  are met:
-
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in
-      the documentation and/or other materials provided with the
-      distribution.
-    * Neither the name of 6WIND S.A. nor the names of its
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
-
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright(c) 2013-2017 6WIND S.A.
 -->
 
 The public API headers are grouped by topics:
@@ -47,6 +20,7 @@ The public API headers are grouped by topics:
   [security]           (@ref rte_security.h),
   [eventdev]           (@ref rte_eventdev.h),
   [event_eth_rx_adapter]   (@ref rte_event_eth_rx_adapter.h),
+  [event_timer_adapter]    (@ref rte_event_timer_adapter.h),
   [rawdev]             (@ref rte_rawdev.h),
   [metrics]            (@ref rte_metrics.h),
   [bitrate]            (@ref rte_bitrate.h),
diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst
index 3923dc2..2b93a1e 100644
--- a/doc/guides/rel_notes/release_18_05.rst
+++ b/doc/guides/rel_notes/release_18_05.rst
@@ -41,6 +41,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added the Event Timer Adapter Library.**
+
+  The Event Timer Adapter Library extends the event-based model by introducing
+  APIs that allow applications to generate timer expiry events that are
+  scheduled by an event device along with existing types of events.
 
 API Changes
 -----------
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 1/7] eventtimer: add event timer adapter API
  2018-03-08 21:54       ` [PATCH v7 1/7] eventtimer: add event timer adapter API Erik Gabriel Carrillo
@ 2018-03-12  7:53         ` Jerin Jacob
  2018-03-12 16:22           ` Carrillo, Erik G
  0 siblings, 1 reply; 133+ messages in thread
From: Jerin Jacob @ 2018-03-12  7:53 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal

-----Original Message-----
> Date: Thu, 8 Mar 2018 15:54:00 -0600
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com,
>  hemant.agrawal@nxp.com
> Subject: [PATCH v7 1/7] eventtimer: add event timer adapter API
> X-Mailer: git-send-email 1.7.10

IMO, you can add some git commit description here.

> 
> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  lib/librte_eventdev/Makefile                  |   1 +
>  lib/librte_eventdev/rte_event_timer_adapter.h | 645 ++++++++++++++++++++++++++
>  lib/librte_eventdev/rte_eventdev.h            |  41 +-
>  3 files changed, 653 insertions(+), 34 deletions(-)
>  create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h
> 
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this structure may change without prior notice
> + *
> + * Timer adapter configuration structure
> + */
> +struct rte_event_timer_adapter_conf {
> +	uint8_t event_dev_id;
> +	/**< Event device identifier */
> +	uint16_t timer_adapter_id;
> +	/**< Event timer adapter identifier */
> +	uint32_t socket_id;
> +	/**< Identifer of socket from which to allocate memory for adapter */

s/Identifer/Identifier

> +	enum rte_event_timer_adapter_clk_src clk_src;
> +	/**< Clock source for timer adapter */
> +	uint64_t timer_tick_ns;
> +	/**< Timer adapter resolution in ns */
> +	uint64_t max_tmo_ns;
> +	/**< Maximum timer timeout(expiry) in ns */
> +	uint64_t nb_timers;
> +	/**< Total number of timers per adapter */
> +	uint64_t flags;
> +	/**< Timer adapter config flags (RTE_EVENT_TIMER_ADAPTER_F_*) */
> +};
> +/**
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice
> + *
> + * Set an event timer's initial state and initialize the event it carries.
> + *
> + * @param evtim
> + *   A pointer to an event timer structure.
> + */
> +void __rte_experimental
> +rte_event_timer_init(struct rte_event_timer *evtim);

Since it can be used in fastpath, How about making it as "static inline" function?
Any it is just setting some variables.

> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice
> + *
> + * Arm a burst of event timers with separate expiration timeout tick for each
> + * event timer.
> + *
> + * Before calling this function, the application allocates
> + * ``struct rte_event_timer`` objects from mempool or huge page backed
> + * application buffers of desired size. On successful allocation,
> + * application updates the `struct rte_event_timer`` attributes such as
> + * expiry event attributes, timeout ticks from now.
> + * This function submits the event timer arm requests to the event timer adapter
> + * and on expiry, the events will be injected to designated event queue.
> + *
> + * @param adapter
> + *   A pointer to an event timer adapter structure.
> + * @param evtims
> + *   Pointer to an array of objects of type *rte_event_timer* structure.
> + * @param nb_evtims
> + *   Number of event timers in the supplied array.
> + *
> + * @return
> + *   The number of successfully armed event timers. The return value can be less
> + *   than the value of the *nb_evtims* parameter. If the return value is less
> + *   than *nb_evtims*, the remaining event timers at the end of *evtims*
> + *   are not consumed, and the caller has to take care of them, and rte_errno
> + *   is set accordingly. Possible errno values include:
> + *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
> + *   expiry event's sched type doesn't match the capabilities of the
> + *   destination event queue.
> + *   - EAGAIN Specified timer adapter is not running
> + *   - EALREADY A timer was encountered that was already armed
> + */
> +int __rte_experimental

To maintain the consistency across eventdev and other subsystems in DPDK.
We could return uint16_t for all the fast path functions. ie. exiting
"int" error return can be changed to 

rte_errno = -EINVAL;
return 0;

This would avoid some series typecasting issues as well for the _retry_
case.

> +rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
> +		struct rte_event_timer **evtims,
> +		uint16_t nb_evtims);
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice
> + *
> + * Arm a burst of event timers with same expiration timeout tick.
> + *
> + * Provides the same functionality as ``rte_event_timer_arm_burst()``, except
> + * that application can use this API when all the event timers have the
> + * same timeout expiration tick. This specialized function can provide the
> + * additional hint to the adapter implementation and optimize if possible.
> + *
> + * @param adapter
> + *   A pointer to an event timer adapter structure.
> + * @param evtims
> + *   Points to an array of objects of type *rte_event_timer* structure.
> + * @param timeout_ticks
> + *   The number of ticks in which the timers should expire.
> + * @param nb_evtims
> + *   Number of event timers in the supplied array.
> + *
> + * @return
> + *   The number of successfully armed event timers. The return value can be less
> + *   than the value of the *nb_evtims* parameter. If the return value is less
> + *   than *nb_evtims*, the remaining event timers at the end of *evtims*
> + *   are not consumed, and the caller has to take care of them, and rte_errno
> + *   is set accordingly. Possible errno values include:
> + *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
> + *   expiry event's sched type doesn't match the capabilities of the
> + *   destination event queue.
> + *   - EAGAIN Specified event timer adapter is not running
> + *   - EALREADY A timer was encountered that was already armed
> + */
> +int __rte_experimental

Same as above

> +rte_event_timer_arm_tmo_tick_burst(
> +		const struct rte_event_timer_adapter *adapter,
> +		struct rte_event_timer **evtims,
> +		const uint64_t timeout_ticks,
> +		const uint16_t nb_evtims);
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice
> + *
> + * Cancel a burst of event timers from being scheduled to the event device.
> + *
> + * @param adapter
> + *   A pointer to an event timer adapter structure.
> + * @param evtims
> + *   Points to an array of objects of type *rte_event_timer* structure
> + * @param nb_evtims
> + *   Number of event timer instances in the supplied array.
> + *
> + * @return
> + *   The number of successfully canceled event timers. The return value can be
> + *   less than the value of the *nb_evtims* parameter. If the return value is
> + *   less than *nb_evtims*, the remaining event timers at the end of *evtims*
> + *   are not consumed, and the caller has to take care of them, and rte_errno
> + *   is set accordingly. Possible errno values include:
> + *   - EINVAL Invalid timer adapter identifier
> + *   - EAGAIN Specified timer adapter is not running
> + *   - EALREADY  A timer was encountered that was already canceled
> + */
> +int __rte_experimental

Same as above

> +rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
> +		struct rte_event_timer **evtims,
> +		uint16_t nb_evtims);
> +
> +#endif /* __RTE_EVENT_TIMER_ADAPTER_H__ */
> diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
> index b21c271..f9ad71e 100644
> --- a/lib/librte_eventdev/rte_eventdev.h
> +++ b/lib/librte_eventdev/rte_eventdev.h
> @@ -1,35 +1,8 @@
> -/*
> - *   BSD LICENSE
> - *
> - *   Copyright 2016 Cavium, Inc.
> - *   Copyright 2016 Intel Corporation.
> - *   Copyright 2016 NXP.
> - *
> - *   Redistribution and use in source and binary forms, with or without
> - *   modification, are permitted provided that the following conditions
> - *   are met:
> - *
> - *     * Redistributions of source code must retain the above copyright
> - *       notice, this list of conditions and the following disclaimer.
> - *     * Redistributions in binary form must reproduce the above copyright
> - *       notice, this list of conditions and the following disclaimer in
> - *       the documentation and/or other materials provided with the
> - *       distribution.
> - *     * Neither the name of Cavium, Inc nor the names of its
> - *       contributors may be used to endorse or promote products derived
> - *       from this software without specific prior written permission.
> - *
> - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2016 Cavium, Inc.
> + * Copyright(c) 2016-2018 Intel Corporation.
> + * Copyright(c) 2016 NXP.

Please send existing license changes as separate patch as we need to
get ACK from all vendors.

> + * All rights reserved.
>   */
>  
>  #ifndef _RTE_EVENTDEV_H_
> @@ -923,8 +896,8 @@ rte_event_dev_close(uint8_t dev_id);
>  /**< The event generated from ethdev subsystem */
>  #define RTE_EVENT_TYPE_CRYPTODEV        0x1
>  /**< The event generated from crypodev subsystem */
> -#define RTE_EVENT_TYPE_TIMERDEV         0x2
> -/**< The event generated from timerdev subsystem */
> +#define RTE_EVENT_TYPE_TIMER		0x2
> +/**< The event generated from event timer adapter */
>  #define RTE_EVENT_TYPE_CPU              0x3
>  /**< The event generated from cpu for pipelining.
>   * Application may use *sub_event_type* to further classify the event
> -- 
> 2.6.4

Other than above minor changes, It looks really good to me.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 2/7] eventtimer: add common code
  2018-03-08 21:54       ` [PATCH v7 2/7] eventtimer: add common code Erik Gabriel Carrillo
@ 2018-03-12  8:11         ` Jerin Jacob
  0 siblings, 0 replies; 133+ messages in thread
From: Jerin Jacob @ 2018-03-12  8:11 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal

-----Original Message-----
> Date: Thu, 8 Mar 2018 15:54:01 -0600
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com,
>  hemant.agrawal@nxp.com
> Subject: [PATCH v7 2/7] eventtimer: add common code
> X-Mailer: git-send-email 1.7.10
> 
> This commit adds the logic that is shared by all event timer adapter
> drivers; the common code handles instance allocation and some
> initialization.
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>

It fails to build at least on clang 5.0(GCC 7.3 builds fine)

/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:280:10:
error: format specifies type 'unsigned short' but the argument has type
'uint8_t' (aka 'unsigned char') [-Werror,-Wformat]
                              adapter->data->id);
                              ^~~~~~~~~~~~~~~~~
/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:36:58:
note: expanded from macro 'EVTIM_LOG_ERR'
#define EVTIM_LOG_ERR(...) EVTIM_LOG(ERR, evtim_logtype, __VA_ARGS__)
                                                         ^~~~~~~~~~~
/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:34:43:
note: expanded from macro 'EVTIM_LOG'
                        "\n", __func__, __LINE__,
RTE_FMT_TAIL(__VA_ARGS__,)))
                                                               ^~~~~~~~~~~
/export/dpdk-next-eventdev/build/include/rte_common.h:382:32: note:
expanded from macro 'RTE_FMT_TAIL'
#define RTE_FMT_TAIL(fmt, ...) __VA_ARGS__
                               ^~~~~~~~~~~
/export/dpdk-next-eventdev/build/include/rte_common.h:380:39: note:
expanded from macro 'RTE_FMT'
#define RTE_FMT(fmt, ...) fmt "%.0s", __VA_ARGS__ ""
                                      ^~~~~~~~~~~
/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:350:28:
error: format specifies type 'unsigned short' but the argument has type
'uint8_t' (aka 'unsigned char') [-Werror,-Wformat]
                              "before freeing", adapter->data->id);
                                                ^~~~~~~~~~~~~~~~~
/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:36:58:
note: expanded from macro 'EVTIM_LOG_ERR'
#define EVTIM_LOG_ERR(...) EVTIM_LOG(ERR, evtim_logtype, __VA_ARGS__)
                                                         ^~~~~~~~~~~
/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:34:43:
note: expanded from macro 'EVTIM_LOG'
                        "\n", __func__, __LINE__,
RTE_FMT_TAIL(__VA_ARGS__,)))
                                                               ^~~~~~~~~~~
/export/dpdk-next-eventdev/build/include/rte_common.h:382:32: note:
expanded from macro 'RTE_FMT_TAIL'
#define RTE_FMT_TAIL(fmt, ...) __VA_ARGS__
                               ^~~~~~~~~~~
/export/dpdk-next-eventdev/build/include/rte_common.h:380:39: note:
expanded from macro 'RTE_FMT'
#define RTE_FMT(fmt, ...) fmt "%.0s", __VA_ARGS__ ""


> ---
>  config/common_base                                |   1 +
>  drivers/event/sw/sw_evdev.c                       |  18 +
>  lib/librte_eventdev/Makefile                      |   2 +
>  lib/librte_eventdev/rte_event_timer_adapter.c     | 459 ++++++++++++++++++++++
>  lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 150 +++++++
>  lib/librte_eventdev/rte_eventdev.h                |   3 +
>  lib/librte_eventdev/rte_eventdev_pmd.h            |  35 ++
>  lib/librte_eventdev/rte_eventdev_version.map      |  20 +
>  8 files changed, 688 insertions(+)
>  create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
>  create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h
> 
> diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
> index 549b182..8b16e3f 100644
> --- a/lib/librte_eventdev/Makefile
> +++ b/lib/librte_eventdev/Makefile
> @@ -20,6 +20,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
>  SRCS-y += rte_eventdev.c
>  SRCS-y += rte_event_ring.c
>  SRCS-y += rte_event_eth_rx_adapter.c
> +SRCS-y += rte_event_timer_adapter.c
>  
>  # export include files
>  SYMLINK-y-include += rte_eventdev.h
> @@ -29,6 +30,7 @@ SYMLINK-y-include += rte_eventdev_pmd_vdev.h
>  SYMLINK-y-include += rte_event_ring.h
>  SYMLINK-y-include += rte_event_eth_rx_adapter.h
>  SYMLINK-y-include += rte_event_timer_adapter.h
> +SYMLINK-y-include += rte_event_timer_adapter_pmd.h
>  
>  # versioning export map
>  EXPORT_MAP := rte_eventdev_version.map
> diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
> new file mode 100644
> index 0000000..711d6b9
> --- /dev/null
> +++ b/lib/librte_eventdev/rte_event_timer_adapter.c
> +void __rte_experimental
> +rte_event_timer_init(struct rte_event_timer *evtim)
> +{
> +	evtim->ev.op = RTE_EVENT_OP_NEW;
> +	evtim->ev.event_type = RTE_EVENT_TYPE_TIMER;
> +	evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
> +}
> +
> +int __rte_experimental
> +rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
> +			  struct rte_event_timer **evtims,
> +			  uint16_t nb_evtims)
> +{
> +#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
> +	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
> +	FUNC_PTR_OR_ERR_RET(adapter->arm_burst, -EINVAL);
> +#endif
> +
> +	return adapter->arm_burst(adapter, evtims, nb_evtims);
> +}
> +
> +int __rte_experimental
> +rte_event_timer_arm_tmo_tick_burst(
> +			const struct rte_event_timer_adapter *adapter,
> +			struct rte_event_timer **evtims,
> +			const uint64_t timeout_ticks,
> +			const uint16_t nb_evtims)
> +{
> +#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
> +	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
> +	FUNC_PTR_OR_ERR_RET(adapter->arm_tmo_tick_burst, -EINVAL);
> +#endif
> +
> +	return adapter->arm_tmo_tick_burst(adapter, evtims, timeout_ticks,
> +					   nb_evtims);
> +}
> +
> +int __rte_experimental
> +rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
> +			     struct rte_event_timer **evtims,
> +			     uint16_t nb_evtims)
> +{
> +#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
> +	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
> +	FUNC_PTR_OR_ERR_RET(adapter->cancel_burst, -EINVAL);
> +#endif
> +
> +	return adapter->cancel_burst(adapter, evtims, nb_evtims);
> +}

Please move fastpath functions to header file as "static inline".
That would avoid function all overhead for fastpath functions.
Even though it makes header file bit ugly, We are following the
same procedure across other subsystems in DPDK to get performance advantage.


> +
> +#endif /* __RTE_EVENT_TIMER_ADAPTER_PMD_H__ */
> diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
> index f9ad71e..888bcf1 100644
> --- a/lib/librte_eventdev/rte_eventdev.h
> +++ b/lib/librte_eventdev/rte_eventdev.h
> @@ -1046,6 +1046,9 @@ struct rte_event {
>   * @see struct rte_event_eth_rx_adapter_queue_conf::rx_queue_flags
>   */
>  
> +#define RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT (1ULL << 1)

1ULL << 0 ??

> +/**< This flag is set when the timer mechanism is in HW. */
> +
> +
> +EXPERIMENTAL {
> +	global:
> +
> +	rte_event_timer_adapter_create;
> +	rte_event_timer_adapter_create_ext;
> +	rte_event_timer_adapter_free;
> +	rte_event_timer_adapter_get_info;
> +	rte_event_timer_adapter_lookup;
> +	rte_event_timer_adapter_service_id_get;
> +	rte_event_timer_adapter_service_id_get;

Duplicate entry

> +	rte_event_timer_adapter_start;
> +	rte_event_timer_adapter_stats_get;
> +	rte_event_timer_adapter_stats_reset;
> +	rte_event_timer_adapter_stop;
> +	rte_event_timer_init;
> +	rte_event_timer_arm_burst;
> +	rte_event_timer_arm_tmo_tick_burst;
> +	rte_event_timer_cancel_burst;
> +} DPDK_18.02;
> -- 
> 2.6.4
> 

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 3/7] eventtimer: add default software driver
  2018-03-08 21:54       ` [PATCH v7 3/7] eventtimer: add default software driver Erik Gabriel Carrillo
@ 2018-03-12  8:45         ` Jerin Jacob
  2018-03-12 21:20           ` Carrillo, Erik G
  0 siblings, 1 reply; 133+ messages in thread
From: Jerin Jacob @ 2018-03-12  8:45 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal

-----Original Message-----
> Date: Thu, 8 Mar 2018 15:54:02 -0600
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com,
>  hemant.agrawal@nxp.com
> Subject: [PATCH v7 3/7] eventtimer: add default software driver
> X-Mailer: git-send-email 1.7.10
> 
> If an eventdev PMD does not wish to provide event timer adapter ops
> definitions, the library will fall back to a default software
> implementation whose entry points are added by this commit.
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  lib/Makefile                                  |   2 +-
>  lib/librte_eventdev/Makefile                  |   2 +-
>  lib/librte_eventdev/rte_event_timer_adapter.c | 874 ++++++++++++++++++++++++++
>  lib/librte_eventdev/rte_event_timer_adapter.h |  55 ++
>  mk/rte.app.mk                                 |   2 +-
>  5 files changed, 932 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/Makefile b/lib/Makefile
> index ec965a6..965be6c 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index 3eb41d1..83660df 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)        += -lrte_bitratestats
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
>  
> -_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer

Any specific reason for this change, if yes, Please create a separate
patch for the common code change, This will help to review

>  _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
>  
>  _LDLIBS-y += --whole-archive
> @@ -98,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)       += -lrte_security
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV)         += -lrte_rawdev
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
>  _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
> -- 
> 2.6.4
> 

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 6/7] doc: add event timer adapter section to programmer's guide
  2018-03-08 21:54       ` [PATCH v7 6/7] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
@ 2018-03-12 11:21         ` Jerin Jacob
  2018-03-12 22:02           ` Carrillo, Erik G
  0 siblings, 1 reply; 133+ messages in thread
From: Jerin Jacob @ 2018-03-12 11:21 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal

-----Original Message-----
> Date: Thu, 8 Mar 2018 15:54:05 -0600
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com,
>  hemant.agrawal@nxp.com
> Subject: [PATCH v7 6/7] doc: add event timer adapter section to
>  programmer's guide
> X-Mailer: git-send-email 1.7.10
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
> ---
>  doc/guides/prog_guide/event_timer_adapter.rst | 277 ++++++++++++++++++++++++++
>  doc/guides/prog_guide/index.rst               |   1 +
>  2 files changed, 278 insertions(+)
>  create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst
> 
> diff --git a/doc/guides/prog_guide/event_timer_adapter.rst b/doc/guides/prog_guide/event_timer_adapter.rst
> new file mode 100644
> index 0000000..423b91d
> --- /dev/null
> +++ b/doc/guides/prog_guide/event_timer_adapter.rst
> @@ -0,0 +1,277 @@
> +..  SPDX-License-Identifier: BSD-3-Clause
> +    Copyright(c) 2017 Intel Corporation. All rights reserved.
> +
> +Event Timer Adapter Library
> +=================================
> +
> +The DPDK
> +`Event Device library <http://dpdk.org/doc/guides/prog_guide/eventdev.html>`_
> +introduces an event driven programming model which presents applications with
> +an alternative to the polling model traditionally used in DPDK
> +applications. Event devices can be coupled with arbitrary components to provide
> +new event sources by using **event adapters**. The Event Timer Adapter is one
> +such adapter; it bridges event devices and timer mechanisms.
> +
> +The Event Timer Adapter library extends the event driven model
> +by introducing a :ref:`new type of event <timer_expiry_event>` that represents
> +a timer expiration, and providing an API with which adapters can be created or
> +destroyed, and :ref:`event timers <event_timer>` can be armed and canceled.
> +
> +The Event Timer Adapter library is designed to interface with hardware or
> +software implementations of the timer mechanism; it will query an eventdev PMD
> +to determine which implementation should be used.  The default software
> +implementation manages timers using the DPDK
> +`Timer library <http://dpdk.org/doc/guides/prog_guide/timer_lib.html>`_.
> +
> +Examples of using the API are presented in the `API Overview`_ and
> +`Processing Timer Expiry Events`_ sections.  Code samples are abstracted and
> +are based on the example of handling a TCP retransmission.
> +
> +.. _event_timer:
> +
> +Event Timer struct
> +------------------
> +Event timers are timers that enqueue a timer expiration event to an event
> +device upon firing.

I think, it better to change to _timer expiry_ from _firing_.

> +
> +The Event Timer Adapter API represents each event timer with a generic struct,
> +which contains an event and user metadata.  The ``rte_event_timer`` struct is
> +defined in ``lib/librte_event/librte_event_timer_adapter.h``.
> +
> +.. _timer_expiry_event:
> +
> +Arming Event Timers
> +~~~~~~~~~~~~~~~~~~~~~
> +
> +Once an event timer adapter has been started, an application can begin to
> +manage event timers with it.
> +
> +The application should allocate ``struct rte_event_timer`` objects from a
> +mempool or huge-page backed application buffers of required size. Upon
> +successful allocation, the application should initialize the event timer, and
> +then set any of the necessary event attributes described in the
> +`Timer Expiry Event`_ section. In the following example, assume ``conn``
> +represents a TCP connection and that ``event_timer_pool`` is a mempool that
> +was created previously:
> +
> +.. code-block:: c
> +
> +	rte_mempool_get(event_timer_pool, (void **)&conn->evtim);
> +	if (conn->evtim == NULL) { ... }
> +
> +        rte_event_timer_init(&conn->evtim);
> +
> +	/* Set up the expiry event. */
> +	conn->evtim->ev.event_ptr = conn;

Not specific to this specific example, What would be the default
behaviour if application does not set ev.event_ptr value.

Can we say?
"NULL value is allowed, in which case adapter set the event_ptr
to struct rte_event_timer *

> +	conn->evtim->ev.queue_id = event_queue_id;
> +	...
> +	conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns)
> +
> +Note that we have saved a pointer to the ``conn`` object in the timer's event
> +payload. This will allow us to locate the connection object again once we
> +dequeue the timer expiry event from the event device later.
> +
> +Processing Timer Expiry Events
> +------------------------------
> +
> +Once an event timer has successfully enqueued a timer expiry event in the event
> +device, the application will subsequently dequeue it from the event device.
> +The application can use the event payload to retrieve a pointer to the object
> +associated with the event timer. It can then re-arm the event timer or free the
> +event timer object as desired:
> +
> +.. code-block:: c
> +
> +	void
> +	event_processing_loop(...)
> +	{
> +		while (...) {
> +			/* Receive events from the configured event port. */
> +			rte_event_dequeue_burst(event_dev_id, event_port, &ev, 1, 0);
> +			...
> +			switch(ev.event_type) {
> +				...
> +				case RTE_EVENT_TYPE_TIMER:
> +					process_timer_event(ev);
> +					...
> +					break;
> +			}
> +		}
> +	}
> +
> +	uint8_t
> +	process_timer_event(...)
> +	{
> +		/* A retransmission timeout for the connection has been received. */
> +		conn = ev.event_ptr;
> +		/* Retransmit last packet (e.g. TCP segment). */
> +		...
> +		/* Re-arm timer using original values. */
> +		rte_event_timer_arm_burst(wheel_id, &conn->timer, 1);

s/wheel_id/adapter_id

> +	}
> +
> +Summary
> +-------
> +
> +The Event Timer Adapter library extends the DPDK event-based programming model
> +by representing timer expirations as events in the system and allowing
> +applications to use existing event processing loops to arm and cancel event
> +timers or handle timer expiry events.
> diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
> index bbbe789..589c05d 100644
> --- a/doc/guides/prog_guide/index.rst
> +++ b/doc/guides/prog_guide/index.rst
> @@ -42,6 +42,7 @@ Programmer's Guide
>      thread_safety_dpdk_functions
>      eventdev
>      event_ethernet_rx_adapter
> +    event_timer_adapter
>      qos_framework
>      power_man
>      packet_classif_access_ctrl

Overall, it looks good. With above changes

Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>


> -- 
> 2.6.4
> 

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 7/7] doc: add event timer adapter documentation
  2018-03-08 21:54       ` [PATCH v7 7/7] doc: add event timer adapter documentation Erik Gabriel Carrillo
@ 2018-03-12 11:28         ` Jerin Jacob
  0 siblings, 0 replies; 133+ messages in thread
From: Jerin Jacob @ 2018-03-12 11:28 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal

-----Original Message-----
> Date: Thu, 8 Mar 2018 15:54:06 -0600
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com,
>  hemant.agrawal@nxp.com
> Subject: [PATCH v7 7/7] doc: add event timer adapter documentation
> X-Mailer: git-send-email 1.7.10
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  MAINTAINERS                            |  7 +++++++
>  doc/api/doxy-api-index.md              | 32 +++-----------------------------
>  doc/guides/rel_notes/release_18_05.rst |  5 +++++
>  3 files changed, 15 insertions(+), 29 deletions(-)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a646ca3..abebf6d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -317,6 +317,13 @@ F: lib/librte_eventdev/*eth_rx_adapter*
>  F: test/test/test_event_eth_rx_adapter.c
>  F: doc/guides/prog_guide/event_ethernet_rx_adapter.rst
>  
> +Eventdev Timer Adapter API - EXPERIMENTAL
> +M: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> +T: git://dpdk.org/next/dpdk-next-eventdev
> +F: lib/librte_eventdev/*timer_adapter*
> +F: test/test/test_event_timer_adapter.c
> +F: doc/guides/prog_guide/event_timer_adapter.rst
> +
>  The public API headers are grouped by topics:
> @@ -47,6 +20,7 @@ The public API headers are grouped by topics:
>    [security]           (@ref rte_security.h),
>    [eventdev]           (@ref rte_eventdev.h),
>    [event_eth_rx_adapter]   (@ref rte_event_eth_rx_adapter.h),
> +  [event_timer_adapter]    (@ref rte_event_timer_adapter.h),
>    [rawdev]             (@ref rte_rawdev.h),
>    [metrics]            (@ref rte_metrics.h),
>    [bitrate]            (@ref rte_bitrate.h),
> diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst
> index 3923dc2..2b93a1e 100644
> --- a/doc/guides/rel_notes/release_18_05.rst
> +++ b/doc/guides/rel_notes/release_18_05.rst
> @@ -41,6 +41,11 @@ New Features
>       Also, make sure to start the actual text at the margin.
>       =========================================================
>  
> +* **Added the Event Timer Adapter Library.**
> +
> +  The Event Timer Adapter Library extends the event-based model by introducing
> +  APIs that allow applications to generate timer expiry events that are

How about ?
API that allow applications to arm/cancel the timer expiry events that are

In any case,
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>

> +  scheduled by an event device along with existing types of events.
>  
>  API Changes
>  -----------
> -- 
> 2.6.4
> 

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 1/7] eventtimer: add event timer adapter API
  2018-03-12  7:53         ` Jerin Jacob
@ 2018-03-12 16:22           ` Carrillo, Erik G
  0 siblings, 0 replies; 133+ messages in thread
From: Carrillo, Erik G @ 2018-03-12 16:22 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: dev

Hi Jerin,

Thanks for reviewing.  I've responded in-line:

> -----Original Message-----
> From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> Sent: Monday, March 12, 2018 2:54 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>
> Cc: pbhagavatula@caviumnetworks.com; dev@dpdk.org;
> nipun.gupta@nxp.com; hemant.agrawal@nxp.com
> Subject: Re: [PATCH v7 1/7] eventtimer: add event timer adapter API
> 
> -----Original Message-----
> > Date: Thu, 8 Mar 2018 15:54:00 -0600
> > From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > To: pbhagavatula@caviumnetworks.com
> > CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com,
> nipun.gupta@nxp.com,
> > hemant.agrawal@nxp.com
> > Subject: [PATCH v7 1/7] eventtimer: add event timer adapter API
> > X-Mailer: git-send-email 1.7.10
> 
> IMO, you can add some git commit description here.

Will do.

> 
> >
> > Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> > Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > ---
> >  lib/librte_eventdev/Makefile                  |   1 +
> >  lib/librte_eventdev/rte_event_timer_adapter.h | 645
> ++++++++++++++++++++++++++
> >  lib/librte_eventdev/rte_eventdev.h            |  41 +-
> >  3 files changed, 653 insertions(+), 34 deletions(-)  create mode
> > 100644 lib/librte_eventdev/rte_event_timer_adapter.h
> >
> > +
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this structure may change without prior notice
> > + *
> > + * Timer adapter configuration structure  */ struct
> > +rte_event_timer_adapter_conf {
> > +	uint8_t event_dev_id;
> > +	/**< Event device identifier */
> > +	uint16_t timer_adapter_id;
> > +	/**< Event timer adapter identifier */
> > +	uint32_t socket_id;
> > +	/**< Identifer of socket from which to allocate memory for adapter
> > +*/
> 
> s/Identifer/Identifier
>

Will fix.
 
> > +	enum rte_event_timer_adapter_clk_src clk_src;
> > +	/**< Clock source for timer adapter */
> > +	uint64_t timer_tick_ns;
> > +	/**< Timer adapter resolution in ns */
> > +	uint64_t max_tmo_ns;
> > +	/**< Maximum timer timeout(expiry) in ns */
> > +	uint64_t nb_timers;
> > +	/**< Total number of timers per adapter */
> > +	uint64_t flags;
> > +	/**< Timer adapter config flags (RTE_EVENT_TIMER_ADAPTER_F_*)
> */ };
> > +/**
> > +
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change without prior notice
> > + *
> > + * Set an event timer's initial state and initialize the event it carries.
> > + *
> > + * @param evtim
> > + *   A pointer to an event timer structure.
> > + */
> > +void __rte_experimental
> > +rte_event_timer_init(struct rte_event_timer *evtim);
> 
> Since it can be used in fastpath, How about making it as "static inline"
> function?
> Any it is just setting some variables.
> 

Will do.

> > +
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change without prior notice
> > + *
> > + * Arm a burst of event timers with separate expiration timeout tick
> > +for each
> > + * event timer.
> > + *
> > + * Before calling this function, the application allocates
> > + * ``struct rte_event_timer`` objects from mempool or huge page
> > +backed
> > + * application buffers of desired size. On successful allocation,
> > + * application updates the `struct rte_event_timer`` attributes such
> > +as
> > + * expiry event attributes, timeout ticks from now.
> > + * This function submits the event timer arm requests to the event
> > +timer adapter
> > + * and on expiry, the events will be injected to designated event queue.
> > + *
> > + * @param adapter
> > + *   A pointer to an event timer adapter structure.
> > + * @param evtims
> > + *   Pointer to an array of objects of type *rte_event_timer* structure.
> > + * @param nb_evtims
> > + *   Number of event timers in the supplied array.
> > + *
> > + * @return
> > + *   The number of successfully armed event timers. The return value can
> be less
> > + *   than the value of the *nb_evtims* parameter. If the return value is
> less
> > + *   than *nb_evtims*, the remaining event timers at the end of *evtims*
> > + *   are not consumed, and the caller has to take care of them, and
> rte_errno
> > + *   is set accordingly. Possible errno values include:
> > + *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
> > + *   expiry event's sched type doesn't match the capabilities of the
> > + *   destination event queue.
> > + *   - EAGAIN Specified timer adapter is not running
> > + *   - EALREADY A timer was encountered that was already armed
> > + */
> > +int __rte_experimental
> 
> To maintain the consistency across eventdev and other subsystems in DPDK.
> We could return uint16_t for all the fast path functions. ie. exiting "int" error
> return can be changed to
> 
> rte_errno = -EINVAL;
> return 0;
> 
> This would avoid some series typecasting issues as well for the _retry_ case.

Sounds good.  I'll change the return type to uint16_t, but the errno behavior seems
to already be what you describe so I think we should be good there.

<... snipped ...>

> > - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> > - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> NOT
> > - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> FITNESS FOR
> > - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> > - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> > - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> BUT NOT
> > - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> LOSS OF USE,
> > - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> AND ON ANY
> > - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> > - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> OF THE USE
> > - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(c) 2016 Cavium, Inc.
> > + * Copyright(c) 2016-2018 Intel Corporation.
> > + * Copyright(c) 2016 NXP.
> 
> Please send existing license changes as separate patch as we need to get
> ACK from all vendors.
> 

Will do.

> > + * All rights reserved.
> >   */
> >
> >  #ifndef _RTE_EVENTDEV_H_
> > @@ -923,8 +896,8 @@ rte_event_dev_close(uint8_t dev_id);  /**< The
> > event generated from ethdev subsystem */
> >  #define RTE_EVENT_TYPE_CRYPTODEV        0x1
> >  /**< The event generated from crypodev subsystem */
> > -#define RTE_EVENT_TYPE_TIMERDEV         0x2
> > -/**< The event generated from timerdev subsystem */
> > +#define RTE_EVENT_TYPE_TIMER		0x2
> > +/**< The event generated from event timer adapter */
> >  #define RTE_EVENT_TYPE_CPU              0x3
> >  /**< The event generated from cpu for pipelining.
> >   * Application may use *sub_event_type* to further classify the event
> > --
> > 2.6.4
> 
> Other than above minor changes, It looks really good to me.

Thanks,
Gabriel

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 3/7] eventtimer: add default software driver
  2018-03-12  8:45         ` Jerin Jacob
@ 2018-03-12 21:20           ` Carrillo, Erik G
  0 siblings, 0 replies; 133+ messages in thread
From: Carrillo, Erik G @ 2018-03-12 21:20 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: pbhagavatula, dev

Hi Jerin,

Response in-line:

> -----Original Message-----
> From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> Sent: Monday, March 12, 2018 3:46 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>
> Cc: pbhagavatula@caviumnetworks.com; dev@dpdk.org;
> nipun.gupta@nxp.com; hemant.agrawal@nxp.com
> Subject: Re: [PATCH v7 3/7] eventtimer: add default software driver
> 
> -----Original Message-----
> > Date: Thu, 8 Mar 2018 15:54:02 -0600
> > From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > To: pbhagavatula@caviumnetworks.com
> > CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com,
> nipun.gupta@nxp.com,
> > hemant.agrawal@nxp.com
> > Subject: [PATCH v7 3/7] eventtimer: add default software driver
> > X-Mailer: git-send-email 1.7.10
> >
> > If an eventdev PMD does not wish to provide event timer adapter ops
> > definitions, the library will fall back to a default software
> > implementation whose entry points are added by this commit.
> >

<... snipped ...>

> > --- a/mk/rte.app.mk
> > +++ b/mk/rte.app.mk
> > @@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)        += -
> lrte_bitratestats
> >  _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
> >  _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
> >
> > -_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
> 
> Any specific reason for this change, if yes, Please create a separate patch for
> the common code change, This will help to review

Yes, I needed to move the rte_timer lib past the eventdev lib in order for the 
static build to complete (since the event timer adapter references symbols from the 
rte_timer lib).  I'll separate that change out in the next series.

Thanks,
Gabriel

> 
> >  _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
> >
> >  _LDLIBS-y += --whole-archive
> > @@ -98,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -
> lrte_cryptodev
> >  _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)       += -lrte_security
> >  _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
> >  _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV)         += -lrte_rawdev
> > +_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
> >  _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
> >  _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -
> lrte_mempool_ring
> >  _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
> > --
> > 2.6.4
> >

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 6/7] doc: add event timer adapter section to programmer's guide
  2018-03-12 11:21         ` Jerin Jacob
@ 2018-03-12 22:02           ` Carrillo, Erik G
  0 siblings, 0 replies; 133+ messages in thread
From: Carrillo, Erik G @ 2018-03-12 22:02 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: pbhagavatula, dev

Hi Jerin,

> -----Original Message-----
> From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> Sent: Monday, March 12, 2018 6:21 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>
> Cc: pbhagavatula@caviumnetworks.com; dev@dpdk.org;
> nipun.gupta@nxp.com; hemant.agrawal@nxp.com
> Subject: Re: [PATCH v7 6/7] doc: add event timer adapter section to
> programmer's guide
> 
> -----Original Message-----
> > Date: Thu, 8 Mar 2018 15:54:05 -0600
> > From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > To: pbhagavatula@caviumnetworks.com
> > CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com,
> nipun.gupta@nxp.com,
> > hemant.agrawal@nxp.com
> > Subject: [PATCH v7 6/7] doc: add event timer adapter section to
> > programmer's guide
> > X-Mailer: git-send-email 1.7.10
> >
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> > Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
> > ---

<... snipped ...>

> > +
> > +Event Timer struct
> > +------------------
> > +Event timers are timers that enqueue a timer expiration event to an
> > +event device upon firing.
> 
> I think, it better to change to _timer expiry_ from _firing_.
> 

Sounds good.

> > +
> > +The Event Timer Adapter API represents each event timer with a
> > +generic struct, which contains an event and user metadata.  The
> > +``rte_event_timer`` struct is defined in
> ``lib/librte_event/librte_event_timer_adapter.h``.
> > +
> > +.. _timer_expiry_event:
> > +
> > +Arming Event Timers
> > +~~~~~~~~~~~~~~~~~~~~~
> > +
> > +Once an event timer adapter has been started, an application can
> > +begin to manage event timers with it.
> > +
> > +The application should allocate ``struct rte_event_timer`` objects
> > +from a mempool or huge-page backed application buffers of required
> > +size. Upon successful allocation, the application should initialize
> > +the event timer, and then set any of the necessary event attributes
> > +described in the `Timer Expiry Event`_ section. In the following
> > +example, assume ``conn`` represents a TCP connection and that
> > +``event_timer_pool`` is a mempool that was created previously:
> > +
> > +.. code-block:: c
> > +
> > +	rte_mempool_get(event_timer_pool, (void **)&conn->evtim);
> > +	if (conn->evtim == NULL) { ... }
> > +
> > +        rte_event_timer_init(&conn->evtim);
> > +
> > +	/* Set up the expiry event. */
> > +	conn->evtim->ev.event_ptr = conn;
> 
> Not specific to this specific example, What would be the default behaviour if
> application does not set ev.event_ptr value.
> 

Currently, it's undefined.

> Can we say?
> "NULL value is allowed, in which case adapter set the event_ptr to struct
> rte_event_timer *
> 

I like that idea; it would be a convenient touch.  I'll look at making this  update.

> > +	conn->evtim->ev.queue_id = event_queue_id;
> > +	...
> > +	conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns)
> > +
> > +Note that we have saved a pointer to the ``conn`` object in the
> > +timer's event payload. This will allow us to locate the connection
> > +object again once we dequeue the timer expiry event from the event
> device later.

<... snipped ...>

> 
> Overall, it looks good. With above changes
> 
> Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> 
> 
> > --
> > 2.6.4
> >

Thanks for the suggestions,
Gabriel

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 5/7] test: add event timer adapter auto-test
  2018-03-08 21:54       ` [PATCH v7 5/7] test: add event timer adapter auto-test Erik Gabriel Carrillo
@ 2018-03-14 12:52         ` Pavan Nikhilesh
  2018-03-14 21:42           ` Carrillo, Erik G
  2018-03-14 13:31         ` Pavan Nikhilesh
  1 sibling, 1 reply; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-03-14 12:52 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

Hi Gabriel,

On Thu, Mar 08, 2018 at 03:54:04PM -0600, Erik Gabriel Carrillo wrote:
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  test/test/Makefile                   |    1 +
>  test/test/test_event_timer_adapter.c | 1234 ++++++++++++++++++++++++++++++++++
>  2 files changed, 1235 insertions(+)
>  create mode 100644 test/test/test_event_timer_adapter.c
>
<snip>
> +
> +static int
> +configure_event_dev(void)
> +{
> +	const char *eventdev_name = "event_sw0";

Can this be made generic? instead of hardcoding to event_sw, check if
event_device is passed via --vdev (verify rte_event_dev_count()) and if it is
absent fallback to event_sw.

Thanks,
Pavan.

> +
> +	return TEST_SUCCESS;
> +}
<snip>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 5/7] test: add event timer adapter auto-test
  2018-03-08 21:54       ` [PATCH v7 5/7] test: add event timer adapter auto-test Erik Gabriel Carrillo
  2018-03-14 12:52         ` Pavan Nikhilesh
@ 2018-03-14 13:31         ` Pavan Nikhilesh
  2018-03-14 21:40           ` Carrillo, Erik G
  1 sibling, 1 reply; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-03-14 13:31 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

Hi Gabriel,

Please make sure that the unit tests are generic, I could see that some places
it is verifying whether event port is used or service cores are used, but
doesn't verify if actually event port/service core are needed i.e.
INTERNAL_PORT capability.

On Thu, Mar 08, 2018 at 03:54:04PM -0600, Erik Gabriel Carrillo wrote:
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  test/test/Makefile                   |    1 +
>  test/test/test_event_timer_adapter.c | 1234 ++++++++++++++++++++++++++++++++++
>  2 files changed, 1235 insertions(+)
>  create mode 100644 test/test/test_event_timer_adapter.c
>
<snip>
> +
> +/* This port conf callback is used by the max adapter instance creation test.
> + * Because that test may be limited by the number of ports available in the
> + * event device, this callback allocates just one port and returns it each
> + * time a port is requested.
> + */
> +static int
> +test_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
> +		  void *conf_arg)
> +{
> +	struct rte_eventdev *dev;
> +	struct rte_event_dev_config dev_conf;
> +	struct rte_event_port_conf *port_conf, def_port_conf = {0};
> +	int started;
> +	static int port_allocated;
> +	static uint8_t port_id;
> +	uint8_t dev_id;
> +	int ret;
> +
> +	if (port_allocated) {
> +		*event_port_id = port_id;
> +		return 0;
> +	}
> +
> +	RTE_SET_USED(id);
> +
> +	dev = &rte_eventdevs[event_dev_id];

I don't think this is the correct way of accessing event dev information i.e.
accessing the global rte_eventdevs structure from a application.

> +	dev_id = dev->data->dev_id;
> +	dev_conf = dev->data->dev_conf;
> +
> +	started = dev->data->dev_started;
> +	if (started)
> +		rte_event_dev_stop(dev_id);
> +
> +	port_id = dev_conf.nb_event_ports;
> +	dev_conf.nb_event_ports += 1;
> +	ret = rte_event_dev_configure(dev_id, &dev_conf);
> +	if (ret < 0) {
> +		if (started)
> +			rte_event_dev_start(dev_id);
Shouldn't this be !started ?. The same pattern repeats a few places.

> +
> +		return ret;
> +	}
> +
> +	if (conf_arg != NULL)
> +		port_conf = conf_arg;
> +	else {
> +		port_conf = &def_port_conf;
> +		ret = rte_event_port_default_conf_get(dev_id, port_id,
> +						      port_conf);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	ret = rte_event_port_setup(dev_id, port_id, port_conf);
> +	if (ret < 0)
> +		return ret;
> +
> +	*event_port_id = port_id;
> +
> +	if (started)
> +		rte_event_dev_start(dev_id);
> +
> +	port_allocated = 1;
> +
> +	return 0;
> +}
<snip>

Thanks,
Pavan.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 5/7] test: add event timer adapter auto-test
  2018-03-14 13:31         ` Pavan Nikhilesh
@ 2018-03-14 21:40           ` Carrillo, Erik G
  0 siblings, 0 replies; 133+ messages in thread
From: Carrillo, Erik G @ 2018-03-14 21:40 UTC (permalink / raw)
  To: Pavan Nikhilesh, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

Hi Pavan,

> -----Original Message-----
> From: Pavan Nikhilesh [mailto:pbhagavatula@caviumnetworks.com]
> Sent: Wednesday, March 14, 2018 8:31 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>;
> jerin.jacob@caviumnetworks.com; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: dev@dpdk.org
> Subject: Re: [PATCH v7 5/7] test: add event timer adapter auto-test
> 
> Hi Gabriel,
> 
> Please make sure that the unit tests are generic, I could see that some places
> it is verifying whether event port is used or service cores are used, but
> doesn't verify if actually event port/service core are needed i.e.
> INTERNAL_PORT capability.

Good point... I'll make these updates.

Thanks for reviewing,
Gabriel

> 
> On Thu, Mar 08, 2018 at 03:54:04PM -0600, Erik Gabriel Carrillo wrote:
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > ---
> >  test/test/Makefile                   |    1 +
> >  test/test/test_event_timer_adapter.c | 1234
> > ++++++++++++++++++++++++++++++++++
> >  2 files changed, 1235 insertions(+)
> >  create mode 100644 test/test/test_event_timer_adapter.c
> >
> <snip>
> > +
> > +/* This port conf callback is used by the max adapter instance creation
> test.
> > + * Because that test may be limited by the number of ports available
> > +in the
> > + * event device, this callback allocates just one port and returns it
> > +each
> > + * time a port is requested.
> > + */
> > +static int
> > +test_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t
> *event_port_id,
> > +		  void *conf_arg)
> > +{
> > +	struct rte_eventdev *dev;
> > +	struct rte_event_dev_config dev_conf;
> > +	struct rte_event_port_conf *port_conf, def_port_conf = {0};
> > +	int started;
> > +	static int port_allocated;
> > +	static uint8_t port_id;
> > +	uint8_t dev_id;
> > +	int ret;
> > +
> > +	if (port_allocated) {
> > +		*event_port_id = port_id;
> > +		return 0;
> > +	}
> > +
> > +	RTE_SET_USED(id);
> > +
> > +	dev = &rte_eventdevs[event_dev_id];
> 
> I don't think this is the correct way of accessing event dev information i.e.
> accessing the global rte_eventdevs structure from a application.
> 
> > +	dev_id = dev->data->dev_id;
> > +	dev_conf = dev->data->dev_conf;
> > +
> > +	started = dev->data->dev_started;
> > +	if (started)
> > +		rte_event_dev_stop(dev_id);
> > +
> > +	port_id = dev_conf.nb_event_ports;
> > +	dev_conf.nb_event_ports += 1;
> > +	ret = rte_event_dev_configure(dev_id, &dev_conf);
> > +	if (ret < 0) {
> > +		if (started)
> > +			rte_event_dev_start(dev_id);
> Shouldn't this be !started ?. The same pattern repeats a few places.
> 
> > +
> > +		return ret;
> > +	}
> > +
> > +	if (conf_arg != NULL)
> > +		port_conf = conf_arg;
> > +	else {
> > +		port_conf = &def_port_conf;
> > +		ret = rte_event_port_default_conf_get(dev_id, port_id,
> > +						      port_conf);
> > +		if (ret < 0)
> > +			return ret;
> > +	}
> > +
> > +	ret = rte_event_port_setup(dev_id, port_id, port_conf);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	*event_port_id = port_id;
> > +
> > +	if (started)
> > +		rte_event_dev_start(dev_id);
> > +
> > +	port_allocated = 1;
> > +
> > +	return 0;
> > +}
> <snip>
> 
> Thanks,
> Pavan.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v7 5/7] test: add event timer adapter auto-test
  2018-03-14 12:52         ` Pavan Nikhilesh
@ 2018-03-14 21:42           ` Carrillo, Erik G
  0 siblings, 0 replies; 133+ messages in thread
From: Carrillo, Erik G @ 2018-03-14 21:42 UTC (permalink / raw)
  To: Pavan Nikhilesh, jerin.jacob, nipun.gupta, hemant.agrawal; +Cc: dev

Hi Pavan,

> -----Original Message-----
> From: Pavan Nikhilesh [mailto:pbhagavatula@caviumnetworks.com]
> Sent: Wednesday, March 14, 2018 7:53 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>;
> jerin.jacob@caviumnetworks.com; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: dev@dpdk.org
> Subject: Re: [PATCH v7 5/7] test: add event timer adapter auto-test
> 
> Hi Gabriel,
> 
> On Thu, Mar 08, 2018 at 03:54:04PM -0600, Erik Gabriel Carrillo wrote:
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > ---
> >  test/test/Makefile                   |    1 +
> >  test/test/test_event_timer_adapter.c | 1234
> > ++++++++++++++++++++++++++++++++++
> >  2 files changed, 1235 insertions(+)
> >  create mode 100644 test/test/test_event_timer_adapter.c
> >
> <snip>
> > +
> > +static int
> > +configure_event_dev(void)
> > +{
> > +	const char *eventdev_name = "event_sw0";
> 
> Can this be made generic? instead of hardcoding to event_sw, check if
> event_device is passed via --vdev (verify rte_event_dev_count()) and if it is
> absent fallback to event_sw.
> 

Sure, I'll look into doing this.

Thanks,
Gabriel

> Thanks,
> Pavan.
> 
> > +
> > +	return TEST_SUCCESS;
> > +}
> <snip>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v8 0/9] eventtimer: introduce event timer adapter
  2018-03-08 21:53     ` [PATCH v7 0/7] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                         ` (6 preceding siblings ...)
  2018-03-08 21:54       ` [PATCH v7 7/7] doc: add event timer adapter documentation Erik Gabriel Carrillo
@ 2018-03-29 21:27       ` Erik Gabriel Carrillo
  2018-03-29 21:27         ` [PATCH v8 1/9] " Erik Gabriel Carrillo
                           ` (9 more replies)
  7 siblings, 10 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-29 21:27 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

This patch series contains the next iteration of the Event Timer Adapter
library, which abstracts timer mechanisms that are tightly coupled with event
devices, and extends the event based programming model so that timer
expirations are represented as an event.

v8
- Addressed comments on previous series from Jerin:
  - Add better git comment to initial patch
  - Return uint16_t for fastpath functions
  - Move updates to existing licenses to separate patch for individual review
  - Fix clang build error
  - Move fastpath functions into header as static inline functions
  - Remove duplicate map file entry
  - Fix flag value
  - Move update to rte.app.mk file into separate commit
- Addressed comments on previous series from Pavan:
  - Make tests generic so that they work for software or hardware event devices
    and timer mechanisms
  - Don't access eventdev internals from tests
- Integrated unit tests from Pavan

v7
- Addressed comments on previous patch series from Pavan:
  - Use SPDX license tags
  - Squash various commits to make series easier to review
  - Tag experimental functions as such
  - Use one mempool for messages and timers in sw driver 
  - Limit service cores mapped to sw driver's service to one
  - Use smp memory barriers
  - In service function, invoke rte_timer_manage() with frequency matching the
    resolution the adapter was configured with
- Reworked synchronization in sw driver between threads producing messages
  and service thread that consumes them.  The new approach avoids a situation
  where event timers couldn't be armed/canceled from the same lcore the service
  was running on.
- Updated logging facility
- Added more unit tests
- Added support for meson build

v6
- Addressed comments on previous version from Jerin:
  - Added RTE_EVENT_TIMER_CANCELED event timer state back in
  - remove check for started adapter in timer arm/cancel functions 
  - reuse CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG instead of adding new config option
- Added initial version of software driver implementation
- Added stats APIs
- Added API to retrieve adapter service ID
- Added API to initialize event timer
- Added entry to Programmer's Guide in documentation
- Added new unit tests to auto-test

v5
- Addressed comments on previous version from Pavan:
  - renamed rte_event_timer_adapter_driver.h to rte_event_timer_adapter_pmd.h
  - moved contents of sw_event_timer_adapter.c into rte_event_timer_adapter.c
  - added flags parameter to timer_adapter_caps_get() call
  - added DEBUG config variable to conditionally compile run-time checks on
    datapath
  - fixed license text and file description
- Also added a config variable to enable/disable compilation of event timer
  adapter - feedback on whether this is desirable is appreciated

v4
- Split changes into multiple patches for easier review

v3
- Reworked allocation and ops organization in common code based on feedback
  received from Jerin and Pavan. This will allow fast-path function pointers to 
  be dereferenced with one level of indirection with pointers valid in primary
  and secondary processes.
- Moved default software implementation from sw_evdev directory to eventdev
  library directory, which will allow it to be used by any eventdev PMD as an
  alternative to providing its own definitions.
- Reverted occurrences of id back to pointer to adapter struct in library API
- Added rte_event_timer_adapter_lookup() function back in

v2
- Added ops structure and stubbed out plugin for SW impl
- Added unit test stubs
- Replaced occurrences of "wheel" in API with "adapter"
- Replaced occurrences of pointer to struct rte_event_timer_adapter with ids
- Removed rte_event_timer_adapter_lookup() function
- Replaced RTE_EVENT_TIMER_SUCCESS_{ARM,CANCEL} states with
  RTE_EVENT_TIMER_ARMED

Erik Gabriel Carrillo (9):
  eventtimer: introduce event timer adapter
  eventdev: convert to SPDX license tag in header
  eventtimer: add common code
  mk: update library order in static build
  eventtimer: add default software driver
  eventtimer: add support for meson build system
  test: add event timer adapter auto-test
  doc: add event timer adapter section to programmer's guide
  doc: add event timer adapter documentation

 MAINTAINERS                                       |    7 +
 config/common_base                                |    1 +
 config/rte_config.h                               |    1 +
 doc/api/doxy-api-index.md                         |   32 +-
 doc/guides/prog_guide/event_timer_adapter.rst     |  297 ++++
 doc/guides/prog_guide/index.rst                   |    1 +
 doc/guides/rel_notes/release_18_05.rst            |    6 +
 drivers/event/sw/sw_evdev.c                       |   18 +
 lib/Makefile                                      |    2 +-
 lib/librte_eventdev/Makefile                      |    5 +-
 lib/librte_eventdev/meson.build                   |    9 +-
 lib/librte_eventdev/rte_event_timer_adapter.c     | 1302 +++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h     |  770 +++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h |  114 ++
 lib/librte_eventdev/rte_eventdev.c                |   22 +
 lib/librte_eventdev/rte_eventdev.h                |   61 +-
 lib/librte_eventdev/rte_eventdev_pmd.h            |   35 +
 lib/librte_eventdev/rte_eventdev_version.map      |   21 +-
 lib/meson.build                                   |    3 +-
 mk/rte.app.mk                                     |    2 +-
 test/test/Makefile                                |    1 +
 test/test/test_event_timer_adapter.c              | 1837 +++++++++++++++++++++
 22 files changed, 4476 insertions(+), 71 deletions(-)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h
 create mode 100644 test/test/test_event_timer_adapter.c

-- 
2.6.4

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v8 1/9] eventtimer: introduce event timer adapter
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
@ 2018-03-29 21:27         ` Erik Gabriel Carrillo
  2018-03-29 21:27         ` [PATCH v8 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
                           ` (8 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-29 21:27 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Event devices can be coupled with various components to provide
new event sources by using event adapters.  The event timer adapter
is one such adapter; it bridges event devices and timer mechanisms.
This library extends the event-driven programming model by
introducing a new type of event that represents a timer expiration,
and it provides APIs with which adapters can be created or destroyed
and event timers can be armed and canceled.

Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/Makefile                  |   1 +
 lib/librte_eventdev/rte_event_timer_adapter.h | 715 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_eventdev.h            |   4 +-
 3 files changed, 718 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h

diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index d27dd07..549b182 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -28,6 +28,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
new file mode 100644
index 0000000..6a76791
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -0,0 +1,715 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc.
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ * @file
+ *
+ * RTE Event Timer Adapter
+ *
+ * An event timer adapter has the following abstract working model:
+ *
+ *                               timer_tick_ns
+ *                                   +
+ *                      +-------+    |
+ *                      |       |    |
+ *              +-------+ bkt 0 +----v---+
+ *              |       |       |        |
+ *              |       +-------+        |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *          |       |                |       |  |   |   |   |   |
+ *          | bkt n |                | bkt 1 |<-> t0| t1| t2| tn|
+ *          |       |                |       |  |   |   |   |   |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *              |     Timer adapter      |
+ *          +---+---+                +---+---+
+ *          |       |                |       |
+ *          | bkt 4 |                | bkt 2 |<--- Current bucket
+ *          |       |                |       |
+ *          +---+---+                +---+---+
+ *               |      +-------+       |
+ *               |      |       |       |
+ *               +------+ bkt 3 +-------+
+ *                      |       |
+ *                      +-------+
+ *
+ * - It has a virtual monotonically increasing 64-bit timer adapter clock based
+ *   on *enum rte_event_timer_adapter_clk_src* clock source. The clock source
+ *   could be a CPU clock, or a platform dependent external clock.
+ *
+ * - The application creates a timer adapter instance with given the clock
+ *   source, the total number of event timers, and a resolution(expressed in ns)
+ *   to traverse between the buckets.
+ *
+ * - Each timer adapter may have 0 to n buckets based on the configured
+ *   max timeout(max_tmo_ns) and resolution(timer_tick_ns). Upon starting the
+ *   timer adapter, the adapter starts ticking at *timer_tick_ns* resolution.
+ *
+ * - The application arms an event timer that will expire *timer_tick_ns*
+ *   from now.
+ *
+ * - The application can cancel an armed timer and no timer expiry event will be
+ *   generated.
+ *
+ * - If a timer expires then the library injects the timer expiry event in
+ *   the designated event queue.
+ *
+ * - The timer expiry event will be received through *rte_event_dequeue_burst*.
+ *
+ * - The application frees the timer adapter instance.
+ *
+ * Multiple timer adapters can be created with a varying level of resolution
+ * for various expiry use cases that run in parallel.
+ *
+ * Before using the timer adapter, the application has to create and configure
+ * an event device along with the event port. Based on the event device
+ * capability it might require creating an additional event port to be used
+ * by the timer adapter.
+ *
+ * The application creates the event timer adapter using the
+ * ``rte_event_timer_adapter_create()``. The event device id is passed to this
+ * function, inside this function the event device capability is checked,
+ * and if an in-built port is absent the application uses the default
+ * function to create a new producer port.
+ *
+ * The application may also use the function
+ * ``rte_event_timer_adapter_create_ext()`` to have granular control over
+ * producer port creation in a case where the in-built port is absent.
+ *
+ * After creating the timer adapter, the application has to start it
+ * using ``rte_event_timer_adapter_start()``. The buckets are traversed from
+ * 0 to n; when the adapter ticks, the next bucket is visited. Each time,
+ * the list per bucket is processed, and timer expiry events are sent to the
+ * designated event queue.
+ *
+ * The application can arm one or more event timers using the
+ * ``rte_event_timer_arm_burst()``. The *timeout_ticks* represents the number
+ * of *timer_tick_ns* after which the timer has to expire. The timeout at
+ * which the timers expire can be grouped or be independent of each
+ * event timer instance. ``rte_event_timer_arm_tmo_tick_burst()`` addresses the
+ * former case and ``rte_event_timer_arm_burst()`` addresses the latter case.
+ *
+ * The application can cancel the timers from expiring using the
+ * ``rte_event_timer_cancel_burst()``.
+ *
+ * On the secondary process, ``rte_event_timer_adapter_lookup()`` can be used
+ * to get the timer adapter pointer from its id and use it to invoke fastpath
+ * operations such as arm and cancel.
+ *
+ * Some of the use cases of event timer adapter are Beacon Timers,
+ * Generic SW Timeout, Wireless MAC Scheduling, 3G Frame Protocols,
+ * Packet Scheduling, Protocol Retransmission Timers, Supervision Timers.
+ * All these use cases require high resolution and low time drift.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_spinlock.h>
+#include <rte_memory.h>
+
+#include "rte_eventdev.h"
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this enum may change without prior notice
+ *
+ * Timer adapter clock source
+ */
+enum rte_event_timer_adapter_clk_src {
+	RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+	/**< Use CPU clock as the clock source. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK0,
+	/**< Platform dependent external clock source 0. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK1,
+	/**< Platform dependent external clock source 1. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK2,
+	/**< Platform dependent external clock source 2. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK3,
+	/**< Platform dependent external clock source 3. */
+};
+
+#define RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES	(1ULL << 0)
+/**< The event timer adapter implementation may have constraints on the
+ * resolution (timer_tick_ns) and maximum timer expiry timeout(max_tmo_ns)
+ * based on the given timer adapter or system.  If this flag is set, the
+ * implementation adjusts the resolution and maximum timeout to the best
+ * possible configuration. On successful timer adapter creation, the
+ * application can get the configured resolution and max timeout with
+ * ``rte_event_timer_adapter_get_info()``.
+ *
+ * @see struct rte_event_timer_adapter_info::min_resolution_ns
+ * @see struct rte_event_timer_adapter_info::max_tmo_ns
+ */
+#define RTE_EVENT_TIMER_ADAPTER_F_SP_PUT	(1ULL << 1)
+/**< ``rte_event_timer_arm_burst()`` API to be used in single producer mode.
+ *
+ * @see struct rte_event_timer_adapter_conf::flags
+ */
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter configuration structure
+ */
+struct rte_event_timer_adapter_conf {
+	uint8_t event_dev_id;
+	/**< Event device identifier */
+	uint16_t timer_adapter_id;
+	/**< Event timer adapter identifier */
+	uint32_t socket_id;
+	/**< Identifier of socket from which to allocate memory for adapter */
+	enum rte_event_timer_adapter_clk_src clk_src;
+	/**< Clock source for timer adapter */
+	uint64_t timer_tick_ns;
+	/**< Timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expiry) in ns */
+	uint64_t nb_timers;
+	/**< Total number of timers per adapter */
+	uint64_t flags;
+	/**< Timer adapter config flags (RTE_EVENT_TIMER_ADAPTER_F_*) */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer adapter stats structure
+ */
+struct rte_event_timer_adapter_stats {
+	uint64_t evtim_exp_count;
+	/**< Number of event timers that have expired. */
+	uint64_t ev_enq_count;
+	/**< Eventdev enqueue count */
+	uint64_t ev_inv_count;
+	/**< Invalid expiry event count */
+	uint64_t evtim_retry_count;
+	/**< Event timer retry count */
+	uint64_t adapter_tick_count;
+	/**< Tick count for the adapter, at its resolution */
+};
+
+struct rte_event_timer_adapter;
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Callback function type for producer port creation.
+ */
+typedef int (*rte_event_timer_adapter_port_conf_cb_t)(uint16_t id,
+						      uint8_t event_dev_id,
+						      uint8_t *event_port_id,
+						      void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create an event timer adapter.
+ *
+ * This function must be invoked first before any other function in the API.
+ *
+ * @param conf
+ *   The event timer adapter configuration structure.
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ *   - EIO: event device reconfiguration and restart error.  The adapter
+ *   reconfigures the event device with an additional port by default if it is
+ *   required to use a service to manage timers. If the device had been started
+ *   before this call, this error code indicates an error in restart following
+ *   an error in reconfiguration, i.e., a combination of the two error codes.
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create a timer adapter with the supplied callback.
+ *
+ * This function can be used to have a more granular control over the timer
+ * adapter creation.  If a built-in port is absent, then the function uses the
+ * callback provided to create and get the port id to be used as a producer
+ * port.
+ *
+ * @param conf
+ *   The timer adapter configuration structure
+ * @param conf_cb
+ *   The port config callback function.
+ * @param conf_arg
+ *   Opaque pointer to the argument for the callback function
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter info structure.
+ */
+struct rte_event_timer_adapter_info {
+	uint64_t min_resolution_ns;
+	/**< Minimum timer adapter resolution in ns */
+	uint64_t resolution_ns;
+	/**< Actual timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expire) in ns */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configured timer adapter attributes */
+	uint32_t caps;
+	/**< Event timer adapter capabilities */
+	int16_t event_dev_port_id;
+	/**< Event device port ID, if applicable */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve the contextual information of an event timer adapter.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @param[out] adapter_info
+ *   A pointer to a structure of type *rte_event_timer_adapter_info* to be
+ *   filled with the contextual information of the adapter.
+ *
+ * @return
+ *   - 0: Success, driver updates the contextual information of the
+ *   timer adapter
+ *   - <0: Error code returned by the driver info get function.
+ *   - -EINVAL: adapter identifier invalid
+ *
+ * @see RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES,
+ *   struct rte_event_timer_adapter_info
+ *
+ */
+int __rte_experimental
+rte_event_timer_adapter_get_info(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Start a timer adapter.
+ *
+ * The adapter start step is the last one and consists of setting the timer
+ * adapter to start accepting the timers and schedules to event queues.
+ *
+ * On success, all basic functions exported by the API (timer arm,
+ * timer cancel and so on) can be invoked.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter started.
+ *   - <0: Error code returned by the driver start function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_start(
+		const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Stop an event timer adapter.
+ *
+ * The adapter can be restarted with a call to
+ * ``rte_event_timer_adapter_start()``.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter stopped.
+ *   - <0: Error code returned by the driver stop function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Lookup an event timer adapter using its identifier.
+ *
+ * If an event timer adapter was created in another process with the same
+ * identifier, this function will locate its state and set up access to it
+ * so that it can be used in this process.
+ *
+ * @param adapter_id
+ *  The event timer adapter identifier.
+ *
+ * @return
+ *  A pointer to the event timer adapter matching the identifier on success.
+ *  NULL on error with rte_errno set appropriately.
+ *  Possible rte_errno values include:
+ *   - ENOENT - requested entry not available to return.
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_lookup(uint16_t adapter_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Free an event timer adapter.
+ *
+ * Destroy an event timer adapter, freeing all resources.
+ *
+ * Before invoking this function, the application must wait for all the
+ * armed timers to expire or cancel the outstanding armed timers.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully freed the event timer adapter resources.
+ *   - <0: Failed to free the event timer adapter resources.
+ *   - -EAGAIN:  adapter is busy; timers outstanding
+ *   - -EBUSY: stop hasn't been called for this adapter yet
+ *   - -EINVAL: adapter id invalid, or adapter invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter);
+
+/**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure
+ *   - -ESRCH: the adapter does not require a service to operate
+ */
+int __rte_experimental
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param[out] stats
+ *   A pointer to a structure to fill with statistics.
+ *
+ * @return
+ *   - 0: Successfully retrieved.
+ *   - <0: Failure; error code returned.
+ */
+int __rte_experimental
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully reset;
+ *   - <0: Failure; error code returned.
+ */
+int __rte_experimental rte_event_timer_adapter_stats_reset(
+		struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer state.
+ */
+enum rte_event_timer_state {
+	RTE_EVENT_TIMER_NOT_ARMED	= 0,
+	/**< Event timer not armed. */
+	RTE_EVENT_TIMER_ARMED		= 1,
+	/**< Event timer successfully armed. */
+	RTE_EVENT_TIMER_CANCELED	= 2,
+	/**< Event timer successfully canceled. */
+	RTE_EVENT_TIMER_ERROR		= -1,
+	/**< Generic event timer error. */
+	RTE_EVENT_TIMER_ERROR_TOOEARLY	= -2,
+	/**< Event timer timeout tick value is too small for the adapter to
+	 * handle, given its configured resolution.
+	 */
+	RTE_EVENT_TIMER_ERROR_TOOLATE	= -3,
+	/**< Event timer timeout tick is greater than the maximum timeout.*/
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * The generic *rte_event_timer* structure to hold the event timer attributes
+ * for arm and cancel operations.
+ */
+RTE_STD_C11
+struct rte_event_timer {
+	struct rte_event ev;
+	/**<
+	 * Expiry event attributes.  On successful event timer timeout,
+	 * the following attributes will be used to inject the expiry event to
+	 * the eventdev:
+	 *  - event_queue_id: Targeted event queue id for expiry events.
+	 *  - event_priority: Event priority of the event expiry event in the
+	 *  event queue relative to other events.
+	 *  - sched_type: Scheduling type of the expiry event.
+	 *  - flow_id: Flow id of the expiry event.
+	 *  - op: RTE_EVENT_OP_NEW
+	 *  - event_type: RTE_EVENT_TYPE_TIMER
+	 */
+	volatile enum rte_event_timer_state state;
+	/**< State of the event timer. */
+	uint64_t timeout_ticks;
+	/**< Expiry timer ticks expressed in number of *timer_ticks_ns* from
+	 * now.
+	 * @see struct rte_event_timer_adapter_info::adapter_conf::timer_tick_ns
+	 */
+	uint64_t impl_opaque[2];
+	/**< Implementation-specific opaque data.
+	 * An event timer adapter implementation use this field to hold
+	 * implementation specific values to share between the arm and cancel
+	 * operations.  The application should not modify this field.
+	 */
+	uint8_t user_meta[0];
+	/**< Memory to store user specific metadata.
+	 * The event timer adapter implementation should not modify this area.
+	 */
+} __rte_cache_aligned;
+
+typedef uint16_t (*rte_event_timer_arm_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Enable event timers to enqueue timer events upon expiry */
+typedef uint16_t (*rte_event_timer_arm_tmo_tick_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint64_t timeout_tick,
+		uint16_t nb_tims);
+/**< @internal Enable event timers with common expiration time */
+typedef uint16_t (*rte_event_timer_cancel_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Prevent event timers from enqueuing timer events */
+
+/**
+ * @internal Data structure associated with each event timer adapter.
+ */
+struct rte_event_timer_adapter {
+	rte_event_timer_arm_burst_t arm_burst;
+	/**< Pointer to driver arm_burst function. */
+	rte_event_timer_arm_tmo_tick_burst_t arm_tmo_tick_burst;
+	/**< Pointer to driver arm_tmo_tick_burst function. */
+	rte_event_timer_cancel_burst_t cancel_burst;
+	/**< Pointer to driver cancel function. */
+	struct rte_event_timer_adapter_data *data;
+	/**< Pointer to shared adapter data */
+	const struct rte_event_timer_adapter_ops *ops;
+	/**< Functions exported by adapter driver */
+
+	RTE_STD_C11
+	uint8_t allocated : 1;
+	/**< Flag to indicate that this adapter has been allocated */
+} __rte_cache_aligned;
+
+#define ADAPTER_VALID_OR_ERR_RET(adapter, retval) do { \
+	if (adapter == NULL || !adapter->allocated)    \
+		return retval;			       \
+} while (0)
+#define FUNC_PTR_OR_ERR_RET(func, errval) do { \
+	if ((func) == NULL)		       \
+		return errval;		       \
+} while (0)
+
+#define FUNC_PTR_OR_NULL_RET_WITH_ERRNO(func, errval) do { \
+	if ((func) == NULL) {				   \
+		rte_errno = errval;			   \
+		return NULL;				   \
+	}						   \
+} while (0)
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with separate expiration timeout tick for each
+ * event timer.
+ *
+ * Before calling this function, the application allocates
+ * ``struct rte_event_timer`` objects from mempool or huge page backed
+ * application buffers of desired size. On successful allocation,
+ * application updates the `struct rte_event_timer`` attributes such as
+ * expiry event attributes, timeout ticks from now.
+ * This function submits the event timer arm requests to the event timer adapter
+ * and on expiry, the events will be injected to designated event queue.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Pointer to an array of objects of type *rte_event_timer* structure.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_evtims* parameter. If the return value is less
+ *   than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
+ *   expiry event's sched type doesn't match the capabilities of the
+ *   destination event queue.
+ *   - EAGAIN Specified timer adapter is not running
+ *   - EALREADY A timer was encountered that was already armed
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **evtims,
+			  uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_burst, -EINVAL);
+#endif
+
+	return adapter->arm_burst(adapter, evtims, nb_evtims);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with same expiration timeout tick.
+ *
+ * Provides the same functionality as ``rte_event_timer_arm_burst()``, except
+ * that application can use this API when all the event timers have the
+ * same timeout expiration tick. This specialized function can provide the
+ * additional hint to the adapter implementation and optimize if possible.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Points to an array of objects of type *rte_event_timer* structure.
+ * @param timeout_ticks
+ *   The number of ticks in which the timers should expire.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_evtims* parameter. If the return value is less
+ *   than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
+ *   expiry event's sched type doesn't match the capabilities of the
+ *   destination event queue.
+ *   - EAGAIN Specified event timer adapter is not running
+ *   - EALREADY A timer was encountered that was already armed
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_arm_tmo_tick_burst(
+			const struct rte_event_timer_adapter *adapter,
+			struct rte_event_timer **evtims,
+			const uint64_t timeout_ticks,
+			const uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_tmo_tick_burst, -EINVAL);
+#endif
+
+	return adapter->arm_tmo_tick_burst(adapter, evtims, timeout_ticks,
+					   nb_evtims);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Cancel a burst of event timers from being scheduled to the event device.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Points to an array of objects of type *rte_event_timer* structure
+ * @param nb_evtims
+ *   Number of event timer instances in the supplied array.
+ *
+ * @return
+ *   The number of successfully canceled event timers. The return value can be
+ *   less than the value of the *nb_evtims* parameter. If the return value is
+ *   less than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter identifier
+ *   - EAGAIN Specified timer adapter is not running
+ *   - EALREADY  A timer was encountered that was already canceled
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			     struct rte_event_timer **evtims,
+			     uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->cancel_burst, -EINVAL);
+#endif
+
+	return adapter->cancel_burst(adapter, evtims, nb_evtims);
+}
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index b21c271..e79583a 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -923,8 +923,8 @@ rte_event_dev_close(uint8_t dev_id);
 /**< The event generated from ethdev subsystem */
 #define RTE_EVENT_TYPE_CRYPTODEV        0x1
 /**< The event generated from crypodev subsystem */
-#define RTE_EVENT_TYPE_TIMERDEV         0x2
-/**< The event generated from timerdev subsystem */
+#define RTE_EVENT_TYPE_TIMER		0x2
+/**< The event generated from event timer adapter */
 #define RTE_EVENT_TYPE_CPU              0x3
 /**< The event generated from cpu for pipelining.
  * Application may use *sub_event_type* to further classify the event
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 2/9] eventdev: convert to SPDX license tag in header
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  2018-03-29 21:27         ` [PATCH v8 1/9] " Erik Gabriel Carrillo
@ 2018-03-29 21:27         ` Erik Gabriel Carrillo
  2018-04-02  8:12           ` Jerin Jacob
  2018-03-29 21:27         ` [PATCH v8 3/9] eventtimer: add common code Erik Gabriel Carrillo
                           ` (7 subsequent siblings)
  9 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-29 21:27 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_eventdev.h | 37 +++++--------------------------------
 1 file changed, 5 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index e79583a..f9ad71e 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -1,35 +1,8 @@
-/*
- *   BSD LICENSE
- *
- *   Copyright 2016 Cavium, Inc.
- *   Copyright 2016 Intel Corporation.
- *   Copyright 2016 NXP.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Cavium, Inc nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2016 Cavium, Inc.
+ * Copyright(c) 2016-2018 Intel Corporation.
+ * Copyright(c) 2016 NXP.
+ * All rights reserved.
  */
 
 #ifndef _RTE_EVENTDEV_H_
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 3/9] eventtimer: add common code
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  2018-03-29 21:27         ` [PATCH v8 1/9] " Erik Gabriel Carrillo
  2018-03-29 21:27         ` [PATCH v8 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
@ 2018-03-29 21:27         ` Erik Gabriel Carrillo
  2018-03-29 21:27         ` [PATCH v8 4/9] mk: update library order in static build Erik Gabriel Carrillo
                           ` (6 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-29 21:27 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

This commit adds the logic that is shared by all event timer adapter
drivers; the common code handles instance allocation and some
initialization.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 config/common_base                                |   1 +
 drivers/event/sw/sw_evdev.c                       |  18 +
 lib/librte_eventdev/Makefile                      |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c     | 387 ++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 114 +++++++
 lib/librte_eventdev/rte_eventdev.c                |  22 ++
 lib/librte_eventdev/rte_eventdev.h                |  20 ++
 lib/librte_eventdev/rte_eventdev_pmd.h            |  35 ++
 lib/librte_eventdev/rte_eventdev_version.map      |  21 +-
 9 files changed, 619 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h

diff --git a/config/common_base b/config/common_base
index ee10b44..accc6f5 100644
--- a/config/common_base
+++ b/config/common_base
@@ -550,6 +550,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
 CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
 CONFIG_RTE_EVENT_MAX_DEVS=16
 CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32
 
 #
 # Compile PMD for skeleton event device
diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index 6672fd8..0847547 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -464,6 +464,22 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
 	return 0;
 }
 
+static int
+sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
+			  uint64_t flags,
+			  uint32_t *caps,
+			  const struct rte_event_timer_adapter_ops **ops)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(flags);
+	*caps = 0;
+
+	/* Use default SW ops */
+	*ops = NULL;
+
+	return 0;
+}
+
 static void
 sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
 {
@@ -791,6 +807,8 @@ sw_probe(struct rte_vdev_device *vdev)
 
 			.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
 
+			.timer_adapter_caps_get = sw_timer_adapter_caps_get,
+
 			.xstats_get = sw_xstats_get,
 			.xstats_get_names = sw_xstats_get_names,
 			.xstats_get_by_name = sw_xstats_get_by_name,
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 549b182..8b16e3f 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -20,6 +20,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
 SRCS-y += rte_eventdev.c
 SRCS-y += rte_event_ring.c
 SRCS-y += rte_event_eth_rx_adapter.c
+SRCS-y += rte_event_timer_adapter.c
 
 # export include files
 SYMLINK-y-include += rte_eventdev.h
@@ -29,6 +30,7 @@ SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
 SYMLINK-y-include += rte_event_timer_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter_pmd.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
new file mode 100644
index 0000000..75a14ac
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -0,0 +1,387 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#include <string.h>
+#include <inttypes.h>
+
+#include <rte_memzone.h>
+#include <rte_memory.h>
+#include <rte_dev.h>
+#include <rte_errno.h>
+
+#include "rte_eventdev.h"
+#include "rte_eventdev_pmd.h"
+#include "rte_event_timer_adapter.h"
+#include "rte_event_timer_adapter_pmd.h"
+
+#define DATA_MZ_NAME_MAX_LEN 64
+#define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
+
+static int evtim_logtype;
+
+static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
+
+#define EVTIM_LOG(level, logtype, ...) \
+	rte_log(RTE_LOG_ ## level, logtype, \
+		RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
+			"\n", __func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__,)))
+
+#define EVTIM_LOG_ERR(...) EVTIM_LOG(ERR, evtim_logtype, __VA_ARGS__)
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+#define EVTIM_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#else
+#define EVTIM_LOG_DBG(...) (void)0
+#endif
+
+static int
+default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		     void *conf_arg)
+{
+	struct rte_event_timer_adapter *adapter;
+	struct rte_eventdev *dev;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	int started;
+	uint8_t port_id;
+	uint8_t dev_id;
+	int ret;
+
+	RTE_SET_USED(event_dev_id);
+
+	adapter = &adapters[id];
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+	dev_id = dev->data->dev_id;
+	dev_conf = dev->data->dev_conf;
+
+	started = dev->data->dev_started;
+	if (started)
+		rte_event_dev_stop(dev_id);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports += 1;
+	ret = rte_event_dev_configure(dev_id, &dev_conf);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to configure event dev %u\n", dev_id);
+		if (started)
+			if (rte_event_dev_start(dev_id))
+				return -EIO;
+
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(dev_id, port_id, port_conf);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to setup event port %u on event dev %u\n",
+			      port_id, dev_id);
+		return ret;
+	}
+
+	*event_port_id = port_id;
+
+	if (started)
+		ret = rte_event_dev_start(dev_id);
+
+	return ret;
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf)
+{
+	return rte_event_timer_adapter_create_ext(conf, default_port_conf_cb,
+						  NULL);
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg)
+{
+	uint16_t adapter_id;
+	struct rte_event_timer_adapter *adapter;
+	const struct rte_memzone *mz;
+	char mz_name[DATA_MZ_NAME_MAX_LEN];
+	int n, ret;
+	struct rte_eventdev *dev;
+
+	if (conf == NULL) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Check eventdev ID */
+	if (!rte_event_pmd_is_valid_dev(conf->event_dev_id)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	dev = &rte_eventdevs[conf->event_dev_id];
+
+	adapter_id = conf->timer_adapter_id;
+
+	/* Check that adapter_id is in range */
+	if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Check adapter ID not already allocated */
+	adapter = &adapters[adapter_id];
+	if (adapter->allocated) {
+		rte_errno = EEXIST;
+		return NULL;
+	}
+
+	/* Create shared data area. */
+	n = snprintf(mz_name, sizeof(mz_name), DATA_MZ_NAME_FORMAT, adapter_id);
+	if (n >= (int)sizeof(mz_name)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	mz = rte_memzone_reserve(mz_name,
+				 sizeof(struct rte_event_timer_adapter_data),
+				 conf->socket_id, 0);
+	if (mz == NULL)
+		/* rte_errno set by rte_memzone_reserve */
+		return NULL;
+
+	adapter->data = mz->addr;
+	memset(adapter->data, 0, sizeof(struct rte_event_timer_adapter_data));
+
+	adapter->data->mz = mz;
+	adapter->data->event_dev_id = conf->event_dev_id;
+	adapter->data->id = adapter_id;
+	adapter->data->socket_id = conf->socket_id;
+	adapter->data->conf = *conf;  /* copy conf structure */
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = ret;
+		goto free_memzone;
+	}
+
+	if (!(adapter->data->caps &
+	      RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+		FUNC_PTR_OR_NULL_RET_WITH_ERRNO(conf_cb, -EINVAL);
+		ret = conf_cb(adapter->data->id, adapter->data->event_dev_id,
+			      &adapter->data->event_port_id, conf_arg);
+		if (ret < 0) {
+			rte_errno = ret;
+			goto free_memzone;
+		}
+	}
+
+	/* Allow driver to do some setup */
+	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
+	ret = adapter->ops->init(adapter);
+	if (ret < 0) {
+		rte_errno = ret;
+		goto free_memzone;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+
+free_memzone:
+	rte_memzone_free(adapter->data->mz);
+	return NULL;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->ops->get_info)
+		/* let driver set values it knows */
+		adapter->ops->get_info(adapter, adapter_info);
+
+	/* Set common values */
+	adapter_info->conf = adapter->data->conf;
+	adapter_info->event_dev_port_id = adapter->data->event_port_id;
+	adapter_info->caps = adapter->data->caps;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->start, -EINVAL);
+
+	ret = adapter->ops->start(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 1;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stop, -EINVAL);
+
+	if (adapter->data->started == 0) {
+		EVTIM_LOG_ERR("event timer adapter %"PRIu8" already stopped",
+			      adapter->data->id);
+		return 0;
+	}
+
+	ret = adapter->ops->stop(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 0;
+
+	return 0;
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_lookup(uint16_t adapter_id)
+{
+	char name[DATA_MZ_NAME_MAX_LEN];
+	const struct rte_memzone *mz;
+	struct rte_event_timer_adapter_data *data;
+	struct rte_event_timer_adapter *adapter;
+	int ret;
+	struct rte_eventdev *dev;
+
+	if (adapters[adapter_id].allocated)
+		return &adapters[adapter_id]; /* Adapter is already loaded */
+
+	snprintf(name, DATA_MZ_NAME_MAX_LEN, DATA_MZ_NAME_FORMAT, adapter_id);
+	mz = rte_memzone_lookup(name);
+	if (mz == NULL) {
+		rte_errno = ENOENT;
+		return NULL;
+	}
+
+	data = mz->addr;
+
+	adapter = &adapters[data->id];
+	adapter->data = data;
+
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->uninit, -EINVAL);
+
+	if (adapter->data->started == 1) {
+		EVTIM_LOG_ERR("event timer adapter %"PRIu8" must be stopped "
+			      "before freeing", adapter->data->id);
+		return -EBUSY;
+	}
+
+	/* free impl priv data */
+	ret = adapter->ops->uninit(adapter);
+	if (ret < 0)
+		return ret;
+
+	/* free shared data area */
+	ret = rte_memzone_free(adapter->data->mz);
+	if (ret < 0)
+		return ret;
+
+	adapter->data = NULL;
+	adapter->allocated = 0;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->data->service_inited && service_id != NULL)
+		*service_id = adapter->data->service_id;
+
+	return adapter->data->service_inited ? 0 : -ESRCH;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer_adapter_stats *stats)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_get, -EINVAL);
+	if (stats == NULL)
+		return -EINVAL;
+
+	return adapter->ops->stats_get(adapter, stats);
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_reset, -EINVAL);
+	return adapter->ops->stats_reset(adapter);
+}
+
+RTE_INIT(event_timer_adapter_init_log);
+static void
+event_timer_adapter_init_log(void)
+{
+	evtim_logtype = rte_log_register("lib.eventdev.adapter.timer");
+	if (evtim_logtype >= 0)
+		rte_log_set_level(evtim_logtype, RTE_LOG_NOTICE);
+}
diff --git a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
new file mode 100644
index 0000000..cf3509d
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_PMD_H__
+#define __RTE_EVENT_TIMER_ADAPTER_PMD_H__
+
+/**
+ * @file
+ * RTE Event Timer Adapter API (PMD Side)
+ *
+ * @note
+ * This file provides implementation helpers for internal use by PMDs.  They
+ * are not intended to be exposed to applications and are not subject to ABI
+ * versioning.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "rte_event_timer_adapter.h"
+
+/*
+ * Definitions of functions exported by an event timer adapter implementation
+ * through *rte_event_timer_adapter_ops* structure supplied in the
+ * *rte_event_timer_adapter* structure associated with an event timer adapter.
+ */
+
+typedef int (*rte_event_timer_adapter_init_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation setup */
+typedef int (*rte_event_timer_adapter_uninit_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation teardown */
+typedef int (*rte_event_timer_adapter_start_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Start running event timer adapter */
+typedef int (*rte_event_timer_adapter_stop_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Stop running event timer adapter */
+typedef void (*rte_event_timer_adapter_get_info_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+/**< @internal Get contextual information for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_get_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_stats *stats);
+/**< @internal Get statistics for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_reset_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Reset statistics for event timer adapter */
+
+/**
+ * @internal Structure containing the functions exported by an event timer
+ * adapter implementation.
+ */
+struct rte_event_timer_adapter_ops {
+	rte_event_timer_adapter_init_t		init;  /**< Set up adapter */
+	rte_event_timer_adapter_uninit_t	uninit;/**< Tear down adapter */
+	rte_event_timer_adapter_start_t		start; /**< Start adapter */
+	rte_event_timer_adapter_stop_t		stop;  /**< Stop adapter */
+	rte_event_timer_adapter_get_info_t	get_info;
+	/**< Get info from driver */
+	rte_event_timer_adapter_stats_get_t	stats_get;
+	/**< Get adapter statistics */
+	rte_event_timer_adapter_stats_reset_t	stats_reset;
+	/**< Reset adapter statistics */
+	rte_event_timer_arm_burst_t		arm_burst;
+	/**< Arm one or more event timers */
+	rte_event_timer_arm_tmo_tick_burst_t	arm_tmo_tick_burst;
+	/**< Arm event timers with same expiration time */
+	rte_event_timer_cancel_burst_t		cancel_burst;
+	/**< Cancel one or more event timers */
+};
+
+/**
+ * @internal Adapter data; structure to be placed in shared memory to be
+ * accessible by various processes in a multi-process configuration.
+ */
+struct rte_event_timer_adapter_data {
+	uint8_t id;
+	/**< Event timer adapter ID */
+	uint8_t event_dev_id;
+	/**< Event device ID */
+	uint32_t socket_id;
+	/**< Socket ID where memory is allocated */
+	uint8_t event_port_id;
+	/**< Optional: event port ID used when the inbuilt port is absent */
+	const struct rte_memzone *mz;
+	/**< Event timer adapter memzone pointer */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configuration used to configure the adapter. */
+	uint32_t caps;
+	/**< Adapter capabilities */
+	void *adapter_priv;
+	/**< Timer adapter private data*/
+	uint8_t service_inited;
+	/**< Service initialization state */
+	uint32_t service_id;
+	/**< Service ID*/
+
+	RTE_STD_C11
+	uint8_t started : 1;
+	/**< Flag to indicate adapter started. */
+} __rte_cache_aligned;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_PMD_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.c b/lib/librte_eventdev/rte_eventdev.c
index 851a119..eb3c601 100644
--- a/lib/librte_eventdev/rte_eventdev.c
+++ b/lib/librte_eventdev/rte_eventdev.c
@@ -123,6 +123,28 @@ rte_event_eth_rx_adapter_caps_get(uint8_t dev_id, uint8_t eth_port_id,
 				: 0;
 }
 
+int __rte_experimental
+rte_event_timer_adapter_caps_get(uint8_t dev_id, uint32_t *caps)
+{
+	struct rte_eventdev *dev;
+	const struct rte_event_timer_adapter_ops *ops;
+
+	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+
+	dev = &rte_eventdevs[dev_id];
+
+	if (caps == NULL)
+		return -EINVAL;
+	*caps = 0;
+
+	return dev->dev_ops->timer_adapter_caps_get ?
+				(*dev->dev_ops->timer_adapter_caps_get)(dev,
+									0,
+									caps,
+									&ops)
+				: 0;
+}
+
 static inline int
 rte_event_dev_queue_config(struct rte_eventdev *dev, uint8_t nb_queues)
 {
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index f9ad71e..77fb693 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -215,6 +215,7 @@ extern "C" {
 #include <rte_config.h>
 #include <rte_memory.h>
 #include <rte_errno.h>
+#include <rte_compat.h>
 
 struct rte_mbuf; /* we just use mbuf pointers; no need to include rte_mbuf.h */
 
@@ -1069,6 +1070,25 @@ int
 rte_event_eth_rx_adapter_caps_get(uint8_t dev_id, uint8_t eth_port_id,
 				uint32_t *caps);
 
+#define RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT (1ULL << 0)
+/**< This flag is set when the timer mechanism is in HW. */
+
+/**
+ * Retrieve the event device's timer adapter capabilities.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ *
+ * @param[out] caps
+ *   A pointer to memory to be filled with event timer adapter capabilities.
+ *
+ * @return
+ *   - 0: Success, driver provided event timer adapter capabilities.
+ *   - <0: Error code returned by the driver function.
+ */
+int __rte_experimental
+rte_event_timer_adapter_caps_get(uint8_t dev_id, uint32_t *caps);
+
 struct rte_eventdev_driver;
 struct rte_eventdev_ops;
 struct rte_eventdev;
diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h b/lib/librte_eventdev/rte_eventdev_pmd.h
index 31343b5..0e37f1c 100644
--- a/lib/librte_eventdev/rte_eventdev_pmd.h
+++ b/lib/librte_eventdev/rte_eventdev_pmd.h
@@ -26,6 +26,7 @@ extern "C" {
 #include <rte_malloc.h>
 
 #include "rte_eventdev.h"
+#include "rte_event_timer_adapter_pmd.h"
 
 /* Logging Macros */
 #define RTE_EDEV_LOG_ERR(...) \
@@ -449,6 +450,37 @@ typedef int (*eventdev_eth_rx_adapter_caps_get_t)
 struct rte_event_eth_rx_adapter_queue_conf *queue_conf;
 
 /**
+ * Retrieve the event device's timer adapter capabilities, as well as the ops
+ * structure that an event timer adapter should call through to enter the
+ * driver
+ *
+ * @param dev
+ *   Event device pointer
+ *
+ * @param flags
+ *   Flags that can be used to determine how to select an event timer
+ *   adapter ops structure
+ *
+ * @param[out] caps
+ *   A pointer to memory filled with Rx event adapter capabilities.
+ *
+ * @param[out] ops
+ *   A pointer to the ops pointer to set with the address of the desired ops
+ *   structure
+ *
+ * @return
+ *   - 0: Success, driver provides Rx event adapter capabilities for the
+ *	ethernet device.
+ *   - <0: Error code returned by the driver function.
+ *
+ */
+typedef int (*eventdev_timer_adapter_caps_get_t)(
+				const struct rte_eventdev *dev,
+				uint64_t flags,
+				uint32_t *caps,
+				const struct rte_event_timer_adapter_ops **ops);
+
+/**
  * Add ethernet Rx queues to event device. This callback is invoked if
  * the caps returned from rte_eventdev_eth_rx_adapter_caps_get(, eth_port_id)
  * has RTE_EVENT_ETH_RX_ADAPTER_CAP_INTERNAL_PORT set.
@@ -640,6 +672,9 @@ struct rte_eventdev_ops {
 	eventdev_eth_rx_adapter_stats_reset eth_rx_adapter_stats_reset;
 	/**< Reset ethernet Rx stats */
 
+	eventdev_timer_adapter_caps_get_t timer_adapter_caps_get;
+	/**< Get timer adapter capabilities */
+
 	eventdev_selftest dev_selftest;
 	/**< Start eventdev Selftest */
 };
diff --git a/lib/librte_eventdev/rte_eventdev_version.map b/lib/librte_eventdev/rte_eventdev_version.map
index 2aef470..537afb8 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -66,7 +66,6 @@ DPDK_17.11 {
 	rte_event_eth_rx_adapter_stats_get;
 	rte_event_eth_rx_adapter_stats_reset;
 	rte_event_eth_rx_adapter_stop;
-
 } DPDK_17.08;
 
 DPDK_18.02 {
@@ -74,3 +73,23 @@ DPDK_18.02 {
 
 	rte_event_dev_selftest;
 } DPDK_17.11;
+
+EXPERIMENTAL {
+	global:
+
+        rte_event_timer_adapter_caps_get;
+	rte_event_timer_adapter_create;
+	rte_event_timer_adapter_create_ext;
+	rte_event_timer_adapter_free;
+	rte_event_timer_adapter_get_info;
+	rte_event_timer_adapter_lookup;
+	rte_event_timer_adapter_service_id_get;
+	rte_event_timer_adapter_start;
+	rte_event_timer_adapter_stats_get;
+	rte_event_timer_adapter_stats_reset;
+	rte_event_timer_adapter_stop;
+	rte_event_timer_init;
+	rte_event_timer_arm_burst;
+	rte_event_timer_arm_tmo_tick_burst;
+	rte_event_timer_cancel_burst;
+} DPDK_18.02;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 4/9] mk: update library order in static build
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                           ` (2 preceding siblings ...)
  2018-03-29 21:27         ` [PATCH v8 3/9] eventtimer: add common code Erik Gabriel Carrillo
@ 2018-03-29 21:27         ` Erik Gabriel Carrillo
  2018-03-29 21:27         ` [PATCH v8 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
                           ` (5 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-29 21:27 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

The introduction of the event timer adapter library adds a dependency
on the rte_timer library from the rte_eventdev library.  Update the
order so that the timer library comes after the eventdev library in the
linker command when statically linking applications.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 mk/rte.app.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 94525dc..983ad09 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)        += -lrte_bitratestats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
 
-_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
 
 _LDLIBS-y += --whole-archive
@@ -98,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)       += -lrte_security
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV)         += -lrte_rawdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 5/9] eventtimer: add default software driver
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                           ` (3 preceding siblings ...)
  2018-03-29 21:27         ` [PATCH v8 4/9] mk: update library order in static build Erik Gabriel Carrillo
@ 2018-03-29 21:27         ` Erik Gabriel Carrillo
  2018-04-02  8:42           ` Jerin Jacob
  2018-03-29 21:27         ` [PATCH v8 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
                           ` (4 subsequent siblings)
  9 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-29 21:27 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

If an eventdev PMD does not wish to provide event timer adapter ops
definitions, the library will fall back to a default software
implementation whose entry points are added by this commit.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/Makefile                                  |   2 +-
 lib/librte_eventdev/Makefile                  |   2 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 915 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h |  55 ++
 4 files changed, 972 insertions(+), 2 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a6..965be6c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -31,7 +31,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
 DEPDIRS-librte_security += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash
+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_RAWDEV) += librte_rawdev
 DEPDIRS-librte_rawdev := librte_eal librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 8b16e3f..297df4a 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -14,7 +14,7 @@ LIBABIVER := 3
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool -lrte_timer
 
 # library source files
 SRCS-y += rte_eventdev.c
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 75a14ac..2b35ffd 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -5,11 +5,20 @@
 
 #include <string.h>
 #include <inttypes.h>
+#include <stdbool.h>
+#include <sys/queue.h>
 
 #include <rte_memzone.h>
 #include <rte_memory.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_common.h>
+#include <rte_timer.h>
+#include <rte_service_component.h>
+#include <rte_cycles.h>
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -20,9 +29,13 @@
 #define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
 
 static int evtim_logtype;
+static int evtim_svc_logtype;
+static int evtim_buffer_logtype;
 
 static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+
 #define EVTIM_LOG(level, logtype, ...) \
 	rte_log(RTE_LOG_ ## level, logtype, \
 		RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
@@ -33,8 +46,14 @@ static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 #ifdef RTE_LIBRTE_EVENTDEV_DEBUG
 #define EVTIM_LOG_DBG(...) \
 	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#define EVTIM_BUF_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_buffer_logtype, __VA_ARGS__)
+#define EVTIM_SVC_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_svc_logtype, __VA_ARGS__)
 #else
 #define EVTIM_LOG_DBG(...) (void)0
+#define EVTIM_BUF_LOG_DBG(...) (void)0
+#define EVTIM_SVC_LOG_DBG(...) (void)0
 #endif
 
 static int
@@ -188,6 +207,12 @@ rte_event_timer_adapter_create_ext(
 		}
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Allow driver to do some setup */
 	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
 	ret = adapter->ops->init(adapter);
@@ -305,6 +330,12 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
 		return NULL;
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Set fast-path function pointers */
 	adapter->arm_burst = adapter->ops->arm_burst;
 	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
@@ -377,6 +408,881 @@ rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
 	return adapter->ops->stats_reset(adapter);
 }
 
+/*
+ * Software event timer adapter buffer helper functions
+ */
+
+#define NSECPERSEC 1E9
+
+/* Optimizations used to index into the buffer require that the buffer size
+ * be a power of 2.
+ */
+#define EVENT_BUFFER_SZ 4096
+#define EVENT_BUFFER_BATCHSZ 32
+#define EVENT_BUFFER_MASK (EVENT_BUFFER_SZ - 1)
+
+struct event_buffer {
+	uint16_t head;
+	uint16_t tail;
+	struct rte_event events[EVENT_BUFFER_SZ];
+} __rte_cache_aligned;
+
+static inline bool
+event_buffer_full(struct event_buffer *bufp)
+{
+	return (bufp->head - bufp->tail) == EVENT_BUFFER_SZ;
+}
+
+static inline bool
+event_buffer_batch_ready(struct event_buffer *bufp)
+{
+	return (bufp->head - bufp->tail) >= EVENT_BUFFER_BATCHSZ;
+}
+
+static void
+event_buffer_init(struct event_buffer *bufp)
+{
+	bufp->head = bufp->tail = 0;
+	memset(&bufp->events, 0, sizeof(struct rte_event) * EVENT_BUFFER_SZ);
+}
+
+static int
+event_buffer_add(struct event_buffer *bufp, struct rte_event *eventp)
+{
+	uint16_t head_idx;
+	struct rte_event *buf_eventp;
+
+	if (event_buffer_full(bufp))
+		return -1;
+
+	/* Instead of modulus, bitwise AND with mask to get head_idx. */
+	head_idx = bufp->head & EVENT_BUFFER_MASK;
+	buf_eventp = &bufp->events[head_idx];
+	rte_memcpy(buf_eventp, eventp, sizeof(struct rte_event));
+
+	/* Wrap automatically when overflow occurs. */
+	bufp->head++;
+
+	return 0;
+}
+
+static void
+event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,
+		   uint16_t *nb_events_flushed,
+		   uint16_t *nb_events_inv)
+{
+	uint16_t head_idx, tail_idx, n = 0;
+	struct rte_event *events = bufp->events;
+
+	/* Instead of modulus, bitwise AND with mask to get index. */
+	head_idx = bufp->head & EVENT_BUFFER_MASK;
+	tail_idx = bufp->tail & EVENT_BUFFER_MASK;
+
+	/* Determine the largest contigous run we can attempt to enqueue to the
+	 * event device.
+	 */
+	if (head_idx > tail_idx)
+		n = head_idx - tail_idx;
+	else if (head_idx < tail_idx)
+		n = EVENT_BUFFER_SZ - tail_idx;
+	else {
+		*nb_events_flushed = 0;
+		return;
+	}
+
+	*nb_events_inv = 0;
+	*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
+						     &events[tail_idx], n);
+	if (*nb_events_flushed != n && rte_errno == -EINVAL) {
+		EVTIM_LOG_ERR("failed to enqueue invalid event - dropping it");
+		(*nb_events_inv)++;
+	}
+
+	bufp->tail = bufp->tail + *nb_events_flushed + *nb_events_inv;
+}
+
+/*
+ * Software event timer adapter implementation
+ */
+
+struct rte_event_timer_adapter_sw_data {
+	/* List of messages for outstanding timers */
+	TAILQ_HEAD(, msg) msgs_tailq_head;
+	/* Lock to guard tailq and armed count */
+	rte_spinlock_t msgs_tailq_sl;
+	/* Identifier of service executing timer management logic. */
+	uint32_t service_id;
+	/* The cycle count at which the adapter should next tick */
+	uint64_t next_tick_cycles;
+	/* Incremented as the service moves through phases of an iteration */
+	volatile int service_phase;
+	/* The tick resolution used by adapter instance. May have been
+	 * adjusted from what user requested
+	 */
+	uint64_t timer_tick_ns;
+	/* The minimum tick resolution supported by this adapter instance. */
+	uint64_t min_resolution_ns;
+	/* Maximum timeout in nanoseconds allowed by adapter instance. */
+	uint64_t max_tmo_ns;
+	/* Ring containing messages to arm or cancel event timers */
+	struct rte_ring *msg_ring;
+	/* Mempool containing msg objects */
+	struct rte_mempool *msg_pool;
+	/* Buffered timer expiry events to be enqueued to an event device. */
+	struct event_buffer buffer;
+	/* Statistics */
+	struct rte_event_timer_adapter_stats stats;
+	/* The number of threads currently adding to the message ring */
+	rte_atomic16_t message_producer_count;
+};
+
+enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
+
+struct msg {
+	enum msg_type type;
+	struct rte_event_timer *evtim;
+	struct rte_timer tim;
+	TAILQ_ENTRY(msg) msgs;
+};
+
+static void
+sw_event_timer_cb(struct rte_timer *tim, void *arg)
+{
+	uint16_t nb_evs_flushed, nb_evs_invalid;
+	int ret;
+	struct rte_event_timer *evtim;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	evtim = arg;
+	adapter = (struct rte_event_timer_adapter *)evtim->impl_opaque[1];
+	sw_data = adapter->data->adapter_priv;
+
+	ret = event_buffer_add(&sw_data->buffer, &evtim->ev);
+	if (ret < 0) {
+		/* If event buffer is full, put timer back in list with
+		 * immediate expiry value, so that we process it again on the
+		 * next iteration.
+		 */
+		rte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),
+				     sw_event_timer_cb, evtim);
+
+		sw_data->stats.evtim_retry_count++;
+		EVTIM_LOG_DBG("event buffer full, resetting rte_timer with "
+			      "immediate expiry value");
+	} else {
+		struct msg *m = container_of(tim, struct msg, tim);
+		TAILQ_REMOVE(&sw_data->msgs_tailq_head, m, msgs);
+		EVTIM_BUF_LOG_DBG("buffered an event timer expiry event");
+		evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+
+		/* Free the msg object containing the rte_timer now that
+		 * we've buffered its event successfully.
+		 */
+		rte_mempool_put(sw_data->msg_pool, m);
+
+		/* Bump the count when we successfully add an expiry event to
+		 * the buffer.
+		 */
+		sw_data->stats.evtim_exp_count++;
+	}
+
+	if (event_buffer_batch_ready(&sw_data->buffer)) {
+		event_buffer_flush(&sw_data->buffer,
+				   adapter->data->event_dev_id,
+				   adapter->data->event_port_id,
+				   &nb_evs_flushed,
+				   &nb_evs_invalid);
+
+		sw_data->stats.ev_enq_count += nb_evs_flushed;
+		sw_data->stats.ev_inv_count += nb_evs_invalid;
+	}
+}
+
+static __rte_always_inline uint64_t
+get_timeout_cycles(struct rte_event_timer *evtim,
+		   struct rte_event_timer_adapter *adapter)
+{
+	uint64_t timeout_ns;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	timeout_ns = evtim->timeout_ticks * sw_data->timer_tick_ns;
+	return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
+
+}
+
+/* This function returns true if one or more (adapter) ticks have occurred since
+ * the last time it was called.
+ */
+static inline bool
+adapter_did_tick(struct rte_event_timer_adapter *adapter)
+{
+	uint64_t cycles_per_adapter_tick, start_cycles;
+	uint64_t *next_tick_cyclesp;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	next_tick_cyclesp = &sw_data->next_tick_cycles;
+
+	cycles_per_adapter_tick = sw_data->timer_tick_ns *
+			(rte_get_timer_hz() / NSECPERSEC);
+
+	start_cycles = rte_get_timer_cycles();
+
+	/* Note: initially, *next_tick_cyclesp == 0, so the clause below will
+	 * execute, and set things going.
+	 */
+
+	if (start_cycles >= *next_tick_cyclesp) {
+		/* Snap the current cycle count to the preceding adapter tick
+		 * boundary.
+		 */
+		start_cycles -= start_cycles % cycles_per_adapter_tick;
+
+		*next_tick_cyclesp = start_cycles + cycles_per_adapter_tick;
+
+		return true;
+	}
+
+	return false;
+}
+
+/* Check that event timer timeout value is in range */
+static __rte_always_inline int
+check_timeout(struct rte_event_timer *evtim,
+	      const struct rte_event_timer_adapter *adapter)
+{
+	uint64_t tmo_nsec;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	tmo_nsec = evtim->timeout_ticks * sw_data->timer_tick_ns;
+
+	if (tmo_nsec > sw_data->max_tmo_ns)
+		return -1;
+
+	if (tmo_nsec < sw_data->timer_tick_ns)
+		return -2;
+
+	return 0;
+}
+
+/* Check that event timer event queue sched type matches destination event queue
+ * sched type
+ */
+static __rte_always_inline int
+check_destination_event_queue(struct rte_event_timer *evtim,
+			      const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	uint32_t sched_type;
+
+	ret = rte_event_queue_attr_get(adapter->data->event_dev_id,
+				       evtim->ev.queue_id,
+				       RTE_EVENT_QUEUE_ATTR_SCHEDULE_TYPE,
+				       &sched_type);
+
+	if ((ret < 0 && ret != -EOVERFLOW) ||
+	    evtim->ev.sched_type != sched_type)
+		return -1;
+
+	return 0;
+}
+
+#define NB_OBJS 32
+static int
+sw_event_timer_adapter_service_func(void *arg)
+{
+	int ret, i, num_msgs;
+	uint64_t cycles;
+	uint16_t nb_evs_flushed, nb_evs_invalid;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_timer *tim = NULL;
+	struct msg *msg, *msgs[NB_OBJS];
+
+	RTE_SET_USED(ret);
+
+	adapter = arg;
+	sw_data = adapter->data->adapter_priv;
+
+	sw_data->service_phase = 1;
+	rte_smp_wmb();
+
+	while (rte_atomic16_read(&sw_data->message_producer_count) > 0 ||
+	       !rte_ring_empty(sw_data->msg_ring)) {
+
+		num_msgs = rte_ring_dequeue_burst(sw_data->msg_ring,
+						  (void **)msgs, NB_OBJS, NULL);
+
+		for (i = 0; i < num_msgs; i++) {
+			msg = msgs[i];
+			evtim = msg->evtim;
+
+			switch (msg->type) {
+			case MSG_TYPE_ARM:
+				EVTIM_SVC_LOG_DBG("dequeued ARM message from "
+						  "ring");
+				tim = &msg->tim;
+				rte_timer_init(tim);
+				cycles = get_timeout_cycles(evtim,
+							    adapter);
+				ret = rte_timer_reset(tim, cycles, SINGLE,
+						      rte_lcore_id(),
+						      sw_event_timer_cb,
+						      evtim);
+				RTE_ASSERT(ret == 0);
+
+				evtim->impl_opaque[0] = (uintptr_t)tim;
+				evtim->impl_opaque[1] = (uintptr_t)adapter;
+
+				TAILQ_INSERT_TAIL(&sw_data->msgs_tailq_head,
+						  msg,
+						  msgs);
+				break;
+			case MSG_TYPE_CANCEL:
+				EVTIM_SVC_LOG_DBG("dequeued CANCEL message "
+						  "from ring");
+				tim = (struct rte_timer *)evtim->impl_opaque[0];
+				RTE_ASSERT(tim != NULL);
+
+				ret = rte_timer_stop(tim);
+				RTE_ASSERT(ret == 0);
+
+				/* Free the msg object for the original arm
+				 * request.
+				 */
+				struct msg *m;
+				m = container_of(tim, struct msg, tim);
+				TAILQ_REMOVE(&sw_data->msgs_tailq_head, m,
+					     msgs);
+				rte_mempool_put(sw_data->msg_pool, m);
+
+				/* Free the msg object for the current msg */
+				rte_mempool_put(sw_data->msg_pool, msg);
+
+				evtim->impl_opaque[0] = 0;
+				evtim->impl_opaque[1] = 0;
+
+				break;
+			}
+		}
+	}
+
+	sw_data->service_phase = 2;
+	rte_smp_wmb();
+
+	if (adapter_did_tick(adapter)) {
+		rte_timer_manage();
+
+		event_buffer_flush(&sw_data->buffer,
+				   adapter->data->event_dev_id,
+				   adapter->data->event_port_id,
+				   &nb_evs_flushed, &nb_evs_invalid);
+
+		sw_data->stats.ev_enq_count += nb_evs_flushed;
+		sw_data->stats.ev_inv_count += nb_evs_invalid;
+		sw_data->stats.adapter_tick_count++;
+	}
+
+	sw_data->service_phase = 0;
+	rte_smp_wmb();
+
+	return 0;
+}
+
+/* The adapter initialization function rounds the mempool size up to the next
+ * power of 2, so we can take the difference between that value and what the
+ * user requested, and use the space for caches.  This avoids a scenario where a
+ * user can't arm the number of timers the adapter was configured with because
+ * mempool objects have been lost to caches.
+ *
+ * nb_actual should always be a power of 2, so we can iterate over the powers
+ * of 2 to see what the largest cache size we can use is.
+ */
+static int
+compute_msg_mempool_cache_size(uint64_t nb_requested, uint64_t nb_actual)
+{
+	int i;
+	int size;
+	int cache_size = 0;
+
+	for (i = 0; ; i++) {
+		size = 1 << i;
+
+		if (RTE_MAX_LCORE * size < (int)(nb_actual - nb_requested) &&
+		    size < RTE_MEMPOOL_CACHE_MAX_SIZE &&
+		    size <= nb_actual / 1.5)
+			cache_size = size;
+		else
+			break;
+	}
+
+	return cache_size;
+}
+
+static uint64_t
+get_min_resolution_ns(void)
+{
+	return 1E5;
+}
+
+static int
+sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	uint64_t nb_timers;
+	unsigned int flags;
+	struct rte_service_spec service;
+	static bool timer_subsystem_inited; // static initialized to false
+
+	/* Allocate storage for SW implementation data */
+	char priv_data_name[RTE_RING_NAMESIZE];
+	snprintf(priv_data_name, RTE_RING_NAMESIZE, "sw_evtim_adap_priv_%"PRIu8,
+		 adapter->data->id);
+	adapter->data->adapter_priv = rte_zmalloc_socket(
+				priv_data_name,
+				sizeof(struct rte_event_timer_adapter_sw_data),
+				RTE_CACHE_LINE_SIZE,
+				adapter->data->socket_id);
+	if (adapter->data->adapter_priv == NULL) {
+		EVTIM_LOG_ERR("failed to allocate space for private data");
+		rte_errno = ENOMEM;
+		return -1;
+	}
+
+	sw_data = adapter->data->adapter_priv;
+
+	sw_data->min_resolution_ns = get_min_resolution_ns();
+	if (adapter->data->conf.timer_tick_ns < sw_data->min_resolution_ns) {
+		if (adapter->data->conf.flags &
+		    RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES)
+			sw_data->timer_tick_ns = sw_data->min_resolution_ns;
+	} else
+		sw_data->timer_tick_ns = adapter->data->conf.timer_tick_ns;
+
+	/* No limit on max tmo value */
+	sw_data->max_tmo_ns = adapter->data->conf.max_tmo_ns;
+
+	TAILQ_INIT(&sw_data->msgs_tailq_head);
+	rte_spinlock_init(&sw_data->msgs_tailq_sl);
+	rte_atomic16_init(&sw_data->message_producer_count);
+
+	/* Rings require power of 2, so round up to next such value */
+	nb_timers = rte_align64pow2(adapter->data->conf.nb_timers);
+
+	char msg_ring_name[RTE_RING_NAMESIZE];
+	snprintf(msg_ring_name, RTE_RING_NAMESIZE,
+		 "sw_evtim_adap_msg_ring_%"PRIu8, adapter->data->id);
+	flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+		RING_F_SP_ENQ | RING_F_SC_DEQ :
+		RING_F_SC_DEQ;
+	sw_data->msg_ring = rte_ring_create(msg_ring_name, nb_timers,
+					    adapter->data->socket_id, flags);
+	if (sw_data->msg_ring == NULL) {
+		EVTIM_LOG_ERR("failed to create message ring");
+		rte_errno = ENOMEM;
+		goto free_priv_data;
+	}
+
+	char pool_name[RTE_RING_NAMESIZE];
+	snprintf(pool_name, RTE_RING_NAMESIZE, "sw_evtim_adap_msg_pool_%"PRIu8,
+		 adapter->data->id);
+
+	/* Both the arming/canceling thread and the service thread will do puts
+	 * to the mempool, but if the SP_PUT flag is enabled, we can specify
+	 * single-consumer get for the mempool.
+	 */
+	flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+		MEMPOOL_F_SC_GET : 0;
+
+	/* The usable size of a ring is count - 1, so subtract one here to
+	 * make the counts agree.
+	 */
+	int pool_size = nb_timers - 1;
+	int cache_size = compute_msg_mempool_cache_size(
+				adapter->data->conf.nb_timers, nb_timers);
+	sw_data->msg_pool = rte_mempool_create(pool_name, pool_size,
+					       sizeof(struct msg), cache_size,
+					       0, NULL, NULL, NULL, NULL,
+					       adapter->data->socket_id, flags);
+	if (sw_data->msg_pool == NULL) {
+		EVTIM_LOG_ERR("failed to create message object mempool");
+		rte_errno = ENOMEM;
+		goto free_msg_ring;
+	}
+
+	event_buffer_init(&sw_data->buffer);
+
+	/* Register a service component to run adapter logic */
+	memset(&service, 0, sizeof(service));
+	snprintf(service.name, RTE_SERVICE_NAME_MAX,
+		 "sw_evimer_adap_svc_%"PRIu8, adapter->data->id);
+	service.socket_id = adapter->data->socket_id;
+	service.callback = sw_event_timer_adapter_service_func;
+	service.callback_userdata = adapter;
+	service.capabilities &= ~(RTE_SERVICE_CAP_MT_SAFE);
+	ret = rte_service_component_register(&service, &sw_data->service_id);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to register service %s with id %"PRIu32
+			      ": err = %d", service.name, sw_data->service_id,
+			      ret);
+
+		rte_errno = ENOSPC;
+		goto free_msg_pool;
+	}
+
+	EVTIM_LOG_DBG("registered service %s with id %"PRIu32, service.name,
+		      sw_data->service_id);
+
+	adapter->data->service_id = sw_data->service_id;
+	adapter->data->service_inited = 1;
+
+	if (!timer_subsystem_inited) {
+		rte_timer_subsystem_init();
+		timer_subsystem_inited = true;
+	}
+
+	return 0;
+
+free_msg_pool:
+	rte_mempool_free(sw_data->msg_pool);
+free_msg_ring:
+	rte_ring_free(sw_data->msg_ring);
+free_priv_data:
+	rte_free(sw_data);
+	return -1;
+}
+
+static int
+sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct msg *m1, *m2;
+	struct rte_event_timer_adapter_sw_data *sw_data =
+						adapter->data->adapter_priv;
+
+	rte_spinlock_lock(&sw_data->msgs_tailq_sl);
+
+	/* Cancel outstanding rte_timers and free msg objects */
+	m1 = TAILQ_FIRST(&sw_data->msgs_tailq_head);
+	while (m1 != NULL) {
+		EVTIM_LOG_DBG("freeing outstanding timer");
+		m2 = TAILQ_NEXT(m1, msgs);
+
+		rte_timer_stop_sync(&m1->tim);
+		rte_mempool_put(sw_data->msg_pool, m1);
+
+		m1 = m2;
+	}
+
+	rte_spinlock_unlock(&sw_data->msgs_tailq_sl);
+
+	ret = rte_service_component_unregister(sw_data->service_id);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to unregister service component");
+		return ret;
+	}
+
+	rte_ring_free(sw_data->msg_ring);
+	rte_mempool_free(sw_data->msg_pool);
+	rte_free(adapter->data->adapter_priv);
+
+	return 0;
+}
+
+static inline int32_t
+get_mapped_count_for_service(uint32_t service_id)
+{
+	int32_t core_count, i, mapped_count = 0;
+	uint32_t lcore_arr[RTE_MAX_LCORE];
+
+	core_count = rte_service_lcore_list(lcore_arr, RTE_MAX_LCORE);
+
+	for (i = 0; i < core_count; i++)
+		if (rte_service_map_lcore_get(service_id, lcore_arr[i]) == 1)
+			mapped_count++;
+
+	return mapped_count;
+}
+
+static int
+sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int mapped_count;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+
+	/* Mapping the service to more than one service core can introduce
+	 * delays while one thread is waiting to acquire a lock, so only allow
+	 * one core to be mapped to the service.
+	 */
+	mapped_count = get_mapped_count_for_service(sw_data->service_id);
+
+	if (mapped_count == 1)
+		return rte_service_component_runstate_set(sw_data->service_id,
+							  1);
+
+	return mapped_count < 1 ? -ENOENT : -ENOTSUP;
+}
+
+static int
+sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data =
+						adapter->data->adapter_priv;
+
+	ret = rte_service_component_runstate_set(sw_data->service_id, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Wait for the service to complete its final iteration before
+	 * stopping.
+	 */
+	while (sw_data->service_phase != 0)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	return 0;
+}
+
+static void
+sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+
+	adapter_info->min_resolution_ns = sw_data->min_resolution_ns; // 100 us
+	adapter_info->resolution_ns = sw_data->timer_tick_ns;
+	adapter_info->max_tmo_ns = sw_data->max_tmo_ns;
+}
+
+static int
+sw_event_timer_adapter_stats_get(const struct rte_event_timer_adapter *adapter,
+				 struct rte_event_timer_adapter_stats *stats)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	*stats = sw_data->stats;
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_stats_reset(
+				const struct rte_event_timer_adapter *adapter)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	memset(&sw_data->stats, 0, sizeof(sw_data->stats));
+	return 0;
+}
+
+static __rte_always_inline uint16_t
+__sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **evtims,
+			  uint16_t nb_evtims)
+{
+	uint16_t i;
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct msg *msgs[nb_evtims];
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	/* Check that the service is running. */
+	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
+		rte_errno = EINVAL;
+		return 0;
+	}
+#endif
+
+	sw_data = adapter->data->adapter_priv;
+
+	ret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (ret < 0) {
+		rte_errno = ENOSPC;
+		return 0;
+	}
+
+	/* Let the service know we're producing messages for it to process */
+	rte_atomic16_inc(&sw_data->message_producer_count);
+
+	/* If the service is managing timers, wait for it to finish */
+	while (sw_data->service_phase == 2)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	for (i = 0; i < nb_evtims; i++) {
+		/* Don't modify the event timer state in these cases */
+		if (evtims[i]->state == RTE_EVENT_TIMER_ARMED) {
+			rte_errno = EALREADY;
+			break;
+		} else if (!(evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
+		    evtims[i]->state == RTE_EVENT_TIMER_CANCELED)) {
+			rte_errno = EINVAL;
+			break;
+		}
+
+		ret = check_timeout(evtims[i], adapter);
+		if (ret == -1) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOLATE;
+			rte_errno = EINVAL;
+			break;
+		}
+		if (ret == -2) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOEARLY;
+			rte_errno = EINVAL;
+			break;
+		}
+
+		if (check_destination_event_queue(evtims[i], adapter) < 0) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR;
+			rte_errno = EINVAL;
+			break;
+		}
+
+		/* Checks passed, set up a message to enqueue */
+		msgs[i]->type = MSG_TYPE_ARM;
+		msgs[i]->evtim = evtims[i];
+
+		/* Set the payload pointer if not set. */
+		if (evtims[i]->ev.event_ptr == NULL)
+			evtims[i]->ev.event_ptr = evtims[i];
+
+		/* msg objects that get enqueued successfully will be freed
+		 * either by a future cancel operation or by the timer
+		 * expiration callback.
+		 */
+		if (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {
+			rte_errno = ENOSPC;
+			break;
+		}
+
+		EVTIM_LOG_DBG("enqueued ARM message to ring");
+
+		evtims[i]->state = RTE_EVENT_TIMER_ARMED;
+	}
+
+	/* Let the service know we're done producing messages */
+	rte_atomic16_dec(&sw_data->message_producer_count);
+
+	if (i < nb_evtims)
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],
+				     nb_evtims - i);
+
+	return i;
+}
+
+static uint16_t
+sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			 struct rte_event_timer **evtims,
+			 uint16_t nb_evtims)
+{
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
+}
+
+static uint16_t
+sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			    struct rte_event_timer **evtims,
+			    uint16_t nb_evtims)
+{
+	uint16_t i;
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct msg *msgs[nb_evtims];
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	/* Check that the service is running. */
+	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
+		rte_errno = EINVAL;
+		return 0;
+	}
+#endif
+
+	sw_data = adapter->data->adapter_priv;
+
+	ret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (ret < 0) {
+		rte_errno = ENOSPC;
+		return 0;
+	}
+
+	/* Let the service know we're producing messages for it to process */
+	rte_atomic16_inc(&sw_data->message_producer_count);
+
+	/* If the service could be modifying event timer states, wait */
+	while (sw_data->service_phase == 2)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	for (i = 0; i < nb_evtims; i++) {
+		/* Don't modify the event timer state in these cases */
+		if (evtims[i]->state == RTE_EVENT_TIMER_CANCELED) {
+			rte_errno = EALREADY;
+			break;
+		} else if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
+			rte_errno = EINVAL;
+			break;
+		}
+
+		msgs[i]->type = MSG_TYPE_CANCEL;
+		msgs[i]->evtim = evtims[i];
+
+		if (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {
+			rte_errno = ENOSPC;
+			break;
+		}
+
+		EVTIM_LOG_DBG("enqueued CANCEL message to ring");
+
+		evtims[i]->state = RTE_EVENT_TIMER_CANCELED;
+	}
+
+	/* Let the service know we're done producing messages */
+	rte_atomic16_dec(&sw_data->message_producer_count);
+
+	if (i < nb_evtims)
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],
+				     nb_evtims - i);
+
+	return i;
+}
+
+static uint16_t
+sw_event_timer_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer **evtims,
+				  uint64_t timeout_ticks,
+				  uint16_t nb_evtims)
+{
+	int i;
+
+	for (i = 0; i < nb_evtims; i++)
+		evtims[i]->timeout_ticks = timeout_ticks;
+
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
+}
+
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
+	.init = sw_event_timer_adapter_init,
+	.uninit = sw_event_timer_adapter_uninit,
+	.start = sw_event_timer_adapter_start,
+	.stop = sw_event_timer_adapter_stop,
+	.get_info = sw_event_timer_adapter_get_info,
+	.stats_get = sw_event_timer_adapter_stats_get,
+	.stats_reset = sw_event_timer_adapter_stats_reset,
+	.arm_burst = sw_event_timer_arm_burst,
+	.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
+	.cancel_burst = sw_event_timer_cancel_burst,
+};
+
 RTE_INIT(event_timer_adapter_init_log);
 static void
 event_timer_adapter_init_log(void)
@@ -384,4 +1290,13 @@ event_timer_adapter_init_log(void)
 	evtim_logtype = rte_log_register("lib.eventdev.adapter.timer");
 	if (evtim_logtype >= 0)
 		rte_log_set_level(evtim_logtype, RTE_LOG_NOTICE);
+
+	evtim_buffer_logtype = rte_log_register("lib.eventdev.adapter.timer."
+						"buffer");
+	if (evtim_buffer_logtype >= 0)
+		rte_log_set_level(evtim_buffer_logtype, RTE_LOG_NOTICE);
+
+	evtim_svc_logtype = rte_log_register("lib.eventdev.adapter.timer.svc");
+	if (evtim_svc_logtype >= 0)
+		rte_log_set_level(evtim_svc_logtype, RTE_LOG_NOTICE);
 }
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index 6a76791..2bc62b2 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -339,6 +339,8 @@ rte_event_timer_adapter_get_info(
  *   - 0: Success, adapter started.
  *   - <0: Error code returned by the driver start function.
  *   - -EINVAL if adapter identifier invalid
+ *   - -ENOENT if software adapter but no service core mapped
+ *   - -ENOTSUP if software adapter and more than one service core mapped
  */
 int __rte_experimental
 rte_event_timer_adapter_start(
@@ -465,6 +467,59 @@ int __rte_experimental rte_event_timer_adapter_stats_reset(
 		struct rte_event_timer_adapter *adapter);
 
 /**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure, if the event dev doesn't use a rte_service
+ *   function, this function returns -ESRCH.
+ */
+int
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param[out] stats
+ *   A pointer to a structure to fill with statistics.
+ *
+ * @return
+ *   - 0: Successfully retrieved.
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				struct rte_event_timer_adapter_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully reset;
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_reset(
+				struct rte_event_timer_adapter *adapter);
+
+/**
  * @warning
  * @b EXPERIMENTAL: this structure may change without prior notice
  *
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 6/9] eventtimer: add support for meson build system
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                           ` (4 preceding siblings ...)
  2018-03-29 21:27         ` [PATCH v8 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
@ 2018-03-29 21:27         ` Erik Gabriel Carrillo
  2018-03-29 21:27         ` [PATCH v8 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
                           ` (3 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-29 21:27 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 config/rte_config.h             | 1 +
 lib/librte_eventdev/meson.build | 9 ++++++---
 lib/meson.build                 | 3 ++-
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/config/rte_config.h b/config/rte_config.h
index 72c0aa2..117c19f 100644
--- a/config/rte_config.h
+++ b/config/rte_config.h
@@ -55,6 +55,7 @@
 /* eventdev defines */
 #define RTE_EVENT_MAX_DEVS 16
 #define RTE_EVENT_MAX_QUEUES_PER_DEV 64
+#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 32
 
 /* ip_fragmentation defines */
 #define RTE_LIBRTE_IP_FRAG_MAX_FRAG 4
diff --git a/lib/librte_eventdev/meson.build b/lib/librte_eventdev/meson.build
index e1e22a5..232b870 100644
--- a/lib/librte_eventdev/meson.build
+++ b/lib/librte_eventdev/meson.build
@@ -5,11 +5,14 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_eventdev.c',
 		'rte_event_ring.c',
-		'rte_event_eth_rx_adapter.c')
+		'rte_event_eth_rx_adapter.c',
+		'rte_event_timer_adapter.c')
 headers = files('rte_eventdev.h',
 		'rte_eventdev_pmd.h',
 		'rte_eventdev_pmd_pci.h',
 		'rte_eventdev_pmd_vdev.h',
 		'rte_event_ring.h',
-		'rte_event_eth_rx_adapter.h')
-deps += ['ring', 'ethdev', 'hash']
+		'rte_event_eth_rx_adapter.h',
+		'rte_event_timer_adapter.h',
+		'rte_event_timer_adapter_pmd.h')
+deps += ['ring', 'ethdev', 'hash', 'mempool', 'timer']
diff --git a/lib/meson.build b/lib/meson.build
index ef61591..b1ad35f 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -13,13 +13,14 @@ libraries = [ 'compat', # just a header, used for versioning
 	'metrics', # bitrate/latency stats depends on this
 	'hash',    # efd depends on this
 	'kvargs',  # cryptodev depends on this
+	'timer',   # eventdev depends on this
 	'acl', 'bbdev', 'bitratestats', 'cfgfile',
 	'cmdline', 'cryptodev',
 	'distributor', 'efd', 'eventdev',
 	'gro', 'gso', 'ip_frag', 'jobstats',
 	'kni', 'latencystats', 'lpm', 'member',
 	'meter', 'power', 'pdump',
-	'reorder', 'sched', 'security', 'timer', 'vhost',
+	'reorder', 'sched', 'security', 'vhost',
 	# add pkt framework libs which use other libs from above
 	'port', 'table', 'pipeline',
 	# flow_classify lib depends on pkt framework table lib
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 7/9] test: add event timer adapter auto-test
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                           ` (5 preceding siblings ...)
  2018-03-29 21:27         ` [PATCH v8 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
@ 2018-03-29 21:27         ` Erik Gabriel Carrillo
  2018-03-30 15:48           ` Bhagavatula, Pavan
  2018-03-29 21:27         ` [PATCH v8 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
                           ` (2 subsequent siblings)
  9 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-29 21:27 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 test/test/Makefile                   |    1 +
 test/test/test_event_timer_adapter.c | 1837 ++++++++++++++++++++++++++++++++++
 2 files changed, 1838 insertions(+)
 create mode 100644 test/test/test_event_timer_adapter.c

diff --git a/test/test/Makefile b/test/test/Makefile
index a88cc38..c9c007c9 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -185,6 +185,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
 SRCS-y += test_eventdev.c
 SRCS-y += test_event_ring.c
 SRCS-y += test_event_eth_rx_adapter.c
+SRCS-y += test_event_timer_adapter.c
 endif
 
 ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y)
diff --git a/test/test/test_event_timer_adapter.c b/test/test/test_event_timer_adapter.c
new file mode 100644
index 0000000..42c425e
--- /dev/null
+++ b/test/test/test_event_timer_adapter.c
@@ -0,0 +1,1837 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc
+ * Copyright(c) 2017-2018 Intel Corporation.
+ */
+
+#include <rte_atomic.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_debug.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_eventdev.h>
+#include <rte_event_timer_adapter.h>
+#include <rte_mempool.h>
+#include <rte_launch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_random.h>
+#include <rte_bus_vdev.h>
+#include <rte_service.h>
+#include <stdbool.h>
+
+#include "test.h"
+
+/* 4K timers corresponds to sw evdev max inflight events */
+#define MAX_TIMERS  (4 * 1024)
+#define BKT_TCK_NSEC
+
+#define NSECPERSEC 1E9
+#define BATCH_SIZE 16
+/* Both the app lcore and adapter ports are linked to this queue */
+#define TEST_QUEUE_ID 0
+/* Port the application dequeues from */
+#define TEST_PORT_ID 0
+#define TEST_ADAPTER_ID 0
+
+/* Handle log statements in same manner as test macros */
+#define LOG_DBG(...)	RTE_LOG(DEBUG, EAL, __VA_ARGS__)
+
+static int evdev;
+static struct rte_event_timer_adapter *timdev;
+static struct rte_mempool *eventdev_test_mempool;
+static struct rte_ring *timer_producer_ring;
+static uint64_t global_bkt_tck_ns;
+static volatile uint8_t arm_done;
+
+static bool using_services;
+static uint32_t test_lcore1;
+static uint32_t test_lcore2;
+static uint32_t test_lcore3;
+static uint32_t sw_evdev_slcore;
+static uint32_t sw_adptr_slcore;
+
+static inline void
+devconf_set_default_sane_values(struct rte_event_dev_config *dev_conf,
+		struct rte_event_dev_info *info)
+{
+	memset(dev_conf, 0, sizeof(struct rte_event_dev_config));
+	dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns;
+	dev_conf->nb_event_ports = 1;
+	dev_conf->nb_event_queues = 1;
+	dev_conf->nb_event_queue_flows = info->max_event_queue_flows;
+	dev_conf->nb_event_port_dequeue_depth =
+		info->max_event_port_dequeue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+		info->max_event_port_enqueue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+		info->max_event_port_enqueue_depth;
+	dev_conf->nb_events_limit =
+		info->max_num_events;
+}
+
+static inline int
+eventdev_setup(void)
+{
+	int ret;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_dev_info info;
+	uint32_t service_id;
+
+	ret = rte_event_dev_info_get(evdev, &info);
+	TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info");
+	TEST_ASSERT(info.max_num_events >= (int32_t)MAX_TIMERS,
+			"ERROR max_num_events=%d < max_events=%d",
+			info.max_num_events, MAX_TIMERS);
+
+	devconf_set_default_sane_values(&dev_conf, &info);
+	ret = rte_event_dev_configure(evdev, &dev_conf);
+	TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev");
+
+	ret = rte_event_queue_setup(evdev, 0, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", 0);
+
+	/* Configure event port */
+	ret = rte_event_port_setup(evdev, 0, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup port=%d", 0);
+	ret = rte_event_port_link(evdev, 0, NULL, NULL, 0);
+	TEST_ASSERT(ret >= 0, "Failed to link all queues port=%d", 0);
+
+	/* If this is a software event device, map and start its service */
+	if (rte_event_dev_service_id_get(evdev, &service_id) == 0) {
+		TEST_ASSERT_SUCCESS(rte_service_lcore_add(sw_evdev_slcore),
+				"Failed to add service core");
+		TEST_ASSERT_SUCCESS(rte_service_lcore_start(
+				sw_evdev_slcore),
+				"Failed to start service core");
+		TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(
+				service_id, sw_evdev_slcore, 1),
+				"Failed to map evdev service");
+		TEST_ASSERT_SUCCESS(rte_service_runstate_set(
+				service_id, 1),
+				"Failed to start evdev service");
+	}
+
+	ret = rte_event_dev_start(evdev);
+	TEST_ASSERT_SUCCESS(ret, "Failed to start device");
+
+	return TEST_SUCCESS;
+}
+
+static int
+testsuite_setup(void)
+{
+	/* Some of the multithreaded tests require 3 other lcores to run */
+	unsigned int required_lcore_count = 4;
+	uint32_t service_id;
+
+	/* To make it easier to map services later if needed, just reset
+	 * service core state.
+	 */
+	(void) rte_service_lcore_reset_all();
+
+	if (!rte_event_dev_count()) {
+		/* If there is no hardware eventdev, or no software vdev was
+		 * specified on the command line, create an instance of
+		 * event_sw.
+		 */
+		LOG_DBG("Failed to find a valid event device... testing with"
+			" event_sw device\n");
+		TEST_ASSERT_SUCCESS(rte_vdev_init("event_sw0", NULL),
+					"Error creating eventdev");
+		evdev = rte_event_dev_get_dev_id("event_sw0");
+	}
+
+	if (rte_event_dev_service_id_get(evdev, &service_id) == 0) {
+		/* A software event device will use a software event timer
+		 * adapter as well. 2 more cores required to convert to
+		 * service cores.
+		 */
+		required_lcore_count += 2;
+		using_services = true;
+	}
+
+	if (rte_lcore_count() < required_lcore_count) {
+		printf("%d lcores needed to run tests", required_lcore_count);
+		return TEST_FAILED;
+	}
+
+	/* Assign lcores for various tasks */
+	test_lcore1 = rte_get_next_lcore(-1, 1, 0);
+	test_lcore2 = rte_get_next_lcore(test_lcore1, 1, 0);
+	test_lcore3 = rte_get_next_lcore(test_lcore2, 1, 0);
+	if (using_services) {
+		sw_evdev_slcore = rte_get_next_lcore(test_lcore3, 1, 0);
+		sw_adptr_slcore = rte_get_next_lcore(sw_evdev_slcore, 1, 0);
+	}
+
+	return eventdev_setup();
+}
+
+static void
+testsuite_teardown(void)
+{
+	rte_event_dev_stop(evdev);
+	rte_event_dev_close(evdev);
+}
+
+static int
+setup_adapter_service(struct rte_event_timer_adapter *adptr)
+{
+	uint32_t adapter_service_id;
+	int ret;
+
+	/* retrieve service ids */
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(adptr,
+			&adapter_service_id), "Failed to get event timer "
+			"adapter service id");
+	/* add a service core and start it */
+	ret = rte_service_lcore_add(sw_adptr_slcore);
+	TEST_ASSERT(ret == 0 || ret == -EALREADY,
+			"Failed to add service core");
+	ret = rte_service_lcore_start(sw_adptr_slcore);
+	TEST_ASSERT(ret == 0 || ret == -EALREADY,
+			"Failed to start service core");
+
+	/* map services to it */
+	TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(adapter_service_id,
+			sw_adptr_slcore, 1),
+			"Failed to map adapter service");
+
+	/* set services to running */
+	TEST_ASSERT_SUCCESS(rte_service_runstate_set(adapter_service_id, 1),
+			"Failed to start event timer adapter service");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		  void *conf_arg)
+{
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_dev_info info;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	uint32_t started;
+	static int port_allocated;
+	static uint8_t port_id;
+	int ret;
+
+	if (port_allocated) {
+		*event_port_id = port_id;
+		return 0;
+	}
+
+	RTE_SET_USED(id);
+
+	ret = rte_event_dev_attr_get(event_dev_id, RTE_EVENT_DEV_ATTR_STARTED,
+				     &started);
+	if (ret < 0)
+		return ret;
+
+	if (started)
+		rte_event_dev_stop(event_dev_id);
+
+	ret = rte_event_dev_info_get(evdev, &info);
+	if (ret < 0)
+		return ret;
+
+	devconf_set_default_sane_values(&dev_conf, &info);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports++;
+
+	ret = rte_event_dev_configure(event_dev_id, &dev_conf);
+	if (ret < 0) {
+		if (started)
+			rte_event_dev_start(event_dev_id);
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(event_dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(event_dev_id, port_id, port_conf);
+	if (ret < 0)
+		return ret;
+
+	*event_port_id = port_id;
+
+	if (started)
+		rte_event_dev_start(event_dev_id);
+
+	/* Reuse this port number next time this is called */
+	port_allocated = 1;
+
+	return 0;
+}
+
+static int
+_timdev_setup(uint64_t max_tmo_ns, uint64_t bkt_tck_ns)
+{
+	struct rte_event_timer_adapter_conf config = {
+		.event_dev_id = evdev,
+		.timer_adapter_id = TEST_ADAPTER_ID,
+		.timer_tick_ns = bkt_tck_ns,
+		.max_tmo_ns = max_tmo_ns,
+		.nb_timers = MAX_TIMERS * 10,
+	};
+	uint32_t caps = 0;
+	const char *pool_name = "timdev_test_pool";
+
+	global_bkt_tck_ns = bkt_tck_ns;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_caps_get(evdev, &caps),
+				"failed to get adapter capabilities");
+	if (!(caps & RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+		timdev = rte_event_timer_adapter_create_ext(&config,
+							    test_port_conf_cb,
+							    NULL);
+		setup_adapter_service(timdev);
+		using_services = true;
+	} else
+		timdev = rte_event_timer_adapter_create(&config);
+
+	TEST_ASSERT_NOT_NULL(timdev,
+			"failed to create event timer ring");
+
+	TEST_ASSERT_EQUAL(rte_event_timer_adapter_start(timdev), 0,
+			"failed to Start event timer adapter");
+
+	/* Create event timer mempool */
+	eventdev_test_mempool = rte_mempool_create(pool_name,
+			MAX_TIMERS * 2,
+			sizeof(struct rte_event_timer), /* element size*/
+			0, /* cache size*/
+			0, NULL, NULL, NULL, NULL,
+			rte_socket_id(), 0);
+	if (!eventdev_test_mempool) {
+		printf("ERROR creating mempool\n");
+		return TEST_FAILED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+timdev_setup_usec(void)
+{
+	return using_services ?
+		/* Max timeout is 10,000us and bucket interval is 100us */
+		_timdev_setup(1E7, 1E5) :
+		/* Max timeout is 100us and bucket interval is 1us */
+		_timdev_setup(1E5, 1E3);
+}
+
+static int
+timdev_setup_usec_multicore(void)
+{
+	return using_services ?
+		/* Max timeout is 10,000us and bucket interval is 100us */
+		_timdev_setup(1E7, 1E5) :
+		/* Max timeout is 100us and bucket interval is 1us */
+		_timdev_setup(1E5, 1E3);
+}
+
+static int
+timdev_setup_msec(void)
+{
+	/* Max timeout is 2 mins, and bucket interval is 100 ms */
+	return _timdev_setup(180 * NSECPERSEC, NSECPERSEC / 10);
+}
+
+static int
+timdev_setup_sec(void)
+{
+	/* Max timeout is 100sec and bucket interval is 1sec */
+	return _timdev_setup(1E11, 1E9);
+}
+
+static int
+timdev_setup_sec_multicore(void)
+{
+	/* Max timeout is 100sec and bucket interval is 1sec */
+	return _timdev_setup(1E11, 1E9);
+}
+
+static void
+timdev_teardown(void)
+{
+	rte_event_timer_adapter_stop(timdev);
+	rte_event_timer_adapter_free(timdev);
+
+	rte_mempool_free(eventdev_test_mempool);
+}
+
+static inline int
+test_timer_state(void)
+{
+	struct rte_event_timer *ev_tim;
+	struct rte_event ev;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&ev_tim);
+	*ev_tim = tim;
+	ev_tim->ev.event_ptr = ev_tim;
+	ev_tim->timeout_ticks = 120;
+
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 0,
+			"Armed timer exceeding max_timeout.");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ERROR_TOOLATE,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_ERROR_TOOLATE, ev_tim->state);
+
+	ev_tim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	ev_tim->timeout_ticks = 10;
+
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+			"Failed to arm timer with proper timeout.");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_ARMED, ev_tim->state);
+
+	if (!using_services)
+		rte_delay_us(20);
+	else
+		rte_delay_us(1000 + 200);
+	TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1, 0), 1,
+			"Armed timer failed to trigger.");
+
+	ev_tim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	ev_tim->timeout_ticks = 90;
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+			"Failed to arm timer with proper timeout.");
+	TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(timdev, &ev_tim, 1),
+			1, "Failed to cancel armed timer");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_CANCELED,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_CANCELED, ev_tim->state);
+
+	rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+_arm_timers(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers; i++) {
+
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+_wait_timer_triggers(uint64_t wait_sec, uint64_t arm_count,
+		uint64_t cancel_count)
+{
+	uint8_t valid_event;
+	uint64_t events = 0;
+	uint64_t wait_start, max_wait;
+	struct rte_event ev;
+
+	max_wait = rte_get_timer_hz() * wait_sec;
+	wait_start = rte_get_timer_cycles();
+	while (1) {
+		if (rte_get_timer_cycles() - wait_start > max_wait) {
+			if (events + cancel_count != arm_count)
+				TEST_ASSERT_SUCCESS(max_wait,
+					"Max time limit for timers exceeded.");
+			break;
+		}
+
+		valid_event = rte_event_dequeue_burst(evdev, 0, &ev, 1, 0);
+		if (!valid_event)
+			continue;
+
+		rte_mempool_put(eventdev_test_mempool, ev.event_ptr);
+		events++;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm(void)
+{
+	TEST_ASSERT_SUCCESS(_arm_timers(20, MAX_TIMERS),
+			"Failed to arm timers");
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS, 0),
+			"Timer triggered count doesn't match arm count");
+	return TEST_SUCCESS;
+}
+
+static int
+_arm_wrapper(void *arg)
+{
+	RTE_SET_USED(arg);
+
+	TEST_ASSERT_SUCCESS(_arm_timers(20, MAX_TIMERS),
+			"Failed to arm timers");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_multicore(void)
+{
+
+	uint32_t lcore_1 = rte_get_next_lcore(-1, 1, 0);
+	uint32_t lcore_2 = rte_get_next_lcore(lcore_1, 1, 0);
+
+	rte_eal_remote_launch(_arm_wrapper, NULL, lcore_1);
+	rte_eal_remote_launch(_arm_wrapper, NULL, lcore_2);
+
+	rte_eal_mp_wait_lcore();
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS * 2, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+#define MAX_BURST 16
+static inline int
+_arm_timers_burst(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	int j;
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers / MAX_BURST; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get_bulk(
+				eventdev_test_mempool,
+				(void **)ev_tim, MAX_BURST),
+				"mempool alloc failed");
+
+		for (j = 0; j < MAX_BURST; j++) {
+			*ev_tim[j] = tim;
+			ev_tim[j]->ev.event_ptr = ev_tim[j];
+		}
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_tmo_tick_burst(timdev,
+				ev_tim, tim.timeout_ticks, MAX_BURST),
+				MAX_BURST, "Failed to arm timer %d", rte_errno);
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_burst(void)
+{
+	TEST_ASSERT_SUCCESS(_arm_timers_burst(20, MAX_TIMERS),
+			"Failed to arm timers");
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_arm_wrapper_burst(void *arg)
+{
+	RTE_SET_USED(arg);
+
+	TEST_ASSERT_SUCCESS(_arm_timers_burst(20, MAX_TIMERS),
+			"Failed to arm timers");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_burst_multicore(void)
+{
+	rte_eal_remote_launch(_arm_wrapper_burst, NULL, test_lcore1);
+	rte_eal_remote_launch(_arm_wrapper_burst, NULL, test_lcore2);
+
+	rte_eal_mp_wait_lcore();
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS * 2, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel(void)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 20,
+	};
+
+	for (i = 0; i < MAX_TIMERS; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		rte_delay_us(100 + (i % 5000));
+
+		TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(timdev,
+					&ev_tim, 1), 1,
+				"Failed to cancel event timer %d", rte_errno);
+		rte_mempool_put(eventdev_test_mempool, ev_tim);
+	}
+
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+				MAX_TIMERS),
+		"Timer triggered count doesn't match arm, cancel count");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+				  "Failed to arm event timer");
+
+		while (rte_ring_enqueue(timer_producer_ring, ev_tim) != 0)
+			;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer_burst(uint64_t timeout_tcks, uint64_t timers)
+{
+
+	uint64_t i;
+	int j;
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+	int arm_count = 0;
+
+	for (i = 0; i < timers / MAX_BURST; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get_bulk(
+				eventdev_test_mempool,
+				(void **)ev_tim, MAX_BURST),
+				"mempool alloc failed");
+
+		for (j = 0; j < MAX_BURST; j++) {
+			*ev_tim[j] = tim;
+			ev_tim[j]->ev.event_ptr = ev_tim[j];
+		}
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_tmo_tick_burst(timdev,
+				ev_tim, tim.timeout_ticks, MAX_BURST),
+				MAX_BURST, "Failed to arm timer %d", rte_errno);
+
+		for (j = 0; j < MAX_BURST; j++)
+			TEST_ASSERT_EQUAL(ev_tim[j]->state,
+					  RTE_EVENT_TIMER_ARMED,
+					  "Event timer not armed, state = %d",
+					  ev_tim[j]->state);
+
+		while (rte_ring_enqueue_bulk(timer_producer_ring,
+				(void **)ev_tim, MAX_BURST, NULL) == 0)
+			;
+
+		arm_count += MAX_BURST;
+	}
+
+	TEST_ASSERT_EQUAL(arm_count, MAX_TIMERS,
+			  "Failed to arm expected number of event timers");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer_wrapper(void *args)
+{
+	RTE_SET_USED(args);
+
+	return _cancel_producer(20, MAX_TIMERS);
+}
+
+static int
+_cancel_producer_burst_wrapper(void *args)
+{
+	RTE_SET_USED(args);
+
+	return _cancel_producer_burst(100, MAX_TIMERS);
+}
+
+static int
+_cancel_thread(void *args)
+{
+	RTE_SET_USED(args);
+	unsigned int count = rte_ring_count(timer_producer_ring);
+	struct rte_event_timer *ev_tim = NULL;
+	uint64_t cancel_count = 0;
+	uint16_t ret;
+
+	while (!arm_done || count) {
+		if (rte_ring_dequeue(timer_producer_ring, (void **)&ev_tim)) {
+			count = rte_ring_count(timer_producer_ring);
+			continue;
+		}
+
+		ret = rte_event_timer_cancel_burst(timdev, &ev_tim, 1);
+		TEST_ASSERT_EQUAL(ret, 1, "Failed to cancel timer");
+		rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+		count = rte_ring_count(timer_producer_ring);
+		cancel_count++;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_burst_thread(void *args)
+{
+	RTE_SET_USED(args);
+
+	int ret, i, n;
+	unsigned int count = rte_ring_count(timer_producer_ring);
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	uint64_t cancel_count = 0;
+
+	while (!arm_done || count) {
+		n = rte_ring_dequeue_burst(timer_producer_ring,
+				(void **)ev_tim, MAX_BURST, &count);
+		if (!n)
+			continue;
+
+		for (i = 0; i < n; i++)
+			TEST_ASSERT_EQUAL(ev_tim[i]->state,
+					  RTE_EVENT_TIMER_ARMED,
+					  "Event timer not armed, state = %d",
+					  ev_tim[i]->state);
+
+		ret = rte_event_timer_cancel_burst(timdev, ev_tim, n);
+		TEST_ASSERT_EQUAL(n, ret, "Failed to cancel complete burst of "
+				  "event timers");
+		rte_mempool_put_bulk(eventdev_test_mempool, (void **)ev_tim,
+				ret);
+
+		cancel_count += ret;
+	}
+
+	TEST_ASSERT_EQUAL(cancel_count, MAX_TIMERS,
+			  "Failed to cancel expected number of timers: "
+			  "expected = %d, cancel_count = %"PRIu64"\n",
+			  MAX_TIMERS, cancel_count);
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_multicore(void)
+{
+	arm_done = 0;
+	timer_producer_ring = rte_ring_create("timer_cancel_queue",
+			MAX_TIMERS * 2, rte_socket_id(), 0);
+	TEST_ASSERT_NOT_NULL(timer_producer_ring,
+			"Unable to reserve memory for ring");
+
+	rte_eal_remote_launch(_cancel_thread, NULL, test_lcore3);
+	rte_eal_remote_launch(_cancel_producer_wrapper, NULL, test_lcore1);
+	rte_eal_remote_launch(_cancel_producer_wrapper, NULL, test_lcore2);
+
+	rte_eal_wait_lcore(test_lcore1);
+	rte_eal_wait_lcore(test_lcore2);
+	arm_done = 1;
+	rte_eal_wait_lcore(test_lcore3);
+	rte_ring_free(timer_producer_ring);
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS * 2,
+			MAX_TIMERS * 2),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_burst_multicore(void)
+{
+	arm_done = 0;
+	timer_producer_ring = rte_ring_create("timer_cancel_queue",
+			MAX_TIMERS * 2, rte_socket_id(), 0);
+	TEST_ASSERT_NOT_NULL(timer_producer_ring,
+			"Unable to reserve memory for ring");
+
+	rte_eal_remote_launch(_cancel_burst_thread, NULL, test_lcore2);
+	rte_eal_remote_launch(_cancel_producer_burst_wrapper, NULL,
+			test_lcore1);
+
+	rte_eal_wait_lcore(test_lcore1);
+	arm_done = 1;
+	rte_eal_wait_lcore(test_lcore2);
+	rte_ring_free(timer_producer_ring);
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+			MAX_TIMERS),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_random(void)
+{
+	uint64_t i;
+	uint64_t events_canceled = 0;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 20,
+	};
+
+	for (i = 0; i < MAX_TIMERS; i++) {
+
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		if (rte_rand() & 1) {
+			rte_delay_us(100 + (i % 5000));
+			TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(
+						timdev,
+						&ev_tim, 1), 1,
+				"Failed to cancel event timer %d", rte_errno);
+			rte_mempool_put(eventdev_test_mempool, ev_tim);
+			events_canceled++;
+		}
+	}
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+				events_canceled),
+		       "Timer triggered count doesn't match arm, cancel count");
+
+	return TEST_SUCCESS;
+}
+
+/* Check that the adapter can be created correctly */
+static int
+adapter_create(void)
+{
+	int adapter_id = 0;
+	struct rte_event_timer_adapter *adapter, *adapter2;
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev + 1,  // invalid event dev id
+		.timer_adapter_id = adapter_id,
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = MAX_TIMERS,
+		.flags = 0,
+	};
+	uint32_t caps = 0;
+
+	/* Test invalid conf */
+	adapter = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapter, "Created adapter with invalid "
+			"event device id");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Incorrect errno value for "
+			"invalid event device id");
+
+	/* Test valid conf */
+	conf.event_dev_id = evdev;
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_caps_get(evdev, &caps),
+			"failed to get adapter capabilities");
+	if (!(caps & RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT))
+		adapter = rte_event_timer_adapter_create_ext(&conf,
+				test_port_conf_cb,
+				NULL);
+	else
+		adapter = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NOT_NULL(adapter, "Failed to create adapter with valid "
+			"configuration");
+
+	/* Test existing id */
+	adapter2 = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapter2, "Created adapter with in-use id");
+	TEST_ASSERT(rte_errno == EEXIST, "Incorrect errno value for existing "
+			"id");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapter),
+			"Failed to free adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+
+/* Test that adapter can be freed correctly. */
+static int
+adapter_free(void)
+{
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stop(timdev),
+			"Failed to stop adapter");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(timdev),
+			"Failed to free valid adapter");
+
+	/* Test free of already freed adapter */
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_free(timdev),
+			"Freed adapter that was already freed");
+
+	/* Test free of null adapter */
+	timdev = NULL;
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_free(timdev),
+			"Freed null adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter info can be retrieved and is correct. */
+static int
+adapter_get_info(void)
+{
+	struct rte_event_timer_adapter_info info;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_get_info(timdev, &info),
+			"Failed to get adapter info");
+
+	if (using_services)
+		TEST_ASSERT_EQUAL(info.event_dev_port_id, 1,
+				"Expected port id = 1, got port id = %d",
+				info.event_dev_port_id);
+
+	return TEST_SUCCESS;
+}
+
+/* Test adapter lookup via adapter ID. */
+static int
+adapter_lookup(void)
+{
+	struct rte_event_timer_adapter *adapter;
+
+	adapter = rte_event_timer_adapter_lookup(TEST_ADAPTER_ID);
+	TEST_ASSERT_NOT_NULL(adapter, "Failed to lookup adapter");
+
+	return TEST_SUCCESS;
+}
+
+static int
+adapter_start(void)
+{
+	TEST_ASSERT_SUCCESS(_timdev_setup(180 * NSECPERSEC,
+			NSECPERSEC / 10),
+			"Failed to start adapter");
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_start(timdev),
+			"Failed to repeatedly start adapter");
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter stops correctly. */
+static int
+adapter_stop(void)
+{
+	uint32_t evdev_service_id, adapter_service_id;
+	struct rte_event_timer_adapter *l_adapter = NULL;
+
+	/* retrieve service ids */
+	TEST_ASSERT_SUCCESS(rte_event_dev_service_id_get(evdev,
+			&evdev_service_id), "Failed to get event device "
+			"service id");
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(timdev,
+			&adapter_service_id), "Failed to get event timer "
+			"adapter service id");
+
+	/* Test adapter stop */
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stop(timdev),
+			"Failed to stop event adapter");
+
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_stop(l_adapter),
+			"Erroneously stopped null event adapter");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(timdev),
+			"Failed to free adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+/* Test increment and reset of ev_enq_count stat */
+static int
+stat_inc_reset_ev_enq(void)
+{
+	int ret, i, n;
+	int num_evtims = MAX_TIMERS;
+	struct rte_event_timer *evtims[num_evtims];
+	struct rte_event evs[BATCH_SIZE];
+	struct rte_event_timer_adapter_stats stats;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
+				   num_evtims);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
+			  ret);
+
+	for (i = 0; i < num_evtims; i++) {
+		*evtims[i] = init_tim;
+		evtims[i]->ev.event_ptr = evtims[i];
+	}
+
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0, "Stats not clear at "
+			  "startup");
+
+	/* Test with the max value for the adapter */
+	ret = rte_event_timer_arm_burst(timdev, evtims, num_evtims);
+	TEST_ASSERT_EQUAL(ret, num_evtims,
+			  "Failed to arm all event timers: attempted = %d, "
+			  "succeeded = %d, rte_errno = %s",
+			  num_evtims, ret, rte_strerror(rte_errno));
+
+	rte_delay_ms(1000);
+
+#define MAX_TRIES 1000
+	int sum = 0;
+	int tries = 0;
+	bool done = false;
+	while (!done) {
+		sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
+					       RTE_DIM(evs), 10);
+		if (sum >= num_evtims || ++tries >= MAX_TRIES)
+			done = true;
+
+		rte_delay_ms(10);
+	}
+
+	TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
+			  "got %d", num_evtims, sum);
+
+	TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");
+
+	rte_delay_ms(100);
+
+	/* Make sure the eventdev is still empty */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
+				      10);
+
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
+			  "events from event device");
+
+	/* Check stats again */
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, num_evtims,
+			  "Expected enqueue stat = %d; got %d", num_evtims,
+			  (int)stats.ev_enq_count);
+
+	/* Reset and check again */
+	ret = rte_event_timer_adapter_stats_reset(timdev);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to reset stats");
+
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0,
+			  "Expected enqueue stat = %d; got %d", 0,
+			  (int)stats.ev_enq_count);
+
+	rte_mempool_put_bulk(eventdev_test_mempool, (void **)evtims,
+			     num_evtims);
+
+	return TEST_SUCCESS;
+}
+
+/* Test various cases in arming timers */
+static int
+event_timer_arm(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+
+	/* Test single timer arm succeeds */
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event timer "
+			  "in incorrect state");
+
+	/* Test arm of armed timer fails */
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "expected return value from "
+			  "rte_event_timer_arm_burst: 0, got: %d", ret);
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after arming already armed timer");
+
+	/* Let timer expire */
+	rte_delay_ms(1000);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* This test checks that repeated references to the same event timer in the
+ * arm request work as expected; only the first one through should succeed.
+ */
+static int
+event_timer_arm_double(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+
+	struct rte_event_timer *evtim_arr[] = {evtim, evtim};
+	ret = rte_event_timer_arm_burst(adapter, evtim_arr, RTE_DIM(evtim_arr));
+	TEST_ASSERT_EQUAL(ret, 1, "Unexpected return value from "
+			  "rte_event_timer_arm_burst");
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after double-arm");
+
+	/* Let timer expire */
+	rte_delay_ms(600);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number of expiry events - "
+			  "expected: 1, actual: %d", n);
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Test the timer expiry event is generated at the expected time.  */
+static int
+event_timer_arm_expiry(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event_timer *evtim2 = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up an event timer */
+	*evtim = init_tim;
+	evtim->timeout_ticks = 30,	// expire in 3 secs
+	evtim->ev.event_ptr = evtim;
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event "
+			  "timer in incorrect state");
+
+	rte_delay_ms(2999);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event");
+
+	/* Delay 100 ms to account for the adapter tick window - should let us
+	 * dequeue one event
+	 */
+	rte_delay_ms(100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number (%d) of timer "
+			  "expiry events", n);
+	TEST_ASSERT_EQUAL(evs[0].event_type, RTE_EVENT_TYPE_TIMER,
+			  "Dequeued unexpected type of event");
+
+	/* Check that we recover the original event timer and then free it */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+	rte_mempool_put(eventdev_test_mempool, evtim2);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that rearming a timer works as expected. */
+static int
+event_timer_arm_rearm(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event_timer *evtim2 = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type = RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->timeout_ticks = 1;  // expire in 0.1 sec
+	evtim->ev.event_ptr = evtim;
+
+	/* Arm it */
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+
+	/* Add 100ms to account for the adapter tick window */
+	rte_delay_ms(100 + 100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	/* Recover the timer through the event that was dequeued. */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+
+	/* Need to reset state in case implementation can't do it */
+	evtim2->state = RTE_EVENT_TIMER_NOT_ARMED;
+
+	/* Rearm it */
+	ret = rte_event_timer_arm_burst(timdev, &evtim2, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+
+	/* Add 100ms to account for the adapter tick window */
+	rte_delay_ms(100 + 100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	/* Free it */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+	rte_mempool_put(eventdev_test_mempool, evtim2);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that the adapter handles the max specified number of timers as
+ * expected.
+ */
+static int
+event_timer_arm_max(void)
+{
+	int ret, i, n;
+	int num_evtims = MAX_TIMERS;
+	struct rte_event_timer *evtims[num_evtims];
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
+				   num_evtims);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
+			  ret);
+
+	for (i = 0; i < num_evtims; i++) {
+		*evtims[i] = init_tim;
+		evtims[i]->ev.event_ptr = evtims[i];
+	}
+
+	/* Test with the max value for the adapter */
+	ret = rte_event_timer_arm_burst(timdev, evtims, num_evtims);
+	TEST_ASSERT_EQUAL(ret, num_evtims,
+			  "Failed to arm all event timers: attempted = %d, "
+			  "succeeded = %d, rte_errno = %s",
+			  num_evtims, ret, rte_strerror(rte_errno));
+
+	rte_delay_ms(1000);
+
+#define MAX_TRIES 1000
+	int sum = 0;
+	int tries = 0;
+	bool done = false;
+	while (!done) {
+		sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
+					       RTE_DIM(evs), 10);
+		if (sum >= num_evtims || ++tries >= MAX_TRIES)
+			done = true;
+
+		rte_delay_ms(10);
+	}
+
+	TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
+			  "got %d", num_evtims, sum);
+
+	TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");
+
+	rte_delay_ms(100);
+
+	/* Make sure the eventdev is still empty */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
+				    10);
+
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
+			  "events from event device");
+
+	rte_mempool_put_bulk(eventdev_test_mempool, (void **)evtims,
+			     num_evtims);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that creating an event timer with incorrect event sched type fails. */
+static int
+event_timer_arm_invalid_sched_type(void)
+{
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	if (!using_services)
+		return -ENOTSUP;
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_PARALLEL; // bad sched type
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "sched type, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid queue");
+
+	rte_mempool_put(eventdev_test_mempool, &evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that creating an event timer with a timeout value that is too small or
+ * too big fails.
+ */
+static int
+event_timer_arm_invalid_timeout(void)
+{
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 0;  // timeout too small
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "timeout, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid timeout");
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOEARLY,
+			  "Unexpected event timer state");
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 1801;  // timeout too big
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "timeout, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid timeout");
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOLATE,
+			  "Unexpected event timer state");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+static int
+event_timer_cancel(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Check that cancelling an uninited timer fails */
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling "
+			  "uninited timer");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after "
+			  "cancelling uninited timer");
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	/* Check that cancelling an inited but unarmed timer fails */
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling "
+			  "unarmed timer");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after "
+			  "cancelling unarmed timer");
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED,
+			  "evtim in incorrect state");
+
+	/* Delay 1 sec */
+	rte_delay_ms(1000);
+
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to cancel event_timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_CANCELED,
+			  "evtim in incorrect state");
+
+	rte_delay_ms(3000);
+
+	/* Make sure that no expiry event was generated */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+static int
+event_timer_cancel_double(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED,
+			  "timer in unexpected state");
+
+	/* Now, test that referencing the same timer twice in the same call
+	 * fails
+	 */
+	struct rte_event_timer *evtim_arr[] = {evtim, evtim};
+	ret = rte_event_timer_cancel_burst(adapter, evtim_arr,
+					   RTE_DIM(evtim_arr));
+
+	/* Two requests to cancel same timer, only one should succeed */
+	TEST_ASSERT_EQUAL(ret, 1, "Succeeded unexpectedly in canceling timer "
+			  "twice");
+
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after double-cancel: rte_errno = %d", rte_errno);
+
+	rte_delay_ms(3000);
+
+	/* Still make sure that no expiry event was generated */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that event timer adapter tick resolution works as expected by testing
+ * the number of adapter ticks that occur within a particular time interval.
+ */
+static int
+adapter_tick_resolution(void)
+{
+	struct rte_event_timer_adapter_stats stats;
+	uint64_t adapter_tick_count;
+
+	/* Only run this test in the software driver case */
+	if (!using_services)
+		return -ENOTSUP;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_reset(timdev),
+				"Failed to reset stats");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(timdev,
+			&stats), "Failed to get adapter stats");
+	TEST_ASSERT_EQUAL(stats.adapter_tick_count, 0, "Adapter tick count "
+			"not zeroed out");
+
+	/* Delay 1 second; should let at least 10 ticks occur with the default
+	 * adapter configuration used by this test.
+	 */
+	rte_delay_ms(1000);
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(timdev,
+			&stats), "Failed to get adapter stats");
+
+	adapter_tick_count = stats.adapter_tick_count;
+	TEST_ASSERT(adapter_tick_count >= 10 && adapter_tick_count <= 12,
+			"Expected 10-12 adapter ticks, got %"PRIu64"\n",
+			adapter_tick_count);
+
+	return TEST_SUCCESS;
+}
+
+static int
+adapter_create_max(void)
+{
+	int i;
+	uint32_t svc_start_count, svc_end_count;
+	struct rte_event_timer_adapter *adapters[
+					RTE_EVENT_TIMER_ADAPTER_NUM_MAX + 1];
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev,
+		// timer_adapter_id set in loop
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = MAX_TIMERS,
+		.flags = 0,
+	};
+
+	svc_start_count = rte_service_get_count();
+
+	/* This test expects that there are sufficient service IDs available
+	 * to be allocated. I.e., RTE_EVENT_TIMER_ADAPTER_NUM_MAX may need to
+	 * be less than RTE_SERVICE_NUM_MAX if anything else uses a service
+	 * (the SW event device, for example).
+	 */
+	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) {
+		conf.timer_adapter_id = i;
+		adapters[i] = rte_event_timer_adapter_create_ext(&conf,
+				test_port_conf_cb, NULL);
+		TEST_ASSERT_NOT_NULL(adapters[i], "Failed to create adapter "
+				"%d", i);
+	}
+
+	conf.timer_adapter_id = i;
+	adapters[i] = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapters[i], "Created too many adapters");
+
+	/* Check that at least RTE_EVENT_TIMER_ADAPTER_NUM_MAX services
+	 * have been created
+	 */
+	svc_end_count = rte_service_get_count();
+	TEST_ASSERT_EQUAL(svc_end_count - svc_start_count,
+			RTE_EVENT_TIMER_ADAPTER_NUM_MAX,
+			"Failed to create expected number of services");
+
+	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++)
+		TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapters[i]),
+				"Failed to free adapter %d", i);
+
+	/* Check that service count is back to where it was at start */
+	svc_end_count = rte_service_get_count();
+	TEST_ASSERT_EQUAL(svc_start_count, svc_end_count, "Failed to release "
+			  "correct number of services");
+
+	return TEST_SUCCESS;
+}
+
+static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
+	.suite_name = "event timer functional test suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_state),
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_arm),
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_arm_burst),
+		TEST_CASE_ST(timdev_setup_sec, timdev_teardown,
+				test_timer_cancel),
+		TEST_CASE_ST(timdev_setup_sec, timdev_teardown,
+				test_timer_cancel_random),
+		TEST_CASE_ST(timdev_setup_usec_multicore, timdev_teardown,
+				test_timer_arm_multicore),
+		TEST_CASE_ST(timdev_setup_usec_multicore, timdev_teardown,
+				test_timer_arm_burst_multicore),
+		TEST_CASE_ST(timdev_setup_sec_multicore, timdev_teardown,
+				test_timer_cancel_multicore),
+		TEST_CASE_ST(timdev_setup_sec_multicore, timdev_teardown,
+				test_timer_cancel_burst_multicore),
+		TEST_CASE(adapter_create),
+		TEST_CASE_ST(timdev_setup_msec, NULL, adapter_free),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_get_info),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_lookup),
+		TEST_CASE_ST(NULL, timdev_teardown,
+				adapter_start),
+		TEST_CASE_ST(timdev_setup_msec, NULL,
+				adapter_stop),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				stat_inc_reset_ev_enq),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm_double),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm_expiry),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_rearm),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_max),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_invalid_sched_type),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_invalid_timeout),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_cancel),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_cancel_double),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_tick_resolution),
+		TEST_CASE(adapter_create_max),
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+static int
+test_event_timer_adapter_func(void)
+{
+	return unit_test_suite_runner(&event_timer_adptr_functional_testsuite);
+}
+
+REGISTER_TEST_COMMAND(event_timer_adapter_test, test_event_timer_adapter_func);
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 8/9] doc: add event timer adapter section to programmer's guide
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                           ` (6 preceding siblings ...)
  2018-03-29 21:27         ` [PATCH v8 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
@ 2018-03-29 21:27         ` Erik Gabriel Carrillo
  2018-03-29 21:27         ` [PATCH v8 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-29 21:27 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
---
 doc/guides/prog_guide/event_timer_adapter.rst | 297 ++++++++++++++++++++++++++
 doc/guides/prog_guide/index.rst               |   1 +
 2 files changed, 298 insertions(+)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst

diff --git a/doc/guides/prog_guide/event_timer_adapter.rst b/doc/guides/prog_guide/event_timer_adapter.rst
new file mode 100644
index 0000000..416f1ff
--- /dev/null
+++ b/doc/guides/prog_guide/event_timer_adapter.rst
@@ -0,0 +1,297 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(c) 2017 Intel Corporation. All rights reserved.
+
+Event Timer Adapter Library
+=================================
+
+The DPDK
+`Event Device library <http://dpdk.org/doc/guides/prog_guide/eventdev.html>`_
+introduces an event driven programming model which presents applications with
+an alternative to the polling model traditionally used in DPDK
+applications. Event devices can be coupled with arbitrary components to provide
+new event sources by using **event adapters**. The Event Timer Adapter is one
+such adapter; it bridges event devices and timer mechanisms.
+
+The Event Timer Adapter library extends the event driven model
+by introducing a :ref:`new type of event <timer_expiry_event>` that represents
+a timer expiration, and providing an API with which adapters can be created or
+destroyed, and :ref:`event timers <event_timer>` can be armed and canceled.
+
+The Event Timer Adapter library is designed to interface with hardware or
+software implementations of the timer mechanism; it will query an eventdev PMD
+to determine which implementation should be used.  The default software
+implementation manages timers using the DPDK
+`Timer library <http://dpdk.org/doc/guides/prog_guide/timer_lib.html>`_.
+
+Examples of using the API are presented in the `API Overview`_ and
+`Processing Timer Expiry Events`_ sections.  Code samples are abstracted and
+are based on the example of handling a TCP retransmission.
+
+.. _event_timer:
+
+Event Timer struct
+------------------
+Event timers are timers that enqueue a timer expiration event to an event
+device upon timer expiration.
+
+The Event Timer Adapter API represents each event timer with a generic struct,
+which contains an event and user metadata.  The ``rte_event_timer`` struct is
+defined in ``lib/librte_event/librte_event_timer_adapter.h``.
+
+.. _timer_expiry_event:
+
+Timer Expiry Event
+~~~~~~~~~~~~~~~~~~
+
+The event contained by an event timer is enqueued in the event device when the
+timer expires, and the event device uses the attributes below when scheduling
+it:
+
+* ``event_queue_id`` - Application should set this to specify an event queue to
+  which the timer expiry event should be enqueued
+* ``event_priority`` - Application can set this to indicate the priority of the
+  timer expiry event in the event queue relative to other events
+* ``sched_type`` - Application can set this to specify the scheduling type of
+  the timer expiry event
+* ``flow_id`` - Application can set this to indicate which flow this timer
+  expiry event corresponds to
+* ``op`` - Will be set to ``RTE_EVENT_OP_NEW`` by the event timer adapter
+* ``event_type`` - Will be set to ``RTE_EVENT_TYPE_TIMER`` by the event timer
+  adapter
+
+Timeout Ticks
+~~~~~~~~~~~~~
+
+The number of ticks from now in which the timer will expire. The ticks value
+has a resolution (``timer_tick_ns``) that is specified in the event timer
+adapter configuration.
+
+State
+~~~~~
+
+Before arming an event timer, the application should initialize its state to
+RTE_EVENT_TIMER_NOT_ARMED. The event timer's state will be updated when a
+request to arm or cancel it takes effect.
+
+If the application wishes to rearm the timer after it has expired, it should
+reset the state back to RTE_EVENT_TIMER_NOT_ARMED before doing so.
+
+User Metadata
+~~~~~~~~~~~~~
+
+Memory to store user specific metadata.  The event timer adapter implementation
+will not modify this area.
+
+API Overview
+----------------
+
+This section will introduce the reader to the event timer adapter API, showing
+how to create and configure an event timer adapter and use it to manage event
+timers.
+
+From a high level, the setup steps are:
+
+* rte_event_timer_adapter_create()
+* rte_event_timer_adapter_start()
+
+And to start and stop timers:
+
+* rte_event_timer_init()
+* rte_event_timer_arm_burst()
+* rte_event_timer_cancel_burst()
+
+Create and Configure an Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To create an event timer adapter instance, initialize an
+``rte_event_timer_adapter_conf`` struct with the desired values, and pass it
+to ``rte_event_timer_adapter_create()``.
+
+.. code-block:: c
+
+	#define NSECPERSEC 1E9 // No of ns in 1 sec
+	const struct rte_event_timer_adapter_config adapter_config = {
+                .event_dev_id = event_dev_id,
+                .timer_adapter_id = 0,
+                .clk_src = RTE_EVENT_TIMER_WHEEL_CPU_CLK,
+                .timer_tick_ns = NSECPERSEC / 10, // 100 milliseconds
+                .max_tmo_nsec = 180 * NSECPERSEC // 2 minutes
+                .nb_timers = 40000,
+                .timer_adapter_flags = 0,
+	};
+
+	struct rte_event_timer_adapter *adapter = NULL;
+	adapter = rte_event_timer_adapter_create(&adapter_config);
+
+	if (adapter == NULL) { ... };
+
+Before creating an instance of a timer adapter, the application should create
+and configure an event device along with its event ports. Based on the event
+device capability, it might require creating an additional event port to be
+used by the timer adapter.  If required, the
+``rte_event_timer_adapter_create()`` function will use a default method to
+configure an event port;  it will examine the current event device
+configuration, determine the next available port identifier number, and create
+a new event port with a default port configuration.
+
+If the application desires to have finer control of event port allocation
+and setup, it can use the ``rte_event_timer_adapter_create_ext()`` function.
+This function is passed a callback function that will be invoked if the
+adapter needs to create an event port, giving the application the opportunity
+to control how it is done.
+
+Retrieve Event Timer Adapter Contextual Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The event timer adapter implementation may have constraints on tick resolution
+or maximum timer expiry timeout based on the given event timer adapter or
+system.  In this case, the implementation may adjust the tick resolution or
+maximum timeout to the best possible configuration.
+
+Upon successful event timer adapter creation, the application can get the
+configured resolution and max timeout with
+``rte_event_timer_adapter_get_info()``. This function will return an
+``rte_event_timer_adapter_info`` struct, which contains the following members:
+
+* ``min_resolution_ns`` - Minimum timer adapter tick resolution in ns.
+* ``max_tmo_ns`` - Maximum timer timeout(expiry) in ns.
+* ``adapter_conf`` - Configured event timer adapter attributes
+
+Configuring the Service Component
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the adapter uses a service component, the application is required to map
+the service to a service core before starting the adapter:
+
+.. code-block:: c
+
+        uint32_t service_id;
+
+        if (rte_event_timer_adapter_service_id_get(adapter, &service_id) == 0)
+                rte_service_map_lcore_set(service_id, EVTIM_CORE_ID);
+
+An event timer adapter uses a service component if the event device PMD
+indicates that the adapter should use a software implementation.
+
+Starting the Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The application should call ``rte_event_timer_adapter_start()`` to start
+running the event timer adapter. This function calls the start entry points
+defined by eventdev PMDs for hardware implementations or puts a service
+component into the running state in the software implementation.
+
+Arming Event Timers
+~~~~~~~~~~~~~~~~~~~~~
+
+Once an event timer adapter has been started, an application can begin to
+manage event timers with it.
+
+The application should allocate ``struct rte_event_timer`` objects from a
+mempool or huge-page backed application buffers of required size. Upon
+successful allocation, the application should initialize the event timer, and
+then set any of the necessary event attributes described in the
+`Timer Expiry Event`_ section. In the following example, assume ``conn``
+represents a TCP connection and that ``event_timer_pool`` is a mempool that
+was created previously:
+
+.. code-block:: c
+
+	rte_mempool_get(event_timer_pool, (void **)&conn->evtim);
+	if (conn->evtim == NULL) { ... }
+
+	/* Set up the event timer. */
+	conn->evtim->ev.op = RTE_EVENT_OP_NEW;
+	conn->evtim->ev.queue_id = event_queue_id;
+        conn->evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+        conn->evtim->ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
+        conn->evtim->ev.event_type = RTE_EVENT_TYPE_TIMER;
+	conn->evtim->ev.event_ptr = conn;
+	conn->evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns)
+
+Note that it is necessary to initialize the event timer state to
+RTE_EVENT_TIMER_NOT_ARMED.  Also note that we have saved a pointer to the
+``conn`` object in the timer's event payload. This will allow us to locate
+the connection object again once we dequeue the timer expiry event from the
+event device later.  As a convenience, the application may specify no value for
+ev.event_ptr (rte_event_timer_init sets it to NULL), and the adapter will by
+default set it to point at the event timer itself.
+
+Now we can arm the event timer with ``rte_event_timer_arm_burst()``:
+
+.. code-block:: c
+
+	ret = rte_event_timer_arm_burst(adapter, &conn->evtim, 1);
+	if (ret != 1) { ... }
+
+Once an event timer expires, the application may free it or rearm it as
+necessary.  If the application will rearm the timer, the state should be reset
+to RTE_EVENT_TIMER_NOT_ARMED by the application before rearming it.
+
+Multiple Event Timers with Same Expiry Value
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the special case that there is a set of event timers that should all expire
+at the same time, the application may call
+``rte_event_timer_arm_tmo_tick_burst()``, which allows the implementation to
+optimize the operation if possible.
+
+Canceling Event Timers
+~~~~~~~~~~~~~~~~~~~~~~~
+
+An event timer that has been armed as described in `Arming Event Timers`_ can
+be canceled by calling ``rte_event_timer_cancel_burst()``:
+
+.. code-block:: c
+
+	/* Ack for the previous tcp data packet has been received;
+	 * cancel the retransmission timer
+         */
+	rte_event_timer_cancel_burst(adapter, &conn->timer, 1);
+
+Processing Timer Expiry Events
+------------------------------
+
+Once an event timer has successfully enqueued a timer expiry event in the event
+device, the application will subsequently dequeue it from the event device.
+The application can use the event payload to retrieve a pointer to the object
+associated with the event timer. It can then re-arm the event timer or free the
+event timer object as desired:
+
+.. code-block:: c
+
+	void
+	event_processing_loop(...)
+	{
+		while (...) {
+			/* Receive events from the configured event port. */
+			rte_event_dequeue_burst(event_dev_id, event_port, &ev, 1, 0);
+			...
+			switch(ev.event_type) {
+				...
+				case RTE_EVENT_TYPE_TIMER:
+					process_timer_event(ev);
+					...
+					break;
+			}
+		}
+	}
+
+	uint8_t
+	process_timer_event(...)
+	{
+		/* A retransmission timeout for the connection has been received. */
+		conn = ev.event_ptr;
+		/* Retransmit last packet (e.g. TCP segment). */
+		...
+		/* Re-arm timer using original values. */
+		rte_event_timer_arm_burst(adapter_id, &conn->timer, 1);
+	}
+
+Summary
+-------
+
+The Event Timer Adapter library extends the DPDK event-based programming model
+by representing timer expirations as events in the system and allowing
+applications to use existing event processing loops to arm and cancel event
+timers or handle timer expiry events.
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index bbbe789..589c05d 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -42,6 +42,7 @@ Programmer's Guide
     thread_safety_dpdk_functions
     eventdev
     event_ethernet_rx_adapter
+    event_timer_adapter
     qos_framework
     power_man
     packet_classif_access_ctrl
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v8 9/9] doc: add event timer adapter documentation
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                           ` (7 preceding siblings ...)
  2018-03-29 21:27         ` [PATCH v8 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
@ 2018-03-29 21:27         ` Erik Gabriel Carrillo
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-03-29 21:27 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, nipun.gupta, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 MAINTAINERS                            |  7 +++++++
 doc/api/doxy-api-index.md              | 32 +++-----------------------------
 doc/guides/rel_notes/release_18_05.rst |  6 ++++++
 3 files changed, 16 insertions(+), 29 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 75d3e92..3cc3a3f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -317,6 +317,13 @@ F: lib/librte_eventdev/*eth_rx_adapter*
 F: test/test/test_event_eth_rx_adapter.c
 F: doc/guides/prog_guide/event_ethernet_rx_adapter.rst
 
+Eventdev Timer Adapter API - EXPERIMENTAL
+M: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
+T: git://dpdk.org/next/dpdk-next-eventdev
+F: lib/librte_eventdev/*timer_adapter*
+F: test/test/test_event_timer_adapter.c
+F: doc/guides/prog_guide/event_timer_adapter.rst
+
 Raw device API - EXPERIMENTAL
 M: Shreyansh Jain <shreyansh.jain@nxp.com>
 M: Hemant Agrawal <hemant.agrawal@nxp.com>
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..5c6cd51 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -2,35 +2,8 @@ API {#index}
 ===
 
 <!--
-  BSD LICENSE
-
-  Copyright 2013-2017 6WIND S.A.
-
-  Redistribution and use in source and binary forms, with or without
-  modification, are permitted provided that the following conditions
-  are met:
-
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in
-      the documentation and/or other materials provided with the
-      distribution.
-    * Neither the name of 6WIND S.A. nor the names of its
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
-
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright(c) 2013-2017 6WIND S.A.
 -->
 
 The public API headers are grouped by topics:
@@ -47,6 +20,7 @@ The public API headers are grouped by topics:
   [security]           (@ref rte_security.h),
   [eventdev]           (@ref rte_eventdev.h),
   [event_eth_rx_adapter]   (@ref rte_event_eth_rx_adapter.h),
+  [event_timer_adapter]    (@ref rte_event_timer_adapter.h),
   [rawdev]             (@ref rte_rawdev.h),
   [metrics]            (@ref rte_metrics.h),
   [bitrate]            (@ref rte_bitrate.h),
diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst
index 3923dc2..d5861be 100644
--- a/doc/guides/rel_notes/release_18_05.rst
+++ b/doc/guides/rel_notes/release_18_05.rst
@@ -41,6 +41,12 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added the Event Timer Adapter Library.**
+
+  The Event Timer Adapter Library extends the event-based model by introducing
+  APIs that allow applications to arm/cancel event timers that generate
+  timer expiry events. This new type of event is scheduled by an event device
+  along with existing types of events.
 
 API Changes
 -----------
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v8 7/9] test: add event timer adapter auto-test
  2018-03-29 21:27         ` [PATCH v8 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
@ 2018-03-30 15:48           ` Bhagavatula, Pavan
  2018-03-30 18:47             ` Carrillo, Erik G
  0 siblings, 1 reply; 133+ messages in thread
From: Bhagavatula, Pavan @ 2018-03-30 15:48 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, Jacob,  Jerin, nipun.gupta, hemant.agrawal; +Cc: dev

Hi Erik,

Few comments below,

On Thu, Mar 29, 2018 at 04:27:30PM -0500, Erik Gabriel Carrillo wrote:
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  test/test/Makefile                   |    1 +
>  test/test/test_event_timer_adapter.c | 1837 ++++++++++++++++++++++++++++++++++
>  2 files changed, 1838 insertions(+)
>  create mode 100644 test/test/test_event_timer_adapter.c
>
<snip>
> +/* Test that adapter stops correctly. */
> +static int
> +adapter_stop(void)
> +{
> +	uint32_t evdev_service_id, adapter_service_id;
> +	struct rte_event_timer_adapter *l_adapter = NULL;
> +
Please use INTERNAL_PORT capability to determine if service core is required.

> +	/* retrieve service ids */
> +	TEST_ASSERT_SUCCESS(rte_event_dev_service_id_get(evdev,
> +			&evdev_service_id), "Failed to get event device "
> +			"service id");
> +	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(timdev,
> +			&adapter_service_id), "Failed to get event timer "
> +			"adapter service id");
> +
> +	/* Test adapter stop */
> +	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stop(timdev),
> +			"Failed to stop event adapter");
> +
> +	TEST_ASSERT_FAIL(rte_event_timer_adapter_stop(l_adapter),
> +			"Erroneously stopped null event adapter");
> +
> +	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(timdev),
> +			"Failed to free adapter");
> +
> +	rte_mempool_free(eventdev_test_mempool);
> +
> +	return TEST_SUCCESS;
> +}
> +
<snip>
> +stat_inc_reset_ev_enq(void)
> +{
> +	int ret, i, n;
> +	int num_evtims = MAX_TIMERS;
> +	struct rte_event_timer *evtims[num_evtims];
> +	struct rte_event evs[BATCH_SIZE];
> +	struct rte_event_timer_adapter_stats stats;
> +	const struct rte_event_timer init_tim = {
> +		.ev.op = RTE_EVENT_OP_NEW,
> +		.ev.queue_id = TEST_QUEUE_ID,
> +		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
> +		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
> +		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
> +		.state = RTE_EVENT_TIMER_NOT_ARMED,
> +		.timeout_ticks = 5,	// expire in .5 sec
> +	};
> +
> +	ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
> +				   num_evtims);
> +	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
> +			  ret);
> +
> +	for (i = 0; i < num_evtims; i++) {
> +		*evtims[i] = init_tim;
> +		evtims[i]->ev.event_ptr = evtims[i];
> +	}
> +
> +	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
> +	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
> +	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0, "Stats not clear at "
> +			  "startup");
> +
> +	/* Test with the max value for the adapter */
> +	ret = rte_event_timer_arm_burst(timdev, evtims, num_evtims);
> +	TEST_ASSERT_EQUAL(ret, num_evtims,
> +			  "Failed to arm all event timers: attempted = %d, "
> +			  "succeeded = %d, rte_errno = %s",
> +			  num_evtims, ret, rte_strerror(rte_errno));
> +
> +	rte_delay_ms(1000);
> +
> +#define MAX_TRIES 1000

Please make MAX_TRIES equivalent to num_evtims, here we are trying to deq 10
events in burst and assume it to succeed but in case event dev doesn't support
burst mode event will be stuck as it will have only 1000 tries instead of 4096.

> +	int sum = 0;
> +	int tries = 0;
> +	bool done = false;
> +	while (!done) {
> +		sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
> +					       RTE_DIM(evs), 10);
> +		if (sum >= num_evtims || ++tries >= MAX_TRIES)
> +			done = true;
> +
> +		rte_delay_ms(10);
> +	}
> +
> +	TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
> +			  "got %d", num_evtims, sum);
> +
<snip>
> +event_timer_arm_max(void)
> +{
> +	int ret, i, n;
> +	int num_evtims = MAX_TIMERS;
> +	struct rte_event_timer *evtims[num_evtims];
> +	struct rte_event evs[BATCH_SIZE];
> +	const struct rte_event_timer init_tim = {
> +		.ev.op = RTE_EVENT_OP_NEW,
> +		.ev.queue_id = TEST_QUEUE_ID,
> +		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
> +		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
> +		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
> +		.state = RTE_EVENT_TIMER_NOT_ARMED,
> +		.timeout_ticks = 5,	// expire in .5 sec
> +	};
> +
> +	ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
> +				   num_evtims);
> +	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
> +			  ret);
> +
> +	for (i = 0; i < num_evtims; i++) {
> +		*evtims[i] = init_tim;
> +		evtims[i]->ev.event_ptr = evtims[i];
> +	}
> +
> +	/* Test with the max value for the adapter */
> +	ret = rte_event_timer_arm_burst(timdev, evtims, num_evtims);
> +	TEST_ASSERT_EQUAL(ret, num_evtims,
> +			  "Failed to arm all event timers: attempted = %d, "
> +			  "succeeded = %d, rte_errno = %s",
> +			  num_evtims, ret, rte_strerror(rte_errno));
> +
> +	rte_delay_ms(1000);
> +
> +#define MAX_TRIES 1000

Same as above.

> +	int sum = 0;
> +	int tries = 0;
> +	bool done = false;

<snip>

> +static int
> +adapter_create_max(void)
> +{
> +	int i;
> +	uint32_t svc_start_count, svc_end_count;
> +	struct rte_event_timer_adapter *adapters[
> +					RTE_EVENT_TIMER_ADAPTER_NUM_MAX + 1];
> +
> +	struct rte_event_timer_adapter_conf conf = {
> +		.event_dev_id = evdev,
> +		// timer_adapter_id set in loop
> +		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
> +		.timer_tick_ns = NSECPERSEC / 10,
> +		.max_tmo_ns = 180 * NSECPERSEC,
> +		.nb_timers = MAX_TIMERS,
> +		.flags = 0,
> +	};
> +
> +	svc_start_count = rte_service_get_count();
> +
> +	/* This test expects that there are sufficient service IDs available
> +	 * to be allocated. I.e., RTE_EVENT_TIMER_ADAPTER_NUM_MAX may need to
> +	 * be less than RTE_SERVICE_NUM_MAX if anything else uses a service
> +	 * (the SW event device, for example).
> +	 */
Same as above service use need to be dependent on INTERNAL_PORT capability.

Also, in software event dev case this can be a valid test but in case of a hw
event dev RTE_EVENT_TIMER_ADAPTER_NUM_MAX number of event devicesmight not be
binded to dpdk. Either we need to provide a API to check how many event devices
are supported or use eventdev_timer_adapter_caps_get_t to get the number.

Thoughts?

> +	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) {
> +		conf.timer_adapter_id = i;
> +		adapters[i] = rte_event_timer_adapter_create_ext(&conf,
> +				test_port_conf_cb, NULL);
> +		TEST_ASSERT_NOT_NULL(adapters[i], "Failed to create adapter "
> +				"%d", i);
> +	}
> +
<snip>

Thanks,
Pavan.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v8 7/9] test: add event timer adapter auto-test
  2018-03-30 15:48           ` Bhagavatula, Pavan
@ 2018-03-30 18:47             ` Carrillo, Erik G
  0 siblings, 0 replies; 133+ messages in thread
From: Carrillo, Erik G @ 2018-03-30 18:47 UTC (permalink / raw)
  To: Bhagavatula, Pavan, Jacob,  Jerin; +Cc: dev

Hi Pavan,

> -----Original Message-----
> From: Bhagavatula, Pavan [mailto:Pavan.Bhagavatula@cavium.com]
> Sent: Friday, March 30, 2018 10:49 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>; Jacob, Jerin
> <Jerin.JacobKollanukkaran@cavium.com>; nipun.gupta@nxp.com;
> hemant.agrawal@nxp.com
> Cc: dev@dpdk.org
> Subject: Re: [PATCH v8 7/9] test: add event timer adapter auto-test
> 
> Hi Erik,
> 
> Few comments below,
> 

<...snipped...>

> > +/* Test that adapter stops correctly. */ static int
> > +adapter_stop(void)
> > +{
> > +	uint32_t evdev_service_id, adapter_service_id;
> > +	struct rte_event_timer_adapter *l_adapter = NULL;
> > +
> Please use INTERNAL_PORT capability to determine if service core is
> required.
> 
 
Good catch.  I meant to remove the references to service ids here, so I've gone ahead and done that.

<...snipped...>

> > +stat_inc_reset_ev_enq(void)
> > +{
> > +	int ret, i, n;
> > +	int num_evtims = MAX_TIMERS;
> > +	struct rte_event_timer *evtims[num_evtims];
> > +	struct rte_event evs[BATCH_SIZE];
> > +	struct rte_event_timer_adapter_stats stats;
> > +	const struct rte_event_timer init_tim = {
> > +		.ev.op = RTE_EVENT_OP_NEW,
> > +		.ev.queue_id = TEST_QUEUE_ID,
> > +		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
> > +		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
> > +		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
> > +		.state = RTE_EVENT_TIMER_NOT_ARMED,
> > +		.timeout_ticks = 5,	// expire in .5 sec
> > +	};
> > +
> > +	ret = rte_mempool_get_bulk(eventdev_test_mempool, (void
> **)evtims,
> > +				   num_evtims);
> > +	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret =
> %d",
> > +			  ret);
> > +
> > +	for (i = 0; i < num_evtims; i++) {
> > +		*evtims[i] = init_tim;
> > +		evtims[i]->ev.event_ptr = evtims[i];
> > +	}
> > +
> > +	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
> > +	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
> > +	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0, "Stats not clear at "
> > +			  "startup");
> > +
> > +	/* Test with the max value for the adapter */
> > +	ret = rte_event_timer_arm_burst(timdev, evtims, num_evtims);
> > +	TEST_ASSERT_EQUAL(ret, num_evtims,
> > +			  "Failed to arm all event timers: attempted = %d, "
> > +			  "succeeded = %d, rte_errno = %s",
> > +			  num_evtims, ret, rte_strerror(rte_errno));
> > +
> > +	rte_delay_ms(1000);
> > +
> > +#define MAX_TRIES 1000
> 
> Please make MAX_TRIES equivalent to num_evtims, here we are trying to
> deq 10 events in burst and assume it to succeed but in case event dev
> doesn't support burst mode event will be stuck as it will have only 1000 tries
> instead of 4096.

Good catch again - I'll make these changes.
 
<...snipped...>

> > +static int
> > +adapter_create_max(void)
> > +{
> > +	int i;
> > +	uint32_t svc_start_count, svc_end_count;
> > +	struct rte_event_timer_adapter *adapters[
> > +
> 	RTE_EVENT_TIMER_ADAPTER_NUM_MAX + 1];
> > +
> > +	struct rte_event_timer_adapter_conf conf = {
> > +		.event_dev_id = evdev,
> > +		// timer_adapter_id set in loop
> > +		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
> > +		.timer_tick_ns = NSECPERSEC / 10,
> > +		.max_tmo_ns = 180 * NSECPERSEC,
> > +		.nb_timers = MAX_TIMERS,
> > +		.flags = 0,
> > +	};
> > +
> > +	svc_start_count = rte_service_get_count();
> > +
> > +	/* This test expects that there are sufficient service IDs available
> > +	 * to be allocated. I.e., RTE_EVENT_TIMER_ADAPTER_NUM_MAX
> may need to
> > +	 * be less than RTE_SERVICE_NUM_MAX if anything else uses a
> service
> > +	 * (the SW event device, for example).
> > +	 */
> Same as above service use need to be dependent on INTERNAL_PORT
> capability.
> 
> Also, in software event dev case this can be a valid test but in case of a hw
> event dev RTE_EVENT_TIMER_ADAPTER_NUM_MAX number of event
> devicesmight not be binded to dpdk. Either we need to provide a API to
> check how many event devices are supported or use
> eventdev_timer_adapter_caps_get_t to get the number.
> 
> Thoughts?
> 

For now, I've modified the test case so that it returns ENOTSUP for the hw case.
But I like the idea of adding an API to query the count of devices.

Thanks,
Gabriel

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v8 2/9] eventdev: convert to SPDX license tag in header
  2018-03-29 21:27         ` [PATCH v8 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
@ 2018-04-02  8:12           ` Jerin Jacob
  2018-04-02  9:16             ` Hemant Agrawal
  0 siblings, 1 reply; 133+ messages in thread
From: Jerin Jacob @ 2018-04-02  8:12 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal

-----Original Message-----
> Date: Thu, 29 Mar 2018 16:27:25 -0500
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com,
>  hemant.agrawal@nxp.com
> Subject: [PATCH v8 2/9] eventdev: convert to SPDX license tag in header
> X-Mailer: git-send-email 1.7.10
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  lib/librte_eventdev/rte_eventdev.h | 37 +++++--------------------------------
>  1 file changed, 5 insertions(+), 32 deletions(-)
> 
> diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
> index e79583a..f9ad71e 100644
> --- a/lib/librte_eventdev/rte_eventdev.h
> +++ b/lib/librte_eventdev/rte_eventdev.h
> @@ -1,35 +1,8 @@
> -/*
> - *   BSD LICENSE
> - *
> - *   Copyright 2016 Cavium, Inc.
> - *   Copyright 2016 Intel Corporation.
> - *   Copyright 2016 NXP.
> - *
> - *   Redistribution and use in source and binary forms, with or without
> - *   modification, are permitted provided that the following conditions
> - *   are met:
> - *
> - *     * Redistributions of source code must retain the above copyright
> - *       notice, this list of conditions and the following disclaimer.
> - *     * Redistributions in binary form must reproduce the above copyright
> - *       notice, this list of conditions and the following disclaimer in
> - *       the documentation and/or other materials provided with the
> - *       distribution.
> - *     * Neither the name of Cavium, Inc nor the names of its
> - *       contributors may be used to endorse or promote products derived
> - *       from this software without specific prior written permission.
> - *
> - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2016 Cavium, Inc.
> + * Copyright(c) 2016-2018 Intel Corporation.
> + * Copyright(c) 2016 NXP.
> + * All rights reserved.

Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>

NXP folks,
Could you ACK the license change.

>   */
>  
>  #ifndef _RTE_EVENTDEV_H_
> -- 
> 2.6.4
> 

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v8 5/9] eventtimer: add default software driver
  2018-03-29 21:27         ` [PATCH v8 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
@ 2018-04-02  8:42           ` Jerin Jacob
  0 siblings, 0 replies; 133+ messages in thread
From: Jerin Jacob @ 2018-04-02  8:42 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, nipun.gupta, hemant.agrawal

-----Original Message-----
> Date: Thu, 29 Mar 2018 16:27:28 -0500
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com,
>  hemant.agrawal@nxp.com
> Subject: [PATCH v8 5/9] eventtimer: add default software driver
> X-Mailer: git-send-email 1.7.10
> 
> If an eventdev PMD does not wish to provide event timer adapter ops
> definitions, the library will fall back to a default software
> implementation whose entry points are added by this commit.
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---

This patch has following warnings

/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:
In function ‘sw_event_timer_adapter_service_func’:
/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:699:27:
error: ‘nb_evs_invalid’ may be used uninitialized in this function
[-Werror=maybe-uninitialized]
  uint16_t nb_evs_flushed, nb_evs_invalid;
                           ^~~~~~~~~~~~~~
/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:
In function ‘sw_event_timer_cb’:
/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:551:27:
error: ‘nb_evs_invalid’ may be used uninitialized in this function
[-Werror=maybe-uninitialized]
  uint16_t nb_evs_flushed, nb_evs_invalid;
                           ^~~~~~~~~~~~~~
cc1: all warnings being treated as errors



> 

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v8 2/9] eventdev: convert to SPDX license tag in header
  2018-04-02  8:12           ` Jerin Jacob
@ 2018-04-02  9:16             ` Hemant Agrawal
  0 siblings, 0 replies; 133+ messages in thread
From: Hemant Agrawal @ 2018-04-02  9:16 UTC (permalink / raw)
  To: Jerin Jacob, Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, Nipun Gupta

> -----Original Message-----
> > Date: Thu, 29 Mar 2018 16:27:25 -0500
> > From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > To: pbhagavatula@caviumnetworks.com
> > CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, nipun.gupta@nxp.com,
> > hemant.agrawal@nxp.com
> > Subject: [PATCH v8 2/9] eventdev: convert to SPDX license tag in
> > header
> > X-Mailer: git-send-email 1.7.10
> >
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > ---
> >  lib/librte_eventdev/rte_eventdev.h | 37
> > +++++--------------------------------
> >  1 file changed, 5 insertions(+), 32 deletions(-)
> >
> > diff --git a/lib/librte_eventdev/rte_eventdev.h
> > b/lib/librte_eventdev/rte_eventdev.h
> > index e79583a..f9ad71e 100644
> > --- a/lib/librte_eventdev/rte_eventdev.h
> > +++ b/lib/librte_eventdev/rte_eventdev.h
> > @@ -1,35 +1,8 @@
> > -/*
> > - *   BSD LICENSE
> > - *
> > - *   Copyright 2016 Cavium, Inc.
> > - *   Copyright 2016 Intel Corporation.
> > - *   Copyright 2016 NXP.
> > - *
> > - *   Redistribution and use in source and binary forms, with or without
> > - *   modification, are permitted provided that the following conditions
> > - *   are met:
> > - *
> > - *     * Redistributions of source code must retain the above copyright
> > - *       notice, this list of conditions and the following disclaimer.
> > - *     * Redistributions in binary form must reproduce the above copyright
> > - *       notice, this list of conditions and the following disclaimer in
> > - *       the documentation and/or other materials provided with the
> > - *       distribution.
> > - *     * Neither the name of Cavium, Inc nor the names of its
> > - *       contributors may be used to endorse or promote products derived
> > - *       from this software without specific prior written permission.
> > - *
> > - *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> > - *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> NOT
> > - *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> FITNESS FOR
> > - *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> > - *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> > - *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> NOT
> > - *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> OF USE,
> > - *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> AND ON ANY
> > - *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> > - *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE
> > - *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(c) 2016 Cavium, Inc.
> > + * Copyright(c) 2016-2018 Intel Corporation.
> > + * Copyright(c) 2016 NXP.

[Hemant]  Please change it to " Copyright 2016 NXP"
(No (c) and no '.')
You can add 
Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>

> > + * All rights reserved.
> 
> Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> 
> NXP folks,
> Could you ACK the license change.
> 
> >   */
> >
> >  #ifndef _RTE_EVENTDEV_H_
> > --
> > 2.6.4
> >

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v9 0/9] eventtimer: introduce event timer adapter
  2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                           ` (8 preceding siblings ...)
  2018-03-29 21:27         ` [PATCH v8 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
@ 2018-04-02 19:39         ` Erik Gabriel Carrillo
  2018-04-02 19:39           ` [PATCH v9 1/9] " Erik Gabriel Carrillo
                             ` (10 more replies)
  9 siblings, 11 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-02 19:39 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, hemant.agrawal

This patch series contains the next iteration of the Event Timer Adapter
library, which abstracts timer mechanisms that are tightly coupled with event
devices, and extends the event based programming model so that timer
expirations are represented as an event.

v9
- Addressed comments on previous series from Pavan:
  - Don't assume services exist in HW cases
  - Adjust retry logic in a couple of tests
- Addressed comments on previous series from Jerin:
  - Fix build warning
- Addressed comments on previous series from Hemant:
  - Adjust copyright text

v8
- Addressed comments on previous series from Jerin:
  - Add better git comment to initial patch
  - Return uint16_t for fastpath functions
  - Move updates to existing licenses to separate patch for individual review
  - Fix clang build error
  - Move fastpath functions into header as static inline functions
  - Remove duplicate map file entry
  - Fix flag value
  - Move update to rte.app.mk file into separate commit
- Addressed comments on previous series from Pavan:
  - Make tests generic so that they work for software or hardware event devices
    and timer mechanisms
  - Don't access eventdev internals from tests
- Integrated unit tests from Pavan

v7
- Addressed comments on previous patch series from Pavan:
  - Use SPDX license tags
  - Squash various commits to make series easier to review
  - Tag experimental functions as such
  - Use one mempool for messages and timers in sw driver 
  - Limit service cores mapped to sw driver's service to one
  - Use smp memory barriers
  - In service function, invoke rte_timer_manage() with frequency matching the
    resolution the adapter was configured with
- Reworked synchronization in sw driver between threads producing messages
  and service thread that consumes them.  The new approach avoids a situation
  where event timers couldn't be armed/canceled from the same lcore the service
  was running on.
- Updated logging facility
- Added more unit tests
- Added support for meson build

v6
- Addressed comments on previous version from Jerin:
  - Added RTE_EVENT_TIMER_CANCELED event timer state back in
  - remove check for started adapter in timer arm/cancel functions 
  - reuse CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG instead of adding new config option
- Added initial version of software driver implementation
- Added stats APIs
- Added API to retrieve adapter service ID
- Added API to initialize event timer
- Added entry to Programmer's Guide in documentation
- Added new unit tests to auto-test

v5
- Addressed comments on previous version from Pavan:
  - renamed rte_event_timer_adapter_driver.h to rte_event_timer_adapter_pmd.h
  - moved contents of sw_event_timer_adapter.c into rte_event_timer_adapter.c
  - added flags parameter to timer_adapter_caps_get() call
  - added DEBUG config variable to conditionally compile run-time checks on
    datapath
  - fixed license text and file description
- Also added a config variable to enable/disable compilation of event timer
  adapter - feedback on whether this is desirable is appreciated

v4
- Split changes into multiple patches for easier review

v3
- Reworked allocation and ops organization in common code based on feedback
  received from Jerin and Pavan. This will allow fast-path function pointers to 
  be dereferenced with one level of indirection with pointers valid in primary
  and secondary processes.
- Moved default software implementation from sw_evdev directory to eventdev
  library directory, which will allow it to be used by any eventdev PMD as an
  alternative to providing its own definitions.
- Reverted occurrences of id back to pointer to adapter struct in library API
- Added rte_event_timer_adapter_lookup() function back in

v2
- Added ops structure and stubbed out plugin for SW impl
- Added unit test stubs
- Replaced occurrences of "wheel" in API with "adapter"
- Replaced occurrences of pointer to struct rte_event_timer_adapter with ids
- Removed rte_event_timer_adapter_lookup() function
- Replaced RTE_EVENT_TIMER_SUCCESS_{ARM,CANCEL} states with
  RTE_EVENT_TIMER_ARMED

Erik Gabriel Carrillo (9):
  eventtimer: introduce event timer adapter
  eventdev: convert to SPDX license tag in header
  eventtimer: add common code
  mk: update library order in static build
  eventtimer: add default software driver
  eventtimer: add support for meson build system
  test: add event timer adapter auto-test
  doc: add event timer adapter section to programmer's guide
  doc: add event timer adapter documentation

 MAINTAINERS                                       |    7 +
 config/common_base                                |    1 +
 config/rte_config.h                               |    1 +
 doc/api/doxy-api-index.md                         |   32 +-
 doc/guides/prog_guide/event_timer_adapter.rst     |  297 ++++
 doc/guides/prog_guide/index.rst                   |    1 +
 doc/guides/rel_notes/release_18_05.rst            |    6 +
 drivers/event/sw/sw_evdev.c                       |   18 +
 lib/Makefile                                      |    2 +-
 lib/librte_eventdev/Makefile                      |    5 +-
 lib/librte_eventdev/meson.build                   |    9 +-
 lib/librte_eventdev/rte_event_timer_adapter.c     | 1296 +++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h     |  768 +++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h |  114 ++
 lib/librte_eventdev/rte_eventdev.c                |   22 +
 lib/librte_eventdev/rte_eventdev.h                |   61 +-
 lib/librte_eventdev/rte_eventdev_pmd.h            |   35 +
 lib/librte_eventdev/rte_eventdev_version.map      |   21 +-
 lib/meson.build                                   |    3 +-
 mk/rte.app.mk                                     |    2 +-
 test/test/Makefile                                |    1 +
 test/test/test_event_timer_adapter.c              | 1831 +++++++++++++++++++++
 22 files changed, 4462 insertions(+), 71 deletions(-)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h
 create mode 100644 test/test/test_event_timer_adapter.c

-- 
2.6.4

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v9 1/9] eventtimer: introduce event timer adapter
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
@ 2018-04-02 19:39           ` Erik Gabriel Carrillo
  2018-04-02 23:25             ` Jerin Jacob
  2018-04-02 19:39           ` [PATCH v9 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
                             ` (9 subsequent siblings)
  10 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-02 19:39 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, hemant.agrawal

Event devices can be coupled with various components to provide
new event sources by using event adapters.  The event timer adapter
is one such adapter; it bridges event devices and timer mechanisms.
This library extends the event-driven programming model by
introducing a new type of event that represents a timer expiration,
and it provides APIs with which adapters can be created or destroyed
and event timers can be armed and canceled.

Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/Makefile                  |   1 +
 lib/librte_eventdev/rte_event_timer_adapter.h | 715 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_eventdev.h            |   4 +-
 3 files changed, 718 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h

diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index d27dd07..549b182 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -28,6 +28,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
new file mode 100644
index 0000000..6a76791
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -0,0 +1,715 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc.
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ * @file
+ *
+ * RTE Event Timer Adapter
+ *
+ * An event timer adapter has the following abstract working model:
+ *
+ *                               timer_tick_ns
+ *                                   +
+ *                      +-------+    |
+ *                      |       |    |
+ *              +-------+ bkt 0 +----v---+
+ *              |       |       |        |
+ *              |       +-------+        |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *          |       |                |       |  |   |   |   |   |
+ *          | bkt n |                | bkt 1 |<-> t0| t1| t2| tn|
+ *          |       |                |       |  |   |   |   |   |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *              |     Timer adapter      |
+ *          +---+---+                +---+---+
+ *          |       |                |       |
+ *          | bkt 4 |                | bkt 2 |<--- Current bucket
+ *          |       |                |       |
+ *          +---+---+                +---+---+
+ *               |      +-------+       |
+ *               |      |       |       |
+ *               +------+ bkt 3 +-------+
+ *                      |       |
+ *                      +-------+
+ *
+ * - It has a virtual monotonically increasing 64-bit timer adapter clock based
+ *   on *enum rte_event_timer_adapter_clk_src* clock source. The clock source
+ *   could be a CPU clock, or a platform dependent external clock.
+ *
+ * - The application creates a timer adapter instance with given the clock
+ *   source, the total number of event timers, and a resolution(expressed in ns)
+ *   to traverse between the buckets.
+ *
+ * - Each timer adapter may have 0 to n buckets based on the configured
+ *   max timeout(max_tmo_ns) and resolution(timer_tick_ns). Upon starting the
+ *   timer adapter, the adapter starts ticking at *timer_tick_ns* resolution.
+ *
+ * - The application arms an event timer that will expire *timer_tick_ns*
+ *   from now.
+ *
+ * - The application can cancel an armed timer and no timer expiry event will be
+ *   generated.
+ *
+ * - If a timer expires then the library injects the timer expiry event in
+ *   the designated event queue.
+ *
+ * - The timer expiry event will be received through *rte_event_dequeue_burst*.
+ *
+ * - The application frees the timer adapter instance.
+ *
+ * Multiple timer adapters can be created with a varying level of resolution
+ * for various expiry use cases that run in parallel.
+ *
+ * Before using the timer adapter, the application has to create and configure
+ * an event device along with the event port. Based on the event device
+ * capability it might require creating an additional event port to be used
+ * by the timer adapter.
+ *
+ * The application creates the event timer adapter using the
+ * ``rte_event_timer_adapter_create()``. The event device id is passed to this
+ * function, inside this function the event device capability is checked,
+ * and if an in-built port is absent the application uses the default
+ * function to create a new producer port.
+ *
+ * The application may also use the function
+ * ``rte_event_timer_adapter_create_ext()`` to have granular control over
+ * producer port creation in a case where the in-built port is absent.
+ *
+ * After creating the timer adapter, the application has to start it
+ * using ``rte_event_timer_adapter_start()``. The buckets are traversed from
+ * 0 to n; when the adapter ticks, the next bucket is visited. Each time,
+ * the list per bucket is processed, and timer expiry events are sent to the
+ * designated event queue.
+ *
+ * The application can arm one or more event timers using the
+ * ``rte_event_timer_arm_burst()``. The *timeout_ticks* represents the number
+ * of *timer_tick_ns* after which the timer has to expire. The timeout at
+ * which the timers expire can be grouped or be independent of each
+ * event timer instance. ``rte_event_timer_arm_tmo_tick_burst()`` addresses the
+ * former case and ``rte_event_timer_arm_burst()`` addresses the latter case.
+ *
+ * The application can cancel the timers from expiring using the
+ * ``rte_event_timer_cancel_burst()``.
+ *
+ * On the secondary process, ``rte_event_timer_adapter_lookup()`` can be used
+ * to get the timer adapter pointer from its id and use it to invoke fastpath
+ * operations such as arm and cancel.
+ *
+ * Some of the use cases of event timer adapter are Beacon Timers,
+ * Generic SW Timeout, Wireless MAC Scheduling, 3G Frame Protocols,
+ * Packet Scheduling, Protocol Retransmission Timers, Supervision Timers.
+ * All these use cases require high resolution and low time drift.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_spinlock.h>
+#include <rte_memory.h>
+
+#include "rte_eventdev.h"
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this enum may change without prior notice
+ *
+ * Timer adapter clock source
+ */
+enum rte_event_timer_adapter_clk_src {
+	RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+	/**< Use CPU clock as the clock source. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK0,
+	/**< Platform dependent external clock source 0. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK1,
+	/**< Platform dependent external clock source 1. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK2,
+	/**< Platform dependent external clock source 2. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK3,
+	/**< Platform dependent external clock source 3. */
+};
+
+#define RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES	(1ULL << 0)
+/**< The event timer adapter implementation may have constraints on the
+ * resolution (timer_tick_ns) and maximum timer expiry timeout(max_tmo_ns)
+ * based on the given timer adapter or system.  If this flag is set, the
+ * implementation adjusts the resolution and maximum timeout to the best
+ * possible configuration. On successful timer adapter creation, the
+ * application can get the configured resolution and max timeout with
+ * ``rte_event_timer_adapter_get_info()``.
+ *
+ * @see struct rte_event_timer_adapter_info::min_resolution_ns
+ * @see struct rte_event_timer_adapter_info::max_tmo_ns
+ */
+#define RTE_EVENT_TIMER_ADAPTER_F_SP_PUT	(1ULL << 1)
+/**< ``rte_event_timer_arm_burst()`` API to be used in single producer mode.
+ *
+ * @see struct rte_event_timer_adapter_conf::flags
+ */
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter configuration structure
+ */
+struct rte_event_timer_adapter_conf {
+	uint8_t event_dev_id;
+	/**< Event device identifier */
+	uint16_t timer_adapter_id;
+	/**< Event timer adapter identifier */
+	uint32_t socket_id;
+	/**< Identifier of socket from which to allocate memory for adapter */
+	enum rte_event_timer_adapter_clk_src clk_src;
+	/**< Clock source for timer adapter */
+	uint64_t timer_tick_ns;
+	/**< Timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expiry) in ns */
+	uint64_t nb_timers;
+	/**< Total number of timers per adapter */
+	uint64_t flags;
+	/**< Timer adapter config flags (RTE_EVENT_TIMER_ADAPTER_F_*) */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer adapter stats structure
+ */
+struct rte_event_timer_adapter_stats {
+	uint64_t evtim_exp_count;
+	/**< Number of event timers that have expired. */
+	uint64_t ev_enq_count;
+	/**< Eventdev enqueue count */
+	uint64_t ev_inv_count;
+	/**< Invalid expiry event count */
+	uint64_t evtim_retry_count;
+	/**< Event timer retry count */
+	uint64_t adapter_tick_count;
+	/**< Tick count for the adapter, at its resolution */
+};
+
+struct rte_event_timer_adapter;
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Callback function type for producer port creation.
+ */
+typedef int (*rte_event_timer_adapter_port_conf_cb_t)(uint16_t id,
+						      uint8_t event_dev_id,
+						      uint8_t *event_port_id,
+						      void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create an event timer adapter.
+ *
+ * This function must be invoked first before any other function in the API.
+ *
+ * @param conf
+ *   The event timer adapter configuration structure.
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ *   - EIO: event device reconfiguration and restart error.  The adapter
+ *   reconfigures the event device with an additional port by default if it is
+ *   required to use a service to manage timers. If the device had been started
+ *   before this call, this error code indicates an error in restart following
+ *   an error in reconfiguration, i.e., a combination of the two error codes.
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create a timer adapter with the supplied callback.
+ *
+ * This function can be used to have a more granular control over the timer
+ * adapter creation.  If a built-in port is absent, then the function uses the
+ * callback provided to create and get the port id to be used as a producer
+ * port.
+ *
+ * @param conf
+ *   The timer adapter configuration structure
+ * @param conf_cb
+ *   The port config callback function.
+ * @param conf_arg
+ *   Opaque pointer to the argument for the callback function
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter info structure.
+ */
+struct rte_event_timer_adapter_info {
+	uint64_t min_resolution_ns;
+	/**< Minimum timer adapter resolution in ns */
+	uint64_t resolution_ns;
+	/**< Actual timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expire) in ns */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configured timer adapter attributes */
+	uint32_t caps;
+	/**< Event timer adapter capabilities */
+	int16_t event_dev_port_id;
+	/**< Event device port ID, if applicable */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve the contextual information of an event timer adapter.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @param[out] adapter_info
+ *   A pointer to a structure of type *rte_event_timer_adapter_info* to be
+ *   filled with the contextual information of the adapter.
+ *
+ * @return
+ *   - 0: Success, driver updates the contextual information of the
+ *   timer adapter
+ *   - <0: Error code returned by the driver info get function.
+ *   - -EINVAL: adapter identifier invalid
+ *
+ * @see RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES,
+ *   struct rte_event_timer_adapter_info
+ *
+ */
+int __rte_experimental
+rte_event_timer_adapter_get_info(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Start a timer adapter.
+ *
+ * The adapter start step is the last one and consists of setting the timer
+ * adapter to start accepting the timers and schedules to event queues.
+ *
+ * On success, all basic functions exported by the API (timer arm,
+ * timer cancel and so on) can be invoked.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter started.
+ *   - <0: Error code returned by the driver start function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_start(
+		const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Stop an event timer adapter.
+ *
+ * The adapter can be restarted with a call to
+ * ``rte_event_timer_adapter_start()``.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter stopped.
+ *   - <0: Error code returned by the driver stop function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Lookup an event timer adapter using its identifier.
+ *
+ * If an event timer adapter was created in another process with the same
+ * identifier, this function will locate its state and set up access to it
+ * so that it can be used in this process.
+ *
+ * @param adapter_id
+ *  The event timer adapter identifier.
+ *
+ * @return
+ *  A pointer to the event timer adapter matching the identifier on success.
+ *  NULL on error with rte_errno set appropriately.
+ *  Possible rte_errno values include:
+ *   - ENOENT - requested entry not available to return.
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_lookup(uint16_t adapter_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Free an event timer adapter.
+ *
+ * Destroy an event timer adapter, freeing all resources.
+ *
+ * Before invoking this function, the application must wait for all the
+ * armed timers to expire or cancel the outstanding armed timers.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully freed the event timer adapter resources.
+ *   - <0: Failed to free the event timer adapter resources.
+ *   - -EAGAIN:  adapter is busy; timers outstanding
+ *   - -EBUSY: stop hasn't been called for this adapter yet
+ *   - -EINVAL: adapter id invalid, or adapter invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter);
+
+/**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure
+ *   - -ESRCH: the adapter does not require a service to operate
+ */
+int __rte_experimental
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param[out] stats
+ *   A pointer to a structure to fill with statistics.
+ *
+ * @return
+ *   - 0: Successfully retrieved.
+ *   - <0: Failure; error code returned.
+ */
+int __rte_experimental
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully reset;
+ *   - <0: Failure; error code returned.
+ */
+int __rte_experimental rte_event_timer_adapter_stats_reset(
+		struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer state.
+ */
+enum rte_event_timer_state {
+	RTE_EVENT_TIMER_NOT_ARMED	= 0,
+	/**< Event timer not armed. */
+	RTE_EVENT_TIMER_ARMED		= 1,
+	/**< Event timer successfully armed. */
+	RTE_EVENT_TIMER_CANCELED	= 2,
+	/**< Event timer successfully canceled. */
+	RTE_EVENT_TIMER_ERROR		= -1,
+	/**< Generic event timer error. */
+	RTE_EVENT_TIMER_ERROR_TOOEARLY	= -2,
+	/**< Event timer timeout tick value is too small for the adapter to
+	 * handle, given its configured resolution.
+	 */
+	RTE_EVENT_TIMER_ERROR_TOOLATE	= -3,
+	/**< Event timer timeout tick is greater than the maximum timeout.*/
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * The generic *rte_event_timer* structure to hold the event timer attributes
+ * for arm and cancel operations.
+ */
+RTE_STD_C11
+struct rte_event_timer {
+	struct rte_event ev;
+	/**<
+	 * Expiry event attributes.  On successful event timer timeout,
+	 * the following attributes will be used to inject the expiry event to
+	 * the eventdev:
+	 *  - event_queue_id: Targeted event queue id for expiry events.
+	 *  - event_priority: Event priority of the event expiry event in the
+	 *  event queue relative to other events.
+	 *  - sched_type: Scheduling type of the expiry event.
+	 *  - flow_id: Flow id of the expiry event.
+	 *  - op: RTE_EVENT_OP_NEW
+	 *  - event_type: RTE_EVENT_TYPE_TIMER
+	 */
+	volatile enum rte_event_timer_state state;
+	/**< State of the event timer. */
+	uint64_t timeout_ticks;
+	/**< Expiry timer ticks expressed in number of *timer_ticks_ns* from
+	 * now.
+	 * @see struct rte_event_timer_adapter_info::adapter_conf::timer_tick_ns
+	 */
+	uint64_t impl_opaque[2];
+	/**< Implementation-specific opaque data.
+	 * An event timer adapter implementation use this field to hold
+	 * implementation specific values to share between the arm and cancel
+	 * operations.  The application should not modify this field.
+	 */
+	uint8_t user_meta[0];
+	/**< Memory to store user specific metadata.
+	 * The event timer adapter implementation should not modify this area.
+	 */
+} __rte_cache_aligned;
+
+typedef uint16_t (*rte_event_timer_arm_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Enable event timers to enqueue timer events upon expiry */
+typedef uint16_t (*rte_event_timer_arm_tmo_tick_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint64_t timeout_tick,
+		uint16_t nb_tims);
+/**< @internal Enable event timers with common expiration time */
+typedef uint16_t (*rte_event_timer_cancel_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Prevent event timers from enqueuing timer events */
+
+/**
+ * @internal Data structure associated with each event timer adapter.
+ */
+struct rte_event_timer_adapter {
+	rte_event_timer_arm_burst_t arm_burst;
+	/**< Pointer to driver arm_burst function. */
+	rte_event_timer_arm_tmo_tick_burst_t arm_tmo_tick_burst;
+	/**< Pointer to driver arm_tmo_tick_burst function. */
+	rte_event_timer_cancel_burst_t cancel_burst;
+	/**< Pointer to driver cancel function. */
+	struct rte_event_timer_adapter_data *data;
+	/**< Pointer to shared adapter data */
+	const struct rte_event_timer_adapter_ops *ops;
+	/**< Functions exported by adapter driver */
+
+	RTE_STD_C11
+	uint8_t allocated : 1;
+	/**< Flag to indicate that this adapter has been allocated */
+} __rte_cache_aligned;
+
+#define ADAPTER_VALID_OR_ERR_RET(adapter, retval) do { \
+	if (adapter == NULL || !adapter->allocated)    \
+		return retval;			       \
+} while (0)
+#define FUNC_PTR_OR_ERR_RET(func, errval) do { \
+	if ((func) == NULL)		       \
+		return errval;		       \
+} while (0)
+
+#define FUNC_PTR_OR_NULL_RET_WITH_ERRNO(func, errval) do { \
+	if ((func) == NULL) {				   \
+		rte_errno = errval;			   \
+		return NULL;				   \
+	}						   \
+} while (0)
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with separate expiration timeout tick for each
+ * event timer.
+ *
+ * Before calling this function, the application allocates
+ * ``struct rte_event_timer`` objects from mempool or huge page backed
+ * application buffers of desired size. On successful allocation,
+ * application updates the `struct rte_event_timer`` attributes such as
+ * expiry event attributes, timeout ticks from now.
+ * This function submits the event timer arm requests to the event timer adapter
+ * and on expiry, the events will be injected to designated event queue.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Pointer to an array of objects of type *rte_event_timer* structure.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_evtims* parameter. If the return value is less
+ *   than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
+ *   expiry event's sched type doesn't match the capabilities of the
+ *   destination event queue.
+ *   - EAGAIN Specified timer adapter is not running
+ *   - EALREADY A timer was encountered that was already armed
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **evtims,
+			  uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_burst, -EINVAL);
+#endif
+
+	return adapter->arm_burst(adapter, evtims, nb_evtims);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with same expiration timeout tick.
+ *
+ * Provides the same functionality as ``rte_event_timer_arm_burst()``, except
+ * that application can use this API when all the event timers have the
+ * same timeout expiration tick. This specialized function can provide the
+ * additional hint to the adapter implementation and optimize if possible.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Points to an array of objects of type *rte_event_timer* structure.
+ * @param timeout_ticks
+ *   The number of ticks in which the timers should expire.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_evtims* parameter. If the return value is less
+ *   than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
+ *   expiry event's sched type doesn't match the capabilities of the
+ *   destination event queue.
+ *   - EAGAIN Specified event timer adapter is not running
+ *   - EALREADY A timer was encountered that was already armed
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_arm_tmo_tick_burst(
+			const struct rte_event_timer_adapter *adapter,
+			struct rte_event_timer **evtims,
+			const uint64_t timeout_ticks,
+			const uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_tmo_tick_burst, -EINVAL);
+#endif
+
+	return adapter->arm_tmo_tick_burst(adapter, evtims, timeout_ticks,
+					   nb_evtims);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Cancel a burst of event timers from being scheduled to the event device.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Points to an array of objects of type *rte_event_timer* structure
+ * @param nb_evtims
+ *   Number of event timer instances in the supplied array.
+ *
+ * @return
+ *   The number of successfully canceled event timers. The return value can be
+ *   less than the value of the *nb_evtims* parameter. If the return value is
+ *   less than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter identifier
+ *   - EAGAIN Specified timer adapter is not running
+ *   - EALREADY  A timer was encountered that was already canceled
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			     struct rte_event_timer **evtims,
+			     uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->cancel_burst, -EINVAL);
+#endif
+
+	return adapter->cancel_burst(adapter, evtims, nb_evtims);
+}
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index b21c271..e79583a 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -923,8 +923,8 @@ rte_event_dev_close(uint8_t dev_id);
 /**< The event generated from ethdev subsystem */
 #define RTE_EVENT_TYPE_CRYPTODEV        0x1
 /**< The event generated from crypodev subsystem */
-#define RTE_EVENT_TYPE_TIMERDEV         0x2
-/**< The event generated from timerdev subsystem */
+#define RTE_EVENT_TYPE_TIMER		0x2
+/**< The event generated from event timer adapter */
 #define RTE_EVENT_TYPE_CPU              0x3
 /**< The event generated from cpu for pipelining.
  * Application may use *sub_event_type* to further classify the event
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 2/9] eventdev: convert to SPDX license tag in header
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  2018-04-02 19:39           ` [PATCH v9 1/9] " Erik Gabriel Carrillo
@ 2018-04-02 19:39           ` Erik Gabriel Carrillo
  2018-04-02 23:27             ` Jerin Jacob
  2018-04-02 19:39           ` [PATCH v9 3/9] eventtimer: add common code Erik Gabriel Carrillo
                             ` (8 subsequent siblings)
  10 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-02 19:39 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/librte_eventdev/rte_eventdev.h | 37 +++++--------------------------------
 1 file changed, 5 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index e79583a..297a93d 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -1,35 +1,8 @@
-/*
- *   BSD LICENSE
- *
- *   Copyright 2016 Cavium, Inc.
- *   Copyright 2016 Intel Corporation.
- *   Copyright 2016 NXP.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Cavium, Inc nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2016 Cavium, Inc.
+ * Copyright(c) 2016-2018 Intel Corporation.
+ * Copyright 2016 NXP
+ * All rights reserved.
  */
 
 #ifndef _RTE_EVENTDEV_H_
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 3/9] eventtimer: add common code
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
  2018-04-02 19:39           ` [PATCH v9 1/9] " Erik Gabriel Carrillo
  2018-04-02 19:39           ` [PATCH v9 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
@ 2018-04-02 19:39           ` Erik Gabriel Carrillo
  2018-04-02 23:35             ` Jerin Jacob
  2018-04-02 19:39           ` [PATCH v9 4/9] mk: update library order in static build Erik Gabriel Carrillo
                             ` (7 subsequent siblings)
  10 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-02 19:39 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, hemant.agrawal

This commit adds the logic that is shared by all event timer adapter
drivers; the common code handles instance allocation and some
initialization.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 config/common_base                                |   1 +
 drivers/event/sw/sw_evdev.c                       |  18 +
 lib/librte_eventdev/Makefile                      |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c     | 387 ++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 114 +++++++
 lib/librte_eventdev/rte_eventdev.c                |  22 ++
 lib/librte_eventdev/rte_eventdev.h                |  20 ++
 lib/librte_eventdev/rte_eventdev_pmd.h            |  35 ++
 lib/librte_eventdev/rte_eventdev_version.map      |  21 +-
 9 files changed, 619 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h

diff --git a/config/common_base b/config/common_base
index ee10b44..accc6f5 100644
--- a/config/common_base
+++ b/config/common_base
@@ -550,6 +550,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
 CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
 CONFIG_RTE_EVENT_MAX_DEVS=16
 CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32
 
 #
 # Compile PMD for skeleton event device
diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index 6672fd8..0847547 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -464,6 +464,22 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
 	return 0;
 }
 
+static int
+sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
+			  uint64_t flags,
+			  uint32_t *caps,
+			  const struct rte_event_timer_adapter_ops **ops)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(flags);
+	*caps = 0;
+
+	/* Use default SW ops */
+	*ops = NULL;
+
+	return 0;
+}
+
 static void
 sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
 {
@@ -791,6 +807,8 @@ sw_probe(struct rte_vdev_device *vdev)
 
 			.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
 
+			.timer_adapter_caps_get = sw_timer_adapter_caps_get,
+
 			.xstats_get = sw_xstats_get,
 			.xstats_get_names = sw_xstats_get_names,
 			.xstats_get_by_name = sw_xstats_get_by_name,
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 549b182..8b16e3f 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -20,6 +20,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
 SRCS-y += rte_eventdev.c
 SRCS-y += rte_event_ring.c
 SRCS-y += rte_event_eth_rx_adapter.c
+SRCS-y += rte_event_timer_adapter.c
 
 # export include files
 SYMLINK-y-include += rte_eventdev.h
@@ -29,6 +30,7 @@ SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
 SYMLINK-y-include += rte_event_timer_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter_pmd.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
new file mode 100644
index 0000000..75a14ac
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -0,0 +1,387 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#include <string.h>
+#include <inttypes.h>
+
+#include <rte_memzone.h>
+#include <rte_memory.h>
+#include <rte_dev.h>
+#include <rte_errno.h>
+
+#include "rte_eventdev.h"
+#include "rte_eventdev_pmd.h"
+#include "rte_event_timer_adapter.h"
+#include "rte_event_timer_adapter_pmd.h"
+
+#define DATA_MZ_NAME_MAX_LEN 64
+#define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
+
+static int evtim_logtype;
+
+static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
+
+#define EVTIM_LOG(level, logtype, ...) \
+	rte_log(RTE_LOG_ ## level, logtype, \
+		RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
+			"\n", __func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__,)))
+
+#define EVTIM_LOG_ERR(...) EVTIM_LOG(ERR, evtim_logtype, __VA_ARGS__)
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+#define EVTIM_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#else
+#define EVTIM_LOG_DBG(...) (void)0
+#endif
+
+static int
+default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		     void *conf_arg)
+{
+	struct rte_event_timer_adapter *adapter;
+	struct rte_eventdev *dev;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	int started;
+	uint8_t port_id;
+	uint8_t dev_id;
+	int ret;
+
+	RTE_SET_USED(event_dev_id);
+
+	adapter = &adapters[id];
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+	dev_id = dev->data->dev_id;
+	dev_conf = dev->data->dev_conf;
+
+	started = dev->data->dev_started;
+	if (started)
+		rte_event_dev_stop(dev_id);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports += 1;
+	ret = rte_event_dev_configure(dev_id, &dev_conf);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to configure event dev %u\n", dev_id);
+		if (started)
+			if (rte_event_dev_start(dev_id))
+				return -EIO;
+
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(dev_id, port_id, port_conf);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to setup event port %u on event dev %u\n",
+			      port_id, dev_id);
+		return ret;
+	}
+
+	*event_port_id = port_id;
+
+	if (started)
+		ret = rte_event_dev_start(dev_id);
+
+	return ret;
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf)
+{
+	return rte_event_timer_adapter_create_ext(conf, default_port_conf_cb,
+						  NULL);
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg)
+{
+	uint16_t adapter_id;
+	struct rte_event_timer_adapter *adapter;
+	const struct rte_memzone *mz;
+	char mz_name[DATA_MZ_NAME_MAX_LEN];
+	int n, ret;
+	struct rte_eventdev *dev;
+
+	if (conf == NULL) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Check eventdev ID */
+	if (!rte_event_pmd_is_valid_dev(conf->event_dev_id)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	dev = &rte_eventdevs[conf->event_dev_id];
+
+	adapter_id = conf->timer_adapter_id;
+
+	/* Check that adapter_id is in range */
+	if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Check adapter ID not already allocated */
+	adapter = &adapters[adapter_id];
+	if (adapter->allocated) {
+		rte_errno = EEXIST;
+		return NULL;
+	}
+
+	/* Create shared data area. */
+	n = snprintf(mz_name, sizeof(mz_name), DATA_MZ_NAME_FORMAT, adapter_id);
+	if (n >= (int)sizeof(mz_name)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	mz = rte_memzone_reserve(mz_name,
+				 sizeof(struct rte_event_timer_adapter_data),
+				 conf->socket_id, 0);
+	if (mz == NULL)
+		/* rte_errno set by rte_memzone_reserve */
+		return NULL;
+
+	adapter->data = mz->addr;
+	memset(adapter->data, 0, sizeof(struct rte_event_timer_adapter_data));
+
+	adapter->data->mz = mz;
+	adapter->data->event_dev_id = conf->event_dev_id;
+	adapter->data->id = adapter_id;
+	adapter->data->socket_id = conf->socket_id;
+	adapter->data->conf = *conf;  /* copy conf structure */
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = ret;
+		goto free_memzone;
+	}
+
+	if (!(adapter->data->caps &
+	      RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+		FUNC_PTR_OR_NULL_RET_WITH_ERRNO(conf_cb, -EINVAL);
+		ret = conf_cb(adapter->data->id, adapter->data->event_dev_id,
+			      &adapter->data->event_port_id, conf_arg);
+		if (ret < 0) {
+			rte_errno = ret;
+			goto free_memzone;
+		}
+	}
+
+	/* Allow driver to do some setup */
+	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
+	ret = adapter->ops->init(adapter);
+	if (ret < 0) {
+		rte_errno = ret;
+		goto free_memzone;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+
+free_memzone:
+	rte_memzone_free(adapter->data->mz);
+	return NULL;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->ops->get_info)
+		/* let driver set values it knows */
+		adapter->ops->get_info(adapter, adapter_info);
+
+	/* Set common values */
+	adapter_info->conf = adapter->data->conf;
+	adapter_info->event_dev_port_id = adapter->data->event_port_id;
+	adapter_info->caps = adapter->data->caps;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->start, -EINVAL);
+
+	ret = adapter->ops->start(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 1;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stop, -EINVAL);
+
+	if (adapter->data->started == 0) {
+		EVTIM_LOG_ERR("event timer adapter %"PRIu8" already stopped",
+			      adapter->data->id);
+		return 0;
+	}
+
+	ret = adapter->ops->stop(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 0;
+
+	return 0;
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_lookup(uint16_t adapter_id)
+{
+	char name[DATA_MZ_NAME_MAX_LEN];
+	const struct rte_memzone *mz;
+	struct rte_event_timer_adapter_data *data;
+	struct rte_event_timer_adapter *adapter;
+	int ret;
+	struct rte_eventdev *dev;
+
+	if (adapters[adapter_id].allocated)
+		return &adapters[adapter_id]; /* Adapter is already loaded */
+
+	snprintf(name, DATA_MZ_NAME_MAX_LEN, DATA_MZ_NAME_FORMAT, adapter_id);
+	mz = rte_memzone_lookup(name);
+	if (mz == NULL) {
+		rte_errno = ENOENT;
+		return NULL;
+	}
+
+	data = mz->addr;
+
+	adapter = &adapters[data->id];
+	adapter->data = data;
+
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->uninit, -EINVAL);
+
+	if (adapter->data->started == 1) {
+		EVTIM_LOG_ERR("event timer adapter %"PRIu8" must be stopped "
+			      "before freeing", adapter->data->id);
+		return -EBUSY;
+	}
+
+	/* free impl priv data */
+	ret = adapter->ops->uninit(adapter);
+	if (ret < 0)
+		return ret;
+
+	/* free shared data area */
+	ret = rte_memzone_free(adapter->data->mz);
+	if (ret < 0)
+		return ret;
+
+	adapter->data = NULL;
+	adapter->allocated = 0;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->data->service_inited && service_id != NULL)
+		*service_id = adapter->data->service_id;
+
+	return adapter->data->service_inited ? 0 : -ESRCH;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer_adapter_stats *stats)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_get, -EINVAL);
+	if (stats == NULL)
+		return -EINVAL;
+
+	return adapter->ops->stats_get(adapter, stats);
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_reset, -EINVAL);
+	return adapter->ops->stats_reset(adapter);
+}
+
+RTE_INIT(event_timer_adapter_init_log);
+static void
+event_timer_adapter_init_log(void)
+{
+	evtim_logtype = rte_log_register("lib.eventdev.adapter.timer");
+	if (evtim_logtype >= 0)
+		rte_log_set_level(evtim_logtype, RTE_LOG_NOTICE);
+}
diff --git a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
new file mode 100644
index 0000000..cf3509d
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_PMD_H__
+#define __RTE_EVENT_TIMER_ADAPTER_PMD_H__
+
+/**
+ * @file
+ * RTE Event Timer Adapter API (PMD Side)
+ *
+ * @note
+ * This file provides implementation helpers for internal use by PMDs.  They
+ * are not intended to be exposed to applications and are not subject to ABI
+ * versioning.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "rte_event_timer_adapter.h"
+
+/*
+ * Definitions of functions exported by an event timer adapter implementation
+ * through *rte_event_timer_adapter_ops* structure supplied in the
+ * *rte_event_timer_adapter* structure associated with an event timer adapter.
+ */
+
+typedef int (*rte_event_timer_adapter_init_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation setup */
+typedef int (*rte_event_timer_adapter_uninit_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation teardown */
+typedef int (*rte_event_timer_adapter_start_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Start running event timer adapter */
+typedef int (*rte_event_timer_adapter_stop_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Stop running event timer adapter */
+typedef void (*rte_event_timer_adapter_get_info_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+/**< @internal Get contextual information for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_get_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_stats *stats);
+/**< @internal Get statistics for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_reset_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Reset statistics for event timer adapter */
+
+/**
+ * @internal Structure containing the functions exported by an event timer
+ * adapter implementation.
+ */
+struct rte_event_timer_adapter_ops {
+	rte_event_timer_adapter_init_t		init;  /**< Set up adapter */
+	rte_event_timer_adapter_uninit_t	uninit;/**< Tear down adapter */
+	rte_event_timer_adapter_start_t		start; /**< Start adapter */
+	rte_event_timer_adapter_stop_t		stop;  /**< Stop adapter */
+	rte_event_timer_adapter_get_info_t	get_info;
+	/**< Get info from driver */
+	rte_event_timer_adapter_stats_get_t	stats_get;
+	/**< Get adapter statistics */
+	rte_event_timer_adapter_stats_reset_t	stats_reset;
+	/**< Reset adapter statistics */
+	rte_event_timer_arm_burst_t		arm_burst;
+	/**< Arm one or more event timers */
+	rte_event_timer_arm_tmo_tick_burst_t	arm_tmo_tick_burst;
+	/**< Arm event timers with same expiration time */
+	rte_event_timer_cancel_burst_t		cancel_burst;
+	/**< Cancel one or more event timers */
+};
+
+/**
+ * @internal Adapter data; structure to be placed in shared memory to be
+ * accessible by various processes in a multi-process configuration.
+ */
+struct rte_event_timer_adapter_data {
+	uint8_t id;
+	/**< Event timer adapter ID */
+	uint8_t event_dev_id;
+	/**< Event device ID */
+	uint32_t socket_id;
+	/**< Socket ID where memory is allocated */
+	uint8_t event_port_id;
+	/**< Optional: event port ID used when the inbuilt port is absent */
+	const struct rte_memzone *mz;
+	/**< Event timer adapter memzone pointer */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configuration used to configure the adapter. */
+	uint32_t caps;
+	/**< Adapter capabilities */
+	void *adapter_priv;
+	/**< Timer adapter private data*/
+	uint8_t service_inited;
+	/**< Service initialization state */
+	uint32_t service_id;
+	/**< Service ID*/
+
+	RTE_STD_C11
+	uint8_t started : 1;
+	/**< Flag to indicate adapter started. */
+} __rte_cache_aligned;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_PMD_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.c b/lib/librte_eventdev/rte_eventdev.c
index 851a119..eb3c601 100644
--- a/lib/librte_eventdev/rte_eventdev.c
+++ b/lib/librte_eventdev/rte_eventdev.c
@@ -123,6 +123,28 @@ rte_event_eth_rx_adapter_caps_get(uint8_t dev_id, uint8_t eth_port_id,
 				: 0;
 }
 
+int __rte_experimental
+rte_event_timer_adapter_caps_get(uint8_t dev_id, uint32_t *caps)
+{
+	struct rte_eventdev *dev;
+	const struct rte_event_timer_adapter_ops *ops;
+
+	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+
+	dev = &rte_eventdevs[dev_id];
+
+	if (caps == NULL)
+		return -EINVAL;
+	*caps = 0;
+
+	return dev->dev_ops->timer_adapter_caps_get ?
+				(*dev->dev_ops->timer_adapter_caps_get)(dev,
+									0,
+									caps,
+									&ops)
+				: 0;
+}
+
 static inline int
 rte_event_dev_queue_config(struct rte_eventdev *dev, uint8_t nb_queues)
 {
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index 297a93d..5c4032c 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -215,6 +215,7 @@ extern "C" {
 #include <rte_config.h>
 #include <rte_memory.h>
 #include <rte_errno.h>
+#include <rte_compat.h>
 
 struct rte_mbuf; /* we just use mbuf pointers; no need to include rte_mbuf.h */
 
@@ -1069,6 +1070,25 @@ int
 rte_event_eth_rx_adapter_caps_get(uint8_t dev_id, uint8_t eth_port_id,
 				uint32_t *caps);
 
+#define RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT (1ULL << 0)
+/**< This flag is set when the timer mechanism is in HW. */
+
+/**
+ * Retrieve the event device's timer adapter capabilities.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ *
+ * @param[out] caps
+ *   A pointer to memory to be filled with event timer adapter capabilities.
+ *
+ * @return
+ *   - 0: Success, driver provided event timer adapter capabilities.
+ *   - <0: Error code returned by the driver function.
+ */
+int __rte_experimental
+rte_event_timer_adapter_caps_get(uint8_t dev_id, uint32_t *caps);
+
 struct rte_eventdev_driver;
 struct rte_eventdev_ops;
 struct rte_eventdev;
diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h b/lib/librte_eventdev/rte_eventdev_pmd.h
index 31343b5..0e37f1c 100644
--- a/lib/librte_eventdev/rte_eventdev_pmd.h
+++ b/lib/librte_eventdev/rte_eventdev_pmd.h
@@ -26,6 +26,7 @@ extern "C" {
 #include <rte_malloc.h>
 
 #include "rte_eventdev.h"
+#include "rte_event_timer_adapter_pmd.h"
 
 /* Logging Macros */
 #define RTE_EDEV_LOG_ERR(...) \
@@ -449,6 +450,37 @@ typedef int (*eventdev_eth_rx_adapter_caps_get_t)
 struct rte_event_eth_rx_adapter_queue_conf *queue_conf;
 
 /**
+ * Retrieve the event device's timer adapter capabilities, as well as the ops
+ * structure that an event timer adapter should call through to enter the
+ * driver
+ *
+ * @param dev
+ *   Event device pointer
+ *
+ * @param flags
+ *   Flags that can be used to determine how to select an event timer
+ *   adapter ops structure
+ *
+ * @param[out] caps
+ *   A pointer to memory filled with Rx event adapter capabilities.
+ *
+ * @param[out] ops
+ *   A pointer to the ops pointer to set with the address of the desired ops
+ *   structure
+ *
+ * @return
+ *   - 0: Success, driver provides Rx event adapter capabilities for the
+ *	ethernet device.
+ *   - <0: Error code returned by the driver function.
+ *
+ */
+typedef int (*eventdev_timer_adapter_caps_get_t)(
+				const struct rte_eventdev *dev,
+				uint64_t flags,
+				uint32_t *caps,
+				const struct rte_event_timer_adapter_ops **ops);
+
+/**
  * Add ethernet Rx queues to event device. This callback is invoked if
  * the caps returned from rte_eventdev_eth_rx_adapter_caps_get(, eth_port_id)
  * has RTE_EVENT_ETH_RX_ADAPTER_CAP_INTERNAL_PORT set.
@@ -640,6 +672,9 @@ struct rte_eventdev_ops {
 	eventdev_eth_rx_adapter_stats_reset eth_rx_adapter_stats_reset;
 	/**< Reset ethernet Rx stats */
 
+	eventdev_timer_adapter_caps_get_t timer_adapter_caps_get;
+	/**< Get timer adapter capabilities */
+
 	eventdev_selftest dev_selftest;
 	/**< Start eventdev Selftest */
 };
diff --git a/lib/librte_eventdev/rte_eventdev_version.map b/lib/librte_eventdev/rte_eventdev_version.map
index 2aef470..537afb8 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -66,7 +66,6 @@ DPDK_17.11 {
 	rte_event_eth_rx_adapter_stats_get;
 	rte_event_eth_rx_adapter_stats_reset;
 	rte_event_eth_rx_adapter_stop;
-
 } DPDK_17.08;
 
 DPDK_18.02 {
@@ -74,3 +73,23 @@ DPDK_18.02 {
 
 	rte_event_dev_selftest;
 } DPDK_17.11;
+
+EXPERIMENTAL {
+	global:
+
+        rte_event_timer_adapter_caps_get;
+	rte_event_timer_adapter_create;
+	rte_event_timer_adapter_create_ext;
+	rte_event_timer_adapter_free;
+	rte_event_timer_adapter_get_info;
+	rte_event_timer_adapter_lookup;
+	rte_event_timer_adapter_service_id_get;
+	rte_event_timer_adapter_start;
+	rte_event_timer_adapter_stats_get;
+	rte_event_timer_adapter_stats_reset;
+	rte_event_timer_adapter_stop;
+	rte_event_timer_init;
+	rte_event_timer_arm_burst;
+	rte_event_timer_arm_tmo_tick_burst;
+	rte_event_timer_cancel_burst;
+} DPDK_18.02;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 4/9] mk: update library order in static build
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                             ` (2 preceding siblings ...)
  2018-04-02 19:39           ` [PATCH v9 3/9] eventtimer: add common code Erik Gabriel Carrillo
@ 2018-04-02 19:39           ` Erik Gabriel Carrillo
  2018-04-02 23:36             ` Jerin Jacob
  2018-04-02 19:39           ` [PATCH v9 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
                             ` (6 subsequent siblings)
  10 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-02 19:39 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, hemant.agrawal

The introduction of the event timer adapter library adds a dependency
on the rte_timer library from the rte_eventdev library.  Update the
order so that the timer library comes after the eventdev library in the
linker command when statically linking applications.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 mk/rte.app.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 94525dc..983ad09 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)        += -lrte_bitratestats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
 
-_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
 
 _LDLIBS-y += --whole-archive
@@ -98,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)       += -lrte_security
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV)         += -lrte_rawdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 5/9] eventtimer: add default software driver
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                             ` (3 preceding siblings ...)
  2018-04-02 19:39           ` [PATCH v9 4/9] mk: update library order in static build Erik Gabriel Carrillo
@ 2018-04-02 19:39           ` Erik Gabriel Carrillo
  2018-04-03  9:59             ` Pavan Nikhilesh
  2018-04-02 19:39           ` [PATCH v9 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
                             ` (5 subsequent siblings)
  10 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-02 19:39 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, hemant.agrawal

If an eventdev PMD does not wish to provide event timer adapter ops
definitions, the library will fall back to a default software
implementation whose entry points are added by this commit.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 lib/Makefile                                  |   2 +-
 lib/librte_eventdev/Makefile                  |   2 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 909 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h |  57 +-
 4 files changed, 966 insertions(+), 4 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a6..965be6c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -31,7 +31,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
 DEPDIRS-librte_security += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash
+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_RAWDEV) += librte_rawdev
 DEPDIRS-librte_rawdev := librte_eal librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 8b16e3f..297df4a 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -14,7 +14,7 @@ LIBABIVER := 3
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool -lrte_timer
 
 # library source files
 SRCS-y += rte_eventdev.c
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 75a14ac..24993c1 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -5,11 +5,20 @@
 
 #include <string.h>
 #include <inttypes.h>
+#include <stdbool.h>
+#include <sys/queue.h>
 
 #include <rte_memzone.h>
 #include <rte_memory.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_common.h>
+#include <rte_timer.h>
+#include <rte_service_component.h>
+#include <rte_cycles.h>
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -20,9 +29,13 @@
 #define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
 
 static int evtim_logtype;
+static int evtim_svc_logtype;
+static int evtim_buffer_logtype;
 
 static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+
 #define EVTIM_LOG(level, logtype, ...) \
 	rte_log(RTE_LOG_ ## level, logtype, \
 		RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
@@ -33,8 +46,14 @@ static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 #ifdef RTE_LIBRTE_EVENTDEV_DEBUG
 #define EVTIM_LOG_DBG(...) \
 	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#define EVTIM_BUF_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_buffer_logtype, __VA_ARGS__)
+#define EVTIM_SVC_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_svc_logtype, __VA_ARGS__)
 #else
 #define EVTIM_LOG_DBG(...) (void)0
+#define EVTIM_BUF_LOG_DBG(...) (void)0
+#define EVTIM_SVC_LOG_DBG(...) (void)0
 #endif
 
 static int
@@ -188,6 +207,12 @@ rte_event_timer_adapter_create_ext(
 		}
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Allow driver to do some setup */
 	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
 	ret = adapter->ops->init(adapter);
@@ -305,6 +330,12 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
 		return NULL;
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Set fast-path function pointers */
 	adapter->arm_burst = adapter->ops->arm_burst;
 	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
@@ -377,6 +408,875 @@ rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
 	return adapter->ops->stats_reset(adapter);
 }
 
+/*
+ * Software event timer adapter buffer helper functions
+ */
+
+#define NSECPERSEC 1E9
+
+/* Optimizations used to index into the buffer require that the buffer size
+ * be a power of 2.
+ */
+#define EVENT_BUFFER_SZ 4096
+#define EVENT_BUFFER_BATCHSZ 32
+#define EVENT_BUFFER_MASK (EVENT_BUFFER_SZ - 1)
+
+struct event_buffer {
+	uint16_t head;
+	uint16_t tail;
+	struct rte_event events[EVENT_BUFFER_SZ];
+} __rte_cache_aligned;
+
+static inline bool
+event_buffer_full(struct event_buffer *bufp)
+{
+	return (bufp->head - bufp->tail) == EVENT_BUFFER_SZ;
+}
+
+static inline bool
+event_buffer_batch_ready(struct event_buffer *bufp)
+{
+	return (bufp->head - bufp->tail) >= EVENT_BUFFER_BATCHSZ;
+}
+
+static void
+event_buffer_init(struct event_buffer *bufp)
+{
+	bufp->head = bufp->tail = 0;
+	memset(&bufp->events, 0, sizeof(struct rte_event) * EVENT_BUFFER_SZ);
+}
+
+static int
+event_buffer_add(struct event_buffer *bufp, struct rte_event *eventp)
+{
+	uint16_t head_idx;
+	struct rte_event *buf_eventp;
+
+	if (event_buffer_full(bufp))
+		return -1;
+
+	/* Instead of modulus, bitwise AND with mask to get head_idx. */
+	head_idx = bufp->head & EVENT_BUFFER_MASK;
+	buf_eventp = &bufp->events[head_idx];
+	rte_memcpy(buf_eventp, eventp, sizeof(struct rte_event));
+
+	/* Wrap automatically when overflow occurs. */
+	bufp->head++;
+
+	return 0;
+}
+
+static void
+event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,
+		   uint16_t *nb_events_flushed,
+		   uint16_t *nb_events_inv)
+{
+	uint16_t head_idx, tail_idx, n = 0;
+	struct rte_event *events = bufp->events;
+
+	/* Instead of modulus, bitwise AND with mask to get index. */
+	head_idx = bufp->head & EVENT_BUFFER_MASK;
+	tail_idx = bufp->tail & EVENT_BUFFER_MASK;
+
+	/* Determine the largest contigous run we can attempt to enqueue to the
+	 * event device.
+	 */
+	if (head_idx > tail_idx)
+		n = head_idx - tail_idx;
+	else if (head_idx < tail_idx)
+		n = EVENT_BUFFER_SZ - tail_idx;
+	else {
+		*nb_events_flushed = 0;
+		return;
+	}
+
+	*nb_events_inv = 0;
+	*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
+						     &events[tail_idx], n);
+	if (*nb_events_flushed != n && rte_errno == -EINVAL) {
+		EVTIM_LOG_ERR("failed to enqueue invalid event - dropping it");
+		(*nb_events_inv)++;
+	}
+
+	bufp->tail = bufp->tail + *nb_events_flushed + *nb_events_inv;
+}
+
+/*
+ * Software event timer adapter implementation
+ */
+
+struct rte_event_timer_adapter_sw_data {
+	/* List of messages for outstanding timers */
+	TAILQ_HEAD(, msg) msgs_tailq_head;
+	/* Lock to guard tailq and armed count */
+	rte_spinlock_t msgs_tailq_sl;
+	/* Identifier of service executing timer management logic. */
+	uint32_t service_id;
+	/* The cycle count at which the adapter should next tick */
+	uint64_t next_tick_cycles;
+	/* Incremented as the service moves through phases of an iteration */
+	volatile int service_phase;
+	/* The tick resolution used by adapter instance. May have been
+	 * adjusted from what user requested
+	 */
+	uint64_t timer_tick_ns;
+	/* Maximum timeout in nanoseconds allowed by adapter instance. */
+	uint64_t max_tmo_ns;
+	/* Ring containing messages to arm or cancel event timers */
+	struct rte_ring *msg_ring;
+	/* Mempool containing msg objects */
+	struct rte_mempool *msg_pool;
+	/* Buffered timer expiry events to be enqueued to an event device. */
+	struct event_buffer buffer;
+	/* Statistics */
+	struct rte_event_timer_adapter_stats stats;
+	/* The number of threads currently adding to the message ring */
+	rte_atomic16_t message_producer_count;
+};
+
+enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
+
+struct msg {
+	enum msg_type type;
+	struct rte_event_timer *evtim;
+	struct rte_timer tim;
+	TAILQ_ENTRY(msg) msgs;
+};
+
+static void
+sw_event_timer_cb(struct rte_timer *tim, void *arg)
+{
+	int ret;
+	uint16_t nb_evs_flushed = 0;
+	uint16_t nb_evs_invalid = 0;
+	struct rte_event_timer *evtim;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	evtim = arg;
+	adapter = (struct rte_event_timer_adapter *)evtim->impl_opaque[1];
+	sw_data = adapter->data->adapter_priv;
+
+	ret = event_buffer_add(&sw_data->buffer, &evtim->ev);
+	if (ret < 0) {
+		/* If event buffer is full, put timer back in list with
+		 * immediate expiry value, so that we process it again on the
+		 * next iteration.
+		 */
+		rte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),
+				     sw_event_timer_cb, evtim);
+
+		sw_data->stats.evtim_retry_count++;
+		EVTIM_LOG_DBG("event buffer full, resetting rte_timer with "
+			      "immediate expiry value");
+	} else {
+		struct msg *m = container_of(tim, struct msg, tim);
+		TAILQ_REMOVE(&sw_data->msgs_tailq_head, m, msgs);
+		EVTIM_BUF_LOG_DBG("buffered an event timer expiry event");
+		evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+
+		/* Free the msg object containing the rte_timer now that
+		 * we've buffered its event successfully.
+		 */
+		rte_mempool_put(sw_data->msg_pool, m);
+
+		/* Bump the count when we successfully add an expiry event to
+		 * the buffer.
+		 */
+		sw_data->stats.evtim_exp_count++;
+	}
+
+	if (event_buffer_batch_ready(&sw_data->buffer)) {
+		event_buffer_flush(&sw_data->buffer,
+				   adapter->data->event_dev_id,
+				   adapter->data->event_port_id,
+				   &nb_evs_flushed,
+				   &nb_evs_invalid);
+
+		sw_data->stats.ev_enq_count += nb_evs_flushed;
+		sw_data->stats.ev_inv_count += nb_evs_invalid;
+	}
+}
+
+static __rte_always_inline uint64_t
+get_timeout_cycles(struct rte_event_timer *evtim,
+		   struct rte_event_timer_adapter *adapter)
+{
+	uint64_t timeout_ns;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	timeout_ns = evtim->timeout_ticks * sw_data->timer_tick_ns;
+	return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
+
+}
+
+/* This function returns true if one or more (adapter) ticks have occurred since
+ * the last time it was called.
+ */
+static inline bool
+adapter_did_tick(struct rte_event_timer_adapter *adapter)
+{
+	uint64_t cycles_per_adapter_tick, start_cycles;
+	uint64_t *next_tick_cyclesp;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	next_tick_cyclesp = &sw_data->next_tick_cycles;
+
+	cycles_per_adapter_tick = sw_data->timer_tick_ns *
+			(rte_get_timer_hz() / NSECPERSEC);
+
+	start_cycles = rte_get_timer_cycles();
+
+	/* Note: initially, *next_tick_cyclesp == 0, so the clause below will
+	 * execute, and set things going.
+	 */
+
+	if (start_cycles >= *next_tick_cyclesp) {
+		/* Snap the current cycle count to the preceding adapter tick
+		 * boundary.
+		 */
+		start_cycles -= start_cycles % cycles_per_adapter_tick;
+
+		*next_tick_cyclesp = start_cycles + cycles_per_adapter_tick;
+
+		return true;
+	}
+
+	return false;
+}
+
+/* Check that event timer timeout value is in range */
+static __rte_always_inline int
+check_timeout(struct rte_event_timer *evtim,
+	      const struct rte_event_timer_adapter *adapter)
+{
+	uint64_t tmo_nsec;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	tmo_nsec = evtim->timeout_ticks * sw_data->timer_tick_ns;
+
+	if (tmo_nsec > sw_data->max_tmo_ns)
+		return -1;
+
+	if (tmo_nsec < sw_data->timer_tick_ns)
+		return -2;
+
+	return 0;
+}
+
+/* Check that event timer event queue sched type matches destination event queue
+ * sched type
+ */
+static __rte_always_inline int
+check_destination_event_queue(struct rte_event_timer *evtim,
+			      const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	uint32_t sched_type;
+
+	ret = rte_event_queue_attr_get(adapter->data->event_dev_id,
+				       evtim->ev.queue_id,
+				       RTE_EVENT_QUEUE_ATTR_SCHEDULE_TYPE,
+				       &sched_type);
+
+	if ((ret < 0 && ret != -EOVERFLOW) ||
+	    evtim->ev.sched_type != sched_type)
+		return -1;
+
+	return 0;
+}
+
+#define NB_OBJS 32
+static int
+sw_event_timer_adapter_service_func(void *arg)
+{
+	int ret, i, num_msgs;
+	uint64_t cycles;
+	uint16_t nb_evs_flushed = 0;
+	uint16_t nb_evs_invalid = 0;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_timer *tim = NULL;
+	struct msg *msg, *msgs[NB_OBJS];
+
+	RTE_SET_USED(ret);
+
+	adapter = arg;
+	sw_data = adapter->data->adapter_priv;
+
+	sw_data->service_phase = 1;
+	rte_smp_wmb();
+
+	while (rte_atomic16_read(&sw_data->message_producer_count) > 0 ||
+	       !rte_ring_empty(sw_data->msg_ring)) {
+
+		num_msgs = rte_ring_dequeue_burst(sw_data->msg_ring,
+						  (void **)msgs, NB_OBJS, NULL);
+
+		for (i = 0; i < num_msgs; i++) {
+			msg = msgs[i];
+			evtim = msg->evtim;
+
+			switch (msg->type) {
+			case MSG_TYPE_ARM:
+				EVTIM_SVC_LOG_DBG("dequeued ARM message from "
+						  "ring");
+				tim = &msg->tim;
+				rte_timer_init(tim);
+				cycles = get_timeout_cycles(evtim,
+							    adapter);
+				ret = rte_timer_reset(tim, cycles, SINGLE,
+						      rte_lcore_id(),
+						      sw_event_timer_cb,
+						      evtim);
+				RTE_ASSERT(ret == 0);
+
+				evtim->impl_opaque[0] = (uintptr_t)tim;
+				evtim->impl_opaque[1] = (uintptr_t)adapter;
+
+				TAILQ_INSERT_TAIL(&sw_data->msgs_tailq_head,
+						  msg,
+						  msgs);
+				break;
+			case MSG_TYPE_CANCEL:
+				EVTIM_SVC_LOG_DBG("dequeued CANCEL message "
+						  "from ring");
+				tim = (struct rte_timer *)evtim->impl_opaque[0];
+				RTE_ASSERT(tim != NULL);
+
+				ret = rte_timer_stop(tim);
+				RTE_ASSERT(ret == 0);
+
+				/* Free the msg object for the original arm
+				 * request.
+				 */
+				struct msg *m;
+				m = container_of(tim, struct msg, tim);
+				TAILQ_REMOVE(&sw_data->msgs_tailq_head, m,
+					     msgs);
+				rte_mempool_put(sw_data->msg_pool, m);
+
+				/* Free the msg object for the current msg */
+				rte_mempool_put(sw_data->msg_pool, msg);
+
+				evtim->impl_opaque[0] = 0;
+				evtim->impl_opaque[1] = 0;
+
+				break;
+			}
+		}
+	}
+
+	sw_data->service_phase = 2;
+	rte_smp_wmb();
+
+	if (adapter_did_tick(adapter)) {
+		rte_timer_manage();
+
+		event_buffer_flush(&sw_data->buffer,
+				   adapter->data->event_dev_id,
+				   adapter->data->event_port_id,
+				   &nb_evs_flushed, &nb_evs_invalid);
+
+		sw_data->stats.ev_enq_count += nb_evs_flushed;
+		sw_data->stats.ev_inv_count += nb_evs_invalid;
+		sw_data->stats.adapter_tick_count++;
+	}
+
+	sw_data->service_phase = 0;
+	rte_smp_wmb();
+
+	return 0;
+}
+
+/* The adapter initialization function rounds the mempool size up to the next
+ * power of 2, so we can take the difference between that value and what the
+ * user requested, and use the space for caches.  This avoids a scenario where a
+ * user can't arm the number of timers the adapter was configured with because
+ * mempool objects have been lost to caches.
+ *
+ * nb_actual should always be a power of 2, so we can iterate over the powers
+ * of 2 to see what the largest cache size we can use is.
+ */
+static int
+compute_msg_mempool_cache_size(uint64_t nb_requested, uint64_t nb_actual)
+{
+	int i;
+	int size;
+	int cache_size = 0;
+
+	for (i = 0; ; i++) {
+		size = 1 << i;
+
+		if (RTE_MAX_LCORE * size < (int)(nb_actual - nb_requested) &&
+		    size < RTE_MEMPOOL_CACHE_MAX_SIZE &&
+		    size <= nb_actual / 1.5)
+			cache_size = size;
+		else
+			break;
+	}
+
+	return cache_size;
+}
+
+#define SW_MIN_INTERVAL 1E5
+
+static int
+sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	uint64_t nb_timers;
+	unsigned int flags;
+	struct rte_service_spec service;
+	static bool timer_subsystem_inited; // static initialized to false
+
+	/* Allocate storage for SW implementation data */
+	char priv_data_name[RTE_RING_NAMESIZE];
+	snprintf(priv_data_name, RTE_RING_NAMESIZE, "sw_evtim_adap_priv_%"PRIu8,
+		 adapter->data->id);
+	adapter->data->adapter_priv = rte_zmalloc_socket(
+				priv_data_name,
+				sizeof(struct rte_event_timer_adapter_sw_data),
+				RTE_CACHE_LINE_SIZE,
+				adapter->data->socket_id);
+	if (adapter->data->adapter_priv == NULL) {
+		EVTIM_LOG_ERR("failed to allocate space for private data");
+		rte_errno = ENOMEM;
+		return -1;
+	}
+
+	if (adapter->data->conf.timer_tick_ns < SW_MIN_INTERVAL) {
+		EVTIM_LOG_ERR("failed to create adapter with requested tick "
+			      "interval");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	sw_data = adapter->data->adapter_priv;
+
+	sw_data->timer_tick_ns = adapter->data->conf.timer_tick_ns;
+	sw_data->max_tmo_ns = adapter->data->conf.max_tmo_ns;
+
+	TAILQ_INIT(&sw_data->msgs_tailq_head);
+	rte_spinlock_init(&sw_data->msgs_tailq_sl);
+	rte_atomic16_init(&sw_data->message_producer_count);
+
+	/* Rings require power of 2, so round up to next such value */
+	nb_timers = rte_align64pow2(adapter->data->conf.nb_timers);
+
+	char msg_ring_name[RTE_RING_NAMESIZE];
+	snprintf(msg_ring_name, RTE_RING_NAMESIZE,
+		 "sw_evtim_adap_msg_ring_%"PRIu8, adapter->data->id);
+	flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+		RING_F_SP_ENQ | RING_F_SC_DEQ :
+		RING_F_SC_DEQ;
+	sw_data->msg_ring = rte_ring_create(msg_ring_name, nb_timers,
+					    adapter->data->socket_id, flags);
+	if (sw_data->msg_ring == NULL) {
+		EVTIM_LOG_ERR("failed to create message ring");
+		rte_errno = ENOMEM;
+		goto free_priv_data;
+	}
+
+	char pool_name[RTE_RING_NAMESIZE];
+	snprintf(pool_name, RTE_RING_NAMESIZE, "sw_evtim_adap_msg_pool_%"PRIu8,
+		 adapter->data->id);
+
+	/* Both the arming/canceling thread and the service thread will do puts
+	 * to the mempool, but if the SP_PUT flag is enabled, we can specify
+	 * single-consumer get for the mempool.
+	 */
+	flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+		MEMPOOL_F_SC_GET : 0;
+
+	/* The usable size of a ring is count - 1, so subtract one here to
+	 * make the counts agree.
+	 */
+	int pool_size = nb_timers - 1;
+	int cache_size = compute_msg_mempool_cache_size(
+				adapter->data->conf.nb_timers, nb_timers);
+	sw_data->msg_pool = rte_mempool_create(pool_name, pool_size,
+					       sizeof(struct msg), cache_size,
+					       0, NULL, NULL, NULL, NULL,
+					       adapter->data->socket_id, flags);
+	if (sw_data->msg_pool == NULL) {
+		EVTIM_LOG_ERR("failed to create message object mempool");
+		rte_errno = ENOMEM;
+		goto free_msg_ring;
+	}
+
+	event_buffer_init(&sw_data->buffer);
+
+	/* Register a service component to run adapter logic */
+	memset(&service, 0, sizeof(service));
+	snprintf(service.name, RTE_SERVICE_NAME_MAX,
+		 "sw_evimer_adap_svc_%"PRIu8, adapter->data->id);
+	service.socket_id = adapter->data->socket_id;
+	service.callback = sw_event_timer_adapter_service_func;
+	service.callback_userdata = adapter;
+	service.capabilities &= ~(RTE_SERVICE_CAP_MT_SAFE);
+	ret = rte_service_component_register(&service, &sw_data->service_id);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to register service %s with id %"PRIu32
+			      ": err = %d", service.name, sw_data->service_id,
+			      ret);
+
+		rte_errno = ENOSPC;
+		goto free_msg_pool;
+	}
+
+	EVTIM_LOG_DBG("registered service %s with id %"PRIu32, service.name,
+		      sw_data->service_id);
+
+	adapter->data->service_id = sw_data->service_id;
+	adapter->data->service_inited = 1;
+
+	if (!timer_subsystem_inited) {
+		rte_timer_subsystem_init();
+		timer_subsystem_inited = true;
+	}
+
+	return 0;
+
+free_msg_pool:
+	rte_mempool_free(sw_data->msg_pool);
+free_msg_ring:
+	rte_ring_free(sw_data->msg_ring);
+free_priv_data:
+	rte_free(sw_data);
+	return -1;
+}
+
+static int
+sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct msg *m1, *m2;
+	struct rte_event_timer_adapter_sw_data *sw_data =
+						adapter->data->adapter_priv;
+
+	rte_spinlock_lock(&sw_data->msgs_tailq_sl);
+
+	/* Cancel outstanding rte_timers and free msg objects */
+	m1 = TAILQ_FIRST(&sw_data->msgs_tailq_head);
+	while (m1 != NULL) {
+		EVTIM_LOG_DBG("freeing outstanding timer");
+		m2 = TAILQ_NEXT(m1, msgs);
+
+		rte_timer_stop_sync(&m1->tim);
+		rte_mempool_put(sw_data->msg_pool, m1);
+
+		m1 = m2;
+	}
+
+	rte_spinlock_unlock(&sw_data->msgs_tailq_sl);
+
+	ret = rte_service_component_unregister(sw_data->service_id);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to unregister service component");
+		return ret;
+	}
+
+	rte_ring_free(sw_data->msg_ring);
+	rte_mempool_free(sw_data->msg_pool);
+	rte_free(adapter->data->adapter_priv);
+
+	return 0;
+}
+
+static inline int32_t
+get_mapped_count_for_service(uint32_t service_id)
+{
+	int32_t core_count, i, mapped_count = 0;
+	uint32_t lcore_arr[RTE_MAX_LCORE];
+
+	core_count = rte_service_lcore_list(lcore_arr, RTE_MAX_LCORE);
+
+	for (i = 0; i < core_count; i++)
+		if (rte_service_map_lcore_get(service_id, lcore_arr[i]) == 1)
+			mapped_count++;
+
+	return mapped_count;
+}
+
+static int
+sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int mapped_count;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+
+	/* Mapping the service to more than one service core can introduce
+	 * delays while one thread is waiting to acquire a lock, so only allow
+	 * one core to be mapped to the service.
+	 */
+	mapped_count = get_mapped_count_for_service(sw_data->service_id);
+
+	if (mapped_count == 1)
+		return rte_service_component_runstate_set(sw_data->service_id,
+							  1);
+
+	return mapped_count < 1 ? -ENOENT : -ENOTSUP;
+}
+
+static int
+sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data =
+						adapter->data->adapter_priv;
+
+	ret = rte_service_component_runstate_set(sw_data->service_id, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Wait for the service to complete its final iteration before
+	 * stopping.
+	 */
+	while (sw_data->service_phase != 0)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	return 0;
+}
+
+static void
+sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+
+	adapter_info->min_resolution_ns = sw_data->timer_tick_ns;
+	adapter_info->max_tmo_ns = sw_data->max_tmo_ns;
+}
+
+static int
+sw_event_timer_adapter_stats_get(const struct rte_event_timer_adapter *adapter,
+				 struct rte_event_timer_adapter_stats *stats)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	*stats = sw_data->stats;
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_stats_reset(
+				const struct rte_event_timer_adapter *adapter)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	memset(&sw_data->stats, 0, sizeof(sw_data->stats));
+	return 0;
+}
+
+static __rte_always_inline uint16_t
+__sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **evtims,
+			  uint16_t nb_evtims)
+{
+	uint16_t i;
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct msg *msgs[nb_evtims];
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	/* Check that the service is running. */
+	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
+		rte_errno = EINVAL;
+		return 0;
+	}
+#endif
+
+	sw_data = adapter->data->adapter_priv;
+
+	ret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (ret < 0) {
+		rte_errno = ENOSPC;
+		return 0;
+	}
+
+	/* Let the service know we're producing messages for it to process */
+	rte_atomic16_inc(&sw_data->message_producer_count);
+
+	/* If the service is managing timers, wait for it to finish */
+	while (sw_data->service_phase == 2)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	for (i = 0; i < nb_evtims; i++) {
+		/* Don't modify the event timer state in these cases */
+		if (evtims[i]->state == RTE_EVENT_TIMER_ARMED) {
+			rte_errno = EALREADY;
+			break;
+		} else if (!(evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
+		    evtims[i]->state == RTE_EVENT_TIMER_CANCELED)) {
+			rte_errno = EINVAL;
+			break;
+		}
+
+		ret = check_timeout(evtims[i], adapter);
+		if (ret == -1) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOLATE;
+			rte_errno = EINVAL;
+			break;
+		}
+		if (ret == -2) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOEARLY;
+			rte_errno = EINVAL;
+			break;
+		}
+
+		if (check_destination_event_queue(evtims[i], adapter) < 0) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR;
+			rte_errno = EINVAL;
+			break;
+		}
+
+		/* Checks passed, set up a message to enqueue */
+		msgs[i]->type = MSG_TYPE_ARM;
+		msgs[i]->evtim = evtims[i];
+
+		/* Set the payload pointer if not set. */
+		if (evtims[i]->ev.event_ptr == NULL)
+			evtims[i]->ev.event_ptr = evtims[i];
+
+		/* msg objects that get enqueued successfully will be freed
+		 * either by a future cancel operation or by the timer
+		 * expiration callback.
+		 */
+		if (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {
+			rte_errno = ENOSPC;
+			break;
+		}
+
+		EVTIM_LOG_DBG("enqueued ARM message to ring");
+
+		evtims[i]->state = RTE_EVENT_TIMER_ARMED;
+	}
+
+	/* Let the service know we're done producing messages */
+	rte_atomic16_dec(&sw_data->message_producer_count);
+
+	if (i < nb_evtims)
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],
+				     nb_evtims - i);
+
+	return i;
+}
+
+static uint16_t
+sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			 struct rte_event_timer **evtims,
+			 uint16_t nb_evtims)
+{
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
+}
+
+static uint16_t
+sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			    struct rte_event_timer **evtims,
+			    uint16_t nb_evtims)
+{
+	uint16_t i;
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct msg *msgs[nb_evtims];
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	/* Check that the service is running. */
+	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
+		rte_errno = EINVAL;
+		return 0;
+	}
+#endif
+
+	sw_data = adapter->data->adapter_priv;
+
+	ret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (ret < 0) {
+		rte_errno = ENOSPC;
+		return 0;
+	}
+
+	/* Let the service know we're producing messages for it to process */
+	rte_atomic16_inc(&sw_data->message_producer_count);
+
+	/* If the service could be modifying event timer states, wait */
+	while (sw_data->service_phase == 2)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	for (i = 0; i < nb_evtims; i++) {
+		/* Don't modify the event timer state in these cases */
+		if (evtims[i]->state == RTE_EVENT_TIMER_CANCELED) {
+			rte_errno = EALREADY;
+			break;
+		} else if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
+			rte_errno = EINVAL;
+			break;
+		}
+
+		msgs[i]->type = MSG_TYPE_CANCEL;
+		msgs[i]->evtim = evtims[i];
+
+		if (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {
+			rte_errno = ENOSPC;
+			break;
+		}
+
+		EVTIM_LOG_DBG("enqueued CANCEL message to ring");
+
+		evtims[i]->state = RTE_EVENT_TIMER_CANCELED;
+	}
+
+	/* Let the service know we're done producing messages */
+	rte_atomic16_dec(&sw_data->message_producer_count);
+
+	if (i < nb_evtims)
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],
+				     nb_evtims - i);
+
+	return i;
+}
+
+static uint16_t
+sw_event_timer_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer **evtims,
+				  uint64_t timeout_ticks,
+				  uint16_t nb_evtims)
+{
+	int i;
+
+	for (i = 0; i < nb_evtims; i++)
+		evtims[i]->timeout_ticks = timeout_ticks;
+
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
+}
+
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
+	.init = sw_event_timer_adapter_init,
+	.uninit = sw_event_timer_adapter_uninit,
+	.start = sw_event_timer_adapter_start,
+	.stop = sw_event_timer_adapter_stop,
+	.get_info = sw_event_timer_adapter_get_info,
+	.stats_get = sw_event_timer_adapter_stats_get,
+	.stats_reset = sw_event_timer_adapter_stats_reset,
+	.arm_burst = sw_event_timer_arm_burst,
+	.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
+	.cancel_burst = sw_event_timer_cancel_burst,
+};
+
 RTE_INIT(event_timer_adapter_init_log);
 static void
 event_timer_adapter_init_log(void)
@@ -384,4 +1284,13 @@ event_timer_adapter_init_log(void)
 	evtim_logtype = rte_log_register("lib.eventdev.adapter.timer");
 	if (evtim_logtype >= 0)
 		rte_log_set_level(evtim_logtype, RTE_LOG_NOTICE);
+
+	evtim_buffer_logtype = rte_log_register("lib.eventdev.adapter.timer."
+						"buffer");
+	if (evtim_buffer_logtype >= 0)
+		rte_log_set_level(evtim_buffer_logtype, RTE_LOG_NOTICE);
+
+	evtim_svc_logtype = rte_log_register("lib.eventdev.adapter.timer.svc");
+	if (evtim_svc_logtype >= 0)
+		rte_log_set_level(evtim_svc_logtype, RTE_LOG_NOTICE);
 }
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index 6a76791..38a314d 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -280,8 +280,6 @@ rte_event_timer_adapter_create_ext(
 struct rte_event_timer_adapter_info {
 	uint64_t min_resolution_ns;
 	/**< Minimum timer adapter resolution in ns */
-	uint64_t resolution_ns;
-	/**< Actual timer adapter resolution in ns */
 	uint64_t max_tmo_ns;
 	/**< Maximum timer timeout(expire) in ns */
 	struct rte_event_timer_adapter_conf conf;
@@ -339,6 +337,8 @@ rte_event_timer_adapter_get_info(
  *   - 0: Success, adapter started.
  *   - <0: Error code returned by the driver start function.
  *   - -EINVAL if adapter identifier invalid
+ *   - -ENOENT if software adapter but no service core mapped
+ *   - -ENOTSUP if software adapter and more than one service core mapped
  */
 int __rte_experimental
 rte_event_timer_adapter_start(
@@ -465,6 +465,59 @@ int __rte_experimental rte_event_timer_adapter_stats_reset(
 		struct rte_event_timer_adapter *adapter);
 
 /**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure, if the event dev doesn't use a rte_service
+ *   function, this function returns -ESRCH.
+ */
+int
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param[out] stats
+ *   A pointer to a structure to fill with statistics.
+ *
+ * @return
+ *   - 0: Successfully retrieved.
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				struct rte_event_timer_adapter_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully reset;
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_reset(
+				struct rte_event_timer_adapter *adapter);
+
+/**
  * @warning
  * @b EXPERIMENTAL: this structure may change without prior notice
  *
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 6/9] eventtimer: add support for meson build system
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                             ` (4 preceding siblings ...)
  2018-04-02 19:39           ` [PATCH v9 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
@ 2018-04-02 19:39           ` Erik Gabriel Carrillo
  2018-04-02 19:39           ` [PATCH v9 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
                             ` (4 subsequent siblings)
  10 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-02 19:39 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 config/rte_config.h             | 1 +
 lib/librte_eventdev/meson.build | 9 ++++++---
 lib/meson.build                 | 3 ++-
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/config/rte_config.h b/config/rte_config.h
index 72c0aa2..117c19f 100644
--- a/config/rte_config.h
+++ b/config/rte_config.h
@@ -55,6 +55,7 @@
 /* eventdev defines */
 #define RTE_EVENT_MAX_DEVS 16
 #define RTE_EVENT_MAX_QUEUES_PER_DEV 64
+#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 32
 
 /* ip_fragmentation defines */
 #define RTE_LIBRTE_IP_FRAG_MAX_FRAG 4
diff --git a/lib/librte_eventdev/meson.build b/lib/librte_eventdev/meson.build
index e1e22a5..232b870 100644
--- a/lib/librte_eventdev/meson.build
+++ b/lib/librte_eventdev/meson.build
@@ -5,11 +5,14 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_eventdev.c',
 		'rte_event_ring.c',
-		'rte_event_eth_rx_adapter.c')
+		'rte_event_eth_rx_adapter.c',
+		'rte_event_timer_adapter.c')
 headers = files('rte_eventdev.h',
 		'rte_eventdev_pmd.h',
 		'rte_eventdev_pmd_pci.h',
 		'rte_eventdev_pmd_vdev.h',
 		'rte_event_ring.h',
-		'rte_event_eth_rx_adapter.h')
-deps += ['ring', 'ethdev', 'hash']
+		'rte_event_eth_rx_adapter.h',
+		'rte_event_timer_adapter.h',
+		'rte_event_timer_adapter_pmd.h')
+deps += ['ring', 'ethdev', 'hash', 'mempool', 'timer']
diff --git a/lib/meson.build b/lib/meson.build
index ef61591..b1ad35f 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -13,13 +13,14 @@ libraries = [ 'compat', # just a header, used for versioning
 	'metrics', # bitrate/latency stats depends on this
 	'hash',    # efd depends on this
 	'kvargs',  # cryptodev depends on this
+	'timer',   # eventdev depends on this
 	'acl', 'bbdev', 'bitratestats', 'cfgfile',
 	'cmdline', 'cryptodev',
 	'distributor', 'efd', 'eventdev',
 	'gro', 'gso', 'ip_frag', 'jobstats',
 	'kni', 'latencystats', 'lpm', 'member',
 	'meter', 'power', 'pdump',
-	'reorder', 'sched', 'security', 'timer', 'vhost',
+	'reorder', 'sched', 'security', 'vhost',
 	# add pkt framework libs which use other libs from above
 	'port', 'table', 'pipeline',
 	# flow_classify lib depends on pkt framework table lib
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 7/9] test: add event timer adapter auto-test
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                             ` (5 preceding siblings ...)
  2018-04-02 19:39           ` [PATCH v9 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
@ 2018-04-02 19:39           ` Erik Gabriel Carrillo
  2018-04-03  9:52             ` Pavan Nikhilesh
  2018-04-02 19:39           ` [PATCH v9 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
                             ` (3 subsequent siblings)
  10 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-02 19:39 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 test/test/Makefile                   |    1 +
 test/test/test_event_timer_adapter.c | 1831 ++++++++++++++++++++++++++++++++++
 2 files changed, 1832 insertions(+)
 create mode 100644 test/test/test_event_timer_adapter.c

diff --git a/test/test/Makefile b/test/test/Makefile
index a88cc38..c9c007c9 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -185,6 +185,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
 SRCS-y += test_eventdev.c
 SRCS-y += test_event_ring.c
 SRCS-y += test_event_eth_rx_adapter.c
+SRCS-y += test_event_timer_adapter.c
 endif
 
 ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y)
diff --git a/test/test/test_event_timer_adapter.c b/test/test/test_event_timer_adapter.c
new file mode 100644
index 0000000..9afe031
--- /dev/null
+++ b/test/test/test_event_timer_adapter.c
@@ -0,0 +1,1831 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc
+ * Copyright(c) 2017-2018 Intel Corporation.
+ */
+
+#include <rte_atomic.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_debug.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_eventdev.h>
+#include <rte_event_timer_adapter.h>
+#include <rte_mempool.h>
+#include <rte_launch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_random.h>
+#include <rte_bus_vdev.h>
+#include <rte_service.h>
+#include <stdbool.h>
+
+#include "test.h"
+
+/* 4K timers corresponds to sw evdev max inflight events */
+#define MAX_TIMERS  (4 * 1024)
+#define BKT_TCK_NSEC
+
+#define NSECPERSEC 1E9
+#define BATCH_SIZE 16
+/* Both the app lcore and adapter ports are linked to this queue */
+#define TEST_QUEUE_ID 0
+/* Port the application dequeues from */
+#define TEST_PORT_ID 0
+#define TEST_ADAPTER_ID 0
+
+/* Handle log statements in same manner as test macros */
+#define LOG_DBG(...)	RTE_LOG(DEBUG, EAL, __VA_ARGS__)
+
+static int evdev;
+static struct rte_event_timer_adapter *timdev;
+static struct rte_mempool *eventdev_test_mempool;
+static struct rte_ring *timer_producer_ring;
+static uint64_t global_bkt_tck_ns;
+static volatile uint8_t arm_done;
+
+static bool using_services;
+static uint32_t test_lcore1;
+static uint32_t test_lcore2;
+static uint32_t test_lcore3;
+static uint32_t sw_evdev_slcore;
+static uint32_t sw_adptr_slcore;
+
+static inline void
+devconf_set_default_sane_values(struct rte_event_dev_config *dev_conf,
+		struct rte_event_dev_info *info)
+{
+	memset(dev_conf, 0, sizeof(struct rte_event_dev_config));
+	dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns;
+	dev_conf->nb_event_ports = 1;
+	dev_conf->nb_event_queues = 1;
+	dev_conf->nb_event_queue_flows = info->max_event_queue_flows;
+	dev_conf->nb_event_port_dequeue_depth =
+		info->max_event_port_dequeue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+		info->max_event_port_enqueue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+		info->max_event_port_enqueue_depth;
+	dev_conf->nb_events_limit =
+		info->max_num_events;
+}
+
+static inline int
+eventdev_setup(void)
+{
+	int ret;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_dev_info info;
+	uint32_t service_id;
+
+	ret = rte_event_dev_info_get(evdev, &info);
+	TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info");
+	TEST_ASSERT(info.max_num_events >= (int32_t)MAX_TIMERS,
+			"ERROR max_num_events=%d < max_events=%d",
+			info.max_num_events, MAX_TIMERS);
+
+	devconf_set_default_sane_values(&dev_conf, &info);
+	ret = rte_event_dev_configure(evdev, &dev_conf);
+	TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev");
+
+	ret = rte_event_queue_setup(evdev, 0, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", 0);
+
+	/* Configure event port */
+	ret = rte_event_port_setup(evdev, 0, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup port=%d", 0);
+	ret = rte_event_port_link(evdev, 0, NULL, NULL, 0);
+	TEST_ASSERT(ret >= 0, "Failed to link all queues port=%d", 0);
+
+	/* If this is a software event device, map and start its service */
+	if (rte_event_dev_service_id_get(evdev, &service_id) == 0) {
+		TEST_ASSERT_SUCCESS(rte_service_lcore_add(sw_evdev_slcore),
+				"Failed to add service core");
+		TEST_ASSERT_SUCCESS(rte_service_lcore_start(
+				sw_evdev_slcore),
+				"Failed to start service core");
+		TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(
+				service_id, sw_evdev_slcore, 1),
+				"Failed to map evdev service");
+		TEST_ASSERT_SUCCESS(rte_service_runstate_set(
+				service_id, 1),
+				"Failed to start evdev service");
+	}
+
+	ret = rte_event_dev_start(evdev);
+	TEST_ASSERT_SUCCESS(ret, "Failed to start device");
+
+	return TEST_SUCCESS;
+}
+
+static int
+testsuite_setup(void)
+{
+	/* Some of the multithreaded tests require 3 other lcores to run */
+	unsigned int required_lcore_count = 4;
+	uint32_t service_id;
+
+	/* To make it easier to map services later if needed, just reset
+	 * service core state.
+	 */
+	(void) rte_service_lcore_reset_all();
+
+	if (!rte_event_dev_count()) {
+		/* If there is no hardware eventdev, or no software vdev was
+		 * specified on the command line, create an instance of
+		 * event_sw.
+		 */
+		LOG_DBG("Failed to find a valid event device... testing with"
+			" event_sw device\n");
+		TEST_ASSERT_SUCCESS(rte_vdev_init("event_sw0", NULL),
+					"Error creating eventdev");
+		evdev = rte_event_dev_get_dev_id("event_sw0");
+	}
+
+	if (rte_event_dev_service_id_get(evdev, &service_id) == 0) {
+		/* A software event device will use a software event timer
+		 * adapter as well. 2 more cores required to convert to
+		 * service cores.
+		 */
+		required_lcore_count += 2;
+		using_services = true;
+	}
+
+	if (rte_lcore_count() < required_lcore_count) {
+		printf("%d lcores needed to run tests", required_lcore_count);
+		return TEST_FAILED;
+	}
+
+	/* Assign lcores for various tasks */
+	test_lcore1 = rte_get_next_lcore(-1, 1, 0);
+	test_lcore2 = rte_get_next_lcore(test_lcore1, 1, 0);
+	test_lcore3 = rte_get_next_lcore(test_lcore2, 1, 0);
+	if (using_services) {
+		sw_evdev_slcore = rte_get_next_lcore(test_lcore3, 1, 0);
+		sw_adptr_slcore = rte_get_next_lcore(sw_evdev_slcore, 1, 0);
+	}
+
+	return eventdev_setup();
+}
+
+static void
+testsuite_teardown(void)
+{
+	rte_event_dev_stop(evdev);
+	rte_event_dev_close(evdev);
+}
+
+static int
+setup_adapter_service(struct rte_event_timer_adapter *adptr)
+{
+	uint32_t adapter_service_id;
+	int ret;
+
+	/* retrieve service ids */
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(adptr,
+			&adapter_service_id), "Failed to get event timer "
+			"adapter service id");
+	/* add a service core and start it */
+	ret = rte_service_lcore_add(sw_adptr_slcore);
+	TEST_ASSERT(ret == 0 || ret == -EALREADY,
+			"Failed to add service core");
+	ret = rte_service_lcore_start(sw_adptr_slcore);
+	TEST_ASSERT(ret == 0 || ret == -EALREADY,
+			"Failed to start service core");
+
+	/* map services to it */
+	TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(adapter_service_id,
+			sw_adptr_slcore, 1),
+			"Failed to map adapter service");
+
+	/* set services to running */
+	TEST_ASSERT_SUCCESS(rte_service_runstate_set(adapter_service_id, 1),
+			"Failed to start event timer adapter service");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		  void *conf_arg)
+{
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_dev_info info;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	uint32_t started;
+	static int port_allocated;
+	static uint8_t port_id;
+	int ret;
+
+	if (port_allocated) {
+		*event_port_id = port_id;
+		return 0;
+	}
+
+	RTE_SET_USED(id);
+
+	ret = rte_event_dev_attr_get(event_dev_id, RTE_EVENT_DEV_ATTR_STARTED,
+				     &started);
+	if (ret < 0)
+		return ret;
+
+	if (started)
+		rte_event_dev_stop(event_dev_id);
+
+	ret = rte_event_dev_info_get(evdev, &info);
+	if (ret < 0)
+		return ret;
+
+	devconf_set_default_sane_values(&dev_conf, &info);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports++;
+
+	ret = rte_event_dev_configure(event_dev_id, &dev_conf);
+	if (ret < 0) {
+		if (started)
+			rte_event_dev_start(event_dev_id);
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(event_dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(event_dev_id, port_id, port_conf);
+	if (ret < 0)
+		return ret;
+
+	*event_port_id = port_id;
+
+	if (started)
+		rte_event_dev_start(event_dev_id);
+
+	/* Reuse this port number next time this is called */
+	port_allocated = 1;
+
+	return 0;
+}
+
+static int
+_timdev_setup(uint64_t max_tmo_ns, uint64_t bkt_tck_ns)
+{
+	struct rte_event_timer_adapter_conf config = {
+		.event_dev_id = evdev,
+		.timer_adapter_id = TEST_ADAPTER_ID,
+		.timer_tick_ns = bkt_tck_ns,
+		.max_tmo_ns = max_tmo_ns,
+		.nb_timers = MAX_TIMERS * 10,
+	};
+	uint32_t caps = 0;
+	const char *pool_name = "timdev_test_pool";
+
+	global_bkt_tck_ns = bkt_tck_ns;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_caps_get(evdev, &caps),
+				"failed to get adapter capabilities");
+	if (!(caps & RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+		timdev = rte_event_timer_adapter_create_ext(&config,
+							    test_port_conf_cb,
+							    NULL);
+		setup_adapter_service(timdev);
+		using_services = true;
+	} else
+		timdev = rte_event_timer_adapter_create(&config);
+
+	TEST_ASSERT_NOT_NULL(timdev,
+			"failed to create event timer ring");
+
+	TEST_ASSERT_EQUAL(rte_event_timer_adapter_start(timdev), 0,
+			"failed to Start event timer adapter");
+
+	/* Create event timer mempool */
+	eventdev_test_mempool = rte_mempool_create(pool_name,
+			MAX_TIMERS * 2,
+			sizeof(struct rte_event_timer), /* element size*/
+			0, /* cache size*/
+			0, NULL, NULL, NULL, NULL,
+			rte_socket_id(), 0);
+	if (!eventdev_test_mempool) {
+		printf("ERROR creating mempool\n");
+		return TEST_FAILED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+timdev_setup_usec(void)
+{
+	return using_services ?
+		/* Max timeout is 10,000us and bucket interval is 100us */
+		_timdev_setup(1E7, 1E5) :
+		/* Max timeout is 100us and bucket interval is 1us */
+		_timdev_setup(1E5, 1E3);
+}
+
+static int
+timdev_setup_usec_multicore(void)
+{
+	return using_services ?
+		/* Max timeout is 10,000us and bucket interval is 100us */
+		_timdev_setup(1E7, 1E5) :
+		/* Max timeout is 100us and bucket interval is 1us */
+		_timdev_setup(1E5, 1E3);
+}
+
+static int
+timdev_setup_msec(void)
+{
+	/* Max timeout is 2 mins, and bucket interval is 100 ms */
+	return _timdev_setup(180 * NSECPERSEC, NSECPERSEC / 10);
+}
+
+static int
+timdev_setup_sec(void)
+{
+	/* Max timeout is 100sec and bucket interval is 1sec */
+	return _timdev_setup(1E11, 1E9);
+}
+
+static int
+timdev_setup_sec_multicore(void)
+{
+	/* Max timeout is 100sec and bucket interval is 1sec */
+	return _timdev_setup(1E11, 1E9);
+}
+
+static void
+timdev_teardown(void)
+{
+	rte_event_timer_adapter_stop(timdev);
+	rte_event_timer_adapter_free(timdev);
+
+	rte_mempool_free(eventdev_test_mempool);
+}
+
+static inline int
+test_timer_state(void)
+{
+	struct rte_event_timer *ev_tim;
+	struct rte_event ev;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&ev_tim);
+	*ev_tim = tim;
+	ev_tim->ev.event_ptr = ev_tim;
+	ev_tim->timeout_ticks = 120;
+
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 0,
+			"Armed timer exceeding max_timeout.");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ERROR_TOOLATE,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_ERROR_TOOLATE, ev_tim->state);
+
+	ev_tim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	ev_tim->timeout_ticks = 10;
+
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+			"Failed to arm timer with proper timeout.");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_ARMED, ev_tim->state);
+
+	if (!using_services)
+		rte_delay_us(20);
+	else
+		rte_delay_us(1000 + 200);
+	TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1, 0), 1,
+			"Armed timer failed to trigger.");
+
+	ev_tim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	ev_tim->timeout_ticks = 90;
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+			"Failed to arm timer with proper timeout.");
+	TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(timdev, &ev_tim, 1),
+			1, "Failed to cancel armed timer");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_CANCELED,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_CANCELED, ev_tim->state);
+
+	rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+_arm_timers(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers; i++) {
+
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+_wait_timer_triggers(uint64_t wait_sec, uint64_t arm_count,
+		uint64_t cancel_count)
+{
+	uint8_t valid_event;
+	uint64_t events = 0;
+	uint64_t wait_start, max_wait;
+	struct rte_event ev;
+
+	max_wait = rte_get_timer_hz() * wait_sec;
+	wait_start = rte_get_timer_cycles();
+	while (1) {
+		if (rte_get_timer_cycles() - wait_start > max_wait) {
+			if (events + cancel_count != arm_count)
+				TEST_ASSERT_SUCCESS(max_wait,
+					"Max time limit for timers exceeded.");
+			break;
+		}
+
+		valid_event = rte_event_dequeue_burst(evdev, 0, &ev, 1, 0);
+		if (!valid_event)
+			continue;
+
+		rte_mempool_put(eventdev_test_mempool, ev.event_ptr);
+		events++;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm(void)
+{
+	TEST_ASSERT_SUCCESS(_arm_timers(20, MAX_TIMERS),
+			"Failed to arm timers");
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS, 0),
+			"Timer triggered count doesn't match arm count");
+	return TEST_SUCCESS;
+}
+
+static int
+_arm_wrapper(void *arg)
+{
+	RTE_SET_USED(arg);
+
+	TEST_ASSERT_SUCCESS(_arm_timers(20, MAX_TIMERS),
+			"Failed to arm timers");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_multicore(void)
+{
+
+	uint32_t lcore_1 = rte_get_next_lcore(-1, 1, 0);
+	uint32_t lcore_2 = rte_get_next_lcore(lcore_1, 1, 0);
+
+	rte_eal_remote_launch(_arm_wrapper, NULL, lcore_1);
+	rte_eal_remote_launch(_arm_wrapper, NULL, lcore_2);
+
+	rte_eal_mp_wait_lcore();
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS * 2, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+#define MAX_BURST 16
+static inline int
+_arm_timers_burst(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	int j;
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers / MAX_BURST; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get_bulk(
+				eventdev_test_mempool,
+				(void **)ev_tim, MAX_BURST),
+				"mempool alloc failed");
+
+		for (j = 0; j < MAX_BURST; j++) {
+			*ev_tim[j] = tim;
+			ev_tim[j]->ev.event_ptr = ev_tim[j];
+		}
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_tmo_tick_burst(timdev,
+				ev_tim, tim.timeout_ticks, MAX_BURST),
+				MAX_BURST, "Failed to arm timer %d", rte_errno);
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_burst(void)
+{
+	TEST_ASSERT_SUCCESS(_arm_timers_burst(20, MAX_TIMERS),
+			"Failed to arm timers");
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_arm_wrapper_burst(void *arg)
+{
+	RTE_SET_USED(arg);
+
+	TEST_ASSERT_SUCCESS(_arm_timers_burst(20, MAX_TIMERS),
+			"Failed to arm timers");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_burst_multicore(void)
+{
+	rte_eal_remote_launch(_arm_wrapper_burst, NULL, test_lcore1);
+	rte_eal_remote_launch(_arm_wrapper_burst, NULL, test_lcore2);
+
+	rte_eal_mp_wait_lcore();
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS * 2, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel(void)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 20,
+	};
+
+	for (i = 0; i < MAX_TIMERS; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		rte_delay_us(100 + (i % 5000));
+
+		TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(timdev,
+					&ev_tim, 1), 1,
+				"Failed to cancel event timer %d", rte_errno);
+		rte_mempool_put(eventdev_test_mempool, ev_tim);
+	}
+
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+				MAX_TIMERS),
+		"Timer triggered count doesn't match arm, cancel count");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+				  "Failed to arm event timer");
+
+		while (rte_ring_enqueue(timer_producer_ring, ev_tim) != 0)
+			;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer_burst(uint64_t timeout_tcks, uint64_t timers)
+{
+
+	uint64_t i;
+	int j;
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+	int arm_count = 0;
+
+	for (i = 0; i < timers / MAX_BURST; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get_bulk(
+				eventdev_test_mempool,
+				(void **)ev_tim, MAX_BURST),
+				"mempool alloc failed");
+
+		for (j = 0; j < MAX_BURST; j++) {
+			*ev_tim[j] = tim;
+			ev_tim[j]->ev.event_ptr = ev_tim[j];
+		}
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_tmo_tick_burst(timdev,
+				ev_tim, tim.timeout_ticks, MAX_BURST),
+				MAX_BURST, "Failed to arm timer %d", rte_errno);
+
+		for (j = 0; j < MAX_BURST; j++)
+			TEST_ASSERT_EQUAL(ev_tim[j]->state,
+					  RTE_EVENT_TIMER_ARMED,
+					  "Event timer not armed, state = %d",
+					  ev_tim[j]->state);
+
+		while (rte_ring_enqueue_bulk(timer_producer_ring,
+				(void **)ev_tim, MAX_BURST, NULL) == 0)
+			;
+
+		arm_count += MAX_BURST;
+	}
+
+	TEST_ASSERT_EQUAL(arm_count, MAX_TIMERS,
+			  "Failed to arm expected number of event timers");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer_wrapper(void *args)
+{
+	RTE_SET_USED(args);
+
+	return _cancel_producer(20, MAX_TIMERS);
+}
+
+static int
+_cancel_producer_burst_wrapper(void *args)
+{
+	RTE_SET_USED(args);
+
+	return _cancel_producer_burst(100, MAX_TIMERS);
+}
+
+static int
+_cancel_thread(void *args)
+{
+	RTE_SET_USED(args);
+	unsigned int count = rte_ring_count(timer_producer_ring);
+	struct rte_event_timer *ev_tim = NULL;
+	uint64_t cancel_count = 0;
+	uint16_t ret;
+
+	while (!arm_done || count) {
+		if (rte_ring_dequeue(timer_producer_ring, (void **)&ev_tim)) {
+			count = rte_ring_count(timer_producer_ring);
+			continue;
+		}
+
+		ret = rte_event_timer_cancel_burst(timdev, &ev_tim, 1);
+		TEST_ASSERT_EQUAL(ret, 1, "Failed to cancel timer");
+		rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+		count = rte_ring_count(timer_producer_ring);
+		cancel_count++;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_burst_thread(void *args)
+{
+	RTE_SET_USED(args);
+
+	int ret, i, n;
+	unsigned int count = rte_ring_count(timer_producer_ring);
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	uint64_t cancel_count = 0;
+
+	while (!arm_done || count) {
+		n = rte_ring_dequeue_burst(timer_producer_ring,
+				(void **)ev_tim, MAX_BURST, &count);
+		if (!n)
+			continue;
+
+		for (i = 0; i < n; i++)
+			TEST_ASSERT_EQUAL(ev_tim[i]->state,
+					  RTE_EVENT_TIMER_ARMED,
+					  "Event timer not armed, state = %d",
+					  ev_tim[i]->state);
+
+		ret = rte_event_timer_cancel_burst(timdev, ev_tim, n);
+		TEST_ASSERT_EQUAL(n, ret, "Failed to cancel complete burst of "
+				  "event timers");
+		rte_mempool_put_bulk(eventdev_test_mempool, (void **)ev_tim,
+				ret);
+
+		cancel_count += ret;
+	}
+
+	TEST_ASSERT_EQUAL(cancel_count, MAX_TIMERS,
+			  "Failed to cancel expected number of timers: "
+			  "expected = %d, cancel_count = %"PRIu64"\n",
+			  MAX_TIMERS, cancel_count);
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_multicore(void)
+{
+	arm_done = 0;
+	timer_producer_ring = rte_ring_create("timer_cancel_queue",
+			MAX_TIMERS * 2, rte_socket_id(), 0);
+	TEST_ASSERT_NOT_NULL(timer_producer_ring,
+			"Unable to reserve memory for ring");
+
+	rte_eal_remote_launch(_cancel_thread, NULL, test_lcore3);
+	rte_eal_remote_launch(_cancel_producer_wrapper, NULL, test_lcore1);
+	rte_eal_remote_launch(_cancel_producer_wrapper, NULL, test_lcore2);
+
+	rte_eal_wait_lcore(test_lcore1);
+	rte_eal_wait_lcore(test_lcore2);
+	arm_done = 1;
+	rte_eal_wait_lcore(test_lcore3);
+	rte_ring_free(timer_producer_ring);
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS * 2,
+			MAX_TIMERS * 2),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_burst_multicore(void)
+{
+	arm_done = 0;
+	timer_producer_ring = rte_ring_create("timer_cancel_queue",
+			MAX_TIMERS * 2, rte_socket_id(), 0);
+	TEST_ASSERT_NOT_NULL(timer_producer_ring,
+			"Unable to reserve memory for ring");
+
+	rte_eal_remote_launch(_cancel_burst_thread, NULL, test_lcore2);
+	rte_eal_remote_launch(_cancel_producer_burst_wrapper, NULL,
+			test_lcore1);
+
+	rte_eal_wait_lcore(test_lcore1);
+	arm_done = 1;
+	rte_eal_wait_lcore(test_lcore2);
+	rte_ring_free(timer_producer_ring);
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+			MAX_TIMERS),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_random(void)
+{
+	uint64_t i;
+	uint64_t events_canceled = 0;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 20,
+	};
+
+	for (i = 0; i < MAX_TIMERS; i++) {
+
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		if (rte_rand() & 1) {
+			rte_delay_us(100 + (i % 5000));
+			TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(
+						timdev,
+						&ev_tim, 1), 1,
+				"Failed to cancel event timer %d", rte_errno);
+			rte_mempool_put(eventdev_test_mempool, ev_tim);
+			events_canceled++;
+		}
+	}
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+				events_canceled),
+		       "Timer triggered count doesn't match arm, cancel count");
+
+	return TEST_SUCCESS;
+}
+
+/* Check that the adapter can be created correctly */
+static int
+adapter_create(void)
+{
+	int adapter_id = 0;
+	struct rte_event_timer_adapter *adapter, *adapter2;
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev + 1,  // invalid event dev id
+		.timer_adapter_id = adapter_id,
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = MAX_TIMERS,
+		.flags = 0,
+	};
+	uint32_t caps = 0;
+
+	/* Test invalid conf */
+	adapter = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapter, "Created adapter with invalid "
+			"event device id");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Incorrect errno value for "
+			"invalid event device id");
+
+	/* Test valid conf */
+	conf.event_dev_id = evdev;
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_caps_get(evdev, &caps),
+			"failed to get adapter capabilities");
+	if (!(caps & RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT))
+		adapter = rte_event_timer_adapter_create_ext(&conf,
+				test_port_conf_cb,
+				NULL);
+	else
+		adapter = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NOT_NULL(adapter, "Failed to create adapter with valid "
+			"configuration");
+
+	/* Test existing id */
+	adapter2 = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapter2, "Created adapter with in-use id");
+	TEST_ASSERT(rte_errno == EEXIST, "Incorrect errno value for existing "
+			"id");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapter),
+			"Failed to free adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+
+/* Test that adapter can be freed correctly. */
+static int
+adapter_free(void)
+{
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stop(timdev),
+			"Failed to stop adapter");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(timdev),
+			"Failed to free valid adapter");
+
+	/* Test free of already freed adapter */
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_free(timdev),
+			"Freed adapter that was already freed");
+
+	/* Test free of null adapter */
+	timdev = NULL;
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_free(timdev),
+			"Freed null adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter info can be retrieved and is correct. */
+static int
+adapter_get_info(void)
+{
+	struct rte_event_timer_adapter_info info;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_get_info(timdev, &info),
+			"Failed to get adapter info");
+
+	if (using_services)
+		TEST_ASSERT_EQUAL(info.event_dev_port_id, 1,
+				"Expected port id = 1, got port id = %d",
+				info.event_dev_port_id);
+
+	return TEST_SUCCESS;
+}
+
+/* Test adapter lookup via adapter ID. */
+static int
+adapter_lookup(void)
+{
+	struct rte_event_timer_adapter *adapter;
+
+	adapter = rte_event_timer_adapter_lookup(TEST_ADAPTER_ID);
+	TEST_ASSERT_NOT_NULL(adapter, "Failed to lookup adapter");
+
+	return TEST_SUCCESS;
+}
+
+static int
+adapter_start(void)
+{
+	TEST_ASSERT_SUCCESS(_timdev_setup(180 * NSECPERSEC,
+			NSECPERSEC / 10),
+			"Failed to start adapter");
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_start(timdev),
+			"Failed to repeatedly start adapter");
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter stops correctly. */
+static int
+adapter_stop(void)
+{
+	struct rte_event_timer_adapter *l_adapter = NULL;
+
+	/* Test adapter stop */
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stop(timdev),
+			"Failed to stop event adapter");
+
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_stop(l_adapter),
+			"Erroneously stopped null event adapter");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(timdev),
+			"Failed to free adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+/* Test increment and reset of ev_enq_count stat */
+static int
+stat_inc_reset_ev_enq(void)
+{
+	int ret, i, n;
+	int num_evtims = MAX_TIMERS;
+	struct rte_event_timer *evtims[num_evtims];
+	struct rte_event evs[BATCH_SIZE];
+	struct rte_event_timer_adapter_stats stats;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
+				   num_evtims);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
+			  ret);
+
+	for (i = 0; i < num_evtims; i++) {
+		*evtims[i] = init_tim;
+		evtims[i]->ev.event_ptr = evtims[i];
+	}
+
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0, "Stats not clear at "
+			  "startup");
+
+	/* Test with the max value for the adapter */
+	ret = rte_event_timer_arm_burst(timdev, evtims, num_evtims);
+	TEST_ASSERT_EQUAL(ret, num_evtims,
+			  "Failed to arm all event timers: attempted = %d, "
+			  "succeeded = %d, rte_errno = %s",
+			  num_evtims, ret, rte_strerror(rte_errno));
+
+	rte_delay_ms(1000);
+
+#define MAX_TRIES num_evtims
+	int sum = 0;
+	int tries = 0;
+	bool done = false;
+	while (!done) {
+		sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
+					       RTE_DIM(evs), 10);
+		if (sum >= num_evtims || ++tries >= MAX_TRIES)
+			done = true;
+
+		rte_delay_ms(10);
+	}
+
+	TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
+			  "got %d", num_evtims, sum);
+
+	TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");
+
+	rte_delay_ms(100);
+
+	/* Make sure the eventdev is still empty */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
+				      10);
+
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
+			  "events from event device");
+
+	/* Check stats again */
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, num_evtims,
+			  "Expected enqueue stat = %d; got %d", num_evtims,
+			  (int)stats.ev_enq_count);
+
+	/* Reset and check again */
+	ret = rte_event_timer_adapter_stats_reset(timdev);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to reset stats");
+
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0,
+			  "Expected enqueue stat = %d; got %d", 0,
+			  (int)stats.ev_enq_count);
+
+	rte_mempool_put_bulk(eventdev_test_mempool, (void **)evtims,
+			     num_evtims);
+
+	return TEST_SUCCESS;
+}
+
+/* Test various cases in arming timers */
+static int
+event_timer_arm(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+
+	/* Test single timer arm succeeds */
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event timer "
+			  "in incorrect state");
+
+	/* Test arm of armed timer fails */
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "expected return value from "
+			  "rte_event_timer_arm_burst: 0, got: %d", ret);
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after arming already armed timer");
+
+	/* Let timer expire */
+	rte_delay_ms(1000);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* This test checks that repeated references to the same event timer in the
+ * arm request work as expected; only the first one through should succeed.
+ */
+static int
+event_timer_arm_double(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+
+	struct rte_event_timer *evtim_arr[] = {evtim, evtim};
+	ret = rte_event_timer_arm_burst(adapter, evtim_arr, RTE_DIM(evtim_arr));
+	TEST_ASSERT_EQUAL(ret, 1, "Unexpected return value from "
+			  "rte_event_timer_arm_burst");
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after double-arm");
+
+	/* Let timer expire */
+	rte_delay_ms(600);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number of expiry events - "
+			  "expected: 1, actual: %d", n);
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Test the timer expiry event is generated at the expected time.  */
+static int
+event_timer_arm_expiry(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event_timer *evtim2 = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up an event timer */
+	*evtim = init_tim;
+	evtim->timeout_ticks = 30,	// expire in 3 secs
+	evtim->ev.event_ptr = evtim;
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event "
+			  "timer in incorrect state");
+
+	rte_delay_ms(2999);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event");
+
+	/* Delay 100 ms to account for the adapter tick window - should let us
+	 * dequeue one event
+	 */
+	rte_delay_ms(100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number (%d) of timer "
+			  "expiry events", n);
+	TEST_ASSERT_EQUAL(evs[0].event_type, RTE_EVENT_TYPE_TIMER,
+			  "Dequeued unexpected type of event");
+
+	/* Check that we recover the original event timer and then free it */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+	rte_mempool_put(eventdev_test_mempool, evtim2);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that rearming a timer works as expected. */
+static int
+event_timer_arm_rearm(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event_timer *evtim2 = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type = RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->timeout_ticks = 1;  // expire in 0.1 sec
+	evtim->ev.event_ptr = evtim;
+
+	/* Arm it */
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+
+	/* Add 100ms to account for the adapter tick window */
+	rte_delay_ms(100 + 100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	/* Recover the timer through the event that was dequeued. */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+
+	/* Need to reset state in case implementation can't do it */
+	evtim2->state = RTE_EVENT_TIMER_NOT_ARMED;
+
+	/* Rearm it */
+	ret = rte_event_timer_arm_burst(timdev, &evtim2, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+
+	/* Add 100ms to account for the adapter tick window */
+	rte_delay_ms(100 + 100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	/* Free it */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+	rte_mempool_put(eventdev_test_mempool, evtim2);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that the adapter handles the max specified number of timers as
+ * expected.
+ */
+static int
+event_timer_arm_max(void)
+{
+	int ret, i, n;
+	int num_evtims = MAX_TIMERS;
+	struct rte_event_timer *evtims[num_evtims];
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
+				   num_evtims);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
+			  ret);
+
+	for (i = 0; i < num_evtims; i++) {
+		*evtims[i] = init_tim;
+		evtims[i]->ev.event_ptr = evtims[i];
+	}
+
+	/* Test with the max value for the adapter */
+	ret = rte_event_timer_arm_burst(timdev, evtims, num_evtims);
+	TEST_ASSERT_EQUAL(ret, num_evtims,
+			  "Failed to arm all event timers: attempted = %d, "
+			  "succeeded = %d, rte_errno = %s",
+			  num_evtims, ret, rte_strerror(rte_errno));
+
+	rte_delay_ms(1000);
+
+#define MAX_TRIES num_evtims
+	int sum = 0;
+	int tries = 0;
+	bool done = false;
+	while (!done) {
+		sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
+					       RTE_DIM(evs), 10);
+		if (sum >= num_evtims || ++tries >= MAX_TRIES)
+			done = true;
+
+		rte_delay_ms(10);
+	}
+
+	TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
+			  "got %d", num_evtims, sum);
+
+	TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");
+
+	rte_delay_ms(100);
+
+	/* Make sure the eventdev is still empty */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
+				    10);
+
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
+			  "events from event device");
+
+	rte_mempool_put_bulk(eventdev_test_mempool, (void **)evtims,
+			     num_evtims);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that creating an event timer with incorrect event sched type fails. */
+static int
+event_timer_arm_invalid_sched_type(void)
+{
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	if (!using_services)
+		return -ENOTSUP;
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_PARALLEL; // bad sched type
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "sched type, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid queue");
+
+	rte_mempool_put(eventdev_test_mempool, &evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that creating an event timer with a timeout value that is too small or
+ * too big fails.
+ */
+static int
+event_timer_arm_invalid_timeout(void)
+{
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 0;  // timeout too small
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "timeout, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid timeout");
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOEARLY,
+			  "Unexpected event timer state");
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 1801;  // timeout too big
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "timeout, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid timeout");
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOLATE,
+			  "Unexpected event timer state");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+static int
+event_timer_cancel(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Check that cancelling an uninited timer fails */
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling "
+			  "uninited timer");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after "
+			  "cancelling uninited timer");
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	/* Check that cancelling an inited but unarmed timer fails */
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling "
+			  "unarmed timer");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after "
+			  "cancelling unarmed timer");
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED,
+			  "evtim in incorrect state");
+
+	/* Delay 1 sec */
+	rte_delay_ms(1000);
+
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to cancel event_timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_CANCELED,
+			  "evtim in incorrect state");
+
+	rte_delay_ms(3000);
+
+	/* Make sure that no expiry event was generated */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+static int
+event_timer_cancel_double(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED,
+			  "timer in unexpected state");
+
+	/* Now, test that referencing the same timer twice in the same call
+	 * fails
+	 */
+	struct rte_event_timer *evtim_arr[] = {evtim, evtim};
+	ret = rte_event_timer_cancel_burst(adapter, evtim_arr,
+					   RTE_DIM(evtim_arr));
+
+	/* Two requests to cancel same timer, only one should succeed */
+	TEST_ASSERT_EQUAL(ret, 1, "Succeeded unexpectedly in canceling timer "
+			  "twice");
+
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after double-cancel: rte_errno = %d", rte_errno);
+
+	rte_delay_ms(3000);
+
+	/* Still make sure that no expiry event was generated */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that event timer adapter tick resolution works as expected by testing
+ * the number of adapter ticks that occur within a particular time interval.
+ */
+static int
+adapter_tick_resolution(void)
+{
+	struct rte_event_timer_adapter_stats stats;
+	uint64_t adapter_tick_count;
+
+	/* Only run this test in the software driver case */
+	if (!using_services)
+		return -ENOTSUP;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_reset(timdev),
+				"Failed to reset stats");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(timdev,
+			&stats), "Failed to get adapter stats");
+	TEST_ASSERT_EQUAL(stats.adapter_tick_count, 0, "Adapter tick count "
+			"not zeroed out");
+
+	/* Delay 1 second; should let at least 10 ticks occur with the default
+	 * adapter configuration used by this test.
+	 */
+	rte_delay_ms(1000);
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(timdev,
+			&stats), "Failed to get adapter stats");
+
+	adapter_tick_count = stats.adapter_tick_count;
+	TEST_ASSERT(adapter_tick_count >= 10 && adapter_tick_count <= 12,
+			"Expected 10-12 adapter ticks, got %"PRIu64"\n",
+			adapter_tick_count);
+
+	return TEST_SUCCESS;
+}
+
+static int
+adapter_create_max(void)
+{
+	int i;
+	uint32_t svc_start_count, svc_end_count;
+	struct rte_event_timer_adapter *adapters[
+					RTE_EVENT_TIMER_ADAPTER_NUM_MAX + 1];
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev,
+		// timer_adapter_id set in loop
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = MAX_TIMERS,
+		.flags = 0,
+	};
+
+	if (!using_services)
+		return -ENOTSUP;
+
+	svc_start_count = rte_service_get_count();
+
+	/* This test expects that there are sufficient service IDs available
+	 * to be allocated. I.e., RTE_EVENT_TIMER_ADAPTER_NUM_MAX may need to
+	 * be less than RTE_SERVICE_NUM_MAX if anything else uses a service
+	 * (the SW event device, for example).
+	 */
+	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) {
+		conf.timer_adapter_id = i;
+		adapters[i] = rte_event_timer_adapter_create_ext(&conf,
+				test_port_conf_cb, NULL);
+		TEST_ASSERT_NOT_NULL(adapters[i], "Failed to create adapter "
+				"%d", i);
+	}
+
+	conf.timer_adapter_id = i;
+	adapters[i] = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapters[i], "Created too many adapters");
+
+	/* Check that at least RTE_EVENT_TIMER_ADAPTER_NUM_MAX services
+	 * have been created
+	 */
+	svc_end_count = rte_service_get_count();
+	TEST_ASSERT_EQUAL(svc_end_count - svc_start_count,
+			RTE_EVENT_TIMER_ADAPTER_NUM_MAX,
+			"Failed to create expected number of services");
+
+	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++)
+		TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapters[i]),
+				"Failed to free adapter %d", i);
+
+	/* Check that service count is back to where it was at start */
+	svc_end_count = rte_service_get_count();
+	TEST_ASSERT_EQUAL(svc_start_count, svc_end_count, "Failed to release "
+			  "correct number of services");
+
+	return TEST_SUCCESS;
+}
+
+static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
+	.suite_name = "event timer functional test suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_state),
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_arm),
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_arm_burst),
+		TEST_CASE_ST(timdev_setup_sec, timdev_teardown,
+				test_timer_cancel),
+		TEST_CASE_ST(timdev_setup_sec, timdev_teardown,
+				test_timer_cancel_random),
+		TEST_CASE_ST(timdev_setup_usec_multicore, timdev_teardown,
+				test_timer_arm_multicore),
+		TEST_CASE_ST(timdev_setup_usec_multicore, timdev_teardown,
+				test_timer_arm_burst_multicore),
+		TEST_CASE_ST(timdev_setup_sec_multicore, timdev_teardown,
+				test_timer_cancel_multicore),
+		TEST_CASE_ST(timdev_setup_sec_multicore, timdev_teardown,
+				test_timer_cancel_burst_multicore),
+		TEST_CASE(adapter_create),
+		TEST_CASE_ST(timdev_setup_msec, NULL, adapter_free),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_get_info),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_lookup),
+		TEST_CASE_ST(NULL, timdev_teardown,
+				adapter_start),
+		TEST_CASE_ST(timdev_setup_msec, NULL,
+				adapter_stop),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				stat_inc_reset_ev_enq),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm_double),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm_expiry),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_rearm),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_max),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_invalid_sched_type),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_invalid_timeout),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_cancel),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_cancel_double),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_tick_resolution),
+		TEST_CASE(adapter_create_max),
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+static int
+test_event_timer_adapter_func(void)
+{
+	return unit_test_suite_runner(&event_timer_adptr_functional_testsuite);
+}
+
+REGISTER_TEST_COMMAND(event_timer_adapter_test, test_event_timer_adapter_func);
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 8/9] doc: add event timer adapter section to programmer's guide
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                             ` (6 preceding siblings ...)
  2018-04-02 19:39           ` [PATCH v9 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
@ 2018-04-02 19:39           ` Erik Gabriel Carrillo
  2018-04-03  0:00             ` Jerin Jacob
  2018-04-02 19:39           ` [PATCH v9 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
                             ` (2 subsequent siblings)
  10 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-02 19:39 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
---
 doc/guides/prog_guide/event_timer_adapter.rst | 297 ++++++++++++++++++++++++++
 doc/guides/prog_guide/index.rst               |   1 +
 2 files changed, 298 insertions(+)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst

diff --git a/doc/guides/prog_guide/event_timer_adapter.rst b/doc/guides/prog_guide/event_timer_adapter.rst
new file mode 100644
index 0000000..416f1ff
--- /dev/null
+++ b/doc/guides/prog_guide/event_timer_adapter.rst
@@ -0,0 +1,297 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(c) 2017 Intel Corporation. All rights reserved.
+
+Event Timer Adapter Library
+=================================
+
+The DPDK
+`Event Device library <http://dpdk.org/doc/guides/prog_guide/eventdev.html>`_
+introduces an event driven programming model which presents applications with
+an alternative to the polling model traditionally used in DPDK
+applications. Event devices can be coupled with arbitrary components to provide
+new event sources by using **event adapters**. The Event Timer Adapter is one
+such adapter; it bridges event devices and timer mechanisms.
+
+The Event Timer Adapter library extends the event driven model
+by introducing a :ref:`new type of event <timer_expiry_event>` that represents
+a timer expiration, and providing an API with which adapters can be created or
+destroyed, and :ref:`event timers <event_timer>` can be armed and canceled.
+
+The Event Timer Adapter library is designed to interface with hardware or
+software implementations of the timer mechanism; it will query an eventdev PMD
+to determine which implementation should be used.  The default software
+implementation manages timers using the DPDK
+`Timer library <http://dpdk.org/doc/guides/prog_guide/timer_lib.html>`_.
+
+Examples of using the API are presented in the `API Overview`_ and
+`Processing Timer Expiry Events`_ sections.  Code samples are abstracted and
+are based on the example of handling a TCP retransmission.
+
+.. _event_timer:
+
+Event Timer struct
+------------------
+Event timers are timers that enqueue a timer expiration event to an event
+device upon timer expiration.
+
+The Event Timer Adapter API represents each event timer with a generic struct,
+which contains an event and user metadata.  The ``rte_event_timer`` struct is
+defined in ``lib/librte_event/librte_event_timer_adapter.h``.
+
+.. _timer_expiry_event:
+
+Timer Expiry Event
+~~~~~~~~~~~~~~~~~~
+
+The event contained by an event timer is enqueued in the event device when the
+timer expires, and the event device uses the attributes below when scheduling
+it:
+
+* ``event_queue_id`` - Application should set this to specify an event queue to
+  which the timer expiry event should be enqueued
+* ``event_priority`` - Application can set this to indicate the priority of the
+  timer expiry event in the event queue relative to other events
+* ``sched_type`` - Application can set this to specify the scheduling type of
+  the timer expiry event
+* ``flow_id`` - Application can set this to indicate which flow this timer
+  expiry event corresponds to
+* ``op`` - Will be set to ``RTE_EVENT_OP_NEW`` by the event timer adapter
+* ``event_type`` - Will be set to ``RTE_EVENT_TYPE_TIMER`` by the event timer
+  adapter
+
+Timeout Ticks
+~~~~~~~~~~~~~
+
+The number of ticks from now in which the timer will expire. The ticks value
+has a resolution (``timer_tick_ns``) that is specified in the event timer
+adapter configuration.
+
+State
+~~~~~
+
+Before arming an event timer, the application should initialize its state to
+RTE_EVENT_TIMER_NOT_ARMED. The event timer's state will be updated when a
+request to arm or cancel it takes effect.
+
+If the application wishes to rearm the timer after it has expired, it should
+reset the state back to RTE_EVENT_TIMER_NOT_ARMED before doing so.
+
+User Metadata
+~~~~~~~~~~~~~
+
+Memory to store user specific metadata.  The event timer adapter implementation
+will not modify this area.
+
+API Overview
+----------------
+
+This section will introduce the reader to the event timer adapter API, showing
+how to create and configure an event timer adapter and use it to manage event
+timers.
+
+From a high level, the setup steps are:
+
+* rte_event_timer_adapter_create()
+* rte_event_timer_adapter_start()
+
+And to start and stop timers:
+
+* rte_event_timer_init()
+* rte_event_timer_arm_burst()
+* rte_event_timer_cancel_burst()
+
+Create and Configure an Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To create an event timer adapter instance, initialize an
+``rte_event_timer_adapter_conf`` struct with the desired values, and pass it
+to ``rte_event_timer_adapter_create()``.
+
+.. code-block:: c
+
+	#define NSECPERSEC 1E9 // No of ns in 1 sec
+	const struct rte_event_timer_adapter_config adapter_config = {
+                .event_dev_id = event_dev_id,
+                .timer_adapter_id = 0,
+                .clk_src = RTE_EVENT_TIMER_WHEEL_CPU_CLK,
+                .timer_tick_ns = NSECPERSEC / 10, // 100 milliseconds
+                .max_tmo_nsec = 180 * NSECPERSEC // 2 minutes
+                .nb_timers = 40000,
+                .timer_adapter_flags = 0,
+	};
+
+	struct rte_event_timer_adapter *adapter = NULL;
+	adapter = rte_event_timer_adapter_create(&adapter_config);
+
+	if (adapter == NULL) { ... };
+
+Before creating an instance of a timer adapter, the application should create
+and configure an event device along with its event ports. Based on the event
+device capability, it might require creating an additional event port to be
+used by the timer adapter.  If required, the
+``rte_event_timer_adapter_create()`` function will use a default method to
+configure an event port;  it will examine the current event device
+configuration, determine the next available port identifier number, and create
+a new event port with a default port configuration.
+
+If the application desires to have finer control of event port allocation
+and setup, it can use the ``rte_event_timer_adapter_create_ext()`` function.
+This function is passed a callback function that will be invoked if the
+adapter needs to create an event port, giving the application the opportunity
+to control how it is done.
+
+Retrieve Event Timer Adapter Contextual Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The event timer adapter implementation may have constraints on tick resolution
+or maximum timer expiry timeout based on the given event timer adapter or
+system.  In this case, the implementation may adjust the tick resolution or
+maximum timeout to the best possible configuration.
+
+Upon successful event timer adapter creation, the application can get the
+configured resolution and max timeout with
+``rte_event_timer_adapter_get_info()``. This function will return an
+``rte_event_timer_adapter_info`` struct, which contains the following members:
+
+* ``min_resolution_ns`` - Minimum timer adapter tick resolution in ns.
+* ``max_tmo_ns`` - Maximum timer timeout(expiry) in ns.
+* ``adapter_conf`` - Configured event timer adapter attributes
+
+Configuring the Service Component
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the adapter uses a service component, the application is required to map
+the service to a service core before starting the adapter:
+
+.. code-block:: c
+
+        uint32_t service_id;
+
+        if (rte_event_timer_adapter_service_id_get(adapter, &service_id) == 0)
+                rte_service_map_lcore_set(service_id, EVTIM_CORE_ID);
+
+An event timer adapter uses a service component if the event device PMD
+indicates that the adapter should use a software implementation.
+
+Starting the Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The application should call ``rte_event_timer_adapter_start()`` to start
+running the event timer adapter. This function calls the start entry points
+defined by eventdev PMDs for hardware implementations or puts a service
+component into the running state in the software implementation.
+
+Arming Event Timers
+~~~~~~~~~~~~~~~~~~~~~
+
+Once an event timer adapter has been started, an application can begin to
+manage event timers with it.
+
+The application should allocate ``struct rte_event_timer`` objects from a
+mempool or huge-page backed application buffers of required size. Upon
+successful allocation, the application should initialize the event timer, and
+then set any of the necessary event attributes described in the
+`Timer Expiry Event`_ section. In the following example, assume ``conn``
+represents a TCP connection and that ``event_timer_pool`` is a mempool that
+was created previously:
+
+.. code-block:: c
+
+	rte_mempool_get(event_timer_pool, (void **)&conn->evtim);
+	if (conn->evtim == NULL) { ... }
+
+	/* Set up the event timer. */
+	conn->evtim->ev.op = RTE_EVENT_OP_NEW;
+	conn->evtim->ev.queue_id = event_queue_id;
+        conn->evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+        conn->evtim->ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
+        conn->evtim->ev.event_type = RTE_EVENT_TYPE_TIMER;
+	conn->evtim->ev.event_ptr = conn;
+	conn->evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns)
+
+Note that it is necessary to initialize the event timer state to
+RTE_EVENT_TIMER_NOT_ARMED.  Also note that we have saved a pointer to the
+``conn`` object in the timer's event payload. This will allow us to locate
+the connection object again once we dequeue the timer expiry event from the
+event device later.  As a convenience, the application may specify no value for
+ev.event_ptr (rte_event_timer_init sets it to NULL), and the adapter will by
+default set it to point at the event timer itself.
+
+Now we can arm the event timer with ``rte_event_timer_arm_burst()``:
+
+.. code-block:: c
+
+	ret = rte_event_timer_arm_burst(adapter, &conn->evtim, 1);
+	if (ret != 1) { ... }
+
+Once an event timer expires, the application may free it or rearm it as
+necessary.  If the application will rearm the timer, the state should be reset
+to RTE_EVENT_TIMER_NOT_ARMED by the application before rearming it.
+
+Multiple Event Timers with Same Expiry Value
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the special case that there is a set of event timers that should all expire
+at the same time, the application may call
+``rte_event_timer_arm_tmo_tick_burst()``, which allows the implementation to
+optimize the operation if possible.
+
+Canceling Event Timers
+~~~~~~~~~~~~~~~~~~~~~~~
+
+An event timer that has been armed as described in `Arming Event Timers`_ can
+be canceled by calling ``rte_event_timer_cancel_burst()``:
+
+.. code-block:: c
+
+	/* Ack for the previous tcp data packet has been received;
+	 * cancel the retransmission timer
+         */
+	rte_event_timer_cancel_burst(adapter, &conn->timer, 1);
+
+Processing Timer Expiry Events
+------------------------------
+
+Once an event timer has successfully enqueued a timer expiry event in the event
+device, the application will subsequently dequeue it from the event device.
+The application can use the event payload to retrieve a pointer to the object
+associated with the event timer. It can then re-arm the event timer or free the
+event timer object as desired:
+
+.. code-block:: c
+
+	void
+	event_processing_loop(...)
+	{
+		while (...) {
+			/* Receive events from the configured event port. */
+			rte_event_dequeue_burst(event_dev_id, event_port, &ev, 1, 0);
+			...
+			switch(ev.event_type) {
+				...
+				case RTE_EVENT_TYPE_TIMER:
+					process_timer_event(ev);
+					...
+					break;
+			}
+		}
+	}
+
+	uint8_t
+	process_timer_event(...)
+	{
+		/* A retransmission timeout for the connection has been received. */
+		conn = ev.event_ptr;
+		/* Retransmit last packet (e.g. TCP segment). */
+		...
+		/* Re-arm timer using original values. */
+		rte_event_timer_arm_burst(adapter_id, &conn->timer, 1);
+	}
+
+Summary
+-------
+
+The Event Timer Adapter library extends the DPDK event-based programming model
+by representing timer expirations as events in the system and allowing
+applications to use existing event processing loops to arm and cancel event
+timers or handle timer expiry events.
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index bbbe789..589c05d 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -42,6 +42,7 @@ Programmer's Guide
     thread_safety_dpdk_functions
     eventdev
     event_ethernet_rx_adapter
+    event_timer_adapter
     qos_framework
     power_man
     packet_classif_access_ctrl
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v9 9/9] doc: add event timer adapter documentation
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                             ` (7 preceding siblings ...)
  2018-04-02 19:39           ` [PATCH v9 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
@ 2018-04-02 19:39           ` Erik Gabriel Carrillo
  2018-04-02 23:42             ` Jerin Jacob
  2018-04-02 23:19           ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Jerin Jacob
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
  10 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-02 19:39 UTC (permalink / raw)
  To: pbhagavatula; +Cc: dev, jerin.jacob, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 MAINTAINERS                            |  7 +++++++
 doc/api/doxy-api-index.md              | 32 +++-----------------------------
 doc/guides/rel_notes/release_18_05.rst |  6 ++++++
 3 files changed, 16 insertions(+), 29 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 75d3e92..3cc3a3f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -317,6 +317,13 @@ F: lib/librte_eventdev/*eth_rx_adapter*
 F: test/test/test_event_eth_rx_adapter.c
 F: doc/guides/prog_guide/event_ethernet_rx_adapter.rst
 
+Eventdev Timer Adapter API - EXPERIMENTAL
+M: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
+T: git://dpdk.org/next/dpdk-next-eventdev
+F: lib/librte_eventdev/*timer_adapter*
+F: test/test/test_event_timer_adapter.c
+F: doc/guides/prog_guide/event_timer_adapter.rst
+
 Raw device API - EXPERIMENTAL
 M: Shreyansh Jain <shreyansh.jain@nxp.com>
 M: Hemant Agrawal <hemant.agrawal@nxp.com>
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..5c6cd51 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -2,35 +2,8 @@ API {#index}
 ===
 
 <!--
-  BSD LICENSE
-
-  Copyright 2013-2017 6WIND S.A.
-
-  Redistribution and use in source and binary forms, with or without
-  modification, are permitted provided that the following conditions
-  are met:
-
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in
-      the documentation and/or other materials provided with the
-      distribution.
-    * Neither the name of 6WIND S.A. nor the names of its
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
-
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright(c) 2013-2017 6WIND S.A.
 -->
 
 The public API headers are grouped by topics:
@@ -47,6 +20,7 @@ The public API headers are grouped by topics:
   [security]           (@ref rte_security.h),
   [eventdev]           (@ref rte_eventdev.h),
   [event_eth_rx_adapter]   (@ref rte_event_eth_rx_adapter.h),
+  [event_timer_adapter]    (@ref rte_event_timer_adapter.h),
   [rawdev]             (@ref rte_rawdev.h),
   [metrics]            (@ref rte_metrics.h),
   [bitrate]            (@ref rte_bitrate.h),
diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst
index 3923dc2..d5861be 100644
--- a/doc/guides/rel_notes/release_18_05.rst
+++ b/doc/guides/rel_notes/release_18_05.rst
@@ -41,6 +41,12 @@ New Features
      Also, make sure to start the actual text at the margin.
      =========================================================
 
+* **Added the Event Timer Adapter Library.**
+
+  The Event Timer Adapter Library extends the event-based model by introducing
+  APIs that allow applications to arm/cancel event timers that generate
+  timer expiry events. This new type of event is scheduled by an event device
+  along with existing types of events.
 
 API Changes
 -----------
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 0/9] eventtimer: introduce event timer adapter
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                             ` (8 preceding siblings ...)
  2018-04-02 19:39           ` [PATCH v9 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
@ 2018-04-02 23:19           ` Jerin Jacob
  2018-04-03 14:09             ` Carrillo, Erik G
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
  10 siblings, 1 reply; 133+ messages in thread
From: Jerin Jacob @ 2018-04-02 23:19 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, hemant.agrawal

-----Original Message-----
> Date: Mon, 2 Apr 2018 14:39:45 -0500
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, hemant.agrawal@nxp.com
> Subject: [PATCH v9 0/9] eventtimer: introduce event timer adapter 
> X-Mailer: git-send-email 1.7.10
> 
> This patch series contains the next iteration of the Event Timer Adapter
> library, which abstracts timer mechanisms that are tightly coupled with event
> devices, and extends the event based programming model so that timer
> expirations are represented as an event.
> 
> v9
> - Addressed comments on previous series from Pavan:
>   - Don't assume services exist in HW cases
>   - Adjust retry logic in a couple of tests
> - Addressed comments on previous series from Jerin:
>   - Fix build warning
> - Addressed comments on previous series from Hemant:
>   - Adjust copyright text

1) Please fix following check-patch warnings:

### eventtimer: introduce event timer adapter

ERROR:POINTER_LOCATION: "foo * bar" should be "foo *bar"
#273: FILE: lib/librte_eventdev/rte_event_timer_adapter.h:238:
+struct rte_event_timer_adapter * __rte_experimental

ERROR:POINTER_LOCATION: "foo * bar" should be "foo *bar"
#303: FILE: lib/librte_eventdev/rte_event_timer_adapter.h:268:
+struct rte_event_timer_adapter * __rte_experimenta


### eventtimer: add common code
ERROR:SPACING: space required after that ',' (ctx:VxB)
#113: FILE: lib/librte_eventdev/rte_event_timer_adapter.c:28:
+		RTE_FMT("EVTIMER: %s() line %u: "
RTE_FMT_HEAD(__VA_ARGS__,) \
 		                                                          ^

ERROR:SPACING: space required after that ',' (ctx:VxB)
#114: FILE: lib/librte_eventdev/rte_event_timer_adapter.c:29:
+			"\n", __func__, __LINE__,
RTE_FMT_TAIL(__VA_ARGS__,)))
 			                                                  ^

ERROR:POINTER_LOCATION: "foo * bar" should be "foo *bar"
#186: FILE: lib/librte_eventdev/rte_event_timer_adapter.c:101:
+struct rte_event_timer_adapter * __rte_experimental

ERROR:POINTER_LOCATION: "foo * bar" should be "foo *bar"
#193: FILE: lib/librte_eventdev/rte_event_timer_adapter.c:108:
+struct rte_event_timer_adapter * __rte_experimental

total: 4 errors, 0 warnings, 695 lines checked


2) PLEASE don't remove previous Acked-by: in the patches that you have got it.
For example, PATCH v9 2/9, Already had Acked-by: from me and Hemant on
License change(Which is missing in this series)

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 1/9] eventtimer: introduce event timer adapter
  2018-04-02 19:39           ` [PATCH v9 1/9] " Erik Gabriel Carrillo
@ 2018-04-02 23:25             ` Jerin Jacob
  0 siblings, 0 replies; 133+ messages in thread
From: Jerin Jacob @ 2018-04-02 23:25 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, hemant.agrawal

-----Original Message-----
> Date: Mon, 2 Apr 2018 14:39:46 -0500
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, hemant.agrawal@nxp.com
> Subject: [PATCH v9 1/9] eventtimer: introduce event timer adapter
> X-Mailer: git-send-email 1.7.10
> 
> Event devices can be coupled with various components to provide
> new event sources by using event adapters.  The event timer adapter
> is one such adapter; it bridges event devices and timer mechanisms.
> This library extends the event-driven programming model by
> introducing a new type of event that represents a timer expiration,
> and it provides APIs with which adapters can be created or destroyed
> and event timers can be armed and canceled.
> 
> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>

Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 2/9] eventdev: convert to SPDX license tag in header
  2018-04-02 19:39           ` [PATCH v9 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
@ 2018-04-02 23:27             ` Jerin Jacob
  0 siblings, 0 replies; 133+ messages in thread
From: Jerin Jacob @ 2018-04-02 23:27 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, hemant.agrawal

-----Original Message-----
> Date: Mon, 2 Apr 2018 14:39:47 -0500
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, hemant.agrawal@nxp.com
> Subject: [PATCH v9 2/9] eventdev: convert to SPDX license tag in header
> X-Mailer: git-send-email 1.7.10
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>

Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>

Hemant already Acked this patch, Please add his Acked-by in next version.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 3/9] eventtimer: add common code
  2018-04-02 19:39           ` [PATCH v9 3/9] eventtimer: add common code Erik Gabriel Carrillo
@ 2018-04-02 23:35             ` Jerin Jacob
  2018-04-03 18:38               ` Carrillo, Erik G
  0 siblings, 1 reply; 133+ messages in thread
From: Jerin Jacob @ 2018-04-02 23:35 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, hemant.agrawal

-----Original Message-----
> Date: Mon, 2 Apr 2018 14:39:48 -0500
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, hemant.agrawal@nxp.com
> Subject: [PATCH v9 3/9] eventtimer: add common code
> X-Mailer: git-send-email 1.7.10
> 
> This commit adds the logic that is shared by all event timer adapter
> drivers; the common code handles instance allocation and some
> initialization.
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
> +
> +EXPERIMENTAL {
> +	global:
> +
> +        rte_event_timer_adapter_caps_get;
> +	rte_event_timer_adapter_create;
> +	rte_event_timer_adapter_create_ext;
> +	rte_event_timer_adapter_free;
> +	rte_event_timer_adapter_get_info;
> +	rte_event_timer_adapter_lookup;
> +	rte_event_timer_adapter_service_id_get;
> +	rte_event_timer_adapter_start;
> +	rte_event_timer_adapter_stats_get;
> +	rte_event_timer_adapter_stats_reset;
> +	rte_event_timer_adapter_stop;
> +	rte_event_timer_init;

rte_event_timer_init() function is missing and it referenced in
programmers guide too.
It suppose to be in the lib/librte_eventdev/rte_event_timer_adapter.h as static inline function.

> +	rte_event_timer_arm_burst;
> +	rte_event_timer_arm_tmo_tick_burst;
> +	rte_event_timer_cancel_burst;
> +} DPDK_18.02;
> -- 
> 2.6.4
> 

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 4/9] mk: update library order in static build
  2018-04-02 19:39           ` [PATCH v9 4/9] mk: update library order in static build Erik Gabriel Carrillo
@ 2018-04-02 23:36             ` Jerin Jacob
  0 siblings, 0 replies; 133+ messages in thread
From: Jerin Jacob @ 2018-04-02 23:36 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, hemant.agrawal

-----Original Message-----
> Date: Mon, 2 Apr 2018 14:39:49 -0500
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, hemant.agrawal@nxp.com
> Subject: [PATCH v9 4/9] mk: update library order in static build
> X-Mailer: git-send-email 1.7.10
> 
> The introduction of the event timer adapter library adds a dependency
> on the rte_timer library from the rte_eventdev library.  Update the
> order so that the timer library comes after the eventdev library in the
> linker command when statically linking applications.
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>

Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>

> ---
>  mk/rte.app.mk | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index 94525dc..983ad09 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)        += -lrte_bitratestats
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
>  
> -_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
>  
>  _LDLIBS-y += --whole-archive
> @@ -98,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)       += -lrte_security
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV)         += -lrte_rawdev
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
>  _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
> -- 
> 2.6.4
> 

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 9/9] doc: add event timer adapter documentation
  2018-04-02 19:39           ` [PATCH v9 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
@ 2018-04-02 23:42             ` Jerin Jacob
  0 siblings, 0 replies; 133+ messages in thread
From: Jerin Jacob @ 2018-04-02 23:42 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, hemant.agrawal

-----Original Message-----
> Date: Mon, 2 Apr 2018 14:39:54 -0500
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, hemant.agrawal@nxp.com
> Subject: [PATCH v9 9/9] doc: add event timer adapter documentation
> X-Mailer: git-send-email 1.7.10
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  MAINTAINERS                            |  7 +++++++
>  doc/api/doxy-api-index.md              | 32 +++-----------------------------
>  doc/guides/rel_notes/release_18_05.rst |  6 ++++++
>  3 files changed, 16 insertions(+), 29 deletions(-)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 75d3e92..3cc3a3f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -317,6 +317,13 @@ F: lib/librte_eventdev/*eth_rx_adapter*
>  F: test/test/test_event_eth_rx_adapter.c
>  F: doc/guides/prog_guide/event_ethernet_rx_adapter.rst
>  
> +Eventdev Timer Adapter API - EXPERIMENTAL
> +M: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> +T: git://dpdk.org/next/dpdk-next-eventdev
> +F: lib/librte_eventdev/*timer_adapter*
> +F: test/test/test_event_timer_adapter.c
> +F: doc/guides/prog_guide/event_timer_adapter.rst
> +

Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>

Please rebase this patch to latest dpdk-next-event tree as there merge
conflicts.

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 8/9] doc: add event timer adapter section to programmer's guide
  2018-04-02 19:39           ` [PATCH v9 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
@ 2018-04-03  0:00             ` Jerin Jacob
  0 siblings, 0 replies; 133+ messages in thread
From: Jerin Jacob @ 2018-04-03  0:00 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, hemant.agrawal

-----Original Message-----
> Date: Mon, 2 Apr 2018 14:39:53 -0500
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com
> CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com, hemant.agrawal@nxp.com
> Subject: [PATCH v9 8/9] doc: add event timer adapter section to
>  programmer's guide
> X-Mailer: git-send-email 1.7.10
> 
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
> ---
> +To create an event timer adapter instance, initialize an
> +``rte_event_timer_adapter_conf`` struct with the desired values, and pass it
> +to ``rte_event_timer_adapter_create()``.
> +
> +.. code-block:: c
> +
> +	#define NSECPERSEC 1E9 // No of ns in 1 sec
> +	const struct rte_event_timer_adapter_config adapter_config = {

s/rte_event_timer_adapter_config/rte_event_timer_adapter_conf

> +                .event_dev_id = event_dev_id,
> +                .timer_adapter_id = 0,
> +                .clk_src = RTE_EVENT_TIMER_WHEEL_CPU_CLK,

s/RTE_EVENT_TIMER_WHEEL_CPU_CLK/RTE_EVENT_TIMER_ADAPTER_CPU_CLK

> +                .timer_tick_ns = NSECPERSEC / 10, // 100 milliseconds
> +                .max_tmo_nsec = 180 * NSECPERSEC // 2 minutes
> +                .nb_timers = 40000,
> +                .timer_adapter_flags = 0,
> +	};
> +
> +Arming Event Timers
> +~~~~~~~~~~~~~~~~~~~~~
> +
> +Once an event timer adapter has been started, an application can begin to
> +manage event timers with it.
> +
> +The application should allocate ``struct rte_event_timer`` objects from a
> +mempool or huge-page backed application buffers of required size. Upon
> +successful allocation, the application should initialize the event timer, and
> +then set any of the necessary event attributes described in the
> +`Timer Expiry Event`_ section. In the following example, assume ``conn``
> +represents a TCP connection and that ``event_timer_pool`` is a mempool that
> +was created previously:
> +
> +.. code-block:: c
> +
> +	rte_mempool_get(event_timer_pool, (void **)&conn->evtim);
> +	if (conn->evtim == NULL) { ... }
> +
> +	/* Set up the event timer. */
> +	conn->evtim->ev.op = RTE_EVENT_OP_NEW;
> +	conn->evtim->ev.queue_id = event_queue_id;
> +        conn->evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
> +        conn->evtim->ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
> +        conn->evtim->ev.event_type = RTE_EVENT_TYPE_TIMER;
> +	conn->evtim->ev.event_ptr = conn;
> +	conn->evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
> +	conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns)
> +
> +Note that it is necessary to initialize the event timer state to
> +RTE_EVENT_TIMER_NOT_ARMED.  Also note that we have saved a pointer to the
> +``conn`` object in the timer's event payload. This will allow us to locate
> +the connection object again once we dequeue the timer expiry event from the
> +event device later.  As a convenience, the application may specify no value for
> +ev.event_ptr (rte_event_timer_init sets it to NULL), and the adapter will by

rte_event_timer_init() has been removed. Either re-introduce the function
or update the programmers guide and fix reference to rte_event_timer_init () in patch 3/9

I think, you made correct decision to remove rte_event_timer_init() as
it does not have much use. So it is up to you to include back or not.

Once above documentation is fixed, you can add my:
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 7/9] test: add event timer adapter auto-test
  2018-04-02 19:39           ` [PATCH v9 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
@ 2018-04-03  9:52             ` Pavan Nikhilesh
  0 siblings, 0 replies; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-04-03  9:52 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, hemant.agrawal; +Cc: dev

On Mon, Apr 02, 2018 at 02:39:52PM -0500, Erik Gabriel Carrillo wrote:
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  test/test/Makefile                   |    1 +
>  test/test/test_event_timer_adapter.c | 1831 ++++++++++++++++++++++++++++++++++
>  2 files changed, 1832 insertions(+)
>  create mode 100644 test/test/test_event_timer_adapter.c
>
Acked-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 5/9] eventtimer: add default software driver
  2018-04-02 19:39           ` [PATCH v9 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
@ 2018-04-03  9:59             ` Pavan Nikhilesh
  0 siblings, 0 replies; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-04-03  9:59 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob, hemant.agrawal; +Cc: dev

Hi Erik,

On Mon, Apr 02, 2018 at 02:39:50PM -0500, Erik Gabriel Carrillo wrote:
> If an eventdev PMD does not wish to provide event timer adapter ops
> definitions, the library will fall back to a default software
> implementation whose entry points are added by this commit.
>
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  lib/Makefile                                  |   2 +-
>  lib/librte_eventdev/Makefile                  |   2 +-
>  lib/librte_eventdev/rte_event_timer_adapter.c | 909 ++++++++++++++++++++++++++
>  lib/librte_eventdev/rte_event_timer_adapter.h |  57 +-
>  4 files changed, 966 insertions(+), 4 deletions(-)
>
<snip>
> +const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;

We can make this as static instead of global as it is only used in this file.

> +
>  #define EVTIM_LOG(level, logtype, ...) \
>  	rte_log(RTE_LOG_ ## level, logtype, \
>  		RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
> @@ -33,8 +46,14 @@ static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
>  #ifdef RTE_LIBRTE_EVENTDEV_DEBUG
>  #define EVTIM_LOG_DBG(...) \
>  	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
> +#define EVTIM_BUF_LOG_DBG(...) \
> +	EVTIM_LOG(DEBUG, evtim_buffer_logtype, __VA_ARGS__)
> +#define EVTIM_SVC_LOG_DBG(...) \
> +	EVTIM_LOG(DEBUG, evtim_svc_logtype, __VA_ARGS__)
>  #else
>  #define EVTIM_LOG_DBG(...) (void)0
> +#define EVTIM_BUF_LOG_DBG(...) (void)0
> +#define EVTIM_SVC_LOG_DBG(...) (void)0
>  #endif

<snip>
> +
> +const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
> +	.init = sw_event_timer_adapter_init,
> +	.uninit = sw_event_timer_adapter_uninit,
> +	.start = sw_event_timer_adapter_start,
> +	.stop = sw_event_timer_adapter_stop,
> +	.get_info = sw_event_timer_adapter_get_info,
> +	.stats_get = sw_event_timer_adapter_stats_get,
> +	.stats_reset = sw_event_timer_adapter_stats_reset,
> +	.arm_burst = sw_event_timer_arm_burst,
> +	.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
> +	.cancel_burst = sw_event_timer_cancel_burst,
> +};

Move this above and make it static.

> +

With the above changes
Acked-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 0/9] eventtimer: introduce event timer adapter
  2018-04-02 23:19           ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Jerin Jacob
@ 2018-04-03 14:09             ` Carrillo, Erik G
  2018-04-03 14:15               ` Jerin Jacob
  0 siblings, 1 reply; 133+ messages in thread
From: Carrillo, Erik G @ 2018-04-03 14:09 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: dev

Hi Jerin,

Question in-line:

> -----Original Message-----
> From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> Sent: Monday, April 2, 2018 6:19 PM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>
> Cc: pbhagavatula@caviumnetworks.com; dev@dpdk.org;
> hemant.agrawal@nxp.com
> Subject: Re: [PATCH v9 0/9] eventtimer: introduce event timer adapter
> 
> -----Original Message-----
> > Date: Mon, 2 Apr 2018 14:39:45 -0500
> > From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > To: pbhagavatula@caviumnetworks.com
> > CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com,
> > hemant.agrawal@nxp.com
> > Subject: [PATCH v9 0/9] eventtimer: introduce event timer adapter
> > X-Mailer: git-send-email 1.7.10
> >
> > This patch series contains the next iteration of the Event Timer
> > Adapter library, which abstracts timer mechanisms that are tightly
> > coupled with event devices, and extends the event based programming
> > model so that timer expirations are represented as an event.
> >
> > v9
> > - Addressed comments on previous series from Pavan:
> >   - Don't assume services exist in HW cases
> >   - Adjust retry logic in a couple of tests
> > - Addressed comments on previous series from Jerin:
> >   - Fix build warning
> > - Addressed comments on previous series from Hemant:
> >   - Adjust copyright text
> 
> 1) Please fix following check-patch warnings:
> 
> ### eventtimer: introduce event timer adapter
> 
> ERROR:POINTER_LOCATION: "foo * bar" should be "foo *bar"
> #273: FILE: lib/librte_eventdev/rte_event_timer_adapter.h:238:
> +struct rte_event_timer_adapter * __rte_experimental
> 
> ERROR:POINTER_LOCATION: "foo * bar" should be "foo *bar"
> #303: FILE: lib/librte_eventdev/rte_event_timer_adapter.h:268:
> +struct rte_event_timer_adapter * __rte_experimenta
> 
 
I was aware that checkpatch was complaining here, but the style I used is 
consistent with almost all the existing DPDK code that uses the __rte_experimental
tag.  Should I fix the warning if the style will differ from existing code?

Thanks,
Gabriel

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 0/9] eventtimer: introduce event timer adapter
  2018-04-03 14:09             ` Carrillo, Erik G
@ 2018-04-03 14:15               ` Jerin Jacob
  2018-04-03 18:32                 ` Carrillo, Erik G
  0 siblings, 1 reply; 133+ messages in thread
From: Jerin Jacob @ 2018-04-03 14:15 UTC (permalink / raw)
  To: Carrillo, Erik G; +Cc: dev

-----Original Message-----
> Date: Tue, 3 Apr 2018 14:09:22 +0000
> From: "Carrillo, Erik G" <erik.g.carrillo@intel.com>
> To: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> CC: "dev@dpdk.org" <dev@dpdk.org>
> Subject: RE: [PATCH v9 0/9] eventtimer: introduce event timer adapter
> 
> Hi Jerin,


Hi Carrillo,

> 
> Question in-line:
> 
> > 1) Please fix following check-patch warnings:
> > 
> > ### eventtimer: introduce event timer adapter
> > 
> > ERROR:POINTER_LOCATION: "foo * bar" should be "foo *bar"
> > #273: FILE: lib/librte_eventdev/rte_event_timer_adapter.h:238:
> > +struct rte_event_timer_adapter * __rte_experimental
> > 
> > ERROR:POINTER_LOCATION: "foo * bar" should be "foo *bar"
> > #303: FILE: lib/librte_eventdev/rte_event_timer_adapter.h:268:
> > +struct rte_event_timer_adapter * __rte_experimenta
> > 
>  
> I was aware that checkpatch was complaining here, but the style I used is 
> consistent with almost all the existing DPDK code that uses the __rte_experimental
> tag.  Should I fix the warning if the style will differ from existing code?

Probably, We could fix the checkpatch. May be for short term we could
live with those warnings.

> 
> Thanks,
> Gabriel
> 

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 0/9] eventtimer: introduce event timer adapter
  2018-04-03 14:15               ` Jerin Jacob
@ 2018-04-03 18:32                 ` Carrillo, Erik G
  0 siblings, 0 replies; 133+ messages in thread
From: Carrillo, Erik G @ 2018-04-03 18:32 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: dev



> -----Original Message-----
> From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> Sent: Tuesday, April 3, 2018 9:15 AM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>
> Cc: dev@dpdk.org
> Subject: Re: [PATCH v9 0/9] eventtimer: introduce event timer adapter
> 
> -----Original Message-----
> > Date: Tue, 3 Apr 2018 14:09:22 +0000
> > From: "Carrillo, Erik G" <erik.g.carrillo@intel.com>
> > To: Jerin Jacob <jerin.jacob@caviumnetworks.com>
> > CC: "dev@dpdk.org" <dev@dpdk.org>
> > Subject: RE: [PATCH v9 0/9] eventtimer: introduce event timer adapter
> >
> > Hi Jerin,
> 
> 
> Hi Carrillo,
> 
> >
> > Question in-line:
> >
> > > 1) Please fix following check-patch warnings:
> > >
> > > ### eventtimer: introduce event timer adapter
> > >
> > > ERROR:POINTER_LOCATION: "foo * bar" should be "foo *bar"
> > > #273: FILE: lib/librte_eventdev/rte_event_timer_adapter.h:238:
> > > +struct rte_event_timer_adapter * __rte_experimental
> > >
> > > ERROR:POINTER_LOCATION: "foo * bar" should be "foo *bar"
> > > #303: FILE: lib/librte_eventdev/rte_event_timer_adapter.h:268:
> > > +struct rte_event_timer_adapter * __rte_experimenta
> > >
> >
> > I was aware that checkpatch was complaining here, but the style I used
> > is consistent with almost all the existing DPDK code that uses the
> > __rte_experimental tag.  Should I fix the warning if the style will differ from
> existing code?
> 
> Probably, We could fix the checkpatch. May be for short term we could live
> with those warnings.

Ok.  I looked at the other warnings too and checkpatch complains if there's no space after
the comma, and it also complains if there's a space between the comma and the closing paren.

Since it complains either way, I propose to leave it as the style is consistent with other uses
of RTE_FMT_HEAD() and RTE_FMT_TAIL() throughout the codebase.
 
> 
> >
> > Thanks,
> > Gabriel
> >

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v9 3/9] eventtimer: add common code
  2018-04-02 23:35             ` Jerin Jacob
@ 2018-04-03 18:38               ` Carrillo, Erik G
  0 siblings, 0 replies; 133+ messages in thread
From: Carrillo, Erik G @ 2018-04-03 18:38 UTC (permalink / raw)
  To: Jerin Jacob; +Cc: pbhagavatula, dev, hemant.agrawal



> -----Original Message-----
> From: Jerin Jacob [mailto:jerin.jacob@caviumnetworks.com]
> Sent: Monday, April 2, 2018 6:36 PM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>
> Cc: pbhagavatula@caviumnetworks.com; dev@dpdk.org;
> hemant.agrawal@nxp.com
> Subject: Re: [PATCH v9 3/9] eventtimer: add common code
> 
> -----Original Message-----
> > Date: Mon, 2 Apr 2018 14:39:48 -0500
> > From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > To: pbhagavatula@caviumnetworks.com
> > CC: dev@dpdk.org, jerin.jacob@caviumnetworks.com,
> > hemant.agrawal@nxp.com
> > Subject: [PATCH v9 3/9] eventtimer: add common code
> > X-Mailer: git-send-email 1.7.10
> >
> > This commit adds the logic that is shared by all event timer adapter
> > drivers; the common code handles instance allocation and some
> > initialization.
> >
> > Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> > ---
> > +
> > +EXPERIMENTAL {
> > +	global:
> > +
> > +        rte_event_timer_adapter_caps_get;
> > +	rte_event_timer_adapter_create;
> > +	rte_event_timer_adapter_create_ext;
> > +	rte_event_timer_adapter_free;
> > +	rte_event_timer_adapter_get_info;
> > +	rte_event_timer_adapter_lookup;
> > +	rte_event_timer_adapter_service_id_get;
> > +	rte_event_timer_adapter_start;
> > +	rte_event_timer_adapter_stats_get;
> > +	rte_event_timer_adapter_stats_reset;
> > +	rte_event_timer_adapter_stop;
> > +	rte_event_timer_init;
> 
> rte_event_timer_init() function is missing and it referenced in programmers
> guide too.
> It suppose to be in the lib/librte_eventdev/rte_event_timer_adapter.h as
> static inline function.
 
Thanks for catching that.  I'll remove the symbol from the map file and from
Programmer's Guide.

Regards,
Gabriel

> 
> > +	rte_event_timer_arm_burst;
> > +	rte_event_timer_arm_tmo_tick_burst;
> > +	rte_event_timer_cancel_burst;
> > +} DPDK_18.02;
> > --
> > 2.6.4
> >

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v10 0/9] eventtimer: introduce event timer adapter
  2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
                             ` (9 preceding siblings ...)
  2018-04-02 23:19           ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Jerin Jacob
@ 2018-04-03 21:44           ` Erik Gabriel Carrillo
  2018-04-03 21:44             ` [PATCH v10 1/9] " Erik Gabriel Carrillo
                               ` (10 more replies)
  10 siblings, 11 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-03 21:44 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev, hemant.agrawal

This patch series contains the next iteration of the Event Timer Adapter
library, which abstracts timer mechanisms that are tightly coupled with event
devices, and extends the event based programming model so that timer
expirations are represented as an event.

v10
- remove stale references to rte_event_timer_init API and update docs (Jerin)
- rebase to latest dpdk-next-eventdev tree (Jerin)
- make sw_event_adapter_timer_ops var static (Pavan)

v9
- Addressed comments on previous series from Pavan:
  - Don't assume services exist in HW cases
  - Adjust retry logic in a couple of tests
- Addressed comments on previous series from Jerin:
  - Fix build warning
- Addressed comments on previous series from Hemant:
  - Adjust copyright text

v8
- Addressed comments on previous series from Jerin:
  - Add better git comment to initial patch
  - Return uint16_t for fastpath functions
  - Move updates to existing licenses to separate patch for individual review
  - Fix clang build error
  - Move fastpath functions into header as static inline functions
  - Remove duplicate map file entry
  - Fix flag value
  - Move update to rte.app.mk file into separate commit
- Addressed comments on previous series from Pavan:
  - Make tests generic so that they work for software or hardware event devices
    and timer mechanisms
  - Don't access eventdev internals from tests
- Integrated unit tests from Pavan

v7
- Addressed comments on previous patch series from Pavan:
  - Use SPDX license tags
  - Squash various commits to make series easier to review
  - Tag experimental functions as such
  - Use one mempool for messages and timers in sw driver 
  - Limit service cores mapped to sw driver's service to one
  - Use smp memory barriers
  - In service function, invoke rte_timer_manage() with frequency matching the
    resolution the adapter was configured with
- Reworked synchronization in sw driver between threads producing messages
  and service thread that consumes them.  The new approach avoids a situation
  where event timers couldn't be armed/canceled from the same lcore the service
  was running on.
- Updated logging facility
- Added more unit tests
- Added support for meson build

v6
- Addressed comments on previous version from Jerin:
  - Added RTE_EVENT_TIMER_CANCELED event timer state back in
  - remove check for started adapter in timer arm/cancel functions 
  - reuse CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG instead of adding new config option
- Added initial version of software driver implementation
- Added stats APIs
- Added API to retrieve adapter service ID
- Added API to initialize event timer
- Added entry to Programmer's Guide in documentation
- Added new unit tests to auto-test

v5
- Addressed comments on previous version from Pavan:
  - renamed rte_event_timer_adapter_driver.h to rte_event_timer_adapter_pmd.h
  - moved contents of sw_event_timer_adapter.c into rte_event_timer_adapter.c
  - added flags parameter to timer_adapter_caps_get() call
  - added DEBUG config variable to conditionally compile run-time checks on
    datapath
  - fixed license text and file description
- Also added a config variable to enable/disable compilation of event timer
  adapter - feedback on whether this is desirable is appreciated

v4
- Split changes into multiple patches for easier review

v3
- Reworked allocation and ops organization in common code based on feedback
  received from Jerin and Pavan. This will allow fast-path function pointers to 
  be dereferenced with one level of indirection with pointers valid in primary
  and secondary processes.
- Moved default software implementation from sw_evdev directory to eventdev
  library directory, which will allow it to be used by any eventdev PMD as an
  alternative to providing its own definitions.
- Reverted occurrences of id back to pointer to adapter struct in library API
- Added rte_event_timer_adapter_lookup() function back in

v2
- Added ops structure and stubbed out plugin for SW impl
- Added unit test stubs
- Replaced occurrences of "wheel" in API with "adapter"
- Replaced occurrences of pointer to struct rte_event_timer_adapter with ids
- Removed rte_event_timer_adapter_lookup() function
- Replaced RTE_EVENT_TIMER_SUCCESS_{ARM,CANCEL} states with
  RTE_EVENT_TIMER_ARMED

Erik Gabriel Carrillo (9):
  eventtimer: introduce event timer adapter
  eventdev: convert to SPDX license tag in header
  eventtimer: add common code
  mk: update library order in static build
  eventtimer: add default software driver
  eventtimer: add support for meson build system
  test: add event timer adapter auto-test
  doc: add event timer adapter section to programmer's guide
  doc: add event timer adapter documentation

 MAINTAINERS                                       |    7 +
 config/common_base                                |    1 +
 config/rte_config.h                               |    1 +
 doc/api/doxy-api-index.md                         |   32 +-
 doc/guides/prog_guide/event_timer_adapter.rst     |  296 ++++
 doc/guides/prog_guide/index.rst                   |    1 +
 doc/guides/rel_notes/release_18_05.rst            |    6 +
 drivers/event/sw/sw_evdev.c                       |   18 +
 lib/Makefile                                      |    2 +-
 lib/librte_eventdev/Makefile                      |    5 +-
 lib/librte_eventdev/meson.build                   |    9 +-
 lib/librte_eventdev/rte_event_timer_adapter.c     | 1296 +++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h     |  768 +++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h |  114 ++
 lib/librte_eventdev/rte_eventdev.c                |   22 +
 lib/librte_eventdev/rte_eventdev.h                |   61 +-
 lib/librte_eventdev/rte_eventdev_pmd.h            |   35 +
 lib/librte_eventdev/rte_eventdev_version.map      |   20 +-
 lib/meson.build                                   |    3 +-
 mk/rte.app.mk                                     |    2 +-
 test/test/Makefile                                |    1 +
 test/test/test_event_timer_adapter.c              | 1831 +++++++++++++++++++++
 22 files changed, 4460 insertions(+), 71 deletions(-)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h
 create mode 100644 test/test/test_event_timer_adapter.c

-- 
2.6.4

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v10 1/9] eventtimer: introduce event timer adapter
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
@ 2018-04-03 21:44             ` Erik Gabriel Carrillo
  2018-04-03 21:44             ` [PATCH v10 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
                               ` (9 subsequent siblings)
  10 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-03 21:44 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev, hemant.agrawal

Event devices can be coupled with various components to provide
new event sources by using event adapters.  The event timer adapter
is one such adapter; it bridges event devices and timer mechanisms.
This library extends the event-driven programming model by
introducing a new type of event that represents a timer expiration,
and it provides APIs with which adapters can be created or destroyed
and event timers can be armed and canceled.

Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 lib/librte_eventdev/Makefile                  |   1 +
 lib/librte_eventdev/rte_event_timer_adapter.h | 715 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_eventdev.h            |   4 +-
 3 files changed, 718 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h

diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index d27dd07..549b182 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -28,6 +28,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
new file mode 100644
index 0000000..6a76791
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -0,0 +1,715 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc.
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ * @file
+ *
+ * RTE Event Timer Adapter
+ *
+ * An event timer adapter has the following abstract working model:
+ *
+ *                               timer_tick_ns
+ *                                   +
+ *                      +-------+    |
+ *                      |       |    |
+ *              +-------+ bkt 0 +----v---+
+ *              |       |       |        |
+ *              |       +-------+        |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *          |       |                |       |  |   |   |   |   |
+ *          | bkt n |                | bkt 1 |<-> t0| t1| t2| tn|
+ *          |       |                |       |  |   |   |   |   |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *              |     Timer adapter      |
+ *          +---+---+                +---+---+
+ *          |       |                |       |
+ *          | bkt 4 |                | bkt 2 |<--- Current bucket
+ *          |       |                |       |
+ *          +---+---+                +---+---+
+ *               |      +-------+       |
+ *               |      |       |       |
+ *               +------+ bkt 3 +-------+
+ *                      |       |
+ *                      +-------+
+ *
+ * - It has a virtual monotonically increasing 64-bit timer adapter clock based
+ *   on *enum rte_event_timer_adapter_clk_src* clock source. The clock source
+ *   could be a CPU clock, or a platform dependent external clock.
+ *
+ * - The application creates a timer adapter instance with given the clock
+ *   source, the total number of event timers, and a resolution(expressed in ns)
+ *   to traverse between the buckets.
+ *
+ * - Each timer adapter may have 0 to n buckets based on the configured
+ *   max timeout(max_tmo_ns) and resolution(timer_tick_ns). Upon starting the
+ *   timer adapter, the adapter starts ticking at *timer_tick_ns* resolution.
+ *
+ * - The application arms an event timer that will expire *timer_tick_ns*
+ *   from now.
+ *
+ * - The application can cancel an armed timer and no timer expiry event will be
+ *   generated.
+ *
+ * - If a timer expires then the library injects the timer expiry event in
+ *   the designated event queue.
+ *
+ * - The timer expiry event will be received through *rte_event_dequeue_burst*.
+ *
+ * - The application frees the timer adapter instance.
+ *
+ * Multiple timer adapters can be created with a varying level of resolution
+ * for various expiry use cases that run in parallel.
+ *
+ * Before using the timer adapter, the application has to create and configure
+ * an event device along with the event port. Based on the event device
+ * capability it might require creating an additional event port to be used
+ * by the timer adapter.
+ *
+ * The application creates the event timer adapter using the
+ * ``rte_event_timer_adapter_create()``. The event device id is passed to this
+ * function, inside this function the event device capability is checked,
+ * and if an in-built port is absent the application uses the default
+ * function to create a new producer port.
+ *
+ * The application may also use the function
+ * ``rte_event_timer_adapter_create_ext()`` to have granular control over
+ * producer port creation in a case where the in-built port is absent.
+ *
+ * After creating the timer adapter, the application has to start it
+ * using ``rte_event_timer_adapter_start()``. The buckets are traversed from
+ * 0 to n; when the adapter ticks, the next bucket is visited. Each time,
+ * the list per bucket is processed, and timer expiry events are sent to the
+ * designated event queue.
+ *
+ * The application can arm one or more event timers using the
+ * ``rte_event_timer_arm_burst()``. The *timeout_ticks* represents the number
+ * of *timer_tick_ns* after which the timer has to expire. The timeout at
+ * which the timers expire can be grouped or be independent of each
+ * event timer instance. ``rte_event_timer_arm_tmo_tick_burst()`` addresses the
+ * former case and ``rte_event_timer_arm_burst()`` addresses the latter case.
+ *
+ * The application can cancel the timers from expiring using the
+ * ``rte_event_timer_cancel_burst()``.
+ *
+ * On the secondary process, ``rte_event_timer_adapter_lookup()`` can be used
+ * to get the timer adapter pointer from its id and use it to invoke fastpath
+ * operations such as arm and cancel.
+ *
+ * Some of the use cases of event timer adapter are Beacon Timers,
+ * Generic SW Timeout, Wireless MAC Scheduling, 3G Frame Protocols,
+ * Packet Scheduling, Protocol Retransmission Timers, Supervision Timers.
+ * All these use cases require high resolution and low time drift.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_spinlock.h>
+#include <rte_memory.h>
+
+#include "rte_eventdev.h"
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this enum may change without prior notice
+ *
+ * Timer adapter clock source
+ */
+enum rte_event_timer_adapter_clk_src {
+	RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+	/**< Use CPU clock as the clock source. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK0,
+	/**< Platform dependent external clock source 0. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK1,
+	/**< Platform dependent external clock source 1. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK2,
+	/**< Platform dependent external clock source 2. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK3,
+	/**< Platform dependent external clock source 3. */
+};
+
+#define RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES	(1ULL << 0)
+/**< The event timer adapter implementation may have constraints on the
+ * resolution (timer_tick_ns) and maximum timer expiry timeout(max_tmo_ns)
+ * based on the given timer adapter or system.  If this flag is set, the
+ * implementation adjusts the resolution and maximum timeout to the best
+ * possible configuration. On successful timer adapter creation, the
+ * application can get the configured resolution and max timeout with
+ * ``rte_event_timer_adapter_get_info()``.
+ *
+ * @see struct rte_event_timer_adapter_info::min_resolution_ns
+ * @see struct rte_event_timer_adapter_info::max_tmo_ns
+ */
+#define RTE_EVENT_TIMER_ADAPTER_F_SP_PUT	(1ULL << 1)
+/**< ``rte_event_timer_arm_burst()`` API to be used in single producer mode.
+ *
+ * @see struct rte_event_timer_adapter_conf::flags
+ */
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter configuration structure
+ */
+struct rte_event_timer_adapter_conf {
+	uint8_t event_dev_id;
+	/**< Event device identifier */
+	uint16_t timer_adapter_id;
+	/**< Event timer adapter identifier */
+	uint32_t socket_id;
+	/**< Identifier of socket from which to allocate memory for adapter */
+	enum rte_event_timer_adapter_clk_src clk_src;
+	/**< Clock source for timer adapter */
+	uint64_t timer_tick_ns;
+	/**< Timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expiry) in ns */
+	uint64_t nb_timers;
+	/**< Total number of timers per adapter */
+	uint64_t flags;
+	/**< Timer adapter config flags (RTE_EVENT_TIMER_ADAPTER_F_*) */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer adapter stats structure
+ */
+struct rte_event_timer_adapter_stats {
+	uint64_t evtim_exp_count;
+	/**< Number of event timers that have expired. */
+	uint64_t ev_enq_count;
+	/**< Eventdev enqueue count */
+	uint64_t ev_inv_count;
+	/**< Invalid expiry event count */
+	uint64_t evtim_retry_count;
+	/**< Event timer retry count */
+	uint64_t adapter_tick_count;
+	/**< Tick count for the adapter, at its resolution */
+};
+
+struct rte_event_timer_adapter;
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Callback function type for producer port creation.
+ */
+typedef int (*rte_event_timer_adapter_port_conf_cb_t)(uint16_t id,
+						      uint8_t event_dev_id,
+						      uint8_t *event_port_id,
+						      void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create an event timer adapter.
+ *
+ * This function must be invoked first before any other function in the API.
+ *
+ * @param conf
+ *   The event timer adapter configuration structure.
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ *   - EIO: event device reconfiguration and restart error.  The adapter
+ *   reconfigures the event device with an additional port by default if it is
+ *   required to use a service to manage timers. If the device had been started
+ *   before this call, this error code indicates an error in restart following
+ *   an error in reconfiguration, i.e., a combination of the two error codes.
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create a timer adapter with the supplied callback.
+ *
+ * This function can be used to have a more granular control over the timer
+ * adapter creation.  If a built-in port is absent, then the function uses the
+ * callback provided to create and get the port id to be used as a producer
+ * port.
+ *
+ * @param conf
+ *   The timer adapter configuration structure
+ * @param conf_cb
+ *   The port config callback function.
+ * @param conf_arg
+ *   Opaque pointer to the argument for the callback function
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter info structure.
+ */
+struct rte_event_timer_adapter_info {
+	uint64_t min_resolution_ns;
+	/**< Minimum timer adapter resolution in ns */
+	uint64_t resolution_ns;
+	/**< Actual timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expire) in ns */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configured timer adapter attributes */
+	uint32_t caps;
+	/**< Event timer adapter capabilities */
+	int16_t event_dev_port_id;
+	/**< Event device port ID, if applicable */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve the contextual information of an event timer adapter.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @param[out] adapter_info
+ *   A pointer to a structure of type *rte_event_timer_adapter_info* to be
+ *   filled with the contextual information of the adapter.
+ *
+ * @return
+ *   - 0: Success, driver updates the contextual information of the
+ *   timer adapter
+ *   - <0: Error code returned by the driver info get function.
+ *   - -EINVAL: adapter identifier invalid
+ *
+ * @see RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES,
+ *   struct rte_event_timer_adapter_info
+ *
+ */
+int __rte_experimental
+rte_event_timer_adapter_get_info(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Start a timer adapter.
+ *
+ * The adapter start step is the last one and consists of setting the timer
+ * adapter to start accepting the timers and schedules to event queues.
+ *
+ * On success, all basic functions exported by the API (timer arm,
+ * timer cancel and so on) can be invoked.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter started.
+ *   - <0: Error code returned by the driver start function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_start(
+		const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Stop an event timer adapter.
+ *
+ * The adapter can be restarted with a call to
+ * ``rte_event_timer_adapter_start()``.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter stopped.
+ *   - <0: Error code returned by the driver stop function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Lookup an event timer adapter using its identifier.
+ *
+ * If an event timer adapter was created in another process with the same
+ * identifier, this function will locate its state and set up access to it
+ * so that it can be used in this process.
+ *
+ * @param adapter_id
+ *  The event timer adapter identifier.
+ *
+ * @return
+ *  A pointer to the event timer adapter matching the identifier on success.
+ *  NULL on error with rte_errno set appropriately.
+ *  Possible rte_errno values include:
+ *   - ENOENT - requested entry not available to return.
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_lookup(uint16_t adapter_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Free an event timer adapter.
+ *
+ * Destroy an event timer adapter, freeing all resources.
+ *
+ * Before invoking this function, the application must wait for all the
+ * armed timers to expire or cancel the outstanding armed timers.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully freed the event timer adapter resources.
+ *   - <0: Failed to free the event timer adapter resources.
+ *   - -EAGAIN:  adapter is busy; timers outstanding
+ *   - -EBUSY: stop hasn't been called for this adapter yet
+ *   - -EINVAL: adapter id invalid, or adapter invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter);
+
+/**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure
+ *   - -ESRCH: the adapter does not require a service to operate
+ */
+int __rte_experimental
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param[out] stats
+ *   A pointer to a structure to fill with statistics.
+ *
+ * @return
+ *   - 0: Successfully retrieved.
+ *   - <0: Failure; error code returned.
+ */
+int __rte_experimental
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully reset;
+ *   - <0: Failure; error code returned.
+ */
+int __rte_experimental rte_event_timer_adapter_stats_reset(
+		struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer state.
+ */
+enum rte_event_timer_state {
+	RTE_EVENT_TIMER_NOT_ARMED	= 0,
+	/**< Event timer not armed. */
+	RTE_EVENT_TIMER_ARMED		= 1,
+	/**< Event timer successfully armed. */
+	RTE_EVENT_TIMER_CANCELED	= 2,
+	/**< Event timer successfully canceled. */
+	RTE_EVENT_TIMER_ERROR		= -1,
+	/**< Generic event timer error. */
+	RTE_EVENT_TIMER_ERROR_TOOEARLY	= -2,
+	/**< Event timer timeout tick value is too small for the adapter to
+	 * handle, given its configured resolution.
+	 */
+	RTE_EVENT_TIMER_ERROR_TOOLATE	= -3,
+	/**< Event timer timeout tick is greater than the maximum timeout.*/
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * The generic *rte_event_timer* structure to hold the event timer attributes
+ * for arm and cancel operations.
+ */
+RTE_STD_C11
+struct rte_event_timer {
+	struct rte_event ev;
+	/**<
+	 * Expiry event attributes.  On successful event timer timeout,
+	 * the following attributes will be used to inject the expiry event to
+	 * the eventdev:
+	 *  - event_queue_id: Targeted event queue id for expiry events.
+	 *  - event_priority: Event priority of the event expiry event in the
+	 *  event queue relative to other events.
+	 *  - sched_type: Scheduling type of the expiry event.
+	 *  - flow_id: Flow id of the expiry event.
+	 *  - op: RTE_EVENT_OP_NEW
+	 *  - event_type: RTE_EVENT_TYPE_TIMER
+	 */
+	volatile enum rte_event_timer_state state;
+	/**< State of the event timer. */
+	uint64_t timeout_ticks;
+	/**< Expiry timer ticks expressed in number of *timer_ticks_ns* from
+	 * now.
+	 * @see struct rte_event_timer_adapter_info::adapter_conf::timer_tick_ns
+	 */
+	uint64_t impl_opaque[2];
+	/**< Implementation-specific opaque data.
+	 * An event timer adapter implementation use this field to hold
+	 * implementation specific values to share between the arm and cancel
+	 * operations.  The application should not modify this field.
+	 */
+	uint8_t user_meta[0];
+	/**< Memory to store user specific metadata.
+	 * The event timer adapter implementation should not modify this area.
+	 */
+} __rte_cache_aligned;
+
+typedef uint16_t (*rte_event_timer_arm_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Enable event timers to enqueue timer events upon expiry */
+typedef uint16_t (*rte_event_timer_arm_tmo_tick_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint64_t timeout_tick,
+		uint16_t nb_tims);
+/**< @internal Enable event timers with common expiration time */
+typedef uint16_t (*rte_event_timer_cancel_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Prevent event timers from enqueuing timer events */
+
+/**
+ * @internal Data structure associated with each event timer adapter.
+ */
+struct rte_event_timer_adapter {
+	rte_event_timer_arm_burst_t arm_burst;
+	/**< Pointer to driver arm_burst function. */
+	rte_event_timer_arm_tmo_tick_burst_t arm_tmo_tick_burst;
+	/**< Pointer to driver arm_tmo_tick_burst function. */
+	rte_event_timer_cancel_burst_t cancel_burst;
+	/**< Pointer to driver cancel function. */
+	struct rte_event_timer_adapter_data *data;
+	/**< Pointer to shared adapter data */
+	const struct rte_event_timer_adapter_ops *ops;
+	/**< Functions exported by adapter driver */
+
+	RTE_STD_C11
+	uint8_t allocated : 1;
+	/**< Flag to indicate that this adapter has been allocated */
+} __rte_cache_aligned;
+
+#define ADAPTER_VALID_OR_ERR_RET(adapter, retval) do { \
+	if (adapter == NULL || !adapter->allocated)    \
+		return retval;			       \
+} while (0)
+#define FUNC_PTR_OR_ERR_RET(func, errval) do { \
+	if ((func) == NULL)		       \
+		return errval;		       \
+} while (0)
+
+#define FUNC_PTR_OR_NULL_RET_WITH_ERRNO(func, errval) do { \
+	if ((func) == NULL) {				   \
+		rte_errno = errval;			   \
+		return NULL;				   \
+	}						   \
+} while (0)
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with separate expiration timeout tick for each
+ * event timer.
+ *
+ * Before calling this function, the application allocates
+ * ``struct rte_event_timer`` objects from mempool or huge page backed
+ * application buffers of desired size. On successful allocation,
+ * application updates the `struct rte_event_timer`` attributes such as
+ * expiry event attributes, timeout ticks from now.
+ * This function submits the event timer arm requests to the event timer adapter
+ * and on expiry, the events will be injected to designated event queue.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Pointer to an array of objects of type *rte_event_timer* structure.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_evtims* parameter. If the return value is less
+ *   than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
+ *   expiry event's sched type doesn't match the capabilities of the
+ *   destination event queue.
+ *   - EAGAIN Specified timer adapter is not running
+ *   - EALREADY A timer was encountered that was already armed
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **evtims,
+			  uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_burst, -EINVAL);
+#endif
+
+	return adapter->arm_burst(adapter, evtims, nb_evtims);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with same expiration timeout tick.
+ *
+ * Provides the same functionality as ``rte_event_timer_arm_burst()``, except
+ * that application can use this API when all the event timers have the
+ * same timeout expiration tick. This specialized function can provide the
+ * additional hint to the adapter implementation and optimize if possible.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Points to an array of objects of type *rte_event_timer* structure.
+ * @param timeout_ticks
+ *   The number of ticks in which the timers should expire.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_evtims* parameter. If the return value is less
+ *   than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
+ *   expiry event's sched type doesn't match the capabilities of the
+ *   destination event queue.
+ *   - EAGAIN Specified event timer adapter is not running
+ *   - EALREADY A timer was encountered that was already armed
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_arm_tmo_tick_burst(
+			const struct rte_event_timer_adapter *adapter,
+			struct rte_event_timer **evtims,
+			const uint64_t timeout_ticks,
+			const uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_tmo_tick_burst, -EINVAL);
+#endif
+
+	return adapter->arm_tmo_tick_burst(adapter, evtims, timeout_ticks,
+					   nb_evtims);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Cancel a burst of event timers from being scheduled to the event device.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Points to an array of objects of type *rte_event_timer* structure
+ * @param nb_evtims
+ *   Number of event timer instances in the supplied array.
+ *
+ * @return
+ *   The number of successfully canceled event timers. The return value can be
+ *   less than the value of the *nb_evtims* parameter. If the return value is
+ *   less than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter identifier
+ *   - EAGAIN Specified timer adapter is not running
+ *   - EALREADY  A timer was encountered that was already canceled
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			     struct rte_event_timer **evtims,
+			     uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->cancel_burst, -EINVAL);
+#endif
+
+	return adapter->cancel_burst(adapter, evtims, nb_evtims);
+}
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index a20077c..a1f0749 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -969,8 +969,8 @@ rte_event_dev_close(uint8_t dev_id);
 /**< The event generated from ethdev subsystem */
 #define RTE_EVENT_TYPE_CRYPTODEV        0x1
 /**< The event generated from crypodev subsystem */
-#define RTE_EVENT_TYPE_TIMERDEV         0x2
-/**< The event generated from timerdev subsystem */
+#define RTE_EVENT_TYPE_TIMER		0x2
+/**< The event generated from event timer adapter */
 #define RTE_EVENT_TYPE_CPU              0x3
 /**< The event generated from cpu for pipelining.
  * Application may use *sub_event_type* to further classify the event
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 2/9] eventdev: convert to SPDX license tag in header
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
  2018-04-03 21:44             ` [PATCH v10 1/9] " Erik Gabriel Carrillo
@ 2018-04-03 21:44             ` Erik Gabriel Carrillo
  2018-04-03 21:44             ` [PATCH v10 3/9] eventtimer: add common code Erik Gabriel Carrillo
                               ` (8 subsequent siblings)
  10 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-03 21:44 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 lib/librte_eventdev/rte_eventdev.h | 37 +++++--------------------------------
 1 file changed, 5 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index a1f0749..86df4be 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -1,35 +1,8 @@
-/*
- *   BSD LICENSE
- *
- *   Copyright 2016 Cavium, Inc.
- *   Copyright 2016 Intel Corporation.
- *   Copyright 2016 NXP.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Cavium, Inc nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2016 Cavium, Inc.
+ * Copyright(c) 2016-2018 Intel Corporation.
+ * Copyright 2016 NXP
+ * All rights reserved.
  */
 
 #ifndef _RTE_EVENTDEV_H_
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 3/9] eventtimer: add common code
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
  2018-04-03 21:44             ` [PATCH v10 1/9] " Erik Gabriel Carrillo
  2018-04-03 21:44             ` [PATCH v10 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
@ 2018-04-03 21:44             ` Erik Gabriel Carrillo
  2018-04-04 16:50               ` Pavan Nikhilesh
  2018-04-03 21:44             ` [PATCH v10 4/9] mk: update library order in static build Erik Gabriel Carrillo
                               ` (7 subsequent siblings)
  10 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-03 21:44 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev, hemant.agrawal

This commit adds the logic that is shared by all event timer adapter
drivers; the common code handles instance allocation and some
initialization.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 config/common_base                                |   1 +
 drivers/event/sw/sw_evdev.c                       |  18 +
 lib/librte_eventdev/Makefile                      |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c     | 387 ++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 114 +++++++
 lib/librte_eventdev/rte_eventdev.c                |  22 ++
 lib/librte_eventdev/rte_eventdev.h                |  20 ++
 lib/librte_eventdev/rte_eventdev_pmd.h            |  35 ++
 lib/librte_eventdev/rte_eventdev_version.map      |  20 +-
 9 files changed, 618 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h

diff --git a/config/common_base b/config/common_base
index 7abf7c6..9354c66 100644
--- a/config/common_base
+++ b/config/common_base
@@ -550,6 +550,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
 CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
 CONFIG_RTE_EVENT_MAX_DEVS=16
 CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32
 
 #
 # Compile PMD for skeleton event device
diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index 0e89f11..dcb6551 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -464,6 +464,22 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
 	return 0;
 }
 
+static int
+sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
+			  uint64_t flags,
+			  uint32_t *caps,
+			  const struct rte_event_timer_adapter_ops **ops)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(flags);
+	*caps = 0;
+
+	/* Use default SW ops */
+	*ops = NULL;
+
+	return 0;
+}
+
 static void
 sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
 {
@@ -791,6 +807,8 @@ sw_probe(struct rte_vdev_device *vdev)
 
 			.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
 
+			.timer_adapter_caps_get = sw_timer_adapter_caps_get,
+
 			.xstats_get = sw_xstats_get,
 			.xstats_get_names = sw_xstats_get_names,
 			.xstats_get_by_name = sw_xstats_get_by_name,
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 549b182..8b16e3f 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -20,6 +20,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
 SRCS-y += rte_eventdev.c
 SRCS-y += rte_event_ring.c
 SRCS-y += rte_event_eth_rx_adapter.c
+SRCS-y += rte_event_timer_adapter.c
 
 # export include files
 SYMLINK-y-include += rte_eventdev.h
@@ -29,6 +30,7 @@ SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
 SYMLINK-y-include += rte_event_timer_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter_pmd.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
new file mode 100644
index 0000000..75a14ac
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -0,0 +1,387 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#include <string.h>
+#include <inttypes.h>
+
+#include <rte_memzone.h>
+#include <rte_memory.h>
+#include <rte_dev.h>
+#include <rte_errno.h>
+
+#include "rte_eventdev.h"
+#include "rte_eventdev_pmd.h"
+#include "rte_event_timer_adapter.h"
+#include "rte_event_timer_adapter_pmd.h"
+
+#define DATA_MZ_NAME_MAX_LEN 64
+#define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
+
+static int evtim_logtype;
+
+static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
+
+#define EVTIM_LOG(level, logtype, ...) \
+	rte_log(RTE_LOG_ ## level, logtype, \
+		RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
+			"\n", __func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__,)))
+
+#define EVTIM_LOG_ERR(...) EVTIM_LOG(ERR, evtim_logtype, __VA_ARGS__)
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+#define EVTIM_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#else
+#define EVTIM_LOG_DBG(...) (void)0
+#endif
+
+static int
+default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		     void *conf_arg)
+{
+	struct rte_event_timer_adapter *adapter;
+	struct rte_eventdev *dev;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	int started;
+	uint8_t port_id;
+	uint8_t dev_id;
+	int ret;
+
+	RTE_SET_USED(event_dev_id);
+
+	adapter = &adapters[id];
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+	dev_id = dev->data->dev_id;
+	dev_conf = dev->data->dev_conf;
+
+	started = dev->data->dev_started;
+	if (started)
+		rte_event_dev_stop(dev_id);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports += 1;
+	ret = rte_event_dev_configure(dev_id, &dev_conf);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to configure event dev %u\n", dev_id);
+		if (started)
+			if (rte_event_dev_start(dev_id))
+				return -EIO;
+
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(dev_id, port_id, port_conf);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to setup event port %u on event dev %u\n",
+			      port_id, dev_id);
+		return ret;
+	}
+
+	*event_port_id = port_id;
+
+	if (started)
+		ret = rte_event_dev_start(dev_id);
+
+	return ret;
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf)
+{
+	return rte_event_timer_adapter_create_ext(conf, default_port_conf_cb,
+						  NULL);
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg)
+{
+	uint16_t adapter_id;
+	struct rte_event_timer_adapter *adapter;
+	const struct rte_memzone *mz;
+	char mz_name[DATA_MZ_NAME_MAX_LEN];
+	int n, ret;
+	struct rte_eventdev *dev;
+
+	if (conf == NULL) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Check eventdev ID */
+	if (!rte_event_pmd_is_valid_dev(conf->event_dev_id)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	dev = &rte_eventdevs[conf->event_dev_id];
+
+	adapter_id = conf->timer_adapter_id;
+
+	/* Check that adapter_id is in range */
+	if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Check adapter ID not already allocated */
+	adapter = &adapters[adapter_id];
+	if (adapter->allocated) {
+		rte_errno = EEXIST;
+		return NULL;
+	}
+
+	/* Create shared data area. */
+	n = snprintf(mz_name, sizeof(mz_name), DATA_MZ_NAME_FORMAT, adapter_id);
+	if (n >= (int)sizeof(mz_name)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	mz = rte_memzone_reserve(mz_name,
+				 sizeof(struct rte_event_timer_adapter_data),
+				 conf->socket_id, 0);
+	if (mz == NULL)
+		/* rte_errno set by rte_memzone_reserve */
+		return NULL;
+
+	adapter->data = mz->addr;
+	memset(adapter->data, 0, sizeof(struct rte_event_timer_adapter_data));
+
+	adapter->data->mz = mz;
+	adapter->data->event_dev_id = conf->event_dev_id;
+	adapter->data->id = adapter_id;
+	adapter->data->socket_id = conf->socket_id;
+	adapter->data->conf = *conf;  /* copy conf structure */
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = ret;
+		goto free_memzone;
+	}
+
+	if (!(adapter->data->caps &
+	      RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+		FUNC_PTR_OR_NULL_RET_WITH_ERRNO(conf_cb, -EINVAL);
+		ret = conf_cb(adapter->data->id, adapter->data->event_dev_id,
+			      &adapter->data->event_port_id, conf_arg);
+		if (ret < 0) {
+			rte_errno = ret;
+			goto free_memzone;
+		}
+	}
+
+	/* Allow driver to do some setup */
+	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
+	ret = adapter->ops->init(adapter);
+	if (ret < 0) {
+		rte_errno = ret;
+		goto free_memzone;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+
+free_memzone:
+	rte_memzone_free(adapter->data->mz);
+	return NULL;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->ops->get_info)
+		/* let driver set values it knows */
+		adapter->ops->get_info(adapter, adapter_info);
+
+	/* Set common values */
+	adapter_info->conf = adapter->data->conf;
+	adapter_info->event_dev_port_id = adapter->data->event_port_id;
+	adapter_info->caps = adapter->data->caps;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->start, -EINVAL);
+
+	ret = adapter->ops->start(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 1;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stop, -EINVAL);
+
+	if (adapter->data->started == 0) {
+		EVTIM_LOG_ERR("event timer adapter %"PRIu8" already stopped",
+			      adapter->data->id);
+		return 0;
+	}
+
+	ret = adapter->ops->stop(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 0;
+
+	return 0;
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_lookup(uint16_t adapter_id)
+{
+	char name[DATA_MZ_NAME_MAX_LEN];
+	const struct rte_memzone *mz;
+	struct rte_event_timer_adapter_data *data;
+	struct rte_event_timer_adapter *adapter;
+	int ret;
+	struct rte_eventdev *dev;
+
+	if (adapters[adapter_id].allocated)
+		return &adapters[adapter_id]; /* Adapter is already loaded */
+
+	snprintf(name, DATA_MZ_NAME_MAX_LEN, DATA_MZ_NAME_FORMAT, adapter_id);
+	mz = rte_memzone_lookup(name);
+	if (mz == NULL) {
+		rte_errno = ENOENT;
+		return NULL;
+	}
+
+	data = mz->addr;
+
+	adapter = &adapters[data->id];
+	adapter->data = data;
+
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->uninit, -EINVAL);
+
+	if (adapter->data->started == 1) {
+		EVTIM_LOG_ERR("event timer adapter %"PRIu8" must be stopped "
+			      "before freeing", adapter->data->id);
+		return -EBUSY;
+	}
+
+	/* free impl priv data */
+	ret = adapter->ops->uninit(adapter);
+	if (ret < 0)
+		return ret;
+
+	/* free shared data area */
+	ret = rte_memzone_free(adapter->data->mz);
+	if (ret < 0)
+		return ret;
+
+	adapter->data = NULL;
+	adapter->allocated = 0;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->data->service_inited && service_id != NULL)
+		*service_id = adapter->data->service_id;
+
+	return adapter->data->service_inited ? 0 : -ESRCH;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer_adapter_stats *stats)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_get, -EINVAL);
+	if (stats == NULL)
+		return -EINVAL;
+
+	return adapter->ops->stats_get(adapter, stats);
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_reset, -EINVAL);
+	return adapter->ops->stats_reset(adapter);
+}
+
+RTE_INIT(event_timer_adapter_init_log);
+static void
+event_timer_adapter_init_log(void)
+{
+	evtim_logtype = rte_log_register("lib.eventdev.adapter.timer");
+	if (evtim_logtype >= 0)
+		rte_log_set_level(evtim_logtype, RTE_LOG_NOTICE);
+}
diff --git a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
new file mode 100644
index 0000000..cf3509d
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_PMD_H__
+#define __RTE_EVENT_TIMER_ADAPTER_PMD_H__
+
+/**
+ * @file
+ * RTE Event Timer Adapter API (PMD Side)
+ *
+ * @note
+ * This file provides implementation helpers for internal use by PMDs.  They
+ * are not intended to be exposed to applications and are not subject to ABI
+ * versioning.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "rte_event_timer_adapter.h"
+
+/*
+ * Definitions of functions exported by an event timer adapter implementation
+ * through *rte_event_timer_adapter_ops* structure supplied in the
+ * *rte_event_timer_adapter* structure associated with an event timer adapter.
+ */
+
+typedef int (*rte_event_timer_adapter_init_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation setup */
+typedef int (*rte_event_timer_adapter_uninit_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation teardown */
+typedef int (*rte_event_timer_adapter_start_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Start running event timer adapter */
+typedef int (*rte_event_timer_adapter_stop_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Stop running event timer adapter */
+typedef void (*rte_event_timer_adapter_get_info_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+/**< @internal Get contextual information for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_get_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_stats *stats);
+/**< @internal Get statistics for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_reset_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Reset statistics for event timer adapter */
+
+/**
+ * @internal Structure containing the functions exported by an event timer
+ * adapter implementation.
+ */
+struct rte_event_timer_adapter_ops {
+	rte_event_timer_adapter_init_t		init;  /**< Set up adapter */
+	rte_event_timer_adapter_uninit_t	uninit;/**< Tear down adapter */
+	rte_event_timer_adapter_start_t		start; /**< Start adapter */
+	rte_event_timer_adapter_stop_t		stop;  /**< Stop adapter */
+	rte_event_timer_adapter_get_info_t	get_info;
+	/**< Get info from driver */
+	rte_event_timer_adapter_stats_get_t	stats_get;
+	/**< Get adapter statistics */
+	rte_event_timer_adapter_stats_reset_t	stats_reset;
+	/**< Reset adapter statistics */
+	rte_event_timer_arm_burst_t		arm_burst;
+	/**< Arm one or more event timers */
+	rte_event_timer_arm_tmo_tick_burst_t	arm_tmo_tick_burst;
+	/**< Arm event timers with same expiration time */
+	rte_event_timer_cancel_burst_t		cancel_burst;
+	/**< Cancel one or more event timers */
+};
+
+/**
+ * @internal Adapter data; structure to be placed in shared memory to be
+ * accessible by various processes in a multi-process configuration.
+ */
+struct rte_event_timer_adapter_data {
+	uint8_t id;
+	/**< Event timer adapter ID */
+	uint8_t event_dev_id;
+	/**< Event device ID */
+	uint32_t socket_id;
+	/**< Socket ID where memory is allocated */
+	uint8_t event_port_id;
+	/**< Optional: event port ID used when the inbuilt port is absent */
+	const struct rte_memzone *mz;
+	/**< Event timer adapter memzone pointer */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configuration used to configure the adapter. */
+	uint32_t caps;
+	/**< Adapter capabilities */
+	void *adapter_priv;
+	/**< Timer adapter private data*/
+	uint8_t service_inited;
+	/**< Service initialization state */
+	uint32_t service_id;
+	/**< Service ID*/
+
+	RTE_STD_C11
+	uint8_t started : 1;
+	/**< Flag to indicate adapter started. */
+} __rte_cache_aligned;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_PMD_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.c b/lib/librte_eventdev/rte_eventdev.c
index 2de8d9a..3f016f4 100644
--- a/lib/librte_eventdev/rte_eventdev.c
+++ b/lib/librte_eventdev/rte_eventdev.c
@@ -123,6 +123,28 @@ rte_event_eth_rx_adapter_caps_get(uint8_t dev_id, uint8_t eth_port_id,
 				: 0;
 }
 
+int __rte_experimental
+rte_event_timer_adapter_caps_get(uint8_t dev_id, uint32_t *caps)
+{
+	struct rte_eventdev *dev;
+	const struct rte_event_timer_adapter_ops *ops;
+
+	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+
+	dev = &rte_eventdevs[dev_id];
+
+	if (caps == NULL)
+		return -EINVAL;
+	*caps = 0;
+
+	return dev->dev_ops->timer_adapter_caps_get ?
+				(*dev->dev_ops->timer_adapter_caps_get)(dev,
+									0,
+									caps,
+									&ops)
+				: 0;
+}
+
 static inline int
 rte_event_dev_queue_config(struct rte_eventdev *dev, uint8_t nb_queues)
 {
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index 86df4be..6fcbe94 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -215,6 +215,7 @@ extern "C" {
 #include <rte_config.h>
 #include <rte_memory.h>
 #include <rte_errno.h>
+#include <rte_compat.h>
 
 struct rte_mbuf; /* we just use mbuf pointers; no need to include rte_mbuf.h */
 struct rte_event;
@@ -1115,6 +1116,25 @@ int
 rte_event_eth_rx_adapter_caps_get(uint8_t dev_id, uint8_t eth_port_id,
 				uint32_t *caps);
 
+#define RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT (1ULL << 0)
+/**< This flag is set when the timer mechanism is in HW. */
+
+/**
+ * Retrieve the event device's timer adapter capabilities.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ *
+ * @param[out] caps
+ *   A pointer to memory to be filled with event timer adapter capabilities.
+ *
+ * @return
+ *   - 0: Success, driver provided event timer adapter capabilities.
+ *   - <0: Error code returned by the driver function.
+ */
+int __rte_experimental
+rte_event_timer_adapter_caps_get(uint8_t dev_id, uint32_t *caps);
+
 struct rte_eventdev_driver;
 struct rte_eventdev_ops;
 struct rte_eventdev;
diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h b/lib/librte_eventdev/rte_eventdev_pmd.h
index 3a8ddd7..2dcb528 100644
--- a/lib/librte_eventdev/rte_eventdev_pmd.h
+++ b/lib/librte_eventdev/rte_eventdev_pmd.h
@@ -26,6 +26,7 @@ extern "C" {
 #include <rte_malloc.h>
 
 #include "rte_eventdev.h"
+#include "rte_event_timer_adapter_pmd.h"
 
 /* Logging Macros */
 #define RTE_EDEV_LOG_ERR(...) \
@@ -449,6 +450,37 @@ typedef int (*eventdev_eth_rx_adapter_caps_get_t)
 struct rte_event_eth_rx_adapter_queue_conf *queue_conf;
 
 /**
+ * Retrieve the event device's timer adapter capabilities, as well as the ops
+ * structure that an event timer adapter should call through to enter the
+ * driver
+ *
+ * @param dev
+ *   Event device pointer
+ *
+ * @param flags
+ *   Flags that can be used to determine how to select an event timer
+ *   adapter ops structure
+ *
+ * @param[out] caps
+ *   A pointer to memory filled with Rx event adapter capabilities.
+ *
+ * @param[out] ops
+ *   A pointer to the ops pointer to set with the address of the desired ops
+ *   structure
+ *
+ * @return
+ *   - 0: Success, driver provides Rx event adapter capabilities for the
+ *	ethernet device.
+ *   - <0: Error code returned by the driver function.
+ *
+ */
+typedef int (*eventdev_timer_adapter_caps_get_t)(
+				const struct rte_eventdev *dev,
+				uint64_t flags,
+				uint32_t *caps,
+				const struct rte_event_timer_adapter_ops **ops);
+
+/**
  * Add ethernet Rx queues to event device. This callback is invoked if
  * the caps returned from rte_eventdev_eth_rx_adapter_caps_get(, eth_port_id)
  * has RTE_EVENT_ETH_RX_ADAPTER_CAP_INTERNAL_PORT set.
@@ -640,6 +672,9 @@ struct rte_eventdev_ops {
 	eventdev_eth_rx_adapter_stats_reset eth_rx_adapter_stats_reset;
 	/**< Reset ethernet Rx stats */
 
+	eventdev_timer_adapter_caps_get_t timer_adapter_caps_get;
+	/**< Get timer adapter capabilities */
+
 	eventdev_selftest dev_selftest;
 	/**< Start eventdev Selftest */
 
diff --git a/lib/librte_eventdev/rte_eventdev_version.map b/lib/librte_eventdev/rte_eventdev_version.map
index 4396536..6979577 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -66,7 +66,6 @@ DPDK_17.11 {
 	rte_event_eth_rx_adapter_stats_get;
 	rte_event_eth_rx_adapter_stats_reset;
 	rte_event_eth_rx_adapter_stop;
-
 } DPDK_17.08;
 
 DPDK_18.02 {
@@ -80,3 +79,22 @@ DPDK_18.05 {
 
 	rte_event_dev_stop_flush_callback_register;
 } DPDK_18.02;
+
+EXPERIMENTAL {
+	global:
+
+        rte_event_timer_adapter_caps_get;
+	rte_event_timer_adapter_create;
+	rte_event_timer_adapter_create_ext;
+	rte_event_timer_adapter_free;
+	rte_event_timer_adapter_get_info;
+	rte_event_timer_adapter_lookup;
+	rte_event_timer_adapter_service_id_get;
+	rte_event_timer_adapter_start;
+	rte_event_timer_adapter_stats_get;
+	rte_event_timer_adapter_stats_reset;
+	rte_event_timer_adapter_stop;
+	rte_event_timer_arm_burst;
+	rte_event_timer_arm_tmo_tick_burst;
+	rte_event_timer_cancel_burst;
+} DPDK_18.05;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 4/9] mk: update library order in static build
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
                               ` (2 preceding siblings ...)
  2018-04-03 21:44             ` [PATCH v10 3/9] eventtimer: add common code Erik Gabriel Carrillo
@ 2018-04-03 21:44             ` Erik Gabriel Carrillo
  2018-04-03 21:44             ` [PATCH v10 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
                               ` (6 subsequent siblings)
  10 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-03 21:44 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev, hemant.agrawal

The introduction of the event timer adapter library adds a dependency
on the rte_timer library from the rte_eventdev library.  Update the
order so that the timer library comes after the eventdev library in the
linker command when statically linking applications.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 mk/rte.app.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index a9b4b05..01d0b4e 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)        += -lrte_bitratestats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
 
-_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
 
 _LDLIBS-y += --whole-archive
@@ -98,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)       += -lrte_security
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV)         += -lrte_rawdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 5/9] eventtimer: add default software driver
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
                               ` (3 preceding siblings ...)
  2018-04-03 21:44             ` [PATCH v10 4/9] mk: update library order in static build Erik Gabriel Carrillo
@ 2018-04-03 21:44             ` Erik Gabriel Carrillo
  2018-04-03 21:44             ` [PATCH v10 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
                               ` (5 subsequent siblings)
  10 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-03 21:44 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev, hemant.agrawal

If an eventdev PMD does not wish to provide event timer adapter ops
definitions, the library will fall back to a default software
implementation whose entry points are added by this commit.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
---
 lib/Makefile                                  |   2 +-
 lib/librte_eventdev/Makefile                  |   2 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 909 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h |  57 +-
 4 files changed, 966 insertions(+), 4 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a6..965be6c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -31,7 +31,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
 DEPDIRS-librte_security += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash
+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_RAWDEV) += librte_rawdev
 DEPDIRS-librte_rawdev := librte_eal librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 8b16e3f..297df4a 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -14,7 +14,7 @@ LIBABIVER := 3
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool -lrte_timer
 
 # library source files
 SRCS-y += rte_eventdev.c
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 75a14ac..968c18b 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -5,11 +5,20 @@
 
 #include <string.h>
 #include <inttypes.h>
+#include <stdbool.h>
+#include <sys/queue.h>
 
 #include <rte_memzone.h>
 #include <rte_memory.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_common.h>
+#include <rte_timer.h>
+#include <rte_service_component.h>
+#include <rte_cycles.h>
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -20,9 +29,13 @@
 #define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
 
 static int evtim_logtype;
+static int evtim_svc_logtype;
+static int evtim_buffer_logtype;
 
 static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 
+static const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+
 #define EVTIM_LOG(level, logtype, ...) \
 	rte_log(RTE_LOG_ ## level, logtype, \
 		RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
@@ -33,8 +46,14 @@ static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 #ifdef RTE_LIBRTE_EVENTDEV_DEBUG
 #define EVTIM_LOG_DBG(...) \
 	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#define EVTIM_BUF_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_buffer_logtype, __VA_ARGS__)
+#define EVTIM_SVC_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_svc_logtype, __VA_ARGS__)
 #else
 #define EVTIM_LOG_DBG(...) (void)0
+#define EVTIM_BUF_LOG_DBG(...) (void)0
+#define EVTIM_SVC_LOG_DBG(...) (void)0
 #endif
 
 static int
@@ -188,6 +207,12 @@ rte_event_timer_adapter_create_ext(
 		}
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Allow driver to do some setup */
 	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
 	ret = adapter->ops->init(adapter);
@@ -305,6 +330,12 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
 		return NULL;
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Set fast-path function pointers */
 	adapter->arm_burst = adapter->ops->arm_burst;
 	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
@@ -377,6 +408,875 @@ rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
 	return adapter->ops->stats_reset(adapter);
 }
 
+/*
+ * Software event timer adapter buffer helper functions
+ */
+
+#define NSECPERSEC 1E9
+
+/* Optimizations used to index into the buffer require that the buffer size
+ * be a power of 2.
+ */
+#define EVENT_BUFFER_SZ 4096
+#define EVENT_BUFFER_BATCHSZ 32
+#define EVENT_BUFFER_MASK (EVENT_BUFFER_SZ - 1)
+
+struct event_buffer {
+	uint16_t head;
+	uint16_t tail;
+	struct rte_event events[EVENT_BUFFER_SZ];
+} __rte_cache_aligned;
+
+static inline bool
+event_buffer_full(struct event_buffer *bufp)
+{
+	return (bufp->head - bufp->tail) == EVENT_BUFFER_SZ;
+}
+
+static inline bool
+event_buffer_batch_ready(struct event_buffer *bufp)
+{
+	return (bufp->head - bufp->tail) >= EVENT_BUFFER_BATCHSZ;
+}
+
+static void
+event_buffer_init(struct event_buffer *bufp)
+{
+	bufp->head = bufp->tail = 0;
+	memset(&bufp->events, 0, sizeof(struct rte_event) * EVENT_BUFFER_SZ);
+}
+
+static int
+event_buffer_add(struct event_buffer *bufp, struct rte_event *eventp)
+{
+	uint16_t head_idx;
+	struct rte_event *buf_eventp;
+
+	if (event_buffer_full(bufp))
+		return -1;
+
+	/* Instead of modulus, bitwise AND with mask to get head_idx. */
+	head_idx = bufp->head & EVENT_BUFFER_MASK;
+	buf_eventp = &bufp->events[head_idx];
+	rte_memcpy(buf_eventp, eventp, sizeof(struct rte_event));
+
+	/* Wrap automatically when overflow occurs. */
+	bufp->head++;
+
+	return 0;
+}
+
+static void
+event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,
+		   uint16_t *nb_events_flushed,
+		   uint16_t *nb_events_inv)
+{
+	uint16_t head_idx, tail_idx, n = 0;
+	struct rte_event *events = bufp->events;
+
+	/* Instead of modulus, bitwise AND with mask to get index. */
+	head_idx = bufp->head & EVENT_BUFFER_MASK;
+	tail_idx = bufp->tail & EVENT_BUFFER_MASK;
+
+	/* Determine the largest contigous run we can attempt to enqueue to the
+	 * event device.
+	 */
+	if (head_idx > tail_idx)
+		n = head_idx - tail_idx;
+	else if (head_idx < tail_idx)
+		n = EVENT_BUFFER_SZ - tail_idx;
+	else {
+		*nb_events_flushed = 0;
+		return;
+	}
+
+	*nb_events_inv = 0;
+	*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
+						     &events[tail_idx], n);
+	if (*nb_events_flushed != n && rte_errno == -EINVAL) {
+		EVTIM_LOG_ERR("failed to enqueue invalid event - dropping it");
+		(*nb_events_inv)++;
+	}
+
+	bufp->tail = bufp->tail + *nb_events_flushed + *nb_events_inv;
+}
+
+/*
+ * Software event timer adapter implementation
+ */
+
+struct rte_event_timer_adapter_sw_data {
+	/* List of messages for outstanding timers */
+	TAILQ_HEAD(, msg) msgs_tailq_head;
+	/* Lock to guard tailq and armed count */
+	rte_spinlock_t msgs_tailq_sl;
+	/* Identifier of service executing timer management logic. */
+	uint32_t service_id;
+	/* The cycle count at which the adapter should next tick */
+	uint64_t next_tick_cycles;
+	/* Incremented as the service moves through phases of an iteration */
+	volatile int service_phase;
+	/* The tick resolution used by adapter instance. May have been
+	 * adjusted from what user requested
+	 */
+	uint64_t timer_tick_ns;
+	/* Maximum timeout in nanoseconds allowed by adapter instance. */
+	uint64_t max_tmo_ns;
+	/* Ring containing messages to arm or cancel event timers */
+	struct rte_ring *msg_ring;
+	/* Mempool containing msg objects */
+	struct rte_mempool *msg_pool;
+	/* Buffered timer expiry events to be enqueued to an event device. */
+	struct event_buffer buffer;
+	/* Statistics */
+	struct rte_event_timer_adapter_stats stats;
+	/* The number of threads currently adding to the message ring */
+	rte_atomic16_t message_producer_count;
+};
+
+enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
+
+struct msg {
+	enum msg_type type;
+	struct rte_event_timer *evtim;
+	struct rte_timer tim;
+	TAILQ_ENTRY(msg) msgs;
+};
+
+static void
+sw_event_timer_cb(struct rte_timer *tim, void *arg)
+{
+	int ret;
+	uint16_t nb_evs_flushed = 0;
+	uint16_t nb_evs_invalid = 0;
+	struct rte_event_timer *evtim;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	evtim = arg;
+	adapter = (struct rte_event_timer_adapter *)evtim->impl_opaque[1];
+	sw_data = adapter->data->adapter_priv;
+
+	ret = event_buffer_add(&sw_data->buffer, &evtim->ev);
+	if (ret < 0) {
+		/* If event buffer is full, put timer back in list with
+		 * immediate expiry value, so that we process it again on the
+		 * next iteration.
+		 */
+		rte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),
+				     sw_event_timer_cb, evtim);
+
+		sw_data->stats.evtim_retry_count++;
+		EVTIM_LOG_DBG("event buffer full, resetting rte_timer with "
+			      "immediate expiry value");
+	} else {
+		struct msg *m = container_of(tim, struct msg, tim);
+		TAILQ_REMOVE(&sw_data->msgs_tailq_head, m, msgs);
+		EVTIM_BUF_LOG_DBG("buffered an event timer expiry event");
+		evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+
+		/* Free the msg object containing the rte_timer now that
+		 * we've buffered its event successfully.
+		 */
+		rte_mempool_put(sw_data->msg_pool, m);
+
+		/* Bump the count when we successfully add an expiry event to
+		 * the buffer.
+		 */
+		sw_data->stats.evtim_exp_count++;
+	}
+
+	if (event_buffer_batch_ready(&sw_data->buffer)) {
+		event_buffer_flush(&sw_data->buffer,
+				   adapter->data->event_dev_id,
+				   adapter->data->event_port_id,
+				   &nb_evs_flushed,
+				   &nb_evs_invalid);
+
+		sw_data->stats.ev_enq_count += nb_evs_flushed;
+		sw_data->stats.ev_inv_count += nb_evs_invalid;
+	}
+}
+
+static __rte_always_inline uint64_t
+get_timeout_cycles(struct rte_event_timer *evtim,
+		   struct rte_event_timer_adapter *adapter)
+{
+	uint64_t timeout_ns;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	timeout_ns = evtim->timeout_ticks * sw_data->timer_tick_ns;
+	return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
+
+}
+
+/* This function returns true if one or more (adapter) ticks have occurred since
+ * the last time it was called.
+ */
+static inline bool
+adapter_did_tick(struct rte_event_timer_adapter *adapter)
+{
+	uint64_t cycles_per_adapter_tick, start_cycles;
+	uint64_t *next_tick_cyclesp;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	next_tick_cyclesp = &sw_data->next_tick_cycles;
+
+	cycles_per_adapter_tick = sw_data->timer_tick_ns *
+			(rte_get_timer_hz() / NSECPERSEC);
+
+	start_cycles = rte_get_timer_cycles();
+
+	/* Note: initially, *next_tick_cyclesp == 0, so the clause below will
+	 * execute, and set things going.
+	 */
+
+	if (start_cycles >= *next_tick_cyclesp) {
+		/* Snap the current cycle count to the preceding adapter tick
+		 * boundary.
+		 */
+		start_cycles -= start_cycles % cycles_per_adapter_tick;
+
+		*next_tick_cyclesp = start_cycles + cycles_per_adapter_tick;
+
+		return true;
+	}
+
+	return false;
+}
+
+/* Check that event timer timeout value is in range */
+static __rte_always_inline int
+check_timeout(struct rte_event_timer *evtim,
+	      const struct rte_event_timer_adapter *adapter)
+{
+	uint64_t tmo_nsec;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	tmo_nsec = evtim->timeout_ticks * sw_data->timer_tick_ns;
+
+	if (tmo_nsec > sw_data->max_tmo_ns)
+		return -1;
+
+	if (tmo_nsec < sw_data->timer_tick_ns)
+		return -2;
+
+	return 0;
+}
+
+/* Check that event timer event queue sched type matches destination event queue
+ * sched type
+ */
+static __rte_always_inline int
+check_destination_event_queue(struct rte_event_timer *evtim,
+			      const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	uint32_t sched_type;
+
+	ret = rte_event_queue_attr_get(adapter->data->event_dev_id,
+				       evtim->ev.queue_id,
+				       RTE_EVENT_QUEUE_ATTR_SCHEDULE_TYPE,
+				       &sched_type);
+
+	if ((ret < 0 && ret != -EOVERFLOW) ||
+	    evtim->ev.sched_type != sched_type)
+		return -1;
+
+	return 0;
+}
+
+#define NB_OBJS 32
+static int
+sw_event_timer_adapter_service_func(void *arg)
+{
+	int ret, i, num_msgs;
+	uint64_t cycles;
+	uint16_t nb_evs_flushed = 0;
+	uint16_t nb_evs_invalid = 0;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_timer *tim = NULL;
+	struct msg *msg, *msgs[NB_OBJS];
+
+	RTE_SET_USED(ret);
+
+	adapter = arg;
+	sw_data = adapter->data->adapter_priv;
+
+	sw_data->service_phase = 1;
+	rte_smp_wmb();
+
+	while (rte_atomic16_read(&sw_data->message_producer_count) > 0 ||
+	       !rte_ring_empty(sw_data->msg_ring)) {
+
+		num_msgs = rte_ring_dequeue_burst(sw_data->msg_ring,
+						  (void **)msgs, NB_OBJS, NULL);
+
+		for (i = 0; i < num_msgs; i++) {
+			msg = msgs[i];
+			evtim = msg->evtim;
+
+			switch (msg->type) {
+			case MSG_TYPE_ARM:
+				EVTIM_SVC_LOG_DBG("dequeued ARM message from "
+						  "ring");
+				tim = &msg->tim;
+				rte_timer_init(tim);
+				cycles = get_timeout_cycles(evtim,
+							    adapter);
+				ret = rte_timer_reset(tim, cycles, SINGLE,
+						      rte_lcore_id(),
+						      sw_event_timer_cb,
+						      evtim);
+				RTE_ASSERT(ret == 0);
+
+				evtim->impl_opaque[0] = (uintptr_t)tim;
+				evtim->impl_opaque[1] = (uintptr_t)adapter;
+
+				TAILQ_INSERT_TAIL(&sw_data->msgs_tailq_head,
+						  msg,
+						  msgs);
+				break;
+			case MSG_TYPE_CANCEL:
+				EVTIM_SVC_LOG_DBG("dequeued CANCEL message "
+						  "from ring");
+				tim = (struct rte_timer *)evtim->impl_opaque[0];
+				RTE_ASSERT(tim != NULL);
+
+				ret = rte_timer_stop(tim);
+				RTE_ASSERT(ret == 0);
+
+				/* Free the msg object for the original arm
+				 * request.
+				 */
+				struct msg *m;
+				m = container_of(tim, struct msg, tim);
+				TAILQ_REMOVE(&sw_data->msgs_tailq_head, m,
+					     msgs);
+				rte_mempool_put(sw_data->msg_pool, m);
+
+				/* Free the msg object for the current msg */
+				rte_mempool_put(sw_data->msg_pool, msg);
+
+				evtim->impl_opaque[0] = 0;
+				evtim->impl_opaque[1] = 0;
+
+				break;
+			}
+		}
+	}
+
+	sw_data->service_phase = 2;
+	rte_smp_wmb();
+
+	if (adapter_did_tick(adapter)) {
+		rte_timer_manage();
+
+		event_buffer_flush(&sw_data->buffer,
+				   adapter->data->event_dev_id,
+				   adapter->data->event_port_id,
+				   &nb_evs_flushed, &nb_evs_invalid);
+
+		sw_data->stats.ev_enq_count += nb_evs_flushed;
+		sw_data->stats.ev_inv_count += nb_evs_invalid;
+		sw_data->stats.adapter_tick_count++;
+	}
+
+	sw_data->service_phase = 0;
+	rte_smp_wmb();
+
+	return 0;
+}
+
+/* The adapter initialization function rounds the mempool size up to the next
+ * power of 2, so we can take the difference between that value and what the
+ * user requested, and use the space for caches.  This avoids a scenario where a
+ * user can't arm the number of timers the adapter was configured with because
+ * mempool objects have been lost to caches.
+ *
+ * nb_actual should always be a power of 2, so we can iterate over the powers
+ * of 2 to see what the largest cache size we can use is.
+ */
+static int
+compute_msg_mempool_cache_size(uint64_t nb_requested, uint64_t nb_actual)
+{
+	int i;
+	int size;
+	int cache_size = 0;
+
+	for (i = 0; ; i++) {
+		size = 1 << i;
+
+		if (RTE_MAX_LCORE * size < (int)(nb_actual - nb_requested) &&
+		    size < RTE_MEMPOOL_CACHE_MAX_SIZE &&
+		    size <= nb_actual / 1.5)
+			cache_size = size;
+		else
+			break;
+	}
+
+	return cache_size;
+}
+
+#define SW_MIN_INTERVAL 1E5
+
+static int
+sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	uint64_t nb_timers;
+	unsigned int flags;
+	struct rte_service_spec service;
+	static bool timer_subsystem_inited; // static initialized to false
+
+	/* Allocate storage for SW implementation data */
+	char priv_data_name[RTE_RING_NAMESIZE];
+	snprintf(priv_data_name, RTE_RING_NAMESIZE, "sw_evtim_adap_priv_%"PRIu8,
+		 adapter->data->id);
+	adapter->data->adapter_priv = rte_zmalloc_socket(
+				priv_data_name,
+				sizeof(struct rte_event_timer_adapter_sw_data),
+				RTE_CACHE_LINE_SIZE,
+				adapter->data->socket_id);
+	if (adapter->data->adapter_priv == NULL) {
+		EVTIM_LOG_ERR("failed to allocate space for private data");
+		rte_errno = ENOMEM;
+		return -1;
+	}
+
+	if (adapter->data->conf.timer_tick_ns < SW_MIN_INTERVAL) {
+		EVTIM_LOG_ERR("failed to create adapter with requested tick "
+			      "interval");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	sw_data = adapter->data->adapter_priv;
+
+	sw_data->timer_tick_ns = adapter->data->conf.timer_tick_ns;
+	sw_data->max_tmo_ns = adapter->data->conf.max_tmo_ns;
+
+	TAILQ_INIT(&sw_data->msgs_tailq_head);
+	rte_spinlock_init(&sw_data->msgs_tailq_sl);
+	rte_atomic16_init(&sw_data->message_producer_count);
+
+	/* Rings require power of 2, so round up to next such value */
+	nb_timers = rte_align64pow2(adapter->data->conf.nb_timers);
+
+	char msg_ring_name[RTE_RING_NAMESIZE];
+	snprintf(msg_ring_name, RTE_RING_NAMESIZE,
+		 "sw_evtim_adap_msg_ring_%"PRIu8, adapter->data->id);
+	flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+		RING_F_SP_ENQ | RING_F_SC_DEQ :
+		RING_F_SC_DEQ;
+	sw_data->msg_ring = rte_ring_create(msg_ring_name, nb_timers,
+					    adapter->data->socket_id, flags);
+	if (sw_data->msg_ring == NULL) {
+		EVTIM_LOG_ERR("failed to create message ring");
+		rte_errno = ENOMEM;
+		goto free_priv_data;
+	}
+
+	char pool_name[RTE_RING_NAMESIZE];
+	snprintf(pool_name, RTE_RING_NAMESIZE, "sw_evtim_adap_msg_pool_%"PRIu8,
+		 adapter->data->id);
+
+	/* Both the arming/canceling thread and the service thread will do puts
+	 * to the mempool, but if the SP_PUT flag is enabled, we can specify
+	 * single-consumer get for the mempool.
+	 */
+	flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+		MEMPOOL_F_SC_GET : 0;
+
+	/* The usable size of a ring is count - 1, so subtract one here to
+	 * make the counts agree.
+	 */
+	int pool_size = nb_timers - 1;
+	int cache_size = compute_msg_mempool_cache_size(
+				adapter->data->conf.nb_timers, nb_timers);
+	sw_data->msg_pool = rte_mempool_create(pool_name, pool_size,
+					       sizeof(struct msg), cache_size,
+					       0, NULL, NULL, NULL, NULL,
+					       adapter->data->socket_id, flags);
+	if (sw_data->msg_pool == NULL) {
+		EVTIM_LOG_ERR("failed to create message object mempool");
+		rte_errno = ENOMEM;
+		goto free_msg_ring;
+	}
+
+	event_buffer_init(&sw_data->buffer);
+
+	/* Register a service component to run adapter logic */
+	memset(&service, 0, sizeof(service));
+	snprintf(service.name, RTE_SERVICE_NAME_MAX,
+		 "sw_evimer_adap_svc_%"PRIu8, adapter->data->id);
+	service.socket_id = adapter->data->socket_id;
+	service.callback = sw_event_timer_adapter_service_func;
+	service.callback_userdata = adapter;
+	service.capabilities &= ~(RTE_SERVICE_CAP_MT_SAFE);
+	ret = rte_service_component_register(&service, &sw_data->service_id);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to register service %s with id %"PRIu32
+			      ": err = %d", service.name, sw_data->service_id,
+			      ret);
+
+		rte_errno = ENOSPC;
+		goto free_msg_pool;
+	}
+
+	EVTIM_LOG_DBG("registered service %s with id %"PRIu32, service.name,
+		      sw_data->service_id);
+
+	adapter->data->service_id = sw_data->service_id;
+	adapter->data->service_inited = 1;
+
+	if (!timer_subsystem_inited) {
+		rte_timer_subsystem_init();
+		timer_subsystem_inited = true;
+	}
+
+	return 0;
+
+free_msg_pool:
+	rte_mempool_free(sw_data->msg_pool);
+free_msg_ring:
+	rte_ring_free(sw_data->msg_ring);
+free_priv_data:
+	rte_free(sw_data);
+	return -1;
+}
+
+static int
+sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct msg *m1, *m2;
+	struct rte_event_timer_adapter_sw_data *sw_data =
+						adapter->data->adapter_priv;
+
+	rte_spinlock_lock(&sw_data->msgs_tailq_sl);
+
+	/* Cancel outstanding rte_timers and free msg objects */
+	m1 = TAILQ_FIRST(&sw_data->msgs_tailq_head);
+	while (m1 != NULL) {
+		EVTIM_LOG_DBG("freeing outstanding timer");
+		m2 = TAILQ_NEXT(m1, msgs);
+
+		rte_timer_stop_sync(&m1->tim);
+		rte_mempool_put(sw_data->msg_pool, m1);
+
+		m1 = m2;
+	}
+
+	rte_spinlock_unlock(&sw_data->msgs_tailq_sl);
+
+	ret = rte_service_component_unregister(sw_data->service_id);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to unregister service component");
+		return ret;
+	}
+
+	rte_ring_free(sw_data->msg_ring);
+	rte_mempool_free(sw_data->msg_pool);
+	rte_free(adapter->data->adapter_priv);
+
+	return 0;
+}
+
+static inline int32_t
+get_mapped_count_for_service(uint32_t service_id)
+{
+	int32_t core_count, i, mapped_count = 0;
+	uint32_t lcore_arr[RTE_MAX_LCORE];
+
+	core_count = rte_service_lcore_list(lcore_arr, RTE_MAX_LCORE);
+
+	for (i = 0; i < core_count; i++)
+		if (rte_service_map_lcore_get(service_id, lcore_arr[i]) == 1)
+			mapped_count++;
+
+	return mapped_count;
+}
+
+static int
+sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int mapped_count;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+
+	/* Mapping the service to more than one service core can introduce
+	 * delays while one thread is waiting to acquire a lock, so only allow
+	 * one core to be mapped to the service.
+	 */
+	mapped_count = get_mapped_count_for_service(sw_data->service_id);
+
+	if (mapped_count == 1)
+		return rte_service_component_runstate_set(sw_data->service_id,
+							  1);
+
+	return mapped_count < 1 ? -ENOENT : -ENOTSUP;
+}
+
+static int
+sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data =
+						adapter->data->adapter_priv;
+
+	ret = rte_service_component_runstate_set(sw_data->service_id, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Wait for the service to complete its final iteration before
+	 * stopping.
+	 */
+	while (sw_data->service_phase != 0)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	return 0;
+}
+
+static void
+sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+
+	adapter_info->min_resolution_ns = sw_data->timer_tick_ns;
+	adapter_info->max_tmo_ns = sw_data->max_tmo_ns;
+}
+
+static int
+sw_event_timer_adapter_stats_get(const struct rte_event_timer_adapter *adapter,
+				 struct rte_event_timer_adapter_stats *stats)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	*stats = sw_data->stats;
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_stats_reset(
+				const struct rte_event_timer_adapter *adapter)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	memset(&sw_data->stats, 0, sizeof(sw_data->stats));
+	return 0;
+}
+
+static __rte_always_inline uint16_t
+__sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **evtims,
+			  uint16_t nb_evtims)
+{
+	uint16_t i;
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct msg *msgs[nb_evtims];
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	/* Check that the service is running. */
+	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
+		rte_errno = EINVAL;
+		return 0;
+	}
+#endif
+
+	sw_data = adapter->data->adapter_priv;
+
+	ret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (ret < 0) {
+		rte_errno = ENOSPC;
+		return 0;
+	}
+
+	/* Let the service know we're producing messages for it to process */
+	rte_atomic16_inc(&sw_data->message_producer_count);
+
+	/* If the service is managing timers, wait for it to finish */
+	while (sw_data->service_phase == 2)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	for (i = 0; i < nb_evtims; i++) {
+		/* Don't modify the event timer state in these cases */
+		if (evtims[i]->state == RTE_EVENT_TIMER_ARMED) {
+			rte_errno = EALREADY;
+			break;
+		} else if (!(evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
+		    evtims[i]->state == RTE_EVENT_TIMER_CANCELED)) {
+			rte_errno = EINVAL;
+			break;
+		}
+
+		ret = check_timeout(evtims[i], adapter);
+		if (ret == -1) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOLATE;
+			rte_errno = EINVAL;
+			break;
+		}
+		if (ret == -2) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOEARLY;
+			rte_errno = EINVAL;
+			break;
+		}
+
+		if (check_destination_event_queue(evtims[i], adapter) < 0) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR;
+			rte_errno = EINVAL;
+			break;
+		}
+
+		/* Checks passed, set up a message to enqueue */
+		msgs[i]->type = MSG_TYPE_ARM;
+		msgs[i]->evtim = evtims[i];
+
+		/* Set the payload pointer if not set. */
+		if (evtims[i]->ev.event_ptr == NULL)
+			evtims[i]->ev.event_ptr = evtims[i];
+
+		/* msg objects that get enqueued successfully will be freed
+		 * either by a future cancel operation or by the timer
+		 * expiration callback.
+		 */
+		if (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {
+			rte_errno = ENOSPC;
+			break;
+		}
+
+		EVTIM_LOG_DBG("enqueued ARM message to ring");
+
+		evtims[i]->state = RTE_EVENT_TIMER_ARMED;
+	}
+
+	/* Let the service know we're done producing messages */
+	rte_atomic16_dec(&sw_data->message_producer_count);
+
+	if (i < nb_evtims)
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],
+				     nb_evtims - i);
+
+	return i;
+}
+
+static uint16_t
+sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			 struct rte_event_timer **evtims,
+			 uint16_t nb_evtims)
+{
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
+}
+
+static uint16_t
+sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			    struct rte_event_timer **evtims,
+			    uint16_t nb_evtims)
+{
+	uint16_t i;
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct msg *msgs[nb_evtims];
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	/* Check that the service is running. */
+	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
+		rte_errno = EINVAL;
+		return 0;
+	}
+#endif
+
+	sw_data = adapter->data->adapter_priv;
+
+	ret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (ret < 0) {
+		rte_errno = ENOSPC;
+		return 0;
+	}
+
+	/* Let the service know we're producing messages for it to process */
+	rte_atomic16_inc(&sw_data->message_producer_count);
+
+	/* If the service could be modifying event timer states, wait */
+	while (sw_data->service_phase == 2)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	for (i = 0; i < nb_evtims; i++) {
+		/* Don't modify the event timer state in these cases */
+		if (evtims[i]->state == RTE_EVENT_TIMER_CANCELED) {
+			rte_errno = EALREADY;
+			break;
+		} else if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
+			rte_errno = EINVAL;
+			break;
+		}
+
+		msgs[i]->type = MSG_TYPE_CANCEL;
+		msgs[i]->evtim = evtims[i];
+
+		if (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {
+			rte_errno = ENOSPC;
+			break;
+		}
+
+		EVTIM_LOG_DBG("enqueued CANCEL message to ring");
+
+		evtims[i]->state = RTE_EVENT_TIMER_CANCELED;
+	}
+
+	/* Let the service know we're done producing messages */
+	rte_atomic16_dec(&sw_data->message_producer_count);
+
+	if (i < nb_evtims)
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],
+				     nb_evtims - i);
+
+	return i;
+}
+
+static uint16_t
+sw_event_timer_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer **evtims,
+				  uint64_t timeout_ticks,
+				  uint16_t nb_evtims)
+{
+	int i;
+
+	for (i = 0; i < nb_evtims; i++)
+		evtims[i]->timeout_ticks = timeout_ticks;
+
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
+}
+
+static const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
+	.init = sw_event_timer_adapter_init,
+	.uninit = sw_event_timer_adapter_uninit,
+	.start = sw_event_timer_adapter_start,
+	.stop = sw_event_timer_adapter_stop,
+	.get_info = sw_event_timer_adapter_get_info,
+	.stats_get = sw_event_timer_adapter_stats_get,
+	.stats_reset = sw_event_timer_adapter_stats_reset,
+	.arm_burst = sw_event_timer_arm_burst,
+	.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
+	.cancel_burst = sw_event_timer_cancel_burst,
+};
+
 RTE_INIT(event_timer_adapter_init_log);
 static void
 event_timer_adapter_init_log(void)
@@ -384,4 +1284,13 @@ event_timer_adapter_init_log(void)
 	evtim_logtype = rte_log_register("lib.eventdev.adapter.timer");
 	if (evtim_logtype >= 0)
 		rte_log_set_level(evtim_logtype, RTE_LOG_NOTICE);
+
+	evtim_buffer_logtype = rte_log_register("lib.eventdev.adapter.timer."
+						"buffer");
+	if (evtim_buffer_logtype >= 0)
+		rte_log_set_level(evtim_buffer_logtype, RTE_LOG_NOTICE);
+
+	evtim_svc_logtype = rte_log_register("lib.eventdev.adapter.timer.svc");
+	if (evtim_svc_logtype >= 0)
+		rte_log_set_level(evtim_svc_logtype, RTE_LOG_NOTICE);
 }
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index 6a76791..38a314d 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -280,8 +280,6 @@ rte_event_timer_adapter_create_ext(
 struct rte_event_timer_adapter_info {
 	uint64_t min_resolution_ns;
 	/**< Minimum timer adapter resolution in ns */
-	uint64_t resolution_ns;
-	/**< Actual timer adapter resolution in ns */
 	uint64_t max_tmo_ns;
 	/**< Maximum timer timeout(expire) in ns */
 	struct rte_event_timer_adapter_conf conf;
@@ -339,6 +337,8 @@ rte_event_timer_adapter_get_info(
  *   - 0: Success, adapter started.
  *   - <0: Error code returned by the driver start function.
  *   - -EINVAL if adapter identifier invalid
+ *   - -ENOENT if software adapter but no service core mapped
+ *   - -ENOTSUP if software adapter and more than one service core mapped
  */
 int __rte_experimental
 rte_event_timer_adapter_start(
@@ -465,6 +465,59 @@ int __rte_experimental rte_event_timer_adapter_stats_reset(
 		struct rte_event_timer_adapter *adapter);
 
 /**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure, if the event dev doesn't use a rte_service
+ *   function, this function returns -ESRCH.
+ */
+int
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param[out] stats
+ *   A pointer to a structure to fill with statistics.
+ *
+ * @return
+ *   - 0: Successfully retrieved.
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				struct rte_event_timer_adapter_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully reset;
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_reset(
+				struct rte_event_timer_adapter *adapter);
+
+/**
  * @warning
  * @b EXPERIMENTAL: this structure may change without prior notice
  *
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 6/9] eventtimer: add support for meson build system
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
                               ` (4 preceding siblings ...)
  2018-04-03 21:44             ` [PATCH v10 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
@ 2018-04-03 21:44             ` Erik Gabriel Carrillo
  2018-04-04 16:51               ` Pavan Nikhilesh
  2018-04-03 21:44             ` [PATCH v10 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
                               ` (4 subsequent siblings)
  10 siblings, 1 reply; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-03 21:44 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
---
 config/rte_config.h             | 1 +
 lib/librte_eventdev/meson.build | 9 ++++++---
 lib/meson.build                 | 3 ++-
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/config/rte_config.h b/config/rte_config.h
index 72c0aa2..117c19f 100644
--- a/config/rte_config.h
+++ b/config/rte_config.h
@@ -55,6 +55,7 @@
 /* eventdev defines */
 #define RTE_EVENT_MAX_DEVS 16
 #define RTE_EVENT_MAX_QUEUES_PER_DEV 64
+#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 32
 
 /* ip_fragmentation defines */
 #define RTE_LIBRTE_IP_FRAG_MAX_FRAG 4
diff --git a/lib/librte_eventdev/meson.build b/lib/librte_eventdev/meson.build
index e1e22a5..232b870 100644
--- a/lib/librte_eventdev/meson.build
+++ b/lib/librte_eventdev/meson.build
@@ -5,11 +5,14 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_eventdev.c',
 		'rte_event_ring.c',
-		'rte_event_eth_rx_adapter.c')
+		'rte_event_eth_rx_adapter.c',
+		'rte_event_timer_adapter.c')
 headers = files('rte_eventdev.h',
 		'rte_eventdev_pmd.h',
 		'rte_eventdev_pmd_pci.h',
 		'rte_eventdev_pmd_vdev.h',
 		'rte_event_ring.h',
-		'rte_event_eth_rx_adapter.h')
-deps += ['ring', 'ethdev', 'hash']
+		'rte_event_eth_rx_adapter.h',
+		'rte_event_timer_adapter.h',
+		'rte_event_timer_adapter_pmd.h')
+deps += ['ring', 'ethdev', 'hash', 'mempool', 'timer']
diff --git a/lib/meson.build b/lib/meson.build
index ef61591..b1ad35f 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -13,13 +13,14 @@ libraries = [ 'compat', # just a header, used for versioning
 	'metrics', # bitrate/latency stats depends on this
 	'hash',    # efd depends on this
 	'kvargs',  # cryptodev depends on this
+	'timer',   # eventdev depends on this
 	'acl', 'bbdev', 'bitratestats', 'cfgfile',
 	'cmdline', 'cryptodev',
 	'distributor', 'efd', 'eventdev',
 	'gro', 'gso', 'ip_frag', 'jobstats',
 	'kni', 'latencystats', 'lpm', 'member',
 	'meter', 'power', 'pdump',
-	'reorder', 'sched', 'security', 'timer', 'vhost',
+	'reorder', 'sched', 'security', 'vhost',
 	# add pkt framework libs which use other libs from above
 	'port', 'table', 'pipeline',
 	# flow_classify lib depends on pkt framework table lib
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 7/9] test: add event timer adapter auto-test
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
                               ` (5 preceding siblings ...)
  2018-04-03 21:44             ` [PATCH v10 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
@ 2018-04-03 21:44             ` Erik Gabriel Carrillo
  2018-04-03 21:44             ` [PATCH v10 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
                               ` (3 subsequent siblings)
  10 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-03 21:44 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
---
 test/test/Makefile                   |    1 +
 test/test/test_event_timer_adapter.c | 1831 ++++++++++++++++++++++++++++++++++
 2 files changed, 1832 insertions(+)
 create mode 100644 test/test/test_event_timer_adapter.c

diff --git a/test/test/Makefile b/test/test/Makefile
index a88cc38..c9c007c9 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -185,6 +185,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
 SRCS-y += test_eventdev.c
 SRCS-y += test_event_ring.c
 SRCS-y += test_event_eth_rx_adapter.c
+SRCS-y += test_event_timer_adapter.c
 endif
 
 ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y)
diff --git a/test/test/test_event_timer_adapter.c b/test/test/test_event_timer_adapter.c
new file mode 100644
index 0000000..9afe031
--- /dev/null
+++ b/test/test/test_event_timer_adapter.c
@@ -0,0 +1,1831 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc
+ * Copyright(c) 2017-2018 Intel Corporation.
+ */
+
+#include <rte_atomic.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_debug.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_eventdev.h>
+#include <rte_event_timer_adapter.h>
+#include <rte_mempool.h>
+#include <rte_launch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_random.h>
+#include <rte_bus_vdev.h>
+#include <rte_service.h>
+#include <stdbool.h>
+
+#include "test.h"
+
+/* 4K timers corresponds to sw evdev max inflight events */
+#define MAX_TIMERS  (4 * 1024)
+#define BKT_TCK_NSEC
+
+#define NSECPERSEC 1E9
+#define BATCH_SIZE 16
+/* Both the app lcore and adapter ports are linked to this queue */
+#define TEST_QUEUE_ID 0
+/* Port the application dequeues from */
+#define TEST_PORT_ID 0
+#define TEST_ADAPTER_ID 0
+
+/* Handle log statements in same manner as test macros */
+#define LOG_DBG(...)	RTE_LOG(DEBUG, EAL, __VA_ARGS__)
+
+static int evdev;
+static struct rte_event_timer_adapter *timdev;
+static struct rte_mempool *eventdev_test_mempool;
+static struct rte_ring *timer_producer_ring;
+static uint64_t global_bkt_tck_ns;
+static volatile uint8_t arm_done;
+
+static bool using_services;
+static uint32_t test_lcore1;
+static uint32_t test_lcore2;
+static uint32_t test_lcore3;
+static uint32_t sw_evdev_slcore;
+static uint32_t sw_adptr_slcore;
+
+static inline void
+devconf_set_default_sane_values(struct rte_event_dev_config *dev_conf,
+		struct rte_event_dev_info *info)
+{
+	memset(dev_conf, 0, sizeof(struct rte_event_dev_config));
+	dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns;
+	dev_conf->nb_event_ports = 1;
+	dev_conf->nb_event_queues = 1;
+	dev_conf->nb_event_queue_flows = info->max_event_queue_flows;
+	dev_conf->nb_event_port_dequeue_depth =
+		info->max_event_port_dequeue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+		info->max_event_port_enqueue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+		info->max_event_port_enqueue_depth;
+	dev_conf->nb_events_limit =
+		info->max_num_events;
+}
+
+static inline int
+eventdev_setup(void)
+{
+	int ret;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_dev_info info;
+	uint32_t service_id;
+
+	ret = rte_event_dev_info_get(evdev, &info);
+	TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info");
+	TEST_ASSERT(info.max_num_events >= (int32_t)MAX_TIMERS,
+			"ERROR max_num_events=%d < max_events=%d",
+			info.max_num_events, MAX_TIMERS);
+
+	devconf_set_default_sane_values(&dev_conf, &info);
+	ret = rte_event_dev_configure(evdev, &dev_conf);
+	TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev");
+
+	ret = rte_event_queue_setup(evdev, 0, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", 0);
+
+	/* Configure event port */
+	ret = rte_event_port_setup(evdev, 0, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup port=%d", 0);
+	ret = rte_event_port_link(evdev, 0, NULL, NULL, 0);
+	TEST_ASSERT(ret >= 0, "Failed to link all queues port=%d", 0);
+
+	/* If this is a software event device, map and start its service */
+	if (rte_event_dev_service_id_get(evdev, &service_id) == 0) {
+		TEST_ASSERT_SUCCESS(rte_service_lcore_add(sw_evdev_slcore),
+				"Failed to add service core");
+		TEST_ASSERT_SUCCESS(rte_service_lcore_start(
+				sw_evdev_slcore),
+				"Failed to start service core");
+		TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(
+				service_id, sw_evdev_slcore, 1),
+				"Failed to map evdev service");
+		TEST_ASSERT_SUCCESS(rte_service_runstate_set(
+				service_id, 1),
+				"Failed to start evdev service");
+	}
+
+	ret = rte_event_dev_start(evdev);
+	TEST_ASSERT_SUCCESS(ret, "Failed to start device");
+
+	return TEST_SUCCESS;
+}
+
+static int
+testsuite_setup(void)
+{
+	/* Some of the multithreaded tests require 3 other lcores to run */
+	unsigned int required_lcore_count = 4;
+	uint32_t service_id;
+
+	/* To make it easier to map services later if needed, just reset
+	 * service core state.
+	 */
+	(void) rte_service_lcore_reset_all();
+
+	if (!rte_event_dev_count()) {
+		/* If there is no hardware eventdev, or no software vdev was
+		 * specified on the command line, create an instance of
+		 * event_sw.
+		 */
+		LOG_DBG("Failed to find a valid event device... testing with"
+			" event_sw device\n");
+		TEST_ASSERT_SUCCESS(rte_vdev_init("event_sw0", NULL),
+					"Error creating eventdev");
+		evdev = rte_event_dev_get_dev_id("event_sw0");
+	}
+
+	if (rte_event_dev_service_id_get(evdev, &service_id) == 0) {
+		/* A software event device will use a software event timer
+		 * adapter as well. 2 more cores required to convert to
+		 * service cores.
+		 */
+		required_lcore_count += 2;
+		using_services = true;
+	}
+
+	if (rte_lcore_count() < required_lcore_count) {
+		printf("%d lcores needed to run tests", required_lcore_count);
+		return TEST_FAILED;
+	}
+
+	/* Assign lcores for various tasks */
+	test_lcore1 = rte_get_next_lcore(-1, 1, 0);
+	test_lcore2 = rte_get_next_lcore(test_lcore1, 1, 0);
+	test_lcore3 = rte_get_next_lcore(test_lcore2, 1, 0);
+	if (using_services) {
+		sw_evdev_slcore = rte_get_next_lcore(test_lcore3, 1, 0);
+		sw_adptr_slcore = rte_get_next_lcore(sw_evdev_slcore, 1, 0);
+	}
+
+	return eventdev_setup();
+}
+
+static void
+testsuite_teardown(void)
+{
+	rte_event_dev_stop(evdev);
+	rte_event_dev_close(evdev);
+}
+
+static int
+setup_adapter_service(struct rte_event_timer_adapter *adptr)
+{
+	uint32_t adapter_service_id;
+	int ret;
+
+	/* retrieve service ids */
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(adptr,
+			&adapter_service_id), "Failed to get event timer "
+			"adapter service id");
+	/* add a service core and start it */
+	ret = rte_service_lcore_add(sw_adptr_slcore);
+	TEST_ASSERT(ret == 0 || ret == -EALREADY,
+			"Failed to add service core");
+	ret = rte_service_lcore_start(sw_adptr_slcore);
+	TEST_ASSERT(ret == 0 || ret == -EALREADY,
+			"Failed to start service core");
+
+	/* map services to it */
+	TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(adapter_service_id,
+			sw_adptr_slcore, 1),
+			"Failed to map adapter service");
+
+	/* set services to running */
+	TEST_ASSERT_SUCCESS(rte_service_runstate_set(adapter_service_id, 1),
+			"Failed to start event timer adapter service");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		  void *conf_arg)
+{
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_dev_info info;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	uint32_t started;
+	static int port_allocated;
+	static uint8_t port_id;
+	int ret;
+
+	if (port_allocated) {
+		*event_port_id = port_id;
+		return 0;
+	}
+
+	RTE_SET_USED(id);
+
+	ret = rte_event_dev_attr_get(event_dev_id, RTE_EVENT_DEV_ATTR_STARTED,
+				     &started);
+	if (ret < 0)
+		return ret;
+
+	if (started)
+		rte_event_dev_stop(event_dev_id);
+
+	ret = rte_event_dev_info_get(evdev, &info);
+	if (ret < 0)
+		return ret;
+
+	devconf_set_default_sane_values(&dev_conf, &info);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports++;
+
+	ret = rte_event_dev_configure(event_dev_id, &dev_conf);
+	if (ret < 0) {
+		if (started)
+			rte_event_dev_start(event_dev_id);
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(event_dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(event_dev_id, port_id, port_conf);
+	if (ret < 0)
+		return ret;
+
+	*event_port_id = port_id;
+
+	if (started)
+		rte_event_dev_start(event_dev_id);
+
+	/* Reuse this port number next time this is called */
+	port_allocated = 1;
+
+	return 0;
+}
+
+static int
+_timdev_setup(uint64_t max_tmo_ns, uint64_t bkt_tck_ns)
+{
+	struct rte_event_timer_adapter_conf config = {
+		.event_dev_id = evdev,
+		.timer_adapter_id = TEST_ADAPTER_ID,
+		.timer_tick_ns = bkt_tck_ns,
+		.max_tmo_ns = max_tmo_ns,
+		.nb_timers = MAX_TIMERS * 10,
+	};
+	uint32_t caps = 0;
+	const char *pool_name = "timdev_test_pool";
+
+	global_bkt_tck_ns = bkt_tck_ns;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_caps_get(evdev, &caps),
+				"failed to get adapter capabilities");
+	if (!(caps & RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+		timdev = rte_event_timer_adapter_create_ext(&config,
+							    test_port_conf_cb,
+							    NULL);
+		setup_adapter_service(timdev);
+		using_services = true;
+	} else
+		timdev = rte_event_timer_adapter_create(&config);
+
+	TEST_ASSERT_NOT_NULL(timdev,
+			"failed to create event timer ring");
+
+	TEST_ASSERT_EQUAL(rte_event_timer_adapter_start(timdev), 0,
+			"failed to Start event timer adapter");
+
+	/* Create event timer mempool */
+	eventdev_test_mempool = rte_mempool_create(pool_name,
+			MAX_TIMERS * 2,
+			sizeof(struct rte_event_timer), /* element size*/
+			0, /* cache size*/
+			0, NULL, NULL, NULL, NULL,
+			rte_socket_id(), 0);
+	if (!eventdev_test_mempool) {
+		printf("ERROR creating mempool\n");
+		return TEST_FAILED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+timdev_setup_usec(void)
+{
+	return using_services ?
+		/* Max timeout is 10,000us and bucket interval is 100us */
+		_timdev_setup(1E7, 1E5) :
+		/* Max timeout is 100us and bucket interval is 1us */
+		_timdev_setup(1E5, 1E3);
+}
+
+static int
+timdev_setup_usec_multicore(void)
+{
+	return using_services ?
+		/* Max timeout is 10,000us and bucket interval is 100us */
+		_timdev_setup(1E7, 1E5) :
+		/* Max timeout is 100us and bucket interval is 1us */
+		_timdev_setup(1E5, 1E3);
+}
+
+static int
+timdev_setup_msec(void)
+{
+	/* Max timeout is 2 mins, and bucket interval is 100 ms */
+	return _timdev_setup(180 * NSECPERSEC, NSECPERSEC / 10);
+}
+
+static int
+timdev_setup_sec(void)
+{
+	/* Max timeout is 100sec and bucket interval is 1sec */
+	return _timdev_setup(1E11, 1E9);
+}
+
+static int
+timdev_setup_sec_multicore(void)
+{
+	/* Max timeout is 100sec and bucket interval is 1sec */
+	return _timdev_setup(1E11, 1E9);
+}
+
+static void
+timdev_teardown(void)
+{
+	rte_event_timer_adapter_stop(timdev);
+	rte_event_timer_adapter_free(timdev);
+
+	rte_mempool_free(eventdev_test_mempool);
+}
+
+static inline int
+test_timer_state(void)
+{
+	struct rte_event_timer *ev_tim;
+	struct rte_event ev;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&ev_tim);
+	*ev_tim = tim;
+	ev_tim->ev.event_ptr = ev_tim;
+	ev_tim->timeout_ticks = 120;
+
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 0,
+			"Armed timer exceeding max_timeout.");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ERROR_TOOLATE,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_ERROR_TOOLATE, ev_tim->state);
+
+	ev_tim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	ev_tim->timeout_ticks = 10;
+
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+			"Failed to arm timer with proper timeout.");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_ARMED, ev_tim->state);
+
+	if (!using_services)
+		rte_delay_us(20);
+	else
+		rte_delay_us(1000 + 200);
+	TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1, 0), 1,
+			"Armed timer failed to trigger.");
+
+	ev_tim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	ev_tim->timeout_ticks = 90;
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+			"Failed to arm timer with proper timeout.");
+	TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(timdev, &ev_tim, 1),
+			1, "Failed to cancel armed timer");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_CANCELED,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_CANCELED, ev_tim->state);
+
+	rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+_arm_timers(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers; i++) {
+
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+_wait_timer_triggers(uint64_t wait_sec, uint64_t arm_count,
+		uint64_t cancel_count)
+{
+	uint8_t valid_event;
+	uint64_t events = 0;
+	uint64_t wait_start, max_wait;
+	struct rte_event ev;
+
+	max_wait = rte_get_timer_hz() * wait_sec;
+	wait_start = rte_get_timer_cycles();
+	while (1) {
+		if (rte_get_timer_cycles() - wait_start > max_wait) {
+			if (events + cancel_count != arm_count)
+				TEST_ASSERT_SUCCESS(max_wait,
+					"Max time limit for timers exceeded.");
+			break;
+		}
+
+		valid_event = rte_event_dequeue_burst(evdev, 0, &ev, 1, 0);
+		if (!valid_event)
+			continue;
+
+		rte_mempool_put(eventdev_test_mempool, ev.event_ptr);
+		events++;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm(void)
+{
+	TEST_ASSERT_SUCCESS(_arm_timers(20, MAX_TIMERS),
+			"Failed to arm timers");
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS, 0),
+			"Timer triggered count doesn't match arm count");
+	return TEST_SUCCESS;
+}
+
+static int
+_arm_wrapper(void *arg)
+{
+	RTE_SET_USED(arg);
+
+	TEST_ASSERT_SUCCESS(_arm_timers(20, MAX_TIMERS),
+			"Failed to arm timers");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_multicore(void)
+{
+
+	uint32_t lcore_1 = rte_get_next_lcore(-1, 1, 0);
+	uint32_t lcore_2 = rte_get_next_lcore(lcore_1, 1, 0);
+
+	rte_eal_remote_launch(_arm_wrapper, NULL, lcore_1);
+	rte_eal_remote_launch(_arm_wrapper, NULL, lcore_2);
+
+	rte_eal_mp_wait_lcore();
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS * 2, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+#define MAX_BURST 16
+static inline int
+_arm_timers_burst(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	int j;
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers / MAX_BURST; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get_bulk(
+				eventdev_test_mempool,
+				(void **)ev_tim, MAX_BURST),
+				"mempool alloc failed");
+
+		for (j = 0; j < MAX_BURST; j++) {
+			*ev_tim[j] = tim;
+			ev_tim[j]->ev.event_ptr = ev_tim[j];
+		}
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_tmo_tick_burst(timdev,
+				ev_tim, tim.timeout_ticks, MAX_BURST),
+				MAX_BURST, "Failed to arm timer %d", rte_errno);
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_burst(void)
+{
+	TEST_ASSERT_SUCCESS(_arm_timers_burst(20, MAX_TIMERS),
+			"Failed to arm timers");
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_arm_wrapper_burst(void *arg)
+{
+	RTE_SET_USED(arg);
+
+	TEST_ASSERT_SUCCESS(_arm_timers_burst(20, MAX_TIMERS),
+			"Failed to arm timers");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_burst_multicore(void)
+{
+	rte_eal_remote_launch(_arm_wrapper_burst, NULL, test_lcore1);
+	rte_eal_remote_launch(_arm_wrapper_burst, NULL, test_lcore2);
+
+	rte_eal_mp_wait_lcore();
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS * 2, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel(void)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 20,
+	};
+
+	for (i = 0; i < MAX_TIMERS; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		rte_delay_us(100 + (i % 5000));
+
+		TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(timdev,
+					&ev_tim, 1), 1,
+				"Failed to cancel event timer %d", rte_errno);
+		rte_mempool_put(eventdev_test_mempool, ev_tim);
+	}
+
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+				MAX_TIMERS),
+		"Timer triggered count doesn't match arm, cancel count");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+				  "Failed to arm event timer");
+
+		while (rte_ring_enqueue(timer_producer_ring, ev_tim) != 0)
+			;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer_burst(uint64_t timeout_tcks, uint64_t timers)
+{
+
+	uint64_t i;
+	int j;
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+	int arm_count = 0;
+
+	for (i = 0; i < timers / MAX_BURST; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get_bulk(
+				eventdev_test_mempool,
+				(void **)ev_tim, MAX_BURST),
+				"mempool alloc failed");
+
+		for (j = 0; j < MAX_BURST; j++) {
+			*ev_tim[j] = tim;
+			ev_tim[j]->ev.event_ptr = ev_tim[j];
+		}
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_tmo_tick_burst(timdev,
+				ev_tim, tim.timeout_ticks, MAX_BURST),
+				MAX_BURST, "Failed to arm timer %d", rte_errno);
+
+		for (j = 0; j < MAX_BURST; j++)
+			TEST_ASSERT_EQUAL(ev_tim[j]->state,
+					  RTE_EVENT_TIMER_ARMED,
+					  "Event timer not armed, state = %d",
+					  ev_tim[j]->state);
+
+		while (rte_ring_enqueue_bulk(timer_producer_ring,
+				(void **)ev_tim, MAX_BURST, NULL) == 0)
+			;
+
+		arm_count += MAX_BURST;
+	}
+
+	TEST_ASSERT_EQUAL(arm_count, MAX_TIMERS,
+			  "Failed to arm expected number of event timers");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer_wrapper(void *args)
+{
+	RTE_SET_USED(args);
+
+	return _cancel_producer(20, MAX_TIMERS);
+}
+
+static int
+_cancel_producer_burst_wrapper(void *args)
+{
+	RTE_SET_USED(args);
+
+	return _cancel_producer_burst(100, MAX_TIMERS);
+}
+
+static int
+_cancel_thread(void *args)
+{
+	RTE_SET_USED(args);
+	unsigned int count = rte_ring_count(timer_producer_ring);
+	struct rte_event_timer *ev_tim = NULL;
+	uint64_t cancel_count = 0;
+	uint16_t ret;
+
+	while (!arm_done || count) {
+		if (rte_ring_dequeue(timer_producer_ring, (void **)&ev_tim)) {
+			count = rte_ring_count(timer_producer_ring);
+			continue;
+		}
+
+		ret = rte_event_timer_cancel_burst(timdev, &ev_tim, 1);
+		TEST_ASSERT_EQUAL(ret, 1, "Failed to cancel timer");
+		rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+		count = rte_ring_count(timer_producer_ring);
+		cancel_count++;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_burst_thread(void *args)
+{
+	RTE_SET_USED(args);
+
+	int ret, i, n;
+	unsigned int count = rte_ring_count(timer_producer_ring);
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	uint64_t cancel_count = 0;
+
+	while (!arm_done || count) {
+		n = rte_ring_dequeue_burst(timer_producer_ring,
+				(void **)ev_tim, MAX_BURST, &count);
+		if (!n)
+			continue;
+
+		for (i = 0; i < n; i++)
+			TEST_ASSERT_EQUAL(ev_tim[i]->state,
+					  RTE_EVENT_TIMER_ARMED,
+					  "Event timer not armed, state = %d",
+					  ev_tim[i]->state);
+
+		ret = rte_event_timer_cancel_burst(timdev, ev_tim, n);
+		TEST_ASSERT_EQUAL(n, ret, "Failed to cancel complete burst of "
+				  "event timers");
+		rte_mempool_put_bulk(eventdev_test_mempool, (void **)ev_tim,
+				ret);
+
+		cancel_count += ret;
+	}
+
+	TEST_ASSERT_EQUAL(cancel_count, MAX_TIMERS,
+			  "Failed to cancel expected number of timers: "
+			  "expected = %d, cancel_count = %"PRIu64"\n",
+			  MAX_TIMERS, cancel_count);
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_multicore(void)
+{
+	arm_done = 0;
+	timer_producer_ring = rte_ring_create("timer_cancel_queue",
+			MAX_TIMERS * 2, rte_socket_id(), 0);
+	TEST_ASSERT_NOT_NULL(timer_producer_ring,
+			"Unable to reserve memory for ring");
+
+	rte_eal_remote_launch(_cancel_thread, NULL, test_lcore3);
+	rte_eal_remote_launch(_cancel_producer_wrapper, NULL, test_lcore1);
+	rte_eal_remote_launch(_cancel_producer_wrapper, NULL, test_lcore2);
+
+	rte_eal_wait_lcore(test_lcore1);
+	rte_eal_wait_lcore(test_lcore2);
+	arm_done = 1;
+	rte_eal_wait_lcore(test_lcore3);
+	rte_ring_free(timer_producer_ring);
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS * 2,
+			MAX_TIMERS * 2),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_burst_multicore(void)
+{
+	arm_done = 0;
+	timer_producer_ring = rte_ring_create("timer_cancel_queue",
+			MAX_TIMERS * 2, rte_socket_id(), 0);
+	TEST_ASSERT_NOT_NULL(timer_producer_ring,
+			"Unable to reserve memory for ring");
+
+	rte_eal_remote_launch(_cancel_burst_thread, NULL, test_lcore2);
+	rte_eal_remote_launch(_cancel_producer_burst_wrapper, NULL,
+			test_lcore1);
+
+	rte_eal_wait_lcore(test_lcore1);
+	arm_done = 1;
+	rte_eal_wait_lcore(test_lcore2);
+	rte_ring_free(timer_producer_ring);
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+			MAX_TIMERS),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_random(void)
+{
+	uint64_t i;
+	uint64_t events_canceled = 0;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 20,
+	};
+
+	for (i = 0; i < MAX_TIMERS; i++) {
+
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		if (rte_rand() & 1) {
+			rte_delay_us(100 + (i % 5000));
+			TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(
+						timdev,
+						&ev_tim, 1), 1,
+				"Failed to cancel event timer %d", rte_errno);
+			rte_mempool_put(eventdev_test_mempool, ev_tim);
+			events_canceled++;
+		}
+	}
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+				events_canceled),
+		       "Timer triggered count doesn't match arm, cancel count");
+
+	return TEST_SUCCESS;
+}
+
+/* Check that the adapter can be created correctly */
+static int
+adapter_create(void)
+{
+	int adapter_id = 0;
+	struct rte_event_timer_adapter *adapter, *adapter2;
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev + 1,  // invalid event dev id
+		.timer_adapter_id = adapter_id,
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = MAX_TIMERS,
+		.flags = 0,
+	};
+	uint32_t caps = 0;
+
+	/* Test invalid conf */
+	adapter = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapter, "Created adapter with invalid "
+			"event device id");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Incorrect errno value for "
+			"invalid event device id");
+
+	/* Test valid conf */
+	conf.event_dev_id = evdev;
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_caps_get(evdev, &caps),
+			"failed to get adapter capabilities");
+	if (!(caps & RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT))
+		adapter = rte_event_timer_adapter_create_ext(&conf,
+				test_port_conf_cb,
+				NULL);
+	else
+		adapter = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NOT_NULL(adapter, "Failed to create adapter with valid "
+			"configuration");
+
+	/* Test existing id */
+	adapter2 = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapter2, "Created adapter with in-use id");
+	TEST_ASSERT(rte_errno == EEXIST, "Incorrect errno value for existing "
+			"id");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapter),
+			"Failed to free adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+
+/* Test that adapter can be freed correctly. */
+static int
+adapter_free(void)
+{
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stop(timdev),
+			"Failed to stop adapter");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(timdev),
+			"Failed to free valid adapter");
+
+	/* Test free of already freed adapter */
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_free(timdev),
+			"Freed adapter that was already freed");
+
+	/* Test free of null adapter */
+	timdev = NULL;
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_free(timdev),
+			"Freed null adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter info can be retrieved and is correct. */
+static int
+adapter_get_info(void)
+{
+	struct rte_event_timer_adapter_info info;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_get_info(timdev, &info),
+			"Failed to get adapter info");
+
+	if (using_services)
+		TEST_ASSERT_EQUAL(info.event_dev_port_id, 1,
+				"Expected port id = 1, got port id = %d",
+				info.event_dev_port_id);
+
+	return TEST_SUCCESS;
+}
+
+/* Test adapter lookup via adapter ID. */
+static int
+adapter_lookup(void)
+{
+	struct rte_event_timer_adapter *adapter;
+
+	adapter = rte_event_timer_adapter_lookup(TEST_ADAPTER_ID);
+	TEST_ASSERT_NOT_NULL(adapter, "Failed to lookup adapter");
+
+	return TEST_SUCCESS;
+}
+
+static int
+adapter_start(void)
+{
+	TEST_ASSERT_SUCCESS(_timdev_setup(180 * NSECPERSEC,
+			NSECPERSEC / 10),
+			"Failed to start adapter");
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_start(timdev),
+			"Failed to repeatedly start adapter");
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter stops correctly. */
+static int
+adapter_stop(void)
+{
+	struct rte_event_timer_adapter *l_adapter = NULL;
+
+	/* Test adapter stop */
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stop(timdev),
+			"Failed to stop event adapter");
+
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_stop(l_adapter),
+			"Erroneously stopped null event adapter");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(timdev),
+			"Failed to free adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+/* Test increment and reset of ev_enq_count stat */
+static int
+stat_inc_reset_ev_enq(void)
+{
+	int ret, i, n;
+	int num_evtims = MAX_TIMERS;
+	struct rte_event_timer *evtims[num_evtims];
+	struct rte_event evs[BATCH_SIZE];
+	struct rte_event_timer_adapter_stats stats;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
+				   num_evtims);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
+			  ret);
+
+	for (i = 0; i < num_evtims; i++) {
+		*evtims[i] = init_tim;
+		evtims[i]->ev.event_ptr = evtims[i];
+	}
+
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0, "Stats not clear at "
+			  "startup");
+
+	/* Test with the max value for the adapter */
+	ret = rte_event_timer_arm_burst(timdev, evtims, num_evtims);
+	TEST_ASSERT_EQUAL(ret, num_evtims,
+			  "Failed to arm all event timers: attempted = %d, "
+			  "succeeded = %d, rte_errno = %s",
+			  num_evtims, ret, rte_strerror(rte_errno));
+
+	rte_delay_ms(1000);
+
+#define MAX_TRIES num_evtims
+	int sum = 0;
+	int tries = 0;
+	bool done = false;
+	while (!done) {
+		sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
+					       RTE_DIM(evs), 10);
+		if (sum >= num_evtims || ++tries >= MAX_TRIES)
+			done = true;
+
+		rte_delay_ms(10);
+	}
+
+	TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
+			  "got %d", num_evtims, sum);
+
+	TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");
+
+	rte_delay_ms(100);
+
+	/* Make sure the eventdev is still empty */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
+				      10);
+
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
+			  "events from event device");
+
+	/* Check stats again */
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, num_evtims,
+			  "Expected enqueue stat = %d; got %d", num_evtims,
+			  (int)stats.ev_enq_count);
+
+	/* Reset and check again */
+	ret = rte_event_timer_adapter_stats_reset(timdev);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to reset stats");
+
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0,
+			  "Expected enqueue stat = %d; got %d", 0,
+			  (int)stats.ev_enq_count);
+
+	rte_mempool_put_bulk(eventdev_test_mempool, (void **)evtims,
+			     num_evtims);
+
+	return TEST_SUCCESS;
+}
+
+/* Test various cases in arming timers */
+static int
+event_timer_arm(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+
+	/* Test single timer arm succeeds */
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event timer "
+			  "in incorrect state");
+
+	/* Test arm of armed timer fails */
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "expected return value from "
+			  "rte_event_timer_arm_burst: 0, got: %d", ret);
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after arming already armed timer");
+
+	/* Let timer expire */
+	rte_delay_ms(1000);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* This test checks that repeated references to the same event timer in the
+ * arm request work as expected; only the first one through should succeed.
+ */
+static int
+event_timer_arm_double(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+
+	struct rte_event_timer *evtim_arr[] = {evtim, evtim};
+	ret = rte_event_timer_arm_burst(adapter, evtim_arr, RTE_DIM(evtim_arr));
+	TEST_ASSERT_EQUAL(ret, 1, "Unexpected return value from "
+			  "rte_event_timer_arm_burst");
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after double-arm");
+
+	/* Let timer expire */
+	rte_delay_ms(600);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number of expiry events - "
+			  "expected: 1, actual: %d", n);
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Test the timer expiry event is generated at the expected time.  */
+static int
+event_timer_arm_expiry(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event_timer *evtim2 = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up an event timer */
+	*evtim = init_tim;
+	evtim->timeout_ticks = 30,	// expire in 3 secs
+	evtim->ev.event_ptr = evtim;
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event "
+			  "timer in incorrect state");
+
+	rte_delay_ms(2999);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event");
+
+	/* Delay 100 ms to account for the adapter tick window - should let us
+	 * dequeue one event
+	 */
+	rte_delay_ms(100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number (%d) of timer "
+			  "expiry events", n);
+	TEST_ASSERT_EQUAL(evs[0].event_type, RTE_EVENT_TYPE_TIMER,
+			  "Dequeued unexpected type of event");
+
+	/* Check that we recover the original event timer and then free it */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+	rte_mempool_put(eventdev_test_mempool, evtim2);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that rearming a timer works as expected. */
+static int
+event_timer_arm_rearm(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event_timer *evtim2 = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type = RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->timeout_ticks = 1;  // expire in 0.1 sec
+	evtim->ev.event_ptr = evtim;
+
+	/* Arm it */
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+
+	/* Add 100ms to account for the adapter tick window */
+	rte_delay_ms(100 + 100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	/* Recover the timer through the event that was dequeued. */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+
+	/* Need to reset state in case implementation can't do it */
+	evtim2->state = RTE_EVENT_TIMER_NOT_ARMED;
+
+	/* Rearm it */
+	ret = rte_event_timer_arm_burst(timdev, &evtim2, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+
+	/* Add 100ms to account for the adapter tick window */
+	rte_delay_ms(100 + 100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	/* Free it */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+	rte_mempool_put(eventdev_test_mempool, evtim2);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that the adapter handles the max specified number of timers as
+ * expected.
+ */
+static int
+event_timer_arm_max(void)
+{
+	int ret, i, n;
+	int num_evtims = MAX_TIMERS;
+	struct rte_event_timer *evtims[num_evtims];
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
+				   num_evtims);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
+			  ret);
+
+	for (i = 0; i < num_evtims; i++) {
+		*evtims[i] = init_tim;
+		evtims[i]->ev.event_ptr = evtims[i];
+	}
+
+	/* Test with the max value for the adapter */
+	ret = rte_event_timer_arm_burst(timdev, evtims, num_evtims);
+	TEST_ASSERT_EQUAL(ret, num_evtims,
+			  "Failed to arm all event timers: attempted = %d, "
+			  "succeeded = %d, rte_errno = %s",
+			  num_evtims, ret, rte_strerror(rte_errno));
+
+	rte_delay_ms(1000);
+
+#define MAX_TRIES num_evtims
+	int sum = 0;
+	int tries = 0;
+	bool done = false;
+	while (!done) {
+		sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
+					       RTE_DIM(evs), 10);
+		if (sum >= num_evtims || ++tries >= MAX_TRIES)
+			done = true;
+
+		rte_delay_ms(10);
+	}
+
+	TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
+			  "got %d", num_evtims, sum);
+
+	TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");
+
+	rte_delay_ms(100);
+
+	/* Make sure the eventdev is still empty */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
+				    10);
+
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
+			  "events from event device");
+
+	rte_mempool_put_bulk(eventdev_test_mempool, (void **)evtims,
+			     num_evtims);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that creating an event timer with incorrect event sched type fails. */
+static int
+event_timer_arm_invalid_sched_type(void)
+{
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	if (!using_services)
+		return -ENOTSUP;
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_PARALLEL; // bad sched type
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "sched type, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid queue");
+
+	rte_mempool_put(eventdev_test_mempool, &evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that creating an event timer with a timeout value that is too small or
+ * too big fails.
+ */
+static int
+event_timer_arm_invalid_timeout(void)
+{
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 0;  // timeout too small
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "timeout, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid timeout");
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOEARLY,
+			  "Unexpected event timer state");
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 1801;  // timeout too big
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "timeout, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid timeout");
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOLATE,
+			  "Unexpected event timer state");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+static int
+event_timer_cancel(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Check that cancelling an uninited timer fails */
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling "
+			  "uninited timer");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after "
+			  "cancelling uninited timer");
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	/* Check that cancelling an inited but unarmed timer fails */
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling "
+			  "unarmed timer");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after "
+			  "cancelling unarmed timer");
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED,
+			  "evtim in incorrect state");
+
+	/* Delay 1 sec */
+	rte_delay_ms(1000);
+
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to cancel event_timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_CANCELED,
+			  "evtim in incorrect state");
+
+	rte_delay_ms(3000);
+
+	/* Make sure that no expiry event was generated */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+static int
+event_timer_cancel_double(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED,
+			  "timer in unexpected state");
+
+	/* Now, test that referencing the same timer twice in the same call
+	 * fails
+	 */
+	struct rte_event_timer *evtim_arr[] = {evtim, evtim};
+	ret = rte_event_timer_cancel_burst(adapter, evtim_arr,
+					   RTE_DIM(evtim_arr));
+
+	/* Two requests to cancel same timer, only one should succeed */
+	TEST_ASSERT_EQUAL(ret, 1, "Succeeded unexpectedly in canceling timer "
+			  "twice");
+
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after double-cancel: rte_errno = %d", rte_errno);
+
+	rte_delay_ms(3000);
+
+	/* Still make sure that no expiry event was generated */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that event timer adapter tick resolution works as expected by testing
+ * the number of adapter ticks that occur within a particular time interval.
+ */
+static int
+adapter_tick_resolution(void)
+{
+	struct rte_event_timer_adapter_stats stats;
+	uint64_t adapter_tick_count;
+
+	/* Only run this test in the software driver case */
+	if (!using_services)
+		return -ENOTSUP;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_reset(timdev),
+				"Failed to reset stats");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(timdev,
+			&stats), "Failed to get adapter stats");
+	TEST_ASSERT_EQUAL(stats.adapter_tick_count, 0, "Adapter tick count "
+			"not zeroed out");
+
+	/* Delay 1 second; should let at least 10 ticks occur with the default
+	 * adapter configuration used by this test.
+	 */
+	rte_delay_ms(1000);
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(timdev,
+			&stats), "Failed to get adapter stats");
+
+	adapter_tick_count = stats.adapter_tick_count;
+	TEST_ASSERT(adapter_tick_count >= 10 && adapter_tick_count <= 12,
+			"Expected 10-12 adapter ticks, got %"PRIu64"\n",
+			adapter_tick_count);
+
+	return TEST_SUCCESS;
+}
+
+static int
+adapter_create_max(void)
+{
+	int i;
+	uint32_t svc_start_count, svc_end_count;
+	struct rte_event_timer_adapter *adapters[
+					RTE_EVENT_TIMER_ADAPTER_NUM_MAX + 1];
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev,
+		// timer_adapter_id set in loop
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = MAX_TIMERS,
+		.flags = 0,
+	};
+
+	if (!using_services)
+		return -ENOTSUP;
+
+	svc_start_count = rte_service_get_count();
+
+	/* This test expects that there are sufficient service IDs available
+	 * to be allocated. I.e., RTE_EVENT_TIMER_ADAPTER_NUM_MAX may need to
+	 * be less than RTE_SERVICE_NUM_MAX if anything else uses a service
+	 * (the SW event device, for example).
+	 */
+	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) {
+		conf.timer_adapter_id = i;
+		adapters[i] = rte_event_timer_adapter_create_ext(&conf,
+				test_port_conf_cb, NULL);
+		TEST_ASSERT_NOT_NULL(adapters[i], "Failed to create adapter "
+				"%d", i);
+	}
+
+	conf.timer_adapter_id = i;
+	adapters[i] = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapters[i], "Created too many adapters");
+
+	/* Check that at least RTE_EVENT_TIMER_ADAPTER_NUM_MAX services
+	 * have been created
+	 */
+	svc_end_count = rte_service_get_count();
+	TEST_ASSERT_EQUAL(svc_end_count - svc_start_count,
+			RTE_EVENT_TIMER_ADAPTER_NUM_MAX,
+			"Failed to create expected number of services");
+
+	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++)
+		TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapters[i]),
+				"Failed to free adapter %d", i);
+
+	/* Check that service count is back to where it was at start */
+	svc_end_count = rte_service_get_count();
+	TEST_ASSERT_EQUAL(svc_start_count, svc_end_count, "Failed to release "
+			  "correct number of services");
+
+	return TEST_SUCCESS;
+}
+
+static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
+	.suite_name = "event timer functional test suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_state),
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_arm),
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_arm_burst),
+		TEST_CASE_ST(timdev_setup_sec, timdev_teardown,
+				test_timer_cancel),
+		TEST_CASE_ST(timdev_setup_sec, timdev_teardown,
+				test_timer_cancel_random),
+		TEST_CASE_ST(timdev_setup_usec_multicore, timdev_teardown,
+				test_timer_arm_multicore),
+		TEST_CASE_ST(timdev_setup_usec_multicore, timdev_teardown,
+				test_timer_arm_burst_multicore),
+		TEST_CASE_ST(timdev_setup_sec_multicore, timdev_teardown,
+				test_timer_cancel_multicore),
+		TEST_CASE_ST(timdev_setup_sec_multicore, timdev_teardown,
+				test_timer_cancel_burst_multicore),
+		TEST_CASE(adapter_create),
+		TEST_CASE_ST(timdev_setup_msec, NULL, adapter_free),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_get_info),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_lookup),
+		TEST_CASE_ST(NULL, timdev_teardown,
+				adapter_start),
+		TEST_CASE_ST(timdev_setup_msec, NULL,
+				adapter_stop),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				stat_inc_reset_ev_enq),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm_double),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm_expiry),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_rearm),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_max),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_invalid_sched_type),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_invalid_timeout),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_cancel),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_cancel_double),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_tick_resolution),
+		TEST_CASE(adapter_create_max),
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+static int
+test_event_timer_adapter_func(void)
+{
+	return unit_test_suite_runner(&event_timer_adptr_functional_testsuite);
+}
+
+REGISTER_TEST_COMMAND(event_timer_adapter_test, test_event_timer_adapter_func);
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 8/9] doc: add event timer adapter section to programmer's guide
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
                               ` (6 preceding siblings ...)
  2018-04-03 21:44             ` [PATCH v10 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
@ 2018-04-03 21:44             ` Erik Gabriel Carrillo
  2018-04-03 21:44             ` [PATCH v10 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
                               ` (2 subsequent siblings)
  10 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-03 21:44 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 doc/guides/prog_guide/event_timer_adapter.rst | 296 ++++++++++++++++++++++++++
 doc/guides/prog_guide/index.rst               |   1 +
 2 files changed, 297 insertions(+)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst

diff --git a/doc/guides/prog_guide/event_timer_adapter.rst b/doc/guides/prog_guide/event_timer_adapter.rst
new file mode 100644
index 0000000..7e5fe18
--- /dev/null
+++ b/doc/guides/prog_guide/event_timer_adapter.rst
@@ -0,0 +1,296 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(c) 2017 Intel Corporation. All rights reserved.
+
+Event Timer Adapter Library
+=================================
+
+The DPDK
+`Event Device library <http://dpdk.org/doc/guides/prog_guide/eventdev.html>`_
+introduces an event driven programming model which presents applications with
+an alternative to the polling model traditionally used in DPDK
+applications. Event devices can be coupled with arbitrary components to provide
+new event sources by using **event adapters**. The Event Timer Adapter is one
+such adapter; it bridges event devices and timer mechanisms.
+
+The Event Timer Adapter library extends the event driven model
+by introducing a :ref:`new type of event <timer_expiry_event>` that represents
+a timer expiration, and providing an API with which adapters can be created or
+destroyed, and :ref:`event timers <event_timer>` can be armed and canceled.
+
+The Event Timer Adapter library is designed to interface with hardware or
+software implementations of the timer mechanism; it will query an eventdev PMD
+to determine which implementation should be used.  The default software
+implementation manages timers using the DPDK
+`Timer library <http://dpdk.org/doc/guides/prog_guide/timer_lib.html>`_.
+
+Examples of using the API are presented in the `API Overview`_ and
+`Processing Timer Expiry Events`_ sections.  Code samples are abstracted and
+are based on the example of handling a TCP retransmission.
+
+.. _event_timer:
+
+Event Timer struct
+------------------
+Event timers are timers that enqueue a timer expiration event to an event
+device upon timer expiration.
+
+The Event Timer Adapter API represents each event timer with a generic struct,
+which contains an event and user metadata.  The ``rte_event_timer`` struct is
+defined in ``lib/librte_event/librte_event_timer_adapter.h``.
+
+.. _timer_expiry_event:
+
+Timer Expiry Event
+~~~~~~~~~~~~~~~~~~
+
+The event contained by an event timer is enqueued in the event device when the
+timer expires, and the event device uses the attributes below when scheduling
+it:
+
+* ``event_queue_id`` - Application should set this to specify an event queue to
+  which the timer expiry event should be enqueued
+* ``event_priority`` - Application can set this to indicate the priority of the
+  timer expiry event in the event queue relative to other events
+* ``sched_type`` - Application can set this to specify the scheduling type of
+  the timer expiry event
+* ``flow_id`` - Application can set this to indicate which flow this timer
+  expiry event corresponds to
+* ``op`` - Will be set to ``RTE_EVENT_OP_NEW`` by the event timer adapter
+* ``event_type`` - Will be set to ``RTE_EVENT_TYPE_TIMER`` by the event timer
+  adapter
+
+Timeout Ticks
+~~~~~~~~~~~~~
+
+The number of ticks from now in which the timer will expire. The ticks value
+has a resolution (``timer_tick_ns``) that is specified in the event timer
+adapter configuration.
+
+State
+~~~~~
+
+Before arming an event timer, the application should initialize its state to
+RTE_EVENT_TIMER_NOT_ARMED. The event timer's state will be updated when a
+request to arm or cancel it takes effect.
+
+If the application wishes to rearm the timer after it has expired, it should
+reset the state back to RTE_EVENT_TIMER_NOT_ARMED before doing so.
+
+User Metadata
+~~~~~~~~~~~~~
+
+Memory to store user specific metadata.  The event timer adapter implementation
+will not modify this area.
+
+API Overview
+----------------
+
+This section will introduce the reader to the event timer adapter API, showing
+how to create and configure an event timer adapter and use it to manage event
+timers.
+
+From a high level, the setup steps are:
+
+* rte_event_timer_adapter_create()
+* rte_event_timer_adapter_start()
+
+And to start and stop timers:
+
+* rte_event_timer_arm_burst()
+* rte_event_timer_cancel_burst()
+
+Create and Configure an Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To create an event timer adapter instance, initialize an
+``rte_event_timer_adapter_conf`` struct with the desired values, and pass it
+to ``rte_event_timer_adapter_create()``.
+
+.. code-block:: c
+
+	#define NSECPERSEC 1E9 // No of ns in 1 sec
+	const struct rte_event_timer_adapter_conf adapter_config = {
+                .event_dev_id = event_dev_id,
+                .timer_adapter_id = 0,
+                .clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+                .timer_tick_ns = NSECPERSEC / 10, // 100 milliseconds
+                .max_tmo_nsec = 180 * NSECPERSEC // 2 minutes
+                .nb_timers = 40000,
+                .timer_adapter_flags = 0,
+	};
+
+	struct rte_event_timer_adapter *adapter = NULL;
+	adapter = rte_event_timer_adapter_create(&adapter_config);
+
+	if (adapter == NULL) { ... };
+
+Before creating an instance of a timer adapter, the application should create
+and configure an event device along with its event ports. Based on the event
+device capability, it might require creating an additional event port to be
+used by the timer adapter.  If required, the
+``rte_event_timer_adapter_create()`` function will use a default method to
+configure an event port;  it will examine the current event device
+configuration, determine the next available port identifier number, and create
+a new event port with a default port configuration.
+
+If the application desires to have finer control of event port allocation
+and setup, it can use the ``rte_event_timer_adapter_create_ext()`` function.
+This function is passed a callback function that will be invoked if the
+adapter needs to create an event port, giving the application the opportunity
+to control how it is done.
+
+Retrieve Event Timer Adapter Contextual Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The event timer adapter implementation may have constraints on tick resolution
+or maximum timer expiry timeout based on the given event timer adapter or
+system.  In this case, the implementation may adjust the tick resolution or
+maximum timeout to the best possible configuration.
+
+Upon successful event timer adapter creation, the application can get the
+configured resolution and max timeout with
+``rte_event_timer_adapter_get_info()``. This function will return an
+``rte_event_timer_adapter_info`` struct, which contains the following members:
+
+* ``min_resolution_ns`` - Minimum timer adapter tick resolution in ns.
+* ``max_tmo_ns`` - Maximum timer timeout(expiry) in ns.
+* ``adapter_conf`` - Configured event timer adapter attributes
+
+Configuring the Service Component
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the adapter uses a service component, the application is required to map
+the service to a service core before starting the adapter:
+
+.. code-block:: c
+
+        uint32_t service_id;
+
+        if (rte_event_timer_adapter_service_id_get(adapter, &service_id) == 0)
+                rte_service_map_lcore_set(service_id, EVTIM_CORE_ID);
+
+An event timer adapter uses a service component if the event device PMD
+indicates that the adapter should use a software implementation.
+
+Starting the Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The application should call ``rte_event_timer_adapter_start()`` to start
+running the event timer adapter. This function calls the start entry points
+defined by eventdev PMDs for hardware implementations or puts a service
+component into the running state in the software implementation.
+
+Arming Event Timers
+~~~~~~~~~~~~~~~~~~~~~
+
+Once an event timer adapter has been started, an application can begin to
+manage event timers with it.
+
+The application should allocate ``struct rte_event_timer`` objects from a
+mempool or huge-page backed application buffers of required size. Upon
+successful allocation, the application should initialize the event timer, and
+then set any of the necessary event attributes described in the
+`Timer Expiry Event`_ section. In the following example, assume ``conn``
+represents a TCP connection and that ``event_timer_pool`` is a mempool that
+was created previously:
+
+.. code-block:: c
+
+	rte_mempool_get(event_timer_pool, (void **)&conn->evtim);
+	if (conn->evtim == NULL) { ... }
+
+	/* Set up the event timer. */
+	conn->evtim->ev.op = RTE_EVENT_OP_NEW;
+	conn->evtim->ev.queue_id = event_queue_id;
+        conn->evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+        conn->evtim->ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
+        conn->evtim->ev.event_type = RTE_EVENT_TYPE_TIMER;
+	conn->evtim->ev.event_ptr = conn;
+	conn->evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns)
+
+Note that it is necessary to initialize the event timer state to
+RTE_EVENT_TIMER_NOT_ARMED.  Also note that we have saved a pointer to the
+``conn`` object in the timer's event payload. This will allow us to locate
+the connection object again once we dequeue the timer expiry event from the
+event device later.  As a convenience, the application may specify no value for
+ev.event_ptr, and the adapter will by default set it to point at the event
+timer itself.
+
+Now we can arm the event timer with ``rte_event_timer_arm_burst()``:
+
+.. code-block:: c
+
+	ret = rte_event_timer_arm_burst(adapter, &conn->evtim, 1);
+	if (ret != 1) { ... }
+
+Once an event timer expires, the application may free it or rearm it as
+necessary.  If the application will rearm the timer, the state should be reset
+to RTE_EVENT_TIMER_NOT_ARMED by the application before rearming it.
+
+Multiple Event Timers with Same Expiry Value
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the special case that there is a set of event timers that should all expire
+at the same time, the application may call
+``rte_event_timer_arm_tmo_tick_burst()``, which allows the implementation to
+optimize the operation if possible.
+
+Canceling Event Timers
+~~~~~~~~~~~~~~~~~~~~~~~
+
+An event timer that has been armed as described in `Arming Event Timers`_ can
+be canceled by calling ``rte_event_timer_cancel_burst()``:
+
+.. code-block:: c
+
+	/* Ack for the previous tcp data packet has been received;
+	 * cancel the retransmission timer
+         */
+	rte_event_timer_cancel_burst(adapter, &conn->timer, 1);
+
+Processing Timer Expiry Events
+------------------------------
+
+Once an event timer has successfully enqueued a timer expiry event in the event
+device, the application will subsequently dequeue it from the event device.
+The application can use the event payload to retrieve a pointer to the object
+associated with the event timer. It can then re-arm the event timer or free the
+event timer object as desired:
+
+.. code-block:: c
+
+	void
+	event_processing_loop(...)
+	{
+		while (...) {
+			/* Receive events from the configured event port. */
+			rte_event_dequeue_burst(event_dev_id, event_port, &ev, 1, 0);
+			...
+			switch(ev.event_type) {
+				...
+				case RTE_EVENT_TYPE_TIMER:
+					process_timer_event(ev);
+					...
+					break;
+			}
+		}
+	}
+
+	uint8_t
+	process_timer_event(...)
+	{
+		/* A retransmission timeout for the connection has been received. */
+		conn = ev.event_ptr;
+		/* Retransmit last packet (e.g. TCP segment). */
+		...
+		/* Re-arm timer using original values. */
+		rte_event_timer_arm_burst(adapter_id, &conn->timer, 1);
+	}
+
+Summary
+-------
+
+The Event Timer Adapter library extends the DPDK event-based programming model
+by representing timer expirations as events in the system and allowing
+applications to use existing event processing loops to arm and cancel event
+timers or handle timer expiry events.
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index bbbe789..589c05d 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -42,6 +42,7 @@ Programmer's Guide
     thread_safety_dpdk_functions
     eventdev
     event_ethernet_rx_adapter
+    event_timer_adapter
     qos_framework
     power_man
     packet_classif_access_ctrl
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v10 9/9] doc: add event timer adapter documentation
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
                               ` (7 preceding siblings ...)
  2018-04-03 21:44             ` [PATCH v10 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
@ 2018-04-03 21:44             ` Erik Gabriel Carrillo
  2018-04-04  2:31             ` [PATCH v10 0/9] eventtimer: introduce event timer adapter Jerin Jacob
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
  10 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-03 21:44 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev, hemant.agrawal

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 MAINTAINERS                            |  7 +++++++
 doc/api/doxy-api-index.md              | 32 +++-----------------------------
 doc/guides/rel_notes/release_18_05.rst |  6 ++++++
 3 files changed, 16 insertions(+), 29 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index d4c0cc1..d72f012 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -317,6 +317,13 @@ F: lib/librte_eventdev/*eth_rx_adapter*
 F: test/test/test_event_eth_rx_adapter.c
 F: doc/guides/prog_guide/event_ethernet_rx_adapter.rst
 
+Eventdev Timer Adapter API - EXPERIMENTAL
+M: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
+T: git://dpdk.org/next/dpdk-next-eventdev
+F: lib/librte_eventdev/*timer_adapter*
+F: test/test/test_event_timer_adapter.c
+F: doc/guides/prog_guide/event_timer_adapter.rst
+
 Raw device API - EXPERIMENTAL
 M: Shreyansh Jain <shreyansh.jain@nxp.com>
 M: Hemant Agrawal <hemant.agrawal@nxp.com>
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..5c6cd51 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -2,35 +2,8 @@ API {#index}
 ===
 
 <!--
-  BSD LICENSE
-
-  Copyright 2013-2017 6WIND S.A.
-
-  Redistribution and use in source and binary forms, with or without
-  modification, are permitted provided that the following conditions
-  are met:
-
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in
-      the documentation and/or other materials provided with the
-      distribution.
-    * Neither the name of 6WIND S.A. nor the names of its
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
-
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright(c) 2013-2017 6WIND S.A.
 -->
 
 The public API headers are grouped by topics:
@@ -47,6 +20,7 @@ The public API headers are grouped by topics:
   [security]           (@ref rte_security.h),
   [eventdev]           (@ref rte_eventdev.h),
   [event_eth_rx_adapter]   (@ref rte_event_eth_rx_adapter.h),
+  [event_timer_adapter]    (@ref rte_event_timer_adapter.h),
   [rawdev]             (@ref rte_rawdev.h),
   [metrics]            (@ref rte_metrics.h),
   [bitrate]            (@ref rte_bitrate.h),
diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst
index 9cc77f8..d2a4192 100644
--- a/doc/guides/rel_notes/release_18_05.rst
+++ b/doc/guides/rel_notes/release_18_05.rst
@@ -58,6 +58,12 @@ New Features
   * Added support for NVGRE, VXLAN and GENEVE filters in flow API.
   * Added support for DROP action in flow API.
 
+* **Added the Event Timer Adapter Library.**
+
+  The Event Timer Adapter Library extends the event-based model by introducing
+  APIs that allow applications to arm/cancel event timers that generate
+  timer expiry events. This new type of event is scheduled by an event device
+  along with existing types of events.
 
 API Changes
 -----------
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v10 0/9] eventtimer: introduce event timer adapter
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
                               ` (8 preceding siblings ...)
  2018-04-03 21:44             ` [PATCH v10 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
@ 2018-04-04  2:31             ` Jerin Jacob
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
  10 siblings, 0 replies; 133+ messages in thread
From: Jerin Jacob @ 2018-04-04  2:31 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev, hemant.agrawal

-----Original Message-----
> Date: Tue, 3 Apr 2018 16:44:14 -0500
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com, jerin.jacob@caviumnetworks.com
> CC: dev@dpdk.org, hemant.agrawal@nxp.com
> Subject: [PATCH v10 0/9] eventtimer: introduce event timer adapter 
> X-Mailer: git-send-email 1.7.10
> 
> This patch series contains the next iteration of the Event Timer Adapter
> library, which abstracts timer mechanisms that are tightly coupled with event
> devices, and extends the event based programming model so that timer
> expirations are represented as an event.
> 
> v10
> - remove stale references to rte_event_timer_init API and update docs (Jerin)
> - rebase to latest dpdk-next-eventdev tree (Jerin)
> - make sw_event_adapter_timer_ops var static (Pavan)

Found build issue with T=i686-native-linuxapp-gcc target

/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:
In function ‘sw_event_timer_cb’:
/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:557:12:
error: cast to pointer from integer of different size
[-Werror=int-to-pointer-cast]
  adapter = (struct rte_event_timer_adapter *)evtim->impl_opaque[1];
            ^
/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:
In function ‘sw_event_timer_adapter_service_func’:
/export/dpdk-next-eventdev/lib/librte_eventdev/rte_event_timer_adapter.c:748:11:
error: cast to pointer from integer of different size
[-Werror=int-to-pointer-cast]
     tim = (struct rte_timer *)evtim->impl_opaque[0];
           ^
cc1: all warnings being treated as errors

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v10 3/9] eventtimer: add common code
  2018-04-03 21:44             ` [PATCH v10 3/9] eventtimer: add common code Erik Gabriel Carrillo
@ 2018-04-04 16:50               ` Pavan Nikhilesh
  0 siblings, 0 replies; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-04-04 16:50 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, jerin.jacob; +Cc: dev

On Tue, Apr 03, 2018 at 04:44:17PM -0500, Erik Gabriel Carrillo wrote:
> This commit adds the logic that is shared by all event timer adapter
> drivers; the common code handles instance allocation and some
> initialization.
>
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  config/common_base                                |   1 +
>  drivers/event/sw/sw_evdev.c                       |  18 +
>  lib/librte_eventdev/Makefile                      |   2 +
>  lib/librte_eventdev/rte_event_timer_adapter.c     | 387 ++++++++++++++++++++++
>  lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 114 +++++++
>  lib/librte_eventdev/rte_eventdev.c                |  22 ++
>  lib/librte_eventdev/rte_eventdev.h                |  20 ++
>  lib/librte_eventdev/rte_eventdev_pmd.h            |  35 ++
>  lib/librte_eventdev/rte_eventdev_version.map      |  20 +-
>  9 files changed, 618 insertions(+), 1 deletion(-)
>  create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
>  create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h
>
<snip>
>  DPDK_18.02 {
> @@ -80,3 +79,22 @@ DPDK_18.05 {
>
>  	rte_event_dev_stop_flush_callback_register;
>  } DPDK_18.02;
> +
> +EXPERIMENTAL {
> +	global:
> +
> +        rte_event_timer_adapter_caps_get;

A trivial extra space issue here please remove it with that,

Acked-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>

> +	rte_event_timer_adapter_create;
> +	rte_event_timer_adapter_create_ext;
> +	rte_event_timer_adapter_free;
> +	rte_event_timer_adapter_get_info;
> +	rte_event_timer_adapter_lookup;
> +	rte_event_timer_adapter_service_id_get;
> +	rte_event_timer_adapter_start;
> +	rte_event_timer_adapter_stats_get;
> +	rte_event_timer_adapter_stats_reset;
> +	rte_event_timer_adapter_stop;
> +	rte_event_timer_arm_burst;
> +	rte_event_timer_arm_tmo_tick_burst;
> +	rte_event_timer_cancel_burst;
> +} DPDK_18.05;
> --
> 2.6.4
>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* Re: [PATCH v10 6/9] eventtimer: add support for meson build system
  2018-04-03 21:44             ` [PATCH v10 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
@ 2018-04-04 16:51               ` Pavan Nikhilesh
  0 siblings, 0 replies; 133+ messages in thread
From: Pavan Nikhilesh @ 2018-04-04 16:51 UTC (permalink / raw)
  To: Erik Gabriel Carrillo, hemant.agrawal, jerin.jacob; +Cc: dev

On Tue, Apr 03, 2018 at 04:44:20PM -0500, Erik Gabriel Carrillo wrote:
> Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> ---
>  config/rte_config.h             | 1 +
>  lib/librte_eventdev/meson.build | 9 ++++++---
>  lib/meson.build                 | 3 ++-
>  3 files changed, 9 insertions(+), 4 deletions(-)
>
Acked-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v11 0/9] eventtimer: introduce event timer adapter
  2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
                               ` (9 preceding siblings ...)
  2018-04-04  2:31             ` [PATCH v10 0/9] eventtimer: introduce event timer adapter Jerin Jacob
@ 2018-04-04 21:51             ` Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 1/9] " Erik Gabriel Carrillo
                                 ` (9 more replies)
  10 siblings, 10 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-04 21:51 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev

This patch series contains the next iteration of the Event Timer Adapter
library, which abstracts timer mechanisms that are tightly coupled with event
devices, and extends the event based programming model so that timer
expirations are represented as an event.

v11
- fix build error (Jerin)
- fix whitespace issue (Pavan)

v10
- remove stale references to rte_event_timer_init API and update docs (Jerin)
- rebase to latest dpdk-next-eventdev tree (Jerin)
- make sw_event_adapter_timer_ops var static (Pavan)

v9
- Addressed comments on previous series from Pavan:
  - Don't assume services exist in HW cases
  - Adjust retry logic in a couple of tests
- Addressed comments on previous series from Jerin:
  - Fix build warning
- Addressed comments on previous series from Hemant:
  - Adjust copyright text

v8
- Addressed comments on previous series from Jerin:
  - Add better git comment to initial patch
  - Return uint16_t for fastpath functions
  - Move updates to existing licenses to separate patch for individual review
  - Fix clang build error
  - Move fastpath functions into header as static inline functions
  - Remove duplicate map file entry
  - Fix flag value
  - Move update to rte.app.mk file into separate commit
- Addressed comments on previous series from Pavan:
  - Make tests generic so that they work for software or hardware event devices
    and timer mechanisms
  - Don't access eventdev internals from tests
- Integrated unit tests from Pavan

v7
- Addressed comments on previous patch series from Pavan:
  - Use SPDX license tags
  - Squash various commits to make series easier to review
  - Tag experimental functions as such
  - Use one mempool for messages and timers in sw driver 
  - Limit service cores mapped to sw driver's service to one
  - Use smp memory barriers
  - In service function, invoke rte_timer_manage() with frequency matching the
    resolution the adapter was configured with
- Reworked synchronization in sw driver between threads producing messages
  and service thread that consumes them.  The new approach avoids a situation
  where event timers couldn't be armed/canceled from the same lcore the service
  was running on.
- Updated logging facility
- Added more unit tests
- Added support for meson build

v6
- Addressed comments on previous version from Jerin:
  - Added RTE_EVENT_TIMER_CANCELED event timer state back in
  - remove check for started adapter in timer arm/cancel functions 
  - reuse CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG instead of adding new config option
- Added initial version of software driver implementation
- Added stats APIs
- Added API to retrieve adapter service ID
- Added API to initialize event timer
- Added entry to Programmer's Guide in documentation
- Added new unit tests to auto-test

v5
- Addressed comments on previous version from Pavan:
  - renamed rte_event_timer_adapter_driver.h to rte_event_timer_adapter_pmd.h
  - moved contents of sw_event_timer_adapter.c into rte_event_timer_adapter.c
  - added flags parameter to timer_adapter_caps_get() call
  - added DEBUG config variable to conditionally compile run-time checks on
    datapath
  - fixed license text and file description
- Also added a config variable to enable/disable compilation of event timer
  adapter - feedback on whether this is desirable is appreciated

v4
- Split changes into multiple patches for easier review

v3
- Reworked allocation and ops organization in common code based on feedback
  received from Jerin and Pavan. This will allow fast-path function pointers to 
  be dereferenced with one level of indirection with pointers valid in primary
  and secondary processes.
- Moved default software implementation from sw_evdev directory to eventdev
  library directory, which will allow it to be used by any eventdev PMD as an
  alternative to providing its own definitions.
- Reverted occurrences of id back to pointer to adapter struct in library API
- Added rte_event_timer_adapter_lookup() function back in

v2
- Added ops structure and stubbed out plugin for SW impl
- Added unit test stubs
- Replaced occurrences of "wheel" in API with "adapter"
- Replaced occurrences of pointer to struct rte_event_timer_adapter with ids
- Removed rte_event_timer_adapter_lookup() function
- Replaced RTE_EVENT_TIMER_SUCCESS_{ARM,CANCEL} states with
  RTE_EVENT_TIMER_ARMED

Erik Gabriel Carrillo (9):
  eventtimer: introduce event timer adapter
  eventdev: convert to SPDX license tag in header
  eventtimer: add common code
  mk: update library order in static build
  eventtimer: add default software driver
  eventtimer: add support for meson build system
  test: add event timer adapter auto-test
  doc: add event timer adapter section to programmer's guide
  doc: add event timer adapter documentation

 MAINTAINERS                                       |    7 +
 config/common_base                                |    1 +
 config/rte_config.h                               |    1 +
 doc/api/doxy-api-index.md                         |   32 +-
 doc/guides/prog_guide/event_timer_adapter.rst     |  296 ++++
 doc/guides/prog_guide/index.rst                   |    1 +
 doc/guides/rel_notes/release_18_05.rst            |    6 +
 drivers/event/sw/sw_evdev.c                       |   18 +
 lib/Makefile                                      |    2 +-
 lib/librte_eventdev/Makefile                      |    5 +-
 lib/librte_eventdev/meson.build                   |    9 +-
 lib/librte_eventdev/rte_event_timer_adapter.c     | 1299 +++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h     |  768 +++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h |  114 ++
 lib/librte_eventdev/rte_eventdev.c                |   22 +
 lib/librte_eventdev/rte_eventdev.h                |   61 +-
 lib/librte_eventdev/rte_eventdev_pmd.h            |   35 +
 lib/librte_eventdev/rte_eventdev_version.map      |   20 +-
 lib/meson.build                                   |    3 +-
 mk/rte.app.mk                                     |    2 +-
 test/test/Makefile                                |    1 +
 test/test/test_event_timer_adapter.c              | 1830 +++++++++++++++++++++
 22 files changed, 4462 insertions(+), 71 deletions(-)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h
 create mode 100644 test/test/test_event_timer_adapter.c

-- 
2.6.4

^ permalink raw reply	[flat|nested] 133+ messages in thread

* [PATCH v11 1/9] eventtimer: introduce event timer adapter
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
@ 2018-04-04 21:51               ` Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
                                 ` (8 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-04 21:51 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev

Event devices can be coupled with various components to provide
new event sources by using event adapters.  The event timer adapter
is one such adapter; it bridges event devices and timer mechanisms.
This library extends the event-driven programming model by
introducing a new type of event that represents a timer expiration,
and it provides APIs with which adapters can be created or destroyed
and event timers can be armed and canceled.

Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 lib/librte_eventdev/Makefile                  |   1 +
 lib/librte_eventdev/rte_event_timer_adapter.h | 715 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_eventdev.h            |   4 +-
 3 files changed, 718 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h

diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index d27dd07..549b182 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -28,6 +28,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
new file mode 100644
index 0000000..6a76791
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -0,0 +1,715 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc.
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ * @file
+ *
+ * RTE Event Timer Adapter
+ *
+ * An event timer adapter has the following abstract working model:
+ *
+ *                               timer_tick_ns
+ *                                   +
+ *                      +-------+    |
+ *                      |       |    |
+ *              +-------+ bkt 0 +----v---+
+ *              |       |       |        |
+ *              |       +-------+        |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *          |       |                |       |  |   |   |   |   |
+ *          | bkt n |                | bkt 1 |<-> t0| t1| t2| tn|
+ *          |       |                |       |  |   |   |   |   |
+ *          +---+---+                +---+---+  +---+---+---+---+
+ *              |     Timer adapter      |
+ *          +---+---+                +---+---+
+ *          |       |                |       |
+ *          | bkt 4 |                | bkt 2 |<--- Current bucket
+ *          |       |                |       |
+ *          +---+---+                +---+---+
+ *               |      +-------+       |
+ *               |      |       |       |
+ *               +------+ bkt 3 +-------+
+ *                      |       |
+ *                      +-------+
+ *
+ * - It has a virtual monotonically increasing 64-bit timer adapter clock based
+ *   on *enum rte_event_timer_adapter_clk_src* clock source. The clock source
+ *   could be a CPU clock, or a platform dependent external clock.
+ *
+ * - The application creates a timer adapter instance with given the clock
+ *   source, the total number of event timers, and a resolution(expressed in ns)
+ *   to traverse between the buckets.
+ *
+ * - Each timer adapter may have 0 to n buckets based on the configured
+ *   max timeout(max_tmo_ns) and resolution(timer_tick_ns). Upon starting the
+ *   timer adapter, the adapter starts ticking at *timer_tick_ns* resolution.
+ *
+ * - The application arms an event timer that will expire *timer_tick_ns*
+ *   from now.
+ *
+ * - The application can cancel an armed timer and no timer expiry event will be
+ *   generated.
+ *
+ * - If a timer expires then the library injects the timer expiry event in
+ *   the designated event queue.
+ *
+ * - The timer expiry event will be received through *rte_event_dequeue_burst*.
+ *
+ * - The application frees the timer adapter instance.
+ *
+ * Multiple timer adapters can be created with a varying level of resolution
+ * for various expiry use cases that run in parallel.
+ *
+ * Before using the timer adapter, the application has to create and configure
+ * an event device along with the event port. Based on the event device
+ * capability it might require creating an additional event port to be used
+ * by the timer adapter.
+ *
+ * The application creates the event timer adapter using the
+ * ``rte_event_timer_adapter_create()``. The event device id is passed to this
+ * function, inside this function the event device capability is checked,
+ * and if an in-built port is absent the application uses the default
+ * function to create a new producer port.
+ *
+ * The application may also use the function
+ * ``rte_event_timer_adapter_create_ext()`` to have granular control over
+ * producer port creation in a case where the in-built port is absent.
+ *
+ * After creating the timer adapter, the application has to start it
+ * using ``rte_event_timer_adapter_start()``. The buckets are traversed from
+ * 0 to n; when the adapter ticks, the next bucket is visited. Each time,
+ * the list per bucket is processed, and timer expiry events are sent to the
+ * designated event queue.
+ *
+ * The application can arm one or more event timers using the
+ * ``rte_event_timer_arm_burst()``. The *timeout_ticks* represents the number
+ * of *timer_tick_ns* after which the timer has to expire. The timeout at
+ * which the timers expire can be grouped or be independent of each
+ * event timer instance. ``rte_event_timer_arm_tmo_tick_burst()`` addresses the
+ * former case and ``rte_event_timer_arm_burst()`` addresses the latter case.
+ *
+ * The application can cancel the timers from expiring using the
+ * ``rte_event_timer_cancel_burst()``.
+ *
+ * On the secondary process, ``rte_event_timer_adapter_lookup()`` can be used
+ * to get the timer adapter pointer from its id and use it to invoke fastpath
+ * operations such as arm and cancel.
+ *
+ * Some of the use cases of event timer adapter are Beacon Timers,
+ * Generic SW Timeout, Wireless MAC Scheduling, 3G Frame Protocols,
+ * Packet Scheduling, Protocol Retransmission Timers, Supervision Timers.
+ * All these use cases require high resolution and low time drift.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_spinlock.h>
+#include <rte_memory.h>
+
+#include "rte_eventdev.h"
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this enum may change without prior notice
+ *
+ * Timer adapter clock source
+ */
+enum rte_event_timer_adapter_clk_src {
+	RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+	/**< Use CPU clock as the clock source. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK0,
+	/**< Platform dependent external clock source 0. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK1,
+	/**< Platform dependent external clock source 1. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK2,
+	/**< Platform dependent external clock source 2. */
+	RTE_EVENT_TIMER_ADAPTER_EXT_CLK3,
+	/**< Platform dependent external clock source 3. */
+};
+
+#define RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES	(1ULL << 0)
+/**< The event timer adapter implementation may have constraints on the
+ * resolution (timer_tick_ns) and maximum timer expiry timeout(max_tmo_ns)
+ * based on the given timer adapter or system.  If this flag is set, the
+ * implementation adjusts the resolution and maximum timeout to the best
+ * possible configuration. On successful timer adapter creation, the
+ * application can get the configured resolution and max timeout with
+ * ``rte_event_timer_adapter_get_info()``.
+ *
+ * @see struct rte_event_timer_adapter_info::min_resolution_ns
+ * @see struct rte_event_timer_adapter_info::max_tmo_ns
+ */
+#define RTE_EVENT_TIMER_ADAPTER_F_SP_PUT	(1ULL << 1)
+/**< ``rte_event_timer_arm_burst()`` API to be used in single producer mode.
+ *
+ * @see struct rte_event_timer_adapter_conf::flags
+ */
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter configuration structure
+ */
+struct rte_event_timer_adapter_conf {
+	uint8_t event_dev_id;
+	/**< Event device identifier */
+	uint16_t timer_adapter_id;
+	/**< Event timer adapter identifier */
+	uint32_t socket_id;
+	/**< Identifier of socket from which to allocate memory for adapter */
+	enum rte_event_timer_adapter_clk_src clk_src;
+	/**< Clock source for timer adapter */
+	uint64_t timer_tick_ns;
+	/**< Timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expiry) in ns */
+	uint64_t nb_timers;
+	/**< Total number of timers per adapter */
+	uint64_t flags;
+	/**< Timer adapter config flags (RTE_EVENT_TIMER_ADAPTER_F_*) */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer adapter stats structure
+ */
+struct rte_event_timer_adapter_stats {
+	uint64_t evtim_exp_count;
+	/**< Number of event timers that have expired. */
+	uint64_t ev_enq_count;
+	/**< Eventdev enqueue count */
+	uint64_t ev_inv_count;
+	/**< Invalid expiry event count */
+	uint64_t evtim_retry_count;
+	/**< Event timer retry count */
+	uint64_t adapter_tick_count;
+	/**< Tick count for the adapter, at its resolution */
+};
+
+struct rte_event_timer_adapter;
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Callback function type for producer port creation.
+ */
+typedef int (*rte_event_timer_adapter_port_conf_cb_t)(uint16_t id,
+						      uint8_t event_dev_id,
+						      uint8_t *event_port_id,
+						      void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create an event timer adapter.
+ *
+ * This function must be invoked first before any other function in the API.
+ *
+ * @param conf
+ *   The event timer adapter configuration structure.
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ *   - EIO: event device reconfiguration and restart error.  The adapter
+ *   reconfigures the event device with an additional port by default if it is
+ *   required to use a service to manage timers. If the device had been started
+ *   before this call, this error code indicates an error in restart following
+ *   an error in reconfiguration, i.e., a combination of the two error codes.
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create a timer adapter with the supplied callback.
+ *
+ * This function can be used to have a more granular control over the timer
+ * adapter creation.  If a built-in port is absent, then the function uses the
+ * callback provided to create and get the port id to be used as a producer
+ * port.
+ *
+ * @param conf
+ *   The timer adapter configuration structure
+ * @param conf_cb
+ *   The port config callback function.
+ * @param conf_arg
+ *   Opaque pointer to the argument for the callback function
+ *
+ * @return
+ *   A pointer to the new allocated event timer adapter on success.
+ *   NULL on error with rte_errno set appropriately.
+ *   Possible rte_errno values include:
+ *   - ERANGE: timer_tick_ns is not in supported range.
+ *   - ENOMEM: unable to allocate sufficient memory for adapter instances
+ *   - EINVAL: invalid event device identifier specified in config
+ *   - ENOSPC: maximum number of adapters already created
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Timer adapter info structure.
+ */
+struct rte_event_timer_adapter_info {
+	uint64_t min_resolution_ns;
+	/**< Minimum timer adapter resolution in ns */
+	uint64_t resolution_ns;
+	/**< Actual timer adapter resolution in ns */
+	uint64_t max_tmo_ns;
+	/**< Maximum timer timeout(expire) in ns */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configured timer adapter attributes */
+	uint32_t caps;
+	/**< Event timer adapter capabilities */
+	int16_t event_dev_port_id;
+	/**< Event device port ID, if applicable */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve the contextual information of an event timer adapter.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @param[out] adapter_info
+ *   A pointer to a structure of type *rte_event_timer_adapter_info* to be
+ *   filled with the contextual information of the adapter.
+ *
+ * @return
+ *   - 0: Success, driver updates the contextual information of the
+ *   timer adapter
+ *   - <0: Error code returned by the driver info get function.
+ *   - -EINVAL: adapter identifier invalid
+ *
+ * @see RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES,
+ *   struct rte_event_timer_adapter_info
+ *
+ */
+int __rte_experimental
+rte_event_timer_adapter_get_info(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Start a timer adapter.
+ *
+ * The adapter start step is the last one and consists of setting the timer
+ * adapter to start accepting the timers and schedules to event queues.
+ *
+ * On success, all basic functions exported by the API (timer arm,
+ * timer cancel and so on) can be invoked.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter started.
+ *   - <0: Error code returned by the driver start function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_start(
+		const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Stop an event timer adapter.
+ *
+ * The adapter can be restarted with a call to
+ * ``rte_event_timer_adapter_start()``.
+ *
+ * @param adapter
+ *   A pointer to the event timer adapter structure.
+ *
+ * @return
+ *   - 0: Success, adapter stopped.
+ *   - <0: Error code returned by the driver stop function.
+ *   - -EINVAL if adapter identifier invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Lookup an event timer adapter using its identifier.
+ *
+ * If an event timer adapter was created in another process with the same
+ * identifier, this function will locate its state and set up access to it
+ * so that it can be used in this process.
+ *
+ * @param adapter_id
+ *  The event timer adapter identifier.
+ *
+ * @return
+ *  A pointer to the event timer adapter matching the identifier on success.
+ *  NULL on error with rte_errno set appropriately.
+ *  Possible rte_errno values include:
+ *   - ENOENT - requested entry not available to return.
+ */
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_lookup(uint16_t adapter_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Free an event timer adapter.
+ *
+ * Destroy an event timer adapter, freeing all resources.
+ *
+ * Before invoking this function, the application must wait for all the
+ * armed timers to expire or cancel the outstanding armed timers.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully freed the event timer adapter resources.
+ *   - <0: Failed to free the event timer adapter resources.
+ *   - -EAGAIN:  adapter is busy; timers outstanding
+ *   - -EBUSY: stop hasn't been called for this adapter yet
+ *   - -EINVAL: adapter id invalid, or adapter invalid
+ */
+int __rte_experimental
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter);
+
+/**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure
+ *   - -ESRCH: the adapter does not require a service to operate
+ */
+int __rte_experimental
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param[out] stats
+ *   A pointer to a structure to fill with statistics.
+ *
+ * @return
+ *   - 0: Successfully retrieved.
+ *   - <0: Failure; error code returned.
+ */
+int __rte_experimental
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully reset;
+ *   - <0: Failure; error code returned.
+ */
+int __rte_experimental rte_event_timer_adapter_stats_reset(
+		struct rte_event_timer_adapter *adapter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * Event timer state.
+ */
+enum rte_event_timer_state {
+	RTE_EVENT_TIMER_NOT_ARMED	= 0,
+	/**< Event timer not armed. */
+	RTE_EVENT_TIMER_ARMED		= 1,
+	/**< Event timer successfully armed. */
+	RTE_EVENT_TIMER_CANCELED	= 2,
+	/**< Event timer successfully canceled. */
+	RTE_EVENT_TIMER_ERROR		= -1,
+	/**< Generic event timer error. */
+	RTE_EVENT_TIMER_ERROR_TOOEARLY	= -2,
+	/**< Event timer timeout tick value is too small for the adapter to
+	 * handle, given its configured resolution.
+	 */
+	RTE_EVENT_TIMER_ERROR_TOOLATE	= -3,
+	/**< Event timer timeout tick is greater than the maximum timeout.*/
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * The generic *rte_event_timer* structure to hold the event timer attributes
+ * for arm and cancel operations.
+ */
+RTE_STD_C11
+struct rte_event_timer {
+	struct rte_event ev;
+	/**<
+	 * Expiry event attributes.  On successful event timer timeout,
+	 * the following attributes will be used to inject the expiry event to
+	 * the eventdev:
+	 *  - event_queue_id: Targeted event queue id for expiry events.
+	 *  - event_priority: Event priority of the event expiry event in the
+	 *  event queue relative to other events.
+	 *  - sched_type: Scheduling type of the expiry event.
+	 *  - flow_id: Flow id of the expiry event.
+	 *  - op: RTE_EVENT_OP_NEW
+	 *  - event_type: RTE_EVENT_TYPE_TIMER
+	 */
+	volatile enum rte_event_timer_state state;
+	/**< State of the event timer. */
+	uint64_t timeout_ticks;
+	/**< Expiry timer ticks expressed in number of *timer_ticks_ns* from
+	 * now.
+	 * @see struct rte_event_timer_adapter_info::adapter_conf::timer_tick_ns
+	 */
+	uint64_t impl_opaque[2];
+	/**< Implementation-specific opaque data.
+	 * An event timer adapter implementation use this field to hold
+	 * implementation specific values to share between the arm and cancel
+	 * operations.  The application should not modify this field.
+	 */
+	uint8_t user_meta[0];
+	/**< Memory to store user specific metadata.
+	 * The event timer adapter implementation should not modify this area.
+	 */
+} __rte_cache_aligned;
+
+typedef uint16_t (*rte_event_timer_arm_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Enable event timers to enqueue timer events upon expiry */
+typedef uint16_t (*rte_event_timer_arm_tmo_tick_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint64_t timeout_tick,
+		uint16_t nb_tims);
+/**< @internal Enable event timers with common expiration time */
+typedef uint16_t (*rte_event_timer_cancel_burst_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer **tims,
+		uint16_t nb_tims);
+/**< @internal Prevent event timers from enqueuing timer events */
+
+/**
+ * @internal Data structure associated with each event timer adapter.
+ */
+struct rte_event_timer_adapter {
+	rte_event_timer_arm_burst_t arm_burst;
+	/**< Pointer to driver arm_burst function. */
+	rte_event_timer_arm_tmo_tick_burst_t arm_tmo_tick_burst;
+	/**< Pointer to driver arm_tmo_tick_burst function. */
+	rte_event_timer_cancel_burst_t cancel_burst;
+	/**< Pointer to driver cancel function. */
+	struct rte_event_timer_adapter_data *data;
+	/**< Pointer to shared adapter data */
+	const struct rte_event_timer_adapter_ops *ops;
+	/**< Functions exported by adapter driver */
+
+	RTE_STD_C11
+	uint8_t allocated : 1;
+	/**< Flag to indicate that this adapter has been allocated */
+} __rte_cache_aligned;
+
+#define ADAPTER_VALID_OR_ERR_RET(adapter, retval) do { \
+	if (adapter == NULL || !adapter->allocated)    \
+		return retval;			       \
+} while (0)
+#define FUNC_PTR_OR_ERR_RET(func, errval) do { \
+	if ((func) == NULL)		       \
+		return errval;		       \
+} while (0)
+
+#define FUNC_PTR_OR_NULL_RET_WITH_ERRNO(func, errval) do { \
+	if ((func) == NULL) {				   \
+		rte_errno = errval;			   \
+		return NULL;				   \
+	}						   \
+} while (0)
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with separate expiration timeout tick for each
+ * event timer.
+ *
+ * Before calling this function, the application allocates
+ * ``struct rte_event_timer`` objects from mempool or huge page backed
+ * application buffers of desired size. On successful allocation,
+ * application updates the `struct rte_event_timer`` attributes such as
+ * expiry event attributes, timeout ticks from now.
+ * This function submits the event timer arm requests to the event timer adapter
+ * and on expiry, the events will be injected to designated event queue.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Pointer to an array of objects of type *rte_event_timer* structure.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_evtims* parameter. If the return value is less
+ *   than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
+ *   expiry event's sched type doesn't match the capabilities of the
+ *   destination event queue.
+ *   - EAGAIN Specified timer adapter is not running
+ *   - EALREADY A timer was encountered that was already armed
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **evtims,
+			  uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_burst, -EINVAL);
+#endif
+
+	return adapter->arm_burst(adapter, evtims, nb_evtims);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Arm a burst of event timers with same expiration timeout tick.
+ *
+ * Provides the same functionality as ``rte_event_timer_arm_burst()``, except
+ * that application can use this API when all the event timers have the
+ * same timeout expiration tick. This specialized function can provide the
+ * additional hint to the adapter implementation and optimize if possible.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Points to an array of objects of type *rte_event_timer* structure.
+ * @param timeout_ticks
+ *   The number of ticks in which the timers should expire.
+ * @param nb_evtims
+ *   Number of event timers in the supplied array.
+ *
+ * @return
+ *   The number of successfully armed event timers. The return value can be less
+ *   than the value of the *nb_evtims* parameter. If the return value is less
+ *   than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter, expiry event queue ID is invalid, or an
+ *   expiry event's sched type doesn't match the capabilities of the
+ *   destination event queue.
+ *   - EAGAIN Specified event timer adapter is not running
+ *   - EALREADY A timer was encountered that was already armed
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_arm_tmo_tick_burst(
+			const struct rte_event_timer_adapter *adapter,
+			struct rte_event_timer **evtims,
+			const uint64_t timeout_ticks,
+			const uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_tmo_tick_burst, -EINVAL);
+#endif
+
+	return adapter->arm_tmo_tick_burst(adapter, evtims, timeout_ticks,
+					   nb_evtims);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Cancel a burst of event timers from being scheduled to the event device.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param evtims
+ *   Points to an array of objects of type *rte_event_timer* structure
+ * @param nb_evtims
+ *   Number of event timer instances in the supplied array.
+ *
+ * @return
+ *   The number of successfully canceled event timers. The return value can be
+ *   less than the value of the *nb_evtims* parameter. If the return value is
+ *   less than *nb_evtims*, the remaining event timers at the end of *evtims*
+ *   are not consumed, and the caller has to take care of them, and rte_errno
+ *   is set accordingly. Possible errno values include:
+ *   - EINVAL Invalid timer adapter identifier
+ *   - EAGAIN Specified timer adapter is not running
+ *   - EALREADY  A timer was encountered that was already canceled
+ */
+static inline uint16_t __rte_experimental
+rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			     struct rte_event_timer **evtims,
+			     uint16_t nb_evtims)
+{
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->cancel_burst, -EINVAL);
+#endif
+
+	return adapter->cancel_burst(adapter, evtims, nb_evtims);
+}
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index a20077c..a1f0749 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -969,8 +969,8 @@ rte_event_dev_close(uint8_t dev_id);
 /**< The event generated from ethdev subsystem */
 #define RTE_EVENT_TYPE_CRYPTODEV        0x1
 /**< The event generated from crypodev subsystem */
-#define RTE_EVENT_TYPE_TIMERDEV         0x2
-/**< The event generated from timerdev subsystem */
+#define RTE_EVENT_TYPE_TIMER		0x2
+/**< The event generated from event timer adapter */
 #define RTE_EVENT_TYPE_CPU              0x3
 /**< The event generated from cpu for pipelining.
  * Application may use *sub_event_type* to further classify the event
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 2/9] eventdev: convert to SPDX license tag in header
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 1/9] " Erik Gabriel Carrillo
@ 2018-04-04 21:51               ` Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 3/9] eventtimer: add common code Erik Gabriel Carrillo
                                 ` (7 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-04 21:51 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 lib/librte_eventdev/rte_eventdev.h | 37 +++++--------------------------------
 1 file changed, 5 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index a1f0749..86df4be 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -1,35 +1,8 @@
-/*
- *   BSD LICENSE
- *
- *   Copyright 2016 Cavium, Inc.
- *   Copyright 2016 Intel Corporation.
- *   Copyright 2016 NXP.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Cavium, Inc nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2016 Cavium, Inc.
+ * Copyright(c) 2016-2018 Intel Corporation.
+ * Copyright 2016 NXP
+ * All rights reserved.
  */
 
 #ifndef _RTE_EVENTDEV_H_
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 3/9] eventtimer: add common code
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 1/9] " Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
@ 2018-04-04 21:51               ` Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 4/9] mk: update library order in static build Erik Gabriel Carrillo
                                 ` (6 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-04 21:51 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev

This commit adds the logic that is shared by all event timer adapter
drivers; the common code handles instance allocation and some
initialization.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
---
 config/common_base                                |   1 +
 drivers/event/sw/sw_evdev.c                       |  18 +
 lib/librte_eventdev/Makefile                      |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c     | 387 ++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 114 +++++++
 lib/librte_eventdev/rte_eventdev.c                |  22 ++
 lib/librte_eventdev/rte_eventdev.h                |  20 ++
 lib/librte_eventdev/rte_eventdev_pmd.h            |  35 ++
 lib/librte_eventdev/rte_eventdev_version.map      |  20 +-
 9 files changed, 618 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h

diff --git a/config/common_base b/config/common_base
index 7abf7c6..9354c66 100644
--- a/config/common_base
+++ b/config/common_base
@@ -550,6 +550,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
 CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
 CONFIG_RTE_EVENT_MAX_DEVS=16
 CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32
 
 #
 # Compile PMD for skeleton event device
diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index 0e89f11..dcb6551 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -464,6 +464,22 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
 	return 0;
 }
 
+static int
+sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
+			  uint64_t flags,
+			  uint32_t *caps,
+			  const struct rte_event_timer_adapter_ops **ops)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(flags);
+	*caps = 0;
+
+	/* Use default SW ops */
+	*ops = NULL;
+
+	return 0;
+}
+
 static void
 sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
 {
@@ -791,6 +807,8 @@ sw_probe(struct rte_vdev_device *vdev)
 
 			.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
 
+			.timer_adapter_caps_get = sw_timer_adapter_caps_get,
+
 			.xstats_get = sw_xstats_get,
 			.xstats_get_names = sw_xstats_get_names,
 			.xstats_get_by_name = sw_xstats_get_by_name,
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 549b182..8b16e3f 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -20,6 +20,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
 SRCS-y += rte_eventdev.c
 SRCS-y += rte_event_ring.c
 SRCS-y += rte_event_eth_rx_adapter.c
+SRCS-y += rte_event_timer_adapter.c
 
 # export include files
 SYMLINK-y-include += rte_eventdev.h
@@ -29,6 +30,7 @@ SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
 SYMLINK-y-include += rte_event_timer_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter_pmd.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
new file mode 100644
index 0000000..75a14ac
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -0,0 +1,387 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#include <string.h>
+#include <inttypes.h>
+
+#include <rte_memzone.h>
+#include <rte_memory.h>
+#include <rte_dev.h>
+#include <rte_errno.h>
+
+#include "rte_eventdev.h"
+#include "rte_eventdev_pmd.h"
+#include "rte_event_timer_adapter.h"
+#include "rte_event_timer_adapter_pmd.h"
+
+#define DATA_MZ_NAME_MAX_LEN 64
+#define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
+
+static int evtim_logtype;
+
+static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
+
+#define EVTIM_LOG(level, logtype, ...) \
+	rte_log(RTE_LOG_ ## level, logtype, \
+		RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
+			"\n", __func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__,)))
+
+#define EVTIM_LOG_ERR(...) EVTIM_LOG(ERR, evtim_logtype, __VA_ARGS__)
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+#define EVTIM_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#else
+#define EVTIM_LOG_DBG(...) (void)0
+#endif
+
+static int
+default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		     void *conf_arg)
+{
+	struct rte_event_timer_adapter *adapter;
+	struct rte_eventdev *dev;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	int started;
+	uint8_t port_id;
+	uint8_t dev_id;
+	int ret;
+
+	RTE_SET_USED(event_dev_id);
+
+	adapter = &adapters[id];
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+	dev_id = dev->data->dev_id;
+	dev_conf = dev->data->dev_conf;
+
+	started = dev->data->dev_started;
+	if (started)
+		rte_event_dev_stop(dev_id);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports += 1;
+	ret = rte_event_dev_configure(dev_id, &dev_conf);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to configure event dev %u\n", dev_id);
+		if (started)
+			if (rte_event_dev_start(dev_id))
+				return -EIO;
+
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(dev_id, port_id, port_conf);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to setup event port %u on event dev %u\n",
+			      port_id, dev_id);
+		return ret;
+	}
+
+	*event_port_id = port_id;
+
+	if (started)
+		ret = rte_event_dev_start(dev_id);
+
+	return ret;
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf)
+{
+	return rte_event_timer_adapter_create_ext(conf, default_port_conf_cb,
+						  NULL);
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_create_ext(
+		const struct rte_event_timer_adapter_conf *conf,
+		rte_event_timer_adapter_port_conf_cb_t conf_cb,
+		void *conf_arg)
+{
+	uint16_t adapter_id;
+	struct rte_event_timer_adapter *adapter;
+	const struct rte_memzone *mz;
+	char mz_name[DATA_MZ_NAME_MAX_LEN];
+	int n, ret;
+	struct rte_eventdev *dev;
+
+	if (conf == NULL) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Check eventdev ID */
+	if (!rte_event_pmd_is_valid_dev(conf->event_dev_id)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	dev = &rte_eventdevs[conf->event_dev_id];
+
+	adapter_id = conf->timer_adapter_id;
+
+	/* Check that adapter_id is in range */
+	if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Check adapter ID not already allocated */
+	adapter = &adapters[adapter_id];
+	if (adapter->allocated) {
+		rte_errno = EEXIST;
+		return NULL;
+	}
+
+	/* Create shared data area. */
+	n = snprintf(mz_name, sizeof(mz_name), DATA_MZ_NAME_FORMAT, adapter_id);
+	if (n >= (int)sizeof(mz_name)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	mz = rte_memzone_reserve(mz_name,
+				 sizeof(struct rte_event_timer_adapter_data),
+				 conf->socket_id, 0);
+	if (mz == NULL)
+		/* rte_errno set by rte_memzone_reserve */
+		return NULL;
+
+	adapter->data = mz->addr;
+	memset(adapter->data, 0, sizeof(struct rte_event_timer_adapter_data));
+
+	adapter->data->mz = mz;
+	adapter->data->event_dev_id = conf->event_dev_id;
+	adapter->data->id = adapter_id;
+	adapter->data->socket_id = conf->socket_id;
+	adapter->data->conf = *conf;  /* copy conf structure */
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = ret;
+		goto free_memzone;
+	}
+
+	if (!(adapter->data->caps &
+	      RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+		FUNC_PTR_OR_NULL_RET_WITH_ERRNO(conf_cb, -EINVAL);
+		ret = conf_cb(adapter->data->id, adapter->data->event_dev_id,
+			      &adapter->data->event_port_id, conf_arg);
+		if (ret < 0) {
+			rte_errno = ret;
+			goto free_memzone;
+		}
+	}
+
+	/* Allow driver to do some setup */
+	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
+	ret = adapter->ops->init(adapter);
+	if (ret < 0) {
+		rte_errno = ret;
+		goto free_memzone;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+
+free_memzone:
+	rte_memzone_free(adapter->data->mz);
+	return NULL;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->ops->get_info)
+		/* let driver set values it knows */
+		adapter->ops->get_info(adapter, adapter_info);
+
+	/* Set common values */
+	adapter_info->conf = adapter->data->conf;
+	adapter_info->event_dev_port_id = adapter->data->event_port_id;
+	adapter_info->caps = adapter->data->caps;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->start, -EINVAL);
+
+	ret = adapter->ops->start(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 1;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stop, -EINVAL);
+
+	if (adapter->data->started == 0) {
+		EVTIM_LOG_ERR("event timer adapter %"PRIu8" already stopped",
+			      adapter->data->id);
+		return 0;
+	}
+
+	ret = adapter->ops->stop(adapter);
+	if (ret < 0)
+		return ret;
+
+	adapter->data->started = 0;
+
+	return 0;
+}
+
+struct rte_event_timer_adapter * __rte_experimental
+rte_event_timer_adapter_lookup(uint16_t adapter_id)
+{
+	char name[DATA_MZ_NAME_MAX_LEN];
+	const struct rte_memzone *mz;
+	struct rte_event_timer_adapter_data *data;
+	struct rte_event_timer_adapter *adapter;
+	int ret;
+	struct rte_eventdev *dev;
+
+	if (adapters[adapter_id].allocated)
+		return &adapters[adapter_id]; /* Adapter is already loaded */
+
+	snprintf(name, DATA_MZ_NAME_MAX_LEN, DATA_MZ_NAME_FORMAT, adapter_id);
+	mz = rte_memzone_lookup(name);
+	if (mz == NULL) {
+		rte_errno = ENOENT;
+		return NULL;
+	}
+
+	data = mz->addr;
+
+	adapter = &adapters[data->id];
+	adapter->data = data;
+
+	dev = &rte_eventdevs[adapter->data->event_dev_id];
+
+	/* Query eventdev PMD for timer adapter capabilities and ops */
+	ret = dev->dev_ops->timer_adapter_caps_get(dev,
+						   adapter->data->conf.flags,
+						   &adapter->data->caps,
+						   &adapter->ops);
+	if (ret < 0) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+
+	/* Set fast-path function pointers */
+	adapter->arm_burst = adapter->ops->arm_burst;
+	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
+	adapter->cancel_burst = adapter->ops->cancel_burst;
+
+	adapter->allocated = 1;
+
+	return adapter;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->uninit, -EINVAL);
+
+	if (adapter->data->started == 1) {
+		EVTIM_LOG_ERR("event timer adapter %"PRIu8" must be stopped "
+			      "before freeing", adapter->data->id);
+		return -EBUSY;
+	}
+
+	/* free impl priv data */
+	ret = adapter->ops->uninit(adapter);
+	if (ret < 0)
+		return ret;
+
+	/* free shared data area */
+	ret = rte_memzone_free(adapter->data->mz);
+	if (ret < 0)
+		return ret;
+
+	adapter->data = NULL;
+	adapter->allocated = 0;
+
+	return 0;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+	if (adapter->data->service_inited && service_id != NULL)
+		*service_id = adapter->data->service_id;
+
+	return adapter->data->service_inited ? 0 : -ESRCH;
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer_adapter_stats *stats)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_get, -EINVAL);
+	if (stats == NULL)
+		return -EINVAL;
+
+	return adapter->ops->stats_get(adapter, stats);
+}
+
+int __rte_experimental
+rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
+{
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_reset, -EINVAL);
+	return adapter->ops->stats_reset(adapter);
+}
+
+RTE_INIT(event_timer_adapter_init_log);
+static void
+event_timer_adapter_init_log(void)
+{
+	evtim_logtype = rte_log_register("lib.eventdev.adapter.timer");
+	if (evtim_logtype >= 0)
+		rte_log_set_level(evtim_logtype, RTE_LOG_NOTICE);
+}
diff --git a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
new file mode 100644
index 0000000..cf3509d
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_PMD_H__
+#define __RTE_EVENT_TIMER_ADAPTER_PMD_H__
+
+/**
+ * @file
+ * RTE Event Timer Adapter API (PMD Side)
+ *
+ * @note
+ * This file provides implementation helpers for internal use by PMDs.  They
+ * are not intended to be exposed to applications and are not subject to ABI
+ * versioning.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "rte_event_timer_adapter.h"
+
+/*
+ * Definitions of functions exported by an event timer adapter implementation
+ * through *rte_event_timer_adapter_ops* structure supplied in the
+ * *rte_event_timer_adapter* structure associated with an event timer adapter.
+ */
+
+typedef int (*rte_event_timer_adapter_init_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation setup */
+typedef int (*rte_event_timer_adapter_uninit_t)(
+		struct rte_event_timer_adapter *adapter);
+/**< @internal Event timer adapter implementation teardown */
+typedef int (*rte_event_timer_adapter_start_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Start running event timer adapter */
+typedef int (*rte_event_timer_adapter_stop_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Stop running event timer adapter */
+typedef void (*rte_event_timer_adapter_get_info_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info);
+/**< @internal Get contextual information for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_get_t)(
+		const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_stats *stats);
+/**< @internal Get statistics for event timer adapter */
+typedef int (*rte_event_timer_adapter_stats_reset_t)(
+		const struct rte_event_timer_adapter *adapter);
+/**< @internal Reset statistics for event timer adapter */
+
+/**
+ * @internal Structure containing the functions exported by an event timer
+ * adapter implementation.
+ */
+struct rte_event_timer_adapter_ops {
+	rte_event_timer_adapter_init_t		init;  /**< Set up adapter */
+	rte_event_timer_adapter_uninit_t	uninit;/**< Tear down adapter */
+	rte_event_timer_adapter_start_t		start; /**< Start adapter */
+	rte_event_timer_adapter_stop_t		stop;  /**< Stop adapter */
+	rte_event_timer_adapter_get_info_t	get_info;
+	/**< Get info from driver */
+	rte_event_timer_adapter_stats_get_t	stats_get;
+	/**< Get adapter statistics */
+	rte_event_timer_adapter_stats_reset_t	stats_reset;
+	/**< Reset adapter statistics */
+	rte_event_timer_arm_burst_t		arm_burst;
+	/**< Arm one or more event timers */
+	rte_event_timer_arm_tmo_tick_burst_t	arm_tmo_tick_burst;
+	/**< Arm event timers with same expiration time */
+	rte_event_timer_cancel_burst_t		cancel_burst;
+	/**< Cancel one or more event timers */
+};
+
+/**
+ * @internal Adapter data; structure to be placed in shared memory to be
+ * accessible by various processes in a multi-process configuration.
+ */
+struct rte_event_timer_adapter_data {
+	uint8_t id;
+	/**< Event timer adapter ID */
+	uint8_t event_dev_id;
+	/**< Event device ID */
+	uint32_t socket_id;
+	/**< Socket ID where memory is allocated */
+	uint8_t event_port_id;
+	/**< Optional: event port ID used when the inbuilt port is absent */
+	const struct rte_memzone *mz;
+	/**< Event timer adapter memzone pointer */
+	struct rte_event_timer_adapter_conf conf;
+	/**< Configuration used to configure the adapter. */
+	uint32_t caps;
+	/**< Adapter capabilities */
+	void *adapter_priv;
+	/**< Timer adapter private data*/
+	uint8_t service_inited;
+	/**< Service initialization state */
+	uint32_t service_id;
+	/**< Service ID*/
+
+	RTE_STD_C11
+	uint8_t started : 1;
+	/**< Flag to indicate adapter started. */
+} __rte_cache_aligned;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RTE_EVENT_TIMER_ADAPTER_PMD_H__ */
diff --git a/lib/librte_eventdev/rte_eventdev.c b/lib/librte_eventdev/rte_eventdev.c
index 2de8d9a..3f016f4 100644
--- a/lib/librte_eventdev/rte_eventdev.c
+++ b/lib/librte_eventdev/rte_eventdev.c
@@ -123,6 +123,28 @@ rte_event_eth_rx_adapter_caps_get(uint8_t dev_id, uint8_t eth_port_id,
 				: 0;
 }
 
+int __rte_experimental
+rte_event_timer_adapter_caps_get(uint8_t dev_id, uint32_t *caps)
+{
+	struct rte_eventdev *dev;
+	const struct rte_event_timer_adapter_ops *ops;
+
+	RTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+
+	dev = &rte_eventdevs[dev_id];
+
+	if (caps == NULL)
+		return -EINVAL;
+	*caps = 0;
+
+	return dev->dev_ops->timer_adapter_caps_get ?
+				(*dev->dev_ops->timer_adapter_caps_get)(dev,
+									0,
+									caps,
+									&ops)
+				: 0;
+}
+
 static inline int
 rte_event_dev_queue_config(struct rte_eventdev *dev, uint8_t nb_queues)
 {
diff --git a/lib/librte_eventdev/rte_eventdev.h b/lib/librte_eventdev/rte_eventdev.h
index 86df4be..6fcbe94 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -215,6 +215,7 @@ extern "C" {
 #include <rte_config.h>
 #include <rte_memory.h>
 #include <rte_errno.h>
+#include <rte_compat.h>
 
 struct rte_mbuf; /* we just use mbuf pointers; no need to include rte_mbuf.h */
 struct rte_event;
@@ -1115,6 +1116,25 @@ int
 rte_event_eth_rx_adapter_caps_get(uint8_t dev_id, uint8_t eth_port_id,
 				uint32_t *caps);
 
+#define RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT (1ULL << 0)
+/**< This flag is set when the timer mechanism is in HW. */
+
+/**
+ * Retrieve the event device's timer adapter capabilities.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ *
+ * @param[out] caps
+ *   A pointer to memory to be filled with event timer adapter capabilities.
+ *
+ * @return
+ *   - 0: Success, driver provided event timer adapter capabilities.
+ *   - <0: Error code returned by the driver function.
+ */
+int __rte_experimental
+rte_event_timer_adapter_caps_get(uint8_t dev_id, uint32_t *caps);
+
 struct rte_eventdev_driver;
 struct rte_eventdev_ops;
 struct rte_eventdev;
diff --git a/lib/librte_eventdev/rte_eventdev_pmd.h b/lib/librte_eventdev/rte_eventdev_pmd.h
index 3a8ddd7..2dcb528 100644
--- a/lib/librte_eventdev/rte_eventdev_pmd.h
+++ b/lib/librte_eventdev/rte_eventdev_pmd.h
@@ -26,6 +26,7 @@ extern "C" {
 #include <rte_malloc.h>
 
 #include "rte_eventdev.h"
+#include "rte_event_timer_adapter_pmd.h"
 
 /* Logging Macros */
 #define RTE_EDEV_LOG_ERR(...) \
@@ -449,6 +450,37 @@ typedef int (*eventdev_eth_rx_adapter_caps_get_t)
 struct rte_event_eth_rx_adapter_queue_conf *queue_conf;
 
 /**
+ * Retrieve the event device's timer adapter capabilities, as well as the ops
+ * structure that an event timer adapter should call through to enter the
+ * driver
+ *
+ * @param dev
+ *   Event device pointer
+ *
+ * @param flags
+ *   Flags that can be used to determine how to select an event timer
+ *   adapter ops structure
+ *
+ * @param[out] caps
+ *   A pointer to memory filled with Rx event adapter capabilities.
+ *
+ * @param[out] ops
+ *   A pointer to the ops pointer to set with the address of the desired ops
+ *   structure
+ *
+ * @return
+ *   - 0: Success, driver provides Rx event adapter capabilities for the
+ *	ethernet device.
+ *   - <0: Error code returned by the driver function.
+ *
+ */
+typedef int (*eventdev_timer_adapter_caps_get_t)(
+				const struct rte_eventdev *dev,
+				uint64_t flags,
+				uint32_t *caps,
+				const struct rte_event_timer_adapter_ops **ops);
+
+/**
  * Add ethernet Rx queues to event device. This callback is invoked if
  * the caps returned from rte_eventdev_eth_rx_adapter_caps_get(, eth_port_id)
  * has RTE_EVENT_ETH_RX_ADAPTER_CAP_INTERNAL_PORT set.
@@ -640,6 +672,9 @@ struct rte_eventdev_ops {
 	eventdev_eth_rx_adapter_stats_reset eth_rx_adapter_stats_reset;
 	/**< Reset ethernet Rx stats */
 
+	eventdev_timer_adapter_caps_get_t timer_adapter_caps_get;
+	/**< Get timer adapter capabilities */
+
 	eventdev_selftest dev_selftest;
 	/**< Start eventdev Selftest */
 
diff --git a/lib/librte_eventdev/rte_eventdev_version.map b/lib/librte_eventdev/rte_eventdev_version.map
index 4396536..3ee28f7 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -66,7 +66,6 @@ DPDK_17.11 {
 	rte_event_eth_rx_adapter_stats_get;
 	rte_event_eth_rx_adapter_stats_reset;
 	rte_event_eth_rx_adapter_stop;
-
 } DPDK_17.08;
 
 DPDK_18.02 {
@@ -80,3 +79,22 @@ DPDK_18.05 {
 
 	rte_event_dev_stop_flush_callback_register;
 } DPDK_18.02;
+
+EXPERIMENTAL {
+	global:
+
+	rte_event_timer_adapter_caps_get;
+	rte_event_timer_adapter_create;
+	rte_event_timer_adapter_create_ext;
+	rte_event_timer_adapter_free;
+	rte_event_timer_adapter_get_info;
+	rte_event_timer_adapter_lookup;
+	rte_event_timer_adapter_service_id_get;
+	rte_event_timer_adapter_start;
+	rte_event_timer_adapter_stats_get;
+	rte_event_timer_adapter_stats_reset;
+	rte_event_timer_adapter_stop;
+	rte_event_timer_arm_burst;
+	rte_event_timer_arm_tmo_tick_burst;
+	rte_event_timer_cancel_burst;
+} DPDK_18.05;
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 4/9] mk: update library order in static build
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
                                 ` (2 preceding siblings ...)
  2018-04-04 21:51               ` [PATCH v11 3/9] eventtimer: add common code Erik Gabriel Carrillo
@ 2018-04-04 21:51               ` Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
                                 ` (5 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-04 21:51 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev

The introduction of the event timer adapter library adds a dependency
on the rte_timer library from the rte_eventdev library.  Update the
order so that the timer library comes after the eventdev library in the
linker command when statically linking applications.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 mk/rte.app.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index a9b4b05..01d0b4e 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)        += -lrte_bitratestats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
 
-_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
 
 _LDLIBS-y += --whole-archive
@@ -98,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)       += -lrte_security
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)       += -lrte_eventdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV)         += -lrte_rawdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 5/9] eventtimer: add default software driver
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
                                 ` (3 preceding siblings ...)
  2018-04-04 21:51               ` [PATCH v11 4/9] mk: update library order in static build Erik Gabriel Carrillo
@ 2018-04-04 21:51               ` Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
                                 ` (4 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-04 21:51 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev

If an eventdev PMD does not wish to provide event timer adapter ops
definitions, the library will fall back to a default software
implementation whose entry points are added by this commit.

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
---
 lib/Makefile                                  |   2 +-
 lib/librte_eventdev/Makefile                  |   2 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 912 ++++++++++++++++++++++++++
 lib/librte_eventdev/rte_event_timer_adapter.h |  57 +-
 4 files changed, 969 insertions(+), 4 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a6..965be6c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -31,7 +31,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
 DEPDIRS-librte_security += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash
+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash librte_mempool librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_RAWDEV) += librte_rawdev
 DEPDIRS-librte_rawdev := librte_eal librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 8b16e3f..297df4a 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -14,7 +14,7 @@ LIBABIVER := 3
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool -lrte_timer
 
 # library source files
 SRCS-y += rte_eventdev.c
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c b/lib/librte_eventdev/rte_event_timer_adapter.c
index 75a14ac..6eba6b4 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -5,11 +5,20 @@
 
 #include <string.h>
 #include <inttypes.h>
+#include <stdbool.h>
+#include <sys/queue.h>
 
 #include <rte_memzone.h>
 #include <rte_memory.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_common.h>
+#include <rte_timer.h>
+#include <rte_service_component.h>
+#include <rte_cycles.h>
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -20,9 +29,13 @@
 #define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
 
 static int evtim_logtype;
+static int evtim_svc_logtype;
+static int evtim_buffer_logtype;
 
 static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 
+static const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+
 #define EVTIM_LOG(level, logtype, ...) \
 	rte_log(RTE_LOG_ ## level, logtype, \
 		RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
@@ -33,8 +46,14 @@ static struct rte_event_timer_adapter adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 #ifdef RTE_LIBRTE_EVENTDEV_DEBUG
 #define EVTIM_LOG_DBG(...) \
 	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#define EVTIM_BUF_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_buffer_logtype, __VA_ARGS__)
+#define EVTIM_SVC_LOG_DBG(...) \
+	EVTIM_LOG(DEBUG, evtim_svc_logtype, __VA_ARGS__)
 #else
 #define EVTIM_LOG_DBG(...) (void)0
+#define EVTIM_BUF_LOG_DBG(...) (void)0
+#define EVTIM_SVC_LOG_DBG(...) (void)0
 #endif
 
 static int
@@ -188,6 +207,12 @@ rte_event_timer_adapter_create_ext(
 		}
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Allow driver to do some setup */
 	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
 	ret = adapter->ops->init(adapter);
@@ -305,6 +330,12 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
 		return NULL;
 	}
 
+	/* If eventdev PMD did not provide ops, use default software
+	 * implementation.
+	 */
+	if (adapter->ops == NULL)
+		adapter->ops = &sw_event_adapter_timer_ops;
+
 	/* Set fast-path function pointers */
 	adapter->arm_burst = adapter->ops->arm_burst;
 	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
@@ -377,6 +408,878 @@ rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
 	return adapter->ops->stats_reset(adapter);
 }
 
+/*
+ * Software event timer adapter buffer helper functions
+ */
+
+#define NSECPERSEC 1E9
+
+/* Optimizations used to index into the buffer require that the buffer size
+ * be a power of 2.
+ */
+#define EVENT_BUFFER_SZ 4096
+#define EVENT_BUFFER_BATCHSZ 32
+#define EVENT_BUFFER_MASK (EVENT_BUFFER_SZ - 1)
+
+struct event_buffer {
+	uint16_t head;
+	uint16_t tail;
+	struct rte_event events[EVENT_BUFFER_SZ];
+} __rte_cache_aligned;
+
+static inline bool
+event_buffer_full(struct event_buffer *bufp)
+{
+	return (bufp->head - bufp->tail) == EVENT_BUFFER_SZ;
+}
+
+static inline bool
+event_buffer_batch_ready(struct event_buffer *bufp)
+{
+	return (bufp->head - bufp->tail) >= EVENT_BUFFER_BATCHSZ;
+}
+
+static void
+event_buffer_init(struct event_buffer *bufp)
+{
+	bufp->head = bufp->tail = 0;
+	memset(&bufp->events, 0, sizeof(struct rte_event) * EVENT_BUFFER_SZ);
+}
+
+static int
+event_buffer_add(struct event_buffer *bufp, struct rte_event *eventp)
+{
+	uint16_t head_idx;
+	struct rte_event *buf_eventp;
+
+	if (event_buffer_full(bufp))
+		return -1;
+
+	/* Instead of modulus, bitwise AND with mask to get head_idx. */
+	head_idx = bufp->head & EVENT_BUFFER_MASK;
+	buf_eventp = &bufp->events[head_idx];
+	rte_memcpy(buf_eventp, eventp, sizeof(struct rte_event));
+
+	/* Wrap automatically when overflow occurs. */
+	bufp->head++;
+
+	return 0;
+}
+
+static void
+event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,
+		   uint16_t *nb_events_flushed,
+		   uint16_t *nb_events_inv)
+{
+	uint16_t head_idx, tail_idx, n = 0;
+	struct rte_event *events = bufp->events;
+
+	/* Instead of modulus, bitwise AND with mask to get index. */
+	head_idx = bufp->head & EVENT_BUFFER_MASK;
+	tail_idx = bufp->tail & EVENT_BUFFER_MASK;
+
+	/* Determine the largest contigous run we can attempt to enqueue to the
+	 * event device.
+	 */
+	if (head_idx > tail_idx)
+		n = head_idx - tail_idx;
+	else if (head_idx < tail_idx)
+		n = EVENT_BUFFER_SZ - tail_idx;
+	else {
+		*nb_events_flushed = 0;
+		return;
+	}
+
+	*nb_events_inv = 0;
+	*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
+						     &events[tail_idx], n);
+	if (*nb_events_flushed != n && rte_errno == -EINVAL) {
+		EVTIM_LOG_ERR("failed to enqueue invalid event - dropping it");
+		(*nb_events_inv)++;
+	}
+
+	bufp->tail = bufp->tail + *nb_events_flushed + *nb_events_inv;
+}
+
+/*
+ * Software event timer adapter implementation
+ */
+
+struct rte_event_timer_adapter_sw_data {
+	/* List of messages for outstanding timers */
+	TAILQ_HEAD(, msg) msgs_tailq_head;
+	/* Lock to guard tailq and armed count */
+	rte_spinlock_t msgs_tailq_sl;
+	/* Identifier of service executing timer management logic. */
+	uint32_t service_id;
+	/* The cycle count at which the adapter should next tick */
+	uint64_t next_tick_cycles;
+	/* Incremented as the service moves through phases of an iteration */
+	volatile int service_phase;
+	/* The tick resolution used by adapter instance. May have been
+	 * adjusted from what user requested
+	 */
+	uint64_t timer_tick_ns;
+	/* Maximum timeout in nanoseconds allowed by adapter instance. */
+	uint64_t max_tmo_ns;
+	/* Ring containing messages to arm or cancel event timers */
+	struct rte_ring *msg_ring;
+	/* Mempool containing msg objects */
+	struct rte_mempool *msg_pool;
+	/* Buffered timer expiry events to be enqueued to an event device. */
+	struct event_buffer buffer;
+	/* Statistics */
+	struct rte_event_timer_adapter_stats stats;
+	/* The number of threads currently adding to the message ring */
+	rte_atomic16_t message_producer_count;
+};
+
+enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
+
+struct msg {
+	enum msg_type type;
+	struct rte_event_timer *evtim;
+	struct rte_timer tim;
+	TAILQ_ENTRY(msg) msgs;
+};
+
+static void
+sw_event_timer_cb(struct rte_timer *tim, void *arg)
+{
+	int ret;
+	uint16_t nb_evs_flushed = 0;
+	uint16_t nb_evs_invalid = 0;
+	uint64_t opaque;
+	struct rte_event_timer *evtim;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	evtim = arg;
+	opaque = evtim->impl_opaque[1];
+	adapter = (struct rte_event_timer_adapter *)(uintptr_t)opaque;
+	sw_data = adapter->data->adapter_priv;
+
+	ret = event_buffer_add(&sw_data->buffer, &evtim->ev);
+	if (ret < 0) {
+		/* If event buffer is full, put timer back in list with
+		 * immediate expiry value, so that we process it again on the
+		 * next iteration.
+		 */
+		rte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),
+				     sw_event_timer_cb, evtim);
+
+		sw_data->stats.evtim_retry_count++;
+		EVTIM_LOG_DBG("event buffer full, resetting rte_timer with "
+			      "immediate expiry value");
+	} else {
+		struct msg *m = container_of(tim, struct msg, tim);
+		TAILQ_REMOVE(&sw_data->msgs_tailq_head, m, msgs);
+		EVTIM_BUF_LOG_DBG("buffered an event timer expiry event");
+		evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+
+		/* Free the msg object containing the rte_timer now that
+		 * we've buffered its event successfully.
+		 */
+		rte_mempool_put(sw_data->msg_pool, m);
+
+		/* Bump the count when we successfully add an expiry event to
+		 * the buffer.
+		 */
+		sw_data->stats.evtim_exp_count++;
+	}
+
+	if (event_buffer_batch_ready(&sw_data->buffer)) {
+		event_buffer_flush(&sw_data->buffer,
+				   adapter->data->event_dev_id,
+				   adapter->data->event_port_id,
+				   &nb_evs_flushed,
+				   &nb_evs_invalid);
+
+		sw_data->stats.ev_enq_count += nb_evs_flushed;
+		sw_data->stats.ev_inv_count += nb_evs_invalid;
+	}
+}
+
+static __rte_always_inline uint64_t
+get_timeout_cycles(struct rte_event_timer *evtim,
+		   struct rte_event_timer_adapter *adapter)
+{
+	uint64_t timeout_ns;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	timeout_ns = evtim->timeout_ticks * sw_data->timer_tick_ns;
+	return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
+
+}
+
+/* This function returns true if one or more (adapter) ticks have occurred since
+ * the last time it was called.
+ */
+static inline bool
+adapter_did_tick(struct rte_event_timer_adapter *adapter)
+{
+	uint64_t cycles_per_adapter_tick, start_cycles;
+	uint64_t *next_tick_cyclesp;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	next_tick_cyclesp = &sw_data->next_tick_cycles;
+
+	cycles_per_adapter_tick = sw_data->timer_tick_ns *
+			(rte_get_timer_hz() / NSECPERSEC);
+
+	start_cycles = rte_get_timer_cycles();
+
+	/* Note: initially, *next_tick_cyclesp == 0, so the clause below will
+	 * execute, and set things going.
+	 */
+
+	if (start_cycles >= *next_tick_cyclesp) {
+		/* Snap the current cycle count to the preceding adapter tick
+		 * boundary.
+		 */
+		start_cycles -= start_cycles % cycles_per_adapter_tick;
+
+		*next_tick_cyclesp = start_cycles + cycles_per_adapter_tick;
+
+		return true;
+	}
+
+	return false;
+}
+
+/* Check that event timer timeout value is in range */
+static __rte_always_inline int
+check_timeout(struct rte_event_timer *evtim,
+	      const struct rte_event_timer_adapter *adapter)
+{
+	uint64_t tmo_nsec;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+	tmo_nsec = evtim->timeout_ticks * sw_data->timer_tick_ns;
+
+	if (tmo_nsec > sw_data->max_tmo_ns)
+		return -1;
+
+	if (tmo_nsec < sw_data->timer_tick_ns)
+		return -2;
+
+	return 0;
+}
+
+/* Check that event timer event queue sched type matches destination event queue
+ * sched type
+ */
+static __rte_always_inline int
+check_destination_event_queue(struct rte_event_timer *evtim,
+			      const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	uint32_t sched_type;
+
+	ret = rte_event_queue_attr_get(adapter->data->event_dev_id,
+				       evtim->ev.queue_id,
+				       RTE_EVENT_QUEUE_ATTR_SCHEDULE_TYPE,
+				       &sched_type);
+
+	if ((ret < 0 && ret != -EOVERFLOW) ||
+	    evtim->ev.sched_type != sched_type)
+		return -1;
+
+	return 0;
+}
+
+#define NB_OBJS 32
+static int
+sw_event_timer_adapter_service_func(void *arg)
+{
+	int ret, i, num_msgs;
+	uint64_t cycles, opaque;
+	uint16_t nb_evs_flushed = 0;
+	uint16_t nb_evs_invalid = 0;
+	struct rte_event_timer_adapter *adapter;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_timer *tim = NULL;
+	struct msg *msg, *msgs[NB_OBJS];
+
+	RTE_SET_USED(ret);
+
+	adapter = arg;
+	sw_data = adapter->data->adapter_priv;
+
+	sw_data->service_phase = 1;
+	rte_smp_wmb();
+
+	while (rte_atomic16_read(&sw_data->message_producer_count) > 0 ||
+	       !rte_ring_empty(sw_data->msg_ring)) {
+
+		num_msgs = rte_ring_dequeue_burst(sw_data->msg_ring,
+						  (void **)msgs, NB_OBJS, NULL);
+
+		for (i = 0; i < num_msgs; i++) {
+			msg = msgs[i];
+			evtim = msg->evtim;
+
+			switch (msg->type) {
+			case MSG_TYPE_ARM:
+				EVTIM_SVC_LOG_DBG("dequeued ARM message from "
+						  "ring");
+				tim = &msg->tim;
+				rte_timer_init(tim);
+				cycles = get_timeout_cycles(evtim,
+							    adapter);
+				ret = rte_timer_reset(tim, cycles, SINGLE,
+						      rte_lcore_id(),
+						      sw_event_timer_cb,
+						      evtim);
+				RTE_ASSERT(ret == 0);
+
+				evtim->impl_opaque[0] = (uintptr_t)tim;
+				evtim->impl_opaque[1] = (uintptr_t)adapter;
+
+				TAILQ_INSERT_TAIL(&sw_data->msgs_tailq_head,
+						  msg,
+						  msgs);
+				break;
+			case MSG_TYPE_CANCEL:
+				EVTIM_SVC_LOG_DBG("dequeued CANCEL message "
+						  "from ring");
+				opaque = evtim->impl_opaque[0];
+				tim = (struct rte_timer *)(uintptr_t)opaque;
+				RTE_ASSERT(tim != NULL);
+
+				ret = rte_timer_stop(tim);
+				RTE_ASSERT(ret == 0);
+
+				/* Free the msg object for the original arm
+				 * request.
+				 */
+				struct msg *m;
+				m = container_of(tim, struct msg, tim);
+				TAILQ_REMOVE(&sw_data->msgs_tailq_head, m,
+					     msgs);
+				rte_mempool_put(sw_data->msg_pool, m);
+
+				/* Free the msg object for the current msg */
+				rte_mempool_put(sw_data->msg_pool, msg);
+
+				evtim->impl_opaque[0] = 0;
+				evtim->impl_opaque[1] = 0;
+
+				break;
+			}
+		}
+	}
+
+	sw_data->service_phase = 2;
+	rte_smp_wmb();
+
+	if (adapter_did_tick(adapter)) {
+		rte_timer_manage();
+
+		event_buffer_flush(&sw_data->buffer,
+				   adapter->data->event_dev_id,
+				   adapter->data->event_port_id,
+				   &nb_evs_flushed, &nb_evs_invalid);
+
+		sw_data->stats.ev_enq_count += nb_evs_flushed;
+		sw_data->stats.ev_inv_count += nb_evs_invalid;
+		sw_data->stats.adapter_tick_count++;
+	}
+
+	sw_data->service_phase = 0;
+	rte_smp_wmb();
+
+	return 0;
+}
+
+/* The adapter initialization function rounds the mempool size up to the next
+ * power of 2, so we can take the difference between that value and what the
+ * user requested, and use the space for caches.  This avoids a scenario where a
+ * user can't arm the number of timers the adapter was configured with because
+ * mempool objects have been lost to caches.
+ *
+ * nb_actual should always be a power of 2, so we can iterate over the powers
+ * of 2 to see what the largest cache size we can use is.
+ */
+static int
+compute_msg_mempool_cache_size(uint64_t nb_requested, uint64_t nb_actual)
+{
+	int i;
+	int size;
+	int cache_size = 0;
+
+	for (i = 0; ; i++) {
+		size = 1 << i;
+
+		if (RTE_MAX_LCORE * size < (int)(nb_actual - nb_requested) &&
+		    size < RTE_MEMPOOL_CACHE_MAX_SIZE &&
+		    size <= nb_actual / 1.5)
+			cache_size = size;
+		else
+			break;
+	}
+
+	return cache_size;
+}
+
+#define SW_MIN_INTERVAL 1E5
+
+static int
+sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	uint64_t nb_timers;
+	unsigned int flags;
+	struct rte_service_spec service;
+	static bool timer_subsystem_inited; // static initialized to false
+
+	/* Allocate storage for SW implementation data */
+	char priv_data_name[RTE_RING_NAMESIZE];
+	snprintf(priv_data_name, RTE_RING_NAMESIZE, "sw_evtim_adap_priv_%"PRIu8,
+		 adapter->data->id);
+	adapter->data->adapter_priv = rte_zmalloc_socket(
+				priv_data_name,
+				sizeof(struct rte_event_timer_adapter_sw_data),
+				RTE_CACHE_LINE_SIZE,
+				adapter->data->socket_id);
+	if (adapter->data->adapter_priv == NULL) {
+		EVTIM_LOG_ERR("failed to allocate space for private data");
+		rte_errno = ENOMEM;
+		return -1;
+	}
+
+	if (adapter->data->conf.timer_tick_ns < SW_MIN_INTERVAL) {
+		EVTIM_LOG_ERR("failed to create adapter with requested tick "
+			      "interval");
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	sw_data = adapter->data->adapter_priv;
+
+	sw_data->timer_tick_ns = adapter->data->conf.timer_tick_ns;
+	sw_data->max_tmo_ns = adapter->data->conf.max_tmo_ns;
+
+	TAILQ_INIT(&sw_data->msgs_tailq_head);
+	rte_spinlock_init(&sw_data->msgs_tailq_sl);
+	rte_atomic16_init(&sw_data->message_producer_count);
+
+	/* Rings require power of 2, so round up to next such value */
+	nb_timers = rte_align64pow2(adapter->data->conf.nb_timers);
+
+	char msg_ring_name[RTE_RING_NAMESIZE];
+	snprintf(msg_ring_name, RTE_RING_NAMESIZE,
+		 "sw_evtim_adap_msg_ring_%"PRIu8, adapter->data->id);
+	flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+		RING_F_SP_ENQ | RING_F_SC_DEQ :
+		RING_F_SC_DEQ;
+	sw_data->msg_ring = rte_ring_create(msg_ring_name, nb_timers,
+					    adapter->data->socket_id, flags);
+	if (sw_data->msg_ring == NULL) {
+		EVTIM_LOG_ERR("failed to create message ring");
+		rte_errno = ENOMEM;
+		goto free_priv_data;
+	}
+
+	char pool_name[RTE_RING_NAMESIZE];
+	snprintf(pool_name, RTE_RING_NAMESIZE, "sw_evtim_adap_msg_pool_%"PRIu8,
+		 adapter->data->id);
+
+	/* Both the arming/canceling thread and the service thread will do puts
+	 * to the mempool, but if the SP_PUT flag is enabled, we can specify
+	 * single-consumer get for the mempool.
+	 */
+	flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+		MEMPOOL_F_SC_GET : 0;
+
+	/* The usable size of a ring is count - 1, so subtract one here to
+	 * make the counts agree.
+	 */
+	int pool_size = nb_timers - 1;
+	int cache_size = compute_msg_mempool_cache_size(
+				adapter->data->conf.nb_timers, nb_timers);
+	sw_data->msg_pool = rte_mempool_create(pool_name, pool_size,
+					       sizeof(struct msg), cache_size,
+					       0, NULL, NULL, NULL, NULL,
+					       adapter->data->socket_id, flags);
+	if (sw_data->msg_pool == NULL) {
+		EVTIM_LOG_ERR("failed to create message object mempool");
+		rte_errno = ENOMEM;
+		goto free_msg_ring;
+	}
+
+	event_buffer_init(&sw_data->buffer);
+
+	/* Register a service component to run adapter logic */
+	memset(&service, 0, sizeof(service));
+	snprintf(service.name, RTE_SERVICE_NAME_MAX,
+		 "sw_evimer_adap_svc_%"PRIu8, adapter->data->id);
+	service.socket_id = adapter->data->socket_id;
+	service.callback = sw_event_timer_adapter_service_func;
+	service.callback_userdata = adapter;
+	service.capabilities &= ~(RTE_SERVICE_CAP_MT_SAFE);
+	ret = rte_service_component_register(&service, &sw_data->service_id);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to register service %s with id %"PRIu32
+			      ": err = %d", service.name, sw_data->service_id,
+			      ret);
+
+		rte_errno = ENOSPC;
+		goto free_msg_pool;
+	}
+
+	EVTIM_LOG_DBG("registered service %s with id %"PRIu32, service.name,
+		      sw_data->service_id);
+
+	adapter->data->service_id = sw_data->service_id;
+	adapter->data->service_inited = 1;
+
+	if (!timer_subsystem_inited) {
+		rte_timer_subsystem_init();
+		timer_subsystem_inited = true;
+	}
+
+	return 0;
+
+free_msg_pool:
+	rte_mempool_free(sw_data->msg_pool);
+free_msg_ring:
+	rte_ring_free(sw_data->msg_ring);
+free_priv_data:
+	rte_free(sw_data);
+	return -1;
+}
+
+static int
+sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct msg *m1, *m2;
+	struct rte_event_timer_adapter_sw_data *sw_data =
+						adapter->data->adapter_priv;
+
+	rte_spinlock_lock(&sw_data->msgs_tailq_sl);
+
+	/* Cancel outstanding rte_timers and free msg objects */
+	m1 = TAILQ_FIRST(&sw_data->msgs_tailq_head);
+	while (m1 != NULL) {
+		EVTIM_LOG_DBG("freeing outstanding timer");
+		m2 = TAILQ_NEXT(m1, msgs);
+
+		rte_timer_stop_sync(&m1->tim);
+		rte_mempool_put(sw_data->msg_pool, m1);
+
+		m1 = m2;
+	}
+
+	rte_spinlock_unlock(&sw_data->msgs_tailq_sl);
+
+	ret = rte_service_component_unregister(sw_data->service_id);
+	if (ret < 0) {
+		EVTIM_LOG_ERR("failed to unregister service component");
+		return ret;
+	}
+
+	rte_ring_free(sw_data->msg_ring);
+	rte_mempool_free(sw_data->msg_pool);
+	rte_free(adapter->data->adapter_priv);
+
+	return 0;
+}
+
+static inline int32_t
+get_mapped_count_for_service(uint32_t service_id)
+{
+	int32_t core_count, i, mapped_count = 0;
+	uint32_t lcore_arr[RTE_MAX_LCORE];
+
+	core_count = rte_service_lcore_list(lcore_arr, RTE_MAX_LCORE);
+
+	for (i = 0; i < core_count; i++)
+		if (rte_service_map_lcore_get(service_id, lcore_arr[i]) == 1)
+			mapped_count++;
+
+	return mapped_count;
+}
+
+static int
+sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+	int mapped_count;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+
+	sw_data = adapter->data->adapter_priv;
+
+	/* Mapping the service to more than one service core can introduce
+	 * delays while one thread is waiting to acquire a lock, so only allow
+	 * one core to be mapped to the service.
+	 */
+	mapped_count = get_mapped_count_for_service(sw_data->service_id);
+
+	if (mapped_count == 1)
+		return rte_service_component_runstate_set(sw_data->service_id,
+							  1);
+
+	return mapped_count < 1 ? -ENOENT : -ENOTSUP;
+}
+
+static int
+sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data =
+						adapter->data->adapter_priv;
+
+	ret = rte_service_component_runstate_set(sw_data->service_id, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Wait for the service to complete its final iteration before
+	 * stopping.
+	 */
+	while (sw_data->service_phase != 0)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	return 0;
+}
+
+static void
+sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+		struct rte_event_timer_adapter_info *adapter_info)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+
+	adapter_info->min_resolution_ns = sw_data->timer_tick_ns;
+	adapter_info->max_tmo_ns = sw_data->max_tmo_ns;
+}
+
+static int
+sw_event_timer_adapter_stats_get(const struct rte_event_timer_adapter *adapter,
+				 struct rte_event_timer_adapter_stats *stats)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	*stats = sw_data->stats;
+	return 0;
+}
+
+static int
+sw_event_timer_adapter_stats_reset(
+				const struct rte_event_timer_adapter *adapter)
+{
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	sw_data = adapter->data->adapter_priv;
+	memset(&sw_data->stats, 0, sizeof(sw_data->stats));
+	return 0;
+}
+
+static __rte_always_inline uint16_t
+__sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			  struct rte_event_timer **evtims,
+			  uint16_t nb_evtims)
+{
+	uint16_t i;
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct msg *msgs[nb_evtims];
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	/* Check that the service is running. */
+	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
+		rte_errno = EINVAL;
+		return 0;
+	}
+#endif
+
+	sw_data = adapter->data->adapter_priv;
+
+	ret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (ret < 0) {
+		rte_errno = ENOSPC;
+		return 0;
+	}
+
+	/* Let the service know we're producing messages for it to process */
+	rte_atomic16_inc(&sw_data->message_producer_count);
+
+	/* If the service is managing timers, wait for it to finish */
+	while (sw_data->service_phase == 2)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	for (i = 0; i < nb_evtims; i++) {
+		/* Don't modify the event timer state in these cases */
+		if (evtims[i]->state == RTE_EVENT_TIMER_ARMED) {
+			rte_errno = EALREADY;
+			break;
+		} else if (!(evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
+		    evtims[i]->state == RTE_EVENT_TIMER_CANCELED)) {
+			rte_errno = EINVAL;
+			break;
+		}
+
+		ret = check_timeout(evtims[i], adapter);
+		if (ret == -1) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOLATE;
+			rte_errno = EINVAL;
+			break;
+		}
+		if (ret == -2) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR_TOOEARLY;
+			rte_errno = EINVAL;
+			break;
+		}
+
+		if (check_destination_event_queue(evtims[i], adapter) < 0) {
+			evtims[i]->state = RTE_EVENT_TIMER_ERROR;
+			rte_errno = EINVAL;
+			break;
+		}
+
+		/* Checks passed, set up a message to enqueue */
+		msgs[i]->type = MSG_TYPE_ARM;
+		msgs[i]->evtim = evtims[i];
+
+		/* Set the payload pointer if not set. */
+		if (evtims[i]->ev.event_ptr == NULL)
+			evtims[i]->ev.event_ptr = evtims[i];
+
+		/* msg objects that get enqueued successfully will be freed
+		 * either by a future cancel operation or by the timer
+		 * expiration callback.
+		 */
+		if (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {
+			rte_errno = ENOSPC;
+			break;
+		}
+
+		EVTIM_LOG_DBG("enqueued ARM message to ring");
+
+		evtims[i]->state = RTE_EVENT_TIMER_ARMED;
+	}
+
+	/* Let the service know we're done producing messages */
+	rte_atomic16_dec(&sw_data->message_producer_count);
+
+	if (i < nb_evtims)
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],
+				     nb_evtims - i);
+
+	return i;
+}
+
+static uint16_t
+sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+			 struct rte_event_timer **evtims,
+			 uint16_t nb_evtims)
+{
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
+}
+
+static uint16_t
+sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			    struct rte_event_timer **evtims,
+			    uint16_t nb_evtims)
+{
+	uint16_t i;
+	int ret;
+	struct rte_event_timer_adapter_sw_data *sw_data;
+	struct msg *msgs[nb_evtims];
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+	/* Check that the service is running. */
+	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
+		rte_errno = EINVAL;
+		return 0;
+	}
+#endif
+
+	sw_data = adapter->data->adapter_priv;
+
+	ret = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+	if (ret < 0) {
+		rte_errno = ENOSPC;
+		return 0;
+	}
+
+	/* Let the service know we're producing messages for it to process */
+	rte_atomic16_inc(&sw_data->message_producer_count);
+
+	/* If the service could be modifying event timer states, wait */
+	while (sw_data->service_phase == 2)
+		rte_pause();
+
+	rte_smp_rmb();
+
+	for (i = 0; i < nb_evtims; i++) {
+		/* Don't modify the event timer state in these cases */
+		if (evtims[i]->state == RTE_EVENT_TIMER_CANCELED) {
+			rte_errno = EALREADY;
+			break;
+		} else if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
+			rte_errno = EINVAL;
+			break;
+		}
+
+		msgs[i]->type = MSG_TYPE_CANCEL;
+		msgs[i]->evtim = evtims[i];
+
+		if (rte_ring_enqueue(sw_data->msg_ring, msgs[i]) < 0) {
+			rte_errno = ENOSPC;
+			break;
+		}
+
+		EVTIM_LOG_DBG("enqueued CANCEL message to ring");
+
+		evtims[i]->state = RTE_EVENT_TIMER_CANCELED;
+	}
+
+	/* Let the service know we're done producing messages */
+	rte_atomic16_dec(&sw_data->message_producer_count);
+
+	if (i < nb_evtims)
+		rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[i],
+				     nb_evtims - i);
+
+	return i;
+}
+
+static uint16_t
+sw_event_timer_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter,
+				  struct rte_event_timer **evtims,
+				  uint64_t timeout_ticks,
+				  uint16_t nb_evtims)
+{
+	int i;
+
+	for (i = 0; i < nb_evtims; i++)
+		evtims[i]->timeout_ticks = timeout_ticks;
+
+	return __sw_event_timer_arm_burst(adapter, evtims, nb_evtims);
+}
+
+static const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
+	.init = sw_event_timer_adapter_init,
+	.uninit = sw_event_timer_adapter_uninit,
+	.start = sw_event_timer_adapter_start,
+	.stop = sw_event_timer_adapter_stop,
+	.get_info = sw_event_timer_adapter_get_info,
+	.stats_get = sw_event_timer_adapter_stats_get,
+	.stats_reset = sw_event_timer_adapter_stats_reset,
+	.arm_burst = sw_event_timer_arm_burst,
+	.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
+	.cancel_burst = sw_event_timer_cancel_burst,
+};
+
 RTE_INIT(event_timer_adapter_init_log);
 static void
 event_timer_adapter_init_log(void)
@@ -384,4 +1287,13 @@ event_timer_adapter_init_log(void)
 	evtim_logtype = rte_log_register("lib.eventdev.adapter.timer");
 	if (evtim_logtype >= 0)
 		rte_log_set_level(evtim_logtype, RTE_LOG_NOTICE);
+
+	evtim_buffer_logtype = rte_log_register("lib.eventdev.adapter.timer."
+						"buffer");
+	if (evtim_buffer_logtype >= 0)
+		rte_log_set_level(evtim_buffer_logtype, RTE_LOG_NOTICE);
+
+	evtim_svc_logtype = rte_log_register("lib.eventdev.adapter.timer.svc");
+	if (evtim_svc_logtype >= 0)
+		rte_log_set_level(evtim_svc_logtype, RTE_LOG_NOTICE);
 }
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h b/lib/librte_eventdev/rte_event_timer_adapter.h
index 6a76791..38a314d 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -280,8 +280,6 @@ rte_event_timer_adapter_create_ext(
 struct rte_event_timer_adapter_info {
 	uint64_t min_resolution_ns;
 	/**< Minimum timer adapter resolution in ns */
-	uint64_t resolution_ns;
-	/**< Actual timer adapter resolution in ns */
 	uint64_t max_tmo_ns;
 	/**< Maximum timer timeout(expire) in ns */
 	struct rte_event_timer_adapter_conf conf;
@@ -339,6 +337,8 @@ rte_event_timer_adapter_get_info(
  *   - 0: Success, adapter started.
  *   - <0: Error code returned by the driver start function.
  *   - -EINVAL if adapter identifier invalid
+ *   - -ENOENT if software adapter but no service core mapped
+ *   - -ENOTSUP if software adapter and more than one service core mapped
  */
 int __rte_experimental
 rte_event_timer_adapter_start(
@@ -465,6 +465,59 @@ int __rte_experimental rte_event_timer_adapter_stats_reset(
 		struct rte_event_timer_adapter *adapter);
 
 /**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure, if the event dev doesn't use a rte_service
+ *   function, this function returns -ESRCH.
+ */
+int
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+				       uint32_t *service_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ * @param[out] stats
+ *   A pointer to a structure to fill with statistics.
+ *
+ * @return
+ *   - 0: Successfully retrieved.
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+				struct rte_event_timer_adapter_stats *stats);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset statistics for an event timer adapter instance.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter structure.
+ *
+ * @return
+ *   - 0: Successfully reset;
+ *   - <0: Failure; error code returned.
+ */
+int rte_event_timer_adapter_stats_reset(
+				struct rte_event_timer_adapter *adapter);
+
+/**
  * @warning
  * @b EXPERIMENTAL: this structure may change without prior notice
  *
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 6/9] eventtimer: add support for meson build system
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
                                 ` (4 preceding siblings ...)
  2018-04-04 21:51               ` [PATCH v11 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
@ 2018-04-04 21:51               ` Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
                                 ` (3 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-04 21:51 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
---
 config/rte_config.h             | 1 +
 lib/librte_eventdev/meson.build | 9 ++++++---
 lib/meson.build                 | 3 ++-
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/config/rte_config.h b/config/rte_config.h
index 72c0aa2..117c19f 100644
--- a/config/rte_config.h
+++ b/config/rte_config.h
@@ -55,6 +55,7 @@
 /* eventdev defines */
 #define RTE_EVENT_MAX_DEVS 16
 #define RTE_EVENT_MAX_QUEUES_PER_DEV 64
+#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 32
 
 /* ip_fragmentation defines */
 #define RTE_LIBRTE_IP_FRAG_MAX_FRAG 4
diff --git a/lib/librte_eventdev/meson.build b/lib/librte_eventdev/meson.build
index e1e22a5..232b870 100644
--- a/lib/librte_eventdev/meson.build
+++ b/lib/librte_eventdev/meson.build
@@ -5,11 +5,14 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_eventdev.c',
 		'rte_event_ring.c',
-		'rte_event_eth_rx_adapter.c')
+		'rte_event_eth_rx_adapter.c',
+		'rte_event_timer_adapter.c')
 headers = files('rte_eventdev.h',
 		'rte_eventdev_pmd.h',
 		'rte_eventdev_pmd_pci.h',
 		'rte_eventdev_pmd_vdev.h',
 		'rte_event_ring.h',
-		'rte_event_eth_rx_adapter.h')
-deps += ['ring', 'ethdev', 'hash']
+		'rte_event_eth_rx_adapter.h',
+		'rte_event_timer_adapter.h',
+		'rte_event_timer_adapter_pmd.h')
+deps += ['ring', 'ethdev', 'hash', 'mempool', 'timer']
diff --git a/lib/meson.build b/lib/meson.build
index ef61591..b1ad35f 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -13,13 +13,14 @@ libraries = [ 'compat', # just a header, used for versioning
 	'metrics', # bitrate/latency stats depends on this
 	'hash',    # efd depends on this
 	'kvargs',  # cryptodev depends on this
+	'timer',   # eventdev depends on this
 	'acl', 'bbdev', 'bitratestats', 'cfgfile',
 	'cmdline', 'cryptodev',
 	'distributor', 'efd', 'eventdev',
 	'gro', 'gso', 'ip_frag', 'jobstats',
 	'kni', 'latencystats', 'lpm', 'member',
 	'meter', 'power', 'pdump',
-	'reorder', 'sched', 'security', 'timer', 'vhost',
+	'reorder', 'sched', 'security', 'vhost',
 	# add pkt framework libs which use other libs from above
 	'port', 'table', 'pipeline',
 	# flow_classify lib depends on pkt framework table lib
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 7/9] test: add event timer adapter auto-test
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
                                 ` (5 preceding siblings ...)
  2018-04-04 21:51               ` [PATCH v11 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
@ 2018-04-04 21:51               ` Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
                                 ` (2 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-04 21:51 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
---
 test/test/Makefile                   |    1 +
 test/test/test_event_timer_adapter.c | 1830 ++++++++++++++++++++++++++++++++++
 2 files changed, 1831 insertions(+)
 create mode 100644 test/test/test_event_timer_adapter.c

diff --git a/test/test/Makefile b/test/test/Makefile
index a88cc38..c9c007c9 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -185,6 +185,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
 SRCS-y += test_eventdev.c
 SRCS-y += test_event_ring.c
 SRCS-y += test_event_eth_rx_adapter.c
+SRCS-y += test_event_timer_adapter.c
 endif
 
 ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y)
diff --git a/test/test/test_event_timer_adapter.c b/test/test/test_event_timer_adapter.c
new file mode 100644
index 0000000..93471db
--- /dev/null
+++ b/test/test/test_event_timer_adapter.c
@@ -0,0 +1,1830 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc
+ * Copyright(c) 2017-2018 Intel Corporation.
+ */
+
+#include <rte_atomic.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_debug.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_eventdev.h>
+#include <rte_event_timer_adapter.h>
+#include <rte_mempool.h>
+#include <rte_launch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_random.h>
+#include <rte_bus_vdev.h>
+#include <rte_service.h>
+#include <stdbool.h>
+
+#include "test.h"
+
+/* 4K timers corresponds to sw evdev max inflight events */
+#define MAX_TIMERS  (4 * 1024)
+#define BKT_TCK_NSEC
+
+#define NSECPERSEC 1E9
+#define BATCH_SIZE 16
+/* Both the app lcore and adapter ports are linked to this queue */
+#define TEST_QUEUE_ID 0
+/* Port the application dequeues from */
+#define TEST_PORT_ID 0
+#define TEST_ADAPTER_ID 0
+
+/* Handle log statements in same manner as test macros */
+#define LOG_DBG(...)	RTE_LOG(DEBUG, EAL, __VA_ARGS__)
+
+static int evdev;
+static struct rte_event_timer_adapter *timdev;
+static struct rte_mempool *eventdev_test_mempool;
+static struct rte_ring *timer_producer_ring;
+static uint64_t global_bkt_tck_ns;
+static volatile uint8_t arm_done;
+
+static bool using_services;
+static uint32_t test_lcore1;
+static uint32_t test_lcore2;
+static uint32_t test_lcore3;
+static uint32_t sw_evdev_slcore;
+static uint32_t sw_adptr_slcore;
+
+static inline void
+devconf_set_default_sane_values(struct rte_event_dev_config *dev_conf,
+		struct rte_event_dev_info *info)
+{
+	memset(dev_conf, 0, sizeof(struct rte_event_dev_config));
+	dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns;
+	dev_conf->nb_event_ports = 1;
+	dev_conf->nb_event_queues = 1;
+	dev_conf->nb_event_queue_flows = info->max_event_queue_flows;
+	dev_conf->nb_event_port_dequeue_depth =
+		info->max_event_port_dequeue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+		info->max_event_port_enqueue_depth;
+	dev_conf->nb_event_port_enqueue_depth =
+		info->max_event_port_enqueue_depth;
+	dev_conf->nb_events_limit =
+		info->max_num_events;
+}
+
+static inline int
+eventdev_setup(void)
+{
+	int ret;
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_dev_info info;
+	uint32_t service_id;
+
+	ret = rte_event_dev_info_get(evdev, &info);
+	TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info");
+	TEST_ASSERT(info.max_num_events >= (int32_t)MAX_TIMERS,
+			"ERROR max_num_events=%d < max_events=%d",
+			info.max_num_events, MAX_TIMERS);
+
+	devconf_set_default_sane_values(&dev_conf, &info);
+	ret = rte_event_dev_configure(evdev, &dev_conf);
+	TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev");
+
+	ret = rte_event_queue_setup(evdev, 0, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", 0);
+
+	/* Configure event port */
+	ret = rte_event_port_setup(evdev, 0, NULL);
+	TEST_ASSERT_SUCCESS(ret, "Failed to setup port=%d", 0);
+	ret = rte_event_port_link(evdev, 0, NULL, NULL, 0);
+	TEST_ASSERT(ret >= 0, "Failed to link all queues port=%d", 0);
+
+	/* If this is a software event device, map and start its service */
+	if (rte_event_dev_service_id_get(evdev, &service_id) == 0) {
+		TEST_ASSERT_SUCCESS(rte_service_lcore_add(sw_evdev_slcore),
+				"Failed to add service core");
+		TEST_ASSERT_SUCCESS(rte_service_lcore_start(
+				sw_evdev_slcore),
+				"Failed to start service core");
+		TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(
+				service_id, sw_evdev_slcore, 1),
+				"Failed to map evdev service");
+		TEST_ASSERT_SUCCESS(rte_service_runstate_set(
+				service_id, 1),
+				"Failed to start evdev service");
+	}
+
+	ret = rte_event_dev_start(evdev);
+	TEST_ASSERT_SUCCESS(ret, "Failed to start device");
+
+	return TEST_SUCCESS;
+}
+
+static int
+testsuite_setup(void)
+{
+	/* Some of the multithreaded tests require 3 other lcores to run */
+	unsigned int required_lcore_count = 4;
+	uint32_t service_id;
+
+	/* To make it easier to map services later if needed, just reset
+	 * service core state.
+	 */
+	(void) rte_service_lcore_reset_all();
+
+	if (!rte_event_dev_count()) {
+		/* If there is no hardware eventdev, or no software vdev was
+		 * specified on the command line, create an instance of
+		 * event_sw.
+		 */
+		LOG_DBG("Failed to find a valid event device... testing with"
+			" event_sw device\n");
+		TEST_ASSERT_SUCCESS(rte_vdev_init("event_sw0", NULL),
+					"Error creating eventdev");
+		evdev = rte_event_dev_get_dev_id("event_sw0");
+	}
+
+	if (rte_event_dev_service_id_get(evdev, &service_id) == 0) {
+		/* A software event device will use a software event timer
+		 * adapter as well. 2 more cores required to convert to
+		 * service cores.
+		 */
+		required_lcore_count += 2;
+		using_services = true;
+	}
+
+	if (rte_lcore_count() < required_lcore_count) {
+		printf("%d lcores needed to run tests", required_lcore_count);
+		return TEST_FAILED;
+	}
+
+	/* Assign lcores for various tasks */
+	test_lcore1 = rte_get_next_lcore(-1, 1, 0);
+	test_lcore2 = rte_get_next_lcore(test_lcore1, 1, 0);
+	test_lcore3 = rte_get_next_lcore(test_lcore2, 1, 0);
+	if (using_services) {
+		sw_evdev_slcore = rte_get_next_lcore(test_lcore3, 1, 0);
+		sw_adptr_slcore = rte_get_next_lcore(sw_evdev_slcore, 1, 0);
+	}
+
+	return eventdev_setup();
+}
+
+static void
+testsuite_teardown(void)
+{
+	rte_event_dev_stop(evdev);
+	rte_event_dev_close(evdev);
+}
+
+static int
+setup_adapter_service(struct rte_event_timer_adapter *adptr)
+{
+	uint32_t adapter_service_id;
+	int ret;
+
+	/* retrieve service ids */
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(adptr,
+			&adapter_service_id), "Failed to get event timer "
+			"adapter service id");
+	/* add a service core and start it */
+	ret = rte_service_lcore_add(sw_adptr_slcore);
+	TEST_ASSERT(ret == 0 || ret == -EALREADY,
+			"Failed to add service core");
+	ret = rte_service_lcore_start(sw_adptr_slcore);
+	TEST_ASSERT(ret == 0 || ret == -EALREADY,
+			"Failed to start service core");
+
+	/* map services to it */
+	TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(adapter_service_id,
+			sw_adptr_slcore, 1),
+			"Failed to map adapter service");
+
+	/* set services to running */
+	TEST_ASSERT_SUCCESS(rte_service_runstate_set(adapter_service_id, 1),
+			"Failed to start event timer adapter service");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+		  void *conf_arg)
+{
+	struct rte_event_dev_config dev_conf;
+	struct rte_event_dev_info info;
+	struct rte_event_port_conf *port_conf, def_port_conf = {0};
+	uint32_t started;
+	static int port_allocated;
+	static uint8_t port_id;
+	int ret;
+
+	if (port_allocated) {
+		*event_port_id = port_id;
+		return 0;
+	}
+
+	RTE_SET_USED(id);
+
+	ret = rte_event_dev_attr_get(event_dev_id, RTE_EVENT_DEV_ATTR_STARTED,
+				     &started);
+	if (ret < 0)
+		return ret;
+
+	if (started)
+		rte_event_dev_stop(event_dev_id);
+
+	ret = rte_event_dev_info_get(evdev, &info);
+	if (ret < 0)
+		return ret;
+
+	devconf_set_default_sane_values(&dev_conf, &info);
+
+	port_id = dev_conf.nb_event_ports;
+	dev_conf.nb_event_ports++;
+
+	ret = rte_event_dev_configure(event_dev_id, &dev_conf);
+	if (ret < 0) {
+		if (started)
+			rte_event_dev_start(event_dev_id);
+		return ret;
+	}
+
+	if (conf_arg != NULL)
+		port_conf = conf_arg;
+	else {
+		port_conf = &def_port_conf;
+		ret = rte_event_port_default_conf_get(event_dev_id, port_id,
+						      port_conf);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = rte_event_port_setup(event_dev_id, port_id, port_conf);
+	if (ret < 0)
+		return ret;
+
+	*event_port_id = port_id;
+
+	if (started)
+		rte_event_dev_start(event_dev_id);
+
+	/* Reuse this port number next time this is called */
+	port_allocated = 1;
+
+	return 0;
+}
+
+static int
+_timdev_setup(uint64_t max_tmo_ns, uint64_t bkt_tck_ns)
+{
+	struct rte_event_timer_adapter_conf config = {
+		.event_dev_id = evdev,
+		.timer_adapter_id = TEST_ADAPTER_ID,
+		.timer_tick_ns = bkt_tck_ns,
+		.max_tmo_ns = max_tmo_ns,
+		.nb_timers = MAX_TIMERS * 10,
+	};
+	uint32_t caps = 0;
+	const char *pool_name = "timdev_test_pool";
+
+	global_bkt_tck_ns = bkt_tck_ns;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_caps_get(evdev, &caps),
+				"failed to get adapter capabilities");
+	if (!(caps & RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
+		timdev = rte_event_timer_adapter_create_ext(&config,
+							    test_port_conf_cb,
+							    NULL);
+		setup_adapter_service(timdev);
+		using_services = true;
+	} else
+		timdev = rte_event_timer_adapter_create(&config);
+
+	TEST_ASSERT_NOT_NULL(timdev,
+			"failed to create event timer ring");
+
+	TEST_ASSERT_EQUAL(rte_event_timer_adapter_start(timdev), 0,
+			"failed to Start event timer adapter");
+
+	/* Create event timer mempool */
+	eventdev_test_mempool = rte_mempool_create(pool_name,
+			MAX_TIMERS * 2,
+			sizeof(struct rte_event_timer), /* element size*/
+			0, /* cache size*/
+			0, NULL, NULL, NULL, NULL,
+			rte_socket_id(), 0);
+	if (!eventdev_test_mempool) {
+		printf("ERROR creating mempool\n");
+		return TEST_FAILED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+timdev_setup_usec(void)
+{
+	return using_services ?
+		/* Max timeout is 10,000us and bucket interval is 100us */
+		_timdev_setup(1E7, 1E5) :
+		/* Max timeout is 100us and bucket interval is 1us */
+		_timdev_setup(1E5, 1E3);
+}
+
+static int
+timdev_setup_usec_multicore(void)
+{
+	return using_services ?
+		/* Max timeout is 10,000us and bucket interval is 100us */
+		_timdev_setup(1E7, 1E5) :
+		/* Max timeout is 100us and bucket interval is 1us */
+		_timdev_setup(1E5, 1E3);
+}
+
+static int
+timdev_setup_msec(void)
+{
+	/* Max timeout is 2 mins, and bucket interval is 100 ms */
+	return _timdev_setup(180 * NSECPERSEC, NSECPERSEC / 10);
+}
+
+static int
+timdev_setup_sec(void)
+{
+	/* Max timeout is 100sec and bucket interval is 1sec */
+	return _timdev_setup(1E11, 1E9);
+}
+
+static int
+timdev_setup_sec_multicore(void)
+{
+	/* Max timeout is 100sec and bucket interval is 1sec */
+	return _timdev_setup(1E11, 1E9);
+}
+
+static void
+timdev_teardown(void)
+{
+	rte_event_timer_adapter_stop(timdev);
+	rte_event_timer_adapter_free(timdev);
+
+	rte_mempool_free(eventdev_test_mempool);
+}
+
+static inline int
+test_timer_state(void)
+{
+	struct rte_event_timer *ev_tim;
+	struct rte_event ev;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&ev_tim);
+	*ev_tim = tim;
+	ev_tim->ev.event_ptr = ev_tim;
+	ev_tim->timeout_ticks = 120;
+
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 0,
+			"Armed timer exceeding max_timeout.");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ERROR_TOOLATE,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_ERROR_TOOLATE, ev_tim->state);
+
+	ev_tim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	ev_tim->timeout_ticks = 10;
+
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+			"Failed to arm timer with proper timeout.");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_ARMED, ev_tim->state);
+
+	if (!using_services)
+		rte_delay_us(20);
+	else
+		rte_delay_us(1000 + 200);
+	TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1, 0), 1,
+			"Armed timer failed to trigger.");
+
+	ev_tim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	ev_tim->timeout_ticks = 90;
+	TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+			"Failed to arm timer with proper timeout.");
+	TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(timdev, &ev_tim, 1),
+			1, "Failed to cancel armed timer");
+	TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_CANCELED,
+			"Improper timer state set expected %d returned %d",
+			RTE_EVENT_TIMER_CANCELED, ev_tim->state);
+
+	rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+_arm_timers(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers; i++) {
+
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+_wait_timer_triggers(uint64_t wait_sec, uint64_t arm_count,
+		uint64_t cancel_count)
+{
+	uint8_t valid_event;
+	uint64_t events = 0;
+	uint64_t wait_start, max_wait;
+	struct rte_event ev;
+
+	max_wait = rte_get_timer_hz() * wait_sec;
+	wait_start = rte_get_timer_cycles();
+	while (1) {
+		if (rte_get_timer_cycles() - wait_start > max_wait) {
+			if (events + cancel_count != arm_count)
+				TEST_ASSERT_SUCCESS(max_wait,
+					"Max time limit for timers exceeded.");
+			break;
+		}
+
+		valid_event = rte_event_dequeue_burst(evdev, 0, &ev, 1, 0);
+		if (!valid_event)
+			continue;
+
+		rte_mempool_put(eventdev_test_mempool, ev.event_ptr);
+		events++;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm(void)
+{
+	TEST_ASSERT_SUCCESS(_arm_timers(20, MAX_TIMERS),
+			"Failed to arm timers");
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS, 0),
+			"Timer triggered count doesn't match arm count");
+	return TEST_SUCCESS;
+}
+
+static int
+_arm_wrapper(void *arg)
+{
+	RTE_SET_USED(arg);
+
+	TEST_ASSERT_SUCCESS(_arm_timers(20, MAX_TIMERS),
+			"Failed to arm timers");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_multicore(void)
+{
+
+	uint32_t lcore_1 = rte_get_next_lcore(-1, 1, 0);
+	uint32_t lcore_2 = rte_get_next_lcore(lcore_1, 1, 0);
+
+	rte_eal_remote_launch(_arm_wrapper, NULL, lcore_1);
+	rte_eal_remote_launch(_arm_wrapper, NULL, lcore_2);
+
+	rte_eal_mp_wait_lcore();
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS * 2, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+#define MAX_BURST 16
+static inline int
+_arm_timers_burst(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	int j;
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers / MAX_BURST; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get_bulk(
+				eventdev_test_mempool,
+				(void **)ev_tim, MAX_BURST),
+				"mempool alloc failed");
+
+		for (j = 0; j < MAX_BURST; j++) {
+			*ev_tim[j] = tim;
+			ev_tim[j]->ev.event_ptr = ev_tim[j];
+		}
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_tmo_tick_burst(timdev,
+				ev_tim, tim.timeout_ticks, MAX_BURST),
+				MAX_BURST, "Failed to arm timer %d", rte_errno);
+	}
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_burst(void)
+{
+	TEST_ASSERT_SUCCESS(_arm_timers_burst(20, MAX_TIMERS),
+			"Failed to arm timers");
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_arm_wrapper_burst(void *arg)
+{
+	RTE_SET_USED(arg);
+
+	TEST_ASSERT_SUCCESS(_arm_timers_burst(20, MAX_TIMERS),
+			"Failed to arm timers");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_arm_burst_multicore(void)
+{
+	rte_eal_remote_launch(_arm_wrapper_burst, NULL, test_lcore1);
+	rte_eal_remote_launch(_arm_wrapper_burst, NULL, test_lcore2);
+
+	rte_eal_mp_wait_lcore();
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(10, MAX_TIMERS * 2, 0),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel(void)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 20,
+	};
+
+	for (i = 0; i < MAX_TIMERS; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		rte_delay_us(100 + (i % 5000));
+
+		TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(timdev,
+					&ev_tim, 1), 1,
+				"Failed to cancel event timer %d", rte_errno);
+		rte_mempool_put(eventdev_test_mempool, ev_tim);
+	}
+
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+				MAX_TIMERS),
+		"Timer triggered count doesn't match arm, cancel count");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer(uint64_t timeout_tcks, uint64_t timers)
+{
+	uint64_t i;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+
+	for (i = 0; i < timers; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+				  "Failed to arm event timer");
+
+		while (rte_ring_enqueue(timer_producer_ring, ev_tim) != 0)
+			;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer_burst(uint64_t timeout_tcks, uint64_t timers)
+{
+
+	uint64_t i;
+	int j, ret;
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = timeout_tcks,
+	};
+	int arm_count = 0;
+
+	for (i = 0; i < timers / MAX_BURST; i++) {
+		TEST_ASSERT_SUCCESS(rte_mempool_get_bulk(
+				eventdev_test_mempool,
+				(void **)ev_tim, MAX_BURST),
+				"mempool alloc failed");
+
+		for (j = 0; j < MAX_BURST; j++) {
+			*ev_tim[j] = tim;
+			ev_tim[j]->ev.event_ptr = ev_tim[j];
+		}
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_tmo_tick_burst(timdev,
+				ev_tim, tim.timeout_ticks, MAX_BURST),
+				MAX_BURST, "Failed to arm timer %d", rte_errno);
+
+		for (j = 0; j < MAX_BURST; j++)
+			TEST_ASSERT_EQUAL(ev_tim[j]->state,
+					  RTE_EVENT_TIMER_ARMED,
+					  "Event timer not armed, state = %d",
+					  ev_tim[j]->state);
+
+		ret = rte_ring_enqueue_bulk(timer_producer_ring,
+				(void **)ev_tim, MAX_BURST, NULL);
+		TEST_ASSERT_EQUAL(ret, MAX_BURST,
+				"Failed to enqueue event timers to ring");
+		arm_count += ret;
+	}
+
+	TEST_ASSERT_EQUAL(arm_count, MAX_TIMERS,
+			  "Failed to arm expected number of event timers");
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_producer_wrapper(void *args)
+{
+	RTE_SET_USED(args);
+
+	return _cancel_producer(20, MAX_TIMERS);
+}
+
+static int
+_cancel_producer_burst_wrapper(void *args)
+{
+	RTE_SET_USED(args);
+
+	return _cancel_producer_burst(100, MAX_TIMERS);
+}
+
+static int
+_cancel_thread(void *args)
+{
+	RTE_SET_USED(args);
+	struct rte_event_timer *ev_tim = NULL;
+	uint64_t cancel_count = 0;
+	uint16_t ret;
+
+	while (!arm_done || rte_ring_count(timer_producer_ring) > 0) {
+		if (rte_ring_dequeue(timer_producer_ring, (void **)&ev_tim))
+			continue;
+
+		ret = rte_event_timer_cancel_burst(timdev, &ev_tim, 1);
+		TEST_ASSERT_EQUAL(ret, 1, "Failed to cancel timer");
+		rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+		cancel_count++;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+_cancel_burst_thread(void *args)
+{
+	RTE_SET_USED(args);
+
+	int ret, i, n;
+	struct rte_event_timer *ev_tim[MAX_BURST];
+	uint64_t cancel_count = 0;
+	uint64_t dequeue_count = 0;
+
+	while (!arm_done || rte_ring_count(timer_producer_ring) > 0) {
+		n = rte_ring_dequeue_burst(timer_producer_ring,
+				(void **)ev_tim, MAX_BURST, NULL);
+		if (!n)
+			continue;
+
+		dequeue_count += n;
+
+		for (i = 0; i < n; i++)
+			TEST_ASSERT_EQUAL(ev_tim[i]->state,
+					  RTE_EVENT_TIMER_ARMED,
+					  "Event timer not armed, state = %d",
+					  ev_tim[i]->state);
+
+		ret = rte_event_timer_cancel_burst(timdev, ev_tim, n);
+		TEST_ASSERT_EQUAL(n, ret, "Failed to cancel complete burst of "
+				  "event timers");
+		rte_mempool_put_bulk(eventdev_test_mempool, (void **)ev_tim,
+				ret);
+
+		cancel_count += ret;
+	}
+
+	TEST_ASSERT_EQUAL(cancel_count, MAX_TIMERS,
+			  "Failed to cancel expected number of timers: "
+			  "expected = %d, cancel_count = %"PRIu64", "
+			  "dequeue_count = %"PRIu64"\n", MAX_TIMERS,
+			  cancel_count, dequeue_count);
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_multicore(void)
+{
+	arm_done = 0;
+	timer_producer_ring = rte_ring_create("timer_cancel_queue",
+			MAX_TIMERS * 2, rte_socket_id(), 0);
+	TEST_ASSERT_NOT_NULL(timer_producer_ring,
+			"Unable to reserve memory for ring");
+
+	rte_eal_remote_launch(_cancel_thread, NULL, test_lcore3);
+	rte_eal_remote_launch(_cancel_producer_wrapper, NULL, test_lcore1);
+	rte_eal_remote_launch(_cancel_producer_wrapper, NULL, test_lcore2);
+
+	rte_eal_wait_lcore(test_lcore1);
+	rte_eal_wait_lcore(test_lcore2);
+	arm_done = 1;
+	rte_eal_wait_lcore(test_lcore3);
+	rte_ring_free(timer_producer_ring);
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS * 2,
+			MAX_TIMERS * 2),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_burst_multicore(void)
+{
+	arm_done = 0;
+	timer_producer_ring = rte_ring_create("timer_cancel_queue",
+			MAX_TIMERS * 2, rte_socket_id(), 0);
+	TEST_ASSERT_NOT_NULL(timer_producer_ring,
+			"Unable to reserve memory for ring");
+
+	rte_eal_remote_launch(_cancel_burst_thread, NULL, test_lcore2);
+	rte_eal_remote_launch(_cancel_producer_burst_wrapper, NULL,
+			test_lcore1);
+
+	rte_eal_wait_lcore(test_lcore1);
+	arm_done = 1;
+	rte_eal_wait_lcore(test_lcore2);
+	rte_ring_free(timer_producer_ring);
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+			MAX_TIMERS),
+			"Timer triggered count doesn't match arm count");
+
+	return TEST_SUCCESS;
+}
+
+static inline int
+test_timer_cancel_random(void)
+{
+	uint64_t i;
+	uint64_t events_canceled = 0;
+	struct rte_event_timer *ev_tim;
+	const struct rte_event_timer tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = 0,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 20,
+	};
+
+	for (i = 0; i < MAX_TIMERS; i++) {
+
+		TEST_ASSERT_SUCCESS(rte_mempool_get(eventdev_test_mempool,
+					(void **)&ev_tim),
+				"mempool alloc failed");
+		*ev_tim = tim;
+		ev_tim->ev.event_ptr = ev_tim;
+
+		TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim,
+					1), 1, "Failed to arm timer %d",
+				rte_errno);
+
+		if (rte_rand() & 1) {
+			rte_delay_us(100 + (i % 5000));
+			TEST_ASSERT_EQUAL(rte_event_timer_cancel_burst(
+						timdev,
+						&ev_tim, 1), 1,
+				"Failed to cancel event timer %d", rte_errno);
+			rte_mempool_put(eventdev_test_mempool, ev_tim);
+			events_canceled++;
+		}
+	}
+
+	TEST_ASSERT_SUCCESS(_wait_timer_triggers(30, MAX_TIMERS,
+				events_canceled),
+		       "Timer triggered count doesn't match arm, cancel count");
+
+	return TEST_SUCCESS;
+}
+
+/* Check that the adapter can be created correctly */
+static int
+adapter_create(void)
+{
+	int adapter_id = 0;
+	struct rte_event_timer_adapter *adapter, *adapter2;
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev + 1,  // invalid event dev id
+		.timer_adapter_id = adapter_id,
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = MAX_TIMERS,
+		.flags = 0,
+	};
+	uint32_t caps = 0;
+
+	/* Test invalid conf */
+	adapter = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapter, "Created adapter with invalid "
+			"event device id");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Incorrect errno value for "
+			"invalid event device id");
+
+	/* Test valid conf */
+	conf.event_dev_id = evdev;
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_caps_get(evdev, &caps),
+			"failed to get adapter capabilities");
+	if (!(caps & RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT))
+		adapter = rte_event_timer_adapter_create_ext(&conf,
+				test_port_conf_cb,
+				NULL);
+	else
+		adapter = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NOT_NULL(adapter, "Failed to create adapter with valid "
+			"configuration");
+
+	/* Test existing id */
+	adapter2 = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapter2, "Created adapter with in-use id");
+	TEST_ASSERT(rte_errno == EEXIST, "Incorrect errno value for existing "
+			"id");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapter),
+			"Failed to free adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+
+/* Test that adapter can be freed correctly. */
+static int
+adapter_free(void)
+{
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stop(timdev),
+			"Failed to stop adapter");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(timdev),
+			"Failed to free valid adapter");
+
+	/* Test free of already freed adapter */
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_free(timdev),
+			"Freed adapter that was already freed");
+
+	/* Test free of null adapter */
+	timdev = NULL;
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_free(timdev),
+			"Freed null adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter info can be retrieved and is correct. */
+static int
+adapter_get_info(void)
+{
+	struct rte_event_timer_adapter_info info;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_get_info(timdev, &info),
+			"Failed to get adapter info");
+
+	if (using_services)
+		TEST_ASSERT_EQUAL(info.event_dev_port_id, 1,
+				"Expected port id = 1, got port id = %d",
+				info.event_dev_port_id);
+
+	return TEST_SUCCESS;
+}
+
+/* Test adapter lookup via adapter ID. */
+static int
+adapter_lookup(void)
+{
+	struct rte_event_timer_adapter *adapter;
+
+	adapter = rte_event_timer_adapter_lookup(TEST_ADAPTER_ID);
+	TEST_ASSERT_NOT_NULL(adapter, "Failed to lookup adapter");
+
+	return TEST_SUCCESS;
+}
+
+static int
+adapter_start(void)
+{
+	TEST_ASSERT_SUCCESS(_timdev_setup(180 * NSECPERSEC,
+			NSECPERSEC / 10),
+			"Failed to start adapter");
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_start(timdev),
+			"Failed to repeatedly start adapter");
+
+	return TEST_SUCCESS;
+}
+
+/* Test that adapter stops correctly. */
+static int
+adapter_stop(void)
+{
+	struct rte_event_timer_adapter *l_adapter = NULL;
+
+	/* Test adapter stop */
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stop(timdev),
+			"Failed to stop event adapter");
+
+	TEST_ASSERT_FAIL(rte_event_timer_adapter_stop(l_adapter),
+			"Erroneously stopped null event adapter");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(timdev),
+			"Failed to free adapter");
+
+	rte_mempool_free(eventdev_test_mempool);
+
+	return TEST_SUCCESS;
+}
+
+/* Test increment and reset of ev_enq_count stat */
+static int
+stat_inc_reset_ev_enq(void)
+{
+	int ret, i, n;
+	int num_evtims = MAX_TIMERS;
+	struct rte_event_timer *evtims[num_evtims];
+	struct rte_event evs[BATCH_SIZE];
+	struct rte_event_timer_adapter_stats stats;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
+				   num_evtims);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
+			  ret);
+
+	for (i = 0; i < num_evtims; i++) {
+		*evtims[i] = init_tim;
+		evtims[i]->ev.event_ptr = evtims[i];
+	}
+
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0, "Stats not clear at "
+			  "startup");
+
+	/* Test with the max value for the adapter */
+	ret = rte_event_timer_arm_burst(timdev, evtims, num_evtims);
+	TEST_ASSERT_EQUAL(ret, num_evtims,
+			  "Failed to arm all event timers: attempted = %d, "
+			  "succeeded = %d, rte_errno = %s",
+			  num_evtims, ret, rte_strerror(rte_errno));
+
+	rte_delay_ms(1000);
+
+#define MAX_TRIES num_evtims
+	int sum = 0;
+	int tries = 0;
+	bool done = false;
+	while (!done) {
+		sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
+					       RTE_DIM(evs), 10);
+		if (sum >= num_evtims || ++tries >= MAX_TRIES)
+			done = true;
+
+		rte_delay_ms(10);
+	}
+
+	TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
+			  "got %d", num_evtims, sum);
+
+	TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");
+
+	rte_delay_ms(100);
+
+	/* Make sure the eventdev is still empty */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
+				      10);
+
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
+			  "events from event device");
+
+	/* Check stats again */
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, num_evtims,
+			  "Expected enqueue stat = %d; got %d", num_evtims,
+			  (int)stats.ev_enq_count);
+
+	/* Reset and check again */
+	ret = rte_event_timer_adapter_stats_reset(timdev);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to reset stats");
+
+	ret = rte_event_timer_adapter_stats_get(timdev, &stats);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get stats");
+	TEST_ASSERT_EQUAL((int)stats.ev_enq_count, 0,
+			  "Expected enqueue stat = %d; got %d", 0,
+			  (int)stats.ev_enq_count);
+
+	rte_mempool_put_bulk(eventdev_test_mempool, (void **)evtims,
+			     num_evtims);
+
+	return TEST_SUCCESS;
+}
+
+/* Test various cases in arming timers */
+static int
+event_timer_arm(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+
+	/* Test single timer arm succeeds */
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event timer "
+			  "in incorrect state");
+
+	/* Test arm of armed timer fails */
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "expected return value from "
+			  "rte_event_timer_arm_burst: 0, got: %d", ret);
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after arming already armed timer");
+
+	/* Let timer expire */
+	rte_delay_ms(1000);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* This test checks that repeated references to the same event timer in the
+ * arm request work as expected; only the first one through should succeed.
+ */
+static int
+event_timer_arm_double(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+
+	struct rte_event_timer *evtim_arr[] = {evtim, evtim};
+	ret = rte_event_timer_arm_burst(adapter, evtim_arr, RTE_DIM(evtim_arr));
+	TEST_ASSERT_EQUAL(ret, 1, "Unexpected return value from "
+			  "rte_event_timer_arm_burst");
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after double-arm");
+
+	/* Let timer expire */
+	rte_delay_ms(600);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number of expiry events - "
+			  "expected: 1, actual: %d", n);
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Test the timer expiry event is generated at the expected time.  */
+static int
+event_timer_arm_expiry(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event_timer *evtim2 = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up an event timer */
+	*evtim = init_tim;
+	evtim->timeout_ticks = 30,	// expire in 3 secs
+	evtim->ev.event_ptr = evtim;
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED, "Event "
+			  "timer in incorrect state");
+
+	rte_delay_ms(2999);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event");
+
+	/* Delay 100 ms to account for the adapter tick window - should let us
+	 * dequeue one event
+	 */
+	rte_delay_ms(100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Dequeued incorrect number (%d) of timer "
+			  "expiry events", n);
+	TEST_ASSERT_EQUAL(evs[0].event_type, RTE_EVENT_TYPE_TIMER,
+			  "Dequeued unexpected type of event");
+
+	/* Check that we recover the original event timer and then free it */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+	rte_mempool_put(eventdev_test_mempool, evtim2);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that rearming a timer works as expected. */
+static int
+event_timer_arm_rearm(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event_timer *evtim2 = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type = RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->timeout_ticks = 1;  // expire in 0.1 sec
+	evtim->ev.event_ptr = evtim;
+
+	/* Arm it */
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+
+	/* Add 100ms to account for the adapter tick window */
+	rte_delay_ms(100 + 100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	/* Recover the timer through the event that was dequeued. */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+
+	/* Need to reset state in case implementation can't do it */
+	evtim2->state = RTE_EVENT_TIMER_NOT_ARMED;
+
+	/* Rearm it */
+	ret = rte_event_timer_arm_burst(timdev, &evtim2, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+
+	/* Add 100ms to account for the adapter tick window */
+	rte_delay_ms(100 + 100);
+
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 1, "Failed to dequeue expected number of expiry "
+			  "events from event device");
+
+	/* Free it */
+	evtim2 = evs[0].event_ptr;
+	TEST_ASSERT_EQUAL(evtim, evtim2,
+			  "Failed to recover pointer to original event timer");
+	rte_mempool_put(eventdev_test_mempool, evtim2);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that the adapter handles the max specified number of timers as
+ * expected.
+ */
+static int
+event_timer_arm_max(void)
+{
+	int ret, i, n;
+	int num_evtims = MAX_TIMERS;
+	struct rte_event_timer *evtims[num_evtims];
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	ret = rte_mempool_get_bulk(eventdev_test_mempool, (void **)evtims,
+				   num_evtims);
+	TEST_ASSERT_EQUAL(ret, 0, "Failed to get array of timer objs: ret = %d",
+			  ret);
+
+	for (i = 0; i < num_evtims; i++) {
+		*evtims[i] = init_tim;
+		evtims[i]->ev.event_ptr = evtims[i];
+	}
+
+	/* Test with the max value for the adapter */
+	ret = rte_event_timer_arm_burst(timdev, evtims, num_evtims);
+	TEST_ASSERT_EQUAL(ret, num_evtims,
+			  "Failed to arm all event timers: attempted = %d, "
+			  "succeeded = %d, rte_errno = %s",
+			  num_evtims, ret, rte_strerror(rte_errno));
+
+	rte_delay_ms(1000);
+
+#define MAX_TRIES num_evtims
+	int sum = 0;
+	int tries = 0;
+	bool done = false;
+	while (!done) {
+		sum += rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs,
+					       RTE_DIM(evs), 10);
+		if (sum >= num_evtims || ++tries >= MAX_TRIES)
+			done = true;
+
+		rte_delay_ms(10);
+	}
+
+	TEST_ASSERT_EQUAL(sum, num_evtims, "Expected %d timer expiry events, "
+			  "got %d", num_evtims, sum);
+
+	TEST_ASSERT(tries < MAX_TRIES, "Exceeded max tries");
+
+	rte_delay_ms(100);
+
+	/* Make sure the eventdev is still empty */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs),
+				    10);
+
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected number of timer expiry "
+			  "events from event device");
+
+	rte_mempool_put_bulk(eventdev_test_mempool, (void **)evtims,
+			     num_evtims);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that creating an event timer with incorrect event sched type fails. */
+static int
+event_timer_arm_invalid_sched_type(void)
+{
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	if (!using_services)
+		return -ENOTSUP;
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->ev.sched_type = RTE_SCHED_TYPE_PARALLEL; // bad sched type
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "sched type, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid queue");
+
+	rte_mempool_put(eventdev_test_mempool, &evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that creating an event timer with a timeout value that is too small or
+ * too big fails.
+ */
+static int
+event_timer_arm_invalid_timeout(void)
+{
+	int ret;
+	struct rte_event_timer *evtim = NULL;
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 0;  // timeout too small
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "timeout, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid timeout");
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOEARLY,
+			  "Unexpected event timer state");
+
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 1801;  // timeout too big
+
+	ret = rte_event_timer_arm_burst(timdev, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Expected to fail timer arm with invalid "
+			  "timeout, but didn't");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after"
+			  " arm fail with invalid timeout");
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ERROR_TOOLATE,
+			  "Unexpected event timer state");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+static int
+event_timer_cancel(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Check that cancelling an uninited timer fails */
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling "
+			  "uninited timer");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after "
+			  "cancelling uninited timer");
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	/* Check that cancelling an inited but unarmed timer fails */
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 0, "Succeeded unexpectedly in canceling "
+			  "unarmed timer");
+	TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Unexpected rte_errno value after "
+			  "cancelling unarmed timer");
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED,
+			  "evtim in incorrect state");
+
+	/* Delay 1 sec */
+	rte_delay_ms(1000);
+
+	ret = rte_event_timer_cancel_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to cancel event_timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_CANCELED,
+			  "evtim in incorrect state");
+
+	rte_delay_ms(3000);
+
+	/* Make sure that no expiry event was generated */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+static int
+event_timer_cancel_double(void)
+{
+	uint16_t n;
+	int ret;
+	struct rte_event_timer_adapter *adapter = timdev;
+	struct rte_event_timer *evtim = NULL;
+	struct rte_event evs[BATCH_SIZE];
+	const struct rte_event_timer init_tim = {
+		.ev.op = RTE_EVENT_OP_NEW,
+		.ev.queue_id = TEST_QUEUE_ID,
+		.ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+		.ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+		.ev.event_type =  RTE_EVENT_TYPE_TIMER,
+		.state = RTE_EVENT_TIMER_NOT_ARMED,
+		.timeout_ticks = 5,	// expire in .5 sec
+	};
+
+	rte_mempool_get(eventdev_test_mempool, (void **)&evtim);
+	if (evtim == NULL) {
+		/* Failed to get an event timer object */
+		return TEST_FAILED;
+	}
+
+	/* Set up a timer */
+	*evtim = init_tim;
+	evtim->ev.event_ptr = evtim;
+	evtim->timeout_ticks = 30;  // expire in 3 sec
+
+	ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+	TEST_ASSERT_EQUAL(ret, 1, "Failed to arm event timer: %s\n",
+			  rte_strerror(rte_errno));
+	TEST_ASSERT_EQUAL(evtim->state, RTE_EVENT_TIMER_ARMED,
+			  "timer in unexpected state");
+
+	/* Now, test that referencing the same timer twice in the same call
+	 * fails
+	 */
+	struct rte_event_timer *evtim_arr[] = {evtim, evtim};
+	ret = rte_event_timer_cancel_burst(adapter, evtim_arr,
+					   RTE_DIM(evtim_arr));
+
+	/* Two requests to cancel same timer, only one should succeed */
+	TEST_ASSERT_EQUAL(ret, 1, "Succeeded unexpectedly in canceling timer "
+			  "twice");
+
+	TEST_ASSERT_EQUAL(rte_errno, EALREADY, "Unexpected rte_errno value "
+			  "after double-cancel: rte_errno = %d", rte_errno);
+
+	rte_delay_ms(3000);
+
+	/* Still make sure that no expiry event was generated */
+	n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+	TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event\n");
+
+	rte_mempool_put(eventdev_test_mempool, evtim);
+
+	return TEST_SUCCESS;
+}
+
+/* Check that event timer adapter tick resolution works as expected by testing
+ * the number of adapter ticks that occur within a particular time interval.
+ */
+static int
+adapter_tick_resolution(void)
+{
+	struct rte_event_timer_adapter_stats stats;
+	uint64_t adapter_tick_count;
+
+	/* Only run this test in the software driver case */
+	if (!using_services)
+		return -ENOTSUP;
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_reset(timdev),
+				"Failed to reset stats");
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(timdev,
+			&stats), "Failed to get adapter stats");
+	TEST_ASSERT_EQUAL(stats.adapter_tick_count, 0, "Adapter tick count "
+			"not zeroed out");
+
+	/* Delay 1 second; should let at least 10 ticks occur with the default
+	 * adapter configuration used by this test.
+	 */
+	rte_delay_ms(1000);
+
+	TEST_ASSERT_SUCCESS(rte_event_timer_adapter_stats_get(timdev,
+			&stats), "Failed to get adapter stats");
+
+	adapter_tick_count = stats.adapter_tick_count;
+	TEST_ASSERT(adapter_tick_count >= 10 && adapter_tick_count <= 12,
+			"Expected 10-12 adapter ticks, got %"PRIu64"\n",
+			adapter_tick_count);
+
+	return TEST_SUCCESS;
+}
+
+static int
+adapter_create_max(void)
+{
+	int i;
+	uint32_t svc_start_count, svc_end_count;
+	struct rte_event_timer_adapter *adapters[
+					RTE_EVENT_TIMER_ADAPTER_NUM_MAX + 1];
+
+	struct rte_event_timer_adapter_conf conf = {
+		.event_dev_id = evdev,
+		// timer_adapter_id set in loop
+		.clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+		.timer_tick_ns = NSECPERSEC / 10,
+		.max_tmo_ns = 180 * NSECPERSEC,
+		.nb_timers = MAX_TIMERS,
+		.flags = 0,
+	};
+
+	if (!using_services)
+		return -ENOTSUP;
+
+	svc_start_count = rte_service_get_count();
+
+	/* This test expects that there are sufficient service IDs available
+	 * to be allocated. I.e., RTE_EVENT_TIMER_ADAPTER_NUM_MAX may need to
+	 * be less than RTE_SERVICE_NUM_MAX if anything else uses a service
+	 * (the SW event device, for example).
+	 */
+	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) {
+		conf.timer_adapter_id = i;
+		adapters[i] = rte_event_timer_adapter_create_ext(&conf,
+				test_port_conf_cb, NULL);
+		TEST_ASSERT_NOT_NULL(adapters[i], "Failed to create adapter "
+				"%d", i);
+	}
+
+	conf.timer_adapter_id = i;
+	adapters[i] = rte_event_timer_adapter_create(&conf);
+	TEST_ASSERT_NULL(adapters[i], "Created too many adapters");
+
+	/* Check that at least RTE_EVENT_TIMER_ADAPTER_NUM_MAX services
+	 * have been created
+	 */
+	svc_end_count = rte_service_get_count();
+	TEST_ASSERT_EQUAL(svc_end_count - svc_start_count,
+			RTE_EVENT_TIMER_ADAPTER_NUM_MAX,
+			"Failed to create expected number of services");
+
+	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++)
+		TEST_ASSERT_SUCCESS(rte_event_timer_adapter_free(adapters[i]),
+				"Failed to free adapter %d", i);
+
+	/* Check that service count is back to where it was at start */
+	svc_end_count = rte_service_get_count();
+	TEST_ASSERT_EQUAL(svc_start_count, svc_end_count, "Failed to release "
+			  "correct number of services");
+
+	return TEST_SUCCESS;
+}
+
+static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
+	.suite_name = "event timer functional test suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_state),
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_arm),
+		TEST_CASE_ST(timdev_setup_usec, timdev_teardown,
+				test_timer_arm_burst),
+		TEST_CASE_ST(timdev_setup_sec, timdev_teardown,
+				test_timer_cancel),
+		TEST_CASE_ST(timdev_setup_sec, timdev_teardown,
+				test_timer_cancel_random),
+		TEST_CASE_ST(timdev_setup_usec_multicore, timdev_teardown,
+				test_timer_arm_multicore),
+		TEST_CASE_ST(timdev_setup_usec_multicore, timdev_teardown,
+				test_timer_arm_burst_multicore),
+		TEST_CASE_ST(timdev_setup_sec_multicore, timdev_teardown,
+				test_timer_cancel_multicore),
+		TEST_CASE_ST(timdev_setup_sec_multicore, timdev_teardown,
+				test_timer_cancel_burst_multicore),
+		TEST_CASE(adapter_create),
+		TEST_CASE_ST(timdev_setup_msec, NULL, adapter_free),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_get_info),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_lookup),
+		TEST_CASE_ST(NULL, timdev_teardown,
+				adapter_start),
+		TEST_CASE_ST(timdev_setup_msec, NULL,
+				adapter_stop),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				stat_inc_reset_ev_enq),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm_double),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+			     event_timer_arm_expiry),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_rearm),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_max),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_invalid_sched_type),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_arm_invalid_timeout),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_cancel),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				event_timer_cancel_double),
+		TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+				adapter_tick_resolution),
+		TEST_CASE(adapter_create_max),
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+static int
+test_event_timer_adapter_func(void)
+{
+	return unit_test_suite_runner(&event_timer_adptr_functional_testsuite);
+}
+
+REGISTER_TEST_COMMAND(event_timer_adapter_test, test_event_timer_adapter_func);
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 8/9] doc: add event timer adapter section to programmer's guide
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
                                 ` (6 preceding siblings ...)
  2018-04-04 21:51               ` [PATCH v11 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
@ 2018-04-04 21:51               ` Erik Gabriel Carrillo
  2018-04-04 21:51               ` [PATCH v11 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
  2018-04-05  3:31               ` [PATCH v11 0/9] eventtimer: introduce event timer adapter Jerin Jacob
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-04 21:51 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <pbhagavatula@caviumnetworks.com>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 doc/guides/prog_guide/event_timer_adapter.rst | 296 ++++++++++++++++++++++++++
 doc/guides/prog_guide/index.rst               |   1 +
 2 files changed, 297 insertions(+)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst

diff --git a/doc/guides/prog_guide/event_timer_adapter.rst b/doc/guides/prog_guide/event_timer_adapter.rst
new file mode 100644
index 0000000..7e5fe18
--- /dev/null
+++ b/doc/guides/prog_guide/event_timer_adapter.rst
@@ -0,0 +1,296 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright(c) 2017 Intel Corporation. All rights reserved.
+
+Event Timer Adapter Library
+=================================
+
+The DPDK
+`Event Device library <http://dpdk.org/doc/guides/prog_guide/eventdev.html>`_
+introduces an event driven programming model which presents applications with
+an alternative to the polling model traditionally used in DPDK
+applications. Event devices can be coupled with arbitrary components to provide
+new event sources by using **event adapters**. The Event Timer Adapter is one
+such adapter; it bridges event devices and timer mechanisms.
+
+The Event Timer Adapter library extends the event driven model
+by introducing a :ref:`new type of event <timer_expiry_event>` that represents
+a timer expiration, and providing an API with which adapters can be created or
+destroyed, and :ref:`event timers <event_timer>` can be armed and canceled.
+
+The Event Timer Adapter library is designed to interface with hardware or
+software implementations of the timer mechanism; it will query an eventdev PMD
+to determine which implementation should be used.  The default software
+implementation manages timers using the DPDK
+`Timer library <http://dpdk.org/doc/guides/prog_guide/timer_lib.html>`_.
+
+Examples of using the API are presented in the `API Overview`_ and
+`Processing Timer Expiry Events`_ sections.  Code samples are abstracted and
+are based on the example of handling a TCP retransmission.
+
+.. _event_timer:
+
+Event Timer struct
+------------------
+Event timers are timers that enqueue a timer expiration event to an event
+device upon timer expiration.
+
+The Event Timer Adapter API represents each event timer with a generic struct,
+which contains an event and user metadata.  The ``rte_event_timer`` struct is
+defined in ``lib/librte_event/librte_event_timer_adapter.h``.
+
+.. _timer_expiry_event:
+
+Timer Expiry Event
+~~~~~~~~~~~~~~~~~~
+
+The event contained by an event timer is enqueued in the event device when the
+timer expires, and the event device uses the attributes below when scheduling
+it:
+
+* ``event_queue_id`` - Application should set this to specify an event queue to
+  which the timer expiry event should be enqueued
+* ``event_priority`` - Application can set this to indicate the priority of the
+  timer expiry event in the event queue relative to other events
+* ``sched_type`` - Application can set this to specify the scheduling type of
+  the timer expiry event
+* ``flow_id`` - Application can set this to indicate which flow this timer
+  expiry event corresponds to
+* ``op`` - Will be set to ``RTE_EVENT_OP_NEW`` by the event timer adapter
+* ``event_type`` - Will be set to ``RTE_EVENT_TYPE_TIMER`` by the event timer
+  adapter
+
+Timeout Ticks
+~~~~~~~~~~~~~
+
+The number of ticks from now in which the timer will expire. The ticks value
+has a resolution (``timer_tick_ns``) that is specified in the event timer
+adapter configuration.
+
+State
+~~~~~
+
+Before arming an event timer, the application should initialize its state to
+RTE_EVENT_TIMER_NOT_ARMED. The event timer's state will be updated when a
+request to arm or cancel it takes effect.
+
+If the application wishes to rearm the timer after it has expired, it should
+reset the state back to RTE_EVENT_TIMER_NOT_ARMED before doing so.
+
+User Metadata
+~~~~~~~~~~~~~
+
+Memory to store user specific metadata.  The event timer adapter implementation
+will not modify this area.
+
+API Overview
+----------------
+
+This section will introduce the reader to the event timer adapter API, showing
+how to create and configure an event timer adapter and use it to manage event
+timers.
+
+From a high level, the setup steps are:
+
+* rte_event_timer_adapter_create()
+* rte_event_timer_adapter_start()
+
+And to start and stop timers:
+
+* rte_event_timer_arm_burst()
+* rte_event_timer_cancel_burst()
+
+Create and Configure an Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To create an event timer adapter instance, initialize an
+``rte_event_timer_adapter_conf`` struct with the desired values, and pass it
+to ``rte_event_timer_adapter_create()``.
+
+.. code-block:: c
+
+	#define NSECPERSEC 1E9 // No of ns in 1 sec
+	const struct rte_event_timer_adapter_conf adapter_config = {
+                .event_dev_id = event_dev_id,
+                .timer_adapter_id = 0,
+                .clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+                .timer_tick_ns = NSECPERSEC / 10, // 100 milliseconds
+                .max_tmo_nsec = 180 * NSECPERSEC // 2 minutes
+                .nb_timers = 40000,
+                .timer_adapter_flags = 0,
+	};
+
+	struct rte_event_timer_adapter *adapter = NULL;
+	adapter = rte_event_timer_adapter_create(&adapter_config);
+
+	if (adapter == NULL) { ... };
+
+Before creating an instance of a timer adapter, the application should create
+and configure an event device along with its event ports. Based on the event
+device capability, it might require creating an additional event port to be
+used by the timer adapter.  If required, the
+``rte_event_timer_adapter_create()`` function will use a default method to
+configure an event port;  it will examine the current event device
+configuration, determine the next available port identifier number, and create
+a new event port with a default port configuration.
+
+If the application desires to have finer control of event port allocation
+and setup, it can use the ``rte_event_timer_adapter_create_ext()`` function.
+This function is passed a callback function that will be invoked if the
+adapter needs to create an event port, giving the application the opportunity
+to control how it is done.
+
+Retrieve Event Timer Adapter Contextual Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The event timer adapter implementation may have constraints on tick resolution
+or maximum timer expiry timeout based on the given event timer adapter or
+system.  In this case, the implementation may adjust the tick resolution or
+maximum timeout to the best possible configuration.
+
+Upon successful event timer adapter creation, the application can get the
+configured resolution and max timeout with
+``rte_event_timer_adapter_get_info()``. This function will return an
+``rte_event_timer_adapter_info`` struct, which contains the following members:
+
+* ``min_resolution_ns`` - Minimum timer adapter tick resolution in ns.
+* ``max_tmo_ns`` - Maximum timer timeout(expiry) in ns.
+* ``adapter_conf`` - Configured event timer adapter attributes
+
+Configuring the Service Component
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the adapter uses a service component, the application is required to map
+the service to a service core before starting the adapter:
+
+.. code-block:: c
+
+        uint32_t service_id;
+
+        if (rte_event_timer_adapter_service_id_get(adapter, &service_id) == 0)
+                rte_service_map_lcore_set(service_id, EVTIM_CORE_ID);
+
+An event timer adapter uses a service component if the event device PMD
+indicates that the adapter should use a software implementation.
+
+Starting the Adapter Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The application should call ``rte_event_timer_adapter_start()`` to start
+running the event timer adapter. This function calls the start entry points
+defined by eventdev PMDs for hardware implementations or puts a service
+component into the running state in the software implementation.
+
+Arming Event Timers
+~~~~~~~~~~~~~~~~~~~~~
+
+Once an event timer adapter has been started, an application can begin to
+manage event timers with it.
+
+The application should allocate ``struct rte_event_timer`` objects from a
+mempool or huge-page backed application buffers of required size. Upon
+successful allocation, the application should initialize the event timer, and
+then set any of the necessary event attributes described in the
+`Timer Expiry Event`_ section. In the following example, assume ``conn``
+represents a TCP connection and that ``event_timer_pool`` is a mempool that
+was created previously:
+
+.. code-block:: c
+
+	rte_mempool_get(event_timer_pool, (void **)&conn->evtim);
+	if (conn->evtim == NULL) { ... }
+
+	/* Set up the event timer. */
+	conn->evtim->ev.op = RTE_EVENT_OP_NEW;
+	conn->evtim->ev.queue_id = event_queue_id;
+        conn->evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+        conn->evtim->ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL;
+        conn->evtim->ev.event_type = RTE_EVENT_TYPE_TIMER;
+	conn->evtim->ev.event_ptr = conn;
+	conn->evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+	conn->evtim->timeout_ticks = 30; //3 sec Per RFC1122(TCP returns)
+
+Note that it is necessary to initialize the event timer state to
+RTE_EVENT_TIMER_NOT_ARMED.  Also note that we have saved a pointer to the
+``conn`` object in the timer's event payload. This will allow us to locate
+the connection object again once we dequeue the timer expiry event from the
+event device later.  As a convenience, the application may specify no value for
+ev.event_ptr, and the adapter will by default set it to point at the event
+timer itself.
+
+Now we can arm the event timer with ``rte_event_timer_arm_burst()``:
+
+.. code-block:: c
+
+	ret = rte_event_timer_arm_burst(adapter, &conn->evtim, 1);
+	if (ret != 1) { ... }
+
+Once an event timer expires, the application may free it or rearm it as
+necessary.  If the application will rearm the timer, the state should be reset
+to RTE_EVENT_TIMER_NOT_ARMED by the application before rearming it.
+
+Multiple Event Timers with Same Expiry Value
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the special case that there is a set of event timers that should all expire
+at the same time, the application may call
+``rte_event_timer_arm_tmo_tick_burst()``, which allows the implementation to
+optimize the operation if possible.
+
+Canceling Event Timers
+~~~~~~~~~~~~~~~~~~~~~~~
+
+An event timer that has been armed as described in `Arming Event Timers`_ can
+be canceled by calling ``rte_event_timer_cancel_burst()``:
+
+.. code-block:: c
+
+	/* Ack for the previous tcp data packet has been received;
+	 * cancel the retransmission timer
+         */
+	rte_event_timer_cancel_burst(adapter, &conn->timer, 1);
+
+Processing Timer Expiry Events
+------------------------------
+
+Once an event timer has successfully enqueued a timer expiry event in the event
+device, the application will subsequently dequeue it from the event device.
+The application can use the event payload to retrieve a pointer to the object
+associated with the event timer. It can then re-arm the event timer or free the
+event timer object as desired:
+
+.. code-block:: c
+
+	void
+	event_processing_loop(...)
+	{
+		while (...) {
+			/* Receive events from the configured event port. */
+			rte_event_dequeue_burst(event_dev_id, event_port, &ev, 1, 0);
+			...
+			switch(ev.event_type) {
+				...
+				case RTE_EVENT_TYPE_TIMER:
+					process_timer_event(ev);
+					...
+					break;
+			}
+		}
+	}
+
+	uint8_t
+	process_timer_event(...)
+	{
+		/* A retransmission timeout for the connection has been received. */
+		conn = ev.event_ptr;
+		/* Retransmit last packet (e.g. TCP segment). */
+		...
+		/* Re-arm timer using original values. */
+		rte_event_timer_arm_burst(adapter_id, &conn->timer, 1);
+	}
+
+Summary
+-------
+
+The Event Timer Adapter library extends the DPDK event-based programming model
+by representing timer expirations as events in the system and allowing
+applications to use existing event processing loops to arm and cancel event
+timers or handle timer expiry events.
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index bbbe789..589c05d 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -42,6 +42,7 @@ Programmer's Guide
     thread_safety_dpdk_functions
     eventdev
     event_ethernet_rx_adapter
+    event_timer_adapter
     qos_framework
     power_man
     packet_classif_access_ctrl
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* [PATCH v11 9/9] doc: add event timer adapter documentation
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
                                 ` (7 preceding siblings ...)
  2018-04-04 21:51               ` [PATCH v11 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
@ 2018-04-04 21:51               ` Erik Gabriel Carrillo
  2018-04-05  3:31               ` [PATCH v11 0/9] eventtimer: introduce event timer adapter Jerin Jacob
  9 siblings, 0 replies; 133+ messages in thread
From: Erik Gabriel Carrillo @ 2018-04-04 21:51 UTC (permalink / raw)
  To: pbhagavatula, jerin.jacob; +Cc: dev

Signed-off-by: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
Acked-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 MAINTAINERS                            |  7 +++++++
 doc/api/doxy-api-index.md              | 32 +++-----------------------------
 doc/guides/rel_notes/release_18_05.rst |  6 ++++++
 3 files changed, 16 insertions(+), 29 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index d4c0cc1..d72f012 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -317,6 +317,13 @@ F: lib/librte_eventdev/*eth_rx_adapter*
 F: test/test/test_event_eth_rx_adapter.c
 F: doc/guides/prog_guide/event_ethernet_rx_adapter.rst
 
+Eventdev Timer Adapter API - EXPERIMENTAL
+M: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
+T: git://dpdk.org/next/dpdk-next-eventdev
+F: lib/librte_eventdev/*timer_adapter*
+F: test/test/test_event_timer_adapter.c
+F: doc/guides/prog_guide/event_timer_adapter.rst
+
 Raw device API - EXPERIMENTAL
 M: Shreyansh Jain <shreyansh.jain@nxp.com>
 M: Hemant Agrawal <hemant.agrawal@nxp.com>
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..5c6cd51 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -2,35 +2,8 @@ API {#index}
 ===
 
 <!--
-  BSD LICENSE
-
-  Copyright 2013-2017 6WIND S.A.
-
-  Redistribution and use in source and binary forms, with or without
-  modification, are permitted provided that the following conditions
-  are met:
-
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in
-      the documentation and/or other materials provided with the
-      distribution.
-    * Neither the name of 6WIND S.A. nor the names of its
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
-
-  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  SPDX-License-Identifier: BSD-3-Clause
+  Copyright(c) 2013-2017 6WIND S.A.
 -->
 
 The public API headers are grouped by topics:
@@ -47,6 +20,7 @@ The public API headers are grouped by topics:
   [security]           (@ref rte_security.h),
   [eventdev]           (@ref rte_eventdev.h),
   [event_eth_rx_adapter]   (@ref rte_event_eth_rx_adapter.h),
+  [event_timer_adapter]    (@ref rte_event_timer_adapter.h),
   [rawdev]             (@ref rte_rawdev.h),
   [metrics]            (@ref rte_metrics.h),
   [bitrate]            (@ref rte_bitrate.h),
diff --git a/doc/guides/rel_notes/release_18_05.rst b/doc/guides/rel_notes/release_18_05.rst
index 9cc77f8..d2a4192 100644
--- a/doc/guides/rel_notes/release_18_05.rst
+++ b/doc/guides/rel_notes/release_18_05.rst
@@ -58,6 +58,12 @@ New Features
   * Added support for NVGRE, VXLAN and GENEVE filters in flow API.
   * Added support for DROP action in flow API.
 
+* **Added the Event Timer Adapter Library.**
+
+  The Event Timer Adapter Library extends the event-based model by introducing
+  APIs that allow applications to arm/cancel event timers that generate
+  timer expiry events. This new type of event is scheduled by an event device
+  along with existing types of events.
 
 API Changes
 -----------
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 133+ messages in thread

* Re: [PATCH v11 0/9] eventtimer: introduce event timer adapter
  2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
                                 ` (8 preceding siblings ...)
  2018-04-04 21:51               ` [PATCH v11 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
@ 2018-04-05  3:31               ` Jerin Jacob
  9 siblings, 0 replies; 133+ messages in thread
From: Jerin Jacob @ 2018-04-05  3:31 UTC (permalink / raw)
  To: Erik Gabriel Carrillo; +Cc: pbhagavatula, dev

-----Original Message-----
> Date: Wed, 4 Apr 2018 16:51:05 -0500
> From: Erik Gabriel Carrillo <erik.g.carrillo@intel.com>
> To: pbhagavatula@caviumnetworks.com, jerin.jacob@caviumnetworks.com
> CC: dev@dpdk.org
> Subject: [PATCH v11 0/9] eventtimer: introduce event timer adapter 
> X-Mailer: git-send-email 1.7.10
> 
> This patch series contains the next iteration of the Event Timer Adapter
> library, which abstracts timer mechanisms that are tightly coupled with event
> devices, and extends the event based programming model so that timer
> expirations are represented as an event.
> 
Good work Erik. Apologies for making it reach to v11.

Applied to dpdk-next-eventdev/master. Thanks.

> 

^ permalink raw reply	[flat|nested] 133+ messages in thread

end of thread, other threads:[~2018-04-05  3:31 UTC | newest]

Thread overview: 133+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <1511890148-22295-1-git-send-email-erik.g.carrillo@intel.com>
2017-12-01 20:00 ` [RFC PATCH v5 0/5] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
2017-12-01 20:00   ` [RFC PATCH v5 1/5] " Erik Gabriel Carrillo
2017-12-06 15:17     ` Jerin Jacob
2017-12-06 16:23       ` Carrillo, Erik G
2017-12-01 20:00   ` [RFC PATCH v5 2/5] eventtimer: add common code Erik Gabriel Carrillo
2017-12-06 15:35     ` Jerin Jacob
2017-12-01 20:00   ` [RFC PATCH v5 3/5] eventtimer: add config variable for adapter Erik Gabriel Carrillo
2017-12-06 15:41     ` Jerin Jacob
2017-12-06 20:01       ` Carrillo, Erik G
2017-12-01 20:00   ` [RFC PATCH v5 4/5] eventtimer: add default software implementation stub Erik Gabriel Carrillo
2017-12-01 20:00   ` [RFC PATCH v5 5/5] test: add event timer adapter auto-test Erik Gabriel Carrillo
2018-01-11  0:20   ` [PATCH v6 00/23] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
2018-01-11  0:20     ` [PATCH v6 01/23] eventtimer: add event timer adapter API Erik Gabriel Carrillo
2018-01-11 11:10       ` Pavan Nikhilesh
2018-01-11 16:56         ` Carrillo, Erik G
2018-01-11 17:31           ` Pavan Nikhilesh
2018-01-11  0:20     ` [PATCH v6 02/23] eventtimer: add common code Erik Gabriel Carrillo
2018-01-11  0:20     ` [PATCH v6 03/23] eventtimer: add default software driver stub Erik Gabriel Carrillo
2018-01-11  0:20     ` [PATCH v6 04/23] test: add event timer adapter auto-test Erik Gabriel Carrillo
2018-01-11  0:20     ` [PATCH v6 05/23] eventtimer: add adapter allocation definitions Erik Gabriel Carrillo
2018-01-11 11:18       ` Pavan Nikhilesh
2018-01-11  0:20     ` [PATCH v6 06/23] test: exercise event timer adapter allocation functions Erik Gabriel Carrillo
2018-01-11  0:20     ` [PATCH v6 07/23] eventtimer: add adapter get info function definition Erik Gabriel Carrillo
2018-01-11  0:20     ` [PATCH v6 08/23] eventtimer: add adapter start/stop definitions Erik Gabriel Carrillo
2018-01-11 17:28       ` Pavan Nikhilesh
2018-01-18 23:57         ` Carrillo, Erik G
2018-01-11  0:21     ` [PATCH v6 09/23] eventtimer: add API to get service id Erik Gabriel Carrillo
2018-01-11  0:21     ` [PATCH v6 10/23] eventtimer: remove service id entry from info structure Erik Gabriel Carrillo
2018-01-11 11:34       ` Pavan Nikhilesh
2018-01-11  0:21     ` [PATCH v6 11/23] test: exercise event timer adapter start/stop functions Erik Gabriel Carrillo
2018-01-11  0:21     ` [PATCH v6 12/23] eventtimer: add event timer arm/cancel function definitions Erik Gabriel Carrillo
2018-01-11 11:38       ` Pavan Nikhilesh
2018-01-11  0:21     ` [PATCH v6 13/23] eventtimer: add adapter service definition Erik Gabriel Carrillo
2018-01-11 12:03       ` Pavan Nikhilesh
2018-01-11  0:21     ` [PATCH v6 14/23] eventtimer: add event timer initializer function Erik Gabriel Carrillo
2018-01-11  0:21     ` [PATCH v6 15/23] eventtimer: add buffering of timer expiry events Erik Gabriel Carrillo
2018-01-11 12:18       ` Pavan Nikhilesh
2018-01-18 23:07         ` Carrillo, Erik G
2018-01-20  8:55           ` Pavan Nikhilesh
2018-01-11  0:21     ` [PATCH v6 16/23] eventtimer: add stats to API Erik Gabriel Carrillo
2018-01-11  0:21     ` [PATCH v6 17/23] eventtimer: add support for single-producer put mode Erik Gabriel Carrillo
2018-01-11  0:21     ` [PATCH v6 18/23] eventtimer: add non-blocking mode for event timer operations Erik Gabriel Carrillo
2018-01-11  0:21     ` [PATCH v6 19/23] test: exercise event timer arm and expiry Erik Gabriel Carrillo
2018-01-11 12:26       ` Pavan Nikhilesh
2018-01-11  0:21     ` [PATCH v6 20/23] maintainers: add event timer adapter section Erik Gabriel Carrillo
2018-01-11  0:21     ` [PATCH v6 21/23] doc: add event timer adapter to API index Erik Gabriel Carrillo
2018-01-12 11:12       ` Kovacevic, Marko
2018-01-11  0:21     ` [PATCH v6 22/23] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
2018-01-11 15:26       ` Kovacevic, Marko
2018-01-11  0:21     ` [PATCH v6 23/23] doc: add event timer adapter to release notes Erik Gabriel Carrillo
2018-01-12 10:48       ` Kovacevic, Marko
2018-03-08 21:53     ` [PATCH v7 0/7] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
2018-03-08 21:54       ` [PATCH v7 1/7] eventtimer: add event timer adapter API Erik Gabriel Carrillo
2018-03-12  7:53         ` Jerin Jacob
2018-03-12 16:22           ` Carrillo, Erik G
2018-03-08 21:54       ` [PATCH v7 2/7] eventtimer: add common code Erik Gabriel Carrillo
2018-03-12  8:11         ` Jerin Jacob
2018-03-08 21:54       ` [PATCH v7 3/7] eventtimer: add default software driver Erik Gabriel Carrillo
2018-03-12  8:45         ` Jerin Jacob
2018-03-12 21:20           ` Carrillo, Erik G
2018-03-08 21:54       ` [PATCH v7 4/7] eventtimer: add support for meson build system Erik Gabriel Carrillo
2018-03-08 21:54       ` [PATCH v7 5/7] test: add event timer adapter auto-test Erik Gabriel Carrillo
2018-03-14 12:52         ` Pavan Nikhilesh
2018-03-14 21:42           ` Carrillo, Erik G
2018-03-14 13:31         ` Pavan Nikhilesh
2018-03-14 21:40           ` Carrillo, Erik G
2018-03-08 21:54       ` [PATCH v7 6/7] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
2018-03-12 11:21         ` Jerin Jacob
2018-03-12 22:02           ` Carrillo, Erik G
2018-03-08 21:54       ` [PATCH v7 7/7] doc: add event timer adapter documentation Erik Gabriel Carrillo
2018-03-12 11:28         ` Jerin Jacob
2018-03-29 21:27       ` [PATCH v8 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
2018-03-29 21:27         ` [PATCH v8 1/9] " Erik Gabriel Carrillo
2018-03-29 21:27         ` [PATCH v8 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
2018-04-02  8:12           ` Jerin Jacob
2018-04-02  9:16             ` Hemant Agrawal
2018-03-29 21:27         ` [PATCH v8 3/9] eventtimer: add common code Erik Gabriel Carrillo
2018-03-29 21:27         ` [PATCH v8 4/9] mk: update library order in static build Erik Gabriel Carrillo
2018-03-29 21:27         ` [PATCH v8 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
2018-04-02  8:42           ` Jerin Jacob
2018-03-29 21:27         ` [PATCH v8 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
2018-03-29 21:27         ` [PATCH v8 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
2018-03-30 15:48           ` Bhagavatula, Pavan
2018-03-30 18:47             ` Carrillo, Erik G
2018-03-29 21:27         ` [PATCH v8 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
2018-03-29 21:27         ` [PATCH v8 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
2018-04-02 19:39         ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Erik Gabriel Carrillo
2018-04-02 19:39           ` [PATCH v9 1/9] " Erik Gabriel Carrillo
2018-04-02 23:25             ` Jerin Jacob
2018-04-02 19:39           ` [PATCH v9 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
2018-04-02 23:27             ` Jerin Jacob
2018-04-02 19:39           ` [PATCH v9 3/9] eventtimer: add common code Erik Gabriel Carrillo
2018-04-02 23:35             ` Jerin Jacob
2018-04-03 18:38               ` Carrillo, Erik G
2018-04-02 19:39           ` [PATCH v9 4/9] mk: update library order in static build Erik Gabriel Carrillo
2018-04-02 23:36             ` Jerin Jacob
2018-04-02 19:39           ` [PATCH v9 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
2018-04-03  9:59             ` Pavan Nikhilesh
2018-04-02 19:39           ` [PATCH v9 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
2018-04-02 19:39           ` [PATCH v9 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
2018-04-03  9:52             ` Pavan Nikhilesh
2018-04-02 19:39           ` [PATCH v9 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
2018-04-03  0:00             ` Jerin Jacob
2018-04-02 19:39           ` [PATCH v9 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
2018-04-02 23:42             ` Jerin Jacob
2018-04-02 23:19           ` [PATCH v9 0/9] eventtimer: introduce event timer adapter Jerin Jacob
2018-04-03 14:09             ` Carrillo, Erik G
2018-04-03 14:15               ` Jerin Jacob
2018-04-03 18:32                 ` Carrillo, Erik G
2018-04-03 21:44           ` [PATCH v10 " Erik Gabriel Carrillo
2018-04-03 21:44             ` [PATCH v10 1/9] " Erik Gabriel Carrillo
2018-04-03 21:44             ` [PATCH v10 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
2018-04-03 21:44             ` [PATCH v10 3/9] eventtimer: add common code Erik Gabriel Carrillo
2018-04-04 16:50               ` Pavan Nikhilesh
2018-04-03 21:44             ` [PATCH v10 4/9] mk: update library order in static build Erik Gabriel Carrillo
2018-04-03 21:44             ` [PATCH v10 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
2018-04-03 21:44             ` [PATCH v10 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
2018-04-04 16:51               ` Pavan Nikhilesh
2018-04-03 21:44             ` [PATCH v10 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
2018-04-03 21:44             ` [PATCH v10 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
2018-04-03 21:44             ` [PATCH v10 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
2018-04-04  2:31             ` [PATCH v10 0/9] eventtimer: introduce event timer adapter Jerin Jacob
2018-04-04 21:51             ` [PATCH v11 " Erik Gabriel Carrillo
2018-04-04 21:51               ` [PATCH v11 1/9] " Erik Gabriel Carrillo
2018-04-04 21:51               ` [PATCH v11 2/9] eventdev: convert to SPDX license tag in header Erik Gabriel Carrillo
2018-04-04 21:51               ` [PATCH v11 3/9] eventtimer: add common code Erik Gabriel Carrillo
2018-04-04 21:51               ` [PATCH v11 4/9] mk: update library order in static build Erik Gabriel Carrillo
2018-04-04 21:51               ` [PATCH v11 5/9] eventtimer: add default software driver Erik Gabriel Carrillo
2018-04-04 21:51               ` [PATCH v11 6/9] eventtimer: add support for meson build system Erik Gabriel Carrillo
2018-04-04 21:51               ` [PATCH v11 7/9] test: add event timer adapter auto-test Erik Gabriel Carrillo
2018-04-04 21:51               ` [PATCH v11 8/9] doc: add event timer adapter section to programmer's guide Erik Gabriel Carrillo
2018-04-04 21:51               ` [PATCH v11 9/9] doc: add event timer adapter documentation Erik Gabriel Carrillo
2018-04-05  3:31               ` [PATCH v11 0/9] eventtimer: introduce event timer adapter Jerin Jacob

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.