net: sched: add qstats.qlen to qlen
[linux-2.6-block.git] / drivers / net / ethernet / netronome / nfp / abm / main.c
CommitLineData
c4c8f39a
JK
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
2/*
3 * Copyright (C) 2018 Netronome Systems, Inc.
4 *
5 * This software is dual licensed under the GNU General License Version 2,
6 * June 1991 as shown in the file COPYING in the top-level directory of this
7 * source tree or the BSD 2-Clause License provided below. You have the
8 * option to license this software under the complete terms of either license.
9 *
10 * The BSD 2-Clause License:
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * 1. Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer.
19 *
20 * 2. Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 */
34
d05d902e 35#include <linux/bitfield.h>
cc54dc28 36#include <linux/etherdevice.h>
d05d902e
JK
37#include <linux/lockdep.h>
38#include <linux/netdevice.h>
39#include <linux/rcupdate.h>
40#include <linux/slab.h>
8c8e6406
JK
41#include <net/pkt_cls.h>
42#include <net/pkt_sched.h>
cc54dc28
JK
43
44#include "../nfpcore/nfp.h"
c4c8f39a
JK
45#include "../nfpcore/nfp_cpp.h"
46#include "../nfpcore/nfp_nsp.h"
47#include "../nfp_app.h"
48#include "../nfp_main.h"
cc54dc28 49#include "../nfp_net.h"
d05d902e 50#include "../nfp_net_repr.h"
cc54dc28 51#include "../nfp_port.h"
c4c8f39a
JK
52#include "main.h"
53
d05d902e
JK
54static u32 nfp_abm_portid(enum nfp_repr_type rtype, unsigned int id)
55{
56 return FIELD_PREP(NFP_ABM_PORTID_TYPE, rtype) |
57 FIELD_PREP(NFP_ABM_PORTID_ID, id);
58}
59
8c8e6406
JK
60static void
61nfp_abm_red_destroy(struct net_device *netdev, struct nfp_abm_link *alink,
62 u32 handle)
63{
64 struct nfp_port *port = nfp_port_from_netdev(netdev);
65
66 if (handle != alink->qdiscs[0].handle)
67 return;
68
69 alink->qdiscs[0].handle = TC_H_UNSPEC;
70 port->tc_offload_cnt = 0;
71 nfp_abm_ctrl_set_all_q_lvls(alink, ~0);
72}
73
74static int
75nfp_abm_red_replace(struct net_device *netdev, struct nfp_abm_link *alink,
76 struct tc_red_qopt_offload *opt)
77{
78 struct nfp_port *port = nfp_port_from_netdev(netdev);
79 int err;
80
81 if (opt->set.min != opt->set.max || !opt->set.is_ecn) {
82 nfp_warn(alink->abm->app->cpp,
83 "RED offload failed - unsupported parameters\n");
84 err = -EINVAL;
85 goto err_destroy;
86 }
87 err = nfp_abm_ctrl_set_all_q_lvls(alink, opt->set.min);
88 if (err)
89 goto err_destroy;
90
91 alink->qdiscs[0].handle = opt->handle;
92 port->tc_offload_cnt = 1;
93
94 return 0;
95err_destroy:
96 if (alink->qdiscs[0].handle != TC_H_UNSPEC)
97 nfp_abm_red_destroy(netdev, alink, alink->qdiscs[0].handle);
98 return err;
99}
100
101static int
102nfp_abm_setup_tc_red(struct net_device *netdev, struct nfp_abm_link *alink,
103 struct tc_red_qopt_offload *opt)
104{
105 if (opt->parent != TC_H_ROOT)
106 return -EOPNOTSUPP;
107
108 switch (opt->command) {
109 case TC_RED_REPLACE:
110 return nfp_abm_red_replace(netdev, alink, opt);
111 case TC_RED_DESTROY:
112 nfp_abm_red_destroy(netdev, alink, opt->handle);
113 return 0;
114 default:
115 return -EOPNOTSUPP;
116 }
117}
118
119static int
120nfp_abm_setup_tc(struct nfp_app *app, struct net_device *netdev,
121 enum tc_setup_type type, void *type_data)
122{
123 struct nfp_repr *repr = netdev_priv(netdev);
124 struct nfp_port *port;
125
126 port = nfp_port_from_netdev(netdev);
127 if (!port || port->type != NFP_PORT_PF_PORT)
128 return -EOPNOTSUPP;
129
130 switch (type) {
131 case TC_SETUP_QDISC_RED:
132 return nfp_abm_setup_tc_red(netdev, repr->app_priv, type_data);
133 default:
134 return -EOPNOTSUPP;
135 }
136}
137
d05d902e
JK
138static struct net_device *nfp_abm_repr_get(struct nfp_app *app, u32 port_id)
139{
140 enum nfp_repr_type rtype;
141 struct nfp_reprs *reprs;
142 u8 port;
143
144 rtype = FIELD_GET(NFP_ABM_PORTID_TYPE, port_id);
145 port = FIELD_GET(NFP_ABM_PORTID_ID, port_id);
146
147 reprs = rcu_dereference(app->reprs[rtype]);
148 if (!reprs)
149 return NULL;
150
151 if (port >= reprs->num_reprs)
152 return NULL;
153
154 return rcu_dereference(reprs->reprs[port]);
155}
156
157static int
158nfp_abm_spawn_repr(struct nfp_app *app, struct nfp_abm_link *alink,
159 enum nfp_port_type ptype)
160{
161 struct net_device *netdev;
162 enum nfp_repr_type rtype;
163 struct nfp_reprs *reprs;
164 struct nfp_repr *repr;
165 struct nfp_port *port;
166 int err;
167
168 if (ptype == NFP_PORT_PHYS_PORT)
169 rtype = NFP_REPR_TYPE_PHYS_PORT;
170 else
171 rtype = NFP_REPR_TYPE_PF;
172
173 netdev = nfp_repr_alloc(app);
174 if (!netdev)
175 return -ENOMEM;
176 repr = netdev_priv(netdev);
177 repr->app_priv = alink;
178
179 port = nfp_port_alloc(app, ptype, netdev);
180 if (IS_ERR(port)) {
181 err = PTR_ERR(port);
182 goto err_free_repr;
183 }
184
185 if (ptype == NFP_PORT_PHYS_PORT) {
1f700367 186 port->eth_forced = true;
d05d902e
JK
187 err = nfp_port_init_phy_port(app->pf, app, port, alink->id);
188 if (err)
189 goto err_free_port;
190 } else {
191 port->pf_id = alink->abm->pf_id;
290f54db
JK
192 port->pf_split = app->pf->max_data_vnics > 1;
193 port->pf_split_id = alink->id;
d05d902e
JK
194 port->vnic = alink->vnic->dp.ctrl_bar;
195 }
196
197 SET_NETDEV_DEV(netdev, &alink->vnic->pdev->dev);
198 eth_hw_addr_random(netdev);
199
200 err = nfp_repr_init(app, netdev, nfp_abm_portid(rtype, alink->id),
201 port, alink->vnic->dp.netdev);
202 if (err)
203 goto err_free_port;
204
205 reprs = nfp_reprs_get_locked(app, rtype);
206 WARN(nfp_repr_get_locked(app, reprs, alink->id), "duplicate repr");
207 rcu_assign_pointer(reprs->reprs[alink->id], netdev);
208
209 nfp_info(app->cpp, "%s Port %d Representor(%s) created\n",
210 ptype == NFP_PORT_PF_PORT ? "PCIe" : "Phys",
211 alink->id, netdev->name);
212
213 return 0;
214
215err_free_port:
216 nfp_port_free(port);
217err_free_repr:
218 nfp_repr_free(netdev);
219 return err;
220}
221
222static void
223nfp_abm_kill_repr(struct nfp_app *app, struct nfp_abm_link *alink,
224 enum nfp_repr_type rtype)
225{
226 struct net_device *netdev;
227 struct nfp_reprs *reprs;
228
229 reprs = nfp_reprs_get_locked(app, rtype);
230 netdev = nfp_repr_get_locked(app, reprs, alink->id);
231 if (!netdev)
232 return;
233 rcu_assign_pointer(reprs->reprs[alink->id], NULL);
234 synchronize_rcu();
235 /* Cast to make sure nfp_repr_clean_and_free() takes a nfp_repr */
236 nfp_repr_clean_and_free((struct nfp_repr *)netdev_priv(netdev));
237}
238
239static void
240nfp_abm_kill_reprs(struct nfp_abm *abm, struct nfp_abm_link *alink)
241{
242 nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PF);
243 nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PHYS_PORT);
244}
245
246static void nfp_abm_kill_reprs_all(struct nfp_abm *abm)
247{
248 struct nfp_pf *pf = abm->app->pf;
249 struct nfp_net *nn;
250
251 list_for_each_entry(nn, &pf->vnics, vnic_list)
252 nfp_abm_kill_reprs(abm, (struct nfp_abm_link *)nn->app_priv);
253}
254
255static enum devlink_eswitch_mode nfp_abm_eswitch_mode_get(struct nfp_app *app)
256{
257 struct nfp_abm *abm = app->priv;
258
259 return abm->eswitch_mode;
260}
261
262static int nfp_abm_eswitch_set_legacy(struct nfp_abm *abm)
263{
264 nfp_abm_kill_reprs_all(abm);
055ee0d6 265 nfp_abm_ctrl_qm_disable(abm);
d05d902e
JK
266
267 abm->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
268 return 0;
269}
270
271static void nfp_abm_eswitch_clean_up(struct nfp_abm *abm)
272{
273 if (abm->eswitch_mode != DEVLINK_ESWITCH_MODE_LEGACY)
274 WARN_ON(nfp_abm_eswitch_set_legacy(abm));
275}
276
277static int nfp_abm_eswitch_set_switchdev(struct nfp_abm *abm)
278{
279 struct nfp_app *app = abm->app;
280 struct nfp_pf *pf = app->pf;
281 struct nfp_net *nn;
282 int err;
283
055ee0d6
JK
284 err = nfp_abm_ctrl_qm_enable(abm);
285 if (err)
286 return err;
287
d05d902e
JK
288 list_for_each_entry(nn, &pf->vnics, vnic_list) {
289 struct nfp_abm_link *alink = nn->app_priv;
290
291 err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PHYS_PORT);
292 if (err)
293 goto err_kill_all_reprs;
294
295 err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PF_PORT);
296 if (err)
297 goto err_kill_all_reprs;
298 }
299
300 abm->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
301 return 0;
302
303err_kill_all_reprs:
304 nfp_abm_kill_reprs_all(abm);
055ee0d6 305 nfp_abm_ctrl_qm_disable(abm);
d05d902e
JK
306 return err;
307}
308
309static int nfp_abm_eswitch_mode_set(struct nfp_app *app, u16 mode)
310{
311 struct nfp_abm *abm = app->priv;
312
313 if (abm->eswitch_mode == mode)
314 return 0;
315
316 switch (mode) {
317 case DEVLINK_ESWITCH_MODE_LEGACY:
318 return nfp_abm_eswitch_set_legacy(abm);
319 case DEVLINK_ESWITCH_MODE_SWITCHDEV:
320 return nfp_abm_eswitch_set_switchdev(abm);
321 default:
322 return -EINVAL;
323 }
324}
325
cc54dc28
JK
326static void
327nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn,
328 unsigned int id)
329{
330 struct nfp_eth_table_port *eth_port = &pf->eth_tbl->ports[id];
331 u8 mac_addr[ETH_ALEN];
332 const char *mac_str;
333 char name[32];
334
335 if (id > pf->eth_tbl->count) {
336 nfp_warn(pf->cpp, "No entry for persistent MAC address\n");
337 eth_hw_addr_random(nn->dp.netdev);
338 return;
339 }
340
341 snprintf(name, sizeof(name), "eth%u.mac.pf%u",
342 eth_port->eth_index, abm->pf_id);
343
344 mac_str = nfp_hwinfo_lookup(pf->hwinfo, name);
345 if (!mac_str) {
346 nfp_warn(pf->cpp, "Can't lookup persistent MAC address (%s)\n",
347 name);
348 eth_hw_addr_random(nn->dp.netdev);
349 return;
350 }
351
352 if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
353 &mac_addr[0], &mac_addr[1], &mac_addr[2],
354 &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) {
355 nfp_warn(pf->cpp, "Can't parse persistent MAC address (%s)\n",
356 mac_str);
357 eth_hw_addr_random(nn->dp.netdev);
358 return;
359 }
360
361 ether_addr_copy(nn->dp.netdev->dev_addr, mac_addr);
362 ether_addr_copy(nn->dp.netdev->perm_addr, mac_addr);
363}
364
365static int
366nfp_abm_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
367{
1f700367 368 struct nfp_eth_table_port *eth_port = &app->pf->eth_tbl->ports[id];
cc54dc28
JK
369 struct nfp_abm *abm = app->priv;
370 struct nfp_abm_link *alink;
1f700367 371 int err;
cc54dc28
JK
372
373 alink = kzalloc(sizeof(*alink), GFP_KERNEL);
374 if (!alink)
375 return -ENOMEM;
376 nn->app_priv = alink;
377 alink->abm = abm;
378 alink->vnic = nn;
379 alink->id = id;
380
1f700367
JK
381 /* This is a multi-host app, make sure MAC/PHY is up, but don't
382 * make the MAC/PHY state follow the state of any of the ports.
383 */
384 err = nfp_eth_set_configured(app->cpp, eth_port->index, true);
385 if (err < 0)
386 goto err_free_alink;
387
d05d902e 388 netif_keep_dst(nn->dp.netdev);
cc54dc28
JK
389
390 nfp_abm_vnic_set_mac(app->pf, abm, nn, id);
391 nfp_abm_ctrl_read_params(alink);
392
393 return 0;
1f700367
JK
394
395err_free_alink:
396 kfree(alink);
397 return err;
cc54dc28
JK
398}
399
400static void nfp_abm_vnic_free(struct nfp_app *app, struct nfp_net *nn)
401{
402 struct nfp_abm_link *alink = nn->app_priv;
403
d05d902e 404 nfp_abm_kill_reprs(alink->abm, alink);
cc54dc28
JK
405 kfree(alink);
406}
407
c4c8f39a
JK
408static int nfp_abm_init(struct nfp_app *app)
409{
410 struct nfp_pf *pf = app->pf;
d05d902e 411 struct nfp_reprs *reprs;
c4c8f39a 412 struct nfp_abm *abm;
cc54dc28 413 int err;
c4c8f39a
JK
414
415 if (!pf->eth_tbl) {
416 nfp_err(pf->cpp, "ABM NIC requires ETH table\n");
417 return -EINVAL;
418 }
419 if (pf->max_data_vnics != pf->eth_tbl->count) {
420 nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n",
421 pf->max_data_vnics, pf->eth_tbl->count);
422 return -EINVAL;
423 }
424 if (!pf->mac_stats_bar) {
425 nfp_warn(app->cpp, "ABM NIC requires mac_stats symbol\n");
426 return -EINVAL;
427 }
428
429 abm = kzalloc(sizeof(*abm), GFP_KERNEL);
430 if (!abm)
431 return -ENOMEM;
432 app->priv = abm;
433 abm->app = app;
434
cc54dc28
JK
435 err = nfp_abm_ctrl_find_addrs(abm);
436 if (err)
437 goto err_free_abm;
438
055ee0d6
JK
439 /* We start in legacy mode, make sure advanced queuing is disabled */
440 err = nfp_abm_ctrl_qm_disable(abm);
441 if (err)
442 goto err_free_abm;
443
d05d902e
JK
444 err = -ENOMEM;
445 reprs = nfp_reprs_alloc(pf->max_data_vnics);
446 if (!reprs)
447 goto err_free_abm;
448 RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PHYS_PORT], reprs);
449
450 reprs = nfp_reprs_alloc(pf->max_data_vnics);
451 if (!reprs)
452 goto err_free_phys;
453 RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PF], reprs);
454
c4c8f39a 455 return 0;
cc54dc28 456
d05d902e
JK
457err_free_phys:
458 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
cc54dc28
JK
459err_free_abm:
460 kfree(abm);
461 app->priv = NULL;
462 return err;
c4c8f39a
JK
463}
464
465static void nfp_abm_clean(struct nfp_app *app)
466{
467 struct nfp_abm *abm = app->priv;
468
d05d902e
JK
469 nfp_abm_eswitch_clean_up(abm);
470 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF);
471 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
c4c8f39a
JK
472 kfree(abm);
473 app->priv = NULL;
474}
475
476const struct nfp_app_type app_abm = {
477 .id = NFP_APP_ACTIVE_BUFFER_MGMT_NIC,
478 .name = "abm",
479
480 .init = nfp_abm_init,
481 .clean = nfp_abm_clean,
482
cc54dc28
JK
483 .vnic_alloc = nfp_abm_vnic_alloc,
484 .vnic_free = nfp_abm_vnic_free,
d05d902e 485
8c8e6406
JK
486 .setup_tc = nfp_abm_setup_tc,
487
d05d902e
JK
488 .eswitch_mode_get = nfp_abm_eswitch_mode_get,
489 .eswitch_mode_set = nfp_abm_eswitch_mode_set,
490
491 .repr_get = nfp_abm_repr_get,
c4c8f39a 492};