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