Skip to contentSkip to conversation

tegra194 PCI endpoint fixes

PATCH Applied Niklas Cassel 4 participants 18 messages Sep 22, 2025 – Feb 12 1 message not in the archive

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

v2 cover tegra194 PCI endpoint fixes

Hello there,

Shin'ichiro and I have recently been trying to get the Jetson to run the PCI endpoint kselftests on a tegra based board. These patches ensure that the BAR test cases and MSI test cases pass. The MSI-X test cases still fail.

Dependency
==========
"PCI: tegra194: Fix broken tegra_pcie_ep_raise_msi_irq()" requires commit 27fce9e8c6f0 ("PCI: endpoint: Drop superfluous pci_epc_features initialization") which is currently queued on branch pci/endpoint.

Changes since v1:
-Improved commit messages.
-Added CC-stable and Fixes tags.

Niklas Cassel (2):
PCI: tegra194: Fix broken tegra_pcie_ep_raise_msi_irq()
PCI: tegra194: Reset BARs when running in PCIe endpoint mode

Vidya Sagar (1):
PCI: tegra194: Handle errors in BPMP response

 drivers/pci/controller/dwc/pcie-tegra194.c | 33 +++++++++++++++++++---
 1 file changed, 29 insertions(+), 4 deletions(-)
Signature · 1 line
2.51.0
#1 lore raw

PATCH v2 1/3 PCI: tegra194: Fix broken tegra_pcie_ep_raise_msi_irq()

The pci_epc_raise_irq() supplies a MSI or MSI-X interrupt number in range (1-N), see kdoc for pci_epc_raise_irq().

Thus, for MSI pci_epc_raise_irq() will supply interrupt number 1-32.

Convert the interrupt number to an MSI vector.

With this, the PCI endpoint kselftest test case MSI_TEST passes.

Also, set msi_capable to true, as the driver obviously supports MSI. This helps pci_endpoint_test to use the optimal IRQ type when using PCITEST_IRQ_TYPE_AUTO.

Fixes c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194")
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/pci/controller/dwc/pcie-tegra194.c +3 -2
index 7c295ec6f0f16..63d310e5335f4 100644
@@ -1969,10 +1969,10 @@ static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq)
 
 static int tegra_pcie_ep_raise_msi_irq(struct tegra_pcie_dw *pcie, u16 irq)
 {
-	if (unlikely(irq > 31))
+	if (unlikely(irq > 32))
 		return -EINVAL;
 
-	appl_writel(pcie, BIT(irq), APPL_MSI_CTRL_1);
+	appl_writel(pcie, BIT(irq - 1), APPL_MSI_CTRL_1);
 
 	return 0;
 }
@@ -2012,6 +2012,7 @@ static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
 
 static const struct pci_epc_features tegra_pcie_epc_features = {
 	.linkup_notifier = true,
+	.msi_capable = true,
 	.bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M,
 			.only_64bit = true, },
 	.bar[BAR_1] = { .type = BAR_RESERVED, },
Signature · 1 line
2.51.0
#2 lore raw

Re: [PATCH v2 1/3] PCI: tegra194: Fix broken tegra_pcie_ep_raise_msi_irq()

Quoted 38 lines · Niklas Cassel

The pci_epc_raise_irq() supplies a MSI or MSI-X interrupt number in range (1-N), see kdoc for pci_epc_raise_irq().

Thus, for MSI pci_epc_raise_irq() will supply interrupt number 1-32.

Convert the interrupt number to an MSI vector.

With this, the PCI endpoint kselftest test case MSI_TEST passes.

Also, set msi_capable to true, as the driver obviously supports MSI. This helps pci_endpoint_test to use the optimal IRQ type when using PCITEST_IRQ_TYPE_AUTO.

Fixes c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194")
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/pci/controller/dwc/pcie-tegra194.c +2 -2
index 7c295ec6f0f16..63d310e5335f4 100644
@@ -1969,10 +1969,10 @@ static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq)
 
 static int tegra_pcie_ep_raise_msi_irq(struct tegra_pcie_dw *pcie, u16 irq)
 {
-	if (unlikely(irq > 31))
+	if (unlikely(irq > 32))
 		return -EINVAL;
 
-	appl_writel(pcie, BIT(irq), APPL_MSI_CTRL_1);
+	appl_writel(pcie, BIT(irq - 1), APPL_MSI_CTRL_1);
 
 	return 0;
 }

drivers/pci/controller/dwc/pcie-tegra194.c static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · line 2015

Quoted 4 lines
drivers/pci/controller/dwc/pcie-tegra194.c +1 -0
@@ -2012,6 +2012,7 @@ static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
 
 static const struct pci_epc_features tegra_pcie_epc_features = {
 	.linkup_notifier = true,
+	.msi_capable = true,

This change is unrelated to the above tegra_pcie_ep_raise_msi_irq() fix. So this change should be in a separate patch.

- Mani

Signature · 1 line
மணிவண்ணன் சதாசிவம்
#3 lore raw

Re: [PATCH v2 1/3] PCI: tegra194: Fix broken tegra_pcie_ep_raise_msi_irq()

Quoted 40 lines · Manivannan Sadhasivam
Quoted 39 lines · Niklas Cassel

The pci_epc_raise_irq() supplies a MSI or MSI-X interrupt number in range (1-N), see kdoc for pci_epc_raise_irq().

Thus, for MSI pci_epc_raise_irq() will supply interrupt number 1-32.

Convert the interrupt number to an MSI vector.

With this, the PCI endpoint kselftest test case MSI_TEST passes.

Also, set msi_capable to true, as the driver obviously supports MSI. This helps pci_endpoint_test to use the optimal IRQ type when using PCITEST_IRQ_TYPE_AUTO.

Fixes c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194")
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/pci/controller/dwc/pcie-tegra194.c +2 -2
index 7c295ec6f0f16..63d310e5335f4 100644
@@ -1969,10 +1969,10 @@ static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq)
 
 static int tegra_pcie_ep_raise_msi_irq(struct tegra_pcie_dw *pcie, u16 irq)
 {
-	if (unlikely(irq > 31))
+	if (unlikely(irq > 32))
 		return -EINVAL;
 
-	appl_writel(pcie, BIT(irq), APPL_MSI_CTRL_1);
+	appl_writel(pcie, BIT(irq - 1), APPL_MSI_CTRL_1);
 
 	return 0;
 }
@@ -2012,6 +2012,7 @@ static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
 
Quoted 7 lines

drivers/pci/controller/dwc/pcie-tegra194.c static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · line 2015

Quoted 3 lines
drivers/pci/controller/dwc/pcie-tegra194.c +1 -0
 static const struct pci_epc_features tegra_pcie_epc_features = {
 	.linkup_notifier = true,
+	.msi_capable = true,

This change is unrelated to the above tegra_pcie_ep_raise_msi_irq() fix. So this change should be in a separate patch.

I did the split and applied the series, thanks!

- Mani

Signature · 1 line
மணிவண்ணன் சதாசிவம்
#4 lore raw

Re: [PATCH v2 1/3] PCI: tegra194: Fix broken tegra_pcie_ep_raise_msi_irq()

Quoted 11 lines · Manivannan Sadhasivam
Quoted 9 lines

drivers/pci/controller/dwc/pcie-tegra194.c static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no, · line 2015

Quoted 5 lines
drivers/pci/controller/dwc/pcie-tegra194.c +1 -0
@@ -2012,6 +2012,7 @@ static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
 
 static const struct pci_epc_features tegra_pcie_epc_features = {
 	.linkup_notifier = true,
+	.msi_capable = true,

This change is unrelated to the above tegra_pcie_ep_raise_msi_irq() fix. So this change should be in a separate patch.

I did the split and applied the series, thanks!

Thank you Mani!

Kind regards,
Niklas

#5 lore raw

PATCH v2 2/3 PCI: tegra194: Reset BARs when running in PCIe endpoint mode

In reply to Niklas Cassel

Tegra already defines all BARs expect for BAR0 as BAR_RESERVED. This is sufficient for pci-epf-test to not allocate backing memory and to not call set_bar() for those BARs. However, marking a BAR as BAR_RESERVED does not mean that the BAR get disabled.

The host side driver, pci_endpoint_test, simply does an ioremap for all enabled BARs, and will run tests against all enabled BARs. (I.e. it will run tests also against the BARs marked as BAR_RESERVED.)

After running the BARs tests (which will write to all enabled BARs), the inbound address translation is broken.
This is because the tegra controller exposes the ATU Port Logic Structure in BAR4. So when BAR4 is written, the inbound address translation settings get overwritten.

To avoid this, implement the dw_pcie_ep_ops .init() callback and start off by disabling all BARs (pci-epf-test will later enable/configure BARs that are not defined as BAR_RESERVED).

This matches the behavior of other PCIe endpoint drivers:
dra7xx, imx6, layerscape-ep, artpec6, dw-rockchip, qcom-ep, rcar-gen4, and uniphier-ep.

With this, the PCI endpoint kselftest test case CONSECUTIVE_BAR_TEST (which was specifically made to detect address translation issues) passes.

Fixes c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194")
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/pci/controller/dwc/pcie-tegra194.c +10 -0
index 63d310e5335f4..7eb48cc13648e 100644
@@ -1955,6 +1955,15 @@ static irqreturn_t tegra_pcie_ep_pex_rst_irq(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
+static void tegra_pcie_ep_init(struct dw_pcie_ep *ep)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	enum pci_barno bar;
+
+	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
+		dw_pcie_ep_reset_bar(pci, bar);
+};
+
 static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq)
 {
 	/* Tegra194 supports only INTA */
@@ -2030,6 +2039,7 @@ tegra_pcie_ep_get_features(struct dw_pcie_ep *ep)
 }
 
 static const struct dw_pcie_ep_ops pcie_ep_ops = {
+	.init = tegra_pcie_ep_init,
 	.raise_irq = tegra_pcie_ep_raise_irq,
 	.get_features = tegra_pcie_ep_get_features,
 };
Signature · 1 line
2.51.0
#6 lore raw

Re: [PATCH v2 2/3] PCI: tegra194: Reset BARs when running in PCIe endpoint mode

Hi Niklas,

Tegra PCIe exposes only DMA register over BAR4, not iATU. So, the issue described in this commit message is not applicable. This patch is disabling BAR2 and BAR4, after enumeration I see only BAR0. I think we should revert this patch.
Please share your inputs on this.

Thanks,
Manikanta

Quoted 61 lines · Niklas Cassel

Tegra already defines all BARs expect for BAR0 as BAR_RESERVED. This is sufficient for pci-epf-test to not allocate backing memory and to not call set_bar() for those BARs. However, marking a BAR as BAR_RESERVED does not mean that the BAR get disabled.

The host side driver, pci_endpoint_test, simply does an ioremap for all enabled BARs, and will run tests against all enabled BARs. (I.e. it will run tests also against the BARs marked as BAR_RESERVED.)

After running the BARs tests (which will write to all enabled BARs), the inbound address translation is broken.
This is because the tegra controller exposes the ATU Port Logic Structure in BAR4. So when BAR4 is written, the inbound address translation settings get overwritten.

To avoid this, implement the dw_pcie_ep_ops .init() callback and start off by disabling all BARs (pci-epf-test will later enable/configure BARs that are not defined as BAR_RESERVED).

This matches the behavior of other PCIe endpoint drivers:
dra7xx, imx6, layerscape-ep, artpec6, dw-rockchip, qcom-ep, rcar-gen4, and uniphier-ep.

With this, the PCI endpoint kselftest test case CONSECUTIVE_BAR_TEST (which was specifically made to detect address translation issues) passes.

Fixes c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194")
---
  drivers/pci/controller/dwc/pcie-tegra194.c | 10 ++++++++++
  1 file changed, 10 insertions(+)
drivers/pci/controller/dwc/pcie-tegra194.c +10 -0
index 63d310e5335f4..7eb48cc13648e 100644
@@ -1955,6 +1955,15 @@ static irqreturn_t tegra_pcie_ep_pex_rst_irq(int irq, void *arg)
  	return IRQ_HANDLED;
  }
 
