can: dev: add CAN interface API for fixed bitrates
authorMarc Kleine-Budde <mkl@pengutronix.de>
Wed, 11 Jan 2017 16:05:35 +0000 (17:05 +0100)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Tue, 24 Jan 2017 12:52:00 +0000 (13:52 +0100)
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 <mkl@pengutronix.de>
drivers/net/can/dev.c
include/linux/can/dev.h
include/uapi/linux/can/netlink.h

index afcf487..611d16a 100644 (file)
@@ -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);
 }
index f6a57f3..141b05a 100644 (file)
@@ -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;
index 7414771..fdf75f7 100644 (file)
@@ -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
 };