* [PATCH v3 0/2] PCI: dw-rockchip: hide broken ATS cap in EP-mode
@ 2025-03-10 9:48 Niklas Cassel
2025-03-10 9:48 ` [PATCH v3 1/2] PCI: dwc: ep: Add dw_pcie_ep_hide_ext_capability() Niklas Cassel
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Niklas Cassel @ 2025-03-10 9:48 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Heiko Stuebner
Cc: Shawn Lin, Damien Le Moal, Niklas Cassel, linux-pci,
linux-arm-kernel, linux-rockchip
Hello there,
Address Translation Services (ATS) is broken on rk3588 when running the
PCIe controller in Endpoint Mode.
This causes IOTLB invalidation timeout errors on the host side when using
and rk3588 in Endpoint Mode, and you are unable to run pci_endpoint_test.
Solve this by hiding the ATS capability.
With this, we do not get any IOTLB invalidation timeouts, and we can run
pci_endpoint_test successfully.
Changes since v2:
-Added missing EXPORT_SYMBOL_GPL().
Niklas Cassel (2):
PCI: dwc: ep: Add dw_pcie_ep_hide_ext_capability()
PCI: dw-rockchip: Hide broken ATS capability
.../pci/controller/dwc/pcie-designware-ep.c | 39 +++++++++++++++++++
drivers/pci/controller/dwc/pcie-designware.h | 7 ++++
drivers/pci/controller/dwc/pcie-dw-rockchip.c | 27 +++++++++++++
3 files changed, 73 insertions(+)
--
2.48.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 1/2] PCI: dwc: ep: Add dw_pcie_ep_hide_ext_capability()
2025-03-10 9:48 [PATCH v3 0/2] PCI: dw-rockchip: hide broken ATS cap in EP-mode Niklas Cassel
@ 2025-03-10 9:48 ` Niklas Cassel
2025-03-10 9:48 ` [PATCH v3 2/2] PCI: dw-rockchip: Hide broken ATS capability Niklas Cassel
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Niklas Cassel @ 2025-03-10 9:48 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas
Cc: Shawn Lin, Damien Le Moal, Niklas Cassel, linux-pci
Add dw_pcie_ep_hide_ext_capability() which can be used by an endpoint
controller driver to hide a capability.
This can be useful to hide a capability that is buggy, such that the
host side does not try to enable the buggy capability.
Suggested-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Niklas Cassel <cassel@kernel.org>
---
.../pci/controller/dwc/pcie-designware-ep.c | 39 +++++++++++++++++++
drivers/pci/controller/dwc/pcie-designware.h | 7 ++++
2 files changed, 46 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index a8568808b5e5..9768703a37b6 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -102,6 +102,45 @@ static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
}
+/**
+ * dw_pcie_ep_hide_ext_capability - Hide a capability from the linked list
+ * @pci: DWC PCI device
+ * @prev_cap: Capability preceding the capability that should be hidden
+ * @cap: Capability that should be hidden
+ *
+ * Return: 0 if success, errno otherwise.
+ */
+int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, u8 prev_cap, u8 cap)
+{
+ u16 prev_cap_offset, cap_offset;
+ u32 prev_cap_header, cap_header;
+
+ prev_cap_offset = dw_pcie_find_ext_capability(pci, prev_cap);
+ if (!prev_cap_offset)
+ return -EINVAL;
+
+ prev_cap_header = dw_pcie_readl_dbi(pci, prev_cap_offset);
+ cap_offset = PCI_EXT_CAP_NEXT(prev_cap_header);
+ cap_header = dw_pcie_readl_dbi(pci, cap_offset);
+
+ /* cap must immediately follow prev_cap. */
+ if (PCI_EXT_CAP_ID(cap_header) != cap)
+ return -EINVAL;
+
+ /* Clear next ptr. */
+ prev_cap_header &= ~GENMASK(31, 20);
+
+ /* Set next ptr to next ptr of cap. */
+ prev_cap_header |= cap_header & GENMASK(31, 20);
+
+ dw_pcie_dbi_ro_wr_en(pci);
+ dw_pcie_writel_dbi(pci, prev_cap_offset, prev_cap_header);
+ dw_pcie_dbi_ro_wr_dis(pci);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dw_pcie_ep_hide_ext_capability);
+
static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
struct pci_epf_header *hdr)
{
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index a03b3799fb27..2d1de81d47b6 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -781,6 +781,7 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
u16 interrupt_num);
void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar);
+int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci, u8 prev_cap, u8 cap);
struct dw_pcie_ep_func *
dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no);
#else
@@ -838,6 +839,12 @@ static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
{
}
+static inline int dw_pcie_ep_hide_ext_capability(struct dw_pcie *pci,
+ u8 prev_cap, u8 cap)
+{
+ return 0;
+}
+
static inline struct dw_pcie_ep_func *
dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
{
--
2.48.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 2/2] PCI: dw-rockchip: Hide broken ATS capability
2025-03-10 9:48 [PATCH v3 0/2] PCI: dw-rockchip: hide broken ATS cap in EP-mode Niklas Cassel
2025-03-10 9:48 ` [PATCH v3 1/2] PCI: dwc: ep: Add dw_pcie_ep_hide_ext_capability() Niklas Cassel
@ 2025-03-10 9:48 ` Niklas Cassel
2025-03-11 17:39 ` [PATCH v3 0/2] PCI: dw-rockchip: hide broken ATS cap in EP-mode Krzysztof Wilczyński
2025-03-14 11:52 ` Manivannan Sadhasivam
3 siblings, 0 replies; 5+ messages in thread
From: Niklas Cassel @ 2025-03-10 9:48 UTC (permalink / raw)
To: Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, Heiko Stuebner
Cc: Shawn Lin, Damien Le Moal, Niklas Cassel, linux-pci,
linux-arm-kernel, linux-rockchip
When running the rk3588 in endpoint mode, with an Intel host with IOMMU
enabled, the host side prints:
DMAR: VT-d detected Invalidation Time-out Error: SID 0
When running the rk3588 in endpoint mode, with an AMD host with IOMMU
enabled, the host side prints:
iommu ivhd0: AMD-Vi: Event logged [IOTLB_INV_TIMEOUT device=63:00.0 address=0x42b5b01a0]
Rockchip has confirmed that the ATS support for rk3588 only works when
running the PCIe controller in RC mode [0].
Usually, to handle these issues, we add a quirk for the PCI vendor and
device ID in drivers/pci/quirks.c with quirk_no_ats(). That is because
we cannot usually modify the capabilities on the EP side.
In this case, we can modify the capabilities on the EP side. Thus, hide the
broken ATS capability on rk3588 when running in EP mode. That way,
we don't need any quirk on the host side, and we see no errors on the host
side, and we can run pci_endpoint_test successfully, with the IOMMU
enabled on the host side.
[0] https://lore.kernel.org/linux-pci/93cdce39-1ae6-4939-a3fc-db10be7564e5@rock-chips.com/
Acked-by: Shawn Lin <shawn.lin@rock-chips.com>
Signed-off-by: Niklas Cassel <cassel@kernel.org>
---
drivers/pci/controller/dwc/pcie-dw-rockchip.c | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 836ea10eafbb..bc4339252a03 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -242,6 +242,32 @@ static const struct dw_pcie_host_ops rockchip_pcie_host_ops = {
.init = rockchip_pcie_host_init,
};
+/*
+ * ATS does not work on rk3588 when running in EP mode.
+ * After a host has enabled ATS on the EP side, it will send an IOTLB
+ * invalidation request to the EP side. The rk3588 will never send a completion
+ * back and eventually the host will print an IOTLB_INV_TIMEOUT error, and the
+ * EP will not be operational. If we hide the ATS cap, things work as expected.
+ */
+static void rockchip_pcie_ep_hide_broken_ats_cap_rk3588(struct dw_pcie_ep *ep)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ struct device *dev = pci->dev;
+
+ /* Only hide the ATS cap for rk3588 running in EP mode */
+ if (!of_device_is_compatible(dev->of_node, "rockchip,rk3588-pcie-ep"))
+ return;
+
+ if (dw_pcie_ep_hide_ext_capability(pci, PCI_EXT_CAP_ID_SECPCI,
+ PCI_EXT_CAP_ID_ATS))
+ dev_err(dev, "failed to hide ATS cap\n");
+}
+
+static void rockchip_pcie_ep_pre_init(struct dw_pcie_ep *ep)
+{
+ rockchip_pcie_ep_hide_broken_ats_cap_rk3588(ep);
+}
+
static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
@@ -314,6 +340,7 @@ rockchip_pcie_get_features(struct dw_pcie_ep *ep)
static const struct dw_pcie_ep_ops rockchip_pcie_ep_ops = {
.init = rockchip_pcie_ep_init,
+ .pre_init = rockchip_pcie_ep_pre_init,
.raise_irq = rockchip_pcie_raise_irq,
.get_features = rockchip_pcie_get_features,
};
--
2.48.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v3 0/2] PCI: dw-rockchip: hide broken ATS cap in EP-mode
2025-03-10 9:48 [PATCH v3 0/2] PCI: dw-rockchip: hide broken ATS cap in EP-mode Niklas Cassel
2025-03-10 9:48 ` [PATCH v3 1/2] PCI: dwc: ep: Add dw_pcie_ep_hide_ext_capability() Niklas Cassel
2025-03-10 9:48 ` [PATCH v3 2/2] PCI: dw-rockchip: Hide broken ATS capability Niklas Cassel
@ 2025-03-11 17:39 ` Krzysztof Wilczyński
2025-03-14 11:52 ` Manivannan Sadhasivam
3 siblings, 0 replies; 5+ messages in thread
From: Krzysztof Wilczyński @ 2025-03-11 17:39 UTC (permalink / raw)
To: Niklas Cassel
Cc: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi, Rob Herring,
Bjorn Helgaas, Heiko Stuebner, Shawn Lin, Damien Le Moal,
linux-pci, linux-arm-kernel, linux-rockchip
Hello,
> Hello there,
>
> Address Translation Services (ATS) is broken on rk3588 when running the
> PCIe controller in Endpoint Mode.
>
> This causes IOTLB invalidation timeout errors on the host side when using
> and rk3588 in Endpoint Mode, and you are unable to run pci_endpoint_test.
>
> Solve this by hiding the ATS capability.
> With this, we do not get any IOTLB invalidation timeouts, and we can run
> pci_endpoint_test successfully.
Applied to controller/dwc, thank you!
Krzysztof
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3 0/2] PCI: dw-rockchip: hide broken ATS cap in EP-mode
2025-03-10 9:48 [PATCH v3 0/2] PCI: dw-rockchip: hide broken ATS cap in EP-mode Niklas Cassel
` (2 preceding siblings ...)
2025-03-11 17:39 ` [PATCH v3 0/2] PCI: dw-rockchip: hide broken ATS cap in EP-mode Krzysztof Wilczyński
@ 2025-03-14 11:52 ` Manivannan Sadhasivam
3 siblings, 0 replies; 5+ messages in thread
From: Manivannan Sadhasivam @ 2025-03-14 11:52 UTC (permalink / raw)
To: Niklas Cassel
Cc: Jingoo Han, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Bjorn Helgaas, Heiko Stuebner, Shawn Lin,
Damien Le Moal, linux-pci, linux-arm-kernel, linux-rockchip
On Mon, Mar 10, 2025 at 10:48:26AM +0100, Niklas Cassel wrote:
> Hello there,
>
> Address Translation Services (ATS) is broken on rk3588 when running the
> PCIe controller in Endpoint Mode.
>
> This causes IOTLB invalidation timeout errors on the host side when using
> and rk3588 in Endpoint Mode, and you are unable to run pci_endpoint_test.
>
> Solve this by hiding the ATS capability.
> With this, we do not get any IOTLB invalidation timeouts, and we can run
> pci_endpoint_test successfully.
>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
- Mani
>
> Changes since v2:
> -Added missing EXPORT_SYMBOL_GPL().
>
>
> Niklas Cassel (2):
> PCI: dwc: ep: Add dw_pcie_ep_hide_ext_capability()
> PCI: dw-rockchip: Hide broken ATS capability
>
> .../pci/controller/dwc/pcie-designware-ep.c | 39 +++++++++++++++++++
> drivers/pci/controller/dwc/pcie-designware.h | 7 ++++
> drivers/pci/controller/dwc/pcie-dw-rockchip.c | 27 +++++++++++++
> 3 files changed, 73 insertions(+)
>
> --
> 2.48.1
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-03-14 11:52 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-10 9:48 [PATCH v3 0/2] PCI: dw-rockchip: hide broken ATS cap in EP-mode Niklas Cassel
2025-03-10 9:48 ` [PATCH v3 1/2] PCI: dwc: ep: Add dw_pcie_ep_hide_ext_capability() Niklas Cassel
2025-03-10 9:48 ` [PATCH v3 2/2] PCI: dw-rockchip: Hide broken ATS capability Niklas Cassel
2025-03-11 17:39 ` [PATCH v3 0/2] PCI: dw-rockchip: hide broken ATS cap in EP-mode Krzysztof Wilczyński
2025-03-14 11:52 ` Manivannan Sadhasivam
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox