1/*
2 * Copyright (C) 2014-2015 Etnaviv Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Christian Gmeiner <christian.gmeiner@gmail.com>
25 */
26
27#ifndef ETNAVIV_PRIV_H_
28#define ETNAVIV_PRIV_H_
29
30#include <stdlib.h>
31#include <errno.h>
32#include <string.h>
33#include <unistd.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <sys/ioctl.h>
37#include <stdio.h>
38#include <assert.h>
39
40#include <xf86drm.h>
41
42#include "util/list.h"
43#include "util/macros.h"
44#include "util/simple_mtx.h"
45#include "util/timespec.h"
46#include "util/u_atomic.h"
47#include "util/u_debug.h"
48#include "util/vma.h"
49
50#include "etnaviv_drmif.h"
51#include "drm-uapi/etnaviv_drm.h"
52
53extern simple_mtx_t etna_drm_table_lock;
54
55struct etna_bo_bucket {
56	uint32_t size;
57	struct list_head list;
58};
59
60struct etna_bo_cache {
61	struct etna_bo_bucket cache_bucket[14 * 4];
62	unsigned num_buckets;
63	time_t time;
64};
65
66struct etna_device {
67	int fd;
68	uint32_t drm_version;
69	int refcnt;
70
71	/* tables to keep track of bo's, to avoid "evil-twin" etna_bo objects:
72	 *
73	 *   handle_table: maps handle to etna_bo
74	 *   name_table: maps flink name to etna_bo
75	 *
76	 * We end up needing two tables, because DRM_IOCTL_GEM_OPEN always
77	 * returns a new handle.  So we need to figure out if the bo is already
78	 * open in the process first, before calling gem-open.
79	 */
80	void *handle_table, *name_table;
81
82	struct etna_bo_cache bo_cache;
83
84	int use_softpin;
85	struct util_vma_heap address_space;
86
87	int closefd;        /* call close(fd) upon destruction */
88};
89
90void etna_bo_cache_init(struct etna_bo_cache *cache);
91void etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time);
92struct etna_bo *etna_bo_cache_alloc(struct etna_bo_cache *cache,
93		uint32_t *size, uint32_t flags);
94int etna_bo_cache_free(struct etna_bo_cache *cache, struct etna_bo *bo);
95
96/* for where @etna_drm_table_lock is already held: */
97void etna_device_del_locked(struct etna_device *dev);
98
99/* a GEM buffer object allocated from the DRM device */
100struct etna_bo {
101	struct etna_device      *dev;
102	void            *map;           /* userspace mmap'ing (if there is one) */
103	uint32_t        size;
104	uint32_t        handle;
105	uint32_t        flags;
106	uint32_t        name;           /* flink global handle (DRI2 name) */
107	uint64_t        offset;         /* offset to mmap() */
108	uint32_t        va;             /* GPU virtual address */
109	int		refcnt;
110
111	/*
112	 * To avoid excess hashtable lookups, cache the stream this bo was
113	 * last emitted on (since that will probably also be the next ring
114	 * it is emitted on).
115	 */
116	struct etna_cmd_stream *current_stream;
117	uint32_t idx;
118
119	int reuse;
120	struct list_head list;   /* bucket-list entry */
121	time_t free_time;        /* time when added to bucket-list */
122};
123
124struct etna_gpu {
125	struct etna_device *dev;
126	uint32_t core;
127	uint32_t model;
128	uint32_t revision;
129};
130
131struct etna_pipe {
132	enum etna_pipe_id id;
133	struct etna_gpu *gpu;
134};
135
136struct etna_cmd_stream_priv {
137	struct etna_cmd_stream base;
138	struct etna_pipe *pipe;
139
140	uint32_t last_timestamp;
141
142	/* submit ioctl related tables: */
143	struct {
144		/* bo's table: */
145		struct drm_etnaviv_gem_submit_bo *bos;
146		uint32_t nr_bos, max_bos;
147
148		/* reloc's table: */
149		struct drm_etnaviv_gem_submit_reloc *relocs;
150		uint32_t nr_relocs, max_relocs;
151
152		/* perf's table: */
153		struct drm_etnaviv_gem_submit_pmr *pmrs;
154		uint32_t nr_pmrs, max_pmrs;
155	} submit;
156
157	/* should have matching entries in submit.bos: */
158	struct etna_bo **bos;
159	uint32_t nr_bos, max_bos;
160
161	/* notify callback if buffer reset happened */
162	void (*force_flush)(struct etna_cmd_stream *stream, void *priv);
163	void *force_flush_priv;
164
165	void *bo_table;
166};
167
168struct etna_perfmon {
169	struct list_head domains;
170	struct etna_pipe *pipe;
171};
172
173struct etna_perfmon_domain
174{
175	struct list_head head;
176	struct list_head signals;
177	uint8_t id;
178	char name[64];
179};
180
181struct etna_perfmon_signal
182{
183	struct list_head head;
184	struct etna_perfmon_domain *domain;
185	uint8_t signal;
186	char name[64];
187};
188
189#define ALIGN(v,a) (((v) + (a) - 1) & ~((a) - 1))
190
191#define enable_debug 0  /* TODO make dynamic */
192
193#define INFO_MSG(fmt, ...) \
194		do { debug_printf("[I] "fmt " (%s:%d)\n", \
195				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
196#define DEBUG_MSG(fmt, ...) \
197		do if (enable_debug) { debug_printf("[D] "fmt " (%s:%d)\n", \
198				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
199#define WARN_MSG(fmt, ...) \
200		do { debug_printf("[W] "fmt " (%s:%d)\n", \
201				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
202#define ERROR_MSG(fmt, ...) \
203		do { debug_printf("[E] " fmt " (%s:%d)\n", \
204				##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
205
206#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
207
208static inline void get_abs_timeout(struct drm_etnaviv_timespec *tv, uint64_t ns)
209{
210	struct timespec t;
211	clock_gettime(CLOCK_MONOTONIC, &t);
212	tv->tv_sec = t.tv_sec + ns / NSEC_PER_SEC;
213	tv->tv_nsec = t.tv_nsec + ns % NSEC_PER_SEC;
214	if (tv->tv_nsec >= NSEC_PER_SEC) {
215		tv->tv_nsec -= NSEC_PER_SEC;
216		tv->tv_sec++;
217	}
218}
219
220#if HAVE_VALGRIND
221#  include <memcheck.h>
222
223/*
224 * For tracking the backing memory (if valgrind enabled, we force a mmap
225 * for the purposes of tracking)
226 */
227static inline void VG_BO_ALLOC(struct etna_bo *bo)
228{
229	if (bo && RUNNING_ON_VALGRIND) {
230		VALGRIND_MALLOCLIKE_BLOCK(etna_bo_map(bo), bo->size, 0, 1);
231	}
232}
233
234static inline void VG_BO_FREE(struct etna_bo *bo)
235{
236	VALGRIND_FREELIKE_BLOCK(bo->map, 0);
237}
238
239/*
240 * For tracking bo structs that are in the buffer-cache, so that valgrind
241 * doesn't attribute ownership to the first one to allocate the recycled
242 * bo.
243 *
244 * Note that the list_head in etna_bo is used to track the buffers in cache
245 * so disable error reporting on the range while they are in cache so
246 * valgrind doesn't squawk about list traversal.
247 *
248 */
249static inline void VG_BO_RELEASE(struct etna_bo *bo)
250{
251	if (RUNNING_ON_VALGRIND) {
252		VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, sizeof(*bo));
253		VALGRIND_MAKE_MEM_NOACCESS(bo, sizeof(*bo));
254		VALGRIND_FREELIKE_BLOCK(bo->map, 0);
255	}
256}
257static inline void VG_BO_OBTAIN(struct etna_bo *bo)
258{
259	if (RUNNING_ON_VALGRIND) {
260		VALGRIND_MAKE_MEM_DEFINED(bo, sizeof(*bo));
261		VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, sizeof(*bo));
262		VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, 1);
263	}
264}
265#else
266static inline void VG_BO_ALLOC(struct etna_bo *bo)   {}
267static inline void VG_BO_FREE(struct etna_bo *bo)    {}
268static inline void VG_BO_RELEASE(struct etna_bo *bo) {}
269static inline void VG_BO_OBTAIN(struct etna_bo *bo)  {}
270#endif
271
272#endif /* ETNAVIV_PRIV_H_ */
273