mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-14 08:36:12 -04:00
can: flexcan: flexcan_chip_start(): fix erroneous flexcan_transceiver_enable() during bus-off recovery
[ Upstream commit cd9f13c59461351d7a5fd07924264fb49b287359 ]
If the CAN controller goes into bus off, the do_set_mode() callback with
CAN_MODE_START can be used to recover the controller, which then calls
flexcan_chip_start(). If configured, this is done automatically by the
framework or manually by the user.
In flexcan_chip_start() there is an explicit call to
flexcan_transceiver_enable(), which does a regulator_enable() on the
transceiver regulator. This results in a net usage counter increase, as there
is no corresponding flexcan_transceiver_disable() in the bus off code path.
This further leads to the transceiver stuck enabled, even if the CAN interface
is shut down.
To fix this problem the
flexcan_transceiver_enable()/flexcan_transceiver_disable() are moved out of
flexcan_chip_start()/flexcan_chip_stop() into flexcan_open()/flexcan_close().
Fixes: e955cead03 ("CAN: Add Flexcan CAN controller driver")
Link: https://lore.kernel.org/r/20201118150148.2664024-1-mkl@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
58f1657c3a
commit
a3c94201e0
1 changed files with 9 additions and 9 deletions
|
|
@ -1202,14 +1202,10 @@ static int flexcan_chip_start(struct net_device *dev)
|
|||
priv->write(reg_mecr, ®s->mecr);
|
||||
}
|
||||
|
||||
err = flexcan_transceiver_enable(priv);
|
||||
if (err)
|
||||
goto out_chip_disable;
|
||||
|
||||
/* synchronize with the can bus */
|
||||
err = flexcan_chip_unfreeze(priv);
|
||||
if (err)
|
||||
goto out_transceiver_disable;
|
||||
goto out_chip_disable;
|
||||
|
||||
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
|
||||
|
|
@ -1226,8 +1222,6 @@ static int flexcan_chip_start(struct net_device *dev)
|
|||
|
||||
return 0;
|
||||
|
||||
out_transceiver_disable:
|
||||
flexcan_transceiver_disable(priv);
|
||||
out_chip_disable:
|
||||
flexcan_chip_disable(priv);
|
||||
return err;
|
||||
|
|
@ -1257,7 +1251,6 @@ static int __flexcan_chip_stop(struct net_device *dev, bool disable_on_error)
|
|||
priv->write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
|
||||
®s->ctrl);
|
||||
|
||||
flexcan_transceiver_disable(priv);
|
||||
priv->can.state = CAN_STATE_STOPPED;
|
||||
|
||||
return 0;
|
||||
|
|
@ -1293,10 +1286,14 @@ static int flexcan_open(struct net_device *dev)
|
|||
if (err)
|
||||
goto out_runtime_put;
|
||||
|
||||
err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
|
||||
err = flexcan_transceiver_enable(priv);
|
||||
if (err)
|
||||
goto out_close;
|
||||
|
||||
err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
|
||||
if (err)
|
||||
goto out_transceiver_disable;
|
||||
|
||||
priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
|
||||
priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) +
|
||||
(sizeof(priv->regs->mb[1]) / priv->mb_size);
|
||||
|
|
@ -1352,6 +1349,8 @@ static int flexcan_open(struct net_device *dev)
|
|||
can_rx_offload_del(&priv->offload);
|
||||
out_free_irq:
|
||||
free_irq(dev->irq, dev);
|
||||
out_transceiver_disable:
|
||||
flexcan_transceiver_disable(priv);
|
||||
out_close:
|
||||
close_candev(dev);
|
||||
out_runtime_put:
|
||||
|
|
@ -1370,6 +1369,7 @@ static int flexcan_close(struct net_device *dev)
|
|||
|
||||
can_rx_offload_del(&priv->offload);
|
||||
free_irq(dev->irq, dev);
|
||||
flexcan_transceiver_disable(priv);
|
||||
|
||||
close_candev(dev);
|
||||
pm_runtime_put(priv->dev);
|
||||
|
|
|
|||
Loading…
Reference in a new issue