Skip to content

Commit 12a18d7

Browse files
Merge patch series "can: add ethtool support and reporting of timestamping capabilities"
Vincent Mailhol <[email protected]> says: ==================== This series revolves around ethtool and timestamping. Its ultimate goal is that the timestamping implementation within socketCAN meets the specification of other network drivers in the kernel. This way, tcpdump or other tools derived from libpcap can be used to do timestamping on CAN devices. * Example on a device with hardware timestamp support * Before this series: | # tcpdump -j adapter_unsynced -i can0 | tcpdump: WARNING: When trying to set timestamp type | 'adapter_unsynced' on can0: That type of time stamp is not supported | by that device After applying this series, the warning disappears and tcpdump can be used to get RX hardware timestamps. This series is articulated in three major parts. * Part 1: Add TX software timestamps and report the software timestamping capabilities through ethtool. All the drivers using can_put_echo_skb() already support TX software timestamps. However, the five drivers not using this function (namely can327, janz-ican3, slcan, vcan and vxcan) lack such support. Patch 1 to 4 adds this support. Finally, patch 5 advertises the timesamping capabilities of all drivers which do not support hardware timestamps. * Part 2: add TX hardware timestapms This part is a single patch. In SocketCAN TX hardware is equal to the RX hardware timestamps of the corresponding loopback frame. Reuse the TX hardware timestamp to populate the RX hardware timestamp. While the need of this feature can be debatable, we implement it here so that generic timestamping tools which are agnostic of the specificity of SocketCAN can still obtain the value. For example, tcpdump expects for both TX and RX hardware timestamps to be supported in order to do: | # tcpdump -j adapter_unsynced -i canX * Part 3: report the hardware timestamping capabilities and implement the hardware timestamps ioctls. The kernel documentation specifies in [1] that, for the drivers which support hardware timestamping, SIOCSHWTSTAMP ioctl must be supported and that SIOCGHWTSTAMP ioctl should be supported. Currently, none of the CAN drivers do so. This is a gap. Furthermore, even if not specified, the tools based on libpcap (e.g. tcpdump) also expect ethtool_ops::get_ts_info to be implemented. This last part first adds some generic implementation of net_device_ops::ndo_eth_ioctl and ethtool_ops::get_ts_info which can be used by the drivers with hardware timestamping capabilities. It then uses those generic functions to add ioctl and reporting functionalities to the drivers with hardware timestamping support (namely: mcp251xfd, etas_es58x, kvaser_{pciefd,usb}, peak_{canfd,usb}) [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 * Testing * I also developed a tool to test all the different timestamps. For those who would also like to test it, please have a look at: https://lore.kernel.org/linux-can/[email protected]/T/ * Changelog * changes since v3: https://lore.kernel.org/all/[email protected] * The peak drivers (both PCI and USB) do not support hardware TX timestamps (only RX). Implement specific ioctl and ethtool callback functions for this device. changes since v2: https://lore.kernel.org/all/[email protected] * The c_can, flexcan, mcp251xfd and the slcan drivers already declared a struct ethtool_ops. Do not declare again the same structure and instead populate the .get_ts_info() field of the existing structures. changes since v1: https://lore.kernel.org/all/[email protected] * First series had a patch to implement ethtool_ops::get_drvinfo. This proved to be useless. This patch was removed and all the clean-up patches made in preparation of that one were moved to a separate series: https://lore.kernel.org/linux-can/[email protected]/T/#u ==================== Link: https://lore.kernel.org/all/[email protected] Signed-off-by: Marc Kleine-Budde <[email protected]>
2 parents 7c862ee + bedd948 commit 12a18d7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+365
-3
lines changed

drivers/net/can/at91_can.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <linux/clk.h>
1010
#include <linux/errno.h>
11+
#include <linux/ethtool.h>
1112
#include <linux/if_arp.h>
1213
#include <linux/interrupt.h>
1314
#include <linux/kernel.h>
@@ -1152,6 +1153,10 @@ static const struct net_device_ops at91_netdev_ops = {
11521153
.ndo_change_mtu = can_change_mtu,
11531154
};
11541155

