As pointed out by Reuben Dowle, the TWRN_INT, RWRN_INT, BOFF_INT interrupt sources need to be cleared as well to avoid interrupt flooding, at least for the Flexcan on i.MX28 SOCs.
CC: Reuben Dowle <[email protected]> Signed-off-by: Wolfgang Grandegger <[email protected]> --- drivers/net/can/flexcan.c | 67 ++++++++++++++++----------------------------- 1 files changed, 24 insertions(+), 43 deletions(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 165a4c7..feb8e64 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -118,6 +118,9 @@ (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | FLEXCAN_ESR_BOFF_INT) #define FLEXCAN_ESR_ERR_ALL \ (FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE) +#define FLEXCAN_ESR_ALL_INT \ + (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \ + FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT) /* FLEXCAN interrupt flag register (IFLAG) bits */ #define FLEXCAN_TX_BUF_ID 8 @@ -224,13 +227,6 @@ static void flexcan_transceiver_switch(const struct flexcan_priv *priv, int on) priv->pdata->transceiver_switch(on); } -static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, - u32 reg_esr) -{ - return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && - (reg_esr & FLEXCAN_ESR_ERR_BUS); -} - static inline void flexcan_chip_enable(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->base; @@ -358,24 +354,6 @@ static void do_bus_err(struct net_device *dev, dev->stats.tx_errors++; } -static int flexcan_poll_bus_err(struct net_device *dev, u32 reg_esr) -{ - struct sk_buff *skb; - struct can_frame *cf; - - skb = alloc_can_err_skb(dev, &cf); - if (unlikely(!skb)) - return 0; - - do_bus_err(dev, cf, reg_esr); - netif_receive_skb(skb); - - dev->stats.rx_packets++; - dev->stats.rx_bytes += cf->can_dlc; - - return 1; -} - static void do_state(struct net_device *dev, struct can_frame *cf, enum can_state new_state) { @@ -442,7 +420,7 @@ static void do_state(struct net_device *dev, } } -static int flexcan_poll_state(struct net_device *dev, u32 reg_esr) +static int flexcan_poll_error_state(struct net_device *dev, u32 reg_esr) { struct flexcan_priv *priv = netdev_priv(dev); struct sk_buff *skb; @@ -462,16 +440,23 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr) else new_state = CAN_STATE_BUS_OFF; - /* state hasn't changed */ - if (likely(new_state == priv->can.state)) + /* has state changed or are there bus errros? */ + if (likely(new_state == priv->can.state && + !(reg_esr & FLEXCAN_ESR_ERR_BUS))) return 0; skb = alloc_can_err_skb(dev, &cf); if (unlikely(!skb)) return 0; - do_state(dev, cf, new_state); - priv->can.state = new_state; + if (new_state != priv->can.state) { + do_state(dev, cf, new_state); + priv->can.state = new_state; + } + + if (reg_esr & FLEXCAN_ESR_ERR_BUS) + do_bus_err(dev, cf, reg_esr); + netif_receive_skb(skb); dev->stats.rx_packets++; @@ -540,10 +525,10 @@ static int flexcan_poll(struct napi_struct *napi, int quota) * The error bits are cleared on read, * use saved value from irq handler. */ - reg_esr = flexcan_read(®s->esr) | priv->reg_esr; + reg_esr = priv->reg_esr; - /* handle state changes */ - work_done += flexcan_poll_state(dev, reg_esr); + /* handle bus error amd state changes */ + work_done += flexcan_poll_error_state(dev, reg_esr); /* handle RX-FIFO */ reg_iflag1 = flexcan_read(®s->iflag1); @@ -553,10 +538,6 @@ static int flexcan_poll(struct napi_struct *napi, int quota) reg_iflag1 = flexcan_read(®s->iflag1); } - /* report bus errors */ - if (flexcan_has_and_handle_berr(priv, reg_esr) && work_done < quota) - work_done += flexcan_poll_bus_err(dev, reg_esr); - if (work_done < quota) { napi_complete(napi); /* enable IRQs */ @@ -577,7 +558,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) reg_iflag1 = flexcan_read(®s->iflag1); reg_esr = flexcan_read(®s->esr); - flexcan_write(FLEXCAN_ESR_ERR_INT, ®s->esr); /* ACK err IRQ */ + /* ACK all bus error and state change IRQ sources */ + if (reg_esr & FLEXCAN_ESR_ALL_INT) + flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, ®s->esr); /* * schedule NAPI in case of: @@ -586,13 +569,11 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) * - bus error IRQ and bus error reporting is activated */ if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) || - (reg_esr & FLEXCAN_ESR_ERR_STATE) || - flexcan_has_and_handle_berr(priv, reg_esr)) { + (reg_esr & FLEXCAN_ESR_ALL_INT)) { /* - * The error bits are cleared on read, - * save them for later use. + * save esr at interrupt time for later use in poll function */ - priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS; + priv->reg_esr = reg_esr; flexcan_write(FLEXCAN_IFLAG_DEFAULT & ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->imask1); flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL, -- 1.7.4.1 _______________________________________________ Socketcan-users mailing list [email protected] https://lists.berlios.de/mailman/listinfo/socketcan-users
