brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · 22ebb20 Raw
469 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* 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 is62	 * (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 int80mlxsw_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 global86	 * 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	devl_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 void106mlxsw_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	devl_resource_occ_get_unregister(devlink,111					 MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS);112	WARN_ON(atomic_read(&family->policers_count) != 0);113}114 115static int116mlxsw_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 int153mlxsw_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 int169mlxsw_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 int308mlxsw_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 void345mlxsw_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 = devl_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 = devl_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 int445mlxsw_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 int458mlxsw_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};469