1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
3
4#include <linux/kernel.h>
5
6#include "core_acl_flex_actions.h"
7#include "spectrum.h"
8#include "spectrum_mr.h"
9
10struct mlxsw_sp2_mr_tcam {
11 struct mlxsw_sp *mlxsw_sp;
12 struct mlxsw_sp_flow_block *flow_block;
13 struct mlxsw_sp_acl_ruleset *ruleset4;
14 struct mlxsw_sp_acl_ruleset *ruleset6;
15};
16
17struct mlxsw_sp2_mr_route {
18 struct mlxsw_sp2_mr_tcam *mr_tcam;
19};
20
21static struct mlxsw_sp_acl_ruleset *
22mlxsw_sp2_mr_tcam_proto_ruleset(struct mlxsw_sp2_mr_tcam *mr_tcam,
23 enum mlxsw_sp_l3proto proto)
24{
25 switch (proto) {
26 case MLXSW_SP_L3_PROTO_IPV4:
27 return mr_tcam->ruleset4;
28 case MLXSW_SP_L3_PROTO_IPV6:
29 return mr_tcam->ruleset6;
30 }
31 return NULL;
32}
33
34static int mlxsw_sp2_mr_tcam_bind_group(struct mlxsw_sp *mlxsw_sp,
35 enum mlxsw_reg_pemrbt_protocol protocol,
36 struct mlxsw_sp_acl_ruleset *ruleset)
37{
38 char pemrbt_pl[MLXSW_REG_PEMRBT_LEN];
39 u16 group_id;
40
41 group_id = mlxsw_sp_acl_ruleset_group_id(ruleset);
42
43 mlxsw_reg_pemrbt_pack(payload: pemrbt_pl, protocol, group_id);
44 return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(pemrbt), payload: pemrbt_pl);
45}
46
47static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv4[] = {
48 MLXSW_AFK_ELEMENT_VIRT_ROUTER,
49 MLXSW_AFK_ELEMENT_SRC_IP_0_31,
50 MLXSW_AFK_ELEMENT_DST_IP_0_31,
51};
52
53static int mlxsw_sp2_mr_tcam_ipv4_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
54{
55 struct mlxsw_afk_element_usage elusage;
56 int err;
57
58 /* Initialize IPv4 ACL group. */
59 mlxsw_afk_element_usage_fill(elusage: &elusage,
60 elements: mlxsw_sp2_mr_tcam_usage_ipv4,
61 ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv4));
62 mr_tcam->ruleset4 = mlxsw_sp_acl_ruleset_get(mlxsw_sp: mr_tcam->mlxsw_sp,
63 block: mr_tcam->flow_block,
64 chain_index: MLXSW_SP_L3_PROTO_IPV4,
65 profile: MLXSW_SP_ACL_PROFILE_MR,
66 tmplt_elusage: &elusage);
67
68 if (IS_ERR(ptr: mr_tcam->ruleset4))
69 return PTR_ERR(ptr: mr_tcam->ruleset4);
70
71 /* MC Router groups should be bound before routes are inserted. */
72 err = mlxsw_sp2_mr_tcam_bind_group(mlxsw_sp: mr_tcam->mlxsw_sp,
73 protocol: MLXSW_REG_PEMRBT_PROTO_IPV4,
74 ruleset: mr_tcam->ruleset4);
75 if (err)
76 goto err_bind_group;
77
78 return 0;
79
80err_bind_group:
81 mlxsw_sp_acl_ruleset_put(mlxsw_sp: mr_tcam->mlxsw_sp, ruleset: mr_tcam->ruleset4);
82 return err;
83}
84
85static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
86{
87 mlxsw_sp_acl_ruleset_put(mlxsw_sp: mr_tcam->mlxsw_sp, ruleset: mr_tcam->ruleset4);
88}
89
90static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = {
91 MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3,
92 MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7,
93 MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
94 MLXSW_AFK_ELEMENT_SRC_IP_96_127,
95 MLXSW_AFK_ELEMENT_SRC_IP_64_95,
96 MLXSW_AFK_ELEMENT_SRC_IP_32_63,
97 MLXSW_AFK_ELEMENT_SRC_IP_0_31,
98 MLXSW_AFK_ELEMENT_DST_IP_96_127,
99 MLXSW_AFK_ELEMENT_DST_IP_64_95,
100 MLXSW_AFK_ELEMENT_DST_IP_32_63,
101 MLXSW_AFK_ELEMENT_DST_IP_0_31,
102};
103
104static int mlxsw_sp2_mr_tcam_ipv6_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
105{
106 struct mlxsw_afk_element_usage elusage;
107 int err;
108
109 /* Initialize IPv6 ACL group */
110 mlxsw_afk_element_usage_fill(elusage: &elusage,
111 elements: mlxsw_sp2_mr_tcam_usage_ipv6,
112 ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv6));
113 mr_tcam->ruleset6 = mlxsw_sp_acl_ruleset_get(mlxsw_sp: mr_tcam->mlxsw_sp,
114 block: mr_tcam->flow_block,
115 chain_index: MLXSW_SP_L3_PROTO_IPV6,
116 profile: MLXSW_SP_ACL_PROFILE_MR,
117 tmplt_elusage: &elusage);
118
119 if (IS_ERR(ptr: mr_tcam->ruleset6))
120 return PTR_ERR(ptr: mr_tcam->ruleset6);
121
122 /* MC Router groups should be bound before routes are inserted. */
123 err = mlxsw_sp2_mr_tcam_bind_group(mlxsw_sp: mr_tcam->mlxsw_sp,
124 protocol: MLXSW_REG_PEMRBT_PROTO_IPV6,
125 ruleset: mr_tcam->ruleset6);
126 if (err)
127 goto err_bind_group;
128
129 return 0;
130
131err_bind_group:
132 mlxsw_sp_acl_ruleset_put(mlxsw_sp: mr_tcam->mlxsw_sp, ruleset: mr_tcam->ruleset6);
133 return err;
134}
135
136static void mlxsw_sp2_mr_tcam_ipv6_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
137{
138 mlxsw_sp_acl_ruleset_put(mlxsw_sp: mr_tcam->mlxsw_sp, ruleset: mr_tcam->ruleset6);
139}
140
141static void
142mlxsw_sp2_mr_tcam_rule_parse4(struct mlxsw_sp_acl_rule_info *rulei,
143 struct mlxsw_sp_mr_route_key *key)
144{
145 mlxsw_sp_acl_rulei_keymask_u32(rulei, element: MLXSW_AFK_ELEMENT_VIRT_ROUTER,
146 key_value: key->vrid, GENMASK(11, 0));
147 mlxsw_sp_acl_rulei_keymask_buf(rulei, element: MLXSW_AFK_ELEMENT_SRC_IP_0_31,
148 key_value: (char *) &key->source.addr4,
149 mask_value: (char *) &key->source_mask.addr4, len: 4);
150 mlxsw_sp_acl_rulei_keymask_buf(rulei, element: MLXSW_AFK_ELEMENT_DST_IP_0_31,
151 key_value: (char *) &key->group.addr4,
152 mask_value: (char *) &key->group_mask.addr4, len: 4);
153}
154
155static void
156mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info *rulei,
157 struct mlxsw_sp_mr_route_key *key)
158{
159 mlxsw_sp_acl_rulei_keymask_u32(rulei, element: MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3,
160 key_value: key->vrid, GENMASK(3, 0));
161 mlxsw_sp_acl_rulei_keymask_u32(rulei, element: MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7,
162 key_value: key->vrid >> 4, GENMASK(3, 0));
163 mlxsw_sp_acl_rulei_keymask_u32(rulei,
164 element: MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
165 key_value: key->vrid >> 8, GENMASK(3, 0));
166 mlxsw_sp_acl_rulei_keymask_buf(rulei, element: MLXSW_AFK_ELEMENT_SRC_IP_96_127,
167 key_value: &key->source.addr6.s6_addr[0x0],
168 mask_value: &key->source_mask.addr6.s6_addr[0x0], len: 4);
169 mlxsw_sp_acl_rulei_keymask_buf(rulei, element: MLXSW_AFK_ELEMENT_SRC_IP_64_95,
170 key_value: &key->source.addr6.s6_addr[0x4],
171 mask_value: &key->source_mask.addr6.s6_addr[0x4], len: 4);
172 mlxsw_sp_acl_rulei_keymask_buf(rulei, element: MLXSW_AFK_ELEMENT_SRC_IP_32_63,
173 key_value: &key->source.addr6.s6_addr[0x8],
174 mask_value: &key->source_mask.addr6.s6_addr[0x8], len: 4);
175 mlxsw_sp_acl_rulei_keymask_buf(rulei, element: MLXSW_AFK_ELEMENT_SRC_IP_0_31,
176 key_value: &key->source.addr6.s6_addr[0xc],
177 mask_value: &key->source_mask.addr6.s6_addr[0xc], len: 4);
178 mlxsw_sp_acl_rulei_keymask_buf(rulei, element: MLXSW_AFK_ELEMENT_DST_IP_96_127,
179 key_value: &key->group.addr6.s6_addr[0x0],
180 mask_value: &key->group_mask.addr6.s6_addr[0x0], len: 4);
181 mlxsw_sp_acl_rulei_keymask_buf(rulei, element: MLXSW_AFK_ELEMENT_DST_IP_64_95,
182 key_value: &key->group.addr6.s6_addr[0x4],
183 mask_value: &key->group_mask.addr6.s6_addr[0x4], len: 4);
184 mlxsw_sp_acl_rulei_keymask_buf(rulei, element: MLXSW_AFK_ELEMENT_DST_IP_32_63,
185 key_value: &key->group.addr6.s6_addr[0x8],
186 mask_value: &key->group_mask.addr6.s6_addr[0x8], len: 4);
187 mlxsw_sp_acl_rulei_keymask_buf(rulei, element: MLXSW_AFK_ELEMENT_DST_IP_0_31,
188 key_value: &key->group.addr6.s6_addr[0xc],
189 mask_value: &key->group_mask.addr6.s6_addr[0xc], len: 4);
190}
191
192static void
193mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,
194 struct mlxsw_sp_mr_route_key *key,
195 unsigned int priority)
196{
197 struct mlxsw_sp_acl_rule_info *rulei;
198
199 rulei = mlxsw_sp_acl_rule_rulei(rule);
200 rulei->priority = priority;
201 switch (key->proto) {
202 case MLXSW_SP_L3_PROTO_IPV4:
203 return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);
204 case MLXSW_SP_L3_PROTO_IPV6:
205 return mlxsw_sp2_mr_tcam_rule_parse6(rulei, key);
206 }
207}
208
209static int
210mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
211 void *route_priv,
212 struct mlxsw_sp_mr_route_key *key,
213 struct mlxsw_afa_block *afa_block,
214 enum mlxsw_sp_mr_route_prio prio)
215{
216 struct mlxsw_sp2_mr_route *mr_route = route_priv;
217 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
218 struct mlxsw_sp_acl_ruleset *ruleset;
219 struct mlxsw_sp_acl_rule *rule;
220 int err;
221
222 mr_route->mr_tcam = mr_tcam;
223 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, proto: key->proto);
224 if (WARN_ON(!ruleset))
225 return -EINVAL;
226
227 rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset,
228 cookie: (unsigned long) route_priv, afa_block,
229 NULL);
230 if (IS_ERR(ptr: rule))
231 return PTR_ERR(ptr: rule);
232
233 mlxsw_sp2_mr_tcam_rule_parse(rule, key, priority: prio);
234 err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
235 if (err)
236 goto err_rule_add;
237
238 return 0;
239
240err_rule_add:
241 mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
242 return err;
243}
244
245static void
246mlxsw_sp2_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
247 void *route_priv,
248 struct mlxsw_sp_mr_route_key *key)
249{
250 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
251 struct mlxsw_sp_acl_ruleset *ruleset;
252 struct mlxsw_sp_acl_rule *rule;
253
254 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, proto: key->proto);
255 if (WARN_ON(!ruleset))
256 return;
257
258 rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
259 cookie: (unsigned long) route_priv);
260 if (WARN_ON(!rule))
261 return;
262
263 mlxsw_sp_acl_rule_del(mlxsw_sp, rule);
264 mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
265}
266
267static int
268mlxsw_sp2_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
269 void *route_priv,
270 struct mlxsw_sp_mr_route_key *key,
271 struct mlxsw_afa_block *afa_block)
272{
273 struct mlxsw_sp2_mr_route *mr_route = route_priv;
274 struct mlxsw_sp2_mr_tcam *mr_tcam = mr_route->mr_tcam;
275 struct mlxsw_sp_acl_ruleset *ruleset;
276 struct mlxsw_sp_acl_rule *rule;
277
278 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, proto: key->proto);
279 if (WARN_ON(!ruleset))
280 return -EINVAL;
281
282 rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
283 cookie: (unsigned long) route_priv);
284 if (WARN_ON(!rule))
285 return -EINVAL;
286
287 return mlxsw_sp_acl_rule_action_replace(mlxsw_sp, rule, afa_block);
288}
289
290static int mlxsw_sp2_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
291{
292 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
293 int err;
294
295 mr_tcam->mlxsw_sp = mlxsw_sp;
296 mr_tcam->flow_block = mlxsw_sp_flow_block_create(mlxsw_sp, NULL);
297 if (!mr_tcam->flow_block)
298 return -ENOMEM;
299
300 err = mlxsw_sp2_mr_tcam_ipv4_init(mr_tcam);
301 if (err)
302 goto err_ipv4_init;
303
304 err = mlxsw_sp2_mr_tcam_ipv6_init(mr_tcam);
305 if (err)
306 goto err_ipv6_init;
307
308 return 0;
309
310err_ipv6_init:
311 mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
312err_ipv4_init:
313 mlxsw_sp_flow_block_destroy(block: mr_tcam->flow_block);
314 return err;
315}
316
317static void mlxsw_sp2_mr_tcam_fini(void *priv)
318{
319 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
320
321 mlxsw_sp2_mr_tcam_ipv6_fini(mr_tcam);
322 mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
323 mlxsw_sp_flow_block_destroy(block: mr_tcam->flow_block);
324}
325
326const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops = {
327 .priv_size = sizeof(struct mlxsw_sp2_mr_tcam),
328 .init = mlxsw_sp2_mr_tcam_init,
329 .fini = mlxsw_sp2_mr_tcam_fini,
330 .route_priv_size = sizeof(struct mlxsw_sp2_mr_route),
331 .route_create = mlxsw_sp2_mr_tcam_route_create,
332 .route_destroy = mlxsw_sp2_mr_tcam_route_destroy,
333 .route_update = mlxsw_sp2_mr_tcam_route_update,
334};
335

source code of linux/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c