aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2010-02-10 20:31:44 -0500
committerBen Skeggs <bskeggs@redhat.com>2010-02-22 22:50:03 -0500
commit531e77139f26e8da32ee694b9ee5e6f4c764f1db (patch)
tree36b279e8fd6ec24be06287fe2f92cfc0505e4e97 /drivers
parent4c27bd339d226175ac0e4dc3ab8289ba696db8be (diff)
drm/nv50: improve vram page table construction
This commit changes nouveau to construct PTEs which look very much like the ones the binary driver creates. I presume that filling multiple PTEs identically with length flags and the physical address of the start of a block of VRAM is a hint to the memory controller that it need not perform additional page table lookups for that range of addresses. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c44
1 files changed, 33 insertions, 11 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 6832c4c969a3..134fedbb7669 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -285,23 +285,45 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
285 uint32_t flags, uint64_t phys) 285 uint32_t flags, uint64_t phys)
286{ 286{
287 struct drm_nouveau_private *dev_priv = dev->dev_private; 287 struct drm_nouveau_private *dev_priv = dev->dev_private;
288 unsigned pages; 288 struct nouveau_gpuobj *pgt;
289 unsigned block;
290 int i;
289 291
290 virt -= dev_priv->vm_vram_base; 292 virt = ((virt - dev_priv->vm_vram_base) >> 16) << 1;
291 pages = size >> 16; 293 size = (size >> 16) << 1;
294 phys |= ((uint64_t)flags << 32) | 1;
292 295
293 dev_priv->engine.instmem.prepare_access(dev, true); 296 dev_priv->engine.instmem.prepare_access(dev, true);
294 while (pages--) { 297 while (size) {
295 struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt[virt >> 29]; 298 unsigned offset_h = upper_32_bits(phys);
296 unsigned pte = ((virt & 0x1fffffffULL) >> 16) << 1;
297 unsigned offset_h = upper_32_bits(phys) & 0xff;
298 unsigned offset_l = lower_32_bits(phys); 299 unsigned offset_l = lower_32_bits(phys);
300 unsigned pte, end;
301
302 for (i = 7; i >= 0; i--) {
303 block = 1 << (i + 1);
304 if (size >= block && !(virt & (block - 1)))
305 break;
306 }
307 offset_l |= (i << 7);
308
309 phys += block << 15;
310 size -= block;
299 311
300 nv_wo32(dev, pt, pte++, offset_l | 1); 312 while (block) {
301 nv_wo32(dev, pt, pte++, offset_h | flags); 313 pgt = dev_priv->vm_vram_pt[virt >> 14];
314 pte = virt & 0x3ffe;
302 315
303 phys += (1 << 16); 316 end = pte + block;
304 virt += (1 << 16); 317 if (end > 16384)
318 end = 16384;
319 block -= (end - pte);
320 virt += (end - pte);
321
322 while (pte < end) {
323 nv_wo32(dev, pgt, pte++, offset_l);
324 nv_wo32(dev, pgt, pte++, offset_h);
325 }
326 }
305 } 327 }
306 dev_priv->engine.instmem.finish_access(dev); 328 dev_priv->engine.instmem.finish_access(dev);
307 329