tle_event.h revision aa97dd1c
13395610eSKonstantin Ananyev/*
23395610eSKonstantin Ananyev * Copyright (c) 2016  Intel Corporation.
33395610eSKonstantin Ananyev * Licensed under the Apache License, Version 2.0 (the "License");
43395610eSKonstantin Ananyev * you may not use this file except in compliance with the License.
53395610eSKonstantin Ananyev * You may obtain a copy of the License at:
63395610eSKonstantin Ananyev *
73395610eSKonstantin Ananyev *     http://www.apache.org/licenses/LICENSE-2.0
83395610eSKonstantin Ananyev *
93395610eSKonstantin Ananyev * Unless required by applicable law or agreed to in writing, software
103395610eSKonstantin Ananyev * distributed under the License is distributed on an "AS IS" BASIS,
113395610eSKonstantin Ananyev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123395610eSKonstantin Ananyev * See the License for the specific language governing permissions and
133395610eSKonstantin Ananyev * limitations under the License.
143395610eSKonstantin Ananyev */
153395610eSKonstantin Ananyev
163395610eSKonstantin Ananyev#ifndef _SEV_IMPL_H_
173395610eSKonstantin Ananyev#define _SEV_IMPL_H_
183395610eSKonstantin Ananyev
193395610eSKonstantin Ananyev#include <rte_common.h>
20aa97dd1cSKonstantin Ananyev#include <rte_memory.h>
213395610eSKonstantin Ananyev#include <rte_spinlock.h>
223395610eSKonstantin Ananyev#include <rte_atomic.h>
233395610eSKonstantin Ananyev#include <sys/queue.h>
243395610eSKonstantin Ananyev
253395610eSKonstantin Ananyev#ifdef __cplusplus
263395610eSKonstantin Ananyevextern "C" {
273395610eSKonstantin Ananyev#endif
283395610eSKonstantin Ananyev
293395610eSKonstantin Ananyevstruct tle_evq;
303395610eSKonstantin Ananyev
313395610eSKonstantin Ananyev/**
323395610eSKonstantin Ananyev * Possible states of the event.
333395610eSKonstantin Ananyev */
343395610eSKonstantin Ananyevenum tle_ev_state {
353395610eSKonstantin Ananyev	TLE_SEV_IDLE,
363395610eSKonstantin Ananyev	TLE_SEV_DOWN,
373395610eSKonstantin Ananyev	TLE_SEV_UP,
383395610eSKonstantin Ananyev	TLE_SEV_NUM
393395610eSKonstantin Ananyev};
403395610eSKonstantin Ananyev
413395610eSKonstantin Ananyevstruct tle_event {
423395610eSKonstantin Ananyev	TAILQ_ENTRY(tle_event) ql;
433395610eSKonstantin Ananyev	struct tle_evq *head;
443395610eSKonstantin Ananyev	const void *data;
453395610eSKonstantin Ananyev	enum tle_ev_state state;
463395610eSKonstantin Ananyev} __rte_cache_aligned;
473395610eSKonstantin Ananyev
483395610eSKonstantin Ananyevstruct tle_evq {
493395610eSKonstantin Ananyev	rte_spinlock_t lock;
503395610eSKonstantin Ananyev	uint32_t nb_events;
513395610eSKonstantin Ananyev	uint32_t nb_armed;
523395610eSKonstantin Ananyev	uint32_t nb_free;
533395610eSKonstantin Ananyev	TAILQ_HEAD(, tle_event) armed;
543395610eSKonstantin Ananyev	TAILQ_HEAD(, tle_event) free;
553395610eSKonstantin Ananyev	struct tle_event events[0];
563395610eSKonstantin Ananyev};
573395610eSKonstantin Ananyev
583395610eSKonstantin Ananyev/**
593395610eSKonstantin Ananyev * event queue creation parameters.
603395610eSKonstantin Ananyev */
613395610eSKonstantin Ananyevstruct tle_evq_param {
623395610eSKonstantin Ananyev	int32_t socket_id;    /**< socket ID to allocate memory from. */
633395610eSKonstantin Ananyev	uint32_t max_events;  /**< max number of events in queue. */
643395610eSKonstantin Ananyev};
653395610eSKonstantin Ananyev
663395610eSKonstantin Ananyev/**
673395610eSKonstantin Ananyev * create event queue.
683395610eSKonstantin Ananyev * @param prm
693395610eSKonstantin Ananyev *   Parameters used to create and initialise the queue.
703395610eSKonstantin Ananyev * @return
713395610eSKonstantin Ananyev *   Pointer to new event queue structure,
723395610eSKonstantin Ananyev *   or NULL on error, with error code set in rte_errno.
733395610eSKonstantin Ananyev *   Possible rte_errno errors include:
743395610eSKonstantin Ananyev *   - EINVAL - invalid parameter passed to function
753395610eSKonstantin Ananyev *   - ENOMEM - out of memory
763395610eSKonstantin Ananyev */
773395610eSKonstantin Ananyevstruct tle_evq *tle_evq_create(const struct tle_evq_param *prm);
783395610eSKonstantin Ananyev
793395610eSKonstantin Ananyev/**
803395610eSKonstantin Ananyev * Destroy given event queue.
813395610eSKonstantin Ananyev *
823395610eSKonstantin Ananyev * @param evq
833395610eSKonstantin Ananyev *   event queue to destroy
843395610eSKonstantin Ananyev */
853395610eSKonstantin Ananyevvoid tle_evq_destroy(struct tle_evq *evq);
863395610eSKonstantin Ananyev
873395610eSKonstantin Ananyev/**
883395610eSKonstantin Ananyev * allocate a new event within given event queue.
893395610eSKonstantin Ananyev * @param evq
903395610eSKonstantin Ananyev *    event queue to allocate a new stream within.
913395610eSKonstantin Ananyev * @param data
923395610eSKonstantin Ananyev *   User data to be associated with that event.
933395610eSKonstantin Ananyev * @return
943395610eSKonstantin Ananyev *   Pointer to event structure that can be used in future tle_event API calls,
953395610eSKonstantin Ananyev *   or NULL on error, with error code set in rte_errno.
963395610eSKonstantin Ananyev *   Possible rte_errno errors include:
973395610eSKonstantin Ananyev *   - EINVAL - invalid parameter passed to function
983395610eSKonstantin Ananyev *   - ENOMEM - max limit of allocated events reached for that context
993395610eSKonstantin Ananyev */
1003395610eSKonstantin Ananyevstruct tle_event *tle_event_alloc(struct tle_evq *evq, const void *data);
1013395610eSKonstantin Ananyev
1023395610eSKonstantin Ananyev/**
1033395610eSKonstantin Ananyev * free an allocated event.
1043395610eSKonstantin Ananyev * @param ev
1053395610eSKonstantin Ananyev *   Pointer to the event to free.
1063395610eSKonstantin Ananyev */
1073395610eSKonstantin Ananyevvoid tle_event_free(struct tle_event *ev);
1083395610eSKonstantin Ananyev
1093395610eSKonstantin Ananyev
1103395610eSKonstantin Ananyev/**
1113395610eSKonstantin Ananyev * move event from DOWN to UP state.
1123395610eSKonstantin Ananyev * @param ev
1133395610eSKonstantin Ananyev *   Pointer to the event.
1143395610eSKonstantin Ananyev */
1153395610eSKonstantin Ananyevstatic inline void
1163395610eSKonstantin Ananyevtle_event_raise(struct tle_event *ev)
1173395610eSKonstantin Ananyev{
1183395610eSKonstantin Ananyev	struct tle_evq *q;
1193395610eSKonstantin Ananyev
1203395610eSKonstantin Ananyev	if (ev->state != TLE_SEV_DOWN)
1213395610eSKonstantin Ananyev		return;
1223395610eSKonstantin Ananyev
1233395610eSKonstantin Ananyev	q = ev->head;
1243395610eSKonstantin Ananyev	rte_compiler_barrier();
1253395610eSKonstantin Ananyev
1263395610eSKonstantin Ananyev	rte_spinlock_lock(&q->lock);
1273395610eSKonstantin Ananyev	if (ev->state == TLE_SEV_DOWN) {
1283395610eSKonstantin Ananyev		ev->state = TLE_SEV_UP;
1293395610eSKonstantin Ananyev		TAILQ_INSERT_TAIL(&q->armed, ev, ql);
1303395610eSKonstantin Ananyev		q->nb_armed++;
1313395610eSKonstantin Ananyev	}
1323395610eSKonstantin Ananyev	rte_spinlock_unlock(&q->lock);
1333395610eSKonstantin Ananyev}
1343395610eSKonstantin Ananyev
1353395610eSKonstantin Ananyev/**
1363395610eSKonstantin Ananyev * move event from UP to DOWN state.
1373395610eSKonstantin Ananyev * @param ev
1383395610eSKonstantin Ananyev *   Pointer to the event.
1393395610eSKonstantin Ananyev */
1403395610eSKonstantin Ananyevstatic inline void
1413395610eSKonstantin Ananyevtle_event_down(struct tle_event *ev)
1423395610eSKonstantin Ananyev{
1433395610eSKonstantin Ananyev	struct tle_evq *q;
1443395610eSKonstantin Ananyev
1453395610eSKonstantin Ananyev	if (ev->state != TLE_SEV_UP)
1463395610eSKonstantin Ananyev		return;
1473395610eSKonstantin Ananyev
1483395610eSKonstantin Ananyev	q = ev->head;
1493395610eSKonstantin Ananyev	rte_compiler_barrier();
1503395610eSKonstantin Ananyev
1513395610eSKonstantin Ananyev	rte_spinlock_lock(&q->lock);
1523395610eSKonstantin Ananyev	if (ev->state == TLE_SEV_UP) {
1533395610eSKonstantin Ananyev		ev->state = TLE_SEV_DOWN;
1543395610eSKonstantin Ananyev		TAILQ_REMOVE(&q->armed, ev, ql);
1553395610eSKonstantin Ananyev		q->nb_armed--;
1563395610eSKonstantin Ananyev	}
1573395610eSKonstantin Ananyev	rte_spinlock_unlock(&q->lock);
1583395610eSKonstantin Ananyev}
1593395610eSKonstantin Ananyev
1603395610eSKonstantin Ananyev/**
1613395610eSKonstantin Ananyev * move from IDLE to DOWN/UP state.
1623395610eSKonstantin Ananyev * @param ev
1633395610eSKonstantin Ananyev *   Pointer to the event.
1643395610eSKonstantin Ananyev * @param st
1653395610eSKonstantin Ananyev *   new state for the event.
1663395610eSKonstantin Ananyev */
1673395610eSKonstantin Ananyevstatic inline void
1683395610eSKonstantin Ananyevtle_event_active(struct tle_event *ev, enum tle_ev_state st)
1693395610eSKonstantin Ananyev{
1703395610eSKonstantin Ananyev	struct tle_evq *q;
1713395610eSKonstantin Ananyev
172c603d3edSKarol Latecki	if (ev->state != TLE_SEV_IDLE)
1733395610eSKonstantin Ananyev		return;
1743395610eSKonstantin Ananyev
1753395610eSKonstantin Ananyev	q = ev->head;
1763395610eSKonstantin Ananyev	rte_compiler_barrier();
1773395610eSKonstantin Ananyev
1783395610eSKonstantin Ananyev	rte_spinlock_lock(&q->lock);
1793395610eSKonstantin Ananyev	if (st > ev->state) {
1803395610eSKonstantin Ananyev		if (st == TLE_SEV_UP) {
1813395610eSKonstantin Ananyev			TAILQ_INSERT_TAIL(&q->armed, ev, ql);
1823395610eSKonstantin Ananyev			q->nb_armed++;
1833395610eSKonstantin Ananyev		}
1843395610eSKonstantin Ananyev		ev->state = st;
1853395610eSKonstantin Ananyev	}
1863395610eSKonstantin Ananyev	rte_spinlock_unlock(&q->lock);
1873395610eSKonstantin Ananyev}
1883395610eSKonstantin Ananyev
1893395610eSKonstantin Ananyev/**
1903395610eSKonstantin Ananyev * move event IDLE state.
1913395610eSKonstantin Ananyev * @param ev
1923395610eSKonstantin Ananyev *   Pointer to the event.
1933395610eSKonstantin Ananyev */
1943395610eSKonstantin Ananyevstatic inline void
1953395610eSKonstantin Ananyevtle_event_idle(struct tle_event *ev)
1963395610eSKonstantin Ananyev{
1973395610eSKonstantin Ananyev	struct tle_evq *q;
1983395610eSKonstantin Ananyev
1993395610eSKonstantin Ananyev	if (ev->state == TLE_SEV_IDLE)
2003395610eSKonstantin Ananyev		return;
2013395610eSKonstantin Ananyev
2023395610eSKonstantin Ananyev	q = ev->head;
2033395610eSKonstantin Ananyev	rte_compiler_barrier();
2043395610eSKonstantin Ananyev
2053395610eSKonstantin Ananyev	rte_spinlock_lock(&q->lock);
2063395610eSKonstantin Ananyev	if (ev->state == TLE_SEV_UP) {
2073395610eSKonstantin Ananyev		TAILQ_REMOVE(&q->armed, ev, ql);
2083395610eSKonstantin Ananyev		q->nb_armed--;
2093395610eSKonstantin Ananyev	}
2103395610eSKonstantin Ananyev	ev->state = TLE_SEV_IDLE;
2113395610eSKonstantin Ananyev	rte_spinlock_unlock(&q->lock);
2123395610eSKonstantin Ananyev}
2133395610eSKonstantin Ananyev
214aa97dd1cSKonstantin Ananyevstatic inline void
215aa97dd1cSKonstantin Ananyevtle_evq_idle(struct tle_evq *evq, struct tle_event *ev[], uint32_t num)
216aa97dd1cSKonstantin Ananyev{
217aa97dd1cSKonstantin Ananyev	uint32_t i, n;
218aa97dd1cSKonstantin Ananyev
219aa97dd1cSKonstantin Ananyev	rte_spinlock_lock(&evq->lock);
220aa97dd1cSKonstantin Ananyev
221aa97dd1cSKonstantin Ananyev	n = 0;
222aa97dd1cSKonstantin Ananyev	for (i = 0; i != num; i++) {
223aa97dd1cSKonstantin Ananyev		if (ev[i]->state == TLE_SEV_UP) {
224aa97dd1cSKonstantin Ananyev			TAILQ_REMOVE(&evq->armed, ev[i], ql);
225aa97dd1cSKonstantin Ananyev			n++;
226aa97dd1cSKonstantin Ananyev		}
227aa97dd1cSKonstantin Ananyev		ev[i]->state = TLE_SEV_IDLE;
228aa97dd1cSKonstantin Ananyev	}
229aa97dd1cSKonstantin Ananyev
230aa97dd1cSKonstantin Ananyev	evq->nb_armed -= n;
231aa97dd1cSKonstantin Ananyev	rte_spinlock_unlock(&evq->lock);
232aa97dd1cSKonstantin Ananyev}
233aa97dd1cSKonstantin Ananyev
2343395610eSKonstantin Ananyev
2353395610eSKonstantin Ananyev/*
2363395610eSKonstantin Ananyev * return up to *num* user data pointers associated with
2373395610eSKonstantin Ananyev * the events that were in the UP state.
2383395610eSKonstantin Ananyev * Each retrieved event is automatically moved into the DOWN state.
2393395610eSKonstantin Ananyev * @param evq
2403395610eSKonstantin Ananyev *   event queue to retrieve events from.
2413395610eSKonstantin Ananyev * @param evd
2423395610eSKonstantin Ananyev *   An array of user data pointers associated with the events retrieved.
2433395610eSKonstantin Ananyev *   It must be large enough to store up to *num* pointers in it.
2443395610eSKonstantin Ananyev * @param num
2453395610eSKonstantin Ananyev *   Number of elements in the *evd* array.
2463395610eSKonstantin Ananyev * @return
2473395610eSKonstantin Ananyev *   number of of entries filled inside *evd* array.
2483395610eSKonstantin Ananyev */
2493395610eSKonstantin Ananyevstatic inline int32_t
2503395610eSKonstantin Ananyevtle_evq_get(struct tle_evq *evq, const void *evd[], uint32_t num)
2513395610eSKonstantin Ananyev{
2523395610eSKonstantin Ananyev	uint32_t i, n;
2533395610eSKonstantin Ananyev	struct tle_event *ev;
2543395610eSKonstantin Ananyev
2553395610eSKonstantin Ananyev	if (evq->nb_armed == 0)
2563395610eSKonstantin Ananyev		return 0;
2573395610eSKonstantin Ananyev
2583395610eSKonstantin Ananyev	rte_compiler_barrier();
2593395610eSKonstantin Ananyev
2603395610eSKonstantin Ananyev	rte_spinlock_lock(&evq->lock);
2613395610eSKonstantin Ananyev	n = RTE_MIN(num, evq->nb_armed);
2623395610eSKonstantin Ananyev	for (i = 0; i != n; i++) {
2633395610eSKonstantin Ananyev		ev = TAILQ_FIRST(&evq->armed);
2643395610eSKonstantin Ananyev		ev->state = TLE_SEV_DOWN;
2653395610eSKonstantin Ananyev		TAILQ_REMOVE(&evq->armed, ev, ql);
2663395610eSKonstantin Ananyev		evd[i] = ev->data;
2673395610eSKonstantin Ananyev	}
2683395610eSKonstantin Ananyev	evq->nb_armed -= n;
2693395610eSKonstantin Ananyev	rte_spinlock_unlock(&evq->lock);
2703395610eSKonstantin Ananyev	return n;
2713395610eSKonstantin Ananyev}
2723395610eSKonstantin Ananyev
2733395610eSKonstantin Ananyev
2743395610eSKonstantin Ananyev#ifdef __cplusplus
2753395610eSKonstantin Ananyev}
2763395610eSKonstantin Ananyev#endif
2773395610eSKonstantin Ananyev
2783395610eSKonstantin Ananyev#endif /* _SEV_IMPL_H_ */
279