diff options
author | Ilia Mirkin <imirkin@alum.mit.edu> | 2015-10-01 23:41:21 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2015-10-11 23:54:56 -0400 |
commit | 25d295882a1adfcdaaad85369289677b87c7c8f0 (patch) | |
tree | 3c586938dcc7b2fd9db944db8745f60f72ae5a52 | |
parent | f231976c2e8964ceaa9250e57d27c35ff03825c2 (diff) |
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>
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c | 17 |
3 files changed, 36 insertions, 11 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h index e0ec2a6b7b79..212800ecdce9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h | |||
@@ -8,7 +8,10 @@ struct nvbios_source { | |||
8 | void *(*init)(struct nvkm_bios *, const char *); | 8 | void *(*init)(struct nvkm_bios *, const char *); |
9 | void (*fini)(void *); | 9 | void (*fini)(void *); |
10 | u32 (*read)(void *, u32 offset, u32 length, struct nvkm_bios *); | 10 | u32 (*read)(void *, u32 offset, u32 length, struct nvkm_bios *); |
11 | u32 (*size)(void *); | ||
11 | bool rw; | 12 | bool rw; |
13 | bool ignore_checksum; | ||
14 | bool no_pcir; | ||
12 | }; | 15 | }; |
13 | 16 | ||
14 | int nvbios_extend(struct nvkm_bios *, u32 length); | 17 | int nvbios_extend(struct nvkm_bios *, u32 length); |
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c index 792f017525f6..b2557e87afdd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c | |||
@@ -45,7 +45,7 @@ shadow_fetch(struct nvkm_bios *bios, struct shadow *mthd, u32 upto) | |||
45 | u32 read = mthd->func->read(data, start, limit - start, bios); | 45 | u32 read = mthd->func->read(data, start, limit - start, bios); |
46 | bios->size = start + read; | 46 | bios->size = start + read; |
47 | } | 47 | } |
48 | return bios->size >= limit; | 48 | return bios->size >= upto; |
49 | } | 49 | } |
50 | 50 | ||
51 | static int | 51 | static int |
@@ -55,14 +55,22 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd) | |||
55 | struct nvbios_image image; | 55 | struct nvbios_image image; |
56 | int score = 1; | 56 | int score = 1; |
57 | 57 | ||
58 | if (!shadow_fetch(bios, mthd, offset + 0x1000)) { | 58 | if (mthd->func->no_pcir) { |
59 | nvkm_debug(subdev, "%08x: header fetch failed\n", offset); | 59 | image.base = 0; |
60 | return 0; | 60 | image.type = 0; |
61 | } | 61 | image.size = mthd->func->size(mthd->data); |
62 | image.last = 1; | ||
63 | } else { | ||
64 | if (!shadow_fetch(bios, mthd, offset + 0x1000)) { | ||
65 | nvkm_debug(subdev, "%08x: header fetch failed\n", | ||
66 | offset); | ||
67 | return 0; | ||
68 | } | ||
62 | 69 | ||
63 | if (!nvbios_image(bios, idx, &image)) { | 70 | if (!nvbios_image(bios, idx, &image)) { |
64 | nvkm_debug(subdev, "image %d invalid\n", idx); | 71 | nvkm_debug(subdev, "image %d invalid\n", idx); |
65 | return 0; | 72 | return 0; |
73 | } | ||
66 | } | 74 | } |
67 | nvkm_debug(subdev, "%08x: type %02x, %d bytes\n", | 75 | nvkm_debug(subdev, "%08x: type %02x, %d bytes\n", |
68 | image.base, image.type, image.size); | 76 | image.base, image.type, image.size); |
@@ -74,7 +82,8 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd) | |||
74 | 82 | ||
75 | switch (image.type) { | 83 | switch (image.type) { |
76 | case 0x00: | 84 | case 0x00: |
77 | if (nvbios_checksum(&bios->data[image.base], image.size)) { | 85 | if (!mthd->func->ignore_checksum && |
86 | nvbios_checksum(&bios->data[image.base], image.size)) { | ||
78 | nvkm_debug(subdev, "%08x: checksum failed\n", | 87 | nvkm_debug(subdev, "%08x: checksum failed\n", |
79 | image.base); | 88 | image.base); |
80 | if (mthd->func->rw) | 89 | if (mthd->func->rw) |
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c index bd60d7dd09f5..4bf486b57101 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c | |||
@@ -21,6 +21,7 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | #include "priv.h" | 23 | #include "priv.h" |
24 | |||
24 | #include <core/pci.h> | 25 | #include <core/pci.h> |
25 | 26 | ||
26 | #if defined(__powerpc__) | 27 | #if defined(__powerpc__) |
@@ -33,17 +34,26 @@ static u32 | |||
33 | of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) | 34 | of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) |
34 | { | 35 | { |
35 | struct priv *priv = data; | 36 | struct priv *priv = data; |
36 | if (offset + length <= priv->size) { | 37 | if (offset < priv->size) { |
38 | length = min_t(u32, length, priv->size - offset); | ||
37 | memcpy_fromio(bios->data + offset, priv->data + offset, length); | 39 | memcpy_fromio(bios->data + offset, priv->data + offset, length); |
38 | return length; | 40 | return length; |
39 | } | 41 | } |
40 | return 0; | 42 | return 0; |
41 | } | 43 | } |
42 | 44 | ||
45 | static u32 | ||
46 | of_size(void *data) | ||
47 | { | ||
48 | struct priv *priv = data; | ||
49 | return priv->size; | ||
50 | } | ||
51 | |||
43 | static void * | 52 | static void * |
44 | of_init(struct nvkm_bios *bios, const char *name) | 53 | of_init(struct nvkm_bios *bios, const char *name) |
45 | { | 54 | { |
46 | struct pci_dev *pdev = bios->subdev.device->func->pci(bios->subdev.device)->pdev; | 55 | struct nvkm_device *device = bios->subdev.device; |
56 | struct pci_dev *pdev = device->func->pci(device)->pdev; | ||
47 | struct device_node *dn; | 57 | struct device_node *dn; |
48 | struct priv *priv; | 58 | struct priv *priv; |
49 | if (!(dn = pci_device_to_OF_node(pdev))) | 59 | if (!(dn = pci_device_to_OF_node(pdev))) |
@@ -62,7 +72,10 @@ nvbios_of = { | |||
62 | .init = of_init, | 72 | .init = of_init, |
63 | .fini = (void(*)(void *))kfree, | 73 | .fini = (void(*)(void *))kfree, |
64 | .read = of_read, | 74 | .read = of_read, |
75 | .size = of_size, | ||
65 | .rw = false, | 76 | .rw = false, |
77 | .ignore_checksum = true, | ||
78 | .no_pcir = true, | ||
66 | }; | 79 | }; |
67 | #else | 80 | #else |
68 | const struct nvbios_source | 81 | const struct nvbios_source |