Discussion:
[dpdk-dev] [RFC PATCH v5 0/5] eventtimer: introduce event timer adapter
(too old to reply)
Erik Gabriel Carrillo
2017-12-01 20:00:53 UTC
Permalink
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
Erik Gabriel Carrillo
2017-12-01 20:00:54 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Jerin Jacob
2017-12-06 15:17:35 UTC
Permalink
-----Original Message-----
Date: Fri, 1 Dec 2017 14:00:54 -0600
Subject: [RFC PATCH v5 1/5] eventtimer: introduce event timer adapter
X-Mailer: git-send-email 1.7.10
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.*/
+};
+
+/**
Carrillo, Erik G
2017-12-06 16:23:38 UTC
Permalink
Post by Jerin Jacob
-----Original Message-----
Sent: Wednesday, December 6, 2017 9:18 AM
Subject: Re: [RFC PATCH v5 1/5] eventtimer: introduce event timer adapter
-----Original Message-----
Date: Fri, 1 Dec 2017 14:00:54 -0600
Subject: [RFC PATCH v5 1/5] eventtimer: introduce event timer adapter
X-Mailer: git-send-email 1.7.10
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.
Post by Jerin Jacob
---
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
Post by Jerin Jacob
+ 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.*/
+};
+
+/**
Erik Gabriel Carrillo
2017-12-01 20:00:55 UTC
Permalink
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 <***@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
Jerin Jacob
2017-12-06 15:35:27 UTC
Permalink
-----Original Message-----
Date: Fri, 1 Dec 2017 14:00:55 -0600
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.
---
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);
+}
*/
Erik Gabriel Carrillo
2017-12-01 20:00:56 UTC
Permalink
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 <***@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
Jerin Jacob
2017-12-06 15:41:40 UTC
Permalink
-----Original Message-----
Date: Fri, 1 Dec 2017 14:00:56 -0600
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.
---
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
Carrillo, Erik G
2017-12-06 20:01:28 UTC
Permalink
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
Post by Jerin Jacob
-----Original Message-----
Sent: Wednesday, December 6, 2017 9:42 AM
Subject: Re: [RFC PATCH v5 3/5] eventtimer: add config variable for adapter
-----Original Message-----
Date: Fri, 1 Dec 2017 14:00:56 -0600
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.
---
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
.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
(*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
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
Erik Gabriel Carrillo
2017-12-01 20:00:57 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2017-12-01 20:00:58 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-01-11 00:20:51 UTC
Permalink
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
Erik Gabriel Carrillo
2018-01-11 00:20:52 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Pavan Nikhilesh
2018-01-11 11:10:53 UTC
Permalink
Consider giving credit to the original authors.
Post by Erik Gabriel Carrillo
---
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
+ *
+ * * 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
Post by Erik Gabriel Carrillo
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ *
+ * RTE Event Timer Adapter
<snip>
Post by Erik Gabriel Carrillo
+ */
+
+#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
+
+/**
Please make sure that Experimental tags usage is inline with the new tool
http://dpdk.org/dev/patchwork/patch/32234.

Cheers,
Pavan
Post by Erik Gabriel Carrillo
+ *
+ * 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>
Carrillo, Erik G
2018-01-11 16:56:40 UTC
Permalink
Post by Jerin Jacob
-----Original Message-----
Sent: Thursday, January 11, 2018 5:11 AM
Subject: Re: [PATCH v6 01/23] eventtimer: add event timer adapter API
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
Pavan Nikhilesh
2018-01-11 17:31:02 UTC
Permalink
Post by Carrillo, Erik G
Post by Jerin Jacob
-----Original Message-----
Sent: Thursday, January 11, 2018 5:11 AM
Subject: Re: [PATCH v6 01/23] eventtimer: add event timer adapter API
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.
Post by Carrillo, Erik G
Regards,
Gabriel
Thanks,
Pavan.
Erik Gabriel Carrillo
2018-01-11 00:20:53 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-01-11 00:20:54 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-01-11 00:20:55 UTC
Permalink
Add initial infrastructure for event timer adapter auto-test.

Signed-off-by: Erik Gabriel 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
Erik Gabriel Carrillo
2018-01-11 00:20:56 UTC
Permalink
Add definitions for the functions that allocate and deallocate adapter
instances in the default software implementation.

Signed-off-by: Erik Gabriel 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
Pavan Nikhilesh
2018-01-11 11:18:31 UTC
Permalink
Post by Erik Gabriel Carrillo
Add definitions for the functions that allocate and deallocate adapter
instances in the default software implementation.
---
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.
Post by Erik Gabriel Carrillo
+
+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>
Post by Erik Gabriel Carrillo
+
+ 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.
Post by Erik Gabriel Carrillo
+
+ /* 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
Post by Erik Gabriel Carrillo
/**
--
2.6.4
Erik Gabriel Carrillo
2018-01-11 00:20:57 UTC
Permalink
Exercise the create and free functions in the event timer adapter
auto-test.

Signed-off-by: Erik Gabriel 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
Erik Gabriel Carrillo
2018-01-11 00:20:59 UTC
Permalink
Add definitions to the default software implementation for the functions
that start and stop adapter instances.

Signed-off-by: Erik Gabriel 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
Pavan Nikhilesh
2018-01-11 17:28:32 UTC
Permalink
Post by Erik Gabriel Carrillo
Add definitions to the default software implementation for the functions
that start and stop adapter instances.
---
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.
Post by Erik Gabriel Carrillo
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
Carrillo, Erik G
2018-01-18 23:57:20 UTC
Permalink
Post by Jerin Jacob
-----Original Message-----
Sent: Thursday, January 11, 2018 11:29 AM
Subject: Re: [PATCH v6 08/23] eventtimer: add adapter start/stop definitions
Post by Erik Gabriel Carrillo
Add definitions to the default software implementation for the
functions that start and stop adapter instances.
---
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.
Post by Jerin Jacob
Cheers,
Pavan.
Post by Erik Gabriel Carrillo
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);
Post by Erik Gabriel Carrillo
}
static void
--
2.6.4
Erik Gabriel Carrillo
2018-01-11 00:20:58 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-01-11 00:21:00 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-01-11 00:21:02 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Erik Gabriel Carrillo
2018-01-11 00:21:01 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Pavan Nikhilesh
2018-01-11 11:34:39 UTC
Permalink
Post by Erik Gabriel Carrillo
---
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.
Post by Erik Gabriel Carrillo
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
Erik Gabriel Carrillo
2018-01-11 00:21:03 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Pavan Nikhilesh
2018-01-11 11:38:37 UTC
Permalink
Post by Erik Gabriel Carrillo
---
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.
Post by Erik Gabriel Carrillo
+ 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
Erik Gabriel Carrillo
2018-01-11 00:21:04 UTC
Permalink
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 <***@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
Pavan Nikhilesh
2018-01-11 12:03:09 UTC
Permalink
Post by Erik Gabriel Carrillo
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.
---
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>
Post by Erik Gabriel Carrillo
+ 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.
Post by Erik Gabriel Carrillo
+ 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.
Post by Erik Gabriel Carrillo
+}
+
+/* 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>
Post by Erik Gabriel Carrillo
+
+#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) {
+ 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.
Post by Erik Gabriel Carrillo
+ evtim->state = RTE_EVENT_TIMER_ARMED;
+ break;
+ /* 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.
Post by Erik Gabriel Carrillo
+ 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.
Post by Erik Gabriel Carrillo
+
+ /* Could use for stats */
+ RTE_SET_USED(nb_events);
+ RTE_SET_USED(ret);
+
return 0;
}
<snip>
Erik Gabriel Carrillo
2018-01-11 00:21:05 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-01-11 00:21:06 UTC
Permalink
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 <***@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
Pavan Nikhilesh
2018-01-11 12:18:32 UTC
Permalink
Post by Erik Gabriel Carrillo
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.
Post by Erik Gabriel Carrillo
---
lib/librte_eventdev/rte_event_timer_adapter.c | 118 +++++++++++++++++++++++---
1 file changed, 108 insertions(+), 10 deletions(-)
<snip>
Carrillo, Erik G
2018-01-18 23:07:52 UTC
Permalink
Post by Jerin Jacob
-----Original Message-----
Sent: Thursday, January 11, 2018 6:19 AM
Subject: Re: [PATCH v6 15/23] eventtimer: add buffering of timer expiry
events
Post by Erik Gabriel Carrillo
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.
Post by Jerin Jacob
Post by Erik Gabriel Carrillo
---
lib/librte_eventdev/rte_event_timer_adapter.c | 118
+++++++++++++++++++++++---
1 file changed, 108 insertions(+), 10 deletions(-)
<snip>
Pavan Nikhilesh
2018-01-20 08:55:21 UTC
Permalink
Post by Carrillo, Erik G
Post by Jerin Jacob
-----Original Message-----
Sent: Thursday, January 11, 2018 6:19 AM
Subject: Re: [PATCH v6 15/23] eventtimer: add buffering of timer expiry
events
Post by Erik Gabriel Carrillo
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().
Post by Carrillo, Erik G
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.
Post by Carrillo, Erik G
Post by Jerin Jacob
Post by Erik Gabriel Carrillo
---
lib/librte_eventdev/rte_event_timer_adapter.c | 118
+++++++++++++++++++++++---
1 file changed, 108 insertions(+), 10 deletions(-)
<snip>
Erik Gabriel Carrillo
2018-01-11 00:21:08 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-01-11 00:21:07 UTC
Permalink
Add interfaces to support the collection, retrieval and resetting of
per-adapter statistics.

