linux-renesas-soc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] can: rcar_canfd: Add suspend/resume support
@ 2025-08-22  9:50 Geert Uytterhoeven
  2025-08-22  9:50 ` [PATCH 1/6] can: rcar_canfd: Invert reset assert order Geert Uytterhoeven
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Geert Uytterhoeven @ 2025-08-22  9:50 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Biju Das
  Cc: linux-can, linux-renesas-soc, Geert Uytterhoeven

	Hi all,

This patch series adds proper suspend/resume support to the Renesas
R-Car CAN-FD controller driver, after the customary cleanuops and fixes.
It aims to fix CAN-FD operation after resume from s2ram on systems where
PSCI powers down the SoC.

The last patch is marked RFC, as it causes a regression on R-Car Gen4.
More details can be found in that patch.

This has been tested on Ebisu-4D (R-Car E3) and White Hawk (R-Car V4H).

Thanks for your comments!

Geert Uytterhoeven (6):
  can: rcar_canfd: Invert reset assert order
  can: rcar_canfd: Invert global vs. channel teardown
  can: rcar_canfd: Extract rcar_canfd_global_{,de}init()
  can: rcar_canfd: Invert CAN clock and close_candev() order
  can: rcar_canfd: Convert to DEFINE_SIMPLE_DEV_PM_OPS()
  [RFC] can: rcar_canfd: Add suspend/resume support

 drivers/net/can/rcar/rcar_canfd.c | 225 ++++++++++++++++++++----------
 1 file changed, 152 insertions(+), 73 deletions(-)

-- 
2.43.0

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/6] can: rcar_canfd: Invert reset assert order
  2025-08-22  9:50 [PATCH 0/6] can: rcar_canfd: Add suspend/resume support Geert Uytterhoeven
@ 2025-08-22  9:50 ` Geert Uytterhoeven
  2025-08-22 14:24   ` Biju Das
  2025-08-22  9:50 ` [PATCH 2/6] can: rcar_canfd: Invert global vs. channel teardown Geert Uytterhoeven
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Geert Uytterhoeven @ 2025-08-22  9:50 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Biju Das
  Cc: linux-can, linux-renesas-soc, Geert Uytterhoeven

The two resets are asserted during cleanup in the same order as they
were deasserted during probe.  Invert the order to restore symmetry.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/net/can/rcar/rcar_canfd.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index b3c8c592fb0e04ed..6f013f87f25c1494 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -2182,8 +2182,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)
 fail_clk:
 	clk_disable_unprepare(gpriv->clkp);
 fail_reset:
-	reset_control_assert(gpriv->rstc1);
 	reset_control_assert(gpriv->rstc2);
+	reset_control_assert(gpriv->rstc1);
 fail_dev:
 	return err;
 }
@@ -2204,8 +2204,8 @@ static void rcar_canfd_remove(struct platform_device *pdev)
 	/* Enter global sleep mode */
 	rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR);
 	clk_disable_unprepare(gpriv->clkp);
-	reset_control_assert(gpriv->rstc1);
 	reset_control_assert(gpriv->rstc2);
+	reset_control_assert(gpriv->rstc1);
 }
 
 static int __maybe_unused rcar_canfd_suspend(struct device *dev)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/6] can: rcar_canfd: Invert global vs. channel teardown
  2025-08-22  9:50 [PATCH 0/6] can: rcar_canfd: Add suspend/resume support Geert Uytterhoeven
  2025-08-22  9:50 ` [PATCH 1/6] can: rcar_canfd: Invert reset assert order Geert Uytterhoeven
@ 2025-08-22  9:50 ` Geert Uytterhoeven
  2025-08-22 14:21   ` Biju Das
  2025-08-22  9:50 ` [PATCH 3/6] can: rcar_canfd: Extract rcar_canfd_global_{,de}init() Geert Uytterhoeven
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Geert Uytterhoeven @ 2025-08-22  9:50 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Biju Das
  Cc: linux-can, linux-renesas-soc, Geert Uytterhoeven

