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 | |
7 | #include "reg.h" |
8 | #include "core.h" |
9 | #include "spectrum.h" |
10 | #include "spectrum_acl_tcam.h" |
11 | |
12 | struct mlxsw_sp1_acl_tcam_region { |
13 | struct mlxsw_sp_acl_ctcam_region cregion; |
14 | struct mlxsw_sp_acl_tcam_region *region; |
15 | struct { |
16 | struct mlxsw_sp_acl_ctcam_chunk cchunk; |
17 | struct mlxsw_sp_acl_ctcam_entry centry; |
18 | struct mlxsw_sp_acl_rule_info *rulei; |
19 | } catchall; |
20 | }; |
21 | |
22 | struct mlxsw_sp1_acl_tcam_chunk { |
23 | struct mlxsw_sp_acl_ctcam_chunk cchunk; |
24 | }; |
25 | |
26 | struct mlxsw_sp1_acl_tcam_entry { |
27 | struct mlxsw_sp_acl_ctcam_entry centry; |
28 | }; |
29 | |
30 | static int |
31 | mlxsw_sp1_acl_ctcam_region_entry_insert(struct mlxsw_sp_acl_ctcam_region *cregion, |
32 | struct mlxsw_sp_acl_ctcam_entry *centry, |
33 | const char *mask) |
34 | { |
35 | return 0; |
36 | } |
37 | |
38 | static void |
39 | mlxsw_sp1_acl_ctcam_region_entry_remove(struct mlxsw_sp_acl_ctcam_region *cregion, |
40 | struct mlxsw_sp_acl_ctcam_entry *centry) |
41 | { |
42 | } |
43 | |
44 | static const struct mlxsw_sp_acl_ctcam_region_ops |
45 | mlxsw_sp1_acl_ctcam_region_ops = { |
46 | .entry_insert = mlxsw_sp1_acl_ctcam_region_entry_insert, |
47 | .entry_remove = mlxsw_sp1_acl_ctcam_region_entry_remove, |
48 | }; |
49 | |
50 | static int mlxsw_sp1_acl_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv, |
51 | struct mlxsw_sp_acl_tcam *tcam) |
52 | { |
53 | return 0; |
54 | } |
55 | |
56 | static void mlxsw_sp1_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp, void *priv) |
57 | { |
58 | } |
59 | |
60 | static int |
61 | mlxsw_sp1_acl_ctcam_region_catchall_add(struct mlxsw_sp *mlxsw_sp, |
62 | struct mlxsw_sp1_acl_tcam_region *region) |
63 | { |
64 | struct mlxsw_sp_acl_rule_info *rulei; |
65 | int err; |
66 | |
67 | mlxsw_sp_acl_ctcam_chunk_init(cregion: ®ion->cregion, |
68 | cchunk: ®ion->catchall.cchunk, |
69 | MLXSW_SP_ACL_TCAM_CATCHALL_PRIO); |
70 | rulei = mlxsw_sp_acl_rulei_create(acl: mlxsw_sp->acl, NULL); |
71 | if (IS_ERR(ptr: rulei)) { |
72 | err = PTR_ERR(ptr: rulei); |
73 | goto err_rulei_create; |
74 | } |
75 | err = mlxsw_sp_acl_rulei_act_continue(rulei); |
76 | if (WARN_ON(err)) |
77 | goto err_rulei_act_continue; |
78 | err = mlxsw_sp_acl_rulei_commit(rulei); |
79 | if (err) |
80 | goto err_rulei_commit; |
81 | err = mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, cregion: ®ion->cregion, |
82 | cchunk: ®ion->catchall.cchunk, |
83 | centry: ®ion->catchall.centry, |
84 | rulei, fillup_priority: false); |
85 | if (err) |
86 | goto err_entry_add; |
87 | region->catchall.rulei = rulei; |
88 | return 0; |
89 | |
90 | err_entry_add: |
91 | err_rulei_commit: |
92 | err_rulei_act_continue: |
93 | mlxsw_sp_acl_rulei_destroy(mlxsw_sp, rulei); |
94 | err_rulei_create: |
95 | mlxsw_sp_acl_ctcam_chunk_fini(cchunk: ®ion->catchall.cchunk); |
96 | return err; |
97 | } |
98 | |
99 | static void |
100 | mlxsw_sp1_acl_ctcam_region_catchall_del(struct mlxsw_sp *mlxsw_sp, |
101 | struct mlxsw_sp1_acl_tcam_region *region) |
102 | { |
103 | struct mlxsw_sp_acl_rule_info *rulei = region->catchall.rulei; |
104 | |
105 | mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, cregion: ®ion->cregion, |
106 | cchunk: ®ion->catchall.cchunk, |
107 | centry: ®ion->catchall.centry); |
108 | mlxsw_sp_acl_rulei_destroy(mlxsw_sp, rulei); |
109 | mlxsw_sp_acl_ctcam_chunk_fini(cchunk: ®ion->catchall.cchunk); |
110 | } |
111 | |
112 | static int |
113 | mlxsw_sp1_acl_tcam_region_init(struct mlxsw_sp *mlxsw_sp, void *region_priv, |
114 | void *tcam_priv, |
115 | struct mlxsw_sp_acl_tcam_region *_region, |
116 | void *hints_priv) |
117 | { |
118 | struct mlxsw_sp1_acl_tcam_region *region = region_priv; |
119 | int err; |
120 | |
121 | err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, cregion: ®ion->cregion, |
122 | region: _region, |
123 | ops: &mlxsw_sp1_acl_ctcam_region_ops); |
124 | if (err) |
125 | return err; |
126 | err = mlxsw_sp1_acl_ctcam_region_catchall_add(mlxsw_sp, region); |
127 | if (err) |
128 | goto err_catchall_add; |
129 | region->region = _region; |
130 | return 0; |
131 | |
132 | err_catchall_add: |
133 | mlxsw_sp_acl_ctcam_region_fini(cregion: ®ion->cregion); |
134 | return err; |
135 | } |
136 | |
137 | static void |
138 | mlxsw_sp1_acl_tcam_region_fini(struct mlxsw_sp *mlxsw_sp, void *region_priv) |
139 | { |
140 | struct mlxsw_sp1_acl_tcam_region *region = region_priv; |
141 | |
142 | mlxsw_sp1_acl_ctcam_region_catchall_del(mlxsw_sp, region); |
143 | mlxsw_sp_acl_ctcam_region_fini(cregion: ®ion->cregion); |
144 | } |
145 | |
146 | static int |
147 | mlxsw_sp1_acl_tcam_region_associate(struct mlxsw_sp *mlxsw_sp, |
148 | struct mlxsw_sp_acl_tcam_region *region) |
149 | { |
150 | return 0; |
151 | } |
152 | |
153 | static void mlxsw_sp1_acl_tcam_chunk_init(void *region_priv, void *chunk_priv, |
154 | unsigned int priority) |
155 | { |
156 | struct mlxsw_sp1_acl_tcam_region *region = region_priv; |
157 | struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; |
158 | |
159 | mlxsw_sp_acl_ctcam_chunk_init(cregion: ®ion->cregion, cchunk: &chunk->cchunk, |
160 | priority); |
161 | } |
162 | |
163 | static void mlxsw_sp1_acl_tcam_chunk_fini(void *chunk_priv) |
164 | { |
165 | struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; |
166 | |
167 | mlxsw_sp_acl_ctcam_chunk_fini(cchunk: &chunk->cchunk); |
168 | } |
169 | |
170 | static int mlxsw_sp1_acl_tcam_entry_add(struct mlxsw_sp *mlxsw_sp, |
171 | void *region_priv, void *chunk_priv, |
172 | void *entry_priv, |
173 | struct mlxsw_sp_acl_rule_info *rulei) |
174 | { |
175 | struct mlxsw_sp1_acl_tcam_region *region = region_priv; |
176 | struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; |
177 | struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; |
178 | |
179 | return mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, cregion: ®ion->cregion, |
180 | cchunk: &chunk->cchunk, centry: &entry->centry, |
181 | rulei, fillup_priority: false); |
182 | } |
183 | |
184 | static void mlxsw_sp1_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp, |
185 | void *region_priv, void *chunk_priv, |
186 | void *entry_priv) |
187 | { |
188 | struct mlxsw_sp1_acl_tcam_region *region = region_priv; |
189 | struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv; |
190 | struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; |
191 | |
192 | mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, cregion: ®ion->cregion, |
193 | cchunk: &chunk->cchunk, centry: &entry->centry); |
194 | } |
195 | |
196 | static int |
197 | mlxsw_sp1_acl_tcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, |
198 | void *region_priv, void *entry_priv, |
199 | struct mlxsw_sp_acl_rule_info *rulei) |
200 | { |
201 | return -EOPNOTSUPP; |
202 | } |
203 | |
204 | static int |
205 | mlxsw_sp1_acl_tcam_region_entry_activity_get(struct mlxsw_sp *mlxsw_sp, |
206 | struct mlxsw_sp_acl_tcam_region *_region, |
207 | unsigned int offset, |
208 | bool *activity) |
209 | { |
210 | char ptce2_pl[MLXSW_REG_PTCE2_LEN]; |
211 | int err; |
212 | |
213 | mlxsw_reg_ptce2_pack(payload: ptce2_pl, valid: true, op: MLXSW_REG_PTCE2_OP_QUERY_CLEAR_ON_READ, |
214 | tcam_region_info: _region->tcam_region_info, offset, priority: 0); |
215 | err = mlxsw_reg_query(mlxsw_core: mlxsw_sp->core, MLXSW_REG(ptce2), payload: ptce2_pl); |
216 | if (err) |
217 | return err; |
218 | *activity = mlxsw_reg_ptce2_a_get(buf: ptce2_pl); |
219 | return 0; |
220 | } |
221 | |
222 | static int |
223 | mlxsw_sp1_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp, |
224 | void *region_priv, void *entry_priv, |
225 | bool *activity) |
226 | { |
227 | struct mlxsw_sp1_acl_tcam_region *region = region_priv; |
228 | struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv; |
229 | unsigned int offset; |
230 | |
231 | offset = mlxsw_sp_acl_ctcam_entry_offset(centry: &entry->centry); |
232 | return mlxsw_sp1_acl_tcam_region_entry_activity_get(mlxsw_sp, |
233 | region: region->region, |
234 | offset, activity); |
235 | } |
236 | |
237 | const struct mlxsw_sp_acl_tcam_ops mlxsw_sp1_acl_tcam_ops = { |
238 | .key_type = MLXSW_REG_PTAR_KEY_TYPE_FLEX, |
239 | .priv_size = 0, |
240 | .init = mlxsw_sp1_acl_tcam_init, |
241 | .fini = mlxsw_sp1_acl_tcam_fini, |
242 | .region_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_region), |
243 | .region_init = mlxsw_sp1_acl_tcam_region_init, |
244 | .region_fini = mlxsw_sp1_acl_tcam_region_fini, |
245 | .region_associate = mlxsw_sp1_acl_tcam_region_associate, |
246 | .chunk_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_chunk), |
247 | .chunk_init = mlxsw_sp1_acl_tcam_chunk_init, |
248 | .chunk_fini = mlxsw_sp1_acl_tcam_chunk_fini, |
249 | .entry_priv_size = sizeof(struct mlxsw_sp1_acl_tcam_entry), |
250 | .entry_add = mlxsw_sp1_acl_tcam_entry_add, |
251 | .entry_del = mlxsw_sp1_acl_tcam_entry_del, |
252 | .entry_action_replace = mlxsw_sp1_acl_tcam_entry_action_replace, |
253 | .entry_activity_get = mlxsw_sp1_acl_tcam_entry_activity_get, |
254 | }; |
255 | |