aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlia Mirkin <imirkin@alum.mit.edu>2015-10-01 23:41:21 -0400
committerBen Skeggs <bskeggs@redhat.com>2015-10-11 23:54:56 -0400
commit25d295882a1adfcdaaad85369289677b87c7c8f0 (patch)
tree3c586938dcc7b2fd9db944db8745f60f72ae5a52
parentf231976c2e8964ceaa9250e57d27c35ff03825c2 (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.h3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c27
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c17
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
14int nvbios_extend(struct nvkm_bios *, u32 length); 17int 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
51static int 51static 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
33of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) 34of_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
45static u32
46of_size(void *data)
47{
48 struct priv *priv = data;
49 return priv->size;
50}
51
43static void * 52static void *
44of_init(struct nvkm_bios *bios, const char *name) 53of_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
68const struct nvbios_source 81const struct nvbios_source