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
10921e7392fSKonstantin Ananyevstatic inline enum tle_ev_state
11021e7392fSKonstantin Ananyevtle_event_state(const struct tle_event *ev)
11121e7392fSKonstantin Ananyev{
11221e7392fSKonstantin Ananyev	return ev->state;
11321e7392fSKonstantin Ananyev}
1143395610eSKonstantin Ananyev
1153395610eSKonstantin Ananyev/**
1163395610eSKonstantin Ananyev * move event from DOWN to UP state.
1173395610eSKonstantin Ananyev * @param ev
1183395610eSKonstantin Ananyev *   Pointer to the event.
1193395610eSKonstantin Ananyev */
1203395610eSKonstantin Ananyevstatic inline void
1213395610eSKonstantin Ananyevtle_event_raise(struct tle_event *ev)
1223395610eSKonstantin Ananyev{
1233395610eSKonstantin Ananyev	struct tle_evq *q;
1243395610eSKonstantin Ananyev
1253395610eSKonstantin Ananyev	if (ev->state != TLE_SEV_DOWN)
1263395610eSKonstantin Ananyev		return;
1273395610eSKonstantin Ananyev
1283395610eSKonstantin Ananyev	q = ev->head;
1293395610eSKonstantin Ananyev	rte_compiler_barrier();
1303395610eSKonstantin Ananyev
1313395610eSKonstantin Ananyev	rte_spinlock_lock(&q->lock);
1323395610eSKonstantin Ananyev	if (ev->state == TLE_SEV_DOWN) {
1333395610eSKonstantin Ananyev		ev->state = TLE_SEV_UP;
1343395610eSKonstantin Ananyev		TAILQ_INSERT_TAIL(&q->armed, ev, ql);
1353395610eSKonstantin Ananyev		q->nb_armed++;
1363395610eSKonstantin Ananyev	}
1373395610eSKonstantin Ananyev	rte_spinlock_unlock(&q->lock);
1383395610eSKonstantin Ananyev}
1393395610eSKonstantin Ananyev
1403395610eSKonstantin Ananyev/**
1413395610eSKonstantin Ananyev * move event from UP to DOWN state.
1423395610eSKonstantin Ananyev * @param ev
1433395610eSKonstantin Ananyev *   Pointer to the event.
1443395610eSKonstantin Ananyev */
1453395610eSKonstantin Ananyevstatic inline void
1463395610eSKonstantin Ananyevtle_event_down(struct tle_event *ev)
1473395610eSKonstantin Ananyev{
1483395610eSKonstantin Ananyev	struct tle_evq *q;
1493395610eSKonstantin Ananyev
1503395610eSKonstantin Ananyev	if (ev->state != TLE_SEV_UP)
1513395610eSKonstantin Ananyev		return;
1523395610eSKonstantin Ananyev
1533395610eSKonstantin Ananyev	q = ev->head;
1543395610eSKonstantin Ananyev	rte_compiler_barrier();
1553395610eSKonstantin Ananyev
1563395610eSKonstantin Ananyev	rte_spinlock_lock(&q->lock);
1573395610eSKonstantin Ananyev	if (ev->state == TLE_SEV_UP) {
1583395610eSKonstantin Ananyev		ev->state = TLE_SEV_DOWN;
1593395610eSKonstantin Ananyev		TAILQ_REMOVE(&q->armed, ev, ql);
1603395610eSKonstantin Ananyev		q->nb_armed--;
1613395610eSKonstantin Ananyev	}
1623395610eSKonstantin Ananyev	rte_spinlock_unlock(&q->lock);
1633395610eSKonstantin Ananyev}
1643395610eSKonstantin Ananyev
1653395610eSKonstantin Ananyev/**
1663395610eSKonstantin Ananyev * move from IDLE to DOWN/UP state.
1673395610eSKonstantin Ananyev * @param ev
1683395610eSKonstantin Ananyev *   Pointer to the event.
1693395610eSKonstantin Ananyev * @param st
1703395610eSKonstantin Ananyev *   new state for the event.
1713395610eSKonstantin Ananyev */
1723395610eSKonstantin Ananyevstatic inline void
1733395610eSKonstantin Ananyevtle_event_active(struct tle_event *ev, enum tle_ev_state st)
1743395610eSKonstantin Ananyev{
1753395610eSKonstantin Ananyev	struct tle_evq *q;
1763395610eSKonstantin Ananyev
177c603d3edSKarol Latecki	if (ev->state != TLE_SEV_IDLE)
1783395610eSKonstantin Ananyev		return;
1793395610eSKonstantin Ananyev
1803395610eSKonstantin Ananyev	q = ev->head;
1813395610eSKonstantin Ananyev	rte_compiler_barrier();
1823395610eSKonstantin Ananyev
1833395610eSKonstantin Ananyev	rte_spinlock_lock(&q->lock);
1843395610eSKonstantin Ananyev	if (st > ev->state) {
1853395610eSKonstantin Ananyev		if (st == TLE_SEV_UP) {
1863395610eSKonstantin Ananyev			TAILQ_INSERT_TAIL(&q->armed, ev, ql);
1873395610eSKonstantin Ananyev			q->nb_armed++;
1883395610eSKonstantin Ananyev		}
1893395610eSKonstantin Ananyev		ev->state = st;
1903395610eSKonstantin Ananyev	}
1913395610eSKonstantin Ananyev	rte_spinlock_unlock(&q->lock);
1923395610eSKonstantin Ananyev}
1933395610eSKonstantin Ananyev
1943395610eSKonstantin Ananyev/**
1953395610eSKonstantin Ananyev * move event IDLE state.
1963395610eSKonstantin Ananyev * @param ev
1973395610eSKonstantin Ananyev *   Pointer to the event.
1983395610eSKonstantin Ananyev */
1993395610eSKonstantin Ananyevstatic inline void
2003395610eSKonstantin Ananyevtle_event_idle(struct tle_event *ev)
2013395610eSKonstantin Ananyev{
2023395610eSKonstantin Ananyev	struct tle_evq *q;
2033395610eSKonstantin Ananyev
2043395610eSKonstantin Ananyev	if (ev->state == TLE_SEV_IDLE)
2053395610eSKonstantin Ananyev		return;
2063395610eSKonstantin Ananyev
2073395610eSKonstantin Ananyev	q = ev->head;
2083395610eSKonstantin Ananyev	rte_compiler_barrier();
2093395610eSKonstantin Ananyev
2103395610eSKonstantin Ananyev	rte_spinlock_lock(&q->lock);
2113395610eSKonstantin Ananyev	if (ev->state == TLE_SEV_UP) {
2123395610eSKonstantin Ananyev		TAILQ_REMOVE(&q->armed, ev, ql);
2133395610eSKonstantin Ananyev		q->nb_armed--;
2143395610eSKonstantin Ananyev	}
2153395610eSKonstantin Ananyev	ev->state = TLE_SEV_IDLE;
2163395610eSKonstantin Ananyev	rte_spinlock_unlock(&q->lock);
2173395610eSKonstantin Ananyev}
2183395610eSKonstantin Ananyev
219aa97dd1cSKonstantin Ananyevstatic inline void
220aa97dd1cSKonstantin Ananyevtle_evq_idle(struct tle_evq *evq, struct tle_event *ev[], uint32_t num)
221aa97dd1cSKonstantin Ananyev{
222aa97dd1cSKonstantin Ananyev	uint32_t i, n;
223aa97dd1cSKonstantin Ananyev
224aa97dd1cSKonstantin Ananyev	rte_spinlock_lock(&evq->lock);
225aa97dd1cSKonstantin Ananyev
226aa97dd1cSKonstantin Ananyev	n = 0;
227aa97dd1cSKonstantin Ananyev	for (i = 0; i != num; i++) {
228aa97dd1cSKonstantin Ananyev		if (ev[i]->state == TLE_SEV_UP) {
229aa97dd1cSKonstantin Ananyev			TAILQ_REMOVE(&evq->armed, ev[i], ql);
230aa97dd1cSKonstantin Ananyev			n++;
231aa97dd1cSKonstantin Ananyev		}
232aa97dd1cSKonstantin Ananyev		ev[i]->state = TLE_SEV_IDLE;
233aa97dd1cSKonstantin Ananyev	}
234aa97dd1cSKonstantin Ananyev
235aa97dd1cSKonstantin Ananyev	evq->nb_armed -= n;
236aa97dd1cSKonstantin Ananyev	rte_spinlock_unlock(&evq->lock);
237aa97dd1cSKonstantin Ananyev}
238aa97dd1cSKonstantin Ananyev
2393395610eSKonstantin Ananyev
2403395610eSKonstantin Ananyev/*
2413395610eSKonstantin Ananyev * return up to *num* user data pointers associated with
2423395610eSKonstantin Ananyev * the events that were in the UP state.
2433395610eSKonstantin Ananyev * Each retrieved event is automatically moved into the DOWN state.
2443395610eSKonstantin Ananyev * @param evq
2453395610eSKonstantin Ananyev *   event queue to retrieve events from.
2463395610eSKonstantin Ananyev * @param evd
2473395610eSKonstantin Ananyev *   An array of user data pointers associated with the events retrieved.
2483395610eSKonstantin Ananyev *   It must be large enough to store up to *num* pointers in it.
2493395610eSKonstantin Ananyev * @param num
2503395610eSKonstantin Ananyev *   Number of elements in the *evd* array.
2513395610eSKonstantin Ananyev * @return
2523395610eSKonstantin Ananyev *   number of of entries filled inside *evd* array.
2533395610eSKonstantin Ananyev */
2543395610eSKonstantin Ananyevstatic inline int32_t
2553395610eSKonstantin Ananyevtle_evq_get(struct tle_evq *evq, const void *evd[], uint32_t num)
2563395610eSKonstantin Ananyev{
2573395610eSKonstantin Ananyev	uint32_t i, n;
2583395610eSKonstantin Ananyev	struct tle_event *ev;
2593395610eSKonstantin Ananyev
2603395610eSKonstantin Ananyev	if (evq->nb_armed == 0)
2613395610eSKonstantin Ananyev		return 0;
2623395610eSKonstantin Ananyev
2633395610eSKonstantin Ananyev	rte_compiler_barrier();
2643395610eSKonstantin Ananyev
2653395610eSKonstantin Ananyev	rte_spinlock_lock(&evq->lock);
2663395610eSKonstantin Ananyev	n = RTE_MIN(num, evq->nb_armed);
2673395610eSKonstantin Ananyev	for (i = 0; i != n; i++) {
2683395610eSKonstantin Ananyev		ev = TAILQ_FIRST(&evq->armed);
2693395610eSKonstantin Ananyev		ev->state = TLE_SEV_DOWN;
2703395610eSKonstantin Ananyev		TAILQ_REMOVE(&evq->armed, ev, ql);
2713395610eSKonstantin Ananyev		evd[i] = ev->data;
2723395610eSKonstantin Ananyev	}
2733395610eSKonstantin Ananyev	evq->nb_armed -= n;
2743395610eSKonstantin Ananyev	rte_spinlock_unlock(&evq->lock);
2753395610eSKonstantin Ananyev	return n;
2763395610eSKonstantin Ananyev}
2773395610eSKonstantin Ananyev
2783395610eSKonstantin Ananyev
2793395610eSKonstantin Ananyev#ifdef __cplusplus
2803395610eSKonstantin Ananyev}
2813395610eSKonstantin Ananyev#endif
2823395610eSKonstantin Ananyev
2833395610eSKonstantin Ananyev#endif /* _SEV_IMPL_H_ */
284