diff mbox

[v6,3/3] PCI: imx6: Add support for i.MX6 PCIe controller

Message ID 1379319655-20210-4-git-send-email-xobs@kosagi.com
State Superseded
Headers show

Commit Message

Sean Cross Sept. 16, 2013, 8:20 a.m. UTC
Add support for the PCIe port present on the i.MX6 family of controllers.
These use the Synopsis Designware core tied to their own PHY.

Signed-off-by: Sean Cross <xobs@kosagi.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
---
 .../devicetree/bindings/pci/designware-pcie.txt    |    7 +-
 arch/arm/boot/dts/imx6qdl.dtsi                     |   16 +
 arch/arm/mach-imx/Kconfig                          |    2 +
 arch/arm/mach-imx/clk-imx6q.c                      |    4 +
 drivers/pci/host/Kconfig                           |    6 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-imx6.c                        |  576 ++++++++++++++++++++
 7 files changed, 611 insertions(+), 1 deletion(-)
 create mode 100644 drivers/pci/host/pci-imx6.c

Comments

Sascha Hauer Sept. 16, 2013, 9:25 a.m. UTC | #1
On Mon, Sep 16, 2013 at 08:20:54AM +0000, Sean Cross wrote:
> Add support for the PCIe port present on the i.MX6 family of controllers.
> These use the Synopsis Designware core tied to their own PHY.
> 
> +static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)
> +{
> +	u32 val;
> +	u32 max_iterations = 10;
> +	u32 wait_counter = 0;
> +
> +	do {
> +		val = readl(dbi_base + PCIE_PHY_STAT);
> +		val = (val >> PCIE_PHY_STAT_ACK_LOC) & 0x1;
> +		wait_counter++;
> +
> +		if (val == exp_val)
> +			return 0;
> +
> +		udelay(1);
> +	} while ((wait_counter < max_iterations) && (val != exp_val));

The test for val != exp_val is unnecessary now of course.

With this and the devm_clk_get Shawn mentioned:

Acked-by: Sascha Hauer <s.hauer@pengutronix.de>

Sascha
Zhi Li Sept. 25, 2013, 4:05 p.m. UTC | #2
On Mon, Sep 16, 2013 at 3:20 AM, Sean Cross <xobs@kosagi.com> wrote:
> Add support for the PCIe port present on the i.MX6 family of controllers.
> These use the Synopsis Designware core tied to their own PHY.
>
> Signed-off-by: Sean Cross <xobs@kosagi.com>
> Acked-by: Bjorn Helgaas <bhelgaas@google.com>

What is the status of this patch, is it queued in next or need future change ?

Best regards
Frank Li
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tim Harvey Sept. 26, 2013, 5:54 a.m. UTC | #3
> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
> index 3d95048..efa24d9 100644
> --- a/drivers/pci/host/Kconfig
> +++ b/drivers/pci/host/Kconfig
> @@ -15,6 +15,12 @@ config PCI_EXYNOS
>         select PCIEPORTBUS
>         select PCIE_DW
>
> +config PCI_IMX6
> +       bool "Freescale i.MX6 PCIe controller"
> +       depends on SOC_IMX6Q
> +       select PCIEPORTBUS

What is PCIEPORTBUS really for?  When I enable this with a PCIe switch
off the root complex I get invalid IRQ messages during enumeration of
ports on the switch:

[    6.572410] PCI: Device 0000:00:00.0 not available because of
resource collisi
[    6.572433] pcieport: probe of 0000:00:00.0 failed with error -22
[    6.572489] pcieport 0000:01:00.0: device [10b5:8609] has invalid
IRQ; check vendor BIOS             [    6.572536] pcieport: probe of
0000:01:00.0 failed with error -22
[    6.572593] pcieport 0000:02:01.0: device [10b5:8609] has invalid
IRQ; check vendor BIOS
[    6.572621] PCI: enabling device 0000:02:01.0 (0140 -> 0143)
[    6.572672] pcieport 0000:02:01.0: enabling bus mastering
[    6.573045] pcieport 0000:02:04.0: device [10b5:8609] has invalid
IRQ; check vendor BIOS
if I remove PCIEPORTBUS these go away however cards behind the switch
don't operate correctly (I believe the interrupts do not get mapped
properly).  Is there some logic perhaps missing in the driver required
for PCIe switches?

> +
> +/*  Added for PCI abort handling */
> +static int imx6q_pcie_abort_handler(unsigned long addr,
> +               unsigned int fsr, struct pt_regs *regs)
> +{
> +       /*
> +        * If it was an imprecise abort, then we need to correct the
> +        * return address to be _after_ the instruction.
> +        */
> +       if (fsr & (1 << 10))
> +               regs->ARM_pc += 4;
> +       return 0;
> +}
> +

you added this per my request but after more testing I'm not sure now
it should be needed.  On the i.MX6, imprecise aborts will occur when
an un-populated device behind a bridge is accessed.  However somewhere
a few kernels back (3.9 I believe) this behavior changed such that the
aborts were not enabled/checked until the kernel completed init.
Therefore with the current kernel any un-populated device will cause a
single imprecise abort to be caught at the end of init and as such it
should be ignored 'without touching the PC'.  I'm not clear if this
should happen - whatever enables the catching of the abort should
perhaps clear any pending flags I would think.  I'm also not clear if
an abort handler should really be required as the current kernel has a
default handler that results in:
...
Freeing unused kernel memory: 6600K (80817000 - 80e89000)
Unhandled fault: imprecise external abort (0x1406) at 0xca8c0d71
...

Do we hook a handler that does nothing but 'return 0' just to
eliminate the Unhandled fault message?

> +static void imx6_pcie_host_init(struct pcie_port *pp)
> +{
> +       int count = 0;
> +       struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
> +
> +       imx6_pcie_assert_core_reset(pp);
> +
> +       imx6_pcie_init_phy(pp);
> +
> +       imx6_pcie_deassert_core_reset(pp);
> +
> +       dw_pcie_setup_rc(pp);
> +
> +       regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
> +                       IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
> +
> +       while (!dw_pcie_link_up(pp)) {
> +               usleep_range(100, 1000);

I've found that I needed to increase this delay in order for a link
detect with a PLX PEX8609 switch off the root complex.  A
usleep_range(2000, 3000) worked in my testing.

> +static int imx6_pcie_link_up(struct pcie_port *pp)
> +{
> +       u32 rc, ltssm, rx_valid, temp;
> +
> +       /* link is debug bit 36, debug register 1 starts at bit 32 */
> +       rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << (36 - 32));
> +       if (rc)
> +               return -EAGAIN;

I'm still having trouble accessing devices behind a PCIe switch in
3.12-rc2.  Device enumeration goes fine however after kernel init it
seems that any access to a switch port fails the check for link in
dw_pcie_valid_config which calls imx6_pcie_link_up here.  I'm
wondering if this is some ASPM issue (I've tried both with that
enabled and disabled).  When I backport this driver to 3.11 I do not
see this behavior and can access config space of all devices behind
the bridge within userspace.  Any ideas here?

Tim

>
> +
> +       /*
> +        * From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
> +        * Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
> +        * If (MAC/LTSSM.state == Recovery.RcvrLock)
> +        * && (PHY/rx_valid==0) then pulse PHY/rx_reset. Transition
> +        * to gen2 is stuck
> +        */
> +       pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
> +       ltssm = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0) & 0x3F;
> +
> +       if (rx_valid & 0x01)
> +               return 0;
> +
> +       if (ltssm != 0x0d)
> +               return 0;
> +
> +       dev_err(pp->dev,
> +               "transition to gen2 is stuck, reset PHY!\n");
> +
> +       pcie_phy_read(pp->dbi_base,
> +               PHY_RX_OVRD_IN_LO, &temp);
> +       temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN
> +               | PHY_RX_OVRD_IN_LO_RX_PLL_EN);
> +       pcie_phy_write(pp->dbi_base,
> +               PHY_RX_OVRD_IN_LO, temp);
> +
> +       usleep_range(2000, 3000);
> +
> +       pcie_phy_read(pp->dbi_base,
> +               PHY_RX_OVRD_IN_LO, &temp);
> +       temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN
> +               | PHY_RX_OVRD_IN_LO_RX_PLL_EN);
> +       pcie_phy_write(pp->dbi_base,
> +               PHY_RX_OVRD_IN_LO, temp);
> +
> +       return 0;
> +}
> +
> +static struct pcie_host_ops imx6_pcie_host_ops = {
> +       .link_up = imx6_pcie_link_up,
> +       .host_init = imx6_pcie_host_init,
> +};
> +
> +static int imx6_add_pcie_port(struct pcie_port *pp,
> +                       struct platform_device *pdev)
> +{
> +       int ret;
> +
> +       pp->irq = platform_get_irq(pdev, 0);
> +       if (!pp->irq) {
> +               dev_err(&pdev->dev, "failed to get irq\n");
> +               return -ENODEV;
> +       }
> +
> +       pp->root_bus_nr = -1;
> +       pp->ops = &imx6_pcie_host_ops;
> +
> +       spin_lock_init(&pp->conf_lock);
> +       ret = dw_pcie_host_init(pp);
> +       if (ret) {
> +               dev_err(&pdev->dev, "failed to initialize host\n");
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int __init imx6_pcie_probe(struct platform_device *pdev)
> +{
> +       struct imx6_pcie *imx6_pcie;
> +       struct pcie_port *pp;
> +       struct device_node *np = pdev->dev.of_node;
> +       struct resource *dbi_base;
> +       int ret;
> +
> +       imx6_pcie = devm_kzalloc(&pdev->dev, sizeof(*imx6_pcie), GFP_KERNEL);
> +       if (!imx6_pcie)
> +               return -ENOMEM;
> +
> +       pp = &imx6_pcie->pp;
> +       pp->dev = &pdev->dev;
> +
> +       /* Added for PCI abort handling */
> +       hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0,
> +               "imprecise external abort");
> +
> +       dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!dbi_base) {
> +               dev_err(&pdev->dev, "dbi_base memory resource not found\n");
> +               return -ENODEV;
> +       }
> +
> +       pp->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base);
> +       if (IS_ERR(pp->dbi_base)) {
> +               dev_err(&pdev->dev, "unable to remap dbi_base\n");
> +               ret = PTR_ERR(pp->dbi_base);
> +               goto err;
> +       }
> +
> +       /* Fetch GPIOs */
> +       imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
> +       if (!gpio_is_valid(imx6_pcie->reset_gpio)) {
> +               dev_err(&pdev->dev, "no reset-gpio defined\n");
> +               ret = -ENODEV;
> +       }
> +       ret = devm_gpio_request_one(&pdev->dev,
> +                               imx6_pcie->reset_gpio,
> +                               GPIOF_OUT_INIT_LOW,
> +                               "PCIe reset");
> +       if (ret) {
> +               dev_err(&pdev->dev, "unable to get reset gpio\n");
> +               goto err;
> +       }
> +
> +       imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0);
> +       if (gpio_is_valid(imx6_pcie->power_on_gpio)) {
> +               ret = devm_gpio_request_one(&pdev->dev,
> +                                       imx6_pcie->power_on_gpio,
> +                                       GPIOF_OUT_INIT_LOW,
> +                                       "PCIe power enable");
> +               if (ret) {
> +                       dev_err(&pdev->dev, "unable to get power-on gpio\n");
> +                       goto err;
> +               }
> +       }
> +
> +       imx6_pcie->wake_up_gpio = of_get_named_gpio(np, "wake-up-gpio", 0);
> +       if (gpio_is_valid(imx6_pcie->wake_up_gpio)) {
> +               ret = devm_gpio_request_one(&pdev->dev,
> +                                       imx6_pcie->wake_up_gpio,
> +                                       GPIOF_IN,
> +                                       "PCIe wake up");
> +               if (ret) {
> +                       dev_err(&pdev->dev, "unable to get wake-up gpio\n");
> +                       goto err;
> +               }
> +       }
> +
> +       imx6_pcie->disable_gpio = of_get_named_gpio(np, "disable-gpio", 0);
> +       if (gpio_is_valid(imx6_pcie->disable_gpio)) {
> +               ret = devm_gpio_request_one(&pdev->dev,
> +                                       imx6_pcie->disable_gpio,
> +                                       GPIOF_OUT_INIT_HIGH,
> +                                       "PCIe disable endpoint");
> +               if (ret) {
> +                       dev_err(&pdev->dev, "unable to get disable-ep gpio\n");
> +                       goto err;
> +               }
> +       }
> +
> +       /* Fetch clocks */
> +       imx6_pcie->lvds_gate = clk_get(&pdev->dev, "lvds_gate");
> +       if (IS_ERR(imx6_pcie->lvds_gate)) {
> +               dev_err(&pdev->dev,
> +                       "lvds_gate clock select missing or invalid\n");
> +               ret = PTR_ERR(imx6_pcie->lvds_gate);
> +               goto err;
> +       }
> +
> +       imx6_pcie->sata_ref_100m = clk_get(&pdev->dev, "sata_ref_100m");
> +       if (IS_ERR(imx6_pcie->sata_ref_100m)) {
> +               dev_err(&pdev->dev,
> +                       "sata_ref_100m clock source missing or invalid\n");
> +               ret = PTR_ERR(imx6_pcie->sata_ref_100m);
> +               goto err;
> +       }
> +
> +       imx6_pcie->pcie_ref_125m = clk_get(&pdev->dev, "pcie_ref_125m");
> +       if (IS_ERR(imx6_pcie->pcie_ref_125m)) {
> +               dev_err(&pdev->dev,
> +                       "pcie_ref_125m clock source missing or invalid\n");
> +               ret = PTR_ERR(imx6_pcie->pcie_ref_125m);
> +               goto err;
> +       }
> +
> +       imx6_pcie->pcie_axi = clk_get(&pdev->dev, "pcie_axi");
> +       if (IS_ERR(imx6_pcie->pcie_axi)) {
> +               dev_err(&pdev->dev,
> +                       "pcie_axi clock source missing or invalid\n");
> +               ret = PTR_ERR(imx6_pcie->pcie_axi);
> +               goto err;
> +       }
> +
> +       /* Grab GPR config register range */
> +       imx6_pcie->iomuxc_gpr =
> +                syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
> +       if (IS_ERR(imx6_pcie->iomuxc_gpr)) {
> +               dev_err(&pdev->dev, "unable to find iomuxc registers\n");
> +               ret = PTR_ERR(imx6_pcie->iomuxc_gpr);
> +               goto err;
> +       }
> +
> +       ret = imx6_add_pcie_port(pp, pdev);
> +       if (ret < 0)
> +               goto err;
> +
> +       platform_set_drvdata(pdev, imx6_pcie);
> +       return 0;
> +
> +err:
> +       return ret;
> +}
> +
> +static const struct of_device_id imx6_pcie_of_match[] = {
> +       { .compatible = "fsl,imx6q-pcie", },
> +       {},
> +};
> +MODULE_DEVICE_TABLE(of, imx6_pcie_of_match);
> +
> +static struct platform_driver imx6_pcie_driver = {
> +       .driver = {
> +               .name   = "imx6q-pcie",
> +               .owner  = THIS_MODULE,
> +               .of_match_table = of_match_ptr(imx6_pcie_of_match),
> +       },
> +};
> +
> +/* Freescale PCIe driver does not allow module unload */
> +
> +static int __init imx6_init(void)
> +{
> +       return platform_driver_probe(&imx6_pcie_driver, imx6_pcie_probe);
> +}
> +module_init(imx6_init);
> +
> +MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
> +MODULE_DESCRIPTION("Freescale i.MX6 PCIe host controller driver");
> +MODULE_LICENSE("GPL v2");
> --
> 1.7.9.5
>
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Zhu Richard-R65037 Sept. 27, 2013, 1:38 a.m. UTC | #4
Hi Tim:
Thanks for your tests.
Yes, it is. There are some problems when the PCIe switch is used on the 3.1x kernel at my side too, although the PCIe switch
is ok on FSL imx_3.0.35 kernels.
I'm debugging this issue now, and would summit the patches asap.

