Takashi Iwai a9d34d
From b24cb2d169e0c9dce664a959e1f2aa9781285dc9 Mon Sep 17 00:00:00 2001
Takashi Iwai a9d34d
From: Jimmy Assarsson <extja@kvaser.com>
Takashi Iwai a9d34d
Date: Mon, 10 Oct 2022 20:52:30 +0200
Takashi Iwai a9d34d
Subject: [PATCH] can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT
Takashi Iwai a9d34d
Git-commit: b24cb2d169e0c9dce664a959e1f2aa9781285dc9
Takashi Iwai a9d34d
Patch-mainline: v6.2-rc1
Takashi Iwai a9d34d
References: git-fixes
Takashi Iwai a9d34d
Takashi Iwai a9d34d
The device will send an error event command, to indicate certain errors.
Takashi Iwai a9d34d
This indicates a misbehaving driver, and should never occur.
Takashi Iwai a9d34d
Takashi Iwai a9d34d
Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
Takashi Iwai a9d34d
Tested-by: Anssi Hannula <anssi.hannula@bitwise.fi>
Takashi Iwai a9d34d
Co-developed-by: Anssi Hannula <anssi.hannula@bitwise.fi>
Takashi Iwai a9d34d
Signed-off-by: Anssi Hannula <anssi.hannula@bitwise.fi>
Takashi Iwai a9d34d
Signed-off-by: Jimmy Assarsson <extja@kvaser.com>
Takashi Iwai a9d34d
Link: https://lore.kernel.org/all/20221010185237.319219-5-extja@kvaser.com
Takashi Iwai a9d34d
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Takashi Iwai a9d34d
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai a9d34d
Takashi Iwai a9d34d
---
Takashi Iwai a9d34d
 .../net/can/usb/kvaser_usb/kvaser_usb_leaf.c  | 99 +++++++++++++++++++
Takashi Iwai a9d34d
 1 file changed, 99 insertions(+)
Takashi Iwai a9d34d
Takashi Iwai a9d34d
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
Takashi Iwai a9d34d
index f34ca9a850aa..e391ec247f54 100644
Takashi Iwai a9d34d
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
Takashi Iwai a9d34d
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
Takashi Iwai a9d34d
@@ -70,6 +70,7 @@
Takashi Iwai a9d34d
 #define CMD_GET_CARD_INFO_REPLY		35
Takashi Iwai a9d34d
 #define CMD_GET_SOFTWARE_INFO		38
Takashi Iwai a9d34d
 #define CMD_GET_SOFTWARE_INFO_REPLY	39
Takashi Iwai a9d34d
+#define CMD_ERROR_EVENT			45
Takashi Iwai a9d34d
 #define CMD_FLUSH_QUEUE			48
Takashi Iwai a9d34d
 #define CMD_TX_ACKNOWLEDGE		50
Takashi Iwai a9d34d
 #define CMD_CAN_ERROR_EVENT		51
Takashi Iwai a9d34d
@@ -258,6 +259,28 @@ struct usbcan_cmd_can_error_event {
Takashi Iwai a9d34d
 	__le16 time;
Takashi Iwai a9d34d
 } __packed;
Takashi Iwai a9d34d
 
