xref: /dpdk/drivers/net/sfc/sfc_flow_rss.c (revision 6da67e706dc9aa053bf1ed60eb97bcb8f2384d99)
1*6da67e70SIvan Malov /* SPDX-License-Identifier: BSD-3-Clause
2*6da67e70SIvan Malov  *
3*6da67e70SIvan Malov  * Copyright(c) 2022 Xilinx, Inc.
4*6da67e70SIvan Malov  */
5*6da67e70SIvan Malov 
6*6da67e70SIvan Malov #include <stdbool.h>
7*6da67e70SIvan Malov #include <stdint.h>
8*6da67e70SIvan Malov 
9*6da67e70SIvan Malov #include <rte_common.h>
10*6da67e70SIvan Malov #include <rte_flow.h>
11*6da67e70SIvan Malov #include <rte_tailq.h>
12*6da67e70SIvan Malov 
13*6da67e70SIvan Malov #include "efx.h"
14*6da67e70SIvan Malov 
15*6da67e70SIvan Malov #include "sfc.h"
16*6da67e70SIvan Malov #include "sfc_debug.h"
17*6da67e70SIvan Malov #include "sfc_flow_rss.h"
18*6da67e70SIvan Malov #include "sfc_log.h"
19*6da67e70SIvan Malov #include "sfc_rx.h"
20*6da67e70SIvan Malov 
21*6da67e70SIvan Malov int
22*6da67e70SIvan Malov sfc_flow_rss_attach(struct sfc_adapter *sa)
23*6da67e70SIvan Malov {
24*6da67e70SIvan Malov 	struct sfc_flow_rss *flow_rss = &sa->flow_rss;
25*6da67e70SIvan Malov 
26*6da67e70SIvan Malov 	sfc_log_init(sa, "entry");
27*6da67e70SIvan Malov 
28*6da67e70SIvan Malov 	TAILQ_INIT(&flow_rss->ctx_list);
29*6da67e70SIvan Malov 
30*6da67e70SIvan Malov 	sfc_log_init(sa, "done");
31*6da67e70SIvan Malov 
32*6da67e70SIvan Malov 	return 0;
33*6da67e70SIvan Malov }
34*6da67e70SIvan Malov 
35*6da67e70SIvan Malov void
36*6da67e70SIvan Malov sfc_flow_rss_detach(struct sfc_adapter *sa)
37*6da67e70SIvan Malov {
38*6da67e70SIvan Malov 	sfc_log_init(sa, "entry");
39*6da67e70SIvan Malov 
40*6da67e70SIvan Malov 	sfc_log_init(sa, "done");
41*6da67e70SIvan Malov }
42*6da67e70SIvan Malov 
43*6da67e70SIvan Malov int
44*6da67e70SIvan Malov sfc_flow_rss_parse_conf(struct sfc_adapter *sa,
45*6da67e70SIvan Malov 			const struct rte_flow_action_rss *in,
46*6da67e70SIvan Malov 			struct sfc_flow_rss_conf *out, uint16_t *sw_qid_minp)
47*6da67e70SIvan Malov {
48*6da67e70SIvan Malov 	struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
49*6da67e70SIvan Malov 	const struct sfc_rss *ethdev_rss = &sas->rss;
50*6da67e70SIvan Malov 	uint16_t sw_qid_min;
51*6da67e70SIvan Malov 	uint16_t sw_qid_max;
52*6da67e70SIvan Malov 	const uint8_t *key;
53*6da67e70SIvan Malov 	unsigned int i;
54*6da67e70SIvan Malov 	int rc;
55*6da67e70SIvan Malov 
56*6da67e70SIvan Malov 	if (in->level) {
57*6da67e70SIvan Malov 		/*
58*6da67e70SIvan Malov 		 * The caller demands that RSS hash be computed
59*6da67e70SIvan Malov 		 * within the given encapsulation frame / level.
60*6da67e70SIvan Malov 		 * Per flow control for that is not implemented.
61*6da67e70SIvan Malov 		 */
62*6da67e70SIvan Malov 		sfc_err(sa, "flow-rss: parse: 'level' must be 0");
63*6da67e70SIvan Malov 		return EINVAL;
64*6da67e70SIvan Malov 	}
65*6da67e70SIvan Malov 
66*6da67e70SIvan Malov 	if (in->types != 0) {
67*6da67e70SIvan Malov 		rc = sfc_rx_hf_rte_to_efx(sa, in->types,
68*6da67e70SIvan Malov 					  &out->efx_hash_types);
69*6da67e70SIvan Malov 		if (rc != 0) {
70*6da67e70SIvan Malov 			sfc_err(sa, "flow-rss: parse: failed to process 'types'");
71*6da67e70SIvan Malov 			return rc;
72*6da67e70SIvan Malov 		}
73*6da67e70SIvan Malov 	} else {
74*6da67e70SIvan Malov 		sfc_dbg(sa, "flow-rss: parse: 'types' is 0; proceeding with ethdev setting");
75*6da67e70SIvan Malov 		out->efx_hash_types = ethdev_rss->hash_types;
76*6da67e70SIvan Malov 	}
77*6da67e70SIvan Malov 
78*6da67e70SIvan Malov 	if (in->key_len != 0) {
79*6da67e70SIvan Malov 		if (in->key_len != sizeof(out->key)) {
80*6da67e70SIvan Malov 			sfc_err(sa, "flow-rss: parse: 'key_len' must be either %zu or 0",
81*6da67e70SIvan Malov 				sizeof(out->key));
82*6da67e70SIvan Malov 			return EINVAL;
83*6da67e70SIvan Malov 		}
84*6da67e70SIvan Malov 
85*6da67e70SIvan Malov 		if (in->key == NULL) {
86*6da67e70SIvan Malov 			sfc_err(sa, "flow-rss: parse: 'key' is NULL");
87*6da67e70SIvan Malov 			return EINVAL;
88*6da67e70SIvan Malov 		}
89*6da67e70SIvan Malov 
90*6da67e70SIvan Malov 		key = in->key;
91*6da67e70SIvan Malov 	} else {
92*6da67e70SIvan Malov 		sfc_dbg(sa, "flow-rss: parse: 'key_len' is 0; proceeding with ethdev key");
93*6da67e70SIvan Malov 		key = ethdev_rss->key;
94*6da67e70SIvan Malov 	}
95*6da67e70SIvan Malov 
96*6da67e70SIvan Malov 	rte_memcpy(out->key, key, sizeof(out->key));
97*6da67e70SIvan Malov 
98*6da67e70SIvan Malov 	switch (in->func) {
99*6da67e70SIvan Malov 	case RTE_ETH_HASH_FUNCTION_DEFAULT:
100*6da67e70SIvan Malov 		/*
101*6da67e70SIvan Malov 		 * DEFAULT means that conformance to a specific
102*6da67e70SIvan Malov 		 * hash algorithm is a don't care to the caller.
103*6da67e70SIvan Malov 		 * The driver can pick the one it deems optimal.
104*6da67e70SIvan Malov 		 */
105*6da67e70SIvan Malov 		break;
106*6da67e70SIvan Malov 	case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
107*6da67e70SIvan Malov 		if (ethdev_rss->hash_alg != EFX_RX_HASHALG_TOEPLITZ) {
108*6da67e70SIvan Malov 			sfc_err(sa, "flow-rss: parse: 'func' TOEPLITZ is unavailable; use DEFAULT");
109*6da67e70SIvan Malov 			return EINVAL;
110*6da67e70SIvan Malov 		}
111*6da67e70SIvan Malov 		break;
112*6da67e70SIvan Malov 	default:
113*6da67e70SIvan Malov 		sfc_err(sa, "flow-rss: parse: 'func' #%d is unsupported", in->func);
114*6da67e70SIvan Malov 		return EINVAL;
115*6da67e70SIvan Malov 	}
116*6da67e70SIvan Malov 
117*6da67e70SIvan Malov 	if (in->queue_num == 0) {
118*6da67e70SIvan Malov 		sfc_err(sa, "flow-rss: parse: 'queue_num' is 0; MIN=1");
119*6da67e70SIvan Malov 		return EINVAL;
120*6da67e70SIvan Malov 	}
121*6da67e70SIvan Malov 
122*6da67e70SIvan Malov 	if (in->queue_num > EFX_RSS_TBL_SIZE) {
123*6da67e70SIvan Malov 		sfc_err(sa, "flow-rss: parse: 'queue_num' is too large; MAX=%u",
124*6da67e70SIvan Malov 			EFX_RSS_TBL_SIZE);
125*6da67e70SIvan Malov 		return EINVAL;
126*6da67e70SIvan Malov 	}
127*6da67e70SIvan Malov 
128*6da67e70SIvan Malov 	if (in->queue == NULL) {
129*6da67e70SIvan Malov 		sfc_err(sa, "flow-rss: parse: 'queue' is NULL");
130*6da67e70SIvan Malov 		return EINVAL;
131*6da67e70SIvan Malov 	}
132*6da67e70SIvan Malov 
133*6da67e70SIvan Malov 	sw_qid_min = sas->ethdev_rxq_count - 1;
134*6da67e70SIvan Malov 	sw_qid_max = 0;
135*6da67e70SIvan Malov 
136*6da67e70SIvan Malov 	out->nb_qid_offsets = 0;
137*6da67e70SIvan Malov 
138*6da67e70SIvan Malov 	for (i = 0; i < in->queue_num; ++i) {
139*6da67e70SIvan Malov 		uint16_t sw_qid = in->queue[i];
140*6da67e70SIvan Malov 
141*6da67e70SIvan Malov 		if (sw_qid >= sas->ethdev_rxq_count) {
142*6da67e70SIvan Malov 			sfc_err(sa, "flow-rss: parse: queue=%u does not exist",
143*6da67e70SIvan Malov 				sw_qid);
144*6da67e70SIvan Malov 			return EINVAL;
145*6da67e70SIvan Malov 		}
146*6da67e70SIvan Malov 
147*6da67e70SIvan Malov 		if (sw_qid < sw_qid_min)
148*6da67e70SIvan Malov 			sw_qid_min = sw_qid;
149*6da67e70SIvan Malov 
150*6da67e70SIvan Malov 		if (sw_qid > sw_qid_max)
151*6da67e70SIvan Malov 			sw_qid_max = sw_qid;
152*6da67e70SIvan Malov 
153*6da67e70SIvan Malov 		if (sw_qid != in->queue[0] + i)
154*6da67e70SIvan Malov 			out->nb_qid_offsets = in->queue_num;
155*6da67e70SIvan Malov 	}
156*6da67e70SIvan Malov 
157*6da67e70SIvan Malov 	out->qid_span = sw_qid_max - sw_qid_min + 1;
158*6da67e70SIvan Malov 
159*6da67e70SIvan Malov 	if (out->qid_span > EFX_MAXRSS) {
160*6da67e70SIvan Malov 		sfc_err(sa, "flow-rss: parse: queue ID span %u is too large; MAX=%u",
161*6da67e70SIvan Malov 			out->qid_span, EFX_MAXRSS);
162*6da67e70SIvan Malov 		return EINVAL;
163*6da67e70SIvan Malov 	}
164*6da67e70SIvan Malov 
165*6da67e70SIvan Malov 	if (sw_qid_minp != NULL)
166*6da67e70SIvan Malov 		*sw_qid_minp = sw_qid_min;
167*6da67e70SIvan Malov 
168*6da67e70SIvan Malov 	return 0;
169*6da67e70SIvan Malov }
170*6da67e70SIvan Malov 
171*6da67e70SIvan Malov struct sfc_flow_rss_ctx *
172*6da67e70SIvan Malov sfc_flow_rss_ctx_reuse(struct sfc_adapter *sa,
173*6da67e70SIvan Malov 		       const struct sfc_flow_rss_conf *conf,
174*6da67e70SIvan Malov 		       uint16_t sw_qid_min, const uint16_t *sw_qids)
175*6da67e70SIvan Malov {
176*6da67e70SIvan Malov 	struct sfc_flow_rss *flow_rss = &sa->flow_rss;
177*6da67e70SIvan Malov 	static struct sfc_flow_rss_ctx *ctx;
178*6da67e70SIvan Malov 
179*6da67e70SIvan Malov 	SFC_ASSERT(sfc_adapter_is_locked(sa));
180*6da67e70SIvan Malov 
181*6da67e70SIvan Malov 	TAILQ_FOREACH(ctx, &flow_rss->ctx_list, entries) {
182*6da67e70SIvan Malov 		if (memcmp(&ctx->conf, conf, sizeof(*conf)) != 0)
183*6da67e70SIvan Malov 			continue;
184*6da67e70SIvan Malov 
185*6da67e70SIvan Malov 		if (conf->nb_qid_offsets != 0) {
186*6da67e70SIvan Malov 			bool match_confirmed = true;
187*6da67e70SIvan Malov 			unsigned int i;
188*6da67e70SIvan Malov 
189*6da67e70SIvan Malov 			for (i = 0; i < conf->nb_qid_offsets; ++i) {
190*6da67e70SIvan Malov 				uint16_t qid_offset = sw_qids[i] - sw_qid_min;
191*6da67e70SIvan Malov 
192*6da67e70SIvan Malov 				if (ctx->qid_offsets[i] != qid_offset) {
193*6da67e70SIvan Malov 					match_confirmed = false;
194*6da67e70SIvan Malov 					break;
195*6da67e70SIvan Malov 				}
196*6da67e70SIvan Malov 			}
197*6da67e70SIvan Malov 
198*6da67e70SIvan Malov 			if (!match_confirmed)
199*6da67e70SIvan Malov 				continue;
200*6da67e70SIvan Malov 		}
201*6da67e70SIvan Malov 
202*6da67e70SIvan Malov 		sfc_dbg(sa, "flow-rss: reusing ctx=%p", ctx);
203*6da67e70SIvan Malov 		++(ctx->refcnt);
204*6da67e70SIvan Malov 		return ctx;
205*6da67e70SIvan Malov 	}
206*6da67e70SIvan Malov 
207*6da67e70SIvan Malov 	return NULL;
208*6da67e70SIvan Malov }
209*6da67e70SIvan Malov 
210*6da67e70SIvan Malov int
211*6da67e70SIvan Malov sfc_flow_rss_ctx_add(struct sfc_adapter *sa,
212*6da67e70SIvan Malov 		     const struct sfc_flow_rss_conf *conf, uint16_t sw_qid_min,
213*6da67e70SIvan Malov 		     const uint16_t *sw_qids, struct sfc_flow_rss_ctx **ctxp)
214*6da67e70SIvan Malov {
215*6da67e70SIvan Malov 	struct sfc_flow_rss *flow_rss = &sa->flow_rss;
216*6da67e70SIvan Malov 	struct sfc_flow_rss_ctx *ctx;
217*6da67e70SIvan Malov 
218*6da67e70SIvan Malov 	SFC_ASSERT(sfc_adapter_is_locked(sa));
219*6da67e70SIvan Malov 
220*6da67e70SIvan Malov 	ctx = rte_zmalloc("sfc_flow_rss_ctx", sizeof(*ctx), 0);
221*6da67e70SIvan Malov 	if (ctx == NULL)
222*6da67e70SIvan Malov 		return ENOMEM;
223*6da67e70SIvan Malov 
224*6da67e70SIvan Malov 	if (conf->nb_qid_offsets != 0) {
225*6da67e70SIvan Malov 		unsigned int i;
226*6da67e70SIvan Malov 
227*6da67e70SIvan Malov 		ctx->qid_offsets = rte_calloc("sfc_flow_rss_ctx_qid_offsets",
228*6da67e70SIvan Malov 					      conf->nb_qid_offsets,
229*6da67e70SIvan Malov 					      sizeof(*ctx->qid_offsets), 0);
230*6da67e70SIvan Malov 		if (ctx->qid_offsets == NULL) {
231*6da67e70SIvan Malov 			rte_free(ctx);
232*6da67e70SIvan Malov 			return ENOMEM;
233*6da67e70SIvan Malov 		}
234*6da67e70SIvan Malov 
235*6da67e70SIvan Malov 		for (i = 0; i < conf->nb_qid_offsets; ++i)
236*6da67e70SIvan Malov 			ctx->qid_offsets[i] = sw_qids[i] - sw_qid_min;
237*6da67e70SIvan Malov 	}
238*6da67e70SIvan Malov 
239*6da67e70SIvan Malov 	ctx->conf = *conf;
240*6da67e70SIvan Malov 	ctx->refcnt = 1;
241*6da67e70SIvan Malov 
242*6da67e70SIvan Malov 	TAILQ_INSERT_TAIL(&flow_rss->ctx_list, ctx, entries);
243*6da67e70SIvan Malov 
244*6da67e70SIvan Malov 	*ctxp = ctx;
245*6da67e70SIvan Malov 
246*6da67e70SIvan Malov 	sfc_dbg(sa, "flow-rss: added ctx=%p", ctx);
247*6da67e70SIvan Malov 
248*6da67e70SIvan Malov 	return 0;
249*6da67e70SIvan Malov }
250*6da67e70SIvan Malov 
251*6da67e70SIvan Malov void
252*6da67e70SIvan Malov sfc_flow_rss_ctx_del(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx)
253*6da67e70SIvan Malov {
254*6da67e70SIvan Malov 	struct sfc_flow_rss *flow_rss = &sa->flow_rss;
255*6da67e70SIvan Malov 
256*6da67e70SIvan Malov 	if (ctx == NULL)
257*6da67e70SIvan Malov 		return;
258*6da67e70SIvan Malov 
259*6da67e70SIvan Malov 	SFC_ASSERT(sfc_adapter_is_locked(sa));
260*6da67e70SIvan Malov 
261*6da67e70SIvan Malov 	if (ctx->dummy)
262*6da67e70SIvan Malov 		return;
263*6da67e70SIvan Malov 
264*6da67e70SIvan Malov 	SFC_ASSERT(ctx->refcnt != 0);
265*6da67e70SIvan Malov 
266*6da67e70SIvan Malov 	--(ctx->refcnt);
267*6da67e70SIvan Malov 
268*6da67e70SIvan Malov 	if (ctx->refcnt != 0)
269*6da67e70SIvan Malov 		return;
270*6da67e70SIvan Malov 
271*6da67e70SIvan Malov 	if (ctx->nic_handle_refcnt != 0) {
272*6da67e70SIvan Malov 		sfc_err(sa, "flow-rss: deleting ctx=%p abandons its NIC resource: handle=0x%08x, refcnt=%u",
273*6da67e70SIvan Malov 			ctx, ctx->nic_handle, ctx->nic_handle_refcnt);
274*6da67e70SIvan Malov 	}
275*6da67e70SIvan Malov 
276*6da67e70SIvan Malov 	TAILQ_REMOVE(&flow_rss->ctx_list, ctx, entries);
277*6da67e70SIvan Malov 	rte_free(ctx->qid_offsets);
278*6da67e70SIvan Malov 	rte_free(ctx);
279*6da67e70SIvan Malov 
280*6da67e70SIvan Malov 	sfc_dbg(sa, "flow-rss: deleted ctx=%p", ctx);
281*6da67e70SIvan Malov }
282*6da67e70SIvan Malov 
283*6da67e70SIvan Malov static int
284*6da67e70SIvan Malov sfc_flow_rss_ctx_program_tbl(struct sfc_adapter *sa,
285*6da67e70SIvan Malov 			     const struct sfc_flow_rss_ctx *ctx)
286*6da67e70SIvan Malov {
287*6da67e70SIvan Malov 	const struct sfc_flow_rss_conf *conf = &ctx->conf;
288*6da67e70SIvan Malov 	unsigned int *tbl = sa->flow_rss.bounce_tbl;
289*6da67e70SIvan Malov 	unsigned int i;
290*6da67e70SIvan Malov 
291*6da67e70SIvan Malov 	SFC_ASSERT(sfc_adapter_is_locked(sa));
292*6da67e70SIvan Malov 
293*6da67e70SIvan Malov 	if (conf->nb_qid_offsets != 0) {
294*6da67e70SIvan Malov 		SFC_ASSERT(ctx->qid_offsets != NULL);
295*6da67e70SIvan Malov 
296*6da67e70SIvan Malov 		for (i = 0; i < EFX_RSS_TBL_SIZE; ++i)
297*6da67e70SIvan Malov 			tbl[i] = ctx->qid_offsets[i % conf->nb_qid_offsets];
298*6da67e70SIvan Malov 	} else {
299*6da67e70SIvan Malov 		for (i = 0; i < EFX_RSS_TBL_SIZE; ++i)
300*6da67e70SIvan Malov 			tbl[i] = i % conf->qid_span;
301*6da67e70SIvan Malov 	}
302*6da67e70SIvan Malov 
303*6da67e70SIvan Malov 	return efx_rx_scale_tbl_set(sa->nic, ctx->nic_handle,
304*6da67e70SIvan Malov 				    tbl, EFX_RSS_TBL_SIZE);
305*6da67e70SIvan Malov }
306*6da67e70SIvan Malov 
307*6da67e70SIvan Malov int
308*6da67e70SIvan Malov sfc_flow_rss_ctx_program(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx)
309*6da67e70SIvan Malov {
310*6da67e70SIvan Malov 	efx_rx_scale_context_type_t ctx_type = EFX_RX_SCALE_EXCLUSIVE;
311*6da67e70SIvan Malov 	struct sfc_adapter_shared * const sas = sfc_sa2shared(sa);
312*6da67e70SIvan Malov 	struct sfc_rss *ethdev_rss = &sas->rss;
313*6da67e70SIvan Malov 	struct sfc_flow_rss_conf *conf;
314*6da67e70SIvan Malov 	bool allocation_done = B_FALSE;
315*6da67e70SIvan Malov 	int rc;
316*6da67e70SIvan Malov 
317*6da67e70SIvan Malov 	if (ctx == NULL)
318*6da67e70SIvan Malov 		return 0;
319*6da67e70SIvan Malov 
320*6da67e70SIvan Malov 	conf = &ctx->conf;
321*6da67e70SIvan Malov 
322*6da67e70SIvan Malov 	SFC_ASSERT(sfc_adapter_is_locked(sa));
323*6da67e70SIvan Malov 
324*6da67e70SIvan Malov 	if (ctx->nic_handle_refcnt == 0) {
325*6da67e70SIvan Malov 		rc = efx_rx_scale_context_alloc(sa->nic, ctx_type,
326*6da67e70SIvan Malov 						conf->qid_span,
327*6da67e70SIvan Malov 						&ctx->nic_handle);
328*6da67e70SIvan Malov 		if (rc != 0) {
329*6da67e70SIvan Malov 			sfc_err(sa, "flow-rss: failed to allocate NIC resource for ctx=%p: type=%d, qid_span=%u, rc=%d",
330*6da67e70SIvan Malov 				ctx, ctx_type, conf->qid_span, rc);
331*6da67e70SIvan Malov 			goto fail;
332*6da67e70SIvan Malov 		}
333*6da67e70SIvan Malov 
334*6da67e70SIvan Malov 		sfc_dbg(sa, "flow-rss: allocated NIC resource for ctx=%p: type=%d, qid_span=%u; handle=0x%08x",
335*6da67e70SIvan Malov 			ctx, ctx_type, conf->qid_span,
336*6da67e70SIvan Malov 			ctx->nic_handle);
337*6da67e70SIvan Malov 
338*6da67e70SIvan Malov 		++(ctx->nic_handle_refcnt);
339*6da67e70SIvan Malov 		allocation_done = B_TRUE;
340*6da67e70SIvan Malov 	} else {
341*6da67e70SIvan Malov 		++(ctx->nic_handle_refcnt);
342*6da67e70SIvan Malov 		return 0;
343*6da67e70SIvan Malov 	}
344*6da67e70SIvan Malov 
345*6da67e70SIvan Malov 	rc = efx_rx_scale_mode_set(sa->nic, ctx->nic_handle,
346*6da67e70SIvan Malov 				   ethdev_rss->hash_alg,
347*6da67e70SIvan Malov 				   (ctx->dummy) ? ethdev_rss->hash_types :
348*6da67e70SIvan Malov 						  conf->efx_hash_types,
349*6da67e70SIvan Malov 				   B_TRUE);
350*6da67e70SIvan Malov 	if (rc != 0) {
351*6da67e70SIvan Malov 		sfc_err(sa, "flow-rss: failed to configure hash for ctx=%p: efx_hash_alg=%d, efx_hash_types=0x%08x; rc=%d",
352*6da67e70SIvan Malov 			ctx, ethdev_rss->hash_alg,
353*6da67e70SIvan Malov 			(ctx->dummy) ? ethdev_rss->hash_types :
354*6da67e70SIvan Malov 				       conf->efx_hash_types,
355*6da67e70SIvan Malov 			rc);
356*6da67e70SIvan Malov 		goto fail;
357*6da67e70SIvan Malov 	}
358*6da67e70SIvan Malov 
359*6da67e70SIvan Malov 	rc = efx_rx_scale_key_set(sa->nic, ctx->nic_handle,
360*6da67e70SIvan Malov 				  (ctx->dummy) ? ethdev_rss->key : conf->key,
361*6da67e70SIvan Malov 				  RTE_DIM(conf->key));
362*6da67e70SIvan Malov 	if (rc != 0) {
363*6da67e70SIvan Malov 		sfc_err(sa, "flow-rss: failed to set key for ctx=%p; rc=%d",
364*6da67e70SIvan Malov 			ctx, rc);
365*6da67e70SIvan Malov 		goto fail;
366*6da67e70SIvan Malov 	}
367*6da67e70SIvan Malov 
368*6da67e70SIvan Malov 	rc = sfc_flow_rss_ctx_program_tbl(sa, ctx);
369*6da67e70SIvan Malov 	if (rc != 0) {
370*6da67e70SIvan Malov 		sfc_err(sa, "flow-rss: failed to program table for ctx=%p; rc=%d",
371*6da67e70SIvan Malov 			ctx, rc);
372*6da67e70SIvan Malov 		goto fail;
373*6da67e70SIvan Malov 	}
374*6da67e70SIvan Malov 
375*6da67e70SIvan Malov 	return 0;
376*6da67e70SIvan Malov 
377*6da67e70SIvan Malov fail:
378*6da67e70SIvan Malov 	if (allocation_done)
379*6da67e70SIvan Malov 		sfc_flow_rss_ctx_terminate(sa, ctx);
380*6da67e70SIvan Malov 
381*6da67e70SIvan Malov 	return rc;
382*6da67e70SIvan Malov }
383*6da67e70SIvan Malov 
384*6da67e70SIvan Malov void
385*6da67e70SIvan Malov sfc_flow_rss_ctx_terminate(struct sfc_adapter *sa, struct sfc_flow_rss_ctx *ctx)
386*6da67e70SIvan Malov {
387*6da67e70SIvan Malov 	if (ctx == NULL)
388*6da67e70SIvan Malov 		return;
389*6da67e70SIvan Malov 
390*6da67e70SIvan Malov 	SFC_ASSERT(sfc_adapter_is_locked(sa));
391*6da67e70SIvan Malov 
392*6da67e70SIvan Malov 	SFC_ASSERT(ctx->nic_handle_refcnt != 0);
393*6da67e70SIvan Malov 	--(ctx->nic_handle_refcnt);
394*6da67e70SIvan Malov 
395*6da67e70SIvan Malov 	if (ctx->nic_handle_refcnt == 0) {
396*6da67e70SIvan Malov 		int rc;
397*6da67e70SIvan Malov 
398*6da67e70SIvan Malov 		rc = efx_rx_scale_context_free(sa->nic, ctx->nic_handle);
399*6da67e70SIvan Malov 		if (rc != 0) {
400*6da67e70SIvan Malov 			sfc_err(sa, "flow-rss: failed to release NIC resource for ctx=%p: handle=0x%08x; rc=%d",
401*6da67e70SIvan Malov 				ctx, ctx->nic_handle, rc);
402*6da67e70SIvan Malov 
403*6da67e70SIvan Malov 			sfc_warn(sa, "flow-rss: proceeding despite the prior error");
404*6da67e70SIvan Malov 		}
405*6da67e70SIvan Malov 
406*6da67e70SIvan Malov 		sfc_dbg(sa, "flow-rss: released NIC resource for ctx=%p; rc=%d",
407*6da67e70SIvan Malov 			ctx, rc);
408*6da67e70SIvan Malov 	}
409*6da67e70SIvan Malov }
410