1b8e80941Smrg/*
2b8e80941Smrg * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org>
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20b8e80941Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21b8e80941Smrg * SOFTWARE.
22b8e80941Smrg *
23b8e80941Smrg * Authors:
24b8e80941Smrg *    Rob Clark <robclark@freedesktop.org>
25b8e80941Smrg */
26b8e80941Smrg
27b8e80941Smrg#include <sys/types.h>
28b8e80941Smrg#include <sys/stat.h>
29b8e80941Smrg#include <unistd.h>
30b8e80941Smrg
31b8e80941Smrg#include "freedreno_drmif.h"
32b8e80941Smrg#include "freedreno_priv.h"
33b8e80941Smrg
34b8e80941Smrgstatic pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
35b8e80941Smrg
36b8e80941Smrgstatic uint32_t
37b8e80941Smrgu32_hash(const void *key)
38b8e80941Smrg{
39b8e80941Smrg	return _mesa_hash_data(key, sizeof(uint32_t));
40b8e80941Smrg}
41b8e80941Smrg
42b8e80941Smrgstatic bool
43b8e80941Smrgu32_equals(const void *key1, const void *key2)
44b8e80941Smrg{
45b8e80941Smrg	return *(const uint32_t *)key1 == *(const uint32_t *)key2;
46b8e80941Smrg}
47b8e80941Smrg
48b8e80941Smrg
49b8e80941Smrgstruct fd_device * kgsl_device_new(int fd);
50b8e80941Smrgstruct fd_device * msm_device_new(int fd);
51b8e80941Smrg
52b8e80941Smrgstruct fd_device * fd_device_new(int fd)
53b8e80941Smrg{
54b8e80941Smrg	struct fd_device *dev;
55b8e80941Smrg	drmVersionPtr version;
56b8e80941Smrg
57b8e80941Smrg	/* figure out if we are kgsl or msm drm driver: */
58b8e80941Smrg	version = drmGetVersion(fd);
59b8e80941Smrg	if (!version) {
60b8e80941Smrg		ERROR_MSG("cannot get version: %s", strerror(errno));
61b8e80941Smrg		return NULL;
62b8e80941Smrg	}
63b8e80941Smrg
64b8e80941Smrg	if (!strcmp(version->name, "msm")) {
65b8e80941Smrg		DEBUG_MSG("msm DRM device");
66b8e80941Smrg		if (version->version_major != 1) {
67b8e80941Smrg			ERROR_MSG("unsupported version: %u.%u.%u", version->version_major,
68b8e80941Smrg				version->version_minor, version->version_patchlevel);
69b8e80941Smrg			dev = NULL;
70b8e80941Smrg			goto out;
71b8e80941Smrg		}
72b8e80941Smrg
73b8e80941Smrg		dev = msm_device_new(fd);
74b8e80941Smrg		dev->version = version->version_minor;
75b8e80941Smrg#if HAVE_FREEDRENO_KGSL
76b8e80941Smrg	} else if (!strcmp(version->name, "kgsl")) {
77b8e80941Smrg		DEBUG_MSG("kgsl DRM device");
78b8e80941Smrg		dev = kgsl_device_new(fd);
79b8e80941Smrg#endif
80b8e80941Smrg	} else {
81b8e80941Smrg		ERROR_MSG("unknown device: %s", version->name);
82b8e80941Smrg		dev = NULL;
83b8e80941Smrg	}
84b8e80941Smrg
85b8e80941Smrgout:
86b8e80941Smrg	drmFreeVersion(version);
87b8e80941Smrg
88b8e80941Smrg	if (!dev)
89b8e80941Smrg		return NULL;
90b8e80941Smrg
91b8e80941Smrg	p_atomic_set(&dev->refcnt, 1);
92b8e80941Smrg	dev->fd = fd;
93b8e80941Smrg	dev->handle_table = _mesa_hash_table_create(NULL, u32_hash, u32_equals);
94b8e80941Smrg	dev->name_table = _mesa_hash_table_create(NULL, u32_hash, u32_equals);
95b8e80941Smrg	fd_bo_cache_init(&dev->bo_cache, FALSE);
96b8e80941Smrg	fd_bo_cache_init(&dev->ring_cache, TRUE);
97b8e80941Smrg
98b8e80941Smrg	return dev;
99b8e80941Smrg}
100b8e80941Smrg
101b8e80941Smrg/* like fd_device_new() but creates it's own private dup() of the fd
102b8e80941Smrg * which is close()d when the device is finalized.
103b8e80941Smrg */
104b8e80941Smrgstruct fd_device * fd_device_new_dup(int fd)
105b8e80941Smrg{
106b8e80941Smrg	int dup_fd = dup(fd);
107b8e80941Smrg	struct fd_device *dev = fd_device_new(dup_fd);
108b8e80941Smrg	if (dev)
109b8e80941Smrg		dev->closefd = 1;
110b8e80941Smrg	else
111b8e80941Smrg		close(dup_fd);
112b8e80941Smrg	return dev;
113b8e80941Smrg}
114b8e80941Smrg
115b8e80941Smrgstruct fd_device * fd_device_ref(struct fd_device *dev)
116b8e80941Smrg{
117b8e80941Smrg	p_atomic_inc(&dev->refcnt);
118b8e80941Smrg	return dev;
119b8e80941Smrg}
120b8e80941Smrg
121b8e80941Smrgstatic void fd_device_del_impl(struct fd_device *dev)
122b8e80941Smrg{
123b8e80941Smrg	int close_fd = dev->closefd ? dev->fd : -1;
124b8e80941Smrg	fd_bo_cache_cleanup(&dev->bo_cache, 0);
125b8e80941Smrg	_mesa_hash_table_destroy(dev->handle_table, NULL);
126b8e80941Smrg	_mesa_hash_table_destroy(dev->name_table, NULL);
127b8e80941Smrg	dev->funcs->destroy(dev);
128b8e80941Smrg	if (close_fd >= 0)
129b8e80941Smrg		close(close_fd);
130b8e80941Smrg}
131b8e80941Smrg
132b8e80941Smrgvoid fd_device_del_locked(struct fd_device *dev)
133b8e80941Smrg{
134b8e80941Smrg	if (!atomic_dec_and_test(&dev->refcnt))
135b8e80941Smrg		return;
136b8e80941Smrg	fd_device_del_impl(dev);
137b8e80941Smrg}
138b8e80941Smrg
139b8e80941Smrgvoid fd_device_del(struct fd_device *dev)
140b8e80941Smrg{
141b8e80941Smrg	if (!atomic_dec_and_test(&dev->refcnt))
142b8e80941Smrg		return;
143b8e80941Smrg	pthread_mutex_lock(&table_lock);
144b8e80941Smrg	fd_device_del_impl(dev);
145b8e80941Smrg	pthread_mutex_unlock(&table_lock);
146b8e80941Smrg}
147b8e80941Smrg
148b8e80941Smrgint fd_device_fd(struct fd_device *dev)
149b8e80941Smrg{
150b8e80941Smrg	return dev->fd;
151b8e80941Smrg}
152b8e80941Smrg
153b8e80941Smrgenum fd_version fd_device_version(struct fd_device *dev)
154b8e80941Smrg{
155b8e80941Smrg	return dev->version;
156b8e80941Smrg}
157