All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] can: kvaser_usb: Don't free packets when tight on URBs
@ 2014-12-23 15:46 Ahmed S. Darwish
  2014-12-23 15:53 ` [PATCH] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
                   ` (7 more replies)
  0 siblings, 8 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2014-12-23 15:46 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

 (Generated over 3.19.0-rc1)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 541fb7a..34c35d8 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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;
 }

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
  2014-12-23 15:46 [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
@ 2014-12-23 15:53 ` Ahmed S. Darwish
  2014-12-24 12:36   ` Olivier Sobrie
  2014-12-24 12:31 ` [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Olivier Sobrie
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2014-12-23 15:53 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 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)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 34c35d8..e7076da 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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 <matthias.fuchs@esd.eu>, esd gmbh
  * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ * 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);

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* Re: [PATCH] can: kvaser_usb: Don't free packets when tight on URBs
  2014-12-23 15:46 [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
  2014-12-23 15:53 ` [PATCH] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
@ 2014-12-24 12:31 ` Olivier Sobrie
  2014-12-24 15:52   ` Ahmed S. Darwish
  2014-12-24 23:56 ` [PATCH v2 1/4] " Ahmed S. Darwish
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 98+ messages in thread
From: Olivier Sobrie @ 2014-12-24 12:31 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hello Ahmed,

On Tue, Dec 23, 2014 at 05:46:54PM +0200, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>
> 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.
>
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Thank you for the fix.

> ---
>  drivers/net/can/usb/kvaser_usb.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
>
>  (Generated over 3.19.0-rc1)
>
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index 541fb7a..34c35d8 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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;

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

>   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;
>  }
>

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
  2014-12-23 15:53 ` [PATCH] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
@ 2014-12-24 12:36   ` Olivier Sobrie
  2014-12-24 15:04     ` Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Olivier Sobrie @ 2014-12-24 12:36 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hello Ahmed,

On Tue, Dec 23, 2014 at 05:53:11PM +0200, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>
> 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.

Good, thank you :-) I'll try to test the patch during the next
week-end. Small remarks below.

>
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> ---
>  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)
>
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index 34c35d8..e7076da 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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 <matthias.fuchs@esd.eu>, esd gmbh
>   * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
> + * 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))

There is a max(a, b) macro in <linux/kernel.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 */
> @@ -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;

IMHO, you can keep MAX_NET_DEVICES here.

>
>   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++) {

here too... or replace it by nchannels.

>   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;
> + }

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.

> +
>   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.

>
>   err = kvaser_usb_get_software_info(dev);

Thank you,

-- 
Olivier

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
  2014-12-24 12:36   ` Olivier Sobrie
@ 2014-12-24 15:04     ` Ahmed S. Darwish
  2014-12-28 21:51       ` Olivier Sobrie
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2014-12-24 15:04 UTC (permalink / raw)
  To: Olivier Sobrie
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hi Olivier,

On Wed, Dec 24, 2014 at 01:36:27PM +0100, Olivier Sobrie wrote:
> Hello Ahmed,
> 
> On Tue, Dec 23, 2014 at 05:53:11PM +0200, Ahmed S. Darwish wrote:
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > 
> > 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.
> > 
> 
> Good, thank you :-) I'll try to test the patch during the next
> week-end. Small remarks below.
> 

Great! thanks and Merry Christmas :-)

> > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > ---
> >  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)
> > 
> > diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> > index 34c35d8..e7076da 100644
> > --- a/drivers/net/can/usb/kvaser_usb.c
> > +++ b/drivers/net/can/usb/kvaser_usb.c
> > @@ -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 <matthias.fuchs@esd.eu>, esd gmbh
> >   * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
> > + * 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))
> 
> 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) ({    \
                   ^

> > +
> > +/*
> > + * 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;
> 
> IMHO, you can keep MAX_NET_DEVICES here.
> 

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 :-(

> >  
> >  	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++) {
> 
> 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.

> >  		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;
> > +	}
> > +
> 
> 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.
> 

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

b) 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 :-)

> >  	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.
> 

Great. I guess I can submit a 3-patch series now
(kfree_skb fix + the above fix + driver).

> >  
> >  	err = 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH] can: kvaser_usb: Don't free packets when tight on URBs
  2014-12-24 12:31 ` [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Olivier Sobrie
@ 2014-12-24 15:52   ` Ahmed S. Darwish
  0 siblings, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2014-12-24 15:52 UTC (permalink / raw)
  To: Olivier Sobrie
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hi Olivier,

On Wed, Dec 24, 2014 at 01:31:20PM +0100, Olivier Sobrie wrote:
> Hello Ahmed,
> 
> On Tue, Dec 23, 2014 at 05:46:54PM +0200, Ahmed S. Darwish wrote:
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > 
> > 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.
> > 
> > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> Thank you for the fix.
> 
> > ---
> >  drivers/net/can/usb/kvaser_usb.c | 8 +++++---
> >  1 file changed, 5 insertions(+), 3 deletions(-)
> > 
> >  (Generated over 3.19.0-rc1)
> > 
> > diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> > index 541fb7a..34c35d8 100644
> > --- a/drivers/net/can/usb/kvaser_usb.c
> > +++ b/drivers/net/can/usb/kvaser_usb.c
> > @@ -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;
> 
> 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 ;-))

> Thank you,
> 
> Olivier
> 
> >  		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;
> >  }
> > 

^ permalink raw reply	[flat|nested] 98+ messages in thread

* [PATCH v2 1/4] can: kvaser_usb: Don't free packets when tight on URBs
  2014-12-23 15:46 [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
  2014-12-23 15:53 ` [PATCH] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
  2014-12-24 12:31 ` [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Olivier Sobrie
@ 2014-12-24 23:56 ` Ahmed S. Darwish
  2014-12-24 23:59   ` [PATCH v2 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
                     ` (2 more replies)
  2015-01-01 21:59 ` [PATCH] " Stephen Hemminger
                   ` (4 subsequent siblings)
  7 siblings, 3 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2014-12-24 23:56 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, Greg KH,
	Linux-stable, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 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?)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 541fb7a..6479a2b 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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;
 }
 

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v2 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close
  2014-12-24 23:56 ` [PATCH v2 1/4] " Ahmed S. Darwish
@ 2014-12-24 23:59   ` Ahmed S. Darwish
  2014-12-25  0:02     ` [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Ahmed S. Darwish
  2014-12-25  2:50   ` [PATCH v2 1/4] can: kvaser_usb: Don't free packets when tight on URBs Greg KH
  2014-12-28 21:52   ` Olivier Sobrie
  2 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2014-12-24 23:59 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, Greg KH,
	Linux-stable, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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"

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 3 +++
 1 file changed, 3 insertions(+)

 (Marc, Greg, this also should be added to -stable?)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 6479a2b..598e251 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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);
 

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels
  2014-12-24 23:59   ` [PATCH v2 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
@ 2014-12-25  0:02     ` Ahmed S. Darwish
  2014-12-25  0:04       ` [PATCH v2 4/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
  2014-12-28 21:54       ` [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Olivier Sobrie
  0 siblings, 2 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2014-12-25  0:02 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Greg KH, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

"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."

Suggested-by: Olivier Sobrie <olivier@sobrie.be>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 598e251..2791501 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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,

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v2 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2014-12-25  0:02     ` [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Ahmed S. Darwish
@ 2014-12-25  0:04       ` Ahmed S. Darwish
  2014-12-28 21:54       ` [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Olivier Sobrie
  1 sibling, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2014-12-25  0:04 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Greg KH, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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 <ahmed.darwish@valeo.com>
---
 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

diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index a77db919..f6f5500 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -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.
 
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 2791501..50da317 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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 <matthias.fuchs@esd.eu>, esd gmbh
  * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ * Copyright (C) 2014 Valeo Corporation
  */
 
 #include <linux/completion.h>
@@ -21,6 +23,18 @@
 #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(a, b)			((a) > (b) ? (a) : (b))
+
 #define MAX_TX_URBS			16
 #define MAX_RX_URBS			4
 #define START_TIMEOUT			1000 /* msecs */
@@ -29,9 +43,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 +72,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 +100,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 +125,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 +141,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 +155,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 +178,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 +189,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 +254,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 +345,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 +371,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 +388,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 +446,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 +471,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 +521,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 +635,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 +665,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 +679,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 +800,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 +884,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 +982,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 +994,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 +1010,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 +1028,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 +1044,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 +1097,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 +1111,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 +1147,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 +1159,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 +1194,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 +1288,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 +1306,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 +1533,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 +1641,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 +1663,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 +1697,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) {
@@ -1601,6 +1968,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)");

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* Re: [PATCH v2 1/4] can: kvaser_usb: Don't free packets when tight on URBs
  2014-12-24 23:56 ` [PATCH v2 1/4] " Ahmed S. Darwish
  2014-12-24 23:59   ` [PATCH v2 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
@ 2014-12-25  2:50   ` Greg KH
  2014-12-25  9:38     ` Ahmed S. Darwish
  2014-12-28 21:52   ` Olivier Sobrie
  2 siblings, 1 reply; 98+ messages in thread
From: Greg KH @ 2014-12-25  2:50 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, David S. Miller, Paul Gortmaker, Linux-CAN,
	netdev, Linux-stable, LKML

On Thu, Dec 25, 2014 at 01:56:44AM +0200, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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.
> 
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> ---
>  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>

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v2 1/4] can: kvaser_usb: Don't free packets when tight on URBs
  2014-12-25  2:50   ` [PATCH v2 1/4] can: kvaser_usb: Don't free packets when tight on URBs Greg KH
@ 2014-12-25  9:38     ` Ahmed S. Darwish
  0 siblings, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2014-12-25  9:38 UTC (permalink / raw)
  To: Greg KH
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, David S. Miller, Paul Gortmaker, Linux-CAN,
	netdev, Linux-stable, LKML

On Wed, Dec 24, 2014 at 06:50:11PM -0800, Greg KH wrote:
> On Thu, Dec 25, 2014 at 01:56:44AM +0200, Ahmed S. Darwish wrote:
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > 
  > > 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.
> > 
> > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > ---
> >  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>

<msg-response>

Note taken. Sorry about that ;-)

</msg-response>

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
  2014-12-24 15:04     ` Ahmed S. Darwish
@ 2014-12-28 21:51       ` Olivier Sobrie
  2014-12-30 15:33         ` Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Olivier Sobrie @ 2014-12-28 21:51 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hello Ahmed,

On Wed, Dec 24, 2014 at 05:04:17PM +0200, Ahmed S. Darwish wrote:
> Hi Olivier,
> 
> On Wed, Dec 24, 2014 at 01:36:27PM +0100, Olivier Sobrie wrote:
> > Hello Ahmed,
> > 
> > On Tue, Dec 23, 2014 at 05:53:11PM +0200, Ahmed S. Darwish wrote:
> > > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > > 
> > > 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.
> > > 
> > 
> > Good, thank you :-) I'll try to test the patch during the next
> > week-end. Small remarks below.
> > 
> 
> Great! thanks and Merry Christmas :-)
> 
> > > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > > ---
> > >  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)
> > > 
> > > diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> > > index 34c35d8..e7076da 100644
> > > --- a/drivers/net/can/usb/kvaser_usb.c
> > > +++ b/drivers/net/can/usb/kvaser_usb.c
> > > @@ -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 <matthias.fuchs@esd.eu>, esd gmbh
> > >   * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
> > > + * 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))
> > 
> > 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) ({    \
>                    ^

Just let MAX_NET_DEVICES equals to 3.

> 
> > > +
> > > +/*
> > > + * 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

I would prefer if you use CMD_LEAF_xxx and CMD_USBCAN_xxx.

> > > +
> > >  #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;
> > 
> > IMHO, you can keep MAX_NET_DEVICES here.
> > 
> 
> 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 :-(
> 
> > >  
> > >  	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++) {
> > 
> > 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.
> 
> > >  		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;
> > > +	}
> > > +
> > 
> > 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.
> > 
> 
> 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
> 
> b) 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 :-)

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.

> 
> > >  	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.
> > 
> 
> Great. I guess I can submit a 3-patch series now
> (kfree_skb fix + the above fix + driver).
> 
> > >  
> > >  	err = 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

Kr,

-- 
Olivier

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v2 1/4] can: kvaser_usb: Don't free packets when tight on URBs
  2014-12-24 23:56 ` [PATCH v2 1/4] " Ahmed S. Darwish
  2014-12-24 23:59   ` [PATCH v2 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
  2014-12-25  2:50   ` [PATCH v2 1/4] can: kvaser_usb: Don't free packets when tight on URBs Greg KH
@ 2014-12-28 21:52   ` Olivier Sobrie
  2 siblings, 0 replies; 98+ messages in thread
From: Olivier Sobrie @ 2014-12-28 21:52 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, Greg KH,
	Linux-stable, LKML

On Thu, Dec 25, 2014 at 01:56:44AM +0200, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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.
> 
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Acked-by: Olivier Sobrie <olivier@sobrie.be>

> ---
>  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?)
> 
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index 541fb7a..6479a2b 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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;
>  }
>  

-- 
Olivier

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels
  2014-12-25  0:02     ` [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Ahmed S. Darwish
  2014-12-25  0:04       ` [PATCH v2 4/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
@ 2014-12-28 21:54       ` Olivier Sobrie
  1 sibling, 0 replies; 98+ messages in thread
From: Olivier Sobrie @ 2014-12-28 21:54 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Greg KH, Linux-CAN, netdev,
	LKML

On Thu, Dec 25, 2014 at 02:02:56AM +0200, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> "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:
Reported-by: Christopher Storah <Christopher.Storah@invetech.com.au>
Signed-off-by: Olivier Sobrie <olivier@sobrie.be>

Kr,

Olivier

> 
> Suggested-by: Olivier Sobrie <olivier@sobrie.be>
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> ---
>  drivers/net/can/usb/kvaser_usb.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index 598e251..2791501 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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,

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
  2014-12-28 21:51       ` Olivier Sobrie
@ 2014-12-30 15:33         ` Ahmed S. Darwish
  2014-12-31 12:13           ` Olivier Sobrie
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2014-12-30 15:33 UTC (permalink / raw)
  To: Olivier Sobrie
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

On Sun, Dec 28, 2014 at 10:51:34PM +0100, Olivier Sobrie wrote:
[...]
> > > >  
> > > > +	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;
> > > > +	}
> > > > +
> > > 
> > > 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.
> > > 
> > 
> > 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
> > 
> > b) 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 :-)
> 
> 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.
> 

Quite nice, will do it that way in v3.

Regards,
Darwish

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH] can: kvaser_usb: Add support for the Usbcan-II family
  2014-12-30 15:33         ` Ahmed S. Darwish
@ 2014-12-31 12:13           ` Olivier Sobrie
  0 siblings, 0 replies; 98+ messages in thread
From: Olivier Sobrie @ 2014-12-31 12:13 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

On Tue, Dec 30, 2014 at 10:33:26AM -0500, Ahmed S. Darwish wrote:
> On Sun, Dec 28, 2014 at 10:51:34PM +0100, Olivier Sobrie wrote:
> [...]
> > > > >  
> > > > > +	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;
> > > > > +	}
> > > > > +
> > > > 
> > > > 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.
> > > > 
> > > 
> > > 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
> > > 
> > > b) 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 :-)
> > 
> > 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.
> > 
> 
> 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,

-- 
Olivier

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH] can: kvaser_usb: Don't free packets when tight on URBs
  2014-12-23 15:46 [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
                   ` (2 preceding siblings ...)
  2014-12-24 23:56 ` [PATCH v2 1/4] " Ahmed S. Darwish
@ 2015-01-01 21:59 ` Stephen Hemminger
  2015-01-03 14:34   ` Ahmed S. Darwish
  2015-01-05 17:49 ` [PATCH v3 1/4] " Ahmed S. Darwish
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 98+ messages in thread
From: Stephen Hemminger @ 2015-01-01 21:59 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, David S. Miller, Paul Gortmaker, Linux-CAN,
	netdev, LKML

On Tue, 23 Dec 2014 17:46:54 +0200
"Ahmed S. Darwish" <darwish.07@gmail.com> wrote:

>  	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;

You already have a flag value (ret == NETDEV_TX_BUSY), why
not use that instead of introducing another variable?

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH] can: kvaser_usb: Don't free packets when tight on URBs
  2015-01-01 21:59 ` [PATCH] " Stephen Hemminger
@ 2015-01-03 14:34   ` Ahmed S. Darwish
  0 siblings, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-03 14:34 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, David S. Miller, Paul Gortmaker, Linux-CAN,
	netdev, LKML

On Thu, Jan 01, 2015 at 01:59:13PM -0800, Stephen Hemminger wrote:
> On Tue, 23 Dec 2014 17:46:54 +0200
> "Ahmed S. Darwish" <darwish.07@gmail.com> wrote:
> 
> >  	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;
> 
> 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* [PATCH v3 1/4] can: kvaser_usb: Don't free packets when tight on URBs
  2014-12-23 15:46 [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
                   ` (3 preceding siblings ...)
  2015-01-01 21:59 ` [PATCH] " Stephen Hemminger
@ 2015-01-05 17:49 ` Ahmed S. Darwish
  2015-01-05 17:52   ` [PATCH v3 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
  2015-01-08  9:59   ` [PATCH v3 1/4] can: kvaser_usb: Don't free packets when tight on URBs Marc Kleine-Budde
  2015-01-11 20:05 ` [PATCH v4 00/04] can: Introduce support for Kvaser USBCAN-II devices Ahmed S. Darwish
                   ` (2 subsequent siblings)
  7 siblings, 2 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-05 17:49 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
Acked-by: Olivier Sobrie <olivier@sobrie.be>
---
 drivers/net/can/usb/kvaser_usb.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

** V3 Changelog:
- checkpatch.pl suggestions ('net/' commenting style)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 541fb7a..2e7d513 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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;
 }
 

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v3 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close
  2015-01-05 17:49 ` [PATCH v3 1/4] " Ahmed S. Darwish
@ 2015-01-05 17:52   ` Ahmed S. Darwish
  2015-01-05 17:57     ` [PATCH v3 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Ahmed S. Darwish
  2015-01-08  9:59   ` [PATCH v3 1/4] can: kvaser_usb: Don't free packets when tight on URBs Marc Kleine-Budde
  1 sibling, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-05 17:52 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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"

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 2e7d513..9accc82 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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);
 

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v3 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels
  2015-01-05 17:52   ` [PATCH v3 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
@ 2015-01-05 17:57     ` Ahmed S. Darwish
  2015-01-05 18:31       ` [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-05 17:57 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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.

Reported-by: Christopher Storah <Christopher.Storah@invetech.com.au>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
Signed-off-by: Olivier Sobrie <olivier@sobrie.be>
---
 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

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 9accc82..cc7bfc0 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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,

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-05 17:57     ` [PATCH v3 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Ahmed S. Darwish
@ 2015-01-05 18:31       ` Ahmed S. Darwish
  2015-01-08 11:53         ` Marc Kleine-Budde
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-05 18:31 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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 <ahmed.darwish@valeo.com>
---
 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.)

diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index a77db919..f6f5500 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -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.
 
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index cc7bfc0..43b3928 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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 <matthias.fuchs@esd.eu>, esd gmbh
  * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ * 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
@@ -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)
+
+/* 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) {
+	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;
 }
@@ -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;
 
 	return 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;
 }
 
-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 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;
 	}
 
-	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, };
+
+	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 +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)
+			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 +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++;
@@ -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;
+	} 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)");



^ permalink raw reply related	[flat|nested] 98+ messages in thread

* Re: [PATCH v3 1/4] can: kvaser_usb: Don't free packets when tight on URBs
  2015-01-05 17:49 ` [PATCH v3 1/4] " Ahmed S. Darwish
  2015-01-05 17:52   ` [PATCH v3 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
@ 2015-01-08  9:59   ` Marc Kleine-Budde
  1 sibling, 0 replies; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-08  9:59 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 1240 bytes --]

On 01/05/2015 06:49 PM, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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.
> 
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> Acked-by: Olivier Sobrie <olivier@sobrie.be>

Applied 1-3 to can/master + added stable on Cc.

Marc

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-05 18:31       ` [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
@ 2015-01-08 11:53         ` Marc Kleine-Budde
  2015-01-08 15:19           ` Ahmed S. Darwish
  2015-01-09  3:06           ` Ahmed S. Darwish
  0 siblings, 2 replies; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-08 11:53 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 36539 bytes --]

On 01/05/2015 07:31 PM, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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 <ahmed.darwish@valeo.com>
> ---
>  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.)
> 
> diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
> index a77db919..f6f5500 100644
> --- a/drivers/net/can/usb/Kconfig
> +++ b/drivers/net/can/usb/Kconfig
> @@ -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.
>  
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index cc7bfc0..43b3928 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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 <matthias.fuchs@esd.eu>, esd gmbh
>   * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
> + * 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
> @@ -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.

> +
> +/* 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) {
> +	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.

> +	}
>  
>  	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 "||"?

>  
>  	return 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;
>  }
>  
> -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).

> +
> +/* 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.

> + */
> +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.

>  {
> -	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;

> +
> +	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?

> +
> +	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, };

IIRC "es = { };" should be sufficient.

>  
>  	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 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;
>  	}
>  
> -	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.

> +
> +	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;

Why is channel == 1 if the device has more than 1 channel?

> +			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:
should not happen.
>  		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 +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)
> +			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.

