19948a064SJiri Pirko // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
29948a064SJiri Pirko /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
3f465261aSIdo Schimmel
4f465261aSIdo Schimmel #include <linux/bitmap.h>
5f465261aSIdo Schimmel #include <linux/errno.h>
6f465261aSIdo Schimmel #include <linux/genalloc.h>
7f465261aSIdo Schimmel #include <linux/gfp.h>
8f465261aSIdo Schimmel #include <linux/kernel.h>
9f465261aSIdo Schimmel #include <linux/list.h>
10ddaa2875SJiri Pirko #include <linux/mutex.h>
11c71abd7dSJiri Pirko #include <linux/objagg.h>
12f465261aSIdo Schimmel #include <linux/rtnetlink.h>
13f465261aSIdo Schimmel #include <linux/slab.h>
14f465261aSIdo Schimmel
15f465261aSIdo Schimmel #include "core.h"
16f465261aSIdo Schimmel #include "reg.h"
17f465261aSIdo Schimmel #include "spectrum.h"
18f465261aSIdo Schimmel #include "spectrum_acl_tcam.h"
19f465261aSIdo Schimmel
20f465261aSIdo Schimmel /* gen_pool_alloc() returns 0 when allocation fails, so use an offset */
21f465261aSIdo Schimmel #define MLXSW_SP_ACL_ERP_GENALLOC_OFFSET 0x100
22f465261aSIdo Schimmel #define MLXSW_SP_ACL_ERP_MAX_PER_REGION 16
23f465261aSIdo Schimmel
24f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_core {
25f465261aSIdo Schimmel unsigned int erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_MAX + 1];
26f465261aSIdo Schimmel struct gen_pool *erp_tables;
27f465261aSIdo Schimmel struct mlxsw_sp *mlxsw_sp;
280487cfbaSNir Dotan struct mlxsw_sp_acl_bf *bf;
29f465261aSIdo Schimmel unsigned int num_erp_banks;
30f465261aSIdo Schimmel };
31f465261aSIdo Schimmel
32f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_key {
33f465261aSIdo Schimmel char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN];
34c22291f7SJiri Pirko #define __MASK_LEN 0x38
35c22291f7SJiri Pirko #define __MASK_IDX(i) (__MASK_LEN - (i) - 1)
36b17b113eSIdo Schimmel bool ctcam;
37f465261aSIdo Schimmel };
38f465261aSIdo Schimmel
39f465261aSIdo Schimmel struct mlxsw_sp_acl_erp {
40f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_key key;
41f465261aSIdo Schimmel u8 id;
42f465261aSIdo Schimmel u8 index;
43f465261aSIdo Schimmel DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
44f465261aSIdo Schimmel struct list_head list;
45f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_table *erp_table;
46f465261aSIdo Schimmel };
47f465261aSIdo Schimmel
48f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_master_mask {
49f465261aSIdo Schimmel DECLARE_BITMAP(bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
50f465261aSIdo Schimmel unsigned int count[MLXSW_SP_ACL_TCAM_MASK_LEN];
51f465261aSIdo Schimmel };
52f465261aSIdo Schimmel
53f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_table {
54f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_master_mask master_mask;
55f465261aSIdo Schimmel DECLARE_BITMAP(erp_id_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
56f465261aSIdo Schimmel DECLARE_BITMAP(erp_index_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
57f465261aSIdo Schimmel struct list_head atcam_erps_list;
58f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_core *erp_core;
59f465261aSIdo Schimmel struct mlxsw_sp_acl_atcam_region *aregion;
60f465261aSIdo Schimmel const struct mlxsw_sp_acl_erp_table_ops *ops;
61f465261aSIdo Schimmel unsigned long base_index;
62f465261aSIdo Schimmel unsigned int num_atcam_erps;
63f465261aSIdo Schimmel unsigned int num_max_atcam_erps;
64b17b113eSIdo Schimmel unsigned int num_ctcam_erps;
65c22291f7SJiri Pirko unsigned int num_deltas;
66c71abd7dSJiri Pirko struct objagg *objagg;
67ddaa2875SJiri Pirko struct mutex objagg_lock; /* guards objagg manipulation */
68f465261aSIdo Schimmel };
69f465261aSIdo Schimmel
70f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_table_ops {
71f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *
72f465261aSIdo Schimmel (*erp_create)(struct mlxsw_sp_acl_erp_table *erp_table,
73f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_key *key);
74f465261aSIdo Schimmel void (*erp_destroy)(struct mlxsw_sp_acl_erp_table *erp_table,
75f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp);
76f465261aSIdo Schimmel };
77f465261aSIdo Schimmel
78f465261aSIdo Schimmel static struct mlxsw_sp_acl_erp *
79f465261aSIdo Schimmel mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
80f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_key *key);
81f465261aSIdo Schimmel static void
82f465261aSIdo Schimmel mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
83f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp);
84f465261aSIdo Schimmel static struct mlxsw_sp_acl_erp *
85f465261aSIdo Schimmel mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
86f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_key *key);
87f465261aSIdo Schimmel static void
88f465261aSIdo Schimmel mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
89f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp);
90f465261aSIdo Schimmel static struct mlxsw_sp_acl_erp *
91f465261aSIdo Schimmel mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
92f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_key *key);
93f465261aSIdo Schimmel static void
94f465261aSIdo Schimmel mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
95f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp);
96f465261aSIdo Schimmel static void
97f465261aSIdo Schimmel mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
98f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp);
99f465261aSIdo Schimmel
100f465261aSIdo Schimmel static const struct mlxsw_sp_acl_erp_table_ops erp_multiple_masks_ops = {
101f465261aSIdo Schimmel .erp_create = mlxsw_sp_acl_erp_mask_create,
102f465261aSIdo Schimmel .erp_destroy = mlxsw_sp_acl_erp_mask_destroy,
103f465261aSIdo Schimmel };
104f465261aSIdo Schimmel
105f465261aSIdo Schimmel static const struct mlxsw_sp_acl_erp_table_ops erp_two_masks_ops = {
106f465261aSIdo Schimmel .erp_create = mlxsw_sp_acl_erp_mask_create,
107f465261aSIdo Schimmel .erp_destroy = mlxsw_sp_acl_erp_second_mask_destroy,
108f465261aSIdo Schimmel };
109f465261aSIdo Schimmel
110f465261aSIdo Schimmel static const struct mlxsw_sp_acl_erp_table_ops erp_single_mask_ops = {
111f465261aSIdo Schimmel .erp_create = mlxsw_sp_acl_erp_second_mask_create,
112f465261aSIdo Schimmel .erp_destroy = mlxsw_sp_acl_erp_first_mask_destroy,
113f465261aSIdo Schimmel };
114f465261aSIdo Schimmel
115f465261aSIdo Schimmel static const struct mlxsw_sp_acl_erp_table_ops erp_no_mask_ops = {
116f465261aSIdo Schimmel .erp_create = mlxsw_sp_acl_erp_first_mask_create,
117f465261aSIdo Schimmel .erp_destroy = mlxsw_sp_acl_erp_no_mask_destroy,
118f465261aSIdo Schimmel };
119f465261aSIdo Schimmel
120f5a2852eSNir Dotan static bool
mlxsw_sp_acl_erp_table_is_used(const struct mlxsw_sp_acl_erp_table * erp_table)121f5a2852eSNir Dotan mlxsw_sp_acl_erp_table_is_used(const struct mlxsw_sp_acl_erp_table *erp_table)
122f5a2852eSNir Dotan {
123f5a2852eSNir Dotan return erp_table->ops != &erp_single_mask_ops &&
124f5a2852eSNir Dotan erp_table->ops != &erp_no_mask_ops;
125f5a2852eSNir Dotan }
126f5a2852eSNir Dotan
127f5a2852eSNir Dotan static unsigned int
mlxsw_sp_acl_erp_bank_get(const struct mlxsw_sp_acl_erp * erp)128f5a2852eSNir Dotan mlxsw_sp_acl_erp_bank_get(const struct mlxsw_sp_acl_erp *erp)
129f5a2852eSNir Dotan {
130f5a2852eSNir Dotan return erp->index % erp->erp_table->erp_core->num_erp_banks;
131f5a2852eSNir Dotan }
132f5a2852eSNir Dotan
133f465261aSIdo Schimmel static unsigned int
mlxsw_sp_acl_erp_table_entry_size(const struct mlxsw_sp_acl_erp_table * erp_table)134f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_entry_size(const struct mlxsw_sp_acl_erp_table *erp_table)
135f465261aSIdo Schimmel {
136f465261aSIdo Schimmel struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
137f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
138f465261aSIdo Schimmel
139f465261aSIdo Schimmel return erp_core->erpt_entries_size[aregion->type];
140f465261aSIdo Schimmel }
141f465261aSIdo Schimmel
mlxsw_sp_acl_erp_id_get(struct mlxsw_sp_acl_erp_table * erp_table,u8 * p_id)142f465261aSIdo Schimmel static int mlxsw_sp_acl_erp_id_get(struct mlxsw_sp_acl_erp_table *erp_table,
143f465261aSIdo Schimmel u8 *p_id)
144f465261aSIdo Schimmel {
145f465261aSIdo Schimmel u8 id;
146f465261aSIdo Schimmel
147f465261aSIdo Schimmel id = find_first_zero_bit(erp_table->erp_id_bitmap,
148f465261aSIdo Schimmel MLXSW_SP_ACL_ERP_MAX_PER_REGION);
149f465261aSIdo Schimmel if (id < MLXSW_SP_ACL_ERP_MAX_PER_REGION) {
150f465261aSIdo Schimmel __set_bit(id, erp_table->erp_id_bitmap);
151f465261aSIdo Schimmel *p_id = id;
152f465261aSIdo Schimmel return 0;
153f465261aSIdo Schimmel }
154f465261aSIdo Schimmel
155f465261aSIdo Schimmel return -ENOBUFS;
156f465261aSIdo Schimmel }
157f465261aSIdo Schimmel
mlxsw_sp_acl_erp_id_put(struct mlxsw_sp_acl_erp_table * erp_table,u8 id)158f465261aSIdo Schimmel static void mlxsw_sp_acl_erp_id_put(struct mlxsw_sp_acl_erp_table *erp_table,
159f465261aSIdo Schimmel u8 id)
160f465261aSIdo Schimmel {
161f465261aSIdo Schimmel __clear_bit(id, erp_table->erp_id_bitmap);
162f465261aSIdo Schimmel }
163f465261aSIdo Schimmel
164f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_master_mask_bit_set(unsigned long bit,struct mlxsw_sp_acl_erp_master_mask * mask)165f465261aSIdo Schimmel mlxsw_sp_acl_erp_master_mask_bit_set(unsigned long bit,
166f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_master_mask *mask)
167f465261aSIdo Schimmel {
168f465261aSIdo Schimmel if (mask->count[bit]++ == 0)
169f465261aSIdo Schimmel __set_bit(bit, mask->bitmap);
170f465261aSIdo Schimmel }
171f465261aSIdo Schimmel
172f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_master_mask_bit_clear(unsigned long bit,struct mlxsw_sp_acl_erp_master_mask * mask)173f465261aSIdo Schimmel mlxsw_sp_acl_erp_master_mask_bit_clear(unsigned long bit,
174f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_master_mask *mask)
175f465261aSIdo Schimmel {
176f465261aSIdo Schimmel if (--mask->count[bit] == 0)
177f465261aSIdo Schimmel __clear_bit(bit, mask->bitmap);
178f465261aSIdo Schimmel }
179f465261aSIdo Schimmel
180f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_master_mask_update(struct mlxsw_sp_acl_erp_table * erp_table)181f465261aSIdo Schimmel mlxsw_sp_acl_erp_master_mask_update(struct mlxsw_sp_acl_erp_table *erp_table)
182f465261aSIdo Schimmel {
183f465261aSIdo Schimmel struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
184f465261aSIdo Schimmel struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;
185f465261aSIdo Schimmel char percr_pl[MLXSW_REG_PERCR_LEN];
186f465261aSIdo Schimmel char *master_mask;
187f465261aSIdo Schimmel
188f465261aSIdo Schimmel mlxsw_reg_percr_pack(percr_pl, region->id);
189f465261aSIdo Schimmel master_mask = mlxsw_reg_percr_master_mask_data(percr_pl);
190f465261aSIdo Schimmel bitmap_to_arr32((u32 *) master_mask, erp_table->master_mask.bitmap,
191f465261aSIdo Schimmel MLXSW_SP_ACL_TCAM_MASK_LEN);
192f465261aSIdo Schimmel
193f465261aSIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
194f465261aSIdo Schimmel }
195f465261aSIdo Schimmel
196f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_master_mask_set(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp_key * key)197f465261aSIdo Schimmel mlxsw_sp_acl_erp_master_mask_set(struct mlxsw_sp_acl_erp_table *erp_table,
198d07cd660SJiri Pirko struct mlxsw_sp_acl_erp_key *key)
199f465261aSIdo Schimmel {
200d07cd660SJiri Pirko DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
201f465261aSIdo Schimmel unsigned long bit;
202f465261aSIdo Schimmel int err;
203f465261aSIdo Schimmel
204d07cd660SJiri Pirko bitmap_from_arr32(mask_bitmap, (u32 *) key->mask,
205d07cd660SJiri Pirko MLXSW_SP_ACL_TCAM_MASK_LEN);
206d07cd660SJiri Pirko for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
207f465261aSIdo Schimmel mlxsw_sp_acl_erp_master_mask_bit_set(bit,
208f465261aSIdo Schimmel &erp_table->master_mask);
209f465261aSIdo Schimmel
210f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
211f465261aSIdo Schimmel if (err)
212f465261aSIdo Schimmel goto err_master_mask_update;
213f465261aSIdo Schimmel
214f465261aSIdo Schimmel return 0;
215f465261aSIdo Schimmel
216f465261aSIdo Schimmel err_master_mask_update:
217d07cd660SJiri Pirko for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
218f465261aSIdo Schimmel mlxsw_sp_acl_erp_master_mask_bit_clear(bit,
219f465261aSIdo Schimmel &erp_table->master_mask);
220f465261aSIdo Schimmel return err;
221f465261aSIdo Schimmel }
222f465261aSIdo Schimmel
223f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_master_mask_clear(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp_key * key)224f465261aSIdo Schimmel mlxsw_sp_acl_erp_master_mask_clear(struct mlxsw_sp_acl_erp_table *erp_table,
225d07cd660SJiri Pirko struct mlxsw_sp_acl_erp_key *key)
226f465261aSIdo Schimmel {
227d07cd660SJiri Pirko DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
228f465261aSIdo Schimmel unsigned long bit;
229f465261aSIdo Schimmel int err;
230f465261aSIdo Schimmel
231d07cd660SJiri Pirko bitmap_from_arr32(mask_bitmap, (u32 *) key->mask,
232d07cd660SJiri Pirko MLXSW_SP_ACL_TCAM_MASK_LEN);
233d07cd660SJiri Pirko for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
234f465261aSIdo Schimmel mlxsw_sp_acl_erp_master_mask_bit_clear(bit,
235f465261aSIdo Schimmel &erp_table->master_mask);
236f465261aSIdo Schimmel
237f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
238f465261aSIdo Schimmel if (err)
239f465261aSIdo Schimmel goto err_master_mask_update;
240f465261aSIdo Schimmel
241f465261aSIdo Schimmel return 0;
242f465261aSIdo Schimmel
243f465261aSIdo Schimmel err_master_mask_update:
244d07cd660SJiri Pirko for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
245f465261aSIdo Schimmel mlxsw_sp_acl_erp_master_mask_bit_set(bit,
246f465261aSIdo Schimmel &erp_table->master_mask);
247f465261aSIdo Schimmel return err;
248f465261aSIdo Schimmel }
249f465261aSIdo Schimmel
250f465261aSIdo Schimmel static struct mlxsw_sp_acl_erp *
mlxsw_sp_acl_erp_generic_create(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp_key * key)251f465261aSIdo Schimmel mlxsw_sp_acl_erp_generic_create(struct mlxsw_sp_acl_erp_table *erp_table,
252f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_key *key)
253f465261aSIdo Schimmel {
254f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp;
255f465261aSIdo Schimmel int err;
256f465261aSIdo Schimmel
257f465261aSIdo Schimmel erp = kzalloc(sizeof(*erp), GFP_KERNEL);
258f465261aSIdo Schimmel if (!erp)
259f465261aSIdo Schimmel return ERR_PTR(-ENOMEM);
260f465261aSIdo Schimmel
261f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_id_get(erp_table, &erp->id);
262f465261aSIdo Schimmel if (err)
263f465261aSIdo Schimmel goto err_erp_id_get;
264f465261aSIdo Schimmel
265f465261aSIdo Schimmel memcpy(&erp->key, key, sizeof(*key));
266f465261aSIdo Schimmel list_add(&erp->list, &erp_table->atcam_erps_list);
267f465261aSIdo Schimmel erp_table->num_atcam_erps++;
268f465261aSIdo Schimmel erp->erp_table = erp_table;
269f465261aSIdo Schimmel
270d07cd660SJiri Pirko err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key);
271f465261aSIdo Schimmel if (err)
272f465261aSIdo Schimmel goto err_master_mask_set;
273f465261aSIdo Schimmel
274f465261aSIdo Schimmel return erp;
275f465261aSIdo Schimmel
276f465261aSIdo Schimmel err_master_mask_set:
277f465261aSIdo Schimmel erp_table->num_atcam_erps--;
278f465261aSIdo Schimmel list_del(&erp->list);
279f465261aSIdo Schimmel mlxsw_sp_acl_erp_id_put(erp_table, erp->id);
280f465261aSIdo Schimmel err_erp_id_get:
281f465261aSIdo Schimmel kfree(erp);
282f465261aSIdo Schimmel return ERR_PTR(err);
283f465261aSIdo Schimmel }
284f465261aSIdo Schimmel
285f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_generic_destroy(struct mlxsw_sp_acl_erp * erp)286f465261aSIdo Schimmel mlxsw_sp_acl_erp_generic_destroy(struct mlxsw_sp_acl_erp *erp)
287f465261aSIdo Schimmel {
288f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
289f465261aSIdo Schimmel
290d07cd660SJiri Pirko mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
291f465261aSIdo Schimmel erp_table->num_atcam_erps--;
292f465261aSIdo Schimmel list_del(&erp->list);
293f465261aSIdo Schimmel mlxsw_sp_acl_erp_id_put(erp_table, erp->id);
294f465261aSIdo Schimmel kfree(erp);
295f465261aSIdo Schimmel }
296f465261aSIdo Schimmel
297f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core * erp_core,unsigned int num_erps,enum mlxsw_sp_acl_atcam_region_type region_type,unsigned long * p_index)298f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core *erp_core,
299f465261aSIdo Schimmel unsigned int num_erps,
300f465261aSIdo Schimmel enum mlxsw_sp_acl_atcam_region_type region_type,
301f465261aSIdo Schimmel unsigned long *p_index)
302f465261aSIdo Schimmel {
303f465261aSIdo Schimmel unsigned int num_rows, entry_size;
304*b1f02070SAmit Cohen unsigned long index;
305f465261aSIdo Schimmel
306f465261aSIdo Schimmel /* We only allow allocations of entire rows */
307f465261aSIdo Schimmel if (num_erps % erp_core->num_erp_banks != 0)
308f465261aSIdo Schimmel return -EINVAL;
309f465261aSIdo Schimmel
310f465261aSIdo Schimmel entry_size = erp_core->erpt_entries_size[region_type];
311f465261aSIdo Schimmel num_rows = num_erps / erp_core->num_erp_banks;
312f465261aSIdo Schimmel
313*b1f02070SAmit Cohen index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
314*b1f02070SAmit Cohen if (!index)
315f465261aSIdo Schimmel return -ENOBUFS;
316*b1f02070SAmit Cohen
317*b1f02070SAmit Cohen *p_index = index - MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
318f465261aSIdo Schimmel
319f465261aSIdo Schimmel return 0;
320f465261aSIdo Schimmel }
321f465261aSIdo Schimmel
322f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_table_free(struct mlxsw_sp_acl_erp_core * erp_core,unsigned int num_erps,enum mlxsw_sp_acl_atcam_region_type region_type,unsigned long index)323f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_free(struct mlxsw_sp_acl_erp_core *erp_core,
324f465261aSIdo Schimmel unsigned int num_erps,
325f465261aSIdo Schimmel enum mlxsw_sp_acl_atcam_region_type region_type,
326f465261aSIdo Schimmel unsigned long index)
327f465261aSIdo Schimmel {
328f465261aSIdo Schimmel unsigned long base_index;
329f465261aSIdo Schimmel unsigned int entry_size;
330f465261aSIdo Schimmel size_t size;
331f465261aSIdo Schimmel
332f465261aSIdo Schimmel entry_size = erp_core->erpt_entries_size[region_type];
333f465261aSIdo Schimmel base_index = index + MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
334f465261aSIdo Schimmel size = num_erps / erp_core->num_erp_banks * entry_size;
335f465261aSIdo Schimmel gen_pool_free(erp_core->erp_tables, base_index, size);
336f465261aSIdo Schimmel }
337f465261aSIdo Schimmel
338f465261aSIdo Schimmel static struct mlxsw_sp_acl_erp *
mlxsw_sp_acl_erp_table_master_rp(struct mlxsw_sp_acl_erp_table * erp_table)339f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_master_rp(struct mlxsw_sp_acl_erp_table *erp_table)
340f465261aSIdo Schimmel {
341f465261aSIdo Schimmel if (!list_is_singular(&erp_table->atcam_erps_list))
342f465261aSIdo Schimmel return NULL;
343f465261aSIdo Schimmel
344f465261aSIdo Schimmel return list_first_entry(&erp_table->atcam_erps_list,
345f465261aSIdo Schimmel struct mlxsw_sp_acl_erp, list);
346f465261aSIdo Schimmel }
347f465261aSIdo Schimmel
mlxsw_sp_acl_erp_index_get(struct mlxsw_sp_acl_erp_table * erp_table,u8 * p_index)348f465261aSIdo Schimmel static int mlxsw_sp_acl_erp_index_get(struct mlxsw_sp_acl_erp_table *erp_table,
349f465261aSIdo Schimmel u8 *p_index)
350f465261aSIdo Schimmel {
351f465261aSIdo Schimmel u8 index;
352f465261aSIdo Schimmel
353f465261aSIdo Schimmel index = find_first_zero_bit(erp_table->erp_index_bitmap,
354f465261aSIdo Schimmel erp_table->num_max_atcam_erps);
355f465261aSIdo Schimmel if (index < erp_table->num_max_atcam_erps) {
356f465261aSIdo Schimmel __set_bit(index, erp_table->erp_index_bitmap);
357f465261aSIdo Schimmel *p_index = index;
358f465261aSIdo Schimmel return 0;
359f465261aSIdo Schimmel }
360f465261aSIdo Schimmel
361f465261aSIdo Schimmel return -ENOBUFS;
362f465261aSIdo Schimmel }
363f465261aSIdo Schimmel
mlxsw_sp_acl_erp_index_put(struct mlxsw_sp_acl_erp_table * erp_table,u8 index)364f465261aSIdo Schimmel static void mlxsw_sp_acl_erp_index_put(struct mlxsw_sp_acl_erp_table *erp_table,
365f465261aSIdo Schimmel u8 index)
366f465261aSIdo Schimmel {
367f465261aSIdo Schimmel __clear_bit(index, erp_table->erp_index_bitmap);
368f465261aSIdo Schimmel }
369f465261aSIdo Schimmel
370f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_table_locate(const struct mlxsw_sp_acl_erp_table * erp_table,const struct mlxsw_sp_acl_erp * erp,u8 * p_erpt_bank,u8 * p_erpt_index)371f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_locate(const struct mlxsw_sp_acl_erp_table *erp_table,
372f465261aSIdo Schimmel const struct mlxsw_sp_acl_erp *erp,
373f465261aSIdo Schimmel u8 *p_erpt_bank, u8 *p_erpt_index)
374f465261aSIdo Schimmel {
375f465261aSIdo Schimmel unsigned int entry_size = mlxsw_sp_acl_erp_table_entry_size(erp_table);
376f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
377f465261aSIdo Schimmel unsigned int row;
378f465261aSIdo Schimmel
379f465261aSIdo Schimmel *p_erpt_bank = erp->index % erp_core->num_erp_banks;
380f465261aSIdo Schimmel row = erp->index / erp_core->num_erp_banks;
381f465261aSIdo Schimmel *p_erpt_index = erp_table->base_index + row * entry_size;
382f465261aSIdo Schimmel }
383f465261aSIdo Schimmel
384f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_table_erp_add(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp * erp)385f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
386f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp)
387f465261aSIdo Schimmel {
388f465261aSIdo Schimmel struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
389f465261aSIdo Schimmel enum mlxsw_reg_perpt_key_size key_size;
390f465261aSIdo Schimmel char perpt_pl[MLXSW_REG_PERPT_LEN];
391f465261aSIdo Schimmel u8 erpt_bank, erpt_index;
392f465261aSIdo Schimmel
393f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index);
394f465261aSIdo Schimmel key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type;
395f465261aSIdo Schimmel mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id,
396f465261aSIdo Schimmel 0, erp_table->base_index, erp->index,
397f465261aSIdo Schimmel erp->key.mask);
398f465261aSIdo Schimmel mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap,
399f465261aSIdo Schimmel MLXSW_SP_ACL_ERP_MAX_PER_REGION);
400f465261aSIdo Schimmel mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, true);
401f465261aSIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl);
402f465261aSIdo Schimmel }
403f465261aSIdo Schimmel
mlxsw_sp_acl_erp_table_erp_del(struct mlxsw_sp_acl_erp * erp)404f465261aSIdo Schimmel static void mlxsw_sp_acl_erp_table_erp_del(struct mlxsw_sp_acl_erp *erp)
405f465261aSIdo Schimmel {
406f465261aSIdo Schimmel char empty_mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 };
407f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
408f465261aSIdo Schimmel struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
409f465261aSIdo Schimmel enum mlxsw_reg_perpt_key_size key_size;
410f465261aSIdo Schimmel char perpt_pl[MLXSW_REG_PERPT_LEN];
411f465261aSIdo Schimmel u8 erpt_bank, erpt_index;
412f465261aSIdo Schimmel
413f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index);
414f465261aSIdo Schimmel key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type;
415f465261aSIdo Schimmel mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id,
416f465261aSIdo Schimmel 0, erp_table->base_index, erp->index, empty_mask);
417f465261aSIdo Schimmel mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap,
418f465261aSIdo Schimmel MLXSW_SP_ACL_ERP_MAX_PER_REGION);
419f465261aSIdo Schimmel mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, false);
420f465261aSIdo Schimmel mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl);
421f465261aSIdo Schimmel }
422f465261aSIdo Schimmel
423f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_table_enable(struct mlxsw_sp_acl_erp_table * erp_table,bool ctcam_le)424b17b113eSIdo Schimmel mlxsw_sp_acl_erp_table_enable(struct mlxsw_sp_acl_erp_table *erp_table,
425b17b113eSIdo Schimmel bool ctcam_le)
426f465261aSIdo Schimmel {
427f465261aSIdo Schimmel struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
428f465261aSIdo Schimmel struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
429f465261aSIdo Schimmel char pererp_pl[MLXSW_REG_PERERP_LEN];
430f465261aSIdo Schimmel
431b17b113eSIdo Schimmel mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
432f465261aSIdo Schimmel erp_table->base_index, 0);
433f465261aSIdo Schimmel mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
434f465261aSIdo Schimmel MLXSW_SP_ACL_ERP_MAX_PER_REGION);
435f465261aSIdo Schimmel
436f465261aSIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
437f465261aSIdo Schimmel }
438f465261aSIdo Schimmel
439f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_table_disable(struct mlxsw_sp_acl_erp_table * erp_table)440f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_disable(struct mlxsw_sp_acl_erp_table *erp_table)
441f465261aSIdo Schimmel {
442f465261aSIdo Schimmel struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
443f465261aSIdo Schimmel struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
444f465261aSIdo Schimmel char pererp_pl[MLXSW_REG_PERERP_LEN];
445f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *master_rp;
446f465261aSIdo Schimmel
447f465261aSIdo Schimmel master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
448b17b113eSIdo Schimmel /* It is possible we do not have a master RP when we disable the
449b17b113eSIdo Schimmel * table when there are no rules in the A-TCAM and the last C-TCAM
450b17b113eSIdo Schimmel * rule is deleted
451b17b113eSIdo Schimmel */
452f465261aSIdo Schimmel mlxsw_reg_pererp_pack(pererp_pl, region->id, false, false, 0, 0,
453b17b113eSIdo Schimmel master_rp ? master_rp->id : 0);
454f465261aSIdo Schimmel mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
455f465261aSIdo Schimmel }
456f465261aSIdo Schimmel
457f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_table_relocate(struct mlxsw_sp_acl_erp_table * erp_table)458f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_relocate(struct mlxsw_sp_acl_erp_table *erp_table)
459f465261aSIdo Schimmel {
460f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp;
461f465261aSIdo Schimmel int err;
462f465261aSIdo Schimmel
463f465261aSIdo Schimmel list_for_each_entry(erp, &erp_table->atcam_erps_list, list) {
464f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
465f465261aSIdo Schimmel if (err)
466f465261aSIdo Schimmel goto err_table_erp_add;
467f465261aSIdo Schimmel }
468f465261aSIdo Schimmel
469f465261aSIdo Schimmel return 0;
470f465261aSIdo Schimmel
471f465261aSIdo Schimmel err_table_erp_add:
472f465261aSIdo Schimmel list_for_each_entry_continue_reverse(erp, &erp_table->atcam_erps_list,
473f465261aSIdo Schimmel list)
474f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_erp_del(erp);
475f465261aSIdo Schimmel return err;
476f465261aSIdo Schimmel }
477f465261aSIdo Schimmel
478f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_table_expand(struct mlxsw_sp_acl_erp_table * erp_table)479f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_expand(struct mlxsw_sp_acl_erp_table *erp_table)
480f465261aSIdo Schimmel {
481f465261aSIdo Schimmel unsigned int num_erps, old_num_erps = erp_table->num_max_atcam_erps;
482f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
483f465261aSIdo Schimmel unsigned long old_base_index = erp_table->base_index;
484b17b113eSIdo Schimmel bool ctcam_le = erp_table->num_ctcam_erps > 0;
485f465261aSIdo Schimmel int err;
486f465261aSIdo Schimmel
487f465261aSIdo Schimmel if (erp_table->num_atcam_erps < erp_table->num_max_atcam_erps)
488f465261aSIdo Schimmel return 0;
489f465261aSIdo Schimmel
490f465261aSIdo Schimmel if (erp_table->num_max_atcam_erps == MLXSW_SP_ACL_ERP_MAX_PER_REGION)
491f465261aSIdo Schimmel return -ENOBUFS;
492f465261aSIdo Schimmel
493f465261aSIdo Schimmel num_erps = old_num_erps + erp_core->num_erp_banks;
494f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_table_alloc(erp_core, num_erps,
495f465261aSIdo Schimmel erp_table->aregion->type,
496f465261aSIdo Schimmel &erp_table->base_index);
497f465261aSIdo Schimmel if (err)
498f465261aSIdo Schimmel return err;
499f465261aSIdo Schimmel erp_table->num_max_atcam_erps = num_erps;
500f465261aSIdo Schimmel
501f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_table_relocate(erp_table);
502f465261aSIdo Schimmel if (err)
503f465261aSIdo Schimmel goto err_table_relocate;
504f465261aSIdo Schimmel
505b17b113eSIdo Schimmel err = mlxsw_sp_acl_erp_table_enable(erp_table, ctcam_le);
506f465261aSIdo Schimmel if (err)
507f465261aSIdo Schimmel goto err_table_enable;
508f465261aSIdo Schimmel
509f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_free(erp_core, old_num_erps,
510f465261aSIdo Schimmel erp_table->aregion->type, old_base_index);
511f465261aSIdo Schimmel
512f465261aSIdo Schimmel return 0;
513f465261aSIdo Schimmel
514f465261aSIdo Schimmel err_table_enable:
515f465261aSIdo Schimmel err_table_relocate:
516f465261aSIdo Schimmel erp_table->num_max_atcam_erps = old_num_erps;
517f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_free(erp_core, num_erps,
518f465261aSIdo Schimmel erp_table->aregion->type,
519f465261aSIdo Schimmel erp_table->base_index);
520f465261aSIdo Schimmel erp_table->base_index = old_base_index;
521f465261aSIdo Schimmel return err;
522f465261aSIdo Schimmel }
523f465261aSIdo Schimmel
524f465261aSIdo Schimmel static int
mlxsw_acl_erp_table_bf_add(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp * erp)525135fd957SNir Dotan mlxsw_acl_erp_table_bf_add(struct mlxsw_sp_acl_erp_table *erp_table,
526135fd957SNir Dotan struct mlxsw_sp_acl_erp *erp)
527135fd957SNir Dotan {
528135fd957SNir Dotan struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
529135fd957SNir Dotan unsigned int erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
530135fd957SNir Dotan struct mlxsw_sp_acl_atcam_entry *aentry;
531135fd957SNir Dotan int err;
532135fd957SNir Dotan
533135fd957SNir Dotan list_for_each_entry(aentry, &aregion->entries_list, list) {
534135fd957SNir Dotan err = mlxsw_sp_acl_bf_entry_add(aregion->region->mlxsw_sp,
535135fd957SNir Dotan erp_table->erp_core->bf,
536135fd957SNir Dotan aregion, erp_bank, aentry);
537135fd957SNir Dotan if (err)
538135fd957SNir Dotan goto bf_entry_add_err;
539135fd957SNir Dotan }
540135fd957SNir Dotan
541135fd957SNir Dotan return 0;
542135fd957SNir Dotan
543135fd957SNir Dotan bf_entry_add_err:
544135fd957SNir Dotan list_for_each_entry_continue_reverse(aentry, &aregion->entries_list,
545135fd957SNir Dotan list)
546135fd957SNir Dotan mlxsw_sp_acl_bf_entry_del(aregion->region->mlxsw_sp,
547135fd957SNir Dotan erp_table->erp_core->bf,
548135fd957SNir Dotan aregion, erp_bank, aentry);
549135fd957SNir Dotan return err;
550135fd957SNir Dotan }
551135fd957SNir Dotan
552135fd957SNir Dotan static void
mlxsw_acl_erp_table_bf_del(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp * erp)553135fd957SNir Dotan mlxsw_acl_erp_table_bf_del(struct mlxsw_sp_acl_erp_table *erp_table,
554135fd957SNir Dotan struct mlxsw_sp_acl_erp *erp)
555135fd957SNir Dotan {
556135fd957SNir Dotan struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
557135fd957SNir Dotan unsigned int erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
558135fd957SNir Dotan struct mlxsw_sp_acl_atcam_entry *aentry;
559135fd957SNir Dotan
560135fd957SNir Dotan list_for_each_entry_reverse(aentry, &aregion->entries_list, list)
561135fd957SNir Dotan mlxsw_sp_acl_bf_entry_del(aregion->region->mlxsw_sp,
562135fd957SNir Dotan erp_table->erp_core->bf,
563135fd957SNir Dotan aregion, erp_bank, aentry);
564135fd957SNir Dotan }
565135fd957SNir Dotan
566135fd957SNir Dotan static int
mlxsw_sp_acl_erp_region_table_trans(struct mlxsw_sp_acl_erp_table * erp_table)567f465261aSIdo Schimmel mlxsw_sp_acl_erp_region_table_trans(struct mlxsw_sp_acl_erp_table *erp_table)
568f465261aSIdo Schimmel {
569f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
570f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *master_rp;
571f465261aSIdo Schimmel int err;
572f465261aSIdo Schimmel
573f465261aSIdo Schimmel /* Initially, allocate a single eRP row. Expand later as needed */
574f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_table_alloc(erp_core, erp_core->num_erp_banks,
575f465261aSIdo Schimmel erp_table->aregion->type,
576f465261aSIdo Schimmel &erp_table->base_index);
577f465261aSIdo Schimmel if (err)
578f465261aSIdo Schimmel return err;
579f465261aSIdo Schimmel erp_table->num_max_atcam_erps = erp_core->num_erp_banks;
580f465261aSIdo Schimmel
581f465261aSIdo Schimmel /* Transition the sole RP currently configured (the master RP)
582f465261aSIdo Schimmel * to the eRP table
583f465261aSIdo Schimmel */
584f465261aSIdo Schimmel master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
585f465261aSIdo Schimmel if (!master_rp) {
586f465261aSIdo Schimmel err = -EINVAL;
587f465261aSIdo Schimmel goto err_table_master_rp;
588f465261aSIdo Schimmel }
589f465261aSIdo Schimmel
590dd97d85fSNir Dotan /* Make sure the master RP is using a valid index, as
591dd97d85fSNir Dotan * only a single eRP row is currently allocated.
592f465261aSIdo Schimmel */
593dd97d85fSNir Dotan master_rp->index = 0;
594f465261aSIdo Schimmel __set_bit(master_rp->index, erp_table->erp_index_bitmap);
595f465261aSIdo Schimmel
596f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_table_erp_add(erp_table, master_rp);
597f465261aSIdo Schimmel if (err)
598f465261aSIdo Schimmel goto err_table_master_rp_add;
599f465261aSIdo Schimmel
600135fd957SNir Dotan /* Update Bloom filter before enabling eRP table, as rules
601135fd957SNir Dotan * on the master RP were not set to Bloom filter up to this
602135fd957SNir Dotan * point.
603135fd957SNir Dotan */
604135fd957SNir Dotan err = mlxsw_acl_erp_table_bf_add(erp_table, master_rp);
605135fd957SNir Dotan if (err)
606135fd957SNir Dotan goto err_table_bf_add;
607135fd957SNir Dotan
608b17b113eSIdo Schimmel err = mlxsw_sp_acl_erp_table_enable(erp_table, false);
609f465261aSIdo Schimmel if (err)
610f465261aSIdo Schimmel goto err_table_enable;
611f465261aSIdo Schimmel
612f465261aSIdo Schimmel return 0;
613f465261aSIdo Schimmel
614f465261aSIdo Schimmel err_table_enable:
615135fd957SNir Dotan mlxsw_acl_erp_table_bf_del(erp_table, master_rp);
616135fd957SNir Dotan err_table_bf_add:
617f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_erp_del(master_rp);
618f465261aSIdo Schimmel err_table_master_rp_add:
619f465261aSIdo Schimmel __clear_bit(master_rp->index, erp_table->erp_index_bitmap);
620f465261aSIdo Schimmel err_table_master_rp:
621f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps,
622f465261aSIdo Schimmel erp_table->aregion->type,
623f465261aSIdo Schimmel erp_table->base_index);
624f465261aSIdo Schimmel return err;
625f465261aSIdo Schimmel }
626f465261aSIdo Schimmel
627f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_region_master_mask_trans(struct mlxsw_sp_acl_erp_table * erp_table)628f465261aSIdo Schimmel mlxsw_sp_acl_erp_region_master_mask_trans(struct mlxsw_sp_acl_erp_table *erp_table)
629f465261aSIdo Schimmel {
630f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
631f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *master_rp;
632f465261aSIdo Schimmel
633f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_disable(erp_table);
634f465261aSIdo Schimmel master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
635f465261aSIdo Schimmel if (!master_rp)
636f465261aSIdo Schimmel return;
637135fd957SNir Dotan mlxsw_acl_erp_table_bf_del(erp_table, master_rp);
638f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_erp_del(master_rp);
639f465261aSIdo Schimmel __clear_bit(master_rp->index, erp_table->erp_index_bitmap);
640f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps,
641f465261aSIdo Schimmel erp_table->aregion->type,
642f465261aSIdo Schimmel erp_table->base_index);
643f465261aSIdo Schimmel }
644f465261aSIdo Schimmel
645f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_region_erp_add(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp * erp)646f465261aSIdo Schimmel mlxsw_sp_acl_erp_region_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
647f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp)
648f465261aSIdo Schimmel {
649f465261aSIdo Schimmel struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
650f465261aSIdo Schimmel struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
651b17b113eSIdo Schimmel bool ctcam_le = erp_table->num_ctcam_erps > 0;
652f465261aSIdo Schimmel char pererp_pl[MLXSW_REG_PERERP_LEN];
653f465261aSIdo Schimmel
654b17b113eSIdo Schimmel mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
655f465261aSIdo Schimmel erp_table->base_index, 0);
656f465261aSIdo Schimmel mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
657f465261aSIdo Schimmel MLXSW_SP_ACL_ERP_MAX_PER_REGION);
658f465261aSIdo Schimmel mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, true);
659f465261aSIdo Schimmel
660f465261aSIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
661f465261aSIdo Schimmel }
662f465261aSIdo Schimmel
mlxsw_sp_acl_erp_region_erp_del(struct mlxsw_sp_acl_erp * erp)663f465261aSIdo Schimmel static void mlxsw_sp_acl_erp_region_erp_del(struct mlxsw_sp_acl_erp *erp)
664f465261aSIdo Schimmel {
665f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
666f465261aSIdo Schimmel struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
667f465261aSIdo Schimmel struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
668b17b113eSIdo Schimmel bool ctcam_le = erp_table->num_ctcam_erps > 0;
669f465261aSIdo Schimmel char pererp_pl[MLXSW_REG_PERERP_LEN];
670f465261aSIdo Schimmel
671b17b113eSIdo Schimmel mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
672f465261aSIdo Schimmel erp_table->base_index, 0);
673f465261aSIdo Schimmel mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
674f465261aSIdo Schimmel MLXSW_SP_ACL_ERP_MAX_PER_REGION);
675f465261aSIdo Schimmel mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, false);
676f465261aSIdo Schimmel
677f465261aSIdo Schimmel mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
678f465261aSIdo Schimmel }
679f465261aSIdo Schimmel
680b17b113eSIdo Schimmel static int
mlxsw_sp_acl_erp_region_ctcam_enable(struct mlxsw_sp_acl_erp_table * erp_table)681b17b113eSIdo Schimmel mlxsw_sp_acl_erp_region_ctcam_enable(struct mlxsw_sp_acl_erp_table *erp_table)
682b17b113eSIdo Schimmel {
683b17b113eSIdo Schimmel /* No need to re-enable lookup in the C-TCAM */
684b17b113eSIdo Schimmel if (erp_table->num_ctcam_erps > 1)
685b17b113eSIdo Schimmel return 0;
686b17b113eSIdo Schimmel
687b17b113eSIdo Schimmel return mlxsw_sp_acl_erp_table_enable(erp_table, true);
688b17b113eSIdo Schimmel }
689b17b113eSIdo Schimmel
690b17b113eSIdo Schimmel static void
mlxsw_sp_acl_erp_region_ctcam_disable(struct mlxsw_sp_acl_erp_table * erp_table)691b17b113eSIdo Schimmel mlxsw_sp_acl_erp_region_ctcam_disable(struct mlxsw_sp_acl_erp_table *erp_table)
692b17b113eSIdo Schimmel {
693b17b113eSIdo Schimmel /* Only disable C-TCAM lookup when last C-TCAM eRP is deleted */
694b17b113eSIdo Schimmel if (erp_table->num_ctcam_erps > 1)
695b17b113eSIdo Schimmel return;
696b17b113eSIdo Schimmel
697b17b113eSIdo Schimmel mlxsw_sp_acl_erp_table_enable(erp_table, false);
698b17b113eSIdo Schimmel }
699b17b113eSIdo Schimmel
700c293ba34SJiri Pirko static int
__mlxsw_sp_acl_erp_table_other_inc(struct mlxsw_sp_acl_erp_table * erp_table,unsigned int * inc_num)701c293ba34SJiri Pirko __mlxsw_sp_acl_erp_table_other_inc(struct mlxsw_sp_acl_erp_table *erp_table,
702c293ba34SJiri Pirko unsigned int *inc_num)
703b17b113eSIdo Schimmel {
704c293ba34SJiri Pirko int err;
705c293ba34SJiri Pirko
706c22291f7SJiri Pirko /* If there are C-TCAM eRP or deltas in use we need to transition
707c293ba34SJiri Pirko * the region to use eRP table, if it is not already done
708c293ba34SJiri Pirko */
709f5a2852eSNir Dotan if (!mlxsw_sp_acl_erp_table_is_used(erp_table)) {
710c293ba34SJiri Pirko err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
711c293ba34SJiri Pirko if (err)
712c293ba34SJiri Pirko return err;
713c293ba34SJiri Pirko }
714c293ba34SJiri Pirko
715c22291f7SJiri Pirko /* When C-TCAM or deltas are used, the eRP table must be used */
716c293ba34SJiri Pirko if (erp_table->ops != &erp_multiple_masks_ops)
717c293ba34SJiri Pirko erp_table->ops = &erp_multiple_masks_ops;
718c293ba34SJiri Pirko
719c293ba34SJiri Pirko (*inc_num)++;
720c293ba34SJiri Pirko
721c293ba34SJiri Pirko return 0;
722c293ba34SJiri Pirko }
723c293ba34SJiri Pirko
mlxsw_sp_acl_erp_ctcam_inc(struct mlxsw_sp_acl_erp_table * erp_table)724c293ba34SJiri Pirko static int mlxsw_sp_acl_erp_ctcam_inc(struct mlxsw_sp_acl_erp_table *erp_table)
725c293ba34SJiri Pirko {
726c293ba34SJiri Pirko return __mlxsw_sp_acl_erp_table_other_inc(erp_table,
727c293ba34SJiri Pirko &erp_table->num_ctcam_erps);
728c293ba34SJiri Pirko }
729c293ba34SJiri Pirko
mlxsw_sp_acl_erp_delta_inc(struct mlxsw_sp_acl_erp_table * erp_table)730c22291f7SJiri Pirko static int mlxsw_sp_acl_erp_delta_inc(struct mlxsw_sp_acl_erp_table *erp_table)
731c22291f7SJiri Pirko {
732c22291f7SJiri Pirko return __mlxsw_sp_acl_erp_table_other_inc(erp_table,
733c22291f7SJiri Pirko &erp_table->num_deltas);
734c22291f7SJiri Pirko }
735c22291f7SJiri Pirko
736c293ba34SJiri Pirko static void
__mlxsw_sp_acl_erp_table_other_dec(struct mlxsw_sp_acl_erp_table * erp_table,unsigned int * dec_num)737c293ba34SJiri Pirko __mlxsw_sp_acl_erp_table_other_dec(struct mlxsw_sp_acl_erp_table *erp_table,
738c293ba34SJiri Pirko unsigned int *dec_num)
739c293ba34SJiri Pirko {
740c293ba34SJiri Pirko (*dec_num)--;
741c293ba34SJiri Pirko
742c22291f7SJiri Pirko /* If there are no C-TCAM eRP or deltas in use, the state we
743c293ba34SJiri Pirko * transition to depends on the number of A-TCAM eRPs currently
744c293ba34SJiri Pirko * in use.
745c293ba34SJiri Pirko */
746c22291f7SJiri Pirko if (erp_table->num_ctcam_erps > 0 || erp_table->num_deltas > 0)
747c293ba34SJiri Pirko return;
748c293ba34SJiri Pirko
749b17b113eSIdo Schimmel switch (erp_table->num_atcam_erps) {
750b17b113eSIdo Schimmel case 2:
751b17b113eSIdo Schimmel /* Keep using the eRP table, but correctly set the
752b17b113eSIdo Schimmel * operations pointer so that when an A-TCAM eRP is
753b17b113eSIdo Schimmel * deleted we will transition to use the master mask
754b17b113eSIdo Schimmel */
755b17b113eSIdo Schimmel erp_table->ops = &erp_two_masks_ops;
756b17b113eSIdo Schimmel break;
757b17b113eSIdo Schimmel case 1:
758b17b113eSIdo Schimmel /* We only kept the eRP table because we had C-TCAM
759b17b113eSIdo Schimmel * eRPs in use. Now that the last C-TCAM eRP is gone we
760b17b113eSIdo Schimmel * can stop using the table and transition to use the
761b17b113eSIdo Schimmel * master mask
762b17b113eSIdo Schimmel */
763b17b113eSIdo Schimmel mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
764b17b113eSIdo Schimmel erp_table->ops = &erp_single_mask_ops;
765b17b113eSIdo Schimmel break;
766b17b113eSIdo Schimmel case 0:
767b17b113eSIdo Schimmel /* There are no more eRPs of any kind used by the region
768b17b113eSIdo Schimmel * so free its eRP table and transition to initial state
769b17b113eSIdo Schimmel */
770b17b113eSIdo Schimmel mlxsw_sp_acl_erp_table_disable(erp_table);
771b17b113eSIdo Schimmel mlxsw_sp_acl_erp_table_free(erp_table->erp_core,
772b17b113eSIdo Schimmel erp_table->num_max_atcam_erps,
773b17b113eSIdo Schimmel erp_table->aregion->type,
774b17b113eSIdo Schimmel erp_table->base_index);
775b17b113eSIdo Schimmel erp_table->ops = &erp_no_mask_ops;
776b17b113eSIdo Schimmel break;
777b17b113eSIdo Schimmel default:
778b17b113eSIdo Schimmel break;
779b17b113eSIdo Schimmel }
780b17b113eSIdo Schimmel }
781b17b113eSIdo Schimmel
mlxsw_sp_acl_erp_ctcam_dec(struct mlxsw_sp_acl_erp_table * erp_table)782c293ba34SJiri Pirko static void mlxsw_sp_acl_erp_ctcam_dec(struct mlxsw_sp_acl_erp_table *erp_table)
783c293ba34SJiri Pirko {
784c293ba34SJiri Pirko __mlxsw_sp_acl_erp_table_other_dec(erp_table,
785c293ba34SJiri Pirko &erp_table->num_ctcam_erps);
786c293ba34SJiri Pirko }
787c293ba34SJiri Pirko
mlxsw_sp_acl_erp_delta_dec(struct mlxsw_sp_acl_erp_table * erp_table)788c22291f7SJiri Pirko static void mlxsw_sp_acl_erp_delta_dec(struct mlxsw_sp_acl_erp_table *erp_table)
789c22291f7SJiri Pirko {
790c22291f7SJiri Pirko __mlxsw_sp_acl_erp_table_other_dec(erp_table,
791c22291f7SJiri Pirko &erp_table->num_deltas);
792c22291f7SJiri Pirko }
793c22291f7SJiri Pirko
794b17b113eSIdo Schimmel static struct mlxsw_sp_acl_erp *
mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp_key * key)795c293ba34SJiri Pirko mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
796b17b113eSIdo Schimmel struct mlxsw_sp_acl_erp_key *key)
797b17b113eSIdo Schimmel {
798b17b113eSIdo Schimmel struct mlxsw_sp_acl_erp *erp;
799b17b113eSIdo Schimmel int err;
800b17b113eSIdo Schimmel
801b17b113eSIdo Schimmel erp = kzalloc(sizeof(*erp), GFP_KERNEL);
802b17b113eSIdo Schimmel if (!erp)
803b17b113eSIdo Schimmel return ERR_PTR(-ENOMEM);
804b17b113eSIdo Schimmel
805b17b113eSIdo Schimmel memcpy(&erp->key, key, sizeof(*key));
806b17b113eSIdo Schimmel bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask,
807b17b113eSIdo Schimmel MLXSW_SP_ACL_TCAM_MASK_LEN);
808c293ba34SJiri Pirko
809c293ba34SJiri Pirko err = mlxsw_sp_acl_erp_ctcam_inc(erp_table);
810c293ba34SJiri Pirko if (err)
811c293ba34SJiri Pirko goto err_erp_ctcam_inc;
812c293ba34SJiri Pirko
813b17b113eSIdo Schimmel erp->erp_table = erp_table;
814b17b113eSIdo Schimmel
815d07cd660SJiri Pirko err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key);
816b17b113eSIdo Schimmel if (err)
817b17b113eSIdo Schimmel goto err_master_mask_set;
818b17b113eSIdo Schimmel
819b17b113eSIdo Schimmel err = mlxsw_sp_acl_erp_region_ctcam_enable(erp_table);
820b17b113eSIdo Schimmel if (err)
821b17b113eSIdo Schimmel goto err_erp_region_ctcam_enable;
822b17b113eSIdo Schimmel
823b17b113eSIdo Schimmel return erp;
824b17b113eSIdo Schimmel
825b17b113eSIdo Schimmel err_erp_region_ctcam_enable:
826d07cd660SJiri Pirko mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
827b17b113eSIdo Schimmel err_master_mask_set:
828c293ba34SJiri Pirko mlxsw_sp_acl_erp_ctcam_dec(erp_table);
829c293ba34SJiri Pirko err_erp_ctcam_inc:
830b17b113eSIdo Schimmel kfree(erp);
831b17b113eSIdo Schimmel return ERR_PTR(err);
832b17b113eSIdo Schimmel }
833b17b113eSIdo Schimmel
834b17b113eSIdo Schimmel static void
mlxsw_sp_acl_erp_ctcam_mask_destroy(struct mlxsw_sp_acl_erp * erp)835b17b113eSIdo Schimmel mlxsw_sp_acl_erp_ctcam_mask_destroy(struct mlxsw_sp_acl_erp *erp)
836b17b113eSIdo Schimmel {
837b17b113eSIdo Schimmel struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
838b17b113eSIdo Schimmel
839b17b113eSIdo Schimmel mlxsw_sp_acl_erp_region_ctcam_disable(erp_table);
840d07cd660SJiri Pirko mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
841c293ba34SJiri Pirko mlxsw_sp_acl_erp_ctcam_dec(erp_table);
842b17b113eSIdo Schimmel kfree(erp);
843b17b113eSIdo Schimmel }
844b17b113eSIdo Schimmel
845f465261aSIdo Schimmel static struct mlxsw_sp_acl_erp *
mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp_key * key)846f465261aSIdo Schimmel mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
847f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_key *key)
848f465261aSIdo Schimmel {
849f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp;
850f465261aSIdo Schimmel int err;
851f465261aSIdo Schimmel
852b17b113eSIdo Schimmel if (key->ctcam)
853c293ba34SJiri Pirko return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
854b17b113eSIdo Schimmel
855f465261aSIdo Schimmel /* Expand the eRP table for the new eRP, if needed */
856f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_table_expand(erp_table);
857f465261aSIdo Schimmel if (err)
858f465261aSIdo Schimmel return ERR_PTR(err);
859f465261aSIdo Schimmel
860f465261aSIdo Schimmel erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
861f465261aSIdo Schimmel if (IS_ERR(erp))
862f465261aSIdo Schimmel return erp;
863f465261aSIdo Schimmel
864f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
865f465261aSIdo Schimmel if (err)
866f465261aSIdo Schimmel goto err_erp_index_get;
867f465261aSIdo Schimmel
868f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
869f465261aSIdo Schimmel if (err)
870f465261aSIdo Schimmel goto err_table_erp_add;
871f465261aSIdo Schimmel
872f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
873f465261aSIdo Schimmel if (err)
874f465261aSIdo Schimmel goto err_region_erp_add;
875f465261aSIdo Schimmel
876f465261aSIdo Schimmel erp_table->ops = &erp_multiple_masks_ops;
877f465261aSIdo Schimmel
878f465261aSIdo Schimmel return erp;
879f465261aSIdo Schimmel
880f465261aSIdo Schimmel err_region_erp_add:
881f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_erp_del(erp);
882f465261aSIdo Schimmel err_table_erp_add:
883f465261aSIdo Schimmel mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
884f465261aSIdo Schimmel err_erp_index_get:
885f465261aSIdo Schimmel mlxsw_sp_acl_erp_generic_destroy(erp);
886f465261aSIdo Schimmel return ERR_PTR(err);
887f465261aSIdo Schimmel }
888f465261aSIdo Schimmel
889f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp * erp)890f465261aSIdo Schimmel mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
891f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp)
892f465261aSIdo Schimmel {
893b17b113eSIdo Schimmel if (erp->key.ctcam)
894b17b113eSIdo Schimmel return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
895b17b113eSIdo Schimmel
896f465261aSIdo Schimmel mlxsw_sp_acl_erp_region_erp_del(erp);
897f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_erp_del(erp);
898f465261aSIdo Schimmel mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
899f465261aSIdo Schimmel mlxsw_sp_acl_erp_generic_destroy(erp);
900f465261aSIdo Schimmel
901c22291f7SJiri Pirko if (erp_table->num_atcam_erps == 2 && erp_table->num_ctcam_erps == 0 &&
902c22291f7SJiri Pirko erp_table->num_deltas == 0)
903f465261aSIdo Schimmel erp_table->ops = &erp_two_masks_ops;
904f465261aSIdo Schimmel }
905f465261aSIdo Schimmel
906f465261aSIdo Schimmel static struct mlxsw_sp_acl_erp *
mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp_key * key)907f465261aSIdo Schimmel mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
908f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_key *key)
909f465261aSIdo Schimmel {
910f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp;
911f465261aSIdo Schimmel int err;
912f465261aSIdo Schimmel
913b17b113eSIdo Schimmel if (key->ctcam)
914b17b113eSIdo Schimmel return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
915b17b113eSIdo Schimmel
916f465261aSIdo Schimmel /* Transition to use eRP table instead of master mask */
917f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
918f465261aSIdo Schimmel if (err)
919f465261aSIdo Schimmel return ERR_PTR(err);
920f465261aSIdo Schimmel
921f465261aSIdo Schimmel erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
922f465261aSIdo Schimmel if (IS_ERR(erp)) {
923f465261aSIdo Schimmel err = PTR_ERR(erp);
924f465261aSIdo Schimmel goto err_erp_create;
925f465261aSIdo Schimmel }
926f465261aSIdo Schimmel
927f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
928f465261aSIdo Schimmel if (err)
929f465261aSIdo Schimmel goto err_erp_index_get;
930f465261aSIdo Schimmel
931f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
932f465261aSIdo Schimmel if (err)
933f465261aSIdo Schimmel goto err_table_erp_add;
934f465261aSIdo Schimmel
935f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
936f465261aSIdo Schimmel if (err)
937f465261aSIdo Schimmel goto err_region_erp_add;
938f465261aSIdo Schimmel
939f465261aSIdo Schimmel erp_table->ops = &erp_two_masks_ops;
940f465261aSIdo Schimmel
941f465261aSIdo Schimmel return erp;
942f465261aSIdo Schimmel
943f465261aSIdo Schimmel err_region_erp_add:
944f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_erp_del(erp);
945f465261aSIdo Schimmel err_table_erp_add:
946f465261aSIdo Schimmel mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
947f465261aSIdo Schimmel err_erp_index_get:
948f465261aSIdo Schimmel mlxsw_sp_acl_erp_generic_destroy(erp);
949f465261aSIdo Schimmel err_erp_create:
950f465261aSIdo Schimmel mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
951f465261aSIdo Schimmel return ERR_PTR(err);
952f465261aSIdo Schimmel }
953f465261aSIdo Schimmel
954f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp * erp)955f465261aSIdo Schimmel mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
956f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp)
957f465261aSIdo Schimmel {
958b17b113eSIdo Schimmel if (erp->key.ctcam)
959b17b113eSIdo Schimmel return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
960b17b113eSIdo Schimmel
961f465261aSIdo Schimmel mlxsw_sp_acl_erp_region_erp_del(erp);
962f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_erp_del(erp);
963f465261aSIdo Schimmel mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
964f465261aSIdo Schimmel mlxsw_sp_acl_erp_generic_destroy(erp);
965f465261aSIdo Schimmel /* Transition to use master mask instead of eRP table */
966f465261aSIdo Schimmel mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
967f465261aSIdo Schimmel
968f465261aSIdo Schimmel erp_table->ops = &erp_single_mask_ops;
969f465261aSIdo Schimmel }
970f465261aSIdo Schimmel
971f465261aSIdo Schimmel static struct mlxsw_sp_acl_erp *
mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp_key * key)972f465261aSIdo Schimmel mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
973f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_key *key)
974f465261aSIdo Schimmel {
975f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp;
976f465261aSIdo Schimmel
977b17b113eSIdo Schimmel if (key->ctcam)
978b17b113eSIdo Schimmel return ERR_PTR(-EINVAL);
979b17b113eSIdo Schimmel
980f465261aSIdo Schimmel erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
981f465261aSIdo Schimmel if (IS_ERR(erp))
982f465261aSIdo Schimmel return erp;
983f465261aSIdo Schimmel
984f465261aSIdo Schimmel erp_table->ops = &erp_single_mask_ops;
985f465261aSIdo Schimmel
986f465261aSIdo Schimmel return erp;
987f465261aSIdo Schimmel }
988f465261aSIdo Schimmel
989f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp * erp)990f465261aSIdo Schimmel mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
991f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp)
992f465261aSIdo Schimmel {
993f465261aSIdo Schimmel mlxsw_sp_acl_erp_generic_destroy(erp);
994f465261aSIdo Schimmel erp_table->ops = &erp_no_mask_ops;
995f465261aSIdo Schimmel }
996f465261aSIdo Schimmel
997f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table * erp_table,struct mlxsw_sp_acl_erp * erp)998f465261aSIdo Schimmel mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
999f465261aSIdo Schimmel struct mlxsw_sp_acl_erp *erp)
1000f465261aSIdo Schimmel {
1001f465261aSIdo Schimmel WARN_ON(1);
1002f465261aSIdo Schimmel }
1003f465261aSIdo Schimmel
1004c71abd7dSJiri Pirko struct mlxsw_sp_acl_erp_mask *
mlxsw_sp_acl_erp_mask_get(struct mlxsw_sp_acl_atcam_region * aregion,const char * mask,bool ctcam)1005c71abd7dSJiri Pirko mlxsw_sp_acl_erp_mask_get(struct mlxsw_sp_acl_atcam_region *aregion,
1006b17b113eSIdo Schimmel const char *mask, bool ctcam)
1007f465261aSIdo Schimmel {
1008ddaa2875SJiri Pirko struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1009f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_key key;
1010c71abd7dSJiri Pirko struct objagg_obj *objagg_obj;
1011f465261aSIdo Schimmel
1012f465261aSIdo Schimmel memcpy(key.mask, mask, MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN);
1013b17b113eSIdo Schimmel key.ctcam = ctcam;
1014ddaa2875SJiri Pirko mutex_lock(&erp_table->objagg_lock);
1015ddaa2875SJiri Pirko objagg_obj = objagg_obj_get(erp_table->objagg, &key);
1016ddaa2875SJiri Pirko mutex_unlock(&erp_table->objagg_lock);
1017c71abd7dSJiri Pirko if (IS_ERR(objagg_obj))
1018c71abd7dSJiri Pirko return ERR_CAST(objagg_obj);
1019c71abd7dSJiri Pirko return (struct mlxsw_sp_acl_erp_mask *) objagg_obj;
1020f465261aSIdo Schimmel }
1021f465261aSIdo Schimmel
mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region * aregion,struct mlxsw_sp_acl_erp_mask * erp_mask)1022c71abd7dSJiri Pirko void mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region *aregion,
1023c71abd7dSJiri Pirko struct mlxsw_sp_acl_erp_mask *erp_mask)
1024f465261aSIdo Schimmel {
1025c71abd7dSJiri Pirko struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1026ddaa2875SJiri Pirko struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1027f465261aSIdo Schimmel
1028ddaa2875SJiri Pirko mutex_lock(&erp_table->objagg_lock);
1029ddaa2875SJiri Pirko objagg_obj_put(erp_table->objagg, objagg_obj);
1030ddaa2875SJiri Pirko mutex_unlock(&erp_table->objagg_lock);
1031f465261aSIdo Schimmel }
1032f465261aSIdo Schimmel
mlxsw_sp_acl_erp_bf_insert(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_acl_atcam_region * aregion,struct mlxsw_sp_acl_erp_mask * erp_mask,struct mlxsw_sp_acl_atcam_entry * aentry)1033f5a2852eSNir Dotan int mlxsw_sp_acl_erp_bf_insert(struct mlxsw_sp *mlxsw_sp,
1034f5a2852eSNir Dotan struct mlxsw_sp_acl_atcam_region *aregion,
1035f5a2852eSNir Dotan struct mlxsw_sp_acl_erp_mask *erp_mask,
1036f5a2852eSNir Dotan struct mlxsw_sp_acl_atcam_entry *aentry)
1037f5a2852eSNir Dotan {
1038f5a2852eSNir Dotan struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1039f5a2852eSNir Dotan const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
1040f5a2852eSNir Dotan unsigned int erp_bank;
1041f5a2852eSNir Dotan
1042f5a2852eSNir Dotan if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
1043f5a2852eSNir Dotan return 0;
1044f5a2852eSNir Dotan
1045f5a2852eSNir Dotan erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
1046f5a2852eSNir Dotan return mlxsw_sp_acl_bf_entry_add(mlxsw_sp,
1047f5a2852eSNir Dotan erp->erp_table->erp_core->bf,
1048f5a2852eSNir Dotan aregion, erp_bank, aentry);
1049f5a2852eSNir Dotan }
1050f5a2852eSNir Dotan
mlxsw_sp_acl_erp_bf_remove(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_acl_atcam_region * aregion,struct mlxsw_sp_acl_erp_mask * erp_mask,struct mlxsw_sp_acl_atcam_entry * aentry)1051f5a2852eSNir Dotan void mlxsw_sp_acl_erp_bf_remove(struct mlxsw_sp *mlxsw_sp,
1052f5a2852eSNir Dotan struct mlxsw_sp_acl_atcam_region *aregion,
1053f5a2852eSNir Dotan struct mlxsw_sp_acl_erp_mask *erp_mask,
1054f5a2852eSNir Dotan struct mlxsw_sp_acl_atcam_entry *aentry)
1055f5a2852eSNir Dotan {
1056f5a2852eSNir Dotan struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1057f5a2852eSNir Dotan const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
1058f5a2852eSNir Dotan unsigned int erp_bank;
1059f5a2852eSNir Dotan
1060f5a2852eSNir Dotan if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
1061f5a2852eSNir Dotan return;
1062f5a2852eSNir Dotan
1063f5a2852eSNir Dotan erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
1064f5a2852eSNir Dotan mlxsw_sp_acl_bf_entry_del(mlxsw_sp,
1065f5a2852eSNir Dotan erp->erp_table->erp_core->bf,
1066f5a2852eSNir Dotan aregion, erp_bank, aentry);
1067f5a2852eSNir Dotan }
1068f5a2852eSNir Dotan
1069c71abd7dSJiri Pirko bool
mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask * erp_mask)1070c71abd7dSJiri Pirko mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1071c71abd7dSJiri Pirko {
1072c71abd7dSJiri Pirko struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1073c71abd7dSJiri Pirko const struct mlxsw_sp_acl_erp_key *key = objagg_obj_raw(objagg_obj);
1074c71abd7dSJiri Pirko
1075c71abd7dSJiri Pirko return key->ctcam;
1076c71abd7dSJiri Pirko }
1077c71abd7dSJiri Pirko
mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask * erp_mask)1078c71abd7dSJiri Pirko u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1079c71abd7dSJiri Pirko {
1080c71abd7dSJiri Pirko struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1081c71abd7dSJiri Pirko const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
1082c71abd7dSJiri Pirko
1083c71abd7dSJiri Pirko return erp->id;
1084c71abd7dSJiri Pirko }
1085c71abd7dSJiri Pirko
1086c22291f7SJiri Pirko struct mlxsw_sp_acl_erp_delta {
1087c22291f7SJiri Pirko struct mlxsw_sp_acl_erp_key key;
1088c22291f7SJiri Pirko u16 start;
1089c22291f7SJiri Pirko u8 mask;
1090c22291f7SJiri Pirko };
1091c22291f7SJiri Pirko
mlxsw_sp_acl_erp_delta_start(const struct mlxsw_sp_acl_erp_delta * delta)1092c22291f7SJiri Pirko u16 mlxsw_sp_acl_erp_delta_start(const struct mlxsw_sp_acl_erp_delta *delta)
1093c22291f7SJiri Pirko {
1094c22291f7SJiri Pirko return delta->start;
1095c22291f7SJiri Pirko }
1096c22291f7SJiri Pirko
mlxsw_sp_acl_erp_delta_mask(const struct mlxsw_sp_acl_erp_delta * delta)1097c22291f7SJiri Pirko u8 mlxsw_sp_acl_erp_delta_mask(const struct mlxsw_sp_acl_erp_delta *delta)
1098c22291f7SJiri Pirko {
1099c22291f7SJiri Pirko return delta->mask;
1100c22291f7SJiri Pirko }
1101c22291f7SJiri Pirko
mlxsw_sp_acl_erp_delta_value(const struct mlxsw_sp_acl_erp_delta * delta,const char * enc_key)1102c22291f7SJiri Pirko u8 mlxsw_sp_acl_erp_delta_value(const struct mlxsw_sp_acl_erp_delta *delta,
1103c22291f7SJiri Pirko const char *enc_key)
1104c22291f7SJiri Pirko {
1105c22291f7SJiri Pirko u16 start = delta->start;
1106c22291f7SJiri Pirko u8 mask = delta->mask;
1107c22291f7SJiri Pirko u16 tmp;
1108c22291f7SJiri Pirko
1109c22291f7SJiri Pirko if (!mask)
1110c22291f7SJiri Pirko return 0;
1111c22291f7SJiri Pirko
1112c22291f7SJiri Pirko tmp = (unsigned char) enc_key[__MASK_IDX(start / 8)];
1113c22291f7SJiri Pirko if (start / 8 + 1 < __MASK_LEN)
1114c22291f7SJiri Pirko tmp |= (unsigned char) enc_key[__MASK_IDX(start / 8 + 1)] << 8;
1115c22291f7SJiri Pirko tmp >>= start % 8;
1116c22291f7SJiri Pirko tmp &= mask;
1117c22291f7SJiri Pirko return tmp;
1118c22291f7SJiri Pirko }
1119c22291f7SJiri Pirko
mlxsw_sp_acl_erp_delta_clear(const struct mlxsw_sp_acl_erp_delta * delta,const char * enc_key)1120c22291f7SJiri Pirko void mlxsw_sp_acl_erp_delta_clear(const struct mlxsw_sp_acl_erp_delta *delta,
1121c22291f7SJiri Pirko const char *enc_key)
1122c22291f7SJiri Pirko {
1123c22291f7SJiri Pirko u16 start = delta->start;
1124c22291f7SJiri Pirko u8 mask = delta->mask;
1125c22291f7SJiri Pirko unsigned char *byte;
1126c22291f7SJiri Pirko u16 tmp;
1127c22291f7SJiri Pirko
1128c22291f7SJiri Pirko tmp = mask;
1129c22291f7SJiri Pirko tmp <<= start % 8;
1130c22291f7SJiri Pirko tmp = ~tmp;
1131c22291f7SJiri Pirko
1132c22291f7SJiri Pirko byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8)];
1133c22291f7SJiri Pirko *byte &= tmp & 0xff;
1134c22291f7SJiri Pirko if (start / 8 + 1 < __MASK_LEN) {
1135c22291f7SJiri Pirko byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8 + 1)];
1136c22291f7SJiri Pirko *byte &= (tmp >> 8) & 0xff;
1137c22291f7SJiri Pirko }
1138c22291f7SJiri Pirko }
1139c22291f7SJiri Pirko
1140c22291f7SJiri Pirko static const struct mlxsw_sp_acl_erp_delta
1141c22291f7SJiri Pirko mlxsw_sp_acl_erp_delta_default = {};
1142c22291f7SJiri Pirko
1143c22291f7SJiri Pirko const struct mlxsw_sp_acl_erp_delta *
mlxsw_sp_acl_erp_delta(const struct mlxsw_sp_acl_erp_mask * erp_mask)1144c22291f7SJiri Pirko mlxsw_sp_acl_erp_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1145c22291f7SJiri Pirko {
1146c22291f7SJiri Pirko struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1147c22291f7SJiri Pirko const struct mlxsw_sp_acl_erp_delta *delta;
1148c22291f7SJiri Pirko
1149c22291f7SJiri Pirko delta = objagg_obj_delta_priv(objagg_obj);
1150c22291f7SJiri Pirko if (!delta)
1151c22291f7SJiri Pirko delta = &mlxsw_sp_acl_erp_delta_default;
1152c22291f7SJiri Pirko return delta;
1153c22291f7SJiri Pirko }
1154c22291f7SJiri Pirko
1155c22291f7SJiri Pirko static int
mlxsw_sp_acl_erp_delta_fill(const struct mlxsw_sp_acl_erp_key * parent_key,const struct mlxsw_sp_acl_erp_key * key,u16 * delta_start,u8 * delta_mask)1156c22291f7SJiri Pirko mlxsw_sp_acl_erp_delta_fill(const struct mlxsw_sp_acl_erp_key *parent_key,
1157c22291f7SJiri Pirko const struct mlxsw_sp_acl_erp_key *key,
1158c22291f7SJiri Pirko u16 *delta_start, u8 *delta_mask)
1159c22291f7SJiri Pirko {
1160c22291f7SJiri Pirko int offset = 0;
1161c22291f7SJiri Pirko int si = -1;
1162c22291f7SJiri Pirko u16 pmask;
1163c22291f7SJiri Pirko u16 mask;
1164c22291f7SJiri Pirko int i;
1165c22291f7SJiri Pirko
1166c22291f7SJiri Pirko /* The difference between 2 masks can be up to 8 consecutive bits. */
1167c22291f7SJiri Pirko for (i = 0; i < __MASK_LEN; i++) {
1168c22291f7SJiri Pirko if (parent_key->mask[__MASK_IDX(i)] == key->mask[__MASK_IDX(i)])
1169c22291f7SJiri Pirko continue;
1170c22291f7SJiri Pirko if (si == -1)
1171c22291f7SJiri Pirko si = i;
1172c22291f7SJiri Pirko else if (si != i - 1)
1173c22291f7SJiri Pirko return -EINVAL;
1174c22291f7SJiri Pirko }
1175c22291f7SJiri Pirko if (si == -1) {
1176ef744220SJiri Pirko /* The masks are the same, this can happen in case eRPs with
1177ef744220SJiri Pirko * the same mask were created in both A-TCAM and C-TCAM.
1178ef744220SJiri Pirko * The only possible condition under which this can happen
1179ef744220SJiri Pirko * is identical rule insertion. Delta is not possible here.
1180c22291f7SJiri Pirko */
1181ef744220SJiri Pirko return -EINVAL;
1182c22291f7SJiri Pirko }
1183c22291f7SJiri Pirko pmask = (unsigned char) parent_key->mask[__MASK_IDX(si)];
1184c22291f7SJiri Pirko mask = (unsigned char) key->mask[__MASK_IDX(si)];
1185c22291f7SJiri Pirko if (si + 1 < __MASK_LEN) {
1186c22291f7SJiri Pirko pmask |= (unsigned char) parent_key->mask[__MASK_IDX(si + 1)] << 8;
1187c22291f7SJiri Pirko mask |= (unsigned char) key->mask[__MASK_IDX(si + 1)] << 8;
1188c22291f7SJiri Pirko }
1189c22291f7SJiri Pirko
1190c22291f7SJiri Pirko if ((pmask ^ mask) & pmask)
1191c22291f7SJiri Pirko return -EINVAL;
1192c22291f7SJiri Pirko mask &= ~pmask;
1193c22291f7SJiri Pirko while (!(mask & (1 << offset)))
1194c22291f7SJiri Pirko offset++;
1195c22291f7SJiri Pirko while (!(mask & 1))
1196c22291f7SJiri Pirko mask >>= 1;
1197c22291f7SJiri Pirko if (mask & 0xff00)
1198c22291f7SJiri Pirko return -EINVAL;
1199c22291f7SJiri Pirko
1200c22291f7SJiri Pirko *delta_start = si * 8 + offset;
1201c22291f7SJiri Pirko *delta_mask = mask;
1202c22291f7SJiri Pirko
1203c22291f7SJiri Pirko return 0;
1204c22291f7SJiri Pirko }
1205c22291f7SJiri Pirko
mlxsw_sp_acl_erp_delta_check(void * priv,const void * parent_obj,const void * obj)12069069a381SJiri Pirko static bool mlxsw_sp_acl_erp_delta_check(void *priv, const void *parent_obj,
12079069a381SJiri Pirko const void *obj)
12089069a381SJiri Pirko {
12099069a381SJiri Pirko const struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
12109069a381SJiri Pirko const struct mlxsw_sp_acl_erp_key *key = obj;
12119069a381SJiri Pirko u16 delta_start;
12129069a381SJiri Pirko u8 delta_mask;
12139069a381SJiri Pirko int err;
12149069a381SJiri Pirko
12159069a381SJiri Pirko err = mlxsw_sp_acl_erp_delta_fill(parent_key, key,
12169069a381SJiri Pirko &delta_start, &delta_mask);
12179069a381SJiri Pirko return err ? false : true;
12189069a381SJiri Pirko }
12199069a381SJiri Pirko
mlxsw_sp_acl_erp_delta_create(void * priv,void * parent_obj,void * obj)1220c71abd7dSJiri Pirko static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj,
1221c71abd7dSJiri Pirko void *obj)
1222c71abd7dSJiri Pirko {
1223c22291f7SJiri Pirko struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
1224c22291f7SJiri Pirko struct mlxsw_sp_acl_atcam_region *aregion = priv;
1225c22291f7SJiri Pirko struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1226c22291f7SJiri Pirko struct mlxsw_sp_acl_erp_key *key = obj;
1227c22291f7SJiri Pirko struct mlxsw_sp_acl_erp_delta *delta;
1228c22291f7SJiri Pirko u16 delta_start;
1229c22291f7SJiri Pirko u8 delta_mask;
1230c22291f7SJiri Pirko int err;
1231c22291f7SJiri Pirko
1232c22291f7SJiri Pirko if (parent_key->ctcam || key->ctcam)
1233c22291f7SJiri Pirko return ERR_PTR(-EINVAL);
1234c22291f7SJiri Pirko err = mlxsw_sp_acl_erp_delta_fill(parent_key, key,
1235c22291f7SJiri Pirko &delta_start, &delta_mask);
1236c22291f7SJiri Pirko if (err)
1237c22291f7SJiri Pirko return ERR_PTR(-EINVAL);
1238c22291f7SJiri Pirko
1239c22291f7SJiri Pirko delta = kzalloc(sizeof(*delta), GFP_KERNEL);
1240c22291f7SJiri Pirko if (!delta)
1241c22291f7SJiri Pirko return ERR_PTR(-ENOMEM);
1242c22291f7SJiri Pirko delta->start = delta_start;
1243c22291f7SJiri Pirko delta->mask = delta_mask;
1244c22291f7SJiri Pirko
1245c22291f7SJiri Pirko err = mlxsw_sp_acl_erp_delta_inc(erp_table);
1246c22291f7SJiri Pirko if (err)
1247c22291f7SJiri Pirko goto err_erp_delta_inc;
1248c22291f7SJiri Pirko
1249c22291f7SJiri Pirko memcpy(&delta->key, key, sizeof(*key));
1250c22291f7SJiri Pirko err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &delta->key);
1251c22291f7SJiri Pirko if (err)
1252c22291f7SJiri Pirko goto err_master_mask_set;
1253c22291f7SJiri Pirko
1254c22291f7SJiri Pirko return delta;
1255c22291f7SJiri Pirko
1256c22291f7SJiri Pirko err_master_mask_set:
1257c22291f7SJiri Pirko mlxsw_sp_acl_erp_delta_dec(erp_table);
1258c22291f7SJiri Pirko err_erp_delta_inc:
1259c22291f7SJiri Pirko kfree(delta);
1260c22291f7SJiri Pirko return ERR_PTR(err);
1261c71abd7dSJiri Pirko }
1262c71abd7dSJiri Pirko
mlxsw_sp_acl_erp_delta_destroy(void * priv,void * delta_priv)1263c71abd7dSJiri Pirko static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv)
1264c71abd7dSJiri Pirko {
1265c22291f7SJiri Pirko struct mlxsw_sp_acl_erp_delta *delta = delta_priv;
1266c22291f7SJiri Pirko struct mlxsw_sp_acl_atcam_region *aregion = priv;
1267c22291f7SJiri Pirko struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1268c22291f7SJiri Pirko
1269c22291f7SJiri Pirko mlxsw_sp_acl_erp_master_mask_clear(erp_table, &delta->key);
1270c22291f7SJiri Pirko mlxsw_sp_acl_erp_delta_dec(erp_table);
1271c22291f7SJiri Pirko kfree(delta);
1272c71abd7dSJiri Pirko }
1273c71abd7dSJiri Pirko
mlxsw_sp_acl_erp_root_create(void * priv,void * obj,unsigned int root_id)12749069a381SJiri Pirko static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj,
12759069a381SJiri Pirko unsigned int root_id)
1276c71abd7dSJiri Pirko {
1277c71abd7dSJiri Pirko struct mlxsw_sp_acl_atcam_region *aregion = priv;
1278c71abd7dSJiri Pirko struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1279c71abd7dSJiri Pirko struct mlxsw_sp_acl_erp_key *key = obj;
1280c71abd7dSJiri Pirko
12819069a381SJiri Pirko if (!key->ctcam &&
12829069a381SJiri Pirko root_id != OBJAGG_OBJ_ROOT_ID_INVALID &&
12839069a381SJiri Pirko root_id >= MLXSW_SP_ACL_ERP_MAX_PER_REGION)
12849069a381SJiri Pirko return ERR_PTR(-ENOBUFS);
1285c71abd7dSJiri Pirko return erp_table->ops->erp_create(erp_table, key);
1286c71abd7dSJiri Pirko }
1287c71abd7dSJiri Pirko
mlxsw_sp_acl_erp_root_destroy(void * priv,void * root_priv)1288c71abd7dSJiri Pirko static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv)
1289c71abd7dSJiri Pirko {
1290c71abd7dSJiri Pirko struct mlxsw_sp_acl_atcam_region *aregion = priv;
1291c71abd7dSJiri Pirko struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1292c71abd7dSJiri Pirko
1293c71abd7dSJiri Pirko erp_table->ops->erp_destroy(erp_table, root_priv);
1294c71abd7dSJiri Pirko }
1295c71abd7dSJiri Pirko
1296c71abd7dSJiri Pirko static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = {
1297c71abd7dSJiri Pirko .obj_size = sizeof(struct mlxsw_sp_acl_erp_key),
12989069a381SJiri Pirko .delta_check = mlxsw_sp_acl_erp_delta_check,
1299c71abd7dSJiri Pirko .delta_create = mlxsw_sp_acl_erp_delta_create,
1300c71abd7dSJiri Pirko .delta_destroy = mlxsw_sp_acl_erp_delta_destroy,
1301c71abd7dSJiri Pirko .root_create = mlxsw_sp_acl_erp_root_create,
1302c71abd7dSJiri Pirko .root_destroy = mlxsw_sp_acl_erp_root_destroy,
1303c71abd7dSJiri Pirko };
1304c71abd7dSJiri Pirko
1305f465261aSIdo Schimmel static struct mlxsw_sp_acl_erp_table *
mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region * aregion,struct objagg_hints * hints)1306a339bf8aSJiri Pirko mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion,
1307a339bf8aSJiri Pirko struct objagg_hints *hints)
1308f465261aSIdo Schimmel {
1309f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_table *erp_table;
1310f465261aSIdo Schimmel int err;
1311f465261aSIdo Schimmel
1312f465261aSIdo Schimmel erp_table = kzalloc(sizeof(*erp_table), GFP_KERNEL);
1313f465261aSIdo Schimmel if (!erp_table)
1314f465261aSIdo Schimmel return ERR_PTR(-ENOMEM);
1315f465261aSIdo Schimmel
1316c71abd7dSJiri Pirko erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops,
1317a339bf8aSJiri Pirko hints, aregion);
1318c71abd7dSJiri Pirko if (IS_ERR(erp_table->objagg)) {
1319c71abd7dSJiri Pirko err = PTR_ERR(erp_table->objagg);
1320c71abd7dSJiri Pirko goto err_objagg_create;
1321c71abd7dSJiri Pirko }
1322f465261aSIdo Schimmel
1323f465261aSIdo Schimmel erp_table->erp_core = aregion->atcam->erp_core;
1324f465261aSIdo Schimmel erp_table->ops = &erp_no_mask_ops;
1325f465261aSIdo Schimmel INIT_LIST_HEAD(&erp_table->atcam_erps_list);
1326f465261aSIdo Schimmel erp_table->aregion = aregion;
1327ddaa2875SJiri Pirko mutex_init(&erp_table->objagg_lock);
1328f465261aSIdo Schimmel
1329f465261aSIdo Schimmel return erp_table;
1330f465261aSIdo Schimmel
1331c71abd7dSJiri Pirko err_objagg_create:
1332f465261aSIdo Schimmel kfree(erp_table);
1333f465261aSIdo Schimmel return ERR_PTR(err);
1334f465261aSIdo Schimmel }
1335f465261aSIdo Schimmel
1336f465261aSIdo Schimmel static void
mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table * erp_table)1337f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table *erp_table)
1338f465261aSIdo Schimmel {
1339f465261aSIdo Schimmel WARN_ON(!list_empty(&erp_table->atcam_erps_list));
1340ddaa2875SJiri Pirko mutex_destroy(&erp_table->objagg_lock);
1341c71abd7dSJiri Pirko objagg_destroy(erp_table->objagg);
1342f465261aSIdo Schimmel kfree(erp_table);
1343f465261aSIdo Schimmel }
1344f465261aSIdo Schimmel
1345f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_master_mask_init(struct mlxsw_sp_acl_atcam_region * aregion)1346f465261aSIdo Schimmel mlxsw_sp_acl_erp_master_mask_init(struct mlxsw_sp_acl_atcam_region *aregion)
1347f465261aSIdo Schimmel {
1348f465261aSIdo Schimmel struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1349f465261aSIdo Schimmel char percr_pl[MLXSW_REG_PERCR_LEN];
1350f465261aSIdo Schimmel
1351f465261aSIdo Schimmel mlxsw_reg_percr_pack(percr_pl, aregion->region->id);
1352f465261aSIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
1353f465261aSIdo Schimmel }
1354f465261aSIdo Schimmel
1355f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_region_param_init(struct mlxsw_sp_acl_atcam_region * aregion)1356f465261aSIdo Schimmel mlxsw_sp_acl_erp_region_param_init(struct mlxsw_sp_acl_atcam_region *aregion)
1357f465261aSIdo Schimmel {
1358f465261aSIdo Schimmel struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1359f465261aSIdo Schimmel char pererp_pl[MLXSW_REG_PERERP_LEN];
1360f465261aSIdo Schimmel
1361a0a777b9SIdo Schimmel mlxsw_reg_pererp_pack(pererp_pl, aregion->region->id, false, false, 0,
1362f465261aSIdo Schimmel 0, 0);
1363f465261aSIdo Schimmel return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
1364f465261aSIdo Schimmel }
1365f465261aSIdo Schimmel
136629a2102aSJiri Pirko static int
mlxsw_sp_acl_erp_hints_check(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_acl_atcam_region * aregion,struct objagg_hints * hints,bool * p_rehash_needed)136729a2102aSJiri Pirko mlxsw_sp_acl_erp_hints_check(struct mlxsw_sp *mlxsw_sp,
136829a2102aSJiri Pirko struct mlxsw_sp_acl_atcam_region *aregion,
136929a2102aSJiri Pirko struct objagg_hints *hints, bool *p_rehash_needed)
137029a2102aSJiri Pirko {
1371ddaa2875SJiri Pirko struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
137229a2102aSJiri Pirko const struct objagg_stats *ostats;
137329a2102aSJiri Pirko const struct objagg_stats *hstats;
137429a2102aSJiri Pirko int err;
137529a2102aSJiri Pirko
137629a2102aSJiri Pirko *p_rehash_needed = false;
137729a2102aSJiri Pirko
1378ddaa2875SJiri Pirko mutex_lock(&erp_table->objagg_lock);
1379ddaa2875SJiri Pirko ostats = objagg_stats_get(erp_table->objagg);
1380ddaa2875SJiri Pirko mutex_unlock(&erp_table->objagg_lock);
138129a2102aSJiri Pirko if (IS_ERR(ostats)) {
138229a2102aSJiri Pirko dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get ERP stats\n");
138329a2102aSJiri Pirko return PTR_ERR(ostats);
138429a2102aSJiri Pirko }
138529a2102aSJiri Pirko
138629a2102aSJiri Pirko hstats = objagg_hints_stats_get(hints);
138729a2102aSJiri Pirko if (IS_ERR(hstats)) {
138829a2102aSJiri Pirko dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get ERP hints stats\n");
138929a2102aSJiri Pirko err = PTR_ERR(hstats);
139029a2102aSJiri Pirko goto err_hints_stats_get;
139129a2102aSJiri Pirko }
139229a2102aSJiri Pirko
139329a2102aSJiri Pirko /* Very basic criterion for now. */
139429a2102aSJiri Pirko if (hstats->root_count < ostats->root_count)
139529a2102aSJiri Pirko *p_rehash_needed = true;
139629a2102aSJiri Pirko
139729a2102aSJiri Pirko err = 0;
139829a2102aSJiri Pirko
139929a2102aSJiri Pirko objagg_stats_put(hstats);
140029a2102aSJiri Pirko err_hints_stats_get:
140129a2102aSJiri Pirko objagg_stats_put(ostats);
140229a2102aSJiri Pirko return err;
140329a2102aSJiri Pirko }
140429a2102aSJiri Pirko
140529a2102aSJiri Pirko void *
mlxsw_sp_acl_erp_rehash_hints_get(struct mlxsw_sp_acl_atcam_region * aregion)140629a2102aSJiri Pirko mlxsw_sp_acl_erp_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion)
140729a2102aSJiri Pirko {
1408ddaa2875SJiri Pirko struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
140929a2102aSJiri Pirko struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
141029a2102aSJiri Pirko struct objagg_hints *hints;
141129a2102aSJiri Pirko bool rehash_needed;
141229a2102aSJiri Pirko int err;
141329a2102aSJiri Pirko
1414ddaa2875SJiri Pirko mutex_lock(&erp_table->objagg_lock);
1415ddaa2875SJiri Pirko hints = objagg_hints_get(erp_table->objagg,
141629a2102aSJiri Pirko OBJAGG_OPT_ALGO_SIMPLE_GREEDY);
1417ddaa2875SJiri Pirko mutex_unlock(&erp_table->objagg_lock);
141829a2102aSJiri Pirko if (IS_ERR(hints)) {
141929a2102aSJiri Pirko dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to create ERP hints\n");
142029a2102aSJiri Pirko return ERR_CAST(hints);
142129a2102aSJiri Pirko }
142229a2102aSJiri Pirko err = mlxsw_sp_acl_erp_hints_check(mlxsw_sp, aregion, hints,
142329a2102aSJiri Pirko &rehash_needed);
142429a2102aSJiri Pirko if (err)
142529a2102aSJiri Pirko goto errout;
142629a2102aSJiri Pirko
142729a2102aSJiri Pirko if (!rehash_needed) {
142829a2102aSJiri Pirko err = -EAGAIN;
142929a2102aSJiri Pirko goto errout;
143029a2102aSJiri Pirko }
143129a2102aSJiri Pirko return hints;
143229a2102aSJiri Pirko
143329a2102aSJiri Pirko errout:
143429a2102aSJiri Pirko objagg_hints_put(hints);
143529a2102aSJiri Pirko return ERR_PTR(err);
143629a2102aSJiri Pirko }
143729a2102aSJiri Pirko
mlxsw_sp_acl_erp_rehash_hints_put(void * hints_priv)143829a2102aSJiri Pirko void mlxsw_sp_acl_erp_rehash_hints_put(void *hints_priv)
143929a2102aSJiri Pirko {
144029a2102aSJiri Pirko struct objagg_hints *hints = hints_priv;
144129a2102aSJiri Pirko
144229a2102aSJiri Pirko objagg_hints_put(hints);
144329a2102aSJiri Pirko }
144429a2102aSJiri Pirko
mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region * aregion,void * hints_priv)1445a339bf8aSJiri Pirko int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion,
1446a339bf8aSJiri Pirko void *hints_priv)
1447f465261aSIdo Schimmel {
1448f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_table *erp_table;
1449a339bf8aSJiri Pirko struct objagg_hints *hints = hints_priv;
1450f465261aSIdo Schimmel int err;
1451f465261aSIdo Schimmel
1452a339bf8aSJiri Pirko erp_table = mlxsw_sp_acl_erp_table_create(aregion, hints);
1453f465261aSIdo Schimmel if (IS_ERR(erp_table))
1454f465261aSIdo Schimmel return PTR_ERR(erp_table);
1455f465261aSIdo Schimmel aregion->erp_table = erp_table;
1456f465261aSIdo Schimmel
1457a0a777b9SIdo Schimmel /* Initialize the region's master mask to all zeroes */
1458f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_master_mask_init(aregion);
1459f465261aSIdo Schimmel if (err)
1460f465261aSIdo Schimmel goto err_erp_master_mask_init;
1461f465261aSIdo Schimmel
1462a0a777b9SIdo Schimmel /* Initialize the region to not use the eRP table */
1463f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_region_param_init(aregion);
1464f465261aSIdo Schimmel if (err)
1465f465261aSIdo Schimmel goto err_erp_region_param_init;
1466f465261aSIdo Schimmel
1467f465261aSIdo Schimmel return 0;
1468f465261aSIdo Schimmel
1469f465261aSIdo Schimmel err_erp_region_param_init:
1470f465261aSIdo Schimmel err_erp_master_mask_init:
1471f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_destroy(erp_table);
1472f465261aSIdo Schimmel return err;
1473f465261aSIdo Schimmel }
1474f465261aSIdo Schimmel
mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region * aregion)1475f465261aSIdo Schimmel void mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region *aregion)
1476f465261aSIdo Schimmel {
1477f465261aSIdo Schimmel mlxsw_sp_acl_erp_table_destroy(aregion->erp_table);
1478f465261aSIdo Schimmel }
1479f465261aSIdo Schimmel
1480f465261aSIdo Schimmel static int
mlxsw_sp_acl_erp_tables_sizes_query(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_acl_erp_core * erp_core)1481f465261aSIdo Schimmel mlxsw_sp_acl_erp_tables_sizes_query(struct mlxsw_sp *mlxsw_sp,
1482f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_core *erp_core)
1483f465261aSIdo Schimmel {
1484f465261aSIdo Schimmel unsigned int size;
1485f465261aSIdo Schimmel
1486f465261aSIdo Schimmel if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB) ||
1487f465261aSIdo Schimmel !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB) ||
1488f465261aSIdo Schimmel !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB) ||
1489f465261aSIdo Schimmel !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB))
1490f465261aSIdo Schimmel return -EIO;
1491f465261aSIdo Schimmel
1492f465261aSIdo Schimmel size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB);
1493f465261aSIdo Schimmel erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] = size;
1494f465261aSIdo Schimmel
1495f465261aSIdo Schimmel size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB);
1496f465261aSIdo Schimmel erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] = size;
1497f465261aSIdo Schimmel
1498f465261aSIdo Schimmel size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB);
1499f465261aSIdo Schimmel erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] = size;
1500f465261aSIdo Schimmel
1501f465261aSIdo Schimmel size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB);
1502f465261aSIdo Schimmel erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] = size;
1503f465261aSIdo Schimmel
1504f465261aSIdo Schimmel return 0;
1505f465261aSIdo Schimmel }
1506f465261aSIdo Schimmel
mlxsw_sp_acl_erp_tables_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_acl_erp_core * erp_core)1507f465261aSIdo Schimmel static int mlxsw_sp_acl_erp_tables_init(struct mlxsw_sp *mlxsw_sp,
1508f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_core *erp_core)
1509f465261aSIdo Schimmel {
1510f465261aSIdo Schimmel unsigned int erpt_bank_size;
1511f465261aSIdo Schimmel int err;
1512f465261aSIdo Schimmel
1513f465261aSIdo Schimmel if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANK_SIZE) ||
1514f465261aSIdo Schimmel !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANKS))
1515f465261aSIdo Schimmel return -EIO;
1516f465261aSIdo Schimmel erpt_bank_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1517f465261aSIdo Schimmel ACL_MAX_ERPT_BANK_SIZE);
1518f465261aSIdo Schimmel erp_core->num_erp_banks = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1519f465261aSIdo Schimmel ACL_MAX_ERPT_BANKS);
1520f465261aSIdo Schimmel
1521f465261aSIdo Schimmel erp_core->erp_tables = gen_pool_create(0, -1);
1522f465261aSIdo Schimmel if (!erp_core->erp_tables)
1523f465261aSIdo Schimmel return -ENOMEM;
1524f465261aSIdo Schimmel gen_pool_set_algo(erp_core->erp_tables, gen_pool_best_fit, NULL);
1525f465261aSIdo Schimmel
1526f465261aSIdo Schimmel err = gen_pool_add(erp_core->erp_tables,
1527f465261aSIdo Schimmel MLXSW_SP_ACL_ERP_GENALLOC_OFFSET, erpt_bank_size,
1528f465261aSIdo Schimmel -1);
1529f465261aSIdo Schimmel if (err)
1530f465261aSIdo Schimmel goto err_gen_pool_add;
1531f465261aSIdo Schimmel
15320487cfbaSNir Dotan erp_core->bf = mlxsw_sp_acl_bf_init(mlxsw_sp, erp_core->num_erp_banks);
15330487cfbaSNir Dotan if (IS_ERR(erp_core->bf)) {
15340487cfbaSNir Dotan err = PTR_ERR(erp_core->bf);
15350487cfbaSNir Dotan goto err_bf_init;
15360487cfbaSNir Dotan }
15370487cfbaSNir Dotan
1538f465261aSIdo Schimmel /* Different regions require masks of different sizes */
1539f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_tables_sizes_query(mlxsw_sp, erp_core);
1540f465261aSIdo Schimmel if (err)
1541f465261aSIdo Schimmel goto err_erp_tables_sizes_query;
1542f465261aSIdo Schimmel
1543f465261aSIdo Schimmel return 0;
1544f465261aSIdo Schimmel
1545f465261aSIdo Schimmel err_erp_tables_sizes_query:
15460487cfbaSNir Dotan mlxsw_sp_acl_bf_fini(erp_core->bf);
15470487cfbaSNir Dotan err_bf_init:
1548f465261aSIdo Schimmel err_gen_pool_add:
1549f465261aSIdo Schimmel gen_pool_destroy(erp_core->erp_tables);
1550f465261aSIdo Schimmel return err;
1551f465261aSIdo Schimmel }
1552f465261aSIdo Schimmel
mlxsw_sp_acl_erp_tables_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_acl_erp_core * erp_core)1553f465261aSIdo Schimmel static void mlxsw_sp_acl_erp_tables_fini(struct mlxsw_sp *mlxsw_sp,
1554f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_core *erp_core)
1555f465261aSIdo Schimmel {
15560487cfbaSNir Dotan mlxsw_sp_acl_bf_fini(erp_core->bf);
1557f465261aSIdo Schimmel gen_pool_destroy(erp_core->erp_tables);
1558f465261aSIdo Schimmel }
1559f465261aSIdo Schimmel
mlxsw_sp_acl_erps_init(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_acl_atcam * atcam)1560f465261aSIdo Schimmel int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp,
1561f465261aSIdo Schimmel struct mlxsw_sp_acl_atcam *atcam)
1562f465261aSIdo Schimmel {
1563f465261aSIdo Schimmel struct mlxsw_sp_acl_erp_core *erp_core;
1564f465261aSIdo Schimmel int err;
1565f465261aSIdo Schimmel
1566f465261aSIdo Schimmel erp_core = kzalloc(sizeof(*erp_core), GFP_KERNEL);
1567f465261aSIdo Schimmel if (!erp_core)
1568f465261aSIdo Schimmel return -ENOMEM;
1569f465261aSIdo Schimmel erp_core->mlxsw_sp = mlxsw_sp;
1570f465261aSIdo Schimmel atcam->erp_core = erp_core;
1571f465261aSIdo Schimmel
1572f465261aSIdo Schimmel err = mlxsw_sp_acl_erp_tables_init(mlxsw_sp, erp_core);
1573f465261aSIdo Schimmel if (err)
1574f465261aSIdo Schimmel goto err_erp_tables_init;
1575f465261aSIdo Schimmel
1576f465261aSIdo Schimmel return 0;
1577f465261aSIdo Schimmel
1578f465261aSIdo Schimmel err_erp_tables_init:
1579f465261aSIdo Schimmel kfree(erp_core);
1580f465261aSIdo Schimmel return err;
1581f465261aSIdo Schimmel }
1582f465261aSIdo Schimmel
mlxsw_sp_acl_erps_fini(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_acl_atcam * atcam)1583f465261aSIdo Schimmel void mlxsw_sp_acl_erps_fini(struct mlxsw_sp *mlxsw_sp,
1584f465261aSIdo Schimmel struct mlxsw_sp_acl_atcam *atcam)
1585f465261aSIdo Schimmel {
1586f465261aSIdo Schimmel mlxsw_sp_acl_erp_tables_fini(mlxsw_sp, atcam->erp_core);
1587f465261aSIdo Schimmel kfree(atcam->erp_core);
1588f465261aSIdo Schimmel }
1589