1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */ 3 4 #include <linux/kernel.h> 5 #include <linux/err.h> 6 #include <linux/errno.h> 7 #include <linux/gfp.h> 8 #include <linux/refcount.h> 9 #include <linux/rhashtable.h> 10 #define CREATE_TRACE_POINTS 11 #include <trace/events/mlxsw.h> 12 13 #include "reg.h" 14 #include "core.h" 15 #include "spectrum.h" 16 #include "spectrum_acl_tcam.h" 17 #include "core_acl_flex_keys.h" 18 19 #define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_START 0 20 #define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_END 5 21 22 struct mlxsw_sp_acl_atcam_lkey_id_ht_key { 23 char enc_key[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN]; /* MSB blocks */ 24 u8 erp_id; 25 }; 26 27 struct mlxsw_sp_acl_atcam_lkey_id { 28 struct rhash_head ht_node; 29 struct mlxsw_sp_acl_atcam_lkey_id_ht_key ht_key; 30 refcount_t refcnt; 31 u32 id; 32 }; 33 34 struct mlxsw_sp_acl_atcam_region_ops { 35 int (*init)(struct mlxsw_sp_acl_atcam_region *aregion); 36 void (*fini)(struct mlxsw_sp_acl_atcam_region *aregion); 37 struct mlxsw_sp_acl_atcam_lkey_id * 38 (*lkey_id_get)(struct mlxsw_sp_acl_atcam_region *aregion, 39 char *enc_key, u8 erp_id); 40 void (*lkey_id_put)(struct mlxsw_sp_acl_atcam_region *aregion, 41 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id); 42 }; 43 44 struct mlxsw_sp_acl_atcam_region_generic { 45 struct mlxsw_sp_acl_atcam_lkey_id dummy_lkey_id; 46 }; 47 48 struct mlxsw_sp_acl_atcam_region_12kb { 49 struct rhashtable lkey_ht; 50 unsigned int max_lkey_id; 51 unsigned long *used_lkey_id; 52 }; 53 54 static const struct rhashtable_params mlxsw_sp_acl_atcam_lkey_id_ht_params = { 55 .key_len = sizeof(struct mlxsw_sp_acl_atcam_lkey_id_ht_key), 56 .key_offset = offsetof(struct mlxsw_sp_acl_atcam_lkey_id, ht_key), 57 .head_offset = offsetof(struct mlxsw_sp_acl_atcam_lkey_id, ht_node), 58 }; 59 60 static const struct rhashtable_params mlxsw_sp_acl_atcam_entries_ht_params = { 61 .key_len = sizeof(struct mlxsw_sp_acl_atcam_entry_ht_key), 62 .key_offset = offsetof(struct mlxsw_sp_acl_atcam_entry, ht_key), 63 .head_offset = offsetof(struct mlxsw_sp_acl_atcam_entry, ht_node), 64 }; 65 66 static bool 67 mlxsw_sp_acl_atcam_is_centry(const struct mlxsw_sp_acl_atcam_entry *aentry) 68 { 69 return mlxsw_sp_acl_erp_mask_is_ctcam(aentry->erp_mask); 70 } 71 72 static int 73 mlxsw_sp_acl_atcam_region_generic_init(struct mlxsw_sp_acl_atcam_region *aregion) 74 { 75 struct mlxsw_sp_acl_atcam_region_generic *region_generic; 76 77 region_generic = kzalloc(sizeof(*region_generic), GFP_KERNEL); 78 if (!region_generic) 79 return -ENOMEM; 80 81 refcount_set(®ion_generic->dummy_lkey_id.refcnt, 1); 82 aregion->priv = region_generic; 83 84 return 0; 85 } 86 87 static void 88 mlxsw_sp_acl_atcam_region_generic_fini(struct mlxsw_sp_acl_atcam_region *aregion) 89 { 90 kfree(aregion->priv); 91 } 92 93 static struct mlxsw_sp_acl_atcam_lkey_id * 94 mlxsw_sp_acl_atcam_generic_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion, 95 char *enc_key, u8 erp_id) 96 { 97 struct mlxsw_sp_acl_atcam_region_generic *region_generic; 98 99 region_generic = aregion->priv; 100 return ®ion_generic->dummy_lkey_id; 101 } 102 103 static void 104 mlxsw_sp_acl_atcam_generic_lkey_id_put(struct mlxsw_sp_acl_atcam_region *aregion, 105 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id) 106 { 107 } 108 109 static const struct mlxsw_sp_acl_atcam_region_ops 110 mlxsw_sp_acl_atcam_region_generic_ops = { 111 .init = mlxsw_sp_acl_atcam_region_generic_init, 112 .fini = mlxsw_sp_acl_atcam_region_generic_fini, 113 .lkey_id_get = mlxsw_sp_acl_atcam_generic_lkey_id_get, 114 .lkey_id_put = mlxsw_sp_acl_atcam_generic_lkey_id_put, 115 }; 116 117 static int 118 mlxsw_sp_acl_atcam_region_12kb_init(struct mlxsw_sp_acl_atcam_region *aregion) 119 { 120 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp; 121 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb; 122 size_t alloc_size; 123 u64 max_lkey_id; 124 int err; 125 126 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_LARGE_KEY_ID)) 127 return -EIO; 128 129 max_lkey_id = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_LARGE_KEY_ID); 130 region_12kb = kzalloc(sizeof(*region_12kb), GFP_KERNEL); 131 if (!region_12kb) 132 return -ENOMEM; 133 134 alloc_size = BITS_TO_LONGS(max_lkey_id) * sizeof(unsigned long); 135 region_12kb->used_lkey_id = kzalloc(alloc_size, GFP_KERNEL); 136 if (!region_12kb->used_lkey_id) { 137 err = -ENOMEM; 138 goto err_used_lkey_id_alloc; 139 } 140 141 err = rhashtable_init(®ion_12kb->lkey_ht, 142 &mlxsw_sp_acl_atcam_lkey_id_ht_params); 143 if (err) 144 goto err_rhashtable_init; 145 146 region_12kb->max_lkey_id = max_lkey_id; 147 aregion->priv = region_12kb; 148 149 return 0; 150 151 err_rhashtable_init: 152 kfree(region_12kb->used_lkey_id); 153 err_used_lkey_id_alloc: 154 kfree(region_12kb); 155 return err; 156 } 157 158 static void 159 mlxsw_sp_acl_atcam_region_12kb_fini(struct mlxsw_sp_acl_atcam_region *aregion) 160 { 161 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv; 162 163 rhashtable_destroy(®ion_12kb->lkey_ht); 164 kfree(region_12kb->used_lkey_id); 165 kfree(region_12kb); 166 } 167 168 static struct mlxsw_sp_acl_atcam_lkey_id * 169 mlxsw_sp_acl_atcam_lkey_id_create(struct mlxsw_sp_acl_atcam_region *aregion, 170 struct mlxsw_sp_acl_atcam_lkey_id_ht_key *ht_key) 171 { 172 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv; 173 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id; 174 u32 id; 175 int err; 176 177 id = find_first_zero_bit(region_12kb->used_lkey_id, 178 region_12kb->max_lkey_id); 179 if (id < region_12kb->max_lkey_id) 180 __set_bit(id, region_12kb->used_lkey_id); 181 else 182 return ERR_PTR(-ENOBUFS); 183 184 lkey_id = kzalloc(sizeof(*lkey_id), GFP_KERNEL); 185 if (!lkey_id) { 186 err = -ENOMEM; 187 goto err_lkey_id_alloc; 188 } 189 190 lkey_id->id = id; 191 memcpy(&lkey_id->ht_key, ht_key, sizeof(*ht_key)); 192 refcount_set(&lkey_id->refcnt, 1); 193 194 err = rhashtable_insert_fast(®ion_12kb->lkey_ht, 195 &lkey_id->ht_node, 196 mlxsw_sp_acl_atcam_lkey_id_ht_params); 197 if (err) 198 goto err_rhashtable_insert; 199 200 return lkey_id; 201 202 err_rhashtable_insert: 203 kfree(lkey_id); 204 err_lkey_id_alloc: 205 __clear_bit(id, region_12kb->used_lkey_id); 206 return ERR_PTR(err); 207 } 208 209 static void 210 mlxsw_sp_acl_atcam_lkey_id_destroy(struct mlxsw_sp_acl_atcam_region *aregion, 211 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id) 212 { 213 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv; 214 u32 id = lkey_id->id; 215 216 rhashtable_remove_fast(®ion_12kb->lkey_ht, &lkey_id->ht_node, 217 mlxsw_sp_acl_atcam_lkey_id_ht_params); 218 kfree(lkey_id); 219 __clear_bit(id, region_12kb->used_lkey_id); 220 } 221 222 static struct mlxsw_sp_acl_atcam_lkey_id * 223 mlxsw_sp_acl_atcam_12kb_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion, 224 char *enc_key, u8 erp_id) 225 { 226 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv; 227 struct mlxsw_sp_acl_tcam_region *region = aregion->region; 228 struct mlxsw_sp_acl_atcam_lkey_id_ht_key ht_key = {{ 0 } }; 229 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp; 230 struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl); 231 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id; 232 233 memcpy(ht_key.enc_key, enc_key, sizeof(ht_key.enc_key)); 234 mlxsw_afk_clear(afk, ht_key.enc_key, 235 MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_START, 236 MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_END); 237 ht_key.erp_id = erp_id; 238 lkey_id = rhashtable_lookup_fast(®ion_12kb->lkey_ht, &ht_key, 239 mlxsw_sp_acl_atcam_lkey_id_ht_params); 240 if (lkey_id) { 241 refcount_inc(&lkey_id->refcnt); 242 return lkey_id; 243 } 244 245 return mlxsw_sp_acl_atcam_lkey_id_create(aregion, &ht_key); 246 } 247 248 static void 249 mlxsw_sp_acl_atcam_12kb_lkey_id_put(struct mlxsw_sp_acl_atcam_region *aregion, 250 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id) 251 { 252 if (refcount_dec_and_test(&lkey_id->refcnt)) 253 mlxsw_sp_acl_atcam_lkey_id_destroy(aregion, lkey_id); 254 } 255 256 static const struct mlxsw_sp_acl_atcam_region_ops 257 mlxsw_sp_acl_atcam_region_12kb_ops = { 258 .init = mlxsw_sp_acl_atcam_region_12kb_init, 259 .fini = mlxsw_sp_acl_atcam_region_12kb_fini, 260 .lkey_id_get = mlxsw_sp_acl_atcam_12kb_lkey_id_get, 261 .lkey_id_put = mlxsw_sp_acl_atcam_12kb_lkey_id_put, 262 }; 263 264 static const struct mlxsw_sp_acl_atcam_region_ops * 265 mlxsw_sp_acl_atcam_region_ops_arr[] = { 266 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] = 267 &mlxsw_sp_acl_atcam_region_generic_ops, 268 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] = 269 &mlxsw_sp_acl_atcam_region_generic_ops, 270 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] = 271 &mlxsw_sp_acl_atcam_region_generic_ops, 272 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] = 273 &mlxsw_sp_acl_atcam_region_12kb_ops, 274 }; 275 276 int mlxsw_sp_acl_atcam_region_associate(struct mlxsw_sp *mlxsw_sp, 277 u16 region_id) 278 { 279 char perar_pl[MLXSW_REG_PERAR_LEN]; 280 /* For now, just assume that every region has 12 key blocks */ 281 u16 hw_region = region_id * 3; 282 u64 max_regions; 283 284 max_regions = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_REGIONS); 285 if (hw_region >= max_regions) 286 return -ENOBUFS; 287 288 mlxsw_reg_perar_pack(perar_pl, region_id, hw_region); 289 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perar), perar_pl); 290 } 291 292 static void 293 mlxsw_sp_acl_atcam_region_type_init(struct mlxsw_sp_acl_atcam_region *aregion) 294 { 295 struct mlxsw_sp_acl_tcam_region *region = aregion->region; 296 enum mlxsw_sp_acl_atcam_region_type region_type; 297 unsigned int blocks_count; 298 299 /* We already know the blocks count can not exceed the maximum 300 * blocks count. 301 */ 302 blocks_count = mlxsw_afk_key_info_blocks_count_get(region->key_info); 303 if (blocks_count <= 2) 304 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB; 305 else if (blocks_count <= 4) 306 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB; 307 else if (blocks_count <= 8) 308 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB; 309 else 310 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB; 311 312 aregion->type = region_type; 313 aregion->ops = mlxsw_sp_acl_atcam_region_ops_arr[region_type]; 314 } 315 316 int 317 mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp, 318 struct mlxsw_sp_acl_atcam *atcam, 319 struct mlxsw_sp_acl_atcam_region *aregion, 320 struct mlxsw_sp_acl_tcam_region *region, 321 void *hints_priv, 322 const struct mlxsw_sp_acl_ctcam_region_ops *ops) 323 { 324 int err; 325 326 aregion->region = region; 327 aregion->atcam = atcam; 328 mlxsw_sp_acl_atcam_region_type_init(aregion); 329 INIT_LIST_HEAD(&aregion->entries_list); 330 331 err = rhashtable_init(&aregion->entries_ht, 332 &mlxsw_sp_acl_atcam_entries_ht_params); 333 if (err) 334 return err; 335 err = aregion->ops->init(aregion); 336 if (err) 337 goto err_ops_init; 338 err = mlxsw_sp_acl_erp_region_init(aregion, hints_priv); 339 if (err) 340 goto err_erp_region_init; 341 err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, &aregion->cregion, 342 region, ops); 343 if (err) 344 goto err_ctcam_region_init; 345 346 return 0; 347 348 err_ctcam_region_init: 349 mlxsw_sp_acl_erp_region_fini(aregion); 350 err_erp_region_init: 351 aregion->ops->fini(aregion); 352 err_ops_init: 353 rhashtable_destroy(&aregion->entries_ht); 354 return err; 355 } 356 357 void mlxsw_sp_acl_atcam_region_fini(struct mlxsw_sp_acl_atcam_region *aregion) 358 { 359 mlxsw_sp_acl_ctcam_region_fini(&aregion->cregion); 360 mlxsw_sp_acl_erp_region_fini(aregion); 361 aregion->ops->fini(aregion); 362 rhashtable_destroy(&aregion->entries_ht); 363 WARN_ON(!list_empty(&aregion->entries_list)); 364 } 365 366 void mlxsw_sp_acl_atcam_chunk_init(struct mlxsw_sp_acl_atcam_region *aregion, 367 struct mlxsw_sp_acl_atcam_chunk *achunk, 368 unsigned int priority) 369 { 370 mlxsw_sp_acl_ctcam_chunk_init(&aregion->cregion, &achunk->cchunk, 371 priority); 372 } 373 374 void mlxsw_sp_acl_atcam_chunk_fini(struct mlxsw_sp_acl_atcam_chunk *achunk) 375 { 376 mlxsw_sp_acl_ctcam_chunk_fini(&achunk->cchunk); 377 } 378 379 static int 380 mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp, 381 struct mlxsw_sp_acl_atcam_region *aregion, 382 struct mlxsw_sp_acl_atcam_entry *aentry, 383 struct mlxsw_sp_acl_rule_info *rulei) 384 { 385 struct mlxsw_sp_acl_tcam_region *region = aregion->region; 386 u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask); 387 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id; 388 char ptce3_pl[MLXSW_REG_PTCE3_LEN]; 389 u32 kvdl_index, priority; 390 int err; 391 392 err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, true); 393 if (err) 394 return err; 395 396 lkey_id = aregion->ops->lkey_id_get(aregion, aentry->enc_key, erp_id); 397 if (IS_ERR(lkey_id)) 398 return PTR_ERR(lkey_id); 399 aentry->lkey_id = lkey_id; 400 401 kvdl_index = mlxsw_afa_block_first_kvdl_index(rulei->act_block); 402 mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_WRITE, 403 priority, region->tcam_region_info, 404 aentry->enc_key, erp_id, 405 aentry->delta_info.start, 406 aentry->delta_info.mask, 407 aentry->delta_info.value, 408 refcount_read(&lkey_id->refcnt) != 1, lkey_id->id, 409 kvdl_index); 410 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl); 411 if (err) 412 goto err_ptce3_write; 413 414 return 0; 415 416 err_ptce3_write: 417 aregion->ops->lkey_id_put(aregion, lkey_id); 418 return err; 419 } 420 421 static void 422 mlxsw_sp_acl_atcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp, 423 struct mlxsw_sp_acl_atcam_region *aregion, 424 struct mlxsw_sp_acl_atcam_entry *aentry) 425 { 426 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id; 427 struct mlxsw_sp_acl_tcam_region *region = aregion->region; 428 u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask); 429 char ptce3_pl[MLXSW_REG_PTCE3_LEN]; 430 431 mlxsw_reg_ptce3_pack(ptce3_pl, false, MLXSW_REG_PTCE3_OP_WRITE_WRITE, 0, 432 region->tcam_region_info, 433 aentry->enc_key, erp_id, 434 aentry->delta_info.start, 435 aentry->delta_info.mask, 436 aentry->delta_info.value, 437 refcount_read(&lkey_id->refcnt) != 1, 438 lkey_id->id, 0); 439 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl); 440 aregion->ops->lkey_id_put(aregion, lkey_id); 441 } 442 443 static int 444 mlxsw_sp_acl_atcam_region_entry_action_replace(struct mlxsw_sp *mlxsw_sp, 445 struct mlxsw_sp_acl_atcam_region *aregion, 446 struct mlxsw_sp_acl_atcam_entry *aentry, 447 struct mlxsw_sp_acl_rule_info *rulei) 448 { 449 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id; 450 u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask); 451 struct mlxsw_sp_acl_tcam_region *region = aregion->region; 452 char ptce3_pl[MLXSW_REG_PTCE3_LEN]; 453 u32 kvdl_index, priority; 454 int err; 455 456 err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, true); 457 if (err) 458 return err; 459 kvdl_index = mlxsw_afa_block_first_kvdl_index(rulei->act_block); 460 mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_UPDATE, 461 priority, region->tcam_region_info, 462 aentry->enc_key, erp_id, 463 aentry->delta_info.start, 464 aentry->delta_info.mask, 465 aentry->delta_info.value, 466 refcount_read(&lkey_id->refcnt) != 1, lkey_id->id, 467 kvdl_index); 468 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl); 469 } 470 471 static int 472 __mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp, 473 struct mlxsw_sp_acl_atcam_region *aregion, 474 struct mlxsw_sp_acl_atcam_entry *aentry, 475 struct mlxsw_sp_acl_rule_info *rulei) 476 { 477 struct mlxsw_sp_acl_tcam_region *region = aregion->region; 478 char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 }; 479 struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl); 480 const struct mlxsw_sp_acl_erp_delta *delta; 481 struct mlxsw_sp_acl_erp_mask *erp_mask; 482 int err; 483 484 mlxsw_afk_encode(afk, region->key_info, &rulei->values, 485 aentry->ht_key.full_enc_key, mask); 486 487 erp_mask = mlxsw_sp_acl_erp_mask_get(aregion, mask, false); 488 if (IS_ERR(erp_mask)) 489 return PTR_ERR(erp_mask); 490 aentry->erp_mask = erp_mask; 491 aentry->ht_key.erp_id = mlxsw_sp_acl_erp_mask_erp_id(erp_mask); 492 memcpy(aentry->enc_key, aentry->ht_key.full_enc_key, 493 sizeof(aentry->enc_key)); 494 495 /* Compute all needed delta information and clear the delta bits 496 * from the encrypted key. 497 */ 498 delta = mlxsw_sp_acl_erp_delta(aentry->erp_mask); 499 aentry->delta_info.start = mlxsw_sp_acl_erp_delta_start(delta); 500 aentry->delta_info.mask = mlxsw_sp_acl_erp_delta_mask(delta); 501 aentry->delta_info.value = 502 mlxsw_sp_acl_erp_delta_value(delta, 503 aentry->ht_key.full_enc_key); 504 mlxsw_sp_acl_erp_delta_clear(delta, aentry->enc_key); 505 506 /* Add rule to the list of A-TCAM rules, assuming this 507 * rule is intended to A-TCAM. In case this rule does 508 * not fit into A-TCAM it will be removed from the list. 509 */ 510 list_add(&aentry->list, &aregion->entries_list); 511 512 /* We can't insert identical rules into the A-TCAM, so fail and 513 * let the rule spill into C-TCAM 514 */ 515 err = rhashtable_lookup_insert_fast(&aregion->entries_ht, 516 &aentry->ht_node, 517 mlxsw_sp_acl_atcam_entries_ht_params); 518 if (err) 519 goto err_rhashtable_insert; 520 521 /* Bloom filter must be updated here, before inserting the rule into 522 * the A-TCAM. 523 */ 524 err = mlxsw_sp_acl_erp_bf_insert(mlxsw_sp, aregion, erp_mask, aentry); 525 if (err) 526 goto err_bf_insert; 527 528 err = mlxsw_sp_acl_atcam_region_entry_insert(mlxsw_sp, aregion, aentry, 529 rulei); 530 if (err) 531 goto err_rule_insert; 532 533 return 0; 534 535 err_rule_insert: 536 mlxsw_sp_acl_erp_bf_remove(mlxsw_sp, aregion, erp_mask, aentry); 537 err_bf_insert: 538 rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node, 539 mlxsw_sp_acl_atcam_entries_ht_params); 540 err_rhashtable_insert: 541 list_del(&aentry->list); 542 mlxsw_sp_acl_erp_mask_put(aregion, erp_mask); 543 return err; 544 } 545 546 static void 547 __mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp, 548 struct mlxsw_sp_acl_atcam_region *aregion, 549 struct mlxsw_sp_acl_atcam_entry *aentry) 550 { 551 mlxsw_sp_acl_atcam_region_entry_remove(mlxsw_sp, aregion, aentry); 552 mlxsw_sp_acl_erp_bf_remove(mlxsw_sp, aregion, aentry->erp_mask, aentry); 553 rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node, 554 mlxsw_sp_acl_atcam_entries_ht_params); 555 list_del(&aentry->list); 556 mlxsw_sp_acl_erp_mask_put(aregion, aentry->erp_mask); 557 } 558 559 static int 560 __mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, 561 struct mlxsw_sp_acl_atcam_region *aregion, 562 struct mlxsw_sp_acl_atcam_entry *aentry, 563 struct mlxsw_sp_acl_rule_info *rulei) 564 { 565 return mlxsw_sp_acl_atcam_region_entry_action_replace(mlxsw_sp, aregion, 566 aentry, rulei); 567 } 568 569 int mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp, 570 struct mlxsw_sp_acl_atcam_region *aregion, 571 struct mlxsw_sp_acl_atcam_chunk *achunk, 572 struct mlxsw_sp_acl_atcam_entry *aentry, 573 struct mlxsw_sp_acl_rule_info *rulei) 574 { 575 int err; 576 577 err = __mlxsw_sp_acl_atcam_entry_add(mlxsw_sp, aregion, aentry, rulei); 578 if (!err) 579 return 0; 580 581 /* It is possible we failed to add the rule to the A-TCAM due to 582 * exceeded number of masks. Try to spill into C-TCAM. 583 */ 584 trace_mlxsw_sp_acl_atcam_entry_add_ctcam_spill(mlxsw_sp, aregion); 585 err = mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, &aregion->cregion, 586 &achunk->cchunk, &aentry->centry, 587 rulei, true); 588 if (!err) 589 return 0; 590 591 return err; 592 } 593 594 void mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp, 595 struct mlxsw_sp_acl_atcam_region *aregion, 596 struct mlxsw_sp_acl_atcam_chunk *achunk, 597 struct mlxsw_sp_acl_atcam_entry *aentry) 598 { 599 if (mlxsw_sp_acl_atcam_is_centry(aentry)) 600 mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, &aregion->cregion, 601 &achunk->cchunk, &aentry->centry); 602 else 603 __mlxsw_sp_acl_atcam_entry_del(mlxsw_sp, aregion, aentry); 604 } 605 606 int 607 mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, 608 struct mlxsw_sp_acl_atcam_region *aregion, 609 struct mlxsw_sp_acl_atcam_entry *aentry, 610 struct mlxsw_sp_acl_rule_info *rulei) 611 { 612 int err; 613 614 if (mlxsw_sp_acl_atcam_is_centry(aentry)) 615 err = mlxsw_sp_acl_ctcam_entry_action_replace(mlxsw_sp, 616 &aregion->cregion, 617 &aentry->centry, 618 rulei); 619 else 620 err = __mlxsw_sp_acl_atcam_entry_action_replace(mlxsw_sp, 621 aregion, aentry, 622 rulei); 623 624 return err; 625 } 626 627 int mlxsw_sp_acl_atcam_init(struct mlxsw_sp *mlxsw_sp, 628 struct mlxsw_sp_acl_atcam *atcam) 629 { 630 return mlxsw_sp_acl_erps_init(mlxsw_sp, atcam); 631 } 632 633 void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp *mlxsw_sp, 634 struct mlxsw_sp_acl_atcam *atcam) 635 { 636 mlxsw_sp_acl_erps_fini(mlxsw_sp, atcam); 637 } 638 639 void * 640 mlxsw_sp_acl_atcam_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion) 641 { 642 return mlxsw_sp_acl_erp_rehash_hints_get(aregion); 643 } 644 645 void mlxsw_sp_acl_atcam_rehash_hints_put(void *hints_priv) 646 { 647 mlxsw_sp_acl_erp_rehash_hints_put(hints_priv); 648 } 649