1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright(c) 2022 Xilinx, Inc.
9 #include <rte_common.h>
11 #include <rte_tailq.h>
16 #include "sfc_debug.h"
17 #include "sfc_flow_rss.h"
22 sfc_flow_rss_attach(struct sfc_adapter *sa)
24 struct sfc_flow_rss *flow_rss = &sa->flow_rss;
26 sfc_log_init(sa, "entry");
28 TAILQ_INIT(&flow_rss->ctx_list);
30 sfc_log_init(sa, "done");
36 sfc_flow_rss_detach(struct sfc_adapter *sa)
38 sfc_log_init(sa, "entry");
40 sfc_log_init(sa, "done");
44 sfc_flow_rss_parse_conf(struct sfc_adapter *sa,
45 const struct rte_flow_action_rss *in,
46 struct sfc_flow_rss_conf *out, uint16_t *sw_qid_minp)
48 struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
49 const struct sfc_rss *ethdev_rss = &sas->rss;
58 * The caller demands that RSS hash be computed
59 * within the given encapsulation frame / level.
60 * Per flow control for that is not implemented.
62 sfc_err(sa, "flow-rss: parse: 'level' must be 0");
67 rc = sfc_rx_hf_rte_to_efx(sa, in->types,
68 &out->efx_hash_types);
70 sfc_err(sa, "flow-rss: parse: failed to process 'types'");
74 sfc_dbg(sa, "flow-rss: parse: 'types' is 0; proceeding with ethdev setting");
75 out->efx_hash_types = ethdev_rss->hash_types;
78 if (in->key_len != 0) {
79 if (in->key_len != sizeof(out->key)) {
80 sfc_err(sa, "flow-rss: parse: 'key_len' must be either %zu or 0",
85 if (in->key == NULL) {
86 sfc_err(sa, "flow-rss: parse: 'key' is NULL");
92 sfc_dbg(sa, "flow-rss: parse: 'key_len' is 0; proceeding with ethdev key");
93 key = ethdev_rss->key;
96 rte_memcpy(out->key, key, sizeof(out->key));
99 case RTE_ETH_HASH_FUNCTION_DEFAULT:
101 * DEFAULT means that conformance to a specific
102 * hash algorithm is a don't care to the caller.
103 * The driver can pick the one it deems optimal.
106 case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
107 if (ethdev_rss->hash_alg != EFX_RX_HASHALG_TOEPLITZ) {
108 sfc_err(sa, "flow-rss: parse: 'func' TOEPLITZ is unavailable; use DEFAULT");
113 sfc_err(sa, "flow-rss: parse: 'func' #%d is unsupported", in->func);
117 if (in->queue_num == 0) {
118 sfc_err(sa, "flow-rss: parse: 'queue_num' is 0; MIN=1");
122 if (in->queue_num > EFX_RSS_TBL_SIZE) {
123 sfc_err(sa, "flow-rss: parse: 'queue_num' is too large; MAX=%u",
128 if (in->queue == NULL) {
129 sfc_err(sa, "flow-rss: parse: 'queue' is NULL");
133 sw_qid_min = sas->ethdev_rxq_count - 1;
136 out->nb_qid_offsets = 0;
138 for (i = 0; i < in->queue_num; ++i) {
139 uint16_t sw_qid = in->queue[i];
141 if (sw_qid >= sas->ethdev_rxq_count) {
142 sfc_err(sa, "flow-rss: parse: queue=%u does not exist",
147 if (sw_qid < sw_qid_min)
150 if (sw_qid > sw_qid_max)
153 if (sw_qid != in->queue[0] + i)
154 out->nb_qid_offsets = in->queue_num;
157 out->qid_span = sw_qid_max - sw_qid_min + 1;
159 if (out->qid_span > EFX_MAXRSS) {
160 sfc_err(sa, "flow-rss: parse: queue ID span %u is too large; MAX=%u",
161 out->qid_span, EFX_MAXRSS);
165 if (sw_qid_minp != NULL)
166 *sw_qid_minp = sw_qid_min;
171 struct sfc_flow_rss_ctx *
172 sfc_flow_rss_ctx_reuse(struct sfc_adapter *sa,
173 const struct sfc_flow_rss_conf *conf,
174 uint16_t sw_qid_min, const uint16_t *sw_qids)
176 struct sfc_flow_rss *flow_rss = &sa->flow_rss;
177 static struct sfc_flow_rss_ctx *ctx;
179 SFC_ASSERT(sfc_adapter_is_locked(sa));
181 TAILQ_FOREACH(ctx, &flow_rss->ctx_list, entries) {
182 if (memcmp(&ctx->conf, conf, sizeof(*conf)) != 0)
185 if (conf->nb_qid_offsets != 0) {
186 bool match_confirmed = true;
189 for (i = 0; i < conf->nb_qid_offsets; ++i) {
190 uint16_t qid_offset = sw_qids[i] - sw_qid_min;
192 if (ctx->qid_offsets[i] != qid_offset) {
193 match_confirmed = false;
198 if (!match_confirmed)
202 sfc_dbg(sa, "flow-rss: reusing ctx=%p", ctx);
211 sfc_flow_rss_ctx_add(struct sfc_adapter *sa,
212 const struct sfc_flow_rss_conf *conf, uint16_t sw_qid_min,
213 const uint16_t *sw_qids, struct sfc_flow_rss_ctx **ctxp)
215 struct sfc_flow_rss *flow_rss = &sa->flow_rss;
216 struct sfc_flow_rss_ctx *ctx;
218 SFC_ASSERT(sfc_adapter_is_locked(sa));
220 ctx = rte_zmalloc("sfc_flow_rss_ctx", sizeof(*ctx), 0);
224 if (conf->nb_qid_offsets != 0) {
227 ctx->qid_offsets = rte_calloc("sfc_flow_rss_ctx_qid_offsets",
228 conf->nb_qid_offsets,
229 sizeof(*ctx->qid_offsets), 0);
230 if (ctx->qid_offsets == NULL) {
235 for (i = 0; i < conf->nb_qid_offsets; ++i)
236 ctx->qid_offsets[i] = sw_qids[i] - sw_qid_min;
242 TAILQ_INSERT_TAIL(&flow_rss->ctx_list, ctx, entries);
246 sfc_dbg(sa, "flow-rss: added ctx=%p", ctx);
252 sfc_flow_rss_ctx_del(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx)
254 struct sfc_flow_rss *flow_rss = &sa->flow_rss;
259 SFC_ASSERT(sfc_adapter_is_locked(sa));
264 SFC_ASSERT(ctx->refcnt != 0);
268 if (ctx->refcnt != 0)
271 if (ctx->nic_handle_refcnt != 0) {
272 sfc_err(sa, "flow-rss: deleting ctx=%p abandons its NIC resource: handle=0x%08x, refcnt=%u",
273 ctx, ctx->nic_handle, ctx->nic_handle_refcnt);
276 TAILQ_REMOVE(&flow_rss->ctx_list, ctx, entries);
277 rte_free(ctx->qid_offsets);
280 sfc_dbg(sa, "flow-rss: deleted ctx=%p", ctx);
284 sfc_flow_rss_ctx_program_tbl(struct sfc_adapter *sa,
285 const struct sfc_flow_rss_ctx *ctx)
287 const struct sfc_flow_rss_conf *conf = &ctx->conf;
288 unsigned int *tbl = sa->flow_rss.bounce_tbl;
291 SFC_ASSERT(sfc_adapter_is_locked(sa));
293 if (conf->nb_qid_offsets != 0) {
294 SFC_ASSERT(ctx->qid_offsets != NULL);
296 for (i = 0; i < EFX_RSS_TBL_SIZE; ++i)
297 tbl[i] = ctx->qid_offsets[i % conf->nb_qid_offsets];
299 for (i = 0; i < EFX_RSS_TBL_SIZE; ++i)
300 tbl[i] = i % conf->qid_span;
303 return efx_rx_scale_tbl_set(sa->nic, ctx->nic_handle,
304 tbl, EFX_RSS_TBL_SIZE);
308 sfc_flow_rss_ctx_program(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx)
310 efx_rx_scale_context_type_t ctx_type = EFX_RX_SCALE_EXCLUSIVE;
311 struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
312 struct sfc_rss *ethdev_rss = &sas->rss;
313 struct sfc_flow_rss_conf *conf;
314 bool allocation_done = B_FALSE;
322 SFC_ASSERT(sfc_adapter_is_locked(sa));
324 if (ctx->nic_handle_refcnt == 0) {
325 rc = efx_rx_scale_context_alloc(sa->nic, ctx_type,
329 sfc_err(sa, "flow-rss: failed to allocate NIC resource for ctx=%p: type=%d, qid_span=%u, rc=%d",
330 ctx, ctx_type, conf->qid_span, rc);
334 sfc_dbg(sa, "flow-rss: allocated NIC resource for ctx=%p: type=%d, qid_span=%u; handle=0x%08x",
335 ctx, ctx_type, conf->qid_span,
338 ++(ctx->nic_handle_refcnt);
339 allocation_done = B_TRUE;
341 ++(ctx->nic_handle_refcnt);
345 rc = efx_rx_scale_mode_set(sa->nic, ctx->nic_handle,
346 ethdev_rss->hash_alg,
347 (ctx->dummy) ? ethdev_rss->hash_types :
348 conf->efx_hash_types,
351 sfc_err(sa, "flow-rss: failed to configure hash for ctx=%p: efx_hash_alg=%d, efx_hash_types=0x%08x; rc=%d",
352 ctx, ethdev_rss->hash_alg,
353 (ctx->dummy) ? ethdev_rss->hash_types :
354 conf->efx_hash_types,
359 rc = efx_rx_scale_key_set(sa->nic, ctx->nic_handle,
360 (ctx->dummy) ? ethdev_rss->key : conf->key,
363 sfc_err(sa, "flow-rss: failed to set key for ctx=%p; rc=%d",
368 rc = sfc_flow_rss_ctx_program_tbl(sa, ctx);
370 sfc_err(sa, "flow-rss: failed to program table for ctx=%p; rc=%d",
379 sfc_flow_rss_ctx_terminate(sa, ctx);
385 sfc_flow_rss_ctx_terminate(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx)
390 SFC_ASSERT(sfc_adapter_is_locked(sa));
392 SFC_ASSERT(ctx->nic_handle_refcnt != 0);
393 --(ctx->nic_handle_refcnt);
395 if (ctx->nic_handle_refcnt == 0) {
398 rc = efx_rx_scale_context_free(sa->nic, ctx->nic_handle);
400 sfc_err(sa, "flow-rss: failed to release NIC resource for ctx=%p: handle=0x%08x; rc=%d",
401 ctx, ctx->nic_handle, rc);
403 sfc_warn(sa, "flow-rss: proceeding despite the prior error");
406 sfc_dbg(sa, "flow-rss: released NIC resource for ctx=%p; rc=%d",