|
Takashi Iwai |
d3b2ab |
From 35364f5b41a4917fe94a3f393d149b63ec583297 Mon Sep 17 00:00:00 2001
|
|
Takashi Iwai |
d3b2ab |
From: Jimmy Assarsson <extja@kvaser.com>
|
|
Takashi Iwai |
d3b2ab |
Date: Mon, 10 Oct 2022 20:52:28 +0200
|
|
Takashi Iwai |
d3b2ab |
Subject: [PATCH] can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device
|
|
Takashi Iwai |
d3b2ab |
Git-commit: 35364f5b41a4917fe94a3f393d149b63ec583297
|
|
Takashi Iwai |
d3b2ab |
Patch-mainline: v6.2-rc1
|
|
Takashi Iwai |
d3b2ab |
References: git-fixes
|
|
Takashi Iwai |
d3b2ab |
|
|
Takashi Iwai |
d3b2ab |
Use the CMD_GET_CAPABILITIES_REQ command to query the device for certain
|
|
Takashi Iwai |
d3b2ab |
capabilities. We are only interested in LISTENONLY mode and wither the
|
|
Takashi Iwai |
d3b2ab |
device reports CAN error counters.
|
|
Takashi Iwai |
d3b2ab |
|
|
Takashi Iwai |
d3b2ab |
Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices")
|
|
Takashi Iwai |
d3b2ab |
Reported-by: Anssi Hannula <anssi.hannula@bitwise.fi>
|
|
Takashi Iwai |
d3b2ab |
Tested-by: Anssi Hannula <anssi.hannula@bitwise.fi>
|
|
Takashi Iwai |
d3b2ab |
Signed-off-by: Jimmy Assarsson <extja@kvaser.com>
|
|
Takashi Iwai |
d3b2ab |
Link: https://lore.kernel.org/all/20221010185237.319219-3-extja@kvaser.com
|
|
Takashi Iwai |
d3b2ab |
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
|
|
Takashi Iwai |
d3b2ab |
Acked-by: Takashi Iwai <tiwai@suse.de>
|
|
Takashi Iwai |
d3b2ab |
|
|
Takashi Iwai |
d3b2ab |
---
|
|
Takashi Iwai |
d3b2ab |
.../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 144 +++++++++++++++++-
|
|
Takashi Iwai |
d3b2ab |
1 file changed, 143 insertions(+), 1 deletion(-)
|
|
Takashi Iwai |
d3b2ab |
|
|
Takashi Iwai |
d3b2ab |
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 |
d3b2ab |
index 50f2ac8319ff..c87b13dc1048 100644
|
|
Takashi Iwai |
d3b2ab |
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
|
|
Takashi Iwai |
d3b2ab |
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
|
|
Takashi Iwai |
d3b2ab |
@@ -74,6 +74,8 @@
|
|
Takashi Iwai |
d3b2ab |
#define CMD_TX_ACKNOWLEDGE 50
|
|
Takashi Iwai |
d3b2ab |
#define CMD_CAN_ERROR_EVENT 51
|
|
Takashi Iwai |
d3b2ab |
#define CMD_FLUSH_QUEUE_REPLY 68
|
|
Takashi Iwai |
d3b2ab |
+#define CMD_GET_CAPABILITIES_REQ 95
|
|
Takashi Iwai |
d3b2ab |
+#define CMD_GET_CAPABILITIES_RESP 96
|
|
Takashi Iwai |
d3b2ab |
|
|
Takashi Iwai |
d3b2ab |
#define CMD_LEAF_LOG_MESSAGE 106
|
|
Takashi Iwai |
d3b2ab |
|
|
Takashi Iwai |
d3b2ab |
@@ -83,6 +85,8 @@
|
|
Takashi Iwai |
d3b2ab |
#define KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK BIT(5)
|
|
Takashi Iwai |
d3b2ab |
#define KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK BIT(6)
|
|
Takashi Iwai |
d3b2ab |
|
|
Takashi Iwai |
d3b2ab |
+#define KVASER_USB_LEAF_SWOPTION_EXT_CAP BIT(12)
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
/* error factors */
|
|
Takashi Iwai |
d3b2ab |
#define M16C_EF_ACKE BIT(0)
|
|
Takashi Iwai |
d3b2ab |
#define M16C_EF_CRCE BIT(1)
|
|
Takashi Iwai |
d3b2ab |
@@ -278,6 +282,28 @@ struct leaf_cmd_log_message {
|
|
Takashi Iwai |
d3b2ab |
u8 data[8];
|
|
Takashi Iwai |
d3b2ab |
} __packed;
|
|
Takashi Iwai |
d3b2ab |
|
|
Takashi Iwai |
d3b2ab |
+/* Sub commands for cap_req and cap_res */
|
|
Takashi Iwai |
d3b2ab |
+#define KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE 0x02
|
|
Takashi Iwai |
d3b2ab |
+#define KVASER_USB_LEAF_CAP_CMD_ERR_REPORT 0x05
|
|
Takashi Iwai |
d3b2ab |
+struct kvaser_cmd_cap_req {
|
|
Takashi Iwai |
d3b2ab |
+ __le16 padding0;
|
|
Takashi Iwai |
d3b2ab |
+ __le16 cap_cmd;
|
|
Takashi Iwai |
d3b2ab |
+ __le16 padding1;
|
|
Takashi Iwai |
d3b2ab |
+ __le16 channel;
|
|
Takashi Iwai |
d3b2ab |
+} __packed;
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+/* Status codes for cap_res */
|
|
Takashi Iwai |
d3b2ab |
+#define KVASER_USB_LEAF_CAP_STAT_OK 0x00
|
|
Takashi Iwai |
d3b2ab |
+#define KVASER_USB_LEAF_CAP_STAT_NOT_IMPL 0x01
|
|
Takashi Iwai |
d3b2ab |
+#define KVASER_USB_LEAF_CAP_STAT_UNAVAIL 0x02
|
|
Takashi Iwai |
d3b2ab |
+struct kvaser_cmd_cap_res {
|
|
Takashi Iwai |
d3b2ab |
+ __le16 padding;
|
|
Takashi Iwai |
d3b2ab |
+ __le16 cap_cmd;
|
|
Takashi Iwai |
d3b2ab |
+ __le16 status;
|
|
Takashi Iwai |
d3b2ab |
+ __le32 mask;
|
|
Takashi Iwai |
d3b2ab |
+ __le32 value;
|
|
Takashi Iwai |
d3b2ab |
+} __packed;
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
struct kvaser_cmd {
|
|
Takashi Iwai |
d3b2ab |
u8 len;
|
|
Takashi Iwai |
d3b2ab |
u8 id;
|
|
Takashi Iwai |
d3b2ab |
@@ -295,6 +321,8 @@ struct kvaser_cmd {
|
|
Takashi Iwai |
d3b2ab |
struct leaf_cmd_chip_state_event chip_state_event;
|
|
Takashi Iwai |
d3b2ab |
struct leaf_cmd_error_event error_event;
|
|
Takashi Iwai |
d3b2ab |
struct leaf_cmd_log_message log_message;
|
|
Takashi Iwai |
d3b2ab |
+ struct kvaser_cmd_cap_req cap_req;
|
|
Takashi Iwai |
d3b2ab |
+ struct kvaser_cmd_cap_res cap_res;
|
|
Takashi Iwai |
d3b2ab |
} __packed leaf;
|
|
Takashi Iwai |
d3b2ab |
|
|
Takashi Iwai |
d3b2ab |
union {
|
|
Takashi Iwai |
d3b2ab |
@@ -324,6 +352,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
|
|
Takashi Iwai |
d3b2ab |
[CMD_LEAF_LOG_MESSAGE] = kvaser_fsize(u.leaf.log_message),
|
|
Takashi Iwai |
d3b2ab |
[CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.leaf.chip_state_event),
|
|
Takashi Iwai |
d3b2ab |
[CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.leaf.error_event),
|
|
Takashi Iwai |
d3b2ab |
+ [CMD_GET_CAPABILITIES_RESP] = kvaser_fsize(u.leaf.cap_res),
|
|
Takashi Iwai |
d3b2ab |
/* ignored events: */
|
|
Takashi Iwai |
d3b2ab |
[CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY,
|
|
Takashi Iwai |
d3b2ab |
};
|
|
Takashi Iwai |
d3b2ab |
@@ -606,6 +635,9 @@ static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
|
|
Takashi Iwai |
d3b2ab |
dev->fw_version = le32_to_cpu(softinfo->fw_version);
|
|
Takashi Iwai |
d3b2ab |
dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx);
|
|
Takashi Iwai |
d3b2ab |
|
|
Takashi Iwai |
d3b2ab |
+ if (sw_options & KVASER_USB_LEAF_SWOPTION_EXT_CAP)
|
|
Takashi Iwai |
d3b2ab |
+ dev->card_data.capabilities |= KVASER_USB_CAP_EXT_CAP;
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
|
|
Takashi Iwai |
d3b2ab |
/* Firmware expects bittiming parameters calculated for 16MHz
|
|
Takashi Iwai |
d3b2ab |
* clock, regardless of the actual clock
|
|
Takashi Iwai |
d3b2ab |
@@ -693,6 +725,116 @@ static int kvaser_usb_leaf_get_card_info(struct kvaser_usb *dev)
|
|
Takashi Iwai |
d3b2ab |
return 0;
|
|
Takashi Iwai |
d3b2ab |
}
|
|
Takashi Iwai |
d3b2ab |
|
|
Takashi Iwai |
d3b2ab |
+static int kvaser_usb_leaf_get_single_capability(struct kvaser_usb *dev,
|
|
Takashi Iwai |
d3b2ab |
+ u16 cap_cmd_req, u16 *status)
|
|
Takashi Iwai |
d3b2ab |
+{
|
|
Takashi Iwai |
d3b2ab |
+ struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
|
|
Takashi Iwai |
d3b2ab |
+ struct kvaser_cmd *cmd;
|
|
Takashi Iwai |
d3b2ab |
+ u32 value = 0;
|
|
Takashi Iwai |
d3b2ab |
+ u32 mask = 0;
|
|
Takashi Iwai |
d3b2ab |
+ u16 cap_cmd_res;
|
|
Takashi Iwai |
d3b2ab |
+ int err;
|
|
Takashi Iwai |
d3b2ab |
+ int i;
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
|
Takashi Iwai |
d3b2ab |
+ if (!cmd)
|
|
Takashi Iwai |
d3b2ab |
+ return -ENOMEM;
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ cmd->id = CMD_GET_CAPABILITIES_REQ;
|
|
Takashi Iwai |
d3b2ab |
+ cmd->u.leaf.cap_req.cap_cmd = cpu_to_le16(cap_cmd_req);
|
|
Takashi Iwai |
d3b2ab |
+ cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_cap_req);
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ err = kvaser_usb_send_cmd(dev, cmd, cmd->len);
|
|
Takashi Iwai |
d3b2ab |
+ if (err)
|
|
Takashi Iwai |
d3b2ab |
+ goto end;
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ err = kvaser_usb_leaf_wait_cmd(dev, CMD_GET_CAPABILITIES_RESP, cmd);
|
|
Takashi Iwai |
d3b2ab |
+ if (err)
|
|
Takashi Iwai |
d3b2ab |
+ goto end;
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ *status = le16_to_cpu(cmd->u.leaf.cap_res.status);
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ if (*status != KVASER_USB_LEAF_CAP_STAT_OK)
|
|
Takashi Iwai |
d3b2ab |
+ goto end;
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ cap_cmd_res = le16_to_cpu(cmd->u.leaf.cap_res.cap_cmd);
|
|
Takashi Iwai |
d3b2ab |
+ switch (cap_cmd_res) {
|
|
Takashi Iwai |
d3b2ab |
+ case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE:
|
|
Takashi Iwai |
d3b2ab |
+ case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT:
|
|
Takashi Iwai |
d3b2ab |
+ value = le32_to_cpu(cmd->u.leaf.cap_res.value);
|
|
Takashi Iwai |
d3b2ab |
+ mask = le32_to_cpu(cmd->u.leaf.cap_res.mask);
|
|
Takashi Iwai |
d3b2ab |
+ break;
|
|
Takashi Iwai |
d3b2ab |
+ default:
|
|
Takashi Iwai |
d3b2ab |
+ dev_warn(&dev->intf->dev, "Unknown capability command %u\n",
|
|
Takashi Iwai |
d3b2ab |
+ cap_cmd_res);
|
|
Takashi Iwai |
d3b2ab |
+ break;
|
|
Takashi Iwai |
d3b2ab |
+ }
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ for (i = 0; i < dev->nchannels; i++) {
|
|
Takashi Iwai |
d3b2ab |
+ if (BIT(i) & (value & mask)) {
|
|
Takashi Iwai |
d3b2ab |
+ switch (cap_cmd_res) {
|
|
Takashi Iwai |
d3b2ab |
+ case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE:
|
|
Takashi Iwai |
d3b2ab |
+ card_data->ctrlmode_supported |=
|
|
Takashi Iwai |
d3b2ab |
+ CAN_CTRLMODE_LISTENONLY;
|
|
Takashi Iwai |
d3b2ab |
+ break;
|
|
Takashi Iwai |
d3b2ab |
+ case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT:
|
|
Takashi Iwai |
d3b2ab |
+ card_data->capabilities |=
|
|
Takashi Iwai |
d3b2ab |
+ KVASER_USB_CAP_BERR_CAP;
|
|
Takashi Iwai |
d3b2ab |
+ break;
|
|
Takashi Iwai |
d3b2ab |
+ }
|
|
Takashi Iwai |
d3b2ab |
+ }
|
|
Takashi Iwai |
d3b2ab |
+ }
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+end:
|
|
Takashi Iwai |
d3b2ab |
+ kfree(cmd);
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ return err;
|
|
Takashi Iwai |
d3b2ab |
+}
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+static int kvaser_usb_leaf_get_capabilities_leaf(struct kvaser_usb *dev)
|
|
Takashi Iwai |
d3b2ab |
+{
|
|
Takashi Iwai |
d3b2ab |
+ int err;
|
|
Takashi Iwai |
d3b2ab |
+ u16 status;
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ if (!(dev->card_data.capabilities & KVASER_USB_CAP_EXT_CAP)) {
|
|
Takashi Iwai |
d3b2ab |
+ dev_info(&dev->intf->dev,
|
|
Takashi Iwai |
d3b2ab |
+ "No extended capability support. Upgrade device firmware.\n");
|
|
Takashi Iwai |
d3b2ab |
+ return 0;
|
|
Takashi Iwai |
d3b2ab |
+ }
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ err = kvaser_usb_leaf_get_single_capability(dev,
|
|
Takashi Iwai |
d3b2ab |
+ KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE,
|
|
Takashi Iwai |
d3b2ab |
+ &status);
|
|
Takashi Iwai |
d3b2ab |
+ if (err)
|
|
Takashi Iwai |
d3b2ab |
+ return err;
|
|
Takashi Iwai |
d3b2ab |
+ if (status)
|
|
Takashi Iwai |
d3b2ab |
+ dev_info(&dev->intf->dev,
|
|
Takashi Iwai |
d3b2ab |
+ "KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE failed %u\n",
|
|
Takashi Iwai |
d3b2ab |
+ status);
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ err = kvaser_usb_leaf_get_single_capability(dev,
|
|
Takashi Iwai |
d3b2ab |
+ KVASER_USB_LEAF_CAP_CMD_ERR_REPORT,
|
|
Takashi Iwai |
d3b2ab |
+ &status);
|
|
Takashi Iwai |
d3b2ab |
+ if (err)
|
|
Takashi Iwai |
d3b2ab |
+ return err;
|
|
Takashi Iwai |
d3b2ab |
+ if (status)
|
|
Takashi Iwai |
d3b2ab |
+ dev_info(&dev->intf->dev,
|
|
Takashi Iwai |
d3b2ab |
+ "KVASER_USB_LEAF_CAP_CMD_ERR_REPORT failed %u\n",
|
|
Takashi Iwai |
d3b2ab |
+ status);
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ return 0;
|
|
Takashi Iwai |
d3b2ab |
+}
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+static int kvaser_usb_leaf_get_capabilities(struct kvaser_usb *dev)
|
|
Takashi Iwai |
d3b2ab |
+{
|
|
Takashi Iwai |
d3b2ab |
+ int err = 0;
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ if (dev->driver_info->family == KVASER_LEAF)
|
|
Takashi Iwai |
d3b2ab |
+ err = kvaser_usb_leaf_get_capabilities_leaf(dev);
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
+ return err;
|
|
Takashi Iwai |
d3b2ab |
+}
|
|
Takashi Iwai |
d3b2ab |
+
|
|
Takashi Iwai |
d3b2ab |
static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
|
|
Takashi Iwai |
d3b2ab |
const struct kvaser_cmd *cmd)
|
|
Takashi Iwai |
d3b2ab |
{
|
|
Takashi Iwai |
d3b2ab |
@@ -1486,7 +1628,7 @@ const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = {
|
|
Takashi Iwai |
d3b2ab |
.dev_get_software_info = kvaser_usb_leaf_get_software_info,
|
|
Takashi Iwai |
d3b2ab |
.dev_get_software_details = NULL,
|
|
Takashi Iwai |
d3b2ab |
.dev_get_card_info = kvaser_usb_leaf_get_card_info,
|
|
Takashi Iwai |
d3b2ab |
- .dev_get_capabilities = NULL,
|
|
Takashi Iwai |
d3b2ab |
+ .dev_get_capabilities = kvaser_usb_leaf_get_capabilities,
|
|
Takashi Iwai |
d3b2ab |
.dev_set_opt_mode = kvaser_usb_leaf_set_opt_mode,
|
|
Takashi Iwai |
d3b2ab |
.dev_start_chip = kvaser_usb_leaf_start_chip,
|
|
Takashi Iwai |
d3b2ab |
.dev_stop_chip = kvaser_usb_leaf_stop_chip,
|
|
Takashi Iwai |
d3b2ab |
--
|
|
Takashi Iwai |
d3b2ab |
2.35.3
|
|
Takashi Iwai |
d3b2ab |
|