diff mbox series

[net-next,8/9] net: phy: icplus: add PHY counter for IP101G

Message ID 20210209164051.18156-9-michael@walle.cc (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series net: phy: icplus: cleanups and new features | expand

Checks

Context Check Description
netdev/cover_letter success Link
netdev/fixes_present success Link
netdev/patch_count success Link
netdev/tree_selection success Clearly marked for net-next
netdev/subject_prefix success Link
netdev/cc_maintainers success CCed 6 of 6 maintainers
netdev/source_inline success Was 0 now: 0
netdev/verify_signedoff success Link
netdev/module_param success Was 0 now: 0
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/verify_fixes success Link
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 111 lines checked
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/header_inline success Link
netdev/stable success Stable not CCed

Commit Message

Michael Walle Feb. 9, 2021, 4:40 p.m. UTC
The IP101G provides three counters: RX packets, CRC errors and symbol
errors. The error counters can be configured to clear automatically on
read. Unfortunately, this isn't true for the RX packet counter. Because
of this and because the RX packet counter is more likely to overflow,
than the error counters implement only support for the error counters.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 drivers/net/phy/icplus.c | 78 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

Comments

Andrew Lunn Feb. 10, 2021, 2:10 a.m. UTC | #1
On Tue, Feb 09, 2021 at 05:40:50PM +0100, Michael Walle wrote:
> The IP101G provides three counters: RX packets, CRC errors and symbol
> errors. The error counters can be configured to clear automatically on
> read. Unfortunately, this isn't true for the RX packet counter. Because
> of this and because the RX packet counter is more likely to overflow,
> than the error counters implement only support for the error counters.
> 
> Signed-off-by: Michael Walle <michael@walle.cc>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew
diff mbox series

Patch

diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index 858b9326a72d..d1b57d81f281 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -51,6 +51,12 @@  MODULE_LICENSE("GPL");
 
 #define IP101G_DEFAULT_PAGE			16
 
+#define IP101G_P1_CNT_CTRL		17
+#define CNT_CTRL_RX_EN			BIT(13)
+#define IP101G_P8_CNT_CTRL		17
+#define CNT_CTRL_RDCLR_EN		BIT(15)
+#define IP101G_CNT_REG			18
+
 #define IP175C_PHY_ID 0x02430d80
 #define IP1001_PHY_ID 0x02430d90
 #define IP101A_PHY_ID 0x02430c54
@@ -70,9 +76,20 @@  enum ip101_model {
 	IP101G,
 };
 
+struct ip101g_hw_stat {
+	const char *name;
+	int page;
+};
+
+static struct ip101g_hw_stat ip101g_hw_stats[] = {
+	{ "phy_crc_errors", 1 },
+	{ "phy_symbol_errors", 11, },
+};
+
 struct ip101a_g_phy_priv {
 	enum ip101gr_sel_intr32 sel_intr32;
 	enum ip101_model model;
+	u64 stats[ARRAY_SIZE(ip101g_hw_stats)];
 };
 
 static int ip175c_config_init(struct phy_device *phydev)
@@ -254,6 +271,18 @@  static int ip101a_g_config_init(struct phy_device *phydev)
 	struct ip101a_g_phy_priv *priv = phydev->priv;
 	int oldpage, err;
 
+	/* Enable the PHY counters */
+	err = phy_modify_paged(phydev, 1, IP101G_P1_CNT_CTRL,
+			       CNT_CTRL_RX_EN, CNT_CTRL_RX_EN);
+	if (err)
+		return err;
+
+	/* Clear error counters on read */
+	err = phy_modify_paged(phydev, 8, IP101G_P8_CNT_CTRL,
+			       CNT_CTRL_RDCLR_EN, CNT_CTRL_RDCLR_EN);
+	if (err)
+		return err;
+
 	oldpage = phy_select_page(phydev, IP101G_DEFAULT_PAGE);
 
 	/* configure the RXER/INTR_32 pin of the 32-pin IP101GR if needed: */
@@ -373,6 +402,52 @@  static int ip101a_g_write_page(struct phy_device *phydev, int page)
 	return __phy_write(phydev, IP101G_PAGE_CONTROL, page);
 }
 
+static int ip101a_g_get_sset_count(struct phy_device *phydev)
+{
+	struct ip101a_g_phy_priv *priv = phydev->priv;
+
+	if (priv->model == IP101A)
+		return -EOPNOTSUPP;
+
+	return ARRAY_SIZE(ip101g_hw_stats);
+}
+
+static void ip101a_g_get_strings(struct phy_device *phydev, u8 *data)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ip101g_hw_stats); i++)
+		strscpy(data + i * ETH_GSTRING_LEN,
+			ip101g_hw_stats[i].name, ETH_GSTRING_LEN);
+}
+
+static u64 ip101a_g_get_stat(struct phy_device *phydev, int i)
+{
+	struct ip101g_hw_stat stat = ip101g_hw_stats[i];
+	struct ip101a_g_phy_priv *priv = phydev->priv;
+	int val;
+	u64 ret;
+
+	val = phy_read_paged(phydev, stat.page, IP101G_CNT_REG);
+	if (val < 0) {
+		ret = U64_MAX;
+	} else {
+		priv->stats[i] += val;
+		ret = priv->stats[i];
+	}
+
+	return ret;
+}
+
+static void ip101a_g_get_stats(struct phy_device *phydev,
+			       struct ethtool_stats *stats, u64 *data)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ip101g_hw_stats); i++)
+		data[i] = ip101a_g_get_stat(phydev, i);
+}
+
 static struct phy_driver icplus_driver[] = {
 {
 	PHY_ID_MATCH_MODEL(IP175C_PHY_ID),
@@ -402,6 +477,9 @@  static struct phy_driver icplus_driver[] = {
 	.read_page	= ip101a_g_read_page,
 	.write_page	= ip101a_g_write_page,
 	.soft_reset	= genphy_soft_reset,
+	.get_sset_count = ip101a_g_get_sset_count,
+	.get_strings	= ip101a_g_get_strings,
+	.get_stats	= ip101a_g_get_stats,
 	.suspend	= genphy_suspend,
 	.resume		= genphy_resume,
 } };