Skip to content

Commit fd770e8

Browse files
vladimirolteankuba-moo
authored andcommitted
net: remove phy_has_hwtstamp() -> phy_mii_ioctl() decision from converted drivers
It is desirable that the new .ndo_hwtstamp_set() API gives more uniformity, less overhead and future flexibility w.r.t. the PHY timestamping behavior. Currently there are some drivers which allow PHY timestamping through the procedure mentioned in Documentation/networking/timestamping.rst. They don't do anything locally if phy_has_hwtstamp() is set, except for lan966x which installs PTP packet traps. Centralize that behavior in a new dev_set_hwtstamp_phylib() code function, which calls either phy_mii_ioctl() for the phylib PHY, or .ndo_hwtstamp_set() of the netdev, based on a single policy (currently simplistic: phy_has_hwtstamp()). Any driver converted to .ndo_hwtstamp_set() will automatically opt into the centralized phylib timestamping policy. Unconverted drivers still get to choose whether they let the PHY handle timestamping or not. Netdev drivers with integrated PHY drivers that don't use phylib presumably don't set dev->phydev, and those will always see HWTSTAMP_SOURCE_NETDEV requests even when converted. The timestamping policy will remain 100% up to them. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Reviewed-by: Jacob Keller <jacob.e.keller@intel.com> Tested-by: Horatiu Vultur <horatiu.vultur@microchip.com> Link: https://lore.kernel.org/r/20230801142824.1772134-13-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 60495b6 commit fd770e8

File tree

6 files changed

+117
-33
lines changed

6 files changed

+117
-33
lines changed

