From b7656aa689b4b366dc835f9570f9ad8127ea6d15 Mon Sep 17 00:00:00 2001
From: Mohd Husaam Mehdi <h.mehdi@gxgroup.eu>
Date: Wed, 1 Nov 2023 14:06:40 +0530
Subject: [PATCH] Add support for clear_stats

---
 bcm/bcm.c       | 26 ++++++++++++++++++++++++++
 econet/econet.c | 22 ++++++++++++++++++++++
 ethernet.c      | 10 ++++++++++
 ethernet.h      |  3 +++
 4 files changed, 61 insertions(+)

diff --git a/bcm/bcm.c b/bcm/bcm.c
index 382392b..d8edf2f 100644
--- a/bcm/bcm.c
+++ b/bcm/bcm.c
@@ -474,6 +474,31 @@ int bcm_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon)
 	return 0;
 }
 
+int bcm_eth_clear_stats(const char *ifname)
+{
+	int ret, unit = -1, port = -1;
+	struct ethswctl_data data;
+
+	memset(&data, 0, sizeof(struct ethswctl_data));
+
+	ret = bcm_eth_get_unit_port(ifname, &unit, &port);
+	if (ret)
+		return -1;
+
+	data.op = ETHSWSTATPORTCLR;
+	data.port = port;
+	data.unit = unit;
+
+	ret = eth_ioctl(ifname, SIOCETHSWCTLOPS, &data,
+			sizeof(struct ethswctl_data));
+	if (ret != 0) {
+		libethernet_err("ioctl failed! ret = %d\n", ret);
+		return -1;
+	}
+
+	return 0;
+}
+
 const struct eth_ops bcm_eth_ops = {
 	.ifname = "eth",
 	//.up = bcm_eth_up,
@@ -485,4 +510,5 @@ const struct eth_ops bcm_eth_ops = {
 	.poweron_phy = bcm_eth_poweron_phy,
 	.poweroff_phy = bcm_eth_poweroff_phy,
 	.reset_phy = bcm_eth_reset_phy,
+	.clear_stats = bcm_eth_clear_stats,
 };
diff --git a/econet/econet.c b/econet/econet.c
index 42cc04f..b965dfd 100644
--- a/econet/econet.c
+++ b/econet/econet.c
@@ -138,6 +138,27 @@ int econet_eth_reset_phy(const char *name, int phy_id)
 	return 0;
 }
 
+int econet_clear_stats(const char *ifname)
+{
+	char clear_stats_filename[128] = {0};
+	FILE *fp = NULL;
+
+	// clear stats files are named as eth0.1_clear_stats etc.
+	snprintf(clear_stats_filename, sizeof(clear_stats_filename), "/proc/tc3162/%s_clear_stats", ifname);
+
+	fp = fopen(clear_stats_filename, "w");
+	if (!fp) {
+		libethernet_err("%s(): fopen() failed for %s\n", __func__, clear_stats_filename);
+		return -1;
+	} else {
+		// just write 1 to clear the stats
+		fprintf(fp, "1");
+		fclose(fp);
+	}
+
+	return 0;
+}
+
 /* Declare separate eth ops for all known Econet interfaces */
 #define ECNT_ETH_OPS(__name, __interface_name)          \
 const struct eth_ops __name = {                         \
@@ -149,6 +170,7 @@ const struct eth_ops __name = {                         \
 	.poweron_phy = econet_eth_poweron_phy,              \
 	.poweroff_phy = econet_eth_poweroff_phy,            \
 	.reset_phy = econet_eth_reset_phy,                  \
+	.clear_stats = econet_clear_stats,                  \
 }
 
 ECNT_ETH_OPS(econet_gen_eth_ops, "eth");
diff --git a/ethernet.c b/ethernet.c
index 8c81568..aea13ef 100644
--- a/ethernet.c
+++ b/ethernet.c
@@ -165,6 +165,16 @@ int eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon)
 	return -1;
 }
 
+int eth_clear_stats(const char *ifname)
+{
+	const struct eth_ops *eth = get_eth_driver(ifname);
+
+	if (eth && eth->clear_stats)
+		return eth->clear_stats(ifname);
+
+	return -1;
+}
+
 int eth_poweron_phy(const char *ifname, struct eth_phy p)
 {
 	const struct eth_ops *eth = get_eth_driver(ifname);
diff --git a/ethernet.h b/ethernet.h
index 3f1dd4e..b08fded 100644
--- a/ethernet.h
+++ b/ethernet.h
@@ -207,6 +207,8 @@ struct eth_ops {
 	int (*get_stats)(const char *ifname, struct eth_stats *s);
 	int (*get_info)(const char *ifname, struct eth_info *info);
 	int (*get_rmon_stats)(const char *ifname, struct eth_rmon_stats *rmon);
+
+	int (*clear_stats)(const char *ifname);
 };
 
 
@@ -220,6 +222,7 @@ int eth_set_operstate(const char *ifname, ifopstatus_t s);
 int eth_get_stats(const char *ifname, struct eth_stats *c);
 int eth_get_info(const char *ifname, struct eth_info *info);
 int eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon);
+int eth_clear_stats(const char *ifname);
 
 int eth_reset_phy(const char *ifname, int phy_id);
 int eth_poweroff_phy(const char *ifname, struct eth_phy p);
-- 
GitLab