diff options
Diffstat (limited to 'include/linux/can')
| -rw-r--r-- | include/linux/can/bittiming.h | 125 | ||||
| -rw-r--r-- | include/linux/can/can-ml.h | 24 | ||||
| -rw-r--r-- | include/linux/can/core.h | 1 | ||||
| -rw-r--r-- | include/linux/can/dev.h | 140 | ||||
| -rw-r--r-- | include/linux/can/dev/peak_canfd.h | 4 | ||||
| -rw-r--r-- | include/linux/can/skb.h | 38 |
6 files changed, 221 insertions, 111 deletions
diff --git a/include/linux/can/bittiming.h b/include/linux/can/bittiming.h index 9b8a9c39614b..726d909e87ce 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 <kernel@pengutronix.de> - * Copyright (c) 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr> + * Copyright (c) 2021-2025 Vincent Mailhol <mailhol@kernel.org> */ #ifndef _CAN_BITTIMING_H @@ -14,8 +14,14 @@ #define CAN_BITRATE_UNSET 0 #define CAN_BITRATE_UNKNOWN (-1U) -#define CAN_CTRLMODE_TDC_MASK \ +#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_XL_TDC_AUTO) +#define CAN_CTRLMODE_TDC_MANUAL_MASK \ + (CAN_CTRLMODE_TDC_MANUAL | CAN_CTRLMODE_XL_TDC_MANUAL) /* * struct can_tdc - CAN FD Transmission Delay Compensation parameters @@ -81,6 +87,11 @@ struct can_tdc { u32 tdcf; }; +/* 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 @@ -114,27 +125,85 @@ struct can_tdc_const { u32 tdcf_max; }; +/* + * 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; + 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); + int (*do_get_auto_tdcv)(const struct net_device *dev, u32 *tdcv); +}; + #ifdef CONFIG_CAN_CALC_BITTIMING int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt, const struct can_bittiming_const *btc, struct netlink_ext_ack *extack); void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const, const struct can_bittiming *dbt, - u32 *ctrlmode, u32 ctrlmode_supported); + 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, const struct can_bittiming_const *btc, struct netlink_ext_ack *extack) { - netdev_err(dev, "bit-timing calculation not available\n"); + NL_SET_ERR_MSG(extack, "bit-timing calculation not available\n"); return -EINVAL; } static inline void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const, const struct can_bittiming *dbt, - u32 *ctrlmode, u32 ctrlmode_supported) + u32 tdc_mask, u32 *ctrlmode, u32 ctrlmode_supported) +{ +} + +static inline int +can_calc_pwm(struct net_device *dev, struct netlink_ext_ack *extack) { + NL_SET_ERR_MSG(extack, + "bit-timing calculation not available: manually provide PWML and PWMS\n"); + return -EINVAL; } #endif /* CONFIG_CAN_CALC_BITTIMING */ @@ -149,6 +218,39 @@ int can_get_bittiming(const struct net_device *dev, struct can_bittiming *bt, const unsigned int bitrate_const_cnt, struct netlink_ext_ack *extack); +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 + * + * struct can_tdc::tdco represents the absolute offset from TDCV. Some + * controllers use instead an offset relative to the Sample Point (SP) + * such that: + * + * SSP = TDCV + absolute TDCO + * = TDCV + SP + relative TDCO + * + * -+----------- one bit ----------+-- TX pin + * |<--- Sample Point --->| + * + * --+----------- one bit ----------+-- RX pin + * |<-------- TDCV -------->| + * |<------------------------>| absolute TDCO + * |<--- Sample Point --->| + * | |<->| relative TDCO + * |<------------- Secondary Sample Point ------------>| + */ +static inline s32 can_get_relative_tdco(const struct data_bittiming_params *dbt_params) +{ + const struct can_bittiming *dbt = &dbt_params->data_bittiming; + s32 sample_point_in_tc = (CAN_SYNC_SEG + dbt->prop_seg + + dbt->phase_seg1) * dbt->brp; + + return (s32)dbt_params->tdc.tdco - sample_point_in_tc; +} + /* * can_bit_time() - Duration of one bit * @@ -162,4 +264,17 @@ static inline unsigned int can_bit_time(const struct can_bittiming *bt) return CAN_SYNC_SEG + bt->prop_seg + bt->phase_seg1 + bt->phase_seg2; } +/* 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 */ diff --git a/include/linux/can/can-ml.h b/include/linux/can/can-ml.h index 8afa92d15a66..1e99fda2b380 100644 --- a/include/linux/can/can-ml.h +++ b/include/linux/can/can-ml.h @@ -46,6 +46,12 @@ #include <linux/list.h> #include <linux/netdevice.h> +/* exposed CAN device capabilities for network layer */ +#define CAN_CAP_CC BIT(0) /* CAN CC aka Classical CAN */ +#define CAN_CAP_FD BIT(1) /* CAN FD */ +#define CAN_CAP_XL BIT(2) /* CAN XL */ +#define CAN_CAP_RO BIT(3) /* read-only mode (LISTEN/RESTRICTED) */ + #define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS) #define CAN_EFF_RCV_HASH_BITS 10 #define CAN_EFF_RCV_ARRAY_SZ (1 << CAN_EFF_RCV_HASH_BITS) @@ -64,6 +70,7 @@ struct can_ml_priv { #ifdef CAN_J1939 struct j1939_priv *j1939_priv; #endif + u32 can_cap; }; static inline struct can_ml_priv *can_get_ml_priv(struct net_device *dev) @@ -77,4 +84,21 @@ static inline void can_set_ml_priv(struct net_device *dev, netdev_set_ml_priv(dev, ml_priv, ML_PRIV_CAN); } +static inline bool can_cap_enabled(struct net_device *dev, u32 cap) +{ + struct can_ml_priv *can_ml = can_get_ml_priv(dev); + + if (!can_ml) + return false; + + return (can_ml->can_cap & cap); +} + +static inline void can_set_cap(struct net_device *dev, u32 cap) +{ + struct can_ml_priv *can_ml = can_get_ml_priv(dev); + + can_ml->can_cap = cap; +} + #endif /* CAN_ML_H */ diff --git a/include/linux/can/core.h b/include/linux/can/core.h index 5fb8d0e3f9c1..3287232e3cad 100644 --- a/include/linux/can/core.h +++ b/include/linux/can/core.h @@ -58,6 +58,7 @@ extern void can_rx_unregister(struct net *net, struct net_device *dev, void *data); extern int can_send(struct sk_buff *skb, int loop); +void can_set_skb_uid(struct sk_buff *skb); void can_sock_destruct(struct sock *sk); #endif /* !_CAN_CORE_H */ diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 23492213ea35..6d0710d6f571 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -45,16 +45,11 @@ struct can_priv { struct net_device *dev; struct can_device_stats can_stats; - const struct can_bittiming_const *bittiming_const, - *data_bittiming_const; - struct can_bittiming bittiming, data_bittiming; - const struct can_tdc_const *tdc_const; - struct can_tdc tdc; - + const struct can_bittiming_const *bittiming_const; + struct can_bittiming bittiming; + struct data_bittiming_params fd, xl; unsigned int bitrate_const_cnt; const u32 *bitrate_const; - const u32 *data_bitrate_const; - unsigned int data_bitrate_const_cnt; u32 bitrate_max; struct can_clock clock; @@ -77,69 +72,22 @@ struct can_priv { struct delayed_work restart_work; int (*do_set_bittiming)(struct net_device *dev); - int (*do_set_data_bittiming)(struct net_device *dev); int (*do_set_mode)(struct net_device *dev, enum can_mode mode); int (*do_set_termination)(struct net_device *dev, u16 term); int (*do_get_state)(const struct net_device *dev, enum can_state *state); int (*do_get_berr_counter)(const struct net_device *dev, struct can_berr_counter *bec); - int (*do_get_auto_tdcv)(const struct net_device *dev, u32 *tdcv); }; -static inline bool can_tdc_is_enabled(const struct can_priv *priv) -{ - return !!(priv->ctrlmode & CAN_CTRLMODE_TDC_MASK); -} - -/* - * can_get_relative_tdco() - TDCO relative to the sample point - * - * struct can_tdc::tdco represents the absolute offset from TDCV. Some - * controllers use instead an offset relative to the Sample Point (SP) - * such that: - * - * SSP = TDCV + absolute TDCO - * = TDCV + SP + relative TDCO - * - * -+----------- one bit ----------+-- TX pin - * |<--- Sample Point --->| - * - * --+----------- one bit ----------+-- RX pin - * |<-------- TDCV -------->| - * |<------------------------>| absolute TDCO - * |<--- Sample Point --->| - * | |<->| relative TDCO - * |<------------- Secondary Sample Point ------------>| - */ -static inline s32 can_get_relative_tdco(const struct can_priv *priv) +static inline bool can_fd_tdc_is_enabled(const struct can_priv *priv) { - const struct can_bittiming *dbt = &priv->data_bittiming; - s32 sample_point_in_tc = (CAN_SYNC_SEG + dbt->prop_seg + - dbt->phase_seg1) * dbt->brp; - - return (s32)priv->tdc.tdco - sample_point_in_tc; + return !!(priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK); } -/* helper to define static CAN controller features at device creation time */ -static inline int __must_check can_set_static_ctrlmode(struct net_device *dev, - u32 static_mode) +static inline bool can_xl_tdc_is_enabled(const struct can_priv *priv) { - struct can_priv *priv = netdev_priv(dev); - - /* alloc_candev() succeeded => netdev_priv() is valid at this point */ - if (priv->ctrlmode_supported & static_mode) { - netdev_warn(dev, - "Controller features can not be supported and static at the same time\n"); - return -EINVAL; - } - priv->ctrlmode = static_mode; - - /* override MTU which was set by default in can_setup()? */ - if (static_mode & CAN_CTRLMODE_FD) - dev->mtu = CANFD_MTU; - - return 0; + return !!(priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MASK); } static inline u32 can_get_static_ctrlmode(struct can_priv *priv) @@ -152,22 +100,6 @@ static inline bool can_is_canxl_dev_mtu(unsigned int mtu) return (mtu >= CANXL_MIN_MTU && mtu <= CANXL_MAX_MTU); } -/* 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_buff *skb) -{ - struct can_priv *priv = netdev_priv(dev); - - 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; - } - - return can_dropped_invalid_skb(dev, skb); -} - void can_setup(struct net_device *dev); struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max, @@ -183,8 +115,15 @@ struct can_priv *safe_candev_priv(struct net_device *dev); int open_candev(struct net_device *dev); void close_candev(struct net_device *dev); -int can_change_mtu(struct net_device *dev, int new_mtu); -int can_eth_ioctl_hwts(struct net_device *netdev, struct ifreq *ifr, int cmd); +void can_set_default_mtu(struct net_device *dev); +void can_set_cap_info(struct net_device *dev); +int __must_check can_set_static_ctrlmode(struct net_device *dev, + u32 static_mode); +int can_hwtstamp_get(struct net_device *netdev, + struct kernel_hwtstamp_config *cfg); +int can_hwtstamp_set(struct net_device *netdev, + struct kernel_hwtstamp_config *cfg, + struct netlink_ext_ack *extack); int can_ethtool_op_get_ts_info_hwts(struct net_device *dev, struct kernel_ethtool_ts_info *info); @@ -195,6 +134,53 @@ int can_restart_now(struct net_device *dev); 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); + +static inline bool can_dev_in_xl_only_mode(struct can_priv *priv) +{ + const u32 mixed_mode = CAN_CTRLMODE_FD | CAN_CTRLMODE_XL; + + /* When CAN XL is enabled but FD is disabled we are running in + * the so-called 'CANXL-only mode' where the error signalling is + * disabled. This helper function determines the required value + * to disable error signalling in the CAN XL controller. + * The so-called CC/FD/XL 'mixed mode' requires error signalling. + */ + return ((priv->ctrlmode & mixed_mode) == CAN_CTRLMODE_XL); +} + +/* 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_buff *skb) +{ + struct can_priv *priv = netdev_priv(dev); + u32 silent_mode = 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; + } + + if (can_dev_in_xl_only_mode(priv) && !can_is_canxl_skb(skb)) { + netdev_info_once(dev, + "Error signaling 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/linux/can/dev/peak_canfd.h b/include/linux/can/dev/peak_canfd.h index f38772fd0c07..d3788a3d0942 100644 --- a/include/linux/can/dev/peak_canfd.h +++ b/include/linux/can/dev/peak_canfd.h @@ -2,8 +2,8 @@ /* * CAN driver for PEAK System micro-CAN based adapters * - * Copyright (C) 2003-2011 PEAK System-Technik GmbH - * Copyright (C) 2011-2013 Stephane Grosjean <s.grosjean@peak-system.com> + * Copyright (C) 2003-2025 PEAK System-Technik GmbH + * Author: Stéphane Grosjean <stephane.grosjean@hms-networks.com> */ #ifndef PUCAN_H #define PUCAN_H diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h index 1abc25a8d144..a70a02967071 100644 --- a/include/linux/can/skb.h +++ b/include/linux/can/skb.h @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/skbuff.h> #include <linux/can.h> +#include <net/can.h> #include <net/sock.h> void can_flush_echo_skb(struct net_device *dev); @@ -37,37 +38,20 @@ struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf); bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb); -/* - * The struct can_skb_priv is used to transport additional information along - * with the stored struct can(fd)_frame that can not be contained in existing - * struct sk_buff elements. - * N.B. that this information must not be modified in cloned CAN sk_buffs. - * To modify the CAN frame content or the struct can_skb_priv content - * skb_copy() needs to be used instead of skb_clone(). - */ - -/** - * struct can_skb_priv - private additional data inside CAN sk_buffs - * @ifindex: ifindex of the first interface the CAN frame appeared on - * @skbcnt: atomic counter to have an unique id together with skb pointer - * @frame_len: length of CAN frame in data link layer - * @cf: align to the following CAN frame at skb->data - */ -struct can_skb_priv { - int ifindex; - int skbcnt; - unsigned int frame_len; - struct can_frame cf[]; -}; - -static inline struct can_skb_priv *can_skb_prv(struct sk_buff *skb) +static inline struct can_skb_ext *can_skb_ext_add(struct sk_buff *skb) { - return (struct can_skb_priv *)(skb->head); + struct can_skb_ext *csx = skb_ext_add(skb, SKB_EXT_CAN); + + /* skb_ext_add() returns uninitialized space */ + if (csx) + csx->can_gw_hops = 0; + + return csx; } -static inline void can_skb_reserve(struct sk_buff *skb) +static inline struct can_skb_ext *can_skb_ext_find(struct sk_buff *skb) { - skb_reserve(skb, sizeof(struct can_skb_priv)); + return skb_ext_find(skb, SKB_EXT_CAN); } static inline void can_skb_set_owner(struct sk_buff *skb, struct sock *sk) |
