From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id ABB95A00C5; Tue, 1 Feb 2022 09:50:12 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 7D208411DF; Tue, 1 Feb 2022 09:50:08 +0100 (CET) Received: from shelob.oktetlabs.ru (shelob.oktetlabs.ru [91.220.146.113]) by mails.dpdk.org (Postfix) with ESMTP id F28A240685 for ; Tue, 1 Feb 2022 09:50:05 +0100 (CET) Received: from bree.oktetlabs.ru (bree.oktetlabs.ru [192.168.34.5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by shelob.oktetlabs.ru (Postfix) with ESMTPS id 9E1A140; Tue, 1 Feb 2022 11:50:05 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 shelob.oktetlabs.ru 9E1A140 Authentication-Results: shelob.oktetlabs.ru/9E1A140; dkim=none; dkim-atps=neutral From: Ivan Malov To: dev@dpdk.org Cc: Andrew Rybchenko , Andy Moreton Subject: [PATCH 1/8] net/sfc: rework flow action RSS support Date: Tue, 1 Feb 2022 11:49:55 +0300 Message-Id: <20220201085002.320102-2-ivan.malov@oktetlabs.ru> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220201085002.320102-1-ivan.malov@oktetlabs.ru> References: <20220201085002.320102-1-ivan.malov@oktetlabs.ru> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Currently, the driver always allocates a dedicated NIC RSS context for every separate flow rule with action RSS, which is not optimal. First of all, multiple rules which have the same RSS specification can share a context since filters in the hardware operate this way. Secondly, entries in a context's indirection table are not precise queue IDs but offsets with regard to the base queue ID of a filter. This way, for example, queue arrays "0, 1, 2" and "3, 4, 5" in two otherwise identical RSS specifications allow the driver to use the same context since they both yield the same table of queue offsets. Rework flow action RSS support in order to use these optimisations. Signed-off-by: Ivan Malov Reviewed-by: Andrew Rybchenko Reviewed-by: Andy Moreton --- drivers/net/sfc/meson.build | 1 + drivers/net/sfc/sfc.c | 12 +- drivers/net/sfc/sfc.h | 4 +- drivers/net/sfc/sfc_ethdev.c | 8 +- drivers/net/sfc/sfc_flow.c | 249 ++++---------------- drivers/net/sfc/sfc_flow.h | 19 +- drivers/net/sfc/sfc_flow_rss.c | 409 +++++++++++++++++++++++++++++++++ drivers/net/sfc/sfc_flow_rss.h | 81 +++++++ 8 files changed, 562 insertions(+), 221 deletions(-) create mode 100644 drivers/net/sfc/sfc_flow_rss.c create mode 100644 drivers/net/sfc/sfc_flow_rss.h diff --git a/drivers/net/sfc/meson.build b/drivers/net/sfc/meson.build index 46d94184b8..547cb8db8c 100644 --- a/drivers/net/sfc/meson.build +++ b/drivers/net/sfc/meson.build @@ -90,6 +90,7 @@ sources = files( 'sfc_mae.c', 'sfc_mae_counter.c', 'sfc_flow.c', + 'sfc_flow_rss.c', 'sfc_flow_tunnel.c', 'sfc_dp.c', 'sfc_ef10_rx.c', diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c index 2cead4e045..51726d229b 100644 --- a/drivers/net/sfc/sfc.c +++ b/drivers/net/sfc/sfc.c @@ -848,7 +848,9 @@ sfc_rss_attach(struct sfc_adapter *sa) efx_intr_fini(sa->nic); rte_memcpy(rss->key, default_rss_key, sizeof(rss->key)); - rss->dummy_rss_context = EFX_RSS_CONTEXT_DEFAULT; + memset(&rss->dummy_ctx, 0, sizeof(rss->dummy_ctx)); + rss->dummy_ctx.conf.qid_span = 1; + rss->dummy_ctx.dummy = true; return 0; @@ -970,6 +972,10 @@ sfc_attach(struct sfc_adapter *sa) if (rc != 0) goto fail_rss_attach; + rc = sfc_flow_rss_attach(sa); + if (rc != 0) + goto fail_flow_rss_attach; + rc = sfc_filter_attach(sa); if (rc != 0) goto fail_filter_attach; @@ -1033,6 +1039,9 @@ sfc_attach(struct sfc_adapter *sa) sfc_filter_detach(sa); fail_filter_attach: + sfc_flow_rss_detach(sa); + +fail_flow_rss_attach: sfc_rss_detach(sa); fail_rss_attach: @@ -1087,6 +1096,7 @@ sfc_detach(struct sfc_adapter *sa) sfc_mae_detach(sa); sfc_mae_counter_rxq_detach(sa); sfc_filter_detach(sa); + sfc_flow_rss_detach(sa); sfc_rss_detach(sa); sfc_port_detach(sa); sfc_ev_detach(sa); diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h index 3337cb57e3..c075c01883 100644 --- a/drivers/net/sfc/sfc.h +++ b/drivers/net/sfc/sfc.h @@ -27,6 +27,7 @@ #include "sfc_debug.h" #include "sfc_log.h" #include "sfc_filter.h" +#include "sfc_flow_rss.h" #include "sfc_flow_tunnel.h" #include "sfc_sriov.h" #include "sfc_mae.h" @@ -118,7 +119,7 @@ struct sfc_rss { unsigned int tbl[EFX_RSS_TBL_SIZE]; uint8_t key[EFX_RSS_KEY_SIZE]; - uint32_t dummy_rss_context; + struct sfc_flow_rss_ctx dummy_ctx; }; /* Adapter private data shared by primary and secondary processes */ @@ -238,6 +239,7 @@ struct sfc_adapter { struct sfc_intr intr; struct sfc_port port; struct sfc_sw_stats sw_stats; + struct sfc_flow_rss flow_rss; /* Registry of tunnel offload contexts */ struct sfc_flow_tunnel flow_tunnels[SFC_FT_MAX_NTUNNELS]; struct sfc_filter filter; diff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c index d4210b63dd..abf7b8d287 100644 --- a/drivers/net/sfc/sfc_ethdev.c +++ b/drivers/net/sfc/sfc_ethdev.c @@ -1674,15 +1674,13 @@ sfc_dev_rss_hash_update(struct rte_eth_dev *dev, struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); struct sfc_rss *rss = &sfc_sa2shared(sa)->rss; unsigned int efx_hash_types; - uint32_t contexts[] = {EFX_RSS_CONTEXT_DEFAULT, rss->dummy_rss_context}; unsigned int n_contexts; unsigned int mode_i = 0; unsigned int key_i = 0; + uint32_t contexts[2]; unsigned int i = 0; int rc = 0; - n_contexts = rss->dummy_rss_context == EFX_RSS_CONTEXT_DEFAULT ? 1 : 2; - if (sfc_sa2shared(sa)->isolated) return -ENOTSUP; @@ -1709,6 +1707,10 @@ sfc_dev_rss_hash_update(struct rte_eth_dev *dev, if (rc != 0) goto fail_rx_hf_rte_to_efx; + contexts[0] = EFX_RSS_CONTEXT_DEFAULT; + contexts[1] = rss->dummy_ctx.nic_handle; + n_contexts = (rss->dummy_ctx.nic_handle_refcnt == 0) ? 1 : 2; + for (mode_i = 0; mode_i < n_contexts; mode_i++) { rc = efx_rx_scale_mode_set(sa->nic, contexts[mode_i], rss->hash_alg, efx_hash_types, diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c index 509fde4a86..bbb40a3b38 100644 --- a/drivers/net/sfc/sfc_flow.c +++ b/drivers/net/sfc/sfc_flow.c @@ -22,6 +22,7 @@ #include "sfc_rx.h" #include "sfc_filter.h" #include "sfc_flow.h" +#include "sfc_flow_rss.h" #include "sfc_flow_tunnel.h" #include "sfc_log.h" #include "sfc_dp_rx.h" @@ -41,11 +42,12 @@ static sfc_flow_parse_cb_t sfc_flow_parse_rte_to_filter; static sfc_flow_parse_cb_t sfc_flow_parse_rte_to_mae; static sfc_flow_insert_cb_t sfc_flow_filter_insert; static sfc_flow_remove_cb_t sfc_flow_filter_remove; +static sfc_flow_cleanup_cb_t sfc_flow_cleanup; static const struct sfc_flow_ops_by_spec sfc_flow_ops_filter = { .parse = sfc_flow_parse_rte_to_filter, .verify = NULL, - .cleanup = NULL, + .cleanup = sfc_flow_cleanup, .insert = sfc_flow_filter_insert, .remove = sfc_flow_filter_remove, .query = NULL, @@ -1429,8 +1431,14 @@ sfc_flow_parse_queue(struct sfc_adapter *sa, spec_filter->template.efs_dmaq_id = (uint16_t)rxq->hw_index; rxq_info = &sfc_sa2shared(sa)->rxq_info[queue->index]; - spec_filter->rss_hash_required = !!(rxq_info->rxq_flags & - SFC_RXQ_FLAG_RSS_HASH); + + if ((rxq_info->rxq_flags & SFC_RXQ_FLAG_RSS_HASH) != 0) { + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_rss *ethdev_rss = &sas->rss; + + spec_filter->template.efs_flags |= EFX_FILTER_FLAG_RX_RSS; + spec_filter->rss_ctx = ðdev_rss->dummy_ctx; + } return 0; } @@ -1440,107 +1448,30 @@ sfc_flow_parse_rss(struct sfc_adapter *sa, const struct rte_flow_action_rss *action_rss, struct rte_flow *flow) { - struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); - struct sfc_rss *rss = &sas->rss; - sfc_ethdev_qid_t ethdev_qid; + struct sfc_flow_spec_filter *spec_filter = &flow->spec.filter; + struct sfc_flow_rss_conf conf; + uint16_t sw_qid_min; struct sfc_rxq *rxq; - unsigned int rxq_hw_index_min; - unsigned int rxq_hw_index_max; - efx_rx_hash_type_t efx_hash_types; - const uint8_t *rss_key; - struct sfc_flow_spec *spec = &flow->spec; - struct sfc_flow_spec_filter *spec_filter = &spec->filter; - struct sfc_flow_rss *sfc_rss_conf = &spec_filter->rss_conf; - unsigned int i; - - if (action_rss->queue_num == 0) - return -EINVAL; - - ethdev_qid = sfc_sa2shared(sa)->ethdev_rxq_count - 1; - rxq = sfc_rxq_ctrl_by_ethdev_qid(sa, ethdev_qid); - rxq_hw_index_min = rxq->hw_index; - rxq_hw_index_max = 0; - - for (i = 0; i < action_rss->queue_num; ++i) { - ethdev_qid = action_rss->queue[i]; - - if ((unsigned int)ethdev_qid >= - sfc_sa2shared(sa)->ethdev_rxq_count) - return -EINVAL; - - rxq = sfc_rxq_ctrl_by_ethdev_qid(sa, ethdev_qid); - - if (rxq->hw_index < rxq_hw_index_min) - rxq_hw_index_min = rxq->hw_index; - - if (rxq->hw_index > rxq_hw_index_max) - rxq_hw_index_max = rxq->hw_index; - } + int rc; - if (rxq_hw_index_max - rxq_hw_index_min + 1 > EFX_MAXRSS) - return -EINVAL; + spec_filter->template.efs_flags |= EFX_FILTER_FLAG_RX_RSS; - switch (action_rss->func) { - case RTE_ETH_HASH_FUNCTION_DEFAULT: - case RTE_ETH_HASH_FUNCTION_TOEPLITZ: - break; - default: - return -EINVAL; - } + rc = sfc_flow_rss_parse_conf(sa, action_rss, &conf, &sw_qid_min); + if (rc != 0) + return -rc; - if (action_rss->level) - return -EINVAL; + rxq = sfc_rxq_ctrl_by_ethdev_qid(sa, sw_qid_min); + spec_filter->template.efs_dmaq_id = rxq->hw_index; - /* - * Dummy RSS action with only one queue and no specific settings - * for hash types and key does not require dedicated RSS context - * and may be simplified to single queue action. - */ - if (action_rss->queue_num == 1 && action_rss->types == 0 && - action_rss->key_len == 0) { - spec_filter->template.efs_dmaq_id = rxq_hw_index_min; + spec_filter->rss_ctx = sfc_flow_rss_ctx_reuse(sa, &conf, sw_qid_min, + action_rss->queue); + if (spec_filter->rss_ctx != NULL) return 0; - } - - if (action_rss->types) { - int rc; - - rc = sfc_rx_hf_rte_to_efx(sa, action_rss->types, - &efx_hash_types); - if (rc != 0) - return -rc; - } else { - unsigned int i; - - efx_hash_types = 0; - for (i = 0; i < rss->hf_map_nb_entries; ++i) - efx_hash_types |= rss->hf_map[i].efx; - } - - if (action_rss->key_len) { - if (action_rss->key_len != sizeof(rss->key)) - return -EINVAL; - - rss_key = action_rss->key; - } else { - rss_key = rss->key; - } - - spec_filter->rss = B_TRUE; - - sfc_rss_conf->rxq_hw_index_min = rxq_hw_index_min; - sfc_rss_conf->rxq_hw_index_max = rxq_hw_index_max; - sfc_rss_conf->rss_hash_types = efx_hash_types; - rte_memcpy(sfc_rss_conf->rss_key, rss_key, sizeof(rss->key)); - for (i = 0; i < RTE_DIM(sfc_rss_conf->rss_tbl); ++i) { - unsigned int nb_queues = action_rss->queue_num; - struct sfc_rxq *rxq; - - ethdev_qid = action_rss->queue[i % nb_queues]; - rxq = sfc_rxq_ctrl_by_ethdev_qid(sa, ethdev_qid); - sfc_rss_conf->rss_tbl[i] = rxq->hw_index - rxq_hw_index_min; - } + rc = sfc_flow_rss_ctx_add(sa, &conf, sw_qid_min, action_rss->queue, + &spec_filter->rss_ctx); + if (rc != 0) + return -rc; return 0; } @@ -1597,61 +1528,17 @@ static int sfc_flow_filter_insert(struct sfc_adapter *sa, struct rte_flow *flow) { - struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); - struct sfc_rss *rss = &sas->rss; struct sfc_flow_spec_filter *spec_filter = &flow->spec.filter; - struct sfc_flow_rss *flow_rss = &spec_filter->rss_conf; - uint32_t efs_rss_context = EFX_RSS_CONTEXT_DEFAULT; - boolean_t create_context; - unsigned int i; + struct sfc_flow_rss_ctx *rss_ctx = spec_filter->rss_ctx; int rc = 0; - create_context = spec_filter->rss || (spec_filter->rss_hash_required && - rss->dummy_rss_context == EFX_RSS_CONTEXT_DEFAULT); - - if (create_context) { - unsigned int rss_spread; - unsigned int rss_hash_types; - uint8_t *rss_key; - - if (spec_filter->rss) { - rss_spread = flow_rss->rxq_hw_index_max - - flow_rss->rxq_hw_index_min + 1; - rss_hash_types = flow_rss->rss_hash_types; - rss_key = flow_rss->rss_key; - } else { - /* - * Initialize dummy RSS context parameters to have - * valid RSS hash. Use default RSS hash function and - * key. - */ - rss_spread = 1; - rss_hash_types = rss->hash_types; - rss_key = rss->key; - } - - rc = efx_rx_scale_context_alloc(sa->nic, - EFX_RX_SCALE_EXCLUSIVE, - rss_spread, - &efs_rss_context); - if (rc != 0) - goto fail_scale_context_alloc; - - rc = efx_rx_scale_mode_set(sa->nic, efs_rss_context, - rss->hash_alg, - rss_hash_types, B_TRUE); - if (rc != 0) - goto fail_scale_mode_set; + rc = sfc_flow_rss_ctx_program(sa, rss_ctx); + if (rc != 0) + goto fail_rss_ctx_program; - rc = efx_rx_scale_key_set(sa->nic, efs_rss_context, - rss_key, sizeof(rss->key)); - if (rc != 0) - goto fail_scale_key_set; - } else { - efs_rss_context = rss->dummy_rss_context; - } + if (rss_ctx != NULL) { + unsigned int i; - if (spec_filter->rss || spec_filter->rss_hash_required) { /* * At this point, fully elaborated filter specifications * have been produced from the template. To make sure that @@ -1661,10 +1548,7 @@ sfc_flow_filter_insert(struct sfc_adapter *sa, for (i = 0; i < spec_filter->count; i++) { efx_filter_spec_t *spec = &spec_filter->filters[i]; - spec->efs_rss_context = efs_rss_context; - spec->efs_flags |= EFX_FILTER_FLAG_RX_RSS; - if (spec_filter->rss) - spec->efs_dmaq_id = flow_rss->rxq_hw_index_min; + spec->efs_rss_context = rss_ctx->nic_handle; } } @@ -1672,42 +1556,12 @@ sfc_flow_filter_insert(struct sfc_adapter *sa, if (rc != 0) goto fail_filter_insert; - if (create_context) { - unsigned int dummy_tbl[RTE_DIM(flow_rss->rss_tbl)] = {0}; - unsigned int *tbl; - - tbl = spec_filter->rss ? flow_rss->rss_tbl : dummy_tbl; - - /* - * Scale table is set after filter insertion because - * the table entries are relative to the base RxQ ID - * and the latter is submitted to the HW by means of - * inserting a filter, so by the time of the request - * the HW knows all the information needed to verify - * the table entries, and the operation will succeed - */ - rc = efx_rx_scale_tbl_set(sa->nic, efs_rss_context, - tbl, RTE_DIM(flow_rss->rss_tbl)); - if (rc != 0) - goto fail_scale_tbl_set; - - /* Remember created dummy RSS context */ - if (!spec_filter->rss) - rss->dummy_rss_context = efs_rss_context; - } - return 0; -fail_scale_tbl_set: - sfc_flow_spec_remove(sa, &flow->spec); - fail_filter_insert: -fail_scale_key_set: -fail_scale_mode_set: - if (create_context) - efx_rx_scale_context_free(sa->nic, efs_rss_context); + sfc_flow_rss_ctx_terminate(sa, rss_ctx); -fail_scale_context_alloc: +fail_rss_ctx_program: return rc; } @@ -1722,18 +1576,9 @@ sfc_flow_filter_remove(struct sfc_adapter *sa, if (rc != 0) return rc; - if (spec_filter->rss) { - /* - * All specifications for a given flow rule have the same RSS - * context, so that RSS context value is taken from the first - * filter specification - */ - efx_filter_spec_t *spec = &spec_filter->filters[0]; - - rc = efx_rx_scale_context_free(sa->nic, spec->efs_rss_context); - } + sfc_flow_rss_ctx_terminate(sa, spec_filter->rss_ctx); - return rc; + return 0; } static int @@ -2985,8 +2830,6 @@ sfc_flow_fini(struct sfc_adapter *sa) void sfc_flow_stop(struct sfc_adapter *sa) { - struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); - struct sfc_rss *rss = &sas->rss; struct rte_flow *flow; SFC_ASSERT(sfc_adapter_is_locked(sa)); @@ -2994,11 +2837,6 @@ sfc_flow_stop(struct sfc_adapter *sa) TAILQ_FOREACH(flow, &sa->flow_list, entries) sfc_flow_remove(sa, flow, NULL); - if (rss->dummy_rss_context != EFX_RSS_CONTEXT_DEFAULT) { - efx_rx_scale_context_free(sa->nic, rss->dummy_rss_context); - rss->dummy_rss_context = EFX_RSS_CONTEXT_DEFAULT; - } - /* * MAE counter service is not stopped on flow rule remove to avoid * extra work. Make sure that it is stopped here. @@ -3029,3 +2867,12 @@ sfc_flow_start(struct sfc_adapter *sa) fail_bad_flow: return rc; } + +static void +sfc_flow_cleanup(struct sfc_adapter *sa, struct rte_flow *flow) +{ + if (flow == NULL) + return; + + sfc_flow_rss_ctx_del(sa, flow->spec.filter.rss_ctx); +} diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h index efdecc97ab..545e2267d4 100644 --- a/drivers/net/sfc/sfc_flow.h +++ b/drivers/net/sfc/sfc_flow.h @@ -15,6 +15,8 @@ #include "efx.h" +#include "sfc_flow_rss.h" + #ifdef __cplusplus extern "C" { #endif @@ -30,15 +32,6 @@ extern "C" { #define SFC_BUILD_SET_OVERFLOW(_action, _set) \ RTE_BUILD_BUG_ON((_action) >= sizeof(_set) * CHAR_BIT) -/* RSS configuration storage */ -struct sfc_flow_rss { - unsigned int rxq_hw_index_min; - unsigned int rxq_hw_index_max; - unsigned int rss_hash_types; - uint8_t rss_key[EFX_RSS_KEY_SIZE]; - unsigned int rss_tbl[EFX_RSS_TBL_SIZE]; -}; - /* Flow engines supported by the implementation */ enum sfc_flow_spec_type { SFC_FLOW_SPEC_FILTER = 0, @@ -55,12 +48,8 @@ struct sfc_flow_spec_filter { efx_filter_spec_t filters[SF_FLOW_SPEC_NB_FILTERS_MAX]; /* number of complete specifications */ unsigned int count; - /* RSS toggle */ - boolean_t rss; - /* RSS hash toggle */ - boolean_t rss_hash_required; - /* RSS configuration */ - struct sfc_flow_rss rss_conf; + /* RSS context (or NULL) */ + struct sfc_flow_rss_ctx *rss_ctx; }; /* Indicates the role of a given flow in tunnel offload */ diff --git a/drivers/net/sfc/sfc_flow_rss.c b/drivers/net/sfc/sfc_flow_rss.c new file mode 100644 index 0000000000..17876f11c1 --- /dev/null +++ b/drivers/net/sfc/sfc_flow_rss.c @@ -0,0 +1,409 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022 Xilinx, Inc. + */ + +#include +#include + +#include +#include +#include + +#include "efx.h" + +#include "sfc.h" +#include "sfc_debug.h" +#include "sfc_flow_rss.h" +#include "sfc_log.h" +#include "sfc_rx.h" + +int +sfc_flow_rss_attach(struct sfc_adapter *sa) +{ + struct sfc_flow_rss *flow_rss = &sa->flow_rss; + + sfc_log_init(sa, "entry"); + + TAILQ_INIT(&flow_rss->ctx_list); + + sfc_log_init(sa, "done"); + + return 0; +} + +void +sfc_flow_rss_detach(struct sfc_adapter *sa) +{ + sfc_log_init(sa, "entry"); + + sfc_log_init(sa, "done"); +} + +int +sfc_flow_rss_parse_conf(struct sfc_adapter *sa, + const struct rte_flow_action_rss *in, + struct sfc_flow_rss_conf *out, uint16_t *sw_qid_minp) +{ + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + const struct sfc_rss *ethdev_rss = &sas->rss; + uint16_t sw_qid_min; + uint16_t sw_qid_max; + const uint8_t *key; + unsigned int i; + int rc; + + if (in->level) { + /* + * The caller demands that RSS hash be computed + * within the given encapsulation frame / level. + * Per flow control for that is not implemented. + */ + sfc_err(sa, "flow-rss: parse: 'level' must be 0"); + return EINVAL; + } + + if (in->types != 0) { + rc = sfc_rx_hf_rte_to_efx(sa, in->types, + &out->efx_hash_types); + if (rc != 0) { + sfc_err(sa, "flow-rss: parse: failed to process 'types'"); + return rc; + } + } else { + sfc_dbg(sa, "flow-rss: parse: 'types' is 0; proceeding with ethdev setting"); + out->efx_hash_types = ethdev_rss->hash_types; + } + + if (in->key_len != 0) { + if (in->key_len != sizeof(out->key)) { + sfc_err(sa, "flow-rss: parse: 'key_len' must be either %zu or 0", + sizeof(out->key)); + return EINVAL; + } + + if (in->key == NULL) { + sfc_err(sa, "flow-rss: parse: 'key' is NULL"); + return EINVAL; + } + + key = in->key; + } else { + sfc_dbg(sa, "flow-rss: parse: 'key_len' is 0; proceeding with ethdev key"); + key = ethdev_rss->key; + } + + rte_memcpy(out->key, key, sizeof(out->key)); + + switch (in->func) { + case RTE_ETH_HASH_FUNCTION_DEFAULT: + /* + * DEFAULT means that conformance to a specific + * hash algorithm is a don't care to the caller. + * The driver can pick the one it deems optimal. + */ + break; + case RTE_ETH_HASH_FUNCTION_TOEPLITZ: + if (ethdev_rss->hash_alg != EFX_RX_HASHALG_TOEPLITZ) { + sfc_err(sa, "flow-rss: parse: 'func' TOEPLITZ is unavailable; use DEFAULT"); + return EINVAL; + } + break; + default: + sfc_err(sa, "flow-rss: parse: 'func' #%d is unsupported", in->func); + return EINVAL; + } + + if (in->queue_num == 0) { + sfc_err(sa, "flow-rss: parse: 'queue_num' is 0; MIN=1"); + return EINVAL; + } + + if (in->queue_num > EFX_RSS_TBL_SIZE) { + sfc_err(sa, "flow-rss: parse: 'queue_num' is too large; MAX=%u", + EFX_RSS_TBL_SIZE); + return EINVAL; + } + + if (in->queue == NULL) { + sfc_err(sa, "flow-rss: parse: 'queue' is NULL"); + return EINVAL; + } + + sw_qid_min = sas->ethdev_rxq_count - 1; + sw_qid_max = 0; + + out->nb_qid_offsets = 0; + + for (i = 0; i < in->queue_num; ++i) { + uint16_t sw_qid = in->queue[i]; + + if (sw_qid >= sas->ethdev_rxq_count) { + sfc_err(sa, "flow-rss: parse: queue=%u does not exist", + sw_qid); + return EINVAL; + } + + if (sw_qid < sw_qid_min) + sw_qid_min = sw_qid; + + if (sw_qid > sw_qid_max) + sw_qid_max = sw_qid; + + if (sw_qid != in->queue[0] + i) + out->nb_qid_offsets = in->queue_num; + } + + out->qid_span = sw_qid_max - sw_qid_min + 1; + + if (out->qid_span > EFX_MAXRSS) { + sfc_err(sa, "flow-rss: parse: queue ID span %u is too large; MAX=%u", + out->qid_span, EFX_MAXRSS); + return EINVAL; + } + + if (sw_qid_minp != NULL) + *sw_qid_minp = sw_qid_min; + + return 0; +} + +struct sfc_flow_rss_ctx * +sfc_flow_rss_ctx_reuse(struct sfc_adapter *sa, + const struct sfc_flow_rss_conf *conf, + uint16_t sw_qid_min, const uint16_t *sw_qids) +{ + struct sfc_flow_rss *flow_rss = &sa->flow_rss; + static struct sfc_flow_rss_ctx *ctx; + + SFC_ASSERT(sfc_adapter_is_locked(sa)); + + TAILQ_FOREACH(ctx, &flow_rss->ctx_list, entries) { + if (memcmp(&ctx->conf, conf, sizeof(*conf)) != 0) + continue; + + if (conf->nb_qid_offsets != 0) { + bool match_confirmed = true; + unsigned int i; + + for (i = 0; i < conf->nb_qid_offsets; ++i) { + uint16_t qid_offset = sw_qids[i] - sw_qid_min; + + if (ctx->qid_offsets[i] != qid_offset) { + match_confirmed = false; + break; + } + } + + if (!match_confirmed) + continue; + } + + sfc_dbg(sa, "flow-rss: reusing ctx=%p", ctx); + ++(ctx->refcnt); + return ctx; + } + + return NULL; +} + +int +sfc_flow_rss_ctx_add(struct sfc_adapter *sa, + const struct sfc_flow_rss_conf *conf, uint16_t sw_qid_min, + const uint16_t *sw_qids, struct sfc_flow_rss_ctx **ctxp) +{ + struct sfc_flow_rss *flow_rss = &sa->flow_rss; + struct sfc_flow_rss_ctx *ctx; + + SFC_ASSERT(sfc_adapter_is_locked(sa)); + + ctx = rte_zmalloc("sfc_flow_rss_ctx", sizeof(*ctx), 0); + if (ctx == NULL) + return ENOMEM; + + if (conf->nb_qid_offsets != 0) { + unsigned int i; + + ctx->qid_offsets = rte_calloc("sfc_flow_rss_ctx_qid_offsets", + conf->nb_qid_offsets, + sizeof(*ctx->qid_offsets), 0); + if (ctx->qid_offsets == NULL) { + rte_free(ctx); + return ENOMEM; + } + + for (i = 0; i < conf->nb_qid_offsets; ++i) + ctx->qid_offsets[i] = sw_qids[i] - sw_qid_min; + } + + ctx->conf = *conf; + ctx->refcnt = 1; + + TAILQ_INSERT_TAIL(&flow_rss->ctx_list, ctx, entries); + + *ctxp = ctx; + + sfc_dbg(sa, "flow-rss: added ctx=%p", ctx); + + return 0; +} + +void +sfc_flow_rss_ctx_del(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx) +{ + struct sfc_flow_rss *flow_rss = &sa->flow_rss; + + if (ctx == NULL) + return; + + SFC_ASSERT(sfc_adapter_is_locked(sa)); + + if (ctx->dummy) + return; + + SFC_ASSERT(ctx->refcnt != 0); + + --(ctx->refcnt); + + if (ctx->refcnt != 0) + return; + + if (ctx->nic_handle_refcnt != 0) { + sfc_err(sa, "flow-rss: deleting ctx=%p abandons its NIC resource: handle=0x%08x, refcnt=%u", + ctx, ctx->nic_handle, ctx->nic_handle_refcnt); + } + + TAILQ_REMOVE(&flow_rss->ctx_list, ctx, entries); + rte_free(ctx->qid_offsets); + rte_free(ctx); + + sfc_dbg(sa, "flow-rss: deleted ctx=%p", ctx); +} + +static int +sfc_flow_rss_ctx_program_tbl(struct sfc_adapter *sa, + const struct sfc_flow_rss_ctx *ctx) +{ + const struct sfc_flow_rss_conf *conf = &ctx->conf; + unsigned int *tbl = sa->flow_rss.bounce_tbl; + unsigned int i; + + SFC_ASSERT(sfc_adapter_is_locked(sa)); + + if (conf->nb_qid_offsets != 0) { + SFC_ASSERT(ctx->qid_offsets != NULL); + + for (i = 0; i < EFX_RSS_TBL_SIZE; ++i) + tbl[i] = ctx->qid_offsets[i % conf->nb_qid_offsets]; + } else { + for (i = 0; i < EFX_RSS_TBL_SIZE; ++i) + tbl[i] = i % conf->qid_span; + } + + return efx_rx_scale_tbl_set(sa->nic, ctx->nic_handle, + tbl, EFX_RSS_TBL_SIZE); +} + +int +sfc_flow_rss_ctx_program(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx) +{ + efx_rx_scale_context_type_t ctx_type = EFX_RX_SCALE_EXCLUSIVE; + struct sfc_adapter_shared * const sas = sfc_sa2shared(sa); + struct sfc_rss *ethdev_rss = &sas->rss; + struct sfc_flow_rss_conf *conf; + bool allocation_done = B_FALSE; + int rc; + + if (ctx == NULL) + return 0; + + conf = &ctx->conf; + + SFC_ASSERT(sfc_adapter_is_locked(sa)); + + if (ctx->nic_handle_refcnt == 0) { + rc = efx_rx_scale_context_alloc(sa->nic, ctx_type, + conf->qid_span, + &ctx->nic_handle); + if (rc != 0) { + sfc_err(sa, "flow-rss: failed to allocate NIC resource for ctx=%p: type=%d, qid_span=%u, rc=%d", + ctx, ctx_type, conf->qid_span, rc); + goto fail; + } + + sfc_dbg(sa, "flow-rss: allocated NIC resource for ctx=%p: type=%d, qid_span=%u; handle=0x%08x", + ctx, ctx_type, conf->qid_span, + ctx->nic_handle); + + ++(ctx->nic_handle_refcnt); + allocation_done = B_TRUE; + } else { + ++(ctx->nic_handle_refcnt); + return 0; + } + + rc = efx_rx_scale_mode_set(sa->nic, ctx->nic_handle, + ethdev_rss->hash_alg, + (ctx->dummy) ? ethdev_rss->hash_types : + conf->efx_hash_types, + B_TRUE); + if (rc != 0) { + sfc_err(sa, "flow-rss: failed to configure hash for ctx=%p: efx_hash_alg=%d, efx_hash_types=0x%08x; rc=%d", + ctx, ethdev_rss->hash_alg, + (ctx->dummy) ? ethdev_rss->hash_types : + conf->efx_hash_types, + rc); + goto fail; + } + + rc = efx_rx_scale_key_set(sa->nic, ctx->nic_handle, + (ctx->dummy) ? ethdev_rss->key : conf->key, + RTE_DIM(conf->key)); + if (rc != 0) { + sfc_err(sa, "flow-rss: failed to set key for ctx=%p; rc=%d", + ctx, rc); + goto fail; + } + + rc = sfc_flow_rss_ctx_program_tbl(sa, ctx); + if (rc != 0) { + sfc_err(sa, "flow-rss: failed to program table for ctx=%p; rc=%d", + ctx, rc); + goto fail; + } + + return 0; + +fail: + if (allocation_done) + sfc_flow_rss_ctx_terminate(sa, ctx); + + return rc; +} + +void +sfc_flow_rss_ctx_terminate(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx) +{ + if (ctx == NULL) + return; + + SFC_ASSERT(sfc_adapter_is_locked(sa)); + + SFC_ASSERT(ctx->nic_handle_refcnt != 0); + --(ctx->nic_handle_refcnt); + + if (ctx->nic_handle_refcnt == 0) { + int rc; + + rc = efx_rx_scale_context_free(sa->nic, ctx->nic_handle); + if (rc != 0) { + sfc_err(sa, "flow-rss: failed to release NIC resource for ctx=%p: handle=0x%08x; rc=%d", + ctx, ctx->nic_handle, rc); + + sfc_warn(sa, "flow-rss: proceeding despite the prior error"); + } + + sfc_dbg(sa, "flow-rss: released NIC resource for ctx=%p; rc=%d", + ctx, rc); + } +} diff --git a/drivers/net/sfc/sfc_flow_rss.h b/drivers/net/sfc/sfc_flow_rss.h new file mode 100644 index 0000000000..cb2355ab67 --- /dev/null +++ b/drivers/net/sfc/sfc_flow_rss.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2022 Xilinx, Inc. + */ + +#ifndef _SFC_FLOW_RSS_H +#define _SFC_FLOW_RSS_H + +#include +#include + +#include +#include + +#include "efx.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct sfc_flow_rss_conf { + uint8_t key[EFX_RSS_KEY_SIZE]; + efx_rx_hash_type_t efx_hash_types; + unsigned int nb_qid_offsets; + unsigned int qid_span; +}; + +struct sfc_flow_rss_ctx { + TAILQ_ENTRY(sfc_flow_rss_ctx) entries; + + unsigned int refcnt; + bool dummy; + + unsigned int nic_handle_refcnt; + uint32_t nic_handle; + + struct sfc_flow_rss_conf conf; + + uint16_t *qid_offsets; +}; + +TAILQ_HEAD(sfc_flow_rss_ctx_list, sfc_flow_rss_ctx); + +struct sfc_flow_rss { + unsigned int bounce_tbl[EFX_RSS_TBL_SIZE]; + + struct sfc_flow_rss_ctx_list ctx_list; +}; + +struct sfc_adapter; + +int sfc_flow_rss_attach(struct sfc_adapter *sa); + +void sfc_flow_rss_detach(struct sfc_adapter *sa); + +int sfc_flow_rss_parse_conf(struct sfc_adapter *sa, + const struct rte_flow_action_rss *in, + struct sfc_flow_rss_conf *out, + uint16_t *sw_qid_minp); + +struct sfc_flow_rss_ctx *sfc_flow_rss_ctx_reuse(struct sfc_adapter *sa, + const struct sfc_flow_rss_conf *conf, + uint16_t sw_qid_min, const uint16_t *sw_qids); + +int sfc_flow_rss_ctx_add(struct sfc_adapter *sa, + const struct sfc_flow_rss_conf *conf, + uint16_t sw_qid_min, const uint16_t *sw_qids, + struct sfc_flow_rss_ctx **ctxp); + +void sfc_flow_rss_ctx_del(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx); + +int sfc_flow_rss_ctx_program(struct sfc_adapter *sa, + struct sfc_flow_rss_ctx *ctx); + +void sfc_flow_rss_ctx_terminate(struct sfc_adapter *sa, + struct sfc_flow_rss_ctx *ctx); + +#ifdef __cplusplus +} +#endif +#endif /* _SFC_FLOW_RSS_H */ -- 2.30.2