RE: [PATCH/RFC 6/6] can: rcar_canfd: Add suspend/resume support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Geert Uytterhoeven,

Thanks for the patch.

> -----Original Message-----
> From: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
> Sent: 22 August 2025 10:51
> Subject: [PATCH/RFC 6/6] can: rcar_canfd: Add suspend/resume support
> 
> On R-Car Gen3 using PSCI, s2ram powers down the SoC.  After resume, the CAN-FD interface no longer
> works.  Trying to bring it up again fails:
> 
>     # ip link set can0 up
>     RTNETLINK answers: Connection timed out
> 
>     # dmesg
>     ...
>     channel 0 communication state failed
> 
> Fix this by populating the (currently empty) suspend and resume callbacks, to stop/start the individual
> CAN-FD channels, and (de)initialize the CAN-FD controller.
> 
> Signed-off-by: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>

Tested-by: Reviewed-by: Biju Das <biju.das.jz@xxxxxxxxxxxxxx>

With adaption to RZ/G3E for ram_clk [1]

> ---
> While this fixes CAN-FD after resume from s2ram on R-Car E3 (Ebisu-4D), it does introduce a regression
> on R-Car V4H (White Hawk): after resume from s2idle (White Hawk does not support s2ram), CAN frames
> sent by other devices are no longer received, and the other side sometimes reports a "bus-off".
> 
> However, the underlying issue is pre-existing, and can be reproduced without this patch: the CAN-FD
> controller fails in the same way after driver unbind/rebind.  So something must be missing in the
> (de)initialization sequence for the R-Car Gen4 CAN-FD register layout.
> Note that it keeps on working after ifdown/ifup, which does not reinitialize the full controller.
> ---
>  drivers/net/can/rcar/rcar_canfd.c | 53 +++++++++++++++++++++++++++++++
>  1 file changed, 53 insertions(+)
> 
> diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
> index eedce83b91414c57..6b0c563e894f74b3 100644
> --- a/drivers/net/can/rcar/rcar_canfd.c
> +++ b/drivers/net/can/rcar/rcar_canfd.c
> @@ -2236,11 +2236,64 @@ static void rcar_canfd_remove(struct platform_device *pdev)
> 
>  static int rcar_canfd_suspend(struct device *dev)  {
> +	struct rcar_canfd_global *gpriv = dev_get_drvdata(dev);
> +	int err;
> +	u32 ch;
> +
> +	for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
> +		struct rcar_canfd_channel *priv = gpriv->ch[ch];
> +		struct net_device *ndev = priv->ndev;
> +
> +		if (!netif_running(ndev))
> +			continue;
> +
> +		netif_device_detach(ndev);
> +
> +		err = rcar_canfd_close(ndev);
> +		if (err) {
> +			netdev_err(ndev, "rcar_canfd_close() failed %pe\n",
> +				   ERR_PTR(err));
> +			return err;
> +		}
> +
> +		priv->can.state = CAN_STATE_SLEEPING;
> +	}
> +
> +	/* TODO Skip if wake-up (which is not yet supported) is enabled */
> +	rcar_canfd_global_deinit(gpriv, false);
> +
>  	return 0;
>  }
> 
>  static int rcar_canfd_resume(struct device *dev)  {
> +	struct rcar_canfd_global *gpriv = dev_get_drvdata(dev);
> +	int err;
> +	u32 ch;
> +
> +	err = rcar_canfd_global_init(gpriv);
> +	if (err) {
> +		dev_err(dev, "rcar_canfd_open() failed %pe\n", ERR_PTR(err));

Typo: rcar_canfd_global_init


> +		return err;
> +	}
> +


[1] 

biju@biju:~/linux-work/linux$ git diff
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index 57ac90e57f11..cb358a4e49d0 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -468,6 +468,7 @@ struct rcar_canfd_global {
        struct platform_device *pdev;   /* Respective platform device */
        struct clk *clkp;               /* Peripheral clock */
        struct clk *can_clk;            /* fCAN clock */
+       struct clk *clk_ram;            /* Clock RAM */
        unsigned long channels_mask;    /* Enabled channels mask */
        bool extclk;                    /* CANFD or Ext clock */
        bool fdmode;                    /* CAN FD or Classical CAN only mode */
@@ -1983,10 +1984,18 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
                goto fail_reset2;
        }
 
+       /* Enable RAM clock */
+       err = clk_prepare_enable(gpriv->clk_ram);
+       if (err) {
+               dev_err(dev,
+                       "failed to enable ram clock, error %d\n", err);
+               goto fail_clk;
+       }
+
        err = rcar_canfd_reset_controller(gpriv);
        if (err) {
                dev_err(dev, "reset controller failed: %pe\n", ERR_PTR(err));
-               goto fail_clk;
+               goto fail_ram_clk;
        }
 
        /* Controller in Global reset & Channel reset mode */
@@ -2026,6 +2035,8 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
        rcar_canfd_disable_global_interrupts(gpriv);
 fail_clk:
        clk_disable_unprepare(gpriv->clkp);
+fail_ram_clk:
+       clk_disable_unprepare(gpriv->clk_ram);
 fail_reset2:
        reset_control_assert(gpriv->rstc2);
 fail_reset1:
@@ -2045,6 +2056,7 @@ static void rcar_canfd_global_deinit(struct rcar_canfd_global *gpriv, bool full)
        }
 
        clk_disable_unprepare(gpriv->clkp);
+       clk_disable_unprepare(gpriv->clk_ram);
        reset_control_assert(gpriv->rstc2);
        reset_control_assert(gpriv->rstc1);
 }
@@ -2153,10 +2165,10 @@ static int rcar_canfd_probe(struct platform_device *pdev)
                gpriv->extclk = gpriv->info->external_clk;
        }
 
-       clk_ram = devm_clk_get_optional_enabled(dev, "ram_clk");
+       gpriv->clk_ram = devm_clk_get_optional(dev, "ram_clk");
        if (IS_ERR(clk_ram))
                return dev_err_probe(dev, PTR_ERR(clk_ram),
-                                    "cannot get enabled ram clock\n");
+                                    "cannot get ram clock\n");






[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux