aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/can
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2016-05-07 18:34:16 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2016-05-09 05:07:28 -0400
commit5bbd655a8bd000579d135ddf30660f759db89996 (patch)
treee127e8b838beab538fc7df6186d01485a11e439c /drivers/net/can
parent1acd80fb982728b8bf467184d5ec4c5a77a5601b (diff)
can: ifi: Add more detailed error reporting
The updated specification for the IFI CANFD core contains description of more detailed error reporting capability of the core. Implement support for this detailed error reporting. Signed-off-by: Marek Vasut <marex@denx.de> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers/net/can')
-rw-r--r--drivers/net/can/ifi_canfd/ifi_canfd.c113
1 files changed, 107 insertions, 6 deletions
diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
index ba6cd43e1bc6..2d1d22eec750 100644
--- a/drivers/net/can/ifi_canfd/ifi_canfd.c
+++ b/drivers/net/can/ifi_canfd/ifi_canfd.c
@@ -52,7 +52,8 @@
52#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13) 52#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13)
53 53
54#define IFI_CANFD_INTERRUPT 0xc 54#define IFI_CANFD_INTERRUPT 0xc
55#define IFI_CANFD_INTERRUPT_ERROR_WARNING ((u32)BIT(1)) 55#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1)
56#define IFI_CANFD_INTERRUPT_ERROR_COUNTER BIT(10)
56#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16) 57#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16)
57#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22) 58#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22)
58#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24) 59#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24)
@@ -103,7 +104,26 @@
103 104
104#define IFI_CANFD_RES1 0x40 105#define IFI_CANFD_RES1 0x40
105 106
106#define IFI_CANFD_RES2 0x44 107#define IFI_CANFD_ERROR_CTR 0x44
108#define IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC 0x21302899
109#define IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST BIT(0)
110#define IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST BIT(1)
111#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST BIT(2)
112#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST BIT(3)
113#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST BIT(4)
114#define IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST BIT(5)
115#define IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST BIT(6)
116#define IFI_CANFD_ERROR_CTR_OVERLOAD_ALL BIT(8)
117#define IFI_CANFD_ERROR_CTR_ACK_ERROR_ALL BIT(9)
118#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_ALL BIT(10)
119#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_ALL BIT(11)
120#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_ALL BIT(12)
121#define IFI_CANFD_ERROR_CTR_CRC_ERROR_ALL BIT(13)
122#define IFI_CANFD_ERROR_CTR_FORM_ERROR_ALL BIT(14)
123#define IFI_CANFD_ERROR_CTR_BITPOSITION_OFFSET 16
124#define IFI_CANFD_ERROR_CTR_BITPOSITION_MASK 0xff
125#define IFI_CANFD_ERROR_CTR_ER_RESET BIT(30)
126#define IFI_CANFD_ERROR_CTR_ER_ENABLE ((u32)BIT(31))
107 127
108#define IFI_CANFD_PAR 0x48 128#define IFI_CANFD_PAR 0x48
109 129
@@ -197,6 +217,8 @@ static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable)
197 if (enable) { 217 if (enable) {
198 enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY | 218 enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY |
199 IFI_CANFD_IRQMASK_RXFIFO_NEMPTY; 219 IFI_CANFD_IRQMASK_RXFIFO_NEMPTY;
220 if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
221 enirq |= IFI_CANFD_INTERRUPT_ERROR_COUNTER;
200 } 222 }
201 223
202 writel(IFI_CANFD_IRQMASK_SET_ERR | 224 writel(IFI_CANFD_IRQMASK_SET_ERR |
@@ -335,6 +357,68 @@ static int ifi_canfd_handle_lost_msg(struct net_device *ndev)
335 return 1; 357 return 1;
336} 358}
337 359
360static int ifi_canfd_handle_lec_err(struct net_device *ndev, const u32 errctr)
361{
362 struct ifi_canfd_priv *priv = netdev_priv(ndev);
363 struct net_device_stats *stats = &ndev->stats;
364 struct can_frame *cf;
365 struct sk_buff *skb;
366 const u32 errmask = IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST |
367 IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST |
368 IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST |
369 IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST |
370 IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST |
371 IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST |
372 IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST;
373
374 if (!(errctr & errmask)) /* No error happened. */
375 return 0;
376
377 priv->can.can_stats.bus_error++;
378 stats->rx_errors++;
379
380 /* Propagate the error condition to the CAN stack. */
381 skb = alloc_can_err_skb(ndev, &cf);
382 if (unlikely(!skb))
383 return 0;
384
385 /* Read the error counter register and check for new errors. */
386 cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
387
388 if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST)
389 cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
390
391 if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST)
392 cf->data[3] = CAN_ERR_PROT_LOC_ACK;
393
394 if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST)
395 cf->data[2] |= CAN_ERR_PROT_BIT0;
396
397 if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST)
398 cf->data[2] |= CAN_ERR_PROT_BIT1;
399
400 if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST)
401 cf->data[2] |= CAN_ERR_PROT_STUFF;
402
403 if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST)
404 cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
405
406 if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST)
407 cf->data[2] |= CAN_ERR_PROT_FORM;
408
409 /* Reset the error counter, ack the IRQ and re-enable the counter. */
410 writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR);
411 writel(IFI_CANFD_INTERRUPT_ERROR_COUNTER,
412 priv->base + IFI_CANFD_INTERRUPT);
413 writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR);
414
415 stats->rx_packets++;
416 stats->rx_bytes += cf->can_dlc;
417 netif_receive_skb(skb);
418
419 return 1;
420}
421
338static int ifi_canfd_get_berr_counter(const struct net_device *ndev, 422static int ifi_canfd_get_berr_counter(const struct net_device *ndev,
339 struct can_berr_counter *bec) 423 struct can_berr_counter *bec)
340{ 424{
@@ -470,6 +554,7 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota)
470 554
471 u32 stcmd = readl(priv->base + IFI_CANFD_STCMD); 555 u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
472 u32 rxstcmd = readl(priv->base + IFI_CANFD_STCMD); 556 u32 rxstcmd = readl(priv->base + IFI_CANFD_STCMD);
557 u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR);
473 558
474 /* Handle bus state changes */ 559 /* Handle bus state changes */
475 if ((stcmd & stcmd_state_mask) || 560 if ((stcmd & stcmd_state_mask) ||
@@ -480,6 +565,10 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota)
480 if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW) 565 if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW)
481 work_done += ifi_canfd_handle_lost_msg(ndev); 566 work_done += ifi_canfd_handle_lost_msg(ndev);
482 567
568 /* Handle lec errors on the bus */
569 if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
570 work_done += ifi_canfd_handle_lec_err(ndev, errctr);
571
483 /* Handle normal messages on RX */ 572 /* Handle normal messages on RX */
484 if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY)) 573 if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY))
485 work_done += ifi_canfd_do_rx_poll(ndev, quota - work_done); 574 work_done += ifi_canfd_do_rx_poll(ndev, quota - work_done);
@@ -499,11 +588,12 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
499 struct net_device_stats *stats = &ndev->stats; 588 struct net_device_stats *stats = &ndev->stats;
500 const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY | 589 const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
501 IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER | 590 IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER |
502 IFI_CANFD_INTERRUPT_ERROR_WARNING; 591 IFI_CANFD_INTERRUPT_ERROR_WARNING |
592 IFI_CANFD_INTERRUPT_ERROR_COUNTER;
503 const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY | 593 const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
504 IFI_CANFD_INTERRUPT_TXFIFO_REMOVE; 594 IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
505 const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ | 595 const u32 clr_irq_mask = ~((u32)(IFI_CANFD_INTERRUPT_SET_IRQ |
506 IFI_CANFD_INTERRUPT_ERROR_WARNING); 596 IFI_CANFD_INTERRUPT_ERROR_WARNING));
507 u32 isr; 597 u32 isr;
508 598
509 isr = readl(priv->base + IFI_CANFD_INTERRUPT); 599 isr = readl(priv->base + IFI_CANFD_INTERRUPT);
@@ -657,6 +747,12 @@ static void ifi_canfd_start(struct net_device *ndev)
657 747
658 ifi_canfd_irq_enable(ndev, 1); 748 ifi_canfd_irq_enable(ndev, 1);
659 749
750 /* Unlock, reset and enable the error counter. */
751 writel(IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC,
752 priv->base + IFI_CANFD_ERROR_CTR);
753 writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR);
754 writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR);
755
660 /* Enable controller */ 756 /* Enable controller */
661 writel(stcmd, priv->base + IFI_CANFD_STCMD); 757 writel(stcmd, priv->base + IFI_CANFD_STCMD);
662} 758}
@@ -665,6 +761,10 @@ static void ifi_canfd_stop(struct net_device *ndev)
665{ 761{
666 struct ifi_canfd_priv *priv = netdev_priv(ndev); 762 struct ifi_canfd_priv *priv = netdev_priv(ndev);
667 763
764 /* Reset and disable the error counter. */
765 writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR);
766 writel(0, priv->base + IFI_CANFD_ERROR_CTR);
767
668 /* Reset the IP */ 768 /* Reset the IP */
669 writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD); 769 writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
670 770
@@ -868,7 +968,8 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev)
868 priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | 968 priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
869 CAN_CTRLMODE_LISTENONLY | 969 CAN_CTRLMODE_LISTENONLY |
870 CAN_CTRLMODE_FD | 970 CAN_CTRLMODE_FD |
871 CAN_CTRLMODE_FD_NON_ISO; 971 CAN_CTRLMODE_FD_NON_ISO |
972 CAN_CTRLMODE_BERR_REPORTING;
872 973
873 platform_set_drvdata(pdev, ndev); 974 platform_set_drvdata(pdev, ndev);
874 SET_NETDEV_DEV(ndev, dev); 975 SET_NETDEV_DEV(ndev, dev);