+static void tegra_pcie_ep_init(struct dw_pcie_ep *ep)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	enum pci_barno bar;
+
+	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
+		dw_pcie_ep_reset_bar(pci, bar);
+};
+
  static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq)
  {
  	/* Tegra194 supports only INTA */
@@ -2030,6 +2039,7 @@ tegra_pcie_ep_get_features(struct dw_pcie_ep *ep)
  }
 
  static const struct dw_pcie_ep_ops pcie_ep_ops = {
+	.init = tegra_pcie_ep_init,
  	.raise_irq = tegra_pcie_ep_raise_irq,
  	.get_features = tegra_pcie_ep_get_features,
  };
#7 lore raw

Re: [PATCH v2 2/3] PCI: tegra194: Reset BARs when running in PCIe endpoint mode

Quoted 7 lines · Manikanta Maddireddy

Hi Niklas,

Tegra PCIe exposes only DMA register over BAR4, not iATU. So, the issue described in this commit message is not applicable. This patch is disabling BAR2 and BAR4, after enumeration I see only BAR0. I think we should revert this patch.
Please share your inputs on this.

If you look at this commit, it only disables all BARs by default, which brings the tegra driver in-line with all other DWC based endpoint drivers: dra7xx, imx6, layerscape-ep, artpec6, dw-rockchip, qcom-ep, rcar-gen4, and uniphier-ep.

A PCI endpoint function (EPF) driver will still be able to enable a BAR that was disabled in .init().
However, an EPF driver will not be able to use/enable a reserved BAR.

Look at e.g. the code in pci-epf-test. It will not allocate backing memory for a BAR that is reserved, so having a BAR enabled that we have not allocated backing memory for is wrong.

Commit c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") is the commit that marked all BARs other than BAR0 as reserved, so if you want to test BARs other than BAR0, talk to the author of that commit.

If you revert this patch, tools/testing/selftests/pci_endpoint/pci_endpoint_test will once again fail the consecutive BAR test, so I think it would be wrong to revert this patch.

If it is ATU registers or eDMA registers exposed in BAR4 does not really matter. The end result is that you overwrite eDMA registers that you should not be overwriting when you run the BAR tests. (So BAR4 should absolutely be marked as reserved).

I don't recall, but if you overwrite the eDMA registers, then in addition to the consecutive BAR test failing, most likely the DMA test cases will also fail.

Have you tried running tools/testing/selftests/pci_endpoint/pci_endpoint_test ?

Kind regards,
Niklas

#8 lore raw

Re: [PATCH v2 2/3] PCI: tegra194: Reset BARs when running in PCIe endpoint mode

Quoted 39 lines · Niklas Cassel
Quoted 7 lines · Manikanta Maddireddy

Hi Niklas,

Tegra PCIe exposes only DMA register over BAR4, not iATU. So, the issue described in this commit message is not applicable. This patch is disabling BAR2 and BAR4, after enumeration I see only BAR0. I think we should revert this patch.
Please share your inputs on this.

If you look at this commit, it only disables all BARs by default, which brings the tegra driver in-line with all other DWC based endpoint drivers: dra7xx, imx6, layerscape-ep, artpec6, dw-rockchip, qcom-ep, rcar-gen4, and uniphier-ep.

A PCI endpoint function (EPF) driver will still be able to enable a BAR that was disabled in .init().
However, an EPF driver will not be able to use/enable a reserved BAR.

Look at e.g. the code in pci-epf-test. It will not allocate backing memory for a BAR that is reserved, so having a BAR enabled that we have not allocated backing memory for is wrong.

Commit c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194") is the commit that marked all BARs other than BAR0 as reserved, so if you want to test BARs other than BAR0, talk to the author of that commit.

If you revert this patch, tools/testing/selftests/pci_endpoint/pci_endpoint_test will once again fail the consecutive BAR test, so I think it would be wrong to revert this patch.

If it is ATU registers or eDMA registers exposed in BAR4 does not really matter. The end result is that you overwrite eDMA registers that you should not be overwriting when you run the BAR tests. (So BAR4 should absolutely be marked as reserved).

