Commit b08a7629 authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'net-dpaa2-mac-export-standard-statistics'

Ioana Ciornei says:

====================
net: dpaa2-mac: export standard statistics

This patch set adds support for standard ethtool statistics - rmon,
eth-ctrl, eth-mac and pause - to dpaa2-mac and its users dpaa2-eth and
dpaa2-switch.

The first patch extends the firmware APIs related to MAC counters and
adds dpmac_get_statistics() which can be used to retrieve multiple counter
values through a single firmware call.

This new API is put in use in the second patch by gathering all
previously exported ethtool statistics through a single MC firmware
call. In this patch we are also adding the setup and cleanup
infrastructure which will be also used for the standard ethtool
counters.

The third patch adds the actual suppord for rmon, eth-ctrl, eth-mac and
pause statistics in dpaa2-mac and its users.
====================

Link: https://patch.msgid.link/20260323115039.3932600-1-ioana.ciornei@nxp.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 8f303194 dd1d4ccb
Loading
Loading
Loading
Loading
+60 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2014-2016 Freescale Semiconductor Inc.
 * Copyright 2016-2022 NXP
 * Copyright 2016-2022, 2024-2026 NXP
 */

#include <linux/net_tstamp.h>
@@ -938,6 +938,61 @@ static void dpaa2_eth_get_channels(struct net_device *net_dev,
				   channels->other_count;
}

static void
dpaa2_eth_get_rmon_stats(struct net_device *net_dev,
			 struct ethtool_rmon_stats *rmon_stats,
			 const struct ethtool_rmon_hist_range **ranges)
{
	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);

	mutex_lock(&priv->mac_lock);

	if (dpaa2_eth_has_mac(priv))
		dpaa2_mac_get_rmon_stats(priv->mac, rmon_stats, ranges);

	mutex_unlock(&priv->mac_lock);
}

static void dpaa2_eth_get_pause_stats(struct net_device *net_dev,
				      struct ethtool_pause_stats *pause_stats)
{
	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);

	mutex_lock(&priv->mac_lock);

	if (dpaa2_eth_has_mac(priv))
		dpaa2_mac_get_pause_stats(priv->mac, pause_stats);

	mutex_unlock(&priv->mac_lock);
}

static void dpaa2_eth_get_ctrl_stats(struct net_device *net_dev,
				     struct ethtool_eth_ctrl_stats *ctrl_stats)
{
	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);

	mutex_lock(&priv->mac_lock);

	if (dpaa2_eth_has_mac(priv))
		dpaa2_mac_get_ctrl_stats(priv->mac, ctrl_stats);

	mutex_unlock(&priv->mac_lock);
}

static void
dpaa2_eth_get_eth_mac_stats(struct net_device *net_dev,
			    struct ethtool_eth_mac_stats *eth_mac_stats)
{
	struct dpaa2_eth_priv *priv = netdev_priv(net_dev);

	mutex_lock(&priv->mac_lock);

	if (dpaa2_eth_has_mac(priv))
		dpaa2_mac_get_eth_mac_stats(priv->mac, eth_mac_stats);

	mutex_unlock(&priv->mac_lock);
}

