diff mbox series

[RFC,net-next,v6,1/5] net: Add NDOs for hardware timestamp get/set

Message ID 20230502043150.17097-2-glipus@gmail.com (mailing list archive)
State RFC
Delegated to: Netdev Maintainers
Headers show
Series New NDO methods ndo_hwtstamp_get/set | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 4193 this patch: 4193
netdev/cc_maintainers warning 4 maintainers not CCed: pabeni@redhat.com edumazet@google.com f.fainelli@gmail.com davem@davemloft.net
netdev/build_clang success Errors and warnings before: 932 this patch: 932
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 4401 this patch: 4401
netdev/checkpatch warning WARNING: line length of 84 exceeds 80 columns WARNING: line length of 95 exceeds 80 columns WARNING: line length of 97 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Max Georgiev May 2, 2023, 4:31 a.m. UTC
Current NIC driver API demands drivers supporting hardware timestamping
to implement handling logic for SIOCGHWTSTAMP/SIOCSHWTSTAMP IOCTLs.
Handling these IOCTLs requires dirivers to implement request parameter
structure translation between user and kernel address spaces, handling
possible translation failures, etc. This translation code is pretty much
identical across most of the NIC drivers that support SIOCGHWTSTAMP/
SIOCSHWTSTAMP.
This patch extends NDO functiuon set with ndo_hwtstamp_get/set
functions, implements SIOCGHWTSTAMP/SIOCSHWTSTAMP IOCTL translation
to ndo_hwtstamp_get/set function calls including parameter structure
translation and translation error handling.

This patch is sent out as RFC.
It still pending on basic testing.

Suggested-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Maxim Georgiev <glipus@gmail.com>
---
Notes:
  Changes in v6:
  - The patch title was updated. No code changes.
  Changes in v4:
  - Renamed hwtstamp_kernel_to_config() function to
    hwtstamp_config_from_kernel().
  - Added struct kernel_hwtstamp_config zero initialization
    in dev_get_hwtstamp() and in dev_get_hwtstamp().

Changes in v3:
- Moved individual driver conversions to separate patches

Changes in v2:
- Introduced kernel_hwtstamp_config structure
- Added netlink_ext_ack* and kernel_hwtstamp_config* as NDO hw timestamp
  function parameters
- Reodered function variable declarations in dev_hwtstamp()
- Refactored error handling logic in dev_hwtstamp()
- Split dev_hwtstamp() into GET and SET versions
- Changed net_hwtstamp_validate() to accept struct hwtstamp_config *
  as a parameter
---
 include/linux/net_tstamp.h |  8 ++++++++
 include/linux/netdevice.h  | 16 +++++++++++++++
 net/core/dev_ioctl.c       | 42 +++++++++++++++++++++++++++++++++++---
 3 files changed, 63 insertions(+), 3 deletions(-)

Comments

Vladimir Oltean May 11, 2023, 12:32 p.m. UTC | #1
On Mon, May 01, 2023 at 10:31:46PM -0600, Maxim Georgiev wrote:
>  struct net_device_ops {
>  	int			(*ndo_init)(struct net_device *dev);
> @@ -1649,6 +1659,12 @@ 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,
> +						    struct netlink_ext_ack *extack);

I'm not sure it is necessary to pass an extack to "get". That should
only give a more detailed reason if the driver refuses something.

For that matter, now that ndo_hwtstamp_get() should no longer be
concerned with the copy_to_user(), I'm not even sure that it should
return int at all, and not void. The transition is going to be slightly
problematic though, with the generic_hwtstamp_get_lower() necessarily
still calling dev_eth_ioctl() -> copy_to_user(), so we probably can't
make it void just now.
Max Georgiev May 12, 2023, 3:22 a.m. UTC | #2
On Thu, May 11, 2023 at 6:32 AM Vladimir Oltean <vladimir.oltean@nxp.com> wrote:
>
> On Mon, May 01, 2023 at 10:31:46PM -0600, Maxim Georgiev wrote:
> >  struct net_device_ops {
> >       int                     (*ndo_init)(struct net_device *dev);
> > @@ -1649,6 +1659,12 @@ 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,
> > +                                                 struct netlink_ext_ack *extack);
>
> I'm not sure it is necessary to pass an extack to "get". That should
> only give a more detailed reason if the driver refuses something.

I have to admit I just followed Jakub's guidance adding "extack" to the
list of parametres. I'll let Jakub to comment on that.

