Skip to content

Commit 1f5a69f

Browse files
floatiouskwilczynski
authored andcommitted
PCI: dw-rockchip: Hide broken ATS capability for RK3588 running in EP mode
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 Root Complex (RC) mode, see: https://lore.kernel.org/linux-pci/[email protected] 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. Acked-by: Shawn Lin <[email protected]> Signed-off-by: Niklas Cassel <[email protected]> [kwilczynski: commit log, tidy up code comments and error message] Signed-off-by: Krzysztof Wilczyński <[email protected]> Reviewed-by: Manivannan Sadhasivam <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent e3d6957 commit 1f5a69f

File tree

1 file changed

+29
-0
lines changed

1 file changed

+29
-0
lines changed

drivers/pci/controller/dwc/pcie-dw-rockchip.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,34 @@ static const struct dw_pcie_host_ops rockchip_pcie_host_ops = {
240240
.init = rockchip_pcie_host_init,
241241
};
242242

243+
/*
244+
* ATS does not work on RK3588 when running in EP mode.
245+
*
246+
* After the host has enabled ATS on the EP side, it will send an IOTLB
247+
* invalidation request to the EP side. However, the RK3588 will never send
248+
* a completion back and eventually the host will print an IOTLB_INV_TIMEOUT
249+
* error, and the EP will not be operational. If we hide the ATS capability,
250+
* things work as expected.
251+
*/
252+
static void rockchip_pcie_ep_hide_broken_ats_cap_rk3588(struct dw_pcie_ep *ep)
253+
{
254+
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
255+
struct device *dev = pci->dev;
256+
257+
/* Only hide the ATS capability for RK3588 running in EP mode. */
258+
if (!of_device_is_compatible(dev->of_node, "rockchip,rk3588-pcie-ep"))
259+
return;
260+
261+
if (dw_pcie_ep_hide_ext_capability(pci, PCI_EXT_CAP_ID_SECPCI,
262+
PCI_EXT_CAP_ID_ATS))
263+
dev_err(dev, "failed to hide ATS capability\n");
264+
}
265+
266+
static void rockchip_pcie_ep_pre_init(struct dw_pcie_ep *ep)
267+
{
268+
rockchip_pcie_ep_hide_broken_ats_cap_rk3588(ep);
269+
}
270+
243271
static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep)
244272
{
245273
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
@@ -312,6 +340,7 @@ rockchip_pcie_get_features(struct dw_pcie_ep *ep)
312340

313341
static const struct dw_pcie_ep_ops rockchip_pcie_ep_ops = {
314342
.init = rockchip_pcie_ep_init,
343+
.pre_init = rockchip_pcie_ep_pre_init,
315344
.raise_irq = rockchip_pcie_raise_irq,
316345
.get_features = rockchip_pcie_get_features,
317346
};

0 commit comments

Comments
 (0)