2022-05-16 19:03:39

by Anssi Hannula

[permalink] [raw]
Subject: [PATCH 00/12] can: kvaser_usb: Various fixes


Hi all,

Here's a set of fixes for issues I found while testing kvaser_usb as we
are preparing to start using it in production (with 0bfd:0124).

The biggest caveat is that I only have two devices to test with [1] and I
don't have HW documentation, so there is a possibility that some of the
fixes might not work properly on all HW variants.
Hopefully Jimmy can confirm they look OK, or suggest alternatives.

[1] Tested devices:
- 0bfd:0017 Kvaser Memorator Professional HS/HS FW 2.0.50
- 0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778

--
Anssi Hannula / Bitwise Oy
+358503803997





2022-05-16 19:53:58

by Anssi Hannula

[permalink] [raw]
Subject: [PATCH 05/12] can: kvaser_usb_leaf: Set Warning state even without bus errors

kvaser_usb_leaf_rx_error_update_can_state() sets error state according
to error counters when the hardware does not indicate a specific state
directly.

However, this is currently gated behind a check for
M16C_STATE_BUS_ERROR which does not always seem to be set when error
counters are increasing, and may not be set when error counters are
decreasing.

This causes the CAN_STATE_ERROR_WARNING state to not be set in some
cases even when appropriate.

Change the code to set error state from counters even without
M16C_STATE_BUS_ERROR.

The Error-Passive case seems superfluous as it is already set via
M16C_STATE_BUS_PASSIVE flag above, but it is kept for now.

