libnvdimm/altmap: Track namespace boundaries in altmap
[linux-2.6-block.git] / drivers / remoteproc / qcom_q6v5_mss.c
index 981581bcdd56b83b1484cde21c6dbc2cec697aaa..8fcf9d28dd731f0eafe80e6830b70dcc25a8b8f2 100644 (file)
@@ -659,23 +659,29 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
 {
        unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
        dma_addr_t phys;
+       void *metadata;
        int mdata_perm;
        int xferop_ret;
+       size_t size;
        void *ptr;
        int ret;
 
-       ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, dma_attrs);
+       metadata = qcom_mdt_read_metadata(fw, &size);
+       if (IS_ERR(metadata))
+               return PTR_ERR(metadata);
+
+       ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
        if (!ptr) {
+               kfree(metadata);
                dev_err(qproc->dev, "failed to allocate mdt buffer\n");
                return -ENOMEM;
        }
 
-       memcpy(ptr, fw->data, fw->size);
+       memcpy(ptr, metadata, size);
 
        /* Hypervisor mapping to access metadata by modem */
        mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
-       ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm,
-                                     true, phys, fw->size);
+       ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, true, phys, size);
        if (ret) {
                dev_err(qproc->dev,
                        "assigning Q6 access to metadata failed: %d\n", ret);
@@ -693,14 +699,14 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
                dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret);
 
        /* Metadata authentication done, remove modem access */
-       xferop_ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm,
-                                            false, phys, fw->size);
+       xferop_ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, false, phys, size);
        if (xferop_ret)
                dev_warn(qproc->dev,
                         "mdt buffer not reclaimed system may become unstable\n");
 
 free_dma_attrs:
-       dma_free_attrs(qproc->dev, fw->size, ptr, phys, dma_attrs);
+       dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
+       kfree(metadata);
 
        return ret < 0 ? ret : 0;
 }
@@ -981,7 +987,18 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
 
                ptr = qproc->mpss_region + offset;
 
-               if (phdr->p_filesz) {
+               if (phdr->p_filesz && phdr->p_offset < fw->size) {
+                       /* Firmware is large enough to be non-split */
+                       if (phdr->p_offset + phdr->p_filesz > fw->size) {
+                               dev_err(qproc->dev,
+                                       "failed to load segment %d from truncated file %s\n",
+                                       i, fw_name);
+                               ret = -EINVAL;
+                               goto release_firmware;
+                       }
+
+                       memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
+               } else if (phdr->p_filesz) {
                        /* Replace "xxx.xxx" with "xxx.bxx" */
                        sprintf(fw_name + fw_name_len - 3, "b%02d", i);
                        ret = request_firmware(&seg_fw, fw_name, qproc->dev);