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 35 #include <linux/bitfield.h> 36 #include <linux/etherdevice.h> 37 #include <linux/lockdep.h> 38 #include <linux/netdevice.h> 39 #include <linux/rcupdate.h> 40 #include <linux/slab.h> 41 #include <net/pkt_cls.h> 42 #include <net/pkt_sched.h> 43 #include <net/red.h> 44 45 #include "../nfpcore/nfp.h" 46 #include "../nfpcore/nfp_cpp.h" 47 #include "../nfpcore/nfp_nsp.h" 48 #include "../nfp_app.h" 49 #include "../nfp_main.h" 50 #include "../nfp_net.h" 51 #include "../nfp_net_repr.h" 52 #include "../nfp_port.h" 53 #include "main.h" 54 55 static 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 61 static int 62 __nfp_abm_reset_root(struct net_device *netdev, struct nfp_abm_link *alink, 63 u32 handle, unsigned int qs, u32 init_val) 64 { 65 struct nfp_port *port = nfp_port_from_netdev(netdev); 66 int ret; 67 68 ret = nfp_abm_ctrl_set_all_q_lvls(alink, init_val); 69 memset(alink->qdiscs, 0, sizeof(*alink->qdiscs) * alink->num_qdiscs); 70 71 alink->parent = handle; 72 alink->num_qdiscs = qs; 73 port->tc_offload_cnt = qs; 74 75 return ret; 76 } 77 78 static void 79 nfp_abm_reset_root(struct net_device *netdev, struct nfp_abm_link *alink, 80 u32 handle, unsigned int qs) 81 { 82 __nfp_abm_reset_root(netdev, alink, handle, qs, ~0); 83 } 84 85 static int 86 nfp_abm_red_find(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt) 87 { 88 unsigned int i = TC_H_MIN(opt->parent) - 1; 89 90 if (opt->parent == TC_H_ROOT) 91 i = 0; 92 else if (TC_H_MAJ(alink->parent) == TC_H_MAJ(opt->parent)) 93 i = TC_H_MIN(opt->parent) - 1; 94 else 95 return -EOPNOTSUPP; 96 97 if (i >= alink->num_qdiscs || opt->handle != alink->qdiscs[i].handle) 98 return -EOPNOTSUPP; 99 100 return i; 101 } 102 103 static void 104 nfp_abm_red_destroy(struct net_device *netdev, struct nfp_abm_link *alink, 105 u32 handle) 106 { 107 unsigned int i; 108 109 for (i = 0; i < alink->num_qdiscs; i++) 110 if (handle == alink->qdiscs[i].handle) 111 break; 112 if (i == alink->num_qdiscs) 113 return; 114 115 if (alink->parent == TC_H_ROOT) { 116 nfp_abm_reset_root(netdev, alink, TC_H_ROOT, 0); 117 } else { 118 nfp_abm_ctrl_set_q_lvl(alink, i, ~0); 119 memset(&alink->qdiscs[i], 0, sizeof(*alink->qdiscs)); 120 } 121 } 122 123 static int 124 nfp_abm_red_replace(struct net_device *netdev, struct nfp_abm_link *alink, 125 struct tc_red_qopt_offload *opt) 126 { 127 bool existing; 128 int i, err; 129 130 i = nfp_abm_red_find(alink, opt); 131 existing = i >= 0; 132 133 if (opt->set.min != opt->set.max || !opt->set.is_ecn) { 134 nfp_warn(alink->abm->app->cpp, 135 "RED offload failed - unsupported parameters\n"); 136 err = -EINVAL; 137 goto err_destroy; 138 } 139 140 if (existing) { 141 if (alink->parent == TC_H_ROOT) 142 err = nfp_abm_ctrl_set_all_q_lvls(alink, opt->set.min); 143 else 144 err = nfp_abm_ctrl_set_q_lvl(alink, i, opt->set.min); 145 if (err) 146 goto err_destroy; 147 return 0; 148 } 149 150 if (opt->parent == TC_H_ROOT) { 151 i = 0; 152 err = __nfp_abm_reset_root(netdev, alink, TC_H_ROOT, 1, 153 opt->set.min); 154 } else if (TC_H_MAJ(alink->parent) == TC_H_MAJ(opt->parent)) { 155 i = TC_H_MIN(opt->parent) - 1; 156 err = nfp_abm_ctrl_set_q_lvl(alink, i, opt->set.min); 157 } else { 158 return -EINVAL; 159 } 160 /* Set the handle to try full clean up, in case IO failed */ 161 alink->qdiscs[i].handle = opt->handle; 162 if (err) 163 goto err_destroy; 164 165 if (opt->parent == TC_H_ROOT) 166 err = nfp_abm_ctrl_read_stats(alink, &alink->qdiscs[i].stats); 167 else 168 err = nfp_abm_ctrl_read_q_stats(alink, i, 169 &alink->qdiscs[i].stats); 170 if (err) 171 goto err_destroy; 172 173 if (opt->parent == TC_H_ROOT) 174 err = nfp_abm_ctrl_read_xstats(alink, 175 &alink->qdiscs[i].xstats); 176 else 177 err = nfp_abm_ctrl_read_q_xstats(alink, i, 178 &alink->qdiscs[i].xstats); 179 if (err) 180 goto err_destroy; 181 182 alink->qdiscs[i].stats.backlog_pkts = 0; 183 alink->qdiscs[i].stats.backlog_bytes = 0; 184 185 return 0; 186 err_destroy: 187 /* If the qdisc keeps on living, but we can't offload undo changes */ 188 if (existing) { 189 opt->set.qstats->qlen -= alink->qdiscs[i].stats.backlog_pkts; 190 opt->set.qstats->backlog -= 191 alink->qdiscs[i].stats.backlog_bytes; 192 } 193 nfp_abm_red_destroy(netdev, alink, opt->handle); 194 195 return err; 196 } 197 198 static void 199 nfp_abm_update_stats(struct nfp_alink_stats *new, struct nfp_alink_stats *old, 200 struct tc_qopt_offload_stats *stats) 201 { 202 _bstats_update(stats->bstats, new->tx_bytes - old->tx_bytes, 203 new->tx_pkts - old->tx_pkts); 204 stats->qstats->qlen += new->backlog_pkts - old->backlog_pkts; 205 stats->qstats->backlog += new->backlog_bytes - old->backlog_bytes; 206 stats->qstats->overlimits += new->overlimits - old->overlimits; 207 stats->qstats->drops += new->drops - old->drops; 208 } 209 210 static int 211 nfp_abm_red_stats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt) 212 { 213 struct nfp_alink_stats *prev_stats; 214 struct nfp_alink_stats stats; 215 int i, err; 216 217 i = nfp_abm_red_find(alink, opt); 218 if (i < 0) 219 return i; 220 prev_stats = &alink->qdiscs[i].stats; 221 222 if (alink->parent == TC_H_ROOT) 223 err = nfp_abm_ctrl_read_stats(alink, &stats); 224 else 225 err = nfp_abm_ctrl_read_q_stats(alink, i, &stats); 226 if (err) 227 return err; 228 229 nfp_abm_update_stats(&stats, prev_stats, &opt->stats); 230 231 *prev_stats = stats; 232 233 return 0; 234 } 235 236 static int 237 nfp_abm_red_xstats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt) 238 { 239 struct nfp_alink_xstats *prev_xstats; 240 struct nfp_alink_xstats xstats; 241 int i, err; 242 243 i = nfp_abm_red_find(alink, opt); 244 if (i < 0) 245 return i; 246 prev_xstats = &alink->qdiscs[i].xstats; 247 248 if (alink->parent == TC_H_ROOT) 249 err = nfp_abm_ctrl_read_xstats(alink, &xstats); 250 else 251 err = nfp_abm_ctrl_read_q_xstats(alink, i, &xstats); 252 if (err) 253 return err; 254 255 opt->xstats->forced_mark += xstats.ecn_marked - prev_xstats->ecn_marked; 256 opt->xstats->pdrop += xstats.pdrop - prev_xstats->pdrop; 257 258 *prev_xstats = xstats; 259 260 return 0; 261 } 262 263 static int 264 nfp_abm_setup_tc_red(struct net_device *netdev, struct nfp_abm_link *alink, 265 struct tc_red_qopt_offload *opt) 266 { 267 switch (opt->command) { 268 case TC_RED_REPLACE: 269 return nfp_abm_red_replace(netdev, alink, opt); 270 case TC_RED_DESTROY: 271 nfp_abm_red_destroy(netdev, alink, opt->handle); 272 return 0; 273 case TC_RED_STATS: 274 return nfp_abm_red_stats(alink, opt); 275 case TC_RED_XSTATS: 276 return nfp_abm_red_xstats(alink, opt); 277 default: 278 return -EOPNOTSUPP; 279 } 280 } 281 282 static int 283 nfp_abm_mq_stats(struct nfp_abm_link *alink, struct tc_mq_qopt_offload *opt) 284 { 285 struct nfp_alink_stats stats; 286 unsigned int i; 287 int err; 288 289 for (i = 0; i < alink->num_qdiscs; i++) { 290 if (alink->qdiscs[i].handle == TC_H_UNSPEC) 291 continue; 292 293 err = nfp_abm_ctrl_read_q_stats(alink, i, &stats); 294 if (err) 295 return err; 296 297 nfp_abm_update_stats(&stats, &alink->qdiscs[i].stats, 298 &opt->stats); 299 } 300 301 return 0; 302 } 303 304 static int 305 nfp_abm_setup_tc_mq(struct net_device *netdev, struct nfp_abm_link *alink, 306 struct tc_mq_qopt_offload *opt) 307 { 308 switch (opt->command) { 309 case TC_MQ_CREATE: 310 nfp_abm_reset_root(netdev, alink, opt->handle, 311 alink->total_queues); 312 return 0; 313 case TC_MQ_DESTROY: 314 if (opt->handle == alink->parent) 315 nfp_abm_reset_root(netdev, alink, TC_H_ROOT, 0); 316 return 0; 317 case TC_MQ_STATS: 318 return nfp_abm_mq_stats(alink, opt); 319 default: 320 return -EOPNOTSUPP; 321 } 322 } 323 324 static int 325 nfp_abm_setup_tc(struct nfp_app *app, struct net_device *netdev, 326 enum tc_setup_type type, void *type_data) 327 { 328 struct nfp_repr *repr = netdev_priv(netdev); 329 struct nfp_port *port; 330 331 port = nfp_port_from_netdev(netdev); 332 if (!port || port->type != NFP_PORT_PF_PORT) 333 return -EOPNOTSUPP; 334 335 switch (type) { 336 case TC_SETUP_QDISC_MQ: 337 return nfp_abm_setup_tc_mq(netdev, repr->app_priv, type_data); 338 case TC_SETUP_QDISC_RED: 339 return nfp_abm_setup_tc_red(netdev, repr->app_priv, type_data); 340 default: 341 return -EOPNOTSUPP; 342 } 343 } 344 345 static struct net_device *nfp_abm_repr_get(struct nfp_app *app, u32 port_id) 346 { 347 enum nfp_repr_type rtype; 348 struct nfp_reprs *reprs; 349 u8 port; 350 351 rtype = FIELD_GET(NFP_ABM_PORTID_TYPE, port_id); 352 port = FIELD_GET(NFP_ABM_PORTID_ID, port_id); 353 354 reprs = rcu_dereference(app->reprs[rtype]); 355 if (!reprs) 356 return NULL; 357 358 if (port >= reprs->num_reprs) 359 return NULL; 360 361 return rcu_dereference(reprs->reprs[port]); 362 } 363 364 static int 365 nfp_abm_spawn_repr(struct nfp_app *app, struct nfp_abm_link *alink, 366 enum nfp_port_type ptype) 367 { 368 struct net_device *netdev; 369 enum nfp_repr_type rtype; 370 struct nfp_reprs *reprs; 371 struct nfp_repr *repr; 372 struct nfp_port *port; 373 unsigned int txqs; 374 int err; 375 376 if (ptype == NFP_PORT_PHYS_PORT) { 377 rtype = NFP_REPR_TYPE_PHYS_PORT; 378 txqs = 1; 379 } else { 380 rtype = NFP_REPR_TYPE_PF; 381 txqs = alink->vnic->max_rx_rings; 382 } 383 384 netdev = nfp_repr_alloc_mqs(app, txqs, 1); 385 if (!netdev) 386 return -ENOMEM; 387 repr = netdev_priv(netdev); 388 repr->app_priv = alink; 389 390 port = nfp_port_alloc(app, ptype, netdev); 391 if (IS_ERR(port)) { 392 err = PTR_ERR(port); 393 goto err_free_repr; 394 } 395 396 if (ptype == NFP_PORT_PHYS_PORT) { 397 port->eth_forced = true; 398 err = nfp_port_init_phy_port(app->pf, app, port, alink->id); 399 if (err) 400 goto err_free_port; 401 } else { 402 port->pf_id = alink->abm->pf_id; 403 port->pf_split = app->pf->max_data_vnics > 1; 404 port->pf_split_id = alink->id; 405 port->vnic = alink->vnic->dp.ctrl_bar; 406 } 407 408 SET_NETDEV_DEV(netdev, &alink->vnic->pdev->dev); 409 eth_hw_addr_random(netdev); 410 411 err = nfp_repr_init(app, netdev, nfp_abm_portid(rtype, alink->id), 412 port, alink->vnic->dp.netdev); 413 if (err) 414 goto err_free_port; 415 416 reprs = nfp_reprs_get_locked(app, rtype); 417 WARN(nfp_repr_get_locked(app, reprs, alink->id), "duplicate repr"); 418 rcu_assign_pointer(reprs->reprs[alink->id], netdev); 419 420 nfp_info(app->cpp, "%s Port %d Representor(%s) created\n", 421 ptype == NFP_PORT_PF_PORT ? "PCIe" : "Phys", 422 alink->id, netdev->name); 423 424 return 0; 425 426 err_free_port: 427 nfp_port_free(port); 428 err_free_repr: 429 nfp_repr_free(netdev); 430 return err; 431 } 432 433 static void 434 nfp_abm_kill_repr(struct nfp_app *app, struct nfp_abm_link *alink, 435 enum nfp_repr_type rtype) 436 { 437 struct net_device *netdev; 438 struct nfp_reprs *reprs; 439 440 reprs = nfp_reprs_get_locked(app, rtype); 441 netdev = nfp_repr_get_locked(app, reprs, alink->id); 442 if (!netdev) 443 return; 444 rcu_assign_pointer(reprs->reprs[alink->id], NULL); 445 synchronize_rcu(); 446 /* Cast to make sure nfp_repr_clean_and_free() takes a nfp_repr */ 447 nfp_repr_clean_and_free((struct nfp_repr *)netdev_priv(netdev)); 448 } 449 450 static void 451 nfp_abm_kill_reprs(struct nfp_abm *abm, struct nfp_abm_link *alink) 452 { 453 nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PF); 454 nfp_abm_kill_repr(abm->app, alink, NFP_REPR_TYPE_PHYS_PORT); 455 } 456 457 static void nfp_abm_kill_reprs_all(struct nfp_abm *abm) 458 { 459 struct nfp_pf *pf = abm->app->pf; 460 struct nfp_net *nn; 461 462 list_for_each_entry(nn, &pf->vnics, vnic_list) 463 nfp_abm_kill_reprs(abm, (struct nfp_abm_link *)nn->app_priv); 464 } 465 466 static enum devlink_eswitch_mode nfp_abm_eswitch_mode_get(struct nfp_app *app) 467 { 468 struct nfp_abm *abm = app->priv; 469 470 return abm->eswitch_mode; 471 } 472 473 static int nfp_abm_eswitch_set_legacy(struct nfp_abm *abm) 474 { 475 nfp_abm_kill_reprs_all(abm); 476 nfp_abm_ctrl_qm_disable(abm); 477 478 abm->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY; 479 return 0; 480 } 481 482 static void nfp_abm_eswitch_clean_up(struct nfp_abm *abm) 483 { 484 if (abm->eswitch_mode != DEVLINK_ESWITCH_MODE_LEGACY) 485 WARN_ON(nfp_abm_eswitch_set_legacy(abm)); 486 } 487 488 static int nfp_abm_eswitch_set_switchdev(struct nfp_abm *abm) 489 { 490 struct nfp_app *app = abm->app; 491 struct nfp_pf *pf = app->pf; 492 struct nfp_net *nn; 493 int err; 494 495 err = nfp_abm_ctrl_qm_enable(abm); 496 if (err) 497 return err; 498 499 list_for_each_entry(nn, &pf->vnics, vnic_list) { 500 struct nfp_abm_link *alink = nn->app_priv; 501 502 err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PHYS_PORT); 503 if (err) 504 goto err_kill_all_reprs; 505 506 err = nfp_abm_spawn_repr(app, alink, NFP_PORT_PF_PORT); 507 if (err) 508 goto err_kill_all_reprs; 509 } 510 511 abm->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV; 512 return 0; 513 514 err_kill_all_reprs: 515 nfp_abm_kill_reprs_all(abm); 516 nfp_abm_ctrl_qm_disable(abm); 517 return err; 518 } 519 520 static int nfp_abm_eswitch_mode_set(struct nfp_app *app, u16 mode) 521 { 522 struct nfp_abm *abm = app->priv; 523 524 if (abm->eswitch_mode == mode) 525 return 0; 526 527 switch (mode) { 528 case DEVLINK_ESWITCH_MODE_LEGACY: 529 return nfp_abm_eswitch_set_legacy(abm); 530 case DEVLINK_ESWITCH_MODE_SWITCHDEV: 531 return nfp_abm_eswitch_set_switchdev(abm); 532 default: 533 return -EINVAL; 534 } 535 } 536 537 static void 538 nfp_abm_vnic_set_mac(struct nfp_pf *pf, struct nfp_abm *abm, struct nfp_net *nn, 539 unsigned int id) 540 { 541 struct nfp_eth_table_port *eth_port = &pf->eth_tbl->ports[id]; 542 u8 mac_addr[ETH_ALEN]; 543 const char *mac_str; 544 char name[32]; 545 546 if (id > pf->eth_tbl->count) { 547 nfp_warn(pf->cpp, "No entry for persistent MAC address\n"); 548 eth_hw_addr_random(nn->dp.netdev); 549 return; 550 } 551 552 snprintf(name, sizeof(name), "eth%u.mac.pf%u", 553 eth_port->eth_index, abm->pf_id); 554 555 mac_str = nfp_hwinfo_lookup(pf->hwinfo, name); 556 if (!mac_str) { 557 nfp_warn(pf->cpp, "Can't lookup persistent MAC address (%s)\n", 558 name); 559 eth_hw_addr_random(nn->dp.netdev); 560 return; 561 } 562 563 if (sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 564 &mac_addr[0], &mac_addr[1], &mac_addr[2], 565 &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6) { 566 nfp_warn(pf->cpp, "Can't parse persistent MAC address (%s)\n", 567 mac_str); 568 eth_hw_addr_random(nn->dp.netdev); 569 return; 570 } 571 572 ether_addr_copy(nn->dp.netdev->dev_addr, mac_addr); 573 ether_addr_copy(nn->dp.netdev->perm_addr, mac_addr); 574 } 575 576 static int 577 nfp_abm_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id) 578 { 579 struct nfp_eth_table_port *eth_port = &app->pf->eth_tbl->ports[id]; 580 struct nfp_abm *abm = app->priv; 581 struct nfp_abm_link *alink; 582 int err; 583 584 alink = kzalloc(sizeof(*alink), GFP_KERNEL); 585 if (!alink) 586 return -ENOMEM; 587 nn->app_priv = alink; 588 alink->abm = abm; 589 alink->vnic = nn; 590 alink->id = id; 591 alink->parent = TC_H_ROOT; 592 alink->total_queues = alink->vnic->max_rx_rings; 593 alink->qdiscs = kvcalloc(alink->total_queues, sizeof(*alink->qdiscs), 594 GFP_KERNEL); 595 if (!alink->qdiscs) { 596 err = -ENOMEM; 597 goto err_free_alink; 598 } 599 600 /* This is a multi-host app, make sure MAC/PHY is up, but don't 601 * make the MAC/PHY state follow the state of any of the ports. 602 */ 603 err = nfp_eth_set_configured(app->cpp, eth_port->index, true); 604 if (err < 0) 605 goto err_free_qdiscs; 606 607 netif_keep_dst(nn->dp.netdev); 608 609 nfp_abm_vnic_set_mac(app->pf, abm, nn, id); 610 nfp_abm_ctrl_read_params(alink); 611 612 return 0; 613 614 err_free_qdiscs: 615 kvfree(alink->qdiscs); 616 err_free_alink: 617 kfree(alink); 618 return err; 619 } 620 621 static void nfp_abm_vnic_free(struct nfp_app *app, struct nfp_net *nn) 622 { 623 struct nfp_abm_link *alink = nn->app_priv; 624 625 nfp_abm_kill_reprs(alink->abm, alink); 626 kvfree(alink->qdiscs); 627 kfree(alink); 628 } 629 630 static u64 * 631 nfp_abm_port_get_stats(struct nfp_app *app, struct nfp_port *port, u64 *data) 632 { 633 struct nfp_repr *repr = netdev_priv(port->netdev); 634 struct nfp_abm_link *alink; 635 unsigned int i; 636 637 if (port->type != NFP_PORT_PF_PORT) 638 return data; 639 alink = repr->app_priv; 640 for (i = 0; i < alink->vnic->dp.num_r_vecs; i++) { 641 *data++ = nfp_abm_ctrl_stat_non_sto(alink, i); 642 *data++ = nfp_abm_ctrl_stat_sto(alink, i); 643 } 644 return data; 645 } 646 647 static int 648 nfp_abm_port_get_stats_count(struct nfp_app *app, struct nfp_port *port) 649 { 650 struct nfp_repr *repr = netdev_priv(port->netdev); 651 struct nfp_abm_link *alink; 652 653 if (port->type != NFP_PORT_PF_PORT) 654 return 0; 655 alink = repr->app_priv; 656 return alink->vnic->dp.num_r_vecs * 2; 657 } 658 659 static u8 * 660 nfp_abm_port_get_stats_strings(struct nfp_app *app, struct nfp_port *port, 661 u8 *data) 662 { 663 struct nfp_repr *repr = netdev_priv(port->netdev); 664 struct nfp_abm_link *alink; 665 unsigned int i; 666 667 if (port->type != NFP_PORT_PF_PORT) 668 return data; 669 alink = repr->app_priv; 670 for (i = 0; i < alink->vnic->dp.num_r_vecs; i++) { 671 data = nfp_pr_et(data, "q%u_no_wait", i); 672 data = nfp_pr_et(data, "q%u_delayed", i); 673 } 674 return data; 675 } 676 677 static int nfp_abm_init(struct nfp_app *app) 678 { 679 struct nfp_pf *pf = app->pf; 680 struct nfp_reprs *reprs; 681 struct nfp_abm *abm; 682 int err; 683 684 if (!pf->eth_tbl) { 685 nfp_err(pf->cpp, "ABM NIC requires ETH table\n"); 686 return -EINVAL; 687 } 688 if (pf->max_data_vnics != pf->eth_tbl->count) { 689 nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n", 690 pf->max_data_vnics, pf->eth_tbl->count); 691 return -EINVAL; 692 } 693 if (!pf->mac_stats_bar) { 694 nfp_warn(app->cpp, "ABM NIC requires mac_stats symbol\n"); 695 return -EINVAL; 696 } 697 698 abm = kzalloc(sizeof(*abm), GFP_KERNEL); 699 if (!abm) 700 return -ENOMEM; 701 app->priv = abm; 702 abm->app = app; 703 704 err = nfp_abm_ctrl_find_addrs(abm); 705 if (err) 706 goto err_free_abm; 707 708 /* We start in legacy mode, make sure advanced queuing is disabled */ 709 err = nfp_abm_ctrl_qm_disable(abm); 710 if (err) 711 goto err_free_abm; 712 713 err = -ENOMEM; 714 reprs = nfp_reprs_alloc(pf->max_data_vnics); 715 if (!reprs) 716 goto err_free_abm; 717 RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PHYS_PORT], reprs); 718 719 reprs = nfp_reprs_alloc(pf->max_data_vnics); 720 if (!reprs) 721 goto err_free_phys; 722 RCU_INIT_POINTER(app->reprs[NFP_REPR_TYPE_PF], reprs); 723 724 return 0; 725 726 err_free_phys: 727 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); 728 err_free_abm: 729 kfree(abm); 730 app->priv = NULL; 731 return err; 732 } 733 734 static void nfp_abm_clean(struct nfp_app *app) 735 { 736 struct nfp_abm *abm = app->priv; 737 738 nfp_abm_eswitch_clean_up(abm); 739 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PF); 740 nfp_reprs_clean_and_free_by_type(app, NFP_REPR_TYPE_PHYS_PORT); 741 kfree(abm); 742 app->priv = NULL; 743 } 744 745 const struct nfp_app_type app_abm = { 746 .id = NFP_APP_ACTIVE_BUFFER_MGMT_NIC, 747 .name = "abm", 748 749 .init = nfp_abm_init, 750 .clean = nfp_abm_clean, 751 752 .vnic_alloc = nfp_abm_vnic_alloc, 753 .vnic_free = nfp_abm_vnic_free, 754 755 .port_get_stats = nfp_abm_port_get_stats, 756 .port_get_stats_count = nfp_abm_port_get_stats_count, 757 .port_get_stats_strings = nfp_abm_port_get_stats_strings, 758 759 .setup_tc = nfp_abm_setup_tc, 760 761 .eswitch_mode_get = nfp_abm_eswitch_mode_get, 762 .eswitch_mode_set = nfp_abm_eswitch_mode_set, 763 764 .repr_get = nfp_abm_repr_get, 765 }; 766