static int amdgpu_benchmark_do_move(struct amdgpu_device *adev, unsigned size, uint64_t saddr, uint64_t daddr, int n) { unsigned long start_jiffies; unsigned long end_jiffies; struct fence *fence = NULL; int i, r; start_jiffies = jiffies; for (i = 0; i < n; i++) { struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; r = amdgpu_copy_buffer(ring, saddr, daddr, size, NULL, &fence, false); if (r) goto exit_do_move; r = fence_wait(fence, false); if (r) goto exit_do_move; fence_put(fence); } end_jiffies = jiffies; r = jiffies_to_msecs(end_jiffies - start_jiffies); exit_do_move: if (fence) fence_put(fence); return r; }
void reservation_object_add_excl_fence(struct reservation_object *obj, struct fence *fence) { struct fence *old_fence = reservation_object_get_excl(obj); struct reservation_object_list *old; u32 i = 0; old = reservation_object_get_list(obj); if (old) i = old->shared_count; if (fence) fence_get(fence); preempt_disable(); write_seqcount_begin(&obj->seq); /* write_seqcount_begin provides the necessary memory barrier */ RCU_INIT_POINTER(obj->fence_excl, fence); if (old) old->shared_count = 0; write_seqcount_end(&obj->seq); preempt_enable(); /* inplace update, no shared fences */ while (i--) fence_put(rcu_dereference_protected(old->shared[i], reservation_object_held(obj))); if (old_fence) fence_put(old_fence); }
/** * amdgpu_ib_free - free an IB (Indirect Buffer) * * @adev: amdgpu_device pointer * @ib: IB object to free * * Free an IB (all asics). */ void amdgpu_ib_free(struct amdgpu_device *adev, struct amdgpu_ib *ib) { amdgpu_sync_free(adev, &ib->sync, &ib->fence->base); amdgpu_sa_bo_free(adev, &ib->sa_bo, &ib->fence->base); if (ib->fence) fence_put(&ib->fence->base); }
/** * uvd_v6_0_ring_test_ib - test ib execution * * @ring: amdgpu_ring pointer * * Test if we can successfully execute an IB */ static int uvd_v6_0_ring_test_ib(struct amdgpu_ring *ring) { struct fence *fence = NULL; int r; r = amdgpu_uvd_get_create_msg(ring, 1, NULL); if (r) { DRM_ERROR("amdgpu: failed to get create msg (%d).\n", r); goto error; } r = amdgpu_uvd_get_destroy_msg(ring, 1, true, &fence); if (r) { DRM_ERROR("amdgpu: failed to get destroy ib (%d).\n", r); goto error; } r = fence_wait(fence, false); if (r) { DRM_ERROR("amdgpu: fence wait failed (%d).\n", r); goto error; } DRM_INFO("ib test on ring %d succeeded\n", ring->idx); error: fence_put(fence); return r; }
/** * amdgpu_fence_process - check for fence activity * * @ring: pointer to struct amdgpu_ring * * Checks the current fence value and calculates the last * signalled fence value. Wakes the fence queue if the * sequence number has increased. */ void amdgpu_fence_process(struct amdgpu_ring *ring) { struct amdgpu_fence_driver *drv = &ring->fence_drv; uint32_t seq, last_seq; int r; do { last_seq = atomic_read(&ring->fence_drv.last_seq); seq = amdgpu_fence_read(ring); } while (atomic_cmpxchg(&drv->last_seq, last_seq, seq) != last_seq); if (seq != ring->fence_drv.sync_seq) amdgpu_fence_schedule_fallback(ring); while (last_seq != seq) { struct fence *fence, **ptr; ptr = &drv->fences[++last_seq & drv->num_fences_mask]; /* There is always exactly one thread signaling this fence slot */ fence = rcu_dereference_protected(*ptr, 1); RCU_INIT_POINTER(*ptr, NULL); BUG_ON(!fence); r = fence_signal(fence); if (!r) FENCE_TRACE(fence, "signaled from irq context\n"); else BUG(); fence_put(fence); } }
/** * radeon_fence_check_signaled - callback from fence_queue * * this function is called with fence_queue lock held, which is also used * for the fence locking itself, so unlocked variants are used for * fence_signal, and remove_wait_queue. */ static int radeon_fence_check_signaled(wait_queue_t *wait, unsigned mode, int flags, void *key) { struct radeon_fence *fence; u64 seq; fence = container_of(wait, struct radeon_fence, fence_wake); /* * We cannot use radeon_fence_process here because we're already * in the waitqueue, in a call from wake_up_all. */ seq = atomic64_read(&fence->rdev->fence_drv[fence->ring].last_seq); if (seq >= fence->seq) { int ret = fence_signal_locked(&fence->base); if (!ret) FENCE_TRACE(&fence->base, "signaled from irq context\n"); else FENCE_TRACE(&fence->base, "was already signaled\n"); radeon_irq_kms_sw_irq_put(fence->rdev, fence->ring); // __remove_wait_queue(&fence->rdev->fence_queue, &fence->fence_wake); fence_put(&fence->base); } else FENCE_TRACE(&fence->base, "pending\n"); return 0; }
static struct fence *amdgpu_sched_run_job(struct amd_sched_job *sched_job) { struct amdgpu_fence *fence = NULL; struct amdgpu_job *job; int r; if (!sched_job) { DRM_ERROR("job is null\n"); return NULL; } job = to_amdgpu_job(sched_job); mutex_lock(&job->job_lock); r = amdgpu_ib_schedule(job->adev, job->num_ibs, job->ibs, job->base.owner); if (r) { DRM_ERROR("Error scheduling IBs (%d)\n", r); goto err; } fence = job->ibs[job->num_ibs - 1].fence; fence_get(&fence->base); err: if (job->free_job) job->free_job(job); mutex_unlock(&job->job_lock); fence_put(&job->base.s_fence->base); kfree(job); return fence ? &fence->base : NULL; }
/** * uvd_v5_0_ring_test_ib - test ib execution * * @ring: amdgpu_ring pointer * * Test if we can successfully execute an IB */ static int uvd_v5_0_ring_test_ib(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; struct fence *fence = NULL; int r; r = amdgpu_asic_set_uvd_clocks(adev, 53300, 40000); if (r) { DRM_ERROR("amdgpu: failed to raise UVD clocks (%d).\n", r); return r; } r = amdgpu_uvd_get_create_msg(ring, 1, NULL); if (r) { DRM_ERROR("amdgpu: failed to get create msg (%d).\n", r); goto error; } r = amdgpu_uvd_get_destroy_msg(ring, 1, true, &fence); if (r) { DRM_ERROR("amdgpu: failed to get destroy ib (%d).\n", r); goto error; } r = fence_wait(fence, false); if (r) { DRM_ERROR("amdgpu: fence wait failed (%d).\n", r); goto error; } DRM_INFO("ib test on ring %d succeeded\n", ring->idx); error: fence_put(fence); amdgpu_asic_set_uvd_clocks(adev, 0, 0); return r; }
uint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring, struct fence *fence) { struct amdgpu_ctx_ring *cring = & ctx->rings[ring->idx]; uint64_t seq = cring->sequence; unsigned idx = 0; struct fence *other = NULL; idx = seq & (amdgpu_sched_jobs - 1); other = cring->fences[idx]; if (other) { signed long r; r = fence_wait_timeout(other, false, MAX_SCHEDULE_TIMEOUT); if (r < 0) DRM_ERROR("Error (%ld) waiting for fence!\n", r); } fence_get(fence); spin_lock(&ctx->ring_lock); cring->fences[idx] = fence; cring->sequence++; spin_unlock(&ctx->ring_lock); fence_put(other); return seq; }
/** * amdgpu_fence_driver_fini - tear down the fence driver * for all possible rings. * * @adev: amdgpu device pointer * * Tear down the fence driver for all possible rings (all asics). */ void amdgpu_fence_driver_fini(struct amdgpu_device *adev) { unsigned i, j; int r; for (i = 0; i < AMDGPU_MAX_RINGS; i++) { struct amdgpu_ring *ring = adev->rings[i]; if (!ring || !ring->fence_drv.initialized) continue; r = amdgpu_fence_wait_empty(ring); if (r) { /* no need to trigger GPU reset as we are unloading */ amdgpu_fence_driver_force_completion(adev); } amdgpu_irq_put(adev, ring->fence_drv.irq_src, ring->fence_drv.irq_type); amd_sched_fini(&ring->sched); del_timer_sync(&ring->fence_drv.fallback_timer); for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j) fence_put(ring->fence_drv.fences[j]); kfree(ring->fence_drv.fences); ring->fence_drv.initialized = false; } }
static struct fence *amdgpu_job_run(struct amd_sched_job *sched_job) { struct fence *fence = NULL; struct amdgpu_job *job; int r; if (!sched_job) { DRM_ERROR("job is null\n"); return NULL; } job = to_amdgpu_job(sched_job); BUG_ON(amdgpu_sync_peek_fence(&job->sync, NULL)); trace_amdgpu_sched_run_job(job); r = amdgpu_ib_schedule(job->ring, job->num_ibs, job->ibs, job->sync.last_vm_update, job, &fence); if (r) { DRM_ERROR("Error scheduling IBs (%d)\n", r); goto err; } err: /* if gpu reset, hw fence will be replaced here */ fence_put(job->fence); job->fence = fence; return fence; }
static void reservation_object_add_shared_replace(struct reservation_object *obj, struct reservation_object_list *old, struct reservation_object_list *fobj, struct fence *fence) { unsigned i; struct fence *old_fence = NULL; fence_get(fence); if (!old) { RCU_INIT_POINTER(fobj->shared[0], fence); fobj->shared_count = 1; goto done; } /* * no need to bump fence refcounts, rcu_read access * requires the use of kref_get_unless_zero, and the * references from the old struct are carried over to * the new. */ fobj->shared_count = old->shared_count; for (i = 0; i < old->shared_count; ++i) { struct fence *check; check = rcu_dereference_protected(old->shared[i], reservation_object_held(obj)); if (!old_fence && check->context == fence->context) { old_fence = check; RCU_INIT_POINTER(fobj->shared[i], fence); } else RCU_INIT_POINTER(fobj->shared[i], check); } if (!old_fence) { RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); fobj->shared_count++; } done: preempt_disable(); write_seqcount_begin(&obj->seq); /* * RCU_INIT_POINTER can be used here, * seqcount provides the necessary barriers */ RCU_INIT_POINTER(obj->fence, fobj); write_seqcount_end(&obj->seq); preempt_enable(); if (old) kfree_rcu(old, rcu); if (old_fence) fence_put(old_fence); }
void amdgpu_job_free(struct amdgpu_job *job) { amdgpu_job_free_resources(job); fence_put(job->fence); amdgpu_sync_free(&job->sync); kfree(job); }
static int reservation_cb_add_fence_cb(struct drm_reservation_cb *rcb, struct fence *fence) { int ret = 0; struct drm_reservation_fence_cb *fence_cb; struct drm_reservation_fence_cb **new_fence_cbs; new_fence_cbs = krealloc(rcb->fence_cbs, (rcb->num_fence_cbs + 1) * sizeof(struct drm_reservation_fence_cb *), GFP_KERNEL); if (!new_fence_cbs) return -ENOMEM; rcb->fence_cbs = new_fence_cbs; fence_cb = kzalloc(sizeof(struct drm_reservation_fence_cb), GFP_KERNEL); if (!fence_cb) return -ENOMEM; /* * do not want for fence to disappear on us while we are waiting for * callback and we need it in case we want to remove callbacks */ fence_get(fence); fence_cb->fence = fence; fence_cb->parent = rcb; rcb->fence_cbs[rcb->num_fence_cbs] = fence_cb; atomic_inc(&rcb->count); ret = fence_add_callback(fence, &fence_cb->base, reservation_cb_fence_cb); if (ret == -ENOENT) { /* already signaled */ atomic_dec(&rcb->count); fence_put(fence_cb->fence); kfree(fence_cb); ret = 0; } else if (ret < 0) { atomic_dec(&rcb->count); fence_put(fence_cb->fence); kfree(fence_cb); return ret; } else { rcb->num_fence_cbs++; } return ret; }
void amdgpu_job_free_cb(struct amd_sched_job *s_job) { struct amdgpu_job *job = container_of(s_job, struct amdgpu_job, base); fence_put(job->fence); amdgpu_sync_free(&job->sync); kfree(job); }
static void ipu_flip_fence_work_func(struct work_struct *__work) { struct ipu_flip_work *work = container_of(__work, struct ipu_flip_work, fence_work); int i; /* wait for all fences attached to the FB obj to signal */ if (work->excl) { fence_wait(work->excl, false); fence_put(work->excl); } for (i = 0; i < work->shared_count; i++) { fence_wait(work->shared[i], false); fence_put(work->shared[i]); } work->crtc->flip_state = IPU_FLIP_SUBMITTED; }
/** * radeon_fence_unref - remove a ref on a fence * * @fence: radeon fence object * * Remove a reference on a fence (all asics). */ void radeon_fence_unref(struct radeon_fence **fence) { struct radeon_fence *tmp = *fence; *fence = NULL; if (tmp) { fence_put(&tmp->base); } }
int drm_reservation_cb_add(struct drm_reservation_cb *rcb, struct reservation_object *resv, bool exclusive) { int ret = 0; struct fence *fence; unsigned shared_count = 0, f; struct fence **shared_fences = NULL; /* enum all the fences in the reservation and add callbacks */ ret = reservation_object_get_fences_rcu(resv, &fence, &shared_count, &shared_fences); if (ret < 0) return ret; if (fence) { ret = reservation_cb_add_fence_cb(rcb, fence); if (ret < 0) { reservation_cb_cleanup(rcb); goto error; } } if (exclusive) { for (f = 0; f < shared_count; f++) { ret = reservation_cb_add_fence_cb(rcb, shared_fences[f]); if (ret < 0) { reservation_cb_cleanup(rcb); goto error; } } } error: if (fence) fence_put(fence); if (shared_fences) { for (f = 0; f < shared_count; f++) fence_put(shared_fences[f]); kfree(shared_fences); } return ret; }
static int virtio_gpu_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height, int32_t hot_x, int32_t hot_y) { struct virtio_gpu_device *vgdev = crtc->dev->dev_private; struct virtio_gpu_output *output = container_of(crtc, struct virtio_gpu_output, crtc); struct drm_gem_object *gobj = NULL; struct virtio_gpu_object *qobj = NULL; struct virtio_gpu_fence *fence = NULL; int ret = 0; if (handle == 0) { virtio_gpu_hide_cursor(vgdev, output); return 0; } /* lookup the cursor */ gobj = drm_gem_object_lookup(crtc->dev, file_priv, handle); if (gobj == NULL) return -ENOENT; qobj = gem_to_virtio_gpu_obj(gobj); if (!qobj->hw_res_handle) { ret = -EINVAL; goto out; } virtio_gpu_cmd_transfer_to_host_2d(vgdev, qobj->hw_res_handle, 0, cpu_to_le32(64), cpu_to_le32(64), 0, 0, &fence); ret = virtio_gpu_object_reserve(qobj, false); if (!ret) { reservation_object_add_excl_fence(qobj->tbo.resv, &fence->f); fence_put(&fence->f); virtio_gpu_object_unreserve(qobj); virtio_gpu_object_wait(qobj, false); } output->cursor.hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR); output->cursor.resource_id = cpu_to_le32(qobj->hw_res_handle); output->cursor.hot_x = cpu_to_le32(hot_x); output->cursor.hot_y = cpu_to_le32(hot_y); virtio_gpu_cursor_ping(vgdev, output); ret = 0; out: drm_gem_object_unreference_unlocked(gobj); return ret; }
static void sync_file_free(struct kref *kref) { struct sync_file *sync_file = container_of(kref, struct sync_file, kref); if (test_bit(POLL_ENABLED, &sync_file->fence->flags)) fence_remove_callback(sync_file->fence, &sync_file->cb); fence_put(sync_file->fence); kfree(sync_file); }
void amdgpu_job_free(struct amdgpu_job *job) { unsigned i; struct fence *f; /* use sched fence if available */ f = (job->base.s_fence)? &job->base.s_fence->base : job->fence; for (i = 0; i < job->num_ibs; ++i) amdgpu_sa_bo_free(job->adev, &job->ibs[i].sa_bo, f); fence_put(job->fence); amdgpu_bo_unref(&job->uf_bo); amdgpu_sync_free(&job->sync); if (!job->base.use_sched) kfree(job); }
static void reservation_cb_cleanup(struct drm_reservation_cb *rcb) { unsigned cb; for (cb = 0; cb < rcb->num_fence_cbs; cb++) { if (rcb->fence_cbs[cb]) { fence_remove_callback(rcb->fence_cbs[cb]->fence, &rcb->fence_cbs[cb]->base); fence_put(rcb->fence_cbs[cb]->fence); kfree(rcb->fence_cbs[cb]); rcb->fence_cbs[cb] = NULL; } } kfree(rcb->fence_cbs); rcb->fence_cbs = NULL; rcb->num_fence_cbs = 0; }
static void amdgpu_ctx_fini(struct amdgpu_ctx *ctx) { struct amdgpu_device *adev = ctx->adev; unsigned i, j; if (!adev) return; for (i = 0; i < AMDGPU_MAX_RINGS; ++i) for (j = 0; j < amdgpu_sched_jobs; ++j) fence_put(ctx->rings[i].fences[j]); kfree(ctx->fences); ctx->fences = NULL; for (i = 0; i < adev->num_rings; i++) amd_sched_entity_fini(&adev->rings[i]->sched, &ctx->rings[i].entity); }
static inline int reservation_object_test_signaled_single(struct fence *passed_fence) { struct fence *fence, *lfence = passed_fence; int ret = 1; if (!test_bit(FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) { int ret; fence = fence_get_rcu(lfence); if (!fence) return -1; ret = !!fence_is_signaled(fence); fence_put(fence); } return ret; }
/** * amdgpu_fence_wait_empty - wait for all fences to signal * * @adev: amdgpu device pointer * @ring: ring index the fence is associated with * * Wait for all fences on the requested ring to signal (all asics). * Returns 0 if the fences have passed, error for all other cases. */ int amdgpu_fence_wait_empty(struct amdgpu_ring *ring) { uint64_t seq = ACCESS_ONCE(ring->fence_drv.sync_seq); struct fence *fence, **ptr; int r; if (!seq) return 0; ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask]; rcu_read_lock(); fence = rcu_dereference(*ptr); if (!fence || !fence_get_rcu(fence)) { rcu_read_unlock(); return 0; } rcu_read_unlock(); r = fence_wait(fence, false); fence_put(fence); return r; }
static void reservation_object_add_shared_inplace(struct reservation_object *obj, struct reservation_object_list *fobj, struct fence *fence) { u32 i; fence_get(fence); preempt_disable(); write_seqcount_begin(&obj->seq); for (i = 0; i < fobj->shared_count; ++i) { struct fence *old_fence; old_fence = rcu_dereference_protected(fobj->shared[i], reservation_object_held(obj)); if (old_fence->context == fence->context) { /* memory barrier is added by write_seqcount_begin */ RCU_INIT_POINTER(fobj->shared[i], fence); write_seqcount_end(&obj->seq); preempt_enable(); fence_put(old_fence); return; } } /* * memory barrier is added by write_seqcount_begin, * fobj->shared_count is protected by this lock too */ RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); fobj->shared_count++; write_seqcount_end(&obj->seq); preempt_enable(); }
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); }
/** * cik_sdma_ring_test_ib - test an IB on the DMA engine * * @ring: amdgpu_ring structure holding ring information * * Test a simple IB in the DMA ring (CIK). * Returns 0 on success, error on failure. */ static int cik_sdma_ring_test_ib(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; struct amdgpu_ib ib; struct fence *f = NULL; unsigned i; unsigned index; int r; u32 tmp = 0; 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); memset(&ib, 0, sizeof(ib)); r = amdgpu_ib_get(ring, NULL, 256, &ib); if (r) { DRM_ERROR("amdgpu: failed to get ib (%d).\n", r); goto err0; } ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0); ib.ptr[1] = lower_32_bits(gpu_addr); ib.ptr[2] = upper_32_bits(gpu_addr); ib.ptr[3] = 1; ib.ptr[4] = 0xDEADBEEF; ib.length_dw = 5; r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, &ib, 1, NULL, AMDGPU_FENCE_OWNER_UNDEFINED, &f); if (r) goto err1; r = fence_wait(f, false); if (r) { DRM_ERROR("amdgpu: fence wait failed (%d).\n", r); goto err1; } 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("ib test on ring %d succeeded in %u usecs\n", ring->idx, i); goto err1; } else { DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp); r = -EINVAL; } err1: fence_put(f); amdgpu_ib_free(adev, &ib); err0: amdgpu_wb_free(adev, index); return r; }
int reservation_object_get_fences_rcu(struct reservation_object *obj, struct fence **pfence_excl, unsigned *pshared_count, struct fence ***pshared) { unsigned shared_count = 0; unsigned retry = 1; struct fence **shared = NULL, *fence_excl = NULL; int ret = 0; while (retry) { struct reservation_object_list *fobj; unsigned seq; seq = read_seqcount_begin(&obj->seq); rcu_read_lock(); fobj = rcu_dereference(obj->fence); if (fobj) { struct fence **nshared; size_t sz = sizeof(*shared) * fobj->shared_max; nshared = krealloc(shared, sz, GFP_NOWAIT | __GFP_NOWARN); if (!nshared) { rcu_read_unlock(); nshared = krealloc(shared, sz, GFP_KERNEL); if (nshared) { shared = nshared; continue; } ret = -ENOMEM; shared_count = 0; break; } shared = nshared; memcpy(shared, fobj->shared, sz); shared_count = fobj->shared_count; } else shared_count = 0; fence_excl = rcu_dereference(obj->fence_excl); retry = read_seqcount_retry(&obj->seq, seq); if (retry) goto unlock; if (!fence_excl || fence_get_rcu(fence_excl)) { unsigned i; for (i = 0; i < shared_count; ++i) { if (fence_get_rcu(shared[i])) continue; /* uh oh, refcount failed, abort and retry */ while (i--) fence_put(shared[i]); if (fence_excl) { fence_put(fence_excl); fence_excl = NULL; } retry = 1; break; } } else retry = 1; unlock: rcu_read_unlock(); } *pshared_count = shared_count; if (shared_count) *pshared = shared; else { *pshared = NULL; kfree(shared); } *pfence_excl = fence_excl; return ret; }
long reservation_object_wait_timeout_rcu(struct reservation_object *obj, bool wait_all, bool intr, unsigned long timeout) { struct fence *fence; unsigned seq, shared_count, i = 0; long ret = timeout; retry: fence = NULL; shared_count = 0; seq = read_seqcount_begin(&obj->seq); rcu_read_lock(); if (wait_all) { struct reservation_object_list *fobj = rcu_dereference(obj->fence); if (fobj) shared_count = fobj->shared_count; if (read_seqcount_retry(&obj->seq, seq)) goto unlock_retry; for (i = 0; i < shared_count; ++i) { struct fence *lfence = rcu_dereference(fobj->shared[i]); if (test_bit(FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) continue; if (!fence_get_rcu(lfence)) goto unlock_retry; if (fence_is_signaled(lfence)) { fence_put(lfence); continue; } fence = lfence; break; } } if (!shared_count) { struct fence *fence_excl = rcu_dereference(obj->fence_excl); if (read_seqcount_retry(&obj->seq, seq)) goto unlock_retry; if (fence_excl && !test_bit(FENCE_FLAG_SIGNALED_BIT, &fence_excl->flags)) { if (!fence_get_rcu(fence_excl)) goto unlock_retry; if (fence_is_signaled(fence_excl)) fence_put(fence_excl); else fence = fence_excl; } } rcu_read_unlock(); if (fence) { ret = fence_wait_timeout(fence, intr, ret); fence_put(fence); if (ret > 0 && wait_all && (i + 1 < shared_count)) goto retry; } return ret; unlock_retry: rcu_read_unlock(); goto retry; }