|
@@ -27,6 +27,7 @@
|
|
|
#include <linux/can/skb.h>
|
|
|
#include <linux/can/netlink.h>
|
|
|
#include <linux/can/led.h>
|
|
|
+#include <linux/of.h>
|
|
|
#include <net/rtnetlink.h>
|
|
|
|
|
|
#define MOD_DESC "CAN device driver interface"
|
|
@@ -814,6 +815,29 @@ int open_candev(struct net_device *dev)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(open_candev);
|
|
|
|
|
|
+#ifdef CONFIG_OF
|
|
|
+/* Common function that can be used to understand the limitation of
|
|
|
+ * a transceiver when it provides no means to determine these limitations
|
|
|
+ * at runtime.
|
|
|
+ */
|
|
|
+void of_can_transceiver(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct device_node *dn;
|
|
|
+ struct can_priv *priv = netdev_priv(dev);
|
|
|
+ struct device_node *np = dev->dev.parent->of_node;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ dn = of_get_child_by_name(np, "can-transceiver");
|
|
|
+ if (!dn)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ret = of_property_read_u32(dn, "max-bitrate", &priv->bitrate_max);
|
|
|
+ if ((ret && ret != -EINVAL) || (!ret && !priv->bitrate_max))
|
|
|
+ netdev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit.\n");
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(of_can_transceiver);
|
|
|
+#endif
|
|
|
+
|
|
|
/*
|
|
|
* Common close function for cleanup before the device gets closed.
|
|
|
*
|
|
@@ -913,6 +937,13 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
|
|
priv->bitrate_const_cnt);
|
|
|
if (err)
|
|
|
return err;
|
|
|
+
|
|
|
+ if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
|
|
|
+ netdev_err(dev, "arbitration bitrate surpasses transceiver capabilities of %d bps\n",
|
|
|
+ priv->bitrate_max);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
memcpy(&priv->bittiming, &bt, sizeof(bt));
|
|
|
|
|
|
if (priv->do_set_bittiming) {
|
|
@@ -997,6 +1028,13 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
|
|
priv->data_bitrate_const_cnt);
|
|
|
if (err)
|
|
|
return err;
|
|
|
+
|
|
|
+ if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
|
|
|
+ netdev_err(dev, "canfd data bitrate surpasses transceiver capabilities of %d bps\n",
|
|
|
+ priv->bitrate_max);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
|
|
|
|
|
|
if (priv->do_set_data_bittiming) {
|
|
@@ -1064,6 +1102,7 @@ static size_t can_get_size(const struct net_device *dev)
|
|
|
if (priv->data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */
|
|
|
size += nla_total_size(sizeof(*priv->data_bitrate_const) *
|
|
|
priv->data_bitrate_const_cnt);
|
|
|
+ size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */
|
|
|
|
|
|
return size;
|
|
|
}
|
|
@@ -1121,7 +1160,11 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|
|
nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST,
|
|
|
sizeof(*priv->data_bitrate_const) *
|
|
|
priv->data_bitrate_const_cnt,
|
|
|
- priv->data_bitrate_const))
|
|
|
+ priv->data_bitrate_const)) ||
|
|
|
+
|
|
|
+ (nla_put(skb, IFLA_CAN_BITRATE_MAX,
|
|
|
+ sizeof(priv->bitrate_max),
|
|
|
+ &priv->bitrate_max))
|
|
|
)
|
|
|
|
|
|
return -EMSGSIZE;
|