Global state is initialized and torn down before per-channel state.
Invert the order to restore symmetry.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/net/can/rcar/rcar_canfd.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index 6f013f87f25c1494..341bc25df32a8973 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -2193,14 +2193,14 @@ static void rcar_canfd_remove(struct platform_device *pdev)
 	struct rcar_canfd_global *gpriv = platform_get_drvdata(pdev);
 	u32 ch;
 
-	rcar_canfd_reset_controller(gpriv);
-	rcar_canfd_disable_global_interrupts(gpriv);
-
 	for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
 		rcar_canfd_disable_channel_interrupts(gpriv->ch[ch]);
 		rcar_canfd_channel_remove(gpriv, ch);
 	}
 
+	rcar_canfd_disable_global_interrupts(gpriv);
+	rcar_canfd_reset_controller(gpriv);
+
 	/* Enter global sleep mode */
 	rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR);
 	clk_disable_unprepare(gpriv->clkp);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/6] can: rcar_canfd: Extract rcar_canfd_global_{,de}init()
  2025-08-22  9:50 [PATCH 0/6] can: rcar_canfd: Add suspend/resume support Geert Uytterhoeven
  2025-08-22  9:50 ` [PATCH 1/6] can: rcar_canfd: Invert reset assert order Geert Uytterhoeven
  2025-08-22  9:50 ` [PATCH 2/6] can: rcar_canfd: Invert global vs. channel teardown Geert Uytterhoeven
@ 2025-08-22  9:50 ` Geert Uytterhoeven
  2025-08-22  9:50 ` [PATCH 4/6] can: rcar_canfd: Invert CAN clock and close_candev() order Geert Uytterhoeven
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Geert Uytterhoeven @ 2025-08-22  9:50 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Biju Das
  Cc: linux-can, linux-renesas-soc, Geert Uytterhoeven

Extract the code to (de)initialize global state into separate functions,
for future reuse.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/net/can/rcar/rcar_canfd.c | 160 +++++++++++++++++-------------
 1 file changed, 93 insertions(+), 67 deletions(-)

diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index 341bc25df32a8973..38c1b327f6b1d540 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -1950,22 +1950,110 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch)
 	}
 }
 
+static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
+{
+	struct device *dev = &gpriv->pdev->dev;
+	u32 rule_entry = 0;
+	u32 ch, sts;
+	int err;
+
+	err = reset_control_reset(gpriv->rstc1);
+	if (err)
+		return err;
+
+	err = reset_control_reset(gpriv->rstc2);
+	if (err)
+		goto fail_reset1;
+
+	/* Enable peripheral clock for register access */
+	err = clk_prepare_enable(gpriv->clkp);
+	if (err) {
+		dev_err(dev, "failed to enable peripheral clock: %pe\n",
+			ERR_PTR(err));
+		goto fail_reset2;
+	}
+
+	err = rcar_canfd_reset_controller(gpriv);
+	if (err) {
+		dev_err(dev, "reset controller failed: %pe\n", ERR_PTR(err));
+		goto fail_clk;
+	}
+
+	/* Controller in Global reset & Channel reset mode */
+	rcar_canfd_configure_controller(gpriv);
+
+	/* Configure per channel attributes */
+	for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+		/* Configure Channel's Rx fifo */
+		rcar_canfd_configure_rx(gpriv, ch);
+
+		/* Configure Channel's Tx (Common) fifo */
+		rcar_canfd_configure_tx(gpriv, ch);
+
+		/* Configure receive rules */
+		rcar_canfd_configure_afl_rules(gpriv, ch, rule_entry);
+		rule_entry += RCANFD_CHANNEL_NUMRULES;
+	}
+
+	/* Configure common interrupts */
+	rcar_canfd_enable_global_interrupts(gpriv);
+
+	/* Start Global operation mode */
+	rcar_canfd_update_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GMDC_MASK,
+			      RCANFD_GCTR_GMDC_GOPM);
+
+	/* Verify mode change */
+	err = readl_poll_timeout((gpriv->base + RCANFD_GSTS), sts,
+				 !(sts & RCANFD_GSTS_GNOPM), 2, 500000);
+	if (err) {
+		dev_err(dev, "global operational mode failed\n");
+		goto fail_mode;
+	}
+
+	return 0;
+
+fail_mode:
+	rcar_canfd_disable_global_interrupts(gpriv);
+fail_clk:
+	clk_disable_unprepare(gpriv->clkp);
+fail_reset2:
+	reset_control_assert(gpriv->rstc2);
+fail_reset1:
+	reset_control_assert(gpriv->rstc1);
+	return err;
+}
+
+static void rcar_canfd_global_deinit(struct rcar_canfd_global *gpriv, bool full)
+{
+	rcar_canfd_disable_global_interrupts(gpriv);
+
+	if (full) {
+		rcar_canfd_reset_controller(gpriv);
+
+		/* Enter global sleep mode */
+		rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR);
+	}
+
+	clk_disable_unprepare(gpriv->clkp);
+	reset_control_assert(gpriv->rstc2);
+	reset_control_assert(gpriv->rstc1);
+}
+
 static int rcar_canfd_probe(struct platform_device *pdev)
 {
 	struct phy *transceivers[RCANFD_NUM_CHANNELS] = { NULL, };
 	const struct rcar_canfd_hw_info *info;
 	struct device *dev = &pdev->dev;
 	void __iomem *addr;
-	u32 sts, ch, fcan_freq;
 	struct rcar_canfd_global *gpriv;
 	struct device_node *of_child;
 	unsigned long channels_mask = 0;
 	int err, ch_irq, g_irq;
 	int g_err_irq, g_recc_irq;
-	u32 rule_entry = 0;
 	bool fdmode = true;			/* CAN FD only mode - default */
 	char name[9] = "channelX";
 	struct clk *clk_ram;
+	u32 ch, fcan_freq;
 	int i;
 
 	info = of_device_get_match_data(dev);
@@ -2107,59 +2195,9 @@ static int rcar_canfd_probe(struct platform_device *pdev)
 		}
 	}
 
