Commit 12a18d79 authored by Marc Kleine-Budde's avatar Marc Kleine-Budde

Merge patch series "can: add ethtool support and reporting of timestamping capabilities"

Vincent Mailhol <mailhol.vincent@wanadoo.fr> 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/20220725134345.432367-1-mailhol.vincent@wanadoo.fr/T/

* Changelog *

changes since v3: https://lore.kernel.org/all/20220726102454.95096-1-mailhol.vincent@wanadoo.fr

  * 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/20220725155354.482986-1-mailhol.vincent@wanadoo.fr

  * 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/20220725133208.432176-1-mailhol.vincent@wanadoo.fr

  * 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/20220725153124.467061-1-mailhol.vincent@wanadoo.fr/T/#u

====================

Link: https://lore.kernel.org/all/20220727101641.198847-1-mailhol.vincent@wanadoo.frSigned-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parents 7c862ee9 bedd9483
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -1152,6 +1153,10 @@ static const struct net_device_ops at91_netdev_ops = { ...@@ -1152,6 +1153,10 @@ static const struct net_device_ops at91_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops at91_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static ssize_t mb0_id_show(struct device *dev, static ssize_t mb0_id_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
...@@ -1293,6 +1298,7 @@ static int at91_can_probe(struct platform_device *pdev) ...@@ -1293,6 +1298,7 @@ static int at91_can_probe(struct platform_device *pdev)
} }
dev->netdev_ops = &at91_netdev_ops; dev->netdev_ops = &at91_netdev_ops;
dev->ethtool_ops = &at91_ethtool_ops;
dev->irq = irq; dev->irq = irq;
dev->flags |= IFF_ECHO; dev->flags |= IFF_ECHO;
......
...@@ -26,4 +26,5 @@ static void c_can_get_ringparam(struct net_device *netdev, ...@@ -26,4 +26,5 @@ static void c_can_get_ringparam(struct net_device *netdev,
const struct ethtool_ops c_can_ethtool_ops = { const struct ethtool_ops c_can_ethtool_ops = {
.get_ringparam = c_can_get_ringparam, .get_ringparam = c_can_get_ringparam,
.get_ts_info = ethtool_op_get_ts_info,
}; };
...@@ -836,6 +836,8 @@ static netdev_tx_t can327_netdev_start_xmit(struct sk_buff *skb, ...@@ -836,6 +836,8 @@ static netdev_tx_t can327_netdev_start_xmit(struct sk_buff *skb,
dev->stats.tx_packets++; dev->stats.tx_packets++;
dev->stats.tx_bytes += frame->can_id & CAN_RTR_FLAG ? 0 : frame->len; dev->stats.tx_bytes += frame->can_id & CAN_RTR_FLAG ? 0 : frame->len;
skb_tx_timestamp(skb);
out: out:
kfree_skb(skb); kfree_skb(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -848,6 +850,10 @@ static const struct net_device_ops can327_netdev_ops = { ...@@ -848,6 +850,10 @@ static const struct net_device_ops can327_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops can327_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static bool can327_is_valid_rx_char(u8 c) static bool can327_is_valid_rx_char(u8 c)
{ {
static const bool lut_char_is_valid['z'] = { static const bool lut_char_is_valid['z'] = {
...@@ -1032,6 +1038,7 @@ static int can327_ldisc_open(struct tty_struct *tty) ...@@ -1032,6 +1038,7 @@ static int can327_ldisc_open(struct tty_struct *tty)
/* Configure netdev interface */ /* Configure netdev interface */
elm->dev = dev; elm->dev = dev;
dev->netdev_ops = &can327_netdev_ops; dev->netdev_ops = &can327_netdev_ops;
dev->ethtool_ops = &can327_ethtool_ops;
/* Mark ldisc channel as alive */ /* Mark ldisc channel as alive */
elm->tty = tty; elm->tty = tty;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
...@@ -836,6 +837,10 @@ static const struct net_device_ops cc770_netdev_ops = { ...@@ -836,6 +837,10 @@ static const struct net_device_ops cc770_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops cc770_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
int register_cc770dev(struct net_device *dev) int register_cc770dev(struct net_device *dev)
{ {
struct cc770_priv *priv = netdev_priv(dev); struct cc770_priv *priv = netdev_priv(dev);
...@@ -846,6 +851,7 @@ int register_cc770dev(struct net_device *dev) ...@@ -846,6 +851,7 @@ int register_cc770dev(struct net_device *dev)
return err; return err;
dev->netdev_ops = &cc770_netdev_ops; dev->netdev_ops = &cc770_netdev_ops;
dev->ethtool_ops = &cc770_ethtool_ops;
dev->flags |= IFF_ECHO; /* we support local echo */ dev->flags |= IFF_ECHO; /* we support local echo */
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -1301,6 +1302,10 @@ static const struct net_device_ops ctucan_netdev_ops = { ...@@ -1301,6 +1302,10 @@ static const struct net_device_ops ctucan_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops ctucan_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
int ctucan_suspend(struct device *dev) int ctucan_suspend(struct device *dev)
{ {
struct net_device *ndev = dev_get_drvdata(dev); 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 ...@@ -1377,6 +1382,7 @@ int ctucan_probe_common(struct device *dev, void __iomem *addr, int irq, unsigne
set_drvdata_fnc(dev, ndev); set_drvdata_fnc(dev, ndev);
SET_NETDEV_DEV(ndev, dev); SET_NETDEV_DEV(ndev, dev);
ndev->netdev_ops = &ctucan_netdev_ops; ndev->netdev_ops = &ctucan_netdev_ops;
ndev->ethtool_ops = &ctucan_ethtool_ops;
/* Getting the can_clk info */ /* Getting the can_clk info */
if (!can_clk_rate) { if (!can_clk_rate) {
......
...@@ -322,6 +322,56 @@ int can_change_mtu(struct net_device *dev, int new_mtu) ...@@ -322,6 +322,56 @@ int can_change_mtu(struct net_device *dev, int new_mtu)
} }
EXPORT_SYMBOL_GPL(can_change_mtu); EXPORT_SYMBOL_GPL(can_change_mtu);
/* generic implementation of netdev_ops::ndo_eth_ioctl for CAN devices
* supporting hardware timestamps
*/
int can_eth_ioctl_hwts(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
struct hwtstamp_config hwts_cfg = { 0 };
switch (cmd) {
case SIOCSHWTSTAMP: /* set */
if (copy_from_user(&hwts_cfg, ifr->ifr_data, sizeof(hwts_cfg)))
return -EFAULT;
if (hwts_cfg.tx_type == HWTSTAMP_TX_ON &&
hwts_cfg.rx_filter == HWTSTAMP_FILTER_ALL)
return 0;
return -ERANGE;
case SIOCGHWTSTAMP: /* get */
hwts_cfg.tx_type = HWTSTAMP_TX_ON;
hwts_cfg.rx_filter = HWTSTAMP_FILTER_ALL;
if (copy_to_user(ifr->ifr_data, &hwts_cfg, sizeof(hwts_cfg)))
return -EFAULT;
return 0;
default:
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL(can_eth_ioctl_hwts);
/* generic implementation of ethtool_ops::get_ts_info for CAN devices
* supporting hardware timestamps
*/
int can_ethtool_op_get_ts_info_hwts(struct net_device *dev,
struct ethtool_ts_info *info)
{
info->so_timestamping =
SOF_TIMESTAMPING_TX_SOFTWARE |
SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
info->phc_index = -1;
info->tx_types = BIT(HWTSTAMP_TX_ON);
info->rx_filters = BIT(HWTSTAMP_FILTER_ALL);
return 0;
}
EXPORT_SYMBOL(can_ethtool_op_get_ts_info_hwts);
/* Common open function when the device gets opened. /* Common open function when the device gets opened.
* *
* This function should be called in the open function of the device * This function should be called in the open function of the device
......
...@@ -72,6 +72,9 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, ...@@ -72,6 +72,9 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
/* save frame_len to reuse it when transmission is completed */ /* save frame_len to reuse it when transmission is completed */
can_skb_prv(skb)->frame_len = frame_len; can_skb_prv(skb)->frame_len = frame_len;
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
/* save this skb for tx interrupt echo handling */ /* 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, ...@@ -107,6 +110,9 @@ __can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr,
struct can_skb_priv *can_skb_priv = can_skb_prv(skb); struct can_skb_priv *can_skb_priv = can_skb_prv(skb);
struct canfd_frame *cf = (struct canfd_frame *)skb->data; struct canfd_frame *cf = (struct canfd_frame *)skb->data;
if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)
skb_tstamp_tx(skb, skb_hwtstamps(skb));
/* get the real payload length for netdev statistics */ /* get the real payload length for netdev statistics */
if (cf->can_id & CAN_RTR_FLAG) if (cf->can_id & CAN_RTR_FLAG)
*len_ptr = 0; *len_ptr = 0;
......
...@@ -106,4 +106,5 @@ const struct ethtool_ops flexcan_ethtool_ops = { ...@@ -106,4 +106,5 @@ const struct ethtool_ops flexcan_ethtool_ops = {
.get_priv_flags = flexcan_get_priv_flags, .get_priv_flags = flexcan_get_priv_flags,
.set_priv_flags = flexcan_set_priv_flags, .set_priv_flags = flexcan_set_priv_flags,
.get_sset_count = flexcan_get_sset_count, .get_sset_count = flexcan_get_sset_count,
.get_ts_info = ethtool_op_get_ts_info,
}; };
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
...@@ -1561,6 +1562,10 @@ static const struct net_device_ops grcan_netdev_ops = { ...@@ -1561,6 +1562,10 @@ static const struct net_device_ops grcan_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops grcan_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static int grcan_setup_netdev(struct platform_device *ofdev, static int grcan_setup_netdev(struct platform_device *ofdev,
void __iomem *base, void __iomem *base,
int irq, u32 ambafreq, bool txbug) int irq, u32 ambafreq, bool txbug)
...@@ -1577,6 +1582,7 @@ static int grcan_setup_netdev(struct platform_device *ofdev, ...@@ -1577,6 +1582,7 @@ static int grcan_setup_netdev(struct platform_device *ofdev,
dev->irq = irq; dev->irq = irq;
dev->flags |= IFF_ECHO; dev->flags |= IFF_ECHO;
dev->netdev_ops = &grcan_netdev_ops; dev->netdev_ops = &grcan_netdev_ops;
dev->ethtool_ops = &grcan_ethtool_ops;
dev->sysfs_groups[0] = &sysfs_grcan_group; dev->sysfs_groups[0] = &sysfs_grcan_group;
priv = netdev_priv(dev); priv = netdev_priv(dev);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -925,6 +926,10 @@ static const struct net_device_ops ifi_canfd_netdev_ops = { ...@@ -925,6 +926,10 @@ static const struct net_device_ops ifi_canfd_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops ifi_canfd_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static int ifi_canfd_plat_probe(struct platform_device *pdev) static int ifi_canfd_plat_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -962,6 +967,7 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) ...@@ -962,6 +967,7 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev)
ndev->irq = irq; ndev->irq = irq;
ndev->flags |= IFF_ECHO; /* we support local echo */ ndev->flags |= IFF_ECHO; /* we support local echo */
ndev->netdev_ops = &ifi_canfd_netdev_ops; ndev->netdev_ops = &ifi_canfd_netdev_ops;
ndev->ethtool_ops = &ifi_canfd_ethtool_ops;
priv = netdev_priv(ndev); priv = netdev_priv(ndev);
priv->ndev = ndev; priv->ndev = ndev;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -1277,6 +1278,8 @@ static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb) ...@@ -1277,6 +1278,8 @@ static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb)
if (!skb) if (!skb)
return; return;
skb_tx_timestamp(skb);
/* save this skb for tx interrupt echo handling */ /* save this skb for tx interrupt echo handling */
skb_queue_tail(&mod->echoq, skb); skb_queue_tail(&mod->echoq, skb);
} }
...@@ -1752,6 +1755,10 @@ static const struct net_device_ops ican3_netdev_ops = { ...@@ -1752,6 +1755,10 @@ static const struct net_device_ops ican3_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops ican3_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
/* /*
* Low-level CAN Device * Low-level CAN Device
*/ */
...@@ -1923,6 +1930,7 @@ static int ican3_probe(struct platform_device *pdev) ...@@ -1923,6 +1930,7 @@ static int ican3_probe(struct platform_device *pdev)
mod->free_page = DPM_FREE_START; mod->free_page = DPM_FREE_START;
ndev->netdev_ops = &ican3_netdev_ops; ndev->netdev_ops = &ican3_netdev_ops;
ndev->ethtool_ops = &ican3_ethtool_ops;
ndev->flags |= IFF_ECHO; ndev->flags |= IFF_ECHO;
SET_NETDEV_DEV(ndev, &pdev->dev); SET_NETDEV_DEV(ndev, &pdev->dev);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/ethtool.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/timer.h> #include <linux/timer.h>
...@@ -919,10 +920,15 @@ static void kvaser_pciefd_bec_poll_timer(struct timer_list *data) ...@@ -919,10 +920,15 @@ static void kvaser_pciefd_bec_poll_timer(struct timer_list *data)
static const struct net_device_ops kvaser_pciefd_netdev_ops = { static const struct net_device_ops kvaser_pciefd_netdev_ops = {
.ndo_open = kvaser_pciefd_open, .ndo_open = kvaser_pciefd_open,
.ndo_stop = kvaser_pciefd_stop, .ndo_stop = kvaser_pciefd_stop,
.ndo_eth_ioctl = can_eth_ioctl_hwts,
.ndo_start_xmit = kvaser_pciefd_start_xmit, .ndo_start_xmit = kvaser_pciefd_start_xmit,
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops kvaser_pciefd_ethtool_ops = {
.get_ts_info = can_ethtool_op_get_ts_info_hwts,
};
static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
{ {
int i; int i;
...@@ -939,6 +945,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) ...@@ -939,6 +945,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
can = netdev_priv(netdev); can = netdev_priv(netdev);
netdev->netdev_ops = &kvaser_pciefd_netdev_ops; netdev->netdev_ops = &kvaser_pciefd_netdev_ops;
netdev->ethtool_ops = &kvaser_pciefd_ethtool_ops;
can->reg_base = pcie->reg_base + KVASER_PCIEFD_KCAN0_BASE + can->reg_base = pcie->reg_base + KVASER_PCIEFD_KCAN0_BASE +
i * KVASER_PCIEFD_KCAN_BASE_OFFSET; i * KVASER_PCIEFD_KCAN_BASE_OFFSET;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
*/ */
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/ethtool.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -1829,10 +1830,15 @@ static const struct net_device_ops m_can_netdev_ops = { ...@@ -1829,10 +1830,15 @@ static const struct net_device_ops m_can_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops m_can_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static int register_m_can_dev(struct net_device *dev) static int register_m_can_dev(struct net_device *dev)
{ {
dev->flags |= IFF_ECHO; /* we support local echo */ dev->flags |= IFF_ECHO; /* we support local echo */
dev->netdev_ops = &m_can_netdev_ops; dev->netdev_ops = &m_can_netdev_ops;
dev->ethtool_ops = &m_can_ethtool_ops;
return register_candev(dev); return register_candev(dev);
} }
......
...@@ -616,6 +616,10 @@ static const struct net_device_ops mscan_netdev_ops = { ...@@ -616,6 +616,10 @@ static const struct net_device_ops mscan_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops mscan_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
int register_mscandev(struct net_device *dev, int mscan_clksrc) int register_mscandev(struct net_device *dev, int mscan_clksrc)
{ {
struct mscan_priv *priv = netdev_priv(dev); struct mscan_priv *priv = netdev_priv(dev);
...@@ -676,6 +680,7 @@ struct net_device *alloc_mscandev(void) ...@@ -676,6 +680,7 @@ struct net_device *alloc_mscandev(void)
priv = netdev_priv(dev); priv = netdev_priv(dev);
dev->netdev_ops = &mscan_netdev_ops; dev->netdev_ops = &mscan_netdev_ops;
dev->ethtool_ops = &mscan_ethtool_ops;
dev->flags |= IFF_ECHO; /* we support local echo */ dev->flags |= IFF_ECHO; /* we support local echo */
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -938,6 +939,10 @@ static const struct net_device_ops pch_can_netdev_ops = { ...@@ -938,6 +939,10 @@ static const struct net_device_ops pch_can_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops pch_can_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static void pch_can_remove(struct pci_dev *pdev) static void pch_can_remove(struct pci_dev *pdev)
{ {
struct net_device *ndev = pci_get_drvdata(pdev); struct net_device *ndev = pci_get_drvdata(pdev);
...@@ -1188,6 +1193,7 @@ static int pch_can_probe(struct pci_dev *pdev, ...@@ -1188,6 +1193,7 @@ static int pch_can_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, ndev); pci_set_drvdata(pdev, ndev);
SET_NETDEV_DEV(ndev, &pdev->dev); SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->netdev_ops = &pch_can_netdev_ops; ndev->netdev_ops = &pch_can_netdev_ops;
ndev->ethtool_ops = &pch_can_ethtool_ops;
priv->can.clock.freq = PCH_CAN_CLK; /* Hz */ priv->can.clock.freq = PCH_CAN_CLK; /* Hz */
netif_napi_add_weight(ndev, &priv->napi, pch_can_poll, PCH_RX_OBJ_END); netif_napi_add_weight(ndev, &priv->napi, pch_can_poll, PCH_RX_OBJ_END);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/ethtool.h>
#include "peak_canfd_user.h" #include "peak_canfd_user.h"
...@@ -742,13 +743,59 @@ static netdev_tx_t peak_canfd_start_xmit(struct sk_buff *skb, ...@@ -742,13 +743,59 @@ static netdev_tx_t peak_canfd_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
static int peak_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
struct hwtstamp_config hwts_cfg = { 0 };
switch (cmd) {
case SIOCSHWTSTAMP: /* set */
if (copy_from_user(&hwts_cfg, ifr->ifr_data, sizeof(hwts_cfg)))
return -EFAULT;
if (hwts_cfg.tx_type == HWTSTAMP_TX_OFF &&
hwts_cfg.rx_filter == HWTSTAMP_FILTER_ALL)
return 0;
return -ERANGE;
case SIOCGHWTSTAMP: /* get */
hwts_cfg.tx_type = HWTSTAMP_TX_OFF;
hwts_cfg.rx_filter = HWTSTAMP_FILTER_ALL;
if (copy_to_user(ifr->ifr_data, &hwts_cfg, sizeof(hwts_cfg)))
return -EFAULT;
return 0;
default:
return -EOPNOTSUPP;
}
}
static const struct net_device_ops peak_canfd_netdev_ops = { static const struct net_device_ops peak_canfd_netdev_ops = {
.ndo_open = peak_canfd_open, .ndo_open = peak_canfd_open,
.ndo_stop = peak_canfd_close, .ndo_stop = peak_canfd_close,
.ndo_eth_ioctl = peak_eth_ioctl,
.ndo_start_xmit = peak_canfd_start_xmit, .ndo_start_xmit = peak_canfd_start_xmit,
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static int peak_get_ts_info(struct net_device *dev,
struct ethtool_ts_info *info)
{
info->so_timestamping =
SOF_TIMESTAMPING_TX_SOFTWARE |
SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
info->phc_index = -1;
info->tx_types = BIT(HWTSTAMP_TX_OFF);
info->rx_filters = BIT(HWTSTAMP_FILTER_ALL);
return 0;
}
static const struct ethtool_ops peak_canfd_ethtool_ops = {
.get_ts_info = peak_get_ts_info,
};
struct net_device *alloc_peak_canfd_dev(int sizeof_priv, int index, struct net_device *alloc_peak_canfd_dev(int sizeof_priv, int index,
int echo_skb_max) int echo_skb_max)
{ {
...@@ -789,6 +836,7 @@ struct net_device *alloc_peak_canfd_dev(int sizeof_priv, int index, ...@@ -789,6 +836,7 @@ struct net_device *alloc_peak_canfd_dev(int sizeof_priv, int index,
ndev->flags |= IFF_ECHO; ndev->flags |= IFF_ECHO;
ndev->netdev_ops = &peak_canfd_netdev_ops; ndev->netdev_ops = &peak_canfd_netdev_ops;
ndev->ethtool_ops = &peak_canfd_ethtool_ops;
ndev->dev_id = index; ndev->dev_id = index;
return ndev; return ndev;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -630,6 +631,10 @@ static const struct net_device_ops rcar_can_netdev_ops = { ...@@ -630,6 +631,10 @@ static const struct net_device_ops rcar_can_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops rcar_can_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static void rcar_can_rx_pkt(struct rcar_can_priv *priv) static void rcar_can_rx_pkt(struct rcar_can_priv *priv)
{ {
struct net_device_stats *stats = &priv->ndev->stats; struct net_device_stats *stats = &priv->ndev->stats;
...@@ -785,6 +790,7 @@ static int rcar_can_probe(struct platform_device *pdev) ...@@ -785,6 +790,7 @@ static int rcar_can_probe(struct platform_device *pdev)
} }
ndev->netdev_ops = &rcar_can_netdev_ops; ndev->netdev_ops = &rcar_can_netdev_ops;
ndev->ethtool_ops = &rcar_can_ethtool_ops;
ndev->irq = irq; ndev->irq = irq;
ndev->flags |= IFF_ECHO; ndev->flags |= IFF_ECHO;
priv->ndev = ndev; priv->ndev = ndev;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -1695,6 +1696,10 @@ static const struct net_device_ops rcar_canfd_netdev_ops = { ...@@ -1695,6 +1696,10 @@ static const struct net_device_ops rcar_canfd_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops rcar_canfd_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
u32 fcan_freq) u32 fcan_freq)
{ {
...@@ -1711,6 +1716,7 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, ...@@ -1711,6 +1716,7 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
priv = netdev_priv(ndev); priv = netdev_priv(ndev);
ndev->netdev_ops = &rcar_canfd_netdev_ops; ndev->netdev_ops = &rcar_canfd_netdev_ops;
ndev->ethtool_ops = &rcar_canfd_ethtool_ops;
ndev->flags |= IFF_ECHO; ndev->flags |= IFF_ECHO;
priv->ndev = ndev; priv->ndev = ndev;
priv->base = gpriv->base; priv->base = gpriv->base;
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
...@@ -654,6 +655,10 @@ static const struct net_device_ops sja1000_netdev_ops = { ...@@ -654,6 +655,10 @@ static const struct net_device_ops sja1000_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops sja1000_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
int register_sja1000dev(struct net_device *dev) int register_sja1000dev(struct net_device *dev)
{ {
int ret; int ret;
...@@ -663,6 +668,7 @@ int register_sja1000dev(struct net_device *dev) ...@@ -663,6 +668,7 @@ int register_sja1000dev(struct net_device *dev)
dev->flags |= IFF_ECHO; /* we support local echo */ dev->flags |= IFF_ECHO; /* we support local echo */
dev->netdev_ops = &sja1000_netdev_ops; dev->netdev_ops = &sja1000_netdev_ops;
dev->ethtool_ops = &sja1000_ethtool_ops;
set_reset_mode(dev); set_reset_mode(dev);
chipset_init(dev); chipset_init(dev);
......
...@@ -612,6 +612,8 @@ static netdev_tx_t slcan_netdev_xmit(struct sk_buff *skb, ...@@ -612,6 +612,8 @@ static netdev_tx_t slcan_netdev_xmit(struct sk_buff *skb,
slcan_encaps(sl, (struct can_frame *)skb->data); /* encaps & send */ slcan_encaps(sl, (struct can_frame *)skb->data); /* encaps & send */
spin_unlock(&sl->lock); spin_unlock(&sl->lock);
skb_tx_timestamp(skb);
out: out:
kfree_skb(skb); kfree_skb(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
......
...@@ -57,4 +57,5 @@ const struct ethtool_ops slcan_ethtool_ops = { ...@@ -57,4 +57,5 @@ const struct ethtool_ops slcan_ethtool_ops = {
.get_priv_flags = slcan_get_priv_flags, .get_priv_flags = slcan_get_priv_flags,
.set_priv_flags = slcan_set_priv_flags, .set_priv_flags = slcan_set_priv_flags,
.get_sset_count = slcan_get_sset_count, .get_sset_count = slcan_get_sset_count,
.get_ts_info = ethtool_op_get_ts_info,
}; };
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* - Kurt Van Dijck, EIA Electronics * - Kurt Van Dijck, EIA Electronics
*/ */
#include <linux/ethtool.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -611,6 +612,10 @@ static const struct net_device_ops softing_netdev_ops = { ...@@ -611,6 +612,10 @@ static const struct net_device_ops softing_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops softing_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static const struct can_bittiming_const softing_btr_const = { static const struct can_bittiming_const softing_btr_const = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.tseg1_min = 1, .tseg1_min = 1,
...@@ -649,6 +654,7 @@ static struct net_device *softing_netdev_create(struct softing *card, ...@@ -649,6 +654,7 @@ static struct net_device *softing_netdev_create(struct softing *card,
netdev->flags |= IFF_ECHO; netdev->flags |= IFF_ECHO;
netdev->netdev_ops = &softing_netdev_ops; netdev->netdev_ops = &softing_netdev_ops;
netdev->ethtool_ops = &softing_ethtool_ops;
priv->can.do_set_mode = softing_candev_set_mode; priv->can.do_set_mode = softing_candev_set_mode;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/ethtool.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -802,6 +803,10 @@ static const struct net_device_ops hi3110_netdev_ops = { ...@@ -802,6 +803,10 @@ static const struct net_device_ops hi3110_netdev_ops = {
.ndo_start_xmit = hi3110_hard_start_xmit, .ndo_start_xmit = hi3110_hard_start_xmit,
}; };
static const struct ethtool_ops hi3110_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static const struct of_device_id hi3110_of_match[] = { static const struct of_device_id hi3110_of_match[] = {
{ {
.compatible = "holt,hi3110", .compatible = "holt,hi3110",
...@@ -856,6 +861,7 @@ static int hi3110_can_probe(struct spi_device *spi) ...@@ -856,6 +861,7 @@ static int hi3110_can_probe(struct spi_device *spi)
goto out_free; goto out_free;
net->netdev_ops = &hi3110_netdev_ops; net->netdev_ops = &hi3110_netdev_ops;
net->ethtool_ops = &hi3110_ethtool_ops;
net->flags |= IFF_ECHO; net->flags |= IFF_ECHO;
priv = netdev_priv(net); priv = netdev_priv(net);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/ethtool.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
...@@ -1248,6 +1249,10 @@ static const struct net_device_ops mcp251x_netdev_ops = { ...@@ -1248,6 +1249,10 @@ static const struct net_device_ops mcp251x_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops mcp251x_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static const struct of_device_id mcp251x_of_match[] = { static const struct of_device_id mcp251x_of_match[] = {
{ {
.compatible = "microchip,mcp2510", .compatible = "microchip,mcp2510",
...@@ -1313,6 +1318,7 @@ static int mcp251x_can_probe(struct spi_device *spi) ...@@ -1313,6 +1318,7 @@ static int mcp251x_can_probe(struct spi_device *spi)
goto out_free; goto out_free;
net->netdev_ops = &mcp251x_netdev_ops; net->netdev_ops = &mcp251x_netdev_ops;
net->ethtool_ops = &mcp251x_ethtool_ops;
net->flags |= IFF_ECHO; net->flags |= IFF_ECHO;
priv = netdev_priv(net); priv = netdev_priv(net);
......
...@@ -1671,6 +1671,7 @@ static const struct net_device_ops mcp251xfd_netdev_ops = { ...@@ -1671,6 +1671,7 @@ static const struct net_device_ops mcp251xfd_netdev_ops = {
.ndo_open = mcp251xfd_open, .ndo_open = mcp251xfd_open,
.ndo_stop = mcp251xfd_stop, .ndo_stop = mcp251xfd_stop,
.ndo_start_xmit = mcp251xfd_start_xmit, .ndo_start_xmit = mcp251xfd_start_xmit,
.ndo_eth_ioctl = can_eth_ioctl_hwts,
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
......
...@@ -124,6 +124,7 @@ static const struct ethtool_ops mcp251xfd_ethtool_ops = { ...@@ -124,6 +124,7 @@ static const struct ethtool_ops mcp251xfd_ethtool_ops = {
.set_ringparam = mcp251xfd_ring_set_ringparam, .set_ringparam = mcp251xfd_ring_set_ringparam,
.get_coalesce = mcp251xfd_ring_get_coalesce, .get_coalesce = mcp251xfd_ring_get_coalesce,
.set_coalesce = mcp251xfd_ring_set_coalesce, .set_coalesce = mcp251xfd_ring_set_coalesce,
.get_ts_info = can_ethtool_op_get_ts_info_hwts,
}; };
void mcp251xfd_ethtool_init(struct mcp251xfd_priv *priv) void mcp251xfd_ethtool_init(struct mcp251xfd_priv *priv)
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -761,6 +762,10 @@ static const struct net_device_ops sun4ican_netdev_ops = { ...@@ -761,6 +762,10 @@ static const struct net_device_ops sun4ican_netdev_ops = {
.ndo_start_xmit = sun4ican_start_xmit, .ndo_start_xmit = sun4ican_start_xmit,
}; };
static const struct ethtool_ops sun4ican_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static const struct sun4ican_quirks sun4ican_quirks_a10 = { static const struct sun4ican_quirks sun4ican_quirks_a10 = {
.has_reset = false, .has_reset = false,
}; };
...@@ -851,6 +856,7 @@ static int sun4ican_probe(struct platform_device *pdev) ...@@ -851,6 +856,7 @@ static int sun4ican_probe(struct platform_device *pdev)
} }
dev->netdev_ops = &sun4ican_netdev_ops; dev->netdev_ops = &sun4ican_netdev_ops;
dev->ethtool_ops = &sun4ican_ethtool_ops;
dev->irq = irq; dev->irq = irq;
dev->flags |= IFF_ECHO; dev->flags |= IFF_ECHO;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -841,6 +842,10 @@ static const struct net_device_ops ti_hecc_netdev_ops = { ...@@ -841,6 +842,10 @@ static const struct net_device_ops ti_hecc_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops ti_hecc_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static const struct of_device_id ti_hecc_dt_ids[] = { static const struct of_device_id ti_hecc_dt_ids[] = {
{ {
.compatible = "ti,am3517-hecc", .compatible = "ti,am3517-hecc",
...@@ -918,6 +923,7 @@ static int ti_hecc_probe(struct platform_device *pdev) ...@@ -918,6 +923,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ndev); platform_set_drvdata(pdev, ndev);
SET_NETDEV_DEV(ndev, &pdev->dev); SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->netdev_ops = &ti_hecc_netdev_ops; ndev->netdev_ops = &ti_hecc_netdev_ops;
ndev->ethtool_ops = &ti_hecc_ethtool_ops;
priv->clk = clk_get(&pdev->dev, "hecc_ck"); priv->clk = clk_get(&pdev->dev, "hecc_ck");
if (IS_ERR(priv->clk)) { if (IS_ERR(priv->clk)) {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* *
* Copyright (C) 2004-2009 EMS Dr. Thomas Wuensche * Copyright (C) 2004-2009 EMS Dr. Thomas Wuensche
*/ */
#include <linux/ethtool.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -879,6 +880,10 @@ static const struct net_device_ops ems_usb_netdev_ops = { ...@@ -879,6 +880,10 @@ static const struct net_device_ops ems_usb_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops ems_usb_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static const struct can_bittiming_const ems_usb_bittiming_const = { static const struct can_bittiming_const ems_usb_bittiming_const = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.tseg1_min = 1, .tseg1_min = 1,
...@@ -990,6 +995,7 @@ static int ems_usb_probe(struct usb_interface *intf, ...@@ -990,6 +995,7 @@ static int ems_usb_probe(struct usb_interface *intf,
dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
netdev->netdev_ops = &ems_usb_netdev_ops; netdev->netdev_ops = &ems_usb_netdev_ops;
netdev->ethtool_ops = &ems_usb_ethtool_ops;
netdev->flags |= IFF_ECHO; /* we support local echo */ netdev->flags |= IFF_ECHO; /* we support local echo */
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs <socketcan@esd.eu> * Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs <socketcan@esd.eu>
* Copyright (C) 2022 esd electronics gmbh, Frank Jungclaus <frank.jungclaus@esd.eu> * Copyright (C) 2022 esd electronics gmbh, Frank Jungclaus <frank.jungclaus@esd.eu>
*/ */
#include <linux/ethtool.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -882,6 +883,10 @@ static const struct net_device_ops esd_usb_netdev_ops = { ...@@ -882,6 +883,10 @@ static const struct net_device_ops esd_usb_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops esd_usb_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static const struct can_bittiming_const esd_usb2_bittiming_const = { static const struct can_bittiming_const esd_usb2_bittiming_const = {
.name = "esd_usb2", .name = "esd_usb2",
.tseg1_min = ESD_USB2_TSEG1_MIN, .tseg1_min = ESD_USB2_TSEG1_MIN,
...@@ -1015,6 +1020,7 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index) ...@@ -1015,6 +1020,7 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index)
netdev->flags |= IFF_ECHO; /* we support local echo */ netdev->flags |= IFF_ECHO; /* we support local echo */
netdev->netdev_ops = &esd_usb_netdev_ops; netdev->netdev_ops = &esd_usb_netdev_ops;
netdev->ethtool_ops = &esd_usb_ethtool_ops;
SET_NETDEV_DEV(netdev, &intf->dev); SET_NETDEV_DEV(netdev, &intf->dev);
netdev->dev_id = index; netdev->dev_id = index;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr> * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
*/ */
#include <linux/ethtool.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb.h> #include <linux/usb.h>
...@@ -1978,7 +1979,12 @@ static netdev_tx_t es58x_start_xmit(struct sk_buff *skb, ...@@ -1978,7 +1979,12 @@ static netdev_tx_t es58x_start_xmit(struct sk_buff *skb,
static const struct net_device_ops es58x_netdev_ops = { static const struct net_device_ops es58x_netdev_ops = {
.ndo_open = es58x_open, .ndo_open = es58x_open,
.ndo_stop = es58x_stop, .ndo_stop = es58x_stop,
.ndo_start_xmit = es58x_start_xmit .ndo_start_xmit = es58x_start_xmit,
.ndo_eth_ioctl = can_eth_ioctl_hwts,
};
static const struct ethtool_ops es58x_ethtool_ops = {
.get_ts_info = can_ethtool_op_get_ts_info_hwts,
}; };
/** /**
...@@ -2085,6 +2091,7 @@ static int es58x_init_netdev(struct es58x_device *es58x_dev, int channel_idx) ...@@ -2085,6 +2091,7 @@ static int es58x_init_netdev(struct es58x_device *es58x_dev, int channel_idx)
es58x_init_priv(es58x_dev, es58x_priv(netdev), channel_idx); es58x_init_priv(es58x_dev, es58x_priv(netdev), channel_idx);
netdev->netdev_ops = &es58x_netdev_ops; netdev->netdev_ops = &es58x_netdev_ops;
netdev->ethtool_ops = &es58x_ethtool_ops;
netdev->flags |= IFF_ECHO; /* We support local echo */ netdev->flags |= IFF_ECHO; /* We support local echo */
netdev->dev_port = channel_idx; netdev->dev_port = channel_idx;
......
...@@ -946,6 +946,7 @@ static int gs_usb_set_phys_id(struct net_device *dev, ...@@ -946,6 +946,7 @@ static int gs_usb_set_phys_id(struct net_device *dev,
static const struct ethtool_ops gs_usb_ethtool_ops = { static const struct ethtool_ops gs_usb_ethtool_ops = {
.set_phys_id = gs_usb_set_phys_id, .set_phys_id = gs_usb_set_phys_id,
.get_ts_info = ethtool_op_get_ts_info,
}; };
static struct gs_can *gs_make_candev(unsigned int channel, static struct gs_can *gs_make_candev(unsigned int channel,
...@@ -989,6 +990,7 @@ static struct gs_can *gs_make_candev(unsigned int channel, ...@@ -989,6 +990,7 @@ static struct gs_can *gs_make_candev(unsigned int channel,
dev = netdev_priv(netdev); dev = netdev_priv(netdev);
netdev->netdev_ops = &gs_usb_netdev_ops; netdev->netdev_ops = &gs_usb_netdev_ops;
netdev->ethtool_ops = &gs_usb_ethtool_ops;
netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */ netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define KVASER_USB_QUIRK_HAS_SILENT_MODE BIT(0) #define KVASER_USB_QUIRK_HAS_SILENT_MODE BIT(0)
#define KVASER_USB_QUIRK_HAS_TXRX_ERRORS BIT(1) #define KVASER_USB_QUIRK_HAS_TXRX_ERRORS BIT(1)
#define KVASER_USB_QUIRK_IGNORE_CLK_FREQ BIT(2) #define KVASER_USB_QUIRK_IGNORE_CLK_FREQ BIT(2)
#define KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP BIT(3)
/* Device capabilities */ /* Device capabilities */
#define KVASER_USB_CAP_BERR_CAP 0x01 #define KVASER_USB_CAP_BERR_CAP 0x01
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/ethtool.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/if.h> #include <linux/if.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -89,7 +90,7 @@ ...@@ -89,7 +90,7 @@
#define USB_HYBRID_PRO_CANLIN_PRODUCT_ID 278 #define USB_HYBRID_PRO_CANLIN_PRODUCT_ID 278
static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = { static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = {
.quirks = 0, .quirks = KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP,
.ops = &kvaser_usb_hydra_dev_ops, .ops = &kvaser_usb_hydra_dev_ops,
}; };
...@@ -665,6 +666,22 @@ static const struct net_device_ops kvaser_usb_netdev_ops = { ...@@ -665,6 +666,22 @@ static const struct net_device_ops kvaser_usb_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct net_device_ops kvaser_usb_netdev_ops_hwts = {
.ndo_open = kvaser_usb_open,
.ndo_stop = kvaser_usb_close,
.ndo_eth_ioctl = can_eth_ioctl_hwts,
.ndo_start_xmit = kvaser_usb_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
static const struct ethtool_ops kvaser_usb_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static const struct ethtool_ops kvaser_usb_ethtool_ops_hwts = {
.get_ts_info = can_ethtool_op_get_ts_info_hwts,
};
static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev) static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
{ {
int i; int i;
...@@ -742,7 +759,13 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) ...@@ -742,7 +759,13 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
netdev->flags |= IFF_ECHO; netdev->flags |= IFF_ECHO;
netdev->netdev_ops = &kvaser_usb_netdev_ops; netdev->netdev_ops = &kvaser_usb_netdev_ops;
if (driver_info->quirks & KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP) {
netdev->netdev_ops = &kvaser_usb_netdev_ops_hwts;
netdev->ethtool_ops = &kvaser_usb_ethtool_ops_hwts;
} else {
netdev->netdev_ops = &kvaser_usb_netdev_ops;
netdev->ethtool_ops = &kvaser_usb_ethtool_ops;
}
SET_NETDEV_DEV(netdev, &dev->intf->dev); SET_NETDEV_DEV(netdev, &dev->intf->dev);
netdev->dev_id = channel; netdev->dev_id = channel;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/ethtool.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/signal.h> #include <linux/signal.h>
...@@ -758,6 +759,10 @@ static const struct net_device_ops mcba_netdev_ops = { ...@@ -758,6 +759,10 @@ static const struct net_device_ops mcba_netdev_ops = {
.ndo_start_xmit = mcba_usb_start_xmit, .ndo_start_xmit = mcba_usb_start_xmit,
}; };
static const struct ethtool_ops mcba_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
/* Microchip CANBUS has hardcoded bittiming values by default. /* Microchip CANBUS has hardcoded bittiming values by default.
* This function sends request via USB to change the speed and align bittiming * This function sends request via USB to change the speed and align bittiming
* values for presentation purposes only * values for presentation purposes only
...@@ -836,6 +841,7 @@ static int mcba_usb_probe(struct usb_interface *intf, ...@@ -836,6 +841,7 @@ static int mcba_usb_probe(struct usb_interface *intf,
priv->can.do_set_bittiming = mcba_net_set_bittiming; priv->can.do_set_bittiming = mcba_net_set_bittiming;
netdev->netdev_ops = &mcba_netdev_ops; netdev->netdev_ops = &mcba_netdev_ops;
netdev->ethtool_ops = &mcba_ethtool_ops;
netdev->flags |= IFF_ECHO; /* we support local echo */ netdev->flags |= IFF_ECHO; /* we support local echo */
......
...@@ -965,6 +965,7 @@ static int pcan_usb_set_phys_id(struct net_device *netdev, ...@@ -965,6 +965,7 @@ static int pcan_usb_set_phys_id(struct net_device *netdev,
static const struct ethtool_ops pcan_usb_ethtool_ops = { static const struct ethtool_ops pcan_usb_ethtool_ops = {
.set_phys_id = pcan_usb_set_phys_id, .set_phys_id = pcan_usb_set_phys_id,
.get_ts_info = pcan_get_ts_info,
}; };
/* /*
......
...@@ -775,13 +775,54 @@ static int peak_usb_set_data_bittiming(struct net_device *netdev) ...@@ -775,13 +775,54 @@ static int peak_usb_set_data_bittiming(struct net_device *netdev)
return 0; return 0;
} }
static int peak_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
struct hwtstamp_config hwts_cfg = { 0 };
switch (cmd) {
case SIOCSHWTSTAMP: /* set */
if (copy_from_user(&hwts_cfg, ifr->ifr_data, sizeof(hwts_cfg)))
return -EFAULT;
if (hwts_cfg.tx_type == HWTSTAMP_TX_OFF &&
hwts_cfg.rx_filter == HWTSTAMP_FILTER_ALL)
return 0;
return -ERANGE;
case SIOCGHWTSTAMP: /* get */
hwts_cfg.tx_type = HWTSTAMP_TX_OFF;
hwts_cfg.rx_filter = HWTSTAMP_FILTER_ALL;
if (copy_to_user(ifr->ifr_data, &hwts_cfg, sizeof(hwts_cfg)))
return -EFAULT;
return 0;
default:
return -EOPNOTSUPP;
}
}
static const struct net_device_ops peak_usb_netdev_ops = { static const struct net_device_ops peak_usb_netdev_ops = {
.ndo_open = peak_usb_ndo_open, .ndo_open = peak_usb_ndo_open,
.ndo_stop = peak_usb_ndo_stop, .ndo_stop = peak_usb_ndo_stop,
.ndo_eth_ioctl = peak_eth_ioctl,
.ndo_start_xmit = peak_usb_ndo_start_xmit, .ndo_start_xmit = peak_usb_ndo_start_xmit,
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
int pcan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
{
info->so_timestamping =
SOF_TIMESTAMPING_TX_SOFTWARE |
SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
info->phc_index = -1;
info->tx_types = BIT(HWTSTAMP_TX_OFF);
info->rx_filters = BIT(HWTSTAMP_FILTER_ALL);
return 0;
}
/* /*
* create one device which is attached to CAN controller #ctrl_idx of the * create one device which is attached to CAN controller #ctrl_idx of the
* usb adapter. * usb adapter.
......
...@@ -145,5 +145,6 @@ int peak_usb_netif_rx(struct sk_buff *skb, ...@@ -145,5 +145,6 @@ int peak_usb_netif_rx(struct sk_buff *skb,
int peak_usb_netif_rx_64(struct sk_buff *skb, u32 ts_low, u32 ts_high); int peak_usb_netif_rx_64(struct sk_buff *skb, u32 ts_low, u32 ts_high);
void peak_usb_async_complete(struct urb *urb); void peak_usb_async_complete(struct urb *urb);
void peak_usb_restart_complete(struct peak_usb_device *dev); void peak_usb_restart_complete(struct peak_usb_device *dev);
int pcan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info);
#endif #endif
...@@ -1080,6 +1080,7 @@ static int pcan_usb_fd_set_phys_id(struct net_device *netdev, ...@@ -1080,6 +1080,7 @@ static int pcan_usb_fd_set_phys_id(struct net_device *netdev,
static const struct ethtool_ops pcan_usb_fd_ethtool_ops = { static const struct ethtool_ops pcan_usb_fd_ethtool_ops = {
.set_phys_id = pcan_usb_fd_set_phys_id, .set_phys_id = pcan_usb_fd_set_phys_id,
.get_ts_info = pcan_get_ts_info,
}; };
/* describes the PCAN-USB FD adapter */ /* describes the PCAN-USB FD adapter */
......
...@@ -1022,6 +1022,7 @@ static int pcan_usb_pro_set_phys_id(struct net_device *netdev, ...@@ -1022,6 +1022,7 @@ static int pcan_usb_pro_set_phys_id(struct net_device *netdev,
static const struct ethtool_ops pcan_usb_pro_ethtool_ops = { static const struct ethtool_ops pcan_usb_pro_ethtool_ops = {
.set_phys_id = pcan_usb_pro_set_phys_id, .set_phys_id = pcan_usb_pro_set_phys_id,
.get_ts_info = pcan_get_ts_info,
}; };
/* /*
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/ethtool.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/signal.h> #include <linux/signal.h>
...@@ -1233,6 +1234,10 @@ static const struct net_device_ops ucan_netdev_ops = { ...@@ -1233,6 +1234,10 @@ static const struct net_device_ops ucan_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops ucan_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
/* Request to set bittiming /* Request to set bittiming
* *
* This function generates an USB set bittiming message and transmits * This function generates an USB set bittiming message and transmits
...@@ -1512,6 +1517,7 @@ static int ucan_probe(struct usb_interface *intf, ...@@ -1512,6 +1517,7 @@ static int ucan_probe(struct usb_interface *intf,
spin_lock_init(&up->context_lock); spin_lock_init(&up->context_lock);
spin_lock_init(&up->echo_skb_lock); spin_lock_init(&up->echo_skb_lock);
netdev->netdev_ops = &ucan_netdev_ops; netdev->netdev_ops = &ucan_netdev_ops;
netdev->ethtool_ops = &ucan_ethtool_ops;
usb_set_intfdata(intf, up); usb_set_intfdata(intf, up);
SET_NETDEV_DEV(netdev, &intf->dev); SET_NETDEV_DEV(netdev, &intf->dev);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
* who were very cooperative and answered my questions. * who were very cooperative and answered my questions.
*/ */
#include <linux/ethtool.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -870,6 +871,10 @@ static const struct net_device_ops usb_8dev_netdev_ops = { ...@@ -870,6 +871,10 @@ static const struct net_device_ops usb_8dev_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops usb_8dev_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static const struct can_bittiming_const usb_8dev_bittiming_const = { static const struct can_bittiming_const usb_8dev_bittiming_const = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.tseg1_min = 1, .tseg1_min = 1,
...@@ -927,6 +932,7 @@ static int usb_8dev_probe(struct usb_interface *intf, ...@@ -927,6 +932,7 @@ static int usb_8dev_probe(struct usb_interface *intf,
CAN_CTRLMODE_CC_LEN8_DLC; CAN_CTRLMODE_CC_LEN8_DLC;
netdev->netdev_ops = &usb_8dev_netdev_ops; netdev->netdev_ops = &usb_8dev_netdev_ops;
netdev->ethtool_ops = &usb_8dev_ethtool_ops;
netdev->flags |= IFF_ECHO; /* we support local echo */ netdev->flags |= IFF_ECHO; /* we support local echo */
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/ethtool.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -99,6 +100,8 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -99,6 +100,8 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
/* set flag whether this packet has to be looped back */ /* set flag whether this packet has to be looped back */
loop = skb->pkt_type == PACKET_LOOPBACK; loop = skb->pkt_type == PACKET_LOOPBACK;
skb_tx_timestamp(skb);
if (!echo) { if (!echo) {
/* no echo handling available inside this driver */ /* no echo handling available inside this driver */
if (loop) { if (loop) {
...@@ -146,6 +149,10 @@ static const struct net_device_ops vcan_netdev_ops = { ...@@ -146,6 +149,10 @@ static const struct net_device_ops vcan_netdev_ops = {
.ndo_change_mtu = vcan_change_mtu, .ndo_change_mtu = vcan_change_mtu,
}; };
static const struct ethtool_ops vcan_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static void vcan_setup(struct net_device *dev) static void vcan_setup(struct net_device *dev)
{ {
dev->type = ARPHRD_CAN; dev->type = ARPHRD_CAN;
...@@ -161,6 +168,7 @@ static void vcan_setup(struct net_device *dev) ...@@ -161,6 +168,7 @@ static void vcan_setup(struct net_device *dev)
dev->flags |= IFF_ECHO; dev->flags |= IFF_ECHO;
dev->netdev_ops = &vcan_netdev_ops; dev->netdev_ops = &vcan_netdev_ops;
dev->ethtool_ops = &vcan_ethtool_ops;
dev->needs_free_netdev = true; dev->needs_free_netdev = true;
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* Copyright (c) 2017 Oliver Hartkopp <socketcan@hartkopp.net> * Copyright (c) 2017 Oliver Hartkopp <socketcan@hartkopp.net>
*/ */
#include <linux/ethtool.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -53,6 +54,8 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev) ...@@ -53,6 +54,8 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev)
goto out_unlock; goto out_unlock;
} }
skb_tx_timestamp(oskb);
skb = skb_clone(oskb, GFP_ATOMIC); skb = skb_clone(oskb, GFP_ATOMIC);
if (skb) { if (skb) {
consume_skb(oskb); consume_skb(oskb);
...@@ -144,6 +147,10 @@ static const struct net_device_ops vxcan_netdev_ops = { ...@@ -144,6 +147,10 @@ static const struct net_device_ops vxcan_netdev_ops = {
.ndo_change_mtu = vxcan_change_mtu, .ndo_change_mtu = vxcan_change_mtu,
}; };
static const struct ethtool_ops vxcan_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static void vxcan_setup(struct net_device *dev) static void vxcan_setup(struct net_device *dev)
{ {
struct can_ml_priv *can_ml; struct can_ml_priv *can_ml;
...@@ -155,6 +162,7 @@ static void vxcan_setup(struct net_device *dev) ...@@ -155,6 +162,7 @@ static void vxcan_setup(struct net_device *dev)
dev->tx_queue_len = 0; dev->tx_queue_len = 0;
dev->flags = IFF_NOARP; dev->flags = IFF_NOARP;
dev->netdev_ops = &vxcan_netdev_ops; dev->netdev_ops = &vxcan_netdev_ops;
dev->ethtool_ops = &vxcan_ethtool_ops;
dev->needs_free_netdev = true; dev->needs_free_netdev = true;
can_ml = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN); can_ml = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -1540,6 +1541,10 @@ static const struct net_device_ops xcan_netdev_ops = { ...@@ -1540,6 +1541,10 @@ static const struct net_device_ops xcan_netdev_ops = {
.ndo_change_mtu = can_change_mtu, .ndo_change_mtu = can_change_mtu,
}; };
static const struct ethtool_ops xcan_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
/** /**
* xcan_suspend - Suspend method for the driver * xcan_suspend - Suspend method for the driver
* @dev: Address of the device structure * @dev: Address of the device structure
...@@ -1821,6 +1826,7 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1821,6 +1826,7 @@ static int xcan_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ndev); platform_set_drvdata(pdev, ndev);
SET_NETDEV_DEV(ndev, &pdev->dev); SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->netdev_ops = &xcan_netdev_ops; ndev->netdev_ops = &xcan_netdev_ops;
ndev->ethtool_ops = &xcan_ethtool_ops;
/* Getting the CAN can_clk info */ /* Getting the CAN can_clk info */
priv->can_clk = devm_clk_get(&pdev->dev, "can_clk"); priv->can_clk = devm_clk_get(&pdev->dev, "can_clk");
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/can/length.h> #include <linux/can/length.h>
#include <linux/can/netlink.h> #include <linux/can/netlink.h>
#include <linux/can/skb.h> #include <linux/can/skb.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
/* /*
...@@ -162,6 +163,9 @@ struct can_priv *safe_candev_priv(struct net_device *dev); ...@@ -162,6 +163,9 @@ struct can_priv *safe_candev_priv(struct net_device *dev);
int open_candev(struct net_device *dev); int open_candev(struct net_device *dev);
void close_candev(struct net_device *dev); void close_candev(struct net_device *dev);
int can_change_mtu(struct net_device *dev, int new_mtu); int can_change_mtu(struct net_device *dev, int new_mtu);
int can_eth_ioctl_hwts(struct net_device *netdev, struct ifreq *ifr, int cmd);
int can_ethtool_op_get_ts_info_hwts(struct net_device *dev,
struct ethtool_ts_info *info);
int register_candev(struct net_device *dev); int register_candev(struct net_device *dev);
void unregister_candev(struct net_device *dev); void unregister_candev(struct net_device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment