All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marc Kleine-Budde <mkl@pengutronix.de>
To: linux-can@vger.kernel.org
Cc: kernel@pengutronix.de, Peter Fink <pfink@christ-es.de>,
	Eric Evenchick <eric@evenchick.com>,
	Marc Kleine-Budde <mkl@pengutronix.de>
Subject: [can-next-rfc 15/21] can: gs_usb: add CAN-FD support
Date: Wed,  9 Mar 2022 13:41:26 +0100	[thread overview]
Message-ID: <20220309124132.291861-16-mkl@pengutronix.de> (raw)
In-Reply-To: <20220309124132.291861-1-mkl@pengutronix.de>

From: Peter Fink <pfink@christ-es.de>

CANtact Pro from Linklayer is the first gs_usb compatible device
supporting CAN-FD with a different HW and re-written candlelight FW.

Support for CAN-FD is indicated by the device setting the
GS_CAN_FEATURE_FD flag. CAN-FD support is requested by the driver with
the GS_CAN_MODE_FD flag. The CAN-FD specific data bit timing
parameters are set with the GS_USB_BREQ_DATA_BITTIMING control
message.

This patch is based on the Eric Evenchick's gs_usb_fd driver (which
itself is a fork of gs_usb). The gs_usb_fd code base was reintegrated
into the gs_usb driver, and reworked to not break the existing
classical-CAN only hardware.

Link: https://github.com/linklayer/gs_usb_fd/issues/2
Co-developed-by: Eric Evenchick <eric@evenchick.com>
Signed-off-by: Eric Evenchick <eric@evenchick.com>
Signed-off-by: Peter Fink <pfink@christ-es.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/usb/gs_usb.c | 124 ++++++++++++++++++++++++++++++-----
 1 file changed, 108 insertions(+), 16 deletions(-)

diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 1fe9d9f08c17..29389de99326 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -42,6 +42,7 @@ enum gs_usb_breq {
 	GS_USB_BREQ_IDENTIFY,
 	GS_USB_BREQ_GET_USER_ID,
 	GS_USB_BREQ_SET_USER_ID,
+	GS_USB_BREQ_DATA_BITTIMING,
 };
 
 enum gs_can_mode {
@@ -98,6 +99,7 @@ struct gs_device_config {
 /* GS_CAN_FEATURE_IDENTIFY BIT(5) */
 /* GS_CAN_FEATURE_USER_ID BIT(6) */
 #define GS_CAN_MODE_PAD_PKTS_TO_MAX_PKT_SIZE BIT(7)
+#define GS_CAN_MODE_FD BIT(8)
 
 struct gs_device_mode {
 	__le32 mode;
@@ -130,6 +132,7 @@ struct gs_identify_mode {
 #define GS_CAN_FEATURE_IDENTIFY BIT(5)
 #define GS_CAN_FEATURE_USER_ID BIT(6)
 #define GS_CAN_FEATURE_PAD_PKTS_TO_MAX_PKT_SIZE BIT(7)
+#define GS_CAN_FEATURE_FD BIT(8)
 
 struct gs_device_bt_const {
 	__le32 feature;
@@ -145,11 +148,18 @@ struct gs_device_bt_const {
 } __packed;
 
 #define GS_CAN_FLAG_OVERFLOW BIT(0)
+#define GS_CAN_FLAG_FD BIT(1)
+#define GS_CAN_FLAG_BRS BIT(2)
+#define GS_CAN_FLAG_ESI BIT(3)
 
 struct classic_can {
 	u8 data[8];
 } __packed;
 
+struct canfd {
+	u8 data[64];
+} __packed;
+
 struct gs_host_frame {
 	u32 echo_id;
 	__le32 can_id;
@@ -161,6 +171,7 @@ struct gs_host_frame {
 
 	union {
 		DECLARE_FLEX_ARRAY(struct classic_can, classic_can);
+		DECLARE_FLEX_ARRAY(struct canfd, canfd);
 	};
 } __packed;
 /* The GS USB devices make use of the same flags and masks as in
@@ -317,6 +328,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
 	struct gs_host_frame *hf = urb->transfer_buffer;
 	struct gs_tx_context *txc;
 	struct can_frame *cf;
+	struct canfd_frame *cfd;
 	struct sk_buff *skb;
 
 	BUG_ON(!usbcan);
@@ -345,18 +357,33 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
 		return;
 
 	if (hf->echo_id == -1) { /* normal rx */
-		skb = alloc_can_skb(dev->netdev, &cf);
-		if (!skb)
-			return;
+		if (hf->flags & GS_CAN_FLAG_FD) {
+			skb = alloc_canfd_skb(dev->netdev, &cfd);
+			if (!skb)
+				return;
+
+			cfd->can_id = le32_to_cpu(hf->can_id);
+			cfd->len = can_fd_dlc2len(hf->can_dlc);
+			if (hf->flags & GS_CAN_FLAG_BRS)
+				cfd->flags |= CANFD_BRS;
+			if (hf->flags & GS_CAN_FLAG_ESI)
+				cfd->flags |= CANFD_ESI;
+
+			memcpy(cfd->data, hf->canfd->data, cfd->len);
+		} else {
+			skb = alloc_can_skb(dev->netdev, &cf);
+			if (!skb)
+				return;
 
-		cf->can_id = le32_to_cpu(hf->can_id);
+			cf->can_id = le32_to_cpu(hf->can_id);
+			can_frame_set_cc_len(cf, hf->can_dlc, dev->can.ctrlmode);
 
-		can_frame_set_cc_len(cf, hf->can_dlc, dev->can.ctrlmode);
-		memcpy(cf->data, hf->classic_can->data, 8);
+			memcpy(cf->data, hf->classic_can->data, 8);
 
-		/* ERROR frames tell us information about the controller */
-		if (le32_to_cpu(hf->can_id) & CAN_ERR_FLAG)
-			gs_update_state(dev, cf);
+			/* ERROR frames tell us information about the controller */
+			if (le32_to_cpu(hf->can_id) & CAN_ERR_FLAG)
+				gs_update_state(dev, cf);
+		}
 
 		netdev->stats.rx_packets++;
 		netdev->stats.rx_bytes += hf->can_dlc;
@@ -456,6 +483,40 @@ static int gs_usb_set_bittiming(struct net_device *netdev)
 	return (rc > 0) ? 0 : rc;
 }
 
+static int gs_usb_set_data_bittiming(struct net_device *netdev)
+{
+	struct gs_can *dev = netdev_priv(netdev);
+	struct can_bittiming *bt = &dev->can.data_bittiming;
+	struct usb_interface *intf = dev->iface;
+	struct gs_device_bittiming *dbt;
+	int rc;
+
+	dbt = kmalloc(sizeof(*dbt), GFP_KERNEL);
+	if (!dbt)
+		return -ENOMEM;
+
+	dbt->prop_seg = cpu_to_le32(bt->prop_seg);
+	dbt->phase_seg1 = cpu_to_le32(bt->phase_seg1);
+	dbt->phase_seg2 = cpu_to_le32(bt->phase_seg2);
+	dbt->sjw = cpu_to_le32(bt->sjw);
+	dbt->brp = cpu_to_le32(bt->brp);
+
+	/* request bit timings */
+	rc = usb_control_msg(interface_to_usbdev(intf),
+			     usb_sndctrlpipe(interface_to_usbdev(intf), 0),
+			     GS_USB_BREQ_DATA_BITTIMING,
+			     USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			     dev->channel, 0, dbt, sizeof(*dbt), 1000);
+
+	kfree(dbt);
+
+	if (rc < 0)
+		dev_err(netdev->dev.parent,
+			"Couldn't set data bittimings (err=%d)", rc);
+
+	return (rc > 0) ? 0 : rc;
+}
+
 static void gs_usb_xmit_callback(struct urb *urb)
 {
 	struct gs_tx_context *txc = urb->context;
@@ -477,6 +538,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
 	struct urb *urb;
 	struct gs_host_frame *hf;
 	struct can_frame *cf;
+	struct canfd_frame *cfd;
 	int rc;
 	unsigned int idx;
 	struct gs_tx_context *txc;
@@ -513,12 +575,26 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
 	hf->flags = 0;
 	hf->reserved = 0;
 
-	cf = (struct can_frame *)skb->data;
+	if (can_is_canfd_skb(skb)) {
+		cfd = (struct canfd_frame *)skb->data;
+
+		hf->can_id = cpu_to_le32(cfd->can_id);
+		hf->can_dlc = can_fd_len2dlc(cfd->len);
+		hf->flags |= GS_CAN_FLAG_FD;
+		if (cfd->flags & CANFD_BRS)
+			hf->flags |= GS_CAN_FLAG_BRS;
+		if (cfd->flags & CANFD_ESI)
+			hf->flags |= GS_CAN_FLAG_ESI;
 
-	hf->can_id = cpu_to_le32(cf->can_id);
-	hf->can_dlc = can_get_cc_dlc(cf, dev->can.ctrlmode);
+		memcpy(hf->canfd->data, cfd->data, cfd->len);
+	} else {
+		cf = (struct can_frame *)skb->data;
 
-	memcpy(hf->classic_can->data, cf->data, cf->len);
+		hf->can_id = cpu_to_le32(cf->can_id);
+		hf->can_dlc = can_get_cc_dlc(cf, dev->can.ctrlmode);
+
+		memcpy(hf->classic_can->data, cf->data, cf->len);
+	}
 
 	usb_fill_bulk_urb(urb, dev->udev,
 			  usb_sndbulkpipe(dev->udev, GSUSB_ENDPOINT_OUT),
@@ -587,7 +663,13 @@ static int gs_can_open(struct net_device *netdev)
 	if (rc)
 		return rc;
 
-	dev->hf_size_tx = struct_size(hf, classic_can, 1);
+	ctrlmode = dev->can.ctrlmode;
+	if (ctrlmode & CAN_CTRLMODE_FD) {
+		flags |= GS_CAN_MODE_FD;
+		dev->hf_size_tx = struct_size(hf, canfd, 1);
+	} else {
+		dev->hf_size_tx = struct_size(hf, classic_can, 1);
+	}
 
 	if (!parent->active_channels) {
 		for (i = 0; i < GS_MAX_RX_URBS; i++) {
@@ -648,8 +730,6 @@ static int gs_can_open(struct net_device *netdev)
 		return -ENOMEM;
 
 	/* flags */
-	ctrlmode = dev->can.ctrlmode;
-
 	if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
 		flags |= GS_CAN_MODE_LOOP_BACK;
 	else if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
@@ -870,6 +950,12 @@ static struct gs_can *gs_make_candev(unsigned int channel,
 	if (feature & GS_CAN_FEATURE_ONE_SHOT)
 		dev->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;
 
+	if (feature & GS_CAN_FEATURE_FD) {
+		dev->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
+		dev->can.data_bittiming_const = &dev->bt_const;
+		dev->can.do_set_data_bittiming = gs_usb_set_data_bittiming;
+	}
+
 	if (le32_to_cpu(dconf->sw_version) > 1)
 		if (feature & GS_CAN_FEATURE_IDENTIFY)
 			netdev->ethtool_ops = &gs_usb_ethtool_ops;
@@ -961,6 +1047,9 @@ static int gs_usb_probe(struct usb_interface *intf,
 	}
 
 	init_usb_anchor(&dev->rx_submitted);
+	/* default to classic CAN, switch to CAN-FD if at least one of
+	 * our channels support CAN-FD.
+	 */
 	dev->hf_size_rx = struct_size(hf, classic_can, 1);
 
 	usb_set_intfdata(intf, dev);
@@ -983,6 +1072,9 @@ static int gs_usb_probe(struct usb_interface *intf,
 			return rc;
 		}
 		dev->canch[i]->parent = dev;
+
+		if (dev->canch[i]->can.ctrlmode_supported & CAN_CTRLMODE_FD)
+			dev->hf_size_rx = struct_size(hf, canfd, 1);
 	}
 
 	kfree(dconf);
-- 
2.34.1



  parent reply	other threads:[~2022-03-09 12:41 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-09 12:41 [RFC]: can-next gs-usb Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 01/21] can: gs_usb: use consistent one space indention Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 02/21] can: gs_usb: fix checkpatch warning Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 03/21] can: gs_usb: sort include files alphabetically Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 04/21] can: gs_usb: GS_CAN_FLAG_OVERFLOW: make use of BIT() Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 05/21] can: gs_usb: rewrap error messages Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 06/21] can: gs_usb: rewrap usb_control_msg() and usb_fill_bulk_urb() Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 07/21] can: gs_usb: gs_make_candev(): call SET_NETDEV_DEV() after handling all bt_const->feature Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 08/21] can: gs_usb: add HW timestamp mode bit Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 09/21] can: gs_usb: update GS_CAN_FEATURE_IDENTIFY documentation Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 10/21] can: gs_usb: document the USER_ID feature Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 11/21] can: gs_usb: document the PAD_PKTS_TO_MAX_PKT_SIZE feature Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 12/21] can: gs_usb: gs_usb_probe(): introduce udev and make use of it Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 13/21] can: gs_usb: support up to 3 channels per device Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 14/21] can: gs_usb: use union and FLEX_ARRAY for data in struct gs_host_frame Marc Kleine-Budde
2022-03-09 14:05   ` Vincent Mailhol
2022-03-09 14:16     ` Vincent Mailhol
2022-03-09 14:20       ` Marc Kleine-Budde
2022-03-09 14:18     ` Marc Kleine-Budde
2022-03-09 12:41 ` Marc Kleine-Budde [this message]
2022-03-09 12:41 ` [can-next-rfc 16/21] can: gs_usb: add usb quirk for NXP LPC546xx controllers Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 17/21] can: gs_usb: add quirk for CANtact Pro overlapping GS_USB_BREQ value Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 18/21] can: gs_usb: activate quirks for CANtact Pro unconditionally Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 19/21] can: gs_usb: add extended bt_const feature Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 20/21] can: gs_usb: add VID/PID for CES CANext FD devices Marc Kleine-Budde
2022-03-09 12:41 ` [can-next-rfc 21/21] can: gs_usb: add VID/PID for ABE CAN Debugger devices Marc Kleine-Budde

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220309124132.291861-16-mkl@pengutronix.de \
    --to=mkl@pengutronix.de \
    --cc=eric@evenchick.com \
    --cc=kernel@pengutronix.de \
    --cc=linux-can@vger.kernel.org \
    --cc=pfink@christ-es.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.