drivers/net/ethernet/freescale/fec_main.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3872,10 +3872,6 @@ static int fec_hwtstamp_get(struct net_device *ndev,
38723872
struct kernel_hwtstamp_config *config)
38733873
{
38743874
struct fec_enet_private *fep = netdev_priv(ndev);
3875-
struct phy_device *phydev = ndev->phydev;
3876-
3877-
if (phy_has_hwtstamp(phydev))
3878-
return phy_mii_ioctl(phydev, config->ifr, SIOCGHWTSTAMP);
38793875

38803876
if (!netif_running(ndev))
38813877
return -EINVAL;
@@ -3893,10 +3889,6 @@ static int fec_hwtstamp_set(struct net_device *ndev,
38933889
struct netlink_ext_ack *extack)
38943890
{
38953891
struct fec_enet_private *fep = netdev_priv(ndev);
3896-
struct phy_device *phydev = ndev->phydev;
3897-
3898-
if (phy_has_hwtstamp(phydev))
3899-
return phy_mii_ioctl(phydev, config->ifr, SIOCSHWTSTAMP);
39003892

39013893
if (!netif_running(ndev))
39023894
return -EINVAL;

drivers/net/ethernet/microchip/lan966x/lan966x_main.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -455,9 +455,6 @@ static int lan966x_port_hwtstamp_get(struct net_device *dev,
455455
{
456456
struct lan966x_port *port = netdev_priv(dev);
457457

458-
if (phy_has_hwtstamp(dev->phydev))
459-
return phy_mii_ioctl(dev->phydev, cfg->ifr, SIOCGHWTSTAMP);
460-
461458
if (!port->lan966x->ptp)
462459
return -EOPNOTSUPP;
463460

@@ -473,21 +470,26 @@ static int lan966x_port_hwtstamp_set(struct net_device *dev,
473470
struct lan966x_port *port = netdev_priv(dev);
474471
int err;
475472

473+
if (cfg->source != HWTSTAMP_SOURCE_NETDEV &&
474+
cfg->source != HWTSTAMP_SOURCE_PHYLIB)
475+
return -EOPNOTSUPP;
476+
476477
err = lan966x_ptp_setup_traps(port, cfg);
477478
if (err)
478479
return err;
479480

480-
if (phy_has_hwtstamp(dev->phydev)) {
481-
err = phy_mii_ioctl(dev->phydev, cfg->ifr, SIOCSHWTSTAMP);
482-
if (err)
481+
if (cfg->source == HWTSTAMP_SOURCE_NETDEV) {
482+
if (!port->lan966x->ptp)
483+
return -EOPNOTSUPP;
484+
485+
err = lan966x_ptp_hwtstamp_set(port, cfg, extack);
486+
if (err) {
483487
lan966x_ptp_del_traps(port);
484-
return err;
488+
return err;
489+
}
485490
}
486491

487-
if (!port->lan966x->ptp)
488-
return -EOPNOTSUPP;
489-
490-
return lan966x_ptp_hwtstamp_set(port, cfg, extack);
492+
return 0;
491493
}
492494

493495
static const struct net_device_ops lan966x_port_netdev_ops = {
@@ -815,6 +817,7 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
815817
NETIF_F_HW_VLAN_STAG_TX |
816818
NETIF_F_HW_TC;
817819
dev->hw_features |= NETIF_F_HW_TC;
820+
dev->priv_flags |= IFF_SEE_ALL_HWTSTAMP_REQUESTS;
818821
dev->needed_headroom = IFH_LEN_BYTES;
819822

820823
eth_hw_addr_gen(dev, lan966x->base_mac, p + 1);

drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,6 @@ static int sparx5_port_hwtstamp_get(struct net_device *dev,
216216
struct sparx5_port *sparx5_port = netdev_priv(dev);
217217
struct sparx5 *sparx5 = sparx5_port->sparx5;
218218

219-
if (phy_has_hwtstamp(dev->phydev))
220-
return phy_mii_ioctl(dev->phydev, cfg->ifr, SIOCGHWTSTAMP);
221-
222219
if (!sparx5->ptp)
223220
return -EOPNOTSUPP;
224221

@@ -234,9 +231,6 @@ static int sparx5_port_hwtstamp_set(struct net_device *dev,
234231
struct sparx5_port *sparx5_port = netdev_priv(dev);
235232
struct sparx5 *sparx5 = sparx5_port->sparx5;
236233

237-
if (phy_has_hwtstamp(dev->phydev))
238-
return phy_mii_ioctl(dev->phydev, cfg->ifr, SIOCSHWTSTAMP);
239-
240234
if (!sparx5->ptp)
241235
return -EOPNOTSUPP;
242236

include/linux/net_tstamp.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55

66
#include <uapi/linux/net_tstamp.h>
77

8+
enum hwtstamp_source {
9+
HWTSTAMP_SOURCE_NETDEV,
10+
HWTSTAMP_SOURCE_PHYLIB,
11+
};
12+
813
/**
914
* struct kernel_hwtstamp_config - Kernel copy of struct hwtstamp_config
1015
*
@@ -15,6 +20,8 @@
1520
* a legacy implementation of a lower driver
1621
* @copied_to_user: request was passed to a legacy implementation which already
1722
* copied the ioctl request back to user space
23+
* @source: indication whether timestamps should come from the netdev or from
24+
* an attached phylib PHY
1825
*
1926
* Prefer using this structure for in-kernel processing of hardware
2027
* timestamping configuration, over the inextensible struct hwtstamp_config
@@ -26,6 +33,7 @@ struct kernel_hwtstamp_config {
2633
int rx_filter;
2734
struct ifreq *ifr;
2835
bool copied_to_user;
36+
enum hwtstamp_source source;
2937
};
3038

3139
static inline void hwtstamp_config_to_kernel(struct kernel_hwtstamp_config *kernel_cfg,
@@ -44,4 +52,12 @@ static inline void hwtstamp_config_from_kernel(struct hwtstamp_config *cfg,
4452
cfg->rx_filter = kernel_cfg->rx_filter;
4553
}
4654

55+
static inline bool kernel_hwtstamp_config_changed(const struct kernel_hwtstamp_config *a,
56+
const struct kernel_hwtstamp_config *b)
57+
{
58+
return a->flags != b->flags ||
59+
a->tx_type != b->tx_type ||
60+
a->rx_filter != b->rx_filter;
61+
}
62+
4763
#endif /* _LINUX_NET_TIMESTAMPING_H_ */

include/linux/netdevice.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,9 @@ struct xdp_metadata_ops {
17241724
* @IFF_TX_SKB_NO_LINEAR: device/driver is capable of xmitting frames with
17251725
* skb_headlen(skb) == 0 (data starts from frag0)
17261726
* @IFF_CHANGE_PROTO_DOWN: device supports setting carrier via IFLA_PROTO_DOWN
1727+
* @IFF_SEE_ALL_HWTSTAMP_REQUESTS: device wants to see calls to
1728+
* ndo_hwtstamp_set() for all timestamp requests regardless of source,
1729+
* even if those aren't HWTSTAMP_SOURCE_NETDEV.
17271730
*/
17281731
enum netdev_priv_flags {
17291732
IFF_802_1Q_VLAN = 1<<0,
@@ -1759,6 +1762,7 @@ enum netdev_priv_flags {
17591762
IFF_NO_ADDRCONF = BIT_ULL(30),
17601763
IFF_TX_SKB_NO_LINEAR = BIT_ULL(31),
17611764
IFF_CHANGE_PROTO_DOWN = BIT_ULL(32),
1765+
IFF_SEE_ALL_HWTSTAMP_REQUESTS = BIT_ULL(33),
17621766
};
17631767

17641768
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN

net/core/dev_ioctl.c

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/etherdevice.h>
66
#include <linux/rtnetlink.h>
77
#include <linux/net_tstamp.h>
8+
#include <linux/phylib_stubs.h>
89
#include <linux/wireless.h>
910
#include <linux/if_bridge.h>
1011
#include <net/dsa_stubs.h>
@@ -252,6 +253,30 @@ static int dev_eth_ioctl(struct net_device *dev,
252253
return ops->ndo_eth_ioctl(dev, ifr, cmd);
253254
}
254255

256+
/**
257+
* dev_get_hwtstamp_phylib() - Get hardware timestamping settings of NIC
258+
* or of attached phylib PHY
259+
* @dev: Network device
260+
* @cfg: Timestamping configuration structure
261+
*
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.
265+
*
266+
* Note: phy_mii_ioctl() only handles SIOCSHWTSTAMP (not SIOCGHWTSTAMP), and
267+
* there only exists a phydev->mii_ts->hwtstamp() method. So this will return
268+
* -EOPNOTSUPP for phylib for now, which is still more accurate than letting
269+
* the netdev handle the GET request.
270+
*/
271+
static int dev_get_hwtstamp_phylib(struct net_device *dev,
272+
struct kernel_hwtstamp_config *cfg)
273+
{
274+
if (phy_has_hwtstamp(dev->phydev))
275+
return phy_hwtstamp_get(dev->phydev, cfg);
276+
277+
return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg);
278+
}
279+
255280
static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
256281
{
257282
const struct net_device_ops *ops = dev->netdev_ops;
@@ -266,7 +291,7 @@ static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
266291
return -ENODEV;
267292

268293
kernel_cfg.ifr = ifr;
269-
err = ops->ndo_hwtstamp_get(dev, &kernel_cfg);
294+
err = dev_get_hwtstamp_phylib(dev, &kernel_cfg);
270295
if (err)
271296
return err;
272297

@@ -283,6 +308,59 @@ static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
283308
return 0;
284309
}
285310

311+
/**
312+
* dev_set_hwtstamp_phylib() - Change hardware timestamping of NIC
313+
* or of attached phylib PHY
314+
* @dev: Network device
315+
* @cfg: Timestamping configuration structure
316+
* @extack: Netlink extended ack message structure, for error reporting
317+
*
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
321+
* timestamping to work properly (a switch port must trap the timestamped
322+
* frames and not forward them), it must set IFF_SEE_ALL_HWTSTAMP_REQUESTS in
323+
* dev->priv_flags.
324+
*/
325+
static int dev_set_hwtstamp_phylib(struct net_device *dev,
326+
struct kernel_hwtstamp_config *cfg,
327+
struct netlink_ext_ack *extack)
328+
{
329+
const struct net_device_ops *ops = dev->netdev_ops;
330+
bool phy_ts = phy_has_hwtstamp(dev->phydev);
331+
struct kernel_hwtstamp_config old_cfg = {};
332+
bool changed = false;
333+
int err;
334+
335+
cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV;
336+
337+
if (!phy_ts || (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) {
338+
err = ops->ndo_hwtstamp_get(dev, &old_cfg);
339+
if (err)
340+
return err;
341+
342+
err = ops->ndo_hwtstamp_set(dev, cfg, extack);
343+
if (err) {
344+
if (extack->_msg)
345+
netdev_err(dev, "%s\n", extack->_msg);
346+
return err;
347+
}
348+
349+
changed = kernel_hwtstamp_config_changed(&old_cfg, cfg);
350+
}
351+
352+
if (phy_ts) {
353+
err = phy_hwtstamp_set(dev->phydev, cfg, extack);
354+
if (err) {
355+
if (changed)
356+
ops->ndo_hwtstamp_set(dev, &old_cfg, NULL);
357+
return err;
358+
}
359+
}
360+
361+
return 0;
362+
}
363+
286364
static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
287365
{
288366
const struct net_device_ops *ops = dev->netdev_ops;
@@ -314,12 +392,9 @@ static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
314392
if (!netif_device_present(dev))
315393
return -ENODEV;
316394

317-
err = ops->ndo_hwtstamp_set(dev, &kernel_cfg, &extack);
318-
if (err) {
319-
if (extack._msg)
320-
netdev_err(dev, "%s\n", extack._msg);
395+
err = dev_set_hwtstamp_phylib(dev, &kernel_cfg, &extack);
396+
if (err)
321397
return err;
322-
}
323398

324399
/* The driver may have modified the configuration, so copy the
325400
* updated version of it back to user space
@@ -362,7 +437,7 @@ int generic_hwtstamp_get_lower(struct net_device *dev,
362437
return -ENODEV;
363438

364439
if (ops->ndo_hwtstamp_get)
365-
return ops->ndo_hwtstamp_get(dev, kernel_cfg);
440+
return dev_get_hwtstamp_phylib(dev, kernel_cfg);
366441

367442
/* Legacy path: unconverted lower driver */
368443
return generic_hwtstamp_ioctl_lower(dev, SIOCGHWTSTAMP, kernel_cfg);
@@ -379,7 +454,7 @@ int generic_hwtstamp_set_lower(struct net_device *dev,
379454
return -ENODEV;
380455

381456
if (ops->ndo_hwtstamp_set)
382-
return ops->ndo_hwtstamp_set(dev, kernel_cfg, extack);
457+
return dev_set_hwtstamp_phylib(dev, kernel_cfg, extack);
383458

384459
/* Legacy path: unconverted lower driver */
385460
return generic_hwtstamp_ioctl_lower(dev, SIOCSHWTSTAMP, kernel_cfg);

0 commit comments

Comments
 (0)