Add the netlink interface for CAN XL. Signed-off-by: Vincent Mailhol <mailhol.vincent@xxxxxxxxxx> --- drivers/net/can/dev/netlink.c | 78 +++++++++++++++++++++++++++++--- include/linux/can/bittiming.h | 2 + include/linux/can/dev.h | 13 ++++-- include/uapi/linux/can/netlink.h | 7 +++ 4 files changed, 90 insertions(+), 10 deletions(-) diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index 6c3fa5aa22cf..3c89b304c5b8 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -22,6 +22,9 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { [IFLA_CAN_TERMINATION] = { .type = NLA_U16 }, [IFLA_CAN_TDC] = { .type = NLA_NESTED }, [IFLA_CAN_CTRLMODE_EXT] = { .type = NLA_NESTED }, + [IFLA_CAN_XL_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) }, + [IFLA_CAN_XL_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) }, + [IFLA_CAN_XL_TDC] = { .type = NLA_NESTED }, }; static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] = { @@ -55,6 +58,10 @@ static int can_validate_tdc(struct nlattr *data_tdc, { int err; + /* TDC is optional */ + if (!data_tdc) + return 0; + /* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually exclusive */ if (tdc_auto == tdc_manual) return -EOPNOTSUPP; @@ -94,7 +101,7 @@ static int can_validate_tdc(struct nlattr *data_tdc, static int can_validate(struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - bool is_can_fd = false; + bool is_can_fd = false, is_can_xl = false; int err; /* Make sure that valid CAN FD configurations always consist of @@ -111,6 +118,7 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[], struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD; + is_can_xl = cm->flags & cm->mask & CAN_CTRLMODE_XL; err = can_validate_tdc(data[IFLA_CAN_TDC], cm->flags & CAN_CTRLMODE_TDC_AUTO, @@ -133,11 +141,19 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[], if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING]) return -EOPNOTSUPP; } + if (is_can_xl) { + if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_XL_DATA_BITTIMING]) + return -EOPNOTSUPP; + } if (data[IFLA_CAN_DATA_BITTIMING] || data[IFLA_CAN_TDC]) { if (!is_can_fd) return -EOPNOTSUPP; } + if (data[IFLA_CAN_XL_DATA_BITTIMING] || data[IFLA_CAN_XL_TDC]) { + if (!is_can_xl) + return -EOPNOTSUPP; + } if (data[IFLA_CAN_DATA_BITTIMING]) { struct can_bittiming bt; @@ -147,6 +163,14 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[], if (err) return err; } + if (data[IFLA_CAN_XL_DATA_BITTIMING]) { + struct can_bittiming bt; + + memcpy(&bt, nla_data(data[IFLA_CAN_XL_DATA_BITTIMING]), sizeof(bt)); + err = can_validate_bittiming(&bt, extack); + if (err) + return err; + } return 0; } @@ -275,8 +299,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { + bool fd_tdc_flag_provided = false, xl_tdc_flag_provided = false; struct can_priv *priv = netdev_priv(dev); - bool fd_tdc_flag_provided = false; int err; /* We need synchronization with dev->stop() */ @@ -310,8 +334,10 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], priv->ctrlmode &= ~cm->mask; priv->ctrlmode |= maskedflags; - /* CAN_CTRLMODE_FD can only be set when driver supports FD */ - if (priv->ctrlmode & CAN_CTRLMODE_FD) { + /* CAN_CTRLMODE_{FD,XL} can only be set when driver supports FD/XL */ + if (priv->ctrlmode & CAN_CTRLMODE_XL) { + dev->mtu = CANXL_MAX_MTU; + } else if (priv->ctrlmode & CAN_CTRLMODE_FD) { dev->mtu = CANFD_MTU; } else { dev->mtu = CAN_MTU; @@ -322,11 +348,14 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], } fd_tdc_flag_provided = cm->mask & CAN_CTRLMODE_FD_TDC_MASK; - /* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually + xl_tdc_flag_provided = cm->mask & CAN_CTRLMODE_XL_TDC_MASK; + /* CAN_CTRLMODE_(XL_)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; + if (xl_tdc_flag_provided) + priv->ctrlmode &= cm->flags | ~CAN_CTRLMODE_XL_TDC_MASK; } if (data[IFLA_CAN_BITTIMING]) { @@ -395,6 +424,15 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], if (err) return err; + /* CAN XL */ + err = can_dbt_changelink(dev, + data[IFLA_CAN_XL_DATA_BITTIMING], &priv->xl, + data[IFLA_CAN_XL_TDC], xl_tdc_flag_provided, + can_xl_tdc_is_enabled(priv), + CAN_CTRLMODE_XL_TDC_MASK, 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; @@ -494,6 +532,16 @@ static size_t can_get_size(const struct net_device *dev) can_fd_tdc_is_enabled(priv), priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL); size += can_ctrlmode_ext_get_size(); /* IFLA_CAN_CTRLMODE_EXT */ + if (priv->xl.data_bittiming.bitrate) /* IFLA_CAN_XL_DATA_BITTIMING */ + size += nla_total_size(sizeof(struct can_bittiming)); + if (priv->xl.data_bittiming_const) /* IFLA_CAN_XL_DATA_BITTIMING_CONST */ + size += nla_total_size(sizeof(struct can_bittiming_const)); + if (priv->xl.data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */ + size += nla_total_size(sizeof(*priv->xl.data_bitrate_const) * + priv->xl.data_bitrate_const_cnt); + size += can_tdc_get_size(&priv->xl, /* IFLA_CAN_XL_TDC */ + can_xl_tdc_is_enabled(priv), + priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MANUAL); return size; } @@ -634,7 +682,25 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) can_tdc_fill_info(skb, dev, &priv->fd, can_fd_tdc_is_enabled(priv), priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL) || - can_ctrlmode_ext_fill_info(skb, priv) + can_ctrlmode_ext_fill_info(skb, priv) || + + (priv->xl.data_bittiming.bitrate && + nla_put(skb, IFLA_CAN_XL_DATA_BITTIMING, + sizeof(priv->xl.data_bittiming), &priv->xl.data_bittiming)) || + + (priv->xl.data_bittiming_const && + nla_put(skb, IFLA_CAN_XL_DATA_BITTIMING_CONST, + sizeof(*priv->xl.data_bittiming_const), + priv->xl.data_bittiming_const)) || + + (priv->xl.data_bitrate_const && + nla_put(skb, IFLA_CAN_XL_DATA_BITRATE_CONST, + sizeof(*priv->xl.data_bitrate_const) * + priv->xl.data_bitrate_const_cnt, + priv->xl.data_bitrate_const)) || + + can_tdc_fill_info(skb, dev, &priv->xl, can_xl_tdc_is_enabled(priv), + priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MANUAL) ) return -EMSGSIZE; diff --git a/include/linux/can/bittiming.h b/include/linux/can/bittiming.h index 5dfdbb63b1d5..2053b9dff0ad 100644 --- a/include/linux/can/bittiming.h +++ b/include/linux/can/bittiming.h @@ -16,6 +16,8 @@ #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) /* * struct can_tdc - CAN FD Transmission Delay Compensation parameters diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 9a92cbe5b2cb..1ac98914f351 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -58,7 +58,7 @@ struct can_priv { const struct can_bittiming_const *bittiming_const; struct can_bittiming bittiming; - struct data_bittiming_params fd; + struct data_bittiming_params fd, xl; unsigned int bitrate_const_cnt; const u32 *bitrate_const; u32 bitrate_max; @@ -96,6 +96,11 @@ static inline bool can_fd_tdc_is_enabled(const struct can_priv *priv) return !!(priv->ctrlmode & CAN_CTRLMODE_FD_TDC_MASK); } +static inline bool can_xl_tdc_is_enabled(const struct can_priv *priv) +{ + return !!(priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MASK); +} + /* * can_get_relative_tdco() - TDCO relative to the sample point * @@ -116,13 +121,13 @@ static inline bool can_fd_tdc_is_enabled(const struct can_priv *priv) * | |<->| relative TDCO * |<------------- Secondary Sample Point ------------>| */ -static inline s32 can_get_relative_tdco(const struct can_priv *priv) +static inline s32 can_get_relative_tdco(const struct data_bittiming_params *dbt_params) { - const struct can_bittiming *dbt = &priv->fd.data_bittiming; + 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)priv->fd.tdc.tdco - sample_point_in_tc; + return (s32)dbt_params->tdc.tdco - sample_point_in_tc; } /* helper to define static CAN controller features at device creation time */ diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h index ef62f56eaaef..c81fd153a07f 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -103,6 +103,9 @@ struct can_ctrlmode { #define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */ #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 */ +#define CAN_CTRLMODE_XL 0x800 /* CAN XL mode */ +#define CAN_CTRLMODE_XL_TDC_AUTO 0x200 /* XL transceiver automatically calculates TDCV */ +#define CAN_CTRLMODE_XL_TDC_MANUAL 0x400 /* XL TDCV is manually set up by user */ /* * CAN device statistics @@ -138,6 +141,10 @@ enum { IFLA_CAN_BITRATE_MAX, IFLA_CAN_TDC, /* FD */ IFLA_CAN_CTRLMODE_EXT, + IFLA_CAN_XL_DATA_BITTIMING, + IFLA_CAN_XL_DATA_BITTIMING_CONST, + IFLA_CAN_XL_DATA_BITRATE_CONST, + IFLA_CAN_XL_TDC, /* add new constants above here */ __IFLA_CAN_MAX, -- 2.45.2