spectrum_acl_atcam.c 16 KB

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