Re: [PATCH 09/12] can: kvaser_usb_leaf: Fix silently failing bus params setup

From: Jimmy Assarsson
Date: Sat May 28 2022 - 03:37:50 EST


On 5/16/22 15:47, Anssi Hannula wrote:
The device may reject bus params with cmd 45, which is an unhandled
error event that does not contain any channel reference.

In such cases set_bittiming() callback returns 0 so upper levels will
think setting bitrate succeeded and proceed with starting the interface
with wrong parameters, causing bus errors (the kernel log will have
"Unhandled command (45)", though).

Fix that by verifying the bus params took hold by reading them back.

Also, add a handler for cmd 45 that simply prints out the error.

This condition can be triggered on 0bfd:0124 Kvaser Mini PCI Express
2xHS FW 4.18.778 by trying to set bitrate 1300000 and on 0bfd:0124
Kvaser Mini PCI Express 2xHS FW 4.18.778 by trying to set bitrate
1000000.

The device will send cmd CMD_ERROR_EVENT (45) when invalid data is
received from the driver and should never occur. CMD_ERROR_EVENT
indicates a misbehaving driver.

For the Kvaser Mini PCI Express 2xHS case, the problem is settings
resulting in prescaler equal to 1 are not accepted. This is a bug in the
firmware and will be fixed in our next release.

And for Kvaser Memorator Professional HS/HS, the can_bittiming_const
limits are not correct.
I'll have to look into this a bit more. I'm pretty sure we endup with
three different can_bittiming_const in kvaser_usb_leaf, depedning on
firmware/microcontroller.

I created new patches for the CMD_ERROR_EVENT, based on your patch.
See at end of this mail.

I prefere if we can avoid the paramter readback and
kvaser_usb_setup_rx_urbs() in kvaser_usb_leaf_set_bittiming().
With correct can_bittiming_const limits this should not be an issue.
On the otherhand, since there are existing devices with a bug that will
reject parameters that are within the correct limits, and the result
silently failing calls, I cannot see any alternative...

If it ok with you I'll create a new patch based on your readback fix,
and also implement this in kvaser_usb_hydra?


Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
Signed-off-by: Anssi Hannula <anssi.hannula@xxxxxxxxxx>

---

Not sure about the best/correct naming for cmd 45. kvaser_usb_hydra
calls it CMD_ERROR_EVENT but kvaser_usb_leaf already has
CMD_CAN_ERROR_EVENT (kvaser_cmd.u.leaf.error_event) so I made it
ctrl_error_event to clearly differentiate it.


drivers/net/can/usb/kvaser_usb/kvaser_usb.h | 2 +
.../net/can/usb/kvaser_usb/kvaser_usb_core.c | 2 +-
.../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 108 ++++++++++++++++++
3 files changed, 111 insertions(+), 1 deletion(-)

diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
index 70aa7a9ed35b..b618ce299dbc 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
@@ -182,6 +182,8 @@ struct kvaser_usb_dev_cfg {
extern const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops;
extern const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops;
+int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev);
+
void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv);
int kvaser_usb_recv_cmd(const struct kvaser_usb *dev, void *cmd, int len,
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
index 6a1ebdd9ba85..ff0119c74b49 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
@@ -326,7 +326,7 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
}
}
-static int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev)
+int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev)
{
int i, err = 0;
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
index abb681808a28..7ed2ced8ba08 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -57,6 +57,8 @@
#define CMD_RX_EXT_MESSAGE 14
#define CMD_TX_EXT_MESSAGE 15
#define CMD_SET_BUS_PARAMS 16
+#define CMD_GET_BUS_PARAMS 17
+#define CMD_GET_BUS_PARAMS_REPLY 18
#define CMD_GET_CHIP_STATE 19
#define CMD_CHIP_STATE_EVENT 20
#define CMD_SET_CTRL_MODE 21
@@ -72,6 +74,7 @@
#define CMD_GET_CARD_INFO_REPLY 35
#define CMD_GET_SOFTWARE_INFO 38
#define CMD_GET_SOFTWARE_INFO_REPLY 39
+#define CMD_CTRL_ERROR_EVENT 45
#define CMD_FLUSH_QUEUE 48
#define CMD_TX_ACKNOWLEDGE 50
#define CMD_CAN_ERROR_EVENT 51
@@ -290,6 +293,15 @@ struct leaf_cmd_log_message {
u8 data[8];
} __packed;
+struct kvaser_cmd_ctrl_error_event {
+ u8 unknown[2];
+ __le16 timestamp[3];
+ u8 reserved;
+ u8 error_code;
+ __le16 info1;
+ __le16 info2;
+} __packed;
+
struct kvaser_cmd {
u8 len;
u8 id;
@@ -319,6 +331,7 @@ struct kvaser_cmd {
struct kvaser_cmd_tx_can tx_can;
struct kvaser_cmd_ctrl_mode ctrl_mode;
struct kvaser_cmd_flush_queue flush_queue;
+ struct kvaser_cmd_ctrl_error_event ctrl_error_event;
} u;
} __packed;
@@ -336,6 +349,8 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
[CMD_LEAF_LOG_MESSAGE] = kvaser_fsize(u.leaf.log_message),
[CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.leaf.chip_state_event),
[CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.leaf.error_event),
+ [CMD_GET_BUS_PARAMS_REPLY] = kvaser_fsize(u.busparams),
+ [CMD_CTRL_ERROR_EVENT] = kvaser_fsize(u.ctrl_error_event),
/* ignored events: */
[CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY,
};
@@ -350,6 +365,8 @@ static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
[CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.usbcan.rx_can),
[CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.usbcan.chip_state_event),
[CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.error_event),
+ [CMD_GET_BUS_PARAMS_REPLY] = kvaser_fsize(u.busparams),
+ [CMD_CTRL_ERROR_EVENT] = kvaser_fsize(u.ctrl_error_event),
/* ignored events: */
[CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY,
};
@@ -380,6 +397,9 @@ struct kvaser_usb_err_summary {
struct kvaser_usb_net_leaf_priv {
struct kvaser_usb_net_priv *net;
+ struct completion get_bus_params_comp;
+ struct kvaser_cmd_busparams params_response;
+
struct delayed_work chip_state_req_work;
};
@@ -1206,6 +1226,44 @@ static void kvaser_usb_leaf_stop_chip_reply(const struct kvaser_usb *dev,
complete(&priv->stop_comp);
}
+static void kvaser_usb_leaf_get_bus_params_reply(const struct kvaser_usb *dev,
+ const struct kvaser_cmd *cmd)
+{
+ struct kvaser_usb_net_leaf_priv *leaf;
+ u8 channel = cmd->u.busparams.channel;
+
+ if (channel >= dev->nchannels) {
+ dev_err(&dev->intf->dev,
+ "Invalid channel number (%d)\n", channel);
+ return;
+ }
+
+ leaf = dev->nets[channel]->sub_priv;
+ memcpy(&leaf->params_response, &cmd->u.busparams, sizeof(leaf->params_response));
+
+ complete(&leaf->get_bus_params_comp);
+}
+
+static void kvaser_usb_leaf_ctrl_error_event(const struct kvaser_usb *dev,
+ const struct kvaser_cmd *cmd)
+{
+ const char *desc = "";
+
+ if (cmd->u.ctrl_error_event.error_code == 0x00 &&
+ cmd->u.ctrl_error_event.info1 == CMD_SET_BUS_PARAMS)
+ desc = "bus params not accepted";
+
+ dev_err_ratelimited(&dev->intf->dev,
+ "received error (cmd 45)%s%s: %02x %02x, code 0x%02x, info1 %u info2 %u\n",
+ desc ? ", " : "",
+ desc,
+ cmd->u.ctrl_error_event.unknown[0],
+ cmd->u.ctrl_error_event.unknown[1],
+ cmd->u.ctrl_error_event.error_code,
+ le16_to_cpu(cmd->u.ctrl_error_event.info1),
+ le16_to_cpu(cmd->u.ctrl_error_event.info2));
+}
+
static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
const struct kvaser_cmd *cmd)
{
@@ -1244,6 +1302,14 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
kvaser_usb_leaf_tx_acknowledge(dev, cmd);
break;
+ case CMD_GET_BUS_PARAMS_REPLY:
+ kvaser_usb_leaf_get_bus_params_reply(dev, cmd);
+ break;
+
+ case CMD_CTRL_ERROR_EVENT:
+ kvaser_usb_leaf_ctrl_error_event(dev, cmd);
+ break;
+
/* Ignored commands */
case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
if (dev->card_data.leaf.family != KVASER_USBCAN)
@@ -1402,6 +1468,7 @@ static int kvaser_usb_leaf_init_channel(struct kvaser_usb_net_priv *priv)
return -ENOMEM;
leaf->net = priv;
+ init_completion(&leaf->get_bus_params_comp);
INIT_DELAYED_WORK(&leaf->chip_state_req_work,
kvaser_usb_leaf_chip_state_req_work);
@@ -1418,9 +1485,34 @@ static void kvaser_usb_leaf_remove_channel(struct kvaser_usb_net_priv *priv)
cancel_delayed_work_sync(&leaf->chip_state_req_work);
}
+static int kvaser_usb_leaf_get_bus_params(struct kvaser_usb_net_priv *priv)
+{
+ struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
+ int err;
+
+ /* we need RX urbs enabled to get the reply */
+ err = kvaser_usb_setup_rx_urbs(priv->dev);
+ if (err)
+ return err;
+
+ reinit_completion(&leaf->get_bus_params_comp);
+
+ err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_GET_BUS_PARAMS,
+ priv->channel);
+ if (err)
+ return err;
+
+ if (!wait_for_completion_timeout(&leaf->get_bus_params_comp,
+ msecs_to_jiffies(KVASER_USB_TIMEOUT)))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev)
{
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
struct can_bittiming *bt = &priv->can.bittiming;
struct kvaser_usb *dev = priv->dev;
struct kvaser_cmd *cmd;
@@ -1446,6 +1538,22 @@ static int kvaser_usb_leaf_set_bittiming(struct net_device *netdev)
rc = kvaser_usb_send_cmd(dev, cmd, cmd->len);
+ if (rc < 0)
+ goto out;
+
+ /* check that the parameters were accepted */
+
+ rc = kvaser_usb_leaf_get_bus_params(priv);
+ if (rc < 0)
+ goto out;
+
+ if (memcmp(&leaf->params_response, &cmd->u.busparams,
+ sizeof(leaf->params_response)) != 0) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+out:
kfree(cmd);
return rc;
}


