kernel: split patches folder up into backport, pending and hack folders
[openwrt/openwrt.git] / target / linux / generic / backport-4.9 / 076-v4.11-0002-net-phy-broadcom-Add-support-code-for-reading-PHY-co.patch
diff --git a/target/linux/generic/backport-4.9/076-v4.11-0002-net-phy-broadcom-Add-support-code-for-reading-PHY-co.patch b/target/linux/generic/backport-4.9/076-v4.11-0002-net-phy-broadcom-Add-support-code-for-reading-PHY-co.patch
new file mode 100644 (file)
index 0000000..1bdecf5
--- /dev/null
@@ -0,0 +1,125 @@
+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