blob: 81ad6092b01b7af3a764b455caf8cc5ff3fbbfc1 [file] [log] [blame]
Rob Clark41fc2cc2012-10-07 18:57:31 -05001/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2
3/*
4 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Authors:
26 * Rob Clark <robclark@freedesktop.org>
27 */
28
29#ifndef FREEDRENO_PRIV_H_
30#define FREEDRENO_PRIV_H_
31
Maarten Lankhorst479b6ce2014-08-04 11:23:20 +020032#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
Rob Clark41fc2cc2012-10-07 18:57:31 -050036#include <stdlib.h>
37#include <errno.h>
38#include <string.h>
39#include <unistd.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <sys/ioctl.h>
Rob Clark0b89e272013-05-15 13:18:02 -040043#include <pthread.h>
Rob Clarkb2b18852013-07-10 15:20:04 -040044#include <stdio.h>
45#include <assert.h>
Rob Clark41fc2cc2012-10-07 18:57:31 -050046
Emil Velikov42465fe2015-04-05 15:51:59 +010047#include "libdrm_macros.h"
Rob Clark41fc2cc2012-10-07 18:57:31 -050048#include "xf86drm.h"
49#include "xf86atomic.h"
50
Alex Deucher4ee0fa22015-05-07 13:03:47 -040051#include "util_double_list.h"
Rob Clark6f0f6ce2018-01-24 15:08:46 -050052#include "util_math.h"
Rob Clark41fc2cc2012-10-07 18:57:31 -050053
54#include "freedreno_drmif.h"
Rob Clarkb2b18852013-07-10 15:20:04 -040055#include "freedreno_ringbuffer.h"
Emil Velikov126c4582013-08-29 21:31:52 +010056#include "drm.h"
Rob Clarkb2b18852013-07-10 15:20:04 -040057
Rob Clarkeb846d42016-05-31 12:06:50 -040058#ifndef TRUE
59# define TRUE 1
60#endif
61#ifndef FALSE
62# define FALSE 0
63#endif
64
Rob Clarkb2b18852013-07-10 15:20:04 -040065struct fd_device_funcs {
66 int (*bo_new_handle)(struct fd_device *dev, uint32_t size,
67 uint32_t flags, uint32_t *handle);
68 struct fd_bo * (*bo_from_handle)(struct fd_device *dev,
69 uint32_t size, uint32_t handle);
Rob Clark7064b2e2017-08-23 17:08:39 -040070 struct fd_pipe * (*pipe_new)(struct fd_device *dev, enum fd_pipe_id id,
71 unsigned prio);
Rob Clarkb2b18852013-07-10 15:20:04 -040072 void (*destroy)(struct fd_device *dev);
73};
Rob Clark41fc2cc2012-10-07 18:57:31 -050074
Rob Clark068ea682013-12-13 12:48:30 -050075struct fd_bo_bucket {
76 uint32_t size;
77 struct list_head list;
78};
79
Rob Clarkb18b6e22016-05-30 11:49:39 -040080struct fd_bo_cache {
81 struct fd_bo_bucket cache_bucket[14 * 4];
82 int num_buckets;
83 time_t time;
84};
85
Rob Clark41fc2cc2012-10-07 18:57:31 -050086struct fd_device {
87 int fd;
Rob Clark904f1362016-06-01 14:35:44 -040088 enum fd_version version;
Rob Clark0b89e272013-05-15 13:18:02 -040089 atomic_t refcnt;
90
91 /* tables to keep track of bo's, to avoid "evil-twin" fd_bo objects:
92 *
93 * handle_table: maps handle to fd_bo
94 * name_table: maps flink name to fd_bo
95 *
96 * We end up needing two tables, because DRM_IOCTL_GEM_OPEN always
97 * returns a new handle. So we need to figure out if the bo is already
98 * open in the process first, before calling gem-open.
99 */
100 void *handle_table, *name_table;
Rob Clarkb2b18852013-07-10 15:20:04 -0400101
Emil Velikov6a6d6682015-08-15 17:17:52 +0100102 const struct fd_device_funcs *funcs;
Rob Clark068ea682013-12-13 12:48:30 -0500103
Rob Clarkb18b6e22016-05-30 11:49:39 -0400104 struct fd_bo_cache bo_cache;
Rob Clark8279c8f2014-01-12 08:27:36 -0500105
106 int closefd; /* call close(fd) upon destruction */
Rob Clarkd0dae262017-03-21 19:44:57 -0400107
108 /* just for valgrind: */
109 int bo_size;
Rob Clarkb2b18852013-07-10 15:20:04 -0400110};
111
Rob Clark8a6a8512016-06-01 15:37:52 -0400112drm_private void fd_bo_cache_init(struct fd_bo_cache *cache, int coarse);
Rob Clark0b34b682016-05-30 12:45:33 -0400113drm_private void fd_bo_cache_cleanup(struct fd_bo_cache *cache, time_t time);
114drm_private struct fd_bo * fd_bo_cache_alloc(struct fd_bo_cache *cache,
115 uint32_t *size, uint32_t flags);
116drm_private int fd_bo_cache_free(struct fd_bo_cache *cache, struct fd_bo *bo);
Rob Clark068ea682013-12-13 12:48:30 -0500117
118/* for where @table_lock is already held: */
Emil Velikov44e9a022015-03-23 21:35:38 +0000119drm_private void fd_device_del_locked(struct fd_device *dev);
Rob Clark068ea682013-12-13 12:48:30 -0500120
Rob Clarkb2b18852013-07-10 15:20:04 -0400121struct fd_pipe_funcs {
122 struct fd_ringbuffer * (*ringbuffer_new)(struct fd_pipe *pipe, uint32_t size);
123 int (*get_param)(struct fd_pipe *pipe, enum fd_param_id param, uint64_t *value);
Rob Clark15ba8762015-08-17 10:33:59 -0400124 int (*wait)(struct fd_pipe *pipe, uint32_t timestamp, uint64_t timeout);
Rob Clarkb2b18852013-07-10 15:20:04 -0400125 void (*destroy)(struct fd_pipe *pipe);
Rob Clark41fc2cc2012-10-07 18:57:31 -0500126};
127
128struct fd_pipe {
129 struct fd_device *dev;
130 enum fd_pipe_id id;
Rob Clark23d10b82016-11-09 09:02:09 -0500131 uint32_t gpu_id;
Emil Velikov6a6d6682015-08-15 17:17:52 +0100132 const struct fd_pipe_funcs *funcs;
Rob Clark41fc2cc2012-10-07 18:57:31 -0500133};
134
Rob Clarkb2b18852013-07-10 15:20:04 -0400135struct fd_ringmarker {
136 struct fd_ringbuffer *ring;
137 uint32_t *cur;
138};
139
140struct fd_ringbuffer_funcs {
141 void * (*hostptr)(struct fd_ringbuffer *ring);
Rob Clarke9eb44b2016-08-15 13:26:18 -0400142 int (*flush)(struct fd_ringbuffer *ring, uint32_t *last_start,
143 int in_fence_fd, int *out_fence_fd);
Rob Clark419a1542016-06-20 14:06:24 -0400144 void (*grow)(struct fd_ringbuffer *ring, uint32_t size);
Rob Clarkc5de5ab2014-02-19 11:01:23 -0500145 void (*reset)(struct fd_ringbuffer *ring);
Rob Clarkb2b18852013-07-10 15:20:04 -0400146 void (*emit_reloc)(struct fd_ringbuffer *ring,
147 const struct fd_reloc *reloc);
Rob Clark419a1542016-06-20 14:06:24 -0400148 uint32_t (*emit_reloc_ring)(struct fd_ringbuffer *ring,
149 struct fd_ringbuffer *target, uint32_t cmd_idx,
Rob Clark73db0a02016-05-20 17:14:43 -0400150 uint32_t submit_offset, uint32_t size);
Rob Clark419a1542016-06-20 14:06:24 -0400151 uint32_t (*cmd_count)(struct fd_ringbuffer *ring);
Rob Clarkb2b18852013-07-10 15:20:04 -0400152 void (*destroy)(struct fd_ringbuffer *ring);
153};
154
155struct fd_bo_funcs {
156 int (*offset)(struct fd_bo *bo, uint64_t *offset);
157 int (*cpu_prep)(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op);
158 void (*cpu_fini)(struct fd_bo *bo);
Rob Clarkeb846d42016-05-31 12:06:50 -0400159 int (*madvise)(struct fd_bo *bo, int willneed);
Rob Clarkb2b18852013-07-10 15:20:04 -0400160 void (*destroy)(struct fd_bo *bo);
161};
Rob Clark41fc2cc2012-10-07 18:57:31 -0500162
163struct fd_bo {
164 struct fd_device *dev;
165 uint32_t size;
166 uint32_t handle;
167 uint32_t name;
Rob Clark41fc2cc2012-10-07 18:57:31 -0500168 void *map;
Rob Clark41fc2cc2012-10-07 18:57:31 -0500169 atomic_t refcnt;
Emil Velikov6a6d6682015-08-15 17:17:52 +0100170 const struct fd_bo_funcs *funcs;
Rob Clark068ea682013-12-13 12:48:30 -0500171
172 int bo_reuse;
173 struct list_head list; /* bucket-list entry */
174 time_t free_time; /* time when added to bucket-list */
Rob Clark41fc2cc2012-10-07 18:57:31 -0500175};
176
Rob Clark41fc2cc2012-10-07 18:57:31 -0500177#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
178
Rob Clarkf17d4172013-07-20 20:35:31 -0400179#define enable_debug 0 /* TODO make dynamic */
Rob Clark41fc2cc2012-10-07 18:57:31 -0500180
181#define INFO_MSG(fmt, ...) \
182 do { drmMsg("[I] "fmt " (%s:%d)\n", \
183 ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
184#define DEBUG_MSG(fmt, ...) \
185 do if (enable_debug) { drmMsg("[D] "fmt " (%s:%d)\n", \
186 ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
187#define WARN_MSG(fmt, ...) \
188 do { drmMsg("[W] "fmt " (%s:%d)\n", \
189 ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
190#define ERROR_MSG(fmt, ...) \
191 do { drmMsg("[E] " fmt " (%s:%d)\n", \
192 ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
193
Rob Clarkb2b18852013-07-10 15:20:04 -0400194#define U642VOID(x) ((void *)(unsigned long)(x))
195#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
196
Rob Clark73db0a02016-05-20 17:14:43 -0400197static inline uint32_t
198offset_bytes(void *end, void *start)
199{
200 return ((char *)end) - ((char *)start);
201}
202
Eric Engestrom1d7bbf82018-01-26 15:08:39 +0000203#if HAVE_VALGRIND
Rob Clarkd0dae262017-03-21 19:44:57 -0400204# include <memcheck.h>
205
206/*
207 * For tracking the backing memory (if valgrind enabled, we force a mmap
208 * for the purposes of tracking)
209 */
210static inline void VG_BO_ALLOC(struct fd_bo *bo)
211{
212 if (bo && RUNNING_ON_VALGRIND) {
213 VALGRIND_MALLOCLIKE_BLOCK(fd_bo_map(bo), bo->size, 0, 1);
214 }
215}
216
217static inline void VG_BO_FREE(struct fd_bo *bo)
218{
219 VALGRIND_FREELIKE_BLOCK(bo->map, 0);
220}
221
222/*
223 * For tracking bo structs that are in the buffer-cache, so that valgrind
224 * doesn't attribute ownership to the first one to allocate the recycled
225 * bo.
226 *
227 * Note that the list_head in fd_bo is used to track the buffers in cache
228 * so disable error reporting on the range while they are in cache so
229 * valgrind doesn't squawk about list traversal.
230 *
231 */
232static inline void VG_BO_RELEASE(struct fd_bo *bo)
233{
234 if (RUNNING_ON_VALGRIND) {
235 VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, bo->dev->bo_size);
236 VALGRIND_MAKE_MEM_NOACCESS(bo, bo->dev->bo_size);
237 VALGRIND_FREELIKE_BLOCK(bo->map, 0);
238 }
239}
240static inline void VG_BO_OBTAIN(struct fd_bo *bo)
241{
242 if (RUNNING_ON_VALGRIND) {
243 VALGRIND_MAKE_MEM_DEFINED(bo, bo->dev->bo_size);
244 VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, bo->dev->bo_size);
245 VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, 1);
246 }
247}
248#else
249static inline void VG_BO_ALLOC(struct fd_bo *bo) {}
250static inline void VG_BO_FREE(struct fd_bo *bo) {}
251static inline void VG_BO_RELEASE(struct fd_bo *bo) {}
252static inline void VG_BO_OBTAIN(struct fd_bo *bo) {}
253#endif
254
255
Rob Clark41fc2cc2012-10-07 18:57:31 -0500256#endif /* FREEDRENO_PRIV_H_ */