-	err = reset_control_reset(gpriv->rstc1);
+	err = rcar_canfd_global_init(gpriv);
 	if (err)
-		goto fail_dev;
-	err = reset_control_reset(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: %pe\n",
-			ERR_PTR(err));
-		goto fail_reset;
-	}
-
-	err = rcar_canfd_reset_controller(gpriv);
-	if (err) {
-		dev_err(dev, "reset controller failed: %pe\n", ERR_PTR(err));
-		goto fail_clk;
-	}
-
-	/* Controller in Global reset & Channel reset mode */
-	rcar_canfd_configure_controller(gpriv);
-
-	/* Configure per channel attributes */
-	for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) {
-		/* Configure Channel's Rx fifo */
-		rcar_canfd_configure_rx(gpriv, ch);
-
-		/* Configure Channel's Tx (Common) fifo */
-		rcar_canfd_configure_tx(gpriv, ch);
-
-		/* Configure receive rules */
-		rcar_canfd_configure_afl_rules(gpriv, ch, rule_entry);
-		rule_entry += RCANFD_CHANNEL_NUMRULES;
-	}
-
-	/* Configure common interrupts */
-	rcar_canfd_enable_global_interrupts(gpriv);
-
-	/* Start Global operation mode */
-	rcar_canfd_update_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GMDC_MASK,
-			      RCANFD_GCTR_GMDC_GOPM);
-
-	/* Verify mode change */
-	err = readl_poll_timeout((gpriv->base + RCANFD_GSTS), sts,
-				 !(sts & RCANFD_GSTS_GNOPM), 2, 500000);
-	if (err) {
-		dev_err(dev, "global operational mode failed\n");
 		goto fail_mode;
-	}
 
 	for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) {
 		err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq,
@@ -2178,12 +2216,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
 	for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels)
 		rcar_canfd_channel_remove(gpriv, ch);
 fail_mode:
-	rcar_canfd_disable_global_interrupts(gpriv);
-fail_clk:
-	clk_disable_unprepare(gpriv->clkp);
-fail_reset:
-	reset_control_assert(gpriv->rstc2);
-	reset_control_assert(gpriv->rstc1);
+	rcar_canfd_global_deinit(gpriv, false);
 fail_dev:
 	return err;
 }
@@ -2198,14 +2231,7 @@ static void rcar_canfd_remove(struct platform_device *pdev)
 		rcar_canfd_channel_remove(gpriv, ch);
 	}
 
-	rcar_canfd_disable_global_interrupts(gpriv);
-	rcar_canfd_reset_controller(gpriv);
-
-	/* Enter global sleep mode */
-	rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR);
-	clk_disable_unprepare(gpriv->clkp);
-	reset_control_assert(gpriv->rstc2);
-	reset_control_assert(gpriv->rstc1);
+	rcar_canfd_global_deinit(gpriv, true);
 }
 
 static int __maybe_unused rcar_canfd_suspend(struct device *dev)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/6] can: rcar_canfd: Invert CAN clock and close_candev() order
  2025-08-22  9:50 [PATCH 0/6] can: rcar_canfd: Add suspend/resume support Geert Uytterhoeven
                   ` (2 preceding siblings ...)
  2025-08-22  9:50 ` [PATCH 3/6] can: rcar_canfd: Extract rcar_canfd_global_{,de}init() Geert Uytterhoeven
@ 2025-08-22  9:50 ` Geert Uytterhoeven
  2025-08-22 14:26   ` Biju Das
  2025-08-22  9:50 ` [PATCH 5/6] can: rcar_canfd: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Geert Uytterhoeven
  2025-08-22  9:50 ` [PATCH/RFC 6/6] can: rcar_canfd: Add suspend/resume support Geert Uytterhoeven
  5 siblings, 1 reply; 13+ messages in thread
From: Geert Uytterhoeven @ 2025-08-22  9:50 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Biju Das
  Cc: linux-can, linux-renesas-soc, Geert Uytterhoeven

The CAN clock is enabled before calling open_candev(), and disabled
before calling close_candev().  Invert the order of the latter, to
restore symmetry.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/net/can/rcar/rcar_canfd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index 38c1b327f6b1d540..de5121efdabdb6ed 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -1561,8 +1561,8 @@ static int rcar_canfd_close(struct net_device *ndev)
 	netif_stop_queue(ndev);
 	rcar_canfd_stop(ndev);
 	napi_disable(&priv->napi);
-	clk_disable_unprepare(gpriv->can_clk);
 	close_candev(ndev);
+	clk_disable_unprepare(gpriv->can_clk);
 	phy_power_off(priv->transceiver);
 	return 0;
 }
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/6] can: rcar_canfd: Convert to DEFINE_SIMPLE_DEV_PM_OPS()
  2025-08-22  9:50 [PATCH 0/6] can: rcar_canfd: Add suspend/resume support Geert Uytterhoeven
                   ` (3 preceding siblings ...)
  2025-08-22  9:50 ` [PATCH 4/6] can: rcar_canfd: Invert CAN clock and close_candev() order Geert Uytterhoeven
