can: kvaser_usb: Don't free packets when tight on URBs
Subsystems (4)
PATCH 1/1 can: kvaser_usb: Don't free packets when tight on URBs
From: Ahmed S. Darwish <[email protected]>
Flooding the Kvaser CAN to USB dongle with multiple reads and writes in high frequency caused seemingly-random panics in the kernel.
On further inspection, it seems the driver erroneously freed the to-be-transmitted packet upon getting tight on URBs and returning NETDEV_TX_BUSY, leading to invalid memory writes and double frees at a later point in time.
--- drivers/net/can/usb/kvaser_usb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
(Generated over 3.19.0-rc1)
drivers/net/can/usb/kvaser_usb.c +5 -3
@@ -1286,6 +1286,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,struct kvaser_msg *msg;int i, err;int ret =NETDEV_TX_OK ; +bool kfree_skb_on_error = true;if (can_dropped_invalid_skb (netdev, skb))return NETDEV_TX_OK ;
@@ -1336,6 +1337,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (!context) {netdev_warn (netdev,"cannot find free context\n" ); + kfree_skb_on_error = false; ret =NETDEV_TX_BUSY ; goto releasebuf; }
@@ -1364,8 +1366,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (unlikely (err)) {can_free_echo_skb (netdev, context->echo_index); - skb =NULL ;/* set to NULL to avoid double free in -* dev_kfree_skb(skb) */ + kfree_skb_on_error = false;atomic_dec (&priv->active_tx_urbs);usb_unanchor_urb (urb);
@@ -1389,7 +1390,8 @@ releasebuf: nobufmem:usb_free_urb (urb); nourbmem: -dev_kfree_skb (skb); +if (kfree_skb_on_error) +dev_kfree_skb (skb);return ret; }
PATCH 1/1 can: kvaser_usb: Add support for the Usbcan-II family
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'UsbcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
This patch adds support for the UsbcanII family of devices to the current Kvaser Leaf-only driver.
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
--- drivers/net/can/usb/kvaser_usb.c | 630 +++++++++++++++++++++++++++++++-------- 1 file changed, 505 insertions(+), 125 deletions(-)
(Generated over 3.19.0-rc1 + generic bugfix at
can-kvaser_usb-Don-t-free-packets-when-tight-on-URBs.patch)
drivers/net/can/usb/kvaser_usb.c +505 -125
@@ -6,12 +6,15 @@* Parts of this driver are based on the following: * - Kvaser linux leaf driver (version 4.78) * - CAN driver for esd CAN-USB/2 +* - Kvaser linux usbcanII driver (version 5.3) * * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. * Copyright (C) 2010 Matthias Fuchs <[email protected]>, esd gmbh * Copyright (C) 2012 Olivier Sobrie <[email protected]> +* Copyright (C) 2014 Valeo Corporation */ +#include <linux/kernel.h> #include <linux/completion.h> #include <linux/module.h> #include <linux/netdevice.h>
@@ -21,6 +24,18 @@#include <linux/can/dev.h> #include <linux/can/error.h> +#define MAX (a, b) ((a) > (b) ? (a) : (b)) + +/* +* Kvaser USB CAN dongles are divided into two major families: +* - Leaf: Based on Renesas M32C, running firmware labeled as 'filo' +* - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios' +*/ +enum kvaser_usb_family { +KVASER_LEAF , +KVASER_USBCAN , +}; +#define MAX_TX_URBS 16#define MAX_RX_URBS 4#define START_TIMEOUT 1000/* msecs */
@@ -29,9 +44,12 @@#define USB_RECV_TIMEOUT 1000/* msecs */ #define RX_BUFFER_SIZE 3072#define CAN_USB_CLOCK 8000000 -#define MAX_NET_DEVICES 3 +#define LEAF_MAX_NET_DEVICES 3 +#define USBCAN_MAX_NET_DEVICES 2 +#define MAX_NET_DEVICES MAX(LEAF_MAX_NET_DEVICES, \ + USBCAN_MAX_NET_DEVICES) -/* Kvaser USB devices */ +/* Leaf USB devices */ #define KVASER_VENDOR_ID 0x0bfd#define USB_LEAF_DEVEL_PRODUCT_ID 10#define USB_LEAF_LITE_PRODUCT_ID 11
@@ -55,6 +73,16 @@#define USB_CAN_R_PRODUCT_ID 39#define USB_LEAF_LITE_V2_PRODUCT_ID 288#define USB_MINI_PCIE_HS_PRODUCT_ID 289 +#define LEAF_PRODUCT_ID (id) (id >= USB_LEAF_DEVEL_PRODUCT_ID && \ + id <= USB_MINI_PCIE_HS_PRODUCT_ID) + +/* USBCANII devices */ +#define USB_USBCAN_REVB_PRODUCT_ID 2 +#define USB_VCI2_PRODUCT_ID 3 +#define USB_USBCAN2_PRODUCT_ID 4 +#define USB_MEMORATOR_PRODUCT_ID 5 +#define USBCAN_PRODUCT_ID (id) (id >= USB_USBCAN_REVB_PRODUCT_ID && \ + id <= USB_MEMORATOR_PRODUCT_ID)/* USB devices features */ #define KVASER_HAS_SILENT_MODE BIT(0)
@@ -73,7 +101,7 @@#define MSG_FLAG_TX_ACK BIT(6)#define MSG_FLAG_TX_REQUEST BIT(7) -/* Can states */ +/* Can states (M16C CxSTRH register) */ #define M16C_STATE_BUS_RESET BIT(0)#define M16C_STATE_BUS_ERROR BIT(4)#define M16C_STATE_BUS_PASSIVE BIT(5)
@@ -98,7 +126,13 @@#define CMD_START_CHIP_REPLY 27#define CMD_STOP_CHIP 28#define CMD_STOP_CHIP_REPLY 29 -#define CMD_GET_CARD_INFO2 32 +#define CMD_READ_CLOCK 30 +#define CMD_READ_CLOCK_REPLY 31 + +#define LEAF_CMD_GET_CARD_INFO2 32 +#define USBCAN_CMD_RESET_CLOCK 32 +#define USBCAN_CMD_CLOCK_OVERFLOW_EVENT 33 +#define CMD_GET_CARD_INFO 34#define CMD_GET_CARD_INFO_REPLY 35#define CMD_GET_SOFTWARE_INFO 38
@@ -108,8 +142,9 @@#define CMD_RESET_ERROR_COUNTER 49#define CMD_TX_ACKNOWLEDGE 50#define CMD_CAN_ERROR_EVENT 51 -#define CMD_USB_THROTTLE 77 -#define CMD_LOG_MESSAGE 106 + +#define LEAF_CMD_USB_THROTTLE 77 +#define LEAF_CMD_LOG_MESSAGE 106/* error factors */ #define M16C_EF_ACKE BIT(0)
@@ -121,6 +156,13 @@#define M16C_EF_RCVE BIT(6)#define M16C_EF_TRE BIT(7) +/* Only Leaf-based devices can report M16C error factors, +* thus define our own error status flags for USBCAN */ +#define USBCAN_ERROR_STATE_NONE 0 +#define USBCAN_ERROR_STATE_TX_ERROR BIT(0) +#define USBCAN_ERROR_STATE_RX_ERROR BIT(1) +#define USBCAN_ERROR_STATE_BUSERROR BIT(2) +/* bittiming parameters */ #define KVASER_USB_TSEG1_MIN 1#define KVASER_USB_TSEG1_MAX 16
@@ -137,7 +179,7 @@#define KVASER_CTRL_MODE_SELFRECEPTION 3#define KVASER_CTRL_MODE_OFF 4 -/* log message */ +/* Extended CAN identifier flag */ #define KVASER_EXTENDED_FRAME BIT(31)struct kvaser_msg_simple {
@@ -148,30 +190,55 @@ struct kvaser_msg_simple {struct kvaser_msg_cardinfo {u8 tid;u8 nchannels; -__le32 serial_number; -__le32 padding; +union { +struct { +__le32 serial_number; +__le32 padding; + } __packed leaf0; +struct { +__le32 serial_number_low; +__le32 serial_number_high; + } __packed usbcan0; + } __packed;__le32 clock_resolution;__le32 mfgdate;u8 ean[8 ];u8 hw_revision; -u8 usb_hs_mode; -__le16 padding2; +union { +struct { +u8 usb_hs_mode; + } __packed leaf1; +struct { +u8 padding; + } __packed usbcan1; + } __packed; +__le16 padding; } __packed;struct kvaser_msg_cardinfo2 {u8 tid; -u8 channel; +u8 reserved;u8 pcb_id[24 ];__le32 oem_unlock_code; } __packed; -struct kvaser_msg_softinfo { +struct leaf_msg_softinfo {u8 tid; -u8 channel; +u8 padding0;__le32 sw_options;__le32 fw_version;__le16 max_outstanding_tx; -__le16 padding[9 ]; +__le16 padding1[9 ]; +} __packed; + +struct usbcan_msg_softinfo { +u8 tid; +u8 fw_name[5 ]; +__le16 max_outstanding_tx; +u8 padding[6 ]; +__le32 fw_version; +__le16 checksum; +__le16 sw_options; } __packed;struct kvaser_msg_busparams {
@@ -188,36 +255,86 @@ struct kvaser_msg_tx_can {u8 channel;u8 tid;u8 msg[14 ]; -u8 padding; -u8 flags; +union { +struct { +u8 padding; +u8 flags; + } __packed leaf; +struct { +u8 flags; +u8 padding; + } __packed usbcan; + } __packed; +} __packed; + +struct kvaser_msg_rx_can_header { +u8 channel; +u8 flag; } __packed; -struct kvaser_msg_rx_can { +struct leaf_msg_rx_can {u8 channel;u8 flag; +__le16 time[3 ];u8 msg[14 ]; } __packed; -struct kvaser_msg_chip_state_event { +struct usbcan_msg_rx_can { +u8 channel; +u8 flag; + +u8 msg[14 ]; +__le16 time; +} __packed; + +struct leaf_msg_chip_state_event {u8 tid;u8 channel; +__le16 time[3 ];u8 tx_errors_count;u8 rx_errors_count; +u8 status;u8 padding[3 ]; } __packed; -struct kvaser_msg_tx_acknowledge { +struct usbcan_msg_chip_state_event { +u8 tid; +u8 channel; + +u8 tx_errors_count; +u8 rx_errors_count; +__le16 time; + +u8 status; +u8 padding[3 ]; +} __packed; + +struct kvaser_msg_tx_acknowledge_header { +u8 channel; +u8 tid; +}; + +struct leaf_msg_tx_acknowledge {u8 channel;u8 tid; +__le16 time[3 ];u8 flags;u8 time_offset; } __packed; -struct kvaser_msg_error_event { +struct usbcan_msg_tx_acknowledge { +u8 channel; +u8 tid; + +__le16 time; +__le16 padding; +} __packed; + +struct leaf_msg_error_event {u8 tid;u8 flags;__le16 time[3 ];
@@ -229,6 +346,18 @@ struct kvaser_msg_error_event {u8 error_factor; } __packed; +struct usbcan_msg_error_event { +u8 tid; +u8 padding; +u8 tx_errors_count_ch0; +u8 rx_errors_count_ch0; +u8 tx_errors_count_ch1; +u8 rx_errors_count_ch1; +u8 status_ch0; +u8 status_ch1; +__le16 time; +} __packed; +struct kvaser_msg_ctrl_mode {u8 tid;u8 channel;
@@ -243,7 +372,7 @@ struct kvaser_msg_flush_queue {u8 padding[3 ]; } __packed; -struct kvaser_msg_log_message { +struct leaf_msg_log_message {u8 channel;u8 flags;__le16 time[3 ];
@@ -260,19 +389,49 @@ struct kvaser_msg {struct kvaser_msg_simple simple;struct kvaser_msg_cardinfo cardinfo;struct kvaser_msg_cardinfo2 cardinfo2; -struct kvaser_msg_softinfo softinfo;struct kvaser_msg_busparams busparams; + +struct kvaser_msg_rx_can_header rx_can_header; +struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header; + +union { +struct leaf_msg_softinfo softinfo; +struct leaf_msg_rx_can rx_can; +struct leaf_msg_chip_state_event chip_state_event; +struct leaf_msg_tx_acknowledge tx_acknowledge; +struct leaf_msg_error_event error_event; +struct leaf_msg_log_message log_message; + } __packed leaf; + +union { +struct usbcan_msg_softinfo softinfo; +struct usbcan_msg_rx_can rx_can; +struct usbcan_msg_chip_state_event chip_state_event; +struct usbcan_msg_tx_acknowledge tx_acknowledge; +struct usbcan_msg_error_event error_event; + } __packed usbcan; +struct kvaser_msg_tx_can tx_can; -struct kvaser_msg_rx_can rx_can; -struct kvaser_msg_chip_state_event chip_state_event; -struct kvaser_msg_tx_acknowledge tx_acknowledge; -struct kvaser_msg_error_event error_event;struct kvaser_msg_ctrl_mode ctrl_mode;struct kvaser_msg_flush_queue flush_queue; -struct kvaser_msg_log_message log_message; } u; } __packed; +/* Leaf/USBCAN-agnostic summary of an error event. +* No M16C error factors for USBCAN-based devices. */ +struct kvaser_error_summary { +u8 channel, status, txerr, rxerr; +union { +struct { +u8 error_factor; + } leaf; +struct { +u8 other_ch_status; +u8 error_state; + } usbcan; + }; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;
@@ -288,6 +447,8 @@ struct kvaser_usb {u32 fw_version;unsigned int nchannels; +enum kvaser_usb_family family; +unsigned int max_channels;bool rxinitdone;void *rxbuf[MAX_RX_URBS ];
@@ -311,6 +472,7 @@ struct kvaser_usb_net_priv { };static const struct usb_device_id kvaser_usb_table[] = { +/* Leaf family IDs */ {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_DEVEL_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_LITE_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_PRO_PRODUCT_ID ),
@@ -360,6 +522,17 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = KVASER_HAS_TXRX_ERRORS }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, + +/* USBCANII family IDs */ + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { } };MODULE_DEVICE_TABLE (usb, kvaser_usb_table);
@@ -463,7 +636,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)if (err)return err; - dev->fw_version =le32_to_cpu (msg.u.softinfo.fw_version); +switch (dev->family) { +case KVASER_LEAF : + dev->fw_version =le32_to_cpu (msg.u.leaf.softinfo.fw_version); +break ; +case KVASER_USBCAN : + dev->fw_version =le32_to_cpu (msg.u.usbcan.softinfo.fw_version); +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); +return -EINVAL ; + }return 0 ; }
@@ -482,7 +666,7 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)return err; dev->nchannels = msg.u.cardinfo.nchannels; -if (dev->nchannels >MAX_NET_DEVICES ) +if (dev->nchannels > dev->max_channels)return -EINVAL ;return 0 ;
@@ -496,8 +680,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,struct kvaser_usb_net_priv *priv;struct sk_buff *skb;struct can_frame *cf; -u8 channel = msg->u.tx_acknowledge.channel; -u8 tid = msg->u.tx_acknowledge.tid; +u8 channel, tid; + + channel = msg->u.tx_acknowledge_header.channel; + tid = msg->u.tx_acknowledge_header.tid;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,
@@ -615,37 +801,83 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index =MAX_TX_URBS ; } -static void kvaser_usb_rx_error (const struct kvaser_usb *dev, -const struct kvaser_msg *msg) +static void kvaser_report_error_event (const struct kvaser_usb *dev, +struct kvaser_error_summary *es); + +/* +* Report error to userspace iff the controller's errors counter has +* increased, or we're the only channel seeing the bus error state. +* +* As reported by USBCAN sheets, "the CAN controller has difficulties +* to tell whether an error frame arrived on channel 1 or on channel 2." +* Thus, error counters are compared with their earlier values to +* determine which channel was responsible for the error event. +*/ +static void usbcan_report_error_if_applicable (const struct kvaser_usb *dev, +struct kvaser_error_summary *es) { -struct can_frame *cf; -struct sk_buff *skb; -struct net_device_stats *stats;struct kvaser_usb_net_priv *priv; -unsigned int new_state; -u8 channel, status, txerr, rxerr, error_factor; +int old_tx_err_count, old_rx_err_count, channel, report_error; + + channel = es->channel; +if (channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , channel); +return ; + } + + priv = dev->nets[channel]; + old_tx_err_count = priv->bec.txerr; + old_rx_err_count = priv->bec.rxerr; + + report_error =0 ; +if (es->txerr > old_tx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_TX_ERROR ; + report_error =1 ; + } +if (es->rxerr > old_rx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_RX_ERROR ; + report_error =1 ; + } +if ((es->status &M16C_STATE_BUS_ERROR ) && + !(es->usbcan.other_ch_status &M16C_STATE_BUS_ERROR )) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_BUSERROR ; + report_error =1 ; + } + +if (report_error) +kvaser_report_error_event (dev, es); +} + +/* +* Extract error summary from a Leaf-based device error message +*/ +static void leaf_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , };switch (msg->id) {case CMD_CAN_ERROR_EVENT : - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; + es.channel = msg->u.leaf.error_event.channel; + es.status = msg->u.leaf.error_event.status; + es.txerr = msg->u.leaf.error_event.tx_errors_count; + es.rxerr = msg->u.leaf.error_event.rx_errors_count; + es.leaf.error_factor = msg->u.leaf.error_event.error_factor;break ; -case CMD_LOG_MESSAGE : - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0 ]; - txerr = msg->u.log_message.data[2 ]; - rxerr = msg->u.log_message.data[3 ]; - error_factor = msg->u.log_message.data[1 ]; +case LEAF_CMD_LOG_MESSAGE : + es.channel = msg->u.leaf.log_message.channel; + es.status = msg->u.leaf.log_message.data[0 ]; + es.txerr = msg->u.leaf.log_message.data[2 ]; + es.rxerr = msg->u.leaf.log_message.data[3 ]; + es.leaf.error_factor = msg->u.leaf.log_message.data[1 ];break ;case CMD_CHIP_STATE_EVENT : - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor =0 ; + es.channel = msg->u.leaf.chip_state_event.channel; + es.status = msg->u.leaf.chip_state_event.status; + es.txerr = msg->u.leaf.chip_state_event.tx_errors_count; + es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count; + es.leaf.error_factor =0 ;break ;default : dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
@@ -653,16 +885,92 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,return ; } -if (channel >= dev->nchannels) { +kvaser_report_error_event (dev, &es); +} + +/* +* Extract summary from a USBCANII-based device error message. +*/ +static void usbcan_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , }; + +switch (msg->id) { + +/* Sometimes errors are sent as unsolicited chip state events */ +case CMD_CHIP_STATE_EVENT : + es.channel = msg->u.usbcan.chip_state_event.channel; + es.status = msg->u.usbcan.chip_state_event.status; + es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count; + es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count; +usbcan_report_error_if_applicable (dev, &es); +break ; + +case CMD_CAN_ERROR_EVENT : + es.channel =0 ; + es.status = msg->u.usbcan.error_event.status_ch0; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch1; +usbcan_report_error_if_applicable (dev, &es); + +/* For error events, the USBCAN firmware does not support +* more than 2 channels: ch0, and ch1. */ +if (dev->nchannels >1 ) { + es.channel =1 ; + es.status = msg->u.usbcan.error_event.status_ch1; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch0; +usbcan_report_error_if_applicable (dev, &es); + } +break ; + +default : +dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , + msg->id); + } +} + +static void kvaser_usb_rx_error (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +switch (dev->family) { +case KVASER_LEAF : +leaf_extract_error_from_msg (dev, msg); +break ; +case KVASER_USBCAN : +usbcan_extract_error_from_msg (dev, msg); +break ; +default :dev_err (dev->udev->dev.parent, -"Invalid channel number (%d)\n" , channel); +"Invalid device family (%d)\n" , dev->family);return ; } +} - priv = dev->nets[channel]; +static void kvaser_report_error_event (const struct kvaser_usb *dev, +struct kvaser_error_summary *es) +{ +struct can_frame *cf; +struct sk_buff *skb; +struct net_device_stats *stats; +struct kvaser_usb_net_priv *priv; +unsigned int new_state; + +if (es->channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , es->channel); +return ; + } + + priv = dev->nets[es->channel]; stats = &priv->netdev->stats; -if (status &M16C_STATE_BUS_RESET ) { +if (es->status &M16C_STATE_BUS_RESET ) {kvaser_usb_unlink_tx_urbs (priv);return ; }
@@ -675,9 +983,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, new_state = priv->can.state; -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (status &M16C_STATE_BUS_OFF ) { +if (es->status &M16C_STATE_BUS_OFF ) { cf->can_id |=CAN_ERR_BUSOFF ; priv->can.can_stats.bus_off++;
@@ -687,12 +995,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,netif_carrier_off (priv->netdev); new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { + }else if (es->status &M16C_STATE_BUS_PASSIVE ) {if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es->txerr || es->rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else
@@ -703,13 +1011,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } new_state =CAN_STATE_ERROR_PASSIVE ; - } - -if (status ==M16C_STATE_BUS_ERROR ) { + }else if (es->status &M16C_STATE_BUS_ERROR ) {if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { + ((es->txerr >=96 ) || (es->rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ;
@@ -723,7 +1029,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } } -if (!status) { +if (!es->status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ;
@@ -739,34 +1045,52 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv->can.can_stats.restarts++; } -if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - - cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; - -if (error_factor &M16C_EF_ACKE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); -if (error_factor &M16C_EF_CRCE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | -CAN_ERR_PROT_LOC_CRC_DEL ); -if (error_factor &M16C_EF_FORME ) - cf->data[2 ] |=CAN_ERR_PROT_FORM ; -if (error_factor &M16C_EF_STFE ) - cf->data[2 ] |=CAN_ERR_PROT_STUFF ; -if (error_factor &M16C_EF_BITE0 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; -if (error_factor &M16C_EF_BITE1 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; -if (error_factor &M16C_EF_TRE ) - cf->data[2 ] |=CAN_ERR_PROT_TX ; +switch (dev->family) { +case KVASER_LEAF : +if (es->leaf.error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; + +if (es->leaf.error_factor &M16C_EF_ACKE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); +if (es->leaf.error_factor &M16C_EF_CRCE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | +CAN_ERR_PROT_LOC_CRC_DEL ); +if (es->leaf.error_factor &M16C_EF_FORME ) + cf->data[2 ] |=CAN_ERR_PROT_FORM ; +if (es->leaf.error_factor &M16C_EF_STFE ) + cf->data[2 ] |=CAN_ERR_PROT_STUFF ; +if (es->leaf.error_factor &M16C_EF_BITE0 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; +if (es->leaf.error_factor &M16C_EF_BITE1 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; +if (es->leaf.error_factor &M16C_EF_TRE ) + cf->data[2 ] |=CAN_ERR_PROT_TX ; + } +break ; +case KVASER_USBCAN : +if (es->usbcan.error_state &USBCAN_ERROR_STATE_TX_ERROR ) + stats->tx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_RX_ERROR ) + stats->rx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_BUSERROR ) { + priv->can.can_stats.bus_error++; + cf->can_id |=CAN_ERR_BUSERROR ; + } +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto err; } - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; + cf->data[6 ] = es->txerr; + cf->data[7 ] = es->rxerr; - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; priv->can.state = new_state;
@@ -774,6 +1098,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + +return ; + +err: +dev_kfree_skb (skb); } static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
@@ -783,16 +1112,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,struct sk_buff *skb;struct net_device_stats *stats = &priv->netdev->stats; -if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | +if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |MSG_FLAG_NERR )) {netdev_err (priv->netdev,"Unknow error (flags: 0x%02x)\n" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); stats->rx_errors++;return ; } -if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { +if (msg->u.rx_can_header.flag &MSG_FLAG_OVERRUN ) { skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;
@@ -819,7 +1148,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,struct can_frame *cf;struct sk_buff *skb;struct net_device_stats *stats; -u8 channel = msg->u.rx_can.channel; +u8 channel = msg->u.rx_can_header.channel; +const u8 *rx_msg;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,
@@ -830,19 +1160,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; -if ((msg->u.rx_can.flag &MSG_FLAG_ERROR_FRAME ) && - (msg->id ==CMD_LOG_MESSAGE )) { +if ((msg->u.rx_can_header.flag &MSG_FLAG_ERROR_FRAME ) && + (dev->family ==KVASER_LEAF && msg->id ==LEAF_CMD_LOG_MESSAGE )) {kvaser_usb_rx_error (dev, msg);return ; - }else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | -MSG_FLAG_NERR | -MSG_FLAG_OVERRUN )) { + }else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME | +MSG_FLAG_NERR | +MSG_FLAG_OVERRUN )) {kvaser_usb_rx_can_err (priv, msg);return ; - }else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME ) { + }else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME ) {netdev_warn (priv->netdev,"Unhandled frame (flags: 0x%02x)" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); +return ; + } + +switch (dev->family) { +case KVASER_LEAF : + rx_msg = msg->u.leaf.rx_can.msg; +break ; +case KVASER_USBCAN : + rx_msg = msg->u.usbcan.rx_can.msg; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family);return ; }
@@ -852,38 +1195,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,return ; } -if (msg->id ==CMD_LOG_MESSAGE ) { - cf->can_id =le32_to_cpu (msg->u.log_message.id); +if (dev->family ==KVASER_LEAF && msg->id ==LEAF_CMD_LOG_MESSAGE ) { + cf->can_id =le32_to_cpu (msg->u.leaf.log_message.id);if (cf->can_id &KVASER_EXTENDED_FRAME ) cf->can_id &=CAN_EFF_MASK |CAN_EFF_FLAG ;else cf->can_id &=CAN_SFF_MASK ; - cf->can_dlc =get_can_dlc (msg->u.log_message.dlc); + cf->can_dlc =get_can_dlc (msg->u.leaf.log_message.dlc); -if (msg->u.log_message.flags &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.leaf.log_message.flags &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.log_message.data, +memcpy (cf->data, &msg->u.leaf.log_message.data, cf->can_dlc); }else { - cf->can_id = ((msg->u.rx_can.msg[0 ] &0x1f ) <<6 ) | - (msg->u.rx_can.msg[1 ] &0x3f ); + cf->can_id = ((rx_msg[0 ] &0x1f ) <<6 ) | (rx_msg[1 ] &0x3f );if (msg->id ==CMD_RX_EXT_MESSAGE ) { cf->can_id <<=18 ; - cf->can_id |= ((msg->u.rx_can.msg[2 ] &0x0f ) <<14 ) | - ((msg->u.rx_can.msg[3 ] &0xff ) <<6 ) | - (msg->u.rx_can.msg[4 ] &0x3f ); + cf->can_id |= ((rx_msg[2 ] &0x0f ) <<14 ) | + ((rx_msg[3 ] &0xff ) <<6 ) | + (rx_msg[4 ] &0x3f ); cf->can_id |=CAN_EFF_FLAG ; } - cf->can_dlc =get_can_dlc (msg->u.rx_can.msg[5 ]); + cf->can_dlc =get_can_dlc (rx_msg[5 ]); -if (msg->u.rx_can.flag &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.rx_can_header.flag &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.rx_can.msg[6 ], +memcpy (cf->data, &rx_msg[6 ], cf->can_dlc); }
@@ -947,7 +1289,12 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,case CMD_RX_STD_MESSAGE :case CMD_RX_EXT_MESSAGE : -case CMD_LOG_MESSAGE : +kvaser_usb_rx_can_msg (dev, msg); +break ; + +case LEAF_CMD_LOG_MESSAGE : +if (dev->family !=KVASER_LEAF ) + goto warn;kvaser_usb_rx_can_msg (dev, msg);break ;
@@ -960,8 +1307,14 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,kvaser_usb_tx_acknowledge (dev, msg);break ; +/* Ignored messages */ +case USBCAN_CMD_CLOCK_OVERFLOW_EVENT : +if (dev->family !=KVASER_USBCAN ) + goto warn; +break ; +default : -dev_warn (dev->udev->dev.parent, +warn:dev_warn (dev->udev->dev.parent,"Unhandled message (%d)\n" , msg->id);break ; }
@@ -1181,7 +1534,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) dev->rxbuf[i], dev->rxbuf_dma[i]); -for (i =0 ; i <MAX_NET_DEVICES ; i++) { +for (i =0 ; i < dev->max_channels; i++) {struct kvaser_usb_net_priv *priv = dev->nets[i];if (priv)
@@ -1286,6 +1639,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,struct kvaser_msg *msg;int i, err;int ret =NETDEV_TX_OK ; +uint8_t *msg_tx_can_flags;bool kfree_skb_on_error = true;if (can_dropped_invalid_skb (netdev, skb))
@@ -1306,9 +1660,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, msg = buf; msg->len =MSG_HEADER_LEN +sizeof (struct kvaser_msg_tx_can ); - msg->u.tx_can.flags =0 ; msg->u.tx_can.channel = priv->channel; +switch (dev->family) { +case KVASER_LEAF : + msg_tx_can_flags = &msg->u.tx_can.leaf.flags; +break ; +case KVASER_USBCAN : + msg_tx_can_flags = &msg->u.tx_can.usbcan.flags; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto releasebuf; + } + + *msg_tx_can_flags =0 ; +if (cf->can_id &CAN_EFF_FLAG ) { msg->id =CMD_TX_EXT_MESSAGE ; msg->u.tx_can.msg[0 ] = (cf->can_id >>24 ) &0x1f ;
@@ -1326,7 +1694,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,memcpy (&msg->u.tx_can.msg[6 ], cf->data, cf->can_dlc);if (cf->can_id &CAN_RTR_FLAG ) - msg->u.tx_can.flags |=MSG_FLAG_REMOTE_FRAME ; + *msg_tx_can_flags |=MSG_FLAG_REMOTE_FRAME ;for (i =0 ; i <ARRAY_SIZE (priv->tx_contexts); i++) {if (priv->tx_contexts[i].echo_index ==MAX_TX_URBS ) {
@@ -1596,6 +1964,18 @@ static int kvaser_usb_probe(struct usb_interface *intf,if (!dev)return -ENOMEM ; +if (LEAF_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_LEAF ; + dev->max_channels =LEAF_MAX_NET_DEVICES ; + }else if (USBCAN_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_USBCAN ; + dev->max_channels =USBCAN_MAX_NET_DEVICES ; + }else { +dev_err (&intf->dev,"Product ID (%d) does not belong to any " +"known Kvaser USB family" , id->idProduct); +return -ENODEV ; + } + err =kvaser_usb_get_endpoints (intf, &dev->bulk_in, &dev->bulk_out);if (err) {dev_err (&intf->dev,"Cannot get usb endpoint(s)" );
@@ -1608,7 +1988,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev); -for (i =0 ; i <MAX_NET_DEVICES ; i++) +for (i =0 ; i < dev->max_channels; i++)kvaser_usb_send_simple_msg (dev,CMD_RESET_CHIP , i); err =kvaser_usb_get_software_info (dev);
Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
Hello Ahmed,
Quoted 7 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'UsbcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
Quoted 6 lines
This patch adds support for the UsbcanII family of devices to the current Kvaser Leaf-only driver.
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
Good, thank you :-) I'll try to test the patch during the next week-end. Small remarks below.
Quoted 30 lines
Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 630 +++++++++++++++++++++++++++++++-------- 1 file changed, 505 insertions(+), 125 deletions(-)(Generated over 3.19.0-rc1 + generic bugfix at
can-kvaser_usb-Don-t-free-packets-when-tight-on-URBs.patch)drivers/net/can/usb/kvaser_usb.c +3
-0@@ -6,12 +6,15 @@* Parts of this driver are based on the following: * - Kvaser linux leaf driver (version 4.78) * - CAN driver for esd CAN-USB/2 +* - Kvaser linux usbcanII driver (version 5.3) * * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. * Copyright (C) 2010 Matthias Fuchs <[email protected]>, esd gmbh * Copyright (C) 2012 Olivier Sobrie <[email protected]> +* Copyright (C) 2014 Valeo Corporation */ +#include <linux/kernel.h> #include <linux/completion.h> #include <linux/module.h> #include <linux/netdevice.h>
drivers/net/can/usb/kvaser_usb.c line 27
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +1
-0@@ -21,6 +24,18 @@#include <linux/can/dev.h> #include <linux/can/error.h> +#define MAX (a, b) ((a) > (b) ? (a) : (b))
There is a max(a, b) macro in <linux/kernel.h>.
Quoted 402 lines
drivers/net/can/usb/kvaser_usb.c +209
-29+ +/* +* Kvaser USB CAN dongles are divided into two major families: +* - Leaf: Based on Renesas M32C, running firmware labeled as 'filo' +* - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios' +*/ +enum kvaser_usb_family { +KVASER_LEAF , +KVASER_USBCAN , +}; +#define MAX_TX_URBS 16#define MAX_RX_URBS 4#define START_TIMEOUT 1000/* msecs */ @@ -29,9 +44,12 @@#define USB_RECV_TIMEOUT 1000/* msecs */ #define RX_BUFFER_SIZE 3072#define CAN_USB_CLOCK 8000000 -#define MAX_NET_DEVICES 3 +#define LEAF_MAX_NET_DEVICES 3 +#define USBCAN_MAX_NET_DEVICES 2 +#define MAX_NET_DEVICES MAX(LEAF_MAX_NET_DEVICES, \ + USBCAN_MAX_NET_DEVICES) -/* Kvaser USB devices */ +/* Leaf USB devices */ #define KVASER_VENDOR_ID 0x0bfd#define USB_LEAF_DEVEL_PRODUCT_ID 10#define USB_LEAF_LITE_PRODUCT_ID 11@@ -55,6 +73,16 @@#define USB_CAN_R_PRODUCT_ID 39#define USB_LEAF_LITE_V2_PRODUCT_ID 288#define USB_MINI_PCIE_HS_PRODUCT_ID 289 +#define LEAF_PRODUCT_ID (id) (id >= USB_LEAF_DEVEL_PRODUCT_ID && \ + id <= USB_MINI_PCIE_HS_PRODUCT_ID) + +/* USBCANII devices */ +#define USB_USBCAN_REVB_PRODUCT_ID 2 +#define USB_VCI2_PRODUCT_ID 3 +#define USB_USBCAN2_PRODUCT_ID 4 +#define USB_MEMORATOR_PRODUCT_ID 5 +#define USBCAN_PRODUCT_ID (id) (id >= USB_USBCAN_REVB_PRODUCT_ID && \ + id <= USB_MEMORATOR_PRODUCT_ID)/* USB devices features */ #define KVASER_HAS_SILENT_MODE BIT(0)@@ -73,7 +101,7 @@#define MSG_FLAG_TX_ACK BIT(6)#define MSG_FLAG_TX_REQUEST BIT(7) -/* Can states */ +/* Can states (M16C CxSTRH register) */ #define M16C_STATE_BUS_RESET BIT(0)#define M16C_STATE_BUS_ERROR BIT(4)#define M16C_STATE_BUS_PASSIVE BIT(5)@@ -98,7 +126,13 @@#define CMD_START_CHIP_REPLY 27#define CMD_STOP_CHIP 28#define CMD_STOP_CHIP_REPLY 29 -#define CMD_GET_CARD_INFO2 32 +#define CMD_READ_CLOCK 30 +#define CMD_READ_CLOCK_REPLY 31 + +#define LEAF_CMD_GET_CARD_INFO2 32 +#define USBCAN_CMD_RESET_CLOCK 32 +#define USBCAN_CMD_CLOCK_OVERFLOW_EVENT 33 +#define CMD_GET_CARD_INFO 34#define CMD_GET_CARD_INFO_REPLY 35#define CMD_GET_SOFTWARE_INFO 38@@ -108,8 +142,9 @@#define CMD_RESET_ERROR_COUNTER 49#define CMD_TX_ACKNOWLEDGE 50#define CMD_CAN_ERROR_EVENT 51 -#define CMD_USB_THROTTLE 77 -#define CMD_LOG_MESSAGE 106 + +#define LEAF_CMD_USB_THROTTLE 77 +#define LEAF_CMD_LOG_MESSAGE 106/* error factors */ #define M16C_EF_ACKE BIT(0)@@ -121,6 +156,13 @@#define M16C_EF_RCVE BIT(6)#define M16C_EF_TRE BIT(7) +/* Only Leaf-based devices can report M16C error factors, +* thus define our own error status flags for USBCAN */ +#define USBCAN_ERROR_STATE_NONE 0 +#define USBCAN_ERROR_STATE_TX_ERROR BIT(0) +#define USBCAN_ERROR_STATE_RX_ERROR BIT(1) +#define USBCAN_ERROR_STATE_BUSERROR BIT(2) +/* bittiming parameters */ #define KVASER_USB_TSEG1_MIN 1#define KVASER_USB_TSEG1_MAX 16@@ -137,7 +179,7 @@#define KVASER_CTRL_MODE_SELFRECEPTION 3#define KVASER_CTRL_MODE_OFF 4 -/* log message */ +/* Extended CAN identifier flag */ #define KVASER_EXTENDED_FRAME BIT(31)struct kvaser_msg_simple {@@ -148,30 +190,55 @@ struct kvaser_msg_simple {struct kvaser_msg_cardinfo {u8 tid;u8 nchannels; -__le32 serial_number; -__le32 padding; +union { +struct { +__le32 serial_number; +__le32 padding; + } __packed leaf0; +struct { +__le32 serial_number_low; +__le32 serial_number_high; + } __packed usbcan0; + } __packed;__le32 clock_resolution;__le32 mfgdate;u8 ean[8 ];u8 hw_revision; -u8 usb_hs_mode; -__le16 padding2; +union { +struct { +u8 usb_hs_mode; + } __packed leaf1; +struct { +u8 padding; + } __packed usbcan1; + } __packed; +__le16 padding; } __packed;struct kvaser_msg_cardinfo2 {u8 tid; -u8 channel; +u8 reserved;u8 pcb_id[24 ];__le32 oem_unlock_code; } __packed; -struct kvaser_msg_softinfo { +struct leaf_msg_softinfo {u8 tid; -u8 channel; +u8 padding0;__le32 sw_options;__le32 fw_version;__le16 max_outstanding_tx; -__le16 padding[9 ]; +__le16 padding1[9 ]; +} __packed; + +struct usbcan_msg_softinfo { +u8 tid; +u8 fw_name[5 ]; +__le16 max_outstanding_tx; +u8 padding[6 ]; +__le32 fw_version; +__le16 checksum; +__le16 sw_options; } __packed;struct kvaser_msg_busparams {@@ -188,36 +255,86 @@ struct kvaser_msg_tx_can {u8 channel;u8 tid;u8 msg[14 ]; -u8 padding; -u8 flags; +union { +struct { +u8 padding; +u8 flags; + } __packed leaf; +struct { +u8 flags; +u8 padding; + } __packed usbcan; + } __packed; +} __packed; + +struct kvaser_msg_rx_can_header { +u8 channel; +u8 flag; } __packed; -struct kvaser_msg_rx_can { +struct leaf_msg_rx_can {u8 channel;u8 flag; +__le16 time[3 ];u8 msg[14 ]; } __packed; -struct kvaser_msg_chip_state_event { +struct usbcan_msg_rx_can { +u8 channel; +u8 flag; + +u8 msg[14 ]; +__le16 time; +} __packed; + +struct leaf_msg_chip_state_event {u8 tid;u8 channel; +__le16 time[3 ];u8 tx_errors_count;u8 rx_errors_count; +u8 status;u8 padding[3 ]; } __packed; -struct kvaser_msg_tx_acknowledge { +struct usbcan_msg_chip_state_event { +u8 tid; +u8 channel; + +u8 tx_errors_count; +u8 rx_errors_count; +__le16 time; + +u8 status; +u8 padding[3 ]; +} __packed; + +struct kvaser_msg_tx_acknowledge_header { +u8 channel; +u8 tid; +}; + +struct leaf_msg_tx_acknowledge {u8 channel;u8 tid; +__le16 time[3 ];u8 flags;u8 time_offset; } __packed; -struct kvaser_msg_error_event { +struct usbcan_msg_tx_acknowledge { +u8 channel; +u8 tid; + +__le16 time; +__le16 padding; +} __packed; + +struct leaf_msg_error_event {u8 tid;u8 flags;__le16 time[3 ];@@ -229,6 +346,18 @@ struct kvaser_msg_error_event {u8 error_factor; } __packed; +struct usbcan_msg_error_event { +u8 tid; +u8 padding; +u8 tx_errors_count_ch0; +u8 rx_errors_count_ch0; +u8 tx_errors_count_ch1; +u8 rx_errors_count_ch1; +u8 status_ch0; +u8 status_ch1; +__le16 time; +} __packed; +struct kvaser_msg_ctrl_mode {u8 tid;u8 channel;@@ -243,7 +372,7 @@ struct kvaser_msg_flush_queue {u8 padding[3 ]; } __packed; -struct kvaser_msg_log_message { +struct leaf_msg_log_message {u8 channel;u8 flags;__le16 time[3 ];@@ -260,19 +389,49 @@ struct kvaser_msg {struct kvaser_msg_simple simple;struct kvaser_msg_cardinfo cardinfo;struct kvaser_msg_cardinfo2 cardinfo2; -struct kvaser_msg_softinfo softinfo;struct kvaser_msg_busparams busparams; + +struct kvaser_msg_rx_can_header rx_can_header; +struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header; + +union { +struct leaf_msg_softinfo softinfo; +struct leaf_msg_rx_can rx_can; +struct leaf_msg_chip_state_event chip_state_event; +struct leaf_msg_tx_acknowledge tx_acknowledge; +struct leaf_msg_error_event error_event; +struct leaf_msg_log_message log_message; + } __packed leaf; + +union { +struct usbcan_msg_softinfo softinfo; +struct usbcan_msg_rx_can rx_can; +struct usbcan_msg_chip_state_event chip_state_event; +struct usbcan_msg_tx_acknowledge tx_acknowledge; +struct usbcan_msg_error_event error_event; + } __packed usbcan; +struct kvaser_msg_tx_can tx_can; -struct kvaser_msg_rx_can rx_can; -struct kvaser_msg_chip_state_event chip_state_event; -struct kvaser_msg_tx_acknowledge tx_acknowledge; -struct kvaser_msg_error_event error_event;struct kvaser_msg_ctrl_mode ctrl_mode;struct kvaser_msg_flush_queue flush_queue; -struct kvaser_msg_log_message log_message; } u; } __packed; +/* Leaf/USBCAN-agnostic summary of an error event. +* No M16C error factors for USBCAN-based devices. */ +struct kvaser_error_summary { +u8 channel, status, txerr, rxerr; +union { +struct { +u8 error_factor; + } leaf; +struct { +u8 other_ch_status; +u8 error_state; + } usbcan; + }; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;@@ -288,6 +447,8 @@ struct kvaser_usb {u32 fw_version;unsigned int nchannels; +enum kvaser_usb_family family; +unsigned int max_channels;bool rxinitdone;void *rxbuf[MAX_RX_URBS ];@@ -311,6 +472,7 @@ struct kvaser_usb_net_priv { };static const struct usb_device_id kvaser_usb_table[] = { +/* Leaf family IDs */ {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_DEVEL_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_LITE_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_PRO_PRODUCT_ID ),@@ -360,6 +522,17 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = KVASER_HAS_TXRX_ERRORS }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, + +/* USBCANII family IDs */ + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { } };MODULE_DEVICE_TABLE (usb, kvaser_usb_table);@@ -463,7 +636,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)if (err)return err; - dev->fw_version =le32_to_cpu (msg.u.softinfo.fw_version); +switch (dev->family) { +case KVASER_LEAF : + dev->fw_version =le32_to_cpu (msg.u.leaf.softinfo.fw_version); +break ; +case KVASER_USBCAN : + dev->fw_version =le32_to_cpu (msg.u.usbcan.softinfo.fw_version); +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); +return -EINVAL ; + }return 0 ; }
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_get_card_info(struct kvaser_usb *dev) · line 670
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c +1
-1@@ -482,7 +666,7 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)return err; dev->nchannels = msg.u.cardinfo.nchannels; -if (dev->nchannels >MAX_NET_DEVICES ) +if (dev->nchannels > dev->max_channels)return -EINVAL ;
IMHO, you can keep MAX_NET_DEVICES here.
Quoted 515 lines
drivers/net/can/usb/kvaser_usb.c +260
-91return 0 ;@@ -496,8 +680,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,struct kvaser_usb_net_priv *priv;struct sk_buff *skb;struct can_frame *cf; -u8 channel = msg->u.tx_acknowledge.channel; -u8 tid = msg->u.tx_acknowledge.tid; +u8 channel, tid; + + channel = msg->u.tx_acknowledge_header.channel; + tid = msg->u.tx_acknowledge_header.tid;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,@@ -615,37 +801,83 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index =MAX_TX_URBS ; } -static void kvaser_usb_rx_error (const struct kvaser_usb *dev, -const struct kvaser_msg *msg) +static void kvaser_report_error_event (const struct kvaser_usb *dev, +struct kvaser_error_summary *es); + +/* +* Report error to userspace iff the controller's errors counter has +* increased, or we're the only channel seeing the bus error state. +* +* As reported by USBCAN sheets, "the CAN controller has difficulties +* to tell whether an error frame arrived on channel 1 or on channel 2." +* Thus, error counters are compared with their earlier values to +* determine which channel was responsible for the error event. +*/ +static void usbcan_report_error_if_applicable (const struct kvaser_usb *dev, +struct kvaser_error_summary *es) { -struct can_frame *cf; -struct sk_buff *skb; -struct net_device_stats *stats;struct kvaser_usb_net_priv *priv; -unsigned int new_state; -u8 channel, status, txerr, rxerr, error_factor; +int old_tx_err_count, old_rx_err_count, channel, report_error; + + channel = es->channel; +if (channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , channel); +return ; + } + + priv = dev->nets[channel]; + old_tx_err_count = priv->bec.txerr; + old_rx_err_count = priv->bec.rxerr; + + report_error =0 ; +if (es->txerr > old_tx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_TX_ERROR ; + report_error =1 ; + } +if (es->rxerr > old_rx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_RX_ERROR ; + report_error =1 ; + } +if ((es->status &M16C_STATE_BUS_ERROR ) && + !(es->usbcan.other_ch_status &M16C_STATE_BUS_ERROR )) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_BUSERROR ; + report_error =1 ; + } + +if (report_error) +kvaser_report_error_event (dev, es); +} + +/* +* Extract error summary from a Leaf-based device error message +*/ +static void leaf_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , };switch (msg->id) {case CMD_CAN_ERROR_EVENT : - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; + es.channel = msg->u.leaf.error_event.channel; + es.status = msg->u.leaf.error_event.status; + es.txerr = msg->u.leaf.error_event.tx_errors_count; + es.rxerr = msg->u.leaf.error_event.rx_errors_count; + es.leaf.error_factor = msg->u.leaf.error_event.error_factor;break ; -case CMD_LOG_MESSAGE : - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0 ]; - txerr = msg->u.log_message.data[2 ]; - rxerr = msg->u.log_message.data[3 ]; - error_factor = msg->u.log_message.data[1 ]; +case LEAF_CMD_LOG_MESSAGE : + es.channel = msg->u.leaf.log_message.channel; + es.status = msg->u.leaf.log_message.data[0 ]; + es.txerr = msg->u.leaf.log_message.data[2 ]; + es.rxerr = msg->u.leaf.log_message.data[3 ]; + es.leaf.error_factor = msg->u.leaf.log_message.data[1 ];break ;case CMD_CHIP_STATE_EVENT : - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor =0 ; + es.channel = msg->u.leaf.chip_state_event.channel; + es.status = msg->u.leaf.chip_state_event.status; + es.txerr = msg->u.leaf.chip_state_event.tx_errors_count; + es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count; + es.leaf.error_factor =0 ;break ;default : dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",@@ -653,16 +885,92 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,return ; } -if (channel >= dev->nchannels) { +kvaser_report_error_event (dev, &es); +} + +/* +* Extract summary from a USBCANII-based device error message. +*/ +static void usbcan_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , }; + +switch (msg->id) { + +/* Sometimes errors are sent as unsolicited chip state events */ +case CMD_CHIP_STATE_EVENT : + es.channel = msg->u.usbcan.chip_state_event.channel; + es.status = msg->u.usbcan.chip_state_event.status; + es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count; + es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count; +usbcan_report_error_if_applicable (dev, &es); +break ; + +case CMD_CAN_ERROR_EVENT : + es.channel =0 ; + es.status = msg->u.usbcan.error_event.status_ch0; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch1; +usbcan_report_error_if_applicable (dev, &es); + +/* For error events, the USBCAN firmware does not support +* more than 2 channels: ch0, and ch1. */ +if (dev->nchannels >1 ) { + es.channel =1 ; + es.status = msg->u.usbcan.error_event.status_ch1; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch0; +usbcan_report_error_if_applicable (dev, &es); + } +break ; + +default : +dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , + msg->id); + } +} + +static void kvaser_usb_rx_error (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +switch (dev->family) { +case KVASER_LEAF : +leaf_extract_error_from_msg (dev, msg); +break ; +case KVASER_USBCAN : +usbcan_extract_error_from_msg (dev, msg); +break ; +default :dev_err (dev->udev->dev.parent, -"Invalid channel number (%d)\n" , channel); +"Invalid device family (%d)\n" , dev->family);return ; } +} - priv = dev->nets[channel]; +static void kvaser_report_error_event (const struct kvaser_usb *dev, +struct kvaser_error_summary *es) +{ +struct can_frame *cf; +struct sk_buff *skb; +struct net_device_stats *stats; +struct kvaser_usb_net_priv *priv; +unsigned int new_state; + +if (es->channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , es->channel); +return ; + } + + priv = dev->nets[es->channel]; stats = &priv->netdev->stats; -if (status &M16C_STATE_BUS_RESET ) { +if (es->status &M16C_STATE_BUS_RESET ) {kvaser_usb_unlink_tx_urbs (priv);return ; }@@ -675,9 +983,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, new_state = priv->can.state; -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (status &M16C_STATE_BUS_OFF ) { +if (es->status &M16C_STATE_BUS_OFF ) { cf->can_id |=CAN_ERR_BUSOFF ; priv->can.can_stats.bus_off++;@@ -687,12 +995,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,netif_carrier_off (priv->netdev); new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { + }else if (es->status &M16C_STATE_BUS_PASSIVE ) {if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es->txerr || es->rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else @@ -703,13 +1011,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } new_state =CAN_STATE_ERROR_PASSIVE ; - } - -if (status ==M16C_STATE_BUS_ERROR ) { + }else if (es->status &M16C_STATE_BUS_ERROR ) {if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { + ((es->txerr >=96 ) || (es->rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ;@@ -723,7 +1029,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } } -if (!status) { +if (!es->status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ;@@ -739,34 +1045,52 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv->can.can_stats.restarts++; } -if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - - cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; - -if (error_factor &M16C_EF_ACKE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); -if (error_factor &M16C_EF_CRCE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | -CAN_ERR_PROT_LOC_CRC_DEL ); -if (error_factor &M16C_EF_FORME ) - cf->data[2 ] |=CAN_ERR_PROT_FORM ; -if (error_factor &M16C_EF_STFE ) - cf->data[2 ] |=CAN_ERR_PROT_STUFF ; -if (error_factor &M16C_EF_BITE0 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; -if (error_factor &M16C_EF_BITE1 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; -if (error_factor &M16C_EF_TRE ) - cf->data[2 ] |=CAN_ERR_PROT_TX ; +switch (dev->family) { +case KVASER_LEAF : +if (es->leaf.error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; + +if (es->leaf.error_factor &M16C_EF_ACKE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); +if (es->leaf.error_factor &M16C_EF_CRCE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | +CAN_ERR_PROT_LOC_CRC_DEL ); +if (es->leaf.error_factor &M16C_EF_FORME ) + cf->data[2 ] |=CAN_ERR_PROT_FORM ; +if (es->leaf.error_factor &M16C_EF_STFE ) + cf->data[2 ] |=CAN_ERR_PROT_STUFF ; +if (es->leaf.error_factor &M16C_EF_BITE0 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; +if (es->leaf.error_factor &M16C_EF_BITE1 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; +if (es->leaf.error_factor &M16C_EF_TRE ) + cf->data[2 ] |=CAN_ERR_PROT_TX ; + } +break ; +case KVASER_USBCAN : +if (es->usbcan.error_state &USBCAN_ERROR_STATE_TX_ERROR ) + stats->tx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_RX_ERROR ) + stats->rx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_BUSERROR ) { + priv->can.can_stats.bus_error++; + cf->can_id |=CAN_ERR_BUSERROR ; + } +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto err; } - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; + cf->data[6 ] = es->txerr; + cf->data[7 ] = es->rxerr; - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; priv->can.state = new_state;@@ -774,6 +1098,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + +return ; + +err: +dev_kfree_skb (skb); } static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,@@ -783,16 +1112,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,struct sk_buff *skb;struct net_device_stats *stats = &priv->netdev->stats; -if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | +if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |MSG_FLAG_NERR )) {netdev_err (priv->netdev,"Unknow error (flags: 0x%02x)\n" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); stats->rx_errors++;return ; } -if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { +if (msg->u.rx_can_header.flag &MSG_FLAG_OVERRUN ) { skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;@@ -819,7 +1148,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,struct can_frame *cf;struct sk_buff *skb;struct net_device_stats *stats; -u8 channel = msg->u.rx_can.channel; +u8 channel = msg->u.rx_can_header.channel; +const u8 *rx_msg;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,@@ -830,19 +1160,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; -if ((msg->u.rx_can.flag &MSG_FLAG_ERROR_FRAME ) && - (msg->id ==CMD_LOG_MESSAGE )) { +if ((msg->u.rx_can_header.flag &MSG_FLAG_ERROR_FRAME ) && + (dev->family ==KVASER_LEAF && msg->id ==LEAF_CMD_LOG_MESSAGE )) {kvaser_usb_rx_error (dev, msg);return ; - }else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | -MSG_FLAG_NERR | -MSG_FLAG_OVERRUN )) { + }else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME | +MSG_FLAG_NERR | +MSG_FLAG_OVERRUN )) {kvaser_usb_rx_can_err (priv, msg);return ; - }else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME ) { + }else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME ) {netdev_warn (priv->netdev,"Unhandled frame (flags: 0x%02x)" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); +return ; + } + +switch (dev->family) { +case KVASER_LEAF : + rx_msg = msg->u.leaf.rx_can.msg; +break ; +case KVASER_USBCAN : + rx_msg = msg->u.usbcan.rx_can.msg; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family);return ; }@@ -852,38 +1195,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,return ; } -if (msg->id ==CMD_LOG_MESSAGE ) { - cf->can_id =le32_to_cpu (msg->u.log_message.id); +if (dev->family ==KVASER_LEAF && msg->id ==LEAF_CMD_LOG_MESSAGE ) { + cf->can_id =le32_to_cpu (msg->u.leaf.log_message.id);if (cf->can_id &KVASER_EXTENDED_FRAME ) cf->can_id &=CAN_EFF_MASK |CAN_EFF_FLAG ;else cf->can_id &=CAN_SFF_MASK ; - cf->can_dlc =get_can_dlc (msg->u.log_message.dlc); + cf->can_dlc =get_can_dlc (msg->u.leaf.log_message.dlc); -if (msg->u.log_message.flags &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.leaf.log_message.flags &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.log_message.data, +memcpy (cf->data, &msg->u.leaf.log_message.data, cf->can_dlc); }else { - cf->can_id = ((msg->u.rx_can.msg[0 ] &0x1f ) <<6 ) | - (msg->u.rx_can.msg[1 ] &0x3f ); + cf->can_id = ((rx_msg[0 ] &0x1f ) <<6 ) | (rx_msg[1 ] &0x3f );if (msg->id ==CMD_RX_EXT_MESSAGE ) { cf->can_id <<=18 ; - cf->can_id |= ((msg->u.rx_can.msg[2 ] &0x0f ) <<14 ) | - ((msg->u.rx_can.msg[3 ] &0xff ) <<6 ) | - (msg->u.rx_can.msg[4 ] &0x3f ); + cf->can_id |= ((rx_msg[2 ] &0x0f ) <<14 ) | + ((rx_msg[3 ] &0xff ) <<6 ) | + (rx_msg[4 ] &0x3f ); cf->can_id |=CAN_EFF_FLAG ; } - cf->can_dlc =get_can_dlc (msg->u.rx_can.msg[5 ]); + cf->can_dlc =get_can_dlc (rx_msg[5 ]); -if (msg->u.rx_can.flag &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.rx_can_header.flag &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.rx_can.msg[6 ], +memcpy (cf->data, &rx_msg[6 ], cf->can_dlc); }@@ -947,7 +1289,12 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,case CMD_RX_STD_MESSAGE :case CMD_RX_EXT_MESSAGE : -case CMD_LOG_MESSAGE : +kvaser_usb_rx_can_msg (dev, msg); +break ; + +case LEAF_CMD_LOG_MESSAGE : +if (dev->family !=KVASER_LEAF ) + goto warn;kvaser_usb_rx_can_msg (dev, msg);break ;@@ -960,8 +1307,14 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,kvaser_usb_tx_acknowledge (dev, msg);break ; +/* Ignored messages */ +case USBCAN_CMD_CLOCK_OVERFLOW_EVENT : +if (dev->family !=KVASER_USBCAN ) + goto warn; +break ; +default : -dev_warn (dev->udev->dev.parent, +warn:dev_warn (dev->udev->dev.parent,"Unhandled message (%d)\n" , msg->id);break ; }
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) · line 1537
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +1
-1@@ -1181,7 +1534,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) dev->rxbuf[i], dev->rxbuf_dma[i]); -for (i =0 ; i <MAX_NET_DEVICES ; i++) { +for (i =0 ; i < dev->max_channels; i++) {
here too... or replace it by nchannels.
Quoted 50 lines
drivers/net/can/usb/kvaser_usb.c +18
-2struct kvaser_usb_net_priv *priv = dev->nets[i];if (priv)@@ -1286,6 +1639,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,struct kvaser_msg *msg;int i, err;int ret =NETDEV_TX_OK ; +uint8_t *msg_tx_can_flags;bool kfree_skb_on_error = true;if (can_dropped_invalid_skb (netdev, skb))@@ -1306,9 +1660,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, msg = buf; msg->len =MSG_HEADER_LEN +sizeof (struct kvaser_msg_tx_can ); - msg->u.tx_can.flags =0 ; msg->u.tx_can.channel = priv->channel; +switch (dev->family) { +case KVASER_LEAF : + msg_tx_can_flags = &msg->u.tx_can.leaf.flags; +break ; +case KVASER_USBCAN : + msg_tx_can_flags = &msg->u.tx_can.usbcan.flags; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto releasebuf; + } + + *msg_tx_can_flags =0 ; +if (cf->can_id &CAN_EFF_FLAG ) { msg->id =CMD_TX_EXT_MESSAGE ; msg->u.tx_can.msg[0 ] = (cf->can_id >>24 ) &0x1f ;@@ -1326,7 +1694,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,memcpy (&msg->u.tx_can.msg[6 ], cf->data, cf->can_dlc);if (cf->can_id &CAN_RTR_FLAG ) - msg->u.tx_can.flags |=MSG_FLAG_REMOTE_FRAME ; + *msg_tx_can_flags |=MSG_FLAG_REMOTE_FRAME ;for (i =0 ; i <ARRAY_SIZE (priv->tx_contexts); i++) {if (priv->tx_contexts[i].echo_index ==MAX_TX_URBS ) {@@ -1596,6 +1964,18 @@ static int kvaser_usb_probe(struct usb_interface *intf,if (!dev)return -ENOMEM ; +if (LEAF_PRODUCT_ID (id->idProduct)) {
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1977
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+ dev->family =KVASER_LEAF ; + dev->max_channels =LEAF_MAX_NET_DEVICES ; + }else if (USBCAN_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_USBCAN ; + dev->max_channels =USBCAN_MAX_NET_DEVICES ; + }else { +dev_err (&intf->dev,"Product ID (%d) does not belong to any " +"known Kvaser USB family" , id->idProduct); +return -ENODEV ; + }
Is it really required to keep max_channels in the kvaser_usb structure? If I looked correctly, you use this variable as a replacement for MAX_NET_DEVICES in the code and MAX_NET_DEVICES is only used in probe and disconnect functions. I think it can even be replaced by nchannels in the disconnect path. So I also think that it don't need to be in the kvaser_usb structure.
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1992
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c +2
-1+ err =kvaser_usb_get_endpoints (intf, &dev->bulk_in, &dev->bulk_out);if (err) {dev_err (&intf->dev,"Cannot get usb endpoint(s)" );@@ -1608,7 +1988,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev); -for (i =0 ; i <MAX_NET_DEVICES ; i++) +for (i =0 ; i < dev->max_channels; i++)kvaser_usb_send_simple_msg (dev,CMD_RESET_CHIP , i);
Someone reported me that recent leaf firmwares go in trouble when you send a command for a channel that does not exist. Instead of max_channels, you can use nchannels here and move the reset command in the kvaser_usb_init_one() function.
I've a patch for this but It is not tested yet. I'll send it next week-end after I did some tests.
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1994
Quoted 2 lines
drivers/net/can/usb/kvaser_usb.c +0
-0err =kvaser_usb_get_software_info (dev);
Thank you,
Signature · 1 line
Olivier
Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
Hi Olivier,
Quoted 13 lines · Olivier Sobrie
Hello Ahmed,
Quoted 10 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'UsbcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
This patch adds support for the UsbcanII family of devices to the current Kvaser Leaf-only driver.
Quoted 8 lines
Quoted 4 lines
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
Good, thank you :-) I'll try to test the patch during the next week-end. Small remarks below.
Great! thanks and Merry Christmas :-)
Quoted 32 lines
Quoted 32 lines
Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 630 +++++++++++++++++++++++++++++++-------- 1 file changed, 505 insertions(+), 125 deletions(-)(Generated over 3.19.0-rc1 + generic bugfix at
can-kvaser_usb-Don-t-free-packets-when-tight-on-URBs.patch)drivers/net/can/usb/kvaser_usb.c +3
-0@@ -6,12 +6,15 @@* Parts of this driver are based on the following: * - Kvaser linux leaf driver (version 4.78) * - CAN driver for esd CAN-USB/2 +* - Kvaser linux usbcanII driver (version 5.3) * * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. * Copyright (C) 2010 Matthias Fuchs <[email protected]>, esd gmbh * Copyright (C) 2012 Olivier Sobrie <[email protected]> +* Copyright (C) 2014 Valeo Corporation */ +#include <linux/kernel.h> #include <linux/completion.h> #include <linux/module.h> #include <linux/netdevice.h> @@ -21,6 +24,18 @@#include <linux/can/dev.h> #include <linux/can/error.h>
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c line 27
Quoted 1 line
drivers/net/can/usb/kvaser_usb.c +1
-0+#define MAX (a, b) ((a) > (b) ? (a) : (b))There is a
max(a, b)macro in <linux/kernel.h>.
Quite true, but it unfortunately fails when the symbol is used in array size declaration as in below:
struct kvaser_usb {
...
struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES];
...
}
include/linux/kernel.h:713:19: error: braced-group within
expression allowed only inside a function
#define max(x, y) ({ \
^Quoted 404 lines
Quoted 404 lines
drivers/net/can/usb/kvaser_usb.c +209
-29+ +/* +* Kvaser USB CAN dongles are divided into two major families: +* - Leaf: Based on Renesas M32C, running firmware labeled as 'filo' +* - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios' +*/ +enum kvaser_usb_family { +KVASER_LEAF , +KVASER_USBCAN , +}; +#define MAX_TX_URBS 16#define MAX_RX_URBS 4#define START_TIMEOUT 1000/* msecs */ @@ -29,9 +44,12 @@#define USB_RECV_TIMEOUT 1000/* msecs */ #define RX_BUFFER_SIZE 3072#define CAN_USB_CLOCK 8000000 -#define MAX_NET_DEVICES 3 +#define LEAF_MAX_NET_DEVICES 3 +#define USBCAN_MAX_NET_DEVICES 2 +#define MAX_NET_DEVICES MAX(LEAF_MAX_NET_DEVICES, \ + USBCAN_MAX_NET_DEVICES) -/* Kvaser USB devices */ +/* Leaf USB devices */ #define KVASER_VENDOR_ID 0x0bfd#define USB_LEAF_DEVEL_PRODUCT_ID 10#define USB_LEAF_LITE_PRODUCT_ID 11@@ -55,6 +73,16 @@#define USB_CAN_R_PRODUCT_ID 39#define USB_LEAF_LITE_V2_PRODUCT_ID 288#define USB_MINI_PCIE_HS_PRODUCT_ID 289 +#define LEAF_PRODUCT_ID (id) (id >= USB_LEAF_DEVEL_PRODUCT_ID && \ + id <= USB_MINI_PCIE_HS_PRODUCT_ID) + +/* USBCANII devices */ +#define USB_USBCAN_REVB_PRODUCT_ID 2 +#define USB_VCI2_PRODUCT_ID 3 +#define USB_USBCAN2_PRODUCT_ID 4 +#define USB_MEMORATOR_PRODUCT_ID 5 +#define USBCAN_PRODUCT_ID (id) (id >= USB_USBCAN_REVB_PRODUCT_ID && \ + id <= USB_MEMORATOR_PRODUCT_ID)/* USB devices features */ #define KVASER_HAS_SILENT_MODE BIT(0)@@ -73,7 +101,7 @@#define MSG_FLAG_TX_ACK BIT(6)#define MSG_FLAG_TX_REQUEST BIT(7) -/* Can states */ +/* Can states (M16C CxSTRH register) */ #define M16C_STATE_BUS_RESET BIT(0)#define M16C_STATE_BUS_ERROR BIT(4)#define M16C_STATE_BUS_PASSIVE BIT(5)@@ -98,7 +126,13 @@#define CMD_START_CHIP_REPLY 27#define CMD_STOP_CHIP 28#define CMD_STOP_CHIP_REPLY 29 -#define CMD_GET_CARD_INFO2 32 +#define CMD_READ_CLOCK 30 +#define CMD_READ_CLOCK_REPLY 31 + +#define LEAF_CMD_GET_CARD_INFO2 32 +#define USBCAN_CMD_RESET_CLOCK 32 +#define USBCAN_CMD_CLOCK_OVERFLOW_EVENT 33 +#define CMD_GET_CARD_INFO 34#define CMD_GET_CARD_INFO_REPLY 35#define CMD_GET_SOFTWARE_INFO 38@@ -108,8 +142,9 @@#define CMD_RESET_ERROR_COUNTER 49#define CMD_TX_ACKNOWLEDGE 50#define CMD_CAN_ERROR_EVENT 51 -#define CMD_USB_THROTTLE 77 -#define CMD_LOG_MESSAGE 106 + +#define LEAF_CMD_USB_THROTTLE 77 +#define LEAF_CMD_LOG_MESSAGE 106/* error factors */ #define M16C_EF_ACKE BIT(0)@@ -121,6 +156,13 @@#define M16C_EF_RCVE BIT(6)#define M16C_EF_TRE BIT(7) +/* Only Leaf-based devices can report M16C error factors, +* thus define our own error status flags for USBCAN */ +#define USBCAN_ERROR_STATE_NONE 0 +#define USBCAN_ERROR_STATE_TX_ERROR BIT(0) +#define USBCAN_ERROR_STATE_RX_ERROR BIT(1) +#define USBCAN_ERROR_STATE_BUSERROR BIT(2) +/* bittiming parameters */ #define KVASER_USB_TSEG1_MIN 1#define KVASER_USB_TSEG1_MAX 16@@ -137,7 +179,7 @@#define KVASER_CTRL_MODE_SELFRECEPTION 3#define KVASER_CTRL_MODE_OFF 4 -/* log message */ +/* Extended CAN identifier flag */ #define KVASER_EXTENDED_FRAME BIT(31)struct kvaser_msg_simple {@@ -148,30 +190,55 @@ struct kvaser_msg_simple {struct kvaser_msg_cardinfo {u8 tid;u8 nchannels; -__le32 serial_number; -__le32 padding; +union { +struct { +__le32 serial_number; +__le32 padding; + } __packed leaf0; +struct { +__le32 serial_number_low; +__le32 serial_number_high; + } __packed usbcan0; + } __packed;__le32 clock_resolution;__le32 mfgdate;u8 ean[8 ];u8 hw_revision; -u8 usb_hs_mode; -__le16 padding2; +union { +struct { +u8 usb_hs_mode; + } __packed leaf1; +struct { +u8 padding; + } __packed usbcan1; + } __packed; +__le16 padding; } __packed;struct kvaser_msg_cardinfo2 {u8 tid; -u8 channel; +u8 reserved;u8 pcb_id[24 ];__le32 oem_unlock_code; } __packed; -struct kvaser_msg_softinfo { +struct leaf_msg_softinfo {u8 tid; -u8 channel; +u8 padding0;__le32 sw_options;__le32 fw_version;__le16 max_outstanding_tx; -__le16 padding[9 ]; +__le16 padding1[9 ]; +} __packed; + +struct usbcan_msg_softinfo { +u8 tid; +u8 fw_name[5 ]; +__le16 max_outstanding_tx; +u8 padding[6 ]; +__le32 fw_version; +__le16 checksum; +__le16 sw_options; } __packed;struct kvaser_msg_busparams {@@ -188,36 +255,86 @@ struct kvaser_msg_tx_can {u8 channel;u8 tid;u8 msg[14 ]; -u8 padding; -u8 flags; +union { +struct { +u8 padding; +u8 flags; + } __packed leaf; +struct { +u8 flags; +u8 padding; + } __packed usbcan; + } __packed; +} __packed; + +struct kvaser_msg_rx_can_header { +u8 channel; +u8 flag; } __packed; -struct kvaser_msg_rx_can { +struct leaf_msg_rx_can {u8 channel;u8 flag; +__le16 time[3 ];u8 msg[14 ]; } __packed; -struct kvaser_msg_chip_state_event { +struct usbcan_msg_rx_can { +u8 channel; +u8 flag; + +u8 msg[14 ]; +__le16 time; +} __packed; + +struct leaf_msg_chip_state_event {u8 tid;u8 channel; +__le16 time[3 ];u8 tx_errors_count;u8 rx_errors_count; +u8 status;u8 padding[3 ]; } __packed; -struct kvaser_msg_tx_acknowledge { +struct usbcan_msg_chip_state_event { +u8 tid; +u8 channel; + +u8 tx_errors_count; +u8 rx_errors_count; +__le16 time; + +u8 status; +u8 padding[3 ]; +} __packed; + +struct kvaser_msg_tx_acknowledge_header { +u8 channel; +u8 tid; +}; + +struct leaf_msg_tx_acknowledge {u8 channel;u8 tid; +__le16 time[3 ];u8 flags;u8 time_offset; } __packed; -struct kvaser_msg_error_event { +struct usbcan_msg_tx_acknowledge { +u8 channel; +u8 tid; + +__le16 time; +__le16 padding; +} __packed; + +struct leaf_msg_error_event {u8 tid;u8 flags;__le16 time[3 ];@@ -229,6 +346,18 @@ struct kvaser_msg_error_event {u8 error_factor; } __packed; +struct usbcan_msg_error_event { +u8 tid; +u8 padding; +u8 tx_errors_count_ch0; +u8 rx_errors_count_ch0; +u8 tx_errors_count_ch1; +u8 rx_errors_count_ch1; +u8 status_ch0; +u8 status_ch1; +__le16 time; +} __packed; +struct kvaser_msg_ctrl_mode {u8 tid;u8 channel;@@ -243,7 +372,7 @@ struct kvaser_msg_flush_queue {u8 padding[3 ]; } __packed; -struct kvaser_msg_log_message { +struct leaf_msg_log_message {u8 channel;u8 flags;__le16 time[3 ];@@ -260,19 +389,49 @@ struct kvaser_msg {struct kvaser_msg_simple simple;struct kvaser_msg_cardinfo cardinfo;struct kvaser_msg_cardinfo2 cardinfo2; -struct kvaser_msg_softinfo softinfo;struct kvaser_msg_busparams busparams; + +struct kvaser_msg_rx_can_header rx_can_header; +struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header; + +union { +struct leaf_msg_softinfo softinfo; +struct leaf_msg_rx_can rx_can; +struct leaf_msg_chip_state_event chip_state_event; +struct leaf_msg_tx_acknowledge tx_acknowledge; +struct leaf_msg_error_event error_event; +struct leaf_msg_log_message log_message; + } __packed leaf; + +union { +struct usbcan_msg_softinfo softinfo; +struct usbcan_msg_rx_can rx_can; +struct usbcan_msg_chip_state_event chip_state_event; +struct usbcan_msg_tx_acknowledge tx_acknowledge; +struct usbcan_msg_error_event error_event; + } __packed usbcan; +struct kvaser_msg_tx_can tx_can; -struct kvaser_msg_rx_can rx_can; -struct kvaser_msg_chip_state_event chip_state_event; -struct kvaser_msg_tx_acknowledge tx_acknowledge; -struct kvaser_msg_error_event error_event;struct kvaser_msg_ctrl_mode ctrl_mode;struct kvaser_msg_flush_queue flush_queue; -struct kvaser_msg_log_message log_message; } u; } __packed; +/* Leaf/USBCAN-agnostic summary of an error event. +* No M16C error factors for USBCAN-based devices. */ +struct kvaser_error_summary { +u8 channel, status, txerr, rxerr; +union { +struct { +u8 error_factor; + } leaf; +struct { +u8 other_ch_status; +u8 error_state; + } usbcan; + }; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;@@ -288,6 +447,8 @@ struct kvaser_usb {u32 fw_version;unsigned int nchannels; +enum kvaser_usb_family family; +unsigned int max_channels;bool rxinitdone;void *rxbuf[MAX_RX_URBS ];@@ -311,6 +472,7 @@ struct kvaser_usb_net_priv { };static const struct usb_device_id kvaser_usb_table[] = { +/* Leaf family IDs */ {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_DEVEL_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_LITE_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_PRO_PRODUCT_ID ),@@ -360,6 +522,17 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = KVASER_HAS_TXRX_ERRORS }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, + +/* USBCANII family IDs */ + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { } };MODULE_DEVICE_TABLE (usb, kvaser_usb_table);@@ -463,7 +636,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)if (err)return err; - dev->fw_version =le32_to_cpu (msg.u.softinfo.fw_version); +switch (dev->family) { +case KVASER_LEAF : + dev->fw_version =le32_to_cpu (msg.u.leaf.softinfo.fw_version); +break ; +case KVASER_USBCAN : + dev->fw_version =le32_to_cpu (msg.u.usbcan.softinfo.fw_version); +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); +return -EINVAL ; + }return 0 ; }@@ -482,7 +666,7 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)return err;
Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_get_card_info(struct kvaser_usb *dev) · line 670
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +1
-1dev->nchannels = msg.u.cardinfo.nchannels; -if (dev->nchannels >MAX_NET_DEVICES ) +if (dev->nchannels > dev->max_channels)return -EINVAL ;IMHO, you can keep
MAX_NET_DEVICEShere.
The UsbcanII firmware hardcodes a maximum of 2 channels in its protocol. This is unfortunately due to its inability to tell whether an error event is from CAN channel 0 or ch 1, and also due to its error_event format:
struct usbcan_msg_error_event {
u8 tid;
u8 padding;
u8 tx_errors_count_ch0;
u8 rx_errors_count_ch0;
u8 tx_errors_count_ch1;
u8 rx_errors_count_ch1;
u8 status_ch0;
u8 status_ch1;
__le16 time;
} __packed;But since we have MAX_NET_DEVICES = 3, and given the above, if the UsbcanII firmware reported to us having more than 2 channels, then it's:
a) most probably a memory corruption bug either in the firmware or in the driver
b) an updated device/firmware we cannot support yet, since we cannot arbitrate the origin of error events quite correctly (especially in the case of CAN_ERR_BUSERROR, where the error counters stays the same and we have to resort to other hacks. Kindly check usbcan_report_error_if_applicable().)
So allowing more than 2 channels given the current set of affairs will really induce correctness problems :-(
Quoted 518 lines
Quoted 518 lines
drivers/net/can/usb/kvaser_usb.c +260
-91return 0 ;@@ -496,8 +680,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,struct kvaser_usb_net_priv *priv;struct sk_buff *skb;struct can_frame *cf; -u8 channel = msg->u.tx_acknowledge.channel; -u8 tid = msg->u.tx_acknowledge.tid; +u8 channel, tid; + + channel = msg->u.tx_acknowledge_header.channel; + tid = msg->u.tx_acknowledge_header.tid;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,@@ -615,37 +801,83 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index =MAX_TX_URBS ; } -static void kvaser_usb_rx_error (const struct kvaser_usb *dev, -const struct kvaser_msg *msg) +static void kvaser_report_error_event (const struct kvaser_usb *dev, +struct kvaser_error_summary *es); + +/* +* Report error to userspace iff the controller's errors counter has +* increased, or we're the only channel seeing the bus error state. +* +* As reported by USBCAN sheets, "the CAN controller has difficulties +* to tell whether an error frame arrived on channel 1 or on channel 2." +* Thus, error counters are compared with their earlier values to +* determine which channel was responsible for the error event. +*/ +static void usbcan_report_error_if_applicable (const struct kvaser_usb *dev, +struct kvaser_error_summary *es) { -struct can_frame *cf; -struct sk_buff *skb; -struct net_device_stats *stats;struct kvaser_usb_net_priv *priv; -unsigned int new_state; -u8 channel, status, txerr, rxerr, error_factor; +int old_tx_err_count, old_rx_err_count, channel, report_error; + + channel = es->channel; +if (channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , channel); +return ; + } + + priv = dev->nets[channel]; + old_tx_err_count = priv->bec.txerr; + old_rx_err_count = priv->bec.rxerr; + + report_error =0 ; +if (es->txerr > old_tx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_TX_ERROR ; + report_error =1 ; + } +if (es->rxerr > old_rx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_RX_ERROR ; + report_error =1 ; + } +if ((es->status &M16C_STATE_BUS_ERROR ) && + !(es->usbcan.other_ch_status &M16C_STATE_BUS_ERROR )) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_BUSERROR ; + report_error =1 ; + } + +if (report_error) +kvaser_report_error_event (dev, es); +} + +/* +* Extract error summary from a Leaf-based device error message +*/ +static void leaf_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , };switch (msg->id) {case CMD_CAN_ERROR_EVENT : - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; + es.channel = msg->u.leaf.error_event.channel; + es.status = msg->u.leaf.error_event.status; + es.txerr = msg->u.leaf.error_event.tx_errors_count; + es.rxerr = msg->u.leaf.error_event.rx_errors_count; + es.leaf.error_factor = msg->u.leaf.error_event.error_factor;break ; -case CMD_LOG_MESSAGE : - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0 ]; - txerr = msg->u.log_message.data[2 ]; - rxerr = msg->u.log_message.data[3 ]; - error_factor = msg->u.log_message.data[1 ]; +case LEAF_CMD_LOG_MESSAGE : + es.channel = msg->u.leaf.log_message.channel; + es.status = msg->u.leaf.log_message.data[0 ]; + es.txerr = msg->u.leaf.log_message.data[2 ]; + es.rxerr = msg->u.leaf.log_message.data[3 ]; + es.leaf.error_factor = msg->u.leaf.log_message.data[1 ];break ;case CMD_CHIP_STATE_EVENT : - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor =0 ; + es.channel = msg->u.leaf.chip_state_event.channel; + es.status = msg->u.leaf.chip_state_event.status; + es.txerr = msg->u.leaf.chip_state_event.tx_errors_count; + es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count; + es.leaf.error_factor =0 ;break ;default : dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",@@ -653,16 +885,92 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,return ; } -if (channel >= dev->nchannels) { +kvaser_report_error_event (dev, &es); +} + +/* +* Extract summary from a USBCANII-based device error message. +*/ +static void usbcan_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , }; + +switch (msg->id) { + +/* Sometimes errors are sent as unsolicited chip state events */ +case CMD_CHIP_STATE_EVENT : + es.channel = msg->u.usbcan.chip_state_event.channel; + es.status = msg->u.usbcan.chip_state_event.status; + es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count; + es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count; +usbcan_report_error_if_applicable (dev, &es); +break ; + +case CMD_CAN_ERROR_EVENT : + es.channel =0 ; + es.status = msg->u.usbcan.error_event.status_ch0; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch1; +usbcan_report_error_if_applicable (dev, &es); + +/* For error events, the USBCAN firmware does not support +* more than 2 channels: ch0, and ch1. */ +if (dev->nchannels >1 ) { + es.channel =1 ; + es.status = msg->u.usbcan.error_event.status_ch1; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch0; +usbcan_report_error_if_applicable (dev, &es); + } +break ; + +default : +dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , + msg->id); + } +} + +static void kvaser_usb_rx_error (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +switch (dev->family) { +case KVASER_LEAF : +leaf_extract_error_from_msg (dev, msg); +break ; +case KVASER_USBCAN : +usbcan_extract_error_from_msg (dev, msg); +break ; +default :dev_err (dev->udev->dev.parent, -"Invalid channel number (%d)\n" , channel); +"Invalid device family (%d)\n" , dev->family);return ; } +} - priv = dev->nets[channel]; +static void kvaser_report_error_event (const struct kvaser_usb *dev, +struct kvaser_error_summary *es) +{ +struct can_frame *cf; +struct sk_buff *skb; +struct net_device_stats *stats; +struct kvaser_usb_net_priv *priv; +unsigned int new_state; + +if (es->channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , es->channel); +return ; + } + + priv = dev->nets[es->channel]; stats = &priv->netdev->stats; -if (status &M16C_STATE_BUS_RESET ) { +if (es->status &M16C_STATE_BUS_RESET ) {kvaser_usb_unlink_tx_urbs (priv);return ; }@@ -675,9 +983,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, new_state = priv->can.state; -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (status &M16C_STATE_BUS_OFF ) { +if (es->status &M16C_STATE_BUS_OFF ) { cf->can_id |=CAN_ERR_BUSOFF ; priv->can.can_stats.bus_off++;@@ -687,12 +995,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,netif_carrier_off (priv->netdev); new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { + }else if (es->status &M16C_STATE_BUS_PASSIVE ) {if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es->txerr || es->rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else @@ -703,13 +1011,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } new_state =CAN_STATE_ERROR_PASSIVE ; - } - -if (status ==M16C_STATE_BUS_ERROR ) { + }else if (es->status &M16C_STATE_BUS_ERROR ) {if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { + ((es->txerr >=96 ) || (es->rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ;@@ -723,7 +1029,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } } -if (!status) { +if (!es->status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ;@@ -739,34 +1045,52 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv->can.can_stats.restarts++; } -if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - - cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; - -if (error_factor &M16C_EF_ACKE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); -if (error_factor &M16C_EF_CRCE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | -CAN_ERR_PROT_LOC_CRC_DEL ); -if (error_factor &M16C_EF_FORME ) - cf->data[2 ] |=CAN_ERR_PROT_FORM ; -if (error_factor &M16C_EF_STFE ) - cf->data[2 ] |=CAN_ERR_PROT_STUFF ; -if (error_factor &M16C_EF_BITE0 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; -if (error_factor &M16C_EF_BITE1 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; -if (error_factor &M16C_EF_TRE ) - cf->data[2 ] |=CAN_ERR_PROT_TX ; +switch (dev->family) { +case KVASER_LEAF : +if (es->leaf.error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; + +if (es->leaf.error_factor &M16C_EF_ACKE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); +if (es->leaf.error_factor &M16C_EF_CRCE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | +CAN_ERR_PROT_LOC_CRC_DEL ); +if (es->leaf.error_factor &M16C_EF_FORME ) + cf->data[2 ] |=CAN_ERR_PROT_FORM ; +if (es->leaf.error_factor &M16C_EF_STFE ) + cf->data[2 ] |=CAN_ERR_PROT_STUFF ; +if (es->leaf.error_factor &M16C_EF_BITE0 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; +if (es->leaf.error_factor &M16C_EF_BITE1 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; +if (es->leaf.error_factor &M16C_EF_TRE ) + cf->data[2 ] |=CAN_ERR_PROT_TX ; + } +break ; +case KVASER_USBCAN : +if (es->usbcan.error_state &USBCAN_ERROR_STATE_TX_ERROR ) + stats->tx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_RX_ERROR ) + stats->rx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_BUSERROR ) { + priv->can.can_stats.bus_error++; + cf->can_id |=CAN_ERR_BUSERROR ; + } +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto err; } - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; + cf->data[6 ] = es->txerr; + cf->data[7 ] = es->rxerr; - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; priv->can.state = new_state;@@ -774,6 +1098,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + +return ; + +err: +dev_kfree_skb (skb); } static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,@@ -783,16 +1112,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,struct sk_buff *skb;struct net_device_stats *stats = &priv->netdev->stats; -if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | +if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |MSG_FLAG_NERR )) {netdev_err (priv->netdev,"Unknow error (flags: 0x%02x)\n" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); stats->rx_errors++;return ; } -if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { +if (msg->u.rx_can_header.flag &MSG_FLAG_OVERRUN ) { skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;@@ -819,7 +1148,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,struct can_frame *cf;struct sk_buff *skb;struct net_device_stats *stats; -u8 channel = msg->u.rx_can.channel; +u8 channel = msg->u.rx_can_header.channel; +const u8 *rx_msg;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,@@ -830,19 +1160,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; -if ((msg->u.rx_can.flag &MSG_FLAG_ERROR_FRAME ) && - (msg->id ==CMD_LOG_MESSAGE )) { +if ((msg->u.rx_can_header.flag &MSG_FLAG_ERROR_FRAME ) && + (dev->family ==KVASER_LEAF && msg->id ==LEAF_CMD_LOG_MESSAGE )) {kvaser_usb_rx_error (dev, msg);return ; - }else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | -MSG_FLAG_NERR | -MSG_FLAG_OVERRUN )) { + }else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME | +MSG_FLAG_NERR | +MSG_FLAG_OVERRUN )) {kvaser_usb_rx_can_err (priv, msg);return ; - }else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME ) { + }else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME ) {netdev_warn (priv->netdev,"Unhandled frame (flags: 0x%02x)" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); +return ; + } + +switch (dev->family) { +case KVASER_LEAF : + rx_msg = msg->u.leaf.rx_can.msg; +break ; +case KVASER_USBCAN : + rx_msg = msg->u.usbcan.rx_can.msg; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family);return ; }@@ -852,38 +1195,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,return ; } -if (msg->id ==CMD_LOG_MESSAGE ) { - cf->can_id =le32_to_cpu (msg->u.log_message.id); +if (dev->family ==KVASER_LEAF && msg->id ==LEAF_CMD_LOG_MESSAGE ) { + cf->can_id =le32_to_cpu (msg->u.leaf.log_message.id);if (cf->can_id &KVASER_EXTENDED_FRAME ) cf->can_id &=CAN_EFF_MASK |CAN_EFF_FLAG ;else cf->can_id &=CAN_SFF_MASK ; - cf->can_dlc =get_can_dlc (msg->u.log_message.dlc); + cf->can_dlc =get_can_dlc (msg->u.leaf.log_message.dlc); -if (msg->u.log_message.flags &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.leaf.log_message.flags &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.log_message.data, +memcpy (cf->data, &msg->u.leaf.log_message.data, cf->can_dlc); }else { - cf->can_id = ((msg->u.rx_can.msg[0 ] &0x1f ) <<6 ) | - (msg->u.rx_can.msg[1 ] &0x3f ); + cf->can_id = ((rx_msg[0 ] &0x1f ) <<6 ) | (rx_msg[1 ] &0x3f );if (msg->id ==CMD_RX_EXT_MESSAGE ) { cf->can_id <<=18 ; - cf->can_id |= ((msg->u.rx_can.msg[2 ] &0x0f ) <<14 ) | - ((msg->u.rx_can.msg[3 ] &0xff ) <<6 ) | - (msg->u.rx_can.msg[4 ] &0x3f ); + cf->can_id |= ((rx_msg[2 ] &0x0f ) <<14 ) | + ((rx_msg[3 ] &0xff ) <<6 ) | + (rx_msg[4 ] &0x3f ); cf->can_id |=CAN_EFF_FLAG ; } - cf->can_dlc =get_can_dlc (msg->u.rx_can.msg[5 ]); + cf->can_dlc =get_can_dlc (rx_msg[5 ]); -if (msg->u.rx_can.flag &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.rx_can_header.flag &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.rx_can.msg[6 ], +memcpy (cf->data, &rx_msg[6 ], cf->can_dlc); }@@ -947,7 +1289,12 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,case CMD_RX_STD_MESSAGE :case CMD_RX_EXT_MESSAGE : -case CMD_LOG_MESSAGE : +kvaser_usb_rx_can_msg (dev, msg); +break ; + +case LEAF_CMD_LOG_MESSAGE : +if (dev->family !=KVASER_LEAF ) + goto warn;kvaser_usb_rx_can_msg (dev, msg);break ;@@ -960,8 +1307,14 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,kvaser_usb_tx_acknowledge (dev, msg);break ; +/* Ignored messages */ +case USBCAN_CMD_CLOCK_OVERFLOW_EVENT : +if (dev->family !=KVASER_USBCAN ) + goto warn; +break ; +default : -dev_warn (dev->udev->dev.parent, +warn:dev_warn (dev->udev->dev.parent,"Unhandled message (%d)\n" , msg->id);break ; }@@ -1181,7 +1534,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) dev->rxbuf[i], dev->rxbuf_dma[i]);
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) · line 1537
Quoted 2 lines
drivers/net/can/usb/kvaser_usb.c +1
-1-for (i =0 ; i <MAX_NET_DEVICES ; i++) { +for (i =0 ; i < dev->max_channels; i++) {here too... or replace it by nchannels.
Yes, indeed. nchannels is the correct choice here, especially since kvaser_usb_init_one() is called "dev->nchannels" times too.
Quoted 60 lines
Quoted 60 lines
drivers/net/can/usb/kvaser_usb.c +28
-2struct kvaser_usb_net_priv *priv = dev->nets[i];if (priv)@@ -1286,6 +1639,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,struct kvaser_msg *msg;int i, err;int ret =NETDEV_TX_OK ; +uint8_t *msg_tx_can_flags;bool kfree_skb_on_error = true;if (can_dropped_invalid_skb (netdev, skb))@@ -1306,9 +1660,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, msg = buf; msg->len =MSG_HEADER_LEN +sizeof (struct kvaser_msg_tx_can ); - msg->u.tx_can.flags =0 ; msg->u.tx_can.channel = priv->channel; +switch (dev->family) { +case KVASER_LEAF : + msg_tx_can_flags = &msg->u.tx_can.leaf.flags; +break ; +case KVASER_USBCAN : + msg_tx_can_flags = &msg->u.tx_can.usbcan.flags; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto releasebuf; + } + + *msg_tx_can_flags =0 ; +if (cf->can_id &CAN_EFF_FLAG ) { msg->id =CMD_TX_EXT_MESSAGE ; msg->u.tx_can.msg[0 ] = (cf->can_id >>24 ) &0x1f ;@@ -1326,7 +1694,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,memcpy (&msg->u.tx_can.msg[6 ], cf->data, cf->can_dlc);if (cf->can_id &CAN_RTR_FLAG ) - msg->u.tx_can.flags |=MSG_FLAG_REMOTE_FRAME ; + *msg_tx_can_flags |=MSG_FLAG_REMOTE_FRAME ;for (i =0 ; i <ARRAY_SIZE (priv->tx_contexts); i++) {if (priv->tx_contexts[i].echo_index ==MAX_TX_URBS ) {@@ -1596,6 +1964,18 @@ static int kvaser_usb_probe(struct usb_interface *intf,if (!dev)return -ENOMEM ; +if (LEAF_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_LEAF ; + dev->max_channels =LEAF_MAX_NET_DEVICES ; + }else if (USBCAN_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_USBCAN ; + dev->max_channels =USBCAN_MAX_NET_DEVICES ; + }else { +dev_err (&intf->dev,"Product ID (%d) does not belong to any " +"known Kvaser USB family" , id->idProduct); +return -ENODEV ; + }
Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1978
Quoted 1 line
drivers/net/can/usb/kvaser_usb.c +1
-0+Is it really required to keep
max_channelsin thekvaser_usbstructure? If I looked correctly, you use this variable as a replacement forMAX_NET_DEVICESin the code andMAX_NET_DEVICESis only used in probe and disconnect functions. I think it can even be replaced by nchannels in the disconnect path. So I also think that it don't need to be in thekvaser_usbstructure.
hmmm.. given the current state of error arbitration explained above, where I cannot accept a dev->nchannels > 2, I guess we have two options:
a) Remove max_channels, and hardcode the channels count correctness logic as follows:
dev->nchannels = msg.u.cardinfo.nchannels;
if ((dev->family == USBCAN && dev->nchannels > USBCAN_MAX_NET_DEVICES)
|| (dev->family == LEAF && dev->nchannels > LEAF_MAX_NET_DEVICES))
return -EINVALb) Leave max_channels in 'struct kvaser_usb' as is.
I personally prefer the solution at 'b)' but I can do it as in 'a)' if you prefer :-)
Quoted 7 lines
Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c +0
-0err =kvaser_usb_get_endpoints (intf, &dev->bulk_in, &dev->bulk_out);if (err) {dev_err (&intf->dev,"Cannot get usb endpoint(s)" );@@ -1608,7 +1988,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev);
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1992
Quoted 3 lines
drivers/net/can/usb/kvaser_usb.c +1
-1-for (i =0 ; i <MAX_NET_DEVICES ; i++) +for (i =0 ; i < dev->max_channels; i++)kvaser_usb_send_simple_msg (dev,CMD_RESET_CHIP , i);Someone reported me that recent leaf firmwares go in trouble when you send a command for a channel that does not exist. Instead of
max_channels, you can use nchannels here and move the reset command in thekvaser_usb_init_one()function.
I've a patch for this but It is not tested yet. I'll send it next week-end after I did some tests.
Great. I guess I can submit a 3-patch series now
(kfree_skb fix + the above fix + driver).
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1994
Quoted 2 lines
drivers/net/can/usb/kvaser_usb.c +0
-0err =kvaser_usb_get_software_info (dev);Thank you,
Thanks a lot for your review.
P.S. the Gmail mailer you've used messed badly with the patch code identation; I had to manually restore it back to make the discussion meaningful for others :-)
Regards,
--
Darwish
Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
Hello Ahmed,
Quoted 67 lines · Ahmed S. Darwish
Hi Olivier,
Quoted 13 lines · Olivier Sobrie
Hello Ahmed,
Quoted 10 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'UsbcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
This patch adds support for the UsbcanII family of devices to the current Kvaser Leaf-only driver.
Quoted 8 lines
Quoted 4 lines
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
Good, thank you :-) I'll try to test the patch during the next week-end. Small remarks below.
Great! thanks and Merry Christmas :-)
Quoted 32 lines
Quoted 32 lines
Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 630 +++++++++++++++++++++++++++++++-------- 1 file changed, 505 insertions(+), 125 deletions(-)(Generated over 3.19.0-rc1 + generic bugfix at
can-kvaser_usb-Don-t-free-packets-when-tight-on-URBs.patch)drivers/net/can/usb/kvaser_usb.c +3
-0@@ -6,12 +6,15 @@* Parts of this driver are based on the following: * - Kvaser linux leaf driver (version 4.78) * - CAN driver for esd CAN-USB/2 +* - Kvaser linux usbcanII driver (version 5.3) * * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. * Copyright (C) 2010 Matthias Fuchs <[email protected]>, esd gmbh * Copyright (C) 2012 Olivier Sobrie <[email protected]> +* Copyright (C) 2014 Valeo Corporation */ +#include <linux/kernel.h> #include <linux/completion.h> #include <linux/module.h> #include <linux/netdevice.h> @@ -21,6 +24,18 @@#include <linux/can/dev.h> #include <linux/can/error.h> Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c line 27
Quoted 1 line
drivers/net/can/usb/kvaser_usb.c +1
-0+#define MAX (a, b) ((a) > (b) ? (a) : (b))There is a
max(a, b)macro in <linux/kernel.h>.Quite true, but it unfortunately fails when the symbol is used in array size declaration as in below:
Quoted 10 lines
struct kvaser_usb {
...
struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES];
...
}
include/linux/kernel.h:713:19: error: braced-group within
expression allowed only inside a function
#define max(x, y) ({ \
^Just let MAX_NET_DEVICES equals to 3.
Quoted 51 lines
Quoted 51 lines
Quoted 51 lines
drivers/net/can/usb/kvaser_usb.c +26
-2+ +/* +* Kvaser USB CAN dongles are divided into two major families: +* - Leaf: Based on Renesas M32C, running firmware labeled as 'filo' +* - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios' +*/ +enum kvaser_usb_family { +KVASER_LEAF , +KVASER_USBCAN , +}; +#define MAX_TX_URBS 16#define MAX_RX_URBS 4#define START_TIMEOUT 1000/* msecs */ @@ -29,9 +44,12 @@#define USB_RECV_TIMEOUT 1000/* msecs */ #define RX_BUFFER_SIZE 3072#define CAN_USB_CLOCK 8000000 -#define MAX_NET_DEVICES 3 +#define LEAF_MAX_NET_DEVICES 3 +#define USBCAN_MAX_NET_DEVICES 2 +#define MAX_NET_DEVICES MAX(LEAF_MAX_NET_DEVICES, \ + USBCAN_MAX_NET_DEVICES) -/* Kvaser USB devices */ +/* Leaf USB devices */ #define KVASER_VENDOR_ID 0x0bfd#define USB_LEAF_DEVEL_PRODUCT_ID 10#define USB_LEAF_LITE_PRODUCT_ID 11@@ -55,6 +73,16 @@#define USB_CAN_R_PRODUCT_ID 39#define USB_LEAF_LITE_V2_PRODUCT_ID 288#define USB_MINI_PCIE_HS_PRODUCT_ID 289 +#define LEAF_PRODUCT_ID (id) (id >= USB_LEAF_DEVEL_PRODUCT_ID && \ + id <= USB_MINI_PCIE_HS_PRODUCT_ID) + +/* USBCANII devices */ +#define USB_USBCAN_REVB_PRODUCT_ID 2 +#define USB_VCI2_PRODUCT_ID 3 +#define USB_USBCAN2_PRODUCT_ID 4 +#define USB_MEMORATOR_PRODUCT_ID 5 +#define USBCAN_PRODUCT_ID (id) (id >= USB_USBCAN_REVB_PRODUCT_ID && \ + id <= USB_MEMORATOR_PRODUCT_ID)/* USB devices features */ #define KVASER_HAS_SILENT_MODE BIT(0)@@ -73,7 +101,7 @@#define MSG_FLAG_TX_ACK BIT(6)#define MSG_FLAG_TX_REQUEST BIT(7)
Quoted 16 lines
Quoted 8 lines
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c +1
-1-/* Can states */ +/* Can states (M16C CxSTRH register) */ #define M16C_STATE_BUS_RESET BIT(0)#define M16C_STATE_BUS_ERROR BIT(4)#define M16C_STATE_BUS_PASSIVE BIT(5)@@ -98,7 +126,13 @@#define CMD_START_CHIP_REPLY 27#define CMD_STOP_CHIP 28Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c line 134
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c +6
-1#define CMD_STOP_CHIP_REPLY 29 -#define CMD_GET_CARD_INFO2 32 +#define CMD_READ_CLOCK 30 +#define CMD_READ_CLOCK_REPLY 31 + +#define LEAF_CMD_GET_CARD_INFO2 32 +#define USBCAN_CMD_RESET_CLOCK 32 +#define USBCAN_CMD_CLOCK_OVERFLOW_EVENT 33
I would prefer if you use CMD_LEAF_xxx and CMD_USBCAN_xxx.
Quoted 987 lines
Quoted 338 lines
Quoted 338 lines
drivers/net/can/usb/kvaser_usb.c +176
-25+#define CMD_GET_CARD_INFO 34#define CMD_GET_CARD_INFO_REPLY 35#define CMD_GET_SOFTWARE_INFO 38@@ -108,8 +142,9 @@#define CMD_RESET_ERROR_COUNTER 49#define CMD_TX_ACKNOWLEDGE 50#define CMD_CAN_ERROR_EVENT 51 -#define CMD_USB_THROTTLE 77 -#define CMD_LOG_MESSAGE 106 + +#define LEAF_CMD_USB_THROTTLE 77 +#define LEAF_CMD_LOG_MESSAGE 106/* error factors */ #define M16C_EF_ACKE BIT(0)@@ -121,6 +156,13 @@#define M16C_EF_RCVE BIT(6)#define M16C_EF_TRE BIT(7) +/* Only Leaf-based devices can report M16C error factors, +* thus define our own error status flags for USBCAN */ +#define USBCAN_ERROR_STATE_NONE 0 +#define USBCAN_ERROR_STATE_TX_ERROR BIT(0) +#define USBCAN_ERROR_STATE_RX_ERROR BIT(1) +#define USBCAN_ERROR_STATE_BUSERROR BIT(2) +/* bittiming parameters */ #define KVASER_USB_TSEG1_MIN 1#define KVASER_USB_TSEG1_MAX 16@@ -137,7 +179,7 @@#define KVASER_CTRL_MODE_SELFRECEPTION 3#define KVASER_CTRL_MODE_OFF 4 -/* log message */ +/* Extended CAN identifier flag */ #define KVASER_EXTENDED_FRAME BIT(31)struct kvaser_msg_simple {@@ -148,30 +190,55 @@ struct kvaser_msg_simple {struct kvaser_msg_cardinfo {u8 tid;u8 nchannels; -__le32 serial_number; -__le32 padding; +union { +struct { +__le32 serial_number; +__le32 padding; + } __packed leaf0; +struct { +__le32 serial_number_low; +__le32 serial_number_high; + } __packed usbcan0; + } __packed;__le32 clock_resolution;__le32 mfgdate;u8 ean[8 ];u8 hw_revision; -u8 usb_hs_mode; -__le16 padding2; +union { +struct { +u8 usb_hs_mode; + } __packed leaf1; +struct { +u8 padding; + } __packed usbcan1; + } __packed; +__le16 padding; } __packed;struct kvaser_msg_cardinfo2 {u8 tid; -u8 channel; +u8 reserved;u8 pcb_id[24 ];__le32 oem_unlock_code; } __packed; -struct kvaser_msg_softinfo { +struct leaf_msg_softinfo {u8 tid; -u8 channel; +u8 padding0;__le32 sw_options;__le32 fw_version;__le16 max_outstanding_tx; -__le16 padding[9 ]; +__le16 padding1[9 ]; +} __packed; + +struct usbcan_msg_softinfo { +u8 tid; +u8 fw_name[5 ]; +__le16 max_outstanding_tx; +u8 padding[6 ]; +__le32 fw_version; +__le16 checksum; +__le16 sw_options; } __packed;struct kvaser_msg_busparams {@@ -188,36 +255,86 @@ struct kvaser_msg_tx_can {u8 channel;u8 tid;u8 msg[14 ]; -u8 padding; -u8 flags; +union { +struct { +u8 padding; +u8 flags; + } __packed leaf; +struct { +u8 flags; +u8 padding; + } __packed usbcan; + } __packed; +} __packed; + +struct kvaser_msg_rx_can_header { +u8 channel; +u8 flag; } __packed; -struct kvaser_msg_rx_can { +struct leaf_msg_rx_can {u8 channel;u8 flag; +__le16 time[3 ];u8 msg[14 ]; } __packed; -struct kvaser_msg_chip_state_event { +struct usbcan_msg_rx_can { +u8 channel; +u8 flag; + +u8 msg[14 ]; +__le16 time; +} __packed; + +struct leaf_msg_chip_state_event {u8 tid;u8 channel; +__le16 time[3 ];u8 tx_errors_count;u8 rx_errors_count; +u8 status;u8 padding[3 ]; } __packed; -struct kvaser_msg_tx_acknowledge { +struct usbcan_msg_chip_state_event { +u8 tid; +u8 channel; + +u8 tx_errors_count; +u8 rx_errors_count; +__le16 time; + +u8 status; +u8 padding[3 ]; +} __packed; + +struct kvaser_msg_tx_acknowledge_header { +u8 channel; +u8 tid; +}; + +struct leaf_msg_tx_acknowledge {u8 channel;u8 tid; +__le16 time[3 ];u8 flags;u8 time_offset; } __packed; -struct kvaser_msg_error_event { +struct usbcan_msg_tx_acknowledge { +u8 channel; +u8 tid; + +__le16 time; +__le16 padding; +} __packed; + +struct leaf_msg_error_event {u8 tid;u8 flags;__le16 time[3 ];@@ -229,6 +346,18 @@ struct kvaser_msg_error_event {u8 error_factor; } __packed; +struct usbcan_msg_error_event { +u8 tid; +u8 padding; +u8 tx_errors_count_ch0; +u8 rx_errors_count_ch0; +u8 tx_errors_count_ch1; +u8 rx_errors_count_ch1; +u8 status_ch0; +u8 status_ch1; +__le16 time; +} __packed; +struct kvaser_msg_ctrl_mode {u8 tid;u8 channel;@@ -243,7 +372,7 @@ struct kvaser_msg_flush_queue {u8 padding[3 ]; } __packed; -struct kvaser_msg_log_message { +struct leaf_msg_log_message {u8 channel;u8 flags;__le16 time[3 ];@@ -260,19 +389,49 @@ struct kvaser_msg {struct kvaser_msg_simple simple;struct kvaser_msg_cardinfo cardinfo;struct kvaser_msg_cardinfo2 cardinfo2; -struct kvaser_msg_softinfo softinfo;struct kvaser_msg_busparams busparams; + +struct kvaser_msg_rx_can_header rx_can_header; +struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header; + +union { +struct leaf_msg_softinfo softinfo; +struct leaf_msg_rx_can rx_can; +struct leaf_msg_chip_state_event chip_state_event; +struct leaf_msg_tx_acknowledge tx_acknowledge; +struct leaf_msg_error_event error_event; +struct leaf_msg_log_message log_message; + } __packed leaf; + +union { +struct usbcan_msg_softinfo softinfo; +struct usbcan_msg_rx_can rx_can; +struct usbcan_msg_chip_state_event chip_state_event; +struct usbcan_msg_tx_acknowledge tx_acknowledge; +struct usbcan_msg_error_event error_event; + } __packed usbcan; +struct kvaser_msg_tx_can tx_can; -struct kvaser_msg_rx_can rx_can; -struct kvaser_msg_chip_state_event chip_state_event; -struct kvaser_msg_tx_acknowledge tx_acknowledge; -struct kvaser_msg_error_event error_event;struct kvaser_msg_ctrl_mode ctrl_mode;struct kvaser_msg_flush_queue flush_queue; -struct kvaser_msg_log_message log_message; } u; } __packed; +/* Leaf/USBCAN-agnostic summary of an error event. +* No M16C error factors for USBCAN-based devices. */ +struct kvaser_error_summary { +u8 channel, status, txerr, rxerr; +union { +struct { +u8 error_factor; + } leaf; +struct { +u8 other_ch_status; +u8 error_state; + } usbcan; + }; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;@@ -288,6 +447,8 @@ struct kvaser_usb {u32 fw_version;unsigned int nchannels; +enum kvaser_usb_family family; +unsigned int max_channels;bool rxinitdone;void *rxbuf[MAX_RX_URBS ];@@ -311,6 +472,7 @@ struct kvaser_usb_net_priv { };static const struct usb_device_id kvaser_usb_table[] = { +/* Leaf family IDs */ {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_DEVEL_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_LITE_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_PRO_PRODUCT_ID ),@@ -360,6 +522,17 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = KVASER_HAS_TXRX_ERRORS }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, + +/* USBCANII family IDs */ + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { } };MODULE_DEVICE_TABLE (usb, kvaser_usb_table);@@ -463,7 +636,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)if (err)return err; - dev->fw_version =le32_to_cpu (msg.u.softinfo.fw_version); +switch (dev->family) { +case KVASER_LEAF : + dev->fw_version =le32_to_cpu (msg.u.leaf.softinfo.fw_version); +break ; +case KVASER_USBCAN : + dev->fw_version =le32_to_cpu (msg.u.usbcan.softinfo.fw_version); +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); +return -EINVAL ; + }return 0 ; }@@ -482,7 +666,7 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)return err;Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_get_card_info(struct kvaser_usb *dev) · line 670
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +1
-1dev->nchannels = msg.u.cardinfo.nchannels; -if (dev->nchannels >MAX_NET_DEVICES ) +if (dev->nchannels > dev->max_channels)return -EINVAL ;IMHO, you can keep
MAX_NET_DEVICEShere.The UsbcanII firmware hardcodes a maximum of 2 channels in its protocol. This is unfortunately due to its inability to tell whether an error event is from CAN channel 0 or ch 1, and also due to its
error_eventformat:struct usbcan_msg_error_event { u8 tid; u8 padding; u8 tx_errors_count_ch0; u8 rx_errors_count_ch0; u8 tx_errors_count_ch1; u8 rx_errors_count_ch1; u8 status_ch0; u8 status_ch1; __le16 time; } __packed;But since we have
MAX_NET_DEVICES= 3, and given the above, if the UsbcanII firmware reported to us having more than 2 channels, then it's:a) most probably a memory corruption bug either in the firmware or in the driver
b) an updated device/firmware we cannot support yet, since we cannot arbitrate the origin of error events quite correctly (especially in the case ofCAN_ERR_BUSERROR, where the error counters stays the same and we have to resort to other hacks. Kindly checkusbcan_report_error_if_applicable().)So allowing more than 2 channels given the current set of affairs will really induce correctness problems :-(
Quoted 518 lines
Quoted 518 lines
drivers/net/can/usb/kvaser_usb.c +260
-91return 0 ;@@ -496,8 +680,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,struct kvaser_usb_net_priv *priv;struct sk_buff *skb;struct can_frame *cf; -u8 channel = msg->u.tx_acknowledge.channel; -u8 tid = msg->u.tx_acknowledge.tid; +u8 channel, tid; + + channel = msg->u.tx_acknowledge_header.channel; + tid = msg->u.tx_acknowledge_header.tid;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,@@ -615,37 +801,83 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index =MAX_TX_URBS ; } -static void kvaser_usb_rx_error (const struct kvaser_usb *dev, -const struct kvaser_msg *msg) +static void kvaser_report_error_event (const struct kvaser_usb *dev, +struct kvaser_error_summary *es); + +/* +* Report error to userspace iff the controller's errors counter has +* increased, or we're the only channel seeing the bus error state. +* +* As reported by USBCAN sheets, "the CAN controller has difficulties +* to tell whether an error frame arrived on channel 1 or on channel 2." +* Thus, error counters are compared with their earlier values to +* determine which channel was responsible for the error event. +*/ +static void usbcan_report_error_if_applicable (const struct kvaser_usb *dev, +struct kvaser_error_summary *es) { -struct can_frame *cf; -struct sk_buff *skb; -struct net_device_stats *stats;struct kvaser_usb_net_priv *priv; -unsigned int new_state; -u8 channel, status, txerr, rxerr, error_factor; +int old_tx_err_count, old_rx_err_count, channel, report_error; + + channel = es->channel; +if (channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , channel); +return ; + } + + priv = dev->nets[channel]; + old_tx_err_count = priv->bec.txerr; + old_rx_err_count = priv->bec.rxerr; + + report_error =0 ; +if (es->txerr > old_tx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_TX_ERROR ; + report_error =1 ; + } +if (es->rxerr > old_rx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_RX_ERROR ; + report_error =1 ; + } +if ((es->status &M16C_STATE_BUS_ERROR ) && + !(es->usbcan.other_ch_status &M16C_STATE_BUS_ERROR )) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_BUSERROR ; + report_error =1 ; + } + +if (report_error) +kvaser_report_error_event (dev, es); +} + +/* +* Extract error summary from a Leaf-based device error message +*/ +static void leaf_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , };switch (msg->id) {case CMD_CAN_ERROR_EVENT : - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; + es.channel = msg->u.leaf.error_event.channel; + es.status = msg->u.leaf.error_event.status; + es.txerr = msg->u.leaf.error_event.tx_errors_count; + es.rxerr = msg->u.leaf.error_event.rx_errors_count; + es.leaf.error_factor = msg->u.leaf.error_event.error_factor;break ; -case CMD_LOG_MESSAGE : - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0 ]; - txerr = msg->u.log_message.data[2 ]; - rxerr = msg->u.log_message.data[3 ]; - error_factor = msg->u.log_message.data[1 ]; +case LEAF_CMD_LOG_MESSAGE : + es.channel = msg->u.leaf.log_message.channel; + es.status = msg->u.leaf.log_message.data[0 ]; + es.txerr = msg->u.leaf.log_message.data[2 ]; + es.rxerr = msg->u.leaf.log_message.data[3 ]; + es.leaf.error_factor = msg->u.leaf.log_message.data[1 ];break ;case CMD_CHIP_STATE_EVENT : - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor =0 ; + es.channel = msg->u.leaf.chip_state_event.channel; + es.status = msg->u.leaf.chip_state_event.status; + es.txerr = msg->u.leaf.chip_state_event.tx_errors_count; + es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count; + es.leaf.error_factor =0 ;break ;default : dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",@@ -653,16 +885,92 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,return ; } -if (channel >= dev->nchannels) { +kvaser_report_error_event (dev, &es); +} + +/* +* Extract summary from a USBCANII-based device error message. +*/ +static void usbcan_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , }; + +switch (msg->id) { + +/* Sometimes errors are sent as unsolicited chip state events */ +case CMD_CHIP_STATE_EVENT : + es.channel = msg->u.usbcan.chip_state_event.channel; + es.status = msg->u.usbcan.chip_state_event.status; + es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count; + es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count; +usbcan_report_error_if_applicable (dev, &es); +break ; + +case CMD_CAN_ERROR_EVENT : + es.channel =0 ; + es.status = msg->u.usbcan.error_event.status_ch0; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch1; +usbcan_report_error_if_applicable (dev, &es); + +/* For error events, the USBCAN firmware does not support +* more than 2 channels: ch0, and ch1. */ +if (dev->nchannels >1 ) { + es.channel =1 ; + es.status = msg->u.usbcan.error_event.status_ch1; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch0; +usbcan_report_error_if_applicable (dev, &es); + } +break ; + +default : +dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , + msg->id); + } +} + +static void kvaser_usb_rx_error (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +switch (dev->family) { +case KVASER_LEAF : +leaf_extract_error_from_msg (dev, msg); +break ; +case KVASER_USBCAN : +usbcan_extract_error_from_msg (dev, msg); +break ; +default :dev_err (dev->udev->dev.parent, -"Invalid channel number (%d)\n" , channel); +"Invalid device family (%d)\n" , dev->family);return ; } +} - priv = dev->nets[channel]; +static void kvaser_report_error_event (const struct kvaser_usb *dev, +struct kvaser_error_summary *es) +{ +struct can_frame *cf; +struct sk_buff *skb; +struct net_device_stats *stats; +struct kvaser_usb_net_priv *priv; +unsigned int new_state; + +if (es->channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , es->channel); +return ; + } + + priv = dev->nets[es->channel]; stats = &priv->netdev->stats; -if (status &M16C_STATE_BUS_RESET ) { +if (es->status &M16C_STATE_BUS_RESET ) {kvaser_usb_unlink_tx_urbs (priv);return ; }@@ -675,9 +983,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, new_state = priv->can.state; -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (status &M16C_STATE_BUS_OFF ) { +if (es->status &M16C_STATE_BUS_OFF ) { cf->can_id |=CAN_ERR_BUSOFF ; priv->can.can_stats.bus_off++;@@ -687,12 +995,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,netif_carrier_off (priv->netdev); new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { + }else if (es->status &M16C_STATE_BUS_PASSIVE ) {if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es->txerr || es->rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else @@ -703,13 +1011,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } new_state =CAN_STATE_ERROR_PASSIVE ; - } - -if (status ==M16C_STATE_BUS_ERROR ) { + }else if (es->status &M16C_STATE_BUS_ERROR ) {if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { + ((es->txerr >=96 ) || (es->rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ;@@ -723,7 +1029,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } } -if (!status) { +if (!es->status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ;@@ -739,34 +1045,52 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv->can.can_stats.restarts++; } -if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - - cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; - -if (error_factor &M16C_EF_ACKE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); -if (error_factor &M16C_EF_CRCE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | -CAN_ERR_PROT_LOC_CRC_DEL ); -if (error_factor &M16C_EF_FORME ) - cf->data[2 ] |=CAN_ERR_PROT_FORM ; -if (error_factor &M16C_EF_STFE ) - cf->data[2 ] |=CAN_ERR_PROT_STUFF ; -if (error_factor &M16C_EF_BITE0 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; -if (error_factor &M16C_EF_BITE1 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; -if (error_factor &M16C_EF_TRE ) - cf->data[2 ] |=CAN_ERR_PROT_TX ; +switch (dev->family) { +case KVASER_LEAF : +if (es->leaf.error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; + +if (es->leaf.error_factor &M16C_EF_ACKE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); +if (es->leaf.error_factor &M16C_EF_CRCE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | +CAN_ERR_PROT_LOC_CRC_DEL ); +if (es->leaf.error_factor &M16C_EF_FORME ) + cf->data[2 ] |=CAN_ERR_PROT_FORM ; +if (es->leaf.error_factor &M16C_EF_STFE ) + cf->data[2 ] |=CAN_ERR_PROT_STUFF ; +if (es->leaf.error_factor &M16C_EF_BITE0 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; +if (es->leaf.error_factor &M16C_EF_BITE1 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; +if (es->leaf.error_factor &M16C_EF_TRE ) + cf->data[2 ] |=CAN_ERR_PROT_TX ; + } +break ; +case KVASER_USBCAN : +if (es->usbcan.error_state &USBCAN_ERROR_STATE_TX_ERROR ) + stats->tx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_RX_ERROR ) + stats->rx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_BUSERROR ) { + priv->can.can_stats.bus_error++; + cf->can_id |=CAN_ERR_BUSERROR ; + } +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto err; } - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; + cf->data[6 ] = es->txerr; + cf->data[7 ] = es->rxerr; - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; priv->can.state = new_state;@@ -774,6 +1098,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + +return ; + +err: +dev_kfree_skb (skb); } static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,@@ -783,16 +1112,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,struct sk_buff *skb;struct net_device_stats *stats = &priv->netdev->stats; -if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | +if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |MSG_FLAG_NERR )) {netdev_err (priv->netdev,"Unknow error (flags: 0x%02x)\n" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); stats->rx_errors++;return ; } -if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { +if (msg->u.rx_can_header.flag &MSG_FLAG_OVERRUN ) { skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;@@ -819,7 +1148,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,struct can_frame *cf;struct sk_buff *skb;struct net_device_stats *stats; -u8 channel = msg->u.rx_can.channel; +u8 channel = msg->u.rx_can_header.channel; +const u8 *rx_msg;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,@@ -830,19 +1160,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; -if ((msg->u.rx_can.flag &MSG_FLAG_ERROR_FRAME ) && - (msg->id ==CMD_LOG_MESSAGE )) { +if ((msg->u.rx_can_header.flag &MSG_FLAG_ERROR_FRAME ) && + (dev->family ==KVASER_LEAF && msg->id ==LEAF_CMD_LOG_MESSAGE )) {kvaser_usb_rx_error (dev, msg);return ; - }else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | -MSG_FLAG_NERR | -MSG_FLAG_OVERRUN )) { + }else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME | +MSG_FLAG_NERR | +MSG_FLAG_OVERRUN )) {kvaser_usb_rx_can_err (priv, msg);return ; - }else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME ) { + }else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME ) {netdev_warn (priv->netdev,"Unhandled frame (flags: 0x%02x)" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); +return ; + } + +switch (dev->family) { +case KVASER_LEAF : + rx_msg = msg->u.leaf.rx_can.msg; +break ; +case KVASER_USBCAN : + rx_msg = msg->u.usbcan.rx_can.msg; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family);return ; }@@ -852,38 +1195,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,return ; } -if (msg->id ==CMD_LOG_MESSAGE ) { - cf->can_id =le32_to_cpu (msg->u.log_message.id); +if (dev->family ==KVASER_LEAF && msg->id ==LEAF_CMD_LOG_MESSAGE ) { + cf->can_id =le32_to_cpu (msg->u.leaf.log_message.id);if (cf->can_id &KVASER_EXTENDED_FRAME ) cf->can_id &=CAN_EFF_MASK |CAN_EFF_FLAG ;else cf->can_id &=CAN_SFF_MASK ; - cf->can_dlc =get_can_dlc (msg->u.log_message.dlc); + cf->can_dlc =get_can_dlc (msg->u.leaf.log_message.dlc); -if (msg->u.log_message.flags &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.leaf.log_message.flags &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.log_message.data, +memcpy (cf->data, &msg->u.leaf.log_message.data, cf->can_dlc); }else { - cf->can_id = ((msg->u.rx_can.msg[0 ] &0x1f ) <<6 ) | - (msg->u.rx_can.msg[1 ] &0x3f ); + cf->can_id = ((rx_msg[0 ] &0x1f ) <<6 ) | (rx_msg[1 ] &0x3f );if (msg->id ==CMD_RX_EXT_MESSAGE ) { cf->can_id <<=18 ; - cf->can_id |= ((msg->u.rx_can.msg[2 ] &0x0f ) <<14 ) | - ((msg->u.rx_can.msg[3 ] &0xff ) <<6 ) | - (msg->u.rx_can.msg[4 ] &0x3f ); + cf->can_id |= ((rx_msg[2 ] &0x0f ) <<14 ) | + ((rx_msg[3 ] &0xff ) <<6 ) | + (rx_msg[4 ] &0x3f ); cf->can_id |=CAN_EFF_FLAG ; } - cf->can_dlc =get_can_dlc (msg->u.rx_can.msg[5 ]); + cf->can_dlc =get_can_dlc (rx_msg[5 ]); -if (msg->u.rx_can.flag &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.rx_can_header.flag &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.rx_can.msg[6 ], +memcpy (cf->data, &rx_msg[6 ], cf->can_dlc); }@@ -947,7 +1289,12 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,case CMD_RX_STD_MESSAGE :case CMD_RX_EXT_MESSAGE : -case CMD_LOG_MESSAGE : +kvaser_usb_rx_can_msg (dev, msg); +break ; + +case LEAF_CMD_LOG_MESSAGE : +if (dev->family !=KVASER_LEAF ) + goto warn;kvaser_usb_rx_can_msg (dev, msg);break ;@@ -960,8 +1307,14 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,kvaser_usb_tx_acknowledge (dev, msg);break ; +/* Ignored messages */ +case USBCAN_CMD_CLOCK_OVERFLOW_EVENT : +if (dev->family !=KVASER_USBCAN ) + goto warn; +break ; +default : -dev_warn (dev->udev->dev.parent, +warn:dev_warn (dev->udev->dev.parent,"Unhandled message (%d)\n" , msg->id);break ; }@@ -1181,7 +1534,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) dev->rxbuf[i], dev->rxbuf_dma[i]);Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) · line 1537
Quoted 2 lines
drivers/net/can/usb/kvaser_usb.c +1
-1-for (i =0 ; i <MAX_NET_DEVICES ; i++) { +for (i =0 ; i < dev->max_channels; i++) {here too... or replace it by nchannels.
Yes, indeed. nchannels is the correct choice here, especially since
kvaser_usb_init_one()is called "dev->nchannels" times too.Quoted 60 lines
Quoted 60 lines
drivers/net/can/usb/kvaser_usb.c +28
-2struct kvaser_usb_net_priv *priv = dev->nets[i];if (priv)@@ -1286,6 +1639,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,struct kvaser_msg *msg;int i, err;int ret =NETDEV_TX_OK ; +uint8_t *msg_tx_can_flags;bool kfree_skb_on_error = true;if (can_dropped_invalid_skb (netdev, skb))@@ -1306,9 +1660,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, msg = buf; msg->len =MSG_HEADER_LEN +sizeof (struct kvaser_msg_tx_can ); - msg->u.tx_can.flags =0 ; msg->u.tx_can.channel = priv->channel; +switch (dev->family) { +case KVASER_LEAF : + msg_tx_can_flags = &msg->u.tx_can.leaf.flags; +break ; +case KVASER_USBCAN : + msg_tx_can_flags = &msg->u.tx_can.usbcan.flags; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto releasebuf; + } + + *msg_tx_can_flags =0 ; +if (cf->can_id &CAN_EFF_FLAG ) { msg->id =CMD_TX_EXT_MESSAGE ; msg->u.tx_can.msg[0 ] = (cf->can_id >>24 ) &0x1f ;@@ -1326,7 +1694,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,memcpy (&msg->u.tx_can.msg[6 ], cf->data, cf->can_dlc);if (cf->can_id &CAN_RTR_FLAG ) - msg->u.tx_can.flags |=MSG_FLAG_REMOTE_FRAME ; + *msg_tx_can_flags |=MSG_FLAG_REMOTE_FRAME ;for (i =0 ; i <ARRAY_SIZE (priv->tx_contexts); i++) {if (priv->tx_contexts[i].echo_index ==MAX_TX_URBS ) {@@ -1596,6 +1964,18 @@ static int kvaser_usb_probe(struct usb_interface *intf,if (!dev)return -ENOMEM ; +if (LEAF_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_LEAF ; + dev->max_channels =LEAF_MAX_NET_DEVICES ; + }else if (USBCAN_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_USBCAN ; + dev->max_channels =USBCAN_MAX_NET_DEVICES ; + }else { +dev_err (&intf->dev,"Product ID (%d) does not belong to any " +"known Kvaser USB family" , id->idProduct); +return -ENODEV ; + }Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1978
Quoted 1 line
drivers/net/can/usb/kvaser_usb.c +1
-0+Is it really required to keep
max_channelsin thekvaser_usbstructure? If I looked correctly, you use this variable as a replacement forMAX_NET_DEVICESin the code andMAX_NET_DEVICESis only used in probe and disconnect functions. I think it can even be replaced by nchannels in the disconnect path. So I also think that it don't need to be in thekvaser_usbstructure.hmmm.. given the current state of error arbitration explained above, where I cannot accept a
dev->nchannels> 2, I guess we have two options:a) Remove
max_channels, and hardcode the channels count correctness logic as follows:dev->nchannels = msg.u.cardinfo.nchannels; if ((dev->family == USBCAN && dev->nchannels > USBCAN_MAX_NET_DEVICES) || (dev->family == LEAF && dev->nchannels > LEAF_MAX_NET_DEVICES)) return -EINVAL
Quoted 4 lines
b) Leave
max_channelsin 'structkvaser_usb' as is.I personally prefer the solution at 'b)' but I can do it as in 'a)' if you prefer :-)
Keeping max_channels in the kvaser_usb structure is useless because it is only used in one function that is called in the probe function.
I would prefer to have:
if (dev->nchannels > MAX_NET_DEVICES) return -EINVAL if ((dev->family == USBCAN) && (dev->nchannels > MAX_USBCAN_NET_DEVICES)) return -EINVAL
You can remove LEAF_MAX_NET_DEVICES which is not used, keep MAX_NET_DEVICES equals to 3 and remove the MAX() macro. The test specific to the USBCAN family can eventually be moved in the kvaser_usb_probe() function.
Quoted 31 lines
Quoted 8 lines
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c +0
-0err =kvaser_usb_get_endpoints (intf, &dev->bulk_in, &dev->bulk_out);if (err) {dev_err (&intf->dev,"Cannot get usb endpoint(s)" );@@ -1608,7 +1988,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev);Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1992
Quoted 3 lines
drivers/net/can/usb/kvaser_usb.c +1
-1-for (i =0 ; i <MAX_NET_DEVICES ; i++) +for (i =0 ; i < dev->max_channels; i++)kvaser_usb_send_simple_msg (dev,CMD_RESET_CHIP , i);Someone reported me that recent leaf firmwares go in trouble when you send a command for a channel that does not exist. Instead of
max_channels, you can use nchannels here and move the reset command in thekvaser_usb_init_one()function.
I've a patch for this but It is not tested yet. I'll send it next week-end after I did some tests.Great. I guess I can submit a 3-patch series now
(kfree_skbfix + the above fix + driver).Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1994
Quoted 2 lines
drivers/net/can/usb/kvaser_usb.c +0
-0err =kvaser_usb_get_software_info (dev);Thank you,
Thanks a lot for your review.
Quoted 7 lines
P.S. the Gmail mailer you've used messed badly with the patch code identation; I had to manually restore it back to make the discussion meaningful for others :-)Regards,
--
Darwish
Kr,
Signature · 1 line
Olivier
Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
On Sun, Dec 28, 2014 at 10:51:34PM +0100, Olivier Sobrie wrote:
[...]
Quoted 50 lines
Quoted 34 lines
Quoted 12 lines
Quoted 12 lines
drivers/net/can/usb/kvaser_usb.c +11
-0+if (LEAF_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_LEAF ; + dev->max_channels =LEAF_MAX_NET_DEVICES ; + }else if (USBCAN_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_USBCAN ; + dev->max_channels =USBCAN_MAX_NET_DEVICES ; + }else { +dev_err (&intf->dev,"Product ID (%d) does not belong to any " +"known Kvaser USB family" , id->idProduct); +return -ENODEV ; + }Quoted 9 lines
Quoted 1 line
+
Is it really required to keep
max_channelsin thekvaser_usbstructure? If I looked correctly, you use this variable as a replacement forMAX_NET_DEVICESin the code andMAX_NET_DEVICESis only used in probe and disconnect functions. I think it can even be replaced by nchannels in the disconnect path. So I also think that it don't need to be in thekvaser_usbstructure.hmmm.. given the current state of error arbitration explained above, where I cannot accept a
dev->nchannels> 2, I guess we have two options:a) Remove
max_channels, and hardcode the channels count correctness logic as follows:dev->nchannels = msg.u.cardinfo.nchannels; if ((dev->family == USBCAN && dev->nchannels > USBCAN_MAX_NET_DEVICES) || (dev->family == LEAF && dev->nchannels > LEAF_MAX_NET_DEVICES)) return -EINVALQuoted 4 lines
b) Leave
max_channelsin 'structkvaser_usb' as is.I personally prefer the solution at 'b)' but I can do it as in 'a)' if you prefer :-)
Keeping
max_channelsin thekvaser_usbstructure is useless because it is only used in one function that is called in the probe function.I would prefer to have:
if (dev->nchannels > MAX_NET_DEVICES) return -EINVAL if ((dev->family == USBCAN) && (dev->nchannels > MAX_USBCAN_NET_DEVICES)) return -EINVAL
Quoted 5 lines
You can remove
LEAF_MAX_NET_DEVICESwhich is not used, keepMAX_NET_DEVICESequals to 3 and remove theMAX()macro. The test specific to the USBCAN family can eventually be moved in thekvaser_usb_probe()function.
Quite nice, will do it that way in v3.
Regards,
Darwish
Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
Quoted 52 lines · Ahmed S. Darwish
On Sun, Dec 28, 2014 at 10:51:34PM +0100, Olivier Sobrie wrote:
[...]Quoted 50 lines
Quoted 34 lines
Quoted 12 lines
Quoted 12 lines
drivers/net/can/usb/kvaser_usb.c +11
-0+if (LEAF_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_LEAF ; + dev->max_channels =LEAF_MAX_NET_DEVICES ; + }else if (USBCAN_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_USBCAN ; + dev->max_channels =USBCAN_MAX_NET_DEVICES ; + }else { +dev_err (&intf->dev,"Product ID (%d) does not belong to any " +"known Kvaser USB family" , id->idProduct); +return -ENODEV ; + }Quoted 9 lines
Quoted 1 line
+
Is it really required to keep
max_channelsin thekvaser_usbstructure? If I looked correctly, you use this variable as a replacement forMAX_NET_DEVICESin the code andMAX_NET_DEVICESis only used in probe and disconnect functions. I think it can even be replaced by nchannels in the disconnect path. So I also think that it don't need to be in thekvaser_usbstructure.hmmm.. given the current state of error arbitration explained above, where I cannot accept a
dev->nchannels> 2, I guess we have two options:a) Remove
max_channels, and hardcode the channels count correctness logic as follows:dev->nchannels = msg.u.cardinfo.nchannels; if ((dev->family == USBCAN && dev->nchannels > USBCAN_MAX_NET_DEVICES) || (dev->family == LEAF && dev->nchannels > LEAF_MAX_NET_DEVICES)) return -EINVALQuoted 4 lines
b) Leave
max_channelsin 'structkvaser_usb' as is.I personally prefer the solution at 'b)' but I can do it as in 'a)' if you prefer :-)
Keeping
max_channelsin thekvaser_usbstructure is useless because it is only used in one function that is called in the probe function.I would prefer to have:
if (dev->nchannels > MAX_NET_DEVICES) return -EINVAL if ((dev->family == USBCAN) && (dev->nchannels > MAX_USBCAN_NET_DEVICES)) return -EINVAL
Quoted 8 lines
Quoted 5 lines
You can remove
LEAF_MAX_NET_DEVICESwhich is not used, keepMAX_NET_DEVICESequals to 3 and remove theMAX()macro. The test specific to the USBCAN family can eventually be moved in thekvaser_usb_probe()function.Quite nice, will do it that way in v3.
Thank you.
Please also check your patches with scripts/checkpatch.pl. I see several warnings when I run it. Please fix them.
All the best for New Year's Eve,
Signature · 1 line
Olivier
Hello Ahmed,
Quoted 6 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
Flooding the Kvaser CAN to USB dongle with multiple reads and writes in high frequency caused seemingly-random panics in the kernel.
Quoted 6 lines
On further inspection, it seems the driver erroneously freed the to-be-transmitted packet upon getting tight on URBs and returning
NETDEV_TX_BUSY, leading to invalid memory writes and double frees at a later point in time.Signed-off-by Ahmed S. Darwish <[email protected]>
Thank you for the fix.
Quoted 19 lines
--- drivers/net/can/usb/kvaser_usb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)(Generated over 3.19.0-rc1)
drivers/net/can/usb/kvaser_usb.c +1
-0@@ -1286,6 +1286,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,struct kvaser_msg *msg;int i, err;int ret =NETDEV_TX_OK ; +bool kfree_skb_on_error = true;if (can_dropped_invalid_skb (netdev, skb))return NETDEV_TX_OK ;
drivers/net/can/usb/kvaser_usb.c static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, · line 1340
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +1
-0@@ -1336,6 +1337,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (!context) {netdev_warn (netdev,"cannot find free context\n" ); + kfree_skb_on_error = false;
Instead of using an extra variable, you can also set skb to NULL here. Or maybe better, you can move the dev_kfree_skb() in the two previous tests (in the check of variables urb and buf).
Thank you,
Olivier
Quoted 23 lines
drivers/net/can/usb/kvaser_usb.c +3
-3ret =NETDEV_TX_BUSY ; goto releasebuf; }@@ -1364,8 +1366,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (unlikely (err)) {can_free_echo_skb (netdev, context->echo_index); - skb =NULL ;/* set to NULL to avoid double free in -* dev_kfree_skb(skb) */ + kfree_skb_on_error = false;atomic_dec (&priv->active_tx_urbs);usb_unanchor_urb (urb);@@ -1389,7 +1390,8 @@ releasebuf: nobufmem:usb_free_urb (urb); nourbmem: -dev_kfree_skb (skb); +if (kfree_skb_on_error) +dev_kfree_skb (skb);return ret; }
Hi Olivier,
Quoted 38 lines · Olivier Sobrie
Hello Ahmed,
Quoted 6 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
Flooding the Kvaser CAN to USB dongle with multiple reads and writes in high frequency caused seemingly-random panics in the kernel.
Quoted 6 lines
On further inspection, it seems the driver erroneously freed the to-be-transmitted packet upon getting tight on URBs and returning
NETDEV_TX_BUSY, leading to invalid memory writes and double frees at a later point in time.Signed-off-by Ahmed S. Darwish <[email protected]>Thank you for the fix.
Quoted 20 lines
--- drivers/net/can/usb/kvaser_usb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)(Generated over 3.19.0-rc1)
drivers/net/can/usb/kvaser_usb.c +1
-0@@ -1286,6 +1286,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,struct kvaser_msg *msg;int i, err;int ret =NETDEV_TX_OK ; +bool kfree_skb_on_error = true;if (can_dropped_invalid_skb (netdev, skb))return NETDEV_TX_OK ;@@ -1336,6 +1337,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, · line 1340
Quoted 3 lines
drivers/net/can/usb/kvaser_usb.c +1
-0if (!context) {netdev_warn (netdev,"cannot find free context\n" ); + kfree_skb_on_error = false;Instead of using an extra variable, you can also set skb to NULL here. Or maybe better, you can move the
dev_kfree_skb()in the two previous tests (in the check of variables urb and buf).
Nice, I'll move dev_kfree_skb() to the two earlier tests then.
Thanks,
P.S. mailer and patch identation; had to manually fix them before replying (but thanks for the quick review, ofc ;-))
Quoted 27 lines
Thank you,
Olivier
Quoted 23 lines
drivers/net/can/usb/kvaser_usb.c +3
-3ret =NETDEV_TX_BUSY ; goto releasebuf; }@@ -1364,8 +1366,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (unlikely (err)) {can_free_echo_skb (netdev, context->echo_index); - skb =NULL ;/* set to NULL to avoid double free in -* dev_kfree_skb(skb) */ + kfree_skb_on_error = false;atomic_dec (&priv->active_tx_urbs);usb_unanchor_urb (urb);@@ -1389,7 +1390,8 @@ releasebuf: nobufmem:usb_free_urb (urb); nourbmem: -dev_kfree_skb (skb); +if (kfree_skb_on_error) +dev_kfree_skb (skb);return ret; }
PATCH v2 1/4 can: kvaser_usb: Don't free packets when tight on URBs
In reply to Ahmed S. DarwishFrom: Ahmed S. Darwish <[email protected]>
Flooding the Kvaser CAN to USB dongle with multiple reads and writes in high frequency caused seemingly-random panics in the kernel.
On further inspection, it seems the driver erroneously freed the to-be-transmitted packet upon getting tight on URBs and returning NETDEV_TX_BUSY, leading to invalid memory writes and double frees at a later point in time.
Note:
Finding no more URBs/transmit-contexts and returning NETDEV_TX_BUSY is a driver bug in and out of itself: it means that our start/stop queue flow control is broken.
This patch only fixes the (buggy) error handling code; the root cause shall be fixed in a later commit.
--- drivers/net/can/usb/kvaser_usb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
(Marc, Greg, I believe this should also be added to -stable?)
drivers/net/can/usb/kvaser_usb.c +6 -6
@@ -1294,12 +1294,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (!urb) {netdev_err (netdev,"No memory left for URBs\n" ); stats->tx_dropped++; - goto nourbmem; +dev_kfree_skb (skb); +return NETDEV_TX_OK ; } buf =kmalloc (sizeof (struct kvaser_msg ),GFP_ATOMIC );if (!buf) { stats->tx_dropped++; +dev_kfree_skb (skb); goto nobufmem; }
@@ -1334,6 +1336,9 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, } } +/* +* This should never happen; it implies a flow control bug. +*/ if (!context) {netdev_warn (netdev,"cannot find free context\n" ); ret =NETDEV_TX_BUSY ;
@@ -1364,9 +1369,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (unlikely (err)) {can_free_echo_skb (netdev, context->echo_index); - skb =NULL ;/* set to NULL to avoid double free in -* dev_kfree_skb(skb) */ -atomic_dec (&priv->active_tx_urbs);usb_unanchor_urb (urb);
@@ -1388,8 +1390,6 @@ releasebuf:kfree (buf); nobufmem:usb_free_urb (urb); -nourbmem: -dev_kfree_skb (skb);return ret; }
PATCH v2 2/4 can: kvaser_usb: Reset all URB tx contexts upon channel close
From: Ahmed S. Darwish <[email protected]>
Flooding the Kvaser CAN to USB dongle with multiple reads and writes in very high frequency (*), closing the CAN channel while all the transmissions are on (#), opening the device again (@), then sending a small number of packets would make the driver enter an almost infinite loop of:
[....]
[15959.853988] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853990] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853991] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853993] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853994] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853995] kvaser_usb 4-3:1.0 can0: cannot find free context
[....]
_dragging the whole system down_ in the process due to the excessive logging output.
Initially, this has caused random panics in the kernel due to a buggy error recovery path. That got fixed in an earlier commit.(%) This patch aims at solving the root cause. -->
16 tx URBs and contexts are allocated per CAN channel per USB device. Such URBs are protected by:
a) A simple atomic counter, up to a value of MAX_TX_URBS (16)
b) A flag in each URB context, stating if it's free
c) The fact that ndo_start_xmit calls are themselves protected by the networking layers higher above
After grabbing one of the tx URBs, if the driver noticed that all of them are now taken, it stops the netif transmission queue. Such queue is worken up again only if an acknowedgment was received from the firmware on one of our earlier-sent frames.
Meanwhile, upon channel close (#), the driver sends a CMD_STOP_CHIP to the firmware, effectively closing all further communication. In the high traffic case, the atomic counter remains at MAX_TX_URBS, and all the URB contexts remain marked as active. While opening the channel again (@), it cannot send any further frames since no more free tx URB contexts are available.
Reset all tx URB contexts upon CAN channel close.
(*) 50 parallel instances of cangen0 -g 0 -ix (#) ifconfig can0 down
(@) ifconfig can0 up
(%) "can: kvaser_usb: Don't free packets when tight on URBs"
--- drivers/net/can/usb/kvaser_usb.c | 3 +++ 1 file changed, 3 insertions(+)
(Marc, Greg, this also should be added to -stable?)
drivers/net/can/usb/kvaser_usb.c +3 -0
@@ -1246,6 +1246,9 @@ static int kvaser_usb_close(struct net_device *netdev)if (err)netdev_warn (netdev,"Cannot stop device, error %d\n" , err); +/* reset tx contexts */ +kvaser_usb_unlink_tx_urbs (priv); + priv->can.state =CAN_STATE_STOPPED ;close_candev (priv->netdev);
PATCH v2 3/4 can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels
From: Ahmed S. Darwish <[email protected]>
"Someone reported me that recent leaf firmwares go in trouble when you send a command for a channel that does not exist. Instead ... you can move the reset command to kvaser_usb_init_one() function."
--- drivers/net/can/usb/kvaser_usb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/can/usb/kvaser_usb.c +4 -3
@@ -1505,6 +1505,10 @@ static int kvaser_usb_init_one(struct usb_interface *intf,struct kvaser_usb_net_priv *priv;int i, err; + err =kvaser_usb_send_simple_msg (dev,CMD_RESET_CHIP , channel); +if (err) +return err; + netdev =alloc_candev (sizeof (*priv),MAX_TX_URBS );if (!netdev) {dev_err (&intf->dev,"Cannot alloc candev\n" );
@@ -1609,9 +1613,6 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev); -for (i =0 ; i <MAX_NET_DEVICES ; i++) -kvaser_usb_send_simple_msg (dev,CMD_RESET_CHIP , i); - err =kvaser_usb_get_software_info (dev);if (err) { dev_err(&intf->dev,
PATCH v2 4/4 can: kvaser_usb: Add support for the Usbcan-II family
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'UsbcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
This patch adds support for the UsbcanII family of devices to the current Kvaser Leaf-only driver.
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
List of new devices supported by this driver update:
- Kvaser USBcan II HS/HS
- Kvaser USBcan II HS/LS
- Kvaser USBcan Rugged ("USBcan Rev B")
- Kvaser Memorator HS/HS
- Kvaser Memorator HS/LS
- Scania VCI2 (if you have the Kvaser logo on top)
--- drivers/net/can/usb/Kconfig | 8 +- drivers/net/can/usb/kvaser_usb.c | 627 +++++++++++++++++++++++++++++++-------- 2 files changed, 510 insertions(+), 125 deletions(-)
** V2 Changelog:
- Update Kconfig entries
- Use actual number of CAN channels (instead of max) where appropriate
- Rebase over a new set of UsbcanII-independent driver fixes
drivers/net/can/usb/Kconfig +7 -1
@@ -25,7 +25,7 @@ config CAN_KVASER_USB tristate "Kvaser CAN/USB interface" ---help--- This driver adds support for Kvaser CAN/USB devices like Kvaser - Leaf Light. + Leaf Light and Kvaser USBcan II. The driver provides support for the following devices: - Kvaser Leaf Light
@@ -46,6 +46,12 @@ config CAN_KVASER_USB - Kvaser USBcan R - Kvaser Leaf Light v2 - Kvaser Mini PCI Express HS + - Kvaser USBcan II HS/HS + - Kvaser USBcan II HS/LS + - Kvaser USBcan Rugged ("USBcan Rev B") + - Kvaser Memorator HS/HS + - Kvaser Memorator HS/LS + - Scania VCI2 (if you have the Kvaser logo on top) If unsure, say N.
drivers/net/can/usb/kvaser_usb.c +503 -124
971 lines not on this page · raw message
Re: [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels
In reply to Ahmed S. DarwishQuoted 5 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
"Someone reported me that recent leaf firmwares go in trouble when you send a command for a channel that does not exist. Instead ... you can move the reset command to
kvaser_usb_init_one()function."
Please adapt the commit log message as follows:
Recent Leaf firmware versions (>= 3.1.557) do not allow to send commands for non-existing channels. If a command is send for a non-existing channel, the firmware crashes.
And you can add:
Kr,
Olivier
Quoted 32 lines
Suggested-by Olivier Sobrie <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)drivers/net/can/usb/kvaser_usb.c +4
-3@@ -1505,6 +1505,10 @@ static int kvaser_usb_init_one(struct usb_interface *intf,struct kvaser_usb_net_priv *priv;int i, err; + err =kvaser_usb_send_simple_msg (dev,CMD_RESET_CHIP , channel); +if (err) +return err; + netdev =alloc_candev (sizeof (*priv),MAX_TX_URBS );if (!netdev) {dev_err (&intf->dev,"Cannot alloc candev\n" );@@ -1609,9 +1613,6 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev); -for (i =0 ; i <MAX_NET_DEVICES ; i++) -kvaser_usb_send_simple_msg (dev,CMD_RESET_CHIP , i); - err =kvaser_usb_get_software_info (dev);if (err) { dev_err(&intf->dev,
Greg KH
maintainerQuoted 20 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
Flooding the Kvaser CAN to USB dongle with multiple reads and writes in high frequency caused seemingly-random panics in the kernel.
On further inspection, it seems the driver erroneously freed the to-be-transmitted packet upon getting tight on URBs and returning
NETDEV_TX_BUSY, leading to invalid memory writes and double frees at a later point in time.Note:
Finding no more URBs/transmit-contexts and returning
NETDEV_TX_BUSYis a driver bug in and out of itself: it means that our start/stop queue flow control is broken.This patch only fixes the (buggy) error handling code; the root cause shall be fixed in a later commit.
Quoted 6 lines
Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)(Marc, Greg, I believe this should also be added to -stable?)
<formletter>
This is not the correct way to submit patches for inclusion in the stable kernel tree. Please read Documentation/stable_kernel_rules.txt for how to do this properly.
</formletter>
Quoted 29 lines · Greg KH
Quoted 20 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
Flooding the Kvaser CAN to USB dongle with multiple reads and writes in high frequency caused seemingly-random panics in the kernel.
On further inspection, it seems the driver erroneously freed the to-be-transmitted packet upon getting tight on URBs and returning
NETDEV_TX_BUSY, leading to invalid memory writes and double frees at a later point in time.Note:
Finding no more URBs/transmit-contexts and returning
NETDEV_TX_BUSYis a driver bug in and out of itself: it means that our start/stop queue flow control is broken.This patch only fixes the (buggy) error handling code; the root cause shall be fixed in a later commit.
Quoted 6 lines
Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)(Marc, Greg, I believe this should also be added to -stable?)
Quoted 7 lines
<formletter>
This is not the correct way to submit patches for inclusion in the stable kernel tree. Please read
Documentation/stable_kernel_rules.txtfor how to do this properly.</formletter>
<msg-response>
Note taken. Sorry about that ;-)
</msg-response>
Quoted 13 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
Flooding the Kvaser CAN to USB dongle with multiple reads and writes in high frequency caused seemingly-random panics in the kernel.
On further inspection, it seems the driver erroneously freed the to-be-transmitted packet upon getting tight on URBs and returning
NETDEV_TX_BUSY, leading to invalid memory writes and double frees at a later point in time.Note:
Quoted 8 lines
Finding no more URBs/transmit-contexts and returning
NETDEV_TX_BUSYis a driver bug in and out of itself: it means that our start/stop queue flow control is broken.This patch only fixes the (buggy) error handling code; the root cause shall be fixed in a later commit.
Signed-off-by Ahmed S. Darwish <[email protected]>
Quoted 55 lines
--- drivers/net/can/usb/kvaser_usb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)(Marc, Greg, I believe this should also be added to -stable?)
drivers/net/can/usb/kvaser_usb.c +6
-6@@ -1294,12 +1294,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (!urb) {netdev_err (netdev,"No memory left for URBs\n" ); stats->tx_dropped++; - goto nourbmem; +dev_kfree_skb (skb); +return NETDEV_TX_OK ; } buf =kmalloc (sizeof (struct kvaser_msg ),GFP_ATOMIC );if (!buf) { stats->tx_dropped++; +dev_kfree_skb (skb); goto nobufmem; }@@ -1334,6 +1336,9 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, } } +/* +* This should never happen; it implies a flow control bug. +*/ if (!context) {netdev_warn (netdev,"cannot find free context\n" ); ret =NETDEV_TX_BUSY ;@@ -1364,9 +1369,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (unlikely (err)) {can_free_echo_skb (netdev, context->echo_index); - skb =NULL ;/* set to NULL to avoid double free in -* dev_kfree_skb(skb) */ -atomic_dec (&priv->active_tx_urbs);usb_unanchor_urb (urb);@@ -1388,8 +1390,6 @@ releasebuf:kfree (buf); nobufmem:usb_free_urb (urb); -nourbmem: -dev_kfree_skb (skb);return ret; }
Signature · 1 line
Olivier
drivers/net/can/usb/kvaser_usb.c static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, · line 1341
Quoted 11 lines · On Tue, 23 Dec 2014 17:46:54 +0200 "Ahmed S. Darwish" <[email protected]>…
drivers/net/can/usb/kvaser_usb.c +2
-0int ret =NETDEV_TX_OK ; +bool kfree_skb_on_error = true;if (can_dropped_invalid_skb (netdev, skb))return NETDEV_TX_OK ;@@ -1336,6 +1337,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (!context) {netdev_warn (netdev,"cannot find free context\n" ); + kfree_skb_on_error = false; ret =NETDEV_TX_BUSY ;
You already have a flag value (ret == NETDEV_TX_BUSY), why not use that instead of introducing another variable?
Quoted 10 lines · Stephen Hemminger
Quoted 7 lines · On Tue, 23 Dec 2014 17:46:54 +0200 "Ahmed S. Darwish" <[email protected]>…
drivers/net/can/usb/kvaser_usb.c +1
-0int ret =NETDEV_TX_OK ; +bool kfree_skb_on_error = true;if (can_dropped_invalid_skb (netdev, skb))return NETDEV_TX_OK ;@@ -1336,6 +1337,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, · line 1341
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +1
-0if (!context) {netdev_warn (netdev,"cannot find free context\n" ); + kfree_skb_on_error = false; ret =NETDEV_TX_BUSY ;You already have a flag value (ret ==
NETDEV_TX_BUSY), why not use that instead of introducing another variable?
Yes, that variable got implicitly removed in v2 patch 1/4.
Thanks,
--
Darwish
PATCH v3 1/4 can: kvaser_usb: Don't free packets when tight on URBs
In reply to Ahmed S. DarwishFrom: Ahmed S. Darwish <[email protected]>
Flooding the Kvaser CAN to USB dongle with multiple reads and writes in high frequency caused seemingly-random panics in the kernel.
On further inspection, it seems the driver erroneously freed the to-be-transmitted packet upon getting tight on URBs and returning NETDEV_TX_BUSY, leading to invalid memory writes and double frees at a later point in time.
Note:
Finding no more URBs/transmit-contexts and returning NETDEV_TX_BUSY is a driver bug in and out of itself: it means that our start/stop queue flow control is broken.
This patch only fixes the (buggy) error handling code; the root cause shall be fixed in a later commit.
--- drivers/net/can/usb/kvaser_usb.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
** V3 Changelog:
- checkpatch.pl suggestions ('net/' commenting style)
drivers/net/can/usb/kvaser_usb.c +4 -6
@@ -1294,12 +1294,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (!urb) {netdev_err (netdev,"No memory left for URBs\n" ); stats->tx_dropped++; - goto nourbmem; +dev_kfree_skb (skb); +return NETDEV_TX_OK ; } buf =kmalloc (sizeof (struct kvaser_msg ),GFP_ATOMIC );if (!buf) { stats->tx_dropped++; +dev_kfree_skb (skb); goto nobufmem; }
@@ -1334,6 +1336,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, } } +/* This should never happen; it implies a flow control bug */ if (!context) {netdev_warn (netdev,"cannot find free context\n" ); ret =NETDEV_TX_BUSY ;
@@ -1364,9 +1367,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,if (unlikely (err)) {can_free_echo_skb (netdev, context->echo_index); - skb =NULL ;/* set to NULL to avoid double free in -* dev_kfree_skb(skb) */ -atomic_dec (&priv->active_tx_urbs);usb_unanchor_urb (urb);
@@ -1388,8 +1388,6 @@ releasebuf:kfree (buf); nobufmem:usb_free_urb (urb); -nourbmem: -dev_kfree_skb (skb);return ret; }
PATCH v3 2/4 can: kvaser_usb: Reset all URB tx contexts upon channel close
From: Ahmed S. Darwish <[email protected]>
Flooding the Kvaser CAN to USB dongle with multiple reads and writes in very high frequency (*), closing the CAN channel while all the transmissions are on (#), opening the device again (@), then sending a small number of packets would make the driver enter an almost infinite loop of:
[....]
[15959.853988] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853990] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853991] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853993] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853994] kvaser_usb 4-3:1.0 can0: cannot find free context [15959.853995] kvaser_usb 4-3:1.0 can0: cannot find free context
[....]
_dragging the whole system down_ in the process due to the excessive logging output.
Initially, this has caused random panics in the kernel due to a buggy error recovery path. That got fixed in an earlier commit.(%) This patch aims at solving the root cause. -->
16 tx URBs and contexts are allocated per CAN channel per USB device. Such URBs are protected by:
a) A simple atomic counter, up to a value of MAX_TX_URBS (16)
b) A flag in each URB context, stating if it's free
c) The fact that ndo_start_xmit calls are themselves protected by the networking layers higher above
After grabbing one of the tx URBs, if the driver noticed that all of them are now taken, it stops the netif transmission queue. Such queue is worken up again only if an acknowedgment was received from the firmware on one of our earlier-sent frames.
Meanwhile, upon channel close (#), the driver sends a CMD_STOP_CHIP to the firmware, effectively closing all further communication. In the high traffic case, the atomic counter remains at MAX_TX_URBS, and all the URB contexts remain marked as active. While opening the channel again (@), it cannot send any further frames since no more free tx URB contexts are available.
Reset all tx URB contexts upon CAN channel close.
(*) 50 parallel instances of cangen0 -g 0 -ix (#) ifconfig can0 down
(@) ifconfig can0 up
(%) "can: kvaser_usb: Don't free packets when tight on URBs"
--- drivers/net/can/usb/kvaser_usb.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/can/usb/kvaser_usb.c +3 -0
@@ -1246,6 +1246,9 @@ static int kvaser_usb_close(struct net_device *netdev)if (err)netdev_warn (netdev,"Cannot stop device, error %d\n" , err); +/* reset tx contexts */ +kvaser_usb_unlink_tx_urbs (priv); + priv->can.state =CAN_STATE_STOPPED ;close_candev (priv->netdev);
PATCH v3 3/4 can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels
From: Ahmed S. Darwish <[email protected]>
Recent Leaf firmware versions (>= 3.1.557) do not allow to send commands for non-existing channels. If a command is sent for a non-existing channel, the firmware crashes.
--- drivers/net/can/usb/kvaser_usb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
** V3 Changelog:
- Update commit log message per Olivier remarks on v2
drivers/net/can/usb/kvaser_usb.c +4 -3
@@ -1503,6 +1503,10 @@ static int kvaser_usb_init_one(struct usb_interface *intf,struct kvaser_usb_net_priv *priv;int i, err; + err =kvaser_usb_send_simple_msg (dev,CMD_RESET_CHIP , channel); +if (err) +return err; + netdev =alloc_candev (sizeof (*priv),MAX_TX_URBS );if (!netdev) {dev_err (&intf->dev,"Cannot alloc candev\n" );
@@ -1607,9 +1611,6 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev); -for (i =0 ; i <MAX_NET_DEVICES ; i++) -kvaser_usb_send_simple_msg (dev,CMD_RESET_CHIP , i); - err =kvaser_usb_get_software_info (dev);if (err) { dev_err(&intf->dev,
PATCH v3 4/4 can: kvaser_usb: Add support for the Usbcan-II family
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'UsbcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
This patch adds support for the UsbcanII family of devices to the current Kvaser Leaf-only driver.
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
List of new devices supported by this driver update:
- Kvaser USBcan II HS/HS
- Kvaser USBcan II HS/LS
- Kvaser USBcan Rugged ("USBcan Rev B")
- Kvaser Memorator HS/HS
- Kvaser Memorator HS/LS
- Scania VCI2 (if you have the Kvaser logo on top)
--- drivers/net/can/usb/Kconfig | 8 +- drivers/net/can/usb/kvaser_usb.c | 618 +++++++++++++++++++++++++++++++-------- 2 files changed, 503 insertions(+), 123 deletions(-)
** V2 Changelog:
- Update Kconfig entries
- Use actual number of CAN channels (instead of max) where appropriate
- Rebase over a new set of UsbcanII-independent driver fixes
** V3 Changelog:
- Fix padding for the usbcan_msg_tx_acknowledge command
- Remove kvaser_usb->max_channels and the MAX_NET_DEVICES macro
- Rename commands to CMD_LEAF_xxx and CMD_USBCAN_xxx
- Apply checkpatch.pl suggestions ('net/' comments, multi-line strings, etc.)
drivers/net/can/usb/Kconfig +7 -1
@@ -25,7 +25,7 @@ config CAN_KVASER_USB tristate "Kvaser CAN/USB interface" ---help--- This driver adds support for Kvaser CAN/USB devices like Kvaser - Leaf Light. + Leaf Light and Kvaser USBcan II. The driver provides support for the following devices: - Kvaser Leaf Light
@@ -46,6 +46,12 @@ config CAN_KVASER_USB - Kvaser USBcan R - Kvaser Leaf Light v2 - Kvaser Mini PCI Express HS + - Kvaser USBcan II HS/HS + - Kvaser USBcan II HS/LS + - Kvaser USBcan Rugged ("USBcan Rev B") + - Kvaser Memorator HS/HS + - Kvaser Memorator HS/LS + - Scania VCI2 (if you have the Kvaser logo on top) If unsure, say N.
drivers/net/can/usb/kvaser_usb.c +496 -122
962 lines not on this page · raw message
Marc Kleine-Budde
maintainerRe: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
Quoted 111 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'UsbcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
This patch adds support for the UsbcanII family of devices to the current Kvaser Leaf-only driver.
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
List of new devices supported by this driver update:
- Kvaser USBcan II HS/HS
- Kvaser USBcan II HS/LS
- Kvaser USBcan Rugged ("USBcan Rev B")
- Kvaser Memorator HS/HS
- Kvaser Memorator HS/LS
- Scania VCI2 (if you have the Kvaser logo on top)Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/Kconfig | 8 +- drivers/net/can/usb/kvaser_usb.c | 618 +++++++++++++++++++++++++++++++-------- 2 files changed, 503 insertions(+), 123 deletions(-)** V2 Changelog:
- UpdateKconfigentries
- Use actual number of CAN channels (instead of max) where appropriate
- Rebase over a new set of UsbcanII-independent driver fixes** V3 Changelog:
- Fix padding for theusbcan_msg_tx_acknowledgecommand
- Removekvaser_usb->max_channelsand theMAX_NET_DEVICESmacro
- Rename commands toCMD_LEAF_xxxandCMD_USBCAN_xxx
- Apply checkpatch.pl suggestions ('net/' comments, multi-line strings, etc.)drivers/net/can/usb/Kconfig +7
-1@@ -25,7 +25,7 @@ config CAN_KVASER_USB tristate "Kvaser CAN/USB interface" ---help--- This driver adds support for Kvaser CAN/USB devices like Kvaser - Leaf Light. + Leaf Light and Kvaser USBcan II. The driver provides support for the following devices: - Kvaser Leaf Light@@ -46,6 +46,12 @@ config CAN_KVASER_USB - Kvaser USBcan R - Kvaser Leaf Light v2 - Kvaser Mini PCI Express HS + - Kvaser USBcan II HS/HS + - Kvaser USBcan II HS/LS + - Kvaser USBcan Rugged ("USBcan Rev B") + - Kvaser Memorator HS/HS + - Kvaser Memorator HS/LS + - Scania VCI2 (if you have the Kvaser logo on top) If unsure, say N.drivers/net/can/usb/kvaser_usb.c +13
-1@@ -6,10 +6,12 @@* Parts of this driver are based on the following: * - Kvaser linux leaf driver (version 4.78) * - CAN driver for esd CAN-USB/2 +* - Kvaser linux usbcanII driver (version 5.3) * * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. * Copyright (C) 2010 Matthias Fuchs <[email protected]>, esd gmbh * Copyright (C) 2012 Olivier Sobrie <[email protected]> +* Copyright (C) 2015 Valeo Corporation */ #include <linux/completion.h> @@ -21,6 +23,15 @@#include <linux/can/dev.h> #include <linux/can/error.h> +/* Kvaser USB CAN dongles are divided into two major families: +* - Leaf: Based on Renesas M32C, running firmware labeled as 'filo' +* - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios' +*/ +enum kvaser_usb_family { +KVASER_LEAF , +KVASER_USBCAN , +}; +#define MAX_TX_URBS 16#define MAX_RX_URBS 4#define START_TIMEOUT 1000/* msecs */ @@ -30,8 +41,9 @@#define RX_BUFFER_SIZE 3072#define CAN_USB_CLOCK 8000000#define MAX_NET_DEVICES 3 +#define MAX_USBCAN_NET_DEVICES 2 -/* Kvaser USB devices */ +/* Leaf USB devices */ #define KVASER_VENDOR_ID 0x0bfd#define USB_LEAF_DEVEL_PRODUCT_ID 10#define USB_LEAF_LITE_PRODUCT_ID 11
drivers/net/can/usb/kvaser_usb.c line 71
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +2
-0@@ -55,6 +67,16 @@#define USB_CAN_R_PRODUCT_ID 39#define USB_LEAF_LITE_V2_PRODUCT_ID 288#define USB_MINI_PCIE_HS_PRODUCT_ID 289 +#define LEAF_PRODUCT_ID (id) (id >= USB_LEAF_DEVEL_PRODUCT_ID && \ + id <= USB_MINI_PCIE_HS_PRODUCT_ID)
Can you please convert both *_PRODUCT_ID() macros into static inline bool functions.
Quoted 353 lines
drivers/net/can/usb/kvaser_usb.c +181
-27+ +/* USBCANII devices */ +#define USB_USBCAN_REVB_PRODUCT_ID 2 +#define USB_VCI2_PRODUCT_ID 3 +#define USB_USBCAN2_PRODUCT_ID 4 +#define USB_MEMORATOR_PRODUCT_ID 5 +#define USBCAN_PRODUCT_ID (id) (id >= USB_USBCAN_REVB_PRODUCT_ID && \ + id <= USB_MEMORATOR_PRODUCT_ID)/* USB devices features */ #define KVASER_HAS_SILENT_MODE BIT(0)@@ -73,7 +95,7 @@#define MSG_FLAG_TX_ACK BIT(6)#define MSG_FLAG_TX_REQUEST BIT(7) -/* Can states */ +/* Can states (M16C CxSTRH register) */ #define M16C_STATE_BUS_RESET BIT(0)#define M16C_STATE_BUS_ERROR BIT(4)#define M16C_STATE_BUS_PASSIVE BIT(5)@@ -98,7 +120,13 @@#define CMD_START_CHIP_REPLY 27#define CMD_STOP_CHIP 28#define CMD_STOP_CHIP_REPLY 29 -#define CMD_GET_CARD_INFO2 32 +#define CMD_READ_CLOCK 30 +#define CMD_READ_CLOCK_REPLY 31 + +#define CMD_LEAF_GET_CARD_INFO2 32 +#define CMD_USBCAN_RESET_CLOCK 32 +#define CMD_USBCAN_CLOCK_OVERFLOW_EVENT 33 +#define CMD_GET_CARD_INFO 34#define CMD_GET_CARD_INFO_REPLY 35#define CMD_GET_SOFTWARE_INFO 38@@ -108,8 +136,9 @@#define CMD_RESET_ERROR_COUNTER 49#define CMD_TX_ACKNOWLEDGE 50#define CMD_CAN_ERROR_EVENT 51 -#define CMD_USB_THROTTLE 77 -#define CMD_LOG_MESSAGE 106 + +#define CMD_LEAF_USB_THROTTLE 77 +#define CMD_LEAF_LOG_MESSAGE 106/* error factors */ #define M16C_EF_ACKE BIT(0)@@ -121,6 +150,14 @@#define M16C_EF_RCVE BIT(6)#define M16C_EF_TRE BIT(7) +/* Only Leaf-based devices can report M16C error factors, +* thus define our own error status flags for USBCANII +*/ +#define USBCAN_ERROR_STATE_NONE 0 +#define USBCAN_ERROR_STATE_TX_ERROR BIT(0) +#define USBCAN_ERROR_STATE_RX_ERROR BIT(1) +#define USBCAN_ERROR_STATE_BUSERROR BIT(2) +/* bittiming parameters */ #define KVASER_USB_TSEG1_MIN 1#define KVASER_USB_TSEG1_MAX 16@@ -137,7 +174,7 @@#define KVASER_CTRL_MODE_SELFRECEPTION 3#define KVASER_CTRL_MODE_OFF 4 -/* log message */ +/* Extended CAN identifier flag */ #define KVASER_EXTENDED_FRAME BIT(31)struct kvaser_msg_simple {@@ -148,30 +185,55 @@ struct kvaser_msg_simple {struct kvaser_msg_cardinfo {u8 tid;u8 nchannels; -__le32 serial_number; -__le32 padding; +union { +struct { +__le32 serial_number; +__le32 padding; + } __packed leaf0; +struct { +__le32 serial_number_low; +__le32 serial_number_high; + } __packed usbcan0; + } __packed;__le32 clock_resolution;__le32 mfgdate;u8 ean[8 ];u8 hw_revision; -u8 usb_hs_mode; -__le16 padding2; +union { +struct { +u8 usb_hs_mode; + } __packed leaf1; +struct { +u8 padding; + } __packed usbcan1; + } __packed; +__le16 padding; } __packed;struct kvaser_msg_cardinfo2 {u8 tid; -u8 channel; +u8 reserved;u8 pcb_id[24 ];__le32 oem_unlock_code; } __packed; -struct kvaser_msg_softinfo { +struct leaf_msg_softinfo {u8 tid; -u8 channel; +u8 padding0;__le32 sw_options;__le32 fw_version;__le16 max_outstanding_tx; -__le16 padding[9 ]; +__le16 padding1[9 ]; +} __packed; + +struct usbcan_msg_softinfo { +u8 tid; +u8 fw_name[5 ]; +__le16 max_outstanding_tx; +u8 padding[6 ]; +__le32 fw_version; +__le16 checksum; +__le16 sw_options; } __packed;struct kvaser_msg_busparams {@@ -188,36 +250,86 @@ struct kvaser_msg_tx_can {u8 channel;u8 tid;u8 msg[14 ]; -u8 padding; -u8 flags; +union { +struct { +u8 padding; +u8 flags; + } __packed leaf; +struct { +u8 flags; +u8 padding; + } __packed usbcan; + } __packed; } __packed; -struct kvaser_msg_rx_can { +struct kvaser_msg_rx_can_header {u8 channel;u8 flag; +} __packed; + +struct leaf_msg_rx_can { +u8 channel; +u8 flag; +__le16 time[3 ];u8 msg[14 ]; } __packed; -struct kvaser_msg_chip_state_event { +struct usbcan_msg_rx_can { +u8 channel; +u8 flag; + +u8 msg[14 ]; +__le16 time; +} __packed; + +struct leaf_msg_chip_state_event {u8 tid;u8 channel; +__le16 time[3 ];u8 tx_errors_count;u8 rx_errors_count; + +u8 status; +u8 padding[3 ]; +} __packed; + +struct usbcan_msg_chip_state_event { +u8 tid; +u8 channel; + +u8 tx_errors_count; +u8 rx_errors_count; +__le16 time; +u8 status;u8 padding[3 ]; } __packed; -struct kvaser_msg_tx_acknowledge { +struct kvaser_msg_tx_acknowledge_header { +u8 channel; +u8 tid; +}; + +struct leaf_msg_tx_acknowledge {u8 channel;u8 tid; +__le16 time[3 ];u8 flags;u8 time_offset; } __packed; -struct kvaser_msg_error_event { +struct usbcan_msg_tx_acknowledge { +u8 channel; +u8 tid; + +__le16 time; +__le16 padding; +} __packed; + +struct leaf_msg_error_event {u8 tid;u8 flags;__le16 time[3 ];@@ -229,6 +341,18 @@ struct kvaser_msg_error_event {u8 error_factor; } __packed; +struct usbcan_msg_error_event { +u8 tid; +u8 padding; +u8 tx_errors_count_ch0; +u8 rx_errors_count_ch0; +u8 tx_errors_count_ch1; +u8 rx_errors_count_ch1; +u8 status_ch0; +u8 status_ch1; +__le16 time; +} __packed; +struct kvaser_msg_ctrl_mode {u8 tid;u8 channel;@@ -243,7 +367,7 @@ struct kvaser_msg_flush_queue {u8 padding[3 ]; } __packed; -struct kvaser_msg_log_message { +struct leaf_msg_log_message {u8 channel;u8 flags;__le16 time[3 ];@@ -260,19 +384,50 @@ struct kvaser_msg {struct kvaser_msg_simple simple;struct kvaser_msg_cardinfo cardinfo;struct kvaser_msg_cardinfo2 cardinfo2; -struct kvaser_msg_softinfo softinfo;struct kvaser_msg_busparams busparams; + +struct kvaser_msg_rx_can_header rx_can_header; +struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header; + +union { +struct leaf_msg_softinfo softinfo; +struct leaf_msg_rx_can rx_can; +struct leaf_msg_chip_state_event chip_state_event; +struct leaf_msg_tx_acknowledge tx_acknowledge; +struct leaf_msg_error_event error_event; +struct leaf_msg_log_message log_message; + } __packed leaf; + +union { +struct usbcan_msg_softinfo softinfo; +struct usbcan_msg_rx_can rx_can; +struct usbcan_msg_chip_state_event chip_state_event; +struct usbcan_msg_tx_acknowledge tx_acknowledge; +struct usbcan_msg_error_event error_event; + } __packed usbcan; +struct kvaser_msg_tx_can tx_can; -struct kvaser_msg_rx_can rx_can; -struct kvaser_msg_chip_state_event chip_state_event; -struct kvaser_msg_tx_acknowledge tx_acknowledge; -struct kvaser_msg_error_event error_event;struct kvaser_msg_ctrl_mode ctrl_mode;struct kvaser_msg_flush_queue flush_queue; -struct kvaser_msg_log_message log_message; } u; } __packed; +/* Leaf/USBCAN-agnostic summary of an error event. +* No M16C error factors for USBCAN-based devices. +*/ +struct kvaser_error_summary { +u8 channel, status, txerr, rxerr; +union { +struct { +u8 error_factor; + } leaf; +struct { +u8 other_ch_status; +u8 error_state; + } usbcan; + }; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;@@ -288,6 +443,7 @@ struct kvaser_usb {u32 fw_version;unsigned int nchannels; +enum kvaser_usb_family family;bool rxinitdone;void *rxbuf[MAX_RX_URBS ];@@ -311,6 +467,7 @@ struct kvaser_usb_net_priv { };static const struct usb_device_id kvaser_usb_table[] = { +/* Leaf family IDs */ {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_DEVEL_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_LITE_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_PRO_PRODUCT_ID ),@@ -360,6 +517,17 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = KVASER_HAS_TXRX_ERRORS }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, + +/* USBCANII family IDs */ + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { } };MODULE_DEVICE_TABLE (usb, kvaser_usb_table);@@ -463,7 +631,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)if (err)return err; - dev->fw_version =le32_to_cpu (msg.u.softinfo.fw_version); +switch (dev->family) {
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_get_software_info(struct kvaser_usb *dev) · line 644
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+case KVASER_LEAF : + dev->fw_version =le32_to_cpu (msg.u.leaf.softinfo.fw_version); +break ; +case KVASER_USBCAN : + dev->fw_version =le32_to_cpu (msg.u.usbcan.softinfo.fw_version); +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); +return -EINVAL ;
The default case should not happen. I think you can remove it.
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_get_card_info(struct kvaser_usb *dev) · line 668
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+ }return 0 ; }@@ -484,6 +663,9 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev) dev->nchannels = msg.u.cardinfo.nchannels;if (dev->nchannels >MAX_NET_DEVICES )return -EINVAL ; +if (dev->family ==KVASER_USBCAN && + dev->nchannels >MAX_USBCAN_NET_DEVICES ) +return -EINVAL ;
Nitpick, as the new "if" also does a test on nchannels, why no extend the existing "if" with an "||"?
Quoted 17 lines
drivers/net/can/usb/kvaser_usb.c +4
-2return 0 ; }@@ -496,8 +678,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,struct kvaser_usb_net_priv *priv;struct sk_buff *skb;struct can_frame *cf; -u8 channel = msg->u.tx_acknowledge.channel; -u8 tid = msg->u.tx_acknowledge.tid; +u8 channel, tid; + + channel = msg->u.tx_acknowledge_header.channel; + tid = msg->u.tx_acknowledge_header.tid;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 803
Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c +2
-2@@ -615,37 +799,80 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index =MAX_TX_URBS ; } -static void kvaser_usb_rx_error (const struct kvaser_usb *dev, -const struct kvaser_msg *msg) +static void kvaser_report_error_event (const struct kvaser_usb *dev, +struct kvaser_error_summary *es);
Please rearange your code that forward declarations are not needed (if possible - I haven't checked, though).
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 811
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c +8
-0+ +/* Report error to userspace iff the controller's errors counter has +* increased, or we're the only channel seeing the bus error state. +* +* As reported by USBCAN sheets, "the CAN controller has difficulties +* to tell whether an error frame arrived on channel 1 or on channel 2." +* Thus, error counters are compared with their earlier values to +* determine which channel was responsible for the error event.
Your code doesn't match this comment. You compare the error counters against the old values to tell if it's a rx or tx error, the channel information from the struct kvaser_error_summary is used directly.
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 814
Quoted 3 lines
drivers/net/can/usb/kvaser_usb.c +3
-0+*/ +static void usbcan_report_error_if_applicable (const struct kvaser_usb *dev, +struct kvaser_error_summary *es)
Nitpick: can you please add a "kvaser_" prefix to the all usbcan_* and leaf_* functions.
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 817
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c +1
-5{ -struct can_frame *cf; -struct sk_buff *skb; -struct net_device_stats *stats;struct kvaser_usb_net_priv *priv; -unsigned int new_state; -u8 channel, status, txerr, rxerr, error_factor; +int old_tx_err_count, old_rx_err_count, channel, report_error;
bool report_error;
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 828
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c +11
-0+ + channel = es->channel; +if (channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , channel); +return ; + } + + priv = dev->nets[channel]; + old_tx_err_count = priv->bec.txerr; + old_rx_err_count = priv->bec.rxerr;
Why do you make a copy of priv->bec, AFAICS you can use priv->bec.{r,t}xerr directly?
Quoted 15 lines
drivers/net/can/usb/kvaser_usb.c +15
-0+ + report_error =0 ; +if (es->txerr > old_tx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_TX_ERROR ; + report_error =1 ; + } +if (es->rxerr > old_rx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_RX_ERROR ; + report_error =1 ; + } +if ((es->status &M16C_STATE_BUS_ERROR ) && + !(es->usbcan.other_ch_status &M16C_STATE_BUS_ERROR )) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_BUSERROR ; + report_error =1 ; + }
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 853
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+ +if (report_error) +kvaser_report_error_event (dev, es); +} + +/* Extract error summary from a Leaf-based device error message */ +static void leaf_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , };
IIRC "es = { };" should be sufficient.
Quoted 44 lines
drivers/net/can/usb/kvaser_usb.c +16
-16switch (msg->id) {case CMD_CAN_ERROR_EVENT : - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; + es.channel = msg->u.leaf.error_event.channel; + es.status = msg->u.leaf.error_event.status; + es.txerr = msg->u.leaf.error_event.tx_errors_count; + es.rxerr = msg->u.leaf.error_event.rx_errors_count; + es.leaf.error_factor = msg->u.leaf.error_event.error_factor;break ; -case CMD_LOG_MESSAGE : - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0 ]; - txerr = msg->u.log_message.data[2 ]; - rxerr = msg->u.log_message.data[3 ]; - error_factor = msg->u.log_message.data[1 ]; +case CMD_LEAF_LOG_MESSAGE : + es.channel = msg->u.leaf.log_message.channel; + es.status = msg->u.leaf.log_message.data[0 ]; + es.txerr = msg->u.leaf.log_message.data[2 ]; + es.rxerr = msg->u.leaf.log_message.data[3 ]; + es.leaf.error_factor = msg->u.leaf.log_message.data[1 ];break ;case CMD_CHIP_STATE_EVENT : - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor =0 ; + es.channel = msg->u.leaf.chip_state_event.channel; + es.status = msg->u.leaf.chip_state_event.status; + es.txerr = msg->u.leaf.chip_state_event.tx_errors_count; + es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count; + es.leaf.error_factor =0 ;break ;default : dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",@@ -653,16 +880,92 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,return ; }
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 890
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +8
-1-if (channel >= dev->nchannels) { +kvaser_report_error_event (dev, &es); +} + +/* Extract error summary from a USBCANII-based device error message */ +static void usbcan_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , };
same here.
Quoted 15 lines
drivers/net/can/usb/kvaser_usb.c +15
-0+ +switch (msg->id) { +/* Sometimes errors are sent as unsolicited chip state events */ +case CMD_CHIP_STATE_EVENT : + es.channel = msg->u.usbcan.chip_state_event.channel; + es.status = msg->u.usbcan.chip_state_event.status; + es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count; + es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count; +usbcan_report_error_if_applicable (dev, &es); +break ; + +case CMD_CAN_ERROR_EVENT : + es.channel =0 ; + es.status = msg->u.usbcan.error_event.status_ch0; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0;
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 915
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+ es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch1; +usbcan_report_error_if_applicable (dev, &es); + +/* For error events, the USBCAN firmware does not support +* more than 2 channels: ch0, and ch1. +*/ +if (dev->nchannels >1 ) { + es.channel =1 ;
Why is channel == 1 if the device has more than 1 channel?
Quoted 18 lines
drivers/net/can/usb/kvaser_usb.c +18
-0+ es.status = msg->u.usbcan.error_event.status_ch1; + es.txerr = + msg->u.usbcan.error_event.tx_errors_count_ch1; + es.rxerr = + msg->u.usbcan.error_event.rx_errors_count_ch1; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch0; +usbcan_report_error_if_applicable (dev, &es); + } +break ; + +default : +dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , + msg->id); + } +} + +static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 943
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+ const struct kvaser_msg *msg) +{ +switch (dev->family) { +case KVASER_LEAF : +leaf_extract_error_from_msg (dev, msg); +break ; +case KVASER_USBCAN : +usbcan_extract_error_from_msg (dev, msg); +break ; +default :
should not happen.
Quoted 139 lines
drivers/net/can/usb/kvaser_usb.c +57
-35dev_err (dev->udev->dev.parent, -"Invalid channel number (%d)\n" , channel); +"Invalid device family (%d)\n" , dev->family);return ; } +} - priv = dev->nets[channel]; +static void kvaser_report_error_event (const struct kvaser_usb *dev, +struct kvaser_error_summary *es) +{ +struct can_frame *cf; +struct sk_buff *skb; +struct net_device_stats *stats; +struct kvaser_usb_net_priv *priv; +unsigned int new_state; + +if (es->channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , es->channel); +return ; + } + + priv = dev->nets[es->channel]; stats = &priv->netdev->stats; -if (status &M16C_STATE_BUS_RESET ) { +if (es->status &M16C_STATE_BUS_RESET ) {kvaser_usb_unlink_tx_urbs (priv);return ; }@@ -675,9 +978,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, new_state = priv->can.state; -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (status &M16C_STATE_BUS_OFF ) { +if (es->status &M16C_STATE_BUS_OFF ) { cf->can_id |=CAN_ERR_BUSOFF ; priv->can.can_stats.bus_off++;@@ -687,12 +990,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,netif_carrier_off (priv->netdev); new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { + }else if (es->status &M16C_STATE_BUS_PASSIVE ) {if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es->txerr || es->rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else @@ -703,13 +1006,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } new_state =CAN_STATE_ERROR_PASSIVE ; - } - -if (status ==M16C_STATE_BUS_ERROR ) { + }else if (es->status &M16C_STATE_BUS_ERROR ) {if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { + ((es->txerr >=96 ) || (es->rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ;@@ -723,7 +1024,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } } -if (!status) { +if (!es->status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ;@@ -739,34 +1040,52 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv->can.can_stats.restarts++; } -if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - - cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; - -if (error_factor &M16C_EF_ACKE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); -if (error_factor &M16C_EF_CRCE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | -CAN_ERR_PROT_LOC_CRC_DEL ); -if (error_factor &M16C_EF_FORME ) - cf->data[2 ] |=CAN_ERR_PROT_FORM ; -if (error_factor &M16C_EF_STFE ) - cf->data[2 ] |=CAN_ERR_PROT_STUFF ; -if (error_factor &M16C_EF_BITE0 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; -if (error_factor &M16C_EF_BITE1 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; -if (error_factor &M16C_EF_TRE ) - cf->data[2 ] |=CAN_ERR_PROT_TX ; +switch (dev->family) { +case KVASER_LEAF : +if (es->leaf.error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; + +if (es->leaf.error_factor &M16C_EF_ACKE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); +if (es->leaf.error_factor &M16C_EF_CRCE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | +CAN_ERR_PROT_LOC_CRC_DEL ); +if (es->leaf.error_factor &M16C_EF_FORME ) + cf->data[2 ] |=CAN_ERR_PROT_FORM ; +if (es->leaf.error_factor &M16C_EF_STFE ) + cf->data[2 ] |=CAN_ERR_PROT_STUFF ; +if (es->leaf.error_factor &M16C_EF_BITE0 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; +if (es->leaf.error_factor &M16C_EF_BITE1 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; +if (es->leaf.error_factor &M16C_EF_TRE ) + cf->data[2 ] |=CAN_ERR_PROT_TX ; + } +break ; +case KVASER_USBCAN : +if (es->usbcan.error_state &USBCAN_ERROR_STATE_TX_ERROR ) + stats->tx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_RX_ERROR )
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 1081
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+ stats->rx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_BUSERROR ) { + priv->can.can_stats.bus_error++; + cf->can_id |=CAN_ERR_BUSERROR ; + } +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto err;
should not happen.
Quoted 46 lines
drivers/net/can/usb/kvaser_usb.c +12
-7} - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; + cf->data[6 ] = es->txerr; + cf->data[7 ] = es->rxerr; - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; priv->can.state = new_state;@@ -774,6 +1093,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + +return ; + +err: +dev_kfree_skb (skb); } static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,@@ -783,16 +1107,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,struct sk_buff *skb;struct net_device_stats *stats = &priv->netdev->stats; -if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | +if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |MSG_FLAG_NERR )) {netdev_err (priv->netdev,"Unknow error (flags: 0x%02x)\n" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); stats->rx_errors++;return ; } -if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { +if (msg->u.rx_can_header.flag &MSG_FLAG_OVERRUN ) { skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;
Quoted 2 lines
return; }
Can you prepare a (seperate) patch that does the stats, even in case of OOM here. Same for kvaser_report_error_event()
Quoted 11 lines
cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; stats->rx_errors++; netif_rx(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc;
Another patch would be not to touch cf after netif_rx(), please move the stats handling before calling netif_rx(). Same applies to the kvaser_usb_rx_can_msg() function.
Quoted 192 lines
}drivers/net/can/usb/kvaser_usb.c +69
-26@@ -819,7 +1143,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,struct can_frame *cf;struct sk_buff *skb;struct net_device_stats *stats; -u8 channel = msg->u.rx_can.channel; +u8 channel = msg->u.rx_can_header.channel; +const u8 *rx_msg;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,@@ -830,19 +1155,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; -if ((msg->u.rx_can.flag &MSG_FLAG_ERROR_FRAME ) && - (msg->id ==CMD_LOG_MESSAGE )) { +if ((msg->u.rx_can_header.flag &MSG_FLAG_ERROR_FRAME ) && + (dev->family ==KVASER_LEAF && msg->id ==CMD_LEAF_LOG_MESSAGE )) {kvaser_usb_rx_error (dev, msg);return ; - }else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | -MSG_FLAG_NERR | -MSG_FLAG_OVERRUN )) { + }else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME | +MSG_FLAG_NERR | +MSG_FLAG_OVERRUN )) {kvaser_usb_rx_can_err (priv, msg);return ; - }else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME ) { + }else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME ) {netdev_warn (priv->netdev,"Unhandled frame (flags: 0x%02x)" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); +return ; + } + +switch (dev->family) { +case KVASER_LEAF : + rx_msg = msg->u.leaf.rx_can.msg; +break ; +case KVASER_USBCAN : + rx_msg = msg->u.usbcan.rx_can.msg; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family);return ; }@@ -852,38 +1190,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,return ; } -if (msg->id ==CMD_LOG_MESSAGE ) { - cf->can_id =le32_to_cpu (msg->u.log_message.id); +if (dev->family ==KVASER_LEAF && msg->id ==CMD_LEAF_LOG_MESSAGE ) { + cf->can_id =le32_to_cpu (msg->u.leaf.log_message.id);if (cf->can_id &KVASER_EXTENDED_FRAME ) cf->can_id &=CAN_EFF_MASK |CAN_EFF_FLAG ;else cf->can_id &=CAN_SFF_MASK ; - cf->can_dlc =get_can_dlc (msg->u.log_message.dlc); + cf->can_dlc =get_can_dlc (msg->u.leaf.log_message.dlc); -if (msg->u.log_message.flags &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.leaf.log_message.flags &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.log_message.data, +memcpy (cf->data, &msg->u.leaf.log_message.data, cf->can_dlc); }else { - cf->can_id = ((msg->u.rx_can.msg[0 ] &0x1f ) <<6 ) | - (msg->u.rx_can.msg[1 ] &0x3f ); + cf->can_id = ((rx_msg[0 ] &0x1f ) <<6 ) | (rx_msg[1 ] &0x3f );if (msg->id ==CMD_RX_EXT_MESSAGE ) { cf->can_id <<=18 ; - cf->can_id |= ((msg->u.rx_can.msg[2 ] &0x0f ) <<14 ) | - ((msg->u.rx_can.msg[3 ] &0xff ) <<6 ) | - (msg->u.rx_can.msg[4 ] &0x3f ); + cf->can_id |= ((rx_msg[2 ] &0x0f ) <<14 ) | + ((rx_msg[3 ] &0xff ) <<6 ) | + (rx_msg[4 ] &0x3f ); cf->can_id |=CAN_EFF_FLAG ; } - cf->can_dlc =get_can_dlc (msg->u.rx_can.msg[5 ]); + cf->can_dlc =get_can_dlc (rx_msg[5 ]); -if (msg->u.rx_can.flag &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.rx_can_header.flag &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.rx_can.msg[6 ], +memcpy (cf->data, &rx_msg[6 ], cf->can_dlc); }@@ -947,7 +1284,12 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,case CMD_RX_STD_MESSAGE :case CMD_RX_EXT_MESSAGE : -case CMD_LOG_MESSAGE : +kvaser_usb_rx_can_msg (dev, msg); +break ; + +case CMD_LEAF_LOG_MESSAGE : +if (dev->family !=KVASER_LEAF ) + goto warn;kvaser_usb_rx_can_msg (dev, msg);break ;@@ -960,8 +1302,14 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,kvaser_usb_tx_acknowledge (dev, msg);break ; +/* Ignored messages */ +case CMD_USBCAN_CLOCK_OVERFLOW_EVENT : +if (dev->family !=KVASER_USBCAN ) + goto warn; +break ; +default : -dev_warn (dev->udev->dev.parent, +warn:dev_warn (dev->udev->dev.parent,"Unhandled message (%d)\n" , msg->id);break ; }@@ -1181,7 +1529,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) dev->rxbuf[i], dev->rxbuf_dma[i]); -for (i =0 ; i <MAX_NET_DEVICES ; i++) { +for (i =0 ; i < dev->nchannels; i++) {struct kvaser_usb_net_priv *priv = dev->nets[i];if (priv)@@ -1289,6 +1637,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,struct kvaser_msg *msg;int i, err;int ret =NETDEV_TX_OK ; +uint8_t *msg_tx_can_flags;if (can_dropped_invalid_skb (netdev, skb))return NETDEV_TX_OK ;@@ -1310,9 +1659,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, msg = buf; msg->len =MSG_HEADER_LEN +sizeof (struct kvaser_msg_tx_can ); - msg->u.tx_can.flags =0 ; msg->u.tx_can.channel = priv->channel; +switch (dev->family) { +case KVASER_LEAF : + msg_tx_can_flags = &msg->u.tx_can.leaf.flags; +break ; +case KVASER_USBCAN : + msg_tx_can_flags = &msg->u.tx_can.usbcan.flags; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto releasebuf; + } + + *msg_tx_can_flags =0 ; +if (cf->can_id &CAN_EFF_FLAG ) { msg->id =CMD_TX_EXT_MESSAGE ; msg->u.tx_can.msg[0 ] = (cf->can_id >>24 ) &0x1f ;@@ -1330,7 +1693,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,memcpy (&msg->u.tx_can.msg[6 ], cf->data, cf->can_dlc);if (cf->can_id &CAN_RTR_FLAG ) - msg->u.tx_can.flags |=MSG_FLAG_REMOTE_FRAME ; + *msg_tx_can_flags |=MSG_FLAG_REMOTE_FRAME ;for (i =0 ; i <ARRAY_SIZE (priv->tx_contexts); i++) {if (priv->tx_contexts[i].echo_index ==MAX_TX_URBS ) {@@ -1599,6 +1962,17 @@ static int kvaser_usb_probe(struct usb_interface *intf,if (!dev)return -ENOMEM ; +if (LEAF_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_LEAF ; + }else if (USBCAN_PRODUCT_ID (id->idProduct)) { + dev->family =KVASER_USBCAN ;
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1978
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +7
-0+ }else { +dev_err (&intf->dev, +"Product ID (%d) does not belong to any known Kvaser USB family" , + id->idProduct); +return -ENODEV ; + } + err =kvaser_usb_get_endpoints (intf, &dev->bulk_in, &dev->bulk_out);if (err) {dev_err (&intf->dev,"Cannot get usb endpoint(s)" );
regards,
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
Hi Marc,
Quoted 2 lines · Marc Kleine-Budde
Quoted 1 line · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
[...]
Quoted 18 lines
Quoted 18 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+/* Kvaser USB CAN dongles are divided into two major families: +* - Leaf: Based on Renesas M32C, running firmware labeled as 'filo' +* - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios' +*/ +enum kvaser_usb_family { +KVASER_LEAF , +KVASER_USBCAN , +}; +#define MAX_TX_URBS 16#define MAX_RX_URBS 4#define START_TIMEOUT 1000/* msecs */ @@ -30,8 +41,9 @@#define RX_BUFFER_SIZE 3072#define CAN_USB_CLOCK 8000000#define MAX_NET_DEVICES 3 +#define MAX_USBCAN_NET_DEVICES 2
Quoted 15 lines
drivers/net/can/usb/kvaser_usb.c line 71
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c +3
-1-/* Kvaser USB devices */ +/* Leaf USB devices */ #define KVASER_VENDOR_ID 0x0bfd#define USB_LEAF_DEVEL_PRODUCT_ID 10#define USB_LEAF_LITE_PRODUCT_ID 11@@ -55,6 +67,16 @@#define USB_CAN_R_PRODUCT_ID 39#define USB_LEAF_LITE_V2_PRODUCT_ID 288#define USB_MINI_PCIE_HS_PRODUCT_ID 289 +#define LEAF_PRODUCT_ID (id) (id >= USB_LEAF_DEVEL_PRODUCT_ID && \ + id <= USB_MINI_PCIE_HS_PRODUCT_ID)Can you please convert both
*_PRODUCT_ID()macros into static inline bool functions.
Will do.
[...]
Quoted 5 lines
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +0
-0MODULE_DEVICE_TABLE (usb, kvaser_usb_table);@@ -463,7 +631,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)if (err)return err;
Quoted 15 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_get_software_info(struct kvaser_usb *dev) · line 644
Quoted 12 lines
drivers/net/can/usb/kvaser_usb.c +11
-1- dev->fw_version =le32_to_cpu (msg.u.softinfo.fw_version); +switch (dev->family) { +case KVASER_LEAF : + dev->fw_version =le32_to_cpu (msg.u.leaf.softinfo.fw_version); +break ; +case KVASER_USBCAN : + dev->fw_version =le32_to_cpu (msg.u.usbcan.softinfo.fw_version); +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); +return -EINVAL ;The default case should not happen. I think you can remove it.
It's true, it _should_ never happen. But I only add such checks if the follow-up code critically depends on a certain dev->family behavior. So it's kind of a defensive check against any possible bug in driver or memory.
What do you think?
Quoted 15 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_get_card_info(struct kvaser_usb *dev) · line 668
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+ }return 0 ; }@@ -484,6 +663,9 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev) dev->nchannels = msg.u.cardinfo.nchannels;if (dev->nchannels >MAX_NET_DEVICES )return -EINVAL ; +if (dev->family ==KVASER_USBCAN && + dev->nchannels >MAX_USBCAN_NET_DEVICES ) +return -EINVAL ;Nitpick, as the new "if" also does a test on nchannels, why no extend the existing "if" with an "||"?
Will do.
Quoted 20 lines
Quoted 20 lines
drivers/net/can/usb/kvaser_usb.c +4
-2return 0 ; }@@ -496,8 +678,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,struct kvaser_usb_net_priv *priv;struct sk_buff *skb;struct can_frame *cf; -u8 channel = msg->u.tx_acknowledge.channel; -u8 tid = msg->u.tx_acknowledge.tid; +u8 channel, tid; + + channel = msg->u.tx_acknowledge_header.channel; + tid = msg->u.tx_acknowledge_header.tid;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,@@ -615,37 +799,80 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index =MAX_TX_URBS ; }
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 803
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +2
-2-static void kvaser_usb_rx_error (const struct kvaser_usb *dev, -const struct kvaser_msg *msg) +static void kvaser_report_error_event (const struct kvaser_usb *dev, +struct kvaser_error_summary *es);Please rearange your code that forward declarations are not needed (if possible - I haven't checked, though).
I originally did it that way, but it completely messed up with the patch if I do such rearrangement. A huge block of code gets removed at top of the patch, and it got added again at the end, making the actual important lines changed _within_ such big block non-apparent.
Maybe I should do the re-arrangement in a follow-up patch?
Quoted 4 lines
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+ +/* Report error to userspace iff the controller's errors counter has +* increased, or we're the only channel seeing the bus error state. +*
Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 811
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+* As reported by USBCAN sheets, "the CAN controller has difficulties +* to tell whether an error frame arrived on channel 1 or on channel 2." +* Thus, error counters are compared with their earlier values to +* determine which channel was responsible for the error event. Your code doesn't match this comment. You compare the error counters against the old values to tell if it's a rx or tx error, the channel information from the struct
kvaser_error_summaryis used directly.
Hmmm, good catch, upon a second look, the code looks a bit deceiving. The comments, meanwhile, are taken verbatim from the Kvaser sheets:
http://www.kvaser.com/canlib-webhelp/page_hardware_specific_can_controllers.html
Archived at http://www.webcitation.org/6VQd87jIA
So, what happens is that the firmware does not tell us whether the received error event is for ch0 or ch1. But it gives us the (possibly new) error counters for both of them:
struct usbcan_msg_error_event {
[..]
u8 tx_errors_count_ch0;
u8 rx_errors_count_ch0;
u8 tx_errors_count_ch1;
u8 rx_errors_count_ch1;
[..]
} __packed;We loop over each channel, and report an error to userspace if extra errors were spotted for such channel.
kvaser_error_summary is not a firmware command or response. Since the wire format for an error event differs between Leaf and Usbcan, it's just our way to summarize an error whether it's from any of them, and this is where the conflict stems from:
- If it's a Leaf-device, `error_summary->channel' is the excat channel reported by the firmware
- If it's a Usbcan device, `error_summary->channel' is just a mark to check the error counters for such a channel and report error to userspace iff they've increased.
Thus the raison d'etre for `error_summary' struct is to share the error handling code between Leaf and UsbcanII devices since it's quite similar.
So to clear up this conflict, I suggest the following error_summary layout:
struct kvaser_error_summary {
union {
struct {
u8 channel;
} leaf;
struct {
u8 possible_channel;
} usbcan;
};
/* Rest of layout is left as-is */
}This way, it's clear that in case of Usbcan, channel is not final and we need further work to do. What do you think?
(BTW, any better name than "kvaser_error_summary"? It conflicts a little bit with the namespace used for the packed wire format structures "kvaser_*")
Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 814
Quoted 3 lines
drivers/net/can/usb/kvaser_usb.c +3
-0+*/ +static void usbcan_report_error_if_applicable (const struct kvaser_usb *dev, +struct kvaser_error_summary *es)Nitpick: can you please add a "
kvaser_" prefix to the all usbcan_* and leaf_* functions.
Will do.
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 817
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c +1
-5{ -struct can_frame *cf; -struct sk_buff *skb; -struct net_device_stats *stats;struct kvaser_usb_net_priv *priv; -unsigned int new_state; -u8 channel, status, txerr, rxerr, error_factor; +int old_tx_err_count, old_rx_err_count, channel, report_error;bool
report_error;
Will do.
Quoted 6 lines
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c +6
-0+ + channel = es->channel; +if (channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , channel); +return ;
Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 828
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +5
-0+ } + + priv = dev->nets[channel]; + old_tx_err_count = priv->bec.txerr; + old_rx_err_count = priv->bec.rxerr;Why do you make a copy of
priv->bec, AFAICS you can use priv->bec.{r,t}xerr directly?
Initially, just for clarity, as I was not used yet to socketCAN structures ;-) will remove it in the next submission.
Quoted 19 lines
Quoted 19 lines
drivers/net/can/usb/kvaser_usb.c +19
-0+ + report_error =0 ; +if (es->txerr > old_tx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_TX_ERROR ; + report_error =1 ; + } +if (es->rxerr > old_rx_err_count) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_RX_ERROR ; + report_error =1 ; + } +if ((es->status &M16C_STATE_BUS_ERROR ) && + !(es->usbcan.other_ch_status &M16C_STATE_BUS_ERROR )) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_BUSERROR ; + report_error =1 ; + } + +if (report_error) +kvaser_report_error_event (dev, es); +}
Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 853
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c +6
-0+ +/* Extract error summary from a Leaf-based device error message */ +static void leaf_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , };IIRC "es = { };" should be sufficient.
Correct, will do.
Quoted 45 lines
Quoted 45 lines
drivers/net/can/usb/kvaser_usb.c +16
-16switch (msg->id) {case CMD_CAN_ERROR_EVENT : - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; + es.channel = msg->u.leaf.error_event.channel; + es.status = msg->u.leaf.error_event.status; + es.txerr = msg->u.leaf.error_event.tx_errors_count; + es.rxerr = msg->u.leaf.error_event.rx_errors_count; + es.leaf.error_factor = msg->u.leaf.error_event.error_factor;break ; -case CMD_LOG_MESSAGE : - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0 ]; - txerr = msg->u.log_message.data[2 ]; - rxerr = msg->u.log_message.data[3 ]; - error_factor = msg->u.log_message.data[1 ]; +case CMD_LEAF_LOG_MESSAGE : + es.channel = msg->u.leaf.log_message.channel; + es.status = msg->u.leaf.log_message.data[0 ]; + es.txerr = msg->u.leaf.log_message.data[2 ]; + es.rxerr = msg->u.leaf.log_message.data[3 ]; + es.leaf.error_factor = msg->u.leaf.log_message.data[1 ];break ;case CMD_CHIP_STATE_EVENT : - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor =0 ; + es.channel = msg->u.leaf.chip_state_event.channel; + es.status = msg->u.leaf.chip_state_event.status; + es.txerr = msg->u.leaf.chip_state_event.tx_errors_count; + es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count; + es.leaf.error_factor =0 ;break ;default : dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",@@ -653,16 +880,92 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,return ; }
Quoted 12 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 890
Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c +8
-1-if (channel >= dev->nchannels) { +kvaser_report_error_event (dev, &es); +} + +/* Extract error summary from a USBCANII-based device error message */ +static void usbcan_extract_error_from_msg (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = {0 , };same here.
Ditto.
Quoted 19 lines
Quoted 19 lines
drivers/net/can/usb/kvaser_usb.c +19
-0+ +switch (msg->id) { +/* Sometimes errors are sent as unsolicited chip state events */ +case CMD_CHIP_STATE_EVENT : + es.channel = msg->u.usbcan.chip_state_event.channel; + es.status = msg->u.usbcan.chip_state_event.status; + es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count; + es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count; +usbcan_report_error_if_applicable (dev, &es); +break ; + +case CMD_CAN_ERROR_EVENT : + es.channel =0 ; + es.status = msg->u.usbcan.error_event.status_ch0; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch1; +usbcan_report_error_if_applicable (dev, &es);
Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 915
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c +6
-0+ +/* For error events, the USBCAN firmware does not support +* more than 2 channels: ch0, and ch1. +*/ +if (dev->nchannels >1 ) { + es.channel =1 ;Why is channel == 1 if the device has more than 1 channel?
This is related to the "kvaser_error_summary" discussion above where "channel" is only a suggestion for checking the error counters.
If the Usbcan device has only one channel, then there's no need to check if the "tx_errors_count_ch1", "rx_errors_count_ch1" has increased or not. Their values are undefined.
Quoted 21 lines
Quoted 21 lines
drivers/net/can/usb/kvaser_usb.c +21
-0+ es.status = msg->u.usbcan.error_event.status_ch1; + es.txerr = + msg->u.usbcan.error_event.tx_errors_count_ch1; + es.rxerr = + msg->u.usbcan.error_event.rx_errors_count_ch1; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch0; +usbcan_report_error_if_applicable (dev, &es); + } +break ; + +default : +dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , + msg->id); + } +} + +static void kvaser_usb_rx_error (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +switch (dev->family) {
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 943
Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c +7
-0+case KVASER_LEAF : +leaf_extract_error_from_msg (dev, msg); +break ; +case KVASER_USBCAN : +usbcan_extract_error_from_msg (dev, msg); +break ; +default :should not happen.
Yes. As in above, will wait your input in this regarding the checks being defensive.
[...]
Quoted 8 lines
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c +8
-0+case KVASER_USBCAN : +if (es->usbcan.error_state &USBCAN_ERROR_STATE_TX_ERROR ) + stats->tx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_RX_ERROR ) + stats->rx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_BUSERROR ) { + priv->can.can_stats.bus_error++; + cf->can_id |=CAN_ERR_BUSERROR ;
Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 1081
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c +6
-0+ } +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto err;should not happen.
Ditto.
Quoted 41 lines
Quoted 41 lines
drivers/net/can/usb/kvaser_usb.c +11
-6} - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; + cf->data[6 ] = es->txerr; + cf->data[7 ] = es->rxerr; - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; priv->can.state = new_state;@@ -774,6 +1093,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, stats->rx_packets++; stats->rx_bytes += cf->can_dlc; + +return ; + +err: +dev_kfree_skb (skb); } static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,@@ -783,16 +1107,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,struct sk_buff *skb;struct net_device_stats *stats = &priv->netdev->stats; -if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | +if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |MSG_FLAG_NERR )) {netdev_err (priv->netdev,"Unknow error (flags: 0x%02x)\n" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); stats->rx_errors++;return ; }
Quoted 9 lines
Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c +1
-1-if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { +if (msg->u.rx_can_header.flag &MSG_FLAG_OVERRUN ) { skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;return; }Can you prepare a (seperate) patch that does the stats, even in case of OOM here. Same for
kvaser_report_error_event()
Sure.
In kvaser_report_error_event() though, isn't it a little bit tricky? Specially in fragments as in below:
switch (dev->family) {
case KVASER_LEAF:
if (es->leaf.error_factor) {
priv->can.can_stats.bus_error++;
stats->rx_errors++;
cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
[...]
}
break;
case KVASER_USBCAN:
if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR)
stats->tx_errors++;
if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR)
stats->rx_errors++;
if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) {
priv->can.can_stats.bus_error++;
cf->can_id |= CAN_ERR_BUSERROR;
}
break;
}IMHO, there will be some duplication of the above fragment. Once to handle "stats->*", and once to handle packet-related "cf->*" stuff. Also in the Usbcan case, it will clutter the error_state checks in different places.
Quoted 8 lines
Quoted 8 lines
cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; stats->rx_errors++;
Quoted 7 lines
Quoted 4 lines
netif_rx(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc;Another patch would be not to touch cf after
netif_rx(), please move the stats handling before callingnetif_rx(). Same applies to thekvaser_usb_rx_can_msg()function.
Indeed, these can be totally bogus values after netif_rx(). I'll introduce this as a new patch in a new series.
Thanks for your review!
Regards,
Darwish
Marc Kleine-Budde
maintainerRe: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
On 01/08/2015 04:19 PM, Ahmed S. Darwish wrote:
[...]
Quoted 20 lines
Quoted 5 lines
Quoted 5 lines
MODULE_DEVICE_TABLE(usb, kvaser_usb_table);drivers/net/can/usb/kvaser_usb.c +0
-0@@ -463,7 +631,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)if (err)return err;Quoted 14 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_get_software_info(struct kvaser_usb *dev) · line 644
Quoted 12 lines
drivers/net/can/usb/kvaser_usb.c +11
-1- dev->fw_version =le32_to_cpu (msg.u.softinfo.fw_version); +switch (dev->family) { +case KVASER_LEAF : + dev->fw_version =le32_to_cpu (msg.u.leaf.softinfo.fw_version); +break ; +case KVASER_USBCAN : + dev->fw_version =le32_to_cpu (msg.u.usbcan.softinfo.fw_version); +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); +return -EINVAL ;The default case should not happen. I think you can remove it.
Quoted 6 lines
It's true, it _should_ never happen. But I only add such checks if the follow-up code critically depends on a certain
dev->familybehavior. So it's kind of a defensive check against any possible bug in driver or memory.What do you think?
The kernel is full of callback functions, if you have a bit flip there you're in trouble anyways. A bug in the driver (or other parts of the kernel) might overwrite the memory of dev->family, but if this happens, more things will break.
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
Quoted 29 lines · Marc Kleine-Budde
On 01/08/2015 04:19 PM, Ahmed S. Darwish wrote:
[...]
Quoted 25 lines
Quoted 5 lines
Quoted 5 lines
MODULE_DEVICE_TABLE(usb, kvaser_usb_table);drivers/net/can/usb/kvaser_usb.c +0
-0@@ -463,7 +631,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)if (err)return err;Quoted 14 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_get_software_info(struct kvaser_usb *dev) · line 644
Quoted 12 lines
drivers/net/can/usb/kvaser_usb.c +11
-1- dev->fw_version =le32_to_cpu (msg.u.softinfo.fw_version); +switch (dev->family) { +case KVASER_LEAF : + dev->fw_version =le32_to_cpu (msg.u.leaf.softinfo.fw_version); +break ; +case KVASER_USBCAN : + dev->fw_version =le32_to_cpu (msg.u.usbcan.softinfo.fw_version); +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); +return -EINVAL ;The default case should not happen. I think you can remove it.
It's true, it _should_ never happen. But I only add such checks if the follow-up code critically depends on a certain
dev->familybehavior. So it's kind of a defensive check against any possible bug in driver or memory.
Quoted 7 lines
Quoted 1 line
What do you think?
The kernel is full of callback functions, if you have a bit flip there you're in trouble anyways. A bug in the driver (or other parts of the kernel) might overwrite the memory of
dev->family, but if this happens, more things will break.
I see. Thanks for the explanation.
Most of them are now removed in latest submission, except two to avoid GCC warnings of variables that "may be used uninitialized".
Regards,
Darwish
Marc Kleine-Budde
maintainerRe: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
Quoted 38 lines · Ahmed S. Darwish
Quoted 29 lines · Marc Kleine-Budde
On 01/08/2015 04:19 PM, Ahmed S. Darwish wrote:
[...]
Quoted 25 lines
Quoted 5 lines
Quoted 5 lines
MODULE_DEVICE_TABLE(usb, kvaser_usb_table);drivers/net/can/usb/kvaser_usb.c +0
-0@@ -463,7 +631,18 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)if (err)return err;Quoted 14 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_get_software_info(struct kvaser_usb *dev) · line 644
Quoted 12 lines
drivers/net/can/usb/kvaser_usb.c +11
-1- dev->fw_version =le32_to_cpu (msg.u.softinfo.fw_version); +switch (dev->family) { +case KVASER_LEAF : + dev->fw_version =le32_to_cpu (msg.u.leaf.softinfo.fw_version); +break ; +case KVASER_USBCAN : + dev->fw_version =le32_to_cpu (msg.u.usbcan.softinfo.fw_version); +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); +return -EINVAL ;The default case should not happen. I think you can remove it.
It's true, it _should_ never happen. But I only add such checks if the follow-up code critically depends on a certain
dev->familybehavior. So it's kind of a defensive check against any possible bug in driver or memory.Quoted 7 lines
Quoted 1 line
What do you think?
The kernel is full of callback functions, if you have a bit flip there you're in trouble anyways. A bug in the driver (or other parts of the kernel) might overwrite the memory of
dev->family, but if this happens, more things will break.
Quoted 4 lines
I see. Thanks for the explanation.
Most of them are now removed in latest submission, except two to avoid GCC warnings of variables that "may be used uninitialized".
Thanks, I'll look at the code later and try to figure out what gcc's problem might be.
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
In reply to Marc Kleine-BuddeQuoted 2 lines · Marc Kleine-Budde
Quoted 1 line · Ahmed S. Darwish
[...]
Quoted 7 lines
Quoted 7 lines
cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; stats->rx_errors++;
Quoted 7 lines
Quoted 4 lines
netif_rx(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc;Another patch would be not to touch cf after
netif_rx(), please move the stats handling before callingnetif_rx(). Same applies to thekvaser_usb_rx_can_msg()function.
BTW, is it guaranteed from the SocketCAN stack that netif_rx() will never return NET_RX_DROPPED? Because if no guarantee exists, I guess below fragment cannot be completely correct?
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
netif_rx(skb);On the other hand, I don't see evan a single CAN driver checking netif_rx() return value, so maybe such a check is an overkill...
Thanks,
Darwish
Marc Kleine-Budde
maintainerRe: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
Quoted 9 lines · Ahmed S. Darwish
Quoted 9 lines
Quoted 9 lines
cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; stats->rx_errors++; netif_rx(skb);
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
stats->rx_packets++; stats->rx_bytes += cf->can_dlc;Another patch would be not to touch cf after
netif_rx(), please move the stats handling before callingnetif_rx(). Same applies to thekvaser_usb_rx_can_msg()function.BTW, is it guaranteed from the SocketCAN stack that
netif_rx()
netif_rx() is the generic networking stack already.
Quoted 2 lines
will never return
NET_RX_DROPPED? Because if no guarantee exists, I guess below fragment cannot be completely correct?
No, it's not guaranteed...
Quoted 7 lines
stats->rx_packets++; stats->rx_bytes += cf->can_dlc; netif_rx(skb);On the other hand, I don't see evan a single CAN driver checking
netif_rx()return value, so maybe such a check is an overkill...
A quick look shows that almost no ethernet or wireless drivers take care about the return value. In case of a RX_DROPPED some increase a drop counter, though.
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
Quoted 5 lines · Marc Kleine-Budde
Quoted 3 lines · Ahmed S. Darwish
Quoted 3 lines
Quoted 3 lines
stats->rx_over_errors++; stats->rx_errors++;
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
netif_rx(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc;A quick look shows that almost no ethernet or wireless drivers take care about the return value. In case of a
RX_DROPPEDsome increase a drop counter, though.
As there IS a return value it makes sense to check it and to increase either the packet OR the drop counter accordingly.
This is definitely better than increasing just the packet counter in every case. Maybe something for the 3.21 merge window ...
Regards,
Oliver
ps. removed the heavy cross-posting on LKML and netdev and others. Posting on linux-can is the right place for this kind of CAN driver discussions.
Marc Kleine-Budde
maintainerQuoted 17 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
Flooding the Kvaser CAN to USB dongle with multiple reads and writes in high frequency caused seemingly-random panics in the kernel.
On further inspection, it seems the driver erroneously freed the to-be-transmitted packet upon getting tight on URBs and returning
NETDEV_TX_BUSY, leading to invalid memory writes and double frees at a later point in time.Note:
Finding no more URBs/transmit-contexts and returning
NETDEV_TX_BUSYis a driver bug in and out of itself: it means that our start/stop queue flow control is broken.
Quoted 5 lines
This patch only fixes the (buggy) error handling code; the root cause shall be fixed in a later commit.
Signed-off-by Ahmed S. Darwish <[email protected]>Acked-by Olivier Sobrie <[email protected]>
Applied 1-3 to can/master + added stable on Cc.
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
v4 cover can: Introduce support for Kvaser USBCAN-II devices
In reply to Ahmed S. DarwishHi,
Now since earlier v3 submission patches #1-3 got merged, this is a new patch series expanding on patch v3 #4: support for the USBCAN-II family.
A new series is introduced due to the extra additions suggested by code review, which required being added in their own self-contained patches.
Thanks,
Darwish
Re: [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() devices
From: Ahmed S. Darwish <[email protected]>
We should not touch the packet after a netif_rx: it might get freed behind our back.
--- drivers/net/can/usb/kvaser_usb.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
drivers/net/can/usb/kvaser_usb.c +4 -7
@@ -520,10 +520,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev, skb =alloc_can_err_skb (priv->netdev, &cf);if (skb) { cf->can_id |=CAN_ERR_RESTARTED ; -netif_rx (skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; +netif_rx (skb); }else {netdev_err (priv->netdev,"No memory left for err_skb\n" );
@@ -770,10 +770,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv->can.state = new_state; -netif_rx (skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; +netif_rx (skb); } static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
@@ -805,10 +804,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, stats->rx_over_errors++; stats->rx_errors++; -netif_rx (skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; +netif_rx (skb); } }
@@ -887,10 +885,9 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, cf->can_dlc); } -netif_rx (skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; +netif_rx (skb); } static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev,
Signature · 1 line
1.9.1
PATCH v4 1/4 can: kvaser_usb: Don't dereference skb after a netif_rx()
From: Ahmed S. Darwish <[email protected]>
We should not touch the packet after a netif_rx: it might get freed behind our back.
--- drivers/net/can/usb/kvaser_usb.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
(Resend, fix the garbled subject line. Sorry)
drivers/net/can/usb/kvaser_usb.c +4 -7
@@ -520,10 +520,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev, skb =alloc_can_err_skb (priv->netdev, &cf);if (skb) { cf->can_id |=CAN_ERR_RESTARTED ; -netif_rx (skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; +netif_rx (skb); }else {netdev_err (priv->netdev,"No memory left for err_skb\n" );
@@ -770,10 +770,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv->can.state = new_state; -netif_rx (skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; +netif_rx (skb); } static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
@@ -805,10 +804,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, stats->rx_over_errors++; stats->rx_errors++; -netif_rx (skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; +netif_rx (skb); } }
@@ -887,10 +885,9 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, cf->can_dlc); } -netif_rx (skb); - stats->rx_packets++; stats->rx_bytes += cf->can_dlc; +netif_rx (skb); } static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev,
Signature · 1 line
1.9.1
Re: [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx()
Quoted 7 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
We should not touch the packet after a
netif_rx: it might get freed behind our back.Suggested-by Marc Kleine-Budde <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>
Applied to can/master.
tnx,
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
PATCH v4 2/4 can: kvaser_usb: Update error counters before exiting on OOM
In reply to Ahmed S. DarwishFrom: Ahmed S. Darwish <[email protected]>
Let the error counters be more accurate in case of Out of Memory conditions.
--- drivers/net/can/usb/kvaser_usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/can/usb/kvaser_usb.c +3 -3
@@ -792,6 +792,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, }if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { + stats->rx_over_errors++; + stats->rx_errors++; + skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;
@@ -801,9 +804,6 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, cf->can_id |=CAN_ERR_CRTL ; cf->data[1 ] =CAN_ERR_CRTL_RX_OVERFLOW ; - stats->rx_over_errors++; - stats->rx_errors++; - stats->rx_packets++; stats->rx_bytes += cf->can_dlc;netif_rx (skb);
Signature · 1 line
1.9.1
PATCH v4 3/4 can: kvaser_usb: Add support for the Usbcan-II family
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'UsbcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
This patch adds support for the UsbcanII family of devices to the current Kvaser Leaf-only driver.
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
List of new devices supported by this driver update:
- Kvaser USBcan II HS/HS
- Kvaser USBcan II HS/LS
- Kvaser USBcan Rugged ("USBcan Rev B")
- Kvaser Memorator HS/HS
- Kvaser Memorator HS/LS
- Scania VCI2 (if you have the Kvaser logo on top)
--- drivers/net/can/usb/Kconfig | 8 +- drivers/net/can/usb/kvaser_usb.c | 612 ++++++++++++++++++++++++++++++--------- 2 files changed, 487 insertions(+), 133 deletions(-)
** V4 Changelog:
- Use type-safe C methods instead of cpp macros
- Further clarify the code and comments on error events channel arbitration
- Remove defensive checks against non-existing families
- Re-order methods to remove forward declarations
- Smaller stuff spotted by earlier review (function prefexes, etc.)
** V3 Changelog:
- Fix padding for the usbcan_msg_tx_acknowledge command
- Remove kvaser_usb->max_channels and the MAX_NET_DEVICES macro
- Rename commands to CMD_LEAF_xxx and CMD_USBCAN_xxx
- Apply checkpatch.pl suggestions ('net/' comments, multi-line strings, etc.)
** V2 Changelog:
- Update Kconfig entries
- Use actual number of CAN channels (instead of max) where appropriate
- Rebase over a new set of UsbcanII-independent driver fixes
drivers/net/can/usb/Kconfig +7 -1
@@ -25,7 +25,7 @@ config CAN_KVASER_USB tristate "Kvaser CAN/USB interface" ---help--- This driver adds support for Kvaser CAN/USB devices like Kvaser - Leaf Light. + Leaf Light and Kvaser USBcan II. The driver provides support for the following devices: - Kvaser Leaf Light
@@ -46,6 +46,12 @@ config CAN_KVASER_USB - Kvaser USBcan R - Kvaser Leaf Light v2 - Kvaser Mini PCI Express HS + - Kvaser USBcan II HS/HS + - Kvaser USBcan II HS/LS + - Kvaser USBcan Rugged ("USBcan Rev B") + - Kvaser Memorator HS/HS + - Kvaser Memorator HS/LS + - Scania VCI2 (if you have the Kvaser logo on top) If unsure, say N.
drivers/net/can/usb/kvaser_usb.c +480 -132
953 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v4 4/4 can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
From: Ahmed S. Darwish <[email protected]>
(This is a draft patch, I'm not sure if this fixes the USB bug or only its psymptom. Feedback from the linux-usb folks is really appreciated.)
When plugging the Kvaser USB/CAN dongle the first time, everything works as expected and all of the transfers from and to the USB device succeeds.
Meanwhile, after unplugging the device and plugging it again, the first bulk transfer _always_ returns an -ETIMEDOUT. The following behaviour was observied:
- Setting higher timeout values for the first bulk transfer never solved the issue.
- Unloading, then loading, our kvaser_usb module in question __always__ solved the issue.
- Checking first bulk transfer status, and retry the transfer again in case of an -ETIMEDOUT also __always__ solved the issue. This is what the patch below does.
- In the testing done so far, this issue appears only on laptops but never on PCs (possibly power related?)
--- drivers/net/can/usb/kvaser_usb.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/net/can/usb/kvaser_usb.c +11 -2
@@ -1927,7 +1927,7 @@ static int kvaser_usb_probe(struct usb_interface *intf, {struct kvaser_usb *dev;int err = -ENOMEM ; -int i; +int i, retry =3 ; dev =devm_kzalloc (&intf->dev,sizeof (*dev),GFP_KERNEL );if (!dev)
@@ -1956,7 +1956,16 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev); - err =kvaser_usb_get_software_info (dev); +/* On some x86 laptops, plugging a USBCAN device again after +* an unplug makes the firmware always ignore the very first +* command. For such a case, provide some room for retries +* instead of completly exiting the driver. +*/ +while (retry--) { + err =kvaser_usb_get_software_info (dev); +if (err != -ETIMEDOUT ) +break ; + }if (err) {dev_err (&intf->dev,"Cannot get software infos, error %d\n" , err);
Signature · 1 line
1.9.1
Marc Kleine-Budde
maintainerRe: [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
Quoted 20 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
(This is a draft patch, I'm not sure if this fixes the USB bug or only its psymptom. Feedback from the linux-usb folks is really appreciated.)
When plugging the Kvaser USB/CAN dongle the first time, everything works as expected and all of the transfers from and to the USB device succeeds.
Meanwhile, after unplugging the device and plugging it again, the first bulk transfer _always_ returns an
-ETIMEDOUT. The following behaviour was observied:- Setting higher timeout values for the first bulk transfer never solved the issue.
- Unloading, then loading, our
kvaser_usbmodule in question__always__solved the issue.
Quoted 8 lines
- Checking first bulk transfer status, and retry the transfer again in case of an
-ETIMEDOUTalso__always__solved the issue. This is what the patch below does.- In the testing done so far, this issue appears only on laptops but never on PCs (possibly power related?)
Signed-off-by Ahmed S. Darwish <[email protected]>
Does this patch apply apply between 3 and 4? If not, please re-arrange the series. As this is a bug fix, patches 1, 2 and 4 will go via net/master, 3 will go via net-next/master.
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
Quoted 25 lines · Marc Kleine-Budde
Quoted 24 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
(This is a draft patch, I'm not sure if this fixes the USB bug or only its psymptom. Feedback from the linux-usb folks is really appreciated.)
When plugging the Kvaser USB/CAN dongle the first time, everything works as expected and all of the transfers from and to the USB device succeeds.
Meanwhile, after unplugging the device and plugging it again, the first bulk transfer _always_ returns an
-ETIMEDOUT. The following behaviour was observied:- Setting higher timeout values for the first bulk transfer never solved the issue.
- Unloading, then loading, our
kvaser_usbmodule in question__always__solved the issue.- Checking first bulk transfer status, and retry the transfer again in case of an
-ETIMEDOUTalso__always__solved the issue. This is what the patch below does.
Quoted 9 lines
Quoted 4 lines
- In the testing done so far, this issue appears only on laptops but never on PCs (possibly power related?)
Signed-off-by Ahmed S. Darwish <[email protected]>Does this patch apply apply between 3 and 4? If not, please re-arrange the series. As this is a bug fix, patches 1, 2 and 4 will go via net/master, 3 will go via net-next/master.
Since no one complained earlier, I guess this issue only affects USBCAN devices. That's why I've based it above patch #3: adding USBCAN hardware support.
Nonetheless, it won't do any harm for the current Leaf-only driver. So _if_ this is the correct fix, I will update the commit log, refactor the check into a 'do { } while()' loop, and then base it above the Leaf-only net/master fixes on patch #1, and #2.
Any feedback on the USB side of things?
Thanks,
Darwish
Marc Kleine-Budde
maintainerRe: [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
Quoted 39 lines · Ahmed S. Darwish
Quoted 25 lines · Marc Kleine-Budde
Quoted 24 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
(This is a draft patch, I'm not sure if this fixes the USB bug or only its psymptom. Feedback from the linux-usb folks is really appreciated.)
When plugging the Kvaser USB/CAN dongle the first time, everything works as expected and all of the transfers from and to the USB device succeeds.
Meanwhile, after unplugging the device and plugging it again, the first bulk transfer _always_ returns an
-ETIMEDOUT. The following behaviour was observied:- Setting higher timeout values for the first bulk transfer never solved the issue.
- Unloading, then loading, our
kvaser_usbmodule in question__always__solved the issue.- Checking first bulk transfer status, and retry the transfer again in case of an
-ETIMEDOUTalso__always__solved the issue. This is what the patch below does.Quoted 8 lines
Quoted 4 lines
- In the testing done so far, this issue appears only on laptops but never on PCs (possibly power related?)
Signed-off-by Ahmed S. Darwish <[email protected]>Does this patch apply apply between 3 and 4? If not, please re-arrange the series. As this is a bug fix, patches 1, 2 and 4 will go via net/master, 3 will go via net-next/master.
Since no one complained earlier, I guess this issue only affects USBCAN devices. That's why I've based it above patch #3: adding USBCAN hardware support.
Quoted 6 lines
Nonetheless, it won't do any harm for the current Leaf-only driver. So _if_ this is the correct fix, I will update the commit log, refactor the check into a 'do { }
while()' loop, and then base it above the Leaf-only net/master fixes on patch #1, and #2.Any feedback on the USB side of things?
Maybe you have to change the subject of this patch to be more visible on the USB list and/or add the right USB people on Cc.
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
In reply to Ahmed S. DarwishHello,
Quoted 40 lines · Ahmed S. Darwish
Quoted 25 lines · Marc Kleine-Budde
Quoted 24 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
(This is a draft patch, I'm not sure if this fixes the USB bug or only its psymptom. Feedback from the linux-usb folks is really appreciated.)
When plugging the Kvaser USB/CAN dongle the first time, everything works as expected and all of the transfers from and to the USB device succeeds.
Meanwhile, after unplugging the device and plugging it again, the first bulk transfer _always_ returns an
-ETIMEDOUT. The following behaviour was observied:- Setting higher timeout values for the first bulk transfer never solved the issue.
- Unloading, then loading, our
kvaser_usbmodule in question__always__solved the issue.- Checking first bulk transfer status, and retry the transfer again in case of an
-ETIMEDOUTalso__always__solved the issue. This is what the patch below does.Quoted 9 lines
Quoted 4 lines
- In the testing done so far, this issue appears only on laptops but never on PCs (possibly power related?)
Signed-off-by Ahmed S. Darwish <[email protected]>Does this patch apply apply between 3 and 4? If not, please re-arrange the series. As this is a bug fix, patches 1, 2 and 4 will go via net/master, 3 will go via net-next/master.
Since no one complained earlier, I guess this issue only affects USBCAN devices. That's why I've based it above patch #3: adding USBCAN hardware support.
Quoted 6 lines
Nonetheless, it won't do any harm for the current Leaf-only driver. So _if_ this is the correct fix, I will update the commit log, refactor the check into a 'do { }
while()' loop, and then base it above the Leaf-only net/master fixes on patch #1, and #2.Any feedback on the USB side of things?
Can you take a wireshark capture showing the problem? It can maybe help people to figure out what happens.
What kind of usbcan device do you use?
Which firmware revision is loaded on the device?
Kr,
Signature · 1 line
Olivier
Re: [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
Quoted 48 lines · Olivier Sobrie
Hello,
Quoted 45 lines · Ahmed S. Darwish
Quoted 25 lines · Marc Kleine-Budde
Quoted 24 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
(This is a draft patch, I'm not sure if this fixes the USB bug or only its psymptom. Feedback from the linux-usb folks is really appreciated.)
When plugging the Kvaser USB/CAN dongle the first time, everything works as expected and all of the transfers from and to the USB device succeeds.
Meanwhile, after unplugging the device and plugging it again, the first bulk transfer _always_ returns an
-ETIMEDOUT. The following behaviour was observied:- Setting higher timeout values for the first bulk transfer never solved the issue.
- Unloading, then loading, our
kvaser_usbmodule in question__always__solved the issue.- Checking first bulk transfer status, and retry the transfer again in case of an
-ETIMEDOUTalso__always__solved the issue. This is what the patch below does.Quoted 9 lines
Quoted 4 lines
- In the testing done so far, this issue appears only on laptops but never on PCs (possibly power related?)
Signed-off-by Ahmed S. Darwish <[email protected]>Does this patch apply apply between 3 and 4? If not, please re-arrange the series. As this is a bug fix, patches 1, 2 and 4 will go via net/master, 3 will go via net-next/master.
Since no one complained earlier, I guess this issue only affects USBCAN devices. That's why I've based it above patch #3: adding USBCAN hardware support.
Nonetheless, it won't do any harm for the current Leaf-only driver. So _if_ this is the correct fix, I will update the commit log, refactor the check into a 'do { }
while()' loop, and then base it above the Leaf-only net/master fixes on patch #1, and #2.
Quoted 5 lines
Quoted 1 line
Any feedback on the USB side of things?
Can you take a wireshark capture showing the problem? It can maybe help people to figure out what happens.
Yeah, I'm planning on doing something similar.
Quoted 1 line
What kind of usbcan device do you use?
"Kvaser USBcan II HS/LS"
Quoted 2 lines
Which firmware revision is loaded on the device?
The device reports firmware version 2.9.410.
Interesting. The changelog of their latest firmware states that it "fixed USB configuration issue during USB attach." That might be the problem.
I have two devices here. I'll update the firmware only for one of them and see what happens.
Thanks,
Darwish
Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
In reply to Ahmed S. DarwishHi Marc,
Quoted 7 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'UsbcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
Quoted 7 lines
This patch adds support for the UsbcanII family of devices to the current Kvaser Leaf-only driver.
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
Please delay applying this to as I've just discovered that removal of two of the device family checks introduced two un-necessary GCC warnings.
Will send and updated version soon.
Thanks,
Darwish
Marc Kleine-Budde
maintainerRe: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
In reply to Ahmed S. DarwishQuoted 16 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'UsbcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
This patch adds support for the UsbcanII family of devices to the current Kvaser Leaf-only driver.
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
List of new devices supported by this driver update:
Quoted 8 lines
- Kvaser USBcan II HS/HS
- Kvaser USBcan II HS/LS
- Kvaser USBcan Rugged ("USBcan Rev B")
- Kvaser Memorator HS/HS
- Kvaser Memorator HS/LS
- Scania VCI2 (if you have the Kvaser logo on top)Signed-off-by Ahmed S. Darwish <[email protected]>
See some minor comments inline.
Marc
Quoted 68 lines
--- drivers/net/can/usb/Kconfig | 8 +- drivers/net/can/usb/kvaser_usb.c | 612 ++++++++++++++++++++++++++++++--------- 2 files changed, 487 insertions(+), 133 deletions(-)** V4 Changelog:
- Use type-safe C methods instead of cpp macros
- Further clarify the code and comments on error events channel arbitration
- Remove defensive checks against non-existing families
- Re-order methods to remove forward declarations
- Smaller stuff spotted by earlier review (function prefexes, etc.)** V3 Changelog:
- Fix padding for theusbcan_msg_tx_acknowledgecommand
- Removekvaser_usb->max_channelsand theMAX_NET_DEVICESmacro
- Rename commands toCMD_LEAF_xxxandCMD_USBCAN_xxx
- Apply checkpatch.pl suggestions ('net/' comments, multi-line strings, etc.)** V2 Changelog:
- UpdateKconfigentries
- Use actual number of CAN channels (instead of max) where appropriate
- Rebase over a new set of UsbcanII-independent driver fixesdrivers/net/can/usb/Kconfig +7
-1@@ -25,7 +25,7 @@ config CAN_KVASER_USB tristate "Kvaser CAN/USB interface" ---help--- This driver adds support for Kvaser CAN/USB devices like Kvaser - Leaf Light. + Leaf Light and Kvaser USBcan II. The driver provides support for the following devices: - Kvaser Leaf Light@@ -46,6 +46,12 @@ config CAN_KVASER_USB - Kvaser USBcan R - Kvaser Leaf Light v2 - Kvaser Mini PCI Express HS + - Kvaser USBcan II HS/HS + - Kvaser USBcan II HS/LS + - Kvaser USBcan Rugged ("USBcan Rev B") + - Kvaser Memorator HS/HS + - Kvaser Memorator HS/LS + - Scania VCI2 (if you have the Kvaser logo on top) If unsure, say N.drivers/net/can/usb/kvaser_usb.c +2
-0@@ -6,10 +6,12 @@* Parts of this driver are based on the following: * - Kvaser linux leaf driver (version 4.78) * - CAN driver for esd CAN-USB/2 +* - Kvaser linux usbcanII driver (version 5.3) * * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. * Copyright (C) 2010 Matthias Fuchs <[email protected]>, esd gmbh * Copyright (C) 2012 Olivier Sobrie <[email protected]> +* Copyright (C) 2015 Valeo Corporation */ #include <linux/completion.h> @@ -21,6 +23,15 @@#include <linux/can/dev.h>
drivers/net/can/usb/kvaser_usb.c line 33
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +8
-0#include <linux/can/error.h> +/* Kvaser USB CAN dongles are divided into two major families: +* - Leaf: Based on Renesas M32C, running firmware labeled as 'filo' +* - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios' +*/ +enum kvaser_usb_family { +KVASER_LEAF , +KVASER_USBCAN , +};
Nitpick: please move after the #defines
Quoted 424 lines
drivers/net/can/usb/kvaser_usb.c +215
-31+#define MAX_TX_URBS 16#define MAX_RX_URBS 4#define START_TIMEOUT 1000/* msecs */ @@ -30,8 +41,9 @@#define RX_BUFFER_SIZE 3072#define CAN_USB_CLOCK 8000000#define MAX_NET_DEVICES 3 +#define MAX_USBCAN_NET_DEVICES 2 -/* Kvaser USB devices */ +/* Leaf USB devices */ #define KVASER_VENDOR_ID 0x0bfd#define USB_LEAF_DEVEL_PRODUCT_ID 10#define USB_LEAF_LITE_PRODUCT_ID 11@@ -56,6 +68,24 @@#define USB_LEAF_LITE_V2_PRODUCT_ID 288#define USB_MINI_PCIE_HS_PRODUCT_ID 289 +static inline bool kvaser_is_leaf (const struct usb_device_id *id) +{ +return id->idProduct >=USB_LEAF_DEVEL_PRODUCT_ID && + id->idProduct <=USB_MINI_PCIE_HS_PRODUCT_ID ; +} + +/* USBCANII devices */ +#define USB_USBCAN_REVB_PRODUCT_ID 2 +#define USB_VCI2_PRODUCT_ID 3 +#define USB_USBCAN2_PRODUCT_ID 4 +#define USB_MEMORATOR_PRODUCT_ID 5 + +static inline bool kvaser_is_usbcan (const struct usb_device_id *id) +{ +return id->idProduct >=USB_USBCAN_REVB_PRODUCT_ID && + id->idProduct <=USB_MEMORATOR_PRODUCT_ID ; +} +/* USB devices features */ #define KVASER_HAS_SILENT_MODE BIT(0)#define KVASER_HAS_TXRX_ERRORS BIT(1)@@ -73,7 +103,7 @@#define MSG_FLAG_TX_ACK BIT(6)#define MSG_FLAG_TX_REQUEST BIT(7) -/* Can states */ +/* Can states (M16C CxSTRH register) */ #define M16C_STATE_BUS_RESET BIT(0)#define M16C_STATE_BUS_ERROR BIT(4)#define M16C_STATE_BUS_PASSIVE BIT(5)@@ -98,7 +128,13 @@#define CMD_START_CHIP_REPLY 27#define CMD_STOP_CHIP 28#define CMD_STOP_CHIP_REPLY 29 -#define CMD_GET_CARD_INFO2 32 +#define CMD_READ_CLOCK 30 +#define CMD_READ_CLOCK_REPLY 31 + +#define CMD_LEAF_GET_CARD_INFO2 32 +#define CMD_USBCAN_RESET_CLOCK 32 +#define CMD_USBCAN_CLOCK_OVERFLOW_EVENT 33 +#define CMD_GET_CARD_INFO 34#define CMD_GET_CARD_INFO_REPLY 35#define CMD_GET_SOFTWARE_INFO 38@@ -108,8 +144,9 @@#define CMD_RESET_ERROR_COUNTER 49#define CMD_TX_ACKNOWLEDGE 50#define CMD_CAN_ERROR_EVENT 51 -#define CMD_USB_THROTTLE 77 -#define CMD_LOG_MESSAGE 106 + +#define CMD_LEAF_USB_THROTTLE 77 +#define CMD_LEAF_LOG_MESSAGE 106/* error factors */ #define M16C_EF_ACKE BIT(0)@@ -121,6 +158,14 @@#define M16C_EF_RCVE BIT(6)#define M16C_EF_TRE BIT(7) +/* Only Leaf-based devices can report M16C error factors, +* thus define our own error status flags for USBCANII +*/ +#define USBCAN_ERROR_STATE_NONE 0 +#define USBCAN_ERROR_STATE_TX_ERROR BIT(0) +#define USBCAN_ERROR_STATE_RX_ERROR BIT(1) +#define USBCAN_ERROR_STATE_BUSERROR BIT(2) +/* bittiming parameters */ #define KVASER_USB_TSEG1_MIN 1#define KVASER_USB_TSEG1_MAX 16@@ -137,7 +182,7 @@#define KVASER_CTRL_MODE_SELFRECEPTION 3#define KVASER_CTRL_MODE_OFF 4 -/* log message */ +/* Extended CAN identifier flag */ #define KVASER_EXTENDED_FRAME BIT(31)struct kvaser_msg_simple {@@ -148,30 +193,55 @@ struct kvaser_msg_simple {struct kvaser_msg_cardinfo {u8 tid;u8 nchannels; -__le32 serial_number; -__le32 padding; +union { +struct { +__le32 serial_number; +__le32 padding; + } __packed leaf0; +struct { +__le32 serial_number_low; +__le32 serial_number_high; + } __packed usbcan0; + } __packed;__le32 clock_resolution;__le32 mfgdate;u8 ean[8 ];u8 hw_revision; -u8 usb_hs_mode; -__le16 padding2; +union { +struct { +u8 usb_hs_mode; + } __packed leaf1; +struct { +u8 padding; + } __packed usbcan1; + } __packed; +__le16 padding; } __packed;struct kvaser_msg_cardinfo2 {u8 tid; -u8 channel; +u8 reserved;u8 pcb_id[24 ];__le32 oem_unlock_code; } __packed; -struct kvaser_msg_softinfo { +struct leaf_msg_softinfo {u8 tid; -u8 channel; +u8 padding0;__le32 sw_options;__le32 fw_version;__le16 max_outstanding_tx; -__le16 padding[9 ]; +__le16 padding1[9 ]; +} __packed; + +struct usbcan_msg_softinfo { +u8 tid; +u8 fw_name[5 ]; +__le16 max_outstanding_tx; +u8 padding[6 ]; +__le32 fw_version; +__le16 checksum; +__le16 sw_options; } __packed;struct kvaser_msg_busparams {@@ -188,36 +258,86 @@ struct kvaser_msg_tx_can {u8 channel;u8 tid;u8 msg[14 ]; -u8 padding; -u8 flags; +union { +struct { +u8 padding; +u8 flags; + } __packed leaf; +struct { +u8 flags; +u8 padding; + } __packed usbcan; + } __packed; +} __packed; + +struct kvaser_msg_rx_can_header { +u8 channel; +u8 flag; } __packed; -struct kvaser_msg_rx_can { +struct leaf_msg_rx_can {u8 channel;u8 flag; +__le16 time[3 ];u8 msg[14 ]; } __packed; -struct kvaser_msg_chip_state_event { +struct usbcan_msg_rx_can { +u8 channel; +u8 flag; + +u8 msg[14 ]; +__le16 time; +} __packed; + +struct leaf_msg_chip_state_event {u8 tid;u8 channel; +__le16 time[3 ];u8 tx_errors_count;u8 rx_errors_count; +u8 status;u8 padding[3 ]; } __packed; -struct kvaser_msg_tx_acknowledge { +struct usbcan_msg_chip_state_event { +u8 tid; +u8 channel; + +u8 tx_errors_count; +u8 rx_errors_count; +__le16 time; + +u8 status; +u8 padding[3 ]; +} __packed; + +struct kvaser_msg_tx_acknowledge_header { +u8 channel; +u8 tid; +}; + +struct leaf_msg_tx_acknowledge {u8 channel;u8 tid; +__le16 time[3 ];u8 flags;u8 time_offset; } __packed; -struct kvaser_msg_error_event { +struct usbcan_msg_tx_acknowledge { +u8 channel; +u8 tid; + +__le16 time; +__le16 padding; +} __packed; + +struct leaf_msg_error_event {u8 tid;u8 flags;__le16 time[3 ];@@ -229,6 +349,18 @@ struct kvaser_msg_error_event {u8 error_factor; } __packed; +struct usbcan_msg_error_event { +u8 tid; +u8 padding; +u8 tx_errors_count_ch0; +u8 rx_errors_count_ch0; +u8 tx_errors_count_ch1; +u8 rx_errors_count_ch1; +u8 status_ch0; +u8 status_ch1; +__le16 time; +} __packed; +struct kvaser_msg_ctrl_mode {u8 tid;u8 channel;@@ -243,7 +375,7 @@ struct kvaser_msg_flush_queue {u8 padding[3 ]; } __packed; -struct kvaser_msg_log_message { +struct leaf_msg_log_message {u8 channel;u8 flags;__le16 time[3 ];@@ -260,19 +392,57 @@ struct kvaser_msg {struct kvaser_msg_simple simple;struct kvaser_msg_cardinfo cardinfo;struct kvaser_msg_cardinfo2 cardinfo2; -struct kvaser_msg_softinfo softinfo;struct kvaser_msg_busparams busparams; + +struct kvaser_msg_rx_can_header rx_can_header; +struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header; + +union { +struct leaf_msg_softinfo softinfo; +struct leaf_msg_rx_can rx_can; +struct leaf_msg_chip_state_event chip_state_event; +struct leaf_msg_tx_acknowledge tx_acknowledge; +struct leaf_msg_error_event error_event; +struct leaf_msg_log_message log_message; + } __packed leaf; + +union { +struct usbcan_msg_softinfo softinfo; +struct usbcan_msg_rx_can rx_can; +struct usbcan_msg_chip_state_event chip_state_event; +struct usbcan_msg_tx_acknowledge tx_acknowledge; +struct usbcan_msg_error_event error_event; + } __packed usbcan; +struct kvaser_msg_tx_can tx_can; -struct kvaser_msg_rx_can rx_can; -struct kvaser_msg_chip_state_event chip_state_event; -struct kvaser_msg_tx_acknowledge tx_acknowledge; -struct kvaser_msg_error_event error_event;struct kvaser_msg_ctrl_mode ctrl_mode;struct kvaser_msg_flush_queue flush_queue; -struct kvaser_msg_log_message log_message; } u; } __packed; +/* Summary of a kvaser error event, for a unified Leaf/Usbcan error +* handling. Some discrepancies between the two families exist: +* +* - USBCAN firmware does not report M16C "error factors" +* - USBCAN controllers has difficulties reporting if the raised error +* event is for ch0 or ch1. They leave such arbitration to the OS +* driver by letting it compare error counters with previous values +* and decide the error event's channel. Thus for USBCAN, the channel +* field is only advisory. +*/ +struct kvaser_error_summary { +u8 channel, status, txerr, rxerr; +union { +struct { +u8 error_factor; + } leaf; +struct { +u8 other_ch_status; +u8 error_state; + } usbcan; + }; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;@@ -288,6 +458,7 @@ struct kvaser_usb {u32 fw_version;unsigned int nchannels; +enum kvaser_usb_family family;bool rxinitdone;void *rxbuf[MAX_RX_URBS ];@@ -311,6 +482,7 @@ struct kvaser_usb_net_priv { };static const struct usb_device_id kvaser_usb_table[] = { +/* Leaf family IDs */ {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_DEVEL_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_LITE_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_PRO_PRODUCT_ID ),@@ -360,6 +532,17 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = KVASER_HAS_TXRX_ERRORS }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, + +/* USBCANII family IDs */ + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { } };MODULE_DEVICE_TABLE (usb, kvaser_usb_table);@@ -463,7 +646,14 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)if (err)return err; - dev->fw_version =le32_to_cpu (msg.u.softinfo.fw_version); +switch (dev->family) { +case KVASER_LEAF : + dev->fw_version =le32_to_cpu (msg.u.leaf.softinfo.fw_version); +break ; +case KVASER_USBCAN : + dev->fw_version =le32_to_cpu (msg.u.usbcan.softinfo.fw_version); +break ; + }return 0 ; }@@ -482,7 +672,9 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)return err; dev->nchannels = msg.u.cardinfo.nchannels; -if (dev->nchannels >MAX_NET_DEVICES ) +if ((dev->nchannels >MAX_NET_DEVICES ) || + (dev->family ==KVASER_USBCAN && + dev->nchannels >MAX_USBCAN_NET_DEVICES ))return -EINVAL ;return 0 ;@@ -496,8 +688,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,struct kvaser_usb_net_priv *priv;struct sk_buff *skb;struct can_frame *cf; -u8 channel = msg->u.tx_acknowledge.channel; -u8 tid = msg->u.tx_acknowledge.tid; +u8 channel, tid; + + channel = msg->u.tx_acknowledge_header.channel; + tid = msg->u.tx_acknowledge_header.tid;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 813
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +1
-1@@ -616,53 +810,24 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) }static void kvaser_usb_rx_error (const struct kvaser_usb *dev, -const struct kvaser_msg *msg) +struct kvaser_error_summary *es)
Can you make "struct kvaser_error_summary *es" const?
Quoted 182 lines
drivers/net/can/usb/kvaser_usb.c +52
-69{struct can_frame *cf;struct sk_buff *skb;struct net_device_stats *stats;struct kvaser_usb_net_priv *priv;unsigned int new_state; -u8 channel, status, txerr, rxerr, error_factor; - -switch (msg->id) { -case CMD_CAN_ERROR_EVENT : - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; -break ; -case CMD_LOG_MESSAGE : - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0 ]; - txerr = msg->u.log_message.data[2 ]; - rxerr = msg->u.log_message.data[3 ]; - error_factor = msg->u.log_message.data[1 ]; -break ; -case CMD_CHIP_STATE_EVENT : - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor =0 ; -break ; -default : -dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , - msg->id); -return ; - } -if (channel >= dev->nchannels) { +if (es->channel >= dev->nchannels) {dev_err (dev->udev->dev.parent, -"Invalid channel number (%d)\n" , channel); +"Invalid channel number (%d)\n" , es->channel);return ; } - priv = dev->nets[channel]; + priv = dev->nets[es->channel]; stats = &priv->netdev->stats; -if (status &M16C_STATE_BUS_RESET ) { +if (es->status &M16C_STATE_BUS_RESET ) {kvaser_usb_unlink_tx_urbs (priv);return ; }@@ -675,9 +840,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, new_state = priv->can.state; -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (status &M16C_STATE_BUS_OFF ) { +if (es->status &M16C_STATE_BUS_OFF ) { cf->can_id |=CAN_ERR_BUSOFF ; priv->can.can_stats.bus_off++;@@ -687,12 +852,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,netif_carrier_off (priv->netdev); new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { + }else if (es->status &M16C_STATE_BUS_PASSIVE ) {if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es->txerr || es->rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else @@ -703,13 +868,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } new_state =CAN_STATE_ERROR_PASSIVE ; - } - -if (status ==M16C_STATE_BUS_ERROR ) { + }else if (es->status &M16C_STATE_BUS_ERROR ) {if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { + ((es->txerr >=96 ) || (es->rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ;@@ -723,7 +886,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } } -if (!status) { +if (!es->status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ;@@ -739,34 +902,48 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv->can.can_stats.restarts++; } -if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - - cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; - -if (error_factor &M16C_EF_ACKE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); -if (error_factor &M16C_EF_CRCE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | -CAN_ERR_PROT_LOC_CRC_DEL ); -if (error_factor &M16C_EF_FORME ) - cf->data[2 ] |=CAN_ERR_PROT_FORM ; -if (error_factor &M16C_EF_STFE ) - cf->data[2 ] |=CAN_ERR_PROT_STUFF ; -if (error_factor &M16C_EF_BITE0 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; -if (error_factor &M16C_EF_BITE1 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; -if (error_factor &M16C_EF_TRE ) - cf->data[2 ] |=CAN_ERR_PROT_TX ; +switch (dev->family) { +case KVASER_LEAF : +if (es->leaf.error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; + +if (es->leaf.error_factor &M16C_EF_ACKE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); +if (es->leaf.error_factor &M16C_EF_CRCE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | +CAN_ERR_PROT_LOC_CRC_DEL ); +if (es->leaf.error_factor &M16C_EF_FORME ) + cf->data[2 ] |=CAN_ERR_PROT_FORM ; +if (es->leaf.error_factor &M16C_EF_STFE ) + cf->data[2 ] |=CAN_ERR_PROT_STUFF ; +if (es->leaf.error_factor &M16C_EF_BITE0 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; +if (es->leaf.error_factor &M16C_EF_BITE1 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; +if (es->leaf.error_factor &M16C_EF_TRE ) + cf->data[2 ] |=CAN_ERR_PROT_TX ; + } +break ; +case KVASER_USBCAN : +if (es->usbcan.error_state &USBCAN_ERROR_STATE_TX_ERROR ) + stats->tx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_RX_ERROR ) + stats->rx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_BUSERROR ) { + priv->can.can_stats.bus_error++; + cf->can_id |=CAN_ERR_BUSERROR ; + } +break ; } - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; + cf->data[6 ] = es->txerr; + cf->data[7 ] = es->rxerr; - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; priv->can.state = new_state;
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 959
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c +5
-0@@ -775,6 +952,124 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,netif_rx (skb); } +/* For USBCAN, report error to userspace iff the channels's errors counter +* has increased, or we're the only channel seeing a bus error state. +*/ +static void kvaser_usbcan_conditionally_rx_error (const struct kvaser_usb *dev, +struct kvaser_error_summary *es)
const struct kvaser_error_summary *es?
Quoted 48 lines
drivers/net/can/usb/kvaser_usb.c +48
-0+{ +struct kvaser_usb_net_priv *priv; +int channel; +bool report_error; + + channel = es->channel; +if (channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , channel); +return ; + } + + priv = dev->nets[channel]; + report_error = false; + +if (es->txerr > priv->bec.txerr) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_TX_ERROR ; + report_error = true; + } +if (es->rxerr > priv->bec.rxerr) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_RX_ERROR ; + report_error = true; + } +if ((es->status &M16C_STATE_BUS_ERROR ) && + !(es->usbcan.other_ch_status &M16C_STATE_BUS_ERROR )) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_BUSERROR ; + report_error = true; + } + +if (report_error) +kvaser_usb_rx_error (dev, es); +} + +static void kvaser_usbcan_rx_error (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = { }; + +switch (msg->id) { +/* Sometimes errors are sent as unsolicited chip state events */ +case CMD_CHIP_STATE_EVENT : + es.channel = msg->u.usbcan.chip_state_event.channel; + es.status = msg->u.usbcan.chip_state_event.status; + es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count; + es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count; +kvaser_usbcan_conditionally_rx_error (dev, &es); +break ; +
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 1017
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+case CMD_CAN_ERROR_EVENT : + es.channel =0 ; + es.status = msg->u.usbcan.error_event.status_ch0; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch1; +kvaser_usbcan_conditionally_rx_error (dev, &es); + +/* The USBCAN firmware does not support more than 2 channels.
Does USBCAN support always 2 channels or are there models with 1 channels, too. I'd rephrase ..."does support up to 2 channels."
Quoted 117 lines
drivers/net/can/usb/kvaser_usb.c +72
-12+* Now that ch0 was checked, check if ch1 has any errors. +*/ +if (dev->nchannels ==MAX_USBCAN_NET_DEVICES ) { + es.channel =1 ; + es.status = msg->u.usbcan.error_event.status_ch1; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch0; +kvaser_usbcan_conditionally_rx_error (dev, &es); + } +break ; + +default : +dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , + msg->id); + } +} + +static void kvaser_leaf_rx_error (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = { }; + +switch (msg->id) { +case CMD_CAN_ERROR_EVENT : + es.channel = msg->u.leaf.error_event.channel; + es.status = msg->u.leaf.error_event.status; + es.txerr = msg->u.leaf.error_event.tx_errors_count; + es.rxerr = msg->u.leaf.error_event.rx_errors_count; + es.leaf.error_factor = msg->u.leaf.error_event.error_factor; +break ; +case CMD_LEAF_LOG_MESSAGE : + es.channel = msg->u.leaf.log_message.channel; + es.status = msg->u.leaf.log_message.data[0 ]; + es.txerr = msg->u.leaf.log_message.data[2 ]; + es.rxerr = msg->u.leaf.log_message.data[3 ]; + es.leaf.error_factor = msg->u.leaf.log_message.data[1 ]; +break ; +case CMD_CHIP_STATE_EVENT : + es.channel = msg->u.leaf.chip_state_event.channel; + es.status = msg->u.leaf.chip_state_event.status; + es.txerr = msg->u.leaf.chip_state_event.tx_errors_count; + es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count; + es.leaf.error_factor =0 ; +break ; +default : +dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , + msg->id); +return ; + } + +kvaser_usb_rx_error (dev, &es); +} +static void kvaser_usb_rx_can_err (const struct kvaser_usb_net_priv *priv,const struct kvaser_msg *msg) {@@ -782,16 +1077,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,struct sk_buff *skb;struct net_device_stats *stats = &priv->netdev->stats; -if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | +if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |MSG_FLAG_NERR )) {netdev_err (priv->netdev,"Unknow error (flags: 0x%02x)\n" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); stats->rx_errors++;return ; } -if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { +if (msg->u.rx_can_header.flag &MSG_FLAG_OVERRUN ) { stats->rx_over_errors++; stats->rx_errors++;@@ -817,7 +1112,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,struct can_frame *cf;struct sk_buff *skb;struct net_device_stats *stats; -u8 channel = msg->u.rx_can.channel; +u8 channel = msg->u.rx_can_header.channel; +const u8 *rx_msg;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,@@ -828,19 +1124,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; -if ((msg->u.rx_can.flag &MSG_FLAG_ERROR_FRAME ) && - (msg->id ==CMD_LOG_MESSAGE )) { -kvaser_usb_rx_error (dev, msg); +if ((msg->u.rx_can_header.flag &MSG_FLAG_ERROR_FRAME ) && + (dev->family ==KVASER_LEAF && msg->id ==CMD_LEAF_LOG_MESSAGE )) { +kvaser_leaf_rx_error (dev, msg);return ; - }else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | -MSG_FLAG_NERR | -MSG_FLAG_OVERRUN )) { + }else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME | +MSG_FLAG_NERR | +MSG_FLAG_OVERRUN )) {kvaser_usb_rx_can_err (priv, msg);return ; - }else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME ) { + }else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME ) {netdev_warn (priv->netdev,"Unhandled frame (flags: 0x%02x)" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); +return ; + } + +switch (dev->family) {
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, · line 1153
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +9
-0+case KVASER_LEAF : + rx_msg = msg->u.leaf.rx_can.msg; +break ; +case KVASER_USBCAN : + rx_msg = msg->u.usbcan.rx_can.msg; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family);return ;
should not happen.
Quoted 102 lines
drivers/net/can/usb/kvaser_usb.c +30
-17}@@ -850,38 +1159,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,return ; } -if (msg->id ==CMD_LOG_MESSAGE ) { - cf->can_id =le32_to_cpu (msg->u.log_message.id); +if (dev->family ==KVASER_LEAF && msg->id ==CMD_LEAF_LOG_MESSAGE ) { + cf->can_id =le32_to_cpu (msg->u.leaf.log_message.id);if (cf->can_id &KVASER_EXTENDED_FRAME ) cf->can_id &=CAN_EFF_MASK |CAN_EFF_FLAG ;else cf->can_id &=CAN_SFF_MASK ; - cf->can_dlc =get_can_dlc (msg->u.log_message.dlc); + cf->can_dlc =get_can_dlc (msg->u.leaf.log_message.dlc); -if (msg->u.log_message.flags &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.leaf.log_message.flags &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.log_message.data, +memcpy (cf->data, &msg->u.leaf.log_message.data, cf->can_dlc); }else { - cf->can_id = ((msg->u.rx_can.msg[0 ] &0x1f ) <<6 ) | - (msg->u.rx_can.msg[1 ] &0x3f ); + cf->can_id = ((rx_msg[0 ] &0x1f ) <<6 ) | (rx_msg[1 ] &0x3f );if (msg->id ==CMD_RX_EXT_MESSAGE ) { cf->can_id <<=18 ; - cf->can_id |= ((msg->u.rx_can.msg[2 ] &0x0f ) <<14 ) | - ((msg->u.rx_can.msg[3 ] &0xff ) <<6 ) | - (msg->u.rx_can.msg[4 ] &0x3f ); + cf->can_id |= ((rx_msg[2 ] &0x0f ) <<14 ) | + ((rx_msg[3 ] &0xff ) <<6 ) | + (rx_msg[4 ] &0x3f ); cf->can_id |=CAN_EFF_FLAG ; } - cf->can_dlc =get_can_dlc (msg->u.rx_can.msg[5 ]); + cf->can_dlc =get_can_dlc (rx_msg[5 ]); -if (msg->u.rx_can.flag &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.rx_can_header.flag &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.rx_can.msg[6 ], +memcpy (cf->data, &rx_msg[6 ], cf->can_dlc); }@@ -944,21 +1252,35 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,case CMD_RX_STD_MESSAGE :case CMD_RX_EXT_MESSAGE : -case CMD_LOG_MESSAGE : +kvaser_usb_rx_can_msg (dev, msg); +break ; + +case CMD_LEAF_LOG_MESSAGE : +if (dev->family !=KVASER_LEAF ) + goto warn;kvaser_usb_rx_can_msg (dev, msg);break ;case CMD_CHIP_STATE_EVENT :case CMD_CAN_ERROR_EVENT : -kvaser_usb_rx_error (dev, msg); +if (dev->family ==KVASER_LEAF ) +kvaser_leaf_rx_error (dev, msg); +else +kvaser_usbcan_rx_error (dev, msg);break ;case CMD_TX_ACKNOWLEDGE :kvaser_usb_tx_acknowledge (dev, msg);break ; +/* Ignored messages */ +case CMD_USBCAN_CLOCK_OVERFLOW_EVENT : +if (dev->family !=KVASER_USBCAN ) + goto warn; +break ; +default : -dev_warn (dev->udev->dev.parent, +warn:dev_warn (dev->udev->dev.parent,"Unhandled message (%d)\n" , msg->id);break ; }@@ -1178,7 +1500,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) dev->rxbuf[i], dev->rxbuf_dma[i]); -for (i =0 ; i <MAX_NET_DEVICES ; i++) { +for (i =0 ; i < dev->nchannels; i++) {struct kvaser_usb_net_priv *priv = dev->nets[i];if (priv)
drivers/net/can/usb/kvaser_usb.c static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, · line 1611
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +1
-0@@ -1286,6 +1608,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,struct kvaser_msg *msg;int i, err;int ret =NETDEV_TX_OK ; +uint8_t *msg_tx_can_flags;
u8 please
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c +1
-1if (can_dropped_invalid_skb (netdev, skb))return NETDEV_TX_OK ;@@ -1307,9 +1630,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, msg = buf; msg->len =MSG_HEADER_LEN +sizeof (struct kvaser_msg_tx_can ); - msg->u.tx_can.flags =0 ; msg->u.tx_can.channel = priv->channel; +switch (dev->family) {
drivers/net/can/usb/kvaser_usb.c static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, · line 1645
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+case KVASER_LEAF : + msg_tx_can_flags = &msg->u.tx_can.leaf.flags; +break ; +case KVASER_USBCAN : + msg_tx_can_flags = &msg->u.tx_can.usbcan.flags; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto releasebuf;
should not happen, please remove
Quoted 25 lines
drivers/net/can/usb/kvaser_usb.c +9
-1+ } + + *msg_tx_can_flags =0 ; +if (cf->can_id &CAN_EFF_FLAG ) { msg->id =CMD_TX_EXT_MESSAGE ; msg->u.tx_can.msg[0 ] = (cf->can_id >>24 ) &0x1f ;@@ -1327,7 +1664,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,memcpy (&msg->u.tx_can.msg[6 ], cf->data, cf->can_dlc);if (cf->can_id &CAN_RTR_FLAG ) - msg->u.tx_can.flags |=MSG_FLAG_REMOTE_FRAME ; + *msg_tx_can_flags |=MSG_FLAG_REMOTE_FRAME ;for (i =0 ; i <ARRAY_SIZE (priv->tx_contexts); i++) {if (priv->tx_contexts[i].echo_index ==MAX_TX_URBS ) {@@ -1596,6 +1933,17 @@ static int kvaser_usb_probe(struct usb_interface *intf,if (!dev)return -ENOMEM ; +if (kvaser_is_leaf (id)) { + dev->family =KVASER_LEAF ; + }else if (kvaser_is_usbcan (id)) { + dev->family =KVASER_USBCAN ;
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1949
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +7
-0+ }else { +dev_err (&intf->dev, +"Product ID (%d) does not belong to any known Kvaser USB family" , + id->idProduct); +return -ENODEV ; + } + err =kvaser_usb_get_endpoints (intf, &dev->bulk_in, &dev->bulk_out);if (err) {dev_err (&intf->dev,"Cannot get usb endpoint(s)" );
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
Hi Marc,
Quoted 1 line · Marc Kleine-Budde
On 01/11/2015 09:36 PM, Ahmed S. Darwish wrote:
[...]
Quoted 21 lines
Quoted 21 lines
drivers/net/can/usb/kvaser_usb.c +2
-0@@ -6,10 +6,12 @@* Parts of this driver are based on the following: * - Kvaser linux leaf driver (version 4.78) * - CAN driver for esd CAN-USB/2 +* - Kvaser linux usbcanII driver (version 5.3) * * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. * Copyright (C) 2010 Matthias Fuchs <[email protected]>, esd gmbh * Copyright (C) 2012 Olivier Sobrie <[email protected]> +* Copyright (C) 2015 Valeo Corporation */ #include <linux/completion.h> @@ -21,6 +23,15 @@#include <linux/can/dev.h> #include <linux/can/error.h>
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c line 33
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c +8
-0+/* Kvaser USB CAN dongles are divided into two major families: +* - Leaf: Based on Renesas M32C, running firmware labeled as 'filo' +* - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios' +*/ +enum kvaser_usb_family { +KVASER_LEAF , +KVASER_USBCAN , +};Nitpick: please move after the #defines
Will do.
[...]
Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 813
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c +1
-1@@ -616,53 +810,24 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) }static void kvaser_usb_rx_error (const struct kvaser_usb *dev, -const struct kvaser_msg *msg) +struct kvaser_error_summary *es)Can you make "struct
kvaser_error_summary*es" const?
Sure.
[...]
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 959
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +5
-0+/* For USBCAN, report error to userspace iff the channels's errors counter +* has increased, or we're the only channel seeing a bus error state. +*/ +static void kvaser_usbcan_conditionally_rx_error (const struct kvaser_usb *dev, +struct kvaser_error_summary *es)const struct
kvaser_error_summary*es?
Ditto.
[...]
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 1017
Quoted 2 lines
drivers/net/can/usb/kvaser_usb.c +2
-0+ +/* The USBCAN firmware does not support more than 2 channels. Does USBCAN support always 2 channels or are there models with 1 channels, too. I'd rephrase ..."does support up to 2 channels."
Yup, that will be more accurate.
[...]
Quoted 6 lines
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c +6
-0+ +switch (dev->family) { +case KVASER_LEAF : + rx_msg = msg->u.leaf.rx_can.msg; +break ; +case KVASER_USBCAN :
Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, · line 1153
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c +5
-0+ rx_msg = msg->u.usbcan.rx_can.msg; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family);return ;should not happen.
Yes, but otherwise I get GCC warnings of 'rx_msg' possibly being unused. I can add __maybe_unused to rx_msg of course, but such annotation may hide possible errors in the future.
Quoted 4 lines
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+switch (dev->family) { +case KVASER_LEAF : + msg_tx_can_flags = &msg->u.tx_can.leaf.flags; +break ;
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, · line 1645
Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c +7
-0+case KVASER_USBCAN : + msg_tx_can_flags = &msg->u.tx_can.usbcan.flags; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto releasebuf;should not happen, please remove
Like the 'rx_msg' case above.
Thanks,
Darwish
Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
Quoted 20 lines · Ahmed S. Darwish
Hi Marc,
Quoted 16 lines · Marc Kleine-Budde
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, · line 1153
Quoted 12 lines · Ahmed S. Darwish
drivers/net/can/usb/kvaser_usb.c +11
-0+ +switch (dev->family) { +case KVASER_LEAF : + rx_msg = msg->u.leaf.rx_can.msg; +break ; +case KVASER_USBCAN : + rx_msg = msg->u.usbcan.rx_can.msg; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family);return ;should not happen.
Quoted 4 lines
Yes, but otherwise I get GCC warnings of '
rx_msg' possibly being unused. I can add__maybe_unusedtorx_msgof course, but such annotation may hide possible errors in the future.
Ah, what I meant is using uninitialized_var() to suppress the GCC warning. But, really, using that macro has a bad history of hiding errors in the future.
Kindly check http://lwn.net/Articles/529954/ for context.
Another solution might be initializing rx_msg to NULL.
Quoted 17 lines
Quoted 4 lines
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+switch (dev->family) { +case KVASER_LEAF : + msg_tx_can_flags = &msg->u.tx_can.leaf.flags; +break ;Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, · line 1645
Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c +7
-0+case KVASER_USBCAN : + msg_tx_can_flags = &msg->u.tx_can.usbcan.flags; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto releasebuf;should not happen, please remove
Like the '
rx_msg' case above.Thanks,
Darwish
Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
In reply to Ahmed S. DarwishHello,
Quoted 16 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'UsbcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
This patch adds support for the UsbcanII family of devices to the current Kvaser Leaf-only driver.
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
List of new devices supported by this driver update:
Quoted 8 lines
- Kvaser USBcan II HS/HS
- Kvaser USBcan II HS/LS
- Kvaser USBcan Rugged ("USBcan Rev B")
- Kvaser Memorator HS/HS
- Kvaser Memorator HS/LS
- Scania VCI2 (if you have the Kvaser logo on top)Signed-off-by Ahmed S. Darwish <[email protected]>
Just two small remarks below.
Thanks,
Olivier
Quoted 128 lines
--- drivers/net/can/usb/Kconfig | 8 +- drivers/net/can/usb/kvaser_usb.c | 612 ++++++++++++++++++++++++++++++--------- 2 files changed, 487 insertions(+), 133 deletions(-)** V4 Changelog:
- Use type-safe C methods instead of cpp macros
- Further clarify the code and comments on error events channel arbitration
- Remove defensive checks against non-existing families
- Re-order methods to remove forward declarations
- Smaller stuff spotted by earlier review (function prefexes, etc.)** V3 Changelog:
- Fix padding for theusbcan_msg_tx_acknowledgecommand
- Removekvaser_usb->max_channelsand theMAX_NET_DEVICESmacro
- Rename commands toCMD_LEAF_xxxandCMD_USBCAN_xxx
- Apply checkpatch.pl suggestions ('net/' comments, multi-line strings, etc.)** V2 Changelog:
- UpdateKconfigentries
- Use actual number of CAN channels (instead of max) where appropriate
- Rebase over a new set of UsbcanII-independent driver fixesdrivers/net/can/usb/Kconfig +7
-1@@ -25,7 +25,7 @@ config CAN_KVASER_USB tristate "Kvaser CAN/USB interface" ---help--- This driver adds support for Kvaser CAN/USB devices like Kvaser - Leaf Light. + Leaf Light and Kvaser USBcan II. The driver provides support for the following devices: - Kvaser Leaf Light@@ -46,6 +46,12 @@ config CAN_KVASER_USB - Kvaser USBcan R - Kvaser Leaf Light v2 - Kvaser Mini PCI Express HS + - Kvaser USBcan II HS/HS + - Kvaser USBcan II HS/LS + - Kvaser USBcan Rugged ("USBcan Rev B") + - Kvaser Memorator HS/HS + - Kvaser Memorator HS/LS + - Scania VCI2 (if you have the Kvaser logo on top) If unsure, say N.drivers/net/can/usb/kvaser_usb.c +32
-2@@ -6,10 +6,12 @@* Parts of this driver are based on the following: * - Kvaser linux leaf driver (version 4.78) * - CAN driver for esd CAN-USB/2 +* - Kvaser linux usbcanII driver (version 5.3) * * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved. * Copyright (C) 2010 Matthias Fuchs <[email protected]>, esd gmbh * Copyright (C) 2012 Olivier Sobrie <[email protected]> +* Copyright (C) 2015 Valeo Corporation */ #include <linux/completion.h> @@ -21,6 +23,15 @@#include <linux/can/dev.h> #include <linux/can/error.h> +/* Kvaser USB CAN dongles are divided into two major families: +* - Leaf: Based on Renesas M32C, running firmware labeled as 'filo' +* - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios' +*/ +enum kvaser_usb_family { +KVASER_LEAF , +KVASER_USBCAN , +}; +#define MAX_TX_URBS 16#define MAX_RX_URBS 4#define START_TIMEOUT 1000/* msecs */ @@ -30,8 +41,9 @@#define RX_BUFFER_SIZE 3072#define CAN_USB_CLOCK 8000000#define MAX_NET_DEVICES 3 +#define MAX_USBCAN_NET_DEVICES 2 -/* Kvaser USB devices */ +/* Leaf USB devices */ #define KVASER_VENDOR_ID 0x0bfd#define USB_LEAF_DEVEL_PRODUCT_ID 10#define USB_LEAF_LITE_PRODUCT_ID 11@@ -56,6 +68,24 @@#define USB_LEAF_LITE_V2_PRODUCT_ID 288#define USB_MINI_PCIE_HS_PRODUCT_ID 289 +static inline bool kvaser_is_leaf (const struct usb_device_id *id) +{ +return id->idProduct >=USB_LEAF_DEVEL_PRODUCT_ID && + id->idProduct <=USB_MINI_PCIE_HS_PRODUCT_ID ; +} + +/* USBCANII devices */ +#define USB_USBCAN_REVB_PRODUCT_ID 2 +#define USB_VCI2_PRODUCT_ID 3 +#define USB_USBCAN2_PRODUCT_ID 4 +#define USB_MEMORATOR_PRODUCT_ID 5 + +static inline bool kvaser_is_usbcan (const struct usb_device_id *id) +{ +return id->idProduct >=USB_USBCAN_REVB_PRODUCT_ID && + id->idProduct <=USB_MEMORATOR_PRODUCT_ID ; +} +/* USB devices features */ #define KVASER_HAS_SILENT_MODE BIT(0)#define KVASER_HAS_TXRX_ERRORS BIT(1)@@ -73,7 +103,7 @@#define MSG_FLAG_TX_ACK BIT(6)#define MSG_FLAG_TX_REQUEST BIT(7) -/* Can states */ +/* Can states (M16C CxSTRH register) */ #define M16C_STATE_BUS_RESET BIT(0)#define M16C_STATE_BUS_ERROR BIT(4)#define M16C_STATE_BUS_PASSIVE BIT(5)
drivers/net/can/usb/kvaser_usb.c line 132
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c +2
-1@@ -98,7 +128,13 @@#define CMD_START_CHIP_REPLY 27#define CMD_STOP_CHIP 28#define CMD_STOP_CHIP_REPLY 29 -#define CMD_GET_CARD_INFO2 32 +#define CMD_READ_CLOCK 30 +#define CMD_READ_CLOCK_REPLY 31
These two defines are not used.
Quoted 168 lines
drivers/net/can/usb/kvaser_usb.c +84
-16+ +#define CMD_LEAF_GET_CARD_INFO2 32 +#define CMD_USBCAN_RESET_CLOCK 32 +#define CMD_USBCAN_CLOCK_OVERFLOW_EVENT 33 +#define CMD_GET_CARD_INFO 34#define CMD_GET_CARD_INFO_REPLY 35#define CMD_GET_SOFTWARE_INFO 38@@ -108,8 +144,9 @@#define CMD_RESET_ERROR_COUNTER 49#define CMD_TX_ACKNOWLEDGE 50#define CMD_CAN_ERROR_EVENT 51 -#define CMD_USB_THROTTLE 77 -#define CMD_LOG_MESSAGE 106 + +#define CMD_LEAF_USB_THROTTLE 77 +#define CMD_LEAF_LOG_MESSAGE 106/* error factors */ #define M16C_EF_ACKE BIT(0)@@ -121,6 +158,14 @@#define M16C_EF_RCVE BIT(6)#define M16C_EF_TRE BIT(7) +/* Only Leaf-based devices can report M16C error factors, +* thus define our own error status flags for USBCANII +*/ +#define USBCAN_ERROR_STATE_NONE 0 +#define USBCAN_ERROR_STATE_TX_ERROR BIT(0) +#define USBCAN_ERROR_STATE_RX_ERROR BIT(1) +#define USBCAN_ERROR_STATE_BUSERROR BIT(2) +/* bittiming parameters */ #define KVASER_USB_TSEG1_MIN 1#define KVASER_USB_TSEG1_MAX 16@@ -137,7 +182,7 @@#define KVASER_CTRL_MODE_SELFRECEPTION 3#define KVASER_CTRL_MODE_OFF 4 -/* log message */ +/* Extended CAN identifier flag */ #define KVASER_EXTENDED_FRAME BIT(31)struct kvaser_msg_simple {@@ -148,30 +193,55 @@ struct kvaser_msg_simple {struct kvaser_msg_cardinfo {u8 tid;u8 nchannels; -__le32 serial_number; -__le32 padding; +union { +struct { +__le32 serial_number; +__le32 padding; + } __packed leaf0; +struct { +__le32 serial_number_low; +__le32 serial_number_high; + } __packed usbcan0; + } __packed;__le32 clock_resolution;__le32 mfgdate;u8 ean[8 ];u8 hw_revision; -u8 usb_hs_mode; -__le16 padding2; +union { +struct { +u8 usb_hs_mode; + } __packed leaf1; +struct { +u8 padding; + } __packed usbcan1; + } __packed; +__le16 padding; } __packed;struct kvaser_msg_cardinfo2 {u8 tid; -u8 channel; +u8 reserved;u8 pcb_id[24 ];__le32 oem_unlock_code; } __packed; -struct kvaser_msg_softinfo { +struct leaf_msg_softinfo {u8 tid; -u8 channel; +u8 padding0;__le32 sw_options;__le32 fw_version;__le16 max_outstanding_tx; -__le16 padding[9 ]; +__le16 padding1[9 ]; +} __packed; + +struct usbcan_msg_softinfo { +u8 tid; +u8 fw_name[5 ]; +__le16 max_outstanding_tx; +u8 padding[6 ]; +__le32 fw_version; +__le16 checksum; +__le16 sw_options; } __packed;struct kvaser_msg_busparams {@@ -188,36 +258,86 @@ struct kvaser_msg_tx_can {u8 channel;u8 tid;u8 msg[14 ]; -u8 padding; -u8 flags; +union { +struct { +u8 padding; +u8 flags; + } __packed leaf; +struct { +u8 flags; +u8 padding; + } __packed usbcan; + } __packed; +} __packed; + +struct kvaser_msg_rx_can_header { +u8 channel; +u8 flag; } __packed; -struct kvaser_msg_rx_can { +struct leaf_msg_rx_can {u8 channel;u8 flag; +__le16 time[3 ];u8 msg[14 ]; } __packed; -struct kvaser_msg_chip_state_event { +struct usbcan_msg_rx_can { +u8 channel; +u8 flag; + +u8 msg[14 ]; +__le16 time; +} __packed; + +struct leaf_msg_chip_state_event {u8 tid;u8 channel; +__le16 time[3 ];u8 tx_errors_count;u8 rx_errors_count; +u8 status;u8 padding[3 ]; } __packed; -struct kvaser_msg_tx_acknowledge { +struct usbcan_msg_chip_state_event { +u8 tid; +u8 channel; + +u8 tx_errors_count; +u8 rx_errors_count;
drivers/net/can/usb/kvaser_usb.c struct kvaser_msg_tx_can { · line 321
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+__le16 time; + +u8 status; +u8 padding[3 ]; +} __packed; + +struct kvaser_msg_tx_acknowledge_header { +u8 channel; +u8 tid; +};
Is this struct really needed? Can't you simply use leaf_msg_tx_acknowledge or usbcan_msg_tx_acknowledge structures to read the header.
Same for kvaser_msg_rx_can_header.
Quoted 734 lines
drivers/net/can/usb/kvaser_usb.c +352
-113+ +struct leaf_msg_tx_acknowledge {u8 channel;u8 tid; +__le16 time[3 ];u8 flags;u8 time_offset; } __packed; -struct kvaser_msg_error_event { +struct usbcan_msg_tx_acknowledge { +u8 channel; +u8 tid; + +__le16 time; +__le16 padding; +} __packed; + +struct leaf_msg_error_event {u8 tid;u8 flags;__le16 time[3 ];@@ -229,6 +349,18 @@ struct kvaser_msg_error_event {u8 error_factor; } __packed; +struct usbcan_msg_error_event { +u8 tid; +u8 padding; +u8 tx_errors_count_ch0; +u8 rx_errors_count_ch0; +u8 tx_errors_count_ch1; +u8 rx_errors_count_ch1; +u8 status_ch0; +u8 status_ch1; +__le16 time; +} __packed; +struct kvaser_msg_ctrl_mode {u8 tid;u8 channel;@@ -243,7 +375,7 @@ struct kvaser_msg_flush_queue {u8 padding[3 ]; } __packed; -struct kvaser_msg_log_message { +struct leaf_msg_log_message {u8 channel;u8 flags;__le16 time[3 ];@@ -260,19 +392,57 @@ struct kvaser_msg {struct kvaser_msg_simple simple;struct kvaser_msg_cardinfo cardinfo;struct kvaser_msg_cardinfo2 cardinfo2; -struct kvaser_msg_softinfo softinfo;struct kvaser_msg_busparams busparams; + +struct kvaser_msg_rx_can_header rx_can_header; +struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header; + +union { +struct leaf_msg_softinfo softinfo; +struct leaf_msg_rx_can rx_can; +struct leaf_msg_chip_state_event chip_state_event; +struct leaf_msg_tx_acknowledge tx_acknowledge; +struct leaf_msg_error_event error_event; +struct leaf_msg_log_message log_message; + } __packed leaf; + +union { +struct usbcan_msg_softinfo softinfo; +struct usbcan_msg_rx_can rx_can; +struct usbcan_msg_chip_state_event chip_state_event; +struct usbcan_msg_tx_acknowledge tx_acknowledge; +struct usbcan_msg_error_event error_event; + } __packed usbcan; +struct kvaser_msg_tx_can tx_can; -struct kvaser_msg_rx_can rx_can; -struct kvaser_msg_chip_state_event chip_state_event; -struct kvaser_msg_tx_acknowledge tx_acknowledge; -struct kvaser_msg_error_event error_event;struct kvaser_msg_ctrl_mode ctrl_mode;struct kvaser_msg_flush_queue flush_queue; -struct kvaser_msg_log_message log_message; } u; } __packed; +/* Summary of a kvaser error event, for a unified Leaf/Usbcan error +* handling. Some discrepancies between the two families exist: +* +* - USBCAN firmware does not report M16C "error factors" +* - USBCAN controllers has difficulties reporting if the raised error +* event is for ch0 or ch1. They leave such arbitration to the OS +* driver by letting it compare error counters with previous values +* and decide the error event's channel. Thus for USBCAN, the channel +* field is only advisory. +*/ +struct kvaser_error_summary { +u8 channel, status, txerr, rxerr; +union { +struct { +u8 error_factor; + } leaf; +struct { +u8 other_ch_status; +u8 error_state; + } usbcan; + }; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;@@ -288,6 +458,7 @@ struct kvaser_usb {u32 fw_version;unsigned int nchannels; +enum kvaser_usb_family family;bool rxinitdone;void *rxbuf[MAX_RX_URBS ];@@ -311,6 +482,7 @@ struct kvaser_usb_net_priv { };static const struct usb_device_id kvaser_usb_table[] = { +/* Leaf family IDs */ {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_DEVEL_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_LITE_PRODUCT_ID ) }, {USB_DEVICE (KVASER_VENDOR_ID ,USB_LEAF_PRO_PRODUCT_ID ),@@ -360,6 +532,17 @@ static const struct usb_device_id kvaser_usb_table[] = { .driver_info = KVASER_HAS_TXRX_ERRORS }, { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) }, { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) }, + +/* USBCANII family IDs */ + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID), + .driver_info = KVASER_HAS_TXRX_ERRORS }, + { } };MODULE_DEVICE_TABLE (usb, kvaser_usb_table);@@ -463,7 +646,14 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)if (err)return err; - dev->fw_version =le32_to_cpu (msg.u.softinfo.fw_version); +switch (dev->family) { +case KVASER_LEAF : + dev->fw_version =le32_to_cpu (msg.u.leaf.softinfo.fw_version); +break ; +case KVASER_USBCAN : + dev->fw_version =le32_to_cpu (msg.u.usbcan.softinfo.fw_version); +break ; + }return 0 ; }@@ -482,7 +672,9 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)return err; dev->nchannels = msg.u.cardinfo.nchannels; -if (dev->nchannels >MAX_NET_DEVICES ) +if ((dev->nchannels >MAX_NET_DEVICES ) || + (dev->family ==KVASER_USBCAN && + dev->nchannels >MAX_USBCAN_NET_DEVICES ))return -EINVAL ;return 0 ;@@ -496,8 +688,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,struct kvaser_usb_net_priv *priv;struct sk_buff *skb;struct can_frame *cf; -u8 channel = msg->u.tx_acknowledge.channel; -u8 tid = msg->u.tx_acknowledge.tid; +u8 channel, tid; + + channel = msg->u.tx_acknowledge_header.channel; + tid = msg->u.tx_acknowledge_header.tid;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,@@ -616,53 +810,24 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) }static void kvaser_usb_rx_error (const struct kvaser_usb *dev, -const struct kvaser_msg *msg) +struct kvaser_error_summary *es) {struct can_frame *cf;struct sk_buff *skb;struct net_device_stats *stats;struct kvaser_usb_net_priv *priv;unsigned int new_state; -u8 channel, status, txerr, rxerr, error_factor; - -switch (msg->id) { -case CMD_CAN_ERROR_EVENT : - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; -break ; -case CMD_LOG_MESSAGE : - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0 ]; - txerr = msg->u.log_message.data[2 ]; - rxerr = msg->u.log_message.data[3 ]; - error_factor = msg->u.log_message.data[1 ]; -break ; -case CMD_CHIP_STATE_EVENT : - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor =0 ; -break ; -default : -dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , - msg->id); -return ; - } -if (channel >= dev->nchannels) { +if (es->channel >= dev->nchannels) {dev_err (dev->udev->dev.parent, -"Invalid channel number (%d)\n" , channel); +"Invalid channel number (%d)\n" , es->channel);return ; } - priv = dev->nets[channel]; + priv = dev->nets[es->channel]; stats = &priv->netdev->stats; -if (status &M16C_STATE_BUS_RESET ) { +if (es->status &M16C_STATE_BUS_RESET ) {kvaser_usb_unlink_tx_urbs (priv);return ; }@@ -675,9 +840,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, new_state = priv->can.state; -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (status &M16C_STATE_BUS_OFF ) { +if (es->status &M16C_STATE_BUS_OFF ) { cf->can_id |=CAN_ERR_BUSOFF ; priv->can.can_stats.bus_off++;@@ -687,12 +852,12 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,netif_carrier_off (priv->netdev); new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { + }else if (es->status &M16C_STATE_BUS_PASSIVE ) {if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es->txerr || es->rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else @@ -703,13 +868,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } new_state =CAN_STATE_ERROR_PASSIVE ; - } - -if (status ==M16C_STATE_BUS_ERROR ) { + }else if (es->status &M16C_STATE_BUS_ERROR ) {if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { + ((es->txerr >=96 ) || (es->rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es->txerr > es->rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ;@@ -723,7 +886,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } } -if (!status) { +if (!es->status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ;@@ -739,34 +902,48 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv->can.can_stats.restarts++; } -if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - - cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; - -if (error_factor &M16C_EF_ACKE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); -if (error_factor &M16C_EF_CRCE ) - cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | -CAN_ERR_PROT_LOC_CRC_DEL ); -if (error_factor &M16C_EF_FORME ) - cf->data[2 ] |=CAN_ERR_PROT_FORM ; -if (error_factor &M16C_EF_STFE ) - cf->data[2 ] |=CAN_ERR_PROT_STUFF ; -if (error_factor &M16C_EF_BITE0 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; -if (error_factor &M16C_EF_BITE1 ) - cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; -if (error_factor &M16C_EF_TRE ) - cf->data[2 ] |=CAN_ERR_PROT_TX ; +switch (dev->family) { +case KVASER_LEAF : +if (es->leaf.error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + + cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; + +if (es->leaf.error_factor &M16C_EF_ACKE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); +if (es->leaf.error_factor &M16C_EF_CRCE ) + cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ | +CAN_ERR_PROT_LOC_CRC_DEL ); +if (es->leaf.error_factor &M16C_EF_FORME ) + cf->data[2 ] |=CAN_ERR_PROT_FORM ; +if (es->leaf.error_factor &M16C_EF_STFE ) + cf->data[2 ] |=CAN_ERR_PROT_STUFF ; +if (es->leaf.error_factor &M16C_EF_BITE0 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; +if (es->leaf.error_factor &M16C_EF_BITE1 ) + cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; +if (es->leaf.error_factor &M16C_EF_TRE ) + cf->data[2 ] |=CAN_ERR_PROT_TX ; + } +break ; +case KVASER_USBCAN : +if (es->usbcan.error_state &USBCAN_ERROR_STATE_TX_ERROR ) + stats->tx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_RX_ERROR ) + stats->rx_errors++; +if (es->usbcan.error_state &USBCAN_ERROR_STATE_BUSERROR ) { + priv->can.can_stats.bus_error++; + cf->can_id |=CAN_ERR_BUSERROR ; + } +break ; } - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; + cf->data[6 ] = es->txerr; + cf->data[7 ] = es->rxerr; - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; priv->can.state = new_state;@@ -775,6 +952,124 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,netif_rx (skb); } +/* For USBCAN, report error to userspace iff the channels's errors counter +* has increased, or we're the only channel seeing a bus error state. +*/ +static void kvaser_usbcan_conditionally_rx_error (const struct kvaser_usb *dev, +struct kvaser_error_summary *es) +{ +struct kvaser_usb_net_priv *priv; +int channel; +bool report_error; + + channel = es->channel; +if (channel >= dev->nchannels) { +dev_err (dev->udev->dev.parent, +"Invalid channel number (%d)\n" , channel); +return ; + } + + priv = dev->nets[channel]; + report_error = false; + +if (es->txerr > priv->bec.txerr) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_TX_ERROR ; + report_error = true; + } +if (es->rxerr > priv->bec.rxerr) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_RX_ERROR ; + report_error = true; + } +if ((es->status &M16C_STATE_BUS_ERROR ) && + !(es->usbcan.other_ch_status &M16C_STATE_BUS_ERROR )) { + es->usbcan.error_state |=USBCAN_ERROR_STATE_BUSERROR ; + report_error = true; + } + +if (report_error) +kvaser_usb_rx_error (dev, es); +} + +static void kvaser_usbcan_rx_error (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = { }; + +switch (msg->id) { +/* Sometimes errors are sent as unsolicited chip state events */ +case CMD_CHIP_STATE_EVENT : + es.channel = msg->u.usbcan.chip_state_event.channel; + es.status = msg->u.usbcan.chip_state_event.status; + es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count; + es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count; +kvaser_usbcan_conditionally_rx_error (dev, &es); +break ; + +case CMD_CAN_ERROR_EVENT : + es.channel =0 ; + es.status = msg->u.usbcan.error_event.status_ch0; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch1; +kvaser_usbcan_conditionally_rx_error (dev, &es); + +/* The USBCAN firmware does not support more than 2 channels. +* Now that ch0 was checked, check if ch1 has any errors. +*/ +if (dev->nchannels ==MAX_USBCAN_NET_DEVICES ) { + es.channel =1 ; + es.status = msg->u.usbcan.error_event.status_ch1; + es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1; + es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1; + es.usbcan.other_ch_status = + msg->u.usbcan.error_event.status_ch0; +kvaser_usbcan_conditionally_rx_error (dev, &es); + } +break ; + +default : +dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , + msg->id); + } +} + +static void kvaser_leaf_rx_error (const struct kvaser_usb *dev, +const struct kvaser_msg *msg) +{ +struct kvaser_error_summary es = { }; + +switch (msg->id) { +case CMD_CAN_ERROR_EVENT : + es.channel = msg->u.leaf.error_event.channel; + es.status = msg->u.leaf.error_event.status; + es.txerr = msg->u.leaf.error_event.tx_errors_count; + es.rxerr = msg->u.leaf.error_event.rx_errors_count; + es.leaf.error_factor = msg->u.leaf.error_event.error_factor; +break ; +case CMD_LEAF_LOG_MESSAGE : + es.channel = msg->u.leaf.log_message.channel; + es.status = msg->u.leaf.log_message.data[0 ]; + es.txerr = msg->u.leaf.log_message.data[2 ]; + es.rxerr = msg->u.leaf.log_message.data[3 ]; + es.leaf.error_factor = msg->u.leaf.log_message.data[1 ]; +break ; +case CMD_CHIP_STATE_EVENT : + es.channel = msg->u.leaf.chip_state_event.channel; + es.status = msg->u.leaf.chip_state_event.status; + es.txerr = msg->u.leaf.chip_state_event.tx_errors_count; + es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count; + es.leaf.error_factor =0 ; +break ; +default : +dev_err (dev->udev->dev.parent,"Invalid msg id (%d)\n" , + msg->id); +return ; + } + +kvaser_usb_rx_error (dev, &es); +} +static void kvaser_usb_rx_can_err (const struct kvaser_usb_net_priv *priv,const struct kvaser_msg *msg) {@@ -782,16 +1077,16 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,struct sk_buff *skb;struct net_device_stats *stats = &priv->netdev->stats; -if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | +if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |MSG_FLAG_NERR )) {netdev_err (priv->netdev,"Unknow error (flags: 0x%02x)\n" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); stats->rx_errors++;return ; } -if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { +if (msg->u.rx_can_header.flag &MSG_FLAG_OVERRUN ) { stats->rx_over_errors++; stats->rx_errors++;@@ -817,7 +1112,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,struct can_frame *cf;struct sk_buff *skb;struct net_device_stats *stats; -u8 channel = msg->u.rx_can.channel; +u8 channel = msg->u.rx_can_header.channel; +const u8 *rx_msg;if (channel >= dev->nchannels) { dev_err(dev->udev->dev.parent,@@ -828,19 +1124,32 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; -if ((msg->u.rx_can.flag &MSG_FLAG_ERROR_FRAME ) && - (msg->id ==CMD_LOG_MESSAGE )) { -kvaser_usb_rx_error (dev, msg); +if ((msg->u.rx_can_header.flag &MSG_FLAG_ERROR_FRAME ) && + (dev->family ==KVASER_LEAF && msg->id ==CMD_LEAF_LOG_MESSAGE )) { +kvaser_leaf_rx_error (dev, msg);return ; - }else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | -MSG_FLAG_NERR | -MSG_FLAG_OVERRUN )) { + }else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME | +MSG_FLAG_NERR | +MSG_FLAG_OVERRUN )) {kvaser_usb_rx_can_err (priv, msg);return ; - }else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME ) { + }else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME ) {netdev_warn (priv->netdev,"Unhandled frame (flags: 0x%02x)" , - msg->u.rx_can.flag); + msg->u.rx_can_header.flag); +return ; + } + +switch (dev->family) { +case KVASER_LEAF : + rx_msg = msg->u.leaf.rx_can.msg; +break ; +case KVASER_USBCAN : + rx_msg = msg->u.usbcan.rx_can.msg; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family);return ; }@@ -850,38 +1159,37 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,return ; } -if (msg->id ==CMD_LOG_MESSAGE ) { - cf->can_id =le32_to_cpu (msg->u.log_message.id); +if (dev->family ==KVASER_LEAF && msg->id ==CMD_LEAF_LOG_MESSAGE ) { + cf->can_id =le32_to_cpu (msg->u.leaf.log_message.id);if (cf->can_id &KVASER_EXTENDED_FRAME ) cf->can_id &=CAN_EFF_MASK |CAN_EFF_FLAG ;else cf->can_id &=CAN_SFF_MASK ; - cf->can_dlc =get_can_dlc (msg->u.log_message.dlc); + cf->can_dlc =get_can_dlc (msg->u.leaf.log_message.dlc); -if (msg->u.log_message.flags &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.leaf.log_message.flags &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.log_message.data, +memcpy (cf->data, &msg->u.leaf.log_message.data, cf->can_dlc); }else { - cf->can_id = ((msg->u.rx_can.msg[0 ] &0x1f ) <<6 ) | - (msg->u.rx_can.msg[1 ] &0x3f ); + cf->can_id = ((rx_msg[0 ] &0x1f ) <<6 ) | (rx_msg[1 ] &0x3f );if (msg->id ==CMD_RX_EXT_MESSAGE ) { cf->can_id <<=18 ; - cf->can_id |= ((msg->u.rx_can.msg[2 ] &0x0f ) <<14 ) | - ((msg->u.rx_can.msg[3 ] &0xff ) <<6 ) | - (msg->u.rx_can.msg[4 ] &0x3f ); + cf->can_id |= ((rx_msg[2 ] &0x0f ) <<14 ) | + ((rx_msg[3 ] &0xff ) <<6 ) | + (rx_msg[4 ] &0x3f ); cf->can_id |=CAN_EFF_FLAG ; } - cf->can_dlc =get_can_dlc (msg->u.rx_can.msg[5 ]); + cf->can_dlc =get_can_dlc (rx_msg[5 ]); -if (msg->u.rx_can.flag &MSG_FLAG_REMOTE_FRAME ) +if (msg->u.rx_can_header.flag &MSG_FLAG_REMOTE_FRAME ) cf->can_id |=CAN_RTR_FLAG ;else -memcpy (cf->data, &msg->u.rx_can.msg[6 ], +memcpy (cf->data, &rx_msg[6 ], cf->can_dlc); }@@ -944,21 +1252,35 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,case CMD_RX_STD_MESSAGE :case CMD_RX_EXT_MESSAGE : -case CMD_LOG_MESSAGE : +kvaser_usb_rx_can_msg (dev, msg); +break ; + +case CMD_LEAF_LOG_MESSAGE : +if (dev->family !=KVASER_LEAF ) + goto warn;kvaser_usb_rx_can_msg (dev, msg);break ;case CMD_CHIP_STATE_EVENT :case CMD_CAN_ERROR_EVENT : -kvaser_usb_rx_error (dev, msg); +if (dev->family ==KVASER_LEAF ) +kvaser_leaf_rx_error (dev, msg); +else +kvaser_usbcan_rx_error (dev, msg);break ;case CMD_TX_ACKNOWLEDGE :kvaser_usb_tx_acknowledge (dev, msg);break ; +/* Ignored messages */ +case CMD_USBCAN_CLOCK_OVERFLOW_EVENT : +if (dev->family !=KVASER_USBCAN ) + goto warn; +break ; +default : -dev_warn (dev->udev->dev.parent, +warn:dev_warn (dev->udev->dev.parent,"Unhandled message (%d)\n" , msg->id);break ; }@@ -1178,7 +1500,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev) dev->rxbuf[i], dev->rxbuf_dma[i]); -for (i =0 ; i <MAX_NET_DEVICES ; i++) { +for (i =0 ; i < dev->nchannels; i++) {struct kvaser_usb_net_priv *priv = dev->nets[i];if (priv)@@ -1286,6 +1608,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,struct kvaser_msg *msg;int i, err;int ret =NETDEV_TX_OK ; +uint8_t *msg_tx_can_flags;if (can_dropped_invalid_skb (netdev, skb))return NETDEV_TX_OK ;@@ -1307,9 +1630,23 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, msg = buf; msg->len =MSG_HEADER_LEN +sizeof (struct kvaser_msg_tx_can ); - msg->u.tx_can.flags =0 ; msg->u.tx_can.channel = priv->channel; +switch (dev->family) { +case KVASER_LEAF : + msg_tx_can_flags = &msg->u.tx_can.leaf.flags; +break ; +case KVASER_USBCAN : + msg_tx_can_flags = &msg->u.tx_can.usbcan.flags; +break ; +default : +dev_err (dev->udev->dev.parent, +"Invalid device family (%d)\n" , dev->family); + goto releasebuf; + } + + *msg_tx_can_flags =0 ; +if (cf->can_id &CAN_EFF_FLAG ) { msg->id =CMD_TX_EXT_MESSAGE ; msg->u.tx_can.msg[0 ] = (cf->can_id >>24 ) &0x1f ;@@ -1327,7 +1664,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,memcpy (&msg->u.tx_can.msg[6 ], cf->data, cf->can_dlc);if (cf->can_id &CAN_RTR_FLAG ) - msg->u.tx_can.flags |=MSG_FLAG_REMOTE_FRAME ; + *msg_tx_can_flags |=MSG_FLAG_REMOTE_FRAME ;for (i =0 ; i <ARRAY_SIZE (priv->tx_contexts); i++) {if (priv->tx_contexts[i].echo_index ==MAX_TX_URBS ) {@@ -1596,6 +1933,17 @@ static int kvaser_usb_probe(struct usb_interface *intf,if (!dev)return -ENOMEM ; +if (kvaser_is_leaf (id)) { + dev->family =KVASER_LEAF ; + }else if (kvaser_is_usbcan (id)) { + dev->family =KVASER_USBCAN ; + }else { +dev_err (&intf->dev, +"Product ID (%d) does not belong to any known Kvaser USB family" , + id->idProduct); +return -ENODEV ; + } + err =kvaser_usb_get_endpoints (intf, &dev->bulk_in, &dev->bulk_out);if (err) {dev_err (&intf->dev,"Cannot get usb endpoint(s)" );Signature · 1 line
1.9.1
Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
Hi!
Quoted 5 lines · Olivier Sobrie
Hello,
Quoted 2 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
...
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c line 132
Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c +2
-1@@ -98,7 +128,13 @@#define CMD_START_CHIP_REPLY 27#define CMD_STOP_CHIP 28#define CMD_STOP_CHIP_REPLY 29 -#define CMD_GET_CARD_INFO2 32 +#define CMD_READ_CLOCK 30 +#define CMD_READ_CLOCK_REPLY 31These two defines are not used.
They were added for completeness: the only gap in our continuous sequence of command IDs from 12 to 39 ;-) No big deal, to be removed in the next submission.
...
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c struct kvaser_msg_tx_can { · line 321
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +5
-0+ +struct kvaser_msg_tx_acknowledge_header { +u8 channel; +u8 tid; +};Is this struct really needed? Can't you simply use
leaf_msg_tx_acknowledgeorusbcan_msg_tx_acknowledgestructures to read the header.
Same forkvaser_msg_rx_can_header.
They're added to ensure type-safety throughout the code. Basically they're the common part of a command that has different wire format between the Leaf and the USBCan, but share a common header. Such notation was only added when it was strictly necessary.
For example, there are three functions where 'rx_can_header' is referenced in the driver, and one function where 'tx_acknowledge_header' is referenced. Without such header structure, I'll have to sprinkle 3 to 4 extra blocks of:
switch (dev->family) {
case KVASER_LEAF:
case KVASER_USBCAN:
}which would be _really_ ugly. The *_header notation ensures that, in the body of each function, we're accessing the fields in a very safe manner.
Thanks,
Darwish
Marc Kleine-Budde
maintainerRe: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
Quoted 50 lines · Ahmed S. Darwish
Hi!
Quoted 5 lines · Olivier Sobrie
Hello,
Quoted 2 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
...
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c line 132
Quoted 7 lines
drivers/net/can/usb/kvaser_usb.c +2
-1@@ -98,7 +128,13 @@#define CMD_START_CHIP_REPLY 27#define CMD_STOP_CHIP 28#define CMD_STOP_CHIP_REPLY 29 -#define CMD_GET_CARD_INFO2 32 +#define CMD_READ_CLOCK 30 +#define CMD_READ_CLOCK_REPLY 31These two defines are not used.
They were added for completeness: the only gap in our continuous sequence of command IDs from 12 to 39 ;-) No big deal, to be removed in the next submission.
...
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c struct kvaser_msg_tx_can { · line 321
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +5
-0+ +struct kvaser_msg_tx_acknowledge_header { +u8 channel; +u8 tid; +};Is this struct really needed? Can't you simply use
leaf_msg_tx_acknowledgeorusbcan_msg_tx_acknowledgestructures to read the header.
Same forkvaser_msg_rx_can_header.They're added to ensure type-safety throughout the code. Basically they're the common part of a command that has different wire format between the Leaf and the USBCan, but share a common header. Such notation was only added when it was strictly necessary.
For example, there are three functions where '
rx_can_header' is referenced in the driver, and one function where 'tx_acknowledge_header' is referenced. Without such header structure, I'll have to sprinkle 3 to 4 extra blocks of:
Quoted 8 lines
switch (dev->family) { case KVASER_LEAF: case KVASER_USBCAN: }which would be _really_ ugly. The
*_headernotation ensures that, in the body of each function, we're accessing the fields in a very safe manner.
+1 Keep it as it is.
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Marc Kleine-Budde
maintainerRe: [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
In reply to Ahmed S. DarwishQuoted 4 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
Let the error counters be more accurate in case of Out of Memory conditions.
Please have a look at kvaser_usb_rx_error(), the whole state handling is omitted in case of OOM.
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
Quoted 9 lines · Marc Kleine-Budde
Quoted 4 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
Let the error counters be more accurate in case of Out of Memory conditions.
Please have a look at
kvaser_usb_rx_error(), the whole state handling is omitted in case of OOM.
I see. Regarding kvaser_usb_rx_error(), would something like below patch be acceptable?
Kindly note that separating recording interface state from error frame packet building leads to duplication of a good number of if-conditions. Meanwhile, it truly saves _all_ of the possible state before any ENOMEM -- the correct thing to do.
Another solution was to allocate the can frame on the stack, and thus avoiding any code duplication. But this only leads to calls of "kvaser_usb_simple_msg_async", which can fail with -ENOMEM by itself, returning to the very same problem again.
If the patch is acceptable, I'll rebase my USBCAN-II driver above it and re-submit the series (minus the merged patch).
Thanks,
-->
[ Patch is build-tested, but not _fully_ run-time tested.
It's based on linux-can/testing commit d642b49f6d84b94bd "can: kvaser_usb: Don't dereference skb after a netif_rx" ]
Subject: [PATCH] can: kvaser_usb: Update net interface state
before exiting on OOM
From: Ahmed S. Darwish <[email protected]>
Let the network interface can bus state and error counters be more accurate in case of Out of Memory conditions.
--- drivers/net/can/usb/kvaser_usb.c | 182 +++++++++++++++++++++++---------------- 1 file changed, 106 insertions(+), 76 deletions(-)
drivers/net/can/usb/kvaser_usb.c +106 -76
@@ -273,6 +273,10 @@ struct kvaser_msg { } u; } __packed; +struct kvaser_usb_error_summary { +u8 channel, status, txerr, rxerr, error_factor; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;
@@ -615,6 +619,57 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index =MAX_TX_URBS ; } +static void kvaser_usb_rx_error_update_state (struct kvaser_usb_net_priv *priv, +const struct kvaser_usb_error_summary *es) +{ +struct net_device_stats *stats; +unsigned int new_state; + + stats = &priv->netdev->stats; + new_state = priv->can.state; + +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); + +if (es->status &M16C_STATE_BUS_OFF ) { + priv->can.can_stats.bus_off++; + new_state =CAN_STATE_BUS_OFF ; + }else if (es->status &M16C_STATE_BUS_PASSIVE ) { +if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { + priv->can.can_stats.error_passive++; + } + new_state =CAN_STATE_ERROR_PASSIVE ; + } + +if (es->status ==M16C_STATE_BUS_ERROR ) { +if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && + ((es->txerr >=96 ) || (es->rxerr >=96 ))) { + priv->can.can_stats.error_warning++; + new_state =CAN_STATE_ERROR_WARNING ; + }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { + new_state =CAN_STATE_ERROR_ACTIVE ; + } + } + +if (!es->status) { + new_state =CAN_STATE_ERROR_ACTIVE ; + } + +if (priv->can.restart_ms && + (priv->can.state >=CAN_STATE_BUS_OFF ) && + (new_state <CAN_STATE_BUS_OFF )) { + priv->can.can_stats.restarts++; + } + +if (es->error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + } + + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; + priv->can.state = new_state; +} +static void kvaser_usb_rx_error (const struct kvaser_usb *dev,const struct kvaser_msg *msg) {
@@ -622,30 +677,30 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,struct sk_buff *skb;struct net_device_stats *stats;struct kvaser_usb_net_priv *priv; -unsigned int new_state; -u8 channel, status, txerr, rxerr, error_factor; +struct kvaser_usb_error_summary es = { }; +unsigned int new_state, old_state;switch (msg->id) {case CMD_CAN_ERROR_EVENT : - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; + es.channel = msg->u.error_event.channel; + es.status = msg->u.error_event.status; + es.txerr = msg->u.error_event.tx_errors_count; + es.rxerr = msg->u.error_event.rx_errors_count; + es.error_factor = msg->u.error_event.error_factor;break ;case CMD_LOG_MESSAGE : - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0 ]; - txerr = msg->u.log_message.data[2 ]; - rxerr = msg->u.log_message.data[3 ]; - error_factor = msg->u.log_message.data[1 ]; + es.channel = msg->u.log_message.channel; + es.status = msg->u.log_message.data[0 ]; + es.txerr = msg->u.log_message.data[2 ]; + es.rxerr = msg->u.log_message.data[3 ]; + es.error_factor = msg->u.log_message.data[1 ];break ;case CMD_CHIP_STATE_EVENT : - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor =0 ; + es.channel = msg->u.chip_state_event.channel; + es.status = msg->u.chip_state_event.status; + es.txerr = msg->u.chip_state_event.tx_errors_count; + es.rxerr = msg->u.chip_state_event.rx_errors_count; + es.error_factor =0 ;break ;default : dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
@@ -653,122 +708,97 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,return ; } -if (channel >= dev->nchannels) { +if (es.channel >= dev->nchannels) {dev_err (dev->udev->dev.parent, -"Invalid channel number (%d)\n" , channel); +"Invalid channel number (%d)\n" , es.channel);return ; } - priv = dev->nets[channel]; + priv = dev->nets[es.channel]; stats = &priv->netdev->stats; -if (status &M16C_STATE_BUS_RESET ) { +if (es.status &M16C_STATE_BUS_RESET ) {kvaser_usb_unlink_tx_urbs (priv);return ; } + old_state = priv->can.state; +kvaser_usb_rx_error_update_state (priv, &es); + new_state = priv->can.state; + skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;return ; } - new_state = priv->can.state; - -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); - -if (status &M16C_STATE_BUS_OFF ) { - cf->can_id |=CAN_ERR_BUSOFF ; - - priv->can.can_stats.bus_off++; +if (es.status &M16C_STATE_BUS_OFF ) {if (!priv->can.restart_ms)kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); -netif_carrier_off (priv->netdev); - new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { -if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { + cf->can_id |=CAN_ERR_BUSOFF ; + }else if (es.status &M16C_STATE_BUS_PASSIVE ) { +if (old_state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es.txerr || es.rxerr) + cf->data[1 ] = (es.txerr > es.rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else cf->data[1 ] =CAN_ERR_CRTL_TX_PASSIVE |CAN_ERR_CRTL_RX_PASSIVE ; - - priv->can.can_stats.error_passive++; } - - new_state =CAN_STATE_ERROR_PASSIVE ; } -if (status ==M16C_STATE_BUS_ERROR ) { -if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { +if (es.status ==M16C_STATE_BUS_ERROR ) { +if ((old_state <CAN_STATE_ERROR_WARNING ) && + ((es.txerr >=96 ) || (es.rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es.txerr > es.rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ; - - priv->can.can_stats.error_warning++; - new_state =CAN_STATE_ERROR_WARNING ; - }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { + }else if (old_state >CAN_STATE_ERROR_ACTIVE ) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - - new_state =CAN_STATE_ERROR_ACTIVE ; } } -if (!status) { +if (!es.status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - - new_state =CAN_STATE_ERROR_ACTIVE ; }if (priv->can.restart_ms && - (priv->can.state >=CAN_STATE_BUS_OFF ) && + (old_state >=CAN_STATE_BUS_OFF ) && (new_state <CAN_STATE_BUS_OFF )) { cf->can_id |=CAN_ERR_RESTARTED ;netif_carrier_on (priv->netdev); - - priv->can.can_stats.restarts++; } -if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - +if (es.error_factor) { cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; -if (error_factor &M16C_EF_ACKE ) +if (es.error_factor &M16C_EF_ACKE ) cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); -if (error_factor &M16C_EF_CRCE ) +if (es.error_factor &M16C_EF_CRCE ) cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ |CAN_ERR_PROT_LOC_CRC_DEL ); -if (error_factor &M16C_EF_FORME ) +if (es.error_factor &M16C_EF_FORME ) cf->data[2 ] |=CAN_ERR_PROT_FORM ; -if (error_factor &M16C_EF_STFE ) +if (es.error_factor &M16C_EF_STFE ) cf->data[2 ] |=CAN_ERR_PROT_STUFF ; -if (error_factor &M16C_EF_BITE0 ) +if (es.error_factor &M16C_EF_BITE0 ) cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; -if (error_factor &M16C_EF_BITE1 ) +if (es.error_factor &M16C_EF_BITE1 ) cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; -if (error_factor &M16C_EF_TRE ) +if (es.error_factor &M16C_EF_TRE ) cf->data[2 ] |=CAN_ERR_PROT_TX ; } - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; - - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; - - priv->can.state = new_state; + cf->data[6 ] = es.txerr; + cf->data[7 ] = es.rxerr; stats->rx_packets++; stats->rx_bytes += cf->can_dlc;
@@ -792,6 +822,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, }if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { + stats->rx_over_errors++; + stats->rx_errors++; + skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;
@@ -801,9 +834,6 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, cf->can_id |=CAN_ERR_CRTL ; cf->data[1 ] =CAN_ERR_CRTL_RX_OVERFLOW ; - stats->rx_over_errors++; - stats->rx_errors++; - stats->rx_packets++; stats->rx_bytes += cf->can_dlc;netif_rx (skb);
Signature · 1 line
1.9.1
Marc Kleine-Budde
maintainerRe: [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
Quoted 20 lines · Ahmed S. Darwish
Quoted 9 lines · Marc Kleine-Budde
Quoted 4 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
Let the error counters be more accurate in case of Out of Memory conditions.
Please have a look at
kvaser_usb_rx_error(), the whole state handling is omitted in case of OOM.I see. Regarding
kvaser_usb_rx_error(), would something like below patch be acceptable?Kindly note that separating recording interface state from error frame packet building leads to duplication of a good number of if-conditions. Meanwhile, it truly saves _all_ of the possible state before any ENOMEM -- the correct thing to do.
Quoted 8 lines
Another solution was to allocate the can frame on the stack, and thus avoiding any code duplication. But this only leads to calls of "
kvaser_usb_simple_msg_async", which can fail with-ENOMEMby itself, returning to the very same problem again.If the patch is acceptable, I'll rebase my USBCAN-II driver above it and re-submit the series (minus the merged patch).
Looks good from my point of view, stats and state are handled independent of the error skb.
Andri can you have a look at the state handling itself?
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
In reply to Ahmed S. DarwishSee comments below.
Quoting Ahmed S. Darwish (2015-01-12 20:36:50)
...
Quoted 36 lines
[ Patch is build-tested, but not _fully_ run-time tested.
It's based on linux-can/testing commit
d642b49f6d84b94bd"can:kvaser_usb: Don't dereference skb after anetif_rx" ]Subject: [PATCH] can:
kvaser_usb: Update net interface state
before exiting on OOMFrom: Ahmed S. Darwish <[email protected]>
Let the network interface can bus state and error counters be more accurate in case of Out of Memory conditions.
Suggested-by Marc Kleine-Budde <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 182 +++++++++++++++++++++++---------------- 1 file changed, 106 insertions(+), 76 deletions(-)drivers/net/can/usb/kvaser_usb.c +4
-0@@ -273,6 +273,10 @@ struct kvaser_msg { } u; } __packed; +struct kvaser_usb_error_summary { +u8 channel, status, txerr, rxerr, error_factor; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 621
Quoted 3 lines
drivers/net/can/usb/kvaser_usb.c +0
-0@@ -615,6 +619,57 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index =MAX_TX_URBS ; }
This function is doing some things that are now be handled by can_change_state(). You can make your state handling code a lot shorter by using it.
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 633
Quoted 12 lines
drivers/net/can/usb/kvaser_usb.c +12
-0+static void kvaser_usb_rx_error_update_state (struct kvaser_usb_net_priv *priv, +const struct kvaser_usb_error_summary *es) +{ +struct net_device_stats *stats; +unsigned int new_state; + + stats = &priv->netdev->stats; + new_state = priv->can.state; + +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); + +if (es->status &M16C_STATE_BUS_OFF ) {
can_change_state() updates the state stats.
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 637
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+ priv->can.can_stats.bus_off++; + new_state =CAN_STATE_BUS_OFF ; + }else if (es->status &M16C_STATE_BUS_PASSIVE ) { +if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) {
See last comment.
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 645
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c +8
-0+ priv->can.can_stats.error_passive++; + } + new_state =CAN_STATE_ERROR_PASSIVE ; + } + +if (es->status ==M16C_STATE_BUS_ERROR ) { +if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && + ((es->txerr >=96 ) || (es->rxerr >=96 ))) {
Same as above.
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+ priv->can.can_stats.error_warning++; + new_state =CAN_STATE_ERROR_WARNING ; + }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { + new_state =CAN_STATE_ERROR_ACTIVE ;
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 659
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+ } + } + +if (!es->status) { + new_state =CAN_STATE_ERROR_ACTIVE ; + } + +if (priv->can.restart_ms && + (priv->can.state >=CAN_STATE_BUS_OFF ) && + (new_state <CAN_STATE_BUS_OFF )) {
This is NOT in can_change_state(). Keep it.
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 669
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+ priv->can.can_stats.restarts++; + } + +if (es->error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + } + + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr;
can_change_state() does this too.
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +3
-0+ priv->can.state = new_state; +} +static void kvaser_usb_rx_error (const struct kvaser_usb *dev,const struct kvaser_msg *msg)
...
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 723
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c +1
-1-if (status &M16C_STATE_BUS_RESET ) { +if (es.status &M16C_STATE_BUS_RESET ) {kvaser_usb_unlink_tx_urbs (priv);return ; }
OK, maybe we need to move "priv->can.state = new_state" out of can_change_state(). See explanation below.
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 733
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+ old_state = priv->can.state; +kvaser_usb_rx_error_update_state (priv, &es); + new_state = priv->can.state; + skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;return ; }
You should be able to replace this:
Quoted 49 lines
drivers/net/can/usb/kvaser_usb.c +10
-22- new_state = priv->can.state; - -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); - -if (status &M16C_STATE_BUS_OFF ) { - cf->can_id |=CAN_ERR_BUSOFF ; - - priv->can.can_stats.bus_off++; +if (es.status &M16C_STATE_BUS_OFF ) {if (!priv->can.restart_ms)kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); -netif_carrier_off (priv->netdev); - new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { -if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { + cf->can_id |=CAN_ERR_BUSOFF ; + }else if (es.status &M16C_STATE_BUS_PASSIVE ) { +if (old_state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es.txerr || es.rxerr) + cf->data[1 ] = (es.txerr > es.rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else cf->data[1 ] =CAN_ERR_CRTL_TX_PASSIVE |CAN_ERR_CRTL_RX_PASSIVE ; - - priv->can.can_stats.error_passive++; } - - new_state =CAN_STATE_ERROR_PASSIVE ; } -if (status ==M16C_STATE_BUS_ERROR ) { -if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { +if (es.status ==M16C_STATE_BUS_ERROR ) { +if ((old_state <CAN_STATE_ERROR_WARNING ) && + ((es.txerr >=96 ) || (es.rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es.txerr > es.rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ;
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 765
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +1
-6- - priv->can.can_stats.error_warning++; - new_state =CAN_STATE_ERROR_WARNING ; - }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { + }else if (old_state >CAN_STATE_ERROR_ACTIVE ) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - - new_state =CAN_STATE_ERROR_ACTIVE ; }
With something like:
if(new_state != old_state)
{
tx_state = get_tx_state(...);
rx_state = get_rx_state(...);
can_change_state(priv, cf, tx_state, rx_state);
if(new_state == CAN_STATE_BUS_OFF)
bus_off(...);
}drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 771
Quoted 10 lines
}drivers/net/can/usb/kvaser_usb.c +1
-3-if (!status) { +if (!es.status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - - new_state =CAN_STATE_ERROR_ACTIVE ; }
...
I suggest that you create functions named kvaser_get_tx_state and kvaser_get_rx_state (or one function that returns to argument if that suits you better) based on kvaser_usb_rx_error_update_state.
Because you want to assign the netlink state before you do the skb alloc, you need to make a copy of the netlink state before you change it and reassign the old state to the netlink structure after the alloc succeeds. This is because can_change_state() relies on priv->can.state for the "current state". This is a hack. Perhaps we need to split up can_change_state().
See:
http://article.gmane.org/gmane.linux.can/7164
http://article.gmane.org/gmane.linux.can/7162
http://article.gmane.org/gmane.linux.can/7163
http://article.gmane.org/gmane.linux.can/7167
Best regards,
Andri Yngvason
Re: [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
Quoted 210 lines · Andri Yngvason
See comments below.
Quoting Ahmed S. Darwish (2015-01-12 20:36:50)
...Quoted 36 lines
[ Patch is build-tested, but not _fully_ run-time tested.
It's based on linux-can/testing commit
d642b49f6d84b94bd"can:kvaser_usb: Don't dereference skb after anetif_rx" ]Subject: [PATCH] can:
kvaser_usb: Update net interface state
before exiting on OOMFrom: Ahmed S. Darwish <[email protected]>
Let the network interface can bus state and error counters be more accurate in case of Out of Memory conditions.
Suggested-by Marc Kleine-Budde <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 182 +++++++++++++++++++++++---------------- 1 file changed, 106 insertions(+), 76 deletions(-)drivers/net/can/usb/kvaser_usb.c +4
-0@@ -273,6 +273,10 @@ struct kvaser_msg { } u; } __packed; +struct kvaser_usb_error_summary { +u8 channel, status, txerr, rxerr, error_factor; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 621
Quoted 3 lines
drivers/net/can/usb/kvaser_usb.c +0
-0@@ -615,6 +619,57 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index =MAX_TX_URBS ; }This function is doing some things that are now be handled by
can_change_state(). You can make your state handling code a lot shorter by using it.drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 633
Quoted 12 lines
drivers/net/can/usb/kvaser_usb.c +12
-0+static void kvaser_usb_rx_error_update_state (struct kvaser_usb_net_priv *priv, +const struct kvaser_usb_error_summary *es) +{ +struct net_device_stats *stats; +unsigned int new_state; + + stats = &priv->netdev->stats; + new_state = priv->can.state; + +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); + +if (es->status &M16C_STATE_BUS_OFF ) {
can_change_state()updates the state stats.drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 637
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+ priv->can.can_stats.bus_off++; + new_state =CAN_STATE_BUS_OFF ; + }else if (es->status &M16C_STATE_BUS_PASSIVE ) { +if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) {See last comment.
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 645
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c +8
-0+ priv->can.can_stats.error_passive++; + } + new_state =CAN_STATE_ERROR_PASSIVE ; + } + +if (es->status ==M16C_STATE_BUS_ERROR ) { +if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && + ((es->txerr >=96 ) || (es->rxerr >=96 ))) {Same as above.
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+ priv->can.can_stats.error_warning++; + new_state =CAN_STATE_ERROR_WARNING ; + }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { + new_state =CAN_STATE_ERROR_ACTIVE ;drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 659
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+ } + } + +if (!es->status) { + new_state =CAN_STATE_ERROR_ACTIVE ; + } + +if (priv->can.restart_ms && + (priv->can.state >=CAN_STATE_BUS_OFF ) && + (new_state <CAN_STATE_BUS_OFF )) {This is NOT in
can_change_state(). Keep it.drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 669
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +10
-0+ priv->can.can_stats.restarts++; + } + +if (es->error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + } + + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr;
can_change_state()does this too.Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +3
-0+ priv->can.state = new_state; +} +static void kvaser_usb_rx_error (const struct kvaser_usb *dev,const struct kvaser_msg *msg)...
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 723
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c +1
-1-if (status &M16C_STATE_BUS_RESET ) { +if (es.status &M16C_STATE_BUS_RESET ) {kvaser_usb_unlink_tx_urbs (priv);return ; }OK, maybe we need to move "
priv->can.state=new_state" out ofcan_change_state(). See explanation below.drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 733
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +4
-0+ old_state = priv->can.state; +kvaser_usb_rx_error_update_state (priv, &es); + new_state = priv->can.state; + skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;return ; }You should be able to replace this:
Quoted 49 lines
drivers/net/can/usb/kvaser_usb.c +10
-22- new_state = priv->can.state; - -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); - -if (status &M16C_STATE_BUS_OFF ) { - cf->can_id |=CAN_ERR_BUSOFF ; - - priv->can.can_stats.bus_off++; +if (es.status &M16C_STATE_BUS_OFF ) {if (!priv->can.restart_ms)kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); -netif_carrier_off (priv->netdev); - new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { -if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { + cf->can_id |=CAN_ERR_BUSOFF ; + }else if (es.status &M16C_STATE_BUS_PASSIVE ) { +if (old_state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es.txerr || es.rxerr) + cf->data[1 ] = (es.txerr > es.rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else cf->data[1 ] =CAN_ERR_CRTL_TX_PASSIVE |CAN_ERR_CRTL_RX_PASSIVE ; - - priv->can.can_stats.error_passive++; } - - new_state =CAN_STATE_ERROR_PASSIVE ; } -if (status ==M16C_STATE_BUS_ERROR ) { -if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { +if (es.status ==M16C_STATE_BUS_ERROR ) { +if ((old_state <CAN_STATE_ERROR_WARNING ) && + ((es.txerr >=96 ) || (es.rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es.txerr > es.rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ;drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 765
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +1
-6- - priv->can.can_stats.error_warning++; - new_state =CAN_STATE_ERROR_WARNING ; - }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { + }else if (old_state >CAN_STATE_ERROR_ACTIVE ) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - - new_state =CAN_STATE_ERROR_ACTIVE ; }With something like:
if(new_state != old_state) { tx_state = get_tx_state(...); rx_state = get_rx_state(...); can_change_state(priv, cf, tx_state, rx_state); if(new_state == CAN_STATE_BUS_OFF) bus_off(...); }drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 771
Quoted 10 lines
}drivers/net/can/usb/kvaser_usb.c +1
-3-if (!status) { +if (!es.status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - - new_state =CAN_STATE_ERROR_ACTIVE ; }...
I suggest that you create functions named
kvaser_get_tx_stateandkvaser_get_rx_state(or one function that returns to argument if that suits you better) based onkvaser_usb_rx_error_update_state.
Quoted 6 lines
Because you want to assign the netlink state before you do the skb alloc, you need to make a copy of the netlink state before you change it and reassign the old state to the netlink structure after the alloc succeeds. This is because
can_change_state()relies onpriv->can.statefor the "current state". This is a hack. Perhaps we need to split upcan_change_state().
Thanks a lot Andri for your detailed review! I've included changes, similar in spirit to the above, in the next patch series.
Regards,
Darwish
Quoted 8 lines
See:
http://article.gmane.org/gmane.linux.can/7164
http://article.gmane.org/gmane.linux.can/7162
http://article.gmane.org/gmane.linux.can/7163
http://article.gmane.org/gmane.linux.can/7167Best regards,
Andri Yngvason
PATCH v5 1/5 can: kvaser_usb: Update net interface state before exiting on OOM
In reply to Ahmed S. DarwishFrom: Ahmed S. Darwish <[email protected]>
Update all of the can interface's state and error counters before trying any skb allocation that can actually fail with -ENOMEM.
--- drivers/net/can/usb/kvaser_usb.c | 182 +++++++++++++++++++++++---------------- 1 file changed, 106 insertions(+), 76 deletions(-)
drivers/net/can/usb/kvaser_usb.c +106 -76
@@ -273,6 +273,10 @@ struct kvaser_msg { } u; } __packed; +struct kvaser_usb_error_summary { +u8 channel, status, txerr, rxerr, error_factor; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;
@@ -615,6 +619,55 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index =MAX_TX_URBS ; } +static void kvaser_usb_rx_error_update_can_state (struct kvaser_usb_net_priv *priv, +const struct kvaser_usb_error_summary *es) +{ +struct net_device_stats *stats; +enum can_state new_state; + + stats = &priv->netdev->stats; + new_state = priv->can.state; + +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); + +if (es->status &M16C_STATE_BUS_OFF ) { + priv->can.can_stats.bus_off++; + new_state =CAN_STATE_BUS_OFF ; + }else if (es->status &M16C_STATE_BUS_PASSIVE ) { +if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) + priv->can.can_stats.error_passive++; + new_state =CAN_STATE_ERROR_PASSIVE ; + } + +if (es->status ==M16C_STATE_BUS_ERROR ) { +if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && + ((es->txerr >=96 ) || (es->rxerr >=96 ))) { + priv->can.can_stats.error_warning++; + new_state =CAN_STATE_ERROR_WARNING ; + }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { + new_state =CAN_STATE_ERROR_ACTIVE ; + } + } + +if (!es->status) + new_state =CAN_STATE_ERROR_ACTIVE ; + +if (priv->can.restart_ms && + (priv->can.state >=CAN_STATE_BUS_OFF ) && + (new_state <CAN_STATE_BUS_OFF )) { + priv->can.can_stats.restarts++; + } + +if (es->error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + } + + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; + priv->can.state = new_state; +} +static void kvaser_usb_rx_error (const struct kvaser_usb *dev,const struct kvaser_msg *msg) {
@@ -622,30 +675,30 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,struct sk_buff *skb;struct net_device_stats *stats;struct kvaser_usb_net_priv *priv; -unsigned int new_state; -u8 channel, status, txerr, rxerr, error_factor; +struct kvaser_usb_error_summary es = { }; +enum can_state old_state;switch (msg->id) {case CMD_CAN_ERROR_EVENT : - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; + es.channel = msg->u.error_event.channel; + es.status = msg->u.error_event.status; + es.txerr = msg->u.error_event.tx_errors_count; + es.rxerr = msg->u.error_event.rx_errors_count; + es.error_factor = msg->u.error_event.error_factor;break ;case CMD_LOG_MESSAGE : - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0 ]; - txerr = msg->u.log_message.data[2 ]; - rxerr = msg->u.log_message.data[3 ]; - error_factor = msg->u.log_message.data[1 ]; + es.channel = msg->u.log_message.channel; + es.status = msg->u.log_message.data[0 ]; + es.txerr = msg->u.log_message.data[2 ]; + es.rxerr = msg->u.log_message.data[3 ]; + es.error_factor = msg->u.log_message.data[1 ];break ;case CMD_CHIP_STATE_EVENT : - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor =0 ; + es.channel = msg->u.chip_state_event.channel; + es.status = msg->u.chip_state_event.status; + es.txerr = msg->u.chip_state_event.tx_errors_count; + es.rxerr = msg->u.chip_state_event.rx_errors_count; + es.error_factor =0 ;break ;default : dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
@@ -653,122 +706,99 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,return ; } -if (channel >= dev->nchannels) { +if (es.channel >= dev->nchannels) {dev_err (dev->udev->dev.parent, -"Invalid channel number (%d)\n" , channel); +"Invalid channel number (%d)\n" , es.channel);return ; } - priv = dev->nets[channel]; + priv = dev->nets[es.channel]; stats = &priv->netdev->stats; -if (status &M16C_STATE_BUS_RESET ) { +if (es.status &M16C_STATE_BUS_RESET ) {kvaser_usb_unlink_tx_urbs (priv);return ; } +/* Update all of the can interface's state and error counters before +* trying any skb allocation that can actually fail with -ENOMEM. +*/ + old_state = priv->can.state; +kvaser_usb_rx_error_update_can_state (priv, &es); + skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;return ; } - new_state = priv->can.state; - -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); - -if (status &M16C_STATE_BUS_OFF ) { +if (es.status &M16C_STATE_BUS_OFF ) { cf->can_id |=CAN_ERR_BUSOFF ; - priv->can.can_stats.bus_off++;if (!priv->can.restart_ms)kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); -netif_carrier_off (priv->netdev); - - new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { -if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { + }else if (es.status &M16C_STATE_BUS_PASSIVE ) { +if (old_state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es.txerr || es.rxerr) + cf->data[1 ] = (es.txerr > es.rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else cf->data[1 ] =CAN_ERR_CRTL_TX_PASSIVE |CAN_ERR_CRTL_RX_PASSIVE ; - - priv->can.can_stats.error_passive++; } - - new_state =CAN_STATE_ERROR_PASSIVE ; } -if (status ==M16C_STATE_BUS_ERROR ) { -if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { +if (es.status ==M16C_STATE_BUS_ERROR ) { +if ((old_state <CAN_STATE_ERROR_WARNING ) && + ((es.txerr >=96 ) || (es.rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es.txerr > es.rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ; - - priv->can.can_stats.error_warning++; - new_state =CAN_STATE_ERROR_WARNING ; - }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { + }else if (old_state >CAN_STATE_ERROR_ACTIVE ) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - - new_state =CAN_STATE_ERROR_ACTIVE ; } } -if (!status) { +if (!es.status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - - new_state =CAN_STATE_ERROR_ACTIVE ; }if (priv->can.restart_ms && - (priv->can.state >=CAN_STATE_BUS_OFF ) && - (new_state <CAN_STATE_BUS_OFF )) { + (old_state >=CAN_STATE_BUS_OFF ) && + (priv->can.state <CAN_STATE_BUS_OFF )) { cf->can_id |=CAN_ERR_RESTARTED ;netif_carrier_on (priv->netdev); - - priv->can.can_stats.restarts++; } -if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - +if (es.error_factor) { cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; -if (error_factor &M16C_EF_ACKE ) +if (es.error_factor &M16C_EF_ACKE ) cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); -if (error_factor &M16C_EF_CRCE ) +if (es.error_factor &M16C_EF_CRCE ) cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ |CAN_ERR_PROT_LOC_CRC_DEL ); -if (error_factor &M16C_EF_FORME ) +if (es.error_factor &M16C_EF_FORME ) cf->data[2 ] |=CAN_ERR_PROT_FORM ; -if (error_factor &M16C_EF_STFE ) +if (es.error_factor &M16C_EF_STFE ) cf->data[2 ] |=CAN_ERR_PROT_STUFF ; -if (error_factor &M16C_EF_BITE0 ) +if (es.error_factor &M16C_EF_BITE0 ) cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; -if (error_factor &M16C_EF_BITE1 ) +if (es.error_factor &M16C_EF_BITE1 ) cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; -if (error_factor &M16C_EF_TRE ) +if (es.error_factor &M16C_EF_TRE ) cf->data[2 ] |=CAN_ERR_PROT_TX ; } - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; - - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; - - priv->can.state = new_state; + cf->data[6 ] = es.txerr; + cf->data[7 ] = es.rxerr; stats->rx_packets++; stats->rx_bytes += cf->can_dlc;
@@ -792,6 +822,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, }if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { + stats->rx_over_errors++; + stats->rx_errors++; + skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;
@@ -801,9 +834,6 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, cf->can_id |=CAN_ERR_CRTL ; cf->data[1 ] =CAN_ERR_CRTL_RX_OVERFLOW ; - stats->rx_over_errors++; - stats->rx_errors++; - stats->rx_packets++; stats->rx_bytes += cf->can_dlc;netif_rx (skb);
Signature · 1 line
1.9.1
PATCH v5 2/5 can: kvaser_usb: Consolidate and unify state change handling
From: Ahmed S. Darwish <[email protected]>
Replace most of the can interface's state and error counters handling with the new can-dev can_change_state() mechanism.
--- drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 59 deletions(-)
drivers/net/can/usb/kvaser_usb.c +55 -59
@@ -620,40 +620,43 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) }static void kvaser_usb_rx_error_update_can_state (struct kvaser_usb_net_priv *priv, -const struct kvaser_usb_error_summary *es) +const struct kvaser_usb_error_summary *es, +struct can_frame *cf) {struct net_device_stats *stats; -enum can_state new_state; - - stats = &priv->netdev->stats; - new_state = priv->can.state; +enum can_state cur_state, new_state, tx_state, rx_state;netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (es->status &M16C_STATE_BUS_OFF ) { - priv->can.can_stats.bus_off++; + stats = &priv->netdev->stats; + new_state = cur_state = priv->can.state; + +if (es->status &M16C_STATE_BUS_OFF ) new_state =CAN_STATE_BUS_OFF ; - }else if (es->status &M16C_STATE_BUS_PASSIVE ) { -if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) - priv->can.can_stats.error_passive++; +else if (es->status &M16C_STATE_BUS_PASSIVE ) new_state =CAN_STATE_ERROR_PASSIVE ; - }if (es->status ==M16C_STATE_BUS_ERROR ) { -if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((es->txerr >=96 ) || (es->rxerr >=96 ))) { - priv->can.can_stats.error_warning++; +if ((cur_state <CAN_STATE_ERROR_WARNING ) && + ((es->txerr >=96 ) || (es->rxerr >=96 ))) new_state =CAN_STATE_ERROR_WARNING ; - }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { +else if (cur_state >CAN_STATE_ERROR_ACTIVE ) new_state =CAN_STATE_ERROR_ACTIVE ; - } }if (!es->status) new_state =CAN_STATE_ERROR_ACTIVE ; +if (new_state != cur_state) { + tx_state = (es->txerr >= es->rxerr) ? new_state :0 ; + rx_state = (es->txerr <= es->rxerr) ? new_state :0 ; + +can_change_state (priv->netdev, cf, tx_state, rx_state); + new_state = priv->can.state; + } +if (priv->can.restart_ms && - (priv->can.state >=CAN_STATE_BUS_OFF ) && + (cur_state >=CAN_STATE_BUS_OFF ) && (new_state <CAN_STATE_BUS_OFF )) { priv->can.can_stats.restarts++; }
@@ -665,18 +668,17 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri priv->bec.txerr = es->txerr; priv->bec.rxerr = es->rxerr; - priv->can.state = new_state; }static void kvaser_usb_rx_error (const struct kvaser_usb *dev,const struct kvaser_msg *msg) { -struct can_frame *cf; +struct can_frame *cf, tmp_cf = { .can_id =CAN_ERR_FLAG , .can_dlc =CAN_ERR_DLC };struct sk_buff *skb;struct net_device_stats *stats;struct kvaser_usb_net_priv *priv;struct kvaser_usb_error_summary es = { }; -enum can_state old_state; +enum can_state old_state, new_state;switch (msg->id) {case CMD_CAN_ERROR_EVENT :
@@ -721,60 +723,54 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, }/* Update all of the can interface's state and error counters before -* trying any skb allocation that can actually fail with -ENOMEM. +* 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_rx_error_update_can_state (priv, &es); +kvaser_usb_rx_error_update_can_state (priv, &es, &tmp_cf); + new_state = priv->can.state; skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;return ; } +memcpy (cf, &tmp_cf,sizeof (*cf)); -if (es.status &M16C_STATE_BUS_OFF ) { - cf->can_id |=CAN_ERR_BUSOFF ; - -if (!priv->can.restart_ms) -kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); -netif_carrier_off (priv->netdev); - }else if (es.status &M16C_STATE_BUS_PASSIVE ) { -if (old_state !=CAN_STATE_ERROR_PASSIVE ) { - cf->can_id |=CAN_ERR_CRTL ; - -if (es.txerr || es.rxerr) - cf->data[1 ] = (es.txerr > es.rxerr) - ?CAN_ERR_CRTL_TX_PASSIVE - :CAN_ERR_CRTL_RX_PASSIVE ; -else - cf->data[1 ] =CAN_ERR_CRTL_TX_PASSIVE | -CAN_ERR_CRTL_RX_PASSIVE ; +if (new_state != old_state) { +if (es.status &M16C_STATE_BUS_OFF ) { +if (!priv->can.restart_ms) +kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); +netif_carrier_off (priv->netdev); + } + +if (es.status ==M16C_STATE_BUS_ERROR ) { +if ((old_state >=CAN_STATE_ERROR_WARNING ) || + (es.txerr <96 && es.rxerr <96 )) { +if (old_state >CAN_STATE_ERROR_ACTIVE ) { + cf->can_id |=CAN_ERR_PROT ; + cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; + } + } } - } -if (es.status ==M16C_STATE_BUS_ERROR ) { -if ((old_state <CAN_STATE_ERROR_WARNING ) && - ((es.txerr >=96 ) || (es.rxerr >=96 ))) { - cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (es.txerr > es.rxerr) - ?CAN_ERR_CRTL_TX_WARNING - :CAN_ERR_CRTL_RX_WARNING ; - }else if (old_state >CAN_STATE_ERROR_ACTIVE ) { +if (!es.status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; } - } -if (!es.status) { - cf->can_id |=CAN_ERR_PROT ; - cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - } - -if (priv->can.restart_ms && - (old_state >=CAN_STATE_BUS_OFF ) && - (priv->can.state <CAN_STATE_BUS_OFF )) { - cf->can_id |=CAN_ERR_RESTARTED ; -netif_carrier_on (priv->netdev); +if (priv->can.restart_ms && + (old_state >=CAN_STATE_BUS_OFF ) && + (new_state <CAN_STATE_BUS_OFF )) { + cf->can_id |=CAN_ERR_RESTARTED ; +netif_carrier_on (priv->netdev); + } }if (es.error_factor) {
Signature · 1 line
1.9.1
PATCH v5 3/5 can: kvaser_usb: Fix state handling upon BUS_ERROR events
From: Ahmed S. Darwish <[email protected]>
While being in an ERROR_WARNING state and receiving further bus error events with error counts in the range of 97-127 inclusive, the state handling code erroneously reverts back to ERROR_ACTIVE.
As per the CAN standard recommendations, only revert to ERROR_ACTIVE when the error counters are less than 96.
Moreover, in certain Kvaser models, the BUS_ERROR flag is always set along with undefined bits in the M16C status register. Thus use bitwise ops instead of full equality for checking the register against bus errors.
--- drivers/net/can/usb/kvaser_usb.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-)
drivers/net/can/usb/kvaser_usb.c +11 -13
@@ -635,10 +635,12 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri new_state =CAN_STATE_BUS_OFF ; else if (es->status & M16C_STATE_BUS_PASSIVE) new_state =CAN_STATE_ERROR_PASSIVE ; - -if (es->status ==M16C_STATE_BUS_ERROR ) { -if ((cur_state <CAN_STATE_ERROR_WARNING ) && - ((es->txerr >=96 ) || (es->rxerr >=96 ))) + else if (es->status & M16C_STATE_BUS_ERROR) { +if ((es->txerr >=256 ) || (es->rxerr >=256 )) + new_state =CAN_STATE_BUS_OFF ; +else if ((es->txerr >=128 ) || (es->rxerr >=128 )) + new_state =CAN_STATE_ERROR_PASSIVE ; +else if ((es->txerr >=96 ) || (es->rxerr >=96 )) new_state =CAN_STATE_ERROR_WARNING ;else if (cur_state >CAN_STATE_ERROR_ACTIVE ) new_state =CAN_STATE_ERROR_ACTIVE ;
@@ -748,15 +750,11 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,if (!priv->can.restart_ms)kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP );netif_carrier_off (priv->netdev); - } - -if (es.status ==M16C_STATE_BUS_ERROR ) { -if ((old_state >=CAN_STATE_ERROR_WARNING ) || - (es.txerr <96 && es.rxerr <96 )) { -if (old_state >CAN_STATE_ERROR_ACTIVE ) { - cf->can_id |=CAN_ERR_PROT ; - cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - } + }else if (es.status &M16C_STATE_BUS_ERROR ) { +if ((es.txerr <96 && es.rxerr <96 ) && + (old_state >CAN_STATE_ERROR_ACTIVE )) { + cf->can_id |=CAN_ERR_PROT ; + cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; } }
Signature · 1 line
1.9.1
PATCH v5 4/5 can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT
From: Ahmed S. Darwish <[email protected]>
On some x86 laptops, plugging a Kvaser device again after an unplug makes the firmware always ignore the very first command. For such a case, provide some room for retries instead of completly exiting the driver init code.
--- drivers/net/can/usb/kvaser_usb.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/net/can/usb/kvaser_usb.c +10 -2
@@ -1614,7 +1614,7 @@ static int kvaser_usb_probe(struct usb_interface *intf, {struct kvaser_usb *dev;int err = -ENOMEM ; -int i; +int i, retry =3 ; dev =devm_kzalloc (&intf->dev,sizeof (*dev),GFP_KERNEL );if (!dev)
@@ -1632,7 +1632,15 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev); - err =kvaser_usb_get_software_info (dev); +/* On some x86 laptops, plugging a Kvaser device again after +* an unplug makes the firmware always ignore the very first +* command. For such a case, provide some room for retries +* instead of completly exiting the driver. +*/ +do { + err =kvaser_usb_get_software_info (dev); + }while (--retry && err == -ETIMEDOUT ); +if (err) {dev_err (&intf->dev,"Cannot get software infos, error %d\n" , err);
Signature · 1 line
1.9.1
PATCH v5 5/5 can: kvaser_usb: Add support for the USBcan-II family
From: Ahmed S. Darwish <[email protected]>
CAN to USB interfaces sold by the Swedish manufacturer Kvaser are divided into two major families: 'Leaf', and 'USBcanII'. From an Operating System perspective, the firmware of both families behave in a not too drastically different fashion.
This patch adds support for the USBcanII family of devices to the current Kvaser Leaf-only driver.
CAN frames sending, receiving, and error handling paths has been tested using the dual-channel "Kvaser USBcan II HS/LS" dongle. It should also work nicely with other products in the same category.
List of new devices supported by this driver update:
- Kvaser USBcan II HS/HS
- Kvaser USBcan II HS/LS
- Kvaser USBcan Rugged ("USBcan Rev B")
- Kvaser Memorator HS/HS
- Kvaser Memorator HS/LS
- Scania VCI2 (if you have the Kvaser logo on top)
--- drivers/net/can/usb/Kconfig | 8 +- drivers/net/can/usb/kvaser_usb.c | 598 ++++++++++++++++++++++++++++++--------- 2 files changed, 478 insertions(+), 128 deletions(-)
** V5 Changelog:
- Rebase on the new CAN error state changes added for the Leaf driver
- Add minor changes (remove unused commands, constify poniters, etc.)
** V4 Changelog:
- Use type-safe C methods instead of cpp macros
- Remove defensive checks against non-existing families
- Re-order methods to remove forward declarations
- Smaller stuff spotted by earlier review (function prefexes, etc.)
** V3 Changelog:
- Fix padding for the usbcan_msg_tx_acknowledge command
- Remove kvaser_usb->max_channels and the MAX_NET_DEVICES macro
- Rename commands to CMD_LEAF_xxx and CMD_USBCAN_xxx
- Apply checkpatch.pl suggestions ('net/' comments, multi-line strings, etc.)
** V2 Changelog:
- Update Kconfig entries
- Use actual number of CAN channels (instead of max) where appropriate
- Rebase over a new set of UsbcanII-independent driver fixes
drivers/net/can/usb/Kconfig +7 -1
@@ -25,7 +25,7 @@ config CAN_KVASER_USB tristate "Kvaser CAN/USB interface" ---help--- This driver adds support for Kvaser CAN/USB devices like Kvaser - Leaf Light. + Leaf Light and Kvaser USBcan II. The driver provides support for the following devices: - Kvaser Leaf Light
@@ -46,6 +46,12 @@ config CAN_KVASER_USB - Kvaser USBcan R - Kvaser Leaf Light v2 - Kvaser Mini PCI Express HS + - Kvaser USBcan II HS/HS + - Kvaser USBcan II HS/LS + - Kvaser USBcan Rugged ("USBcan Rev B") + - Kvaser Memorator HS/HS + - Kvaser Memorator HS/LS + - Scania VCI2 (if you have the Kvaser logo on top) If unsure, say N.
drivers/net/can/usb/kvaser_usb.c +471 -127
945 lines not on this page · raw message
Signature · 1 line
1.9.1
Re: [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT
In reply to Ahmed S. DarwishHello.
Quoted 6 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
On some x86 laptops, plugging a Kvaser device again after an unplug makes the firmware always ignore the very first command. For such a case, provide some room for retries instead of completly exiting the driver init code.
Completely.
Quoted 9 lines
Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)drivers/net/can/usb/kvaser_usb.c +0
-0
[...]
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1638
Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c +4
-1@@ -1632,7 +1632,15 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev); - err =kvaser_usb_get_software_info (dev); +/* On some x86 laptops, plugging a Kvaser device again after +* an unplug makes the firmware always ignore the very first +* command. For such a case, provide some room for retries +* instead of completly exiting the driver.
Completely.
[...]
WBR, Sergei
Re: [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT
Quoted 27 lines · Sergei Shtylyov
Hello.
Quoted 6 lines · Ahmed S. Darwish
From: Ahmed S. Darwish <[email protected]>
On some x86 laptops, plugging a Kvaser device again after an unplug makes the firmware always ignore the very first command. For such a case, provide some room for retries instead of completly exiting the driver init code.
Completely.
Quoted 9 lines
Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)drivers/net/can/usb/kvaser_usb.c +0
-0[...]
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +0
-0@@ -1632,7 +1632,15 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev);
Quoted 8 lines
drivers/net/can/usb/kvaser_usb.c static int kvaser_usb_probe(struct usb_interface *intf, · line 1638
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +4
-1- err =kvaser_usb_get_software_info (dev); +/* On some x86 laptops, plugging a Kvaser device again after +* an unplug makes the firmware always ignore the very first +* command. For such a case, provide some room for retries +* instead of completly exiting the driver. Completely.
Thanks, both fixed in the next submission :-D
Regards,
Darwish
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
In reply to Ahmed S. DarwishQuoting Ahmed S. Darwish (2015-01-20 21:45:37)
Quoted 193 lines
From: Ahmed S. Darwish <[email protected]>
Replace most of the can interface's state and error counters handling with the new can-dev
can_change_state()mechanism.Suggested-by Andri Yngvason <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 59 deletions(-)drivers/net/can/usb/kvaser_usb.c +55
-59@@ -620,40 +620,43 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) }static void kvaser_usb_rx_error_update_can_state (struct kvaser_usb_net_priv *priv, -const struct kvaser_usb_error_summary *es) +const struct kvaser_usb_error_summary *es, +struct can_frame *cf) {struct net_device_stats *stats; -enum can_state new_state; - - stats = &priv->netdev->stats; - new_state = priv->can.state; +enum can_state cur_state, new_state, tx_state, rx_state;netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (es->status &M16C_STATE_BUS_OFF ) { - priv->can.can_stats.bus_off++; + stats = &priv->netdev->stats; + new_state = cur_state = priv->can.state; + +if (es->status &M16C_STATE_BUS_OFF ) new_state =CAN_STATE_BUS_OFF ; - }else if (es->status &M16C_STATE_BUS_PASSIVE ) { -if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) - priv->can.can_stats.error_passive++; +else if (es->status &M16C_STATE_BUS_PASSIVE ) new_state =CAN_STATE_ERROR_PASSIVE ; - }if (es->status ==M16C_STATE_BUS_ERROR ) { -if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((es->txerr >=96 ) || (es->rxerr >=96 ))) { - priv->can.can_stats.error_warning++; +if ((cur_state <CAN_STATE_ERROR_WARNING ) && + ((es->txerr >=96 ) || (es->rxerr >=96 ))) new_state =CAN_STATE_ERROR_WARNING ; - }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { +else if (cur_state >CAN_STATE_ERROR_ACTIVE ) new_state =CAN_STATE_ERROR_ACTIVE ; - } }if (!es->status) new_state =CAN_STATE_ERROR_ACTIVE ; +if (new_state != cur_state) { + tx_state = (es->txerr >= es->rxerr) ? new_state :0 ; + rx_state = (es->txerr <= es->rxerr) ? new_state :0 ; + +can_change_state (priv->netdev, cf, tx_state, rx_state); + new_state = priv->can.state; + } +if (priv->can.restart_ms && - (priv->can.state >=CAN_STATE_BUS_OFF ) && + (cur_state >=CAN_STATE_BUS_OFF ) && (new_state <CAN_STATE_BUS_OFF )) { priv->can.can_stats.restarts++; }@@ -665,18 +668,17 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri priv->bec.txerr = es->txerr; priv->bec.rxerr = es->rxerr; - priv->can.state = new_state; }static void kvaser_usb_rx_error (const struct kvaser_usb *dev,const struct kvaser_msg *msg) { -struct can_frame *cf; +struct can_frame *cf, tmp_cf = { .can_id =CAN_ERR_FLAG , .can_dlc =CAN_ERR_DLC };struct sk_buff *skb;struct net_device_stats *stats;struct kvaser_usb_net_priv *priv;struct kvaser_usb_error_summary es = { }; -enum can_state old_state; +enum can_state old_state, new_state;switch (msg->id) {case CMD_CAN_ERROR_EVENT :@@ -721,60 +723,54 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, }/* Update all of the can interface's state and error counters before -* trying any skb allocation that can actually fail with -ENOMEM. +* 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_rx_error_update_can_state (priv, &es); +kvaser_usb_rx_error_update_can_state (priv, &es, &tmp_cf); + new_state = priv->can.state; skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;return ; } +memcpy (cf, &tmp_cf,sizeof (*cf)); -if (es.status &M16C_STATE_BUS_OFF ) { - cf->can_id |=CAN_ERR_BUSOFF ; - -if (!priv->can.restart_ms) -kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); -netif_carrier_off (priv->netdev); - }else if (es.status &M16C_STATE_BUS_PASSIVE ) { -if (old_state !=CAN_STATE_ERROR_PASSIVE ) { - cf->can_id |=CAN_ERR_CRTL ; - -if (es.txerr || es.rxerr) - cf->data[1 ] = (es.txerr > es.rxerr) - ?CAN_ERR_CRTL_TX_PASSIVE - :CAN_ERR_CRTL_RX_PASSIVE ; -else - cf->data[1 ] =CAN_ERR_CRTL_TX_PASSIVE | -CAN_ERR_CRTL_RX_PASSIVE ; +if (new_state != old_state) { +if (es.status &M16C_STATE_BUS_OFF ) { +if (!priv->can.restart_ms) +kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); +netif_carrier_off (priv->netdev); + } + +if (es.status ==M16C_STATE_BUS_ERROR ) { +if ((old_state >=CAN_STATE_ERROR_WARNING ) || + (es.txerr <96 && es.rxerr <96 )) { +if (old_state >CAN_STATE_ERROR_ACTIVE ) { + cf->can_id |=CAN_ERR_PROT ; + cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; + } + } } - } -if (es.status ==M16C_STATE_BUS_ERROR ) { -if ((old_state <CAN_STATE_ERROR_WARNING ) && - ((es.txerr >=96 ) || (es.rxerr >=96 ))) { - cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (es.txerr > es.rxerr) - ?CAN_ERR_CRTL_TX_WARNING - :CAN_ERR_CRTL_RX_WARNING ; - }else if (old_state >CAN_STATE_ERROR_ACTIVE ) { +if (!es.status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; } - } -if (!es.status) { - cf->can_id |=CAN_ERR_PROT ; - cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - } - -if (priv->can.restart_ms && - (old_state >=CAN_STATE_BUS_OFF ) && - (priv->can.state <CAN_STATE_BUS_OFF )) { - cf->can_id |=CAN_ERR_RESTARTED ; -netif_carrier_on (priv->netdev); +if (priv->can.restart_ms && + (old_state >=CAN_STATE_BUS_OFF ) && + (new_state <CAN_STATE_BUS_OFF )) { + cf->can_id |=CAN_ERR_RESTARTED ; +netif_carrier_on (priv->netdev); + } }if (es.error_factor) {Signature · 1 line
1.9.1
Looks good.
--
Andri
Marc Kleine-Budde
maintainerRe: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoted 12 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
Quoted 11 lines
From: Ahmed S. Darwish <[email protected]>
Replace most of the can interface's state and error counters handling with the new can-dev
can_change_state()mechanism.Suggested-by Andri Yngvason <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 59 deletions(-)
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +0
-0Looks good.
Is this an Acked-by?
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoting Marc Kleine-Budde (2015-01-21 10:44:54)
Quoted 13 lines · Andri Yngvason
Quoted 12 lines
Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
Quoted 11 lines
From: Ahmed S. Darwish <[email protected]>
Replace most of the can interface's state and error counters handling with the new can-dev
can_change_state()mechanism.Suggested-by Andri Yngvason <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 59 deletions(-)
Quoted 9 lines
Quoted 6 lines
drivers/net/can/usb/kvaser_usb.c
Quoted 4 lines
drivers/net/can/usb/kvaser_usb.c +0
-0Looks good.
Is this an Acked-by?
ACK.
--
Andri
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
In reply to Andri YngvasonQuoted 18 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
Quoted 17 lines
From: Ahmed S. Darwish <[email protected]>
Replace most of the can interface's state and error counters handling with the new can-dev
can_change_state()mechanism.Suggested-by Andri Yngvason <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 59 deletions(-)drivers/net/can/usb/kvaser_usb.c +0
-0
...
Quoted 2 lines
Looks good.
Would be nice to see some "candump" traces as well. Ahmed, could you please generate such traces doing:
1. Execute in a session:
# candump -t d -e any,0:0,#FFFFFFFF
2. Execute in another session:
# cangen -g 10 -D i can0
3. Disconnect the CAN cable
4. After a while reconnect the CAN cable
5. Stop candump and save the trace.
and to test bus-off:
1. Execute in a session:
# candump -t d -e any,0:0,#FFFFFFFF
2. Execute in another session:
# cangen -g 10 -D i can0
3. Short-circuit the CAN low and high wires of the CAN cable
4. After a while remove the short-circuit.
5. Stop candump and save the trace.
Thanks,
Wolfgang.
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Hi!
Quoted 23 lines · Wolfgang Grandegger
Quoted 18 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
Quoted 17 lines
From: Ahmed S. Darwish <[email protected]>
Replace most of the can interface's state and error counters handling with the new can-dev
can_change_state()mechanism.Suggested-by Andri Yngvason <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 59 deletions(-)drivers/net/can/usb/kvaser_usb.c +0
-0...
Quoted 1 line
Quoted 3 lines
Quoted 1 line
Looks good.
Would be nice to see some "candump" traces as well.
Sure. The USBCan-II device trace below is generated after applying all patches in the series, especially patch #3, which fixes some some invalid CAN state transitions logic in the original driver.
##########################################################################
candump on a PC, Kvaser USB device on the receiving end:
...
(000.011392) can0 71D [8] 5B 06 00 00 00 00 00 00 (000.009270) can0 712 [3] 5C 06 00 (000.010691) can0 0F3 [7] 5D 06 00 00 00 00 00 (000.010443) can0 63E [8] 5E 06 00 00 00 00 00 00 (000.010112) can0 502 [8] 5F 06 00 00 00 00 00 00 (000.009944) can0 39A [8] 60 06 00 00 00 00 00 00 (000.010186) can0 721 [8] 61 06 00 00 00 00 00 00 (000.009628) can0 5B7 [6] 62 06 00 00 00 00 (000.009784) can0 1D7 [4] 63 06 00 00 (000.010806) can0 4FE [8] 64 06 00 00 00 00 00 00 (000.008897) can0 75E [1] 65 (000.010257) can0 1EA [2] 66 06
<-- Unplug the cable -->
(000.010640) can0 20000080 [8] 00 00 00 00 00 00 00 01 ERRORFRAME
bus-error
error-counter-tx-rx{{0}{1}}<-- Replug the cable, after 12 seconds -->
(044.345134) can0 20000080 [8] 00 00 00 00 00 00 00 02 ERRORFRAME
bus-error
error-counter-tx-rx{{0}{2}}(000.002730) can0 75E [8] 67 06 00 00 00 00 00 00 (000.002097) can0 696 [6] 68 06 00 00 00 00 (000.002328) can0 45A [8] 69 06 00 00 00 00 00 00 (000.002484) can0 496 [8] 6A 06 00 00 00 00 00 00 (000.002458) can0 604 [8] 6B 06 00 00 00 00 00 00 (000.002252) can0 27B [7] 6C 06 00 00 00 00 00 (000.002420) can0 48F [8] 6D 06 00 00 00 00 00 00 (000.001306) can0 1B3 [1] 6E (000.002518) can0 145 [8] 6F 06 00 00 00 00 00 00 (000.002262) can0 6EA [7] 70 06 00 00 00 00 00 (000.001053) can0 2DC [1] 71 (000.001731) can0 1DD [4] 72 06 00 00 (000.002332) can0 455 [8] 73 06 00 00 00 00 00 00
...
If the cable was _swiftly_ plugged and unplugged, no errors appear. So it seems the errors above are just due to noise.
##########################################################################
Afterwards, candump on a PC, Kvaser USB device on the sending end:
...
(000.008784) can0 60A [1] C1 (000.011341) can0 2A8 [8] C2 0A 00 00 00 00 00 00 (000.009873) can0 03D [7] C3 0A 00 00 00 00 00 (000.010394) can0 55C [8] C4 0A 00 00 00 00 00 00 (000.009979) can0 45A [8] C5 0A 00 00 00 00 00 00 (000.010125) can0 6E8 [8] C6 0A 00 00 00 00 00 00 (000.010149) can0 4EE [8] C7 0A 00 00 00 00 00 00 (000.010102) can0 5D2 [8] C8 0A 00 00 00 00 00 00 (000.010000) can0 61F [8] C9 0A 00 00 00 00 00 00 (000.010271) can0 5F8 [8] CA 0A 00 00 00 00 00 00
<-- Unplug the cable -->
(000.009106) can0 20000080 [8] 00 00 00 00 00 00 08 00 ERRORFRAME
bus-error
error-counter-tx-rx{{8}{0}}
(000.001872) can0 20000080 [8] 00 00 00 00 00 00 10 00 ERRORFRAME
bus-error
error-counter-tx-rx{{16}{0}}
(000.001748) can0 20000080 [8] 00 00 00 00 00 00 18 00 ERRORFRAME
bus-error
error-counter-tx-rx{{24}{0}}
(000.001751) can0 20000080 [8] 00 00 00 00 00 00 20 00 ERRORFRAME
bus-error
error-counter-tx-rx{{32}{0}}
(000.001874) can0 20000080 [8] 00 00 00 00 00 00 28 00 ERRORFRAME
bus-error
error-counter-tx-rx{{40}{0}}
(000.001625) can0 20000080 [8] 00 00 00 00 00 00 30 00 ERRORFRAME
bus-error
error-counter-tx-rx{{48}{0}}
(000.001875) can0 20000080 [8] 00 00 00 00 00 00 38 00 ERRORFRAME
bus-error
error-counter-tx-rx{{56}{0}}
(000.001751) can0 20000080 [8] 00 00 00 00 00 00 40 00 ERRORFRAME
bus-error
error-counter-tx-rx{{64}{0}}
(000.001761) can0 20000080 [8] 00 00 00 00 00 00 48 00 ERRORFRAME
bus-error
error-counter-tx-rx{{72}{0}}
(000.001743) can0 20000080 [8] 00 00 00 00 00 00 50 00 ERRORFRAME
bus-error
error-counter-tx-rx{{80}{0}}
(000.001910) can0 20000080 [8] 00 00 00 00 00 00 58 00 ERRORFRAME
bus-error
error-counter-tx-rx{{88}{0}}
(000.001753) can0 20000084 [8] 00 08 00 00 00 00 60 00 ERRORFRAME
controller-problem{tx-error-warning}
bus-error
error-counter-tx-rx{{96}{0}}
(000.001720) can0 20000080 [8] 00 00 00 00 00 00 68 00 ERRORFRAME
bus-error
error-counter-tx-rx{{104}{0}}
(000.001876) can0 20000080 [8] 00 00 00 00 00 00 70 00 ERRORFRAME
bus-error
error-counter-tx-rx{{112}{0}}
(000.001749) can0 20000080 [8] 00 00 00 00 00 00 78 00 ERRORFRAME
bus-error
error-counter-tx-rx{{120}{0}}
(000.001771) can0 20000084 [8] 00 20 00 00 00 00 80 00 ERRORFRAME
controller-problem{tx-error-passive}
bus-error
error-counter-tx-rx{{128}{0}}
(000.001868) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME
bus-error
error-counter-tx-rx{{128}{0}}
(000.001982) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME
bus-error
error-counter-tx-rx{{128}{0}}(( Then a continous flood, exactly similar to the above packet, appears.
Unfortunately this flooding is a firmware problem. ))
<-- Replug the cable, after a good amount of time -->
(000.520485) can0 33D [4] CB 0A 00 00 (000.002693) can0 42E [8] CC 0A 00 00 00 00 00 00 (000.001795) can0 319 [4] CD 0A 00 00 (000.002705) can0 3B1 [8] CE 0A 00 00 00 00 00 00 (000.001295) can0 4CC [2] CF 0A (000.002205) can0 42B [6] D0 0A 00 00 00 00 (000.001620) can0 5A2 [3] D1 0A 00 (000.002636) can0 691 [8] D2 0A 00 00 00 00 00 00 (000.002615) can0 36A [8] D3 0A 00 00 00 00 00 00 (000.001729) can0 068 [4] D4 0A 00 00 (000.001195) can0 4C8 [1] D5
...
##########################################################################
Bus-off Testing:
candump on a PC, Kvaser device on the sending end. An i.mx6 ARM board with flexcan is on the receiving end:
(000.010319) can0 5CC [8] 90 02 00 00 00 00 00 00 (000.008747) can0 679 [1] 91 (000.011442) can0 011 [8] 92 02 00 00 00 00 00 00 (000.008991) can0 631 [2] 93 02 (000.011097) can0 532 [7] 94 02 00 00 00 00 00 (000.009781) can0 0A9 [5] 95 02 00 00 00 (000.010792) can0 1DD [8] 96 02 00 00 00 00 00 00 (000.010026) can0 44E [8] 97 02 00 00 00 00 00 00 (000.010181) can0 76A [8] 98 02 00 00 00 00 00 00 (000.008867) can0 1A5 [1] 99 (000.011322) can0 2B4 [8] 9A 02 00 00 00 00 00 00
<-- Unplug the can low and high wires from the board -->
(000.009688) can0 20000080 [8] 00 00 00 00 00 00 08 00 ERRORFRAME
bus-error
error-counter-tx-rx{{8}{0}}
(000.002246) can0 20000080 [8] 00 00 00 00 00 00 10 00 ERRORFRAME
bus-error
error-counter-tx-rx{{16}{0}}
(000.002124) can0 20000080 [8] 00 00 00 00 00 00 18 00 ERRORFRAME
bus-error
error-counter-tx-rx{{24}{0}}
(000.002115) can0 20000080 [8] 00 00 00 00 00 00 20 00 ERRORFRAME
bus-error
error-counter-tx-rx{{32}{0}}
(000.002132) can0 20000080 [8] 00 00 00 00 00 00 28 00 ERRORFRAME
bus-error
error-counter-tx-rx{{40}{0}}
(000.002266) can0 20000080 [8] 00 00 00 00 00 00 30 00 ERRORFRAME
bus-error
error-counter-tx-rx{{48}{0}}
(000.002187) can0 20000080 [8] 00 00 00 00 00 00 38 00 ERRORFRAME
bus-error
error-counter-tx-rx{{56}{0}}
(000.002046) can0 20000080 [8] 00 00 00 00 00 00 40 00 ERRORFRAME
bus-error
error-counter-tx-rx{{64}{0}}
(000.002076) can0 20000080 [8] 00 00 00 00 00 00 48 00 ERRORFRAME
bus-error
error-counter-tx-rx{{72}{0}}
(000.002406) can0 20000080 [8] 00 00 00 00 00 00 50 00 ERRORFRAME
bus-error
error-counter-tx-rx{{80}{0}}
(000.001969) can0 20000080 [8] 00 00 00 00 00 00 58 00 ERRORFRAME
bus-error
error-counter-tx-rx{{88}{0}}
(000.002388) can0 20000084 [8] 00 08 00 00 00 00 60 00 ERRORFRAME
controller-problem{tx-error-warning}
bus-error
error-counter-tx-rx{{96}{0}}
(000.002021) can0 20000080 [8] 00 00 00 00 00 00 68 00 ERRORFRAME
bus-error
error-counter-tx-rx{{104}{0}}
(000.002110) can0 20000080 [8] 00 00 00 00 00 00 70 00 ERRORFRAME
bus-error
error-counter-tx-rx{{112}{0}}
(000.002155) can0 20000080 [8] 00 00 00 00 00 00 78 00 ERRORFRAME
bus-error
error-counter-tx-rx{{120}{0}}
(000.002140) can0 20000084 [8] 00 20 00 00 00 00 80 00 ERRORFRAME
controller-problem{tx-error-passive}
bus-error
error-counter-tx-rx{{128}{0}}
(000.002324) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME
bus-error
error-counter-tx-rx{{128}{0}}
(000.002416) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME
bus-error
error-counter-tx-rx{{128}{0}}
(000.002237) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME
bus-error
error-counter-tx-rx{{128}{0}}(( Then a continous flood, exactly similar to the above packet, appears ))
<-- Short-circuit the can high and low wires -->
(000.002364) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME
bus-error
error-counter-tx-rx{{128}{0}}
(000.002108) can0 20000080 [8] 00 00 00 00 00 00 88 00 ERRORFRAME
bus-error
error-counter-tx-rx{{136}{0}}
(000.000494) can0 20000080 [8] 00 00 00 00 00 00 90 00 ERRORFRAME
bus-error
error-counter-tx-rx{{144}{0}}
(000.000523) can0 20000080 [8] 00 00 00 00 00 00 98 00 ERRORFRAME
bus-error
error-counter-tx-rx{{152}{0}}
(000.000661) can0 20000080 [8] 00 00 00 00 00 00 A0 00 ERRORFRAME
bus-error
error-counter-tx-rx{{160}{0}}
(000.000464) can0 20000080 [8] 00 00 00 00 00 00 A8 00 ERRORFRAME
bus-error
error-counter-tx-rx{{168}{0}}
(000.000534) can0 20000080 [8] 00 00 00 00 00 00 B0 00 ERRORFRAME
bus-error
error-counter-tx-rx{{176}{0}}
(000.000499) can0 20000080 [8] 00 00 00 00 00 00 B8 00 ERRORFRAME
bus-error
error-counter-tx-rx{{184}{0}}
(000.000626) can0 20000080 [8] 00 00 00 00 00 00 C0 00 ERRORFRAME
bus-error
error-counter-tx-rx{{192}{0}}
(000.000373) can0 20000080 [8] 00 00 00 00 00 00 C8 00 ERRORFRAME
bus-error
error-counter-tx-rx{{200}{0}}
(000.000627) can0 20000080 [8] 00 00 00 00 00 00 D0 00 ERRORFRAME
bus-error
error-counter-tx-rx{{208}{0}}
(000.000507) can0 20000080 [8] 00 00 00 00 00 00 D8 00 ERRORFRAME
bus-error
error-counter-tx-rx{{216}{0}}
(000.000501) can0 20000080 [8] 00 00 00 00 00 00 E0 00 ERRORFRAME
bus-error
error-counter-tx-rx{{224}{0}}
(000.000459) can0 20000080 [8] 00 00 00 00 00 00 E8 00 ERRORFRAME
bus-error
error-counter-tx-rx{{232}{0}}
(000.000606) can0 20000080 [8] 00 00 00 00 00 00 F0 00 ERRORFRAME
bus-error
error-counter-tx-rx{{240}{0}}
(000.000454) can0 20000080 [8] 00 00 00 00 00 00 F8 00 ERRORFRAME
bus-error
error-counter-tx-rx{{248}{0}} (000.000664) can0 200000C0 [8] 00 00 00 00 00 00 00 00 ERRORFRAME
bus-off
bus-error
(( No further bus activity ))
##########################################################################
Regards,
Darwish
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
Quoted 33 lines
Hi!
Quoted 23 lines · Wolfgang Grandegger
Quoted 18 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
Quoted 17 lines
From: Ahmed S. Darwish <[email protected]>
Replace most of the can interface's state and error counters handling with the new can-dev
can_change_state()mechanism.Suggested-by Andri Yngvason <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 59 deletions(-)drivers/net/can/usb/kvaser_usb.c +0
-0...
Quoted 1 line
Quoted 3 lines
Quoted 1 line
Looks good.
Would be nice to see some "candump" traces as well.
Sure. The USBCan-II device trace below is generated after applying all patches in the series, especially patch #3, which fixes some some invalid CAN state transitions logic in the original driver.
[...]
Quoted 23 lines
Afterwards, candump on a PC, Kvaser USB device on the sending end:
...
(000.008784) can0 60A [1] C1 (000.011341) can0 2A8 [8] C2 0A 00 00 00 00 00 00 (000.009873) can0 03D [7] C3 0A 00 00 00 00 00 (000.010394) can0 55C [8] C4 0A 00 00 00 00 00 00 (000.009979) can0 45A [8] C5 0A 00 00 00 00 00 00 (000.010125) can0 6E8 [8] C6 0A 00 00 00 00 00 00 (000.010149) can0 4EE [8] C7 0A 00 00 00 00 00 00 (000.010102) can0 5D2 [8] C8 0A 00 00 00 00 00 00 (000.010000) can0 61F [8] C9 0A 00 00 00 00 00 00 (000.010271) can0 5F8 [8] CA 0A 00 00 00 00 00 00<-- Unplug the cable -->
(000.009106) can0 20000080 [8] 00 00 00 00 00 00 08 00 ERRORFRAME
bus-error error-counter-tx-rx{{8}{0}} (000.001872) can0 20000080 [8] 00 00 00 00 00 00 10 00 ERRORFRAME bus-error error-counter-tx-rx{{16}{0}}
[...]
Quoted 6 lines
error-counter-tx-rx{{80}{0}}
(000.001910) can0 20000080 [8] 00 00 00 00 00 00 58 00 ERRORFRAME
bus-error
error-counter-tx-rx{{88}{0}}
(000.001753) can0 20000084 [8] 00 08 00 00 00 00 60 00 ERRORFRAME
controller-problem{tx-error-warning}Good.
Quoted 5 lines
bus-error
error-counter-tx-rx{{96}{0}}
(000.001720) can0 20000080 [8] 00 00 00 00 00 00 68 00 ERRORFRAME
bus-error
error-counter-tx-rx{{104}{0}}Quoted 8 lines
(000.001876) can0 20000080 [8] 00 00 00 00 00 00 70 00 ERRORFRAME
bus-error error-counter-tx-rx{{112}{0}} (000.001749) can0 20000080 [8] 00 00 00 00 00 00 78 00 ERRORFRAME bus-error error-counter-tx-rx{{120}{0}} (000.001771) can0 20000084 [8] 00 20 00 00 00 00 80 00 ERRORFRAME controller-problem{tx-error-passive}
Also good.
Quoted 9 lines
bus-error
error-counter-tx-rx{{128}{0}}
(000.001868) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME
bus-error
error-counter-tx-rx{{128}{0}}
(000.001982) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME
bus-error
error-counter-tx-rx{{128}{0}}Quoted 5 lines
(( Then a continous flood, exactly similar to the above packet, appears.
Unfortunately this flooding is a firmware problem. ))<-- Replug the cable, after a good amount of time -->
Where are the reverse state transitions?
Quoted 147 lines
(000.520485) can0 33D [4] CB 0A 00 00 (000.002693) can0 42E [8] CC 0A 00 00 00 00 00 00 (000.001795) can0 319 [4] CD 0A 00 00 (000.002705) can0 3B1 [8] CE 0A 00 00 00 00 00 00 (000.001295) can0 4CC [2] CF 0A (000.002205) can0 42B [6] D0 0A 00 00 00 00 (000.001620) can0 5A2 [3] D1 0A 00 (000.002636) can0 691 [8] D2 0A 00 00 00 00 00 00 (000.002615) can0 36A [8] D3 0A 00 00 00 00 00 00 (000.001729) can0 068 [4] D4 0A 00 00 (000.001195) can0 4C8 [1] D5...
##########################################################################
Bus-off Testing:
candump on a PC, Kvaser device on the sending end. An i.mx6 ARM board with flexcan is on the receiving end:
(000.010319) can0 5CC [8] 90 02 00 00 00 00 00 00 (000.008747) can0 679 [1] 91 (000.011442) can0 011 [8] 92 02 00 00 00 00 00 00 (000.008991) can0 631 [2] 93 02 (000.011097) can0 532 [7] 94 02 00 00 00 00 00 (000.009781) can0 0A9 [5] 95 02 00 00 00 (000.010792) can0 1DD [8] 96 02 00 00 00 00 00 00 (000.010026) can0 44E [8] 97 02 00 00 00 00 00 00 (000.010181) can0 76A [8] 98 02 00 00 00 00 00 00 (000.008867) can0 1A5 [1] 99 (000.011322) can0 2B4 [8] 9A 02 00 00 00 00 00 00<-- Unplug the can low and high wires from the board -->
(000.009688) can0 20000080 [8] 00 00 00 00 00 00 08 00 ERRORFRAME
bus-error error-counter-tx-rx{{8}{0}} (000.002246) can0 20000080 [8] 00 00 00 00 00 00 10 00 ERRORFRAME bus-error error-counter-tx-rx{{16}{0}} (000.002124) can0 20000080 [8] 00 00 00 00 00 00 18 00 ERRORFRAME bus-error error-counter-tx-rx{{24}{0}} (000.002115) can0 20000080 [8] 00 00 00 00 00 00 20 00 ERRORFRAME bus-error error-counter-tx-rx{{32}{0}} (000.002132) can0 20000080 [8] 00 00 00 00 00 00 28 00 ERRORFRAME bus-error error-counter-tx-rx{{40}{0}} (000.002266) can0 20000080 [8] 00 00 00 00 00 00 30 00 ERRORFRAME bus-error error-counter-tx-rx{{48}{0}} (000.002187) can0 20000080 [8] 00 00 00 00 00 00 38 00 ERRORFRAME bus-error error-counter-tx-rx{{56}{0}} (000.002046) can0 20000080 [8] 00 00 00 00 00 00 40 00 ERRORFRAME bus-error error-counter-tx-rx{{64}{0}} (000.002076) can0 20000080 [8] 00 00 00 00 00 00 48 00 ERRORFRAME bus-error error-counter-tx-rx{{72}{0}} (000.002406) can0 20000080 [8] 00 00 00 00 00 00 50 00 ERRORFRAME bus-error error-counter-tx-rx{{80}{0}} (000.001969) can0 20000080 [8] 00 00 00 00 00 00 58 00 ERRORFRAME bus-error error-counter-tx-rx{{88}{0}} (000.002388) can0 20000084 [8] 00 08 00 00 00 00 60 00 ERRORFRAME controller-problem{tx-error-warning} bus-error error-counter-tx-rx{{96}{0}} (000.002021) can0 20000080 [8] 00 00 00 00 00 00 68 00 ERRORFRAME bus-error error-counter-tx-rx{{104}{0}} (000.002110) can0 20000080 [8] 00 00 00 00 00 00 70 00 ERRORFRAME bus-error error-counter-tx-rx{{112}{0}} (000.002155) can0 20000080 [8] 00 00 00 00 00 00 78 00 ERRORFRAME bus-error error-counter-tx-rx{{120}{0}} (000.002140) can0 20000084 [8] 00 20 00 00 00 00 80 00 ERRORFRAME controller-problem{tx-error-passive} bus-error error-counter-tx-rx{{128}{0}} (000.002324) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME bus-error error-counter-tx-rx{{128}{0}} (000.002416) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME bus-error error-counter-tx-rx{{128}{0}} (000.002237) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME bus-error error-counter-tx-rx{{128}{0}}(( Then a continous flood, exactly similar to the above packet, appears ))
<-- Short-circuit the can high and low wires -->
(000.002364) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME
bus-error error-counter-tx-rx{{128}{0}} (000.002108) can0 20000080 [8] 00 00 00 00 00 00 88 00 ERRORFRAME bus-error error-counter-tx-rx{{136}{0}} (000.000494) can0 20000080 [8] 00 00 00 00 00 00 90 00 ERRORFRAME bus-error error-counter-tx-rx{{144}{0}} (000.000523) can0 20000080 [8] 00 00 00 00 00 00 98 00 ERRORFRAME bus-error error-counter-tx-rx{{152}{0}} (000.000661) can0 20000080 [8] 00 00 00 00 00 00 A0 00 ERRORFRAME bus-error error-counter-tx-rx{{160}{0}} (000.000464) can0 20000080 [8] 00 00 00 00 00 00 A8 00 ERRORFRAME bus-error error-counter-tx-rx{{168}{0}} (000.000534) can0 20000080 [8] 00 00 00 00 00 00 B0 00 ERRORFRAME bus-error error-counter-tx-rx{{176}{0}} (000.000499) can0 20000080 [8] 00 00 00 00 00 00 B8 00 ERRORFRAME bus-error error-counter-tx-rx{{184}{0}} (000.000626) can0 20000080 [8] 00 00 00 00 00 00 C0 00 ERRORFRAME bus-error error-counter-tx-rx{{192}{0}} (000.000373) can0 20000080 [8] 00 00 00 00 00 00 C8 00 ERRORFRAME bus-error error-counter-tx-rx{{200}{0}} (000.000627) can0 20000080 [8] 00 00 00 00 00 00 D0 00 ERRORFRAME bus-error error-counter-tx-rx{{208}{0}} (000.000507) can0 20000080 [8] 00 00 00 00 00 00 D8 00 ERRORFRAME bus-error error-counter-tx-rx{{216}{0}} (000.000501) can0 20000080 [8] 00 00 00 00 00 00 E0 00 ERRORFRAME bus-error error-counter-tx-rx{{224}{0}} (000.000459) can0 20000080 [8] 00 00 00 00 00 00 E8 00 ERRORFRAME bus-error error-counter-tx-rx{{232}{0}} (000.000606) can0 20000080 [8] 00 00 00 00 00 00 F0 00 ERRORFRAME bus-error error-counter-tx-rx{{240}{0}} (000.000454) can0 20000080 [8] 00 00 00 00 00 00 F8 00 ERRORFRAME bus-error error-counter-tx-rx{{248}{0}}
Quoted 6 lines
(000.000664) can0 200000C0 [8] 00 00 00 00 00 00 00 00 ERRORFRAME
bus-off
bus-error(( No further bus activity ))
Bus-off seems OK. You could have just short circuited them without disconnecting.
Reverse state transitions are missing from the logs. See comments above.
--
Andri
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoted 2 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
Quoted 1 line
Hi!
...
Quoted 8 lines
Quoted 8 lines
<-- Unplug the cable -->
(000.009106) can0 20000080 [8] 00 00 00 00 00 00 08 00 ERRORFRAME
bus-error error-counter-tx-rx{{8}{0}} (000.001872) can0 20000080 [8] 00 00 00 00 00 00 10 00 ERRORFRAME bus-error error-counter-tx-rx{{16}{0}}
Quoted 10 lines
[...]
Quoted 6 lines
error-counter-tx-rx{{80}{0}} (000.001910) can0 20000080 [8] 00 00 00 00 00 00 58 00 ERRORFRAME bus-error error-counter-tx-rx{{88}{0}} (000.001753) can0 20000084 [8] 00 08 00 00 00 00 60 00 ERRORFRAME controller-problem{tx-error-warning}Good.
Quoted 2 lines
bus-error error-counter-tx-rx{{96}{0}}
Nice.
Quoted 11 lines
Quoted 11 lines
(000.001720) can0 20000080 [8] 00 00 00 00 00 00 68 00 ERRORFRAME
bus-error error-counter-tx-rx{{104}{0}} (000.001876) can0 20000080 [8] 00 00 00 00 00 00 70 00 ERRORFRAME bus-error error-counter-tx-rx{{112}{0}} (000.001749) can0 20000080 [8] 00 00 00 00 00 00 78 00 ERRORFRAME bus-error error-counter-tx-rx{{120}{0}} (000.001771) can0 20000084 [8] 00 20 00 00 00 00 80 00 ERRORFRAME controller-problem{tx-error-passive}
Quoted 3 lines
Also good.
Quoted 2 lines
bus-error error-counter-tx-rx{{128}{0}}
Also nice :-)
Quoted 7 lines
Quoted 7 lines
(000.001868) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME
bus-error error-counter-tx-rx{{128}{0}} (000.001982) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME bus-error error-counter-tx-rx{{128}{0}}
Quoted 7 lines
Quoted 5 lines
(( Then a continous flood, exactly similar to the above packet, appears.
Unfortunately this flooding is a firmware problem. ))<-- Replug the cable, after a good amount of time -->
Where are the reverse state transitions?
Quoted 1 line
Hmmm...
[ ... ]
Quoted 3 lines
Reverse state transitions are missing from the logs. See comments above.
When the device is on the _receiving_ end, and I unplug the CAN cable after introducing some noise to the level of reaching WARNING or PASSIVE, I receive a BUS_ERROR event with the rxerr count reset back to 0 or 1. In that case, the driver correctly transitions back the state to ERROR_ACTIVE and candump produces something similar to:
(000.000362) can0 2000008C [8] 00 40 40 00 00 00 00 01 ERRORFRAME
controller-problem{}
protocol-violation{{back-to-error-active}{}}
bus-error
error-counter-tx-rx{{0}{1}}which is, AFAIK, the correct behaviour from the driver side.
Meanwhile, when the device is on the _sending_ end and I re-plug the CAN cable again. Sometimes I receive events with txerr reset to 0 or 1, and the driver correctly reverts back to ERROR_ACTIVE in that case. But on another times like the quoted case above, I don't receive any events resetting txerr back -- only data packets on the bus.
So, What can the driver do given the above?
Thanks,
Darwish
P.S. just in case, I'll also re-check now if the driver unintentionally drops any important events resetting the txerr count back after a CAN cable replug -- preventing the code from returning to ERROR_ACTIVE in the process.
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoted 6 lines · Ahmed S. Darwish
Quoted 2 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
Quoted 1 line
Hi!
...
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
<-- Unplug the cable -->
(000.009106) can0 20000080 [8] 00 00 00 00 00 00 08 00
ERRORFRAMEbus-error error-counter-tx-rx{{8}{0}}(000.001872) can0 20000080 [8] 00 00 00 00 00 00 10 00
For a bus-errors I would also expcect some more information in the data[2..3] fields. But these are always zero.
Quoted 52 lines
Quoted 12 lines
Quoted 3 lines
ERRORFRAME
bus-error error-counter-tx-rx{{16}{0}}[...]
Quoted 8 lines
error-counter-tx-rx{{80}{0}} (000.001910) can0 20000080 [8] 00 00 00 00 00 00 58 00 ERRORFRAME bus-error error-counter-tx-rx{{88}{0}} (000.001753) can0 20000084 [8] 00 08 00 00 00 00 60 00 ERRORFRAME controller-problem{tx-error-warning}Quoted 3 lines
Good.
Quoted 2 lines
bus-error error-counter-tx-rx{{96}{0}}Nice.
Quoted 15 lines
Quoted 15 lines
(000.001720) can0 20000080 [8] 00 00 00 00 00 00 68 00
ERRORFRAMEbus-error error-counter-tx-rx{{104}{0}} (000.001876) can0 20000080 [8] 00 00 00 00 00 00 70 00 ERRORFRAME bus-error error-counter-tx-rx{{112}{0}} (000.001749) can0 20000080 [8] 00 00 00 00 00 00 78 00 ERRORFRAME bus-error error-counter-tx-rx{{120}{0}} (000.001771) can0 20000084 [8] 00 20 00 00 00 00 80 00 ERRORFRAME controller-problem{tx-error-passive}Quoted 3 lines
Also good.
Quoted 2 lines
bus-error error-counter-tx-rx{{128}{0}}Also nice :-)
Quoted 13 lines
Quoted 13 lines
(000.001868) can0 20000080 [8] 00 00 00 00 00 00 80 00
ERRORFRAMEbus-error error-counter-tx-rx{{128}{0}} (000.001982) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME bus-error error-counter-tx-rx{{128}{0}}(( Then a continous flood, exactly similar to the above packet, appears.
Unfortunately this flooding is a firmware problem. ))
Quoted 10 lines
Quoted 4 lines
Quoted 2 lines
<-- Replug the cable, after a good amount of time -->
Where are the reverse state transitions?
Quoted 1 line
Hmmm...
[ ... ]
Quoted 2 lines
Reverse state transitions are missing from the logs. See comments
above.
Quoted 3 lines
Quoted 1 line
When the device is on the _receiving_ end, and I unplug the CAN cable
after
Quoted 3 lines
introducing some noise to the level of reaching WARNING or PASSIVE, I receive a
BUS_ERRORevent with the rxerr count reset back to 0 or 1. In that case, the driver correctly transitions back the state to
ERROR_ACTIVE
Quoted 9 lines
and candump produces something similar to:
(000.000362) can0 2000008C [8] 00 40 40 00 00 00 00 01 ERRORFRAME controller-problem{} protocol-violation{{back-to-error-active}{}} bus-error error-counter-tx-rx{{0}{1}}
Quoted 7 lines
which is, AFAIK, the correct behaviour from the driver side.
Meanwhile, when the device is on the _sending_ end and I re-plug the CAN cable again. Sometimes I receive events with txerr reset to 0 or 1, and the driver correctly reverts back to
ERROR_ACTIVEin that case. But on another times like the quoted case above, I don't receive any events resetting txerr back -- only data packets on the bus.
Well, the firmware seems to report *only* bus-errors via CMD_CAN_ERROR_EVENT
messages, also carrying the new state, but no CMD_CHIP_STATE_EVENT just for
the state changes.
Quoted 1 line
So, What can the driver do given the above?
Little if the notification does not come.
Wolfgang.
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoted 10 lines · Wolfgang Grandegger
Quoted 8 lines · Ahmed S. Darwish
Quoted 2 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
Quoted 1 line
Hi!
...
Quoted 2 lines
Quoted 2 lines
<-- Unplug the cable -->
Quoted 9 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
(000.009106) can0 20000080 [8] 00 00 00 00 00 00 08 00
ERRORFRAMEbus-error error-counter-tx-rx{{8}{0}}(000.001872) can0 20000080 [8] 00 00 00 00 00 00 10 00
For a bus-errors I would also expcect some more information in the data[2..3] fields. But these are always zero.
M16C error factors made it possible to report things like CAN_ERR_PROT_FORM/STUFF/BIT0/BIT1/TX in data[2], and CAN_ERR_PROT_LOC_ACK/CRC_DEL in data[3].
Unfortunately such error factors are only reported in Leaf, but not in USBCan-II due to the wire format change in the error event:
struct leaf_msg_error_event {
u8 tid;
u8 flags;
__le16 time[3];
u8 channel;
u8 padding;
u8 tx_errors_count;
u8 rx_errors_count;
u8 status;
u8 error_factor;
} __packed;
struct usbcan_msg_error_event {
u8 tid;
u8 padding;
u8 tx_errors_count_ch0;
u8 rx_errors_count_ch0;
u8 tx_errors_count_ch1;
u8 rx_errors_count_ch1;
u8 status_ch0;
u8 status_ch1;
__le16 time;
} __packed;I speculate that the wire format was changed due to controller bugs in the USBCan-II, which was slightly mentioned in their data sheets here:
http://www.kvaser.com/canlib-webhelp/page_hardware_specific_can_controllers.html
So it seems there's really no way for filling such bus error info given the very limited amount of data exported :-(
The issue of incomplete data does not even stop here, kindly check below notes regarding reverse state transitions:
Quoted 88 lines
Quoted 52 lines
Quoted 12 lines
Quoted 3 lines
ERRORFRAME
bus-error error-counter-tx-rx{{16}{0}}[...]
Quoted 8 lines
error-counter-tx-rx{{80}{0}} (000.001910) can0 20000080 [8] 00 00 00 00 00 00 58 00 ERRORFRAME bus-error error-counter-tx-rx{{88}{0}} (000.001753) can0 20000084 [8] 00 08 00 00 00 00 60 00 ERRORFRAME controller-problem{tx-error-warning}Quoted 3 lines
Good.
Quoted 2 lines
bus-error error-counter-tx-rx{{96}{0}}Nice.
Quoted 15 lines
Quoted 15 lines
(000.001720) can0 20000080 [8] 00 00 00 00 00 00 68 00
ERRORFRAMEbus-error error-counter-tx-rx{{104}{0}} (000.001876) can0 20000080 [8] 00 00 00 00 00 00 70 00 ERRORFRAME bus-error error-counter-tx-rx{{112}{0}} (000.001749) can0 20000080 [8] 00 00 00 00 00 00 78 00 ERRORFRAME bus-error error-counter-tx-rx{{120}{0}} (000.001771) can0 20000084 [8] 00 20 00 00 00 00 80 00 ERRORFRAME controller-problem{tx-error-passive}Quoted 3 lines
Also good.
Quoted 2 lines
bus-error error-counter-tx-rx{{128}{0}}Also nice :-)
Quoted 13 lines
Quoted 13 lines
(000.001868) can0 20000080 [8] 00 00 00 00 00 00 80 00
ERRORFRAMEbus-error error-counter-tx-rx{{128}{0}} (000.001982) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME bus-error error-counter-tx-rx{{128}{0}}(( Then a continous flood, exactly similar to the above packet, appears.
Unfortunately this flooding is a firmware problem. ))Quoted 10 lines
Quoted 4 lines
Quoted 2 lines
<-- Replug the cable, after a good amount of time -->
Where are the reverse state transitions?
Quoted 1 line
Hmmm...
[ ... ]
Quoted 2 lines
Reverse state transitions are missing from the logs. See comments
above.
Quoted 3 lines
Quoted 1 line
When the device is on the _receiving_ end, and I unplug the CAN cable
after
Quoted 3 lines
introducing some noise to the level of reaching WARNING or PASSIVE, I receive a
BUS_ERRORevent with the rxerr count reset back to 0 or 1. In that case, the driver correctly transitions back the state to
ERROR_ACTIVEQuoted 9 lines
and candump produces something similar to:
(000.000362) can0 2000008C [8] 00 40 40 00 00 00 00 01 ERRORFRAME controller-problem{} protocol-violation{{back-to-error-active}{}} bus-error error-counter-tx-rx{{0}{1}}Quoted 7 lines
which is, AFAIK, the correct behaviour from the driver side.
Meanwhile, when the device is on the _sending_ end and I re-plug the CAN cable again. Sometimes I receive events with txerr reset to 0 or 1, and the driver correctly reverts back to
ERROR_ACTIVEin that case. But on another times like the quoted case above, I don't receive any events resetting txerr back -- only data packets on the bus.
Quoted 4 lines
Well, the firmware seems to report *only* bus-errors via
CMD_CAN_ERROR_EVENTmessages, also carrying the new state, but noCMD_CHIP_STATE_EVENTjust for the state changes.
I've dumped _every_ message I receive from the firmware while disconnecting the CAN bus, waiting a while, and connecting it again. I really received _nothing_ from the firmware when the CAN bus was reconnected and the data packets were flowing again. Not even a single CHIP_STATE_EVENT, even after waiting for a long time.
So it's basically:
...
ERR EVENT, txerr=128, rxerr=0
ERR EVENT, txerr=128, rxerr=0
ERR EVENT, txerr=128, rxerr=0
...
then complete silence, except the data frames. I've even tried with different versions of the firmware, but the same behaviour persisted.
Quoted 4 lines
Quoted 1 line
So, What can the driver do given the above?
Little if the notification does not come.
We can poll the state by sending CMD_GET_CHIP_STATE to the firmware, and it will hopefully reply with a CHIP_STATE_EVENT response containing the new txerr and rxerr values that we can use for reverse state transitions.
But do we _really_ want to go through the path? I feel that it will open some cans of worms w.r.t. concurrent access to both the netdev and USB stacks from a single driver.
A possible solution can be setting up a kernel thread that queries for a CHIP_STATE_EVENT every second?
Your inputs on this is appreciated.
Quoted 2 lines
Wolfgang.
Regards,
Darwish
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoting Ahmed S. Darwish (2015-01-23 06:07:34)
Quoted 52 lines · Wolfgang Grandegger
Quoted 10 lines
Quoted 8 lines · Ahmed S. Darwish
Quoted 2 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
Quoted 1 line
Hi!
...
Quoted 2 lines
Quoted 2 lines
<-- Unplug the cable -->
Quoted 9 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
(000.009106) can0 20000080 [8] 00 00 00 00 00 00 08 00
ERRORFRAMEbus-error error-counter-tx-rx{{8}{0}}(000.001872) can0 20000080 [8] 00 00 00 00 00 00 10 00
For a bus-errors I would also expcect some more information in the data[2..3] fields. But these are always zero.
M16C error factors made it possible to report things like CAN_ERR_PROT_FORM/STUFF/BIT0/BIT1/TX in data[2], and CAN_ERR_PROT_LOC_ACK/CRC_DEL in data[3].
Unfortunately such error factors are only reported in Leaf, but not in USBCan-II due to the wire format change in the error event:
struct leaf_msg_error_event { u8 tid; u8 flags; __le16 time[3]; u8 channel; u8 padding; u8 tx_errors_count; u8 rx_errors_count; u8 status; u8 error_factor; } __packed; struct usbcan_msg_error_event { u8 tid; u8 padding; u8 tx_errors_count_ch0; u8 rx_errors_count_ch0; u8 tx_errors_count_ch1; u8 rx_errors_count_ch1; u8 status_ch0; u8 status_ch1; __le16 time; } __packed;
Quoted 9 lines
I speculate that the wire format was changed due to controller bugs in the USBCan-II, which was slightly mentioned in their data sheets here:
http://www.kvaser.com/canlib-webhelp/page_hardware_specific_can_controllers.html
So it seems there's really no way for filling such bus error info given the very limited amount of data exported :-(
We experienced similar problems with FlexCAN.
Quoted 8 lines
The issue of incomplete data does not even stop here, kindly check below notes regarding reverse state transitions:
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
ERRORFRAME
bus-error error-counter-tx-rx{{16}{0}}[...]
[...]
Quoted 70 lines
Quoted 44 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
ERRORFRAME
bus-error error-counter-tx-rx{{128}{0}}(( Then a continous flood, exactly similar to the above packet, appears.
Unfortunately this flooding is a firmware problem. ))Quoted 10 lines
Quoted 4 lines
Quoted 2 lines
<-- Replug the cable, after a good amount of time -->
Where are the reverse state transitions?
Quoted 1 line
Hmmm...
[ ... ]
Quoted 2 lines
Reverse state transitions are missing from the logs. See comments
above.
Quoted 3 lines
Quoted 1 line
When the device is on the _receiving_ end, and I unplug the CAN cable
after
Quoted 3 lines
introducing some noise to the level of reaching WARNING or PASSIVE, I receive a
BUS_ERRORevent with the rxerr count reset back to 0 or 1. In that case, the driver correctly transitions back the state to
ERROR_ACTIVEQuoted 9 lines
and candump produces something similar to:
(000.000362) can0 2000008C [8] 00 40 40 00 00 00 00 01 ERRORFRAME controller-problem{} protocol-violation{{back-to-error-active}{}} bus-error error-counter-tx-rx{{0}{1}}Quoted 7 lines
which is, AFAIK, the correct behaviour from the driver side.
Meanwhile, when the device is on the _sending_ end and I re-plug the CAN cable again. Sometimes I receive events with txerr reset to 0 or 1, and the driver correctly reverts back to
ERROR_ACTIVEin that case. But on another times like the quoted case above, I don't receive any events resetting txerr back -- only data packets on the bus.Quoted 4 lines
Well, the firmware seems to report *only* bus-errors via
CMD_CAN_ERROR_EVENTmessages, also carrying the new state, but noCMD_CHIP_STATE_EVENTjust for the state changes.I've dumped _every_ message I receive from the firmware while disconnecting the CAN bus, waiting a while, and connecting it again. I really received _nothing_ from the firmware when the CAN bus was reconnected and the data packets were flowing again. Not even a single
CHIP_STATE_EVENT, even after waiting for a long time.So it's basically:
...
ERR EVENT, txerr=128, rxerr=0
ERR EVENT, txerr=128, rxerr=0
ERR EVENT, txerr=128, rxerr=0
...then complete silence, except the data frames. I've even tried with different versions of the firmware, but the same behaviour persisted.
Quoted 4 lines
Quoted 1 line
So, What can the driver do given the above?
Little if the notification does not come.
Quoted 9 lines
We can poll the state by sending
CMD_GET_CHIP_STATEto the firmware, and it will hopefully reply with aCHIP_STATE_EVENTresponse containing the new txerr and rxerr values that we can use for reverse state transitions.But do we _really_ want to go through the path? I feel that it will open some cans of worms w.r.t. concurrent access to both the netdev and USB stacks from a single driver.
Honestly, I don't know.
Quoted 4 lines
A possible solution can be setting up a kernel thread that queries for a
CHIP_STATE_EVENTevery second?
Have you considered polling in kvaser_usb_tx_acknowledge? You could do something like:if(unlikely(dev->can.state != CAN_STATE_ERROR_ACTIVE))
{
request_state();
}I don't think that anything beyond that would be worth pursuing.
Best regards,
Andri
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoted 57 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-23 06:07:34)
Quoted 56 lines · Wolfgang Grandegger
Quoted 10 lines
Quoted 8 lines · Ahmed S. Darwish
Quoted 2 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
Quoted 1 line
Hi!
...
Quoted 2 lines
Quoted 2 lines
<-- Unplug the cable -->
Quoted 9 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
(000.009106) can0 20000080 [8] 00 00 00 00 00 00 08 00
ERRORFRAMEbus-error error-counter-tx-rx{{8}{0}}(000.001872) can0 20000080 [8] 00 00 00 00 00 00 10 00
For a bus-errors I would also expcect some more information in the data[2..3] fields. But these are always zero.
M16C error factors made it possible to report things like CAN_ERR_PROT_FORM/STUFF/BIT0/BIT1/TX in data[2], and CAN_ERR_PROT_LOC_ACK/CRC_DEL in data[3].
Unfortunately such error factors are only reported in Leaf, but not in USBCan-II due to the wire format change in the error event:
struct leaf_msg_error_event { u8 tid; u8 flags; __le16 time[3]; u8 channel; u8 padding; u8 tx_errors_count; u8 rx_errors_count; u8 status; u8 error_factor; } __packed; struct usbcan_msg_error_event { u8 tid; u8 padding; u8 tx_errors_count_ch0; u8 rx_errors_count_ch0; u8 tx_errors_count_ch1; u8 rx_errors_count_ch1; u8 status_ch0; u8 status_ch1; __le16 time; } __packed;I speculate that the wire format was changed due to controller bugs in the USBCan-II, which was slightly mentioned in their data sheets here:
Quoted 6 lines
Quoted 5 lines
http://www.kvaser.com/canlib-webhelp/page_hardware_specific_can_controllers.html
So it seems there's really no way for filling such bus error info given the very limited amount of data exported :-(
We experienced similar problems with FlexCAN.
Hmm, I'll have a look there then...
Although my initial instincts imply that the FlexCAN driver has access to the raw CAN registers, something I'm unable to do here. But maybe there's some black magic I'm missing :-)
[...]
Quoted 36 lines
Quoted 22 lines
I've dumped _every_ message I receive from the firmware while disconnecting the CAN bus, waiting a while, and connecting it again. I really received _nothing_ from the firmware when the CAN bus was reconnected and the data packets were flowing again. Not even a single
CHIP_STATE_EVENT, even after waiting for a long time.So it's basically:
...
ERR EVENT, txerr=128, rxerr=0
ERR EVENT, txerr=128, rxerr=0
ERR EVENT, txerr=128, rxerr=0
...then complete silence, except the data frames. I've even tried with different versions of the firmware, but the same behaviour persisted.
Quoted 4 lines
Quoted 1 line
So, What can the driver do given the above?
Little if the notification does not come.
Quoted 9 lines
We can poll the state by sending
CMD_GET_CHIP_STATEto the firmware, and it will hopefully reply with aCHIP_STATE_EVENTresponse containing the new txerr and rxerr values that we can use for reverse state transitions.But do we _really_ want to go through the path? I feel that it will open some cans of worms w.r.t. concurrent access to both the netdev and USB stacks from a single driver.
Honestly, I don't know.
Quoted 4 lines
A possible solution can be setting up a kernel thread that queries for a
CHIP_STATE_EVENTevery second?
Quoted 7 lines
Have you considered polling in
kvaser_usb_tx_acknowledge? You could do something like:if(unlikely(dev->can.state != CAN_STATE_ERROR_ACTIVE)){ request_state(); }
OK, I have four important updates on this issue:
a) My initial testing was done on high-speed channel, at a bitrate of 50K. After setting the bus to a more reasonable bitrate 500K or 1M, I was _consistently_ able to receive CHIP_STATE_EVENTs when plugging the CAN connector again after an unplug.
b) The error counters on this device do not get reset on plugging after an unplug. I've setup a kernel thread [2] that queries the chip state event every second, and the error counters stays the same all the time. [1]
c) There's a single case when the erro counters do indeed get reversed, and it happens only when introducing some noise in the bus after the re-plug. In that case, the new error events get raised with new error counters starting from 0/1 again.
d) I've discovered a bug that forbids the CAN state from returning to ERROR_ACTIVE in case of the error counters numbers getting decreased. But independent from that bug, the verbose debugging messages clearly imply that we only get the error counters decreased in the case mentioned at `c)' above.
So from [1] and [2], it's now clear that the device do not reset these counters back in the re-plug case. I'll give a check to flexcan as advised, but unfortunately I don't really think there's much I can do about this.
[1]
[ 877.207082] CAN_ERROR_: channel=0, txerr=88, rxerr=0 [ 877.207090] CAN_ERROR_: channel=0, txerr=136, rxerr=0 [ 877.207094] CAN_ERROR_: channel=0, txerr=144, rxerr=0 [ 877.207098] CAN_ERROR_: channel=0, txerr=152, rxerr=0 [ 877.207100] CAN_ERROR_: channel=0, txerr=160, rxerr=0 [ 877.207102] CAN_ERROR_: channel=0, txerr=168, rxerr=0 [ 877.208075] CAN_ERROR_: channel=0, txerr=200, rxerr=0
(( The above error event, staying the same at txerr=200 keeps
flooding the bus until the CAN cable is re-plugged ))
[ 878.225116] CHIP_STATE: channel=0, txerr=200, rxerr=0 [ 878.225143] CHIP_STATE: channel=1, txerr=0, rxerr=0 [ 879.265167] CHIP_STATE: channel=0, txerr=200, rxerr=0 [ 879.267152] CHIP_STATE: channel=1, txerr=0, rxerr=0 [ 879.265167] CHIP_STATE: channel=0, txerr=200, rxerr=0 [ 879.267152] CHIP_STATE: channel=1, txerr=0, rxerr=0
(( The same counters get repeated every second ))
[2] State was polled using:
static int kvaser_usb_poll_chip_state(void *vpriv) {
struct kvaser_usb_net_priv *priv = vpriv;
while (!kthread_should_stop()) {
kvaser_usb_simple_msg_async(priv, CMD_GET_CHIP_STATE);
ssleep(1);
}
return 0;
}Quoted 2 lines
I don't think that anything beyond that would be worth pursuing.
I agree, but given the new input, it seems that our problem extends to the error counters themselves not getting decreased on re-plug. So, even polling will not solve the issue: we'll get the same txerr/rxerr values again and again :-(
Quoted 2 lines
Best regards,
Andri
Regards,
Darwish
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoting Ahmed S. Darwish (2015-01-25 02:43:00)
Quoted 63 lines · Andri Yngvason
Quoted 62 lines
Quoting Ahmed S. Darwish (2015-01-23 06:07:34)
Quoted 61 lines · Wolfgang Grandegger
Quoted 10 lines
Quoted 8 lines · Ahmed S. Darwish
Quoted 2 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
Quoted 1 line
Hi!
...
Quoted 2 lines
Quoted 2 lines
<-- Unplug the cable -->
Quoted 9 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
(000.009106) can0 20000080 [8] 00 00 00 00 00 00 08 00
ERRORFRAMEbus-error error-counter-tx-rx{{8}{0}}(000.001872) can0 20000080 [8] 00 00 00 00 00 00 10 00
For a bus-errors I would also expcect some more information in the data[2..3] fields. But these are always zero.
M16C error factors made it possible to report things like CAN_ERR_PROT_FORM/STUFF/BIT0/BIT1/TX in data[2], and CAN_ERR_PROT_LOC_ACK/CRC_DEL in data[3].
Unfortunately such error factors are only reported in Leaf, but not in USBCan-II due to the wire format change in the error event:
struct leaf_msg_error_event { u8 tid; u8 flags; __le16 time[3]; u8 channel; u8 padding; u8 tx_errors_count; u8 rx_errors_count; u8 status; u8 error_factor; } __packed; struct usbcan_msg_error_event { u8 tid; u8 padding; u8 tx_errors_count_ch0; u8 rx_errors_count_ch0; u8 tx_errors_count_ch1; u8 rx_errors_count_ch1; u8 status_ch0; u8 status_ch1; __le16 time; } __packed;I speculate that the wire format was changed due to controller bugs in the USBCan-II, which was slightly mentioned in their data sheets here:
http://www.kvaser.com/canlib-webhelp/page_hardware_specific_can_controllers.html
So it seems there's really no way for filling such bus error info given the very limited amount of data exported :-(
Quoted 8 lines
Quoted 1 line
We experienced similar problems with FlexCAN.
Hmm, I'll have a look there then...
Although my initial instincts imply that the FlexCAN driver has access to the raw CAN registers, something I'm unable to do here. But maybe there's some black magic I'm missing :-)
Yes, it's memory mapped.
Quoted 110 lines
[...]
Quoted 36 lines
Quoted 22 lines
I've dumped _every_ message I receive from the firmware while disconnecting the CAN bus, waiting a while, and connecting it again. I really received _nothing_ from the firmware when the CAN bus was reconnected and the data packets were flowing again. Not even a single
CHIP_STATE_EVENT, even after waiting for a long time.So it's basically:
...
ERR EVENT, txerr=128, rxerr=0
ERR EVENT, txerr=128, rxerr=0
ERR EVENT, txerr=128, rxerr=0
...then complete silence, except the data frames. I've even tried with different versions of the firmware, but the same behaviour persisted.
Quoted 4 lines
Quoted 1 line
So, What can the driver do given the above?
Little if the notification does not come.
Quoted 9 lines
We can poll the state by sending
CMD_GET_CHIP_STATEto the firmware, and it will hopefully reply with aCHIP_STATE_EVENTresponse containing the new txerr and rxerr values that we can use for reverse state transitions.But do we _really_ want to go through the path? I feel that it will open some cans of worms w.r.t. concurrent access to both the netdev and USB stacks from a single driver.
Honestly, I don't know.
Quoted 4 lines
A possible solution can be setting up a kernel thread that queries for a
CHIP_STATE_EVENTevery second?Quoted 7 lines
Have you considered polling in
kvaser_usb_tx_acknowledge? You could do something like:if(unlikely(dev->can.state != CAN_STATE_ERROR_ACTIVE)){ request_state(); }OK, I have four important updates on this issue:
a) My initial testing was done on high-speed channel, at a bitrate of 50K. After setting the bus to a more reasonable bitrate 500K or 1M, I was _consistently_ able to receive
CHIP_STATE_EVENTswhen plugging the CAN connector again after an unplug.b) The error counters on this device do not get reset on plugging after an unplug. I've setup a kernel thread [2] that queries the chip state event every second, and the error counters stays the same all the time. [1]
c) There's a single case when the erro counters do indeed get reversed, and it happens only when introducing some noise in the bus after the re-plug. In that case, the new error events get raised with new error counters starting from 0/1 again.
d) I've discovered a bug that forbids the CAN state from returning to
ERROR_ACTIVEin case of the error counters numbers getting decreased. But independent from that bug, the verbose debugging messages clearly imply that we only get the error counters decreased in the case mentioned at `c)' above.So from [1] and [2], it's now clear that the device do not reset these counters back in the re-plug case. I'll give a check to flexcan as advised, but unfortunately I don't really think there's much I can do about this.
[1]
[ 877.207082] CAN_ERROR_: channel=0, txerr=88, rxerr=0 [ 877.207090] CAN_ERROR_: channel=0, txerr=136, rxerr=0 [ 877.207094] CAN_ERROR_: channel=0, txerr=144, rxerr=0 [ 877.207098] CAN_ERROR_: channel=0, txerr=152, rxerr=0 [ 877.207100] CAN_ERROR_: channel=0, txerr=160, rxerr=0 [ 877.207102] CAN_ERROR_: channel=0, txerr=168, rxerr=0 [ 877.208075] CAN_ERROR_: channel=0, txerr=200, rxerr=0(( The above error event, staying the same at txerr=200 keeps
flooding the bus until the CAN cable is re-plugged ))[ 878.225116] CHIP_STATE: channel=0, txerr=200, rxerr=0 [ 878.225143] CHIP_STATE: channel=1, txerr=0, rxerr=0 [ 879.265167] CHIP_STATE: channel=0, txerr=200, rxerr=0 [ 879.267152] CHIP_STATE: channel=1, txerr=0, rxerr=0 [ 879.265167] CHIP_STATE: channel=0, txerr=200, rxerr=0 [ 879.267152] CHIP_STATE: channel=1, txerr=0, rxerr=0(( The same counters get repeated every second ))
[2] State was polled using:
static int kvaser_usb_poll_chip_state(void *vpriv) { struct kvaser_usb_net_priv *priv = vpriv; while (!kthread_should_stop()) { kvaser_usb_simple_msg_async(priv, CMD_GET_CHIP_STATE); ssleep(1); } return 0; }
Quoted 8 lines
Quoted 2 lines
I don't think that anything beyond that would be worth pursuing.
I agree, but given the new input, it seems that our problem extends to the error counters themselves not getting decreased on re-plug. So, even polling will not solve the issue: we'll get the same txerr/rxerr values again and again :-(
Well, that's a damn shame. Not much you can do about that.
Best regards,
Andri
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
In reply to Ahmed S. DarwishQuoting Ahmed S. Darwish (2015-01-21 15:36:47)
Quoted 80 lines · Andri Yngvason
Quoted 2 lines
Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
Quoted 1 line
Hi!
...
Quoted 8 lines
Quoted 8 lines
<-- Unplug the cable -->
(000.009106) can0 20000080 [8] 00 00 00 00 00 00 08 00 ERRORFRAME
bus-error error-counter-tx-rx{{8}{0}} (000.001872) can0 20000080 [8] 00 00 00 00 00 00 10 00 ERRORFRAME bus-error error-counter-tx-rx{{16}{0}}Quoted 10 lines
[...]
Quoted 6 lines
error-counter-tx-rx{{80}{0}} (000.001910) can0 20000080 [8] 00 00 00 00 00 00 58 00 ERRORFRAME bus-error error-counter-tx-rx{{88}{0}} (000.001753) can0 20000084 [8] 00 08 00 00 00 00 60 00 ERRORFRAME controller-problem{tx-error-warning}Good.
Quoted 2 lines
bus-error error-counter-tx-rx{{96}{0}}Nice.
Quoted 11 lines
Quoted 11 lines
(000.001720) can0 20000080 [8] 00 00 00 00 00 00 68 00 ERRORFRAME
bus-error error-counter-tx-rx{{104}{0}} (000.001876) can0 20000080 [8] 00 00 00 00 00 00 70 00 ERRORFRAME bus-error error-counter-tx-rx{{112}{0}} (000.001749) can0 20000080 [8] 00 00 00 00 00 00 78 00 ERRORFRAME bus-error error-counter-tx-rx{{120}{0}} (000.001771) can0 20000084 [8] 00 20 00 00 00 00 80 00 ERRORFRAME controller-problem{tx-error-passive}Quoted 3 lines
Also good.
Quoted 2 lines
bus-error error-counter-tx-rx{{128}{0}}Also nice :-)
Quoted 7 lines
Quoted 7 lines
(000.001868) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME
bus-error error-counter-tx-rx{{128}{0}} (000.001982) can0 20000080 [8] 00 00 00 00 00 00 80 00 ERRORFRAME bus-error error-counter-tx-rx{{128}{0}}Quoted 7 lines
Quoted 5 lines
(( Then a continous flood, exactly similar to the above packet, appears.
Unfortunately this flooding is a firmware problem. ))<-- Replug the cable, after a good amount of time -->
Where are the reverse state transitions?
Quoted 1 line
Hmmm...
[ ... ]
Quoted 3 lines
Reverse state transitions are missing from the logs. See comments above.
When the device is on the _receiving_ end, and I unplug the CAN cable after introducing some noise to the level of reaching WARNING or PASSIVE, I receive a
BUS_ERRORevent with the rxerr count reset back to 0 or 1. In that case, the driver correctly transitions back the state toERROR_ACTIVEand candump produces something similar to:(000.000362) can0 2000008C [8] 00 40 40 00 00 00 00 01 ERRORFRAME controller-problem{} protocol-violation{{back-to-error-active}{}} bus-error error-counter-tx-rx{{0}{1}}which is, AFAIK, the correct behaviour from the driver side.
Quoted 8 lines
Meanwhile, when the device is on the _sending_ end and I re-plug the CAN cable again. Sometimes I receive events with txerr reset to 0 or 1, and the driver correctly reverts back to
ERROR_ACTIVEin that case. But on another times like the quoted case above, I don't receive any events resetting txerr back -- only data packets on the bus.So, What can the driver do given the above?
So what you're telling us is that the state does not got back to error-active unless there is something else transmitting on the bus?
If that's the case, it's almost definitely because state changes aren't triggering interrupts.
An rx event will give you an interrupt which yields a napi poll which means that the state will be polled, so in that case you don't need the interrupts.
Look for "Consolidate and unify state change handling" on gmane. There was a lot of discussion about this kind of issues, especially regarding FlexCAN.
Best regards,
Andri
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
In reply to Ahmed S. DarwishQuoting Ahmed S. Darwish (2015-01-20 21:45:37)
Quoted 57 lines
From: Ahmed S. Darwish <[email protected]>
Replace most of the can interface's state and error counters handling with the new can-dev
can_change_state()mechanism.Suggested-by Andri Yngvason <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 59 deletions(-)drivers/net/can/usb/kvaser_usb.c +11
-16@@ -620,40 +620,43 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) }static void kvaser_usb_rx_error_update_can_state (struct kvaser_usb_net_priv *priv, -const struct kvaser_usb_error_summary *es) +const struct kvaser_usb_error_summary *es, +struct can_frame *cf) {struct net_device_stats *stats; -enum can_state new_state; - - stats = &priv->netdev->stats; - new_state = priv->can.state; +enum can_state cur_state, new_state, tx_state, rx_state;netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (es->status &M16C_STATE_BUS_OFF ) { - priv->can.can_stats.bus_off++; + stats = &priv->netdev->stats; + new_state = cur_state = priv->can.state; + +if (es->status &M16C_STATE_BUS_OFF ) new_state =CAN_STATE_BUS_OFF ; - }else if (es->status &M16C_STATE_BUS_PASSIVE ) { -if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) - priv->can.can_stats.error_passive++; +else if (es->status &M16C_STATE_BUS_PASSIVE ) new_state =CAN_STATE_ERROR_PASSIVE ; - }if (es->status ==M16C_STATE_BUS_ERROR ) { -if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((es->txerr >=96 ) || (es->rxerr >=96 ))) { - priv->can.can_stats.error_warning++; +if ((cur_state <CAN_STATE_ERROR_WARNING ) && + ((es->txerr >=96 ) || (es->rxerr >=96 ))) new_state =CAN_STATE_ERROR_WARNING ; - }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { +else if (cur_state >CAN_STATE_ERROR_ACTIVE ) new_state =CAN_STATE_ERROR_ACTIVE ; - }
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 654
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +5
-0}if (!es->status) new_state =CAN_STATE_ERROR_ACTIVE ; +if (new_state != cur_state) { + tx_state = (es->txerr >= es->rxerr) ? new_state :0 ; + rx_state = (es->txerr <= es->rxerr) ? new_state :0 ; + +can_change_state (priv->netdev, cf, tx_state, rx_state);
This (below) is redundant. It doesn't harm but at this point can_change_state has set priv->can.state to new_state.
Quoted 70 lines
drivers/net/can/usb/kvaser_usb.c +17
-20+ new_state = priv->can.state; + } +if (priv->can.restart_ms && - (priv->can.state >=CAN_STATE_BUS_OFF ) && + (cur_state >=CAN_STATE_BUS_OFF ) && (new_state <CAN_STATE_BUS_OFF )) { priv->can.can_stats.restarts++; }@@ -665,18 +668,17 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri priv->bec.txerr = es->txerr; priv->bec.rxerr = es->rxerr; - priv->can.state = new_state; }static void kvaser_usb_rx_error (const struct kvaser_usb *dev,const struct kvaser_msg *msg) { -struct can_frame *cf; +struct can_frame *cf, tmp_cf = { .can_id =CAN_ERR_FLAG , .can_dlc =CAN_ERR_DLC };struct sk_buff *skb;struct net_device_stats *stats;struct kvaser_usb_net_priv *priv;struct kvaser_usb_error_summary es = { }; -enum can_state old_state; +enum can_state old_state, new_state;switch (msg->id) {case CMD_CAN_ERROR_EVENT :@@ -721,60 +723,54 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, }/* Update all of the can interface's state and error counters before -* trying any skb allocation that can actually fail with -ENOMEM. +* 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_rx_error_update_can_state (priv, &es); +kvaser_usb_rx_error_update_can_state (priv, &es, &tmp_cf); + new_state = priv->can.state; skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;return ; } +memcpy (cf, &tmp_cf,sizeof (*cf)); -if (es.status &M16C_STATE_BUS_OFF ) { - cf->can_id |=CAN_ERR_BUSOFF ; - -if (!priv->can.restart_ms) -kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); -netif_carrier_off (priv->netdev); - }else if (es.status &M16C_STATE_BUS_PASSIVE ) { -if (old_state !=CAN_STATE_ERROR_PASSIVE ) { - cf->can_id |=CAN_ERR_CRTL ; - -if (es.txerr || es.rxerr) - cf->data[1 ] = (es.txerr > es.rxerr) - ?CAN_ERR_CRTL_TX_PASSIVE - :CAN_ERR_CRTL_RX_PASSIVE ;
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 752
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +7
-3-else - cf->data[1 ] =CAN_ERR_CRTL_TX_PASSIVE | -CAN_ERR_CRTL_RX_PASSIVE ; +if (new_state != old_state) { +if (es.status &M16C_STATE_BUS_OFF ) { +if (!priv->can.restart_ms) +kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); +netif_carrier_off (priv->netdev); + } +
This block is wrong. The usage of PROT_ACTIVE is based on a misunderstanding. It's used in some drivers to signify back-to-error-active but its original meaning is something completely different, AFAIK.
This is handled in can_change_state() using a new CTRL message; namely:CAN_ERR_CTRL_ACTIVE. The newest version of can-utils is up to date with this.
Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c +8
-0+if (es.status ==M16C_STATE_BUS_ERROR ) { +if ((old_state >=CAN_STATE_ERROR_WARNING ) || + (es.txerr <96 && es.rxerr <96 )) { +if (old_state >CAN_STATE_ERROR_ACTIVE ) { + cf->can_id |=CAN_ERR_PROT ; + cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; + } + } }
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 762
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +0
-9- } -if (es.status ==M16C_STATE_BUS_ERROR ) { -if ((old_state <CAN_STATE_ERROR_WARNING ) && - ((es.txerr >=96 ) || (es.rxerr >=96 ))) { - cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (es.txerr > es.rxerr) - ?CAN_ERR_CRTL_TX_WARNING - :CAN_ERR_CRTL_RX_WARNING ; - }else if (old_state >CAN_STATE_ERROR_ACTIVE ) {
This is also redundant, and wrong:
Quoted 27 lines
drivers/net/can/usb/kvaser_usb.c +7
-11+if (!es.status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; } - } -if (!es.status) { - cf->can_id |=CAN_ERR_PROT ; - cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - } - -if (priv->can.restart_ms && - (old_state >=CAN_STATE_BUS_OFF ) && - (priv->can.state <CAN_STATE_BUS_OFF )) { - cf->can_id |=CAN_ERR_RESTARTED ; -netif_carrier_on (priv->netdev); +if (priv->can.restart_ms && + (old_state >=CAN_STATE_BUS_OFF ) && + (new_state <CAN_STATE_BUS_OFF )) { + cf->can_id |=CAN_ERR_RESTARTED ; +netif_carrier_on (priv->netdev); + } }if (es.error_factor) {Signature · 1 line
1.9.1
Looking over the patch again, I've noticed that there are a few things that are not quite right.
Marc, could you merge the "move bus_off++" patch before you merge this so that I won't have to incorporate this patch-set into it?
--
Andri
Marc Kleine-Budde
maintainerRe: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoted 2 lines · Andri Yngvason
Marc, could you merge the "move bus_off++" patch before you merge this so that I won't have to incorporate this patch-set into it?
...included in the lastest pull-request to David. Use tags/linux-can-next-for-3.20-20150121 of the can-next repo as you new base.
regards,
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoting Marc Kleine-Budde (2015-01-21 22:59:23)
Quoted 7 lines · Andri Yngvason
Quoted 2 lines
Marc, could you merge the "move bus_off++" patch before you merge this so that I won't have to incorporate this patch-set into it?
...included in the lastest pull-request to David. Use tags/linux-can-next-for-3.20-20150121 of the can-next repo as you new base.
Thanks!
--
Andri
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
Quoted 11 lines · Andri Yngvason
Quoting Marc Kleine-Budde (2015-01-21 22:59:23)
Quoted 7 lines · Andri Yngvason
Quoted 2 lines
Marc, could you merge the "move bus_off++" patch before you merge this so that I won't have to incorporate this patch-set into it?
...included in the lastest pull-request to David. Use tags/linux-can-next-for-3.20-20150121 of the can-next repo as you new base.
Thanks!
I guess I'll re-base my next submission over this tag too. Nothing in the new 5 patches is substantial enough to be included in the current kernel release.
Thanks!
Darwish
Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
In reply to Andri YngvasonHi!
Quoted 63 lines · Andri Yngvason
Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
Quoted 62 lines
From: Ahmed S. Darwish <[email protected]>
Replace most of the can interface's state and error counters handling with the new can-dev
can_change_state()mechanism.Suggested-by Andri Yngvason <[email protected]>Signed-off-by Ahmed S. Darwish <[email protected]>--- drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 59 deletions(-)drivers/net/can/usb/kvaser_usb.c +11
-16@@ -620,40 +620,43 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) }static void kvaser_usb_rx_error_update_can_state (struct kvaser_usb_net_priv *priv, -const struct kvaser_usb_error_summary *es) +const struct kvaser_usb_error_summary *es, +struct can_frame *cf) {struct net_device_stats *stats; -enum can_state new_state; - - stats = &priv->netdev->stats; - new_state = priv->can.state; +enum can_state cur_state, new_state, tx_state, rx_state;netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (es->status &M16C_STATE_BUS_OFF ) { - priv->can.can_stats.bus_off++; + stats = &priv->netdev->stats; + new_state = cur_state = priv->can.state; + +if (es->status &M16C_STATE_BUS_OFF ) new_state =CAN_STATE_BUS_OFF ; - }else if (es->status &M16C_STATE_BUS_PASSIVE ) { -if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) - priv->can.can_stats.error_passive++; +else if (es->status &M16C_STATE_BUS_PASSIVE ) new_state =CAN_STATE_ERROR_PASSIVE ; - }if (es->status ==M16C_STATE_BUS_ERROR ) { -if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((es->txerr >=96 ) || (es->rxerr >=96 ))) { - priv->can.can_stats.error_warning++; +if ((cur_state <CAN_STATE_ERROR_WARNING ) && + ((es->txerr >=96 ) || (es->rxerr >=96 ))) new_state =CAN_STATE_ERROR_WARNING ; - }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { +else if (cur_state >CAN_STATE_ERROR_ACTIVE ) new_state =CAN_STATE_ERROR_ACTIVE ; - } }if (!es->status) new_state =CAN_STATE_ERROR_ACTIVE ;
Quoted 12 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) · line 654
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +5
-0+if (new_state != cur_state) { + tx_state = (es->txerr >= es->rxerr) ? new_state :0 ; + rx_state = (es->txerr <= es->rxerr) ? new_state :0 ; + +can_change_state (priv->netdev, cf, tx_state, rx_state);This (below) is redundant. It doesn't harm but at this point
can_change_statehas setpriv->can.statetonew_state.Quoted 3 lines
drivers/net/can/usb/kvaser_usb.c +3
-0+ new_state = priv->can.state; + } +
Correct; I will remove it.
Quoted 75 lines
Quoted 75 lines
drivers/net/can/usb/kvaser_usb.c +19
-23if (priv->can.restart_ms && - (priv->can.state >=CAN_STATE_BUS_OFF ) && + (cur_state >=CAN_STATE_BUS_OFF ) && (new_state <CAN_STATE_BUS_OFF )) { priv->can.can_stats.restarts++; }@@ -665,18 +668,17 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri priv->bec.txerr = es->txerr; priv->bec.rxerr = es->rxerr; - priv->can.state = new_state; }static void kvaser_usb_rx_error (const struct kvaser_usb *dev,const struct kvaser_msg *msg) { -struct can_frame *cf; +struct can_frame *cf, tmp_cf = { .can_id =CAN_ERR_FLAG , .can_dlc =CAN_ERR_DLC };struct sk_buff *skb;struct net_device_stats *stats;struct kvaser_usb_net_priv *priv;struct kvaser_usb_error_summary es = { }; -enum can_state old_state; +enum can_state old_state, new_state;switch (msg->id) {case CMD_CAN_ERROR_EVENT :@@ -721,60 +723,54 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, }/* Update all of the can interface's state and error counters before -* trying any skb allocation that can actually fail with -ENOMEM. +* 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_rx_error_update_can_state (priv, &es); +kvaser_usb_rx_error_update_can_state (priv, &es, &tmp_cf); + new_state = priv->can.state; skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;return ; } +memcpy (cf, &tmp_cf,sizeof (*cf)); -if (es.status &M16C_STATE_BUS_OFF ) { - cf->can_id |=CAN_ERR_BUSOFF ; - -if (!priv->can.restart_ms) -kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); -netif_carrier_off (priv->netdev); - }else if (es.status &M16C_STATE_BUS_PASSIVE ) { -if (old_state !=CAN_STATE_ERROR_PASSIVE ) { - cf->can_id |=CAN_ERR_CRTL ; - -if (es.txerr || es.rxerr) - cf->data[1 ] = (es.txerr > es.rxerr) - ?CAN_ERR_CRTL_TX_PASSIVE - :CAN_ERR_CRTL_RX_PASSIVE ; -else - cf->data[1 ] =CAN_ERR_CRTL_TX_PASSIVE | -CAN_ERR_CRTL_RX_PASSIVE ; +if (new_state != old_state) { +if (es.status &M16C_STATE_BUS_OFF ) { +if (!priv->can.restart_ms) +kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); +netif_carrier_off (priv->netdev);
Quoted 18 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 752
Quoted 2 lines
drivers/net/can/usb/kvaser_usb.c +2
-0+ } +This block [below] is wrong. The usage of
PROT_ACTIVEis based on a misunderstanding. It's used in some drivers to signify back-to-error-active but its original meaning is something completely different, AFAIK.
This is handled incan_change_state()using a new CTRL message; namely:CAN_ERR_CTRL_ACTIVE. The newest version of can-utils is up to date with this.Quoted 9 lines
drivers/net/can/usb/kvaser_usb.c +8
-0+if (es.status ==M16C_STATE_BUS_ERROR ) { +if ((old_state >=CAN_STATE_ERROR_WARNING ) || + (es.txerr <96 && es.rxerr <96 )) { +if (old_state >CAN_STATE_ERROR_ACTIVE ) { + cf->can_id |=CAN_ERR_PROT ; + cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; + } + } }
So I would just make the new_state equals CAN_STATE_ERROR_ACTIVE, and then can_change_state() will do the right thing? Excellent!! This means the entire block above can be removed ;-)
[ On another note, the block's if conditions above are faulty and
fixed in patch #3. This patch (#2) used can_change_state() without changing any of that faulty logic to ease any future bisection. ]
Quoted 11 lines
drivers/net/can/usb/kvaser_usb.c static void kvaser_usb_rx_error(const struct kvaser_usb *dev, · line 762
Quoted 10 lines
drivers/net/can/usb/kvaser_usb.c +0
-9- } -if (es.status ==M16C_STATE_BUS_ERROR ) { -if ((old_state <CAN_STATE_ERROR_WARNING ) && - ((es.txerr >=96 ) || (es.rxerr >=96 ))) { - cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (es.txerr > es.rxerr) - ?CAN_ERR_CRTL_TX_WARNING - :CAN_ERR_CRTL_RX_WARNING ; - }else if (old_state >CAN_STATE_ERROR_ACTIVE ) {
Quoted 7 lines
This is also redundant, and wrong:
Quoted 5 lines
drivers/net/can/usb/kvaser_usb.c +1
-1+if (!es.status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; } - }
As in the above; extra code to be removed, yay! ;-)
Quoted 19 lines
Quoted 19 lines
drivers/net/can/usb/kvaser_usb.c +6
-10-if (!es.status) { - cf->can_id |=CAN_ERR_PROT ; - cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - } - -if (priv->can.restart_ms && - (old_state >=CAN_STATE_BUS_OFF ) && - (priv->can.state <CAN_STATE_BUS_OFF )) { - cf->can_id |=CAN_ERR_RESTARTED ; -netif_carrier_on (priv->netdev); +if (priv->can.restart_ms && + (old_state >=CAN_STATE_BUS_OFF ) && + (new_state <CAN_STATE_BUS_OFF )) { + cf->can_id |=CAN_ERR_RESTARTED ; +netif_carrier_on (priv->netdev); + } }
Quoted 7 lines
Quoted 3 lines
drivers/net/can/usb/kvaser_usb.c +0
-0if (es.error_factor) {Signature · 1 line
1.9.1Looking over the patch again, I've noticed that there are a few things that are not quite right.
The state-handlig code has become much simpler since your reveiw and Kleine-Budde's one. Thanks a lot for all the effort.
Regards,
Darwish
v6 cover can: kvaser_usb: Leaf bugfixes and USBCan-II support
In reply to Ahmed S. DarwishHi!
This is an updated patch series for the Kvaser CAN/USB devices:
1- Extra patches are now added to the series. Most importantly patch #1 which fixes a critical `sleep in atomic context' bug in the current upstream driver. Patch #2 fixes a corruption in the kernel logs, also affecting current upstream driver. Patch #4 was originally USBCan-II only, but since it's a generic fix, it's now retrofitted to the Leaf-only upstream driver first.
2- The series has been re-organized so that patches #1 -> #4 inclusive can go to linux-can/origin, while the rest can move to -next.
3- There are some important updates regarding the USBCan-II error counters, and how really erratic their heaviour is. All the new details are covered at the bottom of this URL:
http://article.gmane.org/gmane.linux.can/7481
4- Attached below is the new candump traces. Now back-to-error-active' states appear _if_ the hardware was kind enough and decreased the error counters appropriately. The earlier code did not recognize the error counters going down, thus the back-to-error-active' transitions did not appear.
###########################################################
* Bus-off scenario (with transitions active -> passive -> back-to-active):
(000.000000) can0 20000080 [8] 00 00 00 00 00 00 30 00 ERRORFRAME
bus-error
error-counter-tx-rx{{48}{0}}
(000.000011) can0 20000084 [8] 00 20 00 00 00 00 88 00 ERRORFRAME
controller-problem{tx-error-passive}
bus-error
error-counter-tx-rx{{136}{0}}
(000.000001) can0 20000080 [8] 00 00 00 00 00 00 88 00 ERRORFRAME
bus-error
error-counter-tx-rx{{136}{0}}
(000.000987) can0 20000080 [8] 00 00 00 00 00 00 98 00 ERRORFRAME
bus-error
error-counter-tx-rx{{152}{0}}
(000.002011) can0 20000084 [8] 00 40 00 00 00 00 30 00 ERRORFRAME
controller-problem{back-to-error-active}
bus-error
error-counter-tx-rx{{48}{0}}
(000.000004) can0 20000084 [8] 00 20 00 00 00 00 78 00 ERRORFRAME
controller-problem{tx-error-passive}
bus-error
error-counter-tx-rx{{120}{0}}
(000.000002) can0 20000080 [8] 00 00 00 00 00 00 88 00 ERRORFRAME
bus-error
error-counter-tx-rx{{136}{0}}
(000.000005) can0 20000080 [8] 00 00 00 00 00 00 90 00 ERRORFRAME
bus-error
error-counter-tx-rx{{144}{0}}
(000.000002) can0 20000080 [8] 00 00 00 00 00 00 98 00 ERRORFRAME
bus-error
error-counter-tx-rx{{152}{0}}
(000.000001) can0 20000080 [8] 00 00 00 00 00 00 A0 00 ERRORFRAME
bus-error
error-counter-tx-rx{{160}{0}}
(000.000966) can0 20000080 [8] 00 00 00 00 00 00 A8 00 ERRORFRAME
bus-error
error-counter-tx-rx{{168}{0}}
(000.002998) can0 20000084 [8] 00 40 00 00 00 00 30 00 ERRORFRAME
controller-problem{back-to-error-active}
bus-error
error-counter-tx-rx{{48}{0}}
(000.000004) can0 20000084 [8] 00 20 00 00 00 00 80 00 ERRORFRAME
controller-problem{tx-error-passive}
bus-error
error-counter-tx-rx{{128}{0}}
(000.000002) can0 20000080 [8] 00 00 00 00 00 00 88 00 ERRORFRAME
bus-error
error-counter-tx-rx{{136}{0}}
(001.031035) can0 200000C0 [8] 00 00 00 00 00 00 00 29 ERRORFRAME
bus-off
bus-error
error-counter-tx-rx{{0}{41}}###########################################################
Regular sending, unpluggng CAN connector, then plugging again:
(with transitions active -> warning -> passive)
[ As stated earlier, the counters don't get decreased upon CAN replug, even if they were constantly polled. ]
(000.011001) can0 2A1 [1] E5
(000.010001) can0 50E [8] E6 05 00 00 00 00 00 00
(000.009999) can0 009 [1] E7
(000.011000) can0 6E2 [8] E8 05 00 00 00 00 00 00
(000.009999) can0 314 [2] E9 05
(000.010001) can0 708 [6] EA 05 00 00 00 00
(000.010991) can0 20000080 [8] 00 00 00 00 00 00 00 09 ERRORFRAME
bus-error
error-counter-tx-rx{{0}{9}}
(000.000002) can0 20000080 [8] 00 00 00 00 00 00 00 0A ERRORFRAME
bus-error
error-counter-tx-rx{{0}{10}}
(000.000007) can0 20000080 [8] 00 00 00 00 00 00 00 2E ERRORFRAME
bus-error
error-counter-tx-rx{{0}{46}}
(000.000003) can0 20000080 [8] 00 00 00 00 00 00 00 37 ERRORFRAME
bus-error
error-counter-tx-rx{{0}{55}}
(000.000002) can0 20000080 [8] 00 00 00 00 00 00 00 40 ERRORFRAME
bus-error
error-counter-tx-rx{{0}{64}}
(000.000993) can0 20000080 [8] 00 00 00 00 00 00 00 49 ERRORFRAME
bus-error
error-counter-tx-rx{{0}{73}}
(000.000002) can0 20000080 [8] 00 00 00 00 00 00 00 52 ERRORFRAME
bus-error
error-counter-tx-rx{{0}{82}}
(000.000001) can0 20000080 [8] 00 00 00 00 00 00 00 5B ERRORFRAME
bus-error
error-counter-tx-rx{{0}{91}}
(000.000028) can0 20000084 [8] 00 04 00 00 00 00 00 6C ERRORFRAME
controller-problem{rx-error-warning}
bus-error
error-counter-tx-rx{{0}{108}}
(000.000955) can0 20000080 [8] 00 00 00 00 00 00 00 7F ERRORFRAME
bus-error
error-counter-tx-rx{{0}{127}}
(000.000008) can0 20000084 [8] 00 10 00 00 00 00 00 87 ERRORFRAME
controller-problem{rx-error-passive}
bus-error
error-counter-tx-rx{{0}{135}}
(000.000001) can0 20000080 [8] 00 00 00 00 00 00 00 87 ERRORFRAME
bus-error
error-counter-tx-rx{{0}{135}}
(000.000004) can0 20000080 [8] 00 00 00 00 00 00 00 87 ERRORFRAME
bus-error
error-counter-tx-rx{{0}{135}}((( Then a continous flood, exactly similar to the above packet, appears )))
(000.500004) can0 2ED [4] EB 05 00 00 (000.000006) can0 0DD [5] EC 05 00 00 00 (000.000002) can0 1D3 [1] ED (000.000988) can0 20D [8] EE 05 00 00 00 00 00 00 (000.000006) can0 04B [8] EF 05 00 00 00 00 00 00 (000.000002) can0 320 [8] F0 05 00 00 00 00 00 00 (000.000002) can0 023 [8] F1 05 00 00 00 00 00 00 (000.000989) can0 21D [8] F2 05 00 00 00 00 00 00 (000.000005) can0 17D [8] F3 05 00 00 00 00 00 00 (000.000002) can0 6DC [8] F4 05 00 00 00 00 00 00 (000.000993) can0 62D [8] F5 05 00 00 00 00 00 00 (000.000006) can0 18B [6] F6 05 00 00 00 00 (000.000001) can0 7EB [8] F7 05 00 00 00 00 00 00 (000.000001) can0 014 [8] F8 05 00 00 00 00 00 00 (000.000994) can0 52F [8] F9 05 00 00 00 00 00 00
--
Regards,
Darwish
PATCH v6 1/7 can: kvaser_usb: Do not sleep in atomic context
From: Ahmed S. Darwish <[email protected]>
Upon receiving a hardware event with the BUS_RESET flag set, the driver kills all of its anchored URBs and resets all of its transmit URB contexts.
Unfortunately it does so under the context of URB completion handler `kvaser_usb_read_bulk_callback()', which is often called in an atomic context.
While the device is flooded with many received error packets, usb_kill_urb() typically sleeps/reschedules till the transfer request of each killed URB in question completes, leading to the sleep in atomic bug. [3]
In v2 submission of the original driver patch [1], it was stated that the URBs kill and tx contexts reset was needed since we don't receive any tx acknowledgments later and thus such resources will be locked down forever. Fortunately this is no longer needed since an earlier bugfix in this patch series is now applied: all tx URB contexts are reset upon CAN channel close. [2]
Moreover, a BUS_RESET is now treated _exactly_ like a BUS_OFF event, which is the recommended handling method advised by the device manufacturer.
[1] http://article.gmane.org/gmane.linux.network/239442
http://www.webcitation.org/6Vr2yagAQ
[2] can: kvaser_usb: Reset all URB tx contexts upon channel close
889b77f7fd2bcc922493d73a4c51d8a851505815
[3] Stacktrace:
<IRQ> [<ffffffff8158de87>] dump_stack+0x45/0x57 [<ffffffff8158b60c>] __schedule_bug+0x41/0x4f [<ffffffff815904b1>] __schedule+0x5f1/0x700 [<ffffffff8159360a>] ? _raw_spin_unlock_irqrestore+0xa/0x10 [<ffffffff81590684>] schedule+0x24/0x70 [<ffffffff8147d0a5>] usb_kill_urb+0x65/0xa0 [<ffffffff81077970>] ? prepare_to_wait_event+0x110/0x110 [<ffffffff8147d7d8>] usb_kill_anchored_urbs+0x48/0x80 [<ffffffffa01f4028>] kvaser_usb_unlink_tx_urbs+0x18/0x50 [kvaser_usb] [<ffffffffa01f45d0>] kvaser_usb_rx_error+0xc0/0x400 [kvaser_usb] [<ffffffff8108b14a>] ? vprintk_default+0x1a/0x20 [<ffffffffa01f5241>] kvaser_usb_read_bulk_callback+0x4c1/0x5f0 [kvaser_usb] [<ffffffff8147a73e>] __usb_hcd_giveback_urb+0x5e/0xc0 [<ffffffff8147a8a1>] usb_hcd_giveback_urb+0x41/0x110 [<ffffffffa0008748>] finish_urb+0x98/0x180 [ohci_hcd] [<ffffffff810cd1a7>] ? acct_account_cputime+0x17/0x20 [<ffffffff81069f65>] ? local_clock+0x15/0x30 [<ffffffffa000a36b>] ohci_work+0x1fb/0x5a0 [ohci_hcd] [<ffffffff814fbb31>] ? process_backlog+0xb1/0x130 [<ffffffffa000cd5b>] ohci_irq+0xeb/0x270 [ohci_hcd] [<ffffffff81479fc1>] usb_hcd_irq+0x21/0x30 [<ffffffff8108bfd3>] handle_irq_event_percpu+0x43/0x120 [<ffffffff8108c0ed>] handle_irq_event+0x3d/0x60 [<ffffffff8108ec84>] handle_fasteoi_irq+0x74/0x110 [<ffffffff81004dfd>] handle_irq+0x1d/0x30 [<ffffffff81004727>] do_IRQ+0x57/0x100 [<ffffffff8159482a>] common_interrupt+0x6a/0x6a
--- drivers/net/can/usb/kvaser_usb.c | 7 +------ 1 files changed, 1 insertions(+), 6 deletions(-)
drivers/net/can/usb/kvaser_usb.c +1 -6
@@ -662,11 +662,6 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; -if (status &M16C_STATE_BUS_RESET ) { -kvaser_usb_unlink_tx_urbs (priv); -return ; - } - skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;
@@ -677,7 +672,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); -if (status &M16C_STATE_BUS_OFF ) { +if (status & (M16C_STATE_BUS_OFF |M16C_STATE_BUS_RESET )) { cf->can_id |=CAN_ERR_BUSOFF ; priv->can.can_stats.bus_off++;
Signature · 1 line
1.7.7.6
PATCH v6 2/7 can: kvaser_usb: Send correct context to URB completion
From: Ahmed S. Darwish <[email protected]>
Send expected argument to the URB completion hander: a CAN netdevice instead of the network interface private context `kvaser_usb_net_priv'.
This was discovered by having some garbage in the kernel log in place of the netdevice names: can0 and can1.
--- drivers/net/can/usb/kvaser_usb.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/net/can/usb/kvaser_usb.c +1 -1
@@ -587,7 +587,7 @@ static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,usb_sndbulkpipe (dev->udev, dev->bulk_out->bEndpointAddress), buf, msg->len, - kvaser_usb_simple_msg_callback, priv); + kvaser_usb_simple_msg_callback, netdev);usb_anchor_urb (urb, &priv->tx_submitted); err =usb_submit_urb (urb,GFP_ATOMIC );
Signature · 1 line
1.7.7.6
PATCH v6 3/7 can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT
From: Ahmed S. Darwish <[email protected]>
On some x86 laptops, plugging a Kvaser device again after an unplug makes the firmware always ignore the very first command. For such a case, provide some room for retries instead of completely exiting the driver init code.
--- drivers/net/can/usb/kvaser_usb.c | 12 ++++++++++-- 1 files changed, 10 insertions(+), 2 deletions(-)
drivers/net/can/usb/kvaser_usb.c +10 -2
@@ -1585,7 +1585,7 @@ static int kvaser_usb_probe(struct usb_interface *intf, {struct kvaser_usb *dev;int err = -ENOMEM ; -int i; +int i, retry =3 ; dev =devm_kzalloc (&intf->dev,sizeof (*dev),GFP_KERNEL );if (!dev)
@@ -1603,7 +1603,15 @@ static int kvaser_usb_probe(struct usb_interface *intf,usb_set_intfdata (intf, dev); - err =kvaser_usb_get_software_info (dev); +/* On some x86 laptops, plugging a Kvaser device again after +* an unplug makes the firmware always ignore the very first +* command. For such a case, provide some room for retries +* instead of completely exiting the driver. +*/ +do { + err =kvaser_usb_get_software_info (dev); + }while (--retry && err == -ETIMEDOUT ); +if (err) {dev_err (&intf->dev,"Cannot get software infos, error %d\n" , err);
Signature · 1 line
1.7.7.6
PATCH v6 4/7 can: kvaser_usb: Fix state handling upon BUS_ERROR events
From: Ahmed S. Darwish <[email protected]>
While being in an ERROR_WARNING state, and receiving further bus error events with error counters still in the ERROR_WARNING range of 97-127 inclusive, the state handling code erroneously reverts back to ERROR_ACTIVE.
Per the CAN standard, only revert to ERROR_ACTIVE when the error counters are less than 96.
Moreover, in certain Kvaser models, the BUS_ERROR flag is always set along with undefined bits in the M16C status register. Thus use bitwise operators instead of full equality for checking that register against bus errors.
--- drivers/net/can/usb/kvaser_usb.c | 7 +++---- 1 files changed, 3 insertions(+), 4 deletions(-)
drivers/net/can/usb/kvaser_usb.c +3 -4
@@ -698,9 +698,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, } new_state =CAN_STATE_ERROR_PASSIVE ; - } - -if (status ==M16C_STATE_BUS_ERROR ) { + }else if (status &M16C_STATE_BUS_ERROR ) {if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && ((txerr >=96 ) || (rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ;
@@ -710,7 +708,8 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, priv->can.can_stats.error_warning++; new_state =CAN_STATE_ERROR_WARNING ; - }else if (priv->can.state >CAN_STATE_ERROR_ACTIVE ) { + }else if ((priv->can.state >CAN_STATE_ERROR_ACTIVE ) && + ((txerr <96 ) && (rxerr <96 ))) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ;
Signature · 1 line
1.7.7.6
PATCH v6 5/7 can: kvaser_usb: Update interface state before exiting on OOM
From: Ahmed S. Darwish <[email protected]>
Update all of the can interface's state and error counters before trying any skb allocation that can actually fail with -ENOMEM.
--- drivers/net/can/usb/kvaser_usb.c | 181 ++++++++++++++++++++++---------------- 1 files changed, 105 insertions(+), 76 deletions(-)
drivers/net/can/usb/kvaser_usb.c +105 -76
@@ -273,6 +273,10 @@ struct kvaser_msg { } u; } __packed; +struct kvaser_usb_error_summary { +u8 channel, status, txerr, rxerr, error_factor; +}; +struct kvaser_usb_tx_urb_context {struct kvaser_usb_net_priv *priv;u32 echo_index;
@@ -615,6 +619,54 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) priv->tx_contexts[i].echo_index =MAX_TX_URBS ; } +static void kvaser_usb_rx_error_update_can_state (struct kvaser_usb_net_priv *priv, +const struct kvaser_usb_error_summary *es) +{ +struct net_device_stats *stats; +enum can_state new_state; + + stats = &priv->netdev->stats; + new_state = priv->can.state; + +netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); + +if (es->status & (M16C_STATE_BUS_OFF |M16C_STATE_BUS_RESET )) { + priv->can.can_stats.bus_off++; + new_state =CAN_STATE_BUS_OFF ; + }else if (es->status &M16C_STATE_BUS_PASSIVE ) { +if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) + priv->can.can_stats.error_passive++; + new_state =CAN_STATE_ERROR_PASSIVE ; + }else if (es->status &M16C_STATE_BUS_ERROR ) { +if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && + ((es->txerr >=96 ) || (es->rxerr >=96 ))) { + priv->can.can_stats.error_warning++; + new_state =CAN_STATE_ERROR_WARNING ; + }else if ((priv->can.state >CAN_STATE_ERROR_ACTIVE ) && + ((es->txerr <96 ) && (es->rxerr <96 ))) { + new_state =CAN_STATE_ERROR_ACTIVE ; + } + } + +if (!es->status) + new_state =CAN_STATE_ERROR_ACTIVE ; + +if (priv->can.restart_ms && + (priv->can.state >=CAN_STATE_BUS_OFF ) && + (new_state <CAN_STATE_BUS_OFF )) { + priv->can.can_stats.restarts++; + } + +if (es->error_factor) { + priv->can.can_stats.bus_error++; + stats->rx_errors++; + } + + priv->bec.txerr = es->txerr; + priv->bec.rxerr = es->rxerr; + priv->can.state = new_state; +} +static void kvaser_usb_rx_error (const struct kvaser_usb *dev,const struct kvaser_msg *msg) {
@@ -622,30 +674,30 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,struct sk_buff *skb;struct net_device_stats *stats;struct kvaser_usb_net_priv *priv; -unsigned int new_state; -u8 channel, status, txerr, rxerr, error_factor; +struct kvaser_usb_error_summary es = { }; +enum can_state old_state;switch (msg->id) {case CMD_CAN_ERROR_EVENT : - channel = msg->u.error_event.channel; - status = msg->u.error_event.status; - txerr = msg->u.error_event.tx_errors_count; - rxerr = msg->u.error_event.rx_errors_count; - error_factor = msg->u.error_event.error_factor; + es.channel = msg->u.error_event.channel; + es.status = msg->u.error_event.status; + es.txerr = msg->u.error_event.tx_errors_count; + es.rxerr = msg->u.error_event.rx_errors_count; + es.error_factor = msg->u.error_event.error_factor;break ;case CMD_LOG_MESSAGE : - channel = msg->u.log_message.channel; - status = msg->u.log_message.data[0 ]; - txerr = msg->u.log_message.data[2 ]; - rxerr = msg->u.log_message.data[3 ]; - error_factor = msg->u.log_message.data[1 ]; + es.channel = msg->u.log_message.channel; + es.status = msg->u.log_message.data[0 ]; + es.txerr = msg->u.log_message.data[2 ]; + es.rxerr = msg->u.log_message.data[3 ]; + es.error_factor = msg->u.log_message.data[1 ];break ;case CMD_CHIP_STATE_EVENT : - channel = msg->u.chip_state_event.channel; - status = msg->u.chip_state_event.status; - txerr = msg->u.chip_state_event.tx_errors_count; - rxerr = msg->u.chip_state_event.rx_errors_count; - error_factor =0 ; + es.channel = msg->u.chip_state_event.channel; + es.status = msg->u.chip_state_event.status; + es.txerr = msg->u.chip_state_event.tx_errors_count; + es.rxerr = msg->u.chip_state_event.rx_errors_count; + es.error_factor =0 ;break ;default : dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
@@ -653,116 +705,93 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,return ; } -if (channel >= dev->nchannels) { +if (es.channel >= dev->nchannels) {dev_err (dev->udev->dev.parent, -"Invalid channel number (%d)\n" , channel); +"Invalid channel number (%d)\n" , es.channel);return ; } - priv = dev->nets[channel]; + priv = dev->nets[es.channel]; stats = &priv->netdev->stats; +/* Update all of the can interface's state and error counters before +* trying any skb allocation that can actually fail with -ENOMEM. +*/ + old_state = priv->can.state; +kvaser_usb_rx_error_update_can_state (priv, &es); + skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;return ; } - new_state = priv->can.state; - -netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , status); - -if (status & (M16C_STATE_BUS_OFF |M16C_STATE_BUS_RESET )) { +if (es.status & (M16C_STATE_BUS_OFF |M16C_STATE_BUS_RESET )) { cf->can_id |=CAN_ERR_BUSOFF ; - priv->can.can_stats.bus_off++;if (!priv->can.restart_ms)kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); -netif_carrier_off (priv->netdev); - - new_state =CAN_STATE_BUS_OFF ; - }else if (status &M16C_STATE_BUS_PASSIVE ) { -if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) { + }else if (es.status &M16C_STATE_BUS_PASSIVE ) { +if (old_state !=CAN_STATE_ERROR_PASSIVE ) { cf->can_id |=CAN_ERR_CRTL ; -if (txerr || rxerr) - cf->data[1 ] = (txerr > rxerr) +if (es.txerr || es.rxerr) + cf->data[1 ] = (es.txerr > es.rxerr) ?CAN_ERR_CRTL_TX_PASSIVE :CAN_ERR_CRTL_RX_PASSIVE ;else cf->data[1 ] =CAN_ERR_CRTL_TX_PASSIVE |CAN_ERR_CRTL_RX_PASSIVE ; - - priv->can.can_stats.error_passive++; } - - new_state =CAN_STATE_ERROR_PASSIVE ; - }else if (status &M16C_STATE_BUS_ERROR ) { -if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((txerr >=96 ) || (rxerr >=96 ))) { + }else if (es.status &M16C_STATE_BUS_ERROR ) { +if ((old_state <CAN_STATE_ERROR_WARNING ) && + ((es.txerr >=96 ) || (es.rxerr >=96 ))) { cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (txerr > rxerr) + cf->data[1 ] = (es.txerr > es.rxerr) ?CAN_ERR_CRTL_TX_WARNING :CAN_ERR_CRTL_RX_WARNING ; - - priv->can.can_stats.error_warning++; - new_state =CAN_STATE_ERROR_WARNING ; - }else if ((priv->can.state >CAN_STATE_ERROR_ACTIVE ) && - ((txerr <96 ) && (rxerr <96 ))) { + }else if ((old_state >CAN_STATE_ERROR_ACTIVE ) && + ((es.txerr <96 ) && (es.rxerr <96 ))) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - - new_state =CAN_STATE_ERROR_ACTIVE ; } } -if (!status) { +if (!es.status) { cf->can_id |=CAN_ERR_PROT ; cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - - new_state =CAN_STATE_ERROR_ACTIVE ; }if (priv->can.restart_ms && - (priv->can.state >=CAN_STATE_BUS_OFF ) && - (new_state <CAN_STATE_BUS_OFF )) { + (old_state >=CAN_STATE_BUS_OFF ) && + (priv->can.state <CAN_STATE_BUS_OFF )) { cf->can_id |=CAN_ERR_RESTARTED ;netif_carrier_on (priv->netdev); - - priv->can.can_stats.restarts++; } -if (error_factor) { - priv->can.can_stats.bus_error++; - stats->rx_errors++; - +if (es.error_factor) { cf->can_id |=CAN_ERR_BUSERROR |CAN_ERR_PROT ; -if (error_factor &M16C_EF_ACKE ) +if (es.error_factor &M16C_EF_ACKE ) cf->data[3 ] |= (CAN_ERR_PROT_LOC_ACK ); -if (error_factor &M16C_EF_CRCE ) +if (es.error_factor &M16C_EF_CRCE ) cf->data[3 ] |= (CAN_ERR_PROT_LOC_CRC_SEQ |CAN_ERR_PROT_LOC_CRC_DEL ); -if (error_factor &M16C_EF_FORME ) +if (es.error_factor &M16C_EF_FORME ) cf->data[2 ] |=CAN_ERR_PROT_FORM ; -if (error_factor &M16C_EF_STFE ) +if (es.error_factor &M16C_EF_STFE ) cf->data[2 ] |=CAN_ERR_PROT_STUFF ; -if (error_factor &M16C_EF_BITE0 ) +if (es.error_factor &M16C_EF_BITE0 ) cf->data[2 ] |=CAN_ERR_PROT_BIT0 ; -if (error_factor &M16C_EF_BITE1 ) +if (es.error_factor &M16C_EF_BITE1 ) cf->data[2 ] |=CAN_ERR_PROT_BIT1 ; -if (error_factor &M16C_EF_TRE ) +if (es.error_factor &M16C_EF_TRE ) cf->data[2 ] |=CAN_ERR_PROT_TX ; } - cf->data[6 ] = txerr; - cf->data[7 ] = rxerr; - - priv->bec.txerr = txerr; - priv->bec.rxerr = rxerr; - - priv->can.state = new_state; + cf->data[6 ] = es.txerr; + cf->data[7 ] = es.rxerr; stats->rx_packets++; stats->rx_bytes += cf->can_dlc;
@@ -786,6 +815,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, }if (msg->u.rx_can.flag &MSG_FLAG_OVERRUN ) { + stats->rx_over_errors++; + stats->rx_errors++; + skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;
@@ -795,9 +827,6 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, cf->can_id |=CAN_ERR_CRTL ; cf->data[1 ] =CAN_ERR_CRTL_RX_OVERFLOW ; - stats->rx_over_errors++; - stats->rx_errors++; - stats->rx_packets++; stats->rx_bytes += cf->can_dlc;netif_rx (skb);
Signature · 1 line
1.7.7.6
PATCH v6 6/7 can: kvaser_usb: Consolidate and unify state change handling
From: Ahmed S. Darwish <[email protected]>
Replace most of the can interface's state and error counters handling with the new can-dev can_change_state() mechanism.
--- drivers/net/can/usb/kvaser_usb.c | 113 ++++++++++++++++--------------------- 1 files changed, 49 insertions(+), 64 deletions(-)
drivers/net/can/usb/kvaser_usb.c +49 -64
@@ -620,39 +620,44 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv) }static void kvaser_usb_rx_error_update_can_state (struct kvaser_usb_net_priv *priv, -const struct kvaser_usb_error_summary *es) +const struct kvaser_usb_error_summary *es, +struct can_frame *cf) {struct net_device_stats *stats; -enum can_state new_state; - - stats = &priv->netdev->stats; - new_state = priv->can.state; +enum can_state cur_state, new_state, tx_state, rx_state;netdev_dbg (priv->netdev,"Error status: 0x%02x\n" , es->status); -if (es->status & (M16C_STATE_BUS_OFF |M16C_STATE_BUS_RESET )) { - priv->can.can_stats.bus_off++; + stats = &priv->netdev->stats; + new_state = cur_state = priv->can.state; + +if (es->status & (M16C_STATE_BUS_OFF |M16C_STATE_BUS_RESET )) new_state =CAN_STATE_BUS_OFF ; - }else if (es->status &M16C_STATE_BUS_PASSIVE ) { -if (priv->can.state !=CAN_STATE_ERROR_PASSIVE ) - priv->can.can_stats.error_passive++; +else if (es->status &M16C_STATE_BUS_PASSIVE ) new_state =CAN_STATE_ERROR_PASSIVE ; - }else if (es->status &M16C_STATE_BUS_ERROR ) { -if ((priv->can.state <CAN_STATE_ERROR_WARNING ) && - ((es->txerr >=96 ) || (es->rxerr >=96 ))) { - priv->can.can_stats.error_warning++; +else if (es->status &M16C_STATE_BUS_ERROR ) { +if ((es->txerr >=256 ) || (es->rxerr >=256 )) + new_state =CAN_STATE_BUS_OFF ; +else if ((es->txerr >=128 ) || (es->rxerr >=128 )) + new_state =CAN_STATE_ERROR_PASSIVE ; +else if ((es->txerr >=96 ) || (es->rxerr >=96 )) new_state =CAN_STATE_ERROR_WARNING ; - }else if ((priv->can.state >CAN_STATE_ERROR_ACTIVE ) && - ((es->txerr <96 ) && (es->rxerr <96 ))) { +else if (cur_state >CAN_STATE_ERROR_ACTIVE ) new_state =CAN_STATE_ERROR_ACTIVE ; - } }if (!es->status) new_state =CAN_STATE_ERROR_ACTIVE ; +if (new_state != cur_state) { + tx_state = (es->txerr >= es->rxerr) ? new_state :0 ; + rx_state = (es->txerr <= es->rxerr) ? new_state :0 ; + +can_change_state (priv->netdev, cf, tx_state, rx_state); + } +if (priv->can.restart_ms && - (priv->can.state >=CAN_STATE_BUS_OFF ) && + (cur_state >=CAN_STATE_BUS_OFF ) && (new_state <CAN_STATE_BUS_OFF )) { priv->can.can_stats.restarts++; }
@@ -664,18 +669,17 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri priv->bec.txerr = es->txerr; priv->bec.rxerr = es->rxerr; - priv->can.state = new_state; }static void kvaser_usb_rx_error (const struct kvaser_usb *dev,const struct kvaser_msg *msg) { -struct can_frame *cf; +struct can_frame *cf, tmp_cf = { .can_id =CAN_ERR_FLAG , .can_dlc =CAN_ERR_DLC };struct sk_buff *skb;struct net_device_stats *stats;struct kvaser_usb_net_priv *priv;struct kvaser_usb_error_summary es = { }; -enum can_state old_state; +enum can_state old_state, new_state;switch (msg->id) {case CMD_CAN_ERROR_EVENT :
@@ -715,59 +719,40 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev, stats = &priv->netdev->stats;/* Update all of the can interface's state and error counters before -* trying any skb allocation that can actually fail with -ENOMEM. +* 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_rx_error_update_can_state (priv, &es); +kvaser_usb_rx_error_update_can_state (priv, &es, &tmp_cf); + new_state = priv->can.state; skb =alloc_can_err_skb (priv->netdev, &cf);if (!skb) { stats->rx_dropped++;return ; } - -if (es.status & (M16C_STATE_BUS_OFF |M16C_STATE_BUS_RESET )) { - cf->can_id |=CAN_ERR_BUSOFF ; - -if (!priv->can.restart_ms) -kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); -netif_carrier_off (priv->netdev); - }else if (es.status &M16C_STATE_BUS_PASSIVE ) { -if (old_state !=CAN_STATE_ERROR_PASSIVE ) { - cf->can_id |=CAN_ERR_CRTL ; - -if (es.txerr || es.rxerr) - cf->data[1 ] = (es.txerr > es.rxerr) - ?CAN_ERR_CRTL_TX_PASSIVE - :CAN_ERR_CRTL_RX_PASSIVE ; -else - cf->data[1 ] =CAN_ERR_CRTL_TX_PASSIVE | -CAN_ERR_CRTL_RX_PASSIVE ; - } - }else if (es.status &M16C_STATE_BUS_ERROR ) { -if ((old_state <CAN_STATE_ERROR_WARNING ) && - ((es.txerr >=96 ) || (es.rxerr >=96 ))) { - cf->can_id |=CAN_ERR_CRTL ; - cf->data[1 ] = (es.txerr > es.rxerr) - ?CAN_ERR_CRTL_TX_WARNING - :CAN_ERR_CRTL_RX_WARNING ; - }else if ((old_state >CAN_STATE_ERROR_ACTIVE ) && - ((es.txerr <96 ) && (es.rxerr <96 ))) { - cf->can_id |=CAN_ERR_PROT ; - cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; +memcpy (cf, &tmp_cf,sizeof (*cf)); + +if (new_state != old_state) { +if (es.status & + (M16C_STATE_BUS_OFF |M16C_STATE_BUS_RESET )) { +if (!priv->can.restart_ms) +kvaser_usb_simple_msg_async (priv,CMD_STOP_CHIP ); +netif_carrier_off (priv->netdev); } - } - -if (!es.status) { - cf->can_id |=CAN_ERR_PROT ; - cf->data[2 ] =CAN_ERR_PROT_ACTIVE ; - } -if (priv->can.restart_ms && - (old_state >=CAN_STATE_BUS_OFF ) && - (priv->can.state <CAN_STATE_BUS_OFF )) { - cf->can_id |=CAN_ERR_RESTARTED ; -netif_carrier_on (priv->netdev); +if (priv->can.restart_ms && + (old_state >=CAN_STATE_BUS_OFF ) && + (new_state <CAN_STATE_BUS_OFF )) { + cf->can_id |=CAN_ERR_RESTARTED ; +netif_carrier_on (priv->netdev); + } }if (es.error_factor) {
Signature · 1 line
1.7.7.6