Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: bittiming: add PWM validation

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 <mailhol@kernel.org>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20251126-canxl-v8-9-e7e3eb74f889@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Vincent Mailhol and committed by
Marc Kleine-Budde
8e2a2885 f6ccc2b2

+85
+63
drivers/net/can/dev/bittiming.c
··· 2 2 /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix 3 3 * Copyright (C) 2006 Andrey Volkov, Varma Electronics 4 4 * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> 5 + * Copyright (c) 2025 Vincent Mailhol <mailhol@kernel.org> 5 6 */ 6 7 7 8 #include <linux/can/dev.h> ··· 151 150 bitrate_const_cnt, extack); 152 151 153 152 return -EINVAL; 153 + } 154 + 155 + int can_validate_pwm_bittiming(const struct net_device *dev, 156 + const struct can_pwm *pwm, 157 + struct netlink_ext_ack *extack) 158 + { 159 + const struct can_priv *priv = netdev_priv(dev); 160 + u32 xl_bit_time_tqmin = can_bit_time_tqmin(&priv->xl.data_bittiming); 161 + u32 nom_bit_time_tqmin = can_bit_time_tqmin(&priv->bittiming); 162 + u32 pwms_ns = can_tqmin_to_ns(pwm->pwms, priv->clock.freq); 163 + u32 pwml_ns = can_tqmin_to_ns(pwm->pwml, priv->clock.freq); 164 + 165 + if (pwms_ns + pwml_ns > CAN_PWM_NS_MAX) { 166 + NL_SET_ERR_MSG_FMT(extack, 167 + "The PWM symbol duration: %u ns may not exceed %u ns", 168 + pwms_ns + pwml_ns, CAN_PWM_NS_MAX); 169 + return -EINVAL; 170 + } 171 + 172 + if (pwms_ns < CAN_PWM_DECODE_NS) { 173 + NL_SET_ERR_MSG_FMT(extack, 174 + "PWMS: %u ns shall be at least %u ns", 175 + pwms_ns, CAN_PWM_DECODE_NS); 176 + return -EINVAL; 177 + } 178 + 179 + if (pwm->pwms >= pwm->pwml) { 180 + NL_SET_ERR_MSG_FMT(extack, 181 + "PWMS: %u tqmin shall be smaller than PWML: %u tqmin", 182 + pwm->pwms, pwm->pwml); 183 + return -EINVAL; 184 + } 185 + 186 + if (pwml_ns - pwms_ns < 2 * CAN_PWM_DECODE_NS) { 187 + NL_SET_ERR_MSG_FMT(extack, 188 + "At least %u ns shall separate PWMS: %u ns from PMWL: %u ns", 189 + 2 * CAN_PWM_DECODE_NS, pwms_ns, pwml_ns); 190 + return -EINVAL; 191 + } 192 + 193 + if (xl_bit_time_tqmin % (pwm->pwms + pwm->pwml) != 0) { 194 + NL_SET_ERR_MSG_FMT(extack, 195 + "PWM duration: %u tqmin does not divide XL's bit time: %u tqmin", 196 + pwm->pwms + pwm->pwml, xl_bit_time_tqmin); 197 + return -EINVAL; 198 + } 199 + 200 + if (pwm->pwmo >= pwm->pwms + pwm->pwml) { 201 + NL_SET_ERR_MSG_FMT(extack, 202 + "PWMO: %u tqmin can not be greater than PWMS + PWML: %u tqmin", 203 + pwm->pwmo, pwm->pwms + pwm->pwml); 204 + return -EINVAL; 205 + } 206 + 207 + if (nom_bit_time_tqmin % (pwm->pwms + pwm->pwml) != pwm->pwmo) { 208 + NL_SET_ERR_MSG_FMT(extack, 209 + "Can not assemble nominal bit time: %u tqmin out of PWMS + PMWL and PWMO", 210 + nom_bit_time_tqmin); 211 + return -EINVAL; 212 + } 213 + 214 + return 0; 154 215 }
+22
include/linux/can/bittiming.h
··· 87 87 u32 tdcf; 88 88 }; 89 89 90 + /* The transceiver decoding margin corresponds to t_Decode in ISO 11898-2 */ 91 + #define CAN_PWM_DECODE_NS 5 92 + /* Maximum PWM symbol duration. Corresponds to t_SymbolNom_MAX - t_Decode */ 93 + #define CAN_PWM_NS_MAX (205 - CAN_PWM_DECODE_NS) 94 + 90 95 /* 91 96 * struct can_tdc_const - CAN hardware-dependent constant for 92 97 * Transmission Delay Compensation ··· 208 203 const unsigned int bitrate_const_cnt, 209 204 struct netlink_ext_ack *extack); 210 205 206 + int can_validate_pwm_bittiming(const struct net_device *dev, 207 + const struct can_pwm *pwm, 208 + struct netlink_ext_ack *extack); 209 + 211 210 /* 212 211 * can_get_relative_tdco() - TDCO relative to the sample point 213 212 * ··· 252 243 static inline unsigned int can_bit_time(const struct can_bittiming *bt) 253 244 { 254 245 return CAN_SYNC_SEG + bt->prop_seg + bt->phase_seg1 + bt->phase_seg2; 246 + } 247 + 248 + /* Duration of one bit in minimum time quantum */ 249 + static inline unsigned int can_bit_time_tqmin(const struct can_bittiming *bt) 250 + { 251 + return can_bit_time(bt) * bt->brp; 252 + } 253 + 254 + /* Convert a duration from minimum a minimum time quantum to nano seconds */ 255 + static inline u32 can_tqmin_to_ns(u32 tqmin, u32 clock_freq) 256 + { 257 + return DIV_U64_ROUND_CLOSEST(mul_u32_u32(tqmin, NSEC_PER_SEC), 258 + clock_freq); 255 259 } 256 260 257 261 #endif /* !_CAN_BITTIMING_H */