Skip to content

Commit 3f6d08d

Browse files
ogerlitzSaeed Mahameed
authored andcommitted
net/mlx5e: Add RSS support for hairpin
Support RSS for hairpin traffic. We create multiple hairpin RQ/SQ pairs and RSS TTC table per hairpin instance and steer the related flows through that table so they are spread between the pairs. We open one pair per 50Gbs link speed, for all speeds <= 50Gbs, there is one pair and no RSS while for 100Gbs ports two RSSed pairs. Signed-off-by: Or Gerlitz <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent ddae74a commit 3f6d08d

File tree

3 files changed

+205
-13
lines changed

3 files changed

+205
-13
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,11 @@ enum {
697697
MLX5E_ARFS_FT_LEVEL
698698
};
699699

700+
enum {
701+
MLX5E_TC_FT_LEVEL = 0,
702+
MLX5E_TC_TTC_FT_LEVEL,
703+
};
704+
700705
struct mlx5e_ethtool_table {
701706
struct mlx5_flow_table *ft;
702707
int num_rules;
@@ -1057,6 +1062,8 @@ int mlx5e_open(struct net_device *netdev);
10571062
void mlx5e_update_stats_work(struct work_struct *work);
10581063
u32 mlx5e_choose_lro_timeout(struct mlx5_core_dev *mdev, u32 wanted_timeout);
10591064

1065+
int mlx5e_bits_invert(unsigned long a, int size);
1066+
10601067
/* ethtool helpers */
10611068
void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv,
10621069
struct ethtool_drvinfo *drvinfo);

drivers/net/ethernet/mellanox/mlx5/core/en_main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2219,7 +2219,7 @@ static int mlx5e_rx_hash_fn(int hfunc)
22192219
MLX5_RX_HASH_FN_INVERTED_XOR8;
22202220
}
22212221

