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