17ec681f3Smrg/* 27ec681f3Smrg * Copyright (C) 2014-2015 Etnaviv Project 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 207ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 217ec681f3Smrg * SOFTWARE. 227ec681f3Smrg * 237ec681f3Smrg * Authors: 247ec681f3Smrg * Christian Gmeiner <christian.gmeiner@gmail.com> 257ec681f3Smrg */ 267ec681f3Smrg 277ec681f3Smrg#ifndef ETNAVIV_PRIV_H_ 287ec681f3Smrg#define ETNAVIV_PRIV_H_ 297ec681f3Smrg 307ec681f3Smrg#include <stdlib.h> 317ec681f3Smrg#include <errno.h> 327ec681f3Smrg#include <string.h> 337ec681f3Smrg#include <unistd.h> 347ec681f3Smrg#include <errno.h> 357ec681f3Smrg#include <fcntl.h> 367ec681f3Smrg#include <sys/ioctl.h> 377ec681f3Smrg#include <stdio.h> 387ec681f3Smrg#include <assert.h> 397ec681f3Smrg 407ec681f3Smrg#include <xf86drm.h> 417ec681f3Smrg 427ec681f3Smrg#include "util/list.h" 437ec681f3Smrg#include "util/macros.h" 447ec681f3Smrg#include "util/simple_mtx.h" 457ec681f3Smrg#include "util/timespec.h" 467ec681f3Smrg#include "util/u_atomic.h" 477ec681f3Smrg#include "util/u_debug.h" 487ec681f3Smrg#include "util/vma.h" 497ec681f3Smrg 507ec681f3Smrg#include "etnaviv_drmif.h" 517ec681f3Smrg#include "drm-uapi/etnaviv_drm.h" 527ec681f3Smrg 537ec681f3Smrgextern simple_mtx_t etna_drm_table_lock; 547ec681f3Smrg 557ec681f3Smrgstruct etna_bo_bucket { 567ec681f3Smrg uint32_t size; 577ec681f3Smrg struct list_head list; 587ec681f3Smrg}; 597ec681f3Smrg 607ec681f3Smrgstruct etna_bo_cache { 617ec681f3Smrg struct etna_bo_bucket cache_bucket[14 * 4]; 627ec681f3Smrg unsigned num_buckets; 637ec681f3Smrg time_t time; 647ec681f3Smrg}; 657ec681f3Smrg 667ec681f3Smrgstruct etna_device { 677ec681f3Smrg int fd; 687ec681f3Smrg uint32_t drm_version; 697ec681f3Smrg int refcnt; 707ec681f3Smrg 717ec681f3Smrg /* tables to keep track of bo's, to avoid "evil-twin" etna_bo objects: 727ec681f3Smrg * 737ec681f3Smrg * handle_table: maps handle to etna_bo 747ec681f3Smrg * name_table: maps flink name to etna_bo 757ec681f3Smrg * 767ec681f3Smrg * We end up needing two tables, because DRM_IOCTL_GEM_OPEN always 777ec681f3Smrg * returns a new handle. So we need to figure out if the bo is already 787ec681f3Smrg * open in the process first, before calling gem-open. 797ec681f3Smrg */ 807ec681f3Smrg void *handle_table, *name_table; 817ec681f3Smrg 827ec681f3Smrg struct etna_bo_cache bo_cache; 837ec681f3Smrg 847ec681f3Smrg int use_softpin; 857ec681f3Smrg struct util_vma_heap address_space; 867ec681f3Smrg 877ec681f3Smrg int closefd; /* call close(fd) upon destruction */ 887ec681f3Smrg}; 897ec681f3Smrg 907ec681f3Smrgvoid etna_bo_cache_init(struct etna_bo_cache *cache); 917ec681f3Smrgvoid etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time); 927ec681f3Smrgstruct etna_bo *etna_bo_cache_alloc(struct etna_bo_cache *cache, 937ec681f3Smrg uint32_t *size, uint32_t flags); 947ec681f3Smrgint etna_bo_cache_free(struct etna_bo_cache *cache, struct etna_bo *bo); 957ec681f3Smrg 967ec681f3Smrg/* for where @etna_drm_table_lock is already held: */ 977ec681f3Smrgvoid etna_device_del_locked(struct etna_device *dev); 987ec681f3Smrg 997ec681f3Smrg/* a GEM buffer object allocated from the DRM device */ 1007ec681f3Smrgstruct etna_bo { 1017ec681f3Smrg struct etna_device *dev; 1027ec681f3Smrg void *map; /* userspace mmap'ing (if there is one) */ 1037ec681f3Smrg uint32_t size; 1047ec681f3Smrg uint32_t handle; 1057ec681f3Smrg uint32_t flags; 1067ec681f3Smrg uint32_t name; /* flink global handle (DRI2 name) */ 1077ec681f3Smrg uint64_t offset; /* offset to mmap() */ 1087ec681f3Smrg uint32_t va; /* GPU virtual address */ 1097ec681f3Smrg int refcnt; 1107ec681f3Smrg 1117ec681f3Smrg /* 1127ec681f3Smrg * To avoid excess hashtable lookups, cache the stream this bo was 1137ec681f3Smrg * last emitted on (since that will probably also be the next ring 1147ec681f3Smrg * it is emitted on). 1157ec681f3Smrg */ 1167ec681f3Smrg struct etna_cmd_stream *current_stream; 1177ec681f3Smrg uint32_t idx; 1187ec681f3Smrg 1197ec681f3Smrg int reuse; 1207ec681f3Smrg struct list_head list; /* bucket-list entry */ 1217ec681f3Smrg time_t free_time; /* time when added to bucket-list */ 1227ec681f3Smrg}; 1237ec681f3Smrg 1247ec681f3Smrgstruct etna_gpu { 1257ec681f3Smrg struct etna_device *dev; 1267ec681f3Smrg uint32_t core; 1277ec681f3Smrg uint32_t model; 1287ec681f3Smrg uint32_t revision; 1297ec681f3Smrg}; 1307ec681f3Smrg 1317ec681f3Smrgstruct etna_pipe { 1327ec681f3Smrg enum etna_pipe_id id; 1337ec681f3Smrg struct etna_gpu *gpu; 1347ec681f3Smrg}; 1357ec681f3Smrg 1367ec681f3Smrgstruct etna_cmd_stream_priv { 1377ec681f3Smrg struct etna_cmd_stream base; 1387ec681f3Smrg struct etna_pipe *pipe; 1397ec681f3Smrg 1407ec681f3Smrg uint32_t last_timestamp; 1417ec681f3Smrg 1427ec681f3Smrg /* submit ioctl related tables: */ 1437ec681f3Smrg struct { 1447ec681f3Smrg /* bo's table: */ 1457ec681f3Smrg struct drm_etnaviv_gem_submit_bo *bos; 1467ec681f3Smrg uint32_t nr_bos, max_bos; 1477ec681f3Smrg 1487ec681f3Smrg /* reloc's table: */ 1497ec681f3Smrg struct drm_etnaviv_gem_submit_reloc *relocs; 1507ec681f3Smrg uint32_t nr_relocs, max_relocs; 1517ec681f3Smrg 1527ec681f3Smrg /* perf's table: */ 1537ec681f3Smrg struct drm_etnaviv_gem_submit_pmr *pmrs; 1547ec681f3Smrg uint32_t nr_pmrs, max_pmrs; 1557ec681f3Smrg } submit; 1567ec681f3Smrg 1577ec681f3Smrg /* should have matching entries in submit.bos: */ 1587ec681f3Smrg struct etna_bo **bos; 1597ec681f3Smrg uint32_t nr_bos, max_bos; 1607ec681f3Smrg 1617ec681f3Smrg /* notify callback if buffer reset happened */ 1627ec681f3Smrg void (*force_flush)(struct etna_cmd_stream *stream, void *priv); 1637ec681f3Smrg void *force_flush_priv; 1647ec681f3Smrg 1657ec681f3Smrg void *bo_table; 1667ec681f3Smrg}; 1677ec681f3Smrg 1687ec681f3Smrgstruct etna_perfmon { 1697ec681f3Smrg struct list_head domains; 1707ec681f3Smrg struct etna_pipe *pipe; 1717ec681f3Smrg}; 1727ec681f3Smrg 1737ec681f3Smrgstruct etna_perfmon_domain 1747ec681f3Smrg{ 1757ec681f3Smrg struct list_head head; 1767ec681f3Smrg struct list_head signals; 1777ec681f3Smrg uint8_t id; 1787ec681f3Smrg char name[64]; 1797ec681f3Smrg}; 1807ec681f3Smrg 1817ec681f3Smrgstruct etna_perfmon_signal 1827ec681f3Smrg{ 1837ec681f3Smrg struct list_head head; 1847ec681f3Smrg struct etna_perfmon_domain *domain; 1857ec681f3Smrg uint8_t signal; 1867ec681f3Smrg char name[64]; 1877ec681f3Smrg}; 1887ec681f3Smrg 1897ec681f3Smrg#define ALIGN(v,a) (((v) + (a) - 1) & ~((a) - 1)) 1907ec681f3Smrg 1917ec681f3Smrg#define enable_debug 0 /* TODO make dynamic */ 1927ec681f3Smrg 1937ec681f3Smrg#define INFO_MSG(fmt, ...) \ 1947ec681f3Smrg do { debug_printf("[I] "fmt " (%s:%d)\n", \ 1957ec681f3Smrg ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 1967ec681f3Smrg#define DEBUG_MSG(fmt, ...) \ 1977ec681f3Smrg do if (enable_debug) { debug_printf("[D] "fmt " (%s:%d)\n", \ 1987ec681f3Smrg ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 1997ec681f3Smrg#define WARN_MSG(fmt, ...) \ 2007ec681f3Smrg do { debug_printf("[W] "fmt " (%s:%d)\n", \ 2017ec681f3Smrg ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 2027ec681f3Smrg#define ERROR_MSG(fmt, ...) \ 2037ec681f3Smrg do { debug_printf("[E] " fmt " (%s:%d)\n", \ 2047ec681f3Smrg ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) 2057ec681f3Smrg 2067ec681f3Smrg#define VOID2U64(x) ((uint64_t)(unsigned long)(x)) 2077ec681f3Smrg 2087ec681f3Smrgstatic inline void get_abs_timeout(struct drm_etnaviv_timespec *tv, uint64_t ns) 2097ec681f3Smrg{ 2107ec681f3Smrg struct timespec t; 2117ec681f3Smrg clock_gettime(CLOCK_MONOTONIC, &t); 2127ec681f3Smrg tv->tv_sec = t.tv_sec + ns / NSEC_PER_SEC; 2137ec681f3Smrg tv->tv_nsec = t.tv_nsec + ns % NSEC_PER_SEC; 2147ec681f3Smrg if (tv->tv_nsec >= NSEC_PER_SEC) { 2157ec681f3Smrg tv->tv_nsec -= NSEC_PER_SEC; 2167ec681f3Smrg tv->tv_sec++; 2177ec681f3Smrg } 2187ec681f3Smrg} 2197ec681f3Smrg 2207ec681f3Smrg#if HAVE_VALGRIND 2217ec681f3Smrg# include <memcheck.h> 2227ec681f3Smrg 2237ec681f3Smrg/* 2247ec681f3Smrg * For tracking the backing memory (if valgrind enabled, we force a mmap 2257ec681f3Smrg * for the purposes of tracking) 2267ec681f3Smrg */ 2277ec681f3Smrgstatic inline void VG_BO_ALLOC(struct etna_bo *bo) 2287ec681f3Smrg{ 2297ec681f3Smrg if (bo && RUNNING_ON_VALGRIND) { 2307ec681f3Smrg VALGRIND_MALLOCLIKE_BLOCK(etna_bo_map(bo), bo->size, 0, 1); 2317ec681f3Smrg } 2327ec681f3Smrg} 2337ec681f3Smrg 2347ec681f3Smrgstatic inline void VG_BO_FREE(struct etna_bo *bo) 2357ec681f3Smrg{ 2367ec681f3Smrg VALGRIND_FREELIKE_BLOCK(bo->map, 0); 2377ec681f3Smrg} 2387ec681f3Smrg 2397ec681f3Smrg/* 2407ec681f3Smrg * For tracking bo structs that are in the buffer-cache, so that valgrind 2417ec681f3Smrg * doesn't attribute ownership to the first one to allocate the recycled 2427ec681f3Smrg * bo. 2437ec681f3Smrg * 2447ec681f3Smrg * Note that the list_head in etna_bo is used to track the buffers in cache 2457ec681f3Smrg * so disable error reporting on the range while they are in cache so 2467ec681f3Smrg * valgrind doesn't squawk about list traversal. 2477ec681f3Smrg * 2487ec681f3Smrg */ 2497ec681f3Smrgstatic inline void VG_BO_RELEASE(struct etna_bo *bo) 2507ec681f3Smrg{ 2517ec681f3Smrg if (RUNNING_ON_VALGRIND) { 2527ec681f3Smrg VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, sizeof(*bo)); 2537ec681f3Smrg VALGRIND_MAKE_MEM_NOACCESS(bo, sizeof(*bo)); 2547ec681f3Smrg VALGRIND_FREELIKE_BLOCK(bo->map, 0); 2557ec681f3Smrg } 2567ec681f3Smrg} 2577ec681f3Smrgstatic inline void VG_BO_OBTAIN(struct etna_bo *bo) 2587ec681f3Smrg{ 2597ec681f3Smrg if (RUNNING_ON_VALGRIND) { 2607ec681f3Smrg VALGRIND_MAKE_MEM_DEFINED(bo, sizeof(*bo)); 2617ec681f3Smrg VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, sizeof(*bo)); 2627ec681f3Smrg VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, 1); 2637ec681f3Smrg } 2647ec681f3Smrg} 2657ec681f3Smrg#else 2667ec681f3Smrgstatic inline void VG_BO_ALLOC(struct etna_bo *bo) {} 2677ec681f3Smrgstatic inline void VG_BO_FREE(struct etna_bo *bo) {} 2687ec681f3Smrgstatic inline void VG_BO_RELEASE(struct etna_bo *bo) {} 2697ec681f3Smrgstatic inline void VG_BO_OBTAIN(struct etna_bo *bo) {} 2707ec681f3Smrg#endif 2717ec681f3Smrg 2727ec681f3Smrg#endif /* ETNAVIV_PRIV_H_ */ 273