Qualcomm remoteproc drivers such as qcom_q6v5_mss, which do not use the
Peripheral Authentication Service (PAS), always map the MBA region before
use and unmap it once the usage is complete. This behavior was introduced
to avoid issues seen in the past where speculative accesses from the
application processor to the MBA region after it was assigned to the remote
Q6 led to an XPU violation. The issue was mitigated by unmapping the region
before handing control to the remote Q6.

Currently, most Qualcomm SoCs using the PAS driver run either with a
standalone QHEE or the Gunyah hypervisor. In these environments, the
hypervisor unmaps the Q6 memory from HLOS Stage-2 and remaps it into the
Q6 Stage-2 page table. As a result, speculative accesses from HLOS cannot
reach the region even if it remains mapped in HLOS Stage-1; therefore, XPU
violations cannot occur.

However, when the same SoC runs Linux at EL2, Linux itself must perform the
unmapping to avoid such issues. It is still correct to apply this mapping/
unmapping sequence even for SoCs that run under Gunyah, so this behavior
should not be conditional.

Signed-off-by: Mukesh Ojha <[email protected]>
---
Changes in v2: 
https://lore.kernel.org/lkml/[email protected]/
 - Moved map/unmap to pas_load function and further to coredump/minidump 
function.

 drivers/remoteproc/qcom_q6v5_pas.c  | 40 ++++++++++++++++++++---------
 drivers/soc/qcom/mdt_loader.c       | 18 ++++++++++---
 include/linux/soc/qcom/mdt_loader.h |  4 +--
 3 files changed, 44 insertions(+), 18 deletions(-)

diff --git a/drivers/remoteproc/qcom_q6v5_pas.c 
b/drivers/remoteproc/qcom_q6v5_pas.c
index 3bde37ac510c..c8c143fea1b4 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -148,7 +148,16 @@ static void qcom_pas_minidump(struct rproc *rproc)
        if (rproc->dump_conf == RPROC_COREDUMP_DISABLED)
                return;
 
+       pas->mem_region = ioremap_wc(pas->mem_phys, pas->mem_size);
+       if (!pas->mem_region) {
+               dev_err(pas->dev, "unable to map memory region: %pa+%zx\n",
+                       &pas->mem_phys, pas->mem_size);
+               return;
+       }
+
        qcom_minidump(rproc, pas->minidump_id, qcom_pas_segment_dump);
+       iounmap(pas->mem_region);
+       pas->mem_region = NULL;
 }
 
 static int qcom_pas_pds_enable(struct qcom_pas *pas, struct device **pds,
@@ -241,7 +250,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct 
firmware *fw)
                }
 
                ret = qcom_mdt_pas_load(pas->dtb_pas_ctx, pas->dtb_firmware,
-                                       pas->dtb_firmware_name, 
pas->dtb_mem_region,
+                                       pas->dtb_firmware_name,
                                        &pas->dtb_mem_reloc);
                if (ret)
                        goto release_dtb_metadata;
@@ -321,7 +330,7 @@ static int qcom_pas_start(struct rproc *rproc)
        }
 
        ret = qcom_mdt_pas_load(pas->pas_ctx, pas->firmware, rproc->firmware,
-                               pas->mem_region, &pas->mem_reloc);
+                               &pas->mem_reloc);
        if (ret)
                goto release_pas_metadata;
 
@@ -512,6 +521,22 @@ static unsigned long qcom_pas_panic(struct rproc *rproc)
        return qcom_q6v5_panic(&pas->q6v5);
 }
 
