Skip to content

Commit 113aa91

Browse files
Merge patch series "can: netlink: add CAN XL support"
Marc Kleine-Budde <[email protected]> says: Similarly to how CAN FD reuses the bittiming logic of Classical CAN, CAN XL also reuses the entirety of CAN FD features, and, on top of that, adds new features which are specific to CAN XL. A so-called 'mixed-mode' is intended to have (XL-tolerant) CAN FD nodes and CAN XL nodes on one CAN segment, where the FD-controllers can talk CC/FD and the XL-controllers can talk CC/FD/XL. This mixed-mode utilizes the known error-signalling (ES) for sending CC/FD/XL frames. For CAN FD and CAN XL the tranceiver delay compensation (TDC) is supported to use common CAN and CAN-SIG transceivers. The CANXL-only mode disables the error-signalling in the CAN XL controller. This mode does not allow CC/FD frames to be sent but additionally offers a CAN XL transceiver mode switching (TMS) to send CAN XL frames with up to 20Mbit/s data rate. The TMS utilizes a PWM configuration which is added to the netlink interface. Configured with CAN_CTRLMODE_FD and CAN_CTRLMODE_XL this leads to: FD=0 XL=0 CC-only mode (ES=1) FD=1 XL=0 FD/CC mixed-mode (ES=1) FD=1 XL=1 XL/FD/CC mixed-mode (ES=1) FD=0 XL=1 XL-only mode (ES=0, TMS optional) Patch kernel-patches#1 print defined ctrlmode strings capitalized to increase the readability and to be in line with the 'ip' tool (iproute2). Patch kernel-patches#2 is a small clean-up which makes can_calc_bittiming() use NL_SET_ERR_MSG() instead of netdev_err(). Patch kernel-patches#3 adds a check in can_dev_dropped_skb() to drop CAN FD frames when CAN FD is turned off. Patch kernel-patches#4 adds CAN_CTRLMODE_RESTRICTED. Note that contrary to the other CAN_CTRL_MODE_XL_* that are introduced in the later patches, this control mode is not specific to CAN XL. The nuance is that because this restricted mode was only added in ISO 11898-1:2024, it is made mandatory for CAN XL devices but optional for other protocols. This is why this patch is added as a preparation before introducing the core CAN XL logic. Patch kernel-patches#5 adds all the CAN XL features which are inherited from CAN FD: the nominal bittiming, the data bittiming and the TDC. Patch kernel-patches#6 add a new CAN_CTRLMODE_XL_TMS control mode which is specific to CAN XL to enable the transceiver mode switching (TMS) in XL-only mode. Patch kernel-patches#7 adds a check in can_dev_dropped_skb() to drop CAN CC/FD frames when the CAN XL controller is in CAN XL-only mode. The introduced can_dev_in_xl_only_mode() function also determines the error-signalling configuration for the CAN XL controllers. Patch kernel-patches#8 to kernel-patches#11 add the PWM logic for the CAN XL TMS mode. Patch kernel-patches#12 to kernel-patches#14 add different default sample-points for standard CAN and CAN SIG transceivers (with TDC) and CAN XL transceivers using PWM in the CAN XL TMS mode. Patch kernel-patches#15 add a dummy_can driver for netlink testing and debugging. Patch kernel-patches#16 check CAN frame type (CC/FD/XL) when writing those frames to the CAN_RAW socket and reject them if it's not supported by the CAN interface. Patch kernel-patches#17 increase the resolution when printing the bitrate error and round-up the value to 0.01% in the case the resolution would still provide values which would lead to 0.00%. Link: https://patch.msgid.link/[email protected] Signed-off-by: Marc Kleine-Budde <[email protected]>
2 parents ab084f0 + b360a13 commit 113aa91

File tree

11 files changed

+990
-88
lines changed

11 files changed

+990
-88
lines changed

drivers/net/can/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,23 @@ config CAN_CAN327
124124

125125
If this driver is built as a module, it will be called can327.
126126

