1
2
3
4#include <linux/bitfield.h>
5#include <linux/etherdevice.h>
6#include <linux/lockdep.h>
7#include <linux/netdevice.h>
8#include <linux/rcupdate.h>
9#include <linux/slab.h>
10#include <net/pkt_cls.h>
11#include <net/pkt_sched.h>
12#include <net/red.h>
13
14#include "../nfpcore/nfp.h"
15#include "../nfpcore/nfp_cpp.h"
16#include "../nfpcore/nfp_nsp.h"
17#include "../nfp_app.h"
18#include "../nfp_main.h"
19#include "../nfp_net.h"
20#include "../nfp_net_repr.h"
21#include "../nfp_port.h"
22#include "main.h"
23
24static u32 nfp_abm_portid(enum nfp_repr_type rtype, unsigned int id)
25{
26 return FIELD_PREP(NFP_ABM_PORTID_TYPE, rtype) |
27 FIELD_PREP(NFP_ABM_PORTID_ID, id);
28}
29
30static int nfp_abm_reset_stats(struct nfp_abm_link *alink)
31{
32 int err;
33
34 err = nfp_abm_ctrl_read_stats(alink, &alink->qdiscs[0].stats);
35 if (err)
36 return err;
37 alink->qdiscs[0].stats.backlog_pkts = 0;
38 alink->qdiscs[0].stats.backlog_bytes = 0;
39
40 err = nfp_abm_ctrl_read_xstats(alink, &alink->qdiscs[0].xstats);
41 if (err)
42 return err;
43
44 return 0;
45}
46
47static void
48nfp_abm_red_destroy(struct net_device *netdev, struct nfp_abm_link *alink,
49 u32 handle)
50{
51 struct nfp_port *port = nfp_port_from_netdev(netdev);
52
53 if (handle != alink->qdiscs[0].handle)
54 return;
55
56 alink->qdiscs[0].handle = TC_H_UNSPEC;
57 port->tc_offload_cnt = 0;
58 nfp_abm_ctrl_set_all_q_lvls(alink, ~0);
59}
60
61static int
62nfp_abm_red_replace(struct net_device *netdev, struct nfp_abm_link *alink,
63 struct tc_red_qopt_offload *opt)
64{
65 struct nfp_port *port = nfp_port_from_netdev(netdev);
66 int err;
67
68 if (opt->set.min != opt->set.max || !opt->set.is_ecn) {
69 nfp_warn(alink->abm->app->cpp,
70 "RED offload failed - unsupported parameters\n");
71 err = -EINVAL;
72 goto err_destroy;
73 }
74 err = nfp_abm_ctrl_set_all_q_lvls(alink, opt->set.min);
75 if (err)
76 goto err_destroy;
77
78
79 if (alink->qdiscs[0].handle != opt->handle) {
80 err = nfp_abm_reset_stats(alink);
81 if (err)
82 goto err_destroy;
83 }
84
85 alink->qdiscs[0].handle = opt->handle;
86 port->tc_offload_cnt = 1;
87
88 return 0;
89err_destroy:
90
91 if (alink->qdiscs[0].handle == opt->handle) {
92 opt->set.qstats->qlen -= alink->qdiscs[0].stats.backlog_pkts;
93 opt->set.qstats->backlog -=
94 alink->qdiscs[0].stats.backlog_bytes;
95 }
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 void
102nfp_abm_update_stats(struct nfp_alink_stats *new, struct nfp_alink_stats *old,
103 struct tc_qopt_offload_stats *stats)
104{
105 _bstats_update(stats->bstats, new->tx_bytes - old->tx_bytes,
106 new->tx_pkts - old->tx_pkts);
107 stats->qstats->qlen += new->backlog_pkts - old->backlog_pkts;
108 stats->qstats->backlog += new->backlog_bytes - old->backlog_bytes;
109 stats->qstats->overlimits += new->overlimits - old->overlimits;
110 stats->qstats->drops += new->drops - old->drops;
111}
112
113static int
114nfp_abm_red_stats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt)
115{
116 struct nfp_alink_stats *prev_stats;
117 struct nfp_alink_stats stats;
118 int err;
119
120 if (alink->qdiscs[0].handle != opt->handle)
121 return -EOPNOTSUPP;
122 prev_stats = &alink->qdiscs[0].stats;
123
124 err = nfp_abm_ctrl_read_stats(alink, &stats);
125 if (err)
126 return err;
127
128 nfp_abm_update_stats(&stats, prev_stats, &opt->stats);
129
130 *prev_stats = stats;
131
132 return 0;
133}
134
135static int
136nfp_abm_red_xstats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt)
137{
138 struct nfp_alink_xstats *prev_xstats;
139 struct nfp_alink_xstats xstats;
140 int err;
141
142 if (alink->qdiscs[0].handle != opt->handle)
143 return -EOPNOTSUPP;
144 prev_xstats = &alink->qdiscs[0].xstats;
145
146 err = nfp_abm_ctrl_read_xstats(alink, &xstats);
147 if (err)
148 return err;
149
150 opt->xstats->forced_mark += xstats.ecn_marked - prev_xstats->ecn_marked;
151 opt->xstats->pdrop += xstats.pdrop - prev_xstats->pdrop;
152
153 *prev_xstats = xstats;
154
155 return 0;
156}
157
158static int
159nfp_abm_setup_tc_red(struct net_device *netdev, struct nfp_abm_link *alink,
160 struct tc_red_qopt_offload *opt)
161{
162 if (opt->parent != TC_H_ROOT)
163 return -EOPNOTSUPP;
164
165 switch (opt->command) {
166 case TC_RED_REPLACE:
167 return nfp_abm_red_replace(netdev, alink, opt);
168 case TC_RED_DESTROY:
169 nfp_abm_red_destroy(netdev, alink, opt->handle);
170 return 0;
171 case TC_RED_STATS:
172 return nfp_abm_red_stats(alink, opt);
173 case TC_RED_XSTATS:
174 return nfp_abm_red_xstats(alink, opt);
175 default:
176 return -EOPNOTSUPP;
177 }
178}
179
180static int
181nfp_abm_setup_tc(struct nfp_app *app, struct net_device *netdev,
182 enum tc_setup_type type, void *type_data)
183{
184 struct nfp_repr *repr = netdev_priv(netdev);
185 struct nfp_port *port;
186
187 port = nfp_port_from_netdev(netdev);
188 if (!port || port->type != NFP_PORT_PF_PORT)
189 return -EOPNOTSUPP;
190
191 switch (type) {
192 case TC_SETUP_QDISC_RED:
193 return nfp_abm_setup_tc_red(netdev, repr->app_priv, type_data);
194 default:
195 return -EOPNOTSUPP;
196 }
197}
198
199static struct net_device *
200nfp_abm_repr_get(struct nfp_app *app, u32 port_id, bool *redir_egress)
201{
202 enum nfp_repr_type rtype;
203 struct nfp_reprs *reprs;
204 u8 port;
205
206 rtype = FIELD_GET(NFP_ABM_PORTID_TYPE, port_id);
207 port = FIELD_GET(NFP_ABM_PORTID_ID, port_id);
208
209 reprs = rcu_dereference(app->reprs[rtype]);
210 if (!reprs)
211 return NULL;
212
213 if (port >= reprs->num_reprs)
214 return NULL;
215
216 return rcu_dereference(reprs->reprs[port]);
217}
218
219static int
220nfp_abm_spawn_repr(struct nfp_app *app, struct nfp_abm_link *alink,
221 enum nfp_port_type ptype)
222{
223 struct net_device *netdev;
224 enum nfp_repr_type rtype;
225 struct nfp_reprs *reprs;
226 struct nfp_repr *repr;
227 struct nfp_port *port;
228 int err;
229
230 if (ptype == NFP_PORT_PHYS_PORT)
231 rtype = NFP_REPR_TYPE_PHYS_PORT;
232 else
233 rtype = NFP_REPR_TYPE_PF;
234
235 netdev = nfp_repr_alloc(app);
236 if (!netdev)
237 return -ENOMEM;
238 repr = netdev_priv(netdev);
239 repr->app_priv = alink;
240
241 port = nfp_port_alloc(app, ptype, netdev);
242 if (IS_ERR(port)) {
243 err = PTR_ERR(port);
244 goto err_free_repr;
245 }
246
247 if (ptype == NFP_PORT_PHYS_PORT) {
248 port->eth_forced = true;
249 err = nfp_port_init_phy_port(app->pf, app, port, alink->id);
250 if (err)
251 goto err_free_port;
252 } else {
253 port->pf_id = alink->abm->pf_id;
254 port->vnic = alink->vnic->dp.ctrl_bar;
255 }
256
257 SET_NETDEV_DEV(netdev, &alink->vnic->pdev->dev);
258 eth_hw_addr_random(netdev);
259
260 err = nfp_repr_init(app, netdev, nfp_abm_portid(rtype, alink->id),
261 port, alink->vnic->dp.netdev);
262 if (err)
263 goto err_free_port;
264
265 reprs = nfp_reprs_get_locked(app, rtype);
266 WARN(nfp_repr_get_locked(app, reprs, alink->id), "duplicate repr");
267 rtnl_lock();
268 rcu_assign_pointer(reprs->reprs[alink->id], netdev);
269 rtnl_unlock();
270
271 nfp_info(app->cpp, "%s Port %d Representor(%s) created\n",
272 ptype == NFP_PORT_PF_PORT ? "PCIe" : "Phys",
273 alink->id, netdev->name);
274
275 return 0;
276
277err_free_port:
278 nfp_port_free(port);
279err_free_repr:
280 nfp_repr_free(netdev);
281 return err;
282}
283
284static void
285nfp_abm_kill_repr(struct nfp_app *app, struct nfp_abm_link *alink,
286 enum nfp_repr_type rtype)
287{
288 struct net_device *netdev;
289 struct nfp_reprs *reprs;
290
291 reprs = nfp_reprs_get_locked(app, rtype);
292 netdev = nfp_repr_get_locked(app, reprs, alink->id);
293 if (!netdev)
294 return;
295 rtnl_lock();
296 rcu_assign_pointer(reprs->reprs[alink->id], NULL);
297 rtnl_unlock();
298 synchronize_rcu();
299
300 nfp_repr_clean_and_free((struct nfp_repr *)netdev_priv(netdev));
301}
302
303static void
304nfp_abm_kill_reprs(struct nfp_abm *abm, struct nfp_abm_link *alink)
305{
306 nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PF);
307 nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PHYS_PORT);
308}
309
310static void nfp_abm_kill_reprs_all(struct nfp_abm *abm)
311{
312 struct nfp_pf *pf = abm->app->pf;
313 struct nfp_net *nn;
314
315 list_for_each_entry(nn, &pf->vnics, vnic_list)
316 nfp_abm_kill_reprs(abm, (struct nfp_abm_link *)nn->app_priv);
317}
318
319static enum devlink_eswitch_mode nfp_abm_eswitch_mode_get(struct nfp_app *app)
320{
321 struct nfp_abm *abm = app->priv;
322
323 return abm->eswitch_mode;
324}
325
326static int nfp_abm_eswitch_set_legacy(struct nfp_abm *abm)
327{
328 nfp_abm_kill_reprs_all(abm);
329 nfp_abm_ctrl_qm_disable(abm);
330
331 abm->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
332 return 0;
333}
334
335static void nfp_abm_eswitch_clean_up(struct nfp_abm *abm)
336{
337 if (abm->eswitch_mode != DEVLINK_ESWITCH_MODE_LEGACY)
338 WARN_ON(nfp_abm_eswitch_set_legacy(abm));
339}
340
341static int nfp_abm_eswitch_set_switchdev(struct nfp_abm *abm)
342{
343 struct nfp_app *app = abm->app;
344 struct nfp_pf *pf = app->pf;
345 struct nfp_net *nn;
346 int err;
347
348 err = nfp_abm_ctrl_qm_enable(abm);
349 if (err)
350 return err;
351
352 list_for_each_entry(nn, &pf->vnics, vnic_list) {
353 struct nfp_abm_link *alink = nn->app_priv;
354
355 err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PHYS_PORT);
356 if (err)
357 goto err_kill_all_reprs;
358
359 err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PF_PORT);
360 if (err)
361 goto err_kill_all_reprs;
362 }
363
364 abm->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
365 return 0;
366
367err_kill_all_reprs:
368 nfp_abm_kill_reprs_all(abm);
369 nfp_abm_ctrl_qm_disable(abm);
370 return err;
371}
372
373static int nfp_abm_eswitch_mode_set(struct nfp_app *app, u16 mode)
374{
375 struct nfp_abm *abm = app->priv;
376
377 if (abm->eswitch_mode == mode)
378 return 0;
379
380 switch (mode) {
381 case DEVLINK_ESWITCH_MODE_LEGACY:
382 return nfp_abm_eswitch_set_legacy(abm);
383 case DEVLINK_ESWITCH_MODE_SWITCHDEV:
384 return nfp_abm_eswitch_set_switchdev(abm);
385 default:
386 return -EINVAL;
387 }
388}
389
390static void
391nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn,
392 unsigned int id)
393{
394 struct nfp_eth_table_port *eth_port = &pf->eth_tbl->ports[id];
395 u8 mac_addr[ETH_ALEN];
396 const char *mac_str;
397 char name[32];
398
399 if (id > pf->eth_tbl->count) {
400 nfp_warn(pf->cpp, "No entry for persistent MAC address\n");
401 eth_hw_addr_random(nn->dp.netdev);
402 return;
403 }
404
405 snprintf(name, sizeof(name), "eth%u.mac.pf%u",
406 eth_port->eth_index, abm->pf_id);
407
408 mac_str = nfp_hwinfo_lookup(pf->hwinfo, name);
409 if (!mac_str) {
410 nfp_warn(pf->cpp, "Can't lookup persistent MAC address (%s)\n",
411 name);
412 eth_hw_addr_random(nn->dp.netdev);
413 return;
414 }
415
416 if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
417 &mac_addr[0], &mac_addr[1], &mac_addr[2],
418 &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) {
419 nfp_warn(pf->cpp, "Can't parse persistent MAC address (%s)\n",
420 mac_str);
421 eth_hw_addr_random(nn->dp.netdev);
422 return;
423 }
424
425 ether_addr_copy(nn->dp.netdev->dev_addr, mac_addr);
426 ether_addr_copy(nn->dp.netdev->perm_addr, mac_addr);
427}
428
429static int
430nfp_abm_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
431{
432 struct nfp_eth_table_port *eth_port = &app->pf->eth_tbl->ports[id];
433 struct nfp_abm *abm = app->priv;
434 struct nfp_abm_link *alink;
435 int err;
436
437 alink = kzalloc(sizeof(*alink), GFP_KERNEL);
438 if (!alink)
439 return -ENOMEM;
440 nn->app_priv = alink;
441 alink->abm = abm;
442 alink->vnic = nn;
443 alink->id = id;
444
445
446
447
448 err = nfp_eth_set_configured(app->cpp, eth_port->index, true);
449 if (err < 0)
450 goto err_free_alink;
451
452 netif_keep_dst(nn->dp.netdev);
453
454 nfp_abm_vnic_set_mac(app->pf, abm, nn, id);
455 nfp_abm_ctrl_read_params(alink);
456
457 return 0;
458
459err_free_alink:
460 kfree(alink);
461 return err;
462}
463
464static void nfp_abm_vnic_free(struct nfp_app *app, struct nfp_net *nn)
465{
466 struct nfp_abm_link *alink = nn->app_priv;
467
468 nfp_abm_kill_reprs(alink->abm, alink);
469 kfree(alink);
470}
471
472static int nfp_abm_init(struct nfp_app *app)
473{
474 struct nfp_pf *pf = app->pf;
475 struct nfp_reprs *reprs;
476 struct nfp_abm *abm;
477 int err;
478
479 if (!pf->eth_tbl) {
480 nfp_err(pf->cpp, "ABM NIC requires ETH table\n");
481 return -EINVAL;
482 }
483 if (pf->max_data_vnics != pf->eth_tbl->count) {
484 nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n",
485 pf->max_data_vnics, pf->eth_tbl->count);
486 return -EINVAL;
487 }
488 if (!pf->mac_stats_bar) {
489 nfp_warn(app->cpp, "ABM NIC requires mac_stats symbol\n");
490 return -EINVAL;
491 }
492
493 abm = kzalloc(sizeof(*abm), GFP_KERNEL);
494 if (!abm)
495 return -ENOMEM;
496 app->priv = abm;
497 abm->app = app;
498
499 err = nfp_abm_ctrl_find_addrs(abm);
500 if (err)
501 goto err_free_abm;
502
503
504 err = nfp_abm_ctrl_qm_disable(abm);
505 if (err)
506 goto err_free_abm;
507
508 err = -ENOMEM;
509 reprs = nfp_reprs_alloc(pf->max_data_vnics);
510 if (!reprs)
511 goto err_free_abm;
512 RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PHYS_PORT], reprs);
513
514 reprs = nfp_reprs_alloc(pf->max_data_vnics);
515 if (!reprs)
516 goto err_free_phys;
517 RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PF], reprs);
518
519 return 0;
520
521err_free_phys:
522 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
523err_free_abm:
524 kfree(abm);
525 app->priv = NULL;
526 return err;
527}
528
529static void nfp_abm_clean(struct nfp_app *app)
530{
531 struct nfp_abm *abm = app->priv;
532
533 nfp_abm_eswitch_clean_up(abm);
534 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF);
535 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT);
536 kfree(abm);
537 app->priv = NULL;
538}
539
540const struct nfp_app_type app_abm = {
541 .id = NFP_APP_ACTIVE_BUFFER_MGMT_NIC,
542 .name = "abm",
543
544 .init = nfp_abm_init,
545 .clean = nfp_abm_clean,
546
547 .vnic_alloc = nfp_abm_vnic_alloc,
548 .vnic_free = nfp_abm_vnic_free,
549
550 .setup_tc = nfp_abm_setup_tc,
551
552 .eswitch_mode_get = nfp_abm_eswitch_mode_get,
553 .eswitch_mode_set = nfp_abm_eswitch_mode_set,
554
555 .dev_get = nfp_abm_repr_get,
556};
557