Commit 896d52af authored by Marc Kleine-Budde's avatar Marc Kleine-Budde
Browse files

Merge patch series "can: netlink: preparation before introduction of CAN XL step 3/3"

Vincent Mailhol <mailhol@kernel.org> says:

In November last year, I sent an RFC to introduce CAN XL [1]. That
RFC, despite positive feedback, was put on hold due to some unanswered
question concerning the PWM encoding [2].

While stuck, some small preparation work was done in parallel in [3]
by refactoring the struct can_priv and doing some trivial clean-up and
renaming. Initially, [3] received zero feedback but was eventually
merged after splitting it in smaller parts and resending it.

Finally, in July this year, we clarified the remaining mysteries about
PWM calculation, thus unlocking the series. Summer being a bit busy
because of some personal matters brings us to now.

After doing all the refactoring and adding all the CAN XL features,
the final result is more than 30 patches, definitively too much for a
single series. So I am splitting the remaining changes three:

  - can: rework the CAN MTU logic [4]
  - can: netlink: preparation before introduction of CAN XL (this series)
  - CAN XL (will come right after the two preparation series get merged)

And thus, this series continues and finishes the preparation work done
in [3] and [4]. It contains all the refactoring needed to smoothly
introduce CAN XL. The goal is to:

  - split the functions in smaller pieces: CAN XL will introduce a
    fair amount of code. And some functions which are already fairly
    long (86 lines for can_validate(), 215 lines for can_changelink())
    would grow to disproportionate sizes if the CAN XL logic were to
    be inlined in those functions.

  - repurpose the existing code to handle both CAN FD and CAN XL: a
    huge part of CAN XL simply reuses the CAN FD logic. All the
    existing CAN FD logic is made more generic to handle both CAN FD
    and XL.

In more details:

  - Patch #1 moves struct data_bittiming_params from dev.h to
    bittiming.h and patch #2 makes can_get_relative_tdco() FD agnostic
    before also moving it to bittiming.h.

  - Patch #3 adds some comments to netlink.h tagging which IFLA
    symbols are FD specific.

  - Patches #4 to #6 are refactoring can_validate() and
    can_validate_bittiming().

  - Patches #7 to #11 are refactoring can_changelink() and
    can_tdc_changelink().

  - Patches #12 and #13 are refactoring can_get_size() and
    can_tdc_get_size().

  - Patches #14 to #17 are refactoring can_fill_info() and
    can_tdc_fill_info().

  - Patch #18 makes can_calc_tdco() FD agnostic.

  - Patch #19 adds can_get_ctrlmode_str() which converts control mode
    flags into strings. This is done in preparation of patch #20.

  - Patch #20 is the final patch and improves the user experience by
    providing detailed error messages whenever invalid parameters are
    provided. All those error messages came into handy when debugging
    the upcoming CAN XL patches.

Aside from the last patch, the other changes do not impact any of the
existing functionalities.

The follow up series which introduces CAN XL is nearly completed but
will be sent only once this one is approved: one thing at a time, I do
not want to overwhelm people (including myself).

[1] https://lore.kernel.org/linux-can/20241110155902.72807-16-mailhol.vincent@wanadoo.fr/
[2] https://lore.kernel.org/linux-can/c4771c16-c578-4a6d-baee-918fe276dbe9@wanadoo.fr/
[3] https://lore.kernel.org/linux-can/20241110155902.72807-16-mailhol.vincent@wanadoo.fr/
[4] https://lore.kernel.org/linux-can/20250923-can-fix-mtu-v2-0-984f9868db69@kernel.org/

Link: https://patch.msgid.link/20250923-canxl-netlink-prep-v4-0-e720d28f66fe@kernel.org


Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parents 2d51a5b8 6742ca18
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -173,13 +173,15 @@ int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,

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)

