1/*
2 * Copyright © 2008 Dave Airlie
3 * Copyright © 2008 Jérôme Glisse
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
18 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * The above copyright notice and this permission notice (including the
24 * next paragraph) shall be included in all copies or substantial portions
25 * of the Software.
26 */
27/*
28 * Authors:
29 *      Dave Airlie
30 *      Jérôme Glisse <glisse@freedesktop.org>
31 */
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35#include <stdio.h>
36#include <stdint.h>
37#include <stdlib.h>
38#include <string.h>
39#include <sys/mman.h>
40#include <sys/ioctl.h>
41#include <errno.h>
42#include "xf86drm.h"
43#include "drm.h"
44#include "radeon_drm.h"
45#include "radeon_bo.h"
46#include "radeon_bo_gem.h"
47
48struct radeon_bo_gem {
49    struct radeon_bo    base;
50    uint32_t            name;
51    int                 map_count;
52    void *priv_ptr;
53};
54
55struct bo_manager_gem {
56    struct radeon_bo_manager    base;
57};
58
59static int bo_wait(struct radeon_bo *bo);
60
61static struct radeon_bo *bo_open(struct radeon_bo_manager *bom,
62                                 uint32_t handle,
63                                 uint32_t size,
64                                 uint32_t alignment,
65                                 uint32_t domains,
66                                 uint32_t flags)
67{
68    struct radeon_bo_gem *bo;
69    int r;
70
71    bo = (struct radeon_bo_gem*)calloc(1, sizeof(struct radeon_bo_gem));
72    if (bo == NULL) {
73        return NULL;
74    }
75
76    bo->base.bom = bom;
77    bo->base.handle = 0;
78    bo->base.size = size;
79    bo->base.alignment = alignment;
80    bo->base.domains = domains;
81    bo->base.flags = flags;
82    bo->base.ptr = NULL;
83    bo->map_count = 0;
84    if (handle) {
85        struct drm_gem_open open_arg;
86
87        memset(&open_arg, 0, sizeof(open_arg));
88        open_arg.name = handle;
89        r = ioctl(bom->fd, DRM_IOCTL_GEM_OPEN, &open_arg);
90        if (r != 0) {
91            free(bo);
92            return NULL;
93        }
94        bo->base.handle = open_arg.handle;
95        bo->base.size = open_arg.size;
96        bo->name = handle;
97    } else {
98        struct drm_radeon_gem_create args;
99
100        args.size = size;
101        args.alignment = alignment;
102        args.initial_domain = bo->base.domains;
103        args.flags = 0;
104        args.handle = 0;
105        r = drmCommandWriteRead(bom->fd, DRM_RADEON_GEM_CREATE,
106                                &args, sizeof(args));
107        bo->base.handle = args.handle;
108        if (r) {
109            fprintf(stderr, "Failed to allocate :\n");
110            fprintf(stderr, "   size      : %d bytes\n", size);
111            fprintf(stderr, "   alignment : %d bytes\n", alignment);
112            fprintf(stderr, "   domains   : %d\n", bo->base.domains);
113            free(bo);
114            return NULL;
115        }
116    }
117    radeon_bo_ref((struct radeon_bo*)bo);
118    return (struct radeon_bo*)bo;
119}
120
121static void bo_ref(struct radeon_bo *bo)
122{
123}
124
125static struct radeon_bo *bo_unref(struct radeon_bo *bo)
126{
127    struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
128    struct drm_gem_close args;
129
130    if (bo == NULL) {
131        return NULL;
132    }
133    if (bo->cref) {
134        return bo;
135    }
136    if (bo_gem->priv_ptr) {
137        munmap(bo_gem->priv_ptr, bo->size);
138    }
139
140    /* close object */
141    args.handle = bo->handle;
142    ioctl(bo->bom->fd, DRM_IOCTL_GEM_CLOSE, &args);
143    memset(bo_gem, 0, sizeof(struct radeon_bo_gem));
144    free(bo_gem);
145    return NULL;
146}
147
148static int bo_map(struct radeon_bo *bo, int write)
149{
150    struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
151    struct drm_radeon_gem_mmap args;
152    int r;
153    void *ptr;
154
155    if (bo_gem->map_count++ != 0) {
156        return 0;
157    }
158    if (bo_gem->priv_ptr) {
159	goto wait;
160    }
161
162    bo->ptr = NULL;
163    args.handle = bo->handle;
164    args.offset = 0;
165    args.size = (uint64_t)bo->size;
166    r = drmCommandWriteRead(bo->bom->fd,
167                            DRM_RADEON_GEM_MMAP,
168                            &args,
169                            sizeof(args));
170    if (r) {
171        fprintf(stderr, "error mapping %p 0x%08X (error = %d)\n",
172                bo, bo->handle, r);
173        return r;
174    }
175    ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED, bo->bom->fd, args.addr_ptr);
176    if (ptr == MAP_FAILED)
177        return -errno;
178    bo_gem->priv_ptr = ptr;
179wait:
180    bo->ptr = bo_gem->priv_ptr;
181    r = bo_wait(bo);
182    if (r)
183	return r;
184    return 0;
185}
186
187static int bo_unmap(struct radeon_bo *bo)
188{
189    struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
190
191    if (--bo_gem->map_count > 0) {
192        return 0;
193    }
194    //munmap(bo->ptr, bo->size);
195    bo->ptr = NULL;
196    return 0;
197}
198
199static int bo_wait(struct radeon_bo *bo)
200{
201    struct drm_radeon_gem_wait_idle args;
202    int ret;
203
204    args.handle = bo->handle;
205    do {
206        ret = drmCommandWriteRead(bo->bom->fd, DRM_RADEON_GEM_WAIT_IDLE,
207                                  &args, sizeof(args));
208    } while (ret == -EBUSY);
209    return ret;
210}
211
212static int bo_is_busy(struct radeon_bo *bo, uint32_t *domain)
213{
214    struct drm_radeon_gem_busy args;
215    int ret;
216
217    args.handle = bo->handle;
218    args.domain = 0;
219
220    ret = drmCommandWriteRead(bo->bom->fd, DRM_RADEON_GEM_BUSY,
221	    &args, sizeof(args));
222
223    *domain = args.domain;
224    return ret;
225}
226
227static int bo_set_tiling(struct radeon_bo *bo, uint32_t tiling_flags,
228				 uint32_t pitch)
229{
230    struct drm_radeon_gem_set_tiling args;
231    int r;
232
233    args.handle = bo->handle;
234    args.tiling_flags = tiling_flags;
235    args.pitch = pitch;
236
237    r = drmCommandWriteRead(bo->bom->fd,
238			    DRM_RADEON_GEM_SET_TILING,
239			    &args,
240			    sizeof(args));
241    return r;
242}
243
244static int bo_get_tiling(struct radeon_bo *bo, uint32_t *tiling_flags,
245				 uint32_t *pitch)
246{
247    struct drm_radeon_gem_set_tiling args;
248    int r;
249
250    args.handle = bo->handle;
251
252    r = drmCommandWriteRead(bo->bom->fd,
253			    DRM_RADEON_GEM_GET_TILING,
254			    &args,
255			    sizeof(args));
256
257    if (r)
258	return r;
259
260    *tiling_flags = args.tiling_flags;
261    *pitch = args.pitch;
262    return r;
263}
264
265static struct radeon_bo_funcs bo_gem_funcs = {
266    bo_open,
267    bo_ref,
268    bo_unref,
269    bo_map,
270    bo_unmap,
271    bo_wait,
272    NULL,
273    bo_set_tiling,
274    bo_get_tiling,
275    bo_is_busy,
276};
277
278struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd)
279{
280    struct bo_manager_gem *bomg;
281
282    bomg = (struct bo_manager_gem*)calloc(1, sizeof(struct bo_manager_gem));
283    if (bomg == NULL) {
284        return NULL;
285    }
286    bomg->base.funcs = &bo_gem_funcs;
287    bomg->base.fd = fd;
288    return (struct radeon_bo_manager*)bomg;
289}
290
291void radeon_bo_manager_gem_dtor(struct radeon_bo_manager *bom)
292{
293    struct bo_manager_gem *bomg = (struct bo_manager_gem*)bom;
294
295    if (bom == NULL) {
296        return;
297    }
298    free(bomg);
299}
300
301uint32_t radeon_gem_name_bo(struct radeon_bo *bo)
302{
303    struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
304    return bo_gem->name;
305}
306
307int radeon_gem_get_kernel_name(struct radeon_bo *bo, uint32_t *name)
308{
309    struct drm_gem_flink flink;
310    int r;
311
312    flink.handle = bo->handle;
313    r = ioctl(bo->bom->fd, DRM_IOCTL_GEM_FLINK, &flink);
314    if (r) {
315	return r;
316    }
317    *name = flink.name;
318    return 0;
319}
320
321int radeon_gem_set_domain(struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain)
322{
323    struct drm_radeon_gem_set_domain args;
324    int r;
325
326    args.handle = bo->handle;
327    args.read_domains = read_domains;
328    args.write_domain = write_domain;
329
330    r = drmCommandWriteRead(bo->bom->fd,
331                            DRM_RADEON_GEM_SET_DOMAIN,
332                            &args,
333                            sizeof(args));
334    return r;
335}
336