Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+15 −6
Original line number Diff line number Diff line
@@ -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,
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;