Commit fa3c40b9 authored by Marc Kleine-Budde's avatar Marc Kleine-Budde

Merge patch series "can: kvaser_usb: Add hardware timestamp support to all devices"

Jimmy Assarsson <extja@kvaser.com> says:

This patch series add hardware timestamp support to all devices supported
by the kvaser_usb driver.

The first patches resolves a known issue; "Hardware timestamps are not set
for CAN Tx frames". I can't remember why this wasn't implemented in the
first version of the hydra driver.

Followed by, hardware timestamp support for leaf and usbcan based devices.

The final patches are removing code used for selecting the correct ethtool
and netdev ops.

Note: This patch series depends on patch
"can: kvaser_usb: Explicitly initialize family in leafimx..." [1].

[1] https://lore.kernel.org/linux-can/20240628194529.312968-1-extja@kvaser.com

Changes in v2:
- Replaced patch 3/15
  can: kvaser_usb: Add function kvaser_usb_ticks_to_ktime()
  with a new patch
  can: kvaser_usb: Add helper functions to convert device timestamp into ktime
  and put it first in this series
- Resolved Vincent MAILHOL's review comments regarding duplicated code when converting timestamps [2] [3]
- As pointed out by Vincent MAILHOL [4], the clock overflow commands is not
  dispatched in this patch
  moved code from 10/15
  can: kvaser_usb: leaf: Add structs for Tx ACK and clock overflow commands
  to 11/15
  can: kvaser_usb: leaf: Store MSB of timestamp
  where it's actually used

[2] https://lore.kernel.org/linux-can/CAMZ6RqKSa-6KjvgfmN9eL7A=A65gMkYsRrnaF41Azhsc45FA2Q@mail.gmail.com/
[3] https://lore.kernel.org/linux-can/CAMZ6Rq+Xd7+th=dKV+vrqzRtS+GY-xq2UziH1CURcQ3HxEXMqQ@mail.gmail.com/
[4] https://lore.kernel.org/linux-can/CAMZ6RqKqJX6eqogS2598BFm-AN1uOBbBGL+MkoJtR=-z379Q=w@mail.gmail.com/

