/** * cik_sdma_ring_test_ring - simple async dma engine test * * @ring: amdgpu_ring structure holding ring information * * Test the DMA engine by writing using it to write an * value to memory. (CIK). * Returns 0 for success, error for failure. */ static int cik_sdma_ring_test_ring(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; unsigned i; unsigned index; int r; u32 tmp; u64 gpu_addr; r = amdgpu_wb_get(adev, &index); if (r) { dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r); return r; } gpu_addr = adev->wb.gpu_addr + (index * 4); tmp = 0xCAFEDEAD; adev->wb.wb[index] = cpu_to_le32(tmp); r = amdgpu_ring_lock(ring, 5); if (r) { DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r); amdgpu_wb_free(adev, index); return r; } amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0)); amdgpu_ring_write(ring, lower_32_bits(gpu_addr)); amdgpu_ring_write(ring, upper_32_bits(gpu_addr)); amdgpu_ring_write(ring, 1); /* number of DWs to follow */ amdgpu_ring_write(ring, 0xDEADBEEF); amdgpu_ring_unlock_commit(ring); for (i = 0; i < adev->usec_timeout; i++) { tmp = le32_to_cpu(adev->wb.wb[index]); if (tmp == 0xDEADBEEF) break; DRM_UDELAY(1); } if (i < adev->usec_timeout) { DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i); } else { DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n", ring->idx, tmp); r = -EINVAL; } amdgpu_wb_free(adev, index); return r; }
static int amdgpu_test_create_and_emit_fence(struct amdgpu_device *adev, struct amdgpu_ring *ring, struct fence **fence) { uint32_t handle = ring->idx ^ 0xdeafbeef; int r; if (ring == &adev->uvd.ring) { r = amdgpu_uvd_get_create_msg(ring, handle, NULL); if (r) { DRM_ERROR("Failed to get dummy create msg\n"); return r; } r = amdgpu_uvd_get_destroy_msg(ring, handle, fence); if (r) { DRM_ERROR("Failed to get dummy destroy msg\n"); return r; } } else if (ring == &adev->vce.ring[0] || ring == &adev->vce.ring[1]) { r = amdgpu_vce_get_create_msg(ring, handle, NULL); if (r) { DRM_ERROR("Failed to get dummy create msg\n"); return r; } r = amdgpu_vce_get_destroy_msg(ring, handle, fence); if (r) { DRM_ERROR("Failed to get dummy destroy msg\n"); return r; } } else { struct amdgpu_fence *a_fence = NULL; r = amdgpu_ring_lock(ring, 64); if (r) { DRM_ERROR("Failed to lock ring A %d\n", ring->idx); return r; } amdgpu_fence_emit(ring, AMDGPU_FENCE_OWNER_UNDEFINED, &a_fence); amdgpu_ring_unlock_commit(ring); *fence = &a_fence->base; } return 0; }
void amdgpu_test_ring_sync(struct amdgpu_device *adev, struct amdgpu_ring *ringA, struct amdgpu_ring *ringB) { struct amdgpu_fence *fence1 = NULL, *fence2 = NULL; struct amdgpu_semaphore *semaphore = NULL; int r; r = amdgpu_semaphore_create(adev, &semaphore); if (r) { DRM_ERROR("Failed to create semaphore\n"); goto out_cleanup; } r = amdgpu_ring_lock(ringA, 64); if (r) { DRM_ERROR("Failed to lock ring A %d\n
/** * amdgpu_ib_schedule - schedule an IB (Indirect Buffer) on the ring * * @adev: amdgpu_device pointer * @num_ibs: number of IBs to schedule * @ibs: IB objects to schedule * @owner: owner for creating the fences * * Schedule an IB on the associated ring (all asics). * Returns 0 on success, error on failure. * * On SI, there are two parallel engines fed from the primary ring, * the CE (Constant Engine) and the DE (Drawing Engine). Since * resource descriptors have moved to memory, the CE allows you to * prime the caches while the DE is updating register state so that * the resource descriptors will be already in cache when the draw is * processed. To accomplish this, the userspace driver submits two * IBs, one for the CE and one for the DE. If there is a CE IB (called * a CONST_IB), it will be put on the ring prior to the DE IB. Prior * to SI there was just a DE IB. */ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs, struct amdgpu_ib *ibs, void *owner) { struct amdgpu_ib *ib = &ibs[0]; struct amdgpu_ring *ring; struct amdgpu_ctx *ctx, *old_ctx; struct amdgpu_vm *vm; unsigned i; int r = 0; if (num_ibs == 0) return -EINVAL; ring = ibs->ring; ctx = ibs->ctx; vm = ibs->vm; if (!ring->ready) { dev_err(adev->dev, "couldn't schedule ib\n"); return -EINVAL; } r = amdgpu_sync_wait(&ibs->sync); if (r) { dev_err(adev->dev, "IB sync failed (%d).\n", r); return r; } r = amdgpu_ring_lock(ring, (256 + AMDGPU_NUM_SYNCS * 8) * num_ibs); if (r) { dev_err(adev->dev, "scheduling IB failed (%d).\n", r); return r; } if (vm) { /* grab a vm id if necessary */ r = amdgpu_vm_grab_id(ibs->vm, ibs->ring, &ibs->sync); if (r) { amdgpu_ring_unlock_undo(ring); return r; } } r = amdgpu_sync_rings(&ibs->sync, ring); if (r) { amdgpu_ring_unlock_undo(ring); dev_err(adev->dev, "failed to sync rings (%d)\n", r); return r; } if (vm) { /* do context switch */ amdgpu_vm_flush(ring, vm, ib->sync.last_vm_update); if (ring->funcs->emit_gds_switch) amdgpu_ring_emit_gds_switch(ring, ib->vm->ids[ring->idx].id, ib->gds_base, ib->gds_size, ib->gws_base, ib->gws_size, ib->oa_base, ib->oa_size); if (ring->funcs->emit_hdp_flush) amdgpu_ring_emit_hdp_flush(ring); } old_ctx = ring->current_ctx; for (i = 0; i < num_ibs; ++i) { ib = &ibs[i]; if (ib->ring != ring || ib->ctx != ctx || ib->vm != vm) { ring->current_ctx = old_ctx; amdgpu_ring_unlock_undo(ring); return -EINVAL; } amdgpu_ring_emit_ib(ring, ib); ring->current_ctx = ctx; } r = amdgpu_fence_emit(ring, owner, &ib->fence); if (r) { dev_err(adev->dev, "failed to emit fence (%d)\n", r); ring->current_ctx = old_ctx; amdgpu_ring_unlock_undo(ring); return r; } if (!amdgpu_enable_scheduler && ib->ctx) ib->sequence = amdgpu_ctx_add_fence(ib->ctx, ring, &ib->fence->base); /* wrap the last IB with fence */ if (ib->user) { uint64_t addr = amdgpu_bo_gpu_offset(ib->user->bo); addr += ib->user->offset; amdgpu_ring_emit_fence(ring, addr, ib->sequence, AMDGPU_FENCE_FLAG_64BIT); } if (ib->vm) amdgpu_vm_fence(adev, ib->vm, &ib->fence->base); amdgpu_ring_unlock_commit(ring); return 0; }
static void amdgpu_test_ring_sync2(struct amdgpu_device *adev, struct amdgpu_ring *ringA, struct amdgpu_ring *ringB, struct amdgpu_ring *ringC) { struct fence *fenceA = NULL, *fenceB = NULL; struct amdgpu_semaphore *semaphore = NULL; bool sigA, sigB; int i, r; r = amdgpu_semaphore_create(adev, &semaphore); if (r) { DRM_ERROR("Failed to create semaphore\n"); goto out_cleanup; } r = amdgpu_ring_lock(ringA, 64); if (r) { DRM_ERROR("Failed to lock ring A %d\n", ringA->idx); goto out_cleanup; } amdgpu_semaphore_emit_wait(ringA, semaphore); amdgpu_ring_unlock_commit(ringA); r = amdgpu_test_create_and_emit_fence(adev, ringA, &fenceA); if (r) goto out_cleanup; r = amdgpu_ring_lock(ringB, 64); if (r) { DRM_ERROR("Failed to lock ring B %d\n", ringB->idx); goto out_cleanup; } amdgpu_semaphore_emit_wait(ringB, semaphore); amdgpu_ring_unlock_commit(ringB); r = amdgpu_test_create_and_emit_fence(adev, ringB, &fenceB); if (r) goto out_cleanup; mdelay(1000); if (fence_is_signaled(fenceA)) { DRM_ERROR("Fence A signaled without waiting for semaphore.\n"); goto out_cleanup; } if (fence_is_signaled(fenceB)) { DRM_ERROR("Fence B signaled without waiting for semaphore.\n"); goto out_cleanup; } r = amdgpu_ring_lock(ringC, 64); if (r) { DRM_ERROR("Failed to lock ring B %p\n", ringC); goto out_cleanup; } amdgpu_semaphore_emit_signal(ringC, semaphore); amdgpu_ring_unlock_commit(ringC); for (i = 0; i < 30; ++i) { mdelay(100); sigA = fence_is_signaled(fenceA); sigB = fence_is_signaled(fenceB); if (sigA || sigB) break; } if (!sigA && !sigB) { DRM_ERROR("Neither fence A nor B has been signaled\n"); goto out_cleanup; } else if (sigA && sigB) { DRM_ERROR("Both fence A and B has been signaled\n"); goto out_cleanup; } DRM_INFO("Fence %c was first signaled\n", sigA ? 'A' : 'B'); r = amdgpu_ring_lock(ringC, 64); if (r) { DRM_ERROR("Failed to lock ring B %p\n", ringC); goto out_cleanup; } amdgpu_semaphore_emit_signal(ringC, semaphore); amdgpu_ring_unlock_commit(ringC); mdelay(1000); r = fence_wait(fenceA, false); if (r) { DRM_ERROR("Failed to wait for sync fence A\n"); goto out_cleanup; } r = fence_wait(fenceB, false); if (r) { DRM_ERROR("Failed to wait for sync fence B\n"); goto out_cleanup; } out_cleanup: amdgpu_semaphore_free(adev, &semaphore, NULL); if (fenceA) fence_put(fenceA); if (fenceB) fence_put(fenceB); if (r) printk(KERN_WARNING "Error while testing ring sync (%d).\n", r); }
void amdgpu_test_ring_sync(struct amdgpu_device *adev, struct amdgpu_ring *ringA, struct amdgpu_ring *ringB) { struct fence *fence1 = NULL, *fence2 = NULL; struct amdgpu_semaphore *semaphore = NULL; int r; r = amdgpu_semaphore_create(adev, &semaphore); if (r) { DRM_ERROR("Failed to create semaphore\n"); goto out_cleanup; } r = amdgpu_ring_lock(ringA, 64); if (r) { DRM_ERROR("Failed to lock ring A %d\n", ringA->idx); goto out_cleanup; } amdgpu_semaphore_emit_wait(ringA, semaphore); amdgpu_ring_unlock_commit(ringA); r = amdgpu_test_create_and_emit_fence(adev, ringA, &fence1); if (r) goto out_cleanup; r = amdgpu_ring_lock(ringA, 64); if (r) { DRM_ERROR("Failed to lock ring A %d\n", ringA->idx); goto out_cleanup; } amdgpu_semaphore_emit_wait(ringA, semaphore); amdgpu_ring_unlock_commit(ringA); r = amdgpu_test_create_and_emit_fence(adev, ringA, &fence2); if (r) goto out_cleanup; mdelay(1000); if (fence_is_signaled(fence1)) { DRM_ERROR("Fence 1 signaled without waiting for semaphore.\n"); goto out_cleanup; } r = amdgpu_ring_lock(ringB, 64); if (r) { DRM_ERROR("Failed to lock ring B %p\n", ringB); goto out_cleanup; } amdgpu_semaphore_emit_signal(ringB, semaphore); amdgpu_ring_unlock_commit(ringB); r = fence_wait(fence1, false); if (r) { DRM_ERROR("Failed to wait for sync fence 1\n"); goto out_cleanup; } mdelay(1000); if (fence_is_signaled(fence2)) { DRM_ERROR("Fence 2 signaled without waiting for semaphore.\n"); goto out_cleanup; } r = amdgpu_ring_lock(ringB, 64); if (r) { DRM_ERROR("Failed to lock ring B %p\n", ringB); goto out_cleanup; } amdgpu_semaphore_emit_signal(ringB, semaphore); amdgpu_ring_unlock_commit(ringB); r = fence_wait(fence2, false); if (r) { DRM_ERROR("Failed to wait for sync fence 1\n"); goto out_cleanup; } out_cleanup: amdgpu_semaphore_free(adev, &semaphore, NULL); if (fence1) fence_put(fence1); if (fence2) fence_put(fence2); if (r) printk(KERN_WARNING "Error while testing ring sync (%d).\n", r); }