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