2222-
static int mlx5e_bits_invert(unsigned long a, int size)
2222+
int mlx5e_bits_invert(unsigned long a, int size)
22232223
{
22242224
int inv = 0;
22252225
int i;

drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

Lines changed: 197 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,22 @@
5151
#include "en_tc.h"
5252
#include "eswitch.h"
5353
#include "vxlan.h"
54+
#include "fs_core.h"
5455

5556
struct mlx5_nic_flow_attr {
5657
u32 action;
5758
u32 flow_tag;
5859
u32 mod_hdr_id;
5960
u32 hairpin_tirn;
61+
struct mlx5_flow_table *hairpin_ft;
6062
};
6163

6264
enum {
6365
MLX5E_TC_FLOW_ESWITCH = BIT(0),
6466
MLX5E_TC_FLOW_NIC = BIT(1),
6567
MLX5E_TC_FLOW_OFFLOADED = BIT(2),
6668
MLX5E_TC_FLOW_HAIRPIN = BIT(3),
69+
MLX5E_TC_FLOW_HAIRPIN_RSS = BIT(4),
6770
};
6871

6972
struct mlx5e_tc_flow {
@@ -100,8 +103,14 @@ struct mlx5e_hairpin {
100103
struct mlx5_hairpin *pair;
101104

102105
struct mlx5_core_dev *func_mdev;
106+
struct mlx5e_priv *func_priv;
103107
u32 tdn;
104108
u32 tirn;
109+
110+
int num_channels;
111+
struct mlx5e_rqt indir_rqt;
112+
u32 indir_tirn[MLX5E_NUM_INDIR_TIRS];
113+
struct mlx5e_ttc_table ttc;
105114
};
106115

107116
struct mlx5e_hairpin_entry {
@@ -290,6 +299,151 @@ static void mlx5e_hairpin_destroy_transport(struct mlx5e_hairpin *hp)
290299
mlx5_core_dealloc_transport_domain(hp->func_mdev, hp->tdn);
291300
}
292301

302+
static void mlx5e_hairpin_fill_rqt_rqns(struct mlx5e_hairpin *hp, void *rqtc)
303+
{
304+
u32 indirection_rqt[MLX5E_INDIR_RQT_SIZE], rqn;
305+
struct mlx5e_priv *priv = hp->func_priv;
306+
int i, ix, sz = MLX5E_INDIR_RQT_SIZE;
307+
308+
mlx5e_build_default_indir_rqt(indirection_rqt, sz,
309+
hp->num_channels);
310+
311+
for (i = 0; i < sz; i++) {
312+
ix = i;
313+
if (priv->channels.params.rss_hfunc == ETH_RSS_HASH_XOR)
314+
ix = mlx5e_bits_invert(i, ilog2(sz));
315+
ix = indirection_rqt[ix];
316+
rqn = hp->pair->rqn[ix];
317+
MLX5_SET(rqtc, rqtc, rq_num[i], rqn);
318+
}
319+
}
320+
321+
static int mlx5e_hairpin_create_indirect_rqt(struct mlx5e_hairpin *hp)
322+
{
323+
int inlen, err, sz = MLX5E_INDIR_RQT_SIZE;
324+
struct mlx5e_priv *priv = hp->func_priv;
325+
struct mlx5_core_dev *mdev = priv->mdev;
326+
void *rqtc;
327+
u32 *in;
328+
329+
inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz;
330+
in = kvzalloc(inlen, GFP_KERNEL);
331+
if (!in)
332+
return -ENOMEM;
333+
334+
rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context);
335+
336+
MLX5_SET(rqtc, rqtc, rqt_actual_size, sz);
337+
MLX5_SET(rqtc, rqtc, rqt_max_size, sz);
338+
339+
mlx5e_hairpin_fill_rqt_rqns(hp, rqtc);
340+
341+
err = mlx5_core_create_rqt(mdev, in, inlen, &hp->indir_rqt.rqtn);
342+
if (!err)
343+
hp->indir_rqt.enabled = true;
344+
345+
kvfree(in);
346+
return err;
347+
}
348+
349+
static int mlx5e_hairpin_create_indirect_tirs(struct mlx5e_hairpin *hp)
350+
{
351+
struct mlx5e_priv *priv = hp->func_priv;
352+
u32 in[MLX5_ST_SZ_DW(create_tir_in)];
353+
int tt, i, err;
354+
void *tirc;
355+
356+
for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
357+
memset(in, 0, MLX5_ST_SZ_BYTES(create_tir_in));
358+
tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
359+
360+
MLX5_SET(tirc, tirc, transport_domain, hp->tdn);
361+
MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT);
362+
MLX5_SET(tirc, tirc, indirect_table, hp->indir_rqt.rqtn);
363+
mlx5e_build_indir_tir_ctx_hash(&priv->channels.params, tt, tirc, false);
364+
365+
err = mlx5_core_create_tir(hp->func_mdev, in,
366+
MLX5_ST_SZ_BYTES(create_tir_in), &hp->indir_tirn[tt]);
367+
if (err) {
368+
mlx5_core_warn(hp->func_mdev, "create indirect tirs failed, %d\n", err);
369+
goto err_destroy_tirs;
370+
}
371+
}
372+
return 0;
373+
374+
err_destroy_tirs:
375+
for (i = 0; i < tt; i++)
376+
mlx5_core_destroy_tir(hp->func_mdev, hp->indir_tirn[i]);
377+
return err;
378+
}
379+
380+
static void mlx5e_hairpin_destroy_indirect_tirs(struct mlx5e_hairpin *hp)
381+
{
382+
int tt;
383+
384+
for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
385+
mlx5_core_destroy_tir(hp->func_mdev, hp->indir_tirn[tt]);
386+
}
387+
388+
static void mlx5e_hairpin_set_ttc_params(struct mlx5e_hairpin *hp,
389+
struct ttc_params *ttc_params)
390+
{
391+
struct mlx5_flow_table_attr *ft_attr = &ttc_params->ft_attr;
392+
int tt;
393+
394+
memset(ttc_params, 0, sizeof(*ttc_params));
395+
396+
ttc_params->any_tt_tirn = hp->tirn;
397+
398+
for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
399+
ttc_params->indir_tirn[tt] = hp->indir_tirn[tt];
400+
401+
ft_attr->max_fte = MLX5E_NUM_TT;
402+
ft_attr->level = MLX5E_TC_TTC_FT_LEVEL;
403+
ft_attr->prio = MLX5E_TC_PRIO;
404+
}
405+
406+
static int mlx5e_hairpin_rss_init(struct mlx5e_hairpin *hp)
407+
{
408+
struct mlx5e_priv *priv = hp->func_priv;
409+
struct ttc_params ttc_params;
410+
int err;
411+
412+
err = mlx5e_hairpin_create_indirect_rqt(hp);
413+
if (err)
414+
return err;
415+
416+
err = mlx5e_hairpin_create_indirect_tirs(hp);
417+
if (err)
418+
goto err_create_indirect_tirs;
419+
420+
mlx5e_hairpin_set_ttc_params(hp, &ttc_params);
421+
err = mlx5e_create_ttc_table(priv, &ttc_params, &hp->ttc);
422+
if (err)
423+
goto err_create_ttc_table;
424+
425+
netdev_dbg(priv->netdev, "add hairpin: using %d channels rss ttc table id %x\n",
426+
hp->num_channels, hp->ttc.ft.t->id);
427+
428+
return 0;
429+
430+
err_create_ttc_table:
431+
mlx5e_hairpin_destroy_indirect_tirs(hp);
432+
err_create_indirect_tirs:
433+
mlx5e_destroy_rqt(priv, &hp->indir_rqt);
434+
435+
return err;
436+
}
437+
438+
static void mlx5e_hairpin_rss_cleanup(struct mlx5e_hairpin *hp)
439+
{
440+
struct mlx5e_priv *priv = hp->func_priv;
441+
442+
mlx5e_destroy_ttc_table(priv, &hp->ttc);
443+
mlx5e_hairpin_destroy_indirect_tirs(hp);
444+
mlx5e_destroy_rqt(priv, &hp->indir_rqt);
445+
}
446+
293447
static struct mlx5e_hairpin *
294448
mlx5e_hairpin_create(struct mlx5e_priv *priv, struct mlx5_hairpin_params *params,
295449
int peer_ifindex)
@@ -313,13 +467,23 @@ mlx5e_hairpin_create(struct mlx5e_priv *priv, struct mlx5_hairpin_params *params
313467
}
314468
hp->pair = pair;
315469
hp->func_mdev = func_mdev;
470+
hp->func_priv = priv;
471+
hp->num_channels = params->num_channels;
316472

