Skip to content

Commit 0f7f463

Browse files
kmaincentdavem330
authored andcommitted
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>
1 parent 51bdf31 commit 0f7f463

File tree

12 files changed

+115
-16
lines changed

12 files changed

+115
-16
lines changed

drivers/net/phy/bcm-phy-ptp.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,9 @@ struct bcm_ptp_private *bcm_ptp_probe(struct phy_device *phydev)
931931
return ERR_CAST(clock);
932932
priv->ptp_clock = clock;
933933

934+
/* Timestamp selected by default to keep legacy API */
935+
phydev->default_timestamp = true;
936+
934937
priv->phydev = phydev;
935938
bcm_ptp_init(priv);
936939

drivers/net/phy/dp83640.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,9 @@ static int dp83640_probe(struct phy_device *phydev)
14501450
phydev->mii_ts = &dp83640->mii_ts;
14511451
phydev->priv = dp83640;
14521452

1453+
/* Timestamp selected by default to keep legacy API */
1454+
phydev->default_timestamp = true;
1455+
14531456
spin_lock_init(&dp83640->rx_lock);
14541457
skb_queue_head_init(&dp83640->rx_queue);
14551458
skb_queue_head_init(&dp83640->tx_queue);

drivers/net/phy/micrel.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3158,6 +3158,9 @@ static void lan8814_ptp_init(struct phy_device *phydev)
31583158
ptp_priv->mii_ts.ts_info = lan8814_ts_info;
31593159

31603160
phydev->mii_ts = &ptp_priv->mii_ts;
3161+
3162+
/* Timestamp selected by default to keep legacy API */
3163+
phydev->default_timestamp = true;
31613164
}
31623165

31633166
static int lan8814_ptp_probe_once(struct phy_device *phydev)
@@ -4586,6 +4589,9 @@ static int lan8841_probe(struct phy_device *phydev)
45864589

45874590
phydev->mii_ts = &ptp_priv->mii_ts;
45884591

4592+
/* Timestamp selected by default to keep legacy API */
4593+
phydev->default_timestamp = true;
4594+
45894595
return 0;
45904596
}
45914597

drivers/net/phy/mscc/mscc_ptp.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,8 @@ int vsc8584_ptp_probe(struct phy_device *phydev)
15701570
return PTR_ERR(vsc8531->load_save);
15711571
}
15721572

1573+
/* Timestamp selected by default to keep legacy API */
1574+
phydev->default_timestamp = true;
15731575
vsc8531->ptp->phydev = phydev;
15741576

15751577
return 0;

drivers/net/phy/nxp-c45-tja11xx.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,9 @@ static int nxp_c45_probe(struct phy_device *phydev)
16581658
priv->mii_ts.ts_info = nxp_c45_ts_info;
16591659
phydev->mii_ts = &priv->mii_ts;
16601660
ret = nxp_c45_init_ptp_clock(priv);
1661+
1662+
/* Timestamp selected by default to keep legacy API */
1663+
phydev->default_timestamp = true;
16611664
} else {
16621665
phydev_dbg(phydev, "PTP support not enabled even if the phy supports it");
16631666
}

drivers/net/phy/phy_device.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,6 +1411,26 @@ int phy_sfp_probe(struct phy_device *phydev,
14111411
}
14121412
EXPORT_SYMBOL(phy_sfp_probe);
14131413

