Merge tag 'asm-generic-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd...
[linux-block.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum2_mr_tcam.c
CommitLineData
9948a064
JP
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
18ce0e4e
JP
3
4#include <linux/kernel.h>
5
6#include "core_acl_flex_actions.h"
7#include "spectrum.h"
8#include "spectrum_mr.h"
9
cf7221a4
ND
10struct mlxsw_sp2_mr_tcam {
11 struct mlxsw_sp *mlxsw_sp;
3bc3ffb6 12 struct mlxsw_sp_flow_block *flow_block;
cf7221a4
ND
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(pemrbt_pl, protocol, group_id);
44 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pemrbt), pemrbt_pl);
45}
46
47static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv4[] = {
6d5d8ebb
AC
48 MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
49 MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
cf7221a4
ND
50 MLXSW_AFK_ELEMENT_SRC_IP_0_31,
51 MLXSW_AFK_ELEMENT_DST_IP_0_31,
52};
53
54static int mlxsw_sp2_mr_tcam_ipv4_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
55{
56 struct mlxsw_afk_element_usage elusage;
57 int err;
58
59 /* Initialize IPv4 ACL group. */
60 mlxsw_afk_element_usage_fill(&elusage,
61 mlxsw_sp2_mr_tcam_usage_ipv4,
62 ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv4));
63 mr_tcam->ruleset4 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
3bc3ffb6 64 mr_tcam->flow_block,
cf7221a4
ND
65 MLXSW_SP_L3_PROTO_IPV4,
66 MLXSW_SP_ACL_PROFILE_MR,
67 &elusage);
68
69 if (IS_ERR(mr_tcam->ruleset4))
70 return PTR_ERR(mr_tcam->ruleset4);
71
72 /* MC Router groups should be bound before routes are inserted. */
73 err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
74 MLXSW_REG_PEMRBT_PROTO_IPV4,
75 mr_tcam->ruleset4);
76 if (err)
77 goto err_bind_group;
78
79 return 0;
80
81err_bind_group:
82 mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
83 return err;
84}
85
86static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
87{
88 mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
89}
90
91static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = {
6d5d8ebb
AC
92 MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
93 MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
cf7221a4
ND
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,
111 mlxsw_sp2_mr_tcam_usage_ipv6,
112 ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv6));
113 mr_tcam->ruleset6 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
3bc3ffb6 114 mr_tcam->flow_block,
cf7221a4
ND
115 MLXSW_SP_L3_PROTO_IPV6,
116 MLXSW_SP_ACL_PROFILE_MR,
117 &elusage);
118
119 if (IS_ERR(mr_tcam->ruleset6))
120 return PTR_ERR(mr_tcam->ruleset6);
121
122 /* MC Router groups should be bound before routes are inserted. */
123 err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
124 MLXSW_REG_PEMRBT_PROTO_IPV6,
125 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(mr_tcam->mlxsw_sp, 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(mr_tcam->mlxsw_sp, 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_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
146 (char *) &key->source.addr4,
147 (char *) &key->source_mask.addr4, 4);
148 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
149 (char *) &key->group.addr4,
150 (char *) &key->group_mask.addr4, 4);
151}
152
153static void
154mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info *rulei,
155 struct mlxsw_sp_mr_route_key *key)
156{
157 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_96_127,
158 &key->source.addr6.s6_addr[0x0],
159 &key->source_mask.addr6.s6_addr[0x0], 4);
160 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_64_95,
161 &key->source.addr6.s6_addr[0x4],
162 &key->source_mask.addr6.s6_addr[0x4], 4);
163 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_32_63,
164 &key->source.addr6.s6_addr[0x8],
165 &key->source_mask.addr6.s6_addr[0x8], 4);
166 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
167 &key->source.addr6.s6_addr[0xc],
168 &key->source_mask.addr6.s6_addr[0xc], 4);
169 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_96_127,
170 &key->group.addr6.s6_addr[0x0],
171 &key->group_mask.addr6.s6_addr[0x0], 4);
172 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_64_95,
173 &key->group.addr6.s6_addr[0x4],
174 &key->group_mask.addr6.s6_addr[0x4], 4);
175 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_32_63,
176 &key->group.addr6.s6_addr[0x8],
177 &key->group_mask.addr6.s6_addr[0x8], 4);
178 mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
179 &key->group.addr6.s6_addr[0xc],
180 &key->group_mask.addr6.s6_addr[0xc], 4);
181}
182
183static void
184mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,
185 struct mlxsw_sp_mr_route_key *key,
186 unsigned int priority)
187{
188 struct mlxsw_sp_acl_rule_info *rulei;
189
190 rulei = mlxsw_sp_acl_rule_rulei(rule);
191 rulei->priority = priority;
6d5d8ebb 192 mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
cf7221a4
ND
193 key->vrid, GENMASK(7, 0));
194 mlxsw_sp_acl_rulei_keymask_u32(rulei,
6d5d8ebb 195 MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
cf7221a4
ND
196 key->vrid >> 8, GENMASK(2, 0));
197 switch (key->proto) {
198 case MLXSW_SP_L3_PROTO_IPV4:
199 return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);
200 case MLXSW_SP_L3_PROTO_IPV6:
201 return mlxsw_sp2_mr_tcam_rule_parse6(rulei, key);
202 }
203}
204
18ce0e4e
JP
205static int
206mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
207 void *route_priv,
208 struct mlxsw_sp_mr_route_key *key,
209 struct mlxsw_afa_block *afa_block,
210 enum mlxsw_sp_mr_route_prio prio)
211{
cf7221a4
ND
212 struct mlxsw_sp2_mr_route *mr_route = route_priv;
213 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
214 struct mlxsw_sp_acl_ruleset *ruleset;
215 struct mlxsw_sp_acl_rule *rule;
216 int err;
217
218 mr_route->mr_tcam = mr_tcam;
219 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
220 if (WARN_ON(!ruleset))
221 return -EINVAL;
222
223 rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset,
224 (unsigned long) route_priv, afa_block,
225 NULL);
226 if (IS_ERR(rule))
227 return PTR_ERR(rule);
228
229 mlxsw_sp2_mr_tcam_rule_parse(rule, key, prio);
230 err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
231 if (err)
232 goto err_rule_add;
233
18ce0e4e 234 return 0;
cf7221a4
ND
235
236err_rule_add:
237 mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
238 return err;
18ce0e4e
JP
239}
240
241static void
242mlxsw_sp2_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
243 void *route_priv,
244 struct mlxsw_sp_mr_route_key *key)
245{
cf7221a4
ND
246 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
247 struct mlxsw_sp_acl_ruleset *ruleset;
248 struct mlxsw_sp_acl_rule *rule;
249
250 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
251 if (WARN_ON(!ruleset))
252 return;
253
254 rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
255 (unsigned long) route_priv);
256 if (WARN_ON(!rule))
257 return;
258
259 mlxsw_sp_acl_rule_del(mlxsw_sp, rule);
260 mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
18ce0e4e
JP
261}
262
263static int
264mlxsw_sp2_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
265 void *route_priv,
266 struct mlxsw_sp_mr_route_key *key,
267 struct mlxsw_afa_block *afa_block)
268{
cf7221a4
ND
269 struct mlxsw_sp2_mr_route *mr_route = route_priv;
270 struct mlxsw_sp2_mr_tcam *mr_tcam = mr_route->mr_tcam;
271 struct mlxsw_sp_acl_ruleset *ruleset;
272 struct mlxsw_sp_acl_rule *rule;
273
274 ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
275 if (WARN_ON(!ruleset))
276 return -EINVAL;
277
278 rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
279 (unsigned long) route_priv);
280 if (WARN_ON(!rule))
281 return -EINVAL;
282
283 return mlxsw_sp_acl_rule_action_replace(mlxsw_sp, rule, afa_block);
18ce0e4e
JP
284}
285
286static int mlxsw_sp2_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
287{
cf7221a4
ND
288 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
289 int err;
290
291 mr_tcam->mlxsw_sp = mlxsw_sp;
3bc3ffb6
JP
292 mr_tcam->flow_block = mlxsw_sp_flow_block_create(mlxsw_sp, NULL);
293 if (!mr_tcam->flow_block)
cf7221a4
ND
294 return -ENOMEM;
295
296 err = mlxsw_sp2_mr_tcam_ipv4_init(mr_tcam);
297 if (err)
298 goto err_ipv4_init;
299
300 err = mlxsw_sp2_mr_tcam_ipv6_init(mr_tcam);
301 if (err)
302 goto err_ipv6_init;
303
18ce0e4e 304 return 0;
cf7221a4
ND
305
306err_ipv6_init:
307 mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
308err_ipv4_init:
3bc3ffb6 309 mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
cf7221a4 310 return err;
18ce0e4e
JP
311}
312
313static void mlxsw_sp2_mr_tcam_fini(void *priv)
314{
cf7221a4
ND
315 struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
316
317 mlxsw_sp2_mr_tcam_ipv6_fini(mr_tcam);
318 mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
3bc3ffb6 319 mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
18ce0e4e
JP
320}
321
322const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops = {
cf7221a4 323 .priv_size = sizeof(struct mlxsw_sp2_mr_tcam),
18ce0e4e
JP
324 .init = mlxsw_sp2_mr_tcam_init,
325 .fini = mlxsw_sp2_mr_tcam_fini,
cf7221a4 326 .route_priv_size = sizeof(struct mlxsw_sp2_mr_route),
18ce0e4e
JP
327 .route_create = mlxsw_sp2_mr_tcam_route_create,
328 .route_destroy = mlxsw_sp2_mr_tcam_route_destroy,
329 .route_update = mlxsw_sp2_mr_tcam_route_update,
330};