const struct ethtool_ops dpaa2_ethtool_ops = {
	.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
				     ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
@@ -962,4 +1017,8 @@ const struct ethtool_ops dpaa2_ethtool_ops = {
	.get_coalesce = dpaa2_eth_get_coalesce,
	.set_coalesce = dpaa2_eth_set_coalesce,
	.get_channels = dpaa2_eth_get_channels,
	.get_rmon_stats = dpaa2_eth_get_rmon_stats,
	.get_pause_stats = dpaa2_eth_get_pause_stats,
	.get_eth_ctrl_stats = dpaa2_eth_get_ctrl_stats,
	.get_eth_mac_stats = dpaa2_eth_get_eth_mac_stats,
};
+373 −36
Original line number Diff line number Diff line
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2019 NXP */
/* Copyright 2019, 2024-2026 NXP */

#include <linux/acpi.h>
#include <linux/pcs-lynx.h>
@@ -15,7 +15,195 @@
#define DPMAC_PROTOCOL_CHANGE_VER_MAJOR		4
#define DPMAC_PROTOCOL_CHANGE_VER_MINOR		8

#define DPMAC_STATS_BUNDLE_VER_MAJOR		4
#define DPMAC_STATS_BUNDLE_VER_MINOR		10

#define DPMAC_STANDARD_STATS_VER_MAJOR		4
#define DPMAC_STANDARD_STATS_VER_MINOR		11

#define DPAA2_MAC_FEATURE_PROTOCOL_CHANGE	BIT(0)
#define DPAA2_MAC_FEATURE_STATS_BUNDLE		BIT(1)
#define DPAA2_MAC_FEATURE_STANDARD_STATS	BIT(2)

struct dpmac_counter {
	enum dpmac_counter_id id;
	size_t offset;
	const char *name;
};

#define DPMAC_COUNTER(counter_id, struct_name, struct_offset)	\
	{							\
		.id = counter_id,				\
		.offset = offsetof(struct_name, struct_offset),	\
	}

#define DPMAC_UNSTRUCTURED_COUNTER(counter_id, counter_name)	\
	{							\
		.id = counter_id,				\
		.name = counter_name,				\
	}

#define DPMAC_RMON_COUNTER(counter_id, struct_offset)		\
	DPMAC_COUNTER(counter_id, struct ethtool_rmon_stats, struct_offset)

#define DPMAC_PAUSE_COUNTER(counter_id, struct_offset)		\
	DPMAC_COUNTER(counter_id, struct ethtool_pause_stats, struct_offset)

#define DPMAC_CTRL_COUNTER(counter_id, struct_offset)		\
	DPMAC_COUNTER(counter_id, struct ethtool_eth_ctrl_stats, struct_offset)

#define DPMAC_MAC_COUNTER(counter_id, struct_offset)		\
	DPMAC_COUNTER(counter_id, struct ethtool_eth_mac_stats, struct_offset)

static const struct dpmac_counter dpaa2_mac_ethtool_stats[] = {
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_ALL_FRAME,  "[mac] rx all frames"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_GOOD_FRAME,  "[mac] rx frames ok"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_ERR_FRAME, "[mac] rx frame errors"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_FRAME_DISCARD, "[mac] rx frame discards"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_UCAST_FRAME, "[mac] rx u-cast"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_BCAST_FRAME, "[mac] rx b-cast"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_MCAST_FRAME, "[mac] rx m-cast"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_FRAME_64, "[mac] rx 64 bytes"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_FRAME_127, "[mac] rx 65-127 bytes"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_FRAME_255, "[mac] rx 128-255 bytes"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_FRAME_511, "[mac] rx 256-511 bytes"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_FRAME_1023, "[mac] rx 512-1023 bytes"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_FRAME_1518, "[mac] rx 1024-1518 bytes"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_FRAME_1519_MAX, "[mac] rx 1519-max bytes"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_FRAG, "[mac] rx frags"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_JABBER, "[mac] rx jabber"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_ALIGN_ERR, "[mac] rx align errors"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_OVERSIZED, "[mac] rx oversized"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_VALID_PAUSE_FRAME, "[mac] rx pause"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_ING_BYTE, "[mac] rx bytes"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_EGR_GOOD_FRAME, "[mac] tx frames ok"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_EGR_UCAST_FRAME, "[mac] tx u-cast"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_EGR_MCAST_FRAME, "[mac] tx m-cast"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_EGR_BCAST_FRAME, "[mac] tx b-cast"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_EGR_ERR_FRAME, "[mac] tx frame errors"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_EGR_UNDERSIZED, "[mac] tx undersized"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_EGR_VALID_PAUSE_FRAME, "[mac] tx b-pause"),
	DPMAC_UNSTRUCTURED_COUNTER(DPMAC_CNT_EGR_BYTE, "[mac] tx bytes"),
};

#define DPAA2_MAC_NUM_ETHTOOL_STATS	ARRAY_SIZE(dpaa2_mac_ethtool_stats)

