Re: [PATCH v2] can: tcan4x5x: put tcan into sleep when removing driver

Sean Nyekjaer <[email protected]> Mon, 03 Aug 2026 11:16:20 +0000
Newsgroups org.kernel.vger.linux-can,dev.linux.lists.sashiko-reviews
Message-ID <q3LwALtEs55OqWLslOGbypHDnnUEkEDZlOYrjnxD7LQhiWSkFOOr9zw5_VahYRMVSjShxnODVlL8k34_HGh3vunnQHHPkT28LApT39NeOvo=@geanix.com>



On Monday, 3 August 2026 at 13:05, [email protected] <sashiko-bot@kern=
el.org> wrote:

> Thank you for your contribution! Sashiko AI review found 3 potential issu=
e(s) to consider:
>=20
> New issues:
> - [High] The function signature of `tcan4x5x_power_enable()` was changed =
to accept a `struct tcan4x5x_priv *` instead of `struct regulator *`, but t=
he call site in `tcan4x5x_can_remove()` was not updated. This causes a seve=
re type mismatch leading to a wild pointer dereference.

Will fix for v3 :)

> - [Medium] The transceiver is not explicitly put into sleep mode via SPI =
during driver removal if it is powered by a regulator, undermining the patc=
h's intended power savings.

Intended, as the regulator will power it off.

>=20
> Pre-existing issues:
> - [High] The polling hrtimer is not synchronously cancelled during device=
 teardown, allowing its callback to execute concurrently on freed memory.
> --
>=20
> --- Patch [1]: [PATCH v2] can: tcan4x5x: put tcan into sleep when removin=
g driver ---
> commit b49d2b844c12ed05e9ff4437bc458dbace9b23e8
> Author: Sean Nyekjaer <[email protected]>
>=20
> can: tcan4x5x: put tcan into sleep when removing driver
>=20
> Put the tcan4x5x transceiver into sleep mode when the driver is
> removed, instead of leaving it in its current operating mode.
> This reduces power consumption(3mA@12V) once the driver is
> no longer bound to the device.
>=20
> > diff --git a/drivers/net/can/m_can/tcan4x5x-core.c b/drivers/net/can/m_=
can/tcan4x5x-core.c
> > index 31cc9d0abd453..67902b8b0fab4 100644
> > --- a/drivers/net/can/m_can/tcan4x5x-core.c
> > +++ b/drivers/net/can/m_can/tcan4x5x-core.c
> > @@ -211,15 +211,21 @@ static int tcan4x5x_write_fifo(struct m_can_class=
dev *cdev,
> >  =09return regmap_bulk_write(priv->regmap, TCAN4X5X_MRAM_START + addr_o=
ffset, val, val_count);
> >  }
> >
> > -static int tcan4x5x_power_enable(struct regulator *reg, int enable)
> > +static int tcan4x5x_power_enable(struct tcan4x5x_priv *priv, int enabl=
e)
> >  {
>=20
> [Severity: High]
> Did this signature change miss updating the call site in
> tcan4x5x_can_remove()?
>=20
> When the driver is unloaded, tcan4x5x_can_remove() still passes priv->pow=
er
> which is a struct regulator pointer:
>=20
> drivers/net/can/m_can/tcan4x5x-core.c:tcan4x5x_can_remove() {
> =09...
> =09tcan4x5x_power_enable(priv->power, 0);
> =09...
> }
>=20
> Could this cause a panic when tcan4x5x_power_enable() tries to dereferenc=
e
> the regulator pointer as a struct tcan4x5x_priv?
>=20
> > -=09if (IS_ERR_OR_NULL(reg))
> > +=09if (IS_ERR_OR_NULL(priv->power)) {
> > +=09=09if (priv->reset_gpio && !enable)
> > +=09=09=09return regmap_update_bits(priv->regmap, TCAN4X5X_CONFIG,
> > +=09=09=09=09=09=09  TCAN4X5X_MODE_SEL_MASK,
> > +=09=09=09=09=09=09  TCAN4X5X_MODE_SLEEP);
> > +
> >  =09=09return 0;
> > +=09}
>=20
> [Severity: Medium]
> If the device tree specifies a regulator for the transceiver, will this
> skip putting the device into sleep mode?
>=20
> Since the sleep configuration is gated inside the check for
> IS_ERR_OR_NULL(priv->power), if a regulator is present, the function skip=
s
> this block and just disables the regulator.
>=20
> If this regulator is shared with other components on the board, does it l=
eave
> the transceiver powered and in its previous state instead of entering sle=
ep
> mode?
>=20
> [ ... ]
>=20
> [Severity: High]
> This isn't a bug introduced by this patch, but is there a race condition
> with the polling hrtimer during device teardown?
>=20
> During device teardown, m_can_disable_all_interrupts() uses a non-blockin=
g
> cancel:
>=20
> drivers/net/can/m_can/m_can.c:m_can_disable_all_interrupts() {
> =09...
> =09if (!cdev->net->irq) {
> =09=09netdev_dbg(cdev->net, "Stop hrtimer\n");
> =09=09hrtimer_try_to_cancel(&cdev->hrtimer);
> =09}
> }
>=20
> If the timer callback m_can_polling_timer() is concurrently running on an=
other
> CPU, hrtimer_try_to_cancel() will fail.
>=20
> If the callback reads the state before it is updated to CAN_STATE_STOPPED=
,
> will it reschedule itself and eventually execute on freed memory?
>=20
> drivers/net/can/m_can/m_can.c:m_can_polling_timer() {
> =09...
> =09hrtimer_forward_now(timer, ms_to_ktime(HRTIMER_POLL_INTERVAL_MS));
>=20
> =09return HRTIMER_RESTART;
> }
>=20
> --
> Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260803101927.17=
[email protected]?part=3D1
>=20
>