net/mlx5e: Avoid unbounded peer devices when unpairing TC hairpin rules
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlxsw / core_acl_flex_keys.c
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
3
4 #include <linux/kernel.h>
5 #include <linux/slab.h>
6 #include <linux/list.h>
7 #include <linux/errno.h>
8
9 #include "item.h"
10 #include "core_acl_flex_keys.h"
11
12 struct mlxsw_afk {
13         struct list_head key_info_list;
14         unsigned int max_blocks;
15         const struct mlxsw_afk_ops *ops;
16         const struct mlxsw_afk_block *blocks;
17         unsigned int blocks_count;
18 };
19
20 static bool mlxsw_afk_blocks_check(struct mlxsw_afk *mlxsw_afk)
21 {
22         int i;
23         int j;
24
25         for (i = 0; i < mlxsw_afk->blocks_count; i++) {
26                 const struct mlxsw_afk_block *block = &mlxsw_afk->blocks[i];
27
28                 for (j = 0; j < block->instances_count; j++) {
29                         struct mlxsw_afk_element_inst *elinst;
30
31                         elinst = &block->instances[j];
32                         if (elinst->type != elinst->info->type ||
33                             elinst->item.size.bits !=
34                             elinst->info->item.size.bits)
35                                 return false;
36                 }
37         }
38         return true;
39 }
40
41 struct mlxsw_afk *mlxsw_afk_create(unsigned int max_blocks,
42                                    const struct mlxsw_afk_ops *ops)
43 {
44         struct mlxsw_afk *mlxsw_afk;
45
46         mlxsw_afk = kzalloc(sizeof(*mlxsw_afk), GFP_KERNEL);
47         if (!mlxsw_afk)
48                 return NULL;
49         INIT_LIST_HEAD(&mlxsw_afk->key_info_list);
50         mlxsw_afk->max_blocks = max_blocks;
51         mlxsw_afk->ops = ops;
52         mlxsw_afk->blocks = ops->blocks;
53         mlxsw_afk->blocks_count = ops->blocks_count;
54         WARN_ON(!mlxsw_afk_blocks_check(mlxsw_afk));
55         return mlxsw_afk;
56 }
57 EXPORT_SYMBOL(mlxsw_afk_create);
58
59 void mlxsw_afk_destroy(struct mlxsw_afk *mlxsw_afk)
60 {
61         WARN_ON(!list_empty(&mlxsw_afk->key_info_list));
62         kfree(mlxsw_afk);
63 }
64 EXPORT_SYMBOL(mlxsw_afk_destroy);
65
66 struct mlxsw_afk_key_info {
67         struct list_head list;
68         unsigned int ref_count;
69         unsigned int blocks_count;
70         int element_to_block[MLXSW_AFK_ELEMENT_MAX]; /* index is element, value
71                                                       * is index inside "blocks"
72                                                       */
73         struct mlxsw_afk_element_usage elusage;
74         const struct mlxsw_afk_block *blocks[0];
75 };
76
77 static bool
78 mlxsw_afk_key_info_elements_eq(struct mlxsw_afk_key_info *key_info,
79                                struct mlxsw_afk_element_usage *elusage)
80 {
81         return memcmp(&key_info->elusage, elusage, sizeof(*elusage)) == 0;
82 }
83
84 static struct mlxsw_afk_key_info *
85 mlxsw_afk_key_info_find(struct mlxsw_afk *mlxsw_afk,
86                         struct mlxsw_afk_element_usage *elusage)
87 {
88         struct mlxsw_afk_key_info *key_info;
89
90         list_for_each_entry(key_info, &mlxsw_afk->key_info_list, list) {
91                 if (mlxsw_afk_key_info_elements_eq(key_info, elusage))
92                         return key_info;
93         }
94         return NULL;
95 }
96
97 struct mlxsw_afk_picker {
98         struct {
99                 DECLARE_BITMAP(element, MLXSW_AFK_ELEMENT_MAX);
100                 unsigned int total;
101         } hits[0];
102 };
103
104 static void mlxsw_afk_picker_count_hits(struct mlxsw_afk *mlxsw_afk,
105                                         struct mlxsw_afk_picker *picker,
106                                         enum mlxsw_afk_element element)
107 {
108         int i;
109         int j;
110
111         for (i = 0; i < mlxsw_afk->blocks_count; i++) {
112                 const struct mlxsw_afk_block *block = &mlxsw_afk->blocks[i];
113
114                 for (j = 0; j < block->instances_count; j++) {
115                         struct mlxsw_afk_element_inst *elinst;
116
117                         elinst = &block->instances[j];
118                         if (elinst->info->element == element) {
119                                 __set_bit(element, picker->hits[i].element);
120                                 picker->hits[i].total++;
121                         }
122                 }
123         }
124 }
125
126 static void mlxsw_afk_picker_subtract_hits(struct mlxsw_afk *mlxsw_afk,
127                                            struct mlxsw_afk_picker *picker,
128                                            int block_index)
129 {
130         DECLARE_BITMAP(hits_element, MLXSW_AFK_ELEMENT_MAX);
131         int i;
132         int j;
133
134         memcpy(&hits_element, &picker->hits[block_index].element,
135                sizeof(hits_element));
136
137         for (i = 0; i < mlxsw_afk->blocks_count; i++) {
138                 for_each_set_bit(j, hits_element, MLXSW_AFK_ELEMENT_MAX) {
139                         if (__test_and_clear_bit(j, picker->hits[i].element))
140                                 picker->hits[i].total--;
141                 }
142         }
143 }
144
145 static int mlxsw_afk_picker_most_hits_get(struct mlxsw_afk *mlxsw_afk,
146                                           struct mlxsw_afk_picker *picker)
147 {
148         int most_index = -EINVAL; /* Should never happen to return this */
149         int most_hits = 0;
150         int i;
151
152         for (i = 0; i < mlxsw_afk->blocks_count; i++) {
153                 if (picker->hits[i].total > most_hits) {
154                         most_hits = picker->hits[i].total;
155                         most_index = i;
156                 }
157         }
158         return most_index;
159 }
160
161 static int mlxsw_afk_picker_key_info_add(struct mlxsw_afk *mlxsw_afk,
162                                          struct mlxsw_afk_picker *picker,
163                                          int block_index,
164                                          struct mlxsw_afk_key_info *key_info)
165 {
166         enum mlxsw_afk_element element;
167
168         if (key_info->blocks_count == mlxsw_afk->max_blocks)
169                 return -EINVAL;
170
171         for_each_set_bit(element, picker->hits[block_index].element,
172                          MLXSW_AFK_ELEMENT_MAX) {
173                 key_info->element_to_block[element] = key_info->blocks_count;
174                 mlxsw_afk_element_usage_add(&key_info->elusage, element);
175         }
176
177         key_info->blocks[key_info->blocks_count] =
178                                         &mlxsw_afk->blocks[block_index];
179         key_info->blocks_count++;
180         return 0;
181 }
182
183 static int mlxsw_afk_picker(struct mlxsw_afk *mlxsw_afk,
184                             struct mlxsw_afk_key_info *key_info,
185                             struct mlxsw_afk_element_usage *elusage)
186 {
187         struct mlxsw_afk_picker *picker;
188         enum mlxsw_afk_element element;
189         size_t alloc_size;
190         int err;
191
192         alloc_size = sizeof(picker->hits[0]) * mlxsw_afk->blocks_count;
193         picker = kzalloc(alloc_size, GFP_KERNEL);
194         if (!picker)
195                 return -ENOMEM;
196
197         /* Since the same elements could be present in multiple blocks,
198          * we must find out optimal block list in order to make the
199          * block count as low as possible.
200          *
201          * First, we count hits. We go over all available blocks and count
202          * how many of requested elements are covered by each.
203          *
204          * Then in loop, we find block with most hits and add it to
205          * output key_info. Then we have to subtract this block hits so
206          * the next iteration will find most suitable block for
207          * the rest of requested elements.
208          */
209
210         mlxsw_afk_element_usage_for_each(element, elusage)
211                 mlxsw_afk_picker_count_hits(mlxsw_afk, picker, element);
212
213         do {
214                 int block_index;
215
216                 block_index = mlxsw_afk_picker_most_hits_get(mlxsw_afk, picker);
217                 if (block_index < 0) {
218                         err = block_index;
219                         goto out;
220                 }
221                 err = mlxsw_afk_picker_key_info_add(mlxsw_afk, picker,
222                                                     block_index, key_info);
223                 if (err)
224                         goto out;
225                 mlxsw_afk_picker_subtract_hits(mlxsw_afk, picker, block_index);
226         } while (!mlxsw_afk_key_info_elements_eq(key_info, elusage));
227
228         err = 0;
229 out:
230         kfree(picker);
231         return err;
232 }
233
234 static struct mlxsw_afk_key_info *
235 mlxsw_afk_key_info_create(struct mlxsw_afk *mlxsw_afk,
236                           struct mlxsw_afk_element_usage *elusage)
237 {
238         struct mlxsw_afk_key_info *key_info;
239         size_t alloc_size;
240         int err;
241
242         alloc_size = sizeof(*key_info) +
243                      sizeof(key_info->blocks[0]) * mlxsw_afk->max_blocks;
244         key_info = kzalloc(alloc_size, GFP_KERNEL);
245         if (!key_info)
246                 return ERR_PTR(-ENOMEM);
247         err = mlxsw_afk_picker(mlxsw_afk, key_info, elusage);
248         if (err)
249                 goto err_picker;
250         list_add(&key_info->list, &mlxsw_afk->key_info_list);
251         key_info->ref_count = 1;
252         return key_info;
253
254 err_picker:
255         kfree(key_info);
256         return ERR_PTR(err);
257 }
258
259 static void mlxsw_afk_key_info_destroy(struct mlxsw_afk_key_info *key_info)
260 {
261         list_del(&key_info->list);
262         kfree(key_info);
263 }
264
265 struct mlxsw_afk_key_info *
266 mlxsw_afk_key_info_get(struct mlxsw_afk *mlxsw_afk,
267                        struct mlxsw_afk_element_usage *elusage)
268 {
269         struct mlxsw_afk_key_info *key_info;
270
271         key_info = mlxsw_afk_key_info_find(mlxsw_afk, elusage);
272         if (key_info) {
273                 key_info->ref_count++;
274                 return key_info;
275         }
276         return mlxsw_afk_key_info_create(mlxsw_afk, elusage);
277 }
278 EXPORT_SYMBOL(mlxsw_afk_key_info_get);
279
280 void mlxsw_afk_key_info_put(struct mlxsw_afk_key_info *key_info)
281 {
282         if (--key_info->ref_count)
283                 return;
284         mlxsw_afk_key_info_destroy(key_info);
285 }
286 EXPORT_SYMBOL(mlxsw_afk_key_info_put);
287
288 bool mlxsw_afk_key_info_subset(struct mlxsw_afk_key_info *key_info,
289                                struct mlxsw_afk_element_usage *elusage)
290 {
291         return mlxsw_afk_element_usage_subset(elusage, &key_info->elusage);
292 }
293 EXPORT_SYMBOL(mlxsw_afk_key_info_subset);
294
295 static const struct mlxsw_afk_element_inst *
296 mlxsw_afk_block_elinst_get(const struct mlxsw_afk_block *block,
297                            enum mlxsw_afk_element element)
298 {
299         int i;
300
301         for (i = 0; i < block->instances_count; i++) {
302                 struct mlxsw_afk_element_inst *elinst;
303
304                 elinst = &block->instances[i];
305                 if (elinst->info->element == element)
306                         return elinst;
307         }
308         return NULL;
309 }
310
311 static const struct mlxsw_afk_element_inst *
312 mlxsw_afk_key_info_elinst_get(struct mlxsw_afk_key_info *key_info,
313                               enum mlxsw_afk_element element,
314                               int *p_block_index)
315 {
316         const struct mlxsw_afk_element_inst *elinst;
317         const struct mlxsw_afk_block *block;
318         int block_index;
319
320         if (WARN_ON(!test_bit(element, key_info->elusage.usage)))
321                 return NULL;
322         block_index = key_info->element_to_block[element];
323         block = key_info->blocks[block_index];
324
325         elinst = mlxsw_afk_block_elinst_get(block, element);
326         if (WARN_ON(!elinst))
327                 return NULL;
328
329         *p_block_index = block_index;
330         return elinst;
331 }
332
333 u16
334 mlxsw_afk_key_info_block_encoding_get(const struct mlxsw_afk_key_info *key_info,
335                                       int block_index)
336 {
337         return key_info->blocks[block_index]->encoding;
338 }
339 EXPORT_SYMBOL(mlxsw_afk_key_info_block_encoding_get);
340
341 unsigned int
342 mlxsw_afk_key_info_blocks_count_get(const struct mlxsw_afk_key_info *key_info)
343 {
344         return key_info->blocks_count;
345 }
346 EXPORT_SYMBOL(mlxsw_afk_key_info_blocks_count_get);
347
348 void mlxsw_afk_values_add_u32(struct mlxsw_afk_element_values *values,
349                               enum mlxsw_afk_element element,
350                               u32 key_value, u32 mask_value)
351 {
352         const struct mlxsw_afk_element_info *elinfo =
353                                 &mlxsw_afk_element_infos[element];
354         const struct mlxsw_item *storage_item = &elinfo->item;
355
356         if (!mask_value)
357                 return;
358         if (WARN_ON(elinfo->type != MLXSW_AFK_ELEMENT_TYPE_U32))
359                 return;
360         __mlxsw_item_set32(values->storage.key, storage_item, 0, key_value);
361         __mlxsw_item_set32(values->storage.mask, storage_item, 0, mask_value);
362         mlxsw_afk_element_usage_add(&values->elusage, element);
363 }
364 EXPORT_SYMBOL(mlxsw_afk_values_add_u32);
365
366 void mlxsw_afk_values_add_buf(struct mlxsw_afk_element_values *values,
367                               enum mlxsw_afk_element element,
368                               const char *key_value, const char *mask_value,
369                               unsigned int len)
370 {
371         const struct mlxsw_afk_element_info *elinfo =
372                                 &mlxsw_afk_element_infos[element];
373         const struct mlxsw_item *storage_item = &elinfo->item;
374
375         if (!memchr_inv(mask_value, 0, len)) /* If mask is zero */
376                 return;
377         if (WARN_ON(elinfo->type != MLXSW_AFK_ELEMENT_TYPE_BUF) ||
378             WARN_ON(elinfo->item.size.bytes != len))
379                 return;
380         __mlxsw_item_memcpy_to(values->storage.key, key_value,
381                                storage_item, 0);
382         __mlxsw_item_memcpy_to(values->storage.mask, mask_value,
383                                storage_item, 0);
384         mlxsw_afk_element_usage_add(&values->elusage, element);
385 }
386 EXPORT_SYMBOL(mlxsw_afk_values_add_buf);
387
388 static void mlxsw_sp_afk_encode_u32(const struct mlxsw_item *storage_item,
389                                     const struct mlxsw_item *output_item,
390                                     char *storage, char *output)
391 {
392         u32 value;
393
394         value = __mlxsw_item_get32(storage, storage_item, 0);
395         __mlxsw_item_set32(output, output_item, 0, value);
396 }
397
398 static void mlxsw_sp_afk_encode_buf(const struct mlxsw_item *storage_item,
399                                     const struct mlxsw_item *output_item,
400                                     char *storage, char *output)
401 {
402         char *storage_data = __mlxsw_item_data(storage, storage_item, 0);
403         char *output_data = __mlxsw_item_data(output, output_item, 0);
404         size_t len = output_item->size.bytes;
405
406         memcpy(output_data, storage_data, len);
407 }
408
409 static void
410 mlxsw_sp_afk_encode_one(const struct mlxsw_afk_element_inst *elinst,
411                         char *output, char *storage)
412 {
413         const struct mlxsw_item *storage_item = &elinst->info->item;
414         const struct mlxsw_item *output_item = &elinst->item;
415
416         if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_U32)
417                 mlxsw_sp_afk_encode_u32(storage_item, output_item,
418                                         storage, output);
419         else if (elinst->type == MLXSW_AFK_ELEMENT_TYPE_BUF)
420                 mlxsw_sp_afk_encode_buf(storage_item, output_item,
421                                         storage, output);
422 }
423
424 #define MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE 16
425
426 void mlxsw_afk_encode(struct mlxsw_afk *mlxsw_afk,
427                       struct mlxsw_afk_key_info *key_info,
428                       struct mlxsw_afk_element_values *values,
429                       char *key, char *mask, int block_start, int block_end)
430 {
431         char block_mask[MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE];
432         char block_key[MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE];
433         const struct mlxsw_afk_element_inst *elinst;
434         enum mlxsw_afk_element element;
435         int block_index, i;
436
437         for (i = block_start; i <= block_end; i++) {
438                 memset(block_key, 0, MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE);
439                 memset(block_mask, 0, MLXSW_SP_AFK_KEY_BLOCK_MAX_SIZE);
440
441                 mlxsw_afk_element_usage_for_each(element, &values->elusage) {
442                         elinst = mlxsw_afk_key_info_elinst_get(key_info,
443                                                                element,
444                                                                &block_index);
445                         if (!elinst || block_index != i)
446                                 continue;
447
448                         mlxsw_sp_afk_encode_one(elinst, block_key,
449                                                 values->storage.key);
450                         mlxsw_sp_afk_encode_one(elinst, block_mask,
451                                                 values->storage.mask);
452                 }
453
454                 if (key)
455                         mlxsw_afk->ops->encode_block(block_key, i, key);
456                 if (mask)
457                         mlxsw_afk->ops->encode_block(block_mask, i, mask);
458         }
459 }
460 EXPORT_SYMBOL(mlxsw_afk_encode);