>  	}
>  
> -	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++;
> 			return;
> 		}

Can you prepare a (seperate) patch that does the stats, even in case of OOM here. Same for kvaser_report_error_event()

> 
> 		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.

> 	}

> @@ -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;
> +	} 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

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-08 11:53         ` Marc Kleine-Budde
@ 2015-01-08 15:19           ` Ahmed S. Darwish
  2015-01-12 11:51             ` Marc Kleine-Budde
  2015-01-09  3:06           ` Ahmed S. Darwish
  1 sibling, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-08 15:19 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hi Marc,

On Thu, Jan 08, 2015 at 12:53:37PM +0100, Marc Kleine-Budde wrote:
> On 01/05/2015 07:31 PM, Ahmed S. Darwish wrote:
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
[...]
> > +/* 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
> > @@ -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.

[...]
> >  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) {
> > +	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?

> > +	}
> >  
> >  	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.

> >  
> >  	return 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;
> >  }
> >  
> > -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?

> > +
> > +/* 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.
> 

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_*")

> > + */
> > +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.

> >  {
> > -	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.

> > +
> > +	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?
> 

Initially, just for clarity, as I was not used yet to socketCAN
structures ;-) will remove it in the next submission.

> > +
> > +	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, };
> 
> IIRC "es = { };" should be sufficient.
> 

Correct, will do.

> >  
> >  	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 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;
> >  	}
> >  
> > -	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.

> > +
> > +	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;
> 
> 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.

> > +			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:
> should not happen.

Yes. As in above, will wait your input in this regarding the checks
being defensive.

[...]
> > +	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;
> 
> should not happen.
> 

Ditto.

> >  	}
> >  
> > -	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++;
> > 			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.

> 
> > 
> > 		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.
> 

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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-08 11:53         ` Marc Kleine-Budde
  2015-01-08 15:19           ` Ahmed S. Darwish
@ 2015-01-09  3:06           ` Ahmed S. Darwish
  2015-01-09 14:05             ` Marc Kleine-Budde
  1 sibling, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-09  3:06 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

On Thu, Jan 08, 2015 at 12:53:37PM +0100, Marc Kleine-Budde wrote:
> On 01/05/2015 07:31 PM, Ahmed S. Darwish wrote:
> > 

[...]

