162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2011 Christian König.
362306a36Sopenharmony_ci * All Rights Reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
662306a36Sopenharmony_ci * copy of this software and associated documentation files (the
762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
962306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1162306a36Sopenharmony_ci * the following conditions:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1462306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1562306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1662306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
1762306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1862306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
1962306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
2262306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
2362306a36Sopenharmony_ci * of the Software.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * Authors:
2862306a36Sopenharmony_ci *    Christian König <deathsimple@vodafone.de>
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include "radeon.h"
3262306a36Sopenharmony_ci#include "radeon_trace.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciint radeon_semaphore_create(struct radeon_device *rdev,
3562306a36Sopenharmony_ci			    struct radeon_semaphore **semaphore)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	int r;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	*semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL);
4062306a36Sopenharmony_ci	if (*semaphore == NULL) {
4162306a36Sopenharmony_ci		return -ENOMEM;
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci	r = radeon_sa_bo_new(&rdev->ring_tmp_bo,
4462306a36Sopenharmony_ci			     &(*semaphore)->sa_bo, 8, 8);
4562306a36Sopenharmony_ci	if (r) {
4662306a36Sopenharmony_ci		kfree(*semaphore);
4762306a36Sopenharmony_ci		*semaphore = NULL;
4862306a36Sopenharmony_ci		return r;
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci	(*semaphore)->waiters = 0;
5162306a36Sopenharmony_ci	(*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	*((uint64_t *)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	return 0;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cibool radeon_semaphore_emit_signal(struct radeon_device *rdev, int ridx,
5962306a36Sopenharmony_ci				  struct radeon_semaphore *semaphore)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[ridx];
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	trace_radeon_semaphore_signale(ridx, semaphore);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (radeon_semaphore_ring_emit(rdev, ridx, ring, semaphore, false)) {
6662306a36Sopenharmony_ci		--semaphore->waiters;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci		/* for debugging lockup only, used by sysfs debug files */
6962306a36Sopenharmony_ci		ring->last_semaphore_signal_addr = semaphore->gpu_addr;
7062306a36Sopenharmony_ci		return true;
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci	return false;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cibool radeon_semaphore_emit_wait(struct radeon_device *rdev, int ridx,
7662306a36Sopenharmony_ci				struct radeon_semaphore *semaphore)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct radeon_ring *ring = &rdev->ring[ridx];
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	trace_radeon_semaphore_wait(ridx, semaphore);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (radeon_semaphore_ring_emit(rdev, ridx, ring, semaphore, true)) {
8362306a36Sopenharmony_ci		++semaphore->waiters;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		/* for debugging lockup only, used by sysfs debug files */
8662306a36Sopenharmony_ci		ring->last_semaphore_wait_addr = semaphore->gpu_addr;
8762306a36Sopenharmony_ci		return true;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci	return false;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_civoid radeon_semaphore_free(struct radeon_device *rdev,
9362306a36Sopenharmony_ci			   struct radeon_semaphore **semaphore,
9462306a36Sopenharmony_ci			   struct radeon_fence *fence)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	if (semaphore == NULL || *semaphore == NULL) {
9762306a36Sopenharmony_ci		return;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci	if ((*semaphore)->waiters > 0) {
10062306a36Sopenharmony_ci		dev_err(rdev->dev, "semaphore %p has more waiters than signalers,"
10162306a36Sopenharmony_ci			" hardware lockup imminent!\n", *semaphore);
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci	radeon_sa_bo_free(&(*semaphore)->sa_bo, fence);
10462306a36Sopenharmony_ci	kfree(*semaphore);
10562306a36Sopenharmony_ci	*semaphore = NULL;
10662306a36Sopenharmony_ci}
107