1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2021, Mellanox Technologies inc. All rights reserved. */
3 
4 #include "rx_res.h"
5 #include "channels.h"
6 #include "params.h"
7 
8 #define MLX5E_MAX_NUM_RSS 16
9 
10 struct mlx5e_rx_res {
11 	struct mlx5_core_dev *mdev;
12 	enum mlx5e_rx_res_features features;
13 	unsigned int max_nch;
14 	u32 drop_rqn;
15 
16 	struct mlx5e_rss *rss[MLX5E_MAX_NUM_RSS];
17 	bool rss_active;
18 	u32 rss_rqns[MLX5E_INDIR_RQT_SIZE];
19 	unsigned int rss_nch;
20 
21 	struct {
22 		struct mlx5e_rqt direct_rqt;
23 		struct mlx5e_tir direct_tir;
24 		struct mlx5e_rqt xsk_rqt;
25 		struct mlx5e_tir xsk_tir;
26 	} *channels;
27 
28 	struct {
29 		struct mlx5e_rqt rqt;
30 		struct mlx5e_tir tir;
31 	} ptp;
32 };
33 
34 /* API for rx_res_rss_* */
35 
36 static int mlx5e_rx_res_rss_init_def(struct mlx5e_rx_res *res,
37 				     const struct mlx5e_lro_param *init_lro_param,
38 				     unsigned int init_nch)
39 {
40 	bool inner_ft_support = res->features & MLX5E_RX_RES_FEATURE_INNER_FT;
41 	struct mlx5e_rss *rss;
42 	int err;
43 
44 	if (WARN_ON(res->rss[0]))
45 		return -EINVAL;
46 
47 	rss = mlx5e_rss_alloc();
48 	if (!rss)
49 		return -ENOMEM;
50 
51 	err = mlx5e_rss_init(rss, res->mdev, inner_ft_support, res->drop_rqn,
52 			     init_lro_param);
53 	if (err)
54 		goto err_rss_free;
55 
56 	mlx5e_rss_set_indir_uniform(rss, init_nch);
57 
58 	res->rss[0] = rss;
59 
60 	return 0;
61 
62 err_rss_free:
63 	mlx5e_rss_free(rss);
64 	return err;
65 }
66 
67 int mlx5e_rx_res_rss_init(struct mlx5e_rx_res *res, u32 *rss_idx, unsigned int init_nch)
68 {
69 	bool inner_ft_support = res->features & MLX5E_RX_RES_FEATURE_INNER_FT;
70 	struct mlx5e_rss *rss;
71 	int err, i;
72 
73 	for (i = 1; i < MLX5E_MAX_NUM_RSS; i++)
74 		if (!res->rss[i])
75 			break;
76 
77 	if (i == MLX5E_MAX_NUM_RSS)
78 		return -ENOSPC;
79 
80 	rss = mlx5e_rss_alloc();
81 	if (!rss)
82 		return -ENOMEM;
83 
84 	err = mlx5e_rss_init_no_tirs(rss, res->mdev, inner_ft_support, res->drop_rqn);
85 	if (err)
86 		goto err_rss_free;
87 
88 	mlx5e_rss_set_indir_uniform(rss, init_nch);
89 	if (res->rss_active)
90 		mlx5e_rss_enable(rss, res->rss_rqns, res->rss_nch);
91 
92 	res->rss[i] = rss;
93 	*rss_idx = i;
94 
95 	return 0;
96 
97 err_rss_free:
98 	mlx5e_rss_free(rss);
99 	return err;
100 }
101 
102 static int __mlx5e_rx_res_rss_destroy(struct mlx5e_rx_res *res, u32 rss_idx)
103 {
104 	struct mlx5e_rss *rss = res->rss[rss_idx];
105 	int err;
106 
107 	err = mlx5e_rss_cleanup(rss);
108 	if (err)
109 		return err;
110 
111 	mlx5e_rss_free(rss);
112 	res->rss[rss_idx] = NULL;
113 
114 	return 0;
115 }
116 
117 int mlx5e_rx_res_rss_destroy(struct mlx5e_rx_res *res, u32 rss_idx)
118 {
119 	struct mlx5e_rss *rss;
120 
121 	if (rss_idx >= MLX5E_MAX_NUM_RSS)
122 		return -EINVAL;
123 
124 	rss = res->rss[rss_idx];
125 	if (!rss)
126 		return -EINVAL;
127 
128 	return __mlx5e_rx_res_rss_destroy(res, rss_idx);
129 }
130 
131 static void mlx5e_rx_res_rss_destroy_all(struct mlx5e_rx_res *res)
132 {
133 	int i;
134 
135 	for (i = 0; i < MLX5E_MAX_NUM_RSS; i++) {
136 		struct mlx5e_rss *rss = res->rss[i];
137 		int err;
138 
139 		if (!rss)
140 			continue;
141 
142 		err = __mlx5e_rx_res_rss_destroy(res, i);
143 		if (err) {
144 			unsigned int refcount;
145 
146 			refcount = mlx5e_rss_refcnt_read(rss);
147 			mlx5_core_warn(res->mdev,
148 				       "Failed to destroy RSS context %d, refcount = %u, err = %d\n",
149 				       i, refcount, err);
150 		}
151 	}
152 }
153 
154 static void mlx5e_rx_res_rss_enable(struct mlx5e_rx_res *res)
155 {
156 	int i;
157 
158 	res->rss_active = true;
159 
160 	for (i = 0; i < MLX5E_MAX_NUM_RSS; i++) {
161 		struct mlx5e_rss *rss = res->rss[i];
162 
163 		if (!rss)
164 			continue;
165 		mlx5e_rss_enable(rss, res->rss_rqns, res->rss_nch);
166 	}
167 }
168 
169 static void mlx5e_rx_res_rss_disable(struct mlx5e_rx_res *res)
170 {
171 	int i;
172 
173 	res->rss_active = false;
174 
175 	for (i = 0; i < MLX5E_MAX_NUM_RSS; i++) {
176 		struct mlx5e_rss *rss = res->rss[i];
177 
178 		if (!rss)
179 			continue;
180 		mlx5e_rss_disable(rss);
181 	}
182 }
183 
184 /* Updates the indirection table SW shadow, does not update the HW resources yet */
185 void mlx5e_rx_res_rss_set_indir_uniform(struct mlx5e_rx_res *res, unsigned int nch)
186 {
187 	WARN_ON_ONCE(res->rss_active);
188 	mlx5e_rss_set_indir_uniform(res->rss[0], nch);
189 }
190 
191 int mlx5e_rx_res_rss_get_rxfh(struct mlx5e_rx_res *res, u32 rss_idx,
192 			      u32 *indir, u8 *key, u8 *hfunc)
193 {
194 	struct mlx5e_rss *rss;
195 
196 	if (rss_idx >= MLX5E_MAX_NUM_RSS)
197 		return -EINVAL;
198 
199 	rss = res->rss[rss_idx];
200 	if (!rss)
201 		return -ENOENT;
202 
203 	return mlx5e_rss_get_rxfh(rss, indir, key, hfunc);
204 }
205 
206 int mlx5e_rx_res_rss_set_rxfh(struct mlx5e_rx_res *res, u32 rss_idx,
207 			      const u32 *indir, const u8 *key, const u8 *hfunc)
208 {
209 	struct mlx5e_rss *rss;
210 
211 	if (rss_idx >= MLX5E_MAX_NUM_RSS)
212 		return -EINVAL;
213 
214 	rss = res->rss[rss_idx];
215 	if (!rss)
216 		return -ENOENT;
217 
218 	return mlx5e_rss_set_rxfh(rss, indir, key, hfunc, res->rss_rqns, res->rss_nch);
219 }
220 
221 u8 mlx5e_rx_res_rss_get_hash_fields(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt)
222 {
223 	struct mlx5e_rss *rss = res->rss[0];
224 
225 	return mlx5e_rss_get_hash_fields(rss, tt);
226 }
227 
228 int mlx5e_rx_res_rss_set_hash_fields(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt,
229 				     u8 rx_hash_fields)
230 {
231 	struct mlx5e_rss *rss = res->rss[0];
232 
233 	return mlx5e_rss_set_hash_fields(rss, tt, rx_hash_fields);
234 }
235 
236 int mlx5e_rx_res_rss_cnt(struct mlx5e_rx_res *res)
237 {
238 	int i, cnt;
239 
240 	cnt = 0;
241 	for (i = 0; i < MLX5E_MAX_NUM_RSS; i++)
242 		if (res->rss[i])
243 			cnt++;
244 
245 	return cnt;
246 }
247 
248 int mlx5e_rx_res_rss_index(struct mlx5e_rx_res *res, struct mlx5e_rss *rss)
249 {
250 	int i;
251 
252 	if (!rss)
253 		return -EINVAL;
254 
255 	for (i = 0; i < MLX5E_MAX_NUM_RSS; i++)
256 		if (rss == res->rss[i])
257 			return i;
258 
259 	return -ENOENT;
260 }
261 
262 struct mlx5e_rss *mlx5e_rx_res_rss_get(struct mlx5e_rx_res *res, u32 rss_idx)
263 {
264 	if (rss_idx >= MLX5E_MAX_NUM_RSS)
265 		return NULL;
266 
267 	return res->rss[rss_idx];
268 }
269 
270 /* End of API rx_res_rss_* */
271 
272 struct mlx5e_rx_res *mlx5e_rx_res_alloc(void)
273 {
274 	return kvzalloc(sizeof(struct mlx5e_rx_res), GFP_KERNEL);
275 }
276 
277 static int mlx5e_rx_res_channels_init(struct mlx5e_rx_res *res,
278 				      const struct mlx5e_lro_param *init_lro_param)
279 {
280 	bool inner_ft_support = res->features & MLX5E_RX_RES_FEATURE_INNER_FT;
281 	struct mlx5e_tir_builder *builder;
282 	int err = 0;
283 	int ix;
284 
285 	builder = mlx5e_tir_builder_alloc(false);
286 	if (!builder)
287 		return -ENOMEM;
288 
289 	res->channels = kvcalloc(res->max_nch, sizeof(*res->channels), GFP_KERNEL);
290 	if (!res->channels) {
291 		err = -ENOMEM;
292 		goto out;
293 	}
294 
295 	for (ix = 0; ix < res->max_nch; ix++) {
296 		err = mlx5e_rqt_init_direct(&res->channels[ix].direct_rqt,
297 					    res->mdev, false, res->drop_rqn);
298 		if (err) {
299 			mlx5_core_warn(res->mdev, "Failed to create a direct RQT: err = %d, ix = %u\n",
300 				       err, ix);
301 			goto err_destroy_direct_rqts;
302 		}
303 	}
304 
305 	for (ix = 0; ix < res->max_nch; ix++) {
306 		mlx5e_tir_builder_build_rqt(builder, res->mdev->mlx5e_res.hw_objs.td.tdn,
307 					    mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt),
308 					    inner_ft_support);
309 		mlx5e_tir_builder_build_lro(builder, init_lro_param);
310 		mlx5e_tir_builder_build_direct(builder);
311 
312 		err = mlx5e_tir_init(&res->channels[ix].direct_tir, builder, res->mdev, true);
313 		if (err) {
314 			mlx5_core_warn(res->mdev, "Failed to create a direct TIR: err = %d, ix = %u\n",
315 				       err, ix);
316 			goto err_destroy_direct_tirs;
317 		}
318 
319 		mlx5e_tir_builder_clear(builder);
320 	}
321 
322 	if (!(res->features & MLX5E_RX_RES_FEATURE_XSK))
323 		goto out;
324 
325 	for (ix = 0; ix < res->max_nch; ix++) {
326 		err = mlx5e_rqt_init_direct(&res->channels[ix].xsk_rqt,
327 					    res->mdev, false, res->drop_rqn);
328 		if (err) {
329 			mlx5_core_warn(res->mdev, "Failed to create an XSK RQT: err = %d, ix = %u\n",
330 				       err, ix);
331 			goto err_destroy_xsk_rqts;
332 		}
333 	}
334 
335 	for (ix = 0; ix < res->max_nch; ix++) {
336 		mlx5e_tir_builder_build_rqt(builder, res->mdev->mlx5e_res.hw_objs.td.tdn,
337 					    mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt),
338 					    inner_ft_support);
339 		mlx5e_tir_builder_build_lro(builder, init_lro_param);
340 		mlx5e_tir_builder_build_direct(builder);
341 
342 		err = mlx5e_tir_init(&res->channels[ix].xsk_tir, builder, res->mdev, true);
343 		if (err) {
344 			mlx5_core_warn(res->mdev, "Failed to create an XSK TIR: err = %d, ix = %u\n",
345 				       err, ix);
346 			goto err_destroy_xsk_tirs;
347 		}
348 
349 		mlx5e_tir_builder_clear(builder);
350 	}
351 
352 	goto out;
353 
354 err_destroy_xsk_tirs:
355 	while (--ix >= 0)
356 		mlx5e_tir_destroy(&res->channels[ix].xsk_tir);
357 
358 	ix = res->max_nch;
359 err_destroy_xsk_rqts:
360 	while (--ix >= 0)
361 		mlx5e_rqt_destroy(&res->channels[ix].xsk_rqt);
362 
363 	ix = res->max_nch;
364 err_destroy_direct_tirs:
365 	while (--ix >= 0)
366 		mlx5e_tir_destroy(&res->channels[ix].direct_tir);
367 
368 	ix = res->max_nch;
369 err_destroy_direct_rqts:
370 	while (--ix >= 0)
371 		mlx5e_rqt_destroy(&res->channels[ix].direct_rqt);
372 
373 	kvfree(res->channels);
374 
375 out:
376 	mlx5e_tir_builder_free(builder);
377 
378 	return err;
379 }
380 
381 static int mlx5e_rx_res_ptp_init(struct mlx5e_rx_res *res)
382 {
383 	bool inner_ft_support = res->features & MLX5E_RX_RES_FEATURE_INNER_FT;
384 	struct mlx5e_tir_builder *builder;
385 	int err;
386 
387 	builder = mlx5e_tir_builder_alloc(false);
388 	if (!builder)
389 		return -ENOMEM;
390 
391 	err = mlx5e_rqt_init_direct(&res->ptp.rqt, res->mdev, false, res->drop_rqn);
392 	if (err)
393 		goto out;
394 
395 	mlx5e_tir_builder_build_rqt(builder, res->mdev->mlx5e_res.hw_objs.td.tdn,
396 				    mlx5e_rqt_get_rqtn(&res->ptp.rqt),
397 				    inner_ft_support);
398 	mlx5e_tir_builder_build_direct(builder);
399 
400 	err = mlx5e_tir_init(&res->ptp.tir, builder, res->mdev, true);
401 	if (err)
402 		goto err_destroy_ptp_rqt;
403 
404 	goto out;
405 
406 err_destroy_ptp_rqt:
407 	mlx5e_rqt_destroy(&res->ptp.rqt);
408 
409 out:
410 	mlx5e_tir_builder_free(builder);
411 	return err;
412 }
413 
414 static void mlx5e_rx_res_channels_destroy(struct mlx5e_rx_res *res)
415 {
416 	unsigned int ix;
417 
418 	for (ix = 0; ix < res->max_nch; ix++) {
419 		mlx5e_tir_destroy(&res->channels[ix].direct_tir);
420 		mlx5e_rqt_destroy(&res->channels[ix].direct_rqt);
421 
422 		if (!(res->features & MLX5E_RX_RES_FEATURE_XSK))
423 			continue;
424 
425 		mlx5e_tir_destroy(&res->channels[ix].xsk_tir);
426 		mlx5e_rqt_destroy(&res->channels[ix].xsk_rqt);
427 	}
428 
429 	kvfree(res->channels);
430 }
431 
432 static void mlx5e_rx_res_ptp_destroy(struct mlx5e_rx_res *res)
433 {
434 	mlx5e_tir_destroy(&res->ptp.tir);
435 	mlx5e_rqt_destroy(&res->ptp.rqt);
436 }
437 
438 int mlx5e_rx_res_init(struct mlx5e_rx_res *res, struct mlx5_core_dev *mdev,
439 		      enum mlx5e_rx_res_features features, unsigned int max_nch,
440 		      u32 drop_rqn, const struct mlx5e_lro_param *init_lro_param,
441 		      unsigned int init_nch)
442 {
443 	int err;
444 
445 	res->mdev = mdev;
446 	res->features = features;
447 	res->max_nch = max_nch;
448 	res->drop_rqn = drop_rqn;
449 
450 	err = mlx5e_rx_res_rss_init_def(res, init_lro_param, init_nch);
451 	if (err)
452 		goto err_out;
453 
454 	err = mlx5e_rx_res_channels_init(res, init_lro_param);
455 	if (err)
456 		goto err_rss_destroy;
457 
458 	err = mlx5e_rx_res_ptp_init(res);
459 	if (err)
460 		goto err_channels_destroy;
461 
462 	return 0;
463 
464 err_channels_destroy:
465 	mlx5e_rx_res_channels_destroy(res);
466 err_rss_destroy:
467 	__mlx5e_rx_res_rss_destroy(res, 0);
468 err_out:
469 	return err;
470 }
471 
472 void mlx5e_rx_res_destroy(struct mlx5e_rx_res *res)
473 {
474 	mlx5e_rx_res_ptp_destroy(res);
475 	mlx5e_rx_res_channels_destroy(res);
476 	mlx5e_rx_res_rss_destroy_all(res);
477 }
478 
479 void mlx5e_rx_res_free(struct mlx5e_rx_res *res)
480 {
481 	kvfree(res);
482 }
483 
484 u32 mlx5e_rx_res_get_tirn_direct(struct mlx5e_rx_res *res, unsigned int ix)
485 {
486 	return mlx5e_tir_get_tirn(&res->channels[ix].direct_tir);
487 }
488 
489 u32 mlx5e_rx_res_get_tirn_xsk(struct mlx5e_rx_res *res, unsigned int ix)
490 {
491 	WARN_ON(!(res->features & MLX5E_RX_RES_FEATURE_XSK));
492 
493 	return mlx5e_tir_get_tirn(&res->channels[ix].xsk_tir);
494 }
495 
496 u32 mlx5e_rx_res_get_tirn_rss(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt)
497 {
498 	struct mlx5e_rss *rss = res->rss[0];
499 
500 	return mlx5e_rss_get_tirn(rss, tt, false);
501 }
502 
503 u32 mlx5e_rx_res_get_tirn_rss_inner(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt)
504 {
505 	struct mlx5e_rss *rss = res->rss[0];
506 
507 	return mlx5e_rss_get_tirn(rss, tt, true);
508 }
509 
510 u32 mlx5e_rx_res_get_tirn_ptp(struct mlx5e_rx_res *res)
511 {
512 	WARN_ON(!(res->features & MLX5E_RX_RES_FEATURE_PTP));
513 	return mlx5e_tir_get_tirn(&res->ptp.tir);
514 }
515 
516 u32 mlx5e_rx_res_get_rqtn_direct(struct mlx5e_rx_res *res, unsigned int ix)
517 {
518 	return mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt);
519 }
520 
521 void mlx5e_rx_res_channels_activate(struct mlx5e_rx_res *res, struct mlx5e_channels *chs)
522 {
523 	unsigned int nch, ix;
524 	int err;
525 
526 	nch = mlx5e_channels_get_num(chs);
527 
528 	for (ix = 0; ix < chs->num; ix++)
529 		mlx5e_channels_get_regular_rqn(chs, ix, &res->rss_rqns[ix]);
530 	res->rss_nch = chs->num;
531 
532 	mlx5e_rx_res_rss_enable(res);
533 
534 	for (ix = 0; ix < nch; ix++) {
535 		u32 rqn;
536 
537 		mlx5e_channels_get_regular_rqn(chs, ix, &rqn);
538 		err = mlx5e_rqt_redirect_direct(&res->channels[ix].direct_rqt, rqn);
539 		if (err)
540 			mlx5_core_warn(res->mdev, "Failed to redirect direct RQT %#x to RQ %#x (channel %u): err = %d\n",
541 				       mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt),
542 				       rqn, ix, err);
543 
544 		if (!(res->features & MLX5E_RX_RES_FEATURE_XSK))
545 			continue;
546 
547 		if (!mlx5e_channels_get_xsk_rqn(chs, ix, &rqn))
548 			rqn = res->drop_rqn;
549 		err = mlx5e_rqt_redirect_direct(&res->channels[ix].xsk_rqt, rqn);
550 		if (err)
551 			mlx5_core_warn(res->mdev, "Failed to redirect XSK RQT %#x to RQ %#x (channel %u): err = %d\n",
552 				       mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt),
553 				       rqn, ix, err);
554 	}
555 	for (ix = nch; ix < res->max_nch; ix++) {
556 		err = mlx5e_rqt_redirect_direct(&res->channels[ix].direct_rqt, res->drop_rqn);
557 		if (err)
558 			mlx5_core_warn(res->mdev, "Failed to redirect direct RQT %#x to drop RQ %#x (channel %u): err = %d\n",
559 				       mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt),
560 				       res->drop_rqn, ix, err);
561 
562 		if (!(res->features & MLX5E_RX_RES_FEATURE_XSK))
563 			continue;
564 
565 		err = mlx5e_rqt_redirect_direct(&res->channels[ix].xsk_rqt, res->drop_rqn);
566 		if (err)
567 			mlx5_core_warn(res->mdev, "Failed to redirect XSK RQT %#x to drop RQ %#x (channel %u): err = %d\n",
568 				       mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt),
569 				       res->drop_rqn, ix, err);
570 	}
571 
572 	if (res->features & MLX5E_RX_RES_FEATURE_PTP) {
573 		u32 rqn;
574 
575 		if (!mlx5e_channels_get_ptp_rqn(chs, &rqn))
576 			rqn = res->drop_rqn;
577 
578 		err = mlx5e_rqt_redirect_direct(&res->ptp.rqt, rqn);
579 		if (err)
580 			mlx5_core_warn(res->mdev, "Failed to redirect direct RQT %#x to RQ %#x (PTP): err = %d\n",
581 				       mlx5e_rqt_get_rqtn(&res->ptp.rqt),
582 				       rqn, err);
583 	}
584 }
585 
586 void mlx5e_rx_res_channels_deactivate(struct mlx5e_rx_res *res)
587 {
588 	unsigned int ix;
589 	int err;
590 
591 	mlx5e_rx_res_rss_disable(res);
592 
593 	for (ix = 0; ix < res->max_nch; ix++) {
594 		err = mlx5e_rqt_redirect_direct(&res->channels[ix].direct_rqt, res->drop_rqn);
595 		if (err)
596 			mlx5_core_warn(res->mdev, "Failed to redirect direct RQT %#x to drop RQ %#x (channel %u): err = %d\n",
597 				       mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt),
598 				       res->drop_rqn, ix, err);
599 
600 		if (!(res->features & MLX5E_RX_RES_FEATURE_XSK))
601 			continue;
602 
603 		err = mlx5e_rqt_redirect_direct(&res->channels[ix].xsk_rqt, res->drop_rqn);
604 		if (err)
605 			mlx5_core_warn(res->mdev, "Failed to redirect XSK RQT %#x to drop RQ %#x (channel %u): err = %d\n",
606 				       mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt),
607 				       res->drop_rqn, ix, err);
608 	}
609 
610 	if (res->features & MLX5E_RX_RES_FEATURE_PTP) {
611 		err = mlx5e_rqt_redirect_direct(&res->ptp.rqt, res->drop_rqn);
612 		if (err)
613 			mlx5_core_warn(res->mdev, "Failed to redirect direct RQT %#x to drop RQ %#x (PTP): err = %d\n",
614 				       mlx5e_rqt_get_rqtn(&res->ptp.rqt),
615 				       res->drop_rqn, err);
616 	}
617 }
618 
619 int mlx5e_rx_res_xsk_activate(struct mlx5e_rx_res *res, struct mlx5e_channels *chs,
620 			      unsigned int ix)
621 {
622 	u32 rqn;
623 	int err;
624 
625 	if (!mlx5e_channels_get_xsk_rqn(chs, ix, &rqn))
626 		return -EINVAL;
627 
628 	err = mlx5e_rqt_redirect_direct(&res->channels[ix].xsk_rqt, rqn);
629 	if (err)
630 		mlx5_core_warn(res->mdev, "Failed to redirect XSK RQT %#x to XSK RQ %#x (channel %u): err = %d\n",
631 			       mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt),
632 			       rqn, ix, err);
633 	return err;
634 }
635 
636 int mlx5e_rx_res_xsk_deactivate(struct mlx5e_rx_res *res, unsigned int ix)
637 {
638 	int err;
639 
640 	err = mlx5e_rqt_redirect_direct(&res->channels[ix].xsk_rqt, res->drop_rqn);
641 	if (err)
642 		mlx5_core_warn(res->mdev, "Failed to redirect XSK RQT %#x to drop RQ %#x (channel %u): err = %d\n",
643 			       mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt),
644 			       res->drop_rqn, ix, err);
645 	return err;
646 }
647 
648 int mlx5e_rx_res_lro_set_param(struct mlx5e_rx_res *res, struct mlx5e_lro_param *lro_param)
649 {
650 	struct mlx5e_tir_builder *builder;
651 	int err, final_err;
652 	unsigned int ix;
653 
654 	builder = mlx5e_tir_builder_alloc(true);
655 	if (!builder)
656 		return -ENOMEM;
657 
658 	mlx5e_tir_builder_build_lro(builder, lro_param);
659 
660 	final_err = 0;
661 
662 	for (ix = 0; ix < MLX5E_MAX_NUM_RSS; ix++) {
663 		struct mlx5e_rss *rss = res->rss[ix];
664 
665 		if (!rss)
666 			continue;
667 
668 		err = mlx5e_rss_lro_set_param(rss, lro_param);
669 		if (err)
670 			final_err = final_err ? : err;
671 	}
672 
673 	for (ix = 0; ix < res->max_nch; ix++) {
674 		err = mlx5e_tir_modify(&res->channels[ix].direct_tir, builder);
675 		if (err) {
676 			mlx5_core_warn(res->mdev, "Failed to update LRO state of direct TIR %#x for channel %u: err = %d\n",
677 				       mlx5e_tir_get_tirn(&res->channels[ix].direct_tir), ix, err);
678 			if (!final_err)
679 				final_err = err;
680 		}
681 	}
682 
683 	mlx5e_tir_builder_free(builder);
684 	return final_err;
685 }
686 
687 struct mlx5e_rss_params_hash mlx5e_rx_res_get_current_hash(struct mlx5e_rx_res *res)
688 {
689 	return mlx5e_rss_get_hash(res->rss[0]);
690 }
691