linux/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015-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/* Authors: David Brunecz <david.brunecz@netronome.com>
  35 *          Jakub Kicinski <jakub.kicinski@netronome.com>
  36 *          Jason Mcmullan <jason.mcmullan@netronome.com>
  37 */
  38
  39#include <linux/bitfield.h>
  40#include <linux/ethtool.h>
  41#include <linux/if_ether.h>
  42#include <linux/kernel.h>
  43#include <linux/module.h>
  44
  45#include "nfp.h"
  46#include "nfp_nsp.h"
  47#include "nfp6000/nfp6000.h"
  48
  49#define NSP_ETH_NBI_PORT_COUNT          24
  50#define NSP_ETH_MAX_COUNT               (2 * NSP_ETH_NBI_PORT_COUNT)
  51#define NSP_ETH_TABLE_SIZE              (NSP_ETH_MAX_COUNT *            \
  52                                         sizeof(union eth_table_entry))
  53
  54#define NSP_ETH_PORT_LANES              GENMASK_ULL(3, 0)
  55#define NSP_ETH_PORT_INDEX              GENMASK_ULL(15, 8)
  56#define NSP_ETH_PORT_LABEL              GENMASK_ULL(53, 48)
  57#define NSP_ETH_PORT_PHYLABEL           GENMASK_ULL(59, 54)
  58#define NSP_ETH_PORT_FEC_SUPP_BASER     BIT_ULL(60)
  59#define NSP_ETH_PORT_FEC_SUPP_RS        BIT_ULL(61)
  60
  61#define NSP_ETH_PORT_LANES_MASK         cpu_to_le64(NSP_ETH_PORT_LANES)
  62
  63#define NSP_ETH_STATE_CONFIGURED        BIT_ULL(0)
  64#define NSP_ETH_STATE_ENABLED           BIT_ULL(1)
  65#define NSP_ETH_STATE_TX_ENABLED        BIT_ULL(2)
  66#define NSP_ETH_STATE_RX_ENABLED        BIT_ULL(3)
  67#define NSP_ETH_STATE_RATE              GENMASK_ULL(11, 8)
  68#define NSP_ETH_STATE_INTERFACE         GENMASK_ULL(19, 12)
  69#define NSP_ETH_STATE_MEDIA             GENMASK_ULL(21, 20)
  70#define NSP_ETH_STATE_OVRD_CHNG         BIT_ULL(22)
  71#define NSP_ETH_STATE_ANEG              GENMASK_ULL(25, 23)
  72#define NSP_ETH_STATE_FEC               GENMASK_ULL(27, 26)
  73
  74#define NSP_ETH_CTRL_CONFIGURED         BIT_ULL(0)
  75#define NSP_ETH_CTRL_ENABLED            BIT_ULL(1)
  76#define NSP_ETH_CTRL_TX_ENABLED         BIT_ULL(2)
  77#define NSP_ETH_CTRL_RX_ENABLED         BIT_ULL(3)
  78#define NSP_ETH_CTRL_SET_RATE           BIT_ULL(4)
  79#define NSP_ETH_CTRL_SET_LANES          BIT_ULL(5)
  80#define NSP_ETH_CTRL_SET_ANEG           BIT_ULL(6)
  81#define NSP_ETH_CTRL_SET_FEC            BIT_ULL(7)
  82
  83enum nfp_eth_raw {
  84        NSP_ETH_RAW_PORT = 0,
  85        NSP_ETH_RAW_STATE,
  86        NSP_ETH_RAW_MAC,
  87        NSP_ETH_RAW_CONTROL,
  88
  89        NSP_ETH_NUM_RAW
  90};
  91
  92enum nfp_eth_rate {
  93        RATE_INVALID = 0,
  94        RATE_10M,
  95        RATE_100M,
  96        RATE_1G,
  97        RATE_10G,
  98        RATE_25G,
  99};
 100
 101union eth_table_entry {
 102        struct {
 103                __le64 port;
 104                __le64 state;
 105                u8 mac_addr[6];
 106                u8 resv[2];
 107                __le64 control;
 108        };
 109        __le64 raw[NSP_ETH_NUM_RAW];
 110};
 111
 112static const struct {
 113        enum nfp_eth_rate rate;
 114        unsigned int speed;
 115} nsp_eth_rate_tbl[] = {
 116        { RATE_INVALID, 0, },
 117        { RATE_10M,     SPEED_10, },
 118        { RATE_100M,    SPEED_100, },
 119        { RATE_1G,      SPEED_1000, },
 120        { RATE_10G,     SPEED_10000, },
 121        { RATE_25G,     SPEED_25000, },
 122};
 123
 124static unsigned int nfp_eth_rate2speed(enum nfp_eth_rate rate)
 125{
 126        int i;
 127
 128        for (i = 0; i < ARRAY_SIZE(nsp_eth_rate_tbl); i++)
 129                if (nsp_eth_rate_tbl[i].rate == rate)
 130                        return nsp_eth_rate_tbl[i].speed;
 131
 132        return 0;
 133}
 134
 135static unsigned int nfp_eth_speed2rate(unsigned int speed)
 136{
 137        int i;
 138
 139        for (i = 0; i < ARRAY_SIZE(nsp_eth_rate_tbl); i++)
 140                if (nsp_eth_rate_tbl[i].speed == speed)
 141                        return nsp_eth_rate_tbl[i].rate;
 142
 143        return RATE_INVALID;
 144}
 145
 146static void nfp_eth_copy_mac_reverse(u8 *dst, const u8 *src)
 147{
 148        int i;
 149
 150        for (i = 0; i < ETH_ALEN; i++)
 151                dst[ETH_ALEN - i - 1] = src[i];
 152}
 153
 154static void
 155nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src,
 156                       unsigned int index, struct nfp_eth_table_port *dst)
 157{
 158        unsigned int rate;
 159        unsigned int fec;
 160        u64 port, state;
 161
 162        port = le64_to_cpu(src->port);
 163        state = le64_to_cpu(src->state);
 164
 165        dst->eth_index = FIELD_GET(NSP_ETH_PORT_INDEX, port);
 166        dst->index = index;
 167        dst->nbi = index / NSP_ETH_NBI_PORT_COUNT;
 168        dst->base = index % NSP_ETH_NBI_PORT_COUNT;
 169        dst->lanes = FIELD_GET(NSP_ETH_PORT_LANES, port);
 170
 171        dst->enabled = FIELD_GET(NSP_ETH_STATE_ENABLED, state);
 172        dst->tx_enabled = FIELD_GET(NSP_ETH_STATE_TX_ENABLED, state);
 173        dst->rx_enabled = FIELD_GET(NSP_ETH_STATE_RX_ENABLED, state);
 174
 175        rate = nfp_eth_rate2speed(FIELD_GET(NSP_ETH_STATE_RATE, state));
 176        dst->speed = dst->lanes * rate;
 177
 178        dst->interface = FIELD_GET(NSP_ETH_STATE_INTERFACE, state);
 179        dst->media = FIELD_GET(NSP_ETH_STATE_MEDIA, state);
 180
 181        nfp_eth_copy_mac_reverse(dst->mac_addr, src->mac_addr);
 182
 183        dst->label_port = FIELD_GET(NSP_ETH_PORT_PHYLABEL, port);
 184        dst->label_subport = FIELD_GET(NSP_ETH_PORT_LABEL, port);
 185
 186        if (nfp_nsp_get_abi_ver_minor(nsp) < 17)
 187                return;
 188
 189        dst->override_changed = FIELD_GET(NSP_ETH_STATE_OVRD_CHNG, state);
 190        dst->aneg = FIELD_GET(NSP_ETH_STATE_ANEG, state);
 191
 192        if (nfp_nsp_get_abi_ver_minor(nsp) < 22)
 193                return;
 194
 195        fec = FIELD_GET(NSP_ETH_PORT_FEC_SUPP_BASER, port);
 196        dst->fec_modes_supported |= fec << NFP_FEC_BASER_BIT;
 197        fec = FIELD_GET(NSP_ETH_PORT_FEC_SUPP_RS, port);
 198        dst->fec_modes_supported |= fec << NFP_FEC_REED_SOLOMON_BIT;
 199        if (dst->fec_modes_supported)
 200                dst->fec_modes_supported |= NFP_FEC_AUTO | NFP_FEC_DISABLED;
 201
 202        dst->fec = 1 << FIELD_GET(NSP_ETH_STATE_FEC, state);
 203}
 204
 205static void
 206nfp_eth_calc_port_geometry(struct nfp_cpp *cpp, struct nfp_eth_table *table)
 207{
 208        unsigned int i, j;
 209
 210        for (i = 0; i < table->count; i++) {
 211                table->max_index = max(table->max_index, table->ports[i].index);
 212
 213                for (j = 0; j < table->count; j++) {
 214                        if (table->ports[i].label_port !=
 215                            table->ports[j].label_port)
 216                                continue;
 217                        table->ports[i].port_lanes += table->ports[j].lanes;
 218
 219                        if (i == j)
 220                                continue;
 221                        if (table->ports[i].label_subport ==
 222                            table->ports[j].label_subport)
 223                                nfp_warn(cpp,
 224                                         "Port %d subport %d is a duplicate\n",
 225                                         table->ports[i].label_port,
 226                                         table->ports[i].label_subport);
 227
 228                        table->ports[i].is_split = true;
 229                }
 230        }
 231}
 232
 233static void
 234nfp_eth_calc_port_type(struct nfp_cpp *cpp, struct nfp_eth_table_port *entry)
 235{
 236        if (entry->interface == NFP_INTERFACE_NONE) {
 237                entry->port_type = PORT_NONE;
 238                return;
 239        }
 240
 241        if (entry->media == NFP_MEDIA_FIBRE)
 242                entry->port_type = PORT_FIBRE;
 243        else
 244                entry->port_type = PORT_DA;
 245}
 246
 247/**
 248 * nfp_eth_read_ports() - retrieve port information
 249 * @cpp:        NFP CPP handle
 250 *
 251 * Read the port information from the device.  Returned structure should
 252 * be freed with kfree() once no longer needed.
 253 *
 254 * Return: populated ETH table or NULL on error.
 255 */
 256struct nfp_eth_table *nfp_eth_read_ports(struct nfp_cpp *cpp)
 257{
 258        struct nfp_eth_table *ret;
 259        struct nfp_nsp *nsp;
 260
 261        nsp = nfp_nsp_open(cpp);
 262        if (IS_ERR(nsp))
 263                return NULL;
 264
 265        ret = __nfp_eth_read_ports(cpp, nsp);
 266        nfp_nsp_close(nsp);
 267
 268        return ret;
 269}
 270
 271struct nfp_eth_table *
 272__nfp_eth_read_ports(struct nfp_cpp *cpp, struct nfp_nsp *nsp)
 273{
 274        union eth_table_entry *entries;
 275        struct nfp_eth_table *table;
 276        int i, j, ret, cnt = 0;
 277
 278        entries = kzalloc(NSP_ETH_TABLE_SIZE, GFP_KERNEL);
 279        if (!entries)
 280                return NULL;
 281
 282        ret = nfp_nsp_read_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
 283        if (ret < 0) {
 284                nfp_err(cpp, "reading port table failed %d\n", ret);
 285                goto err;
 286        }
 287
 288        for (i = 0; i < NSP_ETH_MAX_COUNT; i++)
 289                if (entries[i].port & NSP_ETH_PORT_LANES_MASK)
 290                        cnt++;
 291
 292        /* Some versions of flash will give us 0 instead of port count.
 293         * For those that give a port count, verify it against the value
 294         * calculated above.
 295         */
 296        if (ret && ret != cnt) {
 297                nfp_err(cpp, "table entry count reported (%d) does not match entries present (%d)\n",
 298                        ret, cnt);
 299                goto err;
 300        }
 301
 302        table = kzalloc(sizeof(*table) +
 303                        sizeof(struct nfp_eth_table_port) * cnt, GFP_KERNEL);
 304        if (!table)
 305                goto err;
 306
 307        table->count = cnt;
 308        for (i = 0, j = 0; i < NSP_ETH_MAX_COUNT; i++)
 309                if (entries[i].port & NSP_ETH_PORT_LANES_MASK)
 310                        nfp_eth_port_translate(nsp, &entries[i], i,
 311                                               &table->ports[j++]);
 312
 313        nfp_eth_calc_port_geometry(cpp, table);
 314        for (i = 0; i < table->count; i++)
 315                nfp_eth_calc_port_type(cpp, &table->ports[i]);
 316
 317        kfree(entries);
 318
 319        return table;
 320
 321err:
 322        kfree(entries);
 323        return NULL;
 324}
 325
 326struct nfp_nsp *nfp_eth_config_start(struct nfp_cpp *cpp, unsigned int idx)
 327{
 328        union eth_table_entry *entries;
 329        struct nfp_nsp *nsp;
 330        int ret;
 331
 332        entries = kzalloc(NSP_ETH_TABLE_SIZE, GFP_KERNEL);
 333        if (!entries)
 334                return ERR_PTR(-ENOMEM);
 335
 336        nsp = nfp_nsp_open(cpp);
 337        if (IS_ERR(nsp)) {
 338                kfree(entries);
 339                return nsp;
 340        }
 341
 342        ret = nfp_nsp_read_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
 343        if (ret < 0) {
 344                nfp_err(cpp, "reading port table failed %d\n", ret);
 345                goto err;
 346        }
 347
 348        if (!(entries[idx].port & NSP_ETH_PORT_LANES_MASK)) {
 349                nfp_warn(cpp, "trying to set port state on disabled port %d\n",
 350                         idx);
 351                goto err;
 352        }
 353
 354        nfp_nsp_config_set_state(nsp, entries, idx);
 355        return nsp;
 356
 357err:
 358        nfp_nsp_close(nsp);
 359        kfree(entries);
 360        return ERR_PTR(-EIO);
 361}
 362
 363void nfp_eth_config_cleanup_end(struct nfp_nsp *nsp)
 364{
 365        union eth_table_entry *entries = nfp_nsp_config_entries(nsp);
 366
 367        nfp_nsp_config_set_modified(nsp, false);
 368        nfp_nsp_config_clear_state(nsp);
 369        nfp_nsp_close(nsp);
 370        kfree(entries);
 371}
 372
 373/**
 374 * nfp_eth_config_commit_end() - perform recorded configuration changes
 375 * @nsp:        NFP NSP handle returned from nfp_eth_config_start()
 376 *
 377 * Perform the configuration which was requested with __nfp_eth_set_*()
 378 * helpers and recorded in @nsp state.  If device was already configured
 379 * as requested or no __nfp_eth_set_*() operations were made no NSP command
 380 * will be performed.
 381 *
 382 * Return:
 383 * 0 - configuration successful;
 384 * 1 - no changes were needed;
 385 * -ERRNO - configuration failed.
 386 */
 387int nfp_eth_config_commit_end(struct nfp_nsp *nsp)
 388{
 389        union eth_table_entry *entries = nfp_nsp_config_entries(nsp);
 390        int ret = 1;
 391
 392        if (nfp_nsp_config_modified(nsp)) {
 393                ret = nfp_nsp_write_eth_table(nsp, entries, NSP_ETH_TABLE_SIZE);
 394                ret = ret < 0 ? ret : 0;
 395        }
 396
 397        nfp_eth_config_cleanup_end(nsp);
 398
 399        return ret;
 400}
 401
 402/**
 403 * nfp_eth_set_mod_enable() - set PHY module enable control bit
 404 * @cpp:        NFP CPP handle
 405 * @idx:        NFP chip-wide port index
 406 * @enable:     Desired state
 407 *
 408 * Enable or disable PHY module (this usually means setting the TX lanes
 409 * disable bits).
 410 *
 411 * Return:
 412 * 0 - configuration successful;
 413 * 1 - no changes were needed;
 414 * -ERRNO - configuration failed.
 415 */
 416int nfp_eth_set_mod_enable(struct nfp_cpp *cpp, unsigned int idx, bool enable)
 417{
 418        union eth_table_entry *entries;
 419        struct nfp_nsp *nsp;
 420        u64 reg;
 421
 422        nsp = nfp_eth_config_start(cpp, idx);
 423        if (IS_ERR(nsp))
 424                return PTR_ERR(nsp);
 425
 426        entries = nfp_nsp_config_entries(nsp);
 427
 428        /* Check if we are already in requested state */
 429        reg = le64_to_cpu(entries[idx].state);
 430        if (enable != FIELD_GET(NSP_ETH_CTRL_ENABLED, reg)) {
 431                reg = le64_to_cpu(entries[idx].control);
 432                reg &= ~NSP_ETH_CTRL_ENABLED;
 433                reg |= FIELD_PREP(NSP_ETH_CTRL_ENABLED, enable);
 434                entries[idx].control = cpu_to_le64(reg);
 435
 436                nfp_nsp_config_set_modified(nsp, true);
 437        }
 438
 439        return nfp_eth_config_commit_end(nsp);
 440}
 441
 442/**
 443 * nfp_eth_set_configured() - set PHY module configured control bit
 444 * @cpp:        NFP CPP handle
 445 * @idx:        NFP chip-wide port index
 446 * @configed:   Desired state
 447 *
 448 * Set the ifup/ifdown state on the PHY.
 449 *
 450 * Return:
 451 * 0 - configuration successful;
 452 * 1 - no changes were needed;
 453 * -ERRNO - configuration failed.
 454 */
 455int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx, bool configed)
 456{
 457        union eth_table_entry *entries;
 458        struct nfp_nsp *nsp;
 459        u64 reg;
 460
 461        nsp = nfp_eth_config_start(cpp, idx);
 462        if (IS_ERR(nsp))
 463                return PTR_ERR(nsp);
 464
 465        /* Older ABI versions did support this feature, however this has only
 466         * been reliable since ABI 20.
 467         */
 468        if (nfp_nsp_get_abi_ver_minor(nsp) < 20) {
 469                nfp_eth_config_cleanup_end(nsp);
 470                return -EOPNOTSUPP;
 471        }
 472
 473        entries = nfp_nsp_config_entries(nsp);
 474
 475        /* Check if we are already in requested state */
 476        reg = le64_to_cpu(entries[idx].state);
 477        if (configed != FIELD_GET(NSP_ETH_STATE_CONFIGURED, reg)) {
 478                reg = le64_to_cpu(entries[idx].control);
 479                reg &= ~NSP_ETH_CTRL_CONFIGURED;
 480                reg |= FIELD_PREP(NSP_ETH_CTRL_CONFIGURED, configed);
 481                entries[idx].control = cpu_to_le64(reg);
 482
 483                nfp_nsp_config_set_modified(nsp, true);
 484        }
 485
 486        return nfp_eth_config_commit_end(nsp);
 487}
 488
 489static int
 490nfp_eth_set_bit_config(struct nfp_nsp *nsp, unsigned int raw_idx,
 491                       const u64 mask, const unsigned int shift,
 492                       unsigned int val, const u64 ctrl_bit)
 493{
 494        union eth_table_entry *entries = nfp_nsp_config_entries(nsp);
 495        unsigned int idx = nfp_nsp_config_idx(nsp);
 496        u64 reg;
 497
 498        /* Note: set features were added in ABI 0.14 but the error
 499         *       codes were initially not populated correctly.
 500         */
 501        if (nfp_nsp_get_abi_ver_minor(nsp) < 17) {
 502                nfp_err(nfp_nsp_cpp(nsp),
 503                        "set operations not supported, please update flash\n");
 504                return -EOPNOTSUPP;
 505        }
 506
 507        /* Check if we are already in requested state */
 508        reg = le64_to_cpu(entries[idx].raw[raw_idx]);
 509        if (val == (reg & mask) >> shift)
 510                return 0;
 511
 512        reg &= ~mask;
 513        reg |= (val << shift) & mask;
 514        entries[idx].raw[raw_idx] = cpu_to_le64(reg);
 515
 516        entries[idx].control |= cpu_to_le64(ctrl_bit);
 517
 518        nfp_nsp_config_set_modified(nsp, true);
 519
 520        return 0;
 521}
 522
 523#define NFP_ETH_SET_BIT_CONFIG(nsp, raw_idx, mask, val, ctrl_bit)       \
 524        ({                                                              \
 525                __BF_FIELD_CHECK(mask, 0ULL, val, "NFP_ETH_SET_BIT_CONFIG: "); \
 526                nfp_eth_set_bit_config(nsp, raw_idx, mask, __bf_shf(mask), \
 527                                       val, ctrl_bit);                  \
 528        })
 529
 530/**
 531 * __nfp_eth_set_aneg() - set PHY autonegotiation control bit
 532 * @nsp:        NFP NSP handle returned from nfp_eth_config_start()
 533 * @mode:       Desired autonegotiation mode
 534 *
 535 * Allow/disallow PHY module to advertise/perform autonegotiation.
 536 * Will write to hwinfo overrides in the flash (persistent config).
 537 *
 538 * Return: 0 or -ERRNO.
 539 */
 540int __nfp_eth_set_aneg(struct nfp_nsp *nsp, enum nfp_eth_aneg mode)
 541{
 542        return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE,
 543                                      NSP_ETH_STATE_ANEG, mode,
 544                                      NSP_ETH_CTRL_SET_ANEG);
 545}
 546
 547/**
 548 * __nfp_eth_set_fec() - set PHY forward error correction control bit
 549 * @nsp:        NFP NSP handle returned from nfp_eth_config_start()
 550 * @mode:       Desired fec mode
 551 *
 552 * Set the PHY module forward error correction mode.
 553 * Will write to hwinfo overrides in the flash (persistent config).
 554 *
 555 * Return: 0 or -ERRNO.
 556 */
 557static int __nfp_eth_set_fec(struct nfp_nsp *nsp, enum nfp_eth_fec mode)
 558{
 559        return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE,
 560                                      NSP_ETH_STATE_FEC, mode,
 561                                      NSP_ETH_CTRL_SET_FEC);
 562}
 563
 564/**
 565 * nfp_eth_set_fec() - set PHY forward error correction control mode
 566 * @cpp:        NFP CPP handle
 567 * @idx:        NFP chip-wide port index
 568 * @mode:       Desired fec mode
 569 *
 570 * Return:
 571 * 0 - configuration successful;
 572 * 1 - no changes were needed;
 573 * -ERRNO - configuration failed.
 574 */
 575int
 576nfp_eth_set_fec(struct nfp_cpp *cpp, unsigned int idx, enum nfp_eth_fec mode)
 577{
 578        struct nfp_nsp *nsp;
 579        int err;
 580
 581        nsp = nfp_eth_config_start(cpp, idx);
 582        if (IS_ERR(nsp))
 583                return PTR_ERR(nsp);
 584
 585        err = __nfp_eth_set_fec(nsp, mode);
 586        if (err) {
 587                nfp_eth_config_cleanup_end(nsp);
 588                return err;
 589        }
 590
 591        return nfp_eth_config_commit_end(nsp);
 592}
 593
 594/**
 595 * __nfp_eth_set_speed() - set interface speed/rate
 596 * @nsp:        NFP NSP handle returned from nfp_eth_config_start()
 597 * @speed:      Desired speed (per lane)
 598 *
 599 * Set lane speed.  Provided @speed value should be subport speed divided
 600 * by number of lanes this subport is spanning (i.e. 10000 for 40G, 25000 for
 601 * 50G, etc.)
 602 * Will write to hwinfo overrides in the flash (persistent config).
 603 *
 604 * Return: 0 or -ERRNO.
 605 */
 606int __nfp_eth_set_speed(struct nfp_nsp *nsp, unsigned int speed)
 607{
 608        enum nfp_eth_rate rate;
 609
 610        rate = nfp_eth_speed2rate(speed);
 611        if (rate == RATE_INVALID) {
 612                nfp_warn(nfp_nsp_cpp(nsp),
 613                         "could not find matching lane rate for speed %u\n",
 614                         speed);
 615                return -EINVAL;
 616        }
 617
 618        return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE,
 619                                      NSP_ETH_STATE_RATE, rate,
 620                                      NSP_ETH_CTRL_SET_RATE);
 621}
 622
 623/**
 624 * __nfp_eth_set_split() - set interface lane split
 625 * @nsp:        NFP NSP handle returned from nfp_eth_config_start()
 626 * @lanes:      Desired lanes per port
 627 *
 628 * Set number of lanes in the port.
 629 * Will write to hwinfo overrides in the flash (persistent config).
 630 *
 631 * Return: 0 or -ERRNO.
 632 */
 633int __nfp_eth_set_split(struct nfp_nsp *nsp, unsigned int lanes)
 634{
 635        return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_PORT, NSP_ETH_PORT_LANES,
 636                                      lanes, NSP_ETH_CTRL_SET_LANES);
 637}
 638