can: bittiming: can_fixup_bittiming(): report error via netlink and harmonize error...
[platform/kernel/linux-starfive.git] / drivers / net / can / dev / bittiming.c
index 7ae8076..727dcd5 100644 (file)
@@ -6,25 +6,64 @@
 
 #include <linux/can/dev.h>
 
+void can_sjw_set_default(struct can_bittiming *bt)
+{
+       if (bt->sjw)
+               return;
+
+       /* If user space provides no sjw, use 1 as default */
+       bt->sjw = 1;
+}
+
+int can_sjw_check(const struct net_device *dev, const struct can_bittiming *bt,
+                 const struct can_bittiming_const *btc, struct netlink_ext_ack *extack)
+{
+       if (bt->sjw > btc->sjw_max)
+               return -ERANGE;
+
+       return 0;
+}
+
 /* Checks the validity of the specified bit-timing parameters prop_seg,
  * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
  * prescaler value brp. You can find more information in the header
  * file linux/can/netlink.h.
  */
 static int can_fixup_bittiming(const struct net_device *dev, struct can_bittiming *bt,
-                              const struct can_bittiming_const *btc)
+                              const struct can_bittiming_const *btc,
+                              struct netlink_ext_ack *extack)
 {
+       const unsigned int tseg1 = bt->prop_seg + bt->phase_seg1;
        const struct can_priv *priv = netdev_priv(dev);
-       unsigned int tseg1, alltseg;
        u64 brp64;
+       int err;
 
-       tseg1 = bt->prop_seg + bt->phase_seg1;
-       if (!bt->sjw)
-               bt->sjw = 1;
-       if (bt->sjw > btc->sjw_max ||
-           tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
-           bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
-               return -ERANGE;
+       if (tseg1 < btc->tseg1_min) {
+               NL_SET_ERR_MSG_FMT(extack, "prop-seg + phase-seg1: %u less than tseg1-min: %u",
+                                  tseg1, btc->tseg1_min);
+               return -EINVAL;
+       }
+       if (tseg1 > btc->tseg1_max) {
+               NL_SET_ERR_MSG_FMT(extack, "prop-seg + phase-seg1: %u greater than tseg1-max: %u",
+                                  tseg1, btc->tseg1_max);
+               return -EINVAL;
+       }
+       if (bt->phase_seg2 < btc->tseg2_min) {
+               NL_SET_ERR_MSG_FMT(extack, "phase-seg2: %u less than tseg2-min: %u",
+                                  bt->phase_seg2, btc->tseg2_min);
+               return -EINVAL;
+       }
+       if (bt->phase_seg2 > btc->tseg2_max) {
+               NL_SET_ERR_MSG_FMT(extack, "phase-seg2: %u greater than tseg2-max: %u",
+                                  bt->phase_seg2, btc->tseg2_max);
+               return -EINVAL;
+       }
+
+       can_sjw_set_default(bt);
+
+       err = can_sjw_check(dev, bt, btc, extack);
+       if (err)
+               return err;
 
        brp64 = (u64)priv->clock.freq * (u64)bt->tq;
        if (btc->brp_inc > 1)
@@ -35,12 +74,21 @@ static int can_fixup_bittiming(const struct net_device *dev, struct can_bittimin
                brp64 *= btc->brp_inc;
        bt->brp = (u32)brp64;
 
-       if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
+       if (bt->brp < btc->brp_min) {
+               NL_SET_ERR_MSG_FMT(extack, "resulting brp: %u less than brp-min: %u",
+                                  bt->brp, btc->brp_min);
                return -EINVAL;
+       }
+       if (bt->brp > btc->brp_max) {
+               NL_SET_ERR_MSG_FMT(extack, "resulting brp: %u greater than brp-max: %u",
+                                  bt->brp, btc->brp_max);
+               return -EINVAL;
+       }
 
-       alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
-       bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
-       bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
+       bt->bitrate = priv->clock.freq / (bt->brp * can_bit_time(bt));
+       bt->sample_point = ((CAN_SYNC_SEG + tseg1) * 1000) / can_bit_time(bt);
+       bt->tq = DIV_U64_ROUND_CLOSEST(mul_u32_u32(bt->brp, NSEC_PER_SEC),
+                                      priv->clock.freq);
 
        return 0;
 }
@@ -49,7 +97,8 @@ static int can_fixup_bittiming(const struct net_device *dev, struct can_bittimin
 static int
 can_validate_bitrate(const struct net_device *dev, const struct can_bittiming *bt,
                     const u32 *bitrate_const,
-                    const unsigned int bitrate_const_cnt)
+                    const unsigned int bitrate_const_cnt,
+                    struct netlink_ext_ack *extack)
 {
        unsigned int i;
 
@@ -64,24 +113,21 @@ can_validate_bitrate(const struct net_device *dev, const struct can_bittiming *b
 int can_get_bittiming(const struct net_device *dev, struct can_bittiming *bt,
                      const struct can_bittiming_const *btc,
                      const u32 *bitrate_const,
-                     const unsigned int bitrate_const_cnt)
+                     const unsigned int bitrate_const_cnt,
+                     struct netlink_ext_ack *extack)
 {
-       int err;
-
        /* Depending on the given can_bittiming parameter structure the CAN
         * timing parameters are calculated based on the provided bitrate OR
         * alternatively the CAN timing parameters (tq, prop_seg, etc.) are
         * provided directly which are then checked and fixed up.
         */
        if (!bt->tq && bt->bitrate && btc)
-               err = can_calc_bittiming(dev, bt, btc);
-       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;
-
-       return err;
+               return can_calc_bittiming(dev, bt, btc, extack);
+       if (bt->tq && !bt->bitrate && btc)
+               return can_fixup_bittiming(dev, bt, btc, extack);
+       if (!bt->tq && bt->bitrate && bitrate_const)
+               return can_validate_bitrate(dev, bt, bitrate_const,
+                                           bitrate_const_cnt, extack);
+
+       return -EINVAL;
 }