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

Commit 21fca6e0 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-Extend-availability-of-PHY-statistics'



Florian Fainelli says:

====================
net: Extend availability of PHY statistics

This patch series adds support for retrieving PHY statistics with DSA switches
when the CPU port uses a PHY to PHY connection (as opposed to MAC to MAC).
To get there a number of things are done:

- first we move the code dealing with PHY statistics outside of net/core/ethtool.c
  and create helper functions since the same code will be reused
- then we allow network device drivers to provide an ethtool_get_phy_stats callback
  when the standard PHY library helpers are not suitable
- we update the DSA functions dealing with ethtool operations to get passed a
  stringset instead of assuming ETH_SS_STATS like they currently do
- then we provide a set of standard helpers within DSA as a framework and add
  the plumbing to allow retrieving the PHY statistics of the CPU port(s)
- finally plug support for retrieving such PHY statistics with the b53 driver

Changes in v3:

- retrict the b53 change to 539x and 531x5 series of switches
- added a change to dsa_loop.c to help test the feature

Changes in v2:

- got actual testing when the DSA master network device has a PHY that
  already provides statistics (thanks Nikita!)

- fixed the kbuild error reported when CONFIG_PHYLIB=n

- removed the checking of ops which is redundant and not needed
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 83494407 96cbddcd
Loading
Loading
Loading
Loading
+73 −8
Original line number Diff line number Diff line
@@ -806,16 +806,39 @@ static unsigned int b53_get_mib_size(struct b53_device *dev)
		return B53_MIBS_SIZE;
}

void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
static struct phy_device *b53_get_phy_device(struct dsa_switch *ds, int port)
{
	/* These ports typically do not have built-in PHYs */
	switch (port) {
	case B53_CPU_PORT_25:
	case 7:
	case B53_CPU_PORT:
		return NULL;
	}

	return mdiobus_get_phy(ds->slave_mii_bus, port);
}

void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
		     uint8_t *data)
{
	struct b53_device *dev = ds->priv;
	const struct b53_mib_desc *mibs = b53_get_mib(dev);
	unsigned int mib_size = b53_get_mib_size(dev);
	struct phy_device *phydev;
	unsigned int i;

	if (stringset == ETH_SS_STATS) {
		for (i = 0; i < mib_size; i++)
			strlcpy(data + i * ETH_GSTRING_LEN,
				mibs[i].name, ETH_GSTRING_LEN);
	} else if (stringset == ETH_SS_PHY_STATS) {
		phydev = b53_get_phy_device(ds, port);
		if (!phydev)
			return;

		phy_ethtool_get_strings(phydev, data);
	}
}
EXPORT_SYMBOL(b53_get_strings);

@@ -852,11 +875,34 @@ void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
}
EXPORT_SYMBOL(b53_get_ethtool_stats);

int b53_get_sset_count(struct dsa_switch *ds, int port)
void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data)
{
	struct phy_device *phydev;

	phydev = b53_get_phy_device(ds, port);
	if (!phydev)
		return;

	phy_ethtool_get_stats(phydev, NULL, data);
}
EXPORT_SYMBOL(b53_get_ethtool_phy_stats);

int b53_get_sset_count(struct dsa_switch *ds, int port, int sset)
{
	struct b53_device *dev = ds->priv;
	struct phy_device *phydev;

	if (sset == ETH_SS_STATS) {
		return b53_get_mib_size(dev);
	} else if (sset == ETH_SS_PHY_STATS) {
		phydev = b53_get_phy_device(ds, port);
		if (!phydev)
			return 0;

		return phy_ethtool_get_sset_count(phydev);
	}

	return 0;
}
EXPORT_SYMBOL(b53_get_sset_count);

@@ -1477,7 +1523,7 @@ void b53_br_fast_age(struct dsa_switch *ds, int port)
}
EXPORT_SYMBOL(b53_br_fast_age);

