1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ |
3 | |
4 | #include "spectrum_acl_flex_actions.h" |
5 | #include "core_acl_flex_actions.h" |
6 | #include "spectrum_span.h" |
7 | |
8 | static int mlxsw_sp_act_kvdl_set_add(void *priv, u32 *p_kvdl_index, |
9 | char *enc_actions, bool is_first, bool ca) |
10 | { |
11 | struct mlxsw_sp *mlxsw_sp = priv; |
12 | char pefa_pl[MLXSW_REG_PEFA_LEN]; |
13 | u32 kvdl_index; |
14 | int err; |
15 | |
16 | /* The first action set of a TCAM entry is stored directly in TCAM, |
17 | * not KVD linear area. |
18 | */ |
19 | if (is_first) |
20 | return 0; |
21 | |
22 | err = mlxsw_sp_kvdl_alloc(mlxsw_sp, type: MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET, |
23 | entry_count: 1, p_entry_index: &kvdl_index); |
24 | if (err) |
25 | return err; |
26 | mlxsw_reg_pefa_pack(payload: pefa_pl, index: kvdl_index, ca, flex_action_set: enc_actions); |
27 | err = mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(pefa), payload: pefa_pl); |
28 | if (err) |
29 | goto err_pefa_write; |
30 | *p_kvdl_index = kvdl_index; |
31 | return 0; |
32 | |
33 | err_pefa_write: |
34 | mlxsw_sp_kvdl_free(mlxsw_sp, type: MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET, |
35 | entry_count: 1, entry_index: kvdl_index); |
36 | return err; |
37 | } |
38 | |
39 | static int mlxsw_sp1_act_kvdl_set_add(void *priv, u32 *p_kvdl_index, |
40 | char *enc_actions, bool is_first) |
41 | { |
42 | return mlxsw_sp_act_kvdl_set_add(priv, p_kvdl_index, enc_actions, |
43 | is_first, ca: false); |
44 | } |
45 | |
46 | static int mlxsw_sp2_act_kvdl_set_add(void *priv, u32 *p_kvdl_index, |
47 | char *enc_actions, bool is_first) |
48 | { |
49 | return mlxsw_sp_act_kvdl_set_add(priv, p_kvdl_index, enc_actions, |
50 | is_first, ca: true); |
51 | } |
52 | |
53 | static void mlxsw_sp_act_kvdl_set_del(void *priv, u32 kvdl_index, |
54 | bool is_first) |
55 | { |
56 | struct mlxsw_sp *mlxsw_sp = priv; |
57 | |
58 | if (is_first) |
59 | return; |
60 | mlxsw_sp_kvdl_free(mlxsw_sp, type: MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET, |
61 | entry_count: 1, entry_index: kvdl_index); |
62 | } |
63 | |
64 | static int mlxsw_sp1_act_kvdl_set_activity_get(void *priv, u32 kvdl_index, |
65 | bool *activity) |
66 | { |
67 | return -EOPNOTSUPP; |
68 | } |
69 | |
70 | static int mlxsw_sp2_act_kvdl_set_activity_get(void *priv, u32 kvdl_index, |
71 | bool *activity) |
72 | { |
73 | struct mlxsw_sp *mlxsw_sp = priv; |
74 | char pefa_pl[MLXSW_REG_PEFA_LEN]; |
75 | int err; |
76 | |
77 | mlxsw_reg_pefa_pack(payload: pefa_pl, index: kvdl_index, ca: true, NULL); |
78 | err = mlxsw_reg_query(mlxsw_core: mlxsw_sp->core, MLXSW_REG(pefa), payload: pefa_pl); |
79 | if (err) |
80 | return err; |
81 | mlxsw_reg_pefa_unpack(payload: pefa_pl, p_a: activity); |
82 | return 0; |
83 | } |
84 | |
85 | static int mlxsw_sp_act_kvdl_fwd_entry_add(void *priv, u32 *p_kvdl_index, |
86 | u16 local_port) |
87 | { |
88 | struct mlxsw_sp *mlxsw_sp = priv; |
89 | char ppbs_pl[MLXSW_REG_PPBS_LEN]; |
90 | u32 kvdl_index; |
91 | int err; |
92 | |
93 | err = mlxsw_sp_kvdl_alloc(mlxsw_sp, type: MLXSW_SP_KVDL_ENTRY_TYPE_PBS, |
94 | entry_count: 1, p_entry_index: &kvdl_index); |
95 | if (err) |
96 | return err; |
97 | mlxsw_reg_ppbs_pack(payload: ppbs_pl, pbs_ptr: kvdl_index, system_port: local_port); |
98 | err = mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(ppbs), payload: ppbs_pl); |
99 | if (err) |
100 | goto err_ppbs_write; |
101 | *p_kvdl_index = kvdl_index; |
102 | return 0; |
103 | |
104 | err_ppbs_write: |
105 | mlxsw_sp_kvdl_free(mlxsw_sp, type: MLXSW_SP_KVDL_ENTRY_TYPE_PBS, |
106 | entry_count: 1, entry_index: kvdl_index); |
107 | return err; |
108 | } |
109 | |
110 | static void mlxsw_sp_act_kvdl_fwd_entry_del(void *priv, u32 kvdl_index) |
111 | { |
112 | struct mlxsw_sp *mlxsw_sp = priv; |
113 | |
114 | mlxsw_sp_kvdl_free(mlxsw_sp, type: MLXSW_SP_KVDL_ENTRY_TYPE_PBS, |
115 | entry_count: 1, entry_index: kvdl_index); |
116 | } |
117 | |
118 | static int |
119 | mlxsw_sp_act_counter_index_get(void *priv, unsigned int *p_counter_index) |
120 | { |
121 | struct mlxsw_sp *mlxsw_sp = priv; |
122 | |
123 | return mlxsw_sp_flow_counter_alloc(mlxsw_sp, p_counter_index); |
124 | } |
125 | |
126 | static void |
127 | mlxsw_sp_act_counter_index_put(void *priv, unsigned int counter_index) |
128 | { |
129 | struct mlxsw_sp *mlxsw_sp = priv; |
130 | |
131 | mlxsw_sp_flow_counter_free(mlxsw_sp, counter_index); |
132 | } |
133 | |
134 | static int |
135 | mlxsw_sp_act_mirror_add(void *priv, u16 local_in_port, |
136 | const struct net_device *out_dev, |
137 | bool ingress, int *p_span_id) |
138 | { |
139 | struct mlxsw_sp_span_agent_parms agent_parms = {}; |
140 | struct mlxsw_sp_port *mlxsw_sp_port; |
141 | struct mlxsw_sp *mlxsw_sp = priv; |
142 | int err; |
143 | |
144 | agent_parms.to_dev = out_dev; |
145 | err = mlxsw_sp_span_agent_get(mlxsw_sp, p_span_id, parms: &agent_parms); |
146 | if (err) |
147 | return err; |
148 | |
149 | mlxsw_sp_port = mlxsw_sp->ports[local_in_port]; |
150 | err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, ingress); |
151 | if (err) |
152 | goto err_analyzed_port_get; |
153 | |
154 | return 0; |
155 | |
156 | err_analyzed_port_get: |
157 | mlxsw_sp_span_agent_put(mlxsw_sp, span_id: *p_span_id); |
158 | return err; |
159 | } |
160 | |
161 | static void |
162 | mlxsw_sp_act_mirror_del(void *priv, u16 local_in_port, int span_id, bool ingress) |
163 | { |
164 | struct mlxsw_sp_port *mlxsw_sp_port; |
165 | struct mlxsw_sp *mlxsw_sp = priv; |
166 | |
167 | mlxsw_sp_port = mlxsw_sp->ports[local_in_port]; |
168 | mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, ingress); |
169 | mlxsw_sp_span_agent_put(mlxsw_sp, span_id); |
170 | } |
171 | |
172 | static int mlxsw_sp_act_policer_add(void *priv, u64 rate_bytes_ps, u32 burst, |
173 | u16 *p_policer_index, |
174 | struct netlink_ext_ack *extack) |
175 | { |
176 | struct mlxsw_sp_policer_params params; |
177 | struct mlxsw_sp *mlxsw_sp = priv; |
178 | |
179 | params.rate = rate_bytes_ps; |
180 | params.burst = burst; |
181 | params.bytes = true; |
182 | return mlxsw_sp_policer_add(mlxsw_sp, |
183 | type: MLXSW_SP_POLICER_TYPE_SINGLE_RATE, |
184 | params: ¶ms, extack, p_policer_index); |
185 | } |
186 | |
187 | static void mlxsw_sp_act_policer_del(void *priv, u16 policer_index) |
188 | { |
189 | struct mlxsw_sp *mlxsw_sp = priv; |
190 | |
191 | mlxsw_sp_policer_del(mlxsw_sp, type: MLXSW_SP_POLICER_TYPE_SINGLE_RATE, |
192 | policer_index); |
193 | } |
194 | |
195 | static int mlxsw_sp1_act_sampler_add(void *priv, u16 local_port, |
196 | struct psample_group *psample_group, |
197 | u32 rate, u32 trunc_size, bool truncate, |
198 | bool ingress, int *p_span_id, |
199 | struct netlink_ext_ack *extack) |
200 | { |
201 | NL_SET_ERR_MSG_MOD(extack, "Sampling action is not supported on Spectrum-1" ); |
202 | return -EOPNOTSUPP; |
203 | } |
204 | |
205 | static void mlxsw_sp1_act_sampler_del(void *priv, u16 local_port, int span_id, |
206 | bool ingress) |
207 | { |
208 | WARN_ON_ONCE(1); |
209 | } |
210 | |
211 | const struct mlxsw_afa_ops mlxsw_sp1_act_afa_ops = { |
212 | .kvdl_set_add = mlxsw_sp1_act_kvdl_set_add, |
213 | .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, |
214 | .kvdl_set_activity_get = mlxsw_sp1_act_kvdl_set_activity_get, |
215 | .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, |
216 | .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, |
217 | .counter_index_get = mlxsw_sp_act_counter_index_get, |
218 | .counter_index_put = mlxsw_sp_act_counter_index_put, |
219 | .mirror_add = mlxsw_sp_act_mirror_add, |
220 | .mirror_del = mlxsw_sp_act_mirror_del, |
221 | .policer_add = mlxsw_sp_act_policer_add, |
222 | .policer_del = mlxsw_sp_act_policer_del, |
223 | .sampler_add = mlxsw_sp1_act_sampler_add, |
224 | .sampler_del = mlxsw_sp1_act_sampler_del, |
225 | }; |
226 | |
227 | static int mlxsw_sp2_act_sampler_add(void *priv, u16 local_port, |
228 | struct psample_group *psample_group, |
229 | u32 rate, u32 trunc_size, bool truncate, |
230 | bool ingress, int *p_span_id, |
231 | struct netlink_ext_ack *extack) |
232 | { |
233 | struct mlxsw_sp_span_agent_parms agent_parms = { |
234 | .session_id = MLXSW_SP_SPAN_SESSION_ID_SAMPLING, |
235 | }; |
236 | struct mlxsw_sp_sample_trigger trigger = { |
237 | .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE, |
238 | }; |
239 | struct mlxsw_sp_sample_params params; |
240 | struct mlxsw_sp_port *mlxsw_sp_port; |
241 | struct mlxsw_sp *mlxsw_sp = priv; |
242 | int err; |
243 | |
244 | params.psample_group = psample_group; |
245 | params.trunc_size = trunc_size; |
246 | params.rate = rate; |
247 | params.truncate = truncate; |
248 | err = mlxsw_sp_sample_trigger_params_set(mlxsw_sp, trigger: &trigger, params: ¶ms, |
249 | extack); |
250 | if (err) |
251 | return err; |
252 | |
253 | err = mlxsw_sp_span_agent_get(mlxsw_sp, p_span_id, parms: &agent_parms); |
254 | if (err) { |
255 | NL_SET_ERR_MSG_MOD(extack, "Failed to get SPAN agent" ); |
256 | goto err_span_agent_get; |
257 | } |
258 | |
259 | mlxsw_sp_port = mlxsw_sp->ports[local_port]; |
260 | err = mlxsw_sp_span_analyzed_port_get(mlxsw_sp_port, ingress); |
261 | if (err) { |
262 | NL_SET_ERR_MSG_MOD(extack, "Failed to get analyzed port" ); |
263 | goto err_analyzed_port_get; |
264 | } |
265 | |
266 | return 0; |
267 | |
268 | err_analyzed_port_get: |
269 | mlxsw_sp_span_agent_put(mlxsw_sp, span_id: *p_span_id); |
270 | err_span_agent_get: |
271 | mlxsw_sp_sample_trigger_params_unset(mlxsw_sp, trigger: &trigger); |
272 | return err; |
273 | } |
274 | |
275 | static void mlxsw_sp2_act_sampler_del(void *priv, u16 local_port, int span_id, |
276 | bool ingress) |
277 | { |
278 | struct mlxsw_sp_sample_trigger trigger = { |
279 | .type = MLXSW_SP_SAMPLE_TRIGGER_TYPE_POLICY_ENGINE, |
280 | }; |
281 | struct mlxsw_sp_port *mlxsw_sp_port; |
282 | struct mlxsw_sp *mlxsw_sp = priv; |
283 | |
284 | mlxsw_sp_port = mlxsw_sp->ports[local_port]; |
285 | mlxsw_sp_span_analyzed_port_put(mlxsw_sp_port, ingress); |
286 | mlxsw_sp_span_agent_put(mlxsw_sp, span_id); |
287 | mlxsw_sp_sample_trigger_params_unset(mlxsw_sp, trigger: &trigger); |
288 | } |
289 | |
290 | const struct mlxsw_afa_ops mlxsw_sp2_act_afa_ops = { |
291 | .kvdl_set_add = mlxsw_sp2_act_kvdl_set_add, |
292 | .kvdl_set_del = mlxsw_sp_act_kvdl_set_del, |
293 | .kvdl_set_activity_get = mlxsw_sp2_act_kvdl_set_activity_get, |
294 | .kvdl_fwd_entry_add = mlxsw_sp_act_kvdl_fwd_entry_add, |
295 | .kvdl_fwd_entry_del = mlxsw_sp_act_kvdl_fwd_entry_del, |
296 | .counter_index_get = mlxsw_sp_act_counter_index_get, |
297 | .counter_index_put = mlxsw_sp_act_counter_index_put, |
298 | .mirror_add = mlxsw_sp_act_mirror_add, |
299 | .mirror_del = mlxsw_sp_act_mirror_del, |
300 | .policer_add = mlxsw_sp_act_policer_add, |
301 | .policer_del = mlxsw_sp_act_policer_del, |
302 | .sampler_add = mlxsw_sp2_act_sampler_add, |
303 | .sampler_del = mlxsw_sp2_act_sampler_del, |
304 | .dummy_first_set = true, |
305 | }; |
306 | |
307 | int mlxsw_sp_afa_init(struct mlxsw_sp *mlxsw_sp) |
308 | { |
309 | mlxsw_sp->afa = mlxsw_afa_create(MLXSW_CORE_RES_GET(mlxsw_sp->core, |
310 | ACL_ACTIONS_PER_SET), |
311 | ops: mlxsw_sp->afa_ops, ops_priv: mlxsw_sp); |
312 | return PTR_ERR_OR_ZERO(ptr: mlxsw_sp->afa); |
313 | } |
314 | |
315 | void mlxsw_sp_afa_fini(struct mlxsw_sp *mlxsw_sp) |
316 | { |
317 | mlxsw_afa_destroy(mlxsw_afa: mlxsw_sp->afa); |
318 | } |
319 | |