aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2018-03-01 13:34:00 -0500
committerMarc Kleine-Budde <mkl@pengutronix.de>2018-03-12 04:55:12 -0400
commit880dd464b4304583c557c4e5f5ecebfd55d232b1 (patch)
treee4500fb5f7ffd4aa107f8fcdbcfb2608e772a43a
parent591d65d5b15496af8d05e252bc1da611c66c0b79 (diff)
can: ifi: Repair the error handling
The new version of the IFI CANFD core has significantly less complex error state indication logic. In particular, the warning/error state bits are no longer all over the place, but are all present in the STATUS register. Moreover, there is a new IRQ register bit indicating transition between error states (active/warning/passive/busoff). This patch makes use of this bit to weed out the obscure selective INTERRUPT register clearing, which was used to carry over the error state indication into the poll function. While at it, this patch fixes the handling of the ACTIVE state, since the hardware provides indication of the core being in ACTIVE state and that in turn fixes the state transition indication toward userspace. Finally, register reads in the poll function are moved to the matching subfunctions since those are also no longer needed in the poll function. Signed-off-by: Marek Vasut <marex@denx.de> Cc: Heiko Schocher <hs@denx.de> Cc: Markus Marb <markus@marb.org> Cc: Marc Kleine-Budde <mkl@pengutronix.de> Cc: linux-stable <stable@vger.kernel.org> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r--drivers/net/can/ifi_canfd/ifi_canfd.c64
1 files changed, 37 insertions, 27 deletions
diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
index 9fd396c3569a..fedd927ba6ed 100644
--- a/drivers/net/can/ifi_canfd/ifi_canfd.c
+++ b/drivers/net/can/ifi_canfd/ifi_canfd.c
@@ -30,6 +30,7 @@
30#define IFI_CANFD_STCMD_ERROR_ACTIVE BIT(2) 30#define IFI_CANFD_STCMD_ERROR_ACTIVE BIT(2)
31#define IFI_CANFD_STCMD_ERROR_PASSIVE BIT(3) 31#define IFI_CANFD_STCMD_ERROR_PASSIVE BIT(3)
32#define IFI_CANFD_STCMD_BUSOFF BIT(4) 32#define IFI_CANFD_STCMD_BUSOFF BIT(4)
33#define IFI_CANFD_STCMD_ERROR_WARNING BIT(5)
33#define IFI_CANFD_STCMD_BUSMONITOR BIT(16) 34#define IFI_CANFD_STCMD_BUSMONITOR BIT(16)
34#define IFI_CANFD_STCMD_LOOPBACK BIT(18) 35#define IFI_CANFD_STCMD_LOOPBACK BIT(18)
35#define IFI_CANFD_STCMD_DISABLE_CANFD BIT(24) 36#define IFI_CANFD_STCMD_DISABLE_CANFD BIT(24)
@@ -52,7 +53,10 @@
52#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13) 53#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13)
53 54
54#define IFI_CANFD_INTERRUPT 0xc 55#define IFI_CANFD_INTERRUPT 0xc
56#define IFI_CANFD_INTERRUPT_ERROR_BUSOFF BIT(0)
55#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1) 57#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
58#define IFI_CANFD_INTERRUPT_ERROR_STATE_CHG BIT(2)
59#define IFI_CANFD_INTERRUPT_ERROR_REC_TEC_INC BIT(3)
56#define IFI_CANFD_INTERRUPT_ERROR_COUNTER BIT(10) 60#define IFI_CANFD_INTERRUPT_ERROR_COUNTER BIT(10)
57#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16) 61#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16)
58#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22) 62#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22)
@@ -61,6 +65,10 @@
61#define IFI_CANFD_INTERRUPT_SET_IRQ ((u32)BIT(31)) 65#define IFI_CANFD_INTERRUPT_SET_IRQ ((u32)BIT(31))
62 66
63#define IFI_CANFD_IRQMASK 0x10 67#define IFI_CANFD_IRQMASK 0x10
68#define IFI_CANFD_IRQMASK_ERROR_BUSOFF BIT(0)
69#define IFI_CANFD_IRQMASK_ERROR_WARNING BIT(1)
70#define IFI_CANFD_IRQMASK_ERROR_STATE_CHG BIT(2)
71#define IFI_CANFD_IRQMASK_ERROR_REC_TEC_INC BIT(3)
64#define IFI_CANFD_IRQMASK_SET_ERR BIT(7) 72#define IFI_CANFD_IRQMASK_SET_ERR BIT(7)
65#define IFI_CANFD_IRQMASK_SET_TS BIT(15) 73#define IFI_CANFD_IRQMASK_SET_TS BIT(15)
66#define IFI_CANFD_IRQMASK_TXFIFO_EMPTY BIT(16) 74#define IFI_CANFD_IRQMASK_TXFIFO_EMPTY BIT(16)
@@ -222,7 +230,10 @@ static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable)
222 230
223 if (enable) { 231 if (enable) {
224 enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY | 232 enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY |
225 IFI_CANFD_IRQMASK_RXFIFO_NEMPTY; 233 IFI_CANFD_IRQMASK_RXFIFO_NEMPTY |
234 IFI_CANFD_IRQMASK_ERROR_STATE_CHG |
235 IFI_CANFD_IRQMASK_ERROR_WARNING |
236 IFI_CANFD_IRQMASK_ERROR_BUSOFF;
226 if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) 237 if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
227 enirq |= IFI_CANFD_INTERRUPT_ERROR_COUNTER; 238 enirq |= IFI_CANFD_INTERRUPT_ERROR_COUNTER;
228 } 239 }
@@ -363,12 +374,13 @@ static int ifi_canfd_handle_lost_msg(struct net_device *ndev)
363 return 1; 374 return 1;
364} 375}
365 376
366static int ifi_canfd_handle_lec_err(struct net_device *ndev, const u32 errctr) 377static int ifi_canfd_handle_lec_err(struct net_device *ndev)
367{ 378{
368 struct ifi_canfd_priv *priv = netdev_priv(ndev); 379 struct ifi_canfd_priv *priv = netdev_priv(ndev);
369 struct net_device_stats *stats = &ndev->stats; 380 struct net_device_stats *stats = &ndev->stats;
370 struct can_frame *cf; 381 struct can_frame *cf;
371 struct sk_buff *skb; 382 struct sk_buff *skb;
383 u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR);
372 const u32 errmask = IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST | 384 const u32 errmask = IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST |
373 IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST | 385 IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST |
374 IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST | 386 IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST |
@@ -451,6 +463,11 @@ static int ifi_canfd_handle_state_change(struct net_device *ndev,
451 463
452 switch (new_state) { 464 switch (new_state) {
453 case CAN_STATE_ERROR_ACTIVE: 465 case CAN_STATE_ERROR_ACTIVE:
466 /* error active state */
467 priv->can.can_stats.error_warning++;
468 priv->can.state = CAN_STATE_ERROR_ACTIVE;
469 break;
470 case CAN_STATE_ERROR_WARNING:
454 /* error warning state */ 471 /* error warning state */
455 priv->can.can_stats.error_warning++; 472 priv->can.can_stats.error_warning++;
456 priv->can.state = CAN_STATE_ERROR_WARNING; 473 priv->can.state = CAN_STATE_ERROR_WARNING;
@@ -479,7 +496,7 @@ static int ifi_canfd_handle_state_change(struct net_device *ndev,
479 ifi_canfd_get_berr_counter(ndev, &bec); 496 ifi_canfd_get_berr_counter(ndev, &bec);
480 497
481 switch (new_state) { 498 switch (new_state) {
482 case CAN_STATE_ERROR_ACTIVE: 499 case CAN_STATE_ERROR_WARNING:
483 /* error warning state */ 500 /* error warning state */
484 cf->can_id |= CAN_ERR_CRTL; 501 cf->can_id |= CAN_ERR_CRTL;
485 cf->data[1] = (bec.txerr > bec.rxerr) ? 502 cf->data[1] = (bec.txerr > bec.rxerr) ?
@@ -512,22 +529,21 @@ static int ifi_canfd_handle_state_change(struct net_device *ndev,
512 return 1; 529 return 1;
513} 530}
514 531
515static int ifi_canfd_handle_state_errors(struct net_device *ndev, u32 stcmd) 532static int ifi_canfd_handle_state_errors(struct net_device *ndev)
516{ 533{
517 struct ifi_canfd_priv *priv = netdev_priv(ndev); 534 struct ifi_canfd_priv *priv = netdev_priv(ndev);
535 u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
518 int work_done = 0; 536 int work_done = 0;
519 u32 isr;
520 537
521 /* 538 if ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) &&
522 * The ErrWarn condition is a little special, since the bit is 539 (priv->can.state != CAN_STATE_ERROR_ACTIVE)) {
523 * located in the INTERRUPT register instead of STCMD register. 540 netdev_dbg(ndev, "Error, entered active state\n");
524 */ 541 work_done += ifi_canfd_handle_state_change(ndev,
525 isr = readl(priv->base + IFI_CANFD_INTERRUPT); 542 CAN_STATE_ERROR_ACTIVE);
526 if ((isr & IFI_CANFD_INTERRUPT_ERROR_WARNING) && 543 }
544
545 if ((stcmd & IFI_CANFD_STCMD_ERROR_WARNING) &&
527 (priv->can.state != CAN_STATE_ERROR_WARNING)) { 546 (priv->can.state != CAN_STATE_ERROR_WARNING)) {
528 /* Clear the interrupt */
529 writel(IFI_CANFD_INTERRUPT_ERROR_WARNING,
530 priv->base + IFI_CANFD_INTERRUPT);
531 netdev_dbg(ndev, "Error, entered warning state\n"); 547 netdev_dbg(ndev, "Error, entered warning state\n");
532 work_done += ifi_canfd_handle_state_change(ndev, 548 work_done += ifi_canfd_handle_state_change(ndev,
533 CAN_STATE_ERROR_WARNING); 549 CAN_STATE_ERROR_WARNING);
@@ -554,18 +570,11 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota)
554{ 570{
555 struct net_device *ndev = napi->dev; 571 struct net_device *ndev = napi->dev;
556 struct ifi_canfd_priv *priv = netdev_priv(ndev); 572 struct ifi_canfd_priv *priv = netdev_priv(ndev);
557 const u32 stcmd_state_mask = IFI_CANFD_STCMD_ERROR_PASSIVE |
558 IFI_CANFD_STCMD_BUSOFF;
559 int work_done = 0;
560
561 u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
562 u32 rxstcmd = readl(priv->base + IFI_CANFD_RXSTCMD); 573 u32 rxstcmd = readl(priv->base + IFI_CANFD_RXSTCMD);
563 u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR); 574 int work_done = 0;
564 575
565 /* Handle bus state changes */ 576 /* Handle bus state changes */
566 if ((stcmd & stcmd_state_mask) || 577 work_done += ifi_canfd_handle_state_errors(ndev);
567 ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) == 0))
568 work_done += ifi_canfd_handle_state_errors(ndev, stcmd);
569 578
570 /* Handle lost messages on RX */ 579 /* Handle lost messages on RX */
571 if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW) 580 if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW)
@@ -573,7 +582,7 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota)
573 582
574 /* Handle lec errors on the bus */ 583 /* Handle lec errors on the bus */
575 if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) 584 if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
576 work_done += ifi_canfd_handle_lec_err(ndev, errctr); 585 work_done += ifi_canfd_handle_lec_err(ndev);
577 586
578 /* Handle normal messages on RX */ 587 /* Handle normal messages on RX */
579 if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY)) 588 if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY))
@@ -594,12 +603,13 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
594 struct net_device_stats *stats = &ndev->stats; 603 struct net_device_stats *stats = &ndev->stats;
595 const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY | 604 const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
596 IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER | 605 IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER |
606 IFI_CANFD_INTERRUPT_ERROR_COUNTER |
607 IFI_CANFD_INTERRUPT_ERROR_STATE_CHG |
597 IFI_CANFD_INTERRUPT_ERROR_WARNING | 608 IFI_CANFD_INTERRUPT_ERROR_WARNING |
598 IFI_CANFD_INTERRUPT_ERROR_COUNTER; 609 IFI_CANFD_INTERRUPT_ERROR_BUSOFF;
599 const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY | 610 const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
600 IFI_CANFD_INTERRUPT_TXFIFO_REMOVE; 611 IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
601 const u32 clr_irq_mask = ~((u32)(IFI_CANFD_INTERRUPT_SET_IRQ | 612 const u32 clr_irq_mask = ~((u32)IFI_CANFD_INTERRUPT_SET_IRQ);
602 IFI_CANFD_INTERRUPT_ERROR_WARNING));
603 u32 isr; 613 u32 isr;
604 614
605 isr = readl(priv->base + IFI_CANFD_INTERRUPT); 615 isr = readl(priv->base + IFI_CANFD_INTERRUPT);