diff mbox

[v1,5/5] pci: keystone: add pcie driver based on designware core driver

Message ID 1400169692-9677-6-git-send-email-m-karicheri2@ti.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Murali Karicheri May 15, 2014, 4:01 p.m. UTC
keystone pcie hardware is based on designware version 3.65.
This driver make use of the functions from pci-dw-old.c and
pci-dw-old-msi.c to implement the driver.

Driver mainly handle the platform specific part of the PCI
driver and depends on DW Old driver to configure application
specific registers. Also routes the irq events and ack the
interrupt after the same is acked by the end point device
driver. This requires irqchip implementation for legacy and MSI
irq handling. This patch adds a quirks to override the max read
request size as PCI controller has a limit of 256 bytes.

CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>

Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
 drivers/pci/host/Kconfig                           |    8 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
 drivers/pci/quirks.c                               |   13 +
 5 files changed, 490 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
 create mode 100644 drivers/pci/host/pci-keystone.c

Comments

Arnd Bergmann May 15, 2014, 4:23 p.m. UTC | #1
On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:

> +static int
> +keystone_pcie_fault(unsigned long addr, unsigned int fsr,
> +		struct pt_regs *regs)
> +{
> +	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
> +
> +	if ((instr & 0x0e100090) == 0x00100090) {
> +		int reg = (instr >> 12) & 15;
> +
> +		regs->uregs[reg] = -1;
> +		regs->ARM_pc += 4;
> +	}
> +
> +	return 0;
> +}

This needs to check in the PCI host registers what happened and do
some appropriate action. If the fault was not caused by PCIe, it
should not be ignored here but get passed on to the next handler.

