lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250928171718.436440-4-charan.kalla@oss.qualcomm.com>
Date: Sun, 28 Sep 2025 22:47:18 +0530
From: Charan Teja Kalla <charan.kalla@....qualcomm.com>
To: joro@...tes.org, will@...nel.org, robin.murphy@....com,
        saravanak@...gle.com, conor+dt@...nel.org, robh@...nel.org,
        mchehab@...nel.org, bod@...nel.org, krzk+dt@...nel.org,
        abhinav.kumar@...ux.dev, vikash.garodia@....qualcomm.com,
        dikshita.agarwal@....qualcomm.com
Cc: linux-media@...r.kernel.org, linux-arm-msm@...r.kernel.org,
        devicetree@...r.kernel.org, linux-kernel@...r.kernel.org,
        iommu@...ts.linux.dev,
        Charan Teja Kalla <charan.kalla@....qualcomm.com>
Subject: [RFC PATCH 3/3] of: implment the 'iommu-map-masked' to represent multi-functional devices

The classical representation used by the platform device to represent
the IOMMU specifier pairs is through 'iommus ='. All the IOMMU specifier
pairs represented will be marked to use the single translation context,
at least is the case for ARM IOMMU.

When each functionality of a multi-functional device required to use
individual address spaces, for arm architecture, it need to be mentioned
as multiple sub-device nodes in the device tree. But since the device
tree is used to just pass on the soc layout to the linux kernel, it
doesn't truly fit.

Introduce the iommu-map-masked property(taking cue from iommu-map
for pci devices) where each functionality is represented(in arm64
architecture language) as:
 iommu-map-masked = <FUNCTION_ID1 &iommu SID1 MASK1>,
		    <FUNCTION_ID2 &iommu SID2 MASK2>;

Iommu client drivers can dynamically create the child devices for each
of these function ID's and call of_dma_configure_id() on these child
devices which sets up the IOMMU configuration.

Signed-off-by: Charan Teja Kalla <charan.kalla@....qualcomm.com>
---
 drivers/iommu/of_iommu.c | 44 ++++++++++++++++++++++++++++++++++++++++
 drivers/of/base.c        | 21 +++++++++++++++++--
 include/linux/of.h       |  8 ++++++--
 3 files changed, 69 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 6b989a62def2..2363de8f2fd6 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -41,12 +41,56 @@ static int of_iommu_xlate(struct device *dev,
 	return ret;
 }
 
