remoteproc: qcom: q6v5-mss: Register segments/dumpfn for coredump
[sfrench/cifs-2.6.git] / drivers / remoteproc / qcom_q6v5_mss.c
index b50edc8ccb47ccaca4679e76beb9b9e261c31c57..01be7314e176f08da68dc33433fb6716097927c5 100644 (file)
@@ -1064,10 +1064,52 @@ static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
        return qproc->mpss_region + offset;
 }
 
+static int qcom_q6v5_register_dump_segments(struct rproc *rproc,
+                                           const struct firmware *mba_fw)
+{
+       const struct firmware *fw;
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
+       const struct elf32_hdr *ehdr;
+       struct q6v5 *qproc = rproc->priv;
+       unsigned long i;
+       int ret;
+
+       ret = request_firmware(&fw, "modem.mdt", qproc->dev);
+       if (ret < 0) {
+               dev_err(qproc->dev, "unable to load modem.mdt\n");
+               return ret;
+       }
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+       qproc->dump_complete_mask = 0;
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdrs[i];
+
+               if (!q6v5_phdr_valid(phdr))
+                       continue;
+
+               ret = rproc_coredump_add_custom_segment(rproc, phdr->p_paddr,
+                                                       phdr->p_memsz,
+                                                       qcom_q6v5_dump_segment,
+                                                       (void *)i);
+               if (ret)
+                       break;
+
+               qproc->dump_complete_mask |= BIT(i);
+       }
+
+       release_firmware(fw);
+       return ret;
+}
+
 static const struct rproc_ops q6v5_ops = {
        .start = q6v5_start,
        .stop = q6v5_stop,
        .da_to_va = q6v5_da_to_va,
+       .parse_fw = qcom_q6v5_register_dump_segments,
        .load = q6v5_load,
 };