Tested with 0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778.

Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
Signed-off-by: Anssi Hannula <[email protected]>
---
.../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 20 ++++++++-----------
1 file changed, 8 insertions(+), 12 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 09ade66256b2..d7f2d64a8083 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -775,20 +775,16 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
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) {
+ } else if ((es->status & M16C_STATE_BUS_ERROR) &&
+ cur_state >= CAN_STATE_BUS_OFF) {
/* 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)
+ } 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 {
new_state = CAN_STATE_ERROR_ACTIVE;
+ }

if (new_state != cur_state) {
tx_state = (es->txerr >= es->rxerr) ? new_state : 0;
--
2.34.1


2022-05-16 20:30:18

by Anssi Hannula

[permalink] [raw]
Subject: [PATCH 04/12] can: kvaser_usb: Mark Mini PCIe 2xHS as supporting error counters

The 0bfd:0124 Kvaser Mini PCI Express 2xHS (FW 4.18.778) seems to support
TX/RX error counters in exactly the same way (via unsolicited cmd 106 on
bus errors and via cmd 20 when queried with cmd 19) as 0bfd:0017 Kvaser
Memorator Professional HS/HS (FW 2.0.50), but only the latter has
KVASER_USB_HAS_TXRX_ERRORS set to enable do_get_berr_counter().

Enable error counter retrieval for Kvaser Mini PCI Express 2xHS, too.

Fixes: 71873a9b38d1 ("can: kvaser_usb: Add support for more Kvaser Leaf v2 devices")
Signed-off-by: Anssi Hannula <[email protected]>

---

I'm not really sure what KVASER_USB_HAS_TXRX_ERRORS means, exactly,
w.r.t. device behavior, though, i.e. how does a device without it behave.


drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

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 47bff40c36b6..7388fdca9079 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
@@ -165,7 +165,8 @@ static const struct usb_device_id kvaser_usb_table[] = {
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID) },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID),
+ .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID) },
--
2.34.1


2022-05-17 01:09:41

by Anssi Hannula

[permalink] [raw]
Subject: [PATCH 06/12] can: kvaser_usb_leaf: Fix TX queue out of sync after restart

The TX queue seems to be implicitly flushed by the hardware during
bus-off or bus-off recovery, but the driver does not reset the TX
bookkeeping.

Despite not resetting TX bookkeeping the driver still re-enables TX
queue unconditionally, leading to "cannot find free context" /
NETDEV_TX_BUSY errors if the TX queue was full at bus-off time.

Fix that by resetting TX bookkeeping on CAN restart.

Also, add an explicit queue flush in case some hardware versions do not
do that implicitly.

Tested with 0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778.

Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
Signed-off-by: Anssi Hannula <[email protected]>
---
drivers/net/can/usb/kvaser_usb/kvaser_usb.h | 2 ++
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 2 +-
drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 6 ++++++
3 files changed, 9 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 3a49257f9fa6..f1bea13a3829 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
@@ -175,6 +175,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;

+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,
int *actual_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 7388fdca9079..a8d72fb8291a 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
@@ -440,7 +440,7 @@ static void kvaser_usb_reset_tx_urb_contexts(struct kvaser_usb_net_priv *priv)
/* This method might sleep. Do not call it in the atomic context
* of URB completions.
*/
-static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
+void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
{
usb_kill_anchored_urbs(&priv->tx_submitted);
kvaser_usb_reset_tx_urb_contexts(priv);
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 d7f2d64a8083..2d30a662edb5 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -1402,6 +1402,12 @@ static int kvaser_usb_leaf_set_mode(struct net_device *netdev,

switch (mode) {
case CAN_MODE_START:
+ err = kvaser_usb_leaf_flush_queue(priv);
+ if (err)
+ return err;
+
+ kvaser_usb_unlink_tx_urbs(priv);
+
err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP);
if (err)
return err;
--
2.34.1


2022-05-17 02:04:32

by Anssi Hannula

[permalink] [raw]
Subject: [PATCH 11/12] can: kvaser_usb_leaf: Ignore stale bus-off after start

With 0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778 it was observed
that if the device was bus-off when stopped, at next start (either via
interface down/up or manual bus-off restart) the initial
CMD_CHIP_STATE_EVENT received just after CMD_START_CHIP_REPLY will have
the M16C_STATE_BUS_OFF bit still set, causing the interface to
immediately go bus-off again.

The bit seems to internally clear quickly afterwards but we do not get
another CMD_CHIP_STATE_EVENT.

Fix the issue by ignoring any initial bus-off state until we see at
least one bus-on state. Also, poll the state periodically until that
occurs.

It is possible we lose one actual immediately occurring bus-off event
here in which case the HW will auto-recover and we see the recovery
event. We will then catch the next bus-off event, if any.

This issue did not reproduce with 0bfd:0017 Kvaser Memorator
Professional HS/HS FW 2.0.50.

Fixes: 71873a9b38d1 ("can: kvaser_usb: Add support for more Kvaser Leaf v2 devices")
Signed-off-by: Anssi Hannula <[email protected]>
---
.../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 31 ++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)

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 742626e69dd8..4125074c7066 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -401,6 +401,9 @@ struct kvaser_usb_net_leaf_priv {
struct kvaser_cmd_busparams params_response;

struct delayed_work chip_state_req_work;
+
+ /* started but not reported as bus-on yet */
+ bool joining_bus;
};

static const struct can_bittiming_const kvaser_usb_leaf_bittiming_const = {
@@ -800,6 +803,7 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
const struct kvaser_usb_err_summary *es,
struct can_frame *cf)
{
+ struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
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;
@@ -824,6 +828,22 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
new_state = CAN_STATE_ERROR_ACTIVE;
}

+ /* 0bfd:0124 FW 4.18.778 was observed to send the initial
+ * CMD_CHIP_STATE_EVENT after CMD_START_CHIP with M16C_STATE_BUS_OFF
+ * bit set if the channel was bus-off when it was last stopped (even
+ * across chip resets). This bit will clear shortly afterwards, without
+ * triggering a second unsolicited chip state event.
+ * Ignore this initial bus-off.
+ */
+ if (leaf->joining_bus) {
+ if (new_state == CAN_STATE_BUS_OFF) {
+ netdev_dbg(priv->netdev, "ignoring bus-off during startup");
+ new_state = cur_state;
+ } else {
+ leaf->joining_bus = false;
+ }
+ }
+
if (new_state != cur_state) {
tx_state = (es->txerr >= es->rxerr) ? new_state : 0;
rx_state = (es->txerr <= es->rxerr) ? new_state : 0;
@@ -899,9 +919,12 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,

/* If there are errors, request status updates periodically as we do
* not get automatic notifications of improved state.
+ * Also request updates if we saw a stale BUS_OFF during startup
+ * (joining_bus).
*/
if (new_state < CAN_STATE_BUS_OFF &&
- (es->rxerr || es->txerr || new_state == CAN_STATE_ERROR_PASSIVE))
+ (es->rxerr || es->txerr || new_state == CAN_STATE_ERROR_PASSIVE ||
+ leaf->joining_bus))
schedule_delayed_work(&leaf->chip_state_req_work,
msecs_to_jiffies(500));

@@ -1392,8 +1415,11 @@ static int kvaser_usb_leaf_set_opt_mode(const struct kvaser_usb_net_priv *priv)

static int kvaser_usb_leaf_start_chip(struct kvaser_usb_net_priv *priv)
{
+ struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
int err;

+ leaf->joining_bus = true;
+
reinit_completion(&priv->start_comp);

err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_START_CHIP,
@@ -1566,6 +1592,7 @@ static int kvaser_usb_leaf_set_mode(struct net_device *netdev,
enum can_mode mode)
{
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
+ struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
int err;

switch (mode) {
@@ -1576,6 +1603,8 @@ static int kvaser_usb_leaf_set_mode(struct net_device *netdev,

kvaser_usb_unlink_tx_urbs(priv);

+ leaf->joining_bus = true;
+
err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP);
if (err)
return err;
--
2.34.1


2022-05-17 03:14:35

by Anssi Hannula

[permalink] [raw]
Subject: [PATCH 10/12] can: kvaser_usb_leaf: Fix wrong CAN state after stopping

0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778 sends a
CMD_CHIP_STATE_EVENT indicating bus-off after stopping the device,
causing a stopped device to appear as CAN_STATE_BUS_OFF instead of
CAN_STATE_STOPPED.

Fix that by not handling error events on stopped devices.

Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
Signed-off-by: Anssi Hannula <[email protected]>
---
drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 4 ++++
1 file changed, 4 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 7ed2ced8ba08..742626e69dd8 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -879,6 +879,10 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
leaf = priv->sub_priv;
stats = &priv->netdev->stats;

+ /* Ignore e.g. state change to bus-off reported just after stopping */
+ if (!netif_running(priv->netdev))
+ return;
+
/* Update all of the CAN interface's state and error counters before
* trying any memory allocation that can actually fail with -ENOMEM.
*
--
2.34.1


2022-05-17 03:16:08

by Anssi Hannula

[permalink] [raw]
Subject: [PATCH 07/12] can: kvaser_usb_leaf: Fix CAN state after restart

can_restart() expects CMD_START_CHIP to set the error state to
ERROR_ACTIVE as it calls netif_carrier_on() immediately afterwards.

Otherwise the user may immediately trigger restart again and hit a
BUG_ON() in can_restart().

Fix kvaser_usb_leaf set_mode(CMD_START_CHIP) to set the expected state.

Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
Signed-off-by: Anssi Hannula <[email protected]>
---
drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 2 ++
1 file changed, 2 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 2d30a662edb5..5f27c00179c1 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -1411,6 +1411,8 @@ static int kvaser_usb_leaf_set_mode(struct net_device *netdev,
err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP);
if (err)
return err;
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
break;
default:
return -EOPNOTSUPP;
--
2.34.1


2022-05-17 03:41:41

by Anssi Hannula

[permalink] [raw]
Subject: [PATCH 01/12] can: kvaser_usb_leaf: Fix overread with an invalid command

For command events read from the device,
kvaser_usb_leaf_read_bulk_callback() verifies that cmd->len does not
exceed the size of the received data, but the actual kvaser_cmd handlers
will happily read any kvaser_cmd fields without checking for cmd->len.

This can cause an overread if the last cmd in the buffer is shorter than
expected for the command type (with cmd->len showing the actual short
size).

Maximum overread seems to be 22 bytes (CMD_LEAF_LOG_MESSAGE), some of
which are delivered to userspace as-is.

Fix that by verifying the length of command before handling it.

This issue can only occur after RX URBs have been set up, i.e. the
interface has been opened at least once.

Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
Signed-off-by: Anssi Hannula <[email protected]>

---

A simpler option would be to just zero-pad the data into a
stack-allocated struct kvaser_cmd without knowledge of the needed
minimum size (so no tables needed), though that would mean incomplete
commands would get passed on silently.

.../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 75 +++++++++++++++++++
1 file changed, 75 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 c805b999c543..d9f40b9702a5 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -320,6 +320,38 @@ struct kvaser_cmd {
} u;
} __packed;

+#define CMD_SIZE_ANY 0xff
+#define kvaser_fsize(field) sizeof_field(struct kvaser_cmd, field)
+
+static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
+ [CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
+ [CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
+ [CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo),
+ [CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.tx_acknowledge_header),
+ [CMD_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.leaf.softinfo),
+ [CMD_RX_STD_MESSAGE] = kvaser_fsize(u.leaf.rx_can),
+ [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),
+ /* ignored events: */
+ [CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY,
+};
+
+static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
+ [CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
+ [CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
+ [CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo),
+ [CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.tx_acknowledge_header),
+ [CMD_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.usbcan.softinfo),
+ [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),
+ /* ignored events: */
+ [CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY,
+};
+
/* Summary of a kvaser error event, for a unified Leaf/Usbcan error
* handling. Some discrepancies between the two families exist:
*
@@ -387,6 +419,43 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_32mhz = {
.bittiming_const = &kvaser_usb_leaf_bittiming_const,
};

+static int kvaser_usb_leaf_verify_size(const struct kvaser_usb *dev,
+ const struct kvaser_cmd *cmd)
+{
+ /* buffer size >= cmd->len ensured by caller */
+ u8 min_size = 0;
+
+ switch (dev->card_data.leaf.family) {
+ case KVASER_LEAF:
+ if (cmd->id < ARRAY_SIZE(kvaser_usb_leaf_cmd_sizes_leaf))
+ min_size = kvaser_usb_leaf_cmd_sizes_leaf[cmd->id];
+ break;
+ case KVASER_USBCAN:
+ if (cmd->id < ARRAY_SIZE(kvaser_usb_leaf_cmd_sizes_usbcan))
+ min_size = kvaser_usb_leaf_cmd_sizes_usbcan[cmd->id];
+ break;
+ }
+
+ if (min_size == CMD_SIZE_ANY)
+ return 0;
+
+ if (min_size) {
+ min_size += CMD_HEADER_LEN;
+ if (cmd->len >= min_size)
+ return 0;
+
+ dev_err_ratelimited(&dev->intf->dev,
+ "Received command %u too short (size %u, needed %u)",
+ cmd->id, cmd->len, min_size);
+ return -EIO;
+ }
+
+ dev_warn_ratelimited(&dev->intf->dev,
+ "Unhandled command (%d, size %d)\n",
+ cmd->id, cmd->len);
+ return -EINVAL;
+}
+
static void *
kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
const struct sk_buff *skb, int *cmd_len,
@@ -492,6 +561,9 @@ static int kvaser_usb_leaf_wait_cmd(const struct kvaser_usb *dev, u8 id,
end:
kfree(buf);

+ if (err == 0)
+ err = kvaser_usb_leaf_verify_size(dev, cmd);
+
return err;
}

@@ -1113,6 +1185,9 @@ static void kvaser_usb_leaf_stop_chip_reply(const struct kvaser_usb *dev,
static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
const struct kvaser_cmd *cmd)
{
+ if (kvaser_usb_leaf_verify_size(dev, cmd) < 0)
+ return;
+
switch (cmd->id) {
case CMD_START_CHIP_REPLY:
kvaser_usb_leaf_start_chip_reply(dev, cmd);
--
2.34.1


2022-05-18 04:22:34

by Jimmy Assarsson

[permalink] [raw]
Subject: Re: [PATCH 00/12] can: kvaser_usb: Various fixes

On 2022-05-16 15:47, Anssi Hannula wrote:
>
> Hi all,
>
> Here's a set of fixes for issues I found while testing kvaser_usb as we
> are preparing to start using it in production (with 0bfd:0124).

Hi Anssi,

Thanks for the patches!
I will review and test your fixes before the weekend.

Best regards,
jimmy


> The biggest caveat is that I only have two devices to test with [1] and I
> don't have HW documentation, so there is a possibility that some of the
> fixes might not work properly on all HW variants.
> Hopefully Jimmy can confirm they look OK, or suggest alternatives.
>
> [1] Tested devices:
> - 0bfd:0017 Kvaser Memorator Professional HS/HS FW 2.0.50
> - 0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778

2022-05-28 18:58:03

by Jimmy Assarsson

[permalink] [raw]
Subject: Re: [PATCH 00/12] can: kvaser_usb: Various fixes

On 5/17/22 10:41, Jimmy Assarsson wrote:
> On 2022-05-16 15:47, Anssi Hannula wrote:
>>
>> Hi all,
>>
>> Here's a set of fixes for issues I found while testing kvaser_usb as we
>> are preparing to start using it in production (with 0bfd:0124).
>
> Hi Anssi,
>
> Thanks for the patches!
> I will review and test your fixes before the weekend.
>
> Best regards,
> jimmy

Sorry for the delay!

To summarize the status.

These patches look good:
[PATCH 01/12] can: kvaser_usb_leaf: Fix overread with an invalid command
[PATCH 02/12] can: kvaser_usb: Fix use of uninitialized completion
[PATCH 03/12] can: kvaser_usb: Fix possible completions during
init_completion
[PATCH 05/12] can: kvaser_usb_leaf: Set Warning state even without bus
errors
[PATCH 10/12] can: kvaser_usb_leaf: Fix wrong CAN state after stopping
[PATCH 12/12] can: kvaser_usb_leaf: Fix bogus restart events

This looks good, but see comment regarding explicit queue flush:
[PATCH 06/12] can: kvaser_usb_leaf: Fix TX queue out of sync after restart

I still need some more time looking into:
PATCH 07/12] can: kvaser_usb_leaf: Fix CAN state after restart
PATCH 08/12] can: kvaser_usb_leaf: Fix improved state not being reported
PATCH 11/12] can: kvaser_usb_leaf: Ignore stale bus-off after start

I want to replace
[PATCH 04/12] can: kvaser_usb: Mark Mini PCIe 2xHS as supporting error
counters
with a new patch
"can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device"

I want to split the handling of CMD_ERROR_EVENT and the readback
functionality. I also want to add parameter readback for
kvaser_usb_hydra. I need more time to look over the can_bittiming_const
in kvaser_usb_leaf for the different supported firmware.
[PATCH 09/12] can: kvaser_usb_leaf: Fix silently failing bus params setup


I would like to create a V2 series, including my patches, if you are
okay with it?


Best regards,
jimmy



>> The biggest caveat is that I only have two devices to test with [1] and I
>> don't have HW documentation, so there is a possibility that some of the
>> fixes might not work properly on all HW variants.
>> Hopefully Jimmy can confirm they look OK, or suggest alternatives.
>>
>> [1] Tested devices:
>> - 0bfd:0017 Kvaser Memorator Professional HS/HS FW 2.0.50
>> - 0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778

2022-05-28 19:20:09

by Jimmy Assarsson

[permalink] [raw]
Subject: Re: [PATCH 06/12] can: kvaser_usb_leaf: Fix TX queue out of sync after restart

On 5/16/22 15:47, Anssi Hannula wrote:
> The TX queue seems to be implicitly flushed by the hardware during
> bus-off or bus-off recovery, but the driver does not reset the TX
> bookkeeping.
>
> Despite not resetting TX bookkeeping the driver still re-enables TX
> queue unconditionally, leading to "cannot find free context" /
> NETDEV_TX_BUSY errors if the TX queue was full at bus-off time.
>
> Fix that by resetting TX bookkeeping on CAN restart.
>
> Also, add an explicit queue flush in case some hardware versions do not
> do that implicitly.

See comment below regarding this.

> Tested with 0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778.
>
> Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
> Signed-off-by: Anssi Hannula <[email protected]>
> ---
> drivers/net/can/usb/kvaser_usb/kvaser_usb.h | 2 ++
> drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 2 +-
> drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 6 ++++++
> 3 files changed, 9 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 3a49257f9fa6..f1bea13a3829 100644
> --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
> +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h
> @@ -175,6 +175,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;
>
> +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,
> int *actual_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 7388fdca9079..a8d72fb8291a 100644
> --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
> +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
> @@ -440,7 +440,7 @@ static void kvaser_usb_reset_tx_urb_contexts(struct kvaser_usb_net_priv *priv)
> /* This method might sleep. Do not call it in the atomic context
> * of URB completions.
> */
> -static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
> +void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
> {
> usb_kill_anchored_urbs(&priv->tx_submitted);
> kvaser_usb_reset_tx_urb_contexts(priv);
> 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 d7f2d64a8083..2d30a662edb5 100644
> --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> @@ -1402,6 +1402,12 @@ static int kvaser_usb_leaf_set_mode(struct net_device *netdev,
>
> switch (mode) {
> case CAN_MODE_START:
> + err = kvaser_usb_leaf_flush_queue(priv);

All affected devices, leaf and usbcanII, will flush the Tx queue when
receiving CMD_START_CHIP.
So this is superfluous, and can be removed.

> + if (err)
> + return err;
> +
> + kvaser_usb_unlink_tx_urbs(priv);
> +
> err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP);
> if (err)
> return err;

2022-05-28 19:21:16

by Jimmy Assarsson

[permalink] [raw]
Subject: Re: [PATCH 04/12] can: kvaser_usb: Mark Mini PCIe 2xHS as supporting error counters

On 5/16/22 15:47, Anssi Hannula wrote:
> The 0bfd:0124 Kvaser Mini PCI Express 2xHS (FW 4.18.778) seems to support
> TX/RX error counters in exactly the same way (via unsolicited cmd 106 on
> bus errors and via cmd 20 when queried with cmd 19) as 0bfd:0017 Kvaser
> Memorator Professional HS/HS (FW 2.0.50), but only the latter has
> KVASER_USB_HAS_TXRX_ERRORS set to enable do_get_berr_counter().
>
> Enable error counter retrieval for Kvaser Mini PCI Express 2xHS, too.
>
> Fixes: 71873a9b38d1 ("can: kvaser_usb: Add support for more Kvaser Leaf v2 devices")
> Signed-off-by: Anssi Hannula <[email protected]>
>
> ---
>
> I'm not really sure what KVASER_USB_HAS_TXRX_ERRORS means, exactly,
> w.r.t. device behavior, though, i.e. how does a device without it behave.

Devices without KVASER_USB_HAS_TXRX_ERRORS, firmware will always report
zero for the Rx and Tx error counters.

> drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> 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 47bff40c36b6..7388fdca9079 100644
> --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
> +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
> @@ -165,7 +165,8 @@ static const struct usb_device_id kvaser_usb_table[] = {
> { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
> { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID) },
> { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID) },
> - { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID) },
> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID),
> + .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
> { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID) },
> { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID) },
> { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID) },



It's possible to query the device for specific capabilities.
i.e. Kvaser Mini PCI Express 2xHS does also got support for silent mode.

I want to replace this patch with the one below:

From fbf1c02e5f7860be9bdafd1c9b4f01c903dd9258 Mon Sep 17 00:00:00 2001
From: Jimmy Assarsson <[email protected]>
Date: Wed, 25 May 2022 20:21:19 +0200
Subject: [PATCH 04/13] can: kvaser_usb: kvaser_usb_leaf: Get
capabilities from
device

Use the CMD_GET_CAPABILITIES_REQ command to query the device for certain
capabilities. We are only interested in LISTENONLY mode and wither the
device reports CAN error counters.

And remove hard coded capabilities for all Leaf devices.

Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB
devices")
Reported-by: Anssi Hannula <[email protected]>
Signed-off-by: Jimmy Assarsson <[email protected]>
---
.../net/can/usb/kvaser_usb/kvaser_usb_core.c | 61 ++------
.../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 146 +++++++++++++++++-
2 files changed, 162 insertions(+), 45 deletions(-)

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 47bff40c36b6..247caf0982bc 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
@@ -116,51 +116,24 @@ static const struct usb_device_id
kvaser_usb_table[] = {
/* Leaf USB product 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),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
- KVASER_USB_HAS_SILENT_MODE },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
- KVASER_USB_HAS_SILENT_MODE },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
- KVASER_USB_HAS_SILENT_MODE },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
- KVASER_USB_HAS_SILENT_MODE },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
- KVASER_USB_HAS_SILENT_MODE },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
- KVASER_USB_HAS_SILENT_MODE },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
- KVASER_USB_HAS_SILENT_MODE },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
- KVASER_USB_HAS_SILENT_MODE },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
- KVASER_USB_HAS_SILENT_MODE },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
- KVASER_USB_HAS_SILENT_MODE },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
- { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
- .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID) },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID) },
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 09ade66256b2..aee2dae67459 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -74,6 +74,8 @@
#define CMD_TX_ACKNOWLEDGE 50
#define CMD_CAN_ERROR_EVENT 51
#define CMD_FLUSH_QUEUE_REPLY 68
+#define CMD_GET_CAPABILITIES_REQ 95
+#define CMD_GET_CAPABILITIES_RESP 96

#define CMD_LEAF_LOG_MESSAGE 106

@@ -83,6 +85,8 @@
#define KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK BIT(5)
#define KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK BIT(6)

+#define KVASER_USB_LEAF_SWOPTION_EXT_CAP BIT(12)
+
/* error factors */
#define M16C_EF_ACKE BIT(0)
#define M16C_EF_CRCE BIT(1)
@@ -288,6 +292,28 @@ struct leaf_cmd_log_message {
u8 data[8];
} __packed;

+/* Sub commands for cap_req and cap_res */
+#define KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE 0x02
+#define KVASER_USB_LEAF_CAP_CMD_ERR_REPORT 0x05
+struct kvaser_cmd_cap_req {
+ __le16 padding0;
+ __le16 cap_cmd;
+ __le16 padding1;
+ __le16 channel;
+} __packed;
+
+/* Status codes for cap_res */
+#define KVASER_USB_LEAF_CAP_STAT_OK 0x00
+#define KVASER_USB_LEAF_CAP_STAT_NOT_IMPL 0x01
+#define KVASER_USB_LEAF_CAP_STAT_UNAVAIL 0x02
+struct kvaser_cmd_cap_res {
+ __le16 padding;
+ __le16 cap_cmd;
+ __le16 status;
+ __le32 mask;
+ __le32 value;
+} __packed;
+
struct kvaser_cmd {
u8 len;
u8 id;
@@ -305,6 +331,8 @@ struct kvaser_cmd {
struct leaf_cmd_chip_state_event chip_state_event;
struct leaf_cmd_error_event error_event;
struct leaf_cmd_log_message log_message;
+ struct kvaser_cmd_cap_req cap_req;
+ struct kvaser_cmd_cap_res cap_res;
} __packed leaf;

union {
@@ -334,6 +362,7 @@ 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_CAPABILITIES_RESP] = kvaser_fsize(u.leaf.cap_res),
/* ignored events: */
[CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY,
};
@@ -596,6 +625,9 @@ static void
kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
dev->fw_version = le32_to_cpu(softinfo->fw_version);
dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx);

+ if (sw_options & KVASER_USB_LEAF_SWOPTION_EXT_CAP)
+ dev->card_data.capabilities |= KVASER_USB_CAP_EXT_CAP;
+
switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
dev->cfg = &kvaser_usb_leaf_dev_cfg_16mhz;
@@ -676,6 +708,118 @@ static int kvaser_usb_leaf_get_card_info(struct
kvaser_usb *dev)
return 0;
}

+static int kvaser_usb_leaf_get_single_capability(struct kvaser_usb *dev,
+ u16 cap_cmd_req, u16 *status)
+{
+ struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
+ struct kvaser_cmd *cmd;
+ u32 value = 0;
+ u32 mask = 0;
+ u16 cap_cmd_res;
+ int err;
+ int i;
+
+ cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->id = CMD_GET_CAPABILITIES_REQ;
+ cmd->u.leaf.cap_req.cap_cmd = cpu_to_le16(cap_cmd_req);
+ cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_cap_req);
+
+ err = kvaser_usb_send_cmd(dev, cmd, cmd->len);
+ if (err)
+ goto end;
+
+ err = kvaser_usb_leaf_wait_cmd(dev, CMD_GET_CAPABILITIES_RESP, cmd);
+ if (err)
+ goto end;
+
+ *status = le16_to_cpu(cmd->u.leaf.cap_res.status);
+
+ if (*status != KVASER_USB_LEAF_CAP_STAT_OK)
+ goto end;
+
+ cap_cmd_res = le16_to_cpu(cmd->u.leaf.cap_res.cap_cmd);
+ switch (cap_cmd_res) {
+ case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE:
+ case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT:
+ value = le32_to_cpu(cmd->u.leaf.cap_res.value);
+ mask = le32_to_cpu(cmd->u.leaf.cap_res.mask);
+ break;
+ default:
+ dev_warn(&dev->intf->dev, "Unknown capability command %u\n",
+ cap_cmd_res);
+ break;
+ }
+
+ for (i = 0; i < dev->nchannels; i++) {
+ if (BIT(i) & (value & mask)) {
+ switch (cap_cmd_res) {
+ case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE:
+ card_data->ctrlmode_supported |=
+ CAN_CTRLMODE_LISTENONLY;
+ break;
+ case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT:
+ card_data->capabilities |=
+ KVASER_USB_CAP_BERR_CAP;
+ break;
+ }
+ }
+ }
+
+end:
+ kfree(cmd);
+
+ return err;
+}
+
+static int kvaser_usb_leaf_get_capabilities_leaf(struct kvaser_usb *dev)
+{
+ int err;
+ u16 status;
+
+ if (!(dev->card_data.capabilities & KVASER_USB_CAP_EXT_CAP)) {
+ dev_info(&dev->intf->dev,
+ "No extended capability support. Upgrade device firmware.\n");
+ return 0;
+ }
+
+ err = kvaser_usb_leaf_get_single_capability
+ (dev,
+ KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE,
+ &status);
+ if (err)
+ return err;
+ if (status)
+ dev_info(&dev->intf->dev,
+ "KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE failed %u\n",
+ status);
+
+ err = kvaser_usb_leaf_get_single_capability
+ (dev,
+ KVASER_USB_LEAF_CAP_CMD_ERR_REPORT,
+ &status);
+ if (err)
+ return err;
+ if (status)
+ dev_info(&dev->intf->dev,
+ "KVASER_USB_LEAF_CAP_CMD_ERR_REPORT failed %u\n",
+ status);
+
+ return 0;
+}
+
+static int kvaser_usb_leaf_get_capabilities(struct kvaser_usb *dev)
+{
+ int err = 0;
+
+ if (dev->card_data.leaf.family == KVASER_LEAF)
+ err = kvaser_usb_leaf_get_capabilities_leaf(dev);
+
+ return err;
+}
+
static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
const struct kvaser_cmd *cmd)
{
@@ -1462,7 +1606,7 @@ const struct kvaser_usb_dev_ops
kvaser_usb_leaf_dev_ops = {
.dev_get_software_info = kvaser_usb_leaf_get_software_info,
.dev_get_software_details = NULL,
.dev_get_card_info = kvaser_usb_leaf_get_card_info,
- .dev_get_capabilities = NULL,
+ .dev_get_capabilities = kvaser_usb_leaf_get_capabilities,
.dev_set_opt_mode = kvaser_usb_leaf_set_opt_mode,
.dev_start_chip = kvaser_usb_leaf_start_chip,
.dev_stop_chip = kvaser_usb_leaf_stop_chip,
--
2.36.1


2022-05-28 19:25:04

by Jimmy Assarsson

[permalink] [raw]
Subject: Re: [PATCH 10/12] can: kvaser_usb_leaf: Fix wrong CAN state after stopping

On 5/16/22 15:47, Anssi Hannula wrote:
> 0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778 sends a
> CMD_CHIP_STATE_EVENT indicating bus-off after stopping the device,
> causing a stopped device to appear as CAN_STATE_BUS_OFF instead of
> CAN_STATE_STOPPED.
>
> Fix that by not handling error events on stopped devices.
>
> Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
> Signed-off-by: Anssi Hannula <[email protected]>

Looks good to me.
Tested-by: Jimmy Assarsson <[email protected]>

> ---
> drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 4 ++++
> 1 file changed, 4 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 7ed2ced8ba08..742626e69dd8 100644
> --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> @@ -879,6 +879,10 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
> leaf = priv->sub_priv;
> stats = &priv->netdev->stats;
>
> + /* Ignore e.g. state change to bus-off reported just after stopping */
> + if (!netif_running(priv->netdev))
> + return;
> +
> /* Update all of the CAN interface's state and error counters before
> * trying any memory allocation that can actually fail with -ENOMEM.
> *

2022-05-28 20:02:51

by Jimmy Assarsson

[permalink] [raw]
Subject: Re: [PATCH 05/12] can: kvaser_usb_leaf: Set Warning state even without bus errors

On 5/16/22 15:47, Anssi Hannula wrote:
> kvaser_usb_leaf_rx_error_update_can_state() sets error state according
> to error counters when the hardware does not indicate a specific state
> directly.
>
> However, this is currently gated behind a check for
> M16C_STATE_BUS_ERROR which does not always seem to be set when error
> counters are increasing, and may not be set when error counters are
> decreasing.
>
> This causes the CAN_STATE_ERROR_WARNING state to not be set in some
> cases even when appropriate.
>
> Change the code to set error state from counters even without
> M16C_STATE_BUS_ERROR.
>
> The Error-Passive case seems superfluous as it is already set via
> M16C_STATE_BUS_PASSIVE flag above, but it is kept for now.
>
> Tested with 0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778.
>
> Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
> Signed-off-by: Anssi Hannula <[email protected]>

Looks good to me.
Tested-by: Jimmy Assarsson <[email protected]>

> ---
> .../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 20 ++++++++-----------
> 1 file changed, 8 insertions(+), 12 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 09ade66256b2..d7f2d64a8083 100644
> --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> @@ -775,20 +775,16 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
> 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) {
> + } else if ((es->status & M16C_STATE_BUS_ERROR) &&
> + cur_state >= CAN_STATE_BUS_OFF) {
> /* 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)
> + } 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 {
> new_state = CAN_STATE_ERROR_ACTIVE;
> + }
>
> if (new_state != cur_state) {
> tx_state = (es->txerr >= es->rxerr) ? new_state : 0;

2022-05-28 20:19:06

by Jimmy Assarsson

[permalink] [raw]
Subject: Re: [PATCH 01/12] can: kvaser_usb_leaf: Fix overread with an invalid command

On 5/16/22 15:47, Anssi Hannula wrote:
> For command events read from the device,
> kvaser_usb_leaf_read_bulk_callback() verifies that cmd->len does not
> exceed the size of the received data, but the actual kvaser_cmd handlers
> will happily read any kvaser_cmd fields without checking for cmd->len.
>
> This can cause an overread if the last cmd in the buffer is shorter than
> expected for the command type (with cmd->len showing the actual short
> size).
>
> Maximum overread seems to be 22 bytes (CMD_LEAF_LOG_MESSAGE), some of
> which are delivered to userspace as-is.
>
> Fix that by verifying the length of command before handling it.
>
> This issue can only occur after RX URBs have been set up, i.e. the
> interface has been opened at least once.
>
> Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
> Signed-off-by: Anssi Hannula <[email protected]>

Looks good to me.
Tested-by: Jimmy Assarsson <[email protected]>


> ---
>
> A simpler option would be to just zero-pad the data into a
> stack-allocated struct kvaser_cmd without knowledge of the needed
> minimum size (so no tables needed), though that would mean incomplete
> commands would get passed on silently.
>
> .../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 75 +++++++++++++++++++
> 1 file changed, 75 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 c805b999c543..d9f40b9702a5 100644
> --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> @@ -320,6 +320,38 @@ struct kvaser_cmd {
> } u;
> } __packed;
>
> +#define CMD_SIZE_ANY 0xff
> +#define kvaser_fsize(field) sizeof_field(struct kvaser_cmd, field)
> +
> +static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
> + [CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
> + [CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
> + [CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo),
> + [CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.tx_acknowledge_header),
> + [CMD_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.leaf.softinfo),
> + [CMD_RX_STD_MESSAGE] = kvaser_fsize(u.leaf.rx_can),
> + [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),
> + /* ignored events: */
> + [CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY,
> +};
> +
> +static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
> + [CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
> + [CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
> + [CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo),
> + [CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.tx_acknowledge_header),
> + [CMD_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.usbcan.softinfo),
> + [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),
> + /* ignored events: */
> + [CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY,
> +};
> +
> /* Summary of a kvaser error event, for a unified Leaf/Usbcan error
> * handling. Some discrepancies between the two families exist:
> *
> @@ -387,6 +419,43 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_32mhz = {
> .bittiming_const = &kvaser_usb_leaf_bittiming_const,
> };
>
> +static int kvaser_usb_leaf_verify_size(const struct kvaser_usb *dev,
> + const struct kvaser_cmd *cmd)
> +{
> + /* buffer size >= cmd->len ensured by caller */
> + u8 min_size = 0;
> +
> + switch (dev->card_data.leaf.family) {
> + case KVASER_LEAF:
> + if (cmd->id < ARRAY_SIZE(kvaser_usb_leaf_cmd_sizes_leaf))
> + min_size = kvaser_usb_leaf_cmd_sizes_leaf[cmd->id];
> + break;
> + case KVASER_USBCAN:
> + if (cmd->id < ARRAY_SIZE(kvaser_usb_leaf_cmd_sizes_usbcan))
> + min_size = kvaser_usb_leaf_cmd_sizes_usbcan[cmd->id];
> + break;
> + }
> +
> + if (min_size == CMD_SIZE_ANY)
> + return 0;
> +
> + if (min_size) {
> + min_size += CMD_HEADER_LEN;
> + if (cmd->len >= min_size)
> + return 0;
> +
> + dev_err_ratelimited(&dev->intf->dev,
> + "Received command %u too short (size %u, needed %u)",
> + cmd->id, cmd->len, min_size);
> + return -EIO;
> + }
> +
> + dev_warn_ratelimited(&dev->intf->dev,
> + "Unhandled command (%d, size %d)\n",
> + cmd->id, cmd->len);
> + return -EINVAL;
> +}
> +
> static void *
> kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
> const struct sk_buff *skb, int *cmd_len,
> @@ -492,6 +561,9 @@ static int kvaser_usb_leaf_wait_cmd(const struct kvaser_usb *dev, u8 id,
> end:
> kfree(buf);
>
> + if (err == 0)
> + err = kvaser_usb_leaf_verify_size(dev, cmd);
> +
> return err;
> }
>
> @@ -1113,6 +1185,9 @@ static void kvaser_usb_leaf_stop_chip_reply(const struct kvaser_usb *dev,
> static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
> const struct kvaser_cmd *cmd)
> {
> + if (kvaser_usb_leaf_verify_size(dev, cmd) < 0)
> + return;
> +
> switch (cmd->id) {
> case CMD_START_CHIP_REPLY:
> kvaser_usb_leaf_start_chip_reply(dev, cmd);

2022-05-30 13:23:46

by Anssi Hannula

[permalink] [raw]
Subject: Re: [PATCH 00/12] can: kvaser_usb: Various fixes

On 28.5.2022 10.42, Jimmy Assarsson wrote:
> On 5/17/22 10:41, Jimmy Assarsson wrote:
>> On 2022-05-16 15:47, Anssi Hannula wrote:
>>> Hi all,
>>>
>>> Here's a set of fixes for issues I found while testing kvaser_usb as we
>>> are preparing to start using it in production (with 0bfd:0124).
>> Hi Anssi,
>>
>> Thanks for the patches!
>> I will review and test your fixes before the weekend.
>>
>> Best regards,
>> jimmy
> Sorry for the delay!

No problem!

> To summarize the status.
>
> These patches look good:
> [PATCH 01/12] can: kvaser_usb_leaf: Fix overread with an invalid command
> [PATCH 02/12] can: kvaser_usb: Fix use of uninitialized completion
> [PATCH 03/12] can: kvaser_usb: Fix possible completions during
> init_completion
> [PATCH 05/12] can: kvaser_usb_leaf: Set Warning state even without bus
> errors
> [PATCH 10/12] can: kvaser_usb_leaf: Fix wrong CAN state after stopping
> [PATCH 12/12] can: kvaser_usb_leaf: Fix bogus restart events
>
> This looks good, but see comment regarding explicit queue flush:
> [PATCH 06/12] can: kvaser_usb_leaf: Fix TX queue out of sync after restart

Feel free to drop the flush, or let me know if you want me to resend it
without it.

> I still need some more time looking into:
> PATCH 07/12] can: kvaser_usb_leaf: Fix CAN state after restart
> PATCH 08/12] can: kvaser_usb_leaf: Fix improved state not being reported
> PATCH 11/12] can: kvaser_usb_leaf: Ignore stale bus-off after start
>
> I want to replace
> [PATCH 04/12] can: kvaser_usb: Mark Mini PCIe 2xHS as supporting error
> counters
> with a new patch
> "can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device"
>
> I want to split the handling of CMD_ERROR_EVENT and the readback
> functionality. I also want to add parameter readback for
> kvaser_usb_hydra. I need more time to look over the can_bittiming_const
> in kvaser_usb_leaf for the different supported firmware.
> [PATCH 09/12] can: kvaser_usb_leaf: Fix silently failing bus params setup
>
>
> I would like to create a V2 series, including my patches, if you are
> okay with it?


Yes, that's fine. I can test your series on my setup as well.

>
> Best regards,
> jimmy
>
>
>
>>> The biggest caveat is that I only have two devices to test with [1] and I
>>> don't have HW documentation, so there is a possibility that some of the
>>> fixes might not work properly on all HW variants.
>>> Hopefully Jimmy can confirm they look OK, or suggest alternatives.
>>>
>>> [1] Tested devices:
>>> - 0bfd:0017 Kvaser Memorator Professional HS/HS FW 2.0.50
>>> - 0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778


--
Anssi Hannula / Bitwise Oy
+358 503803997


2022-05-31 16:19:44

by Anssi Hannula

[permalink] [raw]
Subject: Re: [PATCH 04/12] can: kvaser_usb: Mark Mini PCIe 2xHS as supporting error counters

On 28.5.2022 10.37, Jimmy Assarsson wrote:
> On 5/16/22 15:47, Anssi Hannula wrote:
>> The 0bfd:0124 Kvaser Mini PCI Express 2xHS (FW 4.18.778) seems to support
>> TX/RX error counters in exactly the same way (via unsolicited cmd 106 on
>> bus errors and via cmd 20 when queried with cmd 19) as 0bfd:0017 Kvaser
>> Memorator Professional HS/HS (FW 2.0.50), but only the latter has
>> KVASER_USB_HAS_TXRX_ERRORS set to enable do_get_berr_counter().
>>
>> Enable error counter retrieval for Kvaser Mini PCI Express 2xHS, too.
>>
>> Fixes: 71873a9b38d1 ("can: kvaser_usb: Add support for more Kvaser Leaf v2 devices")
>> Signed-off-by: Anssi Hannula <[email protected]>
>>
>> ---
>>
>> I'm not really sure what KVASER_USB_HAS_TXRX_ERRORS means, exactly,
>> w.r.t. device behavior, though, i.e. how does a device without it behave.
> Devices without KVASER_USB_HAS_TXRX_ERRORS, firmware will always report
> zero for the Rx and Tx error counters.
>
> It's possible to query the device for specific capabilities.
> i.e. Kvaser Mini PCI Express 2xHS does also got support for silent mode.
> I want to replace this patch with the one below:

Sounds good!
A couple of minor style comments below. I didn't test the code yet.

> From fbf1c02e5f7860be9bdafd1c9b4f01c903dd9258 Mon Sep 17 00:00:00 2001
> From: Jimmy Assarsson <[email protected]>
> Date: Wed, 25 May 2022 20:21:19 +0200
> Subject: [PATCH 04/13] can: kvaser_usb: kvaser_usb_leaf: Get
> capabilities from
> device
>
> Use the CMD_GET_CAPABILITIES_REQ command to query the device for certain
> capabilities. We are only interested in LISTENONLY mode and wither the
> device reports CAN error counters.
>
> And remove hard coded capabilities for all Leaf devices.
>
> Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB
> devices")
> Reported-by: Anssi Hannula <[email protected]>
> Signed-off-by: Jimmy Assarsson <[email protected]>
> ---
> .../net/can/usb/kvaser_usb/kvaser_usb_core.c | 61 ++------
> .../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 146 +++++++++++++++++-
> 2 files changed, 162 insertions(+), 45 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 09ade66256b2..aee2dae67459 100644
> --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
[...]
> +static int kvaser_usb_leaf_get_single_capability(struct kvaser_usb *dev,
> + u16 cap_cmd_req, u16 *status)
> +{
> + struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
> + struct kvaser_cmd *cmd;
> + u32 value = 0;
> + u32 mask = 0;
> + u16 cap_cmd_res;
> + int err;
> + int i;
> +
> + cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);

kzalloc can be used here, and prefer sizeof(*ptr) to avoid the risk of
type mismatch:

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);


[...]
> +static int kvaser_usb_leaf_get_capabilities_leaf(struct kvaser_usb *dev)
> +{
> + int err;
> + u16 status;
> +
> + if (!(dev->card_data.capabilities & KVASER_USB_CAP_EXT_CAP)) {
> + dev_info(&dev->intf->dev,
> + "No extended capability support. Upgrade device firmware.\n");
> + return 0;
> + }
> +
> + err = kvaser_usb_leaf_get_single_capability
> + (dev,
> + KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE,
> + &status);

I believe kernel style is to keep the opening parenthesis on the same
line with the function name here.

> + if (err)
> + return err;
> + if (status)
> + dev_info(&dev->intf->dev,
> + "KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE failed %u\n",
> + status);
> +
> + err = kvaser_usb_leaf_get_single_capability
> + (dev,
> + KVASER_USB_LEAF_CAP_CMD_ERR_REPORT,
> + &status);


Ditto.

[...]

--
Anssi Hannula / Bitwise Oy
+358 503803997


2022-06-06 15:52:06

by Jimmy Assarsson

[permalink] [raw]
Subject: Re: [PATCH 07/12] can: kvaser_usb_leaf: Fix CAN state after restart

On 5/16/22 15:47, Anssi Hannula wrote:
> can_restart() expects CMD_START_CHIP to set the error state to
> ERROR_ACTIVE as it calls netif_carrier_on() immediately afterwards.
>
> Otherwise the user may immediately trigger restart again and hit a
> BUG_ON() in can_restart().
>
> Fix kvaser_usb_leaf set_mode(CMD_START_CHIP) to set the expected state.
>
> Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
> Signed-off-by: Anssi Hannula <[email protected]>


Looks good to me.
Tested-by: Jimmy Assarsson <[email protected]>

> ---
> drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 2 ++
> 1 file changed, 2 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 2d30a662edb5..5f27c00179c1 100644
> --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> @@ -1411,6 +1411,8 @@ static int kvaser_usb_leaf_set_mode(struct net_device *netdev,
> err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP);
> if (err)
> return err;
> +
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> break;
> default:
> return -EOPNOTSUPP;

2022-06-06 15:52:16

by Jimmy Assarsson

[permalink] [raw]
Subject: Re: [PATCH 00/12] can: kvaser_usb: Various fixes

On 5/30/22 12:56, Anssi Hannula wrote:
> On 28.5.2022 10.42, Jimmy Assarsson wrote:
>> On 5/17/22 10:41, Jimmy Assarsson wrote:
>>> On 2022-05-16 15:47, Anssi Hannula wrote:
>>>> Hi all,
>>>>
>>>> Here's a set of fixes for issues I found while testing kvaser_usb as we
>>>> are preparing to start using it in production (with 0bfd:0124).
>>> Hi Anssi,
>>>
>>> Thanks for the patches!
>>> I will review and test your fixes before the weekend.
>>>
>>> Best regards,
>>> jimmy
>> Sorry for the delay!
>
> No problem!
>
>> To summarize the status.
>>
>> These patches look good:
>> [PATCH 01/12] can: kvaser_usb_leaf: Fix overread with an invalid command
>> [PATCH 02/12] can: kvaser_usb: Fix use of uninitialized completion
>> [PATCH 03/12] can: kvaser_usb: Fix possible completions during
>> init_completion
>> [PATCH 05/12] can: kvaser_usb_leaf: Set Warning state even without bus
>> errors
>> [PATCH 10/12] can: kvaser_usb_leaf: Fix wrong CAN state after stopping
>> [PATCH 12/12] can: kvaser_usb_leaf: Fix bogus restart events
>>
>> This looks good, but see comment regarding explicit queue flush:
>> [PATCH 06/12] can: kvaser_usb_leaf: Fix TX queue out of sync after restart
>
> Feel free to drop the flush, or let me know if you want me to resend it
> without it.
>
>> I still need some more time looking into:
>> PATCH 07/12] can: kvaser_usb_leaf: Fix CAN state after restart
>> PATCH 08/12] can: kvaser_usb_leaf: Fix improved state not being reported
>> PATCH 11/12] can: kvaser_usb_leaf: Ignore stale bus-off after start
>>
>> I want to replace
>> [PATCH 04/12] can: kvaser_usb: Mark Mini PCIe 2xHS as supporting error
>> counters
>> with a new patch
>> "can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device"
>>
>> I want to split the handling of CMD_ERROR_EVENT and the readback
>> functionality. I also want to add parameter readback for
>> kvaser_usb_hydra. I need more time to look over the can_bittiming_const
>> in kvaser_usb_leaf for the different supported firmware.
>> [PATCH 09/12] can: kvaser_usb_leaf: Fix silently failing bus params setup
>>
>>
>> I would like to create a V2 series, including my patches, if you are
>> okay with it?
>
>
> Yes, that's fine. I can test your series on my setup as well.