> > 
> > 		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.
> 

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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-09  3:06           ` Ahmed S. Darwish
@ 2015-01-09 14:05             ` Marc Kleine-Budde
  2015-01-09 16:23               ` Oliver Hartkopp
  0 siblings, 1 reply; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-09 14:05 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 1460 bytes --]

On 01/09/2015 04:06 AM, Ahmed S. Darwish wrote:
>>>
>>> 		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.

> BTW, is it guaranteed from the SocketCAN stack that netif_rx()

netif_rx() is the generic networking stack already.

> will never return NET_RX_DROPPED? Because if no guarantee
> exists, I guess below fragment cannot be completely correct?

No, it's not guaranteed...

> 
>         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

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-09 14:05             ` Marc Kleine-Budde
@ 2015-01-09 16:23               ` Oliver Hartkopp
  0 siblings, 0 replies; 98+ messages in thread
From: Oliver Hartkopp @ 2015-01-09 16:23 UTC (permalink / raw)
  To: Marc Kleine-Budde, Ahmed S. Darwish
  Cc: Olivier Sobrie, Wolfgang Grandegger, Linux-CAN

On 09.01.2015 15:05, Marc Kleine-Budde wrote:
> On 01/09/2015 04:06 AM, Ahmed S. Darwish wrote:

>>>> 		stats->rx_over_errors++;
>>>> 		stats->rx_errors++;
>>>>
>>>> 		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_DROPPED some 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.




^ permalink raw reply	[flat|nested] 98+ messages in thread

* [PATCH v4 00/04] can: Introduce support for Kvaser USBCAN-II devices
  2014-12-23 15:46 [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
                   ` (4 preceding siblings ...)
  2015-01-05 17:49 ` [PATCH v3 1/4] " Ahmed S. Darwish
@ 2015-01-11 20:05 ` Ahmed S. Darwish
  2015-01-11 20:11   ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() devices Ahmed S. Darwish
  2015-01-20 21:44 ` [PATCH v5 1/5] can: kvaser_usb: Update net interface state before exiting on OOM Ahmed S. Darwish
  2015-01-26  5:17 ` [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support Ahmed S. Darwish
  7 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-11 20:05 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hi,

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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() devices
  2015-01-11 20:05 ` [PATCH v4 00/04] can: Introduce support for Kvaser USBCAN-II devices Ahmed S. Darwish
@ 2015-01-11 20:11   ` Ahmed S. Darwish
  2015-01-11 20:15     ` [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM Ahmed S. Darwish
  2015-01-11 20:49     ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() Ahmed S. Darwish
  0 siblings, 2 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-11 20:11 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

We should not touch the packet after a netif_rx: it might
get freed behind our back.

Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index cc7bfc0..c32cd61 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
  2015-01-11 20:11   ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() devices Ahmed S. Darwish
@ 2015-01-11 20:15     ` Ahmed S. Darwish
  2015-01-11 20:36       ` [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
  2015-01-12 11:09       ` [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM Marc Kleine-Budde
  2015-01-11 20:49     ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() Ahmed S. Darwish
  1 sibling, 2 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-11 20:15 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Let the error counters be more accurate in case of Out of
Memory conditions.

Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index c32cd61..0eb870b 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-11 20:15     ` [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM Ahmed S. Darwish
@ 2015-01-11 20:36       ` Ahmed S. Darwish
  2015-01-11 20:45         ` [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
                           ` (3 more replies)
  2015-01-12 11:09       ` [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM Marc Kleine-Budde
  1 sibling, 4 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-11 20:36 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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 <ahmed.darwish@valeo.com>
---
 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

diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index a77db919..f6f5500 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -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.
 
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 0eb870b..da47d17 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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 <matthias.fuchs@esd.eu>, esd gmbh
  * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ * 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)
@@ -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,
@@ -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)");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
  2015-01-11 20:36       ` [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
@ 2015-01-11 20:45         ` Ahmed S. Darwish
  2015-01-11 20:51           ` Marc Kleine-Budde
  2015-01-12 11:20         ` [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
                           ` (2 subsequent siblings)
  3 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-11 20:45 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Greg Kroah-Hartman, Linux-USB, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

(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?)

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index da47d17..5925637 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx()
  2015-01-11 20:11   ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() devices Ahmed S. Darwish
  2015-01-11 20:15     ` [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM Ahmed S. Darwish
@ 2015-01-11 20:49     ` Ahmed S. Darwish
  2015-01-12 11:05       ` Marc Kleine-Budde
  1 sibling, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-11 20:49 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

We should not touch the packet after a netif_rx: it might
get freed behind our back.

Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

 (Resend, fix the garbled subject line. Sorry)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index cc7bfc0..c32cd61 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
  2015-01-11 20:45         ` [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
@ 2015-01-11 20:51           ` Marc Kleine-Budde
  2015-01-12 10:14             ` Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-11 20:51 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger
  Cc: Greg Kroah-Hartman, Linux-USB, Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 1616 bytes --]

On 01/11/2015 09:45 PM, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> (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?)
> 
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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
-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
  2015-01-11 20:51           ` Marc Kleine-Budde
@ 2015-01-12 10:14             ` Ahmed S. Darwish
  2015-01-12 10:25               ` Marc Kleine-Budde
  2015-01-12 13:33               ` Olivier Sobrie
  0 siblings, 2 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-12 10:14 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Greg Kroah-Hartman, Linux-USB, Linux-CAN, netdev, LKML

On Sun, Jan 11, 2015 at 09:51:10PM +0100, Marc Kleine-Budde wrote:
> On 01/11/2015 09:45 PM, Ahmed S. Darwish wrote:
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > 
> > (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?)
> > 
> > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
  2015-01-12 10:14             ` Ahmed S. Darwish
@ 2015-01-12 10:25               ` Marc Kleine-Budde
  2015-01-12 13:33               ` Olivier Sobrie
  1 sibling, 0 replies; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-12 10:25 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Greg Kroah-Hartman, Linux-USB, Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 2413 bytes --]

On 01/12/2015 11:14 AM, Ahmed S. Darwish wrote:
> On Sun, Jan 11, 2015 at 09:51:10PM +0100, Marc Kleine-Budde wrote:
>> On 01/11/2015 09:45 PM, Ahmed S. Darwish wrote:
>>> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>>>
>>> (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?)
>>>
>>> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>>
>> 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?

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

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx()
  2015-01-11 20:49     ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() Ahmed S. Darwish
@ 2015-01-12 11:05       ` Marc Kleine-Budde
  0 siblings, 0 replies; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-12 11:05 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 634 bytes --]

On 01/11/2015 09:49 PM, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> We should not touch the packet after a netif_rx: it might
> get freed behind our back.
> 
> Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Applied to can/master.

tnx,
Marc

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
  2015-01-11 20:15     ` [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM Ahmed S. Darwish
  2015-01-11 20:36       ` [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
@ 2015-01-12 11:09       ` Marc Kleine-Budde
  2015-01-12 20:36         ` Ahmed S. Darwish
  1 sibling, 1 reply; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-12 11:09 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 572 bytes --]

On 01/11/2015 09:15 PM, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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
-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-11 20:36       ` [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
  2015-01-11 20:45         ` [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
@ 2015-01-12 11:20         ` Ahmed S. Darwish
  2015-01-12 11:43         ` Marc Kleine-Budde
  2015-01-12 13:53         ` Olivier Sobrie
  3 siblings, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-12 11:20 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hi Marc,

On Sun, Jan 11, 2015 at 03:36:12PM -0500, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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.
> 

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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-11 20:36       ` [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
  2015-01-11 20:45         ` [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
  2015-01-12 11:20         ` [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
@ 2015-01-12 11:43         ` Marc Kleine-Budde
  2015-01-12 12:07           ` Ahmed S. Darwish
  2015-01-12 13:53         ` Olivier Sobrie
  3 siblings, 1 reply; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-12 11:43 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger
  Cc: David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 35082 bytes --]

On 01/11/2015 09:36 PM, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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 <ahmed.darwish@valeo.com>

See some minor comments inline.

Marc
> ---
>  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
> 
> diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
> index a77db919..f6f5500 100644
> --- a/drivers/net/can/usb/Kconfig
> +++ b/drivers/net/can/usb/Kconfig
> @@ -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.
>  
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index 0eb870b..da47d17 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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 <matthias.fuchs@esd.eu>, esd gmbh
>   * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
> + * 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,
> +};

Nitpick: please move after the #defines

> +
>  #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,
> @@ -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?

>  {
>  	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)

const 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.

Does USBCAN support always 2 channels or are there models with 1
channels, too. I'd rephrase ..."does support up to 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;

should not happen.

>  	}
>  
> @@ -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;

u8 please

>  
>  	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;
should not happen, please remove
> +	}
> +
> +	*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)");
> 

Marc
-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-08 15:19           ` Ahmed S. Darwish
@ 2015-01-12 11:51             ` Marc Kleine-Budde
  2015-01-12 12:26               ` Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-12 11:51 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 1559 bytes --]

On 01/08/2015 04:19 PM, Ahmed S. Darwish wrote:

[...]

>>>  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) {
>>> +	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?

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

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-12 11:43         ` Marc Kleine-Budde
@ 2015-01-12 12:07           ` Ahmed S. Darwish
  2015-01-12 12:36             ` Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-12 12:07 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hi Marc,

On Mon, Jan 12, 2015 at 12:43:56PM +0100, Marc Kleine-Budde wrote:
> On 01/11/2015 09:36 PM, Ahmed S. Darwish wrote:
[...]
> > diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> > index 0eb870b..da47d17 100644
> > --- a/drivers/net/can/usb/kvaser_usb.c
> > +++ b/drivers/net/can/usb/kvaser_usb.c
> > @@ -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 <matthias.fuchs@esd.eu>, esd gmbh
> >   * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
> > + * 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,
> > +};
> 
> Nitpick: please move after the #defines
> 

Will do.

[...]
> > @@ -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.

[...]
> > +/* 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.

[...]
> > +
> > +		/* 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.

[...]
> > +
> > +	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.
> 

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.

> > +	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;
> should not happen, please remove

Like the 'rx_msg' case above.

Thanks,
Darwish

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-12 11:51             ` Marc Kleine-Budde
@ 2015-01-12 12:26               ` Ahmed S. Darwish
  2015-01-12 12:34                 ` Marc Kleine-Budde
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-12 12:26 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

On Mon, Jan 12, 2015 at 12:51:49PM +0100, Marc Kleine-Budde wrote:
> On 01/08/2015 04:19 PM, Ahmed S. Darwish wrote:
> 
> [...]
> 
> >>>  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) {
> >>> +	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?
> 
> 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-12 12:26               ` Ahmed S. Darwish
@ 2015-01-12 12:34                 ` Marc Kleine-Budde
  0 siblings, 0 replies; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-12 12:34 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 2031 bytes --]

On 01/12/2015 01:26 PM, Ahmed S. Darwish wrote:
> On Mon, Jan 12, 2015 at 12:51:49PM +0100, Marc Kleine-Budde wrote:
>> On 01/08/2015 04:19 PM, Ahmed S. Darwish wrote:
>>
>> [...]
>>
>>>>>  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) {
>>>>> +	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?
>>
>> 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".

Thanks, I'll look at the code later and try to figure out what gcc's
problem might be.

Marc

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-12 12:07           ` Ahmed S. Darwish
@ 2015-01-12 12:36             ` Ahmed S. Darwish
  0 siblings, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-12 12:36 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

On Mon, Jan 12, 2015 at 07:07:41AM -0500, Ahmed S. Darwish wrote:
> Hi Marc,
> 
> On Mon, Jan 12, 2015 at 12:43:56PM +0100, Marc Kleine-Budde wrote:
> > On 01/11/2015 09:36 PM, Ahmed S. Darwish wrote:
> > > +
> > > +	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.
> > 
> 
> 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.
> 

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.

> > > +	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;
> > should not happen, please remove
> 
> Like the 'rx_msg' case above.
> 
> Thanks,
> Darwish

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
  2015-01-12 10:14             ` Ahmed S. Darwish
  2015-01-12 10:25               ` Marc Kleine-Budde
@ 2015-01-12 13:33               ` Olivier Sobrie
  2015-01-12 13:50                 ` Ahmed S. Darwish
  1 sibling, 1 reply; 98+ messages in thread
From: Olivier Sobrie @ 2015-01-12 13:33 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Marc Kleine-Budde, Oliver Hartkopp, Wolfgang Grandegger,
	Greg Kroah-Hartman, Linux-USB, Linux-CAN, netdev, LKML

Hello,

On Mon, Jan 12, 2015 at 05:14:07AM -0500, Ahmed S. Darwish wrote:
> On Sun, Jan 11, 2015 at 09:51:10PM +0100, Marc Kleine-Budde wrote:
> > On 01/11/2015 09:45 PM, Ahmed S. Darwish wrote:
> > > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > > 
> > > (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?)
> > > 
> > > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > 
> > 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?

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,

-- 
Olivier

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT
  2015-01-12 13:33               ` Olivier Sobrie
@ 2015-01-12 13:50                 ` Ahmed S. Darwish
  0 siblings, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-12 13:50 UTC (permalink / raw)
  To: Olivier Sobrie
  Cc: Marc Kleine-Budde, Oliver Hartkopp, Wolfgang Grandegger,
	Greg Kroah-Hartman, Linux-USB, Linux-CAN, netdev, LKML

On Mon, Jan 12, 2015 at 02:33:30PM +0100, Olivier Sobrie wrote:
> Hello,
> 
> On Mon, Jan 12, 2015 at 05:14:07AM -0500, Ahmed S. Darwish wrote:
> > On Sun, Jan 11, 2015 at 09:51:10PM +0100, Marc Kleine-Budde wrote:
> > > On 01/11/2015 09:45 PM, Ahmed S. Darwish wrote:
> > > > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > > > 
> > > > (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?)
> > > > 
> > > > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > > 
> > > 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?
> 
> 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.

> What kind of usbcan device do you use?

"Kvaser USBcan II HS/LS"

> 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-11 20:36       ` [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
                           ` (2 preceding siblings ...)
  2015-01-12 11:43         ` Marc Kleine-Budde
@ 2015-01-12 13:53         ` Olivier Sobrie
  2015-01-18 20:12           ` Ahmed S. Darwish
  3 siblings, 1 reply; 98+ messages in thread
From: Olivier Sobrie @ 2015-01-12 13:53 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hello,

On Sun, Jan 11, 2015 at 03:36:12PM -0500, Ahmed S. Darwish wrote:
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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 <ahmed.darwish@valeo.com>

Just two small remarks below.
Thanks,

Olivier

> ---
>  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
> 
> diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
> index a77db919..f6f5500 100644
> --- a/drivers/net/can/usb/Kconfig
> +++ b/drivers/net/can/usb/Kconfig
> @@ -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.
>  
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index 0eb870b..da47d17 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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 <matthias.fuchs@esd.eu>, esd gmbh
>   * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
> + * 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)
> @@ -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.

> +
> +#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;
> +};

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.

> +
> +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)");
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
  2015-01-12 11:09       ` [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM Marc Kleine-Budde
@ 2015-01-12 20:36         ` Ahmed S. Darwish
  2015-01-16 14:39           ` Marc Kleine-Budde
  2015-01-16 15:50           ` Andri Yngvason
  0 siblings, 2 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-12 20:36 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

On Mon, Jan 12, 2015 at 12:09:32PM +0100, Marc Kleine-Budde wrote:
> On 01/11/2015 09:15 PM, Ahmed S. Darwish wrote:
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > 
> > 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 <ahmed.darwish@valeo.com>

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 <mkl@pengutronix.de>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 182 +++++++++++++++++++++++----------------
 1 file changed, 106 insertions(+), 76 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index c32cd61..2d0ef76 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
  2015-01-12 20:36         ` Ahmed S. Darwish
@ 2015-01-16 14:39           ` Marc Kleine-Budde
  2015-01-16 15:50           ` Andri Yngvason
  1 sibling, 0 replies; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-16 14:39 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML,
	andri.yngvason

[-- Attachment #1: Type: text/plain, Size: 1626 bytes --]

On 01/12/2015 09:36 PM, Ahmed S. Darwish wrote:
> On Mon, Jan 12, 2015 at 12:09:32PM +0100, Marc Kleine-Budde wrote:
>> On 01/11/2015 09:15 PM, Ahmed S. Darwish wrote:
>>> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>>>
>>> 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).

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

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
  2015-01-12 20:36         ` Ahmed S. Darwish
  2015-01-16 14:39           ` Marc Kleine-Budde
@ 2015-01-16 15:50           ` Andri Yngvason
  2015-01-18 20:33             ` Ahmed S. Darwish
  1 sibling, 1 reply; 98+ messages in thread
From: Andri Yngvason @ 2015-01-16 15:50 UTC (permalink / raw)
  To: Ahmed S. Darwish, Marc Kleine-Budde; +Cc: Linux-CAN

See comments below.

Quoting Ahmed S. Darwish (2015-01-12 20:36:50)
...
> 
> [ 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 <ahmed.darwish@valeo.com>
> 
> 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 <mkl@pengutronix.de>
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> ---
>  drivers/net/can/usb/kvaser_usb.c | 182 +++++++++++++++++++++++----------------
>  1 file changed, 106 insertions(+), 76 deletions(-)
> 
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index c32cd61..2d0ef76 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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;
>  }
>  

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.

> +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.
> +               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.
> +                       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.
> +                       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)) {
This is NOT in can_change_state(). Keep it.
> +               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.
> +       priv->can.state = new_state;
> +}
> +
>  static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
>                                 const struct kvaser_msg *msg)
...
> -       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.
> +       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:
> -       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;
>                 }
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(...);
	}
>         }
>  
> -       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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-12 13:53         ` Olivier Sobrie
@ 2015-01-18 20:12           ` Ahmed S. Darwish
  2015-01-18 20:13             ` Marc Kleine-Budde
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-18 20:12 UTC (permalink / raw)
  To: Olivier Sobrie
  Cc: Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde,
	David S. Miller, Paul Gortmaker, Linux-CAN, netdev, LKML

Hi!

On Mon, Jan 12, 2015 at 02:53:02PM +0100, Olivier Sobrie wrote:
> Hello,
> 
> On Sun, Jan 11, 2015 at 03:36:12PM -0500, Ahmed S. Darwish wrote:
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > 

...

> > @@ -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.
> 

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.

...

> > +
> > +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.
> 

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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family
  2015-01-18 20:12           ` Ahmed S. Darwish
@ 2015-01-18 20:13             ` Marc Kleine-Budde
  0 siblings, 0 replies; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-18 20:13 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie
  Cc: Oliver Hartkopp, Wolfgang Grandegger, David S. Miller,
	Paul Gortmaker, Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 2137 bytes --]

On 01/18/2015 09:12 PM, Ahmed S. Darwish wrote:
> Hi!
> 
> On Mon, Jan 12, 2015 at 02:53:02PM +0100, Olivier Sobrie wrote:
>> Hello,
>>
>> On Sun, Jan 11, 2015 at 03:36:12PM -0500, Ahmed S. Darwish wrote:
>>> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>>>
> 
> ...
> 
>>> @@ -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.
>>
> 
> 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.
> 
> ...
> 
>>> +
>>> +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.
>>
> 
> 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.

+1 Keep it as it is.

Marc

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM
  2015-01-16 15:50           ` Andri Yngvason
