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