mirror of
https://github.com/raspberrypi/linux.git
synced 2026-01-04 18:27:36 +00:00
net: ethtool: tsinfo: Enhance tsinfo to support several hwtstamp by net topology
Either the MAC or the PHY can provide hwtstamp, so we should be able to read the tsinfo for any hwtstamp provider. Enhance 'get' command to retrieve tsinfo of hwtstamp providers within a network topology. Add support for a specific dump command to retrieve all hwtstamp providers within the network topology, with added functionality for filtered dump to target a single interface. Signed-off-by: Kory Maincent <kory.maincent@bootlin.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
35f7cad174
commit
b9e3f7dc9e
@@ -5,9 +5,12 @@
|
||||
#include <linux/phy.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/phy_link_topology.h>
|
||||
|
||||
#include "netlink.h"
|
||||
#include "common.h"
|
||||
#include "../core/dev.h"
|
||||
|
||||
|
||||
const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
|
||||
[NETIF_F_SG_BIT] = "tx-scatter-gather",
|
||||
@@ -763,20 +766,91 @@ int ethtool_check_ops(const struct ethtool_ops *ops)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info)
|
||||
static void ethtool_init_tsinfo(struct kernel_ethtool_ts_info *info)
|
||||
{
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
struct phy_device *phydev = dev->phydev;
|
||||
int err = 0;
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->cmd = ETHTOOL_GET_TS_INFO;
|
||||
info->phc_index = -1;
|
||||
}
|
||||
|
||||
if (phy_is_default_hwtstamp(phydev) && phy_has_tsinfo(phydev))
|
||||
err = phy_ts_info(phydev, info);
|
||||
else if (ops->get_ts_info)
|
||||
err = ops->get_ts_info(dev, info);
|
||||
int ethtool_net_get_ts_info_by_phc(struct net_device *dev,
|
||||
struct kernel_ethtool_ts_info *info,
|
||||
struct hwtstamp_provider_desc *hwprov_desc)
|
||||
{
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
int err;
|
||||
|
||||
if (!ops->get_ts_info)
|
||||
return -ENODEV;
|
||||
|
||||
/* Does ptp comes from netdev */
|
||||
ethtool_init_tsinfo(info);
|
||||
info->phc_qualifier = hwprov_desc->qualifier;
|
||||
err = ops->get_ts_info(dev, info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (info->phc_index == hwprov_desc->index &&
|
||||
net_support_hwtstamp_qualifier(dev, hwprov_desc->qualifier))
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int
|
||||
ethtool_phy_get_ts_info_by_phc(struct net_device *dev,
|
||||
struct kernel_ethtool_ts_info *info,
|
||||
struct hwtstamp_provider_desc *hwprov_desc)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Only precise qualifier is supported in phydev */
|
||||
if (hwprov_desc->qualifier != HWTSTAMP_PROVIDER_QUALIFIER_PRECISE)
|
||||
return -ENODEV;
|
||||
|
||||
/* Look in the phy topology */
|
||||
if (dev->link_topo) {
|
||||
struct phy_device_node *pdn;
|
||||
unsigned long phy_index;
|
||||
|
||||
xa_for_each(&dev->link_topo->phys, phy_index, pdn) {
|
||||
if (!phy_has_tsinfo(pdn->phy))
|
||||
continue;
|
||||
|
||||
ethtool_init_tsinfo(info);
|
||||
err = phy_ts_info(pdn->phy, info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (info->phc_index == hwprov_desc->index)
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Look on the dev->phydev */
|
||||
if (phy_has_tsinfo(dev->phydev)) {
|
||||
ethtool_init_tsinfo(info);
|
||||
err = phy_ts_info(dev->phydev, info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (info->phc_index == hwprov_desc->index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int ethtool_get_ts_info_by_phc(struct net_device *dev,
|
||||
struct kernel_ethtool_ts_info *info,
|
||||
struct hwtstamp_provider_desc *hwprov_desc)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ethtool_net_get_ts_info_by_phc(dev, info, hwprov_desc);
|
||||
if (err == -ENODEV)
|
||||
err = ethtool_phy_get_ts_info_by_phc(dev, info, hwprov_desc);
|
||||
|
||||
info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE;
|
||||
@@ -784,6 +858,55 @@ int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info
|
||||
return err;
|
||||
}
|
||||
|
||||
int __ethtool_get_ts_info(struct net_device *dev,
|
||||
struct kernel_ethtool_ts_info *info)
|
||||
{
|
||||
struct hwtstamp_provider *hwprov;
|
||||
|
||||
hwprov = rtnl_dereference(dev->hwprov);
|
||||
/* No provider specified, use default behavior */
|
||||
if (!hwprov) {
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
struct phy_device *phydev = dev->phydev;
|
||||
int err = 0;
|
||||
|
||||
ethtool_init_tsinfo(info);
|
||||
if (phy_is_default_hwtstamp(phydev) &&
|
||||
phy_has_tsinfo(phydev))
|
||||
err = phy_ts_info(phydev, info);
|
||||
else if (ops->get_ts_info)
|
||||
err = ops->get_ts_info(dev, info);
|
||||
|
||||
info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return ethtool_get_ts_info_by_phc(dev, info, &hwprov->desc);
|
||||
}
|
||||
|
||||
bool net_support_hwtstamp_qualifier(struct net_device *dev,
|
||||
enum hwtstamp_provider_qualifier qualifier)
|
||||
{
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
|
||||
if (!ops)
|
||||
return false;
|
||||
|
||||
/* Return true with precise qualifier and with NIC without
|
||||
* qualifier description to not break the old behavior.
|
||||
*/
|
||||
if (!ops->supported_hwtstamp_qualifiers &&
|
||||
qualifier == HWTSTAMP_PROVIDER_QUALIFIER_PRECISE)
|
||||
return true;
|
||||
|
||||
if (ops->supported_hwtstamp_qualifiers & BIT(qualifier))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index)
|
||||
{
|
||||
struct kernel_ethtool_ts_info info = { };
|
||||
|
||||
Reference in New Issue
Block a user