Skip to content

Commit 3bbc3c7

Browse files
Richard ZhuLorenzo Pieralisi
authored andcommitted
PCI: imx6: Save and restore root port MSI control in suspend and resume
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/[email protected] Signed-off-by: Richard Zhu <[email protected]> [[email protected]: commit log] Signed-off-by: Lorenzo Pieralisi <[email protected]>
1 parent da56a1b commit 3bbc3c7

File tree

1 file changed

+23
-0
lines changed

1 file changed

+23
-0
lines changed

drivers/pci/controller/dwc/pci-imx6.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ struct imx6_pcie {
8080
struct clk *pcie;
8181
struct clk *pcie_aux;
8282
struct regmap *iomuxc_gpr;
83+
u16 msi_ctrl;
8384
u32 controller_id;
8485
struct reset_control *pciephy_reset;
8586
struct reset_control *apps_reset;
@@ -1178,6 +1179,26 @@ static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
11781179
usleep_range(1000, 10000);
11791180
}
11801181

1182+
static void imx6_pcie_msi_save_restore(struct imx6_pcie *imx6_pcie, bool save)
1183+
{
1184+
u8 offset;
1185+
u16 val;
1186+
struct dw_pcie *pci = imx6_pcie->pci;
1187+
1188+
if (pci_msi_enabled()) {
1189+
offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
1190+
if (save) {
1191+
val = dw_pcie_readw_dbi(pci, offset + PCI_MSI_FLAGS);
1192+
imx6_pcie->msi_ctrl = val;
1193+
} else {
1194+
dw_pcie_dbi_ro_wr_en(pci);
1195+
val = imx6_pcie->msi_ctrl;
1196+
dw_pcie_writew_dbi(pci, offset + PCI_MSI_FLAGS, val);
1197+
dw_pcie_dbi_ro_wr_dis(pci);
1198+
}
1199+
}
1200+
}
1201+
11811202
static int imx6_pcie_suspend_noirq(struct device *dev)
11821203
{
11831204
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
@@ -1186,6 +1207,7 @@ static int imx6_pcie_suspend_noirq(struct device *dev)
11861207
if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_SUPPORTS_SUSPEND))
11871208
return 0;
11881209

1210+
imx6_pcie_msi_save_restore(imx6_pcie, true);
11891211
imx6_pcie_pm_turnoff(imx6_pcie);
11901212
imx6_pcie_stop_link(imx6_pcie->pci);
11911213
imx6_pcie_host_exit(pp);
@@ -1205,6 +1227,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
12051227
ret = imx6_pcie_host_init(pp);
12061228
if (ret)
12071229
return ret;
1230+
imx6_pcie_msi_save_restore(imx6_pcie, false);
12081231
dw_pcie_setup_rc(pp);
12091232

12101233
if (imx6_pcie->link_is_up)

0 commit comments

Comments
 (0)