I don't recall, but if you overwrite the eDMA registers, then in addition to the consecutive BAR test failing, most likely the DMA test cases will also fail.

Quoted 7 lines

Have you tried running tools/testing/selftests/pci_endpoint/pci_endpoint_test ?

Kind regards,
Niklas

Hi Niklas,

In Tegra234 PCIe, BAR1 is MSI-X table and BAR2 is DMA registers backed

by PCIe HW RAM and registers. EPF driver shouldn't allocate memory for

these two BARs. This is the reason for marking them as reserved in

Tegra PCIe driver. DMA registers are exposed over BAR2 to allow

PCI client driver in host to transfer data from host to endpoint

using endpoint remote DMA read functionality. BAR test fails on this

because not all register bits are writable. Consider NVMe example

which has RO capability bits at the start of the BAR, it is not correct

to add BAR test on these bits.

I think following fixes are required to address this issue,

1. BAR test in pci_endpoint_test should skip MSI-X table.

2. BAR test in pci_endpoint_test should provide option to

skip this test on known reserved BARs, maybe we can use

pci_endpoint_test_data for this.

3. EPC driver should provide BAR_DISABLED enum to disable

unused BARs.

4. Tegra PCIe driver should disable only BAR_DISABLED bars and

leave BAR_RESERVED untouched.

5. Return NO_BAR for both BAR_DISABLED and BAR_RESERVED in

pci_epc_get_next_free_bar()

Let me know your opinion on this.

#9 lore raw

Re: [PATCH v2 2/3] PCI: tegra194: Reset BARs when running in PCIe endpoint mode

Hello Manikanta,

Quoted 4 lines · Manikanta Maddireddy
Quoted 4 lines · Manikanta Maddireddy
Quoted 3 lines

Hi Niklas,

Tegra PCIe exposes only DMA register over BAR4, not iATU.

Here you claim that DMA registers are exposed in BAR4.

Quoted 4 lines

Hi Niklas,

In Tegra234 PCIe, BAR1 is MSI-X table and BAR2 is DMA registers backed by PCIe HW RAM and registers.

Here you claim that DMA registers are exposed in BAR2. Which one is it?

Quoted 8 lines

EPF driver shouldn't allocate memory for
these two BARs. This is the reason for marking them as reserved in Tegra PCIe driver. DMA registers are exposed over BAR2 to allow PCI client driver in host to transfer data from host to endpoint using endpoint remote DMA read functionality. BAR test fails on this because not all register bits are writable. Consider NVMe example which has RO capability bits at the start of the BAR, it is not correct to add BAR test on these bits.

Have you tried running tools/testing/selftests/pci_endpoint/pci_endpoint_test ?

pci_endpoint_test will run BAR tests against all BARs that are enabled by default, regardless of the BAR being marked as RESERVED or not, see:
https://github.com/torvalds/linux/blob/v6.19/drivers/misc/pci_endpoint_test.c#L1052-L1061

In the case of nvidia,tegra234-pcie-ep, before my commit 42f9c66a6d0c ("PCI: tegra194: Reset BARs when running in PCIe endpoint mode"):
pcie-tegra194.c marked all BARs except BAR0 as reserved. pci_endpoint_test would run tests against BAR0, BAR2, BAR3, BAR4, BAR5 (it would not run against BAR1, because BAR0 is marked as "only_64bit").

After my commit 42f9c66a6d0c ("PCI: tegra194: Reset BARs when running in PCIe endpoint mode"):
pcie-tegra194.c still marks all BARs except BAR0 as reserved (I did not change this).
pci_endpoint_test would run tests only against BAR0.
I.e. the only BAR that is not marked as reserved.

Quoted 2 lines

I think following fixes are required to address this issue,

Could you please define "this issue", because right now I honestly don't see the issue.

To me it seems like you want pci_endpoint_test to run against BARs that are marked as reserved (I assume that Vidya marked them as reserved for a good reason, most likely because all of them map to MMIO registers) and thus you want multiple test cases in pci_endpoint_test to fail instead of being skipped?

Quoted 4 lines

1. BAR test in pci_endpoint_test should skip MSI-X table.
2. BAR test in pci_endpoint_test should provide option to skip this test on known reserved BARs, maybe we can use pci_endpoint_test_data for this.

pci_endpoint_test already skips disabled BARs by default.

They way it works is that you disable all BARs in you EPC driver's init() callback (i.e. what my patch does), pci-epf-test will then allocate backing memory + enable all BARs that are not marked as RESERVED.

Quoted 2 lines

3. EPC driver should provide BAR_DISABLED enum to disable unused BARs.

BAR_RESERVED already means disabled, it just assumes that an EPC driver disables all BARs by default, which is the case for:
pci-dra7xx.c, pci-imx6.c, pci-layerscape-ep.c, pcie-artpec6.c, pcie-designware-plat.c, pcie-dw-rockchip.c, pcie-qcom-ep.c, pcie-rcar-gen4.c, pcie-stm32-ep.c, pcie-uniphier-ep.c.
(All drivers which disables all BARs by default in the init() callback using dw_pcie_ep_reset_bar(). pci-epf-test will later enable all BARs that are not marked as BAR_RESERVED.)

That leaves: pcie-keembay.c, pci-keystone.c, pcie-tegra194.c (before my patch).

