Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: dev: Add support for limiting configured bitrate

Various CAN or CAN-FD IP may be able to run at a faster rate than
what the transceiver the CAN node is connected to. This can lead to
unexpected errors. However, CAN transceivers typically have fixed
limitations and provide no means to discover these limitations at
runtime. Therefore, add support for a can-transceiver node that
can be reused by other CAN peripheral drivers to determine for both
CAN and CAN-FD what the max bitrate that can be used. If the user
tries to configure CAN to pass these maximum bitrates it will throw
an error.

Also add support for reading bitrate_max via the netlink interface.

Reviewed-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Franklin S Cooper Jr <fcooper@ti.com>
[nsekhar@ti.com: fix build error with !CONFIG_OF]
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Franklin S Cooper Jr and committed by
Marc Kleine-Budde
2290aefa 54a7fbcc

+52 -1
+44 -1
drivers/net/can/dev.c
··· 27 27 #include <linux/can/skb.h> 28 28 #include <linux/can/netlink.h> 29 29 #include <linux/can/led.h> 30 + #include <linux/of.h> 30 31 #include <net/rtnetlink.h> 31 32 32 33 #define MOD_DESC "CAN device driver interface" ··· 815 814 } 816 815 EXPORT_SYMBOL_GPL(open_candev); 817 816 817 + #ifdef CONFIG_OF 818 + /* Common function that can be used to understand the limitation of 819 + * a transceiver when it provides no means to determine these limitations 820 + * at runtime. 821 + */ 822 + void of_can_transceiver(struct net_device *dev) 823 + { 824 + struct device_node *dn; 825 + struct can_priv *priv = netdev_priv(dev); 826 + struct device_node *np = dev->dev.parent->of_node; 827 + int ret; 828 + 829 + dn = of_get_child_by_name(np, "can-transceiver"); 830 + if (!dn) 831 + return; 832 + 833 + ret = of_property_read_u32(dn, "max-bitrate", &priv->bitrate_max); 834 + if ((ret && ret != -EINVAL) || (!ret && !priv->bitrate_max)) 835 + netdev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit.\n"); 836 + } 837 + EXPORT_SYMBOL_GPL(of_can_transceiver); 838 + #endif 839 + 818 840 /* 819 841 * Common close function for cleanup before the device gets closed. 820 842 * ··· 937 913 priv->bitrate_const_cnt); 938 914 if (err) 939 915 return err; 916 + 917 + if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) { 918 + netdev_err(dev, "arbitration bitrate surpasses transceiver capabilities of %d bps\n", 919 + priv->bitrate_max); 920 + return -EINVAL; 921 + } 922 + 940 923 memcpy(&priv->bittiming, &bt, sizeof(bt)); 941 924 942 925 if (priv->do_set_bittiming) { ··· 1028 997 priv->data_bitrate_const_cnt); 1029 998 if (err) 1030 999 return err; 1000 + 1001 + if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) { 1002 + netdev_err(dev, "canfd data bitrate surpasses transceiver capabilities of %d bps\n", 1003 + priv->bitrate_max); 1004 + return -EINVAL; 1005 + } 1006 + 1031 1007 memcpy(&priv->data_bittiming, &dbt, sizeof(dbt)); 1032 1008 1033 1009 if (priv->do_set_data_bittiming) { ··· 1102 1064 if (priv->data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */ 1103 1065 size += nla_total_size(sizeof(*priv->data_bitrate_const) * 1104 1066 priv->data_bitrate_const_cnt); 1067 + size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */ 1105 1068 1106 1069 return size; 1107 1070 } ··· 1160 1121 nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST, 1161 1122 sizeof(*priv->data_bitrate_const) * 1162 1123 priv->data_bitrate_const_cnt, 1163 - priv->data_bitrate_const)) 1124 + priv->data_bitrate_const)) || 1125 + 1126 + (nla_put(skb, IFLA_CAN_BITRATE_MAX, 1127 + sizeof(priv->bitrate_max), 1128 + &priv->bitrate_max)) 1164 1129 ) 1165 1130 1166 1131 return -EMSGSIZE;
+7
include/linux/can/dev.h
··· 46 46 unsigned int bitrate_const_cnt; 47 47 const u32 *data_bitrate_const; 48 48 unsigned int data_bitrate_const_cnt; 49 + u32 bitrate_max; 49 50 struct can_clock clock; 50 51 51 52 enum can_state state; ··· 166 165 unsigned int idx); 167 166 unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx); 168 167 void can_free_echo_skb(struct net_device *dev, unsigned int idx); 168 + 169 + #ifdef CONFIG_OF 170 + void of_can_transceiver(struct net_device *dev); 171 + #else 172 + static inline void of_can_transceiver(struct net_device *dev) { } 173 + #endif 169 174 170 175 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf); 171 176 struct sk_buff *alloc_canfd_skb(struct net_device *dev,
+1
include/uapi/linux/can/netlink.h
··· 132 132 IFLA_CAN_TERMINATION_CONST, 133 133 IFLA_CAN_BITRATE_CONST, 134 134 IFLA_CAN_DATA_BITRATE_CONST, 135 + IFLA_CAN_BITRATE_MAX, 135 136 __IFLA_CAN_MAX 136 137 }; 137 138