diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2010-02-10 20:31:44 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-02-22 22:50:03 -0500 |
commit | 531e77139f26e8da32ee694b9ee5e6f4c764f1db (patch) | |
tree | 36b279e8fd6ec24be06287fe2f92cfc0505e4e97 | |
parent | 4c27bd339d226175ac0e4dc3ab8289ba696db8be (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>
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mem.c | 44 |
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 | ||