199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2017-2018 Intel Corporation. 399a2dd95SBruce Richardson * All rights reserved. 499a2dd95SBruce Richardson */ 599a2dd95SBruce Richardson 699a2dd95SBruce Richardson #include <string.h> 799a2dd95SBruce Richardson #include <inttypes.h> 899a2dd95SBruce Richardson #include <stdbool.h> 999a2dd95SBruce Richardson #include <sys/queue.h> 1099a2dd95SBruce Richardson 1199a2dd95SBruce Richardson #include <rte_memzone.h> 1299a2dd95SBruce Richardson #include <rte_memory.h> 1399a2dd95SBruce Richardson #include <rte_dev.h> 1499a2dd95SBruce Richardson #include <rte_errno.h> 1599a2dd95SBruce Richardson #include <rte_malloc.h> 1699a2dd95SBruce Richardson #include <rte_ring.h> 1799a2dd95SBruce Richardson #include <rte_mempool.h> 1899a2dd95SBruce Richardson #include <rte_common.h> 1999a2dd95SBruce Richardson #include <rte_timer.h> 2099a2dd95SBruce Richardson #include <rte_service_component.h> 2199a2dd95SBruce Richardson #include <rte_cycles.h> 2299a2dd95SBruce Richardson 2353548ad3SPavan Nikhilesh #include "event_timer_adapter_pmd.h" 2499a2dd95SBruce Richardson #include "eventdev_pmd.h" 2599a2dd95SBruce Richardson #include "rte_event_timer_adapter.h" 2653548ad3SPavan Nikhilesh #include "rte_eventdev.h" 2753548ad3SPavan Nikhilesh #include "rte_eventdev_trace.h" 2899a2dd95SBruce Richardson 2999a2dd95SBruce Richardson #define DATA_MZ_NAME_MAX_LEN 64 3099a2dd95SBruce Richardson #define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d" 3199a2dd95SBruce Richardson 32eeded204SDavid Marchand RTE_LOG_REGISTER_SUFFIX(evtim_logtype, adapter.timer, NOTICE); 33eeded204SDavid Marchand RTE_LOG_REGISTER_SUFFIX(evtim_buffer_logtype, adapter.timer, NOTICE); 34eeded204SDavid Marchand RTE_LOG_REGISTER_SUFFIX(evtim_svc_logtype, adapter.timer.svc, NOTICE); 3599a2dd95SBruce Richardson 36*f3f3a917SPavan Nikhilesh static struct rte_event_timer_adapter *adapters; 3799a2dd95SBruce Richardson 3853548ad3SPavan Nikhilesh static const struct event_timer_adapter_ops swtim_ops; 3999a2dd95SBruce Richardson 4099a2dd95SBruce Richardson #define EVTIM_LOG(level, logtype, ...) \ 4199a2dd95SBruce Richardson rte_log(RTE_LOG_ ## level, logtype, \ 4299a2dd95SBruce Richardson RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \ 4399a2dd95SBruce Richardson "\n", __func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__,))) 4499a2dd95SBruce Richardson 4599a2dd95SBruce Richardson #define EVTIM_LOG_ERR(...) EVTIM_LOG(ERR, evtim_logtype, __VA_ARGS__) 4699a2dd95SBruce Richardson 4799a2dd95SBruce Richardson #ifdef RTE_LIBRTE_EVENTDEV_DEBUG 4899a2dd95SBruce Richardson #define EVTIM_LOG_DBG(...) \ 4999a2dd95SBruce Richardson EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__) 5099a2dd95SBruce Richardson #define EVTIM_BUF_LOG_DBG(...) \ 5199a2dd95SBruce Richardson EVTIM_LOG(DEBUG, evtim_buffer_logtype, __VA_ARGS__) 5299a2dd95SBruce Richardson #define EVTIM_SVC_LOG_DBG(...) \ 5399a2dd95SBruce Richardson EVTIM_LOG(DEBUG, evtim_svc_logtype, __VA_ARGS__) 5499a2dd95SBruce Richardson #else 5599a2dd95SBruce Richardson #define EVTIM_LOG_DBG(...) (void)0 5699a2dd95SBruce Richardson #define EVTIM_BUF_LOG_DBG(...) (void)0 5799a2dd95SBruce Richardson #define EVTIM_SVC_LOG_DBG(...) (void)0 5899a2dd95SBruce Richardson #endif 5999a2dd95SBruce Richardson 6099a2dd95SBruce Richardson static int 6199a2dd95SBruce Richardson default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id, 6299a2dd95SBruce Richardson void *conf_arg) 6399a2dd95SBruce Richardson { 6499a2dd95SBruce Richardson struct rte_event_timer_adapter *adapter; 6599a2dd95SBruce Richardson struct rte_eventdev *dev; 6699a2dd95SBruce Richardson struct rte_event_dev_config dev_conf; 6799a2dd95SBruce Richardson struct rte_event_port_conf *port_conf, def_port_conf = {0}; 6899a2dd95SBruce Richardson int started; 6999a2dd95SBruce Richardson uint8_t port_id; 7099a2dd95SBruce Richardson uint8_t dev_id; 7199a2dd95SBruce Richardson int ret; 7299a2dd95SBruce Richardson 7399a2dd95SBruce Richardson RTE_SET_USED(event_dev_id); 7499a2dd95SBruce Richardson 7599a2dd95SBruce Richardson adapter = &adapters[id]; 7699a2dd95SBruce Richardson dev = &rte_eventdevs[adapter->data->event_dev_id]; 7799a2dd95SBruce Richardson dev_id = dev->data->dev_id; 7899a2dd95SBruce Richardson dev_conf = dev->data->dev_conf; 7999a2dd95SBruce Richardson 8099a2dd95SBruce Richardson started = dev->data->dev_started; 8199a2dd95SBruce Richardson if (started) 8299a2dd95SBruce Richardson rte_event_dev_stop(dev_id); 8399a2dd95SBruce Richardson 8499a2dd95SBruce Richardson port_id = dev_conf.nb_event_ports; 8599a2dd95SBruce Richardson dev_conf.nb_event_ports += 1; 8699a2dd95SBruce Richardson ret = rte_event_dev_configure(dev_id, &dev_conf); 8799a2dd95SBruce Richardson if (ret < 0) { 8899a2dd95SBruce Richardson EVTIM_LOG_ERR("failed to configure event dev %u\n", dev_id); 8999a2dd95SBruce Richardson if (started) 9099a2dd95SBruce Richardson if (rte_event_dev_start(dev_id)) 9199a2dd95SBruce Richardson return -EIO; 9299a2dd95SBruce Richardson 9399a2dd95SBruce Richardson return ret; 9499a2dd95SBruce Richardson } 9599a2dd95SBruce Richardson 9699a2dd95SBruce Richardson if (conf_arg != NULL) 9799a2dd95SBruce Richardson port_conf = conf_arg; 9899a2dd95SBruce Richardson else { 9999a2dd95SBruce Richardson port_conf = &def_port_conf; 10099a2dd95SBruce Richardson ret = rte_event_port_default_conf_get(dev_id, port_id, 10199a2dd95SBruce Richardson port_conf); 10299a2dd95SBruce Richardson if (ret < 0) 10399a2dd95SBruce Richardson return ret; 10499a2dd95SBruce Richardson } 10599a2dd95SBruce Richardson 10699a2dd95SBruce Richardson ret = rte_event_port_setup(dev_id, port_id, port_conf); 10799a2dd95SBruce Richardson if (ret < 0) { 10899a2dd95SBruce Richardson EVTIM_LOG_ERR("failed to setup event port %u on event dev %u\n", 10999a2dd95SBruce Richardson port_id, dev_id); 11099a2dd95SBruce Richardson return ret; 11199a2dd95SBruce Richardson } 11299a2dd95SBruce Richardson 11399a2dd95SBruce Richardson *event_port_id = port_id; 11499a2dd95SBruce Richardson 11599a2dd95SBruce Richardson if (started) 11699a2dd95SBruce Richardson ret = rte_event_dev_start(dev_id); 11799a2dd95SBruce Richardson 11899a2dd95SBruce Richardson return ret; 11999a2dd95SBruce Richardson } 12099a2dd95SBruce Richardson 12199a2dd95SBruce Richardson struct rte_event_timer_adapter * 12299a2dd95SBruce Richardson rte_event_timer_adapter_create(const struct rte_event_timer_adapter_conf *conf) 12399a2dd95SBruce Richardson { 12499a2dd95SBruce Richardson return rte_event_timer_adapter_create_ext(conf, default_port_conf_cb, 12599a2dd95SBruce Richardson NULL); 12699a2dd95SBruce Richardson } 12799a2dd95SBruce Richardson 12899a2dd95SBruce Richardson struct rte_event_timer_adapter * 12999a2dd95SBruce Richardson rte_event_timer_adapter_create_ext( 13099a2dd95SBruce Richardson const struct rte_event_timer_adapter_conf *conf, 13199a2dd95SBruce Richardson rte_event_timer_adapter_port_conf_cb_t conf_cb, 13299a2dd95SBruce Richardson void *conf_arg) 13399a2dd95SBruce Richardson { 13499a2dd95SBruce Richardson uint16_t adapter_id; 13599a2dd95SBruce Richardson struct rte_event_timer_adapter *adapter; 13699a2dd95SBruce Richardson const struct rte_memzone *mz; 13799a2dd95SBruce Richardson char mz_name[DATA_MZ_NAME_MAX_LEN]; 13899a2dd95SBruce Richardson int n, ret; 13999a2dd95SBruce Richardson struct rte_eventdev *dev; 14099a2dd95SBruce Richardson 141*f3f3a917SPavan Nikhilesh if (adapters == NULL) { 142*f3f3a917SPavan Nikhilesh adapters = rte_zmalloc("Eventdev", 143*f3f3a917SPavan Nikhilesh sizeof(struct rte_event_timer_adapter) * 144*f3f3a917SPavan Nikhilesh RTE_EVENT_TIMER_ADAPTER_NUM_MAX, 145*f3f3a917SPavan Nikhilesh RTE_CACHE_LINE_SIZE); 146*f3f3a917SPavan Nikhilesh if (adapters == NULL) { 147*f3f3a917SPavan Nikhilesh rte_errno = ENOMEM; 148*f3f3a917SPavan Nikhilesh return NULL; 149*f3f3a917SPavan Nikhilesh } 150*f3f3a917SPavan Nikhilesh } 151*f3f3a917SPavan Nikhilesh 15299a2dd95SBruce Richardson if (conf == NULL) { 15399a2dd95SBruce Richardson rte_errno = EINVAL; 15499a2dd95SBruce Richardson return NULL; 15599a2dd95SBruce Richardson } 15699a2dd95SBruce Richardson 15799a2dd95SBruce Richardson /* Check eventdev ID */ 15899a2dd95SBruce Richardson if (!rte_event_pmd_is_valid_dev(conf->event_dev_id)) { 15999a2dd95SBruce Richardson rte_errno = EINVAL; 16099a2dd95SBruce Richardson return NULL; 16199a2dd95SBruce Richardson } 16299a2dd95SBruce Richardson dev = &rte_eventdevs[conf->event_dev_id]; 16399a2dd95SBruce Richardson 16499a2dd95SBruce Richardson adapter_id = conf->timer_adapter_id; 16599a2dd95SBruce Richardson 16699a2dd95SBruce Richardson /* Check that adapter_id is in range */ 16799a2dd95SBruce Richardson if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) { 16899a2dd95SBruce Richardson rte_errno = EINVAL; 16999a2dd95SBruce Richardson return NULL; 17099a2dd95SBruce Richardson } 17199a2dd95SBruce Richardson 17299a2dd95SBruce Richardson /* Check adapter ID not already allocated */ 17399a2dd95SBruce Richardson adapter = &adapters[adapter_id]; 17499a2dd95SBruce Richardson if (adapter->allocated) { 17599a2dd95SBruce Richardson rte_errno = EEXIST; 17699a2dd95SBruce Richardson return NULL; 17799a2dd95SBruce Richardson } 17899a2dd95SBruce Richardson 17999a2dd95SBruce Richardson /* Create shared data area. */ 18099a2dd95SBruce Richardson n = snprintf(mz_name, sizeof(mz_name), DATA_MZ_NAME_FORMAT, adapter_id); 18199a2dd95SBruce Richardson if (n >= (int)sizeof(mz_name)) { 18299a2dd95SBruce Richardson rte_errno = EINVAL; 18399a2dd95SBruce Richardson return NULL; 18499a2dd95SBruce Richardson } 18599a2dd95SBruce Richardson mz = rte_memzone_reserve(mz_name, 18699a2dd95SBruce Richardson sizeof(struct rte_event_timer_adapter_data), 18799a2dd95SBruce Richardson conf->socket_id, 0); 18899a2dd95SBruce Richardson if (mz == NULL) 18999a2dd95SBruce Richardson /* rte_errno set by rte_memzone_reserve */ 19099a2dd95SBruce Richardson return NULL; 19199a2dd95SBruce Richardson 19299a2dd95SBruce Richardson adapter->data = mz->addr; 19399a2dd95SBruce Richardson memset(adapter->data, 0, sizeof(struct rte_event_timer_adapter_data)); 19499a2dd95SBruce Richardson 19599a2dd95SBruce Richardson adapter->data->mz = mz; 19699a2dd95SBruce Richardson adapter->data->event_dev_id = conf->event_dev_id; 19799a2dd95SBruce Richardson adapter->data->id = adapter_id; 19899a2dd95SBruce Richardson adapter->data->socket_id = conf->socket_id; 19999a2dd95SBruce Richardson adapter->data->conf = *conf; /* copy conf structure */ 20099a2dd95SBruce Richardson 20199a2dd95SBruce Richardson /* Query eventdev PMD for timer adapter capabilities and ops */ 20299a2dd95SBruce Richardson ret = dev->dev_ops->timer_adapter_caps_get(dev, 20399a2dd95SBruce Richardson adapter->data->conf.flags, 20499a2dd95SBruce Richardson &adapter->data->caps, 20599a2dd95SBruce Richardson &adapter->ops); 20699a2dd95SBruce Richardson if (ret < 0) { 20799a2dd95SBruce Richardson rte_errno = -ret; 20899a2dd95SBruce Richardson goto free_memzone; 20999a2dd95SBruce Richardson } 21099a2dd95SBruce Richardson 21199a2dd95SBruce Richardson if (!(adapter->data->caps & 21299a2dd95SBruce Richardson RTE_EVENT_TIMER_ADAPTER_CAP_INTERNAL_PORT)) { 21399a2dd95SBruce Richardson FUNC_PTR_OR_NULL_RET_WITH_ERRNO(conf_cb, EINVAL); 21499a2dd95SBruce Richardson ret = conf_cb(adapter->data->id, adapter->data->event_dev_id, 21599a2dd95SBruce Richardson &adapter->data->event_port_id, conf_arg); 21699a2dd95SBruce Richardson if (ret < 0) { 21799a2dd95SBruce Richardson rte_errno = -ret; 21899a2dd95SBruce Richardson goto free_memzone; 21999a2dd95SBruce Richardson } 22099a2dd95SBruce Richardson } 22199a2dd95SBruce Richardson 22299a2dd95SBruce Richardson /* If eventdev PMD did not provide ops, use default software 22399a2dd95SBruce Richardson * implementation. 22499a2dd95SBruce Richardson */ 22599a2dd95SBruce Richardson if (adapter->ops == NULL) 22699a2dd95SBruce Richardson adapter->ops = &swtim_ops; 22799a2dd95SBruce Richardson 22899a2dd95SBruce Richardson /* Allow driver to do some setup */ 22999a2dd95SBruce Richardson FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, ENOTSUP); 23099a2dd95SBruce Richardson ret = adapter->ops->init(adapter); 23199a2dd95SBruce Richardson if (ret < 0) { 23299a2dd95SBruce Richardson rte_errno = -ret; 23399a2dd95SBruce Richardson goto free_memzone; 23499a2dd95SBruce Richardson } 23599a2dd95SBruce Richardson 23699a2dd95SBruce Richardson /* Set fast-path function pointers */ 23799a2dd95SBruce Richardson adapter->arm_burst = adapter->ops->arm_burst; 23899a2dd95SBruce Richardson adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst; 23999a2dd95SBruce Richardson adapter->cancel_burst = adapter->ops->cancel_burst; 24099a2dd95SBruce Richardson 24199a2dd95SBruce Richardson adapter->allocated = 1; 24299a2dd95SBruce Richardson 24399a2dd95SBruce Richardson rte_eventdev_trace_timer_adapter_create(adapter_id, adapter, conf, 24499a2dd95SBruce Richardson conf_cb); 24599a2dd95SBruce Richardson return adapter; 24699a2dd95SBruce Richardson 24799a2dd95SBruce Richardson free_memzone: 24899a2dd95SBruce Richardson rte_memzone_free(adapter->data->mz); 24999a2dd95SBruce Richardson return NULL; 25099a2dd95SBruce Richardson } 25199a2dd95SBruce Richardson 25299a2dd95SBruce Richardson int 25399a2dd95SBruce Richardson rte_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter, 25499a2dd95SBruce Richardson struct rte_event_timer_adapter_info *adapter_info) 25599a2dd95SBruce Richardson { 25699a2dd95SBruce Richardson ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL); 25799a2dd95SBruce Richardson 25899a2dd95SBruce Richardson if (adapter->ops->get_info) 25999a2dd95SBruce Richardson /* let driver set values it knows */ 26099a2dd95SBruce Richardson adapter->ops->get_info(adapter, adapter_info); 26199a2dd95SBruce Richardson 26299a2dd95SBruce Richardson /* Set common values */ 26399a2dd95SBruce Richardson adapter_info->conf = adapter->data->conf; 26499a2dd95SBruce Richardson adapter_info->event_dev_port_id = adapter->data->event_port_id; 26599a2dd95SBruce Richardson adapter_info->caps = adapter->data->caps; 26699a2dd95SBruce Richardson 26799a2dd95SBruce Richardson return 0; 26899a2dd95SBruce Richardson } 26999a2dd95SBruce Richardson 27099a2dd95SBruce Richardson int 27199a2dd95SBruce Richardson rte_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter) 27299a2dd95SBruce Richardson { 27399a2dd95SBruce Richardson int ret; 27499a2dd95SBruce Richardson 27599a2dd95SBruce Richardson ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL); 27699a2dd95SBruce Richardson FUNC_PTR_OR_ERR_RET(adapter->ops->start, -EINVAL); 27799a2dd95SBruce Richardson 27899a2dd95SBruce Richardson if (adapter->data->started) { 27999a2dd95SBruce Richardson EVTIM_LOG_ERR("event timer adapter %"PRIu8" already started", 28099a2dd95SBruce Richardson adapter->data->id); 28199a2dd95SBruce Richardson return -EALREADY; 28299a2dd95SBruce Richardson } 28399a2dd95SBruce Richardson 28499a2dd95SBruce Richardson ret = adapter->ops->start(adapter); 28599a2dd95SBruce Richardson if (ret < 0) 28699a2dd95SBruce Richardson return ret; 28799a2dd95SBruce Richardson 28899a2dd95SBruce Richardson adapter->data->started = 1; 28999a2dd95SBruce Richardson rte_eventdev_trace_timer_adapter_start(adapter); 29099a2dd95SBruce Richardson return 0; 29199a2dd95SBruce Richardson } 29299a2dd95SBruce Richardson 29399a2dd95SBruce Richardson int 29499a2dd95SBruce Richardson rte_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter) 29599a2dd95SBruce Richardson { 29699a2dd95SBruce Richardson int ret; 29799a2dd95SBruce Richardson 29899a2dd95SBruce Richardson ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL); 29999a2dd95SBruce Richardson FUNC_PTR_OR_ERR_RET(adapter->ops->stop, -EINVAL); 30099a2dd95SBruce Richardson 30199a2dd95SBruce Richardson if (adapter->data->started == 0) { 30299a2dd95SBruce Richardson EVTIM_LOG_ERR("event timer adapter %"PRIu8" already stopped", 30399a2dd95SBruce Richardson adapter->data->id); 30499a2dd95SBruce Richardson return 0; 30599a2dd95SBruce Richardson } 30699a2dd95SBruce Richardson 30799a2dd95SBruce Richardson ret = adapter->ops->stop(adapter); 30899a2dd95SBruce Richardson if (ret < 0) 30999a2dd95SBruce Richardson return ret; 31099a2dd95SBruce Richardson 31199a2dd95SBruce Richardson adapter->data->started = 0; 31299a2dd95SBruce Richardson rte_eventdev_trace_timer_adapter_stop(adapter); 31399a2dd95SBruce Richardson return 0; 31499a2dd95SBruce Richardson } 31599a2dd95SBruce Richardson 31699a2dd95SBruce Richardson struct rte_event_timer_adapter * 31799a2dd95SBruce Richardson rte_event_timer_adapter_lookup(uint16_t adapter_id) 31899a2dd95SBruce Richardson { 31999a2dd95SBruce Richardson char name[DATA_MZ_NAME_MAX_LEN]; 32099a2dd95SBruce Richardson const struct rte_memzone *mz; 32199a2dd95SBruce Richardson struct rte_event_timer_adapter_data *data; 32299a2dd95SBruce Richardson struct rte_event_timer_adapter *adapter; 32399a2dd95SBruce Richardson int ret; 32499a2dd95SBruce Richardson struct rte_eventdev *dev; 32599a2dd95SBruce Richardson 326*f3f3a917SPavan Nikhilesh if (adapters == NULL) { 327*f3f3a917SPavan Nikhilesh adapters = rte_zmalloc("Eventdev", 328*f3f3a917SPavan Nikhilesh sizeof(struct rte_event_timer_adapter) * 329*f3f3a917SPavan Nikhilesh RTE_EVENT_TIMER_ADAPTER_NUM_MAX, 330*f3f3a917SPavan Nikhilesh RTE_CACHE_LINE_SIZE); 331*f3f3a917SPavan Nikhilesh if (adapters == NULL) { 332*f3f3a917SPavan Nikhilesh rte_errno = ENOMEM; 333*f3f3a917SPavan Nikhilesh return NULL; 334*f3f3a917SPavan Nikhilesh } 335*f3f3a917SPavan Nikhilesh } 336*f3f3a917SPavan Nikhilesh 33799a2dd95SBruce Richardson if (adapters[adapter_id].allocated) 33899a2dd95SBruce Richardson return &adapters[adapter_id]; /* Adapter is already loaded */ 33999a2dd95SBruce Richardson 34099a2dd95SBruce Richardson snprintf(name, DATA_MZ_NAME_MAX_LEN, DATA_MZ_NAME_FORMAT, adapter_id); 34199a2dd95SBruce Richardson mz = rte_memzone_lookup(name); 34299a2dd95SBruce Richardson if (mz == NULL) { 34399a2dd95SBruce Richardson rte_errno = ENOENT; 34499a2dd95SBruce Richardson return NULL; 34599a2dd95SBruce Richardson } 34699a2dd95SBruce Richardson 34799a2dd95SBruce Richardson data = mz->addr; 34899a2dd95SBruce Richardson 34999a2dd95SBruce Richardson adapter = &adapters[data->id]; 35099a2dd95SBruce Richardson adapter->data = data; 35199a2dd95SBruce Richardson 35299a2dd95SBruce Richardson dev = &rte_eventdevs[adapter->data->event_dev_id]; 35399a2dd95SBruce Richardson 35499a2dd95SBruce Richardson /* Query eventdev PMD for timer adapter capabilities and ops */ 35599a2dd95SBruce Richardson ret = dev->dev_ops->timer_adapter_caps_get(dev, 35699a2dd95SBruce Richardson adapter->data->conf.flags, 35799a2dd95SBruce Richardson &adapter->data->caps, 35899a2dd95SBruce Richardson &adapter->ops); 35999a2dd95SBruce Richardson if (ret < 0) { 36099a2dd95SBruce Richardson rte_errno = EINVAL; 36199a2dd95SBruce Richardson return NULL; 36299a2dd95SBruce Richardson } 36399a2dd95SBruce Richardson 36499a2dd95SBruce Richardson /* If eventdev PMD did not provide ops, use default software 36599a2dd95SBruce Richardson * implementation. 36699a2dd95SBruce Richardson */ 36799a2dd95SBruce Richardson if (adapter->ops == NULL) 36899a2dd95SBruce Richardson adapter->ops = &swtim_ops; 36999a2dd95SBruce Richardson 37099a2dd95SBruce Richardson /* Set fast-path function pointers */ 37199a2dd95SBruce Richardson adapter->arm_burst = adapter->ops->arm_burst; 37299a2dd95SBruce Richardson adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst; 37399a2dd95SBruce Richardson adapter->cancel_burst = adapter->ops->cancel_burst; 37499a2dd95SBruce Richardson 37599a2dd95SBruce Richardson adapter->allocated = 1; 37699a2dd95SBruce Richardson 37799a2dd95SBruce Richardson return adapter; 37899a2dd95SBruce Richardson } 37999a2dd95SBruce Richardson 38099a2dd95SBruce Richardson int 38199a2dd95SBruce Richardson rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter) 38299a2dd95SBruce Richardson { 383*f3f3a917SPavan Nikhilesh int i, ret; 38499a2dd95SBruce Richardson 38599a2dd95SBruce Richardson ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL); 38699a2dd95SBruce Richardson FUNC_PTR_OR_ERR_RET(adapter->ops->uninit, -EINVAL); 38799a2dd95SBruce Richardson 38899a2dd95SBruce Richardson if (adapter->data->started == 1) { 38999a2dd95SBruce Richardson EVTIM_LOG_ERR("event timer adapter %"PRIu8" must be stopped " 39099a2dd95SBruce Richardson "before freeing", adapter->data->id); 39199a2dd95SBruce Richardson return -EBUSY; 39299a2dd95SBruce Richardson } 39399a2dd95SBruce Richardson 39499a2dd95SBruce Richardson /* free impl priv data */ 39599a2dd95SBruce Richardson ret = adapter->ops->uninit(adapter); 39699a2dd95SBruce Richardson if (ret < 0) 39799a2dd95SBruce Richardson return ret; 39899a2dd95SBruce Richardson 39999a2dd95SBruce Richardson /* free shared data area */ 40099a2dd95SBruce Richardson ret = rte_memzone_free(adapter->data->mz); 40199a2dd95SBruce Richardson if (ret < 0) 40299a2dd95SBruce Richardson return ret; 40399a2dd95SBruce Richardson 40499a2dd95SBruce Richardson adapter->data = NULL; 40599a2dd95SBruce Richardson adapter->allocated = 0; 40699a2dd95SBruce Richardson 407*f3f3a917SPavan Nikhilesh ret = 0; 408*f3f3a917SPavan Nikhilesh for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) 409*f3f3a917SPavan Nikhilesh if (adapters[i].allocated) 410*f3f3a917SPavan Nikhilesh ret = adapters[i].allocated; 411*f3f3a917SPavan Nikhilesh 412*f3f3a917SPavan Nikhilesh if (!ret) { 413*f3f3a917SPavan Nikhilesh rte_free(adapters); 414*f3f3a917SPavan Nikhilesh adapters = NULL; 415*f3f3a917SPavan Nikhilesh } 416*f3f3a917SPavan Nikhilesh 41799a2dd95SBruce Richardson rte_eventdev_trace_timer_adapter_free(adapter); 41899a2dd95SBruce Richardson return 0; 41999a2dd95SBruce Richardson } 42099a2dd95SBruce Richardson 42199a2dd95SBruce Richardson int 42299a2dd95SBruce Richardson rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter, 42399a2dd95SBruce Richardson uint32_t *service_id) 42499a2dd95SBruce Richardson { 42599a2dd95SBruce Richardson ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL); 42699a2dd95SBruce Richardson 42799a2dd95SBruce Richardson if (adapter->data->service_inited && service_id != NULL) 42899a2dd95SBruce Richardson *service_id = adapter->data->service_id; 42999a2dd95SBruce Richardson 43099a2dd95SBruce Richardson return adapter->data->service_inited ? 0 : -ESRCH; 43199a2dd95SBruce Richardson } 43299a2dd95SBruce Richardson 43399a2dd95SBruce Richardson int 43499a2dd95SBruce Richardson rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter, 43599a2dd95SBruce Richardson struct rte_event_timer_adapter_stats *stats) 43699a2dd95SBruce Richardson { 43799a2dd95SBruce Richardson ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL); 43899a2dd95SBruce Richardson FUNC_PTR_OR_ERR_RET(adapter->ops->stats_get, -EINVAL); 43999a2dd95SBruce Richardson if (stats == NULL) 44099a2dd95SBruce Richardson return -EINVAL; 44199a2dd95SBruce Richardson 44299a2dd95SBruce Richardson return adapter->ops->stats_get(adapter, stats); 44399a2dd95SBruce Richardson } 44499a2dd95SBruce Richardson 44599a2dd95SBruce Richardson int 44699a2dd95SBruce Richardson rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter) 44799a2dd95SBruce Richardson { 44899a2dd95SBruce Richardson ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL); 44999a2dd95SBruce Richardson FUNC_PTR_OR_ERR_RET(adapter->ops->stats_reset, -EINVAL); 45099a2dd95SBruce Richardson return adapter->ops->stats_reset(adapter); 45199a2dd95SBruce Richardson } 45299a2dd95SBruce Richardson 45399a2dd95SBruce Richardson /* 45499a2dd95SBruce Richardson * Software event timer adapter buffer helper functions 45599a2dd95SBruce Richardson */ 45699a2dd95SBruce Richardson 45799a2dd95SBruce Richardson #define NSECPERSEC 1E9 45899a2dd95SBruce Richardson 45999a2dd95SBruce Richardson /* Optimizations used to index into the buffer require that the buffer size 46099a2dd95SBruce Richardson * be a power of 2. 46199a2dd95SBruce Richardson */ 46299a2dd95SBruce Richardson #define EVENT_BUFFER_SZ 4096 46399a2dd95SBruce Richardson #define EVENT_BUFFER_BATCHSZ 32 46499a2dd95SBruce Richardson #define EVENT_BUFFER_MASK (EVENT_BUFFER_SZ - 1) 46599a2dd95SBruce Richardson 46699a2dd95SBruce Richardson #define EXP_TIM_BUF_SZ 128 46799a2dd95SBruce Richardson 46899a2dd95SBruce Richardson struct event_buffer { 46999a2dd95SBruce Richardson size_t head; 47099a2dd95SBruce Richardson size_t tail; 47199a2dd95SBruce Richardson struct rte_event events[EVENT_BUFFER_SZ]; 47299a2dd95SBruce Richardson } __rte_cache_aligned; 47399a2dd95SBruce Richardson 47499a2dd95SBruce Richardson static inline bool 47599a2dd95SBruce Richardson event_buffer_full(struct event_buffer *bufp) 47699a2dd95SBruce Richardson { 47799a2dd95SBruce Richardson return (bufp->head - bufp->tail) == EVENT_BUFFER_SZ; 47899a2dd95SBruce Richardson } 47999a2dd95SBruce Richardson 48099a2dd95SBruce Richardson static inline bool 48199a2dd95SBruce Richardson event_buffer_batch_ready(struct event_buffer *bufp) 48299a2dd95SBruce Richardson { 48399a2dd95SBruce Richardson return (bufp->head - bufp->tail) >= EVENT_BUFFER_BATCHSZ; 48499a2dd95SBruce Richardson } 48599a2dd95SBruce Richardson 48699a2dd95SBruce Richardson static void 48799a2dd95SBruce Richardson event_buffer_init(struct event_buffer *bufp) 48899a2dd95SBruce Richardson { 48999a2dd95SBruce Richardson bufp->head = bufp->tail = 0; 49099a2dd95SBruce Richardson memset(&bufp->events, 0, sizeof(struct rte_event) * EVENT_BUFFER_SZ); 49199a2dd95SBruce Richardson } 49299a2dd95SBruce Richardson 49399a2dd95SBruce Richardson static int 49499a2dd95SBruce Richardson event_buffer_add(struct event_buffer *bufp, struct rte_event *eventp) 49599a2dd95SBruce Richardson { 49699a2dd95SBruce Richardson size_t head_idx; 49799a2dd95SBruce Richardson struct rte_event *buf_eventp; 49899a2dd95SBruce Richardson 49999a2dd95SBruce Richardson if (event_buffer_full(bufp)) 50099a2dd95SBruce Richardson return -1; 50199a2dd95SBruce Richardson 50299a2dd95SBruce Richardson /* Instead of modulus, bitwise AND with mask to get head_idx. */ 50399a2dd95SBruce Richardson head_idx = bufp->head & EVENT_BUFFER_MASK; 50499a2dd95SBruce Richardson buf_eventp = &bufp->events[head_idx]; 50599a2dd95SBruce Richardson rte_memcpy(buf_eventp, eventp, sizeof(struct rte_event)); 50699a2dd95SBruce Richardson 50799a2dd95SBruce Richardson /* Wrap automatically when overflow occurs. */ 50899a2dd95SBruce Richardson bufp->head++; 50999a2dd95SBruce Richardson 51099a2dd95SBruce Richardson return 0; 51199a2dd95SBruce Richardson } 51299a2dd95SBruce Richardson 51399a2dd95SBruce Richardson static void 51499a2dd95SBruce Richardson event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id, 51599a2dd95SBruce Richardson uint16_t *nb_events_flushed, 51699a2dd95SBruce Richardson uint16_t *nb_events_inv) 51799a2dd95SBruce Richardson { 51899a2dd95SBruce Richardson struct rte_event *events = bufp->events; 51999a2dd95SBruce Richardson size_t head_idx, tail_idx; 52099a2dd95SBruce Richardson uint16_t n = 0; 52199a2dd95SBruce Richardson 52299a2dd95SBruce Richardson /* Instead of modulus, bitwise AND with mask to get index. */ 52399a2dd95SBruce Richardson head_idx = bufp->head & EVENT_BUFFER_MASK; 52499a2dd95SBruce Richardson tail_idx = bufp->tail & EVENT_BUFFER_MASK; 52599a2dd95SBruce Richardson 52699a2dd95SBruce Richardson RTE_ASSERT(head_idx < EVENT_BUFFER_SZ && tail_idx < EVENT_BUFFER_SZ); 52799a2dd95SBruce Richardson 52899a2dd95SBruce Richardson /* Determine the largest contigous run we can attempt to enqueue to the 52999a2dd95SBruce Richardson * event device. 53099a2dd95SBruce Richardson */ 53199a2dd95SBruce Richardson if (head_idx > tail_idx) 53299a2dd95SBruce Richardson n = head_idx - tail_idx; 53399a2dd95SBruce Richardson else if (head_idx < tail_idx) 53499a2dd95SBruce Richardson n = EVENT_BUFFER_SZ - tail_idx; 53599a2dd95SBruce Richardson else if (event_buffer_full(bufp)) 53699a2dd95SBruce Richardson n = EVENT_BUFFER_SZ - tail_idx; 53799a2dd95SBruce Richardson else { 53899a2dd95SBruce Richardson *nb_events_flushed = 0; 53999a2dd95SBruce Richardson return; 54099a2dd95SBruce Richardson } 54199a2dd95SBruce Richardson 54299a2dd95SBruce Richardson n = RTE_MIN(EVENT_BUFFER_BATCHSZ, n); 54399a2dd95SBruce Richardson *nb_events_inv = 0; 54499a2dd95SBruce Richardson 54599a2dd95SBruce Richardson *nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id, 54699a2dd95SBruce Richardson &events[tail_idx], n); 54799a2dd95SBruce Richardson if (*nb_events_flushed != n) { 54899a2dd95SBruce Richardson if (rte_errno == EINVAL) { 54999a2dd95SBruce Richardson EVTIM_LOG_ERR("failed to enqueue invalid event - " 55099a2dd95SBruce Richardson "dropping it"); 55199a2dd95SBruce Richardson (*nb_events_inv)++; 55299a2dd95SBruce Richardson } else if (rte_errno == ENOSPC) 55399a2dd95SBruce Richardson rte_pause(); 55499a2dd95SBruce Richardson } 55599a2dd95SBruce Richardson 55699a2dd95SBruce Richardson if (*nb_events_flushed > 0) 55799a2dd95SBruce Richardson EVTIM_BUF_LOG_DBG("enqueued %"PRIu16" timer events to event " 55899a2dd95SBruce Richardson "device", *nb_events_flushed); 55999a2dd95SBruce Richardson 56099a2dd95SBruce Richardson bufp->tail = bufp->tail + *nb_events_flushed + *nb_events_inv; 56199a2dd95SBruce Richardson } 56299a2dd95SBruce Richardson 56399a2dd95SBruce Richardson /* 56499a2dd95SBruce Richardson * Software event timer adapter implementation 56599a2dd95SBruce Richardson */ 56699a2dd95SBruce Richardson struct swtim { 56799a2dd95SBruce Richardson /* Identifier of service executing timer management logic. */ 56899a2dd95SBruce Richardson uint32_t service_id; 56999a2dd95SBruce Richardson /* The cycle count at which the adapter should next tick */ 57099a2dd95SBruce Richardson uint64_t next_tick_cycles; 57199a2dd95SBruce Richardson /* The tick resolution used by adapter instance. May have been 57299a2dd95SBruce Richardson * adjusted from what user requested 57399a2dd95SBruce Richardson */ 57499a2dd95SBruce Richardson uint64_t timer_tick_ns; 57599a2dd95SBruce Richardson /* Maximum timeout in nanoseconds allowed by adapter instance. */ 57699a2dd95SBruce Richardson uint64_t max_tmo_ns; 57799a2dd95SBruce Richardson /* Buffered timer expiry events to be enqueued to an event device. */ 57899a2dd95SBruce Richardson struct event_buffer buffer; 57999a2dd95SBruce Richardson /* Statistics */ 58099a2dd95SBruce Richardson struct rte_event_timer_adapter_stats stats; 58199a2dd95SBruce Richardson /* Mempool of timer objects */ 58299a2dd95SBruce Richardson struct rte_mempool *tim_pool; 58399a2dd95SBruce Richardson /* Back pointer for convenience */ 58499a2dd95SBruce Richardson struct rte_event_timer_adapter *adapter; 58599a2dd95SBruce Richardson /* Identifier of timer data instance */ 58699a2dd95SBruce Richardson uint32_t timer_data_id; 58799a2dd95SBruce Richardson /* Track which cores have actually armed a timer */ 58899a2dd95SBruce Richardson struct { 58999a2dd95SBruce Richardson uint16_t v; 59099a2dd95SBruce Richardson } __rte_cache_aligned in_use[RTE_MAX_LCORE]; 59199a2dd95SBruce Richardson /* Track which cores' timer lists should be polled */ 59299a2dd95SBruce Richardson unsigned int poll_lcores[RTE_MAX_LCORE]; 59399a2dd95SBruce Richardson /* The number of lists that should be polled */ 59499a2dd95SBruce Richardson int n_poll_lcores; 59599a2dd95SBruce Richardson /* Timers which have expired and can be returned to a mempool */ 59699a2dd95SBruce Richardson struct rte_timer *expired_timers[EXP_TIM_BUF_SZ]; 59799a2dd95SBruce Richardson /* The number of timers that can be returned to a mempool */ 59899a2dd95SBruce Richardson size_t n_expired_timers; 59999a2dd95SBruce Richardson }; 60099a2dd95SBruce Richardson 60199a2dd95SBruce Richardson static inline struct swtim * 60299a2dd95SBruce Richardson swtim_pmd_priv(const struct rte_event_timer_adapter *adapter) 60399a2dd95SBruce Richardson { 60499a2dd95SBruce Richardson return adapter->data->adapter_priv; 60599a2dd95SBruce Richardson } 60699a2dd95SBruce Richardson 60799a2dd95SBruce Richardson static void 60899a2dd95SBruce Richardson swtim_callback(struct rte_timer *tim) 60999a2dd95SBruce Richardson { 61099a2dd95SBruce Richardson struct rte_event_timer *evtim = tim->arg; 61199a2dd95SBruce Richardson struct rte_event_timer_adapter *adapter; 61299a2dd95SBruce Richardson unsigned int lcore = rte_lcore_id(); 61399a2dd95SBruce Richardson struct swtim *sw; 61499a2dd95SBruce Richardson uint16_t nb_evs_flushed = 0; 61599a2dd95SBruce Richardson uint16_t nb_evs_invalid = 0; 61699a2dd95SBruce Richardson uint64_t opaque; 61799a2dd95SBruce Richardson int ret; 61899a2dd95SBruce Richardson int n_lcores; 61999a2dd95SBruce Richardson 62099a2dd95SBruce Richardson opaque = evtim->impl_opaque[1]; 62199a2dd95SBruce Richardson adapter = (struct rte_event_timer_adapter *)(uintptr_t)opaque; 62299a2dd95SBruce Richardson sw = swtim_pmd_priv(adapter); 62399a2dd95SBruce Richardson 62499a2dd95SBruce Richardson ret = event_buffer_add(&sw->buffer, &evtim->ev); 62599a2dd95SBruce Richardson if (ret < 0) { 62699a2dd95SBruce Richardson /* If event buffer is full, put timer back in list with 62799a2dd95SBruce Richardson * immediate expiry value, so that we process it again on the 62899a2dd95SBruce Richardson * next iteration. 62999a2dd95SBruce Richardson */ 63099a2dd95SBruce Richardson ret = rte_timer_alt_reset(sw->timer_data_id, tim, 0, SINGLE, 63199a2dd95SBruce Richardson lcore, NULL, evtim); 63299a2dd95SBruce Richardson if (ret < 0) { 63399a2dd95SBruce Richardson EVTIM_LOG_DBG("event buffer full, failed to reset " 63499a2dd95SBruce Richardson "timer with immediate expiry value"); 63599a2dd95SBruce Richardson } else { 63699a2dd95SBruce Richardson sw->stats.evtim_retry_count++; 63799a2dd95SBruce Richardson EVTIM_LOG_DBG("event buffer full, resetting rte_timer " 63899a2dd95SBruce Richardson "with immediate expiry value"); 63999a2dd95SBruce Richardson } 64099a2dd95SBruce Richardson 64199a2dd95SBruce Richardson if (unlikely(sw->in_use[lcore].v == 0)) { 64299a2dd95SBruce Richardson sw->in_use[lcore].v = 1; 64399a2dd95SBruce Richardson n_lcores = __atomic_fetch_add(&sw->n_poll_lcores, 1, 64499a2dd95SBruce Richardson __ATOMIC_RELAXED); 64599a2dd95SBruce Richardson __atomic_store_n(&sw->poll_lcores[n_lcores], lcore, 64699a2dd95SBruce Richardson __ATOMIC_RELAXED); 64799a2dd95SBruce Richardson } 64899a2dd95SBruce Richardson } else { 64999a2dd95SBruce Richardson EVTIM_BUF_LOG_DBG("buffered an event timer expiry event"); 65099a2dd95SBruce Richardson 65199a2dd95SBruce Richardson /* Empty the buffer here, if necessary, to free older expired 65299a2dd95SBruce Richardson * timers only 65399a2dd95SBruce Richardson */ 65499a2dd95SBruce Richardson if (unlikely(sw->n_expired_timers == EXP_TIM_BUF_SZ)) { 65599a2dd95SBruce Richardson rte_mempool_put_bulk(sw->tim_pool, 65699a2dd95SBruce Richardson (void **)sw->expired_timers, 65799a2dd95SBruce Richardson sw->n_expired_timers); 65899a2dd95SBruce Richardson sw->n_expired_timers = 0; 65999a2dd95SBruce Richardson } 66099a2dd95SBruce Richardson 66199a2dd95SBruce Richardson sw->expired_timers[sw->n_expired_timers++] = tim; 66299a2dd95SBruce Richardson sw->stats.evtim_exp_count++; 66399a2dd95SBruce Richardson 66499a2dd95SBruce Richardson __atomic_store_n(&evtim->state, RTE_EVENT_TIMER_NOT_ARMED, 66599a2dd95SBruce Richardson __ATOMIC_RELEASE); 66699a2dd95SBruce Richardson } 66799a2dd95SBruce Richardson 66899a2dd95SBruce Richardson if (event_buffer_batch_ready(&sw->buffer)) { 66999a2dd95SBruce Richardson event_buffer_flush(&sw->buffer, 67099a2dd95SBruce Richardson adapter->data->event_dev_id, 67199a2dd95SBruce Richardson adapter->data->event_port_id, 67299a2dd95SBruce Richardson &nb_evs_flushed, 67399a2dd95SBruce Richardson &nb_evs_invalid); 67499a2dd95SBruce Richardson 67599a2dd95SBruce Richardson sw->stats.ev_enq_count += nb_evs_flushed; 67699a2dd95SBruce Richardson sw->stats.ev_inv_count += nb_evs_invalid; 67799a2dd95SBruce Richardson } 67899a2dd95SBruce Richardson } 67999a2dd95SBruce Richardson 68099a2dd95SBruce Richardson static __rte_always_inline uint64_t 68199a2dd95SBruce Richardson get_timeout_cycles(struct rte_event_timer *evtim, 68299a2dd95SBruce Richardson const struct rte_event_timer_adapter *adapter) 68399a2dd95SBruce Richardson { 68499a2dd95SBruce Richardson struct swtim *sw = swtim_pmd_priv(adapter); 68599a2dd95SBruce Richardson uint64_t timeout_ns = evtim->timeout_ticks * sw->timer_tick_ns; 68699a2dd95SBruce Richardson return timeout_ns * rte_get_timer_hz() / NSECPERSEC; 68799a2dd95SBruce Richardson } 68899a2dd95SBruce Richardson 68999a2dd95SBruce Richardson /* This function returns true if one or more (adapter) ticks have occurred since 69099a2dd95SBruce Richardson * the last time it was called. 69199a2dd95SBruce Richardson */ 69299a2dd95SBruce Richardson static inline bool 69399a2dd95SBruce Richardson swtim_did_tick(struct swtim *sw) 69499a2dd95SBruce Richardson { 69599a2dd95SBruce Richardson uint64_t cycles_per_adapter_tick, start_cycles; 69699a2dd95SBruce Richardson uint64_t *next_tick_cyclesp; 69799a2dd95SBruce Richardson 69899a2dd95SBruce Richardson next_tick_cyclesp = &sw->next_tick_cycles; 69999a2dd95SBruce Richardson cycles_per_adapter_tick = sw->timer_tick_ns * 70099a2dd95SBruce Richardson (rte_get_timer_hz() / NSECPERSEC); 70199a2dd95SBruce Richardson start_cycles = rte_get_timer_cycles(); 70299a2dd95SBruce Richardson 70399a2dd95SBruce Richardson /* Note: initially, *next_tick_cyclesp == 0, so the clause below will 70499a2dd95SBruce Richardson * execute, and set things going. 70599a2dd95SBruce Richardson */ 70699a2dd95SBruce Richardson 70799a2dd95SBruce Richardson if (start_cycles >= *next_tick_cyclesp) { 70899a2dd95SBruce Richardson /* Snap the current cycle count to the preceding adapter tick 70999a2dd95SBruce Richardson * boundary. 71099a2dd95SBruce Richardson */ 71199a2dd95SBruce Richardson start_cycles -= start_cycles % cycles_per_adapter_tick; 71299a2dd95SBruce Richardson *next_tick_cyclesp = start_cycles + cycles_per_adapter_tick; 71399a2dd95SBruce Richardson 71499a2dd95SBruce Richardson return true; 71599a2dd95SBruce Richardson } 71699a2dd95SBruce Richardson 71799a2dd95SBruce Richardson return false; 71899a2dd95SBruce Richardson } 71999a2dd95SBruce Richardson 72099a2dd95SBruce Richardson /* Check that event timer timeout value is in range */ 72199a2dd95SBruce Richardson static __rte_always_inline int 72299a2dd95SBruce Richardson check_timeout(struct rte_event_timer *evtim, 72399a2dd95SBruce Richardson const struct rte_event_timer_adapter *adapter) 72499a2dd95SBruce Richardson { 72599a2dd95SBruce Richardson uint64_t tmo_nsec; 72699a2dd95SBruce Richardson struct swtim *sw = swtim_pmd_priv(adapter); 72799a2dd95SBruce Richardson 72899a2dd95SBruce Richardson tmo_nsec = evtim->timeout_ticks * sw->timer_tick_ns; 72999a2dd95SBruce Richardson if (tmo_nsec > sw->max_tmo_ns) 73099a2dd95SBruce Richardson return -1; 73199a2dd95SBruce Richardson if (tmo_nsec < sw->timer_tick_ns) 73299a2dd95SBruce Richardson return -2; 73399a2dd95SBruce Richardson 73499a2dd95SBruce Richardson return 0; 73599a2dd95SBruce Richardson } 73699a2dd95SBruce Richardson 73799a2dd95SBruce Richardson /* Check that event timer event queue sched type matches destination event queue 73899a2dd95SBruce Richardson * sched type 73999a2dd95SBruce Richardson */ 74099a2dd95SBruce Richardson static __rte_always_inline int 74199a2dd95SBruce Richardson check_destination_event_queue(struct rte_event_timer *evtim, 74299a2dd95SBruce Richardson const struct rte_event_timer_adapter *adapter) 74399a2dd95SBruce Richardson { 74499a2dd95SBruce Richardson int ret; 74599a2dd95SBruce Richardson uint32_t sched_type; 74699a2dd95SBruce Richardson 74799a2dd95SBruce Richardson ret = rte_event_queue_attr_get(adapter->data->event_dev_id, 74899a2dd95SBruce Richardson evtim->ev.queue_id, 74999a2dd95SBruce Richardson RTE_EVENT_QUEUE_ATTR_SCHEDULE_TYPE, 75099a2dd95SBruce Richardson &sched_type); 75199a2dd95SBruce Richardson 75299a2dd95SBruce Richardson if ((ret == 0 && evtim->ev.sched_type == sched_type) || 75399a2dd95SBruce Richardson ret == -EOVERFLOW) 75499a2dd95SBruce Richardson return 0; 75599a2dd95SBruce Richardson 75699a2dd95SBruce Richardson return -1; 75799a2dd95SBruce Richardson } 75899a2dd95SBruce Richardson 75999a2dd95SBruce Richardson static int 76099a2dd95SBruce Richardson swtim_service_func(void *arg) 76199a2dd95SBruce Richardson { 76299a2dd95SBruce Richardson struct rte_event_timer_adapter *adapter = arg; 76399a2dd95SBruce Richardson struct swtim *sw = swtim_pmd_priv(adapter); 76499a2dd95SBruce Richardson uint16_t nb_evs_flushed = 0; 76599a2dd95SBruce Richardson uint16_t nb_evs_invalid = 0; 76699a2dd95SBruce Richardson 76799a2dd95SBruce Richardson if (swtim_did_tick(sw)) { 76899a2dd95SBruce Richardson rte_timer_alt_manage(sw->timer_data_id, 76999a2dd95SBruce Richardson sw->poll_lcores, 77099a2dd95SBruce Richardson sw->n_poll_lcores, 77199a2dd95SBruce Richardson swtim_callback); 77299a2dd95SBruce Richardson 77399a2dd95SBruce Richardson /* Return expired timer objects back to mempool */ 77499a2dd95SBruce Richardson rte_mempool_put_bulk(sw->tim_pool, (void **)sw->expired_timers, 77599a2dd95SBruce Richardson sw->n_expired_timers); 77699a2dd95SBruce Richardson sw->n_expired_timers = 0; 77799a2dd95SBruce Richardson 77899a2dd95SBruce Richardson event_buffer_flush(&sw->buffer, 77999a2dd95SBruce Richardson adapter->data->event_dev_id, 78099a2dd95SBruce Richardson adapter->data->event_port_id, 78199a2dd95SBruce Richardson &nb_evs_flushed, 78299a2dd95SBruce Richardson &nb_evs_invalid); 78399a2dd95SBruce Richardson 78499a2dd95SBruce Richardson sw->stats.ev_enq_count += nb_evs_flushed; 78599a2dd95SBruce Richardson sw->stats.ev_inv_count += nb_evs_invalid; 78699a2dd95SBruce Richardson sw->stats.adapter_tick_count++; 78799a2dd95SBruce Richardson } 78899a2dd95SBruce Richardson 78999a2dd95SBruce Richardson return 0; 79099a2dd95SBruce Richardson } 79199a2dd95SBruce Richardson 79299a2dd95SBruce Richardson /* The adapter initialization function rounds the mempool size up to the next 79399a2dd95SBruce Richardson * power of 2, so we can take the difference between that value and what the 79499a2dd95SBruce Richardson * user requested, and use the space for caches. This avoids a scenario where a 79599a2dd95SBruce Richardson * user can't arm the number of timers the adapter was configured with because 79699a2dd95SBruce Richardson * mempool objects have been lost to caches. 79799a2dd95SBruce Richardson * 79899a2dd95SBruce Richardson * nb_actual should always be a power of 2, so we can iterate over the powers 79999a2dd95SBruce Richardson * of 2 to see what the largest cache size we can use is. 80099a2dd95SBruce Richardson */ 80199a2dd95SBruce Richardson static int 80299a2dd95SBruce Richardson compute_msg_mempool_cache_size(uint64_t nb_requested, uint64_t nb_actual) 80399a2dd95SBruce Richardson { 80499a2dd95SBruce Richardson int i; 80599a2dd95SBruce Richardson int size; 80699a2dd95SBruce Richardson int cache_size = 0; 80799a2dd95SBruce Richardson 80899a2dd95SBruce Richardson for (i = 0;; i++) { 80999a2dd95SBruce Richardson size = 1 << i; 81099a2dd95SBruce Richardson 81199a2dd95SBruce Richardson if (RTE_MAX_LCORE * size < (int)(nb_actual - nb_requested) && 81299a2dd95SBruce Richardson size < RTE_MEMPOOL_CACHE_MAX_SIZE && 81399a2dd95SBruce Richardson size <= nb_actual / 1.5) 81499a2dd95SBruce Richardson cache_size = size; 81599a2dd95SBruce Richardson else 81699a2dd95SBruce Richardson break; 81799a2dd95SBruce Richardson } 81899a2dd95SBruce Richardson 81999a2dd95SBruce Richardson return cache_size; 82099a2dd95SBruce Richardson } 82199a2dd95SBruce Richardson 82299a2dd95SBruce Richardson static int 82399a2dd95SBruce Richardson swtim_init(struct rte_event_timer_adapter *adapter) 82499a2dd95SBruce Richardson { 82599a2dd95SBruce Richardson int i, ret; 82699a2dd95SBruce Richardson struct swtim *sw; 82799a2dd95SBruce Richardson unsigned int flags; 82899a2dd95SBruce Richardson struct rte_service_spec service; 82999a2dd95SBruce Richardson 83099a2dd95SBruce Richardson /* Allocate storage for private data area */ 83199a2dd95SBruce Richardson #define SWTIM_NAMESIZE 32 83299a2dd95SBruce Richardson char swtim_name[SWTIM_NAMESIZE]; 83399a2dd95SBruce Richardson snprintf(swtim_name, SWTIM_NAMESIZE, "swtim_%"PRIu8, 83499a2dd95SBruce Richardson adapter->data->id); 83599a2dd95SBruce Richardson sw = rte_zmalloc_socket(swtim_name, sizeof(*sw), RTE_CACHE_LINE_SIZE, 83699a2dd95SBruce Richardson adapter->data->socket_id); 83799a2dd95SBruce Richardson if (sw == NULL) { 83899a2dd95SBruce Richardson EVTIM_LOG_ERR("failed to allocate space for private data"); 83999a2dd95SBruce Richardson rte_errno = ENOMEM; 84099a2dd95SBruce Richardson return -1; 84199a2dd95SBruce Richardson } 84299a2dd95SBruce Richardson 84399a2dd95SBruce Richardson /* Connect storage to adapter instance */ 84499a2dd95SBruce Richardson adapter->data->adapter_priv = sw; 84599a2dd95SBruce Richardson sw->adapter = adapter; 84699a2dd95SBruce Richardson 84799a2dd95SBruce Richardson sw->timer_tick_ns = adapter->data->conf.timer_tick_ns; 84899a2dd95SBruce Richardson sw->max_tmo_ns = adapter->data->conf.max_tmo_ns; 84999a2dd95SBruce Richardson 85099a2dd95SBruce Richardson /* Create a timer pool */ 85199a2dd95SBruce Richardson char pool_name[SWTIM_NAMESIZE]; 85299a2dd95SBruce Richardson snprintf(pool_name, SWTIM_NAMESIZE, "swtim_pool_%"PRIu8, 85399a2dd95SBruce Richardson adapter->data->id); 85499a2dd95SBruce Richardson /* Optimal mempool size is a power of 2 minus one */ 85599a2dd95SBruce Richardson uint64_t nb_timers = rte_align64pow2(adapter->data->conf.nb_timers); 85699a2dd95SBruce Richardson int pool_size = nb_timers - 1; 85799a2dd95SBruce Richardson int cache_size = compute_msg_mempool_cache_size( 85899a2dd95SBruce Richardson adapter->data->conf.nb_timers, nb_timers); 85999a2dd95SBruce Richardson flags = 0; /* pool is multi-producer, multi-consumer */ 86099a2dd95SBruce Richardson sw->tim_pool = rte_mempool_create(pool_name, pool_size, 86199a2dd95SBruce Richardson sizeof(struct rte_timer), cache_size, 0, NULL, NULL, 86299a2dd95SBruce Richardson NULL, NULL, adapter->data->socket_id, flags); 86399a2dd95SBruce Richardson if (sw->tim_pool == NULL) { 86499a2dd95SBruce Richardson EVTIM_LOG_ERR("failed to create timer object mempool"); 86599a2dd95SBruce Richardson rte_errno = ENOMEM; 86699a2dd95SBruce Richardson goto free_alloc; 86799a2dd95SBruce Richardson } 86899a2dd95SBruce Richardson 86999a2dd95SBruce Richardson /* Initialize the variables that track in-use timer lists */ 87099a2dd95SBruce Richardson for (i = 0; i < RTE_MAX_LCORE; i++) 87199a2dd95SBruce Richardson sw->in_use[i].v = 0; 87299a2dd95SBruce Richardson 87399a2dd95SBruce Richardson /* Initialize the timer subsystem and allocate timer data instance */ 87499a2dd95SBruce Richardson ret = rte_timer_subsystem_init(); 87599a2dd95SBruce Richardson if (ret < 0) { 87699a2dd95SBruce Richardson if (ret != -EALREADY) { 87799a2dd95SBruce Richardson EVTIM_LOG_ERR("failed to initialize timer subsystem"); 87899a2dd95SBruce Richardson rte_errno = -ret; 87999a2dd95SBruce Richardson goto free_mempool; 88099a2dd95SBruce Richardson } 88199a2dd95SBruce Richardson } 88299a2dd95SBruce Richardson 88399a2dd95SBruce Richardson ret = rte_timer_data_alloc(&sw->timer_data_id); 88499a2dd95SBruce Richardson if (ret < 0) { 88599a2dd95SBruce Richardson EVTIM_LOG_ERR("failed to allocate timer data instance"); 88699a2dd95SBruce Richardson rte_errno = -ret; 88799a2dd95SBruce Richardson goto free_mempool; 88899a2dd95SBruce Richardson } 88999a2dd95SBruce Richardson 89099a2dd95SBruce Richardson /* Initialize timer event buffer */ 89199a2dd95SBruce Richardson event_buffer_init(&sw->buffer); 89299a2dd95SBruce Richardson 89399a2dd95SBruce Richardson sw->adapter = adapter; 89499a2dd95SBruce Richardson 89599a2dd95SBruce Richardson /* Register a service component to run adapter logic */ 89699a2dd95SBruce Richardson memset(&service, 0, sizeof(service)); 89799a2dd95SBruce Richardson snprintf(service.name, RTE_SERVICE_NAME_MAX, 89899a2dd95SBruce Richardson "swtim_svc_%"PRIu8, adapter->data->id); 89999a2dd95SBruce Richardson service.socket_id = adapter->data->socket_id; 90099a2dd95SBruce Richardson service.callback = swtim_service_func; 90199a2dd95SBruce Richardson service.callback_userdata = adapter; 90299a2dd95SBruce Richardson service.capabilities &= ~(RTE_SERVICE_CAP_MT_SAFE); 90399a2dd95SBruce Richardson ret = rte_service_component_register(&service, &sw->service_id); 90499a2dd95SBruce Richardson if (ret < 0) { 90599a2dd95SBruce Richardson EVTIM_LOG_ERR("failed to register service %s with id %"PRIu32 90699a2dd95SBruce Richardson ": err = %d", service.name, sw->service_id, 90799a2dd95SBruce Richardson ret); 90899a2dd95SBruce Richardson 90999a2dd95SBruce Richardson rte_errno = ENOSPC; 91099a2dd95SBruce Richardson goto free_mempool; 91199a2dd95SBruce Richardson } 91299a2dd95SBruce Richardson 91399a2dd95SBruce Richardson EVTIM_LOG_DBG("registered service %s with id %"PRIu32, service.name, 91499a2dd95SBruce Richardson sw->service_id); 91599a2dd95SBruce Richardson 91699a2dd95SBruce Richardson adapter->data->service_id = sw->service_id; 91799a2dd95SBruce Richardson adapter->data->service_inited = 1; 91899a2dd95SBruce Richardson 91999a2dd95SBruce Richardson return 0; 92099a2dd95SBruce Richardson free_mempool: 92199a2dd95SBruce Richardson rte_mempool_free(sw->tim_pool); 92299a2dd95SBruce Richardson free_alloc: 92399a2dd95SBruce Richardson rte_free(sw); 92499a2dd95SBruce Richardson return -1; 92599a2dd95SBruce Richardson } 92699a2dd95SBruce Richardson 92799a2dd95SBruce Richardson static void 92899a2dd95SBruce Richardson swtim_free_tim(struct rte_timer *tim, void *arg) 92999a2dd95SBruce Richardson { 93099a2dd95SBruce Richardson struct swtim *sw = arg; 93199a2dd95SBruce Richardson 93299a2dd95SBruce Richardson rte_mempool_put(sw->tim_pool, tim); 93399a2dd95SBruce Richardson } 93499a2dd95SBruce Richardson 93599a2dd95SBruce Richardson /* Traverse the list of outstanding timers and put them back in the mempool 93699a2dd95SBruce Richardson * before freeing the adapter to avoid leaking the memory. 93799a2dd95SBruce Richardson */ 93899a2dd95SBruce Richardson static int 93999a2dd95SBruce Richardson swtim_uninit(struct rte_event_timer_adapter *adapter) 94099a2dd95SBruce Richardson { 94199a2dd95SBruce Richardson int ret; 94299a2dd95SBruce Richardson struct swtim *sw = swtim_pmd_priv(adapter); 94399a2dd95SBruce Richardson 94499a2dd95SBruce Richardson /* Free outstanding timers */ 94599a2dd95SBruce Richardson rte_timer_stop_all(sw->timer_data_id, 94699a2dd95SBruce Richardson sw->poll_lcores, 94799a2dd95SBruce Richardson sw->n_poll_lcores, 94899a2dd95SBruce Richardson swtim_free_tim, 94999a2dd95SBruce Richardson sw); 95099a2dd95SBruce Richardson 95199a2dd95SBruce Richardson ret = rte_service_component_unregister(sw->service_id); 95299a2dd95SBruce Richardson if (ret < 0) { 95399a2dd95SBruce Richardson EVTIM_LOG_ERR("failed to unregister service component"); 95499a2dd95SBruce Richardson return ret; 95599a2dd95SBruce Richardson } 95699a2dd95SBruce Richardson 95799a2dd95SBruce Richardson rte_mempool_free(sw->tim_pool); 95899a2dd95SBruce Richardson rte_free(sw); 95999a2dd95SBruce Richardson adapter->data->adapter_priv = NULL; 96099a2dd95SBruce Richardson 96199a2dd95SBruce Richardson return 0; 96299a2dd95SBruce Richardson } 96399a2dd95SBruce Richardson 96499a2dd95SBruce Richardson static inline int32_t 96599a2dd95SBruce Richardson get_mapped_count_for_service(uint32_t service_id) 96699a2dd95SBruce Richardson { 96799a2dd95SBruce Richardson int32_t core_count, i, mapped_count = 0; 96899a2dd95SBruce Richardson uint32_t lcore_arr[RTE_MAX_LCORE]; 96999a2dd95SBruce Richardson 97099a2dd95SBruce Richardson core_count = rte_service_lcore_list(lcore_arr, RTE_MAX_LCORE); 97199a2dd95SBruce Richardson 97299a2dd95SBruce Richardson for (i = 0; i < core_count; i++) 97399a2dd95SBruce Richardson if (rte_service_map_lcore_get(service_id, lcore_arr[i]) == 1) 97499a2dd95SBruce Richardson mapped_count++; 97599a2dd95SBruce Richardson 97699a2dd95SBruce Richardson return mapped_count; 97799a2dd95SBruce Richardson } 97899a2dd95SBruce Richardson 97999a2dd95SBruce Richardson static int 98099a2dd95SBruce Richardson swtim_start(const struct rte_event_timer_adapter *adapter) 98199a2dd95SBruce Richardson { 98299a2dd95SBruce Richardson int mapped_count; 98399a2dd95SBruce Richardson struct swtim *sw = swtim_pmd_priv(adapter); 98499a2dd95SBruce Richardson 98599a2dd95SBruce Richardson /* Mapping the service to more than one service core can introduce 98699a2dd95SBruce Richardson * delays while one thread is waiting to acquire a lock, so only allow 98799a2dd95SBruce Richardson * one core to be mapped to the service. 98899a2dd95SBruce Richardson * 98999a2dd95SBruce Richardson * Note: the service could be modified such that it spreads cores to 99099a2dd95SBruce Richardson * poll over multiple service instances. 99199a2dd95SBruce Richardson */ 99299a2dd95SBruce Richardson mapped_count = get_mapped_count_for_service(sw->service_id); 99399a2dd95SBruce Richardson 99499a2dd95SBruce Richardson if (mapped_count != 1) 99599a2dd95SBruce Richardson return mapped_count < 1 ? -ENOENT : -ENOTSUP; 99699a2dd95SBruce Richardson 99799a2dd95SBruce Richardson return rte_service_component_runstate_set(sw->service_id, 1); 99899a2dd95SBruce Richardson } 99999a2dd95SBruce Richardson 100099a2dd95SBruce Richardson static int 100199a2dd95SBruce Richardson swtim_stop(const struct rte_event_timer_adapter *adapter) 100299a2dd95SBruce Richardson { 100399a2dd95SBruce Richardson int ret; 100499a2dd95SBruce Richardson struct swtim *sw = swtim_pmd_priv(adapter); 100599a2dd95SBruce Richardson 100699a2dd95SBruce Richardson ret = rte_service_component_runstate_set(sw->service_id, 0); 100799a2dd95SBruce Richardson if (ret < 0) 100899a2dd95SBruce Richardson return ret; 100999a2dd95SBruce Richardson 101099a2dd95SBruce Richardson /* Wait for the service to complete its final iteration */ 101199a2dd95SBruce Richardson while (rte_service_may_be_active(sw->service_id)) 101299a2dd95SBruce Richardson rte_pause(); 101399a2dd95SBruce Richardson 101499a2dd95SBruce Richardson return 0; 101599a2dd95SBruce Richardson } 101699a2dd95SBruce Richardson 101799a2dd95SBruce Richardson static void 101899a2dd95SBruce Richardson swtim_get_info(const struct rte_event_timer_adapter *adapter, 101999a2dd95SBruce Richardson struct rte_event_timer_adapter_info *adapter_info) 102099a2dd95SBruce Richardson { 102199a2dd95SBruce Richardson struct swtim *sw = swtim_pmd_priv(adapter); 102299a2dd95SBruce Richardson adapter_info->min_resolution_ns = sw->timer_tick_ns; 102399a2dd95SBruce Richardson adapter_info->max_tmo_ns = sw->max_tmo_ns; 102499a2dd95SBruce Richardson } 102599a2dd95SBruce Richardson 102699a2dd95SBruce Richardson static int 102799a2dd95SBruce Richardson swtim_stats_get(const struct rte_event_timer_adapter *adapter, 102899a2dd95SBruce Richardson struct rte_event_timer_adapter_stats *stats) 102999a2dd95SBruce Richardson { 103099a2dd95SBruce Richardson struct swtim *sw = swtim_pmd_priv(adapter); 103199a2dd95SBruce Richardson *stats = sw->stats; /* structure copy */ 103299a2dd95SBruce Richardson return 0; 103399a2dd95SBruce Richardson } 103499a2dd95SBruce Richardson 103599a2dd95SBruce Richardson static int 103699a2dd95SBruce Richardson swtim_stats_reset(const struct rte_event_timer_adapter *adapter) 103799a2dd95SBruce Richardson { 103899a2dd95SBruce Richardson struct swtim *sw = swtim_pmd_priv(adapter); 103999a2dd95SBruce Richardson memset(&sw->stats, 0, sizeof(sw->stats)); 104099a2dd95SBruce Richardson return 0; 104199a2dd95SBruce Richardson } 104299a2dd95SBruce Richardson 104399a2dd95SBruce Richardson static uint16_t 104499a2dd95SBruce Richardson __swtim_arm_burst(const struct rte_event_timer_adapter *adapter, 104599a2dd95SBruce Richardson struct rte_event_timer **evtims, 104699a2dd95SBruce Richardson uint16_t nb_evtims) 104799a2dd95SBruce Richardson { 104899a2dd95SBruce Richardson int i, ret; 104999a2dd95SBruce Richardson struct swtim *sw = swtim_pmd_priv(adapter); 105099a2dd95SBruce Richardson uint32_t lcore_id = rte_lcore_id(); 105199a2dd95SBruce Richardson struct rte_timer *tim, *tims[nb_evtims]; 105299a2dd95SBruce Richardson uint64_t cycles; 105399a2dd95SBruce Richardson int n_lcores; 105499a2dd95SBruce Richardson /* Timer list for this lcore is not in use. */ 105599a2dd95SBruce Richardson uint16_t exp_state = 0; 105699a2dd95SBruce Richardson enum rte_event_timer_state n_state; 105799a2dd95SBruce Richardson 105899a2dd95SBruce Richardson #ifdef RTE_LIBRTE_EVENTDEV_DEBUG 105999a2dd95SBruce Richardson /* Check that the service is running. */ 106099a2dd95SBruce Richardson if (rte_service_runstate_get(adapter->data->service_id) != 1) { 106199a2dd95SBruce Richardson rte_errno = EINVAL; 106299a2dd95SBruce Richardson return 0; 106399a2dd95SBruce Richardson } 106499a2dd95SBruce Richardson #endif 106599a2dd95SBruce Richardson 106699a2dd95SBruce Richardson /* Adjust lcore_id if non-EAL thread. Arbitrarily pick the timer list of 106799a2dd95SBruce Richardson * the highest lcore to insert such timers into 106899a2dd95SBruce Richardson */ 106999a2dd95SBruce Richardson if (lcore_id == LCORE_ID_ANY) 107099a2dd95SBruce Richardson lcore_id = RTE_MAX_LCORE - 1; 107199a2dd95SBruce Richardson 107299a2dd95SBruce Richardson /* If this is the first time we're arming an event timer on this lcore, 107399a2dd95SBruce Richardson * mark this lcore as "in use"; this will cause the service 107499a2dd95SBruce Richardson * function to process the timer list that corresponds to this lcore. 107599a2dd95SBruce Richardson * The atomic compare-and-swap operation can prevent the race condition 107699a2dd95SBruce Richardson * on in_use flag between multiple non-EAL threads. 107799a2dd95SBruce Richardson */ 107899a2dd95SBruce Richardson if (unlikely(__atomic_compare_exchange_n(&sw->in_use[lcore_id].v, 107999a2dd95SBruce Richardson &exp_state, 1, 0, 108099a2dd95SBruce Richardson __ATOMIC_RELAXED, __ATOMIC_RELAXED))) { 108199a2dd95SBruce Richardson EVTIM_LOG_DBG("Adding lcore id = %u to list of lcores to poll", 108299a2dd95SBruce Richardson lcore_id); 108399a2dd95SBruce Richardson n_lcores = __atomic_fetch_add(&sw->n_poll_lcores, 1, 108499a2dd95SBruce Richardson __ATOMIC_RELAXED); 108599a2dd95SBruce Richardson __atomic_store_n(&sw->poll_lcores[n_lcores], lcore_id, 108699a2dd95SBruce Richardson __ATOMIC_RELAXED); 108799a2dd95SBruce Richardson } 108899a2dd95SBruce Richardson 108999a2dd95SBruce Richardson ret = rte_mempool_get_bulk(sw->tim_pool, (void **)tims, 109099a2dd95SBruce Richardson nb_evtims); 109199a2dd95SBruce Richardson if (ret < 0) { 109299a2dd95SBruce Richardson rte_errno = ENOSPC; 109399a2dd95SBruce Richardson return 0; 109499a2dd95SBruce Richardson } 109599a2dd95SBruce Richardson 109699a2dd95SBruce Richardson for (i = 0; i < nb_evtims; i++) { 109799a2dd95SBruce Richardson n_state = __atomic_load_n(&evtims[i]->state, __ATOMIC_ACQUIRE); 109899a2dd95SBruce Richardson if (n_state == RTE_EVENT_TIMER_ARMED) { 109999a2dd95SBruce Richardson rte_errno = EALREADY; 110099a2dd95SBruce Richardson break; 110199a2dd95SBruce Richardson } else if (!(n_state == RTE_EVENT_TIMER_NOT_ARMED || 110299a2dd95SBruce Richardson n_state == RTE_EVENT_TIMER_CANCELED)) { 110399a2dd95SBruce Richardson rte_errno = EINVAL; 110499a2dd95SBruce Richardson break; 110599a2dd95SBruce Richardson } 110699a2dd95SBruce Richardson 110799a2dd95SBruce Richardson ret = check_timeout(evtims[i], adapter); 110899a2dd95SBruce Richardson if (unlikely(ret == -1)) { 110999a2dd95SBruce Richardson __atomic_store_n(&evtims[i]->state, 111099a2dd95SBruce Richardson RTE_EVENT_TIMER_ERROR_TOOLATE, 111199a2dd95SBruce Richardson __ATOMIC_RELAXED); 111299a2dd95SBruce Richardson rte_errno = EINVAL; 111399a2dd95SBruce Richardson break; 111499a2dd95SBruce Richardson } else if (unlikely(ret == -2)) { 111599a2dd95SBruce Richardson __atomic_store_n(&evtims[i]->state, 111699a2dd95SBruce Richardson RTE_EVENT_TIMER_ERROR_TOOEARLY, 111799a2dd95SBruce Richardson __ATOMIC_RELAXED); 111899a2dd95SBruce Richardson rte_errno = EINVAL; 111999a2dd95SBruce Richardson break; 112099a2dd95SBruce Richardson } 112199a2dd95SBruce Richardson 112299a2dd95SBruce Richardson if (unlikely(check_destination_event_queue(evtims[i], 112399a2dd95SBruce Richardson adapter) < 0)) { 112499a2dd95SBruce Richardson __atomic_store_n(&evtims[i]->state, 112599a2dd95SBruce Richardson RTE_EVENT_TIMER_ERROR, 112699a2dd95SBruce Richardson __ATOMIC_RELAXED); 112799a2dd95SBruce Richardson rte_errno = EINVAL; 112899a2dd95SBruce Richardson break; 112999a2dd95SBruce Richardson } 113099a2dd95SBruce Richardson 113199a2dd95SBruce Richardson tim = tims[i]; 113299a2dd95SBruce Richardson rte_timer_init(tim); 113399a2dd95SBruce Richardson 113499a2dd95SBruce Richardson evtims[i]->impl_opaque[0] = (uintptr_t)tim; 113599a2dd95SBruce Richardson evtims[i]->impl_opaque[1] = (uintptr_t)adapter; 113699a2dd95SBruce Richardson 113799a2dd95SBruce Richardson cycles = get_timeout_cycles(evtims[i], adapter); 113899a2dd95SBruce Richardson ret = rte_timer_alt_reset(sw->timer_data_id, tim, cycles, 113999a2dd95SBruce Richardson SINGLE, lcore_id, NULL, evtims[i]); 114099a2dd95SBruce Richardson if (ret < 0) { 114199a2dd95SBruce Richardson /* tim was in RUNNING or CONFIG state */ 114299a2dd95SBruce Richardson __atomic_store_n(&evtims[i]->state, 114399a2dd95SBruce Richardson RTE_EVENT_TIMER_ERROR, 114499a2dd95SBruce Richardson __ATOMIC_RELEASE); 114599a2dd95SBruce Richardson break; 114699a2dd95SBruce Richardson } 114799a2dd95SBruce Richardson 114899a2dd95SBruce Richardson EVTIM_LOG_DBG("armed an event timer"); 114999a2dd95SBruce Richardson /* RELEASE ordering guarantees the adapter specific value 115099a2dd95SBruce Richardson * changes observed before the update of state. 115199a2dd95SBruce Richardson */ 115299a2dd95SBruce Richardson __atomic_store_n(&evtims[i]->state, RTE_EVENT_TIMER_ARMED, 115399a2dd95SBruce Richardson __ATOMIC_RELEASE); 115499a2dd95SBruce Richardson } 115599a2dd95SBruce Richardson 115699a2dd95SBruce Richardson if (i < nb_evtims) 115799a2dd95SBruce Richardson rte_mempool_put_bulk(sw->tim_pool, 115899a2dd95SBruce Richardson (void **)&tims[i], nb_evtims - i); 115999a2dd95SBruce Richardson 116099a2dd95SBruce Richardson return i; 116199a2dd95SBruce Richardson } 116299a2dd95SBruce Richardson 116399a2dd95SBruce Richardson static uint16_t 116499a2dd95SBruce Richardson swtim_arm_burst(const struct rte_event_timer_adapter *adapter, 116599a2dd95SBruce Richardson struct rte_event_timer **evtims, 116699a2dd95SBruce Richardson uint16_t nb_evtims) 116799a2dd95SBruce Richardson { 116899a2dd95SBruce Richardson return __swtim_arm_burst(adapter, evtims, nb_evtims); 116999a2dd95SBruce Richardson } 117099a2dd95SBruce Richardson 117199a2dd95SBruce Richardson static uint16_t 117299a2dd95SBruce Richardson swtim_cancel_burst(const struct rte_event_timer_adapter *adapter, 117399a2dd95SBruce Richardson struct rte_event_timer **evtims, 117499a2dd95SBruce Richardson uint16_t nb_evtims) 117599a2dd95SBruce Richardson { 117699a2dd95SBruce Richardson int i, ret; 117799a2dd95SBruce Richardson struct rte_timer *timp; 117899a2dd95SBruce Richardson uint64_t opaque; 117999a2dd95SBruce Richardson struct swtim *sw = swtim_pmd_priv(adapter); 118099a2dd95SBruce Richardson enum rte_event_timer_state n_state; 118199a2dd95SBruce Richardson 118299a2dd95SBruce Richardson #ifdef RTE_LIBRTE_EVENTDEV_DEBUG 118399a2dd95SBruce Richardson /* Check that the service is running. */ 118499a2dd95SBruce Richardson if (rte_service_runstate_get(adapter->data->service_id) != 1) { 118599a2dd95SBruce Richardson rte_errno = EINVAL; 118699a2dd95SBruce Richardson return 0; 118799a2dd95SBruce Richardson } 118899a2dd95SBruce Richardson #endif 118999a2dd95SBruce Richardson 119099a2dd95SBruce Richardson for (i = 0; i < nb_evtims; i++) { 119199a2dd95SBruce Richardson /* Don't modify the event timer state in these cases */ 119299a2dd95SBruce Richardson /* ACQUIRE ordering guarantees the access of implementation 119399a2dd95SBruce Richardson * specific opaque data under the correct state. 119499a2dd95SBruce Richardson */ 119599a2dd95SBruce Richardson n_state = __atomic_load_n(&evtims[i]->state, __ATOMIC_ACQUIRE); 119699a2dd95SBruce Richardson if (n_state == RTE_EVENT_TIMER_CANCELED) { 119799a2dd95SBruce Richardson rte_errno = EALREADY; 119899a2dd95SBruce Richardson break; 119999a2dd95SBruce Richardson } else if (n_state != RTE_EVENT_TIMER_ARMED) { 120099a2dd95SBruce Richardson rte_errno = EINVAL; 120199a2dd95SBruce Richardson break; 120299a2dd95SBruce Richardson } 120399a2dd95SBruce Richardson 120499a2dd95SBruce Richardson opaque = evtims[i]->impl_opaque[0]; 120599a2dd95SBruce Richardson timp = (struct rte_timer *)(uintptr_t)opaque; 120699a2dd95SBruce Richardson RTE_ASSERT(timp != NULL); 120799a2dd95SBruce Richardson 120899a2dd95SBruce Richardson ret = rte_timer_alt_stop(sw->timer_data_id, timp); 120999a2dd95SBruce Richardson if (ret < 0) { 121099a2dd95SBruce Richardson /* Timer is running or being configured */ 121199a2dd95SBruce Richardson rte_errno = EAGAIN; 121299a2dd95SBruce Richardson break; 121399a2dd95SBruce Richardson } 121499a2dd95SBruce Richardson 121599a2dd95SBruce Richardson rte_mempool_put(sw->tim_pool, (void **)timp); 121699a2dd95SBruce Richardson 121799a2dd95SBruce Richardson /* The RELEASE ordering here pairs with atomic ordering 121899a2dd95SBruce Richardson * to make sure the state update data observed between 121999a2dd95SBruce Richardson * threads. 122099a2dd95SBruce Richardson */ 122199a2dd95SBruce Richardson __atomic_store_n(&evtims[i]->state, RTE_EVENT_TIMER_CANCELED, 122299a2dd95SBruce Richardson __ATOMIC_RELEASE); 122399a2dd95SBruce Richardson } 122499a2dd95SBruce Richardson 122599a2dd95SBruce Richardson return i; 122699a2dd95SBruce Richardson } 122799a2dd95SBruce Richardson 122899a2dd95SBruce Richardson static uint16_t 122999a2dd95SBruce Richardson swtim_arm_tmo_tick_burst(const struct rte_event_timer_adapter *adapter, 123099a2dd95SBruce Richardson struct rte_event_timer **evtims, 123199a2dd95SBruce Richardson uint64_t timeout_ticks, 123299a2dd95SBruce Richardson uint16_t nb_evtims) 123399a2dd95SBruce Richardson { 123499a2dd95SBruce Richardson int i; 123599a2dd95SBruce Richardson 123699a2dd95SBruce Richardson for (i = 0; i < nb_evtims; i++) 123799a2dd95SBruce Richardson evtims[i]->timeout_ticks = timeout_ticks; 123899a2dd95SBruce Richardson 123999a2dd95SBruce Richardson return __swtim_arm_burst(adapter, evtims, nb_evtims); 124099a2dd95SBruce Richardson } 124199a2dd95SBruce Richardson 124253548ad3SPavan Nikhilesh static const struct event_timer_adapter_ops swtim_ops = { 124399a2dd95SBruce Richardson .init = swtim_init, 124499a2dd95SBruce Richardson .uninit = swtim_uninit, 124599a2dd95SBruce Richardson .start = swtim_start, 124699a2dd95SBruce Richardson .stop = swtim_stop, 124799a2dd95SBruce Richardson .get_info = swtim_get_info, 124899a2dd95SBruce Richardson .stats_get = swtim_stats_get, 124999a2dd95SBruce Richardson .stats_reset = swtim_stats_reset, 125099a2dd95SBruce Richardson .arm_burst = swtim_arm_burst, 125199a2dd95SBruce Richardson .arm_tmo_tick_burst = swtim_arm_tmo_tick_burst, 125299a2dd95SBruce Richardson .cancel_burst = swtim_cancel_burst, 125399a2dd95SBruce Richardson }; 1254