Skip to contentSkip to conversation

PCI: apple: Reset the port for 100ms on probe

PATCH In review Marc Zyngier 3 participants 8 messages Nov 17, 2021 – Nov 20, 2021

Subsystems (3)
lore
Share & tools
lore

Marc Zyngier

author maintainer
#0 lore raw

PATCH 1/1 PCI: apple: Reset the port for 100ms on probe

While the Apple PCIe driver works correctly when directly booted from the firmware, it fails to initialise when the kernel is booted from a bootloader using PCIe such as u-boot.

That's beacuse we're missing a proper reset of the port (we only clear the reset, but never assert it).

Bring the port back to life by wiggling the #PERST pin for 100ms (as per the spec).

Fixes 1e33888fbe44 ("PCI: apple: Add initial hardware bring-up")
Cc Alyssa Rosenzweig <[email protected]>
Cc Lorenzo Pieralisi <[email protected]>
Cc Bjorn Helgaas <[email protected]>
---
 drivers/pci/controller/pcie-apple.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/pci/controller/pcie-apple.c +3 -0
index 1bf4d75b61be..bbea5f6e0a68 100644
@@ -543,6 +543,9 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
 	if (ret < 0)
 		return ret;
 
+	/* Hold #PERST for 100ms as per the spec */
+	gpiod_set_value(reset, 0);
+	msleep(100);
 	rmw_set(PORT_PERST_OFF, port->base + PORT_PERST);
 	gpiod_set_value(reset, 1);
 
Signature · 1 line
2.30.2
#1 lore raw

[+cc Pali]

Quoted 6 lines · Marc Zyngier

While the Apple PCIe driver works correctly when directly booted from the firmware, it fails to initialise when the kernel is booted from a bootloader using PCIe such as u-boot.

That's beacuse we're missing a proper reset of the port (we only clear the reset, but never assert it).

s/beacuse/because/

Quoted 2 lines

Bring the port back to life by wiggling the #PERST pin for 100ms (as per the spec).

I cc'd Pali because I think he's interested in consolidating or somehow rationalizing delays like this.

If we have a specific spec reference here, I think it would help that effort. I *think* it's PCIe r5.0, sec 6.6.1, which mentions the 100ms along with some additional constraints, like waiting 100ms after Link training completes for ports that support > 5.0 GT/s, whether Readiness Notifications are used, and CRS Software Visiblity.

Quoted 26 lines
Fixes 1e33888fbe44 ("PCI: apple: Add initial hardware bring-up")
Cc Alyssa Rosenzweig <[email protected]>
Cc Lorenzo Pieralisi <[email protected]>
Cc Bjorn Helgaas <[email protected]>
---
 drivers/pci/controller/pcie-apple.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/pci/controller/pcie-apple.c +3 -0
index 1bf4d75b61be..bbea5f6e0a68 100644
@@ -543,6 +543,9 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
 	if (ret < 0)
 		return ret;
 
+	/* Hold #PERST for 100ms as per the spec */
+	gpiod_set_value(reset, 0);
+	msleep(100);
 	rmw_set(PORT_PERST_OFF, port->base + PORT_PERST);
 	gpiod_set_value(reset, 1);
 
Signature · 1 line
2.30.2
#2 lore raw

Hello!

Quoted 15 lines · On Wednesday 17 November 2021 14:12:45 Bjorn Helgaas wrote:

[+cc Pali]

Quoted 6 lines · Marc Zyngier

While the Apple PCIe driver works correctly when directly booted from the firmware, it fails to initialise when the kernel is booted from a bootloader using PCIe such as u-boot.

That's beacuse we're missing a proper reset of the port (we only clear the reset, but never assert it).

s/beacuse/because/

Quoted 2 lines

Bring the port back to life by wiggling the #PERST pin for 100ms (as per the spec).

Quoted 8 lines

I cc'd Pali because I think he's interested in consolidating or somehow rationalizing delays like this.

If we have a specific spec reference here, I think it would help that effort. I *think* it's PCIe r5.0, sec 6.6.1, which mentions the 100ms along with some additional constraints, like waiting 100ms after Link training completes for ports that support > 5.0 GT/s, whether Readiness Notifications are used, and CRS Software Visiblity.

This is not 100ms timeout "after link training completes".

Timeout in this patch is between flipping PERST# signal, so timeout means how long needs to be endpoint card in reset state. And this timeout cannot be controller specific. In past I have tried to find this timeout in specifications, I was not able. Some summary is in my email:
https://lore.kernel.org/linux-pci/20210310110535.zh4pnn4vpmvzwl5q@pali/