Best Regards
Richard Zhu


-----Original Message-----
From: Tim Harvey [mailto:tharvey@gateworks.com] 
Sent: Thursday, September 26, 2013 1:54 PM
To: Sean Cross
Cc: devicetree@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-kernel@lists.infradead.org; Sascha Hauer; Zhu Richard-R65037; Shawn Guo; bhelgaas@google.com
Subject: Re: [PATCH v6 3/3] PCI: imx6: Add support for i.MX6 PCIe controller

> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 
> 3d95048..efa24d9 100644
> --- a/drivers/pci/host/Kconfig
> +++ b/drivers/pci/host/Kconfig
> @@ -15,6 +15,12 @@ config PCI_EXYNOS
>         select PCIEPORTBUS
>         select PCIE_DW
>
> +config PCI_IMX6
> +       bool "Freescale i.MX6 PCIe controller"
> +       depends on SOC_IMX6Q
> +       select PCIEPORTBUS

What is PCIEPORTBUS really for?  When I enable this with a PCIe switch off the root complex I get invalid IRQ messages during enumeration of ports on the switch:

[    6.572410] PCI: Device 0000:00:00.0 not available because of
resource collisi
[    6.572433] pcieport: probe of 0000:00:00.0 failed with error -22
[    6.572489] pcieport 0000:01:00.0: device [10b5:8609] has invalid
IRQ; check vendor BIOS             [    6.572536] pcieport: probe of
0000:01:00.0 failed with error -22
[    6.572593] pcieport 0000:02:01.0: device [10b5:8609] has invalid
IRQ; check vendor BIOS
[    6.572621] PCI: enabling device 0000:02:01.0 (0140 -> 0143)
[    6.572672] pcieport 0000:02:01.0: enabling bus mastering
[    6.573045] pcieport 0000:02:04.0: device [10b5:8609] has invalid
IRQ; check vendor BIOS
if I remove PCIEPORTBUS these go away however cards behind the switch don't operate correctly (I believe the interrupts do not get mapped properly).  Is there some logic perhaps missing in the driver required for PCIe switches?

> +
> +/*  Added for PCI abort handling */
> +static int imx6q_pcie_abort_handler(unsigned long addr,
> +               unsigned int fsr, struct pt_regs *regs) {
> +       /*
> +        * If it was an imprecise abort, then we need to correct the
> +        * return address to be _after_ the instruction.
> +        */
> +       if (fsr & (1 << 10))
> +               regs->ARM_pc += 4;
> +       return 0;
> +}
> +

you added this per my request but after more testing I'm not sure now it should be needed.  On the i.MX6, imprecise aborts will occur when an un-populated device behind a bridge is accessed.  However somewhere a few kernels back (3.9 I believe) this behavior changed such that the aborts were not enabled/checked until the kernel completed init.
Therefore with the current kernel any un-populated device will cause a single imprecise abort to be caught at the end of init and as such it should be ignored 'without touching the PC'.  I'm not clear if this should happen - whatever enables the catching of the abort should perhaps clear any pending flags I would think.  I'm also not clear if an abort handler should really be required as the current kernel has a default handler that results in:
...
Freeing unused kernel memory: 6600K (80817000 - 80e89000) Unhandled fault: imprecise external abort (0x1406) at 0xca8c0d71 ...

Do we hook a handler that does nothing but 'return 0' just to eliminate the Unhandled fault message?

> +static void imx6_pcie_host_init(struct pcie_port *pp) {
> +       int count = 0;
> +       struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
> +
> +       imx6_pcie_assert_core_reset(pp);
> +
> +       imx6_pcie_init_phy(pp);
> +
> +       imx6_pcie_deassert_core_reset(pp);
> +
> +       dw_pcie_setup_rc(pp);
> +
> +       regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
> +                       IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
> +
> +       while (!dw_pcie_link_up(pp)) {
> +               usleep_range(100, 1000);

I've found that I needed to increase this delay in order for a link detect with a PLX PEX8609 switch off the root complex.  A usleep_range(2000, 3000) worked in my testing.

> +static int imx6_pcie_link_up(struct pcie_port *pp) {
> +       u32 rc, ltssm, rx_valid, temp;
> +
> +       /* link is debug bit 36, debug register 1 starts at bit 32 */
> +       rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << (36 - 32));
> +       if (rc)
> +               return -EAGAIN;

I'm still having trouble accessing devices behind a PCIe switch in 3.12-rc2.  Device enumeration goes fine however after kernel init it seems that any access to a switch port fails the check for link in dw_pcie_valid_config which calls imx6_pcie_link_up here.  I'm wondering if this is some ASPM issue (I've tried both with that enabled and disabled).  When I backport this driver to 3.11 I do not see this behavior and can access config space of all devices behind the bridge within userspace.  Any ideas here?

Tim

>
> +
> +       /*
> +        * From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
> +        * Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
> +        * If (MAC/LTSSM.state == Recovery.RcvrLock)
> +        * && (PHY/rx_valid==0) then pulse PHY/rx_reset. Transition
> +        * to gen2 is stuck
> +        */
> +       pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
> +       ltssm = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0) & 0x3F;
> +
> +       if (rx_valid & 0x01)
> +               return 0;
> +
> +       if (ltssm != 0x0d)
> +               return 0;
> +
> +       dev_err(pp->dev,
> +               "transition to gen2 is stuck, reset PHY!\n");
> +
> +       pcie_phy_read(pp->dbi_base,
> +               PHY_RX_OVRD_IN_LO, &temp);
> +       temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN
> +               | PHY_RX_OVRD_IN_LO_RX_PLL_EN);
> +       pcie_phy_write(pp->dbi_base,
> +               PHY_RX_OVRD_IN_LO, temp);
> +
> +       usleep_range(2000, 3000);
> +
> +       pcie_phy_read(pp->dbi_base,
> +               PHY_RX_OVRD_IN_LO, &temp);
> +       temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN
> +               | PHY_RX_OVRD_IN_LO_RX_PLL_EN);
> +       pcie_phy_write(pp->dbi_base,
> +               PHY_RX_OVRD_IN_LO, temp);
> +
> +       return 0;
> +}
> +
> +static struct pcie_host_ops imx6_pcie_host_ops = {
> +       .link_up = imx6_pcie_link_up,
> +       .host_init = imx6_pcie_host_init, };
> +
> +static int imx6_add_pcie_port(struct pcie_port *pp,
> +                       struct platform_device *pdev) {
> +       int ret;
> +
> +       pp->irq = platform_get_irq(pdev, 0);
> +       if (!pp->irq) {
> +               dev_err(&pdev->dev, "failed to get irq\n");
> +               return -ENODEV;
> +       }
> +
> +       pp->root_bus_nr = -1;
> +       pp->ops = &imx6_pcie_host_ops;
> +
> +       spin_lock_init(&pp->conf_lock);
> +       ret = dw_pcie_host_init(pp);
> +       if (ret) {
> +               dev_err(&pdev->dev, "failed to initialize host\n");
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int __init imx6_pcie_probe(struct platform_device *pdev) {
> +       struct imx6_pcie *imx6_pcie;
> +       struct pcie_port *pp;
> +       struct device_node *np = pdev->dev.of_node;
> +       struct resource *dbi_base;
> +       int ret;
> +
> +       imx6_pcie = devm_kzalloc(&pdev->dev, sizeof(*imx6_pcie), GFP_KERNEL);
> +       if (!imx6_pcie)
> +               return -ENOMEM;
> +
> +       pp = &imx6_pcie->pp;
> +       pp->dev = &pdev->dev;
> +
> +       /* Added for PCI abort handling */
> +       hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0,
> +               "imprecise external abort");
> +
> +       dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!dbi_base) {
> +               dev_err(&pdev->dev, "dbi_base memory resource not found\n");
> +               return -ENODEV;
> +       }
> +
> +       pp->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base);
> +       if (IS_ERR(pp->dbi_base)) {
> +               dev_err(&pdev->dev, "unable to remap dbi_base\n");
> +               ret = PTR_ERR(pp->dbi_base);
> +               goto err;
> +       }
> +
> +       /* Fetch GPIOs */
> +       imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
> +       if (!gpio_is_valid(imx6_pcie->reset_gpio)) {
> +               dev_err(&pdev->dev, "no reset-gpio defined\n");
> +               ret = -ENODEV;
> +       }
> +       ret = devm_gpio_request_one(&pdev->dev,
> +                               imx6_pcie->reset_gpio,
> +                               GPIOF_OUT_INIT_LOW,
> +                               "PCIe reset");
> +       if (ret) {
> +               dev_err(&pdev->dev, "unable to get reset gpio\n");
> +               goto err;
> +       }
> +
> +       imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0);
> +       if (gpio_is_valid(imx6_pcie->power_on_gpio)) {
> +               ret = devm_gpio_request_one(&pdev->dev,
> +                                       imx6_pcie->power_on_gpio,
> +                                       GPIOF_OUT_INIT_LOW,
> +                                       "PCIe power enable");
> +               if (ret) {
> +                       dev_err(&pdev->dev, "unable to get power-on gpio\n");
> +                       goto err;
> +               }
> +       }
> +
> +       imx6_pcie->wake_up_gpio = of_get_named_gpio(np, "wake-up-gpio", 0);
> +       if (gpio_is_valid(imx6_pcie->wake_up_gpio)) {
> +               ret = devm_gpio_request_one(&pdev->dev,
> +                                       imx6_pcie->wake_up_gpio,
> +                                       GPIOF_IN,
> +                                       "PCIe wake up");
> +               if (ret) {
> +                       dev_err(&pdev->dev, "unable to get wake-up gpio\n");
> +                       goto err;
> +               }
> +       }
> +
> +       imx6_pcie->disable_gpio = of_get_named_gpio(np, "disable-gpio", 0);
> +       if (gpio_is_valid(imx6_pcie->disable_gpio)) {
> +               ret = devm_gpio_request_one(&pdev->dev,
> +                                       imx6_pcie->disable_gpio,
> +                                       GPIOF_OUT_INIT_HIGH,
> +                                       "PCIe disable endpoint");
> +               if (ret) {
> +                       dev_err(&pdev->dev, "unable to get disable-ep gpio\n");
> +                       goto err;
> +               }
> +       }
> +
> +       /* Fetch clocks */
> +       imx6_pcie->lvds_gate = clk_get(&pdev->dev, "lvds_gate");
> +       if (IS_ERR(imx6_pcie->lvds_gate)) {
> +               dev_err(&pdev->dev,
> +                       "lvds_gate clock select missing or invalid\n");
> +               ret = PTR_ERR(imx6_pcie->lvds_gate);
> +               goto err;
> +       }
> +
> +       imx6_pcie->sata_ref_100m = clk_get(&pdev->dev, "sata_ref_100m");
> +       if (IS_ERR(imx6_pcie->sata_ref_100m)) {
> +               dev_err(&pdev->dev,
> +                       "sata_ref_100m clock source missing or invalid\n");
> +               ret = PTR_ERR(imx6_pcie->sata_ref_100m);
> +               goto err;
> +       }
> +
> +       imx6_pcie->pcie_ref_125m = clk_get(&pdev->dev, "pcie_ref_125m");
> +       if (IS_ERR(imx6_pcie->pcie_ref_125m)) {
> +               dev_err(&pdev->dev,
> +                       "pcie_ref_125m clock source missing or invalid\n");
> +               ret = PTR_ERR(imx6_pcie->pcie_ref_125m);
> +               goto err;
> +       }
> +
> +       imx6_pcie->pcie_axi = clk_get(&pdev->dev, "pcie_axi");
> +       if (IS_ERR(imx6_pcie->pcie_axi)) {
> +               dev_err(&pdev->dev,
> +                       "pcie_axi clock source missing or invalid\n");
> +               ret = PTR_ERR(imx6_pcie->pcie_axi);
> +               goto err;
> +       }
> +
> +       /* Grab GPR config register range */
> +       imx6_pcie->iomuxc_gpr =
> +                syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
> +       if (IS_ERR(imx6_pcie->iomuxc_gpr)) {
> +               dev_err(&pdev->dev, "unable to find iomuxc registers\n");
> +               ret = PTR_ERR(imx6_pcie->iomuxc_gpr);
> +               goto err;
> +       }
> +
> +       ret = imx6_add_pcie_port(pp, pdev);
> +       if (ret < 0)
> +               goto err;
> +
> +       platform_set_drvdata(pdev, imx6_pcie);
> +       return 0;
> +
> +err:
> +       return ret;
> +}
> +
> +static const struct of_device_id imx6_pcie_of_match[] = {
> +       { .compatible = "fsl,imx6q-pcie", },
> +       {},
> +};
> +MODULE_DEVICE_TABLE(of, imx6_pcie_of_match);
> +
> +static struct platform_driver imx6_pcie_driver = {
> +       .driver = {
> +               .name   = "imx6q-pcie",
> +               .owner  = THIS_MODULE,
> +               .of_match_table = of_match_ptr(imx6_pcie_of_match),
> +       },
> +};
> +
> +/* Freescale PCIe driver does not allow module unload */
> +
> +static int __init imx6_init(void)
> +{
> +       return platform_driver_probe(&imx6_pcie_driver, 
> +imx6_pcie_probe); } module_init(imx6_init);
> +
> +MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); 
> +MODULE_DESCRIPTION("Freescale i.MX6 PCIe host controller driver"); 
> +MODULE_LICENSE("GPL v2");
> --
> 1.7.9.5
>


