Home | History | Annotate | Download | only in radeon
      1 /*
      2  * Copyright  2008 Dave Airlie
      3  * Copyright  2008 Jrme 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  *      Jrme Glisse <glisse (at) freedesktop.org>
     31  */
     32 #include <stdio.h>
     33 #include <stdint.h>
     34 #include <stdlib.h>
     35 #include <string.h>
     36 #include <errno.h>
     37 #include "libdrm_macros.h"
     38 #include "xf86drm.h"
     39 #include "xf86atomic.h"
     40 #include "drm.h"
     41 #include "radeon_drm.h"
     42 #include "radeon_bo.h"
     43 #include "radeon_bo_int.h"
     44 #include "radeon_bo_gem.h"
     45 #include <fcntl.h>
     46 struct radeon_bo_gem {
     47     struct radeon_bo_int    base;
     48     uint32_t                name;
     49     int                     map_count;
     50     atomic_t                reloc_in_cs;
     51     void                    *priv_ptr;
     52 };
     53 
     54 struct bo_manager_gem {
     55     struct radeon_bo_manager    base;
     56 };
     57 
     58 static int bo_wait(struct radeon_bo_int *boi);
     59 
     60 static struct radeon_bo *bo_open(struct radeon_bo_manager *bom,
     61                                  uint32_t handle,
     62                                  uint32_t size,
     63                                  uint32_t alignment,
     64                                  uint32_t domains,
     65                                  uint32_t flags)
     66 {
     67     struct radeon_bo_gem *bo;
     68     int r;
     69 
     70     bo = (struct radeon_bo_gem*)calloc(1, sizeof(struct radeon_bo_gem));
     71     if (bo == NULL) {
     72         return NULL;
     73     }
     74 
     75     bo->base.bom = bom;
     76     bo->base.handle = 0;
     77     bo->base.size = size;
     78     bo->base.alignment = alignment;
     79     bo->base.domains = domains;
     80     bo->base.flags = flags;
     81     bo->base.ptr = NULL;
     82     atomic_set(&bo->reloc_in_cs, 0);
     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 = drmIoctl(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 = flags;
    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 
    121 static void bo_ref(struct radeon_bo_int *boi)
    122 {
    123 }
    124 
    125 static struct radeon_bo *bo_unref(struct radeon_bo_int *boi)
    126 {
    127     struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)boi;
    128     struct drm_gem_close args;
    129 
    130     if (boi->cref) {
    131         return (struct radeon_bo *)boi;
    132     }
    133     if (bo_gem->priv_ptr) {
    134         drm_munmap(bo_gem->priv_ptr, boi->size);
    135     }
    136 
    137     /* Zero out args to make valgrind happy */
    138     memset(&args, 0, sizeof(args));
    139 
    140     /* close object */
    141     args.handle = boi->handle;
    142     drmIoctl(boi->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 
    148 static int bo_map(struct radeon_bo_int *boi, int write)
    149 {
    150     struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)boi;
    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     boi->ptr = NULL;
    163 
    164     /* Zero out args to make valgrind happy */
    165     memset(&args, 0, sizeof(args));
    166     args.handle = boi->handle;
    167     args.offset = 0;
    168     args.size = (uint64_t)boi->size;
    169     r = drmCommandWriteRead(boi->bom->fd,
    170                             DRM_RADEON_GEM_MMAP,
    171                             &args,
    172                             sizeof(args));
    173     if (r) {
    174         fprintf(stderr, "error mapping %p 0x%08X (error = %d)\n",
    175                 boi, boi->handle, r);
    176         return r;
    177     }
    178     ptr = drm_mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED, boi->bom->fd, args.addr_ptr);
    179     if (ptr == MAP_FAILED)
    180         return -errno;
    181     bo_gem->priv_ptr = ptr;
    182 wait:
    183     boi->ptr = bo_gem->priv_ptr;
    184     r = bo_wait(boi);
    185     if (r)
    186         return r;
    187     return 0;
    188 }
    189 
    190 static int bo_unmap(struct radeon_bo_int *boi)
    191 {
    192     struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)boi;
    193 
    194     if (--bo_gem->map_count > 0) {
    195         return 0;
    196     }
    197     //drm_munmap(bo->ptr, bo->size);
    198     boi->ptr = NULL;
    199     return 0;
    200 }
    201 
    202 static int bo_wait(struct radeon_bo_int *boi)
    203 {
    204     struct drm_radeon_gem_wait_idle args;
    205     int ret;
    206 
    207     /* Zero out args to make valgrind happy */
    208     memset(&args, 0, sizeof(args));
    209     args.handle = boi->handle;
    210     do {
    211         ret = drmCommandWrite(boi->bom->fd, DRM_RADEON_GEM_WAIT_IDLE,
    212 			      &args, sizeof(args));
    213     } while (ret == -EBUSY);
    214     return ret;
    215 }
    216 
    217 static int bo_is_busy(struct radeon_bo_int *boi, uint32_t *domain)
    218 {
    219     struct drm_radeon_gem_busy args;
    220     int ret;
    221 
    222     args.handle = boi->handle;
    223     args.domain = 0;
    224 
    225     ret = drmCommandWriteRead(boi->bom->fd, DRM_RADEON_GEM_BUSY,
    226                               &args, sizeof(args));
    227 
    228     *domain = args.domain;
    229     return ret;
    230 }
    231 
    232 static int bo_set_tiling(struct radeon_bo_int *boi, uint32_t tiling_flags,
    233                          uint32_t pitch)
    234 {
    235     struct drm_radeon_gem_set_tiling args;
    236     int r;
    237 
    238     args.handle = boi->handle;
    239     args.tiling_flags = tiling_flags;
    240     args.pitch = pitch;
    241 
    242     r = drmCommandWriteRead(boi->bom->fd,
    243                             DRM_RADEON_GEM_SET_TILING,
    244                             &args,
    245                             sizeof(args));
    246     return r;
    247 }
    248 
    249 static int bo_get_tiling(struct radeon_bo_int *boi, uint32_t *tiling_flags,
    250                          uint32_t *pitch)
    251 {
    252     struct drm_radeon_gem_set_tiling args = {};
    253     int r;
    254 
    255     args.handle = boi->handle;
    256 
    257     r = drmCommandWriteRead(boi->bom->fd,
    258                             DRM_RADEON_GEM_GET_TILING,
    259                             &args,
    260                             sizeof(args));
    261 
    262     if (r)
    263         return r;
    264 
    265     *tiling_flags = args.tiling_flags;
    266     *pitch = args.pitch;
    267     return r;
    268 }
    269 
    270 static const struct radeon_bo_funcs bo_gem_funcs = {
    271     .bo_open = bo_open,
    272     .bo_ref = bo_ref,
    273     .bo_unref = bo_unref,
    274     .bo_map = bo_map,
    275     .bo_unmap = bo_unmap,
    276     .bo_wait = bo_wait,
    277     .bo_is_static = NULL,
    278     .bo_set_tiling = bo_set_tiling,
    279     .bo_get_tiling = bo_get_tiling,
    280     .bo_is_busy = bo_is_busy,
    281     .bo_is_referenced_by_cs = NULL,
    282 };
    283 
    284 struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd)
    285 {
    286     struct bo_manager_gem *bomg;
    287 
    288     bomg = (struct bo_manager_gem*)calloc(1, sizeof(struct bo_manager_gem));
    289     if (bomg == NULL) {
    290         return NULL;
    291     }
    292     bomg->base.funcs = &bo_gem_funcs;
    293     bomg->base.fd = fd;
    294     return (struct radeon_bo_manager*)bomg;
    295 }
    296 
    297 void radeon_bo_manager_gem_dtor(struct radeon_bo_manager *bom)
    298 {
    299     struct bo_manager_gem *bomg = (struct bo_manager_gem*)bom;
    300 
    301     if (bom == NULL) {
    302         return;
    303     }
    304     free(bomg);
    305 }
    306 
    307 uint32_t
    308 radeon_gem_name_bo(struct radeon_bo *bo)
    309 {
    310     struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
    311     return bo_gem->name;
    312 }
    313 
    314 void *
    315 radeon_gem_get_reloc_in_cs(struct radeon_bo *bo)
    316 {
    317     struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
    318     return &bo_gem->reloc_in_cs;
    319 }
    320 
    321 int
    322 radeon_gem_get_kernel_name(struct radeon_bo *bo, uint32_t *name)
    323 {
    324     struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
    325     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
    326     struct drm_gem_flink flink;
    327     int r;
    328 
    329     if (bo_gem->name) {
    330         *name = bo_gem->name;
    331         return 0;
    332     }
    333     flink.handle = bo->handle;
    334     r = drmIoctl(boi->bom->fd, DRM_IOCTL_GEM_FLINK, &flink);
    335     if (r) {
    336         return r;
    337     }
    338     bo_gem->name = flink.name;
    339     *name = flink.name;
    340     return 0;
    341 }
    342 
    343 int
    344 radeon_gem_set_domain(struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain)
    345 {
    346     struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
    347     struct drm_radeon_gem_set_domain args;
    348     int r;
    349 
    350     args.handle = bo->handle;
    351     args.read_domains = read_domains;
    352     args.write_domain = write_domain;
    353 
    354     r = drmCommandWriteRead(boi->bom->fd,
    355                             DRM_RADEON_GEM_SET_DOMAIN,
    356                             &args,
    357                             sizeof(args));
    358     return r;
    359 }
    360 
    361 int radeon_gem_prime_share_bo(struct radeon_bo *bo, int *handle)
    362 {
    363     struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
    364     int ret;
    365 
    366     ret = drmPrimeHandleToFD(bo_gem->base.bom->fd, bo->handle, DRM_CLOEXEC, handle);
    367     return ret;
    368 }
    369 
    370 struct radeon_bo *
    371 radeon_gem_bo_open_prime(struct radeon_bo_manager *bom, int fd_handle, uint32_t size)
    372 {
    373     struct radeon_bo_gem *bo;
    374     int r;
    375     uint32_t handle;
    376 
    377     bo = (struct radeon_bo_gem*)calloc(1, sizeof(struct radeon_bo_gem));
    378     if (bo == NULL) {
    379         return NULL;
    380     }
    381 
    382     bo->base.bom = bom;
    383     bo->base.handle = 0;
    384     bo->base.size = size;
    385     bo->base.alignment = 0;
    386     bo->base.domains = RADEON_GEM_DOMAIN_GTT;
    387     bo->base.flags = 0;
    388     bo->base.ptr = NULL;
    389     atomic_set(&bo->reloc_in_cs, 0);
    390     bo->map_count = 0;
    391 
    392     r = drmPrimeFDToHandle(bom->fd, fd_handle, &handle);
    393     if (r != 0) {
    394 	free(bo);
    395 	return NULL;
    396     }
    397 
    398     bo->base.handle = handle;
    399     bo->name = handle;
    400 
    401     radeon_bo_ref((struct radeon_bo *)bo);
    402     return (struct radeon_bo *)bo;
    403 
    404 }
    405