2 * Copyright 2019 Red Hat Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
23 #include <core/falcon.h>
24 #include <core/firmware.h>
29 nvkm_acr_lsfw_del(struct nvkm_acr_lsfw
*lsfw
)
31 nvkm_blob_dtor(&lsfw
->img
);
32 nvkm_firmware_put(lsfw
->sig
);
33 list_del(&lsfw
->head
);
38 nvkm_acr_lsfw_del_all(struct nvkm_acr
*acr
)
40 struct nvkm_acr_lsfw
*lsfw
, *lsft
;
41 list_for_each_entry_safe(lsfw
, lsft
, &acr
->lsfw
, head
) {
42 nvkm_acr_lsfw_del(lsfw
);
46 static struct nvkm_acr_lsfw
*
47 nvkm_acr_lsfw_get(struct nvkm_acr
*acr
, enum nvkm_acr_lsf_id id
)
49 struct nvkm_acr_lsfw
*lsfw
;
50 list_for_each_entry(lsfw
, &acr
->lsfw
, head
) {
57 struct nvkm_acr_lsfw
*
58 nvkm_acr_lsfw_add(const struct nvkm_acr_lsf_func
*func
, struct nvkm_acr
*acr
,
59 struct nvkm_falcon
*falcon
, enum nvkm_acr_lsf_id id
)
61 struct nvkm_acr_lsfw
*lsfw
;
64 return ERR_PTR(-ENOSYS
);
66 lsfw
= nvkm_acr_lsfw_get(acr
, id
);
67 if (lsfw
&& lsfw
->func
) {
68 nvkm_error(&acr
->subdev
, "LSFW %d redefined\n", id
);
69 return ERR_PTR(-EEXIST
);
73 if (!(lsfw
= kzalloc(sizeof(*lsfw
), GFP_KERNEL
)))
74 return ERR_PTR(-ENOMEM
);
77 list_add_tail(&lsfw
->head
, &acr
->lsfw
);
81 lsfw
->falcon
= falcon
;
85 static struct nvkm_acr_lsfw
*
86 nvkm_acr_lsfw_load_sig_image_desc_(struct nvkm_subdev
*subdev
,
87 struct nvkm_falcon
*falcon
,
88 enum nvkm_acr_lsf_id id
,
89 const char *path
, int ver
,
90 const struct nvkm_acr_lsf_func
*func
,
91 const struct firmware
**pdesc
)
93 struct nvkm_acr
*acr
= subdev
->device
->acr
;
94 struct nvkm_acr_lsfw
*lsfw
;
97 if (IS_ERR((lsfw
= nvkm_acr_lsfw_add(func
, acr
, falcon
, id
))))
100 ret
= nvkm_firmware_load_name(subdev
, path
, "sig", ver
, &lsfw
->sig
);
104 ret
= nvkm_firmware_load_blob(subdev
, path
, "image", ver
, &lsfw
->img
);
108 ret
= nvkm_firmware_load_name(subdev
, path
, "desc", ver
, pdesc
);
111 nvkm_acr_lsfw_del(lsfw
);
119 nvkm_acr_lsfw_from_desc(const struct nvfw_ls_desc_head
*desc
,
120 struct nvkm_acr_lsfw
*lsfw
)
122 lsfw
->bootloader_size
= ALIGN(desc
->bootloader_size
, 256);
123 lsfw
->bootloader_imem_offset
= desc
->bootloader_imem_offset
;
125 lsfw
->app_size
= ALIGN(desc
->app_size
, 256);
126 lsfw
->app_start_offset
= desc
->app_start_offset
;
127 lsfw
->app_imem_entry
= desc
->app_imem_entry
;
128 lsfw
->app_resident_code_offset
= desc
->app_resident_code_offset
;
129 lsfw
->app_resident_code_size
= desc
->app_resident_code_size
;
130 lsfw
->app_resident_data_offset
= desc
->app_resident_data_offset
;
131 lsfw
->app_resident_data_size
= desc
->app_resident_data_size
;
133 lsfw
->ucode_size
= ALIGN(lsfw
->app_resident_data_offset
, 256) +
134 lsfw
->bootloader_size
;
135 lsfw
->data_size
= lsfw
->app_size
+ lsfw
->bootloader_size
-
140 nvkm_acr_lsfw_load_sig_image_desc(struct nvkm_subdev
*subdev
,
141 struct nvkm_falcon
*falcon
,
142 enum nvkm_acr_lsf_id id
,
143 const char *path
, int ver
,
144 const struct nvkm_acr_lsf_func
*func
)
146 const struct firmware
*fw
;
147 struct nvkm_acr_lsfw
*lsfw
;
149 lsfw
= nvkm_acr_lsfw_load_sig_image_desc_(subdev
, falcon
, id
, path
, ver
,
152 return PTR_ERR(lsfw
);
154 nvkm_acr_lsfw_from_desc(&nvfw_ls_desc(subdev
, fw
->data
)->head
, lsfw
);
155 nvkm_firmware_put(fw
);
160 nvkm_acr_lsfw_load_sig_image_desc_v1(struct nvkm_subdev
*subdev
,
161 struct nvkm_falcon
*falcon
,
162 enum nvkm_acr_lsf_id id
,
163 const char *path
, int ver
,
164 const struct nvkm_acr_lsf_func
*func
)
166 const struct firmware
*fw
;
167 struct nvkm_acr_lsfw
*lsfw
;
169 lsfw
= nvkm_acr_lsfw_load_sig_image_desc_(subdev
, falcon
, id
, path
, ver
,
172 return PTR_ERR(lsfw
);
174 nvkm_acr_lsfw_from_desc(&nvfw_ls_desc_v1(subdev
, fw
->data
)->head
, lsfw
);
175 nvkm_firmware_put(fw
);
180 nvkm_acr_lsfw_load_bl_inst_data_sig(struct nvkm_subdev
*subdev
,
181 struct nvkm_falcon
*falcon
,
182 enum nvkm_acr_lsf_id id
,
183 const char *path
, int ver
,
184 const struct nvkm_acr_lsf_func
*func
)
186 struct nvkm_acr
*acr
= subdev
->device
->acr
;
187 struct nvkm_acr_lsfw
*lsfw
;
188 const struct firmware
*bl
= NULL
, *inst
= NULL
, *data
= NULL
;
189 const struct nvfw_bin_hdr
*hdr
;
190 const struct nvfw_bl_desc
*desc
;
194 if (IS_ERR((lsfw
= nvkm_acr_lsfw_add(func
, acr
, falcon
, id
))))
195 return PTR_ERR(lsfw
);
197 ret
= nvkm_firmware_load_name(subdev
, path
, "bl", ver
, &bl
);
201 hdr
= nvfw_bin_hdr(subdev
, bl
->data
);
202 desc
= nvfw_bl_desc(subdev
, bl
->data
+ hdr
->header_offset
);
203 bldata
= (void *)(bl
->data
+ hdr
->data_offset
);
205 ret
= nvkm_firmware_load_name(subdev
, path
, "inst", ver
, &inst
);
209 ret
= nvkm_firmware_load_name(subdev
, path
, "data", ver
, &data
);
213 ret
= nvkm_firmware_load_name(subdev
, path
, "sig", ver
, &lsfw
->sig
);
217 lsfw
->bootloader_size
= ALIGN(desc
->code_size
, 256);
218 lsfw
->bootloader_imem_offset
= desc
->start_tag
<< 8;
220 lsfw
->app_start_offset
= lsfw
->bootloader_size
;
221 lsfw
->app_imem_entry
= 0;
222 lsfw
->app_resident_code_offset
= 0;
223 lsfw
->app_resident_code_size
= ALIGN(inst
->size
, 256);
224 lsfw
->app_resident_data_offset
= lsfw
->app_resident_code_size
;
225 lsfw
->app_resident_data_size
= ALIGN(data
->size
, 256);
226 lsfw
->app_size
= lsfw
->app_resident_code_size
+
227 lsfw
->app_resident_data_size
;
229 lsfw
->img
.size
= lsfw
->bootloader_size
+ lsfw
->app_size
;
230 if (!(lsfw
->img
.data
= kzalloc(lsfw
->img
.size
, GFP_KERNEL
))) {
235 memcpy(lsfw
->img
.data
, bldata
, lsfw
->bootloader_size
);
236 memcpy(lsfw
->img
.data
+ lsfw
->app_start_offset
+
237 lsfw
->app_resident_code_offset
, inst
->data
, inst
->size
);
238 memcpy(lsfw
->img
.data
+ lsfw
->app_start_offset
+
239 lsfw
->app_resident_data_offset
, data
->data
, data
->size
);
241 lsfw
->ucode_size
= ALIGN(lsfw
->app_resident_data_offset
, 256) +
242 lsfw
->bootloader_size
;
243 lsfw
->data_size
= lsfw
->app_size
+ lsfw
->bootloader_size
-
248 nvkm_acr_lsfw_del(lsfw
);
249 nvkm_firmware_put(data
);
250 nvkm_firmware_put(inst
);
251 nvkm_firmware_put(bl
);