1414+
/**
1415+
* phy_set_timestamp - set the default selected timestamping device
1416+
* @dev: Pointer to net_device
1417+
* @phydev: Pointer to phy_device
1418+
*
1419+
* This is used to set default timestamping device taking into account
1420+
* the new API choice, which is selecting the timestamping from MAC by
1421+
* default if the phydev does not have default_timestamp flag enabled.
1422+
*/
1423+
static void phy_set_timestamp(struct net_device *dev, struct phy_device *phydev)
1424+
{
1425+
const struct ethtool_ops *ops = dev->ethtool_ops;
1426+
1427+
if (!phy_has_tsinfo(phydev))
1428+
return;
1429+
1430+
if (!ops->get_ts_info || phydev->default_timestamp)
1431+
dev->ts_layer = PHY_TIMESTAMPING;
1432+
}
1433+
14141434
/**
14151435
* phy_attach_direct - attach a network device to a given PHY device pointer
14161436
* @dev: network device to attach
@@ -1484,6 +1504,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
14841504

14851505
phydev->phy_link_change = phy_link_change;
14861506
if (dev) {
1507+
phy_set_timestamp(dev, phydev);
14871508
phydev->attached_dev = dev;
14881509
dev->phydev = phydev;
14891510

@@ -1812,6 +1833,22 @@ void phy_detach(struct phy_device *phydev)
18121833

18131834
phy_suspend(phydev);
18141835
if (dev) {
1836+
const struct ethtool_ops *ops = dev->ethtool_ops;
1837+
struct ethtool_ts_info ts_info = {0};
1838+
1839+
if (ops->get_ts_info) {
1840+
ops->get_ts_info(dev, &ts_info);
1841+
if ((ts_info.so_timestamping &
1842+
SOF_TIMESTAMPING_HARDWARE_MASK) ==
1843+
SOF_TIMESTAMPING_HARDWARE_MASK)
1844+
dev->ts_layer = MAC_TIMESTAMPING;
1845+
else if ((ts_info.so_timestamping &
1846+
SOF_TIMESTAMPING_SOFTWARE_MASK) ==
1847+
SOF_TIMESTAMPING_SOFTWARE_MASK)
1848+
dev->ts_layer = SOFTWARE_TIMESTAMPING;
1849+
} else {
1850+
dev->ts_layer = NO_TIMESTAMPING;
1851+
}
18151852
phydev->attached_dev->phydev = NULL;
18161853
phydev->attached_dev = NULL;
18171854
}

include/linux/netdevice.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include <uapi/linux/if_bonding.h>
4848
#include <uapi/linux/pkt_cls.h>
4949
#include <uapi/linux/netdev.h>
50+
#include <uapi/linux/net_tstamp.h>
5051
#include <linux/hashtable.h>
5152
#include <linux/rbtree.h>
5253
#include <net/net_trackers.h>
@@ -2074,6 +2075,8 @@ enum netdev_ml_priv_type {
20742075
*
20752076
* @dpll_pin: Pointer to the SyncE source pin of a DPLL subsystem,
20762077
* where the clock is recovered.
2078+
* @ts_layer: Tracks which network device
2079+
* performs packet time stamping.
20772080
*
20782081
* FIXME: cleanup struct net_device such that network protocol info
20792082
* moves out.
@@ -2435,6 +2438,8 @@ struct net_device {
24352438
#if IS_ENABLED(CONFIG_DPLL)
24362439
struct dpll_pin *dpll_pin;
24372440
#endif
2441+
2442+
enum timestamping_layer ts_layer;
24382443
};
24392444
#define to_net_dev(d) container_of(d, struct net_device, dev)
24402445

include/linux/phy.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,8 @@ struct macsec_ops;
604604
* handling shall be postponed until PHY has resumed
605605
* @irq_rerun: Flag indicating interrupts occurred while PHY was suspended,
606606
* requiring a rerun of the interrupt handler after resume
607+
* @default_timestamp: Flag indicating whether we are using the phy
608+
* timestamp as the default one
607609
* @interface: enum phy_interface_t value
608610
* @skb: Netlink message for cable diagnostics
609611
* @nest: Netlink nest used for cable diagnostics
@@ -667,6 +669,8 @@ struct phy_device {
667669
unsigned irq_suspended:1;
668670
unsigned irq_rerun:1;
669671

672+
unsigned default_timestamp:1;
673+
670674
int rate_matching;
671675

672676
enum phy_state state;

net/core/dev.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10212,6 +10212,9 @@ int register_netdevice(struct net_device *dev)
1021210212
dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
1021310213
rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL, 0, NULL);
1021410214

10215+
if (dev->ethtool_ops->get_ts_info)
10216+
dev->ts_layer = MAC_TIMESTAMPING;
10217+
1021510218
out:
1021610219
return ret;
1021710220

net/core/dev_ioctl.c

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,7 @@ static int dev_eth_ioctl(struct net_device *dev,
259259
* @dev: Network device
260260
* @cfg: Timestamping configuration structure
261261
*
262-
* Helper for enforcing a common policy that phylib timestamping, if available,
263-
* should take precedence in front of hardware timestamping provided by the
264-
* netdev.
262+
* Helper for calling the selected hardware provider timestamping.
265263
*
266264
* Note: phy_mii_ioctl() only handles SIOCSHWTSTAMP (not SIOCGHWTSTAMP), and
267265
* 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,
271269
static int dev_get_hwtstamp_phylib(struct net_device *dev,
272270
struct kernel_hwtstamp_config *cfg)
273271
{
274-
if (phy_has_hwtstamp(dev->phydev))
272+
enum timestamping_layer ts_layer = dev->ts_layer;
273+
274+
if (ts_layer == PHY_TIMESTAMPING)
275275
return phy_hwtstamp_get(dev->phydev, cfg);
276+
else if (ts_layer == MAC_TIMESTAMPING)
277+
return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
276278

277-
return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
279+
return -EOPNOTSUPP;
278280
}
279281

280282
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)
315317
* @cfg: Timestamping configuration structure
316318
* @extack: Netlink extended ack message structure, for error reporting
317319
*
318-
* Helper for enforcing a common policy that phylib timestamping, if available,
319-
* should take precedence in front of hardware timestamping provided by the
320-
* netdev. If the netdev driver needs to perform specific actions even for PHY
320+
* Helper for calling the selected hardware provider timestamping.
321+
* If the netdev driver needs to perform specific actions even for PHY
321322
* timestamping to work properly (a switch port must trap the timestamped
322323
* frames and not forward them), it must set IFF_SEE_ALL_HWTSTAMP_REQUESTS in
323324
* dev->priv_flags.
@@ -327,20 +328,26 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
327328
struct netlink_ext_ack *extack)
328329
{
329330
const struct net_device_ops *ops = dev->netdev_ops;
330-
bool phy_ts = phy_has_hwtstamp(dev->phydev);
331+
enum timestamping_layer ts_layer = dev->ts_layer;
331332
struct kernel_hwtstamp_config old_cfg = {};
332333
bool changed = false;
333334
int err;
334335

335-
cfg->source = phy_ts ? PHY_TIMESTAMPING : MAC_TIMESTAMPING;
336+
cfg->source = ts_layer;
337+
338+
if (ts_layer != PHY_TIMESTAMPING &&
339+
ts_layer != MAC_TIMESTAMPING)
340+
return -EOPNOTSUPP;
336341

337-
if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) {
342+
if (ts_layer == PHY_TIMESTAMPING &&
343+
dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS) {
338344
err = ops->ndo_hwtstamp_get(dev, &old_cfg);
339345
if (err)
340346
return err;
341347
}
342348

343-
if (!phy_ts || (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) {
349+
if (ts_layer == MAC_TIMESTAMPING ||
350+
dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS) {
344351
err = ops->ndo_hwtstamp_set(dev, cfg, extack);
345352
if (err) {
346353
if (extack->_msg)
@@ -349,10 +356,11 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
349356
}
350357
}
351358

352-
if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS))
359+
if (ts_layer == PHY_TIMESTAMPING &&
360+
dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)
353361
changed = kernel_hwtstamp_config_changed(&old_cfg, cfg);
354362

355-
if (phy_ts) {
363+
if (ts_layer == PHY_TIMESTAMPING) {
356364
err = phy_hwtstamp_set(dev->phydev, cfg, extack);
357365
if (err) {
358366
if (changed)

0 commit comments

Comments
 (0)