1156+
static const struct ethtool_ops at91_ethtool_ops = {
1157+
.get_ts_info = ethtool_op_get_ts_info,
1158+
};
1159+
11551160
static ssize_t mb0_id_show(struct device *dev,
11561161
struct device_attribute *attr, char *buf)
11571162
{
@@ -1293,6 +1298,7 @@ static int at91_can_probe(struct platform_device *pdev)
12931298
}
12941299

12951300
dev->netdev_ops = &at91_netdev_ops;
1301+
dev->ethtool_ops = &at91_ethtool_ops;
12961302
dev->irq = irq;
12971303
dev->flags |= IFF_ECHO;
12981304

drivers/net/can/c_can/c_can_ethtool.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ static void c_can_get_ringparam(struct net_device *netdev,
2626

2727
const struct ethtool_ops c_can_ethtool_ops = {
2828
.get_ringparam = c_can_get_ringparam,
29+
.get_ts_info = ethtool_op_get_ts_info,
2930
};

drivers/net/can/can327.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,8 @@ static netdev_tx_t can327_netdev_start_xmit(struct sk_buff *skb,
836836
dev->stats.tx_packets++;
837837
dev->stats.tx_bytes += frame->can_id & CAN_RTR_FLAG ? 0 : frame->len;
838838

839+
skb_tx_timestamp(skb);
840+
839841
out:
840842
kfree_skb(skb);
841843
return NETDEV_TX_OK;
@@ -848,6 +850,10 @@ static const struct net_device_ops can327_netdev_ops = {
848850
.ndo_change_mtu = can_change_mtu,
849851
};
850852

853+
static const struct ethtool_ops can327_ethtool_ops = {
854+
.get_ts_info = ethtool_op_get_ts_info,
855+
};
856+
851857
static bool can327_is_valid_rx_char(u8 c)
852858
{
853859
static const bool lut_char_is_valid['z'] = {
@@ -1032,6 +1038,7 @@ static int can327_ldisc_open(struct tty_struct *tty)
10321038
/* Configure netdev interface */
10331039
elm->dev = dev;
10341040
dev->netdev_ops = &can327_netdev_ops;
1041+
dev->ethtool_ops = &can327_ethtool_ops;
10351042

10361043
/* Mark ldisc channel as alive */
10371044
elm->tty = tty;

drivers/net/can/cc770/cc770.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/ptrace.h>
1818
#include <linux/string.h>
1919
#include <linux/errno.h>
20+
#include <linux/ethtool.h>
2021
#include <linux/netdevice.h>
2122
#include <linux/if_arp.h>
2223
#include <linux/if_ether.h>
@@ -836,6 +837,10 @@ static const struct net_device_ops cc770_netdev_ops = {
836837
.ndo_change_mtu = can_change_mtu,
837838
};
838839

840+
static const struct ethtool_ops cc770_ethtool_ops = {
841+
.get_ts_info = ethtool_op_get_ts_info,
842+
};
843+
839844
int register_cc770dev(struct net_device *dev)
840845
{
841846
struct cc770_priv *priv = netdev_priv(dev);
@@ -846,6 +851,7 @@ int register_cc770dev(struct net_device *dev)
846851
return err;
847852

848853
dev->netdev_ops = &cc770_netdev_ops;
854+
dev->ethtool_ops = &cc770_ethtool_ops;
849855

850856
dev->flags |= IFF_ECHO; /* we support local echo */
851857

drivers/net/can/ctucanfd/ctucanfd_base.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <linux/clk.h>
2121
#include <linux/errno.h>
22+
#include <linux/ethtool.h>
2223
#include <linux/init.h>
2324
#include <linux/bitfield.h>
2425
#include <linux/interrupt.h>
@@ -1301,6 +1302,10 @@ static const struct net_device_ops ctucan_netdev_ops = {
13011302
.ndo_change_mtu = can_change_mtu,
13021303
};
13031304

1305+
static const struct ethtool_ops ctucan_ethtool_ops = {
1306+
.get_ts_info = ethtool_op_get_ts_info,
1307+
};
1308+
13041309
int ctucan_suspend(struct device *dev)
13051310
{
13061311
struct net_device *ndev = dev_get_drvdata(dev);
@@ -1377,6 +1382,7 @@ int ctucan_probe_common(struct device *dev, void __iomem *addr, int irq, unsigne
13771382
set_drvdata_fnc(dev, ndev);
13781383
SET_NETDEV_DEV(ndev, dev);
13791384
ndev->netdev_ops = &ctucan_netdev_ops;
1385+
ndev->ethtool_ops = &ctucan_ethtool_ops;
13801386

13811387
/* Getting the can_clk info */
13821388
if (!can_clk_rate) {

drivers/net/can/dev/dev.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,56 @@ int can_change_mtu(struct net_device *dev, int new_mtu)
322322
}
323323
EXPORT_SYMBOL_GPL(can_change_mtu);
324324

325+
/* generic implementation of netdev_ops::ndo_eth_ioctl for CAN devices
326+
* supporting hardware timestamps
327+
*/
328+
int can_eth_ioctl_hwts(struct net_device *netdev, struct ifreq *ifr, int cmd)
329+
{
330+
struct hwtstamp_config hwts_cfg = { 0 };
331+
332+
switch (cmd) {
333+
case SIOCSHWTSTAMP: /* set */
334+
if (copy_from_user(&hwts_cfg, ifr->ifr_data, sizeof(hwts_cfg)))
335+
return -EFAULT;
336+
if (hwts_cfg.tx_type == HWTSTAMP_TX_ON &&
337+
hwts_cfg.rx_filter == HWTSTAMP_FILTER_ALL)
338+
return 0;
339+
return -ERANGE;
340+
341+
case SIOCGHWTSTAMP: /* get */
342+
hwts_cfg.tx_type = HWTSTAMP_TX_ON;
343+
hwts_cfg.rx_filter = HWTSTAMP_FILTER_ALL;
344+
if (copy_to_user(ifr->ifr_data, &hwts_cfg, sizeof(hwts_cfg)))
345+
return -EFAULT;
346+
return 0;
347+
348+
default:
349+
return -EOPNOTSUPP;
350+
}
351+
}
352+
EXPORT_SYMBOL(can_eth_ioctl_hwts);
353+
354+
/* generic implementation of ethtool_ops::get_ts_info for CAN devices
355+
* supporting hardware timestamps
356+
*/
357+
int can_ethtool_op_get_ts_info_hwts(struct net_device *dev,
358+
struct ethtool_ts_info *info)
359+
{
360+
info->so_timestamping =
361+
SOF_TIMESTAMPING_TX_SOFTWARE |
362+
SOF_TIMESTAMPING_RX_SOFTWARE |
363+
SOF_TIMESTAMPING_SOFTWARE |
364+
SOF_TIMESTAMPING_TX_HARDWARE |
365+
SOF_TIMESTAMPING_RX_HARDWARE |
366+
SOF_TIMESTAMPING_RAW_HARDWARE;
367+
info->phc_index = -1;
368+
info->tx_types = BIT(HWTSTAMP_TX_ON);
369+
info->rx_filters = BIT(HWTSTAMP_FILTER_ALL);
370+
371+
return 0;
372+
}
373+
EXPORT_SYMBOL(can_ethtool_op_get_ts_info_hwts);
374+
325375
/* Common open function when the device gets opened.
326376
*
327377
* This function should be called in the open function of the device

drivers/net/can/dev/skb.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
7272
/* save frame_len to reuse it when transmission is completed */
7373
can_skb_prv(skb)->frame_len = frame_len;
7474

75+
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
76+
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
77+
7578
skb_tx_timestamp(skb);
7679

7780
/* save this skb for tx interrupt echo handling */
@@ -107,6 +110,9 @@ __can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr,
107110
struct can_skb_priv *can_skb_priv = can_skb_prv(skb);
108111
struct canfd_frame *cf = (struct canfd_frame *)skb->data;
109112

113+
if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)
114+
skb_tstamp_tx(skb, skb_hwtstamps(skb));
115+
110116
/* get the real payload length for netdev statistics */
111117
if (cf->can_id & CAN_RTR_FLAG)
112118
*len_ptr = 0;

drivers/net/can/flexcan/flexcan-ethtool.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,5 @@ const struct ethtool_ops flexcan_ethtool_ops = {
106106
.get_priv_flags = flexcan_get_priv_flags,
107107
.set_priv_flags = flexcan_set_priv_flags,
108108
.get_sset_count = flexcan_get_sset_count,
109+
.get_ts_info = ethtool_op_get_ts_info,
109110
};

drivers/net/can/grcan.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/interrupt.h>
2828
#include <linux/netdevice.h>
2929
#include <linux/delay.h>
30+
#include <linux/ethtool.h>
3031
#include <linux/io.h>
3132
#include <linux/can/dev.h>
3233
#include <linux/spinlock.h>
@@ -1561,6 +1562,10 @@ static const struct net_device_ops grcan_netdev_ops = {
15611562
.ndo_change_mtu = can_change_mtu,
15621563
};
15631564

1565+
static const struct ethtool_ops grcan_ethtool_ops = {
1566+
.get_ts_info = ethtool_op_get_ts_info,
1567+
};
1568+
15641569
static int grcan_setup_netdev(struct platform_device *ofdev,
15651570
void __iomem *base,
15661571
int irq, u32 ambafreq, bool txbug)
@@ -1577,6 +1582,7 @@ static int grcan_setup_netdev(struct platform_device *ofdev,
15771582
dev->irq = irq;
15781583
dev->flags |= IFF_ECHO;
15791584
dev->netdev_ops = &grcan_netdev_ops;
1585+
dev->ethtool_ops = &grcan_ethtool_ops;
15801586
dev->sysfs_groups[0] = &sysfs_grcan_group;
15811587

15821588
priv = netdev_priv(dev);

drivers/net/can/ifi_canfd/ifi_canfd.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <linux/clk.h>
1515
#include <linux/delay.h>
16+
#include <linux/ethtool.h>
1617
#include <linux/interrupt.h>
1718
#include <linux/io.h>
1819
#include <linux/kernel.h>
@@ -925,6 +926,10 @@ static const struct net_device_ops ifi_canfd_netdev_ops = {
925926
.ndo_change_mtu = can_change_mtu,
926927
};
927928

929+
static const struct ethtool_ops ifi_canfd_ethtool_ops = {
930+
.get_ts_info = ethtool_op_get_ts_info,
931+
};
932+
928933
static int ifi_canfd_plat_probe(struct platform_device *pdev)
929934
{
930935
struct device *dev = &pdev->dev;
@@ -962,6 +967,7 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev)
962967
ndev->irq = irq;
963968
ndev->flags |= IFF_ECHO; /* we support local echo */
964969
ndev->netdev_ops = &ifi_canfd_netdev_ops;
970+
ndev->ethtool_ops = &ifi_canfd_ethtool_ops;
965971

966972
priv = netdev_priv(ndev);
967973
priv->ndev = ndev;

drivers/net/can/janz-ican3.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/module.h>
1010
#include <linux/interrupt.h>
1111
#include <linux/delay.h>
12+
#include <linux/ethtool.h>
1213
#include <linux/platform_device.h>
1314

1415
#include <linux/netdevice.h>
@@ -1277,6 +1278,8 @@ static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb)
12771278
if (!skb)
12781279
return;
12791280

1281+
skb_tx_timestamp(skb);
1282+
12801283
/* save this skb for tx interrupt echo handling */
12811284
skb_queue_tail(&mod->echoq, skb);
12821285
}
@@ -1752,6 +1755,10 @@ static const struct net_device_ops ican3_netdev_ops = {
17521755
.ndo_change_mtu = can_change_mtu,
17531756
};
17541757

1758+
static const struct ethtool_ops ican3_ethtool_ops = {
1759+
.get_ts_info = ethtool_op_get_ts_info,
1760+
};
1761+
17551762
/*
17561763
* Low-level CAN Device
17571764
*/
@@ -1923,6 +1930,7 @@ static int ican3_probe(struct platform_device *pdev)
19231930
mod->free_page = DPM_FREE_START;
19241931

19251932
ndev->netdev_ops = &ican3_netdev_ops;
1933+
ndev->ethtool_ops = &ican3_ethtool_ops;
19261934
ndev->flags |= IFF_ECHO;
19271935
SET_NETDEV_DEV(ndev, &pdev->dev);
19281936

drivers/net/can/kvaser_pciefd.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/kernel.h>
1010
#include <linux/module.h>
1111
#include <linux/device.h>
12+
#include <linux/ethtool.h>
1213
#include <linux/pci.h>
1314
#include <linux/can/dev.h>
1415
#include <linux/timer.h>
@@ -919,10 +920,15 @@ static void kvaser_pciefd_bec_poll_timer(struct timer_list *data)
919920
static const struct net_device_ops kvaser_pciefd_netdev_ops = {
920921
.ndo_open = kvaser_pciefd_open,
921922
.ndo_stop = kvaser_pciefd_stop,
923+
.ndo_eth_ioctl = can_eth_ioctl_hwts,
922924
.ndo_start_xmit = kvaser_pciefd_start_xmit,
923925
.ndo_change_mtu = can_change_mtu,
924926
};
925927

928+
static const struct ethtool_ops kvaser_pciefd_ethtool_ops = {
929+
.get_ts_info = can_ethtool_op_get_ts_info_hwts,
930+
};
931+
926932
static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
927933
{
928934
int i;
@@ -939,6 +945,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
939945

940946
can = netdev_priv(netdev);
941947
netdev->netdev_ops = &kvaser_pciefd_netdev_ops;
948+
netdev->ethtool_ops = &kvaser_pciefd_ethtool_ops;
942949
can->reg_base = pcie->reg_base + KVASER_PCIEFD_KCAN0_BASE +
943950
i * KVASER_PCIEFD_KCAN_BASE_OFFSET;
944951

drivers/net/can/m_can/m_can.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
#include <linux/bitfield.h>
12+
#include <linux/ethtool.h>
1213
#include <linux/interrupt.h>
1314
#include <linux/io.h>
1415
#include <linux/kernel.h>
@@ -1829,10 +1830,15 @@ static const struct net_device_ops m_can_netdev_ops = {
18291830
.ndo_change_mtu = can_change_mtu,
18301831
};
18311832

1833+
static const struct ethtool_ops m_can_ethtool_ops = {
1834+
.get_ts_info = ethtool_op_get_ts_info,
1835+
};
1836+
18321837
static int register_m_can_dev(struct net_device *dev)
18331838
{
18341839
dev->flags |= IFF_ECHO; /* we support local echo */
18351840
dev->netdev_ops = &m_can_netdev_ops;
1841+
dev->ethtool_ops = &m_can_ethtool_ops;
18361842

18371843
return register_candev(dev);
18381844
}

drivers/net/can/mscan/mscan.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,10 @@ static const struct net_device_ops mscan_netdev_ops = {
616616
.ndo_change_mtu = can_change_mtu,
617617
};
618618

619+
static const struct ethtool_ops mscan_ethtool_ops = {
620+
.get_ts_info = ethtool_op_get_ts_info,
621+
};
622+
619623
int register_mscandev(struct net_device *dev, int mscan_clksrc)
620624
{
621625
struct mscan_priv *priv = netdev_priv(dev);
@@ -676,6 +680,7 @@ struct net_device *alloc_mscandev(void)
676680
priv = netdev_priv(dev);
677681

678682
dev->netdev_ops = &mscan_netdev_ops;
683+
dev->ethtool_ops = &mscan_ethtool_ops;
679684

680685
dev->flags |= IFF_ECHO; /* we support local echo */
681686

drivers/net/can/pch_can.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <linux/interrupt.h>
88
#include <linux/delay.h>
9+
#include <linux/ethtool.h>
910
#include <linux/io.h>
1011
#include <linux/module.h>
1112
#include <linux/sched.h>
@@ -938,6 +939,10 @@ static const struct net_device_ops pch_can_netdev_ops = {
938939
.ndo_change_mtu = can_change_mtu,
939940
};
940941

942+
static const struct ethtool_ops pch_can_ethtool_ops = {
943+
.get_ts_info = ethtool_op_get_ts_info,
944+
};
945+
941946
static void pch_can_remove(struct pci_dev *pdev)
942947
{
943948
struct net_device *ndev = pci_get_drvdata(pdev);
@@ -1188,6 +1193,7 @@ static int pch_can_probe(struct pci_dev *pdev,
11881193
pci_set_drvdata(pdev, ndev);
11891194
SET_NETDEV_DEV(ndev, &pdev->dev);
11901195
ndev->netdev_ops = &pch_can_netdev_ops;
1196+
ndev->ethtool_ops = &pch_can_ethtool_ops;
11911197
priv->can.clock.freq = PCH_CAN_CLK; /* Hz */
11921198

11931199
netif_napi_add_weight(ndev, &priv->napi, pch_can_poll, PCH_RX_OBJ_END);

0 commit comments

Comments
 (0)