History

can: netlink: add PWM netlink interface

When the TMS is switched on, the node uses PWM (Pulse Width Modulation) during the data phase instead of the classic NRZ (Non Return to Zero) encoding. PWM is configured by three parameters: - PWMS: Pulse Width Modulation Short phase - PWML: Pulse Width Modulation Long phase - PWMO: Pulse Width Modulation Offset time For each of these parameters, define three IFLA symbols: - IFLA_CAN_PWM_PWM*_MIN: the minimum allowed value. - IFLA_CAN_PWM_PWM*_MAX: the maximum allowed value. - IFLA_CAN_PWM_PWM*: the runtime value. This results in a total of nine IFLA symbols which are all nested in a parent IFLA_CAN_XL_PWM symbol. IFLA_CAN_PWM_PWM*_MIN and IFLA_CAN_PWM_PWM*_MAX define the range of allowed values and will match the value statically configured by the device in struct can_pwm_const. IFLA_CAN_PWM_PWM* match the runtime values stored in struct can_pwm. Those parameters may only be configured when the tms mode is on. If the PWMS, PWML and PWMO parameters are provided, check that all the needed parameters are present using can_validate_pwm(), then check their value using can_validate_pwm_bittiming(). PWMO defaults to zero if omitted. Otherwise, if CAN_CTRLMODE_XL_TMS is true but none of the PWM parameters are provided, calculate them using can_calc_pwm().

Vincent Mailhol committed 11 months ago

Commit 46552321 parent 98923392 files · +215 −2Browse files

Unified · Split

2 files
  1. drivers/net/can/dev/netlink.c +190 −2
  2. include/uapi/linux/can/netlink.h +25 −0
