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; } -- 2.43.0