> +static int __init ks_pcie_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device *dev = &pdev->dev;
> +	struct keystone_pcie *ks_pcie;
> +	void __iomem *devstat;
> +	struct pcie_port *pp;
> +	struct resource *res;
> +	struct phy *phy;
> +	int ret = 0;
> +	u32 val;
> +
> +	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
> +				GFP_KERNEL);
> +	if (!ks_pcie) {
> +		dev_err(dev, "no memory for keystone pcie\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* check if serdes phy needs to be enabled */
> +	if (of_get_property(np, "ti,init-phy", NULL) != NULL) {
> +		phy = devm_phy_get(dev, "pcie-phy");
> +			if (IS_ERR(phy))
> +				return PTR_ERR(phy);
> +
> +		ret = phy_init(phy);
> +		if (ret < 0)
> +			return ret;
> +	}

I think you can just call devm_phy_get() unconditionally here and
get rid of the ti,init-phy property. If there is no phy, don't
initialize it.

> +
> +	ret = add_pcie_port(ks_pcie, pdev);
> +	if (ret < 0)
> +		goto fail_clk;
> +
> +	platform_set_drvdata(pdev, ks_pcie);

Set the platform data first, then add the port.

> +	dev_info(dev, "pcie rc probe success\n");

Remove this.

> +#ifdef CONFIG_PCI_KEYSTONE
> +/*
> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> + */
> +static void quirk_limit_readrequest(struct pci_dev *dev)
> +{
> +	int readrq = pcie_get_readrq(dev);
> +
> +	if (readrq > 256)
> +		pcie_set_readrq(dev, 256);
> +}
> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> +#endif /* CONFIG_PCI_KEYSTONE */

This doesn't work: you can't just limit do this for all devices just based
on PCI_KEYSTONE being enabled, you have to check if you are actually using
this controller.

	Arnd
--
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
Arnd Bergmann May 15, 2014, 4:28 p.m. UTC | #2
On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
> +Sample bindings shown below:-
> +
> + - Remove ti,enable-linktrain if boot loader already does Link training and do EP
> +   configuration.
> + - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
> +   link

You actually have to document all the properties. Have a look at the
other bindings for what this means.

> +
> +               pcie@21800000 {
> +                       compatible = "ti,keystone-pcie";
> +                       device_type = "pci";
> +                       clocks = <&clkpcie>;
> +                       clock-names = "pcie";

The dw-pcie binding lists two clocks.

> +                       #address-cells = >;
> +                       #size-cells = <2>;
> +                       reg =  <0x21800000 0x1000>, <0x0262014c 4>;
> +                       reg-names = "reg_rc_app", "reg_devcfg";

There should be standard names that are documented in the binding.

> +                       interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
> +                                       <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */

What are all these interrupts?

> +                       ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
> +                                 0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
> +                                 0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */

Please move the config space into 'reg' now instead of 'ranges'.
This was a mistake earlier, and there are already other front-ends
doing the same thing.

> +                       num-lanes = <2>;
> +                       ti,enable-linktrain;
> +                       ti,init-phy;
> +
> +                       /* PCIE phy */
> +                       phys = <&pcie0_phy>;
> +                       phy-names = "pcie-phy";
> +
> +                       #interrupt-cells = <1>;
> +                       interrupt-map-mask = <0 0 0 0>;
> +                       interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
> +                                       <0 0 0 2 &pcie_intc 2>, // INT B
> +                                       <0 0 0 3 &pcie_intc 3>, // INT C
> +                                       <0 0 0 4 &pcie_intc 4>; // INT D

I think this is the wrong map-mask.

	Arnd
--
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
Murali Karicheri May 15, 2014, 5:45 p.m. UTC | #3
Arnd,


Thanks for the review. I may have more questions as I digest the 
comments. Here is the
immediate one.

>> +#ifdef CONFIG_PCI_KEYSTONE
>> +/*
>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>> + */
>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>> +{
>> +	int readrq = pcie_get_readrq(dev);
>> +
>> +	if (readrq > 256)
>> +		pcie_set_readrq(dev, 256);
>> +}
>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>> +#endif /* CONFIG_PCI_KEYSTONE */
> This doesn't work: you can't just limit do this for all devices just based
> on PCI_KEYSTONE being enabled, you have to check if you are actually using
> this controller.
>
> 	Arnd
  I assume, I need to check if PCI controller's vendor ID/ device ID 
match with the keystone
  PCI controller's ID and call pcie_set_readrq() for all of the slave 
PCI devices and do this fixup.
Is this correct understanding?  If you can point me to an example code 
for this that will be
really helpful so that I can avoid re-inventing the wheel.

Murali

--
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
Arnd Bergmann May 15, 2014, 6:20 p.m. UTC | #4
On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> >> +#ifdef CONFIG_PCI_KEYSTONE
> >> +/*
> >> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> >> + */
> >> +static void quirk_limit_readrequest(struct pci_dev *dev)
> >> +{
> >> +    int readrq = pcie_get_readrq(dev);
> >> +
> >> +    if (readrq > 256)
> >> +            pcie_set_readrq(dev, 256);
> >> +}
> >> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> >> +#endif /* CONFIG_PCI_KEYSTONE */
> > This doesn't work: you can't just limit do this for all devices just based
> > on PCI_KEYSTONE being enabled, you have to check if you are actually using
> > this controller.
> >
> >       Arnd
>   I assume, I need to check if PCI controller's vendor ID/ device ID 
> match with the keystone
>   PCI controller's ID and call pcie_set_readrq() for all of the slave 
> PCI devices and do this fixup.
> Is this correct understanding?  If you can point me to an example code 
> for this that will be
> really helpful so that I can avoid re-inventing the wheel.

I think it would be best to move the quirk into the keystone pci driver
and compare compare the dev->driver pointer of the PCI controller device.

	Arnd
--
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
Jason Gunthorpe May 15, 2014, 6:39 p.m. UTC | #5
On Thu, May 15, 2014 at 08:20:13PM +0200, Arnd Bergmann wrote:
> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> > >> +#ifdef CONFIG_PCI_KEYSTONE
> > >> +/*
> > >> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> > >> + */
> > >> +static void quirk_limit_readrequest(struct pci_dev *dev)
> > >> +{
> > >> +    int readrq = pcie_get_readrq(dev);
> > >> +
> > >> +    if (readrq > 256)
> > >> +            pcie_set_readrq(dev, 256);
> > >> +}
> > >> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> > >> +#endif /* CONFIG_PCI_KEYSTONE */
> > > This doesn't work: you can't just limit do this for all devices just based
> > > on PCI_KEYSTONE being enabled, you have to check if you are actually using
> > > this controller.
> > >
> > >       Arnd
> >   I assume, I need to check if PCI controller's vendor ID/ device ID 
> > match with the keystone
> >   PCI controller's ID and call pcie_set_readrq() for all of the slave 
> > PCI devices and do this fixup.
> > Is this correct understanding?  If you can point me to an example code 
> > for this that will be
> > really helpful so that I can avoid re-inventing the wheel.
> 
> I think it would be best to move the quirk into the keystone pci driver
> and compare compare the dev->driver pointer of the PCI controller device.

The PCI core handles setting the maximum read request size already,
can you figure out why the core code isn't doing what you need and
correct the root problem?

I'm guessing the values in the root port bridge config space are not
correct or something like that??

Jason
--
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
Murali Karicheri May 15, 2014, 8:04 p.m. UTC | #6
On 5/15/2014 2:39 PM, Jason Gunthorpe wrote:
> On Thu, May 15, 2014 at 08:20:13PM +0200, Arnd Bergmann wrote:
>> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>>> +/*
>>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>>> + */
>>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>>> +{
>>>>> +    int readrq = pcie_get_readrq(dev);
>>>>> +
>>>>> +    if (readrq > 256)
>>>>> +            pcie_set_readrq(dev, 256);
>>>>> +}
>>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>>> This doesn't work: you can't just limit do this for all devices just based
>>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>>> this controller.
>>>>
>>>>        Arnd
>>>    I assume, I need to check if PCI controller's vendor ID/ device ID
>>> match with the keystone
>>>    PCI controller's ID and call pcie_set_readrq() for all of the slave
>>> PCI devices and do this fixup.
>>> Is this correct understanding?  If you can point me to an example code
>>> for this that will be
>>> really helpful so that I can avoid re-inventing the wheel.
>> I think it would be best to move the quirk into the keystone pci driver
>> and compare compare the dev->driver pointer of the PCI controller device.
> The PCI core handles setting the maximum read request size already,
> can you figure out why the core code isn't doing what you need and
> correct the root problem?
>
> I'm guessing the values in the root port bridge config space are not
> correct or something like that??
>
> Jason
What you mean by "The PCI core handles setting the maximum read request 
size already"
I see there is function pcie_write_mrrs() in the drivers/pci/probe.c 
that reads the mps
using pcie_get_mps() and then set mrrs to mps. But this function is 
called only from
pcie_bus_configure_set() that is called by pcie_bus_configure_settings()

pcie_bus_configure_settings() is called by

0 pci-common.c pcibios_scan_phb             1676 
pcie_bus_configure_settings(child);
1 pci_gx.c     fixup_read_and_payload_sizes  606 
pcie_bus_configure_settings(child);
2 acpi.c       pci_acpi_scan_root            556 
pcie_bus_configure_settings(child);
3 pcihp_slot.c pci_configure_slot            164 
pcie_bus_configure_settings(dev->bus);

None of them gets called on ARM platform.

What is needed for Keystone PCI is that we need to limit mrrs to 256 
bytes for all
of the downstream devices that talks to PCIe controller. This needs to 
be enforced
through a quirk. Or Is there something missing that Keystone or DW 
driver is not
making use of that reads the mrrs value of the RC and set the same on 
all of the
downstream devices connected to the bus that the controller is connected to?

Murali

--
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
Jason Gunthorpe May 15, 2014, 8:52 p.m. UTC | #7
On Thu, May 15, 2014 at 04:04:47PM -0400, Murali Karicheri wrote:

> Jason What you mean by "The PCI core handles setting the maximum
> read request size already" I see there is function pcie_write_mrrs()
> in the drivers/pci/probe.c that reads the mps using pcie_get_mps()
> and then set mrrs to mps. But this function is called only from
> pcie_bus_configure_set() that is called by
> pcie_bus_configure_settings()

Right, that is the common code that correctly sets the MRRS that you
should be using instead of quirks.

> None of them gets called on ARM platform.

Hmm, a cursory glance tells me the same as well.

That seems to be the root problem here, ARM needs to do the PCIE
setup just as much as any other arch.

So, I would prefer to see you fix ARM common code to call
pcie_bus_configure_settings() properly, that seems very simple and is
obviously needed for any PCI-E host driver on ARM.

Thoughts? Arnd? Bjorn?

Jason
--
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
Murali Karicheri May 16, 2014, 8:26 p.m. UTC | #8
On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>> +/*
>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>> + */
>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>> +{
>>>> +    int readrq = pcie_get_readrq(dev);
>>>> +
>>>> +    if (readrq > 256)
>>>> +            pcie_set_readrq(dev, 256);
>>>> +}
>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>> This doesn't work: you can't just limit do this for all devices just based
>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>> this controller.
>>>
>>>        Arnd
>>    I assume, I need to check if PCI controller's vendor ID/ device ID
>> match with the keystone
>>    PCI controller's ID and call pcie_set_readrq() for all of the slave
>> PCI devices and do this fixup.
>> Is this correct understanding?  If you can point me to an example code
>> for this that will be
>> really helpful so that I can avoid re-inventing the wheel.
> I think it would be best to move the quirk into the keystone pci driver
> and compare compare the dev->driver pointer of the PCI controller device.
>
> 	Arnd
Arnd,

I will move this quirk to keystone pci driver. So in that case, I guess 
your original comment
is not applicable as  this quirk gets enabled only with PCI keystone 
driver enabled. Right?

Murali
--
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
Murali Karicheri May 16, 2014, 8:29 p.m. UTC | #9
>-----Original Message-----
>From: Jason Gunthorpe [mailto:jgunthorpe@obsidianresearch.com]
>Sent: Thursday, May 15, 2014 4:52 PM
>To: Karicheri, Muralidharan
>Cc: Arnd Bergmann; linux-arm-kernel@lists.infradead.org; Strashko, Grygorii; linux-
>pci@vger.kernel.org; Jingoo Han; linux-kernel@vger.kernel.org; Shilimkar, Santosh; Mohit
>Kumar; Bjorn Helgaas
>Subject: Re: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core
>driver
>
>On Thu, May 15, 2014 at 04:04:47PM -0400, Murali Karicheri wrote:
>
>> Jason What you mean by "The PCI core handles setting the maximum read
>> request size already" I see there is function pcie_write_mrrs() in the
>> drivers/pci/probe.c that reads the mps using pcie_get_mps() and then
>> set mrrs to mps. But this function is called only from
>> pcie_bus_configure_set() that is called by
>> pcie_bus_configure_settings()
>
>Right, that is the common code that correctly sets the MRRS that you should be using
>instead of quirks.
>
>> None of them gets called on ARM platform.
>
>Hmm, a cursory glance tells me the same as well.
>
>That seems to be the root problem here, ARM needs to do the PCIE setup just as much as
>any other arch.
>
>So, I would prefer to see you fix ARM common code to call
>pcie_bus_configure_settings() properly, that seems very simple and is obviously needed for
>any PCI-E host driver on ARM.
>

But pcie_bus_configure_settings just make sure the mrrs for a device is not greater than
the max payload size. But the quirk that I need is to limit the size of mrr to 256 as required
by the keystone PCI controller. So I still need to implement a quirk to enforce this limit.

In my reply to Arnd, I have agreed to move the quirk to keystone driver.

Murali
>Thoughts? Arnd? Bjorn?
>
>Jason
--
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
Murali Karicheri May 16, 2014, 8:47 p.m. UTC | #10
Adding more people to the list for review.

>-----Original Message-----
>From: Karicheri, Muralidharan
>Sent: Thursday, May 15, 2014 12:02 PM
>To: linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org; linux-arm-
>kernel@lists.infradead.org
>Cc: Karicheri, Muralidharan; Shilimkar, Santosh; Mohit Kumar; Jingoo Han; Bjorn Helgaas;
>Strashko, Grygorii
>Subject: [PATCH v1 5/5] pci: keystone: add pcie driver based on designware core driver
>
>keystone pcie hardware is based on designware version 3.65.
>This driver make use of the functions from pci-dw-old.c and pci-dw-old-msi.c to implement
>the driver.
>
>Driver mainly handle the platform specific part of the PCI driver and depends on DW Old
>driver to configure application specific registers. Also routes the irq events and ack the
>interrupt after the same is acked by the end point device driver. This requires irqchip
>implementation for legacy and MSI irq handling. This patch adds a quirks to override the
>max read request size as PCI controller has a limit of 256 bytes.
>
>CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
>CC: Mohit Kumar <mohit.kumar@st.com>
>CC: Jingoo Han <jg1.han@samsung.com>
>CC: Bjorn Helgaas <bhelgaas@google.com>
>
>Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
>---
> .../devicetree/bindings/pci/pcie-keystone.txt      |   68 ++++
> drivers/pci/host/Kconfig                           |    8 +
> drivers/pci/host/Makefile                          |    1 +
> drivers/pci/host/pci-keystone.c                    |  400 ++++++++++++++++++++
> drivers/pci/quirks.c                               |   13 +
> 5 files changed, 490 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pci/pcie-keystone.txt
> create mode 100644 drivers/pci/host/pci-keystone.c
>
>diff --git a/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>new file mode 100644
>index 0000000..17cf261
>--- /dev/null
>+++ b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
>@@ -0,0 +1,68 @@
>+Keystone PCIE Root complex device tree bindings
>+-----------------------------------------------
>+
>+Sample bindings shown below:-
>+
>+ - Remove ti,enable-linktrain if boot loader already does Link training and do EP
>+   configuration.
>+ - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
>+   link
>+
>+		pcie0_phy: pciephy@2320000 {
>+			#address-cells = <1>;
>+			#size-cells = <1>;
>+			#phy-cells = <0>;
>+			compatible = "ti,keystone-phy";
>+			reg = <0x02320000 0x4000>;
>+			reg-names = "reg_serdes";
>+		};
>+
>+		pcie@21800000 {
>+			compatible = "ti,keystone-pcie";
>+			device_type = "pci";
>+			clocks = <&clkpcie>;
>+			clock-names = "pcie";
>+			#address-cells = <3>;
>+			#size-cells = <2>;
>+			reg =  <0x21800000 0x1000>, <0x0262014c 4>;
>+			reg-names = "reg_rc_app", "reg_devcfg";
>+			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
>+
>+			ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /*
>Configuration space */
>+				  0x81000000 0 0          0x24000000 0 0x4000       /* downstream
>I/O */
>+				  0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /*
>+non-prefetchable memory */
>+
>+			num-lanes = <2>;
>+			ti,enable-linktrain;
>+			ti,init-phy;
>+
>+			/* PCIE phy */
>+			phys = <&pcie0_phy>;
>+			phy-names = "pcie-phy";
>+
>+			#interrupt-cells = <1>;
>+			interrupt-map-mask = <0 0 0 0>;
>+			interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
>+					<0 0 0 2 &pcie_intc 2>, // INT B
>+					<0 0 0 3 &pcie_intc 3>, // INT C
>+					<0 0 0 4 &pcie_intc 4>; // INT D
>+
>+			pcie_intc: legacy-interrupt-controller {
>+				interrupt-controller;
>+				#interrupt-cells = <1>;
>+				interrupt-parent = <&gic>;
>+				interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
>+					<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
>+			};
>+		};
>+
>diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index c4f4732..066d611
>100644
>--- a/drivers/pci/host/Kconfig
>+++ b/drivers/pci/host/Kconfig
>@@ -37,4 +37,12 @@ config PCI_RCAR_GEN2
> 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
> 	  There are 3 internal PCI controllers available with a single
> 	  built-in EHCI/OHCI host controller present on each one.
>+
>+config PCI_KEYSTONE
>+	bool "TI Keystone PCIe controller"
>+	depends on ARCH_KEYSTONE
>+	select PCIE_DW
>+	select PCI_DW_OLD
>+	select PCIEPORTBUS
>+	select PHY_TI_KEYSTONE
> endmenu
>diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index be5d939..10e02f9
>100644
>--- a/drivers/pci/host/Makefile
>+++ b/drivers/pci/host/Makefile
>@@ -5,3 +5,4 @@ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
> obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
> obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
> obj-$(CONFIG_PCI_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
>+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
>diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c new file mode
>100644 index 0000000..2636717
>--- /dev/null
>+++ b/drivers/pci/host/pci-keystone.c
>@@ -0,0 +1,400 @@
>+/*
>+ * PCIe host controller driver for Texas Instruments Keystone SoCs
>+ *
>+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
>+ *		http://www.ti.com
>+ *
>+ * Author: Murali Karicheri <m-karicheri2@ti.com>
>+ * Implementation based on pci-exynos.c and pcie-designware.c
>+ *
>+ * 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/irqchip/chained_irq.h>
>+#include <linux/clk.h>
>+#include <linux/delay.h>
>+#include <linux/irqdomain.h>
>+#include <linux/module.h>
>+#include <linux/msi.h>
>+#include <linux/of_irq.h>
>+#include <linux/of.h>
>+#include <linux/of_pci.h>
>+#include <linux/platform_device.h>
>+#include <linux/phy/phy.h>
>+#include <linux/resource.h>
>+#include <linux/signal.h>
>+
>+#include "pcie-designware.h"
>+#include "pci-dw-old.h"
>+
>+#define DRIVER_NAME	"keystone-pcie"
>+
>+/* driver specific constants */
>+#define MAX_MSI_HOST_IRQS		8
>+#define MAX_LEGACY_HOST_IRQS		4
>+
>+/* RC mode settings */
>+#define PCIE_RC_MODE		(BIT(2))
>+#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
>+
>+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) {
>+	return sys->private_data;
>+}
>+
>+struct keystone_pcie {
>+	struct	clk		*clk;
>+	int			en_link_train;
>+	struct	pcie_port	pp;
>+
>+	int			num_legacy_host_irqs;
>+	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
>+	struct			device_node *np_intc;
>+
>+	int			num_msi_host_irqs;
>+	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
>+};
>+
>+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
>+
>+static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) {
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	int count = 200;
>+
>+	dw_pcie_setup_rc(pp);
>+
>+	/* check if the link is up or not */
>+	while (!dw_pcie_link_up(pp)) {
>+		usleep_range(100, 1000);
>+		if (--count)
>+			continue;
>+		dev_err(pp->dev, "phy link never came up\n");
>+		return -EINVAL;
>+	}
>+
>+	return 0;
>+}
>+
>+static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc
>+*desc) {
>+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
>+	u32 offset = irq - ks_pcie->msi_host_irqs[0];
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	struct irq_chip *chip = irq_desc_get_chip(desc);
>+
>+	dev_dbg(pp->dev, "ks_pcie_msi_irq_handler, irq %d\n", irq);
>+
>+	/*
>+	 * The chained irq handler installation would have replaced normal
>+	 * interrupt driver handler so we need to take care of mask/unmask and
>+	 * ack operation.
>+	 */
>+	chained_irq_enter(chip, desc);
>+	dw_old_handle_msi_irq(pp, offset);
>+	chained_irq_exit(chip, desc);
>+}
>+
>+/**
>+ * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
>+ * @irq: IRQ line for legacy interrupts
>+ * @desc: Pointer to irq descriptor
>+ *
>+ * Traverse through pending legacy interrupts and invoke handler for
>+each. Also
>+ * takes care of interrupt controller level mask/ack operation.
>+ */
>+static void ks_pcie_legacy_irq_handler(unsigned int irq, struct
>+irq_desc *desc) {
>+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
>+	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
>+	struct irq_chip *chip = irq_desc_get_chip(desc);
>+	struct pcie_port *pp = &ks_pcie->pp;
>+
>+	dev_dbg(ks_pcie->pp.dev, ": Handling legacy irq %d\n", irq);
>+
>+	/*
>+	 * The chained irq handler installation would have replaced normal
>+	 * interrupt driver handler so we need to take care of mask/unmask and
>+	 * ack operation.
>+	 */
>+	chained_irq_enter(chip, desc);
>+	dw_old_handle_legacy_irq(pp, irq_offset);
>+	chained_irq_exit(chip, desc);
>+}
>+
>+static int ks_pcie_init_legacy_irqs(struct keystone_pcie *ks_pcie) {
>+	struct device *dev = ks_pcie->pp.dev;
>+	struct device_node *np_pcie = dev->of_node;
>+	int num_legacy_irqs;
>+	int ret = 0;
>+	int i;
>+
>+	/* get node */
>+	ks_pcie->np_intc = of_find_node_by_name(np_pcie,
>+						"legacy-interrupt-controller");
>+	if (!ks_pcie->np_intc) {
>+		dev_err(dev,
>+			"Node for legacy-interrupt-controller is absent\n");
>+		goto out;
>+	}
>+
>+	/* get number of IRQs */
>+	num_legacy_irqs = of_irq_count(ks_pcie->np_intc);
>+	if (!num_legacy_irqs)
>+		goto out;
>+
>+	if (num_legacy_irqs > MAX_LEGACY_HOST_IRQS) {
>+		dev_err(dev, "Too many legacy interrupts defined %u\n",
>+			num_legacy_irqs);
>+		num_legacy_irqs = MAX_LEGACY_HOST_IRQS;
>+	}
>+	/*
>+	 * support upto MAX_LEGACY_HOST_IRQS host and legacy IRQs.
>+	 * In dt from index 0 to 3
>+	 */
>+	for (i = 0; i < num_legacy_irqs; i++) {
>+		ks_pcie->legacy_host_irqs[i] =
>+			irq_of_parse_and_map(ks_pcie->np_intc, i);
>+		if (ks_pcie->legacy_host_irqs[i] < 0)
>+			break;
>+		ks_pcie->num_legacy_host_irqs++;
>+	}
>+
>+	if (!ks_pcie->num_legacy_host_irqs) {
>+		dev_err(dev, "Failed to get legacy interrupts\n");
>+		goto out;
>+	}
>+
>+out:
>+	return ret;
>+}
>+
>+static void ks_pcie_enable_interrupts(struct keystone_pcie *ks_pcie) {
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	int i;
>+
>+	/* Legacy IRQ */
>+	for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
>+		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
>+		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
>+					ks_pcie_legacy_irq_handler);
>+	}
>+	dw_old_enable_legacy_irqs(pp);
>+
>+	/* MSI IRQ */
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
>+			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
>+				ks_pcie_msi_irq_handler);
>+			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
>+						ks_pcie);
>+
>+		}
>+	}
>+
>+	return;
>+}
>+
>+static int
>+keystone_pcie_fault(unsigned long addr, unsigned int fsr,
>+		struct pt_regs *regs)
>+{
>+	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
>+
>+	if ((instr & 0x0e100090) == 0x00100090) {
>+		int reg = (instr >> 12) & 15;
>+
>+		regs->uregs[reg] = -1;
>+		regs->ARM_pc += 4;
>+	}
>+
>+	return 0;
>+}
>+
>+static void __init ks_pcie_host_init(struct pcie_port *pp) {
>+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
>+
>+	ks_pcie_establish_link(ks_pcie);
>+	dw_old_disable_bars(pp);
>+	dw_old_setup_ob_regs(pp);
>+	ks_pcie_enable_interrupts(ks_pcie);
>+	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
>+			pp->dbi_base + PCI_IO_BASE);
>+	/*
>+	 * PCIe access errors that result into OCP errors are caught by ARM as
>+	 * "External aborts" (Precise).
>+	 */
>+	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
>+			"external abort on linefetch");
>+}
>+
>+int ks_pcie_link_up(struct pcie_port *pp) {
>+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
>+
>+	return dw_old_pcie_link_up(pp, ks_pcie->en_link_train); }
>+
>+static struct pcie_host_ops keystone_pcie_host_ops = {
>+	.rd_other_conf = dw_old_rd_other_conf,
>+	.wr_other_conf = dw_old_wr_other_conf,
>+	.link_up = ks_pcie_link_up,
>+	.host_init = ks_pcie_host_init,
>+	.get_msi_data = dw_old_get_msi_data,
>+};
>+
>+static int add_pcie_port(struct keystone_pcie *ks_pcie,
>+			 struct platform_device *pdev)
>+{
>+	struct device_node *np = pdev->dev.of_node;
>+	struct pcie_port *pp = &ks_pcie->pp;
>+	struct resource *res;
>+	int ret, i;
>+
>+	ret = ks_pcie_init_legacy_irqs(ks_pcie);
>+	if (ret)
>+		return ret;
>+
>+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>+		/*
>+		 * support upto 32 MSI irqs mapped to 8 host IRQs.
>+		 * In dt from index 4 to 11
>+		 */
>+		for (i = 0; i < MAX_MSI_HOST_IRQS; i++) {
>+			ks_pcie->msi_host_irqs[i] = irq_of_parse_and_map(np, i);
>+			if (ks_pcie->msi_host_irqs[i] < 0)
>+				break;
>+			ks_pcie->num_msi_host_irqs++;
>+		}
>+	}
>+
>+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_rc_app");
>+	pp->va_app_base = devm_ioremap_resource(&pdev->dev, res);
>+	if (IS_ERR(pp->va_app_base))
>+		return PTR_ERR(pp->va_app_base);
>+	pp->app_base = res->start;
>+
>+	pp->root_bus_nr = -1;
>+	pp->version = DW_VERSION_OLD;
>+	pp->ops = &keystone_pcie_host_ops;
>+	spin_lock_init(&pp->conf_lock);
>+	ret = dw_old_pcie_host_init(pp, ks_pcie->np_intc);
>+	if (ret) {
>+		dev_err(&pdev->dev, "failed to initialize host\n");
>+		return ret;
>+	}
>+
>+	return ret;
>+}
>+
>+static const struct of_device_id ks_pcie_of_match[] = {
>+	{
>+		.type = "pci",
>+		.compatible = "ti,keystone-pcie",
>+	},
>+	{ },
>+};
>+MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
>+
>+static int __exit ks_pcie_remove(struct platform_device *pdev) {
>+	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
>+
>+	clk_disable_unprepare(ks_pcie->clk);
>+
>+	return 0;
>+}
>+
>+static int __init ks_pcie_probe(struct platform_device *pdev) {
>+	struct device_node *np = pdev->dev.of_node;
>+	struct device *dev = &pdev->dev;
>+	struct keystone_pcie *ks_pcie;
>+	void __iomem *devstat;
>+	struct pcie_port *pp;
>+	struct resource *res;
>+	struct phy *phy;
>+	int ret = 0;
>+	u32 val;
>+
>+	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
>+				GFP_KERNEL);
>+	if (!ks_pcie) {
>+		dev_err(dev, "no memory for keystone pcie\n");
>+		return -ENOMEM;
>+	}
>+
>+	/* check if serdes phy needs to be enabled */
>+	if (of_get_property(np, "ti,init-phy", NULL) != NULL) {
>+		phy = devm_phy_get(dev, "pcie-phy");
>+			if (IS_ERR(phy))
>+				return PTR_ERR(phy);
>+
>+		ret = phy_init(phy);
>+		if (ret < 0)
>+			return ret;
>+	}
>+
>+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
>+					   "reg_devcfg");
>+	devstat = devm_ioremap_resource(dev, res);
>+	if (IS_ERR(devstat))
>+		return PTR_ERR(devstat);
>+
>+	/* enable RC mode in devcfg */
>+	val = readl(devstat);
>+	val &= ~PCIE_MODE_MASK;
>+	val |= PCIE_RC_MODE;
>+	writel(val, devstat);
>+
>+	/* check if we need to enable link training */
>+	ks_pcie->en_link_train =
>+		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
>+
>+	pp = &ks_pcie->pp;
>+	pp->dev = dev;
>+
>+	ks_pcie->clk = devm_clk_get(dev, "pcie");
>+	if (IS_ERR(ks_pcie->clk)) {
>+		dev_err(dev, "Failed to get pcie rc clock\n");
>+		return PTR_ERR(ks_pcie->clk);
>+	}
>+	ret = clk_prepare_enable(ks_pcie->clk);
>+	if (ret)
>+		return ret;
>+
>+	ret = add_pcie_port(ks_pcie, pdev);
>+	if (ret < 0)
>+		goto fail_clk;
>+
>+	platform_set_drvdata(pdev, ks_pcie);
>+	dev_info(dev, "pcie rc probe success\n");
>+
>+	return 0;
>+
>+fail_clk:
>+	clk_disable_unprepare(ks_pcie->clk);
>+
>+	return ret;
>+}
>+
>+static struct platform_driver ks_pcie_driver __refdata = {
>+	.probe  = ks_pcie_probe,
>+	.remove = __exit_p(ks_pcie_remove),
>+	.driver = {
>+		.name	= "keystone-pcie",
>+		.owner	= THIS_MODULE,
>+		.of_match_table = of_match_ptr(ks_pcie_of_match),
>+	},
>+};
>+
>+module_platform_driver(ks_pcie_driver);
>+
>+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
>+MODULE_DESCRIPTION("Keystone PCIe host controller driver");
>+MODULE_LICENSE("GPL v2");
>diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e729206..b3e12c2 100644
>--- a/drivers/pci/quirks.c
>+++ b/drivers/pci/quirks.c
>@@ -3651,3 +3651,16 @@ void pci_dev_specific_enable_acs(struct pci_dev *dev)
> 		}
> 	}
> }
>+#ifdef CONFIG_PCI_KEYSTONE
>+/*
>+ * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>+ */
>+static void quirk_limit_readrequest(struct pci_dev *dev) {
>+	int readrq = pcie_get_readrq(dev);
>+
>+	if (readrq > 256)
>+		pcie_set_readrq(dev, 256);
>+}
>+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID,
>+quirk_limit_readrequest); #endif /* CONFIG_PCI_KEYSTONE */
>--
>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
Murali Karicheri May 16, 2014, 10:44 p.m. UTC | #11
On 5/15/2014 12:28 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
>> +Sample bindings shown below:-
>> +
>> + - Remove ti,enable-linktrain if boot loader already does Link training and do EP
>> +   configuration.
>> + - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
>> +   link
> You actually have to document all the properties. Have a look at the
> other bindings for what this means.

