spectrum_acl_erp.c 33 KB

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