Skip to content

Commit 257523d

Browse files
mukeshojha-linuxgouravk-qualcomm
authored andcommitted
FROMLIST: media: iris: Enable Secure PAS support with IOMMU managed by Linux
Most Qualcomm platforms feature a inhouse hypervisor (such as Gunyah or QHEE), which typically handles IOMMU configuration. This includes mapping memory regions and device memory resources for remote processors by intercepting qcom_scm_pas_auth_and_reset() calls. These mappings are later removed during teardown. Additionally, SHM bridge setup is required to enable memory protection for both remoteproc metadata and its memory regions. When the hypervisor is absent, the operating system must perform these configurations instead. Support for handling IOMMU and SHM setup in the absence of a hypervisor is now in place. Extend the Iris driver to enable this functionality on platforms where IOMMU is managed by Linux (i.e., non-Gunyah, non-QHEE). Additionally, the Iris driver must map the firmware and its required resources to the firmware SID, which is now specified via the device tree. Link: https://lore.kernel.org/lkml/20250819165447.4149674-12-mukesh.ojha@oss.qualcomm.com/ Signed-off-by: Vikash Garodia <vikash.garodia@oss.qualcomm.com> Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
1 parent f7beaa7 commit 257523d

4 files changed

Lines changed: 134 additions & 11 deletions

File tree

drivers/media/platform/qcom/iris/iris_core.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ void iris_core_deinit(struct iris_core *core)
1818
if (core->state != IRIS_CORE_DEINIT) {
1919
iris_fw_unload(core);
2020
iris_vpu_power_off(core);
21+
iris_fw_deinit(core);
2122
iris_hfi_queues_deinit(core);
2223
core->state = IRIS_CORE_DEINIT;
2324
}
@@ -67,10 +68,14 @@ int iris_core_init(struct iris_core *core)
6768
if (ret)
6869
goto error_queue_deinit;
6970

70-
ret = iris_fw_load(core);
71+
ret = iris_fw_init(core);
7172
if (ret)
7273
goto error_power_off;
7374

75+
ret = iris_fw_load(core);
76+
if (ret)
77+
goto error_firmware_deinit;
78+
7479
ret = iris_vpu_boot_firmware(core);
7580
if (ret)
7681
goto error_unload_fw;
@@ -85,6 +90,8 @@ int iris_core_init(struct iris_core *core)
8590

8691
error_unload_fw:
8792
iris_fw_unload(core);
93+
error_firmware_deinit:
94+
iris_fw_deinit(core);
8895
error_power_off:
8996
iris_vpu_power_off(core);
9097
error_queue_deinit:

drivers/media/platform/qcom/iris/iris_core.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ struct iris_core {
8282
struct v4l2_device v4l2_dev;
8383
struct video_device *vdev_dec;
8484
struct video_device *vdev_enc;
85+
struct video_firmware {
86+
struct device *dev;
87+
struct qcom_scm_pas_context *ctx;
88+
struct iommu_domain *iommu_domain;
89+
} fw;
8590
const struct v4l2_file_operations *iris_v4l2_file_ops;
8691
const struct v4l2_ioctl_ops *iris_v4l2_ioctl_ops_dec;
8792
const struct v4l2_ioctl_ops *iris_v4l2_ioctl_ops_enc;

drivers/media/platform/qcom/iris/iris_firmware.c

Lines changed: 119 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
44
*/
55

6+
#include <linux/device.h>
67
#include <linux/firmware.h>
78
#include <linux/firmware/qcom/qcom_scm.h>
9+
#include <linux/iommu.h>
10+
#include <linux/of.h>
811
#include <linux/of_address.h>
12+
#include <linux/of_device.h>
913
#include <linux/of_reserved_mem.h>
14+
#include <linux/platform_device.h>
1015
#include <linux/soc/qcom/mdt_loader.h>
1116

1217
#include "iris_core.h"
@@ -17,6 +22,7 @@
1722
static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
1823
{
1924
u32 pas_id = core->iris_platform_data->pas_id;
25+
struct qcom_scm_pas_context *ctx;
2026
const struct firmware *firmware = NULL;
2127
struct device *dev = core->dev;
2228
struct reserved_mem *rmem;
@@ -42,6 +48,14 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
4248
mem_phys = rmem->base;
4349
res_size = rmem->size;
4450

51+
dev = core->fw.dev ? : core->dev;
52+
53+
ctx = devm_qcom_scm_pas_context_alloc(dev, pas_id, mem_phys, res_size);
54+
if (!ctx)
55+
return -ENOMEM;
56+
57+
ctx->use_tzmem = core->fw.dev;
58+
4559
ret = request_firmware(&firmware, fw_name, dev);
4660
if (ret)
4761
return ret;
@@ -58,9 +72,29 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name)
5872
goto err_release_fw;
5973
}
6074

61-
ret = qcom_mdt_load(dev, firmware, fw_name,
62-
pas_id, mem_virt, mem_phys, res_size, NULL);
75+
ret = qcom_mdt_pas_load(ctx, firmware, fw_name, mem_virt, NULL);
76+
qcom_scm_pas_metadata_release(ctx);
77+
if (ret)
78+
goto err_mem_unmap;
79+
80+
if (core->fw.iommu_domain) {
81+
ret = iommu_map(core->fw.iommu_domain, 0, mem_phys, res_size,
82+
IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL);
83+
if (ret)
84+
goto err_mem_unmap;
85+
}
6386

