mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-21 06:33:41 +00:00
126 lines
3.7 KiB
Diff
126 lines
3.7 KiB
Diff
|
From: Florian Fainelli <f.fainelli@gmail.com>
|
||
|
Date: Tue, 29 Nov 2016 09:57:17 -0800
|
||
|
Subject: [PATCH] net: phy: broadcom: Add support code for reading PHY counters
|
||
|
|
||
|
Broadcom PHYs expose a number of PHY error counters: receive errors,
|
||
|
false carrier sense, SerDes BER count, local and remote receive errors.
|
||
|
Add support code to allow retrieving these error counters. Since the
|
||
|
Broadcom PHY library code is used by several drivers, make it possible
|
||
|
for them to specify the storage for the software copy of the statistics.
|
||
|
|
||
|
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||
|
---
|
||
|
|
||
|
--- a/drivers/net/phy/bcm-phy-lib.c
|
||
|
+++ b/drivers/net/phy/bcm-phy-lib.c
|
||
|
@@ -17,6 +17,7 @@
|
||
|
#include <linux/mdio.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/phy.h>
|
||
|
+#include <linux/ethtool.h>
|
||
|
|
||
|
#define MII_BCM_CHANNEL_WIDTH 0x2000
|
||
|
#define BCM_CL45VEN_EEE_ADV 0x3c
|
||
|
@@ -231,6 +232,75 @@ int bcm_phy_set_eee(struct phy_device *p
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(bcm_phy_set_eee);
|
||
|
|
||
|
+struct bcm_phy_hw_stat {
|
||
|
+ const char *string;
|
||
|
+ u8 reg;
|
||
|
+ u8 shift;
|
||
|
+ u8 bits;
|
||
|
+};
|
||
|
+
|
||
|
+/* Counters freeze at either 0xffff or 0xff, better than nothing */
|
||
|
+static const struct bcm_phy_hw_stat bcm_phy_hw_stats[] = {
|
||
|
+ { "phy_receive_errors", MII_BRCM_CORE_BASE12, 0, 16 },
|
||
|
+ { "phy_serdes_ber_errors", MII_BRCM_CORE_BASE13, 8, 8 },
|
||
|
+ { "phy_false_carrier_sense_errors", MII_BRCM_CORE_BASE13, 0, 8 },
|
||
|
+ { "phy_local_rcvr_nok", MII_BRCM_CORE_BASE14, 8, 8 },
|
||
|
+ { "phy_remote_rcv_nok", MII_BRCM_CORE_BASE14, 0, 8 },
|
||
|
+};
|
||
|
+
|
||
|
+int bcm_phy_get_sset_count(struct phy_device *phydev)
|
||
|
+{
|
||
|
+ return ARRAY_SIZE(bcm_phy_hw_stats);
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(bcm_phy_get_sset_count);
|
||
|
+
|
||
|
+void bcm_phy_get_strings(struct phy_device *phydev, u8 *data)
|
||
|
+{
|
||
|
+ unsigned int i;
|
||
|
+
|
||
|
+ for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
|
||
|
+ memcpy(data + i * ETH_GSTRING_LEN,
|
||
|
+ bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN);
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(bcm_phy_get_strings);
|
||
|
+
|
||
|
+#ifndef UINT64_MAX
|
||
|
+#define UINT64_MAX (u64)(~((u64)0))
|
||
|
+#endif
|
||
|
+
|
||
|
+/* Caller is supposed to provide appropriate storage for the library code to
|
||
|
+ * access the shadow copy
|
||
|
+ */
|
||
|
+static u64 bcm_phy_get_stat(struct phy_device *phydev, u64 *shadow,
|
||
|
+ unsigned int i)
|
||
|
+{
|
||
|
+ struct bcm_phy_hw_stat stat = bcm_phy_hw_stats[i];
|
||
|
+ int val;
|
||
|
+ u64 ret;
|
||
|
+
|
||
|
+ val = phy_read(phydev, stat.reg);
|
||
|
+ if (val < 0) {
|
||
|
+ ret = UINT64_MAX;
|
||
|
+ } else {
|
||
|
+ val >>= stat.shift;
|
||
|
+ val = val & ((1 << stat.bits) - 1);
|
||
|
+ shadow[i] += val;
|
||
|
+ ret = shadow[i];
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow,
|
||
|
+ struct ethtool_stats *stats, u64 *data)
|
||
|
+{
|
||
|
+ unsigned int i;
|
||
|
+
|
||
|
+ for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
|
||
|
+ data[i] = bcm_phy_get_stat(phydev, shadow, i);
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(bcm_phy_get_stats);
|
||
|
+
|
||
|
MODULE_DESCRIPTION("Broadcom PHY Library");
|
||
|
MODULE_LICENSE("GPL v2");
|
||
|
MODULE_AUTHOR("Broadcom Corporation");
|
||
|
--- a/drivers/net/phy/bcm-phy-lib.h
|
||
|
+++ b/drivers/net/phy/bcm-phy-lib.h
|
||
|
@@ -37,4 +37,10 @@ int bcm_phy_config_intr(struct phy_devic
|
||
|
int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down);
|
||
|
|
||
|
int bcm_phy_set_eee(struct phy_device *phydev, bool enable);
|
||
|
+
|
||
|
+int bcm_phy_get_sset_count(struct phy_device *phydev);
|
||
|
+void bcm_phy_get_strings(struct phy_device *phydev, u8 *data);
|
||
|
+void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow,
|
||
|
+ struct ethtool_stats *stats, u64 *data);
|
||
|
+
|
||
|
#endif /* _LINUX_BCM_PHY_LIB_H */
|
||
|
--- a/include/linux/brcmphy.h
|
||
|
+++ b/include/linux/brcmphy.h
|
||
|
@@ -234,6 +234,9 @@
|
||
|
#define LPI_FEATURE_EN_DIG1000X 0x4000
|
||
|
|
||
|
/* Core register definitions*/
|
||
|
+#define MII_BRCM_CORE_BASE12 0x12
|
||
|
+#define MII_BRCM_CORE_BASE13 0x13
|
||
|
+#define MII_BRCM_CORE_BASE14 0x14
|
||
|
#define MII_BRCM_CORE_BASE1E 0x1E
|
||
|
#define MII_BRCM_CORE_EXPB0 0xB0
|
||
|
#define MII_BRCM_CORE_EXPB1 0xB1
|