1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ 3 4 #include <linux/bitmap.h> 5 #include <linux/errno.h> 6 #include <linux/genalloc.h> 7 #include <linux/gfp.h> 8 #include <linux/kernel.h> 9 #include <linux/list.h> 10 #include <linux/rhashtable.h> 11 #include <linux/rtnetlink.h> 12 #include <linux/slab.h> 13 14 #include "core.h" 15 #include "reg.h" 16 #include "spectrum.h" 17 #include "spectrum_acl_tcam.h" 18 19 /* gen_pool_alloc() returns 0 when allocation fails, so use an offset */ 20 #define MLXSW_SP_ACL_ERP_GENALLOC_OFFSET 0x100 21 #define MLXSW_SP_ACL_ERP_MAX_PER_REGION 16 22 23 struct mlxsw_sp_acl_erp_core { 24 unsigned int erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_MAX + 1]; 25 struct gen_pool *erp_tables; 26 struct mlxsw_sp *mlxsw_sp; 27 unsigned int num_erp_banks; 28 }; 29 30 struct mlxsw_sp_acl_erp_key { 31 char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN]; 32 bool ctcam; 33 }; 34 35 struct mlxsw_sp_acl_erp { 36 struct mlxsw_sp_acl_erp_key key; 37 u8 id; 38 u8 index; 39 refcount_t refcnt; 40 DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN); 41 struct list_head list; 42 struct rhash_head ht_node; 43 struct mlxsw_sp_acl_erp_table *erp_table; 44 }; 45 46 struct mlxsw_sp_acl_erp_master_mask { 47 DECLARE_BITMAP(bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN); 48 unsigned int count[MLXSW_SP_ACL_TCAM_MASK_LEN]; 49 }; 50 51 struct mlxsw_sp_acl_erp_table { 52 struct mlxsw_sp_acl_erp_master_mask master_mask; 53 DECLARE_BITMAP(erp_id_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION); 54 DECLARE_BITMAP(erp_index_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION); 55 struct list_head atcam_erps_list; 56 struct rhashtable erp_ht; 57 struct mlxsw_sp_acl_erp_core *erp_core; 58 struct mlxsw_sp_acl_atcam_region *aregion; 59 const struct mlxsw_sp_acl_erp_table_ops *ops; 60 unsigned long base_index; 61 unsigned int num_atcam_erps; 62 unsigned int num_max_atcam_erps; 63 unsigned int num_ctcam_erps; 64 }; 65 66 static const struct rhashtable_params mlxsw_sp_acl_erp_ht_params = { 67 .key_len = sizeof(struct mlxsw_sp_acl_erp_key), 68 .key_offset = offsetof(struct mlxsw_sp_acl_erp, key), 69 .head_offset = offsetof(struct mlxsw_sp_acl_erp, ht_node), 70 }; 71 72 struct mlxsw_sp_acl_erp_table_ops { 73 struct mlxsw_sp_acl_erp * 74 (*erp_create)(struct mlxsw_sp_acl_erp_table *erp_table, 75 struct mlxsw_sp_acl_erp_key *key); 76 void (*erp_destroy)(struct mlxsw_sp_acl_erp_table *erp_table, 77 struct mlxsw_sp_acl_erp *erp); 78 }; 79 80 static struct mlxsw_sp_acl_erp * 81 mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 82 struct mlxsw_sp_acl_erp_key *key); 83 static void 84 mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 85 struct mlxsw_sp_acl_erp *erp); 86 static struct mlxsw_sp_acl_erp * 87 mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 88 struct mlxsw_sp_acl_erp_key *key); 89 static void 90 mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 91 struct mlxsw_sp_acl_erp *erp); 92 static struct mlxsw_sp_acl_erp * 93 mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 94 struct mlxsw_sp_acl_erp_key *key); 95 static void 96 mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 97 struct mlxsw_sp_acl_erp *erp); 98 static void 99 mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 100 struct mlxsw_sp_acl_erp *erp); 101 102 static const struct mlxsw_sp_acl_erp_table_ops erp_multiple_masks_ops = { 103 .erp_create = mlxsw_sp_acl_erp_mask_create, 104 .erp_destroy = mlxsw_sp_acl_erp_mask_destroy, 105 }; 106 107 static const struct mlxsw_sp_acl_erp_table_ops erp_two_masks_ops = { 108 .erp_create = mlxsw_sp_acl_erp_mask_create, 109 .erp_destroy = mlxsw_sp_acl_erp_second_mask_destroy, 110 }; 111 112 static const struct mlxsw_sp_acl_erp_table_ops erp_single_mask_ops = { 113 .erp_create = mlxsw_sp_acl_erp_second_mask_create, 114 .erp_destroy = mlxsw_sp_acl_erp_first_mask_destroy, 115 }; 116 117 static const struct mlxsw_sp_acl_erp_table_ops erp_no_mask_ops = { 118 .erp_create = mlxsw_sp_acl_erp_first_mask_create, 119 .erp_destroy = mlxsw_sp_acl_erp_no_mask_destroy, 120 }; 121 122 bool mlxsw_sp_acl_erp_is_ctcam_erp(const struct mlxsw_sp_acl_erp *erp) 123 { 124 return erp->key.ctcam; 125 } 126 127 u8 mlxsw_sp_acl_erp_id(const struct mlxsw_sp_acl_erp *erp) 128 { 129 return erp->id; 130 } 131 132 static unsigned int 133 mlxsw_sp_acl_erp_table_entry_size(const struct mlxsw_sp_acl_erp_table *erp_table) 134 { 135 struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion; 136 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core; 137 138 return erp_core->erpt_entries_size[aregion->type]; 139 } 140 141 static int mlxsw_sp_acl_erp_id_get(struct mlxsw_sp_acl_erp_table *erp_table, 142 u8 *p_id) 143 { 144 u8 id; 145 146 id = find_first_zero_bit(erp_table->erp_id_bitmap, 147 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 148 if (id < MLXSW_SP_ACL_ERP_MAX_PER_REGION) { 149 __set_bit(id, erp_table->erp_id_bitmap); 150 *p_id = id; 151 return 0; 152 } 153 154 return -ENOBUFS; 155 } 156 157 static void mlxsw_sp_acl_erp_id_put(struct mlxsw_sp_acl_erp_table *erp_table, 158 u8 id) 159 { 160 __clear_bit(id, erp_table->erp_id_bitmap); 161 } 162 163 static void 164 mlxsw_sp_acl_erp_master_mask_bit_set(unsigned long bit, 165 struct mlxsw_sp_acl_erp_master_mask *mask) 166 { 167 if (mask->count[bit]++ == 0) 168 __set_bit(bit, mask->bitmap); 169 } 170 171 static void 172 mlxsw_sp_acl_erp_master_mask_bit_clear(unsigned long bit, 173 struct mlxsw_sp_acl_erp_master_mask *mask) 174 { 175 if (--mask->count[bit] == 0) 176 __clear_bit(bit, mask->bitmap); 177 } 178 179 static int 180 mlxsw_sp_acl_erp_master_mask_update(struct mlxsw_sp_acl_erp_table *erp_table) 181 { 182 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region; 183 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp; 184 char percr_pl[MLXSW_REG_PERCR_LEN]; 185 char *master_mask; 186 187 mlxsw_reg_percr_pack(percr_pl, region->id); 188 master_mask = mlxsw_reg_percr_master_mask_data(percr_pl); 189 bitmap_to_arr32((u32 *) master_mask, erp_table->master_mask.bitmap, 190 MLXSW_SP_ACL_TCAM_MASK_LEN); 191 192 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl); 193 } 194 195 static int 196 mlxsw_sp_acl_erp_master_mask_set(struct mlxsw_sp_acl_erp_table *erp_table, 197 const struct mlxsw_sp_acl_erp *erp) 198 { 199 unsigned long bit; 200 int err; 201 202 for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) 203 mlxsw_sp_acl_erp_master_mask_bit_set(bit, 204 &erp_table->master_mask); 205 206 err = mlxsw_sp_acl_erp_master_mask_update(erp_table); 207 if (err) 208 goto err_master_mask_update; 209 210 return 0; 211 212 err_master_mask_update: 213 for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) 214 mlxsw_sp_acl_erp_master_mask_bit_clear(bit, 215 &erp_table->master_mask); 216 return err; 217 } 218 219 static int 220 mlxsw_sp_acl_erp_master_mask_clear(struct mlxsw_sp_acl_erp_table *erp_table, 221 const struct mlxsw_sp_acl_erp *erp) 222 { 223 unsigned long bit; 224 int err; 225 226 for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) 227 mlxsw_sp_acl_erp_master_mask_bit_clear(bit, 228 &erp_table->master_mask); 229 230 err = mlxsw_sp_acl_erp_master_mask_update(erp_table); 231 if (err) 232 goto err_master_mask_update; 233 234 return 0; 235 236 err_master_mask_update: 237 for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) 238 mlxsw_sp_acl_erp_master_mask_bit_set(bit, 239 &erp_table->master_mask); 240 return err; 241 } 242 243 static struct mlxsw_sp_acl_erp * 244 mlxsw_sp_acl_erp_generic_create(struct mlxsw_sp_acl_erp_table *erp_table, 245 struct mlxsw_sp_acl_erp_key *key) 246 { 247 struct mlxsw_sp_acl_erp *erp; 248 int err; 249 250 erp = kzalloc(sizeof(*erp), GFP_KERNEL); 251 if (!erp) 252 return ERR_PTR(-ENOMEM); 253 254 err = mlxsw_sp_acl_erp_id_get(erp_table, &erp->id); 255 if (err) 256 goto err_erp_id_get; 257 258 memcpy(&erp->key, key, sizeof(*key)); 259 bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask, 260 MLXSW_SP_ACL_TCAM_MASK_LEN); 261 list_add(&erp->list, &erp_table->atcam_erps_list); 262 refcount_set(&erp->refcnt, 1); 263 erp_table->num_atcam_erps++; 264 erp->erp_table = erp_table; 265 266 err = mlxsw_sp_acl_erp_master_mask_set(erp_table, erp); 267 if (err) 268 goto err_master_mask_set; 269 270 err = rhashtable_insert_fast(&erp_table->erp_ht, &erp->ht_node, 271 mlxsw_sp_acl_erp_ht_params); 272 if (err) 273 goto err_rhashtable_insert; 274 275 return erp; 276 277 err_rhashtable_insert: 278 mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp); 279 err_master_mask_set: 280 erp_table->num_atcam_erps--; 281 list_del(&erp->list); 282 mlxsw_sp_acl_erp_id_put(erp_table, erp->id); 283 err_erp_id_get: 284 kfree(erp); 285 return ERR_PTR(err); 286 } 287 288 static void 289 mlxsw_sp_acl_erp_generic_destroy(struct mlxsw_sp_acl_erp *erp) 290 { 291 struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table; 292 293 rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node, 294 mlxsw_sp_acl_erp_ht_params); 295 mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp); 296 erp_table->num_atcam_erps--; 297 list_del(&erp->list); 298 mlxsw_sp_acl_erp_id_put(erp_table, erp->id); 299 kfree(erp); 300 } 301 302 static int 303 mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core *erp_core, 304 unsigned int num_erps, 305 enum mlxsw_sp_acl_atcam_region_type region_type, 306 unsigned long *p_index) 307 { 308 unsigned int num_rows, entry_size; 309 310 /* We only allow allocations of entire rows */ 311 if (num_erps % erp_core->num_erp_banks != 0) 312 return -EINVAL; 313 314 entry_size = erp_core->erpt_entries_size[region_type]; 315 num_rows = num_erps / erp_core->num_erp_banks; 316 317 *p_index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size); 318 if (*p_index == 0) 319 return -ENOBUFS; 320 *p_index -= MLXSW_SP_ACL_ERP_GENALLOC_OFFSET; 321 322 return 0; 323 } 324 325 static void 326 mlxsw_sp_acl_erp_table_free(struct mlxsw_sp_acl_erp_core *erp_core, 327 unsigned int num_erps, 328 enum mlxsw_sp_acl_atcam_region_type region_type, 329 unsigned long index) 330 { 331 unsigned long base_index; 332 unsigned int entry_size; 333 size_t size; 334 335 entry_size = erp_core->erpt_entries_size[region_type]; 336 base_index = index + MLXSW_SP_ACL_ERP_GENALLOC_OFFSET; 337 size = num_erps / erp_core->num_erp_banks * entry_size; 338 gen_pool_free(erp_core->erp_tables, base_index, size); 339 } 340 341 static struct mlxsw_sp_acl_erp * 342 mlxsw_sp_acl_erp_table_master_rp(struct mlxsw_sp_acl_erp_table *erp_table) 343 { 344 if (!list_is_singular(&erp_table->atcam_erps_list)) 345 return NULL; 346 347 return list_first_entry(&erp_table->atcam_erps_list, 348 struct mlxsw_sp_acl_erp, list); 349 } 350 351 static int mlxsw_sp_acl_erp_index_get(struct mlxsw_sp_acl_erp_table *erp_table, 352 u8 *p_index) 353 { 354 u8 index; 355 356 index = find_first_zero_bit(erp_table->erp_index_bitmap, 357 erp_table->num_max_atcam_erps); 358 if (index < erp_table->num_max_atcam_erps) { 359 __set_bit(index, erp_table->erp_index_bitmap); 360 *p_index = index; 361 return 0; 362 } 363 364 return -ENOBUFS; 365 } 366 367 static void mlxsw_sp_acl_erp_index_put(struct mlxsw_sp_acl_erp_table *erp_table, 368 u8 index) 369 { 370 __clear_bit(index, erp_table->erp_index_bitmap); 371 } 372 373 static void 374 mlxsw_sp_acl_erp_table_locate(const struct mlxsw_sp_acl_erp_table *erp_table, 375 const struct mlxsw_sp_acl_erp *erp, 376 u8 *p_erpt_bank, u8 *p_erpt_index) 377 { 378 unsigned int entry_size = mlxsw_sp_acl_erp_table_entry_size(erp_table); 379 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core; 380 unsigned int row; 381 382 *p_erpt_bank = erp->index % erp_core->num_erp_banks; 383 row = erp->index / erp_core->num_erp_banks; 384 *p_erpt_index = erp_table->base_index + row * entry_size; 385 } 386 387 static int 388 mlxsw_sp_acl_erp_table_erp_add(struct mlxsw_sp_acl_erp_table *erp_table, 389 struct mlxsw_sp_acl_erp *erp) 390 { 391 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 392 enum mlxsw_reg_perpt_key_size key_size; 393 char perpt_pl[MLXSW_REG_PERPT_LEN]; 394 u8 erpt_bank, erpt_index; 395 396 mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index); 397 key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type; 398 mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id, 399 0, erp_table->base_index, erp->index, 400 erp->key.mask); 401 mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap, 402 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 403 mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, true); 404 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl); 405 } 406 407 static void mlxsw_sp_acl_erp_table_erp_del(struct mlxsw_sp_acl_erp *erp) 408 { 409 char empty_mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 }; 410 struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table; 411 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 412 enum mlxsw_reg_perpt_key_size key_size; 413 char perpt_pl[MLXSW_REG_PERPT_LEN]; 414 u8 erpt_bank, erpt_index; 415 416 mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index); 417 key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type; 418 mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id, 419 0, erp_table->base_index, erp->index, empty_mask); 420 mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap, 421 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 422 mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, false); 423 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl); 424 } 425 426 static int 427 mlxsw_sp_acl_erp_table_enable(struct mlxsw_sp_acl_erp_table *erp_table, 428 bool ctcam_le) 429 { 430 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region; 431 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 432 char pererp_pl[MLXSW_REG_PERERP_LEN]; 433 434 mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0, 435 erp_table->base_index, 0); 436 mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap, 437 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 438 439 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl); 440 } 441 442 static void 443 mlxsw_sp_acl_erp_table_disable(struct mlxsw_sp_acl_erp_table *erp_table) 444 { 445 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region; 446 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 447 char pererp_pl[MLXSW_REG_PERERP_LEN]; 448 struct mlxsw_sp_acl_erp *master_rp; 449 450 master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table); 451 /* It is possible we do not have a master RP when we disable the 452 * table when there are no rules in the A-TCAM and the last C-TCAM 453 * rule is deleted 454 */ 455 mlxsw_reg_pererp_pack(pererp_pl, region->id, false, false, 0, 0, 456 master_rp ? master_rp->id : 0); 457 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl); 458 } 459 460 static int 461 mlxsw_sp_acl_erp_table_relocate(struct mlxsw_sp_acl_erp_table *erp_table) 462 { 463 struct mlxsw_sp_acl_erp *erp; 464 int err; 465 466 list_for_each_entry(erp, &erp_table->atcam_erps_list, list) { 467 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp); 468 if (err) 469 goto err_table_erp_add; 470 } 471 472 return 0; 473 474 err_table_erp_add: 475 list_for_each_entry_continue_reverse(erp, &erp_table->atcam_erps_list, 476 list) 477 mlxsw_sp_acl_erp_table_erp_del(erp); 478 return err; 479 } 480 481 static int 482 mlxsw_sp_acl_erp_table_expand(struct mlxsw_sp_acl_erp_table *erp_table) 483 { 484 unsigned int num_erps, old_num_erps = erp_table->num_max_atcam_erps; 485 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core; 486 unsigned long old_base_index = erp_table->base_index; 487 bool ctcam_le = erp_table->num_ctcam_erps > 0; 488 int err; 489 490 if (erp_table->num_atcam_erps < erp_table->num_max_atcam_erps) 491 return 0; 492 493 if (erp_table->num_max_atcam_erps == MLXSW_SP_ACL_ERP_MAX_PER_REGION) 494 return -ENOBUFS; 495 496 num_erps = old_num_erps + erp_core->num_erp_banks; 497 err = mlxsw_sp_acl_erp_table_alloc(erp_core, num_erps, 498 erp_table->aregion->type, 499 &erp_table->base_index); 500 if (err) 501 return err; 502 erp_table->num_max_atcam_erps = num_erps; 503 504 err = mlxsw_sp_acl_erp_table_relocate(erp_table); 505 if (err) 506 goto err_table_relocate; 507 508 err = mlxsw_sp_acl_erp_table_enable(erp_table, ctcam_le); 509 if (err) 510 goto err_table_enable; 511 512 mlxsw_sp_acl_erp_table_free(erp_core, old_num_erps, 513 erp_table->aregion->type, old_base_index); 514 515 return 0; 516 517 err_table_enable: 518 err_table_relocate: 519 erp_table->num_max_atcam_erps = old_num_erps; 520 mlxsw_sp_acl_erp_table_free(erp_core, num_erps, 521 erp_table->aregion->type, 522 erp_table->base_index); 523 erp_table->base_index = old_base_index; 524 return err; 525 } 526 527 static int 528 mlxsw_sp_acl_erp_region_table_trans(struct mlxsw_sp_acl_erp_table *erp_table) 529 { 530 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core; 531 struct mlxsw_sp_acl_erp *master_rp; 532 int err; 533 534 /* Initially, allocate a single eRP row. Expand later as needed */ 535 err = mlxsw_sp_acl_erp_table_alloc(erp_core, erp_core->num_erp_banks, 536 erp_table->aregion->type, 537 &erp_table->base_index); 538 if (err) 539 return err; 540 erp_table->num_max_atcam_erps = erp_core->num_erp_banks; 541 542 /* Transition the sole RP currently configured (the master RP) 543 * to the eRP table 544 */ 545 master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table); 546 if (!master_rp) { 547 err = -EINVAL; 548 goto err_table_master_rp; 549 } 550 551 /* Maintain the same eRP bank for the master RP, so that we 552 * wouldn't need to update the bloom filter 553 */ 554 master_rp->index = master_rp->index % erp_core->num_erp_banks; 555 __set_bit(master_rp->index, erp_table->erp_index_bitmap); 556 557 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, master_rp); 558 if (err) 559 goto err_table_master_rp_add; 560 561 err = mlxsw_sp_acl_erp_table_enable(erp_table, false); 562 if (err) 563 goto err_table_enable; 564 565 return 0; 566 567 err_table_enable: 568 mlxsw_sp_acl_erp_table_erp_del(master_rp); 569 err_table_master_rp_add: 570 __clear_bit(master_rp->index, erp_table->erp_index_bitmap); 571 err_table_master_rp: 572 mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps, 573 erp_table->aregion->type, 574 erp_table->base_index); 575 return err; 576 } 577 578 static void 579 mlxsw_sp_acl_erp_region_master_mask_trans(struct mlxsw_sp_acl_erp_table *erp_table) 580 { 581 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core; 582 struct mlxsw_sp_acl_erp *master_rp; 583 584 mlxsw_sp_acl_erp_table_disable(erp_table); 585 master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table); 586 if (!master_rp) 587 return; 588 mlxsw_sp_acl_erp_table_erp_del(master_rp); 589 __clear_bit(master_rp->index, erp_table->erp_index_bitmap); 590 mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps, 591 erp_table->aregion->type, 592 erp_table->base_index); 593 } 594 595 static int 596 mlxsw_sp_acl_erp_region_erp_add(struct mlxsw_sp_acl_erp_table *erp_table, 597 struct mlxsw_sp_acl_erp *erp) 598 { 599 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region; 600 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 601 bool ctcam_le = erp_table->num_ctcam_erps > 0; 602 char pererp_pl[MLXSW_REG_PERERP_LEN]; 603 604 mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0, 605 erp_table->base_index, 0); 606 mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap, 607 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 608 mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, true); 609 610 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl); 611 } 612 613 static void mlxsw_sp_acl_erp_region_erp_del(struct mlxsw_sp_acl_erp *erp) 614 { 615 struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table; 616 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region; 617 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 618 bool ctcam_le = erp_table->num_ctcam_erps > 0; 619 char pererp_pl[MLXSW_REG_PERERP_LEN]; 620 621 mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0, 622 erp_table->base_index, 0); 623 mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap, 624 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 625 mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, false); 626 627 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl); 628 } 629 630 static int 631 mlxsw_sp_acl_erp_region_ctcam_enable(struct mlxsw_sp_acl_erp_table *erp_table) 632 { 633 /* No need to re-enable lookup in the C-TCAM */ 634 if (erp_table->num_ctcam_erps > 1) 635 return 0; 636 637 return mlxsw_sp_acl_erp_table_enable(erp_table, true); 638 } 639 640 static void 641 mlxsw_sp_acl_erp_region_ctcam_disable(struct mlxsw_sp_acl_erp_table *erp_table) 642 { 643 /* Only disable C-TCAM lookup when last C-TCAM eRP is deleted */ 644 if (erp_table->num_ctcam_erps > 1) 645 return; 646 647 mlxsw_sp_acl_erp_table_enable(erp_table, false); 648 } 649 650 static void 651 mlxsw_sp_acl_erp_ctcam_table_ops_set(struct mlxsw_sp_acl_erp_table *erp_table) 652 { 653 switch (erp_table->num_atcam_erps) { 654 case 2: 655 /* Keep using the eRP table, but correctly set the 656 * operations pointer so that when an A-TCAM eRP is 657 * deleted we will transition to use the master mask 658 */ 659 erp_table->ops = &erp_two_masks_ops; 660 break; 661 case 1: 662 /* We only kept the eRP table because we had C-TCAM 663 * eRPs in use. Now that the last C-TCAM eRP is gone we 664 * can stop using the table and transition to use the 665 * master mask 666 */ 667 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table); 668 erp_table->ops = &erp_single_mask_ops; 669 break; 670 case 0: 671 /* There are no more eRPs of any kind used by the region 672 * so free its eRP table and transition to initial state 673 */ 674 mlxsw_sp_acl_erp_table_disable(erp_table); 675 mlxsw_sp_acl_erp_table_free(erp_table->erp_core, 676 erp_table->num_max_atcam_erps, 677 erp_table->aregion->type, 678 erp_table->base_index); 679 erp_table->ops = &erp_no_mask_ops; 680 break; 681 default: 682 break; 683 } 684 } 685 686 static struct mlxsw_sp_acl_erp * 687 __mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 688 struct mlxsw_sp_acl_erp_key *key) 689 { 690 struct mlxsw_sp_acl_erp *erp; 691 int err; 692 693 erp = kzalloc(sizeof(*erp), GFP_KERNEL); 694 if (!erp) 695 return ERR_PTR(-ENOMEM); 696 697 memcpy(&erp->key, key, sizeof(*key)); 698 bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask, 699 MLXSW_SP_ACL_TCAM_MASK_LEN); 700 refcount_set(&erp->refcnt, 1); 701 erp_table->num_ctcam_erps++; 702 erp->erp_table = erp_table; 703 704 err = mlxsw_sp_acl_erp_master_mask_set(erp_table, erp); 705 if (err) 706 goto err_master_mask_set; 707 708 err = rhashtable_insert_fast(&erp_table->erp_ht, &erp->ht_node, 709 mlxsw_sp_acl_erp_ht_params); 710 if (err) 711 goto err_rhashtable_insert; 712 713 err = mlxsw_sp_acl_erp_region_ctcam_enable(erp_table); 714 if (err) 715 goto err_erp_region_ctcam_enable; 716 717 /* When C-TCAM is used, the eRP table must be used */ 718 erp_table->ops = &erp_multiple_masks_ops; 719 720 return erp; 721 722 err_erp_region_ctcam_enable: 723 rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node, 724 mlxsw_sp_acl_erp_ht_params); 725 err_rhashtable_insert: 726 mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp); 727 err_master_mask_set: 728 erp_table->num_ctcam_erps--; 729 kfree(erp); 730 return ERR_PTR(err); 731 } 732 733 static struct mlxsw_sp_acl_erp * 734 mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 735 struct mlxsw_sp_acl_erp_key *key) 736 { 737 struct mlxsw_sp_acl_erp *erp; 738 int err; 739 740 /* There is a special situation where we need to spill rules 741 * into the C-TCAM, yet the region is still using a master 742 * mask and thus not performing a lookup in the C-TCAM. This 743 * can happen when two rules that only differ in priority - and 744 * thus sharing the same key - are programmed. In this case 745 * we transition the region to use an eRP table 746 */ 747 err = mlxsw_sp_acl_erp_region_table_trans(erp_table); 748 if (err) 749 return ERR_PTR(err); 750 751 erp = __mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key); 752 if (IS_ERR(erp)) { 753 err = PTR_ERR(erp); 754 goto err_erp_create; 755 } 756 757 return erp; 758 759 err_erp_create: 760 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table); 761 return ERR_PTR(err); 762 } 763 764 static void 765 mlxsw_sp_acl_erp_ctcam_mask_destroy(struct mlxsw_sp_acl_erp *erp) 766 { 767 struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table; 768 769 mlxsw_sp_acl_erp_region_ctcam_disable(erp_table); 770 rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node, 771 mlxsw_sp_acl_erp_ht_params); 772 mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp); 773 erp_table->num_ctcam_erps--; 774 kfree(erp); 775 776 /* Once the last C-TCAM eRP was destroyed, the state we 777 * transition to depends on the number of A-TCAM eRPs currently 778 * in use 779 */ 780 if (erp_table->num_ctcam_erps > 0) 781 return; 782 mlxsw_sp_acl_erp_ctcam_table_ops_set(erp_table); 783 } 784 785 static struct mlxsw_sp_acl_erp * 786 mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 787 struct mlxsw_sp_acl_erp_key *key) 788 { 789 struct mlxsw_sp_acl_erp *erp; 790 int err; 791 792 if (key->ctcam) 793 return __mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key); 794 795 /* Expand the eRP table for the new eRP, if needed */ 796 err = mlxsw_sp_acl_erp_table_expand(erp_table); 797 if (err) 798 return ERR_PTR(err); 799 800 erp = mlxsw_sp_acl_erp_generic_create(erp_table, key); 801 if (IS_ERR(erp)) 802 return erp; 803 804 err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index); 805 if (err) 806 goto err_erp_index_get; 807 808 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp); 809 if (err) 810 goto err_table_erp_add; 811 812 err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp); 813 if (err) 814 goto err_region_erp_add; 815 816 erp_table->ops = &erp_multiple_masks_ops; 817 818 return erp; 819 820 err_region_erp_add: 821 mlxsw_sp_acl_erp_table_erp_del(erp); 822 err_table_erp_add: 823 mlxsw_sp_acl_erp_index_put(erp_table, erp->index); 824 err_erp_index_get: 825 mlxsw_sp_acl_erp_generic_destroy(erp); 826 return ERR_PTR(err); 827 } 828 829 static void 830 mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 831 struct mlxsw_sp_acl_erp *erp) 832 { 833 if (erp->key.ctcam) 834 return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp); 835 836 mlxsw_sp_acl_erp_region_erp_del(erp); 837 mlxsw_sp_acl_erp_table_erp_del(erp); 838 mlxsw_sp_acl_erp_index_put(erp_table, erp->index); 839 mlxsw_sp_acl_erp_generic_destroy(erp); 840 841 if (erp_table->num_atcam_erps == 2 && erp_table->num_ctcam_erps == 0) 842 erp_table->ops = &erp_two_masks_ops; 843 } 844 845 static struct mlxsw_sp_acl_erp * 846 mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 847 struct mlxsw_sp_acl_erp_key *key) 848 { 849 struct mlxsw_sp_acl_erp *erp; 850 int err; 851 852 if (key->ctcam) 853 return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key); 854 855 /* Transition to use eRP table instead of master mask */ 856 err = mlxsw_sp_acl_erp_region_table_trans(erp_table); 857 if (err) 858 return ERR_PTR(err); 859 860 erp = mlxsw_sp_acl_erp_generic_create(erp_table, key); 861 if (IS_ERR(erp)) { 862 err = PTR_ERR(erp); 863 goto err_erp_create; 864 } 865 866 err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index); 867 if (err) 868 goto err_erp_index_get; 869 870 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp); 871 if (err) 872 goto err_table_erp_add; 873 874 err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp); 875 if (err) 876 goto err_region_erp_add; 877 878 erp_table->ops = &erp_two_masks_ops; 879 880 return erp; 881 882 err_region_erp_add: 883 mlxsw_sp_acl_erp_table_erp_del(erp); 884 err_table_erp_add: 885 mlxsw_sp_acl_erp_index_put(erp_table, erp->index); 886 err_erp_index_get: 887 mlxsw_sp_acl_erp_generic_destroy(erp); 888 err_erp_create: 889 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table); 890 return ERR_PTR(err); 891 } 892 893 static void 894 mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 895 struct mlxsw_sp_acl_erp *erp) 896 { 897 if (erp->key.ctcam) 898 return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp); 899 900 mlxsw_sp_acl_erp_region_erp_del(erp); 901 mlxsw_sp_acl_erp_table_erp_del(erp); 902 mlxsw_sp_acl_erp_index_put(erp_table, erp->index); 903 mlxsw_sp_acl_erp_generic_destroy(erp); 904 /* Transition to use master mask instead of eRP table */ 905 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table); 906 907 erp_table->ops = &erp_single_mask_ops; 908 } 909 910 static struct mlxsw_sp_acl_erp * 911 mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 912 struct mlxsw_sp_acl_erp_key *key) 913 { 914 struct mlxsw_sp_acl_erp *erp; 915 916 if (key->ctcam) 917 return ERR_PTR(-EINVAL); 918 919 erp = mlxsw_sp_acl_erp_generic_create(erp_table, key); 920 if (IS_ERR(erp)) 921 return erp; 922 923 erp_table->ops = &erp_single_mask_ops; 924 925 return erp; 926 } 927 928 static void 929 mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 930 struct mlxsw_sp_acl_erp *erp) 931 { 932 mlxsw_sp_acl_erp_generic_destroy(erp); 933 erp_table->ops = &erp_no_mask_ops; 934 } 935 936 static void 937 mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 938 struct mlxsw_sp_acl_erp *erp) 939 { 940 WARN_ON(1); 941 } 942 943 struct mlxsw_sp_acl_erp * 944 mlxsw_sp_acl_erp_get(struct mlxsw_sp_acl_atcam_region *aregion, 945 const char *mask, bool ctcam) 946 { 947 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; 948 struct mlxsw_sp_acl_erp_key key; 949 struct mlxsw_sp_acl_erp *erp; 950 951 /* eRPs are allocated from a shared resource, but currently all 952 * allocations are done under RTNL. 953 */ 954 ASSERT_RTNL(); 955 956 memcpy(key.mask, mask, MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN); 957 key.ctcam = ctcam; 958 erp = rhashtable_lookup_fast(&erp_table->erp_ht, &key, 959 mlxsw_sp_acl_erp_ht_params); 960 if (erp) { 961 refcount_inc(&erp->refcnt); 962 return erp; 963 } 964 965 return erp_table->ops->erp_create(erp_table, &key); 966 } 967 968 void mlxsw_sp_acl_erp_put(struct mlxsw_sp_acl_atcam_region *aregion, 969 struct mlxsw_sp_acl_erp *erp) 970 { 971 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; 972 973 ASSERT_RTNL(); 974 975 if (!refcount_dec_and_test(&erp->refcnt)) 976 return; 977 978 erp_table->ops->erp_destroy(erp_table, erp); 979 } 980 981 static struct mlxsw_sp_acl_erp_table * 982 mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion) 983 { 984 struct mlxsw_sp_acl_erp_table *erp_table; 985 int err; 986 987 erp_table = kzalloc(sizeof(*erp_table), GFP_KERNEL); 988 if (!erp_table) 989 return ERR_PTR(-ENOMEM); 990 991 err = rhashtable_init(&erp_table->erp_ht, &mlxsw_sp_acl_erp_ht_params); 992 if (err) 993 goto err_rhashtable_init; 994 995 erp_table->erp_core = aregion->atcam->erp_core; 996 erp_table->ops = &erp_no_mask_ops; 997 INIT_LIST_HEAD(&erp_table->atcam_erps_list); 998 erp_table->aregion = aregion; 999 1000 return erp_table; 1001 1002 err_rhashtable_init: 1003 kfree(erp_table); 1004 return ERR_PTR(err); 1005 } 1006 1007 static void 1008 mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table *erp_table) 1009 { 1010 WARN_ON(!list_empty(&erp_table->atcam_erps_list)); 1011 rhashtable_destroy(&erp_table->erp_ht); 1012 kfree(erp_table); 1013 } 1014 1015 static int 1016 mlxsw_sp_acl_erp_master_mask_init(struct mlxsw_sp_acl_atcam_region *aregion) 1017 { 1018 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp; 1019 char percr_pl[MLXSW_REG_PERCR_LEN]; 1020 1021 mlxsw_reg_percr_pack(percr_pl, aregion->region->id); 1022 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl); 1023 } 1024 1025 static int 1026 mlxsw_sp_acl_erp_region_param_init(struct mlxsw_sp_acl_atcam_region *aregion) 1027 { 1028 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp; 1029 char pererp_pl[MLXSW_REG_PERERP_LEN]; 1030 1031 mlxsw_reg_pererp_pack(pererp_pl, aregion->region->id, false, false, 0, 1032 0, 0); 1033 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl); 1034 } 1035 1036 int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion) 1037 { 1038 struct mlxsw_sp_acl_erp_table *erp_table; 1039 int err; 1040 1041 erp_table = mlxsw_sp_acl_erp_table_create(aregion); 1042 if (IS_ERR(erp_table)) 1043 return PTR_ERR(erp_table); 1044 aregion->erp_table = erp_table; 1045 1046 /* Initialize the region's master mask to all zeroes */ 1047 err = mlxsw_sp_acl_erp_master_mask_init(aregion); 1048 if (err) 1049 goto err_erp_master_mask_init; 1050 1051 /* Initialize the region to not use the eRP table */ 1052 err = mlxsw_sp_acl_erp_region_param_init(aregion); 1053 if (err) 1054 goto err_erp_region_param_init; 1055 1056 return 0; 1057 1058 err_erp_region_param_init: 1059 err_erp_master_mask_init: 1060 mlxsw_sp_acl_erp_table_destroy(erp_table); 1061 return err; 1062 } 1063 1064 void mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region *aregion) 1065 { 1066 mlxsw_sp_acl_erp_table_destroy(aregion->erp_table); 1067 } 1068 1069 static int 1070 mlxsw_sp_acl_erp_tables_sizes_query(struct mlxsw_sp *mlxsw_sp, 1071 struct mlxsw_sp_acl_erp_core *erp_core) 1072 { 1073 unsigned int size; 1074 1075 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB) || 1076 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB) || 1077 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB) || 1078 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB)) 1079 return -EIO; 1080 1081 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB); 1082 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] = size; 1083 1084 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB); 1085 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] = size; 1086 1087 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB); 1088 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] = size; 1089 1090 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB); 1091 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] = size; 1092 1093 return 0; 1094 } 1095 1096 static int mlxsw_sp_acl_erp_tables_init(struct mlxsw_sp *mlxsw_sp, 1097 struct mlxsw_sp_acl_erp_core *erp_core) 1098 { 1099 unsigned int erpt_bank_size; 1100 int err; 1101 1102 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANK_SIZE) || 1103 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANKS)) 1104 return -EIO; 1105 erpt_bank_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, 1106 ACL_MAX_ERPT_BANK_SIZE); 1107 erp_core->num_erp_banks = MLXSW_CORE_RES_GET(mlxsw_sp->core, 1108 ACL_MAX_ERPT_BANKS); 1109 1110 erp_core->erp_tables = gen_pool_create(0, -1); 1111 if (!erp_core->erp_tables) 1112 return -ENOMEM; 1113 gen_pool_set_algo(erp_core->erp_tables, gen_pool_best_fit, NULL); 1114 1115 err = gen_pool_add(erp_core->erp_tables, 1116 MLXSW_SP_ACL_ERP_GENALLOC_OFFSET, erpt_bank_size, 1117 -1); 1118 if (err) 1119 goto err_gen_pool_add; 1120 1121 /* Different regions require masks of different sizes */ 1122 err = mlxsw_sp_acl_erp_tables_sizes_query(mlxsw_sp, erp_core); 1123 if (err) 1124 goto err_erp_tables_sizes_query; 1125 1126 return 0; 1127 1128 err_erp_tables_sizes_query: 1129 err_gen_pool_add: 1130 gen_pool_destroy(erp_core->erp_tables); 1131 return err; 1132 } 1133 1134 static void mlxsw_sp_acl_erp_tables_fini(struct mlxsw_sp *mlxsw_sp, 1135 struct mlxsw_sp_acl_erp_core *erp_core) 1136 { 1137 gen_pool_destroy(erp_core->erp_tables); 1138 } 1139 1140 int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp, 1141 struct mlxsw_sp_acl_atcam *atcam) 1142 { 1143 struct mlxsw_sp_acl_erp_core *erp_core; 1144 int err; 1145 1146 erp_core = kzalloc(sizeof(*erp_core), GFP_KERNEL); 1147 if (!erp_core) 1148 return -ENOMEM; 1149 erp_core->mlxsw_sp = mlxsw_sp; 1150 atcam->erp_core = erp_core; 1151 1152 err = mlxsw_sp_acl_erp_tables_init(mlxsw_sp, erp_core); 1153 if (err) 1154 goto err_erp_tables_init; 1155 1156 return 0; 1157 1158 err_erp_tables_init: 1159 kfree(erp_core); 1160 return err; 1161 } 1162 1163 void mlxsw_sp_acl_erps_fini(struct mlxsw_sp *mlxsw_sp, 1164 struct mlxsw_sp_acl_atcam *atcam) 1165 { 1166 mlxsw_sp_acl_erp_tables_fini(mlxsw_sp, atcam->erp_core); 1167 kfree(atcam->erp_core); 1168 } 1169