]>
Commit | Line | Data |
---|---|---|
9948a064 JP |
1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ | |
64eccd00 JP |
3 | |
4 | #include <linux/kernel.h> | |
5 | #include <linux/errno.h> | |
6 | #include <linux/parman.h> | |
7 | ||
8 | #include "reg.h" | |
9 | #include "core.h" | |
10 | #include "spectrum.h" | |
11 | #include "spectrum_acl_tcam.h" | |
12 | ||
13 | static int | |
14 | mlxsw_sp_acl_ctcam_region_resize(struct mlxsw_sp *mlxsw_sp, | |
15 | struct mlxsw_sp_acl_tcam_region *region, | |
16 | u16 new_size) | |
17 | { | |
18 | char ptar_pl[MLXSW_REG_PTAR_LEN]; | |
19 | ||
20 | mlxsw_reg_ptar_pack(ptar_pl, MLXSW_REG_PTAR_OP_RESIZE, | |
21 | region->key_type, new_size, region->id, | |
22 | region->tcam_region_info); | |
23 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptar), ptar_pl); | |
24 | } | |
25 | ||
26 | static void | |
27 | mlxsw_sp_acl_ctcam_region_move(struct mlxsw_sp *mlxsw_sp, | |
28 | struct mlxsw_sp_acl_tcam_region *region, | |
29 | u16 src_offset, u16 dst_offset, u16 size) | |
30 | { | |
31 | char prcr_pl[MLXSW_REG_PRCR_LEN]; | |
32 | ||
33 | mlxsw_reg_prcr_pack(prcr_pl, MLXSW_REG_PRCR_OP_MOVE, | |
34 | region->tcam_region_info, src_offset, | |
35 | region->tcam_region_info, dst_offset, size); | |
36 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(prcr), prcr_pl); | |
37 | } | |
38 | ||
39 | static int | |
40 | mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp, | |
a20ff8eb IS |
41 | struct mlxsw_sp_acl_ctcam_region *cregion, |
42 | struct mlxsw_sp_acl_ctcam_entry *centry, | |
ea8b2e28 JP |
43 | struct mlxsw_sp_acl_rule_info *rulei, |
44 | bool fillup_priority) | |
64eccd00 | 45 | { |
a20ff8eb | 46 | struct mlxsw_sp_acl_tcam_region *region = cregion->region; |
a5995cc8 | 47 | struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl); |
64eccd00 JP |
48 | char ptce2_pl[MLXSW_REG_PTCE2_LEN]; |
49 | char *act_set; | |
ea8b2e28 | 50 | u32 priority; |
64eccd00 JP |
51 | char *mask; |
52 | char *key; | |
ea8b2e28 JP |
53 | int err; |
54 | ||
55 | err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, | |
56 | fillup_priority); | |
57 | if (err) | |
58 | return err; | |
64eccd00 JP |
59 | |
60 | mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_WRITE, | |
a20ff8eb IS |
61 | region->tcam_region_info, |
62 | centry->parman_item.index, priority); | |
64eccd00 JP |
63 | key = mlxsw_reg_ptce2_flex_key_blocks_data(ptce2_pl); |
64 | mask = mlxsw_reg_ptce2_mask_data(ptce2_pl); | |
59600844 | 65 | mlxsw_afk_encode(afk, region->key_info, &rulei->values, key, mask); |
64eccd00 | 66 | |
a0a777b9 IS |
67 | err = cregion->ops->entry_insert(cregion, centry, mask); |
68 | if (err) | |
69 | return err; | |
70 | ||
64eccd00 JP |
71 | /* Only the first action set belongs here, the rest is in KVD */ |
72 | act_set = mlxsw_afa_block_first_set(rulei->act_block); | |
73 | mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set); | |
74 | ||
75 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); | |
76 | } | |
77 | ||
78 | static void | |
79 | mlxsw_sp_acl_ctcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp, | |
a20ff8eb IS |
80 | struct mlxsw_sp_acl_ctcam_region *cregion, |
81 | struct mlxsw_sp_acl_ctcam_entry *centry) | |
64eccd00 JP |
82 | { |
83 | char ptce2_pl[MLXSW_REG_PTCE2_LEN]; | |
84 | ||
85 | mlxsw_reg_ptce2_pack(ptce2_pl, false, MLXSW_REG_PTCE2_OP_WRITE_WRITE, | |
a20ff8eb IS |
86 | cregion->region->tcam_region_info, |
87 | centry->parman_item.index, 0); | |
64eccd00 | 88 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); |
a0a777b9 | 89 | cregion->ops->entry_remove(cregion, centry); |
64eccd00 JP |
90 | } |
91 | ||
2507a64c ND |
92 | static int |
93 | mlxsw_sp_acl_ctcam_region_entry_action_replace(struct mlxsw_sp *mlxsw_sp, | |
94 | struct mlxsw_sp_acl_ctcam_region *cregion, | |
95 | struct mlxsw_sp_acl_ctcam_entry *centry, | |
96 | struct mlxsw_afa_block *afa_block, | |
97 | unsigned int priority) | |
98 | { | |
99 | char ptce2_pl[MLXSW_REG_PTCE2_LEN]; | |
100 | char *act_set; | |
101 | ||
102 | mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_UPDATE, | |
103 | cregion->region->tcam_region_info, | |
104 | centry->parman_item.index, priority); | |
105 | ||
106 | act_set = mlxsw_afa_block_first_set(afa_block); | |
107 | mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set); | |
108 | ||
109 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); | |
110 | } | |
111 | ||
112 | ||
64eccd00 JP |
113 | static int mlxsw_sp_acl_ctcam_region_parman_resize(void *priv, |
114 | unsigned long new_count) | |
115 | { | |
116 | struct mlxsw_sp_acl_ctcam_region *cregion = priv; | |
117 | struct mlxsw_sp_acl_tcam_region *region = cregion->region; | |
118 | struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp; | |
119 | u64 max_tcam_rules; | |
120 | ||
121 | max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES); | |
122 | if (new_count > max_tcam_rules) | |
123 | return -EINVAL; | |
124 | return mlxsw_sp_acl_ctcam_region_resize(mlxsw_sp, region, new_count); | |
125 | } | |
126 | ||
127 | static void mlxsw_sp_acl_ctcam_region_parman_move(void *priv, | |
128 | unsigned long from_index, | |
129 | unsigned long to_index, | |
130 | unsigned long count) | |
131 | { | |
132 | struct mlxsw_sp_acl_ctcam_region *cregion = priv; | |
133 | struct mlxsw_sp_acl_tcam_region *region = cregion->region; | |
134 | struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp; | |
135 | ||
136 | mlxsw_sp_acl_ctcam_region_move(mlxsw_sp, region, | |
137 | from_index, to_index, count); | |
138 | } | |
139 | ||
140 | static const struct parman_ops mlxsw_sp_acl_ctcam_region_parman_ops = { | |
141 | .base_count = MLXSW_SP_ACL_TCAM_REGION_BASE_COUNT, | |
142 | .resize_step = MLXSW_SP_ACL_TCAM_REGION_RESIZE_STEP, | |
143 | .resize = mlxsw_sp_acl_ctcam_region_parman_resize, | |
144 | .move = mlxsw_sp_acl_ctcam_region_parman_move, | |
145 | .algo = PARMAN_ALGO_TYPE_LSORT, | |
146 | }; | |
147 | ||
a0a777b9 IS |
148 | int |
149 | mlxsw_sp_acl_ctcam_region_init(struct mlxsw_sp *mlxsw_sp, | |
150 | struct mlxsw_sp_acl_ctcam_region *cregion, | |
151 | struct mlxsw_sp_acl_tcam_region *region, | |
152 | const struct mlxsw_sp_acl_ctcam_region_ops *ops) | |
64eccd00 JP |
153 | { |
154 | cregion->region = region; | |
a0a777b9 | 155 | cregion->ops = ops; |
64eccd00 JP |
156 | cregion->parman = parman_create(&mlxsw_sp_acl_ctcam_region_parman_ops, |
157 | cregion); | |
158 | if (!cregion->parman) | |
159 | return -ENOMEM; | |
160 | return 0; | |
161 | } | |
162 | ||
163 | void mlxsw_sp_acl_ctcam_region_fini(struct mlxsw_sp_acl_ctcam_region *cregion) | |
164 | { | |
165 | parman_destroy(cregion->parman); | |
166 | } | |
167 | ||
168 | void mlxsw_sp_acl_ctcam_chunk_init(struct mlxsw_sp_acl_ctcam_region *cregion, | |
169 | struct mlxsw_sp_acl_ctcam_chunk *cchunk, | |
170 | unsigned int priority) | |
171 | { | |
172 | parman_prio_init(cregion->parman, &cchunk->parman_prio, priority); | |
173 | } | |
174 | ||
175 | void mlxsw_sp_acl_ctcam_chunk_fini(struct mlxsw_sp_acl_ctcam_chunk *cchunk) | |
176 | { | |
177 | parman_prio_fini(&cchunk->parman_prio); | |
178 | } | |
179 | ||
180 | int mlxsw_sp_acl_ctcam_entry_add(struct mlxsw_sp *mlxsw_sp, | |
181 | struct mlxsw_sp_acl_ctcam_region *cregion, | |
182 | struct mlxsw_sp_acl_ctcam_chunk *cchunk, | |
183 | struct mlxsw_sp_acl_ctcam_entry *centry, | |
ea8b2e28 JP |
184 | struct mlxsw_sp_acl_rule_info *rulei, |
185 | bool fillup_priority) | |
64eccd00 JP |
186 | { |
187 | int err; | |
188 | ||
189 | err = parman_item_add(cregion->parman, &cchunk->parman_prio, | |
190 | ¢ry->parman_item); | |
191 | if (err) | |
192 | return err; | |
193 | ||
a20ff8eb | 194 | err = mlxsw_sp_acl_ctcam_region_entry_insert(mlxsw_sp, cregion, centry, |
ea8b2e28 | 195 | rulei, fillup_priority); |
64eccd00 JP |
196 | if (err) |
197 | goto err_rule_insert; | |
198 | return 0; | |
199 | ||
200 | err_rule_insert: | |
201 | parman_item_remove(cregion->parman, &cchunk->parman_prio, | |
202 | ¢ry->parman_item); | |
203 | return err; | |
204 | } | |
205 | ||
206 | void mlxsw_sp_acl_ctcam_entry_del(struct mlxsw_sp *mlxsw_sp, | |
207 | struct mlxsw_sp_acl_ctcam_region *cregion, | |
208 | struct mlxsw_sp_acl_ctcam_chunk *cchunk, | |
209 | struct mlxsw_sp_acl_ctcam_entry *centry) | |
210 | { | |
a20ff8eb | 211 | mlxsw_sp_acl_ctcam_region_entry_remove(mlxsw_sp, cregion, centry); |
64eccd00 JP |
212 | parman_item_remove(cregion->parman, &cchunk->parman_prio, |
213 | ¢ry->parman_item); | |
214 | } | |
2507a64c ND |
215 | |
216 | int mlxsw_sp_acl_ctcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, | |
217 | struct mlxsw_sp_acl_ctcam_region *cregion, | |
218 | struct mlxsw_sp_acl_ctcam_chunk *cchunk, | |
219 | struct mlxsw_sp_acl_ctcam_entry *centry, | |
220 | struct mlxsw_sp_acl_rule_info *rulei) | |
221 | { | |
222 | return mlxsw_sp_acl_ctcam_region_entry_action_replace(mlxsw_sp, cregion, | |
223 | centry, | |
224 | rulei->act_block, | |
225 | rulei->priority); | |
226 | } |