Thomas Gleixner | 35e62ae | 2019-05-29 16:57:58 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 2 | /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 3 | * Copyright (C) 2006 Andrey Volkov, Varma Electronics |
| 4 | * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 5 | */ |
| 6 | |
| 7 | #include <linux/module.h> |
| 8 | #include <linux/kernel.h> |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 9 | #include <linux/slab.h> |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 10 | #include <linux/netdevice.h> |
| 11 | #include <linux/if_arp.h> |
Sergei Miroshnichenko | 9abefcb | 2016-09-07 16:51:12 +0300 | [diff] [blame] | 12 | #include <linux/workqueue.h> |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 13 | #include <linux/can.h> |
Marc Kleine-Budde | ffd956e | 2018-10-08 09:02:38 +0200 | [diff] [blame] | 14 | #include <linux/can/can-ml.h> |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 15 | #include <linux/can/dev.h> |
Oliver Hartkopp | 156c2bb | 2013-01-17 18:43:39 +0100 | [diff] [blame] | 16 | #include <linux/can/skb.h> |
Kurt Van Dijck | a1ef7bd | 2012-12-18 18:50:57 +0100 | [diff] [blame] | 17 | #include <linux/can/led.h> |
Franklin S Cooper Jr | 2290aef | 2018-01-10 16:25:18 +0530 | [diff] [blame] | 18 | #include <linux/of.h> |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 19 | |
| 20 | #define MOD_DESC "CAN device driver interface" |
| 21 | |
| 22 | MODULE_DESCRIPTION(MOD_DESC); |
| 23 | MODULE_LICENSE("GPL v2"); |
| 24 | MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); |
| 25 | |
Andri Yngvason | bac78aa | 2014-12-03 17:54:13 +0000 | [diff] [blame] | 26 | static void can_update_state_error_stats(struct net_device *dev, |
| 27 | enum can_state new_state) |
| 28 | { |
| 29 | struct can_priv *priv = netdev_priv(dev); |
| 30 | |
| 31 | if (new_state <= priv->state) |
| 32 | return; |
| 33 | |
| 34 | switch (new_state) { |
| 35 | case CAN_STATE_ERROR_WARNING: |
| 36 | priv->can_stats.error_warning++; |
| 37 | break; |
| 38 | case CAN_STATE_ERROR_PASSIVE: |
| 39 | priv->can_stats.error_passive++; |
| 40 | break; |
| 41 | case CAN_STATE_BUS_OFF: |
Andri Yngvason | be38a6f | 2015-01-16 14:30:28 +0000 | [diff] [blame] | 42 | priv->can_stats.bus_off++; |
| 43 | break; |
Andri Yngvason | bac78aa | 2014-12-03 17:54:13 +0000 | [diff] [blame] | 44 | default: |
| 45 | break; |
kbuild test robot | 5b5ba2a | 2015-01-16 16:52:21 +0800 | [diff] [blame] | 46 | } |
Andri Yngvason | bac78aa | 2014-12-03 17:54:13 +0000 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | static int can_tx_state_to_frame(struct net_device *dev, enum can_state state) |
| 50 | { |
| 51 | switch (state) { |
| 52 | case CAN_STATE_ERROR_ACTIVE: |
| 53 | return CAN_ERR_CRTL_ACTIVE; |
| 54 | case CAN_STATE_ERROR_WARNING: |
| 55 | return CAN_ERR_CRTL_TX_WARNING; |
| 56 | case CAN_STATE_ERROR_PASSIVE: |
| 57 | return CAN_ERR_CRTL_TX_PASSIVE; |
| 58 | default: |
| 59 | return 0; |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | static int can_rx_state_to_frame(struct net_device *dev, enum can_state state) |
| 64 | { |
| 65 | switch (state) { |
| 66 | case CAN_STATE_ERROR_ACTIVE: |
| 67 | return CAN_ERR_CRTL_ACTIVE; |
| 68 | case CAN_STATE_ERROR_WARNING: |
| 69 | return CAN_ERR_CRTL_RX_WARNING; |
| 70 | case CAN_STATE_ERROR_PASSIVE: |
| 71 | return CAN_ERR_CRTL_RX_PASSIVE; |
| 72 | default: |
| 73 | return 0; |
| 74 | } |
| 75 | } |
| 76 | |
Vincent Mailhol | 6fe27d6 | 2021-01-20 02:03:55 +0900 | [diff] [blame] | 77 | const char *can_get_state_str(const enum can_state state) |
Marc Kleine-Budde | f81eb48 | 2020-09-16 00:35:02 +0200 | [diff] [blame] | 78 | { |
| 79 | switch (state) { |
| 80 | case CAN_STATE_ERROR_ACTIVE: |
| 81 | return "Error Active"; |
| 82 | case CAN_STATE_ERROR_WARNING: |
| 83 | return "Error Warning"; |
| 84 | case CAN_STATE_ERROR_PASSIVE: |
| 85 | return "Error Passive"; |
| 86 | case CAN_STATE_BUS_OFF: |
| 87 | return "Bus Off"; |
| 88 | case CAN_STATE_STOPPED: |
| 89 | return "Stopped"; |
| 90 | case CAN_STATE_SLEEPING: |
| 91 | return "Sleeping"; |
| 92 | default: |
| 93 | return "<unknown>"; |
| 94 | } |
| 95 | |
| 96 | return "<unknown>"; |
| 97 | } |
Vincent Mailhol | 6fe27d6 | 2021-01-20 02:03:55 +0900 | [diff] [blame] | 98 | EXPORT_SYMBOL_GPL(can_get_state_str); |
Marc Kleine-Budde | f81eb48 | 2020-09-16 00:35:02 +0200 | [diff] [blame] | 99 | |
Andri Yngvason | bac78aa | 2014-12-03 17:54:13 +0000 | [diff] [blame] | 100 | void can_change_state(struct net_device *dev, struct can_frame *cf, |
| 101 | enum can_state tx_state, enum can_state rx_state) |
| 102 | { |
| 103 | struct can_priv *priv = netdev_priv(dev); |
| 104 | enum can_state new_state = max(tx_state, rx_state); |
| 105 | |
| 106 | if (unlikely(new_state == priv->state)) { |
| 107 | netdev_warn(dev, "%s: oops, state did not change", __func__); |
| 108 | return; |
| 109 | } |
| 110 | |
Marc Kleine-Budde | f81eb48 | 2020-09-16 00:35:02 +0200 | [diff] [blame] | 111 | netdev_dbg(dev, "Controller changed from %s State (%d) into %s State (%d).\n", |
| 112 | can_get_state_str(priv->state), priv->state, |
| 113 | can_get_state_str(new_state), new_state); |
Andri Yngvason | bac78aa | 2014-12-03 17:54:13 +0000 | [diff] [blame] | 114 | |
| 115 | can_update_state_error_stats(dev, new_state); |
| 116 | priv->state = new_state; |
| 117 | |
Marc Kleine-Budde | ff3416f | 2017-05-18 10:22:22 +0200 | [diff] [blame] | 118 | if (!cf) |
| 119 | return; |
| 120 | |
Andri Yngvason | bac78aa | 2014-12-03 17:54:13 +0000 | [diff] [blame] | 121 | if (unlikely(new_state == CAN_STATE_BUS_OFF)) { |
| 122 | cf->can_id |= CAN_ERR_BUSOFF; |
| 123 | return; |
| 124 | } |
| 125 | |
| 126 | cf->can_id |= CAN_ERR_CRTL; |
| 127 | cf->data[1] |= tx_state >= rx_state ? |
| 128 | can_tx_state_to_frame(dev, tx_state) : 0; |
| 129 | cf->data[1] |= tx_state <= rx_state ? |
| 130 | can_rx_state_to_frame(dev, rx_state) : 0; |
| 131 | } |
| 132 | EXPORT_SYMBOL_GPL(can_change_state); |
| 133 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 134 | /* CAN device restart for bus-off recovery */ |
Sergei Miroshnichenko | 9abefcb | 2016-09-07 16:51:12 +0300 | [diff] [blame] | 135 | static void can_restart(struct net_device *dev) |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 136 | { |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 137 | struct can_priv *priv = netdev_priv(dev); |
| 138 | struct net_device_stats *stats = &dev->stats; |
| 139 | struct sk_buff *skb; |
| 140 | struct can_frame *cf; |
| 141 | int err; |
| 142 | |
| 143 | BUG_ON(netif_carrier_ok(dev)); |
| 144 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 145 | /* No synchronization needed because the device is bus-off and |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 146 | * no messages can come in or go out. |
| 147 | */ |
| 148 | can_flush_echo_skb(dev); |
| 149 | |
| 150 | /* send restart message upstream */ |
Wolfgang Grandegger | 7b6856a0 | 2009-10-20 00:08:01 -0700 | [diff] [blame] | 151 | skb = alloc_can_err_skb(dev, &cf); |
Gustavo A. R. Silva | 371fd7b | 2017-10-20 22:36:52 -0500 | [diff] [blame] | 152 | if (!skb) |
Wolfgang Grandegger | b3d0df7 | 2009-07-20 04:06:40 +0000 | [diff] [blame] | 153 | goto restart; |
Gustavo A. R. Silva | 371fd7b | 2017-10-20 22:36:52 -0500 | [diff] [blame] | 154 | |
Wolfgang Grandegger | 7b6856a0 | 2009-10-20 00:08:01 -0700 | [diff] [blame] | 155 | cf->can_id |= CAN_ERR_RESTARTED; |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 156 | |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 157 | stats->rx_packets++; |
Oliver Hartkopp | c7b7496 | 2020-11-20 11:04:44 +0100 | [diff] [blame] | 158 | stats->rx_bytes += cf->len; |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 159 | |
Jakub Kicinski | 0fe2f27 | 2021-01-20 12:16:11 -0800 | [diff] [blame] | 160 | netif_rx_ni(skb); |
| 161 | |
Wolfgang Grandegger | b3d0df7 | 2009-07-20 04:06:40 +0000 | [diff] [blame] | 162 | restart: |
Wolfgang Grandegger | aabdfd6 | 2012-02-01 11:02:05 +0100 | [diff] [blame] | 163 | netdev_dbg(dev, "restarted\n"); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 164 | priv->can_stats.restarts++; |
| 165 | |
| 166 | /* Now restart the device */ |
| 167 | err = priv->do_set_mode(dev, CAN_MODE_START); |
| 168 | |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 169 | netif_carrier_on(dev); |
| 170 | if (err) |
Wolfgang Grandegger | aabdfd6 | 2012-02-01 11:02:05 +0100 | [diff] [blame] | 171 | netdev_err(dev, "Error %d during restart", err); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 172 | } |
| 173 | |
Sergei Miroshnichenko | 9abefcb | 2016-09-07 16:51:12 +0300 | [diff] [blame] | 174 | static void can_restart_work(struct work_struct *work) |
| 175 | { |
| 176 | struct delayed_work *dwork = to_delayed_work(work); |
Marc Kleine-Budde | d7bda73 | 2019-08-27 13:53:18 +0200 | [diff] [blame] | 177 | struct can_priv *priv = container_of(dwork, struct can_priv, |
| 178 | restart_work); |
Sergei Miroshnichenko | 9abefcb | 2016-09-07 16:51:12 +0300 | [diff] [blame] | 179 | |
| 180 | can_restart(priv->dev); |
| 181 | } |
| 182 | |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 183 | int can_restart_now(struct net_device *dev) |
| 184 | { |
| 185 | struct can_priv *priv = netdev_priv(dev); |
| 186 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 187 | /* A manual restart is only permitted if automatic restart is |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 188 | * disabled and the device is in the bus-off state |
| 189 | */ |
| 190 | if (priv->restart_ms) |
| 191 | return -EINVAL; |
| 192 | if (priv->state != CAN_STATE_BUS_OFF) |
| 193 | return -EBUSY; |
| 194 | |
Sergei Miroshnichenko | 9abefcb | 2016-09-07 16:51:12 +0300 | [diff] [blame] | 195 | cancel_delayed_work_sync(&priv->restart_work); |
| 196 | can_restart(dev); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 197 | |
| 198 | return 0; |
| 199 | } |
| 200 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 201 | /* CAN bus-off |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 202 | * |
| 203 | * This functions should be called when the device goes bus-off to |
| 204 | * tell the netif layer that no more packets can be sent or received. |
| 205 | * If enabled, a timer is started to trigger bus-off recovery. |
| 206 | */ |
| 207 | void can_bus_off(struct net_device *dev) |
| 208 | { |
| 209 | struct can_priv *priv = netdev_priv(dev); |
| 210 | |
Marc Kleine-Budde | 0719631 | 2020-09-16 00:35:03 +0200 | [diff] [blame] | 211 | if (priv->restart_ms) |
| 212 | netdev_info(dev, "bus-off, scheduling restart in %d ms\n", |
| 213 | priv->restart_ms); |
| 214 | else |
| 215 | netdev_info(dev, "bus-off\n"); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 216 | |
| 217 | netif_carrier_off(dev); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 218 | |
| 219 | if (priv->restart_ms) |
Sergei Miroshnichenko | 9abefcb | 2016-09-07 16:51:12 +0300 | [diff] [blame] | 220 | schedule_delayed_work(&priv->restart_work, |
| 221 | msecs_to_jiffies(priv->restart_ms)); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 222 | } |
| 223 | EXPORT_SYMBOL_GPL(can_bus_off); |
| 224 | |
Marc Kleine-Budde | 0a042c6 | 2021-01-11 15:19:21 +0100 | [diff] [blame] | 225 | void can_setup(struct net_device *dev) |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 226 | { |
| 227 | dev->type = ARPHRD_CAN; |
Oliver Hartkopp | 1e0625f | 2012-06-13 20:48:21 +0200 | [diff] [blame] | 228 | dev->mtu = CAN_MTU; |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 229 | dev->hard_header_len = 0; |
| 230 | dev->addr_len = 0; |
| 231 | dev->tx_queue_len = 10; |
| 232 | |
| 233 | /* New-style flags. */ |
| 234 | dev->flags = IFF_NOARP; |
Michał Mirosław | 34324dc | 2011-11-15 15:29:55 +0000 | [diff] [blame] | 235 | dev->features = NETIF_F_HW_CSUM; |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 236 | } |
| 237 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 238 | /* Allocate and setup space for the CAN network device */ |
Zhu Yi | 0387090 | 2018-06-13 16:37:17 +0200 | [diff] [blame] | 239 | struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max, |
| 240 | unsigned int txqs, unsigned int rxqs) |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 241 | { |
Oleksij Rempel | 4e096a1 | 2021-02-23 08:01:26 +0100 | [diff] [blame] | 242 | struct can_ml_priv *can_ml; |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 243 | struct net_device *dev; |
| 244 | struct can_priv *priv; |
Wolfgang Grandegger | a6e4bc5 | 2009-10-08 22:17:11 +0000 | [diff] [blame] | 245 | int size; |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 246 | |
Marc Kleine-Budde | ffd956e | 2018-10-08 09:02:38 +0200 | [diff] [blame] | 247 | /* We put the driver's priv, the CAN mid layer priv and the |
| 248 | * echo skb into the netdevice's priv. The memory layout for |
| 249 | * the netdev_priv is like this: |
| 250 | * |
| 251 | * +-------------------------+ |
| 252 | * | driver's priv | |
| 253 | * +-------------------------+ |
| 254 | * | struct can_ml_priv | |
| 255 | * +-------------------------+ |
| 256 | * | array of struct sk_buff | |
| 257 | * +-------------------------+ |
| 258 | */ |
| 259 | |
| 260 | size = ALIGN(sizeof_priv, NETDEV_ALIGN) + sizeof(struct can_ml_priv); |
| 261 | |
Wolfgang Grandegger | a6e4bc5 | 2009-10-08 22:17:11 +0000 | [diff] [blame] | 262 | if (echo_skb_max) |
Marc Kleine-Budde | ffd956e | 2018-10-08 09:02:38 +0200 | [diff] [blame] | 263 | size = ALIGN(size, sizeof(struct sk_buff *)) + |
Wolfgang Grandegger | a6e4bc5 | 2009-10-08 22:17:11 +0000 | [diff] [blame] | 264 | echo_skb_max * sizeof(struct sk_buff *); |
Wolfgang Grandegger | a6e4bc5 | 2009-10-08 22:17:11 +0000 | [diff] [blame] | 265 | |
Zhu Yi | 0387090 | 2018-06-13 16:37:17 +0200 | [diff] [blame] | 266 | dev = alloc_netdev_mqs(size, "can%d", NET_NAME_UNKNOWN, can_setup, |
| 267 | txqs, rxqs); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 268 | if (!dev) |
| 269 | return NULL; |
| 270 | |
| 271 | priv = netdev_priv(dev); |
Sergei Miroshnichenko | 9abefcb | 2016-09-07 16:51:12 +0300 | [diff] [blame] | 272 | priv->dev = dev; |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 273 | |
Oleksij Rempel | 4e096a1 | 2021-02-23 08:01:26 +0100 | [diff] [blame] | 274 | can_ml = (void *)priv + ALIGN(sizeof_priv, NETDEV_ALIGN); |
| 275 | can_set_ml_priv(dev, can_ml); |
Marc Kleine-Budde | 8df9ffb | 2018-10-08 09:02:39 +0200 | [diff] [blame] | 276 | |
Wolfgang Grandegger | a6e4bc5 | 2009-10-08 22:17:11 +0000 | [diff] [blame] | 277 | if (echo_skb_max) { |
| 278 | priv->echo_skb_max = echo_skb_max; |
| 279 | priv->echo_skb = (void *)priv + |
Marc Kleine-Budde | ffd956e | 2018-10-08 09:02:38 +0200 | [diff] [blame] | 280 | (size - echo_skb_max * sizeof(struct sk_buff *)); |
Wolfgang Grandegger | a6e4bc5 | 2009-10-08 22:17:11 +0000 | [diff] [blame] | 281 | } |
| 282 | |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 283 | priv->state = CAN_STATE_STOPPED; |
| 284 | |
Sergei Miroshnichenko | 9abefcb | 2016-09-07 16:51:12 +0300 | [diff] [blame] | 285 | INIT_DELAYED_WORK(&priv->restart_work, can_restart_work); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 286 | |
| 287 | return dev; |
| 288 | } |
Zhu Yi | 0387090 | 2018-06-13 16:37:17 +0200 | [diff] [blame] | 289 | EXPORT_SYMBOL_GPL(alloc_candev_mqs); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 290 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 291 | /* Free space of the CAN network device */ |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 292 | void free_candev(struct net_device *dev) |
| 293 | { |
| 294 | free_netdev(dev); |
| 295 | } |
| 296 | EXPORT_SYMBOL_GPL(free_candev); |
| 297 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 298 | /* changing MTU and control mode for CAN/CANFD devices */ |
Oliver Hartkopp | bc05a89 | 2014-02-28 16:36:24 +0100 | [diff] [blame] | 299 | int can_change_mtu(struct net_device *dev, int new_mtu) |
| 300 | { |
| 301 | struct can_priv *priv = netdev_priv(dev); |
| 302 | |
| 303 | /* Do not allow changing the MTU while running */ |
| 304 | if (dev->flags & IFF_UP) |
| 305 | return -EBUSY; |
| 306 | |
| 307 | /* allow change of MTU according to the CANFD ability of the device */ |
| 308 | switch (new_mtu) { |
| 309 | case CAN_MTU: |
Oliver Hartkopp | bb208f1 | 2016-03-21 20:18:21 +0100 | [diff] [blame] | 310 | /* 'CANFD-only' controllers can not switch to CAN_MTU */ |
| 311 | if (priv->ctrlmode_static & CAN_CTRLMODE_FD) |
| 312 | return -EINVAL; |
| 313 | |
Oliver Hartkopp | bc05a89 | 2014-02-28 16:36:24 +0100 | [diff] [blame] | 314 | priv->ctrlmode &= ~CAN_CTRLMODE_FD; |
| 315 | break; |
| 316 | |
| 317 | case CANFD_MTU: |
Oliver Hartkopp | bb208f1 | 2016-03-21 20:18:21 +0100 | [diff] [blame] | 318 | /* check for potential CANFD ability */ |
| 319 | if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD) && |
| 320 | !(priv->ctrlmode_static & CAN_CTRLMODE_FD)) |
Oliver Hartkopp | bc05a89 | 2014-02-28 16:36:24 +0100 | [diff] [blame] | 321 | return -EINVAL; |
| 322 | |
| 323 | priv->ctrlmode |= CAN_CTRLMODE_FD; |
| 324 | break; |
| 325 | |
| 326 | default: |
| 327 | return -EINVAL; |
| 328 | } |
| 329 | |
| 330 | dev->mtu = new_mtu; |
| 331 | return 0; |
| 332 | } |
| 333 | EXPORT_SYMBOL_GPL(can_change_mtu); |
| 334 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 335 | /* Common open function when the device gets opened. |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 336 | * |
| 337 | * This function should be called in the open function of the device |
| 338 | * driver. |
| 339 | */ |
| 340 | int open_candev(struct net_device *dev) |
| 341 | { |
| 342 | struct can_priv *priv = netdev_priv(dev); |
| 343 | |
Oliver Hartkopp | b30749f | 2014-02-28 16:36:20 +0100 | [diff] [blame] | 344 | if (!priv->bittiming.bitrate) { |
Wolfgang Grandegger | aabdfd6 | 2012-02-01 11:02:05 +0100 | [diff] [blame] | 345 | netdev_err(dev, "bit-timing not yet defined\n"); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 346 | return -EINVAL; |
| 347 | } |
| 348 | |
Oliver Hartkopp | dd22586 | 2014-02-28 16:36:25 +0100 | [diff] [blame] | 349 | /* For CAN FD the data bitrate has to be >= the arbitration bitrate */ |
| 350 | if ((priv->ctrlmode & CAN_CTRLMODE_FD) && |
| 351 | (!priv->data_bittiming.bitrate || |
Marc Kleine-Budde | 39fe6fd | 2019-08-27 14:04:12 +0200 | [diff] [blame] | 352 | priv->data_bittiming.bitrate < priv->bittiming.bitrate)) { |
Oliver Hartkopp | dd22586 | 2014-02-28 16:36:25 +0100 | [diff] [blame] | 353 | netdev_err(dev, "incorrect/missing data bit-timing\n"); |
| 354 | return -EINVAL; |
| 355 | } |
| 356 | |
Wolfgang Grandegger | 1b0d922 | 2009-07-20 04:06:41 +0000 | [diff] [blame] | 357 | /* Switch carrier on if device was stopped while in bus-off state */ |
| 358 | if (!netif_carrier_ok(dev)) |
| 359 | netif_carrier_on(dev); |
| 360 | |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 361 | return 0; |
| 362 | } |
Wolfgang Grandegger | 128ced8 | 2009-05-30 07:55:48 +0000 | [diff] [blame] | 363 | EXPORT_SYMBOL_GPL(open_candev); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 364 | |
Franklin S Cooper Jr | 2290aef | 2018-01-10 16:25:18 +0530 | [diff] [blame] | 365 | #ifdef CONFIG_OF |
| 366 | /* Common function that can be used to understand the limitation of |
| 367 | * a transceiver when it provides no means to determine these limitations |
| 368 | * at runtime. |
| 369 | */ |
| 370 | void of_can_transceiver(struct net_device *dev) |
| 371 | { |
| 372 | struct device_node *dn; |
| 373 | struct can_priv *priv = netdev_priv(dev); |
| 374 | struct device_node *np = dev->dev.parent->of_node; |
| 375 | int ret; |
| 376 | |
| 377 | dn = of_get_child_by_name(np, "can-transceiver"); |
| 378 | if (!dn) |
| 379 | return; |
| 380 | |
| 381 | ret = of_property_read_u32(dn, "max-bitrate", &priv->bitrate_max); |
Wen Yang | db9ee38 | 2019-09-28 22:29:05 +0800 | [diff] [blame] | 382 | of_node_put(dn); |
Franklin S Cooper Jr | 2290aef | 2018-01-10 16:25:18 +0530 | [diff] [blame] | 383 | if ((ret && ret != -EINVAL) || (!ret && !priv->bitrate_max)) |
| 384 | netdev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit.\n"); |
| 385 | } |
| 386 | EXPORT_SYMBOL_GPL(of_can_transceiver); |
| 387 | #endif |
| 388 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 389 | /* Common close function for cleanup before the device gets closed. |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 390 | * |
| 391 | * This function should be called in the close function of the device |
| 392 | * driver. |
| 393 | */ |
| 394 | void close_candev(struct net_device *dev) |
| 395 | { |
| 396 | struct can_priv *priv = netdev_priv(dev); |
| 397 | |
Sergei Miroshnichenko | 9abefcb | 2016-09-07 16:51:12 +0300 | [diff] [blame] | 398 | cancel_delayed_work_sync(&priv->restart_work); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 399 | can_flush_echo_skb(dev); |
| 400 | } |
| 401 | EXPORT_SYMBOL_GPL(close_candev); |
| 402 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 403 | /* Register the CAN network device */ |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 404 | int register_candev(struct net_device *dev) |
| 405 | { |
Oliver Hartkopp | 12a6075 | 2017-01-10 18:52:06 +0100 | [diff] [blame] | 406 | struct can_priv *priv = netdev_priv(dev); |
| 407 | |
| 408 | /* Ensure termination_const, termination_const_cnt and |
| 409 | * do_set_termination consistency. All must be either set or |
| 410 | * unset. |
| 411 | */ |
| 412 | if ((!priv->termination_const != !priv->termination_const_cnt) || |
| 413 | (!priv->termination_const != !priv->do_set_termination)) |
| 414 | return -EINVAL; |
| 415 | |
Marc Kleine-Budde | 431af77 | 2017-01-11 17:05:35 +0100 | [diff] [blame] | 416 | if (!priv->bitrate_const != !priv->bitrate_const_cnt) |
| 417 | return -EINVAL; |
| 418 | |
| 419 | if (!priv->data_bitrate_const != !priv->data_bitrate_const_cnt) |
| 420 | return -EINVAL; |
| 421 | |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 422 | dev->rtnl_link_ops = &can_link_ops; |
Rasmus Villemoes | c638456 | 2019-06-24 08:34:13 +0000 | [diff] [blame] | 423 | netif_carrier_off(dev); |
| 424 | |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 425 | return register_netdev(dev); |
| 426 | } |
| 427 | EXPORT_SYMBOL_GPL(register_candev); |
| 428 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 429 | /* Unregister the CAN network device */ |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 430 | void unregister_candev(struct net_device *dev) |
| 431 | { |
| 432 | unregister_netdev(dev); |
| 433 | } |
| 434 | EXPORT_SYMBOL_GPL(unregister_candev); |
| 435 | |
Marc Kleine-Budde | ee9a5f5 | 2019-08-27 13:46:41 +0200 | [diff] [blame] | 436 | /* Test if a network device is a candev based device |
Kurt Van Dijck | bf03a53 | 2012-12-18 18:50:56 +0100 | [diff] [blame] | 437 | * and return the can_priv* if so. |
| 438 | */ |
| 439 | struct can_priv *safe_candev_priv(struct net_device *dev) |
| 440 | { |
Marc Kleine-Budde | 39fe6fd | 2019-08-27 14:04:12 +0200 | [diff] [blame] | 441 | if (dev->type != ARPHRD_CAN || dev->rtnl_link_ops != &can_link_ops) |
Kurt Van Dijck | bf03a53 | 2012-12-18 18:50:56 +0100 | [diff] [blame] | 442 | return NULL; |
| 443 | |
| 444 | return netdev_priv(dev); |
| 445 | } |
| 446 | EXPORT_SYMBOL_GPL(safe_candev_priv); |
| 447 | |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 448 | static __init int can_dev_init(void) |
| 449 | { |
| 450 | int err; |
| 451 | |
Kurt Van Dijck | a1ef7bd | 2012-12-18 18:50:57 +0100 | [diff] [blame] | 452 | can_led_notifier_init(); |
| 453 | |
Marc Kleine-Budde | 0a042c6 | 2021-01-11 15:19:21 +0100 | [diff] [blame] | 454 | err = can_netlink_register(); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 455 | if (!err) |
Marc Kleine-Budde | 13ecee7 | 2019-07-26 09:35:43 +0200 | [diff] [blame] | 456 | pr_info(MOD_DESC "\n"); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 457 | |
| 458 | return err; |
| 459 | } |
| 460 | module_init(can_dev_init); |
| 461 | |
| 462 | static __exit void can_dev_exit(void) |
| 463 | { |
Marc Kleine-Budde | 0a042c6 | 2021-01-11 15:19:21 +0100 | [diff] [blame] | 464 | can_netlink_unregister(); |
Kurt Van Dijck | a1ef7bd | 2012-12-18 18:50:57 +0100 | [diff] [blame] | 465 | |
| 466 | can_led_notifier_exit(); |
Wolfgang Grandegger | 39549ee | 2009-05-15 23:39:29 +0000 | [diff] [blame] | 467 | } |
| 468 | module_exit(can_dev_exit); |
| 469 | |
| 470 | MODULE_ALIAS_RTNL_LINK("can"); |