diff options
author | Dong Aisheng <b29396@freescale.com> | 2014-06-25 08:05:19 -0400 |
---|---|---|
committer | Dong Aisheng <b29396@freescale.com> | 2014-06-29 23:36:16 -0400 |
commit | 19d35d8c55fb1edba73c70cf133c8a361e56a956 (patch) | |
tree | 750fea795b6a200345583ad076ab4b9781e65cbe /drivers/net | |
parent | d965cfdbf03d972baac616e9f1d6c9e50d0d3c5c (diff) |
ENGR00320354-1 can: m_can: add bus error handling
Add bus error, state change, lost message handling mechanism.
Signed-off-by: Dong Aisheng <b29396@freescale.com>
(cherry picked from commit f2f95e529927f3debeef1fa19ac560d2ebf71140)
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/can/m_can.c | 271 |
1 files changed, 240 insertions, 31 deletions
diff --git a/drivers/net/can/m_can.c b/drivers/net/can/m_can.c index 4397cfe2ec31..1a320aff2b27 100644 --- a/drivers/net/can/m_can.c +++ b/drivers/net/can/m_can.c | |||
@@ -83,6 +83,18 @@ enum m_can_reg { | |||
83 | M_CAN_TXEFA = 0xf8, | 83 | M_CAN_TXEFA = 0xf8, |
84 | }; | 84 | }; |
85 | 85 | ||
86 | /* m_can lec values */ | ||
87 | enum m_can_lec_type { | ||
88 | LEC_NO_ERROR = 0, | ||
89 | LEC_STUFF_ERROR, | ||
90 | LEC_FORM_ERROR, | ||
91 | LEC_ACK_ERROR, | ||
92 | LEC_BIT1_ERROR, | ||
93 | LEC_BIT0_ERROR, | ||
94 | LEC_CRC_ERROR, | ||
95 | LEC_UNUSED, | ||
96 | }; | ||
97 | |||
86 | /* CC Control Register(CCCR) */ | 98 | /* CC Control Register(CCCR) */ |
87 | #define CCCR_CCE BIT(1) | 99 | #define CCCR_CCE BIT(1) |
88 | #define CCCR_INIT BIT(0) | 100 | #define CCCR_INIT BIT(0) |
@@ -97,6 +109,19 @@ enum m_can_reg { | |||
97 | #define BTR_SJW_SHIFT 0 | 109 | #define BTR_SJW_SHIFT 0 |
98 | #define BTR_SJW_MASK 0xf | 110 | #define BTR_SJW_MASK 0xf |
99 | 111 | ||
112 | /* Error Counter Register(ECR) */ | ||
113 | #define ECR_RP BIT(15) | ||
114 | #define ECR_REC_SHIFT 8 | ||
115 | #define ECR_REC_MASK (0x7f << ECR_REC_SHIFT) | ||
116 | #define ECR_TEC_SHIFT 0 | ||
117 | #define ECR_TEC_MASK 0xff | ||
118 | |||
119 | /* Protocol Status Register(PSR) */ | ||
120 | #define PSR_BO BIT(7) | ||
121 | #define PSR_EW BIT(6) | ||
122 | #define PSR_EP BIT(5) | ||
123 | #define PSR_LEC_MASK 0x7 | ||
124 | |||
100 | /* Interrupt Register(IR) */ | 125 | /* Interrupt Register(IR) */ |
101 | #define IR_ALL_INT 0xffffffff | 126 | #define IR_ALL_INT 0xffffffff |
102 | #define IR_STE BIT(31) | 127 | #define IR_STE BIT(31) |
@@ -131,10 +156,11 @@ enum m_can_reg { | |||
131 | #define IR_RF0F BIT(2) | 156 | #define IR_RF0F BIT(2) |
132 | #define IR_RF0W BIT(1) | 157 | #define IR_RF0W BIT(1) |
133 | #define IR_RF0N BIT(0) | 158 | #define IR_RF0N BIT(0) |
134 | #define IR_ERR_ALL (IR_STE | IR_FOE | IR_ACKE | IR_BE | IR_CRCE | \ | 159 | #define IR_ERR_STATE (IR_BO | IR_EW | IR_EP) |
135 | IR_WDI | IR_BO | IR_EW | IR_EP | IR_ELO | IR_BEU | \ | 160 | #define IR_ERR_BUS (IR_STE | IR_FOE | IR_ACKE | IR_BE | IR_CRCE | \ |
136 | IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \ | 161 | IR_WDI | IR_ELO | IR_BEU | IR_BEC | IR_TOO | IR_MRAF | \ |
137 | IR_RF0L) | 162 | IR_TSW | IR_TEFL | IR_RF1L | IR_RF0L) |
163 | #define IR_ERR_ALL (IR_ERR_STATE | IR_ERR_BUS) | ||
138 | 164 | ||
139 | /* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */ | 165 | /* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */ |
140 | #define RXFC_FWM_OFF 24 | 166 | #define RXFC_FWM_OFF 24 |
@@ -320,12 +346,175 @@ static int m_can_do_rx_poll(struct net_device *dev, int quota) | |||
320 | return num_rx_pkts; | 346 | return num_rx_pkts; |
321 | } | 347 | } |
322 | 348 | ||
349 | static int m_can_handle_lost_msg(struct net_device *dev) | ||
350 | { | ||
351 | struct net_device_stats *stats = &dev->stats; | ||
352 | struct sk_buff *skb; | ||
353 | struct can_frame *frame; | ||
354 | |||
355 | netdev_err(dev, "msg lost in rxf0\n"); | ||
356 | |||
357 | skb = alloc_can_err_skb(dev, &frame); | ||
358 | if (unlikely(!skb)) | ||
359 | return 0; | ||
360 | |||
361 | frame->can_id |= CAN_ERR_CRTL; | ||
362 | frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; | ||
363 | stats->rx_errors++; | ||
364 | stats->rx_over_errors++; | ||
365 | |||
366 | netif_receive_skb(skb); | ||
367 | |||
368 | return 1; | ||
369 | } | ||
370 | |||
371 | static int m_can_handle_bus_err(struct net_device *dev, | ||
372 | enum m_can_lec_type lec_type) | ||
373 | { | ||
374 | struct m_can_priv *priv = netdev_priv(dev); | ||
375 | struct net_device_stats *stats = &dev->stats; | ||
376 | struct can_frame *cf; | ||
377 | struct sk_buff *skb; | ||
378 | |||
379 | /* early exit if no lec update */ | ||
380 | if (lec_type == LEC_UNUSED) | ||
381 | return 0; | ||
382 | |||
383 | /* propagate the error condition to the CAN stack */ | ||
384 | skb = alloc_can_err_skb(dev, &cf); | ||
385 | if (unlikely(!skb)) | ||
386 | return 0; | ||
387 | |||
388 | /* | ||
389 | * check for 'last error code' which tells us the | ||
390 | * type of the last error to occur on the CAN bus | ||
391 | */ | ||
392 | priv->can.can_stats.bus_error++; | ||
393 | stats->rx_errors++; | ||
394 | cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; | ||
395 | cf->data[2] |= CAN_ERR_PROT_UNSPEC; | ||
396 | |||
397 | switch (lec_type) { | ||
398 | case LEC_STUFF_ERROR: | ||
399 | netdev_dbg(dev, "stuff error\n"); | ||
400 | cf->data[2] |= CAN_ERR_PROT_STUFF; | ||
401 | break; | ||
402 | case LEC_FORM_ERROR: | ||
403 | netdev_dbg(dev, "form error\n"); | ||
404 | cf->data[2] |= CAN_ERR_PROT_FORM; | ||
405 | break; | ||
406 | case LEC_ACK_ERROR: | ||
407 | netdev_dbg(dev, "ack error\n"); | ||
408 | cf->data[3] |= (CAN_ERR_PROT_LOC_ACK | | ||
409 | CAN_ERR_PROT_LOC_ACK_DEL); | ||
410 | break; | ||
411 | case LEC_BIT1_ERROR: | ||
412 | netdev_dbg(dev, "bit1 error\n"); | ||
413 | cf->data[2] |= CAN_ERR_PROT_BIT1; | ||
414 | break; | ||
415 | case LEC_BIT0_ERROR: | ||
416 | netdev_dbg(dev, "bit0 error\n"); | ||
417 | cf->data[2] |= CAN_ERR_PROT_BIT0; | ||
418 | break; | ||
419 | case LEC_CRC_ERROR: | ||
420 | netdev_dbg(dev, "CRC error\n"); | ||
421 | cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ | | ||
422 | CAN_ERR_PROT_LOC_CRC_DEL); | ||
423 | break; | ||
424 | default: | ||
425 | break; | ||
426 | } | ||
427 | |||
428 | netif_receive_skb(skb); | ||
429 | stats->rx_packets++; | ||
430 | stats->rx_bytes += cf->can_dlc; | ||
431 | |||
432 | return 1; | ||
433 | } | ||
434 | |||
435 | static int m_can_get_berr_counter(const struct net_device *dev, | ||
436 | struct can_berr_counter *bec) | ||
437 | { | ||
438 | struct m_can_priv *priv = netdev_priv(dev); | ||
439 | unsigned int ecr; | ||
440 | |||
441 | ecr = m_can_read(priv, M_CAN_ECR); | ||
442 | bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT; | ||
443 | bec->txerr = ecr & ECR_TEC_MASK; | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int m_can_handle_state_change(struct net_device *dev, | ||
449 | enum can_state new_state) | ||
450 | { | ||
451 | struct m_can_priv *priv = netdev_priv(dev); | ||
452 | struct net_device_stats *stats = &dev->stats; | ||
453 | struct can_frame *cf; | ||
454 | struct sk_buff *skb; | ||
455 | struct can_berr_counter bec; | ||
456 | unsigned int ecr; | ||
457 | |||
458 | /* propagate the error condition to the CAN stack */ | ||
459 | skb = alloc_can_err_skb(dev, &cf); | ||
460 | if (unlikely(!skb)) | ||
461 | return 0; | ||
462 | |||
463 | m_can_get_berr_counter(dev, &bec); | ||
464 | |||
465 | switch (new_state) { | ||
466 | case CAN_STATE_ERROR_ACTIVE: | ||
467 | /* error warning state */ | ||
468 | priv->can.can_stats.error_warning++; | ||
469 | priv->can.state = CAN_STATE_ERROR_WARNING; | ||
470 | cf->can_id |= CAN_ERR_CRTL; | ||
471 | cf->data[1] = (bec.txerr > bec.rxerr) ? | ||
472 | CAN_ERR_CRTL_TX_WARNING : | ||
473 | CAN_ERR_CRTL_RX_WARNING; | ||
474 | cf->data[6] = bec.txerr; | ||
475 | cf->data[7] = bec.rxerr; | ||
476 | break; | ||
477 | case CAN_STATE_ERROR_PASSIVE: | ||
478 | /* error passive state */ | ||
479 | priv->can.can_stats.error_passive++; | ||
480 | priv->can.state = CAN_STATE_ERROR_PASSIVE; | ||
481 | cf->can_id |= CAN_ERR_CRTL; | ||
482 | ecr = m_can_read(priv, M_CAN_ECR); | ||
483 | if (ecr & ECR_RP) | ||
484 | cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE; | ||
485 | if (bec.txerr > 127) | ||
486 | cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE; | ||
487 | cf->data[6] = bec.txerr; | ||
488 | cf->data[7] = bec.rxerr; | ||
489 | break; | ||
490 | case CAN_STATE_BUS_OFF: | ||
491 | /* bus-off state */ | ||
492 | priv->can.state = CAN_STATE_BUS_OFF; | ||
493 | cf->can_id |= CAN_ERR_BUSOFF; | ||
494 | /* | ||
495 | * disable all interrupts in bus-off mode to ensure that | ||
496 | * the CPU is not hogged down | ||
497 | */ | ||
498 | m_can_enable_all_interrupts(priv, false); | ||
499 | can_bus_off(dev); | ||
500 | break; | ||
501 | default: | ||
502 | break; | ||
503 | } | ||
504 | |||
505 | netif_receive_skb(skb); | ||
506 | stats->rx_packets++; | ||
507 | stats->rx_bytes += cf->can_dlc; | ||
508 | |||
509 | return 1; | ||
510 | } | ||
511 | |||
323 | static int m_can_poll(struct napi_struct *napi, int quota) | 512 | static int m_can_poll(struct napi_struct *napi, int quota) |
324 | { | 513 | { |
325 | struct net_device *dev = napi->dev; | 514 | struct net_device *dev = napi->dev; |
326 | struct m_can_priv *priv = netdev_priv(dev); | 515 | struct m_can_priv *priv = netdev_priv(dev); |
327 | u32 work_done = 0; | 516 | u32 work_done = 0; |
328 | u32 irqstatus; | 517 | u32 irqstatus, psr; |
329 | 518 | ||
330 | irqstatus = m_can_read(priv, M_CAN_IR); | 519 | irqstatus = m_can_read(priv, M_CAN_IR); |
331 | if (irqstatus) | 520 | if (irqstatus) |
@@ -337,6 +526,48 @@ static int m_can_poll(struct napi_struct *napi, int quota) | |||
337 | if (!irqstatus) | 526 | if (!irqstatus) |
338 | goto end; | 527 | goto end; |
339 | 528 | ||
529 | psr = m_can_read(priv, M_CAN_PSR); | ||
530 | if (irqstatus & IR_ERR_STATE) { | ||
531 | if ((psr & PSR_EW) && | ||
532 | (priv->can.state != CAN_STATE_ERROR_WARNING)) { | ||
533 | netdev_dbg(dev, "entered error warning state\n"); | ||
534 | work_done += m_can_handle_state_change(dev, | ||
535 | CAN_STATE_ERROR_WARNING); | ||
536 | } | ||
537 | |||
538 | if ((psr & PSR_EP) && | ||
539 | (priv->can.state != CAN_STATE_ERROR_PASSIVE)) { | ||
540 | netdev_dbg(dev, "entered error warning state\n"); | ||
541 | work_done += m_can_handle_state_change(dev, | ||
542 | CAN_STATE_ERROR_PASSIVE); | ||
543 | } | ||
544 | |||
545 | if ((psr & PSR_BO) && | ||
546 | (priv->can.state != CAN_STATE_BUS_OFF)) { | ||
547 | netdev_dbg(dev, "entered error warning state\n"); | ||
548 | work_done += m_can_handle_state_change(dev, | ||
549 | CAN_STATE_BUS_OFF); | ||
550 | } | ||
551 | } | ||
552 | |||
553 | if (irqstatus & IR_ERR_BUS) { | ||
554 | if (irqstatus & IR_RF0L) | ||
555 | work_done += m_can_handle_lost_msg(dev); | ||
556 | |||
557 | /* handle lec errors on the bus */ | ||
558 | if (psr & LEC_UNUSED) | ||
559 | work_done += m_can_handle_bus_err(dev, | ||
560 | psr & LEC_UNUSED); | ||
561 | |||
562 | /* other unproccessed error interrupts */ | ||
563 | if (irqstatus & IR_WDI) | ||
564 | netdev_err(dev, "Message RAM Watchdog event due to missing READY\n"); | ||
565 | if (irqstatus & IR_TOO) | ||
566 | netdev_err(dev, "Timeout reached\n"); | ||
567 | if (irqstatus & IR_MRAF) | ||
568 | netdev_err(dev, "Message RAM access failure occurred\n"); | ||
569 | } | ||
570 | |||
340 | if (irqstatus & IR_RF0N) | 571 | if (irqstatus & IR_RF0N) |
341 | /* handle events corresponding to receive message objects */ | 572 | /* handle events corresponding to receive message objects */ |
342 | work_done += m_can_do_rx_poll(dev, (quota - work_done)); | 573 | work_done += m_can_do_rx_poll(dev, (quota - work_done)); |
@@ -369,31 +600,18 @@ static irqreturn_t m_can_isr(int irq, void *dev_id) | |||
369 | if (ir & IR_ALL_INT) | 600 | if (ir & IR_ALL_INT) |
370 | m_can_write(priv, M_CAN_IR, ir); | 601 | m_can_write(priv, M_CAN_IR, ir); |
371 | 602 | ||
372 | if (ir & IR_ERR_ALL) { | ||
373 | netdev_dbg(dev, "bus error\n"); | ||
374 | /* TODO: handle bus error */ | ||
375 | } | ||
376 | |||
377 | /* save irqstatus for later using */ | ||
378 | priv->irqstatus = ir; | ||
379 | |||
380 | /* | 603 | /* |
381 | * schedule NAPI in case of | 604 | * schedule NAPI in case of |
382 | * - rx IRQ | 605 | * - rx IRQ |
383 | * - state change IRQ(TODO) | 606 | * - state change IRQ |
384 | * - bus error IRQ and bus error reporting (TODO) | 607 | * - bus error IRQ and bus error reporting |
385 | */ | 608 | */ |
386 | if (ir & IR_RF0N) { | 609 | if ((ir & IR_RF0N) || (ir & IR_ERR_ALL)) { |
610 | priv->irqstatus = ir; | ||
387 | m_can_enable_all_interrupts(priv, false); | 611 | m_can_enable_all_interrupts(priv, false); |
388 | napi_schedule(&priv->napi); | 612 | napi_schedule(&priv->napi); |
389 | } | 613 | } |
390 | 614 | ||
391 | /* FIFO overflow */ | ||
392 | if (ir & IR_RF0L) { | ||
393 | dev->stats.rx_over_errors++; | ||
394 | dev->stats.rx_errors++; | ||
395 | } | ||
396 | |||
397 | /* transmission complete interrupt */ | 615 | /* transmission complete interrupt */ |
398 | if (ir & IR_TC) { | 616 | if (ir & IR_TC) { |
399 | netdev_dbg(dev, "tx complete\n"); | 617 | netdev_dbg(dev, "tx complete\n"); |
@@ -446,7 +664,6 @@ static int m_can_set_bittiming(struct net_device *dev) | |||
446 | * - setup bittiming | 664 | * - setup bittiming |
447 | * - TODO: | 665 | * - TODO: |
448 | * 1) other working modes support like monitor, loopback... | 666 | * 1) other working modes support like monitor, loopback... |
449 | * 2) lec error status report enable | ||
450 | */ | 667 | */ |
451 | static void m_can_chip_config(struct net_device *dev) | 668 | static void m_can_chip_config(struct net_device *dev) |
452 | { | 669 | { |
@@ -515,14 +732,6 @@ static int m_can_set_mode(struct net_device *dev, enum can_mode mode) | |||
515 | return 0; | 732 | return 0; |
516 | } | 733 | } |
517 | 734 | ||
518 | static int m_can_get_berr_counter(const struct net_device *dev, | ||
519 | struct can_berr_counter *bec) | ||
520 | { | ||
521 | /* TODO */ | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static void free_m_can_dev(struct net_device *dev) | 735 | static void free_m_can_dev(struct net_device *dev) |
527 | { | 736 | { |
528 | free_candev(dev); | 737 | free_candev(dev); |