Skip to content

Commit 66f7223

Browse files
maxgeorgievkuba-moo
authored andcommitted
net: add NDOs for configuring hardware timestamping
Current hardware timestamping API for NICs requires implementing .ndo_eth_ioctl() for SIOCGHWTSTAMP and SIOCSHWTSTAMP. That API has some boilerplate such as request parameter translation between user and kernel address spaces, handling possible translation failures correctly, etc. Since it is the same all across the board, it would be desirable to handle it through generic code. Here we introduce .ndo_hwtstamp_get() and .ndo_hwtstamp_set(), which implement that boilerplate and allow drivers to just act upon requests. Suggested-by: Jakub Kicinski <[email protected]> Signed-off-by: Maxim Georgiev <[email protected]> Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Jacob Keller <[email protected]> Tested-by: Horatiu Vultur <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 72c1a28 commit 66f7223

File tree

3 files changed

+68
-2
lines changed

3 files changed

+68
-2
lines changed

include/linux/net_tstamp.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,12 @@ static inline void hwtstamp_config_to_kernel(struct kernel_hwtstamp_config *kern
3030
kernel_cfg->rx_filter = cfg->rx_filter;
3131
}
3232

33+
static inline void hwtstamp_config_from_kernel(struct hwtstamp_config *cfg,
34+
const struct kernel_hwtstamp_config *kernel_cfg)
35+
{
36+
cfg->flags = kernel_cfg->flags;
37+
cfg->tx_type = kernel_cfg->tx_type;
38+
cfg->rx_filter = kernel_cfg->rx_filter;
39+
}
40+
3341
#endif /* _LINUX_NET_TIMESTAMPING_H_ */

include/linux/netdevice.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
struct netpoll_info;
5858
struct device;
5959
struct ethtool_ops;
60+
struct kernel_hwtstamp_config;
6061
struct phy_device;
6162
struct dsa_port;
6263
struct ip_tunnel_parm;
@@ -1418,6 +1419,16 @@ struct netdev_net_notifier {
14181419
* Get hardware timestamp based on normal/adjustable time or free running
14191420
* cycle counter. This function is required if physical clock supports a
14201421
* free running cycle counter.
1422+
*
1423+
* int (*ndo_hwtstamp_get)(struct net_device *dev,
1424+
* struct kernel_hwtstamp_config *kernel_config);
1425+
* Get the currently configured hardware timestamping parameters for the
1426+
* NIC device.
1427+
*
1428+
* int (*ndo_hwtstamp_set)(struct net_device *dev,
1429+
* struct kernel_hwtstamp_config *kernel_config,
1430+
* struct netlink_ext_ack *extack);
1431+
* Change the hardware timestamping parameters for NIC device.
14211432
*/
14221433
struct net_device_ops {
14231434
int (*ndo_init)(struct net_device *dev);
@@ -1652,6 +1663,11 @@ struct net_device_ops {
16521663
ktime_t (*ndo_get_tstamp)(struct net_device *dev,
16531664
const struct skb_shared_hwtstamps *hwtstamps,
16541665
bool cycles);
1666+
int (*ndo_hwtstamp_get)(struct net_device *dev,
1667+
struct kernel_hwtstamp_config *kernel_config);
1668+
int (*ndo_hwtstamp_set)(struct net_device *dev,
1669+
struct kernel_hwtstamp_config *kernel_config,
1670+
struct netlink_ext_ack *extack);
16551671
};
16561672

16571673
struct xdp_metadata_ops {

net/core/dev_ioctl.c

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,32 @@ static int dev_eth_ioctl(struct net_device *dev,
254254

255255
static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
256256
{
257-
return dev_eth_ioctl(dev, ifr, SIOCGHWTSTAMP);
257+
const struct net_device_ops *ops = dev->netdev_ops;
258+
struct kernel_hwtstamp_config kernel_cfg = {};
259+
struct hwtstamp_config cfg;
260+
int err;
261+
262+
if (!ops->ndo_hwtstamp_get)
263+
return dev_eth_ioctl(dev, ifr, SIOCGHWTSTAMP); /* legacy */
264+
265+
if (!netif_device_present(dev))
266+
return -ENODEV;
267+
268+
err = ops->ndo_hwtstamp_get(dev, &kernel_cfg);
269+
if (err)
270+
return err;
271+
272+
hwtstamp_config_from_kernel(&cfg, &kernel_cfg);
273+
274+
if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)))
275+
return -EFAULT;
276+
277+
return 0;
258278
}
259279

260280
static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
261281
{
282+
const struct net_device_ops *ops = dev->netdev_ops;
262283
struct kernel_hwtstamp_config kernel_cfg;
263284
struct netlink_ext_ack extack = {};
264285
struct hwtstamp_config cfg;
@@ -280,7 +301,28 @@ static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
280301
return err;
281302
}
282303

283-
return dev_eth_ioctl(dev, ifr, SIOCSHWTSTAMP);
304+
if (!ops->ndo_hwtstamp_set)
305+
return dev_eth_ioctl(dev, ifr, SIOCSHWTSTAMP); /* legacy */
306+
307+
if (!netif_device_present(dev))
308+
return -ENODEV;
309+
310+
err = ops->ndo_hwtstamp_set(dev, &kernel_cfg, &extack);
311+
if (err) {
312+
if (extack._msg)
313+
netdev_err(dev, "%s\n", extack._msg);
314+
return err;
315+
}
316+
317+
/* The driver may have modified the configuration, so copy the
318+
* updated version of it back to user space
319+
*/
320+
hwtstamp_config_from_kernel(&cfg, &kernel_cfg);
321+
322+
if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)))
323+
return -EFAULT;
324+
325+
return 0;
284326
}
285327

286328
static int dev_siocbond(struct net_device *dev,

0 commit comments

Comments
 (0)