mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-16 04:13:31 +00:00

Refreshed patches for qualcommb/ipq95xx by running make target/linux/refresh after creating a .config containing: CONFIG_TARGET_qualcommbe=y CONFIG_TARGET_qualcommbe_ipq95xx=y CONFIG_TARGET_qualcommbe_ipq95xx_DEVICE_qcom_rdp433=y Signed-off-by: John Audia <therealgraysky@proton.me> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
341 lines
11 KiB
Diff
341 lines
11 KiB
Diff
From ec30075badd13a3e2ffddd1c5dcb40e3c52202ed Mon Sep 17 00:00:00 2001
|
|
From: Pavithra R <quic_pavir@quicinc.com>
|
|
Date: Thu, 30 May 2024 20:46:36 +0530
|
|
Subject: [PATCH 43/50] net: ethernet: qualcomm: Add ethtool support for EDMA
|
|
|
|
ethtool ops can be used for EDMA netdevice configuration and statistics.
|
|
|
|
Change-Id: I57fc19415dacbe51fed000520336463938220609
|
|
Signed-off-by: Pavithra R <quic_pavir@quicinc.com>
|
|
---
|
|
drivers/net/ethernet/qualcomm/ppe/Makefile | 2 +-
|
|
drivers/net/ethernet/qualcomm/ppe/edma.h | 1 +
|
|
.../net/ethernet/qualcomm/ppe/edma_ethtool.c | 294 ++++++++++++++++++
|
|
drivers/net/ethernet/qualcomm/ppe/edma_port.c | 1 +
|
|
4 files changed, 297 insertions(+), 1 deletion(-)
|
|
create mode 100644 drivers/net/ethernet/qualcomm/ppe/edma_ethtool.c
|
|
|
|
--- a/drivers/net/ethernet/qualcomm/ppe/Makefile
|
|
+++ b/drivers/net/ethernet/qualcomm/ppe/Makefile
|
|
@@ -7,4 +7,4 @@ obj-$(CONFIG_QCOM_PPE) += qcom-ppe.o
|
|
qcom-ppe-objs := ppe.o ppe_config.o ppe_api.o ppe_debugfs.o ppe_port.o
|
|
|
|
#EDMA
|
|
-qcom-ppe-objs += edma.o edma_cfg_rx.o edma_cfg_tx.o edma_debugfs.o edma_port.o edma_rx.o edma_tx.o
|
|
+qcom-ppe-objs += edma.o edma_cfg_rx.o edma_cfg_tx.o edma_debugfs.o edma_port.o edma_rx.o edma_tx.o edma_ethtool.o
|
|
--- a/drivers/net/ethernet/qualcomm/ppe/edma.h
|
|
+++ b/drivers/net/ethernet/qualcomm/ppe/edma.h
|
|
@@ -151,4 +151,5 @@ void edma_destroy(struct ppe_device *ppe
|
|
int edma_setup(struct ppe_device *ppe_dev);
|
|
void edma_debugfs_teardown(void);
|
|
int edma_debugfs_setup(struct ppe_device *ppe_dev);
|
|
+void edma_set_ethtool_ops(struct net_device *netdev);
|
|
#endif
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/qualcomm/ppe/edma_ethtool.c
|
|
@@ -0,0 +1,294 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+/* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
+ */
|
|
+
|
|
+/* ethtool support for EDMA */
|
|
+
|
|
+#include <linux/cpumask.h>
|
|
+#include <linux/ethtool.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/netdevice.h>
|
|
+#include <linux/phylink.h>
|
|
+
|
|
+#include "edma.h"
|
|
+#include "edma_port.h"
|
|
+
|
|
+struct edma_ethtool_stats {
|
|
+ u8 stat_string[ETH_GSTRING_LEN];
|
|
+ u32 stat_offset;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * struct edma_gmac_stats - Per-GMAC statistics.
|
|
+ * @rx_packets: Number of RX packets
|
|
+ * @rx_bytes: Number of RX bytes
|
|
+ * @rx_dropped: Number of RX dropped packets
|
|
+ * @rx_fraglist_packets: Number of RX fraglist packets
|
|
+ * @rx_nr_frag_packets: Number of RX nr fragment packets
|
|
+ * @rx_nr_frag_headroom_err: Number of RX nr fragment packets with headroom error
|
|
+ * @tx_packets: Number of TX packets
|
|
+ * @tx_bytes: Number of TX bytes
|
|
+ * @tx_dropped: Number of TX dropped packets
|
|
+ * @tx_nr_frag_packets: Number of TX nr fragment packets
|
|
+ * @tx_fraglist_packets: Number of TX fraglist packets
|
|
+ * @tx_fraglist_with_nr_frags_packets: Number of TX fraglist packets with nr fragments
|
|
+ * @tx_tso_packets: Number of TX TCP segmentation offload packets
|
|
+ * @tx_tso_drop_packets: Number of TX TCP segmentation dropped packets
|
|
+ * @tx_gso_packets: Number of TX SW GSO packets
|
|
+ * @tx_gso_drop_packets: Number of TX SW GSO dropped packets
|
|
+ * @tx_queue_stopped: Number of times Queue got stopped
|
|
+ */
|
|
+struct edma_gmac_stats {
|
|
+ u64 rx_packets;
|
|
+ u64 rx_bytes;
|
|
+ u64 rx_dropped;
|
|
+ u64 rx_fraglist_packets;
|
|
+ u64 rx_nr_frag_packets;
|
|
+ u64 rx_nr_frag_headroom_err;
|
|
+ u64 tx_packets;
|
|
+ u64 tx_bytes;
|
|
+ u64 tx_dropped;
|
|
+ u64 tx_nr_frag_packets;
|
|
+ u64 tx_fraglist_packets;
|
|
+ u64 tx_fraglist_with_nr_frags_packets;
|
|
+ u64 tx_tso_packets;
|
|
+ u64 tx_tso_drop_packets;
|
|
+ u64 tx_gso_packets;
|
|
+ u64 tx_gso_drop_packets;
|
|
+ u64 tx_queue_stopped[EDMA_MAX_CORE];
|
|
+};
|
|
+
|
|
+#define EDMA_STAT(m) offsetof(struct edma_gmac_stats, m)
|
|
+
|
|
+static const struct edma_ethtool_stats edma_gstrings_stats[] = {
|
|
+ {"rx_bytes", EDMA_STAT(rx_bytes)},
|
|
+ {"rx_packets", EDMA_STAT(rx_packets)},
|
|
+ {"rx_dropped", EDMA_STAT(rx_dropped)},
|
|
+ {"rx_fraglist_packets", EDMA_STAT(rx_fraglist_packets)},
|
|
+ {"rx_nr_frag_packets", EDMA_STAT(rx_nr_frag_packets)},
|
|
+ {"rx_nr_frag_headroom_err", EDMA_STAT(rx_nr_frag_headroom_err)},
|
|
+ {"tx_bytes", EDMA_STAT(tx_bytes)},
|
|
+ {"tx_packets", EDMA_STAT(tx_packets)},
|
|
+ {"tx_dropped", EDMA_STAT(tx_dropped)},
|
|
+ {"tx_nr_frag_packets", EDMA_STAT(tx_nr_frag_packets)},
|
|
+ {"tx_fraglist_packets", EDMA_STAT(tx_fraglist_packets)},
|
|
+ {"tx_fraglist_nr_frags_packets", EDMA_STAT(tx_fraglist_with_nr_frags_packets)},
|
|
+ {"tx_tso_packets", EDMA_STAT(tx_tso_packets)},
|
|
+ {"tx_tso_drop_packets", EDMA_STAT(tx_tso_drop_packets)},
|
|
+ {"tx_gso_packets", EDMA_STAT(tx_gso_packets)},
|
|
+ {"tx_gso_drop_packets", EDMA_STAT(tx_gso_drop_packets)},
|
|
+ {"tx_queue_stopped_cpu0", EDMA_STAT(tx_queue_stopped[0])},
|
|
+ {"tx_queue_stopped_cpu1", EDMA_STAT(tx_queue_stopped[1])},
|
|
+ {"tx_queue_stopped_cpu2", EDMA_STAT(tx_queue_stopped[2])},
|
|
+ {"tx_queue_stopped_cpu3", EDMA_STAT(tx_queue_stopped[3])},
|
|
+};
|
|
+
|
|
+#define EDMA_STATS_LEN ARRAY_SIZE(edma_gstrings_stats)
|
|
+
|
|
+static void edma_port_get_stats(struct net_device *netdev,
|
|
+ struct edma_gmac_stats *stats)
|
|
+{
|
|
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
|
|
+ struct edma_port_rx_stats *pcpu_rx_stats;
|
|
+ struct edma_port_tx_stats *pcpu_tx_stats;
|
|
+ int i;
|
|
+
|
|
+ memset(stats, 0, sizeof(struct edma_port_pcpu_stats));
|
|
+
|
|
+ for_each_possible_cpu(i) {
|
|
+ struct edma_port_rx_stats rxp;
|
|
+ struct edma_port_tx_stats txp;
|
|
+ unsigned int start;
|
|
+
|
|
+ pcpu_rx_stats = per_cpu_ptr(port_priv->pcpu_stats.rx_stats, i);
|
|
+
|
|
+ do {
|
|
+ start = u64_stats_fetch_begin(&pcpu_rx_stats->syncp);
|
|
+ memcpy(&rxp, pcpu_rx_stats, sizeof(*pcpu_rx_stats));
|
|
+ } while (u64_stats_fetch_retry(&pcpu_rx_stats->syncp, start));
|
|
+
|
|
+ stats->rx_packets += rxp.rx_pkts;
|
|
+ stats->rx_bytes += rxp.rx_bytes;
|
|
+ stats->rx_dropped += rxp.rx_drops;
|
|
+ stats->rx_nr_frag_packets += rxp.rx_nr_frag_pkts;
|
|
+ stats->rx_fraglist_packets += rxp.rx_fraglist_pkts;
|
|
+ stats->rx_nr_frag_headroom_err += rxp.rx_nr_frag_headroom_err;
|
|
+
|
|
+ pcpu_tx_stats = per_cpu_ptr(port_priv->pcpu_stats.tx_stats, i);
|
|
+
|
|
+ do {
|
|
+ start = u64_stats_fetch_begin(&pcpu_tx_stats->syncp);
|
|
+ memcpy(&txp, pcpu_tx_stats, sizeof(*pcpu_tx_stats));
|
|
+ } while (u64_stats_fetch_retry(&pcpu_tx_stats->syncp, start));
|
|
+
|
|
+ stats->tx_packets += txp.tx_pkts;
|
|
+ stats->tx_bytes += txp.tx_bytes;
|
|
+ stats->tx_dropped += txp.tx_drops;
|
|
+ stats->tx_nr_frag_packets += txp.tx_nr_frag_pkts;
|
|
+ stats->tx_fraglist_packets += txp.tx_fraglist_pkts;
|
|
+ stats->tx_fraglist_with_nr_frags_packets += txp.tx_fraglist_with_nr_frags_pkts;
|
|
+ stats->tx_tso_packets += txp.tx_tso_pkts;
|
|
+ stats->tx_tso_drop_packets += txp.tx_tso_drop_pkts;
|
|
+ stats->tx_gso_packets += txp.tx_gso_pkts;
|
|
+ stats->tx_gso_drop_packets += txp.tx_gso_drop_pkts;
|
|
+ stats->tx_queue_stopped[i] += txp.tx_queue_stopped[i];
|
|
+ }
|
|
+}
|
|
+
|
|
+static void edma_get_ethtool_stats(struct net_device *netdev,
|
|
+ __maybe_unused struct ethtool_stats *stats,
|
|
+ u64 *data)
|
|
+{
|
|
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
|
|
+ struct edma_gmac_stats edma_stats;
|
|
+ u64 *mib_data;
|
|
+ int i;
|
|
+ u8 *p;
|
|
+
|
|
+ if (!port_priv)
|
|
+ return;
|
|
+
|
|
+ /* Get the DMA Driver statistics from the data plane if available. */
|
|
+ memset(&edma_stats, 0, sizeof(struct edma_gmac_stats));
|
|
+ edma_port_get_stats(netdev, &edma_stats);
|
|
+
|
|
+ /* Populate data plane statistics. */
|
|
+ for (i = 0; i < EDMA_STATS_LEN; i++) {
|
|
+ p = ((u8 *)(&edma_stats) + edma_gstrings_stats[i].stat_offset);
|
|
+ data[i] = *(u64 *)p;
|
|
+ }
|
|
+
|
|
+ /* Get the GMAC MIB statistics along with the DMA driver statistics. */
|
|
+ mib_data = &data[EDMA_STATS_LEN];
|
|
+ ppe_port_get_ethtool_stats(port_priv->ppe_port, mib_data);
|
|
+}
|
|
+
|
|
+static int edma_get_strset_count(struct net_device *netdev, int sset)
|
|
+{
|
|
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
|
|
+ int sset_count = 0;
|
|
+
|
|
+ if (!port_priv || sset != ETH_SS_STATS)
|
|
+ return 0;
|
|
+
|
|
+ sset_count = ppe_port_get_sset_count(port_priv->ppe_port, sset);
|
|
+
|
|
+ return (EDMA_STATS_LEN + sset_count);
|
|
+}
|
|
+
|
|
+static void edma_get_strings(struct net_device *netdev, u32 stringset,
|
|
+ u8 *data)
|
|
+{
|
|
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
|
|
+ int i;
|
|
+
|
|
+ if (!port_priv || stringset != ETH_SS_STATS)
|
|
+ return;
|
|
+
|
|
+ for (i = 0; i < EDMA_STATS_LEN; i++) {
|
|
+ memcpy(data, edma_gstrings_stats[i].stat_string,
|
|
+ strlen(edma_gstrings_stats[i].stat_string));
|
|
+ data += ETH_GSTRING_LEN;
|
|
+ }
|
|
+
|
|
+ ppe_port_get_strings(port_priv->ppe_port, stringset, data);
|
|
+}
|
|
+
|
|
+static int edma_get_link_ksettings(struct net_device *netdev,
|
|
+ struct ethtool_link_ksettings *cmd)
|
|
+{
|
|
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
|
|
+ struct ppe_port *port = port_priv->ppe_port;
|
|
+
|
|
+ if (!port_priv)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return phylink_ethtool_ksettings_get(port->phylink, cmd);
|
|
+}
|
|
+
|
|
+static int edma_set_link_ksettings(struct net_device *netdev,
|
|
+ const struct ethtool_link_ksettings *cmd)
|
|
+{
|
|
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
|
|
+ struct ppe_port *port = port_priv->ppe_port;
|
|
+
|
|
+ if (!port_priv)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return phylink_ethtool_ksettings_set(port->phylink, cmd);
|
|
+}
|
|
+
|
|
+static void edma_get_pauseparam(struct net_device *netdev,
|
|
+ struct ethtool_pauseparam *pause)
|
|
+{
|
|
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
|
|
+ struct ppe_port *port = port_priv->ppe_port;
|
|
+
|
|
+ if (!port_priv)
|
|
+ return;
|
|
+
|
|
+ phylink_ethtool_get_pauseparam(port->phylink, pause);
|
|
+}
|
|
+
|
|
+static int edma_set_pauseparam(struct net_device *netdev,
|
|
+ struct ethtool_pauseparam *pause)
|
|
+{
|
|
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
|
|
+ struct ppe_port *port = port_priv->ppe_port;
|
|
+
|
|
+ if (!port_priv)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return phylink_ethtool_set_pauseparam(port->phylink, pause);
|
|
+}
|
|
+
|
|
+static int edma_get_eee(struct net_device *netdev, struct ethtool_eee *eee)
|
|
+{
|
|
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
|
|
+ struct ppe_port *port = port_priv->ppe_port;
|
|
+
|
|
+ if (!port_priv)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return phylink_ethtool_get_eee(port->phylink, eee);
|
|
+}
|
|
+
|
|
+static int edma_set_eee(struct net_device *netdev, struct ethtool_eee *eee)
|
|
+{
|
|
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
|
|
+ struct ppe_port *port = port_priv->ppe_port;
|
|
+ int ret;
|
|
+
|
|
+ if (!port_priv)
|
|
+ return -EINVAL;
|
|
+
|
|
+ ret = ppe_port_set_mac_eee(port_priv->ppe_port, eee);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return phylink_ethtool_set_eee(port->phylink, eee);
|
|
+}
|
|
+
|
|
+static const struct ethtool_ops edma_ethtool_ops = {
|
|
+ .get_strings = &edma_get_strings,
|
|
+ .get_sset_count = &edma_get_strset_count,
|
|
+ .get_ethtool_stats = &edma_get_ethtool_stats,
|
|
+ .get_link = ðtool_op_get_link,
|
|
+ .get_link_ksettings = edma_get_link_ksettings,
|
|
+ .set_link_ksettings = edma_set_link_ksettings,
|
|
+ .get_pauseparam = &edma_get_pauseparam,
|
|
+ .set_pauseparam = &edma_set_pauseparam,
|
|
+ .get_eee = &edma_get_eee,
|
|
+ .set_eee = &edma_set_eee,
|
|
+};
|
|
+
|
|
+/**
|
|
+ * edma_set_ethtool_ops - Set ethtool operations
|
|
+ * @netdev: Netdevice
|
|
+ *
|
|
+ * Set ethtool operations.
|
|
+ */
|
|
+void edma_set_ethtool_ops(struct net_device *netdev)
|
|
+{
|
|
+ netdev->ethtool_ops = &edma_ethtool_ops;
|
|
+}
|
|
--- a/drivers/net/ethernet/qualcomm/ppe/edma_port.c
|
|
+++ b/drivers/net/ethernet/qualcomm/ppe/edma_port.c
|
|
@@ -380,6 +380,7 @@ int edma_port_setup(struct ppe_port *por
|
|
netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
|
|
netdev->netdev_ops = &edma_port_netdev_ops;
|
|
netdev->gso_max_segs = GSO_MAX_SEGS;
|
|
+ edma_set_ethtool_ops(netdev);
|
|
|
|
maddr = mac_addr;
|
|
if (of_get_mac_address(np, maddr))
|