diff options
Diffstat (limited to 'drivers/net/can/usb/kvaser_usb.c')
| -rw-r--r-- | drivers/net/can/usb/kvaser_usb.c | 723 | 
1 files changed, 541 insertions, 182 deletions
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 7af379ca861b..2928f7003041 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 S.A.   */  #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 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; +} __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,19 +390,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_usb_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 +456,7 @@ struct kvaser_usb {  	u32 fw_version;  	unsigned int nchannels; +	enum kvaser_usb_family family;  	bool rxinitdone;  	void *rxbuf[MAX_RX_URBS]; @@ -311,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), @@ -360,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); @@ -463,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;  } @@ -482,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; @@ -496,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, @@ -615,158 +807,280 @@ 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_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *priv, +						 const struct kvaser_usb_error_summary *es, +						 struct can_frame *cf)  { -	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; +	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; -	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]; +	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status); + +	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) +		new_state = CAN_STATE_ERROR_PASSIVE; +	else if (es->status & M16C_STATE_BUS_ERROR) { +		/* Guard against spurious error events after a busoff */ +		if (cur_state < CAN_STATE_BUS_OFF) { +			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; +		} +	} + +	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 && +	    (cur_state >= CAN_STATE_BUS_OFF) && +	    (new_state < CAN_STATE_BUS_OFF)) { +		priv->can.can_stats.restarts++; +	} + +	switch (dev->family) { +	case KVASER_LEAF: +		if (es->leaf.error_factor) { +			priv->can.can_stats.bus_error++; +			stats->rx_errors++; +		}  		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; +	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; -	default: -		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n", -			msg->id); -		return;  	} -	if (channel >= dev->nchannels) { +	priv->bec.txerr = es->txerr; +	priv->bec.rxerr = es->rxerr; +} + +static void kvaser_usb_rx_error(const struct kvaser_usb *dev, +				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; +	enum can_state old_state, new_state; + +	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 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, &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 (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); +		} -	new_state = priv->can.state; - -	netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status); +		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 (status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) { -		cf->can_id |= CAN_ERR_BUSOFF; +	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; +	} -		priv->can.can_stats.bus_off++; -		if (!priv->can.restart_ms) -			kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP); +	cf->data[6] = es->txerr; +	cf->data[7] = es->rxerr; -		netif_carrier_off(priv->netdev); +	stats->rx_packets++; +	stats->rx_bytes += cf->can_dlc; +	netif_rx(skb); +} -		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_CRTL; - -			if (txerr || rxerr) -				cf->data[1] = (txerr > 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++; -		} +/* 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; -		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))) { -			cf->can_id |= CAN_ERR_CRTL; -			cf->data[1] = (txerr > 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))) { -			cf->can_id |= CAN_ERR_PROT; -			cf->data[2] = CAN_ERR_PROT_ACTIVE; - -			new_state = CAN_STATE_ERROR_ACTIVE; -		} +	channel = es->channel; +	if (channel >= dev->nchannels) { +		dev_err(dev->udev->dev.parent, +			"Invalid channel number (%d)\n", channel); +		return;  	} -	if (!status) { -		cf->can_id |= CAN_ERR_PROT; -		cf->data[2] = CAN_ERR_PROT_ACTIVE; +	priv = dev->nets[channel]; +	report_error = false; -		new_state = CAN_STATE_ERROR_ACTIVE; +	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 (priv->can.restart_ms && -	    (priv->can.state >= CAN_STATE_BUS_OFF) && -	    (new_state < CAN_STATE_BUS_OFF)) { -		cf->can_id |= CAN_ERR_RESTARTED; -		netif_carrier_on(priv->netdev); +	if (report_error) +		kvaser_usb_rx_error(dev, es); +} -		priv->can.can_stats.restarts++; -	} +static void kvaser_usbcan_rx_error(const struct kvaser_usb *dev, +				   const struct kvaser_msg *msg) +{ +	struct kvaser_usb_error_summary es = { }; -	if (error_factor) { -		priv->can.can_stats.bus_error++; -		stats->rx_errors++; +	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; -		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; -	} +	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; -	cf->data[6] = txerr; -	cf->data[7] = rxerr; +	default: +		dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n", +			msg->id); +	} +} -	priv->bec.txerr = txerr; -	priv->bec.rxerr = rxerr; +static void kvaser_leaf_rx_error(const struct kvaser_usb *dev, +				 const struct kvaser_msg *msg) +{ +	struct kvaser_usb_error_summary es = { }; -	priv->can.state = new_state; +	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; +	} -	stats->rx_packets++; -	stats->rx_bytes += cf->can_dlc; -	netif_rx(skb); +	kvaser_usb_rx_error(dev, &es);  }  static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv, @@ -776,16 +1090,19 @@ 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++; +  		skb = alloc_can_err_skb(priv->netdev, &cf);  		if (!skb) {  			stats->rx_dropped++; @@ -795,9 +1112,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); @@ -811,7 +1125,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, @@ -822,60 +1137,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);  	} @@ -938,21 +1261,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;  	} @@ -1172,7 +1509,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) @@ -1280,6 +1617,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; @@ -1301,9 +1639,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; @@ -1321,7 +1669,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) { @@ -1590,6 +1938,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)");  | 

