1*99a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2*99a2dd95SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation
3*99a2dd95SBruce Richardson */
4*99a2dd95SBruce Richardson
5*99a2dd95SBruce Richardson #include <stdio.h>
6*99a2dd95SBruce Richardson #include <stdint.h>
7*99a2dd95SBruce Richardson #include <stdbool.h>
8*99a2dd95SBruce Richardson #include <inttypes.h>
9*99a2dd95SBruce Richardson #include <assert.h>
10*99a2dd95SBruce Richardson #include <sys/queue.h>
11*99a2dd95SBruce Richardson
12*99a2dd95SBruce Richardson #include <rte_common.h>
13*99a2dd95SBruce Richardson #include <rte_cycles.h>
14*99a2dd95SBruce Richardson #include <rte_eal_memconfig.h>
15*99a2dd95SBruce Richardson #include <rte_memory.h>
16*99a2dd95SBruce Richardson #include <rte_lcore.h>
17*99a2dd95SBruce Richardson #include <rte_branch_prediction.h>
18*99a2dd95SBruce Richardson #include <rte_spinlock.h>
19*99a2dd95SBruce Richardson #include <rte_random.h>
20*99a2dd95SBruce Richardson #include <rte_pause.h>
21*99a2dd95SBruce Richardson #include <rte_memzone.h>
22*99a2dd95SBruce Richardson
23*99a2dd95SBruce Richardson #include "rte_timer.h"
24*99a2dd95SBruce Richardson
25*99a2dd95SBruce Richardson /**
26*99a2dd95SBruce Richardson * Per-lcore info for timers.
27*99a2dd95SBruce Richardson */
28*99a2dd95SBruce Richardson struct priv_timer {
29*99a2dd95SBruce Richardson struct rte_timer pending_head; /**< dummy timer instance to head up list */
30*99a2dd95SBruce Richardson rte_spinlock_t list_lock; /**< lock to protect list access */
31*99a2dd95SBruce Richardson
32*99a2dd95SBruce Richardson /** per-core variable that true if a timer was updated on this
33*99a2dd95SBruce Richardson * core since last reset of the variable */
34*99a2dd95SBruce Richardson int updated;
35*99a2dd95SBruce Richardson
36*99a2dd95SBruce Richardson /** track the current depth of the skiplist */
37*99a2dd95SBruce Richardson unsigned curr_skiplist_depth;
38*99a2dd95SBruce Richardson
39*99a2dd95SBruce Richardson unsigned prev_lcore; /**< used for lcore round robin */
40*99a2dd95SBruce Richardson
41*99a2dd95SBruce Richardson /** running timer on this lcore now */
42*99a2dd95SBruce Richardson struct rte_timer *running_tim;
43*99a2dd95SBruce Richardson
44*99a2dd95SBruce Richardson #ifdef RTE_LIBRTE_TIMER_DEBUG
45*99a2dd95SBruce Richardson /** per-lcore statistics */
46*99a2dd95SBruce Richardson struct rte_timer_debug_stats stats;
47*99a2dd95SBruce Richardson #endif
48*99a2dd95SBruce Richardson } __rte_cache_aligned;
49*99a2dd95SBruce Richardson
50*99a2dd95SBruce Richardson #define FL_ALLOCATED (1 << 0)
51*99a2dd95SBruce Richardson struct rte_timer_data {
52*99a2dd95SBruce Richardson struct priv_timer priv_timer[RTE_MAX_LCORE];
53*99a2dd95SBruce Richardson uint8_t internal_flags;
54*99a2dd95SBruce Richardson };
55*99a2dd95SBruce Richardson
56*99a2dd95SBruce Richardson #define RTE_MAX_DATA_ELS 64
57*99a2dd95SBruce Richardson static const struct rte_memzone *rte_timer_data_mz;
58*99a2dd95SBruce Richardson static int *volatile rte_timer_mz_refcnt;
59*99a2dd95SBruce Richardson static struct rte_timer_data *rte_timer_data_arr;
60*99a2dd95SBruce Richardson static const uint32_t default_data_id;
61*99a2dd95SBruce Richardson static uint32_t rte_timer_subsystem_initialized;
62*99a2dd95SBruce Richardson
63*99a2dd95SBruce Richardson /* when debug is enabled, store some statistics */
64*99a2dd95SBruce Richardson #ifdef RTE_LIBRTE_TIMER_DEBUG
65*99a2dd95SBruce Richardson #define __TIMER_STAT_ADD(priv_timer, name, n) do { \
66*99a2dd95SBruce Richardson unsigned __lcore_id = rte_lcore_id(); \
67*99a2dd95SBruce Richardson if (__lcore_id < RTE_MAX_LCORE) \
68*99a2dd95SBruce Richardson priv_timer[__lcore_id].stats.name += (n); \
69*99a2dd95SBruce Richardson } while(0)
70*99a2dd95SBruce Richardson #else
71*99a2dd95SBruce Richardson #define __TIMER_STAT_ADD(priv_timer, name, n) do {} while (0)
72*99a2dd95SBruce Richardson #endif
73*99a2dd95SBruce Richardson
74*99a2dd95SBruce Richardson static inline int
timer_data_valid(uint32_t id)75*99a2dd95SBruce Richardson timer_data_valid(uint32_t id)
76*99a2dd95SBruce Richardson {
77*99a2dd95SBruce Richardson return rte_timer_data_arr &&
78*99a2dd95SBruce Richardson (rte_timer_data_arr[id].internal_flags & FL_ALLOCATED);
79*99a2dd95SBruce Richardson }
80*99a2dd95SBruce Richardson
81*99a2dd95SBruce Richardson /* validate ID and retrieve timer data pointer, or return error value */
82*99a2dd95SBruce Richardson #define TIMER_DATA_VALID_GET_OR_ERR_RET(id, timer_data, retval) do { \
83*99a2dd95SBruce Richardson if (id >= RTE_MAX_DATA_ELS || !timer_data_valid(id)) \
84*99a2dd95SBruce Richardson return retval; \
85*99a2dd95SBruce Richardson timer_data = &rte_timer_data_arr[id]; \
86*99a2dd95SBruce Richardson } while (0)
87*99a2dd95SBruce Richardson
88*99a2dd95SBruce Richardson int
rte_timer_data_alloc(uint32_t * id_ptr)89*99a2dd95SBruce Richardson rte_timer_data_alloc(uint32_t *id_ptr)
90*99a2dd95SBruce Richardson {
91*99a2dd95SBruce Richardson int i;
92*99a2dd95SBruce Richardson struct rte_timer_data *data;
93*99a2dd95SBruce Richardson
94*99a2dd95SBruce Richardson if (!rte_timer_subsystem_initialized)
95*99a2dd95SBruce Richardson return -ENOMEM;
96*99a2dd95SBruce Richardson
97*99a2dd95SBruce Richardson for (i = 0; i < RTE_MAX_DATA_ELS; i++) {
98*99a2dd95SBruce Richardson data = &rte_timer_data_arr[i];
99*99a2dd95SBruce Richardson if (!(data->internal_flags & FL_ALLOCATED)) {
100*99a2dd95SBruce Richardson data->internal_flags |= FL_ALLOCATED;
101*99a2dd95SBruce Richardson
102*99a2dd95SBruce Richardson if (id_ptr)
103*99a2dd95SBruce Richardson *id_ptr = i;
104*99a2dd95SBruce Richardson
105*99a2dd95SBruce Richardson return 0;
106*99a2dd95SBruce Richardson }
107*99a2dd95SBruce Richardson }
108*99a2dd95SBruce Richardson
109*99a2dd95SBruce Richardson return -ENOSPC;
110*99a2dd95SBruce Richardson }
111*99a2dd95SBruce Richardson
112*99a2dd95SBruce Richardson int
rte_timer_data_dealloc(uint32_t id)113*99a2dd95SBruce Richardson rte_timer_data_dealloc(uint32_t id)
114*99a2dd95SBruce Richardson {
115*99a2dd95SBruce Richardson struct rte_timer_data *timer_data;
116*99a2dd95SBruce Richardson TIMER_DATA_VALID_GET_OR_ERR_RET(id, timer_data, -EINVAL);
117*99a2dd95SBruce Richardson
118*99a2dd95SBruce Richardson timer_data->internal_flags &= ~(FL_ALLOCATED);
119*99a2dd95SBruce Richardson
120*99a2dd95SBruce Richardson return 0;
121*99a2dd95SBruce Richardson }
122*99a2dd95SBruce Richardson
123*99a2dd95SBruce Richardson /* Init the timer library. Allocate an array of timer data structs in shared
124*99a2dd95SBruce Richardson * memory, and allocate the zeroth entry for use with original timer
125*99a2dd95SBruce Richardson * APIs. Since the intersection of the sets of lcore ids in primary and
126*99a2dd95SBruce Richardson * secondary processes should be empty, the zeroth entry can be shared by
127*99a2dd95SBruce Richardson * multiple processes.
128*99a2dd95SBruce Richardson */
129*99a2dd95SBruce Richardson int
rte_timer_subsystem_init(void)130*99a2dd95SBruce Richardson rte_timer_subsystem_init(void)
131*99a2dd95SBruce Richardson {
132*99a2dd95SBruce Richardson const struct rte_memzone *mz;
133*99a2dd95SBruce Richardson struct rte_timer_data *data;
134*99a2dd95SBruce Richardson int i, lcore_id;
135*99a2dd95SBruce Richardson static const char *mz_name = "rte_timer_mz";
136*99a2dd95SBruce Richardson const size_t data_arr_size =
137*99a2dd95SBruce Richardson RTE_MAX_DATA_ELS * sizeof(*rte_timer_data_arr);
138*99a2dd95SBruce Richardson const size_t mem_size = data_arr_size + sizeof(*rte_timer_mz_refcnt);
139*99a2dd95SBruce Richardson bool do_full_init = true;
140*99a2dd95SBruce Richardson
141*99a2dd95SBruce Richardson rte_mcfg_timer_lock();
142*99a2dd95SBruce Richardson
143*99a2dd95SBruce Richardson if (rte_timer_subsystem_initialized) {
144*99a2dd95SBruce Richardson rte_mcfg_timer_unlock();
145*99a2dd95SBruce Richardson return -EALREADY;
146*99a2dd95SBruce Richardson }
147*99a2dd95SBruce Richardson
148*99a2dd95SBruce Richardson mz = rte_memzone_lookup(mz_name);
149*99a2dd95SBruce Richardson if (mz == NULL) {
150*99a2dd95SBruce Richardson mz = rte_memzone_reserve_aligned(mz_name, mem_size,
151*99a2dd95SBruce Richardson SOCKET_ID_ANY, 0, RTE_CACHE_LINE_SIZE);
152*99a2dd95SBruce Richardson if (mz == NULL) {
153*99a2dd95SBruce Richardson rte_mcfg_timer_unlock();
154*99a2dd95SBruce Richardson return -ENOMEM;
155*99a2dd95SBruce Richardson }
156*99a2dd95SBruce Richardson do_full_init = true;
157*99a2dd95SBruce Richardson } else
158*99a2dd95SBruce Richardson do_full_init = false;
159*99a2dd95SBruce Richardson
160*99a2dd95SBruce Richardson rte_timer_data_mz = mz;
161*99a2dd95SBruce Richardson rte_timer_data_arr = mz->addr;
162*99a2dd95SBruce Richardson rte_timer_mz_refcnt = (void *)((char *)mz->addr + data_arr_size);
163*99a2dd95SBruce Richardson
164*99a2dd95SBruce Richardson if (do_full_init) {
165*99a2dd95SBruce Richardson for (i = 0; i < RTE_MAX_DATA_ELS; i++) {
166*99a2dd95SBruce Richardson data = &rte_timer_data_arr[i];
167*99a2dd95SBruce Richardson
168*99a2dd95SBruce Richardson for (lcore_id = 0; lcore_id < RTE_MAX_LCORE;
169*99a2dd95SBruce Richardson lcore_id++) {
170*99a2dd95SBruce Richardson rte_spinlock_init(
171*99a2dd95SBruce Richardson &data->priv_timer[lcore_id].list_lock);
172*99a2dd95SBruce Richardson data->priv_timer[lcore_id].prev_lcore =
173*99a2dd95SBruce Richardson lcore_id;
174*99a2dd95SBruce Richardson }
175*99a2dd95SBruce Richardson }
176*99a2dd95SBruce Richardson }
177*99a2dd95SBruce Richardson
178*99a2dd95SBruce Richardson rte_timer_data_arr[default_data_id].internal_flags |= FL_ALLOCATED;
179*99a2dd95SBruce Richardson (*rte_timer_mz_refcnt)++;
180*99a2dd95SBruce Richardson
181*99a2dd95SBruce Richardson rte_timer_subsystem_initialized = 1;
182*99a2dd95SBruce Richardson
183*99a2dd95SBruce Richardson rte_mcfg_timer_unlock();
184*99a2dd95SBruce Richardson
185*99a2dd95SBruce Richardson return 0;
186*99a2dd95SBruce Richardson }
187*99a2dd95SBruce Richardson
188*99a2dd95SBruce Richardson void
rte_timer_subsystem_finalize(void)189*99a2dd95SBruce Richardson rte_timer_subsystem_finalize(void)
190*99a2dd95SBruce Richardson {
191*99a2dd95SBruce Richardson rte_mcfg_timer_lock();
192*99a2dd95SBruce Richardson
193*99a2dd95SBruce Richardson if (!rte_timer_subsystem_initialized) {
194*99a2dd95SBruce Richardson rte_mcfg_timer_unlock();
195*99a2dd95SBruce Richardson return;
196*99a2dd95SBruce Richardson }
197*99a2dd95SBruce Richardson
198*99a2dd95SBruce Richardson if (--(*rte_timer_mz_refcnt) == 0)
199*99a2dd95SBruce Richardson rte_memzone_free(rte_timer_data_mz);
200*99a2dd95SBruce Richardson
201*99a2dd95SBruce Richardson rte_timer_subsystem_initialized = 0;
202*99a2dd95SBruce Richardson
203*99a2dd95SBruce Richardson rte_mcfg_timer_unlock();
204*99a2dd95SBruce Richardson }
205*99a2dd95SBruce Richardson
206*99a2dd95SBruce Richardson /* Initialize the timer handle tim for use */
207*99a2dd95SBruce Richardson void
rte_timer_init(struct rte_timer * tim)208*99a2dd95SBruce Richardson rte_timer_init(struct rte_timer *tim)
209*99a2dd95SBruce Richardson {
210*99a2dd95SBruce Richardson union rte_timer_status status;
211*99a2dd95SBruce Richardson
212*99a2dd95SBruce Richardson status.state = RTE_TIMER_STOP;
213*99a2dd95SBruce Richardson status.owner = RTE_TIMER_NO_OWNER;
214*99a2dd95SBruce Richardson __atomic_store_n(&tim->status.u32, status.u32, __ATOMIC_RELAXED);
215*99a2dd95SBruce Richardson }
216*99a2dd95SBruce Richardson
217*99a2dd95SBruce Richardson /*
218*99a2dd95SBruce Richardson * if timer is pending or stopped (or running on the same core than
219*99a2dd95SBruce Richardson * us), mark timer as configuring, and on success return the previous
220*99a2dd95SBruce Richardson * status of the timer
221*99a2dd95SBruce Richardson */
222*99a2dd95SBruce Richardson static int
timer_set_config_state(struct rte_timer * tim,union rte_timer_status * ret_prev_status,struct priv_timer * priv_timer)223*99a2dd95SBruce Richardson timer_set_config_state(struct rte_timer *tim,
224*99a2dd95SBruce Richardson union rte_timer_status *ret_prev_status,
225*99a2dd95SBruce Richardson struct priv_timer *priv_timer)
226*99a2dd95SBruce Richardson {
227*99a2dd95SBruce Richardson union rte_timer_status prev_status, status;
228*99a2dd95SBruce Richardson int success = 0;
229*99a2dd95SBruce Richardson unsigned lcore_id;
230*99a2dd95SBruce Richardson
231*99a2dd95SBruce Richardson lcore_id = rte_lcore_id();
232*99a2dd95SBruce Richardson
233*99a2dd95SBruce Richardson /* wait that the timer is in correct status before update,
234*99a2dd95SBruce Richardson * and mark it as being configured */
235*99a2dd95SBruce Richardson prev_status.u32 = __atomic_load_n(&tim->status.u32, __ATOMIC_RELAXED);
236*99a2dd95SBruce Richardson
237*99a2dd95SBruce Richardson while (success == 0) {
238*99a2dd95SBruce Richardson /* timer is running on another core
239*99a2dd95SBruce Richardson * or ready to run on local core, exit
240*99a2dd95SBruce Richardson */
241*99a2dd95SBruce Richardson if (prev_status.state == RTE_TIMER_RUNNING &&
242*99a2dd95SBruce Richardson (prev_status.owner != (uint16_t)lcore_id ||
243*99a2dd95SBruce Richardson tim != priv_timer[lcore_id].running_tim))
244*99a2dd95SBruce Richardson return -1;
245*99a2dd95SBruce Richardson
246*99a2dd95SBruce Richardson /* timer is being configured on another core */
247*99a2dd95SBruce Richardson if (prev_status.state == RTE_TIMER_CONFIG)
248*99a2dd95SBruce Richardson return -1;
249*99a2dd95SBruce Richardson
250*99a2dd95SBruce Richardson /* here, we know that timer is stopped or pending,
251*99a2dd95SBruce Richardson * mark it atomically as being configured */
252*99a2dd95SBruce Richardson status.state = RTE_TIMER_CONFIG;
253*99a2dd95SBruce Richardson status.owner = (int16_t)lcore_id;
254*99a2dd95SBruce Richardson /* CONFIG states are acting as locked states. If the
255*99a2dd95SBruce Richardson * timer is in CONFIG state, the state cannot be changed
256*99a2dd95SBruce Richardson * by other threads. So, we should use ACQUIRE here.
257*99a2dd95SBruce Richardson */
258*99a2dd95SBruce Richardson success = __atomic_compare_exchange_n(&tim->status.u32,
259*99a2dd95SBruce Richardson &prev_status.u32,
260*99a2dd95SBruce Richardson status.u32, 0,
261*99a2dd95SBruce Richardson __ATOMIC_ACQUIRE,
262*99a2dd95SBruce Richardson __ATOMIC_RELAXED);
263*99a2dd95SBruce Richardson }
264*99a2dd95SBruce Richardson
265*99a2dd95SBruce Richardson ret_prev_status->u32 = prev_status.u32;
266*99a2dd95SBruce Richardson return 0;
267*99a2dd95SBruce Richardson }
268*99a2dd95SBruce Richardson
269*99a2dd95SBruce Richardson /*
270*99a2dd95SBruce Richardson * if timer is pending, mark timer as running
271*99a2dd95SBruce Richardson */
272*99a2dd95SBruce Richardson static int
timer_set_running_state(struct rte_timer * tim)273*99a2dd95SBruce Richardson timer_set_running_state(struct rte_timer *tim)
274*99a2dd95SBruce Richardson {
275*99a2dd95SBruce Richardson union rte_timer_status prev_status, status;
276*99a2dd95SBruce Richardson unsigned lcore_id = rte_lcore_id();
277*99a2dd95SBruce Richardson int success = 0;
278*99a2dd95SBruce Richardson
279*99a2dd95SBruce Richardson /* wait that the timer is in correct status before update,
280*99a2dd95SBruce Richardson * and mark it as running */
281*99a2dd95SBruce Richardson prev_status.u32 = __atomic_load_n(&tim->status.u32, __ATOMIC_RELAXED);
282*99a2dd95SBruce Richardson
283*99a2dd95SBruce Richardson while (success == 0) {
284*99a2dd95SBruce Richardson /* timer is not pending anymore */
285*99a2dd95SBruce Richardson if (prev_status.state != RTE_TIMER_PENDING)
286*99a2dd95SBruce Richardson return -1;
287*99a2dd95SBruce Richardson
288*99a2dd95SBruce Richardson /* we know that the timer will be pending at this point
289*99a2dd95SBruce Richardson * mark it atomically as being running
290*99a2dd95SBruce Richardson */
291*99a2dd95SBruce Richardson status.state = RTE_TIMER_RUNNING;
292*99a2dd95SBruce Richardson status.owner = (int16_t)lcore_id;
293*99a2dd95SBruce Richardson /* RUNNING states are acting as locked states. If the
294*99a2dd95SBruce Richardson * timer is in RUNNING state, the state cannot be changed
295*99a2dd95SBruce Richardson * by other threads. So, we should use ACQUIRE here.
296*99a2dd95SBruce Richardson */
297*99a2dd95SBruce Richardson success = __atomic_compare_exchange_n(&tim->status.u32,
298*99a2dd95SBruce Richardson &prev_status.u32,
299*99a2dd95SBruce Richardson status.u32, 0,
300*99a2dd95SBruce Richardson __ATOMIC_ACQUIRE,
301*99a2dd95SBruce Richardson __ATOMIC_RELAXED);
302*99a2dd95SBruce Richardson }
303*99a2dd95SBruce Richardson
304*99a2dd95SBruce Richardson return 0;
305*99a2dd95SBruce Richardson }
306*99a2dd95SBruce Richardson
307*99a2dd95SBruce Richardson /*
308*99a2dd95SBruce Richardson * Return a skiplist level for a new entry.
309*99a2dd95SBruce Richardson * This probabilistically gives a level with p=1/4 that an entry at level n
310*99a2dd95SBruce Richardson * will also appear at level n+1.
311*99a2dd95SBruce Richardson */
312*99a2dd95SBruce Richardson static uint32_t
timer_get_skiplist_level(unsigned curr_depth)313*99a2dd95SBruce Richardson timer_get_skiplist_level(unsigned curr_depth)
314*99a2dd95SBruce Richardson {
315*99a2dd95SBruce Richardson #ifdef RTE_LIBRTE_TIMER_DEBUG
316*99a2dd95SBruce Richardson static uint32_t i, count = 0;
317*99a2dd95SBruce Richardson static uint32_t levels[MAX_SKIPLIST_DEPTH] = {0};
318*99a2dd95SBruce Richardson #endif
319*99a2dd95SBruce Richardson
320*99a2dd95SBruce Richardson /* probability value is 1/4, i.e. all at level 0, 1 in 4 is at level 1,
321*99a2dd95SBruce Richardson * 1 in 16 at level 2, 1 in 64 at level 3, etc. Calculated using lowest
322*99a2dd95SBruce Richardson * bit position of a (pseudo)random number.
323*99a2dd95SBruce Richardson */
324*99a2dd95SBruce Richardson uint32_t rand = rte_rand() & (UINT32_MAX - 1);
325*99a2dd95SBruce Richardson uint32_t level = rand == 0 ? MAX_SKIPLIST_DEPTH : (rte_bsf32(rand)-1) / 2;
326*99a2dd95SBruce Richardson
327*99a2dd95SBruce Richardson /* limit the levels used to one above our current level, so we don't,
328*99a2dd95SBruce Richardson * for instance, have a level 0 and a level 7 without anything between
329*99a2dd95SBruce Richardson */
330*99a2dd95SBruce Richardson if (level > curr_depth)
331*99a2dd95SBruce Richardson level = curr_depth;
332*99a2dd95SBruce Richardson if (level >= MAX_SKIPLIST_DEPTH)
333*99a2dd95SBruce Richardson level = MAX_SKIPLIST_DEPTH-1;
334*99a2dd95SBruce Richardson #ifdef RTE_LIBRTE_TIMER_DEBUG
335*99a2dd95SBruce Richardson count ++;
336*99a2dd95SBruce Richardson levels[level]++;
337*99a2dd95SBruce Richardson if (count % 10000 == 0)
338*99a2dd95SBruce Richardson for (i = 0; i < MAX_SKIPLIST_DEPTH; i++)
339*99a2dd95SBruce Richardson printf("Level %u: %u\n", (unsigned)i, (unsigned)levels[i]);
340*99a2dd95SBruce Richardson #endif
341*99a2dd95SBruce Richardson return level;
342*99a2dd95SBruce Richardson }
343*99a2dd95SBruce Richardson
344*99a2dd95SBruce Richardson /*
345*99a2dd95SBruce Richardson * For a given time value, get the entries at each level which
346*99a2dd95SBruce Richardson * are <= that time value.
347*99a2dd95SBruce Richardson */
348*99a2dd95SBruce Richardson static void
timer_get_prev_entries(uint64_t time_val,unsigned tim_lcore,struct rte_timer ** prev,struct priv_timer * priv_timer)349*99a2dd95SBruce Richardson timer_get_prev_entries(uint64_t time_val, unsigned tim_lcore,
350*99a2dd95SBruce Richardson struct rte_timer **prev, struct priv_timer *priv_timer)
351*99a2dd95SBruce Richardson {
352*99a2dd95SBruce Richardson unsigned lvl = priv_timer[tim_lcore].curr_skiplist_depth;
353*99a2dd95SBruce Richardson prev[lvl] = &priv_timer[tim_lcore].pending_head;
354*99a2dd95SBruce Richardson while(lvl != 0) {
355*99a2dd95SBruce Richardson lvl--;
356*99a2dd95SBruce Richardson prev[lvl] = prev[lvl+1];
357*99a2dd95SBruce Richardson while (prev[lvl]->sl_next[lvl] &&
358*99a2dd95SBruce Richardson prev[lvl]->sl_next[lvl]->expire <= time_val)
359*99a2dd95SBruce Richardson prev[lvl] = prev[lvl]->sl_next[lvl];
360*99a2dd95SBruce Richardson }
361*99a2dd95SBruce Richardson }
362*99a2dd95SBruce Richardson
363*99a2dd95SBruce Richardson /*
364*99a2dd95SBruce Richardson * Given a timer node in the skiplist, find the previous entries for it at
365*99a2dd95SBruce Richardson * all skiplist levels.
366*99a2dd95SBruce Richardson */
367*99a2dd95SBruce Richardson static void
timer_get_prev_entries_for_node(struct rte_timer * tim,unsigned tim_lcore,struct rte_timer ** prev,struct priv_timer * priv_timer)368*99a2dd95SBruce Richardson timer_get_prev_entries_for_node(struct rte_timer *tim, unsigned tim_lcore,
369*99a2dd95SBruce Richardson struct rte_timer **prev,
370*99a2dd95SBruce Richardson struct priv_timer *priv_timer)
371*99a2dd95SBruce Richardson {
372*99a2dd95SBruce Richardson int i;
373*99a2dd95SBruce Richardson
374*99a2dd95SBruce Richardson /* to get a specific entry in the list, look for just lower than the time
375*99a2dd95SBruce Richardson * values, and then increment on each level individually if necessary
376*99a2dd95SBruce Richardson */
377*99a2dd95SBruce Richardson timer_get_prev_entries(tim->expire - 1, tim_lcore, prev, priv_timer);
378*99a2dd95SBruce Richardson for (i = priv_timer[tim_lcore].curr_skiplist_depth - 1; i >= 0; i--) {
379*99a2dd95SBruce Richardson while (prev[i]->sl_next[i] != NULL &&
380*99a2dd95SBruce Richardson prev[i]->sl_next[i] != tim &&
381*99a2dd95SBruce Richardson prev[i]->sl_next[i]->expire <= tim->expire)
382*99a2dd95SBruce Richardson prev[i] = prev[i]->sl_next[i];
383*99a2dd95SBruce Richardson }
384*99a2dd95SBruce Richardson }
385*99a2dd95SBruce Richardson
386*99a2dd95SBruce Richardson /* call with lock held as necessary
387*99a2dd95SBruce Richardson * add in list
388*99a2dd95SBruce Richardson * timer must be in config state
389*99a2dd95SBruce Richardson * timer must not be in a list
390*99a2dd95SBruce Richardson */
391*99a2dd95SBruce Richardson static void
timer_add(struct rte_timer * tim,unsigned int tim_lcore,struct priv_timer * priv_timer)392*99a2dd95SBruce Richardson timer_add(struct rte_timer *tim, unsigned int tim_lcore,
393*99a2dd95SBruce Richardson struct priv_timer *priv_timer)
394*99a2dd95SBruce Richardson {
395*99a2dd95SBruce Richardson unsigned lvl;
396*99a2dd95SBruce Richardson struct rte_timer *prev[MAX_SKIPLIST_DEPTH+1];
397*99a2dd95SBruce Richardson
398*99a2dd95SBruce Richardson /* find where exactly this element goes in the list of elements
399*99a2dd95SBruce Richardson * for each depth. */
400*99a2dd95SBruce Richardson timer_get_prev_entries(tim->expire, tim_lcore, prev, priv_timer);
401*99a2dd95SBruce Richardson
402*99a2dd95SBruce Richardson /* now assign it a new level and add at that level */
403*99a2dd95SBruce Richardson const unsigned tim_level = timer_get_skiplist_level(
404*99a2dd95SBruce Richardson priv_timer[tim_lcore].curr_skiplist_depth);
405*99a2dd95SBruce Richardson if (tim_level == priv_timer[tim_lcore].curr_skiplist_depth)
406*99a2dd95SBruce Richardson priv_timer[tim_lcore].curr_skiplist_depth++;
407*99a2dd95SBruce Richardson
408*99a2dd95SBruce Richardson lvl = tim_level;
409*99a2dd95SBruce Richardson while (lvl > 0) {
410*99a2dd95SBruce Richardson tim->sl_next[lvl] = prev[lvl]->sl_next[lvl];
411*99a2dd95SBruce Richardson prev[lvl]->sl_next[lvl] = tim;
412*99a2dd95SBruce Richardson lvl--;
413*99a2dd95SBruce Richardson }
414*99a2dd95SBruce Richardson tim->sl_next[0] = prev[0]->sl_next[0];
415*99a2dd95SBruce Richardson prev[0]->sl_next[0] = tim;
416*99a2dd95SBruce Richardson
417*99a2dd95SBruce Richardson /* save the lowest list entry into the expire field of the dummy hdr
418*99a2dd95SBruce Richardson * NOTE: this is not atomic on 32-bit*/
419*99a2dd95SBruce Richardson priv_timer[tim_lcore].pending_head.expire = priv_timer[tim_lcore].\
420*99a2dd95SBruce Richardson pending_head.sl_next[0]->expire;
421*99a2dd95SBruce Richardson }
422*99a2dd95SBruce Richardson
423*99a2dd95SBruce Richardson /*
424*99a2dd95SBruce Richardson * del from list, lock if needed
425*99a2dd95SBruce Richardson * timer must be in config state
426*99a2dd95SBruce Richardson * timer must be in a list
427*99a2dd95SBruce Richardson */
428*99a2dd95SBruce Richardson static void
timer_del(struct rte_timer * tim,union rte_timer_status prev_status,int local_is_locked,struct priv_timer * priv_timer)429*99a2dd95SBruce Richardson timer_del(struct rte_timer *tim, union rte_timer_status prev_status,
430*99a2dd95SBruce Richardson int local_is_locked, struct priv_timer *priv_timer)
431*99a2dd95SBruce Richardson {
432*99a2dd95SBruce Richardson unsigned lcore_id = rte_lcore_id();
433*99a2dd95SBruce Richardson unsigned prev_owner = prev_status.owner;
434*99a2dd95SBruce Richardson int i;
435*99a2dd95SBruce Richardson struct rte_timer *prev[MAX_SKIPLIST_DEPTH+1];
436*99a2dd95SBruce Richardson
437*99a2dd95SBruce Richardson /* if timer needs is pending another core, we need to lock the
438*99a2dd95SBruce Richardson * list; if it is on local core, we need to lock if we are not
439*99a2dd95SBruce Richardson * called from rte_timer_manage() */
440*99a2dd95SBruce Richardson if (prev_owner != lcore_id || !local_is_locked)
441*99a2dd95SBruce Richardson rte_spinlock_lock(&priv_timer[prev_owner].list_lock);
442*99a2dd95SBruce Richardson
443*99a2dd95SBruce Richardson /* save the lowest list entry into the expire field of the dummy hdr.
444*99a2dd95SBruce Richardson * NOTE: this is not atomic on 32-bit */
445*99a2dd95SBruce Richardson if (tim == priv_timer[prev_owner].pending_head.sl_next[0])
446*99a2dd95SBruce Richardson priv_timer[prev_owner].pending_head.expire =
447*99a2dd95SBruce Richardson ((tim->sl_next[0] == NULL) ? 0 : tim->sl_next[0]->expire);
448*99a2dd95SBruce Richardson
449*99a2dd95SBruce Richardson /* adjust pointers from previous entries to point past this */
450*99a2dd95SBruce Richardson timer_get_prev_entries_for_node(tim, prev_owner, prev, priv_timer);
451*99a2dd95SBruce Richardson for (i = priv_timer[prev_owner].curr_skiplist_depth - 1; i >= 0; i--) {
452*99a2dd95SBruce Richardson if (prev[i]->sl_next[i] == tim)
453*99a2dd95SBruce Richardson prev[i]->sl_next[i] = tim->sl_next[i];
454*99a2dd95SBruce Richardson }
455*99a2dd95SBruce Richardson
456*99a2dd95SBruce Richardson /* in case we deleted last entry at a level, adjust down max level */
457*99a2dd95SBruce Richardson for (i = priv_timer[prev_owner].curr_skiplist_depth - 1; i >= 0; i--)
458*99a2dd95SBruce Richardson if (priv_timer[prev_owner].pending_head.sl_next[i] == NULL)
459*99a2dd95SBruce Richardson priv_timer[prev_owner].curr_skiplist_depth --;
460*99a2dd95SBruce Richardson else
461*99a2dd95SBruce Richardson break;
462*99a2dd95SBruce Richardson
463*99a2dd95SBruce Richardson if (prev_owner != lcore_id || !local_is_locked)
464*99a2dd95SBruce Richardson rte_spinlock_unlock(&priv_timer[prev_owner].list_lock);
465*99a2dd95SBruce Richardson }
466*99a2dd95SBruce Richardson
467*99a2dd95SBruce Richardson /* Reset and start the timer associated with the timer handle (private func) */
468*99a2dd95SBruce Richardson static int
__rte_timer_reset(struct rte_timer * tim,uint64_t expire,uint64_t period,unsigned tim_lcore,rte_timer_cb_t fct,void * arg,int local_is_locked,struct rte_timer_data * timer_data)469*99a2dd95SBruce Richardson __rte_timer_reset(struct rte_timer *tim, uint64_t expire,
470*99a2dd95SBruce Richardson uint64_t period, unsigned tim_lcore,
471*99a2dd95SBruce Richardson rte_timer_cb_t fct, void *arg,
472*99a2dd95SBruce Richardson int local_is_locked,
473*99a2dd95SBruce Richardson struct rte_timer_data *timer_data)
474*99a2dd95SBruce Richardson {
475*99a2dd95SBruce Richardson union rte_timer_status prev_status, status;
476*99a2dd95SBruce Richardson int ret;
477*99a2dd95SBruce Richardson unsigned lcore_id = rte_lcore_id();
478*99a2dd95SBruce Richardson struct priv_timer *priv_timer = timer_data->priv_timer;
479*99a2dd95SBruce Richardson
480*99a2dd95SBruce Richardson /* round robin for tim_lcore */
481*99a2dd95SBruce Richardson if (tim_lcore == (unsigned)LCORE_ID_ANY) {
482*99a2dd95SBruce Richardson if (lcore_id < RTE_MAX_LCORE) {
483*99a2dd95SBruce Richardson /* EAL thread with valid lcore_id */
484*99a2dd95SBruce Richardson tim_lcore = rte_get_next_lcore(
485*99a2dd95SBruce Richardson priv_timer[lcore_id].prev_lcore,
486*99a2dd95SBruce Richardson 0, 1);
487*99a2dd95SBruce Richardson priv_timer[lcore_id].prev_lcore = tim_lcore;
488*99a2dd95SBruce Richardson } else
489*99a2dd95SBruce Richardson /* non-EAL thread do not run rte_timer_manage(),
490*99a2dd95SBruce Richardson * so schedule the timer on the first enabled lcore. */
491*99a2dd95SBruce Richardson tim_lcore = rte_get_next_lcore(LCORE_ID_ANY, 0, 1);
492*99a2dd95SBruce Richardson }
493*99a2dd95SBruce Richardson
494*99a2dd95SBruce Richardson /* wait that the timer is in correct status before update,
495*99a2dd95SBruce Richardson * and mark it as being configured */
496*99a2dd95SBruce Richardson ret = timer_set_config_state(tim, &prev_status, priv_timer);
497*99a2dd95SBruce Richardson if (ret < 0)
498*99a2dd95SBruce Richardson return -1;
499*99a2dd95SBruce Richardson
500*99a2dd95SBruce Richardson __TIMER_STAT_ADD(priv_timer, reset, 1);
501*99a2dd95SBruce Richardson if (prev_status.state == RTE_TIMER_RUNNING &&
502*99a2dd95SBruce Richardson lcore_id < RTE_MAX_LCORE) {
503*99a2dd95SBruce Richardson priv_timer[lcore_id].updated = 1;
504*99a2dd95SBruce Richardson }
505*99a2dd95SBruce Richardson
506*99a2dd95SBruce Richardson /* remove it from list */
507*99a2dd95SBruce Richardson if (prev_status.state == RTE_TIMER_PENDING) {
508*99a2dd95SBruce Richardson timer_del(tim, prev_status, local_is_locked, priv_timer);
509*99a2dd95SBruce Richardson __TIMER_STAT_ADD(priv_timer, pending, -1);
510*99a2dd95SBruce Richardson }
511*99a2dd95SBruce Richardson
512*99a2dd95SBruce Richardson tim->period = period;
513*99a2dd95SBruce Richardson tim->expire = expire;
514*99a2dd95SBruce Richardson tim->f = fct;
515*99a2dd95SBruce Richardson tim->arg = arg;
516*99a2dd95SBruce Richardson
517*99a2dd95SBruce Richardson /* if timer needs to be scheduled on another core, we need to
518*99a2dd95SBruce Richardson * lock the destination list; if it is on local core, we need to lock if
519*99a2dd95SBruce Richardson * we are not called from rte_timer_manage()
520*99a2dd95SBruce Richardson */
521*99a2dd95SBruce Richardson if (tim_lcore != lcore_id || !local_is_locked)
522*99a2dd95SBruce Richardson rte_spinlock_lock(&priv_timer[tim_lcore].list_lock);
523*99a2dd95SBruce Richardson
524*99a2dd95SBruce Richardson __TIMER_STAT_ADD(priv_timer, pending, 1);
525*99a2dd95SBruce Richardson timer_add(tim, tim_lcore, priv_timer);
526*99a2dd95SBruce Richardson
527*99a2dd95SBruce Richardson /* update state: as we are in CONFIG state, only us can modify
528*99a2dd95SBruce Richardson * the state so we don't need to use cmpset() here */
529*99a2dd95SBruce Richardson status.state = RTE_TIMER_PENDING;
530*99a2dd95SBruce Richardson status.owner = (int16_t)tim_lcore;
531*99a2dd95SBruce Richardson /* The "RELEASE" ordering guarantees the memory operations above
532*99a2dd95SBruce Richardson * the status update are observed before the update by all threads
533*99a2dd95SBruce Richardson */
534*99a2dd95SBruce Richardson __atomic_store_n(&tim->status.u32, status.u32, __ATOMIC_RELEASE);
535*99a2dd95SBruce Richardson
536*99a2dd95SBruce Richardson if (tim_lcore != lcore_id || !local_is_locked)
537*99a2dd95SBruce Richardson rte_spinlock_unlock(&priv_timer[tim_lcore].list_lock);
538*99a2dd95SBruce Richardson
539*99a2dd95SBruce Richardson return 0;
540*99a2dd95SBruce Richardson }
541*99a2dd95SBruce Richardson
542*99a2dd95SBruce Richardson /* Reset and start the timer associated with the timer handle tim */
543*99a2dd95SBruce Richardson int
rte_timer_reset(struct rte_timer * tim,uint64_t ticks,enum rte_timer_type type,unsigned int tim_lcore,rte_timer_cb_t fct,void * arg)544*99a2dd95SBruce Richardson rte_timer_reset(struct rte_timer *tim, uint64_t ticks,
545*99a2dd95SBruce Richardson enum rte_timer_type type, unsigned int tim_lcore,
546*99a2dd95SBruce Richardson rte_timer_cb_t fct, void *arg)
547*99a2dd95SBruce Richardson {
548*99a2dd95SBruce Richardson return rte_timer_alt_reset(default_data_id, tim, ticks, type,
549*99a2dd95SBruce Richardson tim_lcore, fct, arg);
550*99a2dd95SBruce Richardson }
551*99a2dd95SBruce Richardson
552*99a2dd95SBruce Richardson int
rte_timer_alt_reset(uint32_t timer_data_id,struct rte_timer * tim,uint64_t ticks,enum rte_timer_type type,unsigned int tim_lcore,rte_timer_cb_t fct,void * arg)553*99a2dd95SBruce Richardson rte_timer_alt_reset(uint32_t timer_data_id, struct rte_timer *tim,
554*99a2dd95SBruce Richardson uint64_t ticks, enum rte_timer_type type,
555*99a2dd95SBruce Richardson unsigned int tim_lcore, rte_timer_cb_t fct, void *arg)
556*99a2dd95SBruce Richardson {
557*99a2dd95SBruce Richardson uint64_t cur_time = rte_get_timer_cycles();
558*99a2dd95SBruce Richardson uint64_t period;
559*99a2dd95SBruce Richardson struct rte_timer_data *timer_data;
560*99a2dd95SBruce Richardson
561*99a2dd95SBruce Richardson TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
562*99a2dd95SBruce Richardson
563*99a2dd95SBruce Richardson if (type == PERIODICAL)
564*99a2dd95SBruce Richardson period = ticks;
565*99a2dd95SBruce Richardson else
566*99a2dd95SBruce Richardson period = 0;
567*99a2dd95SBruce Richardson
568*99a2dd95SBruce Richardson return __rte_timer_reset(tim, cur_time + ticks, period, tim_lcore,
569*99a2dd95SBruce Richardson fct, arg, 0, timer_data);
570*99a2dd95SBruce Richardson }
571*99a2dd95SBruce Richardson
572*99a2dd95SBruce Richardson /* loop until rte_timer_reset() succeed */
573*99a2dd95SBruce Richardson void
rte_timer_reset_sync(struct rte_timer * tim,uint64_t ticks,enum rte_timer_type type,unsigned tim_lcore,rte_timer_cb_t fct,void * arg)574*99a2dd95SBruce Richardson rte_timer_reset_sync(struct rte_timer *tim, uint64_t ticks,
575*99a2dd95SBruce Richardson enum rte_timer_type type, unsigned tim_lcore,
576*99a2dd95SBruce Richardson rte_timer_cb_t fct, void *arg)
577*99a2dd95SBruce Richardson {
578*99a2dd95SBruce Richardson while (rte_timer_reset(tim, ticks, type, tim_lcore,
579*99a2dd95SBruce Richardson fct, arg) != 0)
580*99a2dd95SBruce Richardson rte_pause();
581*99a2dd95SBruce Richardson }
582*99a2dd95SBruce Richardson
583*99a2dd95SBruce Richardson static int
__rte_timer_stop(struct rte_timer * tim,int local_is_locked,struct rte_timer_data * timer_data)584*99a2dd95SBruce Richardson __rte_timer_stop(struct rte_timer *tim, int local_is_locked,
585*99a2dd95SBruce Richardson struct rte_timer_data *timer_data)
586*99a2dd95SBruce Richardson {
587*99a2dd95SBruce Richardson union rte_timer_status prev_status, status;
588*99a2dd95SBruce Richardson unsigned lcore_id = rte_lcore_id();
589*99a2dd95SBruce Richardson int ret;
590*99a2dd95SBruce Richardson struct priv_timer *priv_timer = timer_data->priv_timer;
591*99a2dd95SBruce Richardson
592*99a2dd95SBruce Richardson /* wait that the timer is in correct status before update,
593*99a2dd95SBruce Richardson * and mark it as being configured */
594*99a2dd95SBruce Richardson ret = timer_set_config_state(tim, &prev_status, priv_timer);
595*99a2dd95SBruce Richardson if (ret < 0)
596*99a2dd95SBruce Richardson return -1;
597*99a2dd95SBruce Richardson
598*99a2dd95SBruce Richardson __TIMER_STAT_ADD(priv_timer, stop, 1);
599*99a2dd95SBruce Richardson if (prev_status.state == RTE_TIMER_RUNNING &&
600*99a2dd95SBruce Richardson lcore_id < RTE_MAX_LCORE) {
601*99a2dd95SBruce Richardson priv_timer[lcore_id].updated = 1;
602*99a2dd95SBruce Richardson }
603*99a2dd95SBruce Richardson
604*99a2dd95SBruce Richardson /* remove it from list */
605*99a2dd95SBruce Richardson if (prev_status.state == RTE_TIMER_PENDING) {
606*99a2dd95SBruce Richardson timer_del(tim, prev_status, local_is_locked, priv_timer);
607*99a2dd95SBruce Richardson __TIMER_STAT_ADD(priv_timer, pending, -1);
608*99a2dd95SBruce Richardson }
609*99a2dd95SBruce Richardson
610*99a2dd95SBruce Richardson /* mark timer as stopped */
611*99a2dd95SBruce Richardson status.state = RTE_TIMER_STOP;
612*99a2dd95SBruce Richardson status.owner = RTE_TIMER_NO_OWNER;
613*99a2dd95SBruce Richardson /* The "RELEASE" ordering guarantees the memory operations above
614*99a2dd95SBruce Richardson * the status update are observed before the update by all threads
615*99a2dd95SBruce Richardson */
616*99a2dd95SBruce Richardson __atomic_store_n(&tim->status.u32, status.u32, __ATOMIC_RELEASE);
617*99a2dd95SBruce Richardson
618*99a2dd95SBruce Richardson return 0;
619*99a2dd95SBruce Richardson }
620*99a2dd95SBruce Richardson
621*99a2dd95SBruce Richardson /* Stop the timer associated with the timer handle tim */
622*99a2dd95SBruce Richardson int
rte_timer_stop(struct rte_timer * tim)623*99a2dd95SBruce Richardson rte_timer_stop(struct rte_timer *tim)
624*99a2dd95SBruce Richardson {
625*99a2dd95SBruce Richardson return rte_timer_alt_stop(default_data_id, tim);
626*99a2dd95SBruce Richardson }
627*99a2dd95SBruce Richardson
628*99a2dd95SBruce Richardson int
rte_timer_alt_stop(uint32_t timer_data_id,struct rte_timer * tim)629*99a2dd95SBruce Richardson rte_timer_alt_stop(uint32_t timer_data_id, struct rte_timer *tim)
630*99a2dd95SBruce Richardson {
631*99a2dd95SBruce Richardson struct rte_timer_data *timer_data;
632*99a2dd95SBruce Richardson
633*99a2dd95SBruce Richardson TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
634*99a2dd95SBruce Richardson
635*99a2dd95SBruce Richardson return __rte_timer_stop(tim, 0, timer_data);
636*99a2dd95SBruce Richardson }
637*99a2dd95SBruce Richardson
638*99a2dd95SBruce Richardson /* loop until rte_timer_stop() succeed */
639*99a2dd95SBruce Richardson void
rte_timer_stop_sync(struct rte_timer * tim)640*99a2dd95SBruce Richardson rte_timer_stop_sync(struct rte_timer *tim)
641*99a2dd95SBruce Richardson {
642*99a2dd95SBruce Richardson while (rte_timer_stop(tim) != 0)
643*99a2dd95SBruce Richardson rte_pause();
644*99a2dd95SBruce Richardson }
645*99a2dd95SBruce Richardson
646*99a2dd95SBruce Richardson /* Test the PENDING status of the timer handle tim */
647*99a2dd95SBruce Richardson int
rte_timer_pending(struct rte_timer * tim)648*99a2dd95SBruce Richardson rte_timer_pending(struct rte_timer *tim)
649*99a2dd95SBruce Richardson {
650*99a2dd95SBruce Richardson return __atomic_load_n(&tim->status.state,
651*99a2dd95SBruce Richardson __ATOMIC_RELAXED) == RTE_TIMER_PENDING;
652*99a2dd95SBruce Richardson }
653*99a2dd95SBruce Richardson
654*99a2dd95SBruce Richardson /* must be called periodically, run all timer that expired */
655*99a2dd95SBruce Richardson static void
__rte_timer_manage(struct rte_timer_data * timer_data)656*99a2dd95SBruce Richardson __rte_timer_manage(struct rte_timer_data *timer_data)
657*99a2dd95SBruce Richardson {
658*99a2dd95SBruce Richardson union rte_timer_status status;
659*99a2dd95SBruce Richardson struct rte_timer *tim, *next_tim;
660*99a2dd95SBruce Richardson struct rte_timer *run_first_tim, **pprev;
661*99a2dd95SBruce Richardson unsigned lcore_id = rte_lcore_id();
662*99a2dd95SBruce Richardson struct rte_timer *prev[MAX_SKIPLIST_DEPTH + 1];
663*99a2dd95SBruce Richardson uint64_t cur_time;
664*99a2dd95SBruce Richardson int i, ret;
665*99a2dd95SBruce Richardson struct priv_timer *priv_timer = timer_data->priv_timer;
666*99a2dd95SBruce Richardson
667*99a2dd95SBruce Richardson /* timer manager only runs on EAL thread with valid lcore_id */
668*99a2dd95SBruce Richardson assert(lcore_id < RTE_MAX_LCORE);
669*99a2dd95SBruce Richardson
670*99a2dd95SBruce Richardson __TIMER_STAT_ADD(priv_timer, manage, 1);
671*99a2dd95SBruce Richardson /* optimize for the case where per-cpu list is empty */
672*99a2dd95SBruce Richardson if (priv_timer[lcore_id].pending_head.sl_next[0] == NULL)
673*99a2dd95SBruce Richardson return;
674*99a2dd95SBruce Richardson cur_time = rte_get_timer_cycles();
675*99a2dd95SBruce Richardson
676*99a2dd95SBruce Richardson #ifdef RTE_ARCH_64
677*99a2dd95SBruce Richardson /* on 64-bit the value cached in the pending_head.expired will be
678*99a2dd95SBruce Richardson * updated atomically, so we can consult that for a quick check here
679*99a2dd95SBruce Richardson * outside the lock */
680*99a2dd95SBruce Richardson if (likely(priv_timer[lcore_id].pending_head.expire > cur_time))
681*99a2dd95SBruce Richardson return;
682*99a2dd95SBruce Richardson #endif
683*99a2dd95SBruce Richardson
684*99a2dd95SBruce Richardson /* browse ordered list, add expired timers in 'expired' list */
685*99a2dd95SBruce Richardson rte_spinlock_lock(&priv_timer[lcore_id].list_lock);
686*99a2dd95SBruce Richardson
687*99a2dd95SBruce Richardson /* if nothing to do just unlock and return */
688*99a2dd95SBruce Richardson if (priv_timer[lcore_id].pending_head.sl_next[0] == NULL ||
689*99a2dd95SBruce Richardson priv_timer[lcore_id].pending_head.sl_next[0]->expire > cur_time) {
690*99a2dd95SBruce Richardson rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
691*99a2dd95SBruce Richardson return;
692*99a2dd95SBruce Richardson }
693*99a2dd95SBruce Richardson
694*99a2dd95SBruce Richardson /* save start of list of expired timers */
695*99a2dd95SBruce Richardson tim = priv_timer[lcore_id].pending_head.sl_next[0];
696*99a2dd95SBruce Richardson
697*99a2dd95SBruce Richardson /* break the existing list at current time point */
698*99a2dd95SBruce Richardson timer_get_prev_entries(cur_time, lcore_id, prev, priv_timer);
699*99a2dd95SBruce Richardson for (i = priv_timer[lcore_id].curr_skiplist_depth -1; i >= 0; i--) {
700*99a2dd95SBruce Richardson if (prev[i] == &priv_timer[lcore_id].pending_head)
701*99a2dd95SBruce Richardson continue;
702*99a2dd95SBruce Richardson priv_timer[lcore_id].pending_head.sl_next[i] =
703*99a2dd95SBruce Richardson prev[i]->sl_next[i];
704*99a2dd95SBruce Richardson if (prev[i]->sl_next[i] == NULL)
705*99a2dd95SBruce Richardson priv_timer[lcore_id].curr_skiplist_depth--;
706*99a2dd95SBruce Richardson prev[i] ->sl_next[i] = NULL;
707*99a2dd95SBruce Richardson }
708*99a2dd95SBruce Richardson
709*99a2dd95SBruce Richardson /* transition run-list from PENDING to RUNNING */
710*99a2dd95SBruce Richardson run_first_tim = tim;
711*99a2dd95SBruce Richardson pprev = &run_first_tim;
712*99a2dd95SBruce Richardson
713*99a2dd95SBruce Richardson for ( ; tim != NULL; tim = next_tim) {
714*99a2dd95SBruce Richardson next_tim = tim->sl_next[0];
715*99a2dd95SBruce Richardson
716*99a2dd95SBruce Richardson ret = timer_set_running_state(tim);
717*99a2dd95SBruce Richardson if (likely(ret == 0)) {
718*99a2dd95SBruce Richardson pprev = &tim->sl_next[0];
719*99a2dd95SBruce Richardson } else {
720*99a2dd95SBruce Richardson /* another core is trying to re-config this one,
721*99a2dd95SBruce Richardson * remove it from local expired list
722*99a2dd95SBruce Richardson */
723*99a2dd95SBruce Richardson *pprev = next_tim;
724*99a2dd95SBruce Richardson }
725*99a2dd95SBruce Richardson }
726*99a2dd95SBruce Richardson
727*99a2dd95SBruce Richardson /* update the next to expire timer value */
728*99a2dd95SBruce Richardson priv_timer[lcore_id].pending_head.expire =
729*99a2dd95SBruce Richardson (priv_timer[lcore_id].pending_head.sl_next[0] == NULL) ? 0 :
730*99a2dd95SBruce Richardson priv_timer[lcore_id].pending_head.sl_next[0]->expire;
731*99a2dd95SBruce Richardson
732*99a2dd95SBruce Richardson rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
733*99a2dd95SBruce Richardson
734*99a2dd95SBruce Richardson /* now scan expired list and call callbacks */
735*99a2dd95SBruce Richardson for (tim = run_first_tim; tim != NULL; tim = next_tim) {
736*99a2dd95SBruce Richardson next_tim = tim->sl_next[0];
737*99a2dd95SBruce Richardson priv_timer[lcore_id].updated = 0;
738*99a2dd95SBruce Richardson priv_timer[lcore_id].running_tim = tim;
739*99a2dd95SBruce Richardson
740*99a2dd95SBruce Richardson /* execute callback function with list unlocked */
741*99a2dd95SBruce Richardson tim->f(tim, tim->arg);
742*99a2dd95SBruce Richardson
743*99a2dd95SBruce Richardson __TIMER_STAT_ADD(priv_timer, pending, -1);
744*99a2dd95SBruce Richardson /* the timer was stopped or reloaded by the callback
745*99a2dd95SBruce Richardson * function, we have nothing to do here */
746*99a2dd95SBruce Richardson if (priv_timer[lcore_id].updated == 1)
747*99a2dd95SBruce Richardson continue;
748*99a2dd95SBruce Richardson
749*99a2dd95SBruce Richardson if (tim->period == 0) {
750*99a2dd95SBruce Richardson /* remove from done list and mark timer as stopped */
751*99a2dd95SBruce Richardson status.state = RTE_TIMER_STOP;
752*99a2dd95SBruce Richardson status.owner = RTE_TIMER_NO_OWNER;
753*99a2dd95SBruce Richardson /* The "RELEASE" ordering guarantees the memory
754*99a2dd95SBruce Richardson * operations above the status update are observed
755*99a2dd95SBruce Richardson * before the update by all threads
756*99a2dd95SBruce Richardson */
757*99a2dd95SBruce Richardson __atomic_store_n(&tim->status.u32, status.u32,
758*99a2dd95SBruce Richardson __ATOMIC_RELEASE);
759*99a2dd95SBruce Richardson }
760*99a2dd95SBruce Richardson else {
761*99a2dd95SBruce Richardson /* keep it in list and mark timer as pending */
762*99a2dd95SBruce Richardson rte_spinlock_lock(&priv_timer[lcore_id].list_lock);
763*99a2dd95SBruce Richardson status.state = RTE_TIMER_PENDING;
764*99a2dd95SBruce Richardson __TIMER_STAT_ADD(priv_timer, pending, 1);
765*99a2dd95SBruce Richardson status.owner = (int16_t)lcore_id;
766*99a2dd95SBruce Richardson /* The "RELEASE" ordering guarantees the memory
767*99a2dd95SBruce Richardson * operations above the status update are observed
768*99a2dd95SBruce Richardson * before the update by all threads
769*99a2dd95SBruce Richardson */
770*99a2dd95SBruce Richardson __atomic_store_n(&tim->status.u32, status.u32,
771*99a2dd95SBruce Richardson __ATOMIC_RELEASE);
772*99a2dd95SBruce Richardson __rte_timer_reset(tim, tim->expire + tim->period,
773*99a2dd95SBruce Richardson tim->period, lcore_id, tim->f, tim->arg, 1,
774*99a2dd95SBruce Richardson timer_data);
775*99a2dd95SBruce Richardson rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
776*99a2dd95SBruce Richardson }
777*99a2dd95SBruce Richardson }
778*99a2dd95SBruce Richardson priv_timer[lcore_id].running_tim = NULL;
779*99a2dd95SBruce Richardson }
780*99a2dd95SBruce Richardson
781*99a2dd95SBruce Richardson int
rte_timer_manage(void)782*99a2dd95SBruce Richardson rte_timer_manage(void)
783*99a2dd95SBruce Richardson {
784*99a2dd95SBruce Richardson struct rte_timer_data *timer_data;
785*99a2dd95SBruce Richardson
786*99a2dd95SBruce Richardson TIMER_DATA_VALID_GET_OR_ERR_RET(default_data_id, timer_data, -EINVAL);
787*99a2dd95SBruce Richardson
788*99a2dd95SBruce Richardson __rte_timer_manage(timer_data);
789*99a2dd95SBruce Richardson
790*99a2dd95SBruce Richardson return 0;
791*99a2dd95SBruce Richardson }
792*99a2dd95SBruce Richardson
793*99a2dd95SBruce Richardson int
rte_timer_alt_manage(uint32_t timer_data_id,unsigned int * poll_lcores,int nb_poll_lcores,rte_timer_alt_manage_cb_t f)794*99a2dd95SBruce Richardson rte_timer_alt_manage(uint32_t timer_data_id,
795*99a2dd95SBruce Richardson unsigned int *poll_lcores,
796*99a2dd95SBruce Richardson int nb_poll_lcores,
797*99a2dd95SBruce Richardson rte_timer_alt_manage_cb_t f)
798*99a2dd95SBruce Richardson {
799*99a2dd95SBruce Richardson unsigned int default_poll_lcores[] = {rte_lcore_id()};
800*99a2dd95SBruce Richardson union rte_timer_status status;
801*99a2dd95SBruce Richardson struct rte_timer *tim, *next_tim, **pprev;
802*99a2dd95SBruce Richardson struct rte_timer *run_first_tims[RTE_MAX_LCORE];
803*99a2dd95SBruce Richardson unsigned int this_lcore = rte_lcore_id();
804*99a2dd95SBruce Richardson struct rte_timer *prev[MAX_SKIPLIST_DEPTH + 1];
805*99a2dd95SBruce Richardson uint64_t cur_time;
806*99a2dd95SBruce Richardson int i, j, ret;
807*99a2dd95SBruce Richardson int nb_runlists = 0;
808*99a2dd95SBruce Richardson struct rte_timer_data *data;
809*99a2dd95SBruce Richardson struct priv_timer *privp;
810*99a2dd95SBruce Richardson uint32_t poll_lcore;
811*99a2dd95SBruce Richardson
812*99a2dd95SBruce Richardson TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, data, -EINVAL);
813*99a2dd95SBruce Richardson
814*99a2dd95SBruce Richardson /* timer manager only runs on EAL thread with valid lcore_id */
815*99a2dd95SBruce Richardson assert(this_lcore < RTE_MAX_LCORE);
816*99a2dd95SBruce Richardson
817*99a2dd95SBruce Richardson __TIMER_STAT_ADD(data->priv_timer, manage, 1);
818*99a2dd95SBruce Richardson
819*99a2dd95SBruce Richardson if (poll_lcores == NULL) {
820*99a2dd95SBruce Richardson poll_lcores = default_poll_lcores;
821*99a2dd95SBruce Richardson nb_poll_lcores = RTE_DIM(default_poll_lcores);
822*99a2dd95SBruce Richardson }
823*99a2dd95SBruce Richardson
824*99a2dd95SBruce Richardson for (i = 0; i < nb_poll_lcores; i++) {
825*99a2dd95SBruce Richardson poll_lcore = poll_lcores[i];
826*99a2dd95SBruce Richardson privp = &data->priv_timer[poll_lcore];
827*99a2dd95SBruce Richardson
828*99a2dd95SBruce Richardson /* optimize for the case where per-cpu list is empty */
829*99a2dd95SBruce Richardson if (privp->pending_head.sl_next[0] == NULL)
830*99a2dd95SBruce Richardson continue;
831*99a2dd95SBruce Richardson cur_time = rte_get_timer_cycles();
832*99a2dd95SBruce Richardson
833*99a2dd95SBruce Richardson #ifdef RTE_ARCH_64
834*99a2dd95SBruce Richardson /* on 64-bit the value cached in the pending_head.expired will
835*99a2dd95SBruce Richardson * be updated atomically, so we can consult that for a quick
836*99a2dd95SBruce Richardson * check here outside the lock
837*99a2dd95SBruce Richardson */
838*99a2dd95SBruce Richardson if (likely(privp->pending_head.expire > cur_time))
839*99a2dd95SBruce Richardson continue;
840*99a2dd95SBruce Richardson #endif
841*99a2dd95SBruce Richardson
842*99a2dd95SBruce Richardson /* browse ordered list, add expired timers in 'expired' list */
843*99a2dd95SBruce Richardson rte_spinlock_lock(&privp->list_lock);
844*99a2dd95SBruce Richardson
845*99a2dd95SBruce Richardson /* if nothing to do just unlock and return */
846*99a2dd95SBruce Richardson if (privp->pending_head.sl_next[0] == NULL ||
847*99a2dd95SBruce Richardson privp->pending_head.sl_next[0]->expire > cur_time) {
848*99a2dd95SBruce Richardson rte_spinlock_unlock(&privp->list_lock);
849*99a2dd95SBruce Richardson continue;
850*99a2dd95SBruce Richardson }
851*99a2dd95SBruce Richardson
852*99a2dd95SBruce Richardson /* save start of list of expired timers */
853*99a2dd95SBruce Richardson tim = privp->pending_head.sl_next[0];
854*99a2dd95SBruce Richardson
855*99a2dd95SBruce Richardson /* break the existing list at current time point */
856*99a2dd95SBruce Richardson timer_get_prev_entries(cur_time, poll_lcore, prev,
857*99a2dd95SBruce Richardson data->priv_timer);
858*99a2dd95SBruce Richardson for (j = privp->curr_skiplist_depth - 1; j >= 0; j--) {
859*99a2dd95SBruce Richardson if (prev[j] == &privp->pending_head)
860*99a2dd95SBruce Richardson continue;
861*99a2dd95SBruce Richardson privp->pending_head.sl_next[j] =
862*99a2dd95SBruce Richardson prev[j]->sl_next[j];
863*99a2dd95SBruce Richardson if (prev[j]->sl_next[j] == NULL)
864*99a2dd95SBruce Richardson privp->curr_skiplist_depth--;
865*99a2dd95SBruce Richardson
866*99a2dd95SBruce Richardson prev[j]->sl_next[j] = NULL;
867*99a2dd95SBruce Richardson }
868*99a2dd95SBruce Richardson
869*99a2dd95SBruce Richardson /* transition run-list from PENDING to RUNNING */
870*99a2dd95SBruce Richardson run_first_tims[nb_runlists] = tim;
871*99a2dd95SBruce Richardson pprev = &run_first_tims[nb_runlists];
872*99a2dd95SBruce Richardson nb_runlists++;
873*99a2dd95SBruce Richardson
874*99a2dd95SBruce Richardson for ( ; tim != NULL; tim = next_tim) {
875*99a2dd95SBruce Richardson next_tim = tim->sl_next[0];
876*99a2dd95SBruce Richardson
877*99a2dd95SBruce Richardson ret = timer_set_running_state(tim);
878*99a2dd95SBruce Richardson if (likely(ret == 0)) {
879*99a2dd95SBruce Richardson pprev = &tim->sl_next[0];
880*99a2dd95SBruce Richardson } else {
881*99a2dd95SBruce Richardson /* another core is trying to re-config this one,
882*99a2dd95SBruce Richardson * remove it from local expired list
883*99a2dd95SBruce Richardson */
884*99a2dd95SBruce Richardson *pprev = next_tim;
885*99a2dd95SBruce Richardson }
886*99a2dd95SBruce Richardson }
887*99a2dd95SBruce Richardson
888*99a2dd95SBruce Richardson /* update the next to expire timer value */
889*99a2dd95SBruce Richardson privp->pending_head.expire =
890*99a2dd95SBruce Richardson (privp->pending_head.sl_next[0] == NULL) ? 0 :
891*99a2dd95SBruce Richardson privp->pending_head.sl_next[0]->expire;
892*99a2dd95SBruce Richardson
893*99a2dd95SBruce Richardson rte_spinlock_unlock(&privp->list_lock);
894*99a2dd95SBruce Richardson }
895*99a2dd95SBruce Richardson
896*99a2dd95SBruce Richardson /* Now process the run lists */
897*99a2dd95SBruce Richardson while (1) {
898*99a2dd95SBruce Richardson bool done = true;
899*99a2dd95SBruce Richardson uint64_t min_expire = UINT64_MAX;
900*99a2dd95SBruce Richardson int min_idx = 0;
901*99a2dd95SBruce Richardson
902*99a2dd95SBruce Richardson /* Find the next oldest timer to process */
903*99a2dd95SBruce Richardson for (i = 0; i < nb_runlists; i++) {
904*99a2dd95SBruce Richardson tim = run_first_tims[i];
905*99a2dd95SBruce Richardson
906*99a2dd95SBruce Richardson if (tim != NULL && tim->expire < min_expire) {
907*99a2dd95SBruce Richardson min_expire = tim->expire;
908*99a2dd95SBruce Richardson min_idx = i;
909*99a2dd95SBruce Richardson done = false;
910*99a2dd95SBruce Richardson }
911*99a2dd95SBruce Richardson }
912*99a2dd95SBruce Richardson
913*99a2dd95SBruce Richardson if (done)
914*99a2dd95SBruce Richardson break;
915*99a2dd95SBruce Richardson
916*99a2dd95SBruce Richardson tim = run_first_tims[min_idx];
917*99a2dd95SBruce Richardson
918*99a2dd95SBruce Richardson /* Move down the runlist from which we picked a timer to
919*99a2dd95SBruce Richardson * execute
920*99a2dd95SBruce Richardson */
921*99a2dd95SBruce Richardson run_first_tims[min_idx] = run_first_tims[min_idx]->sl_next[0];
922*99a2dd95SBruce Richardson
923*99a2dd95SBruce Richardson data->priv_timer[this_lcore].updated = 0;
924*99a2dd95SBruce Richardson data->priv_timer[this_lcore].running_tim = tim;
925*99a2dd95SBruce Richardson
926*99a2dd95SBruce Richardson /* Call the provided callback function */
927*99a2dd95SBruce Richardson f(tim);
928*99a2dd95SBruce Richardson
929*99a2dd95SBruce Richardson __TIMER_STAT_ADD(data->priv_timer, pending, -1);
930*99a2dd95SBruce Richardson
931*99a2dd95SBruce Richardson /* the timer was stopped or reloaded by the callback
932*99a2dd95SBruce Richardson * function, we have nothing to do here
933*99a2dd95SBruce Richardson */
934*99a2dd95SBruce Richardson if (data->priv_timer[this_lcore].updated == 1)
935*99a2dd95SBruce Richardson continue;
936*99a2dd95SBruce Richardson
937*99a2dd95SBruce Richardson if (tim->period == 0) {
938*99a2dd95SBruce Richardson /* remove from done list and mark timer as stopped */
939*99a2dd95SBruce Richardson status.state = RTE_TIMER_STOP;
940*99a2dd95SBruce Richardson status.owner = RTE_TIMER_NO_OWNER;
941*99a2dd95SBruce Richardson /* The "RELEASE" ordering guarantees the memory
942*99a2dd95SBruce Richardson * operations above the status update are observed
943*99a2dd95SBruce Richardson * before the update by all threads
944*99a2dd95SBruce Richardson */
945*99a2dd95SBruce Richardson __atomic_store_n(&tim->status.u32, status.u32,
946*99a2dd95SBruce Richardson __ATOMIC_RELEASE);
947*99a2dd95SBruce Richardson } else {
948*99a2dd95SBruce Richardson /* keep it in list and mark timer as pending */
949*99a2dd95SBruce Richardson rte_spinlock_lock(
950*99a2dd95SBruce Richardson &data->priv_timer[this_lcore].list_lock);
951*99a2dd95SBruce Richardson status.state = RTE_TIMER_PENDING;
952*99a2dd95SBruce Richardson __TIMER_STAT_ADD(data->priv_timer, pending, 1);
953*99a2dd95SBruce Richardson status.owner = (int16_t)this_lcore;
954*99a2dd95SBruce Richardson /* The "RELEASE" ordering guarantees the memory
955*99a2dd95SBruce Richardson * operations above the status update are observed
956*99a2dd95SBruce Richardson * before the update by all threads
957*99a2dd95SBruce Richardson */
958*99a2dd95SBruce Richardson __atomic_store_n(&tim->status.u32, status.u32,
959*99a2dd95SBruce Richardson __ATOMIC_RELEASE);
960*99a2dd95SBruce Richardson __rte_timer_reset(tim, tim->expire + tim->period,
961*99a2dd95SBruce Richardson tim->period, this_lcore, tim->f, tim->arg, 1,
962*99a2dd95SBruce Richardson data);
963*99a2dd95SBruce Richardson rte_spinlock_unlock(
964*99a2dd95SBruce Richardson &data->priv_timer[this_lcore].list_lock);
965*99a2dd95SBruce Richardson }
966*99a2dd95SBruce Richardson
967*99a2dd95SBruce Richardson data->priv_timer[this_lcore].running_tim = NULL;
968*99a2dd95SBruce Richardson }
969*99a2dd95SBruce Richardson
970*99a2dd95SBruce Richardson return 0;
971*99a2dd95SBruce Richardson }
972*99a2dd95SBruce Richardson
973*99a2dd95SBruce Richardson /* Walk pending lists, stopping timers and calling user-specified function */
974*99a2dd95SBruce Richardson int
rte_timer_stop_all(uint32_t timer_data_id,unsigned int * walk_lcores,int nb_walk_lcores,rte_timer_stop_all_cb_t f,void * f_arg)975*99a2dd95SBruce Richardson rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores,
976*99a2dd95SBruce Richardson int nb_walk_lcores,
977*99a2dd95SBruce Richardson rte_timer_stop_all_cb_t f, void *f_arg)
978*99a2dd95SBruce Richardson {
979*99a2dd95SBruce Richardson int i;
980*99a2dd95SBruce Richardson struct priv_timer *priv_timer;
981*99a2dd95SBruce Richardson uint32_t walk_lcore;
982*99a2dd95SBruce Richardson struct rte_timer *tim, *next_tim;
983*99a2dd95SBruce Richardson struct rte_timer_data *timer_data;
984*99a2dd95SBruce Richardson
985*99a2dd95SBruce Richardson TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
986*99a2dd95SBruce Richardson
987*99a2dd95SBruce Richardson for (i = 0; i < nb_walk_lcores; i++) {
988*99a2dd95SBruce Richardson walk_lcore = walk_lcores[i];
989*99a2dd95SBruce Richardson priv_timer = &timer_data->priv_timer[walk_lcore];
990*99a2dd95SBruce Richardson
991*99a2dd95SBruce Richardson rte_spinlock_lock(&priv_timer->list_lock);
992*99a2dd95SBruce Richardson
993*99a2dd95SBruce Richardson for (tim = priv_timer->pending_head.sl_next[0];
994*99a2dd95SBruce Richardson tim != NULL;
995*99a2dd95SBruce Richardson tim = next_tim) {
996*99a2dd95SBruce Richardson next_tim = tim->sl_next[0];
997*99a2dd95SBruce Richardson
998*99a2dd95SBruce Richardson /* Call timer_stop with lock held */
999*99a2dd95SBruce Richardson __rte_timer_stop(tim, 1, timer_data);
1000*99a2dd95SBruce Richardson
1001*99a2dd95SBruce Richardson if (f)
1002*99a2dd95SBruce Richardson f(tim, f_arg);
1003*99a2dd95SBruce Richardson }
1004*99a2dd95SBruce Richardson
1005*99a2dd95SBruce Richardson rte_spinlock_unlock(&priv_timer->list_lock);
1006*99a2dd95SBruce Richardson }
1007*99a2dd95SBruce Richardson
1008*99a2dd95SBruce Richardson return 0;
1009*99a2dd95SBruce Richardson }
1010*99a2dd95SBruce Richardson
1011*99a2dd95SBruce Richardson int64_t
rte_timer_next_ticks(void)1012*99a2dd95SBruce Richardson rte_timer_next_ticks(void)
1013*99a2dd95SBruce Richardson {
1014*99a2dd95SBruce Richardson unsigned int lcore_id = rte_lcore_id();
1015*99a2dd95SBruce Richardson struct rte_timer_data *timer_data;
1016*99a2dd95SBruce Richardson struct priv_timer *priv_timer;
1017*99a2dd95SBruce Richardson const struct rte_timer *tm;
1018*99a2dd95SBruce Richardson uint64_t cur_time;
1019*99a2dd95SBruce Richardson int64_t left = -ENOENT;
1020*99a2dd95SBruce Richardson
1021*99a2dd95SBruce Richardson TIMER_DATA_VALID_GET_OR_ERR_RET(default_data_id, timer_data, -EINVAL);
1022*99a2dd95SBruce Richardson
1023*99a2dd95SBruce Richardson priv_timer = timer_data->priv_timer;
1024*99a2dd95SBruce Richardson cur_time = rte_get_timer_cycles();
1025*99a2dd95SBruce Richardson
1026*99a2dd95SBruce Richardson rte_spinlock_lock(&priv_timer[lcore_id].list_lock);
1027*99a2dd95SBruce Richardson tm = priv_timer[lcore_id].pending_head.sl_next[0];
1028*99a2dd95SBruce Richardson if (tm) {
1029*99a2dd95SBruce Richardson left = tm->expire - cur_time;
1030*99a2dd95SBruce Richardson if (left < 0)
1031*99a2dd95SBruce Richardson left = 0;
1032*99a2dd95SBruce Richardson }
1033*99a2dd95SBruce Richardson rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
1034*99a2dd95SBruce Richardson
1035*99a2dd95SBruce Richardson return left;
1036*99a2dd95SBruce Richardson }
1037*99a2dd95SBruce Richardson
1038*99a2dd95SBruce Richardson /* dump statistics about timers */
1039*99a2dd95SBruce Richardson static void
__rte_timer_dump_stats(struct rte_timer_data * timer_data __rte_unused,FILE * f)1040*99a2dd95SBruce Richardson __rte_timer_dump_stats(struct rte_timer_data *timer_data __rte_unused, FILE *f)
1041*99a2dd95SBruce Richardson {
1042*99a2dd95SBruce Richardson #ifdef RTE_LIBRTE_TIMER_DEBUG
1043*99a2dd95SBruce Richardson struct rte_timer_debug_stats sum;
1044*99a2dd95SBruce Richardson unsigned lcore_id;
1045*99a2dd95SBruce Richardson struct priv_timer *priv_timer = timer_data->priv_timer;
1046*99a2dd95SBruce Richardson
1047*99a2dd95SBruce Richardson memset(&sum, 0, sizeof(sum));
1048*99a2dd95SBruce Richardson for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1049*99a2dd95SBruce Richardson sum.reset += priv_timer[lcore_id].stats.reset;
1050*99a2dd95SBruce Richardson sum.stop += priv_timer[lcore_id].stats.stop;
1051*99a2dd95SBruce Richardson sum.manage += priv_timer[lcore_id].stats.manage;
1052*99a2dd95SBruce Richardson sum.pending += priv_timer[lcore_id].stats.pending;
1053*99a2dd95SBruce Richardson }
1054*99a2dd95SBruce Richardson fprintf(f, "Timer statistics:\n");
1055*99a2dd95SBruce Richardson fprintf(f, " reset = %"PRIu64"\n", sum.reset);
1056*99a2dd95SBruce Richardson fprintf(f, " stop = %"PRIu64"\n", sum.stop);
1057*99a2dd95SBruce Richardson fprintf(f, " manage = %"PRIu64"\n", sum.manage);
1058*99a2dd95SBruce Richardson fprintf(f, " pending = %"PRIu64"\n", sum.pending);
1059*99a2dd95SBruce Richardson #else
1060*99a2dd95SBruce Richardson fprintf(f, "No timer statistics, RTE_LIBRTE_TIMER_DEBUG is disabled\n");
1061*99a2dd95SBruce Richardson #endif
1062*99a2dd95SBruce Richardson }
1063*99a2dd95SBruce Richardson
1064*99a2dd95SBruce Richardson int
rte_timer_dump_stats(FILE * f)1065*99a2dd95SBruce Richardson rte_timer_dump_stats(FILE *f)
1066*99a2dd95SBruce Richardson {
1067*99a2dd95SBruce Richardson return rte_timer_alt_dump_stats(default_data_id, f);
1068*99a2dd95SBruce Richardson }
1069*99a2dd95SBruce Richardson
1070*99a2dd95SBruce Richardson int
rte_timer_alt_dump_stats(uint32_t timer_data_id __rte_unused,FILE * f)1071*99a2dd95SBruce Richardson rte_timer_alt_dump_stats(uint32_t timer_data_id __rte_unused, FILE *f)
1072*99a2dd95SBruce Richardson {
1073*99a2dd95SBruce Richardson struct rte_timer_data *timer_data;
1074*99a2dd95SBruce Richardson
1075*99a2dd95SBruce Richardson TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
1076*99a2dd95SBruce Richardson
1077*99a2dd95SBruce Richardson __rte_timer_dump_stats(timer_data, f);
1078*99a2dd95SBruce Richardson
1079*99a2dd95SBruce Richardson return 0;
1080*99a2dd95SBruce Richardson }
1081