Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Marek Vasut and committed by
Marc Kleine-Budde
880dd464 591d65d5

+37 -27
+37 -27
drivers/net/can/ifi_canfd/ifi_canfd.c
··· 30 30 #define IFI_CANFD_STCMD_ERROR_ACTIVE BIT(2) 31 31 #define IFI_CANFD_STCMD_ERROR_PASSIVE BIT(3) 32 32 #define IFI_CANFD_STCMD_BUSOFF BIT(4) 33 + #define IFI_CANFD_STCMD_ERROR_WARNING BIT(5) 33 34 #define IFI_CANFD_STCMD_BUSMONITOR BIT(16) 34 35 #define IFI_CANFD_STCMD_LOOPBACK BIT(18) 35 36 #define IFI_CANFD_STCMD_DISABLE_CANFD BIT(24) ··· 53 52 #define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13) 54 53 55 54 #define IFI_CANFD_INTERRUPT 0xc 55 + #define IFI_CANFD_INTERRUPT_ERROR_BUSOFF BIT(0) 56 56 #define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1) 57 + #define IFI_CANFD_INTERRUPT_ERROR_STATE_CHG BIT(2) 58 + #define IFI_CANFD_INTERRUPT_ERROR_REC_TEC_INC BIT(3) 57 59 #define IFI_CANFD_INTERRUPT_ERROR_COUNTER BIT(10) 58 60 #define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16) 59 61 #define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22) ··· 65 61 #define IFI_CANFD_INTERRUPT_SET_IRQ ((u32)BIT(31)) 66 62 67 63 #define IFI_CANFD_IRQMASK 0x10 64 + #define IFI_CANFD_IRQMASK_ERROR_BUSOFF BIT(0) 65 + #define IFI_CANFD_IRQMASK_ERROR_WARNING BIT(1) 66 + #define IFI_CANFD_IRQMASK_ERROR_STATE_CHG BIT(2) 67 + #define IFI_CANFD_IRQMASK_ERROR_REC_TEC_INC BIT(3) 68 68 #define IFI_CANFD_IRQMASK_SET_ERR BIT(7) 69 69 #define IFI_CANFD_IRQMASK_SET_TS BIT(15) 70 70 #define IFI_CANFD_IRQMASK_TXFIFO_EMPTY BIT(16) ··· 230 222 231 223 if (enable) { 232 224 enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY | 233 - IFI_CANFD_IRQMASK_RXFIFO_NEMPTY; 225 + IFI_CANFD_IRQMASK_RXFIFO_NEMPTY | 226 + IFI_CANFD_IRQMASK_ERROR_STATE_CHG | 227 + IFI_CANFD_IRQMASK_ERROR_WARNING | 228 + IFI_CANFD_IRQMASK_ERROR_BUSOFF; 234 229 if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) 235 230 enirq |= IFI_CANFD_INTERRUPT_ERROR_COUNTER; 236 231 } ··· 374 363 return 1; 375 364 } 376 365 377 - static int ifi_canfd_handle_lec_err(struct net_device *ndev, const u32 errctr) 366 + static int ifi_canfd_handle_lec_err(struct net_device *ndev) 378 367 { 379 368 struct ifi_canfd_priv *priv = netdev_priv(ndev); 380 369 struct net_device_stats *stats = &ndev->stats; 381 370 struct can_frame *cf; 382 371 struct sk_buff *skb; 372 + u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR); 383 373 const u32 errmask = IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST | 384 374 IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST | 385 375 IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST | ··· 463 451 464 452 switch (new_state) { 465 453 case CAN_STATE_ERROR_ACTIVE: 454 + /* error active state */ 455 + priv->can.can_stats.error_warning++; 456 + priv->can.state = CAN_STATE_ERROR_ACTIVE; 457 + break; 458 + case CAN_STATE_ERROR_WARNING: 466 459 /* error warning state */ 467 460 priv->can.can_stats.error_warning++; 468 461 priv->can.state = CAN_STATE_ERROR_WARNING; ··· 496 479 ifi_canfd_get_berr_counter(ndev, &bec); 497 480 498 481 switch (new_state) { 499 - case CAN_STATE_ERROR_ACTIVE: 482 + case CAN_STATE_ERROR_WARNING: 500 483 /* error warning state */ 501 484 cf->can_id |= CAN_ERR_CRTL; 502 485 cf->data[1] = (bec.txerr > bec.rxerr) ? ··· 529 512 return 1; 530 513 } 531 514 532 - static int ifi_canfd_handle_state_errors(struct net_device *ndev, u32 stcmd) 515 + static int ifi_canfd_handle_state_errors(struct net_device *ndev) 533 516 { 534 517 struct ifi_canfd_priv *priv = netdev_priv(ndev); 518 + u32 stcmd = readl(priv->base + IFI_CANFD_STCMD); 535 519 int work_done = 0; 536 - u32 isr; 537 520 538 - /* 539 - * The ErrWarn condition is a little special, since the bit is 540 - * located in the INTERRUPT register instead of STCMD register. 541 - */ 542 - isr = readl(priv->base + IFI_CANFD_INTERRUPT); 543 - if ((isr & IFI_CANFD_INTERRUPT_ERROR_WARNING) && 521 + if ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) && 522 + (priv->can.state != CAN_STATE_ERROR_ACTIVE)) { 523 + netdev_dbg(ndev, "Error, entered active state\n"); 524 + work_done += ifi_canfd_handle_state_change(ndev, 525 + CAN_STATE_ERROR_ACTIVE); 526 + } 527 + 528 + if ((stcmd & IFI_CANFD_STCMD_ERROR_WARNING) && 544 529 (priv->can.state != CAN_STATE_ERROR_WARNING)) { 545 - /* Clear the interrupt */ 546 - writel(IFI_CANFD_INTERRUPT_ERROR_WARNING, 547 - priv->base + IFI_CANFD_INTERRUPT); 548 530 netdev_dbg(ndev, "Error, entered warning state\n"); 549 531 work_done += ifi_canfd_handle_state_change(ndev, 550 532 CAN_STATE_ERROR_WARNING); ··· 570 554 { 571 555 struct net_device *ndev = napi->dev; 572 556 struct ifi_canfd_priv *priv = netdev_priv(ndev); 573 - const u32 stcmd_state_mask = IFI_CANFD_STCMD_ERROR_PASSIVE | 574 - IFI_CANFD_STCMD_BUSOFF; 557 + u32 rxstcmd = readl(priv->base + IFI_CANFD_RXSTCMD); 575 558 int work_done = 0; 576 559 577 - u32 stcmd = readl(priv->base + IFI_CANFD_STCMD); 578 - u32 rxstcmd = readl(priv->base + IFI_CANFD_RXSTCMD); 579 - u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR); 580 - 581 560 /* Handle bus state changes */ 582 - if ((stcmd & stcmd_state_mask) || 583 - ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) == 0)) 584 - work_done += ifi_canfd_handle_state_errors(ndev, stcmd); 561 + work_done += ifi_canfd_handle_state_errors(ndev); 585 562 586 563 /* Handle lost messages on RX */ 587 564 if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW) ··· 582 573 583 574 /* Handle lec errors on the bus */ 584 575 if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) 585 - work_done += ifi_canfd_handle_lec_err(ndev, errctr); 576 + work_done += ifi_canfd_handle_lec_err(ndev); 586 577 587 578 /* Handle normal messages on RX */ 588 579 if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY)) ··· 603 594 struct net_device_stats *stats = &ndev->stats; 604 595 const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY | 605 596 IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER | 597 + IFI_CANFD_INTERRUPT_ERROR_COUNTER | 598 + IFI_CANFD_INTERRUPT_ERROR_STATE_CHG | 606 599 IFI_CANFD_INTERRUPT_ERROR_WARNING | 607 - IFI_CANFD_INTERRUPT_ERROR_COUNTER; 600 + IFI_CANFD_INTERRUPT_ERROR_BUSOFF; 608 601 const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY | 609 602 IFI_CANFD_INTERRUPT_TXFIFO_REMOVE; 610 - const u32 clr_irq_mask = ~((u32)(IFI_CANFD_INTERRUPT_SET_IRQ | 611 - IFI_CANFD_INTERRUPT_ERROR_WARNING)); 603 + const u32 clr_irq_mask = ~((u32)IFI_CANFD_INTERRUPT_SET_IRQ); 612 604 u32 isr; 613 605 614 606 isr = readl(priv->base + IFI_CANFD_INTERRUPT);