Signed-off-by: Erik Gabriel 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
Erik Gabriel Carrillo
2018-01-11 00:21:09 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-01-11 00:21:10 UTC
Permalink
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 <***@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
Pavan Nikhilesh
2018-01-11 12:26:56 UTC
Permalink
Post by Erik Gabriel Carrillo
Add a test that creates an event timer and detects the generation of a
timer expiry event being scheduled through the software event device.
---
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>
Erik Gabriel Carrillo
2018-01-11 00:21:11 UTC
Permalink
Signed-off-by: Erik Gabriel 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 <***@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
Erik Gabriel Carrillo
2018-01-11 00:21:12 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Kovacevic, Marko
2018-01-12 11:12:42 UTC
Permalink
Post by Erik Gabriel Carrillo
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 <***@intel.com>
Erik Gabriel Carrillo
2018-01-11 00:21:13 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Kovacevic, Marko
2018-01-11 15:26:26 UTC
Permalink
Post by Erik Gabriel Carrillo
---
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 <***@intel.com>
Erik Gabriel Carrillo
2018-01-11 00:21:14 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Kovacevic, Marko
2018-01-12 10:48:41 UTC
Permalink
Post by Erik Gabriel Carrillo
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 <***@intel.com>
Erik Gabriel Carrillo
2018-03-08 21:53:59 UTC
Permalink
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
Erik Gabriel Carrillo
2018-03-08 21:54:00 UTC
Permalink
Signed-off-by: Jerin Jacob <***@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <***@caviumnetworks.com>
Signed-off-by: Erik Gabriel 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
Jerin Jacob
2018-03-12 07:53:33 UTC
Permalink
-----Original Message-----
Date: Thu, 8 Mar 2018 15:54:00 -0600
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.
---
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
+
+/**
+ *
+ * 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_*) */
+};
+/**
+
+/**
+ *
+ * Set an event timer's initial state and initialize the event it carries.
+ *
+ * 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.
+
+/**
+ *
+ * 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.
+ *
+ * A pointer to an event timer adapter structure.
+ * Pointer to an array of objects of type *rte_event_timer* structure.
+ * Number of event timers in the supplied array.
+ *
+ * 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
+ * - 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);
+
+/**
+ *
+ * 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.
+ *
+ * A pointer to an event timer adapter structure.
+ * Points to an array of objects of type *rte_event_timer* structure.
+ * The number of ticks in which the timers should expire.
+ * Number of event timers in the supplied array.
+ *
+ * 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
+ * - 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);
+
+/**
+ *
+ * Cancel a burst of event timers from being scheduled to the event device.
+ *
+ * A pointer to an event timer adapter structure.
+ * Points to an array of objects of type *rte_event_timer* structure
+ * Number of event timer instances in the supplied array.
+ *
+ * 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
+ * - 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
- *
- * * 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.
Carrillo, Erik G
2018-03-12 16:22:05 UTC
Permalink
Hi Jerin,
Post by Jerin Jacob
-----Original Message-----
Sent: Monday, March 12, 2018 2:54 AM
Subject: Re: [PATCH v7 1/7] eventtimer: add event timer adapter API
-----Original Message-----
Date: Thu, 8 Mar 2018 15:54:00 -0600
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.
Post by Jerin Jacob
---
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
+
+/**
+ *
+ * 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.
Post by Jerin Jacob
+ 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_*)
*/ };
+/**
+
+/**
+ *
+ * Set an event timer's initial state and initialize the event it carries.
+ *
+ * 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.
Post by Jerin Jacob
+
+/**
+ *
+ * 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.
+ *
+ * A pointer to an event timer adapter structure.
+ * Pointer to an array of objects of type *rte_event_timer* structure.
+ * Number of event timers in the supplied array.
+ *
+ * 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
+ * - 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 ...>
Post by Jerin Jacob
- * 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.
Post by Jerin Jacob
+ * 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
Erik Gabriel Carrillo
2018-03-08 21:54:01 UTC
Permalink
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 <***@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
Jerin Jacob
2018-03-12 08:11:07 UTC
Permalink
-----Original Message-----
Date: Thu, 8 Mar 2018 15:54:01 -0600
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.
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 {
*/
+#define RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT (1ULL << 1)
1ULL << 0 ??
+/**< This flag is set when the timer mechanism is in HW. */
+
+
+EXPERIMENTAL {
+
+ 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
Erik Gabriel Carrillo
2018-03-08 21:54:02 UTC
Permalink
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 <***@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
Jerin Jacob
2018-03-12 08:45:46 UTC
Permalink
-----Original Message-----
Date: Thu, 8 Mar 2018 15:54:02 -0600
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.
---
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
Carrillo, Erik G
2018-03-12 21:20:14 UTC
Permalink
Hi Jerin,
Post by Jerin Jacob
-----Original Message-----
Sent: Monday, March 12, 2018 3:46 AM
Subject: Re: [PATCH v7 3/7] eventtimer: add default software driver
-----Original Message-----
Date: Thu, 8 Mar 2018 15:54:02 -0600
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 ...>
Post by Jerin Jacob
--- 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
Post by Jerin Jacob
_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
Erik Gabriel Carrillo
2018-03-08 21:54:03 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Erik Gabriel Carrillo
2018-03-08 21:54:04 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Pavan Nikhilesh
2018-03-14 12:52:41 UTC
Permalink
Hi Gabriel,
Post by Erik Gabriel Carrillo
---
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>
Post by Erik Gabriel Carrillo
+
+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.
Post by Erik Gabriel Carrillo
+
+ return TEST_SUCCESS;
+}
<snip>
Carrillo, Erik G
2018-03-14 21:42:29 UTC
Permalink
Hi Pavan,
Post by Jerin Jacob
-----Original Message-----
Sent: Wednesday, March 14, 2018 7:53 AM
Subject: Re: [PATCH v7 5/7] test: add event timer adapter auto-test
Hi Gabriel,
Post by Erik Gabriel Carrillo
---
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>
Post by Erik Gabriel Carrillo
+
+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
Post by Jerin Jacob
Thanks,
Pavan.
Post by Erik Gabriel Carrillo
+
+ return TEST_SUCCESS;
+}
<snip>
Pavan Nikhilesh
2018-03-14 13:31:04 UTC
Permalink
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.
Post by Erik Gabriel Carrillo
---
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>
Post by Erik Gabriel Carrillo
+
+/* 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.
Post by Erik Gabriel Carrillo
+ 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.
Post by Erik Gabriel Carrillo
+
+ 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.
Carrillo, Erik G
2018-03-14 21:40:47 UTC
Permalink
Hi Pavan,
Post by Jerin Jacob
-----Original Message-----
Sent: Wednesday, March 14, 2018 8:31 AM
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
Post by Jerin Jacob
Post by Erik Gabriel Carrillo
---
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>
Post by Erik Gabriel Carrillo
+
+/* This port conf callback is used by the max adapter instance creation
test.
Post by Erik Gabriel Carrillo
+ * 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,
Post by Erik Gabriel Carrillo
+ 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.
Post by Erik Gabriel Carrillo
+ 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.
Post by Erik Gabriel Carrillo
+
+ 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.
Erik Gabriel Carrillo
2018-03-08 21:54:06 UTC
Permalink
Signed-off-by: Erik Gabriel 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 <***@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 <***@nxp.com>
M: 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
Jerin Jacob
2018-03-12 11:28:16 UTC
Permalink
-----Original Message-----
Date: Thu, 8 Mar 2018 15:54:06 -0600
Subject: [PATCH v7 7/7] doc: add event timer adapter documentation
X-Mailer: git-send-email 1.7.10
---
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
+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
+
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,
+ scheduled by an event device along with existing types of events.
API Changes
-----------
--
2.6.4
Erik Gabriel Carrillo
2018-03-08 21:54:05 UTC
Permalink
Signed-off-by: Erik Gabriel Carrillo <***@intel.com>
Signed-off-by: Jerin Jacob <***@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <***@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
Jerin Jacob
2018-03-12 11:21:07 UTC
Permalink
-----Original Message-----
Date: Thu, 8 Mar 2018 15:54:05 -0600
Subject: [PATCH v7 6/7] doc: add event timer adapter section to
programmer's guide
X-Mailer: git-send-email 1.7.10
---
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 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``.
+
+
+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
+
+.. 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
+
+.. 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) {
+ ...
+ 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
--
2.6.4
Carrillo, Erik G
2018-03-12 22:02:33 UTC
Permalink
Hi Jerin,
Post by Jerin Jacob
-----Original Message-----
Sent: Monday, March 12, 2018 6:21 AM
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
Subject: [PATCH v7 6/7] doc: add event timer adapter section to
programmer's guide
X-Mailer: git-send-email 1.7.10
---
<... snipped ...>
Post by Jerin Jacob
+
+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.
Post by Jerin Jacob
+
+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``.
+
+
+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
+
+.. 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.
Post by Jerin Jacob
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.
Post by Jerin Jacob
+ 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 ...>
Post by Jerin Jacob
Overall, it looks good. With above changes
--
2.6.4
Thanks for the suggestions,
Gabriel
Erik Gabriel Carrillo
2018-03-29 21:27:23 UTC
Permalink
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
Erik Gabriel Carrillo
2018-03-29 21:27:24 UTC
Permalink
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 <***@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <***@caviumnetworks.com>
Signed-off-by: Erik Gabriel 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
Erik Gabriel Carrillo
2018-03-29 21:27:25 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Jerin Jacob
2018-04-02 08:12:29 UTC
Permalink
-----Original Message-----
Date: Thu, 29 Mar 2018 16:27:25 -0500
Subject: [PATCH v8 2/9] eventdev: convert to SPDX license tag in header
X-Mailer: git-send-email 1.7.10
---
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
- *
- * * 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 <***@caviumnetworks.com>

NXP folks,
Could you ACK the license change.
*/
#ifndef _RTE_EVENTDEV_H_
--
2.6.4
Hemant Agrawal
2018-04-02 09:16:56 UTC
Permalink
Post by Jerin Jacob
-----Original Message-----
Date: Thu, 29 Mar 2018 16:27:25 -0500
Subject: [PATCH v8 2/9] eventdev: convert to SPDX license tag in header
X-Mailer: git-send-email 1.7.10
---
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
- *
- * * 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
Post by Jerin Jacob
+ * All rights reserved.
NXP folks,
Could you ACK the license change.
*/
#ifndef _RTE_EVENTDEV_H_
--
2.6.4
Erik Gabriel Carrillo
2018-03-29 21:27:26 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-03-29 21:27:27 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-03-29 21:27:28 UTC
Permalink
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 <***@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
Jerin Jacob
2018-04-02 08:42:45 UTC
Permalink
-----Original Message-----
Date: Thu, 29 Mar 2018 16:27:28 -0500
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.
---
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
Erik Gabriel Carrillo
2018-03-29 21:27:29 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Erik Gabriel Carrillo
2018-03-29 21:27:30 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Bhagavatula, Pavan
2018-03-30 15:48:46 UTC
Permalink
Hi Erik,