127+
config CAN_DUMMY
128+
tristate "Dummy CAN"
129+
help
130+
A dummy CAN module supporting Classical CAN, CAN FD and CAN XL. It
131+
exposes bittiming values which can be configured through the netlink
132+
interface.
133+
134+
The module will simply echo any frame sent to it. If debug messages
135+
are activated, it prints all the CAN bittiming information in the
136+
kernel log. Aside from that it does nothing.
137+
138+
This is convenient for testing the CAN netlink interface. Most of the
139+
users will never need this. If unsure, say NO.
140+
141+
To compile this driver as a module, choose M here: the module will be
142+
called dummy-can.
143+
127144
config CAN_FLEXCAN
128145
tristate "Support for Freescale FLEXCAN based chips"
129146
depends on OF || COLDFIRE || COMPILE_TEST

drivers/net/can/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ obj-$(CONFIG_CAN_CAN327) += can327.o
2121
obj-$(CONFIG_CAN_CC770) += cc770/
2222
obj-$(CONFIG_CAN_C_CAN) += c_can/
2323
obj-$(CONFIG_CAN_CTUCANFD) += ctucanfd/
24+
obj-$(CONFIG_CAN_DUMMY) += dummy_can.o
2425
obj-$(CONFIG_CAN_FLEXCAN) += flexcan/
2526
obj-$(CONFIG_CAN_GRCAN) += grcan.o
2627
obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/

drivers/net/can/dev/bittiming.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
33
* Copyright (C) 2006 Andrey Volkov, Varma Electronics
44
* Copyright (C) 2008-2009 Wolfgang Grandegger <[email protected]>
5+
* Copyright (c) 2025 Vincent Mailhol <[email protected]>
56
*/
67

78
#include <linux/can/dev.h>
@@ -151,3 +152,65 @@ int can_get_bittiming(const struct net_device *dev, struct can_bittiming *bt,
151152

152153
return -EINVAL;
153154
}
155+
156+
int can_validate_pwm_bittiming(const struct net_device *dev,
157+
const struct can_pwm *pwm,
158+
struct netlink_ext_ack *extack)
159+
{
160+
const struct can_priv *priv = netdev_priv(dev);
161+
u32 xl_bit_time_tqmin = can_bit_time_tqmin(&priv->xl.data_bittiming);
162+
u32 nom_bit_time_tqmin = can_bit_time_tqmin(&priv->bittiming);
163+
u32 pwms_ns = can_tqmin_to_ns(pwm->pwms, priv->clock.freq);
164+
u32 pwml_ns = can_tqmin_to_ns(pwm->pwml, priv->clock.freq);
165+
166+
if (pwms_ns + pwml_ns > CAN_PWM_NS_MAX) {
167+
NL_SET_ERR_MSG_FMT(extack,
168+
"The PWM symbol duration: %u ns may not exceed %u ns",
169+
pwms_ns + pwml_ns, CAN_PWM_NS_MAX);
170+
return -EINVAL;
171+
}
172+
173+
if (pwms_ns < CAN_PWM_DECODE_NS) {
174+
NL_SET_ERR_MSG_FMT(extack,
175+
"PWMS: %u ns shall be at least %u ns",
176+
pwms_ns, CAN_PWM_DECODE_NS);
177+
return -EINVAL;
178+
}
179+
180+
if (pwm->pwms >= pwm->pwml) {
181+
NL_SET_ERR_MSG_FMT(extack,
182+
"PWMS: %u tqmin shall be smaller than PWML: %u tqmin",
183+
pwm->pwms, pwm->pwml);
184+
return -EINVAL;
185+
}
186+
187+
if (pwml_ns - pwms_ns < 2 * CAN_PWM_DECODE_NS) {
188+
NL_SET_ERR_MSG_FMT(extack,
189+
"At least %u ns shall separate PWMS: %u ns from PMWL: %u ns",
190+
2 * CAN_PWM_DECODE_NS, pwms_ns, pwml_ns);
191+
return -EINVAL;
192+
}
193+
194+
if (xl_bit_time_tqmin % (pwm->pwms + pwm->pwml) != 0) {
195+
NL_SET_ERR_MSG_FMT(extack,
196+
"PWM duration: %u tqmin does not divide XL's bit time: %u tqmin",
197+
pwm->pwms + pwm->pwml, xl_bit_time_tqmin);
198+
return -EINVAL;
199+
}
200+
201+
if (pwm->pwmo >= pwm->pwms + pwm->pwml) {
202+
NL_SET_ERR_MSG_FMT(extack,
203+
"PWMO: %u tqmin can not be greater than PWMS + PWML: %u tqmin",
204+
pwm->pwmo, pwm->pwms + pwm->pwml);
205+
return -EINVAL;
206+
}
207+
208+
if (nom_bit_time_tqmin % (pwm->pwms + pwm->pwml) != pwm->pwmo) {
209+
NL_SET_ERR_MSG_FMT(extack,
210+
"Can not assemble nominal bit time: %u tqmin out of PWMS + PMWL and PWMO",
211+
nom_bit_time_tqmin);
212+
return -EINVAL;
213+
}
214+
215+
return 0;
216+
}

