From 6b8c12d354dfa9c80d82eea8c0c45d331a28be11 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 4 Oct 2026 03:18:13 +0200 Subject: [PATCH] PCI: rcar-gen4: Add missing PM ops The R-Car Gen4 PCIe controller is part of a power domain. On R-Car S4 and V4H, this is an always-on power domain which is not shut down in suspend. On R-Car V4M, this is a dedicated A2PCIPHY power domain, which is shut down during suspend, and the controller loses state, which prevents the PCIe from working after resume. Fix this by adding generic suspend/resume noirq ops for the controller, which tear the link down on suspend, and restart it on resume. Use the same PM ops on all of R-Car Gen4 to gracefully suspend and resume the PCIe link on V4H and S4 too. Test case which demonstrates the problem on R-Car V4M: $ hexdump -vC /sys/bus/pci/devices/0000:00:00.0/config > /tmp/pre $ echo s2idle > /sys/power/mem_sleep $ echo platform > /sys/power/pm_test $ echo mem > /sys/power/state $ hexdump -vC /sys/bus/pci/devices/0000:00:00.0/config > /tmp/post $ diff -Naru /tmp/pre /tmp/post ... -00000000 12 19 32 00 07 05 10 00 00 00 04 06 00 00 01 00 +00000000 12 19 32 00 07 05 10 00 00 00 00 ff 00 00 80 00 ^^^^^ Class 0604->00ff Fixes: 0270dbe4f891 ("arm64: dts: renesas: r8a779h0: Add PCIe Host and Endpoint nodes") Reported-by: Geert Uytterhoeven Signed-off-by: Marek Vasut Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Tested-by: Geert Uytterhoeven Tested-by: Koichiro Den Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20261004011851.866833-1-marek.vasut+renesas@mailbox.org --- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index 21c3dd9b8891..b8237962de18 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -671,6 +671,8 @@ static int rcar_gen4_add_dw_pcie_rp(struct rcar_gen4_pcie *rcar) return -ENODEV; pp->num_vectors = MAX_MSI_IRQS; + /* Reserve an iATU window for the generic PME_Turn_Off implementation. */ + pp->use_atu_msg = true; pp->ops = &rcar_gen4_pcie_host_ops; return dw_pcie_host_init(pp); @@ -1062,6 +1064,26 @@ static int rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable return 0; } +static int rcar_gen4_pcie_suspend_noirq(struct device *dev) +{ + struct rcar_gen4_pcie *rcar = dev_get_drvdata(dev); + + if (rcar->drvdata->mode != DW_PCIE_RC_TYPE) + return 0; + + return dw_pcie_suspend_noirq(&rcar->dw); +} + +static int rcar_gen4_pcie_resume_noirq(struct device *dev) +{ + struct rcar_gen4_pcie *rcar = dev_get_drvdata(dev); + + if (rcar->drvdata->mode != DW_PCIE_RC_TYPE) + return 0; + + return dw_pcie_resume_noirq(&rcar->dw); +} + static struct rcar_gen4_pcie_drvdata drvdata_r8a779f0_pcie = { .init = rcar_gen4_pcie_common_init, .deinit = rcar_gen4_pcie_common_deinit, @@ -1127,10 +1149,15 @@ static const struct of_device_id rcar_gen4_pcie_of_match[] = { }; MODULE_DEVICE_TABLE(of, rcar_gen4_pcie_of_match); +static DEFINE_NOIRQ_DEV_PM_OPS(rcar_gen4_pcie_pm_ops, + rcar_gen4_pcie_suspend_noirq, + rcar_gen4_pcie_resume_noirq); + static struct platform_driver rcar_gen4_pcie_driver = { .driver = { .name = "pcie-rcar-gen4", .of_match_table = rcar_gen4_pcie_of_match, + .pm = pm_sleep_ptr(&rcar_gen4_pcie_pm_ops), .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = rcar_gen4_pcie_probe,