static const struct dpmac_counter dpaa2_mac_rmon_stats[] = {
	DPMAC_RMON_COUNTER(DPMAC_CNT_ING_FRAME_64, hist[0]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_ING_FRAME_127, hist[1]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_ING_FRAME_255, hist[2]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_ING_FRAME_511, hist[3]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_ING_FRAME_1023, hist[4]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_ING_FRAME_1518, hist[5]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_ING_FRAME_1519_MAX, hist[6]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_EGR_FRAME_64, hist_tx[0]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_EGR_FRAME_127, hist_tx[1]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_EGR_FRAME_255, hist_tx[2]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_EGR_FRAME_511, hist_tx[3]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_EGR_FRAME_1023, hist_tx[4]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_EGR_FRAME_1518, hist_tx[5]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_EGR_FRAME_1519_MAX, hist_tx[6]),
	DPMAC_RMON_COUNTER(DPMAC_CNT_ING_UNDERSIZED, undersize_pkts),
	DPMAC_RMON_COUNTER(DPMAC_CNT_ING_OVERSIZED, oversize_pkts),
	DPMAC_RMON_COUNTER(DPMAC_CNT_ING_FRAG, fragments),
	DPMAC_RMON_COUNTER(DPMAC_CNT_ING_JABBER, jabbers),
};

#define DPAA2_MAC_NUM_RMON_STATS	ARRAY_SIZE(dpaa2_mac_rmon_stats)

static const struct dpmac_counter dpaa2_mac_pause_stats[] = {
	DPMAC_PAUSE_COUNTER(DPMAC_CNT_ING_VALID_PAUSE_FRAME, rx_pause_frames),
	DPMAC_PAUSE_COUNTER(DPMAC_CNT_EGR_VALID_PAUSE_FRAME, tx_pause_frames),
};

#define DPAA2_MAC_NUM_PAUSE_STATS	ARRAY_SIZE(dpaa2_mac_pause_stats)

static const struct dpmac_counter dpaa2_mac_eth_ctrl_stats[] = {
	DPMAC_CTRL_COUNTER(DPMAC_CNT_ING_CONTROL_FRAME, MACControlFramesReceived),
	DPMAC_CTRL_COUNTER(DPMAC_CNT_EGR_CONTROL_FRAME, MACControlFramesTransmitted),
};

#define DPAA2_MAC_NUM_ETH_CTRL_STATS	ARRAY_SIZE(dpaa2_mac_eth_ctrl_stats)

static const struct dpmac_counter dpaa2_mac_eth_mac_stats[] = {
	DPMAC_MAC_COUNTER(DPMAC_CNT_EGR_GOOD_FRAME, FramesTransmittedOK),
	DPMAC_MAC_COUNTER(DPMAC_CNT_ING_GOOD_FRAME, FramesReceivedOK),
	DPMAC_MAC_COUNTER(DPMAC_CNT_ING_FCS_ERR, FrameCheckSequenceErrors),
	DPMAC_MAC_COUNTER(DPMAC_CNT_ING_ALIGN_ERR, AlignmentErrors),
	DPMAC_MAC_COUNTER(DPMAC_CNT_EGR_ALL_BYTE, OctetsTransmittedOK),
	DPMAC_MAC_COUNTER(DPMAC_CNT_EGR_ERR_FRAME, FramesLostDueToIntMACXmitError),
	DPMAC_MAC_COUNTER(DPMAC_CNT_ING_ALL_BYTE, OctetsReceivedOK),
	DPMAC_MAC_COUNTER(DPMAC_CNT_ING_FRAME_DISCARD_NOT_TRUNC, FramesLostDueToIntMACRcvError),
	DPMAC_MAC_COUNTER(DPMAC_CNT_EGR_MCAST_FRAME, MulticastFramesXmittedOK),
	DPMAC_MAC_COUNTER(DPMAC_CNT_EGR_BCAST_FRAME, BroadcastFramesXmittedOK),
	DPMAC_MAC_COUNTER(DPMAC_CNT_ING_MCAST_FRAME, MulticastFramesReceivedOK),
	DPMAC_MAC_COUNTER(DPMAC_CNT_ING_BCAST_FRAME, BroadcastFramesReceivedOK),
};

#define DPAA2_MAC_NUM_ETH_MAC_STATS	ARRAY_SIZE(dpaa2_mac_eth_mac_stats)

