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,

> -----Original Message-----
> From: Biju Das
> Sent: 22 August 2025 14:40
> Subject: RE: [PATCH/RFC 6/6] can: rcar_canfd: Add suspend/resume support
> 
> Hi Geert,
> 
> 
> > -----Original Message-----
> > From: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
> > Sent: 22 August 2025 10:51
> > To: Marc Kleine-Budde <mkl@xxxxxxxxxxxxxx>; Vincent Mailhol
> > <mailhol.vincent@xxxxxxxxxx>; Biju Das <biju.das.jz@xxxxxxxxxxxxxx>
> > Cc: linux-can@xxxxxxxxxxxxxxx; linux-renesas-soc@xxxxxxxxxxxxxxx;
> > Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
> > 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>
> > ---
> > 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));
> > +		return err;
> > +	}
> > +
> > +	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;
> > +
> > +		err = rcar_canfd_open(ndev);
> > +		if (err) {
> > +			netdev_err(ndev, "rcar_canfd_open() failed %pe\n",
> > +				   ERR_PTR(err));
> > +			return err;
> > +		}
> > +
> > +		netif_device_attach(ndev);
> > +	}
> > +
> >  	return 0;
> >  }
> >

STR is now working on G3E based on BSP code with the following modifications[1]


[1]
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index adf73d6238a1..89a1bc73c1af 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -469,6 +469,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 */
@@ -2158,7 +2159,7 @@ 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_enabled(dev, "ram_clk");
        if (IS_ERR(clk_ram))
                return dev_err_probe(dev, PTR_ERR(clk_ram),
                                     "cannot get enabled ram clock\n");
@@ -2262,20 +2263,15 @@ static int rcar_canfd_suspend(struct device *dev)
                if (!netif_running(ndev))
                        continue;
 
+               netif_stop_queue(ndev);
+               rcar_canfd_stop(ndev);
                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);
+       reset_control_assert(gpriv->rstc1);
+       reset_control_assert(gpriv->rstc2);
+       clk_disable_unprepare(gpriv->clkp);
+       clk_disable_unprepare(gpriv->clk_ram);
 
        return 0;
 }
@@ -2286,30 +2282,71 @@ static int rcar_canfd_resume(struct device *dev)
        int err;
        u32 ch;
 
