Commit 25d29588 authored by Ilia Mirkin's avatar Ilia Mirkin Committed by Ben Skeggs

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: default avatarIlia Mirkin <imirkin@alum.mit.edu>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent f231976c
...@@ -8,7 +8,10 @@ struct nvbios_source { ...@@ -8,7 +8,10 @@ struct nvbios_source {
void *(*init)(struct nvkm_bios *, const char *); void *(*init)(struct nvkm_bios *, const char *);
void (*fini)(void *); void (*fini)(void *);
u32 (*read)(void *, u32 offset, u32 length, struct nvkm_bios *); u32 (*read)(void *, u32 offset, u32 length, struct nvkm_bios *);
u32 (*size)(void *);
bool rw; bool rw;
bool ignore_checksum;
bool no_pcir;
}; };
int nvbios_extend(struct nvkm_bios *, u32 length); int nvbios_extend(struct nvkm_bios *, u32 length);
......
...@@ -45,7 +45,7 @@ shadow_fetch(struct nvkm_bios *bios, struct shadow *mthd, u32 upto) ...@@ -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); u32 read = mthd->func->read(data, start, limit - start, bios);
bios->size = start + read; bios->size = start + read;
} }
return bios->size >= limit; return bios->size >= upto;
} }
static int static int
...@@ -55,14 +55,22 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd) ...@@ -55,14 +55,22 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd)
struct nvbios_image image; struct nvbios_image image;
int score = 1; int score = 1;
if (!shadow_fetch(bios, mthd, offset + 0x1000)) { if (mthd->func->no_pcir) {
nvkm_debug(subdev, "%08x: header fetch failed\n", offset); image.base = 0;
return 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)) { if (!nvbios_image(bios, idx, &image)) {
nvkm_debug(subdev, "image %d invalid\n", idx); nvkm_debug(subdev, "image %d invalid\n", idx);
return 0; return 0;
}
} }
nvkm_debug(subdev, "%08x: type %02x, %d bytes\n", nvkm_debug(subdev, "%08x: type %02x, %d bytes\n",
image.base, image.type, image.size); image.base, image.type, image.size);
...@@ -74,7 +82,8 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd) ...@@ -74,7 +82,8 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd)
switch (image.type) { switch (image.type) {
case 0x00: 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", nvkm_debug(subdev, "%08x: checksum failed\n",
image.base); image.base);
if (mthd->func->rw) if (mthd->func->rw)
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
* *
*/ */
#include "priv.h" #include "priv.h"
#include <core/pci.h> #include <core/pci.h>
#if defined(__powerpc__) #if defined(__powerpc__)
...@@ -33,17 +34,26 @@ static u32 ...@@ -33,17 +34,26 @@ static u32
of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
{ {
struct priv *priv = data; 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); memcpy_fromio(bios->data + offset, priv->data + offset, length);
return length; return length;
} }
return 0; return 0;
} }
static u32
of_size(void *data)
{
struct priv *priv = data;
return priv->size;
}
static void * static void *
of_init(struct nvkm_bios *bios, const char *name) 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 device_node *dn;
struct priv *priv; struct priv *priv;
if (!(dn = pci_device_to_OF_node(pdev))) if (!(dn = pci_device_to_OF_node(pdev)))
...@@ -62,7 +72,10 @@ nvbios_of = { ...@@ -62,7 +72,10 @@ nvbios_of = {
.init = of_init, .init = of_init,
.fini = (void(*)(void *))kfree, .fini = (void(*)(void *))kfree,
.read = of_read, .read = of_read,
.size = of_size,
.rw = false, .rw = false,
.ignore_checksum = true,
.no_pcir = true,
}; };
#else #else
const struct nvbios_source const struct nvbios_source
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment