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};