static void dpaa2_mac_setup_stats(struct dpaa2_mac *mac,
				  struct dpaa2_mac_stats *stats,
				  size_t num_stats,
				  const struct dpmac_counter *counters)
{
	struct device *dev = mac->net_dev->dev.parent;
	size_t size_idx, size_values;
	__le32 *cnt_idx;

	size_idx = num_stats * sizeof(u32);
	stats->idx_dma_mem = dma_alloc_noncoherent(dev, size_idx,
						   &stats->idx_iova,
						   DMA_TO_DEVICE,
						   GFP_KERNEL);
	if (!stats->idx_dma_mem)
		goto out;

	size_values = num_stats * sizeof(u64);
	stats->values_dma_mem = dma_alloc_noncoherent(dev, size_values,
						      &stats->values_iova,
						      DMA_FROM_DEVICE,
						      GFP_KERNEL);
	if (!stats->values_dma_mem)
		goto err_alloc_values;

	cnt_idx = stats->idx_dma_mem;
	for (size_t i = 0; i < num_stats; i++)
		*cnt_idx++ = cpu_to_le32((u32)(counters[i].id));

	dma_sync_single_for_device(dev, stats->idx_iova, size_idx,
				   DMA_TO_DEVICE);

	return;

err_alloc_values:
	dma_free_noncoherent(dev, num_stats * sizeof(u32), stats->idx_dma_mem,
			     stats->idx_iova, DMA_TO_DEVICE);
out:
	stats->idx_dma_mem = NULL;
	stats->values_dma_mem = NULL;
}

static void dpaa2_mac_clear_stats(struct dpaa2_mac *mac,
				  struct dpaa2_mac_stats *stats,
				  size_t num_stats)
{
	struct device *dev = mac->net_dev->dev.parent;

	if (stats->idx_dma_mem) {
		dma_free_noncoherent(dev, num_stats * sizeof(u32),
				     stats->idx_dma_mem,
				     stats->idx_iova, DMA_TO_DEVICE);
		stats->idx_dma_mem = NULL;
	}

	if (stats->values_dma_mem) {
		dma_free_noncoherent(dev, num_stats * sizeof(u64),
				     stats->values_dma_mem,
				     stats->values_iova, DMA_FROM_DEVICE);
		stats->values_dma_mem = NULL;
	}
}

static int dpaa2_mac_cmp_ver(struct dpaa2_mac *mac,
			     u16 ver_major, u16 ver_minor)
@@ -32,6 +220,14 @@ static void dpaa2_mac_detect_features(struct dpaa2_mac *mac)
	if (dpaa2_mac_cmp_ver(mac, DPMAC_PROTOCOL_CHANGE_VER_MAJOR,
			      DPMAC_PROTOCOL_CHANGE_VER_MINOR) >= 0)
		mac->features |= DPAA2_MAC_FEATURE_PROTOCOL_CHANGE;

	if (dpaa2_mac_cmp_ver(mac, DPMAC_STATS_BUNDLE_VER_MAJOR,
			      DPMAC_STATS_BUNDLE_VER_MINOR) >= 0)
		mac->features |= DPAA2_MAC_FEATURE_STATS_BUNDLE;

	if (dpaa2_mac_cmp_ver(mac, DPMAC_STANDARD_STATS_VER_MAJOR,
			      DPMAC_STANDARD_STATS_VER_MINOR) >= 0)
		mac->features |= DPAA2_MAC_FEATURE_STANDARD_STATS;
}

static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode)
@@ -504,6 +700,29 @@ int dpaa2_mac_open(struct dpaa2_mac *mac)
	mac->fw_node = fw_node;
	net_dev->dev.of_node = to_of_node(mac->fw_node);

	if (mac->features & DPAA2_MAC_FEATURE_STATS_BUNDLE)
		dpaa2_mac_setup_stats(mac, &mac->ethtool_stats,
				      DPAA2_MAC_NUM_ETHTOOL_STATS,
				      dpaa2_mac_ethtool_stats);

	if (mac->features & DPAA2_MAC_FEATURE_STANDARD_STATS) {
		dpaa2_mac_setup_stats(mac, &mac->rmon_stats,
				      DPAA2_MAC_NUM_RMON_STATS,
				      dpaa2_mac_rmon_stats);

		dpaa2_mac_setup_stats(mac, &mac->pause_stats,
				      DPAA2_MAC_NUM_PAUSE_STATS,
				      dpaa2_mac_pause_stats);

		dpaa2_mac_setup_stats(mac, &mac->eth_ctrl_stats,
				      DPAA2_MAC_NUM_ETH_CTRL_STATS,
				      dpaa2_mac_eth_ctrl_stats);

		dpaa2_mac_setup_stats(mac, &mac->eth_mac_stats,
				      DPAA2_MAC_NUM_ETH_MAC_STATS,
				      dpaa2_mac_eth_mac_stats);
	}

	return 0;