@ 2025-08-22  9:50 ` Geert Uytterhoeven
  2025-08-22 14:27   ` Biju Das
  2025-08-22  9:50 ` [PATCH/RFC 6/6] can: rcar_canfd: Add suspend/resume support Geert Uytterhoeven
  5 siblings, 1 reply; 13+ messages in thread
From: Geert Uytterhoeven @ 2025-08-22  9:50 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Biju Das
  Cc: linux-can, linux-renesas-soc, Geert Uytterhoeven

Convert the Renesas R-Car CAN-FD driver from SIMPLE_DEV_PM_OPS() to
DEFINE_SIMPLE_DEV_PM_OPS() and pm_sleep_ptr().  This lets us drop the
__maybe_unused annotations from its suspend and resume callbacks, and
reduces kernel size in case CONFIG_PM or CONFIG_PM_SLEEP is disabled.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/net/can/rcar/rcar_canfd.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index de5121efdabdb6ed..eedce83b91414c57 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -2234,18 +2234,18 @@ static void rcar_canfd_remove(struct platform_device *pdev)
 	rcar_canfd_global_deinit(gpriv, true);
 }
 
-static int __maybe_unused rcar_canfd_suspend(struct device *dev)
+static int rcar_canfd_suspend(struct device *dev)
 {
 	return 0;
 }
 
-static int __maybe_unused rcar_canfd_resume(struct device *dev)
+static int rcar_canfd_resume(struct device *dev)
 {
 	return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(rcar_canfd_pm_ops, rcar_canfd_suspend,
-			 rcar_canfd_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(rcar_canfd_pm_ops, rcar_canfd_suspend,
+				rcar_canfd_resume);
 
 static const __maybe_unused struct of_device_id rcar_canfd_of_table[] = {
 	{ .compatible = "renesas,r8a779a0-canfd", .data = &rcar_gen4_hw_info },
@@ -2262,7 +2262,7 @@ static struct platform_driver rcar_canfd_driver = {
 	.driver = {
 		.name = RCANFD_DRV_NAME,
 		.of_match_table = of_match_ptr(rcar_canfd_of_table),
-		.pm = &rcar_canfd_pm_ops,
+		.pm = pm_sleep_ptr(&rcar_canfd_pm_ops),
 	},
 	.probe = rcar_canfd_probe,
 	.remove = rcar_canfd_remove,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH/RFC 6/6] can: rcar_canfd: Add suspend/resume support
  2025-08-22  9:50 [PATCH 0/6] can: rcar_canfd: Add suspend/resume support Geert Uytterhoeven
                   ` (4 preceding siblings ...)
  2025-08-22  9:50 ` [PATCH 5/6] can: rcar_canfd: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Geert Uytterhoeven
@ 2025-08-22  9:50 ` Geert Uytterhoeven
  2025-08-22 13:39   ` Biju Das
  5 siblings, 1 reply; 13+ messages in thread
From: Geert Uytterhoeven @ 2025-08-22  9:50 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Biju Das
  Cc: linux-can, linux-renesas-soc, Geert Uytterhoeven

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@glider.be>
---
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;
 }
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* RE: [PATCH/RFC 6/6] can: rcar_canfd: Add suspend/resume support
  2025-08-22  9:50 ` [PATCH/RFC 6/6] can: rcar_canfd: Add suspend/resume support Geert Uytterhoeven
@ 2025-08-22 13:39   ` Biju Das
  2025-08-22 16:19     ` Biju Das
  0 siblings, 1 reply; 13+ messages in thread
From: Biju Das @ 2025-08-22 13:39 UTC (permalink / raw)
  To: Geert Uytterhoeven, Marc Kleine-Budde, Vincent Mailhol
  Cc: linux-can@vger.kernel.org, linux-renesas-soc@vger.kernel.org

Hi Geert,


> -----Original Message-----
> From: Geert Uytterhoeven <geert+renesas@glider.be>
> Sent: 22 August 2025 10:51
> To: Marc Kleine-Budde <mkl@pengutronix.de>; Vincent Mailhol <mailhol.vincent@wanadoo.fr>; Biju Das
> <biju.das.jz@bp.renesas.com>
> Cc: linux-can@vger.kernel.org; linux-renesas-soc@vger.kernel.org; Geert Uytterhoeven
> <geert+renesas@glider.be>
> 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@glider.be>
> ---
> 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;
>  }
> 

This patch does not work on RZ/G3E, please see the logs

Bind/Unbind:
-------------
root@smarc-rzg3e:/cip-test-scripts# cd /sys/bus/platform/drivers/rcar_canfd
n > unbindroot@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd# echo 12440000.can > unbind
root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd# echo 12440000.can > bind
[   67.645615] rcar_canfd 12440000.can: can_clk rate is 80000000
[   67.655044] rcar_canfd 12440000.can: device registered (channel 1)
[   67.661788] rcar_canfd 12440000.can: can_clk rate is 80000000
[   67.671258] rcar_canfd 12440000.can: device registered (channel 4)
[   67.677603] rcar_canfd 12440000.can: global operational state (canfd clk, fd mode)

