• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/log.h"
44 #include "util/macros.h"
45 #include "util/simple_mtx.h"
46 #include "util/timespec.h"
47 #include "util/u_atomic.h"
48 #include "util/u_debug.h"
49 #include "util/vma.h"
50 
51 #include "etnaviv_drmif.h"
52 #include "drm-uapi/etnaviv_drm.h"
53 
54 extern simple_mtx_t etna_device_lock;
55 
56 struct etna_bo_bucket {
57 	uint32_t size;
58 	struct list_head list;
59 };
60 
61 struct etna_bo_cache {
62 	struct etna_bo_bucket cache_bucket[14 * 4];
63 	unsigned num_buckets;
64 	time_t time;
65 };
66 
67 struct etna_device {
68 	int fd;
69 	uint32_t drm_version;
70 	int refcnt;
71 
72 	/* tables to keep track of bo's, to avoid "evil-twin" etna_bo objects:
73 	 *
74 	 *   handle_table: maps handle to etna_bo
75 	 *   name_table: maps flink name to etna_bo
76 	 *
77 	 * We end up needing two tables, because DRM_IOCTL_GEM_OPEN always
78 	 * returns a new handle.  So we need to figure out if the bo is already
79 	 * open in the process first, before calling gem-open.
80 	 */
81 	void *handle_table, *name_table;
82 
83 	struct etna_bo_cache bo_cache;
84 	struct list_head zombie_list;
85 
86 	int use_softpin;
87 	struct util_vma_heap address_space;
88 
89 	int closefd;        /* call close(fd) upon destruction */
90 };
91 
92 void etna_bo_free(struct etna_bo *bo);
93 void etna_bo_kill_zombies(struct etna_device *dev);
94 
95 void etna_bo_cache_init(struct etna_bo_cache *cache);
96 void etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time);
97 struct etna_bo *etna_bo_cache_alloc(struct etna_bo_cache *cache,
98 		uint32_t *size, uint32_t flags);
99 int etna_bo_cache_free(struct etna_bo_cache *cache, struct etna_bo *bo);
100 
101 /* for where @etna_drm_table_lock is already held: */
102 void etna_device_del_locked(struct etna_device *dev);
103 
104 /* a GEM buffer object allocated from the DRM device */
105 struct etna_bo {
106 	struct etna_device      *dev;
107 	void            *map;           /* userspace mmap'ing (if there is one) */
108 	uint32_t        size;
109 	uint32_t        handle;
110 	uint32_t        flags;
111 	uint32_t        name;           /* flink global handle (DRI2 name) */
112 	uint32_t        va;             /* GPU virtual address */
113 	int		refcnt;
114 
115 	int reuse;
116 	struct list_head list;   /* bucket-list entry */
117 	time_t free_time;        /* time when added to bucket-list */
118 };
119 
120 struct etna_gpu {
121 	struct etna_device *dev;
122 	uint32_t core;
123 	uint32_t model;
124 	uint32_t revision;
125 };
126 
127 struct etna_pipe {
128 	enum etna_pipe_id id;
129 	struct etna_gpu *gpu;
130 };
131 
132 struct etna_cmd_stream_priv {
133 	struct etna_cmd_stream base;
134 	struct etna_pipe *pipe;
135 
136 	uint32_t last_timestamp;
137 
138 	/* submit ioctl related tables: */
139 	struct {
140 		/* bo's table: */
141 		struct drm_etnaviv_gem_submit_bo *bos;
142 		uint32_t nr_bos, max_bos;
143 
144 		/* reloc's table: */
145 		struct drm_etnaviv_gem_submit_reloc *relocs;
146 		uint32_t nr_relocs, max_relocs;
147 
148 		/* perf's table: */
149 		struct drm_etnaviv_gem_submit_pmr *pmrs;
150 		uint32_t nr_pmrs, max_pmrs;
151 	} submit;
152 
153 	/* should have matching entries in submit.bos: */
154 	struct etna_bo **bos;
155 	uint32_t nr_bos, max_bos;
156 
157 	/* notify callback if buffer reset happened */
158 	void (*force_flush)(struct etna_cmd_stream *stream, void *priv);
159 	void *force_flush_priv;
160 
161 	void *bo_table;
162 };
163 
164 struct etna_perfmon {
165 	struct list_head domains;
166 	struct etna_pipe *pipe;
167 };
168 
169 struct etna_perfmon_domain
170 {
171 	struct list_head head;
172 	struct list_head signals;
173 	uint8_t id;
174 	char name[64];
175 };
176 
177 struct etna_perfmon_signal
178 {
179 	struct list_head head;
180 	struct etna_perfmon_domain *domain;
181 	uint8_t signal;
182 	char name[64];
183 };
184 
185 #define ALIGN(v,a) (((v) + (a) - 1) & ~((a) - 1))
186 
187 #define ETNA_DRM_MSGS 0x40
188 extern int etna_mesa_debug;
189 
190 #define INFO_MSG(fmt, ...) \
191 		do { mesa_logi("%s:%d: " fmt, \
192 				__FUNCTION__, __LINE__, ##__VA_ARGS__); } while (0)
193 #define DEBUG_MSG(fmt, ...) \
194 		do if (etna_mesa_debug & ETNA_DRM_MSGS) { \
195 		     mesa_logd("%s:%d: " fmt, \
196 				__FUNCTION__, __LINE__, ##__VA_ARGS__); } while (0)
197 #define WARN_MSG(fmt, ...) \
198 		do { mesa_logw("%s:%d: " fmt, \
199 				__FUNCTION__, __LINE__, ##__VA_ARGS__); } while (0)
200 #define ERROR_MSG(fmt, ...) \
201 		do { mesa_loge("%s:%d: " fmt, \
202 				__FUNCTION__, __LINE__, ##__VA_ARGS__); } while (0)
203 
204 #define DEBUG_BO(msg, bo)						\
205    DEBUG_MSG("%s %p, va: 0x%.8x, size: 0x%.8x, flags: 0x%.8x, "		\
206 	     "refcnt: %d, handle: 0x%.8x, name: 0x%.8x",		\
207 	     msg, bo, bo->va, bo->size, bo->flags, bo->refcnt, bo->handle, bo->name);
208 
209 #define VOID2U64(x) ((uint64_t)(unsigned long)(x))
210 
get_abs_timeout(struct drm_etnaviv_timespec * tv,uint64_t ns)211 static inline void get_abs_timeout(struct drm_etnaviv_timespec *tv, uint64_t ns)
212 {
213 	struct timespec t;
214 	clock_gettime(CLOCK_MONOTONIC, &t);
215 	tv->tv_sec = t.tv_sec + ns / NSEC_PER_SEC;
216 	tv->tv_nsec = t.tv_nsec + ns % NSEC_PER_SEC;
217 	if (tv->tv_nsec >= NSEC_PER_SEC) {
218 		tv->tv_nsec -= NSEC_PER_SEC;
219 		tv->tv_sec++;
220 	}
221 }
222 
223 #if HAVE_VALGRIND
224 #  include <memcheck.h>
225 
226 /*
227  * For tracking the backing memory (if valgrind enabled, we force a mmap
228  * for the purposes of tracking)
229  */
VG_BO_ALLOC(struct etna_bo * bo)230 static inline void VG_BO_ALLOC(struct etna_bo *bo)
231 {
232 	if (bo && RUNNING_ON_VALGRIND) {
233 		VALGRIND_MALLOCLIKE_BLOCK(etna_bo_map(bo), bo->size, 0, 1);
234 	}
235 }
236 
VG_BO_FREE(struct etna_bo * bo)237 static inline void VG_BO_FREE(struct etna_bo *bo)
238 {
239 	VALGRIND_FREELIKE_BLOCK(bo->map, 0);
240 }
241 
242 /*
243  * For tracking bo structs that are in the buffer-cache, so that valgrind
244  * doesn't attribute ownership to the first one to allocate the recycled
245  * bo.
246  *
247  * Note that the list_head in etna_bo is used to track the buffers in cache
248  * so disable error reporting on the range while they are in cache so
249  * valgrind doesn't squawk about list traversal.
250  *
251  */
VG_BO_RELEASE(struct etna_bo * bo)252 static inline void VG_BO_RELEASE(struct etna_bo *bo)
253 {
254 	if (RUNNING_ON_VALGRIND) {
255 		VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, sizeof(*bo));
256 		VALGRIND_MAKE_MEM_NOACCESS(bo, sizeof(*bo));
257 		VALGRIND_FREELIKE_BLOCK(bo->map, 0);
258 	}
259 }
VG_BO_OBTAIN(struct etna_bo * bo)260 static inline void VG_BO_OBTAIN(struct etna_bo *bo)
261 {
262 	if (RUNNING_ON_VALGRIND) {
263 		VALGRIND_MAKE_MEM_DEFINED(bo, sizeof(*bo));
264 		VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, sizeof(*bo));
265 		VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, 1);
266 	}
267 }
268 #else
VG_BO_ALLOC(struct etna_bo * bo)269 static inline void VG_BO_ALLOC(struct etna_bo *bo)   {}
VG_BO_FREE(struct etna_bo * bo)270 static inline void VG_BO_FREE(struct etna_bo *bo)    {}
VG_BO_RELEASE(struct etna_bo * bo)271 static inline void VG_BO_RELEASE(struct etna_bo *bo) {}
VG_BO_OBTAIN(struct etna_bo * bo)272 static inline void VG_BO_OBTAIN(struct etna_bo *bo)  {}
273 #endif
274 
275 #endif /* ETNAVIV_PRIV_H_ */
276