+       err = reset_control_deassert(gpriv->rstc1);
+       if (err)
+               goto fail_dev;
+
+       err = reset_control_deassert(gpriv->rstc2);
+       if (err) {
+               reset_control_assert(gpriv->rstc1);
+               goto fail_dev;
+       }
+
+       /* Enable peripheral clock for register access */
+       err = clk_prepare_enable(gpriv->clkp);
+       if (err) {
+               dev_err(dev,
+                       "failed to enable peripheral clock, error %d\n", err);
+               goto fail_reset;
+       }
+
+       /* 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_reset;
+       }
+
+       err = rcar_canfd_reset_controller(gpriv);
+       if (err) {
+               dev_err(dev, "reset controller failed\n");
+               goto fail_clk;
+       }
+
        err = rcar_canfd_global_init(gpriv);
        if (err) {
-               dev_err(dev, "rcar_canfd_open() failed %pe\n", ERR_PTR(err));
-               return err;
+               dev_err(dev, "controller init failed\n");
+               goto fail_mode;
        }
 
-       for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+       for_each_set_bit(ch, &gpriv->channels_mask, RCANFD_NUM_CHANNELS) {
                struct rcar_canfd_channel *priv = gpriv->ch[ch];
                struct net_device *ndev = priv->ndev;
 
                if (!netif_running(ndev))
                        continue;
 
-               err = rcar_canfd_open(ndev);
+               netif_device_attach(ndev);
+               err = rcar_canfd_start(ndev);
                if (err) {
-                       netdev_err(ndev, "rcar_canfd_open() failed %pe\n",
-                                  ERR_PTR(err));
+                       netif_device_detach(ndev);
                        return err;
                }
-
-               netif_device_attach(ndev);
+               netif_start_queue(ndev);
        }
 
        return 0;
+
+fail_mode:
+       rcar_canfd_disable_global_interrupts(gpriv);
+fail_clk:
+       clk_disable_unprepare(gpriv->clkp);
+fail_reset:
+       reset_control_assert(gpriv->rstc1);
+       reset_control_assert(gpriv->rstc2);
+fail_dev:
+       return err;
 }


[2] logs

root@smarc-rzg3e:/cip-test-scripts# [   36.691587] PM: suspend entry (deep)
[   36.695460] Filesystems sync: 0.000 seconds
[   36.704009] Freezing user space processes
[   36.709820] Freezing user space processes completed (elapsed 0.001 seconds)
[   36.716809] OOM killer disabled.
[   36.720049] Freezing remaining freezable tasks
[   36.725879] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
[   36.733327] printk: Suspending console(s) (use no_console_suspend to debug)
NOTICE:  BL2: v2.10.5(release):2.10.5/rz_soc_dev-169-g1410189b0
NOTICE:  BL2: Built : 12:53:12, Jul 15 2025
NOTICE:  BL2: SYS_LSI_MODE: 0x13e06
NOTICE:  BL2: SYS_LSI_DEVID: 0x8679447
NOTICE:  BL2: SYS_LSI_PRR: 0x0
NOTICE:  BL2: Booting BL31
[   36.759719] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[   36.818341] renesas-gbeth 15c30000.ethernet end0: Link is Down
[   36.832139] Disabling non-boot CPUs ...
[   36.836762] psci: CPU3 killed (polled 0 ms)
[   36.843491] psci: CPU2 killed (polled 4 ms)
[   36.852615] psci: CPU1 killed (polled 0 ms)
[   36.855973] Enabling non-boot CPUs ...
[   36.856187] Detected VIPT I-cache on CPU1
[   36.856231] GICv3: CPU1: found redistributor 100 region 0:0x0000000014960000
[   36.856268] CPU1: Booted secondary processor 0x0000000100 [0x412fd050]
[   36.857067] CPU1 is up
[   36.857163] Detected VIPT I-cache on CPU2
[   36.857185] GICv3: CPU2: found redistributor 200 region 0:0x0000000014980000
[   36.857205] CPU2: Booted secondary processor 0x0000000200 [0x412fd050]
[   36.857783] CPU2 is up
[   36.857878] Detected VIPT I-cache on CPU3
[   36.857901] GICv3: CPU3: found redistributor 300 region 0:0x00000000149a0000
[   36.857923] CPU3: Booted secondary processor 0x0000000300 [0x412fd050]
[   36.858631] CPU3 is up
[   36.875320] dwmac4: Master AXI performs fixed burst length
[   36.876219] renesas-gbeth 15c30000.ethernet end0: No Safety Features support found
[   36.876241] renesas-gbeth 15c30000.ethernet end0: IEEE 1588-2008 Advanced Timestamp supported
[   36.879753] renesas-gbeth 15c30000.ethernet end0: configuring for phy/rgmii-id link mode
[   36.897118] dwmac4: Master AXI performs fixed burst length
[   36.898009] renesas-gbeth 15c40000.ethernet end1: No Safety Features support found
[   36.898026] renesas-gbeth 15c40000.ethernet end1: IEEE 1588-2008 Advanced Timestamp supported
[   36.901567] renesas-gbeth 15c40000.ethernet end1: configuring for phy/rgmii-id link mode
[   36.948005] usb usb1: root hub lost power or was reset
[   36.948012] usb usb2: root hub lost power or was reset
[   39.107397] usb 2-1: reset SuperSpeed Plus Gen 2x1 USB device number 2 using xhci-renesas-hcd
[   39.294764] OOM killer enabled.
[   39.297903] Restarting tasks: Starting
[   39.303378] Restarting tasks: Done
[   39.306841] random: crng reseeded on system resumption
[   39.312209] PM: suspend exit
[   39.502581] renesas-gbeth 15c30000.ethernet end0: Link is Up - 1Gbps/Full - flow control rx/tx

root@smarc-rzg3e:/cip-test-scripts# ./canfd_t_003.sh
 [INFO] Testing can0<->can1 with bitrate 1000000 and dbitrate 4000000
 [INFO] Bringing down can0 can1
 [INFO] Bringing up can0 can1
 [INFO] Testing can1 as producer and can0 as consumer
[   48.400817] can: controller area network core
[   48.405291] NET: Registered PF_CAN protocol family
[   48.445879] can: raw protocol
 [INFO] Testing can0 as producer and can1 as consumer
 [INFO] Testing can0<->can1 with bitrate 500000 and dbitrate 2000000
 [INFO] Bringing down can0 can1
 [INFO] Bringing up can0 can1
 [INFO] Testing can1 as producer and can0 as consumer
 [INFO] Testing can0 as producer and can1 as consumer
 [INFO] Testing can0<->can1 with bitrate 250000 and dbitrate 1000000
 [INFO] Bringing down can0 can1
 [INFO] Bringing up can0 can1
 [INFO] Testing can1 as producer and can0 as consumer
 [INFO] Testing can0 as producer and can1 as consumer
[   69.411870] kauditd_printk_skb: 5 callbacks suppressed
[   69.411883] audit: type=1334 audit(1755879165.759:22): prog-id=18 op=UNLOAD
[   69.423995] audit: type=1334 audit(1755879165.759:23): prog-id=17 op=UNLOAD
[   69.430946] audit: type=1334 audit(1755879165.759:24): prog-id=16 op=UNLOAD

EXIT|PASS|canfd_t_003.sh|[00:00:25] ||

root@smarc-rzg3e:/cip-test-scripts#





[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