+static void qcom_pas_coredump(struct rproc *rproc)
+{
+       struct qcom_pas *pas = rproc->priv;
+
+       pas->mem_region = ioremap_wc(pas->mem_phys, pas->mem_size);
+       if (!pas->mem_region) {
+               dev_err(pas->dev, "unable to map memory region: %pa+%zx\n",
+                       &pas->mem_phys, pas->mem_size);
+               return;
+       }
+
+       rproc_coredump(rproc);
+       iounmap(pas->mem_region);
+       pas->mem_region = NULL;
+}
+
 static const struct rproc_ops qcom_pas_ops = {
        .unprepare = qcom_pas_unprepare,
        .start = qcom_pas_start,
@@ -520,6 +545,7 @@ static const struct rproc_ops qcom_pas_ops = {
        .parse_fw = qcom_pas_parse_firmware,
        .load = qcom_pas_load,
        .panic = qcom_pas_panic,
+       .coredump = qcom_pas_coredump,
 };
 
 static const struct rproc_ops qcom_pas_minidump_ops = {
@@ -637,11 +663,6 @@ static int qcom_pas_alloc_memory_region(struct qcom_pas 
*pas)
 
        pas->mem_phys = pas->mem_reloc = res.start;
        pas->mem_size = resource_size(&res);
-       pas->mem_region = devm_ioremap_resource_wc(pas->dev, &res);
-       if (IS_ERR(pas->mem_region)) {
-               dev_err(pas->dev, "unable to map memory region: %pR\n", &res);
-               return PTR_ERR(pas->mem_region);
-       }
 
        pas->pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->pas_id,
                                                       pas->mem_phys, 
pas->mem_size);
@@ -660,11 +681,6 @@ static int qcom_pas_alloc_memory_region(struct qcom_pas 
*pas)
 
        pas->dtb_mem_phys = pas->dtb_mem_reloc = res.start;
        pas->dtb_mem_size = resource_size(&res);
-       pas->dtb_mem_region = devm_ioremap_resource_wc(pas->dev, &res);
-       if (IS_ERR(pas->dtb_mem_region)) {
-               dev_err(pas->dev, "unable to map dtb memory region: %pR\n", 
&res);
-               return PTR_ERR(pas->dtb_mem_region);
-       }
 
        pas->dtb_pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, 
pas->dtb_pas_id,
                                                           pas->dtb_mem_phys,
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index c004d444d698..33f3543f8e55 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -11,6 +11,7 @@
 #include <linux/device.h>
 #include <linux/elf.h>
 #include <linux/firmware.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/firmware/qcom/qcom_scm.h>
@@ -478,22 +479,31 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load);
  * @ctx:        Pointer to the PAS (Peripheral Authentication Service) context
  * @fw:         Firmware object representing the .mdt file
  * @firmware:   Name of the firmware used to construct segment file names
- * @mem_region: Memory region allocated for loading the firmware
  * @reloc_base: Physical address adjusted after relocation
  *
  * Return: 0 on success or a negative error code on failure.
  */
 int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware 
*fw,
-                     const char *firmware, void *mem_region, phys_addr_t 
*reloc_base)
+                     const char *firmware, phys_addr_t *reloc_base)
 {
+       void *mem_region;
        int ret;
 
        ret = __qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, 
ctx->mem_phys, ctx);
        if (ret)
                return ret;
 
-       return qcom_mdt_load_no_init(ctx->dev, fw, firmware, mem_region, 
ctx->mem_phys,
-                                    ctx->mem_size, reloc_base);
+       mem_region = ioremap_wc(ctx->mem_phys, ctx->mem_size);
+       if (!mem_region) {
+               dev_err(ctx->dev, "unable to map memory region: %pa+%zx\n", 
&ctx->mem_phys,
+                       ctx->mem_size);
+               return -EINVAL;
+       }
+
+       ret = qcom_mdt_load_no_init(ctx->dev, fw, firmware, mem_region, 
ctx->mem_phys,
+                                   ctx->mem_size, reloc_base);
+       iounmap(mem_region);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(qcom_mdt_pas_load);
 
diff --git a/include/linux/soc/qcom/mdt_loader.h 
b/include/linux/soc/qcom/mdt_loader.h
index 82372e0db0a1..7c551b98e182 100644
--- a/include/linux/soc/qcom/mdt_loader.h
+++ b/include/linux/soc/qcom/mdt_loader.h
@@ -21,7 +21,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware 
*fw,
                  phys_addr_t *reloc_base);
 
 int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware 
*fw,
-                     const char *firmware, void *mem_region, phys_addr_t 
*reloc_base);
+                     const char *firmware, phys_addr_t *reloc_base);
 
 int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
                          const char *fw_name, void *mem_region,
@@ -47,7 +47,7 @@ static inline int qcom_mdt_load(struct device *dev, const 
struct firmware *fw,
 
 static inline int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx,
                                    const struct firmware *fw, const char 
*firmware,
-                                   void *mem_region, phys_addr_t *reloc_base)
+                                   phys_addr_t *reloc_base)
 {
        return -ENODEV;
 }
-- 
2.53.0


Reply via email to