kgem.c revision 63ef14f0
103b705cfSriastradh/* 203b705cfSriastradh * Copyright (c) 2011 Intel Corporation 303b705cfSriastradh * 403b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a 503b705cfSriastradh * copy of this software and associated documentation files (the "Software"), 603b705cfSriastradh * to deal in the Software without restriction, including without limitation 703b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 803b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the 903b705cfSriastradh * Software is furnished to do so, subject to the following conditions: 1003b705cfSriastradh * 1103b705cfSriastradh * The above copyright notice and this permission notice (including the next 1203b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the 1303b705cfSriastradh * Software. 1403b705cfSriastradh * 1503b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1603b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1703b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1803b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1903b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2003b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2103b705cfSriastradh * SOFTWARE. 2203b705cfSriastradh * 2303b705cfSriastradh * Authors: 2403b705cfSriastradh * Chris Wilson <chris@chris-wilson.co.uk> 2503b705cfSriastradh * 2603b705cfSriastradh */ 2703b705cfSriastradh 2803b705cfSriastradh#ifdef HAVE_CONFIG_H 2903b705cfSriastradh#include "config.h" 3003b705cfSriastradh#endif 3103b705cfSriastradh 3203b705cfSriastradh#include "sna.h" 3303b705cfSriastradh#include "sna_reg.h" 3403b705cfSriastradh 3503b705cfSriastradh#include <unistd.h> 3603b705cfSriastradh#include <sys/ioctl.h> 3703b705cfSriastradh#include <sys/mman.h> 389a906b70Schristos#include <sys/stat.h> 3903b705cfSriastradh#include <time.h> 409a906b70Schristos#include <sched.h> 4103b705cfSriastradh#include <errno.h> 4203b705cfSriastradh#include <fcntl.h> 4303b705cfSriastradh 4403b705cfSriastradh#include <xf86drm.h> 4503b705cfSriastradh 4603b705cfSriastradh#ifdef HAVE_VALGRIND 4703b705cfSriastradh#include <valgrind.h> 4803b705cfSriastradh#include <memcheck.h> 4903b705cfSriastradh#endif 5003b705cfSriastradh 5103b705cfSriastradh#ifdef HAVE_STRUCT_SYSINFO_TOTALRAM 5203b705cfSriastradh#include <sys/sysinfo.h> 5303b705cfSriastradh#endif 5403b705cfSriastradh 5503b705cfSriastradh#include "sna_cpuid.h" 5603b705cfSriastradh 5703b705cfSriastradhstatic struct kgem_bo * 5803b705cfSriastradhsearch_linear_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags); 5903b705cfSriastradh 6003b705cfSriastradhstatic struct kgem_bo * 6103b705cfSriastradhsearch_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags); 6203b705cfSriastradh 6303b705cfSriastradh#define DBG_NO_HW 0 649a906b70Schristos#define DBG_NO_EXEC 0 6503b705cfSriastradh#define DBG_NO_TILING 0 6603b705cfSriastradh#define DBG_NO_CACHE 0 679a906b70Schristos#define DBG_NO_SNOOP_CACHE 0 6803b705cfSriastradh#define DBG_NO_CACHE_LEVEL 0 6903b705cfSriastradh#define DBG_NO_CPU 0 7003b705cfSriastradh#define DBG_NO_CREATE2 0 7103b705cfSriastradh#define DBG_NO_USERPTR 0 7203b705cfSriastradh#define DBG_NO_UNSYNCHRONIZED_USERPTR 0 7363ef14f0Smrg#define DBG_NO_COHERENT_MMAP_GTT 0 7403b705cfSriastradh#define DBG_NO_LLC 0 7503b705cfSriastradh#define DBG_NO_SEMAPHORES 0 7603b705cfSriastradh#define DBG_NO_MADV 0 7703b705cfSriastradh#define DBG_NO_UPLOAD_CACHE 0 7803b705cfSriastradh#define DBG_NO_UPLOAD_ACTIVE 0 7903b705cfSriastradh#define DBG_NO_MAP_UPLOAD 0 8003b705cfSriastradh#define DBG_NO_RELAXED_FENCING 0 8103b705cfSriastradh#define DBG_NO_SECURE_BATCHES 0 8203b705cfSriastradh#define DBG_NO_PINNED_BATCHES 0 83813957e3Ssnj#define DBG_NO_SHRINK_BATCHES 0 8403b705cfSriastradh#define DBG_NO_FAST_RELOC 0 8503b705cfSriastradh#define DBG_NO_HANDLE_LUT 0 8603b705cfSriastradh#define DBG_NO_WT 0 87813957e3Ssnj#define DBG_NO_WC_MMAP 0 8863ef14f0Smrg#define DBG_NO_BLT_Y 0 8963ef14f0Smrg#define DBG_NO_SCANOUT_Y 0 9063ef14f0Smrg#define DBG_NO_DIRTYFB 0 9163ef14f0Smrg#define DBG_NO_DETILING 0 9203b705cfSriastradh#define DBG_DUMP 0 939a906b70Schristos#define DBG_NO_MALLOC_CACHE 0 9403b705cfSriastradh 9503b705cfSriastradh#define FORCE_MMAP_SYNC 0 /* ((1 << DOMAIN_CPU) | (1 << DOMAIN_GTT)) */ 9603b705cfSriastradh 9703b705cfSriastradh#ifndef DEBUG_SYNC 9803b705cfSriastradh#define DEBUG_SYNC 0 9903b705cfSriastradh#endif 10003b705cfSriastradh 1019a906b70Schristos#define SHOW_BATCH_BEFORE 0 1029a906b70Schristos#define SHOW_BATCH_AFTER 0 10303b705cfSriastradh 10403b705cfSriastradh#if 0 10503b705cfSriastradh#define ASSERT_IDLE(kgem__, handle__) assert(!__kgem_busy(kgem__, handle__)) 10603b705cfSriastradh#define ASSERT_MAYBE_IDLE(kgem__, handle__, expect__) assert(!(expect__) || !__kgem_busy(kgem__, handle__)) 10703b705cfSriastradh#else 10803b705cfSriastradh#define ASSERT_IDLE(kgem__, handle__) 10903b705cfSriastradh#define ASSERT_MAYBE_IDLE(kgem__, handle__, expect__) 11003b705cfSriastradh#endif 11103b705cfSriastradh 11203b705cfSriastradh/* Worst case seems to be 965gm where we cannot write within a cacheline that 11303b705cfSriastradh * is being simultaneously being read by the GPU, or within the sampler 11403b705cfSriastradh * prefetch. In general, the chipsets seem to have a requirement that sampler 11503b705cfSriastradh * offsets be aligned to a cacheline (64 bytes). 1169a906b70Schristos * 1179a906b70Schristos * Actually, it turns out the BLT color pattern (BR15) has the most severe 1189a906b70Schristos * alignment restrictions, 64 bytes for 8-bpp, 128 bytes for 16-bpp and 256 1199a906b70Schristos * bytes for 32-bpp. 12003b705cfSriastradh */ 1219a906b70Schristos#define UPLOAD_ALIGNMENT 256 12203b705cfSriastradh 12303b705cfSriastradh#define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE) 12403b705cfSriastradh#define NUM_PAGES(x) (((x) + PAGE_SIZE-1) / PAGE_SIZE) 12503b705cfSriastradh 12603b705cfSriastradh#define MAX_GTT_VMA_CACHE 512 12703b705cfSriastradh#define MAX_CPU_VMA_CACHE INT16_MAX 12803b705cfSriastradh#define MAP_PRESERVE_TIME 10 12903b705cfSriastradh 1309a906b70Schristos#define MAKE_USER_MAP(ptr) ((void*)((uintptr_t)(ptr) | 1)) 1319a906b70Schristos#define IS_USER_MAP(ptr) ((uintptr_t)(ptr) & 1) 13203b705cfSriastradh 13303b705cfSriastradh#define LOCAL_I915_PARAM_HAS_BLT 11 13403b705cfSriastradh#define LOCAL_I915_PARAM_HAS_RELAXED_FENCING 12 13503b705cfSriastradh#define LOCAL_I915_PARAM_HAS_RELAXED_DELTA 15 136813957e3Ssnj#define LOCAL_I915_PARAM_HAS_LLC 17 13703b705cfSriastradh#define LOCAL_I915_PARAM_HAS_SEMAPHORES 20 13803b705cfSriastradh#define LOCAL_I915_PARAM_HAS_SECURE_BATCHES 23 13903b705cfSriastradh#define LOCAL_I915_PARAM_HAS_PINNED_BATCHES 24 14003b705cfSriastradh#define LOCAL_I915_PARAM_HAS_NO_RELOC 25 14103b705cfSriastradh#define LOCAL_I915_PARAM_HAS_HANDLE_LUT 26 14203b705cfSriastradh#define LOCAL_I915_PARAM_HAS_WT 27 143813957e3Ssnj#define LOCAL_I915_PARAM_MMAP_VERSION 30 14463ef14f0Smrg#define LOCAL_I915_PARAM_MMAP_GTT_COHERENT 52 14503b705cfSriastradh 14603b705cfSriastradh#define LOCAL_I915_EXEC_IS_PINNED (1<<10) 14703b705cfSriastradh#define LOCAL_I915_EXEC_NO_RELOC (1<<11) 14803b705cfSriastradh#define LOCAL_I915_EXEC_HANDLE_LUT (1<<12) 14903b705cfSriastradh 1509a906b70Schristos#define LOCAL_I915_GEM_CREATE2 0x34 15103b705cfSriastradh#define LOCAL_IOCTL_I915_GEM_CREATE2 DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_CREATE2, struct local_i915_gem_create2) 15203b705cfSriastradhstruct local_i915_gem_create2 { 15303b705cfSriastradh uint64_t size; 15403b705cfSriastradh uint32_t placement; 15503b705cfSriastradh#define LOCAL_I915_CREATE_PLACEMENT_SYSTEM 0 15603b705cfSriastradh#define LOCAL_I915_CREATE_PLACEMENT_STOLEN 1 /* Cannot use CPU mmaps or pread/pwrite */ 15703b705cfSriastradh uint32_t domain; 15803b705cfSriastradh uint32_t caching; 15903b705cfSriastradh uint32_t tiling_mode; 16003b705cfSriastradh uint32_t stride; 16103b705cfSriastradh uint32_t flags; 16203b705cfSriastradh uint32_t pad; 16303b705cfSriastradh uint32_t handle; 16403b705cfSriastradh}; 16503b705cfSriastradh 16603b705cfSriastradh#define LOCAL_I915_GEM_USERPTR 0x33 16703b705cfSriastradh#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr) 16803b705cfSriastradhstruct local_i915_gem_userptr { 16903b705cfSriastradh uint64_t user_ptr; 17003b705cfSriastradh uint64_t user_size; 17103b705cfSriastradh uint32_t flags; 1729a906b70Schristos#define I915_USERPTR_READ_ONLY 0x1 1739a906b70Schristos#define I915_USERPTR_UNSYNCHRONIZED 0x80000000 17403b705cfSriastradh uint32_t handle; 17503b705cfSriastradh}; 17603b705cfSriastradh 17703b705cfSriastradh#define UNCACHED 0 17803b705cfSriastradh#define SNOOPED 1 17903b705cfSriastradh#define DISPLAY 2 18003b705cfSriastradh 18103b705cfSriastradhstruct local_i915_gem_caching { 18203b705cfSriastradh uint32_t handle; 18303b705cfSriastradh uint32_t caching; 18403b705cfSriastradh}; 18503b705cfSriastradh 18603b705cfSriastradh#define LOCAL_I915_GEM_SET_CACHING 0x2f 1879a906b70Schristos#define LOCAL_I915_GEM_GET_CACHING 0x30 18803b705cfSriastradh#define LOCAL_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_SET_CACHING, struct local_i915_gem_caching) 1899a906b70Schristos#define LOCAL_IOCTL_I915_GEM_GET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_GET_CACHING, struct local_i915_gem_caching) 19003b705cfSriastradh 19163ef14f0Smrgstruct local_i915_gem_mmap { 19263ef14f0Smrg uint32_t handle; 19363ef14f0Smrg uint32_t pad; 19463ef14f0Smrg uint64_t offset; 19563ef14f0Smrg uint64_t size; 19663ef14f0Smrg uint64_t addr_ptr; 19763ef14f0Smrg}; 19863ef14f0Smrg#define LOCAL_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct local_i915_gem_mmap) 19963ef14f0Smrg 200813957e3Ssnjstruct local_i915_gem_mmap2 { 201813957e3Ssnj uint32_t handle; 202813957e3Ssnj uint32_t pad; 203813957e3Ssnj uint64_t offset; 204813957e3Ssnj uint64_t size; 205813957e3Ssnj uint64_t addr_ptr; 206813957e3Ssnj uint64_t flags; 207813957e3Ssnj#define I915_MMAP_WC 0x1 208813957e3Ssnj}; 209813957e3Ssnj#define LOCAL_IOCTL_I915_GEM_MMAP_v2 DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct local_i915_gem_mmap2) 210813957e3Ssnj 21103b705cfSriastradhstruct kgem_buffer { 21203b705cfSriastradh struct kgem_bo base; 21303b705cfSriastradh void *mem; 21403b705cfSriastradh uint32_t used; 21503b705cfSriastradh uint32_t need_io : 1; 21603b705cfSriastradh uint32_t write : 2; 2179a906b70Schristos uint32_t mmapped : 2; 2189a906b70Schristos}; 2199a906b70Schristosenum { 2209a906b70Schristos MMAPPED_NONE, 2219a906b70Schristos MMAPPED_GTT, 2229a906b70Schristos MMAPPED_CPU 22303b705cfSriastradh}; 22403b705cfSriastradh 22503b705cfSriastradhstatic struct kgem_bo *__kgem_freed_bo; 22603b705cfSriastradhstatic struct kgem_request *__kgem_freed_request; 22703b705cfSriastradhstatic struct drm_i915_gem_exec_object2 _kgem_dummy_exec; 22803b705cfSriastradh 22963ef14f0Smrgstatic inline struct sna *__to_sna(struct kgem *kgem) 23063ef14f0Smrg{ 23163ef14f0Smrg /* minor layering violations */ 23263ef14f0Smrg return container_of(kgem, struct sna, kgem); 23363ef14f0Smrg} 23463ef14f0Smrg 23503b705cfSriastradhstatic inline int bytes(struct kgem_bo *bo) 23603b705cfSriastradh{ 23703b705cfSriastradh return __kgem_bo_size(bo); 23803b705cfSriastradh} 23903b705cfSriastradh 24003b705cfSriastradh#define bucket(B) (B)->size.pages.bucket 24103b705cfSriastradh#define num_pages(B) (B)->size.pages.count 24203b705cfSriastradh 24363ef14f0Smrgstatic int __do_ioctl(int fd, unsigned long req, void *arg) 2449a906b70Schristos{ 24563ef14f0Smrg do { 24663ef14f0Smrg int err; 2479a906b70Schristos 24863ef14f0Smrg switch ((err = errno)) { 24963ef14f0Smrg case EAGAIN: 25063ef14f0Smrg sched_yield(); 25163ef14f0Smrg case EINTR: 25263ef14f0Smrg break; 25363ef14f0Smrg default: 25463ef14f0Smrg return -err; 25563ef14f0Smrg } 2569a906b70Schristos 25763ef14f0Smrg if (likely(ioctl(fd, req, arg) == 0)) 25863ef14f0Smrg return 0; 25963ef14f0Smrg } while (1); 26063ef14f0Smrg} 2619a906b70Schristos 26263ef14f0Smrginline static int do_ioctl(int fd, unsigned long req, void *arg) 26363ef14f0Smrg{ 26463ef14f0Smrg if (likely(ioctl(fd, req, arg) == 0)) 26563ef14f0Smrg return 0; 2669a906b70Schristos 26763ef14f0Smrg return __do_ioctl(fd, req, arg); 2689a906b70Schristos} 2699a906b70Schristos 27003b705cfSriastradh#ifdef DEBUG_MEMORY 27103b705cfSriastradhstatic void debug_alloc(struct kgem *kgem, size_t size) 27203b705cfSriastradh{ 27303b705cfSriastradh kgem->debug_memory.bo_allocs++; 27403b705cfSriastradh kgem->debug_memory.bo_bytes += size; 27503b705cfSriastradh} 27603b705cfSriastradhstatic void debug_alloc__bo(struct kgem *kgem, struct kgem_bo *bo) 27703b705cfSriastradh{ 27803b705cfSriastradh debug_alloc(kgem, bytes(bo)); 27903b705cfSriastradh} 28003b705cfSriastradh#else 28103b705cfSriastradh#define debug_alloc__bo(k, b) 28203b705cfSriastradh#endif 28303b705cfSriastradh 28403b705cfSriastradh#ifndef NDEBUG 28503b705cfSriastradhstatic void assert_tiling(struct kgem *kgem, struct kgem_bo *bo) 28603b705cfSriastradh{ 28703b705cfSriastradh struct drm_i915_gem_get_tiling tiling; 28803b705cfSriastradh 28903b705cfSriastradh assert(bo); 29003b705cfSriastradh 29163ef14f0Smrg if (!kgem->can_fence && kgem->gen >= 040 && bo->tiling) 29263ef14f0Smrg return; /* lies */ 29363ef14f0Smrg 29403b705cfSriastradh VG_CLEAR(tiling); 29503b705cfSriastradh tiling.handle = bo->handle; 2969a906b70Schristos tiling.tiling_mode = bo->tiling; 2979a906b70Schristos (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling); 29803b705cfSriastradh assert(tiling.tiling_mode == bo->tiling); 29903b705cfSriastradh} 3009a906b70Schristos 30163ef14f0Smrgstatic void assert_caching(struct kgem *kgem, struct kgem_bo *bo) 3029a906b70Schristos{ 3039a906b70Schristos struct local_i915_gem_caching arg; 3049a906b70Schristos int expect = kgem->has_llc ? SNOOPED : UNCACHED; 3059a906b70Schristos 3069a906b70Schristos VG_CLEAR(arg); 3079a906b70Schristos arg.handle = bo->handle; 3089a906b70Schristos arg.caching = expect; 3099a906b70Schristos 3109a906b70Schristos (void)do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_GET_CACHING, &arg); 3119a906b70Schristos 3129a906b70Schristos assert(arg.caching == expect); 3139a906b70Schristos} 3149a906b70Schristos 3159a906b70Schristosstatic void assert_bo_retired(struct kgem_bo *bo) 3169a906b70Schristos{ 3179a906b70Schristos DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__, 3189a906b70Schristos bo->handle, bo->domain, bo->exec != NULL, bo->rq != NULL)); 3199a906b70Schristos assert(bo->refcnt); 3209a906b70Schristos assert(bo->rq == NULL); 3219a906b70Schristos assert(bo->exec == NULL); 32263ef14f0Smrg assert(!bo->needs_flush); 3239a906b70Schristos assert(list_is_empty(&bo->request)); 3249a906b70Schristos} 32503b705cfSriastradh#else 32603b705cfSriastradh#define assert_tiling(kgem, bo) 32763ef14f0Smrg#define assert_caching(kgem, bo) 3289a906b70Schristos#define assert_bo_retired(bo) 32903b705cfSriastradh#endif 33003b705cfSriastradh 33163ef14f0Smrgstatic int __find_debugfs(struct kgem *kgem) 33263ef14f0Smrg{ 33363ef14f0Smrg int i; 33463ef14f0Smrg 33563ef14f0Smrg for (i = 0; i < DRM_MAX_MINOR; i++) { 33663ef14f0Smrg char path[80]; 33763ef14f0Smrg 33863ef14f0Smrg sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i); 33963ef14f0Smrg if (access(path, R_OK) == 0) 34063ef14f0Smrg return i; 34163ef14f0Smrg 34263ef14f0Smrg sprintf(path, "/debug/dri/%d/i915_wedged", i); 34363ef14f0Smrg if (access(path, R_OK) == 0) 34463ef14f0Smrg return i; 34563ef14f0Smrg } 34663ef14f0Smrg 34763ef14f0Smrg return -1; 34863ef14f0Smrg} 34963ef14f0Smrg 35063ef14f0Smrgstatic int kgem_get_minor(struct kgem *kgem) 35163ef14f0Smrg{ 35263ef14f0Smrg struct stat st; 35363ef14f0Smrg 35463ef14f0Smrg if (fstat(kgem->fd, &st)) 35563ef14f0Smrg return __find_debugfs(kgem); 35663ef14f0Smrg 35763ef14f0Smrg if (!S_ISCHR(st.st_mode)) 35863ef14f0Smrg return __find_debugfs(kgem); 35963ef14f0Smrg 36063ef14f0Smrg return st.st_rdev & 0x63; 36163ef14f0Smrg} 36263ef14f0Smrg 36363ef14f0Smrgstatic bool find_hang_state(struct kgem *kgem, char *path, int maxlen) 36463ef14f0Smrg{ 36563ef14f0Smrg int minor = kgem_get_minor(kgem); 36663ef14f0Smrg 36763ef14f0Smrg /* Search for our hang state in a few canonical locations. 36863ef14f0Smrg * In the unlikely event of having multiple devices, we 36963ef14f0Smrg * will need to check which minor actually corresponds to ours. 37063ef14f0Smrg */ 37163ef14f0Smrg 37263ef14f0Smrg snprintf(path, maxlen, "/sys/class/drm/card%d/error", minor); 37363ef14f0Smrg if (access(path, R_OK) == 0) 37463ef14f0Smrg return true; 37563ef14f0Smrg 37663ef14f0Smrg snprintf(path, maxlen, "/sys/kernel/debug/dri/%d/i915_error_state", minor); 37763ef14f0Smrg if (access(path, R_OK) == 0) 37863ef14f0Smrg return true; 37963ef14f0Smrg 38063ef14f0Smrg snprintf(path, maxlen, "/debug/dri/%d/i915_error_state", minor); 38163ef14f0Smrg if (access(path, R_OK) == 0) 38263ef14f0Smrg return true; 38363ef14f0Smrg 38463ef14f0Smrg path[0] = '\0'; 38563ef14f0Smrg return false; 38663ef14f0Smrg} 38763ef14f0Smrg 38863ef14f0Smrgstatic bool has_error_state(struct kgem *kgem, char *path) 38963ef14f0Smrg{ 39063ef14f0Smrg bool ret = false; 39163ef14f0Smrg char no; 39263ef14f0Smrg int fd; 39363ef14f0Smrg 39463ef14f0Smrg fd = open(path, O_RDONLY); 39563ef14f0Smrg if (fd >= 0) { 39663ef14f0Smrg ret = read(fd, &no, 1) == 1 && no != 'N'; 39763ef14f0Smrg close(fd); 39863ef14f0Smrg } 39963ef14f0Smrg 40063ef14f0Smrg return ret; 40163ef14f0Smrg} 40263ef14f0Smrg 40363ef14f0Smrgstatic int kgem_get_screen_index(struct kgem *kgem) 40463ef14f0Smrg{ 40563ef14f0Smrg return __to_sna(kgem)->scrn->scrnIndex; 40663ef14f0Smrg} 40763ef14f0Smrg 408813957e3Ssnjstatic void 409813957e3Ssnj__kgem_set_wedged(struct kgem *kgem) 410813957e3Ssnj{ 41163ef14f0Smrg static int once; 41263ef14f0Smrg char path[256]; 41363ef14f0Smrg 41463ef14f0Smrg if (kgem->wedged) 41563ef14f0Smrg return; 41663ef14f0Smrg 41763ef14f0Smrg if (!once && 41863ef14f0Smrg find_hang_state(kgem, path, sizeof(path)) && 41963ef14f0Smrg has_error_state(kgem, path)) { 42063ef14f0Smrg xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR, 42163ef14f0Smrg "When reporting this, please include %s and the full dmesg.\n", 42263ef14f0Smrg path); 42363ef14f0Smrg once = 1; 42463ef14f0Smrg } 42563ef14f0Smrg 426813957e3Ssnj kgem->wedged = true; 42763ef14f0Smrg sna_render_mark_wedged(__to_sna(kgem)); 428813957e3Ssnj} 429813957e3Ssnj 43003b705cfSriastradhstatic void kgem_sna_reset(struct kgem *kgem) 43103b705cfSriastradh{ 43263ef14f0Smrg struct sna *sna = __to_sna(kgem); 43303b705cfSriastradh 43403b705cfSriastradh sna->render.reset(sna); 43503b705cfSriastradh sna->blt_state.fill_bo = 0; 43603b705cfSriastradh} 43703b705cfSriastradh 43803b705cfSriastradhstatic void kgem_sna_flush(struct kgem *kgem) 43903b705cfSriastradh{ 44063ef14f0Smrg struct sna *sna = __to_sna(kgem); 44103b705cfSriastradh 44203b705cfSriastradh sna->render.flush(sna); 44303b705cfSriastradh 44403b705cfSriastradh if (sna->render.solid_cache.dirty) 44503b705cfSriastradh sna_render_flush_solid(sna); 44603b705cfSriastradh} 44703b705cfSriastradh 44863ef14f0Smrgstatic bool kgem_bo_rmfb(struct kgem *kgem, struct kgem_bo *bo) 44963ef14f0Smrg{ 45063ef14f0Smrg if (bo->scanout && bo->delta) { 45163ef14f0Smrg DBG(("%s: releasing fb=%d for handle=%d\n", 45263ef14f0Smrg __FUNCTION__, bo->delta, bo->handle)); 45363ef14f0Smrg /* XXX will leak if we are not DRM_MASTER. *shrug* */ 45463ef14f0Smrg do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &bo->delta); 45563ef14f0Smrg bo->delta = 0; 45663ef14f0Smrg return true; 45763ef14f0Smrg } else 45863ef14f0Smrg return false; 45963ef14f0Smrg} 46063ef14f0Smrg 46163ef14f0Smrgstatic bool kgem_set_tiling(struct kgem *kgem, struct kgem_bo *bo, 46263ef14f0Smrg int tiling, int stride) 46303b705cfSriastradh{ 46403b705cfSriastradh struct drm_i915_gem_set_tiling set_tiling; 4659a906b70Schristos int err; 46603b705cfSriastradh 46763ef14f0Smrg if (tiling == bo->tiling) { 46863ef14f0Smrg if (tiling == I915_TILING_NONE) { 46963ef14f0Smrg bo->pitch = stride; 47063ef14f0Smrg return true; 47163ef14f0Smrg } 47263ef14f0Smrg if (stride == bo->pitch) 47363ef14f0Smrg return true; 47463ef14f0Smrg } 47563ef14f0Smrg 47603b705cfSriastradh if (DBG_NO_TILING) 47703b705cfSriastradh return false; 47803b705cfSriastradh 47903b705cfSriastradh VG_CLEAR(set_tiling); 4809a906b70Schristosrestart: 48163ef14f0Smrg set_tiling.handle = bo->handle; 4829a906b70Schristos set_tiling.tiling_mode = tiling; 48363ef14f0Smrg set_tiling.stride = tiling ? stride : 0; 48403b705cfSriastradh 48563ef14f0Smrg if (ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) { 48663ef14f0Smrg bo->tiling = set_tiling.tiling_mode; 48763ef14f0Smrg bo->pitch = set_tiling.tiling_mode ? set_tiling.stride : stride; 48863ef14f0Smrg DBG(("%s: handle=%d, tiling=%d [%d], pitch=%d [%d]: %d\n", 48963ef14f0Smrg __FUNCTION__, bo->handle, 49063ef14f0Smrg bo->tiling, tiling, 49163ef14f0Smrg bo->pitch, stride, 49263ef14f0Smrg set_tiling.tiling_mode == tiling)); 49363ef14f0Smrg return set_tiling.tiling_mode == tiling && bo->pitch >= stride; 49463ef14f0Smrg } 4959a906b70Schristos 4969a906b70Schristos err = errno; 4979a906b70Schristos if (err == EINTR) 4989a906b70Schristos goto restart; 4999a906b70Schristos 5009a906b70Schristos if (err == EAGAIN) { 5019a906b70Schristos sched_yield(); 5029a906b70Schristos goto restart; 5039a906b70Schristos } 5049a906b70Schristos 50563ef14f0Smrg if (err == EBUSY && kgem_bo_rmfb(kgem, bo)) 50663ef14f0Smrg goto restart; 50763ef14f0Smrg 50863ef14f0Smrg ERR(("%s: failed to set-tiling(tiling=%d, pitch=%d) for handle=%d: %d\n", 50963ef14f0Smrg __FUNCTION__, tiling, stride, bo->handle, err)); 5109a906b70Schristos return false; 51103b705cfSriastradh} 51203b705cfSriastradh 51303b705cfSriastradhstatic bool gem_set_caching(int fd, uint32_t handle, int caching) 51403b705cfSriastradh{ 51503b705cfSriastradh struct local_i915_gem_caching arg; 51603b705cfSriastradh 51703b705cfSriastradh VG_CLEAR(arg); 51803b705cfSriastradh arg.handle = handle; 51903b705cfSriastradh arg.caching = caching; 5209a906b70Schristos return do_ioctl(fd, LOCAL_IOCTL_I915_GEM_SET_CACHING, &arg) == 0; 52103b705cfSriastradh} 52203b705cfSriastradh 52303b705cfSriastradhstatic uint32_t gem_userptr(int fd, void *ptr, int size, int read_only) 52403b705cfSriastradh{ 52503b705cfSriastradh struct local_i915_gem_userptr arg; 52603b705cfSriastradh 52703b705cfSriastradh VG_CLEAR(arg); 52803b705cfSriastradh arg.user_ptr = (uintptr_t)ptr; 52903b705cfSriastradh arg.user_size = size; 53003b705cfSriastradh arg.flags = I915_USERPTR_UNSYNCHRONIZED; 53103b705cfSriastradh if (read_only) 53203b705cfSriastradh arg.flags |= I915_USERPTR_READ_ONLY; 53303b705cfSriastradh 53403b705cfSriastradh if (DBG_NO_UNSYNCHRONIZED_USERPTR || 5359a906b70Schristos do_ioctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg)) { 53603b705cfSriastradh arg.flags &= ~I915_USERPTR_UNSYNCHRONIZED; 5379a906b70Schristos if (do_ioctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg)) { 53803b705cfSriastradh DBG(("%s: failed to map %p + %d bytes: %d\n", 53903b705cfSriastradh __FUNCTION__, ptr, size, errno)); 54003b705cfSriastradh return 0; 54103b705cfSriastradh } 54203b705cfSriastradh } 54303b705cfSriastradh 54403b705cfSriastradh return arg.handle; 54503b705cfSriastradh} 54603b705cfSriastradh 5479a906b70Schristosstatic bool __kgem_throttle(struct kgem *kgem, bool harder) 54803b705cfSriastradh{ 5499a906b70Schristos /* Let this be woken up by sigtimer so that we don't block here 5509a906b70Schristos * too much and completely starve X. We will sleep again shortly, 5519a906b70Schristos * and so catch up or detect the hang. 5529a906b70Schristos */ 5539a906b70Schristos do { 5549a906b70Schristos if (ioctl(kgem->fd, DRM_IOCTL_I915_GEM_THROTTLE) == 0) { 5559a906b70Schristos kgem->need_throttle = 0; 5569a906b70Schristos return false; 5579a906b70Schristos } 55803b705cfSriastradh 5599a906b70Schristos if (errno == EIO) 5609a906b70Schristos return true; 5619a906b70Schristos } while (harder); 5629a906b70Schristos 5639a906b70Schristos return false; 5649a906b70Schristos} 5659a906b70Schristos 5669a906b70Schristosstatic bool __kgem_throttle_retire(struct kgem *kgem, unsigned flags) 5679a906b70Schristos{ 5689a906b70Schristos if (flags & CREATE_NO_RETIRE || !kgem->need_retire) { 5699a906b70Schristos DBG(("%s: not retiring\n", __FUNCTION__)); 57003b705cfSriastradh return false; 57103b705cfSriastradh } 57203b705cfSriastradh 57303b705cfSriastradh if (kgem_retire(kgem)) 57403b705cfSriastradh return true; 57503b705cfSriastradh 57603b705cfSriastradh if (flags & CREATE_NO_THROTTLE || !kgem->need_throttle) { 57703b705cfSriastradh DBG(("%s: not throttling\n", __FUNCTION__)); 57803b705cfSriastradh return false; 57903b705cfSriastradh } 58003b705cfSriastradh 5819a906b70Schristos __kgem_throttle(kgem, false); 58203b705cfSriastradh return kgem_retire(kgem); 58303b705cfSriastradh} 58403b705cfSriastradh 58503b705cfSriastradhstatic void *__kgem_bo_map__gtt(struct kgem *kgem, struct kgem_bo *bo) 58603b705cfSriastradh{ 587813957e3Ssnj struct drm_i915_gem_mmap_gtt gtt; 58803b705cfSriastradh void *ptr; 5893d02bce8Sriastradh int err; 59003b705cfSriastradh 59103b705cfSriastradh DBG(("%s(handle=%d, size=%d)\n", __FUNCTION__, 59203b705cfSriastradh bo->handle, bytes(bo))); 59303b705cfSriastradh 59463ef14f0Smrg if (bo->tiling && !kgem->can_fence) 59563ef14f0Smrg return NULL; 59663ef14f0Smrg 597813957e3Ssnj VG_CLEAR(gtt); 59803b705cfSriastradhretry_gtt: 599813957e3Ssnj gtt.handle = bo->handle; 600813957e3Ssnj if ((err = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MMAP_GTT, >t))) { 60163ef14f0Smrg DBG(("%s: failed %d, throttling/cleaning caches\n", 60263ef14f0Smrg __FUNCTION__, err)); 60303b705cfSriastradh assert(err != EINVAL); 60403b705cfSriastradh 60503b705cfSriastradh (void)__kgem_throttle_retire(kgem, 0); 60603b705cfSriastradh if (kgem_expire_cache(kgem)) 60703b705cfSriastradh goto retry_gtt; 60803b705cfSriastradh 6099a906b70Schristos if (kgem_cleanup_cache(kgem)) 61003b705cfSriastradh goto retry_gtt; 61103b705cfSriastradh 6129a906b70Schristos ERR(("%s: failed to retrieve GTT offset for handle=%d: %d\n", 6139a906b70Schristos __FUNCTION__, bo->handle, -err)); 61403b705cfSriastradh return NULL; 61503b705cfSriastradh } 61603b705cfSriastradh 61703b705cfSriastradhretry_mmap: 6189a906b70Schristos ptr = mmap(0, bytes(bo), PROT_READ | PROT_WRITE, MAP_SHARED, 619813957e3Ssnj kgem->fd, gtt.offset); 6209a906b70Schristos if (ptr == MAP_FAILED) { 6219a906b70Schristos err = errno; 62263ef14f0Smrg DBG(("%s: failed %d, throttling/cleaning caches\n", 62363ef14f0Smrg __FUNCTION__, err)); 62403b705cfSriastradh assert(err != EINVAL); 62503b705cfSriastradh 62603b705cfSriastradh if (__kgem_throttle_retire(kgem, 0)) 62703b705cfSriastradh goto retry_mmap; 62803b705cfSriastradh 6299a906b70Schristos if (kgem_cleanup_cache(kgem)) 63003b705cfSriastradh goto retry_mmap; 63103b705cfSriastradh 6329a906b70Schristos ERR(("%s: failed to mmap handle=%d, %d bytes, into GTT domain: %d\n", 6339a906b70Schristos __FUNCTION__, bo->handle, bytes(bo), err)); 63403b705cfSriastradh ptr = NULL; 63503b705cfSriastradh } 63603b705cfSriastradh 637813957e3Ssnj /* Cache this mapping to avoid the overhead of an 638813957e3Ssnj * excruciatingly slow GTT pagefault. This is more an 639813957e3Ssnj * issue with compositing managers which need to 640813957e3Ssnj * frequently flush CPU damage to their GPU bo. 641813957e3Ssnj */ 642813957e3Ssnj return bo->map__gtt = ptr; 643813957e3Ssnj} 644813957e3Ssnj 645813957e3Ssnjstatic void *__kgem_bo_map__wc(struct kgem *kgem, struct kgem_bo *bo) 646813957e3Ssnj{ 647813957e3Ssnj struct local_i915_gem_mmap2 wc; 648813957e3Ssnj int err; 649813957e3Ssnj 650813957e3Ssnj DBG(("%s(handle=%d, size=%d)\n", __FUNCTION__, 651813957e3Ssnj bo->handle, bytes(bo))); 652813957e3Ssnj assert(kgem->has_wc_mmap); 653813957e3Ssnj 654813957e3Ssnj VG_CLEAR(wc); 655813957e3Ssnj 656813957e3Ssnjretry_wc: 657813957e3Ssnj wc.handle = bo->handle; 658813957e3Ssnj wc.offset = 0; 659813957e3Ssnj wc.size = bytes(bo); 660813957e3Ssnj wc.flags = I915_MMAP_WC; 661813957e3Ssnj if ((err = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_MMAP_v2, &wc))) { 66263ef14f0Smrg DBG(("%s: failed %d, throttling/cleaning caches\n", 66363ef14f0Smrg __FUNCTION__, err)); 664813957e3Ssnj assert(err != EINVAL); 665813957e3Ssnj 666813957e3Ssnj if (__kgem_throttle_retire(kgem, 0)) 667813957e3Ssnj goto retry_wc; 668813957e3Ssnj 669813957e3Ssnj if (kgem_cleanup_cache(kgem)) 670813957e3Ssnj goto retry_wc; 671813957e3Ssnj 672813957e3Ssnj ERR(("%s: failed to mmap handle=%d, %d bytes, into CPU(wc) domain: %d\n", 673813957e3Ssnj __FUNCTION__, bo->handle, bytes(bo), -err)); 674813957e3Ssnj return NULL; 675813957e3Ssnj } 676813957e3Ssnj 677813957e3Ssnj VG(VALGRIND_MAKE_MEM_DEFINED(wc.addr_ptr, bytes(bo))); 678813957e3Ssnj 679813957e3Ssnj DBG(("%s: caching CPU(wc) vma for %d\n", __FUNCTION__, bo->handle)); 680813957e3Ssnj return bo->map__wc = (void *)(uintptr_t)wc.addr_ptr; 681813957e3Ssnj} 682813957e3Ssnj 683813957e3Ssnjstatic void *__kgem_bo_map__cpu(struct kgem *kgem, struct kgem_bo *bo) 684813957e3Ssnj{ 68563ef14f0Smrg struct local_i915_gem_mmap arg; 686813957e3Ssnj int err; 687813957e3Ssnj 68863ef14f0Smrg VG_CLEAR(arg); 68963ef14f0Smrg arg.offset = 0; 69063ef14f0Smrg 691813957e3Ssnjretry: 69263ef14f0Smrg arg.handle = bo->handle; 69363ef14f0Smrg arg.size = bytes(bo); 69463ef14f0Smrg arg.flags = 0; 69563ef14f0Smrg if ((err = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_MMAP, &arg))) { 69663ef14f0Smrg DBG(("%s: failed %d, throttling/cleaning caches\n", 69763ef14f0Smrg __FUNCTION__, err)); 69863ef14f0Smrg assert(err != -EINVAL || bo->prime); 699813957e3Ssnj 700813957e3Ssnj if (__kgem_throttle_retire(kgem, 0)) 701813957e3Ssnj goto retry; 702813957e3Ssnj 703813957e3Ssnj if (kgem_cleanup_cache(kgem)) 704813957e3Ssnj goto retry; 705813957e3Ssnj 70663ef14f0Smrg ERR(("%s: failed to mmap handle=%d (prime? %d), %d bytes, into CPU domain: %d\n", 70763ef14f0Smrg __FUNCTION__, bo->handle, bo->prime, bytes(bo), -err)); 70863ef14f0Smrg bo->purged = 1; 709813957e3Ssnj return NULL; 710813957e3Ssnj } 711813957e3Ssnj 71263ef14f0Smrg VG(VALGRIND_MAKE_MEM_DEFINED(arg.addr_ptr, bytes(bo))); 713813957e3Ssnj 714813957e3Ssnj DBG(("%s: caching CPU vma for %d\n", __FUNCTION__, bo->handle)); 71563ef14f0Smrg return bo->map__cpu = (void *)(uintptr_t)arg.addr_ptr; 71603b705cfSriastradh} 71703b705cfSriastradh 7189a906b70Schristosstatic int gem_write(int fd, uint32_t handle, 7199a906b70Schristos int offset, int length, 7209a906b70Schristos const void *src) 72103b705cfSriastradh{ 72203b705cfSriastradh struct drm_i915_gem_pwrite pwrite; 72303b705cfSriastradh 72403b705cfSriastradh DBG(("%s(handle=%d, offset=%d, len=%d)\n", __FUNCTION__, 72503b705cfSriastradh handle, offset, length)); 72603b705cfSriastradh 72703b705cfSriastradh VG_CLEAR(pwrite); 72803b705cfSriastradh pwrite.handle = handle; 72903b705cfSriastradh pwrite.offset = offset; 73003b705cfSriastradh pwrite.size = length; 73103b705cfSriastradh pwrite.data_ptr = (uintptr_t)src; 7329a906b70Schristos return do_ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite); 73303b705cfSriastradh} 73403b705cfSriastradh 7359a906b70Schristosstatic int gem_write__cachealigned(int fd, uint32_t handle, 7369a906b70Schristos int offset, int length, 7379a906b70Schristos const void *src) 73803b705cfSriastradh{ 73903b705cfSriastradh struct drm_i915_gem_pwrite pwrite; 74003b705cfSriastradh 74103b705cfSriastradh DBG(("%s(handle=%d, offset=%d, len=%d)\n", __FUNCTION__, 74203b705cfSriastradh handle, offset, length)); 74303b705cfSriastradh 74403b705cfSriastradh VG_CLEAR(pwrite); 74503b705cfSriastradh pwrite.handle = handle; 74603b705cfSriastradh /* align the transfer to cachelines; fortuitously this is safe! */ 74703b705cfSriastradh if ((offset | length) & 63) { 74803b705cfSriastradh pwrite.offset = offset & ~63; 74903b705cfSriastradh pwrite.size = ALIGN(offset+length, 64) - pwrite.offset; 75003b705cfSriastradh pwrite.data_ptr = (uintptr_t)src + pwrite.offset - offset; 75103b705cfSriastradh } else { 75203b705cfSriastradh pwrite.offset = offset; 75303b705cfSriastradh pwrite.size = length; 75403b705cfSriastradh pwrite.data_ptr = (uintptr_t)src; 75503b705cfSriastradh } 7569a906b70Schristos return do_ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite); 75703b705cfSriastradh} 75803b705cfSriastradh 75903b705cfSriastradhstatic int gem_read(int fd, uint32_t handle, const void *dst, 76003b705cfSriastradh int offset, int length) 76103b705cfSriastradh{ 76203b705cfSriastradh struct drm_i915_gem_pread pread; 76303b705cfSriastradh int ret; 76403b705cfSriastradh 76503b705cfSriastradh DBG(("%s(handle=%d, len=%d)\n", __FUNCTION__, 76603b705cfSriastradh handle, length)); 76703b705cfSriastradh 76803b705cfSriastradh VG_CLEAR(pread); 76903b705cfSriastradh pread.handle = handle; 77003b705cfSriastradh pread.offset = offset; 77103b705cfSriastradh pread.size = length; 77203b705cfSriastradh pread.data_ptr = (uintptr_t)dst; 7739a906b70Schristos ret = do_ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &pread); 77403b705cfSriastradh if (ret) { 7759a906b70Schristos DBG(("%s: failed, errno=%d\n", __FUNCTION__, -ret)); 77603b705cfSriastradh return ret; 77703b705cfSriastradh } 77803b705cfSriastradh 77903b705cfSriastradh VG(VALGRIND_MAKE_MEM_DEFINED(dst, length)); 78003b705cfSriastradh return 0; 78103b705cfSriastradh} 78203b705cfSriastradh 78303b705cfSriastradhbool __kgem_busy(struct kgem *kgem, int handle) 78403b705cfSriastradh{ 78503b705cfSriastradh struct drm_i915_gem_busy busy; 78603b705cfSriastradh 78703b705cfSriastradh VG_CLEAR(busy); 78803b705cfSriastradh busy.handle = handle; 78903b705cfSriastradh busy.busy = !kgem->wedged; 7909a906b70Schristos (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy); 79103b705cfSriastradh DBG(("%s: handle=%d, busy=%d, wedged=%d\n", 79203b705cfSriastradh __FUNCTION__, handle, busy.busy, kgem->wedged)); 79303b705cfSriastradh 79403b705cfSriastradh return busy.busy; 79503b705cfSriastradh} 79603b705cfSriastradh 79703b705cfSriastradhstatic void kgem_bo_retire(struct kgem *kgem, struct kgem_bo *bo) 79803b705cfSriastradh{ 79903b705cfSriastradh DBG(("%s: retiring bo handle=%d (needed flush? %d), rq? %d [busy?=%d]\n", 80003b705cfSriastradh __FUNCTION__, bo->handle, bo->needs_flush, bo->rq != NULL, 80103b705cfSriastradh __kgem_busy(kgem, bo->handle))); 80203b705cfSriastradh assert(bo->exec == NULL); 80303b705cfSriastradh assert(list_is_empty(&bo->vma)); 80403b705cfSriastradh 80563ef14f0Smrg if (bo->rq) 80663ef14f0Smrg __kgem_retire_requests_upto(kgem, bo); 80763ef14f0Smrg ASSERT_IDLE(kgem, bo->handle); 80863ef14f0Smrg assert_bo_retired(bo); 8099a906b70Schristos} 8109a906b70Schristos 8119a906b70Schristosstatic void kgem_bo_maybe_retire(struct kgem *kgem, struct kgem_bo *bo) 8129a906b70Schristos{ 8139a906b70Schristos DBG(("%s: retiring bo handle=%d (needed flush? %d), rq? %d [busy?=%d]\n", 8149a906b70Schristos __FUNCTION__, bo->handle, bo->needs_flush, bo->rq != NULL, 8159a906b70Schristos __kgem_busy(kgem, bo->handle))); 8169a906b70Schristos assert(bo->exec == NULL); 8179a906b70Schristos assert(list_is_empty(&bo->vma)); 8189a906b70Schristos 81903b705cfSriastradh if (bo->rq) { 82063ef14f0Smrg if (!__kgem_busy(kgem, bo->handle)) 82163ef14f0Smrg __kgem_retire_requests_upto(kgem, bo); 82203b705cfSriastradh } else { 82303b705cfSriastradh assert(!bo->needs_flush); 82403b705cfSriastradh ASSERT_IDLE(kgem, bo->handle); 82503b705cfSriastradh } 82603b705cfSriastradh} 82703b705cfSriastradh 82803b705cfSriastradhbool kgem_bo_write(struct kgem *kgem, struct kgem_bo *bo, 82903b705cfSriastradh const void *data, int length) 83003b705cfSriastradh{ 831813957e3Ssnj void *ptr; 8329a906b70Schristos int err; 8339a906b70Schristos 83403b705cfSriastradh assert(bo->refcnt); 83503b705cfSriastradh assert(bo->proxy == NULL); 83603b705cfSriastradh ASSERT_IDLE(kgem, bo->handle); 83703b705cfSriastradh 83803b705cfSriastradh assert(length <= bytes(bo)); 8399a906b70Schristosretry: 840813957e3Ssnj ptr = NULL; 841813957e3Ssnj if (bo->domain == DOMAIN_CPU || (kgem->has_llc && !bo->scanout)) { 842813957e3Ssnj ptr = bo->map__cpu; 843813957e3Ssnj if (ptr == NULL) 844813957e3Ssnj ptr = __kgem_bo_map__cpu(kgem, bo); 845813957e3Ssnj } else if (kgem->has_wc_mmap) { 846813957e3Ssnj ptr = bo->map__wc; 847813957e3Ssnj if (ptr == NULL) 848813957e3Ssnj ptr = __kgem_bo_map__wc(kgem, bo); 849813957e3Ssnj } 850813957e3Ssnj if (ptr) { 851813957e3Ssnj /* XXX unsynchronized? */ 852813957e3Ssnj memcpy(ptr, data, length); 853813957e3Ssnj return true; 854813957e3Ssnj } 855813957e3Ssnj 8569a906b70Schristos if ((err = gem_write(kgem->fd, bo->handle, 0, length, data))) { 85763ef14f0Smrg DBG(("%s: failed %d, throttling/cleaning caches\n", 85863ef14f0Smrg __FUNCTION__, err)); 8599a906b70Schristos assert(err != EINVAL); 8609a906b70Schristos 8619a906b70Schristos (void)__kgem_throttle_retire(kgem, 0); 8629a906b70Schristos if (kgem_expire_cache(kgem)) 8639a906b70Schristos goto retry; 8649a906b70Schristos 8659a906b70Schristos if (kgem_cleanup_cache(kgem)) 8669a906b70Schristos goto retry; 8679a906b70Schristos 8689a906b70Schristos ERR(("%s: failed to write %d bytes into BO handle=%d: %d\n", 8699a906b70Schristos __FUNCTION__, length, bo->handle, -err)); 87003b705cfSriastradh return false; 8719a906b70Schristos } 87203b705cfSriastradh 87303b705cfSriastradh DBG(("%s: flush=%d, domain=%d\n", __FUNCTION__, bo->flush, bo->domain)); 8749a906b70Schristos if (bo->exec == NULL) 8759a906b70Schristos kgem_bo_maybe_retire(kgem, bo); 8769a906b70Schristos bo->domain = DOMAIN_NONE; 87703b705cfSriastradh bo->gtt_dirty = true; 87803b705cfSriastradh return true; 87903b705cfSriastradh} 88003b705cfSriastradh 88103b705cfSriastradhstatic uint32_t gem_create(int fd, int num_pages) 88203b705cfSriastradh{ 88303b705cfSriastradh struct drm_i915_gem_create create; 88403b705cfSriastradh 88503b705cfSriastradh VG_CLEAR(create); 88603b705cfSriastradh create.handle = 0; 88703b705cfSriastradh create.size = PAGE_SIZE * num_pages; 8889a906b70Schristos (void)do_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); 88903b705cfSriastradh 89003b705cfSriastradh return create.handle; 89103b705cfSriastradh} 89203b705cfSriastradh 89363ef14f0Smrgstatic void 89403b705cfSriastradhkgem_bo_set_purgeable(struct kgem *kgem, struct kgem_bo *bo) 89503b705cfSriastradh{ 89663ef14f0Smrg#if !DBG_NO_MADV 89703b705cfSriastradh struct drm_i915_gem_madvise madv; 89803b705cfSriastradh 89903b705cfSriastradh assert(bo->exec == NULL); 90003b705cfSriastradh 90103b705cfSriastradh VG_CLEAR(madv); 90203b705cfSriastradh madv.handle = bo->handle; 90303b705cfSriastradh madv.madv = I915_MADV_DONTNEED; 9049a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) { 90563ef14f0Smrg bo->purged = true; 90663ef14f0Smrg kgem->need_purge |= !madv.retained && bo->domain != DOMAIN_CPU; 90703b705cfSriastradh } 90803b705cfSriastradh#endif 90903b705cfSriastradh} 91003b705cfSriastradh 91103b705cfSriastradhstatic bool 91203b705cfSriastradhkgem_bo_is_retained(struct kgem *kgem, struct kgem_bo *bo) 91303b705cfSriastradh{ 91403b705cfSriastradh#if DBG_NO_MADV 91503b705cfSriastradh return true; 91603b705cfSriastradh#else 91703b705cfSriastradh struct drm_i915_gem_madvise madv; 91803b705cfSriastradh 91903b705cfSriastradh if (!bo->purged) 92003b705cfSriastradh return true; 92103b705cfSriastradh 92203b705cfSriastradh VG_CLEAR(madv); 92303b705cfSriastradh madv.handle = bo->handle; 92403b705cfSriastradh madv.madv = I915_MADV_DONTNEED; 9259a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) 92603b705cfSriastradh return madv.retained; 92703b705cfSriastradh 92803b705cfSriastradh return false; 92903b705cfSriastradh#endif 93003b705cfSriastradh} 93103b705cfSriastradh 93203b705cfSriastradhstatic bool 93303b705cfSriastradhkgem_bo_clear_purgeable(struct kgem *kgem, struct kgem_bo *bo) 93403b705cfSriastradh{ 93503b705cfSriastradh#if DBG_NO_MADV 93603b705cfSriastradh return true; 93703b705cfSriastradh#else 93803b705cfSriastradh struct drm_i915_gem_madvise madv; 93903b705cfSriastradh 94003b705cfSriastradh assert(bo->purged); 94103b705cfSriastradh 94203b705cfSriastradh VG_CLEAR(madv); 94303b705cfSriastradh madv.handle = bo->handle; 94403b705cfSriastradh madv.madv = I915_MADV_WILLNEED; 9459a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) { 94603b705cfSriastradh bo->purged = !madv.retained; 94763ef14f0Smrg kgem->need_purge |= !madv.retained && bo->domain != DOMAIN_CPU; 94803b705cfSriastradh return madv.retained; 94903b705cfSriastradh } 95003b705cfSriastradh 95103b705cfSriastradh return false; 95203b705cfSriastradh#endif 95303b705cfSriastradh} 95403b705cfSriastradh 95503b705cfSriastradhstatic void gem_close(int fd, uint32_t handle) 95603b705cfSriastradh{ 95703b705cfSriastradh struct drm_gem_close close; 95803b705cfSriastradh 95903b705cfSriastradh VG_CLEAR(close); 96003b705cfSriastradh close.handle = handle; 9619a906b70Schristos (void)do_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close); 96203b705cfSriastradh} 96303b705cfSriastradh 96403b705cfSriastradhconstant inline static unsigned long __fls(unsigned long word) 96503b705cfSriastradh{ 96603b705cfSriastradh#if defined(__GNUC__) && (defined(__i386__) || defined(__x86__) || defined(__x86_64__)) 96703b705cfSriastradh asm("bsr %1,%0" 96803b705cfSriastradh : "=r" (word) 96903b705cfSriastradh : "rm" (word)); 97003b705cfSriastradh return word; 97103b705cfSriastradh#else 97203b705cfSriastradh unsigned int v = 0; 97303b705cfSriastradh 97403b705cfSriastradh while (word >>= 1) 97503b705cfSriastradh v++; 97603b705cfSriastradh 97703b705cfSriastradh return v; 97803b705cfSriastradh#endif 97903b705cfSriastradh} 98003b705cfSriastradh 98103b705cfSriastradhconstant inline static int cache_bucket(int num_pages) 98203b705cfSriastradh{ 98303b705cfSriastradh return __fls(num_pages); 98403b705cfSriastradh} 98503b705cfSriastradh 98603b705cfSriastradhstatic struct kgem_bo *__kgem_bo_init(struct kgem_bo *bo, 98703b705cfSriastradh int handle, int num_pages) 98803b705cfSriastradh{ 9899a906b70Schristos DBG(("%s(handle=%d, num_pages=%d)\n", __FUNCTION__, handle, num_pages)); 9909a906b70Schristos 99103b705cfSriastradh assert(num_pages); 99203b705cfSriastradh memset(bo, 0, sizeof(*bo)); 99303b705cfSriastradh 99403b705cfSriastradh bo->refcnt = 1; 99503b705cfSriastradh bo->handle = handle; 99603b705cfSriastradh bo->target_handle = -1; 99703b705cfSriastradh num_pages(bo) = num_pages; 99803b705cfSriastradh bucket(bo) = cache_bucket(num_pages); 99903b705cfSriastradh bo->reusable = true; 100003b705cfSriastradh bo->domain = DOMAIN_CPU; 100103b705cfSriastradh list_init(&bo->request); 100203b705cfSriastradh list_init(&bo->list); 100303b705cfSriastradh list_init(&bo->vma); 100403b705cfSriastradh 100503b705cfSriastradh return bo; 100603b705cfSriastradh} 100703b705cfSriastradh 100803b705cfSriastradhstatic struct kgem_bo *__kgem_bo_alloc(int handle, int num_pages) 100903b705cfSriastradh{ 101003b705cfSriastradh struct kgem_bo *bo; 101103b705cfSriastradh 101203b705cfSriastradh if (__kgem_freed_bo) { 101303b705cfSriastradh bo = __kgem_freed_bo; 101403b705cfSriastradh __kgem_freed_bo = *(struct kgem_bo **)bo; 101503b705cfSriastradh } else { 101603b705cfSriastradh bo = malloc(sizeof(*bo)); 101703b705cfSriastradh if (bo == NULL) 101803b705cfSriastradh return NULL; 101903b705cfSriastradh } 102003b705cfSriastradh 102103b705cfSriastradh return __kgem_bo_init(bo, handle, num_pages); 102203b705cfSriastradh} 102303b705cfSriastradh 102403b705cfSriastradhstatic struct kgem_request *__kgem_request_alloc(struct kgem *kgem) 102503b705cfSriastradh{ 102603b705cfSriastradh struct kgem_request *rq; 102703b705cfSriastradh 102863ef14f0Smrg if (unlikely(kgem->wedged)) { 102963ef14f0Smrg rq = &kgem->static_request; 103003b705cfSriastradh } else { 103163ef14f0Smrg rq = __kgem_freed_request; 103263ef14f0Smrg if (rq) { 103363ef14f0Smrg __kgem_freed_request = *(struct kgem_request **)rq; 103463ef14f0Smrg } else { 103563ef14f0Smrg rq = malloc(sizeof(*rq)); 103663ef14f0Smrg if (rq == NULL) 103763ef14f0Smrg rq = &kgem->static_request; 103863ef14f0Smrg } 103903b705cfSriastradh } 104003b705cfSriastradh 104103b705cfSriastradh list_init(&rq->buffers); 104203b705cfSriastradh rq->bo = NULL; 104303b705cfSriastradh rq->ring = 0; 104403b705cfSriastradh 104503b705cfSriastradh return rq; 104603b705cfSriastradh} 104703b705cfSriastradh 104803b705cfSriastradhstatic void __kgem_request_free(struct kgem_request *rq) 104903b705cfSriastradh{ 105003b705cfSriastradh _list_del(&rq->list); 10519a906b70Schristos if (DBG_NO_MALLOC_CACHE) { 10529a906b70Schristos free(rq); 10539a906b70Schristos } else { 10549a906b70Schristos *(struct kgem_request **)rq = __kgem_freed_request; 10559a906b70Schristos __kgem_freed_request = rq; 10569a906b70Schristos } 105703b705cfSriastradh} 105803b705cfSriastradh 105903b705cfSriastradhstatic struct list *inactive(struct kgem *kgem, int num_pages) 106003b705cfSriastradh{ 106103b705cfSriastradh assert(num_pages < MAX_CACHE_SIZE / PAGE_SIZE); 106203b705cfSriastradh assert(cache_bucket(num_pages) < NUM_CACHE_BUCKETS); 106303b705cfSriastradh return &kgem->inactive[cache_bucket(num_pages)]; 106403b705cfSriastradh} 106503b705cfSriastradh 106603b705cfSriastradhstatic struct list *active(struct kgem *kgem, int num_pages, int tiling) 106703b705cfSriastradh{ 106803b705cfSriastradh assert(num_pages < MAX_CACHE_SIZE / PAGE_SIZE); 106903b705cfSriastradh assert(cache_bucket(num_pages) < NUM_CACHE_BUCKETS); 107003b705cfSriastradh return &kgem->active[cache_bucket(num_pages)][tiling]; 107103b705cfSriastradh} 107203b705cfSriastradh 107303b705cfSriastradhstatic size_t 107403b705cfSriastradhagp_aperture_size(struct pci_device *dev, unsigned gen) 107503b705cfSriastradh{ 107603b705cfSriastradh /* XXX assume that only future chipsets are unknown and follow 107703b705cfSriastradh * the post gen2 PCI layout. 107803b705cfSriastradh */ 107903b705cfSriastradh return dev->regions[gen < 030 ? 0 : 2].size; 108003b705cfSriastradh} 108103b705cfSriastradh 108203b705cfSriastradhstatic size_t 108303b705cfSriastradhtotal_ram_size(void) 108403b705cfSriastradh{ 108503b705cfSriastradh#ifdef HAVE_STRUCT_SYSINFO_TOTALRAM 108603b705cfSriastradh struct sysinfo info; 108703b705cfSriastradh if (sysinfo(&info) == 0) 108863ef14f0Smrg return (size_t)info.totalram * info.mem_unit; 108903b705cfSriastradh#endif 109003b705cfSriastradh 109103b705cfSriastradh#ifdef _SC_PHYS_PAGES 109263ef14f0Smrg return (size_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE); 109303b705cfSriastradh#endif 109403b705cfSriastradh 109503b705cfSriastradh return 0; 109603b705cfSriastradh} 109703b705cfSriastradh 109803b705cfSriastradhstatic unsigned 109903b705cfSriastradhcpu_cache_size__cpuid4(void) 110003b705cfSriastradh{ 11019a906b70Schristos /* Deterministic Cache Parameters (Function 04h)": 110203b705cfSriastradh * When EAX is initialized to a value of 4, the CPUID instruction 110303b705cfSriastradh * returns deterministic cache information in the EAX, EBX, ECX 110403b705cfSriastradh * and EDX registers. This function requires ECX be initialized 110503b705cfSriastradh * with an index which indicates which cache to return information 110603b705cfSriastradh * about. The OS is expected to call this function (CPUID.4) with 110703b705cfSriastradh * ECX = 0, 1, 2, until EAX[4:0] == 0, indicating no more caches. 110803b705cfSriastradh * The order in which the caches are returned is not specified 110903b705cfSriastradh * and may change at Intel's discretion. 111003b705cfSriastradh * 111103b705cfSriastradh * Calculating the Cache Size in bytes: 111203b705cfSriastradh * = (Ways +1) * (Partitions +1) * (Line Size +1) * (Sets +1) 111303b705cfSriastradh */ 111403b705cfSriastradh 111503b705cfSriastradh unsigned int eax, ebx, ecx, edx; 111603b705cfSriastradh unsigned int llc_size = 0; 11179a906b70Schristos int cnt; 111803b705cfSriastradh 111903b705cfSriastradh if (__get_cpuid_max(BASIC_CPUID, NULL) < 4) 112003b705cfSriastradh return 0; 112103b705cfSriastradh 11229a906b70Schristos cnt = 0; 112303b705cfSriastradh do { 112403b705cfSriastradh unsigned associativity, line_partitions, line_size, sets; 112503b705cfSriastradh 112603b705cfSriastradh __cpuid_count(4, cnt++, eax, ebx, ecx, edx); 112703b705cfSriastradh 112803b705cfSriastradh if ((eax & 0x1f) == 0) 112903b705cfSriastradh break; 113003b705cfSriastradh 113103b705cfSriastradh associativity = ((ebx >> 22) & 0x3ff) + 1; 113203b705cfSriastradh line_partitions = ((ebx >> 12) & 0x3ff) + 1; 113303b705cfSriastradh line_size = (ebx & 0xfff) + 1; 113403b705cfSriastradh sets = ecx + 1; 113503b705cfSriastradh 113603b705cfSriastradh llc_size = associativity * line_partitions * line_size * sets; 113703b705cfSriastradh } while (1); 113803b705cfSriastradh 113903b705cfSriastradh return llc_size; 114003b705cfSriastradh} 114103b705cfSriastradh 114203b705cfSriastradhstatic unsigned 114303b705cfSriastradhcpu_cache_size(void) 114403b705cfSriastradh{ 114503b705cfSriastradh unsigned size; 114603b705cfSriastradh FILE *file; 114703b705cfSriastradh 114803b705cfSriastradh size = cpu_cache_size__cpuid4(); 114903b705cfSriastradh if (size) 115003b705cfSriastradh return size; 115103b705cfSriastradh 115203b705cfSriastradh file = fopen("/proc/cpuinfo", "r"); 115303b705cfSriastradh if (file) { 115403b705cfSriastradh size_t len = 0; 115503b705cfSriastradh char *line = NULL; 115603b705cfSriastradh while (getline(&line, &len, file) != -1) { 115703b705cfSriastradh int kb; 115803b705cfSriastradh if (sscanf(line, "cache size : %d KB", &kb) == 1) { 115903b705cfSriastradh /* Paranoid check against gargantuan caches */ 116003b705cfSriastradh if (kb <= 1<<20) 116103b705cfSriastradh size = kb * 1024; 116203b705cfSriastradh break; 116303b705cfSriastradh } 116403b705cfSriastradh } 116503b705cfSriastradh free(line); 116603b705cfSriastradh fclose(file); 116703b705cfSriastradh } 116803b705cfSriastradh 116903b705cfSriastradh if (size == 0) 117003b705cfSriastradh size = 64 * 1024; 117103b705cfSriastradh 117203b705cfSriastradh return size; 117303b705cfSriastradh} 117403b705cfSriastradh 117503b705cfSriastradhstatic int gem_param(struct kgem *kgem, int name) 117603b705cfSriastradh{ 117703b705cfSriastradh drm_i915_getparam_t gp; 117803b705cfSriastradh int v = -1; /* No param uses the sign bit, reserve it for errors */ 117903b705cfSriastradh 118003b705cfSriastradh VG_CLEAR(gp); 118103b705cfSriastradh gp.param = name; 118203b705cfSriastradh gp.value = &v; 11839a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GETPARAM, &gp)) 118403b705cfSriastradh return -1; 118503b705cfSriastradh 118603b705cfSriastradh VG(VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v))); 118703b705cfSriastradh return v; 118803b705cfSriastradh} 118903b705cfSriastradh 119003b705cfSriastradhstatic bool test_has_execbuffer2(struct kgem *kgem) 119103b705cfSriastradh{ 119203b705cfSriastradh struct drm_i915_gem_execbuffer2 execbuf; 119303b705cfSriastradh 119403b705cfSriastradh memset(&execbuf, 0, sizeof(execbuf)); 119503b705cfSriastradh execbuf.buffer_count = 1; 119603b705cfSriastradh 11979a906b70Schristos return do_ioctl(kgem->fd, 119803b705cfSriastradh DRM_IOCTL_I915_GEM_EXECBUFFER2, 11999a906b70Schristos &execbuf) == -EFAULT; 120003b705cfSriastradh} 120103b705cfSriastradh 120203b705cfSriastradhstatic bool test_has_no_reloc(struct kgem *kgem) 120303b705cfSriastradh{ 120403b705cfSriastradh if (DBG_NO_FAST_RELOC) 120503b705cfSriastradh return false; 120603b705cfSriastradh 120703b705cfSriastradh return gem_param(kgem, LOCAL_I915_PARAM_HAS_NO_RELOC) > 0; 120803b705cfSriastradh} 120903b705cfSriastradh 121003b705cfSriastradhstatic bool test_has_handle_lut(struct kgem *kgem) 121103b705cfSriastradh{ 121203b705cfSriastradh if (DBG_NO_HANDLE_LUT) 121303b705cfSriastradh return false; 121403b705cfSriastradh 121503b705cfSriastradh return gem_param(kgem, LOCAL_I915_PARAM_HAS_HANDLE_LUT) > 0; 121603b705cfSriastradh} 121703b705cfSriastradh 121803b705cfSriastradhstatic bool test_has_wt(struct kgem *kgem) 121903b705cfSriastradh{ 122003b705cfSriastradh if (DBG_NO_WT) 122103b705cfSriastradh return false; 122203b705cfSriastradh 122303b705cfSriastradh return gem_param(kgem, LOCAL_I915_PARAM_HAS_WT) > 0; 122403b705cfSriastradh} 122503b705cfSriastradh 122603b705cfSriastradhstatic bool test_has_semaphores_enabled(struct kgem *kgem) 122703b705cfSriastradh{ 122803b705cfSriastradh FILE *file; 122903b705cfSriastradh bool detected = false; 123003b705cfSriastradh int ret; 123103b705cfSriastradh 123203b705cfSriastradh if (DBG_NO_SEMAPHORES) 123303b705cfSriastradh return false; 123403b705cfSriastradh 123503b705cfSriastradh ret = gem_param(kgem, LOCAL_I915_PARAM_HAS_SEMAPHORES); 123603b705cfSriastradh if (ret != -1) 123703b705cfSriastradh return ret > 0; 123803b705cfSriastradh 123903b705cfSriastradh file = fopen("/sys/module/i915/parameters/semaphores", "r"); 124003b705cfSriastradh if (file) { 124103b705cfSriastradh int value; 124203b705cfSriastradh if (fscanf(file, "%d", &value) == 1) 124303b705cfSriastradh detected = value != 0; 124403b705cfSriastradh fclose(file); 124503b705cfSriastradh } 124603b705cfSriastradh 124703b705cfSriastradh return detected; 124803b705cfSriastradh} 124903b705cfSriastradh 125003b705cfSriastradhstatic bool is_hw_supported(struct kgem *kgem, 125103b705cfSriastradh struct pci_device *dev) 125203b705cfSriastradh{ 125303b705cfSriastradh if (DBG_NO_HW) 125403b705cfSriastradh return false; 125503b705cfSriastradh 125603b705cfSriastradh if (!test_has_execbuffer2(kgem)) 125703b705cfSriastradh return false; 125803b705cfSriastradh 125903b705cfSriastradh if (kgem->gen == (unsigned)-1) /* unknown chipset, assume future gen */ 126003b705cfSriastradh return kgem->has_blt; 126103b705cfSriastradh 126203b705cfSriastradh /* Although pre-855gm the GMCH is fubar, it works mostly. So 126303b705cfSriastradh * let the user decide through "NoAccel" whether or not to risk 126403b705cfSriastradh * hw acceleration. 126503b705cfSriastradh */ 126603b705cfSriastradh 12679a906b70Schristos if (kgem->gen == 060 && dev && dev->revision < 8) { 126803b705cfSriastradh /* pre-production SNB with dysfunctional BLT */ 126903b705cfSriastradh return false; 127003b705cfSriastradh } 127103b705cfSriastradh 127203b705cfSriastradh if (kgem->gen >= 060) /* Only if the kernel supports the BLT ring */ 127303b705cfSriastradh return kgem->has_blt; 127403b705cfSriastradh 127503b705cfSriastradh return true; 127603b705cfSriastradh} 127703b705cfSriastradh 127803b705cfSriastradhstatic bool test_has_relaxed_fencing(struct kgem *kgem) 127903b705cfSriastradh{ 128003b705cfSriastradh if (kgem->gen < 040) { 128103b705cfSriastradh if (DBG_NO_RELAXED_FENCING) 128203b705cfSriastradh return false; 128303b705cfSriastradh 128403b705cfSriastradh return gem_param(kgem, LOCAL_I915_PARAM_HAS_RELAXED_FENCING) > 0; 128503b705cfSriastradh } else 128603b705cfSriastradh return true; 128703b705cfSriastradh} 128803b705cfSriastradh 128963ef14f0Smrgstatic bool test_has_coherent_mmap_gtt(struct kgem *kgem) 129063ef14f0Smrg{ 129163ef14f0Smrg if (DBG_NO_COHERENT_MMAP_GTT) 129263ef14f0Smrg return false; 129363ef14f0Smrg 129463ef14f0Smrg return gem_param(kgem, LOCAL_I915_PARAM_MMAP_GTT_COHERENT) > 0; 129563ef14f0Smrg} 129663ef14f0Smrg 129703b705cfSriastradhstatic bool test_has_llc(struct kgem *kgem) 129803b705cfSriastradh{ 129903b705cfSriastradh int has_llc = -1; 130003b705cfSriastradh 130103b705cfSriastradh if (DBG_NO_LLC) 130203b705cfSriastradh return false; 130303b705cfSriastradh 1304813957e3Ssnj has_llc = gem_param(kgem, LOCAL_I915_PARAM_HAS_LLC); 130503b705cfSriastradh if (has_llc == -1) { 130603b705cfSriastradh DBG(("%s: no kernel/drm support for HAS_LLC, assuming support for LLC based on GPU generation\n", __FUNCTION__)); 130703b705cfSriastradh has_llc = kgem->gen >= 060; 130803b705cfSriastradh } 130903b705cfSriastradh 131003b705cfSriastradh return has_llc; 131103b705cfSriastradh} 131203b705cfSriastradh 1313813957e3Ssnjstatic bool test_has_wc_mmap(struct kgem *kgem) 1314813957e3Ssnj{ 1315813957e3Ssnj struct local_i915_gem_mmap2 wc; 1316813957e3Ssnj bool ret; 1317813957e3Ssnj 1318813957e3Ssnj if (DBG_NO_WC_MMAP) 1319813957e3Ssnj return false; 1320813957e3Ssnj 132163ef14f0Smrg /* XXX See https://bugs.freedesktop.org/show_bug.cgi?id=90841 */ 132263ef14f0Smrg if (kgem->gen < 033) 132363ef14f0Smrg return false; 132463ef14f0Smrg 1325813957e3Ssnj if (gem_param(kgem, LOCAL_I915_PARAM_MMAP_VERSION) < 1) 1326813957e3Ssnj return false; 1327813957e3Ssnj 1328813957e3Ssnj VG_CLEAR(wc); 1329813957e3Ssnj wc.handle = gem_create(kgem->fd, 1); 1330813957e3Ssnj wc.offset = 0; 1331813957e3Ssnj wc.size = 4096; 1332813957e3Ssnj wc.flags = I915_MMAP_WC; 1333813957e3Ssnj ret = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_MMAP_v2, &wc) == 0; 1334813957e3Ssnj gem_close(kgem->fd, wc.handle); 1335813957e3Ssnj 1336813957e3Ssnj return ret; 1337813957e3Ssnj} 1338813957e3Ssnj 133903b705cfSriastradhstatic bool test_has_caching(struct kgem *kgem) 134003b705cfSriastradh{ 134103b705cfSriastradh uint32_t handle; 134203b705cfSriastradh bool ret; 134303b705cfSriastradh 134403b705cfSriastradh if (DBG_NO_CACHE_LEVEL) 134503b705cfSriastradh return false; 134603b705cfSriastradh 134703b705cfSriastradh /* Incoherent blt and sampler hangs the GPU */ 134803b705cfSriastradh if (kgem->gen == 040) 134903b705cfSriastradh return false; 135003b705cfSriastradh 135103b705cfSriastradh handle = gem_create(kgem->fd, 1); 135203b705cfSriastradh if (handle == 0) 135303b705cfSriastradh return false; 135403b705cfSriastradh 135503b705cfSriastradh ret = gem_set_caching(kgem->fd, handle, UNCACHED); 135603b705cfSriastradh gem_close(kgem->fd, handle); 135703b705cfSriastradh return ret; 135803b705cfSriastradh} 135903b705cfSriastradh 136003b705cfSriastradhstatic bool test_has_userptr(struct kgem *kgem) 136103b705cfSriastradh{ 136263ef14f0Smrg struct local_i915_gem_userptr arg; 136303b705cfSriastradh void *ptr; 136403b705cfSriastradh 136503b705cfSriastradh if (DBG_NO_USERPTR) 136603b705cfSriastradh return false; 136703b705cfSriastradh 136803b705cfSriastradh /* Incoherent blt and sampler hangs the GPU */ 136903b705cfSriastradh if (kgem->gen == 040) 137003b705cfSriastradh return false; 137103b705cfSriastradh 137203b705cfSriastradh if (posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE)) 137303b705cfSriastradh return false; 137403b705cfSriastradh 137563ef14f0Smrg VG_CLEAR(arg); 137663ef14f0Smrg arg.user_ptr = (uintptr_t)ptr; 137763ef14f0Smrg arg.user_size = PAGE_SIZE; 137863ef14f0Smrg arg.flags = I915_USERPTR_UNSYNCHRONIZED; 137903b705cfSriastradh 138063ef14f0Smrg if (DBG_NO_UNSYNCHRONIZED_USERPTR || 138163ef14f0Smrg do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg)) { 138263ef14f0Smrg arg.flags &= ~I915_USERPTR_UNSYNCHRONIZED; 138363ef14f0Smrg if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg)) 138463ef14f0Smrg arg.handle = 0; 138563ef14f0Smrg /* Leak the userptr bo to keep the mmu_notifier alive */ 138663ef14f0Smrg } else { 138763ef14f0Smrg gem_close(kgem->fd, arg.handle); 138863ef14f0Smrg free(ptr); 138963ef14f0Smrg } 139063ef14f0Smrg 139163ef14f0Smrg return arg.handle != 0; 139203b705cfSriastradh} 139303b705cfSriastradh 139403b705cfSriastradhstatic bool test_has_create2(struct kgem *kgem) 139503b705cfSriastradh{ 139603b705cfSriastradh#if defined(USE_CREATE2) 139703b705cfSriastradh struct local_i915_gem_create2 args; 139803b705cfSriastradh 139903b705cfSriastradh if (DBG_NO_CREATE2) 140003b705cfSriastradh return false; 140103b705cfSriastradh 140203b705cfSriastradh memset(&args, 0, sizeof(args)); 140303b705cfSriastradh args.size = PAGE_SIZE; 140403b705cfSriastradh args.caching = DISPLAY; 14059a906b70Schristos if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_CREATE2, &args) == 0) 140603b705cfSriastradh gem_close(kgem->fd, args.handle); 140703b705cfSriastradh 140803b705cfSriastradh return args.handle != 0; 140903b705cfSriastradh#else 141003b705cfSriastradh return false; 141103b705cfSriastradh#endif 141203b705cfSriastradh} 141303b705cfSriastradh 141463ef14f0Smrgstatic bool test_can_blt_y(struct kgem *kgem) 141503b705cfSriastradh{ 141663ef14f0Smrg struct drm_i915_gem_exec_object2 object; 141763ef14f0Smrg uint32_t batch[] = { 141863ef14f0Smrg#define MI_LOAD_REGISTER_IMM (0x22<<23 | (3-2)) 141963ef14f0Smrg#define BCS_SWCTRL 0x22200 142063ef14f0Smrg#define BCS_SRC_Y (1 << 0) 142163ef14f0Smrg#define BCS_DST_Y (1 << 1) 142263ef14f0Smrg MI_LOAD_REGISTER_IMM, 142363ef14f0Smrg BCS_SWCTRL, 142463ef14f0Smrg (BCS_SRC_Y | BCS_DST_Y) << 16 | (BCS_SRC_Y | BCS_DST_Y), 142563ef14f0Smrg 142663ef14f0Smrg MI_LOAD_REGISTER_IMM, 142763ef14f0Smrg BCS_SWCTRL, 142863ef14f0Smrg (BCS_SRC_Y | BCS_DST_Y) << 16, 142963ef14f0Smrg 143063ef14f0Smrg MI_BATCH_BUFFER_END, 143163ef14f0Smrg 0, 143263ef14f0Smrg }; 143363ef14f0Smrg int ret; 143463ef14f0Smrg 143563ef14f0Smrg if (DBG_NO_BLT_Y) 143603b705cfSriastradh return false; 143703b705cfSriastradh 143863ef14f0Smrg if (kgem->gen < 060) 143963ef14f0Smrg return false; 144063ef14f0Smrg 144163ef14f0Smrg memset(&object, 0, sizeof(object)); 144263ef14f0Smrg object.handle = gem_create(kgem->fd, 1); 144363ef14f0Smrg 144463ef14f0Smrg ret = gem_write(kgem->fd, object.handle, 0, sizeof(batch), batch); 144563ef14f0Smrg if (ret == 0) { 144663ef14f0Smrg struct drm_i915_gem_execbuffer2 execbuf; 144763ef14f0Smrg 144863ef14f0Smrg memset(&execbuf, 0, sizeof(execbuf)); 144963ef14f0Smrg execbuf.buffers_ptr = (uintptr_t)&object; 145063ef14f0Smrg execbuf.buffer_count = 1; 145163ef14f0Smrg execbuf.flags = KGEM_BLT; 145263ef14f0Smrg 145363ef14f0Smrg ret = do_ioctl(kgem->fd, 145463ef14f0Smrg DRM_IOCTL_I915_GEM_EXECBUFFER2, 145563ef14f0Smrg &execbuf); 145663ef14f0Smrg } 145763ef14f0Smrg gem_close(kgem->fd, object.handle); 145863ef14f0Smrg 145963ef14f0Smrg return ret == 0; 146003b705cfSriastradh} 146103b705cfSriastradh 146263ef14f0Smrgstatic bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride) 146303b705cfSriastradh{ 146463ef14f0Smrg struct drm_i915_gem_set_tiling set_tiling; 146563ef14f0Smrg 146663ef14f0Smrg if (DBG_NO_TILING) 146703b705cfSriastradh return false; 146803b705cfSriastradh 146963ef14f0Smrg VG_CLEAR(set_tiling); 147063ef14f0Smrg set_tiling.handle = handle; 147163ef14f0Smrg set_tiling.tiling_mode = tiling; 147263ef14f0Smrg set_tiling.stride = stride; 147363ef14f0Smrg 147463ef14f0Smrg if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) 147563ef14f0Smrg return set_tiling.tiling_mode == tiling; 147663ef14f0Smrg 147763ef14f0Smrg return false; 147803b705cfSriastradh} 147903b705cfSriastradh 148063ef14f0Smrgstatic bool test_can_scanout_y(struct kgem *kgem) 148103b705cfSriastradh{ 148263ef14f0Smrg struct drm_mode_fb_cmd arg; 148363ef14f0Smrg bool ret = false; 148463ef14f0Smrg 148563ef14f0Smrg if (DBG_NO_SCANOUT_Y) 148663ef14f0Smrg return false; 148763ef14f0Smrg 148863ef14f0Smrg VG_CLEAR(arg); 148963ef14f0Smrg arg.width = 32; 149063ef14f0Smrg arg.height = 32; 149163ef14f0Smrg arg.pitch = 4*32; 149263ef14f0Smrg arg.bpp = 32; 149363ef14f0Smrg arg.depth = 24; 149463ef14f0Smrg arg.handle = gem_create(kgem->fd, 1); 149563ef14f0Smrg 149663ef14f0Smrg if (gem_set_tiling(kgem->fd, arg.handle, I915_TILING_Y, arg.pitch)) 149763ef14f0Smrg ret = do_ioctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg) == 0; 149863ef14f0Smrg if (!ret) { 149963ef14f0Smrg struct local_mode_fb_cmd2 { 150063ef14f0Smrg uint32_t fb_id; 150163ef14f0Smrg uint32_t width, height; 150263ef14f0Smrg uint32_t pixel_format; 150363ef14f0Smrg uint32_t flags; 150463ef14f0Smrg 150563ef14f0Smrg uint32_t handles[4]; 150663ef14f0Smrg uint32_t pitches[4]; 150763ef14f0Smrg uint32_t offsets[4]; 150863ef14f0Smrg uint64_t modifiers[4]; 150963ef14f0Smrg } f; 151063ef14f0Smrg#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2) 151163ef14f0Smrg memset(&f, 0, sizeof(f)); 151263ef14f0Smrg f.width = arg.width; 151363ef14f0Smrg f.height = arg.height; 151463ef14f0Smrg f.handles[0] = arg.handle; 151563ef14f0Smrg f.pitches[0] = arg.pitch; 151663ef14f0Smrg f.modifiers[0] = (uint64_t)1 << 56 | 2; /* MOD_Y_TILED */ 151763ef14f0Smrg f.pixel_format = 'X' | 'R' << 8 | '2' << 16 | '4' << 24; /* XRGB8888 */ 151863ef14f0Smrg f.flags = 1 << 1; /* + modifier */ 151963ef14f0Smrg if (drmIoctl(kgem->fd, LOCAL_IOCTL_MODE_ADDFB2, &f) == 0) { 152063ef14f0Smrg ret = true; 152163ef14f0Smrg arg.fb_id = f.fb_id; 152263ef14f0Smrg } 152363ef14f0Smrg } 152463ef14f0Smrg do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &arg.fb_id); 152563ef14f0Smrg gem_close(kgem->fd, arg.handle); 152663ef14f0Smrg 152763ef14f0Smrg return ret; 152803b705cfSriastradh} 152903b705cfSriastradh 153063ef14f0Smrgstatic bool test_has_dirtyfb(struct kgem *kgem) 15319a906b70Schristos{ 153263ef14f0Smrg struct drm_mode_fb_cmd create; 153363ef14f0Smrg bool ret = false; 15349a906b70Schristos 153563ef14f0Smrg if (DBG_NO_DIRTYFB) 153663ef14f0Smrg return false; 15379a906b70Schristos 153863ef14f0Smrg VG_CLEAR(create); 153963ef14f0Smrg create.width = 32; 154063ef14f0Smrg create.height = 32; 154163ef14f0Smrg create.pitch = 4*32; 154263ef14f0Smrg create.bpp = 24; 154363ef14f0Smrg create.depth = 32; /* {bpp:24, depth:32} -> x8r8g8b8 */ 154463ef14f0Smrg create.handle = gem_create(kgem->fd, 1); 154563ef14f0Smrg if (create.handle == 0) 154663ef14f0Smrg return false; 15479a906b70Schristos 154863ef14f0Smrg if (drmIoctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &create) == 0) { 154963ef14f0Smrg struct drm_mode_fb_dirty_cmd dirty; 155063ef14f0Smrg 155163ef14f0Smrg memset(&dirty, 0, sizeof(dirty)); 155263ef14f0Smrg dirty.fb_id = create.fb_id; 155363ef14f0Smrg ret = drmIoctl(kgem->fd, 155463ef14f0Smrg DRM_IOCTL_MODE_DIRTYFB, 155563ef14f0Smrg &dirty) == 0; 155663ef14f0Smrg 155763ef14f0Smrg /* XXX There may be multiple levels of DIRTYFB, depending on 155863ef14f0Smrg * whether the kernel thinks tracking dirty regions is 155963ef14f0Smrg * beneficial vs flagging the whole fb as dirty. 156063ef14f0Smrg */ 156163ef14f0Smrg 156263ef14f0Smrg drmIoctl(kgem->fd, 156363ef14f0Smrg DRM_IOCTL_MODE_RMFB, 156463ef14f0Smrg &create.fb_id); 15659a906b70Schristos } 156663ef14f0Smrg gem_close(kgem->fd, create.handle); 15679a906b70Schristos 156863ef14f0Smrg return ret; 15699a906b70Schristos} 15709a906b70Schristos 157163ef14f0Smrgstatic bool test_has_secure_batches(struct kgem *kgem) 15729a906b70Schristos{ 157363ef14f0Smrg if (DBG_NO_SECURE_BATCHES) 157463ef14f0Smrg return false; 15759a906b70Schristos 157663ef14f0Smrg return gem_param(kgem, LOCAL_I915_PARAM_HAS_SECURE_BATCHES) > 0; 157763ef14f0Smrg} 15789a906b70Schristos 157963ef14f0Smrgstatic bool test_has_pinned_batches(struct kgem *kgem) 158063ef14f0Smrg{ 158163ef14f0Smrg if (DBG_NO_PINNED_BATCHES) 158263ef14f0Smrg return false; 15839a906b70Schristos 158463ef14f0Smrg return gem_param(kgem, LOCAL_I915_PARAM_HAS_PINNED_BATCHES) > 0; 15859a906b70Schristos} 15869a906b70Schristos 158703b705cfSriastradhstatic bool kgem_init_pinned_batches(struct kgem *kgem) 158803b705cfSriastradh{ 158903b705cfSriastradh int count[2] = { 16, 4 }; 159003b705cfSriastradh int size[2] = { 1, 4 }; 159163ef14f0Smrg int ret = 0; 159203b705cfSriastradh int n, i; 159303b705cfSriastradh 159463ef14f0Smrg if (unlikely(kgem->wedged)) 159503b705cfSriastradh return true; 159603b705cfSriastradh 159703b705cfSriastradh for (n = 0; n < ARRAY_SIZE(count); n++) { 159803b705cfSriastradh for (i = 0; i < count[n]; i++) { 159903b705cfSriastradh struct drm_i915_gem_pin pin; 160003b705cfSriastradh struct kgem_bo *bo; 160103b705cfSriastradh 160203b705cfSriastradh VG_CLEAR(pin); 160303b705cfSriastradh 160403b705cfSriastradh pin.handle = gem_create(kgem->fd, size[n]); 160503b705cfSriastradh if (pin.handle == 0) 160603b705cfSriastradh goto err; 160703b705cfSriastradh 160803b705cfSriastradh DBG(("%s: new handle=%d, num_pages=%d\n", 160903b705cfSriastradh __FUNCTION__, pin.handle, size[n])); 161003b705cfSriastradh 161103b705cfSriastradh bo = __kgem_bo_alloc(pin.handle, size[n]); 161203b705cfSriastradh if (bo == NULL) { 161303b705cfSriastradh gem_close(kgem->fd, pin.handle); 161403b705cfSriastradh goto err; 161503b705cfSriastradh } 161603b705cfSriastradh 161703b705cfSriastradh pin.alignment = 0; 161863ef14f0Smrg ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_PIN, &pin); 161963ef14f0Smrg if (ret) { 162003b705cfSriastradh gem_close(kgem->fd, pin.handle); 16219a906b70Schristos free(bo); 162203b705cfSriastradh goto err; 162303b705cfSriastradh } 162403b705cfSriastradh bo->presumed_offset = pin.offset; 162503b705cfSriastradh debug_alloc__bo(kgem, bo); 162603b705cfSriastradh list_add(&bo->list, &kgem->pinned_batches[n]); 162703b705cfSriastradh } 162803b705cfSriastradh } 162903b705cfSriastradh 163003b705cfSriastradh return true; 163103b705cfSriastradh 163203b705cfSriastradherr: 163303b705cfSriastradh for (n = 0; n < ARRAY_SIZE(kgem->pinned_batches); n++) { 163403b705cfSriastradh while (!list_is_empty(&kgem->pinned_batches[n])) { 163503b705cfSriastradh kgem_bo_destroy(kgem, 163603b705cfSriastradh list_first_entry(&kgem->pinned_batches[n], 163703b705cfSriastradh struct kgem_bo, list)); 163803b705cfSriastradh } 163903b705cfSriastradh } 164003b705cfSriastradh 164163ef14f0Smrg /* If we fail to pin some memory for 830gm/845g, we need to disable 164263ef14f0Smrg * acceleration as otherwise the machine will eventually fail. However, 164363ef14f0Smrg * the kernel started arbitrarily rejecting PIN, so hope for the best 164463ef14f0Smrg * if the ioctl no longer works. 164563ef14f0Smrg */ 164663ef14f0Smrg if (ret != -ENODEV && kgem->gen == 020) 164763ef14f0Smrg return false; 164863ef14f0Smrg 164963ef14f0Smrg kgem->has_pinned_batches = false; 165063ef14f0Smrg 165103b705cfSriastradh /* For simplicity populate the lists with a single unpinned bo */ 165203b705cfSriastradh for (n = 0; n < ARRAY_SIZE(count); n++) { 165303b705cfSriastradh struct kgem_bo *bo; 165403b705cfSriastradh uint32_t handle; 165503b705cfSriastradh 165603b705cfSriastradh handle = gem_create(kgem->fd, size[n]); 165703b705cfSriastradh if (handle == 0) 165863ef14f0Smrg return false; 165903b705cfSriastradh 166003b705cfSriastradh bo = __kgem_bo_alloc(handle, size[n]); 166103b705cfSriastradh if (bo == NULL) { 166203b705cfSriastradh gem_close(kgem->fd, handle); 166363ef14f0Smrg return false; 166403b705cfSriastradh } 166503b705cfSriastradh 166603b705cfSriastradh debug_alloc__bo(kgem, bo); 166703b705cfSriastradh list_add(&bo->list, &kgem->pinned_batches[n]); 166803b705cfSriastradh } 166963ef14f0Smrg return true; 167003b705cfSriastradh} 167103b705cfSriastradh 167203b705cfSriastradhstatic void kgem_init_swizzling(struct kgem *kgem) 167303b705cfSriastradh{ 1674813957e3Ssnj struct local_i915_gem_get_tiling_v2 { 1675813957e3Ssnj uint32_t handle; 1676813957e3Ssnj uint32_t tiling_mode; 1677813957e3Ssnj uint32_t swizzle_mode; 1678813957e3Ssnj uint32_t phys_swizzle_mode; 1679813957e3Ssnj } tiling; 1680813957e3Ssnj#define LOCAL_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct local_i915_gem_get_tiling_v2) 168103b705cfSriastradh 168263ef14f0Smrg memset(&tiling, 0, sizeof(tiling)); 168303b705cfSriastradh tiling.handle = gem_create(kgem->fd, 1); 168403b705cfSriastradh if (!tiling.handle) 168503b705cfSriastradh return; 168603b705cfSriastradh 168703b705cfSriastradh if (!gem_set_tiling(kgem->fd, tiling.handle, I915_TILING_X, 512)) 168803b705cfSriastradh goto out; 168903b705cfSriastradh 1690813957e3Ssnj if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_GET_TILING, &tiling)) 1691813957e3Ssnj goto out; 1692813957e3Ssnj 169363ef14f0Smrg DBG(("%s: swizzle_mode=%d, phys_swizzle_mode=%d\n", 169463ef14f0Smrg __FUNCTION__, tiling.swizzle_mode, tiling.phys_swizzle_mode)); 169563ef14f0Smrg 169663ef14f0Smrg kgem->can_fence = 169763ef14f0Smrg !DBG_NO_TILING && 169863ef14f0Smrg tiling.swizzle_mode != I915_BIT_6_SWIZZLE_UNKNOWN; 169963ef14f0Smrg 170063ef14f0Smrg if (kgem->gen < 050 && tiling.phys_swizzle_mode != tiling.swizzle_mode) 170103b705cfSriastradh goto out; 170203b705cfSriastradh 170363ef14f0Smrg if (!DBG_NO_DETILING) 170463ef14f0Smrg choose_memcpy_tiled_x(kgem, 170563ef14f0Smrg tiling.swizzle_mode, 170663ef14f0Smrg __to_sna(kgem)->cpu_features); 170703b705cfSriastradhout: 170803b705cfSriastradh gem_close(kgem->fd, tiling.handle); 170963ef14f0Smrg DBG(("%s: can fence?=%d\n", __FUNCTION__, kgem->can_fence)); 171003b705cfSriastradh} 171103b705cfSriastradh 1712813957e3Ssnjstatic void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink) 1713813957e3Ssnj{ 1714813957e3Ssnj int n; 1715813957e3Ssnj 1716813957e3Ssnj bo->target_handle = kgem->has_handle_lut ? kgem->nexec : bo->handle; 1717813957e3Ssnj 1718813957e3Ssnj assert(kgem->nreloc__self <= 256); 1719813957e3Ssnj if (kgem->nreloc__self == 0) 1720813957e3Ssnj return; 1721813957e3Ssnj 1722813957e3Ssnj DBG(("%s: fixing up %d%s self-relocations to handle=%p, presumed-offset=%llx\n", 1723813957e3Ssnj __FUNCTION__, kgem->nreloc__self, 1724813957e3Ssnj kgem->nreloc__self == 256 ? "+" : "", 1725813957e3Ssnj bo->handle, (long long)bo->presumed_offset)); 1726813957e3Ssnj for (n = 0; n < kgem->nreloc__self; n++) { 1727813957e3Ssnj int i = kgem->reloc__self[n]; 172863ef14f0Smrg uint64_t addr; 1729813957e3Ssnj 1730813957e3Ssnj assert(kgem->reloc[i].target_handle == ~0U); 1731813957e3Ssnj kgem->reloc[i].target_handle = bo->target_handle; 1732813957e3Ssnj kgem->reloc[i].presumed_offset = bo->presumed_offset; 1733813957e3Ssnj 1734813957e3Ssnj if (kgem->reloc[i].read_domains == I915_GEM_DOMAIN_INSTRUCTION) { 1735813957e3Ssnj DBG(("%s: moving base of self-reloc[%d:%d] %d -> %d\n", 1736813957e3Ssnj __FUNCTION__, n, i, 1737813957e3Ssnj kgem->reloc[i].delta, 1738813957e3Ssnj kgem->reloc[i].delta - shrink)); 1739813957e3Ssnj 1740813957e3Ssnj kgem->reloc[i].delta -= shrink; 1741813957e3Ssnj } 174263ef14f0Smrg addr = (int)kgem->reloc[i].delta + bo->presumed_offset; 174363ef14f0Smrg kgem->batch[kgem->reloc[i].offset/sizeof(uint32_t)] = addr; 174463ef14f0Smrg if (kgem->gen >= 0100) 174563ef14f0Smrg kgem->batch[kgem->reloc[i].offset/sizeof(uint32_t) + 1] = addr >> 32; 1746813957e3Ssnj } 1747813957e3Ssnj 1748813957e3Ssnj if (n == 256) { 1749813957e3Ssnj for (n = kgem->reloc__self[255]; n < kgem->nreloc; n++) { 1750813957e3Ssnj if (kgem->reloc[n].target_handle == ~0U) { 175163ef14f0Smrg uint64_t addr; 175263ef14f0Smrg 1753813957e3Ssnj kgem->reloc[n].target_handle = bo->target_handle; 1754813957e3Ssnj kgem->reloc[n].presumed_offset = bo->presumed_offset; 1755813957e3Ssnj 1756813957e3Ssnj if (kgem->reloc[n].read_domains == I915_GEM_DOMAIN_INSTRUCTION) { 1757813957e3Ssnj DBG(("%s: moving base of reloc[%d] %d -> %d\n", 1758813957e3Ssnj __FUNCTION__, n, 1759813957e3Ssnj kgem->reloc[n].delta, 1760813957e3Ssnj kgem->reloc[n].delta - shrink)); 1761813957e3Ssnj kgem->reloc[n].delta -= shrink; 1762813957e3Ssnj } 176363ef14f0Smrg 176463ef14f0Smrg addr = (int)kgem->reloc[n].delta + bo->presumed_offset; 176563ef14f0Smrg kgem->batch[kgem->reloc[n].offset/sizeof(uint32_t)] = addr; 176663ef14f0Smrg if (kgem->gen >= 0100) 176763ef14f0Smrg kgem->batch[kgem->reloc[n].offset/sizeof(uint32_t) + 1] = addr >> 32; 1768813957e3Ssnj } 1769813957e3Ssnj } 1770813957e3Ssnj } 1771813957e3Ssnj 1772813957e3Ssnj if (shrink) { 1773813957e3Ssnj DBG(("%s: shrinking by %d\n", __FUNCTION__, shrink)); 1774813957e3Ssnj for (n = 0; n < kgem->nreloc; n++) { 1775813957e3Ssnj if (kgem->reloc[n].offset >= sizeof(uint32_t)*kgem->nbatch) 1776813957e3Ssnj kgem->reloc[n].offset -= shrink; 1777813957e3Ssnj } 1778813957e3Ssnj } 1779813957e3Ssnj} 1780813957e3Ssnj 178163ef14f0Smrgstatic int kgem_bo_wait(struct kgem *kgem, struct kgem_bo *bo) 178263ef14f0Smrg{ 178363ef14f0Smrg struct local_i915_gem_wait { 178463ef14f0Smrg uint32_t handle; 178563ef14f0Smrg uint32_t flags; 178663ef14f0Smrg int64_t timeout; 178763ef14f0Smrg } wait; 178863ef14f0Smrg#define LOCAL_I915_GEM_WAIT 0x2c 178963ef14f0Smrg#define LOCAL_IOCTL_I915_GEM_WAIT DRM_IOWR(DRM_COMMAND_BASE + LOCAL_I915_GEM_WAIT, struct local_i915_gem_wait) 179063ef14f0Smrg int ret; 179163ef14f0Smrg 179263ef14f0Smrg DBG(("%s: waiting for handle=%d\n", __FUNCTION__, bo->handle)); 179363ef14f0Smrg if (bo->rq == NULL) 179463ef14f0Smrg return 0; 179563ef14f0Smrg 179663ef14f0Smrg VG_CLEAR(wait); 179763ef14f0Smrg wait.handle = bo->handle; 179863ef14f0Smrg wait.flags = 0; 179963ef14f0Smrg wait.timeout = -1; 180063ef14f0Smrg ret = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_WAIT, &wait); 180163ef14f0Smrg if (ret) { 180263ef14f0Smrg struct drm_i915_gem_set_domain set_domain; 180363ef14f0Smrg 180463ef14f0Smrg VG_CLEAR(set_domain); 180563ef14f0Smrg set_domain.handle = bo->handle; 180663ef14f0Smrg set_domain.read_domains = I915_GEM_DOMAIN_GTT; 180763ef14f0Smrg set_domain.write_domain = I915_GEM_DOMAIN_GTT; 180863ef14f0Smrg ret = do_ioctl(kgem->fd, 180963ef14f0Smrg DRM_IOCTL_I915_GEM_SET_DOMAIN, 181063ef14f0Smrg &set_domain); 181163ef14f0Smrg } 181263ef14f0Smrg 181363ef14f0Smrg if (ret == 0) 181463ef14f0Smrg __kgem_retire_requests_upto(kgem, bo); 181563ef14f0Smrg 181663ef14f0Smrg return ret; 181763ef14f0Smrg} 181863ef14f0Smrg 1819813957e3Ssnjstatic struct kgem_bo *kgem_new_batch(struct kgem *kgem) 1820813957e3Ssnj{ 1821813957e3Ssnj struct kgem_bo *last; 1822813957e3Ssnj unsigned flags; 1823813957e3Ssnj 1824813957e3Ssnj last = kgem->batch_bo; 1825813957e3Ssnj if (last) { 1826813957e3Ssnj kgem_fixup_relocs(kgem, last, 0); 1827813957e3Ssnj kgem->batch = NULL; 1828813957e3Ssnj } 1829813957e3Ssnj 1830813957e3Ssnj if (kgem->batch) { 1831813957e3Ssnj assert(last == NULL); 1832813957e3Ssnj return NULL; 1833813957e3Ssnj } 1834813957e3Ssnj 1835813957e3Ssnj flags = CREATE_CPU_MAP | CREATE_NO_THROTTLE; 1836813957e3Ssnj if (!kgem->has_llc) 1837813957e3Ssnj flags |= CREATE_UNCACHED; 1838813957e3Ssnj 183963ef14f0Smrgrestart: 1840813957e3Ssnj kgem->batch_bo = kgem_create_linear(kgem, 1841813957e3Ssnj sizeof(uint32_t)*kgem->batch_size, 1842813957e3Ssnj flags); 1843813957e3Ssnj if (kgem->batch_bo) 1844813957e3Ssnj kgem->batch = kgem_bo_map__cpu(kgem, kgem->batch_bo); 1845813957e3Ssnj if (kgem->batch == NULL) { 184663ef14f0Smrg int ring = kgem->ring == KGEM_BLT; 184763ef14f0Smrg assert(ring < ARRAY_SIZE(kgem->requests)); 184863ef14f0Smrg 1849813957e3Ssnj if (kgem->batch_bo) { 1850813957e3Ssnj kgem_bo_destroy(kgem, kgem->batch_bo); 1851813957e3Ssnj kgem->batch_bo = NULL; 1852813957e3Ssnj } 1853813957e3Ssnj 185463ef14f0Smrg if (!list_is_empty(&kgem->requests[ring])) { 185563ef14f0Smrg struct kgem_request *rq; 185663ef14f0Smrg 185763ef14f0Smrg rq = list_first_entry(&kgem->requests[ring], 185863ef14f0Smrg struct kgem_request, list); 185963ef14f0Smrg assert(rq->ring == ring); 186063ef14f0Smrg assert(rq->bo); 186163ef14f0Smrg assert(RQ(rq->bo->rq) == rq); 186263ef14f0Smrg if (kgem_bo_wait(kgem, rq->bo) == 0) 186363ef14f0Smrg goto restart; 186463ef14f0Smrg } 186563ef14f0Smrg 186663ef14f0Smrg if (flags & CREATE_NO_THROTTLE) { 186763ef14f0Smrg flags &= ~CREATE_NO_THROTTLE; 186863ef14f0Smrg if (kgem_cleanup_cache(kgem)) 186963ef14f0Smrg goto restart; 187063ef14f0Smrg } 187163ef14f0Smrg 187263ef14f0Smrg DBG(("%s: unable to map batch bo, mallocing(size=%d)\n", 187363ef14f0Smrg __FUNCTION__, sizeof(uint32_t)*kgem->batch_size)); 1874813957e3Ssnj if (posix_memalign((void **)&kgem->batch, PAGE_SIZE, 1875813957e3Ssnj ALIGN(sizeof(uint32_t) * kgem->batch_size, PAGE_SIZE))) { 1876813957e3Ssnj ERR(("%s: batch allocation failed, disabling acceleration\n", __FUNCTION__)); 1877813957e3Ssnj __kgem_set_wedged(kgem); 1878813957e3Ssnj } 1879813957e3Ssnj } else { 1880813957e3Ssnj DBG(("%s: allocated and mapped batch handle=%d [size=%d]\n", 1881813957e3Ssnj __FUNCTION__, kgem->batch_bo->handle, 1882813957e3Ssnj sizeof(uint32_t)*kgem->batch_size)); 1883813957e3Ssnj kgem_bo_sync__cpu(kgem, kgem->batch_bo); 1884813957e3Ssnj } 1885813957e3Ssnj 1886813957e3Ssnj DBG(("%s: using last batch handle=%d\n", 1887813957e3Ssnj __FUNCTION__, last ? last->handle : 0)); 1888813957e3Ssnj return last; 1889813957e3Ssnj} 189003b705cfSriastradh 189163ef14f0Smrgstatic void 189263ef14f0Smrgno_retire(struct kgem *kgem) 189363ef14f0Smrg{ 189463ef14f0Smrg (void)kgem; 189563ef14f0Smrg} 189663ef14f0Smrg 189763ef14f0Smrgstatic void 189863ef14f0Smrgno_expire(struct kgem *kgem) 189963ef14f0Smrg{ 190063ef14f0Smrg (void)kgem; 190163ef14f0Smrg} 190263ef14f0Smrg 190363ef14f0Smrgstatic void 190463ef14f0Smrgno_context_switch(struct kgem *kgem, int new_mode) 190563ef14f0Smrg{ 190663ef14f0Smrg (void)kgem; 190763ef14f0Smrg (void)new_mode; 190863ef14f0Smrg} 190963ef14f0Smrg 191063ef14f0Smrgstatic uint64_t get_gtt_size(int fd) 191103b705cfSriastradh{ 191203b705cfSriastradh struct drm_i915_gem_get_aperture aperture; 191363ef14f0Smrg struct local_i915_gem_context_param { 191463ef14f0Smrg uint32_t context; 191563ef14f0Smrg uint32_t size; 191663ef14f0Smrg uint64_t param; 191763ef14f0Smrg#define LOCAL_CONTEXT_PARAM_BAN_PERIOD 0x1 191863ef14f0Smrg#define LOCAL_CONTEXT_PARAM_NO_ZEROMAP 0x2 191963ef14f0Smrg#define LOCAL_CONTEXT_PARAM_GTT_SIZE 0x3 192063ef14f0Smrg uint64_t value; 192163ef14f0Smrg } p; 192263ef14f0Smrg#define LOCAL_I915_GEM_CONTEXT_GETPARAM 0x34 192363ef14f0Smrg#define LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_CONTEXT_GETPARAM, struct local_i915_gem_context_param) 192463ef14f0Smrg 192563ef14f0Smrg memset(&aperture, 0, sizeof(aperture)); 192663ef14f0Smrg 192763ef14f0Smrg memset(&p, 0, sizeof(p)); 192863ef14f0Smrg p.param = LOCAL_CONTEXT_PARAM_GTT_SIZE; 192963ef14f0Smrg if (drmIoctl(fd, LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM, &p) == 0) 193063ef14f0Smrg aperture.aper_size = p.value; 193163ef14f0Smrg if (aperture.aper_size == 0) 193263ef14f0Smrg (void)drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture); 193363ef14f0Smrg if (aperture.aper_size == 0) 193463ef14f0Smrg aperture.aper_size = 64*1024*1024; 193563ef14f0Smrg 193663ef14f0Smrg DBG(("%s: aperture size %lld, available now %lld\n", 193763ef14f0Smrg __FUNCTION__, 193863ef14f0Smrg (long long)aperture.aper_size, 193963ef14f0Smrg (long long)aperture.aper_available_size)); 194063ef14f0Smrg 194163ef14f0Smrg /* clamp aperture to uint32_t for simplicity */ 194263ef14f0Smrg if (aperture.aper_size > 0xc0000000) 194363ef14f0Smrg aperture.aper_size = 0xc0000000; 194463ef14f0Smrg 194563ef14f0Smrg return aperture.aper_size; 194663ef14f0Smrg} 194763ef14f0Smrg 194863ef14f0Smrgvoid kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen) 194963ef14f0Smrg{ 195003b705cfSriastradh size_t totalram; 195103b705cfSriastradh unsigned half_gpu_max; 195203b705cfSriastradh unsigned int i, j; 195363ef14f0Smrg uint64_t gtt_size; 195403b705cfSriastradh 195503b705cfSriastradh DBG(("%s: fd=%d, gen=%d\n", __FUNCTION__, fd, gen)); 195603b705cfSriastradh 195703b705cfSriastradh kgem->fd = fd; 195803b705cfSriastradh kgem->gen = gen; 195903b705cfSriastradh 196063ef14f0Smrg kgem->retire = no_retire; 196163ef14f0Smrg kgem->expire = no_expire; 196263ef14f0Smrg kgem->context_switch = no_context_switch; 196363ef14f0Smrg 196403b705cfSriastradh list_init(&kgem->requests[0]); 196503b705cfSriastradh list_init(&kgem->requests[1]); 196603b705cfSriastradh list_init(&kgem->batch_buffers); 196703b705cfSriastradh list_init(&kgem->active_buffers); 196803b705cfSriastradh list_init(&kgem->flushing); 196903b705cfSriastradh list_init(&kgem->large); 197003b705cfSriastradh list_init(&kgem->large_inactive); 197103b705cfSriastradh list_init(&kgem->snoop); 197203b705cfSriastradh list_init(&kgem->scanout); 197303b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->pinned_batches); i++) 197403b705cfSriastradh list_init(&kgem->pinned_batches[i]); 197503b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) 197603b705cfSriastradh list_init(&kgem->inactive[i]); 197703b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->active); i++) { 197803b705cfSriastradh for (j = 0; j < ARRAY_SIZE(kgem->active[i]); j++) 197903b705cfSriastradh list_init(&kgem->active[i][j]); 198003b705cfSriastradh } 198103b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->vma); i++) { 198203b705cfSriastradh for (j = 0; j < ARRAY_SIZE(kgem->vma[i].inactive); j++) 198303b705cfSriastradh list_init(&kgem->vma[i].inactive[j]); 198403b705cfSriastradh } 198503b705cfSriastradh kgem->vma[MAP_GTT].count = -MAX_GTT_VMA_CACHE; 198603b705cfSriastradh kgem->vma[MAP_CPU].count = -MAX_CPU_VMA_CACHE; 198703b705cfSriastradh 198803b705cfSriastradh kgem->has_blt = gem_param(kgem, LOCAL_I915_PARAM_HAS_BLT) > 0; 198903b705cfSriastradh DBG(("%s: has BLT ring? %d\n", __FUNCTION__, 199003b705cfSriastradh kgem->has_blt)); 199103b705cfSriastradh 199203b705cfSriastradh kgem->has_relaxed_delta = 199303b705cfSriastradh gem_param(kgem, LOCAL_I915_PARAM_HAS_RELAXED_DELTA) > 0; 199403b705cfSriastradh DBG(("%s: has relaxed delta? %d\n", __FUNCTION__, 199503b705cfSriastradh kgem->has_relaxed_delta)); 199603b705cfSriastradh 199703b705cfSriastradh kgem->has_relaxed_fencing = test_has_relaxed_fencing(kgem); 199803b705cfSriastradh DBG(("%s: has relaxed fencing? %d\n", __FUNCTION__, 199903b705cfSriastradh kgem->has_relaxed_fencing)); 200003b705cfSriastradh 200163ef14f0Smrg kgem->has_coherent_mmap_gtt = test_has_coherent_mmap_gtt(kgem); 200263ef14f0Smrg DBG(("%s: has coherent writes into GTT maps? %d\n", __FUNCTION__, 200363ef14f0Smrg kgem->has_coherent_mmap_gtt)); 200463ef14f0Smrg 200503b705cfSriastradh kgem->has_llc = test_has_llc(kgem); 200603b705cfSriastradh DBG(("%s: has shared last-level-cache? %d\n", __FUNCTION__, 200703b705cfSriastradh kgem->has_llc)); 200803b705cfSriastradh 200903b705cfSriastradh kgem->has_wt = test_has_wt(kgem); 201003b705cfSriastradh DBG(("%s: has write-through caching for scanouts? %d\n", __FUNCTION__, 201103b705cfSriastradh kgem->has_wt)); 201203b705cfSriastradh 2013813957e3Ssnj kgem->has_wc_mmap = test_has_wc_mmap(kgem); 2014813957e3Ssnj DBG(("%s: has wc-mmapping? %d\n", __FUNCTION__, 2015813957e3Ssnj kgem->has_wc_mmap)); 2016813957e3Ssnj 201703b705cfSriastradh kgem->has_caching = test_has_caching(kgem); 201803b705cfSriastradh DBG(("%s: has set-cache-level? %d\n", __FUNCTION__, 201903b705cfSriastradh kgem->has_caching)); 202003b705cfSriastradh 202103b705cfSriastradh kgem->has_userptr = test_has_userptr(kgem); 202203b705cfSriastradh DBG(("%s: has userptr? %d\n", __FUNCTION__, 202303b705cfSriastradh kgem->has_userptr)); 202403b705cfSriastradh 202503b705cfSriastradh kgem->has_create2 = test_has_create2(kgem); 202603b705cfSriastradh DBG(("%s: has create2? %d\n", __FUNCTION__, 202703b705cfSriastradh kgem->has_create2)); 202803b705cfSriastradh 202903b705cfSriastradh kgem->has_no_reloc = test_has_no_reloc(kgem); 203003b705cfSriastradh DBG(("%s: has no-reloc? %d\n", __FUNCTION__, 203103b705cfSriastradh kgem->has_no_reloc)); 203203b705cfSriastradh 203303b705cfSriastradh kgem->has_handle_lut = test_has_handle_lut(kgem); 203403b705cfSriastradh DBG(("%s: has handle-lut? %d\n", __FUNCTION__, 203503b705cfSriastradh kgem->has_handle_lut)); 203603b705cfSriastradh 203703b705cfSriastradh kgem->has_semaphores = false; 203803b705cfSriastradh if (kgem->has_blt && test_has_semaphores_enabled(kgem)) 203903b705cfSriastradh kgem->has_semaphores = true; 204003b705cfSriastradh DBG(("%s: semaphores enabled? %d\n", __FUNCTION__, 204103b705cfSriastradh kgem->has_semaphores)); 204203b705cfSriastradh 204303b705cfSriastradh kgem->can_blt_cpu = gen >= 030; 204403b705cfSriastradh DBG(("%s: can blt to cpu? %d\n", __FUNCTION__, 204503b705cfSriastradh kgem->can_blt_cpu)); 204603b705cfSriastradh 204763ef14f0Smrg kgem->can_blt_y = test_can_blt_y(kgem); 204863ef14f0Smrg DBG(("%s: can blit to Y-tiled surfaces? %d\n", __FUNCTION__, 204963ef14f0Smrg kgem->can_blt_y)); 205063ef14f0Smrg 20519a906b70Schristos kgem->can_render_y = gen != 021 && (gen >> 3) != 4; 20529a906b70Schristos DBG(("%s: can render to Y-tiled surfaces? %d\n", __FUNCTION__, 20539a906b70Schristos kgem->can_render_y)); 20549a906b70Schristos 205563ef14f0Smrg kgem->can_scanout_y = test_can_scanout_y(kgem); 205663ef14f0Smrg DBG(("%s: can scanout Y-tiled surfaces? %d\n", __FUNCTION__, 205763ef14f0Smrg kgem->can_scanout_y)); 205863ef14f0Smrg 205963ef14f0Smrg kgem->has_dirtyfb = test_has_dirtyfb(kgem); 206063ef14f0Smrg DBG(("%s: has dirty fb? %d\n", __FUNCTION__, kgem->has_dirtyfb)); 206163ef14f0Smrg 206203b705cfSriastradh kgem->has_secure_batches = test_has_secure_batches(kgem); 206303b705cfSriastradh DBG(("%s: can use privileged batchbuffers? %d\n", __FUNCTION__, 206403b705cfSriastradh kgem->has_secure_batches)); 206503b705cfSriastradh 206603b705cfSriastradh kgem->has_pinned_batches = test_has_pinned_batches(kgem); 206703b705cfSriastradh DBG(("%s: can use pinned batchbuffers (to avoid CS w/a)? %d\n", __FUNCTION__, 206803b705cfSriastradh kgem->has_pinned_batches)); 206903b705cfSriastradh 207003b705cfSriastradh if (!is_hw_supported(kgem, dev)) { 207103b705cfSriastradh xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING, 207203b705cfSriastradh "Detected unsupported/dysfunctional hardware, disabling acceleration.\n"); 2073813957e3Ssnj __kgem_set_wedged(kgem); 20749a906b70Schristos } else if (__kgem_throttle(kgem, false)) { 207503b705cfSriastradh xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING, 207603b705cfSriastradh "Detected a hung GPU, disabling acceleration.\n"); 2077813957e3Ssnj __kgem_set_wedged(kgem); 207803b705cfSriastradh } 207903b705cfSriastradh 2080813957e3Ssnj kgem->batch_size = UINT16_MAX & ~7; 208103b705cfSriastradh if (gen == 020 && !kgem->has_pinned_batches) 208203b705cfSriastradh /* Limited to what we can pin */ 208303b705cfSriastradh kgem->batch_size = 4*1024; 208403b705cfSriastradh if (gen == 022) 208503b705cfSriastradh /* 865g cannot handle a batch spanning multiple pages */ 208603b705cfSriastradh kgem->batch_size = PAGE_SIZE / sizeof(uint32_t); 20879a906b70Schristos if (gen >= 070) 208803b705cfSriastradh kgem->batch_size = 16*1024; 208903b705cfSriastradh if (!kgem->has_relaxed_delta && kgem->batch_size > 4*1024) 209003b705cfSriastradh kgem->batch_size = 4*1024; 209103b705cfSriastradh 209263ef14f0Smrg if (!kgem_init_pinned_batches(kgem)) { 209303b705cfSriastradh xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING, 209403b705cfSriastradh "Unable to reserve memory for GPU, disabling acceleration.\n"); 2095813957e3Ssnj __kgem_set_wedged(kgem); 209603b705cfSriastradh } 209703b705cfSriastradh 209803b705cfSriastradh DBG(("%s: maximum batch size? %d\n", __FUNCTION__, 209903b705cfSriastradh kgem->batch_size)); 2100813957e3Ssnj kgem_new_batch(kgem); 210103b705cfSriastradh 210203b705cfSriastradh kgem->half_cpu_cache_pages = cpu_cache_size() >> 13; 210303b705cfSriastradh DBG(("%s: last-level cache size: %d bytes, threshold in pages: %d\n", 210403b705cfSriastradh __FUNCTION__, cpu_cache_size(), kgem->half_cpu_cache_pages)); 210503b705cfSriastradh 210603b705cfSriastradh kgem->next_request = __kgem_request_alloc(kgem); 210703b705cfSriastradh 210803b705cfSriastradh DBG(("%s: cpu bo enabled %d: llc? %d, set-cache-level? %d, userptr? %d\n", __FUNCTION__, 210903b705cfSriastradh !DBG_NO_CPU && (kgem->has_llc | kgem->has_userptr | kgem->has_caching), 211003b705cfSriastradh kgem->has_llc, kgem->has_caching, kgem->has_userptr)); 211103b705cfSriastradh 211263ef14f0Smrg gtt_size = get_gtt_size(fd); 211363ef14f0Smrg kgem->aperture_total = gtt_size; 211463ef14f0Smrg kgem->aperture_high = gtt_size * 3/4; 211563ef14f0Smrg kgem->aperture_low = gtt_size * 1/3; 211603b705cfSriastradh if (gen < 033) { 211703b705cfSriastradh /* Severe alignment penalties */ 211803b705cfSriastradh kgem->aperture_high /= 2; 211903b705cfSriastradh kgem->aperture_low /= 2; 212003b705cfSriastradh } 212163ef14f0Smrg DBG(("%s: aperture low=%u [%u], high=%u [%u]\n", __FUNCTION__, 212203b705cfSriastradh kgem->aperture_low, kgem->aperture_low / (1024*1024), 212303b705cfSriastradh kgem->aperture_high, kgem->aperture_high / (1024*1024))); 212403b705cfSriastradh 21259a906b70Schristos kgem->aperture_mappable = 256 * 1024 * 1024; 21269a906b70Schristos if (dev != NULL) 21279a906b70Schristos kgem->aperture_mappable = agp_aperture_size(dev, gen); 212863ef14f0Smrg if (kgem->aperture_mappable == 0 || kgem->aperture_mappable > gtt_size) 212963ef14f0Smrg kgem->aperture_mappable = gtt_size; 213003b705cfSriastradh DBG(("%s: aperture mappable=%d [%d MiB]\n", __FUNCTION__, 213103b705cfSriastradh kgem->aperture_mappable, kgem->aperture_mappable / (1024*1024))); 213203b705cfSriastradh 21339a906b70Schristos kgem->aperture_fenceable = MIN(256*1024*1024, kgem->aperture_mappable); 21349a906b70Schristos DBG(("%s: aperture fenceable=%d [%d MiB]\n", __FUNCTION__, 21359a906b70Schristos kgem->aperture_fenceable, kgem->aperture_fenceable / (1024*1024))); 21369a906b70Schristos 213703b705cfSriastradh kgem->buffer_size = 64 * 1024; 213803b705cfSriastradh while (kgem->buffer_size < kgem->aperture_mappable >> 10) 213903b705cfSriastradh kgem->buffer_size *= 2; 214003b705cfSriastradh if (kgem->buffer_size >> 12 > kgem->half_cpu_cache_pages) 214103b705cfSriastradh kgem->buffer_size = kgem->half_cpu_cache_pages << 12; 214203b705cfSriastradh kgem->buffer_size = 1 << __fls(kgem->buffer_size); 214303b705cfSriastradh DBG(("%s: buffer size=%d [%d KiB]\n", __FUNCTION__, 214403b705cfSriastradh kgem->buffer_size, kgem->buffer_size / 1024)); 214503b705cfSriastradh assert(kgem->buffer_size); 214603b705cfSriastradh 214703b705cfSriastradh kgem->max_object_size = 3 * (kgem->aperture_high >> 12) << 10; 214803b705cfSriastradh kgem->max_gpu_size = kgem->max_object_size; 214903b705cfSriastradh if (!kgem->has_llc && kgem->max_gpu_size > MAX_CACHE_SIZE) 215003b705cfSriastradh kgem->max_gpu_size = MAX_CACHE_SIZE; 215103b705cfSriastradh 215203b705cfSriastradh totalram = total_ram_size(); 215303b705cfSriastradh if (totalram == 0) { 215403b705cfSriastradh DBG(("%s: total ram size unknown, assuming maximum of total aperture\n", 215503b705cfSriastradh __FUNCTION__)); 215603b705cfSriastradh totalram = kgem->aperture_total; 215703b705cfSriastradh } 215863ef14f0Smrg DBG(("%s: total ram=%lld\n", __FUNCTION__, (long long)totalram)); 215903b705cfSriastradh if (kgem->max_object_size > totalram / 2) 216003b705cfSriastradh kgem->max_object_size = totalram / 2; 216103b705cfSriastradh if (kgem->max_gpu_size > totalram / 4) 216203b705cfSriastradh kgem->max_gpu_size = totalram / 4; 216303b705cfSriastradh 21649a906b70Schristos if (kgem->aperture_high > totalram / 2) { 21659a906b70Schristos kgem->aperture_high = totalram / 2; 21669a906b70Schristos kgem->aperture_low = kgem->aperture_high / 4; 21679a906b70Schristos DBG(("%s: reduced aperture watermaks to fit into ram; low=%d [%d], high=%d [%d]\n", __FUNCTION__, 21689a906b70Schristos kgem->aperture_low, kgem->aperture_low / (1024*1024), 21699a906b70Schristos kgem->aperture_high, kgem->aperture_high / (1024*1024))); 21709a906b70Schristos } 21719a906b70Schristos 217203b705cfSriastradh kgem->max_cpu_size = kgem->max_object_size; 217303b705cfSriastradh 217403b705cfSriastradh half_gpu_max = kgem->max_gpu_size / 2; 217503b705cfSriastradh kgem->max_copy_tile_size = (MAX_CACHE_SIZE + 1)/2; 217603b705cfSriastradh if (kgem->max_copy_tile_size > half_gpu_max) 217703b705cfSriastradh kgem->max_copy_tile_size = half_gpu_max; 217803b705cfSriastradh 217903b705cfSriastradh if (kgem->has_llc) 218003b705cfSriastradh kgem->max_upload_tile_size = kgem->max_copy_tile_size; 218103b705cfSriastradh else 21829a906b70Schristos kgem->max_upload_tile_size = kgem->aperture_fenceable / 4; 218303b705cfSriastradh if (kgem->max_upload_tile_size > half_gpu_max) 218403b705cfSriastradh kgem->max_upload_tile_size = half_gpu_max; 218503b705cfSriastradh if (kgem->max_upload_tile_size > kgem->aperture_high/2) 218603b705cfSriastradh kgem->max_upload_tile_size = kgem->aperture_high/2; 218703b705cfSriastradh if (kgem->max_upload_tile_size > kgem->aperture_low) 218803b705cfSriastradh kgem->max_upload_tile_size = kgem->aperture_low; 218903b705cfSriastradh if (kgem->max_upload_tile_size < 16*PAGE_SIZE) 219003b705cfSriastradh kgem->max_upload_tile_size = 16*PAGE_SIZE; 219103b705cfSriastradh 219203b705cfSriastradh kgem->large_object_size = MAX_CACHE_SIZE; 219303b705cfSriastradh if (kgem->large_object_size > half_gpu_max) 219403b705cfSriastradh kgem->large_object_size = half_gpu_max; 219503b705cfSriastradh if (kgem->max_copy_tile_size > kgem->aperture_high/2) 219603b705cfSriastradh kgem->max_copy_tile_size = kgem->aperture_high/2; 219703b705cfSriastradh if (kgem->max_copy_tile_size > kgem->aperture_low) 219803b705cfSriastradh kgem->max_copy_tile_size = kgem->aperture_low; 219903b705cfSriastradh if (kgem->max_copy_tile_size < 16*PAGE_SIZE) 220003b705cfSriastradh kgem->max_copy_tile_size = 16*PAGE_SIZE; 220103b705cfSriastradh 220203b705cfSriastradh if (kgem->has_llc | kgem->has_caching | kgem->has_userptr) { 220303b705cfSriastradh if (kgem->large_object_size > kgem->max_cpu_size) 220403b705cfSriastradh kgem->large_object_size = kgem->max_cpu_size; 220503b705cfSriastradh } else 220603b705cfSriastradh kgem->max_cpu_size = 0; 220703b705cfSriastradh if (DBG_NO_CPU) 220803b705cfSriastradh kgem->max_cpu_size = 0; 220903b705cfSriastradh 221063ef14f0Smrg DBG(("%s: maximum object size=%u\n", 221103b705cfSriastradh __FUNCTION__, kgem->max_object_size)); 221263ef14f0Smrg DBG(("%s: large object thresold=%u\n", 221303b705cfSriastradh __FUNCTION__, kgem->large_object_size)); 221463ef14f0Smrg DBG(("%s: max object sizes (gpu=%u, cpu=%u, tile upload=%u, copy=%u)\n", 221503b705cfSriastradh __FUNCTION__, 221603b705cfSriastradh kgem->max_gpu_size, kgem->max_cpu_size, 221703b705cfSriastradh kgem->max_upload_tile_size, kgem->max_copy_tile_size)); 221803b705cfSriastradh 221903b705cfSriastradh /* Convert the aperture thresholds to pages */ 22209a906b70Schristos kgem->aperture_mappable /= PAGE_SIZE; 22219a906b70Schristos kgem->aperture_fenceable /= PAGE_SIZE; 222203b705cfSriastradh kgem->aperture_low /= PAGE_SIZE; 222303b705cfSriastradh kgem->aperture_high /= PAGE_SIZE; 22249a906b70Schristos kgem->aperture_total /= PAGE_SIZE; 222503b705cfSriastradh 222603b705cfSriastradh kgem->fence_max = gem_param(kgem, I915_PARAM_NUM_FENCES_AVAIL) - 2; 222703b705cfSriastradh if ((int)kgem->fence_max < 0) 222803b705cfSriastradh kgem->fence_max = 5; /* minimum safe value for all hw */ 222903b705cfSriastradh DBG(("%s: max fences=%d\n", __FUNCTION__, kgem->fence_max)); 223003b705cfSriastradh 223103b705cfSriastradh kgem->batch_flags_base = 0; 223203b705cfSriastradh if (kgem->has_no_reloc) 223303b705cfSriastradh kgem->batch_flags_base |= LOCAL_I915_EXEC_NO_RELOC; 223403b705cfSriastradh if (kgem->has_handle_lut) 223503b705cfSriastradh kgem->batch_flags_base |= LOCAL_I915_EXEC_HANDLE_LUT; 223603b705cfSriastradh if (kgem->has_pinned_batches) 223703b705cfSriastradh kgem->batch_flags_base |= LOCAL_I915_EXEC_IS_PINNED; 223803b705cfSriastradh 223903b705cfSriastradh kgem_init_swizzling(kgem); 224003b705cfSriastradh} 224103b705cfSriastradh 224203b705cfSriastradh/* XXX hopefully a good approximation */ 22439a906b70Schristosstatic uint32_t kgem_get_unique_id(struct kgem *kgem) 224403b705cfSriastradh{ 224503b705cfSriastradh uint32_t id; 224603b705cfSriastradh id = ++kgem->unique_id; 224703b705cfSriastradh if (id == 0) 224803b705cfSriastradh id = ++kgem->unique_id; 224903b705cfSriastradh return id; 225003b705cfSriastradh} 225103b705cfSriastradh 225203b705cfSriastradhinline static uint32_t kgem_pitch_alignment(struct kgem *kgem, unsigned flags) 225303b705cfSriastradh{ 225403b705cfSriastradh if (flags & CREATE_PRIME) 225503b705cfSriastradh return 256; 225603b705cfSriastradh if (flags & CREATE_SCANOUT) 225703b705cfSriastradh return 64; 2258813957e3Ssnj if (kgem->gen >= 0100) 2259813957e3Ssnj return 32; 22609a906b70Schristos return 8; 226103b705cfSriastradh} 226203b705cfSriastradh 22639a906b70Schristosvoid kgem_get_tile_size(struct kgem *kgem, int tiling, int pitch, 226403b705cfSriastradh int *tile_width, int *tile_height, int *tile_size) 226503b705cfSriastradh{ 226603b705cfSriastradh if (kgem->gen <= 030) { 226703b705cfSriastradh if (tiling) { 226803b705cfSriastradh if (kgem->gen < 030) { 226903b705cfSriastradh *tile_width = 128; 227003b705cfSriastradh *tile_height = 16; 227103b705cfSriastradh *tile_size = 2048; 227203b705cfSriastradh } else { 227303b705cfSriastradh *tile_width = 512; 227403b705cfSriastradh *tile_height = 8; 227503b705cfSriastradh *tile_size = 4096; 227603b705cfSriastradh } 227703b705cfSriastradh } else { 227803b705cfSriastradh *tile_width = 1; 227903b705cfSriastradh *tile_height = 1; 228003b705cfSriastradh *tile_size = 1; 228103b705cfSriastradh } 228203b705cfSriastradh } else switch (tiling) { 228303b705cfSriastradh default: 228403b705cfSriastradh case I915_TILING_NONE: 228503b705cfSriastradh *tile_width = 1; 228603b705cfSriastradh *tile_height = 1; 228703b705cfSriastradh *tile_size = 1; 228803b705cfSriastradh break; 228903b705cfSriastradh case I915_TILING_X: 229003b705cfSriastradh *tile_width = 512; 229103b705cfSriastradh *tile_height = 8; 229203b705cfSriastradh *tile_size = 4096; 229303b705cfSriastradh break; 229403b705cfSriastradh case I915_TILING_Y: 229503b705cfSriastradh *tile_width = 128; 229603b705cfSriastradh *tile_height = 32; 229703b705cfSriastradh *tile_size = 4096; 229803b705cfSriastradh break; 229903b705cfSriastradh } 23009a906b70Schristos 23019a906b70Schristos /* Force offset alignment to tile-row */ 23029a906b70Schristos if (tiling && kgem->gen < 033) 23039a906b70Schristos *tile_width = pitch; 230403b705cfSriastradh} 230503b705cfSriastradh 230603b705cfSriastradhstatic uint32_t kgem_surface_size(struct kgem *kgem, 230703b705cfSriastradh bool relaxed_fencing, 230803b705cfSriastradh unsigned flags, 230903b705cfSriastradh uint32_t width, 231003b705cfSriastradh uint32_t height, 231103b705cfSriastradh uint32_t bpp, 231203b705cfSriastradh uint32_t tiling, 231303b705cfSriastradh uint32_t *pitch) 231403b705cfSriastradh{ 231503b705cfSriastradh uint32_t tile_width, tile_height; 231603b705cfSriastradh uint32_t size; 231703b705cfSriastradh 231803b705cfSriastradh assert(width <= MAXSHORT); 231903b705cfSriastradh assert(height <= MAXSHORT); 232003b705cfSriastradh assert(bpp >= 8); 232103b705cfSriastradh 232203b705cfSriastradh if (kgem->gen <= 030) { 232303b705cfSriastradh if (tiling) { 232403b705cfSriastradh if (kgem->gen < 030) { 232503b705cfSriastradh tile_width = 128; 23269a906b70Schristos tile_height = 16; 232703b705cfSriastradh } else { 232803b705cfSriastradh tile_width = 512; 23299a906b70Schristos tile_height = 8; 233003b705cfSriastradh } 233103b705cfSriastradh } else { 233203b705cfSriastradh tile_width = 2 * bpp >> 3; 233303b705cfSriastradh tile_width = ALIGN(tile_width, 233403b705cfSriastradh kgem_pitch_alignment(kgem, flags)); 23359a906b70Schristos tile_height = 1; 233603b705cfSriastradh } 233703b705cfSriastradh } else switch (tiling) { 233803b705cfSriastradh default: 233903b705cfSriastradh case I915_TILING_NONE: 234003b705cfSriastradh tile_width = 2 * bpp >> 3; 234103b705cfSriastradh tile_width = ALIGN(tile_width, 234203b705cfSriastradh kgem_pitch_alignment(kgem, flags)); 23439a906b70Schristos tile_height = 1; 234403b705cfSriastradh break; 234503b705cfSriastradh 234603b705cfSriastradh case I915_TILING_X: 234703b705cfSriastradh tile_width = 512; 23489a906b70Schristos tile_height = 8; 234903b705cfSriastradh break; 235003b705cfSriastradh case I915_TILING_Y: 235103b705cfSriastradh tile_width = 128; 23529a906b70Schristos tile_height = 32; 235303b705cfSriastradh break; 235403b705cfSriastradh } 23559a906b70Schristos /* XXX align to an even tile row */ 23569a906b70Schristos if (!kgem->has_relaxed_fencing) 23579a906b70Schristos tile_height *= 2; 235803b705cfSriastradh 235903b705cfSriastradh *pitch = ALIGN(width * bpp / 8, tile_width); 236003b705cfSriastradh height = ALIGN(height, tile_height); 23619a906b70Schristos DBG(("%s: tile_width=%d, tile_height=%d => aligned pitch=%d, height=%d\n", 23629a906b70Schristos __FUNCTION__, tile_width, tile_height, *pitch, height)); 23639a906b70Schristos 236403b705cfSriastradh if (kgem->gen >= 040) 236503b705cfSriastradh return PAGE_ALIGN(*pitch * height); 236603b705cfSriastradh 236703b705cfSriastradh /* If it is too wide for the blitter, don't even bother. */ 236803b705cfSriastradh if (tiling != I915_TILING_NONE) { 23699a906b70Schristos if (*pitch > 8192) { 23709a906b70Schristos DBG(("%s: too wide for tiled surface (pitch=%d, limit=%d)\n", 23719a906b70Schristos __FUNCTION__, *pitch, 8192)); 237203b705cfSriastradh return 0; 23739a906b70Schristos } 237403b705cfSriastradh 237503b705cfSriastradh for (size = tile_width; size < *pitch; size <<= 1) 237603b705cfSriastradh ; 237703b705cfSriastradh *pitch = size; 237803b705cfSriastradh } else { 23799a906b70Schristos if (*pitch >= 32768) { 23809a906b70Schristos DBG(("%s: too wide for linear surface (pitch=%d, limit=%d)\n", 23819a906b70Schristos __FUNCTION__, *pitch, 32767)); 238203b705cfSriastradh return 0; 23839a906b70Schristos } 238403b705cfSriastradh } 238503b705cfSriastradh 238603b705cfSriastradh size = *pitch * height; 238703b705cfSriastradh if (relaxed_fencing || tiling == I915_TILING_NONE) 238803b705cfSriastradh return PAGE_ALIGN(size); 238903b705cfSriastradh 23909a906b70Schristos /* We need to allocate a pot fence region for a tiled buffer. */ 239103b705cfSriastradh if (kgem->gen < 030) 239203b705cfSriastradh tile_width = 512 * 1024; 239303b705cfSriastradh else 239403b705cfSriastradh tile_width = 1024 * 1024; 239503b705cfSriastradh while (tile_width < size) 239603b705cfSriastradh tile_width *= 2; 239703b705cfSriastradh return tile_width; 239803b705cfSriastradh} 239903b705cfSriastradh 24009a906b70Schristosbool kgem_check_surface_size(struct kgem *kgem, 24019a906b70Schristos uint32_t width, 24029a906b70Schristos uint32_t height, 24039a906b70Schristos uint32_t bpp, 24049a906b70Schristos uint32_t tiling, 24059a906b70Schristos uint32_t pitch, 24069a906b70Schristos uint32_t size) 24079a906b70Schristos{ 24089a906b70Schristos uint32_t min_size, min_pitch; 24099a906b70Schristos int tile_width, tile_height, tile_size; 24109a906b70Schristos 24119a906b70Schristos DBG(("%s(width=%d, height=%d, bpp=%d, tiling=%d, pitch=%d, size=%d)\n", 24129a906b70Schristos __FUNCTION__, width, height, bpp, tiling, pitch, size)); 24139a906b70Schristos 24149a906b70Schristos if (pitch & 3) 24159a906b70Schristos return false; 24169a906b70Schristos 24179a906b70Schristos min_size = kgem_surface_size(kgem, kgem->has_relaxed_fencing, 0, 24189a906b70Schristos width, height, bpp, tiling, 24199a906b70Schristos &min_pitch); 24209a906b70Schristos 24219a906b70Schristos DBG(("%s: min_pitch=%d, min_size=%d\n", __FUNCTION__, min_pitch, min_size)); 24229a906b70Schristos 24239a906b70Schristos if (size < min_size) 24249a906b70Schristos return false; 24259a906b70Schristos 24269a906b70Schristos if (pitch < min_pitch) 24279a906b70Schristos return false; 24289a906b70Schristos 24299a906b70Schristos kgem_get_tile_size(kgem, tiling, min_pitch, 24309a906b70Schristos &tile_width, &tile_height, &tile_size); 24319a906b70Schristos 24329a906b70Schristos DBG(("%s: tile_width=%d, tile_size=%d\n", __FUNCTION__, tile_width, tile_size)); 24339a906b70Schristos if (pitch & (tile_width - 1)) 24349a906b70Schristos return false; 24359a906b70Schristos if (size & (tile_size - 1)) 24369a906b70Schristos return false; 24379a906b70Schristos 24389a906b70Schristos return true; 24399a906b70Schristos} 24409a906b70Schristos 244103b705cfSriastradhstatic uint32_t kgem_aligned_height(struct kgem *kgem, 244203b705cfSriastradh uint32_t height, uint32_t tiling) 244303b705cfSriastradh{ 244403b705cfSriastradh uint32_t tile_height; 244503b705cfSriastradh 244603b705cfSriastradh if (kgem->gen <= 030) { 24479a906b70Schristos tile_height = tiling ? kgem->gen < 030 ? 16 : 8 : 1; 244803b705cfSriastradh } else switch (tiling) { 244903b705cfSriastradh /* XXX align to an even tile row */ 245003b705cfSriastradh default: 245103b705cfSriastradh case I915_TILING_NONE: 245203b705cfSriastradh tile_height = 1; 245303b705cfSriastradh break; 245403b705cfSriastradh case I915_TILING_X: 24559a906b70Schristos tile_height = 8; 245603b705cfSriastradh break; 245703b705cfSriastradh case I915_TILING_Y: 24589a906b70Schristos tile_height = 32; 245903b705cfSriastradh break; 246003b705cfSriastradh } 246103b705cfSriastradh 24629a906b70Schristos /* XXX align to an even tile row */ 24639a906b70Schristos if (!kgem->has_relaxed_fencing) 24649a906b70Schristos tile_height *= 2; 24659a906b70Schristos 246603b705cfSriastradh return ALIGN(height, tile_height); 246703b705cfSriastradh} 246803b705cfSriastradh 246903b705cfSriastradhstatic struct drm_i915_gem_exec_object2 * 247003b705cfSriastradhkgem_add_handle(struct kgem *kgem, struct kgem_bo *bo) 247103b705cfSriastradh{ 247203b705cfSriastradh struct drm_i915_gem_exec_object2 *exec; 247303b705cfSriastradh 247403b705cfSriastradh DBG(("%s: handle=%d, index=%d\n", 247503b705cfSriastradh __FUNCTION__, bo->handle, kgem->nexec)); 247603b705cfSriastradh 247703b705cfSriastradh assert(kgem->nexec < ARRAY_SIZE(kgem->exec)); 247803b705cfSriastradh bo->target_handle = kgem->has_handle_lut ? kgem->nexec : bo->handle; 247903b705cfSriastradh exec = memset(&kgem->exec[kgem->nexec++], 0, sizeof(*exec)); 248003b705cfSriastradh exec->handle = bo->handle; 248103b705cfSriastradh exec->offset = bo->presumed_offset; 248203b705cfSriastradh 248303b705cfSriastradh kgem->aperture += num_pages(bo); 248403b705cfSriastradh 248503b705cfSriastradh return exec; 248603b705cfSriastradh} 248703b705cfSriastradh 248803b705cfSriastradhstatic void kgem_add_bo(struct kgem *kgem, struct kgem_bo *bo) 248903b705cfSriastradh{ 24909a906b70Schristos assert(bo->refcnt); 24919a906b70Schristos assert(bo->proxy == NULL); 24929a906b70Schristos 249303b705cfSriastradh bo->exec = kgem_add_handle(kgem, bo); 249403b705cfSriastradh bo->rq = MAKE_REQUEST(kgem->next_request, kgem->ring); 249503b705cfSriastradh 249603b705cfSriastradh list_move_tail(&bo->request, &kgem->next_request->buffers); 24979a906b70Schristos if (bo->io && !list_is_empty(&bo->list)) 24989a906b70Schristos list_move(&bo->list, &kgem->batch_buffers); 249903b705cfSriastradh 250003b705cfSriastradh /* XXX is it worth working around gcc here? */ 250103b705cfSriastradh kgem->flush |= bo->flush; 250203b705cfSriastradh} 250303b705cfSriastradh 250463ef14f0Smrgstatic void kgem_clear_swctrl(struct kgem *kgem) 250563ef14f0Smrg{ 250663ef14f0Smrg uint32_t *b; 250763ef14f0Smrg 250863ef14f0Smrg if (kgem->bcs_state == 0) 250963ef14f0Smrg return; 251063ef14f0Smrg 251163ef14f0Smrg DBG(("%s: clearin SWCTRL LRI from %x\n", 251263ef14f0Smrg __FUNCTION__, kgem->bcs_state)); 251363ef14f0Smrg 251463ef14f0Smrg b = kgem->batch + kgem->nbatch; 251563ef14f0Smrg kgem->nbatch += 7; 251663ef14f0Smrg 251763ef14f0Smrg *b++ = MI_FLUSH_DW; 251863ef14f0Smrg *b++ = 0; 251963ef14f0Smrg *b++ = 0; 252063ef14f0Smrg *b++ = 0; 252163ef14f0Smrg 252263ef14f0Smrg *b++ = MI_LOAD_REGISTER_IMM; 252363ef14f0Smrg *b++ = BCS_SWCTRL; 252463ef14f0Smrg *b++ = (BCS_SRC_Y | BCS_DST_Y) << 16; 252563ef14f0Smrg 252663ef14f0Smrg kgem->bcs_state = 0; 252763ef14f0Smrg} 252863ef14f0Smrg 252903b705cfSriastradhstatic uint32_t kgem_end_batch(struct kgem *kgem) 253003b705cfSriastradh{ 253163ef14f0Smrg kgem_clear_swctrl(kgem); 253203b705cfSriastradh kgem->batch[kgem->nbatch++] = MI_BATCH_BUFFER_END; 253303b705cfSriastradh if (kgem->nbatch & 1) 253403b705cfSriastradh kgem->batch[kgem->nbatch++] = MI_NOOP; 253503b705cfSriastradh 253603b705cfSriastradh return kgem->nbatch; 253703b705cfSriastradh} 253803b705cfSriastradh 253903b705cfSriastradhstatic void kgem_bo_binding_free(struct kgem *kgem, struct kgem_bo *bo) 254003b705cfSriastradh{ 254103b705cfSriastradh struct kgem_bo_binding *b; 254203b705cfSriastradh 254303b705cfSriastradh b = bo->binding.next; 254403b705cfSriastradh while (b) { 254503b705cfSriastradh struct kgem_bo_binding *next = b->next; 25469a906b70Schristos free(b); 254703b705cfSriastradh b = next; 254803b705cfSriastradh } 254903b705cfSriastradh} 255003b705cfSriastradh 255103b705cfSriastradhstatic void kgem_bo_free(struct kgem *kgem, struct kgem_bo *bo) 255203b705cfSriastradh{ 25539a906b70Schristos DBG(("%s: handle=%d, size=%d\n", __FUNCTION__, bo->handle, bytes(bo))); 255403b705cfSriastradh assert(bo->refcnt == 0); 255503b705cfSriastradh assert(bo->proxy == NULL); 255603b705cfSriastradh assert(bo->exec == NULL); 255703b705cfSriastradh assert(!bo->snoop || bo->rq == NULL); 255803b705cfSriastradh 255903b705cfSriastradh#ifdef DEBUG_MEMORY 256003b705cfSriastradh kgem->debug_memory.bo_allocs--; 256103b705cfSriastradh kgem->debug_memory.bo_bytes -= bytes(bo); 256203b705cfSriastradh#endif 256303b705cfSriastradh 256403b705cfSriastradh kgem_bo_binding_free(kgem, bo); 25659a906b70Schristos kgem_bo_rmfb(kgem, bo); 256603b705cfSriastradh 25679a906b70Schristos if (IS_USER_MAP(bo->map__cpu)) { 256803b705cfSriastradh assert(bo->rq == NULL); 256903b705cfSriastradh assert(!__kgem_busy(kgem, bo->handle)); 25709a906b70Schristos assert(MAP(bo->map__cpu) != bo || bo->io || bo->flush); 257103b705cfSriastradh if (!(bo->io || bo->flush)) { 257203b705cfSriastradh DBG(("%s: freeing snooped base\n", __FUNCTION__)); 25739a906b70Schristos assert(bo != MAP(bo->map__cpu)); 25749a906b70Schristos free(MAP(bo->map__cpu)); 257503b705cfSriastradh } 25769a906b70Schristos bo->map__cpu = NULL; 25779a906b70Schristos } 25789a906b70Schristos 25799a906b70Schristos DBG(("%s: releasing %p:%p vma for handle=%d, count=%d\n", 25809a906b70Schristos __FUNCTION__, bo->map__gtt, bo->map__cpu, 2581813957e3Ssnj bo->handle, list_is_empty(&bo->vma) ? 0 : kgem->vma[bo->map__gtt == NULL && bo->map__wc == NULL].count)); 25829a906b70Schristos 25839a906b70Schristos if (!list_is_empty(&bo->vma)) { 25849a906b70Schristos _list_del(&bo->vma); 2585813957e3Ssnj kgem->vma[bo->map__gtt == NULL && bo->map__wc == NULL].count--; 258603b705cfSriastradh } 25879a906b70Schristos 25889a906b70Schristos if (bo->map__gtt) 2589813957e3Ssnj munmap(bo->map__gtt, bytes(bo)); 2590813957e3Ssnj if (bo->map__wc) { 2591813957e3Ssnj VG(VALGRIND_MAKE_MEM_NOACCESS(bo->map__wc, bytes(bo))); 2592813957e3Ssnj munmap(bo->map__wc, bytes(bo)); 2593813957e3Ssnj } 2594813957e3Ssnj if (bo->map__cpu) { 2595813957e3Ssnj VG(VALGRIND_MAKE_MEM_NOACCESS(MAP(bo->map__cpu), bytes(bo))); 25969a906b70Schristos munmap(MAP(bo->map__cpu), bytes(bo)); 2597813957e3Ssnj } 259803b705cfSriastradh 259903b705cfSriastradh _list_del(&bo->list); 260003b705cfSriastradh _list_del(&bo->request); 260103b705cfSriastradh gem_close(kgem->fd, bo->handle); 260203b705cfSriastradh 26039a906b70Schristos if (!bo->io && !DBG_NO_MALLOC_CACHE) { 260403b705cfSriastradh *(struct kgem_bo **)bo = __kgem_freed_bo; 260503b705cfSriastradh __kgem_freed_bo = bo; 260603b705cfSriastradh } else 260703b705cfSriastradh free(bo); 260803b705cfSriastradh} 260903b705cfSriastradh 261003b705cfSriastradhinline static void kgem_bo_move_to_inactive(struct kgem *kgem, 261103b705cfSriastradh struct kgem_bo *bo) 261203b705cfSriastradh{ 261303b705cfSriastradh DBG(("%s: moving handle=%d to inactive\n", __FUNCTION__, bo->handle)); 261403b705cfSriastradh 261503b705cfSriastradh assert(bo->refcnt == 0); 261603b705cfSriastradh assert(bo->reusable); 261703b705cfSriastradh assert(bo->rq == NULL); 261803b705cfSriastradh assert(bo->exec == NULL); 261903b705cfSriastradh assert(bo->domain != DOMAIN_GPU); 262003b705cfSriastradh assert(!bo->proxy); 262103b705cfSriastradh assert(!bo->io); 262203b705cfSriastradh assert(!bo->scanout); 262303b705cfSriastradh assert(!bo->snoop); 262403b705cfSriastradh assert(!bo->flush); 262503b705cfSriastradh assert(!bo->needs_flush); 262663ef14f0Smrg assert(!bo->delta); 262703b705cfSriastradh assert(list_is_empty(&bo->vma)); 262803b705cfSriastradh assert_tiling(kgem, bo); 262963ef14f0Smrg assert_caching(kgem, bo); 263003b705cfSriastradh ASSERT_IDLE(kgem, bo->handle); 263103b705cfSriastradh 263203b705cfSriastradh if (bucket(bo) >= NUM_CACHE_BUCKETS) { 26339a906b70Schristos if (bo->map__gtt) { 263463ef14f0Smrg DBG(("%s: relinquishing large GTT mapping for handle=%d\n", 263563ef14f0Smrg __FUNCTION__, bo->handle)); 2636813957e3Ssnj munmap(bo->map__gtt, bytes(bo)); 26379a906b70Schristos bo->map__gtt = NULL; 26389a906b70Schristos } 263903b705cfSriastradh 26409a906b70Schristos list_move(&bo->list, &kgem->large_inactive); 26419a906b70Schristos } else { 26429a906b70Schristos assert(bo->flush == false); 2643813957e3Ssnj assert(list_is_empty(&bo->vma)); 26449a906b70Schristos list_move(&bo->list, &kgem->inactive[bucket(bo)]); 2645813957e3Ssnj if (bo->map__gtt && !kgem_bo_can_map(kgem, bo)) { 264663ef14f0Smrg DBG(("%s: relinquishing old GTT mapping for handle=%d\n", 264763ef14f0Smrg __FUNCTION__, bo->handle)); 2648813957e3Ssnj munmap(bo->map__gtt, bytes(bo)); 2649813957e3Ssnj bo->map__gtt = NULL; 265003b705cfSriastradh } 2651813957e3Ssnj if (bo->map__gtt || (bo->map__wc && !bo->tiling)) { 2652813957e3Ssnj list_add(&bo->vma, &kgem->vma[0].inactive[bucket(bo)]); 2653813957e3Ssnj kgem->vma[0].count++; 2654813957e3Ssnj } 2655813957e3Ssnj if (bo->map__cpu && list_is_empty(&bo->vma)) { 26569a906b70Schristos list_add(&bo->vma, &kgem->vma[1].inactive[bucket(bo)]); 26579a906b70Schristos kgem->vma[1].count++; 265803b705cfSriastradh } 265903b705cfSriastradh } 26609a906b70Schristos 26619a906b70Schristos kgem->need_expire = true; 266203b705cfSriastradh} 266303b705cfSriastradh 266403b705cfSriastradhstatic struct kgem_bo *kgem_bo_replace_io(struct kgem_bo *bo) 266503b705cfSriastradh{ 266603b705cfSriastradh struct kgem_bo *base; 266703b705cfSriastradh 266803b705cfSriastradh if (!bo->io) 266903b705cfSriastradh return bo; 267003b705cfSriastradh 267103b705cfSriastradh assert(!bo->snoop); 267263ef14f0Smrg assert(!bo->purged); 267363ef14f0Smrg assert(!bo->scanout); 267463ef14f0Smrg assert(!bo->delta); 267563ef14f0Smrg 26769a906b70Schristos if (__kgem_freed_bo) { 26779a906b70Schristos base = __kgem_freed_bo; 26789a906b70Schristos __kgem_freed_bo = *(struct kgem_bo **)base; 26799a906b70Schristos } else 26809a906b70Schristos base = malloc(sizeof(*base)); 268103b705cfSriastradh if (base) { 268203b705cfSriastradh DBG(("%s: transferring io handle=%d to bo\n", 268303b705cfSriastradh __FUNCTION__, bo->handle)); 268403b705cfSriastradh /* transfer the handle to a minimum bo */ 268503b705cfSriastradh memcpy(base, bo, sizeof(*base)); 268603b705cfSriastradh base->io = false; 268703b705cfSriastradh list_init(&base->list); 268803b705cfSriastradh list_replace(&bo->request, &base->request); 268903b705cfSriastradh list_replace(&bo->vma, &base->vma); 269003b705cfSriastradh free(bo); 269103b705cfSriastradh bo = base; 269203b705cfSriastradh } else 269303b705cfSriastradh bo->reusable = false; 269403b705cfSriastradh 269503b705cfSriastradh return bo; 269603b705cfSriastradh} 269703b705cfSriastradh 269803b705cfSriastradhinline static void kgem_bo_remove_from_inactive(struct kgem *kgem, 269903b705cfSriastradh struct kgem_bo *bo) 270003b705cfSriastradh{ 270103b705cfSriastradh DBG(("%s: removing handle=%d from inactive\n", __FUNCTION__, bo->handle)); 270203b705cfSriastradh 270303b705cfSriastradh list_del(&bo->list); 270403b705cfSriastradh assert(bo->rq == NULL); 270503b705cfSriastradh assert(bo->exec == NULL); 270663ef14f0Smrg assert(!bo->purged); 27079a906b70Schristos if (!list_is_empty(&bo->vma)) { 2708813957e3Ssnj assert(bo->map__gtt || bo->map__wc || bo->map__cpu); 270903b705cfSriastradh list_del(&bo->vma); 2710813957e3Ssnj kgem->vma[bo->map__gtt == NULL && bo->map__wc == NULL].count--; 271103b705cfSriastradh } 271203b705cfSriastradh} 271303b705cfSriastradh 271403b705cfSriastradhinline static void kgem_bo_remove_from_active(struct kgem *kgem, 271503b705cfSriastradh struct kgem_bo *bo) 271603b705cfSriastradh{ 271703b705cfSriastradh DBG(("%s: removing handle=%d from active\n", __FUNCTION__, bo->handle)); 271803b705cfSriastradh 271903b705cfSriastradh list_del(&bo->list); 272003b705cfSriastradh assert(bo->rq != NULL); 27219a906b70Schristos if (RQ(bo->rq) == (void *)kgem) { 27229a906b70Schristos assert(bo->exec == NULL); 272303b705cfSriastradh list_del(&bo->request); 27249a906b70Schristos } 272503b705cfSriastradh assert(list_is_empty(&bo->vma)); 272603b705cfSriastradh} 272703b705cfSriastradh 272803b705cfSriastradhstatic void _kgem_bo_delete_buffer(struct kgem *kgem, struct kgem_bo *bo) 272903b705cfSriastradh{ 273003b705cfSriastradh struct kgem_buffer *io = (struct kgem_buffer *)bo->proxy; 273103b705cfSriastradh 273203b705cfSriastradh DBG(("%s: size=%d, offset=%d, parent used=%d\n", 273303b705cfSriastradh __FUNCTION__, bo->size.bytes, bo->delta, io->used)); 273403b705cfSriastradh 273503b705cfSriastradh if (ALIGN(bo->delta + bo->size.bytes, UPLOAD_ALIGNMENT) == io->used) 273603b705cfSriastradh io->used = bo->delta; 273703b705cfSriastradh} 273803b705cfSriastradh 273903b705cfSriastradhstatic bool check_scanout_size(struct kgem *kgem, 274003b705cfSriastradh struct kgem_bo *bo, 274103b705cfSriastradh int width, int height) 274203b705cfSriastradh{ 274303b705cfSriastradh struct drm_mode_fb_cmd info; 274403b705cfSriastradh 274503b705cfSriastradh assert(bo->scanout); 274603b705cfSriastradh 274703b705cfSriastradh VG_CLEAR(info); 274803b705cfSriastradh info.fb_id = bo->delta; 274903b705cfSriastradh 27509a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_MODE_GETFB, &info)) 275103b705cfSriastradh return false; 275203b705cfSriastradh 275303b705cfSriastradh gem_close(kgem->fd, info.handle); 275403b705cfSriastradh 275563ef14f0Smrg if (width > info.width || height > info.height) { 275603b705cfSriastradh DBG(("%s: not using scanout %d (%dx%d), want (%dx%d)\n", 275703b705cfSriastradh __FUNCTION__, 275803b705cfSriastradh info.fb_id, info.width, info.height, 275903b705cfSriastradh width, height)); 276003b705cfSriastradh return false; 276103b705cfSriastradh } 276203b705cfSriastradh 276303b705cfSriastradh return true; 276403b705cfSriastradh} 276503b705cfSriastradh 276603b705cfSriastradhstatic void kgem_bo_move_to_scanout(struct kgem *kgem, struct kgem_bo *bo) 276703b705cfSriastradh{ 276803b705cfSriastradh assert(bo->refcnt == 0); 276903b705cfSriastradh assert(bo->scanout); 277003b705cfSriastradh assert(!bo->flush); 277103b705cfSriastradh assert(!bo->snoop); 277203b705cfSriastradh assert(!bo->io); 277303b705cfSriastradh 27749a906b70Schristos if (bo->purged) { /* for stolen fb */ 27759a906b70Schristos if (!bo->exec) { 27769a906b70Schristos DBG(("%s: discarding purged scanout - stolen?\n", 27779a906b70Schristos __FUNCTION__)); 27789a906b70Schristos kgem_bo_free(kgem, bo); 27799a906b70Schristos } 278003b705cfSriastradh return; 278103b705cfSriastradh } 278203b705cfSriastradh 278303b705cfSriastradh DBG(("%s: moving %d [fb %d] to scanout cache, active? %d\n", 278403b705cfSriastradh __FUNCTION__, bo->handle, bo->delta, bo->rq != NULL)); 278503b705cfSriastradh if (bo->rq) 278603b705cfSriastradh list_move_tail(&bo->list, &kgem->scanout); 278703b705cfSriastradh else 278803b705cfSriastradh list_move(&bo->list, &kgem->scanout); 27899a906b70Schristos 27909a906b70Schristos kgem->need_expire = true; 279103b705cfSriastradh} 279203b705cfSriastradh 279303b705cfSriastradhstatic void kgem_bo_move_to_snoop(struct kgem *kgem, struct kgem_bo *bo) 279403b705cfSriastradh{ 279503b705cfSriastradh assert(bo->reusable); 27969a906b70Schristos assert(!bo->scanout); 279703b705cfSriastradh assert(!bo->flush); 279803b705cfSriastradh assert(!bo->needs_flush); 279903b705cfSriastradh assert(bo->refcnt == 0); 280003b705cfSriastradh assert(bo->exec == NULL); 280163ef14f0Smrg assert(!bo->purged); 280263ef14f0Smrg assert(!bo->delta); 280303b705cfSriastradh 28049a906b70Schristos if (DBG_NO_SNOOP_CACHE) { 28059a906b70Schristos kgem_bo_free(kgem, bo); 28069a906b70Schristos return; 28079a906b70Schristos } 28089a906b70Schristos 280903b705cfSriastradh if (num_pages(bo) > kgem->max_cpu_size >> 13) { 281003b705cfSriastradh DBG(("%s handle=%d discarding large CPU buffer (%d >%d pages)\n", 281103b705cfSriastradh __FUNCTION__, bo->handle, num_pages(bo), kgem->max_cpu_size >> 13)); 281203b705cfSriastradh kgem_bo_free(kgem, bo); 281303b705cfSriastradh return; 281403b705cfSriastradh } 281503b705cfSriastradh 281603b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 281703b705cfSriastradh assert(bo->rq == NULL); 281803b705cfSriastradh 281903b705cfSriastradh DBG(("%s: moving %d to snoop cachee\n", __FUNCTION__, bo->handle)); 282003b705cfSriastradh list_add(&bo->list, &kgem->snoop); 28219a906b70Schristos kgem->need_expire = true; 28229a906b70Schristos} 28239a906b70Schristos 28249a906b70Schristosstatic bool kgem_bo_move_to_cache(struct kgem *kgem, struct kgem_bo *bo) 28259a906b70Schristos{ 28269a906b70Schristos bool retired = false; 28279a906b70Schristos 28289a906b70Schristos DBG(("%s: release handle=%d\n", __FUNCTION__, bo->handle)); 28299a906b70Schristos 28309a906b70Schristos if (bo->prime) { 28319a906b70Schristos DBG(("%s: discarding imported prime handle=%d\n", 28329a906b70Schristos __FUNCTION__, bo->handle)); 28339a906b70Schristos kgem_bo_free(kgem, bo); 28349a906b70Schristos } else if (bo->snoop) { 28359a906b70Schristos kgem_bo_move_to_snoop(kgem, bo); 28369a906b70Schristos } else if (bo->scanout) { 28379a906b70Schristos kgem_bo_move_to_scanout(kgem, bo); 283863ef14f0Smrg } else if ((bo = kgem_bo_replace_io(bo))->reusable) { 28399a906b70Schristos kgem_bo_move_to_inactive(kgem, bo); 28409a906b70Schristos retired = true; 28419a906b70Schristos } else 28429a906b70Schristos kgem_bo_free(kgem, bo); 28439a906b70Schristos 28449a906b70Schristos return retired; 284503b705cfSriastradh} 284603b705cfSriastradh 284703b705cfSriastradhstatic struct kgem_bo * 284803b705cfSriastradhsearch_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags) 284903b705cfSriastradh{ 285003b705cfSriastradh struct kgem_bo *bo, *first = NULL; 285103b705cfSriastradh 285203b705cfSriastradh DBG(("%s: num_pages=%d, flags=%x\n", __FUNCTION__, num_pages, flags)); 285303b705cfSriastradh 285403b705cfSriastradh if ((kgem->has_caching | kgem->has_userptr) == 0) 285503b705cfSriastradh return NULL; 285603b705cfSriastradh 285703b705cfSriastradh if (list_is_empty(&kgem->snoop)) { 285803b705cfSriastradh DBG(("%s: inactive and cache empty\n", __FUNCTION__)); 285903b705cfSriastradh if (!__kgem_throttle_retire(kgem, flags)) { 286003b705cfSriastradh DBG(("%s: nothing retired\n", __FUNCTION__)); 286103b705cfSriastradh return NULL; 286203b705cfSriastradh } 286303b705cfSriastradh } 286403b705cfSriastradh 286503b705cfSriastradh list_for_each_entry(bo, &kgem->snoop, list) { 286603b705cfSriastradh assert(bo->refcnt == 0); 286703b705cfSriastradh assert(bo->snoop); 286803b705cfSriastradh assert(!bo->scanout); 286903b705cfSriastradh assert(!bo->purged); 287003b705cfSriastradh assert(bo->proxy == NULL); 287103b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 287203b705cfSriastradh assert(bo->rq == NULL); 287303b705cfSriastradh assert(bo->exec == NULL); 287403b705cfSriastradh 287503b705cfSriastradh if (num_pages > num_pages(bo)) 287603b705cfSriastradh continue; 287703b705cfSriastradh 287803b705cfSriastradh if (num_pages(bo) > 2*num_pages) { 287903b705cfSriastradh if (first == NULL) 288003b705cfSriastradh first = bo; 288103b705cfSriastradh continue; 288203b705cfSriastradh } 288303b705cfSriastradh 288403b705cfSriastradh list_del(&bo->list); 288503b705cfSriastradh bo->pitch = 0; 288603b705cfSriastradh bo->delta = 0; 288703b705cfSriastradh 288803b705cfSriastradh DBG((" %s: found handle=%d (num_pages=%d) in snoop cache\n", 288903b705cfSriastradh __FUNCTION__, bo->handle, num_pages(bo))); 289003b705cfSriastradh return bo; 289103b705cfSriastradh } 289203b705cfSriastradh 289303b705cfSriastradh if (first) { 289403b705cfSriastradh list_del(&first->list); 289503b705cfSriastradh first->pitch = 0; 289603b705cfSriastradh first->delta = 0; 289703b705cfSriastradh 289803b705cfSriastradh DBG((" %s: found handle=%d (num_pages=%d) in snoop cache\n", 289903b705cfSriastradh __FUNCTION__, first->handle, num_pages(first))); 290003b705cfSriastradh return first; 290103b705cfSriastradh } 290203b705cfSriastradh 290303b705cfSriastradh return NULL; 290403b705cfSriastradh} 290503b705cfSriastradh 290603b705cfSriastradhvoid kgem_bo_undo(struct kgem *kgem, struct kgem_bo *bo) 290703b705cfSriastradh{ 290803b705cfSriastradh if (kgem->nexec != 1 || bo->exec == NULL) 290903b705cfSriastradh return; 291003b705cfSriastradh 29119a906b70Schristos assert(bo); 291203b705cfSriastradh DBG(("%s: only handle in batch, discarding last operations for handle=%d\n", 291303b705cfSriastradh __FUNCTION__, bo->handle)); 291403b705cfSriastradh 291563ef14f0Smrg assert(bo->exec == &_kgem_dummy_exec || bo->exec == &kgem->exec[0]); 291603b705cfSriastradh assert(kgem->exec[0].handle == bo->handle); 291703b705cfSriastradh assert(RQ(bo->rq) == kgem->next_request); 291803b705cfSriastradh 291903b705cfSriastradh bo->refcnt++; 292003b705cfSriastradh kgem_reset(kgem); 292103b705cfSriastradh bo->refcnt--; 29229a906b70Schristos 29239a906b70Schristos assert(kgem->nreloc == 0); 29249a906b70Schristos assert(kgem->nexec == 0); 29259a906b70Schristos assert(bo->exec == NULL); 292603b705cfSriastradh} 292703b705cfSriastradh 29289a906b70Schristosvoid kgem_bo_pair_undo(struct kgem *kgem, struct kgem_bo *a, struct kgem_bo *b) 292903b705cfSriastradh{ 29309a906b70Schristos if (kgem->nexec > 2) 29319a906b70Schristos return; 293203b705cfSriastradh 29339a906b70Schristos if (kgem->nexec == 1) { 29349a906b70Schristos if (a) 29359a906b70Schristos kgem_bo_undo(kgem, a); 29369a906b70Schristos if (b) 29379a906b70Schristos kgem_bo_undo(kgem, b); 29389a906b70Schristos return; 29399a906b70Schristos } 29409a906b70Schristos 29419a906b70Schristos if (a == NULL || b == NULL) 29429a906b70Schristos return; 294363ef14f0Smrg assert(a != b); 29449a906b70Schristos if (a->exec == NULL || b->exec == NULL) 29459a906b70Schristos return; 29469a906b70Schristos 294763ef14f0Smrg DBG(("%s: only handles in batch, discarding last operations for handle=%d (index=%d) and handle=%d (index=%d)\n", 294863ef14f0Smrg __FUNCTION__, 294963ef14f0Smrg a->handle, a->proxy ? -1 : a->exec - kgem->exec, 295063ef14f0Smrg b->handle, b->proxy ? -1 : b->exec - kgem->exec)); 29519a906b70Schristos 295263ef14f0Smrg assert(a->exec == &_kgem_dummy_exec || 295363ef14f0Smrg a->exec == &kgem->exec[0] || 295463ef14f0Smrg a->exec == &kgem->exec[1]); 29559a906b70Schristos assert(a->handle == kgem->exec[0].handle || a->handle == kgem->exec[1].handle); 29569a906b70Schristos assert(RQ(a->rq) == kgem->next_request); 295763ef14f0Smrg assert(b->exec == &_kgem_dummy_exec || 295863ef14f0Smrg b->exec == &kgem->exec[0] || 295963ef14f0Smrg b->exec == &kgem->exec[1]); 29609a906b70Schristos assert(b->handle == kgem->exec[0].handle || b->handle == kgem->exec[1].handle); 29619a906b70Schristos assert(RQ(b->rq) == kgem->next_request); 29629a906b70Schristos 29639a906b70Schristos a->refcnt++; 29649a906b70Schristos b->refcnt++; 29659a906b70Schristos kgem_reset(kgem); 29669a906b70Schristos b->refcnt--; 29679a906b70Schristos a->refcnt--; 29689a906b70Schristos 29699a906b70Schristos assert(kgem->nreloc == 0); 29709a906b70Schristos assert(kgem->nexec == 0); 29719a906b70Schristos assert(a->exec == NULL); 29729a906b70Schristos assert(b->exec == NULL); 29739a906b70Schristos} 29749a906b70Schristos 29759a906b70Schristosstatic void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo) 29769a906b70Schristos{ 29779a906b70Schristos DBG(("%s: handle=%d, size=%d\n", __FUNCTION__, bo->handle, bytes(bo))); 29789a906b70Schristos 29799a906b70Schristos assert(list_is_empty(&bo->list)); 298063ef14f0Smrg assert(list_is_empty(&bo->vma)); 29819a906b70Schristos assert(bo->refcnt == 0); 29829a906b70Schristos assert(bo->proxy == NULL); 29839a906b70Schristos assert(bo->active_scanout == 0); 29849a906b70Schristos assert_tiling(kgem, bo); 29859a906b70Schristos 29869a906b70Schristos bo->binding.offset = 0; 298703b705cfSriastradh 298803b705cfSriastradh if (DBG_NO_CACHE) 298903b705cfSriastradh goto destroy; 299003b705cfSriastradh 29919a906b70Schristos if (bo->prime) 29929a906b70Schristos goto destroy; 29939a906b70Schristos 299403b705cfSriastradh if (bo->snoop && !bo->flush) { 299503b705cfSriastradh DBG(("%s: handle=%d is snooped\n", __FUNCTION__, bo->handle)); 299603b705cfSriastradh assert(bo->reusable); 299703b705cfSriastradh assert(list_is_empty(&bo->list)); 299803b705cfSriastradh if (bo->exec == NULL && bo->rq && !__kgem_busy(kgem, bo->handle)) 299903b705cfSriastradh __kgem_bo_clear_busy(bo); 300003b705cfSriastradh if (bo->rq == NULL) 300103b705cfSriastradh kgem_bo_move_to_snoop(kgem, bo); 300203b705cfSriastradh return; 300303b705cfSriastradh } 30049a906b70Schristos if (!IS_USER_MAP(bo->map__cpu)) 300503b705cfSriastradh bo->flush = false; 300603b705cfSriastradh 300703b705cfSriastradh if (bo->scanout) { 300803b705cfSriastradh kgem_bo_move_to_scanout(kgem, bo); 300903b705cfSriastradh return; 301003b705cfSriastradh } 301103b705cfSriastradh 301203b705cfSriastradh if (bo->io) 301303b705cfSriastradh bo = kgem_bo_replace_io(bo); 301403b705cfSriastradh if (!bo->reusable) { 301503b705cfSriastradh DBG(("%s: handle=%d, not reusable\n", 301603b705cfSriastradh __FUNCTION__, bo->handle)); 301703b705cfSriastradh goto destroy; 301803b705cfSriastradh } 301903b705cfSriastradh 302003b705cfSriastradh assert(list_is_empty(&bo->vma)); 302103b705cfSriastradh assert(list_is_empty(&bo->list)); 302203b705cfSriastradh assert(bo->flush == false); 302303b705cfSriastradh assert(bo->snoop == false); 302403b705cfSriastradh assert(bo->io == false); 302503b705cfSriastradh assert(bo->scanout == false); 302663ef14f0Smrg assert_caching(kgem, bo); 302703b705cfSriastradh 302803b705cfSriastradh kgem_bo_undo(kgem, bo); 302903b705cfSriastradh assert(bo->refcnt == 0); 303003b705cfSriastradh 303103b705cfSriastradh if (bo->rq && bo->exec == NULL && !__kgem_busy(kgem, bo->handle)) 303203b705cfSriastradh __kgem_bo_clear_busy(bo); 303303b705cfSriastradh 303403b705cfSriastradh if (bo->rq) { 303503b705cfSriastradh struct list *cache; 303603b705cfSriastradh 303703b705cfSriastradh DBG(("%s: handle=%d -> active\n", __FUNCTION__, bo->handle)); 303803b705cfSriastradh if (bucket(bo) < NUM_CACHE_BUCKETS) 303903b705cfSriastradh cache = &kgem->active[bucket(bo)][bo->tiling]; 304003b705cfSriastradh else 304103b705cfSriastradh cache = &kgem->large; 304203b705cfSriastradh list_add(&bo->list, cache); 304303b705cfSriastradh return; 304403b705cfSriastradh } 304503b705cfSriastradh 304603b705cfSriastradh assert(bo->exec == NULL); 304703b705cfSriastradh assert(list_is_empty(&bo->request)); 304803b705cfSriastradh 30499a906b70Schristos if (bo->map__cpu == NULL || bucket(bo) >= NUM_CACHE_BUCKETS) { 305003b705cfSriastradh if (!kgem->has_llc && bo->domain == DOMAIN_CPU) 305103b705cfSriastradh goto destroy; 305203b705cfSriastradh 305303b705cfSriastradh DBG(("%s: handle=%d, purged\n", 305403b705cfSriastradh __FUNCTION__, bo->handle)); 305503b705cfSriastradh } 305603b705cfSriastradh 305703b705cfSriastradh kgem_bo_move_to_inactive(kgem, bo); 305803b705cfSriastradh return; 305903b705cfSriastradh 306003b705cfSriastradhdestroy: 306103b705cfSriastradh if (!bo->exec) 306203b705cfSriastradh kgem_bo_free(kgem, bo); 306303b705cfSriastradh} 306403b705cfSriastradh 306503b705cfSriastradhstatic void kgem_bo_unref(struct kgem *kgem, struct kgem_bo *bo) 306603b705cfSriastradh{ 306703b705cfSriastradh assert(bo->refcnt); 306803b705cfSriastradh if (--bo->refcnt == 0) 306903b705cfSriastradh __kgem_bo_destroy(kgem, bo); 307003b705cfSriastradh} 307103b705cfSriastradh 307203b705cfSriastradhstatic void kgem_buffer_release(struct kgem *kgem, struct kgem_buffer *bo) 307303b705cfSriastradh{ 30749a906b70Schristos assert(bo->base.io); 307503b705cfSriastradh while (!list_is_empty(&bo->base.vma)) { 307603b705cfSriastradh struct kgem_bo *cached; 307703b705cfSriastradh 307803b705cfSriastradh cached = list_first_entry(&bo->base.vma, struct kgem_bo, vma); 307903b705cfSriastradh assert(cached->proxy == &bo->base); 30809a906b70Schristos assert(cached != &bo->base); 308103b705cfSriastradh list_del(&cached->vma); 308203b705cfSriastradh 30839a906b70Schristos assert(*(struct kgem_bo **)cached->map__gtt == cached); 30849a906b70Schristos *(struct kgem_bo **)cached->map__gtt = NULL; 30859a906b70Schristos cached->map__gtt = NULL; 308603b705cfSriastradh 308703b705cfSriastradh kgem_bo_destroy(kgem, cached); 308803b705cfSriastradh } 308903b705cfSriastradh} 309003b705cfSriastradh 30919a906b70Schristosvoid kgem_retire__buffers(struct kgem *kgem) 309203b705cfSriastradh{ 309303b705cfSriastradh while (!list_is_empty(&kgem->active_buffers)) { 309403b705cfSriastradh struct kgem_buffer *bo = 309503b705cfSriastradh list_last_entry(&kgem->active_buffers, 309603b705cfSriastradh struct kgem_buffer, 309703b705cfSriastradh base.list); 309803b705cfSriastradh 30999a906b70Schristos DBG(("%s: handle=%d, busy? %d [%d]\n", 31009a906b70Schristos __FUNCTION__, bo->base.handle, bo->base.rq != NULL, bo->base.exec != NULL)); 31019a906b70Schristos 31029a906b70Schristos assert(bo->base.exec == NULL || RQ(bo->base.rq) == kgem->next_request); 310303b705cfSriastradh if (bo->base.rq) 310403b705cfSriastradh break; 310503b705cfSriastradh 310603b705cfSriastradh DBG(("%s: releasing upload cache for handle=%d? %d\n", 310703b705cfSriastradh __FUNCTION__, bo->base.handle, !list_is_empty(&bo->base.vma))); 310803b705cfSriastradh list_del(&bo->base.list); 310903b705cfSriastradh kgem_buffer_release(kgem, bo); 311003b705cfSriastradh kgem_bo_unref(kgem, &bo->base); 311103b705cfSriastradh } 311203b705cfSriastradh} 311303b705cfSriastradh 311403b705cfSriastradhstatic bool kgem_retire__flushing(struct kgem *kgem) 311503b705cfSriastradh{ 311603b705cfSriastradh struct kgem_bo *bo, *next; 311703b705cfSriastradh bool retired = false; 311803b705cfSriastradh 311903b705cfSriastradh list_for_each_entry_safe(bo, next, &kgem->flushing, request) { 31209a906b70Schristos assert(RQ(bo->rq) == (void *)kgem); 312103b705cfSriastradh assert(bo->exec == NULL); 312203b705cfSriastradh 312303b705cfSriastradh if (__kgem_busy(kgem, bo->handle)) 312403b705cfSriastradh break; 312503b705cfSriastradh 312603b705cfSriastradh __kgem_bo_clear_busy(bo); 312703b705cfSriastradh 312803b705cfSriastradh if (bo->refcnt) 312903b705cfSriastradh continue; 313003b705cfSriastradh 31319a906b70Schristos retired |= kgem_bo_move_to_cache(kgem, bo); 313203b705cfSriastradh } 313303b705cfSriastradh#if HAS_DEBUG_FULL 313403b705cfSriastradh { 313503b705cfSriastradh int count = 0; 313603b705cfSriastradh list_for_each_entry(bo, &kgem->flushing, request) 313703b705cfSriastradh count++; 313863ef14f0Smrg DBG(("%s: %d bo on flushing list, retired? %d\n", __FUNCTION__, count, retired)); 313903b705cfSriastradh } 314003b705cfSriastradh#endif 314103b705cfSriastradh 314203b705cfSriastradh kgem->need_retire |= !list_is_empty(&kgem->flushing); 314303b705cfSriastradh 314403b705cfSriastradh return retired; 314503b705cfSriastradh} 314603b705cfSriastradh 314763ef14f0Smrgstatic bool __kgem_bo_flush(struct kgem *kgem, struct kgem_bo *bo) 314863ef14f0Smrg{ 314963ef14f0Smrg struct drm_i915_gem_busy busy; 315063ef14f0Smrg 315163ef14f0Smrg if (!bo->needs_flush) 315263ef14f0Smrg return false; 315363ef14f0Smrg 315463ef14f0Smrg bo->needs_flush = false; 315563ef14f0Smrg 315663ef14f0Smrg VG_CLEAR(busy); 315763ef14f0Smrg busy.handle = bo->handle; 315863ef14f0Smrg busy.busy = !kgem->wedged; 315963ef14f0Smrg (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy); 316063ef14f0Smrg DBG(("%s: handle=%d, busy=%d, wedged=%d\n", 316163ef14f0Smrg __FUNCTION__, bo->handle, busy.busy, kgem->wedged)); 316263ef14f0Smrg 316363ef14f0Smrg if (busy.busy == 0) 316463ef14f0Smrg return false; 316563ef14f0Smrg 316663ef14f0Smrg DBG(("%s: moving %d to flushing\n", 316763ef14f0Smrg __FUNCTION__, bo->handle)); 316863ef14f0Smrg list_add(&bo->request, &kgem->flushing); 316963ef14f0Smrg bo->rq = MAKE_REQUEST(kgem, !!(busy.busy & ~0x1ffff)); 317063ef14f0Smrg bo->needs_flush = busy.busy & 0xffff; 317163ef14f0Smrg kgem->need_retire = true; 317263ef14f0Smrg return true; 317363ef14f0Smrg} 317463ef14f0Smrg 317503b705cfSriastradhstatic bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq) 317603b705cfSriastradh{ 317703b705cfSriastradh bool retired = false; 317803b705cfSriastradh 317903b705cfSriastradh DBG(("%s: request %d complete\n", 318003b705cfSriastradh __FUNCTION__, rq->bo->handle)); 31819a906b70Schristos assert(RQ(rq->bo->rq) == rq); 318263ef14f0Smrg assert(rq != (struct kgem_request *)kgem); 318363ef14f0Smrg assert(rq != &kgem->static_request); 318403b705cfSriastradh 3185813957e3Ssnj if (rq == kgem->fence[rq->ring]) 3186813957e3Ssnj kgem->fence[rq->ring] = NULL; 3187813957e3Ssnj 318803b705cfSriastradh while (!list_is_empty(&rq->buffers)) { 318903b705cfSriastradh struct kgem_bo *bo; 319003b705cfSriastradh 319103b705cfSriastradh bo = list_first_entry(&rq->buffers, 319203b705cfSriastradh struct kgem_bo, 319303b705cfSriastradh request); 319403b705cfSriastradh 319503b705cfSriastradh assert(RQ(bo->rq) == rq); 319603b705cfSriastradh assert(bo->exec == NULL); 319703b705cfSriastradh assert(bo->domain == DOMAIN_GPU || bo->domain == DOMAIN_NONE); 319803b705cfSriastradh 319903b705cfSriastradh list_del(&bo->request); 320003b705cfSriastradh 320163ef14f0Smrg if (unlikely(__kgem_bo_flush(kgem, bo))) { 320263ef14f0Smrg assert(bo != rq->bo); 320363ef14f0Smrg DBG(("%s: movied %d to flushing\n", 320403b705cfSriastradh __FUNCTION__, bo->handle)); 320503b705cfSriastradh continue; 320603b705cfSriastradh } 320703b705cfSriastradh 320803b705cfSriastradh bo->domain = DOMAIN_NONE; 320903b705cfSriastradh bo->rq = NULL; 321003b705cfSriastradh if (bo->refcnt) 321103b705cfSriastradh continue; 321203b705cfSriastradh 32139a906b70Schristos retired |= kgem_bo_move_to_cache(kgem, bo); 321403b705cfSriastradh } 321503b705cfSriastradh 321603b705cfSriastradh assert(rq->bo->rq == NULL); 32179a906b70Schristos assert(rq->bo->exec == NULL); 321803b705cfSriastradh assert(list_is_empty(&rq->bo->request)); 32199a906b70Schristos assert(rq->bo->refcnt > 0); 322003b705cfSriastradh 322103b705cfSriastradh if (--rq->bo->refcnt == 0) { 322263ef14f0Smrg kgem_bo_move_to_inactive(kgem, rq->bo); 322363ef14f0Smrg retired = true; 322403b705cfSriastradh } 322503b705cfSriastradh 322603b705cfSriastradh __kgem_request_free(rq); 322703b705cfSriastradh return retired; 322803b705cfSriastradh} 322903b705cfSriastradh 323003b705cfSriastradhstatic bool kgem_retire__requests_ring(struct kgem *kgem, int ring) 323103b705cfSriastradh{ 323203b705cfSriastradh bool retired = false; 323303b705cfSriastradh 323463ef14f0Smrg assert(ring < ARRAY_SIZE(kgem->requests)); 323503b705cfSriastradh while (!list_is_empty(&kgem->requests[ring])) { 323603b705cfSriastradh struct kgem_request *rq; 323703b705cfSriastradh 323863ef14f0Smrg DBG(("%s: retiring ring %d\n", __FUNCTION__, ring)); 323963ef14f0Smrg 324003b705cfSriastradh rq = list_first_entry(&kgem->requests[ring], 324103b705cfSriastradh struct kgem_request, 324203b705cfSriastradh list); 32439a906b70Schristos assert(rq->ring == ring); 324463ef14f0Smrg assert(rq->bo); 324563ef14f0Smrg assert(RQ(rq->bo->rq) == rq); 324603b705cfSriastradh if (__kgem_busy(kgem, rq->bo->handle)) 324703b705cfSriastradh break; 324803b705cfSriastradh 324903b705cfSriastradh retired |= __kgem_retire_rq(kgem, rq); 325003b705cfSriastradh } 325103b705cfSriastradh 325203b705cfSriastradh#if HAS_DEBUG_FULL 325303b705cfSriastradh { 325403b705cfSriastradh struct kgem_bo *bo; 325503b705cfSriastradh int count = 0; 325603b705cfSriastradh 325703b705cfSriastradh list_for_each_entry(bo, &kgem->requests[ring], request) 325803b705cfSriastradh count++; 325903b705cfSriastradh 326003b705cfSriastradh bo = NULL; 326103b705cfSriastradh if (!list_is_empty(&kgem->requests[ring])) 326203b705cfSriastradh bo = list_first_entry(&kgem->requests[ring], 326303b705cfSriastradh struct kgem_request, 326403b705cfSriastradh list)->bo; 326503b705cfSriastradh 326663ef14f0Smrg DBG(("%s: ring=%d, %d outstanding requests, oldest=%d, retired? %d\n", 326763ef14f0Smrg __FUNCTION__, ring, count, bo ? bo->handle : 0, retired)); 326803b705cfSriastradh } 326903b705cfSriastradh#endif 327003b705cfSriastradh 327103b705cfSriastradh return retired; 327203b705cfSriastradh} 327303b705cfSriastradh 327403b705cfSriastradhstatic bool kgem_retire__requests(struct kgem *kgem) 327503b705cfSriastradh{ 327603b705cfSriastradh bool retired = false; 327703b705cfSriastradh int n; 327803b705cfSriastradh 327903b705cfSriastradh for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) { 328003b705cfSriastradh retired |= kgem_retire__requests_ring(kgem, n); 328103b705cfSriastradh kgem->need_retire |= !list_is_empty(&kgem->requests[n]); 328203b705cfSriastradh } 328303b705cfSriastradh 328403b705cfSriastradh return retired; 328503b705cfSriastradh} 328603b705cfSriastradh 328703b705cfSriastradhbool kgem_retire(struct kgem *kgem) 328803b705cfSriastradh{ 328903b705cfSriastradh bool retired = false; 329003b705cfSriastradh 32919a906b70Schristos DBG(("%s, need_retire?=%d\n", __FUNCTION__, kgem->need_retire)); 329203b705cfSriastradh 329303b705cfSriastradh kgem->need_retire = false; 329403b705cfSriastradh 329503b705cfSriastradh retired |= kgem_retire__flushing(kgem); 329603b705cfSriastradh retired |= kgem_retire__requests(kgem); 329703b705cfSriastradh 329803b705cfSriastradh DBG(("%s -- retired=%d, need_retire=%d\n", 329903b705cfSriastradh __FUNCTION__, retired, kgem->need_retire)); 330003b705cfSriastradh 330103b705cfSriastradh kgem->retire(kgem); 330203b705cfSriastradh 330303b705cfSriastradh return retired; 330403b705cfSriastradh} 330503b705cfSriastradh 330603b705cfSriastradhbool __kgem_ring_is_idle(struct kgem *kgem, int ring) 330703b705cfSriastradh{ 330803b705cfSriastradh struct kgem_request *rq; 330903b705cfSriastradh 33109a906b70Schristos assert(ring < ARRAY_SIZE(kgem->requests)); 331103b705cfSriastradh assert(!list_is_empty(&kgem->requests[ring])); 331203b705cfSriastradh 3313813957e3Ssnj rq = kgem->fence[ring]; 3314813957e3Ssnj if (rq) { 3315813957e3Ssnj struct kgem_request *tmp; 3316813957e3Ssnj 3317813957e3Ssnj if (__kgem_busy(kgem, rq->bo->handle)) { 3318813957e3Ssnj DBG(("%s: last fence handle=%d still busy\n", 3319813957e3Ssnj __FUNCTION__, rq->bo->handle)); 3320813957e3Ssnj return false; 3321813957e3Ssnj } 3322813957e3Ssnj 3323813957e3Ssnj do { 3324813957e3Ssnj tmp = list_first_entry(&kgem->requests[ring], 3325813957e3Ssnj struct kgem_request, 3326813957e3Ssnj list); 3327813957e3Ssnj assert(tmp->ring == ring); 3328813957e3Ssnj __kgem_retire_rq(kgem, tmp); 3329813957e3Ssnj } while (tmp != rq); 3330813957e3Ssnj 3331813957e3Ssnj assert(kgem->fence[ring] == NULL); 3332813957e3Ssnj if (list_is_empty(&kgem->requests[ring])) 3333813957e3Ssnj return true; 3334813957e3Ssnj } 3335813957e3Ssnj 333603b705cfSriastradh rq = list_last_entry(&kgem->requests[ring], 333703b705cfSriastradh struct kgem_request, list); 33389a906b70Schristos assert(rq->ring == ring); 333963ef14f0Smrg assert(rq->bo); 334063ef14f0Smrg assert(RQ(rq->bo->rq) == rq); 334103b705cfSriastradh if (__kgem_busy(kgem, rq->bo->handle)) { 334203b705cfSriastradh DBG(("%s: last requests handle=%d still busy\n", 334303b705cfSriastradh __FUNCTION__, rq->bo->handle)); 3344813957e3Ssnj kgem->fence[ring] = rq; 334503b705cfSriastradh return false; 334603b705cfSriastradh } 334703b705cfSriastradh 334803b705cfSriastradh DBG(("%s: ring=%d idle (handle=%d)\n", 334903b705cfSriastradh __FUNCTION__, ring, rq->bo->handle)); 335003b705cfSriastradh 3351813957e3Ssnj while (!list_is_empty(&kgem->requests[ring])) { 3352813957e3Ssnj rq = list_first_entry(&kgem->requests[ring], 3353813957e3Ssnj struct kgem_request, 3354813957e3Ssnj list); 3355813957e3Ssnj assert(rq->ring == ring); 3356813957e3Ssnj __kgem_retire_rq(kgem, rq); 3357813957e3Ssnj } 33589a906b70Schristos 335903b705cfSriastradh return true; 336003b705cfSriastradh} 336103b705cfSriastradh 336263ef14f0Smrgbool __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo) 3363813957e3Ssnj{ 336463ef14f0Smrg struct kgem_request * const rq = RQ(bo->rq), *tmp; 336563ef14f0Smrg struct list *requests = &kgem->requests[rq->ring]; 336663ef14f0Smrg 336763ef14f0Smrg DBG(("%s(handle=%d, ring=%d)\n", __FUNCTION__, bo->handle, rq->ring)); 3368813957e3Ssnj 3369813957e3Ssnj assert(rq != &kgem->static_request); 3370813957e3Ssnj if (rq == (struct kgem_request *)kgem) { 3371813957e3Ssnj __kgem_bo_clear_busy(bo); 337263ef14f0Smrg return false; 3373813957e3Ssnj } 3374813957e3Ssnj 337563ef14f0Smrg assert(rq->ring < ARRAY_SIZE(kgem->requests)); 3376813957e3Ssnj do { 3377813957e3Ssnj tmp = list_first_entry(requests, struct kgem_request, list); 3378813957e3Ssnj assert(tmp->ring == rq->ring); 3379813957e3Ssnj __kgem_retire_rq(kgem, tmp); 3380813957e3Ssnj } while (tmp != rq); 338163ef14f0Smrg 338263ef14f0Smrg assert(bo->needs_flush || bo->rq == NULL); 338363ef14f0Smrg assert(bo->needs_flush || list_is_empty(&bo->request)); 338463ef14f0Smrg assert(bo->needs_flush || bo->domain == DOMAIN_NONE); 338563ef14f0Smrg return bo->rq; 3386813957e3Ssnj} 3387813957e3Ssnj 33889a906b70Schristos#if 0 33899a906b70Schristosstatic void kgem_commit__check_reloc(struct kgem *kgem) 33909a906b70Schristos{ 33919a906b70Schristos struct kgem_request *rq = kgem->next_request; 33929a906b70Schristos struct kgem_bo *bo; 33939a906b70Schristos bool has_64bit = kgem->gen >= 0100; 33949a906b70Schristos int i; 33959a906b70Schristos 33969a906b70Schristos for (i = 0; i < kgem->nreloc; i++) { 33979a906b70Schristos list_for_each_entry(bo, &rq->buffers, request) { 33989a906b70Schristos if (bo->target_handle == kgem->reloc[i].target_handle) { 33999a906b70Schristos uint64_t value = 0; 34009a906b70Schristos gem_read(kgem->fd, rq->bo->handle, &value, kgem->reloc[i].offset, has_64bit ? 8 : 4); 34019a906b70Schristos assert(bo->exec->offset == -1 || value == bo->exec->offset + (int)kgem->reloc[i].delta); 34029a906b70Schristos break; 34039a906b70Schristos } 34049a906b70Schristos } 34059a906b70Schristos } 34069a906b70Schristos} 34079a906b70Schristos#else 34089a906b70Schristos#define kgem_commit__check_reloc(kgem) 34099a906b70Schristos#endif 34109a906b70Schristos 34119a906b70Schristos#ifndef NDEBUG 34129a906b70Schristosstatic void kgem_commit__check_buffers(struct kgem *kgem) 34139a906b70Schristos{ 34149a906b70Schristos struct kgem_buffer *bo; 34159a906b70Schristos 34169a906b70Schristos list_for_each_entry(bo, &kgem->active_buffers, base.list) 34179a906b70Schristos assert(bo->base.exec == NULL); 34189a906b70Schristos} 34199a906b70Schristos#else 34209a906b70Schristos#define kgem_commit__check_buffers(kgem) 34219a906b70Schristos#endif 34229a906b70Schristos 342303b705cfSriastradhstatic void kgem_commit(struct kgem *kgem) 342403b705cfSriastradh{ 342503b705cfSriastradh struct kgem_request *rq = kgem->next_request; 342603b705cfSriastradh struct kgem_bo *bo, *next; 342703b705cfSriastradh 34289a906b70Schristos kgem_commit__check_reloc(kgem); 34299a906b70Schristos 343003b705cfSriastradh list_for_each_entry_safe(bo, next, &rq->buffers, request) { 343103b705cfSriastradh assert(next->request.prev == &bo->request); 343203b705cfSriastradh 343303b705cfSriastradh DBG(("%s: release handle=%d (proxy? %d), dirty? %d flush? %d, snoop? %d -> offset=%x\n", 343403b705cfSriastradh __FUNCTION__, bo->handle, bo->proxy != NULL, 343503b705cfSriastradh bo->gpu_dirty, bo->needs_flush, bo->snoop, 343603b705cfSriastradh (unsigned)bo->exec->offset)); 343703b705cfSriastradh 343803b705cfSriastradh assert(bo->exec); 343903b705cfSriastradh assert(bo->proxy == NULL || bo->exec == &_kgem_dummy_exec); 344003b705cfSriastradh assert(RQ(bo->rq) == rq || (RQ(bo->proxy->rq) == rq)); 344103b705cfSriastradh 344203b705cfSriastradh bo->presumed_offset = bo->exec->offset; 344303b705cfSriastradh bo->exec = NULL; 344403b705cfSriastradh bo->target_handle = -1; 344503b705cfSriastradh 344603b705cfSriastradh if (!bo->refcnt && !bo->reusable) { 344703b705cfSriastradh assert(!bo->snoop); 34489a906b70Schristos assert(!bo->proxy); 344903b705cfSriastradh kgem_bo_free(kgem, bo); 345003b705cfSriastradh continue; 345103b705cfSriastradh } 345203b705cfSriastradh 345303b705cfSriastradh bo->binding.offset = 0; 345403b705cfSriastradh bo->domain = DOMAIN_GPU; 345503b705cfSriastradh bo->gpu_dirty = false; 345663ef14f0Smrg bo->gtt_dirty = false; 345703b705cfSriastradh 345803b705cfSriastradh if (bo->proxy) { 345903b705cfSriastradh /* proxies are not used for domain tracking */ 346003b705cfSriastradh __kgem_bo_clear_busy(bo); 346103b705cfSriastradh } 346203b705cfSriastradh 34639a906b70Schristos kgem->scanout_busy |= bo->scanout && bo->needs_flush; 346403b705cfSriastradh } 346503b705cfSriastradh 346603b705cfSriastradh if (rq == &kgem->static_request) { 346703b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 346803b705cfSriastradh 346903b705cfSriastradh DBG(("%s: syncing due to allocation failure\n", __FUNCTION__)); 347003b705cfSriastradh 347103b705cfSriastradh VG_CLEAR(set_domain); 347203b705cfSriastradh set_domain.handle = rq->bo->handle; 347303b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_GTT; 347403b705cfSriastradh set_domain.write_domain = I915_GEM_DOMAIN_GTT; 34759a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 347603b705cfSriastradh DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 347703b705cfSriastradh kgem_throttle(kgem); 347803b705cfSriastradh } 347903b705cfSriastradh 348063ef14f0Smrg while (!list_is_empty(&rq->buffers)) { 348163ef14f0Smrg bo = list_first_entry(&rq->buffers, 348263ef14f0Smrg struct kgem_bo, 348363ef14f0Smrg request); 348463ef14f0Smrg 348563ef14f0Smrg assert(RQ(bo->rq) == rq); 348663ef14f0Smrg assert(bo->exec == NULL); 348763ef14f0Smrg assert(bo->domain == DOMAIN_GPU); 348863ef14f0Smrg 348963ef14f0Smrg list_del(&bo->request); 349063ef14f0Smrg bo->domain = DOMAIN_NONE; 349163ef14f0Smrg bo->rq = NULL; 349263ef14f0Smrg 349363ef14f0Smrg if (bo->refcnt == 0) 349463ef14f0Smrg _kgem_bo_destroy(kgem, bo); 349563ef14f0Smrg } 349663ef14f0Smrg 349703b705cfSriastradh kgem_retire(kgem); 349803b705cfSriastradh assert(list_is_empty(&rq->buffers)); 349903b705cfSriastradh 35009a906b70Schristos assert(rq->bo->map__gtt == NULL); 3501813957e3Ssnj assert(rq->bo->map__wc == NULL); 35029a906b70Schristos assert(rq->bo->map__cpu == NULL); 350303b705cfSriastradh gem_close(kgem->fd, rq->bo->handle); 350403b705cfSriastradh kgem_cleanup_cache(kgem); 350503b705cfSriastradh } else { 350663ef14f0Smrg assert(rq != (struct kgem_request *)kgem); 35079a906b70Schristos assert(rq->ring < ARRAY_SIZE(kgem->requests)); 350863ef14f0Smrg assert(rq->bo); 350903b705cfSriastradh list_add_tail(&rq->list, &kgem->requests[rq->ring]); 351003b705cfSriastradh kgem->need_throttle = kgem->need_retire = 1; 3511813957e3Ssnj 3512813957e3Ssnj if (kgem->fence[rq->ring] == NULL && 3513813957e3Ssnj __kgem_busy(kgem, rq->bo->handle)) 3514813957e3Ssnj kgem->fence[rq->ring] = rq; 351503b705cfSriastradh } 351603b705cfSriastradh 351703b705cfSriastradh kgem->next_request = NULL; 35189a906b70Schristos 35199a906b70Schristos kgem_commit__check_buffers(kgem); 352003b705cfSriastradh} 352103b705cfSriastradh 352203b705cfSriastradhstatic void kgem_close_list(struct kgem *kgem, struct list *head) 352303b705cfSriastradh{ 352403b705cfSriastradh while (!list_is_empty(head)) 352503b705cfSriastradh kgem_bo_free(kgem, list_first_entry(head, struct kgem_bo, list)); 352603b705cfSriastradh} 352703b705cfSriastradh 352803b705cfSriastradhstatic void kgem_close_inactive(struct kgem *kgem) 352903b705cfSriastradh{ 353003b705cfSriastradh unsigned int i; 353103b705cfSriastradh 353263ef14f0Smrg for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) { 353303b705cfSriastradh kgem_close_list(kgem, &kgem->inactive[i]); 353463ef14f0Smrg assert(list_is_empty(&kgem->inactive[i])); 353563ef14f0Smrg } 353603b705cfSriastradh} 353703b705cfSriastradh 353803b705cfSriastradhstatic void kgem_finish_buffers(struct kgem *kgem) 353903b705cfSriastradh{ 354003b705cfSriastradh struct kgem_buffer *bo, *next; 354103b705cfSriastradh 354203b705cfSriastradh list_for_each_entry_safe(bo, next, &kgem->batch_buffers, base.list) { 35439a906b70Schristos DBG(("%s: buffer handle=%d, used=%d, exec?=%d, write=%d, mmapped=%s, refcnt=%d\n", 354403b705cfSriastradh __FUNCTION__, bo->base.handle, bo->used, bo->base.exec!=NULL, 35459a906b70Schristos bo->write, bo->mmapped == MMAPPED_CPU ? "cpu" : bo->mmapped == MMAPPED_GTT ? "gtt" : "no", 35469a906b70Schristos bo->base.refcnt)); 354703b705cfSriastradh 354803b705cfSriastradh assert(next->base.list.prev == &bo->base.list); 354903b705cfSriastradh assert(bo->base.io); 355003b705cfSriastradh assert(bo->base.refcnt >= 1); 355103b705cfSriastradh 35529a906b70Schristos if (bo->base.refcnt > 1 && !bo->base.exec) { 35539a906b70Schristos DBG(("%s: skipping unattached handle=%d, used=%d, refcnt=%d\n", 35549a906b70Schristos __FUNCTION__, bo->base.handle, bo->used, bo->base.refcnt)); 355503b705cfSriastradh continue; 355603b705cfSriastradh } 355703b705cfSriastradh 355803b705cfSriastradh if (!bo->write) { 355903b705cfSriastradh assert(bo->base.exec || bo->base.refcnt > 1); 356003b705cfSriastradh goto decouple; 356103b705cfSriastradh } 356203b705cfSriastradh 356303b705cfSriastradh if (bo->mmapped) { 35649a906b70Schristos uint32_t used; 356503b705cfSriastradh 356603b705cfSriastradh assert(!bo->need_io); 356703b705cfSriastradh 356803b705cfSriastradh used = ALIGN(bo->used, PAGE_SIZE); 356903b705cfSriastradh if (!DBG_NO_UPLOAD_ACTIVE && 357003b705cfSriastradh used + PAGE_SIZE <= bytes(&bo->base) && 35719a906b70Schristos (kgem->has_llc || bo->mmapped == MMAPPED_GTT || bo->base.snoop)) { 35729a906b70Schristos DBG(("%s: retaining upload buffer (%d/%d): used=%d, refcnt=%d\n", 35739a906b70Schristos __FUNCTION__, bo->used, bytes(&bo->base), used, bo->base.refcnt)); 357403b705cfSriastradh bo->used = used; 357503b705cfSriastradh list_move(&bo->base.list, 357603b705cfSriastradh &kgem->active_buffers); 35779a906b70Schristos kgem->need_retire = true; 357803b705cfSriastradh continue; 357903b705cfSriastradh } 358003b705cfSriastradh DBG(("%s: discarding mmapped buffer, used=%d, map type=%d\n", 35819a906b70Schristos __FUNCTION__, bo->used, bo->mmapped)); 358203b705cfSriastradh goto decouple; 358303b705cfSriastradh } 358403b705cfSriastradh 35859a906b70Schristos if (!bo->used || !bo->base.exec) { 358603b705cfSriastradh /* Unless we replace the handle in the execbuffer, 358703b705cfSriastradh * then this bo will become active. So decouple it 358803b705cfSriastradh * from the buffer list and track it in the normal 358903b705cfSriastradh * manner. 359003b705cfSriastradh */ 359103b705cfSriastradh goto decouple; 359203b705cfSriastradh } 359303b705cfSriastradh 359403b705cfSriastradh assert(bo->need_io); 359503b705cfSriastradh assert(bo->base.rq == MAKE_REQUEST(kgem->next_request, kgem->ring)); 359603b705cfSriastradh assert(bo->base.domain != DOMAIN_GPU); 359703b705cfSriastradh 359803b705cfSriastradh if (bo->base.refcnt == 1 && 359903b705cfSriastradh bo->base.size.pages.count > 1 && 360003b705cfSriastradh bo->used < bytes(&bo->base) / 2) { 360103b705cfSriastradh struct kgem_bo *shrink; 360203b705cfSriastradh unsigned alloc = NUM_PAGES(bo->used); 360303b705cfSriastradh 360403b705cfSriastradh shrink = search_snoop_cache(kgem, alloc, 360503b705cfSriastradh CREATE_INACTIVE | CREATE_NO_RETIRE); 360603b705cfSriastradh if (shrink) { 360703b705cfSriastradh void *map; 360803b705cfSriastradh int n; 360903b705cfSriastradh 361003b705cfSriastradh DBG(("%s: used=%d, shrinking %d to %d, handle %d to %d\n", 361103b705cfSriastradh __FUNCTION__, 361203b705cfSriastradh bo->used, bytes(&bo->base), bytes(shrink), 361303b705cfSriastradh bo->base.handle, shrink->handle)); 361403b705cfSriastradh 361503b705cfSriastradh assert(bo->used <= bytes(shrink)); 361603b705cfSriastradh map = kgem_bo_map__cpu(kgem, shrink); 361703b705cfSriastradh if (map) { 361803b705cfSriastradh memcpy(map, bo->mem, bo->used); 361903b705cfSriastradh 362003b705cfSriastradh shrink->target_handle = 362103b705cfSriastradh kgem->has_handle_lut ? bo->base.target_handle : shrink->handle; 362203b705cfSriastradh for (n = 0; n < kgem->nreloc; n++) { 362303b705cfSriastradh if (kgem->reloc[n].target_handle == bo->base.target_handle) { 362463ef14f0Smrg uint64_t addr = (int)kgem->reloc[n].delta + shrink->presumed_offset; 362563ef14f0Smrg kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = addr; 362663ef14f0Smrg if (kgem->gen >= 0100) 362763ef14f0Smrg kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0]) + 1] = addr >> 32; 362863ef14f0Smrg 362903b705cfSriastradh kgem->reloc[n].target_handle = shrink->target_handle; 363003b705cfSriastradh kgem->reloc[n].presumed_offset = shrink->presumed_offset; 363103b705cfSriastradh } 363203b705cfSriastradh } 363303b705cfSriastradh 363403b705cfSriastradh bo->base.exec->handle = shrink->handle; 363503b705cfSriastradh bo->base.exec->offset = shrink->presumed_offset; 363603b705cfSriastradh shrink->exec = bo->base.exec; 363703b705cfSriastradh shrink->rq = bo->base.rq; 363803b705cfSriastradh list_replace(&bo->base.request, 363903b705cfSriastradh &shrink->request); 364003b705cfSriastradh list_init(&bo->base.request); 364103b705cfSriastradh shrink->needs_flush = bo->base.gpu_dirty; 364203b705cfSriastradh 364303b705cfSriastradh bo->base.exec = NULL; 364403b705cfSriastradh bo->base.rq = NULL; 364503b705cfSriastradh bo->base.gpu_dirty = false; 364603b705cfSriastradh bo->base.needs_flush = false; 364703b705cfSriastradh bo->used = 0; 364803b705cfSriastradh 364903b705cfSriastradh goto decouple; 365003b705cfSriastradh } 365103b705cfSriastradh 365203b705cfSriastradh __kgem_bo_destroy(kgem, shrink); 365303b705cfSriastradh } 365403b705cfSriastradh 365503b705cfSriastradh shrink = search_linear_cache(kgem, alloc, 365603b705cfSriastradh CREATE_INACTIVE | CREATE_NO_RETIRE); 365703b705cfSriastradh if (shrink) { 365803b705cfSriastradh int n; 365903b705cfSriastradh 366003b705cfSriastradh DBG(("%s: used=%d, shrinking %d to %d, handle %d to %d\n", 366103b705cfSriastradh __FUNCTION__, 366203b705cfSriastradh bo->used, bytes(&bo->base), bytes(shrink), 366303b705cfSriastradh bo->base.handle, shrink->handle)); 366403b705cfSriastradh 366503b705cfSriastradh assert(bo->used <= bytes(shrink)); 36669a906b70Schristos if (gem_write__cachealigned(kgem->fd, shrink->handle, 36679a906b70Schristos 0, bo->used, bo->mem) == 0) { 366803b705cfSriastradh shrink->target_handle = 366903b705cfSriastradh kgem->has_handle_lut ? bo->base.target_handle : shrink->handle; 367003b705cfSriastradh for (n = 0; n < kgem->nreloc; n++) { 367103b705cfSriastradh if (kgem->reloc[n].target_handle == bo->base.target_handle) { 367263ef14f0Smrg uint64_t addr = (int)kgem->reloc[n].delta + shrink->presumed_offset; 367363ef14f0Smrg kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = addr; 367463ef14f0Smrg if (kgem->gen >= 0100) 367563ef14f0Smrg kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0]) + 1] = addr >> 32; 367663ef14f0Smrg 367703b705cfSriastradh kgem->reloc[n].target_handle = shrink->target_handle; 367803b705cfSriastradh kgem->reloc[n].presumed_offset = shrink->presumed_offset; 367903b705cfSriastradh } 368003b705cfSriastradh } 368103b705cfSriastradh 368203b705cfSriastradh bo->base.exec->handle = shrink->handle; 368303b705cfSriastradh bo->base.exec->offset = shrink->presumed_offset; 368403b705cfSriastradh shrink->exec = bo->base.exec; 368503b705cfSriastradh shrink->rq = bo->base.rq; 368603b705cfSriastradh list_replace(&bo->base.request, 368703b705cfSriastradh &shrink->request); 368803b705cfSriastradh list_init(&bo->base.request); 368903b705cfSriastradh shrink->needs_flush = bo->base.gpu_dirty; 369003b705cfSriastradh 369103b705cfSriastradh bo->base.exec = NULL; 369203b705cfSriastradh bo->base.rq = NULL; 369303b705cfSriastradh bo->base.gpu_dirty = false; 369403b705cfSriastradh bo->base.needs_flush = false; 369503b705cfSriastradh bo->used = 0; 369603b705cfSriastradh 369703b705cfSriastradh goto decouple; 369803b705cfSriastradh } 369903b705cfSriastradh 370003b705cfSriastradh __kgem_bo_destroy(kgem, shrink); 370103b705cfSriastradh } 370203b705cfSriastradh } 370303b705cfSriastradh 370403b705cfSriastradh DBG(("%s: handle=%d, uploading %d/%d\n", 370503b705cfSriastradh __FUNCTION__, bo->base.handle, bo->used, bytes(&bo->base))); 370603b705cfSriastradh ASSERT_IDLE(kgem, bo->base.handle); 370703b705cfSriastradh assert(bo->used <= bytes(&bo->base)); 37089a906b70Schristos gem_write__cachealigned(kgem->fd, bo->base.handle, 37099a906b70Schristos 0, bo->used, bo->mem); 371003b705cfSriastradh bo->need_io = 0; 371103b705cfSriastradh 371203b705cfSriastradhdecouple: 371303b705cfSriastradh DBG(("%s: releasing handle=%d\n", 371403b705cfSriastradh __FUNCTION__, bo->base.handle)); 371503b705cfSriastradh list_del(&bo->base.list); 371603b705cfSriastradh kgem_bo_unref(kgem, &bo->base); 371703b705cfSriastradh } 371803b705cfSriastradh} 371903b705cfSriastradh 372003b705cfSriastradhstatic void kgem_cleanup(struct kgem *kgem) 372103b705cfSriastradh{ 372203b705cfSriastradh int n; 372303b705cfSriastradh 372403b705cfSriastradh for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) { 372503b705cfSriastradh while (!list_is_empty(&kgem->requests[n])) { 372603b705cfSriastradh struct kgem_request *rq; 372703b705cfSriastradh 372803b705cfSriastradh rq = list_first_entry(&kgem->requests[n], 372903b705cfSriastradh struct kgem_request, 373003b705cfSriastradh list); 37319a906b70Schristos assert(rq->ring == n); 373203b705cfSriastradh while (!list_is_empty(&rq->buffers)) { 373303b705cfSriastradh struct kgem_bo *bo; 373403b705cfSriastradh 373503b705cfSriastradh bo = list_first_entry(&rq->buffers, 373603b705cfSriastradh struct kgem_bo, 373703b705cfSriastradh request); 373803b705cfSriastradh 373903b705cfSriastradh bo->exec = NULL; 374003b705cfSriastradh bo->gpu_dirty = false; 374103b705cfSriastradh __kgem_bo_clear_busy(bo); 374203b705cfSriastradh if (bo->refcnt == 0) 374303b705cfSriastradh kgem_bo_free(kgem, bo); 374403b705cfSriastradh } 374503b705cfSriastradh 374663ef14f0Smrg if (--rq->bo->refcnt == 0) 374763ef14f0Smrg kgem_bo_free(kgem, rq->bo); 374863ef14f0Smrg 374903b705cfSriastradh __kgem_request_free(rq); 375003b705cfSriastradh } 375103b705cfSriastradh } 375203b705cfSriastradh 375303b705cfSriastradh kgem_close_inactive(kgem); 375403b705cfSriastradh} 375503b705cfSriastradh 3756813957e3Ssnjstatic int 3757813957e3Ssnjkgem_batch_write(struct kgem *kgem, 3758813957e3Ssnj struct kgem_bo *bo, 3759813957e3Ssnj uint32_t size) 376003b705cfSriastradh{ 3761813957e3Ssnj char *ptr; 376203b705cfSriastradh int ret; 376303b705cfSriastradh 376463ef14f0Smrg assert(bo->exec == NULL); 376563ef14f0Smrg assert(bo->rq == NULL); 376663ef14f0Smrg assert(!__kgem_busy(kgem, bo->handle)); 376703b705cfSriastradh 37689a906b70Schristos#if DBG_NO_EXEC 37699a906b70Schristos { 37709a906b70Schristos uint32_t batch[] = { MI_BATCH_BUFFER_END, 0}; 3771813957e3Ssnj return gem_write(kgem->fd, bo->handle, 0, sizeof(batch), batch); 37729a906b70Schristos } 37739a906b70Schristos#endif 37749a906b70Schristos 3775813957e3Ssnj assert(!bo->scanout); 37769a906b70Schristosretry: 3777813957e3Ssnj ptr = NULL; 3778813957e3Ssnj if (bo->domain == DOMAIN_CPU || kgem->has_llc) { 3779813957e3Ssnj ptr = bo->map__cpu; 3780813957e3Ssnj if (ptr == NULL) 3781813957e3Ssnj ptr = __kgem_bo_map__cpu(kgem, bo); 3782813957e3Ssnj } else if (kgem->has_wc_mmap) { 3783813957e3Ssnj ptr = bo->map__wc; 3784813957e3Ssnj if (ptr == NULL) 3785813957e3Ssnj ptr = __kgem_bo_map__wc(kgem, bo); 3786813957e3Ssnj } 3787813957e3Ssnj if (ptr) { 3788813957e3Ssnj memcpy(ptr, kgem->batch, sizeof(uint32_t)*kgem->nbatch); 3789813957e3Ssnj if (kgem->surface != kgem->batch_size) { 3790813957e3Ssnj ret = PAGE_ALIGN(sizeof(uint32_t) * kgem->batch_size); 3791813957e3Ssnj ret -= sizeof(uint32_t) * kgem->surface; 3792813957e3Ssnj ptr += size - ret; 3793813957e3Ssnj memcpy(ptr, kgem->batch + kgem->surface, 3794813957e3Ssnj (kgem->batch_size - kgem->surface)*sizeof(uint32_t)); 3795813957e3Ssnj } 3796813957e3Ssnj return 0; 3797813957e3Ssnj } 3798813957e3Ssnj 379903b705cfSriastradh /* If there is no surface data, just upload the batch */ 38009a906b70Schristos if (kgem->surface == kgem->batch_size) { 3801813957e3Ssnj if ((ret = gem_write__cachealigned(kgem->fd, bo->handle, 38029a906b70Schristos 0, sizeof(uint32_t)*kgem->nbatch, 38039a906b70Schristos kgem->batch)) == 0) 38049a906b70Schristos return 0; 38059a906b70Schristos 38069a906b70Schristos goto expire; 38079a906b70Schristos } 380803b705cfSriastradh 380903b705cfSriastradh /* Are the batch pages conjoint with the surface pages? */ 381003b705cfSriastradh if (kgem->surface < kgem->nbatch + PAGE_SIZE/sizeof(uint32_t)) { 381103b705cfSriastradh assert(size == PAGE_ALIGN(kgem->batch_size*sizeof(uint32_t))); 3812813957e3Ssnj if ((ret = gem_write__cachealigned(kgem->fd, bo->handle, 38139a906b70Schristos 0, kgem->batch_size*sizeof(uint32_t), 38149a906b70Schristos kgem->batch)) == 0) 38159a906b70Schristos return 0; 38169a906b70Schristos 38179a906b70Schristos goto expire; 381803b705cfSriastradh } 381903b705cfSriastradh 382003b705cfSriastradh /* Disjoint surface/batch, upload separately */ 3821813957e3Ssnj if ((ret = gem_write__cachealigned(kgem->fd, bo->handle, 38229a906b70Schristos 0, sizeof(uint32_t)*kgem->nbatch, 38239a906b70Schristos kgem->batch))) 38249a906b70Schristos goto expire; 382503b705cfSriastradh 382603b705cfSriastradh ret = PAGE_ALIGN(sizeof(uint32_t) * kgem->batch_size); 382703b705cfSriastradh ret -= sizeof(uint32_t) * kgem->surface; 382803b705cfSriastradh assert(size-ret >= kgem->nbatch*sizeof(uint32_t)); 3829813957e3Ssnj if (gem_write(kgem->fd, bo->handle, 38309a906b70Schristos size - ret, (kgem->batch_size - kgem->surface)*sizeof(uint32_t), 38319a906b70Schristos kgem->batch + kgem->surface)) 38329a906b70Schristos goto expire; 38339a906b70Schristos 38349a906b70Schristos return 0; 38359a906b70Schristos 38369a906b70Schristosexpire: 38379a906b70Schristos assert(ret != EINVAL); 38389a906b70Schristos 38399a906b70Schristos (void)__kgem_throttle_retire(kgem, 0); 38409a906b70Schristos if (kgem_expire_cache(kgem)) 38419a906b70Schristos goto retry; 38429a906b70Schristos 38439a906b70Schristos if (kgem_cleanup_cache(kgem)) 38449a906b70Schristos goto retry; 38459a906b70Schristos 38469a906b70Schristos ERR(("%s: failed to write batch (handle=%d): %d\n", 3847813957e3Ssnj __FUNCTION__, bo->handle, -ret)); 38489a906b70Schristos return ret; 384903b705cfSriastradh} 385003b705cfSriastradh 385103b705cfSriastradhvoid kgem_reset(struct kgem *kgem) 385203b705cfSriastradh{ 385303b705cfSriastradh if (kgem->next_request) { 385403b705cfSriastradh struct kgem_request *rq = kgem->next_request; 385503b705cfSriastradh 385603b705cfSriastradh while (!list_is_empty(&rq->buffers)) { 385703b705cfSriastradh struct kgem_bo *bo = 385803b705cfSriastradh list_first_entry(&rq->buffers, 385903b705cfSriastradh struct kgem_bo, 386003b705cfSriastradh request); 386103b705cfSriastradh list_del(&bo->request); 386203b705cfSriastradh 386303b705cfSriastradh assert(RQ(bo->rq) == rq); 386403b705cfSriastradh 386503b705cfSriastradh bo->binding.offset = 0; 386603b705cfSriastradh bo->exec = NULL; 386703b705cfSriastradh bo->target_handle = -1; 386803b705cfSriastradh bo->gpu_dirty = false; 386903b705cfSriastradh 387003b705cfSriastradh if (bo->needs_flush && __kgem_busy(kgem, bo->handle)) { 387103b705cfSriastradh assert(bo->domain == DOMAIN_GPU || bo->domain == DOMAIN_NONE); 387203b705cfSriastradh list_add(&bo->request, &kgem->flushing); 387303b705cfSriastradh bo->rq = (void *)kgem; 38749a906b70Schristos kgem->need_retire = true; 387503b705cfSriastradh } else 387603b705cfSriastradh __kgem_bo_clear_busy(bo); 387703b705cfSriastradh 387803b705cfSriastradh if (bo->refcnt || bo->rq) 387903b705cfSriastradh continue; 388003b705cfSriastradh 38819a906b70Schristos kgem_bo_move_to_cache(kgem, bo); 388203b705cfSriastradh } 388303b705cfSriastradh 388403b705cfSriastradh if (rq != &kgem->static_request) { 388503b705cfSriastradh list_init(&rq->list); 388603b705cfSriastradh __kgem_request_free(rq); 388703b705cfSriastradh } 388803b705cfSriastradh } 388903b705cfSriastradh 389003b705cfSriastradh kgem->nfence = 0; 389103b705cfSriastradh kgem->nexec = 0; 389203b705cfSriastradh kgem->nreloc = 0; 389303b705cfSriastradh kgem->nreloc__self = 0; 389403b705cfSriastradh kgem->aperture = 0; 389503b705cfSriastradh kgem->aperture_fenced = 0; 38969a906b70Schristos kgem->aperture_max_fence = 0; 389703b705cfSriastradh kgem->nbatch = 0; 389803b705cfSriastradh kgem->surface = kgem->batch_size; 389903b705cfSriastradh kgem->mode = KGEM_NONE; 39009a906b70Schristos kgem->needs_semaphore = false; 39019a906b70Schristos kgem->needs_reservation = false; 390203b705cfSriastradh kgem->flush = 0; 390303b705cfSriastradh kgem->batch_flags = kgem->batch_flags_base; 3904813957e3Ssnj assert(kgem->batch); 390503b705cfSriastradh 390603b705cfSriastradh kgem->next_request = __kgem_request_alloc(kgem); 390703b705cfSriastradh 390803b705cfSriastradh kgem_sna_reset(kgem); 390903b705cfSriastradh} 391003b705cfSriastradh 3911813957e3Ssnjstatic int compact_batch_surface(struct kgem *kgem, int *shrink) 391203b705cfSriastradh{ 3913813957e3Ssnj int size, n; 391403b705cfSriastradh 391503b705cfSriastradh if (!kgem->has_relaxed_delta) 39169a906b70Schristos return kgem->batch_size * sizeof(uint32_t); 391703b705cfSriastradh 391803b705cfSriastradh /* See if we can pack the contents into one or two pages */ 391903b705cfSriastradh n = ALIGN(kgem->batch_size, 1024); 392003b705cfSriastradh size = n - kgem->surface + kgem->nbatch; 392103b705cfSriastradh size = ALIGN(size, 1024); 392203b705cfSriastradh 3923813957e3Ssnj *shrink = (n - size) * sizeof(uint32_t); 392403b705cfSriastradh return size * sizeof(uint32_t); 392503b705cfSriastradh} 392603b705cfSriastradh 392763ef14f0Smrgstatic struct kgem_bo *first_available(struct kgem *kgem, struct list *list) 392863ef14f0Smrg{ 392963ef14f0Smrg struct kgem_bo *bo; 393063ef14f0Smrg 393163ef14f0Smrg list_for_each_entry(bo, list, list) { 393263ef14f0Smrg assert(bo->refcnt > 0); 393363ef14f0Smrg 393463ef14f0Smrg if (bo->rq) { 393563ef14f0Smrg assert(RQ(bo->rq)->bo == bo); 393663ef14f0Smrg if (__kgem_busy(kgem, bo->handle)) 393763ef14f0Smrg break; 393863ef14f0Smrg 393963ef14f0Smrg __kgem_retire_rq(kgem, RQ(bo->rq)); 394063ef14f0Smrg assert(bo->rq == NULL); 394163ef14f0Smrg } 394263ef14f0Smrg 394363ef14f0Smrg if (bo->refcnt > 1) 394463ef14f0Smrg continue; 394563ef14f0Smrg 394663ef14f0Smrg list_move_tail(&bo->list, list); 394763ef14f0Smrg return kgem_bo_reference(bo); 394863ef14f0Smrg } 394963ef14f0Smrg 395063ef14f0Smrg return NULL; 395163ef14f0Smrg} 395263ef14f0Smrg 395303b705cfSriastradhstatic struct kgem_bo * 3954813957e3Ssnjkgem_create_batch(struct kgem *kgem) 395503b705cfSriastradh{ 395603b705cfSriastradh struct kgem_bo *bo; 395763ef14f0Smrg int size, shrink = 0; 3958813957e3Ssnj 395963ef14f0Smrg#if !DBG_NO_SHRINK_BATCHES 3960813957e3Ssnj if (kgem->surface != kgem->batch_size) 3961813957e3Ssnj size = compact_batch_surface(kgem, &shrink); 3962813957e3Ssnj else 3963813957e3Ssnj size = kgem->nbatch * sizeof(uint32_t); 396403b705cfSriastradh 396503b705cfSriastradh if (size <= 4096) { 396663ef14f0Smrg bo = first_available(kgem, &kgem->pinned_batches[0]); 396763ef14f0Smrg if (bo) 3968813957e3Ssnj goto write; 396963ef14f0Smrg } 397003b705cfSriastradh 397163ef14f0Smrg if (size <= 16384) { 397263ef14f0Smrg bo = first_available(kgem, &kgem->pinned_batches[1]); 397363ef14f0Smrg if (bo) 397463ef14f0Smrg goto write; 397503b705cfSriastradh } 397603b705cfSriastradh 39779a906b70Schristos if (kgem->gen == 020) { 39789a906b70Schristos bo = kgem_create_linear(kgem, size, CREATE_CACHED | CREATE_TEMPORARY); 39799a906b70Schristos if (bo) 3980813957e3Ssnj goto write; 398103b705cfSriastradh 39829a906b70Schristos /* Nothing available for reuse, rely on the kernel wa */ 39839a906b70Schristos if (kgem->has_pinned_batches) { 39849a906b70Schristos bo = kgem_create_linear(kgem, size, CREATE_CACHED | CREATE_TEMPORARY); 39859a906b70Schristos if (bo) { 39869a906b70Schristos kgem->batch_flags &= ~LOCAL_I915_EXEC_IS_PINNED; 3987813957e3Ssnj goto write; 39889a906b70Schristos } 39899a906b70Schristos } 39909a906b70Schristos 39919a906b70Schristos if (size < 16384) { 39929a906b70Schristos bo = list_first_entry(&kgem->pinned_batches[size > 4096], 39939a906b70Schristos struct kgem_bo, 39949a906b70Schristos list); 39959a906b70Schristos list_move_tail(&bo->list, &kgem->pinned_batches[size > 4096]); 399603b705cfSriastradh 39979a906b70Schristos DBG(("%s: syncing due to busy batches\n", __FUNCTION__)); 399863ef14f0Smrg if (kgem_bo_wait(kgem, bo)) 39999a906b70Schristos return NULL; 400003b705cfSriastradh 40019a906b70Schristos kgem_retire(kgem); 40029a906b70Schristos assert(bo->rq == NULL); 4003813957e3Ssnj bo = kgem_bo_reference(bo); 4004813957e3Ssnj goto write; 40059a906b70Schristos } 400603b705cfSriastradh } 400763ef14f0Smrg#else 400863ef14f0Smrg if (kgem->surface != kgem->batch_size) 400963ef14f0Smrg size = kgem->batch_size * sizeof(uint32_t); 401063ef14f0Smrg else 401163ef14f0Smrg size = kgem->nbatch * sizeof(uint32_t); 401263ef14f0Smrg#endif 401303b705cfSriastradh 401463ef14f0Smrg if (!kgem->batch_bo || !kgem->has_llc) { 4015813957e3Ssnj bo = kgem_create_linear(kgem, size, CREATE_NO_THROTTLE); 4016813957e3Ssnj if (bo) { 4017813957e3Ssnjwrite: 4018813957e3Ssnj kgem_fixup_relocs(kgem, bo, shrink); 4019813957e3Ssnj if (kgem_batch_write(kgem, bo, size)) { 4020813957e3Ssnj kgem_bo_destroy(kgem, bo); 4021813957e3Ssnj return NULL; 4022813957e3Ssnj } 402363ef14f0Smrg return bo; 4024813957e3Ssnj } 4025813957e3Ssnj } 402663ef14f0Smrg 4027813957e3Ssnj return kgem_new_batch(kgem); 402803b705cfSriastradh} 402903b705cfSriastradh 40309a906b70Schristos#if !NDEBUG 40319a906b70Schristosstatic bool dump_file(const char *path) 40329a906b70Schristos{ 40339a906b70Schristos FILE *file; 40349a906b70Schristos size_t len = 0; 40359a906b70Schristos char *line = NULL; 40369a906b70Schristos 40379a906b70Schristos file = fopen(path, "r"); 40389a906b70Schristos if (file == NULL) 40399a906b70Schristos return false; 40409a906b70Schristos 40419a906b70Schristos while (getline(&line, &len, file) != -1) 40429a906b70Schristos ErrorF("%s", line); 40439a906b70Schristos 40449a906b70Schristos free(line); 40459a906b70Schristos fclose(file); 40469a906b70Schristos return true; 40479a906b70Schristos} 40489a906b70Schristos 40499a906b70Schristosstatic void dump_debugfs(struct kgem *kgem, const char *name) 40509a906b70Schristos{ 40519a906b70Schristos char path[80]; 40529a906b70Schristos int minor = kgem_get_minor(kgem); 40539a906b70Schristos 40549a906b70Schristos if (minor < 0) 40559a906b70Schristos return; 40569a906b70Schristos 40579a906b70Schristos sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 40589a906b70Schristos if (dump_file(path)) 40599a906b70Schristos return; 40609a906b70Schristos 40619a906b70Schristos sprintf(path, "/debug/dri/%d/%s", minor, name); 40629a906b70Schristos if (dump_file(path)) 40639a906b70Schristos return; 40649a906b70Schristos} 40659a906b70Schristos 40669a906b70Schristosstatic void dump_gtt_info(struct kgem *kgem) 40679a906b70Schristos{ 40689a906b70Schristos dump_debugfs(kgem, "i915_gem_gtt"); 40699a906b70Schristos} 40709a906b70Schristos 40719a906b70Schristosstatic void dump_fence_regs(struct kgem *kgem) 40729a906b70Schristos{ 40739a906b70Schristos dump_debugfs(kgem, "i915_gem_fence_regs"); 40749a906b70Schristos} 40759a906b70Schristos#endif 40769a906b70Schristos 40779a906b70Schristosstatic int do_execbuf(struct kgem *kgem, struct drm_i915_gem_execbuffer2 *execbuf) 40789a906b70Schristos{ 407963ef14f0Smrg int ret; 40809a906b70Schristos 40819a906b70Schristosretry: 40829a906b70Schristos ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf); 40839a906b70Schristos if (ret == 0) 40849a906b70Schristos return 0; 40859a906b70Schristos 40869a906b70Schristos DBG(("%s: failed ret=%d, throttling and discarding cache\n", __FUNCTION__, ret)); 40879a906b70Schristos (void)__kgem_throttle_retire(kgem, 0); 40889a906b70Schristos if (kgem_expire_cache(kgem)) 40899a906b70Schristos goto retry; 40909a906b70Schristos 40919a906b70Schristos if (kgem_cleanup_cache(kgem)) 40929a906b70Schristos goto retry; 40939a906b70Schristos 40949a906b70Schristos /* last gasp */ 4095813957e3Ssnj ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf); 409663ef14f0Smrg if (ret != -ENOSPC) 409763ef14f0Smrg return ret; 409863ef14f0Smrg 409963ef14f0Smrg /* One final trick up our sleeve for when we run out of space. 410063ef14f0Smrg * We turn everything off to free up our pinned framebuffers, 410163ef14f0Smrg * sprites and cursors, and try just one more time. 410263ef14f0Smrg */ 4103813957e3Ssnj 4104813957e3Ssnj xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING, 4105813957e3Ssnj "Failed to submit rendering commands, trying again with outputs disabled.\n"); 4106813957e3Ssnj 410763ef14f0Smrg if (sna_mode_disable(__to_sna(kgem))) { 4108813957e3Ssnj kgem_cleanup_cache(kgem); 4109813957e3Ssnj ret = do_ioctl(kgem->fd, 4110813957e3Ssnj DRM_IOCTL_I915_GEM_EXECBUFFER2, 4111813957e3Ssnj execbuf); 4112813957e3Ssnj DBG(("%s: last_gasp ret=%d\n", __FUNCTION__, ret)); 411363ef14f0Smrg sna_mode_enable(__to_sna(kgem)); 4114813957e3Ssnj } 4115813957e3Ssnj 4116813957e3Ssnj return ret; 41179a906b70Schristos} 41189a906b70Schristos 411903b705cfSriastradhvoid _kgem_submit(struct kgem *kgem) 412003b705cfSriastradh{ 412103b705cfSriastradh struct kgem_request *rq; 412203b705cfSriastradh uint32_t batch_end; 412363ef14f0Smrg int i, ret; 412403b705cfSriastradh 412503b705cfSriastradh assert(!DBG_NO_HW); 412603b705cfSriastradh assert(!kgem->wedged); 412703b705cfSriastradh 412803b705cfSriastradh assert(kgem->nbatch); 412903b705cfSriastradh assert(kgem->nbatch <= KGEM_BATCH_SIZE(kgem)); 413003b705cfSriastradh assert(kgem->nbatch <= kgem->surface); 413103b705cfSriastradh 413203b705cfSriastradh batch_end = kgem_end_batch(kgem); 413303b705cfSriastradh kgem_sna_flush(kgem); 413403b705cfSriastradh 41359a906b70Schristos DBG(("batch[%d/%d, flags=%x]: %d %d %d %d, nreloc=%d, nexec=%d, nfence=%d, aperture=%d [fenced=%d]\n", 41369a906b70Schristos kgem->mode, kgem->ring, kgem->batch_flags, 41379a906b70Schristos batch_end, kgem->nbatch, kgem->surface, kgem->batch_size, 41389a906b70Schristos kgem->nreloc, kgem->nexec, kgem->nfence, kgem->aperture, kgem->aperture_fenced)); 413903b705cfSriastradh 414003b705cfSriastradh assert(kgem->nbatch <= kgem->batch_size); 414103b705cfSriastradh assert(kgem->nbatch <= kgem->surface); 414203b705cfSriastradh assert(kgem->nreloc <= ARRAY_SIZE(kgem->reloc)); 414303b705cfSriastradh assert(kgem->nexec < ARRAY_SIZE(kgem->exec)); 414403b705cfSriastradh assert(kgem->nfence <= kgem->fence_max); 414503b705cfSriastradh 414603b705cfSriastradh kgem_finish_buffers(kgem); 414703b705cfSriastradh 41489a906b70Schristos#if SHOW_BATCH_BEFORE 414903b705cfSriastradh __kgem_batch_debug(kgem, batch_end); 415003b705cfSriastradh#endif 415103b705cfSriastradh 415203b705cfSriastradh rq = kgem->next_request; 4153813957e3Ssnj assert(rq->bo == NULL); 4154813957e3Ssnj 4155813957e3Ssnj rq->bo = kgem_create_batch(kgem); 415603b705cfSriastradh if (rq->bo) { 4157813957e3Ssnj struct drm_i915_gem_execbuffer2 execbuf; 415803b705cfSriastradh 415903b705cfSriastradh assert(!rq->bo->needs_flush); 416003b705cfSriastradh 416103b705cfSriastradh i = kgem->nexec++; 4162813957e3Ssnj kgem->exec[i].handle = rq->bo->handle; 416303b705cfSriastradh kgem->exec[i].relocation_count = kgem->nreloc; 416403b705cfSriastradh kgem->exec[i].relocs_ptr = (uintptr_t)kgem->reloc; 416503b705cfSriastradh kgem->exec[i].alignment = 0; 416603b705cfSriastradh kgem->exec[i].offset = rq->bo->presumed_offset; 416763ef14f0Smrg /* Make sure the kernel releases any fence, ignored if gen4+ */ 416863ef14f0Smrg kgem->exec[i].flags = EXEC_OBJECT_NEEDS_FENCE; 416903b705cfSriastradh kgem->exec[i].rsvd1 = 0; 417003b705cfSriastradh kgem->exec[i].rsvd2 = 0; 417103b705cfSriastradh 417203b705cfSriastradh rq->bo->exec = &kgem->exec[i]; 417303b705cfSriastradh rq->bo->rq = MAKE_REQUEST(rq, kgem->ring); /* useful sanity check */ 417403b705cfSriastradh list_add(&rq->bo->request, &rq->buffers); 417503b705cfSriastradh rq->ring = kgem->ring == KGEM_BLT; 417603b705cfSriastradh 4177813957e3Ssnj memset(&execbuf, 0, sizeof(execbuf)); 4178813957e3Ssnj execbuf.buffers_ptr = (uintptr_t)kgem->exec; 4179813957e3Ssnj execbuf.buffer_count = kgem->nexec; 418063ef14f0Smrg if (kgem->gen < 030) 418163ef14f0Smrg execbuf.batch_len = batch_end*sizeof(uint32_t); 4182813957e3Ssnj execbuf.flags = kgem->ring | kgem->batch_flags; 4183813957e3Ssnj 4184813957e3Ssnj if (DBG_DUMP) { 4185813957e3Ssnj int fd = open("/tmp/i915-batchbuffers.dump", 4186813957e3Ssnj O_WRONLY | O_CREAT | O_APPEND, 4187813957e3Ssnj 0666); 4188813957e3Ssnj if (fd != -1) { 4189813957e3Ssnj ret = write(fd, kgem->batch, batch_end*sizeof(uint32_t)); 4190813957e3Ssnj fd = close(fd); 419103b705cfSriastradh } 4192813957e3Ssnj } 419303b705cfSriastradh 4194813957e3Ssnj ret = do_execbuf(kgem, &execbuf); 419563ef14f0Smrg } else 419663ef14f0Smrg ret = -ENOMEM; 419703b705cfSriastradh 419863ef14f0Smrg if (ret < 0) { 419963ef14f0Smrg kgem_throttle(kgem); 420063ef14f0Smrg if (!kgem->wedged) { 420163ef14f0Smrg xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR, 420263ef14f0Smrg "Failed to submit rendering commands (%s), disabling acceleration.\n", 420363ef14f0Smrg strerror(-ret)); 420463ef14f0Smrg __kgem_set_wedged(kgem); 4205813957e3Ssnj } 420603b705cfSriastradh 420703b705cfSriastradh#if !NDEBUG 420863ef14f0Smrg ErrorF("batch[%d/%d]: %d %d %d, nreloc=%d, nexec=%d, nfence=%d, aperture=%d, fenced=%d, high=%d,%d: errno=%d\n", 420963ef14f0Smrg kgem->mode, kgem->ring, batch_end, kgem->nbatch, kgem->surface, 421063ef14f0Smrg kgem->nreloc, kgem->nexec, kgem->nfence, kgem->aperture, kgem->aperture_fenced, kgem->aperture_high, kgem->aperture_total, -ret); 421103b705cfSriastradh 421263ef14f0Smrg for (i = 0; i < kgem->nexec; i++) { 421363ef14f0Smrg struct kgem_bo *bo, *found = NULL; 421403b705cfSriastradh 421563ef14f0Smrg list_for_each_entry(bo, &kgem->next_request->buffers, request) { 421663ef14f0Smrg if (bo->handle == kgem->exec[i].handle) { 421763ef14f0Smrg found = bo; 421863ef14f0Smrg break; 421903b705cfSriastradh } 4220813957e3Ssnj } 422163ef14f0Smrg ErrorF("exec[%d] = handle:%d, presumed offset: %x, size: %d, tiling %d, fenced %d, snooped %d, deleted %d\n", 422263ef14f0Smrg i, 422363ef14f0Smrg kgem->exec[i].handle, 422463ef14f0Smrg (int)kgem->exec[i].offset, 422563ef14f0Smrg found ? kgem_bo_size(found) : -1, 422663ef14f0Smrg found ? found->tiling : -1, 422763ef14f0Smrg (int)(kgem->exec[i].flags & EXEC_OBJECT_NEEDS_FENCE), 422863ef14f0Smrg found ? found->snoop : -1, 422963ef14f0Smrg found ? found->purged : -1); 423063ef14f0Smrg } 423163ef14f0Smrg for (i = 0; i < kgem->nreloc; i++) { 423263ef14f0Smrg ErrorF("reloc[%d] = pos:%d, target:%d, delta:%d, read:%x, write:%x, offset:%x\n", 423363ef14f0Smrg i, 423463ef14f0Smrg (int)kgem->reloc[i].offset, 423563ef14f0Smrg kgem->reloc[i].target_handle, 423663ef14f0Smrg kgem->reloc[i].delta, 423763ef14f0Smrg kgem->reloc[i].read_domains, 423863ef14f0Smrg kgem->reloc[i].write_domain, 423963ef14f0Smrg (int)kgem->reloc[i].presumed_offset); 424063ef14f0Smrg } 424163ef14f0Smrg 424263ef14f0Smrg { 424363ef14f0Smrg struct drm_i915_gem_get_aperture aperture; 424463ef14f0Smrg if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture) == 0) 424563ef14f0Smrg ErrorF("Aperture size %lld, available %lld\n", 424663ef14f0Smrg (long long)aperture.aper_size, 424763ef14f0Smrg (long long)aperture.aper_available_size); 424863ef14f0Smrg } 424963ef14f0Smrg 425063ef14f0Smrg if (ret == -ENOSPC) 425163ef14f0Smrg dump_gtt_info(kgem); 425263ef14f0Smrg if (ret == -EDEADLK) 425363ef14f0Smrg dump_fence_regs(kgem); 425463ef14f0Smrg 425563ef14f0Smrg if (DEBUG_SYNC) { 425663ef14f0Smrg int fd = open("/tmp/batchbuffer", O_WRONLY | O_CREAT | O_APPEND, 0666); 425763ef14f0Smrg if (fd != -1) { 425863ef14f0Smrg int ignored = write(fd, kgem->batch, batch_end*sizeof(uint32_t)); 425963ef14f0Smrg assert(ignored == batch_end*sizeof(uint32_t)); 426063ef14f0Smrg close(fd); 4261813957e3Ssnj } 426203b705cfSriastradh 426363ef14f0Smrg FatalError("SNA: failed to submit batchbuffer, errno=%d\n", -ret); 426463ef14f0Smrg } 426563ef14f0Smrg#endif 426663ef14f0Smrg } else { 426763ef14f0Smrg if (DEBUG_SYNC) { 426863ef14f0Smrg struct drm_i915_gem_set_domain set_domain; 42699a906b70Schristos 427063ef14f0Smrg VG_CLEAR(set_domain); 427163ef14f0Smrg set_domain.handle = rq->bo->handle; 427263ef14f0Smrg set_domain.read_domains = I915_GEM_DOMAIN_GTT; 427363ef14f0Smrg set_domain.write_domain = I915_GEM_DOMAIN_GTT; 4274813957e3Ssnj 427563ef14f0Smrg ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain); 427603b705cfSriastradh } 427763ef14f0Smrg 42789a906b70Schristos#if SHOW_BATCH_AFTER 427963ef14f0Smrg if (gem_read(kgem->fd, rq->bo->handle, kgem->batch, 0, batch_end*sizeof(uint32_t)) == 0) 428063ef14f0Smrg __kgem_batch_debug(kgem, batch_end); 42819a906b70Schristos#endif 428263ef14f0Smrg 428363ef14f0Smrg kgem_commit(kgem); 428463ef14f0Smrg } 428563ef14f0Smrg 428663ef14f0Smrg if (unlikely(kgem->wedged)) 428703b705cfSriastradh kgem_cleanup(kgem); 428803b705cfSriastradh 428903b705cfSriastradh kgem_reset(kgem); 429003b705cfSriastradh 429103b705cfSriastradh assert(kgem->next_request != NULL); 429203b705cfSriastradh} 429303b705cfSriastradh 429403b705cfSriastradhvoid kgem_throttle(struct kgem *kgem) 429503b705cfSriastradh{ 429663ef14f0Smrg if (unlikely(kgem->wedged)) 429703b705cfSriastradh return; 429803b705cfSriastradh 4299813957e3Ssnj if (__kgem_throttle(kgem, true)) { 430003b705cfSriastradh xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR, 430103b705cfSriastradh "Detected a hung GPU, disabling acceleration.\n"); 4302813957e3Ssnj __kgem_set_wedged(kgem); 43039a906b70Schristos kgem->need_throttle = false; 430403b705cfSriastradh } 430503b705cfSriastradh} 430603b705cfSriastradh 43079a906b70Schristosint kgem_is_wedged(struct kgem *kgem) 43089a906b70Schristos{ 43099a906b70Schristos return __kgem_throttle(kgem, true); 43109a906b70Schristos} 43119a906b70Schristos 43129a906b70Schristosstatic void kgem_purge_cache(struct kgem *kgem) 431303b705cfSriastradh{ 431403b705cfSriastradh struct kgem_bo *bo, *next; 431503b705cfSriastradh int i; 431603b705cfSriastradh 431703b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) { 431803b705cfSriastradh list_for_each_entry_safe(bo, next, &kgem->inactive[i], list) { 431903b705cfSriastradh if (!kgem_bo_is_retained(kgem, bo)) { 432003b705cfSriastradh DBG(("%s: purging %d\n", 432103b705cfSriastradh __FUNCTION__, bo->handle)); 432203b705cfSriastradh kgem_bo_free(kgem, bo); 432303b705cfSriastradh } 432403b705cfSriastradh } 432503b705cfSriastradh } 432603b705cfSriastradh 432703b705cfSriastradh kgem->need_purge = false; 432803b705cfSriastradh} 432903b705cfSriastradh 433003b705cfSriastradhvoid kgem_clean_scanout_cache(struct kgem *kgem) 433103b705cfSriastradh{ 433203b705cfSriastradh while (!list_is_empty(&kgem->scanout)) { 433303b705cfSriastradh struct kgem_bo *bo; 433403b705cfSriastradh 433503b705cfSriastradh bo = list_first_entry(&kgem->scanout, struct kgem_bo, list); 433603b705cfSriastradh 433703b705cfSriastradh assert(bo->scanout); 433803b705cfSriastradh assert(!bo->refcnt); 43399a906b70Schristos assert(!bo->prime); 434003b705cfSriastradh assert(bo->proxy == NULL); 434103b705cfSriastradh 434203b705cfSriastradh if (bo->exec || __kgem_busy(kgem, bo->handle)) 434303b705cfSriastradh break; 434403b705cfSriastradh 434503b705cfSriastradh DBG(("%s: handle=%d, fb=%d (reusable=%d)\n", 434603b705cfSriastradh __FUNCTION__, bo->handle, bo->delta, bo->reusable)); 434703b705cfSriastradh list_del(&bo->list); 434803b705cfSriastradh 43499a906b70Schristos kgem_bo_rmfb(kgem, bo); 435003b705cfSriastradh bo->scanout = false; 435103b705cfSriastradh 435203b705cfSriastradh if (!bo->purged) { 435303b705cfSriastradh bo->reusable = true; 435403b705cfSriastradh if (kgem->has_llc && 435503b705cfSriastradh !gem_set_caching(kgem->fd, bo->handle, SNOOPED)) 435603b705cfSriastradh bo->reusable = false; 435703b705cfSriastradh 435803b705cfSriastradh } 435903b705cfSriastradh 436003b705cfSriastradh __kgem_bo_destroy(kgem, bo); 436103b705cfSriastradh } 436203b705cfSriastradh} 436303b705cfSriastradh 436403b705cfSriastradhvoid kgem_clean_large_cache(struct kgem *kgem) 436503b705cfSriastradh{ 436603b705cfSriastradh while (!list_is_empty(&kgem->large_inactive)) { 436703b705cfSriastradh kgem_bo_free(kgem, 436803b705cfSriastradh list_first_entry(&kgem->large_inactive, 436903b705cfSriastradh struct kgem_bo, list)); 437003b705cfSriastradh 437103b705cfSriastradh } 437203b705cfSriastradh} 437303b705cfSriastradh 437403b705cfSriastradhbool kgem_expire_cache(struct kgem *kgem) 437503b705cfSriastradh{ 437603b705cfSriastradh time_t now, expire; 437703b705cfSriastradh struct kgem_bo *bo; 437803b705cfSriastradh unsigned int size = 0, count = 0; 437903b705cfSriastradh bool idle; 438003b705cfSriastradh unsigned int i; 438103b705cfSriastradh 438263ef14f0Smrg if (!time(&now)) 438363ef14f0Smrg return false; 438403b705cfSriastradh 438503b705cfSriastradh while (__kgem_freed_bo) { 438603b705cfSriastradh bo = __kgem_freed_bo; 438703b705cfSriastradh __kgem_freed_bo = *(struct kgem_bo **)bo; 438803b705cfSriastradh free(bo); 438903b705cfSriastradh } 439003b705cfSriastradh 439103b705cfSriastradh while (__kgem_freed_request) { 439203b705cfSriastradh struct kgem_request *rq = __kgem_freed_request; 439303b705cfSriastradh __kgem_freed_request = *(struct kgem_request **)rq; 439403b705cfSriastradh free(rq); 439503b705cfSriastradh } 439603b705cfSriastradh 439703b705cfSriastradh kgem_clean_large_cache(kgem); 439863ef14f0Smrg if (__to_sna(kgem)->scrn->vtSema) 439903b705cfSriastradh kgem_clean_scanout_cache(kgem); 440003b705cfSriastradh 440103b705cfSriastradh expire = 0; 440203b705cfSriastradh list_for_each_entry(bo, &kgem->snoop, list) { 440303b705cfSriastradh if (bo->delta) { 440403b705cfSriastradh expire = now - MAX_INACTIVE_TIME/2; 440503b705cfSriastradh break; 440603b705cfSriastradh } 440703b705cfSriastradh 440863ef14f0Smrg assert(now); 440903b705cfSriastradh bo->delta = now; 441003b705cfSriastradh } 441103b705cfSriastradh if (expire) { 441203b705cfSriastradh while (!list_is_empty(&kgem->snoop)) { 441303b705cfSriastradh bo = list_last_entry(&kgem->snoop, struct kgem_bo, list); 441403b705cfSriastradh 441503b705cfSriastradh if (bo->delta > expire) 441603b705cfSriastradh break; 441703b705cfSriastradh 441803b705cfSriastradh kgem_bo_free(kgem, bo); 441903b705cfSriastradh } 442003b705cfSriastradh } 442103b705cfSriastradh#ifdef DEBUG_MEMORY 442203b705cfSriastradh { 442303b705cfSriastradh long snoop_size = 0; 442403b705cfSriastradh int snoop_count = 0; 442503b705cfSriastradh list_for_each_entry(bo, &kgem->snoop, list) 442603b705cfSriastradh snoop_count++, snoop_size += bytes(bo); 44279a906b70Schristos DBG(("%s: still allocated %d bo, %ld bytes, in snoop cache\n", 44289a906b70Schristos __FUNCTION__, snoop_count, snoop_size)); 442903b705cfSriastradh } 443003b705cfSriastradh#endif 443103b705cfSriastradh 443203b705cfSriastradh kgem_retire(kgem); 443363ef14f0Smrg if (unlikely(kgem->wedged)) 443403b705cfSriastradh kgem_cleanup(kgem); 443503b705cfSriastradh 443603b705cfSriastradh kgem->expire(kgem); 443703b705cfSriastradh 443803b705cfSriastradh if (kgem->need_purge) 443903b705cfSriastradh kgem_purge_cache(kgem); 444003b705cfSriastradh 44419a906b70Schristos if (kgem->need_retire) 44429a906b70Schristos kgem_retire(kgem); 444303b705cfSriastradh 44449a906b70Schristos expire = 0; 44459a906b70Schristos idle = true; 444603b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) { 444703b705cfSriastradh idle &= list_is_empty(&kgem->inactive[i]); 444803b705cfSriastradh list_for_each_entry(bo, &kgem->inactive[i], list) { 444903b705cfSriastradh if (bo->delta) { 445003b705cfSriastradh expire = now - MAX_INACTIVE_TIME; 445103b705cfSriastradh break; 445203b705cfSriastradh } 445303b705cfSriastradh 445463ef14f0Smrg assert(now); 445563ef14f0Smrg kgem_bo_set_purgeable(kgem, bo); 445603b705cfSriastradh bo->delta = now; 445703b705cfSriastradh } 445803b705cfSriastradh } 44599a906b70Schristos if (expire == 0) { 44609a906b70Schristos DBG(("%s: idle? %d\n", __FUNCTION__, idle)); 44619a906b70Schristos kgem->need_expire = !idle; 446203b705cfSriastradh return false; 446303b705cfSriastradh } 446403b705cfSriastradh 44659a906b70Schristos idle = true; 446603b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) { 446703b705cfSriastradh struct list preserve; 446803b705cfSriastradh 446903b705cfSriastradh list_init(&preserve); 447003b705cfSriastradh while (!list_is_empty(&kgem->inactive[i])) { 447103b705cfSriastradh bo = list_last_entry(&kgem->inactive[i], 447203b705cfSriastradh struct kgem_bo, list); 447303b705cfSriastradh 447403b705cfSriastradh if (bo->delta > expire) { 447503b705cfSriastradh idle = false; 447603b705cfSriastradh break; 447703b705cfSriastradh } 447803b705cfSriastradh 44799a906b70Schristos if (bo->map__cpu && bo->delta + MAP_PRESERVE_TIME > expire) { 448003b705cfSriastradh idle = false; 448103b705cfSriastradh list_move_tail(&bo->list, &preserve); 448203b705cfSriastradh } else { 448303b705cfSriastradh count++; 448403b705cfSriastradh size += bytes(bo); 448503b705cfSriastradh kgem_bo_free(kgem, bo); 448663ef14f0Smrg DBG(("%s: expiring handle=%d\n", 448703b705cfSriastradh __FUNCTION__, bo->handle)); 448803b705cfSriastradh } 448903b705cfSriastradh } 449063ef14f0Smrg list_splice_tail(&preserve, &kgem->inactive[i]); 449103b705cfSriastradh } 449203b705cfSriastradh 449303b705cfSriastradh#ifdef DEBUG_MEMORY 449403b705cfSriastradh { 449503b705cfSriastradh long inactive_size = 0; 449603b705cfSriastradh int inactive_count = 0; 449703b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) 449803b705cfSriastradh list_for_each_entry(bo, &kgem->inactive[i], list) 449903b705cfSriastradh inactive_count++, inactive_size += bytes(bo); 45009a906b70Schristos DBG(("%s: still allocated %d bo, %ld bytes, in inactive cache\n", 45019a906b70Schristos __FUNCTION__, inactive_count, inactive_size)); 450203b705cfSriastradh } 450303b705cfSriastradh#endif 450403b705cfSriastradh 450503b705cfSriastradh DBG(("%s: expired %d objects, %d bytes, idle? %d\n", 450603b705cfSriastradh __FUNCTION__, count, size, idle)); 450703b705cfSriastradh 450803b705cfSriastradh kgem->need_expire = !idle; 45099a906b70Schristos return count; 451003b705cfSriastradh (void)count; 451103b705cfSriastradh (void)size; 451203b705cfSriastradh} 451303b705cfSriastradh 45149a906b70Schristosbool kgem_cleanup_cache(struct kgem *kgem) 451503b705cfSriastradh{ 451603b705cfSriastradh unsigned int i; 451703b705cfSriastradh int n; 451803b705cfSriastradh 451963ef14f0Smrg DBG(("%s\n", __FUNCTION__)); 452063ef14f0Smrg 452103b705cfSriastradh /* sync to the most recent request */ 452203b705cfSriastradh for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) { 452303b705cfSriastradh if (!list_is_empty(&kgem->requests[n])) { 452403b705cfSriastradh struct kgem_request *rq; 452503b705cfSriastradh 452663ef14f0Smrg rq = list_last_entry(&kgem->requests[n], 452763ef14f0Smrg struct kgem_request, 452863ef14f0Smrg list); 452903b705cfSriastradh 453003b705cfSriastradh DBG(("%s: sync on cleanup\n", __FUNCTION__)); 453163ef14f0Smrg assert(rq->ring == n); 453263ef14f0Smrg assert(rq->bo); 453363ef14f0Smrg assert(RQ(rq->bo->rq) == rq); 453463ef14f0Smrg kgem_bo_wait(kgem, rq->bo); 453503b705cfSriastradh } 453663ef14f0Smrg assert(list_is_empty(&kgem->requests[n])); 453703b705cfSriastradh } 453803b705cfSriastradh 453903b705cfSriastradh kgem_retire(kgem); 454003b705cfSriastradh kgem_cleanup(kgem); 454103b705cfSriastradh 454263ef14f0Smrg DBG(("%s: need_expire?=%d\n", __FUNCTION__, kgem->need_expire)); 45439a906b70Schristos if (!kgem->need_expire) 45449a906b70Schristos return false; 45459a906b70Schristos 454603b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) { 454703b705cfSriastradh while (!list_is_empty(&kgem->inactive[i])) 454803b705cfSriastradh kgem_bo_free(kgem, 454903b705cfSriastradh list_last_entry(&kgem->inactive[i], 455003b705cfSriastradh struct kgem_bo, list)); 455103b705cfSriastradh } 455203b705cfSriastradh 455303b705cfSriastradh kgem_clean_large_cache(kgem); 455403b705cfSriastradh kgem_clean_scanout_cache(kgem); 455503b705cfSriastradh 455603b705cfSriastradh while (!list_is_empty(&kgem->snoop)) 455703b705cfSriastradh kgem_bo_free(kgem, 455803b705cfSriastradh list_last_entry(&kgem->snoop, 455903b705cfSriastradh struct kgem_bo, list)); 456003b705cfSriastradh 456103b705cfSriastradh while (__kgem_freed_bo) { 456203b705cfSriastradh struct kgem_bo *bo = __kgem_freed_bo; 456303b705cfSriastradh __kgem_freed_bo = *(struct kgem_bo **)bo; 456403b705cfSriastradh free(bo); 456503b705cfSriastradh } 456603b705cfSriastradh 456703b705cfSriastradh kgem->need_purge = false; 456803b705cfSriastradh kgem->need_expire = false; 456963ef14f0Smrg 457063ef14f0Smrg DBG(("%s: complete\n", __FUNCTION__)); 45719a906b70Schristos return true; 457203b705cfSriastradh} 457303b705cfSriastradh 457403b705cfSriastradhstatic struct kgem_bo * 457503b705cfSriastradhsearch_linear_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags) 457603b705cfSriastradh{ 457703b705cfSriastradh struct kgem_bo *bo, *first = NULL; 457803b705cfSriastradh bool use_active = (flags & CREATE_INACTIVE) == 0; 457903b705cfSriastradh struct list *cache; 458003b705cfSriastradh 458103b705cfSriastradh DBG(("%s: num_pages=%d, flags=%x, use_active? %d, use_large=%d [max=%d]\n", 458203b705cfSriastradh __FUNCTION__, num_pages, flags, use_active, 458303b705cfSriastradh num_pages >= MAX_CACHE_SIZE / PAGE_SIZE, 458403b705cfSriastradh MAX_CACHE_SIZE / PAGE_SIZE)); 458503b705cfSriastradh 458603b705cfSriastradh assert(num_pages); 458703b705cfSriastradh 458803b705cfSriastradh if (num_pages >= MAX_CACHE_SIZE / PAGE_SIZE) { 458903b705cfSriastradh DBG(("%s: searching large buffers\n", __FUNCTION__)); 459003b705cfSriastradhretry_large: 459103b705cfSriastradh cache = use_active ? &kgem->large : &kgem->large_inactive; 459203b705cfSriastradh list_for_each_entry_safe(bo, first, cache, list) { 459303b705cfSriastradh assert(bo->refcnt == 0); 459403b705cfSriastradh assert(bo->reusable); 459503b705cfSriastradh assert(!bo->scanout); 459603b705cfSriastradh 459703b705cfSriastradh if (num_pages > num_pages(bo)) 459803b705cfSriastradh goto discard; 459903b705cfSriastradh 460003b705cfSriastradh if (bo->tiling != I915_TILING_NONE) { 460163ef14f0Smrg if (use_active && kgem->gen < 040) 460203b705cfSriastradh goto discard; 460303b705cfSriastradh 460463ef14f0Smrg if (!kgem_set_tiling(kgem, bo, 460503b705cfSriastradh I915_TILING_NONE, 0)) 460603b705cfSriastradh goto discard; 460703b705cfSriastradh } 460863ef14f0Smrg assert(bo->tiling == I915_TILING_NONE); 460963ef14f0Smrg bo->pitch = 0; 461003b705cfSriastradh 461103b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) 461203b705cfSriastradh goto discard; 461303b705cfSriastradh 461403b705cfSriastradh list_del(&bo->list); 46159a906b70Schristos if (RQ(bo->rq) == (void *)kgem) { 46169a906b70Schristos assert(bo->exec == NULL); 461703b705cfSriastradh list_del(&bo->request); 46189a906b70Schristos } 461903b705cfSriastradh 462003b705cfSriastradh bo->delta = 0; 462103b705cfSriastradh assert_tiling(kgem, bo); 462203b705cfSriastradh return bo; 462303b705cfSriastradh 462403b705cfSriastradhdiscard: 462503b705cfSriastradh if (!use_active) 462603b705cfSriastradh kgem_bo_free(kgem, bo); 462703b705cfSriastradh } 462803b705cfSriastradh 462903b705cfSriastradh if (use_active) { 463003b705cfSriastradh use_active = false; 463103b705cfSriastradh goto retry_large; 463203b705cfSriastradh } 463303b705cfSriastradh 463403b705cfSriastradh if (__kgem_throttle_retire(kgem, flags)) 463503b705cfSriastradh goto retry_large; 463603b705cfSriastradh 463703b705cfSriastradh return NULL; 463803b705cfSriastradh } 463903b705cfSriastradh 464003b705cfSriastradh if (!use_active && list_is_empty(inactive(kgem, num_pages))) { 464103b705cfSriastradh DBG(("%s: inactive and cache bucket empty\n", 464203b705cfSriastradh __FUNCTION__)); 464303b705cfSriastradh 464403b705cfSriastradh if (flags & CREATE_NO_RETIRE) { 464503b705cfSriastradh DBG(("%s: can not retire\n", __FUNCTION__)); 464603b705cfSriastradh return NULL; 464703b705cfSriastradh } 464803b705cfSriastradh 464903b705cfSriastradh if (list_is_empty(active(kgem, num_pages, I915_TILING_NONE))) { 465003b705cfSriastradh DBG(("%s: active cache bucket empty\n", __FUNCTION__)); 465103b705cfSriastradh return NULL; 465203b705cfSriastradh } 465303b705cfSriastradh 465403b705cfSriastradh if (!__kgem_throttle_retire(kgem, flags)) { 465503b705cfSriastradh DBG(("%s: nothing retired\n", __FUNCTION__)); 465603b705cfSriastradh return NULL; 465703b705cfSriastradh } 465803b705cfSriastradh 465903b705cfSriastradh if (list_is_empty(inactive(kgem, num_pages))) { 466003b705cfSriastradh DBG(("%s: active cache bucket still empty after retire\n", 466103b705cfSriastradh __FUNCTION__)); 466203b705cfSriastradh return NULL; 466303b705cfSriastradh } 466403b705cfSriastradh } 466503b705cfSriastradh 466603b705cfSriastradh if (!use_active && flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { 466703b705cfSriastradh int for_cpu = !!(flags & CREATE_CPU_MAP); 466803b705cfSriastradh DBG(("%s: searching for inactive %s map\n", 466903b705cfSriastradh __FUNCTION__, for_cpu ? "cpu" : "gtt")); 467003b705cfSriastradh cache = &kgem->vma[for_cpu].inactive[cache_bucket(num_pages)]; 467103b705cfSriastradh list_for_each_entry(bo, cache, vma) { 4672813957e3Ssnj assert(for_cpu ? !!bo->map__cpu : (bo->map__gtt || bo->map__wc)); 467303b705cfSriastradh assert(bucket(bo) == cache_bucket(num_pages)); 467403b705cfSriastradh assert(bo->proxy == NULL); 467503b705cfSriastradh assert(bo->rq == NULL); 467603b705cfSriastradh assert(bo->exec == NULL); 467703b705cfSriastradh assert(!bo->scanout); 467803b705cfSriastradh 467903b705cfSriastradh if (num_pages > num_pages(bo)) { 468003b705cfSriastradh DBG(("inactive too small: %d < %d\n", 468103b705cfSriastradh num_pages(bo), num_pages)); 468203b705cfSriastradh continue; 468303b705cfSriastradh } 468403b705cfSriastradh 468503b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { 468603b705cfSriastradh kgem_bo_free(kgem, bo); 468703b705cfSriastradh break; 468803b705cfSriastradh } 468903b705cfSriastradh 469063ef14f0Smrg if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) { 469163ef14f0Smrg kgem_bo_free(kgem, bo); 469263ef14f0Smrg break; 469363ef14f0Smrg } 469403b705cfSriastradh 469503b705cfSriastradh kgem_bo_remove_from_inactive(kgem, bo); 46969a906b70Schristos assert(list_is_empty(&bo->vma)); 46979a906b70Schristos assert(list_is_empty(&bo->list)); 469803b705cfSriastradh 469963ef14f0Smrg assert(bo->tiling == I915_TILING_NONE); 470063ef14f0Smrg assert(bo->pitch == 0); 470103b705cfSriastradh bo->delta = 0; 470203b705cfSriastradh DBG((" %s: found handle=%d (num_pages=%d) in linear vma cache\n", 470303b705cfSriastradh __FUNCTION__, bo->handle, num_pages(bo))); 470403b705cfSriastradh assert(use_active || bo->domain != DOMAIN_GPU); 470503b705cfSriastradh assert(!bo->needs_flush); 470603b705cfSriastradh assert_tiling(kgem, bo); 470703b705cfSriastradh ASSERT_MAYBE_IDLE(kgem, bo->handle, !use_active); 470803b705cfSriastradh return bo; 470903b705cfSriastradh } 471003b705cfSriastradh 471103b705cfSriastradh if (flags & CREATE_EXACT) 471203b705cfSriastradh return NULL; 471303b705cfSriastradh 471403b705cfSriastradh if (flags & CREATE_CPU_MAP && !kgem->has_llc) 471503b705cfSriastradh return NULL; 471603b705cfSriastradh } 471703b705cfSriastradh 471803b705cfSriastradh cache = use_active ? active(kgem, num_pages, I915_TILING_NONE) : inactive(kgem, num_pages); 471903b705cfSriastradh list_for_each_entry(bo, cache, list) { 472003b705cfSriastradh assert(bo->refcnt == 0); 472103b705cfSriastradh assert(bo->reusable); 472203b705cfSriastradh assert(!!bo->rq == !!use_active); 472303b705cfSriastradh assert(bo->proxy == NULL); 472403b705cfSriastradh assert(!bo->scanout); 472503b705cfSriastradh 472603b705cfSriastradh if (num_pages > num_pages(bo)) 472703b705cfSriastradh continue; 472803b705cfSriastradh 472903b705cfSriastradh if (use_active && 473003b705cfSriastradh kgem->gen <= 040 && 473103b705cfSriastradh bo->tiling != I915_TILING_NONE) 473203b705cfSriastradh continue; 473303b705cfSriastradh 473403b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { 473503b705cfSriastradh kgem_bo_free(kgem, bo); 473603b705cfSriastradh break; 473703b705cfSriastradh } 473803b705cfSriastradh 473903b705cfSriastradh if (I915_TILING_NONE != bo->tiling) { 474003b705cfSriastradh if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) 474103b705cfSriastradh continue; 474203b705cfSriastradh 474303b705cfSriastradh if (first) 474403b705cfSriastradh continue; 474503b705cfSriastradh 474663ef14f0Smrg if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) 474703b705cfSriastradh continue; 474803b705cfSriastradh } 474963ef14f0Smrg assert(bo->tiling == I915_TILING_NONE); 475063ef14f0Smrg bo->pitch = 0; 475103b705cfSriastradh 4752813957e3Ssnj if (bo->map__gtt || bo->map__wc || bo->map__cpu) { 475303b705cfSriastradh if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { 475403b705cfSriastradh int for_cpu = !!(flags & CREATE_CPU_MAP); 4755813957e3Ssnj if (for_cpu ? !!bo->map__cpu : (bo->map__gtt || bo->map__wc)){ 475603b705cfSriastradh if (first != NULL) 475703b705cfSriastradh break; 475803b705cfSriastradh 475903b705cfSriastradh first = bo; 476003b705cfSriastradh continue; 476103b705cfSriastradh } 476203b705cfSriastradh } else { 476303b705cfSriastradh if (first != NULL) 476403b705cfSriastradh break; 476503b705cfSriastradh 476603b705cfSriastradh first = bo; 476703b705cfSriastradh continue; 476803b705cfSriastradh } 476903b705cfSriastradh } else { 47709a906b70Schristos if (flags & CREATE_GTT_MAP && !kgem_bo_can_map(kgem, bo)) 47719a906b70Schristos continue; 47729a906b70Schristos 477303b705cfSriastradh if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { 477403b705cfSriastradh if (first != NULL) 477503b705cfSriastradh break; 477603b705cfSriastradh 477703b705cfSriastradh first = bo; 477803b705cfSriastradh continue; 477903b705cfSriastradh } 478003b705cfSriastradh } 478103b705cfSriastradh 478203b705cfSriastradh if (use_active) 478303b705cfSriastradh kgem_bo_remove_from_active(kgem, bo); 478403b705cfSriastradh else 478503b705cfSriastradh kgem_bo_remove_from_inactive(kgem, bo); 478603b705cfSriastradh 478703b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 478863ef14f0Smrg assert(bo->pitch == 0); 478903b705cfSriastradh bo->delta = 0; 479003b705cfSriastradh DBG((" %s: found handle=%d (num_pages=%d) in linear %s cache\n", 479103b705cfSriastradh __FUNCTION__, bo->handle, num_pages(bo), 479203b705cfSriastradh use_active ? "active" : "inactive")); 479303b705cfSriastradh assert(list_is_empty(&bo->list)); 47949a906b70Schristos assert(list_is_empty(&bo->vma)); 479503b705cfSriastradh assert(use_active || bo->domain != DOMAIN_GPU); 479603b705cfSriastradh assert(!bo->needs_flush || use_active); 479703b705cfSriastradh assert_tiling(kgem, bo); 479803b705cfSriastradh ASSERT_MAYBE_IDLE(kgem, bo->handle, !use_active); 479903b705cfSriastradh return bo; 480003b705cfSriastradh } 480103b705cfSriastradh 480203b705cfSriastradh if (first) { 480303b705cfSriastradh assert(first->tiling == I915_TILING_NONE); 480403b705cfSriastradh 480503b705cfSriastradh if (use_active) 480603b705cfSriastradh kgem_bo_remove_from_active(kgem, first); 480703b705cfSriastradh else 480803b705cfSriastradh kgem_bo_remove_from_inactive(kgem, first); 480903b705cfSriastradh 481003b705cfSriastradh first->pitch = 0; 481103b705cfSriastradh first->delta = 0; 481203b705cfSriastradh DBG((" %s: found handle=%d (near-miss) (num_pages=%d) in linear %s cache\n", 481303b705cfSriastradh __FUNCTION__, first->handle, num_pages(first), 481403b705cfSriastradh use_active ? "active" : "inactive")); 481503b705cfSriastradh assert(list_is_empty(&first->list)); 48169a906b70Schristos assert(list_is_empty(&first->vma)); 481703b705cfSriastradh assert(use_active || first->domain != DOMAIN_GPU); 481803b705cfSriastradh assert(!first->needs_flush || use_active); 481903b705cfSriastradh ASSERT_MAYBE_IDLE(kgem, first->handle, !use_active); 482003b705cfSriastradh return first; 482103b705cfSriastradh } 482203b705cfSriastradh 482303b705cfSriastradh return NULL; 482403b705cfSriastradh} 482503b705cfSriastradh 482603b705cfSriastradhstruct kgem_bo *kgem_create_for_name(struct kgem *kgem, uint32_t name) 482703b705cfSriastradh{ 482803b705cfSriastradh struct drm_gem_open open_arg; 48299a906b70Schristos struct drm_i915_gem_get_tiling tiling; 483003b705cfSriastradh struct kgem_bo *bo; 483103b705cfSriastradh 483203b705cfSriastradh DBG(("%s(name=%d)\n", __FUNCTION__, name)); 483303b705cfSriastradh 483403b705cfSriastradh VG_CLEAR(open_arg); 483503b705cfSriastradh open_arg.name = name; 48369a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_GEM_OPEN, &open_arg)) 483703b705cfSriastradh return NULL; 483803b705cfSriastradh 483903b705cfSriastradh DBG(("%s: new handle=%d\n", __FUNCTION__, open_arg.handle)); 48409a906b70Schristos 48419a906b70Schristos VG_CLEAR(tiling); 48429a906b70Schristos tiling.handle = open_arg.handle; 48439a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling)) { 48449a906b70Schristos DBG(("%s(name=%d) get-tiling failed, ret=%d\n", __FUNCTION__, name, errno)); 48459a906b70Schristos gem_close(kgem->fd, open_arg.handle); 48469a906b70Schristos return NULL; 48479a906b70Schristos } 48489a906b70Schristos 48499a906b70Schristos DBG(("%s: handle=%d, tiling=%d\n", __FUNCTION__, tiling.handle, tiling.tiling_mode)); 48509a906b70Schristos 485103b705cfSriastradh bo = __kgem_bo_alloc(open_arg.handle, open_arg.size / PAGE_SIZE); 485203b705cfSriastradh if (bo == NULL) { 485303b705cfSriastradh gem_close(kgem->fd, open_arg.handle); 485403b705cfSriastradh return NULL; 485503b705cfSriastradh } 485603b705cfSriastradh 48579a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 48589a906b70Schristos bo->tiling = tiling.tiling_mode; 48599a906b70Schristos bo->prime = true; 486063ef14f0Smrg bo->reusable = false; 486163ef14f0Smrg kgem_bo_unclean(kgem, bo); 486203b705cfSriastradh 486303b705cfSriastradh debug_alloc__bo(kgem, bo); 486403b705cfSriastradh return bo; 486503b705cfSriastradh} 486603b705cfSriastradh 486703b705cfSriastradhstruct kgem_bo *kgem_create_for_prime(struct kgem *kgem, int name, uint32_t size) 486803b705cfSriastradh{ 486903b705cfSriastradh#ifdef DRM_IOCTL_PRIME_FD_TO_HANDLE 487003b705cfSriastradh struct drm_prime_handle args; 487103b705cfSriastradh struct drm_i915_gem_get_tiling tiling; 48729a906b70Schristos struct local_i915_gem_caching caching; 487303b705cfSriastradh struct kgem_bo *bo; 48749a906b70Schristos off_t seek; 487503b705cfSriastradh 487603b705cfSriastradh DBG(("%s(name=%d)\n", __FUNCTION__, name)); 487703b705cfSriastradh 487803b705cfSriastradh VG_CLEAR(args); 487903b705cfSriastradh args.fd = name; 488003b705cfSriastradh args.flags = 0; 48819a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args)) { 48829a906b70Schristos DBG(("%s(name=%d) fd-to-handle failed, ret=%d\n", __FUNCTION__, name, errno)); 488303b705cfSriastradh return NULL; 48849a906b70Schristos } 488503b705cfSriastradh 488603b705cfSriastradh VG_CLEAR(tiling); 488703b705cfSriastradh tiling.handle = args.handle; 48889a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling)) { 48899a906b70Schristos DBG(("%s(name=%d) get-tiling failed, ret=%d\n", __FUNCTION__, name, errno)); 489003b705cfSriastradh gem_close(kgem->fd, args.handle); 489103b705cfSriastradh return NULL; 489203b705cfSriastradh } 489303b705cfSriastradh 48949a906b70Schristos /* Query actual size, overriding specified if available */ 48959a906b70Schristos seek = lseek(args.fd, 0, SEEK_END); 48969a906b70Schristos DBG(("%s: estimated size=%ld, actual=%lld\n", 48979a906b70Schristos __FUNCTION__, (long)size, (long long)seek)); 48989a906b70Schristos if (seek != -1) { 48999a906b70Schristos if (size > seek) { 49009a906b70Schristos DBG(("%s(name=%d) estimated required size [%d] is larger than actual [%ld]\n", __FUNCTION__, name, size, (long)seek)); 49019a906b70Schristos gem_close(kgem->fd, args.handle); 49029a906b70Schristos return NULL; 49039a906b70Schristos } 49049a906b70Schristos size = seek; 49059a906b70Schristos } 49069a906b70Schristos 490703b705cfSriastradh DBG(("%s: new handle=%d, tiling=%d\n", __FUNCTION__, 490803b705cfSriastradh args.handle, tiling.tiling_mode)); 490903b705cfSriastradh bo = __kgem_bo_alloc(args.handle, NUM_PAGES(size)); 491003b705cfSriastradh if (bo == NULL) { 491103b705cfSriastradh gem_close(kgem->fd, args.handle); 491203b705cfSriastradh return NULL; 491303b705cfSriastradh } 491403b705cfSriastradh 49159a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 491603b705cfSriastradh bo->tiling = tiling.tiling_mode; 491703b705cfSriastradh bo->reusable = false; 49189a906b70Schristos bo->prime = true; 49199a906b70Schristos bo->domain = DOMAIN_NONE; 49209a906b70Schristos 49219a906b70Schristos /* is this a special bo (e.g. scanout or CPU coherent)? */ 49229a906b70Schristos 49239a906b70Schristos VG_CLEAR(caching); 49249a906b70Schristos caching.handle = args.handle; 49259a906b70Schristos caching.caching = kgem->has_llc; 49269a906b70Schristos (void)drmIoctl(kgem->fd, LOCAL_IOCTL_I915_GEM_GET_CACHING, &caching); 49279a906b70Schristos DBG(("%s: imported handle=%d has caching %d\n", __FUNCTION__, args.handle, caching.caching)); 49289a906b70Schristos switch (caching.caching) { 49299a906b70Schristos case 0: 49309a906b70Schristos if (kgem->has_llc) { 49319a906b70Schristos DBG(("%s: interpreting handle=%d as a foreign scanout\n", 49329a906b70Schristos __FUNCTION__, args.handle)); 49339a906b70Schristos bo->scanout = true; 49349a906b70Schristos } 49359a906b70Schristos break; 49369a906b70Schristos case 1: 49379a906b70Schristos if (!kgem->has_llc) { 49389a906b70Schristos DBG(("%s: interpreting handle=%d as a foreign snooped buffer\n", 49399a906b70Schristos __FUNCTION__, args.handle)); 49409a906b70Schristos bo->snoop = true; 49419a906b70Schristos if (bo->tiling) { 49429a906b70Schristos DBG(("%s: illegal snooped tiled buffer\n", __FUNCTION__)); 49439a906b70Schristos kgem_bo_free(kgem, bo); 49449a906b70Schristos return NULL; 49459a906b70Schristos } 49469a906b70Schristos } 49479a906b70Schristos break; 49489a906b70Schristos case 2: 49499a906b70Schristos DBG(("%s: interpreting handle=%d as a foreign scanout\n", 49509a906b70Schristos __FUNCTION__, args.handle)); 49519a906b70Schristos bo->scanout = true; 49529a906b70Schristos break; 49539a906b70Schristos } 495403b705cfSriastradh 495503b705cfSriastradh debug_alloc__bo(kgem, bo); 495603b705cfSriastradh return bo; 495703b705cfSriastradh#else 495803b705cfSriastradh return NULL; 495903b705cfSriastradh#endif 496003b705cfSriastradh} 496103b705cfSriastradh 496203b705cfSriastradhint kgem_bo_export_to_prime(struct kgem *kgem, struct kgem_bo *bo) 496303b705cfSriastradh{ 496403b705cfSriastradh#if defined(DRM_IOCTL_PRIME_HANDLE_TO_FD) && defined(O_CLOEXEC) 496503b705cfSriastradh struct drm_prime_handle args; 496603b705cfSriastradh 496763ef14f0Smrg assert(kgem_bo_is_fenced(kgem, bo)); 496863ef14f0Smrg 496903b705cfSriastradh VG_CLEAR(args); 497003b705cfSriastradh args.handle = bo->handle; 497103b705cfSriastradh args.flags = O_CLOEXEC; 497203b705cfSriastradh 49739a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args)) 497403b705cfSriastradh return -1; 497503b705cfSriastradh 497603b705cfSriastradh bo->reusable = false; 497703b705cfSriastradh return args.fd; 497803b705cfSriastradh#else 497903b705cfSriastradh return -1; 498003b705cfSriastradh#endif 498103b705cfSriastradh} 498203b705cfSriastradh 498303b705cfSriastradhstruct kgem_bo *kgem_create_linear(struct kgem *kgem, int size, unsigned flags) 498403b705cfSriastradh{ 498503b705cfSriastradh struct kgem_bo *bo; 498603b705cfSriastradh uint32_t handle; 498703b705cfSriastradh 498803b705cfSriastradh DBG(("%s(%d)\n", __FUNCTION__, size)); 498903b705cfSriastradh assert(size); 499003b705cfSriastradh 499103b705cfSriastradh if (flags & CREATE_GTT_MAP && kgem->has_llc) { 499203b705cfSriastradh flags &= ~CREATE_GTT_MAP; 499303b705cfSriastradh flags |= CREATE_CPU_MAP; 499403b705cfSriastradh } 499503b705cfSriastradh 499603b705cfSriastradh size = NUM_PAGES(size); 4997813957e3Ssnj if ((flags & CREATE_UNCACHED) == 0) { 4998813957e3Ssnj bo = search_linear_cache(kgem, size, CREATE_INACTIVE | flags); 4999813957e3Ssnj if (bo) { 500063ef14f0Smrg assert(!bo->purged); 500163ef14f0Smrg assert(!bo->delta); 5002813957e3Ssnj assert(bo->domain != DOMAIN_GPU); 5003813957e3Ssnj ASSERT_IDLE(kgem, bo->handle); 5004813957e3Ssnj bo->refcnt = 1; 5005813957e3Ssnj return bo; 5006813957e3Ssnj } 500703b705cfSriastradh 5008813957e3Ssnj if (flags & CREATE_CACHED) 5009813957e3Ssnj return NULL; 5010813957e3Ssnj } 501103b705cfSriastradh 501203b705cfSriastradh handle = gem_create(kgem->fd, size); 501303b705cfSriastradh if (handle == 0) 501403b705cfSriastradh return NULL; 501503b705cfSriastradh 501603b705cfSriastradh DBG(("%s: new handle=%d, num_pages=%d\n", __FUNCTION__, handle, size)); 501703b705cfSriastradh bo = __kgem_bo_alloc(handle, size); 501803b705cfSriastradh if (bo == NULL) { 501903b705cfSriastradh gem_close(kgem->fd, handle); 502003b705cfSriastradh return NULL; 502103b705cfSriastradh } 502203b705cfSriastradh 502303b705cfSriastradh debug_alloc__bo(kgem, bo); 502403b705cfSriastradh return bo; 502503b705cfSriastradh} 502603b705cfSriastradh 502703b705cfSriastradhint kgem_choose_tiling(struct kgem *kgem, int tiling, int width, int height, int bpp) 502803b705cfSriastradh{ 502903b705cfSriastradh if (DBG_NO_TILING) 503003b705cfSriastradh return tiling < 0 ? tiling : I915_TILING_NONE; 503103b705cfSriastradh 503203b705cfSriastradh if (kgem->gen < 040) { 503303b705cfSriastradh if (tiling && width * bpp > 8192 * 8) { 503403b705cfSriastradh DBG(("%s: pitch too large for tliing [%d]\n", 503503b705cfSriastradh __FUNCTION__, width*bpp/8)); 503603b705cfSriastradh tiling = I915_TILING_NONE; 503703b705cfSriastradh goto done; 503803b705cfSriastradh } 503903b705cfSriastradh } else { 504003b705cfSriastradh if (width*bpp > (MAXSHORT-512) * 8) { 504103b705cfSriastradh if (tiling > 0) 504203b705cfSriastradh tiling = -tiling; 504303b705cfSriastradh else if (tiling == 0) 504403b705cfSriastradh tiling = -I915_TILING_X; 504503b705cfSriastradh DBG(("%s: large pitch [%d], forcing TILING [%d]\n", 504603b705cfSriastradh __FUNCTION__, width*bpp/8, tiling)); 504703b705cfSriastradh } else if (tiling && (width|height) > 8192) { 504803b705cfSriastradh DBG(("%s: large tiled buffer [%dx%d], forcing TILING_X\n", 504903b705cfSriastradh __FUNCTION__, width, height)); 505003b705cfSriastradh tiling = -I915_TILING_X; 505103b705cfSriastradh } 505203b705cfSriastradh 505303b705cfSriastradh /* fences limited to 128k (256k on ivb) */ 505403b705cfSriastradh assert(width * bpp <= 128 * 1024 * 8); 505503b705cfSriastradh } 505603b705cfSriastradh 505703b705cfSriastradh if (tiling < 0) 505803b705cfSriastradh return tiling; 505903b705cfSriastradh 50609a906b70Schristos if (tiling == I915_TILING_Y && !kgem->can_render_y) 50619a906b70Schristos tiling = I915_TILING_X; 50629a906b70Schristos 506303b705cfSriastradh if (tiling && (height == 1 || width == 1)) { 506403b705cfSriastradh DBG(("%s: disabling tiling [%dx%d] for single row/col\n", 506503b705cfSriastradh __FUNCTION__,width, height)); 506603b705cfSriastradh tiling = I915_TILING_NONE; 506703b705cfSriastradh goto done; 506803b705cfSriastradh } 506903b705cfSriastradh if (tiling == I915_TILING_Y && height <= 16) { 507003b705cfSriastradh DBG(("%s: too short [%d] for TILING_Y\n", 507103b705cfSriastradh __FUNCTION__,height)); 507203b705cfSriastradh tiling = I915_TILING_X; 507303b705cfSriastradh } 507403b705cfSriastradh if (tiling && width * bpp > 8 * (4096 - 64)) { 507503b705cfSriastradh DBG(("%s: TLB miss between lines %dx%d (pitch=%d), forcing tiling %d\n", 507603b705cfSriastradh __FUNCTION__, 507703b705cfSriastradh width, height, width*bpp/8, 507803b705cfSriastradh tiling)); 507903b705cfSriastradh return -tiling; 508003b705cfSriastradh } 508103b705cfSriastradh if (tiling == I915_TILING_X && height < 4) { 508203b705cfSriastradh DBG(("%s: too short [%d] for TILING_X\n", 508303b705cfSriastradh __FUNCTION__, height)); 508403b705cfSriastradh tiling = I915_TILING_NONE; 508503b705cfSriastradh goto done; 508603b705cfSriastradh } 508703b705cfSriastradh 50889a906b70Schristos if (tiling == I915_TILING_X && width * bpp <= 8*512) { 508903b705cfSriastradh DBG(("%s: too thin [width %d, %d bpp] for TILING_X\n", 509003b705cfSriastradh __FUNCTION__, width, bpp)); 509103b705cfSriastradh tiling = I915_TILING_NONE; 509203b705cfSriastradh goto done; 509303b705cfSriastradh } 50949a906b70Schristos if (tiling == I915_TILING_Y && width * bpp < 8*128) { 509503b705cfSriastradh DBG(("%s: too thin [%d] for TILING_Y\n", 509603b705cfSriastradh __FUNCTION__, width)); 509703b705cfSriastradh tiling = I915_TILING_NONE; 509803b705cfSriastradh goto done; 509903b705cfSriastradh } 510003b705cfSriastradh 510103b705cfSriastradh if (tiling && ALIGN(height, 2) * ALIGN(width*bpp, 8*64) <= 4096 * 8) { 510203b705cfSriastradh DBG(("%s: too small [%d bytes] for TILING_%c\n", __FUNCTION__, 510303b705cfSriastradh ALIGN(height, 2) * ALIGN(width*bpp, 8*64) / 8, 510403b705cfSriastradh tiling == I915_TILING_X ? 'X' : 'Y')); 510503b705cfSriastradh tiling = I915_TILING_NONE; 510603b705cfSriastradh goto done; 510703b705cfSriastradh } 510803b705cfSriastradh 510903b705cfSriastradh if (tiling && width * bpp >= 8 * 4096 / 2) { 511003b705cfSriastradh DBG(("%s: TLB near-miss between lines %dx%d (pitch=%d), forcing tiling %d\n", 511103b705cfSriastradh __FUNCTION__, 511203b705cfSriastradh width, height, width*bpp/8, 511303b705cfSriastradh tiling)); 511403b705cfSriastradh return -tiling; 511503b705cfSriastradh } 511603b705cfSriastradh 511703b705cfSriastradhdone: 511803b705cfSriastradh DBG(("%s: %dx%d -> %d\n", __FUNCTION__, width, height, tiling)); 511903b705cfSriastradh return tiling; 512003b705cfSriastradh} 512103b705cfSriastradh 512203b705cfSriastradhstatic int bits_per_pixel(int depth) 512303b705cfSriastradh{ 512403b705cfSriastradh switch (depth) { 512503b705cfSriastradh case 8: return 8; 512603b705cfSriastradh case 15: 512703b705cfSriastradh case 16: return 16; 512803b705cfSriastradh case 24: 512903b705cfSriastradh case 30: 513003b705cfSriastradh case 32: return 32; 513103b705cfSriastradh default: return 0; 513203b705cfSriastradh } 513303b705cfSriastradh} 513403b705cfSriastradh 513503b705cfSriastradhunsigned kgem_can_create_2d(struct kgem *kgem, 513603b705cfSriastradh int width, int height, int depth) 513703b705cfSriastradh{ 513803b705cfSriastradh uint32_t pitch, size; 513903b705cfSriastradh unsigned flags = 0; 514003b705cfSriastradh int tiling; 514103b705cfSriastradh int bpp; 514203b705cfSriastradh 514303b705cfSriastradh DBG(("%s: %dx%d @ %d\n", __FUNCTION__, width, height, depth)); 514403b705cfSriastradh 514503b705cfSriastradh bpp = bits_per_pixel(depth); 514603b705cfSriastradh if (bpp == 0) { 514703b705cfSriastradh DBG(("%s: unhandled depth %d\n", __FUNCTION__, depth)); 514803b705cfSriastradh return 0; 514903b705cfSriastradh } 515003b705cfSriastradh 515103b705cfSriastradh if (width > MAXSHORT || height > MAXSHORT) { 515203b705cfSriastradh DBG(("%s: unhandled size %dx%d\n", 515303b705cfSriastradh __FUNCTION__, width, height)); 515403b705cfSriastradh return 0; 515503b705cfSriastradh } 515603b705cfSriastradh 515703b705cfSriastradh size = kgem_surface_size(kgem, false, 0, 515803b705cfSriastradh width, height, bpp, 515903b705cfSriastradh I915_TILING_NONE, &pitch); 516003b705cfSriastradh DBG(("%s: untiled size=%d\n", __FUNCTION__, size)); 516103b705cfSriastradh if (size > 0) { 516203b705cfSriastradh if (size <= kgem->max_cpu_size) 516303b705cfSriastradh flags |= KGEM_CAN_CREATE_CPU; 51649a906b70Schristos if (size > 4096 && size <= kgem->max_gpu_size) 516503b705cfSriastradh flags |= KGEM_CAN_CREATE_GPU; 5166813957e3Ssnj if (size <= PAGE_SIZE*kgem->aperture_mappable/4 || kgem->has_wc_mmap) 516703b705cfSriastradh flags |= KGEM_CAN_CREATE_GTT; 516803b705cfSriastradh if (size > kgem->large_object_size) 516903b705cfSriastradh flags |= KGEM_CAN_CREATE_LARGE; 517003b705cfSriastradh if (size > kgem->max_object_size) { 517103b705cfSriastradh DBG(("%s: too large (untiled) %d > %d\n", 517203b705cfSriastradh __FUNCTION__, size, kgem->max_object_size)); 517303b705cfSriastradh return 0; 517403b705cfSriastradh } 517503b705cfSriastradh } 517603b705cfSriastradh 517703b705cfSriastradh tiling = kgem_choose_tiling(kgem, I915_TILING_X, 517803b705cfSriastradh width, height, bpp); 517903b705cfSriastradh if (tiling != I915_TILING_NONE) { 518003b705cfSriastradh size = kgem_surface_size(kgem, false, 0, 518103b705cfSriastradh width, height, bpp, tiling, 518203b705cfSriastradh &pitch); 518303b705cfSriastradh DBG(("%s: tiled[%d] size=%d\n", __FUNCTION__, tiling, size)); 518403b705cfSriastradh if (size > 0 && size <= kgem->max_gpu_size) 51859a906b70Schristos flags |= KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_TILED; 51869a906b70Schristos if (size > 0 && size <= PAGE_SIZE*kgem->aperture_mappable/4) 518703b705cfSriastradh flags |= KGEM_CAN_CREATE_GTT; 51889a906b70Schristos if (size > PAGE_SIZE*kgem->aperture_mappable/4) 51899a906b70Schristos flags &= ~KGEM_CAN_CREATE_GTT; 519003b705cfSriastradh if (size > kgem->large_object_size) 519103b705cfSriastradh flags |= KGEM_CAN_CREATE_LARGE; 519203b705cfSriastradh if (size > kgem->max_object_size) { 519303b705cfSriastradh DBG(("%s: too large (tiled) %d > %d\n", 519403b705cfSriastradh __FUNCTION__, size, kgem->max_object_size)); 519503b705cfSriastradh return 0; 519603b705cfSriastradh } 51979a906b70Schristos if (kgem->gen < 040) { 51989a906b70Schristos int fence_size = 1024 * 1024; 51999a906b70Schristos while (fence_size < size) 52009a906b70Schristos fence_size <<= 1; 52019a906b70Schristos if (fence_size > kgem->max_gpu_size) 52029a906b70Schristos flags &= ~KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_TILED; 52039a906b70Schristos if (fence_size > PAGE_SIZE*kgem->aperture_fenceable/4) 52049a906b70Schristos flags &= ~KGEM_CAN_CREATE_GTT; 52059a906b70Schristos } 520603b705cfSriastradh } 520703b705cfSriastradh 520803b705cfSriastradh return flags; 520903b705cfSriastradh} 521003b705cfSriastradh 521103b705cfSriastradhinline int kgem_bo_fenced_size(struct kgem *kgem, struct kgem_bo *bo) 521203b705cfSriastradh{ 521303b705cfSriastradh unsigned int size; 521403b705cfSriastradh 521503b705cfSriastradh assert(bo->tiling); 521603b705cfSriastradh assert_tiling(kgem, bo); 521703b705cfSriastradh assert(kgem->gen < 040); 521803b705cfSriastradh 521903b705cfSriastradh if (kgem->gen < 030) 52209a906b70Schristos size = 512 * 1024 / PAGE_SIZE; 522103b705cfSriastradh else 52229a906b70Schristos size = 1024 * 1024 / PAGE_SIZE; 52239a906b70Schristos while (size < num_pages(bo)) 52249a906b70Schristos size <<= 1; 522503b705cfSriastradh 522603b705cfSriastradh return size; 522703b705cfSriastradh} 522803b705cfSriastradh 522903b705cfSriastradhstatic struct kgem_bo * 523003b705cfSriastradh__kgem_bo_create_as_display(struct kgem *kgem, int size, int tiling, int pitch) 523103b705cfSriastradh{ 523203b705cfSriastradh struct local_i915_gem_create2 args; 523303b705cfSriastradh struct kgem_bo *bo; 523403b705cfSriastradh 523503b705cfSriastradh if (!kgem->has_create2) 523603b705cfSriastradh return NULL; 523703b705cfSriastradh 523803b705cfSriastradh memset(&args, 0, sizeof(args)); 523903b705cfSriastradh args.size = size * PAGE_SIZE; 524003b705cfSriastradh args.placement = LOCAL_I915_CREATE_PLACEMENT_STOLEN; 524103b705cfSriastradh args.caching = DISPLAY; 524203b705cfSriastradh args.tiling_mode = tiling; 524303b705cfSriastradh args.stride = pitch; 524403b705cfSriastradh 52459a906b70Schristos if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_CREATE2, &args)) { 524603b705cfSriastradh args.placement = LOCAL_I915_CREATE_PLACEMENT_SYSTEM; 52479a906b70Schristos if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_CREATE2, &args)) 524803b705cfSriastradh return NULL; 524903b705cfSriastradh } 525003b705cfSriastradh 525103b705cfSriastradh bo = __kgem_bo_alloc(args.handle, size); 525203b705cfSriastradh if (bo == NULL) { 525303b705cfSriastradh gem_close(kgem->fd, args.handle); 525403b705cfSriastradh return NULL; 525503b705cfSriastradh } 525603b705cfSriastradh 525703b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 525803b705cfSriastradh bo->tiling = tiling; 525903b705cfSriastradh bo->pitch = pitch; 526003b705cfSriastradh if (args.placement == LOCAL_I915_CREATE_PLACEMENT_STOLEN) { 526103b705cfSriastradh bo->purged = true; /* for asserts against CPU access */ 526203b705cfSriastradh } 526303b705cfSriastradh bo->reusable = false; /* so that unclaimed scanouts are freed */ 526403b705cfSriastradh bo->domain = DOMAIN_NONE; 526503b705cfSriastradh 526603b705cfSriastradh if (__kgem_busy(kgem, bo->handle)) { 52679a906b70Schristos assert(bo->exec == NULL); 526803b705cfSriastradh list_add(&bo->request, &kgem->flushing); 526903b705cfSriastradh bo->rq = (void *)kgem; 52709a906b70Schristos kgem->need_retire = true; 527103b705cfSriastradh } 527203b705cfSriastradh 527303b705cfSriastradh assert_tiling(kgem, bo); 527403b705cfSriastradh debug_alloc__bo(kgem, bo); 527503b705cfSriastradh 527603b705cfSriastradh return bo; 527703b705cfSriastradh} 527803b705cfSriastradh 52799a906b70Schristosstatic void __kgem_bo_make_scanout(struct kgem *kgem, 52809a906b70Schristos struct kgem_bo *bo, 52819a906b70Schristos int width, int height) 52829a906b70Schristos{ 528363ef14f0Smrg ScrnInfoPtr scrn = __to_sna(kgem)->scrn; 52849a906b70Schristos struct drm_mode_fb_cmd arg; 52859a906b70Schristos 52869a906b70Schristos assert(bo->proxy == NULL); 52879a906b70Schristos 52889a906b70Schristos if (!scrn->vtSema) 52899a906b70Schristos return; 52909a906b70Schristos 52919a906b70Schristos DBG(("%s: create fb %dx%d@%d/%d\n", 52929a906b70Schristos __FUNCTION__, width, height, scrn->depth, scrn->bitsPerPixel)); 52939a906b70Schristos 52949a906b70Schristos VG_CLEAR(arg); 52959a906b70Schristos arg.width = width; 52969a906b70Schristos arg.height = height; 52979a906b70Schristos arg.pitch = bo->pitch; 52989a906b70Schristos arg.bpp = scrn->bitsPerPixel; 52999a906b70Schristos arg.depth = scrn->depth; 53009a906b70Schristos arg.handle = bo->handle; 53019a906b70Schristos 53029a906b70Schristos /* First move the scanout out of cached memory */ 53039a906b70Schristos if (kgem->has_llc) { 53049a906b70Schristos if (!gem_set_caching(kgem->fd, bo->handle, DISPLAY) && 53059a906b70Schristos !gem_set_caching(kgem->fd, bo->handle, UNCACHED)) 53069a906b70Schristos return; 53079a906b70Schristos } 53089a906b70Schristos 53099a906b70Schristos bo->scanout = true; 53109a906b70Schristos 53119a906b70Schristos /* Then pre-emptively move the object into the mappable 53129a906b70Schristos * portion to avoid rebinding later when busy. 53139a906b70Schristos */ 53149a906b70Schristos if (bo->map__gtt == NULL) 53159a906b70Schristos bo->map__gtt = __kgem_bo_map__gtt(kgem, bo); 53169a906b70Schristos if (bo->map__gtt) { 5317813957e3Ssnj if (sigtrap_get() == 0) { 5318813957e3Ssnj *(uint32_t *)bo->map__gtt = 0; 5319813957e3Ssnj sigtrap_put(); 5320813957e3Ssnj } 53219a906b70Schristos bo->domain = DOMAIN_GTT; 53229a906b70Schristos } 53239a906b70Schristos 53249a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg) == 0) { 53259a906b70Schristos DBG(("%s: attached fb=%d to handle=%d\n", 53269a906b70Schristos __FUNCTION__, arg.fb_id, arg.handle)); 53279a906b70Schristos bo->delta = arg.fb_id; 53289a906b70Schristos } 53299a906b70Schristos} 53309a906b70Schristos 533163ef14f0Smrgstatic bool tiling_changed(struct kgem_bo *bo, int tiling, int pitch) 533263ef14f0Smrg{ 533363ef14f0Smrg if (tiling != bo->tiling) 533463ef14f0Smrg return true; 533563ef14f0Smrg 533663ef14f0Smrg return tiling != I915_TILING_NONE && pitch != bo->pitch; 533763ef14f0Smrg} 533863ef14f0Smrg 533963ef14f0Smrgstatic void set_gpu_tiling(struct kgem *kgem, 534063ef14f0Smrg struct kgem_bo *bo, 534163ef14f0Smrg int tiling, int pitch) 534263ef14f0Smrg{ 534363ef14f0Smrg DBG(("%s: handle=%d, tiling=%d, pitch=%d\n", 534463ef14f0Smrg __FUNCTION__, bo->handle, tiling, pitch)); 534563ef14f0Smrg 534663ef14f0Smrg if (tiling_changed(bo, tiling, pitch) && bo->map__gtt) { 534763ef14f0Smrg if (!list_is_empty(&bo->vma)) { 534863ef14f0Smrg list_del(&bo->vma); 534963ef14f0Smrg kgem->vma[0].count--; 535063ef14f0Smrg } 535163ef14f0Smrg munmap(bo->map__gtt, bytes(bo)); 535263ef14f0Smrg bo->map__gtt = NULL; 535363ef14f0Smrg } 535463ef14f0Smrg 535563ef14f0Smrg bo->tiling = tiling; 535663ef14f0Smrg bo->pitch = pitch; 535763ef14f0Smrg} 535863ef14f0Smrg 535963ef14f0Smrgbool kgem_bo_is_fenced(struct kgem *kgem, struct kgem_bo *bo) 536063ef14f0Smrg{ 536163ef14f0Smrg struct drm_i915_gem_get_tiling tiling; 536263ef14f0Smrg 536363ef14f0Smrg assert(kgem); 536463ef14f0Smrg assert(bo); 536563ef14f0Smrg 536663ef14f0Smrg VG_CLEAR(tiling); 536763ef14f0Smrg tiling.handle = bo->handle; 536863ef14f0Smrg tiling.tiling_mode = bo->tiling; 536963ef14f0Smrg (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling); 537063ef14f0Smrg return tiling.tiling_mode == bo->tiling; /* assume pitch is fine! */ 537163ef14f0Smrg} 537263ef14f0Smrg 537303b705cfSriastradhstruct kgem_bo *kgem_create_2d(struct kgem *kgem, 537403b705cfSriastradh int width, 537503b705cfSriastradh int height, 537603b705cfSriastradh int bpp, 537703b705cfSriastradh int tiling, 537803b705cfSriastradh uint32_t flags) 537903b705cfSriastradh{ 538003b705cfSriastradh struct list *cache; 538103b705cfSriastradh struct kgem_bo *bo; 538203b705cfSriastradh uint32_t pitch, tiled_height, size; 538303b705cfSriastradh uint32_t handle; 538403b705cfSriastradh int i, bucket, retry; 538503b705cfSriastradh bool exact = flags & (CREATE_EXACT | CREATE_SCANOUT); 538603b705cfSriastradh 538703b705cfSriastradh if (tiling < 0) 538803b705cfSriastradh exact = true, tiling = -tiling; 538903b705cfSriastradh 539003b705cfSriastradh DBG(("%s(%dx%d, bpp=%d, tiling=%d, exact=%d, inactive=%d, cpu-mapping=%d, gtt-mapping=%d, scanout?=%d, prime?=%d, temp?=%d)\n", __FUNCTION__, 539103b705cfSriastradh width, height, bpp, tiling, exact, 539203b705cfSriastradh !!(flags & CREATE_INACTIVE), 539303b705cfSriastradh !!(flags & CREATE_CPU_MAP), 539403b705cfSriastradh !!(flags & CREATE_GTT_MAP), 539503b705cfSriastradh !!(flags & CREATE_SCANOUT), 539603b705cfSriastradh !!(flags & CREATE_PRIME), 539703b705cfSriastradh !!(flags & CREATE_TEMPORARY))); 539803b705cfSriastradh 539903b705cfSriastradh size = kgem_surface_size(kgem, kgem->has_relaxed_fencing, flags, 540003b705cfSriastradh width, height, bpp, tiling, &pitch); 54019a906b70Schristos if (size == 0) { 54029a906b70Schristos DBG(("%s: invalid surface size (too large?)\n", __FUNCTION__)); 54039a906b70Schristos return NULL; 54049a906b70Schristos } 54059a906b70Schristos 540603b705cfSriastradh size /= PAGE_SIZE; 540703b705cfSriastradh bucket = cache_bucket(size); 540803b705cfSriastradh 540903b705cfSriastradh if (flags & CREATE_SCANOUT) { 541003b705cfSriastradh struct kgem_bo *last = NULL; 541103b705cfSriastradh 541203b705cfSriastradh list_for_each_entry_reverse(bo, &kgem->scanout, list) { 541303b705cfSriastradh assert(bo->scanout); 541403b705cfSriastradh assert(!bo->flush); 54159a906b70Schristos assert(!bo->refcnt); 541603b705cfSriastradh assert_tiling(kgem, bo); 541703b705cfSriastradh 541803b705cfSriastradh if (size > num_pages(bo) || num_pages(bo) > 2*size) 541903b705cfSriastradh continue; 542003b705cfSriastradh 54219a906b70Schristos if (bo->tiling != tiling || bo->pitch != pitch) 54229a906b70Schristos /* No tiling/pitch without recreating fb */ 542303b705cfSriastradh continue; 542403b705cfSriastradh 54259a906b70Schristos if (bo->delta && !check_scanout_size(kgem, bo, width, height)) 542663ef14f0Smrg kgem_bo_rmfb(kgem, bo); 542703b705cfSriastradh 542803b705cfSriastradh if (flags & CREATE_INACTIVE && bo->rq) { 542903b705cfSriastradh last = bo; 543003b705cfSriastradh continue; 543103b705cfSriastradh } 543203b705cfSriastradh 543303b705cfSriastradh list_del(&bo->list); 543403b705cfSriastradh 543503b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 543603b705cfSriastradh DBG((" 1:from scanout: pitch=%d, tiling=%d, handle=%d, id=%d\n", 543703b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 543803b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 543903b705cfSriastradh assert_tiling(kgem, bo); 544003b705cfSriastradh bo->refcnt = 1; 544103b705cfSriastradh return bo; 544203b705cfSriastradh } 544303b705cfSriastradh 544403b705cfSriastradh if (last) { 544503b705cfSriastradh list_del(&last->list); 544603b705cfSriastradh 544703b705cfSriastradh last->unique_id = kgem_get_unique_id(kgem); 544803b705cfSriastradh DBG((" 1:from scanout: pitch=%d, tiling=%d, handle=%d, id=%d\n", 544903b705cfSriastradh last->pitch, last->tiling, last->handle, last->unique_id)); 545003b705cfSriastradh assert(last->pitch*kgem_aligned_height(kgem, height, last->tiling) <= kgem_bo_size(last)); 545103b705cfSriastradh assert_tiling(kgem, last); 545203b705cfSriastradh last->refcnt = 1; 545303b705cfSriastradh return last; 545403b705cfSriastradh } 545503b705cfSriastradh 545663ef14f0Smrg if (__to_sna(kgem)->scrn->vtSema) { 545763ef14f0Smrg ScrnInfoPtr scrn = __to_sna(kgem)->scrn; 54589a906b70Schristos 54599a906b70Schristos list_for_each_entry_reverse(bo, &kgem->scanout, list) { 54609a906b70Schristos struct drm_mode_fb_cmd arg; 54619a906b70Schristos 54629a906b70Schristos assert(bo->scanout); 54639a906b70Schristos assert(!bo->refcnt); 54649a906b70Schristos 54659a906b70Schristos if (size > num_pages(bo) || num_pages(bo) > 2*size) 54669a906b70Schristos continue; 54679a906b70Schristos 54689a906b70Schristos if (flags & CREATE_INACTIVE && bo->rq) 54699a906b70Schristos continue; 54709a906b70Schristos 54719a906b70Schristos list_del(&bo->list); 54729a906b70Schristos 54739a906b70Schristos if (bo->tiling != tiling || bo->pitch != pitch) { 54749a906b70Schristos if (bo->delta) { 54759a906b70Schristos kgem_bo_rmfb(kgem, bo); 54769a906b70Schristos bo->delta = 0; 54779a906b70Schristos } 54789a906b70Schristos 547963ef14f0Smrg if (!kgem_set_tiling(kgem, bo, 548063ef14f0Smrg tiling, pitch)) { 548163ef14f0Smrg bo->scanout = false; 548263ef14f0Smrg __kgem_bo_destroy(kgem, bo); 54839a906b70Schristos break; 54849a906b70Schristos } 54859a906b70Schristos } 54869a906b70Schristos 54879a906b70Schristos VG_CLEAR(arg); 54889a906b70Schristos arg.width = width; 54899a906b70Schristos arg.height = height; 54909a906b70Schristos arg.pitch = bo->pitch; 54919a906b70Schristos arg.bpp = scrn->bitsPerPixel; 54929a906b70Schristos arg.depth = scrn->depth; 54939a906b70Schristos arg.handle = bo->handle; 54949a906b70Schristos 54959a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg)) { 549663ef14f0Smrg bo->scanout = false; 549763ef14f0Smrg __kgem_bo_destroy(kgem, bo); 54989a906b70Schristos break; 54999a906b70Schristos } 55009a906b70Schristos 55019a906b70Schristos bo->delta = arg.fb_id; 55029a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 55039a906b70Schristos 55049a906b70Schristos DBG((" 2:from scanout: pitch=%d, tiling=%d, handle=%d, id=%d\n", 55059a906b70Schristos bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 55069a906b70Schristos assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 55079a906b70Schristos assert_tiling(kgem, bo); 55089a906b70Schristos bo->refcnt = 1; 55099a906b70Schristos return bo; 55109a906b70Schristos } 55119a906b70Schristos } 55129a906b70Schristos 551363ef14f0Smrg if (flags & CREATE_CACHED) 551463ef14f0Smrg return NULL; 551563ef14f0Smrg 551603b705cfSriastradh bo = __kgem_bo_create_as_display(kgem, size, tiling, pitch); 551703b705cfSriastradh if (bo) 551803b705cfSriastradh return bo; 55199a906b70Schristos 55209a906b70Schristos flags |= CREATE_INACTIVE; 552103b705cfSriastradh } 552203b705cfSriastradh 552303b705cfSriastradh if (bucket >= NUM_CACHE_BUCKETS) { 552403b705cfSriastradh DBG(("%s: large bo num pages=%d, bucket=%d\n", 552503b705cfSriastradh __FUNCTION__, size, bucket)); 552603b705cfSriastradh 552703b705cfSriastradh if (flags & CREATE_INACTIVE) 552803b705cfSriastradh goto large_inactive; 552903b705cfSriastradh 553003b705cfSriastradh tiled_height = kgem_aligned_height(kgem, height, tiling); 553103b705cfSriastradh 553203b705cfSriastradh list_for_each_entry(bo, &kgem->large, list) { 553303b705cfSriastradh assert(!bo->purged); 553403b705cfSriastradh assert(!bo->scanout); 553503b705cfSriastradh assert(bo->refcnt == 0); 553603b705cfSriastradh assert(bo->reusable); 553703b705cfSriastradh assert_tiling(kgem, bo); 553803b705cfSriastradh 553903b705cfSriastradh if (kgem->gen < 040) { 554003b705cfSriastradh if (bo->pitch < pitch) { 554103b705cfSriastradh DBG(("tiled and pitch too small: tiling=%d, (want %d), pitch=%d, need %d\n", 554203b705cfSriastradh bo->tiling, tiling, 554303b705cfSriastradh bo->pitch, pitch)); 554403b705cfSriastradh continue; 554503b705cfSriastradh } 554603b705cfSriastradh 554703b705cfSriastradh if (bo->pitch * tiled_height > bytes(bo)) 554803b705cfSriastradh continue; 554903b705cfSriastradh } else { 555003b705cfSriastradh if (num_pages(bo) < size) 555103b705cfSriastradh continue; 555203b705cfSriastradh 555363ef14f0Smrg if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { 555463ef14f0Smrg if (exact) { 555563ef14f0Smrg DBG(("tiled and pitch not exact: tiling=%d, (want %d), pitch=%d, need %d\n", 555663ef14f0Smrg bo->tiling, tiling, 555763ef14f0Smrg bo->pitch, pitch)); 555803b705cfSriastradh continue; 555963ef14f0Smrg } 556003b705cfSriastradh 556163ef14f0Smrg set_gpu_tiling(kgem, bo, tiling, pitch); 556203b705cfSriastradh } 556303b705cfSriastradh } 556403b705cfSriastradh 556503b705cfSriastradh kgem_bo_remove_from_active(kgem, bo); 556603b705cfSriastradh 556703b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 556803b705cfSriastradh bo->delta = 0; 556903b705cfSriastradh DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 557003b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 557103b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 557203b705cfSriastradh assert_tiling(kgem, bo); 557303b705cfSriastradh bo->refcnt = 1; 557403b705cfSriastradh return bo; 557503b705cfSriastradh } 557603b705cfSriastradh 557703b705cfSriastradhlarge_inactive: 557803b705cfSriastradh __kgem_throttle_retire(kgem, flags); 557903b705cfSriastradh list_for_each_entry(bo, &kgem->large_inactive, list) { 558003b705cfSriastradh assert(bo->refcnt == 0); 558103b705cfSriastradh assert(bo->reusable); 558203b705cfSriastradh assert(!bo->scanout); 558303b705cfSriastradh assert_tiling(kgem, bo); 558403b705cfSriastradh 558503b705cfSriastradh if (size > num_pages(bo)) 558603b705cfSriastradh continue; 558703b705cfSriastradh 558863ef14f0Smrg if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { 558963ef14f0Smrg if (kgem->gen >= 040 && !exact) 559063ef14f0Smrg set_gpu_tiling(kgem, bo, tiling, pitch); 559163ef14f0Smrg else 559203b705cfSriastradh continue; 559303b705cfSriastradh } 559403b705cfSriastradh 559503b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { 559603b705cfSriastradh kgem_bo_free(kgem, bo); 559703b705cfSriastradh break; 559803b705cfSriastradh } 559903b705cfSriastradh 560003b705cfSriastradh list_del(&bo->list); 560103b705cfSriastradh 560203b705cfSriastradh assert(bo->domain != DOMAIN_GPU); 560303b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 560403b705cfSriastradh bo->delta = 0; 560503b705cfSriastradh DBG((" 1:from large inactive: pitch=%d, tiling=%d, handle=%d, id=%d\n", 560603b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 560703b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 560803b705cfSriastradh assert_tiling(kgem, bo); 560903b705cfSriastradh bo->refcnt = 1; 56109a906b70Schristos 56119a906b70Schristos if (flags & CREATE_SCANOUT) 56129a906b70Schristos __kgem_bo_make_scanout(kgem, bo, width, height); 56139a906b70Schristos 561403b705cfSriastradh return bo; 561503b705cfSriastradh } 561603b705cfSriastradh 561703b705cfSriastradh goto create; 561803b705cfSriastradh } 561903b705cfSriastradh 562003b705cfSriastradh if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { 562103b705cfSriastradh int for_cpu = !!(flags & CREATE_CPU_MAP); 562203b705cfSriastradh if (kgem->has_llc && tiling == I915_TILING_NONE) 562303b705cfSriastradh for_cpu = 1; 562403b705cfSriastradh /* We presume that we will need to upload to this bo, 562503b705cfSriastradh * and so would prefer to have an active VMA. 562603b705cfSriastradh */ 562703b705cfSriastradh cache = &kgem->vma[for_cpu].inactive[bucket]; 562803b705cfSriastradh do { 562903b705cfSriastradh list_for_each_entry(bo, cache, vma) { 563003b705cfSriastradh assert(bucket(bo) == bucket); 563103b705cfSriastradh assert(bo->refcnt == 0); 563203b705cfSriastradh assert(!bo->scanout); 5633813957e3Ssnj assert(for_cpu ? !!bo->map__cpu : (bo->map__gtt || bo->map__wc)); 563403b705cfSriastradh assert(bo->rq == NULL); 56359a906b70Schristos assert(bo->exec == NULL); 563603b705cfSriastradh assert(list_is_empty(&bo->request)); 563703b705cfSriastradh assert(bo->flush == false); 563803b705cfSriastradh assert_tiling(kgem, bo); 563903b705cfSriastradh 564003b705cfSriastradh if (size > num_pages(bo)) { 564103b705cfSriastradh DBG(("inactive too small: %d < %d\n", 564203b705cfSriastradh num_pages(bo), size)); 564303b705cfSriastradh continue; 564403b705cfSriastradh } 564503b705cfSriastradh 56469a906b70Schristos if (flags & UNCACHED && !kgem->has_llc && bo->domain != DOMAIN_CPU) 56479a906b70Schristos continue; 56489a906b70Schristos 564903b705cfSriastradh if (bo->tiling != tiling || 565003b705cfSriastradh (tiling != I915_TILING_NONE && bo->pitch != pitch)) { 56519a906b70Schristos if (bo->map__gtt || 565263ef14f0Smrg !kgem_set_tiling(kgem, bo, 565363ef14f0Smrg tiling, pitch)) { 56549a906b70Schristos DBG(("inactive GTT vma with wrong tiling: %d < %d\n", 56559a906b70Schristos bo->tiling, tiling)); 565663ef14f0Smrg kgem_bo_free(kgem, bo); 565763ef14f0Smrg break; 56589a906b70Schristos } 565903b705cfSriastradh } 566003b705cfSriastradh 566103b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { 566203b705cfSriastradh kgem_bo_free(kgem, bo); 566303b705cfSriastradh break; 566403b705cfSriastradh } 566503b705cfSriastradh 566663ef14f0Smrg if (tiling == I915_TILING_NONE) 566763ef14f0Smrg bo->pitch = pitch; 566863ef14f0Smrg 566903b705cfSriastradh assert(bo->tiling == tiling); 567063ef14f0Smrg assert(bo->pitch >= pitch); 567103b705cfSriastradh bo->delta = 0; 567203b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 567303b705cfSriastradh 567403b705cfSriastradh kgem_bo_remove_from_inactive(kgem, bo); 56759a906b70Schristos assert(list_is_empty(&bo->list)); 56769a906b70Schristos assert(list_is_empty(&bo->vma)); 567703b705cfSriastradh 567803b705cfSriastradh DBG((" from inactive vma: pitch=%d, tiling=%d: handle=%d, id=%d\n", 567903b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 568003b705cfSriastradh assert(bo->reusable); 568103b705cfSriastradh assert(bo->domain != DOMAIN_GPU); 568203b705cfSriastradh ASSERT_IDLE(kgem, bo->handle); 568303b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 568403b705cfSriastradh assert_tiling(kgem, bo); 568503b705cfSriastradh bo->refcnt = 1; 568603b705cfSriastradh return bo; 568703b705cfSriastradh } 568803b705cfSriastradh } while (!list_is_empty(cache) && 568903b705cfSriastradh __kgem_throttle_retire(kgem, flags)); 569003b705cfSriastradh 569103b705cfSriastradh if (flags & CREATE_CPU_MAP && !kgem->has_llc) { 569203b705cfSriastradh if (list_is_empty(&kgem->active[bucket][tiling]) && 569303b705cfSriastradh list_is_empty(&kgem->inactive[bucket])) 569403b705cfSriastradh flags &= ~CREATE_CACHED; 569503b705cfSriastradh 569603b705cfSriastradh goto create; 569703b705cfSriastradh } 569803b705cfSriastradh } 569903b705cfSriastradh 570003b705cfSriastradh if (flags & CREATE_INACTIVE) 570103b705cfSriastradh goto skip_active_search; 570203b705cfSriastradh 570303b705cfSriastradh /* Best active match */ 570403b705cfSriastradh retry = NUM_CACHE_BUCKETS - bucket; 570503b705cfSriastradh if (retry > 3 && (flags & CREATE_TEMPORARY) == 0) 570603b705cfSriastradh retry = 3; 57079a906b70Schristossearch_active: 570803b705cfSriastradh assert(bucket < NUM_CACHE_BUCKETS); 570903b705cfSriastradh cache = &kgem->active[bucket][tiling]; 571003b705cfSriastradh if (tiling) { 571103b705cfSriastradh tiled_height = kgem_aligned_height(kgem, height, tiling); 571203b705cfSriastradh list_for_each_entry(bo, cache, list) { 571303b705cfSriastradh assert(!bo->purged); 571403b705cfSriastradh assert(bo->refcnt == 0); 571503b705cfSriastradh assert(bucket(bo) == bucket); 571603b705cfSriastradh assert(bo->reusable); 571703b705cfSriastradh assert(bo->tiling == tiling); 571803b705cfSriastradh assert(bo->flush == false); 571903b705cfSriastradh assert(!bo->scanout); 572003b705cfSriastradh assert_tiling(kgem, bo); 572103b705cfSriastradh 572203b705cfSriastradh if (kgem->gen < 040) { 572303b705cfSriastradh if (bo->pitch < pitch) { 572403b705cfSriastradh DBG(("tiled and pitch too small: tiling=%d, (want %d), pitch=%d, need %d\n", 572503b705cfSriastradh bo->tiling, tiling, 572603b705cfSriastradh bo->pitch, pitch)); 572703b705cfSriastradh continue; 572803b705cfSriastradh } 572903b705cfSriastradh 573003b705cfSriastradh if (bo->pitch * tiled_height > bytes(bo)) 573103b705cfSriastradh continue; 573203b705cfSriastradh } else { 573303b705cfSriastradh if (num_pages(bo) < size) 573403b705cfSriastradh continue; 573503b705cfSriastradh 573663ef14f0Smrg if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { 573763ef14f0Smrg if (exact) { 573863ef14f0Smrg DBG(("tiled and pitch not exact: tiling=%d, (want %d), pitch=%d, need %d\n", 573963ef14f0Smrg bo->tiling, tiling, 574063ef14f0Smrg bo->pitch, pitch)); 574103b705cfSriastradh continue; 574263ef14f0Smrg } 574303b705cfSriastradh 574463ef14f0Smrg set_gpu_tiling(kgem, bo, tiling, pitch); 574503b705cfSriastradh } 574603b705cfSriastradh } 574763ef14f0Smrg assert(bo->tiling == tiling); 574863ef14f0Smrg assert(bo->pitch >= pitch); 574903b705cfSriastradh 575003b705cfSriastradh kgem_bo_remove_from_active(kgem, bo); 575103b705cfSriastradh 575203b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 575303b705cfSriastradh bo->delta = 0; 575403b705cfSriastradh DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 575503b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 575603b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 575703b705cfSriastradh assert_tiling(kgem, bo); 575803b705cfSriastradh bo->refcnt = 1; 575903b705cfSriastradh return bo; 576003b705cfSriastradh } 576103b705cfSriastradh } else { 576203b705cfSriastradh list_for_each_entry(bo, cache, list) { 576303b705cfSriastradh assert(bucket(bo) == bucket); 576403b705cfSriastradh assert(!bo->purged); 576503b705cfSriastradh assert(bo->refcnt == 0); 576603b705cfSriastradh assert(bo->reusable); 576703b705cfSriastradh assert(!bo->scanout); 576803b705cfSriastradh assert(bo->tiling == tiling); 576903b705cfSriastradh assert(bo->flush == false); 577003b705cfSriastradh assert_tiling(kgem, bo); 577103b705cfSriastradh 577203b705cfSriastradh if (num_pages(bo) < size) 577303b705cfSriastradh continue; 577403b705cfSriastradh 577503b705cfSriastradh kgem_bo_remove_from_active(kgem, bo); 577603b705cfSriastradh 577703b705cfSriastradh bo->pitch = pitch; 577803b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 577903b705cfSriastradh bo->delta = 0; 578003b705cfSriastradh DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 578103b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 578203b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 578303b705cfSriastradh assert_tiling(kgem, bo); 578403b705cfSriastradh bo->refcnt = 1; 578503b705cfSriastradh return bo; 578603b705cfSriastradh } 578703b705cfSriastradh } 578803b705cfSriastradh 57899a906b70Schristos if (kgem->gen >= 040) { 57909a906b70Schristos for (i = I915_TILING_Y; i >= I915_TILING_NONE; i--) { 57919a906b70Schristos cache = &kgem->active[bucket][i]; 57929a906b70Schristos list_for_each_entry(bo, cache, list) { 57939a906b70Schristos assert(!bo->purged); 57949a906b70Schristos assert(bo->refcnt == 0); 57959a906b70Schristos assert(bo->reusable); 57969a906b70Schristos assert(!bo->scanout); 57979a906b70Schristos assert(bo->flush == false); 57989a906b70Schristos assert_tiling(kgem, bo); 579903b705cfSriastradh 58009a906b70Schristos if (num_pages(bo) < size) 58019a906b70Schristos continue; 580203b705cfSriastradh 580363ef14f0Smrg if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { 580463ef14f0Smrg if (exact || kgem->gen < 040) 580503b705cfSriastradh continue; 580663ef14f0Smrg 580763ef14f0Smrg set_gpu_tiling(kgem, bo, tiling, pitch); 58089a906b70Schristos } 580963ef14f0Smrg assert(bo->tiling == tiling); 581063ef14f0Smrg assert(bo->pitch >= pitch); 581103b705cfSriastradh 58129a906b70Schristos kgem_bo_remove_from_active(kgem, bo); 581303b705cfSriastradh 58149a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 58159a906b70Schristos bo->delta = 0; 58169a906b70Schristos DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 58179a906b70Schristos bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 58189a906b70Schristos assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 58199a906b70Schristos assert_tiling(kgem, bo); 58209a906b70Schristos bo->refcnt = 1; 58219a906b70Schristos return bo; 582203b705cfSriastradh } 582303b705cfSriastradh } 58249a906b70Schristos } else if (!exact) { /* allow an active near-miss? */ 58259a906b70Schristos for (i = tiling; i >= I915_TILING_NONE; i--) { 582603b705cfSriastradh tiled_height = kgem_surface_size(kgem, kgem->has_relaxed_fencing, flags, 582703b705cfSriastradh width, height, bpp, tiling, &pitch); 582803b705cfSriastradh cache = active(kgem, tiled_height / PAGE_SIZE, i); 582903b705cfSriastradh tiled_height = kgem_aligned_height(kgem, height, i); 583003b705cfSriastradh list_for_each_entry(bo, cache, list) { 583103b705cfSriastradh assert(!bo->purged); 583203b705cfSriastradh assert(bo->refcnt == 0); 583303b705cfSriastradh assert(bo->reusable); 583403b705cfSriastradh assert(!bo->scanout); 583503b705cfSriastradh assert(bo->flush == false); 583603b705cfSriastradh assert_tiling(kgem, bo); 583703b705cfSriastradh 583803b705cfSriastradh if (bo->tiling) { 583903b705cfSriastradh if (bo->pitch < pitch) { 584003b705cfSriastradh DBG(("tiled and pitch too small: tiling=%d, (want %d), pitch=%d, need %d\n", 584103b705cfSriastradh bo->tiling, tiling, 584203b705cfSriastradh bo->pitch, pitch)); 584303b705cfSriastradh continue; 584403b705cfSriastradh } 584503b705cfSriastradh } else 584603b705cfSriastradh bo->pitch = pitch; 584703b705cfSriastradh 584803b705cfSriastradh if (bo->pitch * tiled_height > bytes(bo)) 584903b705cfSriastradh continue; 585003b705cfSriastradh 585103b705cfSriastradh kgem_bo_remove_from_active(kgem, bo); 585203b705cfSriastradh 585303b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 585403b705cfSriastradh bo->delta = 0; 585503b705cfSriastradh DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 585603b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 585703b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 585803b705cfSriastradh assert_tiling(kgem, bo); 585903b705cfSriastradh bo->refcnt = 1; 586003b705cfSriastradh return bo; 586103b705cfSriastradh } 586203b705cfSriastradh } 586303b705cfSriastradh } 586403b705cfSriastradh 58659a906b70Schristos if (--retry) { 58669a906b70Schristos bucket++; 58679a906b70Schristos goto search_active; 58689a906b70Schristos } 58699a906b70Schristos 587003b705cfSriastradhskip_active_search: 587103b705cfSriastradh bucket = cache_bucket(size); 587203b705cfSriastradh retry = NUM_CACHE_BUCKETS - bucket; 587303b705cfSriastradh if (retry > 3) 587403b705cfSriastradh retry = 3; 587503b705cfSriastradhsearch_inactive: 587603b705cfSriastradh /* Now just look for a close match and prefer any currently active */ 587703b705cfSriastradh assert(bucket < NUM_CACHE_BUCKETS); 587803b705cfSriastradh cache = &kgem->inactive[bucket]; 587903b705cfSriastradh list_for_each_entry(bo, cache, list) { 588003b705cfSriastradh assert(bucket(bo) == bucket); 588103b705cfSriastradh assert(bo->reusable); 588203b705cfSriastradh assert(!bo->scanout); 588303b705cfSriastradh assert(bo->flush == false); 588403b705cfSriastradh assert_tiling(kgem, bo); 588503b705cfSriastradh 588603b705cfSriastradh if (size > num_pages(bo)) { 588703b705cfSriastradh DBG(("inactive too small: %d < %d\n", 588803b705cfSriastradh num_pages(bo), size)); 588903b705cfSriastradh continue; 589003b705cfSriastradh } 589103b705cfSriastradh 589263ef14f0Smrg if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { 589363ef14f0Smrg if (exact || kgem->gen < 040) { 589463ef14f0Smrg kgem_bo_free(kgem, bo); 589563ef14f0Smrg break; 589663ef14f0Smrg } 589763ef14f0Smrg 589863ef14f0Smrg set_gpu_tiling(kgem, bo, tiling, pitch); 589903b705cfSriastradh } 590003b705cfSriastradh 590103b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { 590203b705cfSriastradh kgem_bo_free(kgem, bo); 590303b705cfSriastradh break; 590403b705cfSriastradh } 590503b705cfSriastradh 590603b705cfSriastradh kgem_bo_remove_from_inactive(kgem, bo); 59079a906b70Schristos assert(list_is_empty(&bo->list)); 59089a906b70Schristos assert(list_is_empty(&bo->vma)); 590963ef14f0Smrg assert(bo->tiling == tiling); 591063ef14f0Smrg assert(bo->pitch >= pitch); 591103b705cfSriastradh 591203b705cfSriastradh bo->delta = 0; 591303b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 591403b705cfSriastradh assert(bo->pitch); 591503b705cfSriastradh DBG((" from inactive: pitch=%d, tiling=%d: handle=%d, id=%d\n", 591603b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 591703b705cfSriastradh assert(bo->refcnt == 0); 591803b705cfSriastradh assert(bo->reusable); 591903b705cfSriastradh assert((flags & CREATE_INACTIVE) == 0 || bo->domain != DOMAIN_GPU); 592003b705cfSriastradh ASSERT_MAYBE_IDLE(kgem, bo->handle, flags & CREATE_INACTIVE); 592103b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 592203b705cfSriastradh assert_tiling(kgem, bo); 592303b705cfSriastradh bo->refcnt = 1; 59249a906b70Schristos 59259a906b70Schristos if (flags & CREATE_SCANOUT) 59269a906b70Schristos __kgem_bo_make_scanout(kgem, bo, width, height); 59279a906b70Schristos 592803b705cfSriastradh return bo; 592903b705cfSriastradh } 593003b705cfSriastradh 59319a906b70Schristos if ((flags & CREATE_NO_RETIRE) == 0) { 59329a906b70Schristos list_for_each_entry_reverse(bo, &kgem->active[bucket][tiling], list) { 59339a906b70Schristos if (bo->exec) 59349a906b70Schristos break; 59359a906b70Schristos 59369a906b70Schristos if (size > num_pages(bo)) 59379a906b70Schristos continue; 59389a906b70Schristos 59399a906b70Schristos if (__kgem_busy(kgem, bo->handle)) { 59409a906b70Schristos if (flags & CREATE_NO_THROTTLE) 59419a906b70Schristos goto no_retire; 59429a906b70Schristos 59439a906b70Schristos do { 59449a906b70Schristos if (!kgem->need_throttle) { 59459a906b70Schristos DBG(("%s: not throttling for active handle=%d\n", __FUNCTION__, bo->handle)); 59469a906b70Schristos goto no_retire; 59479a906b70Schristos } 59489a906b70Schristos 59499a906b70Schristos __kgem_throttle(kgem, false); 59509a906b70Schristos } while (__kgem_busy(kgem, bo->handle)); 59519a906b70Schristos } 59529a906b70Schristos 59539a906b70Schristos DBG(("%s: flushed active handle=%d\n", __FUNCTION__, bo->handle)); 59549a906b70Schristos 59559a906b70Schristos kgem_bo_remove_from_active(kgem, bo); 59569a906b70Schristos __kgem_bo_clear_busy(bo); 59579a906b70Schristos 595863ef14f0Smrg if (!kgem_set_tiling(kgem, bo, tiling, pitch)) { 595963ef14f0Smrg if (exact || kgem->gen < 040) 59609a906b70Schristos goto no_retire; 596163ef14f0Smrg 596263ef14f0Smrg set_gpu_tiling(kgem, bo, tiling, pitch); 59639a906b70Schristos } 596463ef14f0Smrg assert(bo->tiling == tiling); 596563ef14f0Smrg assert(bo->pitch >= pitch); 59669a906b70Schristos 59679a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 59689a906b70Schristos bo->delta = 0; 59699a906b70Schristos DBG((" 2:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 59709a906b70Schristos bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 59719a906b70Schristos assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 59729a906b70Schristos assert_tiling(kgem, bo); 59739a906b70Schristos bo->refcnt = 1; 59749a906b70Schristos 59759a906b70Schristos if (flags & CREATE_SCANOUT) 59769a906b70Schristos __kgem_bo_make_scanout(kgem, bo, width, height); 59779a906b70Schristos 59789a906b70Schristos return bo; 59799a906b70Schristos } 59809a906b70Schristosno_retire: 59819a906b70Schristos flags |= CREATE_NO_RETIRE; 598203b705cfSriastradh } 598303b705cfSriastradh 598403b705cfSriastradh if (--retry) { 598503b705cfSriastradh bucket++; 598603b705cfSriastradh goto search_inactive; 598703b705cfSriastradh } 598803b705cfSriastradh 598903b705cfSriastradhcreate: 59909a906b70Schristos if (flags & CREATE_CACHED) { 59919a906b70Schristos DBG(("%s: no cached bo found, requested not to create a new bo\n", __FUNCTION__)); 599203b705cfSriastradh return NULL; 59939a906b70Schristos } 599403b705cfSriastradh 599503b705cfSriastradh if (bucket >= NUM_CACHE_BUCKETS) 599603b705cfSriastradh size = ALIGN(size, 1024); 599703b705cfSriastradh handle = gem_create(kgem->fd, size); 59989a906b70Schristos if (handle == 0) { 59999a906b70Schristos DBG(("%s: kernel allocation (gem_create) failure\n", __FUNCTION__)); 600003b705cfSriastradh return NULL; 60019a906b70Schristos } 600203b705cfSriastradh 600303b705cfSriastradh bo = __kgem_bo_alloc(handle, size); 600403b705cfSriastradh if (!bo) { 60059a906b70Schristos DBG(("%s: malloc failed\n", __FUNCTION__)); 600603b705cfSriastradh gem_close(kgem->fd, handle); 600703b705cfSriastradh return NULL; 600803b705cfSriastradh } 600903b705cfSriastradh 601003b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 601163ef14f0Smrg if (kgem_set_tiling(kgem, bo, tiling, pitch)) { 60129a906b70Schristos if (flags & CREATE_SCANOUT) 60139a906b70Schristos __kgem_bo_make_scanout(kgem, bo, width, height); 601403b705cfSriastradh } else { 601563ef14f0Smrg if (kgem->gen >= 040) { 601663ef14f0Smrg assert(!kgem->can_fence); 601763ef14f0Smrg bo->tiling = tiling; 601863ef14f0Smrg bo->pitch = pitch; 601963ef14f0Smrg } else { 602063ef14f0Smrg if (flags & CREATE_EXACT) { 602163ef14f0Smrg DBG(("%s: failed to set exact tiling (gem_set_tiling)\n", __FUNCTION__)); 602263ef14f0Smrg gem_close(kgem->fd, handle); 602363ef14f0Smrg free(bo); 602463ef14f0Smrg return NULL; 602563ef14f0Smrg } 602603b705cfSriastradh } 602703b705cfSriastradh } 602803b705cfSriastradh 602903b705cfSriastradh assert(bytes(bo) >= bo->pitch * kgem_aligned_height(kgem, height, bo->tiling)); 603003b705cfSriastradh assert_tiling(kgem, bo); 603103b705cfSriastradh 603203b705cfSriastradh debug_alloc__bo(kgem, bo); 603303b705cfSriastradh 603403b705cfSriastradh DBG((" new pitch=%d, tiling=%d, handle=%d, id=%d, num_pages=%d [%d], bucket=%d\n", 603503b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id, 603603b705cfSriastradh size, num_pages(bo), bucket(bo))); 603703b705cfSriastradh return bo; 603803b705cfSriastradh} 603903b705cfSriastradh 604003b705cfSriastradhstruct kgem_bo *kgem_create_cpu_2d(struct kgem *kgem, 604103b705cfSriastradh int width, 604203b705cfSriastradh int height, 604303b705cfSriastradh int bpp, 604403b705cfSriastradh uint32_t flags) 604503b705cfSriastradh{ 604603b705cfSriastradh struct kgem_bo *bo; 604703b705cfSriastradh int stride, size; 604803b705cfSriastradh 604903b705cfSriastradh if (DBG_NO_CPU) 605003b705cfSriastradh return NULL; 605103b705cfSriastradh 605203b705cfSriastradh DBG(("%s(%dx%d, bpp=%d)\n", __FUNCTION__, width, height, bpp)); 605303b705cfSriastradh 605403b705cfSriastradh if (kgem->has_llc) { 605503b705cfSriastradh bo = kgem_create_2d(kgem, width, height, bpp, 605603b705cfSriastradh I915_TILING_NONE, flags); 605703b705cfSriastradh if (bo == NULL) 605803b705cfSriastradh return bo; 605903b705cfSriastradh 606003b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 606103b705cfSriastradh assert_tiling(kgem, bo); 606203b705cfSriastradh 606303b705cfSriastradh if (kgem_bo_map__cpu(kgem, bo) == NULL) { 606403b705cfSriastradh kgem_bo_destroy(kgem, bo); 606503b705cfSriastradh return NULL; 606603b705cfSriastradh } 606703b705cfSriastradh 606803b705cfSriastradh return bo; 606903b705cfSriastradh } 607003b705cfSriastradh 607103b705cfSriastradh assert(width > 0 && height > 0); 607203b705cfSriastradh stride = ALIGN(width, 2) * bpp >> 3; 607303b705cfSriastradh stride = ALIGN(stride, 4); 607403b705cfSriastradh size = stride * ALIGN(height, 2); 607503b705cfSriastradh assert(size >= PAGE_SIZE); 607603b705cfSriastradh 607703b705cfSriastradh DBG(("%s: %dx%d, %d bpp, stride=%d\n", 607803b705cfSriastradh __FUNCTION__, width, height, bpp, stride)); 607903b705cfSriastradh 608003b705cfSriastradh bo = search_snoop_cache(kgem, NUM_PAGES(size), 0); 608103b705cfSriastradh if (bo) { 608203b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 608303b705cfSriastradh assert_tiling(kgem, bo); 608403b705cfSriastradh assert(bo->snoop); 608503b705cfSriastradh bo->refcnt = 1; 608603b705cfSriastradh bo->pitch = stride; 608703b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 608803b705cfSriastradh return bo; 608903b705cfSriastradh } 609003b705cfSriastradh 609103b705cfSriastradh if (kgem->has_caching) { 609203b705cfSriastradh bo = kgem_create_linear(kgem, size, flags); 609303b705cfSriastradh if (bo == NULL) 609403b705cfSriastradh return NULL; 609503b705cfSriastradh 609603b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 609703b705cfSriastradh assert_tiling(kgem, bo); 609803b705cfSriastradh 6099813957e3Ssnj assert(!__kgem_busy(kgem, bo->handle)); 610003b705cfSriastradh if (!gem_set_caching(kgem->fd, bo->handle, SNOOPED)) { 610103b705cfSriastradh kgem_bo_destroy(kgem, bo); 610203b705cfSriastradh return NULL; 610303b705cfSriastradh } 610403b705cfSriastradh bo->snoop = true; 610503b705cfSriastradh 610603b705cfSriastradh if (kgem_bo_map__cpu(kgem, bo) == NULL) { 610703b705cfSriastradh kgem_bo_destroy(kgem, bo); 610803b705cfSriastradh return NULL; 610903b705cfSriastradh } 611003b705cfSriastradh 611103b705cfSriastradh bo->pitch = stride; 611203b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 611303b705cfSriastradh return bo; 611403b705cfSriastradh } 611503b705cfSriastradh 611603b705cfSriastradh if (kgem->has_userptr) { 611703b705cfSriastradh void *ptr; 611803b705cfSriastradh 611903b705cfSriastradh /* XXX */ 612003b705cfSriastradh //if (posix_memalign(&ptr, 64, ALIGN(size, 64))) 612103b705cfSriastradh if (posix_memalign(&ptr, PAGE_SIZE, ALIGN(size, PAGE_SIZE))) 612203b705cfSriastradh return NULL; 612303b705cfSriastradh 612403b705cfSriastradh bo = kgem_create_map(kgem, ptr, size, false); 612503b705cfSriastradh if (bo == NULL) { 612603b705cfSriastradh free(ptr); 612703b705cfSriastradh return NULL; 612803b705cfSriastradh } 612903b705cfSriastradh 613003b705cfSriastradh bo->pitch = stride; 613103b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 613203b705cfSriastradh return bo; 613303b705cfSriastradh } 613403b705cfSriastradh 613503b705cfSriastradh return NULL; 613603b705cfSriastradh} 613703b705cfSriastradh 613803b705cfSriastradhvoid _kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo) 613903b705cfSriastradh{ 614003b705cfSriastradh DBG(("%s: handle=%d, proxy? %d\n", 614103b705cfSriastradh __FUNCTION__, bo->handle, bo->proxy != NULL)); 614203b705cfSriastradh 614303b705cfSriastradh if (bo->proxy) { 61449a906b70Schristos assert(!bo->reusable); 61459a906b70Schristos kgem_bo_binding_free(kgem, bo); 61469a906b70Schristos 61479a906b70Schristos assert(list_is_empty(&bo->list)); 614803b705cfSriastradh _list_del(&bo->vma); 614903b705cfSriastradh _list_del(&bo->request); 61509a906b70Schristos 61519a906b70Schristos if (bo->io && bo->domain == DOMAIN_CPU) 615203b705cfSriastradh _kgem_bo_delete_buffer(kgem, bo); 61539a906b70Schristos 615403b705cfSriastradh kgem_bo_unref(kgem, bo->proxy); 615503b705cfSriastradh 61569a906b70Schristos if (DBG_NO_MALLOC_CACHE) { 61579a906b70Schristos free(bo); 61589a906b70Schristos } else { 61599a906b70Schristos *(struct kgem_bo **)bo = __kgem_freed_bo; 61609a906b70Schristos __kgem_freed_bo = bo; 61619a906b70Schristos } 61629a906b70Schristos } else 61639a906b70Schristos __kgem_bo_destroy(kgem, bo); 616403b705cfSriastradh} 616503b705cfSriastradh 616603b705cfSriastradhstatic void __kgem_flush(struct kgem *kgem, struct kgem_bo *bo) 616703b705cfSriastradh{ 616803b705cfSriastradh assert(bo->rq); 616903b705cfSriastradh assert(bo->exec == NULL); 617003b705cfSriastradh assert(bo->needs_flush); 617103b705cfSriastradh 617203b705cfSriastradh /* The kernel will emit a flush *and* update its own flushing lists. */ 617303b705cfSriastradh if (!__kgem_busy(kgem, bo->handle)) 617403b705cfSriastradh __kgem_bo_clear_busy(bo); 617503b705cfSriastradh 617603b705cfSriastradh DBG(("%s: handle=%d, busy?=%d\n", 617703b705cfSriastradh __FUNCTION__, bo->handle, bo->rq != NULL)); 617803b705cfSriastradh} 617903b705cfSriastradh 618003b705cfSriastradhvoid kgem_scanout_flush(struct kgem *kgem, struct kgem_bo *bo) 618103b705cfSriastradh{ 618263ef14f0Smrg if (!bo->needs_flush && !bo->gtt_dirty) 618303b705cfSriastradh return; 618403b705cfSriastradh 61859a906b70Schristos kgem_bo_submit(kgem, bo); 61869a906b70Schristos 618703b705cfSriastradh /* If the kernel fails to emit the flush, then it will be forced when 618803b705cfSriastradh * we assume direct access. And as the usual failure is EIO, we do 618903b705cfSriastradh * not actually care. 619003b705cfSriastradh */ 619103b705cfSriastradh assert(bo->exec == NULL); 619203b705cfSriastradh if (bo->rq) 619303b705cfSriastradh __kgem_flush(kgem, bo); 619403b705cfSriastradh 619563ef14f0Smrg if (bo->scanout && kgem->needs_dirtyfb) { 619663ef14f0Smrg struct drm_mode_fb_dirty_cmd cmd; 619763ef14f0Smrg memset(&cmd, 0, sizeof(cmd)); 619863ef14f0Smrg cmd.fb_id = bo->delta; 619963ef14f0Smrg (void)drmIoctl(kgem->fd, DRM_IOCTL_MODE_DIRTYFB, &cmd); 620063ef14f0Smrg } 620163ef14f0Smrg 620203b705cfSriastradh /* Whatever actually happens, we can regard the GTT write domain 620303b705cfSriastradh * as being flushed. 620403b705cfSriastradh */ 620563ef14f0Smrg __kgem_bo_clear_dirty(bo); 620603b705cfSriastradh} 620703b705cfSriastradh 62089a906b70Schristosinline static bool nearly_idle(struct kgem *kgem) 62099a906b70Schristos{ 62109a906b70Schristos int ring = kgem->ring == KGEM_BLT; 62119a906b70Schristos 621263ef14f0Smrg assert(ring < ARRAY_SIZE(kgem->requests)); 62139a906b70Schristos if (list_is_singular(&kgem->requests[ring])) 62149a906b70Schristos return true; 62159a906b70Schristos 62169a906b70Schristos return __kgem_ring_is_idle(kgem, ring); 62179a906b70Schristos} 62189a906b70Schristos 621903b705cfSriastradhinline static bool needs_semaphore(struct kgem *kgem, struct kgem_bo *bo) 622003b705cfSriastradh{ 62219a906b70Schristos if (kgem->needs_semaphore) 62229a906b70Schristos return false; 62239a906b70Schristos 62249a906b70Schristos if (bo->rq == NULL || RQ_RING(bo->rq) == kgem->ring) 62259a906b70Schristos return false; 62269a906b70Schristos 62279a906b70Schristos kgem->needs_semaphore = true; 62289a906b70Schristos return true; 62299a906b70Schristos} 62309a906b70Schristos 62319a906b70Schristosinline static bool needs_reservation(struct kgem *kgem, struct kgem_bo *bo) 62329a906b70Schristos{ 62339a906b70Schristos if (kgem->needs_reservation) 62349a906b70Schristos return false; 62359a906b70Schristos 62369a906b70Schristos if (bo->presumed_offset) 62379a906b70Schristos return false; 62389a906b70Schristos 62399a906b70Schristos kgem->needs_reservation = true; 62409a906b70Schristos return nearly_idle(kgem); 62419a906b70Schristos} 62429a906b70Schristos 62439a906b70Schristosinline static bool needs_batch_flush(struct kgem *kgem, struct kgem_bo *bo) 62449a906b70Schristos{ 62459a906b70Schristos bool flush = false; 62469a906b70Schristos 62479a906b70Schristos if (needs_semaphore(kgem, bo)) { 62489a906b70Schristos DBG(("%s: flushing before handle=%d for required semaphore\n", __FUNCTION__, bo->handle)); 62499a906b70Schristos flush = true; 62509a906b70Schristos } 62519a906b70Schristos 62529a906b70Schristos if (needs_reservation(kgem, bo)) { 62539a906b70Schristos DBG(("%s: flushing before handle=%d for new reservation\n", __FUNCTION__, bo->handle)); 62549a906b70Schristos flush = true; 62559a906b70Schristos } 62569a906b70Schristos 62579a906b70Schristos return kgem->nreloc ? flush : false; 62589a906b70Schristos} 62599a906b70Schristos 62609a906b70Schristosstatic bool aperture_check(struct kgem *kgem, unsigned num_pages) 62619a906b70Schristos{ 62629a906b70Schristos struct drm_i915_gem_get_aperture aperture; 62639a906b70Schristos int reserve; 62649a906b70Schristos 62659a906b70Schristos if (kgem->aperture) 62669a906b70Schristos return false; 62679a906b70Schristos 62689a906b70Schristos /* Leave some space in case of alignment issues */ 62699a906b70Schristos reserve = kgem->aperture_mappable / 2; 62709a906b70Schristos if (kgem->gen < 033 && reserve < kgem->aperture_max_fence) 62719a906b70Schristos reserve = kgem->aperture_max_fence; 62729a906b70Schristos if (!kgem->has_llc) 62739a906b70Schristos reserve += kgem->nexec * PAGE_SIZE * 2; 62749a906b70Schristos 62759a906b70Schristos DBG(("%s: num_pages=%d, holding %d pages in reserve, total aperture %d\n", 62769a906b70Schristos __FUNCTION__, num_pages, reserve, kgem->aperture_total)); 62779a906b70Schristos num_pages += reserve; 62789a906b70Schristos 62799a906b70Schristos VG_CLEAR(aperture); 62809a906b70Schristos aperture.aper_available_size = kgem->aperture_total; 62819a906b70Schristos aperture.aper_available_size *= PAGE_SIZE; 62829a906b70Schristos (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture); 62839a906b70Schristos 62849a906b70Schristos DBG(("%s: aperture required %ld bytes, available %ld bytes\n", 62859a906b70Schristos __FUNCTION__, 62869a906b70Schristos (long)num_pages * PAGE_SIZE, 62879a906b70Schristos (long)aperture.aper_available_size)); 62889a906b70Schristos 62899a906b70Schristos return num_pages <= aperture.aper_available_size / PAGE_SIZE; 62909a906b70Schristos} 62919a906b70Schristos 62929a906b70Schristosstatic inline bool kgem_flush(struct kgem *kgem, bool flush) 62939a906b70Schristos{ 62949a906b70Schristos if (unlikely(kgem->wedged)) 62959a906b70Schristos return false; 62969a906b70Schristos 62979a906b70Schristos if (kgem->nreloc == 0) 62989a906b70Schristos return true; 62999a906b70Schristos 630063ef14f0Smrg if (__to_sna(kgem)->flags & SNA_POWERSAVE) 63019a906b70Schristos return true; 63029a906b70Schristos 63039a906b70Schristos if (kgem->flush == flush && kgem->aperture < kgem->aperture_low) 63049a906b70Schristos return true; 63059a906b70Schristos 63069a906b70Schristos DBG(("%s: opportunistic flushing? flush=%d,%d, aperture=%d/%d, idle?=%d\n", 63079a906b70Schristos __FUNCTION__, kgem->flush, flush, kgem->aperture, kgem->aperture_low, kgem_ring_is_idle(kgem, kgem->ring))); 63089a906b70Schristos return !kgem_ring_is_idle(kgem, kgem->ring); 630903b705cfSriastradh} 631003b705cfSriastradh 631103b705cfSriastradhbool kgem_check_bo(struct kgem *kgem, ...) 631203b705cfSriastradh{ 631303b705cfSriastradh va_list ap; 631403b705cfSriastradh struct kgem_bo *bo; 631503b705cfSriastradh int num_exec = 0; 631603b705cfSriastradh int num_pages = 0; 631703b705cfSriastradh bool flush = false; 63189a906b70Schristos bool busy = true; 631903b705cfSriastradh 632003b705cfSriastradh va_start(ap, kgem); 632103b705cfSriastradh while ((bo = va_arg(ap, struct kgem_bo *))) { 632203b705cfSriastradh while (bo->proxy) 632303b705cfSriastradh bo = bo->proxy; 632403b705cfSriastradh if (bo->exec) 632503b705cfSriastradh continue; 632603b705cfSriastradh 63279a906b70Schristos if (needs_batch_flush(kgem, bo)) { 63289a906b70Schristos va_end(ap); 632903b705cfSriastradh return false; 63309a906b70Schristos } 633103b705cfSriastradh 633203b705cfSriastradh num_pages += num_pages(bo); 633303b705cfSriastradh num_exec++; 633403b705cfSriastradh 633503b705cfSriastradh flush |= bo->flush; 63369a906b70Schristos busy &= bo->rq != NULL; 633703b705cfSriastradh } 633803b705cfSriastradh va_end(ap); 633903b705cfSriastradh 634003b705cfSriastradh DBG(("%s: num_pages=+%d, num_exec=+%d\n", 634103b705cfSriastradh __FUNCTION__, num_pages, num_exec)); 634203b705cfSriastradh 634303b705cfSriastradh if (!num_pages) 634403b705cfSriastradh return true; 634503b705cfSriastradh 63469a906b70Schristos if (kgem->nexec + num_exec >= KGEM_EXEC_SIZE(kgem)) { 63479a906b70Schristos DBG(("%s: out of exec slots (%d + %d / %d)\n", __FUNCTION__, 63489a906b70Schristos kgem->nexec, num_exec, KGEM_EXEC_SIZE(kgem))); 634903b705cfSriastradh return false; 635003b705cfSriastradh } 635103b705cfSriastradh 635203b705cfSriastradh if (num_pages + kgem->aperture > kgem->aperture_high) { 63539a906b70Schristos DBG(("%s: final aperture usage (%d + %d) is greater than high water mark (%d)\n", 63549a906b70Schristos __FUNCTION__, kgem->aperture, num_pages, kgem->aperture_high)); 63559a906b70Schristos return aperture_check(kgem, num_pages); 635603b705cfSriastradh } 635703b705cfSriastradh 63589a906b70Schristos if (busy) 63599a906b70Schristos return true; 636003b705cfSriastradh 63619a906b70Schristos return kgem_flush(kgem, flush); 636203b705cfSriastradh} 636303b705cfSriastradh 636403b705cfSriastradhbool kgem_check_bo_fenced(struct kgem *kgem, struct kgem_bo *bo) 636503b705cfSriastradh{ 636603b705cfSriastradh assert(bo->refcnt); 636703b705cfSriastradh while (bo->proxy) 636803b705cfSriastradh bo = bo->proxy; 636903b705cfSriastradh assert(bo->refcnt); 637003b705cfSriastradh 637103b705cfSriastradh if (bo->exec) { 637203b705cfSriastradh if (kgem->gen < 040 && 637303b705cfSriastradh bo->tiling != I915_TILING_NONE && 637403b705cfSriastradh (bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0) { 63759a906b70Schristos uint32_t size; 63769a906b70Schristos 63779a906b70Schristos assert(bo->tiling == I915_TILING_X); 63789a906b70Schristos 637903b705cfSriastradh if (kgem->nfence >= kgem->fence_max) 638003b705cfSriastradh return false; 638103b705cfSriastradh 63829a906b70Schristos if (kgem->aperture_fenced) { 63839a906b70Schristos size = 3*kgem->aperture_fenced; 63849a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 63859a906b70Schristos size += kgem->aperture; 63869a906b70Schristos if (size > kgem->aperture_fenceable && 63879a906b70Schristos kgem_ring_is_idle(kgem, kgem->ring)) { 63889a906b70Schristos DBG(("%s: opportunistic fence flush\n", __FUNCTION__)); 63899a906b70Schristos return false; 63909a906b70Schristos } 63919a906b70Schristos } 639203b705cfSriastradh 63939a906b70Schristos size = kgem_bo_fenced_size(kgem, bo); 63949a906b70Schristos if (size > kgem->aperture_max_fence) 63959a906b70Schristos kgem->aperture_max_fence = size; 63969a906b70Schristos size += kgem->aperture_fenced; 63979a906b70Schristos if (kgem->gen < 033 && size < 2 * kgem->aperture_max_fence) 63989a906b70Schristos size = 2 * kgem->aperture_max_fence; 63999a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 64009a906b70Schristos size += kgem->aperture; 64019a906b70Schristos if (size > kgem->aperture_fenceable) { 64029a906b70Schristos DBG(("%s: estimated fence space required %d (fenced=%d, max_fence=%d, aperture=%d) exceeds fenceable aperture %d\n", 64039a906b70Schristos __FUNCTION__, size, kgem->aperture_fenced, kgem->aperture_max_fence, kgem->aperture, kgem->aperture_fenceable)); 640403b705cfSriastradh return false; 64059a906b70Schristos } 640603b705cfSriastradh } 640703b705cfSriastradh 640803b705cfSriastradh return true; 640903b705cfSriastradh } 641003b705cfSriastradh 641103b705cfSriastradh if (kgem->nexec >= KGEM_EXEC_SIZE(kgem) - 1) 641203b705cfSriastradh return false; 641303b705cfSriastradh 64149a906b70Schristos if (needs_batch_flush(kgem, bo)) 641503b705cfSriastradh return false; 641603b705cfSriastradh 641703b705cfSriastradh assert_tiling(kgem, bo); 641803b705cfSriastradh if (kgem->gen < 040 && bo->tiling != I915_TILING_NONE) { 64199a906b70Schristos uint32_t size; 64209a906b70Schristos 64219a906b70Schristos assert(bo->tiling == I915_TILING_X); 64229a906b70Schristos 642303b705cfSriastradh if (kgem->nfence >= kgem->fence_max) 642403b705cfSriastradh return false; 642503b705cfSriastradh 64269a906b70Schristos if (kgem->aperture_fenced) { 64279a906b70Schristos size = 3*kgem->aperture_fenced; 64289a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 64299a906b70Schristos size += kgem->aperture; 64309a906b70Schristos if (size > kgem->aperture_fenceable && 64319a906b70Schristos kgem_ring_is_idle(kgem, kgem->ring)) { 64329a906b70Schristos DBG(("%s: opportunistic fence flush\n", __FUNCTION__)); 64339a906b70Schristos return false; 64349a906b70Schristos } 64359a906b70Schristos } 643603b705cfSriastradh 64379a906b70Schristos size = kgem_bo_fenced_size(kgem, bo); 64389a906b70Schristos if (size > kgem->aperture_max_fence) 64399a906b70Schristos kgem->aperture_max_fence = size; 64409a906b70Schristos size += kgem->aperture_fenced; 64419a906b70Schristos if (kgem->gen < 033 && size < 2 * kgem->aperture_max_fence) 64429a906b70Schristos size = 2 * kgem->aperture_max_fence; 64439a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 64449a906b70Schristos size += kgem->aperture; 64459a906b70Schristos if (size > kgem->aperture_fenceable) { 64469a906b70Schristos DBG(("%s: estimated fence space required %d (fenced=%d, max_fence=%d, aperture=%d) exceeds fenceable aperture %d\n", 64479a906b70Schristos __FUNCTION__, size, kgem->aperture_fenced, kgem->aperture_max_fence, kgem->aperture, kgem->aperture_fenceable)); 644803b705cfSriastradh return false; 64499a906b70Schristos } 645003b705cfSriastradh } 645103b705cfSriastradh 64529a906b70Schristos if (kgem->aperture + kgem->aperture_fenced + num_pages(bo) > kgem->aperture_high) { 64539a906b70Schristos DBG(("%s: final aperture usage (%d + %d) is greater than high water mark (%d)\n", 64549a906b70Schristos __FUNCTION__, kgem->aperture, num_pages(bo), kgem->aperture_high)); 64559a906b70Schristos return aperture_check(kgem, num_pages(bo)); 64569a906b70Schristos } 64579a906b70Schristos 64589a906b70Schristos if (bo->rq) 64599a906b70Schristos return true; 64609a906b70Schristos 64619a906b70Schristos return kgem_flush(kgem, bo->flush); 646203b705cfSriastradh} 646303b705cfSriastradh 646403b705cfSriastradhbool kgem_check_many_bo_fenced(struct kgem *kgem, ...) 646503b705cfSriastradh{ 646603b705cfSriastradh va_list ap; 646703b705cfSriastradh struct kgem_bo *bo; 646803b705cfSriastradh int num_fence = 0; 646903b705cfSriastradh int num_exec = 0; 647003b705cfSriastradh int num_pages = 0; 647103b705cfSriastradh int fenced_size = 0; 647203b705cfSriastradh bool flush = false; 64739a906b70Schristos bool busy = true; 647403b705cfSriastradh 647503b705cfSriastradh va_start(ap, kgem); 647603b705cfSriastradh while ((bo = va_arg(ap, struct kgem_bo *))) { 647703b705cfSriastradh assert(bo->refcnt); 647803b705cfSriastradh while (bo->proxy) 647903b705cfSriastradh bo = bo->proxy; 648003b705cfSriastradh assert(bo->refcnt); 648103b705cfSriastradh if (bo->exec) { 648203b705cfSriastradh if (kgem->gen >= 040 || bo->tiling == I915_TILING_NONE) 648303b705cfSriastradh continue; 648403b705cfSriastradh 648503b705cfSriastradh if ((bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0) { 648603b705cfSriastradh fenced_size += kgem_bo_fenced_size(kgem, bo); 648703b705cfSriastradh num_fence++; 648803b705cfSriastradh } 648903b705cfSriastradh 649003b705cfSriastradh continue; 649103b705cfSriastradh } 649203b705cfSriastradh 64939a906b70Schristos if (needs_batch_flush(kgem, bo)) { 64949a906b70Schristos va_end(ap); 649503b705cfSriastradh return false; 64969a906b70Schristos } 649703b705cfSriastradh 649803b705cfSriastradh assert_tiling(kgem, bo); 649903b705cfSriastradh num_pages += num_pages(bo); 650003b705cfSriastradh num_exec++; 650103b705cfSriastradh if (kgem->gen < 040 && bo->tiling) { 65029a906b70Schristos uint32_t size = kgem_bo_fenced_size(kgem, bo); 65039a906b70Schristos if (size > kgem->aperture_max_fence) 65049a906b70Schristos kgem->aperture_max_fence = size; 65059a906b70Schristos fenced_size += size; 650603b705cfSriastradh num_fence++; 650703b705cfSriastradh } 650803b705cfSriastradh 650903b705cfSriastradh flush |= bo->flush; 65109a906b70Schristos busy &= bo->rq != NULL; 651103b705cfSriastradh } 651203b705cfSriastradh va_end(ap); 651303b705cfSriastradh 651403b705cfSriastradh if (num_fence) { 65159a906b70Schristos uint32_t size; 65169a906b70Schristos 651703b705cfSriastradh if (kgem->nfence + num_fence > kgem->fence_max) 651803b705cfSriastradh return false; 651903b705cfSriastradh 65209a906b70Schristos if (kgem->aperture_fenced) { 65219a906b70Schristos size = 3*kgem->aperture_fenced; 65229a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 65239a906b70Schristos size += kgem->aperture; 65249a906b70Schristos if (size > kgem->aperture_fenceable && 65259a906b70Schristos kgem_ring_is_idle(kgem, kgem->ring)) { 65269a906b70Schristos DBG(("%s: opportunistic fence flush\n", __FUNCTION__)); 65279a906b70Schristos return false; 65289a906b70Schristos } 65299a906b70Schristos } 653003b705cfSriastradh 65319a906b70Schristos size = kgem->aperture_fenced; 65329a906b70Schristos size += fenced_size; 65339a906b70Schristos if (kgem->gen < 033 && size < 2 * kgem->aperture_max_fence) 65349a906b70Schristos size = 2 * kgem->aperture_max_fence; 65359a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 65369a906b70Schristos size += kgem->aperture; 65379a906b70Schristos if (size > kgem->aperture_fenceable) { 65389a906b70Schristos DBG(("%s: estimated fence space required %d (fenced=%d, max_fence=%d, aperture=%d) exceeds fenceable aperture %d\n", 65399a906b70Schristos __FUNCTION__, size, kgem->aperture_fenced, kgem->aperture_max_fence, kgem->aperture, kgem->aperture_fenceable)); 654003b705cfSriastradh return false; 65419a906b70Schristos } 654203b705cfSriastradh } 654303b705cfSriastradh 65449a906b70Schristos if (num_pages == 0) 65459a906b70Schristos return true; 654603b705cfSriastradh 65479a906b70Schristos if (kgem->nexec + num_exec >= KGEM_EXEC_SIZE(kgem)) 65489a906b70Schristos return false; 654903b705cfSriastradh 65509a906b70Schristos if (num_pages + kgem->aperture > kgem->aperture_high - kgem->aperture_fenced) { 65519a906b70Schristos DBG(("%s: final aperture usage (%d + %d + %d) is greater than high water mark (%d)\n", 65529a906b70Schristos __FUNCTION__, kgem->aperture, kgem->aperture_fenced, num_pages, kgem->aperture_high)); 65539a906b70Schristos return aperture_check(kgem, num_pages); 655403b705cfSriastradh } 655503b705cfSriastradh 65569a906b70Schristos if (busy) 65579a906b70Schristos return true; 65589a906b70Schristos 65599a906b70Schristos return kgem_flush(kgem, flush); 656003b705cfSriastradh} 656103b705cfSriastradh 656263ef14f0Smrgvoid __kgem_bcs_set_tiling(struct kgem *kgem, 656363ef14f0Smrg struct kgem_bo *src, 656463ef14f0Smrg struct kgem_bo *dst) 656563ef14f0Smrg{ 656663ef14f0Smrg uint32_t state, *b; 656763ef14f0Smrg 656863ef14f0Smrg DBG(("%s: src handle=%d:tiling=%d, dst handle=%d:tiling=%d\n", 656963ef14f0Smrg __FUNCTION__, 657063ef14f0Smrg src ? src->handle : 0, src ? src->tiling : 0, 657163ef14f0Smrg dst ? dst->handle : 0, dst ? dst->tiling : 0)); 657263ef14f0Smrg assert(kgem->mode == KGEM_BLT); 657363ef14f0Smrg assert(dst == NULL || kgem_bo_can_blt(kgem, dst)); 657463ef14f0Smrg assert(src == NULL || kgem_bo_can_blt(kgem, src)); 657563ef14f0Smrg 657663ef14f0Smrg state = 0; 657763ef14f0Smrg if (dst && dst->tiling == I915_TILING_Y) 657863ef14f0Smrg state |= BCS_DST_Y; 657963ef14f0Smrg if (src && src->tiling == I915_TILING_Y) 658063ef14f0Smrg state |= BCS_SRC_Y; 658163ef14f0Smrg 658263ef14f0Smrg if (kgem->bcs_state == state) 658363ef14f0Smrg return; 658463ef14f0Smrg 658563ef14f0Smrg DBG(("%s: updating SWCTRL %x -> %x\n", __FUNCTION__, 658663ef14f0Smrg kgem->bcs_state, state)); 658763ef14f0Smrg 658863ef14f0Smrg /* Over-estimate space in case we need to re-emit the cmd packet */ 658963ef14f0Smrg if (!kgem_check_batch(kgem, 24)) { 659063ef14f0Smrg _kgem_submit(kgem); 659163ef14f0Smrg _kgem_set_mode(kgem, KGEM_BLT); 659263ef14f0Smrg if (state == 0) 659363ef14f0Smrg return; 659463ef14f0Smrg } 659563ef14f0Smrg 659663ef14f0Smrg b = kgem->batch + kgem->nbatch; 659763ef14f0Smrg if (kgem->nbatch) { 659863ef14f0Smrg *b++ = MI_FLUSH_DW; 659963ef14f0Smrg *b++ = 0; 660063ef14f0Smrg *b++ = 0; 660163ef14f0Smrg *b++ = 0; 660263ef14f0Smrg } 660363ef14f0Smrg *b++ = MI_LOAD_REGISTER_IMM; 660463ef14f0Smrg *b++ = BCS_SWCTRL; 660563ef14f0Smrg *b++ = (BCS_SRC_Y | BCS_DST_Y) << 16 | state; 660663ef14f0Smrg kgem->nbatch = b - kgem->batch; 660763ef14f0Smrg 660863ef14f0Smrg kgem->bcs_state = state; 660963ef14f0Smrg} 661063ef14f0Smrg 661103b705cfSriastradhuint32_t kgem_add_reloc(struct kgem *kgem, 661203b705cfSriastradh uint32_t pos, 661303b705cfSriastradh struct kgem_bo *bo, 661403b705cfSriastradh uint32_t read_write_domain, 661503b705cfSriastradh uint32_t delta) 661603b705cfSriastradh{ 661703b705cfSriastradh int index; 661803b705cfSriastradh 661903b705cfSriastradh DBG(("%s: handle=%d, pos=%d, delta=%d, domains=%08x\n", 662003b705cfSriastradh __FUNCTION__, bo ? bo->handle : 0, pos, delta, read_write_domain)); 662103b705cfSriastradh 66229a906b70Schristos assert(kgem->gen < 0100); 662303b705cfSriastradh assert((read_write_domain & 0x7fff) == 0 || bo != NULL); 662403b705cfSriastradh 662503b705cfSriastradh index = kgem->nreloc++; 662603b705cfSriastradh assert(index < ARRAY_SIZE(kgem->reloc)); 662703b705cfSriastradh kgem->reloc[index].offset = pos * sizeof(kgem->batch[0]); 662803b705cfSriastradh if (bo) { 66299a906b70Schristos assert(kgem->mode != KGEM_NONE); 663003b705cfSriastradh assert(bo->refcnt); 663103b705cfSriastradh while (bo->proxy) { 663203b705cfSriastradh DBG(("%s: adding proxy [delta=%d] for handle=%d\n", 663303b705cfSriastradh __FUNCTION__, bo->delta, bo->handle)); 663403b705cfSriastradh delta += bo->delta; 663503b705cfSriastradh assert(bo->handle == bo->proxy->handle); 663603b705cfSriastradh /* need to release the cache upon batch submit */ 663703b705cfSriastradh if (bo->exec == NULL) { 663803b705cfSriastradh list_move_tail(&bo->request, 663903b705cfSriastradh &kgem->next_request->buffers); 664003b705cfSriastradh bo->rq = MAKE_REQUEST(kgem->next_request, 664103b705cfSriastradh kgem->ring); 664203b705cfSriastradh bo->exec = &_kgem_dummy_exec; 66439a906b70Schristos bo->domain = DOMAIN_GPU; 664403b705cfSriastradh } 664503b705cfSriastradh 664603b705cfSriastradh if (read_write_domain & 0x7fff && !bo->gpu_dirty) 664703b705cfSriastradh __kgem_bo_mark_dirty(bo); 664803b705cfSriastradh 664903b705cfSriastradh bo = bo->proxy; 665003b705cfSriastradh assert(bo->refcnt); 665103b705cfSriastradh } 665203b705cfSriastradh assert(bo->refcnt); 665303b705cfSriastradh 665403b705cfSriastradh if (bo->exec == NULL) 665503b705cfSriastradh kgem_add_bo(kgem, bo); 665603b705cfSriastradh assert(bo->rq == MAKE_REQUEST(kgem->next_request, kgem->ring)); 665703b705cfSriastradh assert(RQ_RING(bo->rq) == kgem->ring); 665803b705cfSriastradh 665903b705cfSriastradh if (kgem->gen < 040 && read_write_domain & KGEM_RELOC_FENCED) { 666003b705cfSriastradh if (bo->tiling && 666103b705cfSriastradh (bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0) { 66629a906b70Schristos assert(bo->tiling == I915_TILING_X); 666303b705cfSriastradh assert(kgem->nfence < kgem->fence_max); 666403b705cfSriastradh kgem->aperture_fenced += 666503b705cfSriastradh kgem_bo_fenced_size(kgem, bo); 666603b705cfSriastradh kgem->nfence++; 666703b705cfSriastradh } 666803b705cfSriastradh bo->exec->flags |= EXEC_OBJECT_NEEDS_FENCE; 666903b705cfSriastradh } 667003b705cfSriastradh 667103b705cfSriastradh kgem->reloc[index].delta = delta; 667203b705cfSriastradh kgem->reloc[index].target_handle = bo->target_handle; 667303b705cfSriastradh kgem->reloc[index].presumed_offset = bo->presumed_offset; 667403b705cfSriastradh 667503b705cfSriastradh if (read_write_domain & 0x7fff && !bo->gpu_dirty) { 667603b705cfSriastradh assert(!bo->snoop || kgem->can_blt_cpu); 667703b705cfSriastradh __kgem_bo_mark_dirty(bo); 667803b705cfSriastradh } 667903b705cfSriastradh 668003b705cfSriastradh delta += bo->presumed_offset; 668103b705cfSriastradh } else { 668203b705cfSriastradh kgem->reloc[index].delta = delta; 668303b705cfSriastradh kgem->reloc[index].target_handle = ~0U; 668403b705cfSriastradh kgem->reloc[index].presumed_offset = 0; 668503b705cfSriastradh if (kgem->nreloc__self < 256) 668603b705cfSriastradh kgem->reloc__self[kgem->nreloc__self++] = index; 668703b705cfSriastradh } 668803b705cfSriastradh kgem->reloc[index].read_domains = read_write_domain >> 16; 668903b705cfSriastradh kgem->reloc[index].write_domain = read_write_domain & 0x7fff; 669003b705cfSriastradh 669103b705cfSriastradh return delta; 669203b705cfSriastradh} 669303b705cfSriastradh 66949a906b70Schristosuint64_t kgem_add_reloc64(struct kgem *kgem, 66959a906b70Schristos uint32_t pos, 66969a906b70Schristos struct kgem_bo *bo, 66979a906b70Schristos uint32_t read_write_domain, 66989a906b70Schristos uint64_t delta) 66999a906b70Schristos{ 67009a906b70Schristos int index; 67019a906b70Schristos 67029a906b70Schristos DBG(("%s: handle=%d, pos=%d, delta=%ld, domains=%08x\n", 67039a906b70Schristos __FUNCTION__, bo ? bo->handle : 0, pos, (long)delta, read_write_domain)); 67049a906b70Schristos 67059a906b70Schristos assert(kgem->gen >= 0100); 67069a906b70Schristos assert((read_write_domain & 0x7fff) == 0 || bo != NULL); 67079a906b70Schristos 67089a906b70Schristos index = kgem->nreloc++; 67099a906b70Schristos assert(index < ARRAY_SIZE(kgem->reloc)); 67109a906b70Schristos kgem->reloc[index].offset = pos * sizeof(kgem->batch[0]); 67119a906b70Schristos if (bo) { 67129a906b70Schristos assert(kgem->mode != KGEM_NONE); 67139a906b70Schristos assert(bo->refcnt); 67149a906b70Schristos while (bo->proxy) { 67159a906b70Schristos DBG(("%s: adding proxy [delta=%ld] for handle=%d\n", 67169a906b70Schristos __FUNCTION__, (long)bo->delta, bo->handle)); 67179a906b70Schristos delta += bo->delta; 67189a906b70Schristos assert(bo->handle == bo->proxy->handle); 67199a906b70Schristos /* need to release the cache upon batch submit */ 67209a906b70Schristos if (bo->exec == NULL) { 67219a906b70Schristos list_move_tail(&bo->request, 67229a906b70Schristos &kgem->next_request->buffers); 67239a906b70Schristos bo->rq = MAKE_REQUEST(kgem->next_request, 67249a906b70Schristos kgem->ring); 67259a906b70Schristos bo->exec = &_kgem_dummy_exec; 67269a906b70Schristos bo->domain = DOMAIN_GPU; 67279a906b70Schristos } 67289a906b70Schristos 67299a906b70Schristos if (read_write_domain & 0x7fff && !bo->gpu_dirty) 67309a906b70Schristos __kgem_bo_mark_dirty(bo); 67319a906b70Schristos 67329a906b70Schristos bo = bo->proxy; 67339a906b70Schristos assert(bo->refcnt); 67349a906b70Schristos } 67359a906b70Schristos assert(bo->refcnt); 67369a906b70Schristos 67379a906b70Schristos if (bo->exec == NULL) 67389a906b70Schristos kgem_add_bo(kgem, bo); 67399a906b70Schristos assert(bo->rq == MAKE_REQUEST(kgem->next_request, kgem->ring)); 67409a906b70Schristos assert(RQ_RING(bo->rq) == kgem->ring); 67419a906b70Schristos 67429a906b70Schristos DBG(("%s[%d] = (delta=%d, target handle=%d, presumed=%llx)\n", 67439a906b70Schristos __FUNCTION__, index, delta, bo->target_handle, (long long)bo->presumed_offset)); 67449a906b70Schristos kgem->reloc[index].delta = delta; 67459a906b70Schristos kgem->reloc[index].target_handle = bo->target_handle; 67469a906b70Schristos kgem->reloc[index].presumed_offset = bo->presumed_offset; 67479a906b70Schristos 67489a906b70Schristos if (read_write_domain & 0x7fff && !bo->gpu_dirty) { 67499a906b70Schristos assert(!bo->snoop || kgem->can_blt_cpu); 67509a906b70Schristos __kgem_bo_mark_dirty(bo); 67519a906b70Schristos } 67529a906b70Schristos 67539a906b70Schristos delta += bo->presumed_offset; 67549a906b70Schristos } else { 67559a906b70Schristos DBG(("%s[%d] = (delta=%d, target handle=batch)\n", 67569a906b70Schristos __FUNCTION__, index, delta)); 67579a906b70Schristos kgem->reloc[index].delta = delta; 67589a906b70Schristos kgem->reloc[index].target_handle = ~0U; 67599a906b70Schristos kgem->reloc[index].presumed_offset = 0; 67609a906b70Schristos if (kgem->nreloc__self < 256) 67619a906b70Schristos kgem->reloc__self[kgem->nreloc__self++] = index; 67629a906b70Schristos } 67639a906b70Schristos kgem->reloc[index].read_domains = read_write_domain >> 16; 67649a906b70Schristos kgem->reloc[index].write_domain = read_write_domain & 0x7fff; 67659a906b70Schristos 67669a906b70Schristos return delta; 67679a906b70Schristos} 67689a906b70Schristos 676903b705cfSriastradhstatic void kgem_trim_vma_cache(struct kgem *kgem, int type, int bucket) 677003b705cfSriastradh{ 677103b705cfSriastradh int i, j; 677203b705cfSriastradh 677303b705cfSriastradh DBG(("%s: type=%d, count=%d (bucket: %d)\n", 677403b705cfSriastradh __FUNCTION__, type, kgem->vma[type].count, bucket)); 677503b705cfSriastradh if (kgem->vma[type].count <= 0) 677603b705cfSriastradh return; 677703b705cfSriastradh 677803b705cfSriastradh if (kgem->need_purge) 677903b705cfSriastradh kgem_purge_cache(kgem); 678003b705cfSriastradh 678103b705cfSriastradh /* vma are limited on a per-process basis to around 64k. 678203b705cfSriastradh * This includes all malloc arenas as well as other file 678303b705cfSriastradh * mappings. In order to be fair and not hog the cache, 678403b705cfSriastradh * and more importantly not to exhaust that limit and to 678503b705cfSriastradh * start failing mappings, we keep our own number of open 678603b705cfSriastradh * vma to within a conservative value. 678703b705cfSriastradh */ 678803b705cfSriastradh i = 0; 678903b705cfSriastradh while (kgem->vma[type].count > 0) { 679003b705cfSriastradh struct kgem_bo *bo = NULL; 679103b705cfSriastradh 679203b705cfSriastradh for (j = 0; 679303b705cfSriastradh bo == NULL && j < ARRAY_SIZE(kgem->vma[type].inactive); 679403b705cfSriastradh j++) { 679503b705cfSriastradh struct list *head = &kgem->vma[type].inactive[i++%ARRAY_SIZE(kgem->vma[type].inactive)]; 679603b705cfSriastradh if (!list_is_empty(head)) 679703b705cfSriastradh bo = list_last_entry(head, struct kgem_bo, vma); 679803b705cfSriastradh } 679903b705cfSriastradh if (bo == NULL) 680003b705cfSriastradh break; 680103b705cfSriastradh 680203b705cfSriastradh DBG(("%s: discarding inactive %s vma cache for %d\n", 68039a906b70Schristos __FUNCTION__, type ? "CPU" : "GTT", bo->handle)); 68049a906b70Schristos 680503b705cfSriastradh assert(bo->rq == NULL); 6806813957e3Ssnj if (type) { 6807813957e3Ssnj VG(VALGRIND_MAKE_MEM_NOACCESS(MAP(bo->map__cpu), bytes(bo))); 6808813957e3Ssnj munmap(MAP(bo->map__cpu), bytes(bo)); 6809813957e3Ssnj bo->map__cpu = NULL; 6810813957e3Ssnj } else { 6811813957e3Ssnj if (bo->map__wc) { 6812813957e3Ssnj VG(VALGRIND_MAKE_MEM_NOACCESS(bo->map__wc, bytes(bo))); 6813813957e3Ssnj munmap(bo->map__wc, bytes(bo)); 6814813957e3Ssnj bo->map__wc = NULL; 6815813957e3Ssnj } 6816813957e3Ssnj if (bo->map__gtt) { 6817813957e3Ssnj munmap(bo->map__gtt, bytes(bo)); 6818813957e3Ssnj bo->map__gtt = NULL; 6819813957e3Ssnj } 6820813957e3Ssnj } 682103b705cfSriastradh 682203b705cfSriastradh list_del(&bo->vma); 682303b705cfSriastradh kgem->vma[type].count--; 682403b705cfSriastradh } 682503b705cfSriastradh} 682603b705cfSriastradh 6827813957e3Ssnjstatic void *__kgem_bo_map__gtt_or_wc(struct kgem *kgem, struct kgem_bo *bo) 682803b705cfSriastradh{ 682903b705cfSriastradh void *ptr; 683003b705cfSriastradh 6831813957e3Ssnj DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle)); 6832813957e3Ssnj 6833813957e3Ssnj assert(bo->proxy == NULL); 6834813957e3Ssnj assert(!bo->snoop); 6835813957e3Ssnj 6836813957e3Ssnj kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo)); 6837813957e3Ssnj 6838813957e3Ssnj if (bo->tiling || !kgem->has_wc_mmap) { 6839813957e3Ssnj assert(kgem->gen != 021 || bo->tiling != I915_TILING_Y); 684063ef14f0Smrg warn_unless(num_pages(bo) <= kgem->aperture_mappable / 2); 6841813957e3Ssnj 6842813957e3Ssnj ptr = bo->map__gtt; 6843813957e3Ssnj if (ptr == NULL) 6844813957e3Ssnj ptr = __kgem_bo_map__gtt(kgem, bo); 6845813957e3Ssnj } else { 6846813957e3Ssnj ptr = bo->map__wc; 6847813957e3Ssnj if (ptr == NULL) 6848813957e3Ssnj ptr = __kgem_bo_map__wc(kgem, bo); 6849813957e3Ssnj } 6850813957e3Ssnj 6851813957e3Ssnj return ptr; 6852813957e3Ssnj} 6853813957e3Ssnj 6854813957e3Ssnjvoid *kgem_bo_map__async(struct kgem *kgem, struct kgem_bo *bo) 6855813957e3Ssnj{ 68569a906b70Schristos DBG(("%s: handle=%d, offset=%ld, tiling=%d, map=%p:%p, domain=%d\n", __FUNCTION__, 68579a906b70Schristos bo->handle, (long)bo->presumed_offset, bo->tiling, bo->map__gtt, bo->map__cpu, bo->domain)); 685803b705cfSriastradh 685903b705cfSriastradh assert(bo->proxy == NULL); 686003b705cfSriastradh assert(list_is_empty(&bo->list)); 686103b705cfSriastradh assert_tiling(kgem, bo); 68629a906b70Schristos assert(!bo->purged || bo->reusable); 686303b705cfSriastradh 686403b705cfSriastradh if (bo->tiling == I915_TILING_NONE && !bo->scanout && kgem->has_llc) { 686503b705cfSriastradh DBG(("%s: converting request for GTT map into CPU map\n", 686603b705cfSriastradh __FUNCTION__)); 686703b705cfSriastradh return kgem_bo_map__cpu(kgem, bo); 686803b705cfSriastradh } 686903b705cfSriastradh 6870813957e3Ssnj return __kgem_bo_map__gtt_or_wc(kgem, bo); 687103b705cfSriastradh} 687203b705cfSriastradh 687303b705cfSriastradhvoid *kgem_bo_map(struct kgem *kgem, struct kgem_bo *bo) 687403b705cfSriastradh{ 687503b705cfSriastradh void *ptr; 687603b705cfSriastradh 68779a906b70Schristos DBG(("%s: handle=%d, offset=%ld, tiling=%d, map=%p:%p, domain=%d\n", __FUNCTION__, 68789a906b70Schristos bo->handle, (long)bo->presumed_offset, bo->tiling, bo->map__gtt, bo->map__cpu, bo->domain)); 687903b705cfSriastradh 688003b705cfSriastradh assert(bo->proxy == NULL); 688103b705cfSriastradh assert(list_is_empty(&bo->list)); 688203b705cfSriastradh assert(bo->exec == NULL); 688303b705cfSriastradh assert_tiling(kgem, bo); 68849a906b70Schristos assert(!bo->purged || bo->reusable); 688503b705cfSriastradh 688603b705cfSriastradh if (bo->tiling == I915_TILING_NONE && !bo->scanout && 688703b705cfSriastradh (kgem->has_llc || bo->domain == DOMAIN_CPU)) { 688803b705cfSriastradh DBG(("%s: converting request for GTT map into CPU map\n", 688903b705cfSriastradh __FUNCTION__)); 689003b705cfSriastradh ptr = kgem_bo_map__cpu(kgem, bo); 689103b705cfSriastradh if (ptr) 689203b705cfSriastradh kgem_bo_sync__cpu(kgem, bo); 689303b705cfSriastradh return ptr; 689403b705cfSriastradh } 689503b705cfSriastradh 6896813957e3Ssnj ptr = __kgem_bo_map__gtt_or_wc(kgem, bo); 689703b705cfSriastradh 689803b705cfSriastradh if (bo->domain != DOMAIN_GTT || FORCE_MMAP_SYNC & (1 << DOMAIN_GTT)) { 689903b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 690003b705cfSriastradh 690103b705cfSriastradh DBG(("%s: sync: needs_flush? %d, domain? %d, busy? %d\n", __FUNCTION__, 690203b705cfSriastradh bo->needs_flush, bo->domain, __kgem_busy(kgem, bo->handle))); 690303b705cfSriastradh 690403b705cfSriastradh /* XXX use PROT_READ to avoid the write flush? */ 690503b705cfSriastradh 690603b705cfSriastradh VG_CLEAR(set_domain); 690703b705cfSriastradh set_domain.handle = bo->handle; 690803b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_GTT; 690903b705cfSriastradh set_domain.write_domain = I915_GEM_DOMAIN_GTT; 69109a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 69119a906b70Schristos DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 69129a906b70Schristos kgem_throttle(kgem); 691303b705cfSriastradh } 691463ef14f0Smrg bo->needs_flush = false; 69159a906b70Schristos kgem_bo_retire(kgem, bo); 69169a906b70Schristos bo->domain = DOMAIN_GTT; 69179a906b70Schristos bo->gtt_dirty = true; 691803b705cfSriastradh } 691903b705cfSriastradh 692003b705cfSriastradh return ptr; 692103b705cfSriastradh} 692203b705cfSriastradh 692303b705cfSriastradhvoid *kgem_bo_map__gtt(struct kgem *kgem, struct kgem_bo *bo) 692403b705cfSriastradh{ 69259a906b70Schristos DBG(("%s: handle=%d, offset=%ld, tiling=%d, map=%p:%p, domain=%d\n", __FUNCTION__, 69269a906b70Schristos bo->handle, (long)bo->presumed_offset, bo->tiling, bo->map__gtt, bo->map__cpu, bo->domain)); 692703b705cfSriastradh 69289a906b70Schristos assert(bo->proxy == NULL); 692903b705cfSriastradh assert(bo->exec == NULL); 693003b705cfSriastradh assert(list_is_empty(&bo->list)); 693103b705cfSriastradh assert_tiling(kgem, bo); 69329a906b70Schristos assert(!bo->purged || bo->reusable); 693303b705cfSriastradh 6934813957e3Ssnj return __kgem_bo_map__gtt_or_wc(kgem, bo); 6935813957e3Ssnj} 693603b705cfSriastradh 6937813957e3Ssnjvoid *kgem_bo_map__wc(struct kgem *kgem, struct kgem_bo *bo) 6938813957e3Ssnj{ 6939813957e3Ssnj DBG(("%s: handle=%d, offset=%ld, tiling=%d, map=%p:%p, domain=%d\n", __FUNCTION__, 6940813957e3Ssnj bo->handle, (long)bo->presumed_offset, bo->tiling, bo->map__gtt, bo->map__cpu, bo->domain)); 694103b705cfSriastradh 6942813957e3Ssnj assert(bo->proxy == NULL); 6943813957e3Ssnj assert(list_is_empty(&bo->list)); 6944813957e3Ssnj assert_tiling(kgem, bo); 6945813957e3Ssnj assert(!bo->purged || bo->reusable); 694603b705cfSriastradh 6947813957e3Ssnj if (bo->map__wc) 6948813957e3Ssnj return bo->map__wc; 694963ef14f0Smrg if (!kgem->has_wc_mmap) 695063ef14f0Smrg return NULL; 695103b705cfSriastradh 695263ef14f0Smrg kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo)); 6953813957e3Ssnj return __kgem_bo_map__wc(kgem, bo); 695403b705cfSriastradh} 695503b705cfSriastradh 695603b705cfSriastradhvoid *kgem_bo_map__cpu(struct kgem *kgem, struct kgem_bo *bo) 695703b705cfSriastradh{ 69589a906b70Schristos DBG(("%s(handle=%d, size=%d, map=%p:%p)\n", 69599a906b70Schristos __FUNCTION__, bo->handle, bytes(bo), bo->map__gtt, bo->map__cpu)); 696003b705cfSriastradh assert(!bo->purged); 696103b705cfSriastradh assert(list_is_empty(&bo->list)); 696203b705cfSriastradh assert(bo->proxy == NULL); 69639a906b70Schristos assert_tiling(kgem, bo); 696403b705cfSriastradh 69659a906b70Schristos if (bo->map__cpu) 69669a906b70Schristos return MAP(bo->map__cpu); 696703b705cfSriastradh 696803b705cfSriastradh kgem_trim_vma_cache(kgem, MAP_CPU, bucket(bo)); 696903b705cfSriastradh 6970813957e3Ssnj return __kgem_bo_map__cpu(kgem, bo); 6971813957e3Ssnj} 697203b705cfSriastradh 6973813957e3Ssnjvoid *kgem_bo_map__debug(struct kgem *kgem, struct kgem_bo *bo) 6974813957e3Ssnj{ 6975813957e3Ssnj void *ptr; 697603b705cfSriastradh 6977813957e3Ssnj if (bo->tiling == I915_TILING_NONE && kgem->has_llc) { 6978813957e3Ssnj ptr = MAP(bo->map__cpu); 6979813957e3Ssnj if (ptr == NULL) 6980813957e3Ssnj ptr = __kgem_bo_map__cpu(kgem, bo); 6981813957e3Ssnj } else if (bo->tiling || !kgem->has_wc_mmap) { 6982813957e3Ssnj ptr = bo->map__gtt; 6983813957e3Ssnj if (ptr == NULL) 6984813957e3Ssnj ptr = __kgem_bo_map__gtt(kgem, bo); 6985813957e3Ssnj } else { 6986813957e3Ssnj ptr = bo->map__wc; 6987813957e3Ssnj if (ptr == NULL) 6988813957e3Ssnj ptr = __kgem_bo_map__wc(kgem, bo); 698903b705cfSriastradh } 699003b705cfSriastradh 6991813957e3Ssnj return ptr; 699203b705cfSriastradh} 699303b705cfSriastradh 6994813957e3Ssnj 699503b705cfSriastradhuint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo) 699603b705cfSriastradh{ 699703b705cfSriastradh struct drm_gem_flink flink; 699803b705cfSriastradh 699963ef14f0Smrg assert(kgem_bo_is_fenced(kgem, bo)); 700063ef14f0Smrg 700103b705cfSriastradh VG_CLEAR(flink); 700203b705cfSriastradh flink.handle = bo->handle; 70039a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_GEM_FLINK, &flink)) 700403b705cfSriastradh return 0; 700503b705cfSriastradh 700603b705cfSriastradh DBG(("%s: flinked handle=%d to name=%d, marking non-reusable\n", 700703b705cfSriastradh __FUNCTION__, flink.handle, flink.name)); 700803b705cfSriastradh 700903b705cfSriastradh /* Ordinarily giving the name aware makes the buffer non-reusable. 701003b705cfSriastradh * However, we track the lifetime of all clients and their hold 701103b705cfSriastradh * on the buffer, and *presuming* they do not pass it on to a third 701203b705cfSriastradh * party, we track the lifetime accurately. 701303b705cfSriastradh */ 701403b705cfSriastradh bo->reusable = false; 701503b705cfSriastradh kgem_bo_unclean(kgem, bo); 701603b705cfSriastradh 701703b705cfSriastradh return flink.name; 701803b705cfSriastradh} 701903b705cfSriastradh 702003b705cfSriastradhstruct kgem_bo *kgem_create_map(struct kgem *kgem, 702103b705cfSriastradh void *ptr, uint32_t size, 702203b705cfSriastradh bool read_only) 702303b705cfSriastradh{ 702403b705cfSriastradh struct kgem_bo *bo; 702503b705cfSriastradh uintptr_t first_page, last_page; 702603b705cfSriastradh uint32_t handle; 702703b705cfSriastradh 702803b705cfSriastradh assert(MAP(ptr) == ptr); 702903b705cfSriastradh 70309a906b70Schristos DBG(("%s(%p size=%d, read-only?=%d) - has_userptr?=%d\n", __FUNCTION__, 70319a906b70Schristos ptr, size, read_only, kgem->has_userptr)); 703203b705cfSriastradh if (!kgem->has_userptr) 703303b705cfSriastradh return NULL; 703403b705cfSriastradh 703503b705cfSriastradh first_page = (uintptr_t)ptr; 703603b705cfSriastradh last_page = first_page + size + PAGE_SIZE - 1; 703703b705cfSriastradh 703863ef14f0Smrg first_page &= ~(uintptr_t)(PAGE_SIZE-1); 703963ef14f0Smrg last_page &= ~(uintptr_t)(PAGE_SIZE-1); 704003b705cfSriastradh assert(last_page > first_page); 704103b705cfSriastradh 704203b705cfSriastradh handle = gem_userptr(kgem->fd, 704303b705cfSriastradh (void *)first_page, last_page-first_page, 704403b705cfSriastradh read_only); 70459a906b70Schristos if (handle == 0) { 704663ef14f0Smrg if (read_only && kgem->has_wc_mmap) { 704763ef14f0Smrg struct drm_i915_gem_set_domain set_domain; 704863ef14f0Smrg 704963ef14f0Smrg handle = gem_userptr(kgem->fd, 705063ef14f0Smrg (void *)first_page, last_page-first_page, 705163ef14f0Smrg false); 705263ef14f0Smrg 705363ef14f0Smrg VG_CLEAR(set_domain); 705463ef14f0Smrg set_domain.handle = handle; 705563ef14f0Smrg set_domain.read_domains = I915_GEM_DOMAIN_GTT; 705663ef14f0Smrg set_domain.write_domain = 0; 705763ef14f0Smrg if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 705863ef14f0Smrg gem_close(kgem->fd, handle); 705963ef14f0Smrg handle = 0; 706063ef14f0Smrg } 706163ef14f0Smrg } 706263ef14f0Smrg if (handle == 0) { 706363ef14f0Smrg DBG(("%s: import failed, errno=%d\n", __FUNCTION__, errno)); 706463ef14f0Smrg return NULL; 706563ef14f0Smrg } 70669a906b70Schristos } 706703b705cfSriastradh 706803b705cfSriastradh bo = __kgem_bo_alloc(handle, (last_page - first_page) / PAGE_SIZE); 706903b705cfSriastradh if (bo == NULL) { 707003b705cfSriastradh gem_close(kgem->fd, handle); 707103b705cfSriastradh return NULL; 707203b705cfSriastradh } 707303b705cfSriastradh 70749a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 707503b705cfSriastradh bo->snoop = !kgem->has_llc; 707603b705cfSriastradh debug_alloc__bo(kgem, bo); 707703b705cfSriastradh 707803b705cfSriastradh if (first_page != (uintptr_t)ptr) { 707903b705cfSriastradh struct kgem_bo *proxy; 708003b705cfSriastradh 708103b705cfSriastradh proxy = kgem_create_proxy(kgem, bo, 708203b705cfSriastradh (uintptr_t)ptr - first_page, size); 708303b705cfSriastradh kgem_bo_destroy(kgem, bo); 708403b705cfSriastradh if (proxy == NULL) 708503b705cfSriastradh return NULL; 708603b705cfSriastradh 708703b705cfSriastradh bo = proxy; 708803b705cfSriastradh } 708903b705cfSriastradh 70909a906b70Schristos bo->map__cpu = MAKE_USER_MAP(ptr); 709103b705cfSriastradh 709203b705cfSriastradh DBG(("%s(ptr=%p, size=%d, pages=%d, read_only=%d) => handle=%d (proxy? %d)\n", 709303b705cfSriastradh __FUNCTION__, ptr, size, NUM_PAGES(size), read_only, handle, bo->proxy != NULL)); 709403b705cfSriastradh return bo; 709503b705cfSriastradh} 709603b705cfSriastradh 709703b705cfSriastradhvoid kgem_bo_sync__cpu(struct kgem *kgem, struct kgem_bo *bo) 709803b705cfSriastradh{ 709903b705cfSriastradh DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle)); 710003b705cfSriastradh assert(!bo->scanout); 71019a906b70Schristos assert_tiling(kgem, bo); 71029a906b70Schristos 710303b705cfSriastradh kgem_bo_submit(kgem, bo); 710403b705cfSriastradh 710503b705cfSriastradh /* SHM pixmaps use proxies for subpage offsets */ 710603b705cfSriastradh assert(!bo->purged); 710703b705cfSriastradh while (bo->proxy) 710803b705cfSriastradh bo = bo->proxy; 710903b705cfSriastradh assert(!bo->purged); 711003b705cfSriastradh 711103b705cfSriastradh if (bo->domain != DOMAIN_CPU || FORCE_MMAP_SYNC & (1 << DOMAIN_CPU)) { 711203b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 711303b705cfSriastradh 711403b705cfSriastradh DBG(("%s: SYNC: handle=%d, needs_flush? %d, domain? %d, busy? %d\n", 711503b705cfSriastradh __FUNCTION__, bo->handle, 711603b705cfSriastradh bo->needs_flush, bo->domain, 711703b705cfSriastradh __kgem_busy(kgem, bo->handle))); 711803b705cfSriastradh 711903b705cfSriastradh VG_CLEAR(set_domain); 712003b705cfSriastradh set_domain.handle = bo->handle; 712103b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_CPU; 712203b705cfSriastradh set_domain.write_domain = I915_GEM_DOMAIN_CPU; 712303b705cfSriastradh 71249a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 71259a906b70Schristos DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 71269a906b70Schristos kgem_throttle(kgem); 712703b705cfSriastradh } 712863ef14f0Smrg bo->needs_flush = false; 71299a906b70Schristos kgem_bo_retire(kgem, bo); 71309a906b70Schristos bo->domain = DOMAIN_CPU; 713163ef14f0Smrg bo->gtt_dirty = true; 713203b705cfSriastradh } 713303b705cfSriastradh} 713403b705cfSriastradh 713503b705cfSriastradhvoid kgem_bo_sync__cpu_full(struct kgem *kgem, struct kgem_bo *bo, bool write) 713603b705cfSriastradh{ 713703b705cfSriastradh DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle)); 713803b705cfSriastradh assert(!bo->scanout || !write); 71399a906b70Schristos assert_tiling(kgem, bo); 714003b705cfSriastradh 714103b705cfSriastradh if (write || bo->needs_flush) 714203b705cfSriastradh kgem_bo_submit(kgem, bo); 714303b705cfSriastradh 714403b705cfSriastradh /* SHM pixmaps use proxies for subpage offsets */ 714503b705cfSriastradh assert(!bo->purged); 714603b705cfSriastradh assert(bo->refcnt); 714703b705cfSriastradh while (bo->proxy) 714803b705cfSriastradh bo = bo->proxy; 714903b705cfSriastradh assert(bo->refcnt); 715003b705cfSriastradh assert(!bo->purged); 715103b705cfSriastradh 715263ef14f0Smrg if (bo->rq == NULL && (kgem->has_llc || bo->snoop) && !write) 715363ef14f0Smrg return; 715463ef14f0Smrg 715503b705cfSriastradh if (bo->domain != DOMAIN_CPU || FORCE_MMAP_SYNC & (1 << DOMAIN_CPU)) { 715603b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 715703b705cfSriastradh 715803b705cfSriastradh DBG(("%s: SYNC: handle=%d, needs_flush? %d, domain? %d, busy? %d\n", 715903b705cfSriastradh __FUNCTION__, bo->handle, 716003b705cfSriastradh bo->needs_flush, bo->domain, 716103b705cfSriastradh __kgem_busy(kgem, bo->handle))); 716203b705cfSriastradh 716303b705cfSriastradh VG_CLEAR(set_domain); 716403b705cfSriastradh set_domain.handle = bo->handle; 716503b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_CPU; 716603b705cfSriastradh set_domain.write_domain = write ? I915_GEM_DOMAIN_CPU : 0; 716703b705cfSriastradh 71689a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 71699a906b70Schristos DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 71709a906b70Schristos kgem_throttle(kgem); 71719a906b70Schristos } 717263ef14f0Smrg bo->needs_flush = false; 71739a906b70Schristos if (write) { 71749a906b70Schristos kgem_bo_retire(kgem, bo); 71759a906b70Schristos bo->domain = DOMAIN_CPU; 717663ef14f0Smrg bo->gtt_dirty = true; 71779a906b70Schristos } else { 717803b705cfSriastradh if (bo->exec == NULL) 71799a906b70Schristos kgem_bo_maybe_retire(kgem, bo); 71809a906b70Schristos bo->domain = DOMAIN_NONE; 718103b705cfSriastradh } 718203b705cfSriastradh } 718303b705cfSriastradh} 718403b705cfSriastradh 718503b705cfSriastradhvoid kgem_bo_sync__gtt(struct kgem *kgem, struct kgem_bo *bo) 718603b705cfSriastradh{ 718703b705cfSriastradh DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle)); 718803b705cfSriastradh assert(bo->refcnt); 718903b705cfSriastradh assert(bo->proxy == NULL); 71909a906b70Schristos assert_tiling(kgem, bo); 719163ef14f0Smrg assert(!bo->snoop); 719203b705cfSriastradh 719303b705cfSriastradh kgem_bo_submit(kgem, bo); 719403b705cfSriastradh 719563ef14f0Smrg if (bo->domain != DOMAIN_GTT || 719663ef14f0Smrg !kgem->has_coherent_mmap_gtt || 719763ef14f0Smrg FORCE_MMAP_SYNC & (1 << DOMAIN_GTT)) { 719803b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 719903b705cfSriastradh 720003b705cfSriastradh DBG(("%s: SYNC: handle=%d, needs_flush? %d, domain? %d, busy? %d\n", 720103b705cfSriastradh __FUNCTION__, bo->handle, 720203b705cfSriastradh bo->needs_flush, bo->domain, 720303b705cfSriastradh __kgem_busy(kgem, bo->handle))); 720403b705cfSriastradh 720503b705cfSriastradh VG_CLEAR(set_domain); 720603b705cfSriastradh set_domain.handle = bo->handle; 720703b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_GTT; 720803b705cfSriastradh set_domain.write_domain = I915_GEM_DOMAIN_GTT; 720903b705cfSriastradh 72109a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 72119a906b70Schristos DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 72129a906b70Schristos kgem_throttle(kgem); 721303b705cfSriastradh } 721463ef14f0Smrg bo->needs_flush = false; 72159a906b70Schristos kgem_bo_retire(kgem, bo); 72169a906b70Schristos bo->domain = DOMAIN_GTT; 72179a906b70Schristos bo->gtt_dirty = true; 721803b705cfSriastradh } 721903b705cfSriastradh} 722003b705cfSriastradh 722103b705cfSriastradhvoid kgem_clear_dirty(struct kgem *kgem) 722203b705cfSriastradh{ 722303b705cfSriastradh struct list * const buffers = &kgem->next_request->buffers; 722403b705cfSriastradh struct kgem_bo *bo; 722503b705cfSriastradh 722603b705cfSriastradh list_for_each_entry(bo, buffers, request) { 722703b705cfSriastradh if (!bo->gpu_dirty) 722803b705cfSriastradh break; 722903b705cfSriastradh 723003b705cfSriastradh bo->gpu_dirty = false; 723103b705cfSriastradh } 723203b705cfSriastradh} 723303b705cfSriastradh 723403b705cfSriastradhstruct kgem_bo *kgem_create_proxy(struct kgem *kgem, 723503b705cfSriastradh struct kgem_bo *target, 723603b705cfSriastradh int offset, int length) 723703b705cfSriastradh{ 723803b705cfSriastradh struct kgem_bo *bo; 723903b705cfSriastradh 724003b705cfSriastradh DBG(("%s: target handle=%d [proxy? %d], offset=%d, length=%d, io=%d\n", 724103b705cfSriastradh __FUNCTION__, target->handle, target->proxy ? target->proxy->delta : -1, 724203b705cfSriastradh offset, length, target->io)); 724303b705cfSriastradh 724403b705cfSriastradh bo = __kgem_bo_alloc(target->handle, length); 724503b705cfSriastradh if (bo == NULL) 724603b705cfSriastradh return NULL; 724703b705cfSriastradh 724803b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 724903b705cfSriastradh bo->reusable = false; 725003b705cfSriastradh bo->size.bytes = length; 725103b705cfSriastradh 725203b705cfSriastradh bo->io = target->io && target->proxy == NULL; 725303b705cfSriastradh bo->gpu_dirty = target->gpu_dirty; 725403b705cfSriastradh bo->tiling = target->tiling; 725503b705cfSriastradh bo->pitch = target->pitch; 725603b705cfSriastradh bo->flush = target->flush; 725703b705cfSriastradh bo->snoop = target->snoop; 725803b705cfSriastradh 725903b705cfSriastradh assert(!bo->scanout); 726003b705cfSriastradh bo->proxy = kgem_bo_reference(target); 726103b705cfSriastradh bo->delta = offset; 726203b705cfSriastradh 72639a906b70Schristos /* Proxies are only tracked for busyness on the current rq */ 72649a906b70Schristos if (target->exec && !bo->io) { 72659a906b70Schristos assert(RQ(target->rq) == kgem->next_request); 726603b705cfSriastradh list_move_tail(&bo->request, &kgem->next_request->buffers); 726703b705cfSriastradh bo->exec = &_kgem_dummy_exec; 72689a906b70Schristos bo->rq = target->rq; 726903b705cfSriastradh } 727003b705cfSriastradh 727103b705cfSriastradh return bo; 727203b705cfSriastradh} 727303b705cfSriastradh 727403b705cfSriastradhstatic struct kgem_buffer * 727503b705cfSriastradhbuffer_alloc(void) 727603b705cfSriastradh{ 727703b705cfSriastradh struct kgem_buffer *bo; 727803b705cfSriastradh 727903b705cfSriastradh bo = malloc(sizeof(*bo)); 728003b705cfSriastradh if (bo == NULL) 728103b705cfSriastradh return NULL; 728203b705cfSriastradh 728303b705cfSriastradh bo->mem = NULL; 728403b705cfSriastradh bo->need_io = false; 72859a906b70Schristos bo->mmapped = MMAPPED_CPU; 728603b705cfSriastradh 728703b705cfSriastradh return bo; 728803b705cfSriastradh} 728903b705cfSriastradh 729003b705cfSriastradhstatic struct kgem_buffer * 729103b705cfSriastradhbuffer_alloc_with_data(int num_pages) 729203b705cfSriastradh{ 729303b705cfSriastradh struct kgem_buffer *bo; 729403b705cfSriastradh 729503b705cfSriastradh bo = malloc(sizeof(*bo) + 2*UPLOAD_ALIGNMENT + num_pages * PAGE_SIZE); 729603b705cfSriastradh if (bo == NULL) 729703b705cfSriastradh return NULL; 729803b705cfSriastradh 729903b705cfSriastradh bo->mem = (void *)ALIGN((uintptr_t)bo + sizeof(*bo), UPLOAD_ALIGNMENT); 730003b705cfSriastradh bo->mmapped = false; 730103b705cfSriastradh return bo; 730203b705cfSriastradh} 730303b705cfSriastradh 730403b705cfSriastradhstatic inline bool 730503b705cfSriastradhuse_snoopable_buffer(struct kgem *kgem, uint32_t flags) 730603b705cfSriastradh{ 730703b705cfSriastradh if ((flags & KGEM_BUFFER_WRITE) == 0) 730803b705cfSriastradh return kgem->gen >= 030; 730903b705cfSriastradh 731003b705cfSriastradh return true; 731103b705cfSriastradh} 731203b705cfSriastradh 731303b705cfSriastradhstatic void 731403b705cfSriastradhinit_buffer_from_bo(struct kgem_buffer *bo, struct kgem_bo *old) 731503b705cfSriastradh{ 731603b705cfSriastradh DBG(("%s: reusing handle=%d for buffer\n", 731703b705cfSriastradh __FUNCTION__, old->handle)); 731803b705cfSriastradh 731903b705cfSriastradh assert(old->proxy == NULL); 7320813957e3Ssnj assert(list_is_empty(&old->list)); 732103b705cfSriastradh 732203b705cfSriastradh memcpy(&bo->base, old, sizeof(*old)); 732303b705cfSriastradh if (old->rq) 732403b705cfSriastradh list_replace(&old->request, &bo->base.request); 732503b705cfSriastradh else 732603b705cfSriastradh list_init(&bo->base.request); 732703b705cfSriastradh list_replace(&old->vma, &bo->base.vma); 732803b705cfSriastradh list_init(&bo->base.list); 732903b705cfSriastradh free(old); 733003b705cfSriastradh 733103b705cfSriastradh assert(bo->base.tiling == I915_TILING_NONE); 733203b705cfSriastradh 733303b705cfSriastradh bo->base.refcnt = 1; 733403b705cfSriastradh} 733503b705cfSriastradh 733603b705cfSriastradhstatic struct kgem_buffer * 733703b705cfSriastradhsearch_snoopable_buffer(struct kgem *kgem, unsigned alloc) 733803b705cfSriastradh{ 733903b705cfSriastradh struct kgem_buffer *bo; 734003b705cfSriastradh struct kgem_bo *old; 734103b705cfSriastradh 734203b705cfSriastradh old = search_snoop_cache(kgem, alloc, 0); 734303b705cfSriastradh if (old) { 734403b705cfSriastradh if (!old->io) { 734503b705cfSriastradh bo = buffer_alloc(); 734603b705cfSriastradh if (bo == NULL) 734703b705cfSriastradh return NULL; 734803b705cfSriastradh 734903b705cfSriastradh init_buffer_from_bo(bo, old); 735003b705cfSriastradh } else { 735103b705cfSriastradh bo = (struct kgem_buffer *)old; 735203b705cfSriastradh bo->base.refcnt = 1; 735303b705cfSriastradh } 735403b705cfSriastradh 735503b705cfSriastradh DBG(("%s: created CPU handle=%d for buffer, size %d\n", 735603b705cfSriastradh __FUNCTION__, bo->base.handle, num_pages(&bo->base))); 735703b705cfSriastradh 735803b705cfSriastradh assert(bo->base.snoop); 735903b705cfSriastradh assert(bo->base.tiling == I915_TILING_NONE); 736003b705cfSriastradh assert(num_pages(&bo->base) >= alloc); 73619a906b70Schristos assert(bo->mmapped == MMAPPED_CPU); 736203b705cfSriastradh assert(bo->need_io == false); 736303b705cfSriastradh 736403b705cfSriastradh bo->mem = kgem_bo_map__cpu(kgem, &bo->base); 736503b705cfSriastradh if (bo->mem == NULL) { 736603b705cfSriastradh bo->base.refcnt = 0; 736703b705cfSriastradh kgem_bo_free(kgem, &bo->base); 736803b705cfSriastradh bo = NULL; 736903b705cfSriastradh } 737003b705cfSriastradh 737103b705cfSriastradh return bo; 737203b705cfSriastradh } 737303b705cfSriastradh 737403b705cfSriastradh return NULL; 737503b705cfSriastradh} 737603b705cfSriastradh 737703b705cfSriastradhstatic struct kgem_buffer * 737803b705cfSriastradhcreate_snoopable_buffer(struct kgem *kgem, unsigned alloc) 737903b705cfSriastradh{ 738003b705cfSriastradh struct kgem_buffer *bo; 738103b705cfSriastradh uint32_t handle; 738203b705cfSriastradh 738303b705cfSriastradh if (kgem->has_llc) { 738403b705cfSriastradh struct kgem_bo *old; 738503b705cfSriastradh 738603b705cfSriastradh bo = buffer_alloc(); 738703b705cfSriastradh if (bo == NULL) 738803b705cfSriastradh return NULL; 738903b705cfSriastradh 739003b705cfSriastradh old = search_linear_cache(kgem, alloc, 739103b705cfSriastradh CREATE_INACTIVE | CREATE_CPU_MAP | CREATE_EXACT); 739203b705cfSriastradh if (old) { 739303b705cfSriastradh init_buffer_from_bo(bo, old); 739403b705cfSriastradh } else { 739503b705cfSriastradh handle = gem_create(kgem->fd, alloc); 739603b705cfSriastradh if (handle == 0) { 739703b705cfSriastradh free(bo); 739803b705cfSriastradh return NULL; 739903b705cfSriastradh } 740003b705cfSriastradh 740103b705cfSriastradh __kgem_bo_init(&bo->base, handle, alloc); 74029a906b70Schristos debug_alloc__bo(kgem, &bo->base); 740303b705cfSriastradh DBG(("%s: created CPU (LLC) handle=%d for buffer, size %d\n", 740403b705cfSriastradh __FUNCTION__, bo->base.handle, alloc)); 740503b705cfSriastradh } 740603b705cfSriastradh 740703b705cfSriastradh assert(bo->base.refcnt == 1); 74089a906b70Schristos assert(bo->mmapped == MMAPPED_CPU); 740903b705cfSriastradh assert(bo->need_io == false); 741003b705cfSriastradh 741103b705cfSriastradh bo->mem = kgem_bo_map__cpu(kgem, &bo->base); 741203b705cfSriastradh if (bo->mem != NULL) 741303b705cfSriastradh return bo; 741403b705cfSriastradh 741503b705cfSriastradh bo->base.refcnt = 0; /* for valgrind */ 741603b705cfSriastradh kgem_bo_free(kgem, &bo->base); 741703b705cfSriastradh } 741803b705cfSriastradh 741903b705cfSriastradh if (kgem->has_caching) { 742003b705cfSriastradh struct kgem_bo *old; 742103b705cfSriastradh 742203b705cfSriastradh bo = buffer_alloc(); 742303b705cfSriastradh if (bo == NULL) 742403b705cfSriastradh return NULL; 742503b705cfSriastradh 742603b705cfSriastradh old = search_linear_cache(kgem, alloc, 742703b705cfSriastradh CREATE_INACTIVE | CREATE_CPU_MAP | CREATE_EXACT); 742803b705cfSriastradh if (old) { 742903b705cfSriastradh init_buffer_from_bo(bo, old); 743003b705cfSriastradh } else { 743103b705cfSriastradh handle = gem_create(kgem->fd, alloc); 743203b705cfSriastradh if (handle == 0) { 743303b705cfSriastradh free(bo); 743403b705cfSriastradh return NULL; 743503b705cfSriastradh } 743603b705cfSriastradh 743703b705cfSriastradh __kgem_bo_init(&bo->base, handle, alloc); 74389a906b70Schristos debug_alloc__bo(kgem, &bo->base); 743903b705cfSriastradh DBG(("%s: created CPU handle=%d for buffer, size %d\n", 744003b705cfSriastradh __FUNCTION__, bo->base.handle, alloc)); 744103b705cfSriastradh } 744203b705cfSriastradh 744303b705cfSriastradh assert(bo->base.refcnt == 1); 74449a906b70Schristos assert(bo->mmapped == MMAPPED_CPU); 744503b705cfSriastradh assert(bo->need_io == false); 7446813957e3Ssnj assert(!__kgem_busy(kgem, bo->base.handle)); 744703b705cfSriastradh 744803b705cfSriastradh if (!gem_set_caching(kgem->fd, bo->base.handle, SNOOPED)) 744903b705cfSriastradh goto free_caching; 745003b705cfSriastradh 745103b705cfSriastradh bo->base.snoop = true; 745203b705cfSriastradh 745303b705cfSriastradh bo->mem = kgem_bo_map__cpu(kgem, &bo->base); 745403b705cfSriastradh if (bo->mem == NULL) 745503b705cfSriastradh goto free_caching; 745603b705cfSriastradh 745703b705cfSriastradh return bo; 745803b705cfSriastradh 745903b705cfSriastradhfree_caching: 746003b705cfSriastradh bo->base.refcnt = 0; /* for valgrind */ 746103b705cfSriastradh kgem_bo_free(kgem, &bo->base); 746203b705cfSriastradh } 746303b705cfSriastradh 746403b705cfSriastradh if (kgem->has_userptr) { 746503b705cfSriastradh bo = buffer_alloc(); 746603b705cfSriastradh if (bo == NULL) 746703b705cfSriastradh return NULL; 746803b705cfSriastradh 746903b705cfSriastradh //if (posix_memalign(&ptr, 64, ALIGN(size, 64))) 747003b705cfSriastradh if (posix_memalign(&bo->mem, PAGE_SIZE, alloc * PAGE_SIZE)) { 747103b705cfSriastradh free(bo); 747203b705cfSriastradh return NULL; 747303b705cfSriastradh } 747403b705cfSriastradh 747503b705cfSriastradh handle = gem_userptr(kgem->fd, bo->mem, alloc * PAGE_SIZE, false); 747603b705cfSriastradh if (handle == 0) { 747703b705cfSriastradh free(bo->mem); 747803b705cfSriastradh free(bo); 747903b705cfSriastradh return NULL; 748003b705cfSriastradh } 748103b705cfSriastradh 748203b705cfSriastradh __kgem_bo_init(&bo->base, handle, alloc); 74839a906b70Schristos debug_alloc__bo(kgem, &bo->base); 748403b705cfSriastradh DBG(("%s: created snoop handle=%d for buffer\n", 748503b705cfSriastradh __FUNCTION__, bo->base.handle)); 748603b705cfSriastradh 74879a906b70Schristos assert(bo->mmapped == MMAPPED_CPU); 748803b705cfSriastradh assert(bo->need_io == false); 748903b705cfSriastradh 749003b705cfSriastradh bo->base.refcnt = 1; 749103b705cfSriastradh bo->base.snoop = true; 74929a906b70Schristos bo->base.map__cpu = MAKE_USER_MAP(bo->mem); 749303b705cfSriastradh 749403b705cfSriastradh return bo; 749503b705cfSriastradh } 749603b705cfSriastradh 749703b705cfSriastradh return NULL; 749803b705cfSriastradh} 749903b705cfSriastradh 750003b705cfSriastradhstruct kgem_bo *kgem_create_buffer(struct kgem *kgem, 750103b705cfSriastradh uint32_t size, uint32_t flags, 750203b705cfSriastradh void **ret) 750303b705cfSriastradh{ 750403b705cfSriastradh struct kgem_buffer *bo; 750503b705cfSriastradh unsigned offset, alloc; 750603b705cfSriastradh struct kgem_bo *old; 750703b705cfSriastradh 750803b705cfSriastradh DBG(("%s: size=%d, flags=%x [write?=%d, inplace?=%d, last?=%d]\n", 750903b705cfSriastradh __FUNCTION__, size, flags, 751003b705cfSriastradh !!(flags & KGEM_BUFFER_WRITE), 751103b705cfSriastradh !!(flags & KGEM_BUFFER_INPLACE), 751203b705cfSriastradh !!(flags & KGEM_BUFFER_LAST))); 751303b705cfSriastradh assert(size); 751403b705cfSriastradh /* we should never be asked to create anything TOO large */ 751503b705cfSriastradh assert(size <= kgem->max_object_size); 751603b705cfSriastradh 751703b705cfSriastradh#if !DBG_NO_UPLOAD_CACHE 751803b705cfSriastradh list_for_each_entry(bo, &kgem->batch_buffers, base.list) { 751903b705cfSriastradh assert(bo->base.io); 752003b705cfSriastradh assert(bo->base.refcnt >= 1); 752103b705cfSriastradh 752203b705cfSriastradh /* We can reuse any write buffer which we can fit */ 752303b705cfSriastradh if (flags == KGEM_BUFFER_LAST && 752403b705cfSriastradh bo->write == KGEM_BUFFER_WRITE && 75259a906b70Schristos bo->base.refcnt == 1 && 75269a906b70Schristos bo->mmapped == MMAPPED_NONE && 752703b705cfSriastradh size <= bytes(&bo->base)) { 752803b705cfSriastradh DBG(("%s: reusing write buffer for read of %d bytes? used=%d, total=%d\n", 752903b705cfSriastradh __FUNCTION__, size, bo->used, bytes(&bo->base))); 75309a906b70Schristos gem_write__cachealigned(kgem->fd, bo->base.handle, 75319a906b70Schristos 0, bo->used, bo->mem); 75329a906b70Schristos assert(list_is_empty(&bo->base.vma)); 753303b705cfSriastradh bo->need_io = 0; 753403b705cfSriastradh bo->write = 0; 753503b705cfSriastradh offset = 0; 753603b705cfSriastradh bo->used = size; 753703b705cfSriastradh goto done; 753803b705cfSriastradh } 753903b705cfSriastradh 754003b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) { 754103b705cfSriastradh if ((bo->write & KGEM_BUFFER_WRITE) == 0 || 754203b705cfSriastradh (((bo->write & ~flags) & KGEM_BUFFER_INPLACE) && 754303b705cfSriastradh !bo->base.snoop)) { 754403b705cfSriastradh DBG(("%s: skip write %x buffer, need %x\n", 754503b705cfSriastradh __FUNCTION__, bo->write, flags)); 754603b705cfSriastradh continue; 754703b705cfSriastradh } 754803b705cfSriastradh assert(bo->mmapped || bo->need_io); 754903b705cfSriastradh } else { 755003b705cfSriastradh if (bo->write & KGEM_BUFFER_WRITE) { 755103b705cfSriastradh DBG(("%s: skip write %x buffer, need %x\n", 755203b705cfSriastradh __FUNCTION__, bo->write, flags)); 755303b705cfSriastradh continue; 755403b705cfSriastradh } 755503b705cfSriastradh } 755603b705cfSriastradh 755703b705cfSriastradh if (bo->used + size <= bytes(&bo->base)) { 755803b705cfSriastradh DBG(("%s: reusing buffer? used=%d + size=%d, total=%d\n", 755903b705cfSriastradh __FUNCTION__, bo->used, size, bytes(&bo->base))); 756003b705cfSriastradh offset = bo->used; 756103b705cfSriastradh bo->used += size; 756203b705cfSriastradh goto done; 756303b705cfSriastradh } 756403b705cfSriastradh } 756503b705cfSriastradh 756603b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) { 756703b705cfSriastradh list_for_each_entry(bo, &kgem->active_buffers, base.list) { 756803b705cfSriastradh assert(bo->base.io); 756903b705cfSriastradh assert(bo->base.refcnt >= 1); 75709a906b70Schristos assert(bo->base.exec == NULL); 757103b705cfSriastradh assert(bo->mmapped); 75729a906b70Schristos assert(bo->mmapped == MMAPPED_GTT || kgem->has_llc || bo->base.snoop); 757303b705cfSriastradh 75749a906b70Schristos if ((bo->write & ~flags) & KGEM_BUFFER_INPLACE && !bo->base.snoop) { 757503b705cfSriastradh DBG(("%s: skip write %x buffer, need %x\n", 757603b705cfSriastradh __FUNCTION__, bo->write, flags)); 757703b705cfSriastradh continue; 757803b705cfSriastradh } 757903b705cfSriastradh 758003b705cfSriastradh if (bo->used + size <= bytes(&bo->base)) { 758103b705cfSriastradh DBG(("%s: reusing buffer? used=%d + size=%d, total=%d\n", 758203b705cfSriastradh __FUNCTION__, bo->used, size, bytes(&bo->base))); 758303b705cfSriastradh offset = bo->used; 758403b705cfSriastradh bo->used += size; 758503b705cfSriastradh list_move(&bo->base.list, &kgem->batch_buffers); 758603b705cfSriastradh goto done; 758703b705cfSriastradh } 75889a906b70Schristos 75899a906b70Schristos if (bo->base.refcnt == 1 && 75909a906b70Schristos size <= bytes(&bo->base) && 75919a906b70Schristos (bo->base.rq == NULL || 75929a906b70Schristos !__kgem_busy(kgem, bo->base.handle))) { 75939a906b70Schristos DBG(("%s: reusing whole buffer? size=%d, total=%d\n", 75949a906b70Schristos __FUNCTION__, size, bytes(&bo->base))); 75959a906b70Schristos __kgem_bo_clear_busy(&bo->base); 75969a906b70Schristos assert(list_is_empty(&bo->base.vma)); 75979a906b70Schristos 75989a906b70Schristos switch (bo->mmapped) { 75999a906b70Schristos case MMAPPED_CPU: 76009a906b70Schristos kgem_bo_sync__cpu(kgem, &bo->base); 76019a906b70Schristos break; 76029a906b70Schristos case MMAPPED_GTT: 76039a906b70Schristos kgem_bo_sync__gtt(kgem, &bo->base); 76049a906b70Schristos break; 76059a906b70Schristos } 76069a906b70Schristos 76079a906b70Schristos offset = 0; 76089a906b70Schristos bo->used = size; 76099a906b70Schristos list_move(&bo->base.list, &kgem->batch_buffers); 76109a906b70Schristos goto done; 76119a906b70Schristos } 761203b705cfSriastradh } 761303b705cfSriastradh } 761403b705cfSriastradh#endif 761503b705cfSriastradh 761603b705cfSriastradh#if !DBG_NO_MAP_UPLOAD 761703b705cfSriastradh /* Be a little more generous and hope to hold fewer mmappings */ 761803b705cfSriastradh alloc = ALIGN(2*size, kgem->buffer_size); 761903b705cfSriastradh if (alloc > MAX_CACHE_SIZE) 762003b705cfSriastradh alloc = ALIGN(size, kgem->buffer_size); 762103b705cfSriastradh if (alloc > MAX_CACHE_SIZE) 762203b705cfSriastradh alloc = PAGE_ALIGN(size); 762303b705cfSriastradh assert(alloc); 762403b705cfSriastradh 76259a906b70Schristos alloc /= PAGE_SIZE; 7626813957e3Ssnj if (alloc > kgem->aperture_mappable / 4 && !kgem->has_wc_mmap) 762703b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 762803b705cfSriastradh 762903b705cfSriastradh if (kgem->has_llc && 763003b705cfSriastradh (flags & KGEM_BUFFER_WRITE_INPLACE) != KGEM_BUFFER_WRITE_INPLACE) { 763103b705cfSriastradh bo = buffer_alloc(); 763203b705cfSriastradh if (bo == NULL) 763303b705cfSriastradh goto skip_llc; 763403b705cfSriastradh 763503b705cfSriastradh old = NULL; 763603b705cfSriastradh if ((flags & KGEM_BUFFER_WRITE) == 0) 763703b705cfSriastradh old = search_linear_cache(kgem, alloc, CREATE_CPU_MAP); 763803b705cfSriastradh if (old == NULL) 763903b705cfSriastradh old = search_linear_cache(kgem, alloc, CREATE_INACTIVE | CREATE_CPU_MAP); 764003b705cfSriastradh if (old == NULL) 764103b705cfSriastradh old = search_linear_cache(kgem, NUM_PAGES(size), CREATE_INACTIVE | CREATE_CPU_MAP); 764203b705cfSriastradh if (old) { 764303b705cfSriastradh DBG(("%s: found LLC handle=%d for buffer\n", 764403b705cfSriastradh __FUNCTION__, old->handle)); 764503b705cfSriastradh 764603b705cfSriastradh init_buffer_from_bo(bo, old); 764703b705cfSriastradh } else { 764803b705cfSriastradh uint32_t handle = gem_create(kgem->fd, alloc); 764903b705cfSriastradh if (handle == 0) { 765003b705cfSriastradh free(bo); 765103b705cfSriastradh goto skip_llc; 765203b705cfSriastradh } 765303b705cfSriastradh __kgem_bo_init(&bo->base, handle, alloc); 76549a906b70Schristos debug_alloc__bo(kgem, &bo->base); 765503b705cfSriastradh DBG(("%s: created LLC handle=%d for buffer\n", 765603b705cfSriastradh __FUNCTION__, bo->base.handle)); 765703b705cfSriastradh } 765803b705cfSriastradh 765903b705cfSriastradh assert(bo->mmapped); 766003b705cfSriastradh assert(!bo->need_io); 766103b705cfSriastradh 766203b705cfSriastradh bo->mem = kgem_bo_map__cpu(kgem, &bo->base); 766303b705cfSriastradh if (bo->mem) { 766403b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) 766503b705cfSriastradh kgem_bo_sync__cpu(kgem, &bo->base); 766603b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 766703b705cfSriastradh goto init; 766803b705cfSriastradh } else { 766903b705cfSriastradh bo->base.refcnt = 0; /* for valgrind */ 767003b705cfSriastradh kgem_bo_free(kgem, &bo->base); 767103b705cfSriastradh } 767203b705cfSriastradh } 767303b705cfSriastradhskip_llc: 767403b705cfSriastradh 767503b705cfSriastradh if ((flags & KGEM_BUFFER_WRITE_INPLACE) == KGEM_BUFFER_WRITE_INPLACE) { 767603b705cfSriastradh /* The issue with using a GTT upload buffer is that we may 767703b705cfSriastradh * cause eviction-stalls in order to free up some GTT space. 767803b705cfSriastradh * An is-mappable? ioctl could help us detect when we are 767903b705cfSriastradh * about to block, or some per-page magic in the kernel. 768003b705cfSriastradh * 768103b705cfSriastradh * XXX This is especially noticeable on memory constrained 768203b705cfSriastradh * devices like gen2 or with relatively slow gpu like i3. 768303b705cfSriastradh */ 768403b705cfSriastradh DBG(("%s: searching for an inactive GTT map for upload\n", 768503b705cfSriastradh __FUNCTION__)); 768603b705cfSriastradh old = search_linear_cache(kgem, alloc, 768703b705cfSriastradh CREATE_EXACT | CREATE_INACTIVE | CREATE_GTT_MAP); 768803b705cfSriastradh#if HAVE_I915_GEM_BUFFER_INFO 768903b705cfSriastradh if (old) { 769003b705cfSriastradh struct drm_i915_gem_buffer_info info; 769103b705cfSriastradh 769203b705cfSriastradh /* An example of such a non-blocking ioctl might work */ 769303b705cfSriastradh 769403b705cfSriastradh VG_CLEAR(info); 769503b705cfSriastradh info.handle = handle; 76969a906b70Schristos if (do_ioctl(kgem->fd, 769703b705cfSriastradh DRM_IOCTL_I915_GEM_BUFFER_INFO, 769803b705cfSriastradh &fino) == 0) { 769903b705cfSriastradh old->presumed_offset = info.addr; 770003b705cfSriastradh if ((info.flags & I915_GEM_MAPPABLE) == 0) { 770103b705cfSriastradh kgem_bo_move_to_inactive(kgem, old); 770203b705cfSriastradh old = NULL; 770303b705cfSriastradh } 770403b705cfSriastradh } 770503b705cfSriastradh } 770603b705cfSriastradh#endif 770703b705cfSriastradh if (old == NULL) 770803b705cfSriastradh old = search_linear_cache(kgem, NUM_PAGES(size), 770903b705cfSriastradh CREATE_EXACT | CREATE_INACTIVE | CREATE_GTT_MAP); 771003b705cfSriastradh if (old == NULL) { 771103b705cfSriastradh old = search_linear_cache(kgem, alloc, CREATE_INACTIVE); 77129a906b70Schristos if (old && !kgem_bo_can_map(kgem, old)) { 771303b705cfSriastradh _kgem_bo_destroy(kgem, old); 771403b705cfSriastradh old = NULL; 771503b705cfSriastradh } 771603b705cfSriastradh } 771703b705cfSriastradh if (old) { 771803b705cfSriastradh DBG(("%s: reusing handle=%d for buffer\n", 771903b705cfSriastradh __FUNCTION__, old->handle)); 77209a906b70Schristos assert(kgem_bo_can_map(kgem, old)); 772103b705cfSriastradh assert(!old->snoop); 772203b705cfSriastradh assert(old->rq == NULL); 772303b705cfSriastradh 772403b705cfSriastradh bo = buffer_alloc(); 772503b705cfSriastradh if (bo == NULL) 772603b705cfSriastradh return NULL; 772703b705cfSriastradh 772803b705cfSriastradh init_buffer_from_bo(bo, old); 772903b705cfSriastradh assert(num_pages(&bo->base) >= NUM_PAGES(size)); 773003b705cfSriastradh 773103b705cfSriastradh assert(bo->mmapped); 773203b705cfSriastradh assert(bo->base.refcnt == 1); 773303b705cfSriastradh 773403b705cfSriastradh bo->mem = kgem_bo_map(kgem, &bo->base); 773503b705cfSriastradh if (bo->mem) { 77369a906b70Schristos if (bo->mem == MAP(bo->base.map__cpu)) 773703b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 77389a906b70Schristos else 77399a906b70Schristos bo->mmapped = MMAPPED_GTT; 774003b705cfSriastradh goto init; 774103b705cfSriastradh } else { 774203b705cfSriastradh bo->base.refcnt = 0; 774303b705cfSriastradh kgem_bo_free(kgem, &bo->base); 774403b705cfSriastradh } 774503b705cfSriastradh } 774603b705cfSriastradh } 774703b705cfSriastradh#else 774803b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 774903b705cfSriastradh#endif 775003b705cfSriastradh /* Be more parsimonious with pwrite/pread/cacheable buffers */ 775103b705cfSriastradh if ((flags & KGEM_BUFFER_INPLACE) == 0) 775203b705cfSriastradh alloc = NUM_PAGES(size); 775303b705cfSriastradh 775403b705cfSriastradh if (use_snoopable_buffer(kgem, flags)) { 775503b705cfSriastradh bo = search_snoopable_buffer(kgem, alloc); 775603b705cfSriastradh if (bo) { 775703b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) 775803b705cfSriastradh kgem_bo_sync__cpu(kgem, &bo->base); 775903b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 776003b705cfSriastradh goto init; 776103b705cfSriastradh } 776203b705cfSriastradh 776303b705cfSriastradh if ((flags & KGEM_BUFFER_INPLACE) == 0) { 776403b705cfSriastradh bo = create_snoopable_buffer(kgem, alloc); 776503b705cfSriastradh if (bo) 776603b705cfSriastradh goto init; 776703b705cfSriastradh } 776803b705cfSriastradh } 776903b705cfSriastradh 777003b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 777103b705cfSriastradh 777203b705cfSriastradh old = NULL; 777303b705cfSriastradh if ((flags & KGEM_BUFFER_WRITE) == 0) 777403b705cfSriastradh old = search_linear_cache(kgem, alloc, 0); 777503b705cfSriastradh if (old == NULL) 777603b705cfSriastradh old = search_linear_cache(kgem, alloc, CREATE_INACTIVE); 777703b705cfSriastradh if (old) { 777803b705cfSriastradh DBG(("%s: reusing ordinary handle %d for io\n", 777903b705cfSriastradh __FUNCTION__, old->handle)); 778003b705cfSriastradh bo = buffer_alloc_with_data(num_pages(old)); 778103b705cfSriastradh if (bo == NULL) 778203b705cfSriastradh return NULL; 778303b705cfSriastradh 778403b705cfSriastradh init_buffer_from_bo(bo, old); 778503b705cfSriastradh bo->need_io = flags & KGEM_BUFFER_WRITE; 778603b705cfSriastradh } else { 778703b705cfSriastradh unsigned hint; 778803b705cfSriastradh 778903b705cfSriastradh if (use_snoopable_buffer(kgem, flags)) { 779003b705cfSriastradh bo = create_snoopable_buffer(kgem, alloc); 779103b705cfSriastradh if (bo) 779203b705cfSriastradh goto init; 779303b705cfSriastradh } 779403b705cfSriastradh 779503b705cfSriastradh bo = buffer_alloc(); 779603b705cfSriastradh if (bo == NULL) 779703b705cfSriastradh return NULL; 779803b705cfSriastradh 779903b705cfSriastradh hint = CREATE_INACTIVE; 780003b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) 780103b705cfSriastradh hint |= CREATE_CPU_MAP; 780203b705cfSriastradh old = search_linear_cache(kgem, alloc, hint); 780303b705cfSriastradh if (old) { 780403b705cfSriastradh DBG(("%s: reusing handle=%d for buffer\n", 780503b705cfSriastradh __FUNCTION__, old->handle)); 780603b705cfSriastradh 780703b705cfSriastradh init_buffer_from_bo(bo, old); 780803b705cfSriastradh } else { 780903b705cfSriastradh uint32_t handle = gem_create(kgem->fd, alloc); 781003b705cfSriastradh if (handle == 0) { 781103b705cfSriastradh free(bo); 781203b705cfSriastradh return NULL; 781303b705cfSriastradh } 781403b705cfSriastradh 781503b705cfSriastradh DBG(("%s: created handle=%d for buffer\n", 781603b705cfSriastradh __FUNCTION__, handle)); 781703b705cfSriastradh 781803b705cfSriastradh __kgem_bo_init(&bo->base, handle, alloc); 78199a906b70Schristos debug_alloc__bo(kgem, &bo->base); 782003b705cfSriastradh } 782103b705cfSriastradh 782203b705cfSriastradh assert(bo->mmapped); 782303b705cfSriastradh assert(!bo->need_io); 782403b705cfSriastradh assert(bo->base.refcnt == 1); 782503b705cfSriastradh 782603b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) { 782703b705cfSriastradh bo->mem = kgem_bo_map__cpu(kgem, &bo->base); 782803b705cfSriastradh if (bo->mem != NULL) { 782903b705cfSriastradh kgem_bo_sync__cpu(kgem, &bo->base); 783003b705cfSriastradh goto init; 783103b705cfSriastradh } 783203b705cfSriastradh } 783303b705cfSriastradh 783403b705cfSriastradh DBG(("%s: failing back to new pwrite buffer\n", __FUNCTION__)); 783503b705cfSriastradh old = &bo->base; 783603b705cfSriastradh bo = buffer_alloc_with_data(num_pages(old)); 783703b705cfSriastradh if (bo == NULL) { 783803b705cfSriastradh old->refcnt= 0; 783903b705cfSriastradh kgem_bo_free(kgem, old); 784003b705cfSriastradh return NULL; 784103b705cfSriastradh } 784203b705cfSriastradh 784303b705cfSriastradh init_buffer_from_bo(bo, old); 784403b705cfSriastradh 784503b705cfSriastradh assert(bo->mem); 784603b705cfSriastradh assert(!bo->mmapped); 784703b705cfSriastradh assert(bo->base.refcnt == 1); 784803b705cfSriastradh 784903b705cfSriastradh bo->need_io = flags & KGEM_BUFFER_WRITE; 785003b705cfSriastradh } 785103b705cfSriastradhinit: 785203b705cfSriastradh bo->base.io = true; 785303b705cfSriastradh assert(bo->base.refcnt == 1); 785403b705cfSriastradh assert(num_pages(&bo->base) >= NUM_PAGES(size)); 785503b705cfSriastradh assert(!bo->need_io || !bo->base.needs_flush); 785603b705cfSriastradh assert(!bo->need_io || bo->base.domain != DOMAIN_GPU); 785703b705cfSriastradh assert(bo->mem); 7858813957e3Ssnj assert(bo->mmapped != MMAPPED_GTT || bo->base.map__gtt == bo->mem || bo->base.map__wc == bo->mem); 78599a906b70Schristos assert(bo->mmapped != MMAPPED_CPU || MAP(bo->base.map__cpu) == bo->mem); 786003b705cfSriastradh 786103b705cfSriastradh bo->used = size; 786203b705cfSriastradh bo->write = flags & KGEM_BUFFER_WRITE_INPLACE; 786303b705cfSriastradh offset = 0; 786403b705cfSriastradh 786503b705cfSriastradh assert(list_is_empty(&bo->base.list)); 786603b705cfSriastradh list_add(&bo->base.list, &kgem->batch_buffers); 786703b705cfSriastradh 786803b705cfSriastradh DBG(("%s(pages=%d [%d]) new handle=%d, used=%d, write=%d\n", 786903b705cfSriastradh __FUNCTION__, num_pages(&bo->base), alloc, bo->base.handle, bo->used, bo->write)); 787003b705cfSriastradh 787103b705cfSriastradhdone: 787203b705cfSriastradh bo->used = ALIGN(bo->used, UPLOAD_ALIGNMENT); 78739a906b70Schristos assert(bo->used && bo->used <= bytes(&bo->base)); 787403b705cfSriastradh assert(bo->mem); 787503b705cfSriastradh *ret = (char *)bo->mem + offset; 787603b705cfSriastradh return kgem_create_proxy(kgem, &bo->base, offset, size); 787703b705cfSriastradh} 787803b705cfSriastradh 787903b705cfSriastradhbool kgem_buffer_is_inplace(struct kgem_bo *_bo) 788003b705cfSriastradh{ 788103b705cfSriastradh struct kgem_buffer *bo = (struct kgem_buffer *)_bo->proxy; 788203b705cfSriastradh return bo->write & KGEM_BUFFER_WRITE_INPLACE; 788303b705cfSriastradh} 788403b705cfSriastradh 788503b705cfSriastradhstruct kgem_bo *kgem_create_buffer_2d(struct kgem *kgem, 788603b705cfSriastradh int width, int height, int bpp, 788703b705cfSriastradh uint32_t flags, 788803b705cfSriastradh void **ret) 788903b705cfSriastradh{ 789003b705cfSriastradh struct kgem_bo *bo; 789103b705cfSriastradh int stride; 789203b705cfSriastradh 789303b705cfSriastradh assert(width > 0 && height > 0); 789403b705cfSriastradh assert(ret != NULL); 789503b705cfSriastradh stride = ALIGN(width, 2) * bpp >> 3; 7896813957e3Ssnj stride = ALIGN(stride, kgem->gen >= 0100 ? 32 : 4); 789703b705cfSriastradh 789803b705cfSriastradh DBG(("%s: %dx%d, %d bpp, stride=%d\n", 789903b705cfSriastradh __FUNCTION__, width, height, bpp, stride)); 790003b705cfSriastradh 790103b705cfSriastradh bo = kgem_create_buffer(kgem, stride * ALIGN(height, 2), flags, ret); 790203b705cfSriastradh if (bo == NULL) { 790303b705cfSriastradh DBG(("%s: allocation failure for upload buffer\n", 790403b705cfSriastradh __FUNCTION__)); 790503b705cfSriastradh return NULL; 790603b705cfSriastradh } 790703b705cfSriastradh assert(*ret != NULL); 790803b705cfSriastradh assert(bo->proxy != NULL); 790903b705cfSriastradh 791003b705cfSriastradh if (height & 1) { 791103b705cfSriastradh struct kgem_buffer *io = (struct kgem_buffer *)bo->proxy; 791203b705cfSriastradh int min; 791303b705cfSriastradh 791403b705cfSriastradh assert(io->used); 791503b705cfSriastradh 791603b705cfSriastradh /* Having padded this surface to ensure that accesses to 791703b705cfSriastradh * the last pair of rows is valid, remove the padding so 791803b705cfSriastradh * that it can be allocated to other pixmaps. 791903b705cfSriastradh */ 792003b705cfSriastradh min = bo->delta + height * stride; 792103b705cfSriastradh min = ALIGN(min, UPLOAD_ALIGNMENT); 792203b705cfSriastradh if (io->used != min) { 792303b705cfSriastradh DBG(("%s: trimming buffer from %d to %d\n", 792403b705cfSriastradh __FUNCTION__, io->used, min)); 792503b705cfSriastradh io->used = min; 792603b705cfSriastradh } 792703b705cfSriastradh bo->size.bytes -= stride; 792803b705cfSriastradh } 792903b705cfSriastradh 79309a906b70Schristos bo->map__cpu = *ret; 793103b705cfSriastradh bo->pitch = stride; 793203b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 793303b705cfSriastradh return bo; 793403b705cfSriastradh} 793503b705cfSriastradh 793603b705cfSriastradhstruct kgem_bo *kgem_upload_source_image(struct kgem *kgem, 793703b705cfSriastradh const void *data, 793803b705cfSriastradh const BoxRec *box, 793903b705cfSriastradh int stride, int bpp) 794003b705cfSriastradh{ 794103b705cfSriastradh int width = box->x2 - box->x1; 794203b705cfSriastradh int height = box->y2 - box->y1; 794303b705cfSriastradh struct kgem_bo *bo; 794403b705cfSriastradh void *dst; 794503b705cfSriastradh 794603b705cfSriastradh if (!kgem_can_create_2d(kgem, width, height, bpp)) 794703b705cfSriastradh return NULL; 794803b705cfSriastradh 794903b705cfSriastradh DBG(("%s : (%d, %d), (%d, %d), stride=%d, bpp=%d\n", 795003b705cfSriastradh __FUNCTION__, box->x1, box->y1, box->x2, box->y2, stride, bpp)); 795103b705cfSriastradh 795203b705cfSriastradh assert(data); 795303b705cfSriastradh assert(width > 0); 795403b705cfSriastradh assert(height > 0); 795503b705cfSriastradh assert(stride); 795603b705cfSriastradh assert(bpp); 795703b705cfSriastradh 795803b705cfSriastradh bo = kgem_create_buffer_2d(kgem, 795903b705cfSriastradh width, height, bpp, 796003b705cfSriastradh KGEM_BUFFER_WRITE_INPLACE, &dst); 79619a906b70Schristos if (bo == NULL) 79629a906b70Schristos return NULL; 79639a906b70Schristos 79649a906b70Schristos if (sigtrap_get()) { 79659a906b70Schristos kgem_bo_destroy(kgem, bo); 79669a906b70Schristos return NULL; 79679a906b70Schristos } 79689a906b70Schristos 79699a906b70Schristos memcpy_blt(data, dst, bpp, 79709a906b70Schristos stride, bo->pitch, 79719a906b70Schristos box->x1, box->y1, 79729a906b70Schristos 0, 0, 79739a906b70Schristos width, height); 797403b705cfSriastradh 79759a906b70Schristos sigtrap_put(); 797603b705cfSriastradh return bo; 797703b705cfSriastradh} 797803b705cfSriastradh 797903b705cfSriastradhvoid kgem_proxy_bo_attach(struct kgem_bo *bo, 798003b705cfSriastradh struct kgem_bo **ptr) 798103b705cfSriastradh{ 798203b705cfSriastradh DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle)); 79839a906b70Schristos assert(bo->map__gtt == NULL); 798403b705cfSriastradh assert(bo->proxy); 798503b705cfSriastradh list_add(&bo->vma, &bo->proxy->vma); 79869a906b70Schristos bo->map__gtt = ptr; 798703b705cfSriastradh *ptr = kgem_bo_reference(bo); 798803b705cfSriastradh} 798903b705cfSriastradh 799003b705cfSriastradhvoid kgem_buffer_read_sync(struct kgem *kgem, struct kgem_bo *_bo) 799103b705cfSriastradh{ 799203b705cfSriastradh struct kgem_buffer *bo; 799303b705cfSriastradh uint32_t offset = _bo->delta, length = _bo->size.bytes; 799403b705cfSriastradh 799503b705cfSriastradh /* We expect the caller to have already submitted the batch */ 799603b705cfSriastradh assert(_bo->io); 799703b705cfSriastradh assert(_bo->exec == NULL); 799803b705cfSriastradh assert(_bo->rq == NULL); 799903b705cfSriastradh assert(_bo->proxy); 800003b705cfSriastradh 800103b705cfSriastradh _bo = _bo->proxy; 800203b705cfSriastradh assert(_bo->proxy == NULL); 800303b705cfSriastradh assert(_bo->exec == NULL); 800403b705cfSriastradh 800503b705cfSriastradh bo = (struct kgem_buffer *)_bo; 800603b705cfSriastradh 800703b705cfSriastradh DBG(("%s(offset=%d, length=%d, snooped=%d)\n", __FUNCTION__, 800803b705cfSriastradh offset, length, bo->base.snoop)); 800903b705cfSriastradh 801003b705cfSriastradh if (bo->mmapped) { 801103b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 801203b705cfSriastradh 801303b705cfSriastradh DBG(("%s: sync: needs_flush? %d, domain? %d, busy? %d\n", 801403b705cfSriastradh __FUNCTION__, 801503b705cfSriastradh bo->base.needs_flush, 801603b705cfSriastradh bo->base.domain, 801703b705cfSriastradh __kgem_busy(kgem, bo->base.handle))); 801803b705cfSriastradh 80199a906b70Schristos assert(bo->mmapped == MMAPPED_GTT || bo->base.snoop || kgem->has_llc); 802003b705cfSriastradh 802103b705cfSriastradh VG_CLEAR(set_domain); 802203b705cfSriastradh set_domain.handle = bo->base.handle; 802303b705cfSriastradh set_domain.write_domain = 0; 802403b705cfSriastradh set_domain.read_domains = 80259a906b70Schristos bo->mmapped == MMAPPED_CPU ? I915_GEM_DOMAIN_CPU : I915_GEM_DOMAIN_GTT; 802603b705cfSriastradh 80279a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 80289a906b70Schristos DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 80299a906b70Schristos kgem_throttle(kgem); 80309a906b70Schristos } 803103b705cfSriastradh } else { 803203b705cfSriastradh if (gem_read(kgem->fd, 803303b705cfSriastradh bo->base.handle, (char *)bo->mem+offset, 803403b705cfSriastradh offset, length)) 803503b705cfSriastradh return; 803603b705cfSriastradh } 80379a906b70Schristos kgem_bo_maybe_retire(kgem, &bo->base); 803803b705cfSriastradh bo->base.domain = DOMAIN_NONE; 803903b705cfSriastradh} 804003b705cfSriastradh 804103b705cfSriastradhuint32_t kgem_bo_get_binding(struct kgem_bo *bo, uint32_t format) 804203b705cfSriastradh{ 804303b705cfSriastradh struct kgem_bo_binding *b; 804403b705cfSriastradh 80459a906b70Schristos assert(bo->refcnt); 80469a906b70Schristos 804703b705cfSriastradh for (b = &bo->binding; b && b->offset; b = b->next) 804803b705cfSriastradh if (format == b->format) 804903b705cfSriastradh return b->offset; 805003b705cfSriastradh 805103b705cfSriastradh return 0; 805203b705cfSriastradh} 805303b705cfSriastradh 805403b705cfSriastradhvoid kgem_bo_set_binding(struct kgem_bo *bo, uint32_t format, uint16_t offset) 805503b705cfSriastradh{ 805603b705cfSriastradh struct kgem_bo_binding *b; 805703b705cfSriastradh 80589a906b70Schristos assert(bo->refcnt); 80599a906b70Schristos 806003b705cfSriastradh for (b = &bo->binding; b; b = b->next) { 806103b705cfSriastradh if (b->offset) 806203b705cfSriastradh continue; 806303b705cfSriastradh 806403b705cfSriastradh b->offset = offset; 806503b705cfSriastradh b->format = format; 806603b705cfSriastradh 806703b705cfSriastradh if (b->next) 806803b705cfSriastradh b->next->offset = 0; 806903b705cfSriastradh 807003b705cfSriastradh return; 807103b705cfSriastradh } 807203b705cfSriastradh 807303b705cfSriastradh b = malloc(sizeof(*b)); 807403b705cfSriastradh if (b) { 807503b705cfSriastradh b->next = bo->binding.next; 807603b705cfSriastradh b->format = format; 807703b705cfSriastradh b->offset = offset; 807803b705cfSriastradh bo->binding.next = b; 807903b705cfSriastradh } 808003b705cfSriastradh} 808103b705cfSriastradh 808203b705cfSriastradhstruct kgem_bo * 808303b705cfSriastradhkgem_replace_bo(struct kgem *kgem, 808403b705cfSriastradh struct kgem_bo *src, 808503b705cfSriastradh uint32_t width, 808603b705cfSriastradh uint32_t height, 808703b705cfSriastradh uint32_t pitch, 808803b705cfSriastradh uint32_t bpp) 808903b705cfSriastradh{ 809003b705cfSriastradh struct kgem_bo *dst; 809103b705cfSriastradh uint32_t br00, br13; 809203b705cfSriastradh uint32_t handle; 809303b705cfSriastradh uint32_t size; 809403b705cfSriastradh uint32_t *b; 809503b705cfSriastradh 809603b705cfSriastradh DBG(("%s: replacing bo handle=%d, size=%dx%d pitch=%d, with pitch=%d\n", 809703b705cfSriastradh __FUNCTION__, src->handle, width, height, src->pitch, pitch)); 809803b705cfSriastradh 809903b705cfSriastradh /* We only expect to be called to fixup small buffers, hence why 810003b705cfSriastradh * we only attempt to allocate a linear bo. 810103b705cfSriastradh */ 810203b705cfSriastradh assert(src->tiling == I915_TILING_NONE); 81039a906b70Schristos assert(kgem_bo_can_blt(kgem, src)); 810403b705cfSriastradh 810503b705cfSriastradh size = height * pitch; 810603b705cfSriastradh size = NUM_PAGES(size); 810703b705cfSriastradh 810803b705cfSriastradh dst = search_linear_cache(kgem, size, 0); 810903b705cfSriastradh if (dst == NULL) 811003b705cfSriastradh dst = search_linear_cache(kgem, size, CREATE_INACTIVE); 811103b705cfSriastradh if (dst == NULL) { 811203b705cfSriastradh handle = gem_create(kgem->fd, size); 811303b705cfSriastradh if (handle == 0) 811403b705cfSriastradh return NULL; 811503b705cfSriastradh 811603b705cfSriastradh dst = __kgem_bo_alloc(handle, size); 811703b705cfSriastradh if (dst == NULL) { 811803b705cfSriastradh gem_close(kgem->fd, handle); 811903b705cfSriastradh return NULL; 812003b705cfSriastradh } 812103b705cfSriastradh 812203b705cfSriastradh debug_alloc__bo(kgem, dst); 812303b705cfSriastradh } 812403b705cfSriastradh dst->pitch = pitch; 812503b705cfSriastradh dst->unique_id = kgem_get_unique_id(kgem); 812603b705cfSriastradh dst->refcnt = 1; 81279a906b70Schristos assert(dst->tiling == I915_TILING_NONE); 81289a906b70Schristos assert(kgem_bo_can_blt(kgem, dst)); 812903b705cfSriastradh 813003b705cfSriastradh kgem_set_mode(kgem, KGEM_BLT, dst); 81319a906b70Schristos if (!kgem_check_batch(kgem, 10) || 813203b705cfSriastradh !kgem_check_reloc(kgem, 2) || 813303b705cfSriastradh !kgem_check_many_bo_fenced(kgem, src, dst, NULL)) { 813403b705cfSriastradh kgem_submit(kgem); 813503b705cfSriastradh if (!kgem_check_many_bo_fenced(kgem, src, dst, NULL)) { 813603b705cfSriastradh kgem_bo_destroy(kgem, dst); 813703b705cfSriastradh return NULL; 813803b705cfSriastradh } 813903b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 814003b705cfSriastradh } 814163ef14f0Smrg kgem_bcs_set_tiling(kgem, src, dst); 814203b705cfSriastradh 814303b705cfSriastradh br00 = XY_SRC_COPY_BLT_CMD; 814403b705cfSriastradh br13 = pitch; 814503b705cfSriastradh pitch = src->pitch; 814603b705cfSriastradh if (kgem->gen >= 040 && src->tiling) { 814703b705cfSriastradh br00 |= BLT_SRC_TILED; 814803b705cfSriastradh pitch >>= 2; 814903b705cfSriastradh } 815003b705cfSriastradh 815103b705cfSriastradh br13 |= 0xcc << 16; 815203b705cfSriastradh switch (bpp) { 815303b705cfSriastradh default: 815403b705cfSriastradh case 32: br00 |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 815503b705cfSriastradh br13 |= 1 << 25; /* RGB8888 */ 815603b705cfSriastradh case 16: br13 |= 1 << 24; /* RGB565 */ 815703b705cfSriastradh case 8: break; 815803b705cfSriastradh } 815903b705cfSriastradh 816003b705cfSriastradh b = kgem->batch + kgem->nbatch; 81619a906b70Schristos if (kgem->gen >= 0100) { 81629a906b70Schristos b[0] = br00 | 8; 81639a906b70Schristos b[1] = br13; 81649a906b70Schristos b[2] = 0; 81659a906b70Schristos b[3] = height << 16 | width; 81669a906b70Schristos *(uint64_t *)(b+4) = 81679a906b70Schristos kgem_add_reloc64(kgem, kgem->nbatch + 4, dst, 81689a906b70Schristos I915_GEM_DOMAIN_RENDER << 16 | 81699a906b70Schristos I915_GEM_DOMAIN_RENDER | 81709a906b70Schristos KGEM_RELOC_FENCED, 81719a906b70Schristos 0); 81729a906b70Schristos b[6] = 0; 81739a906b70Schristos b[7] = pitch; 81749a906b70Schristos *(uint64_t *)(b+8) = 81759a906b70Schristos kgem_add_reloc64(kgem, kgem->nbatch + 8, src, 81769a906b70Schristos I915_GEM_DOMAIN_RENDER << 16 | 81779a906b70Schristos KGEM_RELOC_FENCED, 81789a906b70Schristos 0); 81799a906b70Schristos kgem->nbatch += 10; 81809a906b70Schristos } else { 81819a906b70Schristos b[0] = br00 | 6; 81829a906b70Schristos b[1] = br13; 81839a906b70Schristos b[2] = 0; 81849a906b70Schristos b[3] = height << 16 | width; 81859a906b70Schristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst, 81869a906b70Schristos I915_GEM_DOMAIN_RENDER << 16 | 81879a906b70Schristos I915_GEM_DOMAIN_RENDER | 81889a906b70Schristos KGEM_RELOC_FENCED, 81899a906b70Schristos 0); 81909a906b70Schristos b[5] = 0; 81919a906b70Schristos b[6] = pitch; 81929a906b70Schristos b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src, 81939a906b70Schristos I915_GEM_DOMAIN_RENDER << 16 | 81949a906b70Schristos KGEM_RELOC_FENCED, 81959a906b70Schristos 0); 81969a906b70Schristos kgem->nbatch += 8; 81979a906b70Schristos } 819803b705cfSriastradh 819903b705cfSriastradh return dst; 820003b705cfSriastradh} 82019a906b70Schristos 82029a906b70Schristosbool kgem_bo_convert_to_gpu(struct kgem *kgem, 82039a906b70Schristos struct kgem_bo *bo, 82049a906b70Schristos unsigned flags) 82059a906b70Schristos{ 8206813957e3Ssnj DBG(("%s: converting handle=%d from CPU to GPU, flags=%x, busy?=%d\n", 8207813957e3Ssnj __FUNCTION__, bo->handle, flags, __kgem_bo_is_busy(kgem, bo))); 82089a906b70Schristos assert(bo->tiling == I915_TILING_NONE); 82099a906b70Schristos 821063ef14f0Smrg if (flags & (__MOVE_PRIME | __MOVE_SCANOUT)) 821163ef14f0Smrg return false; 821263ef14f0Smrg 82139a906b70Schristos if (kgem->has_llc) 82149a906b70Schristos return true; 82159a906b70Schristos 82169a906b70Schristos if (flags & MOVE_ASYNC_HINT && __kgem_bo_is_busy(kgem, bo)) 82179a906b70Schristos return false; 82189a906b70Schristos 82199a906b70Schristos assert(bo->snoop); 82209a906b70Schristos 82219a906b70Schristos kgem_bo_submit(kgem, bo); 82229a906b70Schristos 82239a906b70Schristos if (!gem_set_caching(kgem->fd, bo->handle, UNCACHED)) 82249a906b70Schristos return false; 82259a906b70Schristos 82269a906b70Schristos bo->snoop = false; 82279a906b70Schristos return true; 82289a906b70Schristos} 8229