drivers/net/can/dev/netlink.c+190−2
@@ -25,6 +25,7 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { · 24 unmodified lines
2525 [IFLA_CAN_XL_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) },
2626 [IFLA_CAN_XL_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) },
2727 [IFLA_CAN_XL_TDC] = { .type = NLA_NESTED },
28+ [IFLA_CAN_XL_PWM] = { .type = NLA_NESTED },
2829 };
2930
3031 static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] = {
@@ -39,6 +40,18 @@ static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] = { · 8 unmodified lines
3940 [IFLA_CAN_TDC_TDCF] = { .type = NLA_U32 },
4041 };
4142
43+static const struct nla_policy can_pwm_policy[IFLA_CAN_PWM_MAX + 1] = {
44+ [IFLA_CAN_PWM_PWMS_MIN] = { .type = NLA_U32 },
45+ [IFLA_CAN_PWM_PWMS_MAX] = { .type = NLA_U32 },
46+ [IFLA_CAN_PWM_PWML_MIN] = { .type = NLA_U32 },
47+ [IFLA_CAN_PWM_PWML_MAX] = { .type = NLA_U32 },
48+ [IFLA_CAN_PWM_PWMO_MIN] = { .type = NLA_U32 },
49+ [IFLA_CAN_PWM_PWMO_MAX] = { .type = NLA_U32 },
50+ [IFLA_CAN_PWM_PWMS] = { .type = NLA_U32 },
51+ [IFLA_CAN_PWM_PWML] = { .type = NLA_U32 },
52+ [IFLA_CAN_PWM_PWMO] = { .type = NLA_U32 },
53+};
54+
4255 static int can_validate_bittiming(struct nlattr *data[],
4356 struct netlink_ext_ack *extack,
4457 int ifla_can_bittiming)
@@ -119,6 +132,40 @@ static int can_validate_tdc(struct nlattr *data_tdc, · 74 unmodified lines
119132 return 0;
120133 }
121134
135+static int can_validate_pwm(struct nlattr *data[],
136+ struct netlink_ext_ack *extack, u32 flags)
137+{
138+ struct nlattr *tb_pwm[IFLA_CAN_PWM_MAX + 1];
139+ int err;
140+
141+ if (!data[IFLA_CAN_XL_PWM])
142+ return 0;
143+
144+ if (!(flags & CAN_CTRLMODE_XL_TMS)) {
145+ NL_SET_ERR_MSG(extack, "PWM requires TMS");
146+ return -EOPNOTSUPP;
147+ }
148+
149+ err = nla_parse_nested(tb_pwm, IFLA_CAN_PWM_MAX, data[IFLA_CAN_XL_PWM],
150+ can_pwm_policy, extack);
151+ if (err)
152+ return err;
153+
154+ if (!tb_pwm[IFLA_CAN_PWM_PWMS] != !tb_pwm[IFLA_CAN_PWM_PWML]) {
155+ NL_SET_ERR_MSG(extack,
156+ "Provide either both PWMS and PWML, or none for automatic calculation");
157+ return -EOPNOTSUPP;
158+ }
159+
160+ if (tb_pwm[IFLA_CAN_PWM_PWMO] &&
161+ (!tb_pwm[IFLA_CAN_PWM_PWMS] || !tb_pwm[IFLA_CAN_PWM_PWML])) {
162+ NL_SET_ERR_MSG(extack, "PWMO requires both PWMS and PWML");
163+ return -EOPNOTSUPP;
164+ }
165+
166+ return 0;
167+}
168+
122169 static int can_validate_databittiming(struct nlattr *data[],
123170 struct netlink_ext_ack *extack,
124171 int ifla_can_data_bittiming, u32 flags)
@@ -247,6 +294,10 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[], · 122 unmodified lines
247294 if (err)
248295 return err;
249296
297+ err = can_validate_pwm(data, extack, flags);
298+ if (err)
299+ return err;
300+
250301 return 0;
251302 }
252303
@@ -322,6 +373,7 @@ static int can_ctrlmode_changelink(struct net_device *dev, · 69 unmodified lines
322373 sizeof(priv->fd.data_bittiming));
323374 priv->ctrlmode &= ~CAN_CTRLMODE_XL_TDC_MASK;
324375 memset(&priv->xl.tdc, 0, sizeof(priv->xl.tdc));
376+ memset(&priv->xl.pwm, 0, sizeof(priv->xl.pwm));
325377 }
326378
327379 can_set_default_mtu(dev);
@@ -468,6 +520,76 @@ static int can_dbt_changelink(struct net_device *dev, struct nlattr *data[], · 140 unmodified lines
468520 return 0;
469521 }
470522
523+static int can_pwm_changelink(struct net_device *dev,
524+ const struct nlattr *pwm_nla,
525+ struct netlink_ext_ack *extack)
526+{
527+ struct can_priv *priv = netdev_priv(dev);
528+ const struct can_pwm_const *pwm_const = priv->xl.pwm_const;
529+ struct nlattr *tb_pwm[IFLA_CAN_PWM_MAX + 1];
530+ struct can_pwm pwm = { 0 };
531+ int err;
532+
533+ if (!(priv->ctrlmode & CAN_CTRLMODE_XL_TMS))
534+ return 0;
535+
536+ if (!pwm_const) {
537+ NL_SET_ERR_MSG(extack, "The device does not support PWM");
538+ return -EOPNOTSUPP;
539+ }
540+
541+ if (!pwm_nla)
542+ return can_calc_pwm(dev, extack);
543+
544+ err = nla_parse_nested(tb_pwm, IFLA_CAN_PWM_MAX, pwm_nla,
545+ can_pwm_policy, extack);
546+ if (err)
547+ return err;
548+
549+ if (tb_pwm[IFLA_CAN_PWM_PWMS]) {
550+ pwm.pwms = nla_get_u32(tb_pwm[IFLA_CAN_PWM_PWMS]);
551+ if (pwm.pwms < pwm_const->pwms_min ||
552+ pwm.pwms > pwm_const->pwms_max) {
553+ NL_SET_ERR_MSG_FMT(extack,
554+ "PWMS: %u tqmin is out of range: %u...%u",
555+ pwm.pwms, pwm_const->pwms_min,
556+ pwm_const->pwms_max);
557+ return -EINVAL;
558+ }
559+ }
560+
561+ if (tb_pwm[IFLA_CAN_PWM_PWML]) {
562+ pwm.pwml = nla_get_u32(tb_pwm[IFLA_CAN_PWM_PWML]);
563+ if (pwm.pwml < pwm_const->pwml_min ||
564+ pwm.pwml > pwm_const->pwml_max) {
565+ NL_SET_ERR_MSG_FMT(extack,
566+ "PWML: %u tqmin is out of range: %u...%u",
567+ pwm.pwml, pwm_const->pwml_min,
568+ pwm_const->pwml_max);
569+ return -EINVAL;
570+ }
571+ }
572+
573+ if (tb_pwm[IFLA_CAN_PWM_PWMO]) {
574+ pwm.pwmo = nla_get_u32(tb_pwm[IFLA_CAN_PWM_PWMO]);
575+ if (pwm.pwmo < pwm_const->pwmo_min ||
576+ pwm.pwmo > pwm_const->pwmo_max) {
577+ NL_SET_ERR_MSG_FMT(extack,
578+ "PWMO: %u tqmin is out of range: %u...%u",
579+ pwm.pwmo, pwm_const->pwmo_min,
580+ pwm_const->pwmo_max);
581+ return -EINVAL;
582+ }
583+ }
584+
585+ err = can_validate_pwm_bittiming(dev, &pwm, extack);
586+ if (err)
587+ return err;
588+
589+ priv->xl.pwm = pwm;
590+ return 0;
591+}
592+
471593 static int can_changelink(struct net_device *dev, struct nlattr *tb[],
472594 struct nlattr *data[],
473595 struct netlink_ext_ack *extack)
@@ -559,6 +681,9 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], · 85 unmodified lines
559681
560682 /* CAN XL */
561683 err = can_dbt_changelink(dev, data, false, extack);
684+ if (err)
685+ return err;
686+ err = can_pwm_changelink(dev, data[IFLA_CAN_XL_PWM], extack);
562687 if (err)
563688 return err;
564689
@@ -647,6 +772,30 @@ static size_t can_ctrlmode_ext_get_size(void) · 82 unmodified lines
647772 nla_total_size(sizeof(u32)); /* IFLA_CAN_CTRLMODE_SUPPORTED */
648773 }
649774
775+static size_t can_pwm_get_size(const struct can_pwm_const *pwm_const,
776+ bool pwm_on)
777+{
778+ size_t size;
779+
780+ if (!pwm_const || !pwm_on)
781+ return 0;
782+
783+ size = nla_total_size(0); /* nest IFLA_CAN_PWM */
784+
785+ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMS_MIN */
786+ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMS_MAX */
787+ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWML_MIN */
788+ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWML_MAX */
789+ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMO_MIN */
790+ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMO_MAX */
791+
792+ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMS */
793+ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWML */
794+ size += nla_total_size(sizeof(u32)); /* IFLA_CAN_PWM_PWMO */
795+
796+ return size;
797+}
798+
650799 static size_t can_get_size(const struct net_device *dev)
651800 {
652801 struct can_priv *priv = netdev_priv(dev);
@@ -678,6 +827,8 @@ static size_t can_get_size(const struct net_device *dev) · 25 unmodified lines
678827
679828 size += can_data_bittiming_get_size(&priv->xl,
680829 priv->ctrlmode & CAN_CTRLMODE_XL_TDC_MASK);
830+ size += can_pwm_get_size(priv->xl.pwm_const, /* IFLA_CAN_XL_PWM */
831+ priv->ctrlmode & CAN_CTRLMODE_XL_TMS);
681832
682833 return size;
683834 }
@@ -776,6 +927,42 @@ err_cancel: · 92 unmodified lines
776927 return -EMSGSIZE;
777928 }
778929
930+static int can_pwm_fill_info(struct sk_buff *skb, const struct can_priv *priv)
931+{
932+ const struct can_pwm_const *pwm_const = priv->xl.pwm_const;
933+ const struct can_pwm *pwm = &priv->xl.pwm;
934+ struct nlattr *nest;
935+
936+ if (!pwm_const)
937+ return 0;
938+
939+ nest = nla_nest_start(skb, IFLA_CAN_XL_PWM);
940+ if (!nest)
941+ return -EMSGSIZE;
942+
943+ if (nla_put_u32(skb, IFLA_CAN_PWM_PWMS_MIN, pwm_const->pwms_min) ||
944+ nla_put_u32(skb, IFLA_CAN_PWM_PWMS_MAX, pwm_const->pwms_max) ||
945+ nla_put_u32(skb, IFLA_CAN_PWM_PWML_MIN, pwm_const->pwml_min) ||
946+ nla_put_u32(skb, IFLA_CAN_PWM_PWML_MAX, pwm_const->pwml_max) ||
947+ nla_put_u32(skb, IFLA_CAN_PWM_PWMO_MIN, pwm_const->pwmo_min) ||
948+ nla_put_u32(skb, IFLA_CAN_PWM_PWMO_MAX, pwm_const->pwmo_max))
949+ goto err_cancel;
950+
951+ if (priv->ctrlmode & CAN_CTRLMODE_XL_TMS) {
952+ if (nla_put_u32(skb, IFLA_CAN_PWM_PWMS, pwm->pwms) ||
953+ nla_put_u32(skb, IFLA_CAN_PWM_PWML, pwm->pwml) ||
954+ nla_put_u32(skb, IFLA_CAN_PWM_PWMO, pwm->pwmo))
955+ goto err_cancel;
956+ }
957+
958+ nla_nest_end(skb, nest);
959+ return 0;
960+
961+err_cancel:
962+ nla_nest_cancel(skb, nest);
963+ return -EMSGSIZE;
964+}
965+
779966 static int can_ctrlmode_ext_fill_info(struct sk_buff *skb,
780967 const struct can_priv *priv)
781968 {
@@ -859,9 +1046,10 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) · 77 unmodified lines
8591046 priv->xl.data_bitrate_const,
8601047 priv->xl.data_bitrate_const_cnt) ||
8611048
862− can_tdc_fill_info(skb, dev, IFLA_CAN_XL_TDC)
863− )
1049+ can_tdc_fill_info(skb, dev, IFLA_CAN_XL_TDC) ||
8641050
1051+ can_pwm_fill_info(skb, priv)
1052+ )
8651053 return -EMSGSIZE;
8661054
8671055 return 0;
include/uapi/linux/can/netlink.h+25−0
@@ -5,6 +5,7 @@ · 4 unmodified lines
55 * Definitions for the CAN netlink interface
66 *
77 * Copyright (c) 2009 Wolfgang Grandegger <wg@grandegger.com>
8+ * Copyright (c) 2021-2025 Vincent Mailhol <mailhol@kernel.org>
89 *
910 * This program is free software; you can redistribute it and/or modify
1011 * it under the terms of the version 2 of the GNU General Public License
@@ -147,6 +148,7 @@ enum { · 136 unmodified lines
147148 IFLA_CAN_XL_DATA_BITTIMING_CONST,
148149 IFLA_CAN_XL_DATA_BITRATE_CONST,
149150 IFLA_CAN_XL_TDC,
151+ IFLA_CAN_XL_PWM,
150152
151153 /* add new constants above here */
152154 __IFLA_CAN_MAX,
@@ -188,6 +190,29 @@ enum { · 35 unmodified lines
188190 IFLA_CAN_CTRLMODE_MAX = __IFLA_CAN_CTRLMODE - 1
189191 };
190192
193+/*
194+ * CAN FD/XL Pulse-Width Modulation (PWM)
195+ *
196+ * Please refer to struct can_pwm_const and can_pwm in
197+ * include/linux/can/bittiming.h for further details.
198+ */
199+enum {
200+ IFLA_CAN_PWM_UNSPEC,
201+ IFLA_CAN_PWM_PWMS_MIN, /* u32 */
202+ IFLA_CAN_PWM_PWMS_MAX, /* u32 */
203+ IFLA_CAN_PWM_PWML_MIN, /* u32 */
204+ IFLA_CAN_PWM_PWML_MAX, /* u32 */
205+ IFLA_CAN_PWM_PWMO_MIN, /* u32 */
206+ IFLA_CAN_PWM_PWMO_MAX, /* u32 */
207+ IFLA_CAN_PWM_PWMS, /* u32 */
208+ IFLA_CAN_PWM_PWML, /* u32 */
209+ IFLA_CAN_PWM_PWMO, /* u32 */
210+
211+ /* add new constants above here */
212+ __IFLA_CAN_PWM,
213+ IFLA_CAN_PWM_MAX = __IFLA_CAN_PWM - 1
214+};
215+
191216 /* u16 termination range: 1..65535 Ohms */
192217 #define CAN_TERMINATION_DISABLED 0
193218