I'll rebase and send V2 of this series, once "can: kvaser_usb: CAN clock
frequency regression" [2], is sorted out.
That would be great :)


[2]
https://lore.kernel.org/linux-can/[email protected]

Best regards,
jimmy

2022-06-06 15:52:18

by Jimmy Assarsson

[permalink] [raw]
Subject: Re: [PATCH 11/12] can: kvaser_usb_leaf: Ignore stale bus-off after start

On 5/16/22 15:47, Anssi Hannula wrote:
> With 0bfd:0124 Kvaser Mini PCI Express 2xHS FW 4.18.778 it was observed
> that if the device was bus-off when stopped, at next start (either via
> interface down/up or manual bus-off restart) the initial
> CMD_CHIP_STATE_EVENT received just after CMD_START_CHIP_REPLY will have
> the M16C_STATE_BUS_OFF bit still set, causing the interface to
> immediately go bus-off again.

I'm able to reproduce this and it definitely looks like a bug in
firmware. I've created a case for this in our backlog, but I don't know
which priority it will get.

> The bit seems to internally clear quickly afterwards but we do not get
> another CMD_CHIP_STATE_EVENT.
>
> Fix the issue by ignoring any initial bus-off state until we see at
> least one bus-on state. Also, poll the state periodically until that
> occurs.
>
> It is possible we lose one actual immediately occurring bus-off event
> here in which case the HW will auto-recover and we see the recovery
> event. We will then catch the next bus-off event, if any.
>
> This issue did not reproduce with 0bfd:0017 Kvaser Memorator
> Professional HS/HS FW 2.0.50.
>
> Fixes: 71873a9b38d1 ("can: kvaser_usb: Add support for more Kvaser Leaf v2 devices")
> Signed-off-by: Anssi Hannula <[email protected]>

