Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 1 | /* -*- 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 Lankhorst | 479b6ce | 2014-08-04 11:23:20 +0200 | [diff] [blame] | 32 | #ifdef HAVE_CONFIG_H |
| 33 | #include "config.h" |
| 34 | #endif |
| 35 | |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 36 | #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 Clark | 0b89e27 | 2013-05-15 13:18:02 -0400 | [diff] [blame] | 43 | #include <pthread.h> |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 44 | #include <stdio.h> |
| 45 | #include <assert.h> |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 46 | |
Emil Velikov | 42465fe | 2015-04-05 15:51:59 +0100 | [diff] [blame] | 47 | #include "libdrm_macros.h" |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 48 | #include "xf86drm.h" |
| 49 | #include "xf86atomic.h" |
| 50 | |
Alex Deucher | 4ee0fa2 | 2015-05-07 13:03:47 -0400 | [diff] [blame] | 51 | #include "util_double_list.h" |
Rob Clark | 6f0f6ce | 2018-01-24 15:08:46 -0500 | [diff] [blame] | 52 | #include "util_math.h" |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 53 | |
| 54 | #include "freedreno_drmif.h" |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 55 | #include "freedreno_ringbuffer.h" |
Emil Velikov | 126c458 | 2013-08-29 21:31:52 +0100 | [diff] [blame] | 56 | #include "drm.h" |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 57 | |
Rob Clark | eb846d4 | 2016-05-31 12:06:50 -0400 | [diff] [blame] | 58 | #ifndef TRUE |
| 59 | # define TRUE 1 |
| 60 | #endif |
| 61 | #ifndef FALSE |
| 62 | # define FALSE 0 |
| 63 | #endif |
| 64 | |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 65 | struct 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 Clark | 7064b2e | 2017-08-23 17:08:39 -0400 | [diff] [blame] | 70 | struct fd_pipe * (*pipe_new)(struct fd_device *dev, enum fd_pipe_id id, |
| 71 | unsigned prio); |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 72 | void (*destroy)(struct fd_device *dev); |
| 73 | }; |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 74 | |
Rob Clark | 068ea68 | 2013-12-13 12:48:30 -0500 | [diff] [blame] | 75 | struct fd_bo_bucket { |
| 76 | uint32_t size; |
| 77 | struct list_head list; |
| 78 | }; |
| 79 | |
Rob Clark | b18b6e2 | 2016-05-30 11:49:39 -0400 | [diff] [blame] | 80 | struct fd_bo_cache { |
| 81 | struct fd_bo_bucket cache_bucket[14 * 4]; |
| 82 | int num_buckets; |
| 83 | time_t time; |
| 84 | }; |
| 85 | |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 86 | struct fd_device { |
| 87 | int fd; |
Rob Clark | 904f136 | 2016-06-01 14:35:44 -0400 | [diff] [blame] | 88 | enum fd_version version; |
Rob Clark | 0b89e27 | 2013-05-15 13:18:02 -0400 | [diff] [blame] | 89 | 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 Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 101 | |
Emil Velikov | 6a6d668 | 2015-08-15 17:17:52 +0100 | [diff] [blame] | 102 | const struct fd_device_funcs *funcs; |
Rob Clark | 068ea68 | 2013-12-13 12:48:30 -0500 | [diff] [blame] | 103 | |
Rob Clark | b18b6e2 | 2016-05-30 11:49:39 -0400 | [diff] [blame] | 104 | struct fd_bo_cache bo_cache; |
Rob Clark | 8279c8f | 2014-01-12 08:27:36 -0500 | [diff] [blame] | 105 | |
| 106 | int closefd; /* call close(fd) upon destruction */ |
Rob Clark | d0dae26 | 2017-03-21 19:44:57 -0400 | [diff] [blame] | 107 | |
| 108 | /* just for valgrind: */ |
| 109 | int bo_size; |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 110 | }; |
| 111 | |
Rob Clark | 8a6a851 | 2016-06-01 15:37:52 -0400 | [diff] [blame] | 112 | drm_private void fd_bo_cache_init(struct fd_bo_cache *cache, int coarse); |
Rob Clark | 0b34b68 | 2016-05-30 12:45:33 -0400 | [diff] [blame] | 113 | drm_private void fd_bo_cache_cleanup(struct fd_bo_cache *cache, time_t time); |
| 114 | drm_private struct fd_bo * fd_bo_cache_alloc(struct fd_bo_cache *cache, |
| 115 | uint32_t *size, uint32_t flags); |
| 116 | drm_private int fd_bo_cache_free(struct fd_bo_cache *cache, struct fd_bo *bo); |
Rob Clark | 068ea68 | 2013-12-13 12:48:30 -0500 | [diff] [blame] | 117 | |
| 118 | /* for where @table_lock is already held: */ |
Emil Velikov | 44e9a02 | 2015-03-23 21:35:38 +0000 | [diff] [blame] | 119 | drm_private void fd_device_del_locked(struct fd_device *dev); |
Rob Clark | 068ea68 | 2013-12-13 12:48:30 -0500 | [diff] [blame] | 120 | |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 121 | struct 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 Clark | 15ba876 | 2015-08-17 10:33:59 -0400 | [diff] [blame] | 124 | int (*wait)(struct fd_pipe *pipe, uint32_t timestamp, uint64_t timeout); |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 125 | void (*destroy)(struct fd_pipe *pipe); |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 126 | }; |
| 127 | |
| 128 | struct fd_pipe { |
| 129 | struct fd_device *dev; |
| 130 | enum fd_pipe_id id; |
Rob Clark | 23d10b8 | 2016-11-09 09:02:09 -0500 | [diff] [blame] | 131 | uint32_t gpu_id; |
Emil Velikov | 6a6d668 | 2015-08-15 17:17:52 +0100 | [diff] [blame] | 132 | const struct fd_pipe_funcs *funcs; |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 133 | }; |
| 134 | |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 135 | struct fd_ringmarker { |
| 136 | struct fd_ringbuffer *ring; |
| 137 | uint32_t *cur; |
| 138 | }; |
| 139 | |
| 140 | struct fd_ringbuffer_funcs { |
| 141 | void * (*hostptr)(struct fd_ringbuffer *ring); |
Rob Clark | e9eb44b | 2016-08-15 13:26:18 -0400 | [diff] [blame] | 142 | int (*flush)(struct fd_ringbuffer *ring, uint32_t *last_start, |
| 143 | int in_fence_fd, int *out_fence_fd); |
Rob Clark | 419a154 | 2016-06-20 14:06:24 -0400 | [diff] [blame] | 144 | void (*grow)(struct fd_ringbuffer *ring, uint32_t size); |
Rob Clark | c5de5ab | 2014-02-19 11:01:23 -0500 | [diff] [blame] | 145 | void (*reset)(struct fd_ringbuffer *ring); |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 146 | void (*emit_reloc)(struct fd_ringbuffer *ring, |
| 147 | const struct fd_reloc *reloc); |
Rob Clark | 419a154 | 2016-06-20 14:06:24 -0400 | [diff] [blame] | 148 | uint32_t (*emit_reloc_ring)(struct fd_ringbuffer *ring, |
| 149 | struct fd_ringbuffer *target, uint32_t cmd_idx, |
Rob Clark | 73db0a0 | 2016-05-20 17:14:43 -0400 | [diff] [blame] | 150 | uint32_t submit_offset, uint32_t size); |
Rob Clark | 419a154 | 2016-06-20 14:06:24 -0400 | [diff] [blame] | 151 | uint32_t (*cmd_count)(struct fd_ringbuffer *ring); |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 152 | void (*destroy)(struct fd_ringbuffer *ring); |
| 153 | }; |
| 154 | |
| 155 | struct 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 Clark | eb846d4 | 2016-05-31 12:06:50 -0400 | [diff] [blame] | 159 | int (*madvise)(struct fd_bo *bo, int willneed); |
Rob Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 160 | void (*destroy)(struct fd_bo *bo); |
| 161 | }; |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 162 | |
| 163 | struct fd_bo { |
| 164 | struct fd_device *dev; |
| 165 | uint32_t size; |
| 166 | uint32_t handle; |
| 167 | uint32_t name; |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 168 | void *map; |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 169 | atomic_t refcnt; |
Emil Velikov | 6a6d668 | 2015-08-15 17:17:52 +0100 | [diff] [blame] | 170 | const struct fd_bo_funcs *funcs; |
Rob Clark | 068ea68 | 2013-12-13 12:48:30 -0500 | [diff] [blame] | 171 | |
| 172 | int bo_reuse; |
| 173 | struct list_head list; /* bucket-list entry */ |
| 174 | time_t free_time; /* time when added to bucket-list */ |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 175 | }; |
| 176 | |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 177 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) |
| 178 | |
Rob Clark | f17d417 | 2013-07-20 20:35:31 -0400 | [diff] [blame] | 179 | #define enable_debug 0 /* TODO make dynamic */ |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 180 | |
| 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 Clark | b2b1885 | 2013-07-10 15:20:04 -0400 | [diff] [blame] | 194 | #define U642VOID(x) ((void *)(unsigned long)(x)) |
| 195 | #define VOID2U64(x) ((uint64_t)(unsigned long)(x)) |
| 196 | |
Rob Clark | 73db0a0 | 2016-05-20 17:14:43 -0400 | [diff] [blame] | 197 | static inline uint32_t |
| 198 | offset_bytes(void *end, void *start) |
| 199 | { |
| 200 | return ((char *)end) - ((char *)start); |
| 201 | } |
| 202 | |
Eric Engestrom | 1d7bbf8 | 2018-01-26 15:08:39 +0000 | [diff] [blame^] | 203 | #if HAVE_VALGRIND |
Rob Clark | d0dae26 | 2017-03-21 19:44:57 -0400 | [diff] [blame] | 204 | # 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 | */ |
| 210 | static 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 | |
| 217 | static 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 | */ |
| 232 | static 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 | } |
| 240 | static 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 |
| 249 | static inline void VG_BO_ALLOC(struct fd_bo *bo) {} |
| 250 | static inline void VG_BO_FREE(struct fd_bo *bo) {} |
| 251 | static inline void VG_BO_RELEASE(struct fd_bo *bo) {} |
| 252 | static inline void VG_BO_OBTAIN(struct fd_bo *bo) {} |
| 253 | #endif |
| 254 | |
| 255 | |
Rob Clark | 41fc2cc | 2012-10-07 18:57:31 -0500 | [diff] [blame] | 256 | #endif /* FREEDRENO_PRIV_H_ */ |