cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rss.c (14443B)


      1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
      2// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES.
      3
      4#include "rss.h"
      5
      6#define mlx5e_rss_warn(__dev, format, ...)			\
      7	dev_warn((__dev)->device, "%s:%d:(pid %d): " format,	\
      8		 __func__, __LINE__, current->pid,		\
      9		 ##__VA_ARGS__)
     10
     11static 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,
     16	},
     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,
     21	},
     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,
     26	},
     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,
     31	},
     32	[MLX5_TT_IPV4_IPSEC_AH] = {
     33		.l3_prot_type = MLX5_L3_PROT_TYPE_IPV4,
     34		.l4_prot_type = 0,
     35		.rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI,
     36	},
     37	[MLX5_TT_IPV6_IPSEC_AH] = {
     38		.l3_prot_type = MLX5_L3_PROT_TYPE_IPV6,
     39		.l4_prot_type = 0,
     40		.rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI,
     41	},
     42	[MLX5_TT_IPV4_IPSEC_ESP] = {
     43		.l3_prot_type = MLX5_L3_PROT_TYPE_IPV4,
     44		.l4_prot_type = 0,
     45		.rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI,
     46	},
     47	[MLX5_TT_IPV6_IPSEC_ESP] = {
     48		.l3_prot_type = MLX5_L3_PROT_TYPE_IPV6,
     49		.l4_prot_type = 0,
     50		.rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI,
     51	},
     52	[MLX5_TT_IPV4] = {
     53		.l3_prot_type = MLX5_L3_PROT_TYPE_IPV4,
     54		.l4_prot_type = 0,
     55		.rx_hash_fields = MLX5_HASH_IP,
     56	},
     57	[MLX5_TT_IPV6] = {
     58		.l3_prot_type = MLX5_L3_PROT_TYPE_IPV6,
     59		.l4_prot_type = 0,
     60		.rx_hash_fields = MLX5_HASH_IP,
     61	},
     62};
     63
     64struct mlx5e_rss_params_traffic_type
     65mlx5e_rss_get_default_tt_config(enum mlx5_traffic_types tt)
     66{
     67	return rss_default_config[tt];
     68}
     69
     70struct mlx5e_rss {
     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];
     76	struct mlx5e_rqt rqt;
     77	struct mlx5_core_dev *mdev;
     78	u32 drop_rqn;
     79	bool inner_ft_support;
     80	bool enabled;
     81	refcount_t refcnt;
     82};
     83
     84struct mlx5e_rss *mlx5e_rss_alloc(void)
     85{
     86	return kvzalloc(sizeof(struct mlx5e_rss), GFP_KERNEL);
     87}
     88
     89void mlx5e_rss_free(struct mlx5e_rss *rss)
     90{
     91	kvfree(rss);
     92}
     93
     94static void mlx5e_rss_params_init(struct mlx5e_rss *rss)
     95{
     96	enum mlx5_traffic_types tt;
     97
     98	rss->hash.hfunc = ETH_RSS_HASH_TOP;
     99	netdev_rss_key_fill(rss->hash.toeplitz_hash_key,
    100			    sizeof(rss->hash.toeplitz_hash_key));
    101	for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
    102		rss->rx_hash_fields[tt] =
    103			mlx5e_rss_get_default_tt_config(tt).rx_hash_fields;
    104}
    105
    106static struct mlx5e_tir **rss_get_tirp(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
    107				       bool inner)
    108{
    109	return inner ? &rss->inner_tir[tt] : &rss->tir[tt];
    110}
    111
    112static struct mlx5e_tir *rss_get_tir(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
    113				     bool inner)
    114{
    115	return *rss_get_tirp(rss, tt, inner);
    116}
    117
    118static struct mlx5e_rss_params_traffic_type
    119mlx5e_rss_get_tt_config(struct mlx5e_rss *rss, enum mlx5_traffic_types tt)
    120{
    121	struct mlx5e_rss_params_traffic_type rss_tt;
    122
    123	rss_tt = mlx5e_rss_get_default_tt_config(tt);
    124	rss_tt.rx_hash_fields = rss->rx_hash_fields[tt];
    125	return rss_tt;
    126}
    127
    128static int mlx5e_rss_create_tir(struct mlx5e_rss *rss,
    129				enum mlx5_traffic_types tt,
    130				const struct mlx5e_packet_merge_param *init_pkt_merge_param,
    131				bool inner)
    132{
    133	struct mlx5e_rss_params_traffic_type rss_tt;
    134	struct mlx5e_tir_builder *builder;
    135	struct mlx5e_tir **tir_p;
    136	struct mlx5e_tir *tir;
    137	u32 rqtn;
    138	int err;
    139
    140	if (inner && !rss->inner_ft_support) {
    141		mlx5e_rss_warn(rss->mdev,
    142			       "Cannot create inner indirect TIR[%d], RSS inner FT is not supported.\n",
    143			       tt);
    144		return -EINVAL;
    145	}
    146
    147	tir_p = rss_get_tirp(rss, tt, inner);
    148	if (*tir_p)
    149		return -EINVAL;
    150
    151	tir = kvzalloc(sizeof(*tir), GFP_KERNEL);
    152	if (!tir)
    153		return -ENOMEM;
    154
    155	builder = mlx5e_tir_builder_alloc(false);
    156	if (!builder) {
    157		err = -ENOMEM;
    158		goto free_tir;
    159	}
    160
    161	rqtn = mlx5e_rqt_get_rqtn(&rss->rqt);
    162	mlx5e_tir_builder_build_rqt(builder, rss->mdev->mlx5e_res.hw_objs.td.tdn,
    163				    rqtn, rss->inner_ft_support);
    164	mlx5e_tir_builder_build_packet_merge(builder, init_pkt_merge_param);
    165	rss_tt = mlx5e_rss_get_tt_config(rss, tt);
    166	mlx5e_tir_builder_build_rss(builder, &rss->hash, &rss_tt, inner);
    167
    168	err = mlx5e_tir_init(tir, builder, rss->mdev, true);
    169	mlx5e_tir_builder_free(builder);
    170	if (err) {
    171		mlx5e_rss_warn(rss->mdev, "Failed to create %sindirect TIR: err = %d, tt = %d\n",
    172			       inner ? "inner " : "", err, tt);
    173		goto free_tir;
    174	}
    175
    176	*tir_p = tir;
    177	return 0;
    178
    179free_tir:
    180	kvfree(tir);
    181	return err;
    182}
    183
    184static void mlx5e_rss_destroy_tir(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
    185				  bool inner)
    186{
    187	struct mlx5e_tir **tir_p;
    188	struct mlx5e_tir *tir;
    189
    190	tir_p = rss_get_tirp(rss, tt, inner);
    191	if (!*tir_p)
    192		return;
    193
    194	tir = *tir_p;
    195	mlx5e_tir_destroy(tir);
    196	kvfree(tir);
    197	*tir_p = NULL;
    198}
    199
    200static int mlx5e_rss_create_tirs(struct mlx5e_rss *rss,
    201				 const struct mlx5e_packet_merge_param *init_pkt_merge_param,
    202				 bool inner)
    203{
    204	enum mlx5_traffic_types tt, max_tt;
    205	int err;
    206
    207	for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
    208		err = mlx5e_rss_create_tir(rss, tt, init_pkt_merge_param, inner);
    209		if (err)
    210			goto err_destroy_tirs;
    211	}
    212
    213	return 0;
    214
    215err_destroy_tirs:
    216	max_tt = tt;
    217	for (tt = 0; tt < max_tt; tt++)
    218		mlx5e_rss_destroy_tir(rss, tt, inner);
    219	return err;
    220}
    221
    222static void mlx5e_rss_destroy_tirs(struct mlx5e_rss *rss, bool inner)
    223{
    224	enum mlx5_traffic_types tt;
    225
    226	for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++)
    227		mlx5e_rss_destroy_tir(rss, tt, inner);
    228}
    229
    230static int mlx5e_rss_update_tir(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
    231				bool inner)
    232{
    233	struct mlx5e_rss_params_traffic_type rss_tt;
    234	struct mlx5e_tir_builder *builder;
    235	struct mlx5e_tir *tir;
    236	int err;
    237
    238	tir = rss_get_tir(rss, tt, inner);
    239	if (!tir)
    240		return 0;
    241
    242	builder = mlx5e_tir_builder_alloc(true);
    243	if (!builder)
    244		return -ENOMEM;
    245
    246	rss_tt = mlx5e_rss_get_tt_config(rss, tt);
    247
    248	mlx5e_tir_builder_build_rss(builder, &rss->hash, &rss_tt, inner);
    249	err = mlx5e_tir_modify(tir, builder);
    250
    251	mlx5e_tir_builder_free(builder);
    252	return err;
    253}
    254
    255static int mlx5e_rss_update_tirs(struct mlx5e_rss *rss)
    256{
    257	enum mlx5_traffic_types tt;
    258	int err, retval;
    259
    260	retval = 0;
    261
    262	for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
    263		err = mlx5e_rss_update_tir(rss, tt, false);
    264		if (err) {
    265			retval = retval ? : err;
    266			mlx5e_rss_warn(rss->mdev,
    267				       "Failed to update RSS hash of indirect TIR for traffic type %d: err = %d\n",
    268				       tt, err);
    269		}
    270
    271		if (!rss->inner_ft_support)
    272			continue;
    273
    274		err = mlx5e_rss_update_tir(rss, tt, true);
    275		if (err) {
    276			retval = retval ? : err;
    277			mlx5e_rss_warn(rss->mdev,
    278				       "Failed to update RSS hash of inner indirect TIR for traffic type %d: err = %d\n",
    279				       tt, err);
    280		}
    281	}
    282	return retval;
    283}
    284
    285int mlx5e_rss_init_no_tirs(struct mlx5e_rss *rss, struct mlx5_core_dev *mdev,
    286			   bool inner_ft_support, u32 drop_rqn)
    287{
    288	rss->mdev = mdev;
    289	rss->inner_ft_support = inner_ft_support;
    290	rss->drop_rqn = drop_rqn;
    291
    292	mlx5e_rss_params_init(rss);
    293	refcount_set(&rss->refcnt, 1);
    294
    295	return mlx5e_rqt_init_direct(&rss->rqt, mdev, true, drop_rqn);
    296}
    297
    298int mlx5e_rss_init(struct mlx5e_rss *rss, struct mlx5_core_dev *mdev,
    299		   bool inner_ft_support, u32 drop_rqn,
    300		   const struct mlx5e_packet_merge_param *init_pkt_merge_param)
    301{
    302	int err;
    303
    304	err = mlx5e_rss_init_no_tirs(rss, mdev, inner_ft_support, drop_rqn);
    305	if (err)
    306		goto err_out;
    307
    308	err = mlx5e_rss_create_tirs(rss, init_pkt_merge_param, false);
    309	if (err)
    310		goto err_destroy_rqt;
    311
    312	if (inner_ft_support) {
    313		err = mlx5e_rss_create_tirs(rss, init_pkt_merge_param, true);
    314		if (err)
    315			goto err_destroy_tirs;
    316	}
    317
    318	return 0;
    319
    320err_destroy_tirs:
    321	mlx5e_rss_destroy_tirs(rss, false);
    322err_destroy_rqt:
    323	mlx5e_rqt_destroy(&rss->rqt);
    324err_out:
    325	return err;
    326}
    327
    328int mlx5e_rss_cleanup(struct mlx5e_rss *rss)
    329{
    330	if (!refcount_dec_if_one(&rss->refcnt))
    331		return -EBUSY;
    332
    333	mlx5e_rss_destroy_tirs(rss, false);
    334
    335	if (rss->inner_ft_support)
    336		mlx5e_rss_destroy_tirs(rss, true);
    337
    338	mlx5e_rqt_destroy(&rss->rqt);
    339
    340	return 0;
    341}
    342
    343void mlx5e_rss_refcnt_inc(struct mlx5e_rss *rss)
    344{
    345	refcount_inc(&rss->refcnt);
    346}
    347
    348void mlx5e_rss_refcnt_dec(struct mlx5e_rss *rss)
    349{
    350	refcount_dec(&rss->refcnt);
    351}
    352
    353unsigned int mlx5e_rss_refcnt_read(struct mlx5e_rss *rss)
    354{
    355	return refcount_read(&rss->refcnt);
    356}
    357
    358u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
    359		       bool inner)
    360{
    361	struct mlx5e_tir *tir;
    362
    363	WARN_ON(inner && !rss->inner_ft_support);
    364	tir = rss_get_tir(rss, tt, inner);
    365	WARN_ON(!tir);
    366
    367	return mlx5e_tir_get_tirn(tir);
    368}
    369
    370/* Fill the "tirn" output parameter.
    371 * Create the requested TIR if it's its first usage.
    372 */
    373int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss,
    374			  enum mlx5_traffic_types tt,
    375			  const struct mlx5e_packet_merge_param *init_pkt_merge_param,
    376			  bool inner, u32 *tirn)
    377{
    378	struct mlx5e_tir *tir;
    379
    380	tir = rss_get_tir(rss, tt, inner);
    381	if (!tir) { /* TIR doesn't exist, create one */
    382		int err;
    383
    384		err = mlx5e_rss_create_tir(rss, tt, init_pkt_merge_param, inner);
    385		if (err)
    386			return err;
    387		tir = rss_get_tir(rss, tt, inner);
    388	}
    389
    390	*tirn = mlx5e_tir_get_tirn(tir);
    391	return 0;
    392}
    393
    394static int mlx5e_rss_apply(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns)
    395{
    396	int err;
    397
    398	err = mlx5e_rqt_redirect_indir(&rss->rqt, rqns, num_rqns, rss->hash.hfunc, &rss->indir);
    399	if (err)
    400		mlx5e_rss_warn(rss->mdev, "Failed to redirect RQT %#x to channels: err = %d\n",
    401			       mlx5e_rqt_get_rqtn(&rss->rqt), err);
    402	return err;
    403}
    404
    405void mlx5e_rss_enable(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns)
    406{
    407	rss->enabled = true;
    408	mlx5e_rss_apply(rss, rqns, num_rqns);
    409}
    410
    411void mlx5e_rss_disable(struct mlx5e_rss *rss)
    412{
    413	int err;
    414
    415	rss->enabled = false;
    416	err = mlx5e_rqt_redirect_direct(&rss->rqt, rss->drop_rqn);
    417	if (err)
    418		mlx5e_rss_warn(rss->mdev, "Failed to redirect RQT %#x to drop RQ %#x: err = %d\n",
    419			       mlx5e_rqt_get_rqtn(&rss->rqt), rss->drop_rqn, err);
    420}
    421
    422int mlx5e_rss_packet_merge_set_param(struct mlx5e_rss *rss,
    423				     struct mlx5e_packet_merge_param *pkt_merge_param)
    424{
    425	struct mlx5e_tir_builder *builder;
    426	enum mlx5_traffic_types tt;
    427	int err, final_err;
    428
    429	builder = mlx5e_tir_builder_alloc(true);
    430	if (!builder)
    431		return -ENOMEM;
    432
    433	mlx5e_tir_builder_build_packet_merge(builder, pkt_merge_param);
    434
    435	final_err = 0;
    436
    437	for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
    438		struct mlx5e_tir *tir;
    439
    440		tir = rss_get_tir(rss, tt, false);
    441		if (!tir)
    442			goto inner_tir;
    443		err = mlx5e_tir_modify(tir, builder);
    444		if (err) {
    445			mlx5e_rss_warn(rss->mdev, "Failed to update packet merge state of indirect TIR %#x for traffic type %d: err = %d\n",
    446				       mlx5e_tir_get_tirn(tir), tt, err);
    447			if (!final_err)
    448				final_err = err;
    449		}
    450
    451inner_tir:
    452		if (!rss->inner_ft_support)
    453			continue;
    454
    455		tir = rss_get_tir(rss, tt, true);
    456		if (!tir)
    457			continue;
    458		err = mlx5e_tir_modify(tir, builder);
    459		if (err) {
    460			mlx5e_rss_warn(rss->mdev, "Failed to update packet merge state of inner indirect TIR %#x for traffic type %d: err = %d\n",
    461				       mlx5e_tir_get_tirn(tir), tt, err);
    462			if (!final_err)
    463				final_err = err;
    464		}
    465	}
    466
    467	mlx5e_tir_builder_free(builder);
    468	return final_err;
    469}
    470
    471int mlx5e_rss_get_rxfh(struct mlx5e_rss *rss, u32 *indir, u8 *key, u8 *hfunc)
    472{
    473	unsigned int i;
    474
    475	if (indir)
    476		for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++)
    477			indir[i] = rss->indir.table[i];
    478
    479	if (key)
    480		memcpy(key, rss->hash.toeplitz_hash_key,
    481		       sizeof(rss->hash.toeplitz_hash_key));
    482
    483	if (hfunc)
    484		*hfunc = rss->hash.hfunc;
    485
    486	return 0;
    487}
    488
    489int mlx5e_rss_set_rxfh(struct mlx5e_rss *rss, const u32 *indir,
    490		       const u8 *key, const u8 *hfunc,
    491		       u32 *rqns, unsigned int num_rqns)
    492{
    493	bool changed_indir = false;
    494	bool changed_hash = false;
    495	struct mlx5e_rss *old_rss;
    496	int err = 0;
    497
    498	old_rss = mlx5e_rss_alloc();
    499	if (!old_rss)
    500		return -ENOMEM;
    501
    502	*old_rss = *rss;
    503
    504	if (hfunc && *hfunc != rss->hash.hfunc) {
    505		switch (*hfunc) {
    506		case ETH_RSS_HASH_XOR:
    507		case ETH_RSS_HASH_TOP:
    508			break;
    509		default:
    510			err = -EINVAL;
    511			goto out;
    512		}
    513		changed_hash = true;
    514		changed_indir = true;
    515		rss->hash.hfunc = *hfunc;
    516	}
    517
    518	if (key) {
    519		if (rss->hash.hfunc == ETH_RSS_HASH_TOP)
    520			changed_hash = true;
    521		memcpy(rss->hash.toeplitz_hash_key, key,
    522		       sizeof(rss->hash.toeplitz_hash_key));
    523	}
    524
    525	if (indir) {
    526		unsigned int i;
    527
    528		changed_indir = true;
    529
    530		for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++)
    531			rss->indir.table[i] = indir[i];
    532	}
    533
    534	if (changed_indir && rss->enabled) {
    535		err = mlx5e_rss_apply(rss, rqns, num_rqns);
    536		if (err) {
    537			*rss = *old_rss;
    538			goto out;
    539		}
    540	}
    541
    542	if (changed_hash)
    543		mlx5e_rss_update_tirs(rss);
    544
    545out:
    546	mlx5e_rss_free(old_rss);
    547	return err;
    548}
    549
    550struct mlx5e_rss_params_hash mlx5e_rss_get_hash(struct mlx5e_rss *rss)
    551{
    552	return rss->hash;
    553}
    554
    555u8 mlx5e_rss_get_hash_fields(struct mlx5e_rss *rss, enum mlx5_traffic_types tt)
    556{
    557	return rss->rx_hash_fields[tt];
    558}
    559
    560int mlx5e_rss_set_hash_fields(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
    561			      u8 rx_hash_fields)
    562{
    563	u8 old_rx_hash_fields;
    564	int err;
    565
    566	old_rx_hash_fields = rss->rx_hash_fields[tt];
    567
    568	if (old_rx_hash_fields == rx_hash_fields)
    569		return 0;
    570
    571	rss->rx_hash_fields[tt] = rx_hash_fields;
    572
    573	err = mlx5e_rss_update_tir(rss, tt, false);
    574	if (err) {
    575		rss->rx_hash_fields[tt] = old_rx_hash_fields;
    576		mlx5e_rss_warn(rss->mdev,
    577			       "Failed to update RSS hash fields of indirect TIR for traffic type %d: err = %d\n",
    578			       tt, err);
    579		return err;
    580	}
    581
    582	if (!(rss->inner_ft_support))
    583		return 0;
    584
    585	err = mlx5e_rss_update_tir(rss, tt, true);
    586	if (err) {
    587		/* Partial update happened. Try to revert - it may fail too, but
    588		 * there is nothing more we can do.
    589		 */
    590		rss->rx_hash_fields[tt] = old_rx_hash_fields;
    591		mlx5e_rss_warn(rss->mdev,
    592			       "Failed to update RSS hash fields of inner indirect TIR for traffic type %d: err = %d\n",
    593			       tt, err);
    594		if (mlx5e_rss_update_tir(rss, tt, false))
    595			mlx5e_rss_warn(rss->mdev,
    596				       "Partial update of RSS hash fields happened: failed to revert indirect TIR for traffic type %d to the old values\n",
    597				       tt);
    598	}
    599
    600	return err;
    601}
    602
    603void mlx5e_rss_set_indir_uniform(struct mlx5e_rss *rss, unsigned int nch)
    604{
    605	mlx5e_rss_params_indir_init_uniform(&rss->indir, nch);
    606}