So I would like to know, why was chosen 100ms for msleep() in this patch?

Quoted 26 lines
Quoted 26 lines
Fixes 1e33888fbe44 ("PCI: apple: Add initial hardware bring-up")
Cc Alyssa Rosenzweig <[email protected]>
Cc Lorenzo Pieralisi <[email protected]>
Cc Bjorn Helgaas <[email protected]>
---
 drivers/pci/controller/pcie-apple.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/pci/controller/pcie-apple.c +3 -0
index 1bf4d75b61be..bbea5f6e0a68 100644
@@ -543,6 +543,9 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie,
 	if (ret < 0)
 		return ret;
 
+	/* Hold #PERST for 100ms as per the spec */
+	gpiod_set_value(reset, 0);
+	msleep(100);
 	rmw_set(PORT_PERST_OFF, port->base + PORT_PERST);
 	gpiod_set_value(reset, 1);
 
Signature · 1 line
2.30.2
author maintainer
#3 lore raw
Quoted 30 lines · Pali Rohár

Hello!

Quoted 15 lines · On Wednesday 17 November 2021 14:12:45 Bjorn Helgaas wrote:

[+cc Pali]

Quoted 6 lines · Marc Zyngier

While the Apple PCIe driver works correctly when directly booted from the firmware, it fails to initialise when the kernel is booted from a bootloader using PCIe such as u-boot.

That's beacuse we're missing a proper reset of the port (we only clear the reset, but never assert it).

s/beacuse/because/

Quoted 2 lines

Bring the port back to life by wiggling the #PERST pin for 100ms (as per the spec).

Quoted 8 lines

I cc'd Pali because I think he's interested in consolidating or somehow rationalizing delays like this.

If we have a specific spec reference here, I think it would help that effort. I *think* it's PCIe r5.0, sec 6.6.1, which mentions the 100ms along with some additional constraints, like waiting 100ms after Link training completes for ports that support > 5.0 GT/s, whether Readiness Notifications are used, and CRS Software Visiblity.

This is not 100ms timeout "after link training completes".

Quoted 8 lines

Timeout in this patch is between flipping PERST# signal, so timeout means how long needs to be endpoint card in reset state. And this timeout cannot be controller specific. In past I have tried to find this timeout in specifications, I was not able. Some summary is in my email:
https://lore.kernel.org/linux-pci/20210310110535.zh4pnn4vpmvzwl5q@pali/

So I would like to know, why was chosen 100ms for msleep() in this patch?

Excellent question. I went back to my notes (and the spec), and it looks like I have mistakenly conflated *two* delays here:

- The post-#PERST delay, which is 100ms, and which is *not* what this patch is doing while it really should be doing it. This is documented in the base PCIe spec (in Rev 2.0, this is part of 6.6.1). The amusing part is that on this HW, it seems that only the delay from the falling edge matters (which is why I didn't spot the issue).

- The duration of the power-on #PERST assertion (Tpvperl), which is also 100ms, and documented in the PCIe Card Electromechanical Specification (Rev 1.0a, 2.2 and 2.2.1).

There is also a third delay (Tperst-clk) which represents the time required for the clock to ramp up before releasing #PERST. No, there is no value associated with this.

Having come to my senses, and with these constraints in mind, this is what I currently have in my tree:

	/* Engage #PERST */
	gpiod_set_value(reset, 0);

	ret = apple_pcie_setup_refclk(pcie, port);
	if (ret < 0)
		return ret;

	/* Hold #PERST for 100ms as per the electromechanical spec */
	msleep(100);
	rmw_set(PORT_PERST_OFF, port->base + PORT_PERST);
	gpiod_set_value(reset, 1);
	/* Wait for 100ms after #PERST deassertion before anothing else */
	msleep(100);

Yes, this is totally overkill, as I assume that each port has gone through a complete power-off and is only slowly coming back from the dead.

In practice, I can completely remove the initial Tpvperl delay (we have been powered-on for a long time already, and the clock is stable when we come back from setting it up), and cut the second one by half without observing any ill effect (though I feel safer keeping it to its nominal value).

If nobody screams, I'll respin something shortly.

	M.
Signature · 6 lines
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#4 lore raw
Quoted 51 lines · On Thursday 18 November 2021 10:01:58 Marc Zyngier wrote:
Quoted 30 lines · Pali Rohár

Hello!

Quoted 15 lines · On Wednesday 17 November 2021 14:12:45 Bjorn Helgaas wrote:

[+cc Pali]

Quoted 6 lines · Marc Zyngier

While the Apple PCIe driver works correctly when directly booted from the firmware, it fails to initialise when the kernel is booted from a bootloader using PCIe such as u-boot.

That's beacuse we're missing a proper reset of the port (we only clear the reset, but never assert it).

s/beacuse/because/

Quoted 2 lines

Bring the port back to life by wiggling the #PERST pin for 100ms (as per the spec).

Quoted 8 lines

I cc'd Pali because I think he's interested in consolidating or somehow rationalizing delays like this.

If we have a specific spec reference here, I think it would help that effort. I *think* it's PCIe r5.0, sec 6.6.1, which mentions the 100ms along with some additional constraints, like waiting 100ms after Link training completes for ports that support > 5.0 GT/s, whether Readiness Notifications are used, and CRS Software Visiblity.

This is not 100ms timeout "after link training completes".

Quoted 8 lines

Timeout in this patch is between flipping PERST# signal, so timeout means how long needs to be endpoint card in reset state. And this timeout cannot be controller specific. In past I have tried to find this timeout in specifications, I was not able. Some summary is in my email:
https://lore.kernel.org/linux-pci/20210310110535.zh4pnn4vpmvzwl5q@pali/

So I would like to know, why was chosen 100ms for msleep() in this patch?

Excellent question. I went back to my notes (and the spec), and it looks like I have mistakenly conflated *two* delays here:

- The post-#PERST delay, which is 100ms, and which is *not* what this patch is doing while it really should be doing it. This is documented in the base PCIe spec (in Rev 2.0, this is part of 6.6.1). The amusing part is that on this HW, it seems that only the delay from the falling edge matters (which is why I didn't spot the issue).

Quoted 3 lines

- The duration of the power-on #PERST assertion (Tpvperl), which is also 100ms, and documented in the PCIe Card Electromechanical Specification (Rev 1.0a, 2.2 and 2.2.1).

I think that your patch is doing also something different. It uses PERST# signal to reset card _after_ card was fully powered on and _maybe_ link was already established (depends on bootloader if it initialized PCIe, etc...).

Important is that this reset is really needed for some cards (e.g. lot of Atheros wifi cards as they can be stuck somewhere in broken state) and I do not think it is Tpvperl delay. More controller drivers add some delay between flipping PERST# signal. In past I wrote summary of it:
https://lore.kernel.org/linux-pci/20200424092546.25p3hdtkehohe3xw@pali/

Quoted 3 lines

There is also a third delay (Tperst-clk) which represents the time required for the clock to ramp up before releasing #PERST. No, there is no value associated with this.

But there is minimal value for Tperst-clk which is 100us defined in PCIe CEM spec (3.0) and also in M.2 CEM spec.

Quoted 17 lines

Having come to my senses, and with these constraints in mind, this is what I currently have in my tree:

	/* Engage #PERST */
	gpiod_set_value(reset, 0);

	ret = apple_pcie_setup_refclk(pcie, port);
	if (ret < 0)
		return ret;

	/* Hold #PERST for 100ms as per the electromechanical spec */
	msleep(100);
	rmw_set(PORT_PERST_OFF, port->base + PORT_PERST);
	gpiod_set_value(reset, 1);
	/* Wait for 100ms after #PERST deassertion before anothing else */
	msleep(100);
Quoted 3 lines

Yes, this is totally overkill, as I assume that each port has gone through a complete power-off and is only slowly coming back from the dead.

For power-on it is probably overkill, but I think that delay between flipping PERST# should be there. IIRC Compex WLE1216 wifi card needs to be at least 10-11ms in reset. Last year, during testing of this card I saw that if PERST#-based reset was shorter then card was completely undetected.

Quoted 5 lines

In practice, I can completely remove the initial Tpvperl delay (we have been powered-on for a long time already, and the clock is stable when we come back from setting it up), and cut the second one by half without observing any ill effect (though I feel safer keeping it to its nominal value).

My opinion is that this patch does not power on/off card in PCIe slot. And because card is powered-on for a long time (as you wrote), it means that Tpvperl delay does not apply here. That is why I think that different delay (How long should be PCIe card in Warm Reset state) should be used _between_ flipping PERST# signal.

And of course after the releasing PERST# that 100ms post-PERST# delay is required.

I have an idea to move PERST# handling (with all delays) from controller drivers to pci core functions. Because basically every driver re-implements these delays in its probe function. I wrote this idea with some details in email. If you have a time, could you look at it? I summarized here also details about delays (like Tpvperl, Tperstclk, ..):
https://lore.kernel.org/linux-pci/20211022183808.jdeo7vntnagqkg7g@pali/