87+
ret = qcom_scm_pas_prepare_and_auth_reset(ctx);
88+
if (ret)
89+
goto err_iommu_unmap;
90+
91+
core->fw.ctx = ctx;
92+
93+
return ret;
94+
95+
err_iommu_unmap:
96+
iommu_unmap(core->fw.iommu_domain, 0, res_size);
97+
err_mem_unmap:
6498
memunmap(mem_virt);
6599
err_release_fw:
66100
release_firmware(firmware);
@@ -85,19 +119,13 @@ int iris_fw_load(struct iris_core *core)
85119
return -ENOMEM;
86120
}
87121

88-
ret = qcom_scm_pas_auth_and_reset(core->iris_platform_data->pas_id);
89-
if (ret) {
90-
dev_err(core->dev, "auth and reset failed: %d\n", ret);
91-
return ret;
92-
}
93-
94122
ret = qcom_scm_mem_protect_video_var(cp_config->cp_start,
95123
cp_config->cp_size,
96124
cp_config->cp_nonpixel_start,
97125
cp_config->cp_nonpixel_size);
98126
if (ret) {
99127
dev_err(core->dev, "protect memory failed\n");
100-
qcom_scm_pas_shutdown(core->iris_platform_data->pas_id);
128+
iris_fw_unload(core);
101129
return ret;
102130
}
103131

@@ -106,10 +134,91 @@ int iris_fw_load(struct iris_core *core)
106134

107135
int iris_fw_unload(struct iris_core *core)
108136
{
109-
return qcom_scm_pas_shutdown(core->iris_platform_data->pas_id);
137+
struct qcom_scm_pas_context *ctx = core->fw.ctx;
138+
int ret;
139+
140+
if (!ctx)
141+
return -EINVAL;
142+
143+
ret = qcom_scm_pas_shutdown(ctx->pas_id);
144+
if (core->fw.iommu_domain)
145+
iommu_unmap(core->fw.iommu_domain, 0, ctx->mem_size);
146+
147+
core->fw.ctx = NULL;
148+
return ret;
110149
}
111150

112151
int iris_set_hw_state(struct iris_core *core, bool resume)
113152
{
114153
return qcom_scm_set_remote_state(resume, 0);
115154
}
155+
156+
int iris_fw_init(struct iris_core *core)
157+
{
158+
struct platform_device_info info;
159+
struct iommu_domain *iommu_dom;
160+
struct platform_device *pdev;
161+
struct device_node *np;
162+
int ret;
163+
164+
np = of_get_child_by_name(core->dev->of_node, "video-firmware");
165+
if (!np)
166+
return 0;
167+
168+
memset(&info, 0, sizeof(info));
169+
info.fwnode = &np->fwnode;
170+
info.parent = core->dev;
171+
info.name = np->name;
172+
info.dma_mask = DMA_BIT_MASK(32);
173+
174+
pdev = platform_device_register_full(&info);
175+
if (IS_ERR(pdev)) {
176+
of_node_put(np);
177+
return PTR_ERR(pdev);
178+
}
179+
180+
pdev->dev.of_node = np;
181+
182+
ret = of_dma_configure(&pdev->dev, np, true);
183+
if (ret)
184+
goto err_unregister;
185+
186+
core->fw.dev = &pdev->dev;
187+
188+
iommu_dom = iommu_get_domain_for_dev(core->fw.dev);
189+
if (!iommu_dom) {
190+
ret = -EINVAL;
191+
goto err_unset_fw_dev;
192+
}
193+
194+
ret = iommu_attach_device(iommu_dom, core->fw.dev);
195+
if (ret)
196+
goto err_unset_fw_dev;
197+
198+
core->fw.iommu_domain = iommu_dom;
199+
200+
of_node_put(np);
201+
202+
return 0;
203+
204+
err_unset_fw_dev:
205+
core->fw.dev = NULL;
206+
err_unregister:
207+
platform_device_unregister(pdev);
208+
of_node_put(np);
209+
return ret;
210+
}
211+
212+
void iris_fw_deinit(struct iris_core *core)
213+
{
214+
if (!core->fw.dev)
215+
return;
216+
217+
if (core->fw.iommu_domain) {
218+
iommu_detach_device(core->fw.iommu_domain, core->fw.dev);
219+
core->fw.iommu_domain = NULL;
220+
}
221+
222+
platform_device_unregister(to_platform_device(core->fw.dev));
223+
core->fw.dev = NULL;
224+
}

drivers/media/platform/qcom/iris/iris_firmware.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ struct iris_core;
1111
int iris_fw_load(struct iris_core *core);
1212
int iris_fw_unload(struct iris_core *core);
1313
int iris_set_hw_state(struct iris_core *core, bool resume);
14+
int iris_fw_init(struct iris_core *core);
15+
void iris_fw_deinit(struct iris_core *core);
1416

1517
#endif

0 commit comments

Comments
 (0)