Commit ad9b9b6e authored by Manivannan Sadhasivam's avatar Manivannan Sadhasivam Committed by Lorenzo Pieralisi

PCI: qcom: Add support for system suspend and resume

During the system suspend, vote for minimal interconnect bandwidth (1KiB)
to keep the interconnect path active for config access and also turn OFF
the resources like clock and PHY if there are no active devices connected
to the controller. For the controllers with active devices, the resources
are kept ON as removing the resources will trigger access violation during
the late end of suspend cycle as kernel tries to access the config space of
PCIe devices to mask the MSIs.

Also, it is not desirable to put the link into L2/L3 state as that
implies VDD supply will be removed and the devices may go into powerdown
state. This will affect the lifetime of storage devices like NVMe.

And finally, during resume, turn ON the resources if the controller was
truly suspended (resources OFF) and update the interconnect bandwidth
based on PCIe Gen speed.
Suggested-by: default avatarKrishna chaitanya chundru <quic_krichai@quicinc.com>
Link: https://lore.kernel.org/r/20230403154922.20704-2-manivannan.sadhasivam@linaro.orgTested-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Signed-off-by: default avatarManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: default avatarLorenzo Pieralisi <lpieralisi@kernel.org>
Reviewed-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Acked-by: default avatarDhruva Gole <d-gole@ti.com>
parent 05f46464
......@@ -244,6 +244,7 @@ struct qcom_pcie {
struct icc_path *icc_mem;
const struct qcom_pcie_cfg *cfg;
struct dentry *debugfs;
bool suspended;
};
#define to_qcom_pcie(x) dev_get_drvdata((x)->dev)
......@@ -1538,6 +1539,62 @@ static int qcom_pcie_probe(struct platform_device *pdev)
return ret;
}
static int qcom_pcie_suspend_noirq(struct device *dev)
{
struct qcom_pcie *pcie = dev_get_drvdata(dev);
int ret;
/*
* Set minimum bandwidth required to keep data path functional during
* suspend.
*/
ret = icc_set_bw(pcie->icc_mem, 0, kBps_to_icc(1));
if (ret) {
dev_err(dev, "Failed to set interconnect bandwidth: %d\n", ret);
return ret;
}
/*
* Turn OFF the resources only for controllers without active PCIe
* devices. For controllers with active devices, the resources are kept
* ON and the link is expected to be in L0/L1 (sub)states.
*
* Turning OFF the resources for controllers with active PCIe devices
* will trigger access violation during the end of the suspend cycle,
* as kernel tries to access the PCIe devices config space for masking
* MSIs.
*
* Also, it is not desirable to put the link into L2/L3 state as that
* implies VDD supply will be removed and the devices may go into
* powerdown state. This will affect the lifetime of the storage devices
* like NVMe.
*/
if (!dw_pcie_link_up(pcie->pci)) {
qcom_pcie_host_deinit(&pcie->pci->pp);
pcie->suspended = true;
}
return 0;
}
static int qcom_pcie_resume_noirq(struct device *dev)
{
struct qcom_pcie *pcie = dev_get_drvdata(dev);
int ret;
if (pcie->suspended) {
ret = qcom_pcie_host_init(&pcie->pci->pp);
if (ret)
return ret;
pcie->suspended = false;
}
qcom_pcie_icc_update(pcie);
return 0;
}
static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 },
{ .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 },
......@@ -1574,12 +1631,17 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0302, qcom_fixup_class);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x1000, qcom_fixup_class);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x1001, qcom_fixup_class);
static const struct dev_pm_ops qcom_pcie_pm_ops = {
NOIRQ_SYSTEM_SLEEP_PM_OPS(qcom_pcie_suspend_noirq, qcom_pcie_resume_noirq)
};
static struct platform_driver qcom_pcie_driver = {
.probe = qcom_pcie_probe,
.driver = {
.name = "qcom-pcie",
.suppress_bind_attrs = true,
.of_match_table = qcom_pcie_match,
.pm = &qcom_pcie_pm_ops,
},
};
builtin_platform_driver(qcom_pcie_driver);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment