aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2017-01-27 05:17:23 -0500
committerBjorn Andersson <bjorn.andersson@linaro.org>2017-02-06 11:57:24 -0500
commit7f0dd07a9b29cfadffcd2fa08902a844f5c94e86 (patch)
tree022b7fe0d968f61d2e2035a255e79f43fdb3da9e
parent3e8b571a9a0881ba3381ca0915995696da145ab8 (diff)
remoteproc: qcom: mdt_loader: Refactor MDT loader
Pushing the SCM calls into the MDT loader reduces duplication in the callers and allows for non-remoteproc clients to use the helper for parsing and loading MDT files. Cc: Andy Gross <andy.gross@linaro.com> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
-rw-r--r--drivers/remoteproc/qcom_adsp_pil.c30
-rw-r--r--drivers/remoteproc/qcom_mdt_loader.c137
-rw-r--r--drivers/remoteproc/qcom_mdt_loader.h7
-rw-r--r--drivers/remoteproc/qcom_wcnss.c29
4 files changed, 98 insertions, 105 deletions
diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c
index 4fb4c4b47875..c1ee5c818b42 100644
--- a/drivers/remoteproc/qcom_adsp_pil.c
+++ b/drivers/remoteproc/qcom_adsp_pil.c
@@ -75,35 +75,9 @@ struct qcom_adsp {
75static int adsp_load(struct rproc *rproc, const struct firmware *fw) 75static int adsp_load(struct rproc *rproc, const struct firmware *fw)
76{ 76{
77 struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; 77 struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
78 phys_addr_t fw_addr;
79 size_t fw_size;
80 bool relocate;
81 int ret;
82
83 ret = qcom_scm_pas_init_image(adsp->pas_id, fw->data, fw->size);
84 if (ret) {
85 dev_err(&rproc->dev, "invalid firmware metadata\n");
86 return ret;
87 }
88
89 ret = qcom_mdt_parse(fw, &fw_addr, &fw_size, &relocate);
90 if (ret) {
91 dev_err(&rproc->dev, "failed to parse mdt header\n");
92 return ret;
93 }
94
95 if (relocate) {
96 adsp->mem_reloc = fw_addr;
97
98 ret = qcom_scm_pas_mem_setup(adsp->pas_id,
99 adsp->mem_phys, fw_size);
100 if (ret) {
101 dev_err(&rproc->dev, "unable to setup memory for image\n");
102 return ret;
103 }
104 }
105 78
106 return qcom_mdt_load(rproc, fw, rproc->firmware); 79 return qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id,
80 adsp->mem_region, adsp->mem_phys, adsp->mem_size);
107} 81}
108 82
109static const struct rproc_fw_ops adsp_fw_ops = { 83static const struct rproc_fw_ops adsp_fw_ops = {
diff --git a/drivers/remoteproc/qcom_mdt_loader.c b/drivers/remoteproc/qcom_mdt_loader.c
index fe7d5207ad17..790ab31f31ff 100644
--- a/drivers/remoteproc/qcom_mdt_loader.c
+++ b/drivers/remoteproc/qcom_mdt_loader.c
@@ -15,35 +15,44 @@
15 * GNU General Public License for more details. 15 * GNU General Public License for more details.
16 */ 16 */
17 17
18#include <linux/device.h>
18#include <linux/elf.h> 19#include <linux/elf.h>
19#include <linux/firmware.h> 20#include <linux/firmware.h>
20#include <linux/kernel.h> 21#include <linux/kernel.h>
21#include <linux/module.h> 22#include <linux/module.h>
22#include <linux/remoteproc.h> 23#include <linux/qcom_scm.h>
23#include <linux/sizes.h> 24#include <linux/sizes.h>
24#include <linux/slab.h> 25#include <linux/slab.h>
25 26
26#include "remoteproc_internal.h"
27#include "qcom_mdt_loader.h" 27#include "qcom_mdt_loader.h"
28 28
29static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
30{
31 if (phdr->p_type != PT_LOAD)
32 return false;
33
34 if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
35 return false;
36
37 if (!phdr->p_memsz)
38 return false;
39
40 return true;
41}
42
29/** 43/**
30 * qcom_mdt_parse() - extract useful parameters from the mdt header 44 * qcom_mdt_get_size() - acquire size of the memory region needed to load mdt
31 * @fw: firmware handle 45 * @fw: firmware object for the mdt file
32 * @fw_addr: optional reference for base of the firmware's memory region
33 * @fw_size: optional reference for size of the firmware's memory region
34 * @fw_relocate: optional reference for flagging if the firmware is relocatable
35 * 46 *
36 * Returns 0 on success, negative errno otherwise. 47 * Returns size of the loaded firmware blob, or -EINVAL on failure.
37 */ 48 */
38int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, 49ssize_t qcom_mdt_get_size(const struct firmware *fw)
39 size_t *fw_size, bool *fw_relocate)
40{ 50{
41 const struct elf32_phdr *phdrs; 51 const struct elf32_phdr *phdrs;
42 const struct elf32_phdr *phdr; 52 const struct elf32_phdr *phdr;
43 const struct elf32_hdr *ehdr; 53 const struct elf32_hdr *ehdr;
44 phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX; 54 phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
45 phys_addr_t max_addr = 0; 55 phys_addr_t max_addr = 0;
46 bool relocate = false;
47 int i; 56 int i;
48 57
49 ehdr = (struct elf32_hdr *)fw->data; 58 ehdr = (struct elf32_hdr *)fw->data;
@@ -52,18 +61,9 @@ int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr,
52 for (i = 0; i < ehdr->e_phnum; i++) { 61 for (i = 0; i < ehdr->e_phnum; i++) {
53 phdr = &phdrs[i]; 62 phdr = &phdrs[i];
54 63
55 if (phdr->p_type != PT_LOAD) 64 if (!mdt_phdr_valid(phdr))
56 continue; 65 continue;
57 66
58 if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
59 continue;
60
61 if (!phdr->p_memsz)
62 continue;
63
64 if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
65 relocate = true;
66
67 if (phdr->p_paddr < min_addr) 67 if (phdr->p_paddr < min_addr)
68 min_addr = phdr->p_paddr; 68 min_addr = phdr->p_paddr;
69 69
@@ -71,39 +71,44 @@ int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr,
71 max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K); 71 max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
72 } 72 }
73 73
74 if (fw_addr) 74 return min_addr < max_addr ? max_addr - min_addr : -EINVAL;
75 *fw_addr = min_addr;
76 if (fw_size)
77 *fw_size = max_addr - min_addr;
78 if (fw_relocate)
79 *fw_relocate = relocate;
80
81 return 0;
82} 75}
83EXPORT_SYMBOL_GPL(qcom_mdt_parse); 76EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
84 77
85/** 78/**
86 * qcom_mdt_load() - load the firmware which header is defined in fw 79 * qcom_mdt_load() - load the firmware which header is loaded as fw
87 * @rproc: rproc handle 80 * @dev: device handle to associate resources with
88 * @fw: frimware object for the header 81 * @fw: firmware object for the mdt file
89 * @firmware: filename of the firmware, for building .bXX names 82 * @firmware: name of the firmware, for construction of segment file names
83 * @pas_id: PAS identifier
84 * @mem_region: allocated memory region to load firmware into
85 * @mem_phys: physical address of allocated memory region
86 * @mem_size: size of the allocated memory region
90 * 87 *
91 * Returns 0 on success, negative errno otherwise. 88 * Returns 0 on success, negative errno otherwise.
92 */ 89 */
93int qcom_mdt_load(struct rproc *rproc, 90int qcom_mdt_load(struct device *dev, const struct firmware *fw,
94 const struct firmware *fw, 91 const char *firmware, int pas_id, void *mem_region,
95 const char *firmware) 92 phys_addr_t mem_phys, size_t mem_size)
96{ 93{
97 const struct elf32_phdr *phdrs; 94 const struct elf32_phdr *phdrs;
98 const struct elf32_phdr *phdr; 95 const struct elf32_phdr *phdr;
99 const struct elf32_hdr *ehdr; 96 const struct elf32_hdr *ehdr;
100 const struct firmware *seg_fw; 97 const struct firmware *seg_fw;
98 phys_addr_t mem_reloc;
99 phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
100 phys_addr_t max_addr = 0;
101 size_t fw_name_len; 101 size_t fw_name_len;
102 size_t offset;
102 char *fw_name; 103 char *fw_name;
104 bool relocate = false;
103 void *ptr; 105 void *ptr;
104 int ret; 106 int ret;
105 int i; 107 int i;
106 108
109 if (!fw || !mem_region || !mem_phys || !mem_size)
110 return -EINVAL;
111
107 ehdr = (struct elf32_hdr *)fw->data; 112 ehdr = (struct elf32_hdr *)fw->data;
108 phdrs = (struct elf32_phdr *)(ehdr + 1); 113 phdrs = (struct elf32_phdr *)(ehdr + 1);
109 114
@@ -115,31 +120,68 @@ int qcom_mdt_load(struct rproc *rproc,
115 if (!fw_name) 120 if (!fw_name)
116 return -ENOMEM; 121 return -ENOMEM;
117 122
123 ret = qcom_scm_pas_init_image(pas_id, fw->data, fw->size);
124 if (ret) {
125 dev_err(dev, "invalid firmware metadata\n");
126 goto out;
127 }
128
118 for (i = 0; i < ehdr->e_phnum; i++) { 129 for (i = 0; i < ehdr->e_phnum; i++) {
119 phdr = &phdrs[i]; 130 phdr = &phdrs[i];
120 131
121 if (phdr->p_type != PT_LOAD) 132 if (!mdt_phdr_valid(phdr))
122 continue; 133 continue;
123 134
124 if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) 135 if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
125 continue; 136 relocate = true;
137
138 if (phdr->p_paddr < min_addr)
139 min_addr = phdr->p_paddr;
140
141 if (phdr->p_paddr + phdr->p_memsz > max_addr)
142 max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
143 }
144
145 if (relocate) {
146 ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
147 if (ret) {
148 dev_err(dev, "unable to setup relocation\n");
149 goto out;
150 }
151
152 /*
153 * The image is relocatable, so offset each segment based on
154 * the lowest segment address.
155 */
156 mem_reloc = min_addr;
157 } else {
158 /*
159 * Image is not relocatable, so offset each segment based on
160 * the allocated physical chunk of memory.
161 */
162 mem_reloc = mem_phys;
163 }
126 164
127 if (!phdr->p_memsz) 165 for (i = 0; i < ehdr->e_phnum; i++) {
166 phdr = &phdrs[i];
167
168 if (!mdt_phdr_valid(phdr))
128 continue; 169 continue;
129 170
130 ptr = rproc_da_to_va(rproc, phdr->p_paddr, phdr->p_memsz); 171 offset = phdr->p_paddr - mem_reloc;
131 if (!ptr) { 172 if (offset < 0 || offset + phdr->p_memsz > mem_size) {
132 dev_err(&rproc->dev, "segment outside memory range\n"); 173 dev_err(dev, "segment outside memory range\n");
133 ret = -EINVAL; 174 ret = -EINVAL;
134 break; 175 break;
135 } 176 }
136 177
178 ptr = mem_region + offset;
179
137 if (phdr->p_filesz) { 180 if (phdr->p_filesz) {
138 sprintf(fw_name + fw_name_len - 3, "b%02d", i); 181 sprintf(fw_name + fw_name_len - 3, "b%02d", i);
139 ret = request_firmware(&seg_fw, fw_name, &rproc->dev); 182 ret = request_firmware(&seg_fw, fw_name, dev);
140 if (ret) { 183 if (ret) {
141 dev_err(&rproc->dev, "failed to load %s\n", 184 dev_err(dev, "failed to load %s\n", fw_name);
142 fw_name);
143 break; 185 break;
144 } 186 }
145 187
@@ -152,6 +194,7 @@ int qcom_mdt_load(struct rproc *rproc,
152 memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); 194 memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
153 } 195 }
154 196
197out:
155 kfree(fw_name); 198 kfree(fw_name);
156 199
157 return ret; 200 return ret;
diff --git a/drivers/remoteproc/qcom_mdt_loader.h b/drivers/remoteproc/qcom_mdt_loader.h
index e513548e52ec..ff6e45b77326 100644
--- a/drivers/remoteproc/qcom_mdt_loader.h
+++ b/drivers/remoteproc/qcom_mdt_loader.h
@@ -5,8 +5,9 @@
5#define QCOM_MDT_TYPE_HASH (2 << 24) 5#define QCOM_MDT_TYPE_HASH (2 << 24)
6#define QCOM_MDT_RELOCATABLE BIT(27) 6#define QCOM_MDT_RELOCATABLE BIT(27)
7 7
8int qcom_mdt_load(struct rproc *rproc, const struct firmware *fw, const char *fw_name); 8ssize_t qcom_mdt_get_size(const struct firmware *fw);
9 9int qcom_mdt_load(struct device *dev, const struct firmware *fw,
10int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, size_t *fw_size, bool *fw_relocate); 10 const char *fw_name, int pas_id, void *mem_region,
11 phys_addr_t mem_phys, size_t mem_size);
11 12
12#endif 13#endif
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index f158f8243b04..fbb25ea4ae8a 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -153,34 +153,9 @@ void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss,
153static int wcnss_load(struct rproc *rproc, const struct firmware *fw) 153static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
154{ 154{
155 struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv; 155 struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
156 phys_addr_t fw_addr;
157 size_t fw_size;
158 bool relocate;
159 int ret;
160
161 ret = qcom_scm_pas_init_image(WCNSS_PAS_ID, fw->data, fw->size);
162 if (ret) {
163 dev_err(&rproc->dev, "invalid firmware metadata\n");
164 return ret;
165 }
166
167 ret = qcom_mdt_parse(fw, &fw_addr, &fw_size, &relocate);
168 if (ret) {
169 dev_err(&rproc->dev, "failed to parse mdt header\n");
170 return ret;
171 }
172
173 if (relocate) {
174 wcnss->mem_reloc = fw_addr;
175
176 ret = qcom_scm_pas_mem_setup(WCNSS_PAS_ID, wcnss->mem_phys, fw_size);
177 if (ret) {
178 dev_err(&rproc->dev, "unable to setup memory for image\n");
179 return ret;
180 }
181 }
182 156
183 return qcom_mdt_load(rproc, fw, rproc->firmware); 157 return qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID,
158 wcnss->mem_region, wcnss->mem_phys, wcnss->mem_size);
184} 159}
185 160
186static const struct rproc_fw_ops wcnss_fw_ops = { 161static const struct rproc_fw_ops wcnss_fw_ops = {