diff mbox

[dpdk-dev,RFC,v4,2/4] eventtimer: add common code

Message ID 1511890808-6072-3-git-send-email-erik.g.carrillo@intel.com (mailing list archive)
State Superseded, archived
Headers show

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/Intel-compilation fail Compilation issues

Commit Message

Carrillo, Erik G Nov. 28, 2017, 5:40 p.m. UTC
This commit adds the logic that is shared by all event timer adapter
drivers; the common code handles instance allocation and some
initialization.

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

Comments

Pavan Nikhilesh Nov. 29, 2017, 5:19 a.m. UTC | #1
Hi Gabriel,

Comments inline

On Tue, Nov 28, 2017 at 11:40:06AM -0600, Erik Gabriel Carrillo wrote:
<snip>
> +struct rte_event_timer_adapter *
> +rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf)
> +{
> +	/* default port conf values */
> +	struct rte_event_port_conf port_conf = {
> +		.new_event_threshold = 128,
> +		.dequeue_depth = 32,
> +		.enqueue_depth = 32
> +	};
Instead of harcoding get the port conf values from
rte_event_port_default_conf_get().

> +
> +	return rte_event_timer_adapter_create_ext(conf, default_port_conf_cb,
> +						  &port_conf);
> +}
> +
> +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->caps,
> +						   &adapter->ops);

The underlying driver needs info about the adapter flags i.e.
RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES and RTE_EVENT_TIMER_ADAPTER_F_SP_PUT so we
need to pass those too conf->flags.

> +	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;
> +}
> +
> +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->caps,
> +						   &adapter->ops);

Same as above.

> +	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;
> +}
> +
<snip>
> +int
> +rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
> +			  struct rte_event_timer **event_timers,
> +			  uint16_t nb_event_timers)
> +{
> +	int ret;
> +
> +	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
> +	FUNC_PTR_OR_ERR_RET(adapter->arm_burst, -EINVAL);
> +
> +	if (!adapter->data->started)
> +		return -EAGAIN;

These checks are datapath heavy so enable them under debug compilation.

> +
> +	ret = adapter->arm_burst(adapter, event_timers, nb_event_timers);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;

when burst is called we need to return the number of timers successfully set
and free the failures. Return the result directly.

> +}
> +
> +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)
> +{
> +	int ret;
> +
> +	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
> +	FUNC_PTR_OR_ERR_RET(adapter->arm_tmo_tick_burst, -EINVAL);
> +
> +	if (!adapter->data->started)
> +		return -EAGAIN;
> +
> +	for (int i = 0; i < nb_event_timers; i++)
> +		event_timers[i]->timeout_ticks = timeout_ticks;
> +
> +	ret = adapter->arm_tmo_tick_burst(adapter, event_timers, timeout_ticks,
> +					  nb_event_timers);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;

Same as above.

> +}
> +
> +int
> +rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
> +			     struct rte_event_timer **event_timers,
> +			     uint16_t nb_event_timers)
> +{
> +	int ret;
> +
> +	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
> +	FUNC_PTR_OR_ERR_RET(adapter->cancel_burst, -EINVAL);
> +
> +	if (!adapter->data->started)
> +		return -EAGAIN;
> +
> +	ret = adapter->cancel_burst(adapter, event_timers, nb_event_timers);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;

Same as above.

> +}
> diff --git a/lib/librte_eventdev/rte_event_timer_adapter_driver.h b/lib/librte_eventdev/rte_event_timer_adapter_driver.h

Consider naming this _pmd.h for consistency

> new file mode 100644
> index 0000000..485fad1
> --- /dev/null
> +++ b/lib/librte_eventdev/rte_event_timer_adapter_driver.h
> @@ -0,0 +1,159 @@

Regards,
Pavan.
Carrillo, Erik G Nov. 30, 2017, 8:59 p.m. UTC | #2
Hi Pavan,

Thanks for the review;  I'm working on addressing the comments and have the following question (inline):

<... snipped ...>

> > +	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->caps,
> > +						   &adapter->ops);
> 
> The underlying driver needs info about the adapter flags i.e.
> RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES and
> RTE_EVENT_TIMER_ADAPTER_F_SP_PUT so we need to pass those too conf-
> >flags.

By "underlying driver", are you referring to the eventdev PMD, or the event timer adapter "driver" (i.e., the set of ops functions)?  

If the latter, the adapter "driver" will have a chance to inspect the flags when adapter->ops->init() is called below, since it can look at the flags through the adapter arg.

If the former, will the eventdev PMD consider the flags when deciding whether or not to provide an ops definition in the timer_adapter_caps_get() call?

> 
> > +	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;
> > +}

<... snipped ...>
Pavan Nikhilesh Dec. 1, 2017, 5:13 a.m. UTC | #3
On Thu, Nov 30, 2017 at 08:59:19PM +0000, Carrillo, Erik G wrote:
> Hi Pavan,
>
> Thanks for the review;  I'm working on addressing the comments and have the following question (inline):
>
> <... snipped ...>
>
> > > +	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->caps,
> > > +						   &adapter->ops);
> >
> > The underlying driver needs info about the adapter flags i.e.
> > RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES and
> > RTE_EVENT_TIMER_ADAPTER_F_SP_PUT so we need to pass those too conf-
> > >flags.
>
> By "underlying driver", are you referring to the eventdev PMD, or the event timer adapter "driver" (i.e., the set of ops functions)?
>
> If the latter, the adapter "driver" will have a chance to inspect the flags when adapter->ops->init() is called below, since it can look at the flags through the adapter arg.
>

