net/sfc: add representor proxy port API
[dpdk.git] / drivers / net / sfc / sfc_repr_proxy.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019-2021 Xilinx, Inc.
4  * Copyright(c) 2019 Solarflare Communications Inc.
5  *
6  * This software was jointly developed between OKTET Labs (under contract
7  * for Solarflare) and Solarflare Communications, Inc.
8  */
9
10 #include <rte_service.h>
11 #include <rte_service_component.h>
12
13 #include "sfc_log.h"
14 #include "sfc_service.h"
15 #include "sfc_repr_proxy.h"
16 #include "sfc_repr_proxy_api.h"
17 #include "sfc.h"
18
19 /**
20  * Amount of time to wait for the representor proxy routine (which is
21  * running on a service core) to handle a request sent via mbox.
22  */
23 #define SFC_REPR_PROXY_MBOX_POLL_TIMEOUT_MS     1000
24
25 static struct sfc_repr_proxy *
26 sfc_repr_proxy_by_adapter(struct sfc_adapter *sa)
27 {
28         return &sa->repr_proxy;
29 }
30
31 static struct sfc_adapter *
32 sfc_get_adapter_by_pf_port_id(uint16_t pf_port_id)
33 {
34         struct rte_eth_dev *dev;
35         struct sfc_adapter *sa;
36
37         SFC_ASSERT(pf_port_id < RTE_MAX_ETHPORTS);
38
39         dev = &rte_eth_devices[pf_port_id];
40         sa = sfc_adapter_by_eth_dev(dev);
41
42         sfc_adapter_lock(sa);
43
44         return sa;
45 }
46
47 static void
48 sfc_put_adapter(struct sfc_adapter *sa)
49 {
50         sfc_adapter_unlock(sa);
51 }
52
53 static int
54 sfc_repr_proxy_mbox_send(struct sfc_repr_proxy_mbox *mbox,
55                          struct sfc_repr_proxy_port *port,
56                          enum sfc_repr_proxy_mbox_op op)
57 {
58         const unsigned int wait_ms = SFC_REPR_PROXY_MBOX_POLL_TIMEOUT_MS;
59         unsigned int i;
60
61         mbox->op = op;
62         mbox->port = port;
63         mbox->ack = false;
64
65         /*
66          * Release ordering enforces marker set after data is populated.
67          * Paired with acquire ordering in sfc_repr_proxy_mbox_handle().
68          */
69         __atomic_store_n(&mbox->write_marker, true, __ATOMIC_RELEASE);
70
71         /*
72          * Wait for the representor routine to process the request.
73          * Give up on timeout.
74          */
75         for (i = 0; i < wait_ms; i++) {
76                 /*
77                  * Paired with release ordering in sfc_repr_proxy_mbox_handle()
78                  * on acknowledge write.
79                  */
80                 if (__atomic_load_n(&mbox->ack, __ATOMIC_ACQUIRE))
81                         break;
82
83                 rte_delay_ms(1);
84         }
85
86         if (i == wait_ms) {
87                 SFC_GENERIC_LOG(ERR,
88                         "%s() failed to wait for representor proxy routine ack",
89                         __func__);
90                 return ETIMEDOUT;
91         }
92
93         return 0;
94 }
95
96 static void
97 sfc_repr_proxy_mbox_handle(struct sfc_repr_proxy *rp)
98 {
99         struct sfc_repr_proxy_mbox *mbox = &rp->mbox;
100
101         /*
102          * Paired with release ordering in sfc_repr_proxy_mbox_send()
103          * on marker set.
104          */
105         if (!__atomic_load_n(&mbox->write_marker, __ATOMIC_ACQUIRE))
106                 return;
107
108         mbox->write_marker = false;
109
110         switch (mbox->op) {
111         case SFC_REPR_PROXY_MBOX_ADD_PORT:
112                 TAILQ_INSERT_TAIL(&rp->ports, mbox->port, entries);
113                 break;
114         case SFC_REPR_PROXY_MBOX_DEL_PORT:
115                 TAILQ_REMOVE(&rp->ports, mbox->port, entries);
116                 break;
117         default:
118                 SFC_ASSERT(0);
119                 return;
120         }
121
122         /*
123          * Paired with acquire ordering in sfc_repr_proxy_mbox_send()
124          * on acknowledge read.
125          */
126         __atomic_store_n(&mbox->ack, true, __ATOMIC_RELEASE);
127 }
128
129 static int32_t
130 sfc_repr_proxy_routine(void *arg)
131 {
132         struct sfc_repr_proxy *rp = arg;
133
134         sfc_repr_proxy_mbox_handle(rp);
135
136         return 0;
137 }
138
139 static int
140 sfc_repr_proxy_ports_init(struct sfc_adapter *sa)
141 {
142         struct sfc_repr_proxy *rp = &sa->repr_proxy;
143         int rc;
144
145         sfc_log_init(sa, "entry");
146
147         rc = efx_mcdi_mport_alloc_alias(sa->nic, &rp->mport_alias, NULL);
148         if (rc != 0) {
149                 sfc_err(sa, "failed to alloc mport alias: %s",
150                         rte_strerror(rc));
151                 goto fail_alloc_mport_alias;
152         }
153
154         TAILQ_INIT(&rp->ports);
155
156         sfc_log_init(sa, "done");
157
158         return 0;
159
160 fail_alloc_mport_alias:
161
162         sfc_log_init(sa, "failed: %s", rte_strerror(rc));
163         return rc;
164 }
165
166 void
167 sfc_repr_proxy_pre_detach(struct sfc_adapter *sa)
168 {
169         struct sfc_repr_proxy *rp = &sa->repr_proxy;
170         bool close_ports[RTE_MAX_ETHPORTS] = {0};
171         struct sfc_repr_proxy_port *port;
172         unsigned int i;
173
174         SFC_ASSERT(!sfc_adapter_is_locked(sa));
175
176         sfc_adapter_lock(sa);
177
178         if (sfc_repr_available(sfc_sa2shared(sa))) {
179                 TAILQ_FOREACH(port, &rp->ports, entries)
180                         close_ports[port->rte_port_id] = true;
181         } else {
182                 sfc_log_init(sa, "representors not supported - skip");
183         }
184
185         sfc_adapter_unlock(sa);
186
187         for (i = 0; i < RTE_DIM(close_ports); i++) {
188                 if (close_ports[i]) {
189                         rte_eth_dev_stop(i);
190                         rte_eth_dev_close(i);
191                 }
192         }
193 }
194
195 static void
196 sfc_repr_proxy_ports_fini(struct sfc_adapter *sa)
197 {
198         struct sfc_repr_proxy *rp = &sa->repr_proxy;
199
200         efx_mae_mport_free(sa->nic, &rp->mport_alias);
201 }
202
203 int
204 sfc_repr_proxy_attach(struct sfc_adapter *sa)
205 {
206         struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
207         struct sfc_repr_proxy *rp = &sa->repr_proxy;
208         struct rte_service_spec service;
209         uint32_t cid;
210         uint32_t sid;
211         int rc;
212
213         sfc_log_init(sa, "entry");
214
215         if (!sfc_repr_available(sas)) {
216                 sfc_log_init(sa, "representors not supported - skip");
217                 return 0;
218         }
219
220         rc = sfc_repr_proxy_ports_init(sa);
221         if (rc != 0)
222                 goto fail_ports_init;
223
224         cid = sfc_get_service_lcore(sa->socket_id);
225         if (cid == RTE_MAX_LCORE && sa->socket_id != SOCKET_ID_ANY) {
226                 /* Warn and try to allocate on any NUMA node */
227                 sfc_warn(sa,
228                         "repr proxy: unable to get service lcore at socket %d",
229                         sa->socket_id);
230
231                 cid = sfc_get_service_lcore(SOCKET_ID_ANY);
232         }
233         if (cid == RTE_MAX_LCORE) {
234                 rc = ENOTSUP;
235                 sfc_err(sa, "repr proxy: failed to get service lcore");
236                 goto fail_get_service_lcore;
237         }
238
239         memset(&service, 0, sizeof(service));
240         snprintf(service.name, sizeof(service.name),
241                  "net_sfc_%hu_repr_proxy", sfc_sa2shared(sa)->port_id);
242         service.socket_id = rte_lcore_to_socket_id(cid);
243         service.callback = sfc_repr_proxy_routine;
244         service.callback_userdata = rp;
245
246         rc = rte_service_component_register(&service, &sid);
247         if (rc != 0) {
248                 rc = ENOEXEC;
249                 sfc_err(sa, "repr proxy: failed to register service component");
250                 goto fail_register;
251         }
252
253         rc = rte_service_map_lcore_set(sid, cid, 1);
254         if (rc != 0) {
255                 rc = -rc;
256                 sfc_err(sa, "repr proxy: failed to map lcore");
257                 goto fail_map_lcore;
258         }
259
260         rp->service_core_id = cid;
261         rp->service_id = sid;
262
263         sfc_log_init(sa, "done");
264
265         return 0;
266
267 fail_map_lcore:
268         rte_service_component_unregister(sid);
269
270 fail_register:
271         /*
272          * No need to rollback service lcore get since
273          * it just makes socket_id based search and remembers it.
274          */
275
276 fail_get_service_lcore:
277         sfc_repr_proxy_ports_fini(sa);
278
279 fail_ports_init:
280         sfc_log_init(sa, "failed: %s", rte_strerror(rc));
281         return rc;
282 }
283
284 void
285 sfc_repr_proxy_detach(struct sfc_adapter *sa)
286 {
287         struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
288         struct sfc_repr_proxy *rp = &sa->repr_proxy;
289
290         sfc_log_init(sa, "entry");
291
292         if (!sfc_repr_available(sas)) {
293                 sfc_log_init(sa, "representors not supported - skip");
294                 return;
295         }
296
297         rte_service_map_lcore_set(rp->service_id, rp->service_core_id, 0);
298         rte_service_component_unregister(rp->service_id);
299         sfc_repr_proxy_ports_fini(sa);
300
301         sfc_log_init(sa, "done");
302 }
303
304 int
305 sfc_repr_proxy_start(struct sfc_adapter *sa)
306 {
307         struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
308         struct sfc_repr_proxy *rp = &sa->repr_proxy;
309         int rc;
310
311         sfc_log_init(sa, "entry");
312
313         /*
314          * The condition to start the proxy is insufficient. It will be
315          * complemented with representor port start/stop support.
316          */
317         if (!sfc_repr_available(sas)) {
318                 sfc_log_init(sa, "representors not supported - skip");
319                 return 0;
320         }
321
322         /* Service core may be in "stopped" state, start it */
323         rc = rte_service_lcore_start(rp->service_core_id);
324         if (rc != 0 && rc != -EALREADY) {
325                 rc = -rc;
326                 sfc_err(sa, "failed to start service core for %s: %s",
327                         rte_service_get_name(rp->service_id),
328                         rte_strerror(rc));
329                 goto fail_start_core;
330         }
331
332         /* Run the service */
333         rc = rte_service_component_runstate_set(rp->service_id, 1);
334         if (rc < 0) {
335                 rc = -rc;
336                 sfc_err(sa, "failed to run %s component: %s",
337                         rte_service_get_name(rp->service_id),
338                         rte_strerror(rc));
339                 goto fail_component_runstate_set;
340         }
341         rc = rte_service_runstate_set(rp->service_id, 1);
342         if (rc < 0) {
343                 rc = -rc;
344                 sfc_err(sa, "failed to run %s: %s",
345                         rte_service_get_name(rp->service_id),
346                         rte_strerror(rc));
347                 goto fail_runstate_set;
348         }
349
350         rp->started = true;
351
352         sfc_log_init(sa, "done");
353
354         return 0;
355
356 fail_runstate_set:
357         rte_service_component_runstate_set(rp->service_id, 0);
358
359 fail_component_runstate_set:
360         /* Service lcore may be shared and we never stop it */
361
362 fail_start_core:
363         sfc_log_init(sa, "failed: %s", rte_strerror(rc));
364         return rc;
365 }
366
367 void
368 sfc_repr_proxy_stop(struct sfc_adapter *sa)
369 {
370         struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
371         struct sfc_repr_proxy *rp = &sa->repr_proxy;
372         int rc;
373
374         sfc_log_init(sa, "entry");
375
376         if (!sfc_repr_available(sas)) {
377                 sfc_log_init(sa, "representors not supported - skip");
378                 return;
379         }
380
381         rc = rte_service_runstate_set(rp->service_id, 0);
382         if (rc < 0) {
383                 sfc_err(sa, "failed to stop %s: %s",
384                         rte_service_get_name(rp->service_id),
385                         rte_strerror(-rc));
386         }
387
388         rc = rte_service_component_runstate_set(rp->service_id, 0);
389         if (rc < 0) {
390                 sfc_err(sa, "failed to stop %s component: %s",
391                         rte_service_get_name(rp->service_id),
392                         rte_strerror(-rc));
393         }
394
395         /* Service lcore may be shared and we never stop it */
396
397         rp->started = false;
398
399         sfc_log_init(sa, "done");
400 }
401
402 static struct sfc_repr_proxy_port *
403 sfc_repr_proxy_find_port(struct sfc_repr_proxy *rp, uint16_t repr_id)
404 {
405         struct sfc_repr_proxy_port *port;
406
407         TAILQ_FOREACH(port, &rp->ports, entries) {
408                 if (port->repr_id == repr_id)
409                         return port;
410         }
411
412         return NULL;
413 }
414
415 int
416 sfc_repr_proxy_add_port(uint16_t pf_port_id, uint16_t repr_id,
417                         uint16_t rte_port_id, const efx_mport_sel_t *mport_sel)
418 {
419         struct sfc_repr_proxy_port *port;
420         struct sfc_repr_proxy *rp;
421         struct sfc_adapter *sa;
422         int rc;
423
424         sa = sfc_get_adapter_by_pf_port_id(pf_port_id);
425         rp = sfc_repr_proxy_by_adapter(sa);
426
427         sfc_log_init(sa, "entry");
428         TAILQ_FOREACH(port, &rp->ports, entries) {
429                 if (port->rte_port_id == rte_port_id) {
430                         rc = EEXIST;
431                         sfc_err(sa, "%s() failed: port exists", __func__);
432                         goto fail_port_exists;
433                 }
434         }
435
436         port = rte_zmalloc("sfc-repr-proxy-port", sizeof(*port),
437                            sa->socket_id);
438         if (port == NULL) {
439                 rc = ENOMEM;
440                 sfc_err(sa, "failed to alloc memory for proxy port");
441                 goto fail_alloc_port;
442         }
443
444         rc = efx_mae_mport_id_by_selector(sa->nic, mport_sel,
445                                           &port->egress_mport);
446         if (rc != 0) {
447                 sfc_err(sa,
448                         "failed get MAE mport id by selector (repr_id %u): %s",
449                         repr_id, rte_strerror(rc));
450                 goto fail_mport_id;
451         }
452
453         port->rte_port_id = rte_port_id;
454         port->repr_id = repr_id;
455
456         if (rp->started) {
457                 rc = sfc_repr_proxy_mbox_send(&rp->mbox, port,
458                                               SFC_REPR_PROXY_MBOX_ADD_PORT);
459                 if (rc != 0) {
460                         sfc_err(sa, "failed to add proxy port %u",
461                                 port->repr_id);
462                         goto fail_port_add;
463                 }
464         } else {
465                 TAILQ_INSERT_TAIL(&rp->ports, port, entries);
466         }
467
468         sfc_log_init(sa, "done");
469         sfc_put_adapter(sa);
470
471         return 0;
472
473 fail_port_add:
474 fail_mport_id:
475         rte_free(port);
476 fail_alloc_port:
477 fail_port_exists:
478         sfc_log_init(sa, "failed: %s", rte_strerror(rc));
479         sfc_put_adapter(sa);
480
481         return rc;
482 }
483
484 int
485 sfc_repr_proxy_del_port(uint16_t pf_port_id, uint16_t repr_id)
486 {
487         struct sfc_repr_proxy_port *port;
488         struct sfc_repr_proxy *rp;
489         struct sfc_adapter *sa;
490         int rc;
491
492         sa = sfc_get_adapter_by_pf_port_id(pf_port_id);
493         rp = sfc_repr_proxy_by_adapter(sa);
494
495         sfc_log_init(sa, "entry");
496
497         port = sfc_repr_proxy_find_port(rp, repr_id);
498         if (port == NULL) {
499                 sfc_err(sa, "failed: no such port");
500                 rc = ENOENT;
501                 goto fail_no_port;
502         }
503
504         if (rp->started) {
505                 rc = sfc_repr_proxy_mbox_send(&rp->mbox, port,
506                                               SFC_REPR_PROXY_MBOX_DEL_PORT);
507                 if (rc != 0) {
508                         sfc_err(sa, "failed to remove proxy port %u",
509                                 port->repr_id);
510                         goto fail_port_remove;
511                 }
512         } else {
513                 TAILQ_REMOVE(&rp->ports, port, entries);
514         }
515
516         rte_free(port);
517
518         sfc_log_init(sa, "done");
519
520         sfc_put_adapter(sa);
521
522         return 0;
523
524 fail_port_remove:
525 fail_no_port:
526         sfc_log_init(sa, "failed: %s", rte_strerror(rc));
527         sfc_put_adapter(sa);
528
529         return rc;
530 }