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,
} };--
2.20.1