Commit 99f7b809 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

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
parents 375328fa 3bbc3c72
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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);
@@ -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)
+9 −4
Original line number Diff line number Diff line
@@ -485,14 +485,19 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
	if (ret)
		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);
		if (ret)
			goto err_remove_edma;
	}

	/* Ignore errors, the link may come up later */
	dw_pcie_wait_for_link(pci);
		if (pci->ops && pci->ops->start_link) {
			ret = dw_pcie_wait_for_link(pci);
			if (ret)
				goto err_stop_link;
		}
	}

	bridge->sysdata = pp;

+13 −7
Original line number Diff line number Diff line
@@ -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);
}

int dw_pcie_wait_for_link(struct dw_pcie *pci)
void dw_pcie_print_link_status(struct dw_pcie *pci)
{
	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;

	/* Check if the link is up or not */
@@ -662,12 +673,7 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
		return -ETIMEDOUT;
	}

	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));
	dw_pcie_print_link_status(pci);

	return 0;
}
+1 −0
Original line number Diff line number Diff line
@@ -429,6 +429,7 @@ void dw_pcie_setup(struct dw_pcie *pci);
void dw_pcie_iatu_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_print_link_status(struct dw_pcie *pci);

static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val)
{