From nobody Sun Feb 8 12:51:53 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2DCD22E36EC; Mon, 13 Oct 2025 11:02:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353339; cv=none; b=iHWcQmKtxkGJO+mNcUbp97Mq790vbByM0hvj3FTttjJRhP2vbQYkqUqMfdBqR4odAsWKn7Ee5fRVaKoc08WkoIeqpBsar2mCPwHmTNy3LQTewLGGzm2OqMnutCNNRJlv0tl6l6cekvDnlJ1yawurtyIS8UIBg4IfGuY27ZxAtts= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353339; c=relaxed/simple; bh=Z/lAhsBfAiGioe6wx17saWxZPcTan9gEXDbid8qhzYw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hj+2UFUE2xJ8uK8p9SS0NYJ5XCdrXX+p6JsPzoRfgVeFGWgCC8sFXKS6zC4mJp2CoIDmJY5KakEYl32gCxK7ajWUlt+UgUq5nc6QaHDVVH+BKBxcpKk96OxN+SsomguE2e+O2fp0V2SeGuLLpKF6va+QGM1bYj4Ltce6BtL3Fys= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZbT0nuqP; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZbT0nuqP" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 70906C4CEFE; Mon, 13 Oct 2025 11:02:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1760353338; bh=Z/lAhsBfAiGioe6wx17saWxZPcTan9gEXDbid8qhzYw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=ZbT0nuqPZoKCX75AM9hXYI/WKVFyV+spRzukkgTh16l1Ak9CFPy8Ic9IZexSDTLb+ 2qrEj19eGm+7VW2YTUgJoZGMZIPLgVGBpTIsQy/gm81RWst0TXEUvfuaEZGuOPzu5W rPBcvZEJs02JNGLX3br1rMT7KElWaDwil0uDdSvRV8sH3dXfgHV6Cri0tZ4aiGEn/G kjQFXvEXGCNpk8eIf81cBhflrCT41yEBZNc+3zQiU5XWQ1mZyHyX0SHW8fhFH/2MoT HS+TEc4/TaFUKwDoj5R3b9PJcHTavc4daqmyPZRQbEHoPZE+n0S/k2tJGMh4zEn/nQ e6CV1W67tnyGA== From: Vincent Mailhol Date: Mon, 13 Oct 2025 20:01:23 +0900 Subject: [PATCH 1/9] can: dev: can_dev_dropped_skb: drop CAN FD skbs if FD is off Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251013-canxl-netlink-v1-1-f422b7e2729f@kernel.org> References: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> In-Reply-To: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> To: Marc Kleine-Budde , Oliver Hartkopp Cc: Vincent Mailhol , =?utf-8?q?St=C3=A9phane_Grosjean?= , Robert Nawrath , Minh Le , Duy Nguyen , linux-can@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=2234; i=mailhol@kernel.org; h=from:subject:message-id; bh=Z/lAhsBfAiGioe6wx17saWxZPcTan9gEXDbid8qhzYw=; b=owGbwMvMwCV2McXO4Xp97WbG02pJDBlv7sjwPe84w9Vj5f1Hb3r527cpP35FOTVGdzm9S/jYu ZOn9GpbRykLgxgXg6yYIsuyck5uhY5C77BDfy1h5rAygQxh4OIUgIm8Pc7wv7bY+3L7Au4a/d1F bc/TX0g5lAvF2O5zYe66O/XWBcl+OYY/fIZ11+72Hf0kKvBQjc1yZ9CzS7WMp2/yrfzUq8LDuI+ FGQA= X-Developer-Key: i=mailhol@kernel.org; a=openpgp; fpr=ED8F700574E67F20E574E8E2AB5FEB886DBB99C2 Currently, the CAN FD skb validation logic is based on the MTU: the interface is deemed FD capable if and only if its MTU is greater or equal to CANFD_MTU. This logic is showing its limit with the introduction of CAN XL. For example, consider the two scenarios below: 1. An interface configured with CAN FD on and CAN XL on 2. An interface configured with CAN FD off and CAN XL on In those two scenarios, the interfaces would have the same MTU: CANXL_MTU making it impossible to differentiate which one has CAN FD turned on and which one has it off. Because of the limitation, the only non-UAPI-breaking workaround is to do the check at the device level using the can_priv->ctrlmode flags. Unfortunately, the virtual interfaces (vcan, vxcan), which do not have a can_priv, are left behind. Add a check on the CAN_CTRLMODE_FD flag in can_dev_dropped_skb() and drop FD frames whenever the feature is turned off. Signed-off-by: Vincent Mailhol --- Changelog: RFC -> v1: - add an netdev_info_once() message. - this was sent as a standalone patch for discussion, it is now integrated in the CAN XL series. Link: https://lore.kernel.org/linux-can/20250907080504.598419-2-mailhol@k= ernel.org/ --- include/linux/can/dev.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 0fe8f80f223e..d59b283c981a 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -103,12 +103,20 @@ static inline bool can_dev_dropped_skb(struct net_dev= ice *dev, struct sk_buff *s if (priv->ctrlmode & CAN_CTRLMODE_LISTENONLY) { netdev_info_once(dev, "interface in listen only mode, dropping skb\n"); - kfree_skb(skb); - dev->stats.tx_dropped++; - return true; + goto invalid_skb; + } + + if (!(priv->ctrlmode & CAN_CTRLMODE_FD) && can_is_canfd_skb(skb)) { + netdev_info_once(dev, "CAN FD is disabled, dropping skb\n"); + goto invalid_skb; } =20 return can_dropped_invalid_skb(dev, skb); + +invalid_skb: + kfree_skb(skb); + dev->stats.tx_dropped++; + return true; } =20 void can_setup(struct net_device *dev); --=20 2.49.1 From nobody Sun Feb 8 12:51:53 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5D6243016F7; Mon, 13 Oct 2025 11:02:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353340; cv=none; b=ZUf55+8zc6Qog3J6Vy3EAPTEwzCs5TmtMro5aOM8xQqRHr5AWa4/HDYLCNAbH/wY1ucm8qkV7lfRsa+eMNAznXMSO8IiHRZ4waFAIBdCeWg8+CDn+ehuesk+yv2oGZqeprC0/asP5cJLe7PA1yIEldd5RW/nnJIJvG0UJketxxY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353340; c=relaxed/simple; bh=JBExfb/2NKcoTW/v346rWFedtWA74TYLoMtfsRfq+Go=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ILISEU3t8jZ7bZvQPdd7VTMIfKk47OPOHSOfv1uE5vsjgmajHGQAUQB7XjiHHDQE93QccOAEAOGe1hQZoDDHHtIK5rXrcW0kp5cV0iKFYVoTxn5ZiLSjD8M8AS6NYKrbKdTxaVzTTNDTH5/6Gu8ou/gA56iAzB8sAHNYPYr9G3U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=L2DlN4zn; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="L2DlN4zn" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 05DB0C116C6; Mon, 13 Oct 2025 11:02:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1760353340; bh=JBExfb/2NKcoTW/v346rWFedtWA74TYLoMtfsRfq+Go=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=L2DlN4zn1GjG/EpfJhA9aEKljDl5o4IC22khkMz4HE9YyAiAbie1J5mshZHyj7px/ 8PxnWAw5o0cs1Hq0ArqUCOU4A4Op+dBtgZ7sR7ZEzjJXmtM/M5Jrt1G25ZMydPz3vM /Vo9KRKWgzEyqBGSs9vRRmIv7g75tb+DTf7UyNcHlXNlMHtM7FsdJXnxCCMXV0WEBc EFAMqqRPOtdRtLHmdCLxYWh7EbW7qZpv+EO8KcAnA8ku+WR360Q0MsfVuEz357j3gF tX2q7a0yZ/NygwXrHNdBO3V2Wg/k9OnrV5v6qjARP/uIZ/s6n1ccvHgukTIugQjyz1 474Z90mMUAS6g== From: Vincent Mailhol Date: Mon, 13 Oct 2025 20:01:24 +0900 Subject: [PATCH 2/9] can: netlink: add CAN_CTRLMODE_RESTRICTED Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251013-canxl-netlink-v1-2-f422b7e2729f@kernel.org> References: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> In-Reply-To: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> To: Marc Kleine-Budde , Oliver Hartkopp Cc: Vincent Mailhol , =?utf-8?q?St=C3=A9phane_Grosjean?= , Robert Nawrath , Minh Le , Duy Nguyen , linux-can@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=5265; i=mailhol@kernel.org; h=from:subject:message-id; bh=JBExfb/2NKcoTW/v346rWFedtWA74TYLoMtfsRfq+Go=; b=owGbwMvMwCV2McXO4Xp97WbG02pJDBlv7shvz5vgqH7xw+1zfUsV3e8LLNKN2vhw1sbaaM0Ky Zz6vhkKHaUsDGJcDLJiiizLyjm5FToKvcMO/bWEmcPKBDKEgYtTACZyv5zhv4+AmsZ0oXUKBw/y 10ws/Pp5jXTv+hMr6w+v+Peaa5pBGwMjw8eFP14W7hVcK7hn28PVux/J/26Z53JvmcWsnVdehi1 fcosPAA== X-Developer-Key: i=mailhol@kernel.org; a=openpgp; fpr=ED8F700574E67F20E574E8E2AB5FEB886DBB99C2 ISO 11898-1:2024 adds a new restricted operation mode. This mode is added as a mandatory feature for nodes which support CAN XL and is retrofitted as optional for legacy nodes (i.e. the ones which only support Classical CAN and CAN FD). The restricted operation mode is nearly the same as the listen only mode: the node can not send data frames or remote frames and can not send dominant bits if an error occurs. The only exception is that the node shall still send the acknowledgment bit. A second niche exception is that the node may still send a data frame containing a time reference message if the node is a primary time provider, but because the time provider feature is not yet implemented in the kernel, this second exception is not relevant to us at the moment. Add the CAN_CTRLMODE_RESTRICTED control mode flag and update the can_dev_dropped_skb() helper function accordingly. Finally, bail out if both CAN_CTRLMODE_LISTENONLY and CAN_CTRLMODE_RESTRICTED are provided. Signed-off-by: Vincent Mailhol --- drivers/net/can/dev/dev.c | 2 ++ drivers/net/can/dev/netlink.c | 7 ++++++ include/linux/can/dev.h | 50 +++++++++++++++++++++---------------= ---- include/uapi/linux/can/netlink.h | 1 + 4 files changed, 36 insertions(+), 24 deletions(-) diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index 0cc3d008adb3..3377afb6f1c4 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -115,6 +115,8 @@ const char *can_get_ctrlmode_str(u32 ctrlmode) return "fd-tdc-auto"; case CAN_CTRLMODE_TDC_MANUAL: return "fd-tdc-manual"; + case CAN_CTRLMODE_RESTRICTED: + return "restricted-operation"; default: return ""; } diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index 0591406b6f32..f44b5dffa176 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -188,6 +188,13 @@ static int can_validate(struct nlattr *tb[], struct nl= attr *data[], struct can_ctrlmode *cm =3D nla_data(data[IFLA_CAN_CTRLMODE]); =20 flags =3D cm->flags & cm->mask; + + if ((flags & CAN_CTRLMODE_LISTENONLY) && + (flags & CAN_CTRLMODE_RESTRICTED)) { + NL_SET_ERR_MSG(extack, + "Listen-only and restricted modes are mutually exclusive"); + return -EOPNOTSUPP; + } } =20 err =3D can_validate_bittiming(data, extack, IFLA_CAN_BITTIMING); diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index d59b283c981a..9de8fde3ec9d 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -95,30 +95,6 @@ static inline bool can_is_canxl_dev_mtu(unsigned int mtu) return (mtu >=3D CANXL_MIN_MTU && mtu <=3D CANXL_MAX_MTU); } =20 -/* drop skb if it does not contain a valid CAN frame for sending */ -static inline bool can_dev_dropped_skb(struct net_device *dev, struct sk_b= uff *skb) -{ - struct can_priv *priv =3D netdev_priv(dev); - - if (priv->ctrlmode & CAN_CTRLMODE_LISTENONLY) { - netdev_info_once(dev, - "interface in listen only mode, dropping skb\n"); - goto invalid_skb; - } - - if (!(priv->ctrlmode & CAN_CTRLMODE_FD) && can_is_canfd_skb(skb)) { - netdev_info_once(dev, "CAN FD is disabled, dropping skb\n"); - goto invalid_skb; - } - - return can_dropped_invalid_skb(dev, skb); - -invalid_skb: - kfree_skb(skb); - dev->stats.tx_dropped++; - return true; -} - void can_setup(struct net_device *dev); =20 struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb= _max, @@ -150,6 +126,32 @@ void can_bus_off(struct net_device *dev); const char *can_get_state_str(const enum can_state state); const char *can_get_ctrlmode_str(u32 ctrlmode); =20 +/* drop skb if it does not contain a valid CAN frame for sending */ +static inline bool can_dev_dropped_skb(struct net_device *dev, struct sk_b= uff *skb) +{ + struct can_priv *priv =3D netdev_priv(dev); + u32 silent_mode =3D priv->ctrlmode & (CAN_CTRLMODE_LISTENONLY | + CAN_CTRLMODE_RESTRICTED); + + if (silent_mode) { + netdev_info_once(dev, "interface in %s mode, dropping skb\n", + can_get_ctrlmode_str(silent_mode)); + goto invalid_skb; + } + + if (!(priv->ctrlmode & CAN_CTRLMODE_FD) && can_is_canfd_skb(skb)) { + netdev_info_once(dev, "CAN FD is disabled, dropping skb\n"); + goto invalid_skb; + } + + return can_dropped_invalid_skb(dev, skb); + +invalid_skb: + kfree_skb(skb); + dev->stats.tx_dropped++; + return true; +} + void can_state_get_by_berr_counter(const struct net_device *dev, const struct can_berr_counter *bec, enum can_state *tx_state, diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netl= ink.h index ef62f56eaaef..fafd1cce4798 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -103,6 +103,7 @@ struct can_ctrlmode { #define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */ #define CAN_CTRLMODE_TDC_AUTO 0x200 /* FD transceiver automatically calcu= lates TDCV */ #define CAN_CTRLMODE_TDC_MANUAL 0x400 /* FD TDCV is manually set up by us= er */ +#define CAN_CTRLMODE_RESTRICTED 0x800 /* Restricted operation mode */ =20 /* * CAN device statistics --=20 2.49.1 From nobody Sun Feb 8 12:51:53 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 61989305E3E; Mon, 13 Oct 2025 11:02:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353343; cv=none; b=IlL/l5G4mET28yCbgV0BNjhhgg+xnCsLqbHEAXhauGHEB8TnbbMfRLQdnhfoZn4erzfgqeDFmFF29KYP4X0c4ySa+V4MOFOXSnWXehCAzxFsdSDTRvA1Hdi6Ufai2ip7a8uWdUdjm1MV1okjFvSkAk9ktCGXUbCMZbHPF6JvzLg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353343; c=relaxed/simple; bh=Rg0WRegGJp200GiVP+CAtULnWY0ko3CKjuNVobkCRN4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=g/uhn1jcemOrBCB0S1fMqBS5+MlTl89PfdcyjKIc1ystL0gORs4lwX60DFVb/EgL1MvTmUDk2EDEcp3Y8Y8vrg8kAoXsToMc3/fQeybhX/onieo2k2Cl8FDO+ipAxk/arsJ8bwG1kFP1ZGNsq5ZiVLwIChhmjN2duBjcjnXbzyM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=A/Pb6ogZ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="A/Pb6ogZ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8FC54C4CEF8; Mon, 13 Oct 2025 11:02:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1760353341; bh=Rg0WRegGJp200GiVP+CAtULnWY0ko3CKjuNVobkCRN4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=A/Pb6ogZe9dhMjDWCQUO59u6re5AW/407VjbuaC4jvxWPeQS1mhvyPMmWYHfGsH0J Gpz4BDnxoGM7sKlHbmg3zVjTABFJxQul+W0YCsGSrvMGT5F0GQ6/MDzQbxu7OjoJ+5 /g+J0JQzk++tQeOzebV4CGFpaeR4cRNxgoUSoupibIRkMsIotKfJG8XOZ+B2iMtFhv telJR7fh4Uj9cgCfies8Nw/SlI7arpTWh6qk7n++SwhLhibqNkHvsYURqQTDzLTVpo XOq/ROmDqOZQ4LsQIaluL2SE4p0yF3Y0QLn82QIsP/REQ0AX5lV3jhr8KMSaEK6Qdi 0q9XJ4EVzcTKw== From: Vincent Mailhol Date: Mon, 13 Oct 2025 20:01:25 +0900 Subject: [PATCH 3/9] can: netlink: add initial CAN XL support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251013-canxl-netlink-v1-3-f422b7e2729f@kernel.org> References: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> In-Reply-To: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> To: Marc Kleine-Budde , Oliver Hartkopp Cc: Vincent Mailhol , =?utf-8?q?St=C3=A9phane_Grosjean?= , Robert Nawrath , Minh Le , Duy Nguyen , linux-can@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=14038; i=mailhol@kernel.org; h=from:subject:message-id; bh=Rg0WRegGJp200GiVP+CAtULnWY0ko3CKjuNVobkCRN4=; b=owGbwMvMwCV2McXO4Xp97WbG02pJDBlv7ijd/yE1W//3hKfbNi3W3DX7W1f7JZlO+9o90Yt+3 j979/FU2Y5SFgYxLgZZMUWWZeWc3Aodhd5hh/5awsxhZQIZwsDFKQATUXnA8L/s9bN9NmZ/Oa6/ 2X+YveCn3sLVmxmn7J0rybjoS1ld0sRQRoYV3WUb/m8+t5U3eXedd6fnd27+xNkrstR97m6zX5d u8ooNAA== X-Developer-Key: i=mailhol@kernel.org; a=openpgp; fpr=ED8F700574E67F20E574E8E2AB5FEB886DBB99C2 CAN XL uses bittiming parameters different from Classical CAN and CAN FD. Thus, all the data bittiming parameters, including TDC, need to be duplicated for CAN XL. Add the CAN XL netlink interface for all the features which are common with CAN FD. Any new CAN XL specific features are added later on. Add a check that CAN XL capable nodes correctly provide CAN_CTRLMODE_RESTRIC_OP as mandated by ISO 11898-1:2024 =C2=A76.6.19. The first time CAN XL is activated, the MTU is set by default to CANXL_MAX_MTU. The user may then configure a custom MTU within the CANXL_MIN_MTU to CANXL_MIN_MTU range, in which case, the custom MTU value will be kept as long as CAN XL remains active. Signed-off-by: Vincent Mailhol --- Changelog: RFC -> v1: - Correctly wipe out the CAN XL data bittiming and TDC parameters when switching CAN_CTRLMODE_XL off. - Add one level on nesting for xl parameters so that: - bittiming are under priv->xl.data_bittiming{,_const}=C2=A8 - pwm are under priv->xl.pwm{,_const} - Many other code refactors. --- drivers/net/can/dev/dev.c | 14 ++++++- drivers/net/can/dev/netlink.c | 87 ++++++++++++++++++++++++++++++++----= ---- include/linux/can/bittiming.h | 6 ++- include/linux/can/dev.h | 7 +++- include/uapi/linux/can/netlink.h | 7 ++++ 5 files changed, 100 insertions(+), 21 deletions(-) diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index 3377afb6f1c4..32f11db88295 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -117,6 +117,12 @@ const char *can_get_ctrlmode_str(u32 ctrlmode) return "fd-tdc-manual"; case CAN_CTRLMODE_RESTRICTED: return "restricted-operation"; + case CAN_CTRLMODE_XL: + return "xl"; + case CAN_CTRLMODE_XL_TDC_AUTO: + return "xl-tdc-auto"; + case CAN_CTRLMODE_XL_TDC_MANUAL: + return "xl-tdc-manual"; default: return ""; } @@ -350,7 +356,13 @@ void can_set_default_mtu(struct net_device *dev) { struct can_priv *priv =3D netdev_priv(dev); =20 - if (priv->ctrlmode & CAN_CTRLMODE_FD) { + if (priv->ctrlmode & CAN_CTRLMODE_XL) { + if (can_is_canxl_dev_mtu(dev->mtu)) + return; + dev->mtu =3D CANXL_MTU; + dev->min_mtu =3D CANXL_MIN_MTU; + dev->max_mtu =3D CANXL_MAX_MTU; + } else if (priv->ctrlmode & CAN_CTRLMODE_FD) { dev->mtu =3D CANFD_MTU; dev->min_mtu =3D CANFD_MTU; dev->max_mtu =3D CANFD_MTU; diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index f44b5dffa176..2405f1265488 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -2,7 +2,7 @@ /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix * Copyright (C) 2006 Andrey Volkov, Varma Electronics * Copyright (C) 2008-2009 Wolfgang Grandegger - * Copyright (C) 2021 Vincent Mailhol + * Copyright (C) 2021-2025 Vincent Mailhol */ =20 #include @@ -22,6 +22,9 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + = 1] =3D { [IFLA_CAN_TERMINATION] =3D { .type =3D NLA_U16 }, [IFLA_CAN_TDC] =3D { .type =3D NLA_NESTED }, [IFLA_CAN_CTRLMODE_EXT] =3D { .type =3D NLA_NESTED }, + [IFLA_CAN_XL_DATA_BITTIMING] =3D { .len =3D sizeof(struct can_bittiming) = }, + [IFLA_CAN_XL_DATA_BITTIMING_CONST] =3D { .len =3D sizeof(struct can_bitti= ming_const) }, + [IFLA_CAN_XL_TDC] =3D { .type =3D NLA_NESTED }, }; =20 static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] =3D { @@ -70,7 +73,7 @@ static int can_validate_tdc(struct nlattr *data_tdc, return -EOPNOTSUPP; } =20 - /* If one of the CAN_CTRLMODE_TDC_* flag is set then TDC + /* If one of the CAN_CTRLMODE_{,XL}_TDC_* flags is set then TDC * must be set and vice-versa */ if ((tdc_auto || tdc_manual) && !data_tdc) { @@ -82,8 +85,8 @@ static int can_validate_tdc(struct nlattr *data_tdc, return -EOPNOTSUPP; } =20 - /* If providing TDC parameters, at least TDCO is needed. TDCV - * is needed if and only if CAN_CTRLMODE_TDC_MANUAL is set + /* If providing TDC parameters, at least TDCO is needed. TDCV is + * needed if and only if CAN_CTRLMODE_{,XL}_TDC_MANUAL is set */ if (data_tdc) { struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1]; @@ -126,10 +129,10 @@ static int can_validate_databittiming(struct nlattr *= data[], bool is_on; int err; =20 - /* Make sure that valid CAN FD configurations always consist of + /* Make sure that valid CAN FD/XL configurations always consist of * - nominal/arbitration bittiming * - data bittiming - * - control mode with CAN_CTRLMODE_FD set + * - control mode with CAN_CTRLMODE_{FD,XL} set * - TDC parameters are coherent (details in can_validate_tdc()) */ =20 @@ -139,7 +142,10 @@ static int can_validate_databittiming(struct nlattr *d= ata[], is_on =3D flags & CAN_CTRLMODE_FD; type =3D "FD"; } else { - return -EOPNOTSUPP; /* Place holder for CAN XL */ + data_tdc =3D data[IFLA_CAN_XL_TDC]; + tdc_flags =3D flags & CAN_CTRLMODE_XL_TDC_MASK; + is_on =3D flags & CAN_CTRLMODE_XL; + type =3D "XL"; } =20 if (is_on) { @@ -206,6 +212,11 @@ static int can_validate(struct nlattr *tb[], struct nl= attr *data[], if (err) return err; =20 + err =3D can_validate_databittiming(data, extack, + IFLA_CAN_XL_DATA_BITTIMING, flags); + if (err) + return err; + return 0; } =20 @@ -215,7 +226,8 @@ static int can_ctrlmode_changelink(struct net_device *d= ev, { struct can_priv *priv =3D netdev_priv(dev); struct can_ctrlmode *cm; - u32 ctrlstatic, maskedflags, notsupp, ctrlstatic_missing; + const u32 xl_mandatory =3D CAN_CTRLMODE_RESTRICTED; + u32 ctrlstatic, maskedflags, notsupp, ctrlstatic_missing, xl_missing; =20 if (!data[IFLA_CAN_CTRLMODE]) return 0; @@ -229,6 +241,7 @@ static int can_ctrlmode_changelink(struct net_device *d= ev, maskedflags =3D cm->flags & cm->mask; notsupp =3D maskedflags & ~(priv->ctrlmode_supported | ctrlstatic); ctrlstatic_missing =3D (maskedflags & ctrlstatic) ^ ctrlstatic; + xl_missing =3D (priv->ctrlmode_supported & xl_mandatory) ^ xl_mandatory; =20 if (notsupp) { NL_SET_ERR_MSG_FMT(extack, @@ -248,21 +261,36 @@ static int can_ctrlmode_changelink(struct net_device = *dev, return -EOPNOTSUPP; } =20 + if ((priv->ctrlmode_supported & CAN_CTRLMODE_XL) && xl_missing) { + NL_SET_ERR_MSG_FMT(extack, + "bad device: CAN XL capable nodes must support the %s mode", + can_get_ctrlmode_str(xl_missing)); + return -EOPNOTSUPP; + } + /* If a top dependency flag is provided, reset all its dependencies */ if (cm->mask & CAN_CTRLMODE_FD) priv->ctrlmode &=3D ~CAN_CTRLMODE_FD_TDC_MASK; + if (cm->mask & CAN_CTRLMODE_XL) + priv->ctrlmode &=3D ~(CAN_CTRLMODE_XL_TDC_MASK); =20 /* clear bits to be modified and copy the flag values */ priv->ctrlmode &=3D ~cm->mask; priv->ctrlmode |=3D maskedflags; =20 - /* Wipe potential leftovers from previous CAN FD config */ + /* Wipe potential leftovers from previous CAN FD/XL config */ if (!(priv->ctrlmode & CAN_CTRLMODE_FD)) { memset(&priv->fd.data_bittiming, 0, sizeof(priv->fd.data_bittiming)); priv->ctrlmode &=3D ~CAN_CTRLMODE_FD_TDC_MASK; memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc)); } + if (!(priv->ctrlmode & CAN_CTRLMODE_XL)) { + memset(&priv->xl.data_bittiming, 0, + sizeof(priv->fd.data_bittiming)); + priv->ctrlmode &=3D ~CAN_CTRLMODE_XL_TDC_MASK; + memset(&priv->xl.tdc, 0, sizeof(priv->xl.tdc)); + } =20 can_set_default_mtu(dev); =20 @@ -337,7 +365,10 @@ static int can_dbt_changelink(struct net_device *dev, = struct nlattr *data[], dbt_params =3D &priv->fd; tdc_mask =3D CAN_CTRLMODE_FD_TDC_MASK; } else { - return -EOPNOTSUPP; /* Place holder for CAN XL */ + data_bittiming =3D data[IFLA_CAN_XL_DATA_BITTIMING]; + data_tdc =3D data[IFLA_CAN_XL_TDC]; + dbt_params =3D &priv->xl; + tdc_mask =3D CAN_CTRLMODE_XL_TDC_MASK; } =20 if (!data_bittiming) @@ -388,7 +419,7 @@ static int can_dbt_changelink(struct net_device *dev, s= truct nlattr *data[], */ can_calc_tdco(&dbt_params->tdc, dbt_params->tdc_const, &dbt, tdc_mask, &priv->ctrlmode, priv->ctrlmode_supported); - } /* else: both CAN_CTRLMODE_TDC_{AUTO,MANUAL} are explicitly + } /* else: both CAN_CTRLMODE_{,XL}_TDC_{AUTO,MANUAL} are explicitly * turned off. TDC is disabled: do nothing */ =20 @@ -491,6 +522,11 @@ static int can_changelink(struct net_device *dev, stru= ct nlattr *tb[], if (err) return err; =20 + /* CAN XL */ + err =3D can_dbt_changelink(dev, data, false, extack); + if (err) + return err; + if (data[IFLA_CAN_TERMINATION]) { const u16 termval =3D nla_get_u16(data[IFLA_CAN_TERMINATION]); const unsigned int num_term =3D priv->termination_const_cnt; @@ -558,14 +594,14 @@ static size_t can_data_bittiming_get_size(struct data= _bittiming_params *dbt_para { size_t size =3D 0; =20 - if (dbt_params->data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */ + if (dbt_params->data_bittiming.bitrate) /* IFLA_CAN_{,XL}_DATA_BITTIMING= */ size +=3D nla_total_size(sizeof(dbt_params->data_bittiming)); - if (dbt_params->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */ + if (dbt_params->data_bittiming_const) /* IFLA_CAN_{,XL}_DATA_BITTIMING_C= ONST */ size +=3D nla_total_size(sizeof(*dbt_params->data_bittiming_const)); - if (dbt_params->data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */ + if (dbt_params->data_bitrate_const) /* IFLA_CAN_{,XL}_DATA_BITRATE_CONST= */ size +=3D nla_total_size(sizeof(*dbt_params->data_bitrate_const) * dbt_params->data_bitrate_const_cnt); - size +=3D can_tdc_get_size(dbt_params, tdc_flags);/* IFLA_CAN_TDC */ + size +=3D can_tdc_get_size(dbt_params, tdc_flags);/* IFLA_CAN_{,XL}_TDC */ =20 return size; } @@ -605,6 +641,9 @@ static size_t can_get_size(const struct net_device *dev) size +=3D can_data_bittiming_get_size(&priv->fd, priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK); =20 + size +=3D can_data_bittiming_get_size(&priv->xl, + priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MASK); + return size; } =20 @@ -649,7 +688,9 @@ static int can_tdc_fill_info(struct sk_buff *skb, const= struct net_device *dev, tdc_is_enabled =3D can_fd_tdc_is_enabled(priv); tdc_manual =3D priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL; } else { - return -EOPNOTSUPP; /* Place holder for CAN XL */ + dbt_params =3D &priv->xl; + tdc_is_enabled =3D can_xl_tdc_is_enabled(priv); + tdc_manual =3D priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MANUAL; } tdc_const =3D dbt_params->tdc_const; tdc =3D &dbt_params->tdc; @@ -771,7 +812,19 @@ static int can_fill_info(struct sk_buff *skb, const st= ruct net_device *dev) =20 can_tdc_fill_info(skb, dev, IFLA_CAN_TDC) || =20 - can_ctrlmode_ext_fill_info(skb, priv) + can_ctrlmode_ext_fill_info(skb, priv) || + + can_bittiming_fill_info(skb, IFLA_CAN_XL_DATA_BITTIMING, + &priv->xl.data_bittiming) || + + can_bittiming_const_fill_info(skb, IFLA_CAN_XL_DATA_BITTIMING_CONST, + priv->xl.data_bittiming_const) || + + can_bitrate_const_fill_info(skb, IFLA_CAN_XL_DATA_BITRATE_CONST, + priv->xl.data_bitrate_const, + priv->xl.data_bitrate_const_cnt) || + + can_tdc_fill_info(skb, dev, IFLA_CAN_XL_TDC) ) =20 return -EMSGSIZE; diff --git a/include/linux/can/bittiming.h b/include/linux/can/bittiming.h index d30816dd93c7..68d533bb7856 100644 --- a/include/linux/can/bittiming.h +++ b/include/linux/can/bittiming.h @@ -16,10 +16,12 @@ =20 #define CAN_CTRLMODE_FD_TDC_MASK \ (CAN_CTRLMODE_TDC_AUTO | CAN_CTRLMODE_TDC_MANUAL) +#define CAN_CTRLMODE_XL_TDC_MASK \ + (CAN_CTRLMODE_XL_TDC_AUTO | CAN_CTRLMODE_XL_TDC_MANUAL) #define CAN_CTRLMODE_TDC_AUTO_MASK \ - (CAN_CTRLMODE_TDC_AUTO) + (CAN_CTRLMODE_TDC_AUTO | CAN_CTRLMODE_XL_TDC_AUTO) #define CAN_CTRLMODE_TDC_MANUAL_MASK \ - (CAN_CTRLMODE_TDC_MANUAL) + (CAN_CTRLMODE_TDC_MANUAL | CAN_CTRLMODE_XL_TDC_MANUAL) =20 /* * struct can_tdc - CAN FD Transmission Delay Compensation parameters diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 9de8fde3ec9d..945c16743702 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -47,7 +47,7 @@ struct can_priv { =20 const struct can_bittiming_const *bittiming_const; struct can_bittiming bittiming; - struct data_bittiming_params fd; + struct data_bittiming_params fd, xl; unsigned int bitrate_const_cnt; const u32 *bitrate_const; u32 bitrate_max; @@ -85,6 +85,11 @@ static inline bool can_fd_tdc_is_enabled(const struct ca= n_priv *priv) return !!(priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK); } =20 +static inline bool can_xl_tdc_is_enabled(const struct can_priv *priv) +{ + return !!(priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MASK); +} + static inline u32 can_get_static_ctrlmode(struct can_priv *priv) { return priv->ctrlmode & ~priv->ctrlmode_supported; diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netl= ink.h index fafd1cce4798..c2c96c5978a8 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -104,6 +104,9 @@ struct can_ctrlmode { #define CAN_CTRLMODE_TDC_AUTO 0x200 /* FD transceiver automatically calcu= lates TDCV */ #define CAN_CTRLMODE_TDC_MANUAL 0x400 /* FD TDCV is manually set up by us= er */ #define CAN_CTRLMODE_RESTRICTED 0x800 /* Restricted operation mode */ +#define CAN_CTRLMODE_XL 0x1000 /* CAN XL mode */ +#define CAN_CTRLMODE_XL_TDC_AUTO 0x2000 /* XL transceiver automatically ca= lculates TDCV */ +#define CAN_CTRLMODE_XL_TDC_MANUAL 0x4000 /* XL TDCV is manually set up by= user */ =20 /* * CAN device statistics @@ -139,6 +142,10 @@ enum { IFLA_CAN_BITRATE_MAX, IFLA_CAN_TDC, /* FD */ IFLA_CAN_CTRLMODE_EXT, + IFLA_CAN_XL_DATA_BITTIMING, + IFLA_CAN_XL_DATA_BITTIMING_CONST, + IFLA_CAN_XL_DATA_BITRATE_CONST, + IFLA_CAN_XL_TDC, =20 /* add new constants above here */ __IFLA_CAN_MAX, --=20 2.49.1 From nobody Sun Feb 8 12:51:53 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D8975306495; Mon, 13 Oct 2025 11:02:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353343; cv=none; b=gfnML5hWGKvuEpwDUuy8rMcmCyVhXJ6vlQ28Wgc4kj67Oi77PwwGQP4HpTVP7H3NvSz+H+sK/srYDf953mBmnd6wvx+UczjTvKd9geO61Txyvs9XpCE+oK/z8XMSoJNGx7XBcv2CBu0yefwyE1pdTyTnIOocbNWTh3StrvgPKxs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353343; c=relaxed/simple; bh=VMd2jLfl17yXHcMVN4REYXUpVUjagU+Tc7WCN87WQ9s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bu2Rz71Cmegihu3teXdhIH9fIxqsLxbCGSFPMQ0SsnO2i65Voi5xvqHkF25evL1pXBk8//2wLo/Qvm/2BXMQ8pLNAzkTmc0iGXt7TvcWRnR0xH6Ibu7+QlPBs6Dn4OGhJJNNkRpC7QzCiPHeYnO+KpNGrAUifG6nq6HC4nHbxEA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=p0azoQ2J; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="p0azoQ2J" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 40FC8C4AF09; Mon, 13 Oct 2025 11:02:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1760353343; bh=VMd2jLfl17yXHcMVN4REYXUpVUjagU+Tc7WCN87WQ9s=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=p0azoQ2Jm5uR+ocYrqjVeNE8OoyYXqIXysbPTlvq5Da6aXr84amN7liIP/zKu8S7U 2aXbwLa96SXu2vu0UOPMx8qkrYCuhBNW01jPuD8knTTtJl/RBXXJTKPGSeSUktK9gV R2pic4rw5xA6AY+316N957Ye9Kjzl3KbdLhs3Bh/j1fIMGnZ42bAud+2uerpF7Hfco JyD6l8fw/w49ukcAlXHt2j8hd0cxT3tKP/j8rQeQZPE/3FP4IhubqboB/mgYNuHKl5 3uGv26j9M0Z8CJmy9IoSry3WiIbydc4L1oaNirgPX/eZymUBqBawxNB25d8J3tiQfd VtgAmxWx57Ugg== From: Vincent Mailhol Date: Mon, 13 Oct 2025 20:01:26 +0900 Subject: [PATCH 4/9] can: netlink: add CAN_CTRLMODE_XL_TMS flag Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251013-canxl-netlink-v1-4-f422b7e2729f@kernel.org> References: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> In-Reply-To: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> To: Marc Kleine-Budde , Oliver Hartkopp Cc: Vincent Mailhol , =?utf-8?q?St=C3=A9phane_Grosjean?= , Robert Nawrath , Minh Le , Duy Nguyen , linux-can@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=7104; i=mailhol@kernel.org; h=from:subject:message-id; bh=VMd2jLfl17yXHcMVN4REYXUpVUjagU+Tc7WCN87WQ9s=; b=owGbwMvMwCV2McXO4Xp97WbG02pJDBlv7qhK3ukwfZ9WMd9jQlKj2IMX4V2bJE33SfGtfvm2b de57VPPdpSyMIhxMciKKbIsK+fkVugo9A479NcSZg4rE8gQBi5OAZiIExMjw7LbDWZ3u4/m/fnC Vbl86THGB5cuiqycdkpDqCQgfoGiLh8jw8yoS7c6HZdvC5qucVNTK1nOvvOZwsHObS2HhPKe6AQ 3MAMA X-Developer-Key: i=mailhol@kernel.org; a=openpgp; fpr=ED8F700574E67F20E574E8E2AB5FEB886DBB99C2 The Transceiver Mode Switching (TMS) indicates whether the CAN XL controller shall use the PWM or NRZ encoding during the data phase. The term "transceiver mode switching" is used in both ISO 11898-1 and CiA 612-2 (although only the latter one uses the abbreviation TMS). We adopt the same naming convention here for consistency. Add the CAN_CTRLMODE_XL_TMS flag to the list of the CAN control modes. In the netlink interface, each boolean option is in reality a tristate in disguise: on, off or omitted. For the moment, TMS is implemented as below: - CAN_CTRLMODE_XL_TMS is set to false: TMS is disabled. - CAN_CTRLMODE_XL_TMS is set to true: TMS is enabled. - CAN_CTRLMODE_XL_TMS is omitted: return -EOPNOTSUPP. For most of the other control modes, omitting a flag default to the option turned off. It could also be possible to provide a default behaviour if the TMS flag is omitted (i.e. either default to TMS off or on). However, it is not clear for the moment which default behaviour is preferable. If the usage shows a clear trend (for example if the vast majority of the users want TMS on by default), it is still possible to revisit that choice in the future. Whereas once a default option is provided, we can not change it back without breaking the interface. As a corollary, for the moment, the users will be forced to specify the TMS in the ip tool when using CAN XL. Add can_validate_xl_flags() to check the coherency of the TMS flag. That function will be reused in upcoming changes to validate the other CAN XL flags. Signed-off-by: Vincent Mailhol --- Question: Is it still possible to send Classical CAN frames when TMS is on? If not, we need to also add this filter in can_dev_dropped_skb(): if ((priv->ctrlmode & CAN_CTRLMODE_XL_TMS) && !can_is_canxl_skb(skb)) { netdev_info_once(dev, "Classical CAN frames are not allowed under CAN XL's TMS mode\n"); goto invalid_skb; } My current assumption is that this is possible. But the standard being not crystal clear on that point, I want to double check this with you! --- drivers/net/can/dev/dev.c | 2 ++ drivers/net/can/dev/netlink.c | 52 ++++++++++++++++++++++++++++++++++++= +--- include/uapi/linux/can/netlink.h | 1 + 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index 32f11db88295..1de5babcc4f3 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -123,6 +123,8 @@ const char *can_get_ctrlmode_str(u32 ctrlmode) return "xl-tdc-auto"; case CAN_CTRLMODE_XL_TDC_MANUAL: return "xl-tdc-manual"; + case CAN_CTRLMODE_XL_TMS: + return "xl-tms"; default: return ""; } diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index 2405f1265488..8afd2baa03cf 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -181,6 +181,36 @@ static int can_validate_databittiming(struct nlattr *d= ata[], return 0; } =20 +static int can_validate_xl_flags(struct netlink_ext_ack *extack, + u32 masked_flags, u32 mask) +{ + if (masked_flags & CAN_CTRLMODE_XL) { + if (!(mask & CAN_CTRLMODE_XL_TMS)) { + NL_SET_ERR_MSG(extack, "Specify whether TMS is on or off"); + return -EOPNOTSUPP; + } + if (masked_flags & CAN_CTRLMODE_XL_TMS) { + const u32 tms_conflicts_mask =3D CAN_CTRLMODE_FD | + CAN_CTRLMODE_XL_TDC_MASK; + u32 tms_conflicts =3D masked_flags & tms_conflicts_mask; + + if (tms_conflicts) { + NL_SET_ERR_MSG_FMT(extack, + "TMS and %s are mutually exclusive", + can_get_ctrlmode_str(tms_conflicts)); + return -EOPNOTSUPP; + } + } + } else { + if (mask & CAN_CTRLMODE_XL_TMS) { + NL_SET_ERR_MSG(extack, "TMS requires CAN XL"); + return -EOPNOTSUPP; + } + } + + return 0; +} + static int can_validate(struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { @@ -201,6 +231,10 @@ static int can_validate(struct nlattr *tb[], struct nl= attr *data[], "Listen-only and restricted modes are mutually exclusive"); return -EOPNOTSUPP; } + + err =3D can_validate_xl_flags(extack, flags, cm->mask); + if (err) + return err; } =20 err =3D can_validate_bittiming(data, extack, IFLA_CAN_BITTIMING); @@ -227,7 +261,7 @@ static int can_ctrlmode_changelink(struct net_device *d= ev, struct can_priv *priv =3D netdev_priv(dev); struct can_ctrlmode *cm; const u32 xl_mandatory =3D CAN_CTRLMODE_RESTRICTED; - u32 ctrlstatic, maskedflags, notsupp, ctrlstatic_missing, xl_missing; + u32 ctrlstatic, maskedflags, deactivated, notsupp, ctrlstatic_missing, xl= _missing; =20 if (!data[IFLA_CAN_CTRLMODE]) return 0; @@ -239,6 +273,7 @@ static int can_ctrlmode_changelink(struct net_device *d= ev, cm =3D nla_data(data[IFLA_CAN_CTRLMODE]); ctrlstatic =3D can_get_static_ctrlmode(priv); maskedflags =3D cm->flags & cm->mask; + deactivated =3D ~cm->flags & cm->mask; notsupp =3D maskedflags & ~(priv->ctrlmode_supported | ctrlstatic); ctrlstatic_missing =3D (maskedflags & ctrlstatic) ^ ctrlstatic; xl_missing =3D (priv->ctrlmode_supported & xl_mandatory) ^ xl_mandatory; @@ -268,11 +303,21 @@ static int can_ctrlmode_changelink(struct net_device = *dev, return -EOPNOTSUPP; } =20 + /* If FD was active and is not turned off, check for XL conflicts */ + if (priv->ctrlmode & CAN_CTRLMODE_FD & ~deactivated) { + if (maskedflags & CAN_CTRLMODE_XL_TMS) { + NL_SET_ERR_MSG(extack, + "TMS can not be activated while CAN FD is on"); + return -EOPNOTSUPP; + } + } + /* If a top dependency flag is provided, reset all its dependencies */ if (cm->mask & CAN_CTRLMODE_FD) priv->ctrlmode &=3D ~CAN_CTRLMODE_FD_TDC_MASK; if (cm->mask & CAN_CTRLMODE_XL) - priv->ctrlmode &=3D ~(CAN_CTRLMODE_XL_TDC_MASK); + priv->ctrlmode &=3D ~(CAN_CTRLMODE_XL_TDC_MASK | + CAN_CTRLMODE_XL_TMS); =20 /* clear bits to be modified and copy the flag values */ priv->ctrlmode &=3D ~cm->mask; @@ -404,7 +449,8 @@ static int can_dbt_changelink(struct net_device *dev, s= truct nlattr *data[], if (data[IFLA_CAN_CTRLMODE]) { struct can_ctrlmode *cm =3D nla_data(data[IFLA_CAN_CTRLMODE]); =20 - need_tdc_calc =3D !(cm->mask & tdc_mask); + if (fd || !(priv->ctrlmode & CAN_CTRLMODE_XL_TMS)) + need_tdc_calc =3D !(cm->mask & tdc_mask); } if (data_tdc) { /* TDC parameters are provided: use them */ diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netl= ink.h index c2c96c5978a8..ebafb091d80f 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -107,6 +107,7 @@ struct can_ctrlmode { #define CAN_CTRLMODE_XL 0x1000 /* CAN XL mode */ #define CAN_CTRLMODE_XL_TDC_AUTO 0x2000 /* XL transceiver automatically ca= lculates TDCV */ #define CAN_CTRLMODE_XL_TDC_MANUAL 0x4000 /* XL TDCV is manually set up by= user */ +#define CAN_CTRLMODE_XL_TMS 0x8000 /* Transceiver Mode Switching */ =20 /* * CAN device statistics --=20 2.49.1 From nobody Sun Feb 8 12:51:53 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 640233064AE; Mon, 13 Oct 2025 11:02:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353346; cv=none; b=B1WP4z4cHhzbepXl2SMtEmWXjyv2UKnqxi/RNM1gruybEtzSYqUmeBLtDoKthka6lYxmsBHcP1ZwRV0C21fgYhm1idPPD9AyfUc5dCPuupsmymTxPl4JG5Lz7/bVHSRQ7s9QQK7QbYjS4Fgv0jN6BWiRJSwSmfflh7bIGxFolfM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353346; c=relaxed/simple; bh=6kV42cb3h0HsRyg8DtouOGEoKC4sgLl+Ud2Wwg51ybQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=TaHgM+Ah44p2ARo2BShu27GCJJP5r8jB0Dt4b8zRH1p/yEXFhv/7k8OPT3oxXSKThf1npurgysSefgPLXv0UpOugVFSBzQFrWlsZdwCZ2Kcc8pX9DsEgQFvnKO07p7moqSgu/532inKr7nHlFEtvwPGiw46KdOT5Q63aOlZZRaA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=d4xErBXt; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="d4xErBXt" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C9228C116D0; Mon, 13 Oct 2025 11:02:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1760353345; bh=6kV42cb3h0HsRyg8DtouOGEoKC4sgLl+Ud2Wwg51ybQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=d4xErBXtGHbSMiTKcFG+fSF4zSPh0pZs7i9x+QlgTmXFRxWAGSArI7u7/oSaHn0so j3ZLomtEMR1+vQXZXxMqf24ibndcuSRc/hje99u5nM2nSqsjS9hUs/4bQFGGjm3txC 7hZzr/1ULggHpaZpRBcBjhkKJZy8Vzoot2FppbXQaqAWOUykpHg18OfrRi0gttowW6 V5FpNkf92D8mO8rz/sui0VWLHnHW8YNxUtPDQ1ayqcIT5Po+rLFWIpwJIIeYCOkUyH oowD3ucPgkEuDbRft1dd15LmhWzHpjQhNf9ysHtHWDv7UbdgMxCQ+ZIE6KVg8j3tJW 1QZNFwZVoakzw== From: Vincent Mailhol Date: Mon, 13 Oct 2025 20:01:27 +0900 Subject: [PATCH 5/9] can: netlink: add CAN_CTRLMODE_XL_ERR_SIGNAL Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251013-canxl-netlink-v1-5-f422b7e2729f@kernel.org> References: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> In-Reply-To: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> To: Marc Kleine-Budde , Oliver Hartkopp Cc: Vincent Mailhol , =?utf-8?q?St=C3=A9phane_Grosjean?= , Robert Nawrath , Minh Le , Duy Nguyen , linux-can@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=5152; i=mailhol@kernel.org; h=from:subject:message-id; bh=6kV42cb3h0HsRyg8DtouOGEoKC4sgLl+Ud2Wwg51ybQ=; b=owGbwMvMwCV2McXO4Xp97WbG02pJDBlv7miYJAS1eJ9frtm/be+il/Yphh8EZuWohJ35X7Ns0 2abmT+/d5SyMIhxMciKKbIsK+fkVugo9A479NcSZg4rE8gQBi5OAZjIDG1GhqVhIm+t5xZ4p132 CTvimuh8IO3Si/MClid1HRMNt7b3xjH807IWX79yql+5Ocu8pgYWTX2dR8VMCy9e/fNO4WCtrJg ZOwA= X-Developer-Key: i=mailhol@kernel.org; a=openpgp; fpr=ED8F700574E67F20E574E8E2AB5FEB886DBB99C2 Classical CAN and CAN FD must generate error frames on the CAN bus when detecting a protocol violation. CAN XL's error signaling is different and works as follows: - In interoperability mode (both FD and XL), error signaling must be on. - When operating a CAN controller in CAN XL only mode but with TMS off, the user can decide whether the error signalling is enabled or disabled. - On the contrary, when using TMS, error signalling must be off. Introduce the new CAN_CTRLMODE_XL_ERR_SIGNAL control mode. This new option is only made available for CAN XL, so despite the error signalling being always on for Classical CAN and CAN FD, forbid the use of this flag when CAN XL is off. If the user provides the error signalling flag, check its validity. If the flag is omitted, activate error signalling by default whenever possible. This is summarized in below table: CAN_CTRLMODE_XL_ERR_SIGNAL ------------------------------------------- CC/FD option not available CC/FD/XL on XL TMS off configurable (default on) XL TMS on off Suggested-by: Oliver Hartkopp Link: https://lore.kernel.org/linux-can/20250527195625.65252-9-socketcan@ha= rtkopp.net/ Signed-off-by: Vincent Mailhol --- drivers/net/can/dev/dev.c | 2 ++ drivers/net/can/dev/netlink.c | 29 +++++++++++++++++++++++++++-- include/uapi/linux/can/netlink.h | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index 1de5babcc4f3..0c16d0174f7f 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -125,6 +125,8 @@ const char *can_get_ctrlmode_str(u32 ctrlmode) return "xl-tdc-manual"; case CAN_CTRLMODE_XL_TMS: return "xl-tms"; + case CAN_CTRLMODE_XL_ERR_SIGNAL: + return "xl-error-signalling"; default: return ""; } diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index 8afd2baa03cf..6126b191fea0 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -191,7 +191,8 @@ static int can_validate_xl_flags(struct netlink_ext_ack= *extack, } if (masked_flags & CAN_CTRLMODE_XL_TMS) { const u32 tms_conflicts_mask =3D CAN_CTRLMODE_FD | - CAN_CTRLMODE_XL_TDC_MASK; + CAN_CTRLMODE_XL_TDC_MASK | + CAN_CTRLMODE_XL_ERR_SIGNAL; u32 tms_conflicts =3D masked_flags & tms_conflicts_mask; =20 if (tms_conflicts) { @@ -201,11 +202,23 @@ static int can_validate_xl_flags(struct netlink_ext_a= ck *extack, return -EOPNOTSUPP; } } + if ((masked_flags & CAN_CTRLMODE_FD) && + (mask & CAN_CTRLMODE_XL_ERR_SIGNAL) && + !(masked_flags & CAN_CTRLMODE_XL_ERR_SIGNAL)) { + NL_SET_ERR_MSG(extack, + "When using both CAN FD and XL, error signalling must be on"); + return -EOPNOTSUPP; + } } else { if (mask & CAN_CTRLMODE_XL_TMS) { NL_SET_ERR_MSG(extack, "TMS requires CAN XL"); return -EOPNOTSUPP; } + if (mask & CAN_CTRLMODE_XL_ERR_SIGNAL) { + NL_SET_ERR_MSG(extack, + "Error signalling is only configurable with CAN XL"); + return -EOPNOTSUPP; + } } =20 return 0; @@ -310,6 +323,11 @@ static int can_ctrlmode_changelink(struct net_device *= dev, "TMS can not be activated while CAN FD is on"); return -EOPNOTSUPP; } + if (deactivated & CAN_CTRLMODE_XL_ERR_SIGNAL) { + NL_SET_ERR_MSG(extack, + "Error signalling can not be deactivated while CAN FD is on"); + return -EOPNOTSUPP; + } } =20 /* If a top dependency flag is provided, reset all its dependencies */ @@ -317,12 +335,19 @@ static int can_ctrlmode_changelink(struct net_device = *dev, priv->ctrlmode &=3D ~CAN_CTRLMODE_FD_TDC_MASK; if (cm->mask & CAN_CTRLMODE_XL) priv->ctrlmode &=3D ~(CAN_CTRLMODE_XL_TDC_MASK | - CAN_CTRLMODE_XL_TMS); + CAN_CTRLMODE_XL_TMS | + CAN_CTRLMODE_XL_ERR_SIGNAL); =20 /* clear bits to be modified and copy the flag values */ priv->ctrlmode &=3D ~cm->mask; priv->ctrlmode |=3D maskedflags; =20 + /* If omitted, set error signalling on if possible */ + if ((maskedflags & CAN_CTRLMODE_XL) && + !(cm->mask & CAN_CTRLMODE_XL_ERR_SIGNAL) && + !(priv->ctrlmode & CAN_CTRLMODE_XL_TMS)) + priv->ctrlmode |=3D CAN_CTRLMODE_XL_ERR_SIGNAL; + /* Wipe potential leftovers from previous CAN FD/XL config */ if (!(priv->ctrlmode & CAN_CTRLMODE_FD)) { memset(&priv->fd.data_bittiming, 0, diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netl= ink.h index ebafb091d80f..30d446921dc4 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -108,6 +108,7 @@ struct can_ctrlmode { #define CAN_CTRLMODE_XL_TDC_AUTO 0x2000 /* XL transceiver automatically ca= lculates TDCV */ #define CAN_CTRLMODE_XL_TDC_MANUAL 0x4000 /* XL TDCV is manually set up by= user */ #define CAN_CTRLMODE_XL_TMS 0x8000 /* Transceiver Mode Switching */ +#define CAN_CTRLMODE_XL_ERR_SIGNAL 0x10000 /* XL error signalling */ =20 /* * CAN device statistics --=20 2.49.1 From nobody Sun Feb 8 12:51:53 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1AF0E3064BB; Mon, 13 Oct 2025 11:02:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353347; cv=none; b=HsP+24WlKuQpyoY91vpApi5jZNzaaADfuFa0gDoggW4tZRPJS76WG/dR7miBbMs/Er0vTGaiRze1vYzwGQpJaR9f1c4QVOxfQ9Z9hrUa7h6IUkOzGP9Bp7t4PLeuo3aRDrBko+TmgFS71H5fkYv7VtluJtklpNkgdTNYNYD63Gw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353347; c=relaxed/simple; bh=VCnsJDWsm5D9WrzEysRb1OMusmtX+9CwcyZ1XTPf/as=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=CxwYxq5edGjnxMh47+0WktwMukftu6YeLbmxfG/R6eLJPTM8PsdHuqmVzQ/NfMNj5++9oOAE6ZB/PBxFthS9w557Na+qR3uShD0aAxmrGoB7oU5FoVmWtELd8OrvUBgSPon5FzC+bYVkG6k78Cy0M6ul/mqf2JoM3sHLKz61UIQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bKy4i61I; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="bKy4i61I" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5E2BFC4CEFE; Mon, 13 Oct 2025 11:02:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1760353346; bh=VCnsJDWsm5D9WrzEysRb1OMusmtX+9CwcyZ1XTPf/as=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=bKy4i61IWZyhQ43wpkL49gvRgQ53fi2l3nzi2UV4iuFEN76FDBIKhy4JklWZAkco4 FmZ9qkD6X/FN5PZJYkKI438sOvdj4YA5gRgYwQSGQg5hSybH40996I9tLxOS/yKPVY 0GeeHZJ5d0/r6h7YtkoLb6Tf5oNvA3RYdzLDgrsDsmjeO1wd3JNJAEO89DqzdbAncs 0k0bKeWe8o7ejJ9GtqGhqap7LEKuEvzosCDUeuwC7cYe2CVKpq+mogPMioROn+NAO7 vJu0C2lMt+ukUUcUgyVxqThbXVIG8dM1S+6b0GJirgqHXig9/BIzUNmjXoYYJnqcj6 vYm0RQI5KL8ig== From: Vincent Mailhol Date: Mon, 13 Oct 2025 20:01:28 +0900 Subject: [PATCH 6/9] can: bittiming: add PWM parameters Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251013-canxl-netlink-v1-6-f422b7e2729f@kernel.org> References: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> In-Reply-To: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> To: Marc Kleine-Budde , Oliver Hartkopp Cc: Vincent Mailhol , =?utf-8?q?St=C3=A9phane_Grosjean?= , Robert Nawrath , Minh Le , Duy Nguyen , linux-can@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3173; i=mailhol@kernel.org; h=from:subject:message-id; bh=VCnsJDWsm5D9WrzEysRb1OMusmtX+9CwcyZ1XTPf/as=; b=owGbwMvMwCV2McXO4Xp97WbG02pJDBlv7mhPLd4sO+lJXQGPfK6JTLRqs/lCf+eHnLkRKSI9O VuEQhg7SlkYxLgYZMUUWZaVc3IrdBR6hx36awkzh5UJZAgDF6cATGRiHMP/5CtqYRvstT9X6VbO Pzq9UOst78aggh+e1ZMqNuVf0lV+wvDf4a3F0nXrXs24qLn51qwTxxb8v8gY3dfH0pvWb9rBGSP FBwA= X-Developer-Key: i=mailhol@kernel.org; a=openpgp; fpr=ED8F700574E67F20E574E8E2AB5FEB886DBB99C2 In CAN XL, higher data bit rates require the CAN transceiver to switch its operation mode to use Pulse-Width Modulation (PWM) transmission mode instead of the classic dominant/recessive transmission mode. The PWM parameters are: - PWMS: pulse width modulation short phase - PWML: pulse width modulation long phase - PWMO: pulse width modulation offset CiA 612-2 specifies PWMS and PWML to be at least 1 (arguably, PWML shall be at least 2 to respect the PWMS < PWML rule). PWMO's minimum is expected to always be zero. It is added more for consistency than anything else. Add struct can_pwm_const so that the different devices can provide their minimum and maximum values. When TMS is on, the runtime PWMS, PWML and PWMO are needed (either calculated or provided by the user): add struct can_pwm to store these. TDC and PWM can not be used at the same time (TDC can only be used when TMS is off and PWM only when TMS is on). struct can_pwm is thus put together with struct can_tdc inside a union to save some space. The netlink logic will be added in an upcoming change. Signed-off-by: Vincent Mailhol --- include/linux/can/bittiming.h | 41 +++++++++++++++++++++++++++++++++++++++= -- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/include/linux/can/bittiming.h b/include/linux/can/bittiming.h index 68d533bb7856..14ad249aa8cd 100644 --- a/include/linux/can/bittiming.h +++ b/include/linux/can/bittiming.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2020 Pengutronix, Marc Kleine-Budde - * Copyright (c) 2021 Vincent Mailhol + * Copyright (c) 2021-2025 Vincent Mailhol */ =20 #ifndef _CAN_BITTIMING_H @@ -120,11 +120,48 @@ struct can_tdc_const { u32 tdcf_max; }; =20 +/* + * struct can_pwm - CAN Pulse-Width Modulation (PWM) parameters + * + * @pwms: pulse width modulation short phase + * @pwml: pulse width modulation long phase + * @pwmo: pulse width modulation offset + */ +struct can_pwm { + u32 pwms; + u32 pwml; + u32 pwmo; +}; + +/* + * struct can_pwm - CAN hardware-dependent constants for Pulse-Width + * Modulation (PWM) + * + * @pwms_min: PWM short phase minimum value. Must be at least 1. + * @pwms_max: PWM short phase maximum value + * @pwml_min: PWM long phase minimum value. Must be at least 1. + * @pwml_max: PWM long phase maximum value + * @pwmo_min: PWM offset phase minimum value + * @pwmo_max: PWM offset phase maximum value + */ +struct can_pwm_const { + u32 pwms_min; + u32 pwms_max; + u32 pwml_min; + u32 pwml_max; + u32 pwmo_min; + u32 pwmo_max; +}; + struct data_bittiming_params { const struct can_bittiming_const *data_bittiming_const; struct can_bittiming data_bittiming; const struct can_tdc_const *tdc_const; - struct can_tdc tdc; + const struct can_pwm_const *pwm_const; + union { + struct can_tdc tdc; + struct can_pwm pwm; + }; const u32 *data_bitrate_const; unsigned int data_bitrate_const_cnt; int (*do_set_data_bittiming)(struct net_device *dev); --=20 2.49.1 From nobody Sun Feb 8 12:51:53 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CC60A306B32; Mon, 13 Oct 2025 11:02:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353348; cv=none; b=j6ntYYJUhfpHV/XCFjDbXPuHQBKzoc7E4Go+L1iR5M/DQ428n6tkuZ3dMR9Tnv93b8OeMAnAqfCSF4Z9Blg+/xHJiQwaAO+5+4UCRmjtbdZthOUsxJ+C3zo9j5ZEwRHhZLFne4WFJgNYReVyDQvBo11+4IylGT6FiJ1wJsriOh4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353348; c=relaxed/simple; bh=SVkz8ubG9Huc9VSDbQmkkTmS9kcmf6P1SBgnQ67oxnk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=nPKMWOah2RCku35BNJkcndi0cMzFWIULjM+m+mUWmOT+H9YYvaau+Vz7IJeECCmlc69FY8qC+YFvo2VN47avXTMCb6snUXJINT7/J9eA1bH9qBTnCam7gwepOskDvlhGOpXTqVuwuGZ5OMIhjlX8NmoTgv6mjhDXTZpKd6P8hR4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=EEnvAd2Q; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="EEnvAd2Q" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E546EC4CEE7; Mon, 13 Oct 2025 11:02:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1760353348; bh=SVkz8ubG9Huc9VSDbQmkkTmS9kcmf6P1SBgnQ67oxnk=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=EEnvAd2QfBMws7T2upWfyTIMo1N8WuPnWObRzzBjCjCV8d47Gtz3rrPJ97n2l2MC/ FFaNMOegJDbtyZG1boHN9YNq94jvSFrSrR2BI4RVM2k+D9jTjajcNKBFSQe6RE8OGG 4pH3I9depKVg9Mqz4lGPkwOSWZ4FUEo3m186fpXMQ+B22ZRhlMJ0XGz2J+oXit54Y8 7cTB8+k6SHSY/2KTXxEPXnqi1HefNhfS2jQOiHvPI2KZOdDVCOh8HY/YrcjAtVSH6N HbnLYfgWKPT4aDkWoyynI6QKx8cr1vbAU0AqPj6dw2pzExtJSt2f2IR38jN3silOzx wTNZJyb4ANGqA== From: Vincent Mailhol Date: Mon, 13 Oct 2025 20:01:29 +0900 Subject: [PATCH 7/9] can: bittiming: add PWM validation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251013-canxl-netlink-v1-7-f422b7e2729f@kernel.org> References: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> In-Reply-To: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> To: Marc Kleine-Budde , Oliver Hartkopp Cc: Vincent Mailhol , =?utf-8?q?St=C3=A9phane_Grosjean?= , Robert Nawrath , Minh Le , Duy Nguyen , linux-can@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=5186; i=mailhol@kernel.org; h=from:subject:message-id; bh=SVkz8ubG9Huc9VSDbQmkkTmS9kcmf6P1SBgnQ67oxnk=; b=owGbwMvMwCV2McXO4Xp97WbG02pJDBlv7uglvvULsuL0Cf+tHlWcfm5HXvGy2IOv/B5xxHytM qnzLXTuKGVhEONikBVTZFlWzsmt0FHoHXboryXMHFYmkCEMXJwCMJGVdQz/fZQ57oWJ8hUwbWva /+r+XXYXhdD5D5Revyq9ZrL0/9Ez1xgZnnI0f/nX8b+RtWWZiNGkeo0KdqkizRfbd7GZrdmctP8 4KwA= X-Developer-Key: i=mailhol@kernel.org; a=openpgp; fpr=ED8F700574E67F20E574E8E2AB5FEB886DBB99C2 Add can_validate_pwm() to validate the values pwms, pwml and pwml. Error messages are added to each of the checks to inform the user on what went wrong. Refer to those error messages to understand the validation logic. The boundary values CAN_PWM_DECODE_NS (the transceiver minimum decoding margin) and CAN_PWM_NS_MAX (the maximum PWM symbol duration) are hardcoded for the moment. Note that a transceiver capable of bitrates higher than 20 Mbps may be able to handle a CAN_PWM_DECODE_NS below 5 ns. If such transceivers become commercially available, this code could be revisited to make this parameter configurable. For now, leave it static. Signed-off-by: Vincent Mailhol --- drivers/net/can/dev/bittiming.c | 63 +++++++++++++++++++++++++++++++++++++= ++++ include/linux/can/bittiming.h | 22 ++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/drivers/net/can/dev/bittiming.c b/drivers/net/can/dev/bittimin= g.c index 0b93900b1dfa..730b1b254460 100644 --- a/drivers/net/can/dev/bittiming.c +++ b/drivers/net/can/dev/bittiming.c @@ -2,6 +2,7 @@ /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix * Copyright (C) 2006 Andrey Volkov, Varma Electronics * Copyright (C) 2008-2009 Wolfgang Grandegger + * Copyright (c) 2025 Vincent Mailhol */ =20 #include @@ -151,3 +152,65 @@ int can_get_bittiming(const struct net_device *dev, st= ruct can_bittiming *bt, =20 return -EINVAL; } + +int can_validate_pwm_bittiming(const struct net_device *dev, + const struct can_pwm *pwm, + struct netlink_ext_ack *extack) +{ + const struct can_priv *priv =3D netdev_priv(dev); + u32 xl_bit_time_tqmin =3D can_bit_time_tqmin(&priv->xl.data_bittiming); + u32 nom_bit_time_tqmin =3D can_bit_time_tqmin(&priv->bittiming); + u32 pwms_ns =3D can_tqmin_to_ns(pwm->pwms, priv->clock.freq); + u32 pwml_ns =3D can_tqmin_to_ns(pwm->pwml, priv->clock.freq); + + if (pwms_ns + pwml_ns > CAN_PWM_NS_MAX) { + NL_SET_ERR_MSG_FMT(extack, + "The PWM symbol duration: %u ns may no exceed %u ns", + pwms_ns + pwml_ns, CAN_PWM_NS_MAX); + return -EINVAL; + } + + if (pwms_ns < CAN_PWM_DECODE_NS) { + NL_SET_ERR_MSG_FMT(extack, + "PWMS: %u ns shall be at least %u ns", + pwms_ns, CAN_PWM_DECODE_NS); + return -EINVAL; + } + + if (pwm->pwms >=3D pwm->pwml) { + NL_SET_ERR_MSG_FMT(extack, + "PWMS: %u tqmin shall be smaller than PWML: %u tqmin", + pwm->pwms, pwm->pwml); + return -EINVAL; + } + + if (pwml_ns - pwms_ns < 2 * CAN_PWM_DECODE_NS) { + NL_SET_ERR_MSG_FMT(extack, + "At least %u ns shall separate PWMS: %u ns from PMWL: %u ns", + 2 * CAN_PWM_DECODE_NS, pwms_ns, pwml_ns); + return -EINVAL; + } + + if (xl_bit_time_tqmin % (pwm->pwms + pwm->pwml) !=3D 0) { + NL_SET_ERR_MSG_FMT(extack, + "PWM duration: %u tqmin does not divide XL's bit time: %u tqmin", + pwm->pwms + pwm->pwml, xl_bit_time_tqmin); + return -EINVAL; + } + + if (pwm->pwmo >=3D pwm->pwms + pwm->pwml) { + NL_SET_ERR_MSG_FMT(extack, + "PWMO: %u tqmin can not be greater than PWMS + PWML: %u tqmin", + pwm->pwmo, pwm->pwms + pwm->pwml); + return -EINVAL; + } + + if (nom_bit_time_tqmin % (pwm->pwms + pwm->pwml) !=3D pwm->pwmo) { + NL_SET_ERR_MSG_FMT(extack, + "Can not assemble nominal bit time: %u tqmin out of PWMS + PMWL and= PWMO", + nom_bit_time_tqmin); + return -EINVAL; + } + + return 0; +} diff --git a/include/linux/can/bittiming.h b/include/linux/can/bittiming.h index 14ad249aa8cd..02cf9541a1dd 100644 --- a/include/linux/can/bittiming.h +++ b/include/linux/can/bittiming.h @@ -87,6 +87,11 @@ struct can_tdc { u32 tdcf; }; =20 +/* The transceiver decoding margin corresponds to t_Decode in ISO 11898-2 = */ +#define CAN_PWM_DECODE_NS 5 +/* Maximum PWM symbol duration. Corresponds to t_SymbolNom_MAX - t_Decode = */ +#define CAN_PWM_NS_MAX (205 - CAN_PWM_DECODE_NS) + /* * struct can_tdc_const - CAN hardware-dependent constant for * Transmission Delay Compensation @@ -203,6 +208,10 @@ int can_get_bittiming(const struct net_device *dev, st= ruct can_bittiming *bt, const unsigned int bitrate_const_cnt, struct netlink_ext_ack *extack); =20 +int can_validate_pwm_bittiming(const struct net_device *dev, + const struct can_pwm *pwm, + struct netlink_ext_ack *extack); + /* * can_get_relative_tdco() - TDCO relative to the sample point * @@ -245,4 +254,17 @@ static inline unsigned int can_bit_time(const struct c= an_bittiming *bt) return CAN_SYNC_SEG + bt->prop_seg + bt->phase_seg1 + bt->phase_seg2; } =20 +/* Duration of one bit in minimum time quantum */ +static inline unsigned int can_bit_time_tqmin(const struct can_bittiming *= bt) +{ + return can_bit_time(bt) * bt->brp; +} + +/* Convert a duration from minimum a minimum time quantum to nano seconds = */ +static inline u32 can_tqmin_to_ns(u32 tqmin, u32 clock_freq) +{ + return DIV_U64_ROUND_CLOSEST(mul_u32_u32(tqmin, NSEC_PER_SEC), + clock_freq); +} + #endif /* !_CAN_BITTIMING_H */ --=20 2.49.1 From nobody Sun Feb 8 12:51:53 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3E62E306D58; Mon, 13 Oct 2025 11:02:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353350; cv=none; b=fCqGMJCQknQfOW5jrgOUA+E7W0FQO6FYhgf8vImDlinLBYgjOY80wz7wDU6uB1lKsghwAKmVVRiZB5TwOVbvHim5JOvqaZVC7tO0yqdMdc7lAnfl2mwdiKO//K67u7Mts9lqVT+TmBLtHdVbY2ajK2XoC+CVeeDwpmAI14zKwaQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353350; c=relaxed/simple; bh=lGub19npbHTCvhVB1cTDqpyNm/UO+W35qNItTyIqyiM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Uso28pNrrs7/hwZo/GImpumf1rffFBrsqWjRIBAO3f/d/aoC3hP7sH6+iW5Uo9NotzYw3WBIbeI/Gmm+PCjS0rPP95Ix8m3aLh1eVVOi1jwZ5Udigsnb/uAGGusjmw8oSRMLgcRlWL6FEICdqCz2EEssxNAB//GadqFRHGvBKIM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FycjzVD0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FycjzVD0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 796EEC4CEF8; Mon, 13 Oct 2025 11:02:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1760353349; bh=lGub19npbHTCvhVB1cTDqpyNm/UO+W35qNItTyIqyiM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=FycjzVD0eNNXQZo05/P/dZnvY0utLz+zz9v7hI0NWjR/MIc06IMq2/vOTURQkJZCv X+5Gm4ADThntk1IaCmU9ehKeq6gpn6sZmTT46DeRwG1AiBS6DKYzPKzAjbL/eADruC xO4osJX85eJ4dEv5wPCHszHfZQYyHiC0MPTW7rEza9rk3YHbjnYdmAx53tr3CNtPK8 oXH7qjiO46dsJ1LkYCuuA6OCsqtc14eZYksT6a1PZ3MQEIJ4/zCYSCXHLm7HVm6sGv yk5x5lu0J/icII5oB4s9hSE2ncmIxUKsf5PdhShRCEYnoYke1rMbKv0Dola98FdJZK oyC0N6b2tFEyg== From: Vincent Mailhol Date: Mon, 13 Oct 2025 20:01:30 +0900 Subject: [PATCH 8/9] can: calc_bittiming: add PWM calculation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251013-canxl-netlink-v1-8-f422b7e2729f@kernel.org> References: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> In-Reply-To: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> To: Marc Kleine-Budde , Oliver Hartkopp Cc: Vincent Mailhol , =?utf-8?q?St=C3=A9phane_Grosjean?= , Robert Nawrath , Minh Le , Duy Nguyen , linux-can@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3712; i=mailhol@kernel.org; h=from:subject:message-id; bh=lGub19npbHTCvhVB1cTDqpyNm/UO+W35qNItTyIqyiM=; b=owGbwMvMwCV2McXO4Xp97WbG02pJDBlv7hhW172ZwaZavGDOXvOq4H9PmH/fEeeT6WYwXiBuE aKaPCu+o5SFQYyLQVZMkWVZOSe3Qkehd9ihv5Ywc1iZQIYwcHEKwEQesTL8T775lmlRuuPlXsfJ S9+2zeRbWmkf+H7Vh4QjE7/sfx/pnsvwm9XlOsPxnFf3pIID63qiH2/gU3nMHPBjqwv//LXPfnu v4gUA X-Developer-Key: i=mailhol@kernel.org; a=openpgp; fpr=ED8F700574E67F20E574E8E2AB5FEB886DBB99C2 Perform the PWM calculation according to CiA recommendations. Note that for databitrates greater than 5 MBPS, tqmin is less than CAN_PWM_NS_MAX (which is defined to 200 nano seconds), consequently, the result of the division: DIV_ROUND_UP(xl_ns, CAN_PWM_NS_MAX) is one and thus the for loop automatically stops on the first iteration giving a single PWM symbol per bit as expected. Because of that, there is no actual need for a separate conditional branch for when the databitrate is greater than 5 MBPS. Signed-off-by: Vincent Mailhol --- drivers/net/can/dev/calc_bittiming.c | 36 ++++++++++++++++++++++++++++++++= ++++ include/linux/can/bittiming.h | 7 +++++++ 2 files changed, 43 insertions(+) diff --git a/drivers/net/can/dev/calc_bittiming.c b/drivers/net/can/dev/cal= c_bittiming.c index 394d6974f481..268ec6fa7c49 100644 --- a/drivers/net/can/dev/calc_bittiming.c +++ b/drivers/net/can/dev/calc_bittiming.c @@ -2,6 +2,7 @@ /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix * Copyright (C) 2006 Andrey Volkov, Varma Electronics * Copyright (C) 2008-2009 Wolfgang Grandegger + * Copyright (C) 2021-2025 Vincent Mailhol */ =20 #include @@ -198,3 +199,38 @@ void can_calc_tdco(struct can_tdc *tdc, const struct c= an_tdc_const *tdc_const, *ctrlmode |=3D tdc_auto; } } + +int can_calc_pwm(struct net_device *dev, struct netlink_ext_ack *extack) +{ + struct can_priv *priv =3D netdev_priv(dev); + const struct can_pwm_const *pwm_const =3D priv->xl.pwm_const; + struct can_pwm *pwm =3D &priv->xl.pwm; + u32 xl_tqmin =3D can_bit_time_tqmin(&priv->xl.data_bittiming); + u32 xl_ns =3D can_tqmin_to_ns(xl_tqmin, priv->clock.freq); + u32 nom_tqmin =3D can_bit_time_tqmin(&priv->bittiming); + int pwm_per_bit_max =3D xl_tqmin / (pwm_const->pwms_min + pwm_const->pwml= _min); + int pwm_per_bit; + u32 pwm_tqmin; + + /* For 5 MB/s databitrate or greater, xl_ns < CAN_PWM_NS_MAX + * giving us a pwm_per_bit of 1 and the loop immediately breaks + */ + for (pwm_per_bit =3D DIV_ROUND_UP(xl_ns, CAN_PWM_NS_MAX); + pwm_per_bit <=3D pwm_per_bit_max; pwm_per_bit++) + if (xl_tqmin % pwm_per_bit =3D=3D 0) + break; + + if (pwm_per_bit > pwm_per_bit_max) { + NL_SET_ERR_MSG_FMT(extack, + "Can not divide the XL data phase's bit time: %u tqmin into multipl= e PWM symbols", + xl_tqmin); + return -EINVAL; + } + + pwm_tqmin =3D xl_tqmin / pwm_per_bit; + pwm->pwms =3D DIV_ROUND_UP_POW2(pwm_tqmin, 4); + pwm->pwml =3D pwm_tqmin - pwm->pwms; + pwm->pwmo =3D nom_tqmin % pwm_tqmin; + + return 0; +} diff --git a/include/linux/can/bittiming.h b/include/linux/can/bittiming.h index 02cf9541a1dd..e7671a86afcc 100644 --- a/include/linux/can/bittiming.h +++ b/include/linux/can/bittiming.h @@ -180,6 +180,8 @@ int can_calc_bittiming(const struct net_device *dev, st= ruct can_bittiming *bt, void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_co= nst, const struct can_bittiming *dbt, u32 tdc_mask, u32 *ctrlmode, u32 ctrlmode_supported); + +int can_calc_pwm(struct net_device *dev, struct netlink_ext_ack *extack); #else /* !CONFIG_CAN_CALC_BITTIMING */ static inline int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt, @@ -195,6 +197,11 @@ can_calc_tdco(struct can_tdc *tdc, const struct can_td= c_const *tdc_const, u32 tdc_mask, u32 *ctrlmode, u32 ctrlmode_supported) { } + +static inline int +can_calc_pwm(struct net_device *dev, struct netlink_ext_ack *extack) +{ +} #endif /* CONFIG_CAN_CALC_BITTIMING */ =20 void can_sjw_set_default(struct can_bittiming *bt); --=20 2.49.1 From nobody Sun Feb 8 12:51:53 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6372F30749B; Mon, 13 Oct 2025 11:02:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353351; cv=none; b=PmPVxcqQWmJzEcPDlMnk74hLrpCrmAVMhZN0qaUzxcNW8M1sQ98zCeKKEqbeAhR7EjTH62w0P49nKjoIdEC3Bj8MRIC9Fz0Ehe4CBjZE73W8a3XpQwAHSn2j7PDDnA9hz6K99ka1NzCS5llKYdjbaSv+SmxFlgKs4rTP24ctOVw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760353351; c=relaxed/simple; bh=ZfUv8NZEu4CMF8GZueqj7edLnf73gygyR/erCtk+i4k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hlFaqMH/uCACEqvzC/v3Jj6b/5rzmjnTmBkhWP2vvmAXmgjnnJNNQ9m+puYMcplWQZtM0N2zb0w/EJBLsz9YD/MCzBIkRFIuMwx4n0GX8Hv+QCzwJUKPZ8glP60rr9RitSiQ1GlWaPqspO+nXJgdNRbmT2ew+lFHT6xORqrBivc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jMa8vqaK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="jMa8vqaK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0F826C116D0; Mon, 13 Oct 2025 11:02:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1760353351; bh=ZfUv8NZEu4CMF8GZueqj7edLnf73gygyR/erCtk+i4k=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=jMa8vqaKdhzICBsCuPijVzwyxVCseRD6NotUjDnmVH5LLfJvy7cJdLy1ljdJdE5jS R0qtTnWrLkMh95A9gHxtfpaeAAf5jj8av27l4G0Wv3oFWunrPnDp2wkxUy5O/h9GLT aikBKzhjgWWuTxdUzA+JdVVv1krR0A5WwJ8pVBZcJ2MSNo0eTEh1XsPCWVi9Wythcb 9Udr9sNQsp8QMFUkwnONdhDT+kW2oM7MmW5nnaouxEJ4M+3Lqe8wkBogsP3bBNG9cX zkHYFadIUaPRNCsPcHk3HFMFdJk9dvKuV3dBj9WMeb8hDRHs6FrdlJIxVFlmFy/Fib l4v/BDv/ekOLg== From: Vincent Mailhol Date: Mon, 13 Oct 2025 20:01:31 +0900 Subject: [PATCH 9/9] can: netlink: add PWM netlink interface Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251013-canxl-netlink-v1-9-f422b7e2729f@kernel.org> References: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> In-Reply-To: <20251013-canxl-netlink-v1-0-f422b7e2729f@kernel.org> To: Marc Kleine-Budde , Oliver Hartkopp Cc: Vincent Mailhol , =?utf-8?q?St=C3=A9phane_Grosjean?= , Robert Nawrath , Minh Le , Duy Nguyen , linux-can@vger.kernel.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=11959; i=mailhol@kernel.org; h=from:subject:message-id; bh=ZfUv8NZEu4CMF8GZueqj7edLnf73gygyR/erCtk+i4k=; b=owGbwMvMwCV2McXO4Xp97WbG02pJDBlv7phkJm3QfK6c/eOl/Y1pf1InT++WjhY4+pcv/v6HV 8c/GPLe7ihlYRDjYpAVU2RZVs7JrdBR6B126K8lzBxWJpAhDFycAjCRJXsZ/grvv3llsuui7k2X 17fbrN/Jvv7jlYueKR8nLkpVcTZ8m3KZkeF4c/OV1jNLtnE9eMV37WWPz4XF+/xm/FRXl9h4jfv /ngRWAA== X-Developer-Key: i=mailhol@kernel.org; a=openpgp; fpr=ED8F700574E67F20E574E8E2AB5FEB886DBB99C2 When the TMS is switched on, the node uses PWM (Pulse Width Modulation) during the data phase instead of the classic NRZ (Non Return to Zero) encoding. PWM is configured by three parameters: - PWMS: Pulse Width Modulation Short phase - PWML: Pulse Width Modulation Long phase - PWMO: Pulse Width Modulation Offset time For each of these parameters, define three IFLA symbols: - IFLA_CAN_PWM_PWM*_MIN: the minimum allowed value. - IFLA_CAN_PWM_PWM*_MAX: the maximum allowed value. - IFLA_CAN_PWM_PWM*: the runtime value. This results in a total of nine IFLA symbols which are all nested in a parent IFLA_CAN_XL_PWM symbol. IFLA_CAN_PWM_PWM*_MIN and IFLA_CAN_PWM_PWM*_MAX define the range of allowed values and will match the value statically configured by the device in struct can_pwm_const. IFLA_CAN_PWM_PWM* match the runtime values stored in struct can_pwm. Those parameters may only be configured when the tms mode is on. If the PWMS, PWML and PWMO parameters are provided, check that all the needed parameters are present using can_validate_pwm(), then check their value using can_validate_pwm_bittiming(). PWMO defaults to zero if omitted. Otherwise, if CAN_CTRLMODE_XL_TMS is true but none of the PWM parameters are provided, calculate them using can_calc_pwm(). Signed-off-by: Vincent Mailhol --- drivers/net/can/dev/netlink.c | 192 +++++++++++++++++++++++++++++++++++= +++- include/uapi/linux/can/netlink.h | 25 +++++ 2 files changed, 215 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index 6126b191fea0..7f6d853fc550 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -25,6 +25,7 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + = 1] =3D { [IFLA_CAN_XL_DATA_BITTIMING] =3D { .len =3D sizeof(struct can_bittiming) = }, [IFLA_CAN_XL_DATA_BITTIMING_CONST] =3D { .len =3D sizeof(struct can_bitti= ming_const) }, [IFLA_CAN_XL_TDC] =3D { .type =3D NLA_NESTED }, + [IFLA_CAN_XL_PWM] =3D { .type =3D NLA_NESTED }, }; =20 static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] =3D { @@ -39,6 +40,18 @@ static const struct nla_policy can_tdc_policy[IFLA_CAN_T= DC_MAX + 1] =3D { [IFLA_CAN_TDC_TDCF] =3D { .type =3D NLA_U32 }, }; =20 +static const struct nla_policy can_pwm_policy[IFLA_CAN_PWM_MAX + 1] =3D { + [IFLA_CAN_PWM_PWMS_MIN] =3D { .type =3D NLA_U32 }, + [IFLA_CAN_PWM_PWMS_MAX] =3D { .type =3D NLA_U32 }, + [IFLA_CAN_PWM_PWML_MIN] =3D { .type =3D NLA_U32 }, + [IFLA_CAN_PWM_PWML_MAX] =3D { .type =3D NLA_U32 }, + [IFLA_CAN_PWM_PWMO_MIN] =3D { .type =3D NLA_U32 }, + [IFLA_CAN_PWM_PWMO_MAX] =3D { .type =3D NLA_U32 }, + [IFLA_CAN_PWM_PWMS] =3D { .type =3D NLA_U32 }, + [IFLA_CAN_PWM_PWML] =3D { .type =3D NLA_U32 }, + [IFLA_CAN_PWM_PWMO] =3D { .type =3D NLA_U32 }, +}; + static int can_validate_bittiming(struct nlattr *data[], struct netlink_ext_ack *extack, int ifla_can_bittiming) @@ -119,6 +132,40 @@ static int can_validate_tdc(struct nlattr *data_tdc, return 0; } =20 +static int can_validate_pwm(struct nlattr *data[], + struct netlink_ext_ack *extack, u32 flags) +{ + struct nlattr *tb_pwm[IFLA_CAN_PWM_MAX + 1]; + int err; + + if (!data[IFLA_CAN_XL_PWM]) + return 0; + + if (!(flags & CAN_CTRLMODE_XL_TMS)) { + NL_SET_ERR_MSG(extack, "PWM requires TMS"); + return -EOPNOTSUPP; + } + + err =3D nla_parse_nested(tb_pwm, IFLA_CAN_PWM_MAX, data[IFLA_CAN_XL_PWM], + can_pwm_policy, extack); + if (err) + return err; + + if (!tb_pwm[IFLA_CAN_PWM_PWMS] !=3D !tb_pwm[IFLA_CAN_PWM_PWML]) { + NL_SET_ERR_MSG(extack, + "Provide either both PWMS and PWML, or none for automic calculat= ion"); + return -EOPNOTSUPP; + } + + if (tb_pwm[IFLA_CAN_PWM_PWMO] && + (!tb_pwm[IFLA_CAN_PWM_PWMS] || !tb_pwm[IFLA_CAN_PWM_PWML])) { + NL_SET_ERR_MSG(extack, "PWMO requires both PWMS and PWML"); + return -EOPNOTSUPP; + } + + return 0; +} + static int can_validate_databittiming(struct nlattr *data[], struct netlink_ext_ack *extack, int ifla_can_data_bittiming, u32 flags) @@ -264,6 +311,10 @@ static int can_validate(struct nlattr *tb[], struct nl= attr *data[], if (err) return err; =20 + err =3D can_validate_pwm(data, extack, flags); + if (err) + return err; + return 0; } =20 @@ -360,6 +411,7 @@ static int can_ctrlmode_changelink(struct net_device *d= ev, sizeof(priv->fd.data_bittiming)); priv->ctrlmode &=3D ~CAN_CTRLMODE_XL_TDC_MASK; memset(&priv->xl.tdc, 0, sizeof(priv->xl.tdc)); + memset(&priv->xl.pwm, 0, sizeof(priv->xl.pwm)); } =20 can_set_default_mtu(dev); @@ -506,6 +558,76 @@ static int can_dbt_changelink(struct net_device *dev, = struct nlattr *data[], return 0; } =20 +static int can_pwm_changelink(struct net_device *dev, + const struct nlattr *pwm_nla, + struct netlink_ext_ack *extack) +{ + struct can_priv *priv =3D netdev_priv(dev); + const struct can_pwm_const *pwm_const =3D priv->xl.pwm_const; + struct nlattr *tb_pwm[IFLA_CAN_PWM_MAX + 1]; + struct can_pwm pwm =3D { 0 }; + int err; + + if (!(priv->ctrlmode & CAN_CTRLMODE_XL_TMS)) + return 0; + + if (!pwm_const) { + NL_SET_ERR_MSG(extack, "The device does not support PWM"); + return -EOPNOTSUPP; + } + + if (!pwm_nla) + return can_calc_pwm(dev, extack); + + err =3D nla_parse_nested(tb_pwm, IFLA_CAN_PWM_MAX, pwm_nla, + can_pwm_policy, extack); + if (err) + return err; + + if (tb_pwm[IFLA_CAN_PWM_PWMS]) { + pwm.pwms =3D nla_get_u32(tb_pwm[IFLA_CAN_PWM_PWMS]); + if (pwm.pwms < pwm_const->pwms_min || + pwm.pwms > pwm_const->pwms_max) { + NL_SET_ERR_MSG_FMT(extack, + "PWMS: %u tqmin is out of range: %u...%u", + pwm.pwms, pwm_const->pwms_min, + pwm_const->pwms_max); + return -EINVAL; + } + } + + if (tb_pwm[IFLA_CAN_PWM_PWML]) { + pwm.pwml =3D nla_get_u32(tb_pwm[IFLA_CAN_PWM_PWML]); + if (pwm.pwml < pwm_const->pwml_min || + pwm.pwml > pwm_const->pwml_max) { + NL_SET_ERR_MSG_FMT(extack, + "PWML: %u tqmin is out of range: %u...%u", + pwm.pwml, pwm_const->pwml_min, + pwm_const->pwml_max); + return -EINVAL; + } + } + + if (tb_pwm[IFLA_CAN_PWM_PWMO]) { + pwm.pwmo =3D nla_get_u32(tb_pwm[IFLA_CAN_PWM_PWMO]); + if (pwm.pwmo < pwm_const->pwmo_min || + pwm.pwmo > pwm_const->pwmo_max) { + NL_SET_ERR_MSG_FMT(extack, + "PWMO: %u tqmin is out of range: %u...%u", + pwm.pwmo, pwm_const->pwmo_min, + pwm_const->pwmo_max); + return -EINVAL; + } + } + + err =3D can_validate_pwm_bittiming(dev, &pwm, extack); + if (err) + return err; + + priv->xl.pwm =3D pwm; + return 0; +} + static int can_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) @@ -595,6 +717,9 @@ static int can_changelink(struct net_device *dev, struc= t nlattr *tb[], =20 /* CAN XL */ err =3D can_dbt_changelink(dev, data, false, extack); + if (err) + return err; + err =3D can_pwm_changelink(dev, data[IFLA_CAN_XL_PWM], extack); if (err) return err; =20 @@ -683,6 +808,30 @@ static size_t can_ctrlmode_ext_get_size(void) nla_total_size(sizeof(u32)); /* IFLA_CAN_CTRLMODE_SUPPORTED */ } =20 +static size_t can_pwm_get_size(const struct can_pwm_const *pwm_const, + bool pwm_on) +{ + size_t size; + + if (!pwm_const || !pwm_on) + return 0; + + size =3D nla_total_size(0); /* nest IFLA_CAN_PWM */ + + size +=3D nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMS_MIN */ + size +=3D nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMS_MAX */ + size +=3D nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWML_MIN */ + size +=3D nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWML_MAX */ + size +=3D nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMO_MIN */ + size +=3D nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMO_MAX */ + + size +=3D nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMS */ + size +=3D nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWML */ + size +=3D nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMO */ + + return size; +} + static size_t can_get_size(const struct net_device *dev) { struct can_priv *priv =3D netdev_priv(dev); @@ -714,6 +863,8 @@ static size_t can_get_size(const struct net_device *dev) =20 size +=3D can_data_bittiming_get_size(&priv->xl, priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MASK); + size +=3D can_pwm_get_size(priv->xl.pwm_const, /* IFLA_CAN_XL_PWM */ + priv->ctrlmode & CAN_CTRLMODE_XL_TMS); =20 return size; } @@ -812,6 +963,42 @@ static int can_tdc_fill_info(struct sk_buff *skb, cons= t struct net_device *dev, return -EMSGSIZE; } =20 +static int can_pwm_fill_info(struct sk_buff *skb, const struct can_priv *p= riv) +{ + const struct can_pwm_const *pwm_const =3D priv->xl.pwm_const; + const struct can_pwm *pwm =3D &priv->xl.pwm; + struct nlattr *nest; + + if (!pwm_const) + return 0; + + nest =3D nla_nest_start(skb, IFLA_CAN_XL_PWM); + if (!nest) + return -EMSGSIZE; + + if (nla_put_u32(skb, IFLA_CAN_PWM_PWMS_MIN, pwm_const->pwms_min) || + nla_put_u32(skb, IFLA_CAN_PWM_PWMS_MAX, pwm_const->pwms_max) || + nla_put_u32(skb, IFLA_CAN_PWM_PWML_MIN, pwm_const->pwml_min) || + nla_put_u32(skb, IFLA_CAN_PWM_PWML_MAX, pwm_const->pwml_max) || + nla_put_u32(skb, IFLA_CAN_PWM_PWMO_MIN, pwm_const->pwmo_min) || + nla_put_u32(skb, IFLA_CAN_PWM_PWMO_MAX, pwm_const->pwmo_max)) + goto err_cancel; + + if (priv->ctrlmode & CAN_CTRLMODE_XL_TMS) { + if (nla_put_u32(skb, IFLA_CAN_PWM_PWMS, pwm->pwms) || + nla_put_u32(skb, IFLA_CAN_PWM_PWML, pwm->pwml) || + nla_put_u32(skb, IFLA_CAN_PWM_PWMO, pwm->pwmo)) + goto err_cancel; + } + + nla_nest_end(skb, nest); + return 0; + +err_cancel: + nla_nest_cancel(skb, nest); + return -EMSGSIZE; +} + static int can_ctrlmode_ext_fill_info(struct sk_buff *skb, const struct can_priv *priv) { @@ -895,9 +1082,10 @@ static int can_fill_info(struct sk_buff *skb, const s= truct net_device *dev) priv->xl.data_bitrate_const, priv->xl.data_bitrate_const_cnt) || =20 - can_tdc_fill_info(skb, dev, IFLA_CAN_XL_TDC) - ) + can_tdc_fill_info(skb, dev, IFLA_CAN_XL_TDC) || =20 + can_pwm_fill_info(skb, priv) + ) return -EMSGSIZE; =20 return 0; diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netl= ink.h index 30d446921dc4..4497e3b4210f 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -5,6 +5,7 @@ * Definitions for the CAN netlink interface * * Copyright (c) 2009 Wolfgang Grandegger + * Copyright (c) 2021-2025 Vincent Mailhol * * This program is free software; you can redistribute it and/or modify * it under the terms of the version 2 of the GNU General Public License @@ -148,6 +149,7 @@ enum { IFLA_CAN_XL_DATA_BITTIMING_CONST, IFLA_CAN_XL_DATA_BITRATE_CONST, IFLA_CAN_XL_TDC, + IFLA_CAN_XL_PWM, =20 /* add new constants above here */ __IFLA_CAN_MAX, @@ -189,6 +191,29 @@ enum { IFLA_CAN_CTRLMODE_MAX =3D __IFLA_CAN_CTRLMODE - 1 }; =20 +/* + * CAN FD/XL Pulse-Width Modulation (PWM) + * + * Please refer to struct can_pwm_const and can_pwm in + * include/linux/can/bittiming.h for further details. + */ +enum { + IFLA_CAN_PWM_UNSPEC, + IFLA_CAN_PWM_PWMS_MIN, /* u32 */ + IFLA_CAN_PWM_PWMS_MAX, /* u32 */ + IFLA_CAN_PWM_PWML_MIN, /* u32 */ + IFLA_CAN_PWM_PWML_MAX, /* u32 */ + IFLA_CAN_PWM_PWMO_MIN, /* u32 */ + IFLA_CAN_PWM_PWMO_MAX, /* u32 */ + IFLA_CAN_PWM_PWMS, /* u32 */ + IFLA_CAN_PWM_PWML, /* u32 */ + IFLA_CAN_PWM_PWMO, /* u32 */ + + /* add new constants above here */ + __IFLA_CAN_PWM, + IFLA_CAN_PWM_MAX =3D __IFLA_CAN_PWM - 1 +}; + /* u16 termination range: 1..65535 Ohms */ #define CAN_TERMINATION_DISABLED 0 =20 --=20 2.49.1