17ec681f3Smrg/*
27ec681f3Smrg * Copyright (C) 2014 Etnaviv Project
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
207ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
217ec681f3Smrg * SOFTWARE.
227ec681f3Smrg *
237ec681f3Smrg * Authors:
247ec681f3Smrg *    Christian Gmeiner <christian.gmeiner@gmail.com>
257ec681f3Smrg */
267ec681f3Smrg
277ec681f3Smrg#include "util/hash_table.h"
287ec681f3Smrg#include "util/os_file.h"
297ec681f3Smrg
307ec681f3Smrg#include "etnaviv_priv.h"
317ec681f3Smrg#include "etnaviv_drmif.h"
327ec681f3Smrg
337ec681f3Smrgstruct etna_device *etna_device_new(int fd)
347ec681f3Smrg{
357ec681f3Smrg	struct etna_device *dev;
367ec681f3Smrg	struct drm_etnaviv_param req = {
377ec681f3Smrg		.param = ETNAVIV_PARAM_SOFTPIN_START_ADDR,
387ec681f3Smrg	};
397ec681f3Smrg	drmVersionPtr version;
407ec681f3Smrg	int ret;
417ec681f3Smrg
427ec681f3Smrg	version = drmGetVersion(fd);
437ec681f3Smrg	if (!version) {
447ec681f3Smrg		ERROR_MSG("cannot get version: %s", strerror(errno));
457ec681f3Smrg		return NULL;
467ec681f3Smrg	}
477ec681f3Smrg
487ec681f3Smrg	dev = calloc(sizeof(*dev), 1);
497ec681f3Smrg	if (!dev) {
507ec681f3Smrg		goto out;
517ec681f3Smrg	}
527ec681f3Smrg
537ec681f3Smrg	dev->drm_version = ETNA_DRM_VERSION(version->version_major,
547ec681f3Smrg					    version->version_minor);
557ec681f3Smrg
567ec681f3Smrgout:
577ec681f3Smrg	drmFreeVersion(version);
587ec681f3Smrg
597ec681f3Smrg	if (!dev)
607ec681f3Smrg		return NULL;
617ec681f3Smrg
627ec681f3Smrg	p_atomic_set(&dev->refcnt, 1);
637ec681f3Smrg	dev->fd = fd;
647ec681f3Smrg	dev->handle_table = _mesa_hash_table_create(NULL, _mesa_hash_u32, _mesa_key_u32_equal);
657ec681f3Smrg	dev->name_table = _mesa_hash_table_create(NULL, _mesa_hash_u32, _mesa_key_u32_equal);
667ec681f3Smrg	etna_bo_cache_init(&dev->bo_cache);
677ec681f3Smrg
687ec681f3Smrg	ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GET_PARAM, &req, sizeof(req));
697ec681f3Smrg	if (!ret && req.value != ~0ULL) {
707ec681f3Smrg		const uint64_t _4GB = 1ull << 32;
717ec681f3Smrg
727ec681f3Smrg		util_vma_heap_init(&dev->address_space, req.value, _4GB - req.value);
737ec681f3Smrg		dev->use_softpin = 1;
747ec681f3Smrg	}
757ec681f3Smrg
767ec681f3Smrg	return dev;
777ec681f3Smrg}
787ec681f3Smrg
797ec681f3Smrg/* like etna_device_new() but creates it's own private dup() of the fd
807ec681f3Smrg * which is close()d when the device is finalized. */
817ec681f3Smrgstruct etna_device *etna_device_new_dup(int fd)
827ec681f3Smrg{
837ec681f3Smrg	int dup_fd = os_dupfd_cloexec(fd);
847ec681f3Smrg	struct etna_device *dev = etna_device_new(dup_fd);
857ec681f3Smrg
867ec681f3Smrg	if (dev)
877ec681f3Smrg		dev->closefd = 1;
887ec681f3Smrg	else
897ec681f3Smrg		close(dup_fd);
907ec681f3Smrg
917ec681f3Smrg	return dev;
927ec681f3Smrg}
937ec681f3Smrg
947ec681f3Smrgstruct etna_device *etna_device_ref(struct etna_device *dev)
957ec681f3Smrg{
967ec681f3Smrg	p_atomic_inc(&dev->refcnt);
977ec681f3Smrg
987ec681f3Smrg	return dev;
997ec681f3Smrg}
1007ec681f3Smrg
1017ec681f3Smrgstatic void etna_device_del_impl(struct etna_device *dev)
1027ec681f3Smrg{
1037ec681f3Smrg	etna_bo_cache_cleanup(&dev->bo_cache, 0);
1047ec681f3Smrg
1057ec681f3Smrg	if (dev->use_softpin)
1067ec681f3Smrg		util_vma_heap_finish(&dev->address_space);
1077ec681f3Smrg
1087ec681f3Smrg	_mesa_hash_table_destroy(dev->handle_table, NULL);
1097ec681f3Smrg	_mesa_hash_table_destroy(dev->name_table, NULL);
1107ec681f3Smrg
1117ec681f3Smrg	if (dev->closefd)
1127ec681f3Smrg		close(dev->fd);
1137ec681f3Smrg
1147ec681f3Smrg	free(dev);
1157ec681f3Smrg}
1167ec681f3Smrg
1177ec681f3Smrgvoid etna_device_del_locked(struct etna_device *dev)
1187ec681f3Smrg{
1197ec681f3Smrg	simple_mtx_assert_locked(&etna_drm_table_lock);
1207ec681f3Smrg
1217ec681f3Smrg	if (!p_atomic_dec_zero(&dev->refcnt))
1227ec681f3Smrg		return;
1237ec681f3Smrg
1247ec681f3Smrg	etna_device_del_impl(dev);
1257ec681f3Smrg}
1267ec681f3Smrg
1277ec681f3Smrgvoid etna_device_del(struct etna_device *dev)
1287ec681f3Smrg{
1297ec681f3Smrg	if (!p_atomic_dec_zero(&dev->refcnt))
1307ec681f3Smrg		return;
1317ec681f3Smrg
1327ec681f3Smrg	simple_mtx_lock(&etna_drm_table_lock);
1337ec681f3Smrg	etna_device_del_impl(dev);
1347ec681f3Smrg	simple_mtx_unlock(&etna_drm_table_lock);
1357ec681f3Smrg}
1367ec681f3Smrg
1377ec681f3Smrgint etna_device_fd(struct etna_device *dev)
1387ec681f3Smrg{
1397ec681f3Smrg   return dev->fd;
1407ec681f3Smrg}
1417ec681f3Smrg
1427ec681f3Smrgbool etnaviv_device_softpin_capable(struct etna_device *dev)
1437ec681f3Smrg{
1447ec681f3Smrg	return !!dev->use_softpin;
1457ec681f3Smrg}
1467ec681f3Smrg
1477ec681f3Smrguint32_t etnaviv_device_version(struct etna_device *dev)
1487ec681f3Smrg{
1497ec681f3Smrg   return dev->drm_version;
1507ec681f3Smrg}
151