1bdecf57290e9b3389452472012b84af46c272b1
[librecmc/librecmc.git] /
1 From: Florian Fainelli <f.fainelli@gmail.com>
2 Date: Tue, 29 Nov 2016 09:57:17 -0800
3 Subject: [PATCH] net: phy: broadcom: Add support code for reading PHY counters
4
5 Broadcom PHYs expose a number of PHY error counters: receive errors,
6 false carrier sense, SerDes BER count, local and remote receive errors.
7 Add support code to allow retrieving these error counters. Since the
8 Broadcom PHY library code is used by several drivers, make it possible
9 for them to specify the storage for the software copy of the statistics.
10
11 Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
12 Signed-off-by: David S. Miller <davem@davemloft.net>
13 ---
14
15 --- a/drivers/net/phy/bcm-phy-lib.c
16 +++ b/drivers/net/phy/bcm-phy-lib.c
17 @@ -17,6 +17,7 @@
18  #include <linux/mdio.h>
19  #include <linux/module.h>
20  #include <linux/phy.h>
21 +#include <linux/ethtool.h>
22  
23  #define MII_BCM_CHANNEL_WIDTH     0x2000
24  #define BCM_CL45VEN_EEE_ADV       0x3c
25 @@ -231,6 +232,75 @@ int bcm_phy_set_eee(struct phy_device *p
26  }
27  EXPORT_SYMBOL_GPL(bcm_phy_set_eee);
28  
29 +struct bcm_phy_hw_stat {
30 +       const char *string;
31 +       u8 reg;
32 +       u8 shift;
33 +       u8 bits;
34 +};
35 +
36 +/* Counters freeze at either 0xffff or 0xff, better than nothing */
37 +static const struct bcm_phy_hw_stat bcm_phy_hw_stats[] = {
38 +       { "phy_receive_errors", MII_BRCM_CORE_BASE12, 0, 16 },
39 +       { "phy_serdes_ber_errors", MII_BRCM_CORE_BASE13, 8, 8 },
40 +       { "phy_false_carrier_sense_errors", MII_BRCM_CORE_BASE13, 0, 8 },
41 +       { "phy_local_rcvr_nok", MII_BRCM_CORE_BASE14, 8, 8 },
42 +       { "phy_remote_rcv_nok", MII_BRCM_CORE_BASE14, 0, 8 },
43 +};
44 +
45 +int bcm_phy_get_sset_count(struct phy_device *phydev)
46 +{
47 +       return ARRAY_SIZE(bcm_phy_hw_stats);
48 +}
49 +EXPORT_SYMBOL_GPL(bcm_phy_get_sset_count);
50 +
51 +void bcm_phy_get_strings(struct phy_device *phydev, u8 *data)
52 +{
53 +       unsigned int i;
54 +
55 +       for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
56 +               memcpy(data + i * ETH_GSTRING_LEN,
57 +                      bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN);
58 +}
59 +EXPORT_SYMBOL_GPL(bcm_phy_get_strings);
60 +
61 +#ifndef UINT64_MAX
62 +#define UINT64_MAX              (u64)(~((u64)0))
63 +#endif
64 +
65 +/* Caller is supposed to provide appropriate storage for the library code to
66 + * access the shadow copy
67 + */
68 +static u64 bcm_phy_get_stat(struct phy_device *phydev, u64 *shadow,
69 +                           unsigned int i)
70 +{
71 +       struct bcm_phy_hw_stat stat = bcm_phy_hw_stats[i];
72 +       int val;
73 +       u64 ret;
74 +
75 +       val = phy_read(phydev, stat.reg);
76 +       if (val < 0) {
77 +               ret = UINT64_MAX;
78 +       } else {
79 +               val >>= stat.shift;
80 +               val = val & ((1 << stat.bits) - 1);
81 +               shadow[i] += val;
82 +               ret = shadow[i];
83 +       }
84 +
85 +       return ret;
86 +}
87 +
88 +void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow,
89 +                      struct ethtool_stats *stats, u64 *data)
90 +{
91 +       unsigned int i;
92 +
93 +       for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
94 +               data[i] = bcm_phy_get_stat(phydev, shadow, i);
95 +}
96 +EXPORT_SYMBOL_GPL(bcm_phy_get_stats);
97 +
98  MODULE_DESCRIPTION("Broadcom PHY Library");
99  MODULE_LICENSE("GPL v2");
100  MODULE_AUTHOR("Broadcom Corporation");
101 --- a/drivers/net/phy/bcm-phy-lib.h
102 +++ b/drivers/net/phy/bcm-phy-lib.h
103 @@ -37,4 +37,10 @@ int bcm_phy_config_intr(struct phy_devic
104  int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down);
105  
106  int bcm_phy_set_eee(struct phy_device *phydev, bool enable);
107 +
108 +int bcm_phy_get_sset_count(struct phy_device *phydev);
109 +void bcm_phy_get_strings(struct phy_device *phydev, u8 *data);
110 +void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow,
111 +                      struct ethtool_stats *stats, u64 *data);
112 +
113  #endif /* _LINUX_BCM_PHY_LIB_H */
114 --- a/include/linux/brcmphy.h
115 +++ b/include/linux/brcmphy.h
116 @@ -234,6 +234,9 @@
117  #define LPI_FEATURE_EN_DIG1000X                0x4000
118  
119  /* Core register definitions*/
120 +#define MII_BRCM_CORE_BASE12   0x12
121 +#define MII_BRCM_CORE_BASE13   0x13
122 +#define MII_BRCM_CORE_BASE14   0x14
123  #define MII_BRCM_CORE_BASE1E   0x1E
124  #define MII_BRCM_CORE_EXPB0    0xB0
125  #define MII_BRCM_CORE_EXPB1    0xB1