diff options
Diffstat (limited to 'drivers/net/can/usb/kvaser_usb')
-rw-r--r-- | drivers/net/can/usb/kvaser_usb/kvaser_usb.h | 28 | ||||
-rw-r--r-- | drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 84 | ||||
-rw-r--r-- | drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c | 174 | ||||
-rw-r--r-- | drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 152 |
4 files changed, 257 insertions, 181 deletions
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h index ff10b3790d84..f6c77eca9f43 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h @@ -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 */ @@ -135,7 +137,7 @@ struct kvaser_usb_net_priv { * @dev_set_mode: used for can.do_set_mode * @dev_set_bittiming: used for can.do_set_bittiming * @dev_get_busparams: readback arbitration busparams - * @dev_set_data_bittiming: used for can.do_set_data_bittiming + * @dev_set_data_bittiming: used for can.fd.do_set_data_bittiming * @dev_get_data_busparams: readback data busparams * @dev_get_berr_counter: used for can.do_get_berr_counter * @@ -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 */ 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 8faf8a462c05..daf42080f942 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c @@ -89,9 +89,12 @@ #define USB_HYBRID_CANLIN_PRODUCT_ID 0x0115 #define USB_HYBRID_PRO_CANLIN_PRODUCT_ID 0x0116 #define USB_LEAF_V3_PRODUCT_ID 0x0117 +#define USB_VINING_800_PRODUCT_ID 0x0119 +#define USB_USBCAN_PRO_5XCAN_PRODUCT_ID 0x011A +#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, }; @@ -125,6 +128,7 @@ static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err_liste static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leafimx = { .quirks = 0, + .family = KVASER_LEAF, .ops = &kvaser_usb_leaf_dev_ops, }; @@ -238,6 +242,12 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_V3_PRODUCT_ID), .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_VINING_800_PRODUCT_ID), + .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5XCAN_PRODUCT_ID), + .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_1XCAN_PRODUCT_ID), + .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra }, { } }; MODULE_DEVICE_TABLE(usb, kvaser_usb_table); @@ -294,7 +304,7 @@ int kvaser_usb_send_cmd_async(struct kvaser_usb_net_priv *priv, void *cmd, } usb_free_urb(urb); - return 0; + return err; } int kvaser_usb_can_rx_over_error(struct net_device *netdev) @@ -582,7 +592,7 @@ static int kvaser_usb_set_data_bittiming(struct net_device *netdev) struct kvaser_usb_net_priv *priv = netdev_priv(netdev); struct kvaser_usb *dev = priv->dev; const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops; - struct can_bittiming *dbt = &priv->can.data_bittiming; + struct can_bittiming *dbt = &priv->can.fd.data_bittiming; struct kvaser_usb_busparams busparams; int tseg1 = dbt->prop_seg + dbt->phase_seg1; int tseg2 = dbt->phase_seg2; @@ -746,23 +756,12 @@ freeurb: 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, .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, }; @@ -819,7 +818,8 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) init_completion(&priv->stop_comp); init_completion(&priv->flush_comp); init_completion(&priv->get_busparams_comp); - priv->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC; + priv->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC | + CAN_CTRLMODE_BERR_REPORTING; priv->dev = dev; priv->netdev = netdev; @@ -842,20 +842,14 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) priv->can.ctrlmode_supported |= dev->card_data.ctrlmode_supported; if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) { - priv->can.data_bittiming_const = dev->cfg->data_bittiming_const; - priv->can.do_set_data_bittiming = kvaser_usb_set_data_bittiming; + priv->can.fd.data_bittiming_const = dev->cfg->data_bittiming_const; + priv->can.fd.do_set_data_bittiming = kvaser_usb_set_data_bittiming; } 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; @@ -905,10 +899,8 @@ static int kvaser_usb_probe(struct usb_interface *intf, ops = driver_info->ops; err = ops->dev_setup_endpoints(dev); - if (err) { - dev_err(&intf->dev, "Cannot get usb endpoint(s)"); - return err; - } + if (err) + return dev_err_probe(&intf->dev, err, "Cannot get usb endpoint(s)"); dev->udev = interface_to_usbdev(intf); @@ -919,26 +911,20 @@ static int kvaser_usb_probe(struct usb_interface *intf, dev->card_data.ctrlmode_supported = 0; dev->card_data.capabilities = 0; err = ops->dev_init_card(dev); - if (err) { - dev_err(&intf->dev, - "Failed to initialize card, error %d\n", err); - return err; - } + if (err) + return dev_err_probe(&intf->dev, err, + "Failed to initialize card\n"); err = ops->dev_get_software_info(dev); - if (err) { - dev_err(&intf->dev, - "Cannot get software info, error %d\n", err); - return err; - } + if (err) + return dev_err_probe(&intf->dev, err, + "Cannot get software info\n"); if (ops->dev_get_software_details) { err = ops->dev_get_software_details(dev); - if (err) { - dev_err(&intf->dev, - "Cannot get software details, error %d\n", err); - return err; - } + if (err) + return dev_err_probe(&intf->dev, err, + "Cannot get software details\n"); } if (WARN_ON(!dev->cfg)) @@ -952,18 +938,16 @@ static int kvaser_usb_probe(struct usb_interface *intf, dev_dbg(&intf->dev, "Max outstanding tx = %d URBs\n", dev->max_tx_urbs); err = ops->dev_get_card_info(dev); - if (err) { - dev_err(&intf->dev, "Cannot get card info, error %d\n", err); - return err; - } + if (err) + return dev_err_probe(&intf->dev, err, + "Cannot get card info\n"); if (ops->dev_get_capabilities) { err = ops->dev_get_capabilities(dev); if (err) { - dev_err(&intf->dev, - "Cannot get capabilities, error %d\n", err); kvaser_usb_remove_interfaces(dev); - return err; + return dev_err_probe(&intf->dev, err, + "Cannot get capabilities\n"); } } diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c index c7ba768dfe17..8e88b5917796 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c @@ -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, @@ -915,6 +926,42 @@ kvaser_usb_hydra_bus_status_to_can_state(const struct kvaser_usb_net_priv *priv, } } +static void kvaser_usb_hydra_change_state(struct kvaser_usb_net_priv *priv, + const struct can_berr_counter *bec, + struct can_frame *cf, + enum can_state new_state) +{ + struct net_device *netdev = priv->netdev; + enum can_state old_state = priv->can.state; + enum can_state tx_state, rx_state; + + tx_state = (bec->txerr >= bec->rxerr) ? + new_state : CAN_STATE_ERROR_ACTIVE; + rx_state = (bec->txerr <= bec->rxerr) ? + new_state : CAN_STATE_ERROR_ACTIVE; + can_change_state(netdev, cf, tx_state, rx_state); + + if (new_state == CAN_STATE_BUS_OFF && old_state < CAN_STATE_BUS_OFF) { + if (priv->can.restart_ms == 0) + kvaser_usb_hydra_send_simple_cmd_async(priv, CMD_STOP_CHIP_REQ); + + can_bus_off(netdev); + } + + if (priv->can.restart_ms && + old_state >= CAN_STATE_BUS_OFF && + new_state < CAN_STATE_BUS_OFF) { + priv->can.can_stats.restarts++; + if (cf) + cf->can_id |= CAN_ERR_RESTARTED; + } + if (cf && new_state != CAN_STATE_BUS_OFF) { + cf->can_id |= CAN_ERR_CNT; + cf->data[6] = bec->txerr; + cf->data[7] = bec->rxerr; + } +} + static void kvaser_usb_hydra_update_state(struct kvaser_usb_net_priv *priv, u8 bus_status, const struct can_berr_counter *bec) @@ -940,41 +987,11 @@ static void kvaser_usb_hydra_update_state(struct kvaser_usb_net_priv *priv, return; skb = alloc_can_err_skb(netdev, &cf); - if (skb) { - enum can_state tx_state, rx_state; - - tx_state = (bec->txerr >= bec->rxerr) ? - new_state : CAN_STATE_ERROR_ACTIVE; - rx_state = (bec->txerr <= bec->rxerr) ? - new_state : CAN_STATE_ERROR_ACTIVE; - can_change_state(netdev, cf, tx_state, rx_state); - } - - if (new_state == CAN_STATE_BUS_OFF && old_state < CAN_STATE_BUS_OFF) { - if (!priv->can.restart_ms) - kvaser_usb_hydra_send_simple_cmd_async - (priv, CMD_STOP_CHIP_REQ); - - can_bus_off(netdev); - } - - if (!skb) { + kvaser_usb_hydra_change_state(priv, bec, cf, new_state); + if (skb) + netif_rx(skb); + else netdev_warn(netdev, "No memory left for err_skb\n"); - return; - } - - if (priv->can.restart_ms && - old_state >= CAN_STATE_BUS_OFF && - new_state < CAN_STATE_BUS_OFF) - priv->can.can_stats.restarts++; - - if (new_state != CAN_STATE_BUS_OFF) { - cf->can_id |= CAN_ERR_CNT; - cf->data[6] = bec->txerr; - cf->data[7] = bec->rxerr; - } - - netif_rx(skb); } static void kvaser_usb_hydra_state_event(const struct kvaser_usb *dev, @@ -1067,9 +1084,8 @@ kvaser_usb_hydra_error_frame(struct kvaser_usb_net_priv *priv, { struct net_device *netdev = priv->netdev; struct net_device_stats *stats = &netdev->stats; - struct can_frame *cf; - struct sk_buff *skb; - struct skb_shared_hwtstamps *shhwtstamps; + struct can_frame *cf = NULL; + struct sk_buff *skb = NULL; struct can_berr_counter bec; enum can_state new_state, old_state; u8 bus_status; @@ -1085,52 +1101,26 @@ kvaser_usb_hydra_error_frame(struct kvaser_usb_net_priv *priv, kvaser_usb_hydra_bus_status_to_can_state(priv, bus_status, &bec, &new_state); - skb = alloc_can_err_skb(netdev, &cf); + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + skb = alloc_can_err_skb(netdev, &cf); + if (new_state != old_state) + kvaser_usb_hydra_change_state(priv, &bec, cf, new_state); - if (new_state != old_state) { + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { if (skb) { - enum can_state tx_state, rx_state; - - tx_state = (bec.txerr >= bec.rxerr) ? - new_state : CAN_STATE_ERROR_ACTIVE; - rx_state = (bec.txerr <= bec.rxerr) ? - new_state : CAN_STATE_ERROR_ACTIVE; + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); - can_change_state(netdev, cf, tx_state, rx_state); - - if (priv->can.restart_ms && - old_state >= CAN_STATE_BUS_OFF && - new_state < CAN_STATE_BUS_OFF) - cf->can_id |= CAN_ERR_RESTARTED; - } - - if (new_state == CAN_STATE_BUS_OFF) { - if (!priv->can.restart_ms) - kvaser_usb_hydra_send_simple_cmd_async - (priv, CMD_STOP_CHIP_REQ); - - can_bus_off(netdev); + shhwtstamps->hwtstamp = hwtstamp; + cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_CNT; + cf->data[6] = bec.txerr; + cf->data[7] = bec.rxerr; + netif_rx(skb); + } else { + stats->rx_dropped++; + netdev_warn(netdev, "No memory left for err_skb\n"); } } - if (!skb) { - stats->rx_dropped++; - netdev_warn(netdev, "No memory left for err_skb\n"); - return; - } - - shhwtstamps = skb_hwtstamps(skb); - shhwtstamps->hwtstamp = hwtstamp; - - cf->can_id |= CAN_ERR_BUSERROR; - if (new_state != CAN_STATE_BUS_OFF) { - cf->can_id |= CAN_ERR_CNT; - cf->data[6] = bec.txerr; - cf->data[7] = bec.rxerr; - } - - netif_rx(skb); - priv->bec.txerr = bec.txerr; priv->bec.rxerr = bec.rxerr; } @@ -1175,6 +1165,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 +1192,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 +1228,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 +1296,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, diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c index 23bd7574b1c7..6a45adcc45bd 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c @@ -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); @@ -1045,10 +1120,8 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv, static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev, const struct kvaser_usb_err_summary *es) { - struct can_frame *cf; - struct can_frame tmp_cf = { .can_id = CAN_ERR_FLAG, - .len = CAN_ERR_DLC }; - struct sk_buff *skb; + struct can_frame *cf = NULL; + struct sk_buff *skb = NULL; struct net_device_stats *stats; struct kvaser_usb_net_priv *priv; struct kvaser_usb_net_leaf_priv *leaf; @@ -1068,18 +1141,10 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev, if (!netif_running(priv->netdev)) return; - /* Update all of the CAN interface's state and error counters before - * trying any memory allocation that can actually fail with -ENOMEM. - * - * We send a temporary stack-allocated error CAN frame to - * can_change_state() for the very same reason. - * - * TODO: Split can_change_state() responsibility between updating the - * CAN interface's state and counters, and the setting up of CAN error - * frame ID and data to userspace. Remove stack allocation afterwards. - */ old_state = priv->can.state; - kvaser_usb_leaf_rx_error_update_can_state(priv, es, &tmp_cf); + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + skb = alloc_can_err_skb(priv->netdev, &cf); + kvaser_usb_leaf_rx_error_update_can_state(priv, es, cf); new_state = priv->can.state; /* If there are errors, request status updates periodically as we do @@ -1093,13 +1158,6 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev, schedule_delayed_work(&leaf->chip_state_req_work, msecs_to_jiffies(500)); - skb = alloc_can_err_skb(priv->netdev, &cf); - if (!skb) { - stats->rx_dropped++; - return; - } - memcpy(cf, &tmp_cf, sizeof(*cf)); - if (new_state != old_state) { if (es->status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) { @@ -1112,11 +1170,20 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev, if (priv->can.restart_ms && old_state == CAN_STATE_BUS_OFF && new_state < CAN_STATE_BUS_OFF) { - cf->can_id |= CAN_ERR_RESTARTED; + if (cf) + cf->can_id |= CAN_ERR_RESTARTED; netif_carrier_on(priv->netdev); } } + if (!skb) { + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { + stats->rx_dropped++; + netdev_warn(priv->netdev, "No memory left for err_skb\n"); + } + return; + } + switch (dev->driver_info->family) { case KVASER_LEAF: if (es->leaf.error_factor) { @@ -1299,6 +1366,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 +1397,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 +1445,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 +1579,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 +1625,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; |