--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Shawn Guo Sept. 27, 2013, 2:19 a.m. UTC | #5
On Fri, Sep 27, 2013 at 01:38:39AM +0000, Zhu Richard-R65037 wrote:
> Hi Tim:
> Thanks for your tests.
> Yes, it is. There are some problems when the PCIe switch is used on the 3.1x kernel at my side too, although the PCIe switch
> is ok on FSL imx_3.0.35 kernels.
> I'm debugging this issue now, and would summit the patches asap.
> 

From what I read, it seems Sean's series does not support PCIe switch.
At least, he hasn't got any device to test it.  And there is some
problem with PCIe switch running the latest kernel, which might not be
related to the controller driver.

I suggest we ask Bjorn to merge the v7 I sent yesterday, so that people
can have a same base to work on, and add PCIe switch support with
incremental patches.   Does that sound good to you, Tim?

Shawn

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jingoo Han Sept. 27, 2013, 3:40 a.m. UTC | #6
On Friday, September 27, 2013 11:19 AM, Shawn Guo wrote:
> On Fri, Sep 27, 2013 at 01:38:39AM +0000, Zhu Richard-R65037 wrote:
> > Hi Tim:
> > Thanks for your tests.
> > Yes, it is. There are some problems when the PCIe switch is used
> > on the 3.1x kernel at my side too,
> although the PCIe switch
> > is ok on FSL imx_3.0.35 kernels.
> > I'm debugging this issue now, and would summit the patches asap.
> >
> 
> From what I read, it seems Sean's series does not support PCIe switch.
> At least, he hasn't got any device to test it.  And there is some
> problem with PCIe switch running the latest kernel, which might not be
> related to the controller driver.
> 
> I suggest we ask Bjorn to merge the v7 I sent yesterday, so that people
> can have a same base to work on, and add PCIe switch support with
> incremental patches.   Does that sound good to you, Tim?
> 

Hi Shawn Guo,

I agree with your suggestion. :-)
The PCIe switch support patches can be added later, after the v7 patch for
i.MX6 PCIe controller driver is merged.

Also, if the PCIe switch support patches modify the synopsys designware PCIe
driver (pcie-designware.c), it should be confirmed by other related people.

Best regards,
Jingoo Han

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tim Harvey Sept. 27, 2013, 3:52 a.m. UTC | #7
On Thu, Sep 26, 2013 at 7:19 PM, Shawn Guo <shawn.guo@linaro.org> wrote:
> On Fri, Sep 27, 2013 at 01:38:39AM +0000, Zhu Richard-R65037 wrote:
>> Hi Tim:
>> Thanks for your tests.
>> Yes, it is. There are some problems when the PCIe switch is used on the 3.1x kernel at my side too, although the PCIe switch
>> is ok on FSL imx_3.0.35 kernels.
>> I'm debugging this issue now, and would summit the patches asap.
>>
>
> From what I read, it seems Sean's series does not support PCIe switch.
> At least, he hasn't got any device to test it.  And there is some
> problem with PCIe switch running the latest kernel, which might not be
> related to the controller driver.
>
> I suggest we ask Bjorn to merge the v7 I sent yesterday, so that people
> can have a same base to work on, and add PCIe switch support with
> incremental patches.   Does that sound good to you, Tim?
>
> Shawn
>

Agreed - I would like to get this out there to a broader audience as well.

Thanks,

Tim
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sean Cross Sept. 27, 2013, 3:54 a.m. UTC | #8
On 27/9/13 11:40 AM, Jingoo Han wrote:
> On Friday, September 27, 2013 11:19 AM, Shawn Guo wrote:
>> On Fri, Sep 27, 2013 at 01:38:39AM +0000, Zhu Richard-R65037 wrote:
>>> Hi Tim:
>>> Thanks for your tests.
>>> Yes, it is. There are some problems when the PCIe switch is used
>>> on the 3.1x kernel at my side too,
>> although the PCIe switch
>>> is ok on FSL imx_3.0.35 kernels.
>>> I'm debugging this issue now, and would summit the patches asap.
>>>
>>  From what I read, it seems Sean's series does not support PCIe switch.
>> At least, he hasn't got any device to test it.  And there is some
>> problem with PCIe switch running the latest kernel, which might not be
>> related to the controller driver.
>>
>> I suggest we ask Bjorn to merge the v7 I sent yesterday, so that people
>> can have a same base to work on, and add PCIe switch support with
>> incremental patches.   Does that sound good to you, Tim?
>>
> Hi Shawn Guo,
>
> I agree with your suggestion. :-)
> The PCIe switch support patches can be added later, after the v7 patch for
> i.MX6 PCIe controller driver is merged.
>
> Also, if the PCIe switch support patches modify the synopsys designware PCIe
> driver (pcie-designware.c), it should be confirmed by other related people.
>
Correct.  My series doesn't support PCIe switches mostly because I don't 
have one to test with.  It would be interesting to see if PCIe switches 
work with other Designware drivers.

---
Sean
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tim Harvey Oct. 18, 2013, 5:32 a.m. UTC | #9
On Mon, Sep 16, 2013 at 1:20 AM, Sean Cross <xobs@kosagi.com> wrote:
> Add support for the PCIe port present on the i.MX6 family of controllers.
> These use the Synopsis Designware core tied to their own PHY.
>
> Signed-off-by: Sean Cross <xobs@kosagi.com>
> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
>  .../devicetree/bindings/pci/designware-pcie.txt    |    7 +-
> diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
> index ccd55c2..125202e 100644
> --- a/arch/arm/boot/dts/imx6qdl.dtsi
> +++ b/arch/arm/boot/dts/imx6qdl.dtsi
> @@ -116,6 +116,22 @@
>                         arm,data-latency = <4 2 3>;
>                 };
>
> +               pcie: pcie@0x01000000 {
> +                       compatible = "fsl,imx6q-pcie", "snps,dw-pcie";
> +                       reg = <0x01ffc000 0x4000>; /* DBI */
> +                       #address-cells = <3>;
> +                       #size-cells = <2>;
> +                       device_type = "pci";
> +                       ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000 /* configuration space */
> +                                 0x81000000 0 0          0x01f80000 0 0x00010000 /* downstream I/O */
> +                                 0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */
> +                       num-lanes = <1>;
> +                       interrupts = <0 123 0x04>;
> +                       clocks = <&clks 189>, <&clks 187>, <&clks 205>, <&clks 144>;
> +                       clock-names = "pcie_ref_125m", "sata_ref_100m", "lvds_gate", "pcie_axi";
> +                       status = "disabled";
> +               };
> +

Sean,