drivers/net/can/dev/calc_bittiming.c

Lines changed: 88 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,41 @@
22
/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
33
* Copyright (C) 2006 Andrey Volkov, Varma Electronics
44
* Copyright (C) 2008-2009 Wolfgang Grandegger <[email protected]>
5+
* Copyright (C) 2021-2025 Vincent Mailhol <[email protected]>
56
*/
67

78
#include <linux/units.h>
89
#include <linux/can/dev.h>
910

1011
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
1112

13+
/* CiA recommended sample points for Non Return to Zero encoding. */
14+
static int can_calc_sample_point_nrz(const struct can_bittiming *bt)
15+
{
16+
if (bt->bitrate > 800 * KILO /* BPS */)
17+
return 750;
18+
19+
if (bt->bitrate > 500 * KILO /* BPS */)
20+
return 800;
21+
22+
return 875;
23+
}
24+
25+
/* Sample points for Pulse-Width Modulation encoding. */
26+
static int can_calc_sample_point_pwm(const struct can_bittiming *bt)
27+
{
28+
if (bt->bitrate > 15 * MEGA /* BPS */)
29+
return 625;
30+
31+
if (bt->bitrate > 9 * MEGA /* BPS */)
32+
return 600;
33+
34+
if (bt->bitrate > 4 * MEGA /* BPS */)
35+
return 560;
36+
37+
return 520;
38+
}
39+
1240
/* Bit-timing calculation derived from:
1341
*
1442
* Code based on LinCAN sources and H8S2638 project
@@ -23,7 +51,7 @@
2351
*/
2452
static int
2553
can_update_sample_point(const struct can_bittiming_const *btc,
26-
const unsigned int sample_point_nominal, const unsigned int tseg,
54+
const unsigned int sample_point_reference, const unsigned int tseg,
2755
unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
2856
unsigned int *sample_point_error_ptr)
2957
{
@@ -34,7 +62,7 @@ can_update_sample_point(const struct can_bittiming_const *btc,
3462

3563
for (i = 0; i <= 1; i++) {
3664
tseg2 = tseg + CAN_SYNC_SEG -
37-
(sample_point_nominal * (tseg + CAN_SYNC_SEG)) /
65+
(sample_point_reference * (tseg + CAN_SYNC_SEG)) /
3866
1000 - i;
3967
tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
4068
tseg1 = tseg - tseg2;
@@ -45,9 +73,9 @@ can_update_sample_point(const struct can_bittiming_const *btc,
4573

4674
sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) /
4775
(tseg + CAN_SYNC_SEG);
48-
sample_point_error = abs(sample_point_nominal - sample_point);
76+
sample_point_error = abs(sample_point_reference - sample_point);
4977

50-
if (sample_point <= sample_point_nominal &&
78+
if (sample_point <= sample_point_reference &&
5179
sample_point_error < best_sample_point_error) {
5280
best_sample_point = sample_point;
5381
best_sample_point_error = sample_point_error;
@@ -67,28 +95,24 @@ int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
6795
{
6896
struct can_priv *priv = netdev_priv(dev);
6997
unsigned int bitrate; /* current bitrate */
70-
unsigned int bitrate_error; /* difference between current and nominal value */
98+
unsigned int bitrate_error; /* diff between calculated and reference value */
7199
unsigned int best_bitrate_error = UINT_MAX;
72-
unsigned int sample_point_error; /* difference between current and nominal value */
100+
unsigned int sample_point_error; /* diff between calculated and reference value */
73101
unsigned int best_sample_point_error = UINT_MAX;
74-
unsigned int sample_point_nominal; /* nominal sample point */
102+
unsigned int sample_point_reference; /* reference sample point */
75103
unsigned int best_tseg = 0; /* current best value for tseg */
76104
unsigned int best_brp = 0; /* current best value for brp */
77105
unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
78106
u64 v64;
79107
int err;
80108

81-
/* Use CiA recommended sample points */
82-
if (bt->sample_point) {
83-
sample_point_nominal = bt->sample_point;
84-
} else {
85-
if (bt->bitrate > 800 * KILO /* BPS */)
86-
sample_point_nominal = 750;
87-
else if (bt->bitrate > 500 * KILO /* BPS */)
88-
sample_point_nominal = 800;
89-
else
90-
sample_point_nominal = 875;
91-
}
109+
if (bt->sample_point)
110+
sample_point_reference = bt->sample_point;
111+
else if (btc == priv->xl.data_bittiming_const &&
112+
(priv->ctrlmode & CAN_CTRLMODE_XL_TMS))
113+
sample_point_reference = can_calc_sample_point_pwm(bt);
114+
else
115+
sample_point_reference = can_calc_sample_point_nrz(bt);
92116

93117
/* tseg even = round down, odd = round up */
94118
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
@@ -114,7 +138,7 @@ int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
114138
if (bitrate_error < best_bitrate_error)
115139
best_sample_point_error = UINT_MAX;
116140

117-
can_update_sample_point(btc, sample_point_nominal, tseg / 2,
141+
can_update_sample_point(btc, sample_point_reference, tseg / 2,
118142
&tseg1, &tseg2, &sample_point_error);
119143
if (sample_point_error >= best_sample_point_error)
120144
continue;
@@ -129,23 +153,26 @@ int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
129153
}
130154

131155
if (best_bitrate_error) {
132-
/* Error in one-tenth of a percent */
133-
v64 = (u64)best_bitrate_error * 1000;
156+
/* Error in one-hundredth of a percent */
157+
v64 = (u64)best_bitrate_error * 10000;
134158
do_div(v64, bt->bitrate);
135159
bitrate_error = (u32)v64;
160+
/* print at least 0.01% if the error is smaller */
161+
bitrate_error = max(bitrate_error, 1U);
136162
if (bitrate_error > CAN_CALC_MAX_ERROR) {
137163
NL_SET_ERR_MSG_FMT(extack,
138-
"bitrate error: %u.%u%% too high",
139-
bitrate_error / 10, bitrate_error % 10);
164+
"bitrate error: %u.%02u%% too high",
165+
bitrate_error / 100,
166+
bitrate_error % 100);
140167
return -EINVAL;
141168
}
142169
NL_SET_ERR_MSG_FMT(extack,
143-
"bitrate error: %u.%u%%",
144-
bitrate_error / 10, bitrate_error % 10);
170+
"bitrate error: %u.%02u%%",
171+
bitrate_error / 100, bitrate_error % 100);
145172
}
146173

147174
/* real sample point */
148-
bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
175+
bt->sample_point = can_update_sample_point(btc, sample_point_reference,
149176
best_tseg, &tseg1, &tseg2,
150177
NULL);
151178

@@ -198,3 +225,38 @@ void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const,
198225
*ctrlmode |= tdc_auto;
199226
}
200227
}
228+
229+
int can_calc_pwm(struct net_device *dev, struct netlink_ext_ack *extack)
230+
{
231+
struct can_priv *priv = netdev_priv(dev);
232+
const struct can_pwm_const *pwm_const = priv->xl.pwm_const;
233+
struct can_pwm *pwm = &priv->xl.pwm;
234+
u32 xl_tqmin = can_bit_time_tqmin(&priv->xl.data_bittiming);
235+
u32 xl_ns = can_tqmin_to_ns(xl_tqmin, priv->clock.freq);
236+
u32 nom_tqmin = can_bit_time_tqmin(&priv->bittiming);
237+
int pwm_per_bit_max = xl_tqmin / (pwm_const->pwms_min + pwm_const->pwml_min);
238+
int pwm_per_bit;
239+
u32 pwm_tqmin;
240+
241+
/* For 5 MB/s databitrate or greater, xl_ns < CAN_PWM_NS_MAX
242+
* giving us a pwm_per_bit of 1 and the loop immediately breaks
243+
*/
244+
for (pwm_per_bit = DIV_ROUND_UP(xl_ns, CAN_PWM_NS_MAX);
245+
pwm_per_bit <= pwm_per_bit_max; pwm_per_bit++)
246+
if (xl_tqmin % pwm_per_bit == 0)
247+
break;
248+
249+
if (pwm_per_bit > pwm_per_bit_max) {
250+
NL_SET_ERR_MSG_FMT(extack,
251+
"Can not divide the XL data phase's bit time: %u tqmin into multiple PWM symbols",
252+
xl_tqmin);
253+
return -EINVAL;
254+
}
255+
256+
pwm_tqmin = xl_tqmin / pwm_per_bit;
257+
pwm->pwms = DIV_ROUND_UP_POW2(pwm_tqmin, 4);
258+
pwm->pwml = pwm_tqmin - pwm->pwms;
259+
pwm->pwmo = nom_tqmin % pwm_tqmin;
260+
261+
return 0;
262+
}

drivers/net/can/dev/dev.c

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,29 +92,39 @@ const char *can_get_ctrlmode_str(u32 ctrlmode)
9292
{
9393
switch (ctrlmode & ~(ctrlmode - 1)) {
9494
case 0:
95-
return "none";
95+
return "(none)";
9696
case CAN_CTRLMODE_LOOPBACK:
97-
return "loopback";
97+
return "LOOPBACK";
9898
case CAN_CTRLMODE_LISTENONLY:
99-
return "listen-only";
99+
return "LISTEN-ONLY";
100100
case CAN_CTRLMODE_3_SAMPLES:
101-
return "triple-sampling";
101+
return "TRIPLE-SAMPLING";
102102
case CAN_CTRLMODE_ONE_SHOT:
103-
return "one-shot";
103+
return "ONE-SHOT";
104104
case CAN_CTRLMODE_BERR_REPORTING:
105-
return "berr-reporting";
105+
return "BERR-REPORTING";
106106
case CAN_CTRLMODE_FD:
107-
return "fd";
107+
return "FD";
108108
case CAN_CTRLMODE_PRESUME_ACK:
109-
return "presume-ack";
109+
return "PRESUME-ACK";
110110
case CAN_CTRLMODE_FD_NON_ISO:
111-
return "fd-non-iso";
111+
return "FD-NON-ISO";
112112
case CAN_CTRLMODE_CC_LEN8_DLC:
113-
return "cc-len8-dlc";
113+
return "CC-LEN8-DLC";
114114
case CAN_CTRLMODE_TDC_AUTO:
115-
return "fd-tdc-auto";
115+
return "TDC-AUTO";
116116
case CAN_CTRLMODE_TDC_MANUAL:
117-
return "fd-tdc-manual";
117+
return "TDC-MANUAL";
118+
case CAN_CTRLMODE_RESTRICTED:
119+
return "RESTRICTED";
120+
case CAN_CTRLMODE_XL:
121+
return "XL";
122+
case CAN_CTRLMODE_XL_TDC_AUTO:
123+
return "XL-TDC-AUTO";
124+
case CAN_CTRLMODE_XL_TDC_MANUAL:
125+
return "XL-TDC-MANUAL";
126+
case CAN_CTRLMODE_XL_TMS:
127+
return "TMS";
118128
default:
119129
return "<unknown>";
120130
}
@@ -348,7 +358,13 @@ void can_set_default_mtu(struct net_device *dev)
348358
{
349359
struct can_priv *priv = netdev_priv(dev);
350360

351-
if (priv->ctrlmode & CAN_CTRLMODE_FD) {
361+
if (priv->ctrlmode & CAN_CTRLMODE_XL) {
362+
if (can_is_canxl_dev_mtu(dev->mtu))
363+
return;
364+
dev->mtu = CANXL_MTU;
365+
dev->min_mtu = CANXL_MIN_MTU;
366+
dev->max_mtu = CANXL_MAX_MTU;
367+
} else if (priv->ctrlmode & CAN_CTRLMODE_FD) {
352368
dev->mtu = CANFD_MTU;
353369
dev->min_mtu = CANFD_MTU;
354370
dev->max_mtu = CANFD_MTU;

0 commit comments

Comments
 (0)