For pcie-keembay.c, this is not a problem, because BAR0, BAR2, BAR4 are marked as only_64bit, so pci-epf-test configure these BARs as 64-bit BARs, and thus BAR1, BAR3, and BAR5 will get disabled implicitly.

For pci-keystone.c, this is the only driver that is a bit weird, it marks BAR0 and BAR1 as reserved, but does not disable them in the init() callback. It seems force set BAR0 as a 32-bit BAR in the init() callback.

Thus, for all drivers except for pci-keystone.c, BAR_RESERVED does mean BAR_DISABLED. Feel free to send a patch that renames BAR_RESERVED to BAR_DISABLED.

If you send such a patch, perhaps you also want to modify the PCI endpoint core to call reset_bar() for all BARs marked as BAR_RESERVED/BAR_DISABLED, instead of each EPC driver doing so in the init() callback. I think the main reason why this is not done already is that thare is no reset_bar() op in struct pci_epc_ops epc_ops, there is only clear_bar() which clears an BAR enabled by an EPF driver. (So you would most likely also need to add a .disable_bar() op in struct pci_epc_ops epc_ops.)

Quoted 4 lines

4. Tegra PCIe driver should disable only BAR_DISABLED bars and leave BAR_RESERVED untouched.
5. Return NO_BAR for both BAR_DISABLED and BAR_RESERVED in pci_epc_get_next_free_bar()

A BAR marked as BAR_RESERVED will never be returned by pci_epc_get_next_free_bar(), so this is the case already.

Kind regards,
Niklas

#10 lore raw

Re: [PATCH v2 2/3] PCI: tegra194: Reset BARs when running in PCIe endpoint mode

Quoted 23 lines · Niklas Cassel

BAR_RESERVED already means disabled, it just assumes that an EPC driver disables all BARs by default, which is the case for:
pci-dra7xx.c, pci-imx6.c, pci-layerscape-ep.c, pcie-artpec6.c, pcie-designware-plat.c, pcie-dw-rockchip.c, pcie-qcom-ep.c, pcie-rcar-gen4.c, pcie-stm32-ep.c, pcie-uniphier-ep.c.
(All drivers which disables all BARs by default in the init() callback using dw_pcie_ep_reset_bar(). pci-epf-test will later enable all BARs that are not marked as BAR_RESERVED.)

That leaves: pcie-keembay.c, pci-keystone.c, pcie-tegra194.c (before my patch).

For pcie-keembay.c, this is not a problem, because BAR0, BAR2, BAR4 are marked as only_64bit, so pci-epf-test configure these BARs as 64-bit BARs, and thus BAR1, BAR3, and BAR5 will get disabled implicitly.

For pci-keystone.c, this is the only driver that is a bit weird, it marks BAR0 and BAR1 as reserved, but does not disable them in the init() callback. It seems force set BAR0 as a 32-bit BAR in the init() callback.

Thus, for all drivers except for pci-keystone.c, BAR_RESERVED does mean BAR_DISABLED. Feel free to send a patch that renames BAR_RESERVED to BAR_DISABLED.

Quoted 7 lines

If you send such a patch, perhaps you also want to modify the PCI endpoint core to call reset_bar() for all BARs marked as BAR_RESERVED/BAR_DISABLED, instead of each EPC driver doing so in the init() callback. I think the main reason why this is not done already is that thare is no reset_bar() op in struct pci_epc_ops epc_ops, there is only clear_bar() which clears an BAR enabled by an EPF driver. (So you would most likely also need to add a .disable_bar() op in struct pci_epc_ops epc_ops.)

Aksh (on To:),

since you have a @ti.com email, perhaps you can explain how pci-keystone.c can pass all the pci-epf-test test cases, considering that this is the only driver that has BARs (BAR0 and BAR1) marked as BAR_RESERVED but do not also disable the BARs (using dw_pcie_ep_reset_bar()) in the init() callback.

Or, perhaps the simple answer is that pci-keystone.c does not pass all pci-epf-test test cases?

Kind regards,
Niklas

#11 lore raw

Re: [PATCH v2 2/3] PCI: tegra194: Reset BARs when running in PCIe endpoint mode

+ Kishon

Quoted 38 lines · Niklas Cassel
Quoted 23 lines

BAR_RESERVED already means disabled, it just assumes that an EPC driver disables all BARs by default, which is the case for:
pci-dra7xx.c, pci-imx6.c, pci-layerscape-ep.c, pcie-artpec6.c, pcie-designware-plat.c, pcie-dw-rockchip.c, pcie-qcom-ep.c, pcie-rcar-gen4.c, pcie-stm32-ep.c, pcie-uniphier-ep.c.
(All drivers which disables all BARs by default in the init() callback using dw_pcie_ep_reset_bar(). pci-epf-test will later enable all BARs that are not marked as BAR_RESERVED.)

That leaves: pcie-keembay.c, pci-keystone.c, pcie-tegra194.c (before my patch).

For pcie-keembay.c, this is not a problem, because BAR0, BAR2, BAR4 are marked as only_64bit, so pci-epf-test configure these BARs as 64-bit BARs, and thus BAR1, BAR3, and BAR5 will get disabled implicitly.

For pci-keystone.c, this is the only driver that is a bit weird, it marks BAR0 and BAR1 as reserved, but does not disable them in the init() callback. It seems force set BAR0 as a 32-bit BAR in the init() callback.

Thus, for all drivers except for pci-keystone.c, BAR_RESERVED does mean BAR_DISABLED. Feel free to send a patch that renames BAR_RESERVED to BAR_DISABLED.

Quoted 7 lines

If you send such a patch, perhaps you also want to modify the PCI endpoint core to call reset_bar() for all BARs marked as BAR_RESERVED/BAR_DISABLED, instead of each EPC driver doing so in the init() callback. I think the main reason why this is not done already is that thare is no reset_bar() op in struct pci_epc_ops epc_ops, there is only clear_bar() which clears an BAR enabled by an EPF driver. (So you would most likely also need to add a .disable_bar() op in struct pci_epc_ops epc_ops.)

Aksh (on To:),

since you have a @ti.com email, perhaps you can explain how pci-keystone.c can pass all the pci-epf-test test cases, considering that this is the only driver that has BARs (BAR0 and BAR1) marked as BAR_RESERVED but do not also disable the BARs (using dw_pcie_ep_reset_bar()) in the init() callback.

Quoted 6 lines

Or, perhaps the simple answer is that pci-keystone.c does not pass all pci-epf-test test cases?

Kind regards,
Niklas

Hi Niklas,

I just joined the organization and have no context on why the pci-keystone.c have BAR0 and BAR1 as reserved, without disabling the bars using dw_pcie_ep_reset_bar() in the .init() callback. Because the AM65 do not use any BARs for any purpose like Tegra194 does (ATU registers or eDMA registers exposed in BAR4 for example), there would be no issue if the BAR0 and BAR1 are overwritten.

This was introduced in the driver the time the EP support was added to the driver by Kishon in commit 23284ad677a9 ("PCI: keystone: Add support for PCIe EP in AM654x Platforms"), where no context is provided in the comments or commit message why the BAR0/1 are marked as reserved in the features. Perhaps Kishon can provide a better insight over this.

Regards,
Aksh Garg

Quoted 1 line
#12 lore raw

Re: [PATCH v2 2/3] PCI: tegra194: Reset BARs when running in PCIe endpoint mode

Quoted 17 lines · Aksh Garg
Quoted 7 lines

since you have a @ti.com email, perhaps you can explain how pci-keystone.c can pass all the pci-epf-test test cases, considering that this is the only driver that has BARs (BAR0 and BAR1) marked as BAR_RESERVED but do not also disable the BARs (using dw_pcie_ep_reset_bar()) in the init() callback.

Or, perhaps the simple answer is that pci-keystone.c does not pass all pci-epf-test test cases?

Hi Niklas,

I just joined the organization and have no context on why the pci-keystone.c have BAR0 and BAR1 as reserved, without disabling the bars using dw_pcie_ep_reset_bar() in the .init() callback. Because the AM65 do not use any BARs for any purpose like Tegra194 does (ATU registers or eDMA registers exposed in BAR4 for example), there would be no issue if the BAR0 and BAR1 are overwritten.

Quoted 5 lines

This was introduced in the driver the time the EP support was added to the driver by Kishon in commit 23284ad677a9 ("PCI: keystone: Add support for PCIe EP in AM654x Platforms"), where no context is provided in the comments or commit message why the BAR0/1 are marked as reserved in the features. Perhaps Kishon can provide a better insight over this.

It is extra confusing, since the older driver from TI:
pci-dra7xx.c does have the dw_pcie_ep_reset_bar() calls in init() (git blame shows added by Kishon), so it is a bit surprising that the newer driver (pci-keystone.c) does not.

(And like I explained, currently all DWC drivers except keystone and pcie-keembay.c do have the dw_pcie_ep_reset_bar() calls in init().)

Kind regards,
Niklas

#13 lore raw

Re: [PATCH v2 2/3] PCI: tegra194: Reset BARs when running in PCIe endpoint mode

Quoted 24 lines · Niklas Cassel
Quoted 17 lines · Aksh Garg
Quoted 7 lines

since you have a @ti.com email, perhaps you can explain how pci-keystone.c can pass all the pci-epf-test test cases, considering that this is the only driver that has BARs (BAR0 and BAR1) marked as BAR_RESERVED but do not also disable the BARs (using dw_pcie_ep_reset_bar()) in the init() callback.

Or, perhaps the simple answer is that pci-keystone.c does not pass all pci-epf-test test cases?

Hi Niklas,

I just joined the organization and have no context on why the pci-keystone.c have BAR0 and BAR1 as reserved, without disabling the bars using dw_pcie_ep_reset_bar() in the .init() callback. Because the AM65 do not use any BARs for any purpose like Tegra194 does (ATU registers or eDMA registers exposed in BAR4 for example), there would be no issue if the BAR0 and BAR1 are overwritten.

Quoted 5 lines

This was introduced in the driver the time the EP support was added to the driver by Kishon in commit 23284ad677a9 ("PCI: keystone: Add support for PCIe EP in AM654x Platforms"), where no context is provided in the comments or commit message why the BAR0/1 are marked as reserved in the features. Perhaps Kishon can provide a better insight over this.

Quoted 8 lines

It is extra confusing, since the older driver from TI:
pci-dra7xx.c does have the dw_pcie_ep_reset_bar() calls in init() (git blame shows added by Kishon), so it is a bit surprising that the newer driver (pci-keystone.c) does not.

(And like I explained, currently all DWC drivers except keystone and pcie-keembay.c do have the dw_pcie_ep_reset_bar() calls in init().)

Yes, true. I tried to backtrace why this is so for pci-keystone.c, but couldn't find anything on this.

Quoted 3 lines

Kind regards,
Niklas

A message that is not in the archive (sent off-list or not yet received): [email protected]

#15 lore raw

Re: [PATCH v2 2/3] PCI: tegra194: Reset BARs when running in PCIe endpoint mode

Quoted 22 lines · Manikanta Maddireddy
Quoted 8 lines

For pci-keystone.c, this is the only driver that is a bit weird, it marks BAR0 and BAR1 as reserved, but does not disable them in the init() callback. It seems force set BAR0 as a 32-bit BAR in the init() callback.

Thus, for all drivers except for pci-keystone.c, BAR_RESERVED does mean BAR_DISABLED. Feel free to send a patch that renames BAR_RESERVED to BAR_DISABLED.

Quoted 8 lines

If you send such a patch, perhaps you also want to modify the PCI endpoint core to call reset_bar() for all BARs marked as BAR_RESERVED/BAR_DISABLED, instead of each EPC driver doing so in the init() callback. I think the main reason why this is not done already is that thare is no reset_bar() op in struct pci_epc_ops epc_ops, there is only clear_bar() which clears an BAR enabled by an EPF driver. (So you would most likely also need to add a .disable_bar() op in struct pci_epc_ops epc_ops.)

pci-epc.h defined

 * @BAR_RESERVED: The BAR should not be touched by an EPF driver.

I believe you are interpreting this as unused BAR?

Quoted 7 lines

In Tegra PCIe, BAR2 and BAR4 are backed by PCIe HW memory which

shouldn't be touched by EPF, but should be kept enabled.

This support is not available. I suggested to add BAR_DISABLED

for unused and use BAR_RESERVED for bars like above.

I understand what you want. You want to have a BAR_RESERVED and a BAR_DISABLED.

Sounds like a nice feature. Feel free to add that.

But like I mentioned in my reply, for all existing drivers, except for pci-keystone.c, in practice BAR_RESERVED actually means BAR_DISABLED. (Since all drivers except for pci-keystone.c call reset_bar() in init(), and pci-epf-test will not enable BARs marked as BAR_RESERVED).

So if you add a BAR_DISABLED, make sure that you convert all existing uses of BAR_RESERVED (except for pci-keystone.c) to BAR_DISABLED.

pci-keystone.c and pcie-tegra194.c can then be the only drivers that have BARs marked as BAR_RESERVED (all other drivers would use BAR_DISABLED).

Please just make sure that you don't regress the amount of currently passing pci_endpoint_test test cases that are passing for pcie-tegra194.c. (Which would be the case if you revert the patch in $subject without first adding your proposed new BAR_DISABLED, such that we can have a distinction between BAR_DISABLED and BAR_RESERVED.)

Kind regards,
Niklas

#16 lore raw

Re: [PATCH v2 2/3] PCI: tegra194: Reset BARs when running in PCIe endpoint mode

In reply to Niklas Cassel

Hi Niklas,

Tegra PCIe controller exposes only DMA registers over BAR4, iATU is never

exposed over BAR. So, this bug is not applicable for Tegra PCIe.

However, because of this change, BAR2 & BAR4 is never enabled and

I don't see BAR2 and BAR4 when host enumerates the Endpoint controller.

I think we should revert this patch, let me know your opinion on this.

Thanks,

Manikanta

Quoted 61 lines · Niklas Cassel

Tegra already defines all BARs expect for BAR0 as BAR_RESERVED. This is sufficient for pci-epf-test to not allocate backing memory and to not call set_bar() for those BARs. However, marking a BAR as BAR_RESERVED does not mean that the BAR get disabled.

The host side driver, pci_endpoint_test, simply does an ioremap for all enabled BARs, and will run tests against all enabled BARs. (I.e. it will run tests also against the BARs marked as BAR_RESERVED.)

After running the BARs tests (which will write to all enabled BARs), the inbound address translation is broken.
This is because the tegra controller exposes the ATU Port Logic Structure in BAR4. So when BAR4 is written, the inbound address translation settings get overwritten.

To avoid this, implement the dw_pcie_ep_ops .init() callback and start off by disabling all BARs (pci-epf-test will later enable/configure BARs that are not defined as BAR_RESERVED).

This matches the behavior of other PCIe endpoint drivers:
dra7xx, imx6, layerscape-ep, artpec6, dw-rockchip, qcom-ep, rcar-gen4, and uniphier-ep.

With this, the PCI endpoint kselftest test case CONSECUTIVE_BAR_TEST (which was specifically made to detect address translation issues) passes.

Fixes c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194")
---
  drivers/pci/controller/dwc/pcie-tegra194.c | 10 ++++++++++
  1 file changed, 10 insertions(+)
drivers/pci/controller/dwc/pcie-tegra194.c +10 -0
index 63d310e5335f4..7eb48cc13648e 100644
@@ -1955,6 +1955,15 @@ static irqreturn_t tegra_pcie_ep_pex_rst_irq(int irq, void *arg)
  	return IRQ_HANDLED;
  }
 
+static void tegra_pcie_ep_init(struct dw_pcie_ep *ep)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	enum pci_barno bar;
+
+	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
+		dw_pcie_ep_reset_bar(pci, bar);
+};
+
  static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq)
  {
  	/* Tegra194 supports only INTA */
@@ -2030,6 +2039,7 @@ tegra_pcie_ep_get_features(struct dw_pcie_ep *ep)
  }
 
  static const struct dw_pcie_ep_ops pcie_ep_ops = {
+	.init = tegra_pcie_ep_init,
  	.raise_irq = tegra_pcie_ep_raise_irq,
  	.get_features = tegra_pcie_ep_get_features,
  };
