diff options
Diffstat (limited to 'drivers/net/can/peak_canfd/peak_canfd.c')
-rw-r--r-- | drivers/net/can/peak_canfd/peak_canfd.c | 54 |
1 files changed, 51 insertions, 3 deletions
diff --git a/drivers/net/can/peak_canfd/peak_canfd.c b/drivers/net/can/peak_canfd/peak_canfd.c index b2dea360813d..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 <linux/can.h> #include <linux/can/dev.h> +#include <linux/ethtool.h> #include "peak_canfd_user.h" @@ -373,7 +374,7 @@ static int pucan_handle_status(struct peak_canfd_priv *priv, priv->can.state = CAN_STATE_ERROR_PASSIVE; priv->can.can_stats.error_passive++; if (skb) { - cf->can_id |= CAN_ERR_CRTL; + cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT; cf->data[1] = (priv->bec.txerr > priv->bec.rxerr) ? CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_RX_PASSIVE; @@ -386,7 +387,7 @@ static int pucan_handle_status(struct peak_canfd_priv *priv, priv->can.state = CAN_STATE_ERROR_WARNING; priv->can.can_stats.error_warning++; if (skb) { - cf->can_id |= CAN_ERR_CRTL; + cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT; cf->data[1] = (priv->bec.txerr > priv->bec.rxerr) ? CAN_ERR_CRTL_TX_WARNING : CAN_ERR_CRTL_RX_WARNING; @@ -430,7 +431,7 @@ static int pucan_handle_cache_critical(struct peak_canfd_priv *priv) return -ENOMEM; } - cf->can_id |= CAN_ERR_CRTL; + cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; cf->data[6] = priv->bec.txerr; @@ -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; |