I was refering to the timer driver, the presence of flag RTE_EVENT_TIMER_ADAPTER_F_SP_PUT
would suggest the driver to use a multi thread unsafe arm/cancel data path API
and it would set a different function pointers to adapter->arm_burst etc.

I dont think in the current scheme this is possible. Currently, if we see mempool it inspects
flags before setting ops.

Hope this clears things up.

-Pavan

> If the former, will the eventdev PMD consider the flags when deciding whether or not to provide an ops definition in the timer_adapter_caps_get() call?
>
> >
> > > +	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;
> > > +}
>
> <... snipped ...>
Carrillo, Erik G Dec. 1, 2017, 8:19 p.m. UTC | #4
> -----Original Message-----
> From: Pavan Nikhilesh Bhagavatula
> [mailto:pbhagavatula@caviumnetworks.com]
> Sent: Thursday, November 30, 2017 11:13 PM
> To: Carrillo, Erik G <erik.g.carrillo@intel.com>
> Cc: dev@dpdk.org
> Subject: Re: [RFC PATCH v4 2/4] eventtimer: add common code
> 
> On Thu, Nov 30, 2017 at 08:59:19PM +0000, Carrillo, Erik G wrote:
> > Hi Pavan,
> >
> > Thanks for the review;  I'm working on addressing the comments and have
> the following question (inline):
> >
> > <... snipped ...>
> >
> > > > +	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->caps,
> > > > +						   &adapter->ops);
> > >
> > > The underlying driver needs info about the adapter flags i.e.
> > > RTE_EVENT_TIMER_ADAPTER_F_ADJUST_RES and
> > > RTE_EVENT_TIMER_ADAPTER_F_SP_PUT so we need to pass those too
> conf-
> > > >flags.
> >
> > By "underlying driver", are you referring to the eventdev PMD, or the
> event timer adapter "driver" (i.e., the set of ops functions)?
> >
> > If the latter, the adapter "driver" will have a chance to inspect the flags
> when adapter->ops->init() is called below, since it can look at the flags
> through the adapter arg.
> >
> 
> I was refering to the timer driver, the presence of flag
> RTE_EVENT_TIMER_ADAPTER_F_SP_PUT would suggest the driver to use a
> multi thread unsafe arm/cancel data path API and it would set a different
> function pointers to adapter->arm_burst etc.
> 
> I dont think in the current scheme this is possible. Currently, if we see
> mempool it inspects flags before setting ops.
> 
> Hope this clears things up.
> 
> -Pavan

Yes, I see your point now.  I agree that it would be useful to allow different ops structures to be selected based on the flags that are set in addition to being able to inspect the flags within the ops functions themselves.  I have made the change in the follow-up patch series.

Thanks,
Gabriel

> 
> > If the former, will the eventdev PMD consider the flags when deciding
> whether or not to provide an ops definition in the timer_adapter_caps_get()
> call?
> >
> > >
> > > > +	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;
> > > > +}
> >
> > <... snipped ...>
diff mbox

Patch

diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index fd11079..cba8c8c 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -435,6 +435,20 @@  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,
+			  uint32_t *caps,
+			  const struct rte_event_timer_adapter_ops **ops)
+{
+	RTE_SET_USED(dev);
+	*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 +769,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..ad1a5db 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_driver.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..7708e2b
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -0,0 +1,414 @@ 
+/*-
+ *   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_driver.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 = conf_arg;
+	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;
+	}
+
+	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)
+{
+	/* default port conf values */
+	struct rte_event_port_conf port_conf = {
+		.new_event_threshold = 128,
+		.dequeue_depth = 32,
+		.enqueue_depth = 32
+	};
+
+	return rte_event_timer_adapter_create_ext(conf, default_port_conf_cb,
+						  &port_conf);
+}
+
+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->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->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)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_burst, -EINVAL);
+
+	if (!adapter->data->started)
+		return -EAGAIN;
+
+	ret = adapter->arm_burst(adapter, event_timers, nb_event_timers);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+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)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->arm_tmo_tick_burst, -EINVAL);
+
+	if (!adapter->data->started)
+		return -EAGAIN;
+
+	for (int i = 0; i < nb_event_timers; i++)
+		event_timers[i]->timeout_ticks = timeout_ticks;
+
+	ret = adapter->arm_tmo_tick_burst(adapter, event_timers, timeout_ticks,
+					  nb_event_timers);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+int
+rte_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+			     struct rte_event_timer **event_timers,
+			     uint16_t nb_event_timers)
+{
+	int ret;
+
+	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+	FUNC_PTR_OR_ERR_RET(adapter->cancel_burst, -EINVAL);
+
+	if (!adapter->data->started)
+		return -EAGAIN;
+
+	ret = adapter->cancel_burst(adapter, event_timers, nb_event_timers);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
diff --git a/lib/librte_eventdev/rte_event_timer_adapter_driver.h b/lib/librte_eventdev/rte_event_timer_adapter_driver.h
new file mode 100644
index 0000000..485fad1
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter_driver.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..719fde3 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_driver.h"
 
 /* Logging Macros */
 #define RTE_EDEV_LOG_ERR(...) \
@@ -466,6 +467,9 @@  typedef int (*eventdev_eth_rx_adapter_caps_get_t)
 
 struct rte_event_eth_rx_adapter_queue_conf *queue_conf;
 
+typedef int (*eventdev_timer_adapter_caps_get_t)(const struct rte_eventdev *dev,
+		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)
@@ -650,6 +654,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;