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/objagg.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 #define __MASK_LEN 0x38 33 #define __MASK_IDX(i) (__MASK_LEN - (i) - 1) 34 bool ctcam; 35 }; 36 37 struct mlxsw_sp_acl_erp { 38 struct mlxsw_sp_acl_erp_key key; 39 u8 id; 40 u8 index; 41 DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN); 42 struct list_head list; 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 mlxsw_sp_acl_erp_core *erp_core; 57 struct mlxsw_sp_acl_atcam_region *aregion; 58 const struct mlxsw_sp_acl_erp_table_ops *ops; 59 unsigned long base_index; 60 unsigned int num_atcam_erps; 61 unsigned int num_max_atcam_erps; 62 unsigned int num_ctcam_erps; 63 unsigned int num_deltas; 64 struct objagg *objagg; 65 }; 66 67 struct mlxsw_sp_acl_erp_table_ops { 68 struct mlxsw_sp_acl_erp * 69 (*erp_create)(struct mlxsw_sp_acl_erp_table *erp_table, 70 struct mlxsw_sp_acl_erp_key *key); 71 void (*erp_destroy)(struct mlxsw_sp_acl_erp_table *erp_table, 72 struct mlxsw_sp_acl_erp *erp); 73 }; 74 75 static struct mlxsw_sp_acl_erp * 76 mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 77 struct mlxsw_sp_acl_erp_key *key); 78 static void 79 mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 80 struct mlxsw_sp_acl_erp *erp); 81 static struct mlxsw_sp_acl_erp * 82 mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 83 struct mlxsw_sp_acl_erp_key *key); 84 static void 85 mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 86 struct mlxsw_sp_acl_erp *erp); 87 static struct mlxsw_sp_acl_erp * 88 mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 89 struct mlxsw_sp_acl_erp_key *key); 90 static void 91 mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 92 struct mlxsw_sp_acl_erp *erp); 93 static void 94 mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 95 struct mlxsw_sp_acl_erp *erp); 96 97 static const struct mlxsw_sp_acl_erp_table_ops erp_multiple_masks_ops = { 98 .erp_create = mlxsw_sp_acl_erp_mask_create, 99 .erp_destroy = mlxsw_sp_acl_erp_mask_destroy, 100 }; 101 102 static const struct mlxsw_sp_acl_erp_table_ops erp_two_masks_ops = { 103 .erp_create = mlxsw_sp_acl_erp_mask_create, 104 .erp_destroy = mlxsw_sp_acl_erp_second_mask_destroy, 105 }; 106 107 static const struct mlxsw_sp_acl_erp_table_ops erp_single_mask_ops = { 108 .erp_create = mlxsw_sp_acl_erp_second_mask_create, 109 .erp_destroy = mlxsw_sp_acl_erp_first_mask_destroy, 110 }; 111 112 static const struct mlxsw_sp_acl_erp_table_ops erp_no_mask_ops = { 113 .erp_create = mlxsw_sp_acl_erp_first_mask_create, 114 .erp_destroy = mlxsw_sp_acl_erp_no_mask_destroy, 115 }; 116 117 static unsigned int 118 mlxsw_sp_acl_erp_table_entry_size(const struct mlxsw_sp_acl_erp_table *erp_table) 119 { 120 struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion; 121 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core; 122 123 return erp_core->erpt_entries_size[aregion->type]; 124 } 125 126 static int mlxsw_sp_acl_erp_id_get(struct mlxsw_sp_acl_erp_table *erp_table, 127 u8 *p_id) 128 { 129 u8 id; 130 131 id = find_first_zero_bit(erp_table->erp_id_bitmap, 132 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 133 if (id < MLXSW_SP_ACL_ERP_MAX_PER_REGION) { 134 __set_bit(id, erp_table->erp_id_bitmap); 135 *p_id = id; 136 return 0; 137 } 138 139 return -ENOBUFS; 140 } 141 142 static void mlxsw_sp_acl_erp_id_put(struct mlxsw_sp_acl_erp_table *erp_table, 143 u8 id) 144 { 145 __clear_bit(id, erp_table->erp_id_bitmap); 146 } 147 148 static void 149 mlxsw_sp_acl_erp_master_mask_bit_set(unsigned long bit, 150 struct mlxsw_sp_acl_erp_master_mask *mask) 151 { 152 if (mask->count[bit]++ == 0) 153 __set_bit(bit, mask->bitmap); 154 } 155 156 static void 157 mlxsw_sp_acl_erp_master_mask_bit_clear(unsigned long bit, 158 struct mlxsw_sp_acl_erp_master_mask *mask) 159 { 160 if (--mask->count[bit] == 0) 161 __clear_bit(bit, mask->bitmap); 162 } 163 164 static int 165 mlxsw_sp_acl_erp_master_mask_update(struct mlxsw_sp_acl_erp_table *erp_table) 166 { 167 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region; 168 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp; 169 char percr_pl[MLXSW_REG_PERCR_LEN]; 170 char *master_mask; 171 172 mlxsw_reg_percr_pack(percr_pl, region->id); 173 master_mask = mlxsw_reg_percr_master_mask_data(percr_pl); 174 bitmap_to_arr32((u32 *) master_mask, erp_table->master_mask.bitmap, 175 MLXSW_SP_ACL_TCAM_MASK_LEN); 176 177 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl); 178 } 179 180 static int 181 mlxsw_sp_acl_erp_master_mask_set(struct mlxsw_sp_acl_erp_table *erp_table, 182 struct mlxsw_sp_acl_erp_key *key) 183 { 184 DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN); 185 unsigned long bit; 186 int err; 187 188 bitmap_from_arr32(mask_bitmap, (u32 *) key->mask, 189 MLXSW_SP_ACL_TCAM_MASK_LEN); 190 for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) 191 mlxsw_sp_acl_erp_master_mask_bit_set(bit, 192 &erp_table->master_mask); 193 194 err = mlxsw_sp_acl_erp_master_mask_update(erp_table); 195 if (err) 196 goto err_master_mask_update; 197 198 return 0; 199 200 err_master_mask_update: 201 for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) 202 mlxsw_sp_acl_erp_master_mask_bit_clear(bit, 203 &erp_table->master_mask); 204 return err; 205 } 206 207 static int 208 mlxsw_sp_acl_erp_master_mask_clear(struct mlxsw_sp_acl_erp_table *erp_table, 209 struct mlxsw_sp_acl_erp_key *key) 210 { 211 DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN); 212 unsigned long bit; 213 int err; 214 215 bitmap_from_arr32(mask_bitmap, (u32 *) key->mask, 216 MLXSW_SP_ACL_TCAM_MASK_LEN); 217 for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) 218 mlxsw_sp_acl_erp_master_mask_bit_clear(bit, 219 &erp_table->master_mask); 220 221 err = mlxsw_sp_acl_erp_master_mask_update(erp_table); 222 if (err) 223 goto err_master_mask_update; 224 225 return 0; 226 227 err_master_mask_update: 228 for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) 229 mlxsw_sp_acl_erp_master_mask_bit_set(bit, 230 &erp_table->master_mask); 231 return err; 232 } 233 234 static struct mlxsw_sp_acl_erp * 235 mlxsw_sp_acl_erp_generic_create(struct mlxsw_sp_acl_erp_table *erp_table, 236 struct mlxsw_sp_acl_erp_key *key) 237 { 238 struct mlxsw_sp_acl_erp *erp; 239 int err; 240 241 erp = kzalloc(sizeof(*erp), GFP_KERNEL); 242 if (!erp) 243 return ERR_PTR(-ENOMEM); 244 245 err = mlxsw_sp_acl_erp_id_get(erp_table, &erp->id); 246 if (err) 247 goto err_erp_id_get; 248 249 memcpy(&erp->key, key, sizeof(*key)); 250 list_add(&erp->list, &erp_table->atcam_erps_list); 251 erp_table->num_atcam_erps++; 252 erp->erp_table = erp_table; 253 254 err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key); 255 if (err) 256 goto err_master_mask_set; 257 258 return erp; 259 260 err_master_mask_set: 261 erp_table->num_atcam_erps--; 262 list_del(&erp->list); 263 mlxsw_sp_acl_erp_id_put(erp_table, erp->id); 264 err_erp_id_get: 265 kfree(erp); 266 return ERR_PTR(err); 267 } 268 269 static void 270 mlxsw_sp_acl_erp_generic_destroy(struct mlxsw_sp_acl_erp *erp) 271 { 272 struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table; 273 274 mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key); 275 erp_table->num_atcam_erps--; 276 list_del(&erp->list); 277 mlxsw_sp_acl_erp_id_put(erp_table, erp->id); 278 kfree(erp); 279 } 280 281 static int 282 mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core *erp_core, 283 unsigned int num_erps, 284 enum mlxsw_sp_acl_atcam_region_type region_type, 285 unsigned long *p_index) 286 { 287 unsigned int num_rows, entry_size; 288 289 /* We only allow allocations of entire rows */ 290 if (num_erps % erp_core->num_erp_banks != 0) 291 return -EINVAL; 292 293 entry_size = erp_core->erpt_entries_size[region_type]; 294 num_rows = num_erps / erp_core->num_erp_banks; 295 296 *p_index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size); 297 if (*p_index == 0) 298 return -ENOBUFS; 299 *p_index -= MLXSW_SP_ACL_ERP_GENALLOC_OFFSET; 300 301 return 0; 302 } 303 304 static void 305 mlxsw_sp_acl_erp_table_free(struct mlxsw_sp_acl_erp_core *erp_core, 306 unsigned int num_erps, 307 enum mlxsw_sp_acl_atcam_region_type region_type, 308 unsigned long index) 309 { 310 unsigned long base_index; 311 unsigned int entry_size; 312 size_t size; 313 314 entry_size = erp_core->erpt_entries_size[region_type]; 315 base_index = index + MLXSW_SP_ACL_ERP_GENALLOC_OFFSET; 316 size = num_erps / erp_core->num_erp_banks * entry_size; 317 gen_pool_free(erp_core->erp_tables, base_index, size); 318 } 319 320 static struct mlxsw_sp_acl_erp * 321 mlxsw_sp_acl_erp_table_master_rp(struct mlxsw_sp_acl_erp_table *erp_table) 322 { 323 if (!list_is_singular(&erp_table->atcam_erps_list)) 324 return NULL; 325 326 return list_first_entry(&erp_table->atcam_erps_list, 327 struct mlxsw_sp_acl_erp, list); 328 } 329 330 static int mlxsw_sp_acl_erp_index_get(struct mlxsw_sp_acl_erp_table *erp_table, 331 u8 *p_index) 332 { 333 u8 index; 334 335 index = find_first_zero_bit(erp_table->erp_index_bitmap, 336 erp_table->num_max_atcam_erps); 337 if (index < erp_table->num_max_atcam_erps) { 338 __set_bit(index, erp_table->erp_index_bitmap); 339 *p_index = index; 340 return 0; 341 } 342 343 return -ENOBUFS; 344 } 345 346 static void mlxsw_sp_acl_erp_index_put(struct mlxsw_sp_acl_erp_table *erp_table, 347 u8 index) 348 { 349 __clear_bit(index, erp_table->erp_index_bitmap); 350 } 351 352 static void 353 mlxsw_sp_acl_erp_table_locate(const struct mlxsw_sp_acl_erp_table *erp_table, 354 const struct mlxsw_sp_acl_erp *erp, 355 u8 *p_erpt_bank, u8 *p_erpt_index) 356 { 357 unsigned int entry_size = mlxsw_sp_acl_erp_table_entry_size(erp_table); 358 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core; 359 unsigned int row; 360 361 *p_erpt_bank = erp->index % erp_core->num_erp_banks; 362 row = erp->index / erp_core->num_erp_banks; 363 *p_erpt_index = erp_table->base_index + row * entry_size; 364 } 365 366 static int 367 mlxsw_sp_acl_erp_table_erp_add(struct mlxsw_sp_acl_erp_table *erp_table, 368 struct mlxsw_sp_acl_erp *erp) 369 { 370 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 371 enum mlxsw_reg_perpt_key_size key_size; 372 char perpt_pl[MLXSW_REG_PERPT_LEN]; 373 u8 erpt_bank, erpt_index; 374 375 mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index); 376 key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type; 377 mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id, 378 0, erp_table->base_index, erp->index, 379 erp->key.mask); 380 mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap, 381 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 382 mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, true); 383 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl); 384 } 385 386 static void mlxsw_sp_acl_erp_table_erp_del(struct mlxsw_sp_acl_erp *erp) 387 { 388 char empty_mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 }; 389 struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table; 390 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 391 enum mlxsw_reg_perpt_key_size key_size; 392 char perpt_pl[MLXSW_REG_PERPT_LEN]; 393 u8 erpt_bank, erpt_index; 394 395 mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index); 396 key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type; 397 mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id, 398 0, erp_table->base_index, erp->index, empty_mask); 399 mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap, 400 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 401 mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, false); 402 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl); 403 } 404 405 static int 406 mlxsw_sp_acl_erp_table_enable(struct mlxsw_sp_acl_erp_table *erp_table, 407 bool ctcam_le) 408 { 409 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region; 410 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 411 char pererp_pl[MLXSW_REG_PERERP_LEN]; 412 413 mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0, 414 erp_table->base_index, 0); 415 mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap, 416 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 417 418 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl); 419 } 420 421 static void 422 mlxsw_sp_acl_erp_table_disable(struct mlxsw_sp_acl_erp_table *erp_table) 423 { 424 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region; 425 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 426 char pererp_pl[MLXSW_REG_PERERP_LEN]; 427 struct mlxsw_sp_acl_erp *master_rp; 428 429 master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table); 430 /* It is possible we do not have a master RP when we disable the 431 * table when there are no rules in the A-TCAM and the last C-TCAM 432 * rule is deleted 433 */ 434 mlxsw_reg_pererp_pack(pererp_pl, region->id, false, false, 0, 0, 435 master_rp ? master_rp->id : 0); 436 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl); 437 } 438 439 static int 440 mlxsw_sp_acl_erp_table_relocate(struct mlxsw_sp_acl_erp_table *erp_table) 441 { 442 struct mlxsw_sp_acl_erp *erp; 443 int err; 444 445 list_for_each_entry(erp, &erp_table->atcam_erps_list, list) { 446 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp); 447 if (err) 448 goto err_table_erp_add; 449 } 450 451 return 0; 452 453 err_table_erp_add: 454 list_for_each_entry_continue_reverse(erp, &erp_table->atcam_erps_list, 455 list) 456 mlxsw_sp_acl_erp_table_erp_del(erp); 457 return err; 458 } 459 460 static int 461 mlxsw_sp_acl_erp_table_expand(struct mlxsw_sp_acl_erp_table *erp_table) 462 { 463 unsigned int num_erps, old_num_erps = erp_table->num_max_atcam_erps; 464 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core; 465 unsigned long old_base_index = erp_table->base_index; 466 bool ctcam_le = erp_table->num_ctcam_erps > 0; 467 int err; 468 469 if (erp_table->num_atcam_erps < erp_table->num_max_atcam_erps) 470 return 0; 471 472 if (erp_table->num_max_atcam_erps == MLXSW_SP_ACL_ERP_MAX_PER_REGION) 473 return -ENOBUFS; 474 475 num_erps = old_num_erps + erp_core->num_erp_banks; 476 err = mlxsw_sp_acl_erp_table_alloc(erp_core, num_erps, 477 erp_table->aregion->type, 478 &erp_table->base_index); 479 if (err) 480 return err; 481 erp_table->num_max_atcam_erps = num_erps; 482 483 err = mlxsw_sp_acl_erp_table_relocate(erp_table); 484 if (err) 485 goto err_table_relocate; 486 487 err = mlxsw_sp_acl_erp_table_enable(erp_table, ctcam_le); 488 if (err) 489 goto err_table_enable; 490 491 mlxsw_sp_acl_erp_table_free(erp_core, old_num_erps, 492 erp_table->aregion->type, old_base_index); 493 494 return 0; 495 496 err_table_enable: 497 err_table_relocate: 498 erp_table->num_max_atcam_erps = old_num_erps; 499 mlxsw_sp_acl_erp_table_free(erp_core, num_erps, 500 erp_table->aregion->type, 501 erp_table->base_index); 502 erp_table->base_index = old_base_index; 503 return err; 504 } 505 506 static int 507 mlxsw_sp_acl_erp_region_table_trans(struct mlxsw_sp_acl_erp_table *erp_table) 508 { 509 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core; 510 struct mlxsw_sp_acl_erp *master_rp; 511 int err; 512 513 /* Initially, allocate a single eRP row. Expand later as needed */ 514 err = mlxsw_sp_acl_erp_table_alloc(erp_core, erp_core->num_erp_banks, 515 erp_table->aregion->type, 516 &erp_table->base_index); 517 if (err) 518 return err; 519 erp_table->num_max_atcam_erps = erp_core->num_erp_banks; 520 521 /* Transition the sole RP currently configured (the master RP) 522 * to the eRP table 523 */ 524 master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table); 525 if (!master_rp) { 526 err = -EINVAL; 527 goto err_table_master_rp; 528 } 529 530 /* Maintain the same eRP bank for the master RP, so that we 531 * wouldn't need to update the bloom filter 532 */ 533 master_rp->index = master_rp->index % erp_core->num_erp_banks; 534 __set_bit(master_rp->index, erp_table->erp_index_bitmap); 535 536 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, master_rp); 537 if (err) 538 goto err_table_master_rp_add; 539 540 err = mlxsw_sp_acl_erp_table_enable(erp_table, false); 541 if (err) 542 goto err_table_enable; 543 544 return 0; 545 546 err_table_enable: 547 mlxsw_sp_acl_erp_table_erp_del(master_rp); 548 err_table_master_rp_add: 549 __clear_bit(master_rp->index, erp_table->erp_index_bitmap); 550 err_table_master_rp: 551 mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps, 552 erp_table->aregion->type, 553 erp_table->base_index); 554 return err; 555 } 556 557 static void 558 mlxsw_sp_acl_erp_region_master_mask_trans(struct mlxsw_sp_acl_erp_table *erp_table) 559 { 560 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core; 561 struct mlxsw_sp_acl_erp *master_rp; 562 563 mlxsw_sp_acl_erp_table_disable(erp_table); 564 master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table); 565 if (!master_rp) 566 return; 567 mlxsw_sp_acl_erp_table_erp_del(master_rp); 568 __clear_bit(master_rp->index, erp_table->erp_index_bitmap); 569 mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps, 570 erp_table->aregion->type, 571 erp_table->base_index); 572 } 573 574 static int 575 mlxsw_sp_acl_erp_region_erp_add(struct mlxsw_sp_acl_erp_table *erp_table, 576 struct mlxsw_sp_acl_erp *erp) 577 { 578 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region; 579 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 580 bool ctcam_le = erp_table->num_ctcam_erps > 0; 581 char pererp_pl[MLXSW_REG_PERERP_LEN]; 582 583 mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0, 584 erp_table->base_index, 0); 585 mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap, 586 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 587 mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, true); 588 589 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl); 590 } 591 592 static void mlxsw_sp_acl_erp_region_erp_del(struct mlxsw_sp_acl_erp *erp) 593 { 594 struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table; 595 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region; 596 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp; 597 bool ctcam_le = erp_table->num_ctcam_erps > 0; 598 char pererp_pl[MLXSW_REG_PERERP_LEN]; 599 600 mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0, 601 erp_table->base_index, 0); 602 mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap, 603 MLXSW_SP_ACL_ERP_MAX_PER_REGION); 604 mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, false); 605 606 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl); 607 } 608 609 static int 610 mlxsw_sp_acl_erp_region_ctcam_enable(struct mlxsw_sp_acl_erp_table *erp_table) 611 { 612 /* No need to re-enable lookup in the C-TCAM */ 613 if (erp_table->num_ctcam_erps > 1) 614 return 0; 615 616 return mlxsw_sp_acl_erp_table_enable(erp_table, true); 617 } 618 619 static void 620 mlxsw_sp_acl_erp_region_ctcam_disable(struct mlxsw_sp_acl_erp_table *erp_table) 621 { 622 /* Only disable C-TCAM lookup when last C-TCAM eRP is deleted */ 623 if (erp_table->num_ctcam_erps > 1) 624 return; 625 626 mlxsw_sp_acl_erp_table_enable(erp_table, false); 627 } 628 629 static int 630 __mlxsw_sp_acl_erp_table_other_inc(struct mlxsw_sp_acl_erp_table *erp_table, 631 unsigned int *inc_num) 632 { 633 int err; 634 635 /* If there are C-TCAM eRP or deltas in use we need to transition 636 * the region to use eRP table, if it is not already done 637 */ 638 if (erp_table->ops != &erp_two_masks_ops && 639 erp_table->ops != &erp_multiple_masks_ops) { 640 err = mlxsw_sp_acl_erp_region_table_trans(erp_table); 641 if (err) 642 return err; 643 } 644 645 /* When C-TCAM or deltas are used, the eRP table must be used */ 646 if (erp_table->ops != &erp_multiple_masks_ops) 647 erp_table->ops = &erp_multiple_masks_ops; 648 649 (*inc_num)++; 650 651 return 0; 652 } 653 654 static int mlxsw_sp_acl_erp_ctcam_inc(struct mlxsw_sp_acl_erp_table *erp_table) 655 { 656 return __mlxsw_sp_acl_erp_table_other_inc(erp_table, 657 &erp_table->num_ctcam_erps); 658 } 659 660 static int mlxsw_sp_acl_erp_delta_inc(struct mlxsw_sp_acl_erp_table *erp_table) 661 { 662 return __mlxsw_sp_acl_erp_table_other_inc(erp_table, 663 &erp_table->num_deltas); 664 } 665 666 static void 667 __mlxsw_sp_acl_erp_table_other_dec(struct mlxsw_sp_acl_erp_table *erp_table, 668 unsigned int *dec_num) 669 { 670 (*dec_num)--; 671 672 /* If there are no C-TCAM eRP or deltas in use, the state we 673 * transition to depends on the number of A-TCAM eRPs currently 674 * in use. 675 */ 676 if (erp_table->num_ctcam_erps > 0 || erp_table->num_deltas > 0) 677 return; 678 679 switch (erp_table->num_atcam_erps) { 680 case 2: 681 /* Keep using the eRP table, but correctly set the 682 * operations pointer so that when an A-TCAM eRP is 683 * deleted we will transition to use the master mask 684 */ 685 erp_table->ops = &erp_two_masks_ops; 686 break; 687 case 1: 688 /* We only kept the eRP table because we had C-TCAM 689 * eRPs in use. Now that the last C-TCAM eRP is gone we 690 * can stop using the table and transition to use the 691 * master mask 692 */ 693 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table); 694 erp_table->ops = &erp_single_mask_ops; 695 break; 696 case 0: 697 /* There are no more eRPs of any kind used by the region 698 * so free its eRP table and transition to initial state 699 */ 700 mlxsw_sp_acl_erp_table_disable(erp_table); 701 mlxsw_sp_acl_erp_table_free(erp_table->erp_core, 702 erp_table->num_max_atcam_erps, 703 erp_table->aregion->type, 704 erp_table->base_index); 705 erp_table->ops = &erp_no_mask_ops; 706 break; 707 default: 708 break; 709 } 710 } 711 712 static void mlxsw_sp_acl_erp_ctcam_dec(struct mlxsw_sp_acl_erp_table *erp_table) 713 { 714 __mlxsw_sp_acl_erp_table_other_dec(erp_table, 715 &erp_table->num_ctcam_erps); 716 } 717 718 static void mlxsw_sp_acl_erp_delta_dec(struct mlxsw_sp_acl_erp_table *erp_table) 719 { 720 __mlxsw_sp_acl_erp_table_other_dec(erp_table, 721 &erp_table->num_deltas); 722 } 723 724 static struct mlxsw_sp_acl_erp * 725 mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 726 struct mlxsw_sp_acl_erp_key *key) 727 { 728 struct mlxsw_sp_acl_erp *erp; 729 int err; 730 731 erp = kzalloc(sizeof(*erp), GFP_KERNEL); 732 if (!erp) 733 return ERR_PTR(-ENOMEM); 734 735 memcpy(&erp->key, key, sizeof(*key)); 736 bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask, 737 MLXSW_SP_ACL_TCAM_MASK_LEN); 738 739 err = mlxsw_sp_acl_erp_ctcam_inc(erp_table); 740 if (err) 741 goto err_erp_ctcam_inc; 742 743 erp->erp_table = erp_table; 744 745 err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key); 746 if (err) 747 goto err_master_mask_set; 748 749 err = mlxsw_sp_acl_erp_region_ctcam_enable(erp_table); 750 if (err) 751 goto err_erp_region_ctcam_enable; 752 753 return erp; 754 755 err_erp_region_ctcam_enable: 756 mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key); 757 err_master_mask_set: 758 mlxsw_sp_acl_erp_ctcam_dec(erp_table); 759 err_erp_ctcam_inc: 760 kfree(erp); 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 mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key); 771 mlxsw_sp_acl_erp_ctcam_dec(erp_table); 772 kfree(erp); 773 } 774 775 static struct mlxsw_sp_acl_erp * 776 mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 777 struct mlxsw_sp_acl_erp_key *key) 778 { 779 struct mlxsw_sp_acl_erp *erp; 780 int err; 781 782 if (key->ctcam) 783 return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key); 784 785 /* Expand the eRP table for the new eRP, if needed */ 786 err = mlxsw_sp_acl_erp_table_expand(erp_table); 787 if (err) 788 return ERR_PTR(err); 789 790 erp = mlxsw_sp_acl_erp_generic_create(erp_table, key); 791 if (IS_ERR(erp)) 792 return erp; 793 794 err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index); 795 if (err) 796 goto err_erp_index_get; 797 798 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp); 799 if (err) 800 goto err_table_erp_add; 801 802 err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp); 803 if (err) 804 goto err_region_erp_add; 805 806 erp_table->ops = &erp_multiple_masks_ops; 807 808 return erp; 809 810 err_region_erp_add: 811 mlxsw_sp_acl_erp_table_erp_del(erp); 812 err_table_erp_add: 813 mlxsw_sp_acl_erp_index_put(erp_table, erp->index); 814 err_erp_index_get: 815 mlxsw_sp_acl_erp_generic_destroy(erp); 816 return ERR_PTR(err); 817 } 818 819 static void 820 mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 821 struct mlxsw_sp_acl_erp *erp) 822 { 823 if (erp->key.ctcam) 824 return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp); 825 826 mlxsw_sp_acl_erp_region_erp_del(erp); 827 mlxsw_sp_acl_erp_table_erp_del(erp); 828 mlxsw_sp_acl_erp_index_put(erp_table, erp->index); 829 mlxsw_sp_acl_erp_generic_destroy(erp); 830 831 if (erp_table->num_atcam_erps == 2 && erp_table->num_ctcam_erps == 0 && 832 erp_table->num_deltas == 0) 833 erp_table->ops = &erp_two_masks_ops; 834 } 835 836 static struct mlxsw_sp_acl_erp * 837 mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 838 struct mlxsw_sp_acl_erp_key *key) 839 { 840 struct mlxsw_sp_acl_erp *erp; 841 int err; 842 843 if (key->ctcam) 844 return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key); 845 846 /* Transition to use eRP table instead of master mask */ 847 err = mlxsw_sp_acl_erp_region_table_trans(erp_table); 848 if (err) 849 return ERR_PTR(err); 850 851 erp = mlxsw_sp_acl_erp_generic_create(erp_table, key); 852 if (IS_ERR(erp)) { 853 err = PTR_ERR(erp); 854 goto err_erp_create; 855 } 856 857 err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index); 858 if (err) 859 goto err_erp_index_get; 860 861 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp); 862 if (err) 863 goto err_table_erp_add; 864 865 err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp); 866 if (err) 867 goto err_region_erp_add; 868 869 erp_table->ops = &erp_two_masks_ops; 870 871 return erp; 872 873 err_region_erp_add: 874 mlxsw_sp_acl_erp_table_erp_del(erp); 875 err_table_erp_add: 876 mlxsw_sp_acl_erp_index_put(erp_table, erp->index); 877 err_erp_index_get: 878 mlxsw_sp_acl_erp_generic_destroy(erp); 879 err_erp_create: 880 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table); 881 return ERR_PTR(err); 882 } 883 884 static void 885 mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 886 struct mlxsw_sp_acl_erp *erp) 887 { 888 if (erp->key.ctcam) 889 return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp); 890 891 mlxsw_sp_acl_erp_region_erp_del(erp); 892 mlxsw_sp_acl_erp_table_erp_del(erp); 893 mlxsw_sp_acl_erp_index_put(erp_table, erp->index); 894 mlxsw_sp_acl_erp_generic_destroy(erp); 895 /* Transition to use master mask instead of eRP table */ 896 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table); 897 898 erp_table->ops = &erp_single_mask_ops; 899 } 900 901 static struct mlxsw_sp_acl_erp * 902 mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, 903 struct mlxsw_sp_acl_erp_key *key) 904 { 905 struct mlxsw_sp_acl_erp *erp; 906 907 if (key->ctcam) 908 return ERR_PTR(-EINVAL); 909 910 erp = mlxsw_sp_acl_erp_generic_create(erp_table, key); 911 if (IS_ERR(erp)) 912 return erp; 913 914 erp_table->ops = &erp_single_mask_ops; 915 916 return erp; 917 } 918 919 static void 920 mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 921 struct mlxsw_sp_acl_erp *erp) 922 { 923 mlxsw_sp_acl_erp_generic_destroy(erp); 924 erp_table->ops = &erp_no_mask_ops; 925 } 926 927 static void 928 mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table, 929 struct mlxsw_sp_acl_erp *erp) 930 { 931 WARN_ON(1); 932 } 933 934 struct mlxsw_sp_acl_erp_mask * 935 mlxsw_sp_acl_erp_mask_get(struct mlxsw_sp_acl_atcam_region *aregion, 936 const char *mask, bool ctcam) 937 { 938 struct mlxsw_sp_acl_erp_key key; 939 struct objagg_obj *objagg_obj; 940 941 /* eRPs are allocated from a shared resource, but currently all 942 * allocations are done under RTNL. 943 */ 944 ASSERT_RTNL(); 945 946 memcpy(key.mask, mask, MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN); 947 key.ctcam = ctcam; 948 objagg_obj = objagg_obj_get(aregion->erp_table->objagg, &key); 949 if (IS_ERR(objagg_obj)) 950 return ERR_CAST(objagg_obj); 951 return (struct mlxsw_sp_acl_erp_mask *) objagg_obj; 952 } 953 954 void mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region *aregion, 955 struct mlxsw_sp_acl_erp_mask *erp_mask) 956 { 957 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask; 958 959 ASSERT_RTNL(); 960 objagg_obj_put(aregion->erp_table->objagg, objagg_obj); 961 } 962 963 bool 964 mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask *erp_mask) 965 { 966 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask; 967 const struct mlxsw_sp_acl_erp_key *key = objagg_obj_raw(objagg_obj); 968 969 return key->ctcam; 970 } 971 972 u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask) 973 { 974 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask; 975 const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj); 976 977 return erp->id; 978 } 979 980 struct mlxsw_sp_acl_erp_delta { 981 struct mlxsw_sp_acl_erp_key key; 982 u16 start; 983 u8 mask; 984 }; 985 986 u16 mlxsw_sp_acl_erp_delta_start(const struct mlxsw_sp_acl_erp_delta *delta) 987 { 988 return delta->start; 989 } 990 991 u8 mlxsw_sp_acl_erp_delta_mask(const struct mlxsw_sp_acl_erp_delta *delta) 992 { 993 return delta->mask; 994 } 995 996 u8 mlxsw_sp_acl_erp_delta_value(const struct mlxsw_sp_acl_erp_delta *delta, 997 const char *enc_key) 998 { 999 u16 start = delta->start; 1000 u8 mask = delta->mask; 1001 u16 tmp; 1002 1003 if (!mask) 1004 return 0; 1005 1006 tmp = (unsigned char) enc_key[__MASK_IDX(start / 8)]; 1007 if (start / 8 + 1 < __MASK_LEN) 1008 tmp |= (unsigned char) enc_key[__MASK_IDX(start / 8 + 1)] << 8; 1009 tmp >>= start % 8; 1010 tmp &= mask; 1011 return tmp; 1012 } 1013 1014 void mlxsw_sp_acl_erp_delta_clear(const struct mlxsw_sp_acl_erp_delta *delta, 1015 const char *enc_key) 1016 { 1017 u16 start = delta->start; 1018 u8 mask = delta->mask; 1019 unsigned char *byte; 1020 u16 tmp; 1021 1022 tmp = mask; 1023 tmp <<= start % 8; 1024 tmp = ~tmp; 1025 1026 byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8)]; 1027 *byte &= tmp & 0xff; 1028 if (start / 8 + 1 < __MASK_LEN) { 1029 byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8 + 1)]; 1030 *byte &= (tmp >> 8) & 0xff; 1031 } 1032 } 1033 1034 static const struct mlxsw_sp_acl_erp_delta 1035 mlxsw_sp_acl_erp_delta_default = {}; 1036 1037 const struct mlxsw_sp_acl_erp_delta * 1038 mlxsw_sp_acl_erp_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask) 1039 { 1040 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask; 1041 const struct mlxsw_sp_acl_erp_delta *delta; 1042 1043 delta = objagg_obj_delta_priv(objagg_obj); 1044 if (!delta) 1045 delta = &mlxsw_sp_acl_erp_delta_default; 1046 return delta; 1047 } 1048 1049 static int 1050 mlxsw_sp_acl_erp_delta_fill(const struct mlxsw_sp_acl_erp_key *parent_key, 1051 const struct mlxsw_sp_acl_erp_key *key, 1052 u16 *delta_start, u8 *delta_mask) 1053 { 1054 int offset = 0; 1055 int si = -1; 1056 u16 pmask; 1057 u16 mask; 1058 int i; 1059 1060 /* The difference between 2 masks can be up to 8 consecutive bits. */ 1061 for (i = 0; i < __MASK_LEN; i++) { 1062 if (parent_key->mask[__MASK_IDX(i)] == key->mask[__MASK_IDX(i)]) 1063 continue; 1064 if (si == -1) 1065 si = i; 1066 else if (si != i - 1) 1067 return -EINVAL; 1068 } 1069 if (si == -1) { 1070 /* The masks are the same, this cannot happen. 1071 * That means the caller is broken. 1072 */ 1073 WARN_ON(1); 1074 *delta_start = 0; 1075 *delta_mask = 0; 1076 return 0; 1077 } 1078 pmask = (unsigned char) parent_key->mask[__MASK_IDX(si)]; 1079 mask = (unsigned char) key->mask[__MASK_IDX(si)]; 1080 if (si + 1 < __MASK_LEN) { 1081 pmask |= (unsigned char) parent_key->mask[__MASK_IDX(si + 1)] << 8; 1082 mask |= (unsigned char) key->mask[__MASK_IDX(si + 1)] << 8; 1083 } 1084 1085 if ((pmask ^ mask) & pmask) 1086 return -EINVAL; 1087 mask &= ~pmask; 1088 while (!(mask & (1 << offset))) 1089 offset++; 1090 while (!(mask & 1)) 1091 mask >>= 1; 1092 if (mask & 0xff00) 1093 return -EINVAL; 1094 1095 *delta_start = si * 8 + offset; 1096 *delta_mask = mask; 1097 1098 return 0; 1099 } 1100 1101 static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj, 1102 void *obj) 1103 { 1104 struct mlxsw_sp_acl_erp_key *parent_key = parent_obj; 1105 struct mlxsw_sp_acl_atcam_region *aregion = priv; 1106 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; 1107 struct mlxsw_sp_acl_erp_key *key = obj; 1108 struct mlxsw_sp_acl_erp_delta *delta; 1109 u16 delta_start; 1110 u8 delta_mask; 1111 int err; 1112 1113 if (parent_key->ctcam || key->ctcam) 1114 return ERR_PTR(-EINVAL); 1115 err = mlxsw_sp_acl_erp_delta_fill(parent_key, key, 1116 &delta_start, &delta_mask); 1117 if (err) 1118 return ERR_PTR(-EINVAL); 1119 1120 delta = kzalloc(sizeof(*delta), GFP_KERNEL); 1121 if (!delta) 1122 return ERR_PTR(-ENOMEM); 1123 delta->start = delta_start; 1124 delta->mask = delta_mask; 1125 1126 err = mlxsw_sp_acl_erp_delta_inc(erp_table); 1127 if (err) 1128 goto err_erp_delta_inc; 1129 1130 memcpy(&delta->key, key, sizeof(*key)); 1131 err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &delta->key); 1132 if (err) 1133 goto err_master_mask_set; 1134 1135 return delta; 1136 1137 err_master_mask_set: 1138 mlxsw_sp_acl_erp_delta_dec(erp_table); 1139 err_erp_delta_inc: 1140 kfree(delta); 1141 return ERR_PTR(err); 1142 } 1143 1144 static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv) 1145 { 1146 struct mlxsw_sp_acl_erp_delta *delta = delta_priv; 1147 struct mlxsw_sp_acl_atcam_region *aregion = priv; 1148 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; 1149 1150 mlxsw_sp_acl_erp_master_mask_clear(erp_table, &delta->key); 1151 mlxsw_sp_acl_erp_delta_dec(erp_table); 1152 kfree(delta); 1153 } 1154 1155 static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj) 1156 { 1157 struct mlxsw_sp_acl_atcam_region *aregion = priv; 1158 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; 1159 struct mlxsw_sp_acl_erp_key *key = obj; 1160 1161 return erp_table->ops->erp_create(erp_table, key); 1162 } 1163 1164 static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv) 1165 { 1166 struct mlxsw_sp_acl_atcam_region *aregion = priv; 1167 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; 1168 1169 erp_table->ops->erp_destroy(erp_table, root_priv); 1170 } 1171 1172 static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = { 1173 .obj_size = sizeof(struct mlxsw_sp_acl_erp_key), 1174 .delta_create = mlxsw_sp_acl_erp_delta_create, 1175 .delta_destroy = mlxsw_sp_acl_erp_delta_destroy, 1176 .root_create = mlxsw_sp_acl_erp_root_create, 1177 .root_destroy = mlxsw_sp_acl_erp_root_destroy, 1178 }; 1179 1180 static struct mlxsw_sp_acl_erp_table * 1181 mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion) 1182 { 1183 struct mlxsw_sp_acl_erp_table *erp_table; 1184 int err; 1185 1186 erp_table = kzalloc(sizeof(*erp_table), GFP_KERNEL); 1187 if (!erp_table) 1188 return ERR_PTR(-ENOMEM); 1189 1190 erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops, 1191 aregion); 1192 if (IS_ERR(erp_table->objagg)) { 1193 err = PTR_ERR(erp_table->objagg); 1194 goto err_objagg_create; 1195 } 1196 1197 erp_table->erp_core = aregion->atcam->erp_core; 1198 erp_table->ops = &erp_no_mask_ops; 1199 INIT_LIST_HEAD(&erp_table->atcam_erps_list); 1200 erp_table->aregion = aregion; 1201 1202 return erp_table; 1203 1204 err_objagg_create: 1205 kfree(erp_table); 1206 return ERR_PTR(err); 1207 } 1208 1209 static void 1210 mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table *erp_table) 1211 { 1212 WARN_ON(!list_empty(&erp_table->atcam_erps_list)); 1213 objagg_destroy(erp_table->objagg); 1214 kfree(erp_table); 1215 } 1216 1217 static int 1218 mlxsw_sp_acl_erp_master_mask_init(struct mlxsw_sp_acl_atcam_region *aregion) 1219 { 1220 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp; 1221 char percr_pl[MLXSW_REG_PERCR_LEN]; 1222 1223 mlxsw_reg_percr_pack(percr_pl, aregion->region->id); 1224 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl); 1225 } 1226 1227 static int 1228 mlxsw_sp_acl_erp_region_param_init(struct mlxsw_sp_acl_atcam_region *aregion) 1229 { 1230 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp; 1231 char pererp_pl[MLXSW_REG_PERERP_LEN]; 1232 1233 mlxsw_reg_pererp_pack(pererp_pl, aregion->region->id, false, false, 0, 1234 0, 0); 1235 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl); 1236 } 1237 1238 int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion) 1239 { 1240 struct mlxsw_sp_acl_erp_table *erp_table; 1241 int err; 1242 1243 erp_table = mlxsw_sp_acl_erp_table_create(aregion); 1244 if (IS_ERR(erp_table)) 1245 return PTR_ERR(erp_table); 1246 aregion->erp_table = erp_table; 1247 1248 /* Initialize the region's master mask to all zeroes */ 1249 err = mlxsw_sp_acl_erp_master_mask_init(aregion); 1250 if (err) 1251 goto err_erp_master_mask_init; 1252 1253 /* Initialize the region to not use the eRP table */ 1254 err = mlxsw_sp_acl_erp_region_param_init(aregion); 1255 if (err) 1256 goto err_erp_region_param_init; 1257 1258 return 0; 1259 1260 err_erp_region_param_init: 1261 err_erp_master_mask_init: 1262 mlxsw_sp_acl_erp_table_destroy(erp_table); 1263 return err; 1264 } 1265 1266 void mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region *aregion) 1267 { 1268 mlxsw_sp_acl_erp_table_destroy(aregion->erp_table); 1269 } 1270 1271 static int 1272 mlxsw_sp_acl_erp_tables_sizes_query(struct mlxsw_sp *mlxsw_sp, 1273 struct mlxsw_sp_acl_erp_core *erp_core) 1274 { 1275 unsigned int size; 1276 1277 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB) || 1278 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB) || 1279 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB) || 1280 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB)) 1281 return -EIO; 1282 1283 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB); 1284 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] = size; 1285 1286 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB); 1287 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] = size; 1288 1289 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB); 1290 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] = size; 1291 1292 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB); 1293 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] = size; 1294 1295 return 0; 1296 } 1297 1298 static int mlxsw_sp_acl_erp_tables_init(struct mlxsw_sp *mlxsw_sp, 1299 struct mlxsw_sp_acl_erp_core *erp_core) 1300 { 1301 unsigned int erpt_bank_size; 1302 int err; 1303 1304 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANK_SIZE) || 1305 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANKS)) 1306 return -EIO; 1307 erpt_bank_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, 1308 ACL_MAX_ERPT_BANK_SIZE); 1309 erp_core->num_erp_banks = MLXSW_CORE_RES_GET(mlxsw_sp->core, 1310 ACL_MAX_ERPT_BANKS); 1311 1312 erp_core->erp_tables = gen_pool_create(0, -1); 1313 if (!erp_core->erp_tables) 1314 return -ENOMEM; 1315 gen_pool_set_algo(erp_core->erp_tables, gen_pool_best_fit, NULL); 1316 1317 err = gen_pool_add(erp_core->erp_tables, 1318 MLXSW_SP_ACL_ERP_GENALLOC_OFFSET, erpt_bank_size, 1319 -1); 1320 if (err) 1321 goto err_gen_pool_add; 1322 1323 /* Different regions require masks of different sizes */ 1324 err = mlxsw_sp_acl_erp_tables_sizes_query(mlxsw_sp, erp_core); 1325 if (err) 1326 goto err_erp_tables_sizes_query; 1327 1328 return 0; 1329 1330 err_erp_tables_sizes_query: 1331 err_gen_pool_add: 1332 gen_pool_destroy(erp_core->erp_tables); 1333 return err; 1334 } 1335 1336 static void mlxsw_sp_acl_erp_tables_fini(struct mlxsw_sp *mlxsw_sp, 1337 struct mlxsw_sp_acl_erp_core *erp_core) 1338 { 1339 gen_pool_destroy(erp_core->erp_tables); 1340 } 1341 1342 int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp, 1343 struct mlxsw_sp_acl_atcam *atcam) 1344 { 1345 struct mlxsw_sp_acl_erp_core *erp_core; 1346 int err; 1347 1348 erp_core = kzalloc(sizeof(*erp_core), GFP_KERNEL); 1349 if (!erp_core) 1350 return -ENOMEM; 1351 erp_core->mlxsw_sp = mlxsw_sp; 1352 atcam->erp_core = erp_core; 1353 1354 err = mlxsw_sp_acl_erp_tables_init(mlxsw_sp, erp_core); 1355 if (err) 1356 goto err_erp_tables_init; 1357 1358 return 0; 1359 1360 err_erp_tables_init: 1361 kfree(erp_core); 1362 return err; 1363 } 1364 1365 void mlxsw_sp_acl_erps_fini(struct mlxsw_sp *mlxsw_sp, 1366 struct mlxsw_sp_acl_atcam *atcam) 1367 { 1368 mlxsw_sp_acl_erp_tables_fini(mlxsw_sp, atcam->erp_core); 1369 kfree(atcam->erp_core); 1370 } 1371