[PATCH v2] nouveau: fix OpenFirmware support

Laurent Vivier laurent at vivier.eu
Sun Oct 11 07:48:02 PDT 2015


On PowerMac G5 (and I think on all OpenFirmware platforms), nvbios_pcirTp()
returns NULL. But in fact the OpenFirmware has given us the size
we can store in image->size.

The NV34 has a small image and an invalid checksum, we manage this by
changing the size of the header we try to fetch (reduce from 4096 to 1024),
and by setting the image->type from nvbios_of->init(). A type of "1"
avoid to compute the checksum.

This size is stored in bios->size by of_init() as there is no way
to retrieve it otherwise. And as we know the size, copy all data
to bios->data.

Tested on PowerMac G5 with 64bit kernel and a NV43 card (GeForce 6600 LE),
and a NV34 (GeForce FX 5200 Ultra).

Before:

    nouveau 0000:0a:00.0: NVIDIA NV43 (043200a4)
    u3msi: allocated virq 0x19 (hw 0x8) addr 0xf8004080
    nouveau 0000:0a:00.0: Invalid ROM contents
    nouveau 0000:0a:00.0: bios: unable to locate usable image
    nouveau 0000:0a:00.0: bios ctor failed, -22
    nouveau: probe of 0000:0a:00.0 failed with error -22

After:

    nouveau 0000:0a:00.0: NVIDIA NV43 (043200a4)
    u3msi: allocated virq 0x19 (hw 0x8) addr 0xf8004080
    nouveau 0000:0a:00.0: bios: version 05.43.02.75.00
    nouveau 0000:0a:00.0: fb: 128 MiB DDR1
    nouveau 0000:0a:00.0: Using 32-bit DMA via iommu
    [TTM] Zone  kernel: Available graphics memory: 5610528 kiB
    [TTM] Zone   dma32: Available graphics memory: 2097152 kiB
    [TTM] Initializing pool allocator
    [TTM] Initializing DMA pool allocator
    nouveau 0000:0a:00.0: DRM: VRAM: 124 MiB
    nouveau 0000:0a:00.0: DRM: GART: 512 MiB
    nouveau 0000:0a:00.0: DRM: TMDS table version 1.1
    nouveau 0000:0a:00.0: DRM: DCB version 3.0
    nouveau 0000:0a:00.0: DRM: DCB outp 00: 01000100 00000028
    nouveau 0000:0a:00.0: DRM: DCB outp 01: 03000102 00000000
    nouveau 0000:0a:00.0: DRM: DCB outp 02: 04011210 00000028
    nouveau 0000:0a:00.0: DRM: DCB outp 03: 02111212 02000100
    nouveau 0000:0a:00.0: DRM: DCB outp 04: 02011211 0020c070
    nouveau 0000:0a:00.0: DRM: DCB conn 00: 1030
    nouveau 0000:0a:00.0: DRM: DCB conn 01: 2130
    [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
    [drm] Driver supports precise vblank timestamp query.
    nouveau 0000:0a:00.0: DRM: 0x14C5: Parsing digital output script table
    nouveau 0000:0a:00.0: DRM: MM: using M2MF for buffer copies
    nouveau 0000:0a:00.0: DRM: Setting dpms mode 3 on TV encoder (output 4)
    nouveau 0000:0a:00.0: DRM: allocated 1680x1050 fb: 0x30000, bo c00000000399d800
    nouveau 0000:0a:00.0: DRM: 0x14C5: Parsing digital output script table
    Console: switching to colour frame buffer device 210x65
    nouveau 0000:0a:00.0: fb0: nouveaufb frame buffer device
    [drm] Initialized nouveau 1.3.0 20120801 for 0000:0a:00.0 on minor 0

CC: imirkin at alum.mit.edu
Signed-off-by: Laurent Vivier <laurent at vivier.eu>
---
v2: manage NV34: fetch a smaller header size to avoid error,
                 disable checksum from nvbios_of->init()

 drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h  |  1 +
 drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c    | 13 +++++++++++--
 drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c   |  2 +-
 drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c | 12 ++++++++++--
 4 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h
index e39a1fe..785342d 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h
@@ -6,6 +6,7 @@ struct nvkm_bios {
 	struct nvkm_subdev subdev;
 	u32 size;
 	u8 *data;
+	u8 type;
 
 	u32 bmp_offset;
 	u32 bit_offset;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c
index 74b14cf..25588f4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c
@@ -47,8 +47,17 @@ nvbios_imagen(struct nvkm_bios *bios, struct nvbios_image *image)
 		return false;
 	}
 
-	if (!(data = nvbios_pcirTp(bios, image->base, &ver, &hdr, &pcir)))
-		return false;
+	data = nvbios_pcirTp(bios, image->base, &ver, &hdr, &pcir);
+	if (!data) {
+		/* in the case of openfirmware, size, data and type have
+		 * already been set and known from the device tree
+		 */
+		image->size = bios->size;
+		image->type = bios->type;
+		image->last = true;
+
+		return true;
+	}
 	image->size = pcir.image_size;
 	image->type = pcir.image_type;
 	image->last = pcir.last;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c
index 792f017..edc4f23 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c
@@ -55,7 +55,7 @@ shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd)
 	struct nvbios_image image;
 	int score = 1;
 
-	if (!shadow_fetch(bios, mthd, offset + 0x1000)) {
+	if (!shadow_fetch(bios, mthd, offset + 0x400)) {
 		nvkm_debug(subdev, "%08x: header fetch failed\n", offset);
 		return 0;
 	}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c
index bd60d7d..98fde60 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c
@@ -34,7 +34,6 @@ of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
 {
 	struct priv *priv = data;
 	if (offset + length <= priv->size) {
-		memcpy_fromio(bios->data + offset, priv->data + offset, length);
 		return length;
 	}
 	return 0;
@@ -50,8 +49,17 @@ of_init(struct nvkm_bios *bios, const char *name)
 		return ERR_PTR(-ENODEV);
 	if (!(priv = kzalloc(sizeof(*priv), GFP_KERNEL)))
 		return ERR_PTR(-ENOMEM);
-	if ((priv->data = of_get_property(dn, "NVDA,BMP", &priv->size)))
+	priv->data = of_get_property(dn, "NVDA,BMP", &priv->size);
+	if (priv->data) {
+		/* NV34 has an invalid checksum,
+		 * setting type to 1 allows to ignore the checksum
+		 */
+		bios->type = bios->subdev.device->card_type == NV_30;
+		bios->size = (priv->size + 3) & ~3;
+		bios->data = kzalloc(bios->size, GFP_KERNEL);
+		memcpy(bios->data, priv->data, priv->size);
 		return priv;
+	}
 	kfree(priv);
 	return ERR_PTR(-EINVAL);
 }
-- 
2.4.3



More information about the dri-devel mailing list