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