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

can: peak_canfd: advertise timestamping capabilities and add ioctl support

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

The canonical way to add hardware timestamp support is to implement
ethtool_ops::get_ts_info() in order to advertise the timestamping
capabilities and to implement net_device_ops::ndo_eth_ioctl() as
requested in [1]. Currently, the driver only supports hardware RX
timestamps [2] but not hardware TX. For this reason, the generic
function can_ethtool_op_get_ts_info_hwts() and can_eth_ioctl_hwts()
can not be reused and instead this patch adds peak_get_ts_info() and
peak_eth_ioctl().

[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

[2] https://lore.kernel.org/linux-can/20220727084257.brcbbf7lksoeekbr@pengutronix.de/

CC: Stephane Grosjean <s.grosjean@peak-system.com>
Signed-off-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Link: https://lore.kernel.org/all/20220727101641.198847-14-mailhol.vincent@wanadoo.fr
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Vincent Mailhol and committed by
Marc Kleine-Budde
8ba09bfa 1d5eeda2

+48
+48
drivers/net/can/peak_canfd/peak_canfd.c
··· 7 7 8 8 #include <linux/can.h> 9 9 #include <linux/can/dev.h> 10 + #include <linux/ethtool.h> 10 11 11 12 #include "peak_canfd_user.h" 12 13 ··· 743 742 return NETDEV_TX_OK; 744 743 } 745 744 745 + static int peak_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) 746 + { 747 + struct hwtstamp_config hwts_cfg = { 0 }; 748 + 749 + switch (cmd) { 750 + case SIOCSHWTSTAMP: /* set */ 751 + if (copy_from_user(&hwts_cfg, ifr->ifr_data, sizeof(hwts_cfg))) 752 + return -EFAULT; 753 + if (hwts_cfg.tx_type == HWTSTAMP_TX_OFF && 754 + hwts_cfg.rx_filter == HWTSTAMP_FILTER_ALL) 755 + return 0; 756 + return -ERANGE; 757 + 758 + case SIOCGHWTSTAMP: /* get */ 759 + hwts_cfg.tx_type = HWTSTAMP_TX_OFF; 760 + hwts_cfg.rx_filter = HWTSTAMP_FILTER_ALL; 761 + if (copy_to_user(ifr->ifr_data, &hwts_cfg, sizeof(hwts_cfg))) 762 + return -EFAULT; 763 + return 0; 764 + 765 + default: 766 + return -EOPNOTSUPP; 767 + } 768 + } 769 + 746 770 static const struct net_device_ops peak_canfd_netdev_ops = { 747 771 .ndo_open = peak_canfd_open, 748 772 .ndo_stop = peak_canfd_close, 773 + .ndo_eth_ioctl = peak_eth_ioctl, 749 774 .ndo_start_xmit = peak_canfd_start_xmit, 750 775 .ndo_change_mtu = can_change_mtu, 776 + }; 777 + 778 + static int peak_get_ts_info(struct net_device *dev, 779 + struct ethtool_ts_info *info) 780 + { 781 + info->so_timestamping = 782 + SOF_TIMESTAMPING_TX_SOFTWARE | 783 + SOF_TIMESTAMPING_RX_SOFTWARE | 784 + SOF_TIMESTAMPING_SOFTWARE | 785 + SOF_TIMESTAMPING_RX_HARDWARE | 786 + SOF_TIMESTAMPING_RAW_HARDWARE; 787 + info->phc_index = -1; 788 + info->tx_types = BIT(HWTSTAMP_TX_OFF); 789 + info->rx_filters = BIT(HWTSTAMP_FILTER_ALL); 790 + 791 + return 0; 792 + } 793 + 794 + static const struct ethtool_ops peak_canfd_ethtool_ops = { 795 + .get_ts_info = peak_get_ts_info, 751 796 }; 752 797 753 798 struct net_device *alloc_peak_canfd_dev(int sizeof_priv, int index, ··· 836 789 837 790 ndev->flags |= IFF_ECHO; 838 791 ndev->netdev_ops = &peak_canfd_netdev_ops; 792 + ndev->ethtool_ops = &peak_canfd_ethtool_ops; 839 793 ndev->dev_id = index; 840 794 841 795 return ndev;