aboutsummaryrefslogtreecommitdiff
path: root/net/dsa/port.c
diff options
context:
space:
mode:
authorDavid S. Miller <[email protected]>2018-04-27 11:53:04 -0400
committerDavid S. Miller <[email protected]>2018-04-27 11:53:04 -0400
commit21fca6e01beb9cae33c7d45a69e032d91c81f07d (patch)
treeee5924b4a53b16f813c239101935af3f480b7781 /net/dsa/port.c
parent834944073301e85001c3ed9913027ca47c6f889b (diff)
parent96cbddcd52e76d9052948e408b17bedc8aa1c11a (diff)
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: David S. Miller <[email protected]>
Diffstat (limited to 'net/dsa/port.c')
-rw-r--r--net/dsa/port.c90
1 files changed, 79 insertions, 11 deletions
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 7acc1169d75e..2413beb995be 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -273,25 +273,38 @@ int dsa_port_vlan_del(struct dsa_port *dp,
return 0;
}
-static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
+static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp)
{
- struct device_node *port_dn = dp->dn;
struct device_node *phy_dn;
- struct dsa_switch *ds = dp->ds;
struct phy_device *phydev;
- int port = dp->index;
- int err = 0;
- phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
+ phy_dn = of_parse_phandle(dp->dn, "phy-handle", 0);
if (!phy_dn)
- return 0;
+ return NULL;
phydev = of_phy_find_device(phy_dn);
if (!phydev) {
- err = -EPROBE_DEFER;
- goto err_put_of;
+ of_node_put(phy_dn);
+ return ERR_PTR(-EPROBE_DEFER);
}
+ return phydev;
+}
+
+static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
+{
+ struct dsa_switch *ds = dp->ds;
+ struct phy_device *phydev;
+ int port = dp->index;
+ int err = 0;
+
+ phydev = dsa_port_get_phy_device(dp);
+ if (!phydev)
+ return 0;
+
+ if (IS_ERR(phydev))
+ return PTR_ERR(phydev);
+
if (enable) {
err = genphy_config_init(phydev);
if (err < 0)
@@ -317,8 +330,6 @@ static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable)
err_put_dev:
put_device(&phydev->mdio.dev);
-err_put_of:
- of_node_put(phy_dn);
return err;
}
@@ -372,3 +383,60 @@ void dsa_port_link_unregister_of(struct dsa_port *dp)
else
dsa_port_setup_phy_of(dp, false);
}
+
+int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data)
+{
+ struct phy_device *phydev;
+ int ret = -EOPNOTSUPP;
+
+ if (of_phy_is_fixed_link(dp->dn))
+ return ret;
+
+ phydev = dsa_port_get_phy_device(dp);
+ if (IS_ERR_OR_NULL(phydev))
+ return ret;
+
+ ret = phy_ethtool_get_strings(phydev, data);
+ put_device(&phydev->mdio.dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dsa_port_get_phy_strings);
+
+int dsa_port_get_ethtool_phy_stats(struct dsa_port *dp, uint64_t *data)
+{
+ struct phy_device *phydev;
+ int ret = -EOPNOTSUPP;
+
+ if (of_phy_is_fixed_link(dp->dn))
+ return ret;
+
+ phydev = dsa_port_get_phy_device(dp);
+ if (IS_ERR_OR_NULL(phydev))
+ return ret;
+
+ ret = phy_ethtool_get_stats(phydev, NULL, data);
+ put_device(&phydev->mdio.dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dsa_port_get_ethtool_phy_stats);
+
+int dsa_port_get_phy_sset_count(struct dsa_port *dp)
+{
+ struct phy_device *phydev;
+ int ret = -EOPNOTSUPP;
+
+ if (of_phy_is_fixed_link(dp->dn))
+ return ret;
+
+ phydev = dsa_port_get_phy_device(dp);
+ if (IS_ERR_OR_NULL(phydev))
+ return ret;
+
+ ret = phy_ethtool_get_sset_count(phydev);
+ put_device(&phydev->mdio.dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dsa_port_get_phy_sset_count);