linux/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
   2
   3/* Ethtool support for Mellanox Gigabit Ethernet driver
   4 *
   5 * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
   6 */
   7
   8#include <linux/phy.h>
   9
  10#include "mlxbf_gige.h"
  11#include "mlxbf_gige_regs.h"
  12
  13/* Start of struct ethtool_ops functions */
  14static int mlxbf_gige_get_regs_len(struct net_device *netdev)
  15{
  16        return MLXBF_GIGE_MMIO_REG_SZ;
  17}
  18
  19static void mlxbf_gige_get_regs(struct net_device *netdev,
  20                                struct ethtool_regs *regs, void *p)
  21{
  22        struct mlxbf_gige *priv = netdev_priv(netdev);
  23
  24        regs->version = MLXBF_GIGE_REGS_VERSION;
  25
  26        /* Read entire MMIO register space and store results
  27         * into the provided buffer. Each 64-bit word is converted
  28         * to big-endian to make the output more readable.
  29         *
  30         * NOTE: by design, a read to an offset without an existing
  31         *       register will be acknowledged and return zero.
  32         */
  33        memcpy_fromio(p, priv->base, MLXBF_GIGE_MMIO_REG_SZ);
  34}
  35
  36static void mlxbf_gige_get_ringparam(struct net_device *netdev,
  37                                     struct ethtool_ringparam *ering)
  38{
  39        struct mlxbf_gige *priv = netdev_priv(netdev);
  40
  41        ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ;
  42        ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ;
  43        ering->rx_pending = priv->rx_q_entries;
  44        ering->tx_pending = priv->tx_q_entries;
  45}
  46
  47static const struct {
  48        const char string[ETH_GSTRING_LEN];
  49} mlxbf_gige_ethtool_stats_keys[] = {
  50        { "hw_access_errors" },
  51        { "tx_invalid_checksums" },
  52        { "tx_small_frames" },
  53        { "tx_index_errors" },
  54        { "sw_config_errors" },
  55        { "sw_access_errors" },
  56        { "rx_truncate_errors" },
  57        { "rx_mac_errors" },
  58        { "rx_din_dropped_pkts" },
  59        { "tx_fifo_full" },
  60        { "rx_filter_passed_pkts" },
  61        { "rx_filter_discard_pkts" },
  62};
  63
  64static int mlxbf_gige_get_sset_count(struct net_device *netdev, int stringset)
  65{
  66        if (stringset != ETH_SS_STATS)
  67                return -EOPNOTSUPP;
  68        return ARRAY_SIZE(mlxbf_gige_ethtool_stats_keys);
  69}
  70
  71static void mlxbf_gige_get_strings(struct net_device *netdev, u32 stringset,
  72                                   u8 *buf)
  73{
  74        if (stringset != ETH_SS_STATS)
  75                return;
  76        memcpy(buf, &mlxbf_gige_ethtool_stats_keys,
  77               sizeof(mlxbf_gige_ethtool_stats_keys));
  78}
  79
  80static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev,
  81                                         struct ethtool_stats *estats,
  82                                         u64 *data)
  83{
  84        struct mlxbf_gige *priv = netdev_priv(netdev);
  85
  86        /* Fill data array with interface statistics
  87         *
  88         * NOTE: the data writes must be in
  89         *       sync with the strings shown in
  90         *       the mlxbf_gige_ethtool_stats_keys[] array
  91         *
  92         * NOTE2: certain statistics below are zeroed upon
  93         *        port disable, so the calculation below
  94         *        must include the "cached" value of the stat
  95         *        plus the value read directly from hardware.
  96         *        Cached statistics are currently:
  97         *          rx_din_dropped_pkts
  98         *          rx_filter_passed_pkts
  99         *          rx_filter_discard_pkts
 100         */
 101        *data++ = priv->stats.hw_access_errors;
 102        *data++ = priv->stats.tx_invalid_checksums;
 103        *data++ = priv->stats.tx_small_frames;
 104        *data++ = priv->stats.tx_index_errors;
 105        *data++ = priv->stats.sw_config_errors;
 106        *data++ = priv->stats.sw_access_errors;
 107        *data++ = priv->stats.rx_truncate_errors;
 108        *data++ = priv->stats.rx_mac_errors;
 109        *data++ = (priv->stats.rx_din_dropped_pkts +
 110                   readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER));
 111        *data++ = priv->stats.tx_fifo_full;
 112        *data++ = (priv->stats.rx_filter_passed_pkts +
 113                   readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL));
 114        *data++ = (priv->stats.rx_filter_discard_pkts +
 115                   readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL));
 116}
 117
 118static void mlxbf_gige_get_pauseparam(struct net_device *netdev,
 119                                      struct ethtool_pauseparam *pause)
 120{
 121        pause->autoneg = AUTONEG_DISABLE;
 122        pause->rx_pause = 1;
 123        pause->tx_pause = 1;
 124}
 125
 126const struct ethtool_ops mlxbf_gige_ethtool_ops = {
 127        .get_link               = ethtool_op_get_link,
 128        .get_ringparam          = mlxbf_gige_get_ringparam,
 129        .get_regs_len           = mlxbf_gige_get_regs_len,
 130        .get_regs               = mlxbf_gige_get_regs,
 131        .get_strings            = mlxbf_gige_get_strings,
 132        .get_sset_count         = mlxbf_gige_get_sset_count,
 133        .get_ethtool_stats      = mlxbf_gige_get_ethtool_stats,
 134        .nway_reset             = phy_ethtool_nway_reset,
 135        .get_pauseparam         = mlxbf_gige_get_pauseparam,
 136        .get_link_ksettings     = phy_ethtool_get_link_ksettings,
 137};
 138