0001
0002
0003
0004 #include <linux/idr.h>
0005 #include <linux/log2.h>
0006 #include <linux/mutex.h>
0007 #include <linux/netlink.h>
0008 #include <net/devlink.h>
0009
0010 #include "spectrum.h"
0011
0012 struct mlxsw_sp_policer_family {
0013 enum mlxsw_sp_policer_type type;
0014 enum mlxsw_reg_qpcr_g qpcr_type;
0015 struct mlxsw_sp *mlxsw_sp;
0016 u16 start_index;
0017 u16 end_index;
0018 struct idr policer_idr;
0019 struct mutex lock;
0020 atomic_t policers_count;
0021 const struct mlxsw_sp_policer_family_ops *ops;
0022 };
0023
0024 struct mlxsw_sp_policer {
0025 struct mlxsw_sp_policer_params params;
0026 u16 index;
0027 };
0028
0029 struct mlxsw_sp_policer_family_ops {
0030 int (*init)(struct mlxsw_sp_policer_family *family);
0031 void (*fini)(struct mlxsw_sp_policer_family *family);
0032 int (*policer_index_alloc)(struct mlxsw_sp_policer_family *family,
0033 struct mlxsw_sp_policer *policer);
0034 struct mlxsw_sp_policer * (*policer_index_free)(struct mlxsw_sp_policer_family *family,
0035 u16 policer_index);
0036 int (*policer_init)(struct mlxsw_sp_policer_family *family,
0037 const struct mlxsw_sp_policer *policer);
0038 int (*policer_params_check)(const struct mlxsw_sp_policer_family *family,
0039 const struct mlxsw_sp_policer_params *params,
0040 struct netlink_ext_ack *extack);
0041 };
0042
0043 struct mlxsw_sp_policer_core {
0044 struct mlxsw_sp_policer_family *family_arr[MLXSW_SP_POLICER_TYPE_MAX + 1];
0045 const struct mlxsw_sp_policer_core_ops *ops;
0046 u8 lowest_bs_bits;
0047 u8 highest_bs_bits;
0048 };
0049
0050 struct mlxsw_sp_policer_core_ops {
0051 int (*init)(struct mlxsw_sp_policer_core *policer_core);
0052 };
0053
0054 static u64 mlxsw_sp_policer_rate_bytes_ps_kbps(u64 rate_bytes_ps)
0055 {
0056 return div_u64(rate_bytes_ps, 1000) * BITS_PER_BYTE;
0057 }
0058
0059 static u8 mlxsw_sp_policer_burst_bytes_hw_units(u64 burst_bytes)
0060 {
0061
0062
0063
0064 u64 bs512 = div_u64(burst_bytes, 64);
0065
0066 if (!bs512)
0067 return 0;
0068
0069 return fls64(bs512) - 1;
0070 }
0071
0072 static u64 mlxsw_sp_policer_single_rate_occ_get(void *priv)
0073 {
0074 struct mlxsw_sp_policer_family *family = priv;
0075
0076 return atomic_read(&family->policers_count);
0077 }
0078
0079 static int
0080 mlxsw_sp_policer_single_rate_family_init(struct mlxsw_sp_policer_family *family)
0081 {
0082 struct mlxsw_core *core = family->mlxsw_sp->core;
0083 struct devlink *devlink;
0084
0085
0086
0087
0088 if (!MLXSW_CORE_RES_VALID(core, MAX_GLOBAL_POLICERS) ||
0089 !MLXSW_CORE_RES_VALID(core, MAX_CPU_POLICERS))
0090 return -EIO;
0091
0092 family->start_index = MLXSW_CORE_RES_GET(core, MAX_CPU_POLICERS);
0093 family->end_index = MLXSW_CORE_RES_GET(core, MAX_GLOBAL_POLICERS);
0094
0095 atomic_set(&family->policers_count, 0);
0096 devlink = priv_to_devlink(core);
0097 devl_resource_occ_get_register(devlink,
0098 MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
0099 mlxsw_sp_policer_single_rate_occ_get,
0100 family);
0101
0102 return 0;
0103 }
0104
0105 static void
0106 mlxsw_sp_policer_single_rate_family_fini(struct mlxsw_sp_policer_family *family)
0107 {
0108 struct devlink *devlink = priv_to_devlink(family->mlxsw_sp->core);
0109
0110 devl_resource_occ_get_unregister(devlink,
0111 MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS);
0112 WARN_ON(atomic_read(&family->policers_count) != 0);
0113 }
0114
0115 static int
0116 mlxsw_sp_policer_single_rate_index_alloc(struct mlxsw_sp_policer_family *family,
0117 struct mlxsw_sp_policer *policer)
0118 {
0119 int id;
0120
0121 mutex_lock(&family->lock);
0122 id = idr_alloc(&family->policer_idr, policer, family->start_index,
0123 family->end_index, GFP_KERNEL);
0124 mutex_unlock(&family->lock);
0125
0126 if (id < 0)
0127 return id;
0128
0129 atomic_inc(&family->policers_count);
0130 policer->index = id;
0131
0132 return 0;
0133 }
0134
0135 static struct mlxsw_sp_policer *
0136 mlxsw_sp_policer_single_rate_index_free(struct mlxsw_sp_policer_family *family,
0137 u16 policer_index)
0138 {
0139 struct mlxsw_sp_policer *policer;
0140
0141 atomic_dec(&family->policers_count);
0142
0143 mutex_lock(&family->lock);
0144 policer = idr_remove(&family->policer_idr, policer_index);
0145 mutex_unlock(&family->lock);
0146
0147 WARN_ON(!policer);
0148
0149 return policer;
0150 }
0151
0152 static int
0153 mlxsw_sp_policer_single_rate_init(struct mlxsw_sp_policer_family *family,
0154 const struct mlxsw_sp_policer *policer)
0155 {
0156 u64 rate_kbps = mlxsw_sp_policer_rate_bytes_ps_kbps(policer->params.rate);
0157 u8 bs = mlxsw_sp_policer_burst_bytes_hw_units(policer->params.burst);
0158 struct mlxsw_sp *mlxsw_sp = family->mlxsw_sp;
0159 char qpcr_pl[MLXSW_REG_QPCR_LEN];
0160
0161 mlxsw_reg_qpcr_pack(qpcr_pl, policer->index, MLXSW_REG_QPCR_IR_UNITS_K,
0162 true, rate_kbps, bs);
0163 mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, true);
0164
0165 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
0166 }
0167
0168 static int
0169 mlxsw_sp_policer_single_rate_params_check(const struct mlxsw_sp_policer_family *family,
0170 const struct mlxsw_sp_policer_params *params,
0171 struct netlink_ext_ack *extack)
0172 {
0173 struct mlxsw_sp_policer_core *policer_core = family->mlxsw_sp->policer_core;
0174 u64 rate_bps = params->rate * BITS_PER_BYTE;
0175 u8 bs;
0176
0177 if (!params->bytes) {
0178 NL_SET_ERR_MSG_MOD(extack, "Only bandwidth policing is currently supported by single rate policers");
0179 return -EINVAL;
0180 }
0181
0182 if (!is_power_of_2(params->burst)) {
0183 NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two");
0184 return -EINVAL;
0185 }
0186
0187 bs = mlxsw_sp_policer_burst_bytes_hw_units(params->burst);
0188
0189 if (bs < policer_core->lowest_bs_bits) {
0190 NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
0191 return -EINVAL;
0192 }
0193
0194 if (bs > policer_core->highest_bs_bits) {
0195 NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
0196 return -EINVAL;
0197 }
0198
0199 if (rate_bps < MLXSW_REG_QPCR_LOWEST_CIR_BITS) {
0200 NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
0201 return -EINVAL;
0202 }
0203
0204 if (rate_bps > MLXSW_REG_QPCR_HIGHEST_CIR_BITS) {
0205 NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
0206 return -EINVAL;
0207 }
0208
0209 return 0;
0210 }
0211
0212 static const struct mlxsw_sp_policer_family_ops mlxsw_sp_policer_single_rate_ops = {
0213 .init = mlxsw_sp_policer_single_rate_family_init,
0214 .fini = mlxsw_sp_policer_single_rate_family_fini,
0215 .policer_index_alloc = mlxsw_sp_policer_single_rate_index_alloc,
0216 .policer_index_free = mlxsw_sp_policer_single_rate_index_free,
0217 .policer_init = mlxsw_sp_policer_single_rate_init,
0218 .policer_params_check = mlxsw_sp_policer_single_rate_params_check,
0219 };
0220
0221 static const struct mlxsw_sp_policer_family mlxsw_sp_policer_single_rate_family = {
0222 .type = MLXSW_SP_POLICER_TYPE_SINGLE_RATE,
0223 .qpcr_type = MLXSW_REG_QPCR_G_GLOBAL,
0224 .ops = &mlxsw_sp_policer_single_rate_ops,
0225 };
0226
0227 static const struct mlxsw_sp_policer_family *mlxsw_sp_policer_family_arr[] = {
0228 [MLXSW_SP_POLICER_TYPE_SINGLE_RATE] = &mlxsw_sp_policer_single_rate_family,
0229 };
0230
0231 int mlxsw_sp_policer_add(struct mlxsw_sp *mlxsw_sp,
0232 enum mlxsw_sp_policer_type type,
0233 const struct mlxsw_sp_policer_params *params,
0234 struct netlink_ext_ack *extack, u16 *p_policer_index)
0235 {
0236 struct mlxsw_sp_policer_family *family;
0237 struct mlxsw_sp_policer *policer;
0238 int err;
0239
0240 family = mlxsw_sp->policer_core->family_arr[type];
0241
0242 err = family->ops->policer_params_check(family, params, extack);
0243 if (err)
0244 return err;
0245
0246 policer = kmalloc(sizeof(*policer), GFP_KERNEL);
0247 if (!policer)
0248 return -ENOMEM;
0249 policer->params = *params;
0250
0251 err = family->ops->policer_index_alloc(family, policer);
0252 if (err) {
0253 NL_SET_ERR_MSG_MOD(extack, "Failed to allocate policer index");
0254 goto err_policer_index_alloc;
0255 }
0256
0257 err = family->ops->policer_init(family, policer);
0258 if (err) {
0259 NL_SET_ERR_MSG_MOD(extack, "Failed to initialize policer");
0260 goto err_policer_init;
0261 }
0262
0263 *p_policer_index = policer->index;
0264
0265 return 0;
0266
0267 err_policer_init:
0268 family->ops->policer_index_free(family, policer->index);
0269 err_policer_index_alloc:
0270 kfree(policer);
0271 return err;
0272 }
0273
0274 void mlxsw_sp_policer_del(struct mlxsw_sp *mlxsw_sp,
0275 enum mlxsw_sp_policer_type type, u16 policer_index)
0276 {
0277 struct mlxsw_sp_policer_family *family;
0278 struct mlxsw_sp_policer *policer;
0279
0280 family = mlxsw_sp->policer_core->family_arr[type];
0281 policer = family->ops->policer_index_free(family, policer_index);
0282 kfree(policer);
0283 }
0284
0285 int mlxsw_sp_policer_drops_counter_get(struct mlxsw_sp *mlxsw_sp,
0286 enum mlxsw_sp_policer_type type,
0287 u16 policer_index, u64 *p_drops)
0288 {
0289 struct mlxsw_sp_policer_family *family;
0290 char qpcr_pl[MLXSW_REG_QPCR_LEN];
0291 int err;
0292
0293 family = mlxsw_sp->policer_core->family_arr[type];
0294
0295 MLXSW_REG_ZERO(qpcr, qpcr_pl);
0296 mlxsw_reg_qpcr_pid_set(qpcr_pl, policer_index);
0297 mlxsw_reg_qpcr_g_set(qpcr_pl, family->qpcr_type);
0298 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
0299 if (err)
0300 return err;
0301
0302 *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl);
0303
0304 return 0;
0305 }
0306
0307 static int
0308 mlxsw_sp_policer_family_register(struct mlxsw_sp *mlxsw_sp,
0309 const struct mlxsw_sp_policer_family *tmpl)
0310 {
0311 struct mlxsw_sp_policer_family *family;
0312 int err;
0313
0314 family = kmemdup(tmpl, sizeof(*family), GFP_KERNEL);
0315 if (!family)
0316 return -ENOMEM;
0317
0318 family->mlxsw_sp = mlxsw_sp;
0319 idr_init(&family->policer_idr);
0320 mutex_init(&family->lock);
0321
0322 err = family->ops->init(family);
0323 if (err)
0324 goto err_family_init;
0325
0326 if (WARN_ON(family->start_index >= family->end_index)) {
0327 err = -EINVAL;
0328 goto err_index_check;
0329 }
0330
0331 mlxsw_sp->policer_core->family_arr[tmpl->type] = family;
0332
0333 return 0;
0334
0335 err_index_check:
0336 family->ops->fini(family);
0337 err_family_init:
0338 mutex_destroy(&family->lock);
0339 idr_destroy(&family->policer_idr);
0340 kfree(family);
0341 return err;
0342 }
0343
0344 static void
0345 mlxsw_sp_policer_family_unregister(struct mlxsw_sp *mlxsw_sp,
0346 struct mlxsw_sp_policer_family *family)
0347 {
0348 family->ops->fini(family);
0349 mutex_destroy(&family->lock);
0350 WARN_ON(!idr_is_empty(&family->policer_idr));
0351 idr_destroy(&family->policer_idr);
0352 kfree(family);
0353 }
0354
0355 int mlxsw_sp_policers_init(struct mlxsw_sp *mlxsw_sp)
0356 {
0357 struct mlxsw_sp_policer_core *policer_core;
0358 int i, err;
0359
0360 policer_core = kzalloc(sizeof(*policer_core), GFP_KERNEL);
0361 if (!policer_core)
0362 return -ENOMEM;
0363 mlxsw_sp->policer_core = policer_core;
0364 policer_core->ops = mlxsw_sp->policer_core_ops;
0365
0366 err = policer_core->ops->init(policer_core);
0367 if (err)
0368 goto err_init;
0369
0370 for (i = 0; i < MLXSW_SP_POLICER_TYPE_MAX + 1; i++) {
0371 err = mlxsw_sp_policer_family_register(mlxsw_sp, mlxsw_sp_policer_family_arr[i]);
0372 if (err)
0373 goto err_family_register;
0374 }
0375
0376 return 0;
0377
0378 err_family_register:
0379 for (i--; i >= 0; i--) {
0380 struct mlxsw_sp_policer_family *family;
0381
0382 family = mlxsw_sp->policer_core->family_arr[i];
0383 mlxsw_sp_policer_family_unregister(mlxsw_sp, family);
0384 }
0385 err_init:
0386 kfree(mlxsw_sp->policer_core);
0387 return err;
0388 }
0389
0390 void mlxsw_sp_policers_fini(struct mlxsw_sp *mlxsw_sp)
0391 {
0392 int i;
0393
0394 for (i = MLXSW_SP_POLICER_TYPE_MAX; i >= 0; i--) {
0395 struct mlxsw_sp_policer_family *family;
0396
0397 family = mlxsw_sp->policer_core->family_arr[i];
0398 mlxsw_sp_policer_family_unregister(mlxsw_sp, family);
0399 }
0400
0401 kfree(mlxsw_sp->policer_core);
0402 }
0403
0404 int mlxsw_sp_policer_resources_register(struct mlxsw_core *mlxsw_core)
0405 {
0406 u64 global_policers, cpu_policers, single_rate_policers;
0407 struct devlink *devlink = priv_to_devlink(mlxsw_core);
0408 struct devlink_resource_size_params size_params;
0409 int err;
0410
0411 if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_GLOBAL_POLICERS) ||
0412 !MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS))
0413 return -EIO;
0414
0415 global_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_GLOBAL_POLICERS);
0416 cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS);
0417 single_rate_policers = global_policers - cpu_policers;
0418
0419 devlink_resource_size_params_init(&size_params, global_policers,
0420 global_policers, 1,
0421 DEVLINK_RESOURCE_UNIT_ENTRY);
0422 err = devl_resource_register(devlink, "global_policers",
0423 global_policers,
0424 MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
0425 DEVLINK_RESOURCE_ID_PARENT_TOP,
0426 &size_params);
0427 if (err)
0428 return err;
0429
0430 devlink_resource_size_params_init(&size_params, single_rate_policers,
0431 single_rate_policers, 1,
0432 DEVLINK_RESOURCE_UNIT_ENTRY);
0433 err = devl_resource_register(devlink, "single_rate_policers",
0434 single_rate_policers,
0435 MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
0436 MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
0437 &size_params);
0438 if (err)
0439 return err;
0440
0441 return 0;
0442 }
0443
0444 static int
0445 mlxsw_sp1_policer_core_init(struct mlxsw_sp_policer_core *policer_core)
0446 {
0447 policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP1;
0448 policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP1;
0449
0450 return 0;
0451 }
0452
0453 const struct mlxsw_sp_policer_core_ops mlxsw_sp1_policer_core_ops = {
0454 .init = mlxsw_sp1_policer_core_init,
0455 };
0456
0457 static int
0458 mlxsw_sp2_policer_core_init(struct mlxsw_sp_policer_core *policer_core)
0459 {
0460 policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP2;
0461 policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP2;
0462
0463 return 0;
0464 }
0465
0466 const struct mlxsw_sp_policer_core_ops mlxsw_sp2_policer_core_ops = {
0467 .init = mlxsw_sp2_policer_core_init,
0468 };