1b8e80941Smrg/* 2b8e80941Smrg * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org> 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20b8e80941Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21b8e80941Smrg * SOFTWARE. 22b8e80941Smrg * 23b8e80941Smrg * Authors: 24b8e80941Smrg * Rob Clark <robclark@freedesktop.org> 25b8e80941Smrg */ 26b8e80941Smrg 27b8e80941Smrg#ifndef FREEDRENO_PRIV_H_ 28b8e80941Smrg#define FREEDRENO_PRIV_H_ 29b8e80941Smrg 30b8e80941Smrg#include <stdlib.h> 31b8e80941Smrg#include <errno.h> 32b8e80941Smrg#include <string.h> 33b8e80941Smrg#include <unistd.h> 34b8e80941Smrg#include <errno.h> 35b8e80941Smrg#include <fcntl.h> 36b8e80941Smrg#include <sys/ioctl.h> 37b8e80941Smrg#include <sys/mman.h> 38b8e80941Smrg#include <pthread.h> 39b8e80941Smrg#include <stdio.h> 40b8e80941Smrg 41b8e80941Smrg#include <xf86drm.h> 42b8e80941Smrg 43b8e80941Smrg#include "util/hash_table.h" 44b8e80941Smrg#include "util/list.h" 45b8e80941Smrg#include "util/u_debug.h" 46b8e80941Smrg#include "util/u_atomic.h" 47b8e80941Smrg#include "util/u_math.h" 48b8e80941Smrg#include "util/u_debug.h" 49b8e80941Smrg 50b8e80941Smrg#include "freedreno_drmif.h" 51b8e80941Smrg#include "freedreno_ringbuffer.h" 52b8e80941Smrg 53b8e80941Smrg#define atomic_dec_and_test(x) (__sync_add_and_fetch (x, -1) == 0) 54b8e80941Smrg 55b8e80941Smrgstruct fd_device_funcs { 56b8e80941Smrg int (*bo_new_handle)(struct fd_device *dev, uint32_t size, 57b8e80941Smrg uint32_t flags, uint32_t *handle); 58b8e80941Smrg struct fd_bo * (*bo_from_handle)(struct fd_device *dev, 59b8e80941Smrg uint32_t size, uint32_t handle); 60b8e80941Smrg struct fd_pipe * (*pipe_new)(struct fd_device *dev, enum fd_pipe_id id, 61b8e80941Smrg unsigned prio); 62b8e80941Smrg void (*destroy)(struct fd_device *dev); 63b8e80941Smrg}; 64b8e80941Smrg 65b8e80941Smrgstruct fd_bo_bucket { 66b8e80941Smrg uint32_t size; 67b8e80941Smrg struct list_head list; 68b8e80941Smrg}; 69b8e80941Smrg 70b8e80941Smrgstruct fd_bo_cache { 71b8e80941Smrg struct fd_bo_bucket cache_bucket[14 * 4]; 72b8e80941Smrg int num_buckets; 73b8e80941Smrg time_t time; 74b8e80941Smrg}; 75b8e80941Smrg 76b8e80941Smrgstruct fd_device { 77b8e80941Smrg int fd; 78b8e80941Smrg enum fd_version version; 79b8e80941Smrg int32_t refcnt; 80b8e80941Smrg 81b8e80941Smrg /* tables to keep track of bo's, to avoid "evil-twin" fd_bo objects: 82b8e80941Smrg * 83b8e80941Smrg * handle_table: maps handle to fd_bo 84b8e80941Smrg * name_table: maps flink name to fd_bo 85b8e80941Smrg * 86b8e80941Smrg * We end up needing two tables, because DRM_IOCTL_GEM_OPEN always 87b8e80941Smrg * returns a new handle. So we need to figure out if the bo is already 88b8e80941Smrg * open in the process first, before calling gem-open. 89b8e80941Smrg */ 90b8e80941Smrg struct hash_table *handle_table, *name_table; 91b8e80941Smrg 92b8e80941Smrg const struct fd_device_funcs *funcs; 93b8e80941Smrg 94b8e80941Smrg struct fd_bo_cache bo_cache; 95b8e80941Smrg struct fd_bo_cache ring_cache; 96b8e80941Smrg 97b8e80941Smrg int closefd; /* call close(fd) upon destruction */ 98b8e80941Smrg 99b8e80941Smrg /* just for valgrind: */ 100b8e80941Smrg int bo_size; 101b8e80941Smrg}; 102b8e80941Smrg 103b8e80941Smrgvoid fd_bo_cache_init(struct fd_bo_cache *cache, int coarse); 104b8e80941Smrgvoid fd_bo_cache_cleanup(struct fd_bo_cache *cache, time_t time); 105b8e80941Smrgstruct fd_bo * fd_bo_cache_alloc(struct fd_bo_cache *cache, 106b8e80941Smrg uint32_t *size, uint32_t flags); 107b8e80941Smrgint fd_bo_cache_free(struct fd_bo_cache *cache, struct fd_bo *bo); 108b8e80941Smrg 109b8e80941Smrg/* for where @table_lock is already held: */ 110b8e80941Smrgvoid fd_device_del_locked(struct fd_device *dev); 111b8e80941Smrg 112b8e80941Smrgstruct fd_pipe_funcs { 113b8e80941Smrg struct fd_ringbuffer * (*ringbuffer_new_object)(struct fd_pipe *pipe, uint32_t size); 114b8e80941Smrg struct fd_submit * (*submit_new)(struct fd_pipe *pipe); 115b8e80941Smrg int (*get_param)(struct fd_pipe *pipe, enum fd_param_id param, uint64_t *value); 116b8e80941Smrg int (*wait)(struct fd_pipe *pipe, uint32_t timestamp, uint64_t timeout); 117b8e80941Smrg void (*destroy)(struct fd_pipe *pipe); 118b8e80941Smrg}; 119b8e80941Smrg 120b8e80941Smrgstruct fd_pipe { 121b8e80941Smrg struct fd_device *dev; 122b8e80941Smrg enum fd_pipe_id id; 123b8e80941Smrg uint32_t gpu_id; 124b8e80941Smrg int32_t refcnt; 125b8e80941Smrg const struct fd_pipe_funcs *funcs; 126b8e80941Smrg}; 127b8e80941Smrg 128b8e80941Smrgstruct fd_submit_funcs { 129b8e80941Smrg struct fd_ringbuffer * (*new_ringbuffer)(struct fd_submit *submit, 130b8e80941Smrg uint32_t size, enum fd_ringbuffer_flags flags); 131b8e80941Smrg int (*flush)(struct fd_submit *submit, int in_fence_fd, 132b8e80941Smrg int *out_fence_fd, uint32_t *out_fence); 133b8e80941Smrg void (*destroy)(struct fd_submit *submit); 134b8e80941Smrg}; 135b8e80941Smrg 136b8e80941Smrgstruct fd_submit { 137b8e80941Smrg struct fd_pipe *pipe; 138b8e80941Smrg const struct fd_submit_funcs *funcs; 139b8e80941Smrg}; 140b8e80941Smrg 141b8e80941Smrgstruct fd_ringbuffer_funcs { 142b8e80941Smrg void (*grow)(struct fd_ringbuffer *ring, uint32_t size); 143b8e80941Smrg void (*emit_reloc)(struct fd_ringbuffer *ring, 144b8e80941Smrg const struct fd_reloc *reloc); 145b8e80941Smrg uint32_t (*emit_reloc_ring)(struct fd_ringbuffer *ring, 146b8e80941Smrg struct fd_ringbuffer *target, uint32_t cmd_idx); 147b8e80941Smrg uint32_t (*cmd_count)(struct fd_ringbuffer *ring); 148b8e80941Smrg void (*destroy)(struct fd_ringbuffer *ring); 149b8e80941Smrg}; 150b8e80941Smrg 151b8e80941Smrgstruct fd_bo_funcs { 152b8e80941Smrg int (*offset)(struct fd_bo *bo, uint64_t *offset); 153b8e80941Smrg int (*cpu_prep)(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op); 154b8e80941Smrg void (*cpu_fini)(struct fd_bo *bo); 155b8e80941Smrg int (*madvise)(struct fd_bo *bo, int willneed); 156b8e80941Smrg uint64_t (*iova)(struct fd_bo *bo); 157b8e80941Smrg void (*set_name)(struct fd_bo *bo, const char *fmt, va_list ap); 158b8e80941Smrg void (*destroy)(struct fd_bo *bo); 159b8e80941Smrg}; 160b8e80941Smrg 161b8e80941Smrgstruct fd_bo { 162b8e80941Smrg struct fd_device *dev; 163b8e80941Smrg uint32_t size; 164b8e80941Smrg uint32_t handle; 165b8e80941Smrg uint32_t name; 166b8e80941Smrg int32_t refcnt; 167b8e80941Smrg uint64_t iova; 168b8e80941Smrg void *map; 169b8e80941Smrg const struct fd_bo_funcs *funcs; 170b8e80941Smrg 171b8e80941Smrg enum { 172b8e80941Smrg NO_CACHE = 0, 173b8e80941Smrg BO_CACHE = 1, 174b8e80941Smrg RING_CACHE = 2, 175b8e80941Smrg } bo_reuse; 176b8e80941Smrg 177b8e80941Smrg struct list_head list; /* bucket-list entry */ 178b8e80941Smrg time_t free_time; /* time when added to bucket-list */ 179b8e80941Smrg}; 180b8e80941Smrg 181b8e80941Smrgstruct fd_bo *fd_bo_new_ring(struct fd_device *dev, 182b8e80941Smrg uint32_t size, uint32_t flags); 183b8e80941Smrg 184b8e80941Smrg#define enable_debug 0 /* TODO make dynamic */ 185b8e80941Smrg 186b8e80941Smrg#define INFO_MSG(fmt, ...) \ 187b8e80941Smrg do { debug_printf("[I] "fmt " (%s:%d)\n", \ 188b8e80941Smrg ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 189b8e80941Smrg#define DEBUG_MSG(fmt, ...) \ 190b8e80941Smrg do if (enable_debug) { debug_printf("[D] "fmt " (%s:%d)\n", \ 191b8e80941Smrg ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 192b8e80941Smrg#define WARN_MSG(fmt, ...) \ 193b8e80941Smrg do { debug_printf("[W] "fmt " (%s:%d)\n", \ 194b8e80941Smrg ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 195b8e80941Smrg#define ERROR_MSG(fmt, ...) \ 196b8e80941Smrg do { debug_printf("[E] " fmt " (%s:%d)\n", \ 197b8e80941Smrg ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 198b8e80941Smrg 199b8e80941Smrg#define U642VOID(x) ((void *)(unsigned long)(x)) 200b8e80941Smrg#define VOID2U64(x) ((uint64_t)(unsigned long)(x)) 201b8e80941Smrg 202b8e80941Smrg#if HAVE_VALGRIND 203b8e80941Smrg# include <memcheck.h> 204b8e80941Smrg 205b8e80941Smrg/* 206b8e80941Smrg * For tracking the backing memory (if valgrind enabled, we force a mmap 207b8e80941Smrg * for the purposes of tracking) 208b8e80941Smrg */ 209b8e80941Smrgstatic inline void VG_BO_ALLOC(struct fd_bo *bo) 210b8e80941Smrg{ 211b8e80941Smrg if (bo && RUNNING_ON_VALGRIND) { 212b8e80941Smrg VALGRIND_MALLOCLIKE_BLOCK(fd_bo_map(bo), bo->size, 0, 1); 213b8e80941Smrg } 214b8e80941Smrg} 215b8e80941Smrg 216b8e80941Smrgstatic inline void VG_BO_FREE(struct fd_bo *bo) 217b8e80941Smrg{ 218b8e80941Smrg VALGRIND_FREELIKE_BLOCK(bo->map, 0); 219b8e80941Smrg} 220b8e80941Smrg 221b8e80941Smrg/* 222b8e80941Smrg * For tracking bo structs that are in the buffer-cache, so that valgrind 223b8e80941Smrg * doesn't attribute ownership to the first one to allocate the recycled 224b8e80941Smrg * bo. 225b8e80941Smrg * 226b8e80941Smrg * Note that the list_head in fd_bo is used to track the buffers in cache 227b8e80941Smrg * so disable error reporting on the range while they are in cache so 228b8e80941Smrg * valgrind doesn't squawk about list traversal. 229b8e80941Smrg * 230b8e80941Smrg */ 231b8e80941Smrgstatic inline void VG_BO_RELEASE(struct fd_bo *bo) 232b8e80941Smrg{ 233b8e80941Smrg if (RUNNING_ON_VALGRIND) { 234b8e80941Smrg VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, bo->dev->bo_size); 235b8e80941Smrg VALGRIND_MAKE_MEM_NOACCESS(bo, bo->dev->bo_size); 236b8e80941Smrg VALGRIND_FREELIKE_BLOCK(bo->map, 0); 237b8e80941Smrg } 238b8e80941Smrg} 239b8e80941Smrgstatic inline void VG_BO_OBTAIN(struct fd_bo *bo) 240b8e80941Smrg{ 241b8e80941Smrg if (RUNNING_ON_VALGRIND) { 242b8e80941Smrg VALGRIND_MAKE_MEM_DEFINED(bo, bo->dev->bo_size); 243b8e80941Smrg VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, bo->dev->bo_size); 244b8e80941Smrg VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, 1); 245b8e80941Smrg } 246b8e80941Smrg} 247b8e80941Smrg#else 248b8e80941Smrgstatic inline void VG_BO_ALLOC(struct fd_bo *bo) {} 249b8e80941Smrgstatic inline void VG_BO_FREE(struct fd_bo *bo) {} 250b8e80941Smrgstatic inline void VG_BO_RELEASE(struct fd_bo *bo) {} 251b8e80941Smrgstatic inline void VG_BO_OBTAIN(struct fd_bo *bo) {} 252b8e80941Smrg#endif 253b8e80941Smrg 254b8e80941Smrg#define FD_DEFINE_CAST(parent, child) \ 255b8e80941Smrgstatic inline struct child * to_ ## child (struct parent *x) \ 256b8e80941Smrg{ return (struct child *)x; } 257b8e80941Smrg 258b8e80941Smrg 259b8e80941Smrg#endif /* FREEDRENO_PRIV_H_ */ 260