// 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>
#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 DPAA2_MAC_FEATURE_PROTOCOL_CHANGE BIT(0)
+#define DPAA2_MAC_FEATURE_STATS_BUNDLE BIT(1)
+
+struct dpmac_counter {
+ enum dpmac_counter_id id;
+ const char *name;
+};
+
+#define DPMAC_UNSTRUCTURED_COUNTER(counter_id, counter_name) \
+ { \
+ .id = counter_id, \
+ .name = counter_name, \
+ }
+
+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 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)
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;
}
static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode)
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);
+
return 0;
err_close_dpmac:
{
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);
+
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",
-};
-
-#define DPAA2_MAC_NUM_STATS ARRAY_SIZE(dpaa2_mac_ethtool_stats)
-
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);