root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd# /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
 [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

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

G3E S2Idle:
------------
root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd# echo s2idle > /sys/power/mem_sleep
root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd# echo mem > /sys/power/state
[  160.231921] PM: suspend entry (s2idle)
[  160.236099] Filesystems sync: 0.000 seconds
[  160.248409] Freezing user space processes
[  160.255200] Freezing user space processes completed (elapsed 0.002 seconds)
[  160.262354] OOM killer disabled.
[  160.265681] Freezing remaining freezable tasks
[  160.271723] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
[  160.279253] printk: Suspending console(s) (use no_console_suspend to debug)
[  160.311505] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[  160.377382] renesas-gbeth 15c30000.ethernet end0: Link is Down
[  162.226309] dwmac4: Master AXI performs fixed burst length
[  162.227718] renesas-gbeth 15c30000.ethernet end0: No Safety Features support found
[  162.227788] renesas-gbeth 15c30000.ethernet end0: IEEE 1588-2008 Advanced Timestamp supported
[  162.232919] renesas-gbeth 15c30000.ethernet end0: configuring for phy/rgmii-id link mode
[  162.252982] dwmac4: Master AXI performs fixed burst length
[  162.254258] renesas-gbeth 15c40000.ethernet end1: No Safety Features support found
[  162.254321] renesas-gbeth 15c40000.ethernet end1: IEEE 1588-2008 Advanced Timestamp supported
[  162.259706] renesas-gbeth 15c40000.ethernet end1: configuring for phy/rgmii-id link mode
[  162.307564] usb usb1: root hub lost power or was reset
[  162.307607] usb usb2: root hub lost power or was reset
[  164.471610] usb 2-1: reset SuperSpeed Plus Gen 2x1 USB device number 2 using xhci-renesas-hcd
[  164.584382] OOM killer enabled.
[  164.587540] Restarting tasks: Starting
[  164.593757] Restarting tasks: Done
[  164.597263] random: crng reseeded on system resumption
[  164.602497] PM: suspend exit
root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd# [  164.959424] renesas-gbeth 15c30000.ethernet end0: Link is Up - 1Gbps/Full - flow control rx/tx

root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd# /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
 [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

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

G3E STR:
--------

root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd# echo deep > /sys/power/mem_sleep
root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd# echo mem > /sys/power/state
[  237.863858] PM: suspend entry (deep)
[  237.867860] Filesystems sync: 0.000 seconds
[  237.878623] Freezing user space processes
[  237.885330] Freezing user space processes completed (elapsed 0.002 seconds)
[  237.892455] OOM killer disabled.
[  237.895804] Freezing remaining freezable tasks
[  237.902064] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
[  237.909648] 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
[  237.943571] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[  237.992789] renesas-gbeth 15c30000.ethernet end0: Link is Down
[  238.006388] Disabling non-boot CPUs ...
[  238.011104] psci: CPU3 killed (polled 0 ms)
[  238.017799] psci: CPU2 killed (polled 0 ms)
[  238.023704] psci: CPU1 killed (polled 4 ms)
[  238.028259] Enabling non-boot CPUs ...
[  238.028474] Detected VIPT I-cache on CPU1
[  238.028521] GICv3: CPU1: found redistributor 100 region 0:0x0000000014960000
[  238.028558] CPU1: Booted secondary processor 0x0000000100 [0x412fd050]
[  238.029374] CPU1 is up
[  238.029470] Detected VIPT I-cache on CPU2
[  238.029492] GICv3: CPU2: found redistributor 200 region 0:0x0000000014980000
[  238.029513] CPU2: Booted secondary processor 0x0000000200 [0x412fd050]
[  238.030046] CPU2 is up
[  238.030145] Detected VIPT I-cache on CPU3
[  238.030167] GICv3: CPU3: found redistributor 300 region 0:0x00000000149a0000
[  238.030189] CPU3: Booted secondary processor 0x0000000300 [0x412fd050]
[  238.030873] CPU3 is up
[  238.047257] dwmac4: Master AXI performs fixed burst length
[  238.048165] renesas-gbeth 15c30000.ethernet end0: No Safety Features support found
[  238.048185] renesas-gbeth 15c30000.ethernet end0: IEEE 1588-2008 Advanced Timestamp supported
[  238.051680] renesas-gbeth 15c30000.ethernet end0: configuring for phy/rgmii-id link mode
[  238.069106] dwmac4: Master AXI performs fixed burst length
[  238.070002] renesas-gbeth 15c40000.ethernet end1: No Safety Features support found
[  238.070018] renesas-gbeth 15c40000.ethernet end1: IEEE 1588-2008 Advanced Timestamp supported
[  238.073613] renesas-gbeth 15c40000.ethernet end1: configuring for phy/rgmii-id link mode
[  238.119909] usb usb1: root hub lost power or was reset
[  238.119918] usb usb2: root hub lost power or was reset
[  240.279309] usb 2-1: reset SuperSpeed Plus Gen 2x1 USB device number 2 using xhci-renesas-hcd
[  240.468214] OOM killer enabled.
[  240.471358] Restarting tasks: Starting
[  240.475721] Restarting tasks: Done
[  240.479171] random: crng reseeded on system resumption
[  240.484426] PM: suspend exit
root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd# [  240.692426] renesas-gbeth 15c30000.ethernet end0: Link is Up - 1Gbps/Full - flow control rx/tx

root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd#
root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd# /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

EXIT|FAIL|canfd_t_003.sh|[00:00:04] Problems while producing data from can1 and consuming from can0||

root@smarc-rzg3e:/sys/bus/platform/drivers/rcar_canfd#

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH 2/6] can: rcar_canfd: Invert global vs. channel teardown
  2025-08-22  9:50 ` [PATCH 2/6] can: rcar_canfd: Invert global vs. channel teardown Geert Uytterhoeven
@ 2025-08-22 14:21   ` Biju Das
  0 siblings, 0 replies; 13+ messages in thread
From: Biju Das @ 2025-08-22 14:21 UTC (permalink / raw)
  To: Geert Uytterhoeven, Marc Kleine-Budde, Vincent Mailhol
  Cc: linux-can@vger.kernel.org, linux-renesas-soc@vger.kernel.org

Hi Geert,

Thanks for the patch.

> -----Original Message-----
> From: Geert Uytterhoeven <geert+renesas@glider.be>
> Sent: 22 August 2025 10:51
> Subject: [PATCH 2/6] can: rcar_canfd: Invert global vs. channel teardown
> 
> Global state is initialized and torn down before per-channel state.
> Invert the order to restore symmetry.
> 
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>


Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>

Cheers,
Biju

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH 1/6] can: rcar_canfd: Invert reset assert order
  2025-08-22  9:50 ` [PATCH 1/6] can: rcar_canfd: Invert reset assert order Geert Uytterhoeven
@ 2025-08-22 14:24   ` Biju Das
  0 siblings, 0 replies; 13+ messages in thread
