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",
102 score
+= shadow_image(bios
, idx
+ 1, offset
+ image
.size
, mthd
);
107 shadow_method(struct nvkm_bios
*bios
, struct shadow
*mthd
, const char *name
)
109 const struct nvbios_source
*func
= mthd
->func
;
110 struct nvkm_subdev
*subdev
= &bios
->subdev
;
112 nvkm_debug(subdev
, "trying %s...\n", name
? name
: func
->name
);
114 mthd
->data
= func
->init(bios
, name
);
115 if (IS_ERR(mthd
->data
)) {
120 mthd
->score
= shadow_image(bios
, 0, 0, mthd
);
122 func
->fini(mthd
->data
);
123 nvkm_debug(subdev
, "scored %d\n", mthd
->score
);
124 mthd
->data
= bios
->data
;
125 mthd
->size
= bios
->size
;
133 shadow_fw_read(void *data
, u32 offset
, u32 length
, struct nvkm_bios
*bios
)
135 const struct firmware
*fw
= data
;
136 if (offset
+ length
<= fw
->size
) {
137 memcpy(bios
->data
+ offset
, fw
->data
+ offset
, length
);
144 shadow_fw_init(struct nvkm_bios
*bios
, const char *name
)
146 struct device
*dev
= bios
->subdev
.device
->dev
;
147 const struct firmware
*fw
;
148 int ret
= request_firmware(&fw
, name
, dev
);
150 return ERR_PTR(-ENOENT
);
154 static const struct nvbios_source
157 .init
= shadow_fw_init
,
158 .fini
= (void(*)(void *))release_firmware
,
159 .read
= shadow_fw_read
,
164 nvbios_shadow(struct nvkm_bios
*bios
)
166 struct nvkm_subdev
*subdev
= &bios
->subdev
;
167 struct nvkm_device
*device
= subdev
->device
;
168 struct shadow mthds
[] = {
170 { 0, &nvbios_ramin
},
172 { 0, &nvbios_acpi_fast
},
173 { 4, &nvbios_acpi_slow
},
174 { 1, &nvbios_pcirom
},
175 { 1, &nvbios_platform
},
177 }, *mthd
, *best
= NULL
;
182 /* handle user-specified bios source */
183 optarg
= nvkm_stropt(device
->cfgopt
, "NvBios", &optlen
);
184 source
= optarg
? kstrndup(optarg
, optlen
, GFP_KERNEL
) : NULL
;
186 /* try to match one of the built-in methods */
187 for (mthd
= mthds
; mthd
->func
; mthd
++) {
188 if (mthd
->func
->name
&&
189 !strcasecmp(source
, mthd
->func
->name
)) {
191 if (shadow_method(bios
, mthd
, NULL
))
196 /* otherwise, attempt to load as firmware */
197 if (!best
&& (best
= mthd
)) {
198 mthd
->func
= &shadow_fw
;
199 shadow_method(bios
, mthd
, source
);
204 nvkm_error(subdev
, "%s invalid\n", source
);
210 /* scan all potential bios sources, looking for best image */
211 if (!best
|| !best
->score
) {
212 for (mthd
= mthds
, best
= mthd
; mthd
->func
; mthd
++) {
213 if (!mthd
->skip
|| best
->score
< mthd
->skip
) {
214 if (shadow_method(bios
, mthd
, NULL
)) {
215 if (mthd
->score
> best
->score
)
222 /* cleanup the ones we didn't use */
223 for (mthd
= mthds
; mthd
->func
; mthd
++) {
229 nvkm_error(subdev
, "unable to locate usable image\n");
233 nvkm_debug(subdev
, "using image from %s\n", best
->func
?
234 best
->func
->name
: source
);
235 bios
->data
= best
->data
;
236 bios
->size
= best
->size
;