X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fsfc%2Fsfc_repr_proxy.c;h=d8934bab652d3b0e5bb2ffd12de1ad4e00e811c8;hb=d0f981a3efd8b3204f3d86d6ef55dabf7412298c;hp=6a89cca40ad8334c4e455fa56715a2881d071c37;hpb=155583abe63cee8ffb5fc4a276c03641f492d750;p=dpdk.git diff --git a/drivers/net/sfc/sfc_repr_proxy.c b/drivers/net/sfc/sfc_repr_proxy.c index 6a89cca40a..d8934bab65 100644 --- a/drivers/net/sfc/sfc_repr_proxy.c +++ b/drivers/net/sfc/sfc_repr_proxy.c @@ -15,6 +15,9 @@ #include "sfc_repr_proxy.h" #include "sfc_repr_proxy_api.h" #include "sfc.h" +#include "sfc_ev.h" +#include "sfc_rx.h" +#include "sfc_tx.h" /** * Amount of time to wait for the representor proxy routine (which is @@ -22,6 +25,12 @@ */ #define SFC_REPR_PROXY_MBOX_POLL_TIMEOUT_MS 1000 +/** + * Amount of time to wait for the representor proxy routine (which is + * running on a service core) to terminate after service core is stopped. + */ +#define SFC_REPR_PROXY_ROUTINE_TERMINATE_TIMEOUT_MS 10000 + static struct sfc_repr_proxy * sfc_repr_proxy_by_adapter(struct sfc_adapter *sa) { @@ -50,6 +59,19 @@ sfc_put_adapter(struct sfc_adapter *sa) sfc_adapter_unlock(sa); } +static struct sfc_repr_proxy_port * +sfc_repr_proxy_find_port(struct sfc_repr_proxy *rp, uint16_t repr_id) +{ + struct sfc_repr_proxy_port *port; + + TAILQ_FOREACH(port, &rp->ports, entries) { + if (port->repr_id == repr_id) + return port; + } + + return NULL; +} + static int sfc_repr_proxy_mbox_send(struct sfc_repr_proxy_mbox *mbox, struct sfc_repr_proxy_port *port, @@ -80,60 +102,606 @@ sfc_repr_proxy_mbox_send(struct sfc_repr_proxy_mbox *mbox, if (__atomic_load_n(&mbox->ack, __ATOMIC_ACQUIRE)) break; - rte_delay_ms(1); + rte_delay_ms(1); + } + + if (i == wait_ms) { + SFC_GENERIC_LOG(ERR, + "%s() failed to wait for representor proxy routine ack", + __func__); + return ETIMEDOUT; + } + + return 0; +} + +static void +sfc_repr_proxy_mbox_handle(struct sfc_repr_proxy *rp) +{ + struct sfc_repr_proxy_mbox *mbox = &rp->mbox; + + /* + * Paired with release ordering in sfc_repr_proxy_mbox_send() + * on marker set. + */ + if (!__atomic_load_n(&mbox->write_marker, __ATOMIC_ACQUIRE)) + return; + + mbox->write_marker = false; + + switch (mbox->op) { + case SFC_REPR_PROXY_MBOX_ADD_PORT: + TAILQ_INSERT_TAIL(&rp->ports, mbox->port, entries); + break; + case SFC_REPR_PROXY_MBOX_DEL_PORT: + TAILQ_REMOVE(&rp->ports, mbox->port, entries); + break; + case SFC_REPR_PROXY_MBOX_START_PORT: + mbox->port->started = true; + break; + case SFC_REPR_PROXY_MBOX_STOP_PORT: + mbox->port->started = false; + break; + default: + SFC_ASSERT(0); + return; + } + + /* + * Paired with acquire ordering in sfc_repr_proxy_mbox_send() + * on acknowledge read. + */ + __atomic_store_n(&mbox->ack, true, __ATOMIC_RELEASE); +} + +static void +sfc_repr_proxy_handle_tx(struct sfc_repr_proxy_dp_txq *rp_txq, + struct sfc_repr_proxy_txq *repr_txq) +{ + /* + * With multiple representor proxy queues configured it is + * possible that not all of the corresponding representor + * queues were created. Skip the queues that do not exist. + */ + if (repr_txq->ring == NULL) + return; + + if (rp_txq->available < RTE_DIM(rp_txq->tx_pkts)) { + rp_txq->available += + rte_ring_sc_dequeue_burst(repr_txq->ring, + (void **)(&rp_txq->tx_pkts[rp_txq->available]), + RTE_DIM(rp_txq->tx_pkts) - rp_txq->available, + NULL); + + if (rp_txq->available == rp_txq->transmitted) + return; + } + + rp_txq->transmitted += rp_txq->pkt_burst(rp_txq->dp, + &rp_txq->tx_pkts[rp_txq->transmitted], + rp_txq->available - rp_txq->transmitted); + + if (rp_txq->available == rp_txq->transmitted) { + rp_txq->available = 0; + rp_txq->transmitted = 0; + } +} + +static int32_t +sfc_repr_proxy_routine(void *arg) +{ + struct sfc_repr_proxy_port *port; + struct sfc_repr_proxy *rp = arg; + unsigned int i; + + sfc_repr_proxy_mbox_handle(rp); + + TAILQ_FOREACH(port, &rp->ports, entries) { + if (!port->started) + continue; + + for (i = 0; i < rp->nb_txq; i++) + sfc_repr_proxy_handle_tx(&rp->dp_txq[i], &port->txq[i]); + } + + return 0; +} + +static struct sfc_txq_info * +sfc_repr_proxy_txq_info_get(struct sfc_adapter *sa, unsigned int repr_queue_id) +{ + struct sfc_adapter_shared *sas = sfc_sa2shared(sa); + struct sfc_repr_proxy_dp_txq *dp_txq; + + SFC_ASSERT(repr_queue_id < sfc_repr_nb_txq(sas)); + dp_txq = &sa->repr_proxy.dp_txq[repr_queue_id]; + + return &sas->txq_info[dp_txq->sw_index]; +} + +static int +sfc_repr_proxy_txq_attach(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_repr_proxy *rp = &sa->repr_proxy; + unsigned int i; + + sfc_log_init(sa, "entry"); + + for (i = 0; i < sfc_repr_nb_txq(sas); i++) { + sfc_sw_index_t sw_index = sfc_repr_txq_sw_index(sas, i); + + rp->dp_txq[i].sw_index = sw_index; + } + + sfc_log_init(sa, "done"); + + return 0; +} + +static void +sfc_repr_proxy_txq_detach(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_repr_proxy *rp = &sa->repr_proxy; + unsigned int i; + + sfc_log_init(sa, "entry"); + + for (i = 0; i < sfc_repr_nb_txq(sas); i++) + rp->dp_txq[i].sw_index = 0; + + sfc_log_init(sa, "done"); +} + +int +sfc_repr_proxy_txq_init(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_repr_proxy *rp = &sa->repr_proxy; + const struct rte_eth_txconf tx_conf = { + .tx_free_thresh = SFC_REPR_PROXY_TXQ_FREE_THRESH, + }; + struct sfc_txq_info *txq_info; + unsigned int init_i; + unsigned int i; + int rc; + + sfc_log_init(sa, "entry"); + + if (!sfc_repr_available(sas)) { + sfc_log_init(sa, "representors not supported - skip"); + return 0; + } + + for (init_i = 0; init_i < sfc_repr_nb_txq(sas); init_i++) { + struct sfc_repr_proxy_dp_txq *txq = &rp->dp_txq[init_i]; + + txq_info = &sfc_sa2shared(sa)->txq_info[txq->sw_index]; + if (txq_info->state == SFC_TXQ_INITIALIZED) { + sfc_log_init(sa, + "representor proxy TxQ %u is already initialized - skip", + init_i); + continue; + } + + sfc_tx_qinit_info(sa, txq->sw_index); + + rc = sfc_tx_qinit(sa, txq->sw_index, + SFC_REPR_PROXY_TX_DESC_COUNT, sa->socket_id, + &tx_conf); + + if (rc != 0) { + sfc_err(sa, "failed to init representor proxy TxQ %u", + init_i); + goto fail_init; + } + } + + sfc_log_init(sa, "done"); + + return 0; + +fail_init: + for (i = 0; i < init_i; i++) { + struct sfc_repr_proxy_dp_txq *txq = &rp->dp_txq[i]; + + txq_info = &sfc_sa2shared(sa)->txq_info[txq->sw_index]; + if (txq_info->state == SFC_TXQ_INITIALIZED) + sfc_tx_qfini(sa, txq->sw_index); + } + sfc_log_init(sa, "failed: %s", rte_strerror(rc)); + + return rc; +} + +void +sfc_repr_proxy_txq_fini(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_repr_proxy *rp = &sa->repr_proxy; + struct sfc_txq_info *txq_info; + unsigned int i; + + sfc_log_init(sa, "entry"); + + if (!sfc_repr_available(sas)) { + sfc_log_init(sa, "representors not supported - skip"); + return; + } + + for (i = 0; i < sfc_repr_nb_txq(sas); i++) { + struct sfc_repr_proxy_dp_txq *txq = &rp->dp_txq[i]; + + txq_info = &sfc_sa2shared(sa)->txq_info[txq->sw_index]; + if (txq_info->state != SFC_TXQ_INITIALIZED) { + sfc_log_init(sa, + "representor proxy TxQ %u is already finalized - skip", + i); + continue; + } + + sfc_tx_qfini(sa, txq->sw_index); + } + + sfc_log_init(sa, "done"); +} + +static int +sfc_repr_proxy_txq_start(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_repr_proxy *rp = &sa->repr_proxy; + unsigned int i; + + sfc_log_init(sa, "entry"); + + for (i = 0; i < sfc_repr_nb_txq(sas); i++) { + struct sfc_repr_proxy_dp_txq *txq = &rp->dp_txq[i]; + + txq->dp = sfc_repr_proxy_txq_info_get(sa, i)->dp; + txq->pkt_burst = sa->eth_dev->tx_pkt_burst; + txq->available = 0; + txq->transmitted = 0; + } + + sfc_log_init(sa, "done"); + + return 0; +} + +static void +sfc_repr_proxy_txq_stop(struct sfc_adapter *sa) +{ + sfc_log_init(sa, "entry"); + sfc_log_init(sa, "done"); +} + +static int +sfc_repr_proxy_rxq_attach(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_repr_proxy *rp = &sa->repr_proxy; + unsigned int i; + + sfc_log_init(sa, "entry"); + + for (i = 0; i < sfc_repr_nb_rxq(sas); i++) { + sfc_sw_index_t sw_index = sfc_repr_rxq_sw_index(sas, i); + + rp->dp_rxq[i].sw_index = sw_index; + } + + sfc_log_init(sa, "done"); + + return 0; +} + +static void +sfc_repr_proxy_rxq_detach(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_repr_proxy *rp = &sa->repr_proxy; + unsigned int i; + + sfc_log_init(sa, "entry"); + + for (i = 0; i < sfc_repr_nb_rxq(sas); i++) + rp->dp_rxq[i].sw_index = 0; + + sfc_log_init(sa, "done"); +} + +static int +sfc_repr_proxy_rxq_init(struct sfc_adapter *sa, + struct sfc_repr_proxy_dp_rxq *rxq) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + uint16_t nb_rx_desc = SFC_REPR_PROXY_RX_DESC_COUNT; + struct sfc_rxq_info *rxq_info; + struct rte_eth_rxconf rxconf = { + .rx_free_thresh = SFC_REPR_PROXY_RXQ_REFILL_LEVEL, + .rx_drop_en = 1, + }; + int rc; + + sfc_log_init(sa, "entry"); + + rxq_info = &sas->rxq_info[rxq->sw_index]; + if (rxq_info->state & SFC_RXQ_INITIALIZED) { + sfc_log_init(sa, "RxQ is already initialized - skip"); + return 0; + } + + nb_rx_desc = RTE_MIN(nb_rx_desc, sa->rxq_max_entries); + nb_rx_desc = RTE_MAX(nb_rx_desc, sa->rxq_min_entries); + + rc = sfc_rx_qinit_info(sa, rxq->sw_index, EFX_RXQ_FLAG_INGRESS_MPORT); + if (rc != 0) { + sfc_err(sa, "failed to init representor proxy RxQ info"); + goto fail_repr_rxq_init_info; + } + + rc = sfc_rx_qinit(sa, rxq->sw_index, nb_rx_desc, sa->socket_id, &rxconf, + rxq->mp); + if (rc != 0) { + sfc_err(sa, "failed to init representor proxy RxQ"); + goto fail_repr_rxq_init; + } + + sfc_log_init(sa, "done"); + + return 0; + +fail_repr_rxq_init: +fail_repr_rxq_init_info: + sfc_log_init(sa, "failed: %s", rte_strerror(rc)); + + return rc; +} + +static void +sfc_repr_proxy_rxq_fini(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_repr_proxy *rp = &sa->repr_proxy; + struct sfc_rxq_info *rxq_info; + unsigned int i; + + sfc_log_init(sa, "entry"); + + if (!sfc_repr_available(sas)) { + sfc_log_init(sa, "representors not supported - skip"); + return; + } + + for (i = 0; i < sfc_repr_nb_rxq(sas); i++) { + struct sfc_repr_proxy_dp_rxq *rxq = &rp->dp_rxq[i]; + + rxq_info = &sas->rxq_info[rxq->sw_index]; + if (rxq_info->state != SFC_RXQ_INITIALIZED) { + sfc_log_init(sa, + "representor RxQ %u is already finalized - skip", + i); + continue; + } + + sfc_rx_qfini(sa, rxq->sw_index); + } + + sfc_log_init(sa, "done"); +} + +static void +sfc_repr_proxy_rxq_stop(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + unsigned int i; + + sfc_log_init(sa, "entry"); + + for (i = 0; i < sfc_repr_nb_rxq(sas); i++) + sfc_rx_qstop(sa, sa->repr_proxy.dp_rxq[i].sw_index); + + sfc_repr_proxy_rxq_fini(sa); + + sfc_log_init(sa, "done"); +} + +static int +sfc_repr_proxy_rxq_start(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_repr_proxy *rp = &sa->repr_proxy; + unsigned int i; + int rc; + + sfc_log_init(sa, "entry"); + + if (!sfc_repr_available(sas)) { + sfc_log_init(sa, "representors not supported - skip"); + return 0; + } + + for (i = 0; i < sfc_repr_nb_rxq(sas); i++) { + struct sfc_repr_proxy_dp_rxq *rxq = &rp->dp_rxq[i]; + + rc = sfc_repr_proxy_rxq_init(sa, rxq); + if (rc != 0) { + sfc_err(sa, "failed to init representor proxy RxQ %u", + i); + goto fail_init; + } + + rc = sfc_rx_qstart(sa, rxq->sw_index); + if (rc != 0) { + sfc_err(sa, "failed to start representor proxy RxQ %u", + i); + goto fail_start; + } + } + + sfc_log_init(sa, "done"); + + return 0; + +fail_start: +fail_init: + sfc_repr_proxy_rxq_stop(sa); + sfc_log_init(sa, "failed: %s", rte_strerror(rc)); + return rc; +} + +static int +sfc_repr_proxy_mae_rule_insert(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) +{ + struct sfc_repr_proxy *rp = &sa->repr_proxy; + efx_mport_sel_t mport_alias_selector; + efx_mport_sel_t mport_vf_selector; + struct sfc_mae_rule *mae_rule; + int rc; + + sfc_log_init(sa, "entry"); + + rc = efx_mae_mport_by_id(&port->egress_mport, + &mport_vf_selector); + if (rc != 0) { + sfc_err(sa, "failed to get VF mport for repr %u", + port->repr_id); + goto fail_get_vf; + } + + rc = efx_mae_mport_by_id(&rp->mport_alias, &mport_alias_selector); + if (rc != 0) { + sfc_err(sa, "failed to get mport selector for repr %u", + port->repr_id); + goto fail_get_alias; + } + + rc = sfc_mae_rule_add_mport_match_deliver(sa, &mport_vf_selector, + &mport_alias_selector, -1, + &mae_rule); + if (rc != 0) { + sfc_err(sa, "failed to insert MAE rule for repr %u", + port->repr_id); + goto fail_rule_add; + } + + port->mae_rule = mae_rule; + + sfc_log_init(sa, "done"); + + return 0; + +fail_rule_add: +fail_get_alias: +fail_get_vf: + sfc_log_init(sa, "failed: %s", rte_strerror(rc)); + return rc; +} + +static void +sfc_repr_proxy_mae_rule_remove(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) +{ + struct sfc_mae_rule *mae_rule = port->mae_rule; + + sfc_mae_rule_del(sa, mae_rule); +} + +static int +sfc_repr_proxy_mport_filter_insert(struct sfc_adapter *sa) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_repr_proxy *rp = &sa->repr_proxy; + struct sfc_rxq *rxq_ctrl; + struct sfc_repr_proxy_filter *filter = &rp->mport_filter; + efx_mport_sel_t mport_alias_selector; + static const efx_filter_match_flags_t flags[RTE_DIM(filter->specs)] = { + EFX_FILTER_MATCH_UNKNOWN_UCAST_DST, + EFX_FILTER_MATCH_UNKNOWN_MCAST_DST }; + unsigned int i; + int rc; + + sfc_log_init(sa, "entry"); + + if (sfc_repr_nb_rxq(sas) == 1) { + rxq_ctrl = &sa->rxq_ctrl[rp->dp_rxq[0].sw_index]; + } else { + sfc_err(sa, "multiple representor proxy RxQs not supported"); + rc = ENOTSUP; + goto fail_multiple_queues; } - if (i == wait_ms) { - SFC_GENERIC_LOG(ERR, - "%s() failed to wait for representor proxy routine ack", - __func__); - return ETIMEDOUT; + rc = efx_mae_mport_by_id(&rp->mport_alias, &mport_alias_selector); + if (rc != 0) { + sfc_err(sa, "failed to get repr proxy mport by ID"); + goto fail_get_selector; } + memset(filter->specs, 0, sizeof(filter->specs)); + for (i = 0; i < RTE_DIM(filter->specs); i++) { + filter->specs[i].efs_priority = EFX_FILTER_PRI_MANUAL; + filter->specs[i].efs_flags = EFX_FILTER_FLAG_RX; + filter->specs[i].efs_dmaq_id = rxq_ctrl->hw_index; + filter->specs[i].efs_match_flags = flags[i] | + EFX_FILTER_MATCH_MPORT; + filter->specs[i].efs_ingress_mport = mport_alias_selector.sel; + + rc = efx_filter_insert(sa->nic, &filter->specs[i]); + if (rc != 0) { + sfc_err(sa, "failed to insert repr proxy filter"); + goto fail_insert; + } + } + + sfc_log_init(sa, "done"); + return 0; + +fail_insert: + while (i-- > 0) + efx_filter_remove(sa->nic, &filter->specs[i]); + +fail_get_selector: +fail_multiple_queues: + sfc_log_init(sa, "failed: %s", rte_strerror(rc)); + return rc; } static void -sfc_repr_proxy_mbox_handle(struct sfc_repr_proxy *rp) +sfc_repr_proxy_mport_filter_remove(struct sfc_adapter *sa) { - struct sfc_repr_proxy_mbox *mbox = &rp->mbox; - - /* - * Paired with release ordering in sfc_repr_proxy_mbox_send() - * on marker set. - */ - if (!__atomic_load_n(&mbox->write_marker, __ATOMIC_ACQUIRE)) - return; - - mbox->write_marker = false; - - switch (mbox->op) { - case SFC_REPR_PROXY_MBOX_ADD_PORT: - TAILQ_INSERT_TAIL(&rp->ports, mbox->port, entries); - break; - case SFC_REPR_PROXY_MBOX_DEL_PORT: - TAILQ_REMOVE(&rp->ports, mbox->port, entries); - break; - default: - SFC_ASSERT(0); - return; - } + struct sfc_repr_proxy *rp = &sa->repr_proxy; + struct sfc_repr_proxy_filter *filter = &rp->mport_filter; + unsigned int i; - /* - * Paired with acquire ordering in sfc_repr_proxy_mbox_send() - * on acknowledge read. - */ - __atomic_store_n(&mbox->ack, true, __ATOMIC_RELEASE); + for (i = 0; i < RTE_DIM(filter->specs); i++) + efx_filter_remove(sa->nic, &filter->specs[i]); } -static int32_t -sfc_repr_proxy_routine(void *arg) +static int +sfc_repr_proxy_port_rule_insert(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) { - struct sfc_repr_proxy *rp = arg; + int rc; - sfc_repr_proxy_mbox_handle(rp); + rc = sfc_repr_proxy_mae_rule_insert(sa, port); + if (rc != 0) + goto fail_mae_rule_insert; return 0; + +fail_mae_rule_insert: + return rc; +} + +static void +sfc_repr_proxy_port_rule_remove(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) +{ + sfc_repr_proxy_mae_rule_remove(sa, port); } static int @@ -217,6 +785,14 @@ sfc_repr_proxy_attach(struct sfc_adapter *sa) return 0; } + rc = sfc_repr_proxy_rxq_attach(sa); + if (rc != 0) + goto fail_rxq_attach; + + rc = sfc_repr_proxy_txq_attach(sa); + if (rc != 0) + goto fail_txq_attach; + rc = sfc_repr_proxy_ports_init(sa); if (rc != 0) goto fail_ports_init; @@ -277,6 +853,12 @@ fail_get_service_lcore: sfc_repr_proxy_ports_fini(sa); fail_ports_init: + sfc_repr_proxy_txq_detach(sa); + +fail_txq_attach: + sfc_repr_proxy_rxq_detach(sa); + +fail_rxq_attach: sfc_log_init(sa, "failed: %s", rte_strerror(rc)); return rc; } @@ -297,28 +879,121 @@ sfc_repr_proxy_detach(struct sfc_adapter *sa) rte_service_map_lcore_set(rp->service_id, rp->service_core_id, 0); rte_service_component_unregister(rp->service_id); sfc_repr_proxy_ports_fini(sa); + sfc_repr_proxy_rxq_detach(sa); + sfc_repr_proxy_txq_detach(sa); sfc_log_init(sa, "done"); } +static int +sfc_repr_proxy_do_start_port(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) +{ + struct sfc_repr_proxy *rp = &sa->repr_proxy; + int rc; + + rc = sfc_repr_proxy_port_rule_insert(sa, port); + if (rc != 0) + goto fail_filter_insert; + + if (rp->started) { + rc = sfc_repr_proxy_mbox_send(&rp->mbox, port, + SFC_REPR_PROXY_MBOX_START_PORT); + if (rc != 0) { + sfc_err(sa, "failed to start proxy port %u", + port->repr_id); + goto fail_port_start; + } + } else { + port->started = true; + } + + return 0; + +fail_port_start: + sfc_repr_proxy_port_rule_remove(sa, port); +fail_filter_insert: + sfc_err(sa, "%s() failed %s", __func__, rte_strerror(rc)); + + return rc; +} + +static int +sfc_repr_proxy_do_stop_port(struct sfc_adapter *sa, + struct sfc_repr_proxy_port *port) + +{ + struct sfc_repr_proxy *rp = &sa->repr_proxy; + int rc; + + if (rp->started) { + rc = sfc_repr_proxy_mbox_send(&rp->mbox, port, + SFC_REPR_PROXY_MBOX_STOP_PORT); + if (rc != 0) { + sfc_err(sa, "failed to stop proxy port %u: %s", + port->repr_id, rte_strerror(rc)); + return rc; + } + } else { + port->started = false; + } + + sfc_repr_proxy_port_rule_remove(sa, port); + + return 0; +} + +static bool +sfc_repr_proxy_port_enabled(struct sfc_repr_proxy_port *port) +{ + return port->rte_port_id != RTE_MAX_ETHPORTS && port->enabled; +} + +static bool +sfc_repr_proxy_ports_disabled(struct sfc_repr_proxy *rp) +{ + struct sfc_repr_proxy_port *port; + + TAILQ_FOREACH(port, &rp->ports, entries) { + if (sfc_repr_proxy_port_enabled(port)) + return false; + } + + return true; +} + int sfc_repr_proxy_start(struct sfc_adapter *sa) { struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); struct sfc_repr_proxy *rp = &sa->repr_proxy; + struct sfc_repr_proxy_port *last_port = NULL; + struct sfc_repr_proxy_port *port; int rc; sfc_log_init(sa, "entry"); - /* - * The condition to start the proxy is insufficient. It will be - * complemented with representor port start/stop support. - */ + /* Representor proxy is not started when no representors are started */ if (!sfc_repr_available(sas)) { sfc_log_init(sa, "representors not supported - skip"); return 0; } + if (sfc_repr_proxy_ports_disabled(rp)) { + sfc_log_init(sa, "no started representor ports - skip"); + return 0; + } + + rc = sfc_repr_proxy_rxq_start(sa); + if (rc != 0) + goto fail_rxq_start; + + rc = sfc_repr_proxy_txq_start(sa); + if (rc != 0) + goto fail_txq_start; + + rp->nb_txq = sfc_repr_nb_txq(sas); + /* Service core may be in "stopped" state, start it */ rc = rte_service_lcore_start(rp->service_core_id); if (rc != 0 && rc != -EALREADY) { @@ -347,12 +1022,40 @@ sfc_repr_proxy_start(struct sfc_adapter *sa) goto fail_runstate_set; } + TAILQ_FOREACH(port, &rp->ports, entries) { + if (sfc_repr_proxy_port_enabled(port)) { + rc = sfc_repr_proxy_do_start_port(sa, port); + if (rc != 0) + goto fail_start_id; + + last_port = port; + } + } + + rc = sfc_repr_proxy_mport_filter_insert(sa); + if (rc != 0) + goto fail_mport_filter_insert; + rp->started = true; sfc_log_init(sa, "done"); return 0; +fail_mport_filter_insert: +fail_start_id: + if (last_port != NULL) { + TAILQ_FOREACH(port, &rp->ports, entries) { + if (sfc_repr_proxy_port_enabled(port)) { + (void)sfc_repr_proxy_do_stop_port(sa, port); + if (port == last_port) + break; + } + } + } + + rte_service_runstate_set(rp->service_id, 0); + fail_runstate_set: rte_service_component_runstate_set(rp->service_id, 0); @@ -360,6 +1063,12 @@ fail_component_runstate_set: /* Service lcore may be shared and we never stop it */ fail_start_core: + sfc_repr_proxy_txq_stop(sa); + +fail_txq_start: + sfc_repr_proxy_rxq_stop(sa); + +fail_rxq_start: sfc_log_init(sa, "failed: %s", rte_strerror(rc)); return rc; } @@ -369,6 +1078,10 @@ sfc_repr_proxy_stop(struct sfc_adapter *sa) { struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); struct sfc_repr_proxy *rp = &sa->repr_proxy; + struct sfc_repr_proxy_port *port; + const unsigned int wait_ms_total = + SFC_REPR_PROXY_ROUTINE_TERMINATE_TIMEOUT_MS; + unsigned int i; int rc; sfc_log_init(sa, "entry"); @@ -378,6 +1091,24 @@ sfc_repr_proxy_stop(struct sfc_adapter *sa) return; } + if (sfc_repr_proxy_ports_disabled(rp)) { + sfc_log_init(sa, "no started representor ports - skip"); + return; + } + + TAILQ_FOREACH(port, &rp->ports, entries) { + if (sfc_repr_proxy_port_enabled(port)) { + rc = sfc_repr_proxy_do_stop_port(sa, port); + if (rc != 0) { + sfc_err(sa, + "failed to stop representor proxy port %u: %s", + port->repr_id, rte_strerror(rc)); + } + } + } + + sfc_repr_proxy_mport_filter_remove(sa); + rc = rte_service_runstate_set(rp->service_id, 0); if (rc < 0) { sfc_err(sa, "failed to stop %s: %s", @@ -394,22 +1125,23 @@ sfc_repr_proxy_stop(struct sfc_adapter *sa) /* Service lcore may be shared and we never stop it */ - rp->started = false; + /* + * Wait for the representor proxy routine to finish the last iteration. + * Give up on timeout. + */ + for (i = 0; i < wait_ms_total; i++) { + if (rte_service_may_be_active(rp->service_id) == 0) + break; - sfc_log_init(sa, "done"); -} + rte_delay_ms(1); + } -static struct sfc_repr_proxy_port * -sfc_repr_proxy_find_port(struct sfc_repr_proxy *rp, uint16_t repr_id) -{ - struct sfc_repr_proxy_port *port; + sfc_repr_proxy_rxq_stop(sa); + sfc_repr_proxy_txq_stop(sa); - TAILQ_FOREACH(port, &rp->ports, entries) { - if (port->repr_id == repr_id) - return port; - } + rp->started = false; - return NULL; + sfc_log_init(sa, "done"); } int @@ -660,3 +1392,136 @@ sfc_repr_proxy_del_txq(uint16_t pf_port_id, uint16_t repr_id, sfc_log_init(sa, "done"); sfc_put_adapter(sa); } + +int +sfc_repr_proxy_start_repr(uint16_t pf_port_id, uint16_t repr_id) +{ + bool proxy_start_required = false; + struct sfc_repr_proxy_port *port; + struct sfc_repr_proxy *rp; + struct sfc_adapter *sa; + int rc; + + sa = sfc_get_adapter_by_pf_port_id(pf_port_id); + rp = sfc_repr_proxy_by_adapter(sa); + + sfc_log_init(sa, "entry"); + + port = sfc_repr_proxy_find_port(rp, repr_id); + if (port == NULL) { + sfc_err(sa, "%s() failed: no such port", __func__); + rc = ENOENT; + goto fail_not_found; + } + + if (port->enabled) { + rc = EALREADY; + sfc_err(sa, "failed: repr %u proxy port already started", + repr_id); + goto fail_already_started; + } + + if (sa->state == SFC_ETHDEV_STARTED) { + if (sfc_repr_proxy_ports_disabled(rp)) { + proxy_start_required = true; + } else { + rc = sfc_repr_proxy_do_start_port(sa, port); + if (rc != 0) { + sfc_err(sa, + "failed to start repr %u proxy port", + repr_id); + goto fail_start_id; + } + } + } + + port->enabled = true; + + if (proxy_start_required) { + rc = sfc_repr_proxy_start(sa); + if (rc != 0) { + sfc_err(sa, "failed to start proxy"); + goto fail_proxy_start; + } + } + + sfc_log_init(sa, "done"); + sfc_put_adapter(sa); + + return 0; + +fail_proxy_start: + port->enabled = false; + +fail_start_id: +fail_already_started: +fail_not_found: + sfc_err(sa, "failed to start repr %u proxy port: %s", repr_id, + rte_strerror(rc)); + sfc_put_adapter(sa); + + return rc; +} + +int +sfc_repr_proxy_stop_repr(uint16_t pf_port_id, uint16_t repr_id) +{ + struct sfc_repr_proxy_port *port; + struct sfc_repr_proxy_port *p; + struct sfc_repr_proxy *rp; + struct sfc_adapter *sa; + int rc; + + sa = sfc_get_adapter_by_pf_port_id(pf_port_id); + rp = sfc_repr_proxy_by_adapter(sa); + + sfc_log_init(sa, "entry"); + + port = sfc_repr_proxy_find_port(rp, repr_id); + if (port == NULL) { + sfc_err(sa, "%s() failed: no such port", __func__); + return ENOENT; + } + + if (!port->enabled) { + sfc_log_init(sa, "repr %u proxy port is not started - skip", + repr_id); + sfc_put_adapter(sa); + return 0; + } + + if (sa->state == SFC_ETHDEV_STARTED) { + bool last_enabled = true; + + TAILQ_FOREACH(p, &rp->ports, entries) { + if (p == port) + continue; + + if (sfc_repr_proxy_port_enabled(p)) { + last_enabled = false; + break; + } + } + + rc = 0; + if (last_enabled) + sfc_repr_proxy_stop(sa); + else + rc = sfc_repr_proxy_do_stop_port(sa, port); + + if (rc != 0) { + sfc_err(sa, + "failed to stop representor proxy TxQ %u: %s", + repr_id, rte_strerror(rc)); + sfc_put_adapter(sa); + return rc; + } + } + + port->enabled = false; + + sfc_log_init(sa, "done"); + sfc_put_adapter(sa); + + return 0; +}