mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	Signed-off-by: Felix Fietkau <nbd@nbd.name> Signed-off-by: Tim Harvey <tharvey@gateworks.com> [fixes]
		
			
				
	
	
		
			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
 |