18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2011 Christian König.
38c2ecf20Sopenharmony_ci * All Rights Reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the
78c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
88c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
98c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
108c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
118c2ecf20Sopenharmony_ci * the following conditions:
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
148c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
158c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
168c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
178c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
188c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
198c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the
228c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
238c2ecf20Sopenharmony_ci * of the Software.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * Authors:
288c2ecf20Sopenharmony_ci *    Christian König <deathsimple@vodafone.de>
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include "radeon.h"
328c2ecf20Sopenharmony_ci#include "radeon_trace.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ciint radeon_semaphore_create(struct radeon_device *rdev,
358c2ecf20Sopenharmony_ci			    struct radeon_semaphore **semaphore)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	int r;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	*semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL);
408c2ecf20Sopenharmony_ci	if (*semaphore == NULL) {
418c2ecf20Sopenharmony_ci		return -ENOMEM;
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci	r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo,
448c2ecf20Sopenharmony_ci			     &(*semaphore)->sa_bo, 8, 8);
458c2ecf20Sopenharmony_ci	if (r) {
468c2ecf20Sopenharmony_ci		kfree(*semaphore);
478c2ecf20Sopenharmony_ci		*semaphore = NULL;
488c2ecf20Sopenharmony_ci		return r;
498c2ecf20Sopenharmony_ci	}
508c2ecf20Sopenharmony_ci	(*semaphore)->waiters = 0;
518c2ecf20Sopenharmony_ci	(*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	*((uint64_t *)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return 0;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cibool radeon_semaphore_emit_signal(struct radeon_device *rdev, int ridx,
598c2ecf20Sopenharmony_ci				  struct radeon_semaphore *semaphore)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[ridx];
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	trace_radeon_semaphore_signale(ridx, semaphore);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	if (radeon_semaphore_ring_emit(rdev, ridx, ring, semaphore, false)) {
668c2ecf20Sopenharmony_ci		--semaphore->waiters;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci		/* for debugging lockup only, used by sysfs debug files */
698c2ecf20Sopenharmony_ci		ring->last_semaphore_signal_addr = semaphore->gpu_addr;
708c2ecf20Sopenharmony_ci		return true;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci	return false;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cibool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ridx,
768c2ecf20Sopenharmony_ci				struct radeon_semaphore *semaphore)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[ridx];
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	trace_radeon_semaphore_wait(ridx, semaphore);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (radeon_semaphore_ring_emit(rdev, ridx, ring, semaphore, true)) {
838c2ecf20Sopenharmony_ci		++semaphore->waiters;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		/* for debugging lockup only, used by sysfs debug files */
868c2ecf20Sopenharmony_ci		ring->last_semaphore_wait_addr = semaphore->gpu_addr;
878c2ecf20Sopenharmony_ci		return true;
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci	return false;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_civoid radeon_semaphore_free(struct radeon_device *rdev,
938c2ecf20Sopenharmony_ci			   struct radeon_semaphore **semaphore,
948c2ecf20Sopenharmony_ci			   struct radeon_fence *fence)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	if (semaphore == NULL || *semaphore == NULL) {
978c2ecf20Sopenharmony_ci		return;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci	if ((*semaphore)->waiters > 0) {
1008c2ecf20Sopenharmony_ci		dev_err(rdev->dev, "semaphore %p has more waiters than signalers,"
1018c2ecf20Sopenharmony_ci			" hardware lockup imminent!\n", *semaphore);
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci	radeon_sa_bo_free(rdev, &(*semaphore)->sa_bo, fence);
1048c2ecf20Sopenharmony_ci	kfree(*semaphore);
1058c2ecf20Sopenharmony_ci	*semaphore = NULL;
1068c2ecf20Sopenharmony_ci}
107