Merge branch 'pci/controller/dwc'

- Wait for link to come up only if we've initiated link training (Ajay
  Agarwal)

- Save and restore imx6 Root Port MSI control to work around hardware
  defect (Richard Zhu)

* pci/controller/dwc:
  PCI: imx6: Save and restore root port MSI control in suspend and resume
  PCI: dwc: Wait for link up only if link is started
This commit is contained in:
Bjorn Helgaas 2023-06-26 12:59:58 -05:00
commit 99f7b80906
4 changed files with 46 additions and 11 deletions

View File

@ -80,6 +80,7 @@ struct imx6_pcie {
struct clk *pcie; struct clk *pcie;
struct clk *pcie_aux; struct clk *pcie_aux;
struct regmap *iomuxc_gpr; struct regmap *iomuxc_gpr;
u16 msi_ctrl;
u32 controller_id; u32 controller_id;
struct reset_control *pciephy_reset; struct reset_control *pciephy_reset;
struct reset_control *apps_reset; struct reset_control *apps_reset;
@ -1178,6 +1179,26 @@ pm_turnoff_sleep:
usleep_range(1000, 10000); usleep_range(1000, 10000);
} }
static void imx6_pcie_msi_save_restore(struct imx6_pcie *imx6_pcie, bool save)
{
u8 offset;
u16 val;
struct dw_pcie *pci = imx6_pcie->pci;
if (pci_msi_enabled()) {
offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
if (save) {
val = dw_pcie_readw_dbi(pci, offset + PCI_MSI_FLAGS);
imx6_pcie->msi_ctrl = val;
} else {
dw_pcie_dbi_ro_wr_en(pci);
val = imx6_pcie->msi_ctrl;
dw_pcie_writew_dbi(pci, offset + PCI_MSI_FLAGS, val);
dw_pcie_dbi_ro_wr_dis(pci);
}
}
}
static int imx6_pcie_suspend_noirq(struct device *dev) static int imx6_pcie_suspend_noirq(struct device *dev)
{ {
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev); struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
@ -1186,6 +1207,7 @@ static int imx6_pcie_suspend_noirq(struct device *dev)
if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND)) if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND))
return 0; return 0;
imx6_pcie_msi_save_restore(imx6_pcie, true);
imx6_pcie_pm_turnoff(imx6_pcie); imx6_pcie_pm_turnoff(imx6_pcie);
imx6_pcie_stop_link(imx6_pcie->pci); imx6_pcie_stop_link(imx6_pcie->pci);
imx6_pcie_host_exit(pp); imx6_pcie_host_exit(pp);
@ -1205,6 +1227,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
ret = imx6_pcie_host_init(pp); ret = imx6_pcie_host_init(pp);
if (ret) if (ret)
return ret; return ret;
imx6_pcie_msi_save_restore(imx6_pcie, false);
dw_pcie_setup_rc(pp); dw_pcie_setup_rc(pp);
if (imx6_pcie->link_is_up) if (imx6_pcie->link_is_up)

View File

@ -485,14 +485,19 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
if (ret) if (ret)
goto err_remove_edma; goto err_remove_edma;
if (!dw_pcie_link_up(pci)) { if (dw_pcie_link_up(pci)) {
dw_pcie_print_link_status(pci);
} else {
ret = dw_pcie_start_link(pci); ret = dw_pcie_start_link(pci);
if (ret) if (ret)
goto err_remove_edma; goto err_remove_edma;
}
/* Ignore errors, the link may come up later */ if (pci->ops && pci->ops->start_link) {
dw_pcie_wait_for_link(pci); ret = dw_pcie_wait_for_link(pci);
if (ret)
goto err_stop_link;
}
}
bridge->sysdata = pp; bridge->sysdata = pp;

View File

@ -644,9 +644,20 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index)
dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0); dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0);
} }
int dw_pcie_wait_for_link(struct dw_pcie *pci) void dw_pcie_print_link_status(struct dw_pcie *pci)
{ {
u32 offset, val; u32 offset, val;
offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
FIELD_GET(PCI_EXP_LNKSTA_NLW, val));
}
int dw_pcie_wait_for_link(struct dw_pcie *pci)
{
int retries; int retries;
/* Check if the link is up or not */ /* Check if the link is up or not */
@ -662,12 +673,7 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); dw_pcie_print_link_status(pci);
val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
FIELD_GET(PCI_EXP_LNKSTA_NLW, val));
return 0; return 0;
} }

View File

@ -429,6 +429,7 @@ void dw_pcie_setup(struct dw_pcie *pci);
void dw_pcie_iatu_detect(struct dw_pcie *pci); void dw_pcie_iatu_detect(struct dw_pcie *pci);
int dw_pcie_edma_detect(struct dw_pcie *pci); int dw_pcie_edma_detect(struct dw_pcie *pci);
void dw_pcie_edma_remove(struct dw_pcie *pci); void dw_pcie_edma_remove(struct dw_pcie *pci);
void dw_pcie_print_link_status(struct dw_pcie *pci);
static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val) static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val)
{ {