Message ID | 20230504154414.1864615-3-frank.jungclaus@esd.eu |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp442806vqo; Thu, 4 May 2023 09:15:57 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6qtjwLFrkE8oDr3FP8BjDtxBUjqeYldrPSdqE2DhcDsGpdZytMnJS3kVcfJ3cbowuJtOed X-Received: by 2002:a05:6a00:10d4:b0:63b:5c82:e21a with SMTP id d20-20020a056a0010d400b0063b5c82e21amr3322420pfu.1.1683216957153; Thu, 04 May 2023 09:15:57 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1683216957; cv=pass; d=google.com; s=arc-20160816; b=Q+d/kKhGuQa3cDt+V8A96VO+F13KKSJTTwOs+zysnXEW7rkHzrnQZ0pUm4d8myyoEp F6sSiQZmyZ4a/IxRLno5QpgODogH4PrHwbm1EZcWfpgLmMyA1CTkgwCl/k2U3UQwSQGi OOILsoALOcTxhBwtyP3bPvcAPsdaXB8xPwJj34oVSFhu34/YrXVl0XE1y7FdhD5b6Hx6 FcZXXBhbnJEibOFO2O0mgVnAvLid4Cuc0qAGKF/Ih67BEEH9+c1xAbgXJZF/2t+RCOur HK6rUfzI3QetjrKS9cHNYKGf5ow5BL9R5j3Mdtf5XvXgaP+4sG5lCc8GWQ0KaknLe17S AhAw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=EPhyKgG1xpwo/nX1bXfvdJsx0VDYFN6i7w2yhM7rJnw=; b=MZqW6QfkeXdNN43YdCTFGt6KONPGJY8oo9p3t3KWZ9bkRTuCmEfnDZqHtJTU/z2ITh MZcCGvRT/DsLtlr69m28XXdVxWmVM0yRnwePWmqoHUilMa+5QYsa5PAAJCR3yZDK23Y0 3MXG7SUYslkidwOJic3+UDQQurt9Lq6UIeMbdcoZ6Kn0mMSBpEhb6RaiNVyJRhjLrNPn xFIoMWa/j3bIU9GmElla73JkSZ83IMhNipMaFlGB2z7dYGowt6t+srWE3Aa+CuDq2P1p Am0dNYijpiX3fwb4+mHG/+Jjqbb4VVvI2NW1LVy3YlMgJ/4dOpe2dNlr1Vyc2gfmXSUm w3ZA== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@esdhannover.onmicrosoft.com header.s=selector1-esdhannover-onmicrosoft-com header.b="szLG/ClS"; arc=pass (i=1); spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id q28-20020aa7961c000000b006439b3de4a2si156347pfg.101.2023.05.04.09.15.39; Thu, 04 May 2023 09:15:56 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@esdhannover.onmicrosoft.com header.s=selector1-esdhannover-onmicrosoft-com header.b="szLG/ClS"; arc=pass (i=1); spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231495AbjEDPof (ORCPT <rfc822;b08248@gmail.com> + 99 others); Thu, 4 May 2023 11:44:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54534 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231448AbjEDPoa (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Thu, 4 May 2023 11:44:30 -0400 Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05on2125.outbound.protection.outlook.com [40.107.22.125]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 919D244A1; Thu, 4 May 2023 08:44:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=fASG2fSOLK7SpJdXtZZEtL9BvhkYh0BtMdVAPmYQUm/vyk10qWW27X5bMObxrFtr791hoyz4V6DBg6ZANIWIcrxjvSo/ddqQs3AYYf0TBeINhzGk7NWkJxcK2+8D7MUUzwe2STy6c44lGhYv9IPF18e6HPMU898qDgmrBSuGqhUH12PM71Q0jFWEUOaZ7v3vbzx7KSm6Yz+HMiR9yPBpTn5+5Smd0Mt8bqL7MOc5sETCE2WlneAZrB4RGbMEwuiG8XWx9N4k+INIMjST8fk4LWYBjC3OXz/atZLipszvLXkHiT7QBzRIMzzWKxEfFOnoUpb29g5dZeVdfIFAGpLU1w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=EPhyKgG1xpwo/nX1bXfvdJsx0VDYFN6i7w2yhM7rJnw=; b=T+5r6nLRJEJ4aUaQPEnNUHUdpCl09sp9YQtlhVIc3NmWEvvQsamKSP8zSRZWXTtYXwS3hD5gzWeUxoJQPtX5I24W1HZdvcFY+W77nlTF2wcFiaVqyOlXqtNFXPQ+862EImauQEoBaSY0ttQ3QQIw7p+gZVGPDjZSTRzj/CGkxu/SLelojhOxETYZcWaBldn8yBB0DI7d9q8tJMPEoJNFsGuxwii5u4YPLgOHWreOtR5Voss/BVwGtS1HYPcmOffu6g3SjFp17XJNWpACQdkFlQeYlZkivpsbXWZtLIRJMCMZtVSltNqMOd1l7gjFBi4FQBvw7zmOfQUSZC+GEkgzVg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=softfail (sender ip is 80.151.164.27) smtp.rcpttodomain=esd.eu smtp.mailfrom=esd.eu; dmarc=none action=none header.from=esd.eu; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=esdhannover.onmicrosoft.com; s=selector1-esdhannover-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=EPhyKgG1xpwo/nX1bXfvdJsx0VDYFN6i7w2yhM7rJnw=; b=szLG/ClS5MwtJGgoz3XM9VNiRunp1F9NWGKiaNZ5nfRQ7xApouK0rOVoUplEb1QfLQoHkwbsSSLqrqJQg25e37liV3V+4DewXl3xVxDEP4nzwwGVWkEb4FOChPxVtoVc5Fh1S/IdodZYLVd43NprmKitka22EhwvkFHPfsDk4QU= Received: from DU2PR04CA0035.eurprd04.prod.outlook.com (2603:10a6:10:234::10) by DB9PR03MB7274.eurprd03.prod.outlook.com (2603:10a6:10:222::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6363.21; Thu, 4 May 2023 15:44:25 +0000 Received: from DB8EUR06FT060.eop-eur06.prod.protection.outlook.com (2603:10a6:10:234:cafe::65) by DU2PR04CA0035.outlook.office365.com (2603:10a6:10:234::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6363.26 via Frontend Transport; Thu, 4 May 2023 15:44:25 +0000 X-MS-Exchange-Authentication-Results: spf=softfail (sender IP is 80.151.164.27) smtp.mailfrom=esd.eu; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=esd.eu; Received-SPF: SoftFail (protection.outlook.com: domain of transitioning esd.eu discourages use of 80.151.164.27 as permitted sender) Received: from esd-s7.esd (80.151.164.27) by DB8EUR06FT060.mail.protection.outlook.com (10.233.253.39) with Microsoft SMTP Server id 15.20.6363.27 via Frontend Transport; Thu, 4 May 2023 15:44:24 +0000 Received: from esd-s20.esd.local (jenkins.esd.local [10.0.0.190]) by esd-s7.esd (Postfix) with ESMTPS id 0191C7C16CA; Thu, 4 May 2023 17:44:24 +0200 (CEST) Received: by esd-s20.esd.local (Postfix, from userid 2046) id E954D2E1787; Thu, 4 May 2023 17:44:23 +0200 (CEST) From: Frank Jungclaus <frank.jungclaus@esd.eu> To: linux-can@vger.kernel.org, Marc Kleine-Budde <mkl@pengutronix.de>, Wolfgang Grandegger <wg@grandegger.com>, Vincent Mailhol <mailhol.vincent@wanadoo.fr> Cc: =?utf-8?q?Stefan_M=C3=A4tje?= <stefan.maetje@esd.eu>, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Frank Jungclaus <frank.jungclaus@esd.eu> Subject: [PATCH 2/2] can: esd_usb: Add support for esd CAN-USB/3 Date: Thu, 4 May 2023 17:44:14 +0200 Message-Id: <20230504154414.1864615-3-frank.jungclaus@esd.eu> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230504154414.1864615-1-frank.jungclaus@esd.eu> References: <20230504154414.1864615-1-frank.jungclaus@esd.eu> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DB8EUR06FT060:EE_|DB9PR03MB7274:EE_ Content-Type: text/plain X-MS-Office365-Filtering-Correlation-Id: 6e15cad2-bb59-4e68-a742-08db4cb66f98 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: kIaXaerC5DG+Z6J0ma6izxDQtOp7BfKdx00fIj0Y3LaVzt7AoeVGAb2R81Kdfq0uEiWCeoozHkTKHKQ72jS1nuA5K3BhWafULdaFw9fFrfTO7B7anx7J8kpxwv1ZHSaHWCFXwDZ/hbQJuDQWjtKxFxyBb3KoTtdC60LrOdYtpCnb8OtNpFry8IYkeG9Xd6s+7bu6mf1AyfbsF71FC1moZ3lG8ghyWtm3juOTsiyPMNR852QmZbjTLCU06qOdmJO80oNuh4IeP5g3nZ4xEeXRLHH9nrPfidOq/YV1b1hHsFPlv8LJmKRvt/5WiBtXqAd+/vUVqWykyrCd6ZkQEoX0dDT61MyzmdBsYyNScWciawGFtcj/Ozdq/96Jf+U95NeVLdRZWYongIEgXf/WYkQ8e921kbRfkjy0ZK8YPrl3xRW4AqmaCL5KzOC8LXdP3ZS1cYjfhWZZtMxNeRY3kyUHnq106CBPjG8smnj7L43UV0wf0qCU7S2ezdzURU8Ut1LGx8zTdjM3JWYI6pSGwFKhEgqjAOeYbQ0apQoMj/SK5qh9nj0xO84aP9lFnyJoXaovoQ4KLTIXeLEtvcCBOVmykjPUOeJ/5DFiicPvZeUc/vr1ja46L8MgD4wH1X65ZI/eHPpThQVbA4flfcnjNJNuXAI1PNmTDb+Pmk5g+GpLKBM= X-Forefront-Antispam-Report: CIP:80.151.164.27;CTRY:DE;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:esd-s7.esd;PTR:p5097a41b.dip0.t-ipconnect.de;CAT:NONE;SFS:(13230028)(4636009)(39830400003)(396003)(136003)(376002)(346002)(451199021)(36840700001)(46966006)(42186006)(6266002)(186003)(478600001)(110136005)(54906003)(2616005)(336012)(1076003)(26005)(6666004)(36860700001)(47076005)(70586007)(4326008)(70206006)(41300700001)(316002)(83380400001)(5660300002)(8676002)(8936002)(44832011)(81166007)(30864003)(2906002)(356005)(40480700001)(36756003)(86362001)(82310400005);DIR:OUT;SFP:1102; X-OriginatorOrg: esd.eu X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 May 2023 15:44:24.1997 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 6e15cad2-bb59-4e68-a742-08db4cb66f98 X-MS-Exchange-CrossTenant-Id: 5a9c3a1d-52db-4235-b74c-9fd851db2e6b X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=5a9c3a1d-52db-4235-b74c-9fd851db2e6b;Ip=[80.151.164.27];Helo=[esd-s7.esd] X-MS-Exchange-CrossTenant-AuthSource: DB8EUR06FT060.eop-eur06.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR03MB7274 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1764980903951040936?= X-GMAIL-MSGID: =?utf-8?q?1764980903951040936?= |
Series |
can: esd_usb: Add support for esd CAN-USB/3 (CAN FD)
|
|
Commit Message
Frank Jungclaus
May 4, 2023, 3:44 p.m. UTC
Add support for esd CAN-USB/3 and CAN FD to esd_usb.
Signed-off-by: Frank Jungclaus <frank.jungclaus@esd.eu>
---
drivers/net/can/usb/esd_usb.c | 282 ++++++++++++++++++++++++++++++----
1 file changed, 249 insertions(+), 33 deletions(-)
Comments
Hi Frank, Thank you for your patch. Here is my first batch of comments. Some comments also apply to the existing code. So you may want to address those in separate clean-up patches first. On Fri. 5 May 2023 at 01:16, Frank Jungclaus <frank.jungclaus@esd.eu> wrote: > Add support for esd CAN-USB/3 and CAN FD to esd_usb. > > Signed-off-by: Frank Jungclaus <frank.jungclaus@esd.eu> > --- > drivers/net/can/usb/esd_usb.c | 282 ++++++++++++++++++++++++++++++---- > 1 file changed, 249 insertions(+), 33 deletions(-) > > diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c > index e24fa48b9b42..48cf5e88d216 100644 > --- a/drivers/net/can/usb/esd_usb.c > +++ b/drivers/net/can/usb/esd_usb.c > @@ -1,6 +1,6 @@ > // SPDX-License-Identifier: GPL-2.0-only > /* > - * CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro > + * CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro > * > * Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs <socketcan@esd.eu> > * Copyright (C) 2022-2023 esd electronics gmbh, Frank Jungclaus <frank.jungclaus@esd.eu> > @@ -18,17 +18,19 @@ > > MODULE_AUTHOR("Matthias Fuchs <socketcan@esd.eu>"); > MODULE_AUTHOR("Frank Jungclaus <frank.jungclaus@esd.eu>"); > -MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro interfaces"); > +MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro interfaces"); > MODULE_LICENSE("GPL v2"); > > /* USB vendor and product ID */ > #define USB_ESDGMBH_VENDOR_ID 0x0ab4 > #define USB_CANUSB2_PRODUCT_ID 0x0010 > #define USB_CANUSBM_PRODUCT_ID 0x0011 > +#define USB_CANUSB3_PRODUCT_ID 0x0014 > > /* CAN controller clock frequencies */ > #define ESD_USB2_CAN_CLOCK 60000000 > #define ESD_USBM_CAN_CLOCK 36000000 > +#define ESD_USB3_CAN_CLOCK 80000000 Nitpick: consider using the unit suffixes from linux/units.h: #define ESD_USB3_CAN_CLOCK (80 * MEGA) > /* Maximum number of CAN nets */ > #define ESD_USB_MAX_NETS 2 > @@ -43,6 +45,9 @@ MODULE_LICENSE("GPL v2"); > > /* esd CAN message flags - dlc field */ > #define ESD_DLC_RTR 0x10 > +#define ESD_DLC_NO_BRS 0x10 > +#define ESD_DLC_ESI 0x20 > +#define ESD_DLC_FD 0x80 Use the BIT() macro: #define ESD_DLC_NO_BRS BIT(4) #define ESD_DLC_ESI BIT(5) #define ESD_DLC_FD BIT(7) Also, if this is specific to the ESD_USB3 then add it in the prefix. > /* esd CAN message flags - id field */ > #define ESD_EXTID 0x20000000 > @@ -72,6 +77,28 @@ MODULE_LICENSE("GPL v2"); > #define ESD_USB2_BRP_INC 1 > #define ESD_USB2_3_SAMPLES 0x00800000 > > +/* Bit timing CAN-USB/3 */ > +#define ESD_USB3_TSEG1_MIN 1 > +#define ESD_USB3_TSEG1_MAX 256 > +#define ESD_USB3_TSEG2_MIN 1 > +#define ESD_USB3_TSEG2_MAX 128 > +#define ESD_USB3_SJW_MAX 128 > +#define ESD_USB3_BRP_MIN 1 > +#define ESD_USB3_BRP_MAX 1024 > +#define ESD_USB3_BRP_INC 1 > +/* Bit timing CAN-USB/3, data phase */ > +#define ESD_USB3_DATA_TSEG1_MIN 1 > +#define ESD_USB3_DATA_TSEG1_MAX 32 > +#define ESD_USB3_DATA_TSEG2_MIN 1 > +#define ESD_USB3_DATA_TSEG2_MAX 16 > +#define ESD_USB3_DATA_SJW_MAX 8 > +#define ESD_USB3_DATA_BRP_MIN 1 > +#define ESD_USB3_DATA_BRP_MAX 32 > +#define ESD_USB3_DATA_BRP_INC 1 There is no clear benefit to define macros for some initializers of a const struct. Doing as below has zero ambiguity: static const struct can_bittiming_const esd_usb3_bittiming_const = { .name = "esd_usb3", .tseg1_min = 1, .tseg1_max = 256, .tseg2_min = 1, .tseg2_max = 128, .sjw_max = 128, .brp_min = 1, .brp_max = 1024, .brp_inc = 1, }; > +/* Transmitter Delay Compensation */ > +#define ESD_TDC_MODE_AUTO 0 > + > /* esd IDADD message */ > #define ESD_ID_ENABLE 0x80 > #define ESD_MAX_ID_SEGMENT 64 > @@ -95,6 +122,21 @@ MODULE_LICENSE("GPL v2"); > #define MAX_RX_URBS 4 > #define MAX_TX_URBS 16 /* must be power of 2 */ > > +/* Modes for NTCAN_BAUDRATE_X */ > +#define ESD_BAUDRATE_MODE_DISABLE 0 /* remove from bus */ > +#define ESD_BAUDRATE_MODE_INDEX 1 /* ESD (CiA) bit rate idx */ > +#define ESD_BAUDRATE_MODE_BTR_CTRL 2 /* BTR values (Controller)*/ > +#define ESD_BAUDRATE_MODE_BTR_CANONICAL 3 /* BTR values (Canonical) */ > +#define ESD_BAUDRATE_MODE_NUM 4 /* numerical bit rate */ > +#define ESD_BAUDRATE_MODE_AUTOBAUD 5 /* autobaud */ > + > +/* Flags for NTCAN_BAUDRATE_X */ > +#define ESD_BAUDRATE_FLAG_FD 0x0001 /* enable CAN FD Mode */ > +#define ESD_BAUDRATE_FLAG_LOM 0x0002 /* enable Listen Only mode */ > +#define ESD_BAUDRATE_FLAG_STM 0x0004 /* enable Self test mode */ > +#define ESD_BAUDRATE_FLAG_TRS 0x0008 /* enable Triple Sampling */ > +#define ESD_BAUDRATE_FLAG_TXP 0x0010 /* enable Transmit Pause */ > + > struct header_msg { > u8 len; /* len is always the total message length in 32bit words */ > u8 cmd; > @@ -129,6 +171,7 @@ struct rx_msg { > __le32 id; /* upper 3 bits contain flags */ > union { > u8 data[8]; > + u8 data_fd[64]; > struct { > u8 status; /* CAN Controller Status */ > u8 ecc; /* Error Capture Register */ > @@ -144,8 +187,11 @@ struct tx_msg { > u8 net; > u8 dlc; > u32 hnd; /* opaque handle, not used by device */ > - __le32 id; /* upper 3 bits contain flags */ > - u8 data[8]; > + __le32 id; /* upper 3 bits contain flags */ > + union { > + u8 data[8]; > + u8 data_fd[64]; Nitpick, use the macro: u8 data[CAN_MAX_DLEN]; u8 data_fd[CANFD_MAX_DLEN]; > + }; > }; > > struct tx_done_msg { > @@ -165,12 +211,37 @@ struct id_filter_msg { > __le32 mask[ESD_MAX_ID_SEGMENT + 1]; > }; > > +struct baudrate_x_cfg { > + __le16 brp; /* bit rate pre-scaler */ > + __le16 tseg1; /* TSEG1 register */ > + __le16 tseg2; /* TSEG2 register */ > + __le16 sjw; /* SJW register */ > +}; > + > +struct tdc_cfg { Please prefix all the structures with the device name. e.g. struct esd_usb3_tdc_cfg { > + u8 tdc_mode; /* transmitter Delay Compensation mode */ > + u8 ssp_offset; /* secondary Sample Point offset in mtq */ > + s8 ssp_shift; /* secondary Sample Point shift in mtq */ > + u8 tdc_filter; /* Transmitter Delay Compensation */ > +}; > + > +struct baudrate_x { The x in baudrate_x and baudrate_x_cfg is confusing me. Is it meant to signify that the structure applies to both nominal and data baudrate? In that case, just put a comment and remove the x from the name. > + __le16 mode; /* mode word */ > + __le16 flags; /* control flags */ > + struct tdc_cfg tdc; /* TDC configuration */ > + struct baudrate_x_cfg arb; /* bit rate during arbitration phase */ /* nominal bit rate */ The comment is incorrect. CAN-FD may use the nominal bitrate for the data phase if the bit rate switch (BRS) is not set. > + struct baudrate_x_cfg data; /* bit rate during data phase */ /* data bit rate */ Please adjust the field names accordingly. > +}; > + > struct set_baudrate_msg { > u8 len; > u8 cmd; > u8 net; > u8 rsvd; > - __le32 baud; > + union { > + __le32 baud; > + struct baudrate_x baud_x; > + }; > }; > > /* Main message type used between library and application */ > @@ -188,6 +259,7 @@ union __packed esd_usb_msg { > static struct usb_device_id esd_usb_table[] = { > {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)}, > {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)}, > + {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB3_PRODUCT_ID)}, > {} > }; > MODULE_DEVICE_TABLE(usb, esd_usb_table); > @@ -326,11 +398,13 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv, > static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, > union esd_usb_msg *msg) > { > + bool is_canfd = msg->rx.dlc & ESD_DLC_FD ? true : false; This is redundant. Just this is enough: bool is_canfd = msg->rx.dlc & ESD_DLC_FD; This variable being used only twice, you may want to consider not declaring it and simply doing directly: if (msg->rx.dlc & ESD_DLC_FD) > struct net_device_stats *stats = &priv->netdev->stats; > struct can_frame *cf; > + struct canfd_frame *cfd; > struct sk_buff *skb; > - int i; > u32 id; > + u8 len; > > if (!netif_device_present(priv->netdev)) > return; > @@ -340,27 +414,42 @@ static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, > if (id & ESD_EVENT) { > esd_usb_rx_event(priv, msg); > } else { > - skb = alloc_can_skb(priv->netdev, &cf); > + if (is_canfd) { > + skb = alloc_canfd_skb(priv->netdev, &cfd); > + } else { > + skb = alloc_can_skb(priv->netdev, &cf); > + cfd = (struct canfd_frame *)cf; > + } > + > if (skb == NULL) { > stats->rx_dropped++; > return; > } > > - cf->can_id = id & ESD_IDMASK; > - can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR, > - priv->can.ctrlmode); > - > - if (id & ESD_EXTID) > - cf->can_id |= CAN_EFF_FLAG; > + cfd->can_id = id & ESD_IDMASK; > > - if (msg->rx.dlc & ESD_DLC_RTR) { > - cf->can_id |= CAN_RTR_FLAG; > + if (is_canfd) { > + /* masking by 0x0F is already done within can_fd_dlc2len() */ > + cfd->len = can_fd_dlc2len(msg->rx.dlc); > + len = cfd->len; > + if ((msg->rx.dlc & ESD_DLC_NO_BRS) == 0) > + cfd->flags |= CANFD_BRS; > + if (msg->rx.dlc & ESD_DLC_ESI) > + cfd->flags |= CANFD_ESI; > } else { > - for (i = 0; i < cf->len; i++) > - cf->data[i] = msg->rx.data[i]; > - > - stats->rx_bytes += cf->len; > + can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR, priv->can.ctrlmode); > + len = cf->len; > + if (msg->rx.dlc & ESD_DLC_RTR) { > + cf->can_id |= CAN_RTR_FLAG; > + len = 0; > + } > } > + > + if (id & ESD_EXTID) > + cfd->can_id |= CAN_EFF_FLAG; > + > + memcpy(cfd->data, msg->rx.data_fd, len); > + stats->rx_bytes += len; > stats->rx_packets++; > > netif_rx(skb); > @@ -735,7 +824,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, > struct esd_usb *dev = priv->usb; > struct esd_tx_urb_context *context = NULL; > struct net_device_stats *stats = &netdev->stats; > - struct can_frame *cf = (struct can_frame *)skb->data; > + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; > union esd_usb_msg *msg; > struct urb *urb; > u8 *buf; > @@ -768,19 +857,28 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, > msg->hdr.len = 3; /* minimal length */ > msg->hdr.cmd = CMD_CAN_TX; > msg->tx.net = priv->index; > - msg->tx.dlc = can_get_cc_dlc(cf, priv->can.ctrlmode); > - msg->tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK); > > - if (cf->can_id & CAN_RTR_FLAG) > - msg->tx.dlc |= ESD_DLC_RTR; > + if (can_is_canfd_skb(skb)) { > + msg->tx.dlc = can_fd_len2dlc(cfd->len); > + msg->tx.dlc |= ESD_DLC_FD; > + > + if ((cfd->flags & CANFD_BRS) == 0) > + msg->tx.dlc |= ESD_DLC_NO_BRS; > + } else { > + msg->tx.dlc = can_get_cc_dlc((struct can_frame *)cfd, priv->can.ctrlmode); > + > + if (cfd->can_id & CAN_RTR_FLAG) > + msg->tx.dlc |= ESD_DLC_RTR; > + } > > - if (cf->can_id & CAN_EFF_FLAG) > + msg->tx.id = cpu_to_le32(cfd->can_id & CAN_ERR_MASK); > + > + if (cfd->can_id & CAN_EFF_FLAG) > msg->tx.id |= cpu_to_le32(ESD_EXTID); > > - for (i = 0; i < cf->len; i++) > - msg->tx.data[i] = cf->data[i]; > + memcpy(msg->tx.data_fd, cfd->data, cfd->len); > > - msg->hdr.len += (cf->len + 3) >> 2; > + msg->hdr.len += (cfd->len + 3) >> 2; I do not get the logic. Assuming cfd->len is 8. Then hdr.len += (8 + 3) >> 2 hdr.len += 2 And because hdr.len is initially 3, hdr.len becomes 5. Right? Shouldn't it be 8? > for (i = 0; i < MAX_TX_URBS; i++) { > if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { > @@ -966,6 +1064,108 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) > return err; > } > > +static const struct can_bittiming_const esd_usb3_bittiming_const = { > + .name = "esd_usb3", > + .tseg1_min = ESD_USB3_TSEG1_MIN, > + .tseg1_max = ESD_USB3_TSEG1_MAX, > + .tseg2_min = ESD_USB3_TSEG2_MIN, > + .tseg2_max = ESD_USB3_TSEG2_MAX, > + .sjw_max = ESD_USB3_SJW_MAX, > + .brp_min = ESD_USB3_BRP_MIN, > + .brp_max = ESD_USB3_BRP_MAX, > + .brp_inc = ESD_USB3_BRP_INC, > +}; > + > +static const struct can_bittiming_const esd_usb3_data_bittiming_const = { > + .name = "esd_usb3", > + .tseg1_min = ESD_USB3_DATA_TSEG1_MIN, > + .tseg1_max = ESD_USB3_DATA_TSEG1_MAX, > + .tseg2_min = ESD_USB3_DATA_TSEG2_MIN, > + .tseg2_max = ESD_USB3_DATA_TSEG2_MAX, > + .sjw_max = ESD_USB3_DATA_SJW_MAX, > + .brp_min = ESD_USB3_DATA_BRP_MIN, > + .brp_max = ESD_USB3_DATA_BRP_MAX, > + .brp_inc = ESD_USB3_DATA_BRP_INC, > +}; > + > +static int esd_usb3_set_bittiming(struct net_device *netdev) > +{ > + struct esd_usb_net_priv *priv = netdev_priv(netdev); > + struct can_bittiming *bt = &priv->can.bittiming; > + struct can_bittiming *d_bt = &priv->can.data_bittiming; > + union esd_usb_msg *msg; > + int err; > + u16 mode; > + u16 flags = 0; > + u16 brp, tseg1, tseg2, sjw; > + u16 d_brp, d_tseg1, d_tseg2, d_sjw; > + > + msg = kmalloc(sizeof(*msg), GFP_KERNEL); > + if (!msg) > + return -ENOMEM; > + > + /* Canonical is the most reasonable mode for SocketCAN on CAN-USB/3 ... */ > + mode = ESD_BAUDRATE_MODE_BTR_CANONICAL; > + > + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) > + flags |= ESD_BAUDRATE_FLAG_LOM; > + > + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) > + flags |= ESD_BAUDRATE_FLAG_TRS; > + > + brp = bt->brp & (ESD_USB3_BRP_MAX - 1); > + sjw = bt->sjw & (ESD_USB3_SJW_MAX - 1); > + tseg1 = (bt->prop_seg + bt->phase_seg1) & (ESD_USB3_TSEG1_MAX - 1); > + tseg2 = bt->phase_seg2 & (ESD_USB3_TSEG2_MAX - 1); I am not convinced by the use of these intermediate variables brp, sjw, tseg1 and tseg2. I think you can directly assign them to baud_x. > + msg->setbaud.baud_x.arb.brp = cpu_to_le16(brp); > + msg->setbaud.baud_x.arb.sjw = cpu_to_le16(sjw); > + msg->setbaud.baud_x.arb.tseg1 = cpu_to_le16(tseg1); > + msg->setbaud.baud_x.arb.tseg2 = cpu_to_le16(tseg2); You may want to declare a local variable struct baudrate_x *baud_x = &msg->setbaud.baud_x; so that you do not have to do msg->setbaud.baud_x each time. > + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { > + d_brp = d_bt->brp & (ESD_USB3_DATA_BRP_MAX - 1); > + d_sjw = d_bt->sjw & (ESD_USB3_DATA_SJW_MAX - 1); > + d_tseg1 = (d_bt->prop_seg + d_bt->phase_seg1) & (ESD_USB3_DATA_TSEG1_MAX - 1); > + d_tseg2 = d_bt->phase_seg2 & (ESD_USB3_DATA_TSEG2_MAX - 1); > + flags |= ESD_BAUDRATE_FLAG_FD; > + } else { > + d_brp = 0; > + d_sjw = 0; > + d_tseg1 = 0; > + d_tseg2 = 0; > + } > + > + msg->setbaud.baud_x.data.brp = cpu_to_le16(d_brp); > + msg->setbaud.baud_x.data.sjw = cpu_to_le16(d_sjw); > + msg->setbaud.baud_x.data.tseg1 = cpu_to_le16(d_tseg1); > + msg->setbaud.baud_x.data.tseg2 = cpu_to_le16(d_tseg2); > + msg->setbaud.baud_x.mode = cpu_to_le16(mode); > + msg->setbaud.baud_x.flags = cpu_to_le16(flags); > + msg->setbaud.baud_x.tdc.tdc_mode = ESD_TDC_MODE_AUTO; > + msg->setbaud.baud_x.tdc.ssp_offset = 0; > + msg->setbaud.baud_x.tdc.ssp_shift = 0; > + msg->setbaud.baud_x.tdc.tdc_filter = 0; It seems that your device supports TDC. What is the reason to not configure it? Please have a look at struct can_tdc: https://elixir.bootlin.com/linux/v6.2/source/include/linux/can/bittiming.h#L21 Please refer to this patch if you want an example of how to use TDC: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1010a8fa9608 > + msg->hdr.len = 7; What is this magic number? If possible, replace it with a sizeof(). It seems that this relates to the size of struct set_baudrate_msg, but that structure is 8 bytes. Is the last byte of struct set_baudrate_msg really used? If not, reflect this in the declaration of the structure. > + msg->hdr.cmd = CMD_SETBAUD; > + > + msg->setbaud.net = priv->index; > + msg->setbaud.rsvd = 0; > + > + netdev_info(netdev, > + "ctrlmode=%#x/%#x, esd-net=%u, esd-mode=%#x, esd-flg=%#x, arb: brp=%u, ts1=%u, ts2=%u, sjw=%u, data: dbrp=%u, dts1=%u, dts2=%u dsjw=%u\n", > + priv->can.ctrlmode, priv->can.ctrlmode_supported, > + priv->index, mode, flags, > + brp, tseg1, tseg2, sjw, > + d_brp, d_tseg1, d_tseg2, d_sjw); Remove this debug message. The bittiming information can be retrieved with the ip tool. ip --details link show canX > + err = esd_usb_send_msg(priv->usb, msg); > + > + kfree(msg); esd_usb_send_msg() uses usb_bulk_msg() which does a synchronous call. It would be great to go asynchronous and use usb_submit_urb() so that you minimize the time spent in the driver. I know that esd_usb2_set_bittiming() also uses the synchronous call, so I am fine to have it as-is for this patch but for the future, it would be great to consider refactoring this. > + return err; > +} > + > static int esd_usb_get_berr_counter(const struct net_device *netdev, > struct can_berr_counter *bec) > { > @@ -1023,16 +1223,32 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index) > CAN_CTRLMODE_CC_LEN8_DLC | > CAN_CTRLMODE_BERR_REPORTING; > > - if (le16_to_cpu(dev->udev->descriptor.idProduct) == > - USB_CANUSBM_PRODUCT_ID) > + switch (le16_to_cpu(dev->udev->descriptor.idProduct)) { Instead of doing a switch on idProduct, you can use the driver_info field from struct usb_device_id to store the device quirks. You can pass either a pointer or some flags into driver_info. Examples: https://elixir.bootlin.com/linux/v6.2/source/drivers/net/can/usb/peak_usb/pcan_usb_core.c#L30 https://elixir.bootlin.com/linux/v6.2/source/drivers/net/can/usb/etas_es58x/es58x_core.c#L37 > + case USB_CANUSB3_PRODUCT_ID: > + priv->can.clock.freq = ESD_USB3_CAN_CLOCK; > + priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; > + priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD; > + priv->can.bittiming_const = &esd_usb3_bittiming_const; > + priv->can.data_bittiming_const = &esd_usb3_data_bittiming_const; > + priv->can.do_set_bittiming = esd_usb3_set_bittiming; > + priv->can.do_set_data_bittiming = esd_usb3_set_bittiming; > + break; > + > + case USB_CANUSBM_PRODUCT_ID: > priv->can.clock.freq = ESD_USBM_CAN_CLOCK; > - else { > + priv->can.bittiming_const = &esd_usb2_bittiming_const; > + priv->can.do_set_bittiming = esd_usb2_set_bittiming; > + break; > + > + case USB_CANUSB2_PRODUCT_ID: > + default: > priv->can.clock.freq = ESD_USB2_CAN_CLOCK; > priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; > + priv->can.bittiming_const = &esd_usb2_bittiming_const; > + priv->can.do_set_bittiming = esd_usb2_set_bittiming; > + break; > } > > - priv->can.bittiming_const = &esd_usb2_bittiming_const; > - priv->can.do_set_bittiming = esd_usb2_set_bittiming; > priv->can.do_set_mode = esd_usb_set_mode; > priv->can.do_get_berr_counter = esd_usb_get_berr_counter; > > -- > 2.25.1 >
On Sun, 2023-05-07 at 18:58 +0900, Vincent MAILHOL wrote: > Hi Frank, > > Thank you for your patch. Here is my first batch of comments. Hi Vincent, thanks for your detailed comments. See my answers below your comments ... Regards, Frank > Some comments also apply to the existing code. So you may want to > address those in separate clean-up patches first. > > On Fri. 5 May 2023 at 01:16, Frank Jungclaus <frank.jungclaus@esd.eu> wrote: > > Add support for esd CAN-USB/3 and CAN FD to esd_usb. > > > > Signed-off-by: Frank Jungclaus <frank.jungclaus@esd.eu> > > --- > > drivers/net/can/usb/esd_usb.c | 282 ++++++++++++++++++++++++++++++---- > > 1 file changed, 249 insertions(+), 33 deletions(-) > > > > diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c > > index e24fa48b9b42..48cf5e88d216 100644 > > --- a/drivers/net/can/usb/esd_usb.c > > +++ b/drivers/net/can/usb/esd_usb.c > > @@ -1,6 +1,6 @@ > > // SPDX-License-Identifier: GPL-2.0-only > > /* > > - * CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro > > + * CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro > > * > > * Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs <socketcan@esd.eu> > > * Copyright (C) 2022-2023 esd electronics gmbh, Frank Jungclaus <frank.jungclaus@esd.eu> > > @@ -18,17 +18,19 @@ > > > > MODULE_AUTHOR("Matthias Fuchs <socketcan@esd.eu>"); > > MODULE_AUTHOR("Frank Jungclaus <frank.jungclaus@esd.eu>"); > > -MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro interfaces"); > > +MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro interfaces"); > > MODULE_LICENSE("GPL v2"); > > > > /* USB vendor and product ID */ > > #define USB_ESDGMBH_VENDOR_ID 0x0ab4 > > #define USB_CANUSB2_PRODUCT_ID 0x0010 > > #define USB_CANUSBM_PRODUCT_ID 0x0011 > > +#define USB_CANUSB3_PRODUCT_ID 0x0014 > > > > /* CAN controller clock frequencies */ > > #define ESD_USB2_CAN_CLOCK 60000000 > > #define ESD_USBM_CAN_CLOCK 36000000 > > +#define ESD_USB3_CAN_CLOCK 80000000 > > Nitpick: consider using the unit suffixes from linux/units.h: > > #define ESD_USB3_CAN_CLOCK (80 * MEGA) Ok ... > > > /* Maximum number of CAN nets */ > > #define ESD_USB_MAX_NETS 2 > > @@ -43,6 +45,9 @@ MODULE_LICENSE("GPL v2"); > > > > /* esd CAN message flags - dlc field */ > > #define ESD_DLC_RTR 0x10 > > +#define ESD_DLC_NO_BRS 0x10 > > +#define ESD_DLC_ESI 0x20 > > +#define ESD_DLC_FD 0x80 > > Use the BIT() macro: Ok ... > #define ESD_DLC_NO_BRS BIT(4) > #define ESD_DLC_ESI BIT(5) > #define ESD_DLC_FD BIT(7) > > Also, if this is specific to the ESD_USB3 then add it in the prefix. No, this is not specific to esd CAN-USB/3. Those are generally applicable bits within the len element of an esd CAN (FD) message. See https://esd.eu/fileadmin/esd/docs/manuals/NTCAN_Part1_Function_API_Manual_en_56.pdf 6.2.3 CMSG and 6.2.5 CMSG_X Maybe I should rename the PREFIX ESD_DLC_ to ESD_LEN_ or ESD_USB_LEN_? DLC might by misleading here. > > > /* esd CAN message flags - id field */ > > #define ESD_EXTID 0x20000000 > > @@ -72,6 +77,28 @@ MODULE_LICENSE("GPL v2"); > > #define ESD_USB2_BRP_INC 1 > > #define ESD_USB2_3_SAMPLES 0x00800000 > > > > +/* Bit timing CAN-USB/3 */ > > +#define ESD_USB3_TSEG1_MIN 1 > > +#define ESD_USB3_TSEG1_MAX 256 > > +#define ESD_USB3_TSEG2_MIN 1 > > +#define ESD_USB3_TSEG2_MAX 128 > > +#define ESD_USB3_SJW_MAX 128 > > +#define ESD_USB3_BRP_MIN 1 > > +#define ESD_USB3_BRP_MAX 1024 > > +#define ESD_USB3_BRP_INC 1 > > +/* Bit timing CAN-USB/3, data phase */ > > +#define ESD_USB3_DATA_TSEG1_MIN 1 > > +#define ESD_USB3_DATA_TSEG1_MAX 32 > > +#define ESD_USB3_DATA_TSEG2_MIN 1 > > +#define ESD_USB3_DATA_TSEG2_MAX 16 > > +#define ESD_USB3_DATA_SJW_MAX 8 > > +#define ESD_USB3_DATA_BRP_MIN 1 > > +#define ESD_USB3_DATA_BRP_MAX 32 > > +#define ESD_USB3_DATA_BRP_INC 1 > > There is no clear benefit to define macros for some initializers of a > const struct. > > Doing as below has zero ambiguity: > > static const struct can_bittiming_const esd_usb3_bittiming_const = { > .name = "esd_usb3", > .tseg1_min = 1, > .tseg1_max = 256, > .tseg2_min = 1, > .tseg2_max = 128, > .sjw_max = 128, > .brp_min = 1, > .brp_max = 1024, > .brp_inc = 1, > }; I indeed thought about the way you proposed. But I decided against this, because I wanted to to this the same way as it is already done for the esd_usb2. Additionally esd_usb2_set_bittiming() as well as esd_usb3_set_bittiming() is doing some math by means of this macros! The terms there will become much more lengthy with e.g using can_bittiming_const esd_usb3_data_bittiming_const.tseg1_max instead of the macro ESD_USB3_DATA_TSEG1_MAX. > > > +/* Transmitter Delay Compensation */ > > +#define ESD_TDC_MODE_AUTO 0 > > + > > /* esd IDADD message */ > > #define ESD_ID_ENABLE 0x80 > > #define ESD_MAX_ID_SEGMENT 64 > > @@ -95,6 +122,21 @@ MODULE_LICENSE("GPL v2"); > > #define MAX_RX_URBS 4 > > #define MAX_TX_URBS 16 /* must be power of 2 */ > > > > +/* Modes for NTCAN_BAUDRATE_X */ > > +#define ESD_BAUDRATE_MODE_DISABLE 0 /* remove from bus */ > > +#define ESD_BAUDRATE_MODE_INDEX 1 /* ESD (CiA) bit rate idx */ > > +#define ESD_BAUDRATE_MODE_BTR_CTRL 2 /* BTR values (Controller)*/ > > +#define ESD_BAUDRATE_MODE_BTR_CANONICAL 3 /* BTR values (Canonical) */ > > +#define ESD_BAUDRATE_MODE_NUM 4 /* numerical bit rate */ > > +#define ESD_BAUDRATE_MODE_AUTOBAUD 5 /* autobaud */ > > + > > +/* Flags for NTCAN_BAUDRATE_X */ > > +#define ESD_BAUDRATE_FLAG_FD 0x0001 /* enable CAN FD Mode */ > > +#define ESD_BAUDRATE_FLAG_LOM 0x0002 /* enable Listen Only mode */ > > +#define ESD_BAUDRATE_FLAG_STM 0x0004 /* enable Self test mode */ > > +#define ESD_BAUDRATE_FLAG_TRS 0x0008 /* enable Triple Sampling */ > > +#define ESD_BAUDRATE_FLAG_TXP 0x0010 /* enable Transmit Pause */ > > + > > struct header_msg { > > u8 len; /* len is always the total message length in 32bit words */ > > u8 cmd; > > @@ -129,6 +171,7 @@ struct rx_msg { > > __le32 id; /* upper 3 bits contain flags */ > > union { > > u8 data[8]; > > + u8 data_fd[64]; > > struct { > > u8 status; /* CAN Controller Status */ > > u8 ecc; /* Error Capture Register */ > > @@ -144,8 +187,11 @@ struct tx_msg { > > u8 net; > > u8 dlc; > > u32 hnd; /* opaque handle, not used by device */ > > - __le32 id; /* upper 3 bits contain flags */ > > - u8 data[8]; > > + __le32 id; /* upper 3 bits contain flags */ > > + union { > > + u8 data[8]; > > + u8 data_fd[64]; > > Nitpick, use the macro: > > u8 data[CAN_MAX_DLEN]; > u8 data_fd[CANFD_MAX_DLEN]; Ok, good hint ... > > > + }; > > }; > > > > struct tx_done_msg { > > @@ -165,12 +211,37 @@ struct id_filter_msg { > > __le32 mask[ESD_MAX_ID_SEGMENT + 1]; > > }; > > > > +struct baudrate_x_cfg { > > + __le16 brp; /* bit rate pre-scaler */ > > + __le16 tseg1; /* TSEG1 register */ > > + __le16 tseg2; /* TSEG2 register */ > > + __le16 sjw; /* SJW register */ > > +}; > > + > > +struct tdc_cfg { > > Please prefix all the structures with the device name. e.g. > > struct esd_usb3_tdc_cfg { I'll change this ... > > > + u8 tdc_mode; /* transmitter Delay Compensation mode */ > > + u8 ssp_offset; /* secondary Sample Point offset in mtq */ > > + s8 ssp_shift; /* secondary Sample Point shift in mtq */ > > + u8 tdc_filter; /* Transmitter Delay Compensation */ > > +}; > > + > > +struct baudrate_x { > > The x in baudrate_x and baudrate_x_cfg is confusing me. Is it meant to > signify that the structure applies to both nominal and data baudrate? > In that case, just put a comment and remove the x from the name. I'd like to leave the _x in BAUDRATE_X, because this is the way it is named in the reference implementation in the esd NTCAN API. For details see https://esd.eu/fileadmin/esd/docs/manuals/NTCAN_Part1_Function_API_Manual_en_56.pdf 6.2.15 NTCAN_BAUDRATE_X But it should be fine to remove the _x for the arb and data elements. > > > + __le16 mode; /* mode word */ > > + __le16 flags; /* control flags */ > > + struct tdc_cfg tdc; /* TDC configuration */ > > + struct baudrate_x_cfg arb; /* bit rate during arbitration phase */ > > /* nominal bit rate */ > > The comment is incorrect. CAN-FD may use the nominal bitrate for the > data phase if the bit rate switch (BRS) is not set. > > + struct baudrate_x_cfg data; /* bit rate during data phase */ > > /* data bit rate */ > > Please adjust the field names accordingly. Ok, I'll change the comments + field names to nom(inal) and data > > > +}; > > + > > struct set_baudrate_msg { > > u8 len; > > u8 cmd; > > u8 net; > > u8 rsvd; > > - __le32 baud; > > + union { > > + __le32 baud; > > + struct baudrate_x baud_x; > > + }; > > }; > > > > /* Main message type used between library and application */ > > @@ -188,6 +259,7 @@ union __packed esd_usb_msg { > > static struct usb_device_id esd_usb_table[] = { > > {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)}, > > {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)}, > > + {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB3_PRODUCT_ID)}, > > {} > > }; > > MODULE_DEVICE_TABLE(usb, esd_usb_table); > > @@ -326,11 +398,13 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv, > > static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, > > union esd_usb_msg *msg) > > { > > + bool is_canfd = msg->rx.dlc & ESD_DLC_FD ? true : false; > > This is redundant. Just this is enough: > > bool is_canfd = msg->rx.dlc & ESD_DLC_FD; > > This variable being used only twice, you may want to consider not > declaring it and simply doing directly: I'll change to "doing this directly". Initially, while starting to rework esd_usb_rx_can_msg(), I assumed I'll need to check for is_canfd much more frequently. But obviously, as you stated, it's only used twice. > > if (msg->rx.dlc & ESD_DLC_FD) > > > struct net_device_stats *stats = &priv->netdev->stats; > > struct can_frame *cf; > > + struct canfd_frame *cfd; > > struct sk_buff *skb; > > - int i; > > u32 id; > > + u8 len; > > > > if (!netif_device_present(priv->netdev)) > > return; > > @@ -340,27 +414,42 @@ static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, > > if (id & ESD_EVENT) { > > esd_usb_rx_event(priv, msg); > > } else { > > - skb = alloc_can_skb(priv->netdev, &cf); > > + if (is_canfd) { > > + skb = alloc_canfd_skb(priv->netdev, &cfd); > > + } else { > > + skb = alloc_can_skb(priv->netdev, &cf); > > + cfd = (struct canfd_frame *)cf; > > + } > > + > > if (skb == NULL) { > > stats->rx_dropped++; > > return; > > } > > > > - cf->can_id = id & ESD_IDMASK; > > - can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR, > > - priv->can.ctrlmode); > > - > > - if (id & ESD_EXTID) > > - cf->can_id |= CAN_EFF_FLAG; > > + cfd->can_id = id & ESD_IDMASK; > > > > - if (msg->rx.dlc & ESD_DLC_RTR) { > > - cf->can_id |= CAN_RTR_FLAG; > > + if (is_canfd) { > > + /* masking by 0x0F is already done within can_fd_dlc2len() */ > > + cfd->len = can_fd_dlc2len(msg->rx.dlc); > > + len = cfd->len; > > + if ((msg->rx.dlc & ESD_DLC_NO_BRS) == 0) > > + cfd->flags |= CANFD_BRS; > > + if (msg->rx.dlc & ESD_DLC_ESI) > > + cfd->flags |= CANFD_ESI; > > } else { > > - for (i = 0; i < cf->len; i++) > > - cf->data[i] = msg->rx.data[i]; > > - > > - stats->rx_bytes += cf->len; > > + can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR, priv->can.ctrlmode); > > + len = cf->len; > > + if (msg->rx.dlc & ESD_DLC_RTR) { > > + cf->can_id |= CAN_RTR_FLAG; > > + len = 0; > > + } > > } > > + > > + if (id & ESD_EXTID) > > + cfd->can_id |= CAN_EFF_FLAG; > > + > > + memcpy(cfd->data, msg->rx.data_fd, len); > > + stats->rx_bytes += len; > > stats->rx_packets++; > > > > netif_rx(skb); > > @@ -735,7 +824,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, > > struct esd_usb *dev = priv->usb; > > struct esd_tx_urb_context *context = NULL; > > struct net_device_stats *stats = &netdev->stats; > > - struct can_frame *cf = (struct can_frame *)skb->data; > > + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; > > union esd_usb_msg *msg; > > struct urb *urb; > > u8 *buf; > > @@ -768,19 +857,28 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, > > msg->hdr.len = 3; /* minimal length */ > > msg->hdr.cmd = CMD_CAN_TX; > > msg->tx.net = priv->index; > > - msg->tx.dlc = can_get_cc_dlc(cf, priv->can.ctrlmode); > > - msg->tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK); > > > > - if (cf->can_id & CAN_RTR_FLAG) > > - msg->tx.dlc |= ESD_DLC_RTR; > > + if (can_is_canfd_skb(skb)) { > > + msg->tx.dlc = can_fd_len2dlc(cfd->len); > > + msg->tx.dlc |= ESD_DLC_FD; > > + > > + if ((cfd->flags & CANFD_BRS) == 0) > > + msg->tx.dlc |= ESD_DLC_NO_BRS; > > + } else { > > + msg->tx.dlc = can_get_cc_dlc((struct can_frame *)cfd, priv->can.ctrlmode); > > + > > + if (cfd->can_id & CAN_RTR_FLAG) > > + msg->tx.dlc |= ESD_DLC_RTR; > > + } > > > > - if (cf->can_id & CAN_EFF_FLAG) > > + msg->tx.id = cpu_to_le32(cfd->can_id & CAN_ERR_MASK); > > + > > + if (cfd->can_id & CAN_EFF_FLAG) > > msg->tx.id |= cpu_to_le32(ESD_EXTID); > > > > - for (i = 0; i < cf->len; i++) > > - msg->tx.data[i] = cf->data[i]; > > + memcpy(msg->tx.data_fd, cfd->data, cfd->len); > > > > - msg->hdr.len += (cf->len + 3) >> 2; > > + msg->hdr.len += (cfd->len + 3) >> 2; > > I do not get the logic. > > Assuming cfd->len is 8. Then > > hdr.len += (8 + 3) >> 2 > hdr.len += 2 > > And because hdr.len is initially 3, hdr.len becomes 5. Right? Shouldn't it be 8? It might be a little confusing, but I think it's fine. hdr.len is given in units of longwords (4 bytes each)! Therefore we have 12 bytes (the initial 3 longwords) for struct tx_msg before tx_msg.data[]. Than (8 + 3)/4=2 gives us 2 additional longwords for the 8 data bytes. So that 3+2=5 (equal to 20 bytes) should be ok. > > > for (i = 0; i < MAX_TX_URBS; i++) { > > if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { > > @@ -966,6 +1064,108 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) > > return err; > > } > > > > +static const struct can_bittiming_const esd_usb3_bittiming_const = { > > + .name = "esd_usb3", > > + .tseg1_min = ESD_USB3_TSEG1_MIN, > > + .tseg1_max = ESD_USB3_TSEG1_MAX, > > + .tseg2_min = ESD_USB3_TSEG2_MIN, > > + .tseg2_max = ESD_USB3_TSEG2_MAX, > > + .sjw_max = ESD_USB3_SJW_MAX, > > + .brp_min = ESD_USB3_BRP_MIN, > > + .brp_max = ESD_USB3_BRP_MAX, > > + .brp_inc = ESD_USB3_BRP_INC, > > +}; > > + > > +static const struct can_bittiming_const esd_usb3_data_bittiming_const = { > > + .name = "esd_usb3", > > + .tseg1_min = ESD_USB3_DATA_TSEG1_MIN, > > + .tseg1_max = ESD_USB3_DATA_TSEG1_MAX, > > + .tseg2_min = ESD_USB3_DATA_TSEG2_MIN, > > + .tseg2_max = ESD_USB3_DATA_TSEG2_MAX, > > + .sjw_max = ESD_USB3_DATA_SJW_MAX, > > + .brp_min = ESD_USB3_DATA_BRP_MIN, > > + .brp_max = ESD_USB3_DATA_BRP_MAX, > > + .brp_inc = ESD_USB3_DATA_BRP_INC, > > +}; > > + > > +static int esd_usb3_set_bittiming(struct net_device *netdev) > > +{ > > + struct esd_usb_net_priv *priv = netdev_priv(netdev); > > + struct can_bittiming *bt = &priv->can.bittiming; > > + struct can_bittiming *d_bt = &priv->can.data_bittiming; > > + union esd_usb_msg *msg; > > + int err; > > + u16 mode; > > + u16 flags = 0; > > + u16 brp, tseg1, tseg2, sjw; > > + u16 d_brp, d_tseg1, d_tseg2, d_sjw; > > + > > + msg = kmalloc(sizeof(*msg), GFP_KERNEL); > > + if (!msg) > > + return -ENOMEM; > > + > > + /* Canonical is the most reasonable mode for SocketCAN on CAN-USB/3 ... */ > > + mode = ESD_BAUDRATE_MODE_BTR_CANONICAL; > > + > > + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) > > + flags |= ESD_BAUDRATE_FLAG_LOM; > > + > > + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) > > + flags |= ESD_BAUDRATE_FLAG_TRS; > > + > > + brp = bt->brp & (ESD_USB3_BRP_MAX - 1); > > + sjw = bt->sjw & (ESD_USB3_SJW_MAX - 1); > > + tseg1 = (bt->prop_seg + bt->phase_seg1) & (ESD_USB3_TSEG1_MAX - 1); > > + tseg2 = bt->phase_seg2 & (ESD_USB3_TSEG2_MAX - 1); > > I am not convinced by the use of these intermediate variables brp, > sjw, tseg1 and tseg2. I think you can directly assign them to baud_x. I chose this way to prevent lengthy terms on the right side of the following assignments. Also those variables are (still) used in the netdev_info() below. > > > + msg->setbaud.baud_x.arb.brp = cpu_to_le16(brp); > > + msg->setbaud.baud_x.arb.sjw = cpu_to_le16(sjw); > > + msg->setbaud.baud_x.arb.tseg1 = cpu_to_le16(tseg1); > > + msg->setbaud.baud_x.arb.tseg2 = cpu_to_le16(tseg2); > > You may want to declare a local variable > > struct baudrate_x *baud_x = &msg->setbaud.baud_x; > > so that you do not have to do msg->setbaud.baud_x each time. ... ok, fine, with this I could gain some space for lengthy terms on the right side ;) > > > + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { > > + d_brp = d_bt->brp & (ESD_USB3_DATA_BRP_MAX - 1); > > + d_sjw = d_bt->sjw & (ESD_USB3_DATA_SJW_MAX - 1); > > + d_tseg1 = (d_bt->prop_seg + d_bt->phase_seg1) & (ESD_USB3_DATA_TSEG1_MAX - 1); > > + d_tseg2 = d_bt->phase_seg2 & (ESD_USB3_DATA_TSEG2_MAX - 1); > > + flags |= ESD_BAUDRATE_FLAG_FD; > > + } else { > > + d_brp = 0; > > + d_sjw = 0; > > + d_tseg1 = 0; > > + d_tseg2 = 0; > > + } > > + > > + msg->setbaud.baud_x.data.brp = cpu_to_le16(d_brp); > > + msg->setbaud.baud_x.data.sjw = cpu_to_le16(d_sjw); > > + msg->setbaud.baud_x.data.tseg1 = cpu_to_le16(d_tseg1); > > + msg->setbaud.baud_x.data.tseg2 = cpu_to_le16(d_tseg2); > > + msg->setbaud.baud_x.mode = cpu_to_le16(mode); > > + msg->setbaud.baud_x.flags = cpu_to_le16(flags); > > + msg->setbaud.baud_x.tdc.tdc_mode = ESD_TDC_MODE_AUTO; > > + msg->setbaud.baud_x.tdc.ssp_offset = 0; > > + msg->setbaud.baud_x.tdc.ssp_shift = 0; > > + msg->setbaud.baud_x.tdc.tdc_filter = 0; > > It seems that your device supports TDC. What is the reason to not configure it? Yes, TDC is supported. The intention was to hand this in by means of a follow-up patch and until than live with TDC on auto mode. I'm already far beyond any time schedule for putting CAN-USB/3 into Linux ;) > Please have a look at struct can_tdc: > > https://elixir.bootlin.com/linux/v6.2/source/include/linux/can/bittiming.h#L21 > > Please refer to this patch if you want an example of how to use TDC: > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1010a8fa9608 > Thanks for that pointers! I'll check ... > > + msg->hdr.len = 7; > > What is this magic number? If possible, replace it with a sizeof(). I think each setting of msg->hdr.len in this driver is somewhat hard- coded ;) Maybe this has been caused by the ancient documentation for our can-usb protocol / firmware, that states things like "set len to 2 for set_baudrate" or "set len to 7 (24 bytes) for set_baudrate_x ;) > > It seems that this relates to the size of struct set_baudrate_msg, but > that structure is 8 bytes. Is the last byte of struct set_baudrate_msg > really used? If not, reflect this in the declaration of the structure. sizeof(set_baudrate_msg) should be 4 * u8 + sizeof(baudrate_x). sizeof(baudrate_x) should be 2 * le16 + 4 * u8 + 2 * (4 * le16) So I'll count 4 * 1 + 2 * 2 + 4 * 1 + 2 * (4 * 2) = 28 28 >> 2 gives us 7. So 7 is fine here. But I agree that a sizeof(struct baudrate_x) would be much clearer. I'll change this one to sizeof() and leave all other "msg.hdr.len =" expression as they are, until a follow-up cleanup. > > > + msg->hdr.cmd = CMD_SETBAUD; > > + > > + msg->setbaud.net = priv->index; > > + msg->setbaud.rsvd = 0; > > + > > + netdev_info(netdev, > > + "ctrlmode=%#x/%#x, esd-net=%u, esd-mode=%#x, esd-flg=%#x, arb: brp=%u, ts1=%u, ts2=%u, sjw=%u, data: dbrp=%u, dts1=%u, dts2=%u dsjw=%u\n", > > + priv->can.ctrlmode, priv->can.ctrlmode_supported, > > + priv->index, mode, flags, > > + brp, tseg1, tseg2, sjw, > > + d_brp, d_tseg1, d_tseg2, d_sjw); > > Remove this debug message. The bittiming information can be retrieved > with the ip tool. > > ip --details link show canX Yes, I know. But my intention was to exactly and directly see the individual values passed to the USB set baudrate command without using wireshark to sniff the USB, if anybody complains about problems with the bitrate. This netdev_info is similar to the "netdev_info(netdev, "setting BTR=%#x\n", canbtr);" for CAN-USB/2. So from my point of view this is an informational message too, and not a debug message. > > > + err = esd_usb_send_msg(priv->usb, msg); > > + > > + kfree(msg); > > esd_usb_send_msg() uses usb_bulk_msg() which does a synchronous call. > It would be great to go asynchronous and use usb_submit_urb() so that > you minimize the time spent in the driver. > > I know that esd_usb2_set_bittiming() also uses the synchronous call, > so I am fine to have it as-is for this patch but for the future, it > would be great to consider refactoring this. ACK. I'll put this on the todo list for a follow-up patch. > > > + return err; > > +} > > + > > static int esd_usb_get_berr_counter(const struct net_device *netdev, > > struct can_berr_counter *bec) > > { > > @@ -1023,16 +1223,32 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index) > > CAN_CTRLMODE_CC_LEN8_DLC | > > CAN_CTRLMODE_BERR_REPORTING; > > > > - if (le16_to_cpu(dev->udev->descriptor.idProduct) == > > - USB_CANUSBM_PRODUCT_ID) > > + switch (le16_to_cpu(dev->udev->descriptor.idProduct)) { > > Instead of doing a switch on idProduct, you can use the driver_info > field from struct usb_device_id to store the device quirks. > > You can pass either a pointer or some flags into driver_info. Examples: > > https://elixir.bootlin.com/linux/v6.2/source/drivers/net/can/usb/peak_usb/pcan_usb_core.c#L30 > https://elixir.bootlin.com/linux/v6.2/source/drivers/net/can/usb/etas_es58x/es58x_core.c#L37 > Yes using flags within .driver_info like es58x_core.c does it, seems to be a good idea here. But I'd like to leave this for a follow-up patch, too. > > + case USB_CANUSB3_PRODUCT_ID: > > + priv->can.clock.freq = ESD_USB3_CAN_CLOCK; > > + priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; > > + priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD; > > + priv->can.bittiming_const = &esd_usb3_bittiming_const; > > + priv->can.data_bittiming_const = &esd_usb3_data_bittiming_const; > > + priv->can.do_set_bittiming = esd_usb3_set_bittiming; > > + priv->can.do_set_data_bittiming = esd_usb3_set_bittiming; > > + break; > > + > > + case USB_CANUSBM_PRODUCT_ID: > > priv->can.clock.freq = ESD_USBM_CAN_CLOCK; > > - else { > > + priv->can.bittiming_const = &esd_usb2_bittiming_const; > > + priv->can.do_set_bittiming = esd_usb2_set_bittiming; > > + break; > > + > > + case USB_CANUSB2_PRODUCT_ID: > > + default: > > priv->can.clock.freq = ESD_USB2_CAN_CLOCK; > > priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; > > + priv->can.bittiming_const = &esd_usb2_bittiming_const; > > + priv->can.do_set_bittiming = esd_usb2_set_bittiming; > > + break; > > } > > > > - priv->can.bittiming_const = &esd_usb2_bittiming_const; > > - priv->can.do_set_bittiming = esd_usb2_set_bittiming; > > priv->can.do_set_mode = esd_usb_set_mode; > > priv->can.do_get_berr_counter = esd_usb_get_berr_counter; > > > > -- > > 2.25.1 > >
Hi Frank, On Tue. 9 May 2023 at 03:52, Frank Jungclaus <Frank.Jungclaus@esd.eu> wrote: > On Sun, 2023-05-07 at 18:58 +0900, Vincent MAILHOL wrote: > > Hi Frank, > > > > Thank you for your patch. Here is my first batch of comments. > > Hi Vincent, thanks for your detailed comments. > See my answers below your comments ... > > Regards, Frank > > > Some comments also apply to the existing code. So you may want to > > address those in separate clean-up patches first. > > > > On Fri. 5 May 2023 at 01:16, Frank Jungclaus <frank.jungclaus@esd.eu> wrote: > > > Add support for esd CAN-USB/3 and CAN FD to esd_usb. > > > > > > Signed-off-by: Frank Jungclaus <frank.jungclaus@esd.eu> > > > --- > > > drivers/net/can/usb/esd_usb.c | 282 ++++++++++++++++++++++++++++++---- > > > 1 file changed, 249 insertions(+), 33 deletions(-) > > > > > > diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c > > > index e24fa48b9b42..48cf5e88d216 100644 > > > --- a/drivers/net/can/usb/esd_usb.c > > > +++ b/drivers/net/can/usb/esd_usb.c > > > @@ -1,6 +1,6 @@ > > > // SPDX-License-Identifier: GPL-2.0-only > > > /* > > > - * CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro > > > + * CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro > > > * > > > * Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs <socketcan@esd.eu> > > > * Copyright (C) 2022-2023 esd electronics gmbh, Frank Jungclaus <frank.jungclaus@esd.eu> > > > @@ -18,17 +18,19 @@ > > > > > > MODULE_AUTHOR("Matthias Fuchs <socketcan@esd.eu>"); > > > MODULE_AUTHOR("Frank Jungclaus <frank.jungclaus@esd.eu>"); > > > -MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro interfaces"); > > > +MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro interfaces"); > > > MODULE_LICENSE("GPL v2"); > > > > > > /* USB vendor and product ID */ > > > #define USB_ESDGMBH_VENDOR_ID 0x0ab4 > > > #define USB_CANUSB2_PRODUCT_ID 0x0010 > > > #define USB_CANUSBM_PRODUCT_ID 0x0011 > > > +#define USB_CANUSB3_PRODUCT_ID 0x0014 > > > > > > /* CAN controller clock frequencies */ > > > #define ESD_USB2_CAN_CLOCK 60000000 > > > #define ESD_USBM_CAN_CLOCK 36000000 > > > +#define ESD_USB3_CAN_CLOCK 80000000 > > > > Nitpick: consider using the unit suffixes from linux/units.h: > > > > #define ESD_USB3_CAN_CLOCK (80 * MEGA) > > Ok ... > > > > > > /* Maximum number of CAN nets */ > > > #define ESD_USB_MAX_NETS 2 > > > @@ -43,6 +45,9 @@ MODULE_LICENSE("GPL v2"); > > > > > > /* esd CAN message flags - dlc field */ > > > #define ESD_DLC_RTR 0x10 > > > +#define ESD_DLC_NO_BRS 0x10 > > > +#define ESD_DLC_ESI 0x20 > > > +#define ESD_DLC_FD 0x80 > > > > Use the BIT() macro: > > Ok ... > > > #define ESD_DLC_NO_BRS BIT(4) > > #define ESD_DLC_ESI BIT(5) > > #define ESD_DLC_FD BIT(7) > > > > Also, if this is specific to the ESD_USB3 then add it in the prefix. > > No, this is not specific to esd CAN-USB/3. Those are generally > applicable bits within the len element of an esd CAN (FD) message. > See > https://esd.eu/fileadmin/esd/docs/manuals/NTCAN_Part1_Function_API_Manual_en_56.pdf > 6.2.3 CMSG and 6.2.5 CMSG_X > > Maybe I should rename the PREFIX ESD_DLC_ to ESD_LEN_ or ESD_USB_LEN_? > DLC might by misleading here. ACK. Try to be consistent as much as possible. The ESD_USB_ prefix seems better. > > > > > /* esd CAN message flags - id field */ > > > #define ESD_EXTID 0x20000000 > > > @@ -72,6 +77,28 @@ MODULE_LICENSE("GPL v2"); > > > #define ESD_USB2_BRP_INC 1 > > > #define ESD_USB2_3_SAMPLES 0x00800000 > > > > > > +/* Bit timing CAN-USB/3 */ > > > +#define ESD_USB3_TSEG1_MIN 1 > > > +#define ESD_USB3_TSEG1_MAX 256 > > > +#define ESD_USB3_TSEG2_MIN 1 > > > +#define ESD_USB3_TSEG2_MAX 128 > > > +#define ESD_USB3_SJW_MAX 128 > > > +#define ESD_USB3_BRP_MIN 1 > > > +#define ESD_USB3_BRP_MAX 1024 > > > +#define ESD_USB3_BRP_INC 1 > > > +/* Bit timing CAN-USB/3, data phase */ > > > +#define ESD_USB3_DATA_TSEG1_MIN 1 > > > +#define ESD_USB3_DATA_TSEG1_MAX 32 > > > +#define ESD_USB3_DATA_TSEG2_MIN 1 > > > +#define ESD_USB3_DATA_TSEG2_MAX 16 > > > +#define ESD_USB3_DATA_SJW_MAX 8 > > > +#define ESD_USB3_DATA_BRP_MIN 1 > > > +#define ESD_USB3_DATA_BRP_MAX 32 > > > +#define ESD_USB3_DATA_BRP_INC 1 > > > > There is no clear benefit to define macros for some initializers of a > > const struct. > > > > Doing as below has zero ambiguity: > > > > static const struct can_bittiming_const esd_usb3_bittiming_const = { > > .name = "esd_usb3", > > .tseg1_min = 1, > > .tseg1_max = 256, > > .tseg2_min = 1, > > .tseg2_max = 128, > > .sjw_max = 128, > > .brp_min = 1, > > .brp_max = 1024, > > .brp_inc = 1, > > }; > > I indeed thought about the way you proposed. But I decided against > this, because I wanted to to this the same way as it is already done > for the esd_usb2. Additionally esd_usb2_set_bittiming() as well as > esd_usb3_set_bittiming() is doing some math by means of this macros! > The terms there will become much more lengthy with e.g > using can_bittiming_const esd_usb3_data_bittiming_const.tseg1_max > instead of the macro ESD_USB3_DATA_TSEG1_MAX. If your only concern is the column length of line code, then do: const struct can_bittiming_const *btc = priv->can.bittiming_const; const struct can_bittiming_const *dbtc = priv->can.data_bittiming_const; foo = btc->tseg1_max; This is even shorter than: foo = ESD_USB3_DATA_TSEG1_MAX; > > > +/* Transmitter Delay Compensation */ > > > +#define ESD_TDC_MODE_AUTO 0 > > > + > > > /* esd IDADD message */ > > > #define ESD_ID_ENABLE 0x80 > > > #define ESD_MAX_ID_SEGMENT 64 > > > @@ -95,6 +122,21 @@ MODULE_LICENSE("GPL v2"); > > > #define MAX_RX_URBS 4 > > > #define MAX_TX_URBS 16 /* must be power of 2 */ > > > > > > +/* Modes for NTCAN_BAUDRATE_X */ > > > +#define ESD_BAUDRATE_MODE_DISABLE 0 /* remove from bus */ > > > +#define ESD_BAUDRATE_MODE_INDEX 1 /* ESD (CiA) bit rate idx */ > > > +#define ESD_BAUDRATE_MODE_BTR_CTRL 2 /* BTR values (Controller)*/ > > > +#define ESD_BAUDRATE_MODE_BTR_CANONICAL 3 /* BTR values (Canonical) */ > > > +#define ESD_BAUDRATE_MODE_NUM 4 /* numerical bit rate */ > > > +#define ESD_BAUDRATE_MODE_AUTOBAUD 5 /* autobaud */ > > > + > > > +/* Flags for NTCAN_BAUDRATE_X */ > > > +#define ESD_BAUDRATE_FLAG_FD 0x0001 /* enable CAN FD Mode */ > > > +#define ESD_BAUDRATE_FLAG_LOM 0x0002 /* enable Listen Only mode */ > > > +#define ESD_BAUDRATE_FLAG_STM 0x0004 /* enable Self test mode */ > > > +#define ESD_BAUDRATE_FLAG_TRS 0x0008 /* enable Triple Sampling */ > > > +#define ESD_BAUDRATE_FLAG_TXP 0x0010 /* enable Transmit Pause */ > > > + > > > struct header_msg { > > > u8 len; /* len is always the total message length in 32bit words */ > > > u8 cmd; > > > @@ -129,6 +171,7 @@ struct rx_msg { > > > __le32 id; /* upper 3 bits contain flags */ > > > union { > > > u8 data[8]; > > > + u8 data_fd[64]; > > > struct { > > > u8 status; /* CAN Controller Status */ > > > u8 ecc; /* Error Capture Register */ > > > @@ -144,8 +187,11 @@ struct tx_msg { > > > u8 net; > > > u8 dlc; > > > u32 hnd; /* opaque handle, not used by device */ > > > - __le32 id; /* upper 3 bits contain flags */ > > > - u8 data[8]; > > > + __le32 id; /* upper 3 bits contain flags */ > > > + union { > > > + u8 data[8]; > > > + u8 data_fd[64]; > > > > Nitpick, use the macro: > > > > u8 data[CAN_MAX_DLEN]; > > u8 data_fd[CANFD_MAX_DLEN]; > > Ok, good hint ... > > > > > > + }; > > > }; > > > > > > struct tx_done_msg { > > > @@ -165,12 +211,37 @@ struct id_filter_msg { > > > __le32 mask[ESD_MAX_ID_SEGMENT + 1]; > > > }; > > > > > > +struct baudrate_x_cfg { > > > + __le16 brp; /* bit rate pre-scaler */ > > > + __le16 tseg1; /* TSEG1 register */ > > > + __le16 tseg2; /* TSEG2 register */ > > > + __le16 sjw; /* SJW register */ > > > +}; > > > + > > > +struct tdc_cfg { > > > > Please prefix all the structures with the device name. e.g. > > > > struct esd_usb3_tdc_cfg { > > I'll change this ... > > > > > > + u8 tdc_mode; /* transmitter Delay Compensation mode */ > > > + u8 ssp_offset; /* secondary Sample Point offset in mtq */ > > > + s8 ssp_shift; /* secondary Sample Point shift in mtq */ > > > + u8 tdc_filter; /* Transmitter Delay Compensation */ > > > +}; > > > + > > > +struct baudrate_x { > > > > The x in baudrate_x and baudrate_x_cfg is confusing me. Is it meant to > > signify that the structure applies to both nominal and data baudrate? > > In that case, just put a comment and remove the x from the name. > > I'd like to leave the _x in BAUDRATE_X, because this is the way it is > named in the reference implementation in the esd NTCAN API. For details > see > https://esd.eu/fileadmin/esd/docs/manuals/NTCAN_Part1_Function_API_Manual_en_56.pdf > 6.2.15 NTCAN_BAUDRATE_X OK. Then add a comment and point to the manual definition. > But it should be fine to remove the _x for the arb and data elements. ACK. > > > > > + __le16 mode; /* mode word */ > > > + __le16 flags; /* control flags */ > > > + struct tdc_cfg tdc; /* TDC configuration */ > > > + struct baudrate_x_cfg arb; /* bit rate during arbitration phase */ > > > > /* nominal bit rate */ > > > > The comment is incorrect. CAN-FD may use the nominal bitrate for the > > data phase if the bit rate switch (BRS) is not set. > > > + struct baudrate_x_cfg data; /* bit rate during data phase */ > > > > /* data bit rate */ > > > > Please adjust the field names accordingly. > > Ok, I'll change the comments + field names to nom(inal) and data ACK. > > > +}; > > > + > > > struct set_baudrate_msg { > > > u8 len; > > > u8 cmd; > > > u8 net; > > > u8 rsvd; > > > - __le32 baud; > > > + union { > > > + __le32 baud; > > > + struct baudrate_x baud_x; > > > + }; > > > }; > > > > > > /* Main message type used between library and application */ > > > @@ -188,6 +259,7 @@ union __packed esd_usb_msg { > > > static struct usb_device_id esd_usb_table[] = { > > > {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)}, > > > {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)}, > > > + {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB3_PRODUCT_ID)}, > > > {} > > > }; > > > MODULE_DEVICE_TABLE(usb, esd_usb_table); > > > @@ -326,11 +398,13 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv, > > > static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, > > > union esd_usb_msg *msg) > > > { > > > + bool is_canfd = msg->rx.dlc & ESD_DLC_FD ? true : false; > > > > This is redundant. Just this is enough: > > > > bool is_canfd = msg->rx.dlc & ESD_DLC_FD; > > > > This variable being used only twice, you may want to consider not > > declaring it and simply doing directly: > > I'll change to "doing this directly". Initially, while starting to > rework esd_usb_rx_can_msg(), I assumed I'll need to check for is_canfd > much more frequently. But obviously, as you stated, it's only used > twice. ACK. > > > > if (msg->rx.dlc & ESD_DLC_FD) > > > > > struct net_device_stats *stats = &priv->netdev->stats; > > > struct can_frame *cf; > > > + struct canfd_frame *cfd; > > > struct sk_buff *skb; > > > - int i; > > > u32 id; > > > + u8 len; > > > > > > if (!netif_device_present(priv->netdev)) > > > return; > > > @@ -340,27 +414,42 @@ static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, > > > if (id & ESD_EVENT) { > > > esd_usb_rx_event(priv, msg); > > > } else { > > > - skb = alloc_can_skb(priv->netdev, &cf); > > > + if (is_canfd) { > > > + skb = alloc_canfd_skb(priv->netdev, &cfd); > > > + } else { > > > + skb = alloc_can_skb(priv->netdev, &cf); > > > + cfd = (struct canfd_frame *)cf; > > > + } > > > + > > > if (skb == NULL) { > > > stats->rx_dropped++; > > > return; > > > } > > > > > > - cf->can_id = id & ESD_IDMASK; > > > - can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR, > > > - priv->can.ctrlmode); > > > - > > > - if (id & ESD_EXTID) > > > - cf->can_id |= CAN_EFF_FLAG; > > > + cfd->can_id = id & ESD_IDMASK; > > > > > > - if (msg->rx.dlc & ESD_DLC_RTR) { > > > - cf->can_id |= CAN_RTR_FLAG; > > > + if (is_canfd) { > > > + /* masking by 0x0F is already done within can_fd_dlc2len() */ > > > + cfd->len = can_fd_dlc2len(msg->rx.dlc); > > > + len = cfd->len; > > > + if ((msg->rx.dlc & ESD_DLC_NO_BRS) == 0) > > > + cfd->flags |= CANFD_BRS; > > > + if (msg->rx.dlc & ESD_DLC_ESI) > > > + cfd->flags |= CANFD_ESI; > > > } else { > > > - for (i = 0; i < cf->len; i++) > > > - cf->data[i] = msg->rx.data[i]; > > > - > > > - stats->rx_bytes += cf->len; > > > + can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR, priv->can.ctrlmode); > > > + len = cf->len; > > > + if (msg->rx.dlc & ESD_DLC_RTR) { > > > + cf->can_id |= CAN_RTR_FLAG; > > > + len = 0; > > > + } > > > } > > > + > > > + if (id & ESD_EXTID) > > > + cfd->can_id |= CAN_EFF_FLAG; > > > + > > > + memcpy(cfd->data, msg->rx.data_fd, len); > > > + stats->rx_bytes += len; > > > stats->rx_packets++; > > > > > > netif_rx(skb); > > > @@ -735,7 +824,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, > > > struct esd_usb *dev = priv->usb; > > > struct esd_tx_urb_context *context = NULL; > > > struct net_device_stats *stats = &netdev->stats; > > > - struct can_frame *cf = (struct can_frame *)skb->data; > > > + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; > > > union esd_usb_msg *msg; > > > struct urb *urb; > > > u8 *buf; > > > @@ -768,19 +857,28 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, > > > msg->hdr.len = 3; /* minimal length */ > > > msg->hdr.cmd = CMD_CAN_TX; > > > msg->tx.net = priv->index; > > > - msg->tx.dlc = can_get_cc_dlc(cf, priv->can.ctrlmode); > > > - msg->tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK); > > > > > > - if (cf->can_id & CAN_RTR_FLAG) > > > - msg->tx.dlc |= ESD_DLC_RTR; > > > + if (can_is_canfd_skb(skb)) { > > > + msg->tx.dlc = can_fd_len2dlc(cfd->len); > > > + msg->tx.dlc |= ESD_DLC_FD; > > > + > > > + if ((cfd->flags & CANFD_BRS) == 0) > > > + msg->tx.dlc |= ESD_DLC_NO_BRS; > > > + } else { > > > + msg->tx.dlc = can_get_cc_dlc((struct can_frame *)cfd, priv->can.ctrlmode); > > > + > > > + if (cfd->can_id & CAN_RTR_FLAG) > > > + msg->tx.dlc |= ESD_DLC_RTR; > > > + } > > > > > > - if (cf->can_id & CAN_EFF_FLAG) > > > + msg->tx.id = cpu_to_le32(cfd->can_id & CAN_ERR_MASK); > > > + > > > + if (cfd->can_id & CAN_EFF_FLAG) > > > msg->tx.id |= cpu_to_le32(ESD_EXTID); > > > > > > - for (i = 0; i < cf->len; i++) > > > - msg->tx.data[i] = cf->data[i]; > > > + memcpy(msg->tx.data_fd, cfd->data, cfd->len); > > > > > > - msg->hdr.len += (cf->len + 3) >> 2; > > > + msg->hdr.len += (cfd->len + 3) >> 2; > > > > I do not get the logic. > > > > Assuming cfd->len is 8. Then > > > > hdr.len += (8 + 3) >> 2 > > hdr.len += 2 > > > > And because hdr.len is initially 3, hdr.len becomes 5. Right? Shouldn't it be 8? > > It might be a little confusing, but I think it's fine. > hdr.len is given in units of longwords (4 bytes each)! Therefore we > have 12 bytes (the initial 3 longwords) for struct tx_msg before > tx_msg.data[]. > Than (8 + 3)/4=2 gives us 2 additional longwords for the 8 data bytes. > So that 3+2=5 (equal to 20 bytes) should be ok. OK. So you want to round up the length to the next sizeof(long) multiple, right? First, sizeof(long) being platform specific, you need to declare a macro to make your intent explicit. /* Size of a long int on esd devices */ #define USB_ESD_SIZEOF_LONG 4 Please test, but for what I understand, below line is an equivalent and a more readable way to achieve your goal: msg->hdr.len = DIV_ROUND_UP(cf->len, USB_ESD_SIZEOF_LONG); Also, add documentation to your structure to explain that hdr.len represents the length in long, not in bytes. > > > > > for (i = 0; i < MAX_TX_URBS; i++) { > > > if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { > > > @@ -966,6 +1064,108 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) > > > return err; > > > } > > > > > > +static const struct can_bittiming_const esd_usb3_bittiming_const = { > > > + .name = "esd_usb3", > > > + .tseg1_min = ESD_USB3_TSEG1_MIN, > > > + .tseg1_max = ESD_USB3_TSEG1_MAX, > > > + .tseg2_min = ESD_USB3_TSEG2_MIN, > > > + .tseg2_max = ESD_USB3_TSEG2_MAX, > > > + .sjw_max = ESD_USB3_SJW_MAX, > > > + .brp_min = ESD_USB3_BRP_MIN, > > > + .brp_max = ESD_USB3_BRP_MAX, > > > + .brp_inc = ESD_USB3_BRP_INC, > > > +}; > > > + > > > +static const struct can_bittiming_const esd_usb3_data_bittiming_const = { > > > + .name = "esd_usb3", > > > + .tseg1_min = ESD_USB3_DATA_TSEG1_MIN, > > > + .tseg1_max = ESD_USB3_DATA_TSEG1_MAX, > > > + .tseg2_min = ESD_USB3_DATA_TSEG2_MIN, > > > + .tseg2_max = ESD_USB3_DATA_TSEG2_MAX, > > > + .sjw_max = ESD_USB3_DATA_SJW_MAX, > > > + .brp_min = ESD_USB3_DATA_BRP_MIN, > > > + .brp_max = ESD_USB3_DATA_BRP_MAX, > > > + .brp_inc = ESD_USB3_DATA_BRP_INC, > > > +}; > > > + > > > +static int esd_usb3_set_bittiming(struct net_device *netdev) > > > +{ > > > + struct esd_usb_net_priv *priv = netdev_priv(netdev); > > > + struct can_bittiming *bt = &priv->can.bittiming; > > > + struct can_bittiming *d_bt = &priv->can.data_bittiming; > > > + union esd_usb_msg *msg; > > > + int err; > > > + u16 mode; > > > + u16 flags = 0; > > > + u16 brp, tseg1, tseg2, sjw; > > > + u16 d_brp, d_tseg1, d_tseg2, d_sjw; > > > + > > > + msg = kmalloc(sizeof(*msg), GFP_KERNEL); > > > + if (!msg) > > > + return -ENOMEM; > > > + > > > + /* Canonical is the most reasonable mode for SocketCAN on CAN-USB/3 ... */ > > > + mode = ESD_BAUDRATE_MODE_BTR_CANONICAL; > > > + > > > + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) > > > + flags |= ESD_BAUDRATE_FLAG_LOM; > > > + > > > + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) > > > + flags |= ESD_BAUDRATE_FLAG_TRS; > > > + > > > + brp = bt->brp & (ESD_USB3_BRP_MAX - 1); > > > + sjw = bt->sjw & (ESD_USB3_SJW_MAX - 1); > > > + tseg1 = (bt->prop_seg + bt->phase_seg1) & (ESD_USB3_TSEG1_MAX - 1); > > > + tseg2 = bt->phase_seg2 & (ESD_USB3_TSEG2_MAX - 1); > > > > I am not convinced by the use of these intermediate variables brp, > > sjw, tseg1 and tseg2. I think you can directly assign them to baud_x. > > I chose this way to prevent lengthy terms on the right side of the > following assignments. Also those variables are (still) used in the > netdev_info() below. > > > > > > + msg->setbaud.baud_x.arb.brp = cpu_to_le16(brp); > > > + msg->setbaud.baud_x.arb.sjw = cpu_to_le16(sjw); > > > + msg->setbaud.baud_x.arb.tseg1 = cpu_to_le16(tseg1); > > > + msg->setbaud.baud_x.arb.tseg2 = cpu_to_le16(tseg2); > > > > You may want to declare a local variable > > > > struct baudrate_x *baud_x = &msg->setbaud.baud_x; > > > > so that you do not have to do msg->setbaud.baud_x each time. > > ... ok, fine, with this I could gain some space for lengthy terms on > the right side ;) ACK. > > > > > + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { > > > + d_brp = d_bt->brp & (ESD_USB3_DATA_BRP_MAX - 1); > > > + d_sjw = d_bt->sjw & (ESD_USB3_DATA_SJW_MAX - 1); > > > + d_tseg1 = (d_bt->prop_seg + d_bt->phase_seg1) & (ESD_USB3_DATA_TSEG1_MAX - 1); > > > + d_tseg2 = d_bt->phase_seg2 & (ESD_USB3_DATA_TSEG2_MAX - 1); > > > + flags |= ESD_BAUDRATE_FLAG_FD; > > > + } else { > > > + d_brp = 0; > > > + d_sjw = 0; > > > + d_tseg1 = 0; > > > + d_tseg2 = 0; > > > + } > > > + > > > + msg->setbaud.baud_x.data.brp = cpu_to_le16(d_brp); > > > + msg->setbaud.baud_x.data.sjw = cpu_to_le16(d_sjw); > > > + msg->setbaud.baud_x.data.tseg1 = cpu_to_le16(d_tseg1); > > > + msg->setbaud.baud_x.data.tseg2 = cpu_to_le16(d_tseg2); > > > + msg->setbaud.baud_x.mode = cpu_to_le16(mode); > > > + msg->setbaud.baud_x.flags = cpu_to_le16(flags); > > > + msg->setbaud.baud_x.tdc.tdc_mode = ESD_TDC_MODE_AUTO; > > > + msg->setbaud.baud_x.tdc.ssp_offset = 0; > > > + msg->setbaud.baud_x.tdc.ssp_shift = 0; > > > + msg->setbaud.baud_x.tdc.tdc_filter = 0; > > > > It seems that your device supports TDC. What is the reason to not configure it? > Yes, TDC is supported. > The intention was to hand this in by means of a follow-up patch and > until than live with TDC on auto mode. I'm already far beyond any time > schedule for putting CAN-USB/3 into Linux ;) OK. Just add a message in the commit description that TDC is supported and planed to be implemented later. > > Please have a look at struct can_tdc: > > > > https://elixir.bootlin.com/linux/v6.2/source/include/linux/can/bittiming.h#L21 > > > > Please refer to this patch if you want an example of how to use TDC: > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1010a8fa9608 > > > > Thanks for that pointers! I'll check ... > > > > + msg->hdr.len = 7; > > > > What is this magic number? If possible, replace it with a sizeof(). > > I think each setting of msg->hdr.len in this driver is somewhat hard- > coded ;) > Maybe this has been caused by the ancient documentation for our can-usb > protocol / firmware, that states things like "set len to 2 for > set_baudrate" or "set len to 7 (24 bytes) for set_baudrate_x ;) > > > > > It seems that this relates to the size of struct set_baudrate_msg, but > > that structure is 8 bytes. Is the last byte of struct set_baudrate_msg > > really used? If not, reflect this in the declaration of the structure. > > sizeof(set_baudrate_msg) should be 4 * u8 + sizeof(baudrate_x). > sizeof(baudrate_x) should be 2 * le16 + 4 * u8 + 2 * (4 * le16) > So I'll count 4 * 1 + 2 * 2 + 4 * 1 + 2 * (4 * 2) = 28 > 28 >> 2 gives us 7. > So 7 is fine here. But I agree that a sizeof(struct baudrate_x) would > be much clearer. I'll change this one to sizeof() and leave all other > "msg.hdr.len =" expression as they are, until a follow-up cleanup. So, one more time, this is a length in long, not in bytes? Then, use the DIV_ROUND_UP() similarly to above and document this behaviour in your structures. I would rather have this done now instead of doing it in a follow-up patch. > > > > > + msg->hdr.cmd = CMD_SETBAUD; > > > + > > > + msg->setbaud.net = priv->index; > > > + msg->setbaud.rsvd = 0; > > > + > > > + netdev_info(netdev, > > > + "ctrlmode=%#x/%#x, esd-net=%u, esd-mode=%#x, esd-flg=%#x, arb: brp=%u, ts1=%u, ts2=%u, sjw=%u, data: dbrp=%u, dts1=%u, dts2=%u dsjw=%u\n", > > > + priv->can.ctrlmode, priv->can.ctrlmode_supported, > > > + priv->index, mode, flags, > > > + brp, tseg1, tseg2, sjw, > > > + d_brp, d_tseg1, d_tseg2, d_sjw); > > > > Remove this debug message. The bittiming information can be retrieved > > with the ip tool. > > > > ip --details link show canX > Yes, I know. But my intention was to exactly and directly see the > individual values passed to the USB set baudrate command without using > wireshark to sniff the USB, if anybody complains about problems with > the bitrate. That's my point, this is meant for troubleshooting, not for normal use. The calculation is not rocket science. If a user has an issue with the bitrate, the values provided by the ip tool are enough for you to recalculate the actual values passed to the device. You should not spam the user just to save you the time to do this calculation. > This netdev_info is similar to the "netdev_info(netdev, > "setting BTR=%#x\n", canbtr);" for CAN-USB/2. This one should also be removed. > So from my point of view this is an informational message too, and not > a debug message. NACK. > > > > > + err = esd_usb_send_msg(priv->usb, msg); > > > + > > > + kfree(msg); > > > > esd_usb_send_msg() uses usb_bulk_msg() which does a synchronous call. > > It would be great to go asynchronous and use usb_submit_urb() so that > > you minimize the time spent in the driver. > > > > I know that esd_usb2_set_bittiming() also uses the synchronous call, > > so I am fine to have it as-is for this patch but for the future, it > > would be great to consider refactoring this. > > ACK. I'll put this on the todo list for a follow-up patch. ACK. > > > > > + return err; > > > +} > > > + > > > static int esd_usb_get_berr_counter(const struct net_device *netdev, > > > struct can_berr_counter *bec) > > > { > > > @@ -1023,16 +1223,32 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index) > > > CAN_CTRLMODE_CC_LEN8_DLC | > > > CAN_CTRLMODE_BERR_REPORTING; > > > > > > - if (le16_to_cpu(dev->udev->descriptor.idProduct) == > > > - USB_CANUSBM_PRODUCT_ID) > > > + switch (le16_to_cpu(dev->udev->descriptor.idProduct)) { > > > > Instead of doing a switch on idProduct, you can use the driver_info > > field from struct usb_device_id to store the device quirks. > > > > You can pass either a pointer or some flags into driver_info. Examples: > > > > https://elixir.bootlin.com/linux/v6.2/source/drivers/net/can/usb/peak_usb/pcan_usb_core.c#L30 > > https://elixir.bootlin.com/linux/v6.2/source/drivers/net/can/usb/etas_es58x/es58x_core.c#L37 > > > > Yes using flags within .driver_info like es58x_core.c does it, seems to > be a good idea here. But I'd like to leave this for a follow-up patch, > too. ACK. > > > + case USB_CANUSB3_PRODUCT_ID: > > > + priv->can.clock.freq = ESD_USB3_CAN_CLOCK; > > > + priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; > > > + priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD; > > > + priv->can.bittiming_const = &esd_usb3_bittiming_const; > > > + priv->can.data_bittiming_const = &esd_usb3_data_bittiming_const; > > > + priv->can.do_set_bittiming = esd_usb3_set_bittiming; > > > + priv->can.do_set_data_bittiming = esd_usb3_set_bittiming; > > > + break; > > > + > > > + case USB_CANUSBM_PRODUCT_ID: > > > priv->can.clock.freq = ESD_USBM_CAN_CLOCK; > > > - else { > > > + priv->can.bittiming_const = &esd_usb2_bittiming_const; > > > + priv->can.do_set_bittiming = esd_usb2_set_bittiming; > > > + break; > > > + > > > + case USB_CANUSB2_PRODUCT_ID: > > > + default: > > > priv->can.clock.freq = ESD_USB2_CAN_CLOCK; > > > priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; > > > + priv->can.bittiming_const = &esd_usb2_bittiming_const; > > > + priv->can.do_set_bittiming = esd_usb2_set_bittiming; > > > + break; > > > } > > > > > > - priv->can.bittiming_const = &esd_usb2_bittiming_const; > > > - priv->can.do_set_bittiming = esd_usb2_set_bittiming; > > > priv->can.do_set_mode = esd_usb_set_mode; > > > priv->can.do_get_berr_counter = esd_usb_get_berr_counter; > > > > > > -- > > > 2.25.1 > > > >
On 09.05.2023 10:28:13, Vincent MAILHOL wrote: > > > And because hdr.len is initially 3, hdr.len becomes 5. Right? Shouldn't it be 8? > > > > It might be a little confusing, but I think it's fine. > > hdr.len is given in units of longwords (4 bytes each)! Therefore we > > have 12 bytes (the initial 3 longwords) for struct tx_msg before > > tx_msg.data[]. > > Than (8 + 3)/4=2 gives us 2 additional longwords for the 8 data bytes. > > So that 3+2=5 (equal to 20 bytes) should be ok. I think the term longword is more commonly used in non-Unix operating systems :) > OK. So you want to round up the length to the next sizeof(long) multiple, right? > > First, sizeof(long) being platform specific, you need to declare a > macro to make your intent explicit. > > /* Size of a long int on esd devices */ > #define USB_ESD_SIZEOF_LONG 4 > > Please test, but for what I understand, below line is an equivalent > and a more readable way to achieve your goal: > > msg->hdr.len = DIV_ROUND_UP(cf->len, USB_ESD_SIZEOF_LONG); use "sizeof(u32)" > Also, add documentation to your structure to explain that hdr.len > represents the length in long, not in bytes. ...lengths in multiple of u32. Marc
On Tue. 9 May 2023 at 16:12, Marc Kleine-Budde <mkl@pengutronix.de> wrote: > On 09.05.2023 10:28:13, Vincent MAILHOL wrote: > > > > And because hdr.len is initially 3, hdr.len becomes 5. Right? Shouldn't it be 8? > > > > > > It might be a little confusing, but I think it's fine. > > > hdr.len is given in units of longwords (4 bytes each)! Therefore we > > > have 12 bytes (the initial 3 longwords) for struct tx_msg before > > > tx_msg.data[]. > > > Than (8 + 3)/4=2 gives us 2 additional longwords for the 8 data bytes. > > > So that 3+2=5 (equal to 20 bytes) should be ok. > > I think the term longword is more commonly used in non-Unix operating > systems :) > > > OK. So you want to round up the length to the next sizeof(long) multiple, right? > > > > First, sizeof(long) being platform specific, you need to declare a > > macro to make your intent explicit. > > > > /* Size of a long int on esd devices */ > > #define USB_ESD_SIZEOF_LONG 4 > > > > Please test, but for what I understand, below line is an equivalent > > and a more readable way to achieve your goal: > > > > msg->hdr.len = DIV_ROUND_UP(cf->len, USB_ESD_SIZEOF_LONG); > > use "sizeof(u32)" Marc is right, forget about USB_ESD_SIZEOF_LONG. sizeof(u32) does the job better.
On 09.05.2023 10:28:13, Vincent MAILHOL wrote: > > > ip --details link show canX > > Yes, I know. But my intention was to exactly and directly see the > > individual values passed to the USB set baudrate command without using > > wireshark to sniff the USB, if anybody complains about problems with > > the bitrate. > > That's my point, this is meant for troubleshooting, not for normal > use. The calculation is not rocket science. If a user has an issue > with the bitrate, the values provided by the ip tool are enough for > you to recalculate the actual values passed to the device. You should > not spam the user just to save you the time to do this calculation. > > > This netdev_info is similar to the "netdev_info(netdev, > > "setting BTR=%#x\n", canbtr);" for CAN-USB/2. > > This one should also be removed. > > > So from my point of view this is an informational message too, and not > > a debug message. > > NACK. Please make it a debug message. Marc
diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index e24fa48b9b42..48cf5e88d216 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro + * CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro * * Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs <socketcan@esd.eu> * Copyright (C) 2022-2023 esd electronics gmbh, Frank Jungclaus <frank.jungclaus@esd.eu> @@ -18,17 +18,19 @@ MODULE_AUTHOR("Matthias Fuchs <socketcan@esd.eu>"); MODULE_AUTHOR("Frank Jungclaus <frank.jungclaus@esd.eu>"); -MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro interfaces"); +MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2, CAN-USB/3 and CAN-USB/Micro interfaces"); MODULE_LICENSE("GPL v2"); /* USB vendor and product ID */ #define USB_ESDGMBH_VENDOR_ID 0x0ab4 #define USB_CANUSB2_PRODUCT_ID 0x0010 #define USB_CANUSBM_PRODUCT_ID 0x0011 +#define USB_CANUSB3_PRODUCT_ID 0x0014 /* CAN controller clock frequencies */ #define ESD_USB2_CAN_CLOCK 60000000 #define ESD_USBM_CAN_CLOCK 36000000 +#define ESD_USB3_CAN_CLOCK 80000000 /* Maximum number of CAN nets */ #define ESD_USB_MAX_NETS 2 @@ -43,6 +45,9 @@ MODULE_LICENSE("GPL v2"); /* esd CAN message flags - dlc field */ #define ESD_DLC_RTR 0x10 +#define ESD_DLC_NO_BRS 0x10 +#define ESD_DLC_ESI 0x20 +#define ESD_DLC_FD 0x80 /* esd CAN message flags - id field */ #define ESD_EXTID 0x20000000 @@ -72,6 +77,28 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB2_BRP_INC 1 #define ESD_USB2_3_SAMPLES 0x00800000 +/* Bit timing CAN-USB/3 */ +#define ESD_USB3_TSEG1_MIN 1 +#define ESD_USB3_TSEG1_MAX 256 +#define ESD_USB3_TSEG2_MIN 1 +#define ESD_USB3_TSEG2_MAX 128 +#define ESD_USB3_SJW_MAX 128 +#define ESD_USB3_BRP_MIN 1 +#define ESD_USB3_BRP_MAX 1024 +#define ESD_USB3_BRP_INC 1 +/* Bit timing CAN-USB/3, data phase */ +#define ESD_USB3_DATA_TSEG1_MIN 1 +#define ESD_USB3_DATA_TSEG1_MAX 32 +#define ESD_USB3_DATA_TSEG2_MIN 1 +#define ESD_USB3_DATA_TSEG2_MAX 16 +#define ESD_USB3_DATA_SJW_MAX 8 +#define ESD_USB3_DATA_BRP_MIN 1 +#define ESD_USB3_DATA_BRP_MAX 32 +#define ESD_USB3_DATA_BRP_INC 1 + +/* Transmitter Delay Compensation */ +#define ESD_TDC_MODE_AUTO 0 + /* esd IDADD message */ #define ESD_ID_ENABLE 0x80 #define ESD_MAX_ID_SEGMENT 64 @@ -95,6 +122,21 @@ MODULE_LICENSE("GPL v2"); #define MAX_RX_URBS 4 #define MAX_TX_URBS 16 /* must be power of 2 */ +/* Modes for NTCAN_BAUDRATE_X */ +#define ESD_BAUDRATE_MODE_DISABLE 0 /* remove from bus */ +#define ESD_BAUDRATE_MODE_INDEX 1 /* ESD (CiA) bit rate idx */ +#define ESD_BAUDRATE_MODE_BTR_CTRL 2 /* BTR values (Controller)*/ +#define ESD_BAUDRATE_MODE_BTR_CANONICAL 3 /* BTR values (Canonical) */ +#define ESD_BAUDRATE_MODE_NUM 4 /* numerical bit rate */ +#define ESD_BAUDRATE_MODE_AUTOBAUD 5 /* autobaud */ + +/* Flags for NTCAN_BAUDRATE_X */ +#define ESD_BAUDRATE_FLAG_FD 0x0001 /* enable CAN FD Mode */ +#define ESD_BAUDRATE_FLAG_LOM 0x0002 /* enable Listen Only mode */ +#define ESD_BAUDRATE_FLAG_STM 0x0004 /* enable Self test mode */ +#define ESD_BAUDRATE_FLAG_TRS 0x0008 /* enable Triple Sampling */ +#define ESD_BAUDRATE_FLAG_TXP 0x0010 /* enable Transmit Pause */ + struct header_msg { u8 len; /* len is always the total message length in 32bit words */ u8 cmd; @@ -129,6 +171,7 @@ struct rx_msg { __le32 id; /* upper 3 bits contain flags */ union { u8 data[8]; + u8 data_fd[64]; struct { u8 status; /* CAN Controller Status */ u8 ecc; /* Error Capture Register */ @@ -144,8 +187,11 @@ struct tx_msg { u8 net; u8 dlc; u32 hnd; /* opaque handle, not used by device */ - __le32 id; /* upper 3 bits contain flags */ - u8 data[8]; + __le32 id; /* upper 3 bits contain flags */ + union { + u8 data[8]; + u8 data_fd[64]; + }; }; struct tx_done_msg { @@ -165,12 +211,37 @@ struct id_filter_msg { __le32 mask[ESD_MAX_ID_SEGMENT + 1]; }; +struct baudrate_x_cfg { + __le16 brp; /* bit rate pre-scaler */ + __le16 tseg1; /* TSEG1 register */ + __le16 tseg2; /* TSEG2 register */ + __le16 sjw; /* SJW register */ +}; + +struct tdc_cfg { + u8 tdc_mode; /* transmitter Delay Compensation mode */ + u8 ssp_offset; /* secondary Sample Point offset in mtq */ + s8 ssp_shift; /* secondary Sample Point shift in mtq */ + u8 tdc_filter; /* Transmitter Delay Compensation */ +}; + +struct baudrate_x { + __le16 mode; /* mode word */ + __le16 flags; /* control flags */ + struct tdc_cfg tdc; /* TDC configuration */ + struct baudrate_x_cfg arb; /* bit rate during arbitration phase */ + struct baudrate_x_cfg data; /* bit rate during data phase */ +}; + struct set_baudrate_msg { u8 len; u8 cmd; u8 net; u8 rsvd; - __le32 baud; + union { + __le32 baud; + struct baudrate_x baud_x; + }; }; /* Main message type used between library and application */ @@ -188,6 +259,7 @@ union __packed esd_usb_msg { static struct usb_device_id esd_usb_table[] = { {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)}, {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)}, + {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB3_PRODUCT_ID)}, {} }; MODULE_DEVICE_TABLE(usb, esd_usb_table); @@ -326,11 +398,13 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv, static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, union esd_usb_msg *msg) { + bool is_canfd = msg->rx.dlc & ESD_DLC_FD ? true : false; struct net_device_stats *stats = &priv->netdev->stats; struct can_frame *cf; + struct canfd_frame *cfd; struct sk_buff *skb; - int i; u32 id; + u8 len; if (!netif_device_present(priv->netdev)) return; @@ -340,27 +414,42 @@ static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, if (id & ESD_EVENT) { esd_usb_rx_event(priv, msg); } else { - skb = alloc_can_skb(priv->netdev, &cf); + if (is_canfd) { + skb = alloc_canfd_skb(priv->netdev, &cfd); + } else { + skb = alloc_can_skb(priv->netdev, &cf); + cfd = (struct canfd_frame *)cf; + } + if (skb == NULL) { stats->rx_dropped++; return; } - cf->can_id = id & ESD_IDMASK; - can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR, - priv->can.ctrlmode); - - if (id & ESD_EXTID) - cf->can_id |= CAN_EFF_FLAG; + cfd->can_id = id & ESD_IDMASK; - if (msg->rx.dlc & ESD_DLC_RTR) { - cf->can_id |= CAN_RTR_FLAG; + if (is_canfd) { + /* masking by 0x0F is already done within can_fd_dlc2len() */ + cfd->len = can_fd_dlc2len(msg->rx.dlc); + len = cfd->len; + if ((msg->rx.dlc & ESD_DLC_NO_BRS) == 0) + cfd->flags |= CANFD_BRS; + if (msg->rx.dlc & ESD_DLC_ESI) + cfd->flags |= CANFD_ESI; } else { - for (i = 0; i < cf->len; i++) - cf->data[i] = msg->rx.data[i]; - - stats->rx_bytes += cf->len; + can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_DLC_RTR, priv->can.ctrlmode); + len = cf->len; + if (msg->rx.dlc & ESD_DLC_RTR) { + cf->can_id |= CAN_RTR_FLAG; + len = 0; + } } + + if (id & ESD_EXTID) + cfd->can_id |= CAN_EFF_FLAG; + + memcpy(cfd->data, msg->rx.data_fd, len); + stats->rx_bytes += len; stats->rx_packets++; netif_rx(skb); @@ -735,7 +824,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, struct esd_usb *dev = priv->usb; struct esd_tx_urb_context *context = NULL; struct net_device_stats *stats = &netdev->stats; - struct can_frame *cf = (struct can_frame *)skb->data; + struct canfd_frame *cfd = (struct canfd_frame *)skb->data; union esd_usb_msg *msg; struct urb *urb; u8 *buf; @@ -768,19 +857,28 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, msg->hdr.len = 3; /* minimal length */ msg->hdr.cmd = CMD_CAN_TX; msg->tx.net = priv->index; - msg->tx.dlc = can_get_cc_dlc(cf, priv->can.ctrlmode); - msg->tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK); - if (cf->can_id & CAN_RTR_FLAG) - msg->tx.dlc |= ESD_DLC_RTR; + if (can_is_canfd_skb(skb)) { + msg->tx.dlc = can_fd_len2dlc(cfd->len); + msg->tx.dlc |= ESD_DLC_FD; + + if ((cfd->flags & CANFD_BRS) == 0) + msg->tx.dlc |= ESD_DLC_NO_BRS; + } else { + msg->tx.dlc = can_get_cc_dlc((struct can_frame *)cfd, priv->can.ctrlmode); + + if (cfd->can_id & CAN_RTR_FLAG) + msg->tx.dlc |= ESD_DLC_RTR; + } - if (cf->can_id & CAN_EFF_FLAG) + msg->tx.id = cpu_to_le32(cfd->can_id & CAN_ERR_MASK); + + if (cfd->can_id & CAN_EFF_FLAG) msg->tx.id |= cpu_to_le32(ESD_EXTID); - for (i = 0; i < cf->len; i++) - msg->tx.data[i] = cf->data[i]; + memcpy(msg->tx.data_fd, cfd->data, cfd->len); - msg->hdr.len += (cf->len + 3) >> 2; + msg->hdr.len += (cfd->len + 3) >> 2; for (i = 0; i < MAX_TX_URBS; i++) { if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { @@ -966,6 +1064,108 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) return err; } +static const struct can_bittiming_const esd_usb3_bittiming_const = { + .name = "esd_usb3", + .tseg1_min = ESD_USB3_TSEG1_MIN, + .tseg1_max = ESD_USB3_TSEG1_MAX, + .tseg2_min = ESD_USB3_TSEG2_MIN, + .tseg2_max = ESD_USB3_TSEG2_MAX, + .sjw_max = ESD_USB3_SJW_MAX, + .brp_min = ESD_USB3_BRP_MIN, + .brp_max = ESD_USB3_BRP_MAX, + .brp_inc = ESD_USB3_BRP_INC, +}; + +static const struct can_bittiming_const esd_usb3_data_bittiming_const = { + .name = "esd_usb3", + .tseg1_min = ESD_USB3_DATA_TSEG1_MIN, + .tseg1_max = ESD_USB3_DATA_TSEG1_MAX, + .tseg2_min = ESD_USB3_DATA_TSEG2_MIN, + .tseg2_max = ESD_USB3_DATA_TSEG2_MAX, + .sjw_max = ESD_USB3_DATA_SJW_MAX, + .brp_min = ESD_USB3_DATA_BRP_MIN, + .brp_max = ESD_USB3_DATA_BRP_MAX, + .brp_inc = ESD_USB3_DATA_BRP_INC, +}; + +static int esd_usb3_set_bittiming(struct net_device *netdev) +{ + struct esd_usb_net_priv *priv = netdev_priv(netdev); + struct can_bittiming *bt = &priv->can.bittiming; + struct can_bittiming *d_bt = &priv->can.data_bittiming; + union esd_usb_msg *msg; + int err; + u16 mode; + u16 flags = 0; + u16 brp, tseg1, tseg2, sjw; + u16 d_brp, d_tseg1, d_tseg2, d_sjw; + + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + /* Canonical is the most reasonable mode for SocketCAN on CAN-USB/3 ... */ + mode = ESD_BAUDRATE_MODE_BTR_CANONICAL; + + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + flags |= ESD_BAUDRATE_FLAG_LOM; + + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + flags |= ESD_BAUDRATE_FLAG_TRS; + + brp = bt->brp & (ESD_USB3_BRP_MAX - 1); + sjw = bt->sjw & (ESD_USB3_SJW_MAX - 1); + tseg1 = (bt->prop_seg + bt->phase_seg1) & (ESD_USB3_TSEG1_MAX - 1); + tseg2 = bt->phase_seg2 & (ESD_USB3_TSEG2_MAX - 1); + + msg->setbaud.baud_x.arb.brp = cpu_to_le16(brp); + msg->setbaud.baud_x.arb.sjw = cpu_to_le16(sjw); + msg->setbaud.baud_x.arb.tseg1 = cpu_to_le16(tseg1); + msg->setbaud.baud_x.arb.tseg2 = cpu_to_le16(tseg2); + + if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { + d_brp = d_bt->brp & (ESD_USB3_DATA_BRP_MAX - 1); + d_sjw = d_bt->sjw & (ESD_USB3_DATA_SJW_MAX - 1); + d_tseg1 = (d_bt->prop_seg + d_bt->phase_seg1) & (ESD_USB3_DATA_TSEG1_MAX - 1); + d_tseg2 = d_bt->phase_seg2 & (ESD_USB3_DATA_TSEG2_MAX - 1); + flags |= ESD_BAUDRATE_FLAG_FD; + } else { + d_brp = 0; + d_sjw = 0; + d_tseg1 = 0; + d_tseg2 = 0; + } + + msg->setbaud.baud_x.data.brp = cpu_to_le16(d_brp); + msg->setbaud.baud_x.data.sjw = cpu_to_le16(d_sjw); + msg->setbaud.baud_x.data.tseg1 = cpu_to_le16(d_tseg1); + msg->setbaud.baud_x.data.tseg2 = cpu_to_le16(d_tseg2); + msg->setbaud.baud_x.mode = cpu_to_le16(mode); + msg->setbaud.baud_x.flags = cpu_to_le16(flags); + msg->setbaud.baud_x.tdc.tdc_mode = ESD_TDC_MODE_AUTO; + msg->setbaud.baud_x.tdc.ssp_offset = 0; + msg->setbaud.baud_x.tdc.ssp_shift = 0; + msg->setbaud.baud_x.tdc.tdc_filter = 0; + + msg->hdr.len = 7; + msg->hdr.cmd = CMD_SETBAUD; + + msg->setbaud.net = priv->index; + msg->setbaud.rsvd = 0; + + netdev_info(netdev, + "ctrlmode=%#x/%#x, esd-net=%u, esd-mode=%#x, esd-flg=%#x, arb: brp=%u, ts1=%u, ts2=%u, sjw=%u, data: dbrp=%u, dts1=%u, dts2=%u dsjw=%u\n", + priv->can.ctrlmode, priv->can.ctrlmode_supported, + priv->index, mode, flags, + brp, tseg1, tseg2, sjw, + d_brp, d_tseg1, d_tseg2, d_sjw); + + err = esd_usb_send_msg(priv->usb, msg); + + kfree(msg); + return err; +} + static int esd_usb_get_berr_counter(const struct net_device *netdev, struct can_berr_counter *bec) { @@ -1023,16 +1223,32 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index) CAN_CTRLMODE_CC_LEN8_DLC | CAN_CTRLMODE_BERR_REPORTING; - if (le16_to_cpu(dev->udev->descriptor.idProduct) == - USB_CANUSBM_PRODUCT_ID) + switch (le16_to_cpu(dev->udev->descriptor.idProduct)) { + case USB_CANUSB3_PRODUCT_ID: + priv->can.clock.freq = ESD_USB3_CAN_CLOCK; + priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; + priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD; + priv->can.bittiming_const = &esd_usb3_bittiming_const; + priv->can.data_bittiming_const = &esd_usb3_data_bittiming_const; + priv->can.do_set_bittiming = esd_usb3_set_bittiming; + priv->can.do_set_data_bittiming = esd_usb3_set_bittiming; + break; + + case USB_CANUSBM_PRODUCT_ID: priv->can.clock.freq = ESD_USBM_CAN_CLOCK; - else { + priv->can.bittiming_const = &esd_usb2_bittiming_const; + priv->can.do_set_bittiming = esd_usb2_set_bittiming; + break; + + case USB_CANUSB2_PRODUCT_ID: + default: priv->can.clock.freq = ESD_USB2_CAN_CLOCK; priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; + priv->can.bittiming_const = &esd_usb2_bittiming_const; + priv->can.do_set_bittiming = esd_usb2_set_bittiming; + break; } - priv->can.bittiming_const = &esd_usb2_bittiming_const; - priv->can.do_set_bittiming = esd_usb2_set_bittiming; priv->can.do_set_mode = esd_usb_set_mode; priv->can.do_get_berr_counter = esd_usb_get_berr_counter;