GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum2_mr_tcam.c
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
10 struct 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
17 struct mlxsw_sp2_mr_route {
18         struct mlxsw_sp2_mr_tcam *mr_tcam;
19 };
20
21 static struct mlxsw_sp_acl_ruleset *
22 mlxsw_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
34 static 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
47 static 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
53 static 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,
60                                      mlxsw_sp2_mr_tcam_usage_ipv4,
61                                      ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv4));
62         mr_tcam->ruleset4 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
63                                                      mr_tcam->flow_block,
64                                                      MLXSW_SP_L3_PROTO_IPV4,
65                                                      MLXSW_SP_ACL_PROFILE_MR,
66                                                      &elusage);
67
68         if (IS_ERR(mr_tcam->ruleset4))
69                 return PTR_ERR(mr_tcam->ruleset4);
70
71         /* MC Router groups should be bound before routes are inserted. */
72         err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
73                                            MLXSW_REG_PEMRBT_PROTO_IPV4,
74                                            mr_tcam->ruleset4);
75         if (err)
76                 goto err_bind_group;
77
78         return 0;
79
80 err_bind_group:
81         mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
82         return err;
83 }
84
85 static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
86 {
87         mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
88 }
89
90 static 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
104 static 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,
114                                                      mr_tcam->flow_block,
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
131 err_bind_group:
132         mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
133         return err;
134 }
135
136 static 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
141 static void
142 mlxsw_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, MLXSW_AFK_ELEMENT_VIRT_ROUTER,
146                                        key->vrid, GENMASK(11, 0));
147         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
148                                        (char *) &key->source.addr4,
149                                        (char *) &key->source_mask.addr4, 4);
150         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
151                                        (char *) &key->group.addr4,
152                                        (char *) &key->group_mask.addr4, 4);
153 }
154
155 static void
156 mlxsw_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, MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3,
160                                        key->vrid, GENMASK(3, 0));
161         mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7,
162                                        key->vrid >> 4, GENMASK(3, 0));
163         mlxsw_sp_acl_rulei_keymask_u32(rulei,
164                                        MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
165                                        key->vrid >> 8, GENMASK(3, 0));
166         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_96_127,
167                                        &key->source.addr6.s6_addr[0x0],
168                                        &key->source_mask.addr6.s6_addr[0x0], 4);
169         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_64_95,
170                                        &key->source.addr6.s6_addr[0x4],
171                                        &key->source_mask.addr6.s6_addr[0x4], 4);
172         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_32_63,
173                                        &key->source.addr6.s6_addr[0x8],
174                                        &key->source_mask.addr6.s6_addr[0x8], 4);
175         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
176                                        &key->source.addr6.s6_addr[0xc],
177                                        &key->source_mask.addr6.s6_addr[0xc], 4);
178         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_96_127,
179                                        &key->group.addr6.s6_addr[0x0],
180                                        &key->group_mask.addr6.s6_addr[0x0], 4);
181         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_64_95,
182                                        &key->group.addr6.s6_addr[0x4],
183                                        &key->group_mask.addr6.s6_addr[0x4], 4);
184         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_32_63,
185                                        &key->group.addr6.s6_addr[0x8],
186                                        &key->group_mask.addr6.s6_addr[0x8], 4);
187         mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
188                                        &key->group.addr6.s6_addr[0xc],
189                                        &key->group_mask.addr6.s6_addr[0xc], 4);
190 }
191
192 static void
193 mlxsw_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
209 static int
210 mlxsw_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, key->proto);
224         if (WARN_ON(!ruleset))
225                 return -EINVAL;
226
227         rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset,
228                                         (unsigned long) route_priv, afa_block,
229                                         NULL);
230         if (IS_ERR(rule))
231                 return PTR_ERR(rule);
232
233         mlxsw_sp2_mr_tcam_rule_parse(rule, key, prio);
234         err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
235         if (err)
236                 goto err_rule_add;
237
238         return 0;
239
240 err_rule_add:
241         mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
242         return err;
243 }
244
245 static void
246 mlxsw_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, key->proto);
255         if (WARN_ON(!ruleset))
256                 return;
257
258         rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
259                                         (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
267 static int
268 mlxsw_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, key->proto);
279         if (WARN_ON(!ruleset))
280                 return -EINVAL;
281
282         rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
283                                         (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
290 static 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
310 err_ipv6_init:
311         mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
312 err_ipv4_init:
313         mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
314         return err;
315 }
316
317 static 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(mr_tcam->flow_block);
324 }
325
326 const 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 };