Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+70 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/mdio.h>
#include <linux/mdio.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/phy.h>
#include <linux/phy.h>
#include <linux/ethtool.h>


#define MII_BCM_CHANNEL_WIDTH     0x2000
#define MII_BCM_CHANNEL_WIDTH     0x2000
#define BCM_CL45VEN_EEE_ADV       0x3c
#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);
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_DESCRIPTION("Broadcom PHY Library");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Broadcom Corporation");
MODULE_AUTHOR("Broadcom Corporation");
+5 −0
Original line number Original line Diff line number Diff line
@@ -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_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 */
#endif /* _LINUX_BCM_PHY_LIB_H */
+35 −0
Original line number Original line Diff line number Diff line
@@ -45,6 +45,10 @@
#define AFE_VDAC_OTHERS_0		MISC_ADDR(0x39, 3)
#define AFE_VDAC_OTHERS_0		MISC_ADDR(0x39, 3)
#define AFE_HPF_TRIM_OTHERS		MISC_ADDR(0x3a, 0)
#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)
static void r_rc_cal_reset(struct phy_device *phydev)
{
{
	/* Reset R_CAL/RC_CAL Engine */
	/* 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);
	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)					\
#define BCM7XXX_28NM_GPHY(_oui, _name)					\
{									\
{									\
	.phy_id		= (_oui),					\
	.phy_id		= (_oui),					\
@@ -364,6 +395,10 @@ static int bcm7xxx_28nm_set_tunable(struct phy_device *phydev,
	.resume		= bcm7xxx_28nm_resume,				\
	.resume		= bcm7xxx_28nm_resume,				\
	.get_tunable	= bcm7xxx_28nm_get_tunable,			\
	.get_tunable	= bcm7xxx_28nm_get_tunable,			\
	.set_tunable	= bcm7xxx_28nm_set_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)					\
#define BCM7XXX_40NM_EPHY(_oui, _name)					\
+3 −0
Original line number Original line Diff line number Diff line
@@ -244,6 +244,9 @@
#define LPI_FEATURE_EN_DIG1000X		0x4000
#define LPI_FEATURE_EN_DIG1000X		0x4000


/* Core register definitions*/
/* 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_BASE1E	0x1E
#define MII_BRCM_CORE_EXPB0	0xB0
#define MII_BRCM_CORE_EXPB0	0xB0
#define MII_BRCM_CORE_EXPB1	0xB1
#define MII_BRCM_CORE_EXPB1	0xB1