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