From: Biju Das @ 2025-08-22 14:24 UTC (permalink / raw)
  To: Geert Uytterhoeven, Marc Kleine-Budde, Vincent Mailhol
  Cc: linux-can@vger.kernel.org, linux-renesas-soc@vger.kernel.org

Hi Geert,

> -----Original Message-----
> From: Geert Uytterhoeven <geert+renesas@glider.be>
> Sent: 22 August 2025 10:51
> Subject: [PATCH 1/6] can: rcar_canfd: Invert reset assert order
> 
> The two resets are asserted during cleanup in the same order as they were deasserted during probe.
> Invert the order to restore symmetry.
> 
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>

Cheers,
Biju


^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH 4/6] can: rcar_canfd: Invert CAN clock and close_candev() order
  2025-08-22  9:50 ` [PATCH 4/6] can: rcar_canfd: Invert CAN clock and close_candev() order Geert Uytterhoeven
@ 2025-08-22 14:26   ` Biju Das
  0 siblings, 0 replies; 13+ messages in thread
From: Biju Das @ 2025-08-22 14:26 UTC (permalink / raw)
  To: Geert Uytterhoeven, Marc Kleine-Budde, Vincent Mailhol
  Cc: linux-can@vger.kernel.org, linux-renesas-soc@vger.kernel.org

Hi Geert,

> -----Original Message-----
> From: Geert Uytterhoeven <geert+renesas@glider.be>
> Sent: 22 August 2025 10:51
> Subject: [PATCH 4/6] can: rcar_canfd: Invert CAN clock and close_candev() order
> 
> The CAN clock is enabled before calling open_candev(), and disabled before calling close_candev().
> Invert the order of the latter, to restore symmetry.
> 
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>

