mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-20 02:34:23 +08:00
drm/nouveau/bios: fix OF loading
Currently OF bios load fails for a few reasons: - checksum failure - bios size too small - no PCIR header - bios length not a multiple of 4 In this change, we resolve all of the above by ignoring any checksum failures (since OF VBIOS tends not to have a checksum), and faking the PCIR data when loading from OF. Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
f231976c2e
commit
25d295882a
@ -8,7 +8,10 @@ struct nvbios_source {
|
||||
void *(*init)(struct nvkm_bios *, const char *);
|
||||
void (*fini)(void *);
|
||||
u32 (*read)(void *, u32 offset, u32 length, struct nvkm_bios *);
|
||||
u32 (*size)(void *);
|
||||
bool rw;
|
||||
bool ignore_checksum;
|
||||
bool no_pcir;
|
||||
};
|
||||
|
||||
int nvbios_extend(struct nvkm_bios *, u32 length);
|
||||
|
@ -45,7 +45,7 @@ shadow_fetch(struct nvkm_bios *bios, struct shadow *mthd, u32 upto)
|
||||
u32 read = mthd->func->read(data, start, limit - start, bios);
|
||||
bios->size = start + read;
|
||||
}
|
||||
return bios->size >= limit;
|
||||
return bios->size >= upto;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -55,14 +55,22 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd)
|
||||
struct nvbios_image image;
|
||||
int score = 1;
|
||||
|
||||
if (!shadow_fetch(bios, mthd, offset + 0x1000)) {
|
||||
nvkm_debug(subdev, "%08x: header fetch failed\n", offset);
|
||||
return 0;
|
||||
}
|
||||
if (mthd->func->no_pcir) {
|
||||
image.base = 0;
|
||||
image.type = 0;
|
||||
image.size = mthd->func->size(mthd->data);
|
||||
image.last = 1;
|
||||
} else {
|
||||
if (!shadow_fetch(bios, mthd, offset + 0x1000)) {
|
||||
nvkm_debug(subdev, "%08x: header fetch failed\n",
|
||||
offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!nvbios_image(bios, idx, &image)) {
|
||||
nvkm_debug(subdev, "image %d invalid\n", idx);
|
||||
return 0;
|
||||
if (!nvbios_image(bios, idx, &image)) {
|
||||
nvkm_debug(subdev, "image %d invalid\n", idx);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
nvkm_debug(subdev, "%08x: type %02x, %d bytes\n",
|
||||
image.base, image.type, image.size);
|
||||
@ -74,7 +82,8 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd)
|
||||
|
||||
switch (image.type) {
|
||||
case 0x00:
|
||||
if (nvbios_checksum(&bios->data[image.base], image.size)) {
|
||||
if (!mthd->func->ignore_checksum &&
|
||||
nvbios_checksum(&bios->data[image.base], image.size)) {
|
||||
nvkm_debug(subdev, "%08x: checksum failed\n",
|
||||
image.base);
|
||||
if (mthd->func->rw)
|
||||
|
@ -21,6 +21,7 @@
|
||||
*
|
||||
*/
|
||||
#include "priv.h"
|
||||
|
||||
#include <core/pci.h>
|
||||
|
||||
#if defined(__powerpc__)
|
||||
@ -33,17 +34,26 @@ static u32
|
||||
of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
|
||||
{
|
||||
struct priv *priv = data;
|
||||
if (offset + length <= priv->size) {
|
||||
if (offset < priv->size) {
|
||||
length = min_t(u32, length, priv->size - offset);
|
||||
memcpy_fromio(bios->data + offset, priv->data + offset, length);
|
||||
return length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32
|
||||
of_size(void *data)
|
||||
{
|
||||
struct priv *priv = data;
|
||||
return priv->size;
|
||||
}
|
||||
|
||||
static void *
|
||||
of_init(struct nvkm_bios *bios, const char *name)
|
||||
{
|
||||
struct pci_dev *pdev = bios->subdev.device->func->pci(bios->subdev.device)->pdev;
|
||||
struct nvkm_device *device = bios->subdev.device;
|
||||
struct pci_dev *pdev = device->func->pci(device)->pdev;
|
||||
struct device_node *dn;
|
||||
struct priv *priv;
|
||||
if (!(dn = pci_device_to_OF_node(pdev)))
|
||||
@ -62,7 +72,10 @@ nvbios_of = {
|
||||
.init = of_init,
|
||||
.fini = (void(*)(void *))kfree,
|
||||
.read = of_read,
|
||||
.size = of_size,
|
||||
.rw = false,
|
||||
.ignore_checksum = true,
|
||||
.no_pcir = true,
|
||||
};
|
||||
#else
|
||||
const struct nvbios_source
|
||||
|
Loading…
Reference in New Issue
Block a user