diff options
author | Martin Peres <martin.peres@free.fr> | 2014-03-25 17:23:23 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-03-26 00:08:26 -0400 |
commit | 18acc6d84eba960804f38a21842c02f3981c1c18 (patch) | |
tree | 40d125954358c0084bf50071af74f1cbe360b134 | |
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>
-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) | |||
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 | ||
194 | out: | 199 | out: |