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
>= limit
;
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 (!shadow_fetch(bios
, mthd
, offset
+ 0x1000)) {
59 nvkm_debug(subdev
, "%08x: header fetch failed\n", offset
);
63 if (!nvbios_image(bios
, idx
, &image
)) {
64 nvkm_debug(subdev
, "image %d invalid\n", idx
);
67 nvkm_debug(subdev
, "%08x: type %02x, %d bytes\n",
68 image
.base
, image
.type
, image
.size
);
70 if (!shadow_fetch(bios
, mthd
, image
.size
)) {
71 nvkm_debug(subdev
, "%08x: fetch failed\n", image
.base
);
77 if (nvbios_checksum(&bios
->data
[image
.base
], image
.size
)) {
78 nvkm_debug(subdev
, "%08x: checksum failed\n",
93 score
+= shadow_image(bios
, idx
+ 1, offset
+ image
.size
, mthd
);
98 shadow_method(struct nvkm_bios
*bios
, struct shadow
*mthd
, const char *name
)
100 const struct nvbios_source
*func
= mthd
->func
;
101 struct nvkm_subdev
*subdev
= &bios
->subdev
;
103 nvkm_debug(subdev
, "trying %s...\n", name
? name
: func
->name
);
105 mthd
->data
= func
->init(bios
, name
);
106 if (IS_ERR(mthd
->data
)) {
111 mthd
->score
= shadow_image(bios
, 0, 0, mthd
);
113 func
->fini(mthd
->data
);
114 nvkm_debug(subdev
, "scored %d\n", mthd
->score
);
115 mthd
->data
= bios
->data
;
116 mthd
->size
= bios
->size
;
124 shadow_fw_read(void *data
, u32 offset
, u32 length
, struct nvkm_bios
*bios
)
126 const struct firmware
*fw
= data
;
127 if (offset
+ length
<= fw
->size
) {
128 memcpy(bios
->data
+ offset
, fw
->data
+ offset
, length
);
135 shadow_fw_init(struct nvkm_bios
*bios
, const char *name
)
137 struct device
*dev
= &nv_device(bios
)->pdev
->dev
;
138 const struct firmware
*fw
;
139 int ret
= request_firmware(&fw
, name
, dev
);
141 return ERR_PTR(-ENOENT
);
145 static const struct nvbios_source
148 .init
= shadow_fw_init
,
149 .fini
= (void(*)(void *))release_firmware
,
150 .read
= shadow_fw_read
,
155 nvbios_shadow(struct nvkm_bios
*bios
)
157 struct nvkm_subdev
*subdev
= &bios
->subdev
;
158 struct nvkm_device
*device
= subdev
->device
;
159 struct shadow mthds
[] = {
161 { 0, &nvbios_ramin
},
163 { 0, &nvbios_acpi_fast
},
164 { 4, &nvbios_acpi_slow
},
165 { 1, &nvbios_pcirom
},
166 { 1, &nvbios_platform
},
168 }, *mthd
, *best
= NULL
;
173 /* handle user-specified bios source */
174 optarg
= nvkm_stropt(device
->cfgopt
, "NvBios", &optlen
);
175 source
= optarg
? kstrndup(optarg
, optlen
, GFP_KERNEL
) : NULL
;
177 /* try to match one of the built-in methods */
178 for (mthd
= mthds
; mthd
->func
; mthd
++) {
179 if (mthd
->func
->name
&&
180 !strcasecmp(source
, mthd
->func
->name
)) {
182 if (shadow_method(bios
, mthd
, NULL
))
187 /* otherwise, attempt to load as firmware */
188 if (!best
&& (best
= mthd
)) {
189 mthd
->func
= &shadow_fw
;
190 shadow_method(bios
, mthd
, source
);
195 nvkm_error(subdev
, "%s invalid\n", source
);
201 /* scan all potential bios sources, looking for best image */
202 if (!best
|| !best
->score
) {
203 for (mthd
= mthds
, best
= mthd
; mthd
->func
; mthd
++) {
204 if (!mthd
->skip
|| best
->score
< mthd
->skip
) {
205 if (shadow_method(bios
, mthd
, NULL
)) {
206 if (mthd
->score
> best
->score
)
213 /* cleanup the ones we didn't use */
214 for (mthd
= mthds
; mthd
->func
; mthd
++) {
220 nvkm_error(subdev
, "unable to locate usable image\n");
224 nvkm_debug(subdev
, "using image from %s\n", best
->func
?
225 best
->func
->name
: source
);
226 bios
->data
= best
->data
;
227 bios
->size
= best
->size
;
This page took 0.039706 seconds and 5 git commands to generate.