]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c
Merge remote-tracking branch 'regulator/fix/max77802' into regulator-linus
[mirror_ubuntu-artful-kernel.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_dpipe.c
CommitLineData
230ead01
AS
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"
2ba5999f 40#include "spectrum_router.h"
230ead01 41
d54b70fe
AS
42enum 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
48static 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
64enum mlxsw_sp_dpipe_header_id {
65 MLXSW_SP_DPIPE_HEADER_METADATA,
66};
67
68static 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
75static struct devlink_dpipe_header *mlxsw_dpipe_headers[] = {
76 &mlxsw_sp_dpipe_header_metadata,
77};
230ead01
AS
78
79static struct devlink_dpipe_headers mlxsw_sp_dpipe_headers = {
80 .headers = mlxsw_dpipe_headers,
81 .headers_count = ARRAY_SIZE(mlxsw_dpipe_headers),
82};
83
d54b70fe
AS
84static 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
105static 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
2ba5999f
AS
117static 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
137static void
138mlxsw_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
150static 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
175err_action_alloc:
176 kfree(match_value->value);
177 return -ENOMEM;
178}
179
180static 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;
6dd4aba3
AS
202 entry->index = mlxsw_sp_rif_index(rif);
203
2ba5999f
AS
204 if (!counters_enabled)
205 return 0;
206
2ba5999f
AS
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
217static int
218mlxsw_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;
239start_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;
271err_entry_append:
272err_entry_get:
273 rtnl_unlock();
274 mlxsw_sp_erif_entry_clear(&entry);
275 return err;
276}
277
278static 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
d54b70fe
AS
300static 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,
2ba5999f
AS
303 .entries_dump = mlxsw_sp_table_erif_entries_dump,
304 .counters_set_update = mlxsw_sp_table_erif_counters_update,
d54b70fe
AS
305};
306
307static 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
320static 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
230ead01
AS
327int mlxsw_sp_dpipe_init(struct mlxsw_sp *mlxsw_sp)
328{
d54b70fe
AS
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
341err_erif_register:
342 devlink_dpipe_headers_unregister(priv_to_devlink(mlxsw_sp->core));
343 return err;
230ead01
AS
344}
345
346void mlxsw_sp_dpipe_fini(struct mlxsw_sp *mlxsw_sp)
347{
d54b70fe
AS
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);
230ead01 352}