From c7b53d4aacc37db2bd9cf341690778f92c208d20 Mon Sep 17 00:00:00 2001 From: Vadim Berezhnoi Date: Mon, 13 Oct 2025 09:44:20 -0700 Subject: [PATCH] snps_accel_rproc: add ARC CBU IOMMU bypass option This change implements the ARC CBU IOMMU bypass mechanism so that the IOVA address assigned by the IOMMU to the system memory are equal to the physical addresses used by the ARC CBU master interface for ARC firmware code and data fetching as well as for the IPC buffer. --- arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 6 ++- drivers/remoteproc/snps_accel/accel_rproc.c | 50 +++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index d0484ad0cdb13e..c243b1d7e7d55d 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -936,6 +936,10 @@ snps,arcsync-cluster-id = <0x01>; /* Disable ARC core booting during Linux kernel booting for debugging purposes */ /* snps,auto-boot; */ + #stream-id-cells = <1>; + /* VPX@0 CBU master interface stream ID's for the SMMU, connected to TBU3: + TBU3 (0b11 << 10) | S_AXI_HP0_FPD Master ID (0b1010 << 6) | AXI ID (0) */ + iommus = <&smmu 0xE80>; }; app_vpx@0 { @@ -970,7 +974,7 @@ /* How many address bits the VPX master can use for DMA to system RAM */ snps,dma-bits = <0x1f>; #stream-id-cells = <0x01>; - /* Stream ID = TBU4 (0b100 << 10) | S_AXI_HP1_FPD Master ID (0b1001 << 6) | AXI ID (0) */ + /* Stream ID = TBU4 (0b100 << 10) | S_AXI_HP1_FPD Master ID (0b1001 << 6) | AXI ID (1) */ iommus = <&smmu 0x12c1>; }; }; diff --git a/drivers/remoteproc/snps_accel/accel_rproc.c b/drivers/remoteproc/snps_accel/accel_rproc.c index cafbe244c28059..de346e30a294ec 100644 --- a/drivers/remoteproc/snps_accel/accel_rproc.c +++ b/drivers/remoteproc/snps_accel/accel_rproc.c @@ -26,6 +26,12 @@ #include #endif +#if IS_ENABLED(CONFIG_IOMMU_API) +#include +/* Enable ARC CBU IOMMU bypass so that IOVA equals physical address */ +#define SNPS_ACCEL_RPROC_CBU_IOMMU_BYPASS +#endif + #include "accel_rproc.h" static int snps_accel_rproc_prepare(struct rproc *rproc) @@ -512,11 +518,55 @@ static int snps_accel_rproc_probe(struct platform_device *pdev) return ret; } +#if IS_ENABLED(CONFIG_IOMMU_API) && defined(SNPS_ACCEL_RPROC_CBU_IOMMU_BYPASS) + struct iommu_group *group = iommu_group_get(dev); + if (group) { + /* Allocate a new domain */ + struct iommu_domain *domain = iommu_domain_alloc(dev->bus); + if (!domain) { + dev_err(dev, "Failed to allocate IOMMU domain\n"); + iommu_group_put(group); + return -ENOMEM; + } + + /* Configure allocated domain as an identity domain */ + domain->type = IOMMU_DOMAIN_IDENTITY; + + /* Attach domain to the device */ + ret = iommu_attach_device(domain, dev); + if (ret) { + dev_err(dev, "Failed to attach device to identity domain, error %d\n", ret); + iommu_domain_free(domain); + iommu_group_put(group); + return ret; + } + dev_dbg(dev, "Attached to IOMMU identity domain\n"); + iommu_group_put(group); + } + else { + dev_dbg(dev, "No IOMMU found for device\n"); + } +#endif + return 0; } static int snps_accel_rproc_remove(struct platform_device *pdev) { +#if IS_ENABLED(CONFIG_IOMMU_API) && defined(SNPS_ACCEL_RPROC_CBU_IOMMU_BYPASS) + struct device *dev = &pdev->dev; + struct iommu_group *group = iommu_group_get(dev); + if (group) { + struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + /* Ensure that only the allocated domain is freed */ + if (domain->type == IOMMU_DOMAIN_IDENTITY) { + iommu_detach_device(domain, dev); + iommu_domain_free(domain); + } + iommu_group_put(group); + } +#endif + return 0; }