2 * Copyright 2007 Jérôme Glisse
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
25 * Jerome Glisse <glisse@freedesktop.org>
27 #include "radeon_ms.h"
29 static void radeon_ms_execbuffer_args_clean(struct drm_device *dev,
30 struct drm_buffer_object **buffers,
33 mutex_lock(&dev->struct_mutex);
34 while (args_count--) {
35 drm_bo_usage_deref_locked(&buffers[args_count]);
37 mutex_unlock(&dev->struct_mutex);
40 static int radeon_ms_execbuffer_args(struct drm_device *dev,
41 struct drm_file *file_priv,
42 struct drm_radeon_execbuffer *execbuffer,
43 struct drm_buffer_object **buffers,
46 struct drm_radeon_execbuffer_arg arg;
47 struct drm_bo_arg_rep rep;
48 uint32_t args_count = 0;
50 uint64_t data = execbuffer->args;
54 if (args_count >= execbuffer->args_count) {
55 DRM_ERROR("[radeon_ms] buffer count exceeded %d\n.",
56 execbuffer->args_count);
60 buffers[args_count] = NULL;
61 if (copy_from_user(&arg, (void __user *)((unsigned)data),
62 sizeof(struct drm_radeon_execbuffer_arg))) {
66 mutex_lock(&dev->struct_mutex);
68 drm_lookup_buffer_object(file_priv,
69 arg.d.req.arg_handle, 1);
70 relocs[args_count] = arg.reloc_offset;
71 mutex_unlock(&dev->struct_mutex);
72 if (arg.d.req.op != drm_bo_validate) {
73 DRM_ERROR("[radeon_ms] buffer object operation wasn't "
78 memset(&rep, 0, sizeof(struct drm_bo_arg_rep));
79 if (args_count >= 1) {
80 ret = drm_bo_handle_validate(file_priv,
81 arg.d.req.bo_req.handle,
82 arg.d.req.bo_req.flags,
83 arg.d.req.bo_req.mask,
84 arg.d.req.bo_req.hint,
85 arg.d.req.bo_req.fence_class,
88 &buffers[args_count]);
91 DRM_ERROR("[radeon_ms] error on handle validate %d\n",
98 if (copy_to_user((void __user *)((unsigned)data), &arg,
99 sizeof(struct drm_radeon_execbuffer_arg))) {
106 if (args_count != execbuffer->args_count) {
107 DRM_ERROR("[radeon_ms] not enought buffer got %d waited %d\n.",
108 args_count, execbuffer->args_count);
114 radeon_ms_execbuffer_args_clean(dev, buffers, args_count);
118 static int radeon_ms_execbuffer_check(struct drm_device *dev,
119 struct drm_file *file_priv,
120 struct drm_radeon_execbuffer *execbuffer,
121 struct drm_buffer_object **buffers,
125 uint32_t i, gpu_addr;
128 for (i = 0; i < execbuffer->args_count; i++) {
130 ret = radeon_ms_bo_get_gpu_addr(dev, &buffers[i]->mem,
135 cmd[relocs[i]] |= (gpu_addr) >> 10;
138 for (i = 0; i < execbuffer->cmd_size; i++) {
140 DRM_INFO("cmd[%d]=0x%08X\n", i, cmd[i]);
146 int radeon_ms_execbuffer(struct drm_device *dev, void *data,
147 struct drm_file *file_priv)
149 struct drm_radeon_execbuffer *execbuffer = data;
150 struct drm_fence_arg *fence_arg = &execbuffer->fence_arg;
151 struct drm_buffer_object **buffers;
152 struct drm_bo_kmap_obj cmd_kmap;
153 struct drm_fence_object *fence;
160 ret = drm_bo_read_lock(&dev->bm.bm_lock);
165 relocs = drm_calloc(execbuffer->args_count, sizeof(uint32_t),
167 if (relocs == NULL) {
168 drm_bo_read_unlock(&dev->bm.bm_lock);
171 buffers = drm_calloc(execbuffer->args_count,
172 sizeof(struct drm_buffer_object *),
174 if (buffers == NULL) {
175 drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)),
177 drm_bo_read_unlock(&dev->bm.bm_lock);
180 /* process arguments */
181 ret = radeon_ms_execbuffer_args(dev, file_priv, execbuffer,
184 DRM_ERROR("[radeon_ms] execbuffer wrong arguments\n");
187 /* map command buffer */
188 memset(&cmd_kmap, 0, sizeof(struct drm_bo_kmap_obj));
189 ret = drm_bo_kmap(buffers[0],
191 buffers[0]->mem.num_pages,
194 DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret);
195 goto out_free_release;
197 cmd = drm_bmo_virtual(&cmd_kmap, &cmd_is_iomem);
198 /* do cmd checking & relocations */
199 ret = radeon_ms_execbuffer_check(dev, file_priv, execbuffer,
200 buffers, relocs, cmd);
202 drm_putback_buffer_objects(dev);
203 goto out_free_release;
206 ret = radeon_ms_ring_emit(dev, cmd, execbuffer->cmd_size);
208 drm_putback_buffer_objects(dev);
209 goto out_free_release;
213 if (execbuffer->args_count > 1) {
214 ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence);
216 drm_putback_buffer_objects(dev);
217 DRM_ERROR("[radeon_ms] fence buffer objects failed\n");
218 goto out_free_release;
220 if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) {
221 ret = drm_fence_add_user_object(file_priv, fence,
222 fence_arg->flags & DRM_FENCE_FLAG_SHAREABLE);
224 fence_arg->handle = fence->base.hash.key;
225 fence_arg->fence_class = fence->fence_class;
226 fence_arg->type = fence->type;
227 fence_arg->signaled = fence->signaled_types;
228 fence_arg->sequence = fence->sequence;
231 drm_fence_usage_deref_unlocked(&fence);
234 drm_bo_kunmap(&cmd_kmap);
235 radeon_ms_execbuffer_args_clean(dev, buffers, execbuffer->args_count);
237 drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)),
240 (execbuffer->args_count * sizeof(struct drm_buffer_object *)),
242 drm_bo_read_unlock(&dev->bm.bm_lock);