1/* 2 * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org> 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 * Rob Clark <robclark@freedesktop.org> 25 */ 26 27#ifndef FREEDRENO_PRIV_H_ 28#define FREEDRENO_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 <sys/mman.h> 38#include <pthread.h> 39#include <stdio.h> 40 41#include <xf86drm.h> 42 43#include "util/hash_table.h" 44#include "util/list.h" 45#include "util/u_debug.h" 46#include "util/u_atomic.h" 47#include "util/u_math.h" 48#include "util/u_debug.h" 49 50#include "freedreno_drmif.h" 51#include "freedreno_ringbuffer.h" 52 53#define atomic_dec_and_test(x) (__sync_add_and_fetch (x, -1) == 0) 54 55struct fd_device_funcs { 56 int (*bo_new_handle)(struct fd_device *dev, uint32_t size, 57 uint32_t flags, uint32_t *handle); 58 struct fd_bo * (*bo_from_handle)(struct fd_device *dev, 59 uint32_t size, uint32_t handle); 60 struct fd_pipe * (*pipe_new)(struct fd_device *dev, enum fd_pipe_id id, 61 unsigned prio); 62 void (*destroy)(struct fd_device *dev); 63}; 64 65struct fd_bo_bucket { 66 uint32_t size; 67 struct list_head list; 68}; 69 70struct fd_bo_cache { 71 struct fd_bo_bucket cache_bucket[14 * 4]; 72 int num_buckets; 73 time_t time; 74}; 75 76struct fd_device { 77 int fd; 78 enum fd_version version; 79 int32_t refcnt; 80 81 /* tables to keep track of bo's, to avoid "evil-twin" fd_bo objects: 82 * 83 * handle_table: maps handle to fd_bo 84 * name_table: maps flink name to fd_bo 85 * 86 * We end up needing two tables, because DRM_IOCTL_GEM_OPEN always 87 * returns a new handle. So we need to figure out if the bo is already 88 * open in the process first, before calling gem-open. 89 */ 90 struct hash_table *handle_table, *name_table; 91 92 const struct fd_device_funcs *funcs; 93 94 struct fd_bo_cache bo_cache; 95 struct fd_bo_cache ring_cache; 96 97 int closefd; /* call close(fd) upon destruction */ 98 99 /* just for valgrind: */ 100 int bo_size; 101}; 102 103void fd_bo_cache_init(struct fd_bo_cache *cache, int coarse); 104void fd_bo_cache_cleanup(struct fd_bo_cache *cache, time_t time); 105struct fd_bo * fd_bo_cache_alloc(struct fd_bo_cache *cache, 106 uint32_t *size, uint32_t flags); 107int fd_bo_cache_free(struct fd_bo_cache *cache, struct fd_bo *bo); 108 109/* for where @table_lock is already held: */ 110void fd_device_del_locked(struct fd_device *dev); 111 112struct fd_pipe_funcs { 113 struct fd_ringbuffer * (*ringbuffer_new_object)(struct fd_pipe *pipe, uint32_t size); 114 struct fd_submit * (*submit_new)(struct fd_pipe *pipe); 115 int (*get_param)(struct fd_pipe *pipe, enum fd_param_id param, uint64_t *value); 116 int (*wait)(struct fd_pipe *pipe, uint32_t timestamp, uint64_t timeout); 117 void (*destroy)(struct fd_pipe *pipe); 118}; 119 120struct fd_pipe { 121 struct fd_device *dev; 122 enum fd_pipe_id id; 123 uint32_t gpu_id; 124 int32_t refcnt; 125 const struct fd_pipe_funcs *funcs; 126}; 127 128struct fd_submit_funcs { 129 struct fd_ringbuffer * (*new_ringbuffer)(struct fd_submit *submit, 130 uint32_t size, enum fd_ringbuffer_flags flags); 131 int (*flush)(struct fd_submit *submit, int in_fence_fd, 132 int *out_fence_fd, uint32_t *out_fence); 133 void (*destroy)(struct fd_submit *submit); 134}; 135 136struct fd_submit { 137 struct fd_pipe *pipe; 138 const struct fd_submit_funcs *funcs; 139}; 140 141struct fd_ringbuffer_funcs { 142 void (*grow)(struct fd_ringbuffer *ring, uint32_t size); 143 void (*emit_reloc)(struct fd_ringbuffer *ring, 144 const struct fd_reloc *reloc); 145 uint32_t (*emit_reloc_ring)(struct fd_ringbuffer *ring, 146 struct fd_ringbuffer *target, uint32_t cmd_idx); 147 uint32_t (*cmd_count)(struct fd_ringbuffer *ring); 148 void (*destroy)(struct fd_ringbuffer *ring); 149}; 150 151struct fd_bo_funcs { 152 int (*offset)(struct fd_bo *bo, uint64_t *offset); 153 int (*cpu_prep)(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op); 154 void (*cpu_fini)(struct fd_bo *bo); 155 int (*madvise)(struct fd_bo *bo, int willneed); 156 uint64_t (*iova)(struct fd_bo *bo); 157 void (*set_name)(struct fd_bo *bo, const char *fmt, va_list ap); 158 void (*destroy)(struct fd_bo *bo); 159}; 160 161struct fd_bo { 162 struct fd_device *dev; 163 uint32_t size; 164 uint32_t handle; 165 uint32_t name; 166 int32_t refcnt; 167 uint64_t iova; 168 void *map; 169 const struct fd_bo_funcs *funcs; 170 171 enum { 172 NO_CACHE = 0, 173 BO_CACHE = 1, 174 RING_CACHE = 2, 175 } bo_reuse; 176 177 struct list_head list; /* bucket-list entry */ 178 time_t free_time; /* time when added to bucket-list */ 179}; 180 181struct fd_bo *fd_bo_new_ring(struct fd_device *dev, 182 uint32_t size, uint32_t flags); 183 184#define enable_debug 0 /* TODO make dynamic */ 185 186#define INFO_MSG(fmt, ...) \ 187 do { debug_printf("[I] "fmt " (%s:%d)\n", \ 188 ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 189#define DEBUG_MSG(fmt, ...) \ 190 do if (enable_debug) { debug_printf("[D] "fmt " (%s:%d)\n", \ 191 ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 192#define WARN_MSG(fmt, ...) \ 193 do { debug_printf("[W] "fmt " (%s:%d)\n", \ 194 ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 195#define ERROR_MSG(fmt, ...) \ 196 do { debug_printf("[E] " fmt " (%s:%d)\n", \ 197 ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 198 199#define U642VOID(x) ((void *)(unsigned long)(x)) 200#define VOID2U64(x) ((uint64_t)(unsigned long)(x)) 201 202#if HAVE_VALGRIND 203# include <memcheck.h> 204 205/* 206 * For tracking the backing memory (if valgrind enabled, we force a mmap 207 * for the purposes of tracking) 208 */ 209static inline void VG_BO_ALLOC(struct fd_bo *bo) 210{ 211 if (bo && RUNNING_ON_VALGRIND) { 212 VALGRIND_MALLOCLIKE_BLOCK(fd_bo_map(bo), bo->size, 0, 1); 213 } 214} 215 216static inline void VG_BO_FREE(struct fd_bo *bo) 217{ 218 VALGRIND_FREELIKE_BLOCK(bo->map, 0); 219} 220 221/* 222 * For tracking bo structs that are in the buffer-cache, so that valgrind 223 * doesn't attribute ownership to the first one to allocate the recycled 224 * bo. 225 * 226 * Note that the list_head in fd_bo is used to track the buffers in cache 227 * so disable error reporting on the range while they are in cache so 228 * valgrind doesn't squawk about list traversal. 229 * 230 */ 231static inline void VG_BO_RELEASE(struct fd_bo *bo) 232{ 233 if (RUNNING_ON_VALGRIND) { 234 VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, bo->dev->bo_size); 235 VALGRIND_MAKE_MEM_NOACCESS(bo, bo->dev->bo_size); 236 VALGRIND_FREELIKE_BLOCK(bo->map, 0); 237 } 238} 239static inline void VG_BO_OBTAIN(struct fd_bo *bo) 240{ 241 if (RUNNING_ON_VALGRIND) { 242 VALGRIND_MAKE_MEM_DEFINED(bo, bo->dev->bo_size); 243 VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, bo->dev->bo_size); 244 VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, 1); 245 } 246} 247#else 248static inline void VG_BO_ALLOC(struct fd_bo *bo) {} 249static inline void VG_BO_FREE(struct fd_bo *bo) {} 250static inline void VG_BO_RELEASE(struct fd_bo *bo) {} 251static inline void VG_BO_OBTAIN(struct fd_bo *bo) {} 252#endif 253 254#define FD_DEFINE_CAST(parent, child) \ 255static inline struct child * to_ ## child (struct parent *x) \ 256{ return (struct child *)x; } 257 258 259#endif /* FREEDRENO_PRIV_H_ */ 260