1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES.
6 #define mlx5e_rss_warn(__dev, format, ...) \
7 dev_warn((__dev)->device, "%s:%d:(pid %d): " format, \
8 __func__, __LINE__, current->pid, \
11 static const struct mlx5e_rss_params_traffic_type rss_default_config[MLX5E_NUM_INDIR_TIRS] = {
12 [MLX5_TT_IPV4_TCP] = {
13 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV4,
14 .l4_prot_type = MLX5_L4_PROT_TYPE_TCP,
15 .rx_hash_fields = MLX5_HASH_IP_L4PORTS,
17 [MLX5_TT_IPV6_TCP] = {
18 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV6,
19 .l4_prot_type = MLX5_L4_PROT_TYPE_TCP,
20 .rx_hash_fields = MLX5_HASH_IP_L4PORTS,
22 [MLX5_TT_IPV4_UDP] = {
23 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV4,
24 .l4_prot_type = MLX5_L4_PROT_TYPE_UDP,
25 .rx_hash_fields = MLX5_HASH_IP_L4PORTS,
27 [MLX5_TT_IPV6_UDP] = {
28 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV6,
29 .l4_prot_type = MLX5_L4_PROT_TYPE_UDP,
30 .rx_hash_fields = MLX5_HASH_IP_L4PORTS,
32 [MLX5_TT_IPV4_IPSEC_AH] = {
33 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV4,
35 .rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI,
37 [MLX5_TT_IPV6_IPSEC_AH] = {
38 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV6,
40 .rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI,
42 [MLX5_TT_IPV4_IPSEC_ESP] = {
43 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV4,
45 .rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI,
47 [MLX5_TT_IPV6_IPSEC_ESP] = {
48 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV6,
50 .rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI,
53 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV4,
55 .rx_hash_fields = MLX5_HASH_IP,
58 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV6,
60 .rx_hash_fields = MLX5_HASH_IP,
64 struct mlx5e_rss_params_traffic_type
65 mlx5e_rss_get_default_tt_config(enum mlx5_traffic_types tt)
67 return rss_default_config[tt];
71 struct mlx5e_rss_params_hash hash;
72 struct mlx5e_rss_params_indir indir;
73 u32 rx_hash_fields[MLX5E_NUM_INDIR_TIRS];
74 struct mlx5e_tir *tir[MLX5E_NUM_INDIR_TIRS];
75 struct mlx5e_tir *inner_tir[MLX5E_NUM_INDIR_TIRS];
77 struct mlx5_core_dev *mdev; /* primary */
79 bool inner_ft_support;
84 void mlx5e_rss_params_indir_modify_actual_size(struct mlx5e_rss *rss, u32 num_channels)
86 rss->indir.actual_table_size = mlx5e_rqt_size(rss->mdev, num_channels);
89 int mlx5e_rss_params_indir_init(struct mlx5e_rss_params_indir *indir, struct mlx5_core_dev *mdev,
90 u32 actual_table_size, u32 max_table_size)
92 indir->table = kvmalloc_array(max_table_size, sizeof(*indir->table), GFP_KERNEL);
96 indir->max_table_size = max_table_size;
97 indir->actual_table_size = actual_table_size;
102 void mlx5e_rss_params_indir_cleanup(struct mlx5e_rss_params_indir *indir)
104 kvfree(indir->table);
107 static int mlx5e_rss_copy(struct mlx5e_rss *to, const struct mlx5e_rss *from)
109 u32 *dst_indir_table;
111 if (to->indir.actual_table_size != from->indir.actual_table_size ||
112 to->indir.max_table_size != from->indir.max_table_size) {
113 mlx5e_rss_warn(to->mdev,
114 "Failed to copy RSS due to size mismatch, src (actual %u, max %u) != dst (actual %u, max %u)\n",
115 from->indir.actual_table_size, from->indir.max_table_size,
116 to->indir.actual_table_size, to->indir.max_table_size);
120 dst_indir_table = to->indir.table;
122 to->indir.table = dst_indir_table;
123 memcpy(to->indir.table, from->indir.table,
124 from->indir.actual_table_size * sizeof(*from->indir.table));
128 static struct mlx5e_rss *mlx5e_rss_init_copy(const struct mlx5e_rss *from)
130 struct mlx5e_rss *rss;
133 rss = kvzalloc(sizeof(*rss), GFP_KERNEL);
135 return ERR_PTR(-ENOMEM);
137 err = mlx5e_rss_params_indir_init(&rss->indir, from->mdev, from->indir.actual_table_size,
138 from->indir.max_table_size);
142 err = mlx5e_rss_copy(rss, from);
149 mlx5e_rss_params_indir_cleanup(&rss->indir);
155 static void mlx5e_rss_params_init(struct mlx5e_rss *rss)
157 enum mlx5_traffic_types tt;
159 rss->hash.hfunc = ETH_RSS_HASH_TOP;
160 netdev_rss_key_fill(rss->hash.toeplitz_hash_key,
161 sizeof(rss->hash.toeplitz_hash_key));
162 for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
163 rss->rx_hash_fields[tt] =
164 mlx5e_rss_get_default_tt_config(tt).rx_hash_fields;
167 static struct mlx5e_tir **rss_get_tirp(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
170 return inner ? &rss->inner_tir[tt] : &rss->tir[tt];
173 static struct mlx5e_tir *rss_get_tir(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
176 return *rss_get_tirp(rss, tt, inner);
179 static struct mlx5e_rss_params_traffic_type
180 mlx5e_rss_get_tt_config(struct mlx5e_rss *rss, enum mlx5_traffic_types tt)
182 struct mlx5e_rss_params_traffic_type rss_tt;
184 rss_tt = mlx5e_rss_get_default_tt_config(tt);
185 rss_tt.rx_hash_fields = rss->rx_hash_fields[tt];
189 static int mlx5e_rss_create_tir(struct mlx5e_rss *rss,
190 enum mlx5_traffic_types tt,
191 const struct mlx5e_packet_merge_param *init_pkt_merge_param,
194 struct mlx5e_rss_params_traffic_type rss_tt;
195 struct mlx5e_tir_builder *builder;
196 struct mlx5e_tir **tir_p;
197 struct mlx5e_tir *tir;
201 if (inner && !rss->inner_ft_support) {
202 mlx5e_rss_warn(rss->mdev,
203 "Cannot create inner indirect TIR[%d], RSS inner FT is not supported.\n",
208 tir_p = rss_get_tirp(rss, tt, inner);
212 tir = kvzalloc(sizeof(*tir), GFP_KERNEL);
216 builder = mlx5e_tir_builder_alloc(false);
222 rqtn = mlx5e_rqt_get_rqtn(&rss->rqt);
223 mlx5e_tir_builder_build_rqt(builder, rss->mdev->mlx5e_res.hw_objs.td.tdn,
224 rqtn, rss->inner_ft_support);
225 mlx5e_tir_builder_build_packet_merge(builder, init_pkt_merge_param);
226 rss_tt = mlx5e_rss_get_tt_config(rss, tt);
227 mlx5e_tir_builder_build_rss(builder, &rss->hash, &rss_tt, inner);
229 err = mlx5e_tir_init(tir, builder, rss->mdev, true);
230 mlx5e_tir_builder_free(builder);
232 mlx5e_rss_warn(rss->mdev, "Failed to create %sindirect TIR: err = %d, tt = %d\n",
233 inner ? "inner " : "", err, tt);
245 static void mlx5e_rss_destroy_tir(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
248 struct mlx5e_tir **tir_p;
249 struct mlx5e_tir *tir;
251 tir_p = rss_get_tirp(rss, tt, inner);
256 mlx5e_tir_destroy(tir);
261 static int mlx5e_rss_create_tirs(struct mlx5e_rss *rss,
262 const struct mlx5e_packet_merge_param *init_pkt_merge_param,
265 enum mlx5_traffic_types tt, max_tt;
268 for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
269 err = mlx5e_rss_create_tir(rss, tt, init_pkt_merge_param, inner);
271 goto err_destroy_tirs;
278 for (tt = 0; tt < max_tt; tt++)
279 mlx5e_rss_destroy_tir(rss, tt, inner);
283 static void mlx5e_rss_destroy_tirs(struct mlx5e_rss *rss, bool inner)
285 enum mlx5_traffic_types tt;
287 for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
288 mlx5e_rss_destroy_tir(rss, tt, inner);
291 static int mlx5e_rss_update_tir(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
294 struct mlx5e_rss_params_traffic_type rss_tt;
295 struct mlx5e_tir_builder *builder;
296 struct mlx5e_tir *tir;
299 tir = rss_get_tir(rss, tt, inner);
303 builder = mlx5e_tir_builder_alloc(true);
307 rss_tt = mlx5e_rss_get_tt_config(rss, tt);
309 mlx5e_tir_builder_build_rss(builder, &rss->hash, &rss_tt, inner);
310 err = mlx5e_tir_modify(tir, builder);
312 mlx5e_tir_builder_free(builder);
316 static int mlx5e_rss_update_tirs(struct mlx5e_rss *rss)
318 enum mlx5_traffic_types tt;
323 for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
324 err = mlx5e_rss_update_tir(rss, tt, false);
326 retval = retval ? : err;
327 mlx5e_rss_warn(rss->mdev,
328 "Failed to update RSS hash of indirect TIR for traffic type %d: err = %d\n",
332 if (!rss->inner_ft_support)
335 err = mlx5e_rss_update_tir(rss, tt, true);
337 retval = retval ? : err;
338 mlx5e_rss_warn(rss->mdev,
339 "Failed to update RSS hash of inner indirect TIR for traffic type %d: err = %d\n",
346 static int mlx5e_rss_init_no_tirs(struct mlx5e_rss *rss)
348 mlx5e_rss_params_init(rss);
349 refcount_set(&rss->refcnt, 1);
351 return mlx5e_rqt_init_direct(&rss->rqt, rss->mdev, true,
352 rss->drop_rqn, rss->indir.max_table_size);
355 struct mlx5e_rss *mlx5e_rss_init(struct mlx5_core_dev *mdev, bool inner_ft_support, u32 drop_rqn,
356 const struct mlx5e_packet_merge_param *init_pkt_merge_param,
357 enum mlx5e_rss_init_type type, unsigned int nch,
358 unsigned int max_nch)
360 struct mlx5e_rss *rss;
363 rss = kvzalloc(sizeof(*rss), GFP_KERNEL);
365 return ERR_PTR(-ENOMEM);
367 err = mlx5e_rss_params_indir_init(&rss->indir, mdev,
368 mlx5e_rqt_size(mdev, nch),
369 mlx5e_rqt_size(mdev, max_nch));
374 rss->inner_ft_support = inner_ft_support;
375 rss->drop_rqn = drop_rqn;
377 err = mlx5e_rss_init_no_tirs(rss);
381 if (type == MLX5E_RSS_INIT_NO_TIRS)
384 err = mlx5e_rss_create_tirs(rss, init_pkt_merge_param, false);
386 goto err_destroy_rqt;
388 if (inner_ft_support) {
389 err = mlx5e_rss_create_tirs(rss, init_pkt_merge_param, true);
391 goto err_destroy_tirs;
398 mlx5e_rss_destroy_tirs(rss, false);
400 mlx5e_rqt_destroy(&rss->rqt);
402 mlx5e_rss_params_indir_cleanup(&rss->indir);
408 int mlx5e_rss_cleanup(struct mlx5e_rss *rss)
410 if (!refcount_dec_if_one(&rss->refcnt))
413 mlx5e_rss_destroy_tirs(rss, false);
415 if (rss->inner_ft_support)
416 mlx5e_rss_destroy_tirs(rss, true);
418 mlx5e_rqt_destroy(&rss->rqt);
419 mlx5e_rss_params_indir_cleanup(&rss->indir);
425 void mlx5e_rss_refcnt_inc(struct mlx5e_rss *rss)
427 refcount_inc(&rss->refcnt);
430 void mlx5e_rss_refcnt_dec(struct mlx5e_rss *rss)
432 refcount_dec(&rss->refcnt);
435 unsigned int mlx5e_rss_refcnt_read(struct mlx5e_rss *rss)
437 return refcount_read(&rss->refcnt);
440 u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
443 struct mlx5e_tir *tir;
445 WARN_ON(inner && !rss->inner_ft_support);
446 tir = rss_get_tir(rss, tt, inner);
449 return mlx5e_tir_get_tirn(tir);
452 /* Fill the "tirn" output parameter.
453 * Create the requested TIR if it's its first usage.
455 int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss,
456 enum mlx5_traffic_types tt,
457 const struct mlx5e_packet_merge_param *init_pkt_merge_param,
458 bool inner, u32 *tirn)
460 struct mlx5e_tir *tir;
462 tir = rss_get_tir(rss, tt, inner);
463 if (!tir) { /* TIR doesn't exist, create one */
466 err = mlx5e_rss_create_tir(rss, tt, init_pkt_merge_param, inner);
469 tir = rss_get_tir(rss, tt, inner);
472 *tirn = mlx5e_tir_get_tirn(tir);
476 static int mlx5e_rss_apply(struct mlx5e_rss *rss, u32 *rqns, u32 *vhca_ids, unsigned int num_rqns)
480 err = mlx5e_rqt_redirect_indir(&rss->rqt, rqns, vhca_ids, num_rqns, rss->hash.hfunc,
483 mlx5e_rss_warn(rss->mdev, "Failed to redirect RQT %#x to channels: err = %d\n",
484 mlx5e_rqt_get_rqtn(&rss->rqt), err);
488 void mlx5e_rss_enable(struct mlx5e_rss *rss, u32 *rqns, u32 *vhca_ids, unsigned int num_rqns)
491 mlx5e_rss_apply(rss, rqns, vhca_ids, num_rqns);
494 void mlx5e_rss_disable(struct mlx5e_rss *rss)
498 rss->enabled = false;
499 err = mlx5e_rqt_redirect_direct(&rss->rqt, rss->drop_rqn, NULL);
501 mlx5e_rss_warn(rss->mdev, "Failed to redirect RQT %#x to drop RQ %#x: err = %d\n",
502 mlx5e_rqt_get_rqtn(&rss->rqt), rss->drop_rqn, err);
505 int mlx5e_rss_packet_merge_set_param(struct mlx5e_rss *rss,
506 struct mlx5e_packet_merge_param *pkt_merge_param)
508 struct mlx5e_tir_builder *builder;
509 enum mlx5_traffic_types tt;
512 builder = mlx5e_tir_builder_alloc(true);
516 mlx5e_tir_builder_build_packet_merge(builder, pkt_merge_param);
520 for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
521 struct mlx5e_tir *tir;
523 tir = rss_get_tir(rss, tt, false);
526 err = mlx5e_tir_modify(tir, builder);
528 mlx5e_rss_warn(rss->mdev, "Failed to update packet merge state of indirect TIR %#x for traffic type %d: err = %d\n",
529 mlx5e_tir_get_tirn(tir), tt, err);
535 if (!rss->inner_ft_support)
538 tir = rss_get_tir(rss, tt, true);
541 err = mlx5e_tir_modify(tir, builder);
543 mlx5e_rss_warn(rss->mdev, "Failed to update packet merge state of inner indirect TIR %#x for traffic type %d: err = %d\n",
544 mlx5e_tir_get_tirn(tir), tt, err);
550 mlx5e_tir_builder_free(builder);
554 int mlx5e_rss_get_rxfh(struct mlx5e_rss *rss, u32 *indir, u8 *key, u8 *hfunc)
557 memcpy(indir, rss->indir.table,
558 rss->indir.actual_table_size * sizeof(*rss->indir.table));
561 memcpy(key, rss->hash.toeplitz_hash_key,
562 sizeof(rss->hash.toeplitz_hash_key));
565 *hfunc = rss->hash.hfunc;
570 int mlx5e_rss_set_rxfh(struct mlx5e_rss *rss, const u32 *indir,
571 const u8 *key, const u8 *hfunc,
572 u32 *rqns, u32 *vhca_ids, unsigned int num_rqns)
574 bool changed_indir = false;
575 bool changed_hash = false;
576 struct mlx5e_rss *old_rss;
579 old_rss = mlx5e_rss_init_copy(rss);
581 return PTR_ERR(old_rss);
583 if (hfunc && *hfunc != rss->hash.hfunc) {
585 case ETH_RSS_HASH_XOR:
586 case ETH_RSS_HASH_TOP:
593 changed_indir = true;
594 rss->hash.hfunc = *hfunc;
598 if (rss->hash.hfunc == ETH_RSS_HASH_TOP)
600 memcpy(rss->hash.toeplitz_hash_key, key,
601 sizeof(rss->hash.toeplitz_hash_key));
605 changed_indir = true;
607 memcpy(rss->indir.table, indir,
608 rss->indir.actual_table_size * sizeof(*rss->indir.table));
611 if (changed_indir && rss->enabled) {
612 err = mlx5e_rss_apply(rss, rqns, vhca_ids, num_rqns);
614 mlx5e_rss_copy(rss, old_rss);
620 mlx5e_rss_update_tirs(rss);
623 mlx5e_rss_params_indir_cleanup(&old_rss->indir);
629 struct mlx5e_rss_params_hash mlx5e_rss_get_hash(struct mlx5e_rss *rss)
634 u8 mlx5e_rss_get_hash_fields(struct mlx5e_rss *rss, enum mlx5_traffic_types tt)
636 return rss->rx_hash_fields[tt];
639 int mlx5e_rss_set_hash_fields(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
642 u8 old_rx_hash_fields;
645 old_rx_hash_fields = rss->rx_hash_fields[tt];
647 if (old_rx_hash_fields == rx_hash_fields)
650 rss->rx_hash_fields[tt] = rx_hash_fields;
652 err = mlx5e_rss_update_tir(rss, tt, false);
654 rss->rx_hash_fields[tt] = old_rx_hash_fields;
655 mlx5e_rss_warn(rss->mdev,
656 "Failed to update RSS hash fields of indirect TIR for traffic type %d: err = %d\n",
661 if (!(rss->inner_ft_support))
664 err = mlx5e_rss_update_tir(rss, tt, true);
666 /* Partial update happened. Try to revert - it may fail too, but
667 * there is nothing more we can do.
669 rss->rx_hash_fields[tt] = old_rx_hash_fields;
670 mlx5e_rss_warn(rss->mdev,
671 "Failed to update RSS hash fields of inner indirect TIR for traffic type %d: err = %d\n",
673 if (mlx5e_rss_update_tir(rss, tt, false))
674 mlx5e_rss_warn(rss->mdev,
675 "Partial update of RSS hash fields happened: failed to revert indirect TIR for traffic type %d to the old values\n",
682 void mlx5e_rss_set_indir_uniform(struct mlx5e_rss *rss, unsigned int nch)
684 mlx5e_rss_params_indir_init_uniform(&rss->indir, nch);