diff --git a/drivers/net/can/dev/calc_bittiming.c b/drivers/net/can/dev/calc_bittiming.c index a94bd67c670c..394d6974f481 100644 --- a/drivers/net/can/dev/calc_bittiming.c +++ b/drivers/net/can/dev/calc_bittiming.c @@ -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; } } diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index befdeb4c54c2..15ccedbb3f8d 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -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 ""; + } +} +EXPORT_SYMBOL_GPL(can_get_ctrlmode_str); + static enum can_state can_state_err_to_state(u16 err) { if (err < CAN_ERROR_WARNING_THRESHOLD) diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index 248f607e3864..0591406b6f32 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -36,116 +36,245 @@ static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] = { [IFLA_CAN_TDC_TDCF] = { .type = NLA_U32 }, }; -static int can_validate_bittiming(const struct can_bittiming *bt, - struct netlink_ext_ack *extack) +static int can_validate_bittiming(struct nlattr *data[], + struct netlink_ext_ack *extack, + int ifla_can_bittiming) { + struct can_bittiming *bt; + + if (!data[ifla_can_bittiming]) + return 0; + + static_assert(__alignof__(*bt) <= NLA_ALIGNTO); + bt = nla_data(data[ifla_can_bittiming]); + /* sample point is in one-tenth of a percent */ if (bt->sample_point >= 1000) { NL_SET_ERR_MSG(extack, "sample point must be between 0 and 100%"); - return -EINVAL; } return 0; } +static int can_validate_tdc(struct nlattr *data_tdc, + struct netlink_ext_ack *extack, u32 tdc_flags) +{ + bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK; + bool tdc_auto = tdc_flags & CAN_CTRLMODE_TDC_AUTO_MASK; + int err; + + if (tdc_auto && tdc_manual) { + NL_SET_ERR_MSG(extack, + "TDC manual and auto modes are mutually exclusive"); + return -EOPNOTSUPP; + } + + /* If one of the CAN_CTRLMODE_TDC_* flag is set then TDC + * must be set and vice-versa + */ + if ((tdc_auto || tdc_manual) && !data_tdc) { + NL_SET_ERR_MSG(extack, "TDC parameters are missing"); + return -EOPNOTSUPP; + } + if (!(tdc_auto || tdc_manual) && data_tdc) { + NL_SET_ERR_MSG(extack, "TDC mode (auto or manual) is missing"); + return -EOPNOTSUPP; + } + + /* If providing TDC parameters, at least TDCO is needed. TDCV + * is needed if and only if CAN_CTRLMODE_TDC_MANUAL is set + */ + if (data_tdc) { + struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1]; + + err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, + data_tdc, can_tdc_policy, extack); + if (err) + return err; + + if (tb_tdc[IFLA_CAN_TDC_TDCV]) { + if (tdc_auto) { + NL_SET_ERR_MSG(extack, + "TDCV is incompatible with TDC auto mode"); + return -EOPNOTSUPP; + } + } else { + if (tdc_manual) { + NL_SET_ERR_MSG(extack, + "TDC manual mode requires TDCV"); + return -EOPNOTSUPP; + } + } + + if (!tb_tdc[IFLA_CAN_TDC_TDCO]) { + NL_SET_ERR_MSG(extack, "TDCO is missing"); + return -EOPNOTSUPP; + } + } + + return 0; +} + +static int can_validate_databittiming(struct nlattr *data[], + struct netlink_ext_ack *extack, + int ifla_can_data_bittiming, u32 flags) +{ + struct nlattr *data_tdc; + const char *type; + u32 tdc_flags; + bool is_on; + int err; + + /* Make sure that valid CAN FD configurations always consist of + * - nominal/arbitration bittiming + * - data bittiming + * - control mode with CAN_CTRLMODE_FD set + * - TDC parameters are coherent (details in can_validate_tdc()) + */ + + if (ifla_can_data_bittiming == IFLA_CAN_DATA_BITTIMING) { + data_tdc = data[IFLA_CAN_TDC]; + tdc_flags = flags & CAN_CTRLMODE_FD_TDC_MASK; + is_on = flags & CAN_CTRLMODE_FD; + type = "FD"; + } else { + return -EOPNOTSUPP; /* Place holder for CAN XL */ + } + + if (is_on) { + if (!data[IFLA_CAN_BITTIMING] || !data[ifla_can_data_bittiming]) { + NL_SET_ERR_MSG_FMT(extack, + "Provide both nominal and %s data bittiming", + type); + return -EOPNOTSUPP; + } + } else { + if (data[ifla_can_data_bittiming]) { + NL_SET_ERR_MSG_FMT(extack, + "%s data bittiming requires CAN %s", + type, type); + return -EOPNOTSUPP; + } + if (data_tdc) { + NL_SET_ERR_MSG_FMT(extack, + "%s TDC requires CAN %s", + type, type); + return -EOPNOTSUPP; + } + } + + err = can_validate_bittiming(data, extack, ifla_can_data_bittiming); + if (err) + return err; + + err = can_validate_tdc(data_tdc, extack, tdc_flags); + if (err) + return err; + + return 0; +} + static int can_validate(struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - bool is_can_fd = false; + u32 flags = 0; int err; - /* Make sure that valid CAN FD configurations always consist of - * - nominal/arbitration bittiming - * - data bittiming - * - control mode with CAN_CTRLMODE_FD set - * - TDC parameters are coherent (details below) - */ - if (!data) return 0; if (data[IFLA_CAN_CTRLMODE]) { struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); - u32 tdc_flags = cm->flags & CAN_CTRLMODE_FD_TDC_MASK; - is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD; - - /* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually exclusive */ - if (tdc_flags == CAN_CTRLMODE_FD_TDC_MASK) - return -EOPNOTSUPP; - /* If one of the CAN_CTRLMODE_TDC_* flag is set then - * TDC must be set and vice-versa - */ - if (!!tdc_flags != !!data[IFLA_CAN_TDC]) - return -EOPNOTSUPP; - /* If providing TDC parameters, at least TDCO is - * needed. TDCV is needed if and only if - * CAN_CTRLMODE_TDC_MANUAL is set - */ - if (data[IFLA_CAN_TDC]) { - struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1]; - - err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, - data[IFLA_CAN_TDC], - can_tdc_policy, extack); - if (err) - return err; - - if (tb_tdc[IFLA_CAN_TDC_TDCV]) { - if (tdc_flags & CAN_CTRLMODE_TDC_AUTO) - return -EOPNOTSUPP; - } else { - if (tdc_flags & CAN_CTRLMODE_TDC_MANUAL) - return -EOPNOTSUPP; - } - - if (!tb_tdc[IFLA_CAN_TDC_TDCO]) - return -EOPNOTSUPP; - } + flags = cm->flags & cm->mask; } - if (data[IFLA_CAN_BITTIMING]) { - struct can_bittiming bt; + err = can_validate_bittiming(data, extack, IFLA_CAN_BITTIMING); + if (err) + return err; - memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); - err = can_validate_bittiming(&bt, extack); - if (err) - return err; - } - - if (is_can_fd) { - if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING]) - return -EOPNOTSUPP; - } - - if (data[IFLA_CAN_DATA_BITTIMING] || data[IFLA_CAN_TDC]) { - if (!is_can_fd) - return -EOPNOTSUPP; - } - - if (data[IFLA_CAN_DATA_BITTIMING]) { - struct can_bittiming bt; - - memcpy(&bt, nla_data(data[IFLA_CAN_DATA_BITTIMING]), sizeof(bt)); - err = can_validate_bittiming(&bt, extack); - if (err) - return err; - } + err = can_validate_databittiming(data, extack, + IFLA_CAN_DATA_BITTIMING, flags); + if (err) + return err; return 0; } -static int can_tdc_changelink(struct can_priv *priv, const struct nlattr *nla, +static int can_ctrlmode_changelink(struct net_device *dev, + struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + struct can_priv *priv = netdev_priv(dev); + struct can_ctrlmode *cm; + u32 ctrlstatic, maskedflags, notsupp, ctrlstatic_missing; + + if (!data[IFLA_CAN_CTRLMODE]) + return 0; + + /* Do not allow changing controller mode while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + + cm = nla_data(data[IFLA_CAN_CTRLMODE]); + ctrlstatic = can_get_static_ctrlmode(priv); + maskedflags = cm->flags & cm->mask; + notsupp = maskedflags & ~(priv->ctrlmode_supported | ctrlstatic); + ctrlstatic_missing = (maskedflags & ctrlstatic) ^ ctrlstatic; + + if (notsupp) { + NL_SET_ERR_MSG_FMT(extack, + "requested control mode %s not supported", + can_get_ctrlmode_str(notsupp)); + return -EOPNOTSUPP; + } + + /* do not check for static fd-non-iso if 'fd' is disabled */ + if (!(maskedflags & CAN_CTRLMODE_FD)) + ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO; + + if (ctrlstatic_missing) { + NL_SET_ERR_MSG_FMT(extack, + "missing required %s static control mode", + can_get_ctrlmode_str(ctrlstatic_missing)); + return -EOPNOTSUPP; + } + + /* If a top dependency flag is provided, reset all its dependencies */ + if (cm->mask & CAN_CTRLMODE_FD) + priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; + + /* clear bits to be modified and copy the flag values */ + priv->ctrlmode &= ~cm->mask; + priv->ctrlmode |= maskedflags; + + /* Wipe potential leftovers from previous CAN FD config */ + if (!(priv->ctrlmode & CAN_CTRLMODE_FD)) { + memset(&priv->fd.data_bittiming, 0, + sizeof(priv->fd.data_bittiming)); + priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; + memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc)); + } + + can_set_default_mtu(dev); + + return 0; +} + +static int can_tdc_changelink(struct data_bittiming_params *dbt_params, + const struct nlattr *nla, struct netlink_ext_ack *extack) { struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1]; struct can_tdc tdc = { 0 }; - const struct can_tdc_const *tdc_const = priv->fd.tdc_const; + const struct can_tdc_const *tdc_const = dbt_params->tdc_const; int err; - if (!tdc_const || !can_fd_tdc_is_enabled(priv)) + if (!tdc_const) { + NL_SET_ERR_MSG(extack, "The device does not support TDC"); return -EOPNOTSUPP; + } err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, nla, can_tdc_policy, extack); @@ -179,7 +308,91 @@ static int can_tdc_changelink(struct can_priv *priv, const struct nlattr *nla, tdc.tdcf = tdcf; } - priv->fd.tdc = tdc; + dbt_params->tdc = tdc; + + 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, + tdc_mask, &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; } @@ -189,57 +402,12 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], 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() */ ASSERT_RTNL(); - if (data[IFLA_CAN_CTRLMODE]) { - struct can_ctrlmode *cm; - u32 ctrlstatic; - u32 maskedflags; - - /* Do not allow changing controller mode while running */ - if (dev->flags & IFF_UP) - return -EBUSY; - cm = nla_data(data[IFLA_CAN_CTRLMODE]); - ctrlstatic = can_get_static_ctrlmode(priv); - maskedflags = cm->flags & cm->mask; - - /* check whether provided bits are allowed to be passed */ - if (maskedflags & ~(priv->ctrlmode_supported | ctrlstatic)) - return -EOPNOTSUPP; - - /* do not check for static fd-non-iso if 'fd' is disabled */ - if (!(maskedflags & CAN_CTRLMODE_FD)) - ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO; - - /* make sure static options are provided by configuration */ - if ((maskedflags & ctrlstatic) != ctrlstatic) - return -EOPNOTSUPP; - - /* clear bits to be modified and copy the flag values */ - priv->ctrlmode &= ~cm->mask; - priv->ctrlmode |= maskedflags; - - /* Wipe potential leftovers from previous CAN FD config */ - if (!(priv->ctrlmode & CAN_CTRLMODE_FD)) { - memset(&priv->fd.data_bittiming, 0, - sizeof(priv->fd.data_bittiming)); - priv->ctrlmode &= ~CAN_CTRLMODE_FD_TDC_MASK; - memset(&priv->fd.tdc, 0, sizeof(priv->fd.tdc)); - } - - can_set_default_mtu(dev); - - fd_tdc_flag_provided = cm->mask & CAN_CTRLMODE_FD_TDC_MASK; - /* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually - * exclusive: make sure to turn the other one off - */ - if (fd_tdc_flag_provided) - priv->ctrlmode &= cm->flags | ~CAN_CTRLMODE_FD_TDC_MASK; - } + can_ctrlmode_changelink(dev, data, extack); if (data[IFLA_CAN_BITTIMING]) { struct can_bittiming bt; @@ -311,75 +479,21 @@ 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, 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]); const unsigned int num_term = priv->termination_const_cnt; unsigned int i; - if (!priv->do_set_termination) + if (!priv->do_set_termination) { + NL_SET_ERR_MSG(extack, + "Termination is not configurable on this device"); return -EOPNOTSUPP; + } /* check whether given value is supported by the interface */ for (i = 0; i < num_term; i++) { @@ -400,38 +514,55 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], return 0; } -static size_t can_tdc_get_size(const struct net_device *dev) +static size_t can_tdc_get_size(struct data_bittiming_params *dbt_params, + u32 tdc_flags) { - struct can_priv *priv = netdev_priv(dev); + bool tdc_manual = tdc_flags & CAN_CTRLMODE_TDC_MANUAL_MASK; size_t size; - if (!priv->fd.tdc_const) + if (!dbt_params->tdc_const) return 0; size = nla_total_size(0); /* nest IFLA_CAN_TDC */ - if (priv->ctrlmode_supported & CAN_CTRLMODE_TDC_MANUAL) { + if (tdc_manual) { size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV_MIN */ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV_MAX */ } size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO_MIN */ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO_MAX */ - if (priv->fd.tdc_const->tdcf_max) { + if (dbt_params->tdc_const->tdcf_max) { size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCF_MIN */ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCF_MAX */ } - if (can_fd_tdc_is_enabled(priv)) { - if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL || - priv->fd.do_get_auto_tdcv) + if (tdc_flags) { + if (tdc_manual || dbt_params->do_get_auto_tdcv) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCV */ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCO */ - if (priv->fd.tdc_const->tdcf_max) + if (dbt_params->tdc_const->tdcf_max) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_TDCF */ } return size; } +static size_t can_data_bittiming_get_size(struct data_bittiming_params *dbt_params, + u32 tdc_flags) +{ + size_t size = 0; + + if (dbt_params->data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */ + size += nla_total_size(sizeof(dbt_params->data_bittiming)); + if (dbt_params->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */ + size += nla_total_size(sizeof(*dbt_params->data_bittiming_const)); + if (dbt_params->data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */ + size += nla_total_size(sizeof(*dbt_params->data_bitrate_const) * + dbt_params->data_bitrate_const_cnt); + size += can_tdc_get_size(dbt_params, tdc_flags);/* IFLA_CAN_TDC */ + + return size; +} + static size_t can_ctrlmode_ext_get_size(void) { return nla_total_size(0) + /* nest IFLA_CAN_CTRLMODE_EXT */ @@ -453,10 +584,6 @@ static size_t can_get_size(const struct net_device *dev) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */ if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */ size += nla_total_size(sizeof(struct can_berr_counter)); - if (priv->fd.data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */ - size += nla_total_size(sizeof(struct can_bittiming)); - if (priv->fd.data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */ - size += nla_total_size(sizeof(struct can_bittiming_const)); if (priv->termination_const) { size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */ size += nla_total_size(sizeof(*priv->termination_const) * /* IFLA_CAN_TERMINATION_CONST */ @@ -465,31 +592,69 @@ static size_t can_get_size(const struct net_device *dev) if (priv->bitrate_const) /* IFLA_CAN_BITRATE_CONST */ size += nla_total_size(sizeof(*priv->bitrate_const) * priv->bitrate_const_cnt); - if (priv->fd.data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */ - size += nla_total_size(sizeof(*priv->fd.data_bitrate_const) * - priv->fd.data_bitrate_const_cnt); size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */ - size += can_tdc_get_size(dev); /* IFLA_CAN_TDC */ size += can_ctrlmode_ext_get_size(); /* IFLA_CAN_CTRLMODE_EXT */ + size += can_data_bittiming_get_size(&priv->fd, + priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK); + return size; } -static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev) +static int can_bittiming_fill_info(struct sk_buff *skb, int ifla_can_bittiming, + struct can_bittiming *bittiming) +{ + return bittiming->bitrate != CAN_BITRATE_UNSET && + bittiming->bitrate != CAN_BITRATE_UNKNOWN && + nla_put(skb, ifla_can_bittiming, sizeof(*bittiming), bittiming); +} + +static int can_bittiming_const_fill_info(struct sk_buff *skb, + int ifla_can_bittiming_const, + const struct can_bittiming_const *bittiming_const) +{ + return bittiming_const && + nla_put(skb, ifla_can_bittiming_const, + sizeof(*bittiming_const), bittiming_const); +} + +static int can_bitrate_const_fill_info(struct sk_buff *skb, + int ifla_can_bitrate_const, + const u32 *bitrate_const, unsigned int cnt) +{ + return bitrate_const && + nla_put(skb, ifla_can_bitrate_const, + sizeof(*bitrate_const) * cnt, bitrate_const); +} + +static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev, + int ifla_can_tdc) { - struct nlattr *nest; struct can_priv *priv = netdev_priv(dev); - struct can_tdc *tdc = &priv->fd.tdc; - const struct can_tdc_const *tdc_const = priv->fd.tdc_const; + struct data_bittiming_params *dbt_params; + const struct can_tdc_const *tdc_const; + struct can_tdc *tdc; + struct nlattr *nest; + bool tdc_is_enabled, tdc_manual; + + if (ifla_can_tdc == IFLA_CAN_TDC) { + dbt_params = &priv->fd; + tdc_is_enabled = can_fd_tdc_is_enabled(priv); + tdc_manual = priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL; + } else { + return -EOPNOTSUPP; /* Place holder for CAN XL */ + } + tdc_const = dbt_params->tdc_const; + tdc = &dbt_params->tdc; if (!tdc_const) return 0; - nest = nla_nest_start(skb, IFLA_CAN_TDC); + nest = nla_nest_start(skb, ifla_can_tdc); if (!nest) return -EMSGSIZE; - if (priv->ctrlmode_supported & CAN_CTRLMODE_TDC_MANUAL && + if (tdc_manual && (nla_put_u32(skb, IFLA_CAN_TDC_TDCV_MIN, tdc_const->tdcv_min) || nla_put_u32(skb, IFLA_CAN_TDC_TDCV_MAX, tdc_const->tdcv_max))) goto err_cancel; @@ -501,15 +666,15 @@ static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u32(skb, IFLA_CAN_TDC_TDCF_MAX, tdc_const->tdcf_max))) goto err_cancel; - if (can_fd_tdc_is_enabled(priv)) { + if (tdc_is_enabled) { u32 tdcv; int err = -EINVAL; - if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL) { + if (tdc_manual) { tdcv = tdc->tdcv; err = 0; - } else if (priv->fd.do_get_auto_tdcv) { - err = priv->fd.do_get_auto_tdcv(dev, &tdcv); + } else if (dbt_params->do_get_auto_tdcv) { + err = dbt_params->do_get_auto_tdcv(dev, &tdcv); } if (!err && nla_put_u32(skb, IFLA_CAN_TDC_TDCV, tdcv)) goto err_cancel; @@ -557,14 +722,11 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) if (priv->do_get_state) priv->do_get_state(dev, &state); - if ((priv->bittiming.bitrate != CAN_BITRATE_UNSET && - priv->bittiming.bitrate != CAN_BITRATE_UNKNOWN && - nla_put(skb, IFLA_CAN_BITTIMING, - sizeof(priv->bittiming), &priv->bittiming)) || + if (can_bittiming_fill_info(skb, IFLA_CAN_BITTIMING, + &priv->bittiming) || - (priv->bittiming_const && - nla_put(skb, IFLA_CAN_BITTIMING_CONST, - sizeof(*priv->bittiming_const), priv->bittiming_const)) || + can_bittiming_const_fill_info(skb, IFLA_CAN_BITTIMING_CONST, + priv->bittiming_const) || nla_put(skb, IFLA_CAN_CLOCK, sizeof(priv->clock), &priv->clock) || nla_put_u32(skb, IFLA_CAN_STATE, state) || @@ -575,14 +737,11 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) !priv->do_get_berr_counter(dev, &bec) && nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) || - (priv->fd.data_bittiming.bitrate && - nla_put(skb, IFLA_CAN_DATA_BITTIMING, - sizeof(priv->fd.data_bittiming), &priv->fd.data_bittiming)) || + can_bittiming_fill_info(skb, IFLA_CAN_DATA_BITTIMING, + &priv->fd.data_bittiming) || - (priv->fd.data_bittiming_const && - nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST, - sizeof(*priv->fd.data_bittiming_const), - priv->fd.data_bittiming_const)) || + can_bittiming_const_fill_info(skb, IFLA_CAN_DATA_BITTIMING_CONST, + priv->fd.data_bittiming_const) || (priv->termination_const && (nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) || @@ -591,23 +750,19 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) priv->termination_const_cnt, priv->termination_const))) || - (priv->bitrate_const && - nla_put(skb, IFLA_CAN_BITRATE_CONST, - sizeof(*priv->bitrate_const) * - priv->bitrate_const_cnt, - priv->bitrate_const)) || + can_bitrate_const_fill_info(skb, IFLA_CAN_BITRATE_CONST, + priv->bitrate_const, + priv->bitrate_const_cnt) || - (priv->fd.data_bitrate_const && - nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST, - sizeof(*priv->fd.data_bitrate_const) * - priv->fd.data_bitrate_const_cnt, - priv->fd.data_bitrate_const)) || + can_bitrate_const_fill_info(skb, IFLA_CAN_DATA_BITRATE_CONST, + priv->fd.data_bitrate_const, + priv->fd.data_bitrate_const_cnt) || (nla_put(skb, IFLA_CAN_BITRATE_MAX, sizeof(priv->bitrate_max), &priv->bitrate_max)) || - can_tdc_fill_info(skb, dev) || + can_tdc_fill_info(skb, dev, IFLA_CAN_TDC) || can_ctrlmode_ext_fill_info(skb, priv) ) diff --git a/include/linux/can/bittiming.h b/include/linux/can/bittiming.h index 5dfdbb63b1d5..d30816dd93c7 100644 --- a/include/linux/can/bittiming.h +++ b/include/linux/can/bittiming.h @@ -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 * diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 3354f70ed2c6..a2229a61ccde 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -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, diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h index 02ec32d69474..ef62f56eaaef 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -101,8 +101,8 @@ struct can_ctrlmode { #define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */ #define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */ #define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */ -#define CAN_CTRLMODE_TDC_AUTO 0x200 /* CAN transiver automatically calculates TDCV */ -#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* TDCV is manually set up by user */ +#define CAN_CTRLMODE_TDC_AUTO 0x200 /* FD transceiver automatically calculates TDCV */ +#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* FD TDCV is manually set up by user */ /* * CAN device statistics @@ -129,14 +129,14 @@ enum { IFLA_CAN_RESTART_MS, IFLA_CAN_RESTART, IFLA_CAN_BERR_COUNTER, - IFLA_CAN_DATA_BITTIMING, - IFLA_CAN_DATA_BITTIMING_CONST, + IFLA_CAN_DATA_BITTIMING, /* FD */ + IFLA_CAN_DATA_BITTIMING_CONST, /* FD */ IFLA_CAN_TERMINATION, IFLA_CAN_TERMINATION_CONST, IFLA_CAN_BITRATE_CONST, - IFLA_CAN_DATA_BITRATE_CONST, + IFLA_CAN_DATA_BITRATE_CONST, /* FD */ IFLA_CAN_BITRATE_MAX, - IFLA_CAN_TDC, + IFLA_CAN_TDC, /* FD */ IFLA_CAN_CTRLMODE_EXT, /* add new constants above here */ @@ -145,7 +145,7 @@ enum { }; /* - * CAN FD Transmitter Delay Compensation (TDC) + * CAN FD/XL Transmitter Delay Compensation (TDC) * * Please refer to struct can_tdc_const and can_tdc in * include/linux/can/bittiming.h for further details.