From 916a185331794309f7c791ddff231ce77851f72c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sat, 22 Dec 2012 20:41:14 -0500 Subject: [PATCH] drm/radeon: fix VM flush sequence on cayman (v2) CP changes: - wait for 3D idle - make sure the new VM base address hits the registers - wait for the VM invalidate to finish DMA changes: - wait for the VM invalidate to finish May fix: https://bugs.freedesktop.org/show_bug.cgi?id=58354 https://bugs.freedesktop.org/show_bug.cgi?id=58667 possibly other related issues. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/ni.c | 37 +++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/radeon/nid.h | 9 +++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 896f1cb..e82ece1 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1913,12 +1913,30 @@ void cayman_vm_set_page(struct radeon_device *rdev, uint64_t pe, void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) { struct radeon_ring *ring = &rdev->ring[ridx]; + u32 vm_reg, vm_addr; if (vm == NULL) return; - radeon_ring_write(ring, PACKET0(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2), 0)); - radeon_ring_write(ring, vm->pd_gpu_addr >> 12); + /* wait idle */ + radeon_ring_write(ring, PACKET0(WAIT_UNTIL, 0)); + radeon_ring_write(ring, WAIT_3D_IDLECLEAN); + + vm_reg = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2); + vm_addr = vm->pd_gpu_addr >> 12; + + /* write new vm base */ + radeon_ring_write(ring, PACKET0(vm_reg, 0)); + radeon_ring_write(ring, vm_addr); + + /* wait for the new value to hit the reg */ + radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(ring, 3); /* == */ + radeon_ring_write(ring, vm_reg >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, vm_addr); /* ref */ + radeon_ring_write(ring, 0xfffffff); /* mask */ + radeon_ring_write(ring, 0x10); /* flush hdp cache */ radeon_ring_write(ring, PACKET0(HDP_MEM_COHERENCY_FLUSH_CNTL, 0)); @@ -1928,6 +1946,15 @@ void cayman_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0)); radeon_ring_write(ring, 1 << vm->id); + /* wait for the request bit to clear */ + radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(ring, 3); /* == */ + radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); + radeon_ring_write(ring, 0); + radeon_ring_write(ring, 0); /* ref */ + radeon_ring_write(ring, 1 << vm->id); /* mask */ + radeon_ring_write(ring, 0x10); + /* sync PFP to ME, otherwise we might get invalid PFP reads */ radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); radeon_ring_write(ring, 0x0); @@ -1953,5 +1980,11 @@ void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0)); radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2)); radeon_ring_write(ring, 1 << vm->id); + + /* wait for the request bit to clear */ + radeon_ring_write(ring, DMA_SRBM_READ_PACKET(DMA_PACKET_SRBM_WRITE, 1, 0)); + radeon_ring_write(ring, (0xfff << 20) | (VM_INVALIDATE_REQUEST >> 2)); + radeon_ring_write(ring, 1 << vm->id); /* mask */ + radeon_ring_write(ring, 0); /* value */ } diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index 48e5022..0e0cc8d 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h @@ -252,6 +252,10 @@ #define INSTANCE_BROADCAST_WRITES (1 << 30) #define SE_BROADCAST_WRITES (1 << 31) +#define WAIT_UNTIL 0x8040 +#define WAIT_3D_IDLE (1 << 15) +#define WAIT_3D_IDLECLEAN (1 << 17) + #define SCRATCH_REG0 0x8500 #define SCRATCH_REG1 0x8504 #define SCRATCH_REG2 0x8508 @@ -663,6 +667,11 @@ (((vmid) & 0xF) << 20) | \ (((n) & 0xFFFFF) << 0)) +#define DMA_SRBM_READ_PACKET(cmd, p, n) ((((cmd) & 0xF) << 28) | \ + (1 << 27) | \ + (((p) & 0x1) << 26) | \ + (((n) & 0xFFFFF) << 0)) + /* async DMA Packet types */ #define DMA_PACKET_WRITE 0x2 #define DMA_PACKET_COPY 0x3 -- 1.7.7.5