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.
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). 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 Signed-off-by: Laurent Vivier <laurent at vivier.eu> --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c | 10 ++++++++-- drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c | 8 ++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c index 74b14cf..17ba0c726 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c @@ -47,8 +47,14 @@ 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) { + image->size = bios->size; + image->type = 0x00; + 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/shadowof.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c index bd60d7d..d4c8801 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,13 @@ 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) { + bios->size = (priv->size + 3) & ~3; + bios->data = kmalloc(bios->size, GFP_KERNEL); + memcpy(bios->data, priv->data, priv->size); return priv; + } kfree(priv); return ERR_PTR(-EINVAL); } -- 2.4.3