1*2d9fd380Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2*2d9fd380Sjfb8856606  * Copyright(C) 2020 Marvell International Ltd.
3*2d9fd380Sjfb8856606  */
4*2d9fd380Sjfb8856606 
5*2d9fd380Sjfb8856606 #ifndef _RTE_GRAPH_WORKER_H_
6*2d9fd380Sjfb8856606 #define _RTE_GRAPH_WORKER_H_
7*2d9fd380Sjfb8856606 
8*2d9fd380Sjfb8856606 /**
9*2d9fd380Sjfb8856606  * @file rte_graph_worker.h
10*2d9fd380Sjfb8856606  *
11*2d9fd380Sjfb8856606  * @warning
12*2d9fd380Sjfb8856606  * @b EXPERIMENTAL:
13*2d9fd380Sjfb8856606  * All functions in this file may be changed or removed without prior notice.
14*2d9fd380Sjfb8856606  *
15*2d9fd380Sjfb8856606  * This API allows a worker thread to walk over a graph and nodes to create,
16*2d9fd380Sjfb8856606  * process, enqueue and move streams of objects to the next nodes.
17*2d9fd380Sjfb8856606  */
18*2d9fd380Sjfb8856606 
19*2d9fd380Sjfb8856606 #include <rte_common.h>
20*2d9fd380Sjfb8856606 #include <rte_cycles.h>
21*2d9fd380Sjfb8856606 #include <rte_prefetch.h>
22*2d9fd380Sjfb8856606 #include <rte_memcpy.h>
23*2d9fd380Sjfb8856606 #include <rte_memory.h>
24*2d9fd380Sjfb8856606 
25*2d9fd380Sjfb8856606 #include "rte_graph.h"
26*2d9fd380Sjfb8856606 
27*2d9fd380Sjfb8856606 #ifdef __cplusplus
28*2d9fd380Sjfb8856606 extern "C" {
29*2d9fd380Sjfb8856606 #endif
30*2d9fd380Sjfb8856606 
31*2d9fd380Sjfb8856606 /**
32*2d9fd380Sjfb8856606  * @internal
33*2d9fd380Sjfb8856606  *
34*2d9fd380Sjfb8856606  * Data structure to hold graph data.
35*2d9fd380Sjfb8856606  */
36*2d9fd380Sjfb8856606 struct rte_graph {
37*2d9fd380Sjfb8856606 	uint32_t tail;		     /**< Tail of circular buffer. */
38*2d9fd380Sjfb8856606 	uint32_t head;		     /**< Head of circular buffer. */
39*2d9fd380Sjfb8856606 	uint32_t cir_mask;	     /**< Circular buffer wrap around mask. */
40*2d9fd380Sjfb8856606 	rte_node_t nb_nodes;	     /**< Number of nodes in the graph. */
41*2d9fd380Sjfb8856606 	rte_graph_off_t *cir_start;  /**< Pointer to circular buffer. */
42*2d9fd380Sjfb8856606 	rte_graph_off_t nodes_start; /**< Offset at which node memory starts. */
43*2d9fd380Sjfb8856606 	rte_graph_t id;	/**< Graph identifier. */
44*2d9fd380Sjfb8856606 	int socket;	/**< Socket ID where memory is allocated. */
45*2d9fd380Sjfb8856606 	char name[RTE_GRAPH_NAMESIZE];	/**< Name of the graph. */
46*2d9fd380Sjfb8856606 	uint64_t fence;			/**< Fence. */
47*2d9fd380Sjfb8856606 } __rte_cache_aligned;
48*2d9fd380Sjfb8856606 
49*2d9fd380Sjfb8856606 /**
50*2d9fd380Sjfb8856606  * @internal
51*2d9fd380Sjfb8856606  *
52*2d9fd380Sjfb8856606  * Data structure to hold node data.
53*2d9fd380Sjfb8856606  */
54*2d9fd380Sjfb8856606 struct rte_node {
55*2d9fd380Sjfb8856606 	/* Slow path area  */
56*2d9fd380Sjfb8856606 	uint64_t fence;		/**< Fence. */
57*2d9fd380Sjfb8856606 	rte_graph_off_t next;	/**< Index to next node. */
58*2d9fd380Sjfb8856606 	rte_node_t id;		/**< Node identifier. */
59*2d9fd380Sjfb8856606 	rte_node_t parent_id;	/**< Parent Node identifier. */
60*2d9fd380Sjfb8856606 	rte_edge_t nb_edges;	/**< Number of edges from this node. */
61*2d9fd380Sjfb8856606 	uint32_t realloc_count;	/**< Number of times realloced. */
62*2d9fd380Sjfb8856606 
63*2d9fd380Sjfb8856606 	char parent[RTE_NODE_NAMESIZE];	/**< Parent node name. */
64*2d9fd380Sjfb8856606 	char name[RTE_NODE_NAMESIZE];	/**< Name of the node. */
65*2d9fd380Sjfb8856606 
66*2d9fd380Sjfb8856606 	/* Fast path area  */
67*2d9fd380Sjfb8856606 #define RTE_NODE_CTX_SZ 16
68*2d9fd380Sjfb8856606 	uint8_t ctx[RTE_NODE_CTX_SZ] __rte_cache_aligned; /**< Node Context. */
69*2d9fd380Sjfb8856606 	uint16_t size;		/**< Total number of objects available. */
70*2d9fd380Sjfb8856606 	uint16_t idx;		/**< Number of objects used. */
71*2d9fd380Sjfb8856606 	rte_graph_off_t off;	/**< Offset of node in the graph reel. */
72*2d9fd380Sjfb8856606 	uint64_t total_cycles;	/**< Cycles spent in this node. */
73*2d9fd380Sjfb8856606 	uint64_t total_calls;	/**< Calls done to this node. */
74*2d9fd380Sjfb8856606 	uint64_t total_objs;	/**< Objects processed by this node. */
75*2d9fd380Sjfb8856606 	RTE_STD_C11
76*2d9fd380Sjfb8856606 		union {
77*2d9fd380Sjfb8856606 			void **objs;	   /**< Array of object pointers. */
78*2d9fd380Sjfb8856606 			uint64_t objs_u64;
79*2d9fd380Sjfb8856606 		};
80*2d9fd380Sjfb8856606 	RTE_STD_C11
81*2d9fd380Sjfb8856606 		union {
82*2d9fd380Sjfb8856606 			rte_node_process_t process; /**< Process function. */
83*2d9fd380Sjfb8856606 			uint64_t process_u64;
84*2d9fd380Sjfb8856606 		};
85*2d9fd380Sjfb8856606 	struct rte_node *nodes[] __rte_cache_min_aligned; /**< Next nodes. */
86*2d9fd380Sjfb8856606 } __rte_cache_aligned;
87*2d9fd380Sjfb8856606 
88*2d9fd380Sjfb8856606 /**
89*2d9fd380Sjfb8856606  * @internal
90*2d9fd380Sjfb8856606  *
91*2d9fd380Sjfb8856606  * Allocate a stream of objects.
92*2d9fd380Sjfb8856606  *
93*2d9fd380Sjfb8856606  * If stream already exists then re-allocate it to a larger size.
94*2d9fd380Sjfb8856606  *
95*2d9fd380Sjfb8856606  * @param graph
96*2d9fd380Sjfb8856606  *   Pointer to the graph object.
97*2d9fd380Sjfb8856606  * @param node
98*2d9fd380Sjfb8856606  *   Pointer to the node object.
99*2d9fd380Sjfb8856606  */
100*2d9fd380Sjfb8856606 __rte_experimental
101*2d9fd380Sjfb8856606 void __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node);
102*2d9fd380Sjfb8856606 
103*2d9fd380Sjfb8856606 /**
104*2d9fd380Sjfb8856606  * @internal
105*2d9fd380Sjfb8856606  *
106*2d9fd380Sjfb8856606  * Allocate a stream with requested number of objects.
107*2d9fd380Sjfb8856606  *
108*2d9fd380Sjfb8856606  * If stream already exists then re-allocate it to a larger size.
109*2d9fd380Sjfb8856606  *
110*2d9fd380Sjfb8856606  * @param graph
111*2d9fd380Sjfb8856606  *   Pointer to the graph object.
112*2d9fd380Sjfb8856606  * @param node
113*2d9fd380Sjfb8856606  *   Pointer to the node object.
114*2d9fd380Sjfb8856606  * @param req_size
115*2d9fd380Sjfb8856606  *   Number of objects to be allocated.
116*2d9fd380Sjfb8856606  */
117*2d9fd380Sjfb8856606 __rte_experimental
118*2d9fd380Sjfb8856606 void __rte_node_stream_alloc_size(struct rte_graph *graph,
119*2d9fd380Sjfb8856606 				  struct rte_node *node, uint16_t req_size);
120*2d9fd380Sjfb8856606 
121*2d9fd380Sjfb8856606 /**
122*2d9fd380Sjfb8856606  * Perform graph walk on the circular buffer and invoke the process function
123*2d9fd380Sjfb8856606  * of the nodes and collect the stats.
124*2d9fd380Sjfb8856606  *
125*2d9fd380Sjfb8856606  * @param graph
126*2d9fd380Sjfb8856606  *   Graph pointer returned from rte_graph_lookup function.
127*2d9fd380Sjfb8856606  *
128*2d9fd380Sjfb8856606  * @see rte_graph_lookup()
129*2d9fd380Sjfb8856606  */
130*2d9fd380Sjfb8856606 __rte_experimental
131*2d9fd380Sjfb8856606 static inline void
rte_graph_walk(struct rte_graph * graph)132*2d9fd380Sjfb8856606 rte_graph_walk(struct rte_graph *graph)
133*2d9fd380Sjfb8856606 {
134*2d9fd380Sjfb8856606 	const rte_graph_off_t *cir_start = graph->cir_start;
135*2d9fd380Sjfb8856606 	const rte_node_t mask = graph->cir_mask;
136*2d9fd380Sjfb8856606 	uint32_t head = graph->head;
137*2d9fd380Sjfb8856606 	struct rte_node *node;
138*2d9fd380Sjfb8856606 	uint64_t start;
139*2d9fd380Sjfb8856606 	uint16_t rc;
140*2d9fd380Sjfb8856606 	void **objs;
141*2d9fd380Sjfb8856606 
142*2d9fd380Sjfb8856606 	/*
143*2d9fd380Sjfb8856606 	 * Walk on the source node(s) ((cir_start - head) -> cir_start) and then
144*2d9fd380Sjfb8856606 	 * on the pending streams (cir_start -> (cir_start + mask) -> cir_start)
145*2d9fd380Sjfb8856606 	 * in a circular buffer fashion.
146*2d9fd380Sjfb8856606 	 *
147*2d9fd380Sjfb8856606 	 *	+-----+ <= cir_start - head [number of source nodes]
148*2d9fd380Sjfb8856606 	 *	|     |
149*2d9fd380Sjfb8856606 	 *	| ... | <= source nodes
150*2d9fd380Sjfb8856606 	 *	|     |
151*2d9fd380Sjfb8856606 	 *	+-----+ <= cir_start [head = 0] [tail = 0]
152*2d9fd380Sjfb8856606 	 *	|     |
153*2d9fd380Sjfb8856606 	 *	| ... | <= pending streams
154*2d9fd380Sjfb8856606 	 *	|     |
155*2d9fd380Sjfb8856606 	 *	+-----+ <= cir_start + mask
156*2d9fd380Sjfb8856606 	 */
157*2d9fd380Sjfb8856606 	while (likely(head != graph->tail)) {
158*2d9fd380Sjfb8856606 		node = RTE_PTR_ADD(graph, cir_start[(int32_t)head++]);
159*2d9fd380Sjfb8856606 		RTE_ASSERT(node->fence == RTE_GRAPH_FENCE);
160*2d9fd380Sjfb8856606 		objs = node->objs;
161*2d9fd380Sjfb8856606 		rte_prefetch0(objs);
162*2d9fd380Sjfb8856606 
163*2d9fd380Sjfb8856606 		if (rte_graph_has_stats_feature()) {
164*2d9fd380Sjfb8856606 			start = rte_rdtsc();
165*2d9fd380Sjfb8856606 			rc = node->process(graph, node, objs, node->idx);
166*2d9fd380Sjfb8856606 			node->total_cycles += rte_rdtsc() - start;
167*2d9fd380Sjfb8856606 			node->total_calls++;
168*2d9fd380Sjfb8856606 			node->total_objs += rc;
169*2d9fd380Sjfb8856606 		} else {
170*2d9fd380Sjfb8856606 			node->process(graph, node, objs, node->idx);
171*2d9fd380Sjfb8856606 		}
172*2d9fd380Sjfb8856606 		node->idx = 0;
173*2d9fd380Sjfb8856606 		head = likely((int32_t)head > 0) ? head & mask : head;
174*2d9fd380Sjfb8856606 	}
175*2d9fd380Sjfb8856606 	graph->tail = 0;
176*2d9fd380Sjfb8856606 }
177*2d9fd380Sjfb8856606 
178*2d9fd380Sjfb8856606 /* Fast path helper functions */
179*2d9fd380Sjfb8856606 
180*2d9fd380Sjfb8856606 /**
181*2d9fd380Sjfb8856606  * @internal
182*2d9fd380Sjfb8856606  *
183*2d9fd380Sjfb8856606  * Enqueue a given node to the tail of the graph reel.
184*2d9fd380Sjfb8856606  *
185*2d9fd380Sjfb8856606  * @param graph
186*2d9fd380Sjfb8856606  *   Pointer Graph object.
187*2d9fd380Sjfb8856606  * @param node
188*2d9fd380Sjfb8856606  *   Pointer to node object to be enqueued.
189*2d9fd380Sjfb8856606  */
190*2d9fd380Sjfb8856606 static __rte_always_inline void
__rte_node_enqueue_tail_update(struct rte_graph * graph,struct rte_node * node)191*2d9fd380Sjfb8856606 __rte_node_enqueue_tail_update(struct rte_graph *graph, struct rte_node *node)
192*2d9fd380Sjfb8856606 {
193*2d9fd380Sjfb8856606 	uint32_t tail;
194*2d9fd380Sjfb8856606 
195*2d9fd380Sjfb8856606 	tail = graph->tail;
196*2d9fd380Sjfb8856606 	graph->cir_start[tail++] = node->off;
197*2d9fd380Sjfb8856606 	graph->tail = tail & graph->cir_mask;
198*2d9fd380Sjfb8856606 }
199*2d9fd380Sjfb8856606 
200*2d9fd380Sjfb8856606 /**
201*2d9fd380Sjfb8856606  * @internal
202*2d9fd380Sjfb8856606  *
203*2d9fd380Sjfb8856606  * Enqueue sequence prologue function.
204*2d9fd380Sjfb8856606  *
205*2d9fd380Sjfb8856606  * Updates the node to tail of graph reel and resizes the number of objects
206*2d9fd380Sjfb8856606  * available in the stream as needed.
207*2d9fd380Sjfb8856606  *
208*2d9fd380Sjfb8856606  * @param graph
209*2d9fd380Sjfb8856606  *   Pointer to the graph object.
210*2d9fd380Sjfb8856606  * @param node
211*2d9fd380Sjfb8856606  *   Pointer to the node object.
212*2d9fd380Sjfb8856606  * @param idx
213*2d9fd380Sjfb8856606  *   Index at which the object enqueue starts from.
214*2d9fd380Sjfb8856606  * @param space
215*2d9fd380Sjfb8856606  *   Space required for the object enqueue.
216*2d9fd380Sjfb8856606  */
217*2d9fd380Sjfb8856606 static __rte_always_inline void
__rte_node_enqueue_prologue(struct rte_graph * graph,struct rte_node * node,const uint16_t idx,const uint16_t space)218*2d9fd380Sjfb8856606 __rte_node_enqueue_prologue(struct rte_graph *graph, struct rte_node *node,
219*2d9fd380Sjfb8856606 			    const uint16_t idx, const uint16_t space)
220*2d9fd380Sjfb8856606 {
221*2d9fd380Sjfb8856606 
222*2d9fd380Sjfb8856606 	/* Add to the pending stream list if the node is new */
223*2d9fd380Sjfb8856606 	if (idx == 0)
224*2d9fd380Sjfb8856606 		__rte_node_enqueue_tail_update(graph, node);
225*2d9fd380Sjfb8856606 
226*2d9fd380Sjfb8856606 	if (unlikely(node->size < (idx + space)))
227*2d9fd380Sjfb8856606 		__rte_node_stream_alloc(graph, node);
228*2d9fd380Sjfb8856606 }
229*2d9fd380Sjfb8856606 
230*2d9fd380Sjfb8856606 /**
231*2d9fd380Sjfb8856606  * @internal
232*2d9fd380Sjfb8856606  *
233*2d9fd380Sjfb8856606  * Get the node pointer from current node edge id.
234*2d9fd380Sjfb8856606  *
235*2d9fd380Sjfb8856606  * @param node
236*2d9fd380Sjfb8856606  *   Current node pointer.
237*2d9fd380Sjfb8856606  * @param next
238*2d9fd380Sjfb8856606  *   Edge id of the required node.
239*2d9fd380Sjfb8856606  *
240*2d9fd380Sjfb8856606  * @return
241*2d9fd380Sjfb8856606  *   Pointer to the node denoted by the edge id.
242*2d9fd380Sjfb8856606  */
243*2d9fd380Sjfb8856606 static __rte_always_inline struct rte_node *
__rte_node_next_node_get(struct rte_node * node,rte_edge_t next)244*2d9fd380Sjfb8856606 __rte_node_next_node_get(struct rte_node *node, rte_edge_t next)
245*2d9fd380Sjfb8856606 {
246*2d9fd380Sjfb8856606 	RTE_ASSERT(next < node->nb_edges);
247*2d9fd380Sjfb8856606 	RTE_ASSERT(node->fence == RTE_GRAPH_FENCE);
248*2d9fd380Sjfb8856606 	node = node->nodes[next];
249*2d9fd380Sjfb8856606 	RTE_ASSERT(node->fence == RTE_GRAPH_FENCE);
250*2d9fd380Sjfb8856606 
251*2d9fd380Sjfb8856606 	return node;
252*2d9fd380Sjfb8856606 }
253*2d9fd380Sjfb8856606 
254*2d9fd380Sjfb8856606 /**
255*2d9fd380Sjfb8856606  * Enqueue the objs to next node for further processing and set
256*2d9fd380Sjfb8856606  * the next node to pending state in the circular buffer.
257*2d9fd380Sjfb8856606  *
258*2d9fd380Sjfb8856606  * @param graph
259*2d9fd380Sjfb8856606  *   Graph pointer returned from rte_graph_lookup().
260*2d9fd380Sjfb8856606  * @param node
261*2d9fd380Sjfb8856606  *   Current node pointer.
262*2d9fd380Sjfb8856606  * @param next
263*2d9fd380Sjfb8856606  *   Relative next node index to enqueue objs.
264*2d9fd380Sjfb8856606  * @param objs
265*2d9fd380Sjfb8856606  *   Objs to enqueue.
266*2d9fd380Sjfb8856606  * @param nb_objs
267*2d9fd380Sjfb8856606  *   Number of objs to enqueue.
268*2d9fd380Sjfb8856606  */
269*2d9fd380Sjfb8856606 __rte_experimental
270*2d9fd380Sjfb8856606 static inline void
rte_node_enqueue(struct rte_graph * graph,struct rte_node * node,rte_edge_t next,void ** objs,uint16_t nb_objs)271*2d9fd380Sjfb8856606 rte_node_enqueue(struct rte_graph *graph, struct rte_node *node,
272*2d9fd380Sjfb8856606 		 rte_edge_t next, void **objs, uint16_t nb_objs)
273*2d9fd380Sjfb8856606 {
274*2d9fd380Sjfb8856606 	node = __rte_node_next_node_get(node, next);
275*2d9fd380Sjfb8856606 	const uint16_t idx = node->idx;
276*2d9fd380Sjfb8856606 
277*2d9fd380Sjfb8856606 	__rte_node_enqueue_prologue(graph, node, idx, nb_objs);
278*2d9fd380Sjfb8856606 
279*2d9fd380Sjfb8856606 	rte_memcpy(&node->objs[idx], objs, nb_objs * sizeof(void *));
280*2d9fd380Sjfb8856606 	node->idx = idx + nb_objs;
281*2d9fd380Sjfb8856606 }
282*2d9fd380Sjfb8856606 
283*2d9fd380Sjfb8856606 /**
284*2d9fd380Sjfb8856606  * Enqueue only one obj to next node for further processing and
285*2d9fd380Sjfb8856606  * set the next node to pending state in the circular buffer.
286*2d9fd380Sjfb8856606  *
287*2d9fd380Sjfb8856606  * @param graph
288*2d9fd380Sjfb8856606  *   Graph pointer returned from rte_graph_lookup().
289*2d9fd380Sjfb8856606  * @param node
290*2d9fd380Sjfb8856606  *   Current node pointer.
291*2d9fd380Sjfb8856606  * @param next
292*2d9fd380Sjfb8856606  *   Relative next node index to enqueue objs.
293*2d9fd380Sjfb8856606  * @param obj
294*2d9fd380Sjfb8856606  *   Obj to enqueue.
295*2d9fd380Sjfb8856606  */
296*2d9fd380Sjfb8856606 __rte_experimental
297*2d9fd380Sjfb8856606 static inline void
rte_node_enqueue_x1(struct rte_graph * graph,struct rte_node * node,rte_edge_t next,void * obj)298*2d9fd380Sjfb8856606 rte_node_enqueue_x1(struct rte_graph *graph, struct rte_node *node,
299*2d9fd380Sjfb8856606 		    rte_edge_t next, void *obj)
300*2d9fd380Sjfb8856606 {
301*2d9fd380Sjfb8856606 	node = __rte_node_next_node_get(node, next);
302*2d9fd380Sjfb8856606 	uint16_t idx = node->idx;
303*2d9fd380Sjfb8856606 
304*2d9fd380Sjfb8856606 	__rte_node_enqueue_prologue(graph, node, idx, 1);
305*2d9fd380Sjfb8856606 
306*2d9fd380Sjfb8856606 	node->objs[idx++] = obj;
307*2d9fd380Sjfb8856606 	node->idx = idx;
308*2d9fd380Sjfb8856606 }
309*2d9fd380Sjfb8856606 
310*2d9fd380Sjfb8856606 /**
311*2d9fd380Sjfb8856606  * Enqueue only two objs to next node for further processing and
312*2d9fd380Sjfb8856606  * set the next node to pending state in the circular buffer.
313*2d9fd380Sjfb8856606  * Same as rte_node_enqueue_x1 but enqueue two objs.
314*2d9fd380Sjfb8856606  *
315*2d9fd380Sjfb8856606  * @param graph
316*2d9fd380Sjfb8856606  *   Graph pointer returned from rte_graph_lookup().
317*2d9fd380Sjfb8856606  * @param node
318*2d9fd380Sjfb8856606  *   Current node pointer.
319*2d9fd380Sjfb8856606  * @param next
320*2d9fd380Sjfb8856606  *   Relative next node index to enqueue objs.
321*2d9fd380Sjfb8856606  * @param obj0
322*2d9fd380Sjfb8856606  *   Obj to enqueue.
323*2d9fd380Sjfb8856606  * @param obj1
324*2d9fd380Sjfb8856606  *   Obj to enqueue.
325*2d9fd380Sjfb8856606  */
326*2d9fd380Sjfb8856606 __rte_experimental
327*2d9fd380Sjfb8856606 static inline void
rte_node_enqueue_x2(struct rte_graph * graph,struct rte_node * node,rte_edge_t next,void * obj0,void * obj1)328*2d9fd380Sjfb8856606 rte_node_enqueue_x2(struct rte_graph *graph, struct rte_node *node,
329*2d9fd380Sjfb8856606 		    rte_edge_t next, void *obj0, void *obj1)
330*2d9fd380Sjfb8856606 {
331*2d9fd380Sjfb8856606 	node = __rte_node_next_node_get(node, next);
332*2d9fd380Sjfb8856606 	uint16_t idx = node->idx;
333*2d9fd380Sjfb8856606 
334*2d9fd380Sjfb8856606 	__rte_node_enqueue_prologue(graph, node, idx, 2);
335*2d9fd380Sjfb8856606 
336*2d9fd380Sjfb8856606 	node->objs[idx++] = obj0;
337*2d9fd380Sjfb8856606 	node->objs[idx++] = obj1;
338*2d9fd380Sjfb8856606 	node->idx = idx;
339*2d9fd380Sjfb8856606 }
340*2d9fd380Sjfb8856606 
341*2d9fd380Sjfb8856606 /**
342*2d9fd380Sjfb8856606  * Enqueue only four objs to next node for further processing and
343*2d9fd380Sjfb8856606  * set the next node to pending state in the circular buffer.
344*2d9fd380Sjfb8856606  * Same as rte_node_enqueue_x1 but enqueue four objs.
345*2d9fd380Sjfb8856606  *
346*2d9fd380Sjfb8856606  * @param graph
347*2d9fd380Sjfb8856606  *   Graph pointer returned from rte_graph_lookup().
348*2d9fd380Sjfb8856606  * @param node
349*2d9fd380Sjfb8856606  *   Current node pointer.
350*2d9fd380Sjfb8856606  * @param next
351*2d9fd380Sjfb8856606  *   Relative next node index to enqueue objs.
352*2d9fd380Sjfb8856606  * @param obj0
353*2d9fd380Sjfb8856606  *   1st obj to enqueue.
354*2d9fd380Sjfb8856606  * @param obj1
355*2d9fd380Sjfb8856606  *   2nd obj to enqueue.
356*2d9fd380Sjfb8856606  * @param obj2
357*2d9fd380Sjfb8856606  *   3rd obj to enqueue.
358*2d9fd380Sjfb8856606  * @param obj3
359*2d9fd380Sjfb8856606  *   4th obj to enqueue.
360*2d9fd380Sjfb8856606  */
361*2d9fd380Sjfb8856606 __rte_experimental
362*2d9fd380Sjfb8856606 static inline void
rte_node_enqueue_x4(struct rte_graph * graph,struct rte_node * node,rte_edge_t next,void * obj0,void * obj1,void * obj2,void * obj3)363*2d9fd380Sjfb8856606 rte_node_enqueue_x4(struct rte_graph *graph, struct rte_node *node,
364*2d9fd380Sjfb8856606 		    rte_edge_t next, void *obj0, void *obj1, void *obj2,
365*2d9fd380Sjfb8856606 		    void *obj3)
366*2d9fd380Sjfb8856606 {
367*2d9fd380Sjfb8856606 	node = __rte_node_next_node_get(node, next);
368*2d9fd380Sjfb8856606 	uint16_t idx = node->idx;
369*2d9fd380Sjfb8856606 
370*2d9fd380Sjfb8856606 	__rte_node_enqueue_prologue(graph, node, idx, 4);
371*2d9fd380Sjfb8856606 
372*2d9fd380Sjfb8856606 	node->objs[idx++] = obj0;
373*2d9fd380Sjfb8856606 	node->objs[idx++] = obj1;
374*2d9fd380Sjfb8856606 	node->objs[idx++] = obj2;
375*2d9fd380Sjfb8856606 	node->objs[idx++] = obj3;
376*2d9fd380Sjfb8856606 	node->idx = idx;
377*2d9fd380Sjfb8856606 }
378*2d9fd380Sjfb8856606 
379*2d9fd380Sjfb8856606 /**
380*2d9fd380Sjfb8856606  * Enqueue objs to multiple next nodes for further processing and
381*2d9fd380Sjfb8856606  * set the next nodes to pending state in the circular buffer.
382*2d9fd380Sjfb8856606  * objs[i] will be enqueued to nexts[i].
383*2d9fd380Sjfb8856606  *
384*2d9fd380Sjfb8856606  * @param graph
385*2d9fd380Sjfb8856606  *   Graph pointer returned from rte_graph_lookup().
386*2d9fd380Sjfb8856606  * @param node
387*2d9fd380Sjfb8856606  *   Current node pointer.
388*2d9fd380Sjfb8856606  * @param nexts
389*2d9fd380Sjfb8856606  *   List of relative next node indices to enqueue objs.
390*2d9fd380Sjfb8856606  * @param objs
391*2d9fd380Sjfb8856606  *   List of objs to enqueue.
392*2d9fd380Sjfb8856606  * @param nb_objs
393*2d9fd380Sjfb8856606  *   Number of objs to enqueue.
394*2d9fd380Sjfb8856606  */
395*2d9fd380Sjfb8856606 __rte_experimental
396*2d9fd380Sjfb8856606 static inline void
rte_node_enqueue_next(struct rte_graph * graph,struct rte_node * node,rte_edge_t * nexts,void ** objs,uint16_t nb_objs)397*2d9fd380Sjfb8856606 rte_node_enqueue_next(struct rte_graph *graph, struct rte_node *node,
398*2d9fd380Sjfb8856606 		      rte_edge_t *nexts, void **objs, uint16_t nb_objs)
399*2d9fd380Sjfb8856606 {
400*2d9fd380Sjfb8856606 	uint16_t i;
401*2d9fd380Sjfb8856606 
402*2d9fd380Sjfb8856606 	for (i = 0; i < nb_objs; i++)
403*2d9fd380Sjfb8856606 		rte_node_enqueue_x1(graph, node, nexts[i], objs[i]);
404*2d9fd380Sjfb8856606 }
405*2d9fd380Sjfb8856606 
406*2d9fd380Sjfb8856606 /**
407*2d9fd380Sjfb8856606  * Get the stream of next node to enqueue the objs.
408*2d9fd380Sjfb8856606  * Once done with the updating the objs, needs to call
409*2d9fd380Sjfb8856606  * rte_node_next_stream_put to put the next node to pending state.
410*2d9fd380Sjfb8856606  *
411*2d9fd380Sjfb8856606  * @param graph
412*2d9fd380Sjfb8856606  *   Graph pointer returned from rte_graph_lookup().
413*2d9fd380Sjfb8856606  * @param node
414*2d9fd380Sjfb8856606  *   Current node pointer.
415*2d9fd380Sjfb8856606  * @param next
416*2d9fd380Sjfb8856606  *   Relative next node index to get stream.
417*2d9fd380Sjfb8856606  * @param nb_objs
418*2d9fd380Sjfb8856606  *   Requested free size of the next stream.
419*2d9fd380Sjfb8856606  *
420*2d9fd380Sjfb8856606  * @return
421*2d9fd380Sjfb8856606  *   Valid next stream on success.
422*2d9fd380Sjfb8856606  *
423*2d9fd380Sjfb8856606  * @see rte_node_next_stream_put().
424*2d9fd380Sjfb8856606  */
425*2d9fd380Sjfb8856606 __rte_experimental
426*2d9fd380Sjfb8856606 static inline void **
rte_node_next_stream_get(struct rte_graph * graph,struct rte_node * node,rte_edge_t next,uint16_t nb_objs)427*2d9fd380Sjfb8856606 rte_node_next_stream_get(struct rte_graph *graph, struct rte_node *node,
428*2d9fd380Sjfb8856606 			 rte_edge_t next, uint16_t nb_objs)
429*2d9fd380Sjfb8856606 {
430*2d9fd380Sjfb8856606 	node = __rte_node_next_node_get(node, next);
431*2d9fd380Sjfb8856606 	const uint16_t idx = node->idx;
432*2d9fd380Sjfb8856606 	uint16_t free_space = node->size - idx;
433*2d9fd380Sjfb8856606 
434*2d9fd380Sjfb8856606 	if (unlikely(free_space < nb_objs))
435*2d9fd380Sjfb8856606 		__rte_node_stream_alloc_size(graph, node, nb_objs);
436*2d9fd380Sjfb8856606 
437*2d9fd380Sjfb8856606 	return &node->objs[idx];
438*2d9fd380Sjfb8856606 }
439*2d9fd380Sjfb8856606 
440*2d9fd380Sjfb8856606 /**
441*2d9fd380Sjfb8856606  * Put the next stream to pending state in the circular buffer
442*2d9fd380Sjfb8856606  * for further processing. Should be invoked after rte_node_next_stream_get().
443*2d9fd380Sjfb8856606  *
444*2d9fd380Sjfb8856606  * @param graph
445*2d9fd380Sjfb8856606  *   Graph pointer returned from rte_graph_lookup().
446*2d9fd380Sjfb8856606  * @param node
447*2d9fd380Sjfb8856606  *   Current node pointer.
448*2d9fd380Sjfb8856606  * @param next
449*2d9fd380Sjfb8856606  *   Relative next node index..
450*2d9fd380Sjfb8856606  * @param idx
451*2d9fd380Sjfb8856606  *   Number of objs updated in the stream after getting the stream using
452*2d9fd380Sjfb8856606  *   rte_node_next_stream_get.
453*2d9fd380Sjfb8856606  *
454*2d9fd380Sjfb8856606  * @see rte_node_next_stream_get().
455*2d9fd380Sjfb8856606  */
456*2d9fd380Sjfb8856606 __rte_experimental
457*2d9fd380Sjfb8856606 static inline void
rte_node_next_stream_put(struct rte_graph * graph,struct rte_node * node,rte_edge_t next,uint16_t idx)458*2d9fd380Sjfb8856606 rte_node_next_stream_put(struct rte_graph *graph, struct rte_node *node,
459*2d9fd380Sjfb8856606 			 rte_edge_t next, uint16_t idx)
460*2d9fd380Sjfb8856606 {
461*2d9fd380Sjfb8856606 	if (unlikely(!idx))
462*2d9fd380Sjfb8856606 		return;
463*2d9fd380Sjfb8856606 
464*2d9fd380Sjfb8856606 	node = __rte_node_next_node_get(node, next);
465*2d9fd380Sjfb8856606 	if (node->idx == 0)
466*2d9fd380Sjfb8856606 		__rte_node_enqueue_tail_update(graph, node);
467*2d9fd380Sjfb8856606 
468*2d9fd380Sjfb8856606 	node->idx += idx;
469*2d9fd380Sjfb8856606 }
470*2d9fd380Sjfb8856606 
471*2d9fd380Sjfb8856606 /**
472*2d9fd380Sjfb8856606  * Home run scenario, Enqueue all the objs of current node to next
473*2d9fd380Sjfb8856606  * node in optimized way by swapping the streams of both nodes.
474*2d9fd380Sjfb8856606  * Performs good when next node is already not in pending state.
475*2d9fd380Sjfb8856606  * If next node is already in pending state then normal enqueue
476*2d9fd380Sjfb8856606  * will be used.
477*2d9fd380Sjfb8856606  *
478*2d9fd380Sjfb8856606  * @param graph
479*2d9fd380Sjfb8856606  *   Graph pointer returned from rte_graph_lookup().
480*2d9fd380Sjfb8856606  * @param src
481*2d9fd380Sjfb8856606  *   Current node pointer.
482*2d9fd380Sjfb8856606  * @param next
483*2d9fd380Sjfb8856606  *   Relative next node index.
484*2d9fd380Sjfb8856606  */
485*2d9fd380Sjfb8856606 __rte_experimental
486*2d9fd380Sjfb8856606 static inline void
rte_node_next_stream_move(struct rte_graph * graph,struct rte_node * src,rte_edge_t next)487*2d9fd380Sjfb8856606 rte_node_next_stream_move(struct rte_graph *graph, struct rte_node *src,
488*2d9fd380Sjfb8856606 			  rte_edge_t next)
489*2d9fd380Sjfb8856606 {
490*2d9fd380Sjfb8856606 	struct rte_node *dst = __rte_node_next_node_get(src, next);
491*2d9fd380Sjfb8856606 
492*2d9fd380Sjfb8856606 	/* Let swap the pointers if dst don't have valid objs */
493*2d9fd380Sjfb8856606 	if (likely(dst->idx == 0)) {
494*2d9fd380Sjfb8856606 		void **dobjs = dst->objs;
495*2d9fd380Sjfb8856606 		uint16_t dsz = dst->size;
496*2d9fd380Sjfb8856606 		dst->objs = src->objs;
497*2d9fd380Sjfb8856606 		dst->size = src->size;
498*2d9fd380Sjfb8856606 		src->objs = dobjs;
499*2d9fd380Sjfb8856606 		src->size = dsz;
500*2d9fd380Sjfb8856606 		dst->idx = src->idx;
501*2d9fd380Sjfb8856606 		__rte_node_enqueue_tail_update(graph, dst);
502*2d9fd380Sjfb8856606 	} else { /* Move the objects from src node to dst node */
503*2d9fd380Sjfb8856606 		rte_node_enqueue(graph, src, next, src->objs, src->idx);
504*2d9fd380Sjfb8856606 	}
505*2d9fd380Sjfb8856606 }
506*2d9fd380Sjfb8856606 
507*2d9fd380Sjfb8856606 #ifdef __cplusplus
508*2d9fd380Sjfb8856606 }
509*2d9fd380Sjfb8856606 #endif
510*2d9fd380Sjfb8856606 
511*2d9fd380Sjfb8856606 #endif /* _RTE_GRAPH_WORKER_H_ */
512