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 11 #include "reg.h" 12 #include "core.h" 13 #include "spectrum.h" 14 #include "spectrum_acl_tcam.h" 15 #include "core_acl_flex_keys.h" 16 17 #define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_START 6 18 #define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_END 11 19 20 struct mlxsw_sp_acl_atcam_lkey_id_ht_key { 21 char enc_key[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN]; /* MSB blocks */ 22 u8 erp_id; 23 }; 24 25 struct mlxsw_sp_acl_atcam_lkey_id { 26 struct rhash_head ht_node; 27 struct mlxsw_sp_acl_atcam_lkey_id_ht_key ht_key; 28 refcount_t refcnt; 29 u32 id; 30 }; 31 32 struct mlxsw_sp_acl_atcam_region_ops { 33 int (*init)(struct mlxsw_sp_acl_atcam_region *aregion); 34 void (*fini)(struct mlxsw_sp_acl_atcam_region *aregion); 35 struct mlxsw_sp_acl_atcam_lkey_id * 36 (*lkey_id_get)(struct mlxsw_sp_acl_atcam_region *aregion, 37 struct mlxsw_sp_acl_rule_info *rulei, u8 erp_id); 38 void (*lkey_id_put)(struct mlxsw_sp_acl_atcam_region *aregion, 39 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id); 40 }; 41 42 struct mlxsw_sp_acl_atcam_region_generic { 43 struct mlxsw_sp_acl_atcam_lkey_id dummy_lkey_id; 44 }; 45 46 struct mlxsw_sp_acl_atcam_region_12kb { 47 struct rhashtable lkey_ht; 48 unsigned int max_lkey_id; 49 unsigned long *used_lkey_id; 50 }; 51 52 static const struct rhashtable_params mlxsw_sp_acl_atcam_lkey_id_ht_params = { 53 .key_len = sizeof(struct mlxsw_sp_acl_atcam_lkey_id_ht_key), 54 .key_offset = offsetof(struct mlxsw_sp_acl_atcam_lkey_id, ht_key), 55 .head_offset = offsetof(struct mlxsw_sp_acl_atcam_lkey_id, ht_node), 56 }; 57 58 static const struct rhashtable_params mlxsw_sp_acl_atcam_entries_ht_params = { 59 .key_len = sizeof(struct mlxsw_sp_acl_atcam_entry_ht_key), 60 .key_offset = offsetof(struct mlxsw_sp_acl_atcam_entry, ht_key), 61 .head_offset = offsetof(struct mlxsw_sp_acl_atcam_entry, ht_node), 62 }; 63 64 static bool 65 mlxsw_sp_acl_atcam_is_centry(const struct mlxsw_sp_acl_atcam_entry *aentry) 66 { 67 return mlxsw_sp_acl_erp_is_ctcam_erp(aentry->erp); 68 } 69 70 static int 71 mlxsw_sp_acl_atcam_region_generic_init(struct mlxsw_sp_acl_atcam_region *aregion) 72 { 73 struct mlxsw_sp_acl_atcam_region_generic *region_generic; 74 75 region_generic = kzalloc(sizeof(*region_generic), GFP_KERNEL); 76 if (!region_generic) 77 return -ENOMEM; 78 79 refcount_set(®ion_generic->dummy_lkey_id.refcnt, 1); 80 aregion->priv = region_generic; 81 82 return 0; 83 } 84 85 static void 86 mlxsw_sp_acl_atcam_region_generic_fini(struct mlxsw_sp_acl_atcam_region *aregion) 87 { 88 kfree(aregion->priv); 89 } 90 91 static struct mlxsw_sp_acl_atcam_lkey_id * 92 mlxsw_sp_acl_atcam_generic_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion, 93 struct mlxsw_sp_acl_rule_info *rulei, 94 u8 erp_id) 95 { 96 struct mlxsw_sp_acl_atcam_region_generic *region_generic; 97 98 region_generic = aregion->priv; 99 return ®ion_generic->dummy_lkey_id; 100 } 101 102 static void 103 mlxsw_sp_acl_atcam_generic_lkey_id_put(struct mlxsw_sp_acl_atcam_region *aregion, 104 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id) 105 { 106 } 107 108 static const struct mlxsw_sp_acl_atcam_region_ops 109 mlxsw_sp_acl_atcam_region_generic_ops = { 110 .init = mlxsw_sp_acl_atcam_region_generic_init, 111 .fini = mlxsw_sp_acl_atcam_region_generic_fini, 112 .lkey_id_get = mlxsw_sp_acl_atcam_generic_lkey_id_get, 113 .lkey_id_put = mlxsw_sp_acl_atcam_generic_lkey_id_put, 114 }; 115 116 static int 117 mlxsw_sp_acl_atcam_region_12kb_init(struct mlxsw_sp_acl_atcam_region *aregion) 118 { 119 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp; 120 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb; 121 size_t alloc_size; 122 u64 max_lkey_id; 123 int err; 124 125 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_LARGE_KEY_ID)) 126 return -EIO; 127 128 max_lkey_id = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_LARGE_KEY_ID); 129 region_12kb = kzalloc(sizeof(*region_12kb), GFP_KERNEL); 130 if (!region_12kb) 131 return -ENOMEM; 132 133 alloc_size = BITS_TO_LONGS(max_lkey_id) * sizeof(unsigned long); 134 region_12kb->used_lkey_id = kzalloc(alloc_size, GFP_KERNEL); 135 if (!region_12kb->used_lkey_id) { 136 err = -ENOMEM; 137 goto err_used_lkey_id_alloc; 138 } 139 140 err = rhashtable_init(®ion_12kb->lkey_ht, 141 &mlxsw_sp_acl_atcam_lkey_id_ht_params); 142 if (err) 143 goto err_rhashtable_init; 144 145 region_12kb->max_lkey_id = max_lkey_id; 146 aregion->priv = region_12kb; 147 148 return 0; 149 150 err_rhashtable_init: 151 kfree(region_12kb->used_lkey_id); 152 err_used_lkey_id_alloc: 153 kfree(region_12kb); 154 return err; 155 } 156 157 static void 158 mlxsw_sp_acl_atcam_region_12kb_fini(struct mlxsw_sp_acl_atcam_region *aregion) 159 { 160 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv; 161 162 rhashtable_destroy(®ion_12kb->lkey_ht); 163 kfree(region_12kb->used_lkey_id); 164 kfree(region_12kb); 165 } 166 167 static struct mlxsw_sp_acl_atcam_lkey_id * 168 mlxsw_sp_acl_atcam_lkey_id_create(struct mlxsw_sp_acl_atcam_region *aregion, 169 struct mlxsw_sp_acl_atcam_lkey_id_ht_key *ht_key) 170 { 171 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv; 172 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id; 173 u32 id; 174 int err; 175 176 id = find_first_zero_bit(region_12kb->used_lkey_id, 177 region_12kb->max_lkey_id); 178 if (id < region_12kb->max_lkey_id) 179 __set_bit(id, region_12kb->used_lkey_id); 180 else 181 return ERR_PTR(-ENOBUFS); 182 183 lkey_id = kzalloc(sizeof(*lkey_id), GFP_KERNEL); 184 if (!lkey_id) { 185 err = -ENOMEM; 186 goto err_lkey_id_alloc; 187 } 188 189 lkey_id->id = id; 190 memcpy(&lkey_id->ht_key, ht_key, sizeof(*ht_key)); 191 refcount_set(&lkey_id->refcnt, 1); 192 193 err = rhashtable_insert_fast(®ion_12kb->lkey_ht, 194 &lkey_id->ht_node, 195 mlxsw_sp_acl_atcam_lkey_id_ht_params); 196 if (err) 197 goto err_rhashtable_insert; 198 199 return lkey_id; 200 201 err_rhashtable_insert: 202 kfree(lkey_id); 203 err_lkey_id_alloc: 204 __clear_bit(id, region_12kb->used_lkey_id); 205 return ERR_PTR(err); 206 } 207 208 static void 209 mlxsw_sp_acl_atcam_lkey_id_destroy(struct mlxsw_sp_acl_atcam_region *aregion, 210 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id) 211 { 212 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv; 213 u32 id = lkey_id->id; 214 215 rhashtable_remove_fast(®ion_12kb->lkey_ht, &lkey_id->ht_node, 216 mlxsw_sp_acl_atcam_lkey_id_ht_params); 217 kfree(lkey_id); 218 __clear_bit(id, region_12kb->used_lkey_id); 219 } 220 221 static struct mlxsw_sp_acl_atcam_lkey_id * 222 mlxsw_sp_acl_atcam_12kb_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion, 223 struct mlxsw_sp_acl_rule_info *rulei, 224 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 mlxsw_afk_encode(afk, region->key_info, &rulei->values, ht_key.enc_key, 234 NULL, MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_START, 235 MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_END); 236 ht_key.erp_id = erp_id; 237 lkey_id = rhashtable_lookup_fast(®ion_12kb->lkey_ht, &ht_key, 238 mlxsw_sp_acl_atcam_lkey_id_ht_params); 239 if (lkey_id) { 240 refcount_inc(&lkey_id->refcnt); 241 return lkey_id; 242 } 243 244 return mlxsw_sp_acl_atcam_lkey_id_create(aregion, &ht_key); 245 } 246 247 static void 248 mlxsw_sp_acl_atcam_12kb_lkey_id_put(struct mlxsw_sp_acl_atcam_region *aregion, 249 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id) 250 { 251 if (refcount_dec_and_test(&lkey_id->refcnt)) 252 mlxsw_sp_acl_atcam_lkey_id_destroy(aregion, lkey_id); 253 } 254 255 static const struct mlxsw_sp_acl_atcam_region_ops 256 mlxsw_sp_acl_atcam_region_12kb_ops = { 257 .init = mlxsw_sp_acl_atcam_region_12kb_init, 258 .fini = mlxsw_sp_acl_atcam_region_12kb_fini, 259 .lkey_id_get = mlxsw_sp_acl_atcam_12kb_lkey_id_get, 260 .lkey_id_put = mlxsw_sp_acl_atcam_12kb_lkey_id_put, 261 }; 262 263 static const struct mlxsw_sp_acl_atcam_region_ops * 264 mlxsw_sp_acl_atcam_region_ops_arr[] = { 265 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] = 266 &mlxsw_sp_acl_atcam_region_generic_ops, 267 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] = 268 &mlxsw_sp_acl_atcam_region_generic_ops, 269 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] = 270 &mlxsw_sp_acl_atcam_region_generic_ops, 271 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] = 272 &mlxsw_sp_acl_atcam_region_12kb_ops, 273 }; 274 275 int mlxsw_sp_acl_atcam_region_associate(struct mlxsw_sp *mlxsw_sp, 276 u16 region_id) 277 { 278 char perar_pl[MLXSW_REG_PERAR_LEN]; 279 /* For now, just assume that every region has 12 key blocks */ 280 u16 hw_region = region_id * 3; 281 u64 max_regions; 282 283 max_regions = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_REGIONS); 284 if (hw_region >= max_regions) 285 return -ENOBUFS; 286 287 mlxsw_reg_perar_pack(perar_pl, region_id, hw_region); 288 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perar), perar_pl); 289 } 290 291 static void 292 mlxsw_sp_acl_atcam_region_type_init(struct mlxsw_sp_acl_atcam_region *aregion) 293 { 294 struct mlxsw_sp_acl_tcam_region *region = aregion->region; 295 enum mlxsw_sp_acl_atcam_region_type region_type; 296 unsigned int blocks_count; 297 298 /* We already know the blocks count can not exceed the maximum 299 * blocks count. 300 */ 301 blocks_count = mlxsw_afk_key_info_blocks_count_get(region->key_info); 302 if (blocks_count <= 2) 303 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB; 304 else if (blocks_count <= 4) 305 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB; 306 else if (blocks_count <= 8) 307 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB; 308 else 309 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB; 310 311 aregion->type = region_type; 312 aregion->ops = mlxsw_sp_acl_atcam_region_ops_arr[region_type]; 313 } 314 315 int 316 mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp, 317 struct mlxsw_sp_acl_atcam *atcam, 318 struct mlxsw_sp_acl_atcam_region *aregion, 319 struct mlxsw_sp_acl_tcam_region *region, 320 const struct mlxsw_sp_acl_ctcam_region_ops *ops) 321 { 322 int err; 323 324 aregion->region = region; 325 aregion->atcam = atcam; 326 mlxsw_sp_acl_atcam_region_type_init(aregion); 327 328 err = rhashtable_init(&aregion->entries_ht, 329 &mlxsw_sp_acl_atcam_entries_ht_params); 330 if (err) 331 return err; 332 err = aregion->ops->init(aregion); 333 if (err) 334 goto err_ops_init; 335 err = mlxsw_sp_acl_erp_region_init(aregion); 336 if (err) 337 goto err_erp_region_init; 338 err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, &aregion->cregion, 339 region, ops); 340 if (err) 341 goto err_ctcam_region_init; 342 343 return 0; 344 345 err_ctcam_region_init: 346 mlxsw_sp_acl_erp_region_fini(aregion); 347 err_erp_region_init: 348 aregion->ops->fini(aregion); 349 err_ops_init: 350 rhashtable_destroy(&aregion->entries_ht); 351 return err; 352 } 353 354 void mlxsw_sp_acl_atcam_region_fini(struct mlxsw_sp_acl_atcam_region *aregion) 355 { 356 mlxsw_sp_acl_ctcam_region_fini(&aregion->cregion); 357 mlxsw_sp_acl_erp_region_fini(aregion); 358 aregion->ops->fini(aregion); 359 rhashtable_destroy(&aregion->entries_ht); 360 } 361 362 void mlxsw_sp_acl_atcam_chunk_init(struct mlxsw_sp_acl_atcam_region *aregion, 363 struct mlxsw_sp_acl_atcam_chunk *achunk, 364 unsigned int priority) 365 { 366 mlxsw_sp_acl_ctcam_chunk_init(&aregion->cregion, &achunk->cchunk, 367 priority); 368 } 369 370 void mlxsw_sp_acl_atcam_chunk_fini(struct mlxsw_sp_acl_atcam_chunk *achunk) 371 { 372 mlxsw_sp_acl_ctcam_chunk_fini(&achunk->cchunk); 373 } 374 375 static int 376 mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp, 377 struct mlxsw_sp_acl_atcam_region *aregion, 378 struct mlxsw_sp_acl_atcam_entry *aentry, 379 struct mlxsw_sp_acl_rule_info *rulei) 380 { 381 struct mlxsw_sp_acl_tcam_region *region = aregion->region; 382 u8 erp_id = mlxsw_sp_acl_erp_id(aentry->erp); 383 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id; 384 char ptce3_pl[MLXSW_REG_PTCE3_LEN]; 385 u32 kvdl_index, priority; 386 int err; 387 388 err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, true); 389 if (err) 390 return err; 391 392 lkey_id = aregion->ops->lkey_id_get(aregion, rulei, erp_id); 393 if (IS_ERR(lkey_id)) 394 return PTR_ERR(lkey_id); 395 aentry->lkey_id = lkey_id; 396 397 kvdl_index = mlxsw_afa_block_first_kvdl_index(rulei->act_block); 398 mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_WRITE, 399 priority, region->tcam_region_info, 400 aentry->ht_key.enc_key, erp_id, 401 refcount_read(&lkey_id->refcnt) != 1, lkey_id->id, 402 kvdl_index); 403 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl); 404 if (err) 405 goto err_ptce3_write; 406 407 return 0; 408 409 err_ptce3_write: 410 aregion->ops->lkey_id_put(aregion, lkey_id); 411 return err; 412 } 413 414 static void 415 mlxsw_sp_acl_atcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp, 416 struct mlxsw_sp_acl_atcam_region *aregion, 417 struct mlxsw_sp_acl_atcam_entry *aentry) 418 { 419 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id; 420 struct mlxsw_sp_acl_tcam_region *region = aregion->region; 421 u8 erp_id = mlxsw_sp_acl_erp_id(aentry->erp); 422 char ptce3_pl[MLXSW_REG_PTCE3_LEN]; 423 424 mlxsw_reg_ptce3_pack(ptce3_pl, false, MLXSW_REG_PTCE3_OP_WRITE_WRITE, 0, 425 region->tcam_region_info, aentry->ht_key.enc_key, 426 erp_id, refcount_read(&lkey_id->refcnt) != 1, 427 lkey_id->id, 0); 428 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl); 429 aregion->ops->lkey_id_put(aregion, lkey_id); 430 } 431 432 static int 433 __mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp, 434 struct mlxsw_sp_acl_atcam_region *aregion, 435 struct mlxsw_sp_acl_atcam_entry *aentry, 436 struct mlxsw_sp_acl_rule_info *rulei) 437 { 438 struct mlxsw_sp_acl_tcam_region *region = aregion->region; 439 char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 }; 440 struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl); 441 struct mlxsw_sp_acl_erp *erp; 442 unsigned int blocks_count; 443 int err; 444 445 blocks_count = mlxsw_afk_key_info_blocks_count_get(region->key_info); 446 mlxsw_afk_encode(afk, region->key_info, &rulei->values, 447 aentry->ht_key.enc_key, mask, 0, blocks_count - 1); 448 449 erp = mlxsw_sp_acl_erp_get(aregion, mask, false); 450 if (IS_ERR(erp)) 451 return PTR_ERR(erp); 452 aentry->erp = erp; 453 aentry->ht_key.erp_id = mlxsw_sp_acl_erp_id(erp); 454 455 /* We can't insert identical rules into the A-TCAM, so fail and 456 * let the rule spill into C-TCAM 457 */ 458 err = rhashtable_lookup_insert_fast(&aregion->entries_ht, 459 &aentry->ht_node, 460 mlxsw_sp_acl_atcam_entries_ht_params); 461 if (err) 462 goto err_rhashtable_insert; 463 464 err = mlxsw_sp_acl_atcam_region_entry_insert(mlxsw_sp, aregion, aentry, 465 rulei); 466 if (err) 467 goto err_rule_insert; 468 469 return 0; 470 471 err_rule_insert: 472 rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node, 473 mlxsw_sp_acl_atcam_entries_ht_params); 474 err_rhashtable_insert: 475 mlxsw_sp_acl_erp_put(aregion, erp); 476 return err; 477 } 478 479 static void 480 __mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp, 481 struct mlxsw_sp_acl_atcam_region *aregion, 482 struct mlxsw_sp_acl_atcam_entry *aentry) 483 { 484 mlxsw_sp_acl_atcam_region_entry_remove(mlxsw_sp, aregion, aentry); 485 rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node, 486 mlxsw_sp_acl_atcam_entries_ht_params); 487 mlxsw_sp_acl_erp_put(aregion, aentry->erp); 488 } 489 490 int mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp, 491 struct mlxsw_sp_acl_atcam_region *aregion, 492 struct mlxsw_sp_acl_atcam_chunk *achunk, 493 struct mlxsw_sp_acl_atcam_entry *aentry, 494 struct mlxsw_sp_acl_rule_info *rulei) 495 { 496 int err; 497 498 err = __mlxsw_sp_acl_atcam_entry_add(mlxsw_sp, aregion, aentry, rulei); 499 if (!err) 500 return 0; 501 502 /* It is possible we failed to add the rule to the A-TCAM due to 503 * exceeded number of masks. Try to spill into C-TCAM. 504 */ 505 err = mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, &aregion->cregion, 506 &achunk->cchunk, &aentry->centry, 507 rulei, true); 508 if (!err) 509 return 0; 510 511 return err; 512 } 513 514 void mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp, 515 struct mlxsw_sp_acl_atcam_region *aregion, 516 struct mlxsw_sp_acl_atcam_chunk *achunk, 517 struct mlxsw_sp_acl_atcam_entry *aentry) 518 { 519 if (mlxsw_sp_acl_atcam_is_centry(aentry)) 520 mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, &aregion->cregion, 521 &achunk->cchunk, &aentry->centry); 522 else 523 __mlxsw_sp_acl_atcam_entry_del(mlxsw_sp, aregion, aentry); 524 } 525 526 int mlxsw_sp_acl_atcam_init(struct mlxsw_sp *mlxsw_sp, 527 struct mlxsw_sp_acl_atcam *atcam) 528 { 529 return mlxsw_sp_acl_erps_init(mlxsw_sp, atcam); 530 } 531 532 void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp *mlxsw_sp, 533 struct mlxsw_sp_acl_atcam *atcam) 534 { 535 mlxsw_sp_acl_erps_fini(mlxsw_sp, atcam); 536 } 537