linux/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 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/*
  35 * nfp_net_ethtool.c
  36 * Netronome network device driver: ethtool support
  37 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
  38 *          Jason McMullan <jason.mcmullan@netronome.com>
  39 *          Rolf Neugebauer <rolf.neugebauer@netronome.com>
  40 *          Brad Petrus <brad.petrus@netronome.com>
  41 */
  42
  43#include <linux/version.h>
  44#include <linux/kernel.h>
  45#include <linux/netdevice.h>
  46#include <linux/etherdevice.h>
  47#include <linux/interrupt.h>
  48#include <linux/pci.h>
  49#include <linux/ethtool.h>
  50
  51#include "nfp_net_ctrl.h"
  52#include "nfp_net.h"
  53
  54/* Support for stats. Returns netdev, driver, and device stats */
  55enum { NETDEV_ET_STATS, NFP_NET_DRV_ET_STATS, NFP_NET_DEV_ET_STATS };
  56struct _nfp_net_et_stats {
  57        char name[ETH_GSTRING_LEN];
  58        int type;
  59        int sz;
  60        int off;
  61};
  62
  63#define NN_ET_NETDEV_STAT(m) NETDEV_ET_STATS,                   \
  64                FIELD_SIZEOF(struct net_device_stats, m),       \
  65                offsetof(struct net_device_stats, m)
  66/* For stats in the control BAR (other than Q stats) */
  67#define NN_ET_DEV_STAT(m) NFP_NET_DEV_ET_STATS,                 \
  68                sizeof(u64),                                    \
  69                (m)
  70static const struct _nfp_net_et_stats nfp_net_et_stats[] = {
  71        /* netdev stats */
  72        {"rx_packets", NN_ET_NETDEV_STAT(rx_packets)},
  73        {"tx_packets", NN_ET_NETDEV_STAT(tx_packets)},
  74        {"rx_bytes", NN_ET_NETDEV_STAT(rx_bytes)},
  75        {"tx_bytes", NN_ET_NETDEV_STAT(tx_bytes)},
  76        {"rx_errors", NN_ET_NETDEV_STAT(rx_errors)},
  77        {"tx_errors", NN_ET_NETDEV_STAT(tx_errors)},
  78        {"rx_dropped", NN_ET_NETDEV_STAT(rx_dropped)},
  79        {"tx_dropped", NN_ET_NETDEV_STAT(tx_dropped)},
  80        {"multicast", NN_ET_NETDEV_STAT(multicast)},
  81        {"collisions", NN_ET_NETDEV_STAT(collisions)},
  82        {"rx_over_errors", NN_ET_NETDEV_STAT(rx_over_errors)},
  83        {"rx_crc_errors", NN_ET_NETDEV_STAT(rx_crc_errors)},
  84        {"rx_frame_errors", NN_ET_NETDEV_STAT(rx_frame_errors)},
  85        {"rx_fifo_errors", NN_ET_NETDEV_STAT(rx_fifo_errors)},
  86        {"rx_missed_errors", NN_ET_NETDEV_STAT(rx_missed_errors)},
  87        {"tx_aborted_errors", NN_ET_NETDEV_STAT(tx_aborted_errors)},
  88        {"tx_carrier_errors", NN_ET_NETDEV_STAT(tx_carrier_errors)},
  89        {"tx_fifo_errors", NN_ET_NETDEV_STAT(tx_fifo_errors)},
  90        /* Stats from the device */
  91        {"dev_rx_discards", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_DISCARDS)},
  92        {"dev_rx_errors", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_ERRORS)},
  93        {"dev_rx_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_OCTETS)},
  94        {"dev_rx_uc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_UC_OCTETS)},
  95        {"dev_rx_mc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_MC_OCTETS)},
  96        {"dev_rx_bc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_BC_OCTETS)},
  97        {"dev_rx_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_FRAMES)},
  98        {"dev_rx_mc_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_MC_FRAMES)},
  99        {"dev_rx_bc_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_RX_BC_FRAMES)},
 100
 101        {"dev_tx_discards", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_DISCARDS)},
 102        {"dev_tx_errors", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_ERRORS)},
 103        {"dev_tx_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_OCTETS)},
 104        {"dev_tx_uc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_UC_OCTETS)},
 105        {"dev_tx_mc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_MC_OCTETS)},
 106        {"dev_tx_bc_bytes", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_BC_OCTETS)},
 107        {"dev_tx_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_FRAMES)},
 108        {"dev_tx_mc_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_MC_FRAMES)},
 109        {"dev_tx_bc_pkts", NN_ET_DEV_STAT(NFP_NET_CFG_STATS_TX_BC_FRAMES)},
 110};
 111
 112#define NN_ET_GLOBAL_STATS_LEN ARRAY_SIZE(nfp_net_et_stats)
 113#define NN_ET_RVEC_STATS_LEN (nn->num_r_vecs * 3)
 114#define NN_ET_RVEC_GATHER_STATS 7
 115#define NN_ET_QUEUE_STATS_LEN ((nn->num_tx_rings + nn->num_rx_rings) * 2)
 116#define NN_ET_STATS_LEN (NN_ET_GLOBAL_STATS_LEN + NN_ET_RVEC_GATHER_STATS + \
 117                         NN_ET_RVEC_STATS_LEN + NN_ET_QUEUE_STATS_LEN)
 118
 119static void nfp_net_get_drvinfo(struct net_device *netdev,
 120                                struct ethtool_drvinfo *drvinfo)
 121{
 122        struct nfp_net *nn = netdev_priv(netdev);
 123
 124        strlcpy(drvinfo->driver, nfp_net_driver_name, sizeof(drvinfo->driver));
 125        strlcpy(drvinfo->version, nfp_net_driver_version,
 126                sizeof(drvinfo->version));
 127
 128        snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
 129                 "%d.%d.%d.%d",
 130                 nn->fw_ver.resv, nn->fw_ver.class,
 131                 nn->fw_ver.major, nn->fw_ver.minor);
 132        strlcpy(drvinfo->bus_info, pci_name(nn->pdev),
 133                sizeof(drvinfo->bus_info));
 134
 135        drvinfo->n_stats = NN_ET_STATS_LEN;
 136        drvinfo->regdump_len = NFP_NET_CFG_BAR_SZ;
 137}
 138
 139static void nfp_net_get_ringparam(struct net_device *netdev,
 140                                  struct ethtool_ringparam *ring)
 141{
 142        struct nfp_net *nn = netdev_priv(netdev);
 143
 144        ring->rx_max_pending = NFP_NET_MAX_RX_DESCS;
 145        ring->tx_max_pending = NFP_NET_MAX_TX_DESCS;
 146        ring->rx_pending = nn->rxd_cnt;
 147        ring->tx_pending = nn->txd_cnt;
 148}
 149
 150static int nfp_net_set_ringparam(struct net_device *netdev,
 151                                 struct ethtool_ringparam *ring)
 152{
 153        struct nfp_net *nn = netdev_priv(netdev);
 154        u32 rxd_cnt, txd_cnt;
 155
 156        if (netif_running(netdev)) {
 157                /* Some NIC drivers allow reconfiguration on the fly,
 158                 * some down the interface, change and then up it
 159                 * again.  For now we don't allow changes when the
 160                 * device is up.
 161                 */
 162                nn_warn(nn, "Can't change rings while device is up\n");
 163                return -EBUSY;
 164        }
 165
 166        /* We don't have separate queues/rings for small/large frames. */
 167        if (ring->rx_mini_pending || ring->rx_jumbo_pending)
 168                return -EINVAL;
 169
 170        /* Round up to supported values */
 171        rxd_cnt = roundup_pow_of_two(ring->rx_pending);
 172        rxd_cnt = max_t(u32, rxd_cnt, NFP_NET_MIN_RX_DESCS);
 173        rxd_cnt = min_t(u32, rxd_cnt, NFP_NET_MAX_RX_DESCS);
 174
 175        txd_cnt = roundup_pow_of_two(ring->tx_pending);
 176        txd_cnt = max_t(u32, txd_cnt, NFP_NET_MIN_TX_DESCS);
 177        txd_cnt = min_t(u32, txd_cnt, NFP_NET_MAX_TX_DESCS);
 178
 179        if (nn->rxd_cnt != rxd_cnt || nn->txd_cnt != txd_cnt)
 180                nn_dbg(nn, "Change ring size: RxQ %u->%u, TxQ %u->%u\n",
 181                       nn->rxd_cnt, rxd_cnt, nn->txd_cnt, txd_cnt);
 182
 183        nn->rxd_cnt = rxd_cnt;
 184        nn->txd_cnt = txd_cnt;
 185
 186        return 0;
 187}
 188
 189static void nfp_net_get_strings(struct net_device *netdev,
 190                                u32 stringset, u8 *data)
 191{
 192        struct nfp_net *nn = netdev_priv(netdev);
 193        u8 *p = data;
 194        int i;
 195
 196        switch (stringset) {
 197        case ETH_SS_STATS:
 198                for (i = 0; i < NN_ET_GLOBAL_STATS_LEN; i++) {
 199                        memcpy(p, nfp_net_et_stats[i].name, ETH_GSTRING_LEN);
 200                        p += ETH_GSTRING_LEN;
 201                }
 202                for (i = 0; i < nn->num_r_vecs; i++) {
 203                        sprintf(p, "rvec_%u_rx_pkts", i);
 204                        p += ETH_GSTRING_LEN;
 205                        sprintf(p, "rvec_%u_tx_pkts", i);
 206                        p += ETH_GSTRING_LEN;
 207                        sprintf(p, "rvec_%u_tx_busy", i);
 208                        p += ETH_GSTRING_LEN;
 209                }
 210                strncpy(p, "hw_rx_csum_ok", ETH_GSTRING_LEN);
 211                p += ETH_GSTRING_LEN;
 212                strncpy(p, "hw_rx_csum_inner_ok", ETH_GSTRING_LEN);
 213                p += ETH_GSTRING_LEN;
 214                strncpy(p, "hw_rx_csum_err", ETH_GSTRING_LEN);
 215                p += ETH_GSTRING_LEN;
 216                strncpy(p, "hw_tx_csum", ETH_GSTRING_LEN);
 217                p += ETH_GSTRING_LEN;
 218                strncpy(p, "hw_tx_inner_csum", ETH_GSTRING_LEN);
 219                p += ETH_GSTRING_LEN;
 220                strncpy(p, "tx_gather", ETH_GSTRING_LEN);
 221                p += ETH_GSTRING_LEN;
 222                strncpy(p, "tx_lso", ETH_GSTRING_LEN);
 223                p += ETH_GSTRING_LEN;
 224                for (i = 0; i < nn->num_tx_rings; i++) {
 225                        sprintf(p, "txq_%u_pkts", i);
 226                        p += ETH_GSTRING_LEN;
 227                        sprintf(p, "txq_%u_bytes", i);
 228                        p += ETH_GSTRING_LEN;
 229                }
 230                for (i = 0; i < nn->num_rx_rings; i++) {
 231                        sprintf(p, "rxq_%u_pkts", i);
 232                        p += ETH_GSTRING_LEN;
 233                        sprintf(p, "rxq_%u_bytes", i);
 234                        p += ETH_GSTRING_LEN;
 235                }
 236                break;
 237        }
 238}
 239
 240static void nfp_net_get_stats(struct net_device *netdev,
 241                              struct ethtool_stats *stats, u64 *data)
 242{
 243        u64 gathered_stats[NN_ET_RVEC_GATHER_STATS] = {};
 244        struct nfp_net *nn = netdev_priv(netdev);
 245        struct rtnl_link_stats64 *netdev_stats;
 246        struct rtnl_link_stats64 temp = {};
 247        u64 tmp[NN_ET_RVEC_GATHER_STATS];
 248        u8 __iomem *io_p;
 249        int i, j, k;
 250        u8 *p;
 251
 252        netdev_stats = dev_get_stats(netdev, &temp);
 253
 254        for (i = 0; i < NN_ET_GLOBAL_STATS_LEN; i++) {
 255                switch (nfp_net_et_stats[i].type) {
 256                case NETDEV_ET_STATS:
 257                        p = (char *)netdev_stats + nfp_net_et_stats[i].off;
 258                        data[i] = nfp_net_et_stats[i].sz == sizeof(u64) ?
 259                                *(u64 *)p : *(u32 *)p;
 260                        break;
 261
 262                case NFP_NET_DEV_ET_STATS:
 263                        io_p = nn->ctrl_bar + nfp_net_et_stats[i].off;
 264                        data[i] = readq(io_p);
 265                        break;
 266                }
 267        }
 268        for (j = 0; j < nn->num_r_vecs; j++) {
 269                unsigned int start;
 270
 271                do {
 272                        start = u64_stats_fetch_begin(&nn->r_vecs[j].rx_sync);
 273                        data[i++] = nn->r_vecs[j].rx_pkts;
 274                        tmp[0] = nn->r_vecs[j].hw_csum_rx_ok;
 275                        tmp[1] = nn->r_vecs[j].hw_csum_rx_inner_ok;
 276                        tmp[2] = nn->r_vecs[j].hw_csum_rx_error;
 277                } while (u64_stats_fetch_retry(&nn->r_vecs[j].rx_sync, start));
 278
 279                do {
 280                        start = u64_stats_fetch_begin(&nn->r_vecs[j].tx_sync);
 281                        data[i++] = nn->r_vecs[j].tx_pkts;
 282                        data[i++] = nn->r_vecs[j].tx_busy;
 283                        tmp[3] = nn->r_vecs[j].hw_csum_tx;
 284                        tmp[4] = nn->r_vecs[j].hw_csum_tx_inner;
 285                        tmp[5] = nn->r_vecs[j].tx_gather;
 286                        tmp[6] = nn->r_vecs[j].tx_lso;
 287                } while (u64_stats_fetch_retry(&nn->r_vecs[j].tx_sync, start));
 288
 289                for (k = 0; k < NN_ET_RVEC_GATHER_STATS; k++)
 290                        gathered_stats[k] += tmp[k];
 291        }
 292        for (j = 0; j < NN_ET_RVEC_GATHER_STATS; j++)
 293                data[i++] = gathered_stats[j];
 294        for (j = 0; j < nn->num_tx_rings; j++) {
 295                io_p = nn->ctrl_bar + NFP_NET_CFG_TXR_STATS(j);
 296                data[i++] = readq(io_p);
 297                io_p = nn->ctrl_bar + NFP_NET_CFG_TXR_STATS(j) + 8;
 298                data[i++] = readq(io_p);
 299        }
 300        for (j = 0; j < nn->num_rx_rings; j++) {
 301                io_p = nn->ctrl_bar + NFP_NET_CFG_RXR_STATS(j);
 302                data[i++] = readq(io_p);
 303                io_p = nn->ctrl_bar + NFP_NET_CFG_RXR_STATS(j) + 8;
 304                data[i++] = readq(io_p);
 305        }
 306}
 307
 308static int nfp_net_get_sset_count(struct net_device *netdev, int sset)
 309{
 310        struct nfp_net *nn = netdev_priv(netdev);
 311
 312        switch (sset) {
 313        case ETH_SS_STATS:
 314                return NN_ET_STATS_LEN;
 315        default:
 316                return -EOPNOTSUPP;
 317        }
 318}
 319
 320/* RX network flow classification (RSS, filters, etc)
 321 */
 322static u32 ethtool_flow_to_nfp_flag(u32 flow_type)
 323{
 324        static const u32 xlate_ethtool_to_nfp[IPV6_FLOW + 1] = {
 325                [TCP_V4_FLOW]   = NFP_NET_CFG_RSS_IPV4_TCP,
 326                [TCP_V6_FLOW]   = NFP_NET_CFG_RSS_IPV6_TCP,
 327                [UDP_V4_FLOW]   = NFP_NET_CFG_RSS_IPV4_UDP,
 328                [UDP_V6_FLOW]   = NFP_NET_CFG_RSS_IPV6_UDP,
 329                [IPV4_FLOW]     = NFP_NET_CFG_RSS_IPV4,
 330                [IPV6_FLOW]     = NFP_NET_CFG_RSS_IPV6,
 331        };
 332
 333        if (flow_type >= ARRAY_SIZE(xlate_ethtool_to_nfp))
 334                return 0;
 335
 336        return xlate_ethtool_to_nfp[flow_type];
 337}
 338
 339static int nfp_net_get_rss_hash_opts(struct nfp_net *nn,
 340                                     struct ethtool_rxnfc *cmd)
 341{
 342        u32 nfp_rss_flag;
 343
 344        cmd->data = 0;
 345
 346        if (!(nn->cap & NFP_NET_CFG_CTRL_RSS))
 347                return -EOPNOTSUPP;
 348
 349        nfp_rss_flag = ethtool_flow_to_nfp_flag(cmd->flow_type);
 350        if (!nfp_rss_flag)
 351                return -EINVAL;
 352
 353        cmd->data |= RXH_IP_SRC | RXH_IP_DST;
 354        if (nn->rss_cfg & nfp_rss_flag)
 355                cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
 356
 357        return 0;
 358}
 359
 360static int nfp_net_get_rxnfc(struct net_device *netdev,
 361                             struct ethtool_rxnfc *cmd, u32 *rule_locs)
 362{
 363        struct nfp_net *nn = netdev_priv(netdev);
 364
 365        switch (cmd->cmd) {
 366        case ETHTOOL_GRXRINGS:
 367                cmd->data = nn->num_rx_rings;
 368                return 0;
 369        case ETHTOOL_GRXFH:
 370                return nfp_net_get_rss_hash_opts(nn, cmd);
 371        default:
 372                return -EOPNOTSUPP;
 373        }
 374}
 375
 376static int nfp_net_set_rss_hash_opt(struct nfp_net *nn,
 377                                    struct ethtool_rxnfc *nfc)
 378{
 379        u32 new_rss_cfg = nn->rss_cfg;
 380        u32 nfp_rss_flag;
 381        int err;
 382
 383        if (!(nn->cap & NFP_NET_CFG_CTRL_RSS))
 384                return -EOPNOTSUPP;
 385
 386        /* RSS only supports IP SA/DA and L4 src/dst ports  */
 387        if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
 388                          RXH_L4_B_0_1 | RXH_L4_B_2_3))
 389                return -EINVAL;
 390
 391        /* We need at least the IP SA/DA fields for hashing */
 392        if (!(nfc->data & RXH_IP_SRC) ||
 393            !(nfc->data & RXH_IP_DST))
 394                return -EINVAL;
 395
 396        nfp_rss_flag = ethtool_flow_to_nfp_flag(nfc->flow_type);
 397        if (!nfp_rss_flag)
 398                return -EINVAL;
 399
 400        switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
 401        case 0:
 402                new_rss_cfg &= ~nfp_rss_flag;
 403                break;
 404        case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
 405                new_rss_cfg |= nfp_rss_flag;
 406                break;
 407        default:
 408                return -EINVAL;
 409        }
 410
 411        new_rss_cfg |= NFP_NET_CFG_RSS_TOEPLITZ;
 412        new_rss_cfg |= NFP_NET_CFG_RSS_MASK;
 413
 414        if (new_rss_cfg == nn->rss_cfg)
 415                return 0;
 416
 417        writel(new_rss_cfg, nn->ctrl_bar + NFP_NET_CFG_RSS_CTRL);
 418        err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_RSS);
 419        if (err)
 420                return err;
 421
 422        nn->rss_cfg = new_rss_cfg;
 423
 424        nn_dbg(nn, "Changed RSS config to 0x%x\n", nn->rss_cfg);
 425        return 0;
 426}
 427
 428static int nfp_net_set_rxnfc(struct net_device *netdev,
 429                             struct ethtool_rxnfc *cmd)
 430{
 431        struct nfp_net *nn = netdev_priv(netdev);
 432
 433        switch (cmd->cmd) {
 434        case ETHTOOL_SRXFH:
 435                return nfp_net_set_rss_hash_opt(nn, cmd);
 436        default:
 437                return -EOPNOTSUPP;
 438        }
 439}
 440
 441static u32 nfp_net_get_rxfh_indir_size(struct net_device *netdev)
 442{
 443        struct nfp_net *nn = netdev_priv(netdev);
 444
 445        if (!(nn->cap & NFP_NET_CFG_CTRL_RSS))
 446                return 0;
 447
 448        return ARRAY_SIZE(nn->rss_itbl);
 449}
 450
 451static u32 nfp_net_get_rxfh_key_size(struct net_device *netdev)
 452{
 453        return NFP_NET_CFG_RSS_KEY_SZ;
 454}
 455
 456static int nfp_net_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
 457                            u8 *hfunc)
 458{
 459        struct nfp_net *nn = netdev_priv(netdev);
 460        int i;
 461
 462        if (!(nn->cap & NFP_NET_CFG_CTRL_RSS))
 463                return -EOPNOTSUPP;
 464
 465        if (indir)
 466                for (i = 0; i < ARRAY_SIZE(nn->rss_itbl); i++)
 467                        indir[i] = nn->rss_itbl[i];
 468        if (key)
 469                memcpy(key, nn->rss_key, NFP_NET_CFG_RSS_KEY_SZ);
 470        if (hfunc)
 471                *hfunc = ETH_RSS_HASH_TOP;
 472
 473        return 0;
 474}
 475
 476static int nfp_net_set_rxfh(struct net_device *netdev,
 477                            const u32 *indir, const u8 *key,
 478                            const u8 hfunc)
 479{
 480        struct nfp_net *nn = netdev_priv(netdev);
 481        int i;
 482
 483        if (!(nn->cap & NFP_NET_CFG_CTRL_RSS) ||
 484            !(hfunc == ETH_RSS_HASH_NO_CHANGE || hfunc == ETH_RSS_HASH_TOP))
 485                return -EOPNOTSUPP;
 486
 487        if (!key && !indir)
 488                return 0;
 489
 490        if (key) {
 491                memcpy(nn->rss_key, key, NFP_NET_CFG_RSS_KEY_SZ);
 492                nfp_net_rss_write_key(nn);
 493        }
 494        if (indir) {
 495                for (i = 0; i < ARRAY_SIZE(nn->rss_itbl); i++)
 496                        nn->rss_itbl[i] = indir[i];
 497
 498                nfp_net_rss_write_itbl(nn);
 499        }
 500
 501        return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_RSS);
 502}
 503
 504/* Dump BAR registers
 505 */
 506static int nfp_net_get_regs_len(struct net_device *netdev)
 507{
 508        return NFP_NET_CFG_BAR_SZ;
 509}
 510
 511static void nfp_net_get_regs(struct net_device *netdev,
 512                             struct ethtool_regs *regs, void *p)
 513{
 514        struct nfp_net *nn = netdev_priv(netdev);
 515        u32 *regs_buf = p;
 516        int i;
 517
 518        regs->version = nn_readl(nn, NFP_NET_CFG_VERSION);
 519
 520        for (i = 0; i < NFP_NET_CFG_BAR_SZ / sizeof(u32); i++)
 521                regs_buf[i] = readl(nn->ctrl_bar + (i * sizeof(u32)));
 522}
 523
 524static int nfp_net_get_coalesce(struct net_device *netdev,
 525                                struct ethtool_coalesce *ec)
 526{
 527        struct nfp_net *nn = netdev_priv(netdev);
 528
 529        if (!(nn->cap & NFP_NET_CFG_CTRL_IRQMOD))
 530                return -EINVAL;
 531
 532        ec->rx_coalesce_usecs       = nn->rx_coalesce_usecs;
 533        ec->rx_max_coalesced_frames = nn->rx_coalesce_max_frames;
 534        ec->tx_coalesce_usecs       = nn->tx_coalesce_usecs;
 535        ec->tx_max_coalesced_frames = nn->tx_coalesce_max_frames;
 536
 537        return 0;
 538}
 539
 540static int nfp_net_set_coalesce(struct net_device *netdev,
 541                                struct ethtool_coalesce *ec)
 542{
 543        struct nfp_net *nn = netdev_priv(netdev);
 544        unsigned int factor;
 545
 546        if (ec->rx_coalesce_usecs_irq ||
 547            ec->rx_max_coalesced_frames_irq ||
 548            ec->tx_coalesce_usecs_irq ||
 549            ec->tx_max_coalesced_frames_irq ||
 550            ec->stats_block_coalesce_usecs ||
 551            ec->use_adaptive_rx_coalesce ||
 552            ec->use_adaptive_tx_coalesce ||
 553            ec->pkt_rate_low ||
 554            ec->rx_coalesce_usecs_low ||
 555            ec->rx_max_coalesced_frames_low ||
 556            ec->tx_coalesce_usecs_low ||
 557            ec->tx_max_coalesced_frames_low ||
 558            ec->pkt_rate_high ||
 559            ec->rx_coalesce_usecs_high ||
 560            ec->rx_max_coalesced_frames_high ||
 561            ec->tx_coalesce_usecs_high ||
 562            ec->tx_max_coalesced_frames_high ||
 563            ec->rate_sample_interval)
 564                return -ENOTSUPP;
 565
 566        /* Compute factor used to convert coalesce '_usecs' parameters to
 567         * ME timestamp ticks.  There are 16 ME clock cycles for each timestamp
 568         * count.
 569         */
 570        factor = nn->me_freq_mhz / 16;
 571
 572        /* Each pair of (usecs, max_frames) fields specifies that interrupts
 573         * should be coalesced until
 574         *      (usecs > 0 && time_since_first_completion >= usecs) ||
 575         *      (max_frames > 0 && completed_frames >= max_frames)
 576         *
 577         * It is illegal to set both usecs and max_frames to zero as this would
 578         * cause interrupts to never be generated.  To disable coalescing, set
 579         * usecs = 0 and max_frames = 1.
 580         *
 581         * Some implementations ignore the value of max_frames and use the
 582         * condition time_since_first_completion >= usecs
 583         */
 584
 585        if (!(nn->cap & NFP_NET_CFG_CTRL_IRQMOD))
 586                return -EINVAL;
 587
 588        /* ensure valid configuration */
 589        if (!ec->rx_coalesce_usecs && !ec->rx_max_coalesced_frames)
 590                return -EINVAL;
 591
 592        if (!ec->tx_coalesce_usecs && !ec->tx_max_coalesced_frames)
 593                return -EINVAL;
 594
 595        if (ec->rx_coalesce_usecs * factor >= ((1 << 16) - 1))
 596                return -EINVAL;
 597
 598        if (ec->tx_coalesce_usecs * factor >= ((1 << 16) - 1))
 599                return -EINVAL;
 600
 601        if (ec->rx_max_coalesced_frames >= ((1 << 16) - 1))
 602                return -EINVAL;
 603
 604        if (ec->tx_max_coalesced_frames >= ((1 << 16) - 1))
 605                return -EINVAL;
 606
 607        /* configuration is valid */
 608        nn->rx_coalesce_usecs      = ec->rx_coalesce_usecs;
 609        nn->rx_coalesce_max_frames = ec->rx_max_coalesced_frames;
 610        nn->tx_coalesce_usecs      = ec->tx_coalesce_usecs;
 611        nn->tx_coalesce_max_frames = ec->tx_max_coalesced_frames;
 612
 613        /* write configuration to device */
 614        nfp_net_coalesce_write_cfg(nn);
 615        return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_IRQMOD);
 616}
 617
 618static const struct ethtool_ops nfp_net_ethtool_ops = {
 619        .get_drvinfo            = nfp_net_get_drvinfo,
 620        .get_ringparam          = nfp_net_get_ringparam,
 621        .set_ringparam          = nfp_net_set_ringparam,
 622        .get_strings            = nfp_net_get_strings,
 623        .get_ethtool_stats      = nfp_net_get_stats,
 624        .get_sset_count         = nfp_net_get_sset_count,
 625        .get_rxnfc              = nfp_net_get_rxnfc,
 626        .set_rxnfc              = nfp_net_set_rxnfc,
 627        .get_rxfh_indir_size    = nfp_net_get_rxfh_indir_size,
 628        .get_rxfh_key_size      = nfp_net_get_rxfh_key_size,
 629        .get_rxfh               = nfp_net_get_rxfh,
 630        .set_rxfh               = nfp_net_set_rxfh,
 631        .get_regs_len           = nfp_net_get_regs_len,
 632        .get_regs               = nfp_net_get_regs,
 633        .get_coalesce           = nfp_net_get_coalesce,
 634        .set_coalesce           = nfp_net_set_coalesce,
 635};
 636
 637void nfp_net_set_ethtool_ops(struct net_device *netdev)
 638{
 639        netdev->ethtool_ops = &nfp_net_ethtool_ops;
 640}
 641