aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-dpdk/odp_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linux-dpdk/odp_timer.c')
-rw-r--r--platform/linux-dpdk/odp_timer.c93
1 files changed, 86 insertions, 7 deletions
diff --git a/platform/linux-dpdk/odp_timer.c b/platform/linux-dpdk/odp_timer.c
index 1021a96cd..4056018ae 100644
--- a/platform/linux-dpdk/odp_timer.c
+++ b/platform/linux-dpdk/odp_timer.c
@@ -93,6 +93,9 @@ ODP_STATIC_ASSERT(MAX_TIMERS < MAX_TIMER_RING_SIZE,
/* Maximum number of periodic timers per pool */
#define MAX_PERIODIC_TIMERS 100
+/* Periodic tick fractional part accumulator size */
+#define ACC_SIZE (1ull << 32)
+
typedef struct {
odp_ticketlock_t lock;
uint64_t tick;
@@ -102,8 +105,13 @@ typedef struct {
struct timer_pool_s *timer_pool;
int state;
uint32_t timer_idx;
+
/* Period of periodic timer in ticks, includes PERIODIC_CANCELLED flag. */
uint64_t periodic_ticks;
+ /* Periodic ticks fractional part. */
+ uint32_t periodic_ticks_frac;
+ /* Periodic ticks fractional part accumulator. */
+ uint32_t periodic_ticks_frac_acc;
struct rte_timer rte_timer;
@@ -509,14 +517,26 @@ int odp_timer_res_capability(odp_timer_clk_src_t clk_src,
}
if (res_capa->min_tmo) {
- _ODP_ERR("Only res_ns or max_tmo based quaries supported\n");
+ _ODP_ERR("Only res_ns or max_tmo based queries supported\n");
return -1;
}
if (res_capa->res_ns || res_capa->res_hz) {
+ if (res_capa->res_ns && res_capa->res_ns < MAX_RES_NS) {
+ _ODP_DBG("Timeout resolution capability (res_ns) exceeded\n");
+ return -1;
+ }
+ if (res_capa->res_hz && res_capa->res_hz > MAX_RES_HZ) {
+ _ODP_DBG("Timeout resolution capability (res_hz) exceeded\n");
+ return -1;
+ }
res_capa->min_tmo = min_tmo;
res_capa->max_tmo = MAX_TMO_NS;
} else { /* max_tmo */
+ if (res_capa->max_tmo > MAX_TMO_NS) {
+ _ODP_DBG("Maximum relative timeout capability (max_tmo) exceeded\n");
+ return -1;
+ }
res_capa->min_tmo = min_tmo;
res_capa->res_ns = MAX_RES_NS;
res_capa->res_hz = MAX_RES_HZ;
@@ -787,6 +807,35 @@ uint64_t odp_timer_current_tick(odp_timer_pool_t tp)
return rte_get_timer_cycles();
}
+int odp_timer_sample_ticks(odp_timer_pool_t tp[], uint64_t tick[], uint64_t clk_count[], int num)
+{
+ uint64_t now;
+ int i;
+
+ if (num <= 0 || num > MAX_TIMER_POOLS) {
+ _ODP_ERR("Bad number of timer pools: %i\n", num);
+ return -1;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (odp_unlikely(tp[i] == ODP_TIMER_POOL_INVALID)) {
+ _ODP_ERR("Invalid timer pool\n");
+ return -1;
+ }
+ }
+
+ now = rte_get_timer_cycles();
+
+ for (i = 0; i < num; i++) {
+ tick[i] = now;
+
+ if (clk_count)
+ clk_count[i] = 0;
+ }
+
+ return 0;
+}
+
int odp_timer_pool_info(odp_timer_pool_t tp,
odp_timer_pool_info_t *info)
{
@@ -1065,6 +1114,7 @@ int odp_timer_periodic_start(odp_timer_t timer_hdl,
timer_pool_t *tp = timer->timer_pool;
uint64_t multiplier = start_param->freq_multiplier;
double freq = multiplier * tp->base_freq;
+ double period_ns_dbl;
int absolute;
int ret;
@@ -1083,13 +1133,18 @@ int odp_timer_periodic_start(odp_timer_t timer_hdl,
return ODP_TIMER_FAIL;
}
- period_ns = (uint64_t)((double)ODP_TIME_SEC_IN_NS / freq);
+ period_ns_dbl = (double)ODP_TIME_SEC_IN_NS / freq;
+ period_ns = period_ns_dbl;
+
if (period_ns == 0) {
_ODP_ERR("Too high periodic timer frequency: %f\n", freq);
return ODP_TIMER_FAIL;
}
timer->periodic_ticks = odp_timer_ns_to_tick(timer_pool_to_hdl(tp), period_ns);
+ timer->periodic_ticks_frac = (period_ns_dbl - period_ns) * ACC_SIZE;
+ timer->periodic_ticks_frac_acc = 0;
+
first_tick = timer->periodic_ticks;
absolute = 0;
@@ -1113,7 +1168,7 @@ int odp_timer_periodic_start(odp_timer_t timer_hdl,
int odp_timer_periodic_ack(odp_timer_t timer_hdl, odp_event_t tmo_ev)
{
- uint64_t abs_tick;
+ uint64_t abs_tick, acc;
odp_timeout_t tmo = odp_timeout_from_event(tmo_ev);
timer_entry_t *timer = timer_from_hdl(timer_hdl);
odp_timeout_hdr_t *timeout_hdr;
@@ -1129,6 +1184,15 @@ int odp_timer_periodic_ack(odp_timer_t timer_hdl, odp_event_t tmo_ev)
if (odp_unlikely(abs_tick == PERIODIC_CANCELLED))
return 2;
+ acc = (uint64_t)timer->periodic_ticks_frac_acc + (uint64_t)timer->periodic_ticks_frac;
+
+ if (acc >= ACC_SIZE) {
+ abs_tick++;
+ acc -= ACC_SIZE;
+ }
+
+ timer->periodic_ticks_frac_acc = acc;
+
timeout_hdr = timeout_to_hdr(tmo);
abs_tick += timeout_hdr->expiration;
timeout_hdr->expiration = abs_tick;
@@ -1156,14 +1220,19 @@ int odp_timer_cancel(odp_timer_t timer_hdl, odp_event_t *tmo_ev)
odp_ticketlock_lock(&timer->lock);
if (odp_unlikely(timer->state < TICKING)) {
+ int state = timer->state;
+
odp_ticketlock_unlock(&timer->lock);
- return -1;
+
+ if (state == EXPIRED)
+ return ODP_TIMER_TOO_NEAR;
+ return ODP_TIMER_FAIL;
}
if (odp_unlikely(timer_global->ops.stop(&timer->rte_timer))) {
/* Another core runs timer callback function. */
odp_ticketlock_unlock(&timer->lock);
- return -1;
+ return ODP_TIMER_TOO_NEAR;
}
*tmo_ev = timer->tmo_event;
@@ -1171,7 +1240,7 @@ int odp_timer_cancel(odp_timer_t timer_hdl, odp_event_t *tmo_ev)
timer->state = NOT_TICKING;
odp_ticketlock_unlock(&timer->lock);
- return 0;
+ return ODP_TIMER_SUCCESS;
}
int odp_timer_periodic_cancel(odp_timer_t timer_hdl)
@@ -1228,8 +1297,14 @@ uint64_t odp_timeout_to_u64(odp_timeout_t tmo)
int odp_timeout_fresh(odp_timeout_t tmo)
{
+ timer_entry_t *timer;
odp_timeout_hdr_t *timeout_hdr = timeout_to_hdr(tmo);
- timer_entry_t *timer = timer_from_hdl(timeout_hdr->timer);
+
+ /* Timeout not connected to a timer */
+ if (odp_unlikely(timeout_hdr->timer == ODP_TIMER_INVALID))
+ return 0;
+
+ timer = timer_from_hdl(timeout_hdr->timer);
if (timer->timer_pool->periodic)
return timer->periodic_ticks != PERIODIC_CANCELLED;
@@ -1240,6 +1315,7 @@ int odp_timeout_fresh(odp_timeout_t tmo)
odp_timeout_t odp_timeout_alloc(odp_pool_t pool_hdl)
{
+ odp_timeout_hdr_t *timeout_hdr;
odp_event_t event;
pool_t *pool;
@@ -1253,6 +1329,9 @@ odp_timeout_t odp_timeout_alloc(odp_pool_t pool_hdl)
if (odp_unlikely(event == ODP_EVENT_INVALID))
return ODP_TIMEOUT_INVALID;
+ timeout_hdr = timeout_to_hdr(odp_timeout_from_event(event));
+ timeout_hdr->timer = ODP_TIMER_INVALID;
+
return odp_timeout_from_event(event);
}