xref: /aosp_15_r20/external/mesa3d/src/etnaviv/drm/etnaviv_priv.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 <[email protected]>
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 "etna_core_info.h"
43 #include "util/list.h"
44 #include "util/log.h"
45 #include "util/macros.h"
46 #include "util/simple_mtx.h"
47 #include "util/timespec.h"
48 #include "util/u_atomic.h"
49 #include "util/u_debug.h"
50 #include "util/u_math.h"
51 #include "util/vma.h"
52 
53 #include "etnaviv_drmif.h"
54 #include "drm-uapi/etnaviv_drm.h"
55 
56 extern simple_mtx_t etna_device_lock;
57 
58 struct etna_bo_bucket {
59 	uint32_t size;
60 	struct list_head list;
61 };
62 
63 struct etna_bo_cache {
64 	struct etna_bo_bucket cache_bucket[14 * 4];
65 	unsigned num_buckets;
66 	time_t time;
67 };
68 
69 struct etna_device {
70 	int fd;
71 	uint32_t drm_version;
72 	int refcnt;
73 
74 	/* tables to keep track of bo's, to avoid "evil-twin" etna_bo objects:
75 	 *
76 	 *   handle_table: maps handle to etna_bo
77 	 *   name_table: maps flink name to etna_bo
78 	 *
79 	 * We end up needing two tables, because DRM_IOCTL_GEM_OPEN always
80 	 * returns a new handle.  So we need to figure out if the bo is already
81 	 * open in the process first, before calling gem-open.
82 	 */
83 	void *handle_table, *name_table;
84 
85 	struct etna_bo_cache bo_cache;
86 	struct list_head zombie_list;
87 
88 	int use_softpin;
89 	struct util_vma_heap address_space;
90 
91 	int closefd;        /* call close(fd) upon destruction */
92 };
93 
94 void etna_bo_free(struct etna_bo *bo);
95 void etna_bo_kill_zombies(struct etna_device *dev);
96 
97 void etna_bo_cache_init(struct etna_bo_cache *cache);
98 void etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time);
99 struct etna_bo *etna_bo_cache_alloc(struct etna_bo_cache *cache,
100 		uint32_t *size, uint32_t flags);
101 int etna_bo_cache_free(struct etna_bo_cache *cache, struct etna_bo *bo);
102 
103 /* for where @etna_drm_table_lock is already held: */
104 void etna_device_del_locked(struct etna_device *dev);
105 
106 /* a GEM buffer object allocated from the DRM device */
107 struct etna_bo {
108 	struct etna_device      *dev;
109 	void            *map;           /* userspace mmap'ing (if there is one) */
110 	uint32_t        size;
111 	uint32_t        handle;
112 	uint32_t        flags;
113 	uint32_t        name;           /* flink global handle (DRI2 name) */
114 	uint32_t        va;             /* GPU virtual address */
115 	int		refcnt;
116 
117 	int reuse;
118 	struct list_head list;   /* bucket-list entry */
119 	time_t free_time;        /* time when added to bucket-list */
120 };
121 
122 struct etna_gpu {
123 	struct etna_device *dev;
124 	uint32_t core;
125 	struct etna_core_info info;
126 };
127 
128 struct etna_pipe {
129 	enum etna_pipe_id id;
130 	struct etna_gpu *gpu;
131 };
132 
133 struct etna_cmd_stream_priv {
134 	struct etna_cmd_stream base;
135 	struct etna_pipe *pipe;
136 
137 	uint32_t last_timestamp;
138 	uint32_t offset_end_of_context_init;
139 
140 	/* submit ioctl related tables: */
141 	struct {
142 		/* bo's table: */
143 		struct drm_etnaviv_gem_submit_bo *bos;
144 		uint32_t nr_bos, max_bos;
145 
146 		/* reloc's table: */
147 		struct drm_etnaviv_gem_submit_reloc *relocs;
148 		uint32_t nr_relocs, max_relocs;
149 
150 		/* perf's table: */
151 		struct drm_etnaviv_gem_submit_pmr *pmrs;
152 		uint32_t nr_pmrs, max_pmrs;
153 	} submit;
154 
155 	/* should have matching entries in submit.bos: */
156 	struct etna_bo **bos;
157 	uint32_t nr_bos, max_bos;
158 
159 	/* notify callback if buffer reset happened */
160 	void (*force_flush)(struct etna_cmd_stream *stream, void *priv);
161 	void *force_flush_priv;
162 
163 	void *bo_table;
164 };
165 
166 struct etna_perfmon {
167 	struct list_head domains;
168 	struct etna_pipe *pipe;
169 };
170 
171 struct etna_perfmon_domain
172 {
173 	struct list_head head;
174 	struct list_head signals;
175 	uint8_t id;
176 	char name[64];
177 };
178 
179 struct etna_perfmon_signal
180 {
181 	struct list_head head;
182 	struct etna_perfmon_domain *domain;
183 	uint8_t signal;
184 	char name[64];
185 };
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 				__func__, __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 				__func__, __LINE__, ##__VA_ARGS__); } while (0)
197 #define WARN_MSG(fmt, ...) \
198 		do { mesa_logw("%s:%d: " fmt, \
199 				__func__, __LINE__, ##__VA_ARGS__); } while (0)
200 #define ERROR_MSG(fmt, ...) \
201 		do { mesa_loge("%s:%d: " fmt, \
202 				__func__, __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(ns > 200000000 ? CLOCK_MONOTONIC_COARSE : 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