Skip to content

Commit

Permalink
net: add NDOs for configuring hardware timestamping
Browse files Browse the repository at this point in the history
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 <kuba@kernel.org>
Signed-off-by: Maxim Georgiev <glipus@gmail.com>
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-2-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Maxim Georgiev authored and Jakub Kicinski committed Aug 3, 2023
1 parent 72c1a28 commit 66f7223
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 2 deletions.
8 changes: 8 additions & 0 deletions include/linux/net_tstamp.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,12 @@ static inline void hwtstamp_config_to_kernel(struct kernel_hwtstamp_config *kern
kernel_cfg->rx_filter = cfg->rx_filter;
}

static inline void hwtstamp_config_from_kernel(struct hwtstamp_config *cfg,
const struct kernel_hwtstamp_config *kernel_cfg)
{
cfg->flags = kernel_cfg->flags;
cfg->tx_type = kernel_cfg->tx_type;
cfg->rx_filter = kernel_cfg->rx_filter;
}

#endif /* _LINUX_NET_TIMESTAMPING_H_ */
16 changes: 16 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
struct netpoll_info;
struct device;
struct ethtool_ops;
struct kernel_hwtstamp_config;
struct phy_device;
struct dsa_port;
struct ip_tunnel_parm;
Expand Down Expand Up @@ -1418,6 +1419,16 @@ struct netdev_net_notifier {
* Get hardware timestamp based on normal/adjustable time or free running
* cycle counter. This function is required if physical clock supports a
* free running cycle counter.
*
* int (*ndo_hwtstamp_get)(struct net_device *dev,
* struct kernel_hwtstamp_config *kernel_config);
* Get the currently configured hardware timestamping parameters for the
* NIC device.
*
* int (*ndo_hwtstamp_set)(struct net_device *dev,
* struct kernel_hwtstamp_config *kernel_config,
* struct netlink_ext_ack *extack);
* Change the hardware timestamping parameters for NIC device.
*/
struct net_device_ops {
int (*ndo_init)(struct net_device *dev);
Expand Down Expand Up @@ -1652,6 +1663,11 @@ struct net_device_ops {
ktime_t (*ndo_get_tstamp)(struct net_device *dev,
const struct skb_shared_hwtstamps *hwtstamps,
bool cycles);
int (*ndo_hwtstamp_get)(struct net_device *dev,
struct kernel_hwtstamp_config *kernel_config);
int (*ndo_hwtstamp_set)(struct net_device *dev,
struct kernel_hwtstamp_config *kernel_config,
struct netlink_ext_ack *extack);
};

struct xdp_metadata_ops {
Expand Down
46 changes: 44 additions & 2 deletions net/core/dev_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,32 @@ static int dev_eth_ioctl(struct net_device *dev,

static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
{
return dev_eth_ioctl(dev, ifr, SIOCGHWTSTAMP);
const struct net_device_ops *ops = dev->netdev_ops;
struct kernel_hwtstamp_config kernel_cfg = {};
struct hwtstamp_config cfg;
int err;

if (!ops->ndo_hwtstamp_get)
return dev_eth_ioctl(dev, ifr, SIOCGHWTSTAMP); /* legacy */

if (!netif_device_present(dev))
return -ENODEV;

err = ops->ndo_hwtstamp_get(dev, &kernel_cfg);
if (err)
return err;

hwtstamp_config_from_kernel(&cfg, &kernel_cfg);

if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)))
return -EFAULT;

return 0;
}

static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
{
const struct net_device_ops *ops = dev->netdev_ops;
struct kernel_hwtstamp_config kernel_cfg;
struct netlink_ext_ack extack = {};
struct hwtstamp_config cfg;
Expand All @@ -280,7 +301,28 @@ static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
return err;
}

return dev_eth_ioctl(dev, ifr, SIOCSHWTSTAMP);
if (!ops->ndo_hwtstamp_set)
return dev_eth_ioctl(dev, ifr, SIOCSHWTSTAMP); /* legacy */

if (!netif_device_present(dev))
return -ENODEV;

err = ops->ndo_hwtstamp_set(dev, &kernel_cfg, &extack);
if (err) {
if (extack._msg)
netdev_err(dev, "%s\n", extack._msg);
return err;
}

/* The driver may have modified the configuration, so copy the
* updated version of it back to user space
*/
hwtstamp_config_from_kernel(&cfg, &kernel_cfg);

if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)))
return -EFAULT;

return 0;
}

static int dev_siocbond(struct net_device *dev,
Expand Down

0 comments on commit 66f7223

Please sign in to comment.