{
	if (!tdc_const || !(ctrlmode_supported & CAN_CTRLMODE_TDC_AUTO))
	u32 tdc_auto = tdc_mask & CAN_CTRLMODE_TDC_AUTO_MASK;

	if (!tdc_const || !(ctrlmode_supported & tdc_auto))
		return;

	*ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK;
	*ctrlmode &= ~tdc_mask;

	/* As specified in ISO 11898-1 section 11.3.3 "Transmitter
	 * delay compensation" (TDC) is only applicable if data BRP is
@@ -193,6 +195,6 @@ void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const,
		if (sample_point_in_tc < tdc_const->tdco_min)
			return;
		tdc->tdco = min(sample_point_in_tc, tdc_const->tdco_max);
		*ctrlmode |= CAN_CTRLMODE_TDC_AUTO;
		*ctrlmode |= tdc_auto;
	}
}
+33 −0
Original line number Diff line number Diff line
@@ -88,6 +88,39 @@ const char *can_get_state_str(const enum can_state state)
}
EXPORT_SYMBOL_GPL(can_get_state_str);

const char *can_get_ctrlmode_str(u32 ctrlmode)
{
	switch (ctrlmode & ~(ctrlmode - 1)) {
	case 0:
		return "none";
	case CAN_CTRLMODE_LOOPBACK:
		return "loopback";
	case CAN_CTRLMODE_LISTENONLY:
		return "listen-only";
	case CAN_CTRLMODE_3_SAMPLES:
		return "triple-sampling";
	case CAN_CTRLMODE_ONE_SHOT:
		return "one-shot";
	case CAN_CTRLMODE_BERR_REPORTING:
		return "berr-reporting";
	case CAN_CTRLMODE_FD:
		return "fd";
	case CAN_CTRLMODE_PRESUME_ACK:
		return "presume-ack";
	case CAN_CTRLMODE_FD_NON_ISO:
		return "fd-non-iso";
	case CAN_CTRLMODE_CC_LEN8_DLC:
		return "cc-len8-dlc";
	case CAN_CTRLMODE_TDC_AUTO:
		return "fd-tdc-auto";
	case CAN_CTRLMODE_TDC_MANUAL:
		return "fd-tdc-manual";
	default:
		return "<unknown>";
	}
}
EXPORT_SYMBOL_GPL(can_get_ctrlmode_str);

static enum can_state can_state_err_to_state(u16 err)
{
	if (err < CAN_ERROR_WARNING_THRESHOLD)
+372 −217

File changed.

Preview size limit exceeded, changes collapsed.

+46 −2
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

#define CAN_CTRLMODE_FD_TDC_MASK				\
	(CAN_CTRLMODE_TDC_AUTO | CAN_CTRLMODE_TDC_MANUAL)
#define CAN_CTRLMODE_TDC_AUTO_MASK				\
	(CAN_CTRLMODE_TDC_AUTO)
#define CAN_CTRLMODE_TDC_MANUAL_MASK				\
	(CAN_CTRLMODE_TDC_MANUAL)

/*
 * struct can_tdc - CAN FD Transmission Delay Compensation parameters
@@ -114,13 +118,24 @@ struct can_tdc_const {
	u32 tdcf_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 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);
#else /* !CONFIG_CAN_CALC_BITTIMING */
static inline int
can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
@@ -133,7 +148,7 @@ can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
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)
{
}
#endif /* CONFIG_CAN_CALC_BITTIMING */
@@ -149,6 +164,35 @@ int can_get_bittiming(const struct net_device *dev, struct can_bittiming *bt,
		      const unsigned int bitrate_const_cnt,
		      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
 *
+2 −40
Original line number Diff line number Diff line
@@ -38,17 +38,6 @@ enum can_termination_gpio {
	CAN_TERMINATION_GPIO_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 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);
};

/*
 * CAN common private data
 */
@@ -96,35 +85,6 @@ static inline bool can_fd_tdc_is_enabled(const struct can_priv *priv)
	return !!(priv->ctrlmode & CAN_CTRLMODE_FD_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)
{
	const struct can_bittiming *dbt = &priv->fd.data_bittiming;
	s32 sample_point_in_tc = (CAN_SYNC_SEG + dbt->prop_seg +
				  dbt->phase_seg1) * dbt->brp;

	return (s32)priv->fd.tdc.tdco - sample_point_in_tc;
}

static inline u32 can_get_static_ctrlmode(struct can_priv *priv)
{
	return priv->ctrlmode & ~priv->ctrlmode_supported;
@@ -181,6 +141,8 @@ 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);

void can_state_get_by_berr_counter(const struct net_device *dev,
				   const struct can_berr_counter *bec,
				   enum can_state *tx_state,
Loading