Link: https://lore.kernel.org/all/20240701154936.92633-1-extja@kvaser.comSigned-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parents 0fe41a87 88371f85
......@@ -22,6 +22,8 @@
*/
#include <linux/completion.h>
#include <linux/ktime.h>
#include <linux/math64.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/usb.h>
......@@ -39,7 +41,6 @@
#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
......@@ -68,6 +69,7 @@ struct kvaser_usb_dev_card_data {
u32 ctrlmode_supported;
u32 capabilities;
struct kvaser_usb_dev_card_data_hydra hydra;
u32 usbcan_timestamp_msb;
};
/* Context for an outstanding, not yet ACKed, transmission */
......@@ -216,4 +218,26 @@ int kvaser_usb_can_rx_over_error(struct net_device *netdev);
extern const struct can_bittiming_const kvaser_usb_flexc_bittiming_const;
static inline ktime_t kvaser_usb_ticks_to_ktime(const struct kvaser_usb_dev_cfg *cfg,
u64 ticks)
{
return ns_to_ktime(div_u64(ticks * 1000, cfg->timestamp_freq));
}
static inline ktime_t kvaser_usb_timestamp48_to_ktime(const struct kvaser_usb_dev_cfg *cfg,
const __le16 *timestamp)
{
u64 ticks = le16_to_cpu(timestamp[0]) |
(u64)(le16_to_cpu(timestamp[1])) << 16 |
(u64)(le16_to_cpu(timestamp[2])) << 32;
return kvaser_usb_ticks_to_ktime(cfg, ticks);
}
static inline ktime_t kvaser_usb_timestamp64_to_ktime(const struct kvaser_usb_dev_cfg *cfg,
__le64 timestamp)
{
return kvaser_usb_ticks_to_ktime(cfg, le64_to_cpu(timestamp));
}
#endif /* KVASER_USB_H */
......@@ -94,7 +94,7 @@
#define USB_MINI_PCIE_1XCAN_PRODUCT_ID 0x011B
static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = {
.quirks = KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP,
.quirks = 0,
.ops = &kvaser_usb_hydra_dev_ops,
};
......@@ -754,13 +754,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
}
static const struct net_device_ops kvaser_usb_netdev_ops = {
.ndo_open = kvaser_usb_open,
.ndo_stop = kvaser_usb_close,
.ndo_start_xmit = kvaser_usb_start_xmit,
.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,
......@@ -769,10 +762,6 @@ static const struct net_device_ops kvaser_usb_netdev_ops_hwts = {
};
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,
};
......@@ -859,13 +848,7 @@ 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;
}
netdev->ethtool_ops = &kvaser_usb_ethtool_ops;
SET_NETDEV_DEV(netdev, &dev->intf->dev);
netdev->dev_id = channel;
......
......@@ -10,7 +10,6 @@
* - Transition from CAN_STATE_ERROR_WARNING to CAN_STATE_ERROR_ACTIVE is only
* reported after a call to do_get_berr_counter(), since firmware does not
* distinguish between ERROR_WARNING and ERROR_ACTIVE.
* - Hardware timestamps are not set for CAN Tx frames.
*/
#include <linux/completion.h>
......@@ -261,6 +260,15 @@ struct kvaser_cmd_tx_can {
u8 reserved[11];
} __packed;
struct kvaser_cmd_tx_ack {
__le32 id;
u8 data[8];
u8 dlc;
u8 flags;
__le16 timestamp[3];
u8 reserved0[8];
} __packed;
struct kvaser_cmd_header {
u8 cmd_no;
/* The destination HE address is stored in 0..5 of he_addr.
......@@ -297,6 +305,7 @@ struct kvaser_cmd {
struct kvaser_cmd_rx_can rx_can;
struct kvaser_cmd_tx_can tx_can;
struct kvaser_cmd_tx_ack tx_ack;
} __packed;
} __packed;
......@@ -522,23 +531,25 @@ kvaser_usb_hydra_net_priv_from_cmd(const struct kvaser_usb *dev,
return priv;
}
static ktime_t
kvaser_usb_hydra_ktime_from_rx_cmd(const struct kvaser_usb_dev_cfg *cfg,
const struct kvaser_cmd *cmd)
static ktime_t kvaser_usb_hydra_ktime_from_cmd(const struct kvaser_usb_dev_cfg *cfg,
const struct kvaser_cmd *cmd)
{
u64 ticks;
ktime_t hwtstamp = 0;
if (cmd->header.cmd_no == CMD_EXTENDED) {
struct kvaser_cmd_ext *cmd_ext = (struct kvaser_cmd_ext *)cmd;
ticks = le64_to_cpu(cmd_ext->rx_can.timestamp);
} else {
ticks = le16_to_cpu(cmd->rx_can.timestamp[0]);
ticks += (u64)(le16_to_cpu(cmd->rx_can.timestamp[1])) << 16;
ticks += (u64)(le16_to_cpu(cmd->rx_can.timestamp[2])) << 32;
if (cmd_ext->cmd_no_ext == CMD_RX_MESSAGE_FD)
hwtstamp = kvaser_usb_timestamp64_to_ktime(cfg, cmd_ext->rx_can.timestamp);
else if (cmd_ext->cmd_no_ext == CMD_TX_ACKNOWLEDGE_FD)
hwtstamp = kvaser_usb_timestamp64_to_ktime(cfg, cmd_ext->tx_ack.timestamp);
} else if (cmd->header.cmd_no == CMD_RX_MESSAGE) {
hwtstamp = kvaser_usb_timestamp48_to_ktime(cfg, cmd->rx_can.timestamp);
} else if (cmd->header.cmd_no == CMD_TX_ACKNOWLEDGE) {
hwtstamp = kvaser_usb_timestamp48_to_ktime(cfg, cmd->tx_ack.timestamp);
}
return ns_to_ktime(div_u64(ticks * 1000, cfg->timestamp_freq));
return hwtstamp;
}
static int kvaser_usb_hydra_send_simple_cmd(struct kvaser_usb *dev,
......@@ -1175,6 +1186,7 @@ static void kvaser_usb_hydra_tx_acknowledge(const struct kvaser_usb *dev,
bool one_shot_fail = false;
bool is_err_frame = false;
u16 transid = kvaser_usb_hydra_get_cmd_transid(cmd);
struct sk_buff *skb;
priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd);
if (!priv)
......@@ -1201,6 +1213,9 @@ static void kvaser_usb_hydra_tx_acknowledge(const struct kvaser_usb *dev,
spin_lock_irqsave(&priv->tx_contexts_lock, irq_flags);
skb = priv->can.echo_skb[context->echo_index];
if (skb)
skb_hwtstamps(skb)->hwtstamp = kvaser_usb_hydra_ktime_from_cmd(dev->cfg, cmd);
len = can_get_echo_skb(priv->netdev, context->echo_index, NULL);
context->echo_index = dev->max_tx_urbs;
--priv->active_tx_contexts;
......@@ -1234,7 +1249,7 @@ static void kvaser_usb_hydra_rx_msg_std(const struct kvaser_usb *dev,
stats = &priv->netdev->stats;
flags = cmd->rx_can.flags;
hwtstamp = kvaser_usb_hydra_ktime_from_rx_cmd(dev->cfg, cmd);
hwtstamp = kvaser_usb_hydra_ktime_from_cmd(dev->cfg, cmd);
if (flags & KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME) {
kvaser_usb_hydra_error_frame(priv, &cmd->rx_can.err_frame_data,
......@@ -1302,7 +1317,7 @@ static void kvaser_usb_hydra_rx_msg_ext(const struct kvaser_usb *dev,
KVASER_USB_KCAN_DATA_DLC_SHIFT;
flags = le32_to_cpu(cmd->rx_can.flags);
hwtstamp = kvaser_usb_hydra_ktime_from_rx_cmd(dev->cfg, std_cmd);
hwtstamp = kvaser_usb_hydra_ktime_from_cmd(dev->cfg, std_cmd);
if (flags & KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME) {
kvaser_usb_hydra_error_frame(priv, &cmd->rx_can.err_frame_data,
......
......@@ -119,6 +119,10 @@
/* Extended CAN identifier flag */
#define KVASER_EXTENDED_FRAME BIT(31)
/* USBCanII timestamp */
#define KVASER_USB_USBCAN_CLK_OVERFLOW_MASK GENMASK(31, 16)
#define KVASER_USB_USBCAN_TIMESTAMP_FACTOR 10
struct kvaser_cmd_simple {
u8 tid;
u8 channel;
......@@ -235,6 +239,20 @@ struct kvaser_cmd_tx_acknowledge_header {
u8 tid;
} __packed;
struct leaf_cmd_tx_acknowledge {
u8 channel;
u8 tid;
__le16 time[3];
u8 padding[2];
} __packed;
struct usbcan_cmd_tx_acknowledge {
u8 channel;
u8 tid;
__le16 time;
u8 padding[2];
} __packed;
struct leaf_cmd_can_error_event {
u8 tid;
u8 flags;
......@@ -281,6 +299,12 @@ struct usbcan_cmd_error_event {
__le16 padding;
} __packed;
struct usbcan_cmd_clk_overflow_event {
u8 tid;
u8 padding;
__le32 time;
} __packed;
struct kvaser_cmd_ctrl_mode {
u8 tid;
u8 channel;
......@@ -347,6 +371,7 @@ struct kvaser_cmd {
struct leaf_cmd_error_event error_event;
struct kvaser_cmd_cap_req cap_req;
struct kvaser_cmd_cap_res cap_res;
struct leaf_cmd_tx_acknowledge tx_ack;
} __packed leaf;
union {
......@@ -355,6 +380,8 @@ struct kvaser_cmd {
struct usbcan_cmd_chip_state_event chip_state_event;
struct usbcan_cmd_can_error_event can_error_event;
struct usbcan_cmd_error_event error_event;
struct usbcan_cmd_tx_acknowledge tx_ack;
struct usbcan_cmd_clk_overflow_event clk_overflow_event;
} __packed usbcan;
struct kvaser_cmd_tx_can tx_can;
......@@ -370,7 +397,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
[CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
[CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
[CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo),
[CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.tx_acknowledge_header),
[CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.leaf.tx_ack),
[CMD_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.leaf.softinfo),
[CMD_RX_STD_MESSAGE] = kvaser_fsize(u.leaf.rx_can),
[CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.leaf.rx_can),
......@@ -388,15 +415,14 @@ static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
[CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
[CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
[CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo),
[CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.tx_acknowledge_header),
[CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.usbcan.tx_ack),
[CMD_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.usbcan.softinfo),
[CMD_RX_STD_MESSAGE] = kvaser_fsize(u.usbcan.rx_can),
[CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.usbcan.rx_can),
[CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.usbcan.chip_state_event),
[CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.can_error_event),
[CMD_ERROR_EVENT] = kvaser_fsize(u.usbcan.error_event),
/* ignored events: */
[CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY,
[CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = kvaser_fsize(u.usbcan.clk_overflow_event),
};
/* Summary of a kvaser error event, for a unified Leaf/Usbcan error
......@@ -463,11 +489,27 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_usbcan_dev_cfg = {
.bittiming_const = &kvaser_usb_leaf_m16c_bittiming_const,
};
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg = {
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg_16mhz = {
.clock = {
.freq = 16 * MEGA /* Hz */,
},
.timestamp_freq = 1,
.timestamp_freq = 16,
.bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
};
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg_24mhz = {
.clock = {
.freq = 16 * MEGA /* Hz */,
},
.timestamp_freq = 24,
.bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
};
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg_32mhz = {
.clock = {
.freq = 16 * MEGA /* Hz */,
},
.timestamp_freq = 32,
.bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
};
......@@ -475,7 +517,7 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_16mhz = {
.clock = {
.freq = 16 * MEGA /* Hz */,
},
.timestamp_freq = 1,
.timestamp_freq = 16,
.bittiming_const = &kvaser_usb_flexc_bittiming_const,
};
......@@ -483,7 +525,7 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_24mhz = {
.clock = {
.freq = 24 * MEGA /* Hz */,
},
.timestamp_freq = 1,
.timestamp_freq = 24,
.bittiming_const = &kvaser_usb_flexc_bittiming_const,
};
......@@ -491,10 +533,19 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_32mhz = {
.clock = {
.freq = 32 * MEGA /* Hz */,
},
.timestamp_freq = 1,
.timestamp_freq = 32,
.bittiming_const = &kvaser_usb_flexc_bittiming_const,
};
static inline ktime_t kvaser_usb_usbcan_timestamp_to_ktime(const struct kvaser_usb *dev,
__le16 timestamp)
{
u64 ticks = le16_to_cpu(timestamp) |
dev->card_data.usbcan_timestamp_msb;
return kvaser_usb_ticks_to_ktime(dev->cfg, ticks * KVASER_USB_USBCAN_TIMESTAMP_FACTOR);
}
static int kvaser_usb_leaf_verify_size(const struct kvaser_usb *dev,
const struct kvaser_cmd *cmd)
{
......@@ -678,8 +729,19 @@ static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
/* Firmware expects bittiming parameters calculated for 16MHz
* clock, regardless of the actual clock
* Though, the reported freq is used for timestamps
*/
dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg;
switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg_16mhz;
break;
case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg_24mhz;
break;
case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg_32mhz;
break;
}
} else {
switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
......@@ -880,6 +942,8 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
struct kvaser_usb_net_priv *priv;
unsigned long flags;
u8 channel, tid;
struct sk_buff *skb;
ktime_t hwtstamp = 0;
channel = cmd->u.tx_acknowledge_header.channel;
tid = cmd->u.tx_acknowledge_header.tid;
......@@ -901,14 +965,14 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
/* Sometimes the state change doesn't come after a bus-off event */
if (priv->can.restart_ms && priv->can.state == CAN_STATE_BUS_OFF) {
struct sk_buff *skb;
struct sk_buff *err_skb;
struct can_frame *cf;
skb = alloc_can_err_skb(priv->netdev, &cf);
if (skb) {
err_skb = alloc_can_err_skb(priv->netdev, &cf);
if (err_skb) {
cf->can_id |= CAN_ERR_RESTARTED;
netif_rx(skb);
netif_rx(err_skb);
} else {
netdev_err(priv->netdev,
"No memory left for err_skb\n");
......@@ -919,9 +983,20 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
switch (dev->driver_info->family) {
case KVASER_LEAF:
hwtstamp = kvaser_usb_timestamp48_to_ktime(dev->cfg, cmd->u.leaf.tx_ack.time);
break;
case KVASER_USBCAN:
hwtstamp = kvaser_usb_usbcan_timestamp_to_ktime(dev, cmd->u.usbcan.tx_ack.time);
break;
}
spin_lock_irqsave(&priv->tx_contexts_lock, flags);
skb = priv->can.echo_skb[context->echo_index];
if (skb)
skb_hwtstamps(skb)->hwtstamp = hwtstamp;
stats->tx_packets++;
stats->tx_bytes += can_get_echo_skb(priv->netdev,
context->echo_index, NULL);
......@@ -1299,6 +1374,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
struct net_device_stats *stats;
u8 channel = cmd->u.rx_can_header.channel;
const u8 *rx_data = NULL; /* GCC */
ktime_t hwtstamp = 0;
if (channel >= dev->nchannels) {
dev_err(&dev->intf->dev,
......@@ -1329,9 +1405,11 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
switch (dev->driver_info->family) {
case KVASER_LEAF:
rx_data = cmd->u.leaf.rx_can.data;
hwtstamp = kvaser_usb_timestamp48_to_ktime(dev->cfg, cmd->u.leaf.rx_can.time);
break;
case KVASER_USBCAN:
rx_data = cmd->u.usbcan.rx_can.data;
hwtstamp = kvaser_usb_usbcan_timestamp_to_ktime(dev, cmd->u.usbcan.rx_can.time);
break;
}
......@@ -1375,6 +1453,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
memcpy(cf->data, &rx_data[6], cf->len);
}
skb_hwtstamps(skb)->hwtstamp = hwtstamp;
stats->rx_packets++;
if (!(cf->can_id & CAN_RTR_FLAG))
stats->rx_bytes += cf->len;
......@@ -1508,7 +1587,7 @@ static void kvaser_usb_leaf_get_busparams_reply(const struct kvaser_usb *dev,
complete(&priv->get_busparams_comp);
}
static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
static void kvaser_usb_leaf_handle_command(struct kvaser_usb *dev,
const struct kvaser_cmd *cmd)
{
if (kvaser_usb_leaf_verify_size(dev, cmd) < 0)
......@@ -1554,12 +1633,15 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
kvaser_usb_leaf_get_busparams_reply(dev, cmd);
break;
/* Ignored commands */
case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
if (dev->driver_info->family != KVASER_USBCAN)
goto warn;
dev->card_data.usbcan_timestamp_msb =
le32_to_cpu(cmd->u.usbcan.clk_overflow_event.time) &
KVASER_USB_USBCAN_CLK_OVERFLOW_MASK;
break;
/* Ignored commands */
case CMD_FLUSH_QUEUE_REPLY:
if (dev->driver_info->family != KVASER_LEAF)
goto warn;
......
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