Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / winsys / r600 / drm / radeon_bo.c
1 /*
2  * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21  * USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *      Jerome Glisse
25  */
26 #define _FILE_OFFSET_BITS 64
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/mman.h>
31 #include <errno.h>
32 #include "r600_priv.h"
33 #include "xf86drm.h"
34 #include "radeon_drm.h"
35
36 int radeon_bo_fixed_map(struct radeon *radeon, struct radeon_bo *bo)
37 {
38         struct drm_radeon_gem_mmap args;
39         void *ptr;
40         int r;
41
42         /* Zero out args to make valgrind happy */
43         memset(&args, 0, sizeof(args));
44         args.handle = bo->handle;
45         args.offset = 0;
46         args.size = (uint64_t)bo->size;
47         r = drmCommandWriteRead(radeon->fd, DRM_RADEON_GEM_MMAP,
48                                 &args, sizeof(args));
49         if (r) {
50                 fprintf(stderr, "error mapping %p 0x%08X (error = %d)\n",
51                         bo, bo->handle, r);
52                 return r;
53         }
54         ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED, radeon->fd, args.addr_ptr);
55         if (ptr == MAP_FAILED) {
56                 fprintf(stderr, "%s failed to map bo\n", __func__);
57                 return -errno;
58         }
59         bo->data = ptr;
60
61         bo->map_count++;
62         return 0;
63 }
64
65 static void radeon_bo_fixed_unmap(struct radeon *radeon, struct radeon_bo *bo)
66 {
67         if (bo->data) {
68                 munmap(bo->data, bo->size);
69                 bo->data = NULL;
70         }
71 }
72
73 struct radeon_bo *radeon_bo(struct radeon *radeon, unsigned handle,
74                             unsigned size, unsigned alignment, unsigned initial_domain)
75 {
76         struct radeon_bo *bo;
77         int r;
78
79         if (handle) {
80                 pipe_mutex_lock(radeon->bo_handles_mutex);
81                 bo = util_hash_table_get(radeon->bo_handles,
82                                          (void *)(uintptr_t)handle);
83                 if (bo) {
84                         struct radeon_bo *b = NULL;
85                         radeon_bo_reference(radeon, &b, bo);
86                         goto done;
87                 }
88         }
89         bo = calloc(1, sizeof(*bo));
90         if (bo == NULL) {
91                 return NULL;
92         }
93         bo->size = size;
94         bo->handle = handle;
95         pipe_reference_init(&bo->reference, 1);
96         bo->alignment = alignment;
97         LIST_INITHEAD(&bo->fencedlist);
98
99         if (handle) {
100                 struct drm_gem_open open_arg;
101
102                 memset(&open_arg, 0, sizeof(open_arg));
103                 open_arg.name = handle;
104                 r = drmIoctl(radeon->fd, DRM_IOCTL_GEM_OPEN, &open_arg);
105                 if (r != 0) {
106                         free(bo);
107                         return NULL;
108                 }
109                 bo->name = handle;
110                 bo->handle = open_arg.handle;
111                 bo->size = open_arg.size;
112                 bo->shared = TRUE;
113         } else {
114                 struct drm_radeon_gem_create args = {};
115
116                 args.size = size;
117                 args.alignment = alignment;
118                 args.initial_domain = initial_domain;
119                 args.flags = 0;
120                 args.handle = 0;
121                 r = drmCommandWriteRead(radeon->fd, DRM_RADEON_GEM_CREATE,
122                                         &args, sizeof(args));
123                 bo->handle = args.handle;
124                 if (r) {
125                         fprintf(stderr, "Failed to allocate :\n");
126                         fprintf(stderr, "   size      : %d bytes\n", size);
127                         fprintf(stderr, "   alignment : %d bytes\n", alignment);
128                         free(bo);
129                         return NULL;
130                 }
131         }
132
133         if (handle)
134                 util_hash_table_set(radeon->bo_handles, (void *)(uintptr_t)handle, bo);
135 done:
136         if (handle)
137                 pipe_mutex_unlock(radeon->bo_handles_mutex);
138
139         return bo;
140 }
141
142 static void radeon_bo_destroy(struct radeon *radeon, struct radeon_bo *bo)
143 {
144         struct drm_gem_close args;
145
146         if (bo->name) {
147                 pipe_mutex_lock(radeon->bo_handles_mutex);
148                 util_hash_table_remove(radeon->bo_handles,
149                                        (void *)(uintptr_t)bo->name);
150                 pipe_mutex_unlock(radeon->bo_handles_mutex);
151         }
152         LIST_DEL(&bo->fencedlist);
153         radeon_bo_fixed_unmap(radeon, bo);
154         memset(&args, 0, sizeof(args));
155         args.handle = bo->handle;
156         drmIoctl(radeon->fd, DRM_IOCTL_GEM_CLOSE, &args);
157         memset(bo, 0, sizeof(struct radeon_bo));
158         free(bo);
159 }
160
161 void radeon_bo_reference(struct radeon *radeon,
162                          struct radeon_bo **dst,
163                          struct radeon_bo *src)
164 {
165         struct radeon_bo *old = *dst;
166         if (pipe_reference(&(*dst)->reference, &src->reference)) {
167                 radeon_bo_destroy(radeon, old);
168         }
169         *dst = src;
170 }
171
172 int radeon_bo_wait(struct radeon *radeon, struct radeon_bo *bo)
173 {
174         struct drm_radeon_gem_wait_idle args;
175         int ret;
176
177         if (!bo->shared) {
178                 if (!bo->fence)
179                         return 0;
180                 if (bo->fence <= *radeon->cfence) {
181                         LIST_DELINIT(&bo->fencedlist);
182                         bo->fence = 0;
183                         return 0;
184                 }
185         }
186
187         /* Zero out args to make valgrind happy */
188         memset(&args, 0, sizeof(args));
189         args.handle = bo->handle;
190         do {
191                 ret = drmCommandWriteRead(radeon->fd, DRM_RADEON_GEM_WAIT_IDLE,
192                                         &args, sizeof(args));
193         } while (ret == -EBUSY);
194         return ret;
195 }
196
197 int radeon_bo_busy(struct radeon *radeon, struct radeon_bo *bo, uint32_t *domain)
198 {
199         struct drm_radeon_gem_busy args;
200         int ret;
201
202         if (!bo->shared) {
203                 if (!bo->fence)
204                         return 0;
205                 if (bo->fence <= *radeon->cfence) {
206                         LIST_DELINIT(&bo->fencedlist);
207                         bo->fence = 0;
208                         return 0;
209                 }
210         }
211
212         memset(&args, 0, sizeof(args));
213         args.handle = bo->handle;
214         args.domain = 0;
215
216         ret = drmCommandWriteRead(radeon->fd, DRM_RADEON_GEM_BUSY,
217                         &args, sizeof(args));
218
219         *domain = args.domain;
220         return ret;
221 }
222
223 int radeon_bo_get_tiling_flags(struct radeon *radeon,
224                                struct radeon_bo *bo,
225                                uint32_t *tiling_flags,
226                                uint32_t *pitch)
227 {
228         struct drm_radeon_gem_get_tiling args = {};
229         int ret;
230
231         args.handle = bo->handle;
232         ret = drmCommandWriteRead(radeon->fd, DRM_RADEON_GEM_GET_TILING,
233                                   &args, sizeof(args));
234         if (ret)
235                 return ret;
236
237         *tiling_flags = args.tiling_flags;
238         *pitch = args.pitch;
239         return ret;
240 }
241
242 int radeon_bo_get_name(struct radeon *radeon,
243                        struct radeon_bo *bo,
244                        uint32_t *name)
245 {
246         struct drm_gem_flink flink;
247         int ret;
248
249         flink.handle = bo->handle;
250         ret = drmIoctl(radeon->fd, DRM_IOCTL_GEM_FLINK, &flink);
251         if (ret)
252                 return ret;
253
254         *name = flink.name;
255         return ret;
256 }