Re: [PATCH v2 3/3] PCI: qcom: Program T_POWER_ON

From: Bjorn Helgaas

Date: Mon Feb 23 2026 - 10:54:19 EST


Mention L1 PM Substates in the subject so we know where to look for
T_POWER_ON.

On Mon, Feb 23, 2026 at 04:43:32PM +0530, Krishna Chaitanya Chundru wrote:
> Some platforms have incorrect T_POWER_ON value programmed in hardware.
> Generally these will be corrected by bootloaders, but not all targets
> support bootloaders to program correct values due to that
> LTR_L1.2_THRESHOLD value calculated by aspm driver can be wrong, which
> can result in improper L1.2 exit behavior and can trigger AER's.

"AER" is a little bit too specific here. The actual behavior is some
PCIe error, e.g., Bad DLLP, Data Link Protol Error, etc (if you know
the actual error, please mention it here), and if AER happens to be
supported and enabled, the error may be *reported* via AER.

> Parse "t-power-on-us" property from each root port node and program them
> as part of host initialization using dw_pcie_program_t_power_on() before
> link training.
>
> This property in added to the dtschema here[1].
>
> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@xxxxxxxxxxxxxxxx>
> Link[1]: https://lore.kernel.org/all/20260205093346.667898-1-krishna.chundru@xxxxxxxxxxxxxxxx/
> ---
> drivers/pci/controller/dwc/pcie-qcom.c | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
> index 67a16af69ddc75fca1b123e70715e692a91a9135..489ed64c1df0fa3ed9f6b0d4c3e0bb65cfc3308e 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> @@ -269,6 +269,7 @@ struct qcom_pcie_perst {
> struct qcom_pcie_port {
> struct list_head list;
> struct phy *phy;
> + u32 t_power_on;

Please mention L1 PM Substates somewhere here (comment, member name,
function name?) Currently there's nothing in the code that a reader
could look up in a spec.

> struct list_head perst;
> };
>
> @@ -1283,6 +1284,16 @@ static int qcom_pcie_phy_power_on(struct qcom_pcie *pcie)
> return 0;
> }
>
> +static int qcom_pcie_configure_ports(struct qcom_pcie *pcie)
> +{
> + struct qcom_pcie_port *port;
> +
> + list_for_each_entry(port, &pcie->ports, list)
> + dw_pcie_program_t_power_on(pcie->pci, port->t_power_on);
> +
> + return 0;

Why return a value if it's never used or checked? If we need a return
value later, we can add it then.

> +}
> +
> static int qcom_pcie_host_init(struct dw_pcie_rp *pp)
> {
> struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> @@ -1317,6 +1328,8 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp)
> dw_pcie_remove_capability(pcie->pci, PCI_CAP_ID_MSIX);
> dw_pcie_remove_ext_capability(pcie->pci, PCI_EXT_CAP_ID_DPC);
>
> + qcom_pcie_configure_ports(pcie);
> +
> qcom_pcie_perst_deassert(pcie);
>
> if (pcie->cfg->ops->config_sid) {
> @@ -1759,6 +1772,8 @@ static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node
> if (ret)
> return ret;
>
> + of_property_read_u32(node, "t-power-on-us", &port->t_power_on);
> +
> port->phy = phy;
> INIT_LIST_HEAD(&port->list);
> list_add_tail(&port->list, &pcie->ports);
>
> --
> 2.34.1
>