can: netlink: add can_dtb_changelink()

Factorise the databittiming parsing out of can_changelink() and move
it in the new can_dtb_changelink() function. This is a preparation
patch for the introduction of CAN XL because the databittiming
changelink logic will be reused later on.

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
Link: https://patch.msgid.link/20250923-canxl-netlink-prep-v4-10-e720d28f66fe@kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
Vincent Mailhol
2025-09-23 15:58:35 +09:00
committed by Marc Kleine-Budde
parent 530c918f8c
commit 2e543af483

View File

@@ -221,12 +221,95 @@ static int can_tdc_changelink(struct data_bittiming_params *dbt_params,
return 0;
}
static int can_dbt_changelink(struct net_device *dev, struct nlattr *data[],
bool fd, struct netlink_ext_ack *extack)
{
struct nlattr *data_bittiming, *data_tdc;
struct can_priv *priv = netdev_priv(dev);
struct data_bittiming_params *dbt_params;
struct can_bittiming dbt;
bool need_tdc_calc = false;
u32 tdc_mask;
int err;
if (fd) {
data_bittiming = data[IFLA_CAN_DATA_BITTIMING];
data_tdc = data[IFLA_CAN_TDC];
dbt_params = &priv->fd;
tdc_mask = CAN_CTRLMODE_FD_TDC_MASK;
} else {
return -EOPNOTSUPP; /* Place holder for CAN XL */
}
if (!data_bittiming)
return 0;
/* Do not allow changing bittiming while running */
if (dev->flags & IFF_UP)
return -EBUSY;
/* Calculate bittiming parameters based on data_bittiming_const
* if set, otherwise pass bitrate directly via do_set_bitrate().
* Bail out if neither is given.
*/
if (!dbt_params->data_bittiming_const && !dbt_params->do_set_data_bittiming &&
!dbt_params->data_bitrate_const)
return -EOPNOTSUPP;
memcpy(&dbt, nla_data(data_bittiming), sizeof(dbt));
err = can_get_bittiming(dev, &dbt, dbt_params->data_bittiming_const,
dbt_params->data_bitrate_const,
dbt_params->data_bitrate_const_cnt, extack);
if (err)
return err;
if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
NL_SET_ERR_MSG_FMT(extack,
"CAN data bitrate %u bps surpasses transceiver capabilities of %u bps",
dbt.bitrate, priv->bitrate_max);
return -EINVAL;
}
memset(&dbt_params->tdc, 0, sizeof(dbt_params->tdc));
if (data[IFLA_CAN_CTRLMODE]) {
struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
need_tdc_calc = !(cm->mask & tdc_mask);
}
if (data_tdc) {
/* TDC parameters are provided: use them */
err = can_tdc_changelink(dbt_params, data_tdc, extack);
if (err) {
priv->ctrlmode &= ~tdc_mask;
return err;
}
} else if (need_tdc_calc) {
/* Neither of TDC parameters nor TDC flags are provided:
* do calculation
*/
can_calc_tdco(&dbt_params->tdc, dbt_params->tdc_const, &dbt,
&priv->ctrlmode, priv->ctrlmode_supported);
} /* else: both CAN_CTRLMODE_TDC_{AUTO,MANUAL} are explicitly
* turned off. TDC is disabled: do nothing
*/
memcpy(&dbt_params->data_bittiming, &dbt, sizeof(dbt));
if (dbt_params->do_set_data_bittiming) {
/* Finally, set the bit-timing registers */
err = dbt_params->do_set_data_bittiming(dev);
if (err)
return err;
}
return 0;
}
static int can_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[],
struct netlink_ext_ack *extack)
{
struct can_priv *priv = netdev_priv(dev);
bool fd_tdc_flag_provided = false;
int err;
/* We need synchronization with dev->stop() */
@@ -273,8 +356,6 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
}
can_set_default_mtu(dev);
fd_tdc_flag_provided = cm->mask & CAN_CTRLMODE_FD_TDC_MASK;
}
if (data[IFLA_CAN_BITTIMING]) {
@@ -347,67 +428,10 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
return err;
}
if (data[IFLA_CAN_DATA_BITTIMING]) {
struct can_bittiming dbt;
/* Do not allow changing bittiming while running */
if (dev->flags & IFF_UP)
return -EBUSY;
/* Calculate bittiming parameters based on
* data_bittiming_const if set, otherwise pass bitrate
* directly via do_set_bitrate(). Bail out if neither
* is given.
*/
if (!priv->fd.data_bittiming_const && !priv->fd.do_set_data_bittiming &&
!priv->fd.data_bitrate_const)
return -EOPNOTSUPP;
memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
sizeof(dbt));
err = can_get_bittiming(dev, &dbt,
priv->fd.data_bittiming_const,
priv->fd.data_bitrate_const,
priv->fd.data_bitrate_const_cnt,
extack);
if (err)
return err;
if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
NL_SET_ERR_MSG_FMT(extack,
"CANFD data bitrate %u bps surpasses transceiver capabilities of %u bps",
dbt.bitrate, priv->bitrate_max);
return -EINVAL;
}
memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc));
if (data[IFLA_CAN_TDC]) {
/* TDC parameters are provided: use them */
err = can_tdc_changelink(&priv->fd,
data[IFLA_CAN_TDC], extack);
if (err) {
priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK;
return err;
}
} else if (!fd_tdc_flag_provided) {
/* Neither of TDC parameters nor TDC flags are
* provided: do calculation
*/
can_calc_tdco(&priv->fd.tdc, priv->fd.tdc_const, &dbt,
&priv->ctrlmode, priv->ctrlmode_supported);
} /* else: both CAN_CTRLMODE_TDC_{AUTO,MANUAL} are explicitly
* turned off. TDC is disabled: do nothing
*/
memcpy(&priv->fd.data_bittiming, &dbt, sizeof(dbt));
if (priv->fd.do_set_data_bittiming) {
/* Finally, set the bit-timing registers */
err = priv->fd.do_set_data_bittiming(dev);
if (err)
return err;
}
}
/* CAN FD */
err = can_dbt_changelink(dev, data, true, extack);
if (err)
return err;
if (data[IFLA_CAN_TERMINATION]) {
const u16 termval = nla_get_u16(data[IFLA_CAN_TERMINATION]);