#17 lore raw

PATCH v2 3/3 PCI: tegra194: Handle errors in BPMP response

In reply to Niklas Cassel

From: Vidya Sagar <[email protected]>

The return value from tegra_bpmp_transfer() indicates the success or failure of the IPC transaction with BPMP. If the transaction succeeded, we also need to check the actual command's result code.

If we don't have error handling for tegra_bpmp_transfer(), we will set the pcie->ep_state to EP_STATE_ENABLED (even though the tegra_bpmp_transfer() command failed). Thus, the pcie->ep_state will get out of sync with reality, and any further PERST# assert + deassert will be a no-op (will not trigger the hardware initialization sequence).

This is because pex_ep_event_pex_rst_deassert() checks the current pcie->ep_state, and does nothing if the current state is already EP_STATE_ENABLED.

Thus, it is important to have error handling for tegra_bpmp_transfer(), such that the pcie->ep_state can not get out of sync with reality, so that we will try to initialize the hardware not only during the first PERST# assert + deassert, but also during any succeeding PERST# assert + deassert.

One example where this fix is needed is when using a rock5b as host. During the initial PERST# assert + deassert (triggered by the bootloader on the rock5b) pex_ep_event_pex_rst_deassert() will get called, but for some unknown reason, the tegra_bpmp_transfer() call to initialize the PHY fails. Once Linux has been loaded on the rock5b, the PCIe driver will once again assert + deassert PERST#. However, without tegra_bpmp_transfer() error handling, this second PERST# assert + deassert will not trigger the hardware initialization sequence.

With tegra_bpmp_transfer() error handling, the second PERST# assert + deassert will once again trigger the hardware to be initialized and this time the tegra_bpmp_transfer() succeeds.

Fixes c57247f940e8 ("PCI: tegra: Add support for PCIe endpoint mode in Tegra194")
[cassel: improve commit log]
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)
drivers/pci/controller/dwc/pcie-tegra194.c +16 -2
index 7eb48cc13648e..c4265b3f72048 100644
@@ -1223,6 +1223,7 @@ static int tegra_pcie_bpmp_set_ctrl_state(struct tegra_pcie_dw *pcie,
 	struct mrq_uphy_response resp;
 	struct tegra_bpmp_message msg;
 	struct mrq_uphy_request req;
+	int err;
 
 	/*
 	 * Controller-5 doesn't need to have its state set by BPMP-FW in
@@ -1245,7 +1246,13 @@ static int tegra_pcie_bpmp_set_ctrl_state(struct tegra_pcie_dw *pcie,
 	msg.rx.data = &resp;
 	msg.rx.size = sizeof(resp);
 
-	return tegra_bpmp_transfer(pcie->bpmp, &msg);
+	err = tegra_bpmp_transfer(pcie->bpmp, &msg);
+	if (err)
+		return err;
+	if (msg.rx.ret)
+		return -EINVAL;
+
+	return 0;
 }
 
 static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie,
@@ -1254,6 +1261,7 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie,
 	struct mrq_uphy_response resp;
 	struct tegra_bpmp_message msg;
 	struct mrq_uphy_request req;
+	int err;
 
 	memset(&req, 0, sizeof(req));
 	memset(&resp, 0, sizeof(resp));
@@ -1273,7 +1281,13 @@ static int tegra_pcie_bpmp_set_pll_state(struct tegra_pcie_dw *pcie,
 	msg.rx.data = &resp;
 	msg.rx.size = sizeof(resp);
 
-	return tegra_bpmp_transfer(pcie->bpmp, &msg);
+	err = tegra_bpmp_transfer(pcie->bpmp, &msg);
+	if (err)
+		return err;
+	if (msg.rx.ret)
+		return -EINVAL;
+
+	return 0;
 }
 
 static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie)
Signature · 1 line
2.51.0
maintainer Applied
#18 lore raw
In reply to Niklas Cassel
Quoted 5 lines · Niklas Cassel

Shin'ichiro and I have recently been trying to get the Jetson to run the PCI endpoint kselftests on a tegra based board. These patches ensure that the BAR test cases and MSI test cases pass. The MSI-X test cases still fail.

Quoted 7 lines

Dependency
==========
"PCI: tegra194: Fix broken tegra_pcie_ep_raise_msi_irq()" requires commit 27fce9e8c6f0 ("PCI: endpoint: Drop superfluous pci_epc_features initialization") which is currently queued on branch pci/endpoint.

[...]

Applied, thanks!

[1/3] PCI: tegra194: Fix broken tegra_pcie_ep_raise_msi_irq()

      commit: b640d42a6ac9ba01abe65ec34f7c73aaf6758ab8
[2/3] PCI: tegra194: Reset BARs when running in PCIe endpoint mode
      commit: 308c6d4cf3ef9725054c431b1b8e3db0dc38de34
[3/3] PCI: tegra194: Handle errors in BPMP response
      commit: b308dcd8b385f93c7d210be3a48aaa590739ba17

Note: I've splitted the patch 1 into two to keep the bug fix separate:
https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git/commit/?h=endpoint&id=82f1cc171ce95544c024837c20a54d1954a67a76

- Mani

Best regards,

Signature · 1 line
Manivannan Sadhasivam <[email protected]>