Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
0002 
0003 /* Ethtool support for Mellanox Gigabit Ethernet driver
0004  *
0005  * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES
0006  */
0007 
0008 #include <linux/phy.h>
0009 
0010 #include "mlxbf_gige.h"
0011 #include "mlxbf_gige_regs.h"
0012 
0013 /* Start of struct ethtool_ops functions */
0014 static int mlxbf_gige_get_regs_len(struct net_device *netdev)
0015 {
0016     return MLXBF_GIGE_MMIO_REG_SZ;
0017 }
0018 
0019 static void mlxbf_gige_get_regs(struct net_device *netdev,
0020                 struct ethtool_regs *regs, void *p)
0021 {
0022     struct mlxbf_gige *priv = netdev_priv(netdev);
0023 
0024     regs->version = MLXBF_GIGE_REGS_VERSION;
0025 
0026     /* Read entire MMIO register space and store results
0027      * into the provided buffer. By design, a read to an
0028      * offset without an existing register will be
0029      * acknowledged and return zero.
0030      */
0031     memcpy_fromio(p, priv->base, MLXBF_GIGE_MMIO_REG_SZ);
0032 }
0033 
0034 static void
0035 mlxbf_gige_get_ringparam(struct net_device *netdev,
0036              struct ethtool_ringparam *ering,
0037              struct kernel_ethtool_ringparam *kernel_ering,
0038              struct netlink_ext_ack *extack)
0039 {
0040     struct mlxbf_gige *priv = netdev_priv(netdev);
0041 
0042     ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ;
0043     ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ;
0044     ering->rx_pending = priv->rx_q_entries;
0045     ering->tx_pending = priv->tx_q_entries;
0046 }
0047 
0048 static const struct {
0049     const char string[ETH_GSTRING_LEN];
0050 } mlxbf_gige_ethtool_stats_keys[] = {
0051     { "hw_access_errors" },
0052     { "tx_invalid_checksums" },
0053     { "tx_small_frames" },
0054     { "tx_index_errors" },
0055     { "sw_config_errors" },
0056     { "sw_access_errors" },
0057     { "rx_truncate_errors" },
0058     { "rx_mac_errors" },
0059     { "rx_din_dropped_pkts" },
0060     { "tx_fifo_full" },
0061     { "rx_filter_passed_pkts" },
0062     { "rx_filter_discard_pkts" },
0063 };
0064 
0065 static int mlxbf_gige_get_sset_count(struct net_device *netdev, int stringset)
0066 {
0067     if (stringset != ETH_SS_STATS)
0068         return -EOPNOTSUPP;
0069     return ARRAY_SIZE(mlxbf_gige_ethtool_stats_keys);
0070 }
0071 
0072 static void mlxbf_gige_get_strings(struct net_device *netdev, u32 stringset,
0073                    u8 *buf)
0074 {
0075     if (stringset != ETH_SS_STATS)
0076         return;
0077     memcpy(buf, &mlxbf_gige_ethtool_stats_keys,
0078            sizeof(mlxbf_gige_ethtool_stats_keys));
0079 }
0080 
0081 static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev,
0082                      struct ethtool_stats *estats,
0083                      u64 *data)
0084 {
0085     struct mlxbf_gige *priv = netdev_priv(netdev);
0086 
0087     /* Fill data array with interface statistics
0088      *
0089      * NOTE: the data writes must be in
0090      *       sync with the strings shown in
0091      *       the mlxbf_gige_ethtool_stats_keys[] array
0092      *
0093      * NOTE2: certain statistics below are zeroed upon
0094      *        port disable, so the calculation below
0095      *        must include the "cached" value of the stat
0096      *        plus the value read directly from hardware.
0097      *        Cached statistics are currently:
0098      *          rx_din_dropped_pkts
0099      *          rx_filter_passed_pkts
0100      *          rx_filter_discard_pkts
0101      */
0102     *data++ = priv->stats.hw_access_errors;
0103     *data++ = priv->stats.tx_invalid_checksums;
0104     *data++ = priv->stats.tx_small_frames;
0105     *data++ = priv->stats.tx_index_errors;
0106     *data++ = priv->stats.sw_config_errors;
0107     *data++ = priv->stats.sw_access_errors;
0108     *data++ = priv->stats.rx_truncate_errors;
0109     *data++ = priv->stats.rx_mac_errors;
0110     *data++ = (priv->stats.rx_din_dropped_pkts +
0111            readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER));
0112     *data++ = priv->stats.tx_fifo_full;
0113     *data++ = (priv->stats.rx_filter_passed_pkts +
0114            readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL));
0115     *data++ = (priv->stats.rx_filter_discard_pkts +
0116            readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL));
0117 }
0118 
0119 static void mlxbf_gige_get_pauseparam(struct net_device *netdev,
0120                       struct ethtool_pauseparam *pause)
0121 {
0122     pause->autoneg = AUTONEG_DISABLE;
0123     pause->rx_pause = 1;
0124     pause->tx_pause = 1;
0125 }
0126 
0127 const struct ethtool_ops mlxbf_gige_ethtool_ops = {
0128     .get_link       = ethtool_op_get_link,
0129     .get_ringparam      = mlxbf_gige_get_ringparam,
0130     .get_regs_len           = mlxbf_gige_get_regs_len,
0131     .get_regs               = mlxbf_gige_get_regs,
0132     .get_strings            = mlxbf_gige_get_strings,
0133     .get_sset_count         = mlxbf_gige_get_sset_count,
0134     .get_ethtool_stats      = mlxbf_gige_get_ethtool_stats,
0135     .nway_reset     = phy_ethtool_nway_reset,
0136     .get_pauseparam     = mlxbf_gige_get_pauseparam,
0137     .get_link_ksettings = phy_ethtool_get_link_ksettings,
0138 };