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/device.h>
27 #include <core/option.h>
28 #include <subdev/bios.h>
29 #include <subdev/bios/image.h>
32 struct nvkm_oclass base
;
34 const struct nvbios_source
*func
;
41 shadow_fetch(struct nvkm_bios
*bios
, u32 upto
)
43 struct shadow
*mthd
= (void *)nv_object(bios
)->oclass
;
44 const u32 limit
= (upto
+ 3) & ~3;
45 const u32 start
= bios
->size
;
46 void *data
= mthd
->data
;
47 if (nvbios_extend(bios
, limit
) > 0) {
48 u32 read
= mthd
->func
->read(data
, start
, limit
- start
, bios
);
49 bios
->size
= start
+ read
;
51 return bios
->size
>= limit
;
55 shadow_rd08(struct nvkm_object
*object
, u64 addr
)
57 struct nvkm_bios
*bios
= (void *)object
;
58 if (shadow_fetch(bios
, addr
+ 1))
59 return bios
->data
[addr
];
64 shadow_rd16(struct nvkm_object
*object
, u64 addr
)
66 struct nvkm_bios
*bios
= (void *)object
;
67 if (shadow_fetch(bios
, addr
+ 2))
68 return get_unaligned_le16(&bios
->data
[addr
]);
73 shadow_rd32(struct nvkm_object
*object
, u64 addr
)
75 struct nvkm_bios
*bios
= (void *)object
;
76 if (shadow_fetch(bios
, addr
+ 4))
77 return get_unaligned_le32(&bios
->data
[addr
]);
81 static struct nvkm_oclass
83 .handle
= NV_SUBDEV(VBIOS
, 0x00),
84 .ofuncs
= &(struct nvkm_ofuncs
) {
92 shadow_image(struct nvkm_bios
*bios
, int idx
, struct shadow
*mthd
)
94 struct nvbios_image image
;
97 if (!nvbios_image(bios
, idx
, &image
)) {
98 nv_debug(bios
, "image %d invalid\n", idx
);
101 nv_debug(bios
, "%08x: type %02x, %d bytes\n",
102 image
.base
, image
.type
, image
.size
);
104 if (!shadow_fetch(bios
, image
.size
)) {
105 nv_debug(bios
, "%08x: fetch failed\n", image
.base
);
109 switch (image
.type
) {
111 if (nvbios_checksum(&bios
->data
[image
.base
], image
.size
)) {
112 nv_debug(bios
, "%08x: checksum failed\n", image
.base
);
126 score
+= shadow_image(bios
, idx
+ 1, mthd
);
131 shadow_score(struct nvkm_bios
*bios
, struct shadow
*mthd
)
133 struct nvkm_oclass
*oclass
= nv_object(bios
)->oclass
;
135 nv_object(bios
)->oclass
= &mthd
->base
;
136 score
= shadow_image(bios
, 0, mthd
);
137 nv_object(bios
)->oclass
= oclass
;
143 shadow_method(struct nvkm_bios
*bios
, struct shadow
*mthd
, const char *name
)
145 const struct nvbios_source
*func
= mthd
->func
;
147 nv_debug(bios
, "trying %s...\n", name
? name
: func
->name
);
149 mthd
->data
= func
->init(bios
, name
);
150 if (IS_ERR(mthd
->data
)) {
155 mthd
->score
= shadow_score(bios
, mthd
);
157 func
->fini(mthd
->data
);
158 nv_debug(bios
, "scored %d\n", mthd
->score
);
159 mthd
->data
= bios
->data
;
160 mthd
->size
= bios
->size
;
168 shadow_fw_read(void *data
, u32 offset
, u32 length
, struct nvkm_bios
*bios
)
170 const struct firmware
*fw
= data
;
171 if (offset
+ length
<= fw
->size
) {
172 memcpy(bios
->data
+ offset
, fw
->data
+ offset
, length
);
179 shadow_fw_init(struct nvkm_bios
*bios
, const char *name
)
181 struct device
*dev
= &nv_device(bios
)->pdev
->dev
;
182 const struct firmware
*fw
;
183 int ret
= request_firmware(&fw
, name
, dev
);
185 return ERR_PTR(-ENOENT
);
189 static const struct nvbios_source
192 .init
= shadow_fw_init
,
193 .fini
= (void(*)(void *))release_firmware
,
194 .read
= shadow_fw_read
,
199 nvbios_shadow(struct nvkm_bios
*bios
)
201 struct shadow mthds
[] = {
202 { shadow_class
, 0, &nvbios_of
},
203 { shadow_class
, 0, &nvbios_ramin
},
204 { shadow_class
, 0, &nvbios_rom
},
205 { shadow_class
, 0, &nvbios_acpi_fast
},
206 { shadow_class
, 4, &nvbios_acpi_slow
},
207 { shadow_class
, 1, &nvbios_pcirom
},
208 { shadow_class
, 1, &nvbios_platform
},
210 }, *mthd
= mthds
, *best
= NULL
;
215 /* handle user-specified bios source */
216 optarg
= nvkm_stropt(nv_device(bios
)->cfgopt
, "NvBios", &optlen
);
217 source
= optarg
? kstrndup(optarg
, optlen
, GFP_KERNEL
) : NULL
;
219 /* try to match one of the built-in methods */
220 for (mthd
= mthds
; mthd
->func
; mthd
++) {
221 if (mthd
->func
->name
&&
222 !strcasecmp(source
, mthd
->func
->name
)) {
224 if (shadow_method(bios
, mthd
, NULL
))
229 /* otherwise, attempt to load as firmware */
230 if (!best
&& (best
= mthd
)) {
231 mthd
->func
= &shadow_fw
;
232 shadow_method(bios
, mthd
, source
);
237 nv_error(bios
, "%s invalid\n", source
);
243 /* scan all potential bios sources, looking for best image */
244 if (!best
|| !best
->score
) {
245 for (mthd
= mthds
, best
= mthd
; mthd
->func
; mthd
++) {
246 if (!mthd
->skip
|| best
->score
< mthd
->skip
) {
247 if (shadow_method(bios
, mthd
, NULL
)) {
248 if (mthd
->score
> best
->score
)
255 /* cleanup the ones we didn't use */
256 for (mthd
= mthds
; mthd
->func
; mthd
++) {
262 nv_fatal(bios
, "unable to locate usable image\n");
266 nv_info(bios
, "using image from %s\n", best
->func
?
267 best
->func
->name
: source
);
268 bios
->data
= best
->data
;
269 bios
->size
= best
->size
;