From 12a6075cabc0d9ffbc0366b44daa22f278606312 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Tue, 10 Jan 2017 18:52:06 +0100 Subject: can: dev: add CAN interface termination API This patch adds a netlink interface to configure the CAN bus termination of CAN interfaces. Inside the driver an array of supported termination values is defined: const u16 drvname_termination[] = { 60, 120, CAN_TERMINATION_DISABLED }; struct drvname_priv *priv; priv = netdev_priv(dev); priv->termination_const = drvname_termination; priv->termination_const_cnt = ARRAY_SIZE(drvname_termination); priv->termination = CAN_TERMINATION_DISABLED; And the funtion to set the value has to be defined: priv->do_set_termination = drvname_set_termination; Signed-off-by: Oliver Hartkopp Reviewed-by: Ramesh Shanmugasundaram Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'drivers/net/can/dev.c') diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 8d6208c0b400..fefe2cd17721 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -958,6 +958,30 @@ static int can_changelink(struct net_device *dev, } } + 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) + return -EOPNOTSUPP; + + /* check whether given value is supported by the interface */ + for (i = 0; i < num_term; i++) { + if (termval == priv->termination_const[i]) + break; + } + if (i >= num_term) + return -EINVAL; + + /* Finally, set the termination value */ + err = priv->do_set_termination(dev, termval); + if (err) + return err; + + priv->termination = termval; + } + return 0; } @@ -980,6 +1004,11 @@ static size_t can_get_size(const struct net_device *dev) size += nla_total_size(sizeof(struct can_bittiming)); if (priv->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 */ + priv->termination_const_cnt); + } return size; } @@ -1018,7 +1047,15 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) (priv->data_bittiming_const && nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST, sizeof(*priv->data_bittiming_const), - priv->data_bittiming_const))) + priv->data_bittiming_const)) || + + (priv->termination_const && + (nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) || + nla_put(skb, IFLA_CAN_TERMINATION_CONST, + sizeof(*priv->termination_const) * + priv->termination_const_cnt, + priv->termination_const)))) + return -EMSGSIZE; return 0; @@ -1073,6 +1110,16 @@ static struct rtnl_link_ops can_link_ops __read_mostly = { */ int register_candev(struct net_device *dev) { + struct can_priv *priv = netdev_priv(dev); + + /* Ensure termination_const, termination_const_cnt and + * do_set_termination consistency. All must be either set or + * unset. + */ + if ((!priv->termination_const != !priv->termination_const_cnt) || + (!priv->termination_const != !priv->do_set_termination)) + return -EINVAL; + dev->rtnl_link_ops = &can_link_ops; return register_netdev(dev); } -- cgit From c3606d438a14faa8319eccb75b9502960a97af16 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 6 Jan 2017 11:12:41 +0100 Subject: can: dev: can_changelink: allow to set bitrate on devices not providing {data_,}bittiming_const Until commit 08da7da41ea4 can: provide a separate bittiming_const parameter to bittiming functions it was possible to have devices not providing bittiming_const. This can be used for hardware that only support pre-defined fixed bitrates. Although no mainline driver is using this feature so far. This patch re-introduces this feature for the bitrate and the data bitrate (of CANFD controllers). The driver can specify the {data_,}bittiming_const (if the bittiming parameters should be calculated from the bittiming_const) as before or no {data_,}bittiming_const but implement the do_set_{data,}bittiming callback. Acked-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'drivers/net/can/dev.c') diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index fefe2cd17721..afcf487382c9 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -284,10 +284,6 @@ static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt, { int err; - /* Check if the CAN device has bit-timing parameters */ - if (!btc) - return -EOPNOTSUPP; - /* * Depending on the given can_bittiming parameter structure the CAN * timing parameters are calculated based on the provided bitrate OR @@ -872,10 +868,22 @@ static int can_changelink(struct net_device *dev, /* Do not allow changing bittiming while running */ if (dev->flags & IFF_UP) return -EBUSY; + + /* Calculate bittiming parameters based on + * bittiming_const if set, otherwise pass bitrate + * directly via do_set_bitrate(). Bail out if neither + * is given. + */ + if (!priv->bittiming_const && !priv->do_set_bittiming) + return -EOPNOTSUPP; + memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); - err = can_get_bittiming(dev, &bt, priv->bittiming_const); - if (err) - return err; + if (priv->bittiming_const) { + err = can_get_bittiming(dev, &bt, + priv->bittiming_const); + if (err) + return err; + } memcpy(&priv->bittiming, &bt, sizeof(bt)); if (priv->do_set_bittiming) { @@ -943,11 +951,23 @@ static int can_changelink(struct net_device *dev, /* 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->data_bittiming_const && !priv->do_set_data_bittiming) + return -EOPNOTSUPP; + memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]), sizeof(dbt)); - err = can_get_bittiming(dev, &dbt, priv->data_bittiming_const); - if (err) - return err; + if (priv->data_bittiming_const) { + err = can_get_bittiming(dev, &dbt, + priv->data_bittiming_const); + if (err) + return err; + } memcpy(&priv->data_bittiming, &dbt, sizeof(dbt)); if (priv->do_set_data_bittiming) { -- cgit From 431af779256cd6cb8328ac23c5696bae63c33a51 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 11 Jan 2017 17:05:35 +0100 Subject: can: dev: add CAN interface API for fixed bitrates Some CAN interfaces only support fixed fixed bitrates. This patch adds a netlink interface to get the list of the CAN interface's fixed bitrates and data bitrates. Inside the driver arrays of supported data- bitrate values are defined. const u32 drvname_bitrate[] = { 20000, 50000, 100000 }; const u32 drvname_data_bitrate[] = { 200000, 500000, 1000000 }; struct drvname_priv *priv; priv = netdev_priv(dev); priv->bitrate_const = drvname_bitrate; priv->bitrate_const_cnt = ARRAY_SIZE(drvname_bitrate); priv->data_bitrate_const = drvname_data_bitrate; priv->data_bitrate_const_cnt = ARRAY_SIZE(drvname_data_bitrate); Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 81 ++++++++++++++++++++++++++++++++-------- include/linux/can/dev.h | 4 ++ include/uapi/linux/can/netlink.h | 2 + 3 files changed, 71 insertions(+), 16 deletions(-) (limited to 'drivers/net/can/dev.c') diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index afcf487382c9..611d16a7061d 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -279,8 +279,29 @@ static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, return 0; } +/* Checks the validity of predefined bitrate settings */ +static int can_validate_bitrate(struct net_device *dev, struct can_bittiming *bt, + const u32 *bitrate_const, + const unsigned int bitrate_const_cnt) +{ + struct can_priv *priv = netdev_priv(dev); + unsigned int i; + + for (i = 0; i < bitrate_const_cnt; i++) { + if (bt->bitrate == bitrate_const[i]) + break; + } + + if (i >= priv->bitrate_const_cnt) + return -EINVAL; + + return 0; +} + static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt, - const struct can_bittiming_const *btc) + const struct can_bittiming_const *btc, + const u32 *bitrate_const, + const unsigned int bitrate_const_cnt) { int err; @@ -290,10 +311,13 @@ static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt, * alternatively the CAN timing parameters (tq, prop_seg, etc.) are * provided directly which are then checked and fixed up. */ - if (!bt->tq && bt->bitrate) + if (!bt->tq && bt->bitrate && btc) err = can_calc_bittiming(dev, bt, btc); - else if (bt->tq && !bt->bitrate) + else if (bt->tq && !bt->bitrate && btc) err = can_fixup_bittiming(dev, bt, btc); + else if (!bt->tq && bt->bitrate && bitrate_const) + err = can_validate_bitrate(dev, bt, bitrate_const, + bitrate_const_cnt); else err = -EINVAL; @@ -878,12 +902,12 @@ static int can_changelink(struct net_device *dev, return -EOPNOTSUPP; memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); - if (priv->bittiming_const) { - err = can_get_bittiming(dev, &bt, - priv->bittiming_const); - if (err) - return err; - } + err = can_get_bittiming(dev, &bt, + priv->bittiming_const, + priv->bitrate_const, + priv->bitrate_const_cnt); + if (err) + return err; memcpy(&priv->bittiming, &bt, sizeof(bt)); if (priv->do_set_bittiming) { @@ -962,12 +986,12 @@ static int can_changelink(struct net_device *dev, memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]), sizeof(dbt)); - if (priv->data_bittiming_const) { - err = can_get_bittiming(dev, &dbt, - priv->data_bittiming_const); - if (err) - return err; - } + err = can_get_bittiming(dev, &dbt, + priv->data_bittiming_const, + priv->data_bitrate_const, + priv->data_bitrate_const_cnt); + if (err) + return err; memcpy(&priv->data_bittiming, &dbt, sizeof(dbt)); if (priv->do_set_data_bittiming) { @@ -1029,6 +1053,12 @@ static size_t can_get_size(const struct net_device *dev) size += nla_total_size(sizeof(*priv->termination_const) * /* IFLA_CAN_TERMINATION_CONST */ priv->termination_const_cnt); } + if (priv->bitrate_const) /* IFLA_CAN_BITRATE_CONST */ + size += nla_total_size(sizeof(*priv->bitrate_const) * + priv->bitrate_const_cnt); + if (priv->data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */ + size += nla_total_size(sizeof(*priv->data_bitrate_const) * + priv->data_bitrate_const_cnt); return size; } @@ -1074,7 +1104,20 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put(skb, IFLA_CAN_TERMINATION_CONST, sizeof(*priv->termination_const) * priv->termination_const_cnt, - priv->termination_const)))) + priv->termination_const))) || + + (priv->bitrate_const && + nla_put(skb, IFLA_CAN_BITRATE_CONST, + sizeof(*priv->bitrate_const) * + priv->bitrate_const_cnt, + priv->bitrate_const)) || + + (priv->data_bitrate_const && + nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST, + sizeof(*priv->data_bitrate_const) * + priv->data_bitrate_const_cnt, + priv->data_bitrate_const)) + ) return -EMSGSIZE; @@ -1140,6 +1183,12 @@ int register_candev(struct net_device *dev) (!priv->termination_const != !priv->do_set_termination)) return -EINVAL; + if (!priv->bitrate_const != !priv->bitrate_const_cnt) + return -EINVAL; + + if (!priv->data_bitrate_const != !priv->data_bitrate_const_cnt) + return -EINVAL; + dev->rtnl_link_ops = &can_link_ops; return register_netdev(dev); } diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index f6a57f322f00..141b05aade81 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -41,6 +41,10 @@ struct can_priv { const u16 *termination_const; unsigned int termination_const_cnt; u16 termination; + const u32 *bitrate_const; + unsigned int bitrate_const_cnt; + const u32 *data_bitrate_const; + unsigned int data_bitrate_const_cnt; struct can_clock clock; enum can_state state; diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h index 7414771926fb..fdf75f74fdaf 100644 --- a/include/uapi/linux/can/netlink.h +++ b/include/uapi/linux/can/netlink.h @@ -129,6 +129,8 @@ enum { IFLA_CAN_DATA_BITTIMING_CONST, IFLA_CAN_TERMINATION, IFLA_CAN_TERMINATION_CONST, + IFLA_CAN_BITRATE_CONST, + IFLA_CAN_DATA_BITRATE_CONST, __IFLA_CAN_MAX }; -- cgit