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

can: kvaser_usb: advertise timestamping capabilities and add ioctl support

Currently, userland has no method to query which timestamping features
are supported by the kvaser_usb driver (aside maybe of getting RX
messages and observe whether or not hardware timestamps stay at zero).

The canonical way for a network driver to advertise what kind of
timestamping it supports is to implement
ethtool_ops::get_ts_info(). Here, we use the CAN specific
can_ethtool_op_get_ts_info_hwts() function to achieve this.

In addition, the driver currently does not support the hardware
timestamps ioctls. According to [1], SIOCSHWTSTAMP is "must" and
SIOCGHWTSTAMP is "should". This patch fills up that gap by
implementing net_device_ops::ndo_eth_ioctl() using the CAN specific
function can_eth_ioctl_hwts().

[1] kernel doc Timestamping, section 3.1: "Hardware Timestamping
Implementation: Device Drivers"
Link: https://docs.kernel.org/networking/timestamping.html#hardware-timestamping-implementation-device-drivers

CC: Jimmy Assarsson <extja@kvaser.com>
Signed-off-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Link: https://lore.kernel.org/all/20220727101641.198847-13-mailhol.vincent@wanadoo.fr
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Vincent Mailhol and committed by
Marc Kleine-Budde
1d5eeda2 fa5cc7e1

+26 -2
+1
drivers/net/can/usb/kvaser_usb/kvaser_usb.h
··· 39 39 #define KVASER_USB_QUIRK_HAS_SILENT_MODE BIT(0) 40 40 #define KVASER_USB_QUIRK_HAS_TXRX_ERRORS BIT(1) 41 41 #define KVASER_USB_QUIRK_IGNORE_CLK_FREQ BIT(2) 42 + #define KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP BIT(3) 42 43 43 44 /* Device capabilities */ 44 45 #define KVASER_USB_CAP_BERR_CAP 0x01
+25 -2
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
··· 13 13 14 14 #include <linux/completion.h> 15 15 #include <linux/device.h> 16 + #include <linux/ethtool.h> 16 17 #include <linux/gfp.h> 17 18 #include <linux/if.h> 18 19 #include <linux/kernel.h> ··· 90 89 #define USB_HYBRID_PRO_CANLIN_PRODUCT_ID 278 91 90 92 91 static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = { 93 - .quirks = 0, 92 + .quirks = KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP, 94 93 .ops = &kvaser_usb_hydra_dev_ops, 95 94 }; 96 95 ··· 666 665 .ndo_change_mtu = can_change_mtu, 667 666 }; 668 667 668 + static const struct net_device_ops kvaser_usb_netdev_ops_hwts = { 669 + .ndo_open = kvaser_usb_open, 670 + .ndo_stop = kvaser_usb_close, 671 + .ndo_eth_ioctl = can_eth_ioctl_hwts, 672 + .ndo_start_xmit = kvaser_usb_start_xmit, 673 + .ndo_change_mtu = can_change_mtu, 674 + }; 675 + 676 + static const struct ethtool_ops kvaser_usb_ethtool_ops = { 677 + .get_ts_info = ethtool_op_get_ts_info, 678 + }; 679 + 680 + static const struct ethtool_ops kvaser_usb_ethtool_ops_hwts = { 681 + .get_ts_info = can_ethtool_op_get_ts_info_hwts, 682 + }; 683 + 669 684 static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev) 670 685 { 671 686 int i; ··· 759 742 netdev->flags |= IFF_ECHO; 760 743 761 744 netdev->netdev_ops = &kvaser_usb_netdev_ops; 762 - 745 + if (driver_info->quirks & KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP) { 746 + netdev->netdev_ops = &kvaser_usb_netdev_ops_hwts; 747 + netdev->ethtool_ops = &kvaser_usb_ethtool_ops_hwts; 748 + } else { 749 + netdev->netdev_ops = &kvaser_usb_netdev_ops; 750 + netdev->ethtool_ops = &kvaser_usb_ethtool_ops; 751 + } 763 752 SET_NETDEV_DEV(netdev, &dev->intf->dev); 764 753 netdev->dev_id = channel; 765 754