* [PATCH v2 01/10] PCI: tegra194: Propagate REFCLK select GPIO errors
2026-10-21 6:13 [PATCH v2 00/10] PCI: tegra194: Fix EP and Root Port corner cases Manikanta Maddireddy
@ 2026-10-21 6:13 ` Manikanta Maddireddy
2026-10-21 15:14 ` Frank Li
2026-10-21 6:13 ` [PATCH v2 02/10] PCI: tegra194: Check core reset deassertion Manikanta Maddireddy
` (8 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Manikanta Maddireddy @ 2026-10-21 6:13 UTC (permalink / raw)
To: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci
Cc: robh, thierry.reding, jonathanh, kishon, Frank.Li, vidyas,
cassel, den, marco.crivellari, andriy.shevchenko, linux-tegra,
linux-kernel, mmaddireddy
devm_gpiod_get_optional() returns NULL only when the optional GPIO is
absent. Other error pointers, including -EPROBE_DEFER, describe real
failures and should not be converted to NULL.
Return dev_err_probe() errors for nvidia,refclk-select so probe does not
continue without a GPIO that exists but is not ready or could not be
requested.
Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194")
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
Changes V1 -> V2: None
drivers/pci/controller/dwc/pcie-tegra194.c | 15 +++------------
1 file changed, 3 insertions(+), 12 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 9b349b3430f1..6104a22d930e 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1206,18 +1206,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev,
"nvidia,refclk-select",
GPIOD_OUT_HIGH);
- if (IS_ERR(pcie->pex_refclk_sel_gpiod)) {
- int err = PTR_ERR(pcie->pex_refclk_sel_gpiod);
- const char *level = KERN_ERR;
-
- if (err == -EPROBE_DEFER)
- level = KERN_DEBUG;
-
- dev_printk(level, pcie->dev,
- dev_fmt("Failed to get REFCLK select GPIOs: %d\n"),
- err);
- pcie->pex_refclk_sel_gpiod = NULL;
- }
+ if (IS_ERR(pcie->pex_refclk_sel_gpiod))
+ return dev_err_probe(pcie->dev, PTR_ERR(pcie->pex_refclk_sel_gpiod),
+ "Failed to get REFCLK select GPIO\n");
return 0;
}
--
2.34.1
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 01/10] PCI: tegra194: Propagate REFCLK select GPIO errors
2026-10-21 6:13 ` [PATCH v2 01/10] PCI: tegra194: Propagate REFCLK select GPIO errors Manikanta Maddireddy
@ 2026-10-21 15:14 ` Frank Li
0 siblings, 0 replies; 21+ messages in thread
From: Frank Li @ 2026-10-21 15:14 UTC (permalink / raw)
To: Manikanta Maddireddy
Cc: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci, robh,
thierry.reding, jonathanh, kishon, Frank.Li, vidyas, cassel, den,
marco.crivellari, andriy.shevchenko, linux-tegra, linux-kernel
On Wed, Oct 21, 2026 at 11:43:40AM +0530, Manikanta Maddireddy wrote:
> devm_gpiod_get_optional() returns NULL only when the optional GPIO is
> absent. Other error pointers, including -EPROBE_DEFER, describe real
> failures and should not be converted to NULL.
>
> Return dev_err_probe() errors for nvidia,refclk-select so probe does not
> continue without a GPIO that exists but is not ready or could not be
> requested.
>
> Fixes: c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194")
> Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Changes V1 -> V2: None
>
> drivers/pci/controller/dwc/pcie-tegra194.c | 15 +++------------
> 1 file changed, 3 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 9b349b3430f1..6104a22d930e 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -1206,18 +1206,9 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
> pcie->pex_refclk_sel_gpiod = devm_gpiod_get_optional(pcie->dev,
> "nvidia,refclk-select",
> GPIOD_OUT_HIGH);
> - if (IS_ERR(pcie->pex_refclk_sel_gpiod)) {
> - int err = PTR_ERR(pcie->pex_refclk_sel_gpiod);
> - const char *level = KERN_ERR;
> -
> - if (err == -EPROBE_DEFER)
> - level = KERN_DEBUG;
> -
> - dev_printk(level, pcie->dev,
> - dev_fmt("Failed to get REFCLK select GPIOs: %d\n"),
> - err);
> - pcie->pex_refclk_sel_gpiod = NULL;
> - }
> + if (IS_ERR(pcie->pex_refclk_sel_gpiod))
> + return dev_err_probe(pcie->dev, PTR_ERR(pcie->pex_refclk_sel_gpiod),
> + "Failed to get REFCLK select GPIO\n");
>
> return 0;
> }
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 02/10] PCI: tegra194: Check core reset deassertion
2026-10-21 6:13 [PATCH v2 00/10] PCI: tegra194: Fix EP and Root Port corner cases Manikanta Maddireddy
2026-10-21 6:13 ` [PATCH v2 01/10] PCI: tegra194: Propagate REFCLK select GPIO errors Manikanta Maddireddy
@ 2026-10-21 6:13 ` Manikanta Maddireddy
2026-10-21 15:16 ` Frank Li
2026-10-21 6:13 ` [PATCH v2 03/10] PCI: tegra194: Fix Endpoint PERST# IRQ suspend race Manikanta Maddireddy
` (7 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Manikanta Maddireddy @ 2026-10-21 6:13 UTC (permalink / raw)
To: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci
Cc: robh, thierry.reding, jonathanh, kishon, Frank.Li, vidyas,
cassel, den, marco.crivellari, andriy.shevchenko, linux-tegra,
linux-kernel, mmaddireddy
Several paths access DBI registers after deasserting the controller core
reset. If reset_control_deassert() fails, those DBI accesses can trigger a
CBB timeout, or setup can return success with the core still in reset.
Check core reset deassertion in Root Port setup, the DLF retry path and the
Endpoint PERST# deassert path. Unwind before DBI access when deassertion
fails.
Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
Changes V1 -> V2: None
drivers/pci/controller/dwc/pcie-tegra194.c | 23 +++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 6104a22d930e..89dbef83dd9e 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -954,6 +954,7 @@ static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
struct dw_pcie_rp *pp = &pci->pp;
u32 val, offset, tmp;
+ int ret;
bool retry = true;
if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
@@ -1009,7 +1010,12 @@ static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
appl_writel(pcie, val, APPL_CTRL);
reset_control_assert(pcie->core_rst);
- reset_control_deassert(pcie->core_rst);
+ ret = reset_control_deassert(pcie->core_rst);
+ if (ret) {
+ dev_err(pci->dev, "Failed to deassert core reset: %d\n",
+ ret);
+ return ret;
+ }
offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_DLF);
val = dw_pcie_readl_dbi(pci, offset + PCI_DLF_CAP);
@@ -1455,10 +1461,16 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie,
pcie->atu_dma_res->start & APPL_CFG_IATU_DMA_BASE_ADDR_MASK,
APPL_CFG_IATU_DMA_BASE_ADDR);
- reset_control_deassert(pcie->core_rst);
+ ret = reset_control_deassert(pcie->core_rst);
+ if (ret) {
+ dev_err(pcie->dev, "Failed to deassert core reset: %d\n", ret);
+ goto fail_core_rst;
+ }
return ret;
+fail_core_rst:
+ tegra_pcie_disable_phy(pcie);
fail_phy:
reset_control_assert(pcie->core_apb_rst);
fail_core_apb_rst:
@@ -1853,7 +1865,11 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
LTR_NOSNOOP_MSG_REQ;
appl_writel(pcie, val, APPL_LTR_MSG_1);
- reset_control_deassert(pcie->core_rst);
+ ret = reset_control_deassert(pcie->core_rst);
+ if (ret) {
+ dev_err(dev, "Failed to deassert core reset: %d\n", ret);
+ goto fail_core_rst;
+ }
/* Perform cleanup that requires refclk and core reset deasserted */
pci_epc_deinit_notify(pcie->pci.ep.epc);
@@ -1927,6 +1943,7 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
fail_init_complete:
reset_control_assert(pcie->core_rst);
+fail_core_rst:
tegra_pcie_disable_phy(pcie);
fail_phy:
reset_control_assert(pcie->core_apb_rst);
--
2.34.1
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 02/10] PCI: tegra194: Check core reset deassertion
2026-10-21 6:13 ` [PATCH v2 02/10] PCI: tegra194: Check core reset deassertion Manikanta Maddireddy
@ 2026-10-21 15:16 ` Frank Li
0 siblings, 0 replies; 21+ messages in thread
From: Frank Li @ 2026-10-21 15:16 UTC (permalink / raw)
To: Manikanta Maddireddy
Cc: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci, robh,
thierry.reding, jonathanh, kishon, Frank.Li, vidyas, cassel, den,
marco.crivellari, andriy.shevchenko, linux-tegra, linux-kernel
On Wed, Oct 21, 2026 at 11:43:41AM +0530, Manikanta Maddireddy wrote:
> Several paths access DBI registers after deasserting the controller core
> reset. If reset_control_deassert() fails, those DBI accesses can trigger a
> CBB timeout, or setup can return success with the core still in reset.
>
> Check core reset deassertion in Root Port setup, the DLF retry path and the
> Endpoint PERST# deassert path. Unwind before DBI access when deassertion
> fails.
>
> Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
> Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Changes V1 -> V2: None
>
> drivers/pci/controller/dwc/pcie-tegra194.c | 23 +++++++++++++++++++---
> 1 file changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 6104a22d930e..89dbef83dd9e 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -954,6 +954,7 @@ static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
> struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
> struct dw_pcie_rp *pp = &pci->pp;
> u32 val, offset, tmp;
> + int ret;
> bool retry = true;
>
> if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
> @@ -1009,7 +1010,12 @@ static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
> appl_writel(pcie, val, APPL_CTRL);
>
> reset_control_assert(pcie->core_rst);
> - reset_control_deassert(pcie->core_rst);
> + ret = reset_control_deassert(pcie->core_rst);
> + if (ret) {
> + dev_err(pci->dev, "Failed to deassert core reset: %d\n",
> + ret);
> + return ret;
> + }
>
> offset = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_DLF);
> val = dw_pcie_readl_dbi(pci, offset + PCI_DLF_CAP);
> @@ -1455,10 +1461,16 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie,
> pcie->atu_dma_res->start & APPL_CFG_IATU_DMA_BASE_ADDR_MASK,
> APPL_CFG_IATU_DMA_BASE_ADDR);
>
> - reset_control_deassert(pcie->core_rst);
> + ret = reset_control_deassert(pcie->core_rst);
> + if (ret) {
> + dev_err(pcie->dev, "Failed to deassert core reset: %d\n", ret);
> + goto fail_core_rst;
> + }
>
> return ret;
>
> +fail_core_rst:
> + tegra_pcie_disable_phy(pcie);
> fail_phy:
> reset_control_assert(pcie->core_apb_rst);
> fail_core_apb_rst:
> @@ -1853,7 +1865,11 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
> LTR_NOSNOOP_MSG_REQ;
> appl_writel(pcie, val, APPL_LTR_MSG_1);
>
> - reset_control_deassert(pcie->core_rst);
> + ret = reset_control_deassert(pcie->core_rst);
> + if (ret) {
> + dev_err(dev, "Failed to deassert core reset: %d\n", ret);
> + goto fail_core_rst;
> + }
>
> /* Perform cleanup that requires refclk and core reset deasserted */
> pci_epc_deinit_notify(pcie->pci.ep.epc);
> @@ -1927,6 +1943,7 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
>
> fail_init_complete:
> reset_control_assert(pcie->core_rst);
> +fail_core_rst:
> tegra_pcie_disable_phy(pcie);
> fail_phy:
> reset_control_assert(pcie->core_apb_rst);
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 03/10] PCI: tegra194: Fix Endpoint PERST# IRQ suspend race
2026-10-21 6:13 [PATCH v2 00/10] PCI: tegra194: Fix EP and Root Port corner cases Manikanta Maddireddy
2026-10-21 6:13 ` [PATCH v2 01/10] PCI: tegra194: Propagate REFCLK select GPIO errors Manikanta Maddireddy
2026-10-21 6:13 ` [PATCH v2 02/10] PCI: tegra194: Check core reset deassertion Manikanta Maddireddy
@ 2026-10-21 6:13 ` Manikanta Maddireddy
2026-10-21 15:19 ` Frank Li
2026-10-21 6:13 ` [PATCH v2 04/10] PCI: tegra194: Do not skip no-link Root Port remove cleanup Manikanta Maddireddy
` (6 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Manikanta Maddireddy @ 2026-10-21 6:13 UTC (permalink / raw)
To: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci
Cc: robh, thierry.reding, jonathanh, kishon, Frank.Li, vidyas,
cassel, den, marco.crivellari, andriy.shevchenko, linux-tegra,
linux-kernel, mmaddireddy
Endpoint system suspend is allowed only while the endpoint is disabled.
Checking ep_state before disabling the PERST# IRQ leaves a window in which
PERST# deassertion starts the threaded handler after the check. The
handler can enable the controller, clocks and PHYs before disable_irq()
returns, but suspend still succeeds based on the earlier disabled state.
The system then proceeds into suspend with an active endpoint that should
have caused the suspend callback to reject the transition.
Disable the PERST# IRQ before checking ep_state. disable_irq() waits for
an already-running threaded handler to finish, so the state check sees
its completed transition and no new handler can enable the endpoint.
Re-enable the IRQ immediately if the endpoint is enabled and reject
suspend. Otherwise, keep it disabled until the normal resume callback.
This also balances the IRQ disable when another device aborts suspend
and PM rolls back through .resume without calling .resume_early.
This preserves the existing policy that PERST# is not serviced while the
endpoint is suspended. It serializes the software state check with the
IRQ thread; it does not make PERST# a wakeup source or guarantee delivery
of transitions during suspension.
Wrap the PM ops pointer with pm_sleep_ptr() so the callbacks are used
only when system sleep is enabled.
Fixes: c76f8eae7d46 ("PCI: tegra194: Allow system suspend when the Endpoint link is not up")
Link: https://lore.kernel.org/r/20260324190755.1094879-10-mmaddireddy@nvidia.com
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
Changes V1 -> V2:
- Expand the commit message to explain the active-endpoint suspend race,
IRQ-thread synchronization and suspend rollback handling.
- Clarify that PERST# is not serviced while the endpoint is suspended.
- Add a comment explaining why the IRQ thread is drained before checking
endpoint state.
drivers/pci/controller/dwc/pcie-tegra194.c | 34 ++++++++++++++--------
1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 89dbef83dd9e..0f895c766a71 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2374,19 +2374,30 @@ static int tegra_pcie_dw_suspend(struct device *dev)
{
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
- if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
- if (pcie->ep_state == EP_STATE_ENABLED) {
- dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n");
- return -EPERM;
- }
-
- disable_irq(pcie->pex_rst_irq);
+ if (pcie->of_data->mode != DW_PCIE_EP_TYPE)
return 0;
+
+ /* Drain the PERST# thread before checking whether the endpoint is idle. */
+ disable_irq(pcie->pex_rst_irq);
+ if (pcie->ep_state == EP_STATE_ENABLED) {
+ enable_irq(pcie->pex_rst_irq);
+ dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n");
+ return -EPERM;
}
return 0;
}
+static int tegra_pcie_dw_resume(struct device *dev)
+{
+ struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
+
+ if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
+ enable_irq(pcie->pex_rst_irq);
+
+ return 0;
+}
+
static int tegra_pcie_dw_suspend_late(struct device *dev)
{
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
@@ -2462,10 +2473,8 @@ static int tegra_pcie_dw_resume_early(struct device *dev)
struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
u32 val;
- if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
- enable_irq(pcie->pex_rst_irq);
+ if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
return 0;
- }
if (!pcie->link_state)
return 0;
@@ -2569,10 +2578,11 @@ static const struct of_device_id tegra_pcie_dw_of_match[] = {
static const struct dev_pm_ops tegra_pcie_dw_pm_ops = {
.suspend = tegra_pcie_dw_suspend,
+ .resume = tegra_pcie_dw_resume,
.suspend_late = tegra_pcie_dw_suspend_late,
+ .resume_early = tegra_pcie_dw_resume_early,
.suspend_noirq = tegra_pcie_dw_suspend_noirq,
.resume_noirq = tegra_pcie_dw_resume_noirq,
- .resume_early = tegra_pcie_dw_resume_early,
};
static struct platform_driver tegra_pcie_dw_driver = {
@@ -2581,7 +2591,7 @@ static struct platform_driver tegra_pcie_dw_driver = {
.shutdown = tegra_pcie_dw_shutdown,
.driver = {
.name = "tegra194-pcie",
- .pm = &tegra_pcie_dw_pm_ops,
+ .pm = pm_sleep_ptr(&tegra_pcie_dw_pm_ops),
.of_match_table = tegra_pcie_dw_of_match,
},
};
--
2.34.1
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 03/10] PCI: tegra194: Fix Endpoint PERST# IRQ suspend race
2026-10-21 6:13 ` [PATCH v2 03/10] PCI: tegra194: Fix Endpoint PERST# IRQ suspend race Manikanta Maddireddy
@ 2026-10-21 15:19 ` Frank Li
0 siblings, 0 replies; 21+ messages in thread
From: Frank Li @ 2026-10-21 15:19 UTC (permalink / raw)
To: Manikanta Maddireddy
Cc: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci, robh,
thierry.reding, jonathanh, kishon, Frank.Li, vidyas, cassel, den,
marco.crivellari, andriy.shevchenko, linux-tegra, linux-kernel
On Wed, Oct 21, 2026 at 11:43:42AM +0530, Manikanta Maddireddy wrote:
> Endpoint system suspend is allowed only while the endpoint is disabled.
> Checking ep_state before disabling the PERST# IRQ leaves a window in which
> PERST# deassertion starts the threaded handler after the check. The
> handler can enable the controller, clocks and PHYs before disable_irq()
> returns, but suspend still succeeds based on the earlier disabled state.
> The system then proceeds into suspend with an active endpoint that should
> have caused the suspend callback to reject the transition.
>
> Disable the PERST# IRQ before checking ep_state. disable_irq() waits for
> an already-running threaded handler to finish, so the state check sees
> its completed transition and no new handler can enable the endpoint.
> Re-enable the IRQ immediately if the endpoint is enabled and reject
> suspend. Otherwise, keep it disabled until the normal resume callback.
> This also balances the IRQ disable when another device aborts suspend
> and PM rolls back through .resume without calling .resume_early.
>
> This preserves the existing policy that PERST# is not serviced while the
> endpoint is suspended. It serializes the software state check with the
> IRQ thread; it does not make PERST# a wakeup source or guarantee delivery
> of transitions during suspension.
>
> Wrap the PM ops pointer with pm_sleep_ptr() so the callbacks are used
> only when system sleep is enabled.
>
> Fixes: c76f8eae7d46 ("PCI: tegra194: Allow system suspend when the Endpoint link is not up")
> Link: https://lore.kernel.org/r/20260324190755.1094879-10-mmaddireddy@nvidia.com
> Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Changes V1 -> V2:
> - Expand the commit message to explain the active-endpoint suspend race,
> IRQ-thread synchronization and suspend rollback handling.
> - Clarify that PERST# is not serviced while the endpoint is suspended.
> - Add a comment explaining why the IRQ thread is drained before checking
> endpoint state.
>
> drivers/pci/controller/dwc/pcie-tegra194.c | 34 ++++++++++++++--------
> 1 file changed, 22 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 89dbef83dd9e..0f895c766a71 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -2374,19 +2374,30 @@ static int tegra_pcie_dw_suspend(struct device *dev)
> {
> struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
>
> - if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
> - if (pcie->ep_state == EP_STATE_ENABLED) {
> - dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n");
> - return -EPERM;
> - }
> -
> - disable_irq(pcie->pex_rst_irq);
> + if (pcie->of_data->mode != DW_PCIE_EP_TYPE)
> return 0;
> +
> + /* Drain the PERST# thread before checking whether the endpoint is idle. */
> + disable_irq(pcie->pex_rst_irq);
> + if (pcie->ep_state == EP_STATE_ENABLED) {
> + enable_irq(pcie->pex_rst_irq);
> + dev_err(dev, "Tegra PCIe is in EP mode, suspend not allowed\n");
> + return -EPERM;
> }
>
> return 0;
> }
>
> +static int tegra_pcie_dw_resume(struct device *dev)
> +{
> + struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
> +
> + if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
> + enable_irq(pcie->pex_rst_irq);
> +
> + return 0;
> +}
> +
> static int tegra_pcie_dw_suspend_late(struct device *dev)
> {
> struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
> @@ -2462,10 +2473,8 @@ static int tegra_pcie_dw_resume_early(struct device *dev)
> struct tegra_pcie_dw *pcie = dev_get_drvdata(dev);
> u32 val;
>
> - if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
> - enable_irq(pcie->pex_rst_irq);
> + if (pcie->of_data->mode == DW_PCIE_EP_TYPE)
> return 0;
> - }
>
> if (!pcie->link_state)
> return 0;
> @@ -2569,10 +2578,11 @@ static const struct of_device_id tegra_pcie_dw_of_match[] = {
>
> static const struct dev_pm_ops tegra_pcie_dw_pm_ops = {
> .suspend = tegra_pcie_dw_suspend,
> + .resume = tegra_pcie_dw_resume,
> .suspend_late = tegra_pcie_dw_suspend_late,
> + .resume_early = tegra_pcie_dw_resume_early,
> .suspend_noirq = tegra_pcie_dw_suspend_noirq,
> .resume_noirq = tegra_pcie_dw_resume_noirq,
> - .resume_early = tegra_pcie_dw_resume_early,
> };
>
> static struct platform_driver tegra_pcie_dw_driver = {
> @@ -2581,7 +2591,7 @@ static struct platform_driver tegra_pcie_dw_driver = {
> .shutdown = tegra_pcie_dw_shutdown,
> .driver = {
> .name = "tegra194-pcie",
> - .pm = &tegra_pcie_dw_pm_ops,
> + .pm = pm_sleep_ptr(&tegra_pcie_dw_pm_ops),
> .of_match_table = tegra_pcie_dw_of_match,
> },
> };
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 04/10] PCI: tegra194: Do not skip no-link Root Port remove cleanup
2026-10-21 6:13 [PATCH v2 00/10] PCI: tegra194: Fix EP and Root Port corner cases Manikanta Maddireddy
` (2 preceding siblings ...)
2026-10-21 6:13 ` [PATCH v2 03/10] PCI: tegra194: Fix Endpoint PERST# IRQ suspend race Manikanta Maddireddy
@ 2026-10-21 6:13 ` Manikanta Maddireddy
2026-10-21 15:22 ` Frank Li
2026-10-21 6:13 ` [PATCH v2 05/10] PCI: tegra194: Check for 16 GT/s capability before programming Manikanta Maddireddy
` (5 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Manikanta Maddireddy @ 2026-10-21 6:13 UTC (permalink / raw)
To: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci
Cc: robh, thierry.reding, jonathanh, kishon, Frank.Li, vidyas,
cassel, den, marco.crivellari, andriy.shevchenko, linux-tegra,
linux-kernel, mmaddireddy
tegra_pcie_config_rp() deinitializes the controller and disables runtime PM
when link training fails, then probe treats -ENOMEDIUM as success so the
driver can remain bound without a link.
remove() returned immediately when the Root Port link was down. That skips
common cleanup such as tegra_bpmp_put() and deasserting the refclk-select
GPIO. Keep link-dependent controller teardown conditional, but always run
common remove cleanup.
Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
Changes V1 -> V2: None
drivers/pci/controller/dwc/pcie-tegra194.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 0f895c766a71..fb8084cef38b 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2352,19 +2352,19 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev)
struct dw_pcie_ep *ep = &pcie->pci.ep;
if (pcie->of_data->mode == DW_PCIE_RC_TYPE) {
- if (!pcie->link_state)
- return;
-
- debugfs_remove_recursive(pcie->debugfs);
- tegra_pcie_deinit_controller(pcie);
- pm_runtime_put_sync(pcie->dev);
+ if (pcie->link_state) {
+ debugfs_remove_recursive(pcie->debugfs);
+ tegra_pcie_deinit_controller(pcie);
+ pm_runtime_put_sync(pcie->dev);
+ pm_runtime_disable(pcie->dev);
+ }
} else {
disable_irq(pcie->pex_rst_irq);
pex_ep_event_pex_rst_assert(pcie);
dw_pcie_ep_deinit(ep);
+ pm_runtime_disable(pcie->dev);
}
- pm_runtime_disable(pcie->dev);
tegra_bpmp_put(pcie->bpmp);
if (pcie->pex_refclk_sel_gpiod)
gpiod_set_value(pcie->pex_refclk_sel_gpiod, 0);
--
2.34.1
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 04/10] PCI: tegra194: Do not skip no-link Root Port remove cleanup
2026-10-21 6:13 ` [PATCH v2 04/10] PCI: tegra194: Do not skip no-link Root Port remove cleanup Manikanta Maddireddy
@ 2026-10-21 15:22 ` Frank Li
0 siblings, 0 replies; 21+ messages in thread
From: Frank Li @ 2026-10-21 15:22 UTC (permalink / raw)
To: Manikanta Maddireddy
Cc: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci, robh,
thierry.reding, jonathanh, kishon, Frank.Li, vidyas, cassel, den,
marco.crivellari, andriy.shevchenko, linux-tegra, linux-kernel
On Wed, Oct 21, 2026 at 11:43:43AM +0530, Manikanta Maddireddy wrote:
> tegra_pcie_config_rp() deinitializes the controller and disables runtime PM
> when link training fails, then probe treats -ENOMEDIUM as success so the
> driver can remain bound without a link.
>
> remove() returned immediately when the Root Port link was down. That skips
> common cleanup such as tegra_bpmp_put() and deasserting the refclk-select
> GPIO. Keep link-dependent controller teardown conditional, but always run
> common remove cleanup.
>
> Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
> Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Changes V1 -> V2: None
>
> drivers/pci/controller/dwc/pcie-tegra194.c | 14 +++++++-------
> 1 file changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 0f895c766a71..fb8084cef38b 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -2352,19 +2352,19 @@ static void tegra_pcie_dw_remove(struct platform_device *pdev)
> struct dw_pcie_ep *ep = &pcie->pci.ep;
>
> if (pcie->of_data->mode == DW_PCIE_RC_TYPE) {
> - if (!pcie->link_state)
> - return;
> -
> - debugfs_remove_recursive(pcie->debugfs);
> - tegra_pcie_deinit_controller(pcie);
> - pm_runtime_put_sync(pcie->dev);
> + if (pcie->link_state) {
> + debugfs_remove_recursive(pcie->debugfs);
> + tegra_pcie_deinit_controller(pcie);
> + pm_runtime_put_sync(pcie->dev);
> + pm_runtime_disable(pcie->dev);
> + }
> } else {
> disable_irq(pcie->pex_rst_irq);
> pex_ep_event_pex_rst_assert(pcie);
> dw_pcie_ep_deinit(ep);
> + pm_runtime_disable(pcie->dev);
> }
>
> - pm_runtime_disable(pcie->dev);
> tegra_bpmp_put(pcie->bpmp);
> if (pcie->pex_refclk_sel_gpiod)
> gpiod_set_value(pcie->pex_refclk_sel_gpiod, 0);
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 05/10] PCI: tegra194: Check for 16 GT/s capability before programming
2026-10-21 6:13 [PATCH v2 00/10] PCI: tegra194: Fix EP and Root Port corner cases Manikanta Maddireddy
` (3 preceding siblings ...)
2026-10-21 6:13 ` [PATCH v2 04/10] PCI: tegra194: Do not skip no-link Root Port remove cleanup Manikanta Maddireddy
@ 2026-10-21 6:13 ` Manikanta Maddireddy
2026-10-21 15:24 ` Frank Li
2026-10-21 6:13 ` [PATCH v2 06/10] PCI: tegra194: Check for L1SS " Manikanta Maddireddy
` (4 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Manikanta Maddireddy @ 2026-10-21 6:13 UTC (permalink / raw)
To: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci
Cc: robh, thierry.reding, jonathanh, kishon, Frank.Li, vidyas,
cassel, den, marco.crivellari, andriy.shevchenko, linux-tegra,
linux-kernel, mmaddireddy
config_gen3_gen4_eq_presets() added PCI_PL_16GT_LE_CTRL to the result of
dw_pcie_find_ext_capability() without checking whether the 16 GT/s
capability exists. If the capability is absent, the code writes lane
presets at an unrelated configuration offset.
Look up the capability once before the lane loop and skip the 16 GT/s lane
equivalent control programming when it is absent.
Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
Changes V1 -> V2: None
drivers/pci/controller/dwc/pcie-tegra194.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index fb8084cef38b..14031cfaee8b 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -840,7 +840,11 @@ static void tegra_pcie_enable_interrupts(struct dw_pcie_rp *pp)
static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
{
struct dw_pcie *pci = &pcie->pci;
- u32 val, offset, i;
+ u32 pl16g, val, i;
+
+ pl16g = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PL_16GT);
+ if (pl16g)
+ pl16g += PCI_PL_16GT_LE_CTRL;
/* Program init preset */
for (i = 0; i < pcie->num_lanes; i++) {
@@ -851,15 +855,15 @@ static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
GEN3_GEN4_EQ_PRESET_INIT);
dw_pcie_writew_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2), val);
- offset = dw_pcie_find_ext_capability(pci,
- PCI_EXT_CAP_ID_PL_16GT) +
- PCI_PL_16GT_LE_CTRL;
- val = dw_pcie_readb_dbi(pci, offset + i);
+ if (!pl16g)
+ continue;
+
+ val = dw_pcie_readb_dbi(pci, pl16g + i);
FIELD_MODIFY(PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK, &val,
GEN3_GEN4_EQ_PRESET_INIT);
FIELD_MODIFY(PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK, &val,
GEN3_GEN4_EQ_PRESET_INIT);
- dw_pcie_writeb_dbi(pci, offset + i, val);
+ dw_pcie_writeb_dbi(pci, pl16g + i, val);
}
val = dw_pcie_readl_dbi(pci, GEN3_CTRL);
--
2.34.1
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 05/10] PCI: tegra194: Check for 16 GT/s capability before programming
2026-10-21 6:13 ` [PATCH v2 05/10] PCI: tegra194: Check for 16 GT/s capability before programming Manikanta Maddireddy
@ 2026-10-21 15:24 ` Frank Li
0 siblings, 0 replies; 21+ messages in thread
From: Frank Li @ 2026-10-21 15:24 UTC (permalink / raw)
To: Manikanta Maddireddy
Cc: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci, robh,
thierry.reding, jonathanh, kishon, Frank.Li, vidyas, cassel, den,
marco.crivellari, andriy.shevchenko, linux-tegra, linux-kernel
On Wed, Oct 21, 2026 at 11:43:44AM +0530, Manikanta Maddireddy wrote:
> config_gen3_gen4_eq_presets() added PCI_PL_16GT_LE_CTRL to the result of
> dw_pcie_find_ext_capability() without checking whether the 16 GT/s
> capability exists. If the capability is absent, the code writes lane
> presets at an unrelated configuration offset.
>
> Look up the capability once before the lane loop and skip the 16 GT/s lane
> equivalent control programming when it is absent.
>
> Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
> Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Changes V1 -> V2: None
>
> drivers/pci/controller/dwc/pcie-tegra194.c | 16 ++++++++++------
> 1 file changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index fb8084cef38b..14031cfaee8b 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -840,7 +840,11 @@ static void tegra_pcie_enable_interrupts(struct dw_pcie_rp *pp)
> static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
> {
> struct dw_pcie *pci = &pcie->pci;
> - u32 val, offset, i;
> + u32 pl16g, val, i;
> +
> + pl16g = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_PL_16GT);
> + if (pl16g)
> + pl16g += PCI_PL_16GT_LE_CTRL;
>
> /* Program init preset */
> for (i = 0; i < pcie->num_lanes; i++) {
> @@ -851,15 +855,15 @@ static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
> GEN3_GEN4_EQ_PRESET_INIT);
> dw_pcie_writew_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2), val);
>
> - offset = dw_pcie_find_ext_capability(pci,
> - PCI_EXT_CAP_ID_PL_16GT) +
> - PCI_PL_16GT_LE_CTRL;
> - val = dw_pcie_readb_dbi(pci, offset + i);
> + if (!pl16g)
> + continue;
> +
> + val = dw_pcie_readb_dbi(pci, pl16g + i);
> FIELD_MODIFY(PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK, &val,
> GEN3_GEN4_EQ_PRESET_INIT);
> FIELD_MODIFY(PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK, &val,
> GEN3_GEN4_EQ_PRESET_INIT);
> - dw_pcie_writeb_dbi(pci, offset + i, val);
> + dw_pcie_writeb_dbi(pci, pl16g + i, val);
> }
>
> val = dw_pcie_readl_dbi(pci, GEN3_CTRL);
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 06/10] PCI: tegra194: Check for L1SS capability before programming
2026-10-21 6:13 [PATCH v2 00/10] PCI: tegra194: Fix EP and Root Port corner cases Manikanta Maddireddy
` (4 preceding siblings ...)
2026-10-21 6:13 ` [PATCH v2 05/10] PCI: tegra194: Check for 16 GT/s capability before programming Manikanta Maddireddy
@ 2026-10-21 6:13 ` Manikanta Maddireddy
2026-10-21 15:28 ` Frank Li
2026-10-21 6:13 ` [PATCH v2 07/10] PCI: tegra194: Always disable Tegra234 Endpoint L1.2 Manikanta Maddireddy
` (3 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Manikanta Maddireddy @ 2026-10-21 6:13 UTC (permalink / raw)
To: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci
Cc: robh, thierry.reding, jonathanh, kishon, Frank.Li, vidyas,
cassel, den, marco.crivellari, andriy.shevchenko, linux-tegra,
linux-kernel, mmaddireddy
init_host_aspm() programs the L1 PM Substates capability without checking
whether the controller advertises it. If the capability is absent, the
code writes offsets from zero instead of L1SS registers.
Check for the L1SS capability before programming L1SS-specific fields.
Keep RAS-DES discovery, ASPM counter enablement and AFR latency
programming outside that guard because they do not depend on L1SS.
Only create the ASPM counter debugfs file when the RAS-DES capability is
present.
Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
Changes V1 -> V2:
- Use RAS_DES_EVENT_COUNTER_CONTROL to match the preceding DWC register
renames. No functional changes.
drivers/pci/controller/dwc/pcie-tegra194.c | 72 ++++++++++++----------
1 file changed, 41 insertions(+), 31 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 14031cfaee8b..7c349478556d 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -673,37 +673,46 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
pcie->ras_des_cap = dw_pcie_find_ext_capability(&pcie->pci,
PCI_EXT_CAP_ID_VNDR);
-
- /* Enable ASPM counters */
- val = FIELD_PREP(EVENT_COUNTER_ENABLE_MASK, EVENT_COUNTER_ENABLE_ALL);
- val |= FIELD_PREP(EVENT_COUNTER_GROUP_SEL_MASK, EVENT_COUNTER_GROUP_5);
- dw_pcie_writel_dbi(pci, pcie->ras_des_cap +
- RAS_DES_EVENT_COUNTER_CONTROL, val);
-
- /* Program T_cmrt and T_pwr_on values */
- val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
- FIELD_MODIFY(PCI_L1SS_CAP_CM_RESTORE_TIME, &val, pcie->aspm_cmrt);
- FIELD_MODIFY(PCI_L1SS_CAP_P_PWR_ON_VALUE, &val, pcie->aspm_pwr_on_t);
- dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
-
- if (pcie->supports_clkreq)
- pci->l1ss_support = true;
-
- /*
- * Disable L1.2 capability advertisement for Tegra234 Endpoint mode.
- * Tegra234 has a hardware bug where during L1.2 exit, the UPHY PLL is
- * powered up immediately without waiting for REFCLK to stabilize. This
- * causes the PLL to fail to lock to the correct frequency, resulting in
- * PCIe link loss. Since there is no hardware fix available, we prevent
- * the Endpoint from advertising L1.2 support by clearing the L1.2 bits
- * in the L1 PM Substates Capabilities register. This ensures the host
- * will not attempt to enter L1.2 state with this Endpoint.
- */
- if (pcie->of_data->disable_l1_2 &&
- pcie->of_data->mode == DW_PCIE_EP_TYPE) {
+ if (pcie->ras_des_cap) {
+ /* Enable ASPM counters */
+ val = FIELD_PREP(EVENT_COUNTER_ENABLE_MASK,
+ EVENT_COUNTER_ENABLE_ALL);
+ val |= FIELD_PREP(EVENT_COUNTER_GROUP_SEL_MASK,
+ EVENT_COUNTER_GROUP_5);
+ dw_pcie_writel_dbi(pci, pcie->ras_des_cap +
+ RAS_DES_EVENT_COUNTER_CONTROL, val);
+ }
+
+ if (l1ss) {
+ /* Program T_cmrt and T_pwr_on values */
val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
- val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2);
+ FIELD_MODIFY(PCI_L1SS_CAP_CM_RESTORE_TIME, &val,
+ pcie->aspm_cmrt);
+ FIELD_MODIFY(PCI_L1SS_CAP_P_PWR_ON_VALUE, &val,
+ pcie->aspm_pwr_on_t);
dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
+
+ if (pcie->supports_clkreq)
+ pci->l1ss_support = true;
+
+ /*
+ * Disable L1.2 capability advertisement for Tegra234 Endpoint
+ * mode. Tegra234 has a hardware bug where during L1.2 exit,
+ * the UPHY PLL is powered up immediately without waiting for
+ * REFCLK to stabilize. This causes the PLL to fail to lock to
+ * the correct frequency, resulting in PCIe link loss. Since
+ * there is no hardware fix available, prevent the Endpoint
+ * from advertising L1.2 support by clearing the L1.2 bits in
+ * the L1 PM Substates Capabilities register. This ensures the
+ * host will not attempt to enter L1.2 with this Endpoint.
+ */
+ if (pcie->of_data->disable_l1_2 &&
+ pcie->of_data->mode == DW_PCIE_EP_TYPE) {
+ val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
+ val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 |
+ PCI_L1SS_CAP_ASPM_L1_2);
+ dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
+ }
}
/* Program L0s and L1 entrance latencies */
@@ -727,8 +736,9 @@ static void init_debugfs(struct tegra_pcie_dw *pcie)
pcie->debugfs = debugfs_create_dir(name, NULL);
- debugfs_create_devm_seqfile(dev, "aspm_state_cnt", pcie->debugfs,
- aspm_state_cnt);
+ if (pcie->ras_des_cap)
+ debugfs_create_devm_seqfile(dev, "aspm_state_cnt", pcie->debugfs,
+ aspm_state_cnt);
}
#else
static inline void init_host_aspm(struct tegra_pcie_dw *pcie) { return; }
--
2.34.1
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 06/10] PCI: tegra194: Check for L1SS capability before programming
2026-10-21 6:13 ` [PATCH v2 06/10] PCI: tegra194: Check for L1SS " Manikanta Maddireddy
@ 2026-10-21 15:28 ` Frank Li
0 siblings, 0 replies; 21+ messages in thread
From: Frank Li @ 2026-10-21 15:28 UTC (permalink / raw)
To: Manikanta Maddireddy
Cc: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci, robh,
thierry.reding, jonathanh, kishon, Frank.Li, vidyas, cassel, den,
marco.crivellari, andriy.shevchenko, linux-tegra, linux-kernel
On Wed, Oct 21, 2026 at 11:43:45AM +0530, Manikanta Maddireddy wrote:
> init_host_aspm() programs the L1 PM Substates capability without checking
> whether the controller advertises it. If the capability is absent, the
> code writes offsets from zero instead of L1SS registers.
>
> Check for the L1SS capability before programming L1SS-specific fields.
> Keep RAS-DES discovery, ASPM counter enablement and AFR latency
> programming outside that guard because they do not depend on L1SS.
> Only create the ASPM counter debugfs file when the RAS-DES capability is
> present.
>
> Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
> Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Changes V1 -> V2:
> - Use RAS_DES_EVENT_COUNTER_CONTROL to match the preceding DWC register
> renames. No functional changes.
>
> drivers/pci/controller/dwc/pcie-tegra194.c | 72 ++++++++++++----------
> 1 file changed, 41 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 14031cfaee8b..7c349478556d 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -673,37 +673,46 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
>
> pcie->ras_des_cap = dw_pcie_find_ext_capability(&pcie->pci,
> PCI_EXT_CAP_ID_VNDR);
> -
> - /* Enable ASPM counters */
> - val = FIELD_PREP(EVENT_COUNTER_ENABLE_MASK, EVENT_COUNTER_ENABLE_ALL);
> - val |= FIELD_PREP(EVENT_COUNTER_GROUP_SEL_MASK, EVENT_COUNTER_GROUP_5);
> - dw_pcie_writel_dbi(pci, pcie->ras_des_cap +
> - RAS_DES_EVENT_COUNTER_CONTROL, val);
> -
> - /* Program T_cmrt and T_pwr_on values */
> - val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
> - FIELD_MODIFY(PCI_L1SS_CAP_CM_RESTORE_TIME, &val, pcie->aspm_cmrt);
> - FIELD_MODIFY(PCI_L1SS_CAP_P_PWR_ON_VALUE, &val, pcie->aspm_pwr_on_t);
> - dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
> -
> - if (pcie->supports_clkreq)
> - pci->l1ss_support = true;
> -
> - /*
> - * Disable L1.2 capability advertisement for Tegra234 Endpoint mode.
> - * Tegra234 has a hardware bug where during L1.2 exit, the UPHY PLL is
> - * powered up immediately without waiting for REFCLK to stabilize. This
> - * causes the PLL to fail to lock to the correct frequency, resulting in
> - * PCIe link loss. Since there is no hardware fix available, we prevent
> - * the Endpoint from advertising L1.2 support by clearing the L1.2 bits
> - * in the L1 PM Substates Capabilities register. This ensures the host
> - * will not attempt to enter L1.2 state with this Endpoint.
> - */
> - if (pcie->of_data->disable_l1_2 &&
> - pcie->of_data->mode == DW_PCIE_EP_TYPE) {
> + if (pcie->ras_des_cap) {
> + /* Enable ASPM counters */
> + val = FIELD_PREP(EVENT_COUNTER_ENABLE_MASK,
> + EVENT_COUNTER_ENABLE_ALL);
> + val |= FIELD_PREP(EVENT_COUNTER_GROUP_SEL_MASK,
> + EVENT_COUNTER_GROUP_5);
> + dw_pcie_writel_dbi(pci, pcie->ras_des_cap +
> + RAS_DES_EVENT_COUNTER_CONTROL, val);
> + }
> +
> + if (l1ss) {
> + /* Program T_cmrt and T_pwr_on values */
> val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
> - val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2);
> + FIELD_MODIFY(PCI_L1SS_CAP_CM_RESTORE_TIME, &val,
> + pcie->aspm_cmrt);
> + FIELD_MODIFY(PCI_L1SS_CAP_P_PWR_ON_VALUE, &val,
> + pcie->aspm_pwr_on_t);
> dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
> +
> + if (pcie->supports_clkreq)
> + pci->l1ss_support = true;
> +
> + /*
> + * Disable L1.2 capability advertisement for Tegra234 Endpoint
> + * mode. Tegra234 has a hardware bug where during L1.2 exit,
> + * the UPHY PLL is powered up immediately without waiting for
> + * REFCLK to stabilize. This causes the PLL to fail to lock to
> + * the correct frequency, resulting in PCIe link loss. Since
> + * there is no hardware fix available, prevent the Endpoint
> + * from advertising L1.2 support by clearing the L1.2 bits in
> + * the L1 PM Substates Capabilities register. This ensures the
> + * host will not attempt to enter L1.2 with this Endpoint.
> + */
> + if (pcie->of_data->disable_l1_2 &&
> + pcie->of_data->mode == DW_PCIE_EP_TYPE) {
> + val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
> + val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 |
> + PCI_L1SS_CAP_ASPM_L1_2);
> + dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
> + }
> }
>
> /* Program L0s and L1 entrance latencies */
> @@ -727,8 +736,9 @@ static void init_debugfs(struct tegra_pcie_dw *pcie)
>
> pcie->debugfs = debugfs_create_dir(name, NULL);
>
> - debugfs_create_devm_seqfile(dev, "aspm_state_cnt", pcie->debugfs,
> - aspm_state_cnt);
> + if (pcie->ras_des_cap)
> + debugfs_create_devm_seqfile(dev, "aspm_state_cnt", pcie->debugfs,
> + aspm_state_cnt);
> }
> #else
> static inline void init_host_aspm(struct tegra_pcie_dw *pcie) { return; }
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 07/10] PCI: tegra194: Always disable Tegra234 Endpoint L1.2
2026-10-21 6:13 [PATCH v2 00/10] PCI: tegra194: Fix EP and Root Port corner cases Manikanta Maddireddy
` (5 preceding siblings ...)
2026-10-21 6:13 ` [PATCH v2 06/10] PCI: tegra194: Check for L1SS " Manikanta Maddireddy
@ 2026-10-21 6:13 ` Manikanta Maddireddy
2026-10-21 15:32 ` Frank Li
2026-10-21 6:13 ` [PATCH v2 08/10] PCI: tegra194: Guard Endpoint PLL-off error path Manikanta Maddireddy
` (2 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Manikanta Maddireddy @ 2026-10-21 6:13 UTC (permalink / raw)
To: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci
Cc: robh, thierry.reding, jonathanh, kishon, Frank.Li, vidyas,
cassel, den, marco.crivellari, andriy.shevchenko, linux-tegra,
linux-kernel, mmaddireddy
Tegra234 Endpoint mode must not advertise L1.2 because exiting L1.2 can
bring the link down. That hardware workaround is required regardless of
whether the endpoint kernel is built with CONFIG_PCIEASPM.
Move the L1.2 capability masking out of init_host_aspm(), which is compiled
out when CONFIG_PCIEASPM is disabled, and apply it from the common
initialization paths.
Fixes: f59df1d9e6bd ("PCI: tegra194: Disable L1.2 capability of Tegra234 EP")
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
Changes V1 -> V2: None
drivers/pci/controller/dwc/pcie-tegra194.c | 47 +++++++++++++---------
1 file changed, 28 insertions(+), 19 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 7c349478556d..0e6224b6751d 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -611,6 +611,33 @@ static struct pci_ops tegra_pci_ops = {
.write = tegra_pcie_dw_wr_own_conf,
};
+/*
+ * Disable L1.2 capability advertisement for Tegra234 Endpoint mode.
+ * Tegra234 has a hardware bug where during L1.2 exit, the UPHY PLL is
+ * powered up immediately without waiting for REFCLK to stabilize. This causes
+ * the PLL to fail to lock to the correct frequency, resulting in PCIe link
+ * loss. Since there is no hardware fix available, prevent the Endpoint from
+ * advertising L1.2 support so the host will not attempt to enter L1.2 with
+ * this Endpoint.
+ */
+static void tegra_pcie_disable_ep_l1_2(struct tegra_pcie_dw *pcie)
+{
+ struct dw_pcie *pci = &pcie->pci;
+ u32 l1ss, val;
+
+ if (!pcie->of_data->disable_l1_2 ||
+ pcie->of_data->mode != DW_PCIE_EP_TYPE)
+ return;
+
+ l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
+ if (!l1ss)
+ return;
+
+ val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
+ val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2);
+ dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
+}
+
#if defined(CONFIG_PCIEASPM)
static inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event)
{
@@ -694,25 +721,6 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
if (pcie->supports_clkreq)
pci->l1ss_support = true;
-
- /*
- * Disable L1.2 capability advertisement for Tegra234 Endpoint
- * mode. Tegra234 has a hardware bug where during L1.2 exit,
- * the UPHY PLL is powered up immediately without waiting for
- * REFCLK to stabilize. This causes the PLL to fail to lock to
- * the correct frequency, resulting in PCIe link loss. Since
- * there is no hardware fix available, prevent the Endpoint
- * from advertising L1.2 support by clearing the L1.2 bits in
- * the L1 PM Substates Capabilities register. This ensures the
- * host will not attempt to enter L1.2 with this Endpoint.
- */
- if (pcie->of_data->disable_l1_2 &&
- pcie->of_data->mode == DW_PCIE_EP_TYPE) {
- val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
- val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 |
- PCI_L1SS_CAP_ASPM_L1_2);
- dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
- }
}
/* Program L0s and L1 entrance latencies */
@@ -1903,6 +1911,7 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
config_gen3_gen4_eq_presets(pcie);
init_host_aspm(pcie);
+ tegra_pcie_disable_ep_l1_2(pcie);
if (!pcie->of_data->has_l1ss_exit_fix) {
val = dw_pcie_readl_dbi(pci, GEN3_CTRL);
--
2.34.1
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 07/10] PCI: tegra194: Always disable Tegra234 Endpoint L1.2
2026-10-21 6:13 ` [PATCH v2 07/10] PCI: tegra194: Always disable Tegra234 Endpoint L1.2 Manikanta Maddireddy
@ 2026-10-21 15:32 ` Frank Li
0 siblings, 0 replies; 21+ messages in thread
From: Frank Li @ 2026-10-21 15:32 UTC (permalink / raw)
To: Manikanta Maddireddy
Cc: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci, robh,
thierry.reding, jonathanh, kishon, Frank.Li, vidyas, cassel, den,
marco.crivellari, andriy.shevchenko, linux-tegra, linux-kernel
On Wed, Oct 21, 2026 at 11:43:46AM +0530, Manikanta Maddireddy wrote:
> Tegra234 Endpoint mode must not advertise L1.2 because exiting L1.2 can
> bring the link down. That hardware workaround is required regardless of
> whether the endpoint kernel is built with CONFIG_PCIEASPM.
>
> Move the L1.2 capability masking out of init_host_aspm(), which is compiled
> out when CONFIG_PCIEASPM is disabled, and apply it from the common
> initialization paths.
>
> Fixes: f59df1d9e6bd ("PCI: tegra194: Disable L1.2 capability of Tegra234 EP")
> Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Changes V1 -> V2: None
>
> drivers/pci/controller/dwc/pcie-tegra194.c | 47 +++++++++++++---------
> 1 file changed, 28 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 7c349478556d..0e6224b6751d 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -611,6 +611,33 @@ static struct pci_ops tegra_pci_ops = {
> .write = tegra_pcie_dw_wr_own_conf,
> };
>
> +/*
> + * Disable L1.2 capability advertisement for Tegra234 Endpoint mode.
> + * Tegra234 has a hardware bug where during L1.2 exit, the UPHY PLL is
> + * powered up immediately without waiting for REFCLK to stabilize. This causes
> + * the PLL to fail to lock to the correct frequency, resulting in PCIe link
> + * loss. Since there is no hardware fix available, prevent the Endpoint from
> + * advertising L1.2 support so the host will not attempt to enter L1.2 with
> + * this Endpoint.
> + */
> +static void tegra_pcie_disable_ep_l1_2(struct tegra_pcie_dw *pcie)
> +{
> + struct dw_pcie *pci = &pcie->pci;
> + u32 l1ss, val;
> +
> + if (!pcie->of_data->disable_l1_2 ||
> + pcie->of_data->mode != DW_PCIE_EP_TYPE)
> + return;
> +
> + l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
> + if (!l1ss)
> + return;
> +
> + val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
> + val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2);
> + dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
> +}
> +
> #if defined(CONFIG_PCIEASPM)
> static inline u32 event_counter_prog(struct tegra_pcie_dw *pcie, u32 event)
> {
> @@ -694,25 +721,6 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
>
> if (pcie->supports_clkreq)
> pci->l1ss_support = true;
> -
> - /*
> - * Disable L1.2 capability advertisement for Tegra234 Endpoint
> - * mode. Tegra234 has a hardware bug where during L1.2 exit,
> - * the UPHY PLL is powered up immediately without waiting for
> - * REFCLK to stabilize. This causes the PLL to fail to lock to
> - * the correct frequency, resulting in PCIe link loss. Since
> - * there is no hardware fix available, prevent the Endpoint
> - * from advertising L1.2 support by clearing the L1.2 bits in
> - * the L1 PM Substates Capabilities register. This ensures the
> - * host will not attempt to enter L1.2 with this Endpoint.
> - */
> - if (pcie->of_data->disable_l1_2 &&
> - pcie->of_data->mode == DW_PCIE_EP_TYPE) {
> - val = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
> - val &= ~(PCI_L1SS_CAP_PCIPM_L1_2 |
> - PCI_L1SS_CAP_ASPM_L1_2);
> - dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, val);
> - }
> }
>
> /* Program L0s and L1 entrance latencies */
> @@ -1903,6 +1911,7 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
> config_gen3_gen4_eq_presets(pcie);
>
> init_host_aspm(pcie);
> + tegra_pcie_disable_ep_l1_2(pcie);
>
> if (!pcie->of_data->has_l1ss_exit_fix) {
> val = dw_pcie_readl_dbi(pci, GEN3_CTRL);
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 08/10] PCI: tegra194: Guard Endpoint PLL-off error path
2026-10-21 6:13 [PATCH v2 00/10] PCI: tegra194: Fix EP and Root Port corner cases Manikanta Maddireddy
` (6 preceding siblings ...)
2026-10-21 6:13 ` [PATCH v2 07/10] PCI: tegra194: Always disable Tegra234 Endpoint L1.2 Manikanta Maddireddy
@ 2026-10-21 6:13 ` Manikanta Maddireddy
2026-10-21 15:36 ` Frank Li
2026-10-21 6:13 ` [PATCH v2 09/10] PCI: tegra194: Balance core monitor clock on failures Manikanta Maddireddy
2026-10-21 6:13 ` [PATCH v2 10/10] PCI: tegra194: Reject zero MSI interrupt number Manikanta Maddireddy
9 siblings, 1 reply; 21+ messages in thread
From: Manikanta Maddireddy @ 2026-10-21 6:13 UTC (permalink / raw)
To: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci
Cc: robh, thierry.reding, jonathanh, kishon, Frank.Li, vidyas,
cassel, den, marco.crivellari, andriy.shevchenko, linux-tegra,
linux-kernel, mmaddireddy
The Endpoint PERST# deassert path initializes the external-refclk PLL only
when enable_ext_refclk is set, but the error unwind always sent the PLL-off
request.
Guard the PLL-off request with enable_ext_refclk so Tegra234 Endpoint
configurations that did not enable the PLL do not send a spurious BPMP
PLL-off command.
Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support")
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
Changes V1 -> V2: None
drivers/pci/controller/dwc/pcie-tegra194.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 0e6224b6751d..de14a23f9a4d 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1973,7 +1973,8 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
fail_core_apb_rst:
clk_disable_unprepare(pcie->core_clk);
fail_core_clk_enable:
- tegra_pcie_bpmp_set_pll_state(pcie, false);
+ if (pcie->enable_ext_refclk)
+ tegra_pcie_bpmp_set_pll_state(pcie, false);
fail_pll_init:
tegra_pcie_bpmp_set_ctrl_state(pcie, false);
fail_set_ctrl_state:
--
2.34.1
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 08/10] PCI: tegra194: Guard Endpoint PLL-off error path
2026-10-21 6:13 ` [PATCH v2 08/10] PCI: tegra194: Guard Endpoint PLL-off error path Manikanta Maddireddy
@ 2026-10-21 15:36 ` Frank Li
0 siblings, 0 replies; 21+ messages in thread
From: Frank Li @ 2026-10-21 15:36 UTC (permalink / raw)
To: Manikanta Maddireddy
Cc: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci, robh,
thierry.reding, jonathanh, kishon, Frank.Li, vidyas, cassel, den,
marco.crivellari, andriy.shevchenko, linux-tegra, linux-kernel
On Wed, Oct 21, 2026 at 11:43:47AM +0530, Manikanta Maddireddy wrote:
> The Endpoint PERST# deassert path initializes the external-refclk PLL only
> when enable_ext_refclk is set, but the error unwind always sent the PLL-off
> request.
>
> Guard the PLL-off request with enable_ext_refclk so Tegra234 Endpoint
> configurations that did not enable the PLL do not send a spurious BPMP
> PLL-off command.
>
> Fixes: a54e19073718 ("PCI: tegra194: Add Tegra234 PCIe support")
> Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Changes V1 -> V2: None
>
> drivers/pci/controller/dwc/pcie-tegra194.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 0e6224b6751d..de14a23f9a4d 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -1973,7 +1973,8 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
> fail_core_apb_rst:
> clk_disable_unprepare(pcie->core_clk);
> fail_core_clk_enable:
> - tegra_pcie_bpmp_set_pll_state(pcie, false);
> + if (pcie->enable_ext_refclk)
> + tegra_pcie_bpmp_set_pll_state(pcie, false);
> fail_pll_init:
> tegra_pcie_bpmp_set_ctrl_state(pcie, false);
> fail_set_ctrl_state:
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 09/10] PCI: tegra194: Balance core monitor clock on failures
2026-10-21 6:13 [PATCH v2 00/10] PCI: tegra194: Fix EP and Root Port corner cases Manikanta Maddireddy
` (7 preceding siblings ...)
2026-10-21 6:13 ` [PATCH v2 08/10] PCI: tegra194: Guard Endpoint PLL-off error path Manikanta Maddireddy
@ 2026-10-21 6:13 ` Manikanta Maddireddy
2026-10-21 15:43 ` Frank Li
2026-10-21 6:13 ` [PATCH v2 10/10] PCI: tegra194: Reject zero MSI interrupt number Manikanta Maddireddy
9 siblings, 1 reply; 21+ messages in thread
From: Manikanta Maddireddy @ 2026-10-21 6:13 UTC (permalink / raw)
To: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci
Cc: robh, thierry.reding, jonathanh, kishon, Frank.Li, vidyas,
cassel, den, marco.crivellari, andriy.shevchenko, linux-tegra,
linux-kernel, mmaddireddy
tegra_pcie_dw_host_init() enables core_clk_m, but failure paths that leave
after the host init callback can unconfigure the controller without
disabling that clock. The enable error is also only logged, so later
cleanup can try to disable a clock that was never enabled.
Track the monitor clock state, return enable failures, and use a common
helper on retry, remove, suspend, shutdown and host-init failure paths so
the clock is disabled exactly when it was enabled.
Fixes: a86ca8698c88 ("PCI: tegra194: Add core monitor clock support")
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
Changes V1 -> V2: None
drivers/pci/controller/dwc/pcie-tegra194.c | 33 ++++++++++++++++++----
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index de14a23f9a4d..632ecab3c8ea 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -246,6 +246,7 @@ struct tegra_pcie_dw {
void __iomem *appl_base;
struct clk *core_clk;
struct clk *core_clk_m;
+ bool core_clk_m_enabled;
struct reset_control *core_apb_rst;
struct reset_control *core_rst;
struct dw_pcie pci;
@@ -855,6 +856,15 @@ static void tegra_pcie_enable_interrupts(struct dw_pcie_rp *pp)
tegra_pcie_enable_msi_interrupts(pp);
}
+static void tegra_pcie_disable_core_clk_m(struct tegra_pcie_dw *pcie)
+{
+ if (!pcie->core_clk_m_enabled)
+ return;
+
+ clk_disable_unprepare(pcie->core_clk_m);
+ pcie->core_clk_m_enabled = false;
+}
+
static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
{
struct dw_pcie *pci = &pcie->pci;
@@ -914,6 +924,7 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
u32 val;
u16 val_16;
+ int ret;
pp->bridge->ops = &tegra_pci_ops;
@@ -965,8 +976,12 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
}
clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
- if (clk_prepare_enable(pcie->core_clk_m))
- dev_err(pci->dev, "Failed to enable core monitor clock\n");
+ ret = clk_prepare_enable(pcie->core_clk_m);
+ if (ret) {
+ dev_err(pci->dev, "Failed to enable core monitor clock: %d\n", ret);
+ return ret;
+ }
+ pcie->core_clk_m_enabled = true;
return 0;
}
@@ -1049,8 +1064,11 @@ static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
* dw_pcie_host_init(). Disable the clock since below
* tegra_pcie_dw_host_init() will enable it again.
*/
- clk_disable_unprepare(pcie->core_clk_m);
- tegra_pcie_dw_host_init(pp);
+ tegra_pcie_disable_core_clk_m(pcie);
+ ret = tegra_pcie_dw_host_init(pp);
+ if (ret)
+ return ret;
+
dw_pcie_setup_rc(pp);
retry = false;
@@ -1565,6 +1583,7 @@ static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
return 0;
fail_host_init:
+ tegra_pcie_disable_core_clk_m(pcie);
tegra_pcie_unconfig_controller(pcie);
return ret;
}
@@ -1653,7 +1672,7 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
{
- clk_disable_unprepare(pcie->core_clk_m);
+ tegra_pcie_disable_core_clk_m(pcie);
dw_pcie_host_deinit(&pcie->pci.pp);
tegra_pcie_dw_pme_turnoff(pcie);
tegra_pcie_unconfig_controller(pcie);
@@ -2451,7 +2470,7 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
if (!pcie->link_state)
return 0;
- clk_disable_unprepare(pcie->core_clk_m);
+ tegra_pcie_disable_core_clk_m(pcie);
tegra_pcie_dw_pme_turnoff(pcie);
tegra_pcie_unconfig_controller(pcie);
@@ -2488,6 +2507,7 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
return 0;
fail_host_init:
+ tegra_pcie_disable_core_clk_m(pcie);
tegra_pcie_unconfig_controller(pcie);
return ret;
}
@@ -2529,6 +2549,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev)
if (IS_ENABLED(CONFIG_PCI_MSI))
disable_irq(pcie->pci.pp.msi_irq[0]);
+ tegra_pcie_disable_core_clk_m(pcie);
tegra_pcie_dw_pme_turnoff(pcie);
tegra_pcie_unconfig_controller(pcie);
pm_runtime_put_sync(pcie->dev);
--
2.34.1
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 09/10] PCI: tegra194: Balance core monitor clock on failures
2026-10-21 6:13 ` [PATCH v2 09/10] PCI: tegra194: Balance core monitor clock on failures Manikanta Maddireddy
@ 2026-10-21 15:43 ` Frank Li
0 siblings, 0 replies; 21+ messages in thread
From: Frank Li @ 2026-10-21 15:43 UTC (permalink / raw)
To: Manikanta Maddireddy
Cc: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci, robh,
thierry.reding, jonathanh, kishon, Frank.Li, vidyas, cassel, den,
marco.crivellari, andriy.shevchenko, linux-tegra, linux-kernel
On Wed, Oct 21, 2026 at 11:43:48AM +0530, Manikanta Maddireddy wrote:
> tegra_pcie_dw_host_init() enables core_clk_m, but failure paths that leave
> after the host init callback can unconfigure the controller without
> disabling that clock. The enable error is also only logged, so later
> cleanup can try to disable a clock that was never enabled.
>
> Track the monitor clock state, return enable failures, and use a common
> helper on retry, remove, suspend, shutdown and host-init failure paths so
> the clock is disabled exactly when it was enabled.
Feel like checking core_clk_m_enabled for clock is not good desgin. Do you
disable clock when linkdown?
Frank
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 10/10] PCI: tegra194: Reject zero MSI interrupt number
2026-10-21 6:13 [PATCH v2 00/10] PCI: tegra194: Fix EP and Root Port corner cases Manikanta Maddireddy
` (8 preceding siblings ...)
2026-10-21 6:13 ` [PATCH v2 09/10] PCI: tegra194: Balance core monitor clock on failures Manikanta Maddireddy
@ 2026-10-21 6:13 ` Manikanta Maddireddy
2026-10-21 15:44 ` Frank Li
9 siblings, 1 reply; 21+ messages in thread
From: Manikanta Maddireddy @ 2026-10-21 6:13 UTC (permalink / raw)
To: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci
Cc: robh, thierry.reding, jonathanh, kishon, Frank.Li, vidyas,
cassel, den, marco.crivellari, andriy.shevchenko, linux-tegra,
linux-kernel, mmaddireddy
Reject interrupt number zero before computing BIT(irq - 1). The endpoint
IRQ API uses interrupt numbers in the range 1-N, and existing EPF drivers
already follow that convention. This is defensive validation rather than
a correction to the MSI numbering used by those drivers.
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
---
Changes V1 -> V2:
- Retain only MSI interrupt-number-zero validation from v1 patch 10.
- Rewrite the title and commit message around defensive MSI validation,
and remove the Fixes tag.
drivers/pci/controller/dwc/pcie-tegra194.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 632ecab3c8ea..0f49ea6df8bc 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2026,7 +2026,7 @@ static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq)
static int tegra_pcie_ep_raise_msi_irq(struct tegra_pcie_dw *pcie, u16 irq)
{
- if (unlikely(irq > 32))
+ if (unlikely(!irq || irq > 32))
return -EINVAL;
appl_writel(pcie, BIT(irq - 1), APPL_MSI_CTRL_1);
--
2.34.1
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 10/10] PCI: tegra194: Reject zero MSI interrupt number
2026-10-21 6:13 ` [PATCH v2 10/10] PCI: tegra194: Reject zero MSI interrupt number Manikanta Maddireddy
@ 2026-10-21 15:44 ` Frank Li
0 siblings, 0 replies; 21+ messages in thread
From: Frank Li @ 2026-10-21 15:44 UTC (permalink / raw)
To: Manikanta Maddireddy
Cc: lpieralisi, kwilczynski, mani, bhelgaas, linux-pci, robh,
thierry.reding, jonathanh, kishon, Frank.Li, vidyas, cassel, den,
marco.crivellari, andriy.shevchenko, linux-tegra, linux-kernel
On Wed, Oct 21, 2026 at 11:43:49AM +0530, Manikanta Maddireddy wrote:
> Reject interrupt number zero before computing BIT(irq - 1). The endpoint
> IRQ API uses interrupt numbers in the range 1-N, and existing EPF drivers
> already follow that convention. This is defensive validation rather than
> a correction to the MSI numbering used by those drivers.
>
> Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Changes V1 -> V2:
> - Retain only MSI interrupt-number-zero validation from v1 patch 10.
> - Rewrite the title and commit message around defensive MSI validation,
> and remove the Fixes tag.
>
> drivers/pci/controller/dwc/pcie-tegra194.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
> index 632ecab3c8ea..0f49ea6df8bc 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -2026,7 +2026,7 @@ static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq)
>
> static int tegra_pcie_ep_raise_msi_irq(struct tegra_pcie_dw *pcie, u16 irq)
> {
> - if (unlikely(irq > 32))
> + if (unlikely(!irq || irq > 32))
> return -EINVAL;
>
> appl_writel(pcie, BIT(irq - 1), APPL_MSI_CTRL_1);
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread