.. | .. |
---|
7 | 7 | #include <linux/gfp.h> |
---|
8 | 8 | #include <linux/kernel.h> |
---|
9 | 9 | #include <linux/list.h> |
---|
10 | | -#include <linux/rhashtable.h> |
---|
| 10 | +#include <linux/mutex.h> |
---|
| 11 | +#include <linux/objagg.h> |
---|
11 | 12 | #include <linux/rtnetlink.h> |
---|
12 | 13 | #include <linux/slab.h> |
---|
13 | 14 | |
---|
.. | .. |
---|
24 | 25 | unsigned int erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_MAX + 1]; |
---|
25 | 26 | struct gen_pool *erp_tables; |
---|
26 | 27 | struct mlxsw_sp *mlxsw_sp; |
---|
| 28 | + struct mlxsw_sp_acl_bf *bf; |
---|
27 | 29 | unsigned int num_erp_banks; |
---|
28 | 30 | }; |
---|
29 | 31 | |
---|
30 | 32 | struct mlxsw_sp_acl_erp_key { |
---|
31 | 33 | char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN]; |
---|
| 34 | +#define __MASK_LEN 0x38 |
---|
| 35 | +#define __MASK_IDX(i) (__MASK_LEN - (i) - 1) |
---|
32 | 36 | bool ctcam; |
---|
33 | 37 | }; |
---|
34 | 38 | |
---|
.. | .. |
---|
36 | 40 | struct mlxsw_sp_acl_erp_key key; |
---|
37 | 41 | u8 id; |
---|
38 | 42 | u8 index; |
---|
39 | | - refcount_t refcnt; |
---|
40 | 43 | DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN); |
---|
41 | 44 | struct list_head list; |
---|
42 | | - struct rhash_head ht_node; |
---|
43 | 45 | struct mlxsw_sp_acl_erp_table *erp_table; |
---|
44 | 46 | }; |
---|
45 | 47 | |
---|
.. | .. |
---|
53 | 55 | DECLARE_BITMAP(erp_id_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION); |
---|
54 | 56 | DECLARE_BITMAP(erp_index_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION); |
---|
55 | 57 | struct list_head atcam_erps_list; |
---|
56 | | - struct rhashtable erp_ht; |
---|
57 | 58 | struct mlxsw_sp_acl_erp_core *erp_core; |
---|
58 | 59 | struct mlxsw_sp_acl_atcam_region *aregion; |
---|
59 | 60 | const struct mlxsw_sp_acl_erp_table_ops *ops; |
---|
.. | .. |
---|
61 | 62 | unsigned int num_atcam_erps; |
---|
62 | 63 | unsigned int num_max_atcam_erps; |
---|
63 | 64 | unsigned int num_ctcam_erps; |
---|
64 | | -}; |
---|
65 | | - |
---|
66 | | -static const struct rhashtable_params mlxsw_sp_acl_erp_ht_params = { |
---|
67 | | - .key_len = sizeof(struct mlxsw_sp_acl_erp_key), |
---|
68 | | - .key_offset = offsetof(struct mlxsw_sp_acl_erp, key), |
---|
69 | | - .head_offset = offsetof(struct mlxsw_sp_acl_erp, ht_node), |
---|
| 65 | + unsigned int num_deltas; |
---|
| 66 | + struct objagg *objagg; |
---|
| 67 | + struct mutex objagg_lock; /* guards objagg manipulation */ |
---|
70 | 68 | }; |
---|
71 | 69 | |
---|
72 | 70 | struct mlxsw_sp_acl_erp_table_ops { |
---|
.. | .. |
---|
119 | 117 | .erp_destroy = mlxsw_sp_acl_erp_no_mask_destroy, |
---|
120 | 118 | }; |
---|
121 | 119 | |
---|
122 | | -bool mlxsw_sp_acl_erp_is_ctcam_erp(const struct mlxsw_sp_acl_erp *erp) |
---|
| 120 | +static bool |
---|
| 121 | +mlxsw_sp_acl_erp_table_is_used(const struct mlxsw_sp_acl_erp_table *erp_table) |
---|
123 | 122 | { |
---|
124 | | - return erp->key.ctcam; |
---|
| 123 | + return erp_table->ops != &erp_single_mask_ops && |
---|
| 124 | + erp_table->ops != &erp_no_mask_ops; |
---|
125 | 125 | } |
---|
126 | 126 | |
---|
127 | | -u8 mlxsw_sp_acl_erp_id(const struct mlxsw_sp_acl_erp *erp) |
---|
| 127 | +static unsigned int |
---|
| 128 | +mlxsw_sp_acl_erp_bank_get(const struct mlxsw_sp_acl_erp *erp) |
---|
128 | 129 | { |
---|
129 | | - return erp->id; |
---|
| 130 | + return erp->index % erp->erp_table->erp_core->num_erp_banks; |
---|
130 | 131 | } |
---|
131 | 132 | |
---|
132 | 133 | static unsigned int |
---|
.. | .. |
---|
194 | 195 | |
---|
195 | 196 | static int |
---|
196 | 197 | mlxsw_sp_acl_erp_master_mask_set(struct mlxsw_sp_acl_erp_table *erp_table, |
---|
197 | | - const struct mlxsw_sp_acl_erp *erp) |
---|
| 198 | + struct mlxsw_sp_acl_erp_key *key) |
---|
198 | 199 | { |
---|
| 200 | + DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN); |
---|
199 | 201 | unsigned long bit; |
---|
200 | 202 | int err; |
---|
201 | 203 | |
---|
202 | | - for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) |
---|
| 204 | + bitmap_from_arr32(mask_bitmap, (u32 *) key->mask, |
---|
| 205 | + MLXSW_SP_ACL_TCAM_MASK_LEN); |
---|
| 206 | + for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) |
---|
203 | 207 | mlxsw_sp_acl_erp_master_mask_bit_set(bit, |
---|
204 | 208 | &erp_table->master_mask); |
---|
205 | 209 | |
---|
.. | .. |
---|
210 | 214 | return 0; |
---|
211 | 215 | |
---|
212 | 216 | err_master_mask_update: |
---|
213 | | - for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) |
---|
| 217 | + for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) |
---|
214 | 218 | mlxsw_sp_acl_erp_master_mask_bit_clear(bit, |
---|
215 | 219 | &erp_table->master_mask); |
---|
216 | 220 | return err; |
---|
.. | .. |
---|
218 | 222 | |
---|
219 | 223 | static int |
---|
220 | 224 | mlxsw_sp_acl_erp_master_mask_clear(struct mlxsw_sp_acl_erp_table *erp_table, |
---|
221 | | - const struct mlxsw_sp_acl_erp *erp) |
---|
| 225 | + struct mlxsw_sp_acl_erp_key *key) |
---|
222 | 226 | { |
---|
| 227 | + DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN); |
---|
223 | 228 | unsigned long bit; |
---|
224 | 229 | int err; |
---|
225 | 230 | |
---|
226 | | - for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) |
---|
| 231 | + bitmap_from_arr32(mask_bitmap, (u32 *) key->mask, |
---|
| 232 | + MLXSW_SP_ACL_TCAM_MASK_LEN); |
---|
| 233 | + for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) |
---|
227 | 234 | mlxsw_sp_acl_erp_master_mask_bit_clear(bit, |
---|
228 | 235 | &erp_table->master_mask); |
---|
229 | 236 | |
---|
.. | .. |
---|
234 | 241 | return 0; |
---|
235 | 242 | |
---|
236 | 243 | err_master_mask_update: |
---|
237 | | - for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) |
---|
| 244 | + for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN) |
---|
238 | 245 | mlxsw_sp_acl_erp_master_mask_bit_set(bit, |
---|
239 | 246 | &erp_table->master_mask); |
---|
240 | 247 | return err; |
---|
.. | .. |
---|
256 | 263 | goto err_erp_id_get; |
---|
257 | 264 | |
---|
258 | 265 | memcpy(&erp->key, key, sizeof(*key)); |
---|
259 | | - bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask, |
---|
260 | | - MLXSW_SP_ACL_TCAM_MASK_LEN); |
---|
261 | 266 | list_add(&erp->list, &erp_table->atcam_erps_list); |
---|
262 | | - refcount_set(&erp->refcnt, 1); |
---|
263 | 267 | erp_table->num_atcam_erps++; |
---|
264 | 268 | erp->erp_table = erp_table; |
---|
265 | 269 | |
---|
266 | | - err = mlxsw_sp_acl_erp_master_mask_set(erp_table, erp); |
---|
| 270 | + err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key); |
---|
267 | 271 | if (err) |
---|
268 | 272 | goto err_master_mask_set; |
---|
269 | 273 | |
---|
270 | | - err = rhashtable_insert_fast(&erp_table->erp_ht, &erp->ht_node, |
---|
271 | | - mlxsw_sp_acl_erp_ht_params); |
---|
272 | | - if (err) |
---|
273 | | - goto err_rhashtable_insert; |
---|
274 | | - |
---|
275 | 274 | return erp; |
---|
276 | 275 | |
---|
277 | | -err_rhashtable_insert: |
---|
278 | | - mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp); |
---|
279 | 276 | err_master_mask_set: |
---|
280 | 277 | erp_table->num_atcam_erps--; |
---|
281 | 278 | list_del(&erp->list); |
---|
.. | .. |
---|
290 | 287 | { |
---|
291 | 288 | struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table; |
---|
292 | 289 | |
---|
293 | | - rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node, |
---|
294 | | - mlxsw_sp_acl_erp_ht_params); |
---|
295 | | - mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp); |
---|
| 290 | + mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key); |
---|
296 | 291 | erp_table->num_atcam_erps--; |
---|
297 | 292 | list_del(&erp->list); |
---|
298 | 293 | mlxsw_sp_acl_erp_id_put(erp_table, erp->id); |
---|
.. | .. |
---|
525 | 520 | } |
---|
526 | 521 | |
---|
527 | 522 | static int |
---|
| 523 | +mlxsw_acl_erp_table_bf_add(struct mlxsw_sp_acl_erp_table *erp_table, |
---|
| 524 | + struct mlxsw_sp_acl_erp *erp) |
---|
| 525 | +{ |
---|
| 526 | + struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion; |
---|
| 527 | + unsigned int erp_bank = mlxsw_sp_acl_erp_bank_get(erp); |
---|
| 528 | + struct mlxsw_sp_acl_atcam_entry *aentry; |
---|
| 529 | + int err; |
---|
| 530 | + |
---|
| 531 | + list_for_each_entry(aentry, &aregion->entries_list, list) { |
---|
| 532 | + err = mlxsw_sp_acl_bf_entry_add(aregion->region->mlxsw_sp, |
---|
| 533 | + erp_table->erp_core->bf, |
---|
| 534 | + aregion, erp_bank, aentry); |
---|
| 535 | + if (err) |
---|
| 536 | + goto bf_entry_add_err; |
---|
| 537 | + } |
---|
| 538 | + |
---|
| 539 | + return 0; |
---|
| 540 | + |
---|
| 541 | +bf_entry_add_err: |
---|
| 542 | + list_for_each_entry_continue_reverse(aentry, &aregion->entries_list, |
---|
| 543 | + list) |
---|
| 544 | + mlxsw_sp_acl_bf_entry_del(aregion->region->mlxsw_sp, |
---|
| 545 | + erp_table->erp_core->bf, |
---|
| 546 | + aregion, erp_bank, aentry); |
---|
| 547 | + return err; |
---|
| 548 | +} |
---|
| 549 | + |
---|
| 550 | +static void |
---|
| 551 | +mlxsw_acl_erp_table_bf_del(struct mlxsw_sp_acl_erp_table *erp_table, |
---|
| 552 | + struct mlxsw_sp_acl_erp *erp) |
---|
| 553 | +{ |
---|
| 554 | + struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion; |
---|
| 555 | + unsigned int erp_bank = mlxsw_sp_acl_erp_bank_get(erp); |
---|
| 556 | + struct mlxsw_sp_acl_atcam_entry *aentry; |
---|
| 557 | + |
---|
| 558 | + list_for_each_entry_reverse(aentry, &aregion->entries_list, list) |
---|
| 559 | + mlxsw_sp_acl_bf_entry_del(aregion->region->mlxsw_sp, |
---|
| 560 | + erp_table->erp_core->bf, |
---|
| 561 | + aregion, erp_bank, aentry); |
---|
| 562 | +} |
---|
| 563 | + |
---|
| 564 | +static int |
---|
528 | 565 | mlxsw_sp_acl_erp_region_table_trans(struct mlxsw_sp_acl_erp_table *erp_table) |
---|
529 | 566 | { |
---|
530 | 567 | struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core; |
---|
.. | .. |
---|
548 | 585 | goto err_table_master_rp; |
---|
549 | 586 | } |
---|
550 | 587 | |
---|
551 | | - /* Maintain the same eRP bank for the master RP, so that we |
---|
552 | | - * wouldn't need to update the bloom filter |
---|
| 588 | + /* Make sure the master RP is using a valid index, as |
---|
| 589 | + * only a single eRP row is currently allocated. |
---|
553 | 590 | */ |
---|
554 | | - master_rp->index = master_rp->index % erp_core->num_erp_banks; |
---|
| 591 | + master_rp->index = 0; |
---|
555 | 592 | __set_bit(master_rp->index, erp_table->erp_index_bitmap); |
---|
556 | 593 | |
---|
557 | 594 | err = mlxsw_sp_acl_erp_table_erp_add(erp_table, master_rp); |
---|
558 | 595 | if (err) |
---|
559 | 596 | goto err_table_master_rp_add; |
---|
| 597 | + |
---|
| 598 | + /* Update Bloom filter before enabling eRP table, as rules |
---|
| 599 | + * on the master RP were not set to Bloom filter up to this |
---|
| 600 | + * point. |
---|
| 601 | + */ |
---|
| 602 | + err = mlxsw_acl_erp_table_bf_add(erp_table, master_rp); |
---|
| 603 | + if (err) |
---|
| 604 | + goto err_table_bf_add; |
---|
560 | 605 | |
---|
561 | 606 | err = mlxsw_sp_acl_erp_table_enable(erp_table, false); |
---|
562 | 607 | if (err) |
---|
.. | .. |
---|
565 | 610 | return 0; |
---|
566 | 611 | |
---|
567 | 612 | err_table_enable: |
---|
| 613 | + mlxsw_acl_erp_table_bf_del(erp_table, master_rp); |
---|
| 614 | +err_table_bf_add: |
---|
568 | 615 | mlxsw_sp_acl_erp_table_erp_del(master_rp); |
---|
569 | 616 | err_table_master_rp_add: |
---|
570 | 617 | __clear_bit(master_rp->index, erp_table->erp_index_bitmap); |
---|
.. | .. |
---|
585 | 632 | master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table); |
---|
586 | 633 | if (!master_rp) |
---|
587 | 634 | return; |
---|
| 635 | + mlxsw_acl_erp_table_bf_del(erp_table, master_rp); |
---|
588 | 636 | mlxsw_sp_acl_erp_table_erp_del(master_rp); |
---|
589 | 637 | __clear_bit(master_rp->index, erp_table->erp_index_bitmap); |
---|
590 | 638 | mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps, |
---|
.. | .. |
---|
647 | 695 | mlxsw_sp_acl_erp_table_enable(erp_table, false); |
---|
648 | 696 | } |
---|
649 | 697 | |
---|
650 | | -static void |
---|
651 | | -mlxsw_sp_acl_erp_ctcam_table_ops_set(struct mlxsw_sp_acl_erp_table *erp_table) |
---|
| 698 | +static int |
---|
| 699 | +__mlxsw_sp_acl_erp_table_other_inc(struct mlxsw_sp_acl_erp_table *erp_table, |
---|
| 700 | + unsigned int *inc_num) |
---|
652 | 701 | { |
---|
| 702 | + int err; |
---|
| 703 | + |
---|
| 704 | + /* If there are C-TCAM eRP or deltas in use we need to transition |
---|
| 705 | + * the region to use eRP table, if it is not already done |
---|
| 706 | + */ |
---|
| 707 | + if (!mlxsw_sp_acl_erp_table_is_used(erp_table)) { |
---|
| 708 | + err = mlxsw_sp_acl_erp_region_table_trans(erp_table); |
---|
| 709 | + if (err) |
---|
| 710 | + return err; |
---|
| 711 | + } |
---|
| 712 | + |
---|
| 713 | + /* When C-TCAM or deltas are used, the eRP table must be used */ |
---|
| 714 | + if (erp_table->ops != &erp_multiple_masks_ops) |
---|
| 715 | + erp_table->ops = &erp_multiple_masks_ops; |
---|
| 716 | + |
---|
| 717 | + (*inc_num)++; |
---|
| 718 | + |
---|
| 719 | + return 0; |
---|
| 720 | +} |
---|
| 721 | + |
---|
| 722 | +static int mlxsw_sp_acl_erp_ctcam_inc(struct mlxsw_sp_acl_erp_table *erp_table) |
---|
| 723 | +{ |
---|
| 724 | + return __mlxsw_sp_acl_erp_table_other_inc(erp_table, |
---|
| 725 | + &erp_table->num_ctcam_erps); |
---|
| 726 | +} |
---|
| 727 | + |
---|
| 728 | +static int mlxsw_sp_acl_erp_delta_inc(struct mlxsw_sp_acl_erp_table *erp_table) |
---|
| 729 | +{ |
---|
| 730 | + return __mlxsw_sp_acl_erp_table_other_inc(erp_table, |
---|
| 731 | + &erp_table->num_deltas); |
---|
| 732 | +} |
---|
| 733 | + |
---|
| 734 | +static void |
---|
| 735 | +__mlxsw_sp_acl_erp_table_other_dec(struct mlxsw_sp_acl_erp_table *erp_table, |
---|
| 736 | + unsigned int *dec_num) |
---|
| 737 | +{ |
---|
| 738 | + (*dec_num)--; |
---|
| 739 | + |
---|
| 740 | + /* If there are no C-TCAM eRP or deltas in use, the state we |
---|
| 741 | + * transition to depends on the number of A-TCAM eRPs currently |
---|
| 742 | + * in use. |
---|
| 743 | + */ |
---|
| 744 | + if (erp_table->num_ctcam_erps > 0 || erp_table->num_deltas > 0) |
---|
| 745 | + return; |
---|
| 746 | + |
---|
653 | 747 | switch (erp_table->num_atcam_erps) { |
---|
654 | 748 | case 2: |
---|
655 | 749 | /* Keep using the eRP table, but correctly set the |
---|
.. | .. |
---|
683 | 777 | } |
---|
684 | 778 | } |
---|
685 | 779 | |
---|
| 780 | +static void mlxsw_sp_acl_erp_ctcam_dec(struct mlxsw_sp_acl_erp_table *erp_table) |
---|
| 781 | +{ |
---|
| 782 | + __mlxsw_sp_acl_erp_table_other_dec(erp_table, |
---|
| 783 | + &erp_table->num_ctcam_erps); |
---|
| 784 | +} |
---|
| 785 | + |
---|
| 786 | +static void mlxsw_sp_acl_erp_delta_dec(struct mlxsw_sp_acl_erp_table *erp_table) |
---|
| 787 | +{ |
---|
| 788 | + __mlxsw_sp_acl_erp_table_other_dec(erp_table, |
---|
| 789 | + &erp_table->num_deltas); |
---|
| 790 | +} |
---|
| 791 | + |
---|
686 | 792 | static struct mlxsw_sp_acl_erp * |
---|
687 | | -__mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, |
---|
688 | | - struct mlxsw_sp_acl_erp_key *key) |
---|
| 793 | +mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, |
---|
| 794 | + struct mlxsw_sp_acl_erp_key *key) |
---|
689 | 795 | { |
---|
690 | 796 | struct mlxsw_sp_acl_erp *erp; |
---|
691 | 797 | int err; |
---|
.. | .. |
---|
697 | 803 | memcpy(&erp->key, key, sizeof(*key)); |
---|
698 | 804 | bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask, |
---|
699 | 805 | MLXSW_SP_ACL_TCAM_MASK_LEN); |
---|
700 | | - refcount_set(&erp->refcnt, 1); |
---|
701 | | - erp_table->num_ctcam_erps++; |
---|
| 806 | + |
---|
| 807 | + err = mlxsw_sp_acl_erp_ctcam_inc(erp_table); |
---|
| 808 | + if (err) |
---|
| 809 | + goto err_erp_ctcam_inc; |
---|
| 810 | + |
---|
702 | 811 | erp->erp_table = erp_table; |
---|
703 | 812 | |
---|
704 | | - err = mlxsw_sp_acl_erp_master_mask_set(erp_table, erp); |
---|
| 813 | + err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key); |
---|
705 | 814 | if (err) |
---|
706 | 815 | goto err_master_mask_set; |
---|
707 | | - |
---|
708 | | - err = rhashtable_insert_fast(&erp_table->erp_ht, &erp->ht_node, |
---|
709 | | - mlxsw_sp_acl_erp_ht_params); |
---|
710 | | - if (err) |
---|
711 | | - goto err_rhashtable_insert; |
---|
712 | 816 | |
---|
713 | 817 | err = mlxsw_sp_acl_erp_region_ctcam_enable(erp_table); |
---|
714 | 818 | if (err) |
---|
715 | 819 | goto err_erp_region_ctcam_enable; |
---|
716 | 820 | |
---|
717 | | - /* When C-TCAM is used, the eRP table must be used */ |
---|
718 | | - erp_table->ops = &erp_multiple_masks_ops; |
---|
719 | | - |
---|
720 | 821 | return erp; |
---|
721 | 822 | |
---|
722 | 823 | err_erp_region_ctcam_enable: |
---|
723 | | - rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node, |
---|
724 | | - mlxsw_sp_acl_erp_ht_params); |
---|
725 | | -err_rhashtable_insert: |
---|
726 | | - mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp); |
---|
| 824 | + mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key); |
---|
727 | 825 | err_master_mask_set: |
---|
728 | | - erp_table->num_ctcam_erps--; |
---|
| 826 | + mlxsw_sp_acl_erp_ctcam_dec(erp_table); |
---|
| 827 | +err_erp_ctcam_inc: |
---|
729 | 828 | kfree(erp); |
---|
730 | | - return ERR_PTR(err); |
---|
731 | | -} |
---|
732 | | - |
---|
733 | | -static struct mlxsw_sp_acl_erp * |
---|
734 | | -mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table, |
---|
735 | | - struct mlxsw_sp_acl_erp_key *key) |
---|
736 | | -{ |
---|
737 | | - struct mlxsw_sp_acl_erp *erp; |
---|
738 | | - int err; |
---|
739 | | - |
---|
740 | | - /* There is a special situation where we need to spill rules |
---|
741 | | - * into the C-TCAM, yet the region is still using a master |
---|
742 | | - * mask and thus not performing a lookup in the C-TCAM. This |
---|
743 | | - * can happen when two rules that only differ in priority - and |
---|
744 | | - * thus sharing the same key - are programmed. In this case |
---|
745 | | - * we transition the region to use an eRP table |
---|
746 | | - */ |
---|
747 | | - err = mlxsw_sp_acl_erp_region_table_trans(erp_table); |
---|
748 | | - if (err) |
---|
749 | | - return ERR_PTR(err); |
---|
750 | | - |
---|
751 | | - erp = __mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key); |
---|
752 | | - if (IS_ERR(erp)) { |
---|
753 | | - err = PTR_ERR(erp); |
---|
754 | | - goto err_erp_create; |
---|
755 | | - } |
---|
756 | | - |
---|
757 | | - return erp; |
---|
758 | | - |
---|
759 | | -err_erp_create: |
---|
760 | | - mlxsw_sp_acl_erp_region_master_mask_trans(erp_table); |
---|
761 | 829 | return ERR_PTR(err); |
---|
762 | 830 | } |
---|
763 | 831 | |
---|
.. | .. |
---|
767 | 835 | struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table; |
---|
768 | 836 | |
---|
769 | 837 | mlxsw_sp_acl_erp_region_ctcam_disable(erp_table); |
---|
770 | | - rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node, |
---|
771 | | - mlxsw_sp_acl_erp_ht_params); |
---|
772 | | - mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp); |
---|
773 | | - erp_table->num_ctcam_erps--; |
---|
| 838 | + mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key); |
---|
| 839 | + mlxsw_sp_acl_erp_ctcam_dec(erp_table); |
---|
774 | 840 | kfree(erp); |
---|
775 | | - |
---|
776 | | - /* Once the last C-TCAM eRP was destroyed, the state we |
---|
777 | | - * transition to depends on the number of A-TCAM eRPs currently |
---|
778 | | - * in use |
---|
779 | | - */ |
---|
780 | | - if (erp_table->num_ctcam_erps > 0) |
---|
781 | | - return; |
---|
782 | | - mlxsw_sp_acl_erp_ctcam_table_ops_set(erp_table); |
---|
783 | 841 | } |
---|
784 | 842 | |
---|
785 | 843 | static struct mlxsw_sp_acl_erp * |
---|
.. | .. |
---|
790 | 848 | int err; |
---|
791 | 849 | |
---|
792 | 850 | if (key->ctcam) |
---|
793 | | - return __mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key); |
---|
| 851 | + return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key); |
---|
794 | 852 | |
---|
795 | 853 | /* Expand the eRP table for the new eRP, if needed */ |
---|
796 | 854 | err = mlxsw_sp_acl_erp_table_expand(erp_table); |
---|
.. | .. |
---|
838 | 896 | mlxsw_sp_acl_erp_index_put(erp_table, erp->index); |
---|
839 | 897 | mlxsw_sp_acl_erp_generic_destroy(erp); |
---|
840 | 898 | |
---|
841 | | - if (erp_table->num_atcam_erps == 2 && erp_table->num_ctcam_erps == 0) |
---|
| 899 | + if (erp_table->num_atcam_erps == 2 && erp_table->num_ctcam_erps == 0 && |
---|
| 900 | + erp_table->num_deltas == 0) |
---|
842 | 901 | erp_table->ops = &erp_two_masks_ops; |
---|
843 | 902 | } |
---|
844 | 903 | |
---|
.. | .. |
---|
940 | 999 | WARN_ON(1); |
---|
941 | 1000 | } |
---|
942 | 1001 | |
---|
943 | | -struct mlxsw_sp_acl_erp * |
---|
944 | | -mlxsw_sp_acl_erp_get(struct mlxsw_sp_acl_atcam_region *aregion, |
---|
945 | | - const char *mask, bool ctcam) |
---|
| 1002 | +struct mlxsw_sp_acl_erp_mask * |
---|
| 1003 | +mlxsw_sp_acl_erp_mask_get(struct mlxsw_sp_acl_atcam_region *aregion, |
---|
| 1004 | + const char *mask, bool ctcam) |
---|
946 | 1005 | { |
---|
947 | 1006 | struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; |
---|
948 | 1007 | struct mlxsw_sp_acl_erp_key key; |
---|
949 | | - struct mlxsw_sp_acl_erp *erp; |
---|
950 | | - |
---|
951 | | - /* eRPs are allocated from a shared resource, but currently all |
---|
952 | | - * allocations are done under RTNL. |
---|
953 | | - */ |
---|
954 | | - ASSERT_RTNL(); |
---|
| 1008 | + struct objagg_obj *objagg_obj; |
---|
955 | 1009 | |
---|
956 | 1010 | memcpy(key.mask, mask, MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN); |
---|
957 | 1011 | key.ctcam = ctcam; |
---|
958 | | - erp = rhashtable_lookup_fast(&erp_table->erp_ht, &key, |
---|
959 | | - mlxsw_sp_acl_erp_ht_params); |
---|
960 | | - if (erp) { |
---|
961 | | - refcount_inc(&erp->refcnt); |
---|
962 | | - return erp; |
---|
963 | | - } |
---|
964 | | - |
---|
965 | | - return erp_table->ops->erp_create(erp_table, &key); |
---|
| 1012 | + mutex_lock(&erp_table->objagg_lock); |
---|
| 1013 | + objagg_obj = objagg_obj_get(erp_table->objagg, &key); |
---|
| 1014 | + mutex_unlock(&erp_table->objagg_lock); |
---|
| 1015 | + if (IS_ERR(objagg_obj)) |
---|
| 1016 | + return ERR_CAST(objagg_obj); |
---|
| 1017 | + return (struct mlxsw_sp_acl_erp_mask *) objagg_obj; |
---|
966 | 1018 | } |
---|
967 | 1019 | |
---|
968 | | -void mlxsw_sp_acl_erp_put(struct mlxsw_sp_acl_atcam_region *aregion, |
---|
969 | | - struct mlxsw_sp_acl_erp *erp) |
---|
| 1020 | +void mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region *aregion, |
---|
| 1021 | + struct mlxsw_sp_acl_erp_mask *erp_mask) |
---|
970 | 1022 | { |
---|
| 1023 | + struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask; |
---|
971 | 1024 | struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; |
---|
972 | 1025 | |
---|
973 | | - ASSERT_RTNL(); |
---|
974 | | - |
---|
975 | | - if (!refcount_dec_and_test(&erp->refcnt)) |
---|
976 | | - return; |
---|
977 | | - |
---|
978 | | - erp_table->ops->erp_destroy(erp_table, erp); |
---|
| 1026 | + mutex_lock(&erp_table->objagg_lock); |
---|
| 1027 | + objagg_obj_put(erp_table->objagg, objagg_obj); |
---|
| 1028 | + mutex_unlock(&erp_table->objagg_lock); |
---|
979 | 1029 | } |
---|
980 | 1030 | |
---|
| 1031 | +int mlxsw_sp_acl_erp_bf_insert(struct mlxsw_sp *mlxsw_sp, |
---|
| 1032 | + struct mlxsw_sp_acl_atcam_region *aregion, |
---|
| 1033 | + struct mlxsw_sp_acl_erp_mask *erp_mask, |
---|
| 1034 | + struct mlxsw_sp_acl_atcam_entry *aentry) |
---|
| 1035 | +{ |
---|
| 1036 | + struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask; |
---|
| 1037 | + const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj); |
---|
| 1038 | + unsigned int erp_bank; |
---|
| 1039 | + |
---|
| 1040 | + if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table)) |
---|
| 1041 | + return 0; |
---|
| 1042 | + |
---|
| 1043 | + erp_bank = mlxsw_sp_acl_erp_bank_get(erp); |
---|
| 1044 | + return mlxsw_sp_acl_bf_entry_add(mlxsw_sp, |
---|
| 1045 | + erp->erp_table->erp_core->bf, |
---|
| 1046 | + aregion, erp_bank, aentry); |
---|
| 1047 | +} |
---|
| 1048 | + |
---|
| 1049 | +void mlxsw_sp_acl_erp_bf_remove(struct mlxsw_sp *mlxsw_sp, |
---|
| 1050 | + struct mlxsw_sp_acl_atcam_region *aregion, |
---|
| 1051 | + struct mlxsw_sp_acl_erp_mask *erp_mask, |
---|
| 1052 | + struct mlxsw_sp_acl_atcam_entry *aentry) |
---|
| 1053 | +{ |
---|
| 1054 | + struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask; |
---|
| 1055 | + const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj); |
---|
| 1056 | + unsigned int erp_bank; |
---|
| 1057 | + |
---|
| 1058 | + if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table)) |
---|
| 1059 | + return; |
---|
| 1060 | + |
---|
| 1061 | + erp_bank = mlxsw_sp_acl_erp_bank_get(erp); |
---|
| 1062 | + mlxsw_sp_acl_bf_entry_del(mlxsw_sp, |
---|
| 1063 | + erp->erp_table->erp_core->bf, |
---|
| 1064 | + aregion, erp_bank, aentry); |
---|
| 1065 | +} |
---|
| 1066 | + |
---|
| 1067 | +bool |
---|
| 1068 | +mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask *erp_mask) |
---|
| 1069 | +{ |
---|
| 1070 | + struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask; |
---|
| 1071 | + const struct mlxsw_sp_acl_erp_key *key = objagg_obj_raw(objagg_obj); |
---|
| 1072 | + |
---|
| 1073 | + return key->ctcam; |
---|
| 1074 | +} |
---|
| 1075 | + |
---|
| 1076 | +u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask) |
---|
| 1077 | +{ |
---|
| 1078 | + struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask; |
---|
| 1079 | + const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj); |
---|
| 1080 | + |
---|
| 1081 | + return erp->id; |
---|
| 1082 | +} |
---|
| 1083 | + |
---|
| 1084 | +struct mlxsw_sp_acl_erp_delta { |
---|
| 1085 | + struct mlxsw_sp_acl_erp_key key; |
---|
| 1086 | + u16 start; |
---|
| 1087 | + u8 mask; |
---|
| 1088 | +}; |
---|
| 1089 | + |
---|
| 1090 | +u16 mlxsw_sp_acl_erp_delta_start(const struct mlxsw_sp_acl_erp_delta *delta) |
---|
| 1091 | +{ |
---|
| 1092 | + return delta->start; |
---|
| 1093 | +} |
---|
| 1094 | + |
---|
| 1095 | +u8 mlxsw_sp_acl_erp_delta_mask(const struct mlxsw_sp_acl_erp_delta *delta) |
---|
| 1096 | +{ |
---|
| 1097 | + return delta->mask; |
---|
| 1098 | +} |
---|
| 1099 | + |
---|
| 1100 | +u8 mlxsw_sp_acl_erp_delta_value(const struct mlxsw_sp_acl_erp_delta *delta, |
---|
| 1101 | + const char *enc_key) |
---|
| 1102 | +{ |
---|
| 1103 | + u16 start = delta->start; |
---|
| 1104 | + u8 mask = delta->mask; |
---|
| 1105 | + u16 tmp; |
---|
| 1106 | + |
---|
| 1107 | + if (!mask) |
---|
| 1108 | + return 0; |
---|
| 1109 | + |
---|
| 1110 | + tmp = (unsigned char) enc_key[__MASK_IDX(start / 8)]; |
---|
| 1111 | + if (start / 8 + 1 < __MASK_LEN) |
---|
| 1112 | + tmp |= (unsigned char) enc_key[__MASK_IDX(start / 8 + 1)] << 8; |
---|
| 1113 | + tmp >>= start % 8; |
---|
| 1114 | + tmp &= mask; |
---|
| 1115 | + return tmp; |
---|
| 1116 | +} |
---|
| 1117 | + |
---|
| 1118 | +void mlxsw_sp_acl_erp_delta_clear(const struct mlxsw_sp_acl_erp_delta *delta, |
---|
| 1119 | + const char *enc_key) |
---|
| 1120 | +{ |
---|
| 1121 | + u16 start = delta->start; |
---|
| 1122 | + u8 mask = delta->mask; |
---|
| 1123 | + unsigned char *byte; |
---|
| 1124 | + u16 tmp; |
---|
| 1125 | + |
---|
| 1126 | + tmp = mask; |
---|
| 1127 | + tmp <<= start % 8; |
---|
| 1128 | + tmp = ~tmp; |
---|
| 1129 | + |
---|
| 1130 | + byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8)]; |
---|
| 1131 | + *byte &= tmp & 0xff; |
---|
| 1132 | + if (start / 8 + 1 < __MASK_LEN) { |
---|
| 1133 | + byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8 + 1)]; |
---|
| 1134 | + *byte &= (tmp >> 8) & 0xff; |
---|
| 1135 | + } |
---|
| 1136 | +} |
---|
| 1137 | + |
---|
| 1138 | +static const struct mlxsw_sp_acl_erp_delta |
---|
| 1139 | +mlxsw_sp_acl_erp_delta_default = {}; |
---|
| 1140 | + |
---|
| 1141 | +const struct mlxsw_sp_acl_erp_delta * |
---|
| 1142 | +mlxsw_sp_acl_erp_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask) |
---|
| 1143 | +{ |
---|
| 1144 | + struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask; |
---|
| 1145 | + const struct mlxsw_sp_acl_erp_delta *delta; |
---|
| 1146 | + |
---|
| 1147 | + delta = objagg_obj_delta_priv(objagg_obj); |
---|
| 1148 | + if (!delta) |
---|
| 1149 | + delta = &mlxsw_sp_acl_erp_delta_default; |
---|
| 1150 | + return delta; |
---|
| 1151 | +} |
---|
| 1152 | + |
---|
| 1153 | +static int |
---|
| 1154 | +mlxsw_sp_acl_erp_delta_fill(const struct mlxsw_sp_acl_erp_key *parent_key, |
---|
| 1155 | + const struct mlxsw_sp_acl_erp_key *key, |
---|
| 1156 | + u16 *delta_start, u8 *delta_mask) |
---|
| 1157 | +{ |
---|
| 1158 | + int offset = 0; |
---|
| 1159 | + int si = -1; |
---|
| 1160 | + u16 pmask; |
---|
| 1161 | + u16 mask; |
---|
| 1162 | + int i; |
---|
| 1163 | + |
---|
| 1164 | + /* The difference between 2 masks can be up to 8 consecutive bits. */ |
---|
| 1165 | + for (i = 0; i < __MASK_LEN; i++) { |
---|
| 1166 | + if (parent_key->mask[__MASK_IDX(i)] == key->mask[__MASK_IDX(i)]) |
---|
| 1167 | + continue; |
---|
| 1168 | + if (si == -1) |
---|
| 1169 | + si = i; |
---|
| 1170 | + else if (si != i - 1) |
---|
| 1171 | + return -EINVAL; |
---|
| 1172 | + } |
---|
| 1173 | + if (si == -1) { |
---|
| 1174 | + /* The masks are the same, this can happen in case eRPs with |
---|
| 1175 | + * the same mask were created in both A-TCAM and C-TCAM. |
---|
| 1176 | + * The only possible condition under which this can happen |
---|
| 1177 | + * is identical rule insertion. Delta is not possible here. |
---|
| 1178 | + */ |
---|
| 1179 | + return -EINVAL; |
---|
| 1180 | + } |
---|
| 1181 | + pmask = (unsigned char) parent_key->mask[__MASK_IDX(si)]; |
---|
| 1182 | + mask = (unsigned char) key->mask[__MASK_IDX(si)]; |
---|
| 1183 | + if (si + 1 < __MASK_LEN) { |
---|
| 1184 | + pmask |= (unsigned char) parent_key->mask[__MASK_IDX(si + 1)] << 8; |
---|
| 1185 | + mask |= (unsigned char) key->mask[__MASK_IDX(si + 1)] << 8; |
---|
| 1186 | + } |
---|
| 1187 | + |
---|
| 1188 | + if ((pmask ^ mask) & pmask) |
---|
| 1189 | + return -EINVAL; |
---|
| 1190 | + mask &= ~pmask; |
---|
| 1191 | + while (!(mask & (1 << offset))) |
---|
| 1192 | + offset++; |
---|
| 1193 | + while (!(mask & 1)) |
---|
| 1194 | + mask >>= 1; |
---|
| 1195 | + if (mask & 0xff00) |
---|
| 1196 | + return -EINVAL; |
---|
| 1197 | + |
---|
| 1198 | + *delta_start = si * 8 + offset; |
---|
| 1199 | + *delta_mask = mask; |
---|
| 1200 | + |
---|
| 1201 | + return 0; |
---|
| 1202 | +} |
---|
| 1203 | + |
---|
| 1204 | +static bool mlxsw_sp_acl_erp_delta_check(void *priv, const void *parent_obj, |
---|
| 1205 | + const void *obj) |
---|
| 1206 | +{ |
---|
| 1207 | + const struct mlxsw_sp_acl_erp_key *parent_key = parent_obj; |
---|
| 1208 | + const struct mlxsw_sp_acl_erp_key *key = obj; |
---|
| 1209 | + u16 delta_start; |
---|
| 1210 | + u8 delta_mask; |
---|
| 1211 | + int err; |
---|
| 1212 | + |
---|
| 1213 | + err = mlxsw_sp_acl_erp_delta_fill(parent_key, key, |
---|
| 1214 | + &delta_start, &delta_mask); |
---|
| 1215 | + return err ? false : true; |
---|
| 1216 | +} |
---|
| 1217 | + |
---|
| 1218 | +static int mlxsw_sp_acl_erp_hints_obj_cmp(const void *obj1, const void *obj2) |
---|
| 1219 | +{ |
---|
| 1220 | + const struct mlxsw_sp_acl_erp_key *key1 = obj1; |
---|
| 1221 | + const struct mlxsw_sp_acl_erp_key *key2 = obj2; |
---|
| 1222 | + |
---|
| 1223 | + /* For hints purposes, two objects are considered equal |
---|
| 1224 | + * in case the masks are the same. Does not matter what |
---|
| 1225 | + * the "ctcam" value is. |
---|
| 1226 | + */ |
---|
| 1227 | + return memcmp(key1->mask, key2->mask, sizeof(key1->mask)); |
---|
| 1228 | +} |
---|
| 1229 | + |
---|
| 1230 | +static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj, |
---|
| 1231 | + void *obj) |
---|
| 1232 | +{ |
---|
| 1233 | + struct mlxsw_sp_acl_erp_key *parent_key = parent_obj; |
---|
| 1234 | + struct mlxsw_sp_acl_atcam_region *aregion = priv; |
---|
| 1235 | + struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; |
---|
| 1236 | + struct mlxsw_sp_acl_erp_key *key = obj; |
---|
| 1237 | + struct mlxsw_sp_acl_erp_delta *delta; |
---|
| 1238 | + u16 delta_start; |
---|
| 1239 | + u8 delta_mask; |
---|
| 1240 | + int err; |
---|
| 1241 | + |
---|
| 1242 | + if (parent_key->ctcam || key->ctcam) |
---|
| 1243 | + return ERR_PTR(-EINVAL); |
---|
| 1244 | + err = mlxsw_sp_acl_erp_delta_fill(parent_key, key, |
---|
| 1245 | + &delta_start, &delta_mask); |
---|
| 1246 | + if (err) |
---|
| 1247 | + return ERR_PTR(-EINVAL); |
---|
| 1248 | + |
---|
| 1249 | + delta = kzalloc(sizeof(*delta), GFP_KERNEL); |
---|
| 1250 | + if (!delta) |
---|
| 1251 | + return ERR_PTR(-ENOMEM); |
---|
| 1252 | + delta->start = delta_start; |
---|
| 1253 | + delta->mask = delta_mask; |
---|
| 1254 | + |
---|
| 1255 | + err = mlxsw_sp_acl_erp_delta_inc(erp_table); |
---|
| 1256 | + if (err) |
---|
| 1257 | + goto err_erp_delta_inc; |
---|
| 1258 | + |
---|
| 1259 | + memcpy(&delta->key, key, sizeof(*key)); |
---|
| 1260 | + err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &delta->key); |
---|
| 1261 | + if (err) |
---|
| 1262 | + goto err_master_mask_set; |
---|
| 1263 | + |
---|
| 1264 | + return delta; |
---|
| 1265 | + |
---|
| 1266 | +err_master_mask_set: |
---|
| 1267 | + mlxsw_sp_acl_erp_delta_dec(erp_table); |
---|
| 1268 | +err_erp_delta_inc: |
---|
| 1269 | + kfree(delta); |
---|
| 1270 | + return ERR_PTR(err); |
---|
| 1271 | +} |
---|
| 1272 | + |
---|
| 1273 | +static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv) |
---|
| 1274 | +{ |
---|
| 1275 | + struct mlxsw_sp_acl_erp_delta *delta = delta_priv; |
---|
| 1276 | + struct mlxsw_sp_acl_atcam_region *aregion = priv; |
---|
| 1277 | + struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; |
---|
| 1278 | + |
---|
| 1279 | + mlxsw_sp_acl_erp_master_mask_clear(erp_table, &delta->key); |
---|
| 1280 | + mlxsw_sp_acl_erp_delta_dec(erp_table); |
---|
| 1281 | + kfree(delta); |
---|
| 1282 | +} |
---|
| 1283 | + |
---|
| 1284 | +static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj, |
---|
| 1285 | + unsigned int root_id) |
---|
| 1286 | +{ |
---|
| 1287 | + struct mlxsw_sp_acl_atcam_region *aregion = priv; |
---|
| 1288 | + struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; |
---|
| 1289 | + struct mlxsw_sp_acl_erp_key *key = obj; |
---|
| 1290 | + |
---|
| 1291 | + if (!key->ctcam && |
---|
| 1292 | + root_id != OBJAGG_OBJ_ROOT_ID_INVALID && |
---|
| 1293 | + root_id >= MLXSW_SP_ACL_ERP_MAX_PER_REGION) |
---|
| 1294 | + return ERR_PTR(-ENOBUFS); |
---|
| 1295 | + return erp_table->ops->erp_create(erp_table, key); |
---|
| 1296 | +} |
---|
| 1297 | + |
---|
| 1298 | +static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv) |
---|
| 1299 | +{ |
---|
| 1300 | + struct mlxsw_sp_acl_atcam_region *aregion = priv; |
---|
| 1301 | + struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; |
---|
| 1302 | + |
---|
| 1303 | + erp_table->ops->erp_destroy(erp_table, root_priv); |
---|
| 1304 | +} |
---|
| 1305 | + |
---|
| 1306 | +static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = { |
---|
| 1307 | + .obj_size = sizeof(struct mlxsw_sp_acl_erp_key), |
---|
| 1308 | + .delta_check = mlxsw_sp_acl_erp_delta_check, |
---|
| 1309 | + .hints_obj_cmp = mlxsw_sp_acl_erp_hints_obj_cmp, |
---|
| 1310 | + .delta_create = mlxsw_sp_acl_erp_delta_create, |
---|
| 1311 | + .delta_destroy = mlxsw_sp_acl_erp_delta_destroy, |
---|
| 1312 | + .root_create = mlxsw_sp_acl_erp_root_create, |
---|
| 1313 | + .root_destroy = mlxsw_sp_acl_erp_root_destroy, |
---|
| 1314 | +}; |
---|
| 1315 | + |
---|
981 | 1316 | static struct mlxsw_sp_acl_erp_table * |
---|
982 | | -mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion) |
---|
| 1317 | +mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion, |
---|
| 1318 | + struct objagg_hints *hints) |
---|
983 | 1319 | { |
---|
984 | 1320 | struct mlxsw_sp_acl_erp_table *erp_table; |
---|
985 | 1321 | int err; |
---|
.. | .. |
---|
988 | 1324 | if (!erp_table) |
---|
989 | 1325 | return ERR_PTR(-ENOMEM); |
---|
990 | 1326 | |
---|
991 | | - err = rhashtable_init(&erp_table->erp_ht, &mlxsw_sp_acl_erp_ht_params); |
---|
992 | | - if (err) |
---|
993 | | - goto err_rhashtable_init; |
---|
| 1327 | + erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops, |
---|
| 1328 | + hints, aregion); |
---|
| 1329 | + if (IS_ERR(erp_table->objagg)) { |
---|
| 1330 | + err = PTR_ERR(erp_table->objagg); |
---|
| 1331 | + goto err_objagg_create; |
---|
| 1332 | + } |
---|
994 | 1333 | |
---|
995 | 1334 | erp_table->erp_core = aregion->atcam->erp_core; |
---|
996 | 1335 | erp_table->ops = &erp_no_mask_ops; |
---|
997 | 1336 | INIT_LIST_HEAD(&erp_table->atcam_erps_list); |
---|
998 | 1337 | erp_table->aregion = aregion; |
---|
| 1338 | + mutex_init(&erp_table->objagg_lock); |
---|
999 | 1339 | |
---|
1000 | 1340 | return erp_table; |
---|
1001 | 1341 | |
---|
1002 | | -err_rhashtable_init: |
---|
| 1342 | +err_objagg_create: |
---|
1003 | 1343 | kfree(erp_table); |
---|
1004 | 1344 | return ERR_PTR(err); |
---|
1005 | 1345 | } |
---|
.. | .. |
---|
1008 | 1348 | mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table *erp_table) |
---|
1009 | 1349 | { |
---|
1010 | 1350 | WARN_ON(!list_empty(&erp_table->atcam_erps_list)); |
---|
1011 | | - rhashtable_destroy(&erp_table->erp_ht); |
---|
| 1351 | + mutex_destroy(&erp_table->objagg_lock); |
---|
| 1352 | + objagg_destroy(erp_table->objagg); |
---|
1012 | 1353 | kfree(erp_table); |
---|
1013 | 1354 | } |
---|
1014 | 1355 | |
---|
.. | .. |
---|
1033 | 1374 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl); |
---|
1034 | 1375 | } |
---|
1035 | 1376 | |
---|
1036 | | -int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion) |
---|
| 1377 | +static int |
---|
| 1378 | +mlxsw_sp_acl_erp_hints_check(struct mlxsw_sp *mlxsw_sp, |
---|
| 1379 | + struct mlxsw_sp_acl_atcam_region *aregion, |
---|
| 1380 | + struct objagg_hints *hints, bool *p_rehash_needed) |
---|
1037 | 1381 | { |
---|
1038 | | - struct mlxsw_sp_acl_erp_table *erp_table; |
---|
| 1382 | + struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; |
---|
| 1383 | + const struct objagg_stats *ostats; |
---|
| 1384 | + const struct objagg_stats *hstats; |
---|
1039 | 1385 | int err; |
---|
1040 | 1386 | |
---|
1041 | | - erp_table = mlxsw_sp_acl_erp_table_create(aregion); |
---|
| 1387 | + *p_rehash_needed = false; |
---|
| 1388 | + |
---|
| 1389 | + mutex_lock(&erp_table->objagg_lock); |
---|
| 1390 | + ostats = objagg_stats_get(erp_table->objagg); |
---|
| 1391 | + mutex_unlock(&erp_table->objagg_lock); |
---|
| 1392 | + if (IS_ERR(ostats)) { |
---|
| 1393 | + dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get ERP stats\n"); |
---|
| 1394 | + return PTR_ERR(ostats); |
---|
| 1395 | + } |
---|
| 1396 | + |
---|
| 1397 | + hstats = objagg_hints_stats_get(hints); |
---|
| 1398 | + if (IS_ERR(hstats)) { |
---|
| 1399 | + dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get ERP hints stats\n"); |
---|
| 1400 | + err = PTR_ERR(hstats); |
---|
| 1401 | + goto err_hints_stats_get; |
---|
| 1402 | + } |
---|
| 1403 | + |
---|
| 1404 | + /* Very basic criterion for now. */ |
---|
| 1405 | + if (hstats->root_count < ostats->root_count) |
---|
| 1406 | + *p_rehash_needed = true; |
---|
| 1407 | + |
---|
| 1408 | + err = 0; |
---|
| 1409 | + |
---|
| 1410 | + objagg_stats_put(hstats); |
---|
| 1411 | +err_hints_stats_get: |
---|
| 1412 | + objagg_stats_put(ostats); |
---|
| 1413 | + return err; |
---|
| 1414 | +} |
---|
| 1415 | + |
---|
| 1416 | +void * |
---|
| 1417 | +mlxsw_sp_acl_erp_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion) |
---|
| 1418 | +{ |
---|
| 1419 | + struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; |
---|
| 1420 | + struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp; |
---|
| 1421 | + struct objagg_hints *hints; |
---|
| 1422 | + bool rehash_needed; |
---|
| 1423 | + int err; |
---|
| 1424 | + |
---|
| 1425 | + mutex_lock(&erp_table->objagg_lock); |
---|
| 1426 | + hints = objagg_hints_get(erp_table->objagg, |
---|
| 1427 | + OBJAGG_OPT_ALGO_SIMPLE_GREEDY); |
---|
| 1428 | + mutex_unlock(&erp_table->objagg_lock); |
---|
| 1429 | + if (IS_ERR(hints)) { |
---|
| 1430 | + dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to create ERP hints\n"); |
---|
| 1431 | + return ERR_CAST(hints); |
---|
| 1432 | + } |
---|
| 1433 | + err = mlxsw_sp_acl_erp_hints_check(mlxsw_sp, aregion, hints, |
---|
| 1434 | + &rehash_needed); |
---|
| 1435 | + if (err) |
---|
| 1436 | + goto errout; |
---|
| 1437 | + |
---|
| 1438 | + if (!rehash_needed) { |
---|
| 1439 | + err = -EAGAIN; |
---|
| 1440 | + goto errout; |
---|
| 1441 | + } |
---|
| 1442 | + return hints; |
---|
| 1443 | + |
---|
| 1444 | +errout: |
---|
| 1445 | + objagg_hints_put(hints); |
---|
| 1446 | + return ERR_PTR(err); |
---|
| 1447 | +} |
---|
| 1448 | + |
---|
| 1449 | +void mlxsw_sp_acl_erp_rehash_hints_put(void *hints_priv) |
---|
| 1450 | +{ |
---|
| 1451 | + struct objagg_hints *hints = hints_priv; |
---|
| 1452 | + |
---|
| 1453 | + objagg_hints_put(hints); |
---|
| 1454 | +} |
---|
| 1455 | + |
---|
| 1456 | +int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion, |
---|
| 1457 | + void *hints_priv) |
---|
| 1458 | +{ |
---|
| 1459 | + struct mlxsw_sp_acl_erp_table *erp_table; |
---|
| 1460 | + struct objagg_hints *hints = hints_priv; |
---|
| 1461 | + int err; |
---|
| 1462 | + |
---|
| 1463 | + erp_table = mlxsw_sp_acl_erp_table_create(aregion, hints); |
---|
1042 | 1464 | if (IS_ERR(erp_table)) |
---|
1043 | 1465 | return PTR_ERR(erp_table); |
---|
1044 | 1466 | aregion->erp_table = erp_table; |
---|
.. | .. |
---|
1118 | 1540 | if (err) |
---|
1119 | 1541 | goto err_gen_pool_add; |
---|
1120 | 1542 | |
---|
| 1543 | + erp_core->bf = mlxsw_sp_acl_bf_init(mlxsw_sp, erp_core->num_erp_banks); |
---|
| 1544 | + if (IS_ERR(erp_core->bf)) { |
---|
| 1545 | + err = PTR_ERR(erp_core->bf); |
---|
| 1546 | + goto err_bf_init; |
---|
| 1547 | + } |
---|
| 1548 | + |
---|
1121 | 1549 | /* Different regions require masks of different sizes */ |
---|
1122 | 1550 | err = mlxsw_sp_acl_erp_tables_sizes_query(mlxsw_sp, erp_core); |
---|
1123 | 1551 | if (err) |
---|
.. | .. |
---|
1126 | 1554 | return 0; |
---|
1127 | 1555 | |
---|
1128 | 1556 | err_erp_tables_sizes_query: |
---|
| 1557 | + mlxsw_sp_acl_bf_fini(erp_core->bf); |
---|
| 1558 | +err_bf_init: |
---|
1129 | 1559 | err_gen_pool_add: |
---|
1130 | 1560 | gen_pool_destroy(erp_core->erp_tables); |
---|
1131 | 1561 | return err; |
---|
.. | .. |
---|
1134 | 1564 | static void mlxsw_sp_acl_erp_tables_fini(struct mlxsw_sp *mlxsw_sp, |
---|
1135 | 1565 | struct mlxsw_sp_acl_erp_core *erp_core) |
---|
1136 | 1566 | { |
---|
| 1567 | + mlxsw_sp_acl_bf_fini(erp_core->bf); |
---|
1137 | 1568 | gen_pool_destroy(erp_core->erp_tables); |
---|
1138 | 1569 | } |
---|
1139 | 1570 | |
---|