Commit e35d46ad authored by Marc Kleine-Budde's avatar Marc Kleine-Budde

can: c_can: don't call pm_runtime_get_sync() from interrupt context

The c_can driver contians a callpath (c_can_poll -> c_can_state_change ->
c_can_get_berr_counter) which may call pm_runtime_get_sync() from the IRQ
handler, which is not allowed and results in "BUG: scheduling while atomic".

This problem is fixed by introducing __c_can_get_berr_counter, which will not
call pm_runtime_get_sync().
Reported-by: default avatarAndrew Glen <AGlen@bepmarine.com>
Tested-by: default avatarAndrew Glen <AGlen@bepmarine.com>
Signed-off-by: default avatarAndrew Glen <AGlen@bepmarine.com>
Cc: linux-stable <stable@vger.kernel.org>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 2fea6cd3
...@@ -712,22 +712,31 @@ static int c_can_set_mode(struct net_device *dev, enum can_mode mode) ...@@ -712,22 +712,31 @@ static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
return 0; return 0;
} }
static int c_can_get_berr_counter(const struct net_device *dev, static int __c_can_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec) struct can_berr_counter *bec)
{ {
unsigned int reg_err_counter; unsigned int reg_err_counter;
struct c_can_priv *priv = netdev_priv(dev); struct c_can_priv *priv = netdev_priv(dev);
c_can_pm_runtime_get_sync(priv);
reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG); reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >> bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
ERR_CNT_REC_SHIFT; ERR_CNT_REC_SHIFT;
bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK; bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK;
return 0;
}
static int c_can_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct c_can_priv *priv = netdev_priv(dev);
int err;
c_can_pm_runtime_get_sync(priv);
err = __c_can_get_berr_counter(dev, bec);
c_can_pm_runtime_put_sync(priv); c_can_pm_runtime_put_sync(priv);
return 0; return err;
} }
/* /*
...@@ -872,7 +881,7 @@ static int c_can_handle_state_change(struct net_device *dev, ...@@ -872,7 +881,7 @@ static int c_can_handle_state_change(struct net_device *dev,
if (unlikely(!skb)) if (unlikely(!skb))
return 0; return 0;
c_can_get_berr_counter(dev, &bec); __c_can_get_berr_counter(dev, &bec);
reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG); reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >> rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
ERR_CNT_RP_SHIFT; ERR_CNT_RP_SHIFT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment