]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
can: netlink: add CAN_CTRLMODE_XL_TMS flag
authorVincent Mailhol <mailhol@kernel.org>
Wed, 26 Nov 2025 10:16:07 +0000 (11:16 +0100)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Wed, 26 Nov 2025 10:20:43 +0000 (11:20 +0100)
The Transceiver Mode Switching (TMS) indicates whether the CAN XL
controller shall use the PWM or NRZ encoding during the data phase.

The term "transceiver mode switching" is used in both ISO 11898-1 and
CiA 612-2 (although only the latter one uses the abbreviation TMS). We
adopt the same naming convention here for consistency.

Add the CAN_CTRLMODE_XL_TMS flag to the list of the CAN control modes.

Add can_validate_xl_flags() to check the coherency of the TMS flag.
That function will be reused in upcoming changes to validate the other
CAN XL flags.

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20251126-canxl-v8-6-e7e3eb74f889@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/dev/dev.c
drivers/net/can/dev/netlink.c
include/uapi/linux/can/netlink.h

index bdec2c52c8ecdf40bf5bb710348cc72b191a54be..091f30e94c610cdfb6b808177be73538220627e4 100644 (file)
@@ -123,6 +123,8 @@ const char *can_get_ctrlmode_str(u32 ctrlmode)
                return "XL-TDC-AUTO";
        case CAN_CTRLMODE_XL_TDC_MANUAL:
                return "XL-TDC-MANUAL";
+       case CAN_CTRLMODE_XL_TMS:
+               return "TMS";
        default:
                return "<unknown>";
        }
index fdd1fa7cf93aa81415c4a4d28fe994c6f3ec37da..b2c24439abba66c68e731ce79ace99e89030cd96 100644 (file)
@@ -181,6 +181,32 @@ static int can_validate_databittiming(struct nlattr *data[],
        return 0;
 }
 
+static int can_validate_xl_flags(struct netlink_ext_ack *extack,
+                                u32 masked_flags, u32 mask)
+{
+       if (masked_flags & CAN_CTRLMODE_XL) {
+               if (masked_flags & CAN_CTRLMODE_XL_TMS) {
+                       const u32 tms_conflicts_mask = CAN_CTRLMODE_FD |
+                               CAN_CTRLMODE_XL_TDC_MASK;
+                       u32 tms_conflicts = masked_flags & tms_conflicts_mask;
+
+                       if (tms_conflicts) {
+                               NL_SET_ERR_MSG_FMT(extack,
+                                                  "TMS and %s are mutually exclusive",
+                                                  can_get_ctrlmode_str(tms_conflicts));
+                               return -EOPNOTSUPP;
+                       }
+               }
+       } else {
+               if (mask & CAN_CTRLMODE_XL_TMS) {
+                       NL_SET_ERR_MSG(extack, "TMS requires CAN XL");
+                       return -EOPNOTSUPP;
+               }
+       }
+
+       return 0;
+}
+
 static int can_validate(struct nlattr *tb[], struct nlattr *data[],
                        struct netlink_ext_ack *extack)
 {
@@ -201,6 +227,10 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
                                       "LISTEN-ONLY and RESTRICTED modes are mutually exclusive");
                        return -EOPNOTSUPP;
                }
+
+               err = can_validate_xl_flags(extack, flags, cm->mask);
+               if (err)
+                       return err;
        }
 
        err = can_validate_bittiming(data, extack, IFLA_CAN_BITTIMING);
@@ -226,7 +256,7 @@ static int can_ctrlmode_changelink(struct net_device *dev,
 {
        struct can_priv *priv = netdev_priv(dev);
        struct can_ctrlmode *cm;
-       u32 ctrlstatic, maskedflags, notsupp, ctrlstatic_missing;
+       u32 ctrlstatic, maskedflags, deactivated, notsupp, ctrlstatic_missing;
 
        if (!data[IFLA_CAN_CTRLMODE])
                return 0;
@@ -238,6 +268,7 @@ static int can_ctrlmode_changelink(struct net_device *dev,
        cm = nla_data(data[IFLA_CAN_CTRLMODE]);
        ctrlstatic = can_get_static_ctrlmode(priv);
        maskedflags = cm->flags & cm->mask;
+       deactivated = ~cm->flags & cm->mask;
        notsupp = maskedflags & ~(priv->ctrlmode_supported | ctrlstatic);
        ctrlstatic_missing = (maskedflags & ctrlstatic) ^ ctrlstatic;
 
@@ -259,11 +290,21 @@ static int can_ctrlmode_changelink(struct net_device *dev,
                return -EOPNOTSUPP;
        }
 
+       /* If FD was active and is not turned off, check for XL conflicts */
+       if (priv->ctrlmode & CAN_CTRLMODE_FD & ~deactivated) {
+               if (maskedflags & CAN_CTRLMODE_XL_TMS) {
+                       NL_SET_ERR_MSG(extack,
+                                      "TMS can not be activated while CAN FD is on");
+                       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;
        if (cm->mask & CAN_CTRLMODE_XL)
-               priv->ctrlmode &= ~(CAN_CTRLMODE_XL_TDC_MASK);
+               priv->ctrlmode &= ~(CAN_CTRLMODE_XL_TDC_MASK |
+                                   CAN_CTRLMODE_XL_TMS);
 
        /* clear bits to be modified and copy the flag values */
        priv->ctrlmode &= ~cm->mask;
@@ -395,7 +436,8 @@ static int can_dbt_changelink(struct net_device *dev, struct nlattr *data[],
        if (data[IFLA_CAN_CTRLMODE]) {
                struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
 
-               need_tdc_calc = !(cm->mask & tdc_mask);
+               if (fd || !(priv->ctrlmode & CAN_CTRLMODE_XL_TMS))
+                       need_tdc_calc = !(cm->mask & tdc_mask);
        }
        if (data_tdc) {
                /* TDC parameters are provided: use them */
index c2c96c5978a8fa27adc0e742b227017cfb256a13..ebafb091d80fef6b35f329c42b4e16f19a05df5d 100644 (file)
@@ -107,6 +107,7 @@ struct can_ctrlmode {
 #define CAN_CTRLMODE_XL                        0x1000  /* CAN XL mode */
 #define CAN_CTRLMODE_XL_TDC_AUTO       0x2000  /* XL transceiver automatically calculates TDCV */
 #define CAN_CTRLMODE_XL_TDC_MANUAL     0x4000  /* XL TDCV is manually set up by user */
+#define CAN_CTRLMODE_XL_TMS            0x8000  /* Transceiver Mode Switching */
 
 /*
  * CAN device statistics