Add coredump support for the secure and non-secure OOBMSS carveouts.
Register fixed dump segments at probe time for attached-state recovery.

Signed-off-by: Anvesh Jain P <[email protected]>
---
 drivers/remoteproc/qcom_q6v5_pas.c | 85 ++++++++++++++++++++++++++++++++++----
 1 file changed, 77 insertions(+), 8 deletions(-)

diff --git a/drivers/remoteproc/qcom_q6v5_pas.c 
b/drivers/remoteproc/qcom_q6v5_pas.c
index 31fdde351bed..0dc9985f01f9 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -117,6 +117,7 @@ struct qcom_pas {
        phys_addr_t region_assign_phys[MAX_ASSIGN_COUNT];
 
        void __iomem *mem_region;
+       void __iomem *secondary_mem_region;
 
        size_t mem_size;
        size_t dtb_mem_size;
@@ -162,6 +163,28 @@ static void qcom_pas_segment_dump(struct rproc *rproc,
        memcpy_fromio(dest, pas->mem_region + total_offset, size);
 }
 
+static bool qcom_pas_has_secondary(const struct qcom_pas *pas)
+{
+       return pas->secondary_pas_id && pas->secondary_dtb_pas_id;
+}
+
+static int qcom_pas_register_dump_segments(struct rproc *rproc,
+                                          struct qcom_pas *pas)
+{
+       int ret;
+
+       ret = rproc_coredump_add_segment(rproc, pas->mem_phys, pas->mem_size);
+       if (ret)
+               return ret;
+
+       ret = rproc_coredump_add_segment(rproc, pas->secondary_mem_phys,
+                                        pas->secondary_mem_size);
+       if (ret)
+               rproc_coredump_cleanup(rproc);
+
+       return ret;
+}
+
 static void qcom_pas_minidump(struct rproc *rproc)
 {
        struct qcom_pas *pas = rproc->priv;
@@ -572,16 +595,29 @@ static int qcom_pas_stop(struct rproc *rproc)
 static void *qcom_pas_da_to_va(struct rproc *rproc, u64 da, size_t len, bool 
*is_iomem)
 {
        struct qcom_pas *pas = rproc->priv;
-       int offset;
+       phys_addr_t base;
+       void __iomem *region;
+
+       if (da >= pas->mem_reloc && len <= pas->mem_size &&
+           da - pas->mem_reloc <= pas->mem_size - len) {
+               base = pas->mem_reloc;
+               region = pas->mem_region;
+       } else if (da >= pas->secondary_mem_reloc &&
+                  len <= pas->secondary_mem_size &&
+                  da - pas->secondary_mem_reloc <= pas->secondary_mem_size - 
len) {
+               base = pas->secondary_mem_reloc;
+               region = pas->secondary_mem_region;
+       } else {
+               return NULL;
+       }
 
-       offset = da - pas->mem_reloc;
-       if (offset < 0 || offset + len > pas->mem_size)
+       if (!region)
                return NULL;
 
        if (is_iomem)
                *is_iomem = true;
 
-       return (__force void *)pas->mem_region + offset;
+       return (__force void *)region + (da - base);
 }
 
 static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware 
*fw)
@@ -593,10 +629,21 @@ static int qcom_pas_parse_firmware(struct rproc *rproc, 
const struct firmware *f
        size_t table_sz;
        int ret;
 
-       ret = qcom_register_dump_segments(rproc, fw);
-       if (ret) {
-               dev_err(pas->dev, "Error in registering dump segments\n");
-               return ret;
+       if (qcom_pas_has_secondary(pas)) {
+               if (list_empty(&rproc->dump_segments)) {
+                       ret = qcom_pas_register_dump_segments(rproc, pas);
+                       if (ret) {
+                               dev_err(pas->dev,
+                                       "failed to register dump segments: 
%d\n", ret);
+                               return ret;
+                       }
+               }
+       } else {
+               ret = qcom_register_dump_segments(rproc, fw);
+               if (ret) {
+                       dev_err(pas->dev, "Error in registering dump 
segments\n");
+                       return ret;
+               }
        }
 
        if (!rproc->has_iommu)
@@ -715,7 +762,22 @@ static void qcom_pas_coredump(struct rproc *rproc)
        if (!pas->mem_region)
                return;
 
+       if (qcom_pas_has_secondary(pas)) {
+               pas->secondary_mem_region =
+                       qcom_pas_ctx_map(pas->secondary_pas_ctx);
+               if (!pas->secondary_mem_region) {
+                       dev_err(pas->dev, "unable to map secondary memory for 
coredump\n");
+                       iounmap(pas->mem_region);
+                       pas->mem_region = NULL;
+                       return;
+               }
+       }
+
        rproc_coredump(rproc);
+       if (pas->secondary_mem_region) {
+               iounmap(pas->secondary_mem_region);
+               pas->secondary_mem_region = NULL;
+       }
        iounmap(pas->mem_region);
        pas->mem_region = NULL;
 }
@@ -1130,6 +1192,12 @@ static int qcom_pas_probe(struct platform_device *pdev)
        if (desc->early_boot)
                pas->rproc->state = RPROC_DETACHED;
 
+       if (qcom_pas_has_secondary(pas)) {
+               ret = qcom_pas_register_dump_segments(rproc, pas);
+               if (ret)
+                       goto remove_ssr_sysmon;
+       }
+
        ret = rproc_add(rproc);
        if (ret)
                goto remove_ssr_sysmon;
@@ -1141,6 +1209,7 @@ static int qcom_pas_probe(struct platform_device *pdev)
        return 0;
 
 remove_ssr_sysmon:
+       rproc_coredump_cleanup(rproc);
        qcom_remove_ssr_subdev(rproc, &pas->ssr_subdev);
        qcom_remove_sysmon_subdev(pas->sysmon);
 deinit_remove_pdm_smd_glink:

-- 
2.34.1


Reply via email to