Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <kory.maincent@bootlin.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Kory Maincent and committed by
David S. Miller
35f7cad1 b18fe47c

+140 -7
+10
drivers/net/phy/phy_device.c
··· 32 32 #include <linux/phy_link_topology.h> 33 33 #include <linux/pse-pd/pse.h> 34 34 #include <linux/property.h> 35 + #include <linux/ptp_clock_kernel.h> 35 36 #include <linux/rtnetlink.h> 36 37 #include <linux/sfp.h> 37 38 #include <linux/skbuff.h> ··· 1999 1998 2000 1999 phy_suspend(phydev); 2001 2000 if (dev) { 2001 + struct hwtstamp_provider *hwprov; 2002 + 2003 + hwprov = rtnl_dereference(dev->hwprov); 2004 + /* Disable timestamp if it is the one selected */ 2005 + if (hwprov && hwprov->phydev == phydev) { 2006 + rcu_assign_pointer(dev->hwprov, NULL); 2007 + kfree_rcu(hwprov, rcu_head); 2008 + } 2009 + 2002 2010 phydev->attached_dev->phydev = NULL; 2003 2011 phydev->attached_dev = NULL; 2004 2012 phy_link_topo_del_phy(dev, phydev);
+29
include/linux/net_tstamp.h
··· 20 20 }; 21 21 22 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 + 49 + /** 23 50 * struct kernel_hwtstamp_config - Kernel copy of struct hwtstamp_config 24 51 * 25 52 * @flags: see struct hwtstamp_config ··· 58 31 * copied the ioctl request back to user space 59 32 * @source: indication whether timestamps should come from the netdev or from 60 33 * an attached phylib PHY 34 + * @qualifier: qualifier of the hwtstamp provider 61 35 * 62 36 * Prefer using this structure for in-kernel processing of hardware 63 37 * timestamping configuration, over the inextensible struct hwtstamp_config ··· 71 43 struct ifreq *ifr; 72 44 bool copied_to_user; 73 45 enum hwtstamp_source source; 46 + enum hwtstamp_provider_qualifier qualifier; 74 47 }; 75 48 76 49 static inline void hwtstamp_config_to_kernel(struct kernel_hwtstamp_config *kernel_cfg,
+4
include/linux/netdevice.h
··· 82 82 struct xdp_md; 83 83 struct ethtool_netdev_state; 84 84 struct phy_link_topology; 85 + struct hwtstamp_provider; 85 86 86 87 typedef u32 xdp_features_t; 87 88 ··· 2046 2045 * 2047 2046 * @neighbours: List heads pointing to this device's neighbours' 2048 2047 * dev_list, one per address-family. 2048 + * @hwprov: Tracks which PTP performs hardware packet time stamping. 2049 2049 * 2050 2050 * FIXME: cleanup struct net_device such that network protocol info 2051 2051 * moves out. ··· 2458 2456 #endif 2459 2457 2460 2458 struct hlist_head neighbours[NEIGH_NR_TABLES]; 2459 + 2460 + struct hwtstamp_provider __rcu *hwprov; 2461 2461 2462 2462 u8 priv[] ____cacheline_aligned 2463 2463 __counted_by(priv_len);
+11
include/uapi/linux/net_tstamp.h
··· 13 13 #include <linux/types.h> 14 14 #include <linux/socket.h> /* for SO_TIMESTAMPING */ 15 15 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 + 16 27 /* SO_TIMESTAMPING flags */ 17 28 enum { 18 29 SOF_TIMESTAMPING_TX_HARDWARE = (1<<0),
+39 -2
net/core/dev_ioctl.c
··· 6 6 #include <linux/rtnetlink.h> 7 7 #include <linux/net_tstamp.h> 8 8 #include <linux/phylib_stubs.h> 9 + #include <linux/ptp_clock_kernel.h> 9 10 #include <linux/wireless.h> 10 11 #include <linux/if_bridge.h> 11 12 #include <net/dsa_stubs.h> ··· 270 269 int dev_get_hwtstamp_phylib(struct net_device *dev, 271 270 struct kernel_hwtstamp_config *cfg) 272 271 { 272 + struct hwtstamp_provider *hwprov; 273 + 274 + hwprov = rtnl_dereference(dev->hwprov); 275 + if (hwprov) { 276 + cfg->qualifier = hwprov->desc.qualifier; 277 + if (hwprov->source == HWTSTAMP_SOURCE_PHYLIB && 278 + hwprov->phydev) 279 + return phy_hwtstamp_get(hwprov->phydev, cfg); 280 + 281 + if (hwprov->source == HWTSTAMP_SOURCE_NETDEV) 282 + return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg); 283 + 284 + return -EOPNOTSUPP; 285 + } 286 + 273 287 if (phy_is_default_hwtstamp(dev->phydev)) 274 288 return phy_hwtstamp_get(dev->phydev, cfg); 275 289 ··· 340 324 struct netlink_ext_ack *extack) 341 325 { 342 326 const struct net_device_ops *ops = dev->netdev_ops; 343 - bool phy_ts = phy_is_default_hwtstamp(dev->phydev); 344 327 struct kernel_hwtstamp_config old_cfg = {}; 328 + struct hwtstamp_provider *hwprov; 329 + struct phy_device *phydev; 345 330 bool changed = false; 331 + bool phy_ts; 346 332 int err; 333 + 334 + hwprov = rtnl_dereference(dev->hwprov); 335 + if (hwprov) { 336 + if (hwprov->source == HWTSTAMP_SOURCE_PHYLIB && 337 + hwprov->phydev) { 338 + phy_ts = true; 339 + phydev = hwprov->phydev; 340 + } else if (hwprov->source == HWTSTAMP_SOURCE_NETDEV) { 341 + phy_ts = false; 342 + } else { 343 + return -EOPNOTSUPP; 344 + } 345 + 346 + cfg->qualifier = hwprov->desc.qualifier; 347 + } else { 348 + phy_ts = phy_is_default_hwtstamp(dev->phydev); 349 + if (phy_ts) 350 + phydev = dev->phydev; 351 + } 347 352 348 353 cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV; 349 354 ··· 387 350 changed = kernel_hwtstamp_config_changed(&old_cfg, cfg); 388 351 389 352 if (phy_ts) { 390 - err = phy_hwtstamp_set(dev->phydev, cfg, extack); 353 + err = phy_hwtstamp_set(phydev, cfg, extack); 391 354 if (err) { 392 355 if (changed) 393 356 ops->ndo_hwtstamp_set(dev, &old_cfg, NULL);
+47 -5
net/core/timestamping.c
··· 9 9 #include <linux/ptp_classify.h> 10 10 #include <linux/skbuff.h> 11 11 #include <linux/export.h> 12 + #include <linux/ptp_clock_kernel.h> 12 13 13 14 static unsigned int classify(const struct sk_buff *skb) 14 15 { ··· 22 21 23 22 void skb_clone_tx_timestamp(struct sk_buff *skb) 24 23 { 24 + struct hwtstamp_provider *hwprov; 25 25 struct mii_timestamper *mii_ts; 26 + struct phy_device *phydev; 26 27 struct sk_buff *clone; 27 28 unsigned int type; 28 29 29 - if (!skb->sk || !skb->dev || 30 - !phy_is_default_hwtstamp(skb->dev->phydev)) 30 + if (!skb->sk || !skb->dev) 31 31 return; 32 + 33 + rcu_read_lock(); 34 + hwprov = rcu_dereference(skb->dev->hwprov); 35 + if (hwprov) { 36 + if (hwprov->source != HWTSTAMP_SOURCE_PHYLIB || 37 + !hwprov->phydev) { 38 + rcu_read_unlock(); 39 + return; 40 + } 41 + 42 + phydev = hwprov->phydev; 43 + } else { 44 + phydev = skb->dev->phydev; 45 + if (!phy_is_default_hwtstamp(phydev)) { 46 + rcu_read_unlock(); 47 + return; 48 + } 49 + } 50 + rcu_read_unlock(); 32 51 33 52 type = classify(skb); 34 53 if (type == PTP_CLASS_NONE) 35 54 return; 36 55 37 - mii_ts = skb->dev->phydev->mii_ts; 56 + mii_ts = phydev->mii_ts; 38 57 if (likely(mii_ts->txtstamp)) { 39 58 clone = skb_clone_sk(skb); 40 59 if (!clone) ··· 66 45 67 46 bool skb_defer_rx_timestamp(struct sk_buff *skb) 68 47 { 48 + struct hwtstamp_provider *hwprov; 69 49 struct mii_timestamper *mii_ts; 50 + struct phy_device *phydev; 70 51 unsigned int type; 71 52 72 - if (!skb->dev || !phy_is_default_hwtstamp(skb->dev->phydev)) 53 + if (!skb->dev) 73 54 return false; 55 + 56 + rcu_read_lock(); 57 + hwprov = rcu_dereference(skb->dev->hwprov); 58 + if (hwprov) { 59 + if (hwprov->source != HWTSTAMP_SOURCE_PHYLIB || 60 + !hwprov->phydev) { 61 + rcu_read_unlock(); 62 + return false; 63 + } 64 + 65 + phydev = hwprov->phydev; 66 + } else { 67 + phydev = skb->dev->phydev; 68 + if (!phy_is_default_hwtstamp(phydev)) { 69 + rcu_read_unlock(); 70 + return false; 71 + } 72 + } 73 + rcu_read_unlock(); 74 74 75 75 if (skb_headroom(skb) < ETH_HLEN) 76 76 return false; ··· 105 63 if (type == PTP_CLASS_NONE) 106 64 return false; 107 65 108 - mii_ts = skb->dev->phydev->mii_ts; 66 + mii_ts = phydev->mii_ts; 109 67 if (likely(mii_ts->rxtstamp)) 110 68 return mii_ts->rxtstamp(mii_ts, skb, type); 111 69