505d34ee843e5307a08e3b657d0c4eec59e42621
[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 /**
93  * Master thread & data plane threads: message passing
94  */
95 enum thread_req_type {
96         THREAD_REQ_MAX
97 };
98
99 struct thread_msg_req {
100         enum thread_req_type type;
101 };
102
103 struct thread_msg_rsp {
104         int status;
105 };
106
107 /**
108  * Data plane threads: message handling
109  */
110 static inline struct thread_msg_req *
111 thread_msg_recv(struct rte_ring *msgq_req)
112 {
113         struct thread_msg_req *req;
114
115         int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
116
117         if (status != 0)
118                 return NULL;
119
120         return req;
121 }
122
123 static inline void
124 thread_msg_send(struct rte_ring *msgq_rsp,
125         struct thread_msg_rsp *rsp)
126 {
127         int status;
128
129         do {
130                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
131         } while (status == -ENOBUFS);
132 }
133
134 static void
135 thread_msg_handle(struct softnic_thread_data *t)
136 {
137         for ( ; ; ) {
138                 struct thread_msg_req *req;
139                 struct thread_msg_rsp *rsp;
140
141                 req = thread_msg_recv(t->msgq_req);
142                 if (req == NULL)
143                         break;
144
145                 switch (req->type) {
146                 default:
147                         rsp = (struct thread_msg_rsp *)req;
148                         rsp->status = -1;
149                 }
150
151                 thread_msg_send(t->msgq_rsp, rsp);
152         }
153 }
154
155 /**
156  * Master thread & data plane threads: message passing
157  */
158 enum pipeline_req_type {
159         PIPELINE_REQ_MAX
160 };
161
162 struct pipeline_msg_req {
163         enum pipeline_req_type type;
164 };
165
166 struct pipeline_msg_rsp {
167         int status;
168 };
169
170 /**
171  * Data plane threads: message handling
172  */
173 static inline struct pipeline_msg_req *
174 pipeline_msg_recv(struct rte_ring *msgq_req)
175 {
176         struct pipeline_msg_req *req;
177
178         int status = rte_ring_sc_dequeue(msgq_req, (void **)&req);
179
180         if (status != 0)
181                 return NULL;
182
183         return req;
184 }
185
186 static inline void
187 pipeline_msg_send(struct rte_ring *msgq_rsp,
188         struct pipeline_msg_rsp *rsp)
189 {
190         int status;
191
192         do {
193                 status = rte_ring_sp_enqueue(msgq_rsp, rsp);
194         } while (status == -ENOBUFS);
195 }
196
197 static void
198 pipeline_msg_handle(struct pipeline_data *p)
199 {
200         for ( ; ; ) {
201                 struct pipeline_msg_req *req;
202                 struct pipeline_msg_rsp *rsp;
203
204                 req = pipeline_msg_recv(p->msgq_req);
205                 if (req == NULL)
206                         break;
207
208                 switch (req->type) {
209                 default:
210                         rsp = (struct pipeline_msg_rsp *)req;
211                         rsp->status = -1;
212                 }
213
214                 pipeline_msg_send(p->msgq_rsp, rsp);
215         }
216 }
217
218 /**
219  * Data plane threads: main
220  */
221 int
222 rte_pmd_softnic_run(uint16_t port_id)
223 {
224         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
225         struct pmd_internals *softnic;
226         struct softnic_thread_data *t;
227         uint32_t thread_id, j;
228
229 #ifdef RTE_LIBRTE_ETHDEV_DEBUG
230         RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, 0);
231 #endif
232
233         softnic = dev->data->dev_private;
234         thread_id = rte_lcore_id();
235         t = &softnic->thread_data[thread_id];
236         t->iter++;
237
238         /* Data Plane */
239         for (j = 0; j < t->n_pipelines; j++)
240                 rte_pipeline_run(t->p[j]);
241
242         /* Control Plane */
243         if ((t->iter & 0xFLLU) == 0) {
244                 uint64_t time = rte_get_tsc_cycles();
245                 uint64_t time_next_min = UINT64_MAX;
246
247                 if (time < t->time_next_min)
248                         return 0;
249
250                 /* Pipeline message queues */
251                 for (j = 0; j < t->n_pipelines; j++) {
252                         struct pipeline_data *p =
253                                 &t->pipeline_data[j];
254                         uint64_t time_next = p->time_next;
255
256                         if (time_next <= time) {
257                                 pipeline_msg_handle(p);
258                                 rte_pipeline_flush(p->p);
259                                 time_next = time + p->timer_period;
260                                 p->time_next = time_next;
261                         }
262
263                         if (time_next < time_next_min)
264                                 time_next_min = time_next;
265                 }
266
267                 /* Thread message queues */
268                 {
269                         uint64_t time_next = t->time_next;
270
271                         if (time_next <= time) {
272                                 thread_msg_handle(t);
273                                 time_next = time + t->timer_period;
274                                 t->time_next = time_next;
275                         }
276
277                         if (time_next < time_next_min)
278                                 time_next_min = time_next;
279                 }
280
281                 t->time_next_min = time_next_min;
282         }
283
284         return 0;
285 }