net/softnic: add command to create objects
[dpdk.git] / drivers / net / softnic / rte_eth_softnic_thread.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2018 Intel Corporation
3  */
4
5 #include <stdlib.h>
6
7 #include <rte_cycles.h>
8 #include <rte_lcore.h>
9 #include <rte_ring.h>
10
11 #include "rte_eth_softnic_internals.h"
12
13 /**
14  * Master thread: data plane thread init
15  */
16 void
17 softnic_thread_free(struct pmd_internals *softnic)
18 {
19         uint32_t i;
20
21         RTE_LCORE_FOREACH_SLAVE(i) {
22                 struct softnic_thread *t = &softnic->thread[i];
23
24                 /* MSGQs */
25                 if (t->msgq_req)
26                         rte_ring_free(t->msgq_req);
27
28                 if (t->msgq_rsp)
29                         rte_ring_free(t->msgq_rsp);
30         }
31 }
32
33 int
34 softnic_thread_init(struct pmd_internals *softnic)
35 {
36         uint32_t i;
37
38         RTE_LCORE_FOREACH_SLAVE(i) {
39                 char ring_name[NAME_MAX];
40                 struct rte_ring *msgq_req, *msgq_rsp;
41                 struct softnic_thread *t = &softnic->thread[i];
42                 struct softnic_thread_data *t_data = &softnic->thread_data[i];
43                 uint32_t cpu_id = rte_lcore_to_socket_id(i);
44
45                 /* MSGQs */
46                 snprintf(ring_name, sizeof(ring_name), "%s-TH%u-REQ",
47                         softnic->params.name,
48                         i);
49
50                 msgq_req = rte_ring_create(ring_name,
51                         THREAD_MSGQ_SIZE,
52                         cpu_id,
53                         RING_F_SP_ENQ | RING_F_SC_DEQ);
54
55                 if (msgq_req == NULL) {
56                         softnic_thread_free(softnic);
57                         return -1;
58                 }
59
60                 snprintf(ring_name, sizeof(ring_name), "%s-TH%u-RSP",
61                         softnic->params.name,
62                         i);
63
64                 msgq_rsp = rte_ring_create(ring_name,
65                         THREAD_MSGQ_SIZE,
66                         cpu_id,
67                         RING_F_SP_ENQ | RING_F_SC_DEQ);
68
69                 if (msgq_rsp == NULL) {
70                         softnic_thread_free(softnic);
71                         return -1;
72                 }
73
74                 /* Master thread records */
75                 t->msgq_req = msgq_req;
76                 t->msgq_rsp = msgq_rsp;
77                 t->enabled = 1;
78
79                 /* Data plane thread records */
80                 t_data->n_pipelines = 0;
81                 t_data->msgq_req = msgq_req;
82                 t_data->msgq_rsp = msgq_rsp;
83                 t_data->timer_period =
84                         (rte_get_tsc_hz() * THREAD_TIMER_PERIOD_MS) / 1000;
85                 t_data->time_next = rte_get_tsc_cycles() + t_data->timer_period;
86                 t_data->time_next_min = t_data->time_next;
87         }
88
89         return 0;
90 }
91
92 static inline int
93 thread_is_running(uint32_t thread_id)
94 {
95         enum rte_lcore_state_t thread_state;
96
97         thread_state = rte_eal_get_lcore_state(thread_id);
98         return (thread_state == RUNNING)? 1 : 0;
99 }
100
101 /**
102  * Pipeline is running when:
103  *    (A) Pipeline is mapped to a data plane thread AND
104  *    (B) Its data plane thread is in RUNNING state.
105  */
106 static inline int
107 pipeline_is_running(struct pipeline *p)
108 {
109         if (p->enabled == 0)
110                 return 0;
111
112         return thread_is_running(p->thread_id);
113 }
114
115 /**
116  * Master thread & data plane threads: message passing
117  */
118 enum thread_req_type {
119         THREAD_REQ_MAX
120 };
121
122 struct thread_msg_req {
123         enum thread_req_type type;
124 };
125
126 struct thread_msg_rsp {
127         int status;
128 };
129
130 /**
131  * Data plane threads: message handling
132  */
133 static inline struct thread_msg_req *
134 thread_msg_recv(struct rte_ring *msgq_req)
135 {
136         struct thread_msg_req *req;
137
138         int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
139
140         if (status != 0)
141                 return NULL;
142
143         return req;
144 }
145
146 static inline void
147 thread_msg_send(struct rte_ring *msgq_rsp,
148         struct thread_msg_rsp *rsp)
149 {
150         int status;
151
152         do {
153                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
154         } while (status == -ENOBUFS);
155 }
156
157 static void
158 thread_msg_handle(struct softnic_thread_data *t)
159 {
160         for ( ; ; ) {
161                 struct thread_msg_req *req;
162                 struct thread_msg_rsp *rsp;
163
164                 req = thread_msg_recv(t->msgq_req);
165                 if (req == NULL)
166                         break;
167
168                 switch (req->type) {
169                 default:
170                         rsp = (struct thread_msg_rsp *)req;
171                         rsp->status = -1;
172                 }
173
174                 thread_msg_send(t->msgq_rsp, rsp);
175         }
176 }
177
178 /**
179  * Master thread & data plane threads: message passing
180  */
181 enum pipeline_req_type {
182         /* Port IN */
183         PIPELINE_REQ_PORT_IN_ENABLE,
184         PIPELINE_REQ_PORT_IN_DISABLE,
185
186         PIPELINE_REQ_MAX
187 };
188
189 struct pipeline_msg_req {
190         enum pipeline_req_type type;
191         uint32_t id; /* Port IN, port OUT or table ID */
192 };
193
194 struct pipeline_msg_rsp {
195         int status;
196 };
197
198 /**
199  * Master thread
200  */
201 static struct pipeline_msg_req *
202 pipeline_msg_alloc(void)
203 {
204         size_t size = RTE_MAX(sizeof(struct pipeline_msg_req),
205                 sizeof(struct pipeline_msg_rsp));
206
207         return calloc(1, size);
208 }
209
210 static void
211 pipeline_msg_free(struct pipeline_msg_rsp *rsp)
212 {
213         free(rsp);
214 }
215
216 static struct pipeline_msg_rsp *
217 pipeline_msg_send_recv(struct pipeline *p,
218         struct pipeline_msg_req *req)
219 {
220         struct rte_ring *msgq_req = p->msgq_req;
221         struct rte_ring *msgq_rsp = p->msgq_rsp;
222         struct pipeline_msg_rsp *rsp;
223         int status;
224
225         /* send */
226         do {
227                 status = rte_ring_sp_enqueue(msgq_req, req);
228         } while (status == -ENOBUFS);
229
230         /* recv */
231         do {
232                 status = rte_ring_sc_dequeue(msgq_rsp, (void **)&rsp);
233         } while (status != 0);
234
235         return rsp;
236 }
237
238 int
239 softnic_pipeline_port_in_enable(struct pmd_internals *softnic,
240         const char *pipeline_name,
241         uint32_t port_id)
242 {
243         struct pipeline *p;
244         struct pipeline_msg_req *req;
245         struct pipeline_msg_rsp *rsp;
246         int status;
247
248         /* Check input params */
249         if (pipeline_name == NULL)
250                 return -1;
251
252         p = softnic_pipeline_find(softnic, pipeline_name);
253         if (p == NULL ||
254                 port_id >= p->n_ports_in)
255                 return -1;
256
257         if (!pipeline_is_running(p)) {
258                 status = rte_pipeline_port_in_enable(p->p, port_id);
259                 return status;
260         }
261
262         /* Allocate request */
263         req = pipeline_msg_alloc();
264         if (req == NULL)
265                 return -1;
266
267         /* Write request */
268         req->type = PIPELINE_REQ_PORT_IN_ENABLE;
269         req->id = port_id;
270
271         /* Send request and wait for response */
272         rsp = pipeline_msg_send_recv(p, req);
273         if (rsp == NULL)
274                 return -1;
275
276         /* Read response */
277         status = rsp->status;
278
279         /* Free response */
280         pipeline_msg_free(rsp);
281
282         return status;
283 }
284
285 int
286 softnic_pipeline_port_in_disable(struct pmd_internals *softnic,
287         const char *pipeline_name,
288         uint32_t port_id)
289 {
290         struct pipeline *p;
291         struct pipeline_msg_req *req;
292         struct pipeline_msg_rsp *rsp;
293         int status;
294
295         /* Check input params */
296         if (pipeline_name == NULL)
297                 return -1;
298
299         p = softnic_pipeline_find(softnic, pipeline_name);
300         if (p == NULL ||
301                 port_id >= p->n_ports_in)
302                 return -1;
303
304         if (!pipeline_is_running(p)) {
305                 status = rte_pipeline_port_in_disable(p->p, port_id);
306                 return status;
307         }
308
309         /* Allocate request */
310         req = pipeline_msg_alloc();
311         if (req == NULL)
312                 return -1;
313
314         /* Write request */
315         req->type = PIPELINE_REQ_PORT_IN_DISABLE;
316         req->id = port_id;
317
318         /* Send request and wait for response */
319         rsp = pipeline_msg_send_recv(p, req);
320         if (rsp == NULL)
321                 return -1;
322
323         /* Read response */
324         status = rsp->status;
325
326         /* Free response */
327         pipeline_msg_free(rsp);
328
329         return status;
330 }
331
332 /**
333  * Data plane threads: message handling
334  */
335 static inline struct pipeline_msg_req *
336 pipeline_msg_recv(struct rte_ring *msgq_req)
337 {
338         struct pipeline_msg_req *req;
339
340         int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
341
342         if (status != 0)
343                 return NULL;
344
345         return req;
346 }
347
348 static inline void
349 pipeline_msg_send(struct rte_ring *msgq_rsp,
350         struct pipeline_msg_rsp *rsp)
351 {
352         int status;
353
354         do {
355                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
356         } while (status == -ENOBUFS);
357 }
358
359 static struct pipeline_msg_rsp *
360 pipeline_msg_handle_port_in_enable(struct pipeline_data *p,
361         struct pipeline_msg_req *req)
362 {
363         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
364         uint32_t port_id = req->id;
365
366         rsp->status = rte_pipeline_port_in_enable(p->p,
367                 port_id);
368
369         return rsp;
370 }
371
372 static struct pipeline_msg_rsp *
373 pipeline_msg_handle_port_in_disable(struct pipeline_data *p,
374         struct pipeline_msg_req *req)
375 {
376         struct pipeline_msg_rsp *rsp = (struct pipeline_msg_rsp *)req;
377         uint32_t port_id = req->id;
378
379         rsp->status = rte_pipeline_port_in_disable(p->p,
380                 port_id);
381
382         return rsp;
383 }
384
385 static void
386 pipeline_msg_handle(struct pipeline_data *p)
387 {
388         for ( ; ; ) {
389                 struct pipeline_msg_req *req;
390                 struct pipeline_msg_rsp *rsp;
391
392                 req = pipeline_msg_recv(p->msgq_req);
393                 if (req == NULL)
394                         break;
395
396                 switch (req->type) {
397                 case PIPELINE_REQ_PORT_IN_ENABLE:
398                         rsp = pipeline_msg_handle_port_in_enable(p, req);
399                         break;
400
401                 case PIPELINE_REQ_PORT_IN_DISABLE:
402                         rsp = pipeline_msg_handle_port_in_disable(p, req);
403                         break;
404
405                 default:
406                         rsp = (struct pipeline_msg_rsp *)req;
407                         rsp->status = -1;
408                 }
409
410                 pipeline_msg_send(p->msgq_rsp, rsp);
411         }
412 }
413
414 /**
415  * Data plane threads: main
416  */
417 int
418 rte_pmd_softnic_run(uint16_t port_id)
419 {
420         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
421         struct pmd_internals *softnic;
422         struct softnic_thread_data *t;
423         uint32_t thread_id, j;
424
425 #ifdef RTE_LIBRTE_ETHDEV_DEBUG
426         RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
427 #endif
428
429         softnic = dev->data->dev_private;
430         thread_id = rte_lcore_id();
431         t = &softnic->thread_data[thread_id];
432         t->iter++;
433
434         /* Data Plane */
435         for (j = 0; j < t->n_pipelines; j++)
436                 rte_pipeline_run(t->p[j]);
437
438         /* Control Plane */
439         if ((t->iter & 0xFLLU) == 0) {
440                 uint64_t time = rte_get_tsc_cycles();
441                 uint64_t time_next_min = UINT64_MAX;
442
443                 if (time < t->time_next_min)
444                         return 0;
445
446                 /* Pipeline message queues */
447                 for (j = 0; j < t->n_pipelines; j++) {
448                         struct pipeline_data *p =
449                                 &t->pipeline_data[j];
450                         uint64_t time_next = p->time_next;
451
452                         if (time_next <= time) {
453                                 pipeline_msg_handle(p);
454                                 rte_pipeline_flush(p->p);
455                                 time_next = time + p->timer_period;
456                                 p->time_next = time_next;
457                         }
458
459                         if (time_next < time_next_min)
460                                 time_next_min = time_next;
461                 }
462
463                 /* Thread message queues */
464                 {
465                         uint64_t time_next = t->time_next;
466
467                         if (time_next <= time) {
468                                 thread_msg_handle(t);
469                                 time_next = time + t->timer_period;
470                                 t->time_next = time_next;
471                         }
472
473                         if (time_next < time_next_min)
474                                 time_next_min = time_next;
475                 }
476
477                 t->time_next_min = time_next_min;
478         }
479
480         return 0;
481 }