From db14e82d4cf8c29f2f1b225c2d89418980787df8 Mon Sep 17 00:00:00 2001
From: Jimmy Assarsson <extja@xxxxxxxxxx>
Date: Wed, 25 May 2022 20:42:03 +0200
Subject: [PATCH 05/13] can: kvaser_usb: kvaser_usb_leaf: Rename
{leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event

Prepare for handling CMD_ERROR_EVENT. Rename struct
{leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event.

Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
Reported-by: Anssi Hannula <anssi.hannula@xxxxxxxxxx>
Signed-off-by: Jimmy Assarsson <extja@xxxxxxxxxx>
---
.../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 38 +++++++++----------
1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
index aee2dae67459..420343e512b4 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -244,7 +244,7 @@ struct kvaser_cmd_tx_acknowledge_header {
u8 tid;
} __packed;

-struct leaf_cmd_error_event {
+struct leaf_cmd_can_error_event {
u8 tid;
u8 flags;
__le16 time[3];
@@ -256,7 +256,7 @@ struct leaf_cmd_error_event {
u8 error_factor;
} __packed;

-struct usbcan_cmd_error_event {
+struct usbcan_cmd_can_error_event {
u8 tid;
u8 padding;
u8 tx_errors_count_ch0;
@@ -329,7 +329,7 @@ struct kvaser_cmd {
struct leaf_cmd_softinfo softinfo;
struct leaf_cmd_rx_can rx_can;
struct leaf_cmd_chip_state_event chip_state_event;
- struct leaf_cmd_error_event error_event;
+ struct leaf_cmd_can_error_event can_error_event;
struct leaf_cmd_log_message log_message;
struct kvaser_cmd_cap_req cap_req;
struct kvaser_cmd_cap_res cap_res;
@@ -339,7 +339,7 @@ struct kvaser_cmd {
struct usbcan_cmd_softinfo softinfo;
struct usbcan_cmd_rx_can rx_can;
struct usbcan_cmd_chip_state_event chip_state_event;
- struct usbcan_cmd_error_event error_event;
+ struct usbcan_cmd_can_error_event can_error_event;
} __packed usbcan;

struct kvaser_cmd_tx_can tx_can;
@@ -361,7 +361,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
[CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.leaf.rx_can),
[CMD_LEAF_LOG_MESSAGE] = kvaser_fsize(u.leaf.log_message),
[CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.leaf.chip_state_event),
- [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.leaf.error_event),
+ [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.leaf.can_error_event),
[CMD_GET_CAPABILITIES_RESP] = kvaser_fsize(u.leaf.cap_res),
/* ignored events: */
[CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY,
@@ -376,7 +376,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
[CMD_RX_STD_MESSAGE] = kvaser_fsize(u.usbcan.rx_can),
[CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.usbcan.rx_can),
[CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.usbcan.chip_state_event),
- [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.error_event),
+ [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.can_error_event),
/* ignored events: */
[CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY,
};
@@ -1114,11 +1114,11 @@ static void kvaser_usb_leaf_usbcan_rx_error(const struct kvaser_usb *dev,

case CMD_CAN_ERROR_EVENT:
es.channel = 0;
- es.status = cmd->u.usbcan.error_event.status_ch0;
- es.txerr = cmd->u.usbcan.error_event.tx_errors_count_ch0;
- es.rxerr = cmd->u.usbcan.error_event.rx_errors_count_ch0;
+ es.status = cmd->u.usbcan.can_error_event.status_ch0;
+ es.txerr = cmd->u.usbcan.can_error_event.tx_errors_count_ch0;
+ es.rxerr = cmd->u.usbcan.can_error_event.rx_errors_count_ch0;
es.usbcan.other_ch_status =
- cmd->u.usbcan.error_event.status_ch1;
+ cmd->u.usbcan.can_error_event.status_ch1;
kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es);

/* The USBCAN firmware supports up to 2 channels.
@@ -1126,13 +1126,13 @@ static void kvaser_usb_leaf_usbcan_rx_error(const struct kvaser_usb *dev,
*/
if (dev->nchannels == MAX_USBCAN_NET_DEVICES) {
es.channel = 1;
- es.status = cmd->u.usbcan.error_event.status_ch1;
+ es.status = cmd->u.usbcan.can_error_event.status_ch1;
es.txerr =
- cmd->u.usbcan.error_event.tx_errors_count_ch1;
+ cmd->u.usbcan.can_error_event.tx_errors_count_ch1;
es.rxerr =
- cmd->u.usbcan.error_event.rx_errors_count_ch1;
+ cmd->u.usbcan.can_error_event.rx_errors_count_ch1;
es.usbcan.other_ch_status =
- cmd->u.usbcan.error_event.status_ch0;
+ cmd->u.usbcan.can_error_event.status_ch0;
kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es);
}
break;
@@ -1149,11 +1149,11 @@ static void kvaser_usb_leaf_leaf_rx_error(const struct kvaser_usb *dev,

switch (cmd->id) {
case CMD_CAN_ERROR_EVENT:
- es.channel = cmd->u.leaf.error_event.channel;
- es.status = cmd->u.leaf.error_event.status;
- es.txerr = cmd->u.leaf.error_event.tx_errors_count;
- es.rxerr = cmd->u.leaf.error_event.rx_errors_count;
- es.leaf.error_factor = cmd->u.leaf.error_event.error_factor;
+ es.channel = cmd->u.leaf.can_error_event.channel;
+ es.status = cmd->u.leaf.can_error_event.status;
+ es.txerr = cmd->u.leaf.can_error_event.tx_errors_count;
+ es.rxerr = cmd->u.leaf.can_error_event.rx_errors_count;
+ es.leaf.error_factor = cmd->u.leaf.can_error_event.error_factor;
break;
case CMD_LEAF_LOG_MESSAGE:
es.channel = cmd->u.leaf.log_message.channel;
--
2.36.1





From 33720111c80f23021c1b37deab78e6a10672f81c Mon Sep 17 00:00:00 2001
From: Jimmy Assarsson <extja@xxxxxxxxxx>
Date: Wed, 25 May 2022 21:08:32 +0200
Subject: [PATCH 06/13] can: kvaser_usb: kvaser_usb_leaf: Handle
CMD_ERROR_EVENT

The device will send an error event command, to indicate certain errors.
This indicates a misbehaving driver, and should never occur.

Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
Co-developed-by: Anssi Hannula <anssi.hannula@xxxxxxxxxx>
Signed-off-by: Anssi Hannula <anssi.hannula@xxxxxxxxxx>
Signed-off-by: Jimmy Assarsson <extja@xxxxxxxxxx>
---
.../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 99 +++++++++++++++++++
1 file changed, 99 insertions(+)

diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
index 420343e512b4..5fd4a6133787 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -70,6 +70,7 @@
#define CMD_GET_CARD_INFO_REPLY 35
#define CMD_GET_SOFTWARE_INFO 38
#define CMD_GET_SOFTWARE_INFO_REPLY 39
+#define CMD_ERROR_EVENT 45
#define CMD_FLUSH_QUEUE 48
#define CMD_TX_ACKNOWLEDGE 50
#define CMD_CAN_ERROR_EVENT 51
@@ -268,6 +269,28 @@ struct usbcan_cmd_can_error_event {
__le16 time;
} __packed;

+/* CMD_ERROR_EVENT error codes */
+#define KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL 0x8
+#define KVASER_USB_LEAF_ERROR_EVENT_PARAM 0x9
+
+struct leaf_cmd_error_event {
+ u8 tid;
+ u8 error_code;
+ __le16 timestamp[3];
+ __le16 padding;
+ __le16 info1;
+ __le16 info2;
+} __packed;
+
+struct usbcan_cmd_error_event {
+ u8 tid;
+ u8 error_code;
+ __le16 info1;
+ __le16 info2;
+ __le16 timestamp;
+ __le16 padding;
+} __packed;
+
struct kvaser_cmd_ctrl_mode {
u8 tid;
u8 channel;
@@ -331,6 +354,7 @@ struct kvaser_cmd {
struct leaf_cmd_chip_state_event chip_state_event;
struct leaf_cmd_can_error_event can_error_event;
struct leaf_cmd_log_message log_message;
+ struct leaf_cmd_error_event error_event;
struct kvaser_cmd_cap_req cap_req;
struct kvaser_cmd_cap_res cap_res;
} __packed leaf;
@@ -340,6 +364,7 @@ struct kvaser_cmd {
struct usbcan_cmd_rx_can rx_can;
struct usbcan_cmd_chip_state_event chip_state_event;
struct usbcan_cmd_can_error_event can_error_event;
+ struct usbcan_cmd_error_event error_event;
} __packed usbcan;

struct kvaser_cmd_tx_can tx_can;
@@ -363,6 +388,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
[CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.leaf.chip_state_event),
[CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.leaf.can_error_event),
[CMD_GET_CAPABILITIES_RESP] = kvaser_fsize(u.leaf.cap_res),
+ [CMD_ERROR_EVENT] = kvaser_fsize(u.leaf.error_event),
/* ignored events: */
[CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY,
};
@@ -377,6 +403,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
[CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.usbcan.rx_can),
[CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.usbcan.chip_state_event),
[CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.can_error_event),
+ [CMD_ERROR_EVENT] = kvaser_fsize(u.usbcan.error_event),
/* ignored events: */
[CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY,
};
@@ -1286,6 +1313,74 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
netif_rx(skb);
}

+static void kvaser_usb_leaf_error_event_parameter(const struct kvaser_usb *dev,
+ const struct kvaser_cmd *cmd)
+{
+ u16 info1 = 0;
+
+ switch (dev->card_data.leaf.family) {
+ case KVASER_LEAF:
+ info1 = le16_to_cpu(cmd->u.leaf.error_event.info1);
+ break;
+ case KVASER_USBCAN:
+ info1 = le16_to_cpu(cmd->u.usbcan.error_event.info1);
+ break;
+ }
+
+ /* info1 will contain the offending cmd_no */
+ switch (info1) {
+ case CMD_SET_CTRL_MODE:
+ dev_warn(&dev->intf->dev,
+ "CMD_SET_CTRL_MODE error in parameter\n");
+ break;
+
+ case CMD_SET_BUS_PARAMS:
+ dev_warn(&dev->intf->dev,
+ "CMD_SET_BUS_PARAMS error in parameter\n");
+ break;
+
+ default:
+ dev_warn(&dev->intf->dev,
+ "Unhandled parameter error event cmd_no (%u)\n",
+ info1);
+ break;
+ }
+}
+
+static void kvaser_usb_leaf_error_event(const struct kvaser_usb *dev,
+ const struct kvaser_cmd *cmd)
+{
+ u8 error_code = 0;
+
+ switch (dev->card_data.leaf.family) {
+ case KVASER_LEAF:
+ error_code = cmd->u.leaf.error_event.error_code;
+ break;
+ case KVASER_USBCAN:
+ error_code = cmd->u.usbcan.error_event.error_code;
+ break;
+ }
+
+ switch (error_code) {
+ case KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL:
+ /* Received additional CAN message, when firmware TX queue is
+ * already full. Something is wrong with the driver.
+ * This should never happen!
+ */
+ dev_err(&dev->intf->dev,
+ "Received error event TX_QUEUE_FULL\n");
+ break;
+ case KVASER_USB_LEAF_ERROR_EVENT_PARAM:
+ kvaser_usb_leaf_error_event_parameter(dev, cmd);
+ break;
+
+ default:
+ dev_warn(&dev->intf->dev,
+ "Unhandled error event (%d)\n", error_code);
+ break;
+ }
+}
+
static void kvaser_usb_leaf_start_chip_reply(const struct kvaser_usb *dev,
const struct kvaser_cmd *cmd)
{
@@ -1364,6 +1459,10 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
kvaser_usb_leaf_tx_acknowledge(dev, cmd);
break;

+ case CMD_ERROR_EVENT:
+ kvaser_usb_leaf_error_event(dev, cmd);
+ break;
+
/* Ignored commands */
case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
if (dev->card_data.leaf.family != KVASER_USBCAN)
--
2.36.1