+static int of_iommu_map_id(const __be32 *map, u32 id,
+				struct device *dev, void *data)
+{
+	struct device_node *phandle_node;
+	struct of_phandle_args *iommu_spec = data;
+	u32 id_base = be32_to_cpup(map + 0);
+	u32 phandle = be32_to_cpup(map + 1);
+	u32 master_id0 = be32_to_cpup(map + 2);
+	u32 master_id1 = be32_to_cpup(map + 3);
+	int err;
+
+	phandle_node = of_find_node_by_phandle(phandle);
+	if (!phandle_node)
+		return -ENODEV;
+
+	if (id != id_base)
+		return -EAGAIN;
+
+	iommu_spec->np = phandle_node;
+	iommu_spec->args[0] = master_id0;
+	iommu_spec->args[1] = master_id1;
+
+	err = of_iommu_xlate(dev, iommu_spec);
+	of_node_put(iommu_spec->np);
+
+	return err;
+}
+
+static int of_iommu_configure_map_id_and_mask(struct device_node *master_np,
+					      struct device *dev,
+					      const u32 *id)
+{
+	struct of_phandle_args iommu_spec = { .args_count = 2 };
+
+	return of_map_id_and_mask(master_np, *id,
+		 "iommu-map-masked", NULL,
+		 &iommu_spec.np, NULL,
+		 dev, (void *)&iommu_spec, of_iommu_map_id);
+}
+
 static int of_iommu_configure_dev_id(struct device_node *master_np,
 				     struct device *dev,
 				     const u32 *id)
 {
 	struct of_phandle_args iommu_spec = { .args_count = 1 };
 	int err;
+	bool iommu_map_masked = !!of_find_property(master_np, "iommu-map-masked", NULL);
+
+	if (iommu_map_masked)
+		return of_iommu_configure_map_id_and_mask(master_np, dev, id);
 
 	err = of_map_id(master_np, *id, "iommu-map",
 			 "iommu-map-mask", &iommu_spec.np,
diff --git a/drivers/of/base.c b/drivers/of/base.c
index ed2a924d1fab..bb11125e9624 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -2053,6 +2053,9 @@ int of_find_last_cache_level(unsigned int cpu)
  * @map_mask_name: optional property name of the mask to use.
  * @target: optional pointer to a target device node.
  * @id_out: optional pointer to receive the translated ID.
+ * @dev: TODO
+ * @data: optional param that to be passed to fn.
+ * @fn: custom function to get implementation defined platform/device id.
  *
  * Look at the documentation of of_map_id().
  *
@@ -2060,10 +2063,13 @@ int of_find_last_cache_level(unsigned int cpu)
  */
 int of_map_id_and_mask(const struct device_node *np, u32 id,
 	       const char *map_name, const char *map_mask_name,
-	       struct device_node **target, u32 *id_out)
+	       struct device_node **target, u32 *id_out,
+	       struct device *dev, void *data,
+	       int (*fn)(const __be32 *map, u32 id, struct device *dev, void *data))
 {
 	u32 map_mask, masked_id;
 	int map_len;
+	int ret;
 	const __be32 *map = NULL;
 
 	if (!np || !map_name || (!target && !id_out))
@@ -2109,6 +2115,13 @@ int of_map_id_and_mask(const struct device_node *np, u32 id,
 			return -EFAULT;
 		}
 
+		if (fn) {
+			ret = fn(map, id, dev, data);
+			if (ret != -EAGAIN)
+				break;
+			continue;
+		}
+
 		if (masked_id < id_base || masked_id >= id_base + id_len)
 			continue;
 
@@ -2135,12 +2148,16 @@ int of_map_id_and_mask(const struct device_node *np, u32 id,
 		return 0;
 	}
 
+	if (fn)
+		return ret;
+
 	pr_info("%pOF: no %s translation for id 0x%x on %pOF\n", np, map_name,
 		id, target && *target ? *target : NULL);
 
 	/* Bypasses translation */
 	if (id_out)
 		*id_out = id;
+
 	return 0;
 }
 
@@ -2167,6 +2184,6 @@ int of_map_id(const struct device_node *np, u32 id,
 	       struct device_node **target, u32 *id_out)
 {
 	return of_map_id_and_mask(np, id, map_name, map_mask_name,
-			target, id_out);
+			target, id_out, NULL, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(of_map_id);
diff --git a/include/linux/of.h b/include/linux/of.h
index 6fcc46e8b3da..7f3890ab26d5 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -462,7 +462,9 @@ int of_map_id(const struct device_node *np, u32 id,
 
 int of_map_id_and_mask(const struct device_node *np, u32 id,
 		const char *map_name, const char *map_mask_name,
-		struct device_node **target, u32 *id_out);
+		struct device_node **target, u32 *id_out,
+		struct device *dev, void *data,
+		int (*fn)(const __be32 *map, u32 id, struct device *dev, void *data));
 
 phys_addr_t of_dma_get_max_cpu_address(struct device_node *np);
 
@@ -911,7 +913,9 @@ static inline int of_map_id(const struct device_node *np, u32 id,
 
 static inline int of_map_id_and_mask(const struct device_node *np, u32 id,
 		const char *map_name, const char *map_mask_name,
-		struct device_node **target, u32 *id_out)
+		struct device_node **target, u32 *id_out,
+		struct device *dev, void *data,
+		int (*fn)(const __be32 *map, u32 id, void *data))
 {
 	return -EINVAL;
 }
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