Commit 0f29f05b authored by David S. Miller's avatar David S. Miller

Merge branch 'broadcom-phy-internal-counters'

Florian Fainelli says:

====================
net: phy: broadcom: Support for PHY counters

This patch series adds support for reading the Broadcom PHYs internal counters.

Changes in v3:

- fixed the allocation of priv->stats in bcm7xxx

Changes in v2:

- fixed modular build reported by kbuild

- constify array of stats
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5a6681e2 b23ce9e8
......@@ -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
......@@ -317,6 +318,75 @@ int bcm_phy_downshift_set(struct phy_device *phydev, u8 count)
}
EXPORT_SYMBOL_GPL(bcm_phy_downshift_set);
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");
......@@ -42,4 +42,9 @@ int bcm_phy_downshift_get(struct phy_device *phydev, u8 *count);
int bcm_phy_downshift_set(struct phy_device *phydev, u8 count);
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 */
......@@ -45,6 +45,10 @@
#define AFE_VDAC_OTHERS_0 MISC_ADDR(0x39, 3)
#define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0)
struct bcm7xxx_phy_priv {
u64 *stats;
};
static void r_rc_cal_reset(struct phy_device *phydev)
{
/* Reset R_CAL/RC_CAL Engine */
......@@ -350,6 +354,33 @@ static int bcm7xxx_28nm_set_tunable(struct phy_device *phydev,
return genphy_restart_aneg(phydev);
}
static void bcm7xxx_28nm_get_phy_stats(struct phy_device *phydev,
struct ethtool_stats *stats, u64 *data)
{
struct bcm7xxx_phy_priv *priv = phydev->priv;
bcm_phy_get_stats(phydev, priv->stats, stats, data);
}
static int bcm7xxx_28nm_probe(struct phy_device *phydev)
{
struct bcm7xxx_phy_priv *priv;
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
phydev->priv = priv;
priv->stats = devm_kcalloc(&phydev->mdio.dev,
bcm_phy_get_sset_count(phydev), sizeof(u64),
GFP_KERNEL);
if (!priv->stats)
return -ENOMEM;
return 0;
}
#define BCM7XXX_28NM_GPHY(_oui, _name) \
{ \
.phy_id = (_oui), \
......@@ -364,6 +395,10 @@ static int bcm7xxx_28nm_set_tunable(struct phy_device *phydev,
.resume = bcm7xxx_28nm_resume, \
.get_tunable = bcm7xxx_28nm_get_tunable, \
.set_tunable = bcm7xxx_28nm_set_tunable, \
.get_sset_count = bcm_phy_get_sset_count, \
.get_strings = bcm_phy_get_strings, \
.get_stats = bcm7xxx_28nm_get_phy_stats, \
.probe = bcm7xxx_28nm_probe, \
}
#define BCM7XXX_40NM_EPHY(_oui, _name) \
......
......@@ -244,6 +244,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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment