public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH v3 1/2] pcie-xilinx: Wait for link-up status during initialization
       [not found] <1b153bce-a66a-45ee-a5c6-963ea6fb1c82.949ef384-8293-46b8-903f-40a477c056ae.d67fd5a1-30a5-4d5a-a4ef-dde83ebcdd8d@emailsignatures365.codetwo.com>
@ 2025-04-09 14:49 ` Mike Looijmans
  2025-04-09 14:49   ` [PATCH v3 2/2] pcie-xilinx: Support reset GPIO for PERST# Mike Looijmans
  2025-04-09 15:17   ` [PATCH v3 1/2] pcie-xilinx: Wait for link-up status during initialization Bjorn Helgaas
  0 siblings, 2 replies; 4+ messages in thread
From: Mike Looijmans @ 2025-04-09 14:49 UTC (permalink / raw)
  To: linux-pci
  Cc: Mike Looijmans, Bjorn Helgaas, Krzysztof Wilczyński,
	Lorenzo Pieralisi, Manivannan Sadhasivam, Michal Simek,
	Rob Herring, linux-arm-kernel, linux-kernel

When the driver loads, the transceiver may still be in the state of
setting up a link. Wait for that to complete before continuing. This
fixes that the PCIe core does not work when loading the PL bitstream
from userspace. There's only milliseconds between the FPGA boot and the
core initializing in that case, and the link won't be up yet. The design
only worked when the FPGA was programmed in the bootloader, as that will
give the system hundreds of milliseconds to boot.

As the PCIe spec allows up to 100 ms time to establish a link, we'll
allow up to 200ms before giving up.

Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
---

(no changes since v2)

Changes in v2:
Split into "reset GPIO" and "wait for link" patches
Add timeout explanation

 drivers/pci/controller/pcie-xilinx.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c
index 0b534f73a942..2e59b91f43e0 100644
--- a/drivers/pci/controller/pcie-xilinx.c
+++ b/drivers/pci/controller/pcie-xilinx.c
@@ -15,6 +15,7 @@
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/iopoll.h>
 #include <linux/msi.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
@@ -126,6 +127,19 @@ static inline bool xilinx_pcie_link_up(struct xilinx_pcie *pcie)
 		XILINX_PCIE_REG_PSCR_LNKUP) ? 1 : 0;
 }
 
+static int xilinx_pci_wait_link_up(struct xilinx_pcie *pcie)
+{
+	u32 val;
+
+	/*
+	 * PCIe r6.0, sec 6.6.1 provides 100ms timeout. Since this is FPGA
+	 * fabric, we're more lenient and allow 200 ms for link training.
+	 */
+	return readl_poll_timeout(pcie->reg_base + XILINX_PCIE_REG_PSCR, val,
+			(val & XILINX_PCIE_REG_PSCR_LNKUP), 2 * USEC_PER_MSEC,
+			200 * USEC_PER_MSEC);
+}
+
 /**
  * xilinx_pcie_clear_err_interrupts - Clear Error Interrupts
  * @pcie: PCIe port information
@@ -493,7 +507,7 @@ static void xilinx_pcie_init_port(struct xilinx_pcie *pcie)
 {
 	struct device *dev = pcie->dev;
 
-	if (xilinx_pcie_link_up(pcie))
+	if (!xilinx_pci_wait_link_up(pcie))
 		dev_info(dev, "PCIe Link is UP\n");
 	else
 		dev_info(dev, "PCIe Link is DOWN\n");
-- 
2.43.0


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijmans@topic.nl
W: www.topic.nl

Please consider the environment before printing this e-mail


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v3 2/2] pcie-xilinx: Support reset GPIO for PERST#
  2025-04-09 14:49 ` [PATCH v3 1/2] pcie-xilinx: Wait for link-up status during initialization Mike Looijmans
@ 2025-04-09 14:49   ` Mike Looijmans
  2025-04-09 15:17   ` [PATCH v3 1/2] pcie-xilinx: Wait for link-up status during initialization Bjorn Helgaas
  1 sibling, 0 replies; 4+ messages in thread
From: Mike Looijmans @ 2025-04-09 14:49 UTC (permalink / raw)
  To: linux-pci
  Cc: Mike Looijmans, Bjorn Helgaas, Krzysztof Wilczyński,
	Lorenzo Pieralisi, Manivannan Sadhasivam, Michal Simek,
	Rob Herring, linux-arm-kernel, linux-kernel

Support providing the PERST# reset signal through a devicetree binding.
Thus the system no longer relies on external components to perform the
bus reset.

Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
---

Changes in v3:
Include linux/gpio/consumer.h
Message "Failed to request reset GPIO"
Use PCIE_T_PVPERL_MS and PCIE_T_RRS_READY_MS
Dropped dt-bindings patch, not needed

Changes in v2:
Split into "reset GPIO" and "wait for link" patches
Handle GPIO defer and/or errors

 drivers/pci/controller/pcie-xilinx.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/pci/controller/pcie-xilinx.c b/drivers/pci/controller/pcie-xilinx.c
index 2e59b91f43e0..8e8ca9891b36 100644
--- a/drivers/pci/controller/pcie-xilinx.c
+++ b/drivers/pci/controller/pcie-xilinx.c
@@ -10,6 +10,7 @@
  * ARM PCI Host generic driver.
  */
 
+#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
@@ -577,11 +578,17 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct xilinx_pcie *pcie;
 	struct pci_host_bridge *bridge;
+	struct gpio_desc *perst_gpio;
 	int err;
 
 	if (!dev->of_node)
 		return -ENODEV;
 
+	perst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(perst_gpio))
+		return dev_err_probe(dev, PTR_ERR(perst_gpio),
+				     "Failed to request reset GPIO\n");
+
 	bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
 	if (!bridge)
 		return -ENODEV;
@@ -596,6 +603,13 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
 		return err;
 	}
 
+	if (perst_gpio) {
+		msleep(PCIE_T_PVPERL_MS); /* Minimum assertion time */
+		gpiod_set_value_cansleep(perst_gpio, 0);
+		/* Initial delay to provide endpoint time to initialize */
+		msleep(PCIE_T_RRS_READY_MS);
+	}
+
 	xilinx_pcie_init_port(pcie);
 
 	err = xilinx_pcie_init_irq_domain(pcie);
-- 
2.43.0


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijmans@topic.nl
W: www.topic.nl

Please consider the environment before printing this e-mail


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v3 1/2] pcie-xilinx: Wait for link-up status during initialization
  2025-04-09 14:49 ` [PATCH v3 1/2] pcie-xilinx: Wait for link-up status during initialization Mike Looijmans
  2025-04-09 14:49   ` [PATCH v3 2/2] pcie-xilinx: Support reset GPIO for PERST# Mike Looijmans
@ 2025-04-09 15:17   ` Bjorn Helgaas
  2025-04-10  6:00     ` Mike Looijmans
  1 sibling, 1 reply; 4+ messages in thread
From: Bjorn Helgaas @ 2025-04-09 15:17 UTC (permalink / raw)
  To: Mike Looijmans
  Cc: linux-pci, Bjorn Helgaas, Krzysztof Wilczyński,
	Lorenzo Pieralisi, Manivannan Sadhasivam, Michal Simek,
	Rob Herring, linux-arm-kernel, linux-kernel

Please make the subject line match previous changes to this driver.
See "git log --oneline drivers/pci/controller/pcie-xilinx.c"

On Wed, Apr 09, 2025 at 04:49:24PM +0200, Mike Looijmans wrote:
> When the driver loads, the transceiver may still be in the state of
> setting up a link. Wait for that to complete before continuing. This
> fixes that the PCIe core does not work when loading the PL bitstream
> from userspace. There's only milliseconds between the FPGA boot and the
> core initializing in that case, and the link won't be up yet. The design
> only worked when the FPGA was programmed in the bootloader, as that will
> give the system hundreds of milliseconds to boot.
> 
> As the PCIe spec allows up to 100 ms time to establish a link, we'll
> allow up to 200ms before giving up.

This sounds like there's still a race between userspace loading the PL
bitstream and the driver waiting for link up, but we're just waiting
longer in the kernel so userspace has more chance of winning the race.
Is that true?

> @@ -126,6 +127,19 @@ static inline bool xilinx_pcie_link_up(struct xilinx_pcie *pcie)
>  		XILINX_PCIE_REG_PSCR_LNKUP) ? 1 : 0;
>  }
>  
> +static int xilinx_pci_wait_link_up(struct xilinx_pcie *pcie)
> +{
> +	u32 val;
> +
> +	/*
> +	 * PCIe r6.0, sec 6.6.1 provides 100ms timeout. Since this is FPGA
> +	 * fabric, we're more lenient and allow 200 ms for link training.
> +	 */
> +	return readl_poll_timeout(pcie->reg_base + XILINX_PCIE_REG_PSCR, val,
> +			(val & XILINX_PCIE_REG_PSCR_LNKUP), 2 * USEC_PER_MSEC,
> +			200 * USEC_PER_MSEC);

There should be a #define in drivers/pci/pci.h for this 100ms value
that you can use here to connect this more closely with the spec.

Maybe there's a way to use read_poll_timeout(), readx_poll_timeout(),
or something similar so we can use xilinx_pcie_link_up() directly
instead of reimplementing it here?

> +}
> +
>  /**
>   * xilinx_pcie_clear_err_interrupts - Clear Error Interrupts
>   * @pcie: PCIe port information
> @@ -493,7 +507,7 @@ static void xilinx_pcie_init_port(struct xilinx_pcie *pcie)
>  {
>  	struct device *dev = pcie->dev;
>  
> -	if (xilinx_pcie_link_up(pcie))
> +	if (!xilinx_pci_wait_link_up(pcie))
>  		dev_info(dev, "PCIe Link is UP\n");
>  	else
>  		dev_info(dev, "PCIe Link is DOWN\n");


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v3 1/2] pcie-xilinx: Wait for link-up status during initialization
  2025-04-09 15:17   ` [PATCH v3 1/2] pcie-xilinx: Wait for link-up status during initialization Bjorn Helgaas
@ 2025-04-10  6:00     ` Mike Looijmans
  0 siblings, 0 replies; 4+ messages in thread
From: Mike Looijmans @ 2025-04-10  6:00 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: linux-pci, Bjorn Helgaas, Krzysztof Wilczyński,
	Lorenzo Pieralisi, Manivannan Sadhasivam, Michal Simek,
	Rob Herring, linux-arm-kernel, linux-kernel


Met vriendelijke groet / kind regards,

Mike Looijmans
System Expert


TOPIC Embedded Products B.V.
Materiaalweg 4, 5681 RJ Best
The Netherlands

T: +31 (0) 499 33 69 69
E: mike.looijmans@topic.nl
W: www.topic.nl

Please consider the environment before printing this e-mail
On 09-04-2025 17:17, Bjorn Helgaas wrote:
> Please make the subject line match previous changes to this driver.
> See "git log --oneline drivers/pci/controller/pcie-xilinx.c"
>
> On Wed, Apr 09, 2025 at 04:49:24PM +0200, Mike Looijmans wrote:
>> When the driver loads, the transceiver may still be in the state of
>> setting up a link. Wait for that to complete before continuing. This
>> fixes that the PCIe core does not work when loading the PL bitstream
>> from userspace. There's only milliseconds between the FPGA boot and the
>> core initializing in that case, and the link won't be up yet. The design
>> only worked when the FPGA was programmed in the bootloader, as that will
>> give the system hundreds of milliseconds to boot.
>>
>> As the PCIe spec allows up to 100 ms time to establish a link, we'll
>> allow up to 200ms before giving up.
> This sounds like there's still a race between userspace loading the PL
> bitstream and the driver waiting for link up, but we're just waiting
> longer in the kernel so userspace has more chance of winning the race.
> Is that true?

No, that's not the case here. The PCIe (host) core is what is in the PL 
bitstream. Devicetree overlay and FPGA support take care of that part, so the 
PL is programmed and the PCIe core is available when this driver probes.

The issue is with the endpoint on the other side of the PL, most likely an 
NVME drive, WiFi card or PCIe switch (nothing inside the FPGA, the purpose of 
the PCIe core here is to communicate with something external over PCIe).

The endpoint gets reset by what amounts to black magic (external circuit, 
something in the PL, or just nothing at all). This driver assumes that that 
has already happened, and immediately starts training. This works on Xilinx' 
reference designs that program the PL in their proprietary bootloader. If the 
PL was programmed from within Linux, this driver will probe within 
milliseconds after programming the PL, and in that case, the link won't be up yet.

The second patch in this series adds a PERST# GPIO support, so that the "black 
magic" can also be replaced with a proper reset.


>
>> @@ -126,6 +127,19 @@ static inline bool xilinx_pcie_link_up(struct xilinx_pcie *pcie)
>>   		XILINX_PCIE_REG_PSCR_LNKUP) ? 1 : 0;
>>   }
>>   
>> +static int xilinx_pci_wait_link_up(struct xilinx_pcie *pcie)
>> +{
>> +	u32 val;
>> +
>> +	/*
>> +	 * PCIe r6.0, sec 6.6.1 provides 100ms timeout. Since this is FPGA
>> +	 * fabric, we're more lenient and allow 200 ms for link training.
>> +	 */
>> +	return readl_poll_timeout(pcie->reg_base + XILINX_PCIE_REG_PSCR, val,
>> +			(val & XILINX_PCIE_REG_PSCR_LNKUP), 2 * USEC_PER_MSEC,
>> +			200 * USEC_PER_MSEC);
> There should be a #define in drivers/pci/pci.h for this 100ms value
> that you can use here to connect this more closely with the spec.

That'd be "PCIE_T_RRS_READY_MS". Experience learns that adhering too closely 
to this spec is a good way to make your system fail though, so most host 
controllers are more lenient, e.g. rockchip uses 500ms.


>
> Maybe there's a way to use read_poll_timeout(), readx_poll_timeout(),
> or something similar so we can use xilinx_pcie_link_up() directly
> instead of reimplementing it here?

Other way around would be easier, just call this again when it wants to know 
if the link is up, maybe with a 0 timeout (which allows the compiler to remove 
the loop).


>
>> +}
>> +
>>   /**
>>    * xilinx_pcie_clear_err_interrupts - Clear Error Interrupts
>>    * @pcie: PCIe port information
>> @@ -493,7 +507,7 @@ static void xilinx_pcie_init_port(struct xilinx_pcie *pcie)
>>   {
>>   	struct device *dev = pcie->dev;
>>   
>> -	if (xilinx_pcie_link_up(pcie))
>> +	if (!xilinx_pci_wait_link_up(pcie))
>>   		dev_info(dev, "PCIe Link is UP\n");
>>   	else
>>   		dev_info(dev, "PCIe Link is DOWN\n");




^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-04-10  6:02 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <1b153bce-a66a-45ee-a5c6-963ea6fb1c82.949ef384-8293-46b8-903f-40a477c056ae.d67fd5a1-30a5-4d5a-a4ef-dde83ebcdd8d@emailsignatures365.codetwo.com>
2025-04-09 14:49 ` [PATCH v3 1/2] pcie-xilinx: Wait for link-up status during initialization Mike Looijmans
2025-04-09 14:49   ` [PATCH v3 2/2] pcie-xilinx: Support reset GPIO for PERST# Mike Looijmans
2025-04-09 15:17   ` [PATCH v3 1/2] pcie-xilinx: Wait for link-up status during initialization Bjorn Helgaas
2025-04-10  6:00     ` Mike Looijmans

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox