[PATCH v2 3/4] PCI: qcom: Add link retention support
Konrad Dybcio
konrad.dybcio at oss.qualcomm.com
Tue Jun 16 05:08:44 PDT 2026
On 5/21/26 2:56 PM, Krishna Chaitanya Chundru wrote:
> Some platforms keep the PCIe link active across bootloader and kernel
> handoff. Reinitializing the controller and toggling PERST# in such cases is
> unnecessary when the driver does not need to retrain the link.
>
> Introduce link_retain in both qcom_pcie_cfg and qcom_pcie to indicate when
> link retention is supported. During initialization, check the LTSSM state;
> if the link is already in L0 or L1 idle and LTSSM is enabled, set
> link_retain and skip controller reset, PERST# toggling, and other post-
> init steps.
>
> If the current link speed or lane width does not satisfy the constraints
> specified by max-link-speed or num-lanes in the device tree, fall back to
> normal initialization and retrain the link instead of retaining it.
>
> Configure the DBI and ATU base addresses in the retention path, since the
> bootloader may use different base addresses than those provided by the
> device tree.
>
> Also fix the -EPROBE_DEFER error handling path to return 0 instead of
> propagating the error, avoiding unnecessary cleanup when probe deferral is
> requested.
>
> Tested-by: Qiang Yu <qiang.yu at oss.qualcomm.com>
> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru at oss.qualcomm.com>
> ---
> drivers/pci/controller/dwc/pcie-designware.h | 1 +
> drivers/pci/controller/dwc/pcie-qcom.c | 62 +++++++++++++++++++++++++---
> 2 files changed, 58 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index 3e69ef60165b..be6c4abf31e8 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -450,6 +450,7 @@ struct dw_pcie_rp {
> bool ecam_enabled;
> bool native_ecam;
> bool skip_l23_ready;
> + bool link_retain;
> };
>
> struct dw_pcie_ep_ops {
> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
> index bfe873cbf44f..b061eaa227b3 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> @@ -253,12 +253,14 @@ struct qcom_pcie_ops {
> * @override_no_snoop: Override NO_SNOOP attribute in TLP to enable cache
> * snooping
> * @firmware_managed: Set if the Root Complex is firmware managed
> + * @link_retain: Set if controller supports retaining link from bootloader
> */
> struct qcom_pcie_cfg {
> const struct qcom_pcie_ops *ops;
> bool override_no_snoop;
> bool firmware_managed;
> bool no_l0s;
> + bool link_retain;
> };
>
> struct qcom_pcie_perst {
> @@ -960,6 +962,42 @@ static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie)
> return 0;
> }
>
> +/*
> + * Determine whether the link established by the bootloader can be reused.
> + *
> + * Reuse the existing link only if its current speed and lane count match
> + * the max-link-speed and num-lanes specified in Device Tree; otherwise,
> + * retrain the link.
> + */
> +static bool qcom_pcie_check_link_retain(struct qcom_pcie *pcie)
> +{
> + u32 cap, speed, val, ltssm, width;
> + struct dw_pcie *pci = pcie->pci;
> + u8 offset;
> +
> + val = readl(pcie->parf + PARF_LTSSM);
> + ltssm = val & 0x1f;
> + if ((val & LTSSM_EN) &&
> + (ltssm == DW_PCIE_LTSSM_L0 || ltssm == DW_PCIE_LTSSM_L1_IDLE)) {
> + qcom_pcie_configure_dbi_atu_base(pcie);
> +
> + offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> + cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
> + speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, cap);
> + width = dw_pcie_link_get_max_link_width(pci);
> +
> + if (pci->max_link_speed > 0 && speed > pci->max_link_speed)
I think I raised this concern already, but this goes against what
max-link-speed is supposed to do, i.e. this will not retrain the link if
the bootloader had initialized the link to a speed faster than what the
DT requested
> + return false;
> +
> + if (pci->num_lanes > 0 && width > pci->num_lanes)
> + return false;
Similarly, this should be ==
Konrad
More information about the linux-phy
mailing list