aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Peres <martin.peres@free.fr>2014-03-25 17:23:23 -0400
committerBen Skeggs <bskeggs@redhat.com>2014-03-26 00:08:26 -0400
commit18acc6d84eba960804f38a21842c02f3981c1c18 (patch)
tree40d125954358c0084bf50071af74f1cbe360b134
parent0e994d645627bb67088ae4860e9a0295b123f7b0 (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>
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/base.c33
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)
157 pcireg = 0x001850; 157 pcireg = 0x001850;
158 access = nv_mask(bios, pcireg, 0x00000001, 0x00000000); 158 access = nv_mask(bios, pcireg, 0x00000001, 0x00000000);
159 159
160 /* WARNING: PROM accesses should always be 32-bits aligned. Other
161 * accesses work on most chipset but do not on Kepler chipsets
162 */
163
160 /* bail if no rom signature, with a workaround for a PROM reading 164 /* bail if no rom signature, with a workaround for a PROM reading
161 * issue on some chipsets. the first read after a period of 165 * issue on some chipsets. the first read after a period of
162 * inactivity returns the wrong result, so retry the first header 166 * inactivity returns the wrong result, so retry the first header
@@ -164,31 +168,32 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios)
164 */ 168 */
165 i = 16; 169 i = 16;
166 do { 170 do {
167 if (nv_rd08(bios, 0x300000) == 0x55) 171 if ((nv_rd32(bios, 0x300000) & 0xffff) == 0xaa55)
168 break; 172 break;
169 } while (i--); 173 } while (i--);
170 174
171 if (!i || nv_rd08(bios, 0x300001) != 0xaa) 175 if (!i)
172 goto out;
173
174 /* additional check (see note below) - read PCI record header */
175 pcir = nv_rd08(bios, 0x300018) |
176 nv_rd08(bios, 0x300019) << 8;
177 if (nv_rd08(bios, 0x300000 + pcir) != 'P' ||
178 nv_rd08(bios, 0x300001 + pcir) != 'C' ||
179 nv_rd08(bios, 0x300002 + pcir) != 'I' ||
180 nv_rd08(bios, 0x300003 + pcir) != 'R')
181 goto out; 176 goto out;
182 177
183 /* read entire bios image to system memory */ 178 /* read entire bios image to system memory */
184 bios->size = nv_rd08(bios, 0x300002) * 512; 179 bios->size = ((nv_rd32(bios, 0x300000) >> 16) & 0xff) * 512;
185 if (!bios->size) 180 if (!bios->size)
186 goto out; 181 goto out;
187 182
188 bios->data = kmalloc(bios->size, GFP_KERNEL); 183 bios->data = kmalloc(bios->size, GFP_KERNEL);
189 if (bios->data) { 184 if (bios->data) {
190 for (i = 0; i < bios->size; i++) 185 for (i = 0; i < bios->size; i+=4)
191 nv_wo08(bios, i, nv_rd08(bios, 0x300000 + i)); 186 nv_wo32(bios, i, nv_rd32(bios, 0x300000 + i));
187 }
188
189 /* check the PCI record header */
190 pcir = nv_ro16(bios, 0x0018);
191 if (bios->data[pcir + 0] != 'P' ||
192 bios->data[pcir + 1] != 'C' ||
193 bios->data[pcir + 2] != 'I' ||
194 bios->data[pcir + 3] != 'R') {
195 bios->size = 0;
196 kfree(bios->data);
192 } 197 }
193 198
194out: 199out: