diff --git a/MAINTAINERS b/MAINTAINERS index 1920d82db83e..2cfda104ba4e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18470,6 +18470,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab.git F: include/linux/sl?b*.h F: mm/sl?b* +SLCAN CAN NETWORK DRIVER +M: Dario Binacchi +L: linux-can@vger.kernel.org +S: Maintained +F: drivers/net/can/slcan/ + SLEEPABLE READ-COPY UPDATE (SRCU) M: Lai Jiangshan M: "Paul E. McKenney" diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 29ed0d3cd171..3a2d109a3792 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -1152,6 +1153,10 @@ static const struct net_device_ops at91_netdev_ops = { .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, struct device_attribute *attr, char *buf) { @@ -1293,6 +1298,7 @@ static int at91_can_probe(struct platform_device *pdev) } dev->netdev_ops = &at91_netdev_ops; + dev->ethtool_ops = &at91_ethtool_ops; dev->irq = irq; dev->flags |= IFF_ECHO; diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h index bd2f6dc01194..f23a03300a81 100644 --- a/drivers/net/can/c_can/c_can.h +++ b/drivers/net/can/c_can/c_can.h @@ -223,7 +223,7 @@ int c_can_power_up(struct net_device *dev); int c_can_power_down(struct net_device *dev); #endif -void c_can_set_ethtool_ops(struct net_device *dev); +extern const struct ethtool_ops c_can_ethtool_ops; static inline u8 c_can_get_tx_head(const struct c_can_tx_ring *ring) { diff --git a/drivers/net/can/c_can/c_can_ethtool.c b/drivers/net/can/c_can/c_can_ethtool.c index 8a826a6813bd..e41167eda673 100644 --- a/drivers/net/can/c_can/c_can_ethtool.c +++ b/drivers/net/can/c_can/c_can_ethtool.c @@ -24,11 +24,7 @@ static void c_can_get_ringparam(struct net_device *netdev, ring->tx_pending = priv->msg_obj_tx_num; } -static const struct ethtool_ops c_can_ethtool_ops = { +const struct ethtool_ops c_can_ethtool_ops = { .get_ringparam = c_can_get_ringparam, + .get_ts_info = ethtool_op_get_ts_info, }; - -void c_can_set_ethtool_ops(struct net_device *netdev) -{ - netdev->ethtool_ops = &c_can_ethtool_ops; -} diff --git a/drivers/net/can/c_can/c_can_main.c b/drivers/net/can/c_can/c_can_main.c index de38d8f7b5f7..dc8132862f33 100644 --- a/drivers/net/can/c_can/c_can_main.c +++ b/drivers/net/can/c_can/c_can_main.c @@ -1364,7 +1364,7 @@ int register_c_can_dev(struct net_device *dev) dev->flags |= IFF_ECHO; /* we support local echo */ dev->netdev_ops = &c_can_netdev_ops; - c_can_set_ethtool_ops(dev); + dev->ethtool_ops = &c_can_ethtool_ops; return register_candev(dev); } diff --git a/drivers/net/can/can327.c b/drivers/net/can/can327.c index 5da7778d92dc..0aa1af31d0fe 100644 --- a/drivers/net/can/can327.c +++ b/drivers/net/can/can327.c @@ -10,7 +10,7 @@ * Fred N. van Kempen */ -#define pr_fmt(fmt) "can327: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -827,7 +827,7 @@ static netdev_tx_t can327_netdev_start_xmit(struct sk_buff *skb, netif_stop_queue(dev); /* BHs are already disabled, so no spin_lock_bh(). - * See Documentation/networking/netdevices.txt + * See Documentation/networking/netdevices.rst */ spin_lock(&elm->lock); can327_send_frame(elm, frame); @@ -836,6 +836,8 @@ static netdev_tx_t can327_netdev_start_xmit(struct sk_buff *skb, dev->stats.tx_packets++; dev->stats.tx_bytes += frame->can_id & CAN_RTR_FLAG ? 0 : frame->len; + skb_tx_timestamp(skb); + out: kfree_skb(skb); return NETDEV_TX_OK; @@ -848,6 +850,10 @@ static const struct net_device_ops can327_netdev_ops = { .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 const bool lut_char_is_valid['z'] = { @@ -1032,6 +1038,7 @@ static int can327_ldisc_open(struct tty_struct *tty) /* Configure netdev interface */ elm->dev = dev; dev->netdev_ops = &can327_netdev_ops; + dev->ethtool_ops = &can327_ethtool_ops; /* Mark ldisc channel as alive */ elm->tty = tty; @@ -1100,7 +1107,7 @@ static int can327_ldisc_ioctl(struct tty_struct *tty, unsigned int cmd, static struct tty_ldisc_ops can327_ldisc = { .owner = THIS_MODULE, - .name = "can327", + .name = KBUILD_MODNAME, .num = N_CAN327, .receive_buf = can327_ldisc_rx, .write_wakeup = can327_ldisc_tx_wakeup, diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index 797a954bb1a0..0b9dfc76e769 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -836,6 +837,10 @@ static const struct net_device_ops cc770_netdev_ops = { .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) { struct cc770_priv *priv = netdev_priv(dev); @@ -846,6 +851,7 @@ int register_cc770dev(struct net_device *dev) return err; dev->netdev_ops = &cc770_netdev_ops; + dev->ethtool_ops = &cc770_ethtool_ops; dev->flags |= IFF_ECHO; /* we support local echo */ diff --git a/drivers/net/can/ctucanfd/ctucanfd_base.c b/drivers/net/can/ctucanfd/ctucanfd_base.c index 6b281f6eb9b4..3c18d028bd8c 100644 --- a/drivers/net/can/ctucanfd/ctucanfd_base.c +++ b/drivers/net/can/ctucanfd/ctucanfd_base.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -1301,6 +1302,10 @@ static const struct net_device_ops ctucan_netdev_ops = { .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) { 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 set_drvdata_fnc(dev, ndev); SET_NETDEV_DEV(ndev, dev); ndev->netdev_ops = &ctucan_netdev_ops; + ndev->ethtool_ops = &ctucan_ethtool_ops; /* Getting the can_clk info */ if (!can_clk_rate) { diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index 523eaacfe29e..c1956b1e9faf 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -322,6 +322,56 @@ int can_change_mtu(struct net_device *dev, int new_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. * * This function should be called in the open function of the device diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c index 8bb62dd864c8..07e0feac8629 100644 --- a/drivers/net/can/dev/skb.c +++ b/drivers/net/can/dev/skb.c @@ -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 */ 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); /* 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, struct can_skb_priv *can_skb_priv = can_skb_prv(skb); 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 */ if (cf->can_id & CAN_RTR_FLAG) *len_ptr = 0; diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c index d060088047f1..f857968efed7 100644 --- a/drivers/net/can/flexcan/flexcan-core.c +++ b/drivers/net/can/flexcan/flexcan-core.c @@ -2113,7 +2113,7 @@ static int flexcan_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); dev->netdev_ops = &flexcan_netdev_ops; - flexcan_set_ethtool_ops(dev); + dev->ethtool_ops = &flexcan_ethtool_ops; dev->irq = irq; dev->flags |= IFF_ECHO; diff --git a/drivers/net/can/flexcan/flexcan-ethtool.c b/drivers/net/can/flexcan/flexcan-ethtool.c index 3ae535577700..50e86b2da532 100644 --- a/drivers/net/can/flexcan/flexcan-ethtool.c +++ b/drivers/net/can/flexcan/flexcan-ethtool.c @@ -100,15 +100,11 @@ static int flexcan_get_sset_count(struct net_device *netdev, int sset) } } -static const struct ethtool_ops flexcan_ethtool_ops = { +const struct ethtool_ops flexcan_ethtool_ops = { .get_ringparam = flexcan_get_ringparam, .get_strings = flexcan_get_strings, .get_priv_flags = flexcan_get_priv_flags, .set_priv_flags = flexcan_set_priv_flags, .get_sset_count = flexcan_get_sset_count, + .get_ts_info = ethtool_op_get_ts_info, }; - -void flexcan_set_ethtool_ops(struct net_device *netdev) -{ - netdev->ethtool_ops = &flexcan_ethtool_ops; -} diff --git a/drivers/net/can/flexcan/flexcan.h b/drivers/net/can/flexcan/flexcan.h index 23fc09a7e10f..8621a8ea1dea 100644 --- a/drivers/net/can/flexcan/flexcan.h +++ b/drivers/net/can/flexcan/flexcan.h @@ -114,7 +114,7 @@ struct flexcan_priv { void (*write)(u32 val, void __iomem *addr); }; -void flexcan_set_ethtool_ops(struct net_device *dev); +extern const struct ethtool_ops flexcan_ethtool_ops; static inline bool flexcan_supports_rx_mailbox(const struct flexcan_priv *priv) diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c index 24035a6187c9..6c37aab93eb3 100644 --- a/drivers/net/can/grcan.c +++ b/drivers/net/can/grcan.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1561,6 +1562,10 @@ static const struct net_device_ops grcan_netdev_ops = { .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, void __iomem *base, int irq, u32 ambafreq, bool txbug) @@ -1577,6 +1582,7 @@ static int grcan_setup_netdev(struct platform_device *ofdev, dev->irq = irq; dev->flags |= IFF_ECHO; dev->netdev_ops = &grcan_netdev_ops; + dev->ethtool_ops = &grcan_ethtool_ops; dev->sysfs_groups[0] = &sysfs_grcan_group; priv = netdev_priv(dev); diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index 64e3be8b73af..ad7a89b95da7 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -925,6 +926,10 @@ static const struct net_device_ops ifi_canfd_netdev_ops = { .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) { struct device *dev = &pdev->dev; @@ -962,6 +967,7 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) ndev->irq = irq; ndev->flags |= IFF_ECHO; /* we support local echo */ ndev->netdev_ops = &ifi_canfd_netdev_ops; + ndev->ethtool_ops = &ifi_canfd_ethtool_ops; priv = netdev_priv(ndev); priv->ndev = ndev; diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index ccb5c5405224..71a2caae0757 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -1277,6 +1278,8 @@ static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb) if (!skb) return; + skb_tx_timestamp(skb); + /* save this skb for tx interrupt echo handling */ skb_queue_tail(&mod->echoq, skb); } @@ -1752,6 +1755,10 @@ static const struct net_device_ops ican3_netdev_ops = { .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 */ @@ -1923,6 +1930,7 @@ static int ican3_probe(struct platform_device *pdev) mod->free_page = DPM_FREE_START; ndev->netdev_ops = &ican3_netdev_ops; + ndev->ethtool_ops = &ican3_ethtool_ops; ndev->flags |= IFF_ECHO; SET_NETDEV_DEV(ndev, &pdev->dev); diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index dcd2c9d50d5e..ed54c0b3c7d4 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -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 = { .ndo_open = kvaser_pciefd_open, .ndo_stop = kvaser_pciefd_stop, + .ndo_eth_ioctl = can_eth_ioctl_hwts, .ndo_start_xmit = kvaser_pciefd_start_xmit, .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) { int i; @@ -939,6 +945,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) can = netdev_priv(netdev); netdev->netdev_ops = &kvaser_pciefd_netdev_ops; + netdev->ethtool_ops = &kvaser_pciefd_ethtool_ops; can->reg_base = pcie->reg_base + KVASER_PCIEFD_KCAN0_BASE + i * KVASER_PCIEFD_KCAN_BASE_OFFSET; diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 713a4b0edf86..4709c012b1dc 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -1829,10 +1830,15 @@ static const struct net_device_ops m_can_netdev_ops = { .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) { dev->flags |= IFF_ECHO; /* we support local echo */ dev->netdev_ops = &m_can_netdev_ops; + dev->ethtool_ops = &m_can_ethtool_ops; return register_candev(dev); } diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index 78a21ab63601..2119fbb287ef 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -616,6 +616,10 @@ static const struct net_device_ops mscan_netdev_ops = { .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) { struct mscan_priv *priv = netdev_priv(dev); @@ -676,6 +680,7 @@ struct net_device *alloc_mscandev(void) priv = netdev_priv(dev); dev->netdev_ops = &mscan_netdev_ops; + dev->ethtool_ops = &mscan_ethtool_ops; dev->flags |= IFF_ECHO; /* we support local echo */ diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c index 32804fed116c..0558ff67ec6a 100644 --- a/drivers/net/can/pch_can.c +++ b/drivers/net/can/pch_can.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -938,6 +939,10 @@ static const struct net_device_ops pch_can_netdev_ops = { .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) { struct net_device *ndev = pci_get_drvdata(pdev); @@ -1188,6 +1193,7 @@ static int pch_can_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, ndev); SET_NETDEV_DEV(ndev, &pdev->dev); ndev->netdev_ops = &pch_can_netdev_ops; + ndev->ethtool_ops = &pch_can_ethtool_ops; priv->can.clock.freq = PCH_CAN_CLK; /* Hz */ netif_napi_add_weight(ndev, &priv->napi, pch_can_poll, PCH_RX_OBJ_END); diff --git a/drivers/net/can/peak_canfd/peak_canfd.c b/drivers/net/can/peak_canfd/peak_canfd.c index afb9adb3d5c2..f8420cc1d907 100644 --- a/drivers/net/can/peak_canfd/peak_canfd.c +++ b/drivers/net/can/peak_canfd/peak_canfd.c @@ -7,6 +7,7 @@ #include #include +#include #include "peak_canfd_user.h" @@ -742,13 +743,59 @@ static netdev_tx_t peak_canfd_start_xmit(struct sk_buff *skb, 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 = { .ndo_open = peak_canfd_open, .ndo_stop = peak_canfd_close, + .ndo_eth_ioctl = peak_eth_ioctl, .ndo_start_xmit = peak_canfd_start_xmit, .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, int echo_skb_max) { @@ -789,6 +836,7 @@ struct net_device *alloc_peak_canfd_dev(int sizeof_priv, int index, ndev->flags |= IFF_ECHO; ndev->netdev_ops = &peak_canfd_netdev_ops; + ndev->ethtool_ops = &peak_canfd_ethtool_ops; ndev->dev_id = index; return ndev; diff --git a/drivers/net/can/rcar/rcar_can.c b/drivers/net/can/rcar/rcar_can.c index d11db2112a4a..6ee968c59ac9 100644 --- a/drivers/net/can/rcar/rcar_can.c +++ b/drivers/net/can/rcar/rcar_can.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -630,6 +631,10 @@ static const struct net_device_ops rcar_can_netdev_ops = { .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) { struct net_device_stats *stats = &priv->ndev->stats; @@ -785,6 +790,7 @@ static int rcar_can_probe(struct platform_device *pdev) } ndev->netdev_ops = &rcar_can_netdev_ops; + ndev->ethtool_ops = &rcar_can_ethtool_ops; ndev->irq = irq; ndev->flags |= IFF_ECHO; priv->ndev = ndev; diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index d3e569a02b4d..27085b796e75 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1695,6 +1696,10 @@ static const struct net_device_ops rcar_canfd_netdev_ops = { .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, u32 fcan_freq) { @@ -1711,6 +1716,7 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, priv = netdev_priv(ndev); ndev->netdev_ops = &rcar_canfd_netdev_ops; + ndev->ethtool_ops = &rcar_canfd_ethtool_ops; ndev->flags |= IFF_ECHO; priv->ndev = ndev; priv->base = gpriv->base; diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 75a2f9bf8c16..98dfd5f295a7 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -654,6 +655,10 @@ static const struct net_device_ops sja1000_netdev_ops = { .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 ret; @@ -663,6 +668,7 @@ int register_sja1000dev(struct net_device *dev) dev->flags |= IFF_ECHO; /* we support local echo */ dev->netdev_ops = &sja1000_netdev_ops; + dev->ethtool_ops = &sja1000_ethtool_ops; set_reset_mode(dev); chipset_init(dev); diff --git a/drivers/net/can/slcan/slcan-core.c b/drivers/net/can/slcan/slcan-core.c index dc28e715bbe1..8d13fdf8c28a 100644 --- a/drivers/net/can/slcan/slcan-core.c +++ b/drivers/net/can/slcan/slcan-core.c @@ -1,11 +1,14 @@ /* * slcan.c - serial line CAN interface driver (using tty line discipline) * - * This file is derived from linux/drivers/net/slip/slip.c + * This file is derived from linux/drivers/net/slip/slip.c and got + * inspiration from linux/drivers/net/can/can327.c for the rework made + * on the line discipline code. * * slip.c Authors : Laurence Culhane * Fred N. van Kempen * slcan.c Author : Oliver Hartkopp + * can327.c Author : Max Staudt * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -35,8 +38,9 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include -#include #include #include @@ -46,10 +50,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -63,30 +63,22 @@ MODULE_ALIAS_LDISC(N_SLCAN); MODULE_DESCRIPTION("serial line CAN interface"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Oliver Hartkopp "); - -#define SLCAN_MAGIC 0x53CA - -static int maxdev = 10; /* MAX number of SLCAN channels; - * This can be overridden with - * insmod slcan.ko maxdev=nnn - */ -module_param(maxdev, int, 0); -MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces"); +MODULE_AUTHOR("Dario Binacchi "); /* maximum rx buffer len: extended CAN frame with timestamp */ -#define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r") + 1) +#define SLCAN_MTU (sizeof("T1111222281122334455667788EA5F\r") + 1) -#define SLC_CMD_LEN 1 -#define SLC_SFF_ID_LEN 3 -#define SLC_EFF_ID_LEN 8 -#define SLC_STATE_LEN 1 -#define SLC_STATE_BE_RXCNT_LEN 3 -#define SLC_STATE_BE_TXCNT_LEN 3 -#define SLC_STATE_FRAME_LEN (1 + SLC_CMD_LEN + SLC_STATE_BE_RXCNT_LEN + \ - SLC_STATE_BE_TXCNT_LEN) +#define SLCAN_CMD_LEN 1 +#define SLCAN_SFF_ID_LEN 3 +#define SLCAN_EFF_ID_LEN 8 +#define SLCAN_STATE_LEN 1 +#define SLCAN_STATE_BE_RXCNT_LEN 3 +#define SLCAN_STATE_BE_TXCNT_LEN 3 +#define SLCAN_STATE_FRAME_LEN (1 + SLCAN_CMD_LEN + \ + SLCAN_STATE_BE_RXCNT_LEN + \ + SLCAN_STATE_BE_TXCNT_LEN) struct slcan { struct can_priv can; - int magic; /* Various fields. */ struct tty_struct *tty; /* ptr to TTY structure */ @@ -95,24 +87,21 @@ struct slcan { struct work_struct tx_work; /* Flushes transmit buffer */ /* These are pointers to the malloc()ed frame buffers. */ - unsigned char rbuff[SLC_MTU]; /* receiver buffer */ + unsigned char rbuff[SLCAN_MTU]; /* receiver buffer */ int rcount; /* received chars counter */ - unsigned char xbuff[SLC_MTU]; /* transmitter buffer */ + unsigned char xbuff[SLCAN_MTU]; /* transmitter buffer*/ unsigned char *xhead; /* pointer to next XMIT byte */ int xleft; /* bytes left in XMIT queue */ unsigned long flags; /* Flag values/ mode etc */ -#define SLF_INUSE 0 /* Channel in use */ -#define SLF_ERROR 1 /* Parity, etc. error */ -#define SLF_XCMD 2 /* Command transmission */ +#define SLF_ERROR 0 /* Parity, etc. error */ +#define SLF_XCMD 1 /* Command transmission */ unsigned long cmd_flags; /* Command flags */ #define CF_ERR_RST 0 /* Reset errors on open */ wait_queue_head_t xcmd_wait; /* Wait queue for commands */ /* transmission */ }; -static struct net_device **slcan_devs; - static const u32 slcan_bitrate_const[] = { 10000, 20000, 50000, 100000, 125000, 250000, 500000, 800000, 1000000 @@ -179,7 +168,7 @@ int slcan_enable_err_rst_on_open(struct net_device *ndev, bool on) *************************************************************************/ /* Send one completely decapsulated can_frame to the network layer */ -static void slc_bump_frame(struct slcan *sl) +static void slcan_bump_frame(struct slcan *sl) { struct sk_buff *skb; struct can_frame *cf; @@ -199,10 +188,10 @@ static void slc_bump_frame(struct slcan *sl) fallthrough; case 't': /* store dlc ASCII value and terminate SFF CAN ID string */ - cf->len = sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN]; - sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN] = 0; + cf->len = sl->rbuff[SLCAN_CMD_LEN + SLCAN_SFF_ID_LEN]; + sl->rbuff[SLCAN_CMD_LEN + SLCAN_SFF_ID_LEN] = 0; /* point to payload data behind the dlc */ - cmd += SLC_CMD_LEN + SLC_SFF_ID_LEN + 1; + cmd += SLCAN_CMD_LEN + SLCAN_SFF_ID_LEN + 1; break; case 'R': cf->can_id = CAN_RTR_FLAG; @@ -210,16 +199,16 @@ static void slc_bump_frame(struct slcan *sl) case 'T': cf->can_id |= CAN_EFF_FLAG; /* store dlc ASCII value and terminate EFF CAN ID string */ - cf->len = sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN]; - sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN] = 0; + cf->len = sl->rbuff[SLCAN_CMD_LEN + SLCAN_EFF_ID_LEN]; + sl->rbuff[SLCAN_CMD_LEN + SLCAN_EFF_ID_LEN] = 0; /* point to payload data behind the dlc */ - cmd += SLC_CMD_LEN + SLC_EFF_ID_LEN + 1; + cmd += SLCAN_CMD_LEN + SLCAN_EFF_ID_LEN + 1; break; default: goto decode_failed; } - if (kstrtou32(sl->rbuff + SLC_CMD_LEN, 16, &tmpid)) + if (kstrtou32(sl->rbuff + SLCAN_CMD_LEN, 16, &tmpid)) goto decode_failed; cf->can_id |= tmpid; @@ -266,7 +255,7 @@ decode_failed: * sb256256 : state bus-off: rx counter 256, tx counter 256 * sa057033 : state active, rx counter 57, tx counter 33 */ -static void slc_bump_state(struct slcan *sl) +static void slcan_bump_state(struct slcan *sl) { struct net_device *dev = sl->dev; struct sk_buff *skb; @@ -292,16 +281,16 @@ static void slc_bump_state(struct slcan *sl) return; } - if (state == sl->can.state || sl->rcount < SLC_STATE_FRAME_LEN) + if (state == sl->can.state || sl->rcount < SLCAN_STATE_FRAME_LEN) return; - cmd += SLC_STATE_BE_RXCNT_LEN + SLC_CMD_LEN + 1; - cmd[SLC_STATE_BE_TXCNT_LEN] = 0; + cmd += SLCAN_STATE_BE_RXCNT_LEN + SLCAN_CMD_LEN + 1; + cmd[SLCAN_STATE_BE_TXCNT_LEN] = 0; if (kstrtou32(cmd, 10, &txerr)) return; *cmd = 0; - cmd -= SLC_STATE_BE_RXCNT_LEN; + cmd -= SLCAN_STATE_BE_RXCNT_LEN; if (kstrtou32(cmd, 10, &rxerr)) return; @@ -330,7 +319,7 @@ static void slc_bump_state(struct slcan *sl) * e1a : len 1, errors: ACK error * e3bcO: len 3, errors: Bit0 error, CRC error, Tx overrun error */ -static void slc_bump_err(struct slcan *sl) +static void slcan_bump_err(struct slcan *sl) { struct net_device *dev = sl->dev; struct sk_buff *skb; @@ -346,7 +335,7 @@ static void slc_bump_err(struct slcan *sl) else return; - if ((len + SLC_CMD_LEN + 1) > sl->rcount) + if ((len + SLCAN_CMD_LEN + 1) > sl->rcount) return; skb = alloc_can_err_skb(dev, &cf); @@ -354,7 +343,7 @@ static void slc_bump_err(struct slcan *sl) if (skb) cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cmd += SLC_CMD_LEN + 1; + cmd += SLCAN_CMD_LEN + 1; for (i = 0; i < len; i++, cmd++) { switch (*cmd) { case 'a': @@ -443,7 +432,7 @@ static void slc_bump_err(struct slcan *sl) netif_rx(skb); } -static void slc_bump(struct slcan *sl) +static void slcan_bump(struct slcan *sl) { switch (sl->rbuff[0]) { case 'r': @@ -453,11 +442,11 @@ static void slc_bump(struct slcan *sl) case 'R': fallthrough; case 'T': - return slc_bump_frame(sl); + return slcan_bump_frame(sl); case 'e': - return slc_bump_err(sl); + return slcan_bump_err(sl); case 's': - return slc_bump_state(sl); + return slcan_bump_state(sl); default: return; } @@ -469,12 +458,12 @@ static void slcan_unesc(struct slcan *sl, unsigned char s) if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */ if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && sl->rcount > 4) - slc_bump(sl); + slcan_bump(sl); sl->rcount = 0; } else { if (!test_bit(SLF_ERROR, &sl->flags)) { - if (sl->rcount < SLC_MTU) { + if (sl->rcount < SLCAN_MTU) { sl->rbuff[sl->rcount++] = s; return; } @@ -490,7 +479,7 @@ static void slcan_unesc(struct slcan *sl, unsigned char s) *************************************************************************/ /* Encapsulate one can_frame and stuff into a TTY queue. */ -static void slc_encaps(struct slcan *sl, struct can_frame *cf) +static void slcan_encaps(struct slcan *sl, struct can_frame *cf) { int actual, i; unsigned char *pos; @@ -507,11 +496,11 @@ static void slc_encaps(struct slcan *sl, struct can_frame *cf) /* determine number of chars for the CAN-identifier */ if (cf->can_id & CAN_EFF_FLAG) { id &= CAN_EFF_MASK; - endpos = pos + SLC_EFF_ID_LEN; + endpos = pos + SLCAN_EFF_ID_LEN; } else { *pos |= 0x20; /* convert R/T to lower case for SFF */ id &= CAN_SFF_MASK; - endpos = pos + SLC_SFF_ID_LEN; + endpos = pos + SLCAN_SFF_ID_LEN; } /* build 3 (SFF) or 8 (EFF) digit CAN identifier */ @@ -521,7 +510,8 @@ static void slc_encaps(struct slcan *sl, struct can_frame *cf) id >>= 4; } - pos += (cf->can_id & CAN_EFF_FLAG) ? SLC_EFF_ID_LEN : SLC_SFF_ID_LEN; + pos += (cf->can_id & CAN_EFF_FLAG) ? + SLCAN_EFF_ID_LEN : SLCAN_SFF_ID_LEN; *pos++ = cf->len + '0'; @@ -557,9 +547,8 @@ static void slcan_transmit(struct work_struct *work) spin_lock_bh(&sl->lock); /* First make sure we're connected. */ - if (!sl->tty || sl->magic != SLCAN_MAGIC || - (unlikely(!netif_running(sl->dev)) && - likely(!test_bit(SLF_XCMD, &sl->flags)))) { + if (unlikely(!netif_running(sl->dev)) && + likely(!test_bit(SLF_XCMD, &sl->flags))) { spin_unlock_bh(&sl->lock); return; } @@ -594,17 +583,14 @@ static void slcan_transmit(struct work_struct *work) */ static void slcan_write_wakeup(struct tty_struct *tty) { - struct slcan *sl; + struct slcan *sl = (struct slcan *)tty->disc_data; - rcu_read_lock(); - sl = rcu_dereference(tty->disc_data); - if (sl) - schedule_work(&sl->tx_work); - rcu_read_unlock(); + schedule_work(&sl->tx_work); } /* Send a can_frame to a TTY queue. */ -static netdev_tx_t slc_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t slcan_netdev_xmit(struct sk_buff *skb, + struct net_device *dev) { struct slcan *sl = netdev_priv(dev); @@ -623,9 +609,11 @@ static netdev_tx_t slc_xmit(struct sk_buff *skb, struct net_device *dev) } netif_stop_queue(sl->dev); - slc_encaps(sl, (struct can_frame *)skb->data); /* encaps & send */ + slcan_encaps(sl, (struct can_frame *)skb->data); /* encaps & send */ spin_unlock(&sl->lock); + skb_tx_timestamp(skb); + out: kfree_skb(skb); return NETDEV_TX_OK; @@ -666,30 +654,26 @@ static int slcan_transmit_cmd(struct slcan *sl, const unsigned char *cmd) } /* Netdevice UP -> DOWN routine */ -static int slc_close(struct net_device *dev) +static int slcan_netdev_close(struct net_device *dev) { struct slcan *sl = netdev_priv(dev); int err; - spin_lock_bh(&sl->lock); - if (sl->tty) { - if (sl->can.bittiming.bitrate && - sl->can.bittiming.bitrate != CAN_BITRATE_UNKNOWN) { - spin_unlock_bh(&sl->lock); - err = slcan_transmit_cmd(sl, "C\r"); - spin_lock_bh(&sl->lock); - if (err) - netdev_warn(dev, - "failed to send close command 'C\\r'\n"); - } - - /* TTY discipline is running. */ - clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); + if (sl->can.bittiming.bitrate && + sl->can.bittiming.bitrate != CAN_BITRATE_UNKNOWN) { + err = slcan_transmit_cmd(sl, "C\r"); + if (err) + netdev_warn(dev, + "failed to send close command 'C\\r'\n"); } + + /* TTY discipline is running. */ + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); + flush_work(&sl->tx_work); + netif_stop_queue(dev); sl->rcount = 0; sl->xleft = 0; - spin_unlock_bh(&sl->lock); close_candev(dev); sl->can.state = CAN_STATE_STOPPED; if (sl->can.bittiming.bitrate == CAN_BITRATE_UNKNOWN) @@ -699,15 +683,12 @@ static int slc_close(struct net_device *dev) } /* Netdevice DOWN -> UP routine */ -static int slc_open(struct net_device *dev) +static int slcan_netdev_open(struct net_device *dev) { struct slcan *sl = netdev_priv(dev); - unsigned char cmd[SLC_MTU]; + unsigned char cmd[SLCAN_MTU]; int err, s; - if (!sl->tty) - return -ENODEV; - /* The baud rate is not set with the command * `ip link set type can bitrate ' and therefore * can.bittiming.bitrate is CAN_BITRATE_UNSET (0), causing @@ -722,8 +703,6 @@ static int slc_open(struct net_device *dev) return err; } - sl->flags &= BIT(SLF_INUSE); - if (sl->can.bittiming.bitrate != CAN_BITRATE_UNKNOWN) { for (s = 0; s < ARRAY_SIZE(slcan_bitrate_const); s++) { if (sl->can.bittiming.bitrate == slcan_bitrate_const[s]) @@ -751,10 +730,20 @@ static int slc_open(struct net_device *dev) } } - err = slcan_transmit_cmd(sl, "O\r"); - if (err) { - netdev_err(dev, "failed to send open command 'O\\r'\n"); - goto cmd_transmit_failed; + if (sl->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) { + err = slcan_transmit_cmd(sl, "L\r"); + if (err) { + netdev_err(dev, + "failed to send listen-only command 'L\\r'\n"); + goto cmd_transmit_failed; + } + } else { + err = slcan_transmit_cmd(sl, "O\r"); + if (err) { + netdev_err(dev, + "failed to send open command 'O\\r'\n"); + goto cmd_transmit_failed; + } } } @@ -767,24 +756,11 @@ cmd_transmit_failed: return err; } -static void slc_dealloc(struct slcan *sl) -{ - int i = sl->dev->base_addr; - - free_candev(sl->dev); - slcan_devs[i] = NULL; -} - -static int slcan_change_mtu(struct net_device *dev, int new_mtu) -{ - return -EINVAL; -} - -static const struct net_device_ops slc_netdev_ops = { - .ndo_open = slc_open, - .ndo_stop = slc_close, - .ndo_start_xmit = slc_xmit, - .ndo_change_mtu = slcan_change_mtu, +static const struct net_device_ops slcan_netdev_ops = { + .ndo_open = slcan_netdev_open, + .ndo_stop = slcan_netdev_close, + .ndo_start_xmit = slcan_netdev_xmit, + .ndo_change_mtu = can_change_mtu, }; /****************************************** @@ -804,7 +780,7 @@ static void slcan_receive_buf(struct tty_struct *tty, { struct slcan *sl = (struct slcan *)tty->disc_data; - if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev)) + if (!netif_running(sl->dev)) return; /* Read the characters out of the buffer */ @@ -819,80 +795,15 @@ static void slcan_receive_buf(struct tty_struct *tty, } } -/************************************ - * slcan_open helper routines. - ************************************/ - -/* Collect hanged up channels */ -static void slc_sync(void) -{ - int i; - struct net_device *dev; - struct slcan *sl; - - for (i = 0; i < maxdev; i++) { - dev = slcan_devs[i]; - if (!dev) - break; - - sl = netdev_priv(dev); - if (sl->tty) - continue; - if (dev->flags & IFF_UP) - dev_close(dev); - } -} - -/* Find a free SLCAN channel, and link in this `tty' line. */ -static struct slcan *slc_alloc(void) -{ - int i; - struct net_device *dev = NULL; - struct slcan *sl; - - for (i = 0; i < maxdev; i++) { - dev = slcan_devs[i]; - if (!dev) - break; - } - - /* Sorry, too many, all slots in use */ - if (i >= maxdev) - return NULL; - - dev = alloc_candev(sizeof(*sl), 1); - if (!dev) - return NULL; - - snprintf(dev->name, sizeof(dev->name), "slcan%d", i); - dev->netdev_ops = &slc_netdev_ops; - dev->base_addr = i; - slcan_set_ethtool_ops(dev); - sl = netdev_priv(dev); - - /* Initialize channel control data */ - sl->magic = SLCAN_MAGIC; - sl->dev = dev; - sl->can.bitrate_const = slcan_bitrate_const; - sl->can.bitrate_const_cnt = ARRAY_SIZE(slcan_bitrate_const); - spin_lock_init(&sl->lock); - INIT_WORK(&sl->tx_work, slcan_transmit); - init_waitqueue_head(&sl->xcmd_wait); - slcan_devs[i] = dev; - - return sl; -} - /* Open the high-level part of the SLCAN channel. * This function is called by the TTY module when the - * SLCAN line discipline is called for. Because we are - * sure the tty line exists, we only have to link it to - * a free SLCAN channel... + * SLCAN line discipline is called for. * * Called in process context serialized from other ldisc calls. */ static int slcan_open(struct tty_struct *tty) { + struct net_device *dev; struct slcan *sl; int err; @@ -902,72 +813,50 @@ static int slcan_open(struct tty_struct *tty) if (!tty->ops->write) return -EOPNOTSUPP; - /* RTnetlink lock is misused here to serialize concurrent - * opens of slcan channels. There are better ways, but it is - * the simplest one. - */ - rtnl_lock(); + dev = alloc_candev(sizeof(*sl), 1); + if (!dev) + return -ENFILE; - /* Collect hanged up channels. */ - slc_sync(); + sl = netdev_priv(dev); - sl = tty->disc_data; + /* Configure TTY interface */ + tty->receive_room = 65536; /* We don't flow control */ + sl->rcount = 0; + sl->xleft = 0; + spin_lock_init(&sl->lock); + INIT_WORK(&sl->tx_work, slcan_transmit); + init_waitqueue_head(&sl->xcmd_wait); - err = -EEXIST; - /* First make sure we're not already connected. */ - if (sl && sl->magic == SLCAN_MAGIC) - goto err_exit; + /* Configure CAN metadata */ + sl->can.bitrate_const = slcan_bitrate_const; + sl->can.bitrate_const_cnt = ARRAY_SIZE(slcan_bitrate_const); + sl->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY; - /* OK. Find a free SLCAN channel to use. */ - err = -ENFILE; - sl = slc_alloc(); - if (!sl) - goto err_exit; + /* Configure netdev interface */ + sl->dev = dev; + dev->netdev_ops = &slcan_netdev_ops; + dev->ethtool_ops = &slcan_ethtool_ops; + /* Mark ldisc channel as alive */ sl->tty = tty; tty->disc_data = sl; - if (!test_bit(SLF_INUSE, &sl->flags)) { - /* Perform the low-level SLCAN initialization. */ - sl->rcount = 0; - sl->xleft = 0; - - set_bit(SLF_INUSE, &sl->flags); - - rtnl_unlock(); - err = register_candev(sl->dev); - if (err) { - pr_err("slcan: can't register candev\n"); - goto err_free_chan; - } - } else { - rtnl_unlock(); + err = register_candev(dev); + if (err) { + free_candev(dev); + pr_err("can't register candev\n"); + return err; } - tty->receive_room = 65536; /* We don't flow control */ - + netdev_info(dev, "slcan on %s.\n", tty->name); /* TTY layer expects 0 on success */ return 0; - -err_free_chan: - rtnl_lock(); - sl->tty = NULL; - tty->disc_data = NULL; - clear_bit(SLF_INUSE, &sl->flags); - slc_dealloc(sl); - rtnl_unlock(); - return err; - -err_exit: - rtnl_unlock(); - - /* Count references from TTY module */ - return err; } /* Close down a SLCAN channel. * This means flushing out any pending queues, and then returning. This * call is serialized against other ldisc functions. + * Once this is called, no other ldisc function of ours is entered. * * We also use this method for a hangup event. */ @@ -975,28 +864,20 @@ static void slcan_close(struct tty_struct *tty) { struct slcan *sl = (struct slcan *)tty->disc_data; - /* First make sure we're connected. */ - if (!sl || sl->magic != SLCAN_MAGIC || sl->tty != tty) - return; + /* unregister_netdev() calls .ndo_stop() so we don't have to. + * Our .ndo_stop() also flushes the TTY write wakeup handler, + * so we can safely set sl->tty = NULL after this. + */ + unregister_candev(sl->dev); + /* Mark channel as dead */ spin_lock_bh(&sl->lock); - rcu_assign_pointer(tty->disc_data, NULL); + tty->disc_data = NULL; sl->tty = NULL; spin_unlock_bh(&sl->lock); - synchronize_rcu(); - flush_work(&sl->tx_work); - - slc_close(sl->dev); - unregister_candev(sl->dev); - rtnl_lock(); - slc_dealloc(sl); - rtnl_unlock(); -} - -static void slcan_hangup(struct tty_struct *tty) -{ - slcan_close(tty); + netdev_info(sl->dev, "slcan off %s.\n", tty->name); + free_candev(sl->dev); } /* Perform I/O control on an active SLCAN channel. */ @@ -1006,10 +887,6 @@ static int slcan_ioctl(struct tty_struct *tty, unsigned int cmd, struct slcan *sl = (struct slcan *)tty->disc_data; unsigned int tmp; - /* First make sure we're connected. */ - if (!sl || sl->magic != SLCAN_MAGIC) - return -EINVAL; - switch (cmd) { case SIOCGIFNAME: tmp = strlen(sl->dev->name) + 1; @@ -1025,13 +902,12 @@ static int slcan_ioctl(struct tty_struct *tty, unsigned int cmd, } } -static struct tty_ldisc_ops slc_ldisc = { +static struct tty_ldisc_ops slcan_ldisc = { .owner = THIS_MODULE, .num = N_SLCAN, - .name = "slcan", + .name = KBUILD_MODNAME, .open = slcan_open, .close = slcan_close, - .hangup = slcan_hangup, .ioctl = slcan_ioctl, .receive_buf = slcan_receive_buf, .write_wakeup = slcan_write_wakeup, @@ -1041,79 +917,22 @@ static int __init slcan_init(void) { int status; - if (maxdev < 4) - maxdev = 4; /* Sanity */ - - pr_info("slcan: serial line CAN interface driver\n"); - pr_info("slcan: %d dynamic interface channels.\n", maxdev); - - slcan_devs = kcalloc(maxdev, sizeof(struct net_device *), GFP_KERNEL); - if (!slcan_devs) - return -ENOMEM; + pr_info("serial line CAN interface driver\n"); /* Fill in our line protocol discipline, and register it */ - status = tty_register_ldisc(&slc_ldisc); - if (status) { - pr_err("slcan: can't register line discipline\n"); - kfree(slcan_devs); - } + status = tty_register_ldisc(&slcan_ldisc); + if (status) + pr_err("can't register line discipline\n"); + return status; } static void __exit slcan_exit(void) { - int i; - struct net_device *dev; - struct slcan *sl; - unsigned long timeout = jiffies + HZ; - int busy = 0; - - if (!slcan_devs) - return; - - /* First of all: check for active disciplines and hangup them. + /* This will only be called when all channels have been closed by + * userspace - tty_ldisc.c takes care of the module's refcount. */ - do { - if (busy) - msleep_interruptible(100); - - busy = 0; - for (i = 0; i < maxdev; i++) { - dev = slcan_devs[i]; - if (!dev) - continue; - sl = netdev_priv(dev); - spin_lock_bh(&sl->lock); - if (sl->tty) { - busy++; - tty_hangup(sl->tty); - } - spin_unlock_bh(&sl->lock); - } - } while (busy && time_before(jiffies, timeout)); - - /* FIXME: hangup is async so we should wait when doing this second - * phase - */ - - for (i = 0; i < maxdev; i++) { - dev = slcan_devs[i]; - if (!dev) - continue; - - sl = netdev_priv(dev); - if (sl->tty) - netdev_err(dev, "tty discipline still running\n"); - - slc_close(dev); - unregister_candev(dev); - slc_dealloc(sl); - } - - kfree(slcan_devs); - slcan_devs = NULL; - - tty_unregister_ldisc(&slc_ldisc); + tty_unregister_ldisc(&slcan_ldisc); } module_init(slcan_init); diff --git a/drivers/net/can/slcan/slcan-ethtool.c b/drivers/net/can/slcan/slcan-ethtool.c index bf0afdc4e49d..f598c653fbfa 100644 --- a/drivers/net/can/slcan/slcan-ethtool.c +++ b/drivers/net/can/slcan/slcan-ethtool.c @@ -52,14 +52,10 @@ static int slcan_get_sset_count(struct net_device *netdev, int sset) } } -static const struct ethtool_ops slcan_ethtool_ops = { +const struct ethtool_ops slcan_ethtool_ops = { .get_strings = slcan_get_strings, .get_priv_flags = slcan_get_priv_flags, .set_priv_flags = slcan_set_priv_flags, .get_sset_count = slcan_get_sset_count, + .get_ts_info = ethtool_op_get_ts_info, }; - -void slcan_set_ethtool_ops(struct net_device *netdev) -{ - netdev->ethtool_ops = &slcan_ethtool_ops; -} diff --git a/drivers/net/can/slcan/slcan.h b/drivers/net/can/slcan/slcan.h index d463c8d99e22..85cedf856db3 100644 --- a/drivers/net/can/slcan/slcan.h +++ b/drivers/net/can/slcan/slcan.h @@ -13,6 +13,7 @@ bool slcan_err_rst_on_open(struct net_device *ndev); int slcan_enable_err_rst_on_open(struct net_device *ndev, bool on); -void slcan_set_ethtool_ops(struct net_device *ndev); + +extern const struct ethtool_ops slcan_ethtool_ops; #endif /* _SLCAN_H */ diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c index 8d27ac66ca7f..a5ef57f415f7 100644 --- a/drivers/net/can/softing/softing_main.c +++ b/drivers/net/can/softing/softing_main.c @@ -5,6 +5,7 @@ * - Kurt Van Dijck, EIA Electronics */ +#include #include #include #include @@ -611,8 +612,12 @@ static const struct net_device_ops softing_netdev_ops = { .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 = { - .name = "softing", + .name = KBUILD_MODNAME, .tseg1_min = 1, .tseg1_max = 16, .tseg2_min = 1, @@ -649,6 +654,7 @@ static struct net_device *softing_netdev_create(struct softing *card, netdev->flags |= IFF_ECHO; netdev->netdev_ops = &softing_netdev_ops; + netdev->ethtool_ops = &softing_ethtool_ops; priv->can.do_set_mode = softing_candev_set_mode; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; @@ -846,7 +852,7 @@ platform_resource_failed: static struct platform_driver softing_driver = { .driver = { - .name = "softing", + .name = KBUILD_MODNAME, }, .probe = softing_pdev_probe, .remove = softing_pdev_remove, diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c index 167114aae6dd..b87dc420428d 100644 --- a/drivers/net/can/spi/hi311x.c +++ b/drivers/net/can/spi/hi311x.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -802,6 +803,10 @@ static const struct net_device_ops hi3110_netdev_ops = { .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[] = { { .compatible = "holt,hi3110", @@ -856,6 +861,7 @@ static int hi3110_can_probe(struct spi_device *spi) goto out_free; net->netdev_ops = &hi3110_netdev_ops; + net->ethtool_ops = &hi3110_ethtool_ops; net->flags |= IFF_ECHO; priv = netdev_priv(net); diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index 666a4505a55a..e750d13c8841 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1248,6 +1249,10 @@ static const struct net_device_ops mcp251x_netdev_ops = { .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[] = { { .compatible = "microchip,mcp2510", @@ -1313,6 +1318,7 @@ static int mcp251x_can_probe(struct spi_device *spi) goto out_free; net->netdev_ops = &mcp251x_netdev_ops; + net->ethtool_ops = &mcp251x_ethtool_ops; net->flags |= IFF_ECHO; priv = netdev_priv(net); diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c index 7fc86ed405c6..68df6d4641b5 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c @@ -1671,6 +1671,7 @@ static const struct net_device_ops mcp251xfd_netdev_ops = { .ndo_open = mcp251xfd_open, .ndo_stop = mcp251xfd_stop, .ndo_start_xmit = mcp251xfd_start_xmit, + .ndo_eth_ioctl = can_eth_ioctl_hwts, .ndo_change_mtu = can_change_mtu, }; diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c index c991b30bc9f0..004eaf96262b 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c @@ -253,7 +253,7 @@ void mcp251xfd_dump(const struct mcp251xfd_priv *priv) file_size += mcp251xfd_dump_reg_space[i].size / sizeof(u32) * sizeof(struct mcp251xfd_dump_object_reg); - /* TEF ring, RX ring, TX rings */ + /* TEF ring, RX rings, TX ring */ rings_num = 1 + priv->rx_ring_num + 1; obj_num += rings_num; file_size += rings_num * __MCP251XFD_DUMP_OBJECT_RING_KEY_MAX * diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c index 6c7a57f16cc6..3585f02575df 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c @@ -124,6 +124,7 @@ static const struct ethtool_ops mcp251xfd_ethtool_ops = { .set_ringparam = mcp251xfd_ring_set_ringparam, .get_coalesce = mcp251xfd_ring_get_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) diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c index b90dfb429ccd..525309da1320 100644 --- a/drivers/net/can/sun4i_can.c +++ b/drivers/net/can/sun4i_can.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -761,6 +762,10 @@ static const struct net_device_ops sun4ican_netdev_ops = { .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 = { .has_reset = false, }; @@ -851,6 +856,7 @@ static int sun4ican_probe(struct platform_device *pdev) } dev->netdev_ops = &sun4ican_netdev_ops; + dev->ethtool_ops = &sun4ican_ethtool_ops; dev->irq = irq; dev->flags |= IFF_ECHO; diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index afa38771520e..ec0ffeeb2015 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -841,6 +842,10 @@ static const struct net_device_ops ti_hecc_netdev_ops = { .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[] = { { .compatible = "ti,am3517-hecc", @@ -918,6 +923,7 @@ static int ti_hecc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); SET_NETDEV_DEV(ndev, &pdev->dev); ndev->netdev_ops = &ti_hecc_netdev_ops; + ndev->ethtool_ops = &ti_hecc_ethtool_ops; priv->clk = clk_get(&pdev->dev, "hecc_ck"); if (IS_ERR(priv->clk)) { diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index bbec3311d893..d1e1a459c045 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -4,6 +4,7 @@ * * Copyright (C) 2004-2009 EMS Dr. Thomas Wuensche */ +#include #include #include #include @@ -879,8 +880,12 @@ static const struct net_device_ops ems_usb_netdev_ops = { .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 = { - .name = "ems_usb", + .name = KBUILD_MODNAME, .tseg1_min = 1, .tseg1_max = 16, .tseg2_min = 1, @@ -990,6 +995,7 @@ static int ems_usb_probe(struct usb_interface *intf, dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; netdev->netdev_ops = &ems_usb_netdev_ops; + netdev->ethtool_ops = &ems_usb_ethtool_ops; netdev->flags |= IFF_ECHO; /* we support local echo */ @@ -1074,7 +1080,7 @@ static void ems_usb_disconnect(struct usb_interface *intf) /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver ems_usb_driver = { - .name = "ems_usb", + .name = KBUILD_MODNAME, .probe = ems_usb_probe, .disconnect = ems_usb_disconnect, .id_table = ems_usb_table, diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index 177ed33e08d9..1bcfad11b1e4 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -5,6 +5,7 @@ * Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs * Copyright (C) 2022 esd electronics gmbh, Frank Jungclaus */ +#include #include #include #include @@ -882,6 +883,10 @@ static const struct net_device_ops esd_usb_netdev_ops = { .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 = { .name = "esd_usb2", .tseg1_min = ESD_USB2_TSEG1_MIN, @@ -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->netdev_ops = &esd_usb_netdev_ops; + netdev->ethtool_ops = &esd_usb_ethtool_ops; SET_NETDEV_DEV(netdev, &intf->dev); netdev->dev_id = index; @@ -1138,7 +1144,7 @@ static void esd_usb_disconnect(struct usb_interface *intf) /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver esd_usb_driver = { - .name = "esd_usb", + .name = KBUILD_MODNAME, .probe = esd_usb_probe, .disconnect = esd_usb_disconnect, .id_table = esd_usb_table, diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c index 7353745f92d7..51294b717040 100644 --- a/drivers/net/can/usb/etas_es58x/es58x_core.c +++ b/drivers/net/can/usb/etas_es58x/es58x_core.c @@ -10,6 +10,7 @@ * Copyright (c) 2020, 2021 Vincent Mailhol */ +#include #include #include #include @@ -18,14 +19,11 @@ #include "es58x_core.h" -#define DRV_VERSION "1.00" MODULE_AUTHOR("Vincent Mailhol "); MODULE_AUTHOR("Arunachalam Santhanam "); MODULE_DESCRIPTION("Socket CAN driver for ETAS ES58X USB adapters"); -MODULE_VERSION(DRV_VERSION); MODULE_LICENSE("GPL v2"); -#define ES58X_MODULE_NAME "etas_es58x" #define ES58X_VENDOR_ID 0x108C #define ES581_4_PRODUCT_ID 0x0159 #define ES582_1_PRODUCT_ID 0x0168 @@ -59,11 +57,11 @@ MODULE_DEVICE_TABLE(usb, es58x_id_table); #define es58x_print_hex_dump(buf, len) \ print_hex_dump(KERN_DEBUG, \ - ES58X_MODULE_NAME " " __stringify(buf) ": ", \ + KBUILD_MODNAME " " __stringify(buf) ": ", \ DUMP_PREFIX_NONE, 16, 1, buf, len, false) #define es58x_print_hex_dump_debug(buf, len) \ - print_hex_dump_debug(ES58X_MODULE_NAME " " __stringify(buf) ": ",\ + print_hex_dump_debug(KBUILD_MODNAME " " __stringify(buf) ": ",\ DUMP_PREFIX_NONE, 16, 1, buf, len, false) /* The last two bytes of an ES58X command is a CRC16. The first two @@ -1462,10 +1460,6 @@ static void es58x_read_bulk_callback(struct urb *urb) } resubmit_urb: - usb_fill_bulk_urb(urb, es58x_dev->udev, es58x_dev->rx_pipe, - urb->transfer_buffer, urb->transfer_buffer_length, - es58x_read_bulk_callback, es58x_dev); - ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret == -ENODEV) { for (i = 0; i < es58x_dev->num_can_ch; i++) @@ -1599,7 +1593,8 @@ static struct urb *es58x_get_tx_urb(struct es58x_device *es58x_dev) return NULL; usb_fill_bulk_urb(urb, es58x_dev->udev, es58x_dev->tx_pipe, - buf, tx_buf_len, NULL, NULL); + buf, tx_buf_len, es58x_write_bulk_callback, + NULL); return urb; } @@ -1632,9 +1627,7 @@ static int es58x_submit_urb(struct es58x_device *es58x_dev, struct urb *urb, int ret; es58x_set_crc(urb->transfer_buffer, urb->transfer_buffer_length); - usb_fill_bulk_urb(urb, es58x_dev->udev, es58x_dev->tx_pipe, - urb->transfer_buffer, urb->transfer_buffer_length, - es58x_write_bulk_callback, netdev); + urb->context = netdev; usb_anchor_urb(urb, &es58x_dev->tx_urbs_busy); ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) { @@ -1981,7 +1974,12 @@ static netdev_tx_t es58x_start_xmit(struct sk_buff *skb, static const struct net_device_ops es58x_netdev_ops = { .ndo_open = es58x_open, .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, }; /** @@ -2088,6 +2086,7 @@ static int es58x_init_netdev(struct es58x_device *es58x_dev, int channel_idx) es58x_init_priv(es58x_dev, es58x_priv(netdev), channel_idx); netdev->netdev_ops = &es58x_netdev_ops; + netdev->ethtool_ops = &es58x_ethtool_ops; netdev->flags |= IFF_ECHO; /* We support local echo */ netdev->dev_port = channel_idx; @@ -2181,9 +2180,8 @@ static struct es58x_device *es58x_init_es58x_dev(struct usb_interface *intf, struct usb_endpoint_descriptor *ep_in, *ep_out; int ret; - dev_info(dev, - "Starting %s %s (Serial Number %s) driver version %s\n", - udev->manufacturer, udev->product, udev->serial, DRV_VERSION); + dev_info(dev, "Starting %s %s (Serial Number %s)\n", + udev->manufacturer, udev->product, udev->serial); ret = usb_find_common_endpoints(intf->cur_altsetting, &ep_in, &ep_out, NULL, NULL); @@ -2280,7 +2278,7 @@ static void es58x_disconnect(struct usb_interface *intf) } static struct usb_driver es58x_driver = { - .name = ES58X_MODULE_NAME, + .name = KBUILD_MODNAME, .probe = es58x_probe, .disconnect = es58x_disconnect, .id_table = es58x_id_table diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index d3a658b444b5..baf749c8cda3 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -946,6 +946,7 @@ static int gs_usb_set_phys_id(struct net_device *dev, static const struct ethtool_ops gs_usb_ethtool_ops = { .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, @@ -989,11 +990,12 @@ static struct gs_can *gs_make_candev(unsigned int channel, dev = netdev_priv(netdev); netdev->netdev_ops = &gs_usb_netdev_ops; + netdev->ethtool_ops = &gs_usb_ethtool_ops; netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */ /* dev setup */ - strcpy(dev->bt_const.name, "gs_usb"); + strcpy(dev->bt_const.name, KBUILD_MODNAME); dev->bt_const.tseg1_min = le32_to_cpu(bt_const->tseg1_min); dev->bt_const.tseg1_max = le32_to_cpu(bt_const->tseg1_max); dev->bt_const.tseg2_min = le32_to_cpu(bt_const->tseg2_min); @@ -1100,7 +1102,7 @@ static struct gs_can *gs_make_candev(unsigned int channel, return ERR_PTR(rc); } - strcpy(dev->data_bt_const.name, "gs_usb"); + strcpy(dev->data_bt_const.name, KBUILD_MODNAME); dev->data_bt_const.tseg1_min = le32_to_cpu(bt_const_extended->dtseg1_min); dev->data_bt_const.tseg1_max = le32_to_cpu(bt_const_extended->dtseg1_max); dev->data_bt_const.tseg2_min = le32_to_cpu(bt_const_extended->dtseg2_min); @@ -1270,7 +1272,7 @@ static const struct usb_device_id gs_usb_table[] = { MODULE_DEVICE_TABLE(usb, gs_usb_table); static struct usb_driver gs_usb_driver = { - .name = "gs_usb", + .name = KBUILD_MODNAME, .probe = gs_usb_probe, .disconnect = gs_usb_disconnect, .id_table = gs_usb_table, diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h index eefcbe3aadce..841da29cef93 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h @@ -39,6 +39,7 @@ #define KVASER_USB_QUIRK_HAS_SILENT_MODE BIT(0) #define KVASER_USB_QUIRK_HAS_TXRX_ERRORS BIT(1) #define KVASER_USB_QUIRK_IGNORE_CLK_FREQ BIT(2) +#define KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP BIT(3) /* Device capabilities */ #define KVASER_USB_CAP_BERR_CAP 0x01 diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c index f211bfcb1d97..824cab80aa02 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -89,7 +90,7 @@ #define USB_HYBRID_PRO_CANLIN_PRODUCT_ID 278 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, }; @@ -665,6 +666,22 @@ static const struct net_device_ops kvaser_usb_netdev_ops = { .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) { int i; @@ -742,7 +759,13 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) netdev->flags |= IFF_ECHO; 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); netdev->dev_id = channel; @@ -869,7 +892,7 @@ static void kvaser_usb_disconnect(struct usb_interface *intf) } static struct usb_driver kvaser_usb_driver = { - .name = "kvaser_usb", + .name = KBUILD_MODNAME, .probe = kvaser_usb_probe, .disconnect = kvaser_usb_disconnect, .id_table = kvaser_usb_table, diff --git a/drivers/net/can/usb/mcba_usb.c b/drivers/net/can/usb/mcba_usb.c index 792ab9da317d..69346c63021f 100644 --- a/drivers/net/can/usb/mcba_usb.c +++ b/drivers/net/can/usb/mcba_usb.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -758,6 +759,10 @@ static const struct net_device_ops mcba_netdev_ops = { .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. * This function sends request via USB to change the speed and align bittiming * values for presentation purposes only @@ -836,6 +841,7 @@ static int mcba_usb_probe(struct usb_interface *intf, priv->can.do_set_bittiming = mcba_net_set_bittiming; netdev->netdev_ops = &mcba_netdev_ops; + netdev->ethtool_ops = &mcba_ethtool_ops; netdev->flags |= IFF_ECHO; /* we support local echo */ diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index d07b7ee79e3e..687dd542f7f6 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -965,6 +965,7 @@ static int pcan_usb_set_phys_id(struct net_device *netdev, static const struct ethtool_ops pcan_usb_ethtool_ops = { .set_phys_id = pcan_usb_set_phys_id, + .get_ts_info = pcan_get_ts_info, }; /* diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 27b0a72fd885..8c9d53f6e24c 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -775,13 +775,54 @@ static int peak_usb_set_data_bittiming(struct net_device *netdev) 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 = { .ndo_open = peak_usb_ndo_open, .ndo_stop = peak_usb_ndo_stop, + .ndo_eth_ioctl = peak_eth_ioctl, .ndo_start_xmit = peak_usb_ndo_start_xmit, .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 * usb adapter. diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index 9c90487b9c92..f6bdd8b3f290 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -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); void peak_usb_async_complete(struct urb *urb); 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 diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 3d7e0e370505..2ea1500df393 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -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 = { .set_phys_id = pcan_usb_fd_set_phys_id, + .get_ts_info = pcan_get_ts_info, }; /* describes the PCAN-USB FD adapter */ diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 457887113e75..5d8f6a40bb2c 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -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 = { .set_phys_id = pcan_usb_pro_set_phys_id, + .get_ts_info = pcan_get_ts_info, }; /* diff --git a/drivers/net/can/usb/ucan.c b/drivers/net/can/usb/ucan.c index 5ae0d7c017cc..7c35f50fda4e 100644 --- a/drivers/net/can/usb/ucan.c +++ b/drivers/net/can/usb/ucan.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1233,6 +1234,10 @@ static const struct net_device_ops ucan_netdev_ops = { .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 * * This function generates an USB set bittiming message and transmits @@ -1512,6 +1517,7 @@ static int ucan_probe(struct usb_interface *intf, spin_lock_init(&up->context_lock); spin_lock_init(&up->echo_skb_lock); netdev->netdev_ops = &ucan_netdev_ops; + netdev->ethtool_ops = &ucan_ethtool_ops; usb_set_intfdata(intf, up); SET_NETDEV_DEV(netdev, &intf->dev); diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index 8b7cd69e20b0..64c00abe91cf 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -12,6 +12,7 @@ * who were very cooperative and answered my questions. */ +#include #include #include #include @@ -870,8 +871,12 @@ static const struct net_device_ops usb_8dev_netdev_ops = { .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 = { - .name = "usb_8dev", + .name = KBUILD_MODNAME, .tseg1_min = 1, .tseg1_max = 16, .tseg2_min = 1, @@ -927,6 +932,7 @@ static int usb_8dev_probe(struct usb_interface *intf, CAN_CTRLMODE_CC_LEN8_DLC; netdev->netdev_ops = &usb_8dev_netdev_ops; + netdev->ethtool_ops = &usb_8dev_ethtool_ops; netdev->flags |= IFF_ECHO; /* we support local echo */ @@ -997,7 +1003,7 @@ static void usb_8dev_disconnect(struct usb_interface *intf) } static struct usb_driver usb_8dev_driver = { - .name = "usb_8dev", + .name = KBUILD_MODNAME, .probe = usb_8dev_probe, .disconnect = usb_8dev_disconnect, .id_table = usb_8dev_table, diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index a15619d883ec..36b6310a2e5b 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -40,6 +40,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -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 */ loop = skb->pkt_type == PACKET_LOOPBACK; + skb_tx_timestamp(skb); + if (!echo) { /* no echo handling available inside this driver */ if (loop) { @@ -146,6 +149,10 @@ static const struct net_device_ops vcan_netdev_ops = { .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) { dev->type = ARPHRD_CAN; @@ -161,6 +168,7 @@ static void vcan_setup(struct net_device *dev) dev->flags |= IFF_ECHO; dev->netdev_ops = &vcan_netdev_ops; + dev->ethtool_ops = &vcan_ethtool_ops; dev->needs_free_netdev = true; } diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 577a80300514..cffd107d8b28 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -9,6 +9,7 @@ * Copyright (c) 2017 Oliver Hartkopp */ +#include #include #include #include @@ -53,6 +54,8 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev) goto out_unlock; } + skb_tx_timestamp(oskb); + skb = skb_clone(oskb, GFP_ATOMIC); if (skb) { consume_skb(oskb); @@ -144,6 +147,10 @@ static const struct net_device_ops vxcan_netdev_ops = { .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) { struct can_ml_priv *can_ml; @@ -155,6 +162,7 @@ static void vxcan_setup(struct net_device *dev) dev->tx_queue_len = 0; dev->flags = IFF_NOARP; dev->netdev_ops = &vxcan_netdev_ops; + dev->ethtool_ops = &vxcan_ethtool_ops; dev->needs_free_netdev = true; can_ml = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN); diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index caa6b4cee63f..5d3172795ad0 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1540,6 +1541,10 @@ static const struct net_device_ops xcan_netdev_ops = { .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 * @dev: Address of the device structure @@ -1821,6 +1826,7 @@ static int xcan_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); SET_NETDEV_DEV(ndev, &pdev->dev); ndev->netdev_ops = &xcan_netdev_ops; + ndev->ethtool_ops = &xcan_ethtool_ops; /* Getting the CAN can_clk info */ priv->can_clk = devm_clk_get(&pdev->dev, "can_clk"); diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index e22dc03c850e..c3e50e537e39 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -20,6 +20,7 @@ #include #include #include +#include #include /* @@ -162,6 +163,9 @@ struct can_priv *safe_candev_priv(struct net_device *dev); int open_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_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); void unregister_candev(struct net_device *dev);