Few comments below,
Post by Erik Gabriel Carrillo
---
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>
Post by Erik Gabriel Carrillo
+/* 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.
Post by Erik Gabriel Carrillo
+ /* 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>
Post by Erik Gabriel Carrillo
+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.
Post by Erik Gabriel Carrillo
+ 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>
Post by Erik Gabriel Carrillo
+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.
Post by Erik Gabriel Carrillo
+ int sum = 0;
+ int tries = 0;
+ bool done = false;
<snip>
Post by Erik Gabriel Carrillo
+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?
Post by Erik Gabriel Carrillo
+ 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.
Carrillo, Erik G
2018-03-30 18:47:40 UTC
Permalink
Hi Pavan,
Post by Jerin Jacob
-----Original Message-----
Sent: Friday, March 30, 2018 10:49 AM
Subject: Re: [PATCH v8 7/9] test: add event timer adapter auto-test
Hi Erik,
Few comments below,
<...snipped...>
Post by Jerin Jacob
+/* 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...>
Post by Jerin Jacob
+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...>
Post by Jerin Jacob
+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
Erik Gabriel Carrillo
2018-03-29 21:27:31 UTC
Permalink
Signed-off-by: Erik Gabriel Carrillo <***@intel.com>
Signed-off-by: Jerin Jacob <***@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <***@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
Erik Gabriel Carrillo
2018-03-29 21:27:32 UTC
Permalink
Signed-off-by: Erik Gabriel 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 <***@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 <***@nxp.com>
M: 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
Erik Gabriel Carrillo
2018-04-02 19:39:45 UTC
Permalink
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
Erik Gabriel Carrillo
2018-04-02 19:39:47 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Jerin Jacob
2018-04-02 23:27:18 UTC
Permalink
-----Original Message-----
Date: Mon, 2 Apr 2018 14:39:47 -0500
Subject: [PATCH v9 2/9] eventdev: convert to SPDX license tag in header
X-Mailer: git-send-email 1.7.10
Acked-by: Jerin Jacob <***@caviumnetworks.com>

Hemant already Acked this patch, Please add his Acked-by in next version.
Erik Gabriel Carrillo
2018-04-02 19:39:46 UTC
Permalink
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 <***@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <***@caviumnetworks.com>
Signed-off-by: Erik Gabriel 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
Jerin Jacob
2018-04-02 23:25:16 UTC
Permalink
-----Original Message-----
Date: Mon, 2 Apr 2018 14:39:46 -0500
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.
Acked-by: Jerin Jacob <***@caviumnetworks.com>
Erik Gabriel Carrillo
2018-04-02 19:39:49 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-04-02 19:39:48 UTC
Permalink
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 <***@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
Jerin Jacob
2018-04-02 23:35:34 UTC
Permalink
-----Original Message-----
Date: Mon, 2 Apr 2018 14:39:48 -0500
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.
---
+
+EXPERIMENTAL {
+
+ 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
Erik Gabriel Carrillo
2018-04-02 19:39:50 UTC
Permalink
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 <***@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
Erik Gabriel Carrillo
2018-04-02 19:39:51 UTC
Permalink
Signed-off-by: Erik Gabriel 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
Erik Gabriel Carrillo
2018-04-02 19:39:53 UTC
Permalink
Signed-off-by: Erik Gabriel Carrillo <***@intel.com>
Signed-off-by: Jerin Jacob <***@caviumnetworks.com>
Signed-off-by: Pavan Nikhilesh <***@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
Erik Gabriel Carrillo
2018-04-02 19:39:54 UTC
Permalink
Signed-off-by: Erik Gabriel 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 <***@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 <***@nxp.com>
M: 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
Erik Gabriel Carrillo
2018-04-02 19:39:52 UTC
Permalink
Signed-off-by: Erik Gabriel 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_mem