The devicetree portion above is now here
https://gitorious.org/thierryreding/linux-next/commit/3a57291fa4ca7f7647d826f5b47082ef306d839f
(which I'm told gets pulled into linux-next) and I wanted to see if
you or any of the other IMX/PCI gurus here can answer a question about
region mapping.

The above ranges look to me to allocate 15MB for mem resources, 64K
for io resources, and 256K for cfg space.

Table 2.1 of the IMX6DQRM.pdf
(http://cache.freescale.com/files/32bit/doc/ref_manual/IMX6DQRM.pdf)
shows:
  01FF_C000 01FF_FFFF 16 KB PCIe registers
  0100_0000 01FF_BFFF 16368 KB PCIe

The driver in the fsl 3.0.35_4.1.0 BSP maps the following (see
http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/arch/arm/mach-mx6/pcie.c?h=imx_3.0.35_4.1.0#n331):

0x0100_0000 --- 0x01DF_FFFF 14MB IORESOURCE_MEM
0x01E0_0000 --- 0x01EF_FFFF 1MB IORESOURCE_IO
0x01F0_0000 --- 0x01FF_FFFF 1MB Cfg + MSI + Registers

and, in a discussion on the IMX Community forum
(https://community.freescale.com/message/334959#334959) points out
that you have more flexibility if you map the MEM resource first
because of its more limited alignment.  So, if you were going to stick
with the fsl mapping I would think we would want something like this
in the dt node:

ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000 /* 512K
configuration space */
               0x81000000 0 0          0x01e00000 0 0x00100000 /* 1MB
downstream I/O */
               0x82000000 0 0x01000000 0x01000000 0 0x00e00000>; /*
14MB non-prefetchable memory */

Can these regions be moved around however you want depending on what
kind of mem vs io resource configurations you desire?  How about the
cfg space - is 512K really needed?

Are we sure the committed values to linux-next 'wrong' in any way?  I
still am seeing bus-hangs with devices behind a bridge that use
io-space resources and am trying to figure out where the issue is.  I
don't get these bus-hangs when using the fsl driver which is
structured very different so its been difficult for me to determine
the difference.  The mappings and the way iATU mappings are done are
very different.

Thanks,

Tim
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Zhu Richard-R65037 Oct. 18, 2013, 6:34 a.m. UTC | #10
> -----Original Message-----
> From: Tim Harvey [mailto:tharvey@gateworks.com]
> Sent: Friday, October 18, 2013 1:33 PM
> To: Sean Cross
> Cc: devicetree@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org; Sascha Hauer; Zhu Richard-R65037; Shawn Guo; Bjorn
> Helgaas; Marek Vašut; Jingoo Han; Pratyush Anand; Troy Kisky
> Subject: Re: [PATCH v6 3/3] PCI: imx6: Add support for i.MX6 PCIe controller
> 
> On Mon, Sep 16, 2013 at 1:20 AM, Sean Cross <xobs@kosagi.com> wrote:
> > Add support for the PCIe port present on the i.MX6 family of controllers.
> > These use the Synopsis Designware core tied to their own PHY.
> >
> > Signed-off-by: Sean Cross <xobs@kosagi.com>
> > Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> > ---
> >  .../devicetree/bindings/pci/designware-pcie.txt    |    7 +-
> > diff --git a/arch/arm/boot/dts/imx6qdl.dtsi
> > b/arch/arm/boot/dts/imx6qdl.dtsi index ccd55c2..125202e 100644
> > --- a/arch/arm/boot/dts/imx6qdl.dtsi
> > +++ b/arch/arm/boot/dts/imx6qdl.dtsi
> > @@ -116,6 +116,22 @@
> >                         arm,data-latency = <4 2 3>;
> >                 };
> >
> > +               pcie: pcie@0x01000000 {
> > +                       compatible = "fsl,imx6q-pcie", "snps,dw-pcie";
> > +                       reg = <0x01ffc000 0x4000>; /* DBI */
> > +                       #address-cells = <3>;
> > +                       #size-cells = <2>;
> > +                       device_type = "pci";
> > +                       ranges = <0x00000800 0 0x01f00000 0x01f00000 0
> 0x00080000 /* configuration space */
> > +                                 0x81000000 0 0          0x01f80000 0
> 0x00010000 /* downstream I/O */
> > +                                 0x82000000 0 0x01000000 0x01000000 0
> 0x00f00000>; /* non-prefetchable memory */
> > +                       num-lanes = <1>;
> > +                       interrupts = <0 123 0x04>;
> > +                       clocks = <&clks 189>, <&clks 187>, <&clks 205>,
> <&clks 144>;
> > +                       clock-names = "pcie_ref_125m", "sata_ref_100m",
> "lvds_gate", "pcie_axi";
> > +                       status = "disabled";
> > +               };
> > +
> 
> Sean,
> 
> The devicetree portion above is now here
> https://gitorious.org/thierryreding/linux-
> next/commit/3a57291fa4ca7f7647d826f5b47082ef306d839f
> (which I'm told gets pulled into linux-next) and I wanted to see if you or any
> of the other IMX/PCI gurus here can answer a question about region mapping.
> 
> The above ranges look to me to allocate 15MB for mem resources, 64K for io
> resources, and 256K for cfg space.
> 
> Table 2.1 of the IMX6DQRM.pdf
> (http://cache.freescale.com/files/32bit/doc/ref_manual/IMX6DQRM.pdf)
> shows:
>   01FF_C000 01FF_FFFF 16 KB PCIe registers
>   0100_0000 01FF_BFFF 16368 KB PCIe
> 
> The driver in the fsl 3.0.35_4.1.0 BSP maps the following (see
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-
> imx.git/tree/arch/arm/mach-mx6/pcie.c?h=imx_3.0.35_4.1.0#n331):
> 
> 0x0100_0000 --- 0x01DF_FFFF 14MB IORESOURCE_MEM
> 0x01E0_0000 --- 0x01EF_FFFF 1MB IORESOURCE_IO
> 0x01F0_0000 --- 0x01FF_FFFF 1MB Cfg + MSI + Registers
> 
> and, in a discussion on the IMX Community forum
> (https://community.freescale.com/message/334959#334959) points out that you
> have more flexibility if you map the MEM resource first because of its more
> limited alignment.  So, if you were going to stick with the fsl mapping I
> would think we would want something like this in the dt node:
> 
> ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000 /* 512K
> configuration space */
>                0x81000000 0 0          0x01e00000 0 0x00100000 /* 1MB
> downstream I/O */
>                0x82000000 0 0x01000000 0x01000000 0 0x00e00000>; /* 14MB non-
> prefetchable memory */
> 
> Can these regions be moved around however you want depending on what kind of
> mem vs io resource configurations you desire?  How about the cfg space - is
> 512K really needed?
> 
> Are we sure the committed values to linux-next 'wrong' in any way?  I still am
> seeing bus-hangs with devices behind a bridge that use io-space resources and
> am trying to figure out where the issue is.  I don't get these bus-hangs when
> using the fsl driver which is structured very different so its been difficult
> for me to determine the difference.  The mappings and the way iATU mappings
> are done are very different.

Hi Tim:
Regarding to my experience, the difference shouldn't be related with the bus hang.
Here are my DT region setup when I trying to bring up imx6 pcie on 3.1x kernel by my own driver.
                        clock-names = "pcie_axi", "pcie_ref", "pcie_bus_in", "pcie_bus_out";
                        #address-cells = <3>;
                        #size-cells = <2>;
                        ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000   /* configuration space */
                                  0x81000000 0 0          0x01f80000 0 0x00010000   /* downstream I/O */
                                  0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */
                        num-lanes = <1>;

It works sometimes, although that there is random kernel panic and system hang(log is pasted below):(
LOGS, when pericom's PI7C9X2G303EL and Intel e1000e network card is used.
...
imx-pcie 1ffc000.pcie: legacy_irq 155
imx-pcie 1ffc000.pcie: map [mem 0x01ffc000-0x01ffffff]
IMX PCIe port: link up.
PCI host bridge to bus 0000:00
pci_bus 0000:00: root bus resource [io  0x1000-0x10000]
pci_bus 0000:00: root bus resource [mem 0x01000000-0x01efffff]
pci_bus 0000:00: No busn resource found for root bus, will use [bus 00-ff]
PCI: bus0: Fast back to back transfers disabled
PCI: bus1: Fast back to back transfers disabled
pci 0000:01:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
PCI: bus2: Fast back to back transfers disabled
pci 0000:02:01.0: bridge configuration invalid ([bus 00-00]), reconfiguring
pci 0000:02:02.0: bridge configuration invalid ([bus 00-00]), reconfiguring
PCI: bus3: Fast back to back transfers disabled
PCI: bus4: Fast back to back transfers enabled
pci 0000:00:00.0: BAR 0: assigned [mem 0x01000000-0x010fffff 64bit]
pci 0000:00:00.0: BAR 8: assigned [mem 0x01100000-0x012fffff]
pci 0000:00:00.0: BAR 6: assigned [mem 0x01300000-0x0130ffff pref]
pci 0000:00:00.0: BAR 7: assigned [io  0x1000-0x1fff]
pci 0000:01:00.0: BAR 8: assigned [mem 0x01100000-0x012fffff]
pci 0000:01:00.0: BAR 7: assigned [io  0x1000-0x1fff]
pci 0000:02:01.0: BAR 8: assigned [mem 0x01100000-0x012fffff]
pci 0000:02:01.0: BAR 7: assigned [io  0x1000-0x1fff]
pci 0000:03:00.0: BAR 1: assigned [mem 0x01100000-0x011fffff]
pci 0000:03:00.0: BAR 0: assigned [mem 0x01200000-0x0121ffff]
pci 0000:03:00.0: BAR 3: assigned [mem 0x01220000-0x01223fff]
pci 0000:03:00.0: BAR 2: assigned [io  0x1000-0x101f]
pci 0000:02:01.0: PCI bridge to [bus 03]
pci 0000:02:01.0:   bridge window [io  0x1000-0x1fff]
pci 0000:02:01.0:   bridge window [mem 0x01100000-0x012fffff]
pci 0000:02:02.0: PCI bridge to [bus 04]
pci 0000:01:00.0: PCI bridge to [bus 02-04]
pci 0000:01:00.0:   bridge window [io  0x1000-0x1fff]
pci 0000:01:00.0:   bridge window [mem 0x01100000-0x012fffff]
pci 0000:00:00.0: PCI bridge to [bus 01-04]
pci 0000:00:00.0:   bridge window [io  0x1000-0x1fff]
pci 0000:00:00.0:   bridge window [mem 0x01100000-0x012fffff]
PCI: enabling device 0000:01:00.0 (0140 -> 0143)
PCI: enabling device 0000:02:01.0 (0140 -> 0143)
PCI: enabling device 0000:02:02.0 (0140 -> 0143)
...
e1000e: Intel(R) PRO/1000 Network Driver - 2.3.2-k
e1000e: Copyright(c) 1999 - 2013 Intel Corporation.
e1000e 0000:03:00.0: Disabling ASPM L0s L1
PCI: enabling device 0000:03:00.0 (0140 -> 0142)
e1000e 0000:03:00.0: Interrupt Throttling Rate (ints/sec) set to dynamic conservative mode
e1000e 0000:03:00.0 eth1: registered PHC clock
e1000e 0000:03:00.0 eth1: (PCI Express:2.5GT/s:Width x1) 00:1b:21:3a:18:8b
e1000e 0000:03:00.0 eth1: Intel(R) PRO/1000 Network Connection
e1000e 0000:03:00.0 eth1: MAC: 3, PHY: 8, PBA No: E42641-005
igb: Intel(R) Gigabit Ethernet Network Driver - version 5.0.3-k
igb: Copyright (c) 2007-2013 Intel Corporation.
...

ALSA device list:
  #0: wm8962-audio
VFS: Mounted root (nfs filesystem) on device 0:11.
devtmpfs: mounted
Freeing unused kernel memory: 324K (8082d000 - 8087e000)
Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b  <-- Kernel panic here randomly. Same phenomena when the root-fs is located in SD.

CPU1: stopping
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 3.11.0-rc3+ #13
Backtrace: 
[<80011b58>] (dump_backtrace+0x0/0x10c) from [<80011cf8>] (show_stack+0x18/0x1c)
 r6:bf896000 r5:8087dd84 r4:00000000 r3:00000000
[<80011ce0>] (show_stack+0x0/0x1c) from [<80642d8c>] (dump_stack+0x78/0x94)
[<80642d14>] (dump_stack+0x0/0x94) from [<80014a60>] (handle_IPI+0x138/0x174)
> 
> Thanks,
> 
> Tim


Thanks.

Best Regards
Richard Zhu


--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tim Harvey Oct. 18, 2013, 7:27 a.m. UTC | #11
On Thu, Oct 17, 2013 at 11:34 PM, Zhu Richard-R65037
<r65037@freescale.com> wrote:

[...]

> Hi Tim:
> Regarding to my experience, the difference shouldn't be related with the bus hang.
> Here are my DT region setup when I trying to bring up imx6 pcie on 3.1x kernel by my own driver.
>                         clock-names = "pcie_axi", "pcie_ref", "pcie_bus_in", "pcie_bus_out";
>                         #address-cells = <3>;
>                         #size-cells = <2>;
>                         ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000   /* configuration space */
>                                   0x81000000 0 0          0x01f80000 0 0x00010000   /* downstream I/O */
>                                   0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */
>                         num-lanes = <1>;
>
> It works sometimes, although that there is random kernel panic and system hang(log is pasted below):(
> LOGS, when pericom's PI7C9X2G303EL and Intel e1000e network card is used.
> ...
> imx-pcie 1ffc000.pcie: legacy_irq 155
> imx-pcie 1ffc000.pcie: map [mem 0x01ffc000-0x01ffffff]
> IMX PCIe port: link up.
> PCI host bridge to bus 0000:00
> pci_bus 0000:00: root bus resource [io  0x1000-0x10000]
> pci_bus 0000:00: root bus resource [mem 0x01000000-0x01efffff]
> pci_bus 0000:00: No busn resource found for root bus, will use [bus 00-ff]
> PCI: bus0: Fast back to back transfers disabled
> PCI: bus1: Fast back to back transfers disabled
> pci 0000:01:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
> PCI: bus2: Fast back to back transfers disabled
> pci 0000:02:01.0: bridge configuration invalid ([bus 00-00]), reconfiguring
> pci 0000:02:02.0: bridge configuration invalid ([bus 00-00]), reconfiguring
> PCI: bus3: Fast back to back transfers disabled
> PCI: bus4: Fast back to back transfers enabled
> pci 0000:00:00.0: BAR 0: assigned [mem 0x01000000-0x010fffff 64bit]
> pci 0000:00:00.0: BAR 8: assigned [mem 0x01100000-0x012fffff]
> pci 0000:00:00.0: BAR 6: assigned [mem 0x01300000-0x0130ffff pref]
> pci 0000:00:00.0: BAR 7: assigned [io  0x1000-0x1fff]
> pci 0000:01:00.0: BAR 8: assigned [mem 0x01100000-0x012fffff]
> pci 0000:01:00.0: BAR 7: assigned [io  0x1000-0x1fff]
> pci 0000:02:01.0: BAR 8: assigned [mem 0x01100000-0x012fffff]
> pci 0000:02:01.0: BAR 7: assigned [io  0x1000-0x1fff]
> pci 0000:03:00.0: BAR 1: assigned [mem 0x01100000-0x011fffff]
> pci 0000:03:00.0: BAR 0: assigned [mem 0x01200000-0x0121ffff]
> pci 0000:03:00.0: BAR 3: assigned [mem 0x01220000-0x01223fff]
> pci 0000:03:00.0: BAR 2: assigned [io  0x1000-0x101f]
> pci 0000:02:01.0: PCI bridge to [bus 03]
> pci 0000:02:01.0:   bridge window [io  0x1000-0x1fff]
> pci 0000:02:01.0:   bridge window [mem 0x01100000-0x012fffff]
> pci 0000:02:02.0: PCI bridge to [bus 04]
> pci 0000:01:00.0: PCI bridge to [bus 02-04]
> pci 0000:01:00.0:   bridge window [io  0x1000-0x1fff]
> pci 0000:01:00.0:   bridge window [mem 0x01100000-0x012fffff]
> pci 0000:00:00.0: PCI bridge to [bus 01-04]
> pci 0000:00:00.0:   bridge window [io  0x1000-0x1fff]
> pci 0000:00:00.0:   bridge window [mem 0x01100000-0x012fffff]
> PCI: enabling device 0000:01:00.0 (0140 -> 0143)
> PCI: enabling device 0000:02:01.0 (0140 -> 0143)
> PCI: enabling device 0000:02:02.0 (0140 -> 0143)
> ...
> e1000e: Intel(R) PRO/1000 Network Driver - 2.3.2-k
> e1000e: Copyright(c) 1999 - 2013 Intel Corporation.
> e1000e 0000:03:00.0: Disabling ASPM L0s L1
> PCI: enabling device 0000:03:00.0 (0140 -> 0142)
> e1000e 0000:03:00.0: Interrupt Throttling Rate (ints/sec) set to dynamic conservative mode
> e1000e 0000:03:00.0 eth1: registered PHC clock
> e1000e 0000:03:00.0 eth1: (PCI Express:2.5GT/s:Width x1) 00:1b:21:3a:18:8b
> e1000e 0000:03:00.0 eth1: Intel(R) PRO/1000 Network Connection
> e1000e 0000:03:00.0 eth1: MAC: 3, PHY: 8, PBA No: E42641-005
> igb: Intel(R) Gigabit Ethernet Network Driver - version 5.0.3-k
> igb: Copyright (c) 2007-2013 Intel Corporation.
> ...
>
> ALSA device list:
>   #0: wm8962-audio
> VFS: Mounted root (nfs filesystem) on device 0:11.
> devtmpfs: mounted
> Freeing unused kernel memory: 324K (8082d000 - 8087e000)
> Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b  <-- Kernel panic here randomly. Same phenomena when the root-fs is located in SD.

Richard,

I would suspect this is the imprecise abort issue.  Please see my
patch (http://thread.gmane.org/gmane.linux.kernel.pci/26159) resolves
that for you and reply to that thread if so.

I believe that the imprecise abort's only occurs if you have a PCIe
switch on the bus - is this your topology and if so are you
experiencing any issues with devices behind the bus that use io
regions?  If you do have a switch, perhaps you can provide me with an
'lspci -v' for comparison.

Tim
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Zhu Richard-R65037 Oct. 18, 2013, 7:45 a.m. UTC | #12
Hi


> -----Original Message-----
> From: linux-pci-owner@vger.kernel.org [mailto:linux-pci-owner@vger.kernel.org]
> On Behalf Of Tim Harvey
> Sent: Friday, October 18, 2013 3:28 PM
> To: Zhu Richard-R65037
> Cc: Sean Cross; devicetree@vger.kernel.org; linux-pci@vger.kernel.org; linux-
> arm-kernel@lists.infradead.org; Sascha Hauer; Shawn Guo; Bjorn Helgaas; Marek
> Vašut; Jingoo Han; Pratyush Anand; Troy Kisky
> Subject: Re: [PATCH v6 3/3] PCI: imx6: Add support for i.MX6 PCIe controller
> 
> On Thu, Oct 17, 2013 at 11:34 PM, Zhu Richard-R65037 <r65037@freescale.com>
> wrote:
> 
> [...]
> 
> > Hi Tim:
> > Regarding to my experience, the difference shouldn't be related with the bus
> hang.
> > Here are my DT region setup when I trying to bring up imx6 pcie on 3.1x
> kernel by my own driver.
> >                         clock-names = "pcie_axi", "pcie_ref", "pcie_bus_in",
> "pcie_bus_out";
> >                         #address-cells = <3>;
> >                         #size-cells = <2>;
> >                         ranges = <0x00000800 0 0x01f00000 0x01f00000 0
> 0x00080000   /* configuration space */
> >                                   0x81000000 0 0          0x01f80000 0
> 0x00010000   /* downstream I/O */
> >                                   0x82000000 0 0x01000000 0x01000000 0
> 0x00f00000>; /* non-prefetchable memory */
> >                         num-lanes = <1>;
> >
> > It works sometimes, although that there is random kernel panic and
> > system hang(log is pasted below):( LOGS, when pericom's PI7C9X2G303EL and
> Intel e1000e network card is used.
> > ...
> > imx-pcie 1ffc000.pcie: legacy_irq 155
> > imx-pcie 1ffc000.pcie: map [mem 0x01ffc000-0x01ffffff] IMX PCIe port:
> > link up.
> > PCI host bridge to bus 0000:00
> > pci_bus 0000:00: root bus resource [io  0x1000-0x10000] pci_bus
> > 0000:00: root bus resource [mem 0x01000000-0x01efffff] pci_bus
> > 0000:00: No busn resource found for root bus, will use [bus 00-ff]
> > PCI: bus0: Fast back to back transfers disabled
> > PCI: bus1: Fast back to back transfers disabled pci 0000:01:00.0:
> > bridge configuration invalid ([bus 00-00]), reconfiguring
> > PCI: bus2: Fast back to back transfers disabled pci 0000:02:01.0:
> > bridge configuration invalid ([bus 00-00]), reconfiguring pci
> > 0000:02:02.0: bridge configuration invalid ([bus 00-00]),
> > reconfiguring
> > PCI: bus3: Fast back to back transfers disabled
> > PCI: bus4: Fast back to back transfers enabled pci 0000:00:00.0: BAR
> > 0: assigned [mem 0x01000000-0x010fffff 64bit] pci 0000:00:00.0: BAR 8:
> > assigned [mem 0x01100000-0x012fffff] pci 0000:00:00.0: BAR 6: assigned
> > [mem 0x01300000-0x0130ffff pref] pci 0000:00:00.0: BAR 7: assigned [io
> > 0x1000-0x1fff] pci 0000:01:00.0: BAR 8: assigned [mem
> > 0x01100000-0x012fffff] pci 0000:01:00.0: BAR 7: assigned [io
> > 0x1000-0x1fff] pci 0000:02:01.0: BAR 8: assigned [mem
> > 0x01100000-0x012fffff] pci 0000:02:01.0: BAR 7: assigned [io
> > 0x1000-0x1fff] pci 0000:03:00.0: BAR 1: assigned [mem
> > 0x01100000-0x011fffff] pci 0000:03:00.0: BAR 0: assigned [mem
> > 0x01200000-0x0121ffff] pci 0000:03:00.0: BAR 3: assigned [mem
> > 0x01220000-0x01223fff] pci 0000:03:00.0: BAR 2: assigned [io
> > 0x1000-0x101f] pci 0000:02:01.0: PCI bridge to [bus 03]
> > pci 0000:02:01.0:   bridge window [io  0x1000-0x1fff]
> > pci 0000:02:01.0:   bridge window [mem 0x01100000-0x012fffff]
> > pci 0000:02:02.0: PCI bridge to [bus 04] pci 0000:01:00.0: PCI bridge
> > to [bus 02-04]
> > pci 0000:01:00.0:   bridge window [io  0x1000-0x1fff]
> > pci 0000:01:00.0:   bridge window [mem 0x01100000-0x012fffff]
> > pci 0000:00:00.0: PCI bridge to [bus 01-04]
> > pci 0000:00:00.0:   bridge window [io  0x1000-0x1fff]
> > pci 0000:00:00.0:   bridge window [mem 0x01100000-0x012fffff]
> > PCI: enabling device 0000:01:00.0 (0140 -> 0143)
> > PCI: enabling device 0000:02:01.0 (0140 -> 0143)
> > PCI: enabling device 0000:02:02.0 (0140 -> 0143) ...
> > e1000e: Intel(R) PRO/1000 Network Driver - 2.3.2-k
> > e1000e: Copyright(c) 1999 - 2013 Intel Corporation.
> > e1000e 0000:03:00.0: Disabling ASPM L0s L1
> > PCI: enabling device 0000:03:00.0 (0140 -> 0142) e1000e 0000:03:00.0:
> > Interrupt Throttling Rate (ints/sec) set to dynamic conservative mode
> > e1000e 0000:03:00.0 eth1: registered PHC clock e1000e 0000:03:00.0
> > eth1: (PCI Express:2.5GT/s:Width x1) 00:1b:21:3a:18:8b e1000e
> > 0000:03:00.0 eth1: Intel(R) PRO/1000 Network Connection e1000e
> > 0000:03:00.0 eth1: MAC: 3, PHY: 8, PBA No: E42641-005
> > igb: Intel(R) Gigabit Ethernet Network Driver - version 5.0.3-k
> > igb: Copyright (c) 2007-2013 Intel Corporation.
> > ...
> >
> > ALSA device list:
> >   #0: wm8962-audio
> > VFS: Mounted root (nfs filesystem) on device 0:11.
> > devtmpfs: mounted
> > Freeing unused kernel memory: 324K (8082d000 - 8087e000) Kernel panic
> > - not syncing: Attempted to kill init! exitcode=0x0000000b  <-- Kernel panic
> here randomly. Same phenomena when the root-fs is located in SD.
> 
> Richard,
> 
> I would suspect this is the imprecise abort issue.  Please see my patch
> (http://thread.gmane.org/gmane.linux.kernel.pci/26159) resolves that for you
> and reply to that thread if so.
> 
> I believe that the imprecise abort's only occurs if you have a PCIe switch on
> the bus - is this your topology and if so are you experiencing any issues with
> devices behind the bus that use io regions?  If you do have a switch, perhaps
> you can provide me with an 'lspci -v' for comparison.
> 
Hi Tim:
Oh, It's great. Your patch can fix my problem. 
My own patch-set of pcie driver works well when my Pericom's switch is used.
Thanks a lot.

Yes, it is.
E1000e network card request about 32 bytes IO regions during the bus enumeration procedure, 
and it works well behind the my Pericom's switch.

Based on my own pcie driver(not the one up-streamed by Sean),
Here are the log and the lspci -v results I got just now:

imx-pcie 1ffc000.pcie: legacy_irq 155
imx-pcie 1ffc000.pcie: map [mem 0x01ffc000-0x01ffffff]
imx-pcie 1ffc000.pcie: starting to link pcie port.
imx-pcie 1ffc000.pcie: Link up
PCI host bridge to bus 0000:00
pci_bus 0000:00: root bus resource [io  0x1000-0x10000]
pci_bus 0000:00: root bus resource [mem 0x01000000-0x01efffff]
pci_bus 0000:00: No busn resource found for root bus, will use [bus 00-ff]
PCI: bus0: Fast back to back transfers disabled
PCI: bus1: Fast back to back transfers disabled
pci 0000:01:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
PCI: bus2: Fast back to back transfers disabled
pci 0000:02:01.0: bridge configuration invalid ([bus 00-00]), reconfiguring
pci 0000:02:02.0: bridge configuration invalid ([bus 00-00]), reconfiguring
PCI: bus3: Fast back to back transfers disabled
PCI: bus4: Fast back to back transfers enabled
pci 0000:00:00.0: BAR 0: assigned [mem 0x01000000-0x010fffff]
pci 0000:00:00.0: BAR 8: assigned [mem 0x01100000-0x011fffff]
pci 0000:00:00.0: BAR 9: assigned [mem 0x01200000-0x012fffff pref]
pci 0000:00:00.0: BAR 6: assigned [mem 0x01300000-0x0130ffff pref]
pci 0000:00:00.0: BAR 7: assigned [io  0x1000-0x1fff]
pci 0000:01:00.0: BAR 8: assigned [mem 0x01100000-0x011fffff]
pci 0000:01:00.0: BAR 9: assigned [mem 0x01200000-0x012fffff pref]
pci 0000:01:00.0: BAR 7: assigned [io  0x1000-0x1fff]
pci 0000:02:01.0: BAR 8: assigned [mem 0x01100000-0x011fffff]
pci 0000:02:01.0: BAR 9: assigned [mem 0x01200000-0x012fffff pref]
pci 0000:02:01.0: BAR 7: assigned [io  0x1000-0x1fff]
pci 0000:03:00.0: BAR 1: assigned [mem 0x01100000-0x0117ffff]
pci 0000:03:00.0: BAR 6: assigned [mem 0x01200000-0x0123ffff pref]
pci 0000:03:00.0: BAR 0: assigned [mem 0x01180000-0x0119ffff]
pci 0000:03:00.0: BAR 3: assigned [mem 0x011a0000-0x011a3fff]
pci 0000:03:00.0: BAR 2: assigned [io  0x1000-0x101f]
pci 0000:02:01.0: PCI bridge to [bus 03]
pci 0000:02:01.0:   bridge window [io  0x1000-0x1fff]
pci 0000:02:01.0:   bridge window [mem 0x01100000-0x011fffff]
pci 0000:02:01.0:   bridge window [mem 0x01200000-0x012fffff pref]
pci 0000:02:02.0: PCI bridge to [bus 04]
pci 0000:01:00.0: PCI bridge to [bus 02-04]
pci 0000:01:00.0:   bridge window [io  0x1000-0x1fff]
pci 0000:01:00.0:   bridge window [mem 0x01100000-0x011fffff]
pci 0000:01:00.0:   bridge window [mem 0x01200000-0x012fffff pref]
pci 0000:00:00.0: PCI bridge to [bus 01-04]
pci 0000:00:00.0:   bridge window [io  0x1000-0x1fff]
pci 0000:00:00.0:   bridge window [mem 0x01100000-0x011fffff]
pci 0000:00:00.0:   bridge window [mem 0x01200000-0x012fffff pref]
PCI: enabling device 0000:01:00.0 (0140 -> 0143)
PCI: enabling device 0000:02:01.0 (0140 -> 0143)
PCI: enabling device 0000:02:02.0 (0140 -> 0143)
...
root@freescale ~$ lspci -v
00:00.0 PCI bridge: Unknown device 16c3:abcd (rev 01) (prog-if 00 [Normal decode])
        Flags: bus master, fast devsel, latency 0
        Memory at 01000000 (32-bit, non-prefetchable) [size=1M]
        Bus: primary=00, secondary=01, subordinate=04, sec-latency=0
        I/O behind bridge: 00001000-00001fff
        Memory behind bridge: 01100000-011fffff
        Prefetchable memory behind bridge: 01200000-012fffff
        [virtual] Expansion ROM at 01300000 [disabled] [size=64K]
        Capabilities: [40] Power Management version 3
        Capabilities: [50] Message Signalled Interrupts: Mask+ 64bit+ Queue=0/0 Enable-
        Capabilities: [70] Express Root Port (Slot-) IRQ 0
        Capabilities: [100] Advanced Error Reporting
        Capabilities: [140] Virtual Channel

01:00.0 PCI bridge: Pericom Semiconductor Unknown device 2303 (rev 05) (prog-if 00 [Normal decode])
        Flags: bus master, fast devsel, latency 0
        Bus: primary=01, secondary=02, subordinate=04, sec-latency=0
        I/O behind bridge: 00001000-00001fff
        Memory behind bridge: 01100000-011fffff
        Prefetchable memory behind bridge: 0000000001200000-00000000012fffff
        Capabilities: [40] Power Management version 3
        Capabilities: [5c] Vital Product Data
        Capabilities: [64] Vendor Specific Information
        Capabilities: [b0] Subsystem: Gammagraphx, Inc. Unknown device 0000
        Capabilities: [c0] Express Upstream Port IRQ 0
        Capabilities: [100] Advanced Error Reporting
        Capabilities: [140] Virtual Channel
        Capabilities: [20c] Power Budgeting
        Capabilities: [230] Unknown (24)

02:01.0 PCI bridge: Pericom Semiconductor Unknown device 2303 (rev 05) (prog-if 00 [Normal decode])
        Flags: bus master, fast devsel, latency 0
        Bus: primary=02, secondary=03, subordinate=03, sec-latency=0
        I/O behind bridge: 00001000-00001fff
        Memory behind bridge: 01100000-011fffff
        Prefetchable memory behind bridge: 0000000001200000-00000000012fffff
        Capabilities: [40] Power Management version 3
        Capabilities: [4c] Message Signalled Interrupts: Mask- 64bit+ Queue=0/0 Enable-
        Capabilities: [64] Vendor Specific Information
        Capabilities: [b0] Subsystem: Gammagraphx, Inc. Unknown device 0000
        Capabilities: [c0] Express Downstream Port (Slot+) IRQ 0
        Capabilities: [100] Advanced Error Reporting
        Capabilities: [140] Virtual Channel
        Capabilities: [20c] Power Budgeting
        Capabilities: [220] Unknown (13)

02:02.0 PCI bridge: Pericom Semiconductor Unknown device 2303 (rev 05) (prog-if 00 [Normal decode])
        Flags: bus master, fast devsel, latency 0
        Bus: primary=02, secondary=04, subordinate=04, sec-latency=0
        Capabilities: [40] Power Management version 3
        Capabilities: [4c] Message Signalled Interrupts: Mask- 64bit+ Queue=0/0 Enable-
        Capabilities: [64] Vendor Specific Information
        Capabilities: [b0] Subsystem: Gammagraphx, Inc. Unknown device 0000
        Capabilities: [c0] Express Downstream Port (Slot+) IRQ 0
        Capabilities: [100] Advanced Error Reporting
        Capabilities: [140] Virtual Channel
        Capabilities: [20c] Power Budgeting
        Capabilities: [220] Unknown (13)

03:00.0 Ethernet controller: Intel Corporation Unknown device 10d3
        Subsystem: Intel Corporation Unknown device a01f
        Flags: bus master, fast devsel, latency 0, IRQ 154
        Memory at 01180000 (32-bit, non-prefetchable) [size=128K]
        Memory at 01100000 (32-bit, non-prefetchable) [size=512K]
        I/O ports at 1000 [disabled] [size=32]
        Memory at 011a0000 (32-bit, non-prefetchable) [size=16K]
        [virtual] Expansion ROM at 01200000 [disabled] [size=256K]
        Capabilities: [c8] Power Management version 2
        Capabilities: [d0] Message Signalled Interrupts: Mask- 64bit+ Queue=0/0 Enable-
        Capabilities: [e0] Express Endpoint IRQ 0
        Capabilities: [a0] MSI-X: Enable- Mask- TabSize=5
        Capabilities: [100] Advanced Error Reporting
        Capabilities: [140] Device Serial Number 8b-18-3a-ff-ff-21-1b-00


> Tim
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in the
> body of a message to majordomo@vger.kernel.org More majordomo info at
> http://vger.kernel.org/majordomo-info.html

Best Regards
Richard

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Tim Harvey Oct. 18, 2013, 3:34 p.m. UTC | #13
On Fri, Oct 18, 2013 at 12:45 AM, Zhu Richard-R65037
<r65037@freescale.com> wrote:

[...]

>
> >
> > Richard,
> >
> > I would suspect this is the imprecise abort issue.  Please see my patch
> > (http://thread.gmane.org/gmane.linux.kernel.pci/26159) resolves that for you
> > and reply to that thread if so.
> >
> > I believe that the imprecise abort's only occurs if you have a PCIe switch on
> > the bus - is this your topology and if so are you experiencing any issues with
> > devices behind the bus that use io regions?  If you do have a switch, perhaps
> > you can provide me with an 'lspci -v' for comparison.
> >
> Hi Tim:
> Oh, It's great. Your patch can fix my problem.
> My own patch-set of pcie driver works well when my Pericom's switch is used.
> Thanks a lot.

Good to hear!  Please reply to that thread and provide an Acked-by and
Tested-by so we can get that patch upstream.

>
> Yes, it is.
> E1000e network card request about 32 bytes IO regions during the bus enumeration procedure,
> and it works well behind the my Pericom's switch.
>
> Based on my own pcie driver(not the one up-streamed by Sean),

How about with the upstream driver?  I have 'my own driver' as well
(based on Freescale's BSP) which works, but I'm very interested in
getting this upstream driver to work so we don't have to keep
maintaining our own drivers.  Can you please test with this upstream
driver?

> Here are the log and the lspci -v results I got just now:
>
> imx-pcie 1ffc000.pcie: legacy_irq 155
> imx-pcie 1ffc000.pcie: map [mem 0x01ffc000-0x01ffffff]
> imx-pcie 1ffc000.pcie: starting to link pcie port.
> imx-pcie 1ffc000.pcie: Link up
> PCI host bridge to bus 0000:00
> pci_bus 0000:00: root bus resource [io  0x1000-0x10000]
> pci_bus 0000:00: root bus resource [mem 0x01000000-0x01efffff]
> pci_bus 0000:00: No busn resource found for root bus, will use [bus 00-ff]
> PCI: bus0: Fast back to back transfers disabled
> PCI: bus1: Fast back to back transfers disabled
> pci 0000:01:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
> PCI: bus2: Fast back to back transfers disabled
> pci 0000:02:01.0: bridge configuration invalid ([bus 00-00]), reconfiguring
> pci 0000:02:02.0: bridge configuration invalid ([bus 00-00]), reconfiguring
> PCI: bus3: Fast back to back transfers disabled
> PCI: bus4: Fast back to back transfers enabled
> pci 0000:00:00.0: BAR 0: assigned [mem 0x01000000-0x010fffff]
> pci 0000:00:00.0: BAR 8: assigned [mem 0x01100000-0x011fffff]
> pci 0000:00:00.0: BAR 9: assigned [mem 0x01200000-0x012fffff pref]
> pci 0000:00:00.0: BAR 6: assigned [mem 0x01300000-0x0130ffff pref]
> pci 0000:00:00.0: BAR 7: assigned [io  0x1000-0x1fff]
> pci 0000:01:00.0: BAR 8: assigned [mem 0x01100000-0x011fffff]
> pci 0000:01:00.0: BAR 9: assigned [mem 0x01200000-0x012fffff pref]
> pci 0000:01:00.0: BAR 7: assigned [io  0x1000-0x1fff]
> pci 0000:02:01.0: BAR 8: assigned [mem 0x01100000-0x011fffff]
> pci 0000:02:01.0: BAR 9: assigned [mem 0x01200000-0x012fffff pref]
> pci 0000:02:01.0: BAR 7: assigned [io  0x1000-0x1fff]
> pci 0000:03:00.0: BAR 1: assigned [mem 0x01100000-0x0117ffff]
> pci 0000:03:00.0: BAR 6: assigned [mem 0x01200000-0x0123ffff pref]
> pci 0000:03:00.0: BAR 0: assigned [mem 0x01180000-0x0119ffff]
> pci 0000:03:00.0: BAR 3: assigned [mem 0x011a0000-0x011a3fff]
> pci 0000:03:00.0: BAR 2: assigned [io  0x1000-0x101f]
> pci 0000:02:01.0: PCI bridge to [bus 03]
> pci 0000:02:01.0:   bridge window [io  0x1000-0x1fff]
> pci 0000:02:01.0:   bridge window [mem 0x01100000-0x011fffff]
> pci 0000:02:01.0:   bridge window [mem 0x01200000-0x012fffff pref]
> pci 0000:02:02.0: PCI bridge to [bus 04]
> pci 0000:01:00.0: PCI bridge to [bus 02-04]
> pci 0000:01:00.0:   bridge window [io  0x1000-0x1fff]
> pci 0000:01:00.0:   bridge window [mem 0x01100000-0x011fffff]
> pci 0000:01:00.0:   bridge window [mem 0x01200000-0x012fffff pref]
> pci 0000:00:00.0: PCI bridge to [bus 01-04]
> pci 0000:00:00.0:   bridge window [io  0x1000-0x1fff]
> pci 0000:00:00.0:   bridge window [mem 0x01100000-0x011fffff]
> pci 0000:00:00.0:   bridge window [mem 0x01200000-0x012fffff pref]
> PCI: enabling device 0000:01:00.0 (0140 -> 0143)
> PCI: enabling device 0000:02:01.0 (0140 -> 0143)
> PCI: enabling device 0000:02:02.0 (0140 -> 0143)
> ...
> root@freescale ~$ lspci -v
> 00:00.0 PCI bridge: Unknown device 16c3:abcd (rev 01) (prog-if 00 [Normal decode])
>         Flags: bus master, fast devsel, latency 0
>         Memory at 01000000 (32-bit, non-prefetchable) [size=1M]
>         Bus: primary=00, secondary=01, subordinate=04, sec-latency=0
>         I/O behind bridge: 00001000-00001fff
>         Memory behind bridge: 01100000-011fffff
>         Prefetchable memory behind bridge: 01200000-012fffff
>         [virtual] Expansion ROM at 01300000 [disabled] [size=64K]
>         Capabilities: [40] Power Management version 3
>         Capabilities: [50] Message Signalled Interrupts: Mask+ 64bit+ Queue=0/0 Enable-
>         Capabilities: [70] Express Root Port (Slot-) IRQ 0
>         Capabilities: [100] Advanced Error Reporting
>         Capabilities: [140] Virtual Channel
>
> 01:00.0 PCI bridge: Pericom Semiconductor Unknown device 2303 (rev 05) (prog-if 00 [Normal decode])
>         Flags: bus master, fast devsel, latency 0
>         Bus: primary=01, secondary=02, subordinate=04, sec-latency=0
>         I/O behind bridge: 00001000-00001fff
>         Memory behind bridge: 01100000-011fffff
>         Prefetchable memory behind bridge: 0000000001200000-00000000012fffff
>         Capabilities: [40] Power Management version 3
>         Capabilities: [5c] Vital Product Data
>         Capabilities: [64] Vendor Specific Information
>         Capabilities: [b0] Subsystem: Gammagraphx, Inc. Unknown device 0000
>         Capabilities: [c0] Express Upstream Port IRQ 0
>         Capabilities: [100] Advanced Error Reporting
>         Capabilities: [140] Virtual Channel
>         Capabilities: [20c] Power Budgeting
>         Capabilities: [230] Unknown (24)
>
> 02:01.0 PCI bridge: Pericom Semiconductor Unknown device 2303 (rev 05) (prog-if 00 [Normal decode])
>         Flags: bus master, fast devsel, latency 0
>         Bus: primary=02, secondary=03, subordinate=03, sec-latency=0
>         I/O behind bridge: 00001000-00001fff
>         Memory behind bridge: 01100000-011fffff
>         Prefetchable memory behind bridge: 0000000001200000-00000000012fffff
>         Capabilities: [40] Power Management version 3
>         Capabilities: [4c] Message Signalled Interrupts: Mask- 64bit+ Queue=0/0 Enable-
>         Capabilities: [64] Vendor Specific Information
>         Capabilities: [b0] Subsystem: Gammagraphx, Inc. Unknown device 0000
>         Capabilities: [c0] Express Downstream Port (Slot+) IRQ 0
>         Capabilities: [100] Advanced Error Reporting
>         Capabilities: [140] Virtual Channel
>         Capabilities: [20c] Power Budgeting
>         Capabilities: [220] Unknown (13)
>
> 02:02.0 PCI bridge: Pericom Semiconductor Unknown device 2303 (rev 05) (prog-if 00 [Normal decode])
>         Flags: bus master, fast devsel, latency 0
>         Bus: primary=02, secondary=04, subordinate=04, sec-latency=0
>         Capabilities: [40] Power Management version 3
>         Capabilities: [4c] Message Signalled Interrupts: Mask- 64bit+ Queue=0/0 Enable-
>         Capabilities: [64] Vendor Specific Information
>         Capabilities: [b0] Subsystem: Gammagraphx, Inc. Unknown device 0000
>         Capabilities: [c0] Express Downstream Port (Slot+) IRQ 0
>         Capabilities: [100] Advanced Error Reporting
>         Capabilities: [140] Virtual Channel
>         Capabilities: [20c] Power Budgeting
>         Capabilities: [220] Unknown (13)
>
> 03:00.0 Ethernet controller: Intel Corporation Unknown device 10d3
>         Subsystem: Intel Corporation Unknown device a01f
>         Flags: bus master, fast devsel, latency 0, IRQ 154
>         Memory at 01180000 (32-bit, non-prefetchable) [size=128K]
>         Memory at 01100000 (32-bit, non-prefetchable) [size=512K]
>         I/O ports at 1000 [disabled] [size=32]
>         Memory at 011a0000 (32-bit, non-prefetchable) [size=16K]
>         [virtual] Expansion ROM at 01200000 [disabled] [size=256K]
>         Capabilities: [c8] Power Management version 2
>         Capabilities: [d0] Message Signalled Interrupts: Mask- 64bit+ Queue=0/0 Enable-
>         Capabilities: [e0] Express Endpoint IRQ 0
>         Capabilities: [a0] MSI-X: Enable- Mask- TabSize=5
>         Capabilities: [100] Advanced Error Reporting
>         Capabilities: [140] Device Serial Number 8b-18-3a-ff-ff-21-1b-00
>

The above device does show an io resource but it says its disabled?
I'm not sure what that means, but I'm not convinced you would see the
same issue as I do if the io resource isn't being used.

Tim
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sinan Akman Nov. 5, 2013, 5:35 p.m. UTC | #14
On 10/18/2013 11:34 AM, Tim Harvey wrote:
> On Fri, Oct 18, 2013 at 12:45 AM, Zhu Richard-R65037
> [...]
> How about with the upstream driver?  I have 'my own driver' as well
> (based on Freescale's BSP) which works, but I'm very interested in
> getting this upstream driver to work so we don't have to keep
> maintaining our own drivers.  Can you please test with this upstream
> driver?

   Tim, Sean what is the status of this patch ? Is it part of any tree 
already ? I'd like to test few things.

   Thanks

   Sinan Akman
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bjorn Helgaas Nov. 5, 2013, 8:28 p.m. UTC | #15
On Tue, Nov 5, 2013 at 10:35 AM, Sinan Akman <sinan@writeme.com> wrote:
>   Tim, Sean what is the status of this patch ? Is it part of any tree
> already ? I'd like to test few things.

This patch is in my "next" branch and will be merged into Linus' tree
during the v3.13 merge window (probably next week).  It's also in the
linux-next tree.

http://git.kernel.org/cgit/linux/kernel/git/helgaas/pci.git/commit/?h=next&id=bb38919ec56e0758c3ae56dfc091dcde1391353e
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt
index eabcb4b..dd8d920 100644
--- a/Documentation/devicetree/bindings/pci/designware-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt
@@ -3,7 +3,7 @@ 
 Required properties:
 - compatible: should contain "snps,dw-pcie" to identify the
 	core, plus an identifier for the specific instance, such
-	as "samsung,exynos5440-pcie".
+	as "samsung,exynos5440-pcie" or "fsl,imx6q-pcie".
 - reg: base addresses and lengths of the pcie controller,
 	the phy controller, additional register for the phy controller.
 - interrupts: interrupt values for level interrupt,
@@ -21,6 +21,11 @@  Required properties:
 - num-lanes: number of lanes to use
 - reset-gpio: gpio pin number of power good signal
 
+Optional properties for fsl,imx6q-pcie
+- power-on-gpio: gpio pin number of power-enable signal
+- wake-up-gpio: gpio pin number of incoming wakeup signal
+- disable-gpio: gpio pin number of outgoing rfkill/endpoint disable signal
+
 Example:
 
 SoC specific DT Entry:
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index ccd55c2..125202e 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -116,6 +116,22 @@ 
 			arm,data-latency = <4 2 3>;
 		};
 
+		pcie: pcie@0x01000000 {
+			compatible = "fsl,imx6q-pcie", "snps,dw-pcie";
+			reg = <0x01ffc000 0x4000>; /* DBI */
+			#address-cells = <3>;
+			#size-cells = <2>;
+			device_type = "pci";
+			ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000 /* configuration space */
+				  0x81000000 0 0          0x01f80000 0 0x00010000 /* downstream I/O */
+				  0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */
+			num-lanes = <1>;
+			interrupts = <0 123 0x04>;
+			clocks = <&clks 189>, <&clks 187>, <&clks 205>, <&clks 144>;
+			clock-names = "pcie_ref_125m", "sata_ref_100m", "lvds_gate", "pcie_axi";
+			status = "disabled";
+		};
+
 		pmu {
 			compatible = "arm,cortex-a9-pmu";
 			interrupts = <0 94 0x04>;
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 29a8af6..e6ac281 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -801,6 +801,8 @@  config SOC_IMX6Q
 	select HAVE_IMX_SRC
 	select HAVE_SMP
 	select MFD_SYSCON
+	select MIGHT_HAVE_PCI
+	select PCI_DOMAINS if PCI
 	select PINCTRL
 	select PINCTRL_IMX6Q
 	select PL310_ERRATA_588369 if CACHE_PL310
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index d94be84..6956995 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -621,6 +621,10 @@  static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	if (ret)
 		pr_warn("failed to set up CLKO: %d\n", ret);
 
+	/* All existing boards with PCIe use LVDS1 */
+	if (IS_ENABLED(CONFIG_PCI_IMX6))
+		clk_set_parent(clk[lvds1_sel], clk[sata_ref]);
+
 	/* Set initial power mode */
 	imx6q_set_lpm(WAIT_CLOCKED);
 
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 3d95048..efa24d9 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -15,6 +15,12 @@  config PCI_EXYNOS
 	select PCIEPORTBUS
 	select PCIE_DW
 
+config PCI_IMX6
+	bool "Freescale i.MX6 PCIe controller"
+	depends on SOC_IMX6Q
+	select PCIEPORTBUS
+	select PCIE_DW
+
 config PCI_TEGRA
 	bool "NVIDIA Tegra PCIe controller"
 	depends on ARCH_TEGRA
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index c9a997b..287d6a0 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -1,4 +1,5 @@ 
 obj-$(CONFIG_PCIE_DW) += pcie-designware.o
 obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
+obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
 obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
 obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
new file mode 100644
index 0000000..f68cc2e
--- /dev/null
+++ b/drivers/pci/host/pci-imx6.c
@@ -0,0 +1,576 @@ 
+/*
+ * PCIe host controller driver for Freescale i.MX6 SoCs
+ *
+ * Copyright (C) 2013 Kosagi
+ *		http://www.kosagi.com
+ *
+ * Author: Sean Cross <xobs@kosagi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+
+#include "pcie-designware.h"
+
+#define to_imx6_pcie(x)	container_of(x, struct imx6_pcie, pp)
+
+struct imx6_pcie {
+	int			reset_gpio;
+	int			power_on_gpio;
+	int			wake_up_gpio;
+	int			disable_gpio;
+	struct clk		*lvds_gate;
+	struct clk		*sata_ref_100m;
+	struct clk		*pcie_ref_125m;
+	struct clk		*pcie_axi;
+	struct pcie_port	pp;
+	struct regmap		*iomuxc_gpr;
+	void __iomem		*mem_base;
+};
+
+/* PCIe Port Logic registers (memory-mapped) */
+#define PL_OFFSET 0x700
+#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
+#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
+
+#define PCIE_PHY_CTRL (PL_OFFSET + 0x114)
+#define PCIE_PHY_CTRL_DATA_LOC 0
+#define PCIE_PHY_CTRL_CAP_ADR_LOC 16
+#define PCIE_PHY_CTRL_CAP_DAT_LOC 17
+#define PCIE_PHY_CTRL_WR_LOC 18
+#define PCIE_PHY_CTRL_RD_LOC 19
+
+#define PCIE_PHY_STAT (PL_OFFSET + 0x110)
+#define PCIE_PHY_STAT_ACK_LOC 16
+
+/* PHY registers (not memory-mapped) */
+#define PCIE_PHY_RX_ASIC_OUT 0x100D
+
+#define PHY_RX_OVRD_IN_LO 0x1005
+#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
+#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3)
+
+static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)
+{
+	u32 val;
+	u32 max_iterations = 10;
+	u32 wait_counter = 0;
+
+	do {
+		val = readl(dbi_base + PCIE_PHY_STAT);
+		val = (val >> PCIE_PHY_STAT_ACK_LOC) & 0x1;
+		wait_counter++;
+
+		if (val == exp_val)
+			return 0;
+
+		udelay(1);
+	} while ((wait_counter < max_iterations) && (val != exp_val));
+
+	return -ETIMEDOUT;
+}
+
+static int pcie_phy_wait_ack(void __iomem *dbi_base, int addr)
+{
+	u32 val;
+	int ret;
+
+	val = addr << PCIE_PHY_CTRL_DATA_LOC;
+	writel(val, dbi_base + PCIE_PHY_CTRL);
+
+	val |= (0x1 << PCIE_PHY_CTRL_CAP_ADR_LOC);
+	writel(val, dbi_base + PCIE_PHY_CTRL);
+
+	ret = pcie_phy_poll_ack(dbi_base, 1);
+	if (ret)
+		return ret;
+
+	val = addr << PCIE_PHY_CTRL_DATA_LOC;
+	writel(val, dbi_base + PCIE_PHY_CTRL);
+
+	ret = pcie_phy_poll_ack(dbi_base, 0);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */
+static int pcie_phy_read(void __iomem *dbi_base, int addr , int *data)
+{
+	u32 val, phy_ctl;
+	int ret;
+
+	ret = pcie_phy_wait_ack(dbi_base, addr);
+	if (ret)
+		return ret;
+
+	/* assert Read signal */
+	phy_ctl = 0x1 << PCIE_PHY_CTRL_RD_LOC;
+	writel(phy_ctl, dbi_base + PCIE_PHY_CTRL);
+
+	ret = pcie_phy_poll_ack(dbi_base, 1);
+	if (ret)
+		return ret;
+
+	val = readl(dbi_base + PCIE_PHY_STAT);
+	*data = val & 0xffff;
+
+	/* deassert Read signal */
+	writel(0x00, dbi_base + PCIE_PHY_CTRL);
+
+	ret = pcie_phy_poll_ack(dbi_base, 0);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int pcie_phy_write(void __iomem *dbi_base, int addr, int data)
+{
+	u32 var;
+	int ret;
+
+	/* write addr */
+	/* cap addr */
+	ret = pcie_phy_wait_ack(dbi_base, addr);
+	if (ret)
+		return ret;
+
+	var = data << PCIE_PHY_CTRL_DATA_LOC;
+	writel(var, dbi_base + PCIE_PHY_CTRL);
+
+	/* capture data */
+	var |= (0x1 << PCIE_PHY_CTRL_CAP_DAT_LOC);
+	writel(var, dbi_base + PCIE_PHY_CTRL);
+
+	ret = pcie_phy_poll_ack(dbi_base, 1);
+	if (ret)
+		return ret;
+
+	/* deassert cap data */
+	var = data << PCIE_PHY_CTRL_DATA_LOC;
+	writel(var, dbi_base + PCIE_PHY_CTRL);
+
+	/* wait for ack de-assetion */
+	ret = pcie_phy_poll_ack(dbi_base, 0);
+	if (ret)
+		return ret;
+
+	/* assert wr signal */
+	var = 0x1 << PCIE_PHY_CTRL_WR_LOC;
+	writel(var, dbi_base + PCIE_PHY_CTRL);
+
+	/* wait for ack */
+	ret = pcie_phy_poll_ack(dbi_base, 1);
+	if (ret)
+		return ret;
+
+	/* deassert wr signal */
+	var = data << PCIE_PHY_CTRL_DATA_LOC;
+	writel(var, dbi_base + PCIE_PHY_CTRL);
+
+	/* wait for ack de-assetion */
+	ret = pcie_phy_poll_ack(dbi_base, 0);
+	if (ret)
+		return ret;
+
+	writel(0x0, dbi_base + PCIE_PHY_CTRL);
+
+	return 0;
+}
+
+/*  Added for PCI abort handling */
+static int imx6q_pcie_abort_handler(unsigned long addr,
+		unsigned int fsr, struct pt_regs *regs)
+{
+	/*
+	 * If it was an imprecise abort, then we need to correct the
+	 * return address to be _after_ the instruction.
+	 */
+	if (fsr & (1 << 10))
+		regs->ARM_pc += 4;
+	return 0;
+}
+
+static int imx6_pcie_assert_core_reset(struct pcie_port *pp)
+{
+	struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+			IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18);
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+			IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+			IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16);
+
+	gpio_set_value(imx6_pcie->reset_gpio, 0);
+	msleep(100);
+	gpio_set_value(imx6_pcie->reset_gpio, 1);
+
+	return 0;
+}
+
+static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
+{
+	struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+	int ret;
+
+	if (gpio_is_valid(imx6_pcie->power_on_gpio))
+		gpio_set_value(imx6_pcie->power_on_gpio, 1);
+
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+			IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+			IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
+
+	ret = clk_prepare_enable(imx6_pcie->sata_ref_100m);
+	if (ret) {
+		dev_err(pp->dev, "unable to enable sata_ref_100m\n");
+		goto err_sata_ref;
+	}
+
+	ret = clk_prepare_enable(imx6_pcie->pcie_ref_125m);
+	if (ret) {
+		dev_err(pp->dev, "unable to enable pcie_ref_125m\n");
+		goto err_pcie_ref;
+	}
+
+	ret = clk_prepare_enable(imx6_pcie->lvds_gate);
+	if (ret) {
+		dev_err(pp->dev, "unable to enable lvds_gate\n");
+		goto err_lvds_gate;
+	}
+
+	ret = clk_prepare_enable(imx6_pcie->pcie_axi);
+	if (ret) {
+		dev_err(pp->dev, "unable to enable pcie_axi\n");
+		goto err_pcie_axi;
+	}
+
+	/* allow the clocks to stabilize */
+	usleep_range(200, 500);
+
+	return 0;
+
+err_pcie_axi:
+	clk_disable_unprepare(imx6_pcie->lvds_gate);
+err_lvds_gate:
+	clk_disable_unprepare(imx6_pcie->pcie_ref_125m);
+err_pcie_ref:
+	clk_disable_unprepare(imx6_pcie->sata_ref_100m);
+err_sata_ref:
+	return ret;
+
+}
+
+static void imx6_pcie_init_phy(struct pcie_port *pp)
+{
+	struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+			IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
+
+	/* configure constant input signal to the pcie ctrl and phy */
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+			IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12);
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+			IMX6Q_GPR12_LOS_LEVEL, 9 << 4);
+
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
+			IMX6Q_GPR8_TX_DEEMPH_GEN1, 0 << 0);
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
+			IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB, 0 << 6);
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
+			IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB, 20 << 12);
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
+			IMX6Q_GPR8_TX_SWING_FULL, 127 << 18);
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
+			IMX6Q_GPR8_TX_SWING_LOW, 127 << 25);
+}
+
+static void imx6_pcie_host_init(struct pcie_port *pp)
+{
+	int count = 0;
+	struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+
+	imx6_pcie_assert_core_reset(pp);
+
+	imx6_pcie_init_phy(pp);
+
+	imx6_pcie_deassert_core_reset(pp);
+
+	dw_pcie_setup_rc(pp);
+
+	regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+			IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
+
+	while (!dw_pcie_link_up(pp)) {
+		usleep_range(100, 1000);
+		count++;
+		if (count >= 10) {
+			dev_err(pp->dev, "phy link never came up\n");
+			dev_dbg(pp->dev,
+				"DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
+				readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
+				readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
+			break;
+		}
+	}
+
+	return;
+}
+
+static int imx6_pcie_link_up(struct pcie_port *pp)
+{
+	u32 rc, ltssm, rx_valid, temp;
+
+	/* link is debug bit 36, debug register 1 starts at bit 32 */
+	rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << (36 - 32));
+	if (rc)
+		return -EAGAIN;
+
+	/*
+	 * From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
+	 * Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
+	 * If (MAC/LTSSM.state == Recovery.RcvrLock)
+	 * && (PHY/rx_valid==0) then pulse PHY/rx_reset. Transition
+	 * to gen2 is stuck
+	 */
+	pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
+	ltssm = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0) & 0x3F;
+
+	if (rx_valid & 0x01)
+		return 0;
+
+	if (ltssm != 0x0d)
+		return 0;
+
+	dev_err(pp->dev,
+		"transition to gen2 is stuck, reset PHY!\n");
+
+	pcie_phy_read(pp->dbi_base,
+		PHY_RX_OVRD_IN_LO, &temp);
+	temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN
+		| PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+	pcie_phy_write(pp->dbi_base,
+		PHY_RX_OVRD_IN_LO, temp);
+
+	usleep_range(2000, 3000);
+
+	pcie_phy_read(pp->dbi_base,
+		PHY_RX_OVRD_IN_LO, &temp);
+	temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN
+		| PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+	pcie_phy_write(pp->dbi_base,
+		PHY_RX_OVRD_IN_LO, temp);
+
+	return 0;
+}
+
+static struct pcie_host_ops imx6_pcie_host_ops = {
+	.link_up = imx6_pcie_link_up,
+	.host_init = imx6_pcie_host_init,
+};
+
+static int imx6_add_pcie_port(struct pcie_port *pp,
+			struct platform_device *pdev)
+{
+	int ret;
+
+	pp->irq = platform_get_irq(pdev, 0);
+	if (!pp->irq) {
+		dev_err(&pdev->dev, "failed to get irq\n");
+		return -ENODEV;
+	}
+
+	pp->root_bus_nr = -1;
+	pp->ops = &imx6_pcie_host_ops;
+
+	spin_lock_init(&pp->conf_lock);
+	ret = dw_pcie_host_init(pp);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize host\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __init imx6_pcie_probe(struct platform_device *pdev)
+{
+	struct imx6_pcie *imx6_pcie;
+	struct pcie_port *pp;
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *dbi_base;
+	int ret;
+
+	imx6_pcie = devm_kzalloc(&pdev->dev, sizeof(*imx6_pcie), GFP_KERNEL);
+	if (!imx6_pcie)
+		return -ENOMEM;
+
+	pp = &imx6_pcie->pp;
+	pp->dev = &pdev->dev;
+
+	/* Added for PCI abort handling */
+	hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0,
+		"imprecise external abort");
+
+	dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!dbi_base) {
+		dev_err(&pdev->dev, "dbi_base memory resource not found\n");
+		return -ENODEV;
+	}
+
+	pp->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base);
+	if (IS_ERR(pp->dbi_base)) {
+		dev_err(&pdev->dev, "unable to remap dbi_base\n");
+		ret = PTR_ERR(pp->dbi_base);
+		goto err;
+	}
+
+	/* Fetch GPIOs */
+	imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
+	if (!gpio_is_valid(imx6_pcie->reset_gpio)) {
+		dev_err(&pdev->dev, "no reset-gpio defined\n");
+		ret = -ENODEV;
+	}
+	ret = devm_gpio_request_one(&pdev->dev,
+				imx6_pcie->reset_gpio,
+				GPIOF_OUT_INIT_LOW,
+				"PCIe reset");
+	if (ret) {
+		dev_err(&pdev->dev, "unable to get reset gpio\n");
+		goto err;
+	}
+
+	imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0);
+	if (gpio_is_valid(imx6_pcie->power_on_gpio)) {
+		ret = devm_gpio_request_one(&pdev->dev,
+					imx6_pcie->power_on_gpio,
+					GPIOF_OUT_INIT_LOW,
+					"PCIe power enable");
+		if (ret) {
+			dev_err(&pdev->dev, "unable to get power-on gpio\n");
+			goto err;
+		}
+	}
+
+	imx6_pcie->wake_up_gpio = of_get_named_gpio(np, "wake-up-gpio", 0);
+	if (gpio_is_valid(imx6_pcie->wake_up_gpio)) {
+		ret = devm_gpio_request_one(&pdev->dev,
+					imx6_pcie->wake_up_gpio,
+					GPIOF_IN,
+					"PCIe wake up");
+		if (ret) {
+			dev_err(&pdev->dev, "unable to get wake-up gpio\n");
+			goto err;
+		}
+	}
+
+	imx6_pcie->disable_gpio = of_get_named_gpio(np, "disable-gpio", 0);
+	if (gpio_is_valid(imx6_pcie->disable_gpio)) {
+		ret = devm_gpio_request_one(&pdev->dev,
+					imx6_pcie->disable_gpio,
+					GPIOF_OUT_INIT_HIGH,
+					"PCIe disable endpoint");
+		if (ret) {
+			dev_err(&pdev->dev, "unable to get disable-ep gpio\n");
+			goto err;
+		}
+	}
+
+	/* Fetch clocks */
+	imx6_pcie->lvds_gate = clk_get(&pdev->dev, "lvds_gate");
+	if (IS_ERR(imx6_pcie->lvds_gate)) {
+		dev_err(&pdev->dev,
+			"lvds_gate clock select missing or invalid\n");
+		ret = PTR_ERR(imx6_pcie->lvds_gate);
+		goto err;
+	}
+
+	imx6_pcie->sata_ref_100m = clk_get(&pdev->dev, "sata_ref_100m");
+	if (IS_ERR(imx6_pcie->sata_ref_100m)) {
+		dev_err(&pdev->dev,
+			"sata_ref_100m clock source missing or invalid\n");
+		ret = PTR_ERR(imx6_pcie->sata_ref_100m);
+		goto err;
+	}
+
+	imx6_pcie->pcie_ref_125m = clk_get(&pdev->dev, "pcie_ref_125m");
+	if (IS_ERR(imx6_pcie->pcie_ref_125m)) {
+		dev_err(&pdev->dev,
+			"pcie_ref_125m clock source missing or invalid\n");
+		ret = PTR_ERR(imx6_pcie->pcie_ref_125m);
+		goto err;
+	}
+
+	imx6_pcie->pcie_axi = clk_get(&pdev->dev, "pcie_axi");
+	if (IS_ERR(imx6_pcie->pcie_axi)) {
+		dev_err(&pdev->dev,
+			"pcie_axi clock source missing or invalid\n");
+		ret = PTR_ERR(imx6_pcie->pcie_axi);
+		goto err;
+	}
+
+	/* Grab GPR config register range */
+	imx6_pcie->iomuxc_gpr =
+		 syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+	if (IS_ERR(imx6_pcie->iomuxc_gpr)) {
+		dev_err(&pdev->dev, "unable to find iomuxc registers\n");
+		ret = PTR_ERR(imx6_pcie->iomuxc_gpr);
+		goto err;
+	}
+
+	ret = imx6_add_pcie_port(pp, pdev);
+	if (ret < 0)
+		goto err;
+
+	platform_set_drvdata(pdev, imx6_pcie);
+	return 0;
+
+err:
+	return ret;
+}
+
+static const struct of_device_id imx6_pcie_of_match[] = {
+	{ .compatible = "fsl,imx6q-pcie", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, imx6_pcie_of_match);
+
+static struct platform_driver imx6_pcie_driver = {
+	.driver = {
+		.name	= "imx6q-pcie",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(imx6_pcie_of_match),
+	},
+};
+
+/* Freescale PCIe driver does not allow module unload */
+
+static int __init imx6_init(void)
+{
+	return platform_driver_probe(&imx6_pcie_driver, imx6_pcie_probe);
+}
+module_init(imx6_init);
+
+MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
+MODULE_DESCRIPTION("Freescale i.MX6 PCIe host controller driver");
+MODULE_LICENSE("GPL v2");