brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · 8b63968 Raw
176 lines · c
1// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause2 3/* Ethtool support for Mellanox Gigabit Ethernet driver4 *5 * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES6 */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 results27	 * into the provided buffer. By design, a read to an28	 * offset without an existing register will be29	 * acknowledged and return zero.30	 */31	memcpy_fromio(p, priv->base, MLXBF_GIGE_MMIO_REG_SZ);32}33 34static void35mlxbf_gige_get_ringparam(struct net_device *netdev,36			 struct ethtool_ringparam *ering,37			 struct kernel_ethtool_ringparam *kernel_ering,38			 struct netlink_ext_ack *extack)39{40	struct mlxbf_gige *priv = netdev_priv(netdev);41 42	ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ;43	ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ;44	ering->rx_pending = priv->rx_q_entries;45	ering->tx_pending = priv->tx_q_entries;46}47 48static const struct {49	const char string[ETH_GSTRING_LEN];50} mlxbf_gige_ethtool_stats_keys[] = {51	{ "hw_access_errors" },52	{ "tx_invalid_checksums" },53	{ "tx_small_frames" },54	{ "tx_index_errors" },55	{ "sw_config_errors" },56	{ "sw_access_errors" },57	{ "rx_truncate_errors" },58	{ "rx_mac_errors" },59	{ "rx_din_dropped_pkts" },60	{ "tx_fifo_full" },61	{ "rx_filter_passed_pkts" },62	{ "rx_filter_discard_pkts" },63};64 65static int mlxbf_gige_get_sset_count(struct net_device *netdev, int stringset)66{67	if (stringset != ETH_SS_STATS)68		return -EOPNOTSUPP;69	return ARRAY_SIZE(mlxbf_gige_ethtool_stats_keys);70}71 72static void mlxbf_gige_get_strings(struct net_device *netdev, u32 stringset,73				   u8 *buf)74{75	if (stringset != ETH_SS_STATS)76		return;77	memcpy(buf, &mlxbf_gige_ethtool_stats_keys,78	       sizeof(mlxbf_gige_ethtool_stats_keys));79}80 81static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev,82					 struct ethtool_stats *estats,83					 u64 *data)84{85	struct mlxbf_gige *priv = netdev_priv(netdev);86 87	/* Fill data array with interface statistics88	 *89	 * NOTE: the data writes must be in90	 *       sync with the strings shown in91	 *       the mlxbf_gige_ethtool_stats_keys[] array92	 *93	 * NOTE2: certain statistics below are zeroed upon94	 *        port disable, so the calculation below95	 *        must include the "cached" value of the stat96	 *        plus the value read directly from hardware.97	 *        Cached statistics are currently:98	 *          rx_din_dropped_pkts99	 *          rx_filter_passed_pkts100	 *          rx_filter_discard_pkts101	 */102	*data++ = priv->stats.hw_access_errors;103	*data++ = priv->stats.tx_invalid_checksums;104	*data++ = priv->stats.tx_small_frames;105	*data++ = priv->stats.tx_index_errors;106	*data++ = priv->stats.sw_config_errors;107	*data++ = priv->stats.sw_access_errors;108	*data++ = priv->stats.rx_truncate_errors;109	*data++ = priv->stats.rx_mac_errors;110	*data++ = (priv->stats.rx_din_dropped_pkts +111		   readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER));112	*data++ = priv->stats.tx_fifo_full;113	*data++ = (priv->stats.rx_filter_passed_pkts +114		   readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL));115	*data++ = (priv->stats.rx_filter_discard_pkts +116		   readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL));117}118 119static void mlxbf_gige_get_pauseparam(struct net_device *netdev,120				      struct ethtool_pauseparam *pause)121{122	pause->autoneg = AUTONEG_DISABLE;123	pause->rx_pause = 1;124	pause->tx_pause = 1;125}126 127static bool mlxbf_gige_llu_counters_enabled(struct mlxbf_gige *priv)128{129	u32 data;130 131	if (priv->hw_version == MLXBF_GIGE_VERSION_BF2) {132		data = readl(priv->llu_base + MLXBF_GIGE_BF2_LLU_GENERAL_CONFIG);133		if (data & MLXBF_GIGE_BF2_LLU_COUNTERS_EN)134			return true;135	} else {136		data = readl(priv->llu_base + MLXBF_GIGE_BF3_LLU_GENERAL_CONFIG);137		if (data & MLXBF_GIGE_BF3_LLU_COUNTERS_EN)138			return true;139	}140 141	return false;142}143 144static void mlxbf_gige_get_pause_stats(struct net_device *netdev,145				       struct ethtool_pause_stats *pause_stats)146{147	struct mlxbf_gige *priv = netdev_priv(netdev);148	u64 data_lo, data_hi;149 150	/* Read LLU counters to provide stats only if counters are enabled */151	if (mlxbf_gige_llu_counters_enabled(priv)) {152		data_lo = readl(priv->llu_base + MLXBF_GIGE_TX_PAUSE_CNT_LO);153		data_hi = readl(priv->llu_base + MLXBF_GIGE_TX_PAUSE_CNT_HI);154		pause_stats->tx_pause_frames = (data_hi << 32) | data_lo;155 156		data_lo = readl(priv->llu_base + MLXBF_GIGE_RX_PAUSE_CNT_LO);157		data_hi = readl(priv->llu_base + MLXBF_GIGE_RX_PAUSE_CNT_HI);158		pause_stats->rx_pause_frames = (data_hi << 32) | data_lo;159	}160}161 162const struct ethtool_ops mlxbf_gige_ethtool_ops = {163	.get_link		= ethtool_op_get_link,164	.get_ringparam		= mlxbf_gige_get_ringparam,165	.get_regs_len           = mlxbf_gige_get_regs_len,166	.get_regs               = mlxbf_gige_get_regs,167	.get_strings            = mlxbf_gige_get_strings,168	.get_sset_count         = mlxbf_gige_get_sset_count,169	.get_ethtool_stats      = mlxbf_gige_get_ethtool_stats,170	.nway_reset		= phy_ethtool_nway_reset,171	.get_pauseparam		= mlxbf_gige_get_pauseparam,172	.get_pause_stats	= mlxbf_gige_get_pause_stats,173	.get_link_ksettings	= phy_ethtool_get_link_ksettings,174	.set_link_ksettings	= phy_ethtool_set_link_ksettings,175};176