1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Core driver for the CC770 and AN82527 CAN controllers |
4 | * |
5 | * Copyright (C) 2009, 2011 Wolfgang Grandegger <wg@grandegger.com> |
6 | */ |
7 | |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/init.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/sched.h> |
14 | #include <linux/types.h> |
15 | #include <linux/fcntl.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/ptrace.h> |
18 | #include <linux/string.h> |
19 | #include <linux/errno.h> |
20 | #include <linux/ethtool.h> |
21 | #include <linux/netdevice.h> |
22 | #include <linux/if_arp.h> |
23 | #include <linux/if_ether.h> |
24 | #include <linux/skbuff.h> |
25 | #include <linux/delay.h> |
26 | |
27 | #include <linux/can.h> |
28 | #include <linux/can/dev.h> |
29 | #include <linux/can/error.h> |
30 | #include <linux/can/platform/cc770.h> |
31 | |
32 | #include "cc770.h" |
33 | |
34 | MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>" ); |
35 | MODULE_LICENSE("GPL v2" ); |
36 | MODULE_DESCRIPTION(KBUILD_MODNAME "CAN netdevice driver" ); |
37 | |
38 | /* |
39 | * The CC770 is a CAN controller from Bosch, which is 100% compatible |
40 | * with the AN82527 from Intel, but with "bugs" being fixed and some |
41 | * additional functionality, mainly: |
42 | * |
43 | * 1. RX and TX error counters are readable. |
44 | * 2. Support of silent (listen-only) mode. |
45 | * 3. Message object 15 can receive all types of frames, also RTR and EFF. |
46 | * |
47 | * Details are available from Bosch's "CC770_Product_Info_2007-01.pdf", |
48 | * which explains in detail the compatibility between the CC770 and the |
49 | * 82527. This driver use the additional functionality 3. on real CC770 |
50 | * devices. Unfortunately, the CC770 does still not store the message |
51 | * identifier of received remote transmission request frames and |
52 | * therefore it's set to 0. |
53 | * |
54 | * The message objects 1..14 can be used for TX and RX while the message |
55 | * objects 15 is optimized for RX. It has a shadow register for reliable |
56 | * data reception under heavy bus load. Therefore it makes sense to use |
57 | * this message object for the needed use case. The frame type (EFF/SFF) |
58 | * for the message object 15 can be defined via kernel module parameter |
59 | * "msgobj15_eff". If not equal 0, it will receive 29-bit EFF frames, |
60 | * otherwise 11 bit SFF messages. |
61 | */ |
62 | static int msgobj15_eff; |
63 | module_param(msgobj15_eff, int, 0444); |
64 | MODULE_PARM_DESC(msgobj15_eff, "Extended 29-bit frames for message object 15 " |
65 | "(default: 11-bit standard frames)" ); |
66 | |
67 | static int i82527_compat; |
68 | module_param(i82527_compat, int, 0444); |
69 | MODULE_PARM_DESC(i82527_compat, "Strict Intel 82527 compatibility mode " |
70 | "without using additional functions" ); |
71 | |
72 | /* |
73 | * This driver uses the last 5 message objects 11..15. The definitions |
74 | * and structure below allows to configure and assign them to the real |
75 | * message object. |
76 | */ |
77 | static unsigned char cc770_obj_flags[CC770_OBJ_MAX] = { |
78 | [CC770_OBJ_RX0] = CC770_OBJ_FLAG_RX, |
79 | [CC770_OBJ_RX1] = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_EFF, |
80 | [CC770_OBJ_RX_RTR0] = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_RTR, |
81 | [CC770_OBJ_RX_RTR1] = CC770_OBJ_FLAG_RX | CC770_OBJ_FLAG_RTR | |
82 | CC770_OBJ_FLAG_EFF, |
83 | [CC770_OBJ_TX] = 0, |
84 | }; |
85 | |
86 | static const struct can_bittiming_const cc770_bittiming_const = { |
87 | .name = KBUILD_MODNAME, |
88 | .tseg1_min = 1, |
89 | .tseg1_max = 16, |
90 | .tseg2_min = 1, |
91 | .tseg2_max = 8, |
92 | .sjw_max = 4, |
93 | .brp_min = 1, |
94 | .brp_max = 64, |
95 | .brp_inc = 1, |
96 | }; |
97 | |
98 | static inline int intid2obj(unsigned int intid) |
99 | { |
100 | if (intid == 2) |
101 | return 0; |
102 | else |
103 | return MSGOBJ_LAST + 2 - intid; |
104 | } |
105 | |
106 | static void enable_all_objs(const struct net_device *dev) |
107 | { |
108 | struct cc770_priv *priv = netdev_priv(dev); |
109 | u8 msgcfg; |
110 | unsigned char obj_flags; |
111 | unsigned int o, mo; |
112 | |
113 | for (o = 0; o < ARRAY_SIZE(priv->obj_flags); o++) { |
114 | obj_flags = priv->obj_flags[o]; |
115 | mo = obj2msgobj(o); |
116 | |
117 | if (obj_flags & CC770_OBJ_FLAG_RX) { |
118 | /* |
119 | * We don't need extra objects for RTR and EFF if |
120 | * the additional CC770 functions are enabled. |
121 | */ |
122 | if (priv->control_normal_mode & CTRL_EAF) { |
123 | if (o > 0) |
124 | continue; |
125 | netdev_dbg(dev, "Message object %d for " |
126 | "RX data, RTR, SFF and EFF\n" , mo); |
127 | } else { |
128 | netdev_dbg(dev, |
129 | "Message object %d for RX %s %s\n" , |
130 | mo, obj_flags & CC770_OBJ_FLAG_RTR ? |
131 | "RTR" : "data" , |
132 | obj_flags & CC770_OBJ_FLAG_EFF ? |
133 | "EFF" : "SFF" ); |
134 | } |
135 | |
136 | if (obj_flags & CC770_OBJ_FLAG_EFF) |
137 | msgcfg = MSGCFG_XTD; |
138 | else |
139 | msgcfg = 0; |
140 | if (obj_flags & CC770_OBJ_FLAG_RTR) |
141 | msgcfg |= MSGCFG_DIR; |
142 | |
143 | cc770_write_reg(priv, msgobj[mo].config, msgcfg); |
144 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
145 | MSGVAL_SET | TXIE_RES | |
146 | RXIE_SET | INTPND_RES); |
147 | |
148 | if (obj_flags & CC770_OBJ_FLAG_RTR) |
149 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
150 | NEWDAT_RES | CPUUPD_SET | |
151 | TXRQST_RES | RMTPND_RES); |
152 | else |
153 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
154 | NEWDAT_RES | MSGLST_RES | |
155 | TXRQST_RES | RMTPND_RES); |
156 | } else { |
157 | netdev_dbg(dev, "Message object %d for " |
158 | "TX data, RTR, SFF and EFF\n" , mo); |
159 | |
160 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
161 | RMTPND_RES | TXRQST_RES | |
162 | CPUUPD_RES | NEWDAT_RES); |
163 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
164 | MSGVAL_RES | TXIE_RES | |
165 | RXIE_RES | INTPND_RES); |
166 | } |
167 | } |
168 | } |
169 | |
170 | static void disable_all_objs(const struct cc770_priv *priv) |
171 | { |
172 | int o, mo; |
173 | |
174 | for (o = 0; o < ARRAY_SIZE(priv->obj_flags); o++) { |
175 | mo = obj2msgobj(o); |
176 | |
177 | if (priv->obj_flags[o] & CC770_OBJ_FLAG_RX) { |
178 | if (o > 0 && priv->control_normal_mode & CTRL_EAF) |
179 | continue; |
180 | |
181 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
182 | NEWDAT_RES | MSGLST_RES | |
183 | TXRQST_RES | RMTPND_RES); |
184 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
185 | MSGVAL_RES | TXIE_RES | |
186 | RXIE_RES | INTPND_RES); |
187 | } else { |
188 | /* Clear message object for send */ |
189 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
190 | RMTPND_RES | TXRQST_RES | |
191 | CPUUPD_RES | NEWDAT_RES); |
192 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
193 | MSGVAL_RES | TXIE_RES | |
194 | RXIE_RES | INTPND_RES); |
195 | } |
196 | } |
197 | } |
198 | |
199 | static void set_reset_mode(struct net_device *dev) |
200 | { |
201 | struct cc770_priv *priv = netdev_priv(dev); |
202 | |
203 | /* Enable configuration and puts chip in bus-off, disable interrupts */ |
204 | cc770_write_reg(priv, control, CTRL_CCE | CTRL_INI); |
205 | |
206 | priv->can.state = CAN_STATE_STOPPED; |
207 | |
208 | /* Clear interrupts */ |
209 | cc770_read_reg(priv, interrupt); |
210 | |
211 | /* Clear status register */ |
212 | cc770_write_reg(priv, status, 0); |
213 | |
214 | /* Disable all used message objects */ |
215 | disable_all_objs(priv); |
216 | } |
217 | |
218 | static void set_normal_mode(struct net_device *dev) |
219 | { |
220 | struct cc770_priv *priv = netdev_priv(dev); |
221 | |
222 | /* Clear interrupts */ |
223 | cc770_read_reg(priv, interrupt); |
224 | |
225 | /* Clear status register and pre-set last error code */ |
226 | cc770_write_reg(priv, status, STAT_LEC_MASK); |
227 | |
228 | /* Enable all used message objects*/ |
229 | enable_all_objs(dev); |
230 | |
231 | /* |
232 | * Clear bus-off, interrupts only for errors, |
233 | * not for status change |
234 | */ |
235 | cc770_write_reg(priv, control, priv->control_normal_mode); |
236 | |
237 | priv->can.state = CAN_STATE_ERROR_ACTIVE; |
238 | } |
239 | |
240 | static void chipset_init(struct cc770_priv *priv) |
241 | { |
242 | int mo, id, data; |
243 | |
244 | /* Enable configuration and put chip in bus-off, disable interrupts */ |
245 | cc770_write_reg(priv, control, (CTRL_CCE | CTRL_INI)); |
246 | |
247 | /* Set CLKOUT divider and slew rates */ |
248 | cc770_write_reg(priv, clkout, priv->clkout); |
249 | |
250 | /* Configure CPU interface / CLKOUT enable */ |
251 | cc770_write_reg(priv, cpu_interface, priv->cpu_interface); |
252 | |
253 | /* Set bus configuration */ |
254 | cc770_write_reg(priv, bus_config, priv->bus_config); |
255 | |
256 | /* Clear interrupts */ |
257 | cc770_read_reg(priv, interrupt); |
258 | |
259 | /* Clear status register */ |
260 | cc770_write_reg(priv, status, 0); |
261 | |
262 | /* Clear and invalidate message objects */ |
263 | for (mo = MSGOBJ_FIRST; mo <= MSGOBJ_LAST; mo++) { |
264 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
265 | INTPND_UNC | RXIE_RES | |
266 | TXIE_RES | MSGVAL_RES); |
267 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
268 | INTPND_RES | RXIE_RES | |
269 | TXIE_RES | MSGVAL_RES); |
270 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
271 | NEWDAT_RES | MSGLST_RES | |
272 | TXRQST_RES | RMTPND_RES); |
273 | for (data = 0; data < 8; data++) |
274 | cc770_write_reg(priv, msgobj[mo].data[data], 0); |
275 | for (id = 0; id < 4; id++) |
276 | cc770_write_reg(priv, msgobj[mo].id[id], 0); |
277 | cc770_write_reg(priv, msgobj[mo].config, 0); |
278 | } |
279 | |
280 | /* Set all global ID masks to "don't care" */ |
281 | cc770_write_reg(priv, global_mask_std[0], 0); |
282 | cc770_write_reg(priv, global_mask_std[1], 0); |
283 | cc770_write_reg(priv, global_mask_ext[0], 0); |
284 | cc770_write_reg(priv, global_mask_ext[1], 0); |
285 | cc770_write_reg(priv, global_mask_ext[2], 0); |
286 | cc770_write_reg(priv, global_mask_ext[3], 0); |
287 | |
288 | } |
289 | |
290 | static int cc770_probe_chip(struct net_device *dev) |
291 | { |
292 | struct cc770_priv *priv = netdev_priv(dev); |
293 | |
294 | /* Enable configuration, put chip in bus-off, disable ints */ |
295 | cc770_write_reg(priv, control, CTRL_CCE | CTRL_EAF | CTRL_INI); |
296 | /* Configure cpu interface / CLKOUT disable */ |
297 | cc770_write_reg(priv, cpu_interface, priv->cpu_interface); |
298 | |
299 | /* |
300 | * Check if hardware reset is still inactive or maybe there |
301 | * is no chip in this address space |
302 | */ |
303 | if (cc770_read_reg(priv, cpu_interface) & CPUIF_RST) { |
304 | netdev_info(dev, format: "probing @0x%p failed (reset)\n" , |
305 | priv->reg_base); |
306 | return -ENODEV; |
307 | } |
308 | |
309 | /* Write and read back test pattern (some arbitrary values) */ |
310 | cc770_write_reg(priv, msgobj[1].data[1], 0x25); |
311 | cc770_write_reg(priv, msgobj[2].data[3], 0x52); |
312 | cc770_write_reg(priv, msgobj[10].data[6], 0xc3); |
313 | if ((cc770_read_reg(priv, msgobj[1].data[1]) != 0x25) || |
314 | (cc770_read_reg(priv, msgobj[2].data[3]) != 0x52) || |
315 | (cc770_read_reg(priv, msgobj[10].data[6]) != 0xc3)) { |
316 | netdev_info(dev, format: "probing @0x%p failed (pattern)\n" , |
317 | priv->reg_base); |
318 | return -ENODEV; |
319 | } |
320 | |
321 | /* Check if this chip is a CC770 supporting additional functions */ |
322 | if (cc770_read_reg(priv, control) & CTRL_EAF) |
323 | priv->control_normal_mode |= CTRL_EAF; |
324 | |
325 | return 0; |
326 | } |
327 | |
328 | static void cc770_start(struct net_device *dev) |
329 | { |
330 | struct cc770_priv *priv = netdev_priv(dev); |
331 | |
332 | /* leave reset mode */ |
333 | if (priv->can.state != CAN_STATE_STOPPED) |
334 | set_reset_mode(dev); |
335 | |
336 | /* leave reset mode */ |
337 | set_normal_mode(dev); |
338 | } |
339 | |
340 | static int cc770_set_mode(struct net_device *dev, enum can_mode mode) |
341 | { |
342 | switch (mode) { |
343 | case CAN_MODE_START: |
344 | cc770_start(dev); |
345 | netif_wake_queue(dev); |
346 | break; |
347 | |
348 | default: |
349 | return -EOPNOTSUPP; |
350 | } |
351 | |
352 | return 0; |
353 | } |
354 | |
355 | static int cc770_set_bittiming(struct net_device *dev) |
356 | { |
357 | struct cc770_priv *priv = netdev_priv(dev); |
358 | struct can_bittiming *bt = &priv->can.bittiming; |
359 | u8 btr0, btr1; |
360 | |
361 | btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6); |
362 | btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) | |
363 | (((bt->phase_seg2 - 1) & 0x7) << 4); |
364 | if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) |
365 | btr1 |= 0x80; |
366 | |
367 | netdev_info(dev, format: "setting BTR0=0x%02x BTR1=0x%02x\n" , btr0, btr1); |
368 | |
369 | cc770_write_reg(priv, bit_timing_0, btr0); |
370 | cc770_write_reg(priv, bit_timing_1, btr1); |
371 | |
372 | return 0; |
373 | } |
374 | |
375 | static int cc770_get_berr_counter(const struct net_device *dev, |
376 | struct can_berr_counter *bec) |
377 | { |
378 | struct cc770_priv *priv = netdev_priv(dev); |
379 | |
380 | bec->txerr = cc770_read_reg(priv, tx_error_counter); |
381 | bec->rxerr = cc770_read_reg(priv, rx_error_counter); |
382 | |
383 | return 0; |
384 | } |
385 | |
386 | static void cc770_tx(struct net_device *dev, int mo) |
387 | { |
388 | struct cc770_priv *priv = netdev_priv(dev); |
389 | struct can_frame *cf = (struct can_frame *)priv->tx_skb->data; |
390 | u8 dlc, rtr; |
391 | u32 id; |
392 | int i; |
393 | |
394 | dlc = cf->len; |
395 | id = cf->can_id; |
396 | rtr = cf->can_id & CAN_RTR_FLAG ? 0 : MSGCFG_DIR; |
397 | |
398 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
399 | MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); |
400 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
401 | RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES); |
402 | |
403 | if (id & CAN_EFF_FLAG) { |
404 | id &= CAN_EFF_MASK; |
405 | cc770_write_reg(priv, msgobj[mo].config, |
406 | (dlc << 4) | rtr | MSGCFG_XTD); |
407 | cc770_write_reg(priv, msgobj[mo].id[3], id << 3); |
408 | cc770_write_reg(priv, msgobj[mo].id[2], id >> 5); |
409 | cc770_write_reg(priv, msgobj[mo].id[1], id >> 13); |
410 | cc770_write_reg(priv, msgobj[mo].id[0], id >> 21); |
411 | } else { |
412 | id &= CAN_SFF_MASK; |
413 | cc770_write_reg(priv, msgobj[mo].config, (dlc << 4) | rtr); |
414 | cc770_write_reg(priv, msgobj[mo].id[0], id >> 3); |
415 | cc770_write_reg(priv, msgobj[mo].id[1], id << 5); |
416 | } |
417 | |
418 | for (i = 0; i < dlc; i++) |
419 | cc770_write_reg(priv, msgobj[mo].data[i], cf->data[i]); |
420 | |
421 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
422 | RMTPND_UNC | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC); |
423 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
424 | MSGVAL_SET | TXIE_SET | RXIE_SET | INTPND_UNC); |
425 | } |
426 | |
427 | static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) |
428 | { |
429 | struct cc770_priv *priv = netdev_priv(dev); |
430 | unsigned int mo = obj2msgobj(CC770_OBJ_TX); |
431 | |
432 | if (can_dev_dropped_skb(dev, skb)) |
433 | return NETDEV_TX_OK; |
434 | |
435 | netif_stop_queue(dev); |
436 | |
437 | if ((cc770_read_reg(priv, |
438 | msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) { |
439 | netdev_err(dev, format: "TX register is still occupied!\n" ); |
440 | return NETDEV_TX_BUSY; |
441 | } |
442 | |
443 | priv->tx_skb = skb; |
444 | cc770_tx(dev, mo); |
445 | |
446 | return NETDEV_TX_OK; |
447 | } |
448 | |
449 | static void cc770_rx(struct net_device *dev, unsigned int mo, u8 ctrl1) |
450 | { |
451 | struct cc770_priv *priv = netdev_priv(dev); |
452 | struct net_device_stats *stats = &dev->stats; |
453 | struct can_frame *cf; |
454 | struct sk_buff *skb; |
455 | u8 config; |
456 | u32 id; |
457 | int i; |
458 | |
459 | skb = alloc_can_skb(dev, cf: &cf); |
460 | if (!skb) |
461 | return; |
462 | |
463 | config = cc770_read_reg(priv, msgobj[mo].config); |
464 | |
465 | if (ctrl1 & RMTPND_SET) { |
466 | /* |
467 | * Unfortunately, the chip does not store the real message |
468 | * identifier of the received remote transmission request |
469 | * frame. Therefore we set it to 0. |
470 | */ |
471 | cf->can_id = CAN_RTR_FLAG; |
472 | if (config & MSGCFG_XTD) |
473 | cf->can_id |= CAN_EFF_FLAG; |
474 | cf->len = 0; |
475 | } else { |
476 | if (config & MSGCFG_XTD) { |
477 | id = cc770_read_reg(priv, msgobj[mo].id[3]); |
478 | id |= cc770_read_reg(priv, msgobj[mo].id[2]) << 8; |
479 | id |= cc770_read_reg(priv, msgobj[mo].id[1]) << 16; |
480 | id |= cc770_read_reg(priv, msgobj[mo].id[0]) << 24; |
481 | id >>= 3; |
482 | id |= CAN_EFF_FLAG; |
483 | } else { |
484 | id = cc770_read_reg(priv, msgobj[mo].id[1]); |
485 | id |= cc770_read_reg(priv, msgobj[mo].id[0]) << 8; |
486 | id >>= 5; |
487 | } |
488 | |
489 | cf->can_id = id; |
490 | cf->len = can_cc_dlc2len((config & 0xf0) >> 4); |
491 | for (i = 0; i < cf->len; i++) |
492 | cf->data[i] = cc770_read_reg(priv, msgobj[mo].data[i]); |
493 | |
494 | stats->rx_bytes += cf->len; |
495 | } |
496 | stats->rx_packets++; |
497 | |
498 | netif_rx(skb); |
499 | } |
500 | |
501 | static int cc770_err(struct net_device *dev, u8 status) |
502 | { |
503 | struct cc770_priv *priv = netdev_priv(dev); |
504 | struct can_frame *cf; |
505 | struct sk_buff *skb; |
506 | u8 lec; |
507 | |
508 | netdev_dbg(dev, "status interrupt (%#x)\n" , status); |
509 | |
510 | skb = alloc_can_err_skb(dev, cf: &cf); |
511 | if (!skb) |
512 | return -ENOMEM; |
513 | |
514 | /* Use extended functions of the CC770 */ |
515 | if (priv->control_normal_mode & CTRL_EAF) { |
516 | cf->can_id |= CAN_ERR_CNT; |
517 | cf->data[6] = cc770_read_reg(priv, tx_error_counter); |
518 | cf->data[7] = cc770_read_reg(priv, rx_error_counter); |
519 | } |
520 | |
521 | if (status & STAT_BOFF) { |
522 | /* Disable interrupts */ |
523 | cc770_write_reg(priv, control, CTRL_INI); |
524 | cf->can_id |= CAN_ERR_BUSOFF; |
525 | priv->can.state = CAN_STATE_BUS_OFF; |
526 | priv->can.can_stats.bus_off++; |
527 | can_bus_off(dev); |
528 | } else if (status & STAT_WARN) { |
529 | cf->can_id |= CAN_ERR_CRTL; |
530 | /* Only the CC770 does show error passive */ |
531 | if (cf->data[7] > 127) { |
532 | cf->data[1] = CAN_ERR_CRTL_RX_PASSIVE | |
533 | CAN_ERR_CRTL_TX_PASSIVE; |
534 | priv->can.state = CAN_STATE_ERROR_PASSIVE; |
535 | priv->can.can_stats.error_passive++; |
536 | } else { |
537 | cf->data[1] = CAN_ERR_CRTL_RX_WARNING | |
538 | CAN_ERR_CRTL_TX_WARNING; |
539 | priv->can.state = CAN_STATE_ERROR_WARNING; |
540 | priv->can.can_stats.error_warning++; |
541 | } |
542 | } else { |
543 | /* Back to error active */ |
544 | cf->can_id |= CAN_ERR_PROT; |
545 | cf->data[2] = CAN_ERR_PROT_ACTIVE; |
546 | priv->can.state = CAN_STATE_ERROR_ACTIVE; |
547 | } |
548 | |
549 | lec = status & STAT_LEC_MASK; |
550 | if (lec < 7 && lec > 0) { |
551 | if (lec == STAT_LEC_ACK) { |
552 | cf->can_id |= CAN_ERR_ACK; |
553 | } else { |
554 | cf->can_id |= CAN_ERR_PROT; |
555 | switch (lec) { |
556 | case STAT_LEC_STUFF: |
557 | cf->data[2] |= CAN_ERR_PROT_STUFF; |
558 | break; |
559 | case STAT_LEC_FORM: |
560 | cf->data[2] |= CAN_ERR_PROT_FORM; |
561 | break; |
562 | case STAT_LEC_BIT1: |
563 | cf->data[2] |= CAN_ERR_PROT_BIT1; |
564 | break; |
565 | case STAT_LEC_BIT0: |
566 | cf->data[2] |= CAN_ERR_PROT_BIT0; |
567 | break; |
568 | case STAT_LEC_CRC: |
569 | cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; |
570 | break; |
571 | } |
572 | } |
573 | } |
574 | |
575 | |
576 | netif_rx(skb); |
577 | |
578 | return 0; |
579 | } |
580 | |
581 | static int cc770_status_interrupt(struct net_device *dev) |
582 | { |
583 | struct cc770_priv *priv = netdev_priv(dev); |
584 | u8 status; |
585 | |
586 | status = cc770_read_reg(priv, status); |
587 | /* Reset the status register including RXOK and TXOK */ |
588 | cc770_write_reg(priv, status, STAT_LEC_MASK); |
589 | |
590 | if (status & (STAT_WARN | STAT_BOFF) || |
591 | (status & STAT_LEC_MASK) != STAT_LEC_MASK) { |
592 | cc770_err(dev, status); |
593 | return status & STAT_BOFF; |
594 | } |
595 | |
596 | return 0; |
597 | } |
598 | |
599 | static void cc770_rx_interrupt(struct net_device *dev, unsigned int o) |
600 | { |
601 | struct cc770_priv *priv = netdev_priv(dev); |
602 | struct net_device_stats *stats = &dev->stats; |
603 | unsigned int mo = obj2msgobj(o); |
604 | u8 ctrl1; |
605 | int n = CC770_MAX_MSG; |
606 | |
607 | while (n--) { |
608 | ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1); |
609 | |
610 | if (!(ctrl1 & NEWDAT_SET)) { |
611 | /* Check for RTR if additional functions are enabled */ |
612 | if (priv->control_normal_mode & CTRL_EAF) { |
613 | if (!(cc770_read_reg(priv, msgobj[mo].ctrl0) & |
614 | INTPND_SET)) |
615 | break; |
616 | } else { |
617 | break; |
618 | } |
619 | } |
620 | |
621 | if (ctrl1 & MSGLST_SET) { |
622 | stats->rx_over_errors++; |
623 | stats->rx_errors++; |
624 | } |
625 | if (mo < MSGOBJ_LAST) |
626 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
627 | NEWDAT_RES | MSGLST_RES | |
628 | TXRQST_UNC | RMTPND_UNC); |
629 | cc770_rx(dev, mo, ctrl1); |
630 | |
631 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
632 | MSGVAL_SET | TXIE_RES | |
633 | RXIE_SET | INTPND_RES); |
634 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
635 | NEWDAT_RES | MSGLST_RES | |
636 | TXRQST_RES | RMTPND_RES); |
637 | } |
638 | } |
639 | |
640 | static void cc770_rtr_interrupt(struct net_device *dev, unsigned int o) |
641 | { |
642 | struct cc770_priv *priv = netdev_priv(dev); |
643 | unsigned int mo = obj2msgobj(o); |
644 | u8 ctrl0, ctrl1; |
645 | int n = CC770_MAX_MSG; |
646 | |
647 | while (n--) { |
648 | ctrl0 = cc770_read_reg(priv, msgobj[mo].ctrl0); |
649 | if (!(ctrl0 & INTPND_SET)) |
650 | break; |
651 | |
652 | ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1); |
653 | cc770_rx(dev, mo, ctrl1); |
654 | |
655 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
656 | MSGVAL_SET | TXIE_RES | |
657 | RXIE_SET | INTPND_RES); |
658 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
659 | NEWDAT_RES | CPUUPD_SET | |
660 | TXRQST_RES | RMTPND_RES); |
661 | } |
662 | } |
663 | |
664 | static void cc770_tx_interrupt(struct net_device *dev, unsigned int o) |
665 | { |
666 | struct cc770_priv *priv = netdev_priv(dev); |
667 | struct net_device_stats *stats = &dev->stats; |
668 | unsigned int mo = obj2msgobj(o); |
669 | u8 ctrl1; |
670 | |
671 | ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1); |
672 | |
673 | cc770_write_reg(priv, msgobj[mo].ctrl0, |
674 | MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); |
675 | cc770_write_reg(priv, msgobj[mo].ctrl1, |
676 | RMTPND_RES | TXRQST_RES | MSGLST_RES | NEWDAT_RES); |
677 | |
678 | if (unlikely(!priv->tx_skb)) { |
679 | netdev_err(dev, format: "missing tx skb in tx interrupt\n" ); |
680 | return; |
681 | } |
682 | |
683 | if (unlikely(ctrl1 & MSGLST_SET)) { |
684 | stats->rx_over_errors++; |
685 | stats->rx_errors++; |
686 | } |
687 | |
688 | /* When the CC770 is sending an RTR message and it receives a regular |
689 | * message that matches the id of the RTR message, it will overwrite the |
690 | * outgoing message in the TX register. When this happens we must |
691 | * process the received message and try to transmit the outgoing skb |
692 | * again. |
693 | */ |
694 | if (unlikely(ctrl1 & NEWDAT_SET)) { |
695 | cc770_rx(dev, mo, ctrl1); |
696 | cc770_tx(dev, mo); |
697 | return; |
698 | } |
699 | |
700 | can_put_echo_skb(skb: priv->tx_skb, dev, idx: 0, frame_len: 0); |
701 | stats->tx_bytes += can_get_echo_skb(dev, idx: 0, NULL); |
702 | stats->tx_packets++; |
703 | priv->tx_skb = NULL; |
704 | |
705 | netif_wake_queue(dev); |
706 | } |
707 | |
708 | static irqreturn_t cc770_interrupt(int irq, void *dev_id) |
709 | { |
710 | struct net_device *dev = (struct net_device *)dev_id; |
711 | struct cc770_priv *priv = netdev_priv(dev); |
712 | u8 intid; |
713 | int o, n = 0; |
714 | |
715 | /* Shared interrupts and IRQ off? */ |
716 | if (priv->can.state == CAN_STATE_STOPPED) |
717 | return IRQ_NONE; |
718 | |
719 | if (priv->pre_irq) |
720 | priv->pre_irq(priv); |
721 | |
722 | while (n < CC770_MAX_IRQ) { |
723 | /* Read the highest pending interrupt request */ |
724 | intid = cc770_read_reg(priv, interrupt); |
725 | if (!intid) |
726 | break; |
727 | n++; |
728 | |
729 | if (intid == 1) { |
730 | /* Exit in case of bus-off */ |
731 | if (cc770_status_interrupt(dev)) |
732 | break; |
733 | } else { |
734 | o = intid2obj(intid); |
735 | |
736 | if (o >= CC770_OBJ_MAX) { |
737 | netdev_err(dev, format: "Unexpected interrupt id %d\n" , |
738 | intid); |
739 | continue; |
740 | } |
741 | |
742 | if (priv->obj_flags[o] & CC770_OBJ_FLAG_RTR) |
743 | cc770_rtr_interrupt(dev, o); |
744 | else if (priv->obj_flags[o] & CC770_OBJ_FLAG_RX) |
745 | cc770_rx_interrupt(dev, o); |
746 | else |
747 | cc770_tx_interrupt(dev, o); |
748 | } |
749 | } |
750 | |
751 | if (priv->post_irq) |
752 | priv->post_irq(priv); |
753 | |
754 | if (n >= CC770_MAX_IRQ) |
755 | netdev_dbg(dev, "%d messages handled in ISR" , n); |
756 | |
757 | return (n) ? IRQ_HANDLED : IRQ_NONE; |
758 | } |
759 | |
760 | static int cc770_open(struct net_device *dev) |
761 | { |
762 | struct cc770_priv *priv = netdev_priv(dev); |
763 | int err; |
764 | |
765 | /* set chip into reset mode */ |
766 | set_reset_mode(dev); |
767 | |
768 | /* common open */ |
769 | err = open_candev(dev); |
770 | if (err) |
771 | return err; |
772 | |
773 | err = request_irq(irq: dev->irq, handler: &cc770_interrupt, flags: priv->irq_flags, |
774 | name: dev->name, dev); |
775 | if (err) { |
776 | close_candev(dev); |
777 | return -EAGAIN; |
778 | } |
779 | |
780 | /* init and start chip */ |
781 | cc770_start(dev); |
782 | |
783 | netif_start_queue(dev); |
784 | |
785 | return 0; |
786 | } |
787 | |
788 | static int cc770_close(struct net_device *dev) |
789 | { |
790 | netif_stop_queue(dev); |
791 | set_reset_mode(dev); |
792 | |
793 | free_irq(dev->irq, dev); |
794 | close_candev(dev); |
795 | |
796 | return 0; |
797 | } |
798 | |
799 | struct net_device *alloc_cc770dev(int sizeof_priv) |
800 | { |
801 | struct net_device *dev; |
802 | struct cc770_priv *priv; |
803 | |
804 | dev = alloc_candev(sizeof(struct cc770_priv) + sizeof_priv, |
805 | CC770_ECHO_SKB_MAX); |
806 | if (!dev) |
807 | return NULL; |
808 | |
809 | priv = netdev_priv(dev); |
810 | |
811 | priv->dev = dev; |
812 | priv->can.bittiming_const = &cc770_bittiming_const; |
813 | priv->can.do_set_bittiming = cc770_set_bittiming; |
814 | priv->can.do_set_mode = cc770_set_mode; |
815 | priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; |
816 | priv->tx_skb = NULL; |
817 | |
818 | memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags)); |
819 | |
820 | if (sizeof_priv) |
821 | priv->priv = (void *)priv + sizeof(struct cc770_priv); |
822 | |
823 | return dev; |
824 | } |
825 | EXPORT_SYMBOL_GPL(alloc_cc770dev); |
826 | |
827 | void free_cc770dev(struct net_device *dev) |
828 | { |
829 | free_candev(dev); |
830 | } |
831 | EXPORT_SYMBOL_GPL(free_cc770dev); |
832 | |
833 | static const struct net_device_ops cc770_netdev_ops = { |
834 | .ndo_open = cc770_open, |
835 | .ndo_stop = cc770_close, |
836 | .ndo_start_xmit = cc770_start_xmit, |
837 | .ndo_change_mtu = can_change_mtu, |
838 | }; |
839 | |
840 | static const struct ethtool_ops cc770_ethtool_ops = { |
841 | .get_ts_info = ethtool_op_get_ts_info, |
842 | }; |
843 | |
844 | int register_cc770dev(struct net_device *dev) |
845 | { |
846 | struct cc770_priv *priv = netdev_priv(dev); |
847 | int err; |
848 | |
849 | err = cc770_probe_chip(dev); |
850 | if (err) |
851 | return err; |
852 | |
853 | dev->netdev_ops = &cc770_netdev_ops; |
854 | dev->ethtool_ops = &cc770_ethtool_ops; |
855 | |
856 | dev->flags |= IFF_ECHO; /* we support local echo */ |
857 | |
858 | /* Should we use additional functions? */ |
859 | if (!i82527_compat && priv->control_normal_mode & CTRL_EAF) { |
860 | priv->can.do_get_berr_counter = cc770_get_berr_counter; |
861 | priv->control_normal_mode = CTRL_IE | CTRL_EAF | CTRL_EIE; |
862 | netdev_dbg(dev, "i82527 mode with additional functions\n" ); |
863 | } else { |
864 | priv->control_normal_mode = CTRL_IE | CTRL_EIE; |
865 | netdev_dbg(dev, "strict i82527 compatibility mode\n" ); |
866 | } |
867 | |
868 | chipset_init(priv); |
869 | set_reset_mode(dev); |
870 | |
871 | return register_candev(dev); |
872 | } |
873 | EXPORT_SYMBOL_GPL(register_cc770dev); |
874 | |
875 | void unregister_cc770dev(struct net_device *dev) |
876 | { |
877 | set_reset_mode(dev); |
878 | unregister_candev(dev); |
879 | } |
880 | EXPORT_SYMBOL_GPL(unregister_cc770dev); |
881 | |
882 | static __init int cc770_init(void) |
883 | { |
884 | if (msgobj15_eff) { |
885 | cc770_obj_flags[CC770_OBJ_RX0] |= CC770_OBJ_FLAG_EFF; |
886 | cc770_obj_flags[CC770_OBJ_RX1] &= ~CC770_OBJ_FLAG_EFF; |
887 | } |
888 | |
889 | pr_info("CAN netdevice driver\n" ); |
890 | |
891 | return 0; |
892 | } |
893 | module_init(cc770_init); |
894 | |
895 | static __exit void cc770_exit(void) |
896 | { |
897 | pr_info("driver removed\n" ); |
898 | } |
899 | module_exit(cc770_exit); |
900 | |