| From: Anssi Hannula <anssi.hannula@bitwise.fi> |
| Date: Mon, 26 Feb 2018 14:39:59 +0200 |
| Subject: can: xilinx_can: fix incorrect clear of non-processed interrupts |
| |
| commit 2f4f0f338cf453bfcdbcf089e177c16f35f023c8 upstream. |
| |
| xcan_interrupt() clears ERROR|RXOFLV|BSOFF|ARBLST interrupts if any of |
| them is asserted. This does not take into account that some of them |
| could have been asserted between interrupt status read and interrupt |
| clear, therefore clearing them without handling them. |
| |
| Fix the code to only clear those interrupts that it knows are asserted |
| and therefore going to be processed in xcan_err_interrupt(). |
| |
| Fixes: b1201e44f50b ("can: xilinx CAN controller support") |
| Signed-off-by: Anssi Hannula <anssi.hannula@bitwise.fi> |
| Cc: Michal Simek <michal.simek@xilinx.com> |
| Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/net/can/xilinx_can.c | 10 +++++----- |
| 1 file changed, 5 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/net/can/xilinx_can.c |
| +++ b/drivers/net/can/xilinx_can.c |
| @@ -939,6 +939,7 @@ static irqreturn_t xcan_interrupt(int ir |
| struct net_device *ndev = (struct net_device *)dev_id; |
| struct xcan_priv *priv = netdev_priv(ndev); |
| u32 isr, ier; |
| + u32 isr_errors; |
| |
| /* Get the interrupt status from Xilinx CAN */ |
| isr = priv->read_reg(priv, XCAN_ISR_OFFSET); |
| @@ -957,11 +958,10 @@ static irqreturn_t xcan_interrupt(int ir |
| xcan_tx_interrupt(ndev, isr); |
| |
| /* Check for the type of error interrupt and Processing it */ |
| - if (isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | |
| - XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK)) { |
| - priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_ERROR_MASK | |
| - XCAN_IXR_RXOFLW_MASK | XCAN_IXR_BSOFF_MASK | |
| - XCAN_IXR_ARBLST_MASK)); |
| + isr_errors = isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | |
| + XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK); |
| + if (isr_errors) { |
| + priv->write_reg(priv, XCAN_ICR_OFFSET, isr_errors); |
| xcan_err_interrupt(ndev, isr); |
| } |
| |