diff options
author | Martin Peres <martin.peres@free.fr> | 2014-03-25 22:23:23 +0100 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-03-26 14:08:26 +1000 |
commit | 18acc6d84eba960804f38a21842c02f3981c1c18 (patch) | |
tree | 40d125954358c0084bf50071af74f1cbe360b134 /drivers/gpu | |
parent | 0e994d645627bb67088ae4860e9a0295b123f7b0 (diff) |
drm/nouveau/bios: fetch the vbios from PROM using only aligned 32-bit accesses
Other kind of accesses are unreliable on Kepler cards. As advised by NVIDIA,
let's only use 32-bit accesses to fetch the vbios from PROM.
This fixes vbios fetching on my nve7 which failed in certain specific
conditions.
I suggest we Cc stable, for all kernels they still maintain after the big
rewrite.
Suggested-by: Christian Zander <czander@nvidia.com>
Signed-off-by: Martin Peres <martin.peres@free.fr>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/bios/base.c | 33 |
1 files changed, 19 insertions, 14 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index 56085304a847..e9df94f96d78 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c @@ -157,6 +157,10 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios) pcireg = 0x001850; access = nv_mask(bios, pcireg, 0x00000001, 0x00000000); + /* WARNING: PROM accesses should always be 32-bits aligned. Other + * accesses work on most chipset but do not on Kepler chipsets + */ + /* bail if no rom signature, with a workaround for a PROM reading * issue on some chipsets. the first read after a period of * inactivity returns the wrong result, so retry the first header @@ -164,31 +168,32 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios) */ i = 16; do { - if (nv_rd08(bios, 0x300000) == 0x55) + if ((nv_rd32(bios, 0x300000) & 0xffff) == 0xaa55) break; } while (i--); - if (!i || nv_rd08(bios, 0x300001) != 0xaa) - goto out; - - /* additional check (see note below) - read PCI record header */ - pcir = nv_rd08(bios, 0x300018) | - nv_rd08(bios, 0x300019) << 8; - if (nv_rd08(bios, 0x300000 + pcir) != 'P' || - nv_rd08(bios, 0x300001 + pcir) != 'C' || - nv_rd08(bios, 0x300002 + pcir) != 'I' || - nv_rd08(bios, 0x300003 + pcir) != 'R') + if (!i) goto out; /* read entire bios image to system memory */ - bios->size = nv_rd08(bios, 0x300002) * 512; + bios->size = ((nv_rd32(bios, 0x300000) >> 16) & 0xff) * 512; if (!bios->size) goto out; bios->data = kmalloc(bios->size, GFP_KERNEL); if (bios->data) { - for (i = 0; i < bios->size; i++) - nv_wo08(bios, i, nv_rd08(bios, 0x300000 + i)); + for (i = 0; i < bios->size; i+=4) + nv_wo32(bios, i, nv_rd32(bios, 0x300000 + i)); + } + + /* check the PCI record header */ + pcir = nv_ro16(bios, 0x0018); + if (bios->data[pcir + 0] != 'P' || + bios->data[pcir + 1] != 'C' || + bios->data[pcir + 2] != 'I' || + bios->data[pcir + 3] != 'R') { + bios->size = 0; + kfree(bios->data); } out: |