err_close_dpmac:
@@ -515,66 +734,184 @@ void dpaa2_mac_close(struct dpaa2_mac *mac)
{
	struct fsl_mc_device *dpmac_dev = mac->mc_dev;

	if (mac->features & DPAA2_MAC_FEATURE_STATS_BUNDLE)
		dpaa2_mac_clear_stats(mac, &mac->ethtool_stats,
				      DPAA2_MAC_NUM_ETHTOOL_STATS);

	if (mac->features & DPAA2_MAC_FEATURE_STANDARD_STATS) {
		dpaa2_mac_clear_stats(mac, &mac->rmon_stats,
				      DPAA2_MAC_NUM_RMON_STATS);
		dpaa2_mac_clear_stats(mac, &mac->pause_stats,
				      DPAA2_MAC_NUM_PAUSE_STATS);
		dpaa2_mac_clear_stats(mac, &mac->eth_ctrl_stats,
				      DPAA2_MAC_NUM_ETH_CTRL_STATS);
		dpaa2_mac_clear_stats(mac, &mac->eth_mac_stats,
				      DPAA2_MAC_NUM_ETH_MAC_STATS);
	}

	dpmac_close(mac->mc_io, 0, dpmac_dev->mc_handle);
	if (mac->fw_node)
		fwnode_handle_put(mac->fw_node);
}

