linux/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
   3
   4#include <linux/rtnetlink.h>
   5#include <net/devlink.h>
   6
   7#include "nfpcore/nfp.h"
   8#include "nfpcore/nfp_nsp.h"
   9#include "nfp_app.h"
  10#include "nfp_main.h"
  11#include "nfp_port.h"
  12
  13static int
  14nfp_devlink_fill_eth_port(struct nfp_port *port,
  15                          struct nfp_eth_table_port *copy)
  16{
  17        struct nfp_eth_table_port *eth_port;
  18
  19        eth_port = __nfp_port_get_eth_port(port);
  20        if (!eth_port)
  21                return -EINVAL;
  22
  23        memcpy(copy, eth_port, sizeof(*eth_port));
  24
  25        return 0;
  26}
  27
  28static int
  29nfp_devlink_fill_eth_port_from_id(struct nfp_pf *pf, unsigned int port_index,
  30                                  struct nfp_eth_table_port *copy)
  31{
  32        struct nfp_port *port;
  33
  34        port = nfp_port_from_id(pf, NFP_PORT_PHYS_PORT, port_index);
  35
  36        return nfp_devlink_fill_eth_port(port, copy);
  37}
  38
  39static int
  40nfp_devlink_set_lanes(struct nfp_pf *pf, unsigned int idx, unsigned int lanes)
  41{
  42        struct nfp_nsp *nsp;
  43        int ret;
  44
  45        nsp = nfp_eth_config_start(pf->cpp, idx);
  46        if (IS_ERR(nsp))
  47                return PTR_ERR(nsp);
  48
  49        ret = __nfp_eth_set_split(nsp, lanes);
  50        if (ret) {
  51                nfp_eth_config_cleanup_end(nsp);
  52                return ret;
  53        }
  54
  55        ret = nfp_eth_config_commit_end(nsp);
  56        if (ret < 0)
  57                return ret;
  58        if (ret) /* no change */
  59                return 0;
  60
  61        return nfp_net_refresh_port_table_sync(pf);
  62}
  63
  64static int
  65nfp_devlink_port_split(struct devlink *devlink, unsigned int port_index,
  66                       unsigned int count, struct netlink_ext_ack *extack)
  67{
  68        struct nfp_pf *pf = devlink_priv(devlink);
  69        struct nfp_eth_table_port eth_port;
  70        unsigned int lanes;
  71        int ret;
  72
  73        mutex_lock(&pf->lock);
  74
  75        rtnl_lock();
  76        ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, &eth_port);
  77        rtnl_unlock();
  78        if (ret)
  79                goto out;
  80
  81        if (eth_port.port_lanes % count) {
  82                ret = -EINVAL;
  83                goto out;
  84        }
  85
  86        /* Special case the 100G CXP -> 2x40G split */
  87        lanes = eth_port.port_lanes / count;
  88        if (eth_port.lanes == 10 && count == 2)
  89                lanes = 8 / count;
  90
  91        ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes);
  92out:
  93        mutex_unlock(&pf->lock);
  94
  95        return ret;
  96}
  97
  98static int
  99nfp_devlink_port_unsplit(struct devlink *devlink, unsigned int port_index,
 100                         struct netlink_ext_ack *extack)
 101{
 102        struct nfp_pf *pf = devlink_priv(devlink);
 103        struct nfp_eth_table_port eth_port;
 104        unsigned int lanes;
 105        int ret;
 106
 107        mutex_lock(&pf->lock);
 108
 109        rtnl_lock();
 110        ret = nfp_devlink_fill_eth_port_from_id(pf, port_index, &eth_port);
 111        rtnl_unlock();
 112        if (ret)
 113                goto out;
 114
 115        if (!eth_port.is_split) {
 116                ret = -EINVAL;
 117                goto out;
 118        }
 119
 120        /* Special case the 100G CXP -> 2x40G unsplit */
 121        lanes = eth_port.port_lanes;
 122        if (eth_port.port_lanes == 8)
 123                lanes = 10;
 124
 125        ret = nfp_devlink_set_lanes(pf, eth_port.index, lanes);
 126out:
 127        mutex_unlock(&pf->lock);
 128
 129        return ret;
 130}
 131
 132static int
 133nfp_devlink_sb_pool_get(struct devlink *devlink, unsigned int sb_index,
 134                        u16 pool_index, struct devlink_sb_pool_info *pool_info)
 135{
 136        struct nfp_pf *pf = devlink_priv(devlink);
 137
 138        return nfp_shared_buf_pool_get(pf, sb_index, pool_index, pool_info);
 139}
 140
 141static int
 142nfp_devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
 143                        u16 pool_index,
 144                        u32 size, enum devlink_sb_threshold_type threshold_type,
 145                        struct netlink_ext_ack *extack)
 146{
 147        struct nfp_pf *pf = devlink_priv(devlink);
 148
 149        return nfp_shared_buf_pool_set(pf, sb_index, pool_index,
 150                                       size, threshold_type);
 151}
 152
 153static int nfp_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
 154{
 155        struct nfp_pf *pf = devlink_priv(devlink);
 156
 157        return nfp_app_eswitch_mode_get(pf->app, mode);
 158}
 159
 160static int nfp_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
 161                                        struct netlink_ext_ack *extack)
 162{
 163        struct nfp_pf *pf = devlink_priv(devlink);
 164        int ret;
 165
 166        mutex_lock(&pf->lock);
 167        ret = nfp_app_eswitch_mode_set(pf->app, mode);
 168        mutex_unlock(&pf->lock);
 169
 170        return ret;
 171}
 172
 173static const struct nfp_devlink_versions_simple {
 174        const char *key;
 175        const char *hwinfo;
 176} nfp_devlink_versions_hwinfo[] = {
 177        { DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,        "assembly.partno", },
 178        { DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,       "assembly.revision", },
 179        { DEVLINK_INFO_VERSION_GENERIC_BOARD_MANUFACTURE, "assembly.vendor", },
 180        { "board.model", /* code name */                "assembly.model", },
 181};
 182
 183static int
 184nfp_devlink_versions_get_hwinfo(struct nfp_pf *pf, struct devlink_info_req *req)
 185{
 186        unsigned int i;
 187        int err;
 188
 189        for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_hwinfo); i++) {
 190                const struct nfp_devlink_versions_simple *info;
 191                const char *val;
 192
 193                info = &nfp_devlink_versions_hwinfo[i];
 194
 195                val = nfp_hwinfo_lookup(pf->hwinfo, info->hwinfo);
 196                if (!val)
 197                        continue;
 198
 199                err = devlink_info_version_fixed_put(req, info->key, val);
 200                if (err)
 201                        return err;
 202        }
 203
 204        return 0;
 205}
 206
 207static const struct nfp_devlink_versions {
 208        enum nfp_nsp_versions id;
 209        const char *key;
 210} nfp_devlink_versions_nsp[] = {
 211        { NFP_VERSIONS_BUNDLE,  DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, },
 212        { NFP_VERSIONS_BSP,     DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, },
 213        { NFP_VERSIONS_CPLD,    "fw.cpld", },
 214        { NFP_VERSIONS_APP,     DEVLINK_INFO_VERSION_GENERIC_FW_APP, },
 215        { NFP_VERSIONS_UNDI,    DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, },
 216        { NFP_VERSIONS_NCSI,    DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, },
 217        { NFP_VERSIONS_CFGR,    "chip.init", },
 218};
 219
 220static int
 221nfp_devlink_versions_get_nsp(struct devlink_info_req *req, bool flash,
 222                             const u8 *buf, unsigned int size)
 223{
 224        unsigned int i;
 225        int err;
 226
 227        for (i = 0; i < ARRAY_SIZE(nfp_devlink_versions_nsp); i++) {
 228                const struct nfp_devlink_versions *info;
 229                const char *version;
 230
 231                info = &nfp_devlink_versions_nsp[i];
 232
 233                version = nfp_nsp_versions_get(info->id, flash, buf, size);
 234                if (IS_ERR(version)) {
 235                        if (PTR_ERR(version) == -ENOENT)
 236                                continue;
 237                        else
 238                                return PTR_ERR(version);
 239                }
 240
 241                if (flash)
 242                        err = devlink_info_version_stored_put(req, info->key,
 243                                                              version);
 244                else
 245                        err = devlink_info_version_running_put(req, info->key,
 246                                                               version);
 247                if (err)
 248                        return err;
 249        }
 250
 251        return 0;
 252}
 253
 254static int
 255nfp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
 256                     struct netlink_ext_ack *extack)
 257{
 258        struct nfp_pf *pf = devlink_priv(devlink);
 259        const char *sn, *vendor, *part;
 260        struct nfp_nsp *nsp;
 261        char *buf = NULL;
 262        int err;
 263
 264        err = devlink_info_driver_name_put(req, "nfp");
 265        if (err)
 266                return err;
 267
 268        vendor = nfp_hwinfo_lookup(pf->hwinfo, "assembly.vendor");
 269        part = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno");
 270        sn = nfp_hwinfo_lookup(pf->hwinfo, "assembly.serial");
 271        if (vendor && part && sn) {
 272                char *buf;
 273
 274                buf = kmalloc(strlen(vendor) + strlen(part) + strlen(sn) + 1,
 275                              GFP_KERNEL);
 276                if (!buf)
 277                        return -ENOMEM;
 278
 279                buf[0] = '\0';
 280                strcat(buf, vendor);
 281                strcat(buf, part);
 282                strcat(buf, sn);
 283
 284                err = devlink_info_serial_number_put(req, buf);
 285                kfree(buf);
 286                if (err)
 287                        return err;
 288        }
 289
 290        nsp = nfp_nsp_open(pf->cpp);
 291        if (IS_ERR(nsp)) {
 292                NL_SET_ERR_MSG_MOD(extack, "can't access NSP");
 293                return PTR_ERR(nsp);
 294        }
 295
 296        if (nfp_nsp_has_versions(nsp)) {
 297                buf = kzalloc(NFP_NSP_VERSION_BUFSZ, GFP_KERNEL);
 298                if (!buf) {
 299                        err = -ENOMEM;
 300                        goto err_close_nsp;
 301                }
 302
 303                err = nfp_nsp_versions(nsp, buf, NFP_NSP_VERSION_BUFSZ);
 304                if (err)
 305                        goto err_free_buf;
 306
 307                err = nfp_devlink_versions_get_nsp(req, false,
 308                                                   buf, NFP_NSP_VERSION_BUFSZ);
 309                if (err)
 310                        goto err_free_buf;
 311
 312                err = nfp_devlink_versions_get_nsp(req, true,
 313                                                   buf, NFP_NSP_VERSION_BUFSZ);
 314                if (err)
 315                        goto err_free_buf;
 316
 317                kfree(buf);
 318        }
 319
 320        nfp_nsp_close(nsp);
 321
 322        return nfp_devlink_versions_get_hwinfo(pf, req);
 323
 324err_free_buf:
 325        kfree(buf);
 326err_close_nsp:
 327        nfp_nsp_close(nsp);
 328        return err;
 329}
 330
 331static int
 332nfp_devlink_flash_update(struct devlink *devlink,
 333                         struct devlink_flash_update_params *params,
 334                         struct netlink_ext_ack *extack)
 335{
 336        return nfp_flash_update_common(devlink_priv(devlink), params->fw, extack);
 337}
 338
 339const struct devlink_ops nfp_devlink_ops = {
 340        .port_split             = nfp_devlink_port_split,
 341        .port_unsplit           = nfp_devlink_port_unsplit,
 342        .sb_pool_get            = nfp_devlink_sb_pool_get,
 343        .sb_pool_set            = nfp_devlink_sb_pool_set,
 344        .eswitch_mode_get       = nfp_devlink_eswitch_mode_get,
 345        .eswitch_mode_set       = nfp_devlink_eswitch_mode_set,
 346        .info_get               = nfp_devlink_info_get,
 347        .flash_update           = nfp_devlink_flash_update,
 348};
 349
 350int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port)
 351{
 352        struct devlink_port_attrs attrs = {};
 353        struct nfp_eth_table_port eth_port;
 354        struct devlink *devlink;
 355        const u8 *serial;
 356        int serial_len;
 357        int ret;
 358
 359        rtnl_lock();
 360        ret = nfp_devlink_fill_eth_port(port, &eth_port);
 361        rtnl_unlock();
 362        if (ret)
 363                return ret;
 364
 365        attrs.split = eth_port.is_split;
 366        attrs.splittable = !attrs.split;
 367        attrs.lanes = eth_port.port_lanes;
 368        attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
 369        attrs.phys.port_number = eth_port.label_port;
 370        attrs.phys.split_subport_number = eth_port.label_subport;
 371        serial_len = nfp_cpp_serial(port->app->cpp, &serial);
 372        memcpy(attrs.switch_id.id, serial, serial_len);
 373        attrs.switch_id.id_len = serial_len;
 374        devlink_port_attrs_set(&port->dl_port, &attrs);
 375
 376        devlink = priv_to_devlink(app->pf);
 377
 378        return devlink_port_register(devlink, &port->dl_port, port->eth_id);
 379}
 380
 381void nfp_devlink_port_unregister(struct nfp_port *port)
 382{
 383        devlink_port_unregister(&port->dl_port);
 384}
 385
 386void nfp_devlink_port_type_eth_set(struct nfp_port *port)
 387{
 388        devlink_port_type_eth_set(&port->dl_port, port->netdev);
 389}
 390
 391void nfp_devlink_port_type_clear(struct nfp_port *port)
 392{
 393        devlink_port_type_clear(&port->dl_port);
 394}
 395
 396struct devlink_port *nfp_devlink_get_devlink_port(struct net_device *netdev)
 397{
 398        struct nfp_port *port;
 399
 400        port = nfp_port_from_netdev(netdev);
 401        if (!port)
 402                return NULL;
 403
 404        return &port->dl_port;
 405}
 406