static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port)
static bool b53_possible_cpu_port(struct dsa_switch *ds, int port)
{
	/* Broadcom switches will accept enabling Broadcom tags on the
	 * following ports: 5, 7 and 8, any other port is not supported
@@ -1489,10 +1535,19 @@ static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port)
		return true;
	}

	dev_warn(ds->dev, "Port %d is not Broadcom tag capable\n", port);
	return false;
}

static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port)
{
	bool ret = b53_possible_cpu_port(ds, port);

	if (!ret)
		dev_warn(ds->dev, "Port %d is not Broadcom tag capable\n",
			 port);
	return ret;
}

enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port)
{
	struct b53_device *dev = ds->priv;
@@ -1650,6 +1705,7 @@ static const struct dsa_switch_ops b53_switch_ops = {
	.get_strings		= b53_get_strings,
	.get_ethtool_stats	= b53_get_ethtool_stats,
	.get_sset_count		= b53_get_sset_count,
	.get_ethtool_phy_stats	= b53_get_ethtool_phy_stats,
	.phy_read		= b53_phy_read16,
	.phy_write		= b53_phy_write16,
	.adjust_link		= b53_adjust_link,
@@ -1954,6 +2010,15 @@ static int b53_switch_init(struct b53_device *dev)
	dev->num_ports = dev->cpu_port + 1;
	dev->enabled_ports |= BIT(dev->cpu_port);

	/* Include non standard CPU port built-in PHYs to be probed */
	if (is539x(dev) || is531x5(dev)) {
		for (i = 0; i < dev->num_ports; i++) {
			if (!(dev->ds->phys_mii_mask & BIT(i)) &&
			    !b53_possible_cpu_port(dev->ds, i))
				dev->ds->phys_mii_mask |= BIT(i);
		}
	}

	dev->ports = devm_kzalloc(dev->dev,
				  sizeof(struct b53_port) * dev->num_ports,
				  GFP_KERNEL);
+4 −2
Original line number Diff line number Diff line
@@ -286,9 +286,11 @@ static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
/* Exported functions towards other drivers */
void b53_imp_vlan_setup(struct dsa_switch *ds, int cpu_port);
int b53_configure_vlan(struct dsa_switch *ds);
void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data);
void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
		     uint8_t *data);
void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
int b53_get_sset_count(struct dsa_switch *ds, int port);
int b53_get_sset_count(struct dsa_switch *ds, int port, int sset);
void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data);
int b53_br_join(struct dsa_switch *ds, int port, struct net_device *bridge);
void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *bridge);
void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state);
+1 −0
Original line number Diff line number Diff line
@@ -859,6 +859,7 @@ static const struct dsa_switch_ops bcm_sf2_ops = {
	.get_strings		= b53_get_strings,
	.get_ethtool_stats	= b53_get_ethtool_stats,
	.get_sset_count		= b53_get_sset_count,
	.get_ethtool_phy_stats	= b53_get_ethtool_phy_stats,
	.get_phy_flags		= bcm_sf2_sw_get_phy_flags,
	.adjust_link		= bcm_sf2_sw_adjust_link,
	.fixed_link_update	= bcm_sf2_sw_fixed_link_update,
+10 −2
Original line number Diff line number Diff line
@@ -86,16 +86,23 @@ static int dsa_loop_setup(struct dsa_switch *ds)
	return 0;
}

static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port)
static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port, int sset)
{
	if (sset != ETH_SS_STATS && sset != ETH_SS_PHY_STATS)
		return 0;

	return __DSA_LOOP_CNT_MAX;
}

static void dsa_loop_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
static void dsa_loop_get_strings(struct dsa_switch *ds, int port,
				 u32 stringset, uint8_t *data)
{
	struct dsa_loop_priv *ps = ds->priv;
	unsigned int i;

	if (stringset != ETH_SS_STATS && stringset != ETH_SS_PHY_STATS)
		return;

	for (i = 0; i < __DSA_LOOP_CNT_MAX; i++)
		memcpy(data + i * ETH_GSTRING_LEN,
		       ps->ports[port].mib[i].name, ETH_GSTRING_LEN);
@@ -256,6 +263,7 @@ static const struct dsa_switch_ops dsa_loop_driver = {
	.get_strings		= dsa_loop_get_strings,
	.get_ethtool_stats	= dsa_loop_get_ethtool_stats,
	.get_sset_count		= dsa_loop_get_sset_count,
	.get_ethtool_phy_stats	= dsa_loop_get_ethtool_stats,
	.phy_read		= dsa_loop_phy_read,
	.phy_write		= dsa_loop_phy_write,
	.port_bridge_join	= dsa_loop_port_bridge_join,
+9 −2
Original line number Diff line number Diff line
@@ -977,10 +977,14 @@ static const struct lan9303_mib_desc lan9303_mib[] = {
	{ .offset = LAN9303_MAC_TX_LATECOL_0, .name = "TxLateCol", },
};

static void lan9303_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
static void lan9303_get_strings(struct dsa_switch *ds, int port,
				u32 stringset, uint8_t *data)
{
	unsigned int u;

	if (stringset != ETH_SS_STATS)
		return;

	for (u = 0; u < ARRAY_SIZE(lan9303_mib); u++) {
		strncpy(data + u * ETH_GSTRING_LEN, lan9303_mib[u].name,
			ETH_GSTRING_LEN);
@@ -1007,8 +1011,11 @@ static void lan9303_get_ethtool_stats(struct dsa_switch *ds, int port,
	}
}

static int lan9303_get_sset_count(struct dsa_switch *ds, int port)
static int lan9303_get_sset_count(struct dsa_switch *ds, int port, int sset)
{
	if (sset != ETH_SS_STATS)
		return 0;

	return ARRAY_SIZE(lan9303_mib);
}

Loading