static char dpaa2_mac_ethtool_stats[][ETH_GSTRING_LEN] = {
	[DPMAC_CNT_ING_ALL_FRAME]		= "[mac] rx all frames",
	[DPMAC_CNT_ING_GOOD_FRAME]		= "[mac] rx frames ok",
	[DPMAC_CNT_ING_ERR_FRAME]		= "[mac] rx frame errors",
	[DPMAC_CNT_ING_FRAME_DISCARD]		= "[mac] rx frame discards",
	[DPMAC_CNT_ING_UCAST_FRAME]		= "[mac] rx u-cast",
	[DPMAC_CNT_ING_BCAST_FRAME]		= "[mac] rx b-cast",
	[DPMAC_CNT_ING_MCAST_FRAME]		= "[mac] rx m-cast",
	[DPMAC_CNT_ING_FRAME_64]		= "[mac] rx 64 bytes",
	[DPMAC_CNT_ING_FRAME_127]		= "[mac] rx 65-127 bytes",
	[DPMAC_CNT_ING_FRAME_255]		= "[mac] rx 128-255 bytes",
	[DPMAC_CNT_ING_FRAME_511]		= "[mac] rx 256-511 bytes",
	[DPMAC_CNT_ING_FRAME_1023]		= "[mac] rx 512-1023 bytes",
	[DPMAC_CNT_ING_FRAME_1518]		= "[mac] rx 1024-1518 bytes",
	[DPMAC_CNT_ING_FRAME_1519_MAX]		= "[mac] rx 1519-max bytes",
	[DPMAC_CNT_ING_FRAG]			= "[mac] rx frags",
	[DPMAC_CNT_ING_JABBER]			= "[mac] rx jabber",
	[DPMAC_CNT_ING_ALIGN_ERR]		= "[mac] rx align errors",
	[DPMAC_CNT_ING_OVERSIZED]		= "[mac] rx oversized",
	[DPMAC_CNT_ING_VALID_PAUSE_FRAME]	= "[mac] rx pause",
	[DPMAC_CNT_ING_BYTE]			= "[mac] rx bytes",
	[DPMAC_CNT_EGR_GOOD_FRAME]		= "[mac] tx frames ok",
	[DPMAC_CNT_EGR_UCAST_FRAME]		= "[mac] tx u-cast",
	[DPMAC_CNT_EGR_MCAST_FRAME]		= "[mac] tx m-cast",
	[DPMAC_CNT_EGR_BCAST_FRAME]		= "[mac] tx b-cast",
	[DPMAC_CNT_EGR_ERR_FRAME]		= "[mac] tx frame errors",
	[DPMAC_CNT_EGR_UNDERSIZED]		= "[mac] tx undersized",
	[DPMAC_CNT_EGR_VALID_PAUSE_FRAME]	= "[mac] tx b-pause",
	[DPMAC_CNT_EGR_BYTE]			= "[mac] tx bytes",
static void dpaa2_mac_transfer_stats(const struct dpmac_counter *counters,
				     size_t num_counters, void *s,
				     __le64 *cnt_values)
{
	for (size_t i = 0; i < num_counters; i++) {
		u64 *p = s + counters[i].offset;

		*p = le64_to_cpu(cnt_values[i]);
	}
}

static const struct ethtool_rmon_hist_range dpaa2_mac_rmon_ranges[] = {
	{   64,   64 },
	{   65,  127 },
	{  128,  255 },
	{  256,  511 },
	{  512, 1023 },
	{ 1024, 1518 },
	{ 1519, DPAA2_ETH_MFL },
	{},
};

#define DPAA2_MAC_NUM_STATS	ARRAY_SIZE(dpaa2_mac_ethtool_stats)
static void dpaa2_mac_get_standard_stats(struct dpaa2_mac *mac,
					 struct dpaa2_mac_stats *stats,
					 size_t num_cnt,
					 const struct dpmac_counter *counters,
					 void *s)
{
	struct device *dev = mac->net_dev->dev.parent;
	struct fsl_mc_device *dpmac_dev = mac->mc_dev;
	size_t values_size = num_cnt * sizeof(u64);
	int err;

	if (!(mac->features & DPAA2_MAC_FEATURE_STANDARD_STATS))
		return;

	if (!stats->idx_dma_mem || !stats->values_dma_mem)
		return;

	dma_sync_single_for_device(dev, stats->values_iova, values_size,
				   DMA_FROM_DEVICE);

	err = dpmac_get_statistics(mac->mc_io, 0, dpmac_dev->mc_handle,
				   stats->idx_iova, stats->values_iova,
				   num_cnt);
	if (err) {
		netdev_err(mac->net_dev, "%s: dpmac_get_statistics() = %d\n",
			   __func__, err);
		return;
	}

	dma_sync_single_for_cpu(dev, stats->values_iova, values_size,
				DMA_FROM_DEVICE);

	dpaa2_mac_transfer_stats(counters, num_cnt, s, stats->values_dma_mem);
}

void dpaa2_mac_get_rmon_stats(struct dpaa2_mac *mac,
			      struct ethtool_rmon_stats *s,
			      const struct ethtool_rmon_hist_range **ranges)
{
	if (s->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE)
		return;

	dpaa2_mac_get_standard_stats(mac, &mac->rmon_stats,
				     DPAA2_MAC_NUM_RMON_STATS,
				     dpaa2_mac_rmon_stats, s);

	*ranges = dpaa2_mac_rmon_ranges;
}

void dpaa2_mac_get_pause_stats(struct dpaa2_mac *mac,
			       struct ethtool_pause_stats *s)
{
	if (s->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE)
		return;

	dpaa2_mac_get_standard_stats(mac, &mac->pause_stats,
				     DPAA2_MAC_NUM_PAUSE_STATS,
				     dpaa2_mac_pause_stats, s);
}

void dpaa2_mac_get_ctrl_stats(struct dpaa2_mac *mac,
			      struct ethtool_eth_ctrl_stats *s)
{
	if (s->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE)
		return;

	dpaa2_mac_get_standard_stats(mac, &mac->eth_ctrl_stats,
				     DPAA2_MAC_NUM_ETH_CTRL_STATS,
				     dpaa2_mac_eth_ctrl_stats, s);
}

void dpaa2_mac_get_eth_mac_stats(struct dpaa2_mac *mac,
				 struct ethtool_eth_mac_stats *s)
{
	if (s->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE)
		return;

	dpaa2_mac_get_standard_stats(mac, &mac->eth_mac_stats,
				     DPAA2_MAC_NUM_ETH_MAC_STATS,
				     dpaa2_mac_eth_mac_stats, s);
}

int dpaa2_mac_get_sset_count(void)
{
	return DPAA2_MAC_NUM_STATS;
	return DPAA2_MAC_NUM_ETHTOOL_STATS;
}

void dpaa2_mac_get_strings(u8 **data)
{
	int i;

	for (i = 0; i < DPAA2_MAC_NUM_STATS; i++)
		ethtool_puts(data, dpaa2_mac_ethtool_stats[i]);
	for (i = 0; i < DPAA2_MAC_NUM_ETHTOOL_STATS; i++)
		ethtool_puts(data, dpaa2_mac_ethtool_stats[i].name);
}

void dpaa2_mac_get_ethtool_stats(struct dpaa2_mac *mac, u64 *data)
{
	size_t values_size = DPAA2_MAC_NUM_ETHTOOL_STATS * sizeof(u64);
	struct device *dev = mac->net_dev->dev.parent;
	struct fsl_mc_device *dpmac_dev = mac->mc_dev;
	__le64 *cnt_values;
	int i, err;
	u64 value;

	for (i = 0; i < DPAA2_MAC_NUM_STATS; i++) {
	if (!(mac->features & DPAA2_MAC_FEATURE_STATS_BUNDLE))
		goto fallback;

	if (!mac->ethtool_stats.idx_dma_mem ||
	    !mac->ethtool_stats.values_dma_mem)
		goto fallback;

	dma_sync_single_for_device(dev, mac->ethtool_stats.values_iova,
				   values_size, DMA_FROM_DEVICE);

	err = dpmac_get_statistics(mac->mc_io, 0, dpmac_dev->mc_handle,
				   mac->ethtool_stats.idx_iova,
				   mac->ethtool_stats.values_iova,
				   DPAA2_MAC_NUM_ETHTOOL_STATS);
	if (err)
		goto fallback;

	dma_sync_single_for_cpu(dev, mac->ethtool_stats.values_iova,
				values_size, DMA_FROM_DEVICE);

	cnt_values = mac->ethtool_stats.values_dma_mem;
	for (i = 0; i < DPAA2_MAC_NUM_ETHTOOL_STATS; i++)
		*(data + i) = le64_to_cpu(*cnt_values++);

	return;

fallback:

	/* Fallback and retrieve each counter one by one */
	for (i = 0; i < DPAA2_MAC_NUM_ETHTOOL_STATS; i++) {
		err = dpmac_get_counter(mac->mc_io, 0, dpmac_dev->mc_handle,
					i, &value);
					dpaa2_mac_ethtool_stats[i].id, &value);
		if (err) {
			netdev_err_once(mac->net_dev,
					"dpmac_get_counter error %d\n", err);
+26 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
/* Copyright 2019 NXP */
/* Copyright 2019, 2024-2026 NXP */
#ifndef DPAA2_MAC_H
#define DPAA2_MAC_H

@@ -11,6 +11,12 @@
#include "dpmac.h"
#include "dpmac-cmd.h"

struct dpaa2_mac_stats {
	__le32 *idx_dma_mem;
	__le64 *values_dma_mem;
	dma_addr_t idx_iova, values_iova;
};

struct dpaa2_mac {
	struct fsl_mc_device *mc_dev;
	struct dpmac_link_state state;
@@ -28,6 +34,12 @@ struct dpaa2_mac {
	struct fwnode_handle *fw_node;

	struct phy *serdes_phy;

	struct dpaa2_mac_stats ethtool_stats;
	struct dpaa2_mac_stats rmon_stats;
	struct dpaa2_mac_stats pause_stats;
	struct dpaa2_mac_stats eth_ctrl_stats;
	struct dpaa2_mac_stats eth_mac_stats;
};

static inline bool dpaa2_mac_is_type_phy(struct dpaa2_mac *mac)
@@ -53,6 +65,19 @@ void dpaa2_mac_get_strings(u8 **data);

void dpaa2_mac_get_ethtool_stats(struct dpaa2_mac *mac, u64 *data);

void dpaa2_mac_get_rmon_stats(struct dpaa2_mac *mac,
			      struct ethtool_rmon_stats *s,
			      const struct ethtool_rmon_hist_range **ranges);

void dpaa2_mac_get_pause_stats(struct dpaa2_mac *mac,
			       struct ethtool_pause_stats *s);

void dpaa2_mac_get_ctrl_stats(struct dpaa2_mac *mac,
			      struct ethtool_eth_ctrl_stats *s);

void dpaa2_mac_get_eth_mac_stats(struct dpaa2_mac *mac,
				 struct ethtool_eth_mac_stats *s);

void dpaa2_mac_start(struct dpaa2_mac *mac);

void dpaa2_mac_stop(struct dpaa2_mac *mac);
+47 −1
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
 * DPAA2 Ethernet Switch ethtool support
 *
 * Copyright 2014-2016 Freescale Semiconductor Inc.
 * Copyright 2017-2018 NXP
 * Copyright 2017-2018, 2024-2026 NXP
 *
 */

@@ -210,6 +210,49 @@ static void dpaa2_switch_ethtool_get_stats(struct net_device *netdev,
	mutex_unlock(&port_priv->mac_lock);
}

static void
dpaa2_switch_get_rmon_stats(struct net_device *netdev,
			    struct ethtool_rmon_stats *rmon_stats,
			    const struct ethtool_rmon_hist_range **ranges)
{
	struct ethsw_port_priv *port_priv = netdev_priv(netdev);

	mutex_lock(&port_priv->mac_lock);

	if (dpaa2_switch_port_has_mac(port_priv))
		dpaa2_mac_get_rmon_stats(port_priv->mac, rmon_stats, ranges);

	mutex_unlock(&port_priv->mac_lock);
}

static void
dpaa2_switch_get_ctrl_stats(struct net_device *net_dev,
			    struct ethtool_eth_ctrl_stats *ctrl_stats)
{
	struct ethsw_port_priv *port_priv = netdev_priv(net_dev);

	mutex_lock(&port_priv->mac_lock);

	if (dpaa2_switch_port_has_mac(port_priv))
		dpaa2_mac_get_ctrl_stats(port_priv->mac, ctrl_stats);

	mutex_unlock(&port_priv->mac_lock);
}

static void
dpaa2_switch_get_eth_mac_stats(struct net_device *net_dev,
			       struct ethtool_eth_mac_stats *eth_mac_stats)
{
	struct ethsw_port_priv *port_priv = netdev_priv(net_dev);

	mutex_lock(&port_priv->mac_lock);

	if (dpaa2_switch_port_has_mac(port_priv))
		dpaa2_mac_get_eth_mac_stats(port_priv->mac, eth_mac_stats);

	mutex_unlock(&port_priv->mac_lock);
}

const struct ethtool_ops dpaa2_switch_port_ethtool_ops = {
	.get_drvinfo		= dpaa2_switch_get_drvinfo,
	.get_link		= ethtool_op_get_link,
@@ -218,4 +261,7 @@ const struct ethtool_ops dpaa2_switch_port_ethtool_ops = {
	.get_strings		= dpaa2_switch_ethtool_get_strings,
	.get_ethtool_stats	= dpaa2_switch_ethtool_get_stats,
	.get_sset_count		= dpaa2_switch_ethtool_get_sset_count,
	.get_rmon_stats		= dpaa2_switch_get_rmon_stats,
	.get_eth_ctrl_stats	= dpaa2_switch_get_ctrl_stats,
	.get_eth_mac_stats	= dpaa2_switch_get_eth_mac_stats,
};
+10 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
/* Copyright 2013-2016 Freescale Semiconductor Inc.
 * Copyright 2019 NXP
 * Copyright 2019, 2024-2026 NXP
 */
#ifndef _FSL_DPMAC_CMD_H
#define _FSL_DPMAC_CMD_H
@@ -28,6 +28,8 @@

#define DPMAC_CMDID_SET_PROTOCOL	DPMAC_CMD(0x0c7)

#define DPMAC_CMDID_GET_STATISTICS	DPMAC_CMD(0x0c8)

/* Macros for accessing command fields smaller than 1byte */
#define DPMAC_MASK(field)        \
	GENMASK(DPMAC_##field##_SHIFT + DPMAC_##field##_SIZE - 1, \
@@ -82,4 +84,11 @@ struct dpmac_rsp_get_api_version {
struct dpmac_cmd_set_protocol {
	u8 eth_if;
};

struct dpmac_cmd_get_statistics {
	__le64 iova_cnt;
	__le64 iova_values;
	__le32 num_cnt;
};

#endif /* _FSL_DPMAC_CMD_H */
Loading