xref: /dpdk/lib/eventdev/rte_event_timer_adapter.c (revision 592ab76f9f0f41993bebb44da85c37750a93ece9)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017-2018 Intel Corporation.
3  * All rights reserved.
4  */
5 
6 #include <string.h>
7 #include <inttypes.h>
8 #include <stdbool.h>
9 
10 #include <rte_memzone.h>
11 #include <rte_errno.h>
12 #include <rte_malloc.h>
13 #include <rte_mempool.h>
14 #include <rte_common.h>
15 #include <rte_timer.h>
16 #include <rte_service_component.h>
17 #include <rte_telemetry.h>
18 
19 #include "event_timer_adapter_pmd.h"
20 #include "eventdev_pmd.h"
21 #include "rte_event_timer_adapter.h"
22 #include "rte_eventdev.h"
23 #include "eventdev_trace.h"
24 
25 #define DATA_MZ_NAME_MAX_LEN 64
26 #define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
27 
28 RTE_LOG_REGISTER_SUFFIX(evtim_logtype, adapter.timer, NOTICE);
29 RTE_LOG_REGISTER_SUFFIX(evtim_buffer_logtype, adapter.timer, NOTICE);
30 RTE_LOG_REGISTER_SUFFIX(evtim_svc_logtype, adapter.timer.svc, NOTICE);
31 
32 static struct rte_event_timer_adapter *adapters;
33 
34 static const struct event_timer_adapter_ops swtim_ops;
35 
36 #define EVTIM_LOG(level, logtype, ...) \
37 	rte_log(RTE_LOG_ ## level, logtype, \
38 		RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
39 			"\n", __func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__,)))
40 
41 #define EVTIM_LOG_ERR(...) EVTIM_LOG(ERR, evtim_logtype, __VA_ARGS__)
42 
43 #ifdef RTE_LIBRTE_EVENTDEV_DEBUG
44 #define EVTIM_LOG_DBG(...) \
45 	EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
46 #define EVTIM_BUF_LOG_DBG(...) \
47 	EVTIM_LOG(DEBUG, evtim_buffer_logtype, __VA_ARGS__)
48 #define EVTIM_SVC_LOG_DBG(...) \
49 	EVTIM_LOG(DEBUG, evtim_svc_logtype, __VA_ARGS__)
50 #else
51 #define EVTIM_LOG_DBG(...) (void)0
52 #define EVTIM_BUF_LOG_DBG(...) (void)0
53 #define EVTIM_SVC_LOG_DBG(...) (void)0
54 #endif
55 
56 static int
57 default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
58 		     void *conf_arg)
59 {
60 	struct rte_event_timer_adapter *adapter;
61 	struct rte_eventdev *dev;
62 	struct rte_event_dev_config dev_conf;
63 	struct rte_event_port_conf *port_conf, def_port_conf = {0};
64 	int started;
65 	uint8_t port_id;
66 	uint8_t dev_id;
67 	int ret;
68 
69 	RTE_SET_USED(event_dev_id);
70 
71 	adapter = &adapters[id];
72 	dev = &rte_eventdevs[adapter->data->event_dev_id];
73 	dev_id = dev->data->dev_id;
74 	dev_conf = dev->data->dev_conf;
75 
76 	started = dev->data->dev_started;
77 	if (started)
78 		rte_event_dev_stop(dev_id);
79 
80 	port_id = dev_conf.nb_event_ports;
81 	dev_conf.nb_event_ports += 1;
82 	ret = rte_event_dev_configure(dev_id, &dev_conf);
83 	if (ret < 0) {
84 		EVTIM_LOG_ERR("failed to configure event dev %u\n", dev_id);
85 		if (started)
86 			if (rte_event_dev_start(dev_id))
87 				return -EIO;
88 
89 		return ret;
90 	}
91 
92 	if (conf_arg != NULL)
93 		port_conf = conf_arg;
94 	else {
95 		port_conf = &def_port_conf;
96 		ret = rte_event_port_default_conf_get(dev_id, port_id,
97 						      port_conf);
98 		if (ret < 0)
99 			return ret;
100 	}
101 
102 	ret = rte_event_port_setup(dev_id, port_id, port_conf);
103 	if (ret < 0) {
104 		EVTIM_LOG_ERR("failed to setup event port %u on event dev %u\n",
105 			      port_id, dev_id);
106 		return ret;
107 	}
108 
109 	*event_port_id = port_id;
110 
111 	if (started)
112 		ret = rte_event_dev_start(dev_id);
113 
114 	return ret;
115 }
116 
117 struct rte_event_timer_adapter *
118 rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf)
119 {
120 	return rte_event_timer_adapter_create_ext(conf, default_port_conf_cb,
121 						  NULL);
122 }
123 
124 struct rte_event_timer_adapter *
125 rte_event_timer_adapter_create_ext(
126 		const struct rte_event_timer_adapter_conf *conf,
127 		rte_event_timer_adapter_port_conf_cb_t conf_cb,
128 		void *conf_arg)
129 {
130 	uint16_t adapter_id;
131 	struct rte_event_timer_adapter *adapter;
132 	const struct rte_memzone *mz;
133 	char mz_name[DATA_MZ_NAME_MAX_LEN];
134 	int n, ret;
135 	struct rte_eventdev *dev;
136 
137 	if (adapters == NULL) {
138 		adapters = rte_zmalloc("Eventdev",
139 				       sizeof(struct rte_event_timer_adapter) *
140 					       RTE_EVENT_TIMER_ADAPTER_NUM_MAX,
141 				       RTE_CACHE_LINE_SIZE);
142 		if (adapters == NULL) {
143 			rte_errno = ENOMEM;
144 			return NULL;
145 		}
146 	}
147 
148 	if (conf == NULL) {
149 		rte_errno = EINVAL;
150 		return NULL;
151 	}
152 
153 	/* Check eventdev ID */
154 	if (!rte_event_pmd_is_valid_dev(conf->event_dev_id)) {
155 		rte_errno = EINVAL;
156 		return NULL;
157 	}
158 	dev = &rte_eventdevs[conf->event_dev_id];
159 
160 	adapter_id = conf->timer_adapter_id;
161 
162 	/* Check that adapter_id is in range */
163 	if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) {
164 		rte_errno = EINVAL;
165 		return NULL;
166 	}
167 
168 	/* Check adapter ID not already allocated */
169 	adapter = &adapters[adapter_id];
170 	if (adapter->allocated) {
171 		rte_errno = EEXIST;
172 		return NULL;
173 	}
174 
175 	/* Create shared data area. */
176 	n = snprintf(mz_name, sizeof(mz_name), DATA_MZ_NAME_FORMAT, adapter_id);
177 	if (n >= (int)sizeof(mz_name)) {
178 		rte_errno = EINVAL;
179 		return NULL;
180 	}
181 	mz = rte_memzone_reserve(mz_name,
182 				 sizeof(struct rte_event_timer_adapter_data),
183 				 conf->socket_id, 0);
184 	if (mz == NULL)
185 		/* rte_errno set by rte_memzone_reserve */
186 		return NULL;
187 
188 	adapter->data = mz->addr;
189 	memset(adapter->data, 0, sizeof(struct rte_event_timer_adapter_data));
190 
191 	adapter->data->mz = mz;
192 	adapter->data->event_dev_id = conf->event_dev_id;
193 	adapter->data->id = adapter_id;
194 	adapter->data->socket_id = conf->socket_id;
195 	adapter->data->conf = *conf;  /* copy conf structure */
196 
197 	/* Query eventdev PMD for timer adapter capabilities and ops */
198 	ret = dev->dev_ops->timer_adapter_caps_get(dev,
199 						   adapter->data->conf.flags,
200 						   &adapter->data->caps,
201 						   &adapter->ops);
202 	if (ret < 0) {
203 		rte_errno = -ret;
204 		goto free_memzone;
205 	}
206 
207 	if (!(adapter->data->caps &
208 	      RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) {
209 		FUNC_PTR_OR_NULL_RET_WITH_ERRNO(conf_cb, EINVAL);
210 		ret = conf_cb(adapter->data->id, adapter->data->event_dev_id,
211 			      &adapter->data->event_port_id, conf_arg);
212 		if (ret < 0) {
213 			rte_errno = -ret;
214 			goto free_memzone;
215 		}
216 	}
217 
218 	/* If eventdev PMD did not provide ops, use default software
219 	 * implementation.
220 	 */
221 	if (adapter->ops == NULL)
222 		adapter->ops = &swtim_ops;
223 
224 	/* Allow driver to do some setup */
225 	FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, ENOTSUP);
226 	ret = adapter->ops->init(adapter);
227 	if (ret < 0) {
228 		rte_errno = -ret;
229 		goto free_memzone;
230 	}
231 
232 	/* Set fast-path function pointers */
233 	adapter->arm_burst = adapter->ops->arm_burst;
234 	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
235 	adapter->cancel_burst = adapter->ops->cancel_burst;
236 
237 	adapter->allocated = 1;
238 
239 	rte_eventdev_trace_timer_adapter_create(adapter_id, adapter, conf,
240 		conf_cb);
241 	return adapter;
242 
243 free_memzone:
244 	rte_memzone_free(adapter->data->mz);
245 	return NULL;
246 }
247 
248 int
249 rte_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
250 		struct rte_event_timer_adapter_info *adapter_info)
251 {
252 	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
253 
254 	if (adapter->ops->get_info)
255 		/* let driver set values it knows */
256 		adapter->ops->get_info(adapter, adapter_info);
257 
258 	/* Set common values */
259 	adapter_info->conf = adapter->data->conf;
260 	adapter_info->event_dev_port_id = adapter->data->event_port_id;
261 	adapter_info->caps = adapter->data->caps;
262 
263 	return 0;
264 }
265 
266 int
267 rte_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
268 {
269 	int ret;
270 
271 	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
272 	FUNC_PTR_OR_ERR_RET(adapter->ops->start, -EINVAL);
273 
274 	if (adapter->data->started) {
275 		EVTIM_LOG_ERR("event timer adapter %"PRIu8" already started",
276 			      adapter->data->id);
277 		return -EALREADY;
278 	}
279 
280 	ret = adapter->ops->start(adapter);
281 	if (ret < 0)
282 		return ret;
283 
284 	adapter->data->started = 1;
285 	rte_eventdev_trace_timer_adapter_start(adapter);
286 	return 0;
287 }
288 
289 int
290 rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
291 {
292 	int ret;
293 
294 	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
295 	FUNC_PTR_OR_ERR_RET(adapter->ops->stop, -EINVAL);
296 
297 	if (adapter->data->started == 0) {
298 		EVTIM_LOG_ERR("event timer adapter %"PRIu8" already stopped",
299 			      adapter->data->id);
300 		return 0;
301 	}
302 
303 	ret = adapter->ops->stop(adapter);
304 	if (ret < 0)
305 		return ret;
306 
307 	adapter->data->started = 0;
308 	rte_eventdev_trace_timer_adapter_stop(adapter);
309 	return 0;
310 }
311 
312 struct rte_event_timer_adapter *
313 rte_event_timer_adapter_lookup(uint16_t adapter_id)
314 {
315 	char name[DATA_MZ_NAME_MAX_LEN];
316 	const struct rte_memzone *mz;
317 	struct rte_event_timer_adapter_data *data;
318 	struct rte_event_timer_adapter *adapter;
319 	int ret;
320 	struct rte_eventdev *dev;
321 
322 	if (adapters == NULL) {
323 		adapters = rte_zmalloc("Eventdev",
324 				       sizeof(struct rte_event_timer_adapter) *
325 					       RTE_EVENT_TIMER_ADAPTER_NUM_MAX,
326 				       RTE_CACHE_LINE_SIZE);
327 		if (adapters == NULL) {
328 			rte_errno = ENOMEM;
329 			return NULL;
330 		}
331 	}
332 
333 	if (adapters[adapter_id].allocated)
334 		return &adapters[adapter_id]; /* Adapter is already loaded */
335 
336 	snprintf(name, DATA_MZ_NAME_MAX_LEN, DATA_MZ_NAME_FORMAT, adapter_id);
337 	mz = rte_memzone_lookup(name);
338 	if (mz == NULL) {
339 		rte_errno = ENOENT;
340 		return NULL;
341 	}
342 
343 	data = mz->addr;
344 
345 	adapter = &adapters[data->id];
346 	adapter->data = data;
347 
348 	dev = &rte_eventdevs[adapter->data->event_dev_id];
349 
350 	/* Query eventdev PMD for timer adapter capabilities and ops */
351 	ret = dev->dev_ops->timer_adapter_caps_get(dev,
352 						   adapter->data->conf.flags,
353 						   &adapter->data->caps,
354 						   &adapter->ops);
355 	if (ret < 0) {
356 		rte_errno = EINVAL;
357 		return NULL;
358 	}
359 
360 	/* If eventdev PMD did not provide ops, use default software
361 	 * implementation.
362 	 */
363 	if (adapter->ops == NULL)
364 		adapter->ops = &swtim_ops;
365 
366 	/* Set fast-path function pointers */
367 	adapter->arm_burst = adapter->ops->arm_burst;
368 	adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
369 	adapter->cancel_burst = adapter->ops->cancel_burst;
370 
371 	adapter->allocated = 1;
372 
373 	return adapter;
374 }
375 
376 int
377 rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter)
378 {
379 	int i, ret;
380 
381 	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
382 	FUNC_PTR_OR_ERR_RET(adapter->ops->uninit, -EINVAL);
383 
384 	if (adapter->data->started == 1) {
385 		EVTIM_LOG_ERR("event timer adapter %"PRIu8" must be stopped "
386 			      "before freeing", adapter->data->id);
387 		return -EBUSY;
388 	}
389 
390 	/* free impl priv data */
391 	ret = adapter->ops->uninit(adapter);
392 	if (ret < 0)
393 		return ret;
394 
395 	/* free shared data area */
396 	ret = rte_memzone_free(adapter->data->mz);
397 	if (ret < 0)
398 		return ret;
399 
400 	adapter->data = NULL;
401 	adapter->allocated = 0;
402 
403 	ret = 0;
404 	for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++)
405 		if (adapters[i].allocated)
406 			ret = adapters[i].allocated;
407 
408 	if (!ret) {
409 		rte_free(adapters);
410 		adapters = NULL;
411 	}
412 
413 	rte_eventdev_trace_timer_adapter_free(adapter);
414 	return 0;
415 }
416 
417 int
418 rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
419 				       uint32_t *service_id)
420 {
421 	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
422 
423 	if (adapter->data->service_inited && service_id != NULL)
424 		*service_id = adapter->data->service_id;
425 
426 	return adapter->data->service_inited ? 0 : -ESRCH;
427 }
428 
429 int
430 rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
431 				  struct rte_event_timer_adapter_stats *stats)
432 {
433 	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
434 	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_get, -EINVAL);
435 	if (stats == NULL)
436 		return -EINVAL;
437 
438 	return adapter->ops->stats_get(adapter, stats);
439 }
440 
441 int
442 rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
443 {
444 	ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
445 	FUNC_PTR_OR_ERR_RET(adapter->ops->stats_reset, -EINVAL);
446 	return adapter->ops->stats_reset(adapter);
447 }
448 
449 /*
450  * Software event timer adapter buffer helper functions
451  */
452 
453 #define NSECPERSEC 1E9
454 
455 /* Optimizations used to index into the buffer require that the buffer size
456  * be a power of 2.
457  */
458 #define EVENT_BUFFER_SZ 4096
459 #define EVENT_BUFFER_BATCHSZ 32
460 #define EVENT_BUFFER_MASK (EVENT_BUFFER_SZ - 1)
461 
462 #define EXP_TIM_BUF_SZ 128
463 
464 struct event_buffer {
465 	size_t head;
466 	size_t tail;
467 	struct rte_event events[EVENT_BUFFER_SZ];
468 } __rte_cache_aligned;
469 
470 static inline bool
471 event_buffer_full(struct event_buffer *bufp)
472 {
473 	return (bufp->head - bufp->tail) == EVENT_BUFFER_SZ;
474 }
475 
476 static inline bool
477 event_buffer_batch_ready(struct event_buffer *bufp)
478 {
479 	return (bufp->head - bufp->tail) >= EVENT_BUFFER_BATCHSZ;
480 }
481 
482 static void
483 event_buffer_init(struct event_buffer *bufp)
484 {
485 	bufp->head = bufp->tail = 0;
486 	memset(&bufp->events, 0, sizeof(struct rte_event) * EVENT_BUFFER_SZ);
487 }
488 
489 static int
490 event_buffer_add(struct event_buffer *bufp, struct rte_event *eventp)
491 {
492 	size_t head_idx;
493 	struct rte_event *buf_eventp;
494 
495 	if (event_buffer_full(bufp))
496 		return -1;
497 
498 	/* Instead of modulus, bitwise AND with mask to get head_idx. */
499 	head_idx = bufp->head & EVENT_BUFFER_MASK;
500 	buf_eventp = &bufp->events[head_idx];
501 	rte_memcpy(buf_eventp, eventp, sizeof(struct rte_event));
502 
503 	/* Wrap automatically when overflow occurs. */
504 	bufp->head++;
505 
506 	return 0;
507 }
508 
509 static void
510 event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,
511 		   uint16_t *nb_events_flushed,
512 		   uint16_t *nb_events_inv)
513 {
514 	struct rte_event *events = bufp->events;
515 	size_t head_idx, tail_idx;
516 	uint16_t n = 0;
517 
518 	/* Instead of modulus, bitwise AND with mask to get index. */
519 	head_idx = bufp->head & EVENT_BUFFER_MASK;
520 	tail_idx = bufp->tail & EVENT_BUFFER_MASK;
521 
522 	RTE_ASSERT(head_idx < EVENT_BUFFER_SZ && tail_idx < EVENT_BUFFER_SZ);
523 
524 	/* Determine the largest contiguous run we can attempt to enqueue to the
525 	 * event device.
526 	 */
527 	if (head_idx > tail_idx)
528 		n = head_idx - tail_idx;
529 	else if (head_idx < tail_idx)
530 		n = EVENT_BUFFER_SZ - tail_idx;
531 	else if (event_buffer_full(bufp))
532 		n = EVENT_BUFFER_SZ - tail_idx;
533 	else {
534 		*nb_events_flushed = 0;
535 		return;
536 	}
537 
538 	n = RTE_MIN(EVENT_BUFFER_BATCHSZ, n);
539 	*nb_events_inv = 0;
540 
541 	*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
542 						     &events[tail_idx], n);
543 	if (*nb_events_flushed != n) {
544 		if (rte_errno == EINVAL) {
545 			EVTIM_LOG_ERR("failed to enqueue invalid event - "
546 				      "dropping it");
547 			(*nb_events_inv)++;
548 		} else if (rte_errno == ENOSPC)
549 			rte_pause();
550 	}
551 
552 	if (*nb_events_flushed > 0)
553 		EVTIM_BUF_LOG_DBG("enqueued %"PRIu16" timer events to event "
554 				  "device", *nb_events_flushed);
555 
556 	bufp->tail = bufp->tail + *nb_events_flushed + *nb_events_inv;
557 }
558 
559 /*
560  * Software event timer adapter implementation
561  */
562 struct swtim {
563 	/* Identifier of service executing timer management logic. */
564 	uint32_t service_id;
565 	/* The cycle count at which the adapter should next tick */
566 	uint64_t next_tick_cycles;
567 	/* The tick resolution used by adapter instance. May have been
568 	 * adjusted from what user requested
569 	 */
570 	uint64_t timer_tick_ns;
571 	/* Maximum timeout in nanoseconds allowed by adapter instance. */
572 	uint64_t max_tmo_ns;
573 	/* Buffered timer expiry events to be enqueued to an event device. */
574 	struct event_buffer buffer;
575 	/* Statistics */
576 	struct rte_event_timer_adapter_stats stats;
577 	/* Mempool of timer objects */
578 	struct rte_mempool *tim_pool;
579 	/* Back pointer for convenience */
580 	struct rte_event_timer_adapter *adapter;
581 	/* Identifier of timer data instance */
582 	uint32_t timer_data_id;
583 	/* Track which cores have actually armed a timer */
584 	struct {
585 		uint16_t v;
586 	} __rte_cache_aligned in_use[RTE_MAX_LCORE];
587 	/* Track which cores' timer lists should be polled */
588 	unsigned int poll_lcores[RTE_MAX_LCORE];
589 	/* The number of lists that should be polled */
590 	int n_poll_lcores;
591 	/* Timers which have expired and can be returned to a mempool */
592 	struct rte_timer *expired_timers[EXP_TIM_BUF_SZ];
593 	/* The number of timers that can be returned to a mempool */
594 	size_t n_expired_timers;
595 };
596 
597 static inline struct swtim *
598 swtim_pmd_priv(const struct rte_event_timer_adapter *adapter)
599 {
600 	return adapter->data->adapter_priv;
601 }
602 
603 static void
604 swtim_callback(struct rte_timer *tim)
605 {
606 	struct rte_event_timer *evtim = tim->arg;
607 	struct rte_event_timer_adapter *adapter;
608 	unsigned int lcore = rte_lcore_id();
609 	struct swtim *sw;
610 	uint16_t nb_evs_flushed = 0;
611 	uint16_t nb_evs_invalid = 0;
612 	uint64_t opaque;
613 	int ret;
614 	int n_lcores;
615 
616 	opaque = evtim->impl_opaque[1];
617 	adapter = (struct rte_event_timer_adapter *)(uintptr_t)opaque;
618 	sw = swtim_pmd_priv(adapter);
619 
620 	ret = event_buffer_add(&sw->buffer, &evtim->ev);
621 	if (ret < 0) {
622 		/* If event buffer is full, put timer back in list with
623 		 * immediate expiry value, so that we process it again on the
624 		 * next iteration.
625 		 */
626 		ret = rte_timer_alt_reset(sw->timer_data_id, tim, 0, SINGLE,
627 					  lcore, NULL, evtim);
628 		if (ret < 0) {
629 			EVTIM_LOG_DBG("event buffer full, failed to reset "
630 				      "timer with immediate expiry value");
631 		} else {
632 			sw->stats.evtim_retry_count++;
633 			EVTIM_LOG_DBG("event buffer full, resetting rte_timer "
634 				      "with immediate expiry value");
635 		}
636 
637 		if (unlikely(sw->in_use[lcore].v == 0)) {
638 			sw->in_use[lcore].v = 1;
639 			n_lcores = __atomic_fetch_add(&sw->n_poll_lcores, 1,
640 						     __ATOMIC_RELAXED);
641 			__atomic_store_n(&sw->poll_lcores[n_lcores], lcore,
642 					__ATOMIC_RELAXED);
643 		}
644 	} else {
645 		EVTIM_BUF_LOG_DBG("buffered an event timer expiry event");
646 
647 		/* Empty the buffer here, if necessary, to free older expired
648 		 * timers only
649 		 */
650 		if (unlikely(sw->n_expired_timers == EXP_TIM_BUF_SZ)) {
651 			rte_mempool_put_bulk(sw->tim_pool,
652 					     (void **)sw->expired_timers,
653 					     sw->n_expired_timers);
654 			sw->n_expired_timers = 0;
655 		}
656 
657 		sw->expired_timers[sw->n_expired_timers++] = tim;
658 		sw->stats.evtim_exp_count++;
659 
660 		__atomic_store_n(&evtim->state, RTE_EVENT_TIMER_NOT_ARMED,
661 				__ATOMIC_RELEASE);
662 	}
663 
664 	if (event_buffer_batch_ready(&sw->buffer)) {
665 		event_buffer_flush(&sw->buffer,
666 				   adapter->data->event_dev_id,
667 				   adapter->data->event_port_id,
668 				   &nb_evs_flushed,
669 				   &nb_evs_invalid);
670 
671 		sw->stats.ev_enq_count += nb_evs_flushed;
672 		sw->stats.ev_inv_count += nb_evs_invalid;
673 	}
674 }
675 
676 static __rte_always_inline uint64_t
677 get_timeout_cycles(struct rte_event_timer *evtim,
678 		   const struct rte_event_timer_adapter *adapter)
679 {
680 	struct swtim *sw = swtim_pmd_priv(adapter);
681 	uint64_t timeout_ns = evtim->timeout_ticks * sw->timer_tick_ns;
682 	return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
683 }
684 
685 /* This function returns true if one or more (adapter) ticks have occurred since
686  * the last time it was called.
687  */
688 static inline bool
689 swtim_did_tick(struct swtim *sw)
690 {
691 	uint64_t cycles_per_adapter_tick, start_cycles;
692 	uint64_t *next_tick_cyclesp;
693 
694 	next_tick_cyclesp = &sw->next_tick_cycles;
695 	cycles_per_adapter_tick = sw->timer_tick_ns *
696 			(rte_get_timer_hz() / NSECPERSEC);
697 	start_cycles = rte_get_timer_cycles();
698 
699 	/* Note: initially, *next_tick_cyclesp == 0, so the clause below will
700 	 * execute, and set things going.
701 	 */
702 
703 	if (start_cycles >= *next_tick_cyclesp) {
704 		/* Snap the current cycle count to the preceding adapter tick
705 		 * boundary.
706 		 */
707 		start_cycles -= start_cycles % cycles_per_adapter_tick;
708 		*next_tick_cyclesp = start_cycles + cycles_per_adapter_tick;
709 
710 		return true;
711 	}
712 
713 	return false;
714 }
715 
716 /* Check that event timer timeout value is in range */
717 static __rte_always_inline int
718 check_timeout(struct rte_event_timer *evtim,
719 	      const struct rte_event_timer_adapter *adapter)
720 {
721 	uint64_t tmo_nsec;
722 	struct swtim *sw = swtim_pmd_priv(adapter);
723 
724 	tmo_nsec = evtim->timeout_ticks * sw->timer_tick_ns;
725 	if (tmo_nsec > sw->max_tmo_ns)
726 		return -1;
727 	if (tmo_nsec < sw->timer_tick_ns)
728 		return -2;
729 
730 	return 0;
731 }
732 
733 /* Check that event timer event queue sched type matches destination event queue
734  * sched type
735  */
736 static __rte_always_inline int
737 check_destination_event_queue(struct rte_event_timer *evtim,
738 			      const struct rte_event_timer_adapter *adapter)
739 {
740 	int ret;
741 	uint32_t sched_type;
742 
743 	ret = rte_event_queue_attr_get(adapter->data->event_dev_id,
744 				       evtim->ev.queue_id,
745 				       RTE_EVENT_QUEUE_ATTR_SCHEDULE_TYPE,
746 				       &sched_type);
747 
748 	if ((ret == 0 && evtim->ev.sched_type == sched_type) ||
749 	    ret == -EOVERFLOW)
750 		return 0;
751 
752 	return -1;
753 }
754 
755 static int
756 swtim_service_func(void *arg)
757 {
758 	struct rte_event_timer_adapter *adapter = arg;
759 	struct swtim *sw = swtim_pmd_priv(adapter);
760 	uint16_t nb_evs_flushed = 0;
761 	uint16_t nb_evs_invalid = 0;
762 
763 	if (swtim_did_tick(sw)) {
764 		rte_timer_alt_manage(sw->timer_data_id,
765 				     sw->poll_lcores,
766 				     sw->n_poll_lcores,
767 				     swtim_callback);
768 
769 		/* Return expired timer objects back to mempool */
770 		rte_mempool_put_bulk(sw->tim_pool, (void **)sw->expired_timers,
771 				     sw->n_expired_timers);
772 		sw->n_expired_timers = 0;
773 
774 		event_buffer_flush(&sw->buffer,
775 				   adapter->data->event_dev_id,
776 				   adapter->data->event_port_id,
777 				   &nb_evs_flushed,
778 				   &nb_evs_invalid);
779 
780 		sw->stats.ev_enq_count += nb_evs_flushed;
781 		sw->stats.ev_inv_count += nb_evs_invalid;
782 		sw->stats.adapter_tick_count++;
783 	}
784 
785 	rte_event_maintain(adapter->data->event_dev_id,
786 			   adapter->data->event_port_id, 0);
787 
788 	return 0;
789 }
790 
791 /* The adapter initialization function rounds the mempool size up to the next
792  * power of 2, so we can take the difference between that value and what the
793  * user requested, and use the space for caches.  This avoids a scenario where a
794  * user can't arm the number of timers the adapter was configured with because
795  * mempool objects have been lost to caches.
796  *
797  * nb_actual should always be a power of 2, so we can iterate over the powers
798  * of 2 to see what the largest cache size we can use is.
799  */
800 static int
801 compute_msg_mempool_cache_size(uint64_t nb_requested, uint64_t nb_actual)
802 {
803 	int i;
804 	int size;
805 	int cache_size = 0;
806 
807 	for (i = 0;; i++) {
808 		size = 1 << i;
809 
810 		if (RTE_MAX_LCORE * size < (int)(nb_actual - nb_requested) &&
811 		    size < RTE_MEMPOOL_CACHE_MAX_SIZE &&
812 		    size <= nb_actual / 1.5)
813 			cache_size = size;
814 		else
815 			break;
816 	}
817 
818 	return cache_size;
819 }
820 
821 static int
822 swtim_init(struct rte_event_timer_adapter *adapter)
823 {
824 	int i, ret;
825 	struct swtim *sw;
826 	unsigned int flags;
827 	struct rte_service_spec service;
828 
829 	/* Allocate storage for private data area */
830 #define SWTIM_NAMESIZE 32
831 	char swtim_name[SWTIM_NAMESIZE];
832 	snprintf(swtim_name, SWTIM_NAMESIZE, "swtim_%"PRIu8,
833 			adapter->data->id);
834 	sw = rte_zmalloc_socket(swtim_name, sizeof(*sw), RTE_CACHE_LINE_SIZE,
835 			adapter->data->socket_id);
836 	if (sw == NULL) {
837 		EVTIM_LOG_ERR("failed to allocate space for private data");
838 		rte_errno = ENOMEM;
839 		return -1;
840 	}
841 
842 	/* Connect storage to adapter instance */
843 	adapter->data->adapter_priv = sw;
844 	sw->adapter = adapter;
845 
846 	sw->timer_tick_ns = adapter->data->conf.timer_tick_ns;
847 	sw->max_tmo_ns = adapter->data->conf.max_tmo_ns;
848 
849 	/* Create a timer pool */
850 	char pool_name[SWTIM_NAMESIZE];
851 	snprintf(pool_name, SWTIM_NAMESIZE, "swtim_pool_%"PRIu8,
852 		 adapter->data->id);
853 	/* Optimal mempool size is a power of 2 minus one */
854 	uint64_t nb_timers = rte_align64pow2(adapter->data->conf.nb_timers);
855 	int pool_size = nb_timers - 1;
856 	int cache_size = compute_msg_mempool_cache_size(
857 				adapter->data->conf.nb_timers, nb_timers);
858 	flags = 0; /* pool is multi-producer, multi-consumer */
859 	sw->tim_pool = rte_mempool_create(pool_name, pool_size,
860 			sizeof(struct rte_timer), cache_size, 0, NULL, NULL,
861 			NULL, NULL, adapter->data->socket_id, flags);
862 	if (sw->tim_pool == NULL) {
863 		EVTIM_LOG_ERR("failed to create timer object mempool");
864 		rte_errno = ENOMEM;
865 		goto free_alloc;
866 	}
867 
868 	/* Initialize the variables that track in-use timer lists */
869 	for (i = 0; i < RTE_MAX_LCORE; i++)
870 		sw->in_use[i].v = 0;
871 
872 	/* Initialize the timer subsystem and allocate timer data instance */
873 	ret = rte_timer_subsystem_init();
874 	if (ret < 0) {
875 		if (ret != -EALREADY) {
876 			EVTIM_LOG_ERR("failed to initialize timer subsystem");
877 			rte_errno = -ret;
878 			goto free_mempool;
879 		}
880 	}
881 
882 	ret = rte_timer_data_alloc(&sw->timer_data_id);
883 	if (ret < 0) {
884 		EVTIM_LOG_ERR("failed to allocate timer data instance");
885 		rte_errno = -ret;
886 		goto free_mempool;
887 	}
888 
889 	/* Initialize timer event buffer */
890 	event_buffer_init(&sw->buffer);
891 
892 	sw->adapter = adapter;
893 
894 	/* Register a service component to run adapter logic */
895 	memset(&service, 0, sizeof(service));
896 	snprintf(service.name, RTE_SERVICE_NAME_MAX,
897 		 "swtim_svc_%"PRIu8, adapter->data->id);
898 	service.socket_id = adapter->data->socket_id;
899 	service.callback = swtim_service_func;
900 	service.callback_userdata = adapter;
901 	service.capabilities &= ~(RTE_SERVICE_CAP_MT_SAFE);
902 	ret = rte_service_component_register(&service, &sw->service_id);
903 	if (ret < 0) {
904 		EVTIM_LOG_ERR("failed to register service %s with id %"PRIu32
905 			      ": err = %d", service.name, sw->service_id,
906 			      ret);
907 
908 		rte_errno = ENOSPC;
909 		goto free_mempool;
910 	}
911 
912 	EVTIM_LOG_DBG("registered service %s with id %"PRIu32, service.name,
913 		      sw->service_id);
914 
915 	adapter->data->service_id = sw->service_id;
916 	adapter->data->service_inited = 1;
917 
918 	return 0;
919 free_mempool:
920 	rte_mempool_free(sw->tim_pool);
921 free_alloc:
922 	rte_free(sw);
923 	return -1;
924 }
925 
926 static void
927 swtim_free_tim(struct rte_timer *tim, void *arg)
928 {
929 	struct swtim *sw = arg;
930 
931 	rte_mempool_put(sw->tim_pool, tim);
932 }
933 
934 /* Traverse the list of outstanding timers and put them back in the mempool
935  * before freeing the adapter to avoid leaking the memory.
936  */
937 static int
938 swtim_uninit(struct rte_event_timer_adapter *adapter)
939 {
940 	int ret;
941 	struct swtim *sw = swtim_pmd_priv(adapter);
942 
943 	/* Free outstanding timers */
944 	rte_timer_stop_all(sw->timer_data_id,
945 			   sw->poll_lcores,
946 			   sw->n_poll_lcores,
947 			   swtim_free_tim,
948 			   sw);
949 
950 	ret = rte_service_component_unregister(sw->service_id);
951 	if (ret < 0) {
952 		EVTIM_LOG_ERR("failed to unregister service component");
953 		return ret;
954 	}
955 
956 	rte_mempool_free(sw->tim_pool);
957 	rte_free(sw);
958 	adapter->data->adapter_priv = NULL;
959 
960 	return 0;
961 }
962 
963 static inline int32_t
964 get_mapped_count_for_service(uint32_t service_id)
965 {
966 	int32_t core_count, i, mapped_count = 0;
967 	uint32_t lcore_arr[RTE_MAX_LCORE];
968 
969 	core_count = rte_service_lcore_list(lcore_arr, RTE_MAX_LCORE);
970 
971 	for (i = 0; i < core_count; i++)
972 		if (rte_service_map_lcore_get(service_id, lcore_arr[i]) == 1)
973 			mapped_count++;
974 
975 	return mapped_count;
976 }
977 
978 static int
979 swtim_start(const struct rte_event_timer_adapter *adapter)
980 {
981 	int mapped_count;
982 	struct swtim *sw = swtim_pmd_priv(adapter);
983 
984 	/* Mapping the service to more than one service core can introduce
985 	 * delays while one thread is waiting to acquire a lock, so only allow
986 	 * one core to be mapped to the service.
987 	 *
988 	 * Note: the service could be modified such that it spreads cores to
989 	 * poll over multiple service instances.
990 	 */
991 	mapped_count = get_mapped_count_for_service(sw->service_id);
992 
993 	if (mapped_count != 1)
994 		return mapped_count < 1 ? -ENOENT : -ENOTSUP;
995 
996 	return rte_service_component_runstate_set(sw->service_id, 1);
997 }
998 
999 static int
1000 swtim_stop(const struct rte_event_timer_adapter *adapter)
1001 {
1002 	int ret;
1003 	struct swtim *sw = swtim_pmd_priv(adapter);
1004 
1005 	ret = rte_service_component_runstate_set(sw->service_id, 0);
1006 	if (ret < 0)
1007 		return ret;
1008 
1009 	/* Wait for the service to complete its final iteration */
1010 	while (rte_service_may_be_active(sw->service_id))
1011 		rte_pause();
1012 
1013 	return 0;
1014 }
1015 
1016 static void
1017 swtim_get_info(const struct rte_event_timer_adapter *adapter,
1018 		struct rte_event_timer_adapter_info *adapter_info)
1019 {
1020 	struct swtim *sw = swtim_pmd_priv(adapter);
1021 	adapter_info->min_resolution_ns = sw->timer_tick_ns;
1022 	adapter_info->max_tmo_ns = sw->max_tmo_ns;
1023 }
1024 
1025 static int
1026 swtim_stats_get(const struct rte_event_timer_adapter *adapter,
1027 		struct rte_event_timer_adapter_stats *stats)
1028 {
1029 	struct swtim *sw = swtim_pmd_priv(adapter);
1030 	*stats = sw->stats; /* structure copy */
1031 	return 0;
1032 }
1033 
1034 static int
1035 swtim_stats_reset(const struct rte_event_timer_adapter *adapter)
1036 {
1037 	struct swtim *sw = swtim_pmd_priv(adapter);
1038 	memset(&sw->stats, 0, sizeof(sw->stats));
1039 	return 0;
1040 }
1041 
1042 static uint16_t
1043 __swtim_arm_burst(const struct rte_event_timer_adapter *adapter,
1044 		struct rte_event_timer **evtims,
1045 		uint16_t nb_evtims)
1046 {
1047 	int i, ret;
1048 	struct swtim *sw = swtim_pmd_priv(adapter);
1049 	uint32_t lcore_id = rte_lcore_id();
1050 	struct rte_timer *tim, *tims[nb_evtims];
1051 	uint64_t cycles;
1052 	int n_lcores;
1053 	/* Timer list for this lcore is not in use. */
1054 	uint16_t exp_state = 0;
1055 	enum rte_event_timer_state n_state;
1056 
1057 #ifdef RTE_LIBRTE_EVENTDEV_DEBUG
1058 	/* Check that the service is running. */
1059 	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
1060 		rte_errno = EINVAL;
1061 		return 0;
1062 	}
1063 #endif
1064 
1065 	/* Adjust lcore_id if non-EAL thread. Arbitrarily pick the timer list of
1066 	 * the highest lcore to insert such timers into
1067 	 */
1068 	if (lcore_id == LCORE_ID_ANY)
1069 		lcore_id = RTE_MAX_LCORE - 1;
1070 
1071 	/* If this is the first time we're arming an event timer on this lcore,
1072 	 * mark this lcore as "in use"; this will cause the service
1073 	 * function to process the timer list that corresponds to this lcore.
1074 	 * The atomic compare-and-swap operation can prevent the race condition
1075 	 * on in_use flag between multiple non-EAL threads.
1076 	 */
1077 	if (unlikely(__atomic_compare_exchange_n(&sw->in_use[lcore_id].v,
1078 			&exp_state, 1, 0,
1079 			__ATOMIC_RELAXED, __ATOMIC_RELAXED))) {
1080 		EVTIM_LOG_DBG("Adding lcore id = %u to list of lcores to poll",
1081 			      lcore_id);
1082 		n_lcores = __atomic_fetch_add(&sw->n_poll_lcores, 1,
1083 					     __ATOMIC_RELAXED);
1084 		__atomic_store_n(&sw->poll_lcores[n_lcores], lcore_id,
1085 				__ATOMIC_RELAXED);
1086 	}
1087 
1088 	ret = rte_mempool_get_bulk(sw->tim_pool, (void **)tims,
1089 				   nb_evtims);
1090 	if (ret < 0) {
1091 		rte_errno = ENOSPC;
1092 		return 0;
1093 	}
1094 
1095 	for (i = 0; i < nb_evtims; i++) {
1096 		n_state = __atomic_load_n(&evtims[i]->state, __ATOMIC_ACQUIRE);
1097 		if (n_state == RTE_EVENT_TIMER_ARMED) {
1098 			rte_errno = EALREADY;
1099 			break;
1100 		} else if (!(n_state == RTE_EVENT_TIMER_NOT_ARMED ||
1101 			     n_state == RTE_EVENT_TIMER_CANCELED)) {
1102 			rte_errno = EINVAL;
1103 			break;
1104 		}
1105 
1106 		ret = check_timeout(evtims[i], adapter);
1107 		if (unlikely(ret == -1)) {
1108 			__atomic_store_n(&evtims[i]->state,
1109 					RTE_EVENT_TIMER_ERROR_TOOLATE,
1110 					__ATOMIC_RELAXED);
1111 			rte_errno = EINVAL;
1112 			break;
1113 		} else if (unlikely(ret == -2)) {
1114 			__atomic_store_n(&evtims[i]->state,
1115 					RTE_EVENT_TIMER_ERROR_TOOEARLY,
1116 					__ATOMIC_RELAXED);
1117 			rte_errno = EINVAL;
1118 			break;
1119 		}
1120 
1121 		if (unlikely(check_destination_event_queue(evtims[i],
1122 							   adapter) < 0)) {
1123 			__atomic_store_n(&evtims[i]->state,
1124 					RTE_EVENT_TIMER_ERROR,
1125 					__ATOMIC_RELAXED);
1126 			rte_errno = EINVAL;
1127 			break;
1128 		}
1129 
1130 		tim = tims[i];
1131 		rte_timer_init(tim);
1132 
1133 		evtims[i]->impl_opaque[0] = (uintptr_t)tim;
1134 		evtims[i]->impl_opaque[1] = (uintptr_t)adapter;
1135 
1136 		cycles = get_timeout_cycles(evtims[i], adapter);
1137 		ret = rte_timer_alt_reset(sw->timer_data_id, tim, cycles,
1138 					  SINGLE, lcore_id, NULL, evtims[i]);
1139 		if (ret < 0) {
1140 			/* tim was in RUNNING or CONFIG state */
1141 			__atomic_store_n(&evtims[i]->state,
1142 					RTE_EVENT_TIMER_ERROR,
1143 					__ATOMIC_RELEASE);
1144 			break;
1145 		}
1146 
1147 		EVTIM_LOG_DBG("armed an event timer");
1148 		/* RELEASE ordering guarantees the adapter specific value
1149 		 * changes observed before the update of state.
1150 		 */
1151 		__atomic_store_n(&evtims[i]->state, RTE_EVENT_TIMER_ARMED,
1152 				__ATOMIC_RELEASE);
1153 	}
1154 
1155 	if (i < nb_evtims)
1156 		rte_mempool_put_bulk(sw->tim_pool,
1157 				     (void **)&tims[i], nb_evtims - i);
1158 
1159 	return i;
1160 }
1161 
1162 static uint16_t
1163 swtim_arm_burst(const struct rte_event_timer_adapter *adapter,
1164 		struct rte_event_timer **evtims,
1165 		uint16_t nb_evtims)
1166 {
1167 	return __swtim_arm_burst(adapter, evtims, nb_evtims);
1168 }
1169 
1170 static uint16_t
1171 swtim_cancel_burst(const struct rte_event_timer_adapter *adapter,
1172 		   struct rte_event_timer **evtims,
1173 		   uint16_t nb_evtims)
1174 {
1175 	int i, ret;
1176 	struct rte_timer *timp;
1177 	uint64_t opaque;
1178 	struct swtim *sw = swtim_pmd_priv(adapter);
1179 	enum rte_event_timer_state n_state;
1180 
1181 #ifdef RTE_LIBRTE_EVENTDEV_DEBUG
1182 	/* Check that the service is running. */
1183 	if (rte_service_runstate_get(adapter->data->service_id) != 1) {
1184 		rte_errno = EINVAL;
1185 		return 0;
1186 	}
1187 #endif
1188 
1189 	for (i = 0; i < nb_evtims; i++) {
1190 		/* Don't modify the event timer state in these cases */
1191 		/* ACQUIRE ordering guarantees the access of implementation
1192 		 * specific opaque data under the correct state.
1193 		 */
1194 		n_state = __atomic_load_n(&evtims[i]->state, __ATOMIC_ACQUIRE);
1195 		if (n_state == RTE_EVENT_TIMER_CANCELED) {
1196 			rte_errno = EALREADY;
1197 			break;
1198 		} else if (n_state != RTE_EVENT_TIMER_ARMED) {
1199 			rte_errno = EINVAL;
1200 			break;
1201 		}
1202 
1203 		opaque = evtims[i]->impl_opaque[0];
1204 		timp = (struct rte_timer *)(uintptr_t)opaque;
1205 		RTE_ASSERT(timp != NULL);
1206 
1207 		ret = rte_timer_alt_stop(sw->timer_data_id, timp);
1208 		if (ret < 0) {
1209 			/* Timer is running or being configured */
1210 			rte_errno = EAGAIN;
1211 			break;
1212 		}
1213 
1214 		rte_mempool_put(sw->tim_pool, (void **)timp);
1215 
1216 		/* The RELEASE ordering here pairs with atomic ordering
1217 		 * to make sure the state update data observed between
1218 		 * threads.
1219 		 */
1220 		__atomic_store_n(&evtims[i]->state, RTE_EVENT_TIMER_CANCELED,
1221 				__ATOMIC_RELEASE);
1222 	}
1223 
1224 	return i;
1225 }
1226 
1227 static uint16_t
1228 swtim_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter,
1229 			 struct rte_event_timer **evtims,
1230 			 uint64_t timeout_ticks,
1231 			 uint16_t nb_evtims)
1232 {
1233 	int i;
1234 
1235 	for (i = 0; i < nb_evtims; i++)
1236 		evtims[i]->timeout_ticks = timeout_ticks;
1237 
1238 	return __swtim_arm_burst(adapter, evtims, nb_evtims);
1239 }
1240 
1241 static const struct event_timer_adapter_ops swtim_ops = {
1242 	.init = swtim_init,
1243 	.uninit = swtim_uninit,
1244 	.start = swtim_start,
1245 	.stop = swtim_stop,
1246 	.get_info = swtim_get_info,
1247 	.stats_get = swtim_stats_get,
1248 	.stats_reset = swtim_stats_reset,
1249 	.arm_burst = swtim_arm_burst,
1250 	.arm_tmo_tick_burst = swtim_arm_tmo_tick_burst,
1251 	.cancel_burst = swtim_cancel_burst,
1252 };
1253 
1254 static int
1255 handle_ta_info(const char *cmd __rte_unused, const char *params,
1256 		struct rte_tel_data *d)
1257 {
1258 	struct rte_event_timer_adapter_info adapter_info;
1259 	struct rte_event_timer_adapter *adapter;
1260 	uint16_t adapter_id;
1261 	int ret;
1262 
1263 	if (params == NULL || strlen(params) == 0 || !isdigit(*params))
1264 		return -1;
1265 
1266 	adapter_id = atoi(params);
1267 
1268 	if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) {
1269 		EVTIM_LOG_ERR("Invalid timer adapter id %u", adapter_id);
1270 		return -EINVAL;
1271 	}
1272 
1273 	adapter = &adapters[adapter_id];
1274 
1275 	ret = rte_event_timer_adapter_get_info(adapter, &adapter_info);
1276 	if (ret < 0) {
1277 		EVTIM_LOG_ERR("Failed to get info for timer adapter id %u", adapter_id);
1278 		return ret;
1279 	}
1280 
1281 	rte_tel_data_start_dict(d);
1282 	rte_tel_data_add_dict_u64(d, "timer_adapter_id", adapter_id);
1283 	rte_tel_data_add_dict_u64(d, "min_resolution_ns", adapter_info.min_resolution_ns);
1284 	rte_tel_data_add_dict_u64(d, "max_tmo_ns", adapter_info.max_tmo_ns);
1285 	rte_tel_data_add_dict_u64(d, "event_dev_id", adapter_info.conf.event_dev_id);
1286 	rte_tel_data_add_dict_u64(d, "socket_id", adapter_info.conf.socket_id);
1287 	rte_tel_data_add_dict_u64(d, "clk_src", adapter_info.conf.clk_src);
1288 	rte_tel_data_add_dict_u64(d, "timer_tick_ns", adapter_info.conf.timer_tick_ns);
1289 	rte_tel_data_add_dict_u64(d, "nb_timers", adapter_info.conf.nb_timers);
1290 	rte_tel_data_add_dict_u64(d, "flags", adapter_info.conf.flags);
1291 
1292 	return 0;
1293 }
1294 
1295 static int
1296 handle_ta_stats(const char *cmd __rte_unused, const char *params,
1297 		struct rte_tel_data *d)
1298 {
1299 	struct rte_event_timer_adapter_stats stats;
1300 	struct rte_event_timer_adapter *adapter;
1301 	uint16_t adapter_id;
1302 	int ret;
1303 
1304 	if (params == NULL || strlen(params) == 0 || !isdigit(*params))
1305 		return -1;
1306 
1307 	adapter_id = atoi(params);
1308 
1309 	if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) {
1310 		EVTIM_LOG_ERR("Invalid timer adapter id %u", adapter_id);
1311 		return -EINVAL;
1312 	}
1313 
1314 	adapter = &adapters[adapter_id];
1315 
1316 	ret = rte_event_timer_adapter_stats_get(adapter, &stats);
1317 	if (ret < 0) {
1318 		EVTIM_LOG_ERR("Failed to get stats for timer adapter id %u", adapter_id);
1319 		return ret;
1320 	}
1321 
1322 	rte_tel_data_start_dict(d);
1323 	rte_tel_data_add_dict_u64(d, "timer_adapter_id", adapter_id);
1324 	rte_tel_data_add_dict_u64(d, "evtim_exp_count", stats.evtim_exp_count);
1325 	rte_tel_data_add_dict_u64(d, "ev_enq_count", stats.ev_enq_count);
1326 	rte_tel_data_add_dict_u64(d, "ev_inv_count", stats.ev_inv_count);
1327 	rte_tel_data_add_dict_u64(d, "evtim_retry_count", stats.evtim_retry_count);
1328 	rte_tel_data_add_dict_u64(d, "adapter_tick_count", stats.adapter_tick_count);
1329 
1330 	return 0;
1331 }
1332 
1333 RTE_INIT(ta_init_telemetry)
1334 {
1335 	rte_telemetry_register_cmd("/eventdev/ta_info",
1336 		handle_ta_info,
1337 		"Returns Timer adapter info. Parameter: Timer adapter id");
1338 
1339 	rte_telemetry_register_cmd("/eventdev/ta_stats",
1340 		handle_ta_stats,
1341 		"Returns Timer adapter stats. Parameter: Timer adapter id");
1342 }
1343