Actually this is dw pcie variant. So I will document if there are any 
deviations from the dw-designware
bindings. Based on comments from Jingo, I think I need to add a new DT 
property for old hw that we
use in keystone. May be a compatibility string for older dw h/w like 
"snps ,dw-pcie-v3.65" is that we
could use and do things differently in the common code.

So I will update the Documentation of dw bindings  once we agree on this.
>> +
>> +               pcie@21800000 {
>> +                       compatible = "ti,keystone-pcie";
>> +                       device_type = "pci";
>> +                       clocks = <&clkpcie>;
>> +                       clock-names = "pcie";
> The dw-pcie binding lists two clocks.
Ok. As per dw documentation, pcie and pcie_bus are the clocks. But 
pci-imx6 is currently not using pcie_bus. So the pcie_bus
clock is actually optional. In the case of keystone pcie, bus clock is 
provided by the phy hardware and if I need to provide
a clock for bus, it has to be a dummy or change documentation to make 
pcie_bus an optional clock. I prefer later, but want
to know if this is true for pci-imx6. There is also a plan to move the 
pcie clock API call to designware core. So making pcie_bus
clock optional looks correct to me.

Seen/Jingoo,  any comments?

>> +                       #address-cells = >;
>> +                       #size-cells = <2>;
>> +                       reg =  <0x21800000 0x1000>, <0x0262014c 4>;
>> +                       reg-names = "reg_rc_app", "reg_devcfg";
> There should be standard names that are documented in the binding.

Currently  Documentation says

- reg: base addresses and lengths of the pcie controller,
     the phy controller, additional register for the phy controller.

And following dw drivers defines as

samsung,exynos5440-pcie

         reg = <0x290000 0x1000
             0x270000 0x1000
             0x271000 0x40>;

fsl,imx6q-pcie"
         reg = <0x01ffc000 0x4000>; /* DBI */

There are no names used for registers. So this needs to be documented in 
the dw-designware
bindings. reg_dbi is what is common to pci controller assuming at index 
0 of the both above drivers use
reg_dbi address for config space. Shall I modify the documentation to 
include optional reg name
reg_dbi  for config space base address registers? Additional registers 
are optional and varies from
platform to platform. Phy registers are actually part of Phy driver and 
should be removed from
the dw-documentation bindings. Agree?

>
>> +                       interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
>> +                                       <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
> What are all these interrupts?
These are MSI interrupts tied to the GIC over which MSI interrupts are 
multiplexed.  I will document
it in the keystone PCI DT bindings.
>> +                       ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
>> +                                 0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
>> +                                 0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */
> Please move the config space into 'reg' now instead of 'ranges'.
> This was a mistake earlier, and there are already other front-ends
> doing the same thing.
  This has to be coordinated with other drivers when DW core makes the 
change.

Jingoo, Sean,

What is the plan for this change? I  have to defer this currently.

>
>> +                       num-lanes = <2>;
>> +                       ti,enable-linktrain;
>> +                       ti,init-phy;
>> +
>> +                       /* PCIE phy */
>> +                       phys = <&pcie0_phy>;
>> +                       phy-names = "pcie-phy";
>> +
>> +                       #interrupt-cells = <1>;
>> +                       interrupt-map-mask = <0 0 0 0>;
>> +                       interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
>> +                                       <0 0 0 2 &pcie_intc 2>, // INT B
>> +                                       <0 0 0 3 &pcie_intc 3>, // INT C
>> +                                       <0 0 0 4 &pcie_intc 4>; // INT D
> I think this is the wrong map-mask.
I think this should be changed to

interrupt-map-mask = <0 0 0 0x7> ?

>
> 	Arnd

--
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
Arnd Bergmann May 19, 2014, 12:06 p.m. UTC | #12
On Friday 16 May 2014 16:26:51 Murali Karicheri wrote:
> On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
> > On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> >>>> +#ifdef CONFIG_PCI_KEYSTONE
> >>>> +/*
> >>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> >>>> + */
> >>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
> >>>> +{
> >>>> +    int readrq = pcie_get_readrq(dev);
> >>>> +
> >>>> +    if (readrq > 256)
> >>>> +            pcie_set_readrq(dev, 256);
> >>>> +}
> >>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> >>>> +#endif /* CONFIG_PCI_KEYSTONE */
> >>> This doesn't work: you can't just limit do this for all devices just based
> >>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
> >>> this controller.
> >>>
> >>>        Arnd
> >>    I assume, I need to check if PCI controller's vendor ID/ device ID
> >> match with the keystone
> >>    PCI controller's ID and call pcie_set_readrq() for all of the slave
> >> PCI devices and do this fixup.
> >> Is this correct understanding?  If you can point me to an example code
> >> for this that will be
> >> really helpful so that I can avoid re-inventing the wheel.
> > I think it would be best to move the quirk into the keystone pci driver
> > and compare compare the dev->driver pointer of the PCI controller device.
> >
> >       Arnd
> Arnd,
> 
> I will move this quirk to keystone pci driver. So in that case, I guess 
> your original comment
> is not applicable as  this quirk gets enabled only with PCI keystone 
> driver enabled. Right?

Of course you still have to fix the bug, not just move the code into
the driver. Otherwise it's still broken for every machine after the keystone
driver is enabled.

I also agree with Jason that changing the PCI core to call
pcie_bus_configure_settings() would be a better way of dealing with this
if it solves the problem.

	Arnd
--
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
Arnd Bergmann May 19, 2014, 12:12 p.m. UTC | #13
On Friday 16 May 2014 18:44:44 Murali Karicheri wrote:
> On 5/15/2014 12:28 PM, Arnd Bergmann wrote:
> > On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
> >> +Sample bindings shown below:-
> >> +
> >> + - Remove ti,enable-linktrain if boot loader already does Link training and do EP
> >> +   configuration.
> >> + - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
> >> +   link
> > You actually have to document all the properties. Have a look at the
> > other bindings for what this means.
> 
> Actually this is dw pcie variant. So I will document if there are any 
> deviations from the dw-designware
> bindings. Based on comments from Jingo, I think I need to add a new DT 
> property for old hw that we
> use in keystone. May be a compatibility string for older dw h/w like 
> "snps ,dw-pcie-v3.65" is that we
> could use and do things differently in the common code.

A compatible string with the exact version sounds like a good idea, yes.

> So I will update the Documentation of dw bindings  once we agree on this.
> >> +
> >> +               pcie@21800000 {
> >> +                       compatible = "ti,keystone-pcie";
> >> +                       device_type = "pci";
> >> +                       clocks = <&clkpcie>;
> >> +                       clock-names = "pcie";
> > The dw-pcie binding lists two clocks.
>
> Ok. As per dw documentation, pcie and pcie_bus are the clocks. But 
> pci-imx6 is currently not using pcie_bus. So the pcie_bus
> clock is actually optional. In the case of keystone pcie, bus clock is 
> provided by the phy hardware and if I need to provide
> a clock for bus, it has to be a dummy or change documentation to make 
> pcie_bus an optional clock. I prefer later, but want
> to know if this is true for pci-imx6. There is also a plan to move the 
> pcie clock API call to designware core. So making pcie_bus
> clock optional looks correct to me.

A documentation change sounds fine to me. How about documenting that
there should be either a "pcie_bus" clock or a phy reference?

> >> +                       #address-cells = >;
> >> +                       #size-cells = <2>;
> >> +                       reg =  <0x21800000 0x1000>, <0x0262014c 4>;
> >> +                       reg-names = "reg_rc_app", "reg_devcfg";
> > There should be standard names that are documented in the binding.
> 
> Currently  Documentation says
> 
> - reg: base addresses and lengths of the pcie controller,
>      the phy controller, additional register for the phy controller.
> 
> And following dw drivers defines as
> 
> samsung,exynos5440-pcie
> 
>          reg = <0x290000 0x1000
>              0x270000 0x1000
>              0x271000 0x40>;
> 
> fsl,imx6q-pcie"
>          reg = <0x01ffc000 0x4000>; /* DBI */
> 
> There are no names used for registers. So this needs to be documented in 
> the dw-designware
> bindings. reg_dbi is what is common to pci controller assuming at index 
> 0 of the both above drivers use
> reg_dbi address for config space. Shall I modify the documentation to 
> include optional reg name
> reg_dbi  for config space base address registers? Additional registers 
> are optional and varies from
> platform to platform. Phy registers are actually part of Phy driver and 
> should be removed from
> the dw-documentation bindings. Agree?

It makes sense to remove the phy registers if there is always a separate
phy driver. Regarding the names, it's probably easier to remove them
completely than to document them.

If the register names are optional, you can't rely on them anyway
and have to uses the indexes/

> >
> >> +                       interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
> >> +                                       <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
> > What are all these interrupts?
> These are MSI interrupts tied to the GIC over which MSI interrupts are 
> multiplexed.  I will document
> it in the keystone PCI DT bindings.

Maybe they should be moved into the subnode that has the LSI interrupts,
or perhaps a separate node? I don't know how the other dw-pcie variants
do it, but it always seems like a good idea to keep MSI separate because
you might not want to use it if there is also an MSI capable GIC in the
system.

> >> +                       ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
> >> +                                 0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
> >> +                                 0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */
> > Please move the config space into 'reg' now instead of 'ranges'.
> > This was a mistake earlier, and there are already other front-ends
> > doing the same thing.
>   This has to be coordinated with other drivers when DW core makes the 
> change.
> 
> Jingoo, Sean,
> 
> What is the plan for this change? I  have to defer this currently.

> >> +                       #interrupt-cells = <1>;
> >> +                       interrupt-map-mask = <0 0 0 0>;
> >> +                       interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
> >> +                                       <0 0 0 2 &pcie_intc 2>, // INT B
> >> +                                       <0 0 0 3 &pcie_intc 3>, // INT C
> >> +                                       <0 0 0 4 &pcie_intc 4>; // INT D
> > I think this is the wrong map-mask.
> I think this should be changed to
> 
> interrupt-map-mask = <0 0 0 0x7> ?

That sounds reasonable. Is that what your hardware implements?

	Arnd
--
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
Murali Karicheri May 19, 2014, 9:10 p.m. UTC | #14
On 5/19/2014 8:06 AM, Arnd Bergmann wrote:
> On Friday 16 May 2014 16:26:51 Murali Karicheri wrote:
>> On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
>>> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
>>>>>> +#ifdef CONFIG_PCI_KEYSTONE
>>>>>> +/*
>>>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>>>>>> + */
>>>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
>>>>>> +{
>>>>>> +    int readrq = pcie_get_readrq(dev);
>>>>>> +
>>>>>> +    if (readrq > 256)
>>>>>> +            pcie_set_readrq(dev, 256);
>>>>>> +}
>>>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
>>>>>> +#endif /* CONFIG_PCI_KEYSTONE */
>>>>> This doesn't work: you can't just limit do this for all devices just based
>>>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
>>>>> this controller.
>>>>>
>>>>>         Arnd
>>>>     I assume, I need to check if PCI controller's vendor ID/ device ID
>>>> match with the keystone
>>>>     PCI controller's ID and call pcie_set_readrq() for all of the slave
>>>> PCI devices and do this fixup.
>>>> Is this correct understanding?  If you can point me to an example code
>>>> for this that will be
>>>> really helpful so that I can avoid re-inventing the wheel.
>>> I think it would be best to move the quirk into the keystone pci driver
>>> and compare compare the dev->driver pointer of the PCI controller device.
>>>
>>>        Arnd
>> Arnd,
>>
>> I will move this quirk to keystone pci driver. So in that case, I guess
>> your original comment
>> is not applicable as  this quirk gets enabled only with PCI keystone
>> driver enabled. Right?
> Of course you still have to fix the bug, not just move the code into
> the driver. Otherwise it's still broken for every machine after the keystone
> driver is enabled.

Agree. I have tried following to get this work so that the quirk gets 
applied only for
keystone pci controller.

#define KS_K2HK_PCI_DEVICE_ID    0xb008
#define KS_K2E_PCI_DEVICE_ID    0xb009
#define KS_K2L_PCI_DEVICE_ID    0xb00a

static u16 root_pci_ids[] =
     {KS_K2HK_PCI_DEVICE_ID, KS_K2E_PCI_DEVICE_ID, KS_K2L_PCI_DEVICE_ID, 
0 };
/*
  * The KeyStone PCIe controller has maximum read request size of 256 bytes.
  */
static void quirk_limit_readrequest(struct pci_dev *dev)
{
     struct pci_dev *root_dev;
     int i = 0;

     /* Apply quirk only if this bridge device is keystone */
     while (root_pci_ids[i]) {
         root_dev = pci_get_device(PCI_VENDOR_ID_TI, root_pci_ids[i], NULL);
         if ((root_dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
             int readrq;

             readrq = pcie_get_readrq(dev);
             if (pcie_get_readrq(dev) > 256) {
                 pcie_set_readrq(dev, 256);
                 printk("Applied quirk\n");
             }
             break;
         };
     }
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);

>
> I also agree with Jason that changing the PCI core to call
> pcie_bus_configure_settings() would be a better way of dealing with this
> if it solves the problem.

I tried following piece of code added to bios32.c

void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
{
         struct pci_sys_data *sys;
         LIST_HEAD(head);

         pci_add_flags(PCI_REASSIGN_ALL_RSRC);
         if (hw->preinit)
                 hw->preinit();

          ........
          ....

          list_for_each_entry(sys, &head, node) {
                 struct pci_bus *bus = sys->bus;

                 if (!pci_has_flag(PCI_PROBE_ONLY)) {
                         /*
                          * Size the bridge windows.
                          */
                         pci_bus_size_bridges(bus);

                         /*
                          * Assign resources.
                          */
                         pci_bus_assign_resources(bus);
                 }
                 /*
                  * Tell drivers about devices found.
                  */
                 pci_bus_add_devices(bus);
         }

// New code starts here
         list_for_each_entry(sys, &head, node) {
                 struct pci_bus *bus = sys->bus;

                 /* Configure PCI Express settings */
                 if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
                         struct pci_bus *child;

                         list_for_each_entry(child, &bus->children, node)
                         pcie_bus_configure_settings(child);
                 }
         }
// New code ends.

This seems to do different things based on the pci bootargs. The key 
requirement for Keystone PCI controller
is that the MRRS can't be more than 256 bytes.  The only option that 
works for keystone PCI controller
is with pci=pcie_bus_perf.   I see following logs:-

[    3.382747] pcie_bus_configure_settings, config 2
[    3.382753] pcie_bus_configure_set
[    3.382781] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  256
[    3.382788] pcie_bus_configure_set
[    3.382846] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256
[    3.382852] pcie_bus_configure_set
[    3.382909] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256

On ARM, by default pci_bus_config seems to be set to 0 
(PCIE_BUS_TUNE_OFF). So the code doesn't get
executed for this default. But for PCIE_BUS_SAFE, it doesn't change the 
mrrs at the EP and is not
good for our platform w.r.t mrrs settings. For PCIE_BUS_PERFORMANCE, it 
seems to increase the payload
size as well and Keystone Payload size is limited to 128 bytes. So it is 
not safe to increase the payload
size to 256 based on the log.

On other platforms, Why the PCI core try to set the payload size equal 
to mrrs? Is this explained in any
PCI spec?  Looks like this is done for performance? Let me know if you 
want me to send a patch for
review to add the pcie_bus_configure_settings() code to 
arch/arm/kernel/bios32.c

For the Keystone PCI driver, I believe. it is safe to have the quirk so 
that controller can handle the
read requests properly. Let me know if the quirk code above looks good 
to go.

Murali

> 	Arnd

--
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
Arnd Bergmann May 20, 2014, 7:55 a.m. UTC | #15
On Monday 19 May 2014 17:10:50 Murali Karicheri wrote:
> On 5/19/2014 8:06 AM, Arnd Bergmann wrote:
> > On Friday 16 May 2014 16:26:51 Murali Karicheri wrote:
> >> On 5/15/2014 2:20 PM, Arnd Bergmann wrote:
> >>> On Thursday 15 May 2014 13:45:08 Murali Karicheri wrote:
> >>>>>> +#ifdef CONFIG_PCI_KEYSTONE
> >>>>>> +/*
> >>>>>> + * The KeyStone PCIe controller has maximum read request size of 256 bytes.
> >>>>>> + */
> >>>>>> +static void quirk_limit_readrequest(struct pci_dev *dev)
> >>>>>> +{
> >>>>>> +    int readrq = pcie_get_readrq(dev);
> >>>>>> +
> >>>>>> +    if (readrq > 256)
> >>>>>> +            pcie_set_readrq(dev, 256);
> >>>>>> +}
> >>>>>> +DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
> >>>>>> +#endif /* CONFIG_PCI_KEYSTONE */
> >>>>> This doesn't work: you can't just limit do this for all devices just based
> >>>>> on PCI_KEYSTONE being enabled, you have to check if you are actually using
> >>>>> this controller.
> >>>>>
> >>>>>         Arnd
> >>>>     I assume, I need to check if PCI controller's vendor ID/ device ID
> >>>> match with the keystone
> >>>>     PCI controller's ID and call pcie_set_readrq() for all of the slave
> >>>> PCI devices and do this fixup.
> >>>> Is this correct understanding?  If you can point me to an example code
> >>>> for this that will be
> >>>> really helpful so that I can avoid re-inventing the wheel.
> >>> I think it would be best to move the quirk into the keystone pci driver
> >>> and compare compare the dev->driver pointer of the PCI controller device.
> >>>
> >>>        Arnd
> >> Arnd,
> >>
> >> I will move this quirk to keystone pci driver. So in that case, I guess
> >> your original comment
> >> is not applicable as  this quirk gets enabled only with PCI keystone
> >> driver enabled. Right?
> > Of course you still have to fix the bug, not just move the code into
> > the driver. Otherwise it's still broken for every machine after the keystone
> > driver is enabled.
> 
> Agree. I have tried following to get this work so that the quirk gets 
> applied only for
> keystone pci controller.
> 
> #define KS_K2HK_PCI_DEVICE_ID    0xb008
> #define KS_K2E_PCI_DEVICE_ID    0xb009
> #define KS_K2L_PCI_DEVICE_ID    0xb00a
> 
> static u16 root_pci_ids[] =
>      {KS_K2HK_PCI_DEVICE_ID, KS_K2E_PCI_DEVICE_ID, KS_K2L_PCI_DEVICE_ID, 
> 0 };
> /*
>   * The KeyStone PCIe controller has maximum read request size of 256 bytes.
>   */
> static void quirk_limit_readrequest(struct pci_dev *dev)
> {
>      struct pci_dev *root_dev;
>      int i = 0;
> 
>      /* Apply quirk only if this bridge device is keystone */
>      while (root_pci_ids[i]) {
>          root_dev = pci_get_device(PCI_VENDOR_ID_TI, root_pci_ids[i], NULL);
>          if ((root_dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
>              int readrq;
> 
>              readrq = pcie_get_readrq(dev);
>              if (pcie_get_readrq(dev) > 256) {
>                  pcie_set_readrq(dev, 256);
>                  printk("Applied quirk\n");
>              }
>              break;
>          };
>      }
> }
> DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);

Why not compare the driver pointer as I suggested?

> > I also agree with Jason that changing the PCI core to call
> > pcie_bus_configure_settings() would be a better way of dealing with this
> > if it solves the problem.
> 
> I tried following piece of code added to bios32.c
> 
> void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
> {
>          struct pci_sys_data *sys;
>          LIST_HEAD(head);
> 
>          pci_add_flags(PCI_REASSIGN_ALL_RSRC);
>          if (hw->preinit)
>                  hw->preinit();
> 
>           ........
>           ....
> 
>           list_for_each_entry(sys, &head, node) {
>                  struct pci_bus *bus = sys->bus;
> 
>                  if (!pci_has_flag(PCI_PROBE_ONLY)) {
>                          /*
>                           * Size the bridge windows.
>                           */
>                          pci_bus_size_bridges(bus);
> 
>                          /*
>                           * Assign resources.
>                           */
>                          pci_bus_assign_resources(bus);
>                  }
>                  /*
>                   * Tell drivers about devices found.
>                   */
>                  pci_bus_add_devices(bus);
>          }
> 
> // New code starts here
>          list_for_each_entry(sys, &head, node) {
>                  struct pci_bus *bus = sys->bus;
> 
>                  /* Configure PCI Express settings */
>                  if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
>                          struct pci_bus *child;
> 
>                          list_for_each_entry(child, &bus->children, node)
>                          pcie_bus_configure_settings(child);
>                  }
>          }
> // New code ends.

This is the ARM specific part of the PCI code. I think it would be
better to do this independent of the architecture.

> This seems to do different things based on the pci bootargs. The key 
> requirement for Keystone PCI controller
> is that the MRRS can't be more than 256 bytes.  The only option that 
> works for keystone PCI controller
> is with pci=pcie_bus_perf.   I see following logs:-
> 
> [    3.382747] pcie_bus_configure_settings, config 2
> [    3.382753] pcie_bus_configure_set
> [    3.382781] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
> (was  128), Max Read Rq  256
> [    3.382788] pcie_bus_configure_set
> [    3.382846] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
> 128), Max Read Rq  256
> [    3.382852] pcie_bus_configure_set
> [    3.382909] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
> 128), Max Read Rq  256
> 
> On ARM, by default pci_bus_config seems to be set to 0 
> (PCIE_BUS_TUNE_OFF). So the code doesn't get
> executed for this default. But for PCIE_BUS_SAFE, it doesn't change the 
> mrrs at the EP and is not
> good for our platform w.r.t mrrs settings. For PCIE_BUS_PERFORMANCE, it 
> seems to increase the payload
> size as well and Keystone Payload size is limited to 128 bytes. So it is 
> not safe to increase the payload
> size to 256 based on the log.
> 
> On other platforms, Why the PCI core try to set the payload size equal 
> to mrrs? Is this explained in any
> PCI spec?  Looks like this is done for performance? Let me know if you 
> want me to send a patch for
> review to add the pcie_bus_configure_settings() code to 
> arch/arm/kernel/bios32.c
> 
> For the Keystone PCI driver, I believe. it is safe to have the quirk so 
> that controller can handle the
> read requests properly. Let me know if the quirk code above looks good 
> to go.

I don't know enough about these to give you a definite answer, but
I'd still prefer to handle this in generic code. A quirk seems to
be the wrong answer here. If this isn't something we can do in generic
fashion, can you do it in the add_bus() callback perhaps?

Maybe Jason or Bjorn have a better idea.

	Arnd
--
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
Jason Gunthorpe May 20, 2014, 5:02 p.m. UTC | #16
On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:

> But pcie_bus_configure_settings just make sure the mrrs for a device
> is not greater than the max payload size. 

Not quite, it first scans the network checking the Maximum Payload Size
Supported (MPSS) for each device, and chooses the highest supported by
all as the MPS for all.

PCI-E requires that an end point support all packets up to the MPS, so
if your bridge can't generate a 512 byte read response packet, then it
must not advertise a MPSS greater than 256 bytes.

Setting your MPSS to 128, 256, then using the
pcie_bus_configure_settings to run the standard algorithm should
properly limit the readrq to 256 and be able to properly support all
the fun edge cases like hot plug.

If the config space in your root port bridge is correct and already
declares a MPSS of 256 then you have nothing else to do but make sure
pcie_bus_configure_settings gets calls.

If it is broken and claims a higher MPSS than it can support then you
need to use a quirk only for the root port bridge or edit the config
reply in the driver only to fix the MPSS.

Jason
--
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 May 20, 2014, 5:17 p.m. UTC | #17
On Tue, May 20, 2014 at 1:55 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Monday 19 May 2014 17:10:50 Murali Karicheri wrote:

>> On ARM, by default pci_bus_config seems to be set to 0
>> (PCIE_BUS_TUNE_OFF). So the code doesn't get
>> executed for this default. But for PCIE_BUS_SAFE, it doesn't change the
>> mrrs at the EP and is not
>> good for our platform w.r.t mrrs settings. For PCIE_BUS_PERFORMANCE, it
>> seems to increase the payload
>> size as well and Keystone Payload size is limited to 128 bytes. So it is
>> not safe to increase the payload
>> size to 256 based on the log.
>>
>> On other platforms, Why the PCI core try to set the payload size equal
>> to mrrs? Is this explained in any
>> PCI spec?  Looks like this is done for performance? Let me know if you
>> want me to send a patch for
>> review to add the pcie_bus_configure_settings() code to
>> arch/arm/kernel/bios32.c
>>
>> For the Keystone PCI driver, I believe. it is safe to have the quirk so
>> that controller can handle the
>> read requests properly. Let me know if the quirk code above looks good
>> to go.
>
> I don't know enough about these to give you a definite answer, but
> I'd still prefer to handle this in generic code. A quirk seems to
> be the wrong answer here. If this isn't something we can do in generic
> fashion, can you do it in the add_bus() callback perhaps?

I definitely prefer a more generic approach than a quirk.
Unfortunately the MPS management was implemented originally just for
x86, not because there's anything arch-specific about it, but because
the author was only concerned about x86.  Making that more generic has
been an open issue all along.

Bjorn
--
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 May 20, 2014, 5:22 p.m. UTC | #18
On Tue, May 20, 2014 at 11:02 AM, Jason Gunthorpe
<jgunthorpe@obsidianresearch.com> wrote:
> On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
>
>> But pcie_bus_configure_settings just make sure the mrrs for a device
>> is not greater than the max payload size.
>
> Not quite, it first scans the network checking the Maximum Payload Size
> Supported (MPSS) for each device, and chooses the highest supported by
> all as the MPS for all.

The "performance" setting, e.g., "pci=pcie_bus_perf", adds a few
wrinkles by setting MRRS in ways that allow some devices to have
larger MPS than others.  I don't think this is exactly what was
envisioned in the spec, and it is not guaranteed to work if there is
peer-to-peer DMA.  This isn't documented very well; the best I know of
is the changelogs for:

  a1c473aa11e6 pci: Clamp pcie_set_readrq() when using "performance" settings
  b03e7495a862 PCI: Set PCI-E Max Payload Size on fabric

Bjorn
--
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
Jason Gunthorpe May 20, 2014, 5:42 p.m. UTC | #19
On Tue, May 20, 2014 at 11:22:22AM -0600, Bjorn Helgaas wrote:
> On Tue, May 20, 2014 at 11:02 AM, Jason Gunthorpe
> <jgunthorpe@obsidianresearch.com> wrote:
> > On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
> >
> >> But pcie_bus_configure_settings just make sure the mrrs for a device
> >> is not greater than the max payload size.
> >
> > Not quite, it first scans the network checking the Maximum Payload Size
> > Supported (MPSS) for each device, and chooses the highest supported by
> > all as the MPS for all.
> 
> The "performance" setting, e.g., "pci=pcie_bus_perf", adds a few
> wrinkles by setting MRRS in ways that allow some devices to have
> larger MPS than others.  I don't think this is exactly what was
> envisioned in the spec, and it is not guaranteed to work if there is
> peer-to-peer DMA.  This isn't documented very well; the best I know of
> is the changelogs for:
> 
>   a1c473aa11e6 pci: Clamp pcie_set_readrq() when using "performance" settings
>   b03e7495a862 PCI: Set PCI-E Max Payload Size on fabric

Neat, and does pretty much confirm that setting the host bridge MPSS
properly is necessary to support all drivers, particularly the ones
that call pcie_set_readrq with any old value.

The 'performance' setting is a bit scary, it isn't just peer-to-peer
DMA that would be impacted but also CPU initiated burst writes. Eg
InfiniBand drivers burst a WQE to the NIC via the CPU. The MPS on the
root port bridge is used to segment the write. Probably not a problem
in practice because I think this is rare, and even rarer that a burst
would be > 128 bytes - but as you say, not really what the spec
intended..

Jason
--
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
Murali Karicheri May 21, 2014, 11:32 p.m. UTC | #20
On 5/20/2014 1:02 PM, Jason Gunthorpe wrote:
> On Fri, May 16, 2014 at 08:29:56PM +0000, Karicheri, Muralidharan wrote:
>
>> But pcie_bus_configure_settings just make sure the mrrs for a device
>> is not greater than the max payload size.
> Not quite, it first scans the network checking the Maximum Payload Size
> Supported (MPSS) for each device, and chooses the highest supported by
> all as the MPS for all.
Why highest? It should be lowest so that all on the bus can handle it??
>
> PCI-E requires that an end point support all packets up to the MPS, so
> if your bridge can't generate a 512 byte read response packet, then it
> must not advertise a MPSS greater than 256 bytes.
What is MPSS? Is it the payload size in a message TLP? I read the PCIe 
spec and find
MRSS is the maxumum read request size. So memory reads completion data 
size is limited
to this size, right? So for DMA from EP to RC can't be greater than what 
RC publishes.
Not sure how they are related?

I have checked that root port is advertising 256 bytes for mrrs and 128 
bytes for mps
in the config space. So keystone pcie bridge is doing as expected.

In Keystone case, what I see is after  adding 
pcie_bus_configure_settings() with pci=pcie_bus_safe,
I get following log.

[    1.988851] pcie_bus_configure_settings, config 1
[    1.988860] pcie_bus_configure_set
[    1.988879] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  512
[    1.988887] pcie_bus_configure_set
[    1.988921] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  512
[    1.988928] pcie_bus_configure_set
[    1.988961] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  512

So it is not limiting MRRS to 256 bytes.

With pci=pcie_bus_perf

[    1.985777] pcie_bus_configure_settings, config 2
[    1.985783] pcie_bus_configure_set
[    1.985810] pcieport 0000:00:00.0: Max Payload Size set to  256/ 256 
(was  128), Max Read Rq  256
[    1.985818] pcie_bus_configure_set
[    1.985875] pci 0000:01:00.0: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256
[    1.985882] pcie_bus_configure_set
[    1.985939] pci 0000:01:00.1: Max Payload Size set to  256/ 256 (was  
128), Max Read Rq  256

Is this log what you expect?

>
> Setting your MPSS to 128, 256, then using the
> pcie_bus_configure_settings to run the standard algorithm should
> properly limit the readrq to 256 and be able to properly support all
> the fun edge cases like hot plug.

> If the config space in your root port bridge is correct and already
> declares a MPSS of 256 then you have nothing else to do but make sure
> pcie_bus_configure_settings gets calls.
>
> If it is broken and claims a higher MPSS than it can support then you
> need to use a quirk only for the root port bridge or edit the config
> reply in the driver only to fix the MPSS
If MRSS is clamped to lowest, then this would work with out a quirk, and 
has to
be unconditional (all cases, safe, performance etc).

I would like to go with the quirk approach until this discussion 
concludes the next
step to fix this issue. May be someone can take owner ship of this 
change at PCI
core level?

My quirk can be removed once the fix is accepted into the tree. Is that 
an acceptable path forward?

Murali
>
> Jason

--
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
Jason Gunthorpe May 22, 2014, 12:55 a.m. UTC | #21
On Wed, May 21, 2014 at 07:32:58PM -0400, Murali Karicheri wrote:

> >Not quite, it first scans the network checking the Maximum Payload Size
> >Supported (MPSS) for each device, and chooses the highest supported by
> >all as the MPS for all.

> Why highest? It should be lowest so that all on the bus can handle
> it??

Right, that is what 'chooses the highest supported by all' means.

> >PCI-E requires that an end point support all packets up to the MPS, so
> >if your bridge can't generate a 512 byte read response packet, then it
> >must not advertise a MPSS greater than 256 bytes.

> What is MPSS? Is it the payload size in a message TLP? I read the
> PCIe spec and find MRSS is the maxumum read request size. So memory
> reads completion data size is limited to this size, right? So for
> DMA from EP to RC can't be greater than what RC publishes.  Not sure
> how they are related?

MPSS is the maximum packet size supported for send or receive, it is
the absolute max capability of the port:

		DevCap:	MaxPayload 256 bytes, PhantFunc 0, Latency L0s <64ns, L1 unlimited
MPSS                      ^^^^^^^^^^^^^^^^^^^^^^^

MPS is then the largest packet the port will send or receive.

MRSS is the largest read the port will request.

		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			MaxPayload 128 bytes, MaxReadReq 512 bytes
MPS                   ^^^^^^^^^^^^^^^^^^^^^^^
MRSS                                          ^^^^^^^^^^^^^^^^^^^^


It is a little confusing what MRSS > MPS means exactly, but at a
minimum if MRSS > MPS then the responding port must segment the read
reply into MPS sized TLPs.

> I have checked that root port is advertising 256 bytes for mrrs and
> 128 bytes for mps in the config space. So keystone pcie bridge is
> doing as expected.

What is the MPSS?

> In Keystone case, what I see is after  adding
> pcie_bus_configure_settings() with pci=pcie_bus_safe,
> I get following log.
> 
> [    1.988851] pcie_bus_configure_settings, config 1
> [    1.988860] pcie_bus_configure_set
> [    1.988879] pcieport 0000:00:00.0: Max Payload Size set to  256/
> 256 (was  128), Max Read Rq  512
> [    1.988887] pcie_bus_configure_set
> [    1.988921] pci 0000:01:00.0: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  512
> [    1.988928] pcie_bus_configure_set
> [    1.988961] pci 0000:01:00.1: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  512
> 
> So it is not limiting MRRS to 256 bytes.

Right, pcie_bus_safe is the option that doesn't really change
too much, it is assuming the firmware set everything up properly.

> With pci=pcie_bus_perf
> 
> [    1.985777] pcie_bus_configure_settings, config 2
> [    1.985783] pcie_bus_configure_set
> [    1.985810] pcieport 0000:00:00.0: Max Payload Size set to  256/
> 256 (was  128), Max Read Rq  256
> [    1.985818] pcie_bus_configure_set
> [    1.985875] pci 0000:01:00.0: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  256
> [    1.985882] pcie_bus_configure_set
> [    1.985939] pci 0000:01:00.1: Max Payload Size set to  256/ 256
> (was  128), Max Read Rq  256
> 
> Is this log what you expect?

Yes, that matches what the code seems to do.

> If MRSS is clamped to lowest, then this would work with out a quirk,
> and has to be unconditional (all cases, safe, performance etc).

Well, except in this is working around a defect in Keystone. There are
going to be potential problems no matter which route you take because
some drivers do blindly alter the MRRS, and when the core ARM code
starts calling pcie_bus_configure_settings() it will alter the MRRS as
well.

So, the quirk solution is only going to work in some cases.

Adding pci=pcie_bus_perf to the command line in the DTS as a work
around for the defect might be the most comprehensive option?

> I would like to go with the quirk approach until this discussion
> concludes the next step to fix this issue. May be someone can take
> owner ship of this change at PCI core level?

Well, the core code isn't wrong, it just isn't designed to address this
sort of HW defect.

Regards,
Jason
--
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
Jason Gunthorpe May 26, 2014, 11:31 p.m. UTC | #22
On Thu, May 22, 2014 at 06:20:19PM -0400, Murali Karicheri wrote:

>> What is the MPSS?
> 
>    MPS published in DEV CAP is 1 (256 bytes). In our IP for some reason,
>    mrss is set to 2 though IP
>    support only 256 bytes. I am trying to resolve this with IP team. If
>    this is an IP issue, then
>    software will overwrite this to 1.

The MRSS of the root port bridge is very rarely used, it is OK to be
larger than the MPS, but I'm not sure it makes much sense as a
default.

>    So the mps  will not get written to mrss for performance mode. So the
>    check seems not right. It should be changed to

So, looking at this more closely, the MRRS does not *have* to be
smaller than the MPS, but it probably performs better if it is.

I think that reflects what the code is doing.

The fact your root complex can't segment replies is a serious defect,
and there is no infrastructure to support that in the kernel.

Adding something to this generic code might be your best option to
cover the majority of cases.

It would also be good to know for sure that it can correctly segment a
256 byte read into 128 byte packets, and that only 512 is mishandled.

Jason
--
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
Murali Karicheri May 29, 2014, 3:34 p.m. UTC | #23
On 5/15/2014 12:23 PM, Arnd Bergmann wrote:
> On Thursday 15 May 2014 12:01:32 Murali Karicheri wrote:
>
>> +static int
>> +keystone_pcie_fault(unsigned long addr, unsigned int fsr,
>> +		struct pt_regs *regs)
>> +{
>> +	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
>> +
>> +	if ((instr & 0x0e100090) == 0x00100090) {
>> +		int reg = (instr >> 12) & 15;
>> +
>> +		regs->uregs[reg] = -1;
>> +		regs->ARM_pc += 4;
>> +	}
>> +
>> +	return 0;
>> +}
> This needs to check in the PCI host registers what happened and do
> some appropriate action. If the fault was not caused by PCIe, it
> should not be ignored here but get passed on to the next handler.
>
>
Arnd,

The PCI controller is not able to detect the abort error from the EP and 
this gets
reported to ARM as an Asynchronous external abort. PCI fault handler 
needs to
consume this fault, otherwise it can't work on the Keystone h/w.

For example pci-imx6.c has

/*  Added for PCI abort handling */
static int imx6q_pcie_abort_handler(unsigned long addr,
                 unsigned int fsr, struct pt_regs *regs)
{
         return 0;
}

Other examples are

1) arch/arm/mach-cns3xxx/pci.c
static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr,
                                       struct pt_regs *regs)
{
         if (fsr & (1 << 10))
                 regs->ARM_pc += 4;
         return 0;
}
2) arch/.arm/plat-iop/pci.c
/*
  * When a PCI device does not exist during config cycles, the 80200 gets a
  * bus error instead of returning 0xffffffff. This handler simply returns.
  */
static int
iop3xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
         DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR 
= 0x%08lx\n",
                 addr, fsr, regs->ARM_pc, regs->ARM_lr);

         /*
          * 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;
}

I suggest we document this as done in plat-iop. Let me know as I need to 
post my
v2 of the patch this week that incorporates all the comments so far on v1.

Murali
--
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/pcie-keystone.txt b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
new file mode 100644
index 0000000..17cf261
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/pcie-keystone.txt
@@ -0,0 +1,68 @@ 
+Keystone PCIE Root complex device tree bindings
+-----------------------------------------------
+
+Sample bindings shown below:-
+
+ - Remove ti,enable-linktrain if boot loader already does Link training and do EP
+   configuration.
+ - Remove ti,init-phy if boot loader already initialize the phy and sets up pcie
+   link
+
+		pcie0_phy: pciephy@2320000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			#phy-cells = <0>;
+			compatible = "ti,keystone-phy";
+			reg = <0x02320000 0x4000>;
+			reg-names = "reg_serdes";
+		};
+
+		pcie@21800000 {
+			compatible = "ti,keystone-pcie";
+			device_type = "pci";
+			clocks = <&clkpcie>;
+			clock-names = "pcie";
+			#address-cells = <3>;
+			#size-cells = <2>;
+			reg =  <0x21800000 0x1000>, <0x0262014c 4>;
+			reg-names = "reg_rc_app", "reg_devcfg";
+			interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 38 IRQ_TYPE_EDGE_RISING>; /* Error IRQ */
+
+			ranges = <0x00000800 0 0x21801000 0x21801000 0 0x0002000    /* Configuration space */
+				  0x81000000 0 0          0x24000000 0 0x4000       /* downstream I/O */
+				  0x82000000 0 0x50000000 0x50000000 0 0x10000000>; /* non-prefetchable memory */
+
+			num-lanes = <2>;
+			ti,enable-linktrain;
+			ti,init-phy;
+
+			/* PCIE phy */
+			phys = <&pcie0_phy>;
+			phy-names = "pcie-phy";
+
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0>;
+			interrupt-map = <0 0 0 1 &pcie_intc 1>, // INT A
+					<0 0 0 2 &pcie_intc 2>, // INT B
+					<0 0 0 3 &pcie_intc 3>, // INT C
+					<0 0 0 4 &pcie_intc 4>; // INT D
+
+			pcie_intc: legacy-interrupt-controller {
+				interrupt-controller;
+				#interrupt-cells = <1>;
+				interrupt-parent = <&gic>;
+				interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
+					<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+			};
+		};
+
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index c4f4732..066d611 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -37,4 +37,12 @@  config PCI_RCAR_GEN2
 	  Say Y here if you want internal PCI support on R-Car Gen2 SoC.
 	  There are 3 internal PCI controllers available with a single
 	  built-in EHCI/OHCI host controller present on each one.
