2 * Copyright 2014 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.
22 * Authors: Ben Skeggs <bskeggs@redhat.com>
26 #include <core/option.h>
27 #include <subdev/bios.h>
28 #include <subdev/bios/image.h>
32 const struct nvbios_source
*func
;
39 shadow_fetch(struct nvkm_bios
*bios
, struct shadow
*mthd
, u32 upto
)
41 const u32 limit
= (upto
+ 3) & ~3;
42 const u32 start
= bios
->size
;
43 void *data
= mthd
->data
;
44 if (nvbios_extend(bios
, limit
) > 0) {
45 u32 read
= mthd
->func
->read(data
, start
, limit
- start
, bios
);
46 bios
->size
= start
+ read
;
48 return bios
->size
>= upto
;
52 shadow_image(struct nvkm_bios
*bios
, int idx
, u32 offset
, struct shadow
*mthd
)
54 struct nvkm_subdev
*subdev
= &bios
->subdev
;
55 struct nvbios_image image
;
58 if (mthd
->func
->no_pcir
) {
61 image
.size
= mthd
->func
->size(mthd
->data
);
64 if (!shadow_fetch(bios
, mthd
, offset
+ 0x1000)) {
65 nvkm_debug(subdev
, "%08x: header fetch failed\n",
70 if (!nvbios_image(bios
, idx
, &image
)) {
71 nvkm_debug(subdev
, "image %d invalid\n", idx
);
75 nvkm_debug(subdev
, "%08x: type %02x, %d bytes\n",
76 image
.base
, image
.type
, image
.size
);
78 if (!shadow_fetch(bios
, mthd
, image
.size
)) {
79 nvkm_debug(subdev
, "%08x: fetch failed\n", image
.base
);
85 if (!mthd
->func
->ignore_checksum
&&
86 nvbios_checksum(&bios
->data
[image
.base
], image
.size
)) {
87 nvkm_debug(subdev
, "%08x: checksum failed\n",
89 if (!mthd
->func
->require_checksum
) {
105 score
+= shadow_image(bios
, idx
+ 1, offset
+ image
.size
, mthd
);
110 shadow_method(struct nvkm_bios
*bios
, struct shadow
*mthd
, const char *name
)
112 const struct nvbios_source
*func
= mthd
->func
;
113 struct nvkm_subdev
*subdev
= &bios
->subdev
;
115 nvkm_debug(subdev
, "trying %s...\n", name
? name
: func
->name
);
117 mthd
->data
= func
->init(bios
, name
);
118 if (IS_ERR(mthd
->data
)) {
123 mthd
->score
= shadow_image(bios
, 0, 0, mthd
);
125 func
->fini(mthd
->data
);
126 nvkm_debug(subdev
, "scored %d\n", mthd
->score
);
127 mthd
->data
= bios
->data
;
128 mthd
->size
= bios
->size
;
136 shadow_fw_read(void *data
, u32 offset
, u32 length
, struct nvkm_bios
*bios
)
138 const struct firmware
*fw
= data
;
139 if (offset
+ length
<= fw
->size
) {
140 memcpy(bios
->data
+ offset
, fw
->data
+ offset
, length
);
147 shadow_fw_init(struct nvkm_bios
*bios
, const char *name
)
149 struct device
*dev
= bios
->subdev
.device
->dev
;
150 const struct firmware
*fw
;
151 int ret
= request_firmware(&fw
, name
, dev
);
153 return ERR_PTR(-ENOENT
);
157 static const struct nvbios_source
160 .init
= shadow_fw_init
,
161 .fini
= (void(*)(void *))release_firmware
,
162 .read
= shadow_fw_read
,
167 nvbios_shadow(struct nvkm_bios
*bios
)
169 struct nvkm_subdev
*subdev
= &bios
->subdev
;
170 struct nvkm_device
*device
= subdev
->device
;
171 struct shadow mthds
[] = {
173 { 0, &nvbios_ramin
},
175 { 0, &nvbios_acpi_fast
},
176 { 4, &nvbios_acpi_slow
},
177 { 1, &nvbios_pcirom
},
178 { 1, &nvbios_platform
},
180 }, *mthd
, *best
= NULL
;
185 /* handle user-specified bios source */
186 optarg
= nvkm_stropt(device
->cfgopt
, "NvBios", &optlen
);
187 source
= optarg
? kstrndup(optarg
, optlen
, GFP_KERNEL
) : NULL
;
189 /* try to match one of the built-in methods */
190 for (mthd
= mthds
; mthd
->func
; mthd
++) {
191 if (mthd
->func
->name
&&
192 !strcasecmp(source
, mthd
->func
->name
)) {
194 if (shadow_method(bios
, mthd
, NULL
))
199 /* otherwise, attempt to load as firmware */
200 if (!best
&& (best
= mthd
)) {
201 mthd
->func
= &shadow_fw
;
202 shadow_method(bios
, mthd
, source
);
207 nvkm_error(subdev
, "%s invalid\n", source
);
213 /* scan all potential bios sources, looking for best image */
214 if (!best
|| !best
->score
) {
215 for (mthd
= mthds
, best
= mthd
; mthd
->func
; mthd
++) {
216 if (!mthd
->skip
|| best
->score
< mthd
->skip
) {
217 if (shadow_method(bios
, mthd
, NULL
)) {
218 if (mthd
->score
> best
->score
)
225 /* cleanup the ones we didn't use */
226 for (mthd
= mthds
; mthd
->func
; mthd
++) {
232 nvkm_error(subdev
, "unable to locate usable image\n");
236 nvkm_debug(subdev
, "using image from %s\n", best
->func
?
237 best
->func
->name
: source
);
238 bios
->data
= best
->data
;
239 bios
->size
= best
->size
;