forked from Minki/linux
remoteproc: qcom: q6v5-mss: Support loading non-split images
In some software releases the firmware images are not split up with each loadable segment in it's own file. Check the size of the loaded firmware to see if it still contains each segment to be loaded, before falling back to the split-out segments. Reviewed-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
This commit is contained in:
parent
498b98e939
commit
f04b913834
@ -667,23 +667,29 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
|
|||||||
{
|
{
|
||||||
unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
|
unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
|
||||||
dma_addr_t phys;
|
dma_addr_t phys;
|
||||||
|
void *metadata;
|
||||||
int mdata_perm;
|
int mdata_perm;
|
||||||
int xferop_ret;
|
int xferop_ret;
|
||||||
|
size_t size;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
int ret;
|
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) {
|
if (!ptr) {
|
||||||
|
kfree(metadata);
|
||||||
dev_err(qproc->dev, "failed to allocate mdt buffer\n");
|
dev_err(qproc->dev, "failed to allocate mdt buffer\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(ptr, fw->data, fw->size);
|
memcpy(ptr, metadata, size);
|
||||||
|
|
||||||
/* Hypervisor mapping to access metadata by modem */
|
/* Hypervisor mapping to access metadata by modem */
|
||||||
mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
|
mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
|
||||||
ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm,
|
ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, true, phys, size);
|
||||||
true, phys, fw->size);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(qproc->dev,
|
dev_err(qproc->dev,
|
||||||
"assigning Q6 access to metadata failed: %d\n", ret);
|
"assigning Q6 access to metadata failed: %d\n", ret);
|
||||||
@ -701,14 +707,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);
|
dev_err(qproc->dev, "MPSS header authentication failed: %d\n", ret);
|
||||||
|
|
||||||
/* Metadata authentication done, remove modem access */
|
/* Metadata authentication done, remove modem access */
|
||||||
xferop_ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm,
|
xferop_ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, false, phys, size);
|
||||||
false, phys, fw->size);
|
|
||||||
if (xferop_ret)
|
if (xferop_ret)
|
||||||
dev_warn(qproc->dev,
|
dev_warn(qproc->dev,
|
||||||
"mdt buffer not reclaimed system may become unstable\n");
|
"mdt buffer not reclaimed system may become unstable\n");
|
||||||
|
|
||||||
free_dma_attrs:
|
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;
|
return ret < 0 ? ret : 0;
|
||||||
}
|
}
|
||||||
@ -989,7 +995,18 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
|
|||||||
|
|
||||||
ptr = qproc->mpss_region + offset;
|
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" */
|
/* Replace "xxx.xxx" with "xxx.bxx" */
|
||||||
sprintf(fw_name + fw_name_len - 3, "b%02d", i);
|
sprintf(fw_name + fw_name_len - 3, "b%02d", i);
|
||||||
ret = request_firmware(&seg_fw, fw_name, qproc->dev);
|
ret = request_firmware(&seg_fw, fw_name, qproc->dev);
|
||||||
|
Loading…
Reference in New Issue
Block a user