Looks good to me.
Tested-by: Jimmy Assarsson <[email protected]>

> ---
> .../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 31 ++++++++++++++++++-
> 1 file changed, 30 insertions(+), 1 deletion(-)
>
> 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 742626e69dd8..4125074c7066 100644
> --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
> @@ -401,6 +401,9 @@ struct kvaser_usb_net_leaf_priv {
> struct kvaser_cmd_busparams params_response;
>
> struct delayed_work chip_state_req_work;
> +
> + /* started but not reported as bus-on yet */
> + bool joining_bus;
> };
>
> static const struct can_bittiming_const kvaser_usb_leaf_bittiming_const = {
> @@ -800,6 +803,7 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
> const struct kvaser_usb_err_summary *es,
> struct can_frame *cf)
> {
> + struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
> 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;
> @@ -824,6 +828,22 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
> new_state = CAN_STATE_ERROR_ACTIVE;
> }
>
> + /* 0bfd:0124 FW 4.18.778 was observed to send the initial
> + * CMD_CHIP_STATE_EVENT after CMD_START_CHIP with M16C_STATE_BUS_OFF
> + * bit set if the channel was bus-off when it was last stopped (even
> + * across chip resets). This bit will clear shortly afterwards, without
> + * triggering a second unsolicited chip state event.
> + * Ignore this initial bus-off.
> + */
> + if (leaf->joining_bus) {
> + if (new_state == CAN_STATE_BUS_OFF) {
> + netdev_dbg(priv->netdev, "ignoring bus-off during startup");
> + new_state = cur_state;
> + } else {
> + leaf->joining_bus = false;
> + }
> + }
> +
> if (new_state != cur_state) {
> tx_state = (es->txerr >= es->rxerr) ? new_state : 0;
> rx_state = (es->txerr <= es->rxerr) ? new_state : 0;
> @@ -899,9 +919,12 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
>
> /* If there are errors, request status updates periodically as we do
> * not get automatic notifications of improved state.
> + * Also request updates if we saw a stale BUS_OFF during startup
> + * (joining_bus).
> */
> if (new_state < CAN_STATE_BUS_OFF &&
> - (es->rxerr || es->txerr || new_state == CAN_STATE_ERROR_PASSIVE))
> + (es->rxerr || es->txerr || new_state == CAN_STATE_ERROR_PASSIVE ||
> + leaf->joining_bus))
> schedule_delayed_work(&leaf->chip_state_req_work,
> msecs_to_jiffies(500));
>
> @@ -1392,8 +1415,11 @@ static int kvaser_usb_leaf_set_opt_mode(const struct kvaser_usb_net_priv *priv)
>
> static int kvaser_usb_leaf_start_chip(struct kvaser_usb_net_priv *priv)
> {
> + struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
> int err;
>
> + leaf->joining_bus = true;
> +
> reinit_completion(&priv->start_comp);
>
> err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_START_CHIP,
> @@ -1566,6 +1592,7 @@ static int kvaser_usb_leaf_set_mode(struct net_device *netdev,
> enum can_mode mode)
> {
> struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
> + struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
> int err;
>
> switch (mode) {
> @@ -1576,6 +1603,8 @@ static int kvaser_usb_leaf_set_mode(struct net_device *netdev,
>
> kvaser_usb_unlink_tx_urbs(priv);
>
> + leaf->joining_bus = true;
> +
> err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP);
> if (err)
> return err;