Merge remote-tracking branch 'asoc/fix/intel' into asoc-linus
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_dpipe.c
1 /*
2  * drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
3  * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
4  * Copyright (c) 2017 Arkadi Sharshevsky <arakdis@mellanox.com>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the names of the copyright holders nor the names of its
15  *    contributors may be used to endorse or promote products derived from
16  *    this software without specific prior written permission.
17  *
18  * Alternatively, this software may be distributed under the terms of the
19  * GNU General Public License ("GPL") version 2 as published by the Free
20  * Software Foundation.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <linux/kernel.h>
36 #include <net/devlink.h>
37
38 #include "spectrum.h"
39 #include "spectrum_dpipe.h"
40 #include "spectrum_router.h"
41
42 enum mlxsw_sp_field_metadata_id {
43         MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
44         MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
45         MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
46 };
47
48 static struct devlink_dpipe_field mlxsw_sp_dpipe_fields_metadata[] = {
49         { .name = "erif_port",
50           .id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT,
51           .bitwidth = 32,
52           .mapping_type = DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX,
53         },
54         { .name = "l3_forward",
55           .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD,
56           .bitwidth = 1,
57         },
58         { .name = "l3_drop",
59           .id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP,
60           .bitwidth = 1,
61         },
62 };
63
64 enum mlxsw_sp_dpipe_header_id {
65         MLXSW_SP_DPIPE_HEADER_METADATA,
66 };
67
68 static struct devlink_dpipe_header mlxsw_sp_dpipe_header_metadata = {
69         .name = "mlxsw_meta",
70         .id = MLXSW_SP_DPIPE_HEADER_METADATA,
71         .fields = mlxsw_sp_dpipe_fields_metadata,
72         .fields_count = ARRAY_SIZE(mlxsw_sp_dpipe_fields_metadata),
73 };
74
75 static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
76         &mlxsw_sp_dpipe_header_metadata,
77 };
78
79 static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
80         .headers = mlxsw_dpipe_headers,
81         .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
82 };
83
84 static int mlxsw_sp_dpipe_table_erif_actions_dump(void *priv,
85                                                   struct sk_buff *skb)
86 {
87         struct devlink_dpipe_action action = {0};
88         int err;
89
90         action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
91         action.header = &mlxsw_sp_dpipe_header_metadata;
92         action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
93
94         err = devlink_dpipe_action_put(skb, &action);
95         if (err)
96                 return err;
97
98         action.type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
99         action.header = &mlxsw_sp_dpipe_header_metadata;
100         action.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_DROP;
101
102         return devlink_dpipe_action_put(skb, &action);
103 }
104
105 static int mlxsw_sp_dpipe_table_erif_matches_dump(void *priv,
106                                                   struct sk_buff *skb)
107 {
108         struct devlink_dpipe_match match = {0};
109
110         match.type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
111         match.header = &mlxsw_sp_dpipe_header_metadata;
112         match.field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
113
114         return devlink_dpipe_match_put(skb, &match);
115 }
116
117 static void mlxsw_sp_erif_entry_clear(struct devlink_dpipe_entry *entry)
118 {
119         unsigned int value_count, value_index;
120         struct devlink_dpipe_value *value;
121
122         value = entry->action_values;
123         value_count = entry->action_values_count;
124         for (value_index = 0; value_index < value_count; value_index++) {
125                 kfree(value[value_index].value);
126                 kfree(value[value_index].mask);
127         }
128
129         value = entry->match_values;
130         value_count = entry->match_values_count;
131         for (value_index = 0; value_index < value_count; value_index++) {
132                 kfree(value[value_index].value);
133                 kfree(value[value_index].mask);
134         }
135 }
136
137 static void
138 mlxsw_sp_erif_match_action_prepare(struct devlink_dpipe_match *match,
139                                    struct devlink_dpipe_action *action)
140 {
141         action->type = DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY;
142         action->header = &mlxsw_sp_dpipe_header_metadata;
143         action->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_L3_FORWARD;
144
145         match->type = DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT;
146         match->header = &mlxsw_sp_dpipe_header_metadata;
147         match->field_id = MLXSW_SP_DPIPE_FIELD_METADATA_ERIF_PORT;
148 }
149
150 static int mlxsw_sp_erif_entry_prepare(struct devlink_dpipe_entry *entry,
151                                        struct devlink_dpipe_value *match_value,
152                                        struct devlink_dpipe_match *match,
153                                        struct devlink_dpipe_value *action_value,
154                                        struct devlink_dpipe_action *action)
155 {
156         entry->match_values = match_value;
157         entry->match_values_count = 1;
158
159         entry->action_values = action_value;
160         entry->action_values_count = 1;
161
162         match_value->match = match;
163         match_value->value_size = sizeof(u32);
164         match_value->value = kmalloc(match_value->value_size, GFP_KERNEL);
165         if (!match_value->value)
166                 return -ENOMEM;
167
168         action_value->action = action;
169         action_value->value_size = sizeof(u32);
170         action_value->value = kmalloc(action_value->value_size, GFP_KERNEL);
171         if (!action_value->value)
172                 goto err_action_alloc;
173         return 0;
174
175 err_action_alloc:
176         kfree(match_value->value);
177         return -ENOMEM;
178 }
179
180 static int mlxsw_sp_erif_entry_get(struct mlxsw_sp *mlxsw_sp,
181                                    struct devlink_dpipe_entry *entry,
182                                    struct mlxsw_sp_rif *rif,
183                                    bool counters_enabled)
184 {
185         u32 *action_value;
186         u32 *rif_value;
187         u64 cnt;
188         int err;
189
190         /* Set Match RIF index */
191         rif_value = entry->match_values->value;
192         *rif_value = mlxsw_sp_rif_index(rif);
193         entry->match_values->mapping_value = mlxsw_sp_rif_dev_ifindex(rif);
194         entry->match_values->mapping_valid = true;
195
196         /* Set Action Forwarding */
197         action_value = entry->action_values->value;
198         *action_value = 1;
199
200         entry->counter_valid = false;
201         entry->counter = 0;
202         entry->index = mlxsw_sp_rif_index(rif);
203
204         if (!counters_enabled)
205                 return 0;
206
207         err = mlxsw_sp_rif_counter_value_get(mlxsw_sp, rif,
208                                              MLXSW_SP_RIF_COUNTER_EGRESS,
209                                              &cnt);
210         if (!err) {
211                 entry->counter = cnt;
212                 entry->counter_valid = true;
213         }
214         return 0;
215 }
216
217 static int
218 mlxsw_sp_table_erif_entries_dump(void *priv, bool counters_enabled,
219                                  struct devlink_dpipe_dump_ctx *dump_ctx)
220 {
221         struct devlink_dpipe_value match_value = {{0}}, action_value = {{0}};
222         struct devlink_dpipe_action action = {0};
223         struct devlink_dpipe_match match = {0};
224         struct devlink_dpipe_entry entry = {0};
225         struct mlxsw_sp *mlxsw_sp = priv;
226         unsigned int rif_count;
227         int i, j;
228         int err;
229
230         mlxsw_sp_erif_match_action_prepare(&match, &action);
231         err = mlxsw_sp_erif_entry_prepare(&entry, &match_value, &match,
232                                           &action_value, &action);
233         if (err)
234                 return err;
235
236         rif_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
237         rtnl_lock();
238         i = 0;
239 start_again:
240         err = devlink_dpipe_entry_ctx_prepare(dump_ctx);
241         if (err)
242                 return err;
243         j = 0;
244         for (; i < rif_count; i++) {
245                 if (!mlxsw_sp->rifs[i])
246                         continue;
247                 err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry,
248                                               mlxsw_sp->rifs[i],
249                                               counters_enabled);
250                 if (err)
251                         goto err_entry_get;
252                 err = devlink_dpipe_entry_ctx_append(dump_ctx, &entry);
253                 if (err) {
254                         if (err == -EMSGSIZE) {
255                                 if (!j)
256                                         goto err_entry_append;
257                                 break;
258                         }
259                         goto err_entry_append;
260                 }
261                 j++;
262         }
263
264         devlink_dpipe_entry_ctx_close(dump_ctx);
265         if (i != rif_count)
266                 goto start_again;
267         rtnl_unlock();
268
269         mlxsw_sp_erif_entry_clear(&entry);
270         return 0;
271 err_entry_append:
272 err_entry_get:
273         rtnl_unlock();
274         mlxsw_sp_erif_entry_clear(&entry);
275         return err;
276 }
277
278 static int mlxsw_sp_table_erif_counters_update(void *priv, bool enable)
279 {
280         struct mlxsw_sp *mlxsw_sp = priv;
281         int i;
282
283         rtnl_lock();
284         for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
285                 if (!mlxsw_sp->rifs[i])
286                         continue;
287                 if (enable)
288                         mlxsw_sp_rif_counter_alloc(mlxsw_sp,
289                                                    mlxsw_sp->rifs[i],
290                                                    MLXSW_SP_RIF_COUNTER_EGRESS);
291                 else
292                         mlxsw_sp_rif_counter_free(mlxsw_sp,
293                                                   mlxsw_sp->rifs[i],
294                                                   MLXSW_SP_RIF_COUNTER_EGRESS);
295         }
296         rtnl_unlock();
297         return 0;
298 }
299
300 static struct devlink_dpipe_table_ops mlxsw_sp_erif_ops = {
301         .matches_dump = mlxsw_sp_dpipe_table_erif_matches_dump,
302         .actions_dump = mlxsw_sp_dpipe_table_erif_actions_dump,
303         .entries_dump = mlxsw_sp_table_erif_entries_dump,
304         .counters_set_update = mlxsw_sp_table_erif_counters_update,
305 };
306
307 static int mlxsw_sp_dpipe_erif_table_init(struct mlxsw_sp *mlxsw_sp)
308 {
309         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
310         u64 table_size;
311
312         table_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
313         return devlink_dpipe_table_register(devlink,
314                                             MLXSW_SP_DPIPE_TABLE_NAME_ERIF,
315                                             &mlxsw_sp_erif_ops,
316                                             mlxsw_sp, table_size,
317                                             false);
318 }
319
320 static void mlxsw_sp_dpipe_erif_table_fini(struct mlxsw_sp *mlxsw_sp)
321 {
322         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
323
324         devlink_dpipe_table_unregister(devlink, MLXSW_SP_DPIPE_TABLE_NAME_ERIF);
325 }
326
327 int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
328 {
329         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
330         int err;
331
332         err = devlink_dpipe_headers_register(devlink,
333                                              &mlxsw_sp_dpipe_headers);
334         if (err)
335                 return err;
336         err = mlxsw_sp_dpipe_erif_table_init(mlxsw_sp);
337         if (err)
338                 goto err_erif_register;
339         return 0;
340
341 err_erif_register:
342         devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
343         return err;
344 }
345
346 void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
347 {
348         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
349
350         mlxsw_sp_dpipe_erif_table_fini(mlxsw_sp);
351         devlink_dpipe_headers_unregister(devlink);
352 }