Skip to content

Commit 35f7cad

Browse files
kmaincentdavem330
authored andcommitted
net: Add the possibility to support a selected hwtstamp in netdevice
Introduce the description of a hwtstamp provider, mainly defined with a the hwtstamp source and the phydev pointer. Add a hwtstamp provider description within the netdev structure to allow saving the hwtstamp we want to use. This prepares for future support of an ethtool netlink command to select the desired hwtstamp provider. By default, the old API that does not support hwtstamp selectability is used, meaning the hwtstamp provider pointer is unset. Signed-off-by: Kory Maincent <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b18fe47 commit 35f7cad

File tree

6 files changed

+140
-7
lines changed

6 files changed

+140
-7
lines changed

drivers/net/phy/phy_device.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <linux/phy_link_topology.h>
3333
#include <linux/pse-pd/pse.h>
3434
#include <linux/property.h>
35+
#include <linux/ptp_clock_kernel.h>
3536
#include <linux/rtnetlink.h>
3637
#include <linux/sfp.h>
3738
#include <linux/skbuff.h>
@@ -1998,6 +1999,15 @@ void phy_detach(struct phy_device *phydev)
19981999

19992000
phy_suspend(phydev);
20002001
if (dev) {
2002+
struct hwtstamp_provider *hwprov;
2003+
2004+
hwprov = rtnl_dereference(dev->hwprov);
2005+
/* Disable timestamp if it is the one selected */
2006+
if (hwprov && hwprov->phydev == phydev) {
2007+
rcu_assign_pointer(dev->hwprov, NULL);
2008+
kfree_rcu(hwprov, rcu_head);
2009+
}
2010+
20012011
phydev->attached_dev->phydev = NULL;
20022012
phydev->attached_dev = NULL;
20032013
phy_link_topo_del_phy(dev, phydev);

include/linux/net_tstamp.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,33 @@ enum hwtstamp_source {
1919
HWTSTAMP_SOURCE_PHYLIB,
2020
};
2121

22+
/**
23+
* struct hwtstamp_provider_desc - hwtstamp provider description
24+
*
25+
* @index: index of the hwtstamp provider.
26+
* @qualifier: hwtstamp provider qualifier.
27+
*/
28+
struct hwtstamp_provider_desc {
29+
int index;
30+
enum hwtstamp_provider_qualifier qualifier;
31+
};
32+
33+
/**
34+
* struct hwtstamp_provider - hwtstamp provider object
35+
*
36+
* @rcu_head: RCU callback used to free the struct.
37+
* @source: source of the hwtstamp provider.
38+
* @phydev: pointer of the phydev source in case a PTP coming from phylib
39+
* @desc: hwtstamp provider description.
40+
*/
41+
42+
struct hwtstamp_provider {
43+
struct rcu_head rcu_head;
44+
enum hwtstamp_source source;
45+
struct phy_device *phydev;
46+
struct hwtstamp_provider_desc desc;
47+
};
48+
2249
/**
2350
* struct kernel_hwtstamp_config - Kernel copy of struct hwtstamp_config
2451
*
@@ -31,6 +58,7 @@ enum hwtstamp_source {
3158
* copied the ioctl request back to user space
3259
* @source: indication whether timestamps should come from the netdev or from
3360
* an attached phylib PHY
61+
* @qualifier: qualifier of the hwtstamp provider
3462
*
3563
* Prefer using this structure for in-kernel processing of hardware
3664
* timestamping configuration, over the inextensible struct hwtstamp_config
@@ -43,6 +71,7 @@ struct kernel_hwtstamp_config {
4371
struct ifreq *ifr;
4472
bool copied_to_user;
4573
enum hwtstamp_source source;
74+
enum hwtstamp_provider_qualifier qualifier;
4675
};
4776

4877
static inline void hwtstamp_config_to_kernel(struct kernel_hwtstamp_config *kernel_cfg,

include/linux/netdevice.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ struct xdp_metadata_ops;
8282
struct xdp_md;
8383
struct ethtool_netdev_state;
8484
struct phy_link_topology;
85+
struct hwtstamp_provider;
8586

8687
typedef u32 xdp_features_t;
8788

@@ -2045,6 +2046,7 @@ enum netdev_reg_state {
20452046
*
20462047
* @neighbours: List heads pointing to this device's neighbours'
20472048
* dev_list, one per address-family.
2049+
* @hwprov: Tracks which PTP performs hardware packet time stamping.
20482050
*
20492051
* FIXME: cleanup struct net_device such that network protocol info
20502052
* moves out.
@@ -2457,6 +2459,8 @@ struct net_device {
24572459

24582460
struct hlist_head neighbours[NEIGH_NR_TABLES];
24592461

2462+
struct hwtstamp_provider __rcu *hwprov;
2463+
24602464
u8 priv[] ____cacheline_aligned
24612465
__counted_by(priv_len);
24622466
} ____cacheline_aligned;

include/uapi/linux/net_tstamp.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@
1313
#include <linux/types.h>
1414
#include <linux/socket.h> /* for SO_TIMESTAMPING */
1515

16+
/*
17+
* Possible type of hwtstamp provider. Mainly "precise" the default one
18+
* is for IEEE 1588 quality and "approx" is for NICs DMA point.
19+
*/
20+
enum hwtstamp_provider_qualifier {
21+
HWTSTAMP_PROVIDER_QUALIFIER_PRECISE,
22+
HWTSTAMP_PROVIDER_QUALIFIER_APPROX,
23+
24+
HWTSTAMP_PROVIDER_QUALIFIER_CNT,
25+
};
26+
1627
/* SO_TIMESTAMPING flags */
1728
enum {
1829
SOF_TIMESTAMPING_TX_HARDWARE = (1<<0),

net/core/dev_ioctl.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <linux/rtnetlink.h>
77
#include <linux/net_tstamp.h>
88
#include <linux/phylib_stubs.h>
9+
#include <linux/ptp_clock_kernel.h>
910
#include <linux/wireless.h>
1011
#include <linux/if_bridge.h>
1112
#include <net/dsa_stubs.h>
@@ -269,6 +270,21 @@ static int dev_eth_ioctl(struct net_device *dev,
269270
int dev_get_hwtstamp_phylib(struct net_device *dev,
270271
struct kernel_hwtstamp_config *cfg)
271272
{
273+
struct hwtstamp_provider *hwprov;
274+
275+
hwprov = rtnl_dereference(dev->hwprov);
276+
if (hwprov) {
277+
cfg->qualifier = hwprov->desc.qualifier;
278+
if (hwprov->source == HWTSTAMP_SOURCE_PHYLIB &&
279+
hwprov->phydev)
280+
return phy_hwtstamp_get(hwprov->phydev, cfg);
281+
282+
if (hwprov->source == HWTSTAMP_SOURCE_NETDEV)
283+
return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
284+
285+
return -EOPNOTSUPP;
286+
}
287+
272288
if (phy_is_default_hwtstamp(dev->phydev))
273289
return phy_hwtstamp_get(dev->phydev, cfg);
274290

@@ -324,11 +340,32 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
324340
struct netlink_ext_ack *extack)
325341
{
326342
const struct net_device_ops *ops = dev->netdev_ops;
327-
bool phy_ts = phy_is_default_hwtstamp(dev->phydev);
328343
struct kernel_hwtstamp_config old_cfg = {};
344+
struct hwtstamp_provider *hwprov;
345+
struct phy_device *phydev;
329346
bool changed = false;
347+
bool phy_ts;
330348
int err;
331349

350+
hwprov = rtnl_dereference(dev->hwprov);
351+
if (hwprov) {
352+
if (hwprov->source == HWTSTAMP_SOURCE_PHYLIB &&
353+
hwprov->phydev) {
354+
phy_ts = true;
355+
phydev = hwprov->phydev;
356+
} else if (hwprov->source == HWTSTAMP_SOURCE_NETDEV) {
357+
phy_ts = false;
358+
} else {
359+
return -EOPNOTSUPP;
360+
}
361+
362+
cfg->qualifier = hwprov->desc.qualifier;
363+
} else {
364+
phy_ts = phy_is_default_hwtstamp(dev->phydev);
365+
if (phy_ts)
366+
phydev = dev->phydev;
367+
}
368+
332369
cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV;
333370

334371
if (phy_ts && dev->see_all_hwtstamp_requests) {
@@ -350,7 +387,7 @@ int dev_set_hwtstamp_phylib(struct net_device *dev,
350387
changed = kernel_hwtstamp_config_changed(&old_cfg, cfg);
351388

352389
if (phy_ts) {
353-
err = phy_hwtstamp_set(dev->phydev, cfg, extack);
390+
err = phy_hwtstamp_set(phydev, cfg, extack);
354391
if (err) {
355392
if (changed)
356393
ops->ndo_hwtstamp_set(dev, &old_cfg, NULL);

net/core/timestamping.c

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/ptp_classify.h>
1010
#include <linux/skbuff.h>
1111
#include <linux/export.h>
12+
#include <linux/ptp_clock_kernel.h>
1213

1314
static unsigned int classify(const struct sk_buff *skb)
1415
{
@@ -21,19 +22,39 @@ static unsigned int classify(const struct sk_buff *skb)
2122

2223
void skb_clone_tx_timestamp(struct sk_buff *skb)
2324
{
25+
struct hwtstamp_provider *hwprov;
2426
struct mii_timestamper *mii_ts;
27+
struct phy_device *phydev;
2528
struct sk_buff *clone;
2629
unsigned int type;
2730

28-
if (!skb->sk || !skb->dev ||
29-
!phy_is_default_hwtstamp(skb->dev->phydev))
31+
if (!skb->sk || !skb->dev)
3032
return;
3133

34+
rcu_read_lock();
35+
hwprov = rcu_dereference(skb->dev->hwprov);
36+
if (hwprov) {
37+
if (hwprov->source != HWTSTAMP_SOURCE_PHYLIB ||
38+
!hwprov->phydev) {
39+
rcu_read_unlock();
40+
return;
41+
}
42+
43+
phydev = hwprov->phydev;
44+
} else {
45+
phydev = skb->dev->phydev;
46+
if (!phy_is_default_hwtstamp(phydev)) {
47+
rcu_read_unlock();
48+
return;
49+
}
50+
}
51+
rcu_read_unlock();
52+
3253
type = classify(skb);
3354
if (type == PTP_CLASS_NONE)
3455
return;
3556

36-
mii_ts = skb->dev->phydev->mii_ts;
57+
mii_ts = phydev->mii_ts;
3758
if (likely(mii_ts->txtstamp)) {
3859
clone = skb_clone_sk(skb);
3960
if (!clone)
@@ -45,12 +66,33 @@ EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp);
4566

4667
bool skb_defer_rx_timestamp(struct sk_buff *skb)
4768
{
69+
struct hwtstamp_provider *hwprov;
4870
struct mii_timestamper *mii_ts;
71+
struct phy_device *phydev;
4972
unsigned int type;
5073

51-
if (!skb->dev || !phy_is_default_hwtstamp(skb->dev->phydev))
74+
if (!skb->dev)
5275
return false;
5376

77+
rcu_read_lock();
78+
hwprov = rcu_dereference(skb->dev->hwprov);
79+
if (hwprov) {
80+
if (hwprov->source != HWTSTAMP_SOURCE_PHYLIB ||
81+
!hwprov->phydev) {
82+
rcu_read_unlock();
83+
return false;
84+
}
85+
86+
phydev = hwprov->phydev;
87+
} else {
88+
phydev = skb->dev->phydev;
89+
if (!phy_is_default_hwtstamp(phydev)) {
90+
rcu_read_unlock();
91+
return false;
92+
}
93+
}
94+
rcu_read_unlock();
95+
5496
if (skb_headroom(skb) < ETH_HLEN)
5597
return false;
5698

@@ -63,7 +105,7 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb)
63105
if (type == PTP_CLASS_NONE)
64106
return false;
65107

66-
mii_ts = skb->dev->phydev->mii_ts;
108+
mii_ts = phydev->mii_ts;
67109
if (likely(mii_ts->rxtstamp))
68110
return mii_ts->rxtstamp(mii_ts, skb, type);
69111

0 commit comments

Comments
 (0)