Merge tag 'regmap-fix-v5.0-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum1_mr_tcam.c
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/parman.h>
6
7 #include "reg.h"
8 #include "spectrum.h"
9 #include "core_acl_flex_actions.h"
10 #include "spectrum_mr.h"
11
12 struct mlxsw_sp1_mr_tcam_region {
13         struct mlxsw_sp *mlxsw_sp;
14         enum mlxsw_reg_rtar_key_type rtar_key_type;
15         struct parman *parman;
16         struct parman_prio *parman_prios;
17 };
18
19 struct mlxsw_sp1_mr_tcam {
20         struct mlxsw_sp1_mr_tcam_region tcam_regions[MLXSW_SP_L3_PROTO_MAX];
21 };
22
23 struct mlxsw_sp1_mr_tcam_route {
24         struct parman_item parman_item;
25         struct parman_prio *parman_prio;
26 };
27
28 static int mlxsw_sp1_mr_tcam_route_replace(struct mlxsw_sp *mlxsw_sp,
29                                            struct parman_item *parman_item,
30                                            struct mlxsw_sp_mr_route_key *key,
31                                            struct mlxsw_afa_block *afa_block)
32 {
33         char rmft2_pl[MLXSW_REG_RMFT2_LEN];
34
35         switch (key->proto) {
36         case MLXSW_SP_L3_PROTO_IPV4:
37                 mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, true, parman_item->index,
38                                           key->vrid,
39                                           MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
40                                           ntohl(key->group.addr4),
41                                           ntohl(key->group_mask.addr4),
42                                           ntohl(key->source.addr4),
43                                           ntohl(key->source_mask.addr4),
44                                           mlxsw_afa_block_first_set(afa_block));
45                 break;
46         case MLXSW_SP_L3_PROTO_IPV6:
47                 mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, true, parman_item->index,
48                                           key->vrid,
49                                           MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
50                                           key->group.addr6,
51                                           key->group_mask.addr6,
52                                           key->source.addr6,
53                                           key->source_mask.addr6,
54                                           mlxsw_afa_block_first_set(afa_block));
55         }
56
57         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
58 }
59
60 static int mlxsw_sp1_mr_tcam_route_remove(struct mlxsw_sp *mlxsw_sp,
61                                           struct parman_item *parman_item,
62                                           struct mlxsw_sp_mr_route_key *key)
63 {
64         struct in6_addr zero_addr = IN6ADDR_ANY_INIT;
65         char rmft2_pl[MLXSW_REG_RMFT2_LEN];
66
67         switch (key->proto) {
68         case MLXSW_SP_L3_PROTO_IPV4:
69                 mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, false, parman_item->index,
70                                           key->vrid, 0, 0, 0, 0, 0, 0, NULL);
71                 break;
72         case MLXSW_SP_L3_PROTO_IPV6:
73                 mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, false, parman_item->index,
74                                           key->vrid, 0, 0, zero_addr, zero_addr,
75                                           zero_addr, zero_addr, NULL);
76                 break;
77         }
78
79         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
80 }
81
82 static struct mlxsw_sp1_mr_tcam_region *
83 mlxsw_sp1_mr_tcam_protocol_region(struct mlxsw_sp1_mr_tcam *mr_tcam,
84                                   enum mlxsw_sp_l3proto proto)
85 {
86         return &mr_tcam->tcam_regions[proto];
87 }
88
89 static int
90 mlxsw_sp1_mr_tcam_route_parman_item_add(struct mlxsw_sp1_mr_tcam *mr_tcam,
91                                         struct mlxsw_sp1_mr_tcam_route *route,
92                                         struct mlxsw_sp_mr_route_key *key,
93                                         enum mlxsw_sp_mr_route_prio prio)
94 {
95         struct mlxsw_sp1_mr_tcam_region *tcam_region;
96         int err;
97
98         tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
99         err = parman_item_add(tcam_region->parman,
100                               &tcam_region->parman_prios[prio],
101                               &route->parman_item);
102         if (err)
103                 return err;
104
105         route->parman_prio = &tcam_region->parman_prios[prio];
106         return 0;
107 }
108
109 static void
110 mlxsw_sp1_mr_tcam_route_parman_item_remove(struct mlxsw_sp1_mr_tcam *mr_tcam,
111                                            struct mlxsw_sp1_mr_tcam_route *route,
112                                            struct mlxsw_sp_mr_route_key *key)
113 {
114         struct mlxsw_sp1_mr_tcam_region *tcam_region;
115
116         tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
117         parman_item_remove(tcam_region->parman,
118                            route->parman_prio, &route->parman_item);
119 }
120
121 static int
122 mlxsw_sp1_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
123                                void *route_priv,
124                                struct mlxsw_sp_mr_route_key *key,
125                                struct mlxsw_afa_block *afa_block,
126                                enum mlxsw_sp_mr_route_prio prio)
127 {
128         struct mlxsw_sp1_mr_tcam_route *route = route_priv;
129         struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
130         int err;
131
132         err = mlxsw_sp1_mr_tcam_route_parman_item_add(mr_tcam, route,
133                                                       key, prio);
134         if (err)
135                 return err;
136
137         err = mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
138                                               key, afa_block);
139         if (err)
140                 goto err_route_replace;
141         return 0;
142
143 err_route_replace:
144         mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
145         return err;
146 }
147
148 static void
149 mlxsw_sp1_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
150                                 void *route_priv,
151                                 struct mlxsw_sp_mr_route_key *key)
152 {
153         struct mlxsw_sp1_mr_tcam_route *route = route_priv;
154         struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
155
156         mlxsw_sp1_mr_tcam_route_remove(mlxsw_sp, &route->parman_item, key);
157         mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
158 }
159
160 static int
161 mlxsw_sp1_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
162                                void *route_priv,
163                                struct mlxsw_sp_mr_route_key *key,
164                                struct mlxsw_afa_block *afa_block)
165 {
166         struct mlxsw_sp1_mr_tcam_route *route = route_priv;
167
168         return mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
169                                                key, afa_block);
170 }
171
172 #define MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT 16
173 #define MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP 16
174
175 static int
176 mlxsw_sp1_mr_tcam_region_alloc(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
177 {
178         struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
179         char rtar_pl[MLXSW_REG_RTAR_LEN];
180
181         mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_ALLOCATE,
182                             mr_tcam_region->rtar_key_type,
183                             MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT);
184         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
185 }
186
187 static void
188 mlxsw_sp1_mr_tcam_region_free(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
189 {
190         struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
191         char rtar_pl[MLXSW_REG_RTAR_LEN];
192
193         mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_DEALLOCATE,
194                             mr_tcam_region->rtar_key_type, 0);
195         mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
196 }
197
198 static int mlxsw_sp1_mr_tcam_region_parman_resize(void *priv,
199                                                   unsigned long new_count)
200 {
201         struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
202         struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
203         char rtar_pl[MLXSW_REG_RTAR_LEN];
204         u64 max_tcam_rules;
205
206         max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES);
207         if (new_count > max_tcam_rules)
208                 return -EINVAL;
209         mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_RESIZE,
210                             mr_tcam_region->rtar_key_type, new_count);
211         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
212 }
213
214 static void mlxsw_sp1_mr_tcam_region_parman_move(void *priv,
215                                                  unsigned long from_index,
216                                                  unsigned long to_index,
217                                                  unsigned long count)
218 {
219         struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
220         struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
221         char rrcr_pl[MLXSW_REG_RRCR_LEN];
222
223         mlxsw_reg_rrcr_pack(rrcr_pl, MLXSW_REG_RRCR_OP_MOVE,
224                             from_index, count,
225                             mr_tcam_region->rtar_key_type, to_index);
226         mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rrcr), rrcr_pl);
227 }
228
229 static const struct parman_ops mlxsw_sp1_mr_tcam_region_parman_ops = {
230         .base_count     = MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT,
231         .resize_step    = MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP,
232         .resize         = mlxsw_sp1_mr_tcam_region_parman_resize,
233         .move           = mlxsw_sp1_mr_tcam_region_parman_move,
234         .algo           = PARMAN_ALGO_TYPE_LSORT,
235 };
236
237 static int
238 mlxsw_sp1_mr_tcam_region_init(struct mlxsw_sp *mlxsw_sp,
239                               struct mlxsw_sp1_mr_tcam_region *mr_tcam_region,
240                               enum mlxsw_reg_rtar_key_type rtar_key_type)
241 {
242         struct parman_prio *parman_prios;
243         struct parman *parman;
244         int err;
245         int i;
246
247         mr_tcam_region->rtar_key_type = rtar_key_type;
248         mr_tcam_region->mlxsw_sp = mlxsw_sp;
249
250         err = mlxsw_sp1_mr_tcam_region_alloc(mr_tcam_region);
251         if (err)
252                 return err;
253
254         parman = parman_create(&mlxsw_sp1_mr_tcam_region_parman_ops,
255                                mr_tcam_region);
256         if (!parman) {
257                 err = -ENOMEM;
258                 goto err_parman_create;
259         }
260         mr_tcam_region->parman = parman;
261
262         parman_prios = kmalloc_array(MLXSW_SP_MR_ROUTE_PRIO_MAX + 1,
263                                      sizeof(*parman_prios), GFP_KERNEL);
264         if (!parman_prios) {
265                 err = -ENOMEM;
266                 goto err_parman_prios_alloc;
267         }
268         mr_tcam_region->parman_prios = parman_prios;
269
270         for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
271                 parman_prio_init(mr_tcam_region->parman,
272                                  &mr_tcam_region->parman_prios[i], i);
273         return 0;
274
275 err_parman_prios_alloc:
276         parman_destroy(parman);
277 err_parman_create:
278         mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
279         return err;
280 }
281
282 static void
283 mlxsw_sp1_mr_tcam_region_fini(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
284 {
285         int i;
286
287         for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
288                 parman_prio_fini(&mr_tcam_region->parman_prios[i]);
289         kfree(mr_tcam_region->parman_prios);
290         parman_destroy(mr_tcam_region->parman);
291         mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
292 }
293
294 static int mlxsw_sp1_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
295 {
296         struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
297         struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
298         u32 rtar_key;
299         int err;
300
301         if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_TCAM_RULES))
302                 return -EIO;
303
304         rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV4_MULTICAST;
305         err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
306                                             &region[MLXSW_SP_L3_PROTO_IPV4],
307                                             rtar_key);
308         if (err)
309                 return err;
310
311         rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV6_MULTICAST;
312         err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
313                                             &region[MLXSW_SP_L3_PROTO_IPV6],
314                                             rtar_key);
315         if (err)
316                 goto err_ipv6_region_init;
317
318         return 0;
319
320 err_ipv6_region_init:
321         mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
322         return err;
323 }
324
325 static void mlxsw_sp1_mr_tcam_fini(void *priv)
326 {
327         struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
328         struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
329
330         mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV6]);
331         mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
332 }
333
334 const struct mlxsw_sp_mr_tcam_ops mlxsw_sp1_mr_tcam_ops = {
335         .priv_size = sizeof(struct mlxsw_sp1_mr_tcam),
336         .init = mlxsw_sp1_mr_tcam_init,
337         .fini = mlxsw_sp1_mr_tcam_fini,
338         .route_priv_size = sizeof(struct mlxsw_sp1_mr_tcam_route),
339         .route_create = mlxsw_sp1_mr_tcam_route_create,
340         .route_destroy = mlxsw_sp1_mr_tcam_route_destroy,
341         .route_update = mlxsw_sp1_mr_tcam_route_update,
342 };