xref: /dpdk/lib/timer/rte_timer.c (revision 30a1de10)
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