Example #1
0
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;
}
Example #2
0
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);
}
Example #3
0
/**
 * 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;
}
Example #5
0
/**
 * 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);
	}
}
Example #6
0
/**
 * 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;
}
Example #9
0
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;
}
Example #10
0
/**
 * 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;
}
Example #12
0
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);
}
Example #14
0
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);
}
Example #16
0
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;
}
Example #17
0
/**
 * 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);
	}
}
Example #18
0
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;
}
Example #19
0
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;
}
Example #20
0
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);
}
Example #21
0
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);
}
Example #22
0
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;
}
Example #23
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);
}
Example #24
0
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;
}
Example #25
0
/**
 * 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;
}
Example #26
0
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();
}
Example #27
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);
}
Example #28
0
/**
 * 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;
}
Example #29
0
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;
}
Example #30
0
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;
}