blob: ef77d7b0d99d0945c448e76203adc1fa17f13844 [file] [log] [blame]
Jakub Kicinskic4c8f392018-05-21 22:12:47 -07001// 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
Jakub Kicinskid05d9022018-05-21 22:12:52 -070035#include <linux/bitfield.h>
Jakub Kicinskicc54dc22018-05-21 22:12:48 -070036#include <linux/etherdevice.h>
Jakub Kicinskid05d9022018-05-21 22:12:52 -070037#include <linux/lockdep.h>
38#include <linux/netdevice.h>
39#include <linux/rcupdate.h>
40#include <linux/slab.h>
Jakub Kicinski8c8e6402018-05-25 21:53:29 -070041#include <net/pkt_cls.h>
42#include <net/pkt_sched.h>
Jakub Kicinskicb89cac2018-05-25 21:53:31 -070043#include <net/red.h>
Jakub Kicinskicc54dc22018-05-21 22:12:48 -070044
45#include "../nfpcore/nfp.h"
Jakub Kicinskic4c8f392018-05-21 22:12:47 -070046#include "../nfpcore/nfp_cpp.h"
47#include "../nfpcore/nfp_nsp.h"
48#include "../nfp_app.h"
49#include "../nfp_main.h"
Jakub Kicinskicc54dc22018-05-21 22:12:48 -070050#include "../nfp_net.h"
Jakub Kicinskid05d9022018-05-21 22:12:52 -070051#include "../nfp_net_repr.h"
Jakub Kicinskicc54dc22018-05-21 22:12:48 -070052#include "../nfp_port.h"
Jakub Kicinskic4c8f392018-05-21 22:12:47 -070053#include "main.h"
54
Jakub Kicinskid05d9022018-05-21 22:12:52 -070055static u32 nfp_abm_portid(enum nfp_repr_type rtype, unsigned int id)
56{
57 return FIELD_PREP(NFP_ABM_PORTID_TYPE, rtype) |
58 FIELD_PREP(NFP_ABM_PORTID_ID, id);
59}
60
Jakub Kicinskicb89cac2018-05-25 21:53:31 -070061static int nfp_abm_reset_stats(struct nfp_abm_link *alink)
62{
63 int err;
64
65 err = nfp_abm_ctrl_read_stats(alink, &alink->qdiscs[0].stats);
66 if (err)
67 return err;
68 alink->qdiscs[0].stats.backlog_pkts = 0;
69 alink->qdiscs[0].stats.backlog_bytes = 0;
70
71 err = nfp_abm_ctrl_read_xstats(alink, &alink->qdiscs[0].xstats);
72 if (err)
73 return err;
74
75 return 0;
76}
77
Jakub Kicinski8c8e6402018-05-25 21:53:29 -070078static void
79nfp_abm_red_destroy(struct net_device *netdev, struct nfp_abm_link *alink,
80 u32 handle)
81{
82 struct nfp_port *port = nfp_port_from_netdev(netdev);
83
84 if (handle != alink->qdiscs[0].handle)
85 return;
86
87 alink->qdiscs[0].handle = TC_H_UNSPEC;
88 port->tc_offload_cnt = 0;
89 nfp_abm_ctrl_set_all_q_lvls(alink, ~0);
90}
91
92static int
93nfp_abm_red_replace(struct net_device *netdev, struct nfp_abm_link *alink,
94 struct tc_red_qopt_offload *opt)
95{
96 struct nfp_port *port = nfp_port_from_netdev(netdev);
97 int err;
98
99 if (opt->set.min != opt->set.max || !opt->set.is_ecn) {
100 nfp_warn(alink->abm->app->cpp,
101 "RED offload failed - unsupported parameters\n");
102 err = -EINVAL;
103 goto err_destroy;
104 }
105 err = nfp_abm_ctrl_set_all_q_lvls(alink, opt->set.min);
106 if (err)
107 goto err_destroy;
108
Jakub Kicinskicb89cac2018-05-25 21:53:31 -0700109 /* Reset stats only on new qdisc */
110 if (alink->qdiscs[0].handle != opt->handle) {
111 err = nfp_abm_reset_stats(alink);
112 if (err)
113 goto err_destroy;
114 }
115
Jakub Kicinski8c8e6402018-05-25 21:53:29 -0700116 alink->qdiscs[0].handle = opt->handle;
117 port->tc_offload_cnt = 1;
118
119 return 0;
120err_destroy:
Jakub Kicinskicb89cac2018-05-25 21:53:31 -0700121 /* If the qdisc keeps on living, but we can't offload undo changes */
122 if (alink->qdiscs[0].handle == opt->handle) {
123 opt->set.qstats->qlen -= alink->qdiscs[0].stats.backlog_pkts;
124 opt->set.qstats->backlog -=
125 alink->qdiscs[0].stats.backlog_bytes;
126 }
Jakub Kicinski8c8e6402018-05-25 21:53:29 -0700127 if (alink->qdiscs[0].handle != TC_H_UNSPEC)
128 nfp_abm_red_destroy(netdev, alink, alink->qdiscs[0].handle);
129 return err;
130}
131
Jakub Kicinskicb89cac2018-05-25 21:53:31 -0700132static void
133nfp_abm_update_stats(struct nfp_alink_stats *new, struct nfp_alink_stats *old,
134 struct tc_qopt_offload_stats *stats)
135{
136 _bstats_update(stats->bstats, new->tx_bytes - old->tx_bytes,
137 new->tx_pkts - old->tx_pkts);
138 stats->qstats->qlen += new->backlog_pkts - old->backlog_pkts;
139 stats->qstats->backlog += new->backlog_bytes - old->backlog_bytes;
140 stats->qstats->overlimits += new->overlimits - old->overlimits;
141 stats->qstats->drops += new->drops - old->drops;
142}
143
144static int
145nfp_abm_red_stats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt)
146{
147 struct nfp_alink_stats *prev_stats;
148 struct nfp_alink_stats stats;
149 int err;
150
151 if (alink->qdiscs[0].handle != opt->handle)
152 return -EOPNOTSUPP;
153 prev_stats = &alink->qdiscs[0].stats;
154
155 err = nfp_abm_ctrl_read_stats(alink, &stats);
156 if (err)
157 return err;
158
159 nfp_abm_update_stats(&stats, prev_stats, &opt->stats);
160
161 *prev_stats = stats;
162
163 return 0;
164}
165
166static int
167nfp_abm_red_xstats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt)
168{
169 struct nfp_alink_xstats *prev_xstats;
170 struct nfp_alink_xstats xstats;
171 int err;
172
173 if (alink->qdiscs[0].handle != opt->handle)
174 return -EOPNOTSUPP;
175 prev_xstats = &alink->qdiscs[0].xstats;
176
177 err = nfp_abm_ctrl_read_xstats(alink, &xstats);
178 if (err)
179 return err;
180
181 opt->xstats->forced_mark += xstats.ecn_marked - prev_xstats->ecn_marked;
182 opt->xstats->pdrop += xstats.pdrop - prev_xstats->pdrop;
183
184 *prev_xstats = xstats;
185
186 return 0;
187}
188
Jakub Kicinski8c8e6402018-05-25 21:53:29 -0700189static int
190nfp_abm_setup_tc_red(struct net_device *netdev, struct nfp_abm_link *alink,
191 struct tc_red_qopt_offload *opt)
192{
193 if (opt->parent != TC_H_ROOT)
194 return -EOPNOTSUPP;
195
196 switch (opt->command) {
197 case TC_RED_REPLACE:
198 return nfp_abm_red_replace(netdev, alink, opt);
199 case TC_RED_DESTROY:
200 nfp_abm_red_destroy(netdev, alink, opt->handle);
201 return 0;
Jakub Kicinskicb89cac2018-05-25 21:53:31 -0700202 case TC_RED_STATS:
203 return nfp_abm_red_stats(alink, opt);
204 case TC_RED_XSTATS:
205 return nfp_abm_red_xstats(alink, opt);
Jakub Kicinski8c8e6402018-05-25 21:53:29 -0700206 default:
207 return -EOPNOTSUPP;
208 }
209}
210
211static int
212nfp_abm_setup_tc(struct nfp_app *app, struct net_device *netdev,
213 enum tc_setup_type type, void *type_data)
214{
215 struct nfp_repr *repr = netdev_priv(netdev);
216 struct nfp_port *port;
217
218 port = nfp_port_from_netdev(netdev);
219 if (!port || port->type != NFP_PORT_PF_PORT)
220 return -EOPNOTSUPP;
221
222 switch (type) {
223 case TC_SETUP_QDISC_RED:
224 return nfp_abm_setup_tc_red(netdev, repr->app_priv, type_data);
225 default:
226 return -EOPNOTSUPP;
227 }
228}
229
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700230static struct net_device *nfp_abm_repr_get(struct nfp_app *app, u32 port_id)
231{
232 enum nfp_repr_type rtype;
233 struct nfp_reprs *reprs;
234 u8 port;
235
236 rtype = FIELD_GET(NFP_ABM_PORTID_TYPE, port_id);
237 port = FIELD_GET(NFP_ABM_PORTID_ID, port_id);
238
239 reprs = rcu_dereference(app->reprs[rtype]);
240 if (!reprs)
241 return NULL;
242
243 if (port >= reprs->num_reprs)
244 return NULL;
245
246 return rcu_dereference(reprs->reprs[port]);
247}
248
249static int
250nfp_abm_spawn_repr(struct nfp_app *app, struct nfp_abm_link *alink,
251 enum nfp_port_type ptype)
252{
253 struct net_device *netdev;
254 enum nfp_repr_type rtype;
255 struct nfp_reprs *reprs;
256 struct nfp_repr *repr;
257 struct nfp_port *port;
Jakub Kicinski2ef3c252018-05-25 21:53:34 -0700258 unsigned int txqs;
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700259 int err;
260
Jakub Kicinski2ef3c252018-05-25 21:53:34 -0700261 if (ptype == NFP_PORT_PHYS_PORT) {
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700262 rtype = NFP_REPR_TYPE_PHYS_PORT;
Jakub Kicinski2ef3c252018-05-25 21:53:34 -0700263 txqs = 1;
264 } else {
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700265 rtype = NFP_REPR_TYPE_PF;
Jakub Kicinski2ef3c252018-05-25 21:53:34 -0700266 txqs = alink->vnic->max_rx_rings;
267 }
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700268
Jakub Kicinski2ef3c252018-05-25 21:53:34 -0700269 netdev = nfp_repr_alloc_mqs(app, txqs, 1);
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700270 if (!netdev)
271 return -ENOMEM;
272 repr = netdev_priv(netdev);
273 repr->app_priv = alink;
274
275 port = nfp_port_alloc(app, ptype, netdev);
276 if (IS_ERR(port)) {
277 err = PTR_ERR(port);
278 goto err_free_repr;
279 }
280
281 if (ptype == NFP_PORT_PHYS_PORT) {
Jakub Kicinski1f700362018-05-21 22:12:53 -0700282 port->eth_forced = true;
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700283 err = nfp_port_init_phy_port(app->pf, app, port, alink->id);
284 if (err)
285 goto err_free_port;
286 } else {
287 port->pf_id = alink->abm->pf_id;
Jakub Kicinski290f54d2018-05-21 22:12:54 -0700288 port->pf_split = app->pf->max_data_vnics > 1;
289 port->pf_split_id = alink->id;
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700290 port->vnic = alink->vnic->dp.ctrl_bar;
291 }
292
293 SET_NETDEV_DEV(netdev, &alink->vnic->pdev->dev);
294 eth_hw_addr_random(netdev);
295
296 err = nfp_repr_init(app, netdev, nfp_abm_portid(rtype, alink->id),
297 port, alink->vnic->dp.netdev);
298 if (err)
299 goto err_free_port;
300
301 reprs = nfp_reprs_get_locked(app, rtype);
302 WARN(nfp_repr_get_locked(app, reprs, alink->id), "duplicate repr");
303 rcu_assign_pointer(reprs->reprs[alink->id], netdev);
304
305 nfp_info(app->cpp, "%s Port %d Representor(%s) created\n",
306 ptype == NFP_PORT_PF_PORT ? "PCIe" : "Phys",
307 alink->id, netdev->name);
308
309 return 0;
310
311err_free_port:
312 nfp_port_free(port);
313err_free_repr:
314 nfp_repr_free(netdev);
315 return err;
316}
317
318static void
319nfp_abm_kill_repr(struct nfp_app *app, struct nfp_abm_link *alink,
320 enum nfp_repr_type rtype)
321{
322 struct net_device *netdev;
323 struct nfp_reprs *reprs;
324
325 reprs = nfp_reprs_get_locked(app, rtype);
326 netdev = nfp_repr_get_locked(app, reprs, alink->id);
327 if (!netdev)
328 return;
329 rcu_assign_pointer(reprs->reprs[alink->id], NULL);
330 synchronize_rcu();
331 /* Cast to make sure nfp_repr_clean_and_free() takes a nfp_repr */
332 nfp_repr_clean_and_free((struct nfp_repr *)netdev_priv(netdev));
333}
334
335static void
336nfp_abm_kill_reprs(struct nfp_abm *abm, struct nfp_abm_link *alink)
337{
338 nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PF);
339 nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PHYS_PORT);
340}
341
342static void nfp_abm_kill_reprs_all(struct nfp_abm *abm)
343{
344 struct nfp_pf *pf = abm->app->pf;
345 struct nfp_net *nn;
346
347 list_for_each_entry(nn, &pf->vnics, vnic_list)
348 nfp_abm_kill_reprs(abm, (struct nfp_abm_link *)nn->app_priv);
349}
350
351static enum devlink_eswitch_mode nfp_abm_eswitch_mode_get(struct nfp_app *app)
352{
353 struct nfp_abm *abm = app->priv;
354
355 return abm->eswitch_mode;
356}
357
358static int nfp_abm_eswitch_set_legacy(struct nfp_abm *abm)
359{
360 nfp_abm_kill_reprs_all(abm);
Jakub Kicinski055ee0d2018-05-25 21:53:27 -0700361 nfp_abm_ctrl_qm_disable(abm);
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700362
363 abm->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
364 return 0;
365}
366
367static void nfp_abm_eswitch_clean_up(struct nfp_abm *abm)
368{
369 if (abm->eswitch_mode != DEVLINK_ESWITCH_MODE_LEGACY)
370 WARN_ON(nfp_abm_eswitch_set_legacy(abm));
371}
372
373static int nfp_abm_eswitch_set_switchdev(struct nfp_abm *abm)
374{
375 struct nfp_app *app = abm->app;
376 struct nfp_pf *pf = app->pf;
377 struct nfp_net *nn;
378 int err;
379
Jakub Kicinski055ee0d2018-05-25 21:53:27 -0700380 err = nfp_abm_ctrl_qm_enable(abm);
381 if (err)
382 return err;
383
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700384 list_for_each_entry(nn, &pf->vnics, vnic_list) {
385 struct nfp_abm_link *alink = nn->app_priv;
386
387 err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PHYS_PORT);
388 if (err)
389 goto err_kill_all_reprs;
390
391 err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PF_PORT);
392 if (err)
393 goto err_kill_all_reprs;
394 }
395
396 abm->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
397 return 0;
398
399err_kill_all_reprs:
400 nfp_abm_kill_reprs_all(abm);
Jakub Kicinski055ee0d2018-05-25 21:53:27 -0700401 nfp_abm_ctrl_qm_disable(abm);
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700402 return err;
403}
404
405static int nfp_abm_eswitch_mode_set(struct nfp_app *app, u16 mode)
406{
407 struct nfp_abm *abm = app->priv;
408
409 if (abm->eswitch_mode == mode)
410 return 0;
411
412 switch (mode) {
413 case DEVLINK_ESWITCH_MODE_LEGACY:
414 return nfp_abm_eswitch_set_legacy(abm);
415 case DEVLINK_ESWITCH_MODE_SWITCHDEV:
416 return nfp_abm_eswitch_set_switchdev(abm);
417 default:
418 return -EINVAL;
419 }
420}
421
Jakub Kicinskicc54dc22018-05-21 22:12:48 -0700422static void
423nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn,
424 unsigned int id)
425{
426 struct nfp_eth_table_port *eth_port = &pf->eth_tbl->ports[id];
427 u8 mac_addr[ETH_ALEN];
428 const char *mac_str;
429 char name[32];
430
431 if (id > pf->eth_tbl->count) {
432 nfp_warn(pf->cpp, "No entry for persistent MAC address\n");
433 eth_hw_addr_random(nn->dp.netdev);
434 return;
435 }
436
437 snprintf(name, sizeof(name), "eth%u.mac.pf%u",
438 eth_port->eth_index, abm->pf_id);
439
440 mac_str = nfp_hwinfo_lookup(pf->hwinfo, name);
441 if (!mac_str) {
442 nfp_warn(pf->cpp, "Can't lookup persistent MAC address (%s)\n",
443 name);
444 eth_hw_addr_random(nn->dp.netdev);
445 return;
446 }
447
448 if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
449 &mac_addr[0], &mac_addr[1], &mac_addr[2],
450 &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) {
451 nfp_warn(pf->cpp, "Can't parse persistent MAC address (%s)\n",
452 mac_str);
453 eth_hw_addr_random(nn->dp.netdev);
454 return;
455 }
456
457 ether_addr_copy(nn->dp.netdev->dev_addr, mac_addr);
458 ether_addr_copy(nn->dp.netdev->perm_addr, mac_addr);
459}
460
461static int
462nfp_abm_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
463{
Jakub Kicinski1f700362018-05-21 22:12:53 -0700464 struct nfp_eth_table_port *eth_port = &app->pf->eth_tbl->ports[id];
Jakub Kicinskicc54dc22018-05-21 22:12:48 -0700465 struct nfp_abm *abm = app->priv;
466 struct nfp_abm_link *alink;
Jakub Kicinski1f700362018-05-21 22:12:53 -0700467 int err;
Jakub Kicinskicc54dc22018-05-21 22:12:48 -0700468
469 alink = kzalloc(sizeof(*alink), GFP_KERNEL);
470 if (!alink)
471 return -ENOMEM;
472 nn->app_priv = alink;
473 alink->abm = abm;
474 alink->vnic = nn;
475 alink->id = id;
476
Jakub Kicinski1f700362018-05-21 22:12:53 -0700477 /* This is a multi-host app, make sure MAC/PHY is up, but don't
478 * make the MAC/PHY state follow the state of any of the ports.
479 */
480 err = nfp_eth_set_configured(app->cpp, eth_port->index, true);
481 if (err < 0)
482 goto err_free_alink;
483
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700484 netif_keep_dst(nn->dp.netdev);
Jakub Kicinskicc54dc22018-05-21 22:12:48 -0700485
486 nfp_abm_vnic_set_mac(app->pf, abm, nn, id);
487 nfp_abm_ctrl_read_params(alink);
488
489 return 0;
Jakub Kicinski1f700362018-05-21 22:12:53 -0700490
491err_free_alink:
492 kfree(alink);
493 return err;
Jakub Kicinskicc54dc22018-05-21 22:12:48 -0700494}
495
496static void nfp_abm_vnic_free(struct nfp_app *app, struct nfp_net *nn)
497{
498 struct nfp_abm_link *alink = nn->app_priv;
499
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700500 nfp_abm_kill_reprs(alink->abm, alink);
Jakub Kicinskicc54dc22018-05-21 22:12:48 -0700501 kfree(alink);
502}
503
Jakub Kicinski0a8b7012018-05-25 21:53:33 -0700504static u64 *
505nfp_abm_port_get_stats(struct nfp_app *app, struct nfp_port *port, u64 *data)
506{
507 struct nfp_repr *repr = netdev_priv(port->netdev);
508 struct nfp_abm_link *alink;
509 unsigned int i;
510
511 if (port->type != NFP_PORT_PF_PORT)
512 return data;
513 alink = repr->app_priv;
514 for (i = 0; i < alink->vnic->dp.num_r_vecs; i++) {
515 *data++ = nfp_abm_ctrl_stat_non_sto(alink, i);
516 *data++ = nfp_abm_ctrl_stat_sto(alink, i);
517 }
518 return data;
519}
520
521static int
522nfp_abm_port_get_stats_count(struct nfp_app *app, struct nfp_port *port)
523{
524 struct nfp_repr *repr = netdev_priv(port->netdev);
525 struct nfp_abm_link *alink;
526
527 if (port->type != NFP_PORT_PF_PORT)
528 return 0;
529 alink = repr->app_priv;
530 return alink->vnic->dp.num_r_vecs * 2;
531}
532
533static u8 *
534nfp_abm_port_get_stats_strings(struct nfp_app *app, struct nfp_port *port,
535 u8 *data)
536{
537 struct nfp_repr *repr = netdev_priv(port->netdev);
538 struct nfp_abm_link *alink;
539 unsigned int i;
540
541 if (port->type != NFP_PORT_PF_PORT)
542 return data;
543 alink = repr->app_priv;
544 for (i = 0; i < alink->vnic->dp.num_r_vecs; i++) {
545 data = nfp_pr_et(data, "q%u_no_wait", i);
546 data = nfp_pr_et(data, "q%u_delayed", i);
547 }
548 return data;
549}
550
Jakub Kicinskic4c8f392018-05-21 22:12:47 -0700551static int nfp_abm_init(struct nfp_app *app)
552{
553 struct nfp_pf *pf = app->pf;
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700554 struct nfp_reprs *reprs;
Jakub Kicinskic4c8f392018-05-21 22:12:47 -0700555 struct nfp_abm *abm;
Jakub Kicinskicc54dc22018-05-21 22:12:48 -0700556 int err;
Jakub Kicinskic4c8f392018-05-21 22:12:47 -0700557
558 if (!pf->eth_tbl) {
559 nfp_err(pf->cpp, "ABM NIC requires ETH table\n");
560 return -EINVAL;
561 }
562 if (pf->max_data_vnics != pf->eth_tbl->count) {
563 nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n",
564 pf->max_data_vnics, pf->eth_tbl->count);
565 return -EINVAL;
566 }
567 if (!pf->mac_stats_bar) {
568 nfp_warn(app->cpp, "ABM NIC requires mac_stats symbol\n");
569 return -EINVAL;
570 }
571
572 abm = kzalloc(sizeof(*abm), GFP_KERNEL);
573 if (!abm)
574 return -ENOMEM;
575 app->priv = abm;
576 abm->app = app;
577
Jakub Kicinskicc54dc22018-05-21 22:12:48 -0700578 err = nfp_abm_ctrl_find_addrs(abm);
579 if (err)
580 goto err_free_abm;
581
Jakub Kicinski055ee0d2018-05-25 21:53:27 -0700582 /* We start in legacy mode, make sure advanced queuing is disabled */
583 err = nfp_abm_ctrl_qm_disable(abm);
584 if (err)
585 goto err_free_abm;
586
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700587 err = -ENOMEM;
588 reprs = nfp_reprs_alloc(pf->max_data_vnics);
589 if (!reprs)
590 goto err_free_abm;
591 RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PHYS_PORT], reprs);
592
593 reprs = nfp_reprs_alloc(pf->max_data_vnics);
594 if (!reprs)
595 goto err_free_phys;
596 RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PF], reprs);
597
Jakub Kicinskic4c8f392018-05-21 22:12:47 -0700598 return 0;
Jakub Kicinskicc54dc22018-05-21 22:12:48 -0700599
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700600err_free_phys:
601 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
Jakub Kicinskicc54dc22018-05-21 22:12:48 -0700602err_free_abm:
603 kfree(abm);
604 app->priv = NULL;
605 return err;
Jakub Kicinskic4c8f392018-05-21 22:12:47 -0700606}
607
608static void nfp_abm_clean(struct nfp_app *app)
609{
610 struct nfp_abm *abm = app->priv;
611
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700612 nfp_abm_eswitch_clean_up(abm);
613 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF);
614 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
Jakub Kicinskic4c8f392018-05-21 22:12:47 -0700615 kfree(abm);
616 app->priv = NULL;
617}
618
619const struct nfp_app_type app_abm = {
620 .id = NFP_APP_ACTIVE_BUFFER_MGMT_NIC,
621 .name = "abm",
622
623 .init = nfp_abm_init,
624 .clean = nfp_abm_clean,
625
Jakub Kicinskicc54dc22018-05-21 22:12:48 -0700626 .vnic_alloc = nfp_abm_vnic_alloc,
627 .vnic_free = nfp_abm_vnic_free,
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700628
Jakub Kicinski0a8b7012018-05-25 21:53:33 -0700629 .port_get_stats = nfp_abm_port_get_stats,
630 .port_get_stats_count = nfp_abm_port_get_stats_count,
631 .port_get_stats_strings = nfp_abm_port_get_stats_strings,
632
Jakub Kicinski8c8e6402018-05-25 21:53:29 -0700633 .setup_tc = nfp_abm_setup_tc,
634
Jakub Kicinskid05d9022018-05-21 22:12:52 -0700635 .eswitch_mode_get = nfp_abm_eswitch_mode_get,
636 .eswitch_mode_set = nfp_abm_eswitch_mode_set,
637
638 .repr_get = nfp_abm_repr_get,
Jakub Kicinskic4c8f392018-05-21 22:12:47 -0700639};