Quoted 6 lines

If nobody screams, I'll respin something shortly.

	M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
author maintainer
#5 lore raw
Quoted 53 lines · Pali Rohár
Quoted 51 lines · On Thursday 18 November 2021 10:01:58 Marc Zyngier wrote:
Quoted 30 lines · Pali Rohár

Hello!

Quoted 15 lines · On Wednesday 17 November 2021 14:12:45 Bjorn Helgaas wrote:

[+cc Pali]

Quoted 6 lines · Marc Zyngier

While the Apple PCIe driver works correctly when directly booted from the firmware, it fails to initialise when the kernel is booted from a bootloader using PCIe such as u-boot.

That's beacuse we're missing a proper reset of the port (we only clear the reset, but never assert it).

s/beacuse/because/

Quoted 2 lines

Bring the port back to life by wiggling the #PERST pin for 100ms (as per the spec).

Quoted 8 lines

I cc'd Pali because I think he's interested in consolidating or somehow rationalizing delays like this.

If we have a specific spec reference here, I think it would help that effort. I *think* it's PCIe r5.0, sec 6.6.1, which mentions the 100ms along with some additional constraints, like waiting 100ms after Link training completes for ports that support > 5.0 GT/s, whether Readiness Notifications are used, and CRS Software Visiblity.

This is not 100ms timeout "after link training completes".

Quoted 8 lines

Timeout in this patch is between flipping PERST# signal, so timeout means how long needs to be endpoint card in reset state. And this timeout cannot be controller specific. In past I have tried to find this timeout in specifications, I was not able. Some summary is in my email:
https://lore.kernel.org/linux-pci/20210310110535.zh4pnn4vpmvzwl5q@pali/

So I would like to know, why was chosen 100ms for msleep() in this patch?

Excellent question. I went back to my notes (and the spec), and it looks like I have mistakenly conflated *two* delays here:

- The post-#PERST delay, which is 100ms, and which is *not* what this patch is doing while it really should be doing it. This is documented in the base PCIe spec (in Rev 2.0, this is part of 6.6.1). The amusing part is that on this HW, it seems that only the delay from the falling edge matters (which is why I didn't spot the issue).

Quoted 8 lines
Quoted 3 lines

- The duration of the power-on #PERST assertion (Tpvperl), which is also 100ms, and documented in the PCIe Card Electromechanical Specification (Rev 1.0a, 2.2 and 2.2.1).

I think that your patch is doing also something different. It uses PERST# signal to reset card _after_ card was fully powered on and _maybe_ link was already established (depends on bootloader if it initialized PCIe, etc...).

Yes, and that's what I have said above.

Quoted 5 lines

Important is that this reset is really needed for some cards (e.g. lot of Atheros wifi cards as they can be stuck somewhere in broken state) and I do not think it is Tpvperl delay. More controller drivers add some delay between flipping PERST# signal. In past I wrote summary of it:
https://lore.kernel.org/linux-pci/20200424092546.25p3hdtkehohe3xw@pali/

I don't think any of this applies here.

Quoted 6 lines
Quoted 3 lines

There is also a third delay (Tperst-clk) which represents the time required for the clock to ramp up before releasing #PERST. No, there is no value associated with this.

But there is minimal value for Tperst-clk which is 100us defined in PCIe CEM spec (3.0) and also in M.2 CEM spec.

Which is what I have pointed out in my followup to my original email.

Quoted 22 lines
Quoted 18 lines

Having come to my senses, and with these constraints in mind, this is what I currently have in my tree:

	/* Engage #PERST */
	gpiod_set_value(reset, 0);

	ret = apple_pcie_setup_refclk(pcie, port);
	if (ret < 0)
		return ret;

	/* Hold #PERST for 100ms as per the electromechanical spec */
	msleep(100);
	rmw_set(PORT_PERST_OFF, port->base + PORT_PERST);
	gpiod_set_value(reset, 1);
	/* Wait for 100ms after #PERST deassertion before anothing else */
	msleep(100);
Quoted 3 lines

Yes, this is totally overkill, as I assume that each port has gone through a complete power-off and is only slowly coming back from the dead.

Quoted 5 lines

For power-on it is probably overkill, but I think that delay between flipping PERST# should be there. IIRC Compex WLE1216 wifi card needs to be at least 10-11ms in reset. Last year, during testing of this card I saw that if PERST#-based reset was shorter then card was completely undetected.