@ 2015-01-18 20:33             ` Ahmed S. Darwish
  0 siblings, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-18 20:33 UTC (permalink / raw)
  To: Andri Yngvason; +Cc: Marc Kleine-Budde, Linux-CAN

On Fri, Jan 16, 2015 at 03:50:40PM +0000, Andri Yngvason wrote:
> See comments below.
> 
> Quoting Ahmed S. Darwish (2015-01-12 20:36:50)
> ...
> > 
> > [ 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 <ahmed.darwish@valeo.com>
> > 
> > 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 <mkl@pengutronix.de>
> > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > ---
> >  drivers/net/can/usb/kvaser_usb.c | 182 +++++++++++++++++++++++----------------
> >  1 file changed, 106 insertions(+), 76 deletions(-)
> > 
> > diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> > index c32cd61..2d0ef76 100644
> > --- a/drivers/net/can/usb/kvaser_usb.c
> > +++ b/drivers/net/can/usb/kvaser_usb.c
> > @@ -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;
> >  }
> >  
> 
> 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.
> 
> > +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.
> > +               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.
> > +                       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.
> > +                       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)) {
> This is NOT in can_change_state(). Keep it.
> > +               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.
> > +       priv->can.state = new_state;
> > +}
> > +
> >  static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> >                                 const struct kvaser_msg *msg)
> ...
> > -       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.
> > +       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:
> > -       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;
> >                 }
> 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(...);
> 	}
> >         }
> >  
> > -       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().
> 

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

> 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* [PATCH v5 1/5] can: kvaser_usb: Update net interface state before exiting on OOM
  2014-12-23 15:46 [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
                   ` (5 preceding siblings ...)
  2015-01-11 20:05 ` [PATCH v4 00/04] can: Introduce support for Kvaser USBCAN-II devices Ahmed S. Darwish
@ 2015-01-20 21:44 ` Ahmed S. Darwish
  2015-01-20 21:45   ` [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling Ahmed S. Darwish
  2015-01-26  5:17 ` [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support Ahmed S. Darwish
  7 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-20 21:44 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Andri Yngvason, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Update all of the can interface's state and error counters before
trying any skb allocation that can actually fail with -ENOMEM.

Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 182 +++++++++++++++++++++++----------------
 1 file changed, 106 insertions(+), 76 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index c32cd61..971c5f9 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-20 21:44 ` [PATCH v5 1/5] can: kvaser_usb: Update net interface state before exiting on OOM Ahmed S. Darwish
@ 2015-01-20 21:45   ` Ahmed S. Darwish
  2015-01-20 21:47     ` [PATCH v5 3/5] can: kvaser_usb: Fix state handling upon BUS_ERROR events Ahmed S. Darwish
                       ` (2 more replies)
  0 siblings, 3 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-20 21:45 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Andri Yngvason, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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 <andri.yngvason@marel.com>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++--------------------
 1 file changed, 55 insertions(+), 59 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 971c5f9..0386d3f 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v5 3/5] can: kvaser_usb: Fix state handling upon BUS_ERROR events
  2015-01-20 21:45   ` [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling Ahmed S. Darwish
@ 2015-01-20 21:47     ` Ahmed S. Darwish
  2015-01-20 21:48       ` [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
  2015-01-21 10:33     ` [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling Andri Yngvason
  2015-01-21 16:20     ` Andri Yngvason
  2 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-20 21:47 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Andri Yngvason, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 24 +++++++++++-------------
 1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 0386d3f..640b0eb 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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;
 			}
 		}
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT
  2015-01-20 21:47     ` [PATCH v5 3/5] can: kvaser_usb: Fix state handling upon BUS_ERROR events Ahmed S. Darwish
@ 2015-01-20 21:48       ` Ahmed S. Darwish
  2015-01-20 21:50         ` [PATCH v5 5/5] can: kvaser_usb: Add support for the USBcan-II family Ahmed S. Darwish
  2015-01-21 12:24         ` [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT Sergei Shtylyov
  0 siblings, 2 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-20 21:48 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Andri Yngvason, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 640b0eb..068e76c 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v5 5/5] can: kvaser_usb: Add support for the USBcan-II family
  2015-01-20 21:48       ` [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
@ 2015-01-20 21:50         ` Ahmed S. Darwish
  2015-01-21 12:24         ` [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT Sergei Shtylyov
  1 sibling, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-20 21:50 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Andri Yngvason, Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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 <ahmed.darwish@valeo.com>
---
 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

diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index a77db919..f6f5500 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -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.
 
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 068e76c..3e1eb5d 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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 <matthias.fuchs@esd.eu>, esd gmbh
  * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ * Copyright (C) 2015 Valeo A.S.
  */
 
 #include <linux/completion.h>
@@ -30,8 +32,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 */
+/* Kvaser Leaf USB devices */
 #define KVASER_VENDOR_ID		0x0bfd
 #define USB_LEAF_DEVEL_PRODUCT_ID	10
 #define USB_LEAF_LITE_PRODUCT_ID	11
@@ -56,6 +59,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;
+}
+
+/* Kvaser USBCan-II 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 +94,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 +119,11 @@
 #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_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 +133,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 +147,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,9 +171,18 @@
 #define KVASER_CTRL_MODE_SELFRECEPTION	3
 #define KVASER_CTRL_MODE_OFF		4
 
-/* log message */
+/* Extended CAN identifier flag */
 #define KVASER_EXTENDED_FRAME		BIT(31)
 
+/* 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,
+};
+
 struct kvaser_msg_simple {
 	u8 tid;
 	u8 channel;
@@ -148,30 +191,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 +256,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 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;
+} __packed;
+
+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 +347,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 +373,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,21 +390,55 @@ 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_usb_error_summary {
-	u8 channel, status, txerr, rxerr, error_factor;
+	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 {
@@ -292,6 +456,7 @@ struct kvaser_usb {
 
 	u32 fw_version;
 	unsigned int nchannels;
+	enum kvaser_usb_family family;
 
 	bool rxinitdone;
 	void *rxbuf[MAX_RX_URBS];
@@ -315,6 +480,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),
@@ -364,6 +530,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);
@@ -467,7 +644,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;
 }
@@ -486,7 +670,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;
@@ -500,8 +686,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,
@@ -623,12 +811,12 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri
 						 const struct kvaser_usb_error_summary *es,
 						 struct can_frame *cf)
 {
-	struct net_device_stats *stats;
+	struct kvaser_usb *dev = priv->dev;
+	struct net_device_stats *stats = &priv->netdev->stats;
 	enum can_state cur_state, new_state, tx_state, rx_state;
 
 	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status);
 
-	stats = &priv->netdev->stats;
 	new_state = cur_state = priv->can.state;
 
 	if (es->status & M16C_STATE_BUS_OFF)
@@ -663,9 +851,22 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri
 		priv->can.can_stats.restarts++;
 	}
 
-	if (es->error_factor) {
-		priv->can.can_stats.bus_error++;
-		stats->rx_errors++;
+	switch (dev->family) {
+	case KVASER_LEAF:
+		if (es->leaf.error_factor) {
+			priv->can.can_stats.bus_error++;
+			stats->rx_errors++;
+		}
+		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++;
+		}
+		break;
 	}
 
 	priv->bec.txerr = es->txerr;
@@ -673,53 +874,24 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri
 }
 
 static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
-				const struct kvaser_msg *msg)
+				const struct kvaser_usb_error_summary *es)
 {
 	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, new_state;
 
-	switch (msg->id) {
-	case CMD_CAN_ERROR_EVENT:
-		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:
-		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:
-		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",
-			msg->id);
-		return;
-	}
-
-	if (es.channel >= dev->nchannels) {
+	if (es->channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
-			"Invalid channel number (%d)\n", es.channel);
+			"Invalid channel number (%d)\n", es->channel);
 		return;
 	}
 
-	priv = dev->nets[es.channel];
+	priv = dev->nets[es->channel];
 	stats = &priv->netdev->stats;
 
-	if (es.status & M16C_STATE_BUS_RESET) {
+	if (es->status & M16C_STATE_BUS_RESET) {
 		kvaser_usb_unlink_tx_urbs(priv);
 		return;
 	}
@@ -735,7 +907,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 	 * frame ID and data to userspace. Remove stack allocation afterwards.
 	 */
 	old_state = priv->can.state;
-	kvaser_usb_rx_error_update_can_state(priv, &es, &tmp_cf);
+	kvaser_usb_rx_error_update_can_state(priv, es, &tmp_cf);
 	new_state = priv->can.state;
 
 	skb = alloc_can_err_skb(priv->netdev, &cf);
@@ -746,19 +918,19 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 	memcpy(cf, &tmp_cf, sizeof(*cf));
 
 	if (new_state != old_state) {
-		if (es.status & M16C_STATE_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);
-		} else if (es.status & M16C_STATE_BUS_ERROR) {
-			if ((es.txerr < 96 && es.rxerr < 96) &&
+		} 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;
 			}
 		}
 
-		if (!es.status) {
+		if (!es->status) {
 			cf->can_id |= CAN_ERR_PROT;
 			cf->data[2] = CAN_ERR_PROT_ACTIVE;
 		}
@@ -771,34 +943,161 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		}
 	}
 
-	if (es.error_factor) {
-		cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
-
-		if (es.error_factor & M16C_EF_ACKE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
-		if (es.error_factor & M16C_EF_CRCE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
-					CAN_ERR_PROT_LOC_CRC_DEL);
-		if (es.error_factor & M16C_EF_FORME)
-			cf->data[2] |= CAN_ERR_PROT_FORM;
-		if (es.error_factor & M16C_EF_STFE)
-			cf->data[2] |= CAN_ERR_PROT_STUFF;
-		if (es.error_factor & M16C_EF_BITE0)
-			cf->data[2] |= CAN_ERR_PROT_BIT0;
-		if (es.error_factor & M16C_EF_BITE1)
-			cf->data[2] |= CAN_ERR_PROT_BIT1;
-		if (es.error_factor & M16C_EF_TRE)
-			cf->data[2] |= CAN_ERR_PROT_TX;
+	switch (dev->family) {
+	case KVASER_LEAF:
+		if (es->leaf.error_factor) {
+			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_BUSERROR) {
+			cf->can_id |= CAN_ERR_BUSERROR;
+		}
+		break;
 	}
 
-	cf->data[6] = es.txerr;
-	cf->data[7] = es.rxerr;
+	cf->data[6] = es->txerr;
+	cf->data[7] = es->rxerr;
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
 	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_usb_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_usb_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 supports up to 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_usb_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)
 {
@@ -806,16 +1105,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++;
 
@@ -841,7 +1140,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 = NULL;	/* GCC */
 
 	if (channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
@@ -852,60 +1152,68 @@ 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;
+	}
+
 	skb = alloc_can_skb(priv->netdev, &cf);
 	if (!skb) {
 		stats->tx_dropped++;
 		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);
 	}
 
@@ -968,21 +1276,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;
 	}
@@ -1202,7 +1524,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)
@@ -1310,6 +1632,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;
+	u8 *msg_tx_can_flags = NULL;		/* GCC */
 
 	if (can_dropped_invalid_skb(netdev, skb))
 		return NETDEV_TX_OK;
