d8f678428c4bad54ec26548fef9b4d220700c003
[profile/ivi/libdrm.git] / shared-core / radeon_ms_exec.c
1 /*
2  * Copyright 2007 Jérôme Glisse
3  * All Rights Reserved.
4  *
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:
11  *
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
14  * Software.
15  *
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.
23  *
24  * Authors:
25  *    Jerome Glisse <glisse@freedesktop.org>
26  */
27 #include "radeon_ms.h"
28
29 static void radeon_ms_execbuffer_args_clean(struct drm_device *dev,
30                                             struct drm_buffer_object **buffers,
31                                             uint32_t args_count)
32 {
33         mutex_lock(&dev->struct_mutex);
34         while (args_count--) {
35                 drm_bo_usage_deref_locked(&buffers[args_count]);
36         }
37         mutex_unlock(&dev->struct_mutex);
38 }
39
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,
44                                      uint32_t *relocs)
45 {
46         struct drm_radeon_execbuffer_arg arg;
47         struct drm_bo_arg_rep rep;
48         uint32_t args_count = 0;
49         uint64_t next = 0;
50         uint64_t data = execbuffer->args;
51         int ret = 0;
52
53         do {
54                 if (args_count >= execbuffer->args_count) {
55                         DRM_ERROR("[radeon_ms] buffer count exceeded %d\n.",
56                                   execbuffer->args_count);
57                         ret = -EINVAL;
58                         goto out_err;
59                 }
60                 buffers[args_count] = NULL;
61                 if (copy_from_user(&arg, (void __user *)((unsigned)data),
62                     sizeof(struct drm_radeon_execbuffer_arg))) {
63                         ret = -EFAULT;
64                         goto out_err;
65                 }
66                 mutex_lock(&dev->struct_mutex);
67                 buffers[args_count] =
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 "
74                                   "validate.\n");
75                         ret = -EINVAL;
76                         goto out_err;
77                 }
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,
86                                                      0,
87                                                      &rep.bo_info,
88                                                      &buffers[args_count]);
89                 }
90                 if (ret) {
91                         DRM_ERROR("[radeon_ms] error on handle validate %d\n",
92                                   ret);
93                         rep.ret = ret;
94                         goto out_err;
95                 }
96                 next = arg.next;
97                 arg.d.rep = rep;
98                 if (copy_to_user((void __user *)((unsigned)data), &arg,
99                     sizeof(struct drm_radeon_execbuffer_arg))) {
100                         ret = -EFAULT;
101                         goto out_err;
102                 }
103                 data = next;
104                 args_count++;
105         } while (next != 0);
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);
109                 ret = -EINVAL;
110                 goto out_err;
111         }
112         return 0;
113 out_err:
114         radeon_ms_execbuffer_args_clean(dev, buffers, args_count);
115         return ret;
116 }
117
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,
122                                       uint32_t *relocs,
123                                       uint32_t *cmd)
124 {
125         uint32_t i, gpu_addr;
126         int ret;
127
128         for (i = 0; i < execbuffer->args_count; i++) {
129                 if (relocs[i]) {
130                         ret = radeon_ms_bo_get_gpu_addr(dev, &buffers[i]->mem,
131                                                         &gpu_addr);
132                         if (ret) {
133                                 return ret;
134                         }
135                         cmd[relocs[i]] |= (gpu_addr) >> 10;
136                 }
137         }
138         for (i = 0; i < execbuffer->cmd_size; i++) {
139 #if 0
140                 DRM_INFO("cmd[%d]=0x%08X\n", i, cmd[i]);
141 #endif
142         }
143         return 0;
144 }
145
146 int radeon_ms_execbuffer(struct drm_device *dev, void *data,
147                          struct drm_file *file_priv)
148 {
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;
154         uint32_t *relocs;
155         uint32_t *cmd;
156         int cmd_is_iomem;
157         int ret = 0;
158
159
160         ret = drm_bo_read_lock(&dev->bm.bm_lock);
161         if (ret) {
162                 return ret;
163         }
164
165         relocs = drm_calloc(execbuffer->args_count, sizeof(uint32_t),
166                             DRM_MEM_DRIVER);
167         if (relocs == NULL) {
168                 drm_bo_read_unlock(&dev->bm.bm_lock);
169                 return -ENOMEM;
170         }
171         buffers = drm_calloc(execbuffer->args_count,
172                              sizeof(struct drm_buffer_object *),
173                              DRM_MEM_DRIVER);
174         if (buffers == NULL) {
175                 drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)),
176                          DRM_MEM_DRIVER);
177                 drm_bo_read_unlock(&dev->bm.bm_lock);
178                 return -ENOMEM;
179         }
180         /* process arguments */
181         ret = radeon_ms_execbuffer_args(dev, file_priv, execbuffer,
182                                         buffers, relocs);
183         if (ret) {
184                 DRM_ERROR("[radeon_ms] execbuffer wrong arguments\n");
185                 goto out_free;
186         }
187         /* map command buffer */
188         memset(&cmd_kmap, 0, sizeof(struct drm_bo_kmap_obj));
189         ret = drm_bo_kmap(buffers[0],
190                           0,
191                           buffers[0]->mem.num_pages,
192                           &cmd_kmap);
193         if (ret) {
194                 DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret);
195                 goto out_free_release;
196         }
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);
201         if (ret) {
202                 drm_putback_buffer_objects(dev);
203                 goto out_free_release;
204         }
205
206         ret = radeon_ms_ring_emit(dev, cmd, execbuffer->cmd_size);
207         if (ret) {
208                 drm_putback_buffer_objects(dev);
209                 goto out_free_release;
210         }
211
212         /* fence */
213         ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence);
214         if (ret) {
215                 drm_putback_buffer_objects(dev);
216                 DRM_ERROR("[radeon_ms] fence buffer objects failed\n");
217                 goto out_free_release;
218         }
219         if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) {
220                 ret = drm_fence_add_user_object(file_priv, fence,
221                                                 fence_arg->flags & DRM_FENCE_FLAG_SHAREABLE);
222                 if (!ret) {
223                         fence_arg->handle = fence->base.hash.key;
224                         fence_arg->fence_class = fence->fence_class;
225                         fence_arg->type = fence->type;
226                         fence_arg->signaled = fence->signaled_types;
227                         fence_arg->sequence = fence->sequence;
228                 }
229         }
230         drm_fence_usage_deref_unlocked(&fence);
231 out_free_release:
232         drm_bo_kunmap(&cmd_kmap);
233         radeon_ms_execbuffer_args_clean(dev, buffers, execbuffer->args_count);
234 out_free:
235         drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)),
236                  DRM_MEM_DRIVER);
237         drm_free(buffers,
238                  (execbuffer->args_count * sizeof(struct drm_buffer_object *)),
239                  DRM_MEM_DRIVER);
240         drm_bo_read_unlock(&dev->bm.bm_lock);
241         return ret;
242 }