317473
err = mlx5e_hairpin_create_transport(hp);
318474
if (err)
319475
goto create_transport_err;
320476

477+
if (hp->num_channels > 1) {
478+
err = mlx5e_hairpin_rss_init(hp);
479+
if (err)
480+
goto rss_init_err;
481+
}
482+
321483
return hp;
322484

485+
rss_init_err:
486+
mlx5e_hairpin_destroy_transport(hp);
323487
create_transport_err:
324488
mlx5_core_hairpin_destroy(hp->pair);
325489
create_pair_err:
@@ -329,6 +493,8 @@ mlx5e_hairpin_create(struct mlx5e_priv *priv, struct mlx5_hairpin_params *params
329493

330494
static void mlx5e_hairpin_destroy(struct mlx5e_hairpin *hp)
331495
{
496+
if (hp->num_channels > 1)
497+
mlx5e_hairpin_rss_cleanup(hp);
332498
mlx5e_hairpin_destroy_transport(hp);
333499
mlx5_core_hairpin_destroy(hp->pair);
334500
kvfree(hp);
@@ -400,6 +566,8 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
400566
struct mlx5_core_dev *peer_mdev;
401567
struct mlx5e_hairpin_entry *hpe;
402568
struct mlx5e_hairpin *hp;
569+
u64 link_speed64;
570+
u32 link_speed;
403571
u8 match_prio;
404572
u16 peer_id;
405573
int err;
@@ -433,6 +601,13 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
433601
MLX5_CAP_GEN(priv->mdev, log_min_hairpin_wq_data_sz));
434602
params.q_counter = priv->q_counter;
435603

604+
/* set hairpin pair per each 50Gbs share of the link */
605+
mlx5e_get_max_linkspeed(priv->mdev, &link_speed);
606+
link_speed = max_t(u32, link_speed, 50000);
607+
link_speed64 = link_speed;
608+
do_div(link_speed64, 50000);
609+
params.num_channels = link_speed64;
610+
436611
hp = mlx5e_hairpin_create(priv, &params, peer_ifindex);
437612
if (IS_ERR(hp)) {
438613
err = PTR_ERR(hp);
@@ -448,8 +623,14 @@ static int mlx5e_hairpin_flow_add(struct mlx5e_priv *priv,
448623
hash_hairpin_info(peer_id, match_prio));
449624

450625
attach_flow:
451-
flow->nic_attr->hairpin_tirn = hpe->hp->tirn;
626+
if (hpe->hp->num_channels > 1) {
627+
flow->flags |= MLX5E_TC_FLOW_HAIRPIN_RSS;
628+
flow->nic_attr->hairpin_ft = hpe->hp->ttc.ft.t;
629+
} else {
630+
flow->nic_attr->hairpin_tirn = hpe->hp->tirn;
631+
}
452632
list_add(&flow->hairpin, &hpe->flows);
633+
453634
return 0;
454635

455636
create_hairpin_err:
@@ -497,20 +678,24 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
497678
bool table_created = false;
498679
int err, dest_ix = 0;
499680

500-
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
501-
if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) {
502-
err = mlx5e_hairpin_flow_add(priv, flow, parse_attr);
503-
if (err) {
504-
rule = ERR_PTR(err);
505-
goto err_add_hairpin_flow;
506-
}
681+
if (flow->flags & MLX5E_TC_FLOW_HAIRPIN) {
682+
err = mlx5e_hairpin_flow_add(priv, flow, parse_attr);
683+
if (err) {
684+
rule = ERR_PTR(err);
685+
goto err_add_hairpin_flow;
686+
}
687+
if (flow->flags & MLX5E_TC_FLOW_HAIRPIN_RSS) {
688+
dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
689+
dest[dest_ix].ft = attr->hairpin_ft;
690+
} else {
507691
dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_TIR;
508692
dest[dest_ix].tir_num = attr->hairpin_tirn;
509-
} else {
510-
dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
511-
dest[dest_ix].ft = priv->fs.vlan.ft.t;
512693
}
513694
dest_ix++;
695+
} else if (attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
696+
dest[dest_ix].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
697+
dest[dest_ix].ft = priv->fs.vlan.ft.t;
698+
dest_ix++;
514699
}
515700

516701
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
@@ -551,7 +736,7 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
551736
MLX5E_TC_PRIO,
552737
tc_tbl_size,
553738
MLX5E_TC_TABLE_NUM_GROUPS,
554-
0, 0);
739+
MLX5E_TC_FT_LEVEL, 0);
555740
if (IS_ERR(priv->fs.tc.t)) {
556741
netdev_err(priv->netdev,
557742
"Failed to create tc offload table\n");

0 commit comments

Comments
 (0)