etnaviv_bo.c revision 49ef06a4
11.105Sskrll/*
21.1Sichiro * Copyright (C) 2014 Etnaviv Project
31.1Sichiro *
41.1Sichiro * Permission is hereby granted, free of charge, to any person obtaining a
51.1Sichiro * copy of this software and associated documentation files (the "Software"),
61.77Snonaka * to deal in the Software without restriction, including without limitation
71.1Sichiro * the rights to use, copy, modify, merge, publish, distribute, sublicense,
81.19Satatat * and/or sell copies of the Software, and to permit persons to whom the
91.19Satatat * Software is furnished to do so, subject to the following conditions:
101.105Sskrll *
111.1Sichiro * The above copyright notice and this permission notice (including the next
121.1Sichiro * paragraph) shall be included in all copies or substantial portions of the
131.1Sichiro * Software.
141.1Sichiro *
151.1Sichiro * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161.1Sichiro * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171.79Stsutsui * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
181.79Stsutsui * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191.1Sichiro * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
201.1Sichiro * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
211.1Sichiro * SOFTWARE.
221.1Sichiro *
231.61Speter * Authors:
241.1Sichiro *    Christian Gmeiner <christian.gmeiner@gmail.com>
251.1Sichiro */
261.1Sichiro
271.1Sichiro#include "etnaviv_priv.h"
281.1Sichiro#include "etnaviv_drmif.h"
291.1Sichiro
301.1Sichirodrm_private pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
311.1Sichirodrm_private void bo_del(struct etna_bo *bo);
321.1Sichiro
331.1Sichiro/* set buffer name, and add to table, call w/ table_lock held: */
341.1Sichirostatic void set_name(struct etna_bo *bo, uint32_t name)
351.63Sichiro{
361.1Sichiro	bo->name = name;
371.1Sichiro	/* add ourself into the name table: */
381.1Sichiro	drmHashInsert(bo->dev->name_table, name, bo);
391.1Sichiro}
401.1Sichiro
411.1Sichiro/* Called under table_lock */
421.63Sichirodrm_private void bo_del(struct etna_bo *bo)
431.1Sichiro{
441.63Sichiro	if (bo->map)
451.46Schristos		drm_munmap(bo->map, bo->size);
461.63Sichiro
471.54Speter	if (bo->name)
481.1Sichiro		drmHashDelete(bo->dev->name_table, bo->name);
491.1Sichiro
501.82Sbouyer	if (bo->handle) {
511.82Sbouyer		drmHashDelete(bo->dev->handle_table, bo->handle);
521.83Swiz		drmCloseBufferHandle(bo->dev->fd, bo->handle);
531.85Sdholland	}
541.48Stsutsui
551.1Sichiro	free(bo);
561.1Sichiro}
571.1Sichiro
581.1Sichiro/* lookup a buffer from it's handle, call w/ table_lock held: */
591.1Sichirostatic struct etna_bo *lookup_bo(void *tbl, uint32_t handle)
601.1Sichiro{
611.1Sichiro	struct etna_bo *bo = NULL;
621.63Sichiro
631.1Sichiro	if (!drmHashLookup(tbl, handle, (void **)&bo)) {
641.63Sichiro		/* found, incr refcnt and return: */
651.63Sichiro		bo = etna_bo_ref(bo);
661.1Sichiro
671.1Sichiro		/* don't break the bucket if this bo was found in one */
681.1Sichiro		list_delinit(&bo->list);
691.1Sichiro	}
701.10Sabs
711.1Sichiro	return bo;
721.1Sichiro}
731.1Sichiro
741.101Smrg/* allocate a new buffer object, call w/ table_lock held */
751.101Smrgstatic struct etna_bo *bo_from_handle(struct etna_device *dev,
761.1Sichiro		uint32_t size, uint32_t handle, uint32_t flags)
771.1Sichiro{
781.1Sichiro	struct etna_bo *bo = calloc(sizeof(*bo), 1);
791.1Sichiro
801.1Sichiro	if (!bo) {
811.1Sichiro		drmCloseBufferHandle(dev->fd, handle);
821.1Sichiro		return NULL;
831.1Sichiro	}
841.1Sichiro
851.22Stoshii	bo->dev = etna_device_ref(dev);
861.15Slukem	bo->size = size;
871.1Sichiro	bo->handle = handle;
881.1Sichiro	bo->flags = flags;
891.1Sichiro	atomic_set(&bo->refcnt, 1);
901.1Sichiro	list_inithead(&bo->list);
911.1Sichiro	/* add ourselves to the handle table: */
921.1Sichiro	drmHashInsert(dev->handle_table, handle, bo);
931.28Slukem
941.13Sjdolecek	return bo;
951.35Satatat}
961.1Sichiro
971.4Stoshii/* allocate a new (un-tiled) buffer object */
981.4Stoshiidrm_public struct etna_bo *etna_bo_new(struct etna_device *dev, uint32_t size,
991.103Ssevan		uint32_t flags)
1001.103Ssevan{
1011.103Ssevan	struct etna_bo *bo;
1021.103Ssevan	int ret;
1031.103Ssevan	struct drm_etnaviv_gem_new req = {
1041.1Sichiro			.flags = flags,
1051.1Sichiro	};
1061.12Slukem
1071.55Speter	bo = etna_bo_cache_alloc(&dev->bo_cache, &size, flags);
1081.47Speter	if (bo)
1091.105Sskrll		return bo;
1101.99Ssevan
1111.99Ssevan	req.size = size;
1121.1Sichiro	ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GEM_NEW,
1131.1Sichiro			&req, sizeof(req));
1141.99Ssevan	if (ret)
1151.1Sichiro		return NULL;
1161.1Sichiro
1171.2Sichiro	pthread_mutex_lock(&table_lock);
1181.1Sichiro	bo = bo_from_handle(dev, size, req.handle, flags);
1191.1Sichiro	bo->reuse = 1;
1201.1Sichiro	pthread_mutex_unlock(&table_lock);
1211.1Sichiro
1221.34Swiz	return bo;
1231.1Sichiro}
1241.1Sichiro
1251.1Sichirodrm_public struct etna_bo *etna_bo_ref(struct etna_bo *bo)
1261.1Sichiro{
1271.1Sichiro	atomic_inc(&bo->refcnt);
1281.12Slukem
1291.58Speter	return bo;
1301.1Sichiro}
1311.53Speter
1321.12Slukem/* get buffer info */
1331.1Sichirostatic int get_buffer_info(struct etna_bo *bo)
1341.61Speter{
1351.4Stoshii	int ret;
1361.4Stoshii	struct drm_etnaviv_gem_info req = {
1371.4Stoshii		.handle = bo->handle,
1381.4Stoshii	};
1391.4Stoshii
1401.4Stoshii	ret = drmCommandWriteRead(bo->dev->fd, DRM_ETNAVIV_GEM_INFO,
1411.4Stoshii			&req, sizeof(req));
1421.4Stoshii	if (ret) {
1431.4Stoshii		return ret;
1441.63Sichiro	}
1451.63Sichiro
1461.63Sichiro	/* really all we need for now is mmap offset */
1471.63Sichiro	bo->offset = req.offset;
1481.63Sichiro
1491.63Sichiro	return 0;
1501.63Sichiro}
1511.63Sichiro
1521.63Sichiro/* import a buffer object from DRI2 name */
1531.63Sichirodrm_public struct etna_bo *etna_bo_from_name(struct etna_device *dev,
1541.63Sichiro		uint32_t name)
1551.63Sichiro{
1561.63Sichiro	struct etna_bo *bo;
1571.63Sichiro	struct drm_gem_open req = {
1581.63Sichiro		.name = name,
1591.63Sichiro	};
1601.63Sichiro
1611.63Sichiro	pthread_mutex_lock(&table_lock);
1621.63Sichiro
1631.63Sichiro	/* check name table first, to see if bo is already open: */
1641.4Stoshii	bo = lookup_bo(dev->name_table, name);
1651.4Stoshii	if (bo)
1661.33Slukem		goto out_unlock;
1671.32Sbouyer
1681.4Stoshii	if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
1691.4Stoshii		ERROR_MSG("gem-open failed: %s", strerror(errno));
1701.9Stoshii		goto out_unlock;
1711.9Stoshii	}
1721.9Stoshii
1731.63Sichiro	bo = lookup_bo(dev->handle_table, req.handle);
1741.9Stoshii	if (bo)
1751.9Stoshii		goto out_unlock;
1761.4Stoshii
1771.9Stoshii	bo = bo_from_handle(dev, req.size, req.handle, 0);
1781.63Sichiro	if (bo)
1791.4Stoshii		set_name(bo, name);
1801.63Sichiro
1811.63Sichiroout_unlock:
1821.63Sichiro	pthread_mutex_unlock(&table_lock);
1831.63Sichiro
1841.63Sichiro	return bo;
1851.63Sichiro}
1861.23Smanu
1871.63Sichiro/* import a buffer from dmabuf fd, does not take ownership of the
1881.63Sichiro * fd so caller should close() the fd when it is otherwise done
1891.63Sichiro * with it (even if it is still using the 'struct etna_bo *')
1901.63Sichiro */
1911.65Skiyoharadrm_public struct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd)
1921.63Sichiro{
1931.63Sichiro	struct etna_bo *bo;
1941.67Skiyohara	int ret, size;
1951.63Sichiro	uint32_t handle;
1961.65Skiyohara
1971.64Skiyohara	/* take the lock before calling drmPrimeFDToHandle to avoid
1981.63Sichiro	 * racing against etna_bo_del, which might invalidate the
1991.63Sichiro	 * returned handle.
2001.63Sichiro	 */
2011.63Sichiro	pthread_mutex_lock(&table_lock);
2021.63Sichiro
2031.63Sichiro	ret = drmPrimeFDToHandle(dev->fd, fd, &handle);
2041.63Sichiro	if (ret) {
2051.63Sichiro		pthread_mutex_unlock(&table_lock);
2061.63Sichiro		return NULL;
2071.63Sichiro	}
2081.63Sichiro
2091.63Sichiro	bo = lookup_bo(dev->handle_table, handle);
2101.78Splunky	if (bo)
2111.78Splunky		goto out_unlock;
2121.78Splunky
2131.78Splunky	/* lseek() to get bo size */
2141.63Sichiro	size = lseek(fd, 0, SEEK_END);
2151.63Sichiro	lseek(fd, 0, SEEK_CUR);
2161.63Sichiro
2171.50Speter	bo = bo_from_handle(dev, size, handle, 0);
2181.8Stoshii
2191.8Stoshiiout_unlock:
2201.8Stoshii	pthread_mutex_unlock(&table_lock);
2211.26Smanu
2221.87Sabs	return bo;
2231.26Smanu}
2241.50Speter
2251.50Speter/* destroy a buffer object */
2261.50Speterdrm_public void etna_bo_del(struct etna_bo *bo)
2271.50Speter{
2281.50Speter	struct etna_device *dev = bo->dev;
2291.50Speter
2301.50Speter	if (!bo)
2311.50Speter		return;
2321.50Speter
2331.50Speter	if (!atomic_dec_and_test(&bo->refcnt))
2341.8Stoshii		return;
2351.53Speter
2361.5Stoshii	pthread_mutex_lock(&table_lock);
2371.5Stoshii
2381.5Stoshii	if (bo->reuse && (etna_bo_cache_free(&dev->bo_cache, bo) == 0))
2391.53Speter		goto out;
2401.53Speter
2411.8Stoshii	bo_del(bo);
2421.1Sichiro	etna_device_del_locked(dev);
2431.53Speterout:
2441.53Speter	pthread_mutex_unlock(&table_lock);
2451.53Speter}
2461.53Speter
2471.53Speter/* get the global flink/DRI2 buffer name */
2481.53Speterdrm_public int etna_bo_get_name(struct etna_bo *bo, uint32_t *name)
2491.53Speter{
2501.53Speter	if (!bo->name) {
2511.61Speter		struct drm_gem_flink req = {
2521.53Speter			.handle = bo->handle,
2531.53Speter		};
2541.53Speter		int ret;
2551.53Speter
2561.53Speter		ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
2571.53Speter		if (ret) {
2581.53Speter			return ret;
2591.53Speter		}
2601.53Speter
2611.53Speter		pthread_mutex_lock(&table_lock);
2621.91Schristos		set_name(bo, req.name);
2631.103Ssevan		pthread_mutex_unlock(&table_lock);
2641.51Srpaulo		bo->reuse = 0;
2651.52Scube	}
2661.52Scube
2671.52Scube	*name = bo->name;
2681.52Scube
2691.102Smaxv	return 0;
2701.52Scube}
2711.52Scube
2721.57Spaveldrm_public uint32_t etna_bo_handle(struct etna_bo *bo)
2731.47Speter{
2741.1Sichiro	return bo->handle;
2751.1Sichiro}
2761.52Scube
2771.91Schristos/* caller owns the dmabuf fd that is returned and is responsible
2781.91Schristos * to close() it when done
2791.92Schristos */
2801.1Sichirodrm_public int etna_bo_dmabuf(struct etna_bo *bo)
2811.76Spooka{
2821.1Sichiro	int ret, prime_fd;
2831.12Slukem
2841.12Slukem	ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC,
2851.1Sichiro				&prime_fd);
2861.80Shannken	if (ret) {
2871.21Slukem		ERROR_MSG("failed to get dmabuf fd: %d", ret);
2881.47Speter		return ret;
2891.67Skiyohara	}
2901.64Skiyohara
2911.103Ssevan	bo->reuse = 0;
2921.103Ssevan
293	return prime_fd;
294}
295
296drm_public uint32_t etna_bo_size(struct etna_bo *bo)
297{
298	return bo->size;
299}
300
301drm_public void *etna_bo_map(struct etna_bo *bo)
302{
303	if (!bo->map) {
304		if (!bo->offset) {
305			get_buffer_info(bo);
306		}
307
308		bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE,
309				MAP_SHARED, bo->dev->fd, bo->offset);
310		if (bo->map == MAP_FAILED) {
311			ERROR_MSG("mmap failed: %s", strerror(errno));
312			bo->map = NULL;
313		}
314	}
315
316	return bo->map;
317}
318
319drm_public int etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op)
320{
321	struct drm_etnaviv_gem_cpu_prep req = {
322		.handle = bo->handle,
323		.op = op,
324	};
325
326	get_abs_timeout(&req.timeout, 5000000000);
327
328	return drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_PREP,
329			&req, sizeof(req));
330}
331
332drm_public void etna_bo_cpu_fini(struct etna_bo *bo)
333{
334	struct drm_etnaviv_gem_cpu_fini req = {
335		.handle = bo->handle,
336	};
337
338	drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_FINI,
339			&req, sizeof(req));
340}
341