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: Andrew Glen <AGlen@bepmarine.com> Tested-by: Andrew Glen <AGlen@bepmarine.com> Signed-off-by: Andrew Glen <AGlen@bepmarine.com> Cc: linux-stable <stable@vger.kernel.org> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
parent
2fea6cd303
commit
e35d46adc4
@ -712,22 +712,31 @@ static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int c_can_get_berr_counter(const struct net_device *dev,
|
||||
struct can_berr_counter *bec)
|
||||
static int __c_can_get_berr_counter(const struct net_device *dev,
|
||||
struct can_berr_counter *bec)
|
||||
{
|
||||
unsigned int reg_err_counter;
|
||||
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);
|
||||
bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
|
||||
ERR_CNT_REC_SHIFT;
|
||||
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);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -872,7 +881,7 @@ static int c_can_handle_state_change(struct net_device *dev,
|
||||
if (unlikely(!skb))
|
||||
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);
|
||||
rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
|
||||
ERR_CNT_RP_SHIFT;
|
||||
|
Loading…
x
Reference in New Issue
Block a user