[Nouveau] [PATCH 4/4] vbios/prom: fetch the vbios using only aligned 32-bit accesses

Martin Peres martin.peres at free.fr
Tue Mar 25 15:11:20 PDT 2014


Other kind of accesses are unreliable on Maxwell 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 at nvidia.com>
Signed-off-by: Martin Peres <martin.peres at free.fr>
---
 nvkm/subdev/bios/base.c | 35 +++++++++++++++++++++++------------
 1 file changed, 23 insertions(+), 12 deletions(-)

diff --git a/nvkm/subdev/bios/base.c b/nvkm/subdev/bios/base.c
index 5608530..baa5687 100644
--- a/nvkm/subdev/bios/base.c
+++ b/nvkm/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,38 @@ 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)
+	if (!i)
 		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')
+	/* check the PCI record header ("PCIR") if its address is aligned */
+	pcir = nv_rd32(bios, 0x300018) & 0xffff;
+	if ((pcir % 4) == 0 && nv_rd32(bios, 0x300000 + pcir) != 0x52494350)
 		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 again, now that we can make
+	 * un-aligned accesses
+	 */
+	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:
-- 
1.9.1



More information about the Nouveau mailing list