Takashi Iwai a9d34d
+/* CMD_ERROR_EVENT error codes */
Takashi Iwai a9d34d
+#define KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL 0x8
Takashi Iwai a9d34d
+#define KVASER_USB_LEAF_ERROR_EVENT_PARAM 0x9
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
+struct leaf_cmd_error_event {
Takashi Iwai a9d34d
+	u8 tid;
Takashi Iwai a9d34d
+	u8 error_code;
Takashi Iwai a9d34d
+	__le16 timestamp[3];
Takashi Iwai a9d34d
+	__le16 padding;
Takashi Iwai a9d34d
+	__le16 info1;
Takashi Iwai a9d34d
+	__le16 info2;
Takashi Iwai a9d34d
+} __packed;
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
+struct usbcan_cmd_error_event {
Takashi Iwai a9d34d
+	u8 tid;
Takashi Iwai a9d34d
+	u8 error_code;
Takashi Iwai a9d34d
+	__le16 info1;
Takashi Iwai a9d34d
+	__le16 info2;
Takashi Iwai a9d34d
+	__le16 timestamp;
Takashi Iwai a9d34d
+	__le16 padding;
Takashi Iwai a9d34d
+} __packed;
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
 struct kvaser_cmd_ctrl_mode {
Takashi Iwai a9d34d
 	u8 tid;
Takashi Iwai a9d34d
 	u8 channel;
Takashi Iwai a9d34d
@@ -321,6 +344,7 @@ struct kvaser_cmd {
Takashi Iwai a9d34d
 			struct leaf_cmd_chip_state_event chip_state_event;
Takashi Iwai a9d34d
 			struct leaf_cmd_can_error_event can_error_event;
Takashi Iwai a9d34d
 			struct leaf_cmd_log_message log_message;
Takashi Iwai a9d34d
+			struct leaf_cmd_error_event error_event;
Takashi Iwai a9d34d
 			struct kvaser_cmd_cap_req cap_req;
Takashi Iwai a9d34d
 			struct kvaser_cmd_cap_res cap_res;
Takashi Iwai a9d34d
 		} __packed leaf;
Takashi Iwai a9d34d
@@ -330,6 +354,7 @@ struct kvaser_cmd {
Takashi Iwai a9d34d
 			struct usbcan_cmd_rx_can rx_can;
Takashi Iwai a9d34d
 			struct usbcan_cmd_chip_state_event chip_state_event;
Takashi Iwai a9d34d
 			struct usbcan_cmd_can_error_event can_error_event;
Takashi Iwai a9d34d
+			struct usbcan_cmd_error_event error_event;
Takashi Iwai a9d34d
 		} __packed usbcan;
Takashi Iwai a9d34d
 
Takashi Iwai a9d34d
 		struct kvaser_cmd_tx_can tx_can;
Takashi Iwai a9d34d
@@ -353,6 +378,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
Takashi Iwai a9d34d
 	[CMD_CHIP_STATE_EVENT]		= kvaser_fsize(u.leaf.chip_state_event),
Takashi Iwai a9d34d
 	[CMD_CAN_ERROR_EVENT]		= kvaser_fsize(u.leaf.can_error_event),
Takashi Iwai a9d34d
 	[CMD_GET_CAPABILITIES_RESP]	= kvaser_fsize(u.leaf.cap_res),
Takashi Iwai a9d34d
+	[CMD_ERROR_EVENT]		= kvaser_fsize(u.leaf.error_event),
Takashi Iwai a9d34d
 	/* ignored events: */
Takashi Iwai a9d34d
 	[CMD_FLUSH_QUEUE_REPLY]		= CMD_SIZE_ANY,
Takashi Iwai a9d34d
 };
Takashi Iwai a9d34d
@@ -367,6 +393,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
Takashi Iwai a9d34d
 	[CMD_RX_EXT_MESSAGE]		= kvaser_fsize(u.usbcan.rx_can),
Takashi Iwai a9d34d
 	[CMD_CHIP_STATE_EVENT]		= kvaser_fsize(u.usbcan.chip_state_event),
Takashi Iwai a9d34d
 	[CMD_CAN_ERROR_EVENT]		= kvaser_fsize(u.usbcan.can_error_event),
Takashi Iwai a9d34d
+	[CMD_ERROR_EVENT]		= kvaser_fsize(u.usbcan.error_event),
Takashi Iwai a9d34d
 	/* ignored events: */
Takashi Iwai a9d34d
 	[CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY,
Takashi Iwai a9d34d
 };
Takashi Iwai a9d34d
@@ -1304,6 +1331,74 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
Takashi Iwai a9d34d
 	netif_rx(skb);
Takashi Iwai a9d34d
 }
Takashi Iwai a9d34d
 