The only delay we really need is Tperst-clk. Random bugs on random devices don't apply here, as the system is completely closed (there is no slot to add anything). Once we have TB running one of these days, we will see whether this still holds.

Quoted 11 lines
Quoted 5 lines

In practice, I can completely remove the initial Tpvperl delay (we have been powered-on for a long time already, and the clock is stable when we come back from setting it up), and cut the second one by half without observing any ill effect (though I feel safer keeping it to its nominal value).

My opinion is that this patch does not power on/off card in PCIe slot. And because card is powered-on for a long time (as you wrote), it means that Tpvperl delay does not apply here. That is why I think that different delay (How long should be PCIe card in Warm Reset state) should be used _between_ flipping PERST# signal.

My reading of the spec is that the only thing we need while #PERST is asserted is Tperst-clk. The value you keep arguing about doesn't seem to exist as such in the spec, because it appears to be endpoint specific.

Quoted 2 lines

And of course after the releasing PERST# that 100ms post-PERST# delay is required.

That we agree on.

Quoted 6 lines

I have an idea to move PERST# handling (with all delays) from controller drivers to pci core functions. Because basically every driver re-implements these delays in its probe function. I wrote this idea with some details in email. If you have a time, could you look at it? I summarized here also details about delays (like Tpvperl, Tperstclk, ..):
https://lore.kernel.org/linux-pci/20211022183808.jdeo7vntnagqkg7g@pali/

That's a laudable goal. What isn't clear to me is whether you intend to move the whole state machine into core code, or just have a set of helpers that the driver calls into. IMO, the former is what we really need, while the latter only rids us of the simple stuff.

	M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
#6 lore raw
Quoted 8 lines · On Thursday 18 November 2021 12:57:46 Marc Zyngier wrote:
Quoted 5 lines · Pali Rohár

For power-on it is probably overkill, but I think that delay between flipping PERST# should be there. IIRC Compex WLE1216 wifi card needs to be at least 10-11ms in reset. Last year, during testing of this card I saw that if PERST#-based reset was shorter then card was completely undetected.

Quoted 4 lines

The only delay we really need is Tperst-clk. Random bugs on random devices don't apply here, as the system is completely closed (there is no slot to add anything). Once we have TB running one of these days, we will see whether this still holds.

Ok!

Quoted 12 lines
Quoted 11 lines
Quoted 5 lines

In practice, I can completely remove the initial Tpvperl delay (we have been powered-on for a long time already, and the clock is stable when we come back from setting it up), and cut the second one by half without observing any ill effect (though I feel safer keeping it to its nominal value).

My opinion is that this patch does not power on/off card in PCIe slot. And because card is powered-on for a long time (as you wrote), it means that Tpvperl delay does not apply here. That is why I think that different delay (How long should be PCIe card in Warm Reset state) should be used _between_ flipping PERST# signal.

Quoted 4 lines

My reading of the spec is that the only thing we need while #PERST is asserted is Tperst-clk. The value you keep arguing about doesn't seem to exist as such in the spec, because it appears to be endpoint specific.

Well, I was not able to find it in the spec too, that is why I do not know...

Quoted 12 lines
Quoted 2 lines

And of course after the releasing PERST# that 100ms post-PERST# delay is required.

That we agree on.

Quoted 6 lines

I have an idea to move PERST# handling (with all delays) from controller drivers to pci core functions. Because basically every driver re-implements these delays in its probe function. I wrote this idea with some details in email. If you have a time, could you look at it? I summarized here also details about delays (like Tpvperl, Tperstclk, ..):
https://lore.kernel.org/linux-pci/20211022183808.jdeo7vntnagqkg7g@pali/

Quoted 4 lines

That's a laudable goal. What isn't clear to me is whether you intend to move the whole state machine into core code, or just have a set of helpers that the driver calls into. IMO, the former is what we really need, while the latter only rids us of the simple stuff.

Now I'm just collecting comments and feedbacks for this idea. I think that state machine in core code is what we need.

author maintainer
#7 lore raw
In reply to Marc Zyngier
Quoted 4 lines · Marc Zyngier

There is also a third delay (Tperst-clk) which represents the time required for the clock to ramp up before releasing #PERST. No, there is no value associated with this.

Actually, there is. At least the PCIe CMS r2.0 (2.6.2. AC Specifications) does provide a table of the timings. Tperst-clk has a minimum value of 100us.

Which means I can tighten things further.

	M.
Signature · 1 line
Without deviation from the norm, progress is not possible.