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

spectrum_policer.c (12878B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/* Copyright (c) 2020 Mellanox Technologies. All rights reserved */
      3
      4#include <linux/idr.h>
      5#include <linux/log2.h>
      6#include <linux/mutex.h>
      7#include <linux/netlink.h>
      8#include <net/devlink.h>
      9
     10#include "spectrum.h"
     11
     12struct mlxsw_sp_policer_family {
     13	enum mlxsw_sp_policer_type type;
     14	enum mlxsw_reg_qpcr_g qpcr_type;
     15	struct mlxsw_sp *mlxsw_sp;
     16	u16 start_index; /* Inclusive */
     17	u16 end_index; /* Exclusive */
     18	struct idr policer_idr;
     19	struct mutex lock; /* Protects policer_idr */
     20	atomic_t policers_count;
     21	const struct mlxsw_sp_policer_family_ops *ops;
     22};
     23
     24struct mlxsw_sp_policer {
     25	struct mlxsw_sp_policer_params params;
     26	u16 index;
     27};
     28
     29struct mlxsw_sp_policer_family_ops {
     30	int (*init)(struct mlxsw_sp_policer_family *family);
     31	void (*fini)(struct mlxsw_sp_policer_family *family);
     32	int (*policer_index_alloc)(struct mlxsw_sp_policer_family *family,
     33				   struct mlxsw_sp_policer *policer);
     34	struct mlxsw_sp_policer * (*policer_index_free)(struct mlxsw_sp_policer_family *family,
     35							u16 policer_index);
     36	int (*policer_init)(struct mlxsw_sp_policer_family *family,
     37			    const struct mlxsw_sp_policer *policer);
     38	int (*policer_params_check)(const struct mlxsw_sp_policer_family *family,
     39				    const struct mlxsw_sp_policer_params *params,
     40				    struct netlink_ext_ack *extack);
     41};
     42
     43struct mlxsw_sp_policer_core {
     44	struct mlxsw_sp_policer_family *family_arr[MLXSW_SP_POLICER_TYPE_MAX + 1];
     45	const struct mlxsw_sp_policer_core_ops *ops;
     46	u8 lowest_bs_bits;
     47	u8 highest_bs_bits;
     48};
     49
     50struct mlxsw_sp_policer_core_ops {
     51	int (*init)(struct mlxsw_sp_policer_core *policer_core);
     52};
     53
     54static u64 mlxsw_sp_policer_rate_bytes_ps_kbps(u64 rate_bytes_ps)
     55{
     56	return div_u64(rate_bytes_ps, 1000) * BITS_PER_BYTE;
     57}
     58
     59static u8 mlxsw_sp_policer_burst_bytes_hw_units(u64 burst_bytes)
     60{
     61	/* Provided burst size is in bytes. The ASIC burst size value is
     62	 * (2 ^ bs) * 512 bits. Convert the provided size to 512-bit units.
     63	 */
     64	u64 bs512 = div_u64(burst_bytes, 64);
     65
     66	if (!bs512)
     67		return 0;
     68
     69	return fls64(bs512) - 1;
     70}
     71
     72static u64 mlxsw_sp_policer_single_rate_occ_get(void *priv)
     73{
     74	struct mlxsw_sp_policer_family *family = priv;
     75
     76	return atomic_read(&family->policers_count);
     77}
     78
     79static int
     80mlxsw_sp_policer_single_rate_family_init(struct mlxsw_sp_policer_family *family)
     81{
     82	struct mlxsw_core *core = family->mlxsw_sp->core;
     83	struct devlink *devlink;
     84
     85	/* CPU policers are allocated from the first N policers in the global
     86	 * range, so skip them.
     87	 */
     88	if (!MLXSW_CORE_RES_VALID(core, MAX_GLOBAL_POLICERS) ||
     89	    !MLXSW_CORE_RES_VALID(core, MAX_CPU_POLICERS))
     90		return -EIO;
     91
     92	family->start_index = MLXSW_CORE_RES_GET(core, MAX_CPU_POLICERS);
     93	family->end_index = MLXSW_CORE_RES_GET(core, MAX_GLOBAL_POLICERS);
     94
     95	atomic_set(&family->policers_count, 0);
     96	devlink = priv_to_devlink(core);
     97	devlink_resource_occ_get_register(devlink,
     98					  MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
     99					  mlxsw_sp_policer_single_rate_occ_get,
    100					  family);
    101
    102	return 0;
    103}
    104
    105static void
    106mlxsw_sp_policer_single_rate_family_fini(struct mlxsw_sp_policer_family *family)
    107{
    108	struct devlink *devlink = priv_to_devlink(family->mlxsw_sp->core);
    109
    110	devlink_resource_occ_get_unregister(devlink,
    111					    MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS);
    112	WARN_ON(atomic_read(&family->policers_count) != 0);
    113}
    114
    115static int
    116mlxsw_sp_policer_single_rate_index_alloc(struct mlxsw_sp_policer_family *family,
    117					 struct mlxsw_sp_policer *policer)
    118{
    119	int id;
    120
    121	mutex_lock(&family->lock);
    122	id = idr_alloc(&family->policer_idr, policer, family->start_index,
    123		       family->end_index, GFP_KERNEL);
    124	mutex_unlock(&family->lock);
    125
    126	if (id < 0)
    127		return id;
    128
    129	atomic_inc(&family->policers_count);
    130	policer->index = id;
    131
    132	return 0;
    133}
    134
    135static struct mlxsw_sp_policer *
    136mlxsw_sp_policer_single_rate_index_free(struct mlxsw_sp_policer_family *family,
    137					u16 policer_index)
    138{
    139	struct mlxsw_sp_policer *policer;
    140
    141	atomic_dec(&family->policers_count);
    142
    143	mutex_lock(&family->lock);
    144	policer = idr_remove(&family->policer_idr, policer_index);
    145	mutex_unlock(&family->lock);
    146
    147	WARN_ON(!policer);
    148
    149	return policer;
    150}
    151
    152static int
    153mlxsw_sp_policer_single_rate_init(struct mlxsw_sp_policer_family *family,
    154				  const struct mlxsw_sp_policer *policer)
    155{
    156	u64 rate_kbps = mlxsw_sp_policer_rate_bytes_ps_kbps(policer->params.rate);
    157	u8 bs = mlxsw_sp_policer_burst_bytes_hw_units(policer->params.burst);
    158	struct mlxsw_sp *mlxsw_sp = family->mlxsw_sp;
    159	char qpcr_pl[MLXSW_REG_QPCR_LEN];
    160
    161	mlxsw_reg_qpcr_pack(qpcr_pl, policer->index, MLXSW_REG_QPCR_IR_UNITS_K,
    162			    true, rate_kbps, bs);
    163	mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, true);
    164
    165	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
    166}
    167
    168static int
    169mlxsw_sp_policer_single_rate_params_check(const struct mlxsw_sp_policer_family *family,
    170					  const struct mlxsw_sp_policer_params *params,
    171					  struct netlink_ext_ack *extack)
    172{
    173	struct mlxsw_sp_policer_core *policer_core = family->mlxsw_sp->policer_core;
    174	u64 rate_bps = params->rate * BITS_PER_BYTE;
    175	u8 bs;
    176
    177	if (!params->bytes) {
    178		NL_SET_ERR_MSG_MOD(extack, "Only bandwidth policing is currently supported by single rate policers");
    179		return -EINVAL;
    180	}
    181
    182	if (!is_power_of_2(params->burst)) {
    183		NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two");
    184		return -EINVAL;
    185	}
    186
    187	bs = mlxsw_sp_policer_burst_bytes_hw_units(params->burst);
    188
    189	if (bs < policer_core->lowest_bs_bits) {
    190		NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
    191		return -EINVAL;
    192	}
    193
    194	if (bs > policer_core->highest_bs_bits) {
    195		NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
    196		return -EINVAL;
    197	}
    198
    199	if (rate_bps < MLXSW_REG_QPCR_LOWEST_CIR_BITS) {
    200		NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
    201		return -EINVAL;
    202	}
    203
    204	if (rate_bps > MLXSW_REG_QPCR_HIGHEST_CIR_BITS) {
    205		NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
    206		return -EINVAL;
    207	}
    208
    209	return 0;
    210}
    211
    212static const struct mlxsw_sp_policer_family_ops mlxsw_sp_policer_single_rate_ops = {
    213	.init			= mlxsw_sp_policer_single_rate_family_init,
    214	.fini			= mlxsw_sp_policer_single_rate_family_fini,
    215	.policer_index_alloc	= mlxsw_sp_policer_single_rate_index_alloc,
    216	.policer_index_free	= mlxsw_sp_policer_single_rate_index_free,
    217	.policer_init		= mlxsw_sp_policer_single_rate_init,
    218	.policer_params_check	= mlxsw_sp_policer_single_rate_params_check,
    219};
    220
    221static const struct mlxsw_sp_policer_family mlxsw_sp_policer_single_rate_family = {
    222	.type		= MLXSW_SP_POLICER_TYPE_SINGLE_RATE,
    223	.qpcr_type	= MLXSW_REG_QPCR_G_GLOBAL,
    224	.ops		= &mlxsw_sp_policer_single_rate_ops,
    225};
    226
    227static const struct mlxsw_sp_policer_family *mlxsw_sp_policer_family_arr[] = {
    228	[MLXSW_SP_POLICER_TYPE_SINGLE_RATE]	= &mlxsw_sp_policer_single_rate_family,
    229};
    230
    231int mlxsw_sp_policer_add(struct mlxsw_sp *mlxsw_sp,
    232			 enum mlxsw_sp_policer_type type,
    233			 const struct mlxsw_sp_policer_params *params,
    234			 struct netlink_ext_ack *extack, u16 *p_policer_index)
    235{
    236	struct mlxsw_sp_policer_family *family;
    237	struct mlxsw_sp_policer *policer;
    238	int err;
    239
    240	family = mlxsw_sp->policer_core->family_arr[type];
    241
    242	err = family->ops->policer_params_check(family, params, extack);
    243	if (err)
    244		return err;
    245
    246	policer = kmalloc(sizeof(*policer), GFP_KERNEL);
    247	if (!policer)
    248		return -ENOMEM;
    249	policer->params = *params;
    250
    251	err = family->ops->policer_index_alloc(family, policer);
    252	if (err) {
    253		NL_SET_ERR_MSG_MOD(extack, "Failed to allocate policer index");
    254		goto err_policer_index_alloc;
    255	}
    256
    257	err = family->ops->policer_init(family, policer);
    258	if (err) {
    259		NL_SET_ERR_MSG_MOD(extack, "Failed to initialize policer");
    260		goto err_policer_init;
    261	}
    262
    263	*p_policer_index = policer->index;
    264
    265	return 0;
    266
    267err_policer_init:
    268	family->ops->policer_index_free(family, policer->index);
    269err_policer_index_alloc:
    270	kfree(policer);
    271	return err;
    272}
    273
    274void mlxsw_sp_policer_del(struct mlxsw_sp *mlxsw_sp,
    275			  enum mlxsw_sp_policer_type type, u16 policer_index)
    276{
    277	struct mlxsw_sp_policer_family *family;
    278	struct mlxsw_sp_policer *policer;
    279
    280	family = mlxsw_sp->policer_core->family_arr[type];
    281	policer = family->ops->policer_index_free(family, policer_index);
    282	kfree(policer);
    283}
    284
    285int mlxsw_sp_policer_drops_counter_get(struct mlxsw_sp *mlxsw_sp,
    286				       enum mlxsw_sp_policer_type type,
    287				       u16 policer_index, u64 *p_drops)
    288{
    289	struct mlxsw_sp_policer_family *family;
    290	char qpcr_pl[MLXSW_REG_QPCR_LEN];
    291	int err;
    292
    293	family = mlxsw_sp->policer_core->family_arr[type];
    294
    295	MLXSW_REG_ZERO(qpcr, qpcr_pl);
    296	mlxsw_reg_qpcr_pid_set(qpcr_pl, policer_index);
    297	mlxsw_reg_qpcr_g_set(qpcr_pl, family->qpcr_type);
    298	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
    299	if (err)
    300		return err;
    301
    302	*p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl);
    303
    304	return 0;
    305}
    306
    307static int
    308mlxsw_sp_policer_family_register(struct mlxsw_sp *mlxsw_sp,
    309				 const struct mlxsw_sp_policer_family *tmpl)
    310{
    311	struct mlxsw_sp_policer_family *family;
    312	int err;
    313
    314	family = kmemdup(tmpl, sizeof(*family), GFP_KERNEL);
    315	if (!family)
    316		return -ENOMEM;
    317
    318	family->mlxsw_sp = mlxsw_sp;
    319	idr_init(&family->policer_idr);
    320	mutex_init(&family->lock);
    321
    322	err = family->ops->init(family);
    323	if (err)
    324		goto err_family_init;
    325
    326	if (WARN_ON(family->start_index >= family->end_index)) {
    327		err = -EINVAL;
    328		goto err_index_check;
    329	}
    330
    331	mlxsw_sp->policer_core->family_arr[tmpl->type] = family;
    332
    333	return 0;
    334
    335err_index_check:
    336	family->ops->fini(family);
    337err_family_init:
    338	mutex_destroy(&family->lock);
    339	idr_destroy(&family->policer_idr);
    340	kfree(family);
    341	return err;
    342}
    343
    344static void
    345mlxsw_sp_policer_family_unregister(struct mlxsw_sp *mlxsw_sp,
    346				   struct mlxsw_sp_policer_family *family)
    347{
    348	family->ops->fini(family);
    349	mutex_destroy(&family->lock);
    350	WARN_ON(!idr_is_empty(&family->policer_idr));
    351	idr_destroy(&family->policer_idr);
    352	kfree(family);
    353}
    354
    355int mlxsw_sp_policers_init(struct mlxsw_sp *mlxsw_sp)
    356{
    357	struct mlxsw_sp_policer_core *policer_core;
    358	int i, err;
    359
    360	policer_core = kzalloc(sizeof(*policer_core), GFP_KERNEL);
    361	if (!policer_core)
    362		return -ENOMEM;
    363	mlxsw_sp->policer_core = policer_core;
    364	policer_core->ops = mlxsw_sp->policer_core_ops;
    365
    366	err = policer_core->ops->init(policer_core);
    367	if (err)
    368		goto err_init;
    369
    370	for (i = 0; i < MLXSW_SP_POLICER_TYPE_MAX + 1; i++) {
    371		err = mlxsw_sp_policer_family_register(mlxsw_sp, mlxsw_sp_policer_family_arr[i]);
    372		if (err)
    373			goto err_family_register;
    374	}
    375
    376	return 0;
    377
    378err_family_register:
    379	for (i--; i >= 0; i--) {
    380		struct mlxsw_sp_policer_family *family;
    381
    382		family = mlxsw_sp->policer_core->family_arr[i];
    383		mlxsw_sp_policer_family_unregister(mlxsw_sp, family);
    384	}
    385err_init:
    386	kfree(mlxsw_sp->policer_core);
    387	return err;
    388}
    389
    390void mlxsw_sp_policers_fini(struct mlxsw_sp *mlxsw_sp)
    391{
    392	int i;
    393
    394	for (i = MLXSW_SP_POLICER_TYPE_MAX; i >= 0; i--) {
    395		struct mlxsw_sp_policer_family *family;
    396
    397		family = mlxsw_sp->policer_core->family_arr[i];
    398		mlxsw_sp_policer_family_unregister(mlxsw_sp, family);
    399	}
    400
    401	kfree(mlxsw_sp->policer_core);
    402}
    403
    404int mlxsw_sp_policer_resources_register(struct mlxsw_core *mlxsw_core)
    405{
    406	u64 global_policers, cpu_policers, single_rate_policers;
    407	struct devlink *devlink = priv_to_devlink(mlxsw_core);
    408	struct devlink_resource_size_params size_params;
    409	int err;
    410
    411	if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_GLOBAL_POLICERS) ||
    412	    !MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS))
    413		return -EIO;
    414
    415	global_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_GLOBAL_POLICERS);
    416	cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS);
    417	single_rate_policers = global_policers - cpu_policers;
    418
    419	devlink_resource_size_params_init(&size_params, global_policers,
    420					  global_policers, 1,
    421					  DEVLINK_RESOURCE_UNIT_ENTRY);
    422	err = devlink_resource_register(devlink, "global_policers",
    423					global_policers,
    424					MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
    425					DEVLINK_RESOURCE_ID_PARENT_TOP,
    426					&size_params);
    427	if (err)
    428		return err;
    429
    430	devlink_resource_size_params_init(&size_params, single_rate_policers,
    431					  single_rate_policers, 1,
    432					  DEVLINK_RESOURCE_UNIT_ENTRY);
    433	err = devlink_resource_register(devlink, "single_rate_policers",
    434					single_rate_policers,
    435					MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
    436					MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
    437					&size_params);
    438	if (err)
    439		return err;
    440
    441	return 0;
    442}
    443
    444static int
    445mlxsw_sp1_policer_core_init(struct mlxsw_sp_policer_core *policer_core)
    446{
    447	policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP1;
    448	policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP1;
    449
    450	return 0;
    451}
    452
    453const struct mlxsw_sp_policer_core_ops mlxsw_sp1_policer_core_ops = {
    454	.init = mlxsw_sp1_policer_core_init,
    455};
    456
    457static int
    458mlxsw_sp2_policer_core_init(struct mlxsw_sp_policer_core *policer_core)
    459{
    460	policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP2;
    461	policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP2;
    462
    463	return 0;
    464}
    465
    466const struct mlxsw_sp_policer_core_ops mlxsw_sp2_policer_core_ops = {
    467	.init = mlxsw_sp2_policer_core_init,
    468};