can: fix sja1000 pre_irq/post_irq handling
PATCH v2 1/1 can: fix sja1000 pre_irq/post_irq handling
The SJA1000 driver provides optional function pointers to handle specific hardware setups at interrupt time.
This patch fixes the issue that the sja1000_interrupt() function may have returned IRQ_NONE without processing the post_irq function. Additionally an introduced return value from the pre_irq function is checked to skip the entire interrupt handling on pre_irq function errors.
Reported-by Wolfgang Grandegger <[email protected]>
Signed-off-by Oliver Hartkopp <[email protected]>
---
v2: move irq processing counter 'n' to the end of the while statement to return correct IRQ_[NONE|HANDLED] values at error conditions.
drivers/net/can/sja1000/sja1000.c +9 -8
@@ -494,20 +494,20 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)uint8_t isrc, status;int n =0 ; +if (priv->pre_irq && priv->pre_irq (priv)) + goto out; +/* Shared interrupts and IRQ off? */ if (priv->read_reg (priv,SJA1000_IER ) ==IRQ_OFF ) -return IRQ_NONE ; - -if (priv->pre_irq) - priv->pre_irq (priv); + goto out;while ((isrc = priv->read_reg (priv,SJA1000_IR )) && (n <SJA1000_MAX_IRQ )) { - n++; + status = priv->read_reg (priv,SJA1000_SR );/* check for absent controller due to hw unplug */ if (status ==0xFF &&sja1000_is_absent (priv)) -return IRQ_NONE ; + goto out;if (isrc &IRQ_WUI )netdev_warn (dev,"wakeup interrupt\n" );
@@ -535,7 +535,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) status = priv->read_reg (priv,SJA1000_SR );/* check for absent controller */ if (status ==0xFF &&sja1000_is_absent (priv)) -return IRQ_NONE ; + goto out; } }if (isrc & (IRQ_DOI |IRQ_EI |IRQ_BEI |IRQ_EPI |IRQ_ALI )) {
@@ -543,8 +543,9 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)if (sja1000_err (dev, isrc, status))break ; } + n++; } - +out:if (priv->post_irq) priv->post_irq (priv);
drivers/net/can/sja1000/sja1000.h +1 -1
@@ -157,7 +157,7 @@ struct sja1000_priv {/* the lower-layer is responsible for appropriate locking */ u8 (*read_reg) (const struct sja1000_priv *priv,int reg);void (*write_reg) (const struct sja1000_priv *priv,int reg,u8 val); -void (*pre_irq) (const struct sja1000_priv *priv); +int (*pre_irq) (const struct sja1000_priv *priv);void (*post_irq) (const struct sja1000_priv *priv);void *priv;/* for board-specific data */