1*2bfe3f2eSlogwang /*-
2*2bfe3f2eSlogwang  *   BSD LICENSE
3*2bfe3f2eSlogwang  *
4*2bfe3f2eSlogwang  *   Copyright(c) 2017 Intel Corporation. All rights reserved.
5*2bfe3f2eSlogwang  *
6*2bfe3f2eSlogwang  *   Redistribution and use in source and binary forms, with or without
7*2bfe3f2eSlogwang  *   modification, are permitted provided that the following conditions
8*2bfe3f2eSlogwang  *   are met:
9*2bfe3f2eSlogwang  *
10*2bfe3f2eSlogwang  *     * Redistributions of source code must retain the above copyright
11*2bfe3f2eSlogwang  *       notice, this list of conditions and the following disclaimer.
12*2bfe3f2eSlogwang  *     * Redistributions in binary form must reproduce the above copyright
13*2bfe3f2eSlogwang  *       notice, this list of conditions and the following disclaimer in
14*2bfe3f2eSlogwang  *       the documentation and/or other materials provided with the
15*2bfe3f2eSlogwang  *       distribution.
16*2bfe3f2eSlogwang  *     * Neither the name of Intel Corporation nor the names of its
17*2bfe3f2eSlogwang  *       contributors may be used to endorse or promote products derived
18*2bfe3f2eSlogwang  *       from this software without specific prior written permission.
19*2bfe3f2eSlogwang  *
20*2bfe3f2eSlogwang  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*2bfe3f2eSlogwang  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*2bfe3f2eSlogwang  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*2bfe3f2eSlogwang  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*2bfe3f2eSlogwang  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*2bfe3f2eSlogwang  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*2bfe3f2eSlogwang  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*2bfe3f2eSlogwang  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*2bfe3f2eSlogwang  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*2bfe3f2eSlogwang  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*2bfe3f2eSlogwang  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*2bfe3f2eSlogwang  */
32*2bfe3f2eSlogwang 
33*2bfe3f2eSlogwang #include <sys/queue.h>
34*2bfe3f2eSlogwang #include <string.h>
35*2bfe3f2eSlogwang 
36*2bfe3f2eSlogwang #include <rte_tailq.h>
37*2bfe3f2eSlogwang #include <rte_memzone.h>
38*2bfe3f2eSlogwang #include <rte_rwlock.h>
39*2bfe3f2eSlogwang #include <rte_eal_memconfig.h>
40*2bfe3f2eSlogwang #include "rte_event_ring.h"
41*2bfe3f2eSlogwang 
42*2bfe3f2eSlogwang TAILQ_HEAD(rte_event_ring_list, rte_tailq_entry);
43*2bfe3f2eSlogwang 
44*2bfe3f2eSlogwang static struct rte_tailq_elem rte_event_ring_tailq = {
45*2bfe3f2eSlogwang 	.name = RTE_TAILQ_EVENT_RING_NAME,
46*2bfe3f2eSlogwang };
47*2bfe3f2eSlogwang EAL_REGISTER_TAILQ(rte_event_ring_tailq)
48*2bfe3f2eSlogwang 
49*2bfe3f2eSlogwang int
50*2bfe3f2eSlogwang rte_event_ring_init(struct rte_event_ring *r, const char *name,
51*2bfe3f2eSlogwang 	unsigned int count, unsigned int flags)
52*2bfe3f2eSlogwang {
53*2bfe3f2eSlogwang 	/* compilation-time checks */
54*2bfe3f2eSlogwang 	RTE_BUILD_BUG_ON((sizeof(struct rte_event_ring) &
55*2bfe3f2eSlogwang 			  RTE_CACHE_LINE_MASK) != 0);
56*2bfe3f2eSlogwang 
57*2bfe3f2eSlogwang 	/* init the ring structure */
58*2bfe3f2eSlogwang 	return rte_ring_init(&r->r, name, count, flags);
59*2bfe3f2eSlogwang }
60*2bfe3f2eSlogwang 
61*2bfe3f2eSlogwang /* create the ring */
62*2bfe3f2eSlogwang struct rte_event_ring *
63*2bfe3f2eSlogwang rte_event_ring_create(const char *name, unsigned int count, int socket_id,
64*2bfe3f2eSlogwang 		unsigned int flags)
65*2bfe3f2eSlogwang {
66*2bfe3f2eSlogwang 	char mz_name[RTE_MEMZONE_NAMESIZE];
67*2bfe3f2eSlogwang 	struct rte_event_ring *r;
68*2bfe3f2eSlogwang 	struct rte_tailq_entry *te;
69*2bfe3f2eSlogwang 	const struct rte_memzone *mz;
70*2bfe3f2eSlogwang 	ssize_t ring_size;
71*2bfe3f2eSlogwang 	int mz_flags = 0;
72*2bfe3f2eSlogwang 	struct rte_event_ring_list *ring_list = NULL;
73*2bfe3f2eSlogwang 	const unsigned int requested_count = count;
74*2bfe3f2eSlogwang 	int ret;
75*2bfe3f2eSlogwang 
76*2bfe3f2eSlogwang 	ring_list = RTE_TAILQ_CAST(rte_event_ring_tailq.head,
77*2bfe3f2eSlogwang 		rte_event_ring_list);
78*2bfe3f2eSlogwang 
79*2bfe3f2eSlogwang 	/* for an exact size ring, round up from count to a power of two */
80*2bfe3f2eSlogwang 	if (flags & RING_F_EXACT_SZ)
81*2bfe3f2eSlogwang 		count = rte_align32pow2(count + 1);
82*2bfe3f2eSlogwang 	else if (!rte_is_power_of_2(count)) {
83*2bfe3f2eSlogwang 		rte_errno = EINVAL;
84*2bfe3f2eSlogwang 		return NULL;
85*2bfe3f2eSlogwang 	}
86*2bfe3f2eSlogwang 
87*2bfe3f2eSlogwang 	ring_size = sizeof(*r) + (count * sizeof(struct rte_event));
88*2bfe3f2eSlogwang 
89*2bfe3f2eSlogwang 	ret = snprintf(mz_name, sizeof(mz_name), "%s%s",
90*2bfe3f2eSlogwang 		RTE_RING_MZ_PREFIX, name);
91*2bfe3f2eSlogwang 	if (ret < 0 || ret >= (int)sizeof(mz_name)) {
92*2bfe3f2eSlogwang 		rte_errno = ENAMETOOLONG;
93*2bfe3f2eSlogwang 		return NULL;
94*2bfe3f2eSlogwang 	}
95*2bfe3f2eSlogwang 
96*2bfe3f2eSlogwang 	te = rte_zmalloc("RING_TAILQ_ENTRY", sizeof(*te), 0);
97*2bfe3f2eSlogwang 	if (te == NULL) {
98*2bfe3f2eSlogwang 		RTE_LOG(ERR, RING, "Cannot reserve memory for tailq\n");
99*2bfe3f2eSlogwang 		rte_errno = ENOMEM;
100*2bfe3f2eSlogwang 		return NULL;
101*2bfe3f2eSlogwang 	}
102*2bfe3f2eSlogwang 
103*2bfe3f2eSlogwang 	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
104*2bfe3f2eSlogwang 
105*2bfe3f2eSlogwang 	/*
106*2bfe3f2eSlogwang 	 * reserve a memory zone for this ring. If we can't get rte_config or
107*2bfe3f2eSlogwang 	 * we are secondary process, the memzone_reserve function will set
108*2bfe3f2eSlogwang 	 * rte_errno for us appropriately - hence no check in this this function
109*2bfe3f2eSlogwang 	 */
110*2bfe3f2eSlogwang 	mz = rte_memzone_reserve(mz_name, ring_size, socket_id, mz_flags);
111*2bfe3f2eSlogwang 	if (mz != NULL) {
112*2bfe3f2eSlogwang 		r = mz->addr;
113*2bfe3f2eSlogwang 		/*
114*2bfe3f2eSlogwang 		 * no need to check return value here, we already checked the
115*2bfe3f2eSlogwang 		 * arguments above
116*2bfe3f2eSlogwang 		 */
117*2bfe3f2eSlogwang 		rte_event_ring_init(r, name, requested_count, flags);
118*2bfe3f2eSlogwang 
119*2bfe3f2eSlogwang 		te->data = (void *) r;
120*2bfe3f2eSlogwang 		r->r.memzone = mz;
121*2bfe3f2eSlogwang 
122*2bfe3f2eSlogwang 		TAILQ_INSERT_TAIL(ring_list, te, next);
123*2bfe3f2eSlogwang 	} else {
124*2bfe3f2eSlogwang 		r = NULL;
125*2bfe3f2eSlogwang 		RTE_LOG(ERR, RING, "Cannot reserve memory\n");
126*2bfe3f2eSlogwang 		rte_free(te);
127*2bfe3f2eSlogwang 	}
128*2bfe3f2eSlogwang 	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
129*2bfe3f2eSlogwang 
130*2bfe3f2eSlogwang 	return r;
131*2bfe3f2eSlogwang }
132*2bfe3f2eSlogwang 
133*2bfe3f2eSlogwang 
134*2bfe3f2eSlogwang struct rte_event_ring *
135*2bfe3f2eSlogwang rte_event_ring_lookup(const char *name)
136*2bfe3f2eSlogwang {
137*2bfe3f2eSlogwang 	struct rte_tailq_entry *te;
138*2bfe3f2eSlogwang 	struct rte_event_ring *r = NULL;
139*2bfe3f2eSlogwang 	struct rte_event_ring_list *ring_list;
140*2bfe3f2eSlogwang 
141*2bfe3f2eSlogwang 	ring_list = RTE_TAILQ_CAST(rte_event_ring_tailq.head,
142*2bfe3f2eSlogwang 			rte_event_ring_list);
143*2bfe3f2eSlogwang 
144*2bfe3f2eSlogwang 	rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
145*2bfe3f2eSlogwang 
146*2bfe3f2eSlogwang 	TAILQ_FOREACH(te, ring_list, next) {
147*2bfe3f2eSlogwang 		r = (struct rte_event_ring *) te->data;
148*2bfe3f2eSlogwang 		if (strncmp(name, r->r.name, RTE_RING_NAMESIZE) == 0)
149*2bfe3f2eSlogwang 			break;
150*2bfe3f2eSlogwang 	}
151*2bfe3f2eSlogwang 
152*2bfe3f2eSlogwang 	rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
153*2bfe3f2eSlogwang 
154*2bfe3f2eSlogwang 	if (te == NULL) {
155*2bfe3f2eSlogwang 		rte_errno = ENOENT;
156*2bfe3f2eSlogwang 		return NULL;
157*2bfe3f2eSlogwang 	}
158*2bfe3f2eSlogwang 
159*2bfe3f2eSlogwang 	return r;
160*2bfe3f2eSlogwang }
161*2bfe3f2eSlogwang 
162*2bfe3f2eSlogwang /* free the ring */
163*2bfe3f2eSlogwang void
164*2bfe3f2eSlogwang rte_event_ring_free(struct rte_event_ring *r)
165*2bfe3f2eSlogwang {
166*2bfe3f2eSlogwang 	struct rte_event_ring_list *ring_list = NULL;
167*2bfe3f2eSlogwang 	struct rte_tailq_entry *te;
168*2bfe3f2eSlogwang 
169*2bfe3f2eSlogwang 	if (r == NULL)
170*2bfe3f2eSlogwang 		return;
171*2bfe3f2eSlogwang 
172*2bfe3f2eSlogwang 	/*
173*2bfe3f2eSlogwang 	 * Ring was not created with rte_event_ring_create,
174*2bfe3f2eSlogwang 	 * therefore, there is no memzone to free.
175*2bfe3f2eSlogwang 	 */
176*2bfe3f2eSlogwang 	if (r->r.memzone == NULL) {
177*2bfe3f2eSlogwang 		RTE_LOG(ERR, RING,
178*2bfe3f2eSlogwang 			"Cannot free ring (not created with rte_event_ring_create()");
179*2bfe3f2eSlogwang 		return;
180*2bfe3f2eSlogwang 	}
181*2bfe3f2eSlogwang 
182*2bfe3f2eSlogwang 	if (rte_memzone_free(r->r.memzone) != 0) {
183*2bfe3f2eSlogwang 		RTE_LOG(ERR, RING, "Cannot free memory\n");
184*2bfe3f2eSlogwang 		return;
185*2bfe3f2eSlogwang 	}
186*2bfe3f2eSlogwang 
187*2bfe3f2eSlogwang 	ring_list = RTE_TAILQ_CAST(rte_event_ring_tailq.head,
188*2bfe3f2eSlogwang 			rte_event_ring_list);
189*2bfe3f2eSlogwang 	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
190*2bfe3f2eSlogwang 
191*2bfe3f2eSlogwang 	/* find out tailq entry */
192*2bfe3f2eSlogwang 	TAILQ_FOREACH(te, ring_list, next) {
193*2bfe3f2eSlogwang 		if (te->data == (void *) r)
194*2bfe3f2eSlogwang 			break;
195*2bfe3f2eSlogwang 	}
196*2bfe3f2eSlogwang 
197*2bfe3f2eSlogwang 	if (te == NULL) {
198*2bfe3f2eSlogwang 		rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
199*2bfe3f2eSlogwang 		return;
200*2bfe3f2eSlogwang 	}
201*2bfe3f2eSlogwang 
202*2bfe3f2eSlogwang 	TAILQ_REMOVE(ring_list, te, next);
203*2bfe3f2eSlogwang 
204*2bfe3f2eSlogwang 	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
205*2bfe3f2eSlogwang 
206*2bfe3f2eSlogwang 	rte_free(te);
207*2bfe3f2eSlogwang }
208