EM-ODP 4.4.0
Event Machine on ODP
Loading...
Searching...
No Matches
event_machine_timer.c
1/*
2 * Copyright (c) 2016-2026, Nokia Solutions and Networks
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * ---------------------------------------------------------------------
31 * Some notes about the implementation:
32 *
33 * EM Timer API is close to ODP timer, but there are issues
34 * making this code a bit more complex than it could be:
35 *
36 * 1) there is no generic periodic timer in ODP
37 * 2) unless using the pre-defined timeout event there is no way to access
38 * all necessary information runtime to implement a periodic timer
39 *
40 * Point 2 is solved by creating a timeout pool. When user allocates
41 * EM timeout, a new minimum size buffer is allocated to store all the needed
42 * information. Timer handle is a pointer to such buffer so all data is
43 * available via the handle (ack() is the most problematic case). This does
44 * create performance penalty, but so far it looks like the penalty is not
45 * too large and does simplify the code otherwise. Also timeouts could be
46 * pre-allocated as the API separates creation and arming.
47 * Most of the synchronization is handled by ODP timer, a ticketlock is used
48 * for high level management API.
49 *
50 */
51#ifndef _GNU_SOURCE
52#define _GNU_SOURCE
53#endif
54
55#ifdef HAVE_CONFIG_H
56#include "config.h"
57#endif
58
59#include <stdbool.h>
60#include <stddef.h>
61#include <stdint.h>
62#include <stdio.h>
63#include <string.h>
64
65#include <odp_api.h>
66
67#include <event_machine.h>
69
70#include "em_chaining.h"
71#include "em_error.h"
72#include "em_event.h"
73#include "em_event_inline.h"
74#include "em_event_state.h"
75#include "em_event_types.h"
76#include "em_libconfig.h"
77#include "em_mem.h"
78#include "em_queue.h"
79#include "em_queue_inline.h"
80#include "em_queue_types.h"
81#include "em_timer.h"
82#include "em_timer_types.h"
83
84/* timer handle = index + 1 (UNDEF 0) */
85#define TMR_I2H(x) ((em_timer_t)(uintptr_t)((x) + 1))
86#define TMR_H2I(x) ((int)((uintptr_t)(x) - 1))
87
88/*
89 * em_fract_u64_t is cast to odp_fract_u64_t * when passing freq arrays to ODP.
90 * Verify layout compatibility so the cast stays safe if either type changes.
91 */
92ODP_STATIC_ASSERT(sizeof(em_fract_u64_t) == sizeof(odp_fract_u64_t),
93 "em_fract_u64_t size must match odp_fract_u64_t");
94ODP_STATIC_ASSERT(offsetof(em_fract_u64_t, integer) ==
95 offsetof(odp_fract_u64_t, integer),
96 "em_fract_u64_t.integer offset mismatch");
97ODP_STATIC_ASSERT(offsetof(em_fract_u64_t, numer) ==
98 offsetof(odp_fract_u64_t, numer),
99 "em_fract_u64_t.numer offset mismatch");
100ODP_STATIC_ASSERT(offsetof(em_fract_u64_t, denom) ==
101 offsetof(odp_fract_u64_t, denom),
102 "em_fract_u64_t.denom offset mismatch");
103
104static inline em_status_t timer_rv_odp2em(int odpret)
105{
106 switch (odpret) {
107 case ODP_TIMER_SUCCESS:
108 return EM_OK;
109 case ODP_TIMER_TOO_NEAR:
110 return EM_ERR_TOONEAR;
111 case ODP_TIMER_TOO_FAR:
112 return EM_ERR_TOOFAR;
113#if !PRE_1_50_ODP_TIMER_API
114 case ODP_TIMER_BUSY:
115 return EM_ERR_BUSY;
116#endif
117 default:
118 break;
119 }
120
121 return EM_ERR_LIB_FAILED;
122}
123
124static inline int is_queue_valid_type(em_timer_t tmr, const queue_elem_t *q_elem)
125{
126 unsigned int tmridx = (unsigned int)TMR_H2I(tmr);
127
128 /* implementation specific */
129 if (em_shm->timers.timer[tmridx].plain_q_ok &&
131 return 1;
132
133 /* EM assumes scheduled always supported */
134 return (q_elem->type == EM_QUEUE_TYPE_ATOMIC ||
135 q_elem->type == EM_QUEUE_TYPE_PARALLEL ||
136 q_elem->type == EM_QUEUE_TYPE_ORDERED) ? 1 : 0;
137
138 /* LOCAL or OUTPUT queues not supported */
139}
140
141static inline bool is_event_type_valid(em_event_type_t evtype_major)
142{
143 if (likely(evtype_major == EM_EVENT_TYPE_PACKET ||
144 evtype_major == EM_EVENT_TYPE_SW ||
145 evtype_major == EM_EVENT_TYPE_TIMER))
146 return true;
147
148 /* limitations mainly set by odp spec, e.g. no vectors */
149 return false;
150}
151
152/* Helper for em_tmo_type() */
153static inline bool can_have_tmo_type(em_event_type_t evtype_major)
154{
155 if (likely(evtype_major == EM_EVENT_TYPE_PACKET ||
156 evtype_major == EM_EVENT_TYPE_SW ||
157 evtype_major == EM_EVENT_TYPE_TIMER ||
158 evtype_major == EM_EVENT_TYPE_TIMER_IND))
159 return true;
160
161 return false;
162}
163
164static inline int is_timer_valid(em_timer_t tmr)
165{
166 unsigned int i;
167 const timer_storage_t *const tmrs = &em_shm->timers;
168
169 if (unlikely(tmr == EM_TIMER_UNDEF))
170 return 0;
171
172 i = (unsigned int)TMR_H2I(tmr);
173 if (unlikely(i >= EM_ODP_MAX_TIMERS))
174 return 0;
175
176 if (unlikely(tmrs->timer[i].odp_tmr_pool == ODP_TIMER_POOL_INVALID ||
177 tmrs->timer[i].tmo_pool == ODP_POOL_INVALID))
178 return 0;
179 return 1;
180}
181
182static inline em_status_t ack_ring_timeout_event(em_tmo_t tmo,
183 em_event_t ev,
184 em_tmo_state_t tmo_state,
185 event_hdr_t *ev_hdr,
186 odp_event_t odp_ev)
187{
188 (void)ev;
189 (void)tmo_state;
190
191 if (EM_CHECK_LEVEL > 0 && unlikely(ev_hdr->event_type != EM_EVENT_TYPE_TIMER_IND))
192 return INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_RING_ACK,
193 "Invalid event type:%u, expected timer-ring:%u",
195
196 if (EM_CHECK_LEVEL > 0 && unlikely(tmo != ev_hdr->tmo))
197 return INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_RING_ACK,
198 "Wrong event returned? tmo %p->%p", tmo, ev_hdr->tmo);
199
200 int ret = odp_timer_periodic_ack(tmo->odp_timer, odp_ev);
201
202 if (unlikely(ret < 0)) /* failure */
203 return INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_TMO_RING_ACK,
204 "Tmo ACK: ring timer odp ack fail, rv %d", ret);
205
206#if PRE_1_50_ODP_TIMER_API
207 if (unlikely(ret == 2)) { /* cancelled, no more events coming */
208 ev_hdr->flags.tmo_type = EM_TMO_TYPE_NONE; /* allows em_free */
209 ev_hdr->tmo = EM_TMO_UNDEF;
210 atomic_thread_fence(memory_order_release);
211 TMR_DBG_PRINT("last periodic event, deleted %p\n", odp_ev);
212 /* Event must be freed internally */
213 em_free(ev);
214 return EM_ERR_CANCELED;
215 }
216
217 /* ret = 1 would mean timer is cancelled, but more coming still.
218 * return ok to make ring and normal periodic behave the same
219 * e.g. CANCELED means tmo can now be deleted
220 */
221#else
222 /*
223 * Since ODP API >= 1.50: ret == 1 means cancelled, last event (no more coming).
224 * Unlike old API where ret == 1 meant "cancelled, more coming" and
225 * ret == 2 meant "cancelled, last event".
226 */
227 if (unlikely(ret == 1)) { /* cancelled, last event - no more coming */
228 /*
229 * Don't clear tmo_type: ODP manages the event internally,
230 * it must not be freed by the application.
231 * EM_ERR_CANCELED tells the user the tmo can now be deleted.
232 */
233 TMR_DBG_PRINT("last periodic event %p\n", odp_ev);
234 return EM_ERR_CANCELED;
235 }
236#endif
237
238 return EM_OK;
239}
240
241static void cleanup_timer_create_fail(event_timer_t *timer)
242{
243 if (timer->tmo_pool != ODP_POOL_INVALID &&
244 timer->tmo_pool != em_shm->timers.shared_tmo_pool) /* don't kill shared pool */
245 odp_pool_destroy(timer->tmo_pool);
246 if (timer->odp_tmr_pool != ODP_TIMER_POOL_INVALID)
247 odp_timer_pool_destroy(timer->odp_tmr_pool);
248 timer->tmo_pool = ODP_POOL_INVALID;
249 timer->odp_tmr_pool = ODP_TIMER_POOL_INVALID;
250 TMR_DBG_PRINT("cleaned up failed timer create\n");
251}
252
253static odp_pool_t create_tmo_handle_pool(uint32_t num_buf, uint32_t cache,
254 const event_timer_t *tmr)
255{
256 odp_pool_param_t odp_pool_param;
257 odp_pool_t pool;
258 char tmo_pool_name[ODP_POOL_NAME_LEN];
259
260 odp_pool_param_init(&odp_pool_param);
261 odp_pool_param.type = ODP_POOL_BUFFER;
262 odp_pool_param.buf.size = sizeof(em_timer_timeout_t);
263 odp_pool_param.buf.align = ODP_CACHE_LINE_SIZE;
264 odp_pool_param.buf.cache_size = cache;
265 odp_pool_param.stats.all = 0;
266 TMR_DBG_PRINT("tmo handle pool cache %d\n", cache);
267
268 uint32_t num = num_buf;
269
270 if (cache > 0) {
271 /*
272 * Local pool caching may cause an out of bufs situation on
273 * a core. Adjust the number of bufs by taking this into account.
274 */
275 const uint32_t max_cores = em_shm->conf.core_count; /* <= EM_MAX_CORES */
276
277 num += (max_cores - 1) * cache;
278 }
279
280 if (num_buf != num) {
281 TMR_DBG_PRINT("Adjusted pool size %d->%d due to local caching (%d)\n",
282 num_buf, num, odp_pool_param.buf.cache_size);
283 }
284 odp_pool_param.buf.num = num;
285 snprintf(tmo_pool_name, ODP_POOL_NAME_LEN, "Tmo-pool-%d", tmr->idx);
286 pool = odp_pool_create(tmo_pool_name, &odp_pool_param);
287 if (pool != ODP_POOL_INVALID) {
288 TMR_DBG_PRINT("Created ODP-pool: %s for %d timeouts\n",
289 tmo_pool_name, odp_pool_param.buf.num);
290 }
291 return pool;
292}
293
294#if !PRE_1_50_ODP_TIMER_API
295/**
296 * Callback for ODP to initialize the user area (event_hdr_t) of timeout events
297 * allocated internally by odp_timer_periodic_alloc().
298 */
299static void ring_tmo_uarea_init(void *uarea, uint32_t size, void *args,
300 uint32_t index, uint32_t max_num)
301{
302 (void)size;
303 (void)index;
304 (void)max_num;
305
306 em_tmo_t tmo = (em_tmo_t)args;
307 event_hdr_t *ev_hdr = (event_hdr_t *)uarea;
308
309 ev_hdr->flags.all = 0;
311 ev_hdr->tmo = tmo;
313 ev_hdr->event_size = 0;
314 ev_hdr->egrp = EM_EVENT_GROUP_UNDEF;
315 ev_hdr->user_area.all = 0;
316 ev_hdr->user_area.isinit = 1;
317}
318#endif
319
320#if PRE_1_50_ODP_TIMER_API
321static inline odp_event_t alloc_odp_timeout(em_tmo_t tmo)
322{
323 odp_timeout_t odp_tmo = odp_timeout_alloc(tmo->ring_tmo_pool);
324
325 if (unlikely(odp_tmo == ODP_TIMEOUT_INVALID))
326 return ODP_EVENT_INVALID;
327
328 /* init EM event header */
329 event_hdr_t *const ev_hdr = odp_timeout_user_area(odp_tmo);
330 odp_event_t odp_event = odp_timeout_to_event(odp_tmo);
331 em_event_t event = event_odp2em(odp_event);
332
333 if (unlikely(!ev_hdr)) {
334 odp_timeout_free(odp_tmo);
335 return ODP_EVENT_INVALID;
336 }
337
338 if (esv_enabled())
339 event = evstate_alloc_tmo(event, ev_hdr);
340 ev_hdr->flags.all = 0;
342 ev_hdr->tmo = tmo;
344 ev_hdr->event_size = 0;
345 ev_hdr->egrp = EM_EVENT_GROUP_UNDEF;
346 ev_hdr->user_area.all = 0;
347 ev_hdr->user_area.isinit = 1;
348
349 return odp_event;
350}
351
352static inline void free_odp_timeout(odp_event_t odp_event)
353{
354 if (esv_enabled()) {
355 em_event_t event = event_odp2em(odp_event);
356 event_hdr_t *const ev_hdr = event_to_hdr(event);
357
358 event = ev_hdr->event;
359 evstate_free(event, ev_hdr, EVSTATE__TMO_DELETE);
360 }
361
362 odp_event_free(odp_event);
363}
364#endif
365
366static inline em_status_t handle_ack_noskip(em_event_t next_tmo_ev,
367 event_hdr_t *ev_hdr,
368 em_queue_t queue)
369{
370 if (esv_enabled())
371 evstate_usr2em_revert(next_tmo_ev, ev_hdr, EVSTATE__TMO_ACK__NOSKIP);
372
373 em_status_t err = em_send(next_tmo_ev, queue);
374
375 if (unlikely(err != EM_OK)) {
376 err = INTERNAL_ERROR(err, EM_ESCOPE_TMO_ACK, "Tmo ACK: noskip em_send fail");
378 ev_hdr->tmo = EM_TMO_UNDEF;
379 }
380
381 return err; /* EM_OK or send-failure */
382}
383
384static inline void handle_ack_skip(em_tmo_t tmo)
385{
386 uint64_t odpt = odp_timer_current_tick(tmo->odp_timer_pool);
387 uint64_t skips;
388
389 if (odpt > tmo->last_tick) /* late, over next period */
390 skips = ((odpt - tmo->last_tick) / tmo->period) + 1;
391 else
392 skips = 1; /* not yet over next period, but late for setting */
393
394 tmo->last_tick += skips * tmo->period;
395 TMR_DBG_PRINT("%lu skips * %lu ticks => new tgt %lu\n",
396 skips, tmo->period, tmo->last_tick);
397 if (EM_TIMER_TMO_STATS)
398 tmo->stats.num_period_skips += skips;
399}
400
401static inline bool check_tmo_flags(em_tmo_flag_t flags)
402{
403 /* Check for valid tmo flags (oneshot OR periodic mainly) */
404 if (unlikely(!(flags & (EM_TMO_FLAG_ONESHOT | EM_TMO_FLAG_PERIODIC))))
405 return false;
406
407 if (unlikely((flags & EM_TMO_FLAG_ONESHOT) && (flags & EM_TMO_FLAG_PERIODIC)))
408 return false;
409
410 if (EM_CHECK_LEVEL > 1) {
413 if (unlikely(flags & inv_flags))
414 return false;
415 }
416 return true;
417}
418
419static inline bool check_timer_attr(const em_timer_attr_t *tmr_attr)
420{
421 if (unlikely(tmr_attr == NULL)) {
422 INTERNAL_ERROR(EM_ERR_BAD_POINTER, EM_ESCOPE_TIMER_CREATE,
423 "NULL ptr given");
424 return false;
425 }
426 if (unlikely(tmr_attr->__internal_check != EM_CHECK_INIT_CALLED)) {
427 INTERNAL_ERROR(EM_ERR_NOT_INITIALIZED, EM_ESCOPE_TIMER_CREATE,
428 "Not initialized: em_timer_attr_init(tmr_attr) not called");
429 return false;
430 }
431 if (unlikely(tmr_attr->resparam.res_ns && tmr_attr->resparam.res_hz)) {
432 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_CREATE,
433 "Only res_ns OR res_hz allowed");
434 return false;
435 }
436 return true;
437}
438
439static inline bool check_timer_attr_ring(const em_timer_attr_t *ring_attr)
440{
441 if (unlikely(ring_attr == NULL)) {
442 INTERNAL_ERROR(EM_ERR_BAD_POINTER, EM_ESCOPE_TIMER_RING_CREATE,
443 "NULL attr given");
444 return false;
445 }
446 if (EM_CHECK_LEVEL > 0 && unlikely(ring_attr->__internal_check != EM_CHECK_INIT_CALLED)) {
447 INTERNAL_ERROR(EM_ERR_NOT_INITIALIZED, EM_ESCOPE_TIMER_RING_CREATE,
448 "Not initialized: em_timer_ring_attr_init(ring_attr) not called");
449 return false;
450 }
451
452 if (EM_CHECK_LEVEL > 1 &&
453 unlikely((ring_attr->ringparam.base_hz.integer < 1 &&
454 (ring_attr->ringparam.base_hz.numer < 1 ||
455 ring_attr->ringparam.base_hz.denom < 1)) ||
456 (ring_attr->ringparam.base_hz.numer > 0 &&
457 ring_attr->ringparam.base_hz.denom == 0) ||
458 ring_attr->ringparam.max_mul < 1 ||
459 (ring_attr->flags & EM_TIMER_FLAG_RING) == 0)) {
460 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_RING_CREATE,
461 "Invalid attr values for ring timer");
462 return false;
463 }
464
465 return true;
466}
467
468static inline bool check_timer_attr_ring_freq(const em_timer_attr_t *ring_attr)
469{
470 if (unlikely(ring_attr == NULL)) {
471 INTERNAL_ERROR(EM_ERR_BAD_POINTER, EM_ESCOPE_TIMER_RING_FREQ_CREATE,
472 "NULL attr given");
473 return false;
474 }
475 if (unlikely(ring_attr->__internal_check != EM_CHECK_INIT_CALLED)) {
476 INTERNAL_ERROR(EM_ERR_NOT_INITIALIZED, EM_ESCOPE_TIMER_RING_FREQ_CREATE,
477 "Not initialized: em_timer_ring_freq_attr_init() not called");
478 return false;
479 }
480 if (unlikely((ring_attr->flags & EM_TIMER_FLAG_RING_FREQ) == 0)) {
481 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_RING_FREQ_CREATE,
482 "EM_TIMER_FLAG_RING_FREQ not set");
483 return false;
484 }
485 if (unlikely(ring_attr->freqparam.freq_hz == NULL ||
486 ring_attr->freqparam.num == 0)) {
487 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_RING_FREQ_CREATE,
488 "Invalid freq params: freq_hz=%p, num=%u",
489 ring_attr->freqparam.freq_hz, ring_attr->freqparam.num);
490 return false;
491 }
492 return true;
493}
494
495static inline int find_free_timer_index(void)
496{
497 /*
498 * Find a free timer-slot.
499 * This linear search should not be a performance problem with only a few timers
500 * available especially when these are typically created at startup.
501 * Assumes context is locked
502 */
503 int i;
504
505 for (i = 0; i < EM_ODP_MAX_TIMERS; i++) {
506 const event_timer_t *timer = &em_shm->timers.timer[i];
507
508 if (timer->odp_tmr_pool == ODP_TIMER_POOL_INVALID) /* marks unused entry */
509 break;
510 }
511 return i;
512}
513
515{
516 if (unlikely(EM_CHECK_LEVEL > 0 && tmr_attr == NULL))
517 return; /* just ignore NULL here */
518
519 /* clear/invalidate unused ring timer */
520 memset(&tmr_attr->ringparam, 0, sizeof(em_timer_ring_param_t));
521 /* clear/invalidate unused freq ring timer */
522 memset(&tmr_attr->freqparam, 0, sizeof(em_timer_ring_freq_param_t));
523
524 /* strategy: first put default resolution, then validate based on that */
525 tmr_attr->resparam.res_ns = EM_ODP_TIMER_RESOL_DEF_NS;
526 tmr_attr->resparam.res_hz = 0;
528 tmr_attr->flags = EM_TIMER_FLAG_NONE;
529
530 odp_timer_clk_src_t odp_clksrc;
531 odp_timer_capability_t odp_capa;
532 odp_timer_res_capability_t odp_res_capa;
533 int err;
534
535 err = timer_clksrc_em2odp(tmr_attr->resparam.clk_src, &odp_clksrc);
536 if (unlikely(err)) {
537 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_ATTR_INIT,
538 "Unsupported EM-timer clock source:%d",
539 tmr_attr->resparam.clk_src);
540 return;
541 }
542 err = odp_timer_capability(odp_clksrc, &odp_capa);
543 if (unlikely(err)) {
544 INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_TIMER_ATTR_INIT,
545 "Timer capability: ret %d, odp-clksrc:%d",
546 err, odp_clksrc);
547 return;
548 }
549
550 TMR_DBG_PRINT("odp says highest res %lu\n", odp_capa.highest_res_ns);
551 if (unlikely(odp_capa.highest_res_ns > tmr_attr->resparam.res_ns)) {
552 INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_TIMER_ATTR_INIT,
553 "Timer capability: maxres %lu req %lu, odp-clksrc:%d!",
554 odp_capa.highest_res_ns, tmr_attr->resparam.res_ns, odp_clksrc);
555 return;
556 }
557
558 memset(&odp_res_capa, 0, sizeof(odp_timer_res_capability_t));
559 odp_res_capa.res_ns = tmr_attr->resparam.res_ns;
560 err = odp_timer_res_capability(odp_clksrc, &odp_res_capa);
561 if (unlikely(err)) {
562 INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_TIMER_ATTR_INIT,
563 "Timer res capability failed: ret %d, odp-clksrc:%d, res %lu",
564 err, odp_clksrc, tmr_attr->resparam.res_ns);
565 return;
566 }
567
568 TMR_DBG_PRINT("res %lu -> ODP says min %lu, max %lu\n",
569 tmr_attr->resparam.res_ns, odp_res_capa.min_tmo,
570 odp_res_capa.max_tmo);
571
572 tmr_attr->num_tmo = EM_ODP_DEFAULT_TMOS;
573 if (odp_capa.max_timers && odp_capa.max_timers < EM_ODP_DEFAULT_TMOS)
574 tmr_attr->num_tmo = odp_capa.max_timers;
575
576 tmr_attr->resparam.min_tmo = odp_res_capa.min_tmo;
577 tmr_attr->resparam.max_tmo = odp_res_capa.max_tmo;
578 tmr_attr->name[0] = 0; /* timer_create will add default (no index available here) */
579 tmr_attr->priority = 0; /* default priority */
580 tmr_attr->max_pending_events = 0; /* 0 means default, no flow control */
582}
583
585 em_timer_clksrc_t clk_src,
586 uint64_t base_hz,
587 uint64_t max_mul,
588 uint64_t res_ns)
589{
590 /* NULL deref would crash the memset() below regardless of EM_CHECK_LEVEL */
591 if (unlikely(ring_attr == NULL))
592 return EM_ERR_BAD_ARG;
593
594 /* clear unused fields */
595 memset(ring_attr, 0, sizeof(em_timer_attr_t));
596
597 ring_attr->ringparam.base_hz.integer = base_hz;
598 ring_attr->ringparam.clk_src = clk_src;
599 ring_attr->ringparam.max_mul = max_mul;
600 ring_attr->ringparam.res_ns = res_ns; /* 0 is legal and means odp default */
601 ring_attr->num_tmo = EM_ODP_DEFAULT_RING_TMOS;
602 ring_attr->flags = EM_TIMER_FLAG_RING;
603 ring_attr->name[0] = 0; /* default at ring_create, index not known here */
604 ring_attr->priority = 0; /* default priority */
605 ring_attr->max_pending_events = 0; /* no flow control */
606
607 odp_timer_clk_src_t odp_clksrc;
608 odp_timer_capability_t capa;
609 int rv = timer_clksrc_em2odp(ring_attr->ringparam.clk_src, &odp_clksrc);
610
611 if (unlikely(rv))
612 return EM_ERR_BAD_ARG;
613 if (unlikely(odp_timer_capability(odp_clksrc, &capa) != 0)) {
614 TMR_DBG_PRINT("odp_timer_capability returned error for clk_src %u\n", odp_clksrc);
615 return EM_ERR_BAD_ARG; /* assume clksrc not supported */
616 }
617
618 if (capa.periodic.max_pools == 0) /* no odp support */
620
621 if (capa.periodic.max_timers < ring_attr->num_tmo)
622 ring_attr->num_tmo = capa.periodic.max_timers;
623
624 odp_timer_periodic_capability_t pcapa;
625
626 pcapa.res_ns = ring_attr->ringparam.res_ns;
627
628#if PRE_1_50_ODP_TIMER_API
629 pcapa.base_freq_hz.integer = ring_attr->ringparam.base_hz.integer;
630 pcapa.base_freq_hz.numer = ring_attr->ringparam.base_hz.numer;
631 pcapa.base_freq_hz.denom = ring_attr->ringparam.base_hz.denom;
632 pcapa.max_multiplier = ring_attr->ringparam.max_mul;
633 rv = odp_timer_periodic_capability(odp_clksrc, &pcapa);
634 ring_attr->ringparam.res_ns = pcapa.res_ns; /* update back */
635 ring_attr->ringparam.base_hz.integer = pcapa.base_freq_hz.integer;
636 ring_attr->ringparam.base_hz.numer = pcapa.base_freq_hz.numer;
637 ring_attr->ringparam.base_hz.denom = pcapa.base_freq_hz.denom;
638 if (pcapa.max_multiplier < ring_attr->ringparam.max_mul) /* don't increase here */
639 ring_attr->ringparam.max_mul = pcapa.max_multiplier;
640#else
641 pcapa.type = ODP_TIMER_TYPE_PERIODIC_BASE_MUL;
642 pcapa.base_mul.base_freq_hz.integer = ring_attr->ringparam.base_hz.integer;
643 pcapa.base_mul.base_freq_hz.numer = ring_attr->ringparam.base_hz.numer;
644 pcapa.base_mul.base_freq_hz.denom = ring_attr->ringparam.base_hz.denom;
645 pcapa.base_mul.max_multiplier = ring_attr->ringparam.max_mul;
646 rv = odp_timer_periodic_capability(odp_clksrc, &pcapa);
647 ring_attr->ringparam.res_ns = pcapa.res_ns; /* update back */
648 ring_attr->ringparam.base_hz.integer = pcapa.base_mul.base_freq_hz.integer;
649 ring_attr->ringparam.base_hz.numer = pcapa.base_mul.base_freq_hz.numer;
650 ring_attr->ringparam.base_hz.denom = pcapa.base_mul.base_freq_hz.denom;
651 if (pcapa.base_mul.max_multiplier < ring_attr->ringparam.max_mul) /* don't increase here */
652 ring_attr->ringparam.max_mul = pcapa.base_mul.max_multiplier;
653#endif
654 if (rv != 1) /* 1 means all values supported */
655 return EM_ERR_BAD_ARG;
656
658 return EM_OK;
659}
660
662 em_timer_clksrc_t clk_src,
663 em_fract_u64_t *freq_hz,
664 uint32_t num,
665 uint64_t res_ns)
666{
667#if PRE_1_50_ODP_TIMER_API
668 (void)ring_attr;
669 (void)clk_src;
670 (void)freq_hz;
671 (void)num;
672 (void)res_ns;
674#else
675 /* NULL deref would crash memset()/ODP call below regardless of EM_CHECK_LEVEL */
676 if (unlikely(ring_attr == NULL || freq_hz == NULL || num == 0))
677 return EM_ERR_BAD_ARG;
678
679 /* clear unused fields */
680 memset(ring_attr, 0, sizeof(em_timer_attr_t));
681
682 ring_attr->freqparam.clk_src = clk_src;
683 ring_attr->freqparam.freq_hz = freq_hz;
684 ring_attr->freqparam.num = num;
685 ring_attr->freqparam.res_ns = res_ns; /* 0 is legal and means odp default */
686 ring_attr->num_tmo = EM_ODP_DEFAULT_RING_TMOS;
687 ring_attr->flags = EM_TIMER_FLAG_RING_FREQ;
688 ring_attr->name[0] = 0;
689 ring_attr->priority = 0;
690 ring_attr->max_pending_events = 0; /* no flow control */
691
692 odp_timer_clk_src_t odp_clksrc;
693 odp_timer_capability_t capa;
694 int rv = timer_clksrc_em2odp(clk_src, &odp_clksrc);
695
696 if (unlikely(rv))
697 return EM_ERR_BAD_ARG;
698 if (unlikely(odp_timer_capability(odp_clksrc, &capa) != 0)) {
699 TMR_DBG_PRINT("odp_timer_capability returned error for clk_src %u\n", odp_clksrc);
700 return EM_ERR_BAD_ARG;
701 }
702
703 if (capa.periodic.max_pools == 0 || !capa.periodic.support.freq)
705
706 if (capa.periodic.max_timers < ring_attr->num_tmo)
707 ring_attr->num_tmo = capa.periodic.max_timers;
708
709 odp_timer_periodic_capability_t pcapa;
710
711 pcapa.type = ODP_TIMER_TYPE_PERIODIC_FREQ;
712 pcapa.res_ns = res_ns;
713 pcapa.freq.freq_hz = (odp_fract_u64_t *)freq_hz;
714 pcapa.freq.num = num;
715 rv = odp_timer_periodic_capability(odp_clksrc, &pcapa);
716 ring_attr->freqparam.res_ns = pcapa.res_ns; /* update back */
717 /* freq_hz array contents may be updated in-place by ODP */
718
719 if (rv != 1) /* 1 means all values supported */
720 return EM_ERR_BAD_ARG;
721
723 return EM_OK;
724#endif /* !PRE_1_50_ODP_TIMER_API */
725}
726
728{
729 if (EM_CHECK_LEVEL > 0 && unlikely(capa == NULL)) {
730 EM_LOG(EM_LOG_DBG, "%s(): NULL capa ptr!\n", __func__);
731 return EM_ERR_BAD_POINTER;
732 }
733
734 odp_timer_clk_src_t odp_clksrc;
735 odp_timer_capability_t odp_capa;
736
737 if (unlikely(timer_clksrc_em2odp(clk_src, &odp_clksrc) ||
738 odp_timer_capability(odp_clksrc, &odp_capa))) {
739 EM_LOG(EM_LOG_DBG, "%s: Not supported clk_src %d\n", __func__, clk_src);
740 return EM_ERR_BAD_ARG;
741 }
742
743 capa->max_timers = odp_capa.max_pools < EM_ODP_MAX_TIMERS ?
744 odp_capa.max_pools : EM_ODP_MAX_TIMERS;
745 capa->max_num_tmo = odp_capa.max_timers;
746 capa->max_res.clk_src = clk_src;
747 capa->max_res.res_ns = odp_capa.max_res.res_ns;
748 capa->max_res.res_hz = odp_capa.max_res.res_hz;
749 capa->max_res.min_tmo = odp_capa.max_res.min_tmo;
750 capa->max_res.max_tmo = odp_capa.max_res.max_tmo;
751 capa->max_tmo.clk_src = clk_src;
752 capa->max_tmo.res_ns = odp_capa.max_tmo.res_ns;
753 capa->max_tmo.res_hz = odp_capa.max_tmo.res_hz;
754 capa->max_tmo.min_tmo = odp_capa.max_tmo.min_tmo;
755 capa->max_tmo.max_tmo = odp_capa.max_tmo.max_tmo;
756 capa->max_priority = odp_capa.max_priority;
757
758 /* ring timer basic capability */
759 capa->ring.max_rings = odp_capa.periodic.max_pools; /* 0 if not supported */
760 capa->ring.max_num_tmo = odp_capa.periodic.max_timers;
761 capa->ring.max_priority = odp_capa.periodic.max_priority;
762 capa->ring.min_base_hz.integer = odp_capa.periodic.min_base_freq_hz.integer;
763 capa->ring.min_base_hz.numer = odp_capa.periodic.min_base_freq_hz.numer;
764 capa->ring.min_base_hz.denom = odp_capa.periodic.min_base_freq_hz.denom;
765 capa->ring.max_base_hz.integer = odp_capa.periodic.max_base_freq_hz.integer;
766 capa->ring.max_base_hz.numer = odp_capa.periodic.max_base_freq_hz.numer;
767 capa->ring.max_base_hz.denom = odp_capa.periodic.max_base_freq_hz.denom;
768#if PRE_1_50_ODP_TIMER_API
769 capa->ring.min_pending_events = 0; /* no flow control, no odp capability */
770 capa->ring.max_pending_events = 0; /* no flow control, no odp capability */
771 capa->ring.min_freq_hz.integer = 0;
772 capa->ring.min_freq_hz.numer = 0;
773 capa->ring.min_freq_hz.denom = 0;
774 capa->ring.max_freq_hz.integer = 0;
775 capa->ring.max_freq_hz.numer = 0;
776 capa->ring.max_freq_hz.denom = 0;
777 capa->ring.support.base_mul = 1; /* base-mul is only supported mode */
778 capa->ring.support.freq = 0; /* freq list not supported in old API */
779#else
780 capa->ring.min_pending_events = odp_capa.periodic.min_pending_tmo;
781 capa->ring.max_pending_events = odp_capa.periodic.max_pending_tmo;
782 capa->ring.min_freq_hz.integer = odp_capa.periodic.min_freq_hz.integer;
783 capa->ring.min_freq_hz.numer = odp_capa.periodic.min_freq_hz.numer;
784 capa->ring.min_freq_hz.denom = odp_capa.periodic.min_freq_hz.denom;
785 capa->ring.max_freq_hz.integer = odp_capa.periodic.max_freq_hz.integer;
786 capa->ring.max_freq_hz.numer = odp_capa.periodic.max_freq_hz.numer;
787 capa->ring.max_freq_hz.denom = odp_capa.periodic.max_freq_hz.denom;
788 capa->ring.support.base_mul = odp_capa.periodic.support.base_mul;
789 capa->ring.support.freq = odp_capa.periodic.support.freq;
790#endif
791 return EM_OK;
792}
793
795{
796 if (EM_CHECK_LEVEL > 0 && unlikely(res == NULL)) {
797 EM_LOG(EM_LOG_DBG, "%s: NULL ptr res\n", __func__);
798 return EM_ERR_BAD_POINTER;
799 }
800
801 odp_timer_clk_src_t odp_clksrc;
802 odp_timer_res_capability_t odp_res_capa;
803 int err;
804
805 err = timer_clksrc_em2odp(clk_src, &odp_clksrc);
806 if (unlikely(err)) {
807 EM_LOG(EM_LOG_DBG, "%s: Not supported clk_src %d\n", __func__, clk_src);
808 return EM_ERR_BAD_ARG;
809 }
810 memset(&odp_res_capa, 0, sizeof(odp_timer_res_capability_t));
811 odp_res_capa.res_ns = res->res_ns;
812 odp_res_capa.res_hz = res->res_hz; /* ODP will check if both were set */
813 odp_res_capa.max_tmo = res->max_tmo;
814 err = odp_timer_res_capability(odp_clksrc, &odp_res_capa);
815 if (unlikely(err)) {
816 EM_LOG(EM_LOG_DBG, "%s: ODP res_capability failed (ret %d)!\n", __func__, err);
817 return EM_ERR_BAD_ARG;
818 }
819 res->min_tmo = odp_res_capa.min_tmo;
820 res->max_tmo = odp_res_capa.max_tmo;
821 res->res_ns = odp_res_capa.res_ns;
822 res->res_hz = odp_res_capa.res_hz;
823 res->clk_src = clk_src;
824 return EM_OK;
825}
826
828{
829 odp_timer_clk_src_t odp_clksrc;
830 odp_timer_periodic_capability_t pcapa;
831
832 if (EM_CHECK_LEVEL > 0 && unlikely(ring == NULL)) {
833 EM_LOG(EM_LOG_DBG, "%s: NULL ptr ring\n", __func__);
834 return EM_ERR_BAD_POINTER;
835 }
836
837 if (unlikely(timer_clksrc_em2odp(ring->clk_src, &odp_clksrc))) {
838 EM_LOG(EM_LOG_DBG, "%s: Invalid clk_src %d\n", __func__, ring->clk_src);
839 return EM_ERR_BAD_ARG;
840 }
841
842 pcapa.res_ns = ring->res_ns;
843
844#if PRE_1_50_ODP_TIMER_API
845 pcapa.base_freq_hz.integer = ring->base_hz.integer;
846 pcapa.base_freq_hz.numer = ring->base_hz.numer;
847 pcapa.base_freq_hz.denom = ring->base_hz.denom;
848 pcapa.max_multiplier = ring->max_mul;
849 int rv = odp_timer_periodic_capability(odp_clksrc, &pcapa);
850
851 ring->base_hz.integer = pcapa.base_freq_hz.integer;
852 ring->base_hz.numer = pcapa.base_freq_hz.numer;
853 ring->base_hz.denom = pcapa.base_freq_hz.denom;
854 ring->max_mul = pcapa.max_multiplier;
855#else
856 pcapa.type = ODP_TIMER_TYPE_PERIODIC_BASE_MUL;
857 pcapa.base_mul.base_freq_hz.integer = ring->base_hz.integer;
858 pcapa.base_mul.base_freq_hz.numer = ring->base_hz.numer;
859 pcapa.base_mul.base_freq_hz.denom = ring->base_hz.denom;
860 pcapa.base_mul.max_multiplier = ring->max_mul;
861 int rv = odp_timer_periodic_capability(odp_clksrc, &pcapa);
862
863 ring->base_hz.integer = pcapa.base_mul.base_freq_hz.integer;
864 ring->base_hz.numer = pcapa.base_mul.base_freq_hz.numer;
865 ring->base_hz.denom = pcapa.base_mul.base_freq_hz.denom;
866 ring->max_mul = pcapa.base_mul.max_multiplier;
867#endif
868 ring->res_ns = pcapa.res_ns;
869
870 if (unlikely(rv < 0)) {
871 EM_LOG(EM_LOG_DBG, "%s: odp failed periodic capability for clk_src %d\n",
872 __func__, ring->clk_src);
873 return EM_ERR_LIB_FAILED;
874 }
875 if (rv == 0)
876 return EM_ERR_NOT_SUPPORTED; /* no error, but no exact support */
877
878 return EM_OK; /* meet or exceed */
879}
880
882{
883#if PRE_1_50_ODP_TIMER_API
884 (void)ring;
886#else
887 odp_timer_clk_src_t odp_clksrc;
888 odp_timer_periodic_capability_t pcapa;
889
890 if (EM_CHECK_LEVEL > 0 && unlikely(ring == NULL)) {
891 EM_LOG(EM_LOG_DBG, "%s: NULL ptr ring\n", __func__);
892 return EM_ERR_BAD_POINTER;
893 }
894
895 if (EM_CHECK_LEVEL > 0 && unlikely(ring->freq_hz == NULL || ring->num == 0)) {
896 EM_LOG(EM_LOG_DBG, "%s: Invalid freq params\n", __func__);
897 return EM_ERR_BAD_ARG;
898 }
899
900 if (unlikely(timer_clksrc_em2odp(ring->clk_src, &odp_clksrc))) {
901 EM_LOG(EM_LOG_DBG, "%s: Invalid clk_src %d\n", __func__, ring->clk_src);
902 return EM_ERR_BAD_ARG;
903 }
904
905 pcapa.type = ODP_TIMER_TYPE_PERIODIC_FREQ;
906 pcapa.res_ns = ring->res_ns;
907 pcapa.freq.freq_hz = (odp_fract_u64_t *)ring->freq_hz;
908 pcapa.freq.num = ring->num;
909
910 int rv = odp_timer_periodic_capability(odp_clksrc, &pcapa);
911
912 ring->res_ns = pcapa.res_ns;
913 /* freq_hz array contents updated in-place by ODP when rv == 0 */
914
915 if (unlikely(rv < 0)) {
916 EM_LOG(EM_LOG_DBG, "%s: odp failed periodic capability for clk_src %d\n",
917 __func__, ring->clk_src);
918 return EM_ERR_LIB_FAILED;
919 }
920 if (rv == 0)
921 return EM_ERR_NOT_SUPPORTED; /* closest supported values written to freq_hz */
922
923 return EM_OK; /* meet or exceed */
924#endif /* !PRE_1_50_ODP_TIMER_API */
925}
926
927em_timer_t em_timer_create(const em_timer_attr_t *tmr_attr)
928{
929 /* timers are initialized? */
930 if (unlikely(em_shm->timers.init_check != EM_CHECK_INIT_CALLED)) {
931 INTERNAL_ERROR(EM_ERR_NOT_INITIALIZED, EM_ESCOPE_TIMER_CREATE,
932 "Timer is not initialized!");
933 return EM_TIMER_UNDEF;
934 }
935
936 if (EM_CHECK_LEVEL > 0) {
937 if (check_timer_attr(tmr_attr) == false)
938 return EM_TIMER_UNDEF;
939 }
940
941 odp_timer_pool_param_t odp_tpool_param;
942 odp_timer_clk_src_t odp_clksrc;
943
944 odp_timer_pool_param_init(&odp_tpool_param);
945 odp_tpool_param.res_ns = tmr_attr->resparam.res_ns;
946 odp_tpool_param.res_hz = tmr_attr->resparam.res_hz;
947 odp_tpool_param.min_tmo = tmr_attr->resparam.min_tmo;
948 odp_tpool_param.max_tmo = tmr_attr->resparam.max_tmo;
949 odp_tpool_param.num_timers = tmr_attr->num_tmo;
950 odp_tpool_param.priv = tmr_attr->flags & EM_TIMER_FLAG_PRIVATE ? 1 : 0;
951 if (unlikely(timer_clksrc_em2odp(tmr_attr->resparam.clk_src, &odp_clksrc))) {
952 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_CREATE,
953 "Unsupported EM-timer clock source:%d",
954 tmr_attr->resparam.clk_src);
955 return EM_TIMER_UNDEF;
956 }
957 odp_tpool_param.clk_src = odp_clksrc;
958
959 /* check queue type support */
960 odp_timer_capability_t capa;
961
962 if (unlikely(odp_timer_capability(odp_clksrc, &capa))) {
963 INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_TIMER_CREATE,
964 "ODP timer capa failed for clk:%d",
965 tmr_attr->resparam.clk_src);
966 return EM_TIMER_UNDEF;
967 }
968 if (unlikely(!capa.queue_type_sched)) { /* must support scheduled queues */
969 INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_TIMER_CREATE,
970 "ODP does not support scheduled q for clk:%d",
971 tmr_attr->resparam.clk_src);
972 return EM_TIMER_UNDEF;
973 }
974 /* check priority support */
975 if (unlikely(tmr_attr->priority > capa.max_priority)) {
976 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_CREATE,
977 "Priority %u exceeds ODP max %u for clk:%d",
978 tmr_attr->priority, capa.max_priority,
979 tmr_attr->resparam.clk_src);
980 return EM_TIMER_UNDEF;
981 }
982 odp_tpool_param.priority = tmr_attr->priority;
983
984 odp_ticketlock_lock(&em_shm->timers.timer_lock);
985
986 int i = find_free_timer_index();
987
988 if (unlikely(i >= EM_ODP_MAX_TIMERS)) {
989 odp_ticketlock_unlock(&em_shm->timers.timer_lock);
990 INTERNAL_ERROR(EM_ERR_ALLOC_FAILED, EM_ESCOPE_TIMER_CREATE,
991 "No more timers available");
992 return EM_TIMER_UNDEF;
993 }
994
995 event_timer_t *timer = &em_shm->timers.timer[i];
996 char timer_pool_name[ODP_TIMER_POOL_NAME_LEN];
997 const char *name = tmr_attr->name;
998 const char *reason = "";
999
1000 if (tmr_attr->name[0] == '\0') { /* replace NULL with default */
1001 snprintf(timer_pool_name, ODP_TIMER_POOL_NAME_LEN,
1002 "EM-timer-%d", timer->idx); /* idx initialized by timer_init */
1003 name = timer_pool_name;
1004 }
1005
1006 TMR_DBG_PRINT("Creating ODP tmr pool: clk %d, res_ns %lu, res_hz %lu, priority %u\n",
1007 odp_tpool_param.clk_src, odp_tpool_param.res_ns,
1008 odp_tpool_param.res_hz, odp_tpool_param.priority);
1009 timer->odp_tmr_pool = odp_timer_pool_create(name, &odp_tpool_param);
1010 if (unlikely(timer->odp_tmr_pool == ODP_TIMER_POOL_INVALID)) {
1011 reason = "odp_timer_pool_create error";
1012 goto error_locked;
1013 }
1014 TMR_DBG_PRINT("Created timer: %s with idx: %d\n", name, timer->idx);
1015
1016 /* tmo handle pool can be per-timer or shared */
1017 if (!em_shm->opt.timer.shared_tmo_pool_enable) { /* per-timer pool */
1018 odp_pool_t opool = create_tmo_handle_pool(tmr_attr->num_tmo,
1019 em_shm->opt.timer.tmo_pool_cache, timer);
1020
1021 if (unlikely(opool == ODP_POOL_INVALID)) {
1022 reason = "Tmo handle buffer pool create failed";
1023 goto error_locked;
1024 }
1025
1026 timer->tmo_pool = opool;
1027 TMR_DBG_PRINT("Created per-timer tmo handle pool\n");
1028 } else {
1029 if (em_shm->timers.shared_tmo_pool == ODP_POOL_INVALID) { /* first timer */
1030 odp_pool_t opool =
1031 create_tmo_handle_pool(em_shm->opt.timer.shared_tmo_pool_size,
1032 em_shm->opt.timer.tmo_pool_cache, timer);
1033
1034 if (unlikely(opool == ODP_POOL_INVALID)) {
1035 reason = "Shared tmo handle buffer pool create failed";
1036 goto error_locked;
1037 }
1038 timer->tmo_pool = opool;
1039 em_shm->timers.shared_tmo_pool = opool;
1040 TMR_DBG_PRINT("Created shared tmo handle pool for total %u tmos\n",
1041 em_shm->opt.timer.shared_tmo_pool_size);
1042 } else {
1043 timer->tmo_pool = em_shm->timers.shared_tmo_pool;
1044 }
1045 }
1046
1047 timer->num_tmo_reserve = tmr_attr->num_tmo;
1048 if (em_shm->opt.timer.shared_tmo_pool_enable) { /* check reservation */
1049 uint32_t left = em_shm->opt.timer.shared_tmo_pool_size - em_shm->timers.reserved;
1050
1051 if (timer->num_tmo_reserve > left) {
1052 TMR_DBG_PRINT("Not enough tmos left in shared pool (%u)\n", left);
1053 reason = "Not enough tmos left in shared pool";
1054 goto error_locked;
1055 }
1056 em_shm->timers.reserved += timer->num_tmo_reserve;
1057 TMR_DBG_PRINT("Updated shared tmo reserve by +%u to %u\n",
1058 timer->num_tmo_reserve, em_shm->timers.reserved);
1059 }
1060 timer->flags = tmr_attr->flags;
1061 timer->plain_q_ok = capa.queue_type_plain;
1062 timer->is_ring = false;
1063
1064 if (odp_timer_pool_start_multi(&timer->odp_tmr_pool, 1) != 1) {
1065 reason = "odp_timer_pool_start_multi failed";
1066 goto error_locked;
1067 }
1068
1069 em_shm->timers.num_timers++;
1070 odp_ticketlock_unlock(&em_shm->timers.timer_lock);
1071
1072 TMR_DBG_PRINT("ret %" PRI_TMR ", total timers %u\n", TMR_I2H(i), em_shm->timers.num_timers);
1073 return TMR_I2H(i);
1074
1075error_locked:
1076 cleanup_timer_create_fail(timer);
1077 odp_ticketlock_unlock(&em_shm->timers.timer_lock);
1078
1079 TMR_DBG_PRINT("ERR odp tmr pool in: clk %u, res %lu, min %lu, max %lu, num %u\n",
1080 odp_tpool_param.clk_src, odp_tpool_param.res_ns,
1081 odp_tpool_param.min_tmo, odp_tpool_param.max_tmo, odp_tpool_param.num_timers);
1082 INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_TIMER_CREATE,
1083 "Timer pool create failed: %s", reason);
1084 return EM_TIMER_UNDEF;
1085}
1086
1087typedef enum ring_kind {
1088 RING_KIND_BASE_MUL,
1089 RING_KIND_FREQ,
1090} ring_kind_t;
1091
1092/*
1093 * Validate ODP timer capabilities for a ring timer and resolve the ODP clock
1094 * source. Returns true on success; on failure reports via INTERNAL_ERROR().
1095 */
1096static bool ring_check_capa(ring_kind_t kind, const em_timer_attr_t *ring_attr,
1097 em_timer_clksrc_t em_clksrc, em_escope_t escope,
1098 odp_timer_clk_src_t *odp_clksrc,
1099 odp_timer_capability_t *capa)
1100{
1101#if PRE_1_50_ODP_TIMER_API
1102 (void)kind;
1103#endif
1104 if (unlikely(timer_clksrc_em2odp(em_clksrc, odp_clksrc))) {
1106 "Unsupported EM-timer clock source:%d", em_clksrc);
1107 return false;
1108 }
1109
1110 if (unlikely(odp_timer_capability(*odp_clksrc, capa))) {
1112 "ODP timer capa failed for clk:%d", em_clksrc);
1113 return false;
1114 }
1115 if (unlikely(!capa->queue_type_sched)) {
1117 "ODP does not support scheduled q for clk:%d", em_clksrc);
1118 return false;
1119 }
1120#if !PRE_1_50_ODP_TIMER_API
1121 if (kind == RING_KIND_FREQ && unlikely(!capa->periodic.support.freq)) {
1123 "ODP_TIMER_TYPE_PERIODIC_FREQ not supported");
1124 return false;
1125 }
1126#endif
1127 if (unlikely(ring_attr->priority > capa->periodic.max_priority)) {
1129 "Priority %u exceeds ODP max %u for clk:%d",
1130 ring_attr->priority, capa->periodic.max_priority, em_clksrc);
1131 return false;
1132 }
1133 return true;
1134}
1135
1136/*
1137 * Fill the type-specific ODP timer pool parameters (base-mul or freq) and the
1138 * optional flow-control (max pending events) settings for a ring timer.
1139 * Returns true on success; on failure reports via INTERNAL_ERROR().
1140 */
1141static bool ring_fill_tpool_param(ring_kind_t kind, const em_timer_attr_t *ring_attr,
1142 const odp_timer_capability_t *capa, em_escope_t escope,
1143 odp_timer_pool_param_t *odp_tpool_param)
1144{
1145#if PRE_1_50_ODP_TIMER_API
1146 (void)kind;
1147 (void)capa;
1148 /* freq variant is rejected by the wrapper on PRE_1_50, only base_mul reaches here */
1149 odp_tpool_param->timer_type = ODP_TIMER_TYPE_PERIODIC;
1150 odp_tpool_param->periodic.base_freq_hz.integer = ring_attr->ringparam.base_hz.integer;
1151 odp_tpool_param->periodic.base_freq_hz.numer = ring_attr->ringparam.base_hz.numer;
1152 odp_tpool_param->periodic.base_freq_hz.denom = ring_attr->ringparam.base_hz.denom;
1153 odp_tpool_param->periodic.max_multiplier = ring_attr->ringparam.max_mul;
1154 if (ring_attr->max_pending_events > 0) {
1156 "Ring flow control not supported with this ODP version");
1157 return false;
1158 }
1159 TMR_DBG_PRINT("Creating ODP periodic tmr pool: clk %d, res_ns %lu, base_hz %lu, priority %u\n",
1160 odp_tpool_param->clk_src, odp_tpool_param->res_ns,
1161 odp_tpool_param->periodic.base_freq_hz.integer, odp_tpool_param->priority);
1162#else
1163 if (kind == RING_KIND_FREQ) {
1164 odp_tpool_param->timer_type = ODP_TIMER_TYPE_PERIODIC_FREQ;
1165 odp_tpool_param->periodic.freq.freq_hz =
1166 (odp_fract_u64_t *)ring_attr->freqparam.freq_hz;
1167 odp_tpool_param->periodic.freq.num = ring_attr->freqparam.num;
1168 } else {
1169 odp_tpool_param->timer_type = ODP_TIMER_TYPE_PERIODIC_BASE_MUL;
1170 odp_tpool_param->periodic.base_mul.base_freq_hz.integer =
1171 ring_attr->ringparam.base_hz.integer;
1172 odp_tpool_param->periodic.base_mul.base_freq_hz.numer =
1173 ring_attr->ringparam.base_hz.numer;
1174 odp_tpool_param->periodic.base_mul.base_freq_hz.denom =
1175 ring_attr->ringparam.base_hz.denom;
1176 odp_tpool_param->periodic.base_mul.max_multiplier =
1177 ring_attr->ringparam.max_mul;
1178 }
1179
1180 /* flow control (common to both types in new ODP) */
1181 if (ring_attr->max_pending_events > 0) {
1182 if (capa->periodic.max_pending_tmo == 0) {
1184 "Ring flow control not supported by ODP");
1185 return false;
1186 }
1187 if (ring_attr->max_pending_events > capa->periodic.max_pending_tmo) {
1189 "Requested max_pending_events %u exceeds ODP max %u",
1190 ring_attr->max_pending_events,
1191 capa->periodic.max_pending_tmo);
1192 return false;
1193 }
1194 if (ring_attr->max_pending_events < capa->periodic.min_pending_tmo) {
1196 "Requested max_pending_events %u less than ODP min %u",
1197 ring_attr->max_pending_events,
1198 capa->periodic.min_pending_tmo);
1199 return false;
1200 }
1201 odp_tpool_param->periodic.max_pending_tmo = ring_attr->max_pending_events;
1202 }
1203 odp_tpool_param->periodic.uarea_size = sizeof(event_hdr_t);
1204 TMR_DBG_PRINT("Creating ODP periodic %s tmr pool: clk %d, res_ns %lu, priority %u, max_pending_tmo %u\n",
1205 kind == RING_KIND_FREQ ? "freq" : "base_mul",
1206 odp_tpool_param->clk_src, odp_tpool_param->res_ns,
1207 odp_tpool_param->priority, odp_tpool_param->periodic.max_pending_tmo);
1208#endif
1209 return true;
1210}
1211
1212/*
1213 * Create or attach the per-timer or shared tmo handle pool for a ring timer.
1214 * Returns true on success; on failure sets *reason for the caller's error path.
1215 * Caller must hold timers.timer_lock.
1216 */
1217static bool ring_setup_tmo_handle_pool(event_timer_t *timer, uint32_t num_tmo,
1218 const char **reason)
1219{
1220 if (!em_shm->opt.timer.shared_tmo_pool_enable) {
1221 odp_pool_t opool = create_tmo_handle_pool(num_tmo,
1222 em_shm->opt.timer.tmo_pool_cache,
1223 timer);
1224
1225 if (unlikely(opool == ODP_POOL_INVALID)) {
1226 *reason = "tmo handle pool creation failed";
1227 return false;
1228 }
1229
1230 timer->tmo_pool = opool;
1231 TMR_DBG_PRINT("Created per-timer tmo handle pool %p\n", opool);
1232 return true;
1233 }
1234
1235 if (em_shm->timers.shared_tmo_pool == ODP_POOL_INVALID) {
1236 odp_pool_t opool =
1237 create_tmo_handle_pool(em_shm->opt.timer.shared_tmo_pool_size,
1238 em_shm->opt.timer.tmo_pool_cache, timer);
1239
1240 if (unlikely(opool == ODP_POOL_INVALID)) {
1241 *reason = "Shared tmo handle pool creation failed";
1242 return false;
1243 }
1244
1245 timer->tmo_pool = opool;
1246 em_shm->timers.shared_tmo_pool = opool;
1247 TMR_DBG_PRINT("Created shared tmo handle pool %p\n", opool);
1248 return true;
1249 }
1250
1251 timer->tmo_pool = em_shm->timers.shared_tmo_pool;
1252 return true;
1253}
1254
1255static em_timer_t ring_create_common(const em_timer_attr_t *ring_attr, ring_kind_t kind)
1256{
1257 const em_escope_t escope = (kind == RING_KIND_FREQ) ?
1258 EM_ESCOPE_TIMER_RING_FREQ_CREATE :
1259 EM_ESCOPE_TIMER_RING_CREATE;
1260 const em_timer_clksrc_t em_clksrc = (kind == RING_KIND_FREQ) ?
1261 ring_attr->freqparam.clk_src :
1262 ring_attr->ringparam.clk_src;
1263 const uint64_t res_ns = (kind == RING_KIND_FREQ) ?
1264 ring_attr->freqparam.res_ns :
1265 ring_attr->ringparam.res_ns;
1266
1267 odp_timer_pool_param_t odp_tpool_param;
1268 odp_timer_clk_src_t odp_clksrc;
1269 odp_timer_capability_t capa;
1270
1271 odp_timer_pool_param_init(&odp_tpool_param);
1272 odp_tpool_param.exp_mode = ODP_TIMER_EXP_AFTER;
1273 odp_tpool_param.num_timers = ring_attr->num_tmo;
1274 odp_tpool_param.priv = ring_attr->flags & EM_TIMER_FLAG_PRIVATE ? 1 : 0;
1275
1276 if (!ring_check_capa(kind, ring_attr, em_clksrc, escope, &odp_clksrc, &capa))
1277 return EM_TIMER_UNDEF;
1278
1279 odp_tpool_param.clk_src = odp_clksrc;
1280 odp_tpool_param.res_hz = 0;
1281 odp_tpool_param.res_ns = res_ns;
1282 odp_tpool_param.priority = ring_attr->priority;
1283
1284 /* type-specific ODP param fill */
1285 if (!ring_fill_tpool_param(kind, ring_attr, &capa, escope, &odp_tpool_param))
1286 return EM_TIMER_UNDEF;
1287
1288 /* lock context to find free slot and update it */
1289 timer_storage_t *const tmrs = &em_shm->timers;
1290
1291 odp_ticketlock_lock(&tmrs->timer_lock);
1292
1293#if PRE_1_50_ODP_TIMER_API
1294 /* is there enough events left in shared pool ? */
1295 {
1296 uint32_t left = em_shm->opt.timer.ring.timer_event_pool_size - tmrs->ring_reserved;
1297
1298 if (ring_attr->num_tmo > left) {
1299 odp_ticketlock_unlock(&tmrs->timer_lock);
1301 "Too few ring timeout events left (req %u/%u)",
1302 ring_attr->num_tmo, left);
1303 return EM_TIMER_UNDEF;
1304 }
1305 }
1306#endif
1307
1308 /* allocate timer */
1309 int i = find_free_timer_index();
1310
1311 if (unlikely(i >= EM_ODP_MAX_TIMERS)) {
1312 odp_ticketlock_unlock(&tmrs->timer_lock);
1313 INTERNAL_ERROR(EM_ERR_ALLOC_FAILED, escope, "No more timers available");
1314 return EM_TIMER_UNDEF;
1315 }
1316
1317 event_timer_t *timer = &tmrs->timer[i];
1318
1319 /* then timer pool */
1320 char timer_pool_name[ODP_TIMER_POOL_NAME_LEN];
1321 const char *name = ring_attr->name;
1322 const char *reason = "";
1323
1324 if (ring_attr->name[0] == '\0') { /* replace empty with default */
1325 snprintf(timer_pool_name, ODP_TIMER_POOL_NAME_LEN,
1326 "EM-timer-%d", timer->idx);
1327 name = timer_pool_name;
1328 }
1329
1330 timer->odp_tmr_pool = odp_timer_pool_create(name, &odp_tpool_param);
1331 if (unlikely(timer->odp_tmr_pool == ODP_TIMER_POOL_INVALID)) {
1332 reason = "odp_timer_pool_create failed";
1333 goto error_locked;
1334 }
1335 TMR_DBG_PRINT("Created %s timer: %s with idx: %d\n",
1336 kind == RING_KIND_FREQ ? "ring freq" : "ring", name, timer->idx);
1337
1338 /* tmo handle pool can be per-timer or shared */
1339 if (!ring_setup_tmo_handle_pool(timer, ring_attr->num_tmo, &reason))
1340 goto error_locked;
1341
1342 timer->num_tmo_reserve = ring_attr->num_tmo;
1343 if (em_shm->opt.timer.shared_tmo_pool_enable) {
1344 uint32_t left = em_shm->opt.timer.shared_tmo_pool_size - em_shm->timers.reserved;
1345
1346 if (timer->num_tmo_reserve > left) {
1347 TMR_DBG_PRINT("Not enough tmos left in shared pool (%u)\n", left);
1348 reason = "Not enough tmos left in shared pool";
1349 goto error_locked;
1350 }
1351 em_shm->timers.reserved += timer->num_tmo_reserve;
1352 TMR_DBG_PRINT("Updated shared tmo reserve by +%u to %u\n",
1353 timer->num_tmo_reserve, em_shm->timers.reserved);
1354 }
1355
1356#if PRE_1_50_ODP_TIMER_API
1357 /* odp timeout event pool for ring tmo events is shared for all ring timers.
1358 * New ODP API creates event pools internally during odp_timer_pool_create().
1359 */
1360 if (tmrs->ring_tmo_pool == ODP_POOL_INVALID) {
1361 odp_pool_param_t odp_tmo_pool_param;
1362 char pool_name[ODP_POOL_NAME_LEN];
1363
1364 odp_pool_param_init(&odp_tmo_pool_param);
1365 odp_tmo_pool_param.type = ODP_POOL_TIMEOUT;
1366 odp_tmo_pool_param.tmo.cache_size = em_shm->opt.timer.ring.timer_event_pool_cache;
1367 odp_tmo_pool_param.tmo.num = em_shm->opt.timer.ring.timer_event_pool_size;
1368 odp_tmo_pool_param.tmo.uarea_size = sizeof(event_hdr_t);
1369 odp_tmo_pool_param.stats.all = 0;
1370 snprintf(pool_name, ODP_POOL_NAME_LEN, "Ring-%d-tmo-pool", timer->idx);
1371 tmrs->ring_tmo_pool = odp_pool_create(pool_name, &odp_tmo_pool_param);
1372 if (unlikely(tmrs->ring_tmo_pool == ODP_POOL_INVALID)) {
1373 reason = "odp timeout event pool creation failed";
1374 goto error_locked;
1375 }
1376 TMR_DBG_PRINT("Created ODP-timeout event pool %p: '%s'\n",
1377 tmrs->ring_tmo_pool, pool_name);
1378 }
1379
1380 tmrs->ring_reserved += ring_attr->num_tmo;
1381 TMR_DBG_PRINT("Updated ring reserve by +%u to %u\n", ring_attr->num_tmo,
1382 tmrs->ring_reserved);
1383#endif
1384
1385 tmrs->num_rings++;
1386 tmrs->num_timers++;
1387 timer->num_ring_reserve = ring_attr->num_tmo;
1388 timer->flags = ring_attr->flags;
1389 timer->plain_q_ok = capa.queue_type_plain;
1390 timer->is_ring = true;
1391 tmrs->num_ring_create_calls++;
1392
1393 if (odp_timer_pool_start_multi(&timer->odp_tmr_pool, 1) != 1) {
1394 reason = "odp_timer_pool_start_multi failed";
1395 goto error_locked;
1396 }
1397
1398 odp_ticketlock_unlock(&em_shm->timers.timer_lock);
1399
1400 TMR_DBG_PRINT("ret %" PRI_TMR ", total timers %u\n", TMR_I2H(i), tmrs->num_timers);
1401 return TMR_I2H(i);
1402
1403error_locked:
1404 cleanup_timer_create_fail(timer);
1405 odp_ticketlock_unlock(&tmrs->timer_lock);
1407 "Ring%s timer create failed: %s",
1408 kind == RING_KIND_FREQ ? " freq" : "", reason);
1409 return EM_TIMER_UNDEF;
1410}
1411
1412em_timer_t em_timer_ring_create(const em_timer_attr_t *ring_attr)
1413{
1414 /* timers are initialized? */
1415 if (unlikely(em_shm->timers.init_check != EM_CHECK_INIT_CALLED)) {
1416 INTERNAL_ERROR(EM_ERR_NOT_INITIALIZED, EM_ESCOPE_TIMER_CREATE,
1417 "Timer is disabled!");
1418 return EM_TIMER_UNDEF;
1419 }
1420
1421 if (EM_CHECK_LEVEL > 0 && unlikely(check_timer_attr_ring(ring_attr) == false)) {
1422 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_RING_CREATE,
1423 "NULL or incorrect attribute");
1424 return EM_TIMER_UNDEF;
1425 }
1426
1427 return ring_create_common(ring_attr, RING_KIND_BASE_MUL);
1428}
1429
1430em_timer_t em_timer_ring_freq_create(const em_timer_attr_t *ring_attr)
1431{
1432#if PRE_1_50_ODP_TIMER_API
1433 (void)ring_attr;
1434 INTERNAL_ERROR(EM_ERR_NOT_IMPLEMENTED, EM_ESCOPE_TIMER_RING_FREQ_CREATE,
1435 "Freq-based ring timer not supported by this ODP version");
1436 return EM_TIMER_UNDEF;
1437#else
1438 /* timers are initialized? */
1439 if (unlikely(em_shm->timers.init_check != EM_CHECK_INIT_CALLED)) {
1440 INTERNAL_ERROR(EM_ERR_NOT_INITIALIZED, EM_ESCOPE_TIMER_RING_FREQ_CREATE,
1441 "Timer is disabled!");
1442 return EM_TIMER_UNDEF;
1443 }
1444
1445 if (EM_CHECK_LEVEL > 0 && unlikely(check_timer_attr_ring_freq(ring_attr) == false))
1446 return EM_TIMER_UNDEF;
1447
1448 return ring_create_common(ring_attr, RING_KIND_FREQ);
1449#endif /* !PRE_1_50_ODP_TIMER_API */
1450}
1451
1453{
1454 timer_storage_t *const tmrs = &em_shm->timers;
1455 int i = TMR_H2I(tmr);
1456 em_status_t rv = EM_OK;
1457 odp_pool_t pool_fail = ODP_POOL_INVALID;
1458
1459 /* take lock before checking so nothing can change */
1460 odp_ticketlock_lock(&tmrs->timer_lock);
1461 if (unlikely(!is_timer_valid(tmr))) {
1462 odp_ticketlock_unlock(&tmrs->timer_lock);
1463 return INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_DELETE,
1464 "Invalid timer:%" PRI_TMR "", tmr);
1465 }
1466
1467 if (tmrs->timer[i].tmo_pool != tmrs->shared_tmo_pool) { /* don't delete shared pool */
1468 if (unlikely(odp_pool_destroy(tmrs->timer[i].tmo_pool) != 0)) {
1469 rv = EM_ERR_LIB_FAILED;
1470 pool_fail = tmrs->timer[i].tmo_pool;
1471 } else {
1472 TMR_DBG_PRINT("Deleted odp pool %p\n", tmrs->timer[i].tmo_pool);
1473 }
1474 }
1475 tmrs->timer[i].tmo_pool = ODP_POOL_INVALID;
1476 odp_timer_pool_destroy(tmrs->timer[i].odp_tmr_pool);
1477 tmrs->timer[i].odp_tmr_pool = ODP_TIMER_POOL_INVALID;
1478
1479 /* Ring delete. ODP timeout pool is destroyed with the timer pool. */
1480 if (tmrs->timer[i].is_ring && tmrs->num_rings) {
1481 tmrs->num_rings--;
1482 if (tmrs->num_rings < 1)
1483 TMR_DBG_PRINT("Last ring deleted\n");
1484#if PRE_1_50_ODP_TIMER_API
1485 tmrs->ring_reserved -= tmrs->timer[i].num_ring_reserve;
1486 TMR_DBG_PRINT("Updated ring reserve by -%u to %u\n",
1487 tmrs->timer[i].num_ring_reserve, tmrs->ring_reserved);
1488#endif
1489 tmrs->timer[i].num_ring_reserve = 0;
1490 }
1491
1492 tmrs->num_timers--;
1493 if (tmrs->shared_tmo_pool != ODP_POOL_INVALID) { /* shared pool in use */
1494 tmrs->reserved -= tmrs->timer[i].num_tmo_reserve;
1495 TMR_DBG_PRINT("Updated tmo reserve by -%u to %u\n",
1496 tmrs->timer[i].num_tmo_reserve, tmrs->reserved);
1497 tmrs->timer[i].num_tmo_reserve = 0;
1498 }
1499 if (tmrs->num_timers == 0 && tmrs->shared_tmo_pool != ODP_POOL_INVALID) {
1500 /* no more timers, delete shared tmo pool */
1501 if (unlikely(odp_pool_destroy(tmrs->shared_tmo_pool) != 0)) {
1502 rv = EM_ERR_LIB_FAILED;
1503 pool_fail = tmrs->shared_tmo_pool;
1504 } else {
1505 TMR_DBG_PRINT("Deleted shared tmo pool %p\n", tmrs->shared_tmo_pool);
1506 tmrs->shared_tmo_pool = ODP_POOL_INVALID;
1507 }
1508 }
1509
1510 odp_ticketlock_unlock(&tmrs->timer_lock);
1511 if (unlikely(rv != EM_OK)) {
1512 return INTERNAL_ERROR(rv, EM_ESCOPE_TIMER_DELETE,
1513 "timer %p delete fail, odp pool %p fail\n", tmr, pool_fail);
1514 }
1515 TMR_DBG_PRINT("ok, deleted timer %p, num_timers %u\n", tmr, tmrs->num_timers);
1516 return rv;
1517}
1518
1520{
1521 const timer_storage_t *const tmrs = &em_shm->timers;
1522 int i = TMR_H2I(tmr);
1523
1524 if (EM_CHECK_LEVEL > 0 && !is_timer_valid(tmr))
1525 return 0;
1526
1527 return odp_timer_current_tick(tmrs->timer[i].odp_tmr_pool);
1528}
1529
1530em_tmo_t em_tmo_create(em_timer_t tmr, em_tmo_flag_t flags, em_queue_t queue)
1531{
1532 return em_tmo_create_arg(tmr, flags, queue, NULL);
1533}
1534
1536 em_queue_t queue, em_tmo_args_t *args)
1537{
1538 const queue_elem_t *const q_elem = queue_elem_get(queue);
1539
1540 if (EM_CHECK_LEVEL > 0) {
1541 if (unlikely(!is_timer_valid(tmr))) {
1542 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_CREATE,
1543 "Invalid timer:%" PRI_TMR "", tmr);
1544 return EM_TMO_UNDEF;
1545 }
1546 if (unlikely(q_elem == NULL || !queue_allocated(q_elem))) {
1547 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_CREATE,
1548 "Tmr:%" PRI_TMR ": inv.Q:%" PRI_QUEUE "",
1549 tmr, queue);
1550 return EM_TMO_UNDEF;
1551 }
1552 if (unlikely(!is_queue_valid_type(tmr, q_elem))) {
1553 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_CREATE,
1554 "Tmr:%" PRI_TMR ": inv.Q (type):%" PRI_QUEUE "",
1555 tmr, queue);
1556 return EM_TMO_UNDEF;
1557 }
1558 if (unlikely(!check_tmo_flags(flags))) {
1559 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_CREATE,
1560 "Tmr:%" PRI_TMR ": inv. tmo-flags:0x%x",
1561 tmr, flags);
1562 return EM_TMO_UNDEF;
1563 }
1564 }
1565
1566 int i = TMR_H2I(tmr);
1567
1568 if (EM_CHECK_LEVEL > 1 &&
1569 em_shm->timers.timer[i].is_ring &&
1570 !(flags & EM_TMO_FLAG_PERIODIC)) {
1571 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_CREATE,
1572 "Tmr:%" PRI_TMR ": asking oneshot with ring timer!",
1573 tmr);
1574 return EM_TMO_UNDEF;
1575 }
1576
1577 odp_buffer_t tmo_buf = odp_buffer_alloc(em_shm->timers.timer[i].tmo_pool);
1578
1579 if (unlikely(tmo_buf == ODP_BUFFER_INVALID)) {
1580 INTERNAL_ERROR(EM_ERR_ALLOC_FAILED, EM_ESCOPE_TMO_CREATE,
1581 "Tmr:%" PRI_TMR ": tmo pool exhausted", tmr);
1582 return EM_TMO_UNDEF;
1583 }
1584
1585 em_timer_timeout_t *tmo = odp_buffer_addr(tmo_buf);
1586 odp_timer_pool_t odptmr = em_shm->timers.timer[i].odp_tmr_pool;
1587
1588 const void *userptr = NULL;
1589
1590 if (args != NULL)
1591 userptr = args->userptr;
1592
1593#if PRE_1_50_ODP_TIMER_API
1594 tmo->odp_timer = odp_timer_alloc(odptmr, q_elem->odp_queue, userptr);
1595 if (unlikely(tmo->odp_timer == ODP_TIMER_INVALID)) {
1596 INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_TMO_CREATE,
1597 "Tmr:%" PRI_TMR ": odp_timer_alloc() failed", tmr);
1598 odp_buffer_free(tmo_buf);
1599 return EM_TMO_UNDEF;
1600 }
1601
1602#else
1603 /*
1604 * Ring timers use odp_timer_periodic_alloc() which requires
1605 * freq_multiplier. Defer allocation to em_tmo_set_periodic_ring().
1606 */
1607 if (!em_shm->timers.timer[i].is_ring) {
1608 tmo->odp_timer = odp_timer_alloc(odptmr, q_elem->odp_queue, userptr);
1609 if (unlikely(tmo->odp_timer == ODP_TIMER_INVALID)) {
1610 INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_TMO_CREATE,
1611 "Tmr:%" PRI_TMR ": odp_timer_alloc() failed", tmr);
1612 odp_buffer_free(tmo_buf);
1613 return EM_TMO_UNDEF;
1614 }
1615 } else {
1616 tmo->odp_timer = ODP_TIMER_INVALID;
1617 }
1618#endif
1619
1620 /* OK, init state. Some values copied for faster access runtime */
1621 tmo->period = 0;
1622 tmo->odp_timer_pool = odptmr;
1623 tmo->timer = tmr;
1624 tmo->odp_buffer = tmo_buf;
1625 tmo->flags = flags;
1626 tmo->queue = queue;
1627 tmo->is_ring = em_shm->timers.timer[i].is_ring;
1628 tmo->odp_timeout = ODP_EVENT_INVALID;
1629
1630#if PRE_1_50_ODP_TIMER_API
1631 tmo->ring_tmo_pool = em_shm->timers.ring_tmo_pool;
1632
1633 if (tmo->is_ring) { /* pre-allocate timeout event to save time at start */
1634 odp_event_t odp_tmo_event = alloc_odp_timeout(tmo);
1635
1636 if (unlikely(odp_tmo_event == ODP_EVENT_INVALID)) {
1637 INTERNAL_ERROR(EM_ERR_ALLOC_FAILED, EM_ESCOPE_TMO_CREATE,
1638 "Ring: odp timeout event allocation failed");
1639 odp_timer_free(tmo->odp_timer);
1640 odp_buffer_free(tmo_buf);
1641 return EM_TMO_UNDEF;
1642 }
1643 tmo->odp_timeout = odp_tmo_event;
1644 TMR_DBG_PRINT("Ring: allocated odp timeout ev %p\n", tmo->odp_timeout);
1645 }
1646#else
1647 tmo->ring_tmo_pool = ODP_POOL_INVALID;
1648 tmo->user_ptr = userptr;
1649 tmo->multiplier = 0;
1650 tmo->freq_hz = (em_fract_u64_t){0};
1651#endif
1652
1653 if (EM_TIMER_TMO_STATS)
1654 memset(&tmo->stats, 0, sizeof(em_tmo_stats_t));
1655
1656 odp_atomic_init_u32(&tmo->state, EM_TMO_STATE_IDLE);
1657 TMR_DBG_PRINT("ODP timer %p allocated\n", tmo->odp_timer);
1658 TMR_DBG_PRINT("tmo %p created\n", tmo);
1659 return tmo;
1660}
1661
1663{
1664 if (EM_CHECK_LEVEL > 0) {
1666 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_DELETE,
1667 "Invalid args: tmo:%" PRI_TMO, tmo);
1668 }
1669
1670 em_tmo_state_t tmo_state = odp_atomic_load_acq_u32(&tmo->state);
1671
1672 if (EM_CHECK_LEVEL > 1) {
1673 /* check that tmo buf is valid before accessing other struct members */
1674 RETURN_ERROR_IF(!odp_buffer_is_valid(tmo->odp_buffer),
1675 EM_ERR_BAD_ID, EM_ESCOPE_TMO_DELETE,
1676 "Invalid tmo buffer");
1677
1678 RETURN_ERROR_IF(tmo_state == EM_TMO_STATE_UNKNOWN,
1679 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_DELETE,
1680 "Invalid tmo state:%d", tmo_state);
1681
1682#if PRE_1_50_ODP_TIMER_API
1683 RETURN_ERROR_IF(tmo->odp_timer == ODP_TIMER_INVALID,
1684 EM_ERR_BAD_ID, EM_ESCOPE_TMO_DELETE,
1685 "Invalid tmo odp_timer, deleted?");
1686#else
1687 /* Ring timers defer ODP allocation to set_periodic_ring() */
1688 RETURN_ERROR_IF(!tmo->is_ring && tmo->odp_timer == ODP_TIMER_INVALID,
1689 EM_ERR_BAD_ID, EM_ESCOPE_TMO_DELETE,
1690 "Invalid tmo odp_timer, deleted?");
1691#endif
1692 }
1693
1694 TMR_DBG_PRINT("ODP timer %p\n", tmo->odp_timer);
1695
1696 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_UNKNOWN);
1697
1698#if PRE_1_50_ODP_TIMER_API
1699 int fret = odp_timer_free(tmo->odp_timer);
1700
1701 RETURN_ERROR_IF(fret != 0, EM_ERR_LIB_FAILED, EM_ESCOPE_TMO_DELETE,
1702 "odp timer free failed!?, rv %d\n", fret);
1703
1704 /* Old API: manually free pre-allocated ring timeout event.
1705 * New API: odp_timer_free() releases the internally managed event.
1706 */
1707 if (tmo->is_ring && tmo->odp_timeout != ODP_EVENT_INVALID) {
1708 TMR_DBG_PRINT("ring: free unused ODP timeout ev %p\n", tmo->odp_timeout);
1709 free_odp_timeout(tmo->odp_timeout);
1710 tmo->odp_timeout = ODP_EVENT_INVALID;
1711 }
1712#else
1713 /* Ring timers may not have an ODP timer if never started */
1714 if (tmo->odp_timer != ODP_TIMER_INVALID) {
1715 int fret = odp_timer_free(tmo->odp_timer);
1716
1717 RETURN_ERROR_IF(fret != 0, EM_ERR_LIB_FAILED, EM_ESCOPE_TMO_DELETE,
1718 "odp timer free failed!?, rv %d\n", fret);
1719 }
1720#endif
1721 odp_buffer_t tmp = tmo->odp_buffer;
1722
1723 tmo->odp_timer = ODP_TIMER_INVALID;
1724 tmo->odp_buffer = ODP_BUFFER_INVALID;
1725
1726 odp_buffer_free(tmp);
1727
1728 TMR_DBG_PRINT("tmo %p delete ok\n", tmo);
1729
1730 return EM_OK;
1731}
1732
1734 em_event_t tmo_ev)
1735{
1737 (tmo == EM_TMO_UNDEF || tmo_ev == EM_EVENT_UNDEF),
1738 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_ABS,
1739 "Inv.args: tmo:%" PRI_TMO " ev:%" PRI_EVENT "",
1740 tmo, tmo_ev);
1741 /* check that tmo buf is valid before accessing other struct members */
1742 RETURN_ERROR_IF(EM_CHECK_LEVEL > 1 && !odp_buffer_is_valid(tmo->odp_buffer),
1743 EM_ERR_BAD_ID, EM_ESCOPE_TMO_SET_ABS,
1744 "Invalid tmo buffer");
1746 (tmo->flags & EM_TMO_FLAG_PERIODIC),
1747 EM_ERR_BAD_CONTEXT, EM_ESCOPE_TMO_SET_ABS,
1748 "Cannot set periodic tmo, use _set_periodic()");
1749 if (EM_CHECK_LEVEL > 1) {
1750 em_tmo_state_t tmo_state = odp_atomic_load_acq_u32(&tmo->state);
1751
1752 RETURN_ERROR_IF(tmo_state == EM_TMO_STATE_UNKNOWN,
1753 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_SET_ABS,
1754 "Invalid tmo state:%d", tmo_state);
1755 }
1757 tmo->odp_timer == ODP_TIMER_INVALID,
1758 EM_ERR_BAD_ID, EM_ESCOPE_TMO_SET_ABS,
1759 "Invalid tmo odp_timer");
1760
1761 event_hdr_t *ev_hdr = event_to_hdr(tmo_ev);
1762 odp_event_t odp_ev = event_em2odp(tmo_ev);
1763 bool esv_ena = esv_enabled();
1764 odp_timer_start_t startp;
1765
1766 if (EM_CHECK_LEVEL > 0) {
1767 em_event_type_t evtype_major = em_event_type_major(ev_hdr->event_type);
1768
1770 !is_event_type_valid(evtype_major),
1771 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_ABS,
1772 "Invalid event type:%u", evtype_major);
1774 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_ABS,
1775 "Invalid event type: timer-ring");
1776 }
1777
1778 if (esv_ena)
1779 evstate_usr2em(tmo_ev, ev_hdr, EVSTATE__TMO_SET_ABS);
1780
1781 /* set tmo active and arm with absolute time */
1782 startp.tick_type = ODP_TIMER_TICK_ABS;
1783 startp.tick = ticks_abs;
1784 startp.tmo_ev = odp_ev;
1786 ev_hdr->tmo = tmo;
1787 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_ACTIVE);
1788 int odpret = odp_timer_start(tmo->odp_timer, &startp);
1789
1790 if (unlikely(odpret != ODP_TIMER_SUCCESS)) {
1792 ev_hdr->tmo = EM_TMO_UNDEF;
1793 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_IDLE);
1794 if (esv_ena)
1795 evstate_usr2em_revert(tmo_ev, ev_hdr, EVSTATE__TMO_SET_ABS__FAIL);
1796
1797 em_status_t retval = timer_rv_odp2em(odpret);
1798
1799 if (retval == EM_ERR_TOONEAR) { /* skip errorhandler */
1800 TMR_DBG_PRINT("TOONEAR, skip ErrH\n");
1801 return retval;
1802 }
1803 if (retval == EM_ERR_BUSY) { /* skip errorhandler */
1804 TMR_DBG_PRINT("BUSY, skip ErrH\n");
1805 return retval;
1806 }
1807 return INTERNAL_ERROR(retval, EM_ESCOPE_TMO_SET_ABS,
1808 "odp_timer_start():%d", odpret);
1809 }
1810 TMR_DBG_PRINT("OK\n");
1811 return EM_OK;
1812}
1813
1815 em_event_t tmo_ev)
1816{
1817 if (EM_CHECK_LEVEL > 0) {
1818 RETURN_ERROR_IF(tmo == EM_TMO_UNDEF || tmo_ev == EM_EVENT_UNDEF,
1819 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_REL,
1820 "Inv.args: tmo:%" PRI_TMO " ev:%" PRI_EVENT "",
1821 tmo, tmo_ev);
1822
1824 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_REL,
1825 "%s: Periodic no longer supported", __func__);
1826 }
1827 if (EM_CHECK_LEVEL > 1) {
1828 /* check that tmo buf is valid before accessing other struct members */
1829 RETURN_ERROR_IF(!odp_buffer_is_valid(tmo->odp_buffer),
1830 EM_ERR_BAD_ID, EM_ESCOPE_TMO_SET_REL,
1831 "Invalid tmo buffer");
1832
1833 em_tmo_state_t tmo_state = odp_atomic_load_acq_u32(&tmo->state);
1834
1835 RETURN_ERROR_IF(tmo_state == EM_TMO_STATE_UNKNOWN,
1836 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_SET_REL,
1837 "Invalid tmo state:%d", tmo_state);
1838 }
1839
1840 event_hdr_t *ev_hdr = event_to_hdr(tmo_ev);
1841 odp_event_t odp_ev = event_em2odp(tmo_ev);
1842 bool esv_ena = esv_enabled();
1843 odp_timer_start_t startp;
1844
1845 if (EM_CHECK_LEVEL > 0) {
1846 em_event_type_t evtype_major = em_event_type_major(ev_hdr->event_type);
1847
1849 !is_event_type_valid(evtype_major),
1850 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_REL,
1851 "Invalid event type:%u", evtype_major);
1853 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_REL,
1854 "Invalid event type: timer-ring");
1855 }
1856
1857 if (esv_ena)
1858 evstate_usr2em(tmo_ev, ev_hdr, EVSTATE__TMO_SET_REL);
1859
1860 /* set tmo active and arm with relative time */
1861 startp.tick_type = ODP_TIMER_TICK_REL;
1862 startp.tick = ticks_rel;
1863 startp.tmo_ev = odp_ev;
1865 ev_hdr->tmo = tmo;
1866 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_ACTIVE);
1867 int odpret = odp_timer_start(tmo->odp_timer, &startp);
1868
1869 if (unlikely(odpret != ODP_TIMER_SUCCESS)) {
1871 ev_hdr->tmo = EM_TMO_UNDEF;
1872 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_IDLE);
1873 if (esv_ena)
1874 evstate_usr2em_revert(tmo_ev, ev_hdr, EVSTATE__TMO_SET_REL__FAIL);
1875
1876 em_status_t retval = timer_rv_odp2em(odpret);
1877
1878 if (retval == EM_ERR_TOONEAR) { /* skip errorhandler */
1879 TMR_DBG_PRINT("TOONEAR, skip ErrH\n");
1880 return retval;
1881 }
1882 if (retval == EM_ERR_BUSY) { /* skip errorhandler */
1883 TMR_DBG_PRINT("BUSY, skip ErrH\n");
1884 return retval;
1885 }
1886 return INTERNAL_ERROR(retval, EM_ESCOPE_TMO_SET_REL,
1887 "odp_timer_start():%d", odpret);
1888 }
1889 TMR_DBG_PRINT("OK\n");
1890 return EM_OK;
1891}
1892
1894 em_timer_tick_t start_abs,
1895 em_timer_tick_t period,
1896 em_event_t tmo_ev)
1897{
1899 (tmo == EM_TMO_UNDEF || tmo_ev == EM_EVENT_UNDEF),
1900 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_PERIODIC,
1901 "Inv.args: tmo:%" PRI_TMO " ev:%" PRI_EVENT "",
1902 tmo, tmo_ev);
1903 /* check that tmo buf is valid before accessing other struct members */
1904 RETURN_ERROR_IF(EM_CHECK_LEVEL > 1 && !odp_buffer_is_valid(tmo->odp_buffer),
1905 EM_ERR_BAD_ID, EM_ESCOPE_TMO_SET_PERIODIC,
1906 "Invalid tmo buffer");
1908 EM_ERR_BAD_CONTEXT, EM_ESCOPE_TMO_SET_PERIODIC,
1909 "Not periodic tmo");
1910 if (EM_CHECK_LEVEL > 1) {
1911 em_tmo_state_t tmo_state = odp_atomic_load_acq_u32(&tmo->state);
1912
1913 RETURN_ERROR_IF(tmo_state == EM_TMO_STATE_UNKNOWN,
1914 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_SET_PERIODIC,
1915 "Invalid tmo state:%d", tmo_state);
1916 }
1917
1918 event_hdr_t *ev_hdr = event_to_hdr(tmo_ev);
1919 odp_event_t odp_ev = event_em2odp(tmo_ev);
1920 bool esv_ena = esv_enabled();
1921 odp_timer_start_t startp;
1922
1923 if (EM_CHECK_LEVEL > 0) {
1924 em_event_type_t evtype_major = em_event_type_major(ev_hdr->event_type);
1925
1927 !is_event_type_valid(evtype_major),
1928 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_PERIODIC,
1929 "invalid event type");
1931 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_PERIODIC,
1932 "Invalid event type: timer-ring");
1933 }
1934
1935 if (esv_ena)
1936 evstate_usr2em(tmo_ev, ev_hdr, EVSTATE__TMO_SET_PERIODIC);
1937
1938 TMR_DBG_PRINT("start %lu, period %lu\n", start_abs, period);
1939
1940 tmo->period = period;
1941 if (start_abs == 0)
1942 start_abs = odp_timer_current_tick(tmo->odp_timer_pool) + period;
1943 tmo->last_tick = start_abs;
1944 TMR_DBG_PRINT("last_tick %lu, now %lu\n", tmo->last_tick,
1945 odp_timer_current_tick(tmo->odp_timer_pool));
1946
1947 /* set tmo active and arm with absolute time */
1948 startp.tick_type = ODP_TIMER_TICK_ABS;
1949 startp.tick = start_abs;
1950 startp.tmo_ev = odp_ev;
1952 ev_hdr->tmo = tmo;
1953 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_ACTIVE);
1954 int odpret = odp_timer_start(tmo->odp_timer, &startp);
1955
1956 if (unlikely(odpret != ODP_TIMER_SUCCESS)) {
1958 ev_hdr->tmo = EM_TMO_UNDEF;
1959 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_IDLE);
1960 if (esv_ena)
1961 evstate_usr2em_revert(tmo_ev, ev_hdr, EVSTATE__TMO_SET_PERIODIC__FAIL);
1962
1963 TMR_DBG_PRINT("diff to tmo %ld\n",
1964 (int64_t)tmo->last_tick -
1965 (int64_t)odp_timer_current_tick(tmo->odp_timer_pool));
1966
1967 em_status_t retval = timer_rv_odp2em(odpret);
1968
1969 if (retval == EM_ERR_TOONEAR) { /* skip errorhandler */
1970 TMR_DBG_PRINT("TOONEAR, skip ErrH\n");
1971 return retval;
1972 }
1973 if (retval == EM_ERR_BUSY) { /* skip errorhandler */
1974 TMR_DBG_PRINT("BUSY, skip ErrH\n");
1975 return retval;
1976 }
1977 return INTERNAL_ERROR(retval,
1978 EM_ESCOPE_TMO_SET_PERIODIC,
1979 "odp_timer_start():%d", odpret);
1980 }
1981 TMR_DBG_PRINT("OK\n");
1982 return EM_OK;
1983}
1984
1986 em_timer_tick_t start_abs,
1987 uint64_t multiplier)
1988{
1990 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_PERIODIC_RING,
1991 "Inv.args: tmo UNDEF");
1992 /* check that tmo buf is valid before accessing other struct members */
1993 RETURN_ERROR_IF(EM_CHECK_LEVEL > 1 && !odp_buffer_is_valid(tmo->odp_buffer),
1994 EM_ERR_BAD_ID, EM_ESCOPE_TMO_SET_PERIODIC_RING,
1995 "Invalid tmo buffer");
1997 EM_ERR_BAD_CONTEXT, EM_ESCOPE_TMO_SET_PERIODIC_RING,
1998 "Not periodic tmo");
2000 (em_shm->timers.timer[TMR_H2I(tmo->timer)].flags & EM_TIMER_FLAG_RING_FREQ),
2001 EM_ERR_BAD_CONTEXT, EM_ESCOPE_TMO_SET_PERIODIC_RING,
2002 "Timer created with EM_TIMER_FLAG_RING_FREQ, use em_tmo_set_periodic_ring_freq()");
2003 if (EM_CHECK_LEVEL > 1) {
2004 em_tmo_state_t tmo_state = odp_atomic_load_acq_u32(&tmo->state);
2005
2006 RETURN_ERROR_IF(tmo_state == EM_TMO_STATE_UNKNOWN ||
2007 tmo_state == EM_TMO_STATE_ACTIVE,
2008 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_SET_PERIODIC_RING,
2009 "Invalid tmo state:%d", tmo_state);
2010 }
2011
2012#if PRE_1_50_ODP_TIMER_API
2013 odp_timer_periodic_start_t startp;
2014 odp_event_t odp_ev = tmo->odp_timeout; /* pre-allocated */
2015
2016 tmo->odp_timeout = ODP_EVENT_INVALID; /* now used */
2017
2018 if (odp_ev == ODP_EVENT_INVALID) { /* re-start, pre-alloc used */
2019 odp_event_t odp_tmo_event = alloc_odp_timeout(tmo);
2020
2021 if (unlikely(odp_tmo_event == ODP_EVENT_INVALID))
2022 return INTERNAL_ERROR(EM_ERR_ALLOC_FAILED, EM_ESCOPE_TMO_SET_PERIODIC_RING,
2023 "Ring: odp timeout event allocation failed");
2024 odp_ev = odp_tmo_event;
2025 }
2026
2027 TMR_DBG_PRINT("ring tmo start_abs %lu, M=%lu, odp ev=%p\n", start_abs, multiplier, odp_ev);
2028 startp.first_tick = start_abs;
2029 startp.freq_multiplier = multiplier;
2030 startp.tmo_ev = odp_ev;
2031#else
2032 /*
2033 * ODP periodic timers are allocated with odp_timer_periodic_alloc() which
2034 * sets the freq_multiplier. If the timer is not yet allocated or the
2035 * multiplier changed, (re-)allocate.
2036 */
2037 if (tmo->odp_timer != ODP_TIMER_INVALID && tmo->multiplier != multiplier) {
2038 /* multiplier changed, free old timer and re-allocate */
2039 em_tmo_state_t cur_state = odp_atomic_load_acq_u32(&tmo->state);
2040
2042 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_SET_PERIODIC_RING,
2043 "Cannot change multiplier while tmo is active");
2044 odp_timer_free(tmo->odp_timer);
2045 tmo->odp_timer = ODP_TIMER_INVALID;
2046 }
2047
2048 if (tmo->odp_timer == ODP_TIMER_INVALID) {
2049 const queue_elem_t *q_elem = queue_elem_get(tmo->queue);
2050
2051 if (EM_CHECK_LEVEL > 1) {
2052 RETURN_ERROR_IF(q_elem == NULL || !queue_allocated(q_elem),
2053 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_PERIODIC_RING,
2054 "Invalid queue:%" PRI_QUEUE "", tmo->queue);
2055 }
2056
2057 odp_timer_periodic_param_t pparams;
2058
2059 odp_timer_periodic_param_init(&pparams);
2060 pparams.queue = q_elem->odp_queue;
2061 pparams.user_ptr = tmo->user_ptr;
2062 pparams.base_mul.multiplier = multiplier;
2063 pparams.uarea_init.init_fn = ring_tmo_uarea_init;
2064 pparams.uarea_init.args = tmo;
2065
2066 tmo->odp_timer = odp_timer_periodic_alloc(tmo->odp_timer_pool, &pparams);
2067 if (unlikely(tmo->odp_timer == ODP_TIMER_INVALID))
2068 return INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_TMO_SET_PERIODIC_RING,
2069 "odp_timer_periodic_alloc() failed");
2070 tmo->multiplier = multiplier;
2071 TMR_DBG_PRINT("Allocated periodic ODP timer %p, M=%lu\n",
2072 tmo->odp_timer, multiplier);
2073 }
2074
2075 TMR_DBG_PRINT("ring tmo start_abs %lu, M=%lu\n", start_abs, multiplier);
2076
2077 odp_timer_periodic_start_t startp;
2078
2079 startp.first_tick = start_abs;
2080#endif
2081 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_ACTIVE);
2082 int odpret = odp_timer_periodic_start(tmo->odp_timer, &startp);
2083
2084 if (unlikely(odpret != ODP_TIMER_SUCCESS)) {
2085 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_IDLE);
2086
2087 em_status_t retval = timer_rv_odp2em(odpret);
2088
2089 if (retval == EM_ERR_TOONEAR) { /* skip errorhandler */
2090 TMR_DBG_PRINT("TOONEAR, skip ErrH\n");
2091 return retval;
2092 }
2093 if (retval == EM_ERR_BUSY) { /* skip errorhandler */
2094 TMR_DBG_PRINT("BUSY, skip ErrH\n");
2095 return retval;
2096 }
2097 return INTERNAL_ERROR(retval,
2098 EM_ESCOPE_TMO_SET_PERIODIC_RING,
2099 "odp_timer_periodic_start(): ret %d", odpret);
2100 }
2101 /* ok */
2102 TMR_DBG_PRINT("OK\n");
2103 return EM_OK;
2104}
2105
2107 em_timer_tick_t start_abs,
2108 em_fract_u64_t freq_hz)
2109{
2110#if PRE_1_50_ODP_TIMER_API
2111 (void)tmo;
2112 (void)start_abs;
2113 (void)freq_hz;
2115#else
2117 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_PERIODIC_RING_FREQ,
2118 "Inv.args: tmo UNDEF");
2119 /* check that tmo buf is valid before accessing other struct members */
2120 RETURN_ERROR_IF(EM_CHECK_LEVEL > 1 && !odp_buffer_is_valid(tmo->odp_buffer),
2121 EM_ERR_BAD_ID, EM_ESCOPE_TMO_SET_PERIODIC_RING_FREQ,
2122 "Invalid tmo buffer");
2124 EM_ERR_BAD_CONTEXT, EM_ESCOPE_TMO_SET_PERIODIC_RING_FREQ,
2125 "Not periodic tmo");
2127 !(em_shm->timers.timer[TMR_H2I(tmo->timer)].flags &
2129 EM_ERR_BAD_CONTEXT, EM_ESCOPE_TMO_SET_PERIODIC_RING_FREQ,
2130 "Timer not created with EM_TIMER_FLAG_RING_FREQ");
2131 RETURN_ERROR_IF(EM_CHECK_LEVEL > 0 && (freq_hz.numer != 0 && freq_hz.denom == 0),
2132 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_PERIODIC_RING_FREQ,
2133 "Invalid freq_hz, denom cannot be 0 if numer is not 0");
2134 RETURN_ERROR_IF(EM_CHECK_LEVEL > 0 && freq_hz.integer == 0 && freq_hz.numer == 0,
2135 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_PERIODIC_RING_FREQ,
2136 "freq_hz is 0");
2137 if (EM_CHECK_LEVEL > 1) {
2138 em_tmo_state_t tmo_state = odp_atomic_load_acq_u32(&tmo->state);
2139
2140 RETURN_ERROR_IF(tmo_state == EM_TMO_STATE_UNKNOWN ||
2141 tmo_state == EM_TMO_STATE_ACTIVE,
2142 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_SET_PERIODIC_RING_FREQ,
2143 "Invalid tmo state:%d", tmo_state);
2144 }
2145
2146 /*
2147 * ODP periodic timers are allocated with odp_timer_periodic_alloc() which
2148 * sets the freq_hz. If the timer is not yet allocated or the freq changed,
2149 * (re-)allocate.
2150 */
2151 if (tmo->odp_timer != ODP_TIMER_INVALID &&
2152 (tmo->freq_hz.integer != freq_hz.integer ||
2153 tmo->freq_hz.numer != freq_hz.numer ||
2154 tmo->freq_hz.denom != freq_hz.denom)) {
2155 /* freq changed, free old timer and re-allocate */
2156 em_tmo_state_t cur_state = odp_atomic_load_acq_u32(&tmo->state);
2157
2159 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_SET_PERIODIC_RING_FREQ,
2160 "Cannot change freq while tmo is active");
2161 odp_timer_free(tmo->odp_timer);
2162 tmo->odp_timer = ODP_TIMER_INVALID;
2163 }
2164
2165 if (tmo->odp_timer == ODP_TIMER_INVALID) {
2166 const queue_elem_t *q_elem = queue_elem_get(tmo->queue);
2167
2168 if (EM_CHECK_LEVEL > 1) {
2169 RETURN_ERROR_IF(q_elem == NULL || !queue_allocated(q_elem),
2170 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_SET_PERIODIC_RING_FREQ,
2171 "Invalid queue:%" PRI_QUEUE "", tmo->queue);
2172 }
2173
2174 odp_timer_periodic_param_t pparams;
2175
2176 odp_timer_periodic_param_init(&pparams);
2177 pparams.queue = q_elem->odp_queue;
2178 pparams.user_ptr = tmo->user_ptr;
2179 pparams.freq.freq_hz.integer = freq_hz.integer;
2180 pparams.freq.freq_hz.numer = freq_hz.numer;
2181 pparams.freq.freq_hz.denom = freq_hz.denom;
2182 pparams.uarea_init.init_fn = ring_tmo_uarea_init;
2183 pparams.uarea_init.args = tmo;
2184
2185 tmo->odp_timer = odp_timer_periodic_alloc(tmo->odp_timer_pool, &pparams);
2186 if (unlikely(tmo->odp_timer == ODP_TIMER_INVALID))
2188 EM_ESCOPE_TMO_SET_PERIODIC_RING_FREQ,
2189 "odp_timer_periodic_alloc() failed");
2190 tmo->freq_hz.integer = freq_hz.integer;
2191 tmo->freq_hz.numer = freq_hz.numer;
2192 tmo->freq_hz.denom = freq_hz.denom;
2193 TMR_DBG_PRINT("Allocated periodic freq ODP timer %p, freq=%lu %lu/%lu.\n",
2194 tmo->odp_timer, freq_hz.integer, freq_hz.numer, freq_hz.denom);
2195 }
2196
2197 TMR_DBG_PRINT("ring freq tmo start_abs %lu, freq=%lu %lu/%lu\n",
2198 start_abs, freq_hz.integer, freq_hz.numer, freq_hz.denom);
2199
2200 odp_timer_periodic_start_t startp;
2201
2202 startp.first_tick = start_abs;
2203
2204 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_ACTIVE);
2205 int odpret = odp_timer_periodic_start(tmo->odp_timer, &startp);
2206
2207 if (unlikely(odpret != ODP_TIMER_SUCCESS)) {
2208 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_IDLE);
2209
2210 em_status_t retval = timer_rv_odp2em(odpret);
2211
2212 if (retval == EM_ERR_TOONEAR) { /* skip errorhandler */
2213 TMR_DBG_PRINT("TOONEAR, skip ErrH\n");
2214 return retval;
2215 }
2216 if (retval == EM_ERR_BUSY) { /* skip errorhandler */
2217 TMR_DBG_PRINT("BUSY, skip ErrH\n");
2218 return retval;
2219 }
2220 return INTERNAL_ERROR(retval,
2221 EM_ESCOPE_TMO_SET_PERIODIC_RING_FREQ,
2222 "odp_timer_periodic_start(): ret %d", odpret);
2223 }
2224 /* ok */
2225 TMR_DBG_PRINT("OK\n");
2226 return EM_OK;
2227#endif /* !PRE_1_50_ODP_TIMER_API */
2228}
2229
2230em_status_t em_tmo_cancel(em_tmo_t tmo, em_event_t *cur_event)
2231{
2232 if (EM_CHECK_LEVEL > 0) {
2233 RETURN_ERROR_IF(tmo == EM_TMO_UNDEF || cur_event == NULL,
2234 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_CANCEL,
2235 "Invalid args: tmo:%" PRI_TMO " cur_event:%p",
2236 tmo, cur_event);
2237 }
2238 *cur_event = EM_EVENT_UNDEF;
2239 if (EM_CHECK_LEVEL > 1) {
2240 RETURN_ERROR_IF(!odp_buffer_is_valid(tmo->odp_buffer),
2241 EM_ERR_BAD_ID, EM_ESCOPE_TMO_CANCEL,
2242 "Invalid tmo buffer");
2243 RETURN_ERROR_IF(tmo->odp_timer == ODP_TIMER_INVALID,
2244 EM_ERR_BAD_ID, EM_ESCOPE_TMO_CANCEL,
2245 "Invalid tmo odp_timer");
2246 }
2247
2248 /* check state: EM_TMO_STATE_UNKNOWN | EM_TMO_STATE_IDLE | EM_TMO_STATE_ACTIVE */
2249 em_tmo_state_t tmo_state = odp_atomic_load_acq_u32(&tmo->state);
2250
2252 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_CANCEL,
2253 "Invalid tmo state:%d (!%d)", tmo_state, EM_TMO_STATE_ACTIVE);
2254
2255 TMR_DBG_PRINT("ODP tmo %p\n", tmo->odp_timer);
2256
2257 odp_atomic_store_rel_u32(&tmo->state, EM_TMO_STATE_IDLE);
2258
2259 if (tmo->is_ring) { /* periodic ring never returns event here */
2260 RETURN_ERROR_IF(odp_timer_periodic_cancel(tmo->odp_timer) != 0,
2261 EM_ERR_LIB_FAILED, EM_ESCOPE_TMO_CANCEL,
2262 "odp periodic cancel fail");
2263 return EM_ERR_TOONEAR; /* ack will tell when no more coming */
2264 }
2265
2266 /* not ring, cancel*/
2267 odp_event_t odp_ev = ODP_EVENT_INVALID;
2268 int ret = odp_timer_cancel(tmo->odp_timer, &odp_ev);
2269
2270 if (ret == ODP_TIMER_TOO_NEAR) {
2271 if (EM_CHECK_LEVEL > 1) {
2272 RETURN_ERROR_IF(odp_ev != ODP_EVENT_INVALID,
2273 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_CANCEL,
2274 "ODP timer cancel return TOONEAR but return event!");
2275 }
2276 TMR_DBG_PRINT("ODP returned TOONEAR\n");
2277 return EM_ERR_TOONEAR;
2278 }
2279
2280 RETURN_ERROR_IF(ret == ODP_TIMER_FAIL,
2281 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_CANCEL,
2282 "ODP timer cancel fail!");
2283
2284 /*
2285 * Cancel successful (ret == ODP_TIMER_SUCCESS): odp_ev contains the canceled tmo event
2286 */
2287
2288 if (EM_CHECK_LEVEL > 2) {
2289 RETURN_ERROR_IF(!odp_event_is_valid(odp_ev),
2290 EM_ERR_LIB_FAILED, EM_ESCOPE_TMO_CANCEL,
2291 "Invalid tmo event from odp_timer_cancel");
2292 }
2293
2294 em_event_t tmo_ev = event_odp2em(odp_ev);
2295 event_hdr_t *ev_hdr = event_to_hdr(tmo_ev);
2296
2297 /* successful cancel also resets the event tmo type */
2299 ev_hdr->tmo = EM_TMO_UNDEF;
2300
2301 if (esv_enabled())
2302 tmo_ev = evstate_em2usr(tmo_ev, ev_hdr, EVSTATE__TMO_CANCEL);
2303
2304 *cur_event = tmo_ev;
2305 TMR_DBG_PRINT("OK\n");
2306 return EM_OK;
2307}
2308
2309/*
2310 * Re-arm a periodic (non-ring) tmo for its next period, retrying on late/busy
2311 * timeouts. Returns EM_OK on success, or an error after restoring event state.
2312 * Kept 'static inline' so the compiler still inlines it into em_tmo_ack() and
2313 * the generated code (and performance) stays equivalent to the original.
2314 */
2315static inline em_status_t tmo_ack_rearm(em_tmo_t tmo, em_event_t next_tmo_ev,
2316 event_hdr_t *ev_hdr, odp_event_t odp_ev,
2317 bool esv_ena)
2318{
2319 int ret;
2320 int tries = EM_TIMER_ACK_TRIES;
2321 em_status_t err;
2322 odp_timer_start_t startp;
2323
2324 startp.tick_type = ODP_TIMER_TICK_ABS;
2325 startp.tmo_ev = odp_ev;
2326 ev_hdr->flags.tmo_type = EM_TMO_TYPE_PERIODIC; /* could be new event */
2327 ev_hdr->tmo = tmo;
2328
2329 /* try to set tmo EM_TIMER_ACK_TRIES times */
2330 do {
2331 /* ask new timeout for next period */
2332 startp.tick = tmo->last_tick;
2333 ret = odp_timer_start(tmo->odp_timer, &startp);
2334
2335 if (likely(ret == ODP_TIMER_SUCCESS))
2336 break; /* ok */
2337
2338#if !PRE_1_50_ODP_TIMER_API
2339 /*
2340 * ODP_TIMER_BUSY: the timer is being expired concurrently,
2341 * retry the same start (no skip) until it succeeds or the
2342 * retry limit is reached.
2343 */
2344 if (unlikely(ret == ODP_TIMER_BUSY)) {
2345 if (unlikely(--tries < 1)) {
2347 EM_ESCOPE_TMO_ACK,
2348 "Tmo ACK: too many retries (busy):%u",
2349 EM_TIMER_ACK_TRIES);
2350 goto ack_err;
2351 }
2352 TMR_DBG_PRINT("BUSY, retry\n");
2353 continue;
2354 }
2355#endif
2356
2357 /*
2358 * Calling ack() was delayed over next period if 'ret' is
2359 * ODP_TIMER_TOO_NEAR, i.e. now in past. Any other error is
2360 * unexpected and fatal for this tmo.
2361 */
2362 if (ret != ODP_TIMER_TOO_NEAR) {
2363 TMR_DBG_PRINT("ODP return %d\n"
2364 "tmo tgt/tick now %lu/%lu\n",
2365 ret, tmo->last_tick,
2366 odp_timer_current_tick(tmo->odp_timer_pool));
2367 err = INTERNAL_ERROR(EM_ERR_LIB_FAILED, EM_ESCOPE_TMO_ACK,
2368 "Tmo ACK: failed to renew tmo (odp ret %d)",
2369 ret);
2370 goto ack_err;
2371 }
2372
2373 /* ODP_TIMER_TOO_NEAR: ack() delayed beyond next time slot */
2374 if (EM_TIMER_TMO_STATS)
2375 tmo->stats.num_late_ack++;
2376 TMR_DBG_PRINT("late, tgt/now %lu/%lu\n", tmo->last_tick,
2377 odp_timer_current_tick(tmo->odp_timer_pool));
2378
2379 if (tmo->flags & EM_TMO_FLAG_NOSKIP) /* not allowed to skip, send immediately */
2380 return handle_ack_noskip(next_tmo_ev, ev_hdr, tmo->queue);
2381
2382 /* skip already passed periods and try again */
2383 handle_ack_skip(tmo);
2384
2385 if (unlikely(--tries < 1)) {
2387 EM_ESCOPE_TMO_ACK,
2388 "Tmo ACK: too many retries:%u",
2389 EM_TIMER_ACK_TRIES);
2390 goto ack_err;
2391 }
2392 } while (ret != ODP_TIMER_SUCCESS);
2393
2394 return EM_OK;
2395
2396ack_err:
2397 /* fail, restore event state */
2399 ev_hdr->tmo = EM_TMO_UNDEF;
2400 if (esv_ena)
2401 evstate_usr2em_revert(next_tmo_ev, ev_hdr, EVSTATE__TMO_ACK__FAIL);
2402 return err;
2403}
2404
2405em_status_t em_tmo_ack(em_tmo_t tmo, em_event_t next_tmo_ev)
2406{
2408 (tmo == EM_TMO_UNDEF || next_tmo_ev == EM_EVENT_UNDEF),
2409 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_ACK,
2410 "Inv.args: tmo:%" PRI_TMO " ev:%" PRI_EVENT "",
2411 tmo, next_tmo_ev);
2412 /* check that tmo buf is valid before accessing other struct members */
2413 RETURN_ERROR_IF(EM_CHECK_LEVEL > 1 && !odp_buffer_is_valid(tmo->odp_buffer),
2414 EM_ERR_BAD_ID, EM_ESCOPE_TMO_ACK,
2415 "Tmo ACK: invalid tmo buffer");
2417 EM_ERR_BAD_CONTEXT, EM_ESCOPE_TMO_ACK,
2418 "Tmo ACK: Not a periodic tmo");
2419
2420 if (EM_TIMER_TMO_STATS)
2421 tmo->stats.num_acks++;
2422
2423 em_tmo_state_t tmo_state = odp_atomic_load_acq_u32(&tmo->state);
2424 event_hdr_t *ev_hdr = event_to_hdr(next_tmo_ev);
2425
2427 EM_ERR_BAD_CONTEXT, EM_ESCOPE_TMO_ACK,
2428 "Tmo ACK: Given tmo event is not an EM event");
2429
2431 EM_ERR_BAD_CONTEXT, EM_ESCOPE_TMO_ACK,
2432 "Tmo ACK: Given tmo event is a timer-ring event");
2433
2434 odp_event_t odp_ev = event_em2odp(next_tmo_ev);
2435
2436 /* not periodic ring, set next timeout */
2437 if (unlikely(tmo_state != EM_TMO_STATE_ACTIVE)) {
2439 ev_hdr->tmo = EM_TMO_UNDEF;
2440
2441 if (tmo_state == EM_TMO_STATE_IDLE) /* canceled, skip errorhandler */
2442 return EM_ERR_CANCELED;
2443
2444 return INTERNAL_ERROR(EM_ERR_BAD_STATE, EM_ESCOPE_TMO_ACK,
2445 "Tmo ACK: invalid tmo state:%d", tmo_state);
2446 }
2447
2448 bool esv_ena = esv_enabled();
2449
2450 if (esv_ena)
2451 evstate_usr2em(next_tmo_ev, ev_hdr, EVSTATE__TMO_ACK);
2452 /*
2453 * The periodic timer will silently stop if ack fails! Attempt to
2454 * handle exceptions and if the tmo cannot be renewed, call
2455 * the errorhandler so the application may recover.
2456 */
2457 tmo->last_tick += tmo->period; /* maintain absolute time */
2458
2459 return tmo_ack_rearm(tmo, next_tmo_ev, ev_hdr, odp_ev, esv_ena);
2460}
2461
2462em_status_t em_tmo_ring_ack(em_tmo_t tmo, em_event_t tmo_ev)
2463{
2465 (tmo == EM_TMO_UNDEF || tmo_ev == EM_EVENT_UNDEF),
2466 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_RING_ACK,
2467 "Inv.args: tmo:%" PRI_TMO " ev:%" PRI_EVENT "",
2468 tmo, tmo_ev);
2469 /* check that tmo buf is valid before accessing other struct members */
2470 RETURN_ERROR_IF(EM_CHECK_LEVEL > 1 && !odp_buffer_is_valid(tmo->odp_buffer),
2471 EM_ERR_BAD_ID, EM_ESCOPE_TMO_RING_ACK,
2472 "Tmo ring ACK: invalid tmo buffer");
2473 RETURN_ERROR_IF(EM_CHECK_LEVEL > 0 && !tmo->is_ring,
2474 EM_ERR_BAD_CONTEXT, EM_ESCOPE_TMO_RING_ACK,
2475 "Tmo ring ACK: Not a ring tmo");
2476
2477 if (EM_TIMER_TMO_STATS)
2478 tmo->stats.num_acks++;
2479
2480 em_tmo_state_t tmo_state = odp_atomic_load_acq_u32(&tmo->state);
2481 event_hdr_t *ev_hdr = event_to_hdr(tmo_ev);
2482
2484 EM_ERR_BAD_CONTEXT, EM_ESCOPE_TMO_RING_ACK,
2485 "Tmo ring ACK: Given tmo event is not an EM event");
2486
2487 /*
2488 * No ESV (event state verification) tracking for ring timer events:
2489 * ODP manages the timeout event internally, so the application does
2490 * not own it and must not free or modify it.
2491 */
2492 odp_event_t odp_ev = event_em2odp(tmo_ev);
2493
2494 return ack_ring_timeout_event(tmo, tmo_ev, tmo_state, ev_hdr, odp_ev);
2495}
2496
2497int em_timer_list(em_timer_t tmr_list[], int max)
2498{
2499 odp_ticketlock_lock(&em_shm->timers.timer_lock);
2500
2501 const uint32_t num_timers = em_shm->timers.num_timers;
2502
2503 if (tmr_list && max > 0 && num_timers > 0) {
2504 int num = 0;
2505
2506 for (int i = 0; i < EM_ODP_MAX_TIMERS; i++) {
2507 if (em_shm->timers.timer[i].odp_tmr_pool != ODP_TIMER_POOL_INVALID) {
2508 tmr_list[num] = TMR_I2H(i);
2509 num++;
2510 if (num >= max)
2511 break;
2512 }
2513 }
2514 }
2515
2516 odp_ticketlock_unlock(&em_shm->timers.timer_lock);
2517
2518 return num_timers;
2519}
2520
2522{
2523 odp_timer_pool_info_t poolinfo;
2524 int i = TMR_H2I(tmr);
2525 int ret;
2526 em_timer_clksrc_t clk = EM_TIMER_CLKSRC_DEFAULT;
2527
2528 if (EM_CHECK_LEVEL > 0)
2529 RETURN_ERROR_IF(!is_timer_valid(tmr) || tmr_attr == NULL,
2530 EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_ATTR,
2531 "Inv.args: timer:%" PRI_TMR " tmr_attr:%p",
2532 tmr, tmr_attr);
2533
2534 /* get current values from ODP */
2535 ret = odp_timer_pool_info(em_shm->timers.timer[i].odp_tmr_pool, &poolinfo);
2536 RETURN_ERROR_IF(ret != 0, EM_ERR_LIB_FAILED, EM_ESCOPE_TIMER_ATTR,
2537 "ODP timer pool info failed");
2538
2539 timer_clksrc_odp2em(poolinfo.param.clk_src, &clk);
2540
2541 if (poolinfo.param.timer_type == ODP_TIMER_TYPE_SINGLE) {
2542 tmr_attr->resparam.res_ns = poolinfo.param.res_ns;
2543 tmr_attr->resparam.res_hz = poolinfo.param.res_hz;
2544 tmr_attr->resparam.max_tmo = poolinfo.param.max_tmo;
2545 tmr_attr->resparam.min_tmo = poolinfo.param.min_tmo;
2546 tmr_attr->resparam.clk_src = clk;
2547 tmr_attr->max_pending_events = 0;
2548 memset(&tmr_attr->ringparam, 0, sizeof(em_timer_ring_param_t));
2549 memset(&tmr_attr->freqparam, 0, sizeof(em_timer_ring_freq_param_t));
2550#if PRE_1_50_ODP_TIMER_API
2551 } else {
2552 tmr_attr->ringparam.base_hz.integer = poolinfo.param.periodic.base_freq_hz.integer;
2553 tmr_attr->ringparam.base_hz.numer = poolinfo.param.periodic.base_freq_hz.numer;
2554 tmr_attr->ringparam.base_hz.denom = poolinfo.param.periodic.base_freq_hz.denom;
2555 tmr_attr->ringparam.max_mul = poolinfo.param.periodic.max_multiplier;
2556 tmr_attr->ringparam.res_ns = poolinfo.param.res_ns;
2557 tmr_attr->ringparam.clk_src = clk;
2558 tmr_attr->max_pending_events = 0;
2559 memset(&tmr_attr->resparam, 0, sizeof(em_timer_res_param_t));
2560 memset(&tmr_attr->freqparam, 0, sizeof(em_timer_ring_freq_param_t));
2561#else
2562 } else if (poolinfo.param.timer_type == ODP_TIMER_TYPE_PERIODIC_BASE_MUL) {
2563 tmr_attr->ringparam.base_hz.integer =
2564 poolinfo.param.periodic.base_mul.base_freq_hz.integer;
2565 tmr_attr->ringparam.base_hz.numer =
2566 poolinfo.param.periodic.base_mul.base_freq_hz.numer;
2567 tmr_attr->ringparam.base_hz.denom =
2568 poolinfo.param.periodic.base_mul.base_freq_hz.denom;
2569 tmr_attr->ringparam.max_mul =
2570 poolinfo.param.periodic.base_mul.max_multiplier;
2571 tmr_attr->ringparam.res_ns = poolinfo.param.res_ns;
2572 tmr_attr->ringparam.clk_src = clk;
2573 tmr_attr->max_pending_events = poolinfo.param.periodic.max_pending_tmo;
2574 memset(&tmr_attr->resparam, 0, sizeof(em_timer_res_param_t));
2575 memset(&tmr_attr->freqparam, 0, sizeof(em_timer_ring_freq_param_t));
2576 } else { /* ODP_TIMER_TYPE_PERIODIC_FREQ */
2577 tmr_attr->freqparam.freq_hz =
2578 (em_fract_u64_t *)(uintptr_t)poolinfo.param.periodic.freq.freq_hz;
2579 tmr_attr->freqparam.num = poolinfo.param.periodic.freq.num;
2580 tmr_attr->freqparam.res_ns = poolinfo.param.res_ns;
2581 tmr_attr->freqparam.clk_src = clk;
2582 tmr_attr->max_pending_events = poolinfo.param.periodic.max_pending_tmo;
2583 memset(&tmr_attr->resparam, 0, sizeof(em_timer_res_param_t));
2584 memset(&tmr_attr->ringparam, 0, sizeof(em_timer_ring_param_t));
2585#endif
2586 }
2587
2588 tmr_attr->num_tmo = poolinfo.param.num_timers;
2589 tmr_attr->flags = em_shm->timers.timer[i].flags;
2590 tmr_attr->priority = poolinfo.param.priority;
2591
2592 strncpy(tmr_attr->name, poolinfo.name, EM_TIMER_NAME_LEN - 1);
2593 tmr_attr->name[EM_TIMER_NAME_LEN - 1] = '\0';
2594 return EM_OK;
2595}
2596
2597uint64_t em_timer_freq(em_timer_t tmr)
2598{
2599 const timer_storage_t *const tmrs = &em_shm->timers;
2600
2601 if (EM_CHECK_LEVEL > 0 && !is_timer_valid(tmr)) {
2602 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_FREQ,
2603 "Invalid timer:%" PRI_TMR "", tmr);
2604 return 0;
2605 }
2606
2607 return odp_timer_ns_to_tick(tmrs->timer[TMR_H2I(tmr)].odp_tmr_pool,
2608 1000ULL * 1000ULL * 1000ULL); /* 1 sec */
2609}
2610
2611uint64_t em_timer_tick_to_ns(em_timer_t tmr, em_timer_tick_t ticks)
2612{
2613 const timer_storage_t *const tmrs = &em_shm->timers;
2614
2615 if (EM_CHECK_LEVEL > 0 && !is_timer_valid(tmr)) {
2616 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_TICK_TO_NS,
2617 "Invalid timer:%" PRI_TMR "", tmr);
2618 return 0;
2619 }
2620
2621 return odp_timer_tick_to_ns(tmrs->timer[TMR_H2I(tmr)].odp_tmr_pool, ticks);
2622}
2623
2624em_timer_tick_t em_timer_ns_to_tick(em_timer_t tmr, uint64_t ns)
2625{
2626 const timer_storage_t *const tmrs = &em_shm->timers;
2627
2628 if (EM_CHECK_LEVEL > 0 && !is_timer_valid(tmr)) {
2629 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TIMER_NS_TO_TICK,
2630 "Invalid timer:%" PRI_TMR "", tmr);
2631 return 0;
2632 }
2633
2634 return odp_timer_ns_to_tick(tmrs->timer[TMR_H2I(tmr)].odp_tmr_pool, ns);
2635}
2636
2638{
2639 if (EM_CHECK_LEVEL > 0 && unlikely(tmo == EM_TMO_UNDEF)) {
2640 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_STATE, "Invalid tmo");
2641 return EM_TMO_STATE_UNKNOWN;
2642 }
2643 if (EM_CHECK_LEVEL > 1 && !odp_buffer_is_valid(tmo->odp_buffer)) {
2644 INTERNAL_ERROR(EM_ERR_BAD_ID, EM_ESCOPE_TMO_STATE, "Invalid tmo buffer");
2645 return EM_TMO_STATE_UNKNOWN;
2646 }
2647
2648 return odp_atomic_load_acq_u32(&tmo->state);
2649}
2650
2652{
2654 EM_ERR_BAD_ARG, EM_ESCOPE_TMO_STATS,
2655 "Invalid tmo");
2656 /* check that tmo buf is valid before accessing other struct members */
2657 RETURN_ERROR_IF(EM_CHECK_LEVEL > 1 && !odp_buffer_is_valid(tmo->odp_buffer),
2658 EM_ERR_BAD_ID, EM_ESCOPE_TMO_STATS,
2659 "Invalid tmo buffer");
2660 RETURN_ERROR_IF(EM_CHECK_LEVEL > 0 && tmo->odp_timer == ODP_TIMER_INVALID,
2661 EM_ERR_BAD_STATE, EM_ESCOPE_TMO_STATS,
2662 "tmo deleted?");
2663
2664 if (EM_TIMER_TMO_STATS) {
2665 if (stat)
2666 *stat = tmo->stats;
2667 } else {
2669 }
2670
2671 return EM_OK;
2672}
2673
2674em_tmo_type_t em_tmo_type(em_event_t event, em_tmo_t *tmo, bool reset)
2675{
2676 if (EM_CHECK_LEVEL > 0 && unlikely(event == EM_EVENT_UNDEF)) {
2677 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_STATE, "Invalid event given");
2678 return EM_TMO_TYPE_NONE;
2679 }
2680
2681 event_hdr_t *ev_hdr = event_to_hdr(event);
2682 em_event_type_t evtype_major = em_event_type_major(ev_hdr->event_type);
2683 em_tmo_type_t tmo_type = (em_tmo_type_t)ev_hdr->flags.tmo_type;
2684
2685 if (EM_CHECK_LEVEL > 1 && unlikely(!can_have_tmo_type(evtype_major))) {
2686 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_STATE,
2687 "Invalid event type:%u", evtype_major);
2688 return EM_TMO_TYPE_NONE;
2689 }
2690
2691 if (EM_CHECK_LEVEL > 2 && unlikely(tmo_type > EM_TMO_TYPE_PERIODIC)) {
2692 INTERNAL_ERROR(EM_ERR_BAD_STATE, EM_ESCOPE_TMO_STATE,
2693 "Invalid tmo event type, header corrupted?");
2694 return EM_TMO_TYPE_NONE;
2695 }
2696
2697 if (tmo)
2698 *tmo = (tmo_type == EM_TMO_TYPE_NONE) ? EM_TMO_UNDEF : ev_hdr->tmo;
2699
2700 if (reset && evtype_major != EM_EVENT_TYPE_TIMER_IND) {
2702 ev_hdr->tmo = EM_TMO_UNDEF;
2703 }
2704
2705 return tmo_type;
2706}
2707
2708void *em_tmo_userptr(em_event_t event, em_tmo_t *tmo)
2709{
2710 if (EM_CHECK_LEVEL > 0 && unlikely(event == EM_EVENT_UNDEF)) {
2711 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_USERPTR, "Invalid event given");
2712 return NULL;
2713 }
2714
2715 odp_event_t odp_event = event_em2odp(event);
2716 odp_event_type_t evtype = odp_event_type(odp_event);
2717
2718 if (unlikely(evtype != ODP_EVENT_TIMEOUT)) /* no errorhandler for other events */
2719 return NULL;
2720
2721 event_hdr_t *ev_hdr = event_to_hdr(event);
2722
2723 if (tmo) /* always periodic timeout here */
2724 *tmo = ev_hdr->tmo;
2725
2726 return odp_timeout_user_ptr(odp_timeout_from_event(odp_event));
2727}
2728
2729em_timer_t em_tmo_timer(em_tmo_t tmo)
2730{
2731 if (EM_CHECK_LEVEL > 0 && unlikely(tmo == EM_TMO_UNDEF)) {
2732 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_TIMER, "Invalid tmo given");
2733 return EM_TIMER_UNDEF;
2734 }
2735 if (EM_CHECK_LEVEL > 1 && !odp_buffer_is_valid(tmo->odp_buffer)) {
2736 INTERNAL_ERROR(EM_ERR_BAD_ARG, EM_ESCOPE_TMO_TIMER, "Corrupted tmo?");
2737 return EM_TIMER_UNDEF;
2738 }
2739
2740 return tmo->timer;
2741}
2742
2743uint64_t em_timer_to_u64(em_timer_t timer)
2744{
2745 return (uint64_t)timer;
2746}
2747
2749{
2750 return (uint64_t)tmo;
2751}
#define INTERNAL_ERROR(error, escope, fmt,...)
Definition em_error.h:58
#define RETURN_ERROR_IF(cond, error, escope, fmt,...)
Definition em_error.h:65
struct event_hdr event_hdr_t
#define EM_CHECK_INIT_CALLED
em_shm_t * em_shm
#define EM_CHECK_LEVEL
#define EM_TIMER_CLKSRC_DEFAULT
struct em_timer_timeout_t * em_tmo_t
#define PRI_QUEUE
uint32_t em_event_type_t
#define EM_EVENT_UNDEF
#define EM_EVENT_GROUP_UNDEF
#define PRI_EVENT
#define EM_OK
uint32_t em_escope_t
uint32_t em_status_t
@ EM_ERR_TOOFAR
@ EM_ERR_BUSY
@ EM_ERR_OPERATION_FAILED
@ EM_ERR_BAD_ID
@ EM_ERR_CANCELED
@ EM_ERR_BAD_CONTEXT
@ EM_ERR_ALLOC_FAILED
@ EM_ERR_BAD_ARG
@ EM_ERR_NOT_IMPLEMENTED
@ EM_ERR_NOT_SUPPORTED
@ EM_ERR_BAD_STATE
@ EM_ERR_TOONEAR
@ EM_ERR_LIB_FAILED
@ EM_ERR_NOT_INITIALIZED
@ EM_ERR_BAD_POINTER
em_status_t em_send(em_event_t event, em_queue_t queue)
void em_free(em_event_t event)
@ EM_EVENT_TYPE_SW
@ EM_EVENT_TYPE_ODP
@ EM_EVENT_TYPE_PACKET
@ EM_EVENT_TYPE_TIMER_IND
@ EM_EVENT_TYPE_TIMER
@ EM_QUEUE_TYPE_ORDERED
@ EM_QUEUE_TYPE_ATOMIC
@ EM_QUEUE_TYPE_UNSCHEDULED
@ EM_QUEUE_TYPE_PARALLEL
em_status_t em_timer_capability(em_timer_capability_t *capa, em_timer_clksrc_t clk_src)
em_status_t em_tmo_set_abs(em_tmo_t tmo, em_timer_tick_t ticks_abs, em_event_t tmo_ev)
em_status_t em_timer_ring_freq_capability(em_timer_ring_freq_param_t *ring)
Check frequency-based periodic ring timer capability.
int em_timer_list(em_timer_t tmr_list[], int max)
uint64_t em_timer_freq(em_timer_t tmr)
uint64_t em_tmo_to_u64(em_tmo_t tmo)
em_status_t em_tmo_stats(em_tmo_t tmo, em_tmo_stats_t *stat)
em_status_t em_timer_delete(em_timer_t tmr)
em_status_t em_timer_ring_attr_init(em_timer_attr_t *ring_attr, em_timer_clksrc_t clk_src, uint64_t base_hz, uint64_t max_mul, uint64_t res_ns)
em_status_t em_timer_ring_freq_attr_init(em_timer_attr_t *ring_attr, em_timer_clksrc_t clk_src, em_fract_u64_t *freq_hz, uint32_t num, uint64_t res_ns)
em_timer_tick_t em_timer_ns_to_tick(em_timer_t tmr, uint64_t ns)
em_tmo_state_t em_tmo_state(em_tmo_t tmo)
void * em_tmo_userptr(em_event_t event, em_tmo_t *tmo)
em_tmo_t em_tmo_create(em_timer_t tmr, em_tmo_flag_t flags, em_queue_t queue)
em_timer_t em_timer_create(const em_timer_attr_t *tmr_attr)
em_status_t em_tmo_set_periodic_ring(em_tmo_t tmo, em_timer_tick_t start_abs, uint64_t multiplier)
em_status_t em_tmo_delete(em_tmo_t tmo)
em_status_t em_tmo_cancel(em_tmo_t tmo, em_event_t *cur_event)
em_tmo_type_t em_tmo_type(em_event_t event, em_tmo_t *tmo, bool reset)
em_timer_t em_timer_ring_create(const em_timer_attr_t *ring_attr)
em_status_t em_tmo_set_periodic(em_tmo_t tmo, em_timer_tick_t start_abs, em_timer_tick_t period, em_event_t tmo_ev)
em_timer_tick_t em_timer_current_tick(em_timer_t tmr)
em_status_t em_tmo_ring_ack(em_tmo_t tmo, em_event_t tmo_ev)
em_timer_t em_timer_ring_freq_create(const em_timer_attr_t *ring_attr)
em_status_t em_tmo_set_rel(em_tmo_t tmo, em_timer_tick_t ticks_rel, em_event_t tmo_ev)
em_status_t em_tmo_set_periodic_ring_freq(em_tmo_t tmo, em_timer_tick_t start_abs, em_fract_u64_t freq_hz)
uint64_t em_timer_tick_to_ns(em_timer_t tmr, em_timer_tick_t ticks)
uint64_t em_timer_to_u64(em_timer_t timer)
em_tmo_t em_tmo_create_arg(em_timer_t tmr, em_tmo_flag_t flags, em_queue_t queue, em_tmo_args_t *args)
em_status_t em_timer_attr(em_timer_t tmr, em_timer_attr_t *tmr_attr)
void em_timer_attr_init(em_timer_attr_t *tmr_attr)
em_timer_t em_tmo_timer(em_tmo_t tmo)
em_status_t em_timer_ring_capability(em_timer_ring_param_t *ring)
Check periodic ring timer capability.
em_status_t em_tmo_ack(em_tmo_t tmo, em_event_t next_tmo_ev)
uint64_t em_timer_tick_t
em_status_t em_timer_res_capability(em_timer_res_param_t *res, em_timer_clksrc_t clk_src)
@ EM_TMO_STATE_ACTIVE
@ EM_TMO_TYPE_ONESHOT
@ EM_TMO_TYPE_PERIODIC
uint32_t core_count
em_conf_t conf
Definition em_mem.h:93
em_cfgfile_opts_t opt
Definition em_mem.h:99
em_timer_ring_freq_param_t freqparam
em_timer_ring_param_t ringparam
char name[EM_TIMER_NAME_LEN]
em_timer_res_param_t resparam
struct em_timer_capability_t::@27::@28 support
struct em_timer_capability_t::@27 ring
em_event_t event
em_tmo_t tmo
uint8_t tmo_type
ev_hdr_user_area_t user_area
union event_hdr::@43 flags
uint32_t event_size
em_event_type_t event_type
em_event_group_t egrp
odp_queue_t odp_queue