1b77f6600SCristian Dumitrescu /* SPDX-License-Identifier: BSD-3-Clause
2b77f6600SCristian Dumitrescu * Copyright(c) 2020 Intel Corporation
3b77f6600SCristian Dumitrescu */
4b77f6600SCristian Dumitrescu
5b77f6600SCristian Dumitrescu #include <stdlib.h>
641f5dfcbSCristian Dumitrescu #include <errno.h>
7b77f6600SCristian Dumitrescu
841f5dfcbSCristian Dumitrescu #include <rte_atomic.h>
9b77f6600SCristian Dumitrescu #include <rte_common.h>
10b77f6600SCristian Dumitrescu #include <rte_lcore.h>
11b77f6600SCristian Dumitrescu
12b77f6600SCristian Dumitrescu #include "obj.h"
13b77f6600SCristian Dumitrescu #include "thread.h"
14b77f6600SCristian Dumitrescu
15b77f6600SCristian Dumitrescu #ifndef THREAD_PIPELINES_MAX
16b77f6600SCristian Dumitrescu #define THREAD_PIPELINES_MAX 256
17b77f6600SCristian Dumitrescu #endif
18b77f6600SCristian Dumitrescu
19ce5d73a9SCristian Dumitrescu #ifndef THREAD_BLOCKS_MAX
20ce5d73a9SCristian Dumitrescu #define THREAD_BLOCKS_MAX 256
21ce5d73a9SCristian Dumitrescu #endif
22ce5d73a9SCristian Dumitrescu
230b50ea60SCristian Dumitrescu /* Pipeline instruction quanta: Needs to be big enough to do some meaningful
240b50ea60SCristian Dumitrescu * work, but not too big to avoid starving any other pipelines mapped to the
250b50ea60SCristian Dumitrescu * same thread. For a pipeline that executes 10 instructions per packet, a
260b50ea60SCristian Dumitrescu * quanta of 1000 instructions equates to processing 100 packets.
270b50ea60SCristian Dumitrescu */
280b50ea60SCristian Dumitrescu #ifndef PIPELINE_INSTR_QUANTA
290b50ea60SCristian Dumitrescu #define PIPELINE_INSTR_QUANTA 1000
300b50ea60SCristian Dumitrescu #endif
310b50ea60SCristian Dumitrescu
32b77f6600SCristian Dumitrescu /**
3341f5dfcbSCristian Dumitrescu * In this design, there is a single control plane (CP) thread and one or multiple data plane (DP)
3441f5dfcbSCristian Dumitrescu * threads. Each DP thread can run up to THREAD_PIPELINES_MAX pipelines and up to THREAD_BLOCKS_MAX
3541f5dfcbSCristian Dumitrescu * blocks.
3641f5dfcbSCristian Dumitrescu *
3741f5dfcbSCristian Dumitrescu * The pipelines and blocks are single threaded, meaning that a given pipeline/block can be run by a
3841f5dfcbSCristian Dumitrescu * single thread at any given time, so the same pipeline/block cannot show up in the list of
3941f5dfcbSCristian Dumitrescu * pipelines/blocks of more than one thread at any specific moment.
4041f5dfcbSCristian Dumitrescu *
4141f5dfcbSCristian Dumitrescu * Each DP thread has its own context (struct thread instance), which it shares with the CP thread:
4241f5dfcbSCristian Dumitrescu * - Read-write by the CP thread;
4341f5dfcbSCristian Dumitrescu * - Read-only by the DP thread.
44b77f6600SCristian Dumitrescu */
45ce5d73a9SCristian Dumitrescu struct block {
46ce5d73a9SCristian Dumitrescu block_run_f block_func;
47ce5d73a9SCristian Dumitrescu void *block;
48ce5d73a9SCristian Dumitrescu };
49ce5d73a9SCristian Dumitrescu
50*7e06c0deSTyler Retzlaff struct __rte_cache_aligned thread {
5141f5dfcbSCristian Dumitrescu struct rte_swx_pipeline *pipelines[THREAD_PIPELINES_MAX];
52ce5d73a9SCristian Dumitrescu struct block *blocks[THREAD_BLOCKS_MAX];
5341f5dfcbSCristian Dumitrescu volatile uint64_t n_pipelines;
54ce5d73a9SCristian Dumitrescu volatile uint64_t n_blocks;
5541f5dfcbSCristian Dumitrescu int enabled;
56*7e06c0deSTyler Retzlaff };
57b77f6600SCristian Dumitrescu
5841f5dfcbSCristian Dumitrescu static struct thread threads[RTE_MAX_LCORE];
59b77f6600SCristian Dumitrescu
60b77f6600SCristian Dumitrescu /**
6141f5dfcbSCristian Dumitrescu * Control plane (CP) thread.
62b77f6600SCristian Dumitrescu */
63b77f6600SCristian Dumitrescu int
thread_init(void)64b77f6600SCristian Dumitrescu thread_init(void)
65b77f6600SCristian Dumitrescu {
6641f5dfcbSCristian Dumitrescu uint32_t thread_id;
67ce5d73a9SCristian Dumitrescu int status = 0;
68b77f6600SCristian Dumitrescu
6941f5dfcbSCristian Dumitrescu RTE_LCORE_FOREACH_WORKER(thread_id) {
7041f5dfcbSCristian Dumitrescu struct thread *t = &threads[thread_id];
71ce5d73a9SCristian Dumitrescu uint32_t i;
72b77f6600SCristian Dumitrescu
73b77f6600SCristian Dumitrescu t->enabled = 1;
74ce5d73a9SCristian Dumitrescu
75ce5d73a9SCristian Dumitrescu for (i = 0; i < THREAD_BLOCKS_MAX; i++) {
76ce5d73a9SCristian Dumitrescu struct block *b;
77ce5d73a9SCristian Dumitrescu
78ce5d73a9SCristian Dumitrescu b = calloc(1, sizeof(struct block));
79ce5d73a9SCristian Dumitrescu if (!b) {
80ce5d73a9SCristian Dumitrescu status = -ENOMEM;
81ce5d73a9SCristian Dumitrescu goto error;
82ce5d73a9SCristian Dumitrescu }
83ce5d73a9SCristian Dumitrescu
84ce5d73a9SCristian Dumitrescu t->blocks[i] = b;
85ce5d73a9SCristian Dumitrescu }
86b77f6600SCristian Dumitrescu }
87b77f6600SCristian Dumitrescu
88b77f6600SCristian Dumitrescu return 0;
89ce5d73a9SCristian Dumitrescu
90ce5d73a9SCristian Dumitrescu error:
91ce5d73a9SCristian Dumitrescu RTE_LCORE_FOREACH_WORKER(thread_id) {
92ce5d73a9SCristian Dumitrescu struct thread *t = &threads[thread_id];
93ce5d73a9SCristian Dumitrescu uint32_t i;
94ce5d73a9SCristian Dumitrescu
95ce5d73a9SCristian Dumitrescu t->enabled = 0;
96ce5d73a9SCristian Dumitrescu
97ce5d73a9SCristian Dumitrescu for (i = 0; i < THREAD_BLOCKS_MAX; i++) {
98ce5d73a9SCristian Dumitrescu free(t->blocks[i]);
99ce5d73a9SCristian Dumitrescu t->blocks[i] = NULL;
100ce5d73a9SCristian Dumitrescu }
101ce5d73a9SCristian Dumitrescu }
102ce5d73a9SCristian Dumitrescu
103ce5d73a9SCristian Dumitrescu return status;
104b77f6600SCristian Dumitrescu }
105b77f6600SCristian Dumitrescu
10641f5dfcbSCristian Dumitrescu static uint32_t
pipeline_find(struct rte_swx_pipeline * p)10741f5dfcbSCristian Dumitrescu pipeline_find(struct rte_swx_pipeline *p)
108b77f6600SCristian Dumitrescu {
10941f5dfcbSCristian Dumitrescu uint32_t thread_id;
110b77f6600SCristian Dumitrescu
11141f5dfcbSCristian Dumitrescu for (thread_id = 0; thread_id < RTE_MAX_LCORE; thread_id++) {
11241f5dfcbSCristian Dumitrescu struct thread *t = &threads[thread_id];
113b9559f94SCristian Dumitrescu uint32_t i;
114b9559f94SCristian Dumitrescu
115b9559f94SCristian Dumitrescu if (!t->enabled)
116b77f6600SCristian Dumitrescu continue;
117b77f6600SCristian Dumitrescu
11841f5dfcbSCristian Dumitrescu for (i = 0; i < t->n_pipelines; i++)
11941f5dfcbSCristian Dumitrescu if (t->pipelines[i] == p)
120b77f6600SCristian Dumitrescu break;
121b77f6600SCristian Dumitrescu }
122b77f6600SCristian Dumitrescu
12341f5dfcbSCristian Dumitrescu return thread_id;
124b77f6600SCristian Dumitrescu }
125b77f6600SCristian Dumitrescu
126ce5d73a9SCristian Dumitrescu static uint32_t
block_find(void * b)127ce5d73a9SCristian Dumitrescu block_find(void *b)
128ce5d73a9SCristian Dumitrescu {
129ce5d73a9SCristian Dumitrescu uint32_t thread_id;
130ce5d73a9SCristian Dumitrescu
131ce5d73a9SCristian Dumitrescu for (thread_id = 0; thread_id < RTE_MAX_LCORE; thread_id++) {
132ce5d73a9SCristian Dumitrescu struct thread *t = &threads[thread_id];
133ce5d73a9SCristian Dumitrescu uint32_t i;
134ce5d73a9SCristian Dumitrescu
135ce5d73a9SCristian Dumitrescu if (!t->enabled)
136ce5d73a9SCristian Dumitrescu continue;
137ce5d73a9SCristian Dumitrescu
138ce5d73a9SCristian Dumitrescu for (i = 0; i < t->n_blocks; i++)
139ce5d73a9SCristian Dumitrescu if (t->blocks[i]->block == b)
140ce5d73a9SCristian Dumitrescu break;
141ce5d73a9SCristian Dumitrescu }
142ce5d73a9SCristian Dumitrescu
143ce5d73a9SCristian Dumitrescu return thread_id;
144ce5d73a9SCristian Dumitrescu }
145ce5d73a9SCristian Dumitrescu
14641f5dfcbSCristian Dumitrescu /**
14741f5dfcbSCristian Dumitrescu * Enable a given pipeline to run on a specific DP thread.
14841f5dfcbSCristian Dumitrescu *
14941f5dfcbSCristian Dumitrescu * CP thread:
15041f5dfcbSCristian Dumitrescu * - Adds a new pipeline to the end of the DP thread pipeline list (t->pipelines[]);
15141f5dfcbSCristian Dumitrescu * - Increments the DP thread number of pipelines (t->n_pipelines). It is important to make sure
15241f5dfcbSCristian Dumitrescu * that t->pipelines[] update is completed BEFORE the t->n_pipelines update, hence the memory
15341f5dfcbSCristian Dumitrescu * write barrier used below.
15441f5dfcbSCristian Dumitrescu *
15541f5dfcbSCristian Dumitrescu * DP thread:
15641f5dfcbSCristian Dumitrescu * - Reads t->n_pipelines before starting every new iteration through t->pipelines[]. It detects
15741f5dfcbSCristian Dumitrescu * the new pipeline when it sees the updated t->n_pipelines value;
15841f5dfcbSCristian Dumitrescu * - If somehow the above condition is not met, so t->n_pipelines update is incorrectly taking
15941f5dfcbSCristian Dumitrescu * place before the t->pipelines[] update is completed, then the DP thread will use an incorrect
16041f5dfcbSCristian Dumitrescu * handle for the new pipeline, which can result in memory corruption or segmentation fault.
16141f5dfcbSCristian Dumitrescu */
16241f5dfcbSCristian Dumitrescu int
pipeline_enable(struct rte_swx_pipeline * p,uint32_t thread_id)16341f5dfcbSCristian Dumitrescu pipeline_enable(struct rte_swx_pipeline *p, uint32_t thread_id)
16441f5dfcbSCristian Dumitrescu {
16541f5dfcbSCristian Dumitrescu struct thread *t;
16641f5dfcbSCristian Dumitrescu uint64_t n_pipelines;
167b77f6600SCristian Dumitrescu
16841f5dfcbSCristian Dumitrescu /* Check input params */
16941f5dfcbSCristian Dumitrescu if (!p || thread_id >= RTE_MAX_LCORE)
17041f5dfcbSCristian Dumitrescu return -EINVAL;
171b77f6600SCristian Dumitrescu
17241f5dfcbSCristian Dumitrescu if (pipeline_find(p) < RTE_MAX_LCORE)
17341f5dfcbSCristian Dumitrescu return -EEXIST;
174b77f6600SCristian Dumitrescu
17541f5dfcbSCristian Dumitrescu t = &threads[thread_id];
17641f5dfcbSCristian Dumitrescu if (!t->enabled)
17741f5dfcbSCristian Dumitrescu return -EINVAL;
178b77f6600SCristian Dumitrescu
17941f5dfcbSCristian Dumitrescu n_pipelines = t->n_pipelines;
180b77f6600SCristian Dumitrescu
18141f5dfcbSCristian Dumitrescu /* Check there is room for at least one more pipeline. */
18241f5dfcbSCristian Dumitrescu if (n_pipelines >= THREAD_PIPELINES_MAX)
18341f5dfcbSCristian Dumitrescu return -ENOSPC;
18441f5dfcbSCristian Dumitrescu
18541f5dfcbSCristian Dumitrescu /* Install the new pipeline. */
18641f5dfcbSCristian Dumitrescu t->pipelines[n_pipelines] = p;
18741f5dfcbSCristian Dumitrescu rte_wmb();
18841f5dfcbSCristian Dumitrescu t->n_pipelines = n_pipelines + 1;
189b77f6600SCristian Dumitrescu
190b77f6600SCristian Dumitrescu return 0;
191b77f6600SCristian Dumitrescu }
192b77f6600SCristian Dumitrescu
193b77f6600SCristian Dumitrescu /**
19441f5dfcbSCristian Dumitrescu * Disable a given pipeline from running on any DP thread.
19541f5dfcbSCristian Dumitrescu *
19641f5dfcbSCristian Dumitrescu * CP thread:
19741f5dfcbSCristian Dumitrescu * - Detects the thread that is running the given pipeline, if any;
19841f5dfcbSCristian Dumitrescu * - Writes the last pipeline handle (pipeline_last = t->pipelines[t->n_pipelines - 1]) on the
19941f5dfcbSCristian Dumitrescu * position of the pipeline to be disabled (t->pipelines[i] = pipeline_last) and decrements the
20041f5dfcbSCristian Dumitrescu * number of pipelines running on the current thread (t->n_pipelines--). This approach makes sure
20141f5dfcbSCristian Dumitrescu * that no holes with invalid locations are ever developed within the t->pipelines[] array.
20241f5dfcbSCristian Dumitrescu * - If the memory barrier below is present, then t->n_pipelines update is guaranteed to take place
20341f5dfcbSCristian Dumitrescu * after the t->pipelines[] update is completed. The possible DP thread behaviors are detailed
20441f5dfcbSCristian Dumitrescu * below, which are all valid:
20541f5dfcbSCristian Dumitrescu * - Not run the removed pipeline at all, run all the other pipelines (including pipeline_last)
20641f5dfcbSCristian Dumitrescu * exactly one time during the current dispatch loop iteration. This takes place when the DP
20741f5dfcbSCristian Dumitrescu * thread sees the final value of t->n_pipelines;
20841f5dfcbSCristian Dumitrescu * - Not run the removed pipeline at all, run all the other pipelines, except pipeline_last,
20941f5dfcbSCristian Dumitrescu * exactly one time and the pipeline_last exactly two times during the current dispatch loop
21041f5dfcbSCristian Dumitrescu * iteration. This takes place when the DP thread sees the initial value of t->n_pipelines.
21141f5dfcbSCristian Dumitrescu * - If the memory barrier below is not present, then the t->n_pipelines update may be reordered by
21241f5dfcbSCristian Dumitrescu * the CPU, so that it takes place before the t->pipelines[] update. The possible DP thread
21341f5dfcbSCristian Dumitrescu * behaviors are detailed below, which are all valid:
21441f5dfcbSCristian Dumitrescu * - Not run the removed pipeline at all, run all the other pipelines (including pipeline_last)
21541f5dfcbSCristian Dumitrescu * exactly one time during the current dispatch loop iteration. This takes place when the DP
21641f5dfcbSCristian Dumitrescu * thread sees the final values of the t->pipeline[] array;
21741f5dfcbSCristian Dumitrescu * - Run the removed pipeline one last time, run all the other pipelines exactly one time, with
21841f5dfcbSCristian Dumitrescu * the exception of the pipeline_last, which is not run during the current dispatch loop
21941f5dfcbSCristian Dumitrescu * iteration. This takes place when the DP thread sees the initial values of t->pipeline[].
22041f5dfcbSCristian Dumitrescu *
22141f5dfcbSCristian Dumitrescu * DP thread:
22241f5dfcbSCristian Dumitrescu * - Reads t->n_pipelines before starting every new iteration through t->pipelines[].
223b77f6600SCristian Dumitrescu */
22441f5dfcbSCristian Dumitrescu void
pipeline_disable(struct rte_swx_pipeline * p)22541f5dfcbSCristian Dumitrescu pipeline_disable(struct rte_swx_pipeline *p)
226b77f6600SCristian Dumitrescu {
22741f5dfcbSCristian Dumitrescu struct thread *t;
22841f5dfcbSCristian Dumitrescu uint64_t n_pipelines;
22941f5dfcbSCristian Dumitrescu uint32_t thread_id, i;
230b77f6600SCristian Dumitrescu
23141f5dfcbSCristian Dumitrescu /* Check input params */
23241f5dfcbSCristian Dumitrescu if (!p)
23341f5dfcbSCristian Dumitrescu return;
234b77f6600SCristian Dumitrescu
23541f5dfcbSCristian Dumitrescu /* Find the thread that runs this pipeline. */
23641f5dfcbSCristian Dumitrescu thread_id = pipeline_find(p);
23741f5dfcbSCristian Dumitrescu if (thread_id == RTE_MAX_LCORE)
23841f5dfcbSCristian Dumitrescu return;
239b77f6600SCristian Dumitrescu
24041f5dfcbSCristian Dumitrescu t = &threads[thread_id];
24141f5dfcbSCristian Dumitrescu n_pipelines = t->n_pipelines;
242b77f6600SCristian Dumitrescu
243b77f6600SCristian Dumitrescu for (i = 0; i < n_pipelines; i++) {
24441f5dfcbSCristian Dumitrescu struct rte_swx_pipeline *pipeline = t->pipelines[i];
245b77f6600SCristian Dumitrescu
24641f5dfcbSCristian Dumitrescu if (pipeline != p)
247b77f6600SCristian Dumitrescu continue;
248b77f6600SCristian Dumitrescu
249b77f6600SCristian Dumitrescu if (i < n_pipelines - 1) {
25041f5dfcbSCristian Dumitrescu struct rte_swx_pipeline *pipeline_last = t->pipelines[n_pipelines - 1];
251b77f6600SCristian Dumitrescu
25241f5dfcbSCristian Dumitrescu t->pipelines[i] = pipeline_last;
253b77f6600SCristian Dumitrescu }
254b77f6600SCristian Dumitrescu
25541f5dfcbSCristian Dumitrescu rte_wmb();
25641f5dfcbSCristian Dumitrescu t->n_pipelines = n_pipelines - 1;
257b77f6600SCristian Dumitrescu
25841f5dfcbSCristian Dumitrescu return;
259b77f6600SCristian Dumitrescu }
260b77f6600SCristian Dumitrescu
26141f5dfcbSCristian Dumitrescu return;
262b77f6600SCristian Dumitrescu }
263b77f6600SCristian Dumitrescu
264ce5d73a9SCristian Dumitrescu int
block_enable(block_run_f block_func,void * block,uint32_t thread_id)265ce5d73a9SCristian Dumitrescu block_enable(block_run_f block_func, void *block, uint32_t thread_id)
266ce5d73a9SCristian Dumitrescu {
267ce5d73a9SCristian Dumitrescu struct thread *t;
268ce5d73a9SCristian Dumitrescu uint64_t n_blocks;
269ce5d73a9SCristian Dumitrescu
270ce5d73a9SCristian Dumitrescu /* Check input params */
271ce5d73a9SCristian Dumitrescu if (!block_func || !block || thread_id >= RTE_MAX_LCORE)
272ce5d73a9SCristian Dumitrescu return -EINVAL;
273ce5d73a9SCristian Dumitrescu
274ce5d73a9SCristian Dumitrescu if (block_find(block) < RTE_MAX_LCORE)
275ce5d73a9SCristian Dumitrescu return -EEXIST;
276ce5d73a9SCristian Dumitrescu
277ce5d73a9SCristian Dumitrescu t = &threads[thread_id];
278ce5d73a9SCristian Dumitrescu if (!t->enabled)
279ce5d73a9SCristian Dumitrescu return -EINVAL;
280ce5d73a9SCristian Dumitrescu
281ce5d73a9SCristian Dumitrescu n_blocks = t->n_blocks;
282ce5d73a9SCristian Dumitrescu
283ce5d73a9SCristian Dumitrescu /* Check there is room for at least one more block. */
284ce5d73a9SCristian Dumitrescu if (n_blocks >= THREAD_BLOCKS_MAX)
285ce5d73a9SCristian Dumitrescu return -ENOSPC;
286ce5d73a9SCristian Dumitrescu
287ce5d73a9SCristian Dumitrescu /* Install the new block. */
288ce5d73a9SCristian Dumitrescu t->blocks[n_blocks]->block_func = block_func;
289ce5d73a9SCristian Dumitrescu t->blocks[n_blocks]->block = block;
290ce5d73a9SCristian Dumitrescu
291ce5d73a9SCristian Dumitrescu rte_wmb();
292ce5d73a9SCristian Dumitrescu t->n_blocks = n_blocks + 1;
293ce5d73a9SCristian Dumitrescu
294ce5d73a9SCristian Dumitrescu return 0;
295ce5d73a9SCristian Dumitrescu }
296ce5d73a9SCristian Dumitrescu
297ce5d73a9SCristian Dumitrescu void
block_disable(void * block)298ce5d73a9SCristian Dumitrescu block_disable(void *block)
299ce5d73a9SCristian Dumitrescu {
300ce5d73a9SCristian Dumitrescu struct thread *t;
301ce5d73a9SCristian Dumitrescu uint64_t n_blocks;
302ce5d73a9SCristian Dumitrescu uint32_t thread_id, i;
303ce5d73a9SCristian Dumitrescu
304ce5d73a9SCristian Dumitrescu /* Check input params */
305ce5d73a9SCristian Dumitrescu if (!block)
306ce5d73a9SCristian Dumitrescu return;
307ce5d73a9SCristian Dumitrescu
308ce5d73a9SCristian Dumitrescu /* Find the thread that runs this block. */
309ce5d73a9SCristian Dumitrescu thread_id = block_find(block);
310ce5d73a9SCristian Dumitrescu if (thread_id == RTE_MAX_LCORE)
311ce5d73a9SCristian Dumitrescu return;
312ce5d73a9SCristian Dumitrescu
313ce5d73a9SCristian Dumitrescu t = &threads[thread_id];
314ce5d73a9SCristian Dumitrescu n_blocks = t->n_blocks;
315ce5d73a9SCristian Dumitrescu
316ce5d73a9SCristian Dumitrescu for (i = 0; i < n_blocks; i++) {
317ce5d73a9SCristian Dumitrescu struct block *b = t->blocks[i];
318ce5d73a9SCristian Dumitrescu
319ce5d73a9SCristian Dumitrescu if (block != b->block)
320ce5d73a9SCristian Dumitrescu continue;
321ce5d73a9SCristian Dumitrescu
322ce5d73a9SCristian Dumitrescu if (i < n_blocks - 1) {
323ce5d73a9SCristian Dumitrescu struct block *block_last = t->blocks[n_blocks - 1];
324ce5d73a9SCristian Dumitrescu
325ce5d73a9SCristian Dumitrescu t->blocks[i] = block_last;
326ce5d73a9SCristian Dumitrescu }
327ce5d73a9SCristian Dumitrescu
328ce5d73a9SCristian Dumitrescu rte_wmb();
329ce5d73a9SCristian Dumitrescu t->n_blocks = n_blocks - 1;
330ce5d73a9SCristian Dumitrescu
331ce5d73a9SCristian Dumitrescu rte_wmb();
332ce5d73a9SCristian Dumitrescu t->blocks[n_blocks - 1] = b;
333ce5d73a9SCristian Dumitrescu
334ce5d73a9SCristian Dumitrescu return;
335ce5d73a9SCristian Dumitrescu }
336ce5d73a9SCristian Dumitrescu }
337ce5d73a9SCristian Dumitrescu
338b77f6600SCristian Dumitrescu /**
33941f5dfcbSCristian Dumitrescu * Data plane (DP) threads.
34041f5dfcbSCristian Dumitrescu *
341ce5d73a9SCristian Dumitrescu
342ce5d73a9SCristian Dumitrescu
34341f5dfcbSCristian Dumitrescu * The t->n_pipelines variable is modified by the CP thread every time changes to the t->pipeline[]
34441f5dfcbSCristian Dumitrescu * array are operated, so it is therefore very important that the latest value of t->n_pipelines is
34541f5dfcbSCristian Dumitrescu * read by the DP thread at the beginning of every new dispatch loop iteration, otherwise a stale
34641f5dfcbSCristian Dumitrescu * t->n_pipelines value may result in new pipelines not being detected, running pipelines that have
34741f5dfcbSCristian Dumitrescu * been removed and are possibly no longer valid (e.g. when the pipeline_last is removed), running
34841f5dfcbSCristian Dumitrescu * one pipeline (pipeline_last) twice as frequently than the rest of the pipelines (e.g. when a
34941f5dfcbSCristian Dumitrescu * pipeline other than pipeline_last is removed), etc. This is the reason why t->n_pipelines is
35041f5dfcbSCristian Dumitrescu * marked as volatile.
351b77f6600SCristian Dumitrescu */
352b77f6600SCristian Dumitrescu int
thread_main(void * arg __rte_unused)353b77f6600SCristian Dumitrescu thread_main(void *arg __rte_unused)
354b77f6600SCristian Dumitrescu {
35541f5dfcbSCristian Dumitrescu struct thread *t;
35641f5dfcbSCristian Dumitrescu uint32_t thread_id;
357b77f6600SCristian Dumitrescu
358b77f6600SCristian Dumitrescu thread_id = rte_lcore_id();
35941f5dfcbSCristian Dumitrescu t = &threads[thread_id];
360b77f6600SCristian Dumitrescu
36141f5dfcbSCristian Dumitrescu /* Dispatch loop. */
36241f5dfcbSCristian Dumitrescu for ( ; ; ) {
36341f5dfcbSCristian Dumitrescu uint32_t i;
364b77f6600SCristian Dumitrescu
36541f5dfcbSCristian Dumitrescu /* Pipelines. */
36641f5dfcbSCristian Dumitrescu for (i = 0; i < t->n_pipelines; i++)
36741f5dfcbSCristian Dumitrescu rte_swx_pipeline_run(t->pipelines[i], PIPELINE_INSTR_QUANTA);
368ce5d73a9SCristian Dumitrescu
369ce5d73a9SCristian Dumitrescu /* Blocks. */
370ce5d73a9SCristian Dumitrescu for (i = 0; i < t->n_blocks; i++) {
371ce5d73a9SCristian Dumitrescu struct block *b = t->blocks[i];
372ce5d73a9SCristian Dumitrescu
373ce5d73a9SCristian Dumitrescu b->block_func(b->block);
374ce5d73a9SCristian Dumitrescu }
375b77f6600SCristian Dumitrescu }
376b77f6600SCristian Dumitrescu
377b77f6600SCristian Dumitrescu return 0;
378b77f6600SCristian Dumitrescu }
379