>
> For that matter, now that ndo_hwtstamp_get() should no longer be
> concerned with the copy_to_user(), I'm not even sure that it should
> return int at all, and not void. The transition is going to be slightly
> problematic though, with the generic_hwtstamp_get_lower() necessarily
> still calling dev_eth_ioctl() -> copy_to_user(), so we probably can't
> make it void just now.

Would it make sense to keep the return int value here "for future extensions"?
Jakub Kicinski May 12, 2023, 5:41 p.m. UTC | #3
On Thu, 11 May 2023 21:22:23 -0600 Max Georgiev wrote:
> > > +     int                     (*ndo_hwtstamp_get)(struct net_device *dev,
> > > +                                                 struct kernel_hwtstamp_config *kernel_config,
> > > +                                                 struct netlink_ext_ack *extack);  
> >
> > I'm not sure it is necessary to pass an extack to "get". That should
> > only give a more detailed reason if the driver refuses something.  
> 
> I have to admit I just followed Jakub's guidance adding "extack" to the
> list of parametres. I'll let Jakub to comment on that.

We can drop it from get, I can't think of any strong use case.
Max Georgiev May 15, 2023, 3:36 p.m. UTC | #4
On Fri, May 12, 2023 at 11:41 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Thu, 11 May 2023 21:22:23 -0600 Max Georgiev wrote:
> > > > +     int                     (*ndo_hwtstamp_get)(struct net_device *dev,
> > > > +                                                 struct kernel_hwtstamp_config *kernel_config,
> > > > +                                                 struct netlink_ext_ack *extack);
> > >
> > > I'm not sure it is necessary to pass an extack to "get". That should
> > > only give a more detailed reason if the driver refuses something.
> >
> > I have to admit I just followed Jakub's guidance adding "extack" to the
> > list of parametres. I'll let Jakub to comment on that.
>
> We can drop it from get, I can't think of any strong use case.

Got it. Will remove the  "extack" parameter from ndo_hwtstamp_get() in the
next revision.
diff mbox series

Patch

diff --git a/include/linux/net_tstamp.h b/include/linux/net_tstamp.h
index fd67f3cc0c4b..7c59824f43f5 100644
--- a/include/linux/net_tstamp.h
+++ b/include/linux/net_tstamp.h
@@ -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_ */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 08fbd4622ccf..7160135ca540 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -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;
@@ -1415,6 +1416,15 @@  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,
+ *				struct netlink_ext_ack *extack);
+ *	Get hardware timestamping parameters currently configured for NIC
+ *	device.
+ *	int (*ndo_hwtstamp_set)(struct net_device *dev,
+ *				struct kernel_hwtstamp_config *kernel_config,
+ *				struct netlink_ext_ack *extack);
+ *	Set hardware timestamping parameters for NIC device.
  */
 struct net_device_ops {
 	int			(*ndo_init)(struct net_device *dev);
@@ -1649,6 +1659,12 @@  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,
+						    struct netlink_ext_ack *extack);
+	int			(*ndo_hwtstamp_set)(struct net_device *dev,
+						    struct kernel_hwtstamp_config *kernel_config,
+						    struct netlink_ext_ack *extack);
 };
 
 struct xdp_metadata_ops {
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
index 3730945ee294..a157b9ab5237 100644
--- a/net/core/dev_ioctl.c
+++ b/net/core/dev_ioctl.c
@@ -254,12 +254,33 @@  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 config;
+	int err;
+
+	if (!ops->ndo_hwtstamp_get)
+		return dev_eth_ioctl(dev, ifr, SIOCGHWTSTAMP);
+
+	if (!netif_device_present(dev))
+		return -ENODEV;
+
+	err = ops->ndo_hwtstamp_get(dev, &kernel_cfg, NULL);
+	if (err)
+		return err;
+
+	hwtstamp_config_from_kernel(&config, &kernel_cfg);
+
+	if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
+		return -EFAULT;
+
+	return 0;
 }
 
 static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
 {
-	struct kernel_hwtstamp_config kernel_cfg;
+	const struct net_device_ops *ops = dev->netdev_ops;
+	struct kernel_hwtstamp_config kernel_cfg = {};
 	struct netlink_ext_ack extack = {};
 	struct hwtstamp_config cfg;
 	int err;
@@ -280,7 +301,22 @@  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);
+
+	if (!netif_device_present(dev))
+		return -ENODEV;
+
+	err = ops->ndo_hwtstamp_set(dev, &kernel_cfg, NULL);
+	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_siocbond(struct net_device *dev,