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