+
+config PCI_KEYSTONE
+	bool "TI Keystone PCIe controller"
+	depends on ARCH_KEYSTONE
+	select PCIE_DW
+	select PCI_DW_OLD
+	select PCIEPORTBUS
+	select PHY_TI_KEYSTONE
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index be5d939..10e02f9 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -5,3 +5,4 @@  obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
 obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
 obj-$(CONFIG_PCI_DW_OLD) += pci-dw-old-msi.o pci-dw-old.o
+obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
new file mode 100644
index 0000000..2636717
--- /dev/null
+++ b/drivers/pci/host/pci-keystone.c
@@ -0,0 +1,400 @@ 
+/*
+ * PCIe host controller driver for Texas Instruments Keystone SoCs
+ *
+ * Copyright (C) 2013-2014 Texas Instruments., Ltd.
+ *		http://www.ti.com
+ *
+ * Author: Murali Karicheri <m-karicheri2@ti.com>
+ * Implementation based on pci-exynos.c and pcie-designware.c
+ *
+ * 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/irqchip/chained_irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+
+#include "pcie-designware.h"
+#include "pci-dw-old.h"
+
+#define DRIVER_NAME	"keystone-pcie"
+
+/* driver specific constants */
+#define MAX_MSI_HOST_IRQS		8
+#define MAX_LEGACY_HOST_IRQS		4
+
+/* RC mode settings */
+#define PCIE_RC_MODE		(BIT(2))
+#define PCIE_MODE_MASK		(BIT(1) | BIT(2))
+
+static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
+{
+	return sys->private_data;
+}
+
+struct keystone_pcie {
+	struct	clk		*clk;
+	int			en_link_train;
+	struct	pcie_port	pp;
+
+	int			num_legacy_host_irqs;
+	int			legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
+	struct			device_node *np_intc;
+
+	int			num_msi_host_irqs;
+	int			msi_host_irqs[MAX_MSI_HOST_IRQS];
+};
+
+#define to_keystone_pcie(x)	container_of(x, struct keystone_pcie, pp)
+
+static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int count = 200;
+
+	dw_pcie_setup_rc(pp);
+
+	/* check if the link is up or not */
+	while (!dw_pcie_link_up(pp)) {
+		usleep_range(100, 1000);
+		if (--count)
+			continue;
+		dev_err(pp->dev, "phy link never came up\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	u32 offset = irq - ks_pcie->msi_host_irqs[0];
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	dev_dbg(pp->dev, "ks_pcie_msi_irq_handler, irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	dw_old_handle_msi_irq(pp, offset);
+	chained_irq_exit(chip, desc);
+}
+
+/**
+ * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
+ * @irq: IRQ line for legacy interrupts
+ * @desc: Pointer to irq descriptor
+ *
+ * Traverse through pending legacy interrupts and invoke handler for each. Also
+ * takes care of interrupt controller level mask/ack operation.
+ */
+static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
+	u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct pcie_port *pp = &ks_pcie->pp;
+
+	dev_dbg(ks_pcie->pp.dev, ": Handling legacy irq %d\n", irq);
+
+	/*
+	 * The chained irq handler installation would have replaced normal
+	 * interrupt driver handler so we need to take care of mask/unmask and
+	 * ack operation.
+	 */
+	chained_irq_enter(chip, desc);
+	dw_old_handle_legacy_irq(pp, irq_offset);
+	chained_irq_exit(chip, desc);
+}
+
+static int ks_pcie_init_legacy_irqs(struct keystone_pcie *ks_pcie)
+{
+	struct device *dev = ks_pcie->pp.dev;
+	struct device_node *np_pcie = dev->of_node;
+	int num_legacy_irqs;
+	int ret = 0;
+	int i;
+
+	/* get node */
+	ks_pcie->np_intc = of_find_node_by_name(np_pcie,
+						"legacy-interrupt-controller");
+	if (!ks_pcie->np_intc) {
+		dev_err(dev,
+			"Node for legacy-interrupt-controller is absent\n");
+		goto out;
+	}
+
+	/* get number of IRQs */
+	num_legacy_irqs = of_irq_count(ks_pcie->np_intc);
+	if (!num_legacy_irqs)
+		goto out;
+
+	if (num_legacy_irqs > MAX_LEGACY_HOST_IRQS) {
+		dev_err(dev, "Too many legacy interrupts defined %u\n",
+			num_legacy_irqs);
+		num_legacy_irqs = MAX_LEGACY_HOST_IRQS;
+	}
+	/*
+	 * support upto MAX_LEGACY_HOST_IRQS host and legacy IRQs.
+	 * In dt from index 0 to 3
+	 */
+	for (i = 0; i < num_legacy_irqs; i++) {
+		ks_pcie->legacy_host_irqs[i] =
+			irq_of_parse_and_map(ks_pcie->np_intc, i);
+		if (ks_pcie->legacy_host_irqs[i] < 0)
+			break;
+		ks_pcie->num_legacy_host_irqs++;
+	}
+
+	if (!ks_pcie->num_legacy_host_irqs) {
+		dev_err(dev, "Failed to get legacy interrupts\n");
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+static void ks_pcie_enable_interrupts(struct keystone_pcie *ks_pcie)
+{
+	struct pcie_port *pp = &ks_pcie->pp;
+	int i;
+
+	/* Legacy IRQ */
+	for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
+		irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
+		irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
+					ks_pcie_legacy_irq_handler);
+	}
+	dw_old_enable_legacy_irqs(pp);
+
+	/* MSI IRQ */
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
+			irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
+				ks_pcie_msi_irq_handler);
+			irq_set_handler_data(ks_pcie->msi_host_irqs[i],
+						ks_pcie);
+
+		}
+	}
+
+	return;
+}
+
+static int
+keystone_pcie_fault(unsigned long addr, unsigned int fsr,
+		struct pt_regs *regs)
+{
+	unsigned long instr = *(unsigned long *) instruction_pointer(regs);
+
+	if ((instr & 0x0e100090) == 0x00100090) {
+		int reg = (instr >> 12) & 15;
+
+		regs->uregs[reg] = -1;
+		regs->ARM_pc += 4;
+	}
+
+	return 0;
+}
+
+static void __init ks_pcie_host_init(struct pcie_port *pp)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	ks_pcie_establish_link(ks_pcie);
+	dw_old_disable_bars(pp);
+	dw_old_setup_ob_regs(pp);
+	ks_pcie_enable_interrupts(ks_pcie);
+	writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
+			pp->dbi_base + PCI_IO_BASE);
+	/*
+	 * PCIe access errors that result into OCP errors are caught by ARM as
+	 * "External aborts" (Precise).
+	 */
+	hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
+			"external abort on linefetch");
+}
+
+int ks_pcie_link_up(struct pcie_port *pp)
+{
+	struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
+
+	return dw_old_pcie_link_up(pp, ks_pcie->en_link_train);
+}
+
+static struct pcie_host_ops keystone_pcie_host_ops = {
+	.rd_other_conf = dw_old_rd_other_conf,
+	.wr_other_conf = dw_old_wr_other_conf,
+	.link_up = ks_pcie_link_up,
+	.host_init = ks_pcie_host_init,
+	.get_msi_data = dw_old_get_msi_data,
+};
+
+static int add_pcie_port(struct keystone_pcie *ks_pcie,
+			 struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct pcie_port *pp = &ks_pcie->pp;
+	struct resource *res;
+	int ret, i;
+
+	ret = ks_pcie_init_legacy_irqs(ks_pcie);
+	if (ret)
+		return ret;
+
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		/*
+		 * support upto 32 MSI irqs mapped to 8 host IRQs.
+		 * In dt from index 4 to 11
+		 */
+		for (i = 0; i < MAX_MSI_HOST_IRQS; i++) {
+			ks_pcie->msi_host_irqs[i] = irq_of_parse_and_map(np, i);
+			if (ks_pcie->msi_host_irqs[i] < 0)
+				break;
+			ks_pcie->num_msi_host_irqs++;
+		}
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg_rc_app");
+	pp->va_app_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pp->va_app_base))
+		return PTR_ERR(pp->va_app_base);
+	pp->app_base = res->start;
+
+	pp->root_bus_nr = -1;
+	pp->version = DW_VERSION_OLD;
+	pp->ops = &keystone_pcie_host_ops;
+	spin_lock_init(&pp->conf_lock);
+	ret = dw_old_pcie_host_init(pp, ks_pcie->np_intc);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize host\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id ks_pcie_of_match[] = {
+	{
+		.type = "pci",
+		.compatible = "ti,keystone-pcie",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
+
+static int __exit ks_pcie_remove(struct platform_device *pdev)
+{
+	struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return 0;
+}
+
+static int __init ks_pcie_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct keystone_pcie *ks_pcie;
+	void __iomem *devstat;
+	struct pcie_port *pp;
+	struct resource *res;
+	struct phy *phy;
+	int ret = 0;
+	u32 val;
+
+	ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
+				GFP_KERNEL);
+	if (!ks_pcie) {
+		dev_err(dev, "no memory for keystone pcie\n");
+		return -ENOMEM;
+	}
+
+	/* check if serdes phy needs to be enabled */
+	if (of_get_property(np, "ti,init-phy", NULL) != NULL) {
+		phy = devm_phy_get(dev, "pcie-phy");
+			if (IS_ERR(phy))
+				return PTR_ERR(phy);
+
+		ret = phy_init(phy);
+		if (ret < 0)
+			return ret;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   "reg_devcfg");
+	devstat = devm_ioremap_resource(dev, res);
+	if (IS_ERR(devstat))
+		return PTR_ERR(devstat);
+
+	/* enable RC mode in devcfg */
+	val = readl(devstat);
+	val &= ~PCIE_MODE_MASK;
+	val |= PCIE_RC_MODE;
+	writel(val, devstat);
+
+	/* check if we need to enable link training */
+	ks_pcie->en_link_train =
+		(of_get_property(np, "ti,enable-linktrain", NULL) != NULL);
+
+	pp = &ks_pcie->pp;
+	pp->dev = dev;
+
+	ks_pcie->clk = devm_clk_get(dev, "pcie");
+	if (IS_ERR(ks_pcie->clk)) {
+		dev_err(dev, "Failed to get pcie rc clock\n");
+		return PTR_ERR(ks_pcie->clk);
+	}
+	ret = clk_prepare_enable(ks_pcie->clk);
+	if (ret)
+		return ret;
+
+	ret = add_pcie_port(ks_pcie, pdev);
+	if (ret < 0)
+		goto fail_clk;
+
+	platform_set_drvdata(pdev, ks_pcie);
+	dev_info(dev, "pcie rc probe success\n");
+
+	return 0;
+
+fail_clk:
+	clk_disable_unprepare(ks_pcie->clk);
+
+	return ret;
+}
+
+static struct platform_driver ks_pcie_driver __refdata = {
+	.probe  = ks_pcie_probe,
+	.remove = __exit_p(ks_pcie_remove),
+	.driver = {
+		.name	= "keystone-pcie",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(ks_pcie_of_match),
+	},
+};
+
+module_platform_driver(ks_pcie_driver);
+
+MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
+MODULE_DESCRIPTION("Keystone PCIe host controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index e729206..b3e12c2 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3651,3 +3651,16 @@  void pci_dev_specific_enable_acs(struct pci_dev *dev)
 		}
 	}
 }
+#ifdef CONFIG_PCI_KEYSTONE
+/*
+ * The KeyStone PCIe controller has maximum read request size of 256 bytes.
+ */
+static void quirk_limit_readrequest(struct pci_dev *dev)
+{
+	int readrq = pcie_get_readrq(dev);
+
+	if (readrq > 256)
+		pcie_set_readrq(dev, 256);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_readrequest);
+#endif /* CONFIG_PCI_KEYSTONE */