Home | History | Annotate | Download | only in freedreno
      1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
      2 
      3 /*
      4  * Copyright (C) 2012 Rob Clark <robclark (at) freedesktop.org>
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the next
     14  * paragraph) shall be included in all copies or substantial portions of the
     15  * Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE.
     24  *
     25  * Authors:
     26  *    Rob Clark <robclark (at) freedesktop.org>
     27  */
     28 
     29 #ifdef HAVE_CONFIG_H
     30 # include <config.h>
     31 #endif
     32 
     33 #include "freedreno_drmif.h"
     34 #include "freedreno_priv.h"
     35 
     36 drm_private pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
     37 drm_private void bo_del(struct fd_bo *bo);
     38 
     39 /* set buffer name, and add to table, call w/ table_lock held: */
     40 static void set_name(struct fd_bo *bo, uint32_t name)
     41 {
     42 	bo->name = name;
     43 	/* add ourself into the handle table: */
     44 	drmHashInsert(bo->dev->name_table, name, bo);
     45 }
     46 
     47 /* lookup a buffer, call w/ table_lock held: */
     48 static struct fd_bo * lookup_bo(void *tbl, uint32_t key)
     49 {
     50 	struct fd_bo *bo = NULL;
     51 	if (!drmHashLookup(tbl, key, (void **)&bo)) {
     52 		/* found, incr refcnt and return: */
     53 		bo = fd_bo_ref(bo);
     54 
     55 		/* don't break the bucket if this bo was found in one */
     56 		list_delinit(&bo->list);
     57 	}
     58 	return bo;
     59 }
     60 
     61 /* allocate a new buffer object, call w/ table_lock held */
     62 static struct fd_bo * bo_from_handle(struct fd_device *dev,
     63 		uint32_t size, uint32_t handle)
     64 {
     65 	struct fd_bo *bo;
     66 
     67 	bo = dev->funcs->bo_from_handle(dev, size, handle);
     68 	if (!bo) {
     69 		struct drm_gem_close req = {
     70 				.handle = handle,
     71 		};
     72 		drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
     73 		return NULL;
     74 	}
     75 	bo->dev = fd_device_ref(dev);
     76 	bo->size = size;
     77 	bo->handle = handle;
     78 	atomic_set(&bo->refcnt, 1);
     79 	list_inithead(&bo->list);
     80 	/* add ourself into the handle table: */
     81 	drmHashInsert(dev->handle_table, handle, bo);
     82 	return bo;
     83 }
     84 
     85 struct fd_bo *
     86 fd_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags)
     87 {
     88 	struct fd_bo *bo = NULL;
     89 	uint32_t handle;
     90 	int ret;
     91 
     92 	bo = fd_bo_cache_alloc(&dev->bo_cache, &size, flags);
     93 	if (bo)
     94 		return bo;
     95 
     96 	ret = dev->funcs->bo_new_handle(dev, size, flags, &handle);
     97 	if (ret)
     98 		return NULL;
     99 
    100 	pthread_mutex_lock(&table_lock);
    101 	bo = bo_from_handle(dev, size, handle);
    102 	bo->bo_reuse = TRUE;
    103 	pthread_mutex_unlock(&table_lock);
    104 
    105 	return bo;
    106 }
    107 
    108 struct fd_bo *
    109 fd_bo_from_handle(struct fd_device *dev, uint32_t handle, uint32_t size)
    110 {
    111 	struct fd_bo *bo = NULL;
    112 
    113 	pthread_mutex_lock(&table_lock);
    114 
    115 	bo = lookup_bo(dev->handle_table, handle);
    116 	if (bo)
    117 		goto out_unlock;
    118 
    119 	bo = bo_from_handle(dev, size, handle);
    120 
    121 out_unlock:
    122 	pthread_mutex_unlock(&table_lock);
    123 
    124 	return bo;
    125 }
    126 
    127 struct fd_bo *
    128 fd_bo_from_dmabuf(struct fd_device *dev, int fd)
    129 {
    130 	int ret, size;
    131 	uint32_t handle;
    132 	struct fd_bo *bo;
    133 
    134 	pthread_mutex_lock(&table_lock);
    135 	ret = drmPrimeFDToHandle(dev->fd, fd, &handle);
    136 	if (ret) {
    137 		return NULL;
    138 	}
    139 
    140 	bo = lookup_bo(dev->handle_table, handle);
    141 	if (bo)
    142 		goto out_unlock;
    143 
    144 	/* lseek() to get bo size */
    145 	size = lseek(fd, 0, SEEK_END);
    146 	lseek(fd, 0, SEEK_CUR);
    147 
    148 	bo = bo_from_handle(dev, size, handle);
    149 
    150 out_unlock:
    151 	pthread_mutex_unlock(&table_lock);
    152 
    153 	return bo;
    154 }
    155 
    156 struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name)
    157 {
    158 	struct drm_gem_open req = {
    159 			.name = name,
    160 	};
    161 	struct fd_bo *bo;
    162 
    163 	pthread_mutex_lock(&table_lock);
    164 
    165 	/* check name table first, to see if bo is already open: */
    166 	bo = lookup_bo(dev->name_table, name);
    167 	if (bo)
    168 		goto out_unlock;
    169 
    170 	if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
    171 		ERROR_MSG("gem-open failed: %s", strerror(errno));
    172 		goto out_unlock;
    173 	}
    174 
    175 	bo = lookup_bo(dev->handle_table, req.handle);
    176 	if (bo)
    177 		goto out_unlock;
    178 
    179 	bo = bo_from_handle(dev, req.size, req.handle);
    180 	if (bo)
    181 		set_name(bo, name);
    182 
    183 out_unlock:
    184 	pthread_mutex_unlock(&table_lock);
    185 
    186 	return bo;
    187 }
    188 
    189 struct fd_bo * fd_bo_ref(struct fd_bo *bo)
    190 {
    191 	atomic_inc(&bo->refcnt);
    192 	return bo;
    193 }
    194 
    195 void fd_bo_del(struct fd_bo *bo)
    196 {
    197 	struct fd_device *dev = bo->dev;
    198 
    199 	if (!atomic_dec_and_test(&bo->refcnt))
    200 		return;
    201 
    202 	pthread_mutex_lock(&table_lock);
    203 
    204 	if (bo->bo_reuse && (fd_bo_cache_free(&dev->bo_cache, bo) == 0))
    205 		goto out;
    206 
    207 	bo_del(bo);
    208 	fd_device_del_locked(dev);
    209 out:
    210 	pthread_mutex_unlock(&table_lock);
    211 }
    212 
    213 /* Called under table_lock */
    214 drm_private void bo_del(struct fd_bo *bo)
    215 {
    216 	if (bo->map)
    217 		drm_munmap(bo->map, bo->size);
    218 
    219 	/* TODO probably bo's in bucket list get removed from
    220 	 * handle table??
    221 	 */
    222 
    223 	if (bo->handle) {
    224 		struct drm_gem_close req = {
    225 				.handle = bo->handle,
    226 		};
    227 		drmHashDelete(bo->dev->handle_table, bo->handle);
    228 		if (bo->name)
    229 			drmHashDelete(bo->dev->name_table, bo->name);
    230 		drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
    231 	}
    232 
    233 	bo->funcs->destroy(bo);
    234 }
    235 
    236 int fd_bo_get_name(struct fd_bo *bo, uint32_t *name)
    237 {
    238 	if (!bo->name) {
    239 		struct drm_gem_flink req = {
    240 				.handle = bo->handle,
    241 		};
    242 		int ret;
    243 
    244 		ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
    245 		if (ret) {
    246 			return ret;
    247 		}
    248 
    249 		pthread_mutex_lock(&table_lock);
    250 		set_name(bo, req.name);
    251 		pthread_mutex_unlock(&table_lock);
    252 		bo->bo_reuse = FALSE;
    253 	}
    254 
    255 	*name = bo->name;
    256 
    257 	return 0;
    258 }
    259 
    260 uint32_t fd_bo_handle(struct fd_bo *bo)
    261 {
    262 	return bo->handle;
    263 }
    264 
    265 int fd_bo_dmabuf(struct fd_bo *bo)
    266 {
    267 	int ret, prime_fd;
    268 
    269 	ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC,
    270 			&prime_fd);
    271 	if (ret) {
    272 		ERROR_MSG("failed to get dmabuf fd: %d", ret);
    273 		return ret;
    274 	}
    275 
    276 	bo->bo_reuse = FALSE;
    277 
    278 	return prime_fd;
    279 }
    280 
    281 uint32_t fd_bo_size(struct fd_bo *bo)
    282 {
    283 	return bo->size;
    284 }
    285 
    286 void * fd_bo_map(struct fd_bo *bo)
    287 {
    288 	if (!bo->map) {
    289 		uint64_t offset;
    290 		int ret;
    291 
    292 		ret = bo->funcs->offset(bo, &offset);
    293 		if (ret) {
    294 			return NULL;
    295 		}
    296 
    297 		bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
    298 				bo->dev->fd, offset);
    299 		if (bo->map == MAP_FAILED) {
    300 			ERROR_MSG("mmap failed: %s", strerror(errno));
    301 			bo->map = NULL;
    302 		}
    303 	}
    304 	return bo->map;
    305 }
    306 
    307 /* a bit odd to take the pipe as an arg, but it's a, umm, quirk of kgsl.. */
    308 int fd_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op)
    309 {
    310 	return bo->funcs->cpu_prep(bo, pipe, op);
    311 }
    312 
    313 void fd_bo_cpu_fini(struct fd_bo *bo)
    314 {
    315 	bo->funcs->cpu_fini(bo);
    316 }
    317 
    318 #ifndef HAVE_FREEDRENO_KGSL
    319 struct fd_bo * fd_bo_from_fbdev(struct fd_pipe *pipe, int fbfd, uint32_t size)
    320 {
    321     return NULL;
    322 }
    323 #endif
    324