Cheers,
Biju


^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH 5/6] can: rcar_canfd: Convert to DEFINE_SIMPLE_DEV_PM_OPS()
  2025-08-22  9:50 ` [PATCH 5/6] can: rcar_canfd: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Geert Uytterhoeven
@ 2025-08-22 14:27   ` Biju Das
  0 siblings, 0 replies; 13+ messages in thread
From: Biju Das @ 2025-08-22 14:27 UTC (permalink / raw)
  To: Geert Uytterhoeven, Marc Kleine-Budde, Vincent Mailhol
  Cc: linux-can@vger.kernel.org, linux-renesas-soc@vger.kernel.org

Hi Geert,

Thanks for the patch.

> -----Original Message-----
> From: Geert Uytterhoeven <geert+renesas@glider.be>
> Sent: 22 August 2025 10:51
> To: Marc Kleine-Budde <mkl@pengutronix.de>; Vincent Mailhol <mailhol.vincent@wanadoo.fr>; Biju Das
> <biju.das.jz@bp.renesas.com>
> Cc: linux-can@vger.kernel.org; linux-renesas-soc@vger.kernel.org; Geert Uytterhoeven
> <geert+renesas@glider.be>
> Subject: [PATCH 5/6] can: rcar_canfd: Convert to DEFINE_SIMPLE_DEV_PM_OPS()
> 
> Convert the Renesas R-Car CAN-FD driver from SIMPLE_DEV_PM_OPS() to
> DEFINE_SIMPLE_DEV_PM_OPS() and pm_sleep_ptr().  This lets us drop the __maybe_unused annotations from
> its suspend and resume callbacks, and reduces kernel size in case CONFIG_PM or CONFIG_PM_SLEEP is
> disabled.
> 
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>

Cheers,
Biju

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH/RFC 6/6] can: rcar_canfd: Add suspend/resume support
  2025-08-22 13:39   ` Biju Das
@ 2025-08-22 16:19     ` Biju Das
  0 siblings, 0 replies; 13+ messages in thread
From: Biju Das @ 2025-08-22 16:19 UTC (permalink / raw)
  To: Geert Uytterhoeven, Marc Kleine-Budde, Vincent Mailhol
  Cc: linux-can@vger.kernel.org, linux-renesas-soc@vger.kernel.org

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@glider.be>
> > Sent: 22 August 2025 10:51
> > To: Marc Kleine-Budde <mkl@pengutronix.de>; Vincent Mailhol
> > <mailhol.vincent@wanadoo.fr>; Biju Das <biju.das.jz@bp.renesas.com>
> > Cc: linux-can@vger.kernel.org; linux-renesas-soc@vger.kernel.org;
> > Geert Uytterhoeven <geert+renesas@glider.be>
> > 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@glider.be>
> > ---
> > 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#

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2025-08-22 16:19 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-22  9:50 [PATCH 0/6] can: rcar_canfd: Add suspend/resume support Geert Uytterhoeven
2025-08-22  9:50 ` [PATCH 1/6] can: rcar_canfd: Invert reset assert order Geert Uytterhoeven
2025-08-22 14:24   ` Biju Das
2025-08-22  9:50 ` [PATCH 2/6] can: rcar_canfd: Invert global vs. channel teardown Geert Uytterhoeven
2025-08-22 14:21   ` Biju Das
2025-08-22  9:50 ` [PATCH 3/6] can: rcar_canfd: Extract rcar_canfd_global_{,de}init() Geert Uytterhoeven
2025-08-22  9:50 ` [PATCH 4/6] can: rcar_canfd: Invert CAN clock and close_candev() order Geert Uytterhoeven
2025-08-22 14:26   ` Biju Das
2025-08-22  9:50 ` [PATCH 5/6] can: rcar_canfd: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Geert Uytterhoeven
2025-08-22 14:27   ` Biju Das
2025-08-22  9:50 ` [PATCH/RFC 6/6] can: rcar_canfd: Add suspend/resume support Geert Uytterhoeven
2025-08-22 13:39   ` Biju Das
2025-08-22 16:19     ` Biju Das

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).