linux/drivers/net/ethernet/netronome/nfp/nfp_port.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017 Netronome Systems, Inc.
   3 *
   4 * This software is dual licensed under the GNU General License Version 2,
   5 * June 1991 as shown in the file COPYING in the top-level directory of this
   6 * source tree or the BSD 2-Clause License provided below.  You have the
   7 * option to license this software under the complete terms of either license.
   8 *
   9 * The BSD 2-Clause License:
  10 *
  11 *     Redistribution and use in source and binary forms, with or
  12 *     without modification, are permitted provided that the following
  13 *     conditions are met:
  14 *
  15 *      1. Redistributions of source code must retain the above
  16 *         copyright notice, this list of conditions and the following
  17 *         disclaimer.
  18 *
  19 *      2. Redistributions in binary form must reproduce the above
  20 *         copyright notice, this list of conditions and the following
  21 *         disclaimer in the documentation and/or other materials
  22 *         provided with the distribution.
  23 *
  24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  31 * SOFTWARE.
  32 */
  33
  34#include <linux/lockdep.h>
  35#include <net/switchdev.h>
  36
  37#include "nfpcore/nfp_cpp.h"
  38#include "nfpcore/nfp_nsp.h"
  39#include "nfp_app.h"
  40#include "nfp_main.h"
  41#include "nfp_net.h"
  42#include "nfp_port.h"
  43
  44struct nfp_port *nfp_port_from_netdev(struct net_device *netdev)
  45{
  46        if (nfp_netdev_is_nfp_net(netdev)) {
  47                struct nfp_net *nn = netdev_priv(netdev);
  48
  49                return nn->port;
  50        }
  51
  52        if (nfp_netdev_is_nfp_repr(netdev)) {
  53                struct nfp_repr *repr = netdev_priv(netdev);
  54
  55                return repr->port;
  56        }
  57
  58        WARN(1, "Unknown netdev type for nfp_port\n");
  59
  60        return NULL;
  61}
  62
  63static int
  64nfp_port_attr_get(struct net_device *netdev, struct switchdev_attr *attr)
  65{
  66        struct nfp_port *port;
  67
  68        port = nfp_port_from_netdev(netdev);
  69        if (!port)
  70                return -EOPNOTSUPP;
  71
  72        switch (attr->id) {
  73        case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: {
  74                const u8 *serial;
  75                /* N.B: attr->u.ppid.id is binary data */
  76                attr->u.ppid.id_len = nfp_cpp_serial(port->app->cpp, &serial);
  77                memcpy(&attr->u.ppid.id, serial, attr->u.ppid.id_len);
  78                break;
  79        }
  80        default:
  81                return -EOPNOTSUPP;
  82        }
  83
  84        return 0;
  85}
  86
  87const struct switchdev_ops nfp_port_switchdev_ops = {
  88        .switchdev_port_attr_get        = nfp_port_attr_get,
  89};
  90
  91int nfp_port_setup_tc(struct net_device *netdev, enum tc_setup_type type,
  92                      void *type_data)
  93{
  94        struct nfp_port *port;
  95
  96        port = nfp_port_from_netdev(netdev);
  97        if (!port)
  98                return -EOPNOTSUPP;
  99
 100        return nfp_app_setup_tc(port->app, netdev, type, type_data);
 101}
 102
 103struct nfp_port *
 104nfp_port_from_id(struct nfp_pf *pf, enum nfp_port_type type, unsigned int id)
 105{
 106        struct nfp_port *port;
 107
 108        lockdep_assert_held(&pf->lock);
 109
 110        if (type != NFP_PORT_PHYS_PORT)
 111                return NULL;
 112
 113        list_for_each_entry(port, &pf->ports, port_list)
 114                if (port->eth_id == id)
 115                        return port;
 116
 117        return NULL;
 118}
 119
 120struct nfp_eth_table_port *__nfp_port_get_eth_port(struct nfp_port *port)
 121{
 122        if (!port)
 123                return NULL;
 124        if (port->type != NFP_PORT_PHYS_PORT)
 125                return NULL;
 126
 127        return port->eth_port;
 128}
 129
 130struct nfp_eth_table_port *nfp_port_get_eth_port(struct nfp_port *port)
 131{
 132        if (!__nfp_port_get_eth_port(port))
 133                return NULL;
 134
 135        if (test_bit(NFP_PORT_CHANGED, &port->flags))
 136                if (nfp_net_refresh_eth_port(port))
 137                        return NULL;
 138
 139        return __nfp_port_get_eth_port(port);
 140}
 141
 142int
 143nfp_port_get_phys_port_name(struct net_device *netdev, char *name, size_t len)
 144{
 145        struct nfp_eth_table_port *eth_port;
 146        struct nfp_port *port;
 147        int n;
 148
 149        port = nfp_port_from_netdev(netdev);
 150        if (!port)
 151                return -EOPNOTSUPP;
 152
 153        switch (port->type) {
 154        case NFP_PORT_PHYS_PORT:
 155                eth_port = __nfp_port_get_eth_port(port);
 156                if (!eth_port)
 157                        return -EOPNOTSUPP;
 158
 159                if (!eth_port->is_split)
 160                        n = snprintf(name, len, "p%d", eth_port->label_port);
 161                else
 162                        n = snprintf(name, len, "p%ds%d", eth_port->label_port,
 163                                     eth_port->label_subport);
 164                break;
 165        case NFP_PORT_PF_PORT:
 166                n = snprintf(name, len, "pf%d", port->pf_id);
 167                break;
 168        case NFP_PORT_VF_PORT:
 169                n = snprintf(name, len, "pf%dvf%d", port->pf_id, port->vf_id);
 170                break;
 171        default:
 172                return -EOPNOTSUPP;
 173        }
 174
 175        if (n >= len)
 176                return -EINVAL;
 177
 178        return 0;
 179}
 180
 181/**
 182 * nfp_port_configure() - helper to set the interface configured bit
 183 * @netdev:     net_device instance
 184 * @configed:   Desired state
 185 *
 186 * Helper to set the ifup/ifdown state on the PHY only if there is a physical
 187 * interface associated with the netdev.
 188 *
 189 * Return:
 190 * 0 - configuration successful (or no change);
 191 * -ERRNO - configuration failed.
 192 */
 193int nfp_port_configure(struct net_device *netdev, bool configed)
 194{
 195        struct nfp_eth_table_port *eth_port;
 196        struct nfp_port *port;
 197        int err;
 198
 199        port = nfp_port_from_netdev(netdev);
 200        eth_port = __nfp_port_get_eth_port(port);
 201        if (!eth_port)
 202                return 0;
 203
 204        err = nfp_eth_set_configured(port->app->cpp, eth_port->index, configed);
 205        return err < 0 && err != -EOPNOTSUPP ? err : 0;
 206}
 207
 208int nfp_port_init_phy_port(struct nfp_pf *pf, struct nfp_app *app,
 209                           struct nfp_port *port, unsigned int id)
 210{
 211        /* Check if vNIC has external port associated and cfg is OK */
 212        if (!pf->eth_tbl || id >= pf->eth_tbl->count) {
 213                nfp_err(app->cpp,
 214                        "NSP port entries don't match vNICs (no entry %d)\n",
 215                        id);
 216                return -EINVAL;
 217        }
 218        if (pf->eth_tbl->ports[id].override_changed) {
 219                nfp_warn(app->cpp,
 220                         "Config changed for port #%d, reboot required before port will be operational\n",
 221                         pf->eth_tbl->ports[id].index);
 222                port->type = NFP_PORT_INVALID;
 223                return 0;
 224        }
 225
 226        port->eth_port = &pf->eth_tbl->ports[id];
 227        port->eth_id = pf->eth_tbl->ports[id].index;
 228        if (pf->mac_stats_mem)
 229                port->eth_stats =
 230                        pf->mac_stats_mem + port->eth_id * NFP_MAC_STATS_SIZE;
 231
 232        return 0;
 233}
 234
 235struct nfp_port *
 236nfp_port_alloc(struct nfp_app *app, enum nfp_port_type type,
 237               struct net_device *netdev)
 238{
 239        struct nfp_port *port;
 240
 241        port = kzalloc(sizeof(*port), GFP_KERNEL);
 242        if (!port)
 243                return ERR_PTR(-ENOMEM);
 244
 245        port->netdev = netdev;
 246        port->type = type;
 247        port->app = app;
 248
 249        list_add_tail(&port->port_list, &app->pf->ports);
 250
 251        return port;
 252}
 253
 254void nfp_port_free(struct nfp_port *port)
 255{
 256        if (!port)
 257                return;
 258        list_del(&port->port_list);
 259        kfree(port);
 260}
 261