summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2010-02-11 01:25:53 +0100
committerBen Skeggs <bskeggs@redhat.com>2010-02-23 04:49:58 +0100
commit4c27bd339d226175ac0e4dc3ab8289ba696db8be (patch)
treea6c30ae5e1e5d81d5f9746a6b0a7ca10d6202048
parentdrm/nv50: make nv50_mem_vm_{bind,unbind} operate only on vram (diff)
downloadlinux-4c27bd339d226175ac0e4dc3ab8289ba696db8be.tar.xz
linux-4c27bd339d226175ac0e4dc3ab8289ba696db8be.zip
drm/nv50: more efficient clearing of gpu page table entries
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c68
1 files changed, 44 insertions, 24 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 04885d2fb15f..6832c4c969a3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -291,31 +291,17 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
pages = size >> 16;
dev_priv->engine.instmem.prepare_access(dev, true);
- if (flags & 0x80000000) {
- while (pages--) {
- struct nouveau_gpuobj *pt =
- dev_priv->vm_vram_pt[virt >> 29];
- unsigned pte = ((virt & 0x1fffffffULL) >> 16) << 1;
+ while (pages--) {
+ struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt[virt >> 29];
+ unsigned pte = ((virt & 0x1fffffffULL) >> 16) << 1;
+ unsigned offset_h = upper_32_bits(phys) & 0xff;
+ unsigned offset_l = lower_32_bits(phys);
- nv_wo32(dev, pt, pte++, 0x00000000);
- nv_wo32(dev, pt, pte++, 0x00000000);
+ nv_wo32(dev, pt, pte++, offset_l | 1);
+ nv_wo32(dev, pt, pte++, offset_h | flags);
- virt += (1 << 16);
- }
- } else {
- while (pages--) {
- struct nouveau_gpuobj *pt =
- dev_priv->vm_vram_pt[virt >> 29];
- unsigned pte = ((virt & 0x1fffffffULL) >> 16) << 1;
- unsigned offset_h = upper_32_bits(phys) & 0xff;
- unsigned offset_l = lower_32_bits(phys);
-
- nv_wo32(dev, pt, pte++, offset_l | 1);
- nv_wo32(dev, pt, pte++, offset_h | flags);
-
- phys += (1 << 16);
- virt += (1 << 16);
- }
+ phys += (1 << 16);
+ virt += (1 << 16);
}
dev_priv->engine.instmem.finish_access(dev);
@@ -339,7 +325,41 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
void
nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
{
- nv50_mem_vm_bind_linear(dev, virt, size, 0x80000000, 0);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *pgt;
+ unsigned pages, pte, end;
+
+ virt -= dev_priv->vm_vram_base;
+ pages = (size >> 16) << 1;
+
+ dev_priv->engine.instmem.prepare_access(dev, true);
+ while (pages) {
+ pgt = dev_priv->vm_vram_pt[virt >> 29];
+ pte = (virt & 0x1ffe0000ULL) >> 15;
+
+ end = pte + pages;
+ if (end > 16384)
+ end = 16384;
+ pages -= (end - pte);
+ virt += (end - pte) << 15;
+
+ while (pte < end)
+ nv_wo32(dev, pgt, pte++, 0);
+ }
+ dev_priv->engine.instmem.finish_access(dev);
+
+ nv_wr32(dev, 0x100c80, 0x00050001);
+ if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+ NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
+ return;
+ }
+
+ nv_wr32(dev, 0x100c80, 0x00000001);
+ if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+ NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
+ }
}
/*