mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
PCI: tegra: Fix host link initialization
Commitb9ac0f9dc8
("PCI: dwc: Move dw_pcie_setup_rc() to DWC common code") broke enumeration of downstream devices on Tegra: In non-working case (next-20201211): 0001:00:00.0 PCI bridge: NVIDIA Corporation Device 1ad2 (rev a1) 0001:01:00.0 SATA controller: Marvell Technology Group Ltd. Device 9171 (rev 13) 0005:00:00.0 PCI bridge: NVIDIA Corporation Device 1ad0 (rev a1) In working case (v5.10-rc7): 0001:00:00.0 PCI bridge: Molex Incorporated Device 1ad2 (rev a1) 0001:01:00.0 SATA controller: Marvell Technology Group Ltd. Device 9171 (rev 13) 0005:00:00.0 PCI bridge: Molex Incorporated Device 1ad0 (rev a1) 0005:01:00.0 PCI bridge: PLX Technology, Inc. Device 3380 (rev ab) 0005:02:02.0 PCI bridge: PLX Technology, Inc. Device 3380 (rev ab) 0005:03:00.0 USB controller: PLX Technology, Inc. Device 3380 (rev ab) The problem seems to be dw_pcie_setup_rc() is now called twice before and after the link up handling. The fix is to move Tegra's link up handling to .start_link() function like other DWC drivers. Tegra is a bit more complicated than others as it re-inits the whole DWC controller to retry the link. With this, the initialization ordering is restored to match the prior sequence. Fixes:b9ac0f9dc8
("PCI: dwc: Move dw_pcie_setup_rc() to DWC common code") Link: https://lore.kernel.org/r/20201218143905.1614098-1-robh@kernel.org Reported-by: Mian Yousaf Kaukab <ykaukab@suse.de> Tested-by: Mian Yousaf Kaukab <ykaukab@suse.de> Signed-off-by: Rob Herring <robh@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Cc: Thierry Reding <thierry.reding@gmail.com> Cc: Jonathan Hunter <jonathanh@nvidia.com> Cc: Vidya Sagar <vidyas@nvidia.com>
This commit is contained in:
parent
255b2d5248
commit
275e88b06a
1 changed files with 29 additions and 26 deletions
|
@ -853,12 +853,14 @@ static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
|
|||
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
|
||||
}
|
||||
|
||||
static void tegra_pcie_prepare_host(struct pcie_port *pp)
|
||||
static int tegra_pcie_dw_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
u32 val;
|
||||
|
||||
pp->bridge->ops = &tegra_pci_ops;
|
||||
|
||||
if (!pcie->pcie_cap_base)
|
||||
pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
|
||||
PCI_CAP_ID_EXP);
|
||||
|
@ -907,10 +909,24 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
|
|||
dw_pcie_writel_dbi(pci, CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val);
|
||||
}
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val, offset, speed, tmp;
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
bool retry = true;
|
||||
|
||||
if (pcie->mode == DW_PCIE_EP_TYPE) {
|
||||
enable_irq(pcie->pex_rst_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
retry_link:
|
||||
/* Assert RST */
|
||||
val = appl_readl(pcie, APPL_PINMUX);
|
||||
val &= ~APPL_PINMUX_PEX_RST;
|
||||
|
@ -929,19 +945,10 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
|
|||
appl_writel(pcie, val, APPL_PINMUX);
|
||||
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
u32 val, tmp, offset, speed;
|
||||
|
||||
pp->bridge->ops = &tegra_pci_ops;
|
||||
|
||||
tegra_pcie_prepare_host(pp);
|
||||
|
||||
if (dw_pcie_wait_for_link(pci)) {
|
||||
if (!retry)
|
||||
return 0;
|
||||
/*
|
||||
* There are some endpoints which can't get the link up if
|
||||
* root port has Data Link Feature (DLF) enabled.
|
||||
|
@ -975,10 +982,11 @@ static int tegra_pcie_dw_host_init(struct pcie_port *pp)
|
|||
val &= ~PCI_DLF_EXCHANGE_ENABLE;
|
||||
dw_pcie_writel_dbi(pci, offset, val);
|
||||
|
||||
tegra_pcie_prepare_host(pp);
|
||||
tegra_pcie_dw_host_init(pp);
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
if (dw_pcie_wait_for_link(pci))
|
||||
return 0;
|
||||
retry = false;
|
||||
goto retry_link;
|
||||
}
|
||||
|
||||
speed = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA) &
|
||||
|
@ -998,15 +1006,6 @@ static int tegra_pcie_dw_link_up(struct dw_pcie *pci)
|
|||
return !!(val & PCI_EXP_LNKSTA_DLLLA);
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
|
||||
enable_irq(pcie->pex_rst_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_pcie_dw_stop_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
|
@ -2215,6 +2214,10 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
|
|||
goto fail_host_init;
|
||||
}
|
||||
|
||||
ret = tegra_pcie_dw_start_link(&pcie->pci);
|
||||
if (ret < 0)
|
||||
goto fail_host_init;
|
||||
|
||||
/* Restore MSI interrupt vector */
|
||||
dw_pcie_writel_dbi(&pcie->pci, PORT_LOGIC_MSI_CTRL_INT_0_EN,
|
||||
pcie->msi_ctrl_int);
|
||||
|
|
Loading…
Reference in a new issue