@@ -1331,9 +1654,19 @@ 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;
+	}
+
+	*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;
@@ -1351,7 +1684,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) {
@@ -1620,6 +1953,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)");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-20 21:45   ` [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling Ahmed S. Darwish
  2015-01-20 21:47     ` [PATCH v5 3/5] can: kvaser_usb: Fix state handling upon BUS_ERROR events Ahmed S. Darwish
@ 2015-01-21 10:33     ` Andri Yngvason
  2015-01-21 10:44       ` Marc Kleine-Budde
  2015-01-21 11:53       ` Wolfgang Grandegger
  2015-01-21 16:20     ` Andri Yngvason
  2 siblings, 2 replies; 98+ messages in thread
From: Andri Yngvason @ 2015-01-21 10:33 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp,
	Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Linux-CAN, netdev, LKML

Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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 <andri.yngvason@marel.com>
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> ---
>  drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++--------------------
>  1 file changed, 55 insertions(+), 59 deletions(-)
> 
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index 971c5f9..0386d3f 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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) {
> -- 
> 1.9.1

Looks good.

--
Andri

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 10:33     ` [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling Andri Yngvason
@ 2015-01-21 10:44       ` Marc Kleine-Budde
  2015-01-21 11:00         ` Andri Yngvason
  2015-01-21 11:53       ` Wolfgang Grandegger
  1 sibling, 1 reply; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-21 10:44 UTC (permalink / raw)
  To: Andri Yngvason, Ahmed S. Darwish, Olivier Sobrie,
	Oliver Hartkopp, Wolfgang Grandegger
  Cc: Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 1091 bytes --]

On 01/21/2015 11:33 AM, Andri Yngvason wrote:
> Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
>> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>>
>> 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 <andri.yngvason@marel.com>
>> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>> ---
>>  drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++--------------------
>>  1 file changed, 55 insertions(+), 59 deletions(-)
>>
>> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
>> index 971c5f9..0386d3f 100644
>> --- a/drivers/net/can/usb/kvaser_usb.c
>> +++ b/drivers/net/can/usb/kvaser_usb.c

> Looks good.

Is this an Acked-by?

Marc

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 10:44       ` Marc Kleine-Budde
@ 2015-01-21 11:00         ` Andri Yngvason
  0 siblings, 0 replies; 98+ messages in thread
From: Andri Yngvason @ 2015-01-21 11:00 UTC (permalink / raw)
  To: Marc Kleine-Budde, Ahmed S. Darwish, Olivier Sobrie,
	Oliver Hartkopp, Wolfgang Grandegger
  Cc: Linux-CAN, netdev, LKML

Quoting Marc Kleine-Budde (2015-01-21 10:44:54)
> On 01/21/2015 11:33 AM, Andri Yngvason wrote:
> > Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
> >> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> >>
> >> 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 <andri.yngvason@marel.com>
> >> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> >> ---
> >>  drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++--------------------
> >>  1 file changed, 55 insertions(+), 59 deletions(-)
> >>
> >> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> >> index 971c5f9..0386d3f 100644
> >> --- a/drivers/net/can/usb/kvaser_usb.c
> >> +++ b/drivers/net/can/usb/kvaser_usb.c
> 
> > Looks good.
> 
> Is this an Acked-by?
> 

ACK.

--
Andri

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 10:33     ` [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling Andri Yngvason
  2015-01-21 10:44       ` Marc Kleine-Budde
@ 2015-01-21 11:53       ` Wolfgang Grandegger
  2015-01-21 14:43         ` Ahmed S. Darwish
  1 sibling, 1 reply; 98+ messages in thread
From: Wolfgang Grandegger @ 2015-01-21 11:53 UTC (permalink / raw)
  To: Andri Yngvason
  Cc: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp,
	Marc Kleine-Budde, Linux-CAN, netdev, LKML

On Wed, 21 Jan 2015 10:33:19 +0000, Andri Yngvason
<andri.yngvason@marel.com> wrote:
> Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
>> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>> 
>> 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 <andri.yngvason@marel.com>
>> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>> ---
>>  drivers/net/can/usb/kvaser_usb.c | 114
>>  +++++++++++++++++++--------------------
>>  1 file changed, 55 insertions(+), 59 deletions(-)
>> 
>> diff --git a/drivers/net/can/usb/kvaser_usb.c
>> b/drivers/net/can/usb/kvaser_usb.c
>> index 971c5f9..0386d3f 100644
>> --- a/drivers/net/can/usb/kvaser_usb.c
>> +++ b/drivers/net/can/usb/kvaser_usb.c

...
> 
> 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.

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT
  2015-01-20 21:48       ` [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
  2015-01-20 21:50         ` [PATCH v5 5/5] can: kvaser_usb: Add support for the USBcan-II family Ahmed S. Darwish
@ 2015-01-21 12:24         ` Sergei Shtylyov
  2015-01-25 11:59           ` Ahmed S. Darwish
  1 sibling, 1 reply; 98+ messages in thread
From: Sergei Shtylyov @ 2015-01-21 12:24 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp,
	Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Andri Yngvason, Linux-CAN, netdev, LKML

Hello.

On 1/21/2015 12:48 AM, Ahmed S. Darwish wrote:

> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

> 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.

> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> ---
>   drivers/net/can/usb/kvaser_usb.c | 12 ++++++++++--
>   1 file changed, 10 insertions(+), 2 deletions(-)

> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index 640b0eb..068e76c 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
[...]
> @@ -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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 11:53       ` Wolfgang Grandegger
@ 2015-01-21 14:43         ` Ahmed S. Darwish
  2015-01-21 15:00           ` Andri Yngvason
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-21 14:43 UTC (permalink / raw)
  To: Wolfgang Grandegger
  Cc: Andri Yngvason, Olivier Sobrie, Oliver Hartkopp,
	Marc Kleine-Budde, Linux-CAN, netdev, LKML

Hi!

On Wed, Jan 21, 2015 at 12:53:58PM +0100, Wolfgang Grandegger wrote:
> On Wed, 21 Jan 2015 10:33:19 +0000, Andri Yngvason
> <andri.yngvason@marel.com> wrote:
> > Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
> >> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> >> 
> >> 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 <andri.yngvason@marel.com>
> >> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> >> ---
> >>  drivers/net/can/usb/kvaser_usb.c | 114
> >>  +++++++++++++++++++--------------------
> >>  1 file changed, 55 insertions(+), 59 deletions(-)
> >> 
> >> diff --git a/drivers/net/can/usb/kvaser_usb.c
> >> b/drivers/net/can/usb/kvaser_usb.c
> >> index 971c5f9..0386d3f 100644
> >> --- a/drivers/net/can/usb/kvaser_usb.c
> >> +++ b/drivers/net/can/usb/kvaser_usb.c
> 
> ...
> > 
> > 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 14:43         ` Ahmed S. Darwish
@ 2015-01-21 15:00           ` Andri Yngvason
  2015-01-21 15:36             ` Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Andri Yngvason @ 2015-01-21 15:00 UTC (permalink / raw)
  To: Ahmed S. Darwish, Wolfgang Grandegger
  Cc: Olivier Sobrie, Oliver Hartkopp, Marc Kleine-Budde, Linux-CAN,
	netdev, LKML

Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
> Hi!
> 
> On Wed, Jan 21, 2015 at 12:53:58PM +0100, Wolfgang Grandegger wrote:
> > On Wed, 21 Jan 2015 10:33:19 +0000, Andri Yngvason
> > <andri.yngvason@marel.com> wrote:
> > > Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
> > >> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > >> 
> > >> 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 <andri.yngvason@marel.com>
> > >> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > >> ---
> > >>  drivers/net/can/usb/kvaser_usb.c | 114
> > >>  +++++++++++++++++++--------------------
> > >>  1 file changed, 55 insertions(+), 59 deletions(-)
> > >> 
> > >> diff --git a/drivers/net/can/usb/kvaser_usb.c
> > >> b/drivers/net/can/usb/kvaser_usb.c
> > >> index 971c5f9..0386d3f 100644
> > >> --- a/drivers/net/can/usb/kvaser_usb.c
> > >> +++ b/drivers/net/can/usb/kvaser_usb.c
> > 
> > ...
> > > 
> > > 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.
[...]
> 
> 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}}
[...]
>         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.
>         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}
Also good.
>         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 -->
>
Where are the reverse state transitions?
> 
>  (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 ))
> 
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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 15:00           ` Andri Yngvason
@ 2015-01-21 15:36             ` Ahmed S. Darwish
  2015-01-21 16:13               ` Wolfgang Grandegger
  2015-01-21 16:37               ` Andri Yngvason
  0 siblings, 2 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-21 15:36 UTC (permalink / raw)
  To: Andri Yngvason
  Cc: Wolfgang Grandegger, Olivier Sobrie, Oliver Hartkopp,
	Marc Kleine-Budde, Linux-CAN, netdev, LKML

On Wed, Jan 21, 2015 at 03:00:15PM +0000, Andri Yngvason wrote:
> Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
> > Hi!

...

> > <-- 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}}
> [...]
> >         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.
> >         bus-error
> >         error-counter-tx-rx{{96}{0}}

Nice.

> >  (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}
> Also good.
> >         bus-error
> >         error-counter-tx-rx{{128}{0}}

Also nice :-)

> >  (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 -->
> >
> Where are the reverse state transitions?
> > 

Hmmm...

[ ... ]
> 
> 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.


^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 15:36             ` Ahmed S. Darwish
@ 2015-01-21 16:13               ` Wolfgang Grandegger
  2015-01-23  6:07                 ` Ahmed S. Darwish
  2015-01-21 16:37               ` Andri Yngvason
  1 sibling, 1 reply; 98+ messages in thread
From: Wolfgang Grandegger @ 2015-01-21 16:13 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Andri Yngvason, Olivier Sobrie, Oliver Hartkopp,
	Marc Kleine-Budde, Linux-CAN, netdev, LKML

On Wed, 21 Jan 2015 10:36:47 -0500, "Ahmed S. Darwish"
<darwish.07@gmail.com> wrote:
> On Wed, Jan 21, 2015 at 03:00:15PM +0000, Andri Yngvason wrote:
>> Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
>> > Hi!
> 
> ...
> 
>> > <-- 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  

For a bus-errors I would also expcect some more information in the
data[2..3] fields. But these are always zero.

>> >  ERRORFRAME
>> >         bus-error
>> >         error-counter-tx-rx{{16}{0}}
>> [...]
>> >         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.
>> >         bus-error
>> >         error-counter-tx-rx{{96}{0}}
> 
> Nice.
> 
>> >  (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}
>> Also good.
>> >         bus-error
>> >         error-counter-tx-rx{{128}{0}}
> 
> Also nice :-)
> 
>> >  (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 -->
>> >
>> Where are the reverse state transitions?
>> > 
> 
> Hmmm...
> 
> [ ... ]
>> 
>> 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.

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.

> So, What can the driver do given the above?

Little if the notification does not come.

Wolfgang.


^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-20 21:45   ` [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling Ahmed S. Darwish
  2015-01-20 21:47     ` [PATCH v5 3/5] can: kvaser_usb: Fix state handling upon BUS_ERROR events Ahmed S. Darwish
  2015-01-21 10:33     ` [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling Andri Yngvason
@ 2015-01-21 16:20     ` Andri Yngvason
  2015-01-21 22:59       ` Marc Kleine-Budde
  2015-01-25  3:21       ` Ahmed S. Darwish
  2 siblings, 2 replies; 98+ messages in thread
From: Andri Yngvason @ 2015-01-21 16:20 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp,
	Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Linux-CAN, netdev, LKML

Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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 <andri.yngvason@marel.com>
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> ---
>  drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++--------------------
>  1 file changed, 55 insertions(+), 59 deletions(-)
> 
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index 971c5f9..0386d3f 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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);
This (below) is redundant. It doesn't harm but at this point can_change_state
has set priv->can.state to new_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);
> +               }
> +
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.
> +               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) {
This is also redundant, and wrong:
> +               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) {
> -- 
> 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 15:36             ` Ahmed S. Darwish
  2015-01-21 16:13               ` Wolfgang Grandegger
@ 2015-01-21 16:37               ` Andri Yngvason
  1 sibling, 0 replies; 98+ messages in thread
From: Andri Yngvason @ 2015-01-21 16:37 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Wolfgang Grandegger, Olivier Sobrie, Oliver Hartkopp,
	Marc Kleine-Budde, Linux-CAN, netdev, LKML

Quoting Ahmed S. Darwish (2015-01-21 15:36:47)
> On Wed, Jan 21, 2015 at 03:00:15PM +0000, Andri Yngvason wrote:
> > Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
> > > Hi!
> 
> ...
> 
> > > <-- 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}}
> > [...]
> > >         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.
> > >         bus-error
> > >         error-counter-tx-rx{{96}{0}}
> 
> Nice.
> 
> > >  (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}
> > Also good.
> > >         bus-error
> > >         error-counter-tx-rx{{128}{0}}
> 
> Also nice :-)
> 
> > >  (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 -->
> > >
> > Where are the reverse state transitions?
> > > 
> 
> Hmmm...
> 
> [ ... ]
> > 
> > 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?
>
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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 16:20     ` Andri Yngvason
@ 2015-01-21 22:59       ` Marc Kleine-Budde
  2015-01-22 10:14         ` Andri Yngvason
  2015-01-25  3:21       ` Ahmed S. Darwish
  1 sibling, 1 reply; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-21 22:59 UTC (permalink / raw)
  To: Andri Yngvason, Ahmed S. Darwish, Olivier Sobrie,
	Oliver Hartkopp, Wolfgang Grandegger
  Cc: Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 613 bytes --]

On 01/21/2015 05:20 PM, Andri Yngvason wrote:
> 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

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 22:59       ` Marc Kleine-Budde
@ 2015-01-22 10:14         ` Andri Yngvason
  2015-01-25  2:49           ` Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Andri Yngvason @ 2015-01-22 10:14 UTC (permalink / raw)
  To: Marc Kleine-Budde, Ahmed S. Darwish, Olivier Sobrie,
	Oliver Hartkopp, Wolfgang Grandegger
  Cc: Linux-CAN, netdev, LKML

Quoting Marc Kleine-Budde (2015-01-21 22:59:23)
> On 01/21/2015 05:20 PM, Andri Yngvason wrote:
> > 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 16:13               ` Wolfgang Grandegger
@ 2015-01-23  6:07                 ` Ahmed S. Darwish
  2015-01-23 10:32                   ` Andri Yngvason
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-23  6:07 UTC (permalink / raw)
  To: Wolfgang Grandegger
  Cc: Andri Yngvason, Olivier Sobrie, Oliver Hartkopp,
	Marc Kleine-Budde, Linux-CAN, netdev, LKML

On Wed, Jan 21, 2015 at 05:13:45PM +0100, Wolfgang Grandegger wrote:
> On Wed, 21 Jan 2015 10:36:47 -0500, "Ahmed S. Darwish"
> <darwish.07@gmail.com> wrote:
> > On Wed, Jan 21, 2015 at 03:00:15PM +0000, Andri Yngvason wrote:
> >> Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
> >> > Hi!
> > 
> > ...
> > 
> >> > <-- 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  
> 
> 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:

> >> >  ERRORFRAME
> >> >         bus-error
> >> >         error-counter-tx-rx{{16}{0}}
> >> [...]
> >> >         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.
> >> >         bus-error
> >> >         error-counter-tx-rx{{96}{0}}
> > 
> > Nice.
> > 
> >> >  (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}
> >> Also good.
> >> >         bus-error
> >> >         error-counter-tx-rx{{128}{0}}
> > 
> > Also nice :-)
> > 
> >> >  (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 -->
> >> >
> >> Where are the reverse state transitions?
> >> > 
> > 
> > Hmmm...
> > 
> > [ ... ]
> >> 
> >> 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.
> 
> 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.
> 

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.

> > 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.

> Wolfgang.
> 

Regards,
Darwish

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-23  6:07                 ` Ahmed S. Darwish
@ 2015-01-23 10:32                   ` Andri Yngvason
  2015-01-25  2:43                     ` Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Andri Yngvason @ 2015-01-23 10:32 UTC (permalink / raw)
  To: Ahmed S. Darwish, Wolfgang Grandegger
  Cc: Olivier Sobrie, Oliver Hartkopp, Marc Kleine-Budde, Linux-CAN,
	netdev, LKML

Quoting Ahmed S. Darwish (2015-01-23 06:07:34)
> On Wed, Jan 21, 2015 at 05:13:45PM +0100, Wolfgang Grandegger wrote:
> > On Wed, 21 Jan 2015 10:36:47 -0500, "Ahmed S. Darwish"
> > <darwish.07@gmail.com> wrote:
> > > On Wed, Jan 21, 2015 at 03:00:15PM +0000, Andri Yngvason wrote:
> > >> Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
> > >> > Hi!
> > > 
> > > ...
> > > 
> > >> > <-- 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  
> > 
> > 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 :-(
>
We experienced similar problems with FlexCAN.
> 
> The issue of incomplete data does not even stop here, kindly
> check below notes regarding reverse state transitions:
> 
> > >> >  ERRORFRAME
> > >> >         bus-error
> > >> >         error-counter-tx-rx{{16}{0}}
> > >> [...]
[...]
> > >> >  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 -->
> > >> >
> > >> Where are the reverse state transitions?
> > >> > 
> > > 
> > > Hmmm...
> > > 
> > > [ ... ]
> > >> 
> > >> 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.
> > 
> > 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.
> > 
> 
> 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.
> 
> > > 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.
>
Honestly, I don't know.
>
> A possible solution can be setting up a kernel thread that queries
> for a CHIP_STATE_EVENT every 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-23 10:32                   ` Andri Yngvason
@ 2015-01-25  2:43                     ` Ahmed S. Darwish
  2015-01-26 10:21                       ` Andri Yngvason
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-25  2:43 UTC (permalink / raw)
  To: Andri Yngvason
  Cc: Wolfgang Grandegger, Olivier Sobrie, Oliver Hartkopp,
	Marc Kleine-Budde, Linux-CAN, netdev, LKML

On Fri, Jan 23, 2015 at 10:32:13AM +0000, Andri Yngvason wrote:
> Quoting Ahmed S. Darwish (2015-01-23 06:07:34)
> > On Wed, Jan 21, 2015 at 05:13:45PM +0100, Wolfgang Grandegger wrote:
> > > On Wed, 21 Jan 2015 10:36:47 -0500, "Ahmed S. Darwish"
> > > <darwish.07@gmail.com> wrote:
> > > > On Wed, Jan 21, 2015 at 03:00:15PM +0000, Andri Yngvason wrote:
> > > >> Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
> > > >> > Hi!
> > > > 
> > > > ...
> > > > 
> > > >> > <-- 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  
> > > 
> > > 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 :-(
> >
> 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 :-)

[...]

> > 
> > 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.
> > 
> > > > 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.
> >
> Honestly, I don't know.
> >
> > A possible solution can be setting up a kernel thread that queries
> > for a CHIP_STATE_EVENT every 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();
> }
> 

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;
}

> 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 :-(

> Best regards,
> Andri

Regards,
Darwish


^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-22 10:14         ` Andri Yngvason
@ 2015-01-25  2:49           ` Ahmed S. Darwish
  0 siblings, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-25  2:49 UTC (permalink / raw)
  To: Andri Yngvason
  Cc: Marc Kleine-Budde, Olivier Sobrie, Oliver Hartkopp,
	Wolfgang Grandegger, Linux-CAN, netdev, LKML

On Thu, Jan 22, 2015 at 10:14:47AM +0000, Andri Yngvason wrote:
> Quoting Marc Kleine-Budde (2015-01-21 22:59:23)
> > On 01/21/2015 05:20 PM, Andri Yngvason wrote:
> > > 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-21 16:20     ` Andri Yngvason
  2015-01-21 22:59       ` Marc Kleine-Budde
@ 2015-01-25  3:21       ` Ahmed S. Darwish
  1 sibling, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-25  3:21 UTC (permalink / raw)
  To: Andri Yngvason
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, Linux-CAN, netdev, LKML

Hi!

On Wed, Jan 21, 2015 at 04:20:25PM +0000, Andri Yngvason wrote:
> Quoting Ahmed S. Darwish (2015-01-20 21:45:37)
> > From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > 
> > 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 <andri.yngvason@marel.com>
> > Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> > ---
> >  drivers/net/can/usb/kvaser_usb.c | 114 +++++++++++++++++++--------------------
> >  1 file changed, 55 insertions(+), 59 deletions(-)
> > 
> > diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> > index 971c5f9..0386d3f 100644
> > --- a/drivers/net/can/usb/kvaser_usb.c
> > +++ b/drivers/net/can/usb/kvaser_usb.c
> > @@ -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);
>
> This (below) is redundant. It doesn't harm but at this point can_change_state
> has set priv->can.state to new_state.
>
> > +               new_state = priv->can.state;
> > +       }
> > +

Correct; I will remove it.

> >         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);
> > +               }
> > +
>
> This block [below] 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.
>
> > +               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. ]

> > -       }
> >  
> > -       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:
>
> > +               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! ;-)

> >  
> > -       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) {
> > -- 
> > 1.9.1
> 
> Looking 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT
  2015-01-21 12:24         ` [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT Sergei Shtylyov
@ 2015-01-25 11:59           ` Ahmed S. Darwish
  0 siblings, 0 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-25 11:59 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, Andri Yngvason, Linux-CAN, netdev, LKML

On Wed, Jan 21, 2015 at 03:24:46PM +0300, Sergei Shtylyov wrote:
> Hello.
> 
> On 1/21/2015 12:48 AM, Ahmed S. Darwish wrote:
> 
> >From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> >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.
> 
> >Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> >---
> >  drivers/net/can/usb/kvaser_usb.c | 12 ++++++++++--
> >  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> >diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> >index 640b0eb..068e76c 100644
> >--- a/drivers/net/can/usb/kvaser_usb.c
> >+++ b/drivers/net/can/usb/kvaser_usb.c
> [...]
> >@@ -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.
> 

Thanks, both fixed in the next submission :-D

Regards,
Darwish

^ permalink raw reply	[flat|nested] 98+ messages in thread

* [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support
  2014-12-23 15:46 [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
                   ` (6 preceding siblings ...)
  2015-01-20 21:44 ` [PATCH v5 1/5] can: kvaser_usb: Update net interface state before exiting on OOM Ahmed S. Darwish
@ 2015-01-26  5:17 ` Ahmed S. Darwish
  2015-01-26  5:20   ` [PATCH v6 1/7] can: kvaser_usb: Do not sleep in atomic context Ahmed S. Darwish
                     ` (2 more replies)
  7 siblings, 3 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-26  5:17 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, Andri Yngvason
  Cc: Linux-CAN, netdev, LKML

Hi!

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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* [PATCH v6 1/7] can: kvaser_usb: Do not sleep in atomic context
  2015-01-26  5:17 ` [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support Ahmed S. Darwish
@ 2015-01-26  5:20   ` Ahmed S. Darwish
  2015-01-26  5:22     ` [PATCH v6 2/7] can: kvaser_usb: Send correct context to URB completion Ahmed S. Darwish
  2015-01-26  9:55   ` [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support Marc Kleine-Budde
  2015-01-26 10:07   ` Marc Kleine-Budde
  2 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-26  5:20 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, Andri Yngvason
  Cc: Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c |    7 +------
 1 files changed, 1 insertions(+), 6 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index c32cd61..978a25e 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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++;
-- 
1.7.7.6



^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v6 2/7] can: kvaser_usb: Send correct context to URB completion
  2015-01-26  5:20   ` [PATCH v6 1/7] can: kvaser_usb: Do not sleep in atomic context Ahmed S. Darwish
@ 2015-01-26  5:22     ` Ahmed S. Darwish
  2015-01-26  5:24       ` [PATCH v6 3/7] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-26  5:22 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, Andri Yngvason
  Cc: Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 978a25e..f0c6207 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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);
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v6 3/7] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT
  2015-01-26  5:22     ` [PATCH v6 2/7] can: kvaser_usb: Send correct context to URB completion Ahmed S. Darwish
@ 2015-01-26  5:24       ` Ahmed S. Darwish
  2015-01-26  5:25         ` [PATCH v6 4/7] can: kvaser_usb: Fix state handling upon BUS_ERROR events Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-26  5:24 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, Andri Yngvason
  Cc: Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index f0c6207..55407b9 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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);
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v6 4/7] can: kvaser_usb: Fix state handling upon BUS_ERROR events
  2015-01-26  5:24       ` [PATCH v6 3/7] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
@ 2015-01-26  5:25         ` Ahmed S. Darwish
  2015-01-26  5:27           ` [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM Ahmed S. Darwish
  0 siblings, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-26  5:25 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, Andri Yngvason
  Cc: Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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.

Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c |    7 +++----
 1 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 55407b9..7af379c 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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;
 
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM
  2015-01-26  5:25         ` [PATCH v6 4/7] can: kvaser_usb: Fix state handling upon BUS_ERROR events Ahmed S. Darwish
@ 2015-01-26  5:27           ` Ahmed S. Darwish
  2015-01-26  5:29             ` [PATCH v6 6/7] can: kvaser_usb: Consolidate and unify state change handling Ahmed S. Darwish
  2015-01-26 10:28             ` [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM Andri Yngvason
  0 siblings, 2 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-26  5:27 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, Andri Yngvason
  Cc: Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

Update all of the can interface's state and error counters before
trying any skb allocation that can actually fail with -ENOMEM.

Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c |  181 ++++++++++++++++++++++----------------
 1 files changed, 105 insertions(+), 76 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 7af379c..f57ce55 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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);
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v6 6/7] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-26  5:27           ` [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM Ahmed S. Darwish
@ 2015-01-26  5:29             ` Ahmed S. Darwish
  2015-01-26  5:33               ` [PATCH v6 7/7] can: kvaser_usb: Add support for the USBcan-II family Ahmed S. Darwish
  2015-01-26 10:26               ` [PATCH v6 6/7] can: kvaser_usb: Consolidate and unify state change handling Andri Yngvason
  2015-01-26 10:28             ` [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM Andri Yngvason
  1 sibling, 2 replies; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-26  5:29 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, Andri Yngvason
  Cc: Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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 <andri.yngvason@marel.com>
Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/kvaser_usb.c |  113 ++++++++++++++++---------------------
 1 files changed, 49 insertions(+), 64 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index f57ce55..ddc2954 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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) {
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* [PATCH v6 7/7] can: kvaser_usb: Add support for the USBcan-II family
  2015-01-26  5:29             ` [PATCH v6 6/7] can: kvaser_usb: Consolidate and unify state change handling Ahmed S. Darwish
@ 2015-01-26  5:33               ` Ahmed S. Darwish
  2015-01-26 10:34                 ` Andri Yngvason
  2015-01-26 10:26               ` [PATCH v6 6/7] can: kvaser_usb: Consolidate and unify state change handling Andri Yngvason
  1 sibling, 1 reply; 98+ messages in thread
From: Ahmed S. Darwish @ 2015-01-26  5:33 UTC (permalink / raw)
  To: Olivier Sobrie, Oliver Hartkopp, Wolfgang Grandegger,
	Marc Kleine-Budde, Andri Yngvason
  Cc: Linux-CAN, netdev, LKML

From: Ahmed S. Darwish <ahmed.darwish@valeo.com>

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 <ahmed.darwish@valeo.com>
---
 drivers/net/can/usb/Kconfig      |    8 +-
 drivers/net/can/usb/kvaser_usb.c |  590 ++++++++++++++++++++++++++++++--------
 2 files changed, 474 insertions(+), 124 deletions(-)

** V6 Changelog:
- Revert to the error-active state if the error counters were
  decreased by hardware
- Rebase over a new set of upstream Leaf-driver bugfixes

** 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

diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index a77db919..f6f5500 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -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.
 
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index ddc2954..17d28d7 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -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 <matthias.fuchs@esd.eu>, esd gmbh
  * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ * Copyright (C) 2015 Valeo A.S.
  */
 
 #include <linux/completion.h>
@@ -30,8 +32,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 */
+/* Kvaser Leaf USB devices */
 #define KVASER_VENDOR_ID		0x0bfd
 #define USB_LEAF_DEVEL_PRODUCT_ID	10
 #define USB_LEAF_LITE_PRODUCT_ID	11
@@ -56,6 +59,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;
+}
+
+/* Kvaser USBCan-II 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 +94,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 +119,11 @@
 #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_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 +133,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 +147,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,9 +171,18 @@
 #define KVASER_CTRL_MODE_SELFRECEPTION	3
 #define KVASER_CTRL_MODE_OFF		4
 
-/* log message */
+/* Extended CAN identifier flag */
 #define KVASER_EXTENDED_FRAME		BIT(31)
 
+/* 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,
+};
+
 struct kvaser_msg_simple {
 	u8 tid;
 	u8 channel;
@@ -148,30 +191,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 +256,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 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;
+} __packed;
+
+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 +347,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 +373,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,21 +390,55 @@ 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_usb_error_summary {
-	u8 channel, status, txerr, rxerr, error_factor;
+	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 {
@@ -292,6 +456,7 @@ struct kvaser_usb {
 
 	u32 fw_version;
 	unsigned int nchannels;
+	enum kvaser_usb_family family;
 
 	bool rxinitdone;
 	void *rxbuf[MAX_RX_URBS];
@@ -315,6 +480,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),
@@ -364,6 +530,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);
@@ -467,7 +644,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;
 }
@@ -486,7 +670,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;
@@ -500,8 +686,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,
@@ -623,12 +811,12 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri
 						 const struct kvaser_usb_error_summary *es,
 						 struct can_frame *cf)
 {
-	struct net_device_stats *stats;
+	struct kvaser_usb *dev = priv->dev;
+	struct net_device_stats *stats = &priv->netdev->stats;
 	enum can_state cur_state, new_state, tx_state, rx_state;
 
 	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status);
 
-	stats = &priv->netdev->stats;
 	new_state = cur_state = priv->can.state;
 
 	if (es->status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET))
@@ -662,9 +850,22 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri
 		priv->can.can_stats.restarts++;
 	}
 
-	if (es->error_factor) {
-		priv->can.can_stats.bus_error++;
-		stats->rx_errors++;
+	switch (dev->family) {
+	case KVASER_LEAF:
+		if (es->leaf.error_factor) {
+			priv->can.can_stats.bus_error++;
+			stats->rx_errors++;
+		}
+		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++;
+		}
+		break;
 	}
 
 	priv->bec.txerr = es->txerr;
@@ -672,50 +873,21 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri
 }
 
 static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
-				const struct kvaser_msg *msg)
+				const struct kvaser_usb_error_summary *es)
 {
 	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, new_state;
 
-	switch (msg->id) {
-	case CMD_CAN_ERROR_EVENT:
-		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:
-		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:
-		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",
-			msg->id);
-		return;
-	}
-
-	if (es.channel >= dev->nchannels) {
+	if (es->channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
-			"Invalid channel number (%d)\n", es.channel);
+			"Invalid channel number (%d)\n", es->channel);
 		return;
 	}
 
-	priv = dev->nets[es.channel];
+	priv = dev->nets[es->channel];
 	stats = &priv->netdev->stats;
 
 	/* Update all of the can interface's state and error counters before
@@ -729,7 +901,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 	 * frame ID and data to userspace. Remove stack allocation afterwards.
 	 */
 	old_state = priv->can.state;
-	kvaser_usb_rx_error_update_can_state(priv, &es, &tmp_cf);
+	kvaser_usb_rx_error_update_can_state(priv, es, &tmp_cf);
 	new_state = priv->can.state;
 
 	skb = alloc_can_err_skb(priv->netdev, &cf);
@@ -740,7 +912,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 	memcpy(cf, &tmp_cf, sizeof(*cf));
 
 	if (new_state != old_state) {
-		if (es.status &
+		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);
@@ -755,34 +927,161 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 		}
 	}
 
-	if (es.error_factor) {
-		cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
-
-		if (es.error_factor & M16C_EF_ACKE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
-		if (es.error_factor & M16C_EF_CRCE)
-			cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
-					CAN_ERR_PROT_LOC_CRC_DEL);
-		if (es.error_factor & M16C_EF_FORME)
-			cf->data[2] |= CAN_ERR_PROT_FORM;
-		if (es.error_factor & M16C_EF_STFE)
-			cf->data[2] |= CAN_ERR_PROT_STUFF;
-		if (es.error_factor & M16C_EF_BITE0)
-			cf->data[2] |= CAN_ERR_PROT_BIT0;
-		if (es.error_factor & M16C_EF_BITE1)
-			cf->data[2] |= CAN_ERR_PROT_BIT1;
-		if (es.error_factor & M16C_EF_TRE)
-			cf->data[2] |= CAN_ERR_PROT_TX;
+	switch (dev->family) {
+	case KVASER_LEAF:
+		if (es->leaf.error_factor) {
+			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_BUSERROR) {
+			cf->can_id |= CAN_ERR_BUSERROR;
+		}
+		break;
 	}
 
-	cf->data[6] = es.txerr;
-	cf->data[7] = es.rxerr;
+	cf->data[6] = es->txerr;
+	cf->data[7] = es->rxerr;
 
 	stats->rx_packets++;
 	stats->rx_bytes += cf->can_dlc;
 	netif_rx(skb);
 }
 
+/* For USBCAN, report error to userspace iff the channels's errors counter
+ * has changed, 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_usb_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_usb_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 supports up to 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_usb_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)
 {
@@ -790,16 +1089,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++;
 
@@ -825,7 +1124,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 = NULL;	/* GCC */
 
 	if (channel >= dev->nchannels) {
 		dev_err(dev->udev->dev.parent,
@@ -836,60 +1136,68 @@ 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;
+	}
+
 	skb = alloc_can_skb(priv->netdev, &cf);
 	if (!skb) {
 		stats->tx_dropped++;
 		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);
 	}
 
@@ -952,21 +1260,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;
 	}
@@ -1186,7 +1508,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)
@@ -1294,6 +1616,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;
+	u8 *msg_tx_can_flags = NULL;		/* GCC */
 
 	if (can_dropped_invalid_skb(netdev, skb))
 		return NETDEV_TX_OK;
@@ -1315,9 +1638,19 @@ 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;
+	}
+
+	*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;
@@ -1335,7 +1668,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) {
@@ -1604,6 +1937,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)");
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 98+ messages in thread

* Re: [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support
  2015-01-26  5:17 ` [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support Ahmed S. Darwish
  2015-01-26  5:20   ` [PATCH v6 1/7] can: kvaser_usb: Do not sleep in atomic context Ahmed S. Darwish
@ 2015-01-26  9:55   ` Marc Kleine-Budde
  2015-01-26 10:07   ` Marc Kleine-Budde
  2 siblings, 0 replies; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-26  9:55 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp,
	Wolfgang Grandegger, Andri Yngvason
  Cc: Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 1060 bytes --]

On 01/26/2015 06:17 AM, Ahmed S. Darwish wrote:
> Hi!
> 
> 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.

Applied 1-4 to can/master, I'm adding stable on Cc before sending a
pull-request to David.

Thanks,
Marc

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support
  2015-01-26  5:17 ` [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support Ahmed S. Darwish
  2015-01-26  5:20   ` [PATCH v6 1/7] can: kvaser_usb: Do not sleep in atomic context Ahmed S. Darwish
  2015-01-26  9:55   ` [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support Marc Kleine-Budde
@ 2015-01-26 10:07   ` Marc Kleine-Budde
  2015-01-26 10:56     ` Marc Kleine-Budde
  2 siblings, 1 reply; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-26 10:07 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp,
	Wolfgang Grandegger, Andri Yngvason
  Cc: Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 1645 bytes --]

On 01/26/2015 06:17 AM, Ahmed S. Darwish wrote:
> Hi!
> 
> 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.

For patches 5-7 I'm waiting for an Acked by Andri.

...and we have to wait until Patches 1-4 will show up on net-next/master.

Marc
-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-25  2:43                     ` Ahmed S. Darwish
@ 2015-01-26 10:21                       ` Andri Yngvason
  0 siblings, 0 replies; 98+ messages in thread
From: Andri Yngvason @ 2015-01-26 10:21 UTC (permalink / raw)
  To: Ahmed S. Darwish
  Cc: Wolfgang Grandegger, Olivier Sobrie, Oliver Hartkopp,
	Marc Kleine-Budde, Linux-CAN, netdev, LKML

Quoting Ahmed S. Darwish (2015-01-25 02:43:00)
> On Fri, Jan 23, 2015 at 10:32:13AM +0000, Andri Yngvason wrote:
> > Quoting Ahmed S. Darwish (2015-01-23 06:07:34)
> > > On Wed, Jan 21, 2015 at 05:13:45PM +0100, Wolfgang Grandegger wrote:
> > > > On Wed, 21 Jan 2015 10:36:47 -0500, "Ahmed S. Darwish"
> > > > <darwish.07@gmail.com> wrote:
> > > > > On Wed, Jan 21, 2015 at 03:00:15PM +0000, Andri Yngvason wrote:
> > > > >> Quoting Ahmed S. Darwish (2015-01-21 14:43:23)
> > > > >> > Hi!
> > > > > 
> > > > > ...
> > > > > 
> > > > >> > <-- 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  
> > > > 
> > > > 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 :-(
> > >
> > 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.
> 
> [...]
> 
> > > 
> > > 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.
> > > 
> > > > > 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.
> > >
> > Honestly, I don't know.
> > >
> > > A possible solution can be setting up a kernel thread that queries
> > > for a CHIP_STATE_EVENT every 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();
> > }
> > 
> 
> 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;
> }
> 
> > 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

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v6 6/7] can: kvaser_usb: Consolidate and unify state change handling
  2015-01-26  5:29             ` [PATCH v6 6/7] can: kvaser_usb: Consolidate and unify state change handling Ahmed S. Darwish
  2015-01-26  5:33               ` [PATCH v6 7/7] can: kvaser_usb: Add support for the USBcan-II family Ahmed S. Darwish
@ 2015-01-26 10:26               ` Andri Yngvason
  1 sibling, 0 replies; 98+ messages in thread
From: Andri Yngvason @ 2015-01-26 10:26 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp,
	Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Linux-CAN, netdev, LKML

Quoting Ahmed S. Darwish (2015-01-26 05:29:15)
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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 <andri.yngvason@marel.com>
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> ---
>  drivers/net/can/usb/kvaser_usb.c |  113 ++++++++++++++++---------------------
>  1 files changed, 49 insertions(+), 64 deletions(-)
> 
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index f57ce55..ddc2954 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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) {
> -- 
> 1.7.7.6

ACK, for real this time. ;)

--
Andri

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM
  2015-01-26  5:27           ` [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM Ahmed S. Darwish
  2015-01-26  5:29             ` [PATCH v6 6/7] can: kvaser_usb: Consolidate and unify state change handling Ahmed S. Darwish
@ 2015-01-26 10:28             ` Andri Yngvason
  2015-01-26 10:50               ` Marc Kleine-Budde
  1 sibling, 1 reply; 98+ messages in thread
From: Andri Yngvason @ 2015-01-26 10:28 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp,
	Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Linux-CAN, netdev, LKML

Quoting Ahmed S. Darwish (2015-01-26 05:27:19)
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> Update all of the can interface's state and error counters before
> trying any skb allocation that can actually fail with -ENOMEM.
> 
> Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> ---
>  drivers/net/can/usb/kvaser_usb.c |  181 ++++++++++++++++++++++----------------
>  1 files changed, 105 insertions(+), 76 deletions(-)
> 
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index 7af379c..f57ce55 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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);
> -- 
> 1.7.7.6

Looks good to me.

--
Andri

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v6 7/7] can: kvaser_usb: Add support for the USBcan-II family
  2015-01-26  5:33               ` [PATCH v6 7/7] can: kvaser_usb: Add support for the USBcan-II family Ahmed S. Darwish
@ 2015-01-26 10:34                 ` Andri Yngvason
  0 siblings, 0 replies; 98+ messages in thread
From: Andri Yngvason @ 2015-01-26 10:34 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp,
	Wolfgang Grandegger, Marc Kleine-Budde
  Cc: Linux-CAN, netdev, LKML

Quoting Ahmed S. Darwish (2015-01-26 05:33:10)
> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> 
> 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 <ahmed.darwish@valeo.com>
> ---
>  drivers/net/can/usb/Kconfig      |    8 +-
>  drivers/net/can/usb/kvaser_usb.c |  590 ++++++++++++++++++++++++++++++--------
>  2 files changed, 474 insertions(+), 124 deletions(-)
> 
> ** V6 Changelog:
> - Revert to the error-active state if the error counters were
>   decreased by hardware
> - Rebase over a new set of upstream Leaf-driver bugfixes
> 
> ** 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
> 
> diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
> index a77db919..f6f5500 100644
> --- a/drivers/net/can/usb/Kconfig
> +++ b/drivers/net/can/usb/Kconfig
> @@ -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.
>  
> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
> index ddc2954..17d28d7 100644
> --- a/drivers/net/can/usb/kvaser_usb.c
> +++ b/drivers/net/can/usb/kvaser_usb.c
> @@ -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 <matthias.fuchs@esd.eu>, esd gmbh
>   * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
> + * Copyright (C) 2015 Valeo A.S.
>   */
>  
>  #include <linux/completion.h>
> @@ -30,8 +32,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 */
> +/* Kvaser Leaf USB devices */
>  #define KVASER_VENDOR_ID               0x0bfd
>  #define USB_LEAF_DEVEL_PRODUCT_ID      10
>  #define USB_LEAF_LITE_PRODUCT_ID       11
> @@ -56,6 +59,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;
> +}
> +
> +/* Kvaser USBCan-II 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 +94,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 +119,11 @@
>  #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_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 +133,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 +147,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,9 +171,18 @@
>  #define KVASER_CTRL_MODE_SELFRECEPTION 3
>  #define KVASER_CTRL_MODE_OFF           4
>  
> -/* log message */
> +/* Extended CAN identifier flag */
>  #define KVASER_EXTENDED_FRAME          BIT(31)
>  
> +/* 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,
> +};
> +
>  struct kvaser_msg_simple {
>         u8 tid;
>         u8 channel;
> @@ -148,30 +191,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 +256,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 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;
> +} __packed;
> +
> +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 +347,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 +373,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,21 +390,55 @@ 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_usb_error_summary {
> -       u8 channel, status, txerr, rxerr, error_factor;
> +       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 {
> @@ -292,6 +456,7 @@ struct kvaser_usb {
>  
>         u32 fw_version;
>         unsigned int nchannels;
> +       enum kvaser_usb_family family;
>  
>         bool rxinitdone;
>         void *rxbuf[MAX_RX_URBS];
> @@ -315,6 +480,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),
> @@ -364,6 +530,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);
> @@ -467,7 +644,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;
>  }
> @@ -486,7 +670,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;
> @@ -500,8 +686,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,
> @@ -623,12 +811,12 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri
>                                                  const struct kvaser_usb_error_summary *es,
>                                                  struct can_frame *cf)
>  {
> -       struct net_device_stats *stats;
> +       struct kvaser_usb *dev = priv->dev;
> +       struct net_device_stats *stats = &priv->netdev->stats;
>         enum can_state cur_state, new_state, tx_state, rx_state;
>  
>         netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status);
>  
> -       stats = &priv->netdev->stats;
>         new_state = cur_state = priv->can.state;
>  
>         if (es->status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET))
> @@ -662,9 +850,22 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri
>                 priv->can.can_stats.restarts++;
>         }
>  
> -       if (es->error_factor) {
> -               priv->can.can_stats.bus_error++;
> -               stats->rx_errors++;
> +       switch (dev->family) {
> +       case KVASER_LEAF:
> +               if (es->leaf.error_factor) {
> +                       priv->can.can_stats.bus_error++;
> +                       stats->rx_errors++;
> +               }
> +               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++;
> +               }
> +               break;
>         }
>  
>         priv->bec.txerr = es->txerr;
> @@ -672,50 +873,21 @@ static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *pri
>  }
>  
>  static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
> -                               const struct kvaser_msg *msg)
> +                               const struct kvaser_usb_error_summary *es)
>  {
>         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, new_state;
>  
> -       switch (msg->id) {
> -       case CMD_CAN_ERROR_EVENT:
> -               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:
> -               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:
> -               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",
> -                       msg->id);
> -               return;
> -       }
> -
> -       if (es.channel >= dev->nchannels) {
> +       if (es->channel >= dev->nchannels) {
>                 dev_err(dev->udev->dev.parent,
> -                       "Invalid channel number (%d)\n", es.channel);
> +                       "Invalid channel number (%d)\n", es->channel);
>                 return;
>         }
>  
> -       priv = dev->nets[es.channel];
> +       priv = dev->nets[es->channel];
>         stats = &priv->netdev->stats;
>  
>         /* Update all of the can interface's state and error counters before
> @@ -729,7 +901,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
>          * frame ID and data to userspace. Remove stack allocation afterwards.
>          */
>         old_state = priv->can.state;
> -       kvaser_usb_rx_error_update_can_state(priv, &es, &tmp_cf);
> +       kvaser_usb_rx_error_update_can_state(priv, es, &tmp_cf);
>         new_state = priv->can.state;
>  
>         skb = alloc_can_err_skb(priv->netdev, &cf);
> @@ -740,7 +912,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
>         memcpy(cf, &tmp_cf, sizeof(*cf));
>  
>         if (new_state != old_state) {
> -               if (es.status &
> +               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);
> @@ -755,34 +927,161 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
>                 }
>         }
>  
> -       if (es.error_factor) {
> -               cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
> -
> -               if (es.error_factor & M16C_EF_ACKE)
> -                       cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
> -               if (es.error_factor & M16C_EF_CRCE)
> -                       cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
> -                                       CAN_ERR_PROT_LOC_CRC_DEL);
> -               if (es.error_factor & M16C_EF_FORME)
> -                       cf->data[2] |= CAN_ERR_PROT_FORM;
> -               if (es.error_factor & M16C_EF_STFE)
> -                       cf->data[2] |= CAN_ERR_PROT_STUFF;
> -               if (es.error_factor & M16C_EF_BITE0)
> -                       cf->data[2] |= CAN_ERR_PROT_BIT0;
> -               if (es.error_factor & M16C_EF_BITE1)
> -                       cf->data[2] |= CAN_ERR_PROT_BIT1;
> -               if (es.error_factor & M16C_EF_TRE)
> -                       cf->data[2] |= CAN_ERR_PROT_TX;
> +       switch (dev->family) {
> +       case KVASER_LEAF:
> +               if (es->leaf.error_factor) {
> +                       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_BUSERROR) {
> +                       cf->can_id |= CAN_ERR_BUSERROR;
> +               }
> +               break;
>         }
>  
> -       cf->data[6] = es.txerr;
> -       cf->data[7] = es.rxerr;
> +       cf->data[6] = es->txerr;
> +       cf->data[7] = es->rxerr;
>  
>         stats->rx_packets++;
>         stats->rx_bytes += cf->can_dlc;
>         netif_rx(skb);
>  }
>  
> +/* For USBCAN, report error to userspace iff the channels's errors counter
> + * has changed, 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_usb_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_usb_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 supports up to 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_usb_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)
>  {
> @@ -790,16 +1089,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++;
>  
> @@ -825,7 +1124,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 = NULL;        /* GCC */
>  
>         if (channel >= dev->nchannels) {
>                 dev_err(dev->udev->dev.parent,
> @@ -836,60 +1136,68 @@ 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;
> +       }
> +
>         skb = alloc_can_skb(priv->netdev, &cf);
>         if (!skb) {
>                 stats->tx_dropped++;
>                 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);
>         }
>  
> @@ -952,21 +1260,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;
>         }
> @@ -1186,7 +1508,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)
> @@ -1294,6 +1616,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;
> +       u8 *msg_tx_can_flags = NULL;            /* GCC */
>  
>         if (can_dropped_invalid_skb(netdev, skb))
>                 return NETDEV_TX_OK;
> @@ -1315,9 +1638,19 @@ 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;
> +       }
> +
> +       *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;
> @@ -1335,7 +1668,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) {
> @@ -1604,6 +1937,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)");
> -- 
> 1.7.7.6

There's a lot of changes here but as far as error state is concerned, I see
nothing out of the ordinary.

--
Andri

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM
  2015-01-26 10:28             ` [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM Andri Yngvason
@ 2015-01-26 10:50               ` Marc Kleine-Budde
  2015-01-26 10:52                 ` Andri Yngvason
  0 siblings, 1 reply; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-26 10:50 UTC (permalink / raw)
  To: Andri Yngvason, Ahmed S. Darwish, Olivier Sobrie,
	Oliver Hartkopp, Wolfgang Grandegger
  Cc: Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 910 bytes --]

On 01/26/2015 11:28 AM, Andri Yngvason wrote:
> Quoting Ahmed S. Darwish (2015-01-26 05:27:19)
>> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>>
>> Update all of the can interface's state and error counters before
>> trying any skb allocation that can actually fail with -ENOMEM.
>>
>> Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
>> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>> ---
>>  drivers/net/can/usb/kvaser_usb.c |  181 ++++++++++++++++++++++----------------
>>  1 files changed, 105 insertions(+), 76 deletions(-)
[..]

> Looks good to me.

Can I add your Acked-by to 5-7?

Marc
-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM
  2015-01-26 10:50               ` Marc Kleine-Budde
@ 2015-01-26 10:52                 ` Andri Yngvason
  2015-01-26 10:53                   ` Marc Kleine-Budde
  0 siblings, 1 reply; 98+ messages in thread
From: Andri Yngvason @ 2015-01-26 10:52 UTC (permalink / raw)
  To: Marc Kleine-Budde, Ahmed S. Darwish, Olivier Sobrie,
	Oliver Hartkopp, Wolfgang Grandegger
  Cc: Linux-CAN, netdev, LKML

Quoting Marc Kleine-Budde (2015-01-26 10:50:12)
> On 01/26/2015 11:28 AM, Andri Yngvason wrote:
> > Quoting Ahmed S. Darwish (2015-01-26 05:27:19)
> >> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> >>
> >> Update all of the can interface's state and error counters before
> >> trying any skb allocation that can actually fail with -ENOMEM.
> >>
> >> Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
> >> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
> >> ---
> >>  drivers/net/can/usb/kvaser_usb.c |  181 ++++++++++++++++++++++----------------
> >>  1 files changed, 105 insertions(+), 76 deletions(-)
> [..]
> 
> > Looks good to me.
> 
> Can I add your Acked-by to 5-7?
> 
Yes.

--
Andri

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM
  2015-01-26 10:52                 ` Andri Yngvason
@ 2015-01-26 10:53                   ` Marc Kleine-Budde
  0 siblings, 0 replies; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-26 10:53 UTC (permalink / raw)
  To: Andri Yngvason, Ahmed S. Darwish, Olivier Sobrie,
	Oliver Hartkopp, Wolfgang Grandegger
  Cc: Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 1067 bytes --]

On 01/26/2015 11:52 AM, Andri Yngvason wrote:
> Quoting Marc Kleine-Budde (2015-01-26 10:50:12)
>> On 01/26/2015 11:28 AM, Andri Yngvason wrote:
>>> Quoting Ahmed S. Darwish (2015-01-26 05:27:19)
>>>> From: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>>>>
>>>> Update all of the can interface's state and error counters before
>>>> trying any skb allocation that can actually fail with -ENOMEM.
>>>>
>>>> Suggested-by: Marc Kleine-Budde <mkl@pengutronix.de>
>>>> Signed-off-by: Ahmed S. Darwish <ahmed.darwish@valeo.com>
>>>> ---
>>>>  drivers/net/can/usb/kvaser_usb.c |  181 ++++++++++++++++++++++----------------
>>>>  1 files changed, 105 insertions(+), 76 deletions(-)
>> [..]
>>
>>> Looks good to me.
>>
>> Can I add your Acked-by to 5-7?
>>
> Yes.

Tnx.

Marc

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

* Re: [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support
  2015-01-26 10:07   ` Marc Kleine-Budde
@ 2015-01-26 10:56     ` Marc Kleine-Budde
  0 siblings, 0 replies; 98+ messages in thread
From: Marc Kleine-Budde @ 2015-01-26 10:56 UTC (permalink / raw)
  To: Ahmed S. Darwish, Olivier Sobrie, Oliver Hartkopp,
	Wolfgang Grandegger, Andri Yngvason
  Cc: Linux-CAN, netdev, LKML

[-- Attachment #1: Type: text/plain, Size: 1736 bytes --]

On 01/26/2015 11:07 AM, Marc Kleine-Budde wrote:
> On 01/26/2015 06:17 AM, Ahmed S. Darwish wrote:
>> Hi!
>>
>> 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.
> 
> For patches 5-7 I'm waiting for an Acked by Andri.

Applied to can-next, it's available as can-next-testing in the
linux-can-next repo.

Marc.

-- 
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   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 98+ messages in thread

end of thread, other threads:[~2015-01-26 10:56 UTC | newest]

Thread overview: 98+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-23 15:46 [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Ahmed S. Darwish
2014-12-23 15:53 ` [PATCH] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
2014-12-24 12:36   ` Olivier Sobrie
2014-12-24 15:04     ` Ahmed S. Darwish
2014-12-28 21:51       ` Olivier Sobrie
2014-12-30 15:33         ` Ahmed S. Darwish
2014-12-31 12:13           ` Olivier Sobrie
2014-12-24 12:31 ` [PATCH] can: kvaser_usb: Don't free packets when tight on URBs Olivier Sobrie
2014-12-24 15:52   ` Ahmed S. Darwish
2014-12-24 23:56 ` [PATCH v2 1/4] " Ahmed S. Darwish
2014-12-24 23:59   ` [PATCH v2 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
2014-12-25  0:02     ` [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Ahmed S. Darwish
2014-12-25  0:04       ` [PATCH v2 4/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
2014-12-28 21:54       ` [PATCH v2 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Olivier Sobrie
2014-12-25  2:50   ` [PATCH v2 1/4] can: kvaser_usb: Don't free packets when tight on URBs Greg KH
2014-12-25  9:38     ` Ahmed S. Darwish
2014-12-28 21:52   ` Olivier Sobrie
2015-01-01 21:59 ` [PATCH] " Stephen Hemminger
2015-01-03 14:34   ` Ahmed S. Darwish
2015-01-05 17:49 ` [PATCH v3 1/4] " Ahmed S. Darwish
2015-01-05 17:52   ` [PATCH v3 2/4] can: kvaser_usb: Reset all URB tx contexts upon channel close Ahmed S. Darwish
2015-01-05 17:57     ` [PATCH v3 3/4] can: kvaser_usb: Don't send a RESET_CHIP for non-existing channels Ahmed S. Darwish
2015-01-05 18:31       ` [PATCH v3 4/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
2015-01-08 11:53         ` Marc Kleine-Budde
2015-01-08 15:19           ` Ahmed S. Darwish
2015-01-12 11:51             ` Marc Kleine-Budde
2015-01-12 12:26               ` Ahmed S. Darwish
2015-01-12 12:34                 ` Marc Kleine-Budde
2015-01-09  3:06           ` Ahmed S. Darwish
2015-01-09 14:05             ` Marc Kleine-Budde
2015-01-09 16:23               ` Oliver Hartkopp
2015-01-08  9:59   ` [PATCH v3 1/4] can: kvaser_usb: Don't free packets when tight on URBs Marc Kleine-Budde
2015-01-11 20:05 ` [PATCH v4 00/04] can: Introduce support for Kvaser USBCAN-II devices Ahmed S. Darwish
2015-01-11 20:11   ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() devices Ahmed S. Darwish
2015-01-11 20:15     ` [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM Ahmed S. Darwish
2015-01-11 20:36       ` [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
2015-01-11 20:45         ` [PATCH v4 4/4] can: kvaser_usb: Retry first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
2015-01-11 20:51           ` Marc Kleine-Budde
2015-01-12 10:14             ` Ahmed S. Darwish
2015-01-12 10:25               ` Marc Kleine-Budde
2015-01-12 13:33               ` Olivier Sobrie
2015-01-12 13:50                 ` Ahmed S. Darwish
2015-01-12 11:20         ` [PATCH v4 3/4] can: kvaser_usb: Add support for the Usbcan-II family Ahmed S. Darwish
2015-01-12 11:43         ` Marc Kleine-Budde
2015-01-12 12:07           ` Ahmed S. Darwish
2015-01-12 12:36             ` Ahmed S. Darwish
2015-01-12 13:53         ` Olivier Sobrie
2015-01-18 20:12           ` Ahmed S. Darwish
2015-01-18 20:13             ` Marc Kleine-Budde
2015-01-12 11:09       ` [PATCH v4 2/4] can: kvaser_usb: Update error counters before exiting on OOM Marc Kleine-Budde
2015-01-12 20:36         ` Ahmed S. Darwish
2015-01-16 14:39           ` Marc Kleine-Budde
2015-01-16 15:50           ` Andri Yngvason
2015-01-18 20:33             ` Ahmed S. Darwish
2015-01-11 20:49     ` [PATCH v4 01/04] can: kvaser_usb: Don't dereference skb after a netif_rx() Ahmed S. Darwish
2015-01-12 11:05       ` Marc Kleine-Budde
2015-01-20 21:44 ` [PATCH v5 1/5] can: kvaser_usb: Update net interface state before exiting on OOM Ahmed S. Darwish
2015-01-20 21:45   ` [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling Ahmed S. Darwish
2015-01-20 21:47     ` [PATCH v5 3/5] can: kvaser_usb: Fix state handling upon BUS_ERROR events Ahmed S. Darwish
2015-01-20 21:48       ` [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
2015-01-20 21:50         ` [PATCH v5 5/5] can: kvaser_usb: Add support for the USBcan-II family Ahmed S. Darwish
2015-01-21 12:24         ` [PATCH v5 4/5] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT Sergei Shtylyov
2015-01-25 11:59           ` Ahmed S. Darwish
2015-01-21 10:33     ` [PATCH v5 2/5] can: kvaser_usb: Consolidate and unify state change handling Andri Yngvason
2015-01-21 10:44       ` Marc Kleine-Budde
2015-01-21 11:00         ` Andri Yngvason
2015-01-21 11:53       ` Wolfgang Grandegger
2015-01-21 14:43         ` Ahmed S. Darwish
2015-01-21 15:00           ` Andri Yngvason
2015-01-21 15:36             ` Ahmed S. Darwish
2015-01-21 16:13               ` Wolfgang Grandegger
2015-01-23  6:07                 ` Ahmed S. Darwish
2015-01-23 10:32                   ` Andri Yngvason
2015-01-25  2:43                     ` Ahmed S. Darwish
2015-01-26 10:21                       ` Andri Yngvason
2015-01-21 16:37               ` Andri Yngvason
2015-01-21 16:20     ` Andri Yngvason
2015-01-21 22:59       ` Marc Kleine-Budde
2015-01-22 10:14         ` Andri Yngvason
2015-01-25  2:49           ` Ahmed S. Darwish
2015-01-25  3:21       ` Ahmed S. Darwish
2015-01-26  5:17 ` [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support Ahmed S. Darwish
2015-01-26  5:20   ` [PATCH v6 1/7] can: kvaser_usb: Do not sleep in atomic context Ahmed S. Darwish
2015-01-26  5:22     ` [PATCH v6 2/7] can: kvaser_usb: Send correct context to URB completion Ahmed S. Darwish
2015-01-26  5:24       ` [PATCH v6 3/7] can: kvaser_usb: Retry the first bulk transfer on -ETIMEDOUT Ahmed S. Darwish
2015-01-26  5:25         ` [PATCH v6 4/7] can: kvaser_usb: Fix state handling upon BUS_ERROR events Ahmed S. Darwish
2015-01-26  5:27           ` [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM Ahmed S. Darwish
2015-01-26  5:29             ` [PATCH v6 6/7] can: kvaser_usb: Consolidate and unify state change handling Ahmed S. Darwish
2015-01-26  5:33               ` [PATCH v6 7/7] can: kvaser_usb: Add support for the USBcan-II family Ahmed S. Darwish
2015-01-26 10:34                 ` Andri Yngvason
2015-01-26 10:26               ` [PATCH v6 6/7] can: kvaser_usb: Consolidate and unify state change handling Andri Yngvason
2015-01-26 10:28             ` [PATCH v6 5/7] can: kvaser_usb: Update interface state before exiting on OOM Andri Yngvason
2015-01-26 10:50               ` Marc Kleine-Budde
2015-01-26 10:52                 ` Andri Yngvason
2015-01-26 10:53                   ` Marc Kleine-Budde
2015-01-26  9:55   ` [PATCH v6 0/7] can: kvaser_usb: Leaf bugfixes and USBCan-II support Marc Kleine-Budde
2015-01-26 10:07   ` Marc Kleine-Budde
2015-01-26 10:56     ` Marc Kleine-Budde

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.