1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright(c) 2019-2021 Xilinx, Inc.
4 * Copyright(c) 2019 Solarflare Communications Inc.
6 * This software was jointly developed between OKTET Labs (under contract
7 * for Solarflare) and Solarflare Communications, Inc.
10 #include <rte_service.h>
11 #include <rte_service_component.h>
14 #include "sfc_service.h"
15 #include "sfc_repr_proxy.h"
16 #include "sfc_repr_proxy_api.h"
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.
23 #define SFC_REPR_PROXY_MBOX_POLL_TIMEOUT_MS 1000
25 static struct sfc_repr_proxy *
26 sfc_repr_proxy_by_adapter(struct sfc_adapter *sa)
28 return &sa->repr_proxy;
31 static struct sfc_adapter *
32 sfc_get_adapter_by_pf_port_id(uint16_t pf_port_id)
34 struct rte_eth_dev *dev;
35 struct sfc_adapter *sa;
37 SFC_ASSERT(pf_port_id < RTE_MAX_ETHPORTS);
39 dev = &rte_eth_devices[pf_port_id];
40 sa = sfc_adapter_by_eth_dev(dev);
48 sfc_put_adapter(struct sfc_adapter *sa)
50 sfc_adapter_unlock(sa);
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)
58 const unsigned int wait_ms = SFC_REPR_PROXY_MBOX_POLL_TIMEOUT_MS;
66 * Release ordering enforces marker set after data is populated.
67 * Paired with acquire ordering in sfc_repr_proxy_mbox_handle().
69 __atomic_store_n(&mbox->write_marker, true, __ATOMIC_RELEASE);
72 * Wait for the representor routine to process the request.
75 for (i = 0; i < wait_ms; i++) {
77 * Paired with release ordering in sfc_repr_proxy_mbox_handle()
78 * on acknowledge write.
80 if (__atomic_load_n(&mbox->ack, __ATOMIC_ACQUIRE))
88 "%s() failed to wait for representor proxy routine ack",
97 sfc_repr_proxy_mbox_handle(struct sfc_repr_proxy *rp)
99 struct sfc_repr_proxy_mbox *mbox = &rp->mbox;
102 * Paired with release ordering in sfc_repr_proxy_mbox_send()
105 if (!__atomic_load_n(&mbox->write_marker, __ATOMIC_ACQUIRE))
108 mbox->write_marker = false;
111 case SFC_REPR_PROXY_MBOX_ADD_PORT:
112 TAILQ_INSERT_TAIL(&rp->ports, mbox->port, entries);
114 case SFC_REPR_PROXY_MBOX_DEL_PORT:
115 TAILQ_REMOVE(&rp->ports, mbox->port, entries);
123 * Paired with acquire ordering in sfc_repr_proxy_mbox_send()
124 * on acknowledge read.
126 __atomic_store_n(&mbox->ack, true, __ATOMIC_RELEASE);
130 sfc_repr_proxy_routine(void *arg)
132 struct sfc_repr_proxy *rp = arg;
134 sfc_repr_proxy_mbox_handle(rp);
140 sfc_repr_proxy_ports_init(struct sfc_adapter *sa)
142 struct sfc_repr_proxy *rp = &sa->repr_proxy;
145 sfc_log_init(sa, "entry");
147 rc = efx_mcdi_mport_alloc_alias(sa->nic, &rp->mport_alias, NULL);
149 sfc_err(sa, "failed to alloc mport alias: %s",
151 goto fail_alloc_mport_alias;
154 TAILQ_INIT(&rp->ports);
156 sfc_log_init(sa, "done");
160 fail_alloc_mport_alias:
162 sfc_log_init(sa, "failed: %s", rte_strerror(rc));
167 sfc_repr_proxy_pre_detach(struct sfc_adapter *sa)
169 struct sfc_repr_proxy *rp = &sa->repr_proxy;
170 bool close_ports[RTE_MAX_ETHPORTS] = {0};
171 struct sfc_repr_proxy_port *port;
174 SFC_ASSERT(!sfc_adapter_is_locked(sa));
176 sfc_adapter_lock(sa);
178 if (sfc_repr_available(sfc_sa2shared(sa))) {
179 TAILQ_FOREACH(port, &rp->ports, entries)
180 close_ports[port->rte_port_id] = true;
182 sfc_log_init(sa, "representors not supported - skip");
185 sfc_adapter_unlock(sa);
187 for (i = 0; i < RTE_DIM(close_ports); i++) {
188 if (close_ports[i]) {
190 rte_eth_dev_close(i);
196 sfc_repr_proxy_ports_fini(struct sfc_adapter *sa)
198 struct sfc_repr_proxy *rp = &sa->repr_proxy;
200 efx_mae_mport_free(sa->nic, &rp->mport_alias);
204 sfc_repr_proxy_attach(struct sfc_adapter *sa)
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;
213 sfc_log_init(sa, "entry");
215 if (!sfc_repr_available(sas)) {
216 sfc_log_init(sa, "representors not supported - skip");
220 rc = sfc_repr_proxy_ports_init(sa);
222 goto fail_ports_init;
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 */
228 "repr proxy: unable to get service lcore at socket %d",
231 cid = sfc_get_service_lcore(SOCKET_ID_ANY);
233 if (cid == RTE_MAX_LCORE) {
235 sfc_err(sa, "repr proxy: failed to get service lcore");
236 goto fail_get_service_lcore;
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;
246 rc = rte_service_component_register(&service, &sid);
249 sfc_err(sa, "repr proxy: failed to register service component");
253 rc = rte_service_map_lcore_set(sid, cid, 1);
256 sfc_err(sa, "repr proxy: failed to map lcore");
260 rp->service_core_id = cid;
261 rp->service_id = sid;
263 sfc_log_init(sa, "done");
268 rte_service_component_unregister(sid);
272 * No need to rollback service lcore get since
273 * it just makes socket_id based search and remembers it.
276 fail_get_service_lcore:
277 sfc_repr_proxy_ports_fini(sa);
280 sfc_log_init(sa, "failed: %s", rte_strerror(rc));
285 sfc_repr_proxy_detach(struct sfc_adapter *sa)
287 struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
288 struct sfc_repr_proxy *rp = &sa->repr_proxy;
290 sfc_log_init(sa, "entry");
292 if (!sfc_repr_available(sas)) {
293 sfc_log_init(sa, "representors not supported - skip");
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);
301 sfc_log_init(sa, "done");
305 sfc_repr_proxy_start(struct sfc_adapter *sa)
307 struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
308 struct sfc_repr_proxy *rp = &sa->repr_proxy;
311 sfc_log_init(sa, "entry");
314 * The condition to start the proxy is insufficient. It will be
315 * complemented with representor port start/stop support.
317 if (!sfc_repr_available(sas)) {
318 sfc_log_init(sa, "representors not supported - skip");
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) {
326 sfc_err(sa, "failed to start service core for %s: %s",
327 rte_service_get_name(rp->service_id),
329 goto fail_start_core;
332 /* Run the service */
333 rc = rte_service_component_runstate_set(rp->service_id, 1);
336 sfc_err(sa, "failed to run %s component: %s",
337 rte_service_get_name(rp->service_id),
339 goto fail_component_runstate_set;
341 rc = rte_service_runstate_set(rp->service_id, 1);
344 sfc_err(sa, "failed to run %s: %s",
345 rte_service_get_name(rp->service_id),
347 goto fail_runstate_set;
352 sfc_log_init(sa, "done");
357 rte_service_component_runstate_set(rp->service_id, 0);
359 fail_component_runstate_set:
360 /* Service lcore may be shared and we never stop it */
363 sfc_log_init(sa, "failed: %s", rte_strerror(rc));
368 sfc_repr_proxy_stop(struct sfc_adapter *sa)
370 struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
371 struct sfc_repr_proxy *rp = &sa->repr_proxy;
374 sfc_log_init(sa, "entry");
376 if (!sfc_repr_available(sas)) {
377 sfc_log_init(sa, "representors not supported - skip");
381 rc = rte_service_runstate_set(rp->service_id, 0);
383 sfc_err(sa, "failed to stop %s: %s",
384 rte_service_get_name(rp->service_id),
388 rc = rte_service_component_runstate_set(rp->service_id, 0);
390 sfc_err(sa, "failed to stop %s component: %s",
391 rte_service_get_name(rp->service_id),
395 /* Service lcore may be shared and we never stop it */
399 sfc_log_init(sa, "done");
402 static struct sfc_repr_proxy_port *
403 sfc_repr_proxy_find_port(struct sfc_repr_proxy *rp, uint16_t repr_id)
405 struct sfc_repr_proxy_port *port;
407 TAILQ_FOREACH(port, &rp->ports, entries) {
408 if (port->repr_id == repr_id)
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)
419 struct sfc_repr_proxy_port *port;
420 struct sfc_repr_proxy *rp;
421 struct sfc_adapter *sa;
424 sa = sfc_get_adapter_by_pf_port_id(pf_port_id);
425 rp = sfc_repr_proxy_by_adapter(sa);
427 sfc_log_init(sa, "entry");
428 TAILQ_FOREACH(port, &rp->ports, entries) {
429 if (port->rte_port_id == rte_port_id) {
431 sfc_err(sa, "%s() failed: port exists", __func__);
432 goto fail_port_exists;
436 port = rte_zmalloc("sfc-repr-proxy-port", sizeof(*port),
440 sfc_err(sa, "failed to alloc memory for proxy port");
441 goto fail_alloc_port;
444 rc = efx_mae_mport_id_by_selector(sa->nic, mport_sel,
445 &port->egress_mport);
448 "failed get MAE mport id by selector (repr_id %u): %s",
449 repr_id, rte_strerror(rc));
453 port->rte_port_id = rte_port_id;
454 port->repr_id = repr_id;
457 rc = sfc_repr_proxy_mbox_send(&rp->mbox, port,
458 SFC_REPR_PROXY_MBOX_ADD_PORT);
460 sfc_err(sa, "failed to add proxy port %u",
465 TAILQ_INSERT_TAIL(&rp->ports, port, entries);
468 sfc_log_init(sa, "done");
478 sfc_log_init(sa, "failed: %s", rte_strerror(rc));
485 sfc_repr_proxy_del_port(uint16_t pf_port_id, uint16_t repr_id)
487 struct sfc_repr_proxy_port *port;
488 struct sfc_repr_proxy *rp;
489 struct sfc_adapter *sa;
492 sa = sfc_get_adapter_by_pf_port_id(pf_port_id);
493 rp = sfc_repr_proxy_by_adapter(sa);
495 sfc_log_init(sa, "entry");
497 port = sfc_repr_proxy_find_port(rp, repr_id);
499 sfc_err(sa, "failed: no such port");
505 rc = sfc_repr_proxy_mbox_send(&rp->mbox, port,
506 SFC_REPR_PROXY_MBOX_DEL_PORT);
508 sfc_err(sa, "failed to remove proxy port %u",
510 goto fail_port_remove;
513 TAILQ_REMOVE(&rp->ports, port, entries);
518 sfc_log_init(sa, "done");
526 sfc_log_init(sa, "failed: %s", rte_strerror(rc));
533 sfc_repr_proxy_add_rxq(uint16_t pf_port_id, uint16_t repr_id,
534 uint16_t queue_id, struct rte_ring *rx_ring,
535 struct rte_mempool *mp)
537 struct sfc_repr_proxy_port *port;
538 struct sfc_repr_proxy_rxq *rxq;
539 struct sfc_repr_proxy *rp;
540 struct sfc_adapter *sa;
542 sa = sfc_get_adapter_by_pf_port_id(pf_port_id);
543 rp = sfc_repr_proxy_by_adapter(sa);
545 sfc_log_init(sa, "entry");
547 port = sfc_repr_proxy_find_port(rp, repr_id);
549 sfc_err(sa, "%s() failed: no such port", __func__);
553 rxq = &port->rxq[queue_id];
554 if (rp->dp_rxq[queue_id].mp != NULL && rp->dp_rxq[queue_id].mp != mp) {
555 sfc_err(sa, "multiple mempools per queue are not supported");
562 rp->dp_rxq[queue_id].mp = mp;
563 rp->dp_rxq[queue_id].ref_count++;
565 sfc_log_init(sa, "done");
572 sfc_repr_proxy_del_rxq(uint16_t pf_port_id, uint16_t repr_id,
575 struct sfc_repr_proxy_port *port;
576 struct sfc_repr_proxy_rxq *rxq;
577 struct sfc_repr_proxy *rp;
578 struct sfc_adapter *sa;
580 sa = sfc_get_adapter_by_pf_port_id(pf_port_id);
581 rp = sfc_repr_proxy_by_adapter(sa);
583 sfc_log_init(sa, "entry");
585 port = sfc_repr_proxy_find_port(rp, repr_id);
587 sfc_err(sa, "%s() failed: no such port", __func__);
591 rxq = &port->rxq[queue_id];
595 rp->dp_rxq[queue_id].ref_count--;
596 if (rp->dp_rxq[queue_id].ref_count == 0)
597 rp->dp_rxq[queue_id].mp = NULL;
599 sfc_log_init(sa, "done");
604 sfc_repr_proxy_add_txq(uint16_t pf_port_id, uint16_t repr_id,
605 uint16_t queue_id, struct rte_ring *tx_ring,
606 efx_mport_id_t *egress_mport)
608 struct sfc_repr_proxy_port *port;
609 struct sfc_repr_proxy_txq *txq;
610 struct sfc_repr_proxy *rp;
611 struct sfc_adapter *sa;
613 sa = sfc_get_adapter_by_pf_port_id(pf_port_id);
614 rp = sfc_repr_proxy_by_adapter(sa);
616 sfc_log_init(sa, "entry");
618 port = sfc_repr_proxy_find_port(rp, repr_id);
620 sfc_err(sa, "%s() failed: no such port", __func__);
624 txq = &port->txq[queue_id];
628 *egress_mport = port->egress_mport;
630 sfc_log_init(sa, "done");
637 sfc_repr_proxy_del_txq(uint16_t pf_port_id, uint16_t repr_id,
640 struct sfc_repr_proxy_port *port;
641 struct sfc_repr_proxy_txq *txq;
642 struct sfc_repr_proxy *rp;
643 struct sfc_adapter *sa;
645 sa = sfc_get_adapter_by_pf_port_id(pf_port_id);
646 rp = sfc_repr_proxy_by_adapter(sa);
648 sfc_log_init(sa, "entry");
650 port = sfc_repr_proxy_find_port(rp, repr_id);
652 sfc_err(sa, "%s() failed: no such port", __func__);
656 txq = &port->txq[queue_id];
660 sfc_log_init(sa, "done");