linux/drivers/net/ethernet/netronome/nfp/nfp_devlink.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/rtnetlink.h>
  35#include <net/devlink.h>
  36
  37#include "nfpcore/nfp_nsp.h"
  38#include "nfp_app.h"
  39#include "nfp_main.h"
  40#include "nfp_port.h"
  41
  42static int
  43nfp_devlink_fill_eth_port(struct nfp_port *port,
  44                          struct nfp_eth_table_port *copy)
  45{
  46        struct nfp_eth_table_port *eth_port;
  47
  48        eth_port = __nfp_port_get_eth_port(port);
  49        if (!eth_port)
  50                return -EINVAL;
  51
  52        memcpy(copy, eth_port, sizeof(*eth_port));
  53
  54        return 0;
  55}
  56
  57static int
  58nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf, unsigned int port_index,
  59                                  struct nfp_eth_table_port *copy)
  60{
  61        struct nfp_port *port;
  62
  63        port = nfp_port_from_id(pf, NFP_PORT_PHYS_PORT, port_index);
  64
  65        return nfp_devlink_fill_eth_port(port, copy);
  66}
  67
  68static int
  69nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes)
  70{
  71        struct nfp_nsp *nsp;
  72        int ret;
  73
  74        nsp = nfp_eth_config_start(pf->cpp, idx);
  75        if (IS_ERR(nsp))
  76                return PTR_ERR(nsp);
  77
  78        ret = __nfp_eth_set_split(nsp, lanes);
  79        if (ret) {
  80                nfp_eth_config_cleanup_end(nsp);
  81                return ret;
  82        }
  83
  84        ret = nfp_eth_config_commit_end(nsp);
  85        if (ret < 0)
  86                return ret;
  87        if (ret) /* no change */
  88                return 0;
  89
  90        return nfp_net_refresh_port_table_sync(pf);
  91}
  92
  93static int
  94nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index,
  95                       unsigned int count, struct netlink_ext_ack *extack)
  96{
  97        struct nfp_pf *pf = devlink_priv(devlink);
  98        struct nfp_eth_table_port eth_port;
  99        int ret;
 100
 101        if (count < 2)
 102                return -EINVAL;
 103
 104        mutex_lock(&pf->lock);
 105
 106        rtnl_lock();
 107        ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, &eth_port);
 108        rtnl_unlock();
 109        if (ret)
 110                goto out;
 111
 112        if (eth_port.is_split || eth_port.port_lanes % count) {
 113                ret = -EINVAL;
 114                goto out;
 115        }
 116
 117        ret = nfp_devlink_set_lanes(pf, eth_port.index,
 118                                    eth_port.port_lanes / count);
 119out:
 120        mutex_unlock(&pf->lock);
 121
 122        return ret;
 123}
 124
 125static int
 126nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index,
 127                         struct netlink_ext_ack *extack)
 128{
 129        struct nfp_pf *pf = devlink_priv(devlink);
 130        struct nfp_eth_table_port eth_port;
 131        int ret;
 132
 133        mutex_lock(&pf->lock);
 134
 135        rtnl_lock();
 136        ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, &eth_port);
 137        rtnl_unlock();
 138        if (ret)
 139                goto out;
 140
 141        if (!eth_port.is_split) {
 142                ret = -EINVAL;
 143                goto out;
 144        }
 145
 146        ret = nfp_devlink_set_lanes(pf, eth_port.index, eth_port.port_lanes);
 147out:
 148        mutex_unlock(&pf->lock);
 149
 150        return ret;
 151}
 152
 153static int
 154nfp_devlink_sb_pool_get(struct devlink *devlink, unsigned int sb_index,
 155                        u16 pool_index, struct devlink_sb_pool_info *pool_info)
 156{
 157        struct nfp_pf *pf = devlink_priv(devlink);
 158
 159        return nfp_shared_buf_pool_get(pf, sb_index, pool_index, pool_info);
 160}
 161
 162static int
 163nfp_devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
 164                        u16 pool_index,
 165                        u32 size, enum devlink_sb_threshold_type threshold_type)
 166{
 167        struct nfp_pf *pf = devlink_priv(devlink);
 168
 169        return nfp_shared_buf_pool_set(pf, sb_index, pool_index,
 170                                       size, threshold_type);
 171}
 172
 173static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
 174{
 175        struct nfp_pf *pf = devlink_priv(devlink);
 176
 177        return nfp_app_eswitch_mode_get(pf->app, mode);
 178}
 179
 180static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode)
 181{
 182        struct nfp_pf *pf = devlink_priv(devlink);
 183        int ret;
 184
 185        mutex_lock(&pf->lock);
 186        ret = nfp_app_eswitch_mode_set(pf->app, mode);
 187        mutex_unlock(&pf->lock);
 188
 189        return ret;
 190}
 191
 192const struct devlink_ops nfp_devlink_ops = {
 193        .port_split             = nfp_devlink_port_split,
 194        .port_unsplit           = nfp_devlink_port_unsplit,
 195        .sb_pool_get            = nfp_devlink_sb_pool_get,
 196        .sb_pool_set            = nfp_devlink_sb_pool_set,
 197        .eswitch_mode_get       = nfp_devlink_eswitch_mode_get,
 198        .eswitch_mode_set       = nfp_devlink_eswitch_mode_set,
 199};
 200
 201int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
 202{
 203        struct nfp_eth_table_port eth_port;
 204        struct devlink *devlink;
 205        int ret;
 206
 207        rtnl_lock();
 208        ret = nfp_devlink_fill_eth_port(port, &eth_port);
 209        rtnl_unlock();
 210        if (ret)
 211                return ret;
 212
 213        devlink_port_type_eth_set(&port->dl_port, port->netdev);
 214        devlink_port_attrs_set(&port->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
 215                               eth_port.label_port, eth_port.is_split,
 216                               eth_port.label_subport);
 217
 218        devlink = priv_to_devlink(app->pf);
 219
 220        return devlink_port_register(devlink, &port->dl_port, port->eth_id);
 221}
 222
 223void nfp_devlink_port_unregister(struct nfp_port *port)
 224{
 225        devlink_port_unregister(&port->dl_port);
 226}
 227