summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorKory Maincent <kory.maincent@bootlin.com>2023-11-14 14:28:41 +0300
committerDavid S. Miller <davem@davemloft.net>2023-11-18 17:52:57 +0300
commit0f7f463d4821a4f52fa5c0a961389e651d50c384 (patch)
tree76d682494226939dac8adba05bf57ae34b827357 /net
parent51bdf3165f012827644c474a6d905baa3de3f1ea (diff)
downloadlinux-0f7f463d4821a4f52fa5c0a961389e651d50c384.tar.xz
net: Change the API of PHY default timestamp to MAC
Change the API to select MAC default time stamping instead of the PHY. Indeed the PHY is closer to the wire therefore theoretically it has less delay than the MAC timestamping but the reality is different. Due to lower time stamping clock frequency, latency in the MDIO bus and no PHC hardware synchronization between different PHY, the PHY PTP is often less precise than the MAC. The exception is for PHY designed specially for PTP case but these devices are not very widespread. For not breaking the compatibility I introduce a default_timestamp flag in phy_device that is set by the phy driver to know we are using the old API behavior. The phy_set_timestamp function is called at each call of phy_attach_direct. In case of MAC driver using phylink this function is called when the interface is turned up. Then if the interface goes down and up again the last choice of timestamp will be overwritten by the default choice. A solution could be to cache the timestamp status but it can bring other issues. In case of SFP, if we change the module, it doesn't make sense to blindly re-set the timestamp back to PHY, if the new module has a PHY with mediocre timestamping capabilities. Signed-off-by: Kory Maincent <kory.maincent@bootlin.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/dev.c3
-rw-r--r--net/core/dev_ioctl.c36
-rw-r--r--net/core/timestamping.c10
-rw-r--r--net/ethtool/common.c19
4 files changed, 52 insertions, 16 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index af53f6d838ce..05ce00632892 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -10212,6 +10212,9 @@ int register_netdevice(struct net_device *dev)
dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL, 0, NULL);
+ if (dev->ethtool_ops->get_ts_info)
+ dev->ts_layer = MAC_TIMESTAMPING;
+
out:
return ret;
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
index 267cd00269d0..bc8be9749376 100644
--- a/net/core/dev_ioctl.c
+++ b/net/core/dev_ioctl.c
@@ -259,9 +259,7 @@ static int dev_eth_ioctl(struct net_device *dev,
* @dev: Network device
* @cfg: Timestamping configuration structure
*
- * Helper for enforcing a common policy that phylib timestamping, if available,
- * should take precedence in front of hardware timestamping provided by the
- * netdev.
+ * Helper for calling the selected hardware provider timestamping.
*
* Note: phy_mii_ioctl() only handles SIOCSHWTSTAMP (not SIOCGHWTSTAMP), and
* there only exists a phydev->mii_ts->hwtstamp() method. So this will return
@@ -271,10 +269,14 @@ static int dev_eth_ioctl(struct net_device *dev,
static int dev_get_hwtstamp_phylib(struct net_device *dev,
struct kernel_hwtstamp_config *cfg)
{
- if (phy_has_hwtstamp(dev->phydev))
+ enum timestamping_layer ts_layer = dev->ts_layer;
+
+ if (ts_layer == PHY_TIMESTAMPING)
return phy_hwtstamp_get(dev->phydev, cfg);
+ else if (ts_layer == MAC_TIMESTAMPING)
+ return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
- return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
+ return -EOPNOTSUPP;
}
static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
@@ -315,9 +317,8 @@ static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
* @cfg: Timestamping configuration structure
* @extack: Netlink extended ack message structure, for error reporting
*
- * Helper for enforcing a common policy that phylib timestamping, if available,
- * should take precedence in front of hardware timestamping provided by the
- * netdev. If the netdev driver needs to perform specific actions even for PHY
+ * Helper for calling the selected hardware provider timestamping.
+ * If the netdev driver needs to perform specific actions even for PHY
* timestamping to work properly (a switch port must trap the timestamped
* frames and not forward them), it must set IFF_SEE_ALL_HWTSTAMP_REQUESTS in
* dev->priv_flags.
@@ -327,20 +328,26 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
struct netlink_ext_ack *extack)
{
const struct net_device_ops *ops = dev->netdev_ops;
- bool phy_ts = phy_has_hwtstamp(dev->phydev);
+ enum timestamping_layer ts_layer = dev->ts_layer;
struct kernel_hwtstamp_config old_cfg = {};
bool changed = false;
int err;
- cfg->source = phy_ts ? PHY_TIMESTAMPING : MAC_TIMESTAMPING;
+ cfg->source = ts_layer;
+
+ if (ts_layer != PHY_TIMESTAMPING &&
+ ts_layer != MAC_TIMESTAMPING)
+ return -EOPNOTSUPP;
- if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) {
+ if (ts_layer == PHY_TIMESTAMPING &&
+ dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS) {
err = ops->ndo_hwtstamp_get(dev, &old_cfg);
if (err)
return err;
}
- if (!phy_ts || (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) {
+ if (ts_layer == MAC_TIMESTAMPING ||
+ dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS) {
err = ops->ndo_hwtstamp_set(dev, cfg, extack);
if (err) {
if (extack->_msg)
@@ -349,10 +356,11 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
}
}
- if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS))
+ if (ts_layer == PHY_TIMESTAMPING &&
+ dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)
changed = kernel_hwtstamp_config_changed(&old_cfg, cfg);
- if (phy_ts) {
+ if (ts_layer == PHY_TIMESTAMPING) {
err = phy_hwtstamp_set(dev->phydev, cfg, extack);
if (err) {
if (changed)
diff --git a/net/core/timestamping.c b/net/core/timestamping.c
index 04840697fe79..5cf51a523fb3 100644
--- a/net/core/timestamping.c
+++ b/net/core/timestamping.c
@@ -21,6 +21,7 @@ static unsigned int classify(const struct sk_buff *skb)
void skb_clone_tx_timestamp(struct sk_buff *skb)
{
+ enum timestamping_layer ts_layer;
struct mii_timestamper *mii_ts;
struct sk_buff *clone;
unsigned int type;
@@ -28,6 +29,10 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
if (!skb->sk)
return;
+ ts_layer = skb->dev->ts_layer;
+ if (ts_layer != PHY_TIMESTAMPING)
+ return;
+
type = classify(skb);
if (type == PTP_CLASS_NONE)
return;
@@ -44,12 +49,17 @@ EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp);
bool skb_defer_rx_timestamp(struct sk_buff *skb)
{
+ enum timestamping_layer ts_layer;
struct mii_timestamper *mii_ts;
unsigned int type;
if (!skb->dev || !skb->dev->phydev || !skb->dev->phydev->mii_ts)
return false;
+ ts_layer = skb->dev->ts_layer;
+ if (ts_layer != PHY_TIMESTAMPING)
+ return false;
+
if (skb_headroom(skb) < ETH_HLEN)
return false;
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 11d8797f63f6..9f6e3b2c74e2 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -633,13 +633,28 @@ int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
{
const struct ethtool_ops *ops = dev->ethtool_ops;
struct phy_device *phydev = dev->phydev;
+ enum timestamping_layer ts_layer;
+ int ret;
memset(info, 0, sizeof(*info));
info->cmd = ETHTOOL_GET_TS_INFO;
- if (phy_has_tsinfo(phydev))
+ ts_layer = dev->ts_layer;
+ if (ts_layer == SOFTWARE_TIMESTAMPING) {
+ ret = ops->get_ts_info(dev, info);
+ if (ret)
+ return ret;
+ info->so_timestamping &= ~SOF_TIMESTAMPING_HARDWARE_MASK;
+ info->phc_index = -1;
+ info->rx_filters = 0;
+ info->tx_types = 0;
+ return 0;
+ }
+
+ if (ts_layer == PHY_TIMESTAMPING)
return phy_ts_info(phydev, info);
- if (ops->get_ts_info)
+
+ if (ts_layer == MAC_TIMESTAMPING)
return ops->get_ts_info(dev, info);
info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |