Skip to content

Commit

Permalink
PCI: imx6: Save and restore root port MSI control in suspend and resume
Browse files Browse the repository at this point in the history
The imx6 PCI host controller suffers from a HW integration bug whereby
the MSI enable bit in the root port MSI capability enables/disables MSIs
interrupts for all downstream components in the PCI tree.

This requires, as implemented in

75cb8d2 ("PCI: imx: Enable MSI from downstream components")

that the root port MSI enable bit should be set in order for downstream
PCI devices MSIs to function.

The MSI enable bit programming might be lost during the suspend and
should be re-stored during resume.

Save the MSI control during suspend and restore it in resume.

Link: https://lore.kernel.org/r/1670479534-22154-1-git-send-email-hongxing.zhu@nxp.com
Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>
[lpieralisi@kernel.org: commit log]
Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
  • Loading branch information
Richard Zhu authored and Lorenzo Pieralisi committed Jun 19, 2023
1 parent da56a1b commit 3bbc3c7
Showing 1 changed file with 23 additions and 0 deletions.
23 changes: 23 additions & 0 deletions drivers/pci/controller/dwc/pci-imx6.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ struct imx6_pcie {
struct clk *pcie;
struct clk *pcie_aux;
struct regmap *iomuxc_gpr;
u16 msi_ctrl;
u32 controller_id;
struct reset_control *pciephy_reset;
struct reset_control *apps_reset;
Expand Down Expand Up @@ -1178,6 +1179,26 @@ static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
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)
{
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
Expand All @@ -1186,6 +1207,7 @@ static int imx6_pcie_suspend_noirq(struct device *dev)
if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND))
return 0;

imx6_pcie_msi_save_restore(imx6_pcie, true);
imx6_pcie_pm_turnoff(imx6_pcie);
imx6_pcie_stop_link(imx6_pcie->pci);
imx6_pcie_host_exit(pp);
Expand All @@ -1205,6 +1227,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
ret = imx6_pcie_host_init(pp);
if (ret)
return ret;
imx6_pcie_msi_save_restore(imx6_pcie, false);
dw_pcie_setup_rc(pp);

if (imx6_pcie->link_is_up)
Expand Down

0 comments on commit 3bbc3c7

Please sign in to comment.