1254885Sdumbbell/*
2254885Sdumbbell * Copyright 2011 Christian K��nig.
3254885Sdumbbell * All Rights Reserved.
4254885Sdumbbell *
5254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a
6254885Sdumbbell * copy of this software and associated documentation files (the
7254885Sdumbbell * "Software"), to deal in the Software without restriction, including
8254885Sdumbbell * without limitation the rights to use, copy, modify, merge, publish,
9254885Sdumbbell * distribute, sub license, and/or sell copies of the Software, and to
10254885Sdumbbell * permit persons to whom the Software is furnished to do so, subject to
11254885Sdumbbell * the following conditions:
12254885Sdumbbell *
13254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
16254885Sdumbbell * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
17254885Sdumbbell * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18254885Sdumbbell * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19254885Sdumbbell * USE OR OTHER DEALINGS IN THE SOFTWARE.
20254885Sdumbbell *
21254885Sdumbbell * The above copyright notice and this permission notice (including the
22254885Sdumbbell * next paragraph) shall be included in all copies or substantial portions
23254885Sdumbbell * of the Software.
24254885Sdumbbell *
25254885Sdumbbell */
26254885Sdumbbell
27254885Sdumbbell#include <sys/cdefs.h>
28254885Sdumbbell__FBSDID("$FreeBSD$");
29254885Sdumbbell
30254885Sdumbbell/*
31254885Sdumbbell * Authors:
32254885Sdumbbell *    Christian K��nig <deathsimple@vodafone.de>
33254885Sdumbbell */
34254885Sdumbbell#include <dev/drm2/drmP.h>
35254885Sdumbbell#include "radeon.h"
36254885Sdumbbell
37254885Sdumbbell
38254885Sdumbbellint radeon_semaphore_create(struct radeon_device *rdev,
39254885Sdumbbell			    struct radeon_semaphore **semaphore)
40254885Sdumbbell{
41254885Sdumbbell	int r;
42254885Sdumbbell
43254885Sdumbbell	*semaphore = malloc(sizeof(struct radeon_semaphore),
44280183Sdumbbell	    DRM_MEM_DRIVER, M_NOWAIT);
45254885Sdumbbell	if (*semaphore == NULL) {
46254885Sdumbbell		return -ENOMEM;
47254885Sdumbbell	}
48254885Sdumbbell	r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo,
49254885Sdumbbell			     &(*semaphore)->sa_bo, 8, 8, true);
50254885Sdumbbell	if (r) {
51254885Sdumbbell		free(*semaphore, DRM_MEM_DRIVER);
52254885Sdumbbell		*semaphore = NULL;
53254885Sdumbbell		return r;
54254885Sdumbbell	}
55254885Sdumbbell	(*semaphore)->waiters = 0;
56254885Sdumbbell	(*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo);
57254885Sdumbbell	*((uint64_t*)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0;
58254885Sdumbbell	return 0;
59254885Sdumbbell}
60254885Sdumbbell
61254885Sdumbbellvoid radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring,
62254885Sdumbbell			          struct radeon_semaphore *semaphore)
63254885Sdumbbell{
64254885Sdumbbell	--semaphore->waiters;
65254885Sdumbbell	radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, false);
66254885Sdumbbell}
67254885Sdumbbell
68254885Sdumbbellvoid radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring,
69254885Sdumbbell			        struct radeon_semaphore *semaphore)
70254885Sdumbbell{
71254885Sdumbbell	++semaphore->waiters;
72254885Sdumbbell	radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, true);
73254885Sdumbbell}
74254885Sdumbbell
75254885Sdumbbell/* caller must hold ring lock */
76254885Sdumbbellint radeon_semaphore_sync_rings(struct radeon_device *rdev,
77254885Sdumbbell				struct radeon_semaphore *semaphore,
78254885Sdumbbell				int signaler, int waiter)
79254885Sdumbbell{
80254885Sdumbbell	int r;
81254885Sdumbbell
82254885Sdumbbell	/* no need to signal and wait on the same ring */
83254885Sdumbbell	if (signaler == waiter) {
84254885Sdumbbell		return 0;
85254885Sdumbbell	}
86254885Sdumbbell
87254885Sdumbbell	/* prevent GPU deadlocks */
88254885Sdumbbell	if (!rdev->ring[signaler].ready) {
89254885Sdumbbell		dev_err(rdev->dev, "Trying to sync to a disabled ring!");
90254885Sdumbbell		return -EINVAL;
91254885Sdumbbell	}
92254885Sdumbbell
93254885Sdumbbell	r = radeon_ring_alloc(rdev, &rdev->ring[signaler], 8);
94254885Sdumbbell	if (r) {
95254885Sdumbbell		return r;
96254885Sdumbbell	}
97254885Sdumbbell	radeon_semaphore_emit_signal(rdev, signaler, semaphore);
98254885Sdumbbell	radeon_ring_commit(rdev, &rdev->ring[signaler]);
99254885Sdumbbell
100254885Sdumbbell	/* we assume caller has already allocated space on waiters ring */
101254885Sdumbbell	radeon_semaphore_emit_wait(rdev, waiter, semaphore);
102254885Sdumbbell
103254885Sdumbbell	/* for debugging lockup only, used by sysfs debug files */
104254885Sdumbbell	rdev->ring[signaler].last_semaphore_signal_addr = semaphore->gpu_addr;
105254885Sdumbbell	rdev->ring[waiter].last_semaphore_wait_addr = semaphore->gpu_addr;
106254885Sdumbbell
107254885Sdumbbell	return 0;
108254885Sdumbbell}
109254885Sdumbbell
110254885Sdumbbellvoid radeon_semaphore_free(struct radeon_device *rdev,
111254885Sdumbbell			   struct radeon_semaphore **semaphore,
112254885Sdumbbell			   struct radeon_fence *fence)
113254885Sdumbbell{
114254885Sdumbbell	if (semaphore == NULL || *semaphore == NULL) {
115254885Sdumbbell		return;
116254885Sdumbbell	}
117254885Sdumbbell	if ((*semaphore)->waiters > 0) {
118254885Sdumbbell		dev_err(rdev->dev, "semaphore %p has more waiters than signalers,"
119254885Sdumbbell			" hardware lockup imminent!\n", *semaphore);
120254885Sdumbbell	}
121254885Sdumbbell	radeon_sa_bo_free(rdev, &(*semaphore)->sa_bo, fence);
122254885Sdumbbell	free(*semaphore, DRM_MEM_DRIVER);
123254885Sdumbbell	*semaphore = NULL;
124254885Sdumbbell}
125