1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (C) 2014 Etnaviv Project
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21bf215546Sopenharmony_ci * SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci * Authors:
24bf215546Sopenharmony_ci *    Christian Gmeiner <christian.gmeiner@gmail.com>
25bf215546Sopenharmony_ci */
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "util/hash_table.h"
28bf215546Sopenharmony_ci#include "util/os_file.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include "etnaviv_priv.h"
31bf215546Sopenharmony_ci#include "etnaviv_drmif.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci/* Declare symbol in case we don't link with etnaviv's gallium driver */
34bf215546Sopenharmony_ciint etna_mesa_debug __attribute__((weak)) = 0;
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_cistruct etna_device *etna_device_new(int fd)
37bf215546Sopenharmony_ci{
38bf215546Sopenharmony_ci	struct etna_device *dev;
39bf215546Sopenharmony_ci	struct drm_etnaviv_param req = {
40bf215546Sopenharmony_ci		.param = ETNAVIV_PARAM_SOFTPIN_START_ADDR,
41bf215546Sopenharmony_ci	};
42bf215546Sopenharmony_ci	drmVersionPtr version;
43bf215546Sopenharmony_ci	int ret;
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci	version = drmGetVersion(fd);
46bf215546Sopenharmony_ci	if (!version) {
47bf215546Sopenharmony_ci		ERROR_MSG("cannot get version: %s", strerror(errno));
48bf215546Sopenharmony_ci		return NULL;
49bf215546Sopenharmony_ci	}
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci	dev = calloc(sizeof(*dev), 1);
52bf215546Sopenharmony_ci	if (!dev) {
53bf215546Sopenharmony_ci		goto out;
54bf215546Sopenharmony_ci	}
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci	dev->drm_version = ETNA_DRM_VERSION(version->version_major,
57bf215546Sopenharmony_ci					    version->version_minor);
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ciout:
60bf215546Sopenharmony_ci	drmFreeVersion(version);
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci	if (!dev)
63bf215546Sopenharmony_ci		return NULL;
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci	p_atomic_set(&dev->refcnt, 1);
66bf215546Sopenharmony_ci	dev->fd = fd;
67bf215546Sopenharmony_ci	dev->handle_table = _mesa_hash_table_create(NULL, _mesa_hash_u32, _mesa_key_u32_equal);
68bf215546Sopenharmony_ci	dev->name_table = _mesa_hash_table_create(NULL, _mesa_hash_u32, _mesa_key_u32_equal);
69bf215546Sopenharmony_ci	etna_bo_cache_init(&dev->bo_cache);
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci	ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GET_PARAM, &req, sizeof(req));
72bf215546Sopenharmony_ci	if (!ret && req.value != ~0ULL) {
73bf215546Sopenharmony_ci		const uint64_t _4GB = 1ull << 32;
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci		list_inithead(&dev->zombie_list);
76bf215546Sopenharmony_ci		util_vma_heap_init(&dev->address_space, req.value, _4GB - req.value);
77bf215546Sopenharmony_ci		dev->use_softpin = 1;
78bf215546Sopenharmony_ci	}
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci	return dev;
81bf215546Sopenharmony_ci}
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci/* like etna_device_new() but creates it's own private dup() of the fd
84bf215546Sopenharmony_ci * which is close()d when the device is finalized. */
85bf215546Sopenharmony_cistruct etna_device *etna_device_new_dup(int fd)
86bf215546Sopenharmony_ci{
87bf215546Sopenharmony_ci	int dup_fd = os_dupfd_cloexec(fd);
88bf215546Sopenharmony_ci	struct etna_device *dev = etna_device_new(dup_fd);
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci	if (dev)
91bf215546Sopenharmony_ci		dev->closefd = 1;
92bf215546Sopenharmony_ci	else
93bf215546Sopenharmony_ci		close(dup_fd);
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci	return dev;
96bf215546Sopenharmony_ci}
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_cistruct etna_device *etna_device_ref(struct etna_device *dev)
99bf215546Sopenharmony_ci{
100bf215546Sopenharmony_ci	p_atomic_inc(&dev->refcnt);
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci	return dev;
103bf215546Sopenharmony_ci}
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_cistatic void etna_device_del_impl(struct etna_device *dev)
106bf215546Sopenharmony_ci{
107bf215546Sopenharmony_ci	etna_bo_cache_cleanup(&dev->bo_cache, 0);
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci	if (dev->use_softpin) {
110bf215546Sopenharmony_ci		etna_bo_kill_zombies(dev);
111bf215546Sopenharmony_ci		util_vma_heap_finish(&dev->address_space);
112bf215546Sopenharmony_ci	}
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci	_mesa_hash_table_destroy(dev->handle_table, NULL);
115bf215546Sopenharmony_ci	_mesa_hash_table_destroy(dev->name_table, NULL);
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci	if (dev->closefd)
118bf215546Sopenharmony_ci		close(dev->fd);
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci	free(dev);
121bf215546Sopenharmony_ci}
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_civoid etna_device_del_locked(struct etna_device *dev)
124bf215546Sopenharmony_ci{
125bf215546Sopenharmony_ci	simple_mtx_assert_locked(&etna_device_lock);
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci	if (!p_atomic_dec_zero(&dev->refcnt))
128bf215546Sopenharmony_ci		return;
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci	etna_device_del_impl(dev);
131bf215546Sopenharmony_ci}
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_civoid etna_device_del(struct etna_device *dev)
134bf215546Sopenharmony_ci{
135bf215546Sopenharmony_ci	if (!p_atomic_dec_zero(&dev->refcnt))
136bf215546Sopenharmony_ci		return;
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci	simple_mtx_lock(&etna_device_lock);
139bf215546Sopenharmony_ci	etna_device_del_impl(dev);
140bf215546Sopenharmony_ci	simple_mtx_unlock(&etna_device_lock);
141bf215546Sopenharmony_ci}
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ciint etna_device_fd(struct etna_device *dev)
144bf215546Sopenharmony_ci{
145bf215546Sopenharmony_ci   return dev->fd;
146bf215546Sopenharmony_ci}
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_cibool etnaviv_device_softpin_capable(struct etna_device *dev)
149bf215546Sopenharmony_ci{
150bf215546Sopenharmony_ci	return !!dev->use_softpin;
151bf215546Sopenharmony_ci}
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ciuint32_t etnaviv_device_version(struct etna_device *dev)
154bf215546Sopenharmony_ci{
155bf215546Sopenharmony_ci   return dev->drm_version;
156bf215546Sopenharmony_ci}
157