Takashi Iwai a9d34d
+static void kvaser_usb_leaf_error_event_parameter(const struct kvaser_usb *dev,
Takashi Iwai a9d34d
+						  const struct kvaser_cmd *cmd)
Takashi Iwai a9d34d
+{
Takashi Iwai a9d34d
+	u16 info1 = 0;
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
+	switch (dev->driver_info->family) {
Takashi Iwai a9d34d
+	case KVASER_LEAF:
Takashi Iwai a9d34d
+		info1 = le16_to_cpu(cmd->u.leaf.error_event.info1);
Takashi Iwai a9d34d
+		break;
Takashi Iwai a9d34d
+	case KVASER_USBCAN:
Takashi Iwai a9d34d
+		info1 = le16_to_cpu(cmd->u.usbcan.error_event.info1);
Takashi Iwai a9d34d
+		break;
Takashi Iwai a9d34d
+	}
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
+	/* info1 will contain the offending cmd_no */
Takashi Iwai a9d34d
+	switch (info1) {
Takashi Iwai a9d34d
+	case CMD_SET_CTRL_MODE:
Takashi Iwai a9d34d
+		dev_warn(&dev->intf->dev,
Takashi Iwai a9d34d
+			 "CMD_SET_CTRL_MODE error in parameter\n");
Takashi Iwai a9d34d
+		break;
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
+	case CMD_SET_BUS_PARAMS:
Takashi Iwai a9d34d
+		dev_warn(&dev->intf->dev,
Takashi Iwai a9d34d
+			 "CMD_SET_BUS_PARAMS error in parameter\n");
Takashi Iwai a9d34d
+		break;
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
+	default:
Takashi Iwai a9d34d
+		dev_warn(&dev->intf->dev,
Takashi Iwai a9d34d
+			 "Unhandled parameter error event cmd_no (%u)\n",
Takashi Iwai a9d34d
+			 info1);
Takashi Iwai a9d34d
+		break;
Takashi Iwai a9d34d
+	}
Takashi Iwai a9d34d
+}
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
+static void kvaser_usb_leaf_error_event(const struct kvaser_usb *dev,
Takashi Iwai a9d34d
+					const struct kvaser_cmd *cmd)
Takashi Iwai a9d34d
+{
Takashi Iwai a9d34d
+	u8 error_code = 0;
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
+	switch (dev->driver_info->family) {
Takashi Iwai a9d34d
+	case KVASER_LEAF:
Takashi Iwai a9d34d
+		error_code = cmd->u.leaf.error_event.error_code;
Takashi Iwai a9d34d
+		break;
Takashi Iwai a9d34d
+	case KVASER_USBCAN:
Takashi Iwai a9d34d
+		error_code = cmd->u.usbcan.error_event.error_code;
Takashi Iwai a9d34d
+		break;
Takashi Iwai a9d34d
+	}
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
+	switch (error_code) {
Takashi Iwai a9d34d
+	case KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL:
Takashi Iwai a9d34d
+		/* Received additional CAN message, when firmware TX queue is
Takashi Iwai a9d34d
+		 * already full. Something is wrong with the driver.
Takashi Iwai a9d34d
+		 * This should never happen!
Takashi Iwai a9d34d
+		 */
Takashi Iwai a9d34d
+		dev_err(&dev->intf->dev,
Takashi Iwai a9d34d
+			"Received error event TX_QUEUE_FULL\n");
Takashi Iwai a9d34d
+		break;
Takashi Iwai a9d34d
+	case KVASER_USB_LEAF_ERROR_EVENT_PARAM:
Takashi Iwai a9d34d
+		kvaser_usb_leaf_error_event_parameter(dev, cmd);
Takashi Iwai a9d34d
+		break;
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
+	default:
Takashi Iwai a9d34d
+		dev_warn(&dev->intf->dev,
Takashi Iwai a9d34d
+			 "Unhandled error event (%d)\n", error_code);
Takashi Iwai a9d34d
+		break;
Takashi Iwai a9d34d
+	}
Takashi Iwai a9d34d
+}
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
 static void kvaser_usb_leaf_start_chip_reply(const struct kvaser_usb *dev,
Takashi Iwai a9d34d
 					     const struct kvaser_cmd *cmd)
Takashi Iwai a9d34d
 {
Takashi Iwai a9d34d
@@ -1382,6 +1477,10 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
Takashi Iwai a9d34d
 		kvaser_usb_leaf_tx_acknowledge(dev, cmd);
Takashi Iwai a9d34d
 		break;
Takashi Iwai a9d34d
 
Takashi Iwai a9d34d
+	case CMD_ERROR_EVENT:
Takashi Iwai a9d34d
+		kvaser_usb_leaf_error_event(dev, cmd);
Takashi Iwai a9d34d
+		break;
Takashi Iwai a9d34d
+
Takashi Iwai a9d34d
 	/* Ignored commands */
Takashi Iwai a9d34d
 	case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
Takashi Iwai a9d34d
 		if (dev->driver_info->family != KVASER_USBCAN)
Takashi Iwai a9d34d
-- 
Takashi Iwai a9d34d
2.35.3
Takashi Iwai a9d34d