xref: /dpdk/examples/pipeline/thread.c (revision 0b50ea60fbfadba1f5edce1893782e4d928e5446)
1b77f6600SCristian Dumitrescu /* SPDX-License-Identifier: BSD-3-Clause
2b77f6600SCristian Dumitrescu  * Copyright(c) 2020 Intel Corporation
3b77f6600SCristian Dumitrescu  */
4b77f6600SCristian Dumitrescu 
5b77f6600SCristian Dumitrescu #include <stdlib.h>
6b77f6600SCristian Dumitrescu 
7b77f6600SCristian Dumitrescu #include <rte_common.h>
8b77f6600SCristian Dumitrescu #include <rte_cycles.h>
9b77f6600SCristian Dumitrescu #include <rte_lcore.h>
10b77f6600SCristian Dumitrescu #include <rte_ring.h>
11b77f6600SCristian Dumitrescu 
12b77f6600SCristian Dumitrescu #include <rte_table_acl.h>
13b77f6600SCristian Dumitrescu #include <rte_table_array.h>
14b77f6600SCristian Dumitrescu #include <rte_table_hash.h>
15b77f6600SCristian Dumitrescu #include <rte_table_lpm.h>
16b77f6600SCristian Dumitrescu #include <rte_table_lpm_ipv6.h>
17b77f6600SCristian Dumitrescu 
18b77f6600SCristian Dumitrescu #include "obj.h"
19b77f6600SCristian Dumitrescu #include "thread.h"
20b77f6600SCristian Dumitrescu 
21b77f6600SCristian Dumitrescu #ifndef THREAD_PIPELINES_MAX
22b77f6600SCristian Dumitrescu #define THREAD_PIPELINES_MAX                               256
23b77f6600SCristian Dumitrescu #endif
24b77f6600SCristian Dumitrescu 
25b77f6600SCristian Dumitrescu #ifndef THREAD_MSGQ_SIZE
26b77f6600SCristian Dumitrescu #define THREAD_MSGQ_SIZE                                   64
27b77f6600SCristian Dumitrescu #endif
28b77f6600SCristian Dumitrescu 
29b77f6600SCristian Dumitrescu #ifndef THREAD_TIMER_PERIOD_MS
30b77f6600SCristian Dumitrescu #define THREAD_TIMER_PERIOD_MS                             100
31b77f6600SCristian Dumitrescu #endif
32b77f6600SCristian Dumitrescu 
33*0b50ea60SCristian Dumitrescu /* Pipeline instruction quanta: Needs to be big enough to do some meaningful
34*0b50ea60SCristian Dumitrescu  * work, but not too big to avoid starving any other pipelines mapped to the
35*0b50ea60SCristian Dumitrescu  * same thread. For a pipeline that executes 10 instructions per packet, a
36*0b50ea60SCristian Dumitrescu  * quanta of 1000 instructions equates to processing 100 packets.
37*0b50ea60SCristian Dumitrescu  */
38*0b50ea60SCristian Dumitrescu #ifndef PIPELINE_INSTR_QUANTA
39*0b50ea60SCristian Dumitrescu #define PIPELINE_INSTR_QUANTA                              1000
40*0b50ea60SCristian Dumitrescu #endif
41*0b50ea60SCristian Dumitrescu 
42b77f6600SCristian Dumitrescu /**
43b77f6600SCristian Dumitrescu  * Control thread: data plane thread context
44b77f6600SCristian Dumitrescu  */
45b77f6600SCristian Dumitrescu struct thread {
46b77f6600SCristian Dumitrescu 	struct rte_ring *msgq_req;
47b77f6600SCristian Dumitrescu 	struct rte_ring *msgq_rsp;
48b77f6600SCristian Dumitrescu 
49b77f6600SCristian Dumitrescu 	uint32_t enabled;
50b77f6600SCristian Dumitrescu };
51b77f6600SCristian Dumitrescu 
52b77f6600SCristian Dumitrescu static struct thread thread[RTE_MAX_LCORE];
53b77f6600SCristian Dumitrescu 
54b77f6600SCristian Dumitrescu /**
55b77f6600SCristian Dumitrescu  * Data plane threads: context
56b77f6600SCristian Dumitrescu  */
57b77f6600SCristian Dumitrescu struct pipeline_data {
58b77f6600SCristian Dumitrescu 	struct rte_swx_pipeline *p;
59b77f6600SCristian Dumitrescu 	uint64_t timer_period; /* Measured in CPU cycles. */
60b77f6600SCristian Dumitrescu 	uint64_t time_next;
61b77f6600SCristian Dumitrescu };
62b77f6600SCristian Dumitrescu 
63b77f6600SCristian Dumitrescu struct thread_data {
64b77f6600SCristian Dumitrescu 	struct rte_swx_pipeline *p[THREAD_PIPELINES_MAX];
65b77f6600SCristian Dumitrescu 	uint32_t n_pipelines;
66b77f6600SCristian Dumitrescu 
67b77f6600SCristian Dumitrescu 	struct pipeline_data pipeline_data[THREAD_PIPELINES_MAX];
68b77f6600SCristian Dumitrescu 	struct rte_ring *msgq_req;
69b77f6600SCristian Dumitrescu 	struct rte_ring *msgq_rsp;
70b77f6600SCristian Dumitrescu 	uint64_t timer_period; /* Measured in CPU cycles. */
71b77f6600SCristian Dumitrescu 	uint64_t time_next;
72b77f6600SCristian Dumitrescu 	uint64_t time_next_min;
73b77f6600SCristian Dumitrescu } __rte_cache_aligned;
74b77f6600SCristian Dumitrescu 
75b77f6600SCristian Dumitrescu static struct thread_data thread_data[RTE_MAX_LCORE];
76b77f6600SCristian Dumitrescu 
77b77f6600SCristian Dumitrescu /**
78b77f6600SCristian Dumitrescu  * Control thread: data plane thread init
79b77f6600SCristian Dumitrescu  */
80b77f6600SCristian Dumitrescu static void
81b77f6600SCristian Dumitrescu thread_free(void)
82b77f6600SCristian Dumitrescu {
83b77f6600SCristian Dumitrescu 	uint32_t i;
84b77f6600SCristian Dumitrescu 
85b77f6600SCristian Dumitrescu 	for (i = 0; i < RTE_MAX_LCORE; i++) {
86b77f6600SCristian Dumitrescu 		struct thread *t = &thread[i];
87b77f6600SCristian Dumitrescu 
88b77f6600SCristian Dumitrescu 		if (!rte_lcore_is_enabled(i))
89b77f6600SCristian Dumitrescu 			continue;
90b77f6600SCristian Dumitrescu 
91b77f6600SCristian Dumitrescu 		/* MSGQs */
92b77f6600SCristian Dumitrescu 		if (t->msgq_req)
93b77f6600SCristian Dumitrescu 			rte_ring_free(t->msgq_req);
94b77f6600SCristian Dumitrescu 
95b77f6600SCristian Dumitrescu 		if (t->msgq_rsp)
96b77f6600SCristian Dumitrescu 			rte_ring_free(t->msgq_rsp);
97b77f6600SCristian Dumitrescu 	}
98b77f6600SCristian Dumitrescu }
99b77f6600SCristian Dumitrescu 
100b77f6600SCristian Dumitrescu int
101b77f6600SCristian Dumitrescu thread_init(void)
102b77f6600SCristian Dumitrescu {
103b77f6600SCristian Dumitrescu 	uint32_t i;
104b77f6600SCristian Dumitrescu 
105cb056611SStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(i) {
106b77f6600SCristian Dumitrescu 		char name[NAME_MAX];
107b77f6600SCristian Dumitrescu 		struct rte_ring *msgq_req, *msgq_rsp;
108b77f6600SCristian Dumitrescu 		struct thread *t = &thread[i];
109b77f6600SCristian Dumitrescu 		struct thread_data *t_data = &thread_data[i];
110b77f6600SCristian Dumitrescu 		uint32_t cpu_id = rte_lcore_to_socket_id(i);
111b77f6600SCristian Dumitrescu 
112b77f6600SCristian Dumitrescu 		/* MSGQs */
113b77f6600SCristian Dumitrescu 		snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-REQ", i);
114b77f6600SCristian Dumitrescu 
115b77f6600SCristian Dumitrescu 		msgq_req = rte_ring_create(name,
116b77f6600SCristian Dumitrescu 			THREAD_MSGQ_SIZE,
117b77f6600SCristian Dumitrescu 			cpu_id,
118b77f6600SCristian Dumitrescu 			RING_F_SP_ENQ | RING_F_SC_DEQ);
119b77f6600SCristian Dumitrescu 
120b77f6600SCristian Dumitrescu 		if (msgq_req == NULL) {
121b77f6600SCristian Dumitrescu 			thread_free();
122b77f6600SCristian Dumitrescu 			return -1;
123b77f6600SCristian Dumitrescu 		}
124b77f6600SCristian Dumitrescu 
125b77f6600SCristian Dumitrescu 		snprintf(name, sizeof(name), "THREAD-%04x-MSGQ-RSP", i);
126b77f6600SCristian Dumitrescu 
127b77f6600SCristian Dumitrescu 		msgq_rsp = rte_ring_create(name,
128b77f6600SCristian Dumitrescu 			THREAD_MSGQ_SIZE,
129b77f6600SCristian Dumitrescu 			cpu_id,
130b77f6600SCristian Dumitrescu 			RING_F_SP_ENQ | RING_F_SC_DEQ);
131b77f6600SCristian Dumitrescu 
132b77f6600SCristian Dumitrescu 		if (msgq_rsp == NULL) {
133b77f6600SCristian Dumitrescu 			thread_free();
134b77f6600SCristian Dumitrescu 			return -1;
135b77f6600SCristian Dumitrescu 		}
136b77f6600SCristian Dumitrescu 
137b77f6600SCristian Dumitrescu 		/* Control thread records */
138b77f6600SCristian Dumitrescu 		t->msgq_req = msgq_req;
139b77f6600SCristian Dumitrescu 		t->msgq_rsp = msgq_rsp;
140b77f6600SCristian Dumitrescu 		t->enabled = 1;
141b77f6600SCristian Dumitrescu 
142b77f6600SCristian Dumitrescu 		/* Data plane thread records */
143b77f6600SCristian Dumitrescu 		t_data->n_pipelines = 0;
144b77f6600SCristian Dumitrescu 		t_data->msgq_req = msgq_req;
145b77f6600SCristian Dumitrescu 		t_data->msgq_rsp = msgq_rsp;
146b77f6600SCristian Dumitrescu 		t_data->timer_period =
147b77f6600SCristian Dumitrescu 			(rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
148b77f6600SCristian Dumitrescu 		t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
149b77f6600SCristian Dumitrescu 		t_data->time_next_min = t_data->time_next;
150b77f6600SCristian Dumitrescu 	}
151b77f6600SCristian Dumitrescu 
152b77f6600SCristian Dumitrescu 	return 0;
153b77f6600SCristian Dumitrescu }
154b77f6600SCristian Dumitrescu 
155b77f6600SCristian Dumitrescu static inline int
156b77f6600SCristian Dumitrescu thread_is_running(uint32_t thread_id)
157b77f6600SCristian Dumitrescu {
158b77f6600SCristian Dumitrescu 	enum rte_lcore_state_t thread_state;
159b77f6600SCristian Dumitrescu 
160b77f6600SCristian Dumitrescu 	thread_state = rte_eal_get_lcore_state(thread_id);
161b77f6600SCristian Dumitrescu 	return (thread_state == RUNNING) ? 1 : 0;
162b77f6600SCristian Dumitrescu }
163b77f6600SCristian Dumitrescu 
164b77f6600SCristian Dumitrescu /**
165b77f6600SCristian Dumitrescu  * Control thread & data plane threads: message passing
166b77f6600SCristian Dumitrescu  */
167b77f6600SCristian Dumitrescu enum thread_req_type {
168b77f6600SCristian Dumitrescu 	THREAD_REQ_PIPELINE_ENABLE = 0,
169b77f6600SCristian Dumitrescu 	THREAD_REQ_PIPELINE_DISABLE,
170b77f6600SCristian Dumitrescu 	THREAD_REQ_MAX
171b77f6600SCristian Dumitrescu };
172b77f6600SCristian Dumitrescu 
173b77f6600SCristian Dumitrescu struct thread_msg_req {
174b77f6600SCristian Dumitrescu 	enum thread_req_type type;
175b77f6600SCristian Dumitrescu 
176b77f6600SCristian Dumitrescu 	union {
177b77f6600SCristian Dumitrescu 		struct {
178b77f6600SCristian Dumitrescu 			struct rte_swx_pipeline *p;
179b77f6600SCristian Dumitrescu 			uint32_t timer_period_ms;
180b77f6600SCristian Dumitrescu 		} pipeline_enable;
181b77f6600SCristian Dumitrescu 
182b77f6600SCristian Dumitrescu 		struct {
183b77f6600SCristian Dumitrescu 			struct rte_swx_pipeline *p;
184b77f6600SCristian Dumitrescu 		} pipeline_disable;
185b77f6600SCristian Dumitrescu 	};
186b77f6600SCristian Dumitrescu };
187b77f6600SCristian Dumitrescu 
188b77f6600SCristian Dumitrescu struct thread_msg_rsp {
189b77f6600SCristian Dumitrescu 	int status;
190b77f6600SCristian Dumitrescu };
191b77f6600SCristian Dumitrescu 
192b77f6600SCristian Dumitrescu /**
193b77f6600SCristian Dumitrescu  * Control thread
194b77f6600SCristian Dumitrescu  */
195b77f6600SCristian Dumitrescu static struct thread_msg_req *
196b77f6600SCristian Dumitrescu thread_msg_alloc(void)
197b77f6600SCristian Dumitrescu {
198b77f6600SCristian Dumitrescu 	size_t size = RTE_MAX(sizeof(struct thread_msg_req),
199b77f6600SCristian Dumitrescu 		sizeof(struct thread_msg_rsp));
200b77f6600SCristian Dumitrescu 
201b77f6600SCristian Dumitrescu 	return calloc(1, size);
202b77f6600SCristian Dumitrescu }
203b77f6600SCristian Dumitrescu 
204b77f6600SCristian Dumitrescu static void
205b77f6600SCristian Dumitrescu thread_msg_free(struct thread_msg_rsp *rsp)
206b77f6600SCristian Dumitrescu {
207b77f6600SCristian Dumitrescu 	free(rsp);
208b77f6600SCristian Dumitrescu }
209b77f6600SCristian Dumitrescu 
210b77f6600SCristian Dumitrescu static struct thread_msg_rsp *
211b77f6600SCristian Dumitrescu thread_msg_send_recv(uint32_t thread_id,
212b77f6600SCristian Dumitrescu 	struct thread_msg_req *req)
213b77f6600SCristian Dumitrescu {
214b77f6600SCristian Dumitrescu 	struct thread *t = &thread[thread_id];
215b77f6600SCristian Dumitrescu 	struct rte_ring *msgq_req = t->msgq_req;
216b77f6600SCristian Dumitrescu 	struct rte_ring *msgq_rsp = t->msgq_rsp;
217b77f6600SCristian Dumitrescu 	struct thread_msg_rsp *rsp;
218b77f6600SCristian Dumitrescu 	int status;
219b77f6600SCristian Dumitrescu 
220b77f6600SCristian Dumitrescu 	/* send */
221b77f6600SCristian Dumitrescu 	do {
222b77f6600SCristian Dumitrescu 		status = rte_ring_sp_enqueue(msgq_req, req);
223b77f6600SCristian Dumitrescu 	} while (status == -ENOBUFS);
224b77f6600SCristian Dumitrescu 
225b77f6600SCristian Dumitrescu 	/* recv */
226b77f6600SCristian Dumitrescu 	do {
227b77f6600SCristian Dumitrescu 		status = rte_ring_sc_dequeue(msgq_rsp, (void **) &rsp);
228b77f6600SCristian Dumitrescu 	} while (status != 0);
229b77f6600SCristian Dumitrescu 
230b77f6600SCristian Dumitrescu 	return rsp;
231b77f6600SCristian Dumitrescu }
232b77f6600SCristian Dumitrescu 
233b77f6600SCristian Dumitrescu int
234b77f6600SCristian Dumitrescu thread_pipeline_enable(uint32_t thread_id,
235b77f6600SCristian Dumitrescu 	struct obj *obj,
236b77f6600SCristian Dumitrescu 	const char *pipeline_name)
237b77f6600SCristian Dumitrescu {
238b77f6600SCristian Dumitrescu 	struct pipeline *p = pipeline_find(obj, pipeline_name);
239b77f6600SCristian Dumitrescu 	struct thread *t;
240b77f6600SCristian Dumitrescu 	struct thread_msg_req *req;
241b77f6600SCristian Dumitrescu 	struct thread_msg_rsp *rsp;
242b77f6600SCristian Dumitrescu 	int status;
243b77f6600SCristian Dumitrescu 
244b77f6600SCristian Dumitrescu 	/* Check input params */
245b77f6600SCristian Dumitrescu 	if ((thread_id >= RTE_MAX_LCORE) ||
246b77f6600SCristian Dumitrescu 		(p == NULL))
247b77f6600SCristian Dumitrescu 		return -1;
248b77f6600SCristian Dumitrescu 
249b77f6600SCristian Dumitrescu 	t = &thread[thread_id];
250b77f6600SCristian Dumitrescu 	if (t->enabled == 0)
251b77f6600SCristian Dumitrescu 		return -1;
252b77f6600SCristian Dumitrescu 
253b77f6600SCristian Dumitrescu 	if (!thread_is_running(thread_id)) {
254b77f6600SCristian Dumitrescu 		struct thread_data *td = &thread_data[thread_id];
255b77f6600SCristian Dumitrescu 		struct pipeline_data *tdp = &td->pipeline_data[td->n_pipelines];
256b77f6600SCristian Dumitrescu 
257b77f6600SCristian Dumitrescu 		if (td->n_pipelines >= THREAD_PIPELINES_MAX)
258b77f6600SCristian Dumitrescu 			return -1;
259b77f6600SCristian Dumitrescu 
260b77f6600SCristian Dumitrescu 		/* Data plane thread */
261b77f6600SCristian Dumitrescu 		td->p[td->n_pipelines] = p->p;
262b77f6600SCristian Dumitrescu 
263b77f6600SCristian Dumitrescu 		tdp->p = p->p;
264b77f6600SCristian Dumitrescu 		tdp->timer_period =
265b77f6600SCristian Dumitrescu 			(rte_get_tsc_hz() * p->timer_period_ms) / 1000;
266b77f6600SCristian Dumitrescu 		tdp->time_next = rte_get_tsc_cycles() + tdp->timer_period;
267b77f6600SCristian Dumitrescu 
268b77f6600SCristian Dumitrescu 		td->n_pipelines++;
269b77f6600SCristian Dumitrescu 
270b77f6600SCristian Dumitrescu 		/* Pipeline */
271b77f6600SCristian Dumitrescu 		p->thread_id = thread_id;
272b77f6600SCristian Dumitrescu 		p->enabled = 1;
273b77f6600SCristian Dumitrescu 
274b77f6600SCristian Dumitrescu 		return 0;
275b77f6600SCristian Dumitrescu 	}
276b77f6600SCristian Dumitrescu 
277b77f6600SCristian Dumitrescu 	/* Allocate request */
278b77f6600SCristian Dumitrescu 	req = thread_msg_alloc();
279b77f6600SCristian Dumitrescu 	if (req == NULL)
280b77f6600SCristian Dumitrescu 		return -1;
281b77f6600SCristian Dumitrescu 
282b77f6600SCristian Dumitrescu 	/* Write request */
283b77f6600SCristian Dumitrescu 	req->type = THREAD_REQ_PIPELINE_ENABLE;
284b77f6600SCristian Dumitrescu 	req->pipeline_enable.p = p->p;
285b77f6600SCristian Dumitrescu 	req->pipeline_enable.timer_period_ms = p->timer_period_ms;
286b77f6600SCristian Dumitrescu 
287b77f6600SCristian Dumitrescu 	/* Send request and wait for response */
288b77f6600SCristian Dumitrescu 	rsp = thread_msg_send_recv(thread_id, req);
289b77f6600SCristian Dumitrescu 
290b77f6600SCristian Dumitrescu 	/* Read response */
291b77f6600SCristian Dumitrescu 	status = rsp->status;
292b77f6600SCristian Dumitrescu 
293b77f6600SCristian Dumitrescu 	/* Free response */
294b77f6600SCristian Dumitrescu 	thread_msg_free(rsp);
295b77f6600SCristian Dumitrescu 
296b77f6600SCristian Dumitrescu 	/* Request completion */
297b77f6600SCristian Dumitrescu 	if (status)
298b77f6600SCristian Dumitrescu 		return status;
299b77f6600SCristian Dumitrescu 
300b77f6600SCristian Dumitrescu 	p->thread_id = thread_id;
301b77f6600SCristian Dumitrescu 	p->enabled = 1;
302b77f6600SCristian Dumitrescu 
303b77f6600SCristian Dumitrescu 	return 0;
304b77f6600SCristian Dumitrescu }
305b77f6600SCristian Dumitrescu 
306b77f6600SCristian Dumitrescu int
307b77f6600SCristian Dumitrescu thread_pipeline_disable(uint32_t thread_id,
308b77f6600SCristian Dumitrescu 	struct obj *obj,
309b77f6600SCristian Dumitrescu 	const char *pipeline_name)
310b77f6600SCristian Dumitrescu {
311b77f6600SCristian Dumitrescu 	struct pipeline *p = pipeline_find(obj, pipeline_name);
312b77f6600SCristian Dumitrescu 	struct thread *t;
313b77f6600SCristian Dumitrescu 	struct thread_msg_req *req;
314b77f6600SCristian Dumitrescu 	struct thread_msg_rsp *rsp;
315b77f6600SCristian Dumitrescu 	int status;
316b77f6600SCristian Dumitrescu 
317b77f6600SCristian Dumitrescu 	/* Check input params */
318b77f6600SCristian Dumitrescu 	if ((thread_id >= RTE_MAX_LCORE) ||
319b77f6600SCristian Dumitrescu 		(p == NULL))
320b77f6600SCristian Dumitrescu 		return -1;
321b77f6600SCristian Dumitrescu 
322b77f6600SCristian Dumitrescu 	t = &thread[thread_id];
323b77f6600SCristian Dumitrescu 	if (t->enabled == 0)
324b77f6600SCristian Dumitrescu 		return -1;
325b77f6600SCristian Dumitrescu 
326b77f6600SCristian Dumitrescu 	if (p->enabled == 0)
327b77f6600SCristian Dumitrescu 		return 0;
328b77f6600SCristian Dumitrescu 
329b77f6600SCristian Dumitrescu 	if (p->thread_id != thread_id)
330b77f6600SCristian Dumitrescu 		return -1;
331b77f6600SCristian Dumitrescu 
332b77f6600SCristian Dumitrescu 	if (!thread_is_running(thread_id)) {
333b77f6600SCristian Dumitrescu 		struct thread_data *td = &thread_data[thread_id];
334b77f6600SCristian Dumitrescu 		uint32_t i;
335b77f6600SCristian Dumitrescu 
336b77f6600SCristian Dumitrescu 		for (i = 0; i < td->n_pipelines; i++) {
337b77f6600SCristian Dumitrescu 			struct pipeline_data *tdp = &td->pipeline_data[i];
338b77f6600SCristian Dumitrescu 
339b77f6600SCristian Dumitrescu 			if (tdp->p != p->p)
340b77f6600SCristian Dumitrescu 				continue;
341b77f6600SCristian Dumitrescu 
342b77f6600SCristian Dumitrescu 			/* Data plane thread */
343b77f6600SCristian Dumitrescu 			if (i < td->n_pipelines - 1) {
344b77f6600SCristian Dumitrescu 				struct rte_swx_pipeline *pipeline_last =
345b77f6600SCristian Dumitrescu 					td->p[td->n_pipelines - 1];
346b77f6600SCristian Dumitrescu 				struct pipeline_data *tdp_last =
347b77f6600SCristian Dumitrescu 					&td->pipeline_data[td->n_pipelines - 1];
348b77f6600SCristian Dumitrescu 
349b77f6600SCristian Dumitrescu 				td->p[i] = pipeline_last;
350b77f6600SCristian Dumitrescu 				memcpy(tdp, tdp_last, sizeof(*tdp));
351b77f6600SCristian Dumitrescu 			}
352b77f6600SCristian Dumitrescu 
353b77f6600SCristian Dumitrescu 			td->n_pipelines--;
354b77f6600SCristian Dumitrescu 
355b77f6600SCristian Dumitrescu 			/* Pipeline */
356b77f6600SCristian Dumitrescu 			p->enabled = 0;
357b77f6600SCristian Dumitrescu 
358b77f6600SCristian Dumitrescu 			break;
359b77f6600SCristian Dumitrescu 		}
360b77f6600SCristian Dumitrescu 
361b77f6600SCristian Dumitrescu 		return 0;
362b77f6600SCristian Dumitrescu 	}
363b77f6600SCristian Dumitrescu 
364b77f6600SCristian Dumitrescu 	/* Allocate request */
365b77f6600SCristian Dumitrescu 	req = thread_msg_alloc();
366b77f6600SCristian Dumitrescu 	if (req == NULL)
367b77f6600SCristian Dumitrescu 		return -1;
368b77f6600SCristian Dumitrescu 
369b77f6600SCristian Dumitrescu 	/* Write request */
370b77f6600SCristian Dumitrescu 	req->type = THREAD_REQ_PIPELINE_DISABLE;
371b77f6600SCristian Dumitrescu 	req->pipeline_disable.p = p->p;
372b77f6600SCristian Dumitrescu 
373b77f6600SCristian Dumitrescu 	/* Send request and wait for response */
374b77f6600SCristian Dumitrescu 	rsp = thread_msg_send_recv(thread_id, req);
375b77f6600SCristian Dumitrescu 
376b77f6600SCristian Dumitrescu 	/* Read response */
377b77f6600SCristian Dumitrescu 	status = rsp->status;
378b77f6600SCristian Dumitrescu 
379b77f6600SCristian Dumitrescu 	/* Free response */
380b77f6600SCristian Dumitrescu 	thread_msg_free(rsp);
381b77f6600SCristian Dumitrescu 
382b77f6600SCristian Dumitrescu 	/* Request completion */
383b77f6600SCristian Dumitrescu 	if (status)
384b77f6600SCristian Dumitrescu 		return status;
385b77f6600SCristian Dumitrescu 
386b77f6600SCristian Dumitrescu 	p->enabled = 0;
387b77f6600SCristian Dumitrescu 
388b77f6600SCristian Dumitrescu 	return 0;
389b77f6600SCristian Dumitrescu }
390b77f6600SCristian Dumitrescu 
391b77f6600SCristian Dumitrescu /**
392b77f6600SCristian Dumitrescu  * Data plane threads: message handling
393b77f6600SCristian Dumitrescu  */
394b77f6600SCristian Dumitrescu static inline struct thread_msg_req *
395b77f6600SCristian Dumitrescu thread_msg_recv(struct rte_ring *msgq_req)
396b77f6600SCristian Dumitrescu {
397b77f6600SCristian Dumitrescu 	struct thread_msg_req *req;
398b77f6600SCristian Dumitrescu 
399b77f6600SCristian Dumitrescu 	int status = rte_ring_sc_dequeue(msgq_req, (void **) &req);
400b77f6600SCristian Dumitrescu 
401b77f6600SCristian Dumitrescu 	if (status != 0)
402b77f6600SCristian Dumitrescu 		return NULL;
403b77f6600SCristian Dumitrescu 
404b77f6600SCristian Dumitrescu 	return req;
405b77f6600SCristian Dumitrescu }
406b77f6600SCristian Dumitrescu 
407b77f6600SCristian Dumitrescu static inline void
408b77f6600SCristian Dumitrescu thread_msg_send(struct rte_ring *msgq_rsp,
409b77f6600SCristian Dumitrescu 	struct thread_msg_rsp *rsp)
410b77f6600SCristian Dumitrescu {
411b77f6600SCristian Dumitrescu 	int status;
412b77f6600SCristian Dumitrescu 
413b77f6600SCristian Dumitrescu 	do {
414b77f6600SCristian Dumitrescu 		status = rte_ring_sp_enqueue(msgq_rsp, rsp);
415b77f6600SCristian Dumitrescu 	} while (status == -ENOBUFS);
416b77f6600SCristian Dumitrescu }
417b77f6600SCristian Dumitrescu 
418b77f6600SCristian Dumitrescu static struct thread_msg_rsp *
419b77f6600SCristian Dumitrescu thread_msg_handle_pipeline_enable(struct thread_data *t,
420b77f6600SCristian Dumitrescu 	struct thread_msg_req *req)
421b77f6600SCristian Dumitrescu {
422b77f6600SCristian Dumitrescu 	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
423b77f6600SCristian Dumitrescu 	struct pipeline_data *p = &t->pipeline_data[t->n_pipelines];
424b77f6600SCristian Dumitrescu 
425b77f6600SCristian Dumitrescu 	/* Request */
426b77f6600SCristian Dumitrescu 	if (t->n_pipelines >= THREAD_PIPELINES_MAX) {
427b77f6600SCristian Dumitrescu 		rsp->status = -1;
428b77f6600SCristian Dumitrescu 		return rsp;
429b77f6600SCristian Dumitrescu 	}
430b77f6600SCristian Dumitrescu 
431b77f6600SCristian Dumitrescu 	t->p[t->n_pipelines] = req->pipeline_enable.p;
432b77f6600SCristian Dumitrescu 
433b77f6600SCristian Dumitrescu 	p->p = req->pipeline_enable.p;
434b77f6600SCristian Dumitrescu 	p->timer_period = (rte_get_tsc_hz() *
435b77f6600SCristian Dumitrescu 		req->pipeline_enable.timer_period_ms) / 1000;
436b77f6600SCristian Dumitrescu 	p->time_next = rte_get_tsc_cycles() + p->timer_period;
437b77f6600SCristian Dumitrescu 
438b77f6600SCristian Dumitrescu 	t->n_pipelines++;
439b77f6600SCristian Dumitrescu 
440b77f6600SCristian Dumitrescu 	/* Response */
441b77f6600SCristian Dumitrescu 	rsp->status = 0;
442b77f6600SCristian Dumitrescu 	return rsp;
443b77f6600SCristian Dumitrescu }
444b77f6600SCristian Dumitrescu 
445b77f6600SCristian Dumitrescu static struct thread_msg_rsp *
446b77f6600SCristian Dumitrescu thread_msg_handle_pipeline_disable(struct thread_data *t,
447b77f6600SCristian Dumitrescu 	struct thread_msg_req *req)
448b77f6600SCristian Dumitrescu {
449b77f6600SCristian Dumitrescu 	struct thread_msg_rsp *rsp = (struct thread_msg_rsp *) req;
450b77f6600SCristian Dumitrescu 	uint32_t n_pipelines = t->n_pipelines;
451b77f6600SCristian Dumitrescu 	struct rte_swx_pipeline *pipeline = req->pipeline_disable.p;
452b77f6600SCristian Dumitrescu 	uint32_t i;
453b77f6600SCristian Dumitrescu 
454b77f6600SCristian Dumitrescu 	/* find pipeline */
455b77f6600SCristian Dumitrescu 	for (i = 0; i < n_pipelines; i++) {
456b77f6600SCristian Dumitrescu 		struct pipeline_data *p = &t->pipeline_data[i];
457b77f6600SCristian Dumitrescu 
458b77f6600SCristian Dumitrescu 		if (p->p != pipeline)
459b77f6600SCristian Dumitrescu 			continue;
460b77f6600SCristian Dumitrescu 
461b77f6600SCristian Dumitrescu 		if (i < n_pipelines - 1) {
462b77f6600SCristian Dumitrescu 			struct rte_swx_pipeline *pipeline_last =
463b77f6600SCristian Dumitrescu 				t->p[n_pipelines - 1];
464b77f6600SCristian Dumitrescu 			struct pipeline_data *p_last =
465b77f6600SCristian Dumitrescu 				&t->pipeline_data[n_pipelines - 1];
466b77f6600SCristian Dumitrescu 
467b77f6600SCristian Dumitrescu 			t->p[i] = pipeline_last;
468b77f6600SCristian Dumitrescu 			memcpy(p, p_last, sizeof(*p));
469b77f6600SCristian Dumitrescu 		}
470b77f6600SCristian Dumitrescu 
471b77f6600SCristian Dumitrescu 		t->n_pipelines--;
472b77f6600SCristian Dumitrescu 
473b77f6600SCristian Dumitrescu 		rsp->status = 0;
474b77f6600SCristian Dumitrescu 		return rsp;
475b77f6600SCristian Dumitrescu 	}
476b77f6600SCristian Dumitrescu 
477b77f6600SCristian Dumitrescu 	/* should not get here */
478b77f6600SCristian Dumitrescu 	rsp->status = 0;
479b77f6600SCristian Dumitrescu 	return rsp;
480b77f6600SCristian Dumitrescu }
481b77f6600SCristian Dumitrescu 
482b77f6600SCristian Dumitrescu static void
483b77f6600SCristian Dumitrescu thread_msg_handle(struct thread_data *t)
484b77f6600SCristian Dumitrescu {
485b77f6600SCristian Dumitrescu 	for ( ; ; ) {
486b77f6600SCristian Dumitrescu 		struct thread_msg_req *req;
487b77f6600SCristian Dumitrescu 		struct thread_msg_rsp *rsp;
488b77f6600SCristian Dumitrescu 
489b77f6600SCristian Dumitrescu 		req = thread_msg_recv(t->msgq_req);
490b77f6600SCristian Dumitrescu 		if (req == NULL)
491b77f6600SCristian Dumitrescu 			break;
492b77f6600SCristian Dumitrescu 
493b77f6600SCristian Dumitrescu 		switch (req->type) {
494b77f6600SCristian Dumitrescu 		case THREAD_REQ_PIPELINE_ENABLE:
495b77f6600SCristian Dumitrescu 			rsp = thread_msg_handle_pipeline_enable(t, req);
496b77f6600SCristian Dumitrescu 			break;
497b77f6600SCristian Dumitrescu 
498b77f6600SCristian Dumitrescu 		case THREAD_REQ_PIPELINE_DISABLE:
499b77f6600SCristian Dumitrescu 			rsp = thread_msg_handle_pipeline_disable(t, req);
500b77f6600SCristian Dumitrescu 			break;
501b77f6600SCristian Dumitrescu 
502b77f6600SCristian Dumitrescu 		default:
503b77f6600SCristian Dumitrescu 			rsp = (struct thread_msg_rsp *) req;
504b77f6600SCristian Dumitrescu 			rsp->status = -1;
505b77f6600SCristian Dumitrescu 		}
506b77f6600SCristian Dumitrescu 
507b77f6600SCristian Dumitrescu 		thread_msg_send(t->msgq_rsp, rsp);
508b77f6600SCristian Dumitrescu 	}
509b77f6600SCristian Dumitrescu }
510b77f6600SCristian Dumitrescu 
511b77f6600SCristian Dumitrescu /**
512b77f6600SCristian Dumitrescu  * Data plane threads: main
513b77f6600SCristian Dumitrescu  */
514b77f6600SCristian Dumitrescu int
515b77f6600SCristian Dumitrescu thread_main(void *arg __rte_unused)
516b77f6600SCristian Dumitrescu {
517b77f6600SCristian Dumitrescu 	struct thread_data *t;
518b77f6600SCristian Dumitrescu 	uint32_t thread_id, i;
519b77f6600SCristian Dumitrescu 
520b77f6600SCristian Dumitrescu 	thread_id = rte_lcore_id();
521b77f6600SCristian Dumitrescu 	t = &thread_data[thread_id];
522b77f6600SCristian Dumitrescu 
523b77f6600SCristian Dumitrescu 	/* Dispatch loop */
524b77f6600SCristian Dumitrescu 	for (i = 0; ; i++) {
525b77f6600SCristian Dumitrescu 		uint32_t j;
526b77f6600SCristian Dumitrescu 
527b77f6600SCristian Dumitrescu 		/* Data Plane */
528b77f6600SCristian Dumitrescu 		for (j = 0; j < t->n_pipelines; j++)
529*0b50ea60SCristian Dumitrescu 			rte_swx_pipeline_run(t->p[j], PIPELINE_INSTR_QUANTA);
530b77f6600SCristian Dumitrescu 
531b77f6600SCristian Dumitrescu 		/* Control Plane */
532b77f6600SCristian Dumitrescu 		if ((i & 0xF) == 0) {
533b77f6600SCristian Dumitrescu 			uint64_t time = rte_get_tsc_cycles();
534b77f6600SCristian Dumitrescu 			uint64_t time_next_min = UINT64_MAX;
535b77f6600SCristian Dumitrescu 
536b77f6600SCristian Dumitrescu 			if (time < t->time_next_min)
537b77f6600SCristian Dumitrescu 				continue;
538b77f6600SCristian Dumitrescu 
539b77f6600SCristian Dumitrescu 			/* Thread message queues */
540b77f6600SCristian Dumitrescu 			{
541b77f6600SCristian Dumitrescu 				uint64_t time_next = t->time_next;
542b77f6600SCristian Dumitrescu 
543b77f6600SCristian Dumitrescu 				if (time_next <= time) {
544b77f6600SCristian Dumitrescu 					thread_msg_handle(t);
545b77f6600SCristian Dumitrescu 					time_next = time + t->timer_period;
546b77f6600SCristian Dumitrescu 					t->time_next = time_next;
547b77f6600SCristian Dumitrescu 				}
548b77f6600SCristian Dumitrescu 
549b77f6600SCristian Dumitrescu 				if (time_next < time_next_min)
550b77f6600SCristian Dumitrescu 					time_next_min = time_next;
551b77f6600SCristian Dumitrescu 			}
552b77f6600SCristian Dumitrescu 
553b77f6600SCristian Dumitrescu 			t->time_next_min = time_next_min;
554b77f6600SCristian Dumitrescu 		}
555b77f6600SCristian Dumitrescu 	}
556b77f6600SCristian Dumitrescu 
557b77f6600SCristian Dumitrescu 	return 0;
558b77f6600SCristian Dumitrescu }
559