kgem.c revision 9a906b70
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 7303b705cfSriastradh#define DBG_NO_LLC 0 7403b705cfSriastradh#define DBG_NO_SEMAPHORES 0 7503b705cfSriastradh#define DBG_NO_MADV 0 7603b705cfSriastradh#define DBG_NO_UPLOAD_CACHE 0 7703b705cfSriastradh#define DBG_NO_UPLOAD_ACTIVE 0 7803b705cfSriastradh#define DBG_NO_MAP_UPLOAD 0 7903b705cfSriastradh#define DBG_NO_RELAXED_FENCING 0 8003b705cfSriastradh#define DBG_NO_SECURE_BATCHES 0 8103b705cfSriastradh#define DBG_NO_PINNED_BATCHES 0 8203b705cfSriastradh#define DBG_NO_FAST_RELOC 0 8303b705cfSriastradh#define DBG_NO_HANDLE_LUT 0 8403b705cfSriastradh#define DBG_NO_WT 0 8503b705cfSriastradh#define DBG_DUMP 0 869a906b70Schristos#define DBG_NO_MALLOC_CACHE 0 8703b705cfSriastradh 8803b705cfSriastradh#define FORCE_MMAP_SYNC 0 /* ((1 << DOMAIN_CPU) | (1 << DOMAIN_GTT)) */ 8903b705cfSriastradh 9003b705cfSriastradh#ifndef DEBUG_SYNC 9103b705cfSriastradh#define DEBUG_SYNC 0 9203b705cfSriastradh#endif 9303b705cfSriastradh 949a906b70Schristos#define SHOW_BATCH_BEFORE 0 959a906b70Schristos#define SHOW_BATCH_AFTER 0 9603b705cfSriastradh 9703b705cfSriastradh#if 0 9803b705cfSriastradh#define ASSERT_IDLE(kgem__, handle__) assert(!__kgem_busy(kgem__, handle__)) 9903b705cfSriastradh#define ASSERT_MAYBE_IDLE(kgem__, handle__, expect__) assert(!(expect__) || !__kgem_busy(kgem__, handle__)) 10003b705cfSriastradh#else 10103b705cfSriastradh#define ASSERT_IDLE(kgem__, handle__) 10203b705cfSriastradh#define ASSERT_MAYBE_IDLE(kgem__, handle__, expect__) 10303b705cfSriastradh#endif 10403b705cfSriastradh 10503b705cfSriastradh/* Worst case seems to be 965gm where we cannot write within a cacheline that 10603b705cfSriastradh * is being simultaneously being read by the GPU, or within the sampler 10703b705cfSriastradh * prefetch. In general, the chipsets seem to have a requirement that sampler 10803b705cfSriastradh * offsets be aligned to a cacheline (64 bytes). 1099a906b70Schristos * 1109a906b70Schristos * Actually, it turns out the BLT color pattern (BR15) has the most severe 1119a906b70Schristos * alignment restrictions, 64 bytes for 8-bpp, 128 bytes for 16-bpp and 256 1129a906b70Schristos * bytes for 32-bpp. 11303b705cfSriastradh */ 1149a906b70Schristos#define UPLOAD_ALIGNMENT 256 11503b705cfSriastradh 11603b705cfSriastradh#define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE) 11703b705cfSriastradh#define NUM_PAGES(x) (((x) + PAGE_SIZE-1) / PAGE_SIZE) 11803b705cfSriastradh 11903b705cfSriastradh#define MAX_GTT_VMA_CACHE 512 12003b705cfSriastradh#define MAX_CPU_VMA_CACHE INT16_MAX 12103b705cfSriastradh#define MAP_PRESERVE_TIME 10 12203b705cfSriastradh 1239a906b70Schristos#define MAKE_USER_MAP(ptr) ((void*)((uintptr_t)(ptr) | 1)) 1249a906b70Schristos#define IS_USER_MAP(ptr) ((uintptr_t)(ptr) & 1) 12503b705cfSriastradh 12603b705cfSriastradh#define LOCAL_I915_PARAM_HAS_BLT 11 12703b705cfSriastradh#define LOCAL_I915_PARAM_HAS_RELAXED_FENCING 12 12803b705cfSriastradh#define LOCAL_I915_PARAM_HAS_RELAXED_DELTA 15 12903b705cfSriastradh#define LOCAL_I915_PARAM_HAS_SEMAPHORES 20 13003b705cfSriastradh#define LOCAL_I915_PARAM_HAS_SECURE_BATCHES 23 13103b705cfSriastradh#define LOCAL_I915_PARAM_HAS_PINNED_BATCHES 24 13203b705cfSriastradh#define LOCAL_I915_PARAM_HAS_NO_RELOC 25 13303b705cfSriastradh#define LOCAL_I915_PARAM_HAS_HANDLE_LUT 26 13403b705cfSriastradh#define LOCAL_I915_PARAM_HAS_WT 27 13503b705cfSriastradh 13603b705cfSriastradh#define LOCAL_I915_EXEC_IS_PINNED (1<<10) 13703b705cfSriastradh#define LOCAL_I915_EXEC_NO_RELOC (1<<11) 13803b705cfSriastradh#define LOCAL_I915_EXEC_HANDLE_LUT (1<<12) 13903b705cfSriastradh 1409a906b70Schristos#define LOCAL_I915_GEM_CREATE2 0x34 14103b705cfSriastradh#define LOCAL_IOCTL_I915_GEM_CREATE2 DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_CREATE2, struct local_i915_gem_create2) 14203b705cfSriastradhstruct local_i915_gem_create2 { 14303b705cfSriastradh uint64_t size; 14403b705cfSriastradh uint32_t placement; 14503b705cfSriastradh#define LOCAL_I915_CREATE_PLACEMENT_SYSTEM 0 14603b705cfSriastradh#define LOCAL_I915_CREATE_PLACEMENT_STOLEN 1 /* Cannot use CPU mmaps or pread/pwrite */ 14703b705cfSriastradh uint32_t domain; 14803b705cfSriastradh uint32_t caching; 14903b705cfSriastradh uint32_t tiling_mode; 15003b705cfSriastradh uint32_t stride; 15103b705cfSriastradh uint32_t flags; 15203b705cfSriastradh uint32_t pad; 15303b705cfSriastradh uint32_t handle; 15403b705cfSriastradh}; 15503b705cfSriastradh 15603b705cfSriastradh#define LOCAL_I915_GEM_USERPTR 0x33 15703b705cfSriastradh#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr) 15803b705cfSriastradhstruct local_i915_gem_userptr { 15903b705cfSriastradh uint64_t user_ptr; 16003b705cfSriastradh uint64_t user_size; 16103b705cfSriastradh uint32_t flags; 1629a906b70Schristos#define I915_USERPTR_READ_ONLY 0x1 1639a906b70Schristos#define I915_USERPTR_UNSYNCHRONIZED 0x80000000 16403b705cfSriastradh uint32_t handle; 16503b705cfSriastradh}; 16603b705cfSriastradh 16703b705cfSriastradh#define UNCACHED 0 16803b705cfSriastradh#define SNOOPED 1 16903b705cfSriastradh#define DISPLAY 2 17003b705cfSriastradh 17103b705cfSriastradhstruct local_i915_gem_caching { 17203b705cfSriastradh uint32_t handle; 17303b705cfSriastradh uint32_t caching; 17403b705cfSriastradh}; 17503b705cfSriastradh 17603b705cfSriastradh#define LOCAL_I915_GEM_SET_CACHING 0x2f 1779a906b70Schristos#define LOCAL_I915_GEM_GET_CACHING 0x30 17803b705cfSriastradh#define LOCAL_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_SET_CACHING, struct local_i915_gem_caching) 1799a906b70Schristos#define LOCAL_IOCTL_I915_GEM_GET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_GET_CACHING, struct local_i915_gem_caching) 18003b705cfSriastradh 18103b705cfSriastradhstruct kgem_buffer { 18203b705cfSriastradh struct kgem_bo base; 18303b705cfSriastradh void *mem; 18403b705cfSriastradh uint32_t used; 18503b705cfSriastradh uint32_t need_io : 1; 18603b705cfSriastradh uint32_t write : 2; 1879a906b70Schristos uint32_t mmapped : 2; 1889a906b70Schristos}; 1899a906b70Schristosenum { 1909a906b70Schristos MMAPPED_NONE, 1919a906b70Schristos MMAPPED_GTT, 1929a906b70Schristos MMAPPED_CPU 19303b705cfSriastradh}; 19403b705cfSriastradh 19503b705cfSriastradhstatic struct kgem_bo *__kgem_freed_bo; 19603b705cfSriastradhstatic struct kgem_request *__kgem_freed_request; 19703b705cfSriastradhstatic struct drm_i915_gem_exec_object2 _kgem_dummy_exec; 19803b705cfSriastradh 19903b705cfSriastradhstatic inline int bytes(struct kgem_bo *bo) 20003b705cfSriastradh{ 20103b705cfSriastradh return __kgem_bo_size(bo); 20203b705cfSriastradh} 20303b705cfSriastradh 20403b705cfSriastradh#define bucket(B) (B)->size.pages.bucket 20503b705cfSriastradh#define num_pages(B) (B)->size.pages.count 20603b705cfSriastradh 2079a906b70Schristosstatic int do_ioctl(int fd, unsigned long req, void *arg) 2089a906b70Schristos{ 2099a906b70Schristos int err; 2109a906b70Schristos 2119a906b70Schristosrestart: 2129a906b70Schristos if (ioctl(fd, req, arg) == 0) 2139a906b70Schristos return 0; 2149a906b70Schristos 2159a906b70Schristos err = errno; 2169a906b70Schristos 2179a906b70Schristos if (err == EINTR) 2189a906b70Schristos goto restart; 2199a906b70Schristos 2209a906b70Schristos if (err == EAGAIN) { 2219a906b70Schristos sched_yield(); 2229a906b70Schristos goto restart; 2239a906b70Schristos } 2249a906b70Schristos 2259a906b70Schristos return -err; 2269a906b70Schristos} 2279a906b70Schristos 22803b705cfSriastradh#ifdef DEBUG_MEMORY 22903b705cfSriastradhstatic void debug_alloc(struct kgem *kgem, size_t size) 23003b705cfSriastradh{ 23103b705cfSriastradh kgem->debug_memory.bo_allocs++; 23203b705cfSriastradh kgem->debug_memory.bo_bytes += size; 23303b705cfSriastradh} 23403b705cfSriastradhstatic void debug_alloc__bo(struct kgem *kgem, struct kgem_bo *bo) 23503b705cfSriastradh{ 23603b705cfSriastradh debug_alloc(kgem, bytes(bo)); 23703b705cfSriastradh} 23803b705cfSriastradh#else 23903b705cfSriastradh#define debug_alloc__bo(k, b) 24003b705cfSriastradh#endif 24103b705cfSriastradh 24203b705cfSriastradh#ifndef NDEBUG 24303b705cfSriastradhstatic void assert_tiling(struct kgem *kgem, struct kgem_bo *bo) 24403b705cfSriastradh{ 24503b705cfSriastradh struct drm_i915_gem_get_tiling tiling; 24603b705cfSriastradh 24703b705cfSriastradh assert(bo); 24803b705cfSriastradh 24903b705cfSriastradh VG_CLEAR(tiling); 25003b705cfSriastradh tiling.handle = bo->handle; 2519a906b70Schristos tiling.tiling_mode = bo->tiling; 2529a906b70Schristos (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling); 25303b705cfSriastradh assert(tiling.tiling_mode == bo->tiling); 25403b705cfSriastradh} 2559a906b70Schristos 2569a906b70Schristosstatic void assert_cacheing(struct kgem *kgem, struct kgem_bo *bo) 2579a906b70Schristos{ 2589a906b70Schristos struct local_i915_gem_caching arg; 2599a906b70Schristos int expect = kgem->has_llc ? SNOOPED : UNCACHED; 2609a906b70Schristos 2619a906b70Schristos VG_CLEAR(arg); 2629a906b70Schristos arg.handle = bo->handle; 2639a906b70Schristos arg.caching = expect; 2649a906b70Schristos 2659a906b70Schristos (void)do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_GET_CACHING, &arg); 2669a906b70Schristos 2679a906b70Schristos assert(arg.caching == expect); 2689a906b70Schristos} 2699a906b70Schristos 2709a906b70Schristosstatic void assert_bo_retired(struct kgem_bo *bo) 2719a906b70Schristos{ 2729a906b70Schristos DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__, 2739a906b70Schristos bo->handle, bo->domain, bo->exec != NULL, bo->rq != NULL)); 2749a906b70Schristos assert(bo->refcnt); 2759a906b70Schristos assert(bo->rq == NULL); 2769a906b70Schristos assert(bo->exec == NULL); 2779a906b70Schristos assert(list_is_empty(&bo->request)); 2789a906b70Schristos} 27903b705cfSriastradh#else 28003b705cfSriastradh#define assert_tiling(kgem, bo) 2819a906b70Schristos#define assert_cacheing(kgem, bo) 2829a906b70Schristos#define assert_bo_retired(bo) 28303b705cfSriastradh#endif 28403b705cfSriastradh 28503b705cfSriastradhstatic void kgem_sna_reset(struct kgem *kgem) 28603b705cfSriastradh{ 28703b705cfSriastradh struct sna *sna = container_of(kgem, struct sna, kgem); 28803b705cfSriastradh 28903b705cfSriastradh sna->render.reset(sna); 29003b705cfSriastradh sna->blt_state.fill_bo = 0; 29103b705cfSriastradh} 29203b705cfSriastradh 29303b705cfSriastradhstatic void kgem_sna_flush(struct kgem *kgem) 29403b705cfSriastradh{ 29503b705cfSriastradh struct sna *sna = container_of(kgem, struct sna, kgem); 29603b705cfSriastradh 29703b705cfSriastradh sna->render.flush(sna); 29803b705cfSriastradh 29903b705cfSriastradh if (sna->render.solid_cache.dirty) 30003b705cfSriastradh sna_render_flush_solid(sna); 30103b705cfSriastradh} 30203b705cfSriastradh 30303b705cfSriastradhstatic bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride) 30403b705cfSriastradh{ 30503b705cfSriastradh struct drm_i915_gem_set_tiling set_tiling; 3069a906b70Schristos int err; 30703b705cfSriastradh 30803b705cfSriastradh if (DBG_NO_TILING) 30903b705cfSriastradh return false; 31003b705cfSriastradh 31103b705cfSriastradh VG_CLEAR(set_tiling); 3129a906b70Schristosrestart: 3139a906b70Schristos set_tiling.handle = handle; 3149a906b70Schristos set_tiling.tiling_mode = tiling; 3159a906b70Schristos set_tiling.stride = stride; 31603b705cfSriastradh 3179a906b70Schristos if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) 3189a906b70Schristos return true; 3199a906b70Schristos 3209a906b70Schristos err = errno; 3219a906b70Schristos if (err == EINTR) 3229a906b70Schristos goto restart; 3239a906b70Schristos 3249a906b70Schristos if (err == EAGAIN) { 3259a906b70Schristos sched_yield(); 3269a906b70Schristos goto restart; 3279a906b70Schristos } 3289a906b70Schristos 3299a906b70Schristos return false; 33003b705cfSriastradh} 33103b705cfSriastradh 33203b705cfSriastradhstatic bool gem_set_caching(int fd, uint32_t handle, int caching) 33303b705cfSriastradh{ 33403b705cfSriastradh struct local_i915_gem_caching arg; 33503b705cfSriastradh 33603b705cfSriastradh VG_CLEAR(arg); 33703b705cfSriastradh arg.handle = handle; 33803b705cfSriastradh arg.caching = caching; 3399a906b70Schristos return do_ioctl(fd, LOCAL_IOCTL_I915_GEM_SET_CACHING, &arg) == 0; 34003b705cfSriastradh} 34103b705cfSriastradh 34203b705cfSriastradhstatic uint32_t gem_userptr(int fd, void *ptr, int size, int read_only) 34303b705cfSriastradh{ 34403b705cfSriastradh struct local_i915_gem_userptr arg; 34503b705cfSriastradh 34603b705cfSriastradh VG_CLEAR(arg); 34703b705cfSriastradh arg.user_ptr = (uintptr_t)ptr; 34803b705cfSriastradh arg.user_size = size; 34903b705cfSriastradh arg.flags = I915_USERPTR_UNSYNCHRONIZED; 35003b705cfSriastradh if (read_only) 35103b705cfSriastradh arg.flags |= I915_USERPTR_READ_ONLY; 35203b705cfSriastradh 35303b705cfSriastradh if (DBG_NO_UNSYNCHRONIZED_USERPTR || 3549a906b70Schristos do_ioctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg)) { 35503b705cfSriastradh arg.flags &= ~I915_USERPTR_UNSYNCHRONIZED; 3569a906b70Schristos if (do_ioctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg)) { 35703b705cfSriastradh DBG(("%s: failed to map %p + %d bytes: %d\n", 35803b705cfSriastradh __FUNCTION__, ptr, size, errno)); 35903b705cfSriastradh return 0; 36003b705cfSriastradh } 36103b705cfSriastradh } 36203b705cfSriastradh 36303b705cfSriastradh return arg.handle; 36403b705cfSriastradh} 36503b705cfSriastradh 3669a906b70Schristosstatic bool __kgem_throttle(struct kgem *kgem, bool harder) 36703b705cfSriastradh{ 3689a906b70Schristos /* Let this be woken up by sigtimer so that we don't block here 3699a906b70Schristos * too much and completely starve X. We will sleep again shortly, 3709a906b70Schristos * and so catch up or detect the hang. 3719a906b70Schristos */ 3729a906b70Schristos do { 3739a906b70Schristos if (ioctl(kgem->fd, DRM_IOCTL_I915_GEM_THROTTLE) == 0) { 3749a906b70Schristos kgem->need_throttle = 0; 3759a906b70Schristos return false; 3769a906b70Schristos } 37703b705cfSriastradh 3789a906b70Schristos if (errno == EIO) 3799a906b70Schristos return true; 3809a906b70Schristos } while (harder); 3819a906b70Schristos 3829a906b70Schristos return false; 3839a906b70Schristos} 3849a906b70Schristos 3859a906b70Schristosstatic bool __kgem_throttle_retire(struct kgem *kgem, unsigned flags) 3869a906b70Schristos{ 3879a906b70Schristos if (flags & CREATE_NO_RETIRE || !kgem->need_retire) { 3889a906b70Schristos DBG(("%s: not retiring\n", __FUNCTION__)); 38903b705cfSriastradh return false; 39003b705cfSriastradh } 39103b705cfSriastradh 39203b705cfSriastradh if (kgem_retire(kgem)) 39303b705cfSriastradh return true; 39403b705cfSriastradh 39503b705cfSriastradh if (flags & CREATE_NO_THROTTLE || !kgem->need_throttle) { 39603b705cfSriastradh DBG(("%s: not throttling\n", __FUNCTION__)); 39703b705cfSriastradh return false; 39803b705cfSriastradh } 39903b705cfSriastradh 4009a906b70Schristos __kgem_throttle(kgem, false); 40103b705cfSriastradh return kgem_retire(kgem); 40203b705cfSriastradh} 40303b705cfSriastradh 40403b705cfSriastradhstatic void *__kgem_bo_map__gtt(struct kgem *kgem, struct kgem_bo *bo) 40503b705cfSriastradh{ 40603b705cfSriastradh struct drm_i915_gem_mmap_gtt mmap_arg; 40703b705cfSriastradh void *ptr; 4083d02bce8Sriastradh int err; 40903b705cfSriastradh 41003b705cfSriastradh DBG(("%s(handle=%d, size=%d)\n", __FUNCTION__, 41103b705cfSriastradh bo->handle, bytes(bo))); 41203b705cfSriastradh assert(bo->proxy == NULL); 41303b705cfSriastradh assert(!bo->snoop); 4149a906b70Schristos assert(num_pages(bo) <= kgem->aperture_mappable / 4); 41503b705cfSriastradh 41603b705cfSriastradhretry_gtt: 41703b705cfSriastradh VG_CLEAR(mmap_arg); 41803b705cfSriastradh mmap_arg.handle = bo->handle; 4199a906b70Schristos#ifdef __NetBSD__ 42003b705cfSriastradh if (drmIoctl(kgem->fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg)) { 4213d02bce8Sriastradh err = errno; 4229a906b70Schristos#else 4239a906b70Schristos if ((err = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))) { 4249a906b70Schristos#endif 42503b705cfSriastradh assert(err != EINVAL); 42603b705cfSriastradh 42703b705cfSriastradh (void)__kgem_throttle_retire(kgem, 0); 42803b705cfSriastradh if (kgem_expire_cache(kgem)) 42903b705cfSriastradh goto retry_gtt; 43003b705cfSriastradh 4319a906b70Schristos if (kgem_cleanup_cache(kgem)) 43203b705cfSriastradh goto retry_gtt; 43303b705cfSriastradh 4349a906b70Schristos ERR(("%s: failed to retrieve GTT offset for handle=%d: %d\n", 4359a906b70Schristos __FUNCTION__, bo->handle, -err)); 43603b705cfSriastradh return NULL; 43703b705cfSriastradh } 43803b705cfSriastradh 43903b705cfSriastradhretry_mmap: 4409a906b70Schristos#ifdef __NetBSD__ 4413d02bce8Sriastradh err = -drmMap(kgem->fd, mmap_arg.offset, bytes(bo), &ptr); 4423d02bce8Sriastradh if (err) { 4439a906b70Schristos#else 4449a906b70Schristos ptr = mmap(0, bytes(bo), PROT_READ | PROT_WRITE, MAP_SHARED, 4459a906b70Schristos kgem->fd, mmap_arg.offset); 4469a906b70Schristos if (ptr == MAP_FAILED) { 4479a906b70Schristos err = errno; 4489a906b70Schristos#endif 44903b705cfSriastradh assert(err != EINVAL); 45003b705cfSriastradh 45103b705cfSriastradh if (__kgem_throttle_retire(kgem, 0)) 45203b705cfSriastradh goto retry_mmap; 45303b705cfSriastradh 4549a906b70Schristos if (kgem_cleanup_cache(kgem)) 45503b705cfSriastradh goto retry_mmap; 45603b705cfSriastradh 4579a906b70Schristos ERR(("%s: failed to mmap handle=%d, %d bytes, into GTT domain: %d\n", 4589a906b70Schristos __FUNCTION__, bo->handle, bytes(bo), err)); 45903b705cfSriastradh ptr = NULL; 46003b705cfSriastradh } 46103b705cfSriastradh 46203b705cfSriastradh return ptr; 46303b705cfSriastradh} 46403b705cfSriastradh 4659a906b70Schristosstatic int gem_write(int fd, uint32_t handle, 4669a906b70Schristos int offset, int length, 4679a906b70Schristos const void *src) 46803b705cfSriastradh{ 46903b705cfSriastradh struct drm_i915_gem_pwrite pwrite; 47003b705cfSriastradh 47103b705cfSriastradh DBG(("%s(handle=%d, offset=%d, len=%d)\n", __FUNCTION__, 47203b705cfSriastradh handle, offset, length)); 47303b705cfSriastradh 47403b705cfSriastradh VG_CLEAR(pwrite); 47503b705cfSriastradh pwrite.handle = handle; 47603b705cfSriastradh pwrite.offset = offset; 47703b705cfSriastradh pwrite.size = length; 47803b705cfSriastradh pwrite.data_ptr = (uintptr_t)src; 4799a906b70Schristos return do_ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite); 48003b705cfSriastradh} 48103b705cfSriastradh 4829a906b70Schristosstatic int gem_write__cachealigned(int fd, uint32_t handle, 4839a906b70Schristos int offset, int length, 4849a906b70Schristos const void *src) 48503b705cfSriastradh{ 48603b705cfSriastradh struct drm_i915_gem_pwrite pwrite; 48703b705cfSriastradh 48803b705cfSriastradh DBG(("%s(handle=%d, offset=%d, len=%d)\n", __FUNCTION__, 48903b705cfSriastradh handle, offset, length)); 49003b705cfSriastradh 49103b705cfSriastradh VG_CLEAR(pwrite); 49203b705cfSriastradh pwrite.handle = handle; 49303b705cfSriastradh /* align the transfer to cachelines; fortuitously this is safe! */ 49403b705cfSriastradh if ((offset | length) & 63) { 49503b705cfSriastradh pwrite.offset = offset & ~63; 49603b705cfSriastradh pwrite.size = ALIGN(offset+length, 64) - pwrite.offset; 49703b705cfSriastradh pwrite.data_ptr = (uintptr_t)src + pwrite.offset - offset; 49803b705cfSriastradh } else { 49903b705cfSriastradh pwrite.offset = offset; 50003b705cfSriastradh pwrite.size = length; 50103b705cfSriastradh pwrite.data_ptr = (uintptr_t)src; 50203b705cfSriastradh } 5039a906b70Schristos return do_ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite); 50403b705cfSriastradh} 50503b705cfSriastradh 50603b705cfSriastradhstatic int gem_read(int fd, uint32_t handle, const void *dst, 50703b705cfSriastradh int offset, int length) 50803b705cfSriastradh{ 50903b705cfSriastradh struct drm_i915_gem_pread pread; 51003b705cfSriastradh int ret; 51103b705cfSriastradh 51203b705cfSriastradh DBG(("%s(handle=%d, len=%d)\n", __FUNCTION__, 51303b705cfSriastradh handle, length)); 51403b705cfSriastradh 51503b705cfSriastradh VG_CLEAR(pread); 51603b705cfSriastradh pread.handle = handle; 51703b705cfSriastradh pread.offset = offset; 51803b705cfSriastradh pread.size = length; 51903b705cfSriastradh pread.data_ptr = (uintptr_t)dst; 5209a906b70Schristos ret = do_ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &pread); 52103b705cfSriastradh if (ret) { 5229a906b70Schristos DBG(("%s: failed, errno=%d\n", __FUNCTION__, -ret)); 52303b705cfSriastradh return ret; 52403b705cfSriastradh } 52503b705cfSriastradh 52603b705cfSriastradh VG(VALGRIND_MAKE_MEM_DEFINED(dst, length)); 52703b705cfSriastradh return 0; 52803b705cfSriastradh} 52903b705cfSriastradh 53003b705cfSriastradhbool __kgem_busy(struct kgem *kgem, int handle) 53103b705cfSriastradh{ 53203b705cfSriastradh struct drm_i915_gem_busy busy; 53303b705cfSriastradh 53403b705cfSriastradh VG_CLEAR(busy); 53503b705cfSriastradh busy.handle = handle; 53603b705cfSriastradh busy.busy = !kgem->wedged; 5379a906b70Schristos (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy); 53803b705cfSriastradh DBG(("%s: handle=%d, busy=%d, wedged=%d\n", 53903b705cfSriastradh __FUNCTION__, handle, busy.busy, kgem->wedged)); 54003b705cfSriastradh 54103b705cfSriastradh return busy.busy; 54203b705cfSriastradh} 54303b705cfSriastradh 54403b705cfSriastradhstatic void kgem_bo_retire(struct kgem *kgem, struct kgem_bo *bo) 54503b705cfSriastradh{ 54603b705cfSriastradh DBG(("%s: retiring bo handle=%d (needed flush? %d), rq? %d [busy?=%d]\n", 54703b705cfSriastradh __FUNCTION__, bo->handle, bo->needs_flush, bo->rq != NULL, 54803b705cfSriastradh __kgem_busy(kgem, bo->handle))); 54903b705cfSriastradh assert(bo->exec == NULL); 55003b705cfSriastradh assert(list_is_empty(&bo->vma)); 55103b705cfSriastradh 5529a906b70Schristos if (bo->rq) { 5539a906b70Schristos __kgem_bo_clear_busy(bo); 5549a906b70Schristos kgem_retire(kgem); 5559a906b70Schristos assert_bo_retired(bo); 5569a906b70Schristos } else { 5579a906b70Schristos assert(bo->exec == NULL); 5589a906b70Schristos assert(list_is_empty(&bo->request)); 5599a906b70Schristos assert(!bo->needs_flush); 5609a906b70Schristos ASSERT_IDLE(kgem, bo->handle); 5619a906b70Schristos } 5629a906b70Schristos} 5639a906b70Schristos 5649a906b70Schristosstatic void kgem_bo_maybe_retire(struct kgem *kgem, struct kgem_bo *bo) 5659a906b70Schristos{ 5669a906b70Schristos DBG(("%s: retiring bo handle=%d (needed flush? %d), rq? %d [busy?=%d]\n", 5679a906b70Schristos __FUNCTION__, bo->handle, bo->needs_flush, bo->rq != NULL, 5689a906b70Schristos __kgem_busy(kgem, bo->handle))); 5699a906b70Schristos assert(bo->exec == NULL); 5709a906b70Schristos assert(list_is_empty(&bo->vma)); 5719a906b70Schristos 57203b705cfSriastradh if (bo->rq) { 57303b705cfSriastradh if (!__kgem_busy(kgem, bo->handle)) { 57403b705cfSriastradh __kgem_bo_clear_busy(bo); 57503b705cfSriastradh kgem_retire(kgem); 57603b705cfSriastradh } 57703b705cfSriastradh } else { 57803b705cfSriastradh assert(!bo->needs_flush); 57903b705cfSriastradh ASSERT_IDLE(kgem, bo->handle); 58003b705cfSriastradh } 58103b705cfSriastradh} 58203b705cfSriastradh 58303b705cfSriastradhbool kgem_bo_write(struct kgem *kgem, struct kgem_bo *bo, 58403b705cfSriastradh const void *data, int length) 58503b705cfSriastradh{ 5869a906b70Schristos int err; 5879a906b70Schristos 58803b705cfSriastradh assert(bo->refcnt); 58903b705cfSriastradh assert(bo->proxy == NULL); 59003b705cfSriastradh ASSERT_IDLE(kgem, bo->handle); 59103b705cfSriastradh 59203b705cfSriastradh assert(length <= bytes(bo)); 5939a906b70Schristosretry: 5949a906b70Schristos if ((err = gem_write(kgem->fd, bo->handle, 0, length, data))) { 5959a906b70Schristos assert(err != EINVAL); 5969a906b70Schristos 5979a906b70Schristos (void)__kgem_throttle_retire(kgem, 0); 5989a906b70Schristos if (kgem_expire_cache(kgem)) 5999a906b70Schristos goto retry; 6009a906b70Schristos 6019a906b70Schristos if (kgem_cleanup_cache(kgem)) 6029a906b70Schristos goto retry; 6039a906b70Schristos 6049a906b70Schristos ERR(("%s: failed to write %d bytes into BO handle=%d: %d\n", 6059a906b70Schristos __FUNCTION__, length, bo->handle, -err)); 60603b705cfSriastradh return false; 6079a906b70Schristos } 60803b705cfSriastradh 60903b705cfSriastradh DBG(("%s: flush=%d, domain=%d\n", __FUNCTION__, bo->flush, bo->domain)); 6109a906b70Schristos if (bo->exec == NULL) 6119a906b70Schristos kgem_bo_maybe_retire(kgem, bo); 6129a906b70Schristos bo->domain = DOMAIN_NONE; 61303b705cfSriastradh bo->gtt_dirty = true; 61403b705cfSriastradh return true; 61503b705cfSriastradh} 61603b705cfSriastradh 61703b705cfSriastradhstatic uint32_t gem_create(int fd, int num_pages) 61803b705cfSriastradh{ 61903b705cfSriastradh struct drm_i915_gem_create create; 62003b705cfSriastradh 62103b705cfSriastradh VG_CLEAR(create); 62203b705cfSriastradh create.handle = 0; 62303b705cfSriastradh create.size = PAGE_SIZE * num_pages; 6249a906b70Schristos (void)do_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); 62503b705cfSriastradh 62603b705cfSriastradh return create.handle; 62703b705cfSriastradh} 62803b705cfSriastradh 62903b705cfSriastradhstatic bool 63003b705cfSriastradhkgem_bo_set_purgeable(struct kgem *kgem, struct kgem_bo *bo) 63103b705cfSriastradh{ 63203b705cfSriastradh#if DBG_NO_MADV 63303b705cfSriastradh return true; 63403b705cfSriastradh#else 63503b705cfSriastradh struct drm_i915_gem_madvise madv; 63603b705cfSriastradh 63703b705cfSriastradh assert(bo->exec == NULL); 63803b705cfSriastradh assert(!bo->purged); 63903b705cfSriastradh 64003b705cfSriastradh VG_CLEAR(madv); 64103b705cfSriastradh madv.handle = bo->handle; 64203b705cfSriastradh madv.madv = I915_MADV_DONTNEED; 6439a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) { 64403b705cfSriastradh bo->purged = 1; 64503b705cfSriastradh kgem->need_purge |= !madv.retained && bo->domain == DOMAIN_GPU; 64603b705cfSriastradh return madv.retained; 64703b705cfSriastradh } 64803b705cfSriastradh 64903b705cfSriastradh return true; 65003b705cfSriastradh#endif 65103b705cfSriastradh} 65203b705cfSriastradh 65303b705cfSriastradhstatic bool 65403b705cfSriastradhkgem_bo_is_retained(struct kgem *kgem, struct kgem_bo *bo) 65503b705cfSriastradh{ 65603b705cfSriastradh#if DBG_NO_MADV 65703b705cfSriastradh return true; 65803b705cfSriastradh#else 65903b705cfSriastradh struct drm_i915_gem_madvise madv; 66003b705cfSriastradh 66103b705cfSriastradh if (!bo->purged) 66203b705cfSriastradh return true; 66303b705cfSriastradh 66403b705cfSriastradh VG_CLEAR(madv); 66503b705cfSriastradh madv.handle = bo->handle; 66603b705cfSriastradh madv.madv = I915_MADV_DONTNEED; 6679a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) 66803b705cfSriastradh return madv.retained; 66903b705cfSriastradh 67003b705cfSriastradh return false; 67103b705cfSriastradh#endif 67203b705cfSriastradh} 67303b705cfSriastradh 67403b705cfSriastradhstatic bool 67503b705cfSriastradhkgem_bo_clear_purgeable(struct kgem *kgem, struct kgem_bo *bo) 67603b705cfSriastradh{ 67703b705cfSriastradh#if DBG_NO_MADV 67803b705cfSriastradh return true; 67903b705cfSriastradh#else 68003b705cfSriastradh struct drm_i915_gem_madvise madv; 68103b705cfSriastradh 68203b705cfSriastradh assert(bo->purged); 68303b705cfSriastradh 68403b705cfSriastradh VG_CLEAR(madv); 68503b705cfSriastradh madv.handle = bo->handle; 68603b705cfSriastradh madv.madv = I915_MADV_WILLNEED; 6879a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) { 68803b705cfSriastradh bo->purged = !madv.retained; 68903b705cfSriastradh kgem->need_purge |= !madv.retained && bo->domain == DOMAIN_GPU; 69003b705cfSriastradh return madv.retained; 69103b705cfSriastradh } 69203b705cfSriastradh 69303b705cfSriastradh return false; 69403b705cfSriastradh#endif 69503b705cfSriastradh} 69603b705cfSriastradh 69703b705cfSriastradhstatic void gem_close(int fd, uint32_t handle) 69803b705cfSriastradh{ 69903b705cfSriastradh struct drm_gem_close close; 70003b705cfSriastradh 70103b705cfSriastradh VG_CLEAR(close); 70203b705cfSriastradh close.handle = handle; 7039a906b70Schristos (void)do_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close); 70403b705cfSriastradh} 70503b705cfSriastradh 70603b705cfSriastradhconstant inline static unsigned long __fls(unsigned long word) 70703b705cfSriastradh{ 70803b705cfSriastradh#if defined(__GNUC__) && (defined(__i386__) || defined(__x86__) || defined(__x86_64__)) 70903b705cfSriastradh asm("bsr %1,%0" 71003b705cfSriastradh : "=r" (word) 71103b705cfSriastradh : "rm" (word)); 71203b705cfSriastradh return word; 71303b705cfSriastradh#else 71403b705cfSriastradh unsigned int v = 0; 71503b705cfSriastradh 71603b705cfSriastradh while (word >>= 1) 71703b705cfSriastradh v++; 71803b705cfSriastradh 71903b705cfSriastradh return v; 72003b705cfSriastradh#endif 72103b705cfSriastradh} 72203b705cfSriastradh 72303b705cfSriastradhconstant inline static int cache_bucket(int num_pages) 72403b705cfSriastradh{ 72503b705cfSriastradh return __fls(num_pages); 72603b705cfSriastradh} 72703b705cfSriastradh 72803b705cfSriastradhstatic struct kgem_bo *__kgem_bo_init(struct kgem_bo *bo, 72903b705cfSriastradh int handle, int num_pages) 73003b705cfSriastradh{ 7319a906b70Schristos DBG(("%s(handle=%d, num_pages=%d)\n", __FUNCTION__, handle, num_pages)); 7329a906b70Schristos 73303b705cfSriastradh assert(num_pages); 73403b705cfSriastradh memset(bo, 0, sizeof(*bo)); 73503b705cfSriastradh 73603b705cfSriastradh bo->refcnt = 1; 73703b705cfSriastradh bo->handle = handle; 73803b705cfSriastradh bo->target_handle = -1; 73903b705cfSriastradh num_pages(bo) = num_pages; 74003b705cfSriastradh bucket(bo) = cache_bucket(num_pages); 74103b705cfSriastradh bo->reusable = true; 74203b705cfSriastradh bo->domain = DOMAIN_CPU; 74303b705cfSriastradh list_init(&bo->request); 74403b705cfSriastradh list_init(&bo->list); 74503b705cfSriastradh list_init(&bo->vma); 74603b705cfSriastradh 74703b705cfSriastradh return bo; 74803b705cfSriastradh} 74903b705cfSriastradh 75003b705cfSriastradhstatic struct kgem_bo *__kgem_bo_alloc(int handle, int num_pages) 75103b705cfSriastradh{ 75203b705cfSriastradh struct kgem_bo *bo; 75303b705cfSriastradh 75403b705cfSriastradh if (__kgem_freed_bo) { 75503b705cfSriastradh bo = __kgem_freed_bo; 75603b705cfSriastradh __kgem_freed_bo = *(struct kgem_bo **)bo; 75703b705cfSriastradh } else { 75803b705cfSriastradh bo = malloc(sizeof(*bo)); 75903b705cfSriastradh if (bo == NULL) 76003b705cfSriastradh return NULL; 76103b705cfSriastradh } 76203b705cfSriastradh 76303b705cfSriastradh return __kgem_bo_init(bo, handle, num_pages); 76403b705cfSriastradh} 76503b705cfSriastradh 76603b705cfSriastradhstatic struct kgem_request *__kgem_request_alloc(struct kgem *kgem) 76703b705cfSriastradh{ 76803b705cfSriastradh struct kgem_request *rq; 76903b705cfSriastradh 77003b705cfSriastradh rq = __kgem_freed_request; 77103b705cfSriastradh if (rq) { 77203b705cfSriastradh __kgem_freed_request = *(struct kgem_request **)rq; 77303b705cfSriastradh } else { 77403b705cfSriastradh rq = malloc(sizeof(*rq)); 77503b705cfSriastradh if (rq == NULL) 77603b705cfSriastradh rq = &kgem->static_request; 77703b705cfSriastradh } 77803b705cfSriastradh 77903b705cfSriastradh list_init(&rq->buffers); 78003b705cfSriastradh rq->bo = NULL; 78103b705cfSriastradh rq->ring = 0; 78203b705cfSriastradh 78303b705cfSriastradh return rq; 78403b705cfSriastradh} 78503b705cfSriastradh 78603b705cfSriastradhstatic void __kgem_request_free(struct kgem_request *rq) 78703b705cfSriastradh{ 78803b705cfSriastradh _list_del(&rq->list); 7899a906b70Schristos if (DBG_NO_MALLOC_CACHE) { 7909a906b70Schristos free(rq); 7919a906b70Schristos } else { 7929a906b70Schristos *(struct kgem_request **)rq = __kgem_freed_request; 7939a906b70Schristos __kgem_freed_request = rq; 7949a906b70Schristos } 79503b705cfSriastradh} 79603b705cfSriastradh 79703b705cfSriastradhstatic struct list *inactive(struct kgem *kgem, int num_pages) 79803b705cfSriastradh{ 79903b705cfSriastradh assert(num_pages < MAX_CACHE_SIZE / PAGE_SIZE); 80003b705cfSriastradh assert(cache_bucket(num_pages) < NUM_CACHE_BUCKETS); 80103b705cfSriastradh return &kgem->inactive[cache_bucket(num_pages)]; 80203b705cfSriastradh} 80303b705cfSriastradh 80403b705cfSriastradhstatic struct list *active(struct kgem *kgem, int num_pages, int tiling) 80503b705cfSriastradh{ 80603b705cfSriastradh assert(num_pages < MAX_CACHE_SIZE / PAGE_SIZE); 80703b705cfSriastradh assert(cache_bucket(num_pages) < NUM_CACHE_BUCKETS); 80803b705cfSriastradh return &kgem->active[cache_bucket(num_pages)][tiling]; 80903b705cfSriastradh} 81003b705cfSriastradh 81103b705cfSriastradhstatic size_t 81203b705cfSriastradhagp_aperture_size(struct pci_device *dev, unsigned gen) 81303b705cfSriastradh{ 81403b705cfSriastradh /* XXX assume that only future chipsets are unknown and follow 81503b705cfSriastradh * the post gen2 PCI layout. 81603b705cfSriastradh */ 81703b705cfSriastradh return dev->regions[gen < 030 ? 0 : 2].size; 81803b705cfSriastradh} 81903b705cfSriastradh 82003b705cfSriastradhstatic size_t 82103b705cfSriastradhtotal_ram_size(void) 82203b705cfSriastradh{ 82303b705cfSriastradh#ifdef HAVE_STRUCT_SYSINFO_TOTALRAM 82403b705cfSriastradh struct sysinfo info; 82503b705cfSriastradh if (sysinfo(&info) == 0) 82603b705cfSriastradh return info.totalram * info.mem_unit; 82703b705cfSriastradh#endif 82803b705cfSriastradh 82903b705cfSriastradh#ifdef _SC_PHYS_PAGES 83003b705cfSriastradh return sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE); 83103b705cfSriastradh#endif 83203b705cfSriastradh 83303b705cfSriastradh return 0; 83403b705cfSriastradh} 83503b705cfSriastradh 83603b705cfSriastradhstatic unsigned 83703b705cfSriastradhcpu_cache_size__cpuid4(void) 83803b705cfSriastradh{ 8399a906b70Schristos /* Deterministic Cache Parameters (Function 04h)": 84003b705cfSriastradh * When EAX is initialized to a value of 4, the CPUID instruction 84103b705cfSriastradh * returns deterministic cache information in the EAX, EBX, ECX 84203b705cfSriastradh * and EDX registers. This function requires ECX be initialized 84303b705cfSriastradh * with an index which indicates which cache to return information 84403b705cfSriastradh * about. The OS is expected to call this function (CPUID.4) with 84503b705cfSriastradh * ECX = 0, 1, 2, until EAX[4:0] == 0, indicating no more caches. 84603b705cfSriastradh * The order in which the caches are returned is not specified 84703b705cfSriastradh * and may change at Intel's discretion. 84803b705cfSriastradh * 84903b705cfSriastradh * Calculating the Cache Size in bytes: 85003b705cfSriastradh * = (Ways +1) * (Partitions +1) * (Line Size +1) * (Sets +1) 85103b705cfSriastradh */ 85203b705cfSriastradh 85303b705cfSriastradh unsigned int eax, ebx, ecx, edx; 85403b705cfSriastradh unsigned int llc_size = 0; 8559a906b70Schristos int cnt; 85603b705cfSriastradh 85703b705cfSriastradh if (__get_cpuid_max(BASIC_CPUID, NULL) < 4) 85803b705cfSriastradh return 0; 85903b705cfSriastradh 8609a906b70Schristos cnt = 0; 86103b705cfSriastradh do { 86203b705cfSriastradh unsigned associativity, line_partitions, line_size, sets; 86303b705cfSriastradh 86403b705cfSriastradh __cpuid_count(4, cnt++, eax, ebx, ecx, edx); 86503b705cfSriastradh 86603b705cfSriastradh if ((eax & 0x1f) == 0) 86703b705cfSriastradh break; 86803b705cfSriastradh 86903b705cfSriastradh associativity = ((ebx >> 22) & 0x3ff) + 1; 87003b705cfSriastradh line_partitions = ((ebx >> 12) & 0x3ff) + 1; 87103b705cfSriastradh line_size = (ebx & 0xfff) + 1; 87203b705cfSriastradh sets = ecx + 1; 87303b705cfSriastradh 87403b705cfSriastradh llc_size = associativity * line_partitions * line_size * sets; 87503b705cfSriastradh } while (1); 87603b705cfSriastradh 87703b705cfSriastradh return llc_size; 87803b705cfSriastradh} 87903b705cfSriastradh 88003b705cfSriastradhstatic unsigned 88103b705cfSriastradhcpu_cache_size(void) 88203b705cfSriastradh{ 88303b705cfSriastradh unsigned size; 88403b705cfSriastradh FILE *file; 88503b705cfSriastradh 88603b705cfSriastradh size = cpu_cache_size__cpuid4(); 88703b705cfSriastradh if (size) 88803b705cfSriastradh return size; 88903b705cfSriastradh 89003b705cfSriastradh file = fopen("/proc/cpuinfo", "r"); 89103b705cfSriastradh if (file) { 89203b705cfSriastradh size_t len = 0; 89303b705cfSriastradh char *line = NULL; 89403b705cfSriastradh while (getline(&line, &len, file) != -1) { 89503b705cfSriastradh int kb; 89603b705cfSriastradh if (sscanf(line, "cache size : %d KB", &kb) == 1) { 89703b705cfSriastradh /* Paranoid check against gargantuan caches */ 89803b705cfSriastradh if (kb <= 1<<20) 89903b705cfSriastradh size = kb * 1024; 90003b705cfSriastradh break; 90103b705cfSriastradh } 90203b705cfSriastradh } 90303b705cfSriastradh free(line); 90403b705cfSriastradh fclose(file); 90503b705cfSriastradh } 90603b705cfSriastradh 90703b705cfSriastradh if (size == 0) 90803b705cfSriastradh size = 64 * 1024; 90903b705cfSriastradh 91003b705cfSriastradh return size; 91103b705cfSriastradh} 91203b705cfSriastradh 91303b705cfSriastradhstatic int gem_param(struct kgem *kgem, int name) 91403b705cfSriastradh{ 91503b705cfSriastradh drm_i915_getparam_t gp; 91603b705cfSriastradh int v = -1; /* No param uses the sign bit, reserve it for errors */ 91703b705cfSriastradh 91803b705cfSriastradh VG_CLEAR(gp); 91903b705cfSriastradh gp.param = name; 92003b705cfSriastradh gp.value = &v; 9219a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GETPARAM, &gp)) 92203b705cfSriastradh return -1; 92303b705cfSriastradh 92403b705cfSriastradh VG(VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v))); 92503b705cfSriastradh return v; 92603b705cfSriastradh} 92703b705cfSriastradh 92803b705cfSriastradhstatic bool test_has_execbuffer2(struct kgem *kgem) 92903b705cfSriastradh{ 93003b705cfSriastradh struct drm_i915_gem_execbuffer2 execbuf; 93103b705cfSriastradh 93203b705cfSriastradh memset(&execbuf, 0, sizeof(execbuf)); 93303b705cfSriastradh execbuf.buffer_count = 1; 93403b705cfSriastradh 9359a906b70Schristos return do_ioctl(kgem->fd, 93603b705cfSriastradh DRM_IOCTL_I915_GEM_EXECBUFFER2, 9379a906b70Schristos &execbuf) == -EFAULT; 93803b705cfSriastradh} 93903b705cfSriastradh 94003b705cfSriastradhstatic bool test_has_no_reloc(struct kgem *kgem) 94103b705cfSriastradh{ 94203b705cfSriastradh if (DBG_NO_FAST_RELOC) 94303b705cfSriastradh return false; 94403b705cfSriastradh 94503b705cfSriastradh return gem_param(kgem, LOCAL_I915_PARAM_HAS_NO_RELOC) > 0; 94603b705cfSriastradh} 94703b705cfSriastradh 94803b705cfSriastradhstatic bool test_has_handle_lut(struct kgem *kgem) 94903b705cfSriastradh{ 95003b705cfSriastradh if (DBG_NO_HANDLE_LUT) 95103b705cfSriastradh return false; 95203b705cfSriastradh 95303b705cfSriastradh return gem_param(kgem, LOCAL_I915_PARAM_HAS_HANDLE_LUT) > 0; 95403b705cfSriastradh} 95503b705cfSriastradh 95603b705cfSriastradhstatic bool test_has_wt(struct kgem *kgem) 95703b705cfSriastradh{ 95803b705cfSriastradh if (DBG_NO_WT) 95903b705cfSriastradh return false; 96003b705cfSriastradh 96103b705cfSriastradh return gem_param(kgem, LOCAL_I915_PARAM_HAS_WT) > 0; 96203b705cfSriastradh} 96303b705cfSriastradh 96403b705cfSriastradhstatic bool test_has_semaphores_enabled(struct kgem *kgem) 96503b705cfSriastradh{ 96603b705cfSriastradh FILE *file; 96703b705cfSriastradh bool detected = false; 96803b705cfSriastradh int ret; 96903b705cfSriastradh 97003b705cfSriastradh if (DBG_NO_SEMAPHORES) 97103b705cfSriastradh return false; 97203b705cfSriastradh 97303b705cfSriastradh ret = gem_param(kgem, LOCAL_I915_PARAM_HAS_SEMAPHORES); 97403b705cfSriastradh if (ret != -1) 97503b705cfSriastradh return ret > 0; 97603b705cfSriastradh 97703b705cfSriastradh file = fopen("/sys/module/i915/parameters/semaphores", "r"); 97803b705cfSriastradh if (file) { 97903b705cfSriastradh int value; 98003b705cfSriastradh if (fscanf(file, "%d", &value) == 1) 98103b705cfSriastradh detected = value != 0; 98203b705cfSriastradh fclose(file); 98303b705cfSriastradh } 98403b705cfSriastradh 98503b705cfSriastradh return detected; 98603b705cfSriastradh} 98703b705cfSriastradh 98803b705cfSriastradhstatic bool is_hw_supported(struct kgem *kgem, 98903b705cfSriastradh struct pci_device *dev) 99003b705cfSriastradh{ 99103b705cfSriastradh if (DBG_NO_HW) 99203b705cfSriastradh return false; 99303b705cfSriastradh 99403b705cfSriastradh if (!test_has_execbuffer2(kgem)) 99503b705cfSriastradh return false; 99603b705cfSriastradh 99703b705cfSriastradh if (kgem->gen == (unsigned)-1) /* unknown chipset, assume future gen */ 99803b705cfSriastradh return kgem->has_blt; 99903b705cfSriastradh 100003b705cfSriastradh /* Although pre-855gm the GMCH is fubar, it works mostly. So 100103b705cfSriastradh * let the user decide through "NoAccel" whether or not to risk 100203b705cfSriastradh * hw acceleration. 100303b705cfSriastradh */ 100403b705cfSriastradh 10059a906b70Schristos if (kgem->gen == 060 && dev && dev->revision < 8) { 100603b705cfSriastradh /* pre-production SNB with dysfunctional BLT */ 100703b705cfSriastradh return false; 100803b705cfSriastradh } 100903b705cfSriastradh 101003b705cfSriastradh if (kgem->gen >= 060) /* Only if the kernel supports the BLT ring */ 101103b705cfSriastradh return kgem->has_blt; 101203b705cfSriastradh 101303b705cfSriastradh return true; 101403b705cfSriastradh} 101503b705cfSriastradh 101603b705cfSriastradhstatic bool test_has_relaxed_fencing(struct kgem *kgem) 101703b705cfSriastradh{ 101803b705cfSriastradh if (kgem->gen < 040) { 101903b705cfSriastradh if (DBG_NO_RELAXED_FENCING) 102003b705cfSriastradh return false; 102103b705cfSriastradh 102203b705cfSriastradh return gem_param(kgem, LOCAL_I915_PARAM_HAS_RELAXED_FENCING) > 0; 102303b705cfSriastradh } else 102403b705cfSriastradh return true; 102503b705cfSriastradh} 102603b705cfSriastradh 102703b705cfSriastradhstatic bool test_has_llc(struct kgem *kgem) 102803b705cfSriastradh{ 102903b705cfSriastradh int has_llc = -1; 103003b705cfSriastradh 103103b705cfSriastradh if (DBG_NO_LLC) 103203b705cfSriastradh return false; 103303b705cfSriastradh 103403b705cfSriastradh#if defined(I915_PARAM_HAS_LLC) /* Expected in libdrm-2.4.31 */ 103503b705cfSriastradh has_llc = gem_param(kgem, I915_PARAM_HAS_LLC); 103603b705cfSriastradh#endif 103703b705cfSriastradh if (has_llc == -1) { 103803b705cfSriastradh DBG(("%s: no kernel/drm support for HAS_LLC, assuming support for LLC based on GPU generation\n", __FUNCTION__)); 103903b705cfSriastradh has_llc = kgem->gen >= 060; 104003b705cfSriastradh } 104103b705cfSriastradh 104203b705cfSriastradh return has_llc; 104303b705cfSriastradh} 104403b705cfSriastradh 104503b705cfSriastradhstatic bool test_has_caching(struct kgem *kgem) 104603b705cfSriastradh{ 104703b705cfSriastradh uint32_t handle; 104803b705cfSriastradh bool ret; 104903b705cfSriastradh 105003b705cfSriastradh if (DBG_NO_CACHE_LEVEL) 105103b705cfSriastradh return false; 105203b705cfSriastradh 105303b705cfSriastradh /* Incoherent blt and sampler hangs the GPU */ 105403b705cfSriastradh if (kgem->gen == 040) 105503b705cfSriastradh return false; 105603b705cfSriastradh 105703b705cfSriastradh handle = gem_create(kgem->fd, 1); 105803b705cfSriastradh if (handle == 0) 105903b705cfSriastradh return false; 106003b705cfSriastradh 106103b705cfSriastradh ret = gem_set_caching(kgem->fd, handle, UNCACHED); 106203b705cfSriastradh gem_close(kgem->fd, handle); 106303b705cfSriastradh return ret; 106403b705cfSriastradh} 106503b705cfSriastradh 106603b705cfSriastradhstatic bool test_has_userptr(struct kgem *kgem) 106703b705cfSriastradh{ 106803b705cfSriastradh uint32_t handle; 106903b705cfSriastradh void *ptr; 107003b705cfSriastradh 107103b705cfSriastradh if (DBG_NO_USERPTR) 107203b705cfSriastradh return false; 107303b705cfSriastradh 107403b705cfSriastradh /* Incoherent blt and sampler hangs the GPU */ 107503b705cfSriastradh if (kgem->gen == 040) 107603b705cfSriastradh return false; 107703b705cfSriastradh 10789a906b70Schristos if (kgem->gen >= 0100) 10799a906b70Schristos return false; /* FIXME https://bugs.freedesktop.org/show_bug.cgi?id=79053 */ 10809a906b70Schristos 108103b705cfSriastradh if (posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE)) 108203b705cfSriastradh return false; 108303b705cfSriastradh 108403b705cfSriastradh handle = gem_userptr(kgem->fd, ptr, PAGE_SIZE, false); 108503b705cfSriastradh gem_close(kgem->fd, handle); 108603b705cfSriastradh free(ptr); 108703b705cfSriastradh 108803b705cfSriastradh return handle != 0; 108903b705cfSriastradh} 109003b705cfSriastradh 109103b705cfSriastradhstatic bool test_has_create2(struct kgem *kgem) 109203b705cfSriastradh{ 109303b705cfSriastradh#if defined(USE_CREATE2) 109403b705cfSriastradh struct local_i915_gem_create2 args; 109503b705cfSriastradh 109603b705cfSriastradh if (DBG_NO_CREATE2) 109703b705cfSriastradh return false; 109803b705cfSriastradh 109903b705cfSriastradh memset(&args, 0, sizeof(args)); 110003b705cfSriastradh args.size = PAGE_SIZE; 110103b705cfSriastradh args.caching = DISPLAY; 11029a906b70Schristos if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_CREATE2, &args) == 0) 110303b705cfSriastradh gem_close(kgem->fd, args.handle); 110403b705cfSriastradh 110503b705cfSriastradh return args.handle != 0; 110603b705cfSriastradh#else 110703b705cfSriastradh return false; 110803b705cfSriastradh#endif 110903b705cfSriastradh} 111003b705cfSriastradh 111103b705cfSriastradhstatic bool test_has_secure_batches(struct kgem *kgem) 111203b705cfSriastradh{ 111303b705cfSriastradh if (DBG_NO_SECURE_BATCHES) 111403b705cfSriastradh return false; 111503b705cfSriastradh 111603b705cfSriastradh return gem_param(kgem, LOCAL_I915_PARAM_HAS_SECURE_BATCHES) > 0; 111703b705cfSriastradh} 111803b705cfSriastradh 111903b705cfSriastradhstatic bool test_has_pinned_batches(struct kgem *kgem) 112003b705cfSriastradh{ 112103b705cfSriastradh if (DBG_NO_PINNED_BATCHES) 112203b705cfSriastradh return false; 112303b705cfSriastradh 112403b705cfSriastradh return gem_param(kgem, LOCAL_I915_PARAM_HAS_PINNED_BATCHES) > 0; 112503b705cfSriastradh} 112603b705cfSriastradh 112703b705cfSriastradhstatic int kgem_get_screen_index(struct kgem *kgem) 112803b705cfSriastradh{ 112903b705cfSriastradh struct sna *sna = container_of(kgem, struct sna, kgem); 113003b705cfSriastradh return sna->scrn->scrnIndex; 113103b705cfSriastradh} 113203b705cfSriastradh 11339a906b70Schristosstatic int __find_debugfs(struct kgem *kgem) 11349a906b70Schristos{ 11359a906b70Schristos int i; 11369a906b70Schristos 11379a906b70Schristos for (i = 0; i < DRM_MAX_MINOR; i++) { 11389a906b70Schristos char path[80]; 11399a906b70Schristos 11409a906b70Schristos sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i); 11419a906b70Schristos if (access(path, R_OK) == 0) 11429a906b70Schristos return i; 11439a906b70Schristos 11449a906b70Schristos sprintf(path, "/debug/dri/%d/i915_wedged", i); 11459a906b70Schristos if (access(path, R_OK) == 0) 11469a906b70Schristos return i; 11479a906b70Schristos } 11489a906b70Schristos 11499a906b70Schristos return -1; 11509a906b70Schristos} 11519a906b70Schristos 11529a906b70Schristosstatic int kgem_get_minor(struct kgem *kgem) 11539a906b70Schristos{ 11549a906b70Schristos struct stat st; 11559a906b70Schristos 11569a906b70Schristos if (fstat(kgem->fd, &st)) 11579a906b70Schristos return __find_debugfs(kgem); 11589a906b70Schristos 11599a906b70Schristos if (!S_ISCHR(st.st_mode)) 11609a906b70Schristos return __find_debugfs(kgem); 11619a906b70Schristos 11629a906b70Schristos return st.st_rdev & 0x63; 11639a906b70Schristos} 11649a906b70Schristos 116503b705cfSriastradhstatic bool kgem_init_pinned_batches(struct kgem *kgem) 116603b705cfSriastradh{ 116703b705cfSriastradh int count[2] = { 16, 4 }; 116803b705cfSriastradh int size[2] = { 1, 4 }; 116903b705cfSriastradh int n, i; 117003b705cfSriastradh 117103b705cfSriastradh if (kgem->wedged) 117203b705cfSriastradh return true; 117303b705cfSriastradh 117403b705cfSriastradh for (n = 0; n < ARRAY_SIZE(count); n++) { 117503b705cfSriastradh for (i = 0; i < count[n]; i++) { 117603b705cfSriastradh struct drm_i915_gem_pin pin; 117703b705cfSriastradh struct kgem_bo *bo; 117803b705cfSriastradh 117903b705cfSriastradh VG_CLEAR(pin); 118003b705cfSriastradh 118103b705cfSriastradh pin.handle = gem_create(kgem->fd, size[n]); 118203b705cfSriastradh if (pin.handle == 0) 118303b705cfSriastradh goto err; 118403b705cfSriastradh 118503b705cfSriastradh DBG(("%s: new handle=%d, num_pages=%d\n", 118603b705cfSriastradh __FUNCTION__, pin.handle, size[n])); 118703b705cfSriastradh 118803b705cfSriastradh bo = __kgem_bo_alloc(pin.handle, size[n]); 118903b705cfSriastradh if (bo == NULL) { 119003b705cfSriastradh gem_close(kgem->fd, pin.handle); 119103b705cfSriastradh goto err; 119203b705cfSriastradh } 119303b705cfSriastradh 119403b705cfSriastradh pin.alignment = 0; 11959a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_PIN, &pin)) { 119603b705cfSriastradh gem_close(kgem->fd, pin.handle); 11979a906b70Schristos free(bo); 119803b705cfSriastradh goto err; 119903b705cfSriastradh } 120003b705cfSriastradh bo->presumed_offset = pin.offset; 120103b705cfSriastradh debug_alloc__bo(kgem, bo); 120203b705cfSriastradh list_add(&bo->list, &kgem->pinned_batches[n]); 120303b705cfSriastradh } 120403b705cfSriastradh } 120503b705cfSriastradh 120603b705cfSriastradh return true; 120703b705cfSriastradh 120803b705cfSriastradherr: 120903b705cfSriastradh for (n = 0; n < ARRAY_SIZE(kgem->pinned_batches); n++) { 121003b705cfSriastradh while (!list_is_empty(&kgem->pinned_batches[n])) { 121103b705cfSriastradh kgem_bo_destroy(kgem, 121203b705cfSriastradh list_first_entry(&kgem->pinned_batches[n], 121303b705cfSriastradh struct kgem_bo, list)); 121403b705cfSriastradh } 121503b705cfSriastradh } 121603b705cfSriastradh 121703b705cfSriastradh /* For simplicity populate the lists with a single unpinned bo */ 121803b705cfSriastradh for (n = 0; n < ARRAY_SIZE(count); n++) { 121903b705cfSriastradh struct kgem_bo *bo; 122003b705cfSriastradh uint32_t handle; 122103b705cfSriastradh 122203b705cfSriastradh handle = gem_create(kgem->fd, size[n]); 122303b705cfSriastradh if (handle == 0) 122403b705cfSriastradh break; 122503b705cfSriastradh 122603b705cfSriastradh bo = __kgem_bo_alloc(handle, size[n]); 122703b705cfSriastradh if (bo == NULL) { 122803b705cfSriastradh gem_close(kgem->fd, handle); 122903b705cfSriastradh break; 123003b705cfSriastradh } 123103b705cfSriastradh 123203b705cfSriastradh debug_alloc__bo(kgem, bo); 123303b705cfSriastradh list_add(&bo->list, &kgem->pinned_batches[n]); 123403b705cfSriastradh } 123503b705cfSriastradh return false; 123603b705cfSriastradh} 123703b705cfSriastradh 123803b705cfSriastradhstatic void kgem_init_swizzling(struct kgem *kgem) 123903b705cfSriastradh{ 124003b705cfSriastradh struct drm_i915_gem_get_tiling tiling; 124103b705cfSriastradh 124203b705cfSriastradh if (kgem->gen < 050) /* bit17 swizzling :( */ 124303b705cfSriastradh return; 124403b705cfSriastradh 124503b705cfSriastradh VG_CLEAR(tiling); 124603b705cfSriastradh tiling.handle = gem_create(kgem->fd, 1); 124703b705cfSriastradh if (!tiling.handle) 124803b705cfSriastradh return; 124903b705cfSriastradh 125003b705cfSriastradh if (!gem_set_tiling(kgem->fd, tiling.handle, I915_TILING_X, 512)) 125103b705cfSriastradh goto out; 125203b705cfSriastradh 12539a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling)) 125403b705cfSriastradh goto out; 125503b705cfSriastradh 125603b705cfSriastradh choose_memcpy_tiled_x(kgem, tiling.swizzle_mode); 125703b705cfSriastradhout: 125803b705cfSriastradh gem_close(kgem->fd, tiling.handle); 125903b705cfSriastradh} 126003b705cfSriastradh 126103b705cfSriastradh 126203b705cfSriastradhvoid kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen) 126303b705cfSriastradh{ 126403b705cfSriastradh struct drm_i915_gem_get_aperture aperture; 126503b705cfSriastradh size_t totalram; 126603b705cfSriastradh unsigned half_gpu_max; 126703b705cfSriastradh unsigned int i, j; 126803b705cfSriastradh 126903b705cfSriastradh DBG(("%s: fd=%d, gen=%d\n", __FUNCTION__, fd, gen)); 127003b705cfSriastradh 127103b705cfSriastradh kgem->fd = fd; 127203b705cfSriastradh kgem->gen = gen; 127303b705cfSriastradh 127403b705cfSriastradh list_init(&kgem->requests[0]); 127503b705cfSriastradh list_init(&kgem->requests[1]); 127603b705cfSriastradh list_init(&kgem->batch_buffers); 127703b705cfSriastradh list_init(&kgem->active_buffers); 127803b705cfSriastradh list_init(&kgem->flushing); 127903b705cfSriastradh list_init(&kgem->large); 128003b705cfSriastradh list_init(&kgem->large_inactive); 128103b705cfSriastradh list_init(&kgem->snoop); 128203b705cfSriastradh list_init(&kgem->scanout); 128303b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->pinned_batches); i++) 128403b705cfSriastradh list_init(&kgem->pinned_batches[i]); 128503b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) 128603b705cfSriastradh list_init(&kgem->inactive[i]); 128703b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->active); i++) { 128803b705cfSriastradh for (j = 0; j < ARRAY_SIZE(kgem->active[i]); j++) 128903b705cfSriastradh list_init(&kgem->active[i][j]); 129003b705cfSriastradh } 129103b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->vma); i++) { 129203b705cfSriastradh for (j = 0; j < ARRAY_SIZE(kgem->vma[i].inactive); j++) 129303b705cfSriastradh list_init(&kgem->vma[i].inactive[j]); 129403b705cfSriastradh } 129503b705cfSriastradh kgem->vma[MAP_GTT].count = -MAX_GTT_VMA_CACHE; 129603b705cfSriastradh kgem->vma[MAP_CPU].count = -MAX_CPU_VMA_CACHE; 129703b705cfSriastradh 129803b705cfSriastradh kgem->has_blt = gem_param(kgem, LOCAL_I915_PARAM_HAS_BLT) > 0; 129903b705cfSriastradh DBG(("%s: has BLT ring? %d\n", __FUNCTION__, 130003b705cfSriastradh kgem->has_blt)); 130103b705cfSriastradh 130203b705cfSriastradh kgem->has_relaxed_delta = 130303b705cfSriastradh gem_param(kgem, LOCAL_I915_PARAM_HAS_RELAXED_DELTA) > 0; 130403b705cfSriastradh DBG(("%s: has relaxed delta? %d\n", __FUNCTION__, 130503b705cfSriastradh kgem->has_relaxed_delta)); 130603b705cfSriastradh 130703b705cfSriastradh kgem->has_relaxed_fencing = test_has_relaxed_fencing(kgem); 130803b705cfSriastradh DBG(("%s: has relaxed fencing? %d\n", __FUNCTION__, 130903b705cfSriastradh kgem->has_relaxed_fencing)); 131003b705cfSriastradh 131103b705cfSriastradh kgem->has_llc = test_has_llc(kgem); 131203b705cfSriastradh DBG(("%s: has shared last-level-cache? %d\n", __FUNCTION__, 131303b705cfSriastradh kgem->has_llc)); 131403b705cfSriastradh 131503b705cfSriastradh kgem->has_wt = test_has_wt(kgem); 131603b705cfSriastradh DBG(("%s: has write-through caching for scanouts? %d\n", __FUNCTION__, 131703b705cfSriastradh kgem->has_wt)); 131803b705cfSriastradh 131903b705cfSriastradh kgem->has_caching = test_has_caching(kgem); 132003b705cfSriastradh DBG(("%s: has set-cache-level? %d\n", __FUNCTION__, 132103b705cfSriastradh kgem->has_caching)); 132203b705cfSriastradh 132303b705cfSriastradh kgem->has_userptr = test_has_userptr(kgem); 132403b705cfSriastradh DBG(("%s: has userptr? %d\n", __FUNCTION__, 132503b705cfSriastradh kgem->has_userptr)); 132603b705cfSriastradh 132703b705cfSriastradh kgem->has_create2 = test_has_create2(kgem); 132803b705cfSriastradh DBG(("%s: has create2? %d\n", __FUNCTION__, 132903b705cfSriastradh kgem->has_create2)); 133003b705cfSriastradh 133103b705cfSriastradh kgem->has_no_reloc = test_has_no_reloc(kgem); 133203b705cfSriastradh DBG(("%s: has no-reloc? %d\n", __FUNCTION__, 133303b705cfSriastradh kgem->has_no_reloc)); 133403b705cfSriastradh 133503b705cfSriastradh kgem->has_handle_lut = test_has_handle_lut(kgem); 133603b705cfSriastradh DBG(("%s: has handle-lut? %d\n", __FUNCTION__, 133703b705cfSriastradh kgem->has_handle_lut)); 133803b705cfSriastradh 133903b705cfSriastradh kgem->has_semaphores = false; 134003b705cfSriastradh if (kgem->has_blt && test_has_semaphores_enabled(kgem)) 134103b705cfSriastradh kgem->has_semaphores = true; 134203b705cfSriastradh DBG(("%s: semaphores enabled? %d\n", __FUNCTION__, 134303b705cfSriastradh kgem->has_semaphores)); 134403b705cfSriastradh 134503b705cfSriastradh kgem->can_blt_cpu = gen >= 030; 134603b705cfSriastradh DBG(("%s: can blt to cpu? %d\n", __FUNCTION__, 134703b705cfSriastradh kgem->can_blt_cpu)); 134803b705cfSriastradh 13499a906b70Schristos kgem->can_render_y = gen != 021 && (gen >> 3) != 4; 13509a906b70Schristos DBG(("%s: can render to Y-tiled surfaces? %d\n", __FUNCTION__, 13519a906b70Schristos kgem->can_render_y)); 13529a906b70Schristos 135303b705cfSriastradh kgem->has_secure_batches = test_has_secure_batches(kgem); 135403b705cfSriastradh DBG(("%s: can use privileged batchbuffers? %d\n", __FUNCTION__, 135503b705cfSriastradh kgem->has_secure_batches)); 135603b705cfSriastradh 135703b705cfSriastradh kgem->has_pinned_batches = test_has_pinned_batches(kgem); 135803b705cfSriastradh DBG(("%s: can use pinned batchbuffers (to avoid CS w/a)? %d\n", __FUNCTION__, 135903b705cfSriastradh kgem->has_pinned_batches)); 136003b705cfSriastradh 136103b705cfSriastradh if (!is_hw_supported(kgem, dev)) { 136203b705cfSriastradh xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING, 136303b705cfSriastradh "Detected unsupported/dysfunctional hardware, disabling acceleration.\n"); 136403b705cfSriastradh kgem->wedged = 1; 13659a906b70Schristos } else if (__kgem_throttle(kgem, false)) { 136603b705cfSriastradh xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING, 136703b705cfSriastradh "Detected a hung GPU, disabling acceleration.\n"); 136803b705cfSriastradh kgem->wedged = 1; 136903b705cfSriastradh } 137003b705cfSriastradh 137103b705cfSriastradh kgem->batch_size = ARRAY_SIZE(kgem->batch); 137203b705cfSriastradh if (gen == 020 && !kgem->has_pinned_batches) 137303b705cfSriastradh /* Limited to what we can pin */ 137403b705cfSriastradh kgem->batch_size = 4*1024; 137503b705cfSriastradh if (gen == 022) 137603b705cfSriastradh /* 865g cannot handle a batch spanning multiple pages */ 137703b705cfSriastradh kgem->batch_size = PAGE_SIZE / sizeof(uint32_t); 13789a906b70Schristos if (gen >= 070) 137903b705cfSriastradh kgem->batch_size = 16*1024; 138003b705cfSriastradh if (!kgem->has_relaxed_delta && kgem->batch_size > 4*1024) 138103b705cfSriastradh kgem->batch_size = 4*1024; 138203b705cfSriastradh 138303b705cfSriastradh if (!kgem_init_pinned_batches(kgem) && gen == 020) { 138403b705cfSriastradh xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING, 138503b705cfSriastradh "Unable to reserve memory for GPU, disabling acceleration.\n"); 138603b705cfSriastradh kgem->wedged = 1; 138703b705cfSriastradh } 138803b705cfSriastradh 138903b705cfSriastradh DBG(("%s: maximum batch size? %d\n", __FUNCTION__, 139003b705cfSriastradh kgem->batch_size)); 139103b705cfSriastradh 139203b705cfSriastradh kgem->half_cpu_cache_pages = cpu_cache_size() >> 13; 139303b705cfSriastradh DBG(("%s: last-level cache size: %d bytes, threshold in pages: %d\n", 139403b705cfSriastradh __FUNCTION__, cpu_cache_size(), kgem->half_cpu_cache_pages)); 139503b705cfSriastradh 139603b705cfSriastradh kgem->next_request = __kgem_request_alloc(kgem); 139703b705cfSriastradh 139803b705cfSriastradh DBG(("%s: cpu bo enabled %d: llc? %d, set-cache-level? %d, userptr? %d\n", __FUNCTION__, 139903b705cfSriastradh !DBG_NO_CPU && (kgem->has_llc | kgem->has_userptr | kgem->has_caching), 140003b705cfSriastradh kgem->has_llc, kgem->has_caching, kgem->has_userptr)); 140103b705cfSriastradh 140203b705cfSriastradh VG_CLEAR(aperture); 140303b705cfSriastradh aperture.aper_size = 0; 14049a906b70Schristos (void)do_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture); 140503b705cfSriastradh if (aperture.aper_size == 0) 140603b705cfSriastradh aperture.aper_size = 64*1024*1024; 140703b705cfSriastradh 140803b705cfSriastradh DBG(("%s: aperture size %lld, available now %lld\n", 140903b705cfSriastradh __FUNCTION__, 141003b705cfSriastradh (long long)aperture.aper_size, 141103b705cfSriastradh (long long)aperture.aper_available_size)); 141203b705cfSriastradh 141303b705cfSriastradh kgem->aperture_total = aperture.aper_size; 141403b705cfSriastradh kgem->aperture_high = aperture.aper_size * 3/4; 141503b705cfSriastradh kgem->aperture_low = aperture.aper_size * 1/3; 141603b705cfSriastradh if (gen < 033) { 141703b705cfSriastradh /* Severe alignment penalties */ 141803b705cfSriastradh kgem->aperture_high /= 2; 141903b705cfSriastradh kgem->aperture_low /= 2; 142003b705cfSriastradh } 142103b705cfSriastradh DBG(("%s: aperture low=%d [%d], high=%d [%d]\n", __FUNCTION__, 142203b705cfSriastradh kgem->aperture_low, kgem->aperture_low / (1024*1024), 142303b705cfSriastradh kgem->aperture_high, kgem->aperture_high / (1024*1024))); 142403b705cfSriastradh 14259a906b70Schristos kgem->aperture_mappable = 256 * 1024 * 1024; 14269a906b70Schristos if (dev != NULL) 14279a906b70Schristos kgem->aperture_mappable = agp_aperture_size(dev, gen); 142803b705cfSriastradh if (kgem->aperture_mappable == 0 || 142903b705cfSriastradh kgem->aperture_mappable > aperture.aper_size) 143003b705cfSriastradh kgem->aperture_mappable = aperture.aper_size; 143103b705cfSriastradh DBG(("%s: aperture mappable=%d [%d MiB]\n", __FUNCTION__, 143203b705cfSriastradh kgem->aperture_mappable, kgem->aperture_mappable / (1024*1024))); 143303b705cfSriastradh 14349a906b70Schristos kgem->aperture_fenceable = MIN(256*1024*1024, kgem->aperture_mappable); 14359a906b70Schristos DBG(("%s: aperture fenceable=%d [%d MiB]\n", __FUNCTION__, 14369a906b70Schristos kgem->aperture_fenceable, kgem->aperture_fenceable / (1024*1024))); 14379a906b70Schristos 143803b705cfSriastradh kgem->buffer_size = 64 * 1024; 143903b705cfSriastradh while (kgem->buffer_size < kgem->aperture_mappable >> 10) 144003b705cfSriastradh kgem->buffer_size *= 2; 144103b705cfSriastradh if (kgem->buffer_size >> 12 > kgem->half_cpu_cache_pages) 144203b705cfSriastradh kgem->buffer_size = kgem->half_cpu_cache_pages << 12; 144303b705cfSriastradh kgem->buffer_size = 1 << __fls(kgem->buffer_size); 144403b705cfSriastradh DBG(("%s: buffer size=%d [%d KiB]\n", __FUNCTION__, 144503b705cfSriastradh kgem->buffer_size, kgem->buffer_size / 1024)); 144603b705cfSriastradh assert(kgem->buffer_size); 144703b705cfSriastradh 144803b705cfSriastradh kgem->max_object_size = 3 * (kgem->aperture_high >> 12) << 10; 144903b705cfSriastradh kgem->max_gpu_size = kgem->max_object_size; 145003b705cfSriastradh if (!kgem->has_llc && kgem->max_gpu_size > MAX_CACHE_SIZE) 145103b705cfSriastradh kgem->max_gpu_size = MAX_CACHE_SIZE; 145203b705cfSriastradh 145303b705cfSriastradh totalram = total_ram_size(); 145403b705cfSriastradh if (totalram == 0) { 145503b705cfSriastradh DBG(("%s: total ram size unknown, assuming maximum of total aperture\n", 145603b705cfSriastradh __FUNCTION__)); 145703b705cfSriastradh totalram = kgem->aperture_total; 145803b705cfSriastradh } 145903b705cfSriastradh DBG(("%s: total ram=%ld\n", __FUNCTION__, (long)totalram)); 146003b705cfSriastradh if (kgem->max_object_size > totalram / 2) 146103b705cfSriastradh kgem->max_object_size = totalram / 2; 146203b705cfSriastradh if (kgem->max_gpu_size > totalram / 4) 146303b705cfSriastradh kgem->max_gpu_size = totalram / 4; 146403b705cfSriastradh 14659a906b70Schristos if (kgem->aperture_high > totalram / 2) { 14669a906b70Schristos kgem->aperture_high = totalram / 2; 14679a906b70Schristos kgem->aperture_low = kgem->aperture_high / 4; 14689a906b70Schristos DBG(("%s: reduced aperture watermaks to fit into ram; low=%d [%d], high=%d [%d]\n", __FUNCTION__, 14699a906b70Schristos kgem->aperture_low, kgem->aperture_low / (1024*1024), 14709a906b70Schristos kgem->aperture_high, kgem->aperture_high / (1024*1024))); 14719a906b70Schristos } 14729a906b70Schristos 147303b705cfSriastradh kgem->max_cpu_size = kgem->max_object_size; 147403b705cfSriastradh 147503b705cfSriastradh half_gpu_max = kgem->max_gpu_size / 2; 147603b705cfSriastradh kgem->max_copy_tile_size = (MAX_CACHE_SIZE + 1)/2; 147703b705cfSriastradh if (kgem->max_copy_tile_size > half_gpu_max) 147803b705cfSriastradh kgem->max_copy_tile_size = half_gpu_max; 147903b705cfSriastradh 148003b705cfSriastradh if (kgem->has_llc) 148103b705cfSriastradh kgem->max_upload_tile_size = kgem->max_copy_tile_size; 148203b705cfSriastradh else 14839a906b70Schristos kgem->max_upload_tile_size = kgem->aperture_fenceable / 4; 148403b705cfSriastradh if (kgem->max_upload_tile_size > half_gpu_max) 148503b705cfSriastradh kgem->max_upload_tile_size = half_gpu_max; 148603b705cfSriastradh if (kgem->max_upload_tile_size > kgem->aperture_high/2) 148703b705cfSriastradh kgem->max_upload_tile_size = kgem->aperture_high/2; 148803b705cfSriastradh if (kgem->max_upload_tile_size > kgem->aperture_low) 148903b705cfSriastradh kgem->max_upload_tile_size = kgem->aperture_low; 149003b705cfSriastradh if (kgem->max_upload_tile_size < 16*PAGE_SIZE) 149103b705cfSriastradh kgem->max_upload_tile_size = 16*PAGE_SIZE; 149203b705cfSriastradh 149303b705cfSriastradh kgem->large_object_size = MAX_CACHE_SIZE; 149403b705cfSriastradh if (kgem->large_object_size > half_gpu_max) 149503b705cfSriastradh kgem->large_object_size = half_gpu_max; 149603b705cfSriastradh if (kgem->max_copy_tile_size > kgem->aperture_high/2) 149703b705cfSriastradh kgem->max_copy_tile_size = kgem->aperture_high/2; 149803b705cfSriastradh if (kgem->max_copy_tile_size > kgem->aperture_low) 149903b705cfSriastradh kgem->max_copy_tile_size = kgem->aperture_low; 150003b705cfSriastradh if (kgem->max_copy_tile_size < 16*PAGE_SIZE) 150103b705cfSriastradh kgem->max_copy_tile_size = 16*PAGE_SIZE; 150203b705cfSriastradh 150303b705cfSriastradh if (kgem->has_llc | kgem->has_caching | kgem->has_userptr) { 150403b705cfSriastradh if (kgem->large_object_size > kgem->max_cpu_size) 150503b705cfSriastradh kgem->large_object_size = kgem->max_cpu_size; 150603b705cfSriastradh } else 150703b705cfSriastradh kgem->max_cpu_size = 0; 150803b705cfSriastradh if (DBG_NO_CPU) 150903b705cfSriastradh kgem->max_cpu_size = 0; 151003b705cfSriastradh 151103b705cfSriastradh DBG(("%s: maximum object size=%d\n", 151203b705cfSriastradh __FUNCTION__, kgem->max_object_size)); 151303b705cfSriastradh DBG(("%s: large object thresold=%d\n", 151403b705cfSriastradh __FUNCTION__, kgem->large_object_size)); 151503b705cfSriastradh DBG(("%s: max object sizes (gpu=%d, cpu=%d, tile upload=%d, copy=%d)\n", 151603b705cfSriastradh __FUNCTION__, 151703b705cfSriastradh kgem->max_gpu_size, kgem->max_cpu_size, 151803b705cfSriastradh kgem->max_upload_tile_size, kgem->max_copy_tile_size)); 151903b705cfSriastradh 152003b705cfSriastradh /* Convert the aperture thresholds to pages */ 15219a906b70Schristos kgem->aperture_mappable /= PAGE_SIZE; 15229a906b70Schristos kgem->aperture_fenceable /= PAGE_SIZE; 152303b705cfSriastradh kgem->aperture_low /= PAGE_SIZE; 152403b705cfSriastradh kgem->aperture_high /= PAGE_SIZE; 15259a906b70Schristos kgem->aperture_total /= PAGE_SIZE; 152603b705cfSriastradh 152703b705cfSriastradh kgem->fence_max = gem_param(kgem, I915_PARAM_NUM_FENCES_AVAIL) - 2; 152803b705cfSriastradh if ((int)kgem->fence_max < 0) 152903b705cfSriastradh kgem->fence_max = 5; /* minimum safe value for all hw */ 153003b705cfSriastradh DBG(("%s: max fences=%d\n", __FUNCTION__, kgem->fence_max)); 153103b705cfSriastradh 153203b705cfSriastradh kgem->batch_flags_base = 0; 153303b705cfSriastradh if (kgem->has_no_reloc) 153403b705cfSriastradh kgem->batch_flags_base |= LOCAL_I915_EXEC_NO_RELOC; 153503b705cfSriastradh if (kgem->has_handle_lut) 153603b705cfSriastradh kgem->batch_flags_base |= LOCAL_I915_EXEC_HANDLE_LUT; 153703b705cfSriastradh if (kgem->has_pinned_batches) 153803b705cfSriastradh kgem->batch_flags_base |= LOCAL_I915_EXEC_IS_PINNED; 153903b705cfSriastradh 154003b705cfSriastradh kgem_init_swizzling(kgem); 154103b705cfSriastradh} 154203b705cfSriastradh 154303b705cfSriastradh/* XXX hopefully a good approximation */ 15449a906b70Schristosstatic uint32_t kgem_get_unique_id(struct kgem *kgem) 154503b705cfSriastradh{ 154603b705cfSriastradh uint32_t id; 154703b705cfSriastradh id = ++kgem->unique_id; 154803b705cfSriastradh if (id == 0) 154903b705cfSriastradh id = ++kgem->unique_id; 155003b705cfSriastradh return id; 155103b705cfSriastradh} 155203b705cfSriastradh 155303b705cfSriastradhinline static uint32_t kgem_pitch_alignment(struct kgem *kgem, unsigned flags) 155403b705cfSriastradh{ 155503b705cfSriastradh if (flags & CREATE_PRIME) 155603b705cfSriastradh return 256; 155703b705cfSriastradh if (flags & CREATE_SCANOUT) 155803b705cfSriastradh return 64; 15599a906b70Schristos return 8; 156003b705cfSriastradh} 156103b705cfSriastradh 15629a906b70Schristosvoid kgem_get_tile_size(struct kgem *kgem, int tiling, int pitch, 156303b705cfSriastradh int *tile_width, int *tile_height, int *tile_size) 156403b705cfSriastradh{ 156503b705cfSriastradh if (kgem->gen <= 030) { 156603b705cfSriastradh if (tiling) { 156703b705cfSriastradh if (kgem->gen < 030) { 156803b705cfSriastradh *tile_width = 128; 156903b705cfSriastradh *tile_height = 16; 157003b705cfSriastradh *tile_size = 2048; 157103b705cfSriastradh } else { 157203b705cfSriastradh *tile_width = 512; 157303b705cfSriastradh *tile_height = 8; 157403b705cfSriastradh *tile_size = 4096; 157503b705cfSriastradh } 157603b705cfSriastradh } else { 157703b705cfSriastradh *tile_width = 1; 157803b705cfSriastradh *tile_height = 1; 157903b705cfSriastradh *tile_size = 1; 158003b705cfSriastradh } 158103b705cfSriastradh } else switch (tiling) { 158203b705cfSriastradh default: 158303b705cfSriastradh case I915_TILING_NONE: 158403b705cfSriastradh *tile_width = 1; 158503b705cfSriastradh *tile_height = 1; 158603b705cfSriastradh *tile_size = 1; 158703b705cfSriastradh break; 158803b705cfSriastradh case I915_TILING_X: 158903b705cfSriastradh *tile_width = 512; 159003b705cfSriastradh *tile_height = 8; 159103b705cfSriastradh *tile_size = 4096; 159203b705cfSriastradh break; 159303b705cfSriastradh case I915_TILING_Y: 159403b705cfSriastradh *tile_width = 128; 159503b705cfSriastradh *tile_height = 32; 159603b705cfSriastradh *tile_size = 4096; 159703b705cfSriastradh break; 159803b705cfSriastradh } 15999a906b70Schristos 16009a906b70Schristos /* Force offset alignment to tile-row */ 16019a906b70Schristos if (tiling && kgem->gen < 033) 16029a906b70Schristos *tile_width = pitch; 160303b705cfSriastradh} 160403b705cfSriastradh 160503b705cfSriastradhstatic uint32_t kgem_surface_size(struct kgem *kgem, 160603b705cfSriastradh bool relaxed_fencing, 160703b705cfSriastradh unsigned flags, 160803b705cfSriastradh uint32_t width, 160903b705cfSriastradh uint32_t height, 161003b705cfSriastradh uint32_t bpp, 161103b705cfSriastradh uint32_t tiling, 161203b705cfSriastradh uint32_t *pitch) 161303b705cfSriastradh{ 161403b705cfSriastradh uint32_t tile_width, tile_height; 161503b705cfSriastradh uint32_t size; 161603b705cfSriastradh 161703b705cfSriastradh assert(width <= MAXSHORT); 161803b705cfSriastradh assert(height <= MAXSHORT); 161903b705cfSriastradh assert(bpp >= 8); 162003b705cfSriastradh 162103b705cfSriastradh if (kgem->gen <= 030) { 162203b705cfSriastradh if (tiling) { 162303b705cfSriastradh if (kgem->gen < 030) { 162403b705cfSriastradh tile_width = 128; 16259a906b70Schristos tile_height = 16; 162603b705cfSriastradh } else { 162703b705cfSriastradh tile_width = 512; 16289a906b70Schristos tile_height = 8; 162903b705cfSriastradh } 163003b705cfSriastradh } else { 163103b705cfSriastradh tile_width = 2 * bpp >> 3; 163203b705cfSriastradh tile_width = ALIGN(tile_width, 163303b705cfSriastradh kgem_pitch_alignment(kgem, flags)); 16349a906b70Schristos tile_height = 1; 163503b705cfSriastradh } 163603b705cfSriastradh } else switch (tiling) { 163703b705cfSriastradh default: 163803b705cfSriastradh case I915_TILING_NONE: 163903b705cfSriastradh tile_width = 2 * bpp >> 3; 164003b705cfSriastradh tile_width = ALIGN(tile_width, 164103b705cfSriastradh kgem_pitch_alignment(kgem, flags)); 16429a906b70Schristos tile_height = 1; 164303b705cfSriastradh break; 164403b705cfSriastradh 164503b705cfSriastradh case I915_TILING_X: 164603b705cfSriastradh tile_width = 512; 16479a906b70Schristos tile_height = 8; 164803b705cfSriastradh break; 164903b705cfSriastradh case I915_TILING_Y: 165003b705cfSriastradh tile_width = 128; 16519a906b70Schristos tile_height = 32; 165203b705cfSriastradh break; 165303b705cfSriastradh } 16549a906b70Schristos /* XXX align to an even tile row */ 16559a906b70Schristos if (!kgem->has_relaxed_fencing) 16569a906b70Schristos tile_height *= 2; 165703b705cfSriastradh 165803b705cfSriastradh *pitch = ALIGN(width * bpp / 8, tile_width); 165903b705cfSriastradh height = ALIGN(height, tile_height); 16609a906b70Schristos DBG(("%s: tile_width=%d, tile_height=%d => aligned pitch=%d, height=%d\n", 16619a906b70Schristos __FUNCTION__, tile_width, tile_height, *pitch, height)); 16629a906b70Schristos 166303b705cfSriastradh if (kgem->gen >= 040) 166403b705cfSriastradh return PAGE_ALIGN(*pitch * height); 166503b705cfSriastradh 166603b705cfSriastradh /* If it is too wide for the blitter, don't even bother. */ 166703b705cfSriastradh if (tiling != I915_TILING_NONE) { 16689a906b70Schristos if (*pitch > 8192) { 16699a906b70Schristos DBG(("%s: too wide for tiled surface (pitch=%d, limit=%d)\n", 16709a906b70Schristos __FUNCTION__, *pitch, 8192)); 167103b705cfSriastradh return 0; 16729a906b70Schristos } 167303b705cfSriastradh 167403b705cfSriastradh for (size = tile_width; size < *pitch; size <<= 1) 167503b705cfSriastradh ; 167603b705cfSriastradh *pitch = size; 167703b705cfSriastradh } else { 16789a906b70Schristos if (*pitch >= 32768) { 16799a906b70Schristos DBG(("%s: too wide for linear surface (pitch=%d, limit=%d)\n", 16809a906b70Schristos __FUNCTION__, *pitch, 32767)); 168103b705cfSriastradh return 0; 16829a906b70Schristos } 168303b705cfSriastradh } 168403b705cfSriastradh 168503b705cfSriastradh size = *pitch * height; 168603b705cfSriastradh if (relaxed_fencing || tiling == I915_TILING_NONE) 168703b705cfSriastradh return PAGE_ALIGN(size); 168803b705cfSriastradh 16899a906b70Schristos /* We need to allocate a pot fence region for a tiled buffer. */ 169003b705cfSriastradh if (kgem->gen < 030) 169103b705cfSriastradh tile_width = 512 * 1024; 169203b705cfSriastradh else 169303b705cfSriastradh tile_width = 1024 * 1024; 169403b705cfSriastradh while (tile_width < size) 169503b705cfSriastradh tile_width *= 2; 169603b705cfSriastradh return tile_width; 169703b705cfSriastradh} 169803b705cfSriastradh 16999a906b70Schristosbool kgem_check_surface_size(struct kgem *kgem, 17009a906b70Schristos uint32_t width, 17019a906b70Schristos uint32_t height, 17029a906b70Schristos uint32_t bpp, 17039a906b70Schristos uint32_t tiling, 17049a906b70Schristos uint32_t pitch, 17059a906b70Schristos uint32_t size) 17069a906b70Schristos{ 17079a906b70Schristos uint32_t min_size, min_pitch; 17089a906b70Schristos int tile_width, tile_height, tile_size; 17099a906b70Schristos 17109a906b70Schristos DBG(("%s(width=%d, height=%d, bpp=%d, tiling=%d, pitch=%d, size=%d)\n", 17119a906b70Schristos __FUNCTION__, width, height, bpp, tiling, pitch, size)); 17129a906b70Schristos 17139a906b70Schristos if (pitch & 3) 17149a906b70Schristos return false; 17159a906b70Schristos 17169a906b70Schristos min_size = kgem_surface_size(kgem, kgem->has_relaxed_fencing, 0, 17179a906b70Schristos width, height, bpp, tiling, 17189a906b70Schristos &min_pitch); 17199a906b70Schristos 17209a906b70Schristos DBG(("%s: min_pitch=%d, min_size=%d\n", __FUNCTION__, min_pitch, min_size)); 17219a906b70Schristos 17229a906b70Schristos if (size < min_size) 17239a906b70Schristos return false; 17249a906b70Schristos 17259a906b70Schristos if (pitch < min_pitch) 17269a906b70Schristos return false; 17279a906b70Schristos 17289a906b70Schristos kgem_get_tile_size(kgem, tiling, min_pitch, 17299a906b70Schristos &tile_width, &tile_height, &tile_size); 17309a906b70Schristos 17319a906b70Schristos DBG(("%s: tile_width=%d, tile_size=%d\n", __FUNCTION__, tile_width, tile_size)); 17329a906b70Schristos if (pitch & (tile_width - 1)) 17339a906b70Schristos return false; 17349a906b70Schristos if (size & (tile_size - 1)) 17359a906b70Schristos return false; 17369a906b70Schristos 17379a906b70Schristos return true; 17389a906b70Schristos} 17399a906b70Schristos 174003b705cfSriastradhstatic uint32_t kgem_aligned_height(struct kgem *kgem, 174103b705cfSriastradh uint32_t height, uint32_t tiling) 174203b705cfSriastradh{ 174303b705cfSriastradh uint32_t tile_height; 174403b705cfSriastradh 174503b705cfSriastradh if (kgem->gen <= 030) { 17469a906b70Schristos tile_height = tiling ? kgem->gen < 030 ? 16 : 8 : 1; 174703b705cfSriastradh } else switch (tiling) { 174803b705cfSriastradh /* XXX align to an even tile row */ 174903b705cfSriastradh default: 175003b705cfSriastradh case I915_TILING_NONE: 175103b705cfSriastradh tile_height = 1; 175203b705cfSriastradh break; 175303b705cfSriastradh case I915_TILING_X: 17549a906b70Schristos tile_height = 8; 175503b705cfSriastradh break; 175603b705cfSriastradh case I915_TILING_Y: 17579a906b70Schristos tile_height = 32; 175803b705cfSriastradh break; 175903b705cfSriastradh } 176003b705cfSriastradh 17619a906b70Schristos /* XXX align to an even tile row */ 17629a906b70Schristos if (!kgem->has_relaxed_fencing) 17639a906b70Schristos tile_height *= 2; 17649a906b70Schristos 176503b705cfSriastradh return ALIGN(height, tile_height); 176603b705cfSriastradh} 176703b705cfSriastradh 176803b705cfSriastradhstatic struct drm_i915_gem_exec_object2 * 176903b705cfSriastradhkgem_add_handle(struct kgem *kgem, struct kgem_bo *bo) 177003b705cfSriastradh{ 177103b705cfSriastradh struct drm_i915_gem_exec_object2 *exec; 177203b705cfSriastradh 177303b705cfSriastradh DBG(("%s: handle=%d, index=%d\n", 177403b705cfSriastradh __FUNCTION__, bo->handle, kgem->nexec)); 177503b705cfSriastradh 177603b705cfSriastradh assert(kgem->nexec < ARRAY_SIZE(kgem->exec)); 177703b705cfSriastradh bo->target_handle = kgem->has_handle_lut ? kgem->nexec : bo->handle; 177803b705cfSriastradh exec = memset(&kgem->exec[kgem->nexec++], 0, sizeof(*exec)); 177903b705cfSriastradh exec->handle = bo->handle; 178003b705cfSriastradh exec->offset = bo->presumed_offset; 178103b705cfSriastradh 178203b705cfSriastradh kgem->aperture += num_pages(bo); 178303b705cfSriastradh 178403b705cfSriastradh return exec; 178503b705cfSriastradh} 178603b705cfSriastradh 178703b705cfSriastradhstatic void kgem_add_bo(struct kgem *kgem, struct kgem_bo *bo) 178803b705cfSriastradh{ 17899a906b70Schristos assert(bo->refcnt); 17909a906b70Schristos assert(bo->proxy == NULL); 17919a906b70Schristos 179203b705cfSriastradh bo->exec = kgem_add_handle(kgem, bo); 179303b705cfSriastradh bo->rq = MAKE_REQUEST(kgem->next_request, kgem->ring); 179403b705cfSriastradh 179503b705cfSriastradh list_move_tail(&bo->request, &kgem->next_request->buffers); 17969a906b70Schristos if (bo->io && !list_is_empty(&bo->list)) 17979a906b70Schristos list_move(&bo->list, &kgem->batch_buffers); 179803b705cfSriastradh 179903b705cfSriastradh /* XXX is it worth working around gcc here? */ 180003b705cfSriastradh kgem->flush |= bo->flush; 180103b705cfSriastradh} 180203b705cfSriastradh 180303b705cfSriastradhstatic uint32_t kgem_end_batch(struct kgem *kgem) 180403b705cfSriastradh{ 180503b705cfSriastradh kgem->batch[kgem->nbatch++] = MI_BATCH_BUFFER_END; 180603b705cfSriastradh if (kgem->nbatch & 1) 180703b705cfSriastradh kgem->batch[kgem->nbatch++] = MI_NOOP; 180803b705cfSriastradh 180903b705cfSriastradh return kgem->nbatch; 181003b705cfSriastradh} 181103b705cfSriastradh 181203b705cfSriastradhstatic void kgem_fixup_self_relocs(struct kgem *kgem, struct kgem_bo *bo) 181303b705cfSriastradh{ 181403b705cfSriastradh int n; 181503b705cfSriastradh 181603b705cfSriastradh assert(kgem->nreloc__self <= 256); 181703b705cfSriastradh if (kgem->nreloc__self == 0) 181803b705cfSriastradh return; 181903b705cfSriastradh 182003b705cfSriastradh for (n = 0; n < kgem->nreloc__self; n++) { 182103b705cfSriastradh int i = kgem->reloc__self[n]; 182203b705cfSriastradh assert(kgem->reloc[i].target_handle == ~0U); 182303b705cfSriastradh kgem->reloc[i].target_handle = bo->target_handle; 182403b705cfSriastradh kgem->reloc[i].presumed_offset = bo->presumed_offset; 182503b705cfSriastradh kgem->batch[kgem->reloc[i].offset/sizeof(kgem->batch[0])] = 182603b705cfSriastradh kgem->reloc[i].delta + bo->presumed_offset; 182703b705cfSriastradh } 182803b705cfSriastradh 182903b705cfSriastradh if (n == 256) { 183003b705cfSriastradh for (n = kgem->reloc__self[255]; n < kgem->nreloc; n++) { 183103b705cfSriastradh if (kgem->reloc[n].target_handle == ~0U) { 183203b705cfSriastradh kgem->reloc[n].target_handle = bo->target_handle; 183303b705cfSriastradh kgem->reloc[n].presumed_offset = bo->presumed_offset; 183403b705cfSriastradh kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = 183503b705cfSriastradh kgem->reloc[n].delta + bo->presumed_offset; 183603b705cfSriastradh } 183703b705cfSriastradh } 183803b705cfSriastradh 183903b705cfSriastradh } 184003b705cfSriastradh} 184103b705cfSriastradh 184203b705cfSriastradhstatic void kgem_bo_binding_free(struct kgem *kgem, struct kgem_bo *bo) 184303b705cfSriastradh{ 184403b705cfSriastradh struct kgem_bo_binding *b; 184503b705cfSriastradh 184603b705cfSriastradh b = bo->binding.next; 184703b705cfSriastradh while (b) { 184803b705cfSriastradh struct kgem_bo_binding *next = b->next; 18499a906b70Schristos free(b); 185003b705cfSriastradh b = next; 185103b705cfSriastradh } 185203b705cfSriastradh} 185303b705cfSriastradh 18549a906b70Schristosstatic void kgem_bo_rmfb(struct kgem *kgem, struct kgem_bo *bo) 185503b705cfSriastradh{ 18569a906b70Schristos if (bo->scanout && bo->delta) { 18579a906b70Schristos DBG(("%s: releasing fb=%d for handle=%d\n", 18589a906b70Schristos __FUNCTION__, bo->delta, bo->handle)); 18599a906b70Schristos /* XXX will leak if we are not DRM_MASTER. *shrug* */ 18609a906b70Schristos do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &bo->delta); 18619a906b70Schristos bo->delta = 0; 186203b705cfSriastradh } 186303b705cfSriastradh} 186403b705cfSriastradh 186503b705cfSriastradhstatic void kgem_bo_free(struct kgem *kgem, struct kgem_bo *bo) 186603b705cfSriastradh{ 18679a906b70Schristos DBG(("%s: handle=%d, size=%d\n", __FUNCTION__, bo->handle, bytes(bo))); 186803b705cfSriastradh assert(bo->refcnt == 0); 186903b705cfSriastradh assert(bo->proxy == NULL); 187003b705cfSriastradh assert(bo->exec == NULL); 187103b705cfSriastradh assert(!bo->snoop || bo->rq == NULL); 187203b705cfSriastradh 187303b705cfSriastradh#ifdef DEBUG_MEMORY 187403b705cfSriastradh kgem->debug_memory.bo_allocs--; 187503b705cfSriastradh kgem->debug_memory.bo_bytes -= bytes(bo); 187603b705cfSriastradh#endif 187703b705cfSriastradh 187803b705cfSriastradh kgem_bo_binding_free(kgem, bo); 18799a906b70Schristos kgem_bo_rmfb(kgem, bo); 188003b705cfSriastradh 18819a906b70Schristos if (IS_USER_MAP(bo->map__cpu)) { 188203b705cfSriastradh assert(bo->rq == NULL); 188303b705cfSriastradh assert(!__kgem_busy(kgem, bo->handle)); 18849a906b70Schristos assert(MAP(bo->map__cpu) != bo || bo->io || bo->flush); 188503b705cfSriastradh if (!(bo->io || bo->flush)) { 188603b705cfSriastradh DBG(("%s: freeing snooped base\n", __FUNCTION__)); 18879a906b70Schristos assert(bo != MAP(bo->map__cpu)); 18889a906b70Schristos free(MAP(bo->map__cpu)); 188903b705cfSriastradh } 18909a906b70Schristos bo->map__cpu = NULL; 18919a906b70Schristos } 18929a906b70Schristos 18939a906b70Schristos DBG(("%s: releasing %p:%p vma for handle=%d, count=%d\n", 18949a906b70Schristos __FUNCTION__, bo->map__gtt, bo->map__cpu, 18959a906b70Schristos bo->handle, list_is_empty(&bo->vma) ? 0 : kgem->vma[bo->map__gtt == NULL].count)); 18969a906b70Schristos 18979a906b70Schristos if (!list_is_empty(&bo->vma)) { 18989a906b70Schristos _list_del(&bo->vma); 18999a906b70Schristos kgem->vma[bo->map__gtt == NULL].count--; 190003b705cfSriastradh } 19019a906b70Schristos 19029a906b70Schristos if (bo->map__gtt) 19039a906b70Schristos munmap(MAP(bo->map__gtt), bytes(bo)); 19049a906b70Schristos if (bo->map__cpu) 19059a906b70Schristos munmap(MAP(bo->map__cpu), bytes(bo)); 190603b705cfSriastradh 190703b705cfSriastradh _list_del(&bo->list); 190803b705cfSriastradh _list_del(&bo->request); 190903b705cfSriastradh gem_close(kgem->fd, bo->handle); 191003b705cfSriastradh 19119a906b70Schristos if (!bo->io && !DBG_NO_MALLOC_CACHE) { 191203b705cfSriastradh *(struct kgem_bo **)bo = __kgem_freed_bo; 191303b705cfSriastradh __kgem_freed_bo = bo; 191403b705cfSriastradh } else 191503b705cfSriastradh free(bo); 191603b705cfSriastradh} 191703b705cfSriastradh 191803b705cfSriastradhinline static void kgem_bo_move_to_inactive(struct kgem *kgem, 191903b705cfSriastradh struct kgem_bo *bo) 192003b705cfSriastradh{ 192103b705cfSriastradh DBG(("%s: moving handle=%d to inactive\n", __FUNCTION__, bo->handle)); 192203b705cfSriastradh 192303b705cfSriastradh assert(bo->refcnt == 0); 192403b705cfSriastradh assert(bo->reusable); 192503b705cfSriastradh assert(bo->rq == NULL); 192603b705cfSriastradh assert(bo->exec == NULL); 192703b705cfSriastradh assert(bo->domain != DOMAIN_GPU); 192803b705cfSriastradh assert(!bo->proxy); 192903b705cfSriastradh assert(!bo->io); 193003b705cfSriastradh assert(!bo->scanout); 193103b705cfSriastradh assert(!bo->snoop); 193203b705cfSriastradh assert(!bo->flush); 193303b705cfSriastradh assert(!bo->needs_flush); 193403b705cfSriastradh assert(list_is_empty(&bo->vma)); 193503b705cfSriastradh assert_tiling(kgem, bo); 19369a906b70Schristos assert_cacheing(kgem, bo); 193703b705cfSriastradh ASSERT_IDLE(kgem, bo->handle); 193803b705cfSriastradh 193903b705cfSriastradh if (bucket(bo) >= NUM_CACHE_BUCKETS) { 19409a906b70Schristos if (bo->map__gtt) { 19419a906b70Schristos munmap(MAP(bo->map__gtt), bytes(bo)); 19429a906b70Schristos bo->map__gtt = NULL; 19439a906b70Schristos } 194403b705cfSriastradh 19459a906b70Schristos list_move(&bo->list, &kgem->large_inactive); 19469a906b70Schristos } else { 19479a906b70Schristos assert(bo->flush == false); 19489a906b70Schristos list_move(&bo->list, &kgem->inactive[bucket(bo)]); 19499a906b70Schristos if (bo->map__gtt) { 19509a906b70Schristos if (!kgem_bo_can_map(kgem, bo)) { 19519a906b70Schristos munmap(MAP(bo->map__gtt), bytes(bo)); 19529a906b70Schristos bo->map__gtt = NULL; 19539a906b70Schristos } 19549a906b70Schristos if (bo->map__gtt) { 19559a906b70Schristos list_add(&bo->vma, &kgem->vma[0].inactive[bucket(bo)]); 19569a906b70Schristos kgem->vma[0].count++; 19579a906b70Schristos } 195803b705cfSriastradh } 19599a906b70Schristos if (bo->map__cpu && !bo->map__gtt) { 19609a906b70Schristos list_add(&bo->vma, &kgem->vma[1].inactive[bucket(bo)]); 19619a906b70Schristos kgem->vma[1].count++; 196203b705cfSriastradh } 196303b705cfSriastradh } 19649a906b70Schristos 19659a906b70Schristos kgem->need_expire = true; 196603b705cfSriastradh} 196703b705cfSriastradh 196803b705cfSriastradhstatic struct kgem_bo *kgem_bo_replace_io(struct kgem_bo *bo) 196903b705cfSriastradh{ 197003b705cfSriastradh struct kgem_bo *base; 197103b705cfSriastradh 197203b705cfSriastradh if (!bo->io) 197303b705cfSriastradh return bo; 197403b705cfSriastradh 197503b705cfSriastradh assert(!bo->snoop); 19769a906b70Schristos if (__kgem_freed_bo) { 19779a906b70Schristos base = __kgem_freed_bo; 19789a906b70Schristos __kgem_freed_bo = *(struct kgem_bo **)base; 19799a906b70Schristos } else 19809a906b70Schristos base = malloc(sizeof(*base)); 198103b705cfSriastradh if (base) { 198203b705cfSriastradh DBG(("%s: transferring io handle=%d to bo\n", 198303b705cfSriastradh __FUNCTION__, bo->handle)); 198403b705cfSriastradh /* transfer the handle to a minimum bo */ 198503b705cfSriastradh memcpy(base, bo, sizeof(*base)); 198603b705cfSriastradh base->io = false; 198703b705cfSriastradh list_init(&base->list); 198803b705cfSriastradh list_replace(&bo->request, &base->request); 198903b705cfSriastradh list_replace(&bo->vma, &base->vma); 199003b705cfSriastradh free(bo); 199103b705cfSriastradh bo = base; 199203b705cfSriastradh } else 199303b705cfSriastradh bo->reusable = false; 199403b705cfSriastradh 199503b705cfSriastradh return bo; 199603b705cfSriastradh} 199703b705cfSriastradh 199803b705cfSriastradhinline static void kgem_bo_remove_from_inactive(struct kgem *kgem, 199903b705cfSriastradh struct kgem_bo *bo) 200003b705cfSriastradh{ 200103b705cfSriastradh DBG(("%s: removing handle=%d from inactive\n", __FUNCTION__, bo->handle)); 200203b705cfSriastradh 200303b705cfSriastradh list_del(&bo->list); 200403b705cfSriastradh assert(bo->rq == NULL); 200503b705cfSriastradh assert(bo->exec == NULL); 20069a906b70Schristos if (!list_is_empty(&bo->vma)) { 20079a906b70Schristos assert(bo->map__gtt || bo->map__cpu); 200803b705cfSriastradh list_del(&bo->vma); 20099a906b70Schristos kgem->vma[bo->map__gtt == NULL].count--; 201003b705cfSriastradh } 201103b705cfSriastradh} 201203b705cfSriastradh 201303b705cfSriastradhinline static void kgem_bo_remove_from_active(struct kgem *kgem, 201403b705cfSriastradh struct kgem_bo *bo) 201503b705cfSriastradh{ 201603b705cfSriastradh DBG(("%s: removing handle=%d from active\n", __FUNCTION__, bo->handle)); 201703b705cfSriastradh 201803b705cfSriastradh list_del(&bo->list); 201903b705cfSriastradh assert(bo->rq != NULL); 20209a906b70Schristos if (RQ(bo->rq) == (void *)kgem) { 20219a906b70Schristos assert(bo->exec == NULL); 202203b705cfSriastradh list_del(&bo->request); 20239a906b70Schristos } 202403b705cfSriastradh assert(list_is_empty(&bo->vma)); 202503b705cfSriastradh} 202603b705cfSriastradh 202703b705cfSriastradhstatic void _kgem_bo_delete_buffer(struct kgem *kgem, struct kgem_bo *bo) 202803b705cfSriastradh{ 202903b705cfSriastradh struct kgem_buffer *io = (struct kgem_buffer *)bo->proxy; 203003b705cfSriastradh 203103b705cfSriastradh DBG(("%s: size=%d, offset=%d, parent used=%d\n", 203203b705cfSriastradh __FUNCTION__, bo->size.bytes, bo->delta, io->used)); 203303b705cfSriastradh 203403b705cfSriastradh if (ALIGN(bo->delta + bo->size.bytes, UPLOAD_ALIGNMENT) == io->used) 203503b705cfSriastradh io->used = bo->delta; 203603b705cfSriastradh} 203703b705cfSriastradh 203803b705cfSriastradhstatic bool check_scanout_size(struct kgem *kgem, 203903b705cfSriastradh struct kgem_bo *bo, 204003b705cfSriastradh int width, int height) 204103b705cfSriastradh{ 204203b705cfSriastradh struct drm_mode_fb_cmd info; 204303b705cfSriastradh 204403b705cfSriastradh assert(bo->scanout); 204503b705cfSriastradh 204603b705cfSriastradh VG_CLEAR(info); 204703b705cfSriastradh info.fb_id = bo->delta; 204803b705cfSriastradh 20499a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_MODE_GETFB, &info)) 205003b705cfSriastradh return false; 205103b705cfSriastradh 205203b705cfSriastradh gem_close(kgem->fd, info.handle); 205303b705cfSriastradh 205403b705cfSriastradh if (width != info.width || height != info.height) { 205503b705cfSriastradh DBG(("%s: not using scanout %d (%dx%d), want (%dx%d)\n", 205603b705cfSriastradh __FUNCTION__, 205703b705cfSriastradh info.fb_id, info.width, info.height, 205803b705cfSriastradh width, height)); 205903b705cfSriastradh return false; 206003b705cfSriastradh } 206103b705cfSriastradh 206203b705cfSriastradh return true; 206303b705cfSriastradh} 206403b705cfSriastradh 206503b705cfSriastradhstatic void kgem_bo_move_to_scanout(struct kgem *kgem, struct kgem_bo *bo) 206603b705cfSriastradh{ 206703b705cfSriastradh assert(bo->refcnt == 0); 206803b705cfSriastradh assert(bo->scanout); 206903b705cfSriastradh assert(!bo->flush); 207003b705cfSriastradh assert(!bo->snoop); 207103b705cfSriastradh assert(!bo->io); 207203b705cfSriastradh 20739a906b70Schristos if (bo->purged) { /* for stolen fb */ 20749a906b70Schristos if (!bo->exec) { 20759a906b70Schristos DBG(("%s: discarding purged scanout - stolen?\n", 20769a906b70Schristos __FUNCTION__)); 20779a906b70Schristos kgem_bo_free(kgem, bo); 20789a906b70Schristos } 207903b705cfSriastradh return; 208003b705cfSriastradh } 208103b705cfSriastradh 208203b705cfSriastradh DBG(("%s: moving %d [fb %d] to scanout cache, active? %d\n", 208303b705cfSriastradh __FUNCTION__, bo->handle, bo->delta, bo->rq != NULL)); 208403b705cfSriastradh if (bo->rq) 208503b705cfSriastradh list_move_tail(&bo->list, &kgem->scanout); 208603b705cfSriastradh else 208703b705cfSriastradh list_move(&bo->list, &kgem->scanout); 20889a906b70Schristos 20899a906b70Schristos kgem->need_expire = true; 20909a906b70Schristos 209103b705cfSriastradh} 209203b705cfSriastradh 209303b705cfSriastradhstatic void kgem_bo_move_to_snoop(struct kgem *kgem, struct kgem_bo *bo) 209403b705cfSriastradh{ 209503b705cfSriastradh assert(bo->reusable); 20969a906b70Schristos assert(!bo->scanout); 209703b705cfSriastradh assert(!bo->flush); 209803b705cfSriastradh assert(!bo->needs_flush); 209903b705cfSriastradh assert(bo->refcnt == 0); 210003b705cfSriastradh assert(bo->exec == NULL); 210103b705cfSriastradh 21029a906b70Schristos if (DBG_NO_SNOOP_CACHE) { 21039a906b70Schristos kgem_bo_free(kgem, bo); 21049a906b70Schristos return; 21059a906b70Schristos } 21069a906b70Schristos 210703b705cfSriastradh if (num_pages(bo) > kgem->max_cpu_size >> 13) { 210803b705cfSriastradh DBG(("%s handle=%d discarding large CPU buffer (%d >%d pages)\n", 210903b705cfSriastradh __FUNCTION__, bo->handle, num_pages(bo), kgem->max_cpu_size >> 13)); 211003b705cfSriastradh kgem_bo_free(kgem, bo); 211103b705cfSriastradh return; 211203b705cfSriastradh } 211303b705cfSriastradh 211403b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 211503b705cfSriastradh assert(bo->rq == NULL); 211603b705cfSriastradh 211703b705cfSriastradh DBG(("%s: moving %d to snoop cachee\n", __FUNCTION__, bo->handle)); 211803b705cfSriastradh list_add(&bo->list, &kgem->snoop); 21199a906b70Schristos kgem->need_expire = true; 21209a906b70Schristos} 21219a906b70Schristos 21229a906b70Schristosstatic bool kgem_bo_move_to_cache(struct kgem *kgem, struct kgem_bo *bo) 21239a906b70Schristos{ 21249a906b70Schristos bool retired = false; 21259a906b70Schristos 21269a906b70Schristos DBG(("%s: release handle=%d\n", __FUNCTION__, bo->handle)); 21279a906b70Schristos 21289a906b70Schristos if (bo->prime) { 21299a906b70Schristos DBG(("%s: discarding imported prime handle=%d\n", 21309a906b70Schristos __FUNCTION__, bo->handle)); 21319a906b70Schristos kgem_bo_free(kgem, bo); 21329a906b70Schristos } else if (bo->snoop) { 21339a906b70Schristos kgem_bo_move_to_snoop(kgem, bo); 21349a906b70Schristos } else if (bo->scanout) { 21359a906b70Schristos kgem_bo_move_to_scanout(kgem, bo); 21369a906b70Schristos } else if ((bo = kgem_bo_replace_io(bo))->reusable && 21379a906b70Schristos kgem_bo_set_purgeable(kgem, bo)) { 21389a906b70Schristos kgem_bo_move_to_inactive(kgem, bo); 21399a906b70Schristos retired = true; 21409a906b70Schristos } else 21419a906b70Schristos kgem_bo_free(kgem, bo); 21429a906b70Schristos 21439a906b70Schristos return retired; 214403b705cfSriastradh} 214503b705cfSriastradh 214603b705cfSriastradhstatic struct kgem_bo * 214703b705cfSriastradhsearch_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags) 214803b705cfSriastradh{ 214903b705cfSriastradh struct kgem_bo *bo, *first = NULL; 215003b705cfSriastradh 215103b705cfSriastradh DBG(("%s: num_pages=%d, flags=%x\n", __FUNCTION__, num_pages, flags)); 215203b705cfSriastradh 215303b705cfSriastradh if ((kgem->has_caching | kgem->has_userptr) == 0) 215403b705cfSriastradh return NULL; 215503b705cfSriastradh 215603b705cfSriastradh if (list_is_empty(&kgem->snoop)) { 215703b705cfSriastradh DBG(("%s: inactive and cache empty\n", __FUNCTION__)); 215803b705cfSriastradh if (!__kgem_throttle_retire(kgem, flags)) { 215903b705cfSriastradh DBG(("%s: nothing retired\n", __FUNCTION__)); 216003b705cfSriastradh return NULL; 216103b705cfSriastradh } 216203b705cfSriastradh } 216303b705cfSriastradh 216403b705cfSriastradh list_for_each_entry(bo, &kgem->snoop, list) { 216503b705cfSriastradh assert(bo->refcnt == 0); 216603b705cfSriastradh assert(bo->snoop); 216703b705cfSriastradh assert(!bo->scanout); 216803b705cfSriastradh assert(!bo->purged); 216903b705cfSriastradh assert(bo->proxy == NULL); 217003b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 217103b705cfSriastradh assert(bo->rq == NULL); 217203b705cfSriastradh assert(bo->exec == NULL); 217303b705cfSriastradh 217403b705cfSriastradh if (num_pages > num_pages(bo)) 217503b705cfSriastradh continue; 217603b705cfSriastradh 217703b705cfSriastradh if (num_pages(bo) > 2*num_pages) { 217803b705cfSriastradh if (first == NULL) 217903b705cfSriastradh first = bo; 218003b705cfSriastradh continue; 218103b705cfSriastradh } 218203b705cfSriastradh 218303b705cfSriastradh list_del(&bo->list); 218403b705cfSriastradh bo->pitch = 0; 218503b705cfSriastradh bo->delta = 0; 218603b705cfSriastradh 218703b705cfSriastradh DBG((" %s: found handle=%d (num_pages=%d) in snoop cache\n", 218803b705cfSriastradh __FUNCTION__, bo->handle, num_pages(bo))); 218903b705cfSriastradh return bo; 219003b705cfSriastradh } 219103b705cfSriastradh 219203b705cfSriastradh if (first) { 219303b705cfSriastradh list_del(&first->list); 219403b705cfSriastradh first->pitch = 0; 219503b705cfSriastradh first->delta = 0; 219603b705cfSriastradh 219703b705cfSriastradh DBG((" %s: found handle=%d (num_pages=%d) in snoop cache\n", 219803b705cfSriastradh __FUNCTION__, first->handle, num_pages(first))); 219903b705cfSriastradh return first; 220003b705cfSriastradh } 220103b705cfSriastradh 220203b705cfSriastradh return NULL; 220303b705cfSriastradh} 220403b705cfSriastradh 220503b705cfSriastradhvoid kgem_bo_undo(struct kgem *kgem, struct kgem_bo *bo) 220603b705cfSriastradh{ 220703b705cfSriastradh if (kgem->nexec != 1 || bo->exec == NULL) 220803b705cfSriastradh return; 220903b705cfSriastradh 22109a906b70Schristos assert(bo); 221103b705cfSriastradh DBG(("%s: only handle in batch, discarding last operations for handle=%d\n", 221203b705cfSriastradh __FUNCTION__, bo->handle)); 221303b705cfSriastradh 221403b705cfSriastradh assert(bo->exec == &kgem->exec[0]); 221503b705cfSriastradh assert(kgem->exec[0].handle == bo->handle); 221603b705cfSriastradh assert(RQ(bo->rq) == kgem->next_request); 221703b705cfSriastradh 221803b705cfSriastradh bo->refcnt++; 221903b705cfSriastradh kgem_reset(kgem); 222003b705cfSriastradh bo->refcnt--; 22219a906b70Schristos 22229a906b70Schristos assert(kgem->nreloc == 0); 22239a906b70Schristos assert(kgem->nexec == 0); 22249a906b70Schristos assert(bo->exec == NULL); 222503b705cfSriastradh} 222603b705cfSriastradh 22279a906b70Schristosvoid kgem_bo_pair_undo(struct kgem *kgem, struct kgem_bo *a, struct kgem_bo *b) 222803b705cfSriastradh{ 22299a906b70Schristos if (kgem->nexec > 2) 22309a906b70Schristos return; 223103b705cfSriastradh 22329a906b70Schristos if (kgem->nexec == 1) { 22339a906b70Schristos if (a) 22349a906b70Schristos kgem_bo_undo(kgem, a); 22359a906b70Schristos if (b) 22369a906b70Schristos kgem_bo_undo(kgem, b); 22379a906b70Schristos return; 22389a906b70Schristos } 22399a906b70Schristos 22409a906b70Schristos if (a == NULL || b == NULL) 22419a906b70Schristos return; 22429a906b70Schristos if (a->exec == NULL || b->exec == NULL) 22439a906b70Schristos return; 22449a906b70Schristos 22459a906b70Schristos DBG(("%s: only handles in batch, discarding last operations for handle=%d and handle=%d\n", 22469a906b70Schristos __FUNCTION__, a->handle, b->handle)); 22479a906b70Schristos 22489a906b70Schristos assert(a->exec == &kgem->exec[0] || a->exec == &kgem->exec[1]); 22499a906b70Schristos assert(a->handle == kgem->exec[0].handle || a->handle == kgem->exec[1].handle); 22509a906b70Schristos assert(RQ(a->rq) == kgem->next_request); 22519a906b70Schristos assert(b->exec == &kgem->exec[0] || b->exec == &kgem->exec[1]); 22529a906b70Schristos assert(b->handle == kgem->exec[0].handle || b->handle == kgem->exec[1].handle); 22539a906b70Schristos assert(RQ(b->rq) == kgem->next_request); 22549a906b70Schristos 22559a906b70Schristos a->refcnt++; 22569a906b70Schristos b->refcnt++; 22579a906b70Schristos kgem_reset(kgem); 22589a906b70Schristos b->refcnt--; 22599a906b70Schristos a->refcnt--; 22609a906b70Schristos 22619a906b70Schristos assert(kgem->nreloc == 0); 22629a906b70Schristos assert(kgem->nexec == 0); 22639a906b70Schristos assert(a->exec == NULL); 22649a906b70Schristos assert(b->exec == NULL); 22659a906b70Schristos} 22669a906b70Schristos 22679a906b70Schristosstatic void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo) 22689a906b70Schristos{ 22699a906b70Schristos DBG(("%s: handle=%d, size=%d\n", __FUNCTION__, bo->handle, bytes(bo))); 22709a906b70Schristos 22719a906b70Schristos assert(list_is_empty(&bo->list)); 22729a906b70Schristos assert(bo->refcnt == 0); 22739a906b70Schristos assert(bo->proxy == NULL); 22749a906b70Schristos assert(bo->active_scanout == 0); 22759a906b70Schristos assert_tiling(kgem, bo); 22769a906b70Schristos 22779a906b70Schristos bo->binding.offset = 0; 227803b705cfSriastradh 227903b705cfSriastradh if (DBG_NO_CACHE) 228003b705cfSriastradh goto destroy; 228103b705cfSriastradh 22829a906b70Schristos if (bo->prime) 22839a906b70Schristos goto destroy; 22849a906b70Schristos 228503b705cfSriastradh if (bo->snoop && !bo->flush) { 228603b705cfSriastradh DBG(("%s: handle=%d is snooped\n", __FUNCTION__, bo->handle)); 228703b705cfSriastradh assert(bo->reusable); 228803b705cfSriastradh assert(list_is_empty(&bo->list)); 228903b705cfSriastradh if (bo->exec == NULL && bo->rq && !__kgem_busy(kgem, bo->handle)) 229003b705cfSriastradh __kgem_bo_clear_busy(bo); 229103b705cfSriastradh if (bo->rq == NULL) 229203b705cfSriastradh kgem_bo_move_to_snoop(kgem, bo); 229303b705cfSriastradh return; 229403b705cfSriastradh } 22959a906b70Schristos if (!IS_USER_MAP(bo->map__cpu)) 229603b705cfSriastradh bo->flush = false; 229703b705cfSriastradh 229803b705cfSriastradh if (bo->scanout) { 229903b705cfSriastradh kgem_bo_move_to_scanout(kgem, bo); 230003b705cfSriastradh return; 230103b705cfSriastradh } 230203b705cfSriastradh 230303b705cfSriastradh if (bo->io) 230403b705cfSriastradh bo = kgem_bo_replace_io(bo); 230503b705cfSriastradh if (!bo->reusable) { 230603b705cfSriastradh DBG(("%s: handle=%d, not reusable\n", 230703b705cfSriastradh __FUNCTION__, bo->handle)); 230803b705cfSriastradh goto destroy; 230903b705cfSriastradh } 231003b705cfSriastradh 231103b705cfSriastradh assert(list_is_empty(&bo->vma)); 231203b705cfSriastradh assert(list_is_empty(&bo->list)); 231303b705cfSriastradh assert(bo->flush == false); 231403b705cfSriastradh assert(bo->snoop == false); 231503b705cfSriastradh assert(bo->io == false); 231603b705cfSriastradh assert(bo->scanout == false); 23179a906b70Schristos assert_cacheing(kgem, bo); 231803b705cfSriastradh 231903b705cfSriastradh kgem_bo_undo(kgem, bo); 232003b705cfSriastradh assert(bo->refcnt == 0); 232103b705cfSriastradh 232203b705cfSriastradh if (bo->rq && bo->exec == NULL && !__kgem_busy(kgem, bo->handle)) 232303b705cfSriastradh __kgem_bo_clear_busy(bo); 232403b705cfSriastradh 232503b705cfSriastradh if (bo->rq) { 232603b705cfSriastradh struct list *cache; 232703b705cfSriastradh 232803b705cfSriastradh DBG(("%s: handle=%d -> active\n", __FUNCTION__, bo->handle)); 232903b705cfSriastradh if (bucket(bo) < NUM_CACHE_BUCKETS) 233003b705cfSriastradh cache = &kgem->active[bucket(bo)][bo->tiling]; 233103b705cfSriastradh else 233203b705cfSriastradh cache = &kgem->large; 233303b705cfSriastradh list_add(&bo->list, cache); 233403b705cfSriastradh return; 233503b705cfSriastradh } 233603b705cfSriastradh 233703b705cfSriastradh assert(bo->exec == NULL); 233803b705cfSriastradh assert(list_is_empty(&bo->request)); 233903b705cfSriastradh 23409a906b70Schristos if (bo->map__cpu == NULL || bucket(bo) >= NUM_CACHE_BUCKETS) { 234103b705cfSriastradh if (!kgem_bo_set_purgeable(kgem, bo)) 234203b705cfSriastradh goto destroy; 234303b705cfSriastradh 234403b705cfSriastradh if (!kgem->has_llc && bo->domain == DOMAIN_CPU) 234503b705cfSriastradh goto destroy; 234603b705cfSriastradh 234703b705cfSriastradh DBG(("%s: handle=%d, purged\n", 234803b705cfSriastradh __FUNCTION__, bo->handle)); 234903b705cfSriastradh } 235003b705cfSriastradh 235103b705cfSriastradh kgem_bo_move_to_inactive(kgem, bo); 235203b705cfSriastradh return; 235303b705cfSriastradh 235403b705cfSriastradhdestroy: 235503b705cfSriastradh if (!bo->exec) 235603b705cfSriastradh kgem_bo_free(kgem, bo); 235703b705cfSriastradh} 235803b705cfSriastradh 235903b705cfSriastradhstatic void kgem_bo_unref(struct kgem *kgem, struct kgem_bo *bo) 236003b705cfSriastradh{ 236103b705cfSriastradh assert(bo->refcnt); 236203b705cfSriastradh if (--bo->refcnt == 0) 236303b705cfSriastradh __kgem_bo_destroy(kgem, bo); 236403b705cfSriastradh} 236503b705cfSriastradh 236603b705cfSriastradhstatic void kgem_buffer_release(struct kgem *kgem, struct kgem_buffer *bo) 236703b705cfSriastradh{ 23689a906b70Schristos assert(bo->base.io); 236903b705cfSriastradh while (!list_is_empty(&bo->base.vma)) { 237003b705cfSriastradh struct kgem_bo *cached; 237103b705cfSriastradh 237203b705cfSriastradh cached = list_first_entry(&bo->base.vma, struct kgem_bo, vma); 237303b705cfSriastradh assert(cached->proxy == &bo->base); 23749a906b70Schristos assert(cached != &bo->base); 237503b705cfSriastradh list_del(&cached->vma); 237603b705cfSriastradh 23779a906b70Schristos assert(*(struct kgem_bo **)cached->map__gtt == cached); 23789a906b70Schristos *(struct kgem_bo **)cached->map__gtt = NULL; 23799a906b70Schristos cached->map__gtt = NULL; 238003b705cfSriastradh 238103b705cfSriastradh kgem_bo_destroy(kgem, cached); 238203b705cfSriastradh } 238303b705cfSriastradh} 238403b705cfSriastradh 23859a906b70Schristosvoid kgem_retire__buffers(struct kgem *kgem) 238603b705cfSriastradh{ 238703b705cfSriastradh while (!list_is_empty(&kgem->active_buffers)) { 238803b705cfSriastradh struct kgem_buffer *bo = 238903b705cfSriastradh list_last_entry(&kgem->active_buffers, 239003b705cfSriastradh struct kgem_buffer, 239103b705cfSriastradh base.list); 239203b705cfSriastradh 23939a906b70Schristos DBG(("%s: handle=%d, busy? %d [%d]\n", 23949a906b70Schristos __FUNCTION__, bo->base.handle, bo->base.rq != NULL, bo->base.exec != NULL)); 23959a906b70Schristos 23969a906b70Schristos assert(bo->base.exec == NULL || RQ(bo->base.rq) == kgem->next_request); 239703b705cfSriastradh if (bo->base.rq) 239803b705cfSriastradh break; 239903b705cfSriastradh 240003b705cfSriastradh DBG(("%s: releasing upload cache for handle=%d? %d\n", 240103b705cfSriastradh __FUNCTION__, bo->base.handle, !list_is_empty(&bo->base.vma))); 240203b705cfSriastradh list_del(&bo->base.list); 240303b705cfSriastradh kgem_buffer_release(kgem, bo); 240403b705cfSriastradh kgem_bo_unref(kgem, &bo->base); 240503b705cfSriastradh } 240603b705cfSriastradh} 240703b705cfSriastradh 240803b705cfSriastradhstatic bool kgem_retire__flushing(struct kgem *kgem) 240903b705cfSriastradh{ 241003b705cfSriastradh struct kgem_bo *bo, *next; 241103b705cfSriastradh bool retired = false; 241203b705cfSriastradh 241303b705cfSriastradh list_for_each_entry_safe(bo, next, &kgem->flushing, request) { 24149a906b70Schristos assert(RQ(bo->rq) == (void *)kgem); 241503b705cfSriastradh assert(bo->exec == NULL); 241603b705cfSriastradh 241703b705cfSriastradh if (__kgem_busy(kgem, bo->handle)) 241803b705cfSriastradh break; 241903b705cfSriastradh 242003b705cfSriastradh __kgem_bo_clear_busy(bo); 242103b705cfSriastradh 242203b705cfSriastradh if (bo->refcnt) 242303b705cfSriastradh continue; 242403b705cfSriastradh 24259a906b70Schristos retired |= kgem_bo_move_to_cache(kgem, bo); 242603b705cfSriastradh } 242703b705cfSriastradh#if HAS_DEBUG_FULL 242803b705cfSriastradh { 242903b705cfSriastradh int count = 0; 243003b705cfSriastradh list_for_each_entry(bo, &kgem->flushing, request) 243103b705cfSriastradh count++; 24329a906b70Schristos DBG(("%s: %d bo on flushing list\n", __FUNCTION__, count)); 243303b705cfSriastradh } 243403b705cfSriastradh#endif 243503b705cfSriastradh 243603b705cfSriastradh kgem->need_retire |= !list_is_empty(&kgem->flushing); 243703b705cfSriastradh 243803b705cfSriastradh return retired; 243903b705cfSriastradh} 244003b705cfSriastradh 244103b705cfSriastradhstatic bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq) 244203b705cfSriastradh{ 244303b705cfSriastradh bool retired = false; 244403b705cfSriastradh 244503b705cfSriastradh DBG(("%s: request %d complete\n", 244603b705cfSriastradh __FUNCTION__, rq->bo->handle)); 24479a906b70Schristos assert(RQ(rq->bo->rq) == rq); 244803b705cfSriastradh 244903b705cfSriastradh while (!list_is_empty(&rq->buffers)) { 245003b705cfSriastradh struct kgem_bo *bo; 245103b705cfSriastradh 245203b705cfSriastradh bo = list_first_entry(&rq->buffers, 245303b705cfSriastradh struct kgem_bo, 245403b705cfSriastradh request); 245503b705cfSriastradh 245603b705cfSriastradh assert(RQ(bo->rq) == rq); 245703b705cfSriastradh assert(bo->exec == NULL); 245803b705cfSriastradh assert(bo->domain == DOMAIN_GPU || bo->domain == DOMAIN_NONE); 245903b705cfSriastradh 246003b705cfSriastradh list_del(&bo->request); 246103b705cfSriastradh 246203b705cfSriastradh if (bo->needs_flush) 246303b705cfSriastradh bo->needs_flush = __kgem_busy(kgem, bo->handle); 246403b705cfSriastradh if (bo->needs_flush) { 246503b705cfSriastradh DBG(("%s: moving %d to flushing\n", 246603b705cfSriastradh __FUNCTION__, bo->handle)); 246703b705cfSriastradh list_add(&bo->request, &kgem->flushing); 24689a906b70Schristos bo->rq = MAKE_REQUEST(kgem, RQ_RING(bo->rq)); 24699a906b70Schristos kgem->need_retire = true; 247003b705cfSriastradh continue; 247103b705cfSriastradh } 247203b705cfSriastradh 247303b705cfSriastradh bo->domain = DOMAIN_NONE; 247403b705cfSriastradh bo->rq = NULL; 247503b705cfSriastradh if (bo->refcnt) 247603b705cfSriastradh continue; 247703b705cfSriastradh 24789a906b70Schristos retired |= kgem_bo_move_to_cache(kgem, bo); 247903b705cfSriastradh } 248003b705cfSriastradh 248103b705cfSriastradh assert(rq->bo->rq == NULL); 24829a906b70Schristos assert(rq->bo->exec == NULL); 248303b705cfSriastradh assert(list_is_empty(&rq->bo->request)); 24849a906b70Schristos assert(rq->bo->refcnt > 0); 248503b705cfSriastradh 248603b705cfSriastradh if (--rq->bo->refcnt == 0) { 248703b705cfSriastradh if (kgem_bo_set_purgeable(kgem, rq->bo)) { 248803b705cfSriastradh kgem_bo_move_to_inactive(kgem, rq->bo); 248903b705cfSriastradh retired = true; 249003b705cfSriastradh } else { 249103b705cfSriastradh DBG(("%s: closing %d\n", 249203b705cfSriastradh __FUNCTION__, rq->bo->handle)); 249303b705cfSriastradh kgem_bo_free(kgem, rq->bo); 249403b705cfSriastradh } 249503b705cfSriastradh } 249603b705cfSriastradh 249703b705cfSriastradh __kgem_request_free(rq); 249803b705cfSriastradh return retired; 249903b705cfSriastradh} 250003b705cfSriastradh 250103b705cfSriastradhstatic bool kgem_retire__requests_ring(struct kgem *kgem, int ring) 250203b705cfSriastradh{ 250303b705cfSriastradh bool retired = false; 250403b705cfSriastradh 250503b705cfSriastradh while (!list_is_empty(&kgem->requests[ring])) { 250603b705cfSriastradh struct kgem_request *rq; 250703b705cfSriastradh 250803b705cfSriastradh rq = list_first_entry(&kgem->requests[ring], 250903b705cfSriastradh struct kgem_request, 251003b705cfSriastradh list); 25119a906b70Schristos assert(rq->ring == ring); 251203b705cfSriastradh if (__kgem_busy(kgem, rq->bo->handle)) 251303b705cfSriastradh break; 251403b705cfSriastradh 251503b705cfSriastradh retired |= __kgem_retire_rq(kgem, rq); 251603b705cfSriastradh } 251703b705cfSriastradh 251803b705cfSriastradh#if HAS_DEBUG_FULL 251903b705cfSriastradh { 252003b705cfSriastradh struct kgem_bo *bo; 252103b705cfSriastradh int count = 0; 252203b705cfSriastradh 252303b705cfSriastradh list_for_each_entry(bo, &kgem->requests[ring], request) 252403b705cfSriastradh count++; 252503b705cfSriastradh 252603b705cfSriastradh bo = NULL; 252703b705cfSriastradh if (!list_is_empty(&kgem->requests[ring])) 252803b705cfSriastradh bo = list_first_entry(&kgem->requests[ring], 252903b705cfSriastradh struct kgem_request, 253003b705cfSriastradh list)->bo; 253103b705cfSriastradh 25329a906b70Schristos DBG(("%s: ring=%d, %d outstanding requests, oldest=%d\n", 25339a906b70Schristos __FUNCTION__, ring, count, bo ? bo->handle : 0)); 253403b705cfSriastradh } 253503b705cfSriastradh#endif 253603b705cfSriastradh 253703b705cfSriastradh return retired; 253803b705cfSriastradh} 253903b705cfSriastradh 254003b705cfSriastradhstatic bool kgem_retire__requests(struct kgem *kgem) 254103b705cfSriastradh{ 254203b705cfSriastradh bool retired = false; 254303b705cfSriastradh int n; 254403b705cfSriastradh 254503b705cfSriastradh for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) { 254603b705cfSriastradh retired |= kgem_retire__requests_ring(kgem, n); 254703b705cfSriastradh kgem->need_retire |= !list_is_empty(&kgem->requests[n]); 254803b705cfSriastradh } 254903b705cfSriastradh 255003b705cfSriastradh return retired; 255103b705cfSriastradh} 255203b705cfSriastradh 255303b705cfSriastradhbool kgem_retire(struct kgem *kgem) 255403b705cfSriastradh{ 255503b705cfSriastradh bool retired = false; 255603b705cfSriastradh 25579a906b70Schristos DBG(("%s, need_retire?=%d\n", __FUNCTION__, kgem->need_retire)); 255803b705cfSriastradh 255903b705cfSriastradh kgem->need_retire = false; 256003b705cfSriastradh 256103b705cfSriastradh retired |= kgem_retire__flushing(kgem); 256203b705cfSriastradh retired |= kgem_retire__requests(kgem); 256303b705cfSriastradh 256403b705cfSriastradh DBG(("%s -- retired=%d, need_retire=%d\n", 256503b705cfSriastradh __FUNCTION__, retired, kgem->need_retire)); 256603b705cfSriastradh 256703b705cfSriastradh kgem->retire(kgem); 256803b705cfSriastradh 256903b705cfSriastradh return retired; 257003b705cfSriastradh} 257103b705cfSriastradh 257203b705cfSriastradhbool __kgem_ring_is_idle(struct kgem *kgem, int ring) 257303b705cfSriastradh{ 257403b705cfSriastradh struct kgem_request *rq; 257503b705cfSriastradh 25769a906b70Schristos assert(ring < ARRAY_SIZE(kgem->requests)); 257703b705cfSriastradh assert(!list_is_empty(&kgem->requests[ring])); 257803b705cfSriastradh 257903b705cfSriastradh rq = list_last_entry(&kgem->requests[ring], 258003b705cfSriastradh struct kgem_request, list); 25819a906b70Schristos assert(rq->ring == ring); 258203b705cfSriastradh if (__kgem_busy(kgem, rq->bo->handle)) { 258303b705cfSriastradh DBG(("%s: last requests handle=%d still busy\n", 258403b705cfSriastradh __FUNCTION__, rq->bo->handle)); 258503b705cfSriastradh return false; 258603b705cfSriastradh } 258703b705cfSriastradh 258803b705cfSriastradh DBG(("%s: ring=%d idle (handle=%d)\n", 258903b705cfSriastradh __FUNCTION__, ring, rq->bo->handle)); 259003b705cfSriastradh 259103b705cfSriastradh kgem_retire__requests_ring(kgem, ring); 25929a906b70Schristos 259303b705cfSriastradh assert(list_is_empty(&kgem->requests[ring])); 259403b705cfSriastradh return true; 259503b705cfSriastradh} 259603b705cfSriastradh 25979a906b70Schristos#if 0 25989a906b70Schristosstatic void kgem_commit__check_reloc(struct kgem *kgem) 25999a906b70Schristos{ 26009a906b70Schristos struct kgem_request *rq = kgem->next_request; 26019a906b70Schristos struct kgem_bo *bo; 26029a906b70Schristos bool has_64bit = kgem->gen >= 0100; 26039a906b70Schristos int i; 26049a906b70Schristos 26059a906b70Schristos for (i = 0; i < kgem->nreloc; i++) { 26069a906b70Schristos list_for_each_entry(bo, &rq->buffers, request) { 26079a906b70Schristos if (bo->target_handle == kgem->reloc[i].target_handle) { 26089a906b70Schristos uint64_t value = 0; 26099a906b70Schristos gem_read(kgem->fd, rq->bo->handle, &value, kgem->reloc[i].offset, has_64bit ? 8 : 4); 26109a906b70Schristos assert(bo->exec->offset == -1 || value == bo->exec->offset + (int)kgem->reloc[i].delta); 26119a906b70Schristos break; 26129a906b70Schristos } 26139a906b70Schristos } 26149a906b70Schristos } 26159a906b70Schristos} 26169a906b70Schristos#else 26179a906b70Schristos#define kgem_commit__check_reloc(kgem) 26189a906b70Schristos#endif 26199a906b70Schristos 26209a906b70Schristos#ifndef NDEBUG 26219a906b70Schristosstatic void kgem_commit__check_buffers(struct kgem *kgem) 26229a906b70Schristos{ 26239a906b70Schristos struct kgem_buffer *bo; 26249a906b70Schristos 26259a906b70Schristos list_for_each_entry(bo, &kgem->active_buffers, base.list) 26269a906b70Schristos assert(bo->base.exec == NULL); 26279a906b70Schristos} 26289a906b70Schristos#else 26299a906b70Schristos#define kgem_commit__check_buffers(kgem) 26309a906b70Schristos#endif 26319a906b70Schristos 263203b705cfSriastradhstatic void kgem_commit(struct kgem *kgem) 263303b705cfSriastradh{ 263403b705cfSriastradh struct kgem_request *rq = kgem->next_request; 263503b705cfSriastradh struct kgem_bo *bo, *next; 263603b705cfSriastradh 26379a906b70Schristos kgem_commit__check_reloc(kgem); 26389a906b70Schristos 263903b705cfSriastradh list_for_each_entry_safe(bo, next, &rq->buffers, request) { 264003b705cfSriastradh assert(next->request.prev == &bo->request); 264103b705cfSriastradh 264203b705cfSriastradh DBG(("%s: release handle=%d (proxy? %d), dirty? %d flush? %d, snoop? %d -> offset=%x\n", 264303b705cfSriastradh __FUNCTION__, bo->handle, bo->proxy != NULL, 264403b705cfSriastradh bo->gpu_dirty, bo->needs_flush, bo->snoop, 264503b705cfSriastradh (unsigned)bo->exec->offset)); 264603b705cfSriastradh 264703b705cfSriastradh assert(bo->exec); 264803b705cfSriastradh assert(bo->proxy == NULL || bo->exec == &_kgem_dummy_exec); 264903b705cfSriastradh assert(RQ(bo->rq) == rq || (RQ(bo->proxy->rq) == rq)); 265003b705cfSriastradh 265103b705cfSriastradh bo->presumed_offset = bo->exec->offset; 265203b705cfSriastradh bo->exec = NULL; 265303b705cfSriastradh bo->target_handle = -1; 265403b705cfSriastradh 265503b705cfSriastradh if (!bo->refcnt && !bo->reusable) { 265603b705cfSriastradh assert(!bo->snoop); 26579a906b70Schristos assert(!bo->proxy); 265803b705cfSriastradh kgem_bo_free(kgem, bo); 265903b705cfSriastradh continue; 266003b705cfSriastradh } 266103b705cfSriastradh 266203b705cfSriastradh bo->binding.offset = 0; 266303b705cfSriastradh bo->domain = DOMAIN_GPU; 266403b705cfSriastradh bo->gpu_dirty = false; 266503b705cfSriastradh 266603b705cfSriastradh if (bo->proxy) { 266703b705cfSriastradh /* proxies are not used for domain tracking */ 266803b705cfSriastradh __kgem_bo_clear_busy(bo); 266903b705cfSriastradh } 267003b705cfSriastradh 26719a906b70Schristos kgem->scanout_busy |= bo->scanout && bo->needs_flush; 267203b705cfSriastradh } 267303b705cfSriastradh 267403b705cfSriastradh if (rq == &kgem->static_request) { 267503b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 267603b705cfSriastradh 267703b705cfSriastradh DBG(("%s: syncing due to allocation failure\n", __FUNCTION__)); 267803b705cfSriastradh 267903b705cfSriastradh VG_CLEAR(set_domain); 268003b705cfSriastradh set_domain.handle = rq->bo->handle; 268103b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_GTT; 268203b705cfSriastradh set_domain.write_domain = I915_GEM_DOMAIN_GTT; 26839a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 268403b705cfSriastradh DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 268503b705cfSriastradh kgem_throttle(kgem); 268603b705cfSriastradh } 268703b705cfSriastradh 268803b705cfSriastradh kgem_retire(kgem); 268903b705cfSriastradh assert(list_is_empty(&rq->buffers)); 269003b705cfSriastradh 26919a906b70Schristos assert(rq->bo->map__gtt == NULL); 26929a906b70Schristos assert(rq->bo->map__cpu == NULL); 269303b705cfSriastradh gem_close(kgem->fd, rq->bo->handle); 269403b705cfSriastradh kgem_cleanup_cache(kgem); 269503b705cfSriastradh } else { 26969a906b70Schristos assert(rq->ring < ARRAY_SIZE(kgem->requests)); 269703b705cfSriastradh list_add_tail(&rq->list, &kgem->requests[rq->ring]); 269803b705cfSriastradh kgem->need_throttle = kgem->need_retire = 1; 269903b705cfSriastradh } 270003b705cfSriastradh 270103b705cfSriastradh kgem->next_request = NULL; 27029a906b70Schristos 27039a906b70Schristos kgem_commit__check_buffers(kgem); 270403b705cfSriastradh} 270503b705cfSriastradh 270603b705cfSriastradhstatic void kgem_close_list(struct kgem *kgem, struct list *head) 270703b705cfSriastradh{ 270803b705cfSriastradh while (!list_is_empty(head)) 270903b705cfSriastradh kgem_bo_free(kgem, list_first_entry(head, struct kgem_bo, list)); 271003b705cfSriastradh} 271103b705cfSriastradh 271203b705cfSriastradhstatic void kgem_close_inactive(struct kgem *kgem) 271303b705cfSriastradh{ 271403b705cfSriastradh unsigned int i; 271503b705cfSriastradh 271603b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) 271703b705cfSriastradh kgem_close_list(kgem, &kgem->inactive[i]); 271803b705cfSriastradh} 271903b705cfSriastradh 272003b705cfSriastradhstatic void kgem_finish_buffers(struct kgem *kgem) 272103b705cfSriastradh{ 272203b705cfSriastradh struct kgem_buffer *bo, *next; 272303b705cfSriastradh 272403b705cfSriastradh list_for_each_entry_safe(bo, next, &kgem->batch_buffers, base.list) { 27259a906b70Schristos DBG(("%s: buffer handle=%d, used=%d, exec?=%d, write=%d, mmapped=%s, refcnt=%d\n", 272603b705cfSriastradh __FUNCTION__, bo->base.handle, bo->used, bo->base.exec!=NULL, 27279a906b70Schristos bo->write, bo->mmapped == MMAPPED_CPU ? "cpu" : bo->mmapped == MMAPPED_GTT ? "gtt" : "no", 27289a906b70Schristos bo->base.refcnt)); 272903b705cfSriastradh 273003b705cfSriastradh assert(next->base.list.prev == &bo->base.list); 273103b705cfSriastradh assert(bo->base.io); 273203b705cfSriastradh assert(bo->base.refcnt >= 1); 273303b705cfSriastradh 27349a906b70Schristos if (bo->base.refcnt > 1 && !bo->base.exec) { 27359a906b70Schristos DBG(("%s: skipping unattached handle=%d, used=%d, refcnt=%d\n", 27369a906b70Schristos __FUNCTION__, bo->base.handle, bo->used, bo->base.refcnt)); 273703b705cfSriastradh continue; 273803b705cfSriastradh } 273903b705cfSriastradh 274003b705cfSriastradh if (!bo->write) { 274103b705cfSriastradh assert(bo->base.exec || bo->base.refcnt > 1); 274203b705cfSriastradh goto decouple; 274303b705cfSriastradh } 274403b705cfSriastradh 274503b705cfSriastradh if (bo->mmapped) { 27469a906b70Schristos uint32_t used; 274703b705cfSriastradh 274803b705cfSriastradh assert(!bo->need_io); 274903b705cfSriastradh 275003b705cfSriastradh used = ALIGN(bo->used, PAGE_SIZE); 275103b705cfSriastradh if (!DBG_NO_UPLOAD_ACTIVE && 275203b705cfSriastradh used + PAGE_SIZE <= bytes(&bo->base) && 27539a906b70Schristos (kgem->has_llc || bo->mmapped == MMAPPED_GTT || bo->base.snoop)) { 27549a906b70Schristos DBG(("%s: retaining upload buffer (%d/%d): used=%d, refcnt=%d\n", 27559a906b70Schristos __FUNCTION__, bo->used, bytes(&bo->base), used, bo->base.refcnt)); 275603b705cfSriastradh bo->used = used; 275703b705cfSriastradh list_move(&bo->base.list, 275803b705cfSriastradh &kgem->active_buffers); 27599a906b70Schristos kgem->need_retire = true; 276003b705cfSriastradh continue; 276103b705cfSriastradh } 276203b705cfSriastradh DBG(("%s: discarding mmapped buffer, used=%d, map type=%d\n", 27639a906b70Schristos __FUNCTION__, bo->used, bo->mmapped)); 276403b705cfSriastradh goto decouple; 276503b705cfSriastradh } 276603b705cfSriastradh 27679a906b70Schristos if (!bo->used || !bo->base.exec) { 276803b705cfSriastradh /* Unless we replace the handle in the execbuffer, 276903b705cfSriastradh * then this bo will become active. So decouple it 277003b705cfSriastradh * from the buffer list and track it in the normal 277103b705cfSriastradh * manner. 277203b705cfSriastradh */ 277303b705cfSriastradh goto decouple; 277403b705cfSriastradh } 277503b705cfSriastradh 277603b705cfSriastradh assert(bo->need_io); 277703b705cfSriastradh assert(bo->base.rq == MAKE_REQUEST(kgem->next_request, kgem->ring)); 277803b705cfSriastradh assert(bo->base.domain != DOMAIN_GPU); 277903b705cfSriastradh 278003b705cfSriastradh if (bo->base.refcnt == 1 && 278103b705cfSriastradh bo->base.size.pages.count > 1 && 278203b705cfSriastradh bo->used < bytes(&bo->base) / 2) { 278303b705cfSriastradh struct kgem_bo *shrink; 278403b705cfSriastradh unsigned alloc = NUM_PAGES(bo->used); 278503b705cfSriastradh 278603b705cfSriastradh shrink = search_snoop_cache(kgem, alloc, 278703b705cfSriastradh CREATE_INACTIVE | CREATE_NO_RETIRE); 278803b705cfSriastradh if (shrink) { 278903b705cfSriastradh void *map; 279003b705cfSriastradh int n; 279103b705cfSriastradh 279203b705cfSriastradh DBG(("%s: used=%d, shrinking %d to %d, handle %d to %d\n", 279303b705cfSriastradh __FUNCTION__, 279403b705cfSriastradh bo->used, bytes(&bo->base), bytes(shrink), 279503b705cfSriastradh bo->base.handle, shrink->handle)); 279603b705cfSriastradh 279703b705cfSriastradh assert(bo->used <= bytes(shrink)); 279803b705cfSriastradh map = kgem_bo_map__cpu(kgem, shrink); 279903b705cfSriastradh if (map) { 280003b705cfSriastradh kgem_bo_sync__cpu(kgem, shrink); 280103b705cfSriastradh memcpy(map, bo->mem, bo->used); 280203b705cfSriastradh 280303b705cfSriastradh shrink->target_handle = 280403b705cfSriastradh kgem->has_handle_lut ? bo->base.target_handle : shrink->handle; 280503b705cfSriastradh for (n = 0; n < kgem->nreloc; n++) { 280603b705cfSriastradh if (kgem->reloc[n].target_handle == bo->base.target_handle) { 280703b705cfSriastradh kgem->reloc[n].target_handle = shrink->target_handle; 280803b705cfSriastradh kgem->reloc[n].presumed_offset = shrink->presumed_offset; 280903b705cfSriastradh kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = 281003b705cfSriastradh kgem->reloc[n].delta + shrink->presumed_offset; 281103b705cfSriastradh } 281203b705cfSriastradh } 281303b705cfSriastradh 281403b705cfSriastradh bo->base.exec->handle = shrink->handle; 281503b705cfSriastradh bo->base.exec->offset = shrink->presumed_offset; 281603b705cfSriastradh shrink->exec = bo->base.exec; 281703b705cfSriastradh shrink->rq = bo->base.rq; 281803b705cfSriastradh list_replace(&bo->base.request, 281903b705cfSriastradh &shrink->request); 282003b705cfSriastradh list_init(&bo->base.request); 282103b705cfSriastradh shrink->needs_flush = bo->base.gpu_dirty; 282203b705cfSriastradh 282303b705cfSriastradh bo->base.exec = NULL; 282403b705cfSriastradh bo->base.rq = NULL; 282503b705cfSriastradh bo->base.gpu_dirty = false; 282603b705cfSriastradh bo->base.needs_flush = false; 282703b705cfSriastradh bo->used = 0; 282803b705cfSriastradh 282903b705cfSriastradh goto decouple; 283003b705cfSriastradh } 283103b705cfSriastradh 283203b705cfSriastradh __kgem_bo_destroy(kgem, shrink); 283303b705cfSriastradh } 283403b705cfSriastradh 283503b705cfSriastradh shrink = search_linear_cache(kgem, alloc, 283603b705cfSriastradh CREATE_INACTIVE | CREATE_NO_RETIRE); 283703b705cfSriastradh if (shrink) { 283803b705cfSriastradh int n; 283903b705cfSriastradh 284003b705cfSriastradh DBG(("%s: used=%d, shrinking %d to %d, handle %d to %d\n", 284103b705cfSriastradh __FUNCTION__, 284203b705cfSriastradh bo->used, bytes(&bo->base), bytes(shrink), 284303b705cfSriastradh bo->base.handle, shrink->handle)); 284403b705cfSriastradh 284503b705cfSriastradh assert(bo->used <= bytes(shrink)); 28469a906b70Schristos if (gem_write__cachealigned(kgem->fd, shrink->handle, 28479a906b70Schristos 0, bo->used, bo->mem) == 0) { 284803b705cfSriastradh shrink->target_handle = 284903b705cfSriastradh kgem->has_handle_lut ? bo->base.target_handle : shrink->handle; 285003b705cfSriastradh for (n = 0; n < kgem->nreloc; n++) { 285103b705cfSriastradh if (kgem->reloc[n].target_handle == bo->base.target_handle) { 285203b705cfSriastradh kgem->reloc[n].target_handle = shrink->target_handle; 285303b705cfSriastradh kgem->reloc[n].presumed_offset = shrink->presumed_offset; 285403b705cfSriastradh kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = 285503b705cfSriastradh kgem->reloc[n].delta + shrink->presumed_offset; 285603b705cfSriastradh } 285703b705cfSriastradh } 285803b705cfSriastradh 285903b705cfSriastradh bo->base.exec->handle = shrink->handle; 286003b705cfSriastradh bo->base.exec->offset = shrink->presumed_offset; 286103b705cfSriastradh shrink->exec = bo->base.exec; 286203b705cfSriastradh shrink->rq = bo->base.rq; 286303b705cfSriastradh list_replace(&bo->base.request, 286403b705cfSriastradh &shrink->request); 286503b705cfSriastradh list_init(&bo->base.request); 286603b705cfSriastradh shrink->needs_flush = bo->base.gpu_dirty; 286703b705cfSriastradh 286803b705cfSriastradh bo->base.exec = NULL; 286903b705cfSriastradh bo->base.rq = NULL; 287003b705cfSriastradh bo->base.gpu_dirty = false; 287103b705cfSriastradh bo->base.needs_flush = false; 287203b705cfSriastradh bo->used = 0; 287303b705cfSriastradh 287403b705cfSriastradh goto decouple; 287503b705cfSriastradh } 287603b705cfSriastradh 287703b705cfSriastradh __kgem_bo_destroy(kgem, shrink); 287803b705cfSriastradh } 287903b705cfSriastradh } 288003b705cfSriastradh 288103b705cfSriastradh DBG(("%s: handle=%d, uploading %d/%d\n", 288203b705cfSriastradh __FUNCTION__, bo->base.handle, bo->used, bytes(&bo->base))); 288303b705cfSriastradh ASSERT_IDLE(kgem, bo->base.handle); 288403b705cfSriastradh assert(bo->used <= bytes(&bo->base)); 28859a906b70Schristos gem_write__cachealigned(kgem->fd, bo->base.handle, 28869a906b70Schristos 0, bo->used, bo->mem); 288703b705cfSriastradh bo->need_io = 0; 288803b705cfSriastradh 288903b705cfSriastradhdecouple: 289003b705cfSriastradh DBG(("%s: releasing handle=%d\n", 289103b705cfSriastradh __FUNCTION__, bo->base.handle)); 289203b705cfSriastradh list_del(&bo->base.list); 289303b705cfSriastradh kgem_bo_unref(kgem, &bo->base); 289403b705cfSriastradh } 289503b705cfSriastradh} 289603b705cfSriastradh 289703b705cfSriastradhstatic void kgem_cleanup(struct kgem *kgem) 289803b705cfSriastradh{ 289903b705cfSriastradh int n; 290003b705cfSriastradh 290103b705cfSriastradh for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) { 290203b705cfSriastradh while (!list_is_empty(&kgem->requests[n])) { 290303b705cfSriastradh struct kgem_request *rq; 290403b705cfSriastradh 290503b705cfSriastradh rq = list_first_entry(&kgem->requests[n], 290603b705cfSriastradh struct kgem_request, 290703b705cfSriastradh list); 29089a906b70Schristos assert(rq->ring == n); 290903b705cfSriastradh while (!list_is_empty(&rq->buffers)) { 291003b705cfSriastradh struct kgem_bo *bo; 291103b705cfSriastradh 291203b705cfSriastradh bo = list_first_entry(&rq->buffers, 291303b705cfSriastradh struct kgem_bo, 291403b705cfSriastradh request); 291503b705cfSriastradh 291603b705cfSriastradh bo->exec = NULL; 291703b705cfSriastradh bo->gpu_dirty = false; 291803b705cfSriastradh __kgem_bo_clear_busy(bo); 291903b705cfSriastradh if (bo->refcnt == 0) 292003b705cfSriastradh kgem_bo_free(kgem, bo); 292103b705cfSriastradh } 292203b705cfSriastradh 292303b705cfSriastradh __kgem_request_free(rq); 292403b705cfSriastradh } 292503b705cfSriastradh } 292603b705cfSriastradh 292703b705cfSriastradh kgem_close_inactive(kgem); 292803b705cfSriastradh} 292903b705cfSriastradh 293003b705cfSriastradhstatic int kgem_batch_write(struct kgem *kgem, uint32_t handle, uint32_t size) 293103b705cfSriastradh{ 293203b705cfSriastradh int ret; 293303b705cfSriastradh 293403b705cfSriastradh ASSERT_IDLE(kgem, handle); 293503b705cfSriastradh 29369a906b70Schristos#if DBG_NO_EXEC 29379a906b70Schristos { 29389a906b70Schristos uint32_t batch[] = { MI_BATCH_BUFFER_END, 0}; 29399a906b70Schristos return gem_write(kgem->fd, handle, 0, sizeof(batch), batch); 29409a906b70Schristos } 29419a906b70Schristos#endif 29429a906b70Schristos 29439a906b70Schristos 29449a906b70Schristosretry: 294503b705cfSriastradh /* If there is no surface data, just upload the batch */ 29469a906b70Schristos if (kgem->surface == kgem->batch_size) { 29479a906b70Schristos if ((ret = gem_write__cachealigned(kgem->fd, handle, 29489a906b70Schristos 0, sizeof(uint32_t)*kgem->nbatch, 29499a906b70Schristos kgem->batch)) == 0) 29509a906b70Schristos return 0; 29519a906b70Schristos 29529a906b70Schristos goto expire; 29539a906b70Schristos } 295403b705cfSriastradh 295503b705cfSriastradh /* Are the batch pages conjoint with the surface pages? */ 295603b705cfSriastradh if (kgem->surface < kgem->nbatch + PAGE_SIZE/sizeof(uint32_t)) { 295703b705cfSriastradh assert(size == PAGE_ALIGN(kgem->batch_size*sizeof(uint32_t))); 29589a906b70Schristos if ((ret = gem_write__cachealigned(kgem->fd, handle, 29599a906b70Schristos 0, kgem->batch_size*sizeof(uint32_t), 29609a906b70Schristos kgem->batch)) == 0) 29619a906b70Schristos return 0; 29629a906b70Schristos 29639a906b70Schristos goto expire; 296403b705cfSriastradh } 296503b705cfSriastradh 296603b705cfSriastradh /* Disjoint surface/batch, upload separately */ 29679a906b70Schristos if ((ret = gem_write__cachealigned(kgem->fd, handle, 29689a906b70Schristos 0, sizeof(uint32_t)*kgem->nbatch, 29699a906b70Schristos kgem->batch))) 29709a906b70Schristos goto expire; 297103b705cfSriastradh 297203b705cfSriastradh ret = PAGE_ALIGN(sizeof(uint32_t) * kgem->batch_size); 297303b705cfSriastradh ret -= sizeof(uint32_t) * kgem->surface; 297403b705cfSriastradh assert(size-ret >= kgem->nbatch*sizeof(uint32_t)); 29759a906b70Schristos if (gem_write(kgem->fd, handle, 29769a906b70Schristos size - ret, (kgem->batch_size - kgem->surface)*sizeof(uint32_t), 29779a906b70Schristos kgem->batch + kgem->surface)) 29789a906b70Schristos goto expire; 29799a906b70Schristos 29809a906b70Schristos return 0; 29819a906b70Schristos 29829a906b70Schristosexpire: 29839a906b70Schristos assert(ret != EINVAL); 29849a906b70Schristos 29859a906b70Schristos (void)__kgem_throttle_retire(kgem, 0); 29869a906b70Schristos if (kgem_expire_cache(kgem)) 29879a906b70Schristos goto retry; 29889a906b70Schristos 29899a906b70Schristos if (kgem_cleanup_cache(kgem)) 29909a906b70Schristos goto retry; 29919a906b70Schristos 29929a906b70Schristos ERR(("%s: failed to write batch (handle=%d): %d\n", 29939a906b70Schristos __FUNCTION__, handle, -ret)); 29949a906b70Schristos return ret; 299503b705cfSriastradh} 299603b705cfSriastradh 299703b705cfSriastradhvoid kgem_reset(struct kgem *kgem) 299803b705cfSriastradh{ 299903b705cfSriastradh if (kgem->next_request) { 300003b705cfSriastradh struct kgem_request *rq = kgem->next_request; 300103b705cfSriastradh 300203b705cfSriastradh while (!list_is_empty(&rq->buffers)) { 300303b705cfSriastradh struct kgem_bo *bo = 300403b705cfSriastradh list_first_entry(&rq->buffers, 300503b705cfSriastradh struct kgem_bo, 300603b705cfSriastradh request); 300703b705cfSriastradh list_del(&bo->request); 300803b705cfSriastradh 300903b705cfSriastradh assert(RQ(bo->rq) == rq); 301003b705cfSriastradh 301103b705cfSriastradh bo->binding.offset = 0; 301203b705cfSriastradh bo->exec = NULL; 301303b705cfSriastradh bo->target_handle = -1; 301403b705cfSriastradh bo->gpu_dirty = false; 301503b705cfSriastradh 301603b705cfSriastradh if (bo->needs_flush && __kgem_busy(kgem, bo->handle)) { 301703b705cfSriastradh assert(bo->domain == DOMAIN_GPU || bo->domain == DOMAIN_NONE); 301803b705cfSriastradh list_add(&bo->request, &kgem->flushing); 301903b705cfSriastradh bo->rq = (void *)kgem; 30209a906b70Schristos kgem->need_retire = true; 302103b705cfSriastradh } else 302203b705cfSriastradh __kgem_bo_clear_busy(bo); 302303b705cfSriastradh 302403b705cfSriastradh if (bo->refcnt || bo->rq) 302503b705cfSriastradh continue; 302603b705cfSriastradh 30279a906b70Schristos kgem_bo_move_to_cache(kgem, bo); 302803b705cfSriastradh } 302903b705cfSriastradh 303003b705cfSriastradh if (rq != &kgem->static_request) { 303103b705cfSriastradh list_init(&rq->list); 303203b705cfSriastradh __kgem_request_free(rq); 303303b705cfSriastradh } 303403b705cfSriastradh } 303503b705cfSriastradh 303603b705cfSriastradh kgem->nfence = 0; 303703b705cfSriastradh kgem->nexec = 0; 303803b705cfSriastradh kgem->nreloc = 0; 303903b705cfSriastradh kgem->nreloc__self = 0; 304003b705cfSriastradh kgem->aperture = 0; 304103b705cfSriastradh kgem->aperture_fenced = 0; 30429a906b70Schristos kgem->aperture_max_fence = 0; 304303b705cfSriastradh kgem->nbatch = 0; 304403b705cfSriastradh kgem->surface = kgem->batch_size; 304503b705cfSriastradh kgem->mode = KGEM_NONE; 30469a906b70Schristos kgem->needs_semaphore = false; 30479a906b70Schristos kgem->needs_reservation = false; 304803b705cfSriastradh kgem->flush = 0; 304903b705cfSriastradh kgem->batch_flags = kgem->batch_flags_base; 305003b705cfSriastradh 305103b705cfSriastradh kgem->next_request = __kgem_request_alloc(kgem); 305203b705cfSriastradh 305303b705cfSriastradh kgem_sna_reset(kgem); 305403b705cfSriastradh} 305503b705cfSriastradh 305603b705cfSriastradhstatic int compact_batch_surface(struct kgem *kgem) 305703b705cfSriastradh{ 305803b705cfSriastradh int size, shrink, n; 305903b705cfSriastradh 306003b705cfSriastradh if (!kgem->has_relaxed_delta) 30619a906b70Schristos return kgem->batch_size * sizeof(uint32_t); 306203b705cfSriastradh 306303b705cfSriastradh /* See if we can pack the contents into one or two pages */ 306403b705cfSriastradh n = ALIGN(kgem->batch_size, 1024); 306503b705cfSriastradh size = n - kgem->surface + kgem->nbatch; 306603b705cfSriastradh size = ALIGN(size, 1024); 306703b705cfSriastradh 306803b705cfSriastradh shrink = n - size; 306903b705cfSriastradh if (shrink) { 307003b705cfSriastradh DBG(("shrinking from %d to %d\n", kgem->batch_size, size)); 307103b705cfSriastradh 307203b705cfSriastradh shrink *= sizeof(uint32_t); 307303b705cfSriastradh for (n = 0; n < kgem->nreloc; n++) { 307403b705cfSriastradh if (kgem->reloc[n].read_domains == I915_GEM_DOMAIN_INSTRUCTION && 307503b705cfSriastradh kgem->reloc[n].target_handle == ~0U) 307603b705cfSriastradh kgem->reloc[n].delta -= shrink; 307703b705cfSriastradh 307803b705cfSriastradh if (kgem->reloc[n].offset >= sizeof(uint32_t)*kgem->nbatch) 307903b705cfSriastradh kgem->reloc[n].offset -= shrink; 308003b705cfSriastradh } 308103b705cfSriastradh } 308203b705cfSriastradh 308303b705cfSriastradh return size * sizeof(uint32_t); 308403b705cfSriastradh} 308503b705cfSriastradh 308603b705cfSriastradhstatic struct kgem_bo * 308703b705cfSriastradhkgem_create_batch(struct kgem *kgem, int size) 308803b705cfSriastradh{ 308903b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 309003b705cfSriastradh struct kgem_bo *bo; 309103b705cfSriastradh 309203b705cfSriastradh if (size <= 4096) { 309303b705cfSriastradh bo = list_first_entry(&kgem->pinned_batches[0], 309403b705cfSriastradh struct kgem_bo, 309503b705cfSriastradh list); 309603b705cfSriastradh if (!bo->rq) { 309703b705cfSriastradhout_4096: 30989a906b70Schristos assert(bo->refcnt > 0); 309903b705cfSriastradh list_move_tail(&bo->list, &kgem->pinned_batches[0]); 310003b705cfSriastradh return kgem_bo_reference(bo); 310103b705cfSriastradh } 310203b705cfSriastradh 310303b705cfSriastradh if (!__kgem_busy(kgem, bo->handle)) { 310403b705cfSriastradh __kgem_retire_rq(kgem, RQ(bo->rq)); 310503b705cfSriastradh goto out_4096; 310603b705cfSriastradh } 310703b705cfSriastradh } 310803b705cfSriastradh 310903b705cfSriastradh if (size <= 16384) { 311003b705cfSriastradh bo = list_first_entry(&kgem->pinned_batches[1], 311103b705cfSriastradh struct kgem_bo, 311203b705cfSriastradh list); 311303b705cfSriastradh if (!bo->rq) { 311403b705cfSriastradhout_16384: 31159a906b70Schristos assert(bo->refcnt > 0); 311603b705cfSriastradh list_move_tail(&bo->list, &kgem->pinned_batches[1]); 311703b705cfSriastradh return kgem_bo_reference(bo); 311803b705cfSriastradh } 311903b705cfSriastradh 312003b705cfSriastradh if (!__kgem_busy(kgem, bo->handle)) { 312103b705cfSriastradh __kgem_retire_rq(kgem, RQ(bo->rq)); 312203b705cfSriastradh goto out_16384; 312303b705cfSriastradh } 312403b705cfSriastradh } 312503b705cfSriastradh 31269a906b70Schristos if (kgem->gen == 020) { 31279a906b70Schristos bo = kgem_create_linear(kgem, size, CREATE_CACHED | CREATE_TEMPORARY); 31289a906b70Schristos if (bo) 31299a906b70Schristos return bo; 313003b705cfSriastradh 31319a906b70Schristos /* Nothing available for reuse, rely on the kernel wa */ 31329a906b70Schristos if (kgem->has_pinned_batches) { 31339a906b70Schristos bo = kgem_create_linear(kgem, size, CREATE_CACHED | CREATE_TEMPORARY); 31349a906b70Schristos if (bo) { 31359a906b70Schristos kgem->batch_flags &= ~LOCAL_I915_EXEC_IS_PINNED; 31369a906b70Schristos return bo; 31379a906b70Schristos } 31389a906b70Schristos } 31399a906b70Schristos 31409a906b70Schristos if (size < 16384) { 31419a906b70Schristos bo = list_first_entry(&kgem->pinned_batches[size > 4096], 31429a906b70Schristos struct kgem_bo, 31439a906b70Schristos list); 31449a906b70Schristos list_move_tail(&bo->list, &kgem->pinned_batches[size > 4096]); 314503b705cfSriastradh 31469a906b70Schristos DBG(("%s: syncing due to busy batches\n", __FUNCTION__)); 314703b705cfSriastradh 31489a906b70Schristos VG_CLEAR(set_domain); 31499a906b70Schristos set_domain.handle = bo->handle; 31509a906b70Schristos set_domain.read_domains = I915_GEM_DOMAIN_GTT; 31519a906b70Schristos set_domain.write_domain = I915_GEM_DOMAIN_GTT; 31529a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 31539a906b70Schristos DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 31549a906b70Schristos kgem_throttle(kgem); 31559a906b70Schristos return NULL; 31569a906b70Schristos } 315703b705cfSriastradh 31589a906b70Schristos kgem_retire(kgem); 31599a906b70Schristos assert(bo->rq == NULL); 31609a906b70Schristos return kgem_bo_reference(bo); 31619a906b70Schristos } 316203b705cfSriastradh } 316303b705cfSriastradh 316403b705cfSriastradh return kgem_create_linear(kgem, size, CREATE_NO_THROTTLE); 316503b705cfSriastradh} 316603b705cfSriastradh 31679a906b70Schristos#if !NDEBUG 31689a906b70Schristosstatic bool dump_file(const char *path) 31699a906b70Schristos{ 31709a906b70Schristos FILE *file; 31719a906b70Schristos size_t len = 0; 31729a906b70Schristos char *line = NULL; 31739a906b70Schristos 31749a906b70Schristos file = fopen(path, "r"); 31759a906b70Schristos if (file == NULL) 31769a906b70Schristos return false; 31779a906b70Schristos 31789a906b70Schristos while (getline(&line, &len, file) != -1) 31799a906b70Schristos ErrorF("%s", line); 31809a906b70Schristos 31819a906b70Schristos free(line); 31829a906b70Schristos fclose(file); 31839a906b70Schristos return true; 31849a906b70Schristos} 31859a906b70Schristos 31869a906b70Schristosstatic void dump_debugfs(struct kgem *kgem, const char *name) 31879a906b70Schristos{ 31889a906b70Schristos char path[80]; 31899a906b70Schristos int minor = kgem_get_minor(kgem); 31909a906b70Schristos 31919a906b70Schristos if (minor < 0) 31929a906b70Schristos return; 31939a906b70Schristos 31949a906b70Schristos sprintf(path, "/sys/kernel/debug/dri/%d/%s", minor, name); 31959a906b70Schristos if (dump_file(path)) 31969a906b70Schristos return; 31979a906b70Schristos 31989a906b70Schristos sprintf(path, "/debug/dri/%d/%s", minor, name); 31999a906b70Schristos if (dump_file(path)) 32009a906b70Schristos return; 32019a906b70Schristos} 32029a906b70Schristos 32039a906b70Schristosstatic void dump_gtt_info(struct kgem *kgem) 32049a906b70Schristos{ 32059a906b70Schristos dump_debugfs(kgem, "i915_gem_gtt"); 32069a906b70Schristos} 32079a906b70Schristos 32089a906b70Schristosstatic void dump_fence_regs(struct kgem *kgem) 32099a906b70Schristos{ 32109a906b70Schristos dump_debugfs(kgem, "i915_gem_fence_regs"); 32119a906b70Schristos} 32129a906b70Schristos#endif 32139a906b70Schristos 32149a906b70Schristosstatic int do_execbuf(struct kgem *kgem, struct drm_i915_gem_execbuffer2 *execbuf) 32159a906b70Schristos{ 32169a906b70Schristos int ret; 32179a906b70Schristos 32189a906b70Schristosretry: 32199a906b70Schristos ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf); 32209a906b70Schristos if (ret == 0) 32219a906b70Schristos return 0; 32229a906b70Schristos 32239a906b70Schristos DBG(("%s: failed ret=%d, throttling and discarding cache\n", __FUNCTION__, ret)); 32249a906b70Schristos (void)__kgem_throttle_retire(kgem, 0); 32259a906b70Schristos if (kgem_expire_cache(kgem)) 32269a906b70Schristos goto retry; 32279a906b70Schristos 32289a906b70Schristos if (kgem_cleanup_cache(kgem)) 32299a906b70Schristos goto retry; 32309a906b70Schristos 32319a906b70Schristos /* last gasp */ 32329a906b70Schristos return do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf); 32339a906b70Schristos} 32349a906b70Schristos 323503b705cfSriastradhvoid _kgem_submit(struct kgem *kgem) 323603b705cfSriastradh{ 323703b705cfSriastradh struct kgem_request *rq; 323803b705cfSriastradh uint32_t batch_end; 323903b705cfSriastradh int size; 324003b705cfSriastradh 324103b705cfSriastradh assert(!DBG_NO_HW); 324203b705cfSriastradh assert(!kgem->wedged); 324303b705cfSriastradh 324403b705cfSriastradh assert(kgem->nbatch); 324503b705cfSriastradh assert(kgem->nbatch <= KGEM_BATCH_SIZE(kgem)); 324603b705cfSriastradh assert(kgem->nbatch <= kgem->surface); 324703b705cfSriastradh 324803b705cfSriastradh batch_end = kgem_end_batch(kgem); 324903b705cfSriastradh kgem_sna_flush(kgem); 325003b705cfSriastradh 32519a906b70Schristos DBG(("batch[%d/%d, flags=%x]: %d %d %d %d, nreloc=%d, nexec=%d, nfence=%d, aperture=%d [fenced=%d]\n", 32529a906b70Schristos kgem->mode, kgem->ring, kgem->batch_flags, 32539a906b70Schristos batch_end, kgem->nbatch, kgem->surface, kgem->batch_size, 32549a906b70Schristos kgem->nreloc, kgem->nexec, kgem->nfence, kgem->aperture, kgem->aperture_fenced)); 325503b705cfSriastradh 325603b705cfSriastradh assert(kgem->nbatch <= kgem->batch_size); 325703b705cfSriastradh assert(kgem->nbatch <= kgem->surface); 325803b705cfSriastradh assert(kgem->nreloc <= ARRAY_SIZE(kgem->reloc)); 325903b705cfSriastradh assert(kgem->nexec < ARRAY_SIZE(kgem->exec)); 326003b705cfSriastradh assert(kgem->nfence <= kgem->fence_max); 326103b705cfSriastradh 326203b705cfSriastradh kgem_finish_buffers(kgem); 326303b705cfSriastradh 32649a906b70Schristos#if SHOW_BATCH_BEFORE 326503b705cfSriastradh __kgem_batch_debug(kgem, batch_end); 326603b705cfSriastradh#endif 326703b705cfSriastradh 326803b705cfSriastradh rq = kgem->next_request; 326903b705cfSriastradh if (kgem->surface != kgem->batch_size) 327003b705cfSriastradh size = compact_batch_surface(kgem); 327103b705cfSriastradh else 327203b705cfSriastradh size = kgem->nbatch * sizeof(kgem->batch[0]); 327303b705cfSriastradh rq->bo = kgem_create_batch(kgem, size); 327403b705cfSriastradh if (rq->bo) { 327503b705cfSriastradh uint32_t handle = rq->bo->handle; 327603b705cfSriastradh int i; 327703b705cfSriastradh 327803b705cfSriastradh assert(!rq->bo->needs_flush); 327903b705cfSriastradh 328003b705cfSriastradh i = kgem->nexec++; 328103b705cfSriastradh kgem->exec[i].handle = handle; 328203b705cfSriastradh kgem->exec[i].relocation_count = kgem->nreloc; 328303b705cfSriastradh kgem->exec[i].relocs_ptr = (uintptr_t)kgem->reloc; 328403b705cfSriastradh kgem->exec[i].alignment = 0; 328503b705cfSriastradh kgem->exec[i].offset = rq->bo->presumed_offset; 328603b705cfSriastradh kgem->exec[i].flags = 0; 328703b705cfSriastradh kgem->exec[i].rsvd1 = 0; 328803b705cfSriastradh kgem->exec[i].rsvd2 = 0; 328903b705cfSriastradh 329003b705cfSriastradh rq->bo->target_handle = kgem->has_handle_lut ? i : handle; 329103b705cfSriastradh rq->bo->exec = &kgem->exec[i]; 329203b705cfSriastradh rq->bo->rq = MAKE_REQUEST(rq, kgem->ring); /* useful sanity check */ 329303b705cfSriastradh list_add(&rq->bo->request, &rq->buffers); 329403b705cfSriastradh rq->ring = kgem->ring == KGEM_BLT; 329503b705cfSriastradh 329603b705cfSriastradh kgem_fixup_self_relocs(kgem, rq->bo); 329703b705cfSriastradh 329803b705cfSriastradh if (kgem_batch_write(kgem, handle, size) == 0) { 329903b705cfSriastradh struct drm_i915_gem_execbuffer2 execbuf; 33009a906b70Schristos int ret; 330103b705cfSriastradh 330203b705cfSriastradh memset(&execbuf, 0, sizeof(execbuf)); 330303b705cfSriastradh execbuf.buffers_ptr = (uintptr_t)kgem->exec; 330403b705cfSriastradh execbuf.buffer_count = kgem->nexec; 330503b705cfSriastradh execbuf.batch_len = batch_end*sizeof(uint32_t); 330603b705cfSriastradh execbuf.flags = kgem->ring | kgem->batch_flags; 330703b705cfSriastradh 330803b705cfSriastradh if (DBG_DUMP) { 330903b705cfSriastradh int fd = open("/tmp/i915-batchbuffers.dump", 331003b705cfSriastradh O_WRONLY | O_CREAT | O_APPEND, 331103b705cfSriastradh 0666); 331203b705cfSriastradh if (fd != -1) { 331303b705cfSriastradh ret = write(fd, kgem->batch, batch_end*sizeof(uint32_t)); 331403b705cfSriastradh fd = close(fd); 331503b705cfSriastradh } 331603b705cfSriastradh } 331703b705cfSriastradh 33189a906b70Schristos ret = do_execbuf(kgem, &execbuf); 331903b705cfSriastradh if (DEBUG_SYNC && ret == 0) { 332003b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 332103b705cfSriastradh 332203b705cfSriastradh VG_CLEAR(set_domain); 332303b705cfSriastradh set_domain.handle = handle; 332403b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_GTT; 332503b705cfSriastradh set_domain.write_domain = I915_GEM_DOMAIN_GTT; 332603b705cfSriastradh 33279a906b70Schristos ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain); 332803b705cfSriastradh } 33299a906b70Schristos if (ret < 0) { 333003b705cfSriastradh kgem_throttle(kgem); 33319a906b70Schristos if (!kgem->wedged) { 33329a906b70Schristos xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR, 33339a906b70Schristos "Failed to submit rendering commands, disabling acceleration.\n"); 33349a906b70Schristos kgem->wedged = true; 33359a906b70Schristos } 333603b705cfSriastradh 333703b705cfSriastradh#if !NDEBUG 33389a906b70Schristos ErrorF("batch[%d/%d]: %d %d %d, nreloc=%d, nexec=%d, nfence=%d, aperture=%d, fenced=%d, high=%d,%d: errno=%d\n", 333903b705cfSriastradh kgem->mode, kgem->ring, batch_end, kgem->nbatch, kgem->surface, 33409a906b70Schristos kgem->nreloc, kgem->nexec, kgem->nfence, kgem->aperture, kgem->aperture_fenced, kgem->aperture_high, kgem->aperture_total, -ret); 334103b705cfSriastradh 334203b705cfSriastradh for (i = 0; i < kgem->nexec; i++) { 334303b705cfSriastradh struct kgem_bo *bo, *found = NULL; 334403b705cfSriastradh 334503b705cfSriastradh list_for_each_entry(bo, &kgem->next_request->buffers, request) { 334603b705cfSriastradh if (bo->handle == kgem->exec[i].handle) { 334703b705cfSriastradh found = bo; 334803b705cfSriastradh break; 334903b705cfSriastradh } 335003b705cfSriastradh } 335103b705cfSriastradh ErrorF("exec[%d] = handle:%d, presumed offset: %x, size: %d, tiling %d, fenced %d, snooped %d, deleted %d\n", 335203b705cfSriastradh i, 335303b705cfSriastradh kgem->exec[i].handle, 335403b705cfSriastradh (int)kgem->exec[i].offset, 335503b705cfSriastradh found ? kgem_bo_size(found) : -1, 335603b705cfSriastradh found ? found->tiling : -1, 335703b705cfSriastradh (int)(kgem->exec[i].flags & EXEC_OBJECT_NEEDS_FENCE), 335803b705cfSriastradh found ? found->snoop : -1, 335903b705cfSriastradh found ? found->purged : -1); 336003b705cfSriastradh } 336103b705cfSriastradh for (i = 0; i < kgem->nreloc; i++) { 336203b705cfSriastradh ErrorF("reloc[%d] = pos:%d, target:%d, delta:%d, read:%x, write:%x, offset:%x\n", 336303b705cfSriastradh i, 336403b705cfSriastradh (int)kgem->reloc[i].offset, 336503b705cfSriastradh kgem->reloc[i].target_handle, 336603b705cfSriastradh kgem->reloc[i].delta, 336703b705cfSriastradh kgem->reloc[i].read_domains, 336803b705cfSriastradh kgem->reloc[i].write_domain, 336903b705cfSriastradh (int)kgem->reloc[i].presumed_offset); 337003b705cfSriastradh } 337103b705cfSriastradh 33729a906b70Schristos { 33739a906b70Schristos struct drm_i915_gem_get_aperture aperture; 33749a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture) == 0) 33759a906b70Schristos ErrorF("Aperture size %lld, available %lld\n", 33769a906b70Schristos (long long)aperture.aper_size, 33779a906b70Schristos (long long)aperture.aper_available_size); 33789a906b70Schristos } 33799a906b70Schristos 33809a906b70Schristos if (ret == -ENOSPC) 33819a906b70Schristos dump_gtt_info(kgem); 33829a906b70Schristos if (ret == -EDEADLK) 33839a906b70Schristos dump_fence_regs(kgem); 33849a906b70Schristos 338503b705cfSriastradh if (DEBUG_SYNC) { 338603b705cfSriastradh int fd = open("/tmp/batchbuffer", O_WRONLY | O_CREAT | O_APPEND, 0666); 338703b705cfSriastradh if (fd != -1) { 33889a906b70Schristos int ignored = write(fd, kgem->batch, batch_end*sizeof(uint32_t)); 33899a906b70Schristos assert(ignored == batch_end*sizeof(uint32_t)); 339003b705cfSriastradh close(fd); 339103b705cfSriastradh } 339203b705cfSriastradh 33939a906b70Schristos FatalError("SNA: failed to submit batchbuffer, errno=%d\n", -ret); 339403b705cfSriastradh } 339503b705cfSriastradh#endif 339603b705cfSriastradh } 339703b705cfSriastradh } 339803b705cfSriastradh } 33999a906b70Schristos#if SHOW_BATCH_AFTER 34009a906b70Schristos if (gem_read(kgem->fd, rq->bo->handle, kgem->batch, 0, batch_end*sizeof(uint32_t) == 0)) 34019a906b70Schristos __kgem_batch_debug(kgem, batch_end); 34029a906b70Schristos#endif 34039a906b70Schristos kgem_commit(kgem); 340403b705cfSriastradh if (kgem->wedged) 340503b705cfSriastradh kgem_cleanup(kgem); 340603b705cfSriastradh 340703b705cfSriastradh kgem_reset(kgem); 340803b705cfSriastradh 340903b705cfSriastradh assert(kgem->next_request != NULL); 341003b705cfSriastradh} 341103b705cfSriastradh 34129a906b70Schristosstatic bool find_hang_state(struct kgem *kgem, char *path, int maxlen) 341303b705cfSriastradh{ 34149a906b70Schristos int minor = kgem_get_minor(kgem); 341503b705cfSriastradh 341603b705cfSriastradh /* Search for our hang state in a few canonical locations. 341703b705cfSriastradh * In the unlikely event of having multiple devices, we 341803b705cfSriastradh * will need to check which minor actually corresponds to ours. 341903b705cfSriastradh */ 342003b705cfSriastradh 34219a906b70Schristos snprintf(path, maxlen, "/sys/class/drm/card%d/error", minor); 34229a906b70Schristos if (access(path, R_OK) == 0) 34239a906b70Schristos return true; 342403b705cfSriastradh 34259a906b70Schristos snprintf(path, maxlen, "/sys/kernel/debug/dri/%d/i915_error_state", minor); 34269a906b70Schristos if (access(path, R_OK) == 0) 34279a906b70Schristos return true; 342803b705cfSriastradh 34299a906b70Schristos snprintf(path, maxlen, "/debug/dri/%d/i915_error_state", minor); 34309a906b70Schristos if (access(path, R_OK) == 0) 34319a906b70Schristos return true; 343203b705cfSriastradh 343303b705cfSriastradh path[0] = '\0'; 34349a906b70Schristos return false; 343503b705cfSriastradh} 343603b705cfSriastradh 343703b705cfSriastradhvoid kgem_throttle(struct kgem *kgem) 343803b705cfSriastradh{ 343903b705cfSriastradh if (kgem->wedged) 344003b705cfSriastradh return; 344103b705cfSriastradh 34429a906b70Schristos kgem->wedged = __kgem_throttle(kgem, true); 344303b705cfSriastradh if (kgem->wedged) { 34449a906b70Schristos static int once; 344503b705cfSriastradh char path[128]; 344603b705cfSriastradh 344703b705cfSriastradh xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR, 344803b705cfSriastradh "Detected a hung GPU, disabling acceleration.\n"); 34499a906b70Schristos if (!once && find_hang_state(kgem, path, sizeof(path))) { 345003b705cfSriastradh xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR, 345103b705cfSriastradh "When reporting this, please include %s and the full dmesg.\n", 345203b705cfSriastradh path); 34539a906b70Schristos once = 1; 34549a906b70Schristos } 34559a906b70Schristos 34569a906b70Schristos kgem->need_throttle = false; 345703b705cfSriastradh } 345803b705cfSriastradh} 345903b705cfSriastradh 34609a906b70Schristosint kgem_is_wedged(struct kgem *kgem) 34619a906b70Schristos{ 34629a906b70Schristos return __kgem_throttle(kgem, true); 34639a906b70Schristos} 34649a906b70Schristos 34659a906b70Schristosstatic void kgem_purge_cache(struct kgem *kgem) 346603b705cfSriastradh{ 346703b705cfSriastradh struct kgem_bo *bo, *next; 346803b705cfSriastradh int i; 346903b705cfSriastradh 347003b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) { 347103b705cfSriastradh list_for_each_entry_safe(bo, next, &kgem->inactive[i], list) { 347203b705cfSriastradh if (!kgem_bo_is_retained(kgem, bo)) { 347303b705cfSriastradh DBG(("%s: purging %d\n", 347403b705cfSriastradh __FUNCTION__, bo->handle)); 347503b705cfSriastradh kgem_bo_free(kgem, bo); 347603b705cfSriastradh } 347703b705cfSriastradh } 347803b705cfSriastradh } 347903b705cfSriastradh 348003b705cfSriastradh kgem->need_purge = false; 348103b705cfSriastradh} 348203b705cfSriastradh 348303b705cfSriastradhvoid kgem_clean_scanout_cache(struct kgem *kgem) 348403b705cfSriastradh{ 348503b705cfSriastradh while (!list_is_empty(&kgem->scanout)) { 348603b705cfSriastradh struct kgem_bo *bo; 348703b705cfSriastradh 348803b705cfSriastradh bo = list_first_entry(&kgem->scanout, struct kgem_bo, list); 348903b705cfSriastradh 349003b705cfSriastradh assert(bo->scanout); 349103b705cfSriastradh assert(!bo->refcnt); 34929a906b70Schristos assert(!bo->prime); 349303b705cfSriastradh assert(bo->proxy == NULL); 349403b705cfSriastradh 349503b705cfSriastradh if (bo->exec || __kgem_busy(kgem, bo->handle)) 349603b705cfSriastradh break; 349703b705cfSriastradh 349803b705cfSriastradh DBG(("%s: handle=%d, fb=%d (reusable=%d)\n", 349903b705cfSriastradh __FUNCTION__, bo->handle, bo->delta, bo->reusable)); 350003b705cfSriastradh list_del(&bo->list); 350103b705cfSriastradh 35029a906b70Schristos kgem_bo_rmfb(kgem, bo); 350303b705cfSriastradh bo->scanout = false; 350403b705cfSriastradh 350503b705cfSriastradh if (!bo->purged) { 350603b705cfSriastradh bo->reusable = true; 350703b705cfSriastradh if (kgem->has_llc && 350803b705cfSriastradh !gem_set_caching(kgem->fd, bo->handle, SNOOPED)) 350903b705cfSriastradh bo->reusable = false; 351003b705cfSriastradh 351103b705cfSriastradh } 351203b705cfSriastradh 351303b705cfSriastradh __kgem_bo_destroy(kgem, bo); 351403b705cfSriastradh } 351503b705cfSriastradh} 351603b705cfSriastradh 351703b705cfSriastradhvoid kgem_clean_large_cache(struct kgem *kgem) 351803b705cfSriastradh{ 351903b705cfSriastradh while (!list_is_empty(&kgem->large_inactive)) { 352003b705cfSriastradh kgem_bo_free(kgem, 352103b705cfSriastradh list_first_entry(&kgem->large_inactive, 352203b705cfSriastradh struct kgem_bo, list)); 352303b705cfSriastradh 352403b705cfSriastradh } 352503b705cfSriastradh} 352603b705cfSriastradh 352703b705cfSriastradhbool kgem_expire_cache(struct kgem *kgem) 352803b705cfSriastradh{ 352903b705cfSriastradh time_t now, expire; 353003b705cfSriastradh struct kgem_bo *bo; 353103b705cfSriastradh unsigned int size = 0, count = 0; 353203b705cfSriastradh bool idle; 353303b705cfSriastradh unsigned int i; 353403b705cfSriastradh 353503b705cfSriastradh time(&now); 353603b705cfSriastradh 353703b705cfSriastradh while (__kgem_freed_bo) { 353803b705cfSriastradh bo = __kgem_freed_bo; 353903b705cfSriastradh __kgem_freed_bo = *(struct kgem_bo **)bo; 354003b705cfSriastradh free(bo); 354103b705cfSriastradh } 354203b705cfSriastradh 354303b705cfSriastradh while (__kgem_freed_request) { 354403b705cfSriastradh struct kgem_request *rq = __kgem_freed_request; 354503b705cfSriastradh __kgem_freed_request = *(struct kgem_request **)rq; 354603b705cfSriastradh free(rq); 354703b705cfSriastradh } 354803b705cfSriastradh 354903b705cfSriastradh kgem_clean_large_cache(kgem); 355003b705cfSriastradh if (container_of(kgem, struct sna, kgem)->scrn->vtSema) 355103b705cfSriastradh kgem_clean_scanout_cache(kgem); 355203b705cfSriastradh 355303b705cfSriastradh expire = 0; 355403b705cfSriastradh list_for_each_entry(bo, &kgem->snoop, list) { 355503b705cfSriastradh if (bo->delta) { 355603b705cfSriastradh expire = now - MAX_INACTIVE_TIME/2; 355703b705cfSriastradh break; 355803b705cfSriastradh } 355903b705cfSriastradh 356003b705cfSriastradh bo->delta = now; 356103b705cfSriastradh } 356203b705cfSriastradh if (expire) { 356303b705cfSriastradh while (!list_is_empty(&kgem->snoop)) { 356403b705cfSriastradh bo = list_last_entry(&kgem->snoop, struct kgem_bo, list); 356503b705cfSriastradh 356603b705cfSriastradh if (bo->delta > expire) 356703b705cfSriastradh break; 356803b705cfSriastradh 356903b705cfSriastradh kgem_bo_free(kgem, bo); 357003b705cfSriastradh } 357103b705cfSriastradh } 357203b705cfSriastradh#ifdef DEBUG_MEMORY 357303b705cfSriastradh { 357403b705cfSriastradh long snoop_size = 0; 357503b705cfSriastradh int snoop_count = 0; 357603b705cfSriastradh list_for_each_entry(bo, &kgem->snoop, list) 357703b705cfSriastradh snoop_count++, snoop_size += bytes(bo); 35789a906b70Schristos DBG(("%s: still allocated %d bo, %ld bytes, in snoop cache\n", 35799a906b70Schristos __FUNCTION__, snoop_count, snoop_size)); 358003b705cfSriastradh } 358103b705cfSriastradh#endif 358203b705cfSriastradh 358303b705cfSriastradh kgem_retire(kgem); 358403b705cfSriastradh if (kgem->wedged) 358503b705cfSriastradh kgem_cleanup(kgem); 358603b705cfSriastradh 358703b705cfSriastradh kgem->expire(kgem); 358803b705cfSriastradh 358903b705cfSriastradh if (kgem->need_purge) 359003b705cfSriastradh kgem_purge_cache(kgem); 359103b705cfSriastradh 35929a906b70Schristos if (kgem->need_retire) 35939a906b70Schristos kgem_retire(kgem); 359403b705cfSriastradh 35959a906b70Schristos expire = 0; 35969a906b70Schristos idle = true; 359703b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) { 359803b705cfSriastradh idle &= list_is_empty(&kgem->inactive[i]); 359903b705cfSriastradh list_for_each_entry(bo, &kgem->inactive[i], list) { 360003b705cfSriastradh if (bo->delta) { 360103b705cfSriastradh expire = now - MAX_INACTIVE_TIME; 360203b705cfSriastradh break; 360303b705cfSriastradh } 360403b705cfSriastradh 360503b705cfSriastradh bo->delta = now; 360603b705cfSriastradh } 360703b705cfSriastradh } 36089a906b70Schristos if (expire == 0) { 36099a906b70Schristos DBG(("%s: idle? %d\n", __FUNCTION__, idle)); 36109a906b70Schristos kgem->need_expire = !idle; 361103b705cfSriastradh return false; 361203b705cfSriastradh } 361303b705cfSriastradh 36149a906b70Schristos idle = true; 361503b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) { 361603b705cfSriastradh struct list preserve; 361703b705cfSriastradh 361803b705cfSriastradh list_init(&preserve); 361903b705cfSriastradh while (!list_is_empty(&kgem->inactive[i])) { 362003b705cfSriastradh bo = list_last_entry(&kgem->inactive[i], 362103b705cfSriastradh struct kgem_bo, list); 362203b705cfSriastradh 362303b705cfSriastradh if (bo->delta > expire) { 362403b705cfSriastradh idle = false; 362503b705cfSriastradh break; 362603b705cfSriastradh } 362703b705cfSriastradh 36289a906b70Schristos if (bo->map__cpu && bo->delta + MAP_PRESERVE_TIME > expire) { 362903b705cfSriastradh idle = false; 363003b705cfSriastradh list_move_tail(&bo->list, &preserve); 363103b705cfSriastradh } else { 363203b705cfSriastradh count++; 363303b705cfSriastradh size += bytes(bo); 363403b705cfSriastradh kgem_bo_free(kgem, bo); 363503b705cfSriastradh DBG(("%s: expiring %d\n", 363603b705cfSriastradh __FUNCTION__, bo->handle)); 363703b705cfSriastradh } 363803b705cfSriastradh } 363903b705cfSriastradh if (!list_is_empty(&preserve)) { 364003b705cfSriastradh preserve.prev->next = kgem->inactive[i].next; 364103b705cfSriastradh kgem->inactive[i].next->prev = preserve.prev; 364203b705cfSriastradh kgem->inactive[i].next = preserve.next; 364303b705cfSriastradh preserve.next->prev = &kgem->inactive[i]; 364403b705cfSriastradh } 364503b705cfSriastradh } 364603b705cfSriastradh 364703b705cfSriastradh#ifdef DEBUG_MEMORY 364803b705cfSriastradh { 364903b705cfSriastradh long inactive_size = 0; 365003b705cfSriastradh int inactive_count = 0; 365103b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) 365203b705cfSriastradh list_for_each_entry(bo, &kgem->inactive[i], list) 365303b705cfSriastradh inactive_count++, inactive_size += bytes(bo); 36549a906b70Schristos DBG(("%s: still allocated %d bo, %ld bytes, in inactive cache\n", 36559a906b70Schristos __FUNCTION__, inactive_count, inactive_size)); 365603b705cfSriastradh } 365703b705cfSriastradh#endif 365803b705cfSriastradh 365903b705cfSriastradh DBG(("%s: expired %d objects, %d bytes, idle? %d\n", 366003b705cfSriastradh __FUNCTION__, count, size, idle)); 366103b705cfSriastradh 366203b705cfSriastradh kgem->need_expire = !idle; 36639a906b70Schristos return count; 366403b705cfSriastradh (void)count; 366503b705cfSriastradh (void)size; 366603b705cfSriastradh} 366703b705cfSriastradh 36689a906b70Schristosbool kgem_cleanup_cache(struct kgem *kgem) 366903b705cfSriastradh{ 367003b705cfSriastradh unsigned int i; 367103b705cfSriastradh int n; 367203b705cfSriastradh 367303b705cfSriastradh /* sync to the most recent request */ 367403b705cfSriastradh for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) { 367503b705cfSriastradh if (!list_is_empty(&kgem->requests[n])) { 367603b705cfSriastradh struct kgem_request *rq; 367703b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 367803b705cfSriastradh 367903b705cfSriastradh rq = list_first_entry(&kgem->requests[n], 368003b705cfSriastradh struct kgem_request, 368103b705cfSriastradh list); 368203b705cfSriastradh 368303b705cfSriastradh DBG(("%s: sync on cleanup\n", __FUNCTION__)); 368403b705cfSriastradh 368503b705cfSriastradh VG_CLEAR(set_domain); 368603b705cfSriastradh set_domain.handle = rq->bo->handle; 368703b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_GTT; 368803b705cfSriastradh set_domain.write_domain = I915_GEM_DOMAIN_GTT; 36899a906b70Schristos (void)do_ioctl(kgem->fd, 369003b705cfSriastradh DRM_IOCTL_I915_GEM_SET_DOMAIN, 369103b705cfSriastradh &set_domain); 369203b705cfSriastradh } 369303b705cfSriastradh } 369403b705cfSriastradh 369503b705cfSriastradh kgem_retire(kgem); 369603b705cfSriastradh kgem_cleanup(kgem); 369703b705cfSriastradh 36989a906b70Schristos if (!kgem->need_expire) 36999a906b70Schristos return false; 37009a906b70Schristos 370103b705cfSriastradh for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) { 370203b705cfSriastradh while (!list_is_empty(&kgem->inactive[i])) 370303b705cfSriastradh kgem_bo_free(kgem, 370403b705cfSriastradh list_last_entry(&kgem->inactive[i], 370503b705cfSriastradh struct kgem_bo, list)); 370603b705cfSriastradh } 370703b705cfSriastradh 370803b705cfSriastradh kgem_clean_large_cache(kgem); 370903b705cfSriastradh kgem_clean_scanout_cache(kgem); 371003b705cfSriastradh 371103b705cfSriastradh while (!list_is_empty(&kgem->snoop)) 371203b705cfSriastradh kgem_bo_free(kgem, 371303b705cfSriastradh list_last_entry(&kgem->snoop, 371403b705cfSriastradh struct kgem_bo, list)); 371503b705cfSriastradh 371603b705cfSriastradh while (__kgem_freed_bo) { 371703b705cfSriastradh struct kgem_bo *bo = __kgem_freed_bo; 371803b705cfSriastradh __kgem_freed_bo = *(struct kgem_bo **)bo; 371903b705cfSriastradh free(bo); 372003b705cfSriastradh } 372103b705cfSriastradh 372203b705cfSriastradh kgem->need_purge = false; 372303b705cfSriastradh kgem->need_expire = false; 37249a906b70Schristos return true; 372503b705cfSriastradh} 372603b705cfSriastradh 372703b705cfSriastradhstatic struct kgem_bo * 372803b705cfSriastradhsearch_linear_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags) 372903b705cfSriastradh{ 373003b705cfSriastradh struct kgem_bo *bo, *first = NULL; 373103b705cfSriastradh bool use_active = (flags & CREATE_INACTIVE) == 0; 373203b705cfSriastradh struct list *cache; 373303b705cfSriastradh 373403b705cfSriastradh DBG(("%s: num_pages=%d, flags=%x, use_active? %d, use_large=%d [max=%d]\n", 373503b705cfSriastradh __FUNCTION__, num_pages, flags, use_active, 373603b705cfSriastradh num_pages >= MAX_CACHE_SIZE / PAGE_SIZE, 373703b705cfSriastradh MAX_CACHE_SIZE / PAGE_SIZE)); 373803b705cfSriastradh 373903b705cfSriastradh assert(num_pages); 374003b705cfSriastradh 374103b705cfSriastradh if (num_pages >= MAX_CACHE_SIZE / PAGE_SIZE) { 374203b705cfSriastradh DBG(("%s: searching large buffers\n", __FUNCTION__)); 374303b705cfSriastradhretry_large: 374403b705cfSriastradh cache = use_active ? &kgem->large : &kgem->large_inactive; 374503b705cfSriastradh list_for_each_entry_safe(bo, first, cache, list) { 374603b705cfSriastradh assert(bo->refcnt == 0); 374703b705cfSriastradh assert(bo->reusable); 374803b705cfSriastradh assert(!bo->scanout); 374903b705cfSriastradh 375003b705cfSriastradh if (num_pages > num_pages(bo)) 375103b705cfSriastradh goto discard; 375203b705cfSriastradh 375303b705cfSriastradh if (bo->tiling != I915_TILING_NONE) { 375403b705cfSriastradh if (use_active) 375503b705cfSriastradh goto discard; 375603b705cfSriastradh 375703b705cfSriastradh if (!gem_set_tiling(kgem->fd, bo->handle, 375803b705cfSriastradh I915_TILING_NONE, 0)) 375903b705cfSriastradh goto discard; 376003b705cfSriastradh 376103b705cfSriastradh bo->tiling = I915_TILING_NONE; 376203b705cfSriastradh bo->pitch = 0; 376303b705cfSriastradh } 376403b705cfSriastradh 376503b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) 376603b705cfSriastradh goto discard; 376703b705cfSriastradh 376803b705cfSriastradh list_del(&bo->list); 37699a906b70Schristos if (RQ(bo->rq) == (void *)kgem) { 37709a906b70Schristos assert(bo->exec == NULL); 377103b705cfSriastradh list_del(&bo->request); 37729a906b70Schristos } 377303b705cfSriastradh 377403b705cfSriastradh bo->delta = 0; 377503b705cfSriastradh assert_tiling(kgem, bo); 377603b705cfSriastradh return bo; 377703b705cfSriastradh 377803b705cfSriastradhdiscard: 377903b705cfSriastradh if (!use_active) 378003b705cfSriastradh kgem_bo_free(kgem, bo); 378103b705cfSriastradh } 378203b705cfSriastradh 378303b705cfSriastradh if (use_active) { 378403b705cfSriastradh use_active = false; 378503b705cfSriastradh goto retry_large; 378603b705cfSriastradh } 378703b705cfSriastradh 378803b705cfSriastradh if (__kgem_throttle_retire(kgem, flags)) 378903b705cfSriastradh goto retry_large; 379003b705cfSriastradh 379103b705cfSriastradh return NULL; 379203b705cfSriastradh } 379303b705cfSriastradh 379403b705cfSriastradh if (!use_active && list_is_empty(inactive(kgem, num_pages))) { 379503b705cfSriastradh DBG(("%s: inactive and cache bucket empty\n", 379603b705cfSriastradh __FUNCTION__)); 379703b705cfSriastradh 379803b705cfSriastradh if (flags & CREATE_NO_RETIRE) { 379903b705cfSriastradh DBG(("%s: can not retire\n", __FUNCTION__)); 380003b705cfSriastradh return NULL; 380103b705cfSriastradh } 380203b705cfSriastradh 380303b705cfSriastradh if (list_is_empty(active(kgem, num_pages, I915_TILING_NONE))) { 380403b705cfSriastradh DBG(("%s: active cache bucket empty\n", __FUNCTION__)); 380503b705cfSriastradh return NULL; 380603b705cfSriastradh } 380703b705cfSriastradh 380803b705cfSriastradh if (!__kgem_throttle_retire(kgem, flags)) { 380903b705cfSriastradh DBG(("%s: nothing retired\n", __FUNCTION__)); 381003b705cfSriastradh return NULL; 381103b705cfSriastradh } 381203b705cfSriastradh 381303b705cfSriastradh if (list_is_empty(inactive(kgem, num_pages))) { 381403b705cfSriastradh DBG(("%s: active cache bucket still empty after retire\n", 381503b705cfSriastradh __FUNCTION__)); 381603b705cfSriastradh return NULL; 381703b705cfSriastradh } 381803b705cfSriastradh } 381903b705cfSriastradh 382003b705cfSriastradh if (!use_active && flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { 382103b705cfSriastradh int for_cpu = !!(flags & CREATE_CPU_MAP); 382203b705cfSriastradh DBG(("%s: searching for inactive %s map\n", 382303b705cfSriastradh __FUNCTION__, for_cpu ? "cpu" : "gtt")); 382403b705cfSriastradh cache = &kgem->vma[for_cpu].inactive[cache_bucket(num_pages)]; 382503b705cfSriastradh list_for_each_entry(bo, cache, vma) { 38269a906b70Schristos assert(for_cpu ? bo->map__cpu : bo->map__gtt); 382703b705cfSriastradh assert(bucket(bo) == cache_bucket(num_pages)); 382803b705cfSriastradh assert(bo->proxy == NULL); 382903b705cfSriastradh assert(bo->rq == NULL); 383003b705cfSriastradh assert(bo->exec == NULL); 383103b705cfSriastradh assert(!bo->scanout); 383203b705cfSriastradh 383303b705cfSriastradh if (num_pages > num_pages(bo)) { 383403b705cfSriastradh DBG(("inactive too small: %d < %d\n", 383503b705cfSriastradh num_pages(bo), num_pages)); 383603b705cfSriastradh continue; 383703b705cfSriastradh } 383803b705cfSriastradh 383903b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { 384003b705cfSriastradh kgem_bo_free(kgem, bo); 384103b705cfSriastradh break; 384203b705cfSriastradh } 384303b705cfSriastradh 384403b705cfSriastradh if (I915_TILING_NONE != bo->tiling && 384503b705cfSriastradh !gem_set_tiling(kgem->fd, bo->handle, 384603b705cfSriastradh I915_TILING_NONE, 0)) 384703b705cfSriastradh continue; 384803b705cfSriastradh 384903b705cfSriastradh kgem_bo_remove_from_inactive(kgem, bo); 38509a906b70Schristos assert(list_is_empty(&bo->vma)); 38519a906b70Schristos assert(list_is_empty(&bo->list)); 385203b705cfSriastradh 385303b705cfSriastradh bo->tiling = I915_TILING_NONE; 385403b705cfSriastradh bo->pitch = 0; 385503b705cfSriastradh bo->delta = 0; 385603b705cfSriastradh DBG((" %s: found handle=%d (num_pages=%d) in linear vma cache\n", 385703b705cfSriastradh __FUNCTION__, bo->handle, num_pages(bo))); 385803b705cfSriastradh assert(use_active || bo->domain != DOMAIN_GPU); 385903b705cfSriastradh assert(!bo->needs_flush); 386003b705cfSriastradh assert_tiling(kgem, bo); 386103b705cfSriastradh ASSERT_MAYBE_IDLE(kgem, bo->handle, !use_active); 386203b705cfSriastradh return bo; 386303b705cfSriastradh } 386403b705cfSriastradh 386503b705cfSriastradh if (flags & CREATE_EXACT) 386603b705cfSriastradh return NULL; 386703b705cfSriastradh 386803b705cfSriastradh if (flags & CREATE_CPU_MAP && !kgem->has_llc) 386903b705cfSriastradh return NULL; 387003b705cfSriastradh } 387103b705cfSriastradh 387203b705cfSriastradh cache = use_active ? active(kgem, num_pages, I915_TILING_NONE) : inactive(kgem, num_pages); 387303b705cfSriastradh list_for_each_entry(bo, cache, list) { 387403b705cfSriastradh assert(bo->refcnt == 0); 387503b705cfSriastradh assert(bo->reusable); 387603b705cfSriastradh assert(!!bo->rq == !!use_active); 387703b705cfSriastradh assert(bo->proxy == NULL); 387803b705cfSriastradh assert(!bo->scanout); 387903b705cfSriastradh 388003b705cfSriastradh if (num_pages > num_pages(bo)) 388103b705cfSriastradh continue; 388203b705cfSriastradh 388303b705cfSriastradh if (use_active && 388403b705cfSriastradh kgem->gen <= 040 && 388503b705cfSriastradh bo->tiling != I915_TILING_NONE) 388603b705cfSriastradh continue; 388703b705cfSriastradh 388803b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { 388903b705cfSriastradh kgem_bo_free(kgem, bo); 389003b705cfSriastradh break; 389103b705cfSriastradh } 389203b705cfSriastradh 389303b705cfSriastradh if (I915_TILING_NONE != bo->tiling) { 389403b705cfSriastradh if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) 389503b705cfSriastradh continue; 389603b705cfSriastradh 389703b705cfSriastradh if (first) 389803b705cfSriastradh continue; 389903b705cfSriastradh 390003b705cfSriastradh if (!gem_set_tiling(kgem->fd, bo->handle, 390103b705cfSriastradh I915_TILING_NONE, 0)) 390203b705cfSriastradh continue; 390303b705cfSriastradh 390403b705cfSriastradh bo->tiling = I915_TILING_NONE; 390503b705cfSriastradh bo->pitch = 0; 390603b705cfSriastradh } 390703b705cfSriastradh 39089a906b70Schristos if (bo->map__gtt || bo->map__cpu) { 390903b705cfSriastradh if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { 391003b705cfSriastradh int for_cpu = !!(flags & CREATE_CPU_MAP); 39119a906b70Schristos if (for_cpu ? bo->map__cpu : bo->map__gtt){ 391203b705cfSriastradh if (first != NULL) 391303b705cfSriastradh break; 391403b705cfSriastradh 391503b705cfSriastradh first = bo; 391603b705cfSriastradh continue; 391703b705cfSriastradh } 391803b705cfSriastradh } else { 391903b705cfSriastradh if (first != NULL) 392003b705cfSriastradh break; 392103b705cfSriastradh 392203b705cfSriastradh first = bo; 392303b705cfSriastradh continue; 392403b705cfSriastradh } 392503b705cfSriastradh } else { 39269a906b70Schristos if (flags & CREATE_GTT_MAP && !kgem_bo_can_map(kgem, bo)) 39279a906b70Schristos continue; 39289a906b70Schristos 392903b705cfSriastradh if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { 393003b705cfSriastradh if (first != NULL) 393103b705cfSriastradh break; 393203b705cfSriastradh 393303b705cfSriastradh first = bo; 393403b705cfSriastradh continue; 393503b705cfSriastradh } 393603b705cfSriastradh } 393703b705cfSriastradh 393803b705cfSriastradh if (use_active) 393903b705cfSriastradh kgem_bo_remove_from_active(kgem, bo); 394003b705cfSriastradh else 394103b705cfSriastradh kgem_bo_remove_from_inactive(kgem, bo); 394203b705cfSriastradh 394303b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 394403b705cfSriastradh bo->pitch = 0; 394503b705cfSriastradh bo->delta = 0; 394603b705cfSriastradh DBG((" %s: found handle=%d (num_pages=%d) in linear %s cache\n", 394703b705cfSriastradh __FUNCTION__, bo->handle, num_pages(bo), 394803b705cfSriastradh use_active ? "active" : "inactive")); 394903b705cfSriastradh assert(list_is_empty(&bo->list)); 39509a906b70Schristos assert(list_is_empty(&bo->vma)); 395103b705cfSriastradh assert(use_active || bo->domain != DOMAIN_GPU); 395203b705cfSriastradh assert(!bo->needs_flush || use_active); 395303b705cfSriastradh assert_tiling(kgem, bo); 395403b705cfSriastradh ASSERT_MAYBE_IDLE(kgem, bo->handle, !use_active); 395503b705cfSriastradh return bo; 395603b705cfSriastradh } 395703b705cfSriastradh 395803b705cfSriastradh if (first) { 395903b705cfSriastradh assert(first->tiling == I915_TILING_NONE); 396003b705cfSriastradh 396103b705cfSriastradh if (use_active) 396203b705cfSriastradh kgem_bo_remove_from_active(kgem, first); 396303b705cfSriastradh else 396403b705cfSriastradh kgem_bo_remove_from_inactive(kgem, first); 396503b705cfSriastradh 396603b705cfSriastradh first->pitch = 0; 396703b705cfSriastradh first->delta = 0; 396803b705cfSriastradh DBG((" %s: found handle=%d (near-miss) (num_pages=%d) in linear %s cache\n", 396903b705cfSriastradh __FUNCTION__, first->handle, num_pages(first), 397003b705cfSriastradh use_active ? "active" : "inactive")); 397103b705cfSriastradh assert(list_is_empty(&first->list)); 39729a906b70Schristos assert(list_is_empty(&first->vma)); 397303b705cfSriastradh assert(use_active || first->domain != DOMAIN_GPU); 397403b705cfSriastradh assert(!first->needs_flush || use_active); 397503b705cfSriastradh ASSERT_MAYBE_IDLE(kgem, first->handle, !use_active); 397603b705cfSriastradh return first; 397703b705cfSriastradh } 397803b705cfSriastradh 397903b705cfSriastradh return NULL; 398003b705cfSriastradh} 398103b705cfSriastradh 398203b705cfSriastradhstruct kgem_bo *kgem_create_for_name(struct kgem *kgem, uint32_t name) 398303b705cfSriastradh{ 398403b705cfSriastradh struct drm_gem_open open_arg; 39859a906b70Schristos struct drm_i915_gem_get_tiling tiling; 398603b705cfSriastradh struct kgem_bo *bo; 398703b705cfSriastradh 398803b705cfSriastradh DBG(("%s(name=%d)\n", __FUNCTION__, name)); 398903b705cfSriastradh 399003b705cfSriastradh VG_CLEAR(open_arg); 399103b705cfSriastradh open_arg.name = name; 39929a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_GEM_OPEN, &open_arg)) 399303b705cfSriastradh return NULL; 399403b705cfSriastradh 399503b705cfSriastradh DBG(("%s: new handle=%d\n", __FUNCTION__, open_arg.handle)); 39969a906b70Schristos 39979a906b70Schristos VG_CLEAR(tiling); 39989a906b70Schristos tiling.handle = open_arg.handle; 39999a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling)) { 40009a906b70Schristos DBG(("%s(name=%d) get-tiling failed, ret=%d\n", __FUNCTION__, name, errno)); 40019a906b70Schristos gem_close(kgem->fd, open_arg.handle); 40029a906b70Schristos return NULL; 40039a906b70Schristos } 40049a906b70Schristos 40059a906b70Schristos DBG(("%s: handle=%d, tiling=%d\n", __FUNCTION__, tiling.handle, tiling.tiling_mode)); 40069a906b70Schristos 400703b705cfSriastradh bo = __kgem_bo_alloc(open_arg.handle, open_arg.size / PAGE_SIZE); 400803b705cfSriastradh if (bo == NULL) { 400903b705cfSriastradh gem_close(kgem->fd, open_arg.handle); 401003b705cfSriastradh return NULL; 401103b705cfSriastradh } 401203b705cfSriastradh 40139a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 40149a906b70Schristos bo->tiling = tiling.tiling_mode; 401503b705cfSriastradh bo->reusable = false; 40169a906b70Schristos bo->prime = true; 40179a906b70Schristos bo->purged = true; /* no coherency guarantees */ 401803b705cfSriastradh 401903b705cfSriastradh debug_alloc__bo(kgem, bo); 402003b705cfSriastradh return bo; 402103b705cfSriastradh} 402203b705cfSriastradh 402303b705cfSriastradhstruct kgem_bo *kgem_create_for_prime(struct kgem *kgem, int name, uint32_t size) 402403b705cfSriastradh{ 402503b705cfSriastradh#ifdef DRM_IOCTL_PRIME_FD_TO_HANDLE 402603b705cfSriastradh struct drm_prime_handle args; 402703b705cfSriastradh struct drm_i915_gem_get_tiling tiling; 40289a906b70Schristos struct local_i915_gem_caching caching; 402903b705cfSriastradh struct kgem_bo *bo; 40309a906b70Schristos off_t seek; 403103b705cfSriastradh 403203b705cfSriastradh DBG(("%s(name=%d)\n", __FUNCTION__, name)); 403303b705cfSriastradh 403403b705cfSriastradh VG_CLEAR(args); 403503b705cfSriastradh args.fd = name; 403603b705cfSriastradh args.flags = 0; 40379a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args)) { 40389a906b70Schristos DBG(("%s(name=%d) fd-to-handle failed, ret=%d\n", __FUNCTION__, name, errno)); 403903b705cfSriastradh return NULL; 40409a906b70Schristos } 404103b705cfSriastradh 404203b705cfSriastradh VG_CLEAR(tiling); 404303b705cfSriastradh tiling.handle = args.handle; 40449a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling)) { 40459a906b70Schristos DBG(("%s(name=%d) get-tiling failed, ret=%d\n", __FUNCTION__, name, errno)); 404603b705cfSriastradh gem_close(kgem->fd, args.handle); 404703b705cfSriastradh return NULL; 404803b705cfSriastradh } 404903b705cfSriastradh 40509a906b70Schristos /* Query actual size, overriding specified if available */ 40519a906b70Schristos seek = lseek(args.fd, 0, SEEK_END); 40529a906b70Schristos DBG(("%s: estimated size=%ld, actual=%lld\n", 40539a906b70Schristos __FUNCTION__, (long)size, (long long)seek)); 40549a906b70Schristos if (seek != -1) { 40559a906b70Schristos if (size > seek) { 40569a906b70Schristos DBG(("%s(name=%d) estimated required size [%d] is larger than actual [%ld]\n", __FUNCTION__, name, size, (long)seek)); 40579a906b70Schristos gem_close(kgem->fd, args.handle); 40589a906b70Schristos return NULL; 40599a906b70Schristos } 40609a906b70Schristos size = seek; 40619a906b70Schristos } 40629a906b70Schristos 406303b705cfSriastradh DBG(("%s: new handle=%d, tiling=%d\n", __FUNCTION__, 406403b705cfSriastradh args.handle, tiling.tiling_mode)); 406503b705cfSriastradh bo = __kgem_bo_alloc(args.handle, NUM_PAGES(size)); 406603b705cfSriastradh if (bo == NULL) { 406703b705cfSriastradh gem_close(kgem->fd, args.handle); 406803b705cfSriastradh return NULL; 406903b705cfSriastradh } 407003b705cfSriastradh 40719a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 407203b705cfSriastradh bo->tiling = tiling.tiling_mode; 407303b705cfSriastradh bo->reusable = false; 40749a906b70Schristos bo->prime = true; 40759a906b70Schristos bo->domain = DOMAIN_NONE; 40769a906b70Schristos 40779a906b70Schristos /* is this a special bo (e.g. scanout or CPU coherent)? */ 40789a906b70Schristos 40799a906b70Schristos VG_CLEAR(caching); 40809a906b70Schristos caching.handle = args.handle; 40819a906b70Schristos caching.caching = kgem->has_llc; 40829a906b70Schristos (void)drmIoctl(kgem->fd, LOCAL_IOCTL_I915_GEM_GET_CACHING, &caching); 40839a906b70Schristos DBG(("%s: imported handle=%d has caching %d\n", __FUNCTION__, args.handle, caching.caching)); 40849a906b70Schristos switch (caching.caching) { 40859a906b70Schristos case 0: 40869a906b70Schristos if (kgem->has_llc) { 40879a906b70Schristos DBG(("%s: interpreting handle=%d as a foreign scanout\n", 40889a906b70Schristos __FUNCTION__, args.handle)); 40899a906b70Schristos bo->scanout = true; 40909a906b70Schristos } 40919a906b70Schristos break; 40929a906b70Schristos case 1: 40939a906b70Schristos if (!kgem->has_llc) { 40949a906b70Schristos DBG(("%s: interpreting handle=%d as a foreign snooped buffer\n", 40959a906b70Schristos __FUNCTION__, args.handle)); 40969a906b70Schristos bo->snoop = true; 40979a906b70Schristos if (bo->tiling) { 40989a906b70Schristos DBG(("%s: illegal snooped tiled buffer\n", __FUNCTION__)); 40999a906b70Schristos kgem_bo_free(kgem, bo); 41009a906b70Schristos return NULL; 41019a906b70Schristos } 41029a906b70Schristos } 41039a906b70Schristos break; 41049a906b70Schristos case 2: 41059a906b70Schristos DBG(("%s: interpreting handle=%d as a foreign scanout\n", 41069a906b70Schristos __FUNCTION__, args.handle)); 41079a906b70Schristos bo->scanout = true; 41089a906b70Schristos break; 41099a906b70Schristos } 411003b705cfSriastradh 411103b705cfSriastradh debug_alloc__bo(kgem, bo); 411203b705cfSriastradh return bo; 411303b705cfSriastradh#else 411403b705cfSriastradh return NULL; 411503b705cfSriastradh#endif 411603b705cfSriastradh} 411703b705cfSriastradh 411803b705cfSriastradhint kgem_bo_export_to_prime(struct kgem *kgem, struct kgem_bo *bo) 411903b705cfSriastradh{ 412003b705cfSriastradh#if defined(DRM_IOCTL_PRIME_HANDLE_TO_FD) && defined(O_CLOEXEC) 412103b705cfSriastradh struct drm_prime_handle args; 412203b705cfSriastradh 412303b705cfSriastradh VG_CLEAR(args); 412403b705cfSriastradh args.handle = bo->handle; 412503b705cfSriastradh args.flags = O_CLOEXEC; 412603b705cfSriastradh 41279a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args)) 412803b705cfSriastradh return -1; 412903b705cfSriastradh 413003b705cfSriastradh bo->reusable = false; 413103b705cfSriastradh return args.fd; 413203b705cfSriastradh#else 413303b705cfSriastradh return -1; 413403b705cfSriastradh#endif 413503b705cfSriastradh} 413603b705cfSriastradh 413703b705cfSriastradhstruct kgem_bo *kgem_create_linear(struct kgem *kgem, int size, unsigned flags) 413803b705cfSriastradh{ 413903b705cfSriastradh struct kgem_bo *bo; 414003b705cfSriastradh uint32_t handle; 414103b705cfSriastradh 414203b705cfSriastradh DBG(("%s(%d)\n", __FUNCTION__, size)); 414303b705cfSriastradh assert(size); 414403b705cfSriastradh 414503b705cfSriastradh if (flags & CREATE_GTT_MAP && kgem->has_llc) { 414603b705cfSriastradh flags &= ~CREATE_GTT_MAP; 414703b705cfSriastradh flags |= CREATE_CPU_MAP; 414803b705cfSriastradh } 414903b705cfSriastradh 415003b705cfSriastradh size = NUM_PAGES(size); 415103b705cfSriastradh bo = search_linear_cache(kgem, size, CREATE_INACTIVE | flags); 415203b705cfSriastradh if (bo) { 415303b705cfSriastradh assert(bo->domain != DOMAIN_GPU); 415403b705cfSriastradh ASSERT_IDLE(kgem, bo->handle); 415503b705cfSriastradh bo->refcnt = 1; 415603b705cfSriastradh return bo; 415703b705cfSriastradh } 415803b705cfSriastradh 415903b705cfSriastradh if (flags & CREATE_CACHED) 416003b705cfSriastradh return NULL; 416103b705cfSriastradh 416203b705cfSriastradh handle = gem_create(kgem->fd, size); 416303b705cfSriastradh if (handle == 0) 416403b705cfSriastradh return NULL; 416503b705cfSriastradh 416603b705cfSriastradh DBG(("%s: new handle=%d, num_pages=%d\n", __FUNCTION__, handle, size)); 416703b705cfSriastradh bo = __kgem_bo_alloc(handle, size); 416803b705cfSriastradh if (bo == NULL) { 416903b705cfSriastradh gem_close(kgem->fd, handle); 417003b705cfSriastradh return NULL; 417103b705cfSriastradh } 417203b705cfSriastradh 417303b705cfSriastradh debug_alloc__bo(kgem, bo); 417403b705cfSriastradh return bo; 417503b705cfSriastradh} 417603b705cfSriastradh 417703b705cfSriastradhint kgem_choose_tiling(struct kgem *kgem, int tiling, int width, int height, int bpp) 417803b705cfSriastradh{ 417903b705cfSriastradh if (DBG_NO_TILING) 418003b705cfSriastradh return tiling < 0 ? tiling : I915_TILING_NONE; 418103b705cfSriastradh 418203b705cfSriastradh if (kgem->gen < 040) { 418303b705cfSriastradh if (tiling && width * bpp > 8192 * 8) { 418403b705cfSriastradh DBG(("%s: pitch too large for tliing [%d]\n", 418503b705cfSriastradh __FUNCTION__, width*bpp/8)); 418603b705cfSriastradh tiling = I915_TILING_NONE; 418703b705cfSriastradh goto done; 418803b705cfSriastradh } 418903b705cfSriastradh } else { 419003b705cfSriastradh if (width*bpp > (MAXSHORT-512) * 8) { 419103b705cfSriastradh if (tiling > 0) 419203b705cfSriastradh tiling = -tiling; 419303b705cfSriastradh else if (tiling == 0) 419403b705cfSriastradh tiling = -I915_TILING_X; 419503b705cfSriastradh DBG(("%s: large pitch [%d], forcing TILING [%d]\n", 419603b705cfSriastradh __FUNCTION__, width*bpp/8, tiling)); 419703b705cfSriastradh } else if (tiling && (width|height) > 8192) { 419803b705cfSriastradh DBG(("%s: large tiled buffer [%dx%d], forcing TILING_X\n", 419903b705cfSriastradh __FUNCTION__, width, height)); 420003b705cfSriastradh tiling = -I915_TILING_X; 420103b705cfSriastradh } 420203b705cfSriastradh 420303b705cfSriastradh /* fences limited to 128k (256k on ivb) */ 420403b705cfSriastradh assert(width * bpp <= 128 * 1024 * 8); 420503b705cfSriastradh } 420603b705cfSriastradh 420703b705cfSriastradh if (tiling < 0) 420803b705cfSriastradh return tiling; 420903b705cfSriastradh 42109a906b70Schristos if (tiling == I915_TILING_Y && !kgem->can_render_y) 42119a906b70Schristos tiling = I915_TILING_X; 42129a906b70Schristos 421303b705cfSriastradh if (tiling && (height == 1 || width == 1)) { 421403b705cfSriastradh DBG(("%s: disabling tiling [%dx%d] for single row/col\n", 421503b705cfSriastradh __FUNCTION__,width, height)); 421603b705cfSriastradh tiling = I915_TILING_NONE; 421703b705cfSriastradh goto done; 421803b705cfSriastradh } 421903b705cfSriastradh if (tiling == I915_TILING_Y && height <= 16) { 422003b705cfSriastradh DBG(("%s: too short [%d] for TILING_Y\n", 422103b705cfSriastradh __FUNCTION__,height)); 422203b705cfSriastradh tiling = I915_TILING_X; 422303b705cfSriastradh } 422403b705cfSriastradh if (tiling && width * bpp > 8 * (4096 - 64)) { 422503b705cfSriastradh DBG(("%s: TLB miss between lines %dx%d (pitch=%d), forcing tiling %d\n", 422603b705cfSriastradh __FUNCTION__, 422703b705cfSriastradh width, height, width*bpp/8, 422803b705cfSriastradh tiling)); 422903b705cfSriastradh return -tiling; 423003b705cfSriastradh } 423103b705cfSriastradh if (tiling == I915_TILING_X && height < 4) { 423203b705cfSriastradh DBG(("%s: too short [%d] for TILING_X\n", 423303b705cfSriastradh __FUNCTION__, height)); 423403b705cfSriastradh tiling = I915_TILING_NONE; 423503b705cfSriastradh goto done; 423603b705cfSriastradh } 423703b705cfSriastradh 42389a906b70Schristos if (tiling == I915_TILING_X && width * bpp <= 8*512) { 423903b705cfSriastradh DBG(("%s: too thin [width %d, %d bpp] for TILING_X\n", 424003b705cfSriastradh __FUNCTION__, width, bpp)); 424103b705cfSriastradh tiling = I915_TILING_NONE; 424203b705cfSriastradh goto done; 424303b705cfSriastradh } 42449a906b70Schristos if (tiling == I915_TILING_Y && width * bpp < 8*128) { 424503b705cfSriastradh DBG(("%s: too thin [%d] for TILING_Y\n", 424603b705cfSriastradh __FUNCTION__, width)); 424703b705cfSriastradh tiling = I915_TILING_NONE; 424803b705cfSriastradh goto done; 424903b705cfSriastradh } 425003b705cfSriastradh 425103b705cfSriastradh if (tiling && ALIGN(height, 2) * ALIGN(width*bpp, 8*64) <= 4096 * 8) { 425203b705cfSriastradh DBG(("%s: too small [%d bytes] for TILING_%c\n", __FUNCTION__, 425303b705cfSriastradh ALIGN(height, 2) * ALIGN(width*bpp, 8*64) / 8, 425403b705cfSriastradh tiling == I915_TILING_X ? 'X' : 'Y')); 425503b705cfSriastradh tiling = I915_TILING_NONE; 425603b705cfSriastradh goto done; 425703b705cfSriastradh } 425803b705cfSriastradh 425903b705cfSriastradh if (tiling && width * bpp >= 8 * 4096 / 2) { 426003b705cfSriastradh DBG(("%s: TLB near-miss between lines %dx%d (pitch=%d), forcing tiling %d\n", 426103b705cfSriastradh __FUNCTION__, 426203b705cfSriastradh width, height, width*bpp/8, 426303b705cfSriastradh tiling)); 426403b705cfSriastradh return -tiling; 426503b705cfSriastradh } 426603b705cfSriastradh 426703b705cfSriastradhdone: 426803b705cfSriastradh DBG(("%s: %dx%d -> %d\n", __FUNCTION__, width, height, tiling)); 426903b705cfSriastradh return tiling; 427003b705cfSriastradh} 427103b705cfSriastradh 427203b705cfSriastradhstatic int bits_per_pixel(int depth) 427303b705cfSriastradh{ 427403b705cfSriastradh switch (depth) { 427503b705cfSriastradh case 8: return 8; 427603b705cfSriastradh case 15: 427703b705cfSriastradh case 16: return 16; 427803b705cfSriastradh case 24: 427903b705cfSriastradh case 30: 428003b705cfSriastradh case 32: return 32; 428103b705cfSriastradh default: return 0; 428203b705cfSriastradh } 428303b705cfSriastradh} 428403b705cfSriastradh 428503b705cfSriastradhunsigned kgem_can_create_2d(struct kgem *kgem, 428603b705cfSriastradh int width, int height, int depth) 428703b705cfSriastradh{ 428803b705cfSriastradh uint32_t pitch, size; 428903b705cfSriastradh unsigned flags = 0; 429003b705cfSriastradh int tiling; 429103b705cfSriastradh int bpp; 429203b705cfSriastradh 429303b705cfSriastradh DBG(("%s: %dx%d @ %d\n", __FUNCTION__, width, height, depth)); 429403b705cfSriastradh 429503b705cfSriastradh bpp = bits_per_pixel(depth); 429603b705cfSriastradh if (bpp == 0) { 429703b705cfSriastradh DBG(("%s: unhandled depth %d\n", __FUNCTION__, depth)); 429803b705cfSriastradh return 0; 429903b705cfSriastradh } 430003b705cfSriastradh 430103b705cfSriastradh if (width > MAXSHORT || height > MAXSHORT) { 430203b705cfSriastradh DBG(("%s: unhandled size %dx%d\n", 430303b705cfSriastradh __FUNCTION__, width, height)); 430403b705cfSriastradh return 0; 430503b705cfSriastradh } 430603b705cfSriastradh 430703b705cfSriastradh size = kgem_surface_size(kgem, false, 0, 430803b705cfSriastradh width, height, bpp, 430903b705cfSriastradh I915_TILING_NONE, &pitch); 431003b705cfSriastradh DBG(("%s: untiled size=%d\n", __FUNCTION__, size)); 431103b705cfSriastradh if (size > 0) { 431203b705cfSriastradh if (size <= kgem->max_cpu_size) 431303b705cfSriastradh flags |= KGEM_CAN_CREATE_CPU; 43149a906b70Schristos if (size > 4096 && size <= kgem->max_gpu_size) 431503b705cfSriastradh flags |= KGEM_CAN_CREATE_GPU; 43169a906b70Schristos if (size <= PAGE_SIZE*kgem->aperture_mappable/4) 431703b705cfSriastradh flags |= KGEM_CAN_CREATE_GTT; 431803b705cfSriastradh if (size > kgem->large_object_size) 431903b705cfSriastradh flags |= KGEM_CAN_CREATE_LARGE; 432003b705cfSriastradh if (size > kgem->max_object_size) { 432103b705cfSriastradh DBG(("%s: too large (untiled) %d > %d\n", 432203b705cfSriastradh __FUNCTION__, size, kgem->max_object_size)); 432303b705cfSriastradh return 0; 432403b705cfSriastradh } 432503b705cfSriastradh } 432603b705cfSriastradh 432703b705cfSriastradh tiling = kgem_choose_tiling(kgem, I915_TILING_X, 432803b705cfSriastradh width, height, bpp); 432903b705cfSriastradh if (tiling != I915_TILING_NONE) { 433003b705cfSriastradh size = kgem_surface_size(kgem, false, 0, 433103b705cfSriastradh width, height, bpp, tiling, 433203b705cfSriastradh &pitch); 433303b705cfSriastradh DBG(("%s: tiled[%d] size=%d\n", __FUNCTION__, tiling, size)); 433403b705cfSriastradh if (size > 0 && size <= kgem->max_gpu_size) 43359a906b70Schristos flags |= KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_TILED; 43369a906b70Schristos if (size > 0 && size <= PAGE_SIZE*kgem->aperture_mappable/4) 433703b705cfSriastradh flags |= KGEM_CAN_CREATE_GTT; 43389a906b70Schristos if (size > PAGE_SIZE*kgem->aperture_mappable/4) 43399a906b70Schristos flags &= ~KGEM_CAN_CREATE_GTT; 434003b705cfSriastradh if (size > kgem->large_object_size) 434103b705cfSriastradh flags |= KGEM_CAN_CREATE_LARGE; 434203b705cfSriastradh if (size > kgem->max_object_size) { 434303b705cfSriastradh DBG(("%s: too large (tiled) %d > %d\n", 434403b705cfSriastradh __FUNCTION__, size, kgem->max_object_size)); 434503b705cfSriastradh return 0; 434603b705cfSriastradh } 43479a906b70Schristos if (kgem->gen < 040) { 43489a906b70Schristos int fence_size = 1024 * 1024; 43499a906b70Schristos while (fence_size < size) 43509a906b70Schristos fence_size <<= 1; 43519a906b70Schristos if (fence_size > kgem->max_gpu_size) 43529a906b70Schristos flags &= ~KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_TILED; 43539a906b70Schristos if (fence_size > PAGE_SIZE*kgem->aperture_fenceable/4) 43549a906b70Schristos flags &= ~KGEM_CAN_CREATE_GTT; 43559a906b70Schristos } 435603b705cfSriastradh } 435703b705cfSriastradh 435803b705cfSriastradh return flags; 435903b705cfSriastradh} 436003b705cfSriastradh 436103b705cfSriastradhinline int kgem_bo_fenced_size(struct kgem *kgem, struct kgem_bo *bo) 436203b705cfSriastradh{ 436303b705cfSriastradh unsigned int size; 436403b705cfSriastradh 436503b705cfSriastradh assert(bo->tiling); 436603b705cfSriastradh assert_tiling(kgem, bo); 436703b705cfSriastradh assert(kgem->gen < 040); 436803b705cfSriastradh 436903b705cfSriastradh if (kgem->gen < 030) 43709a906b70Schristos size = 512 * 1024 / PAGE_SIZE; 437103b705cfSriastradh else 43729a906b70Schristos size = 1024 * 1024 / PAGE_SIZE; 43739a906b70Schristos while (size < num_pages(bo)) 43749a906b70Schristos size <<= 1; 437503b705cfSriastradh 437603b705cfSriastradh return size; 437703b705cfSriastradh} 437803b705cfSriastradh 437903b705cfSriastradhstatic struct kgem_bo * 438003b705cfSriastradh__kgem_bo_create_as_display(struct kgem *kgem, int size, int tiling, int pitch) 438103b705cfSriastradh{ 438203b705cfSriastradh struct local_i915_gem_create2 args; 438303b705cfSriastradh struct kgem_bo *bo; 438403b705cfSriastradh 438503b705cfSriastradh if (!kgem->has_create2) 438603b705cfSriastradh return NULL; 438703b705cfSriastradh 438803b705cfSriastradh memset(&args, 0, sizeof(args)); 438903b705cfSriastradh args.size = size * PAGE_SIZE; 439003b705cfSriastradh args.placement = LOCAL_I915_CREATE_PLACEMENT_STOLEN; 439103b705cfSriastradh args.caching = DISPLAY; 439203b705cfSriastradh args.tiling_mode = tiling; 439303b705cfSriastradh args.stride = pitch; 439403b705cfSriastradh 43959a906b70Schristos if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_CREATE2, &args)) { 439603b705cfSriastradh args.placement = LOCAL_I915_CREATE_PLACEMENT_SYSTEM; 43979a906b70Schristos if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_CREATE2, &args)) 439803b705cfSriastradh return NULL; 439903b705cfSriastradh } 440003b705cfSriastradh 440103b705cfSriastradh bo = __kgem_bo_alloc(args.handle, size); 440203b705cfSriastradh if (bo == NULL) { 440303b705cfSriastradh gem_close(kgem->fd, args.handle); 440403b705cfSriastradh return NULL; 440503b705cfSriastradh } 440603b705cfSriastradh 440703b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 440803b705cfSriastradh bo->tiling = tiling; 440903b705cfSriastradh bo->pitch = pitch; 441003b705cfSriastradh if (args.placement == LOCAL_I915_CREATE_PLACEMENT_STOLEN) { 441103b705cfSriastradh bo->purged = true; /* for asserts against CPU access */ 441203b705cfSriastradh } 441303b705cfSriastradh bo->reusable = false; /* so that unclaimed scanouts are freed */ 441403b705cfSriastradh bo->domain = DOMAIN_NONE; 441503b705cfSriastradh 441603b705cfSriastradh if (__kgem_busy(kgem, bo->handle)) { 44179a906b70Schristos assert(bo->exec == NULL); 441803b705cfSriastradh list_add(&bo->request, &kgem->flushing); 441903b705cfSriastradh bo->rq = (void *)kgem; 44209a906b70Schristos kgem->need_retire = true; 442103b705cfSriastradh } 442203b705cfSriastradh 442303b705cfSriastradh assert_tiling(kgem, bo); 442403b705cfSriastradh debug_alloc__bo(kgem, bo); 442503b705cfSriastradh 442603b705cfSriastradh return bo; 442703b705cfSriastradh} 442803b705cfSriastradh 44299a906b70Schristosstatic void __kgem_bo_make_scanout(struct kgem *kgem, 44309a906b70Schristos struct kgem_bo *bo, 44319a906b70Schristos int width, int height) 44329a906b70Schristos{ 44339a906b70Schristos ScrnInfoPtr scrn = 44349a906b70Schristos container_of(kgem, struct sna, kgem)->scrn; 44359a906b70Schristos struct drm_mode_fb_cmd arg; 44369a906b70Schristos 44379a906b70Schristos assert(bo->proxy == NULL); 44389a906b70Schristos 44399a906b70Schristos if (!scrn->vtSema) 44409a906b70Schristos return; 44419a906b70Schristos 44429a906b70Schristos DBG(("%s: create fb %dx%d@%d/%d\n", 44439a906b70Schristos __FUNCTION__, width, height, scrn->depth, scrn->bitsPerPixel)); 44449a906b70Schristos 44459a906b70Schristos VG_CLEAR(arg); 44469a906b70Schristos arg.width = width; 44479a906b70Schristos arg.height = height; 44489a906b70Schristos arg.pitch = bo->pitch; 44499a906b70Schristos arg.bpp = scrn->bitsPerPixel; 44509a906b70Schristos arg.depth = scrn->depth; 44519a906b70Schristos arg.handle = bo->handle; 44529a906b70Schristos 44539a906b70Schristos /* First move the scanout out of cached memory */ 44549a906b70Schristos if (kgem->has_llc) { 44559a906b70Schristos if (!gem_set_caching(kgem->fd, bo->handle, DISPLAY) && 44569a906b70Schristos !gem_set_caching(kgem->fd, bo->handle, UNCACHED)) 44579a906b70Schristos return; 44589a906b70Schristos } 44599a906b70Schristos 44609a906b70Schristos bo->scanout = true; 44619a906b70Schristos 44629a906b70Schristos /* Then pre-emptively move the object into the mappable 44639a906b70Schristos * portion to avoid rebinding later when busy. 44649a906b70Schristos */ 44659a906b70Schristos if (bo->map__gtt == NULL) 44669a906b70Schristos bo->map__gtt = __kgem_bo_map__gtt(kgem, bo); 44679a906b70Schristos if (bo->map__gtt) { 44689a906b70Schristos *(uint32_t *)bo->map__gtt = 0; 44699a906b70Schristos bo->domain = DOMAIN_GTT; 44709a906b70Schristos } 44719a906b70Schristos 44729a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg) == 0) { 44739a906b70Schristos DBG(("%s: attached fb=%d to handle=%d\n", 44749a906b70Schristos __FUNCTION__, arg.fb_id, arg.handle)); 44759a906b70Schristos bo->delta = arg.fb_id; 44769a906b70Schristos } 44779a906b70Schristos} 44789a906b70Schristos 447903b705cfSriastradhstruct kgem_bo *kgem_create_2d(struct kgem *kgem, 448003b705cfSriastradh int width, 448103b705cfSriastradh int height, 448203b705cfSriastradh int bpp, 448303b705cfSriastradh int tiling, 448403b705cfSriastradh uint32_t flags) 448503b705cfSriastradh{ 448603b705cfSriastradh struct list *cache; 448703b705cfSriastradh struct kgem_bo *bo; 448803b705cfSriastradh uint32_t pitch, tiled_height, size; 448903b705cfSriastradh uint32_t handle; 449003b705cfSriastradh int i, bucket, retry; 449103b705cfSriastradh bool exact = flags & (CREATE_EXACT | CREATE_SCANOUT); 449203b705cfSriastradh 449303b705cfSriastradh if (tiling < 0) 449403b705cfSriastradh exact = true, tiling = -tiling; 449503b705cfSriastradh 449603b705cfSriastradh 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__, 449703b705cfSriastradh width, height, bpp, tiling, exact, 449803b705cfSriastradh !!(flags & CREATE_INACTIVE), 449903b705cfSriastradh !!(flags & CREATE_CPU_MAP), 450003b705cfSriastradh !!(flags & CREATE_GTT_MAP), 450103b705cfSriastradh !!(flags & CREATE_SCANOUT), 450203b705cfSriastradh !!(flags & CREATE_PRIME), 450303b705cfSriastradh !!(flags & CREATE_TEMPORARY))); 450403b705cfSriastradh 450503b705cfSriastradh size = kgem_surface_size(kgem, kgem->has_relaxed_fencing, flags, 450603b705cfSriastradh width, height, bpp, tiling, &pitch); 45079a906b70Schristos if (size == 0) { 45089a906b70Schristos DBG(("%s: invalid surface size (too large?)\n", __FUNCTION__)); 45099a906b70Schristos return NULL; 45109a906b70Schristos } 45119a906b70Schristos 451203b705cfSriastradh size /= PAGE_SIZE; 451303b705cfSriastradh bucket = cache_bucket(size); 451403b705cfSriastradh 451503b705cfSriastradh if (flags & CREATE_SCANOUT) { 451603b705cfSriastradh struct kgem_bo *last = NULL; 451703b705cfSriastradh 451803b705cfSriastradh list_for_each_entry_reverse(bo, &kgem->scanout, list) { 451903b705cfSriastradh assert(bo->scanout); 452003b705cfSriastradh assert(!bo->flush); 45219a906b70Schristos assert(!bo->refcnt); 452203b705cfSriastradh assert_tiling(kgem, bo); 452303b705cfSriastradh 452403b705cfSriastradh if (size > num_pages(bo) || num_pages(bo) > 2*size) 452503b705cfSriastradh continue; 452603b705cfSriastradh 45279a906b70Schristos if (bo->tiling != tiling || bo->pitch != pitch) 45289a906b70Schristos /* No tiling/pitch without recreating fb */ 452903b705cfSriastradh continue; 453003b705cfSriastradh 45319a906b70Schristos if (bo->delta && !check_scanout_size(kgem, bo, width, height)) 45329a906b70Schristos continue; 453303b705cfSriastradh 453403b705cfSriastradh if (flags & CREATE_INACTIVE && bo->rq) { 453503b705cfSriastradh last = bo; 453603b705cfSriastradh continue; 453703b705cfSriastradh } 453803b705cfSriastradh 453903b705cfSriastradh list_del(&bo->list); 454003b705cfSriastradh 454103b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 454203b705cfSriastradh DBG((" 1:from scanout: pitch=%d, tiling=%d, handle=%d, id=%d\n", 454303b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 454403b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 454503b705cfSriastradh assert_tiling(kgem, bo); 454603b705cfSriastradh bo->refcnt = 1; 454703b705cfSriastradh return bo; 454803b705cfSriastradh } 454903b705cfSriastradh 455003b705cfSriastradh if (last) { 455103b705cfSriastradh list_del(&last->list); 455203b705cfSriastradh 455303b705cfSriastradh last->unique_id = kgem_get_unique_id(kgem); 455403b705cfSriastradh DBG((" 1:from scanout: pitch=%d, tiling=%d, handle=%d, id=%d\n", 455503b705cfSriastradh last->pitch, last->tiling, last->handle, last->unique_id)); 455603b705cfSriastradh assert(last->pitch*kgem_aligned_height(kgem, height, last->tiling) <= kgem_bo_size(last)); 455703b705cfSriastradh assert_tiling(kgem, last); 455803b705cfSriastradh last->refcnt = 1; 455903b705cfSriastradh return last; 456003b705cfSriastradh } 456103b705cfSriastradh 45629a906b70Schristos if (container_of(kgem, struct sna, kgem)->scrn->vtSema) { 45639a906b70Schristos ScrnInfoPtr scrn = container_of(kgem, struct sna, kgem)->scrn; 45649a906b70Schristos 45659a906b70Schristos list_for_each_entry_reverse(bo, &kgem->scanout, list) { 45669a906b70Schristos struct drm_mode_fb_cmd arg; 45679a906b70Schristos 45689a906b70Schristos assert(bo->scanout); 45699a906b70Schristos assert(!bo->refcnt); 45709a906b70Schristos 45719a906b70Schristos if (size > num_pages(bo) || num_pages(bo) > 2*size) 45729a906b70Schristos continue; 45739a906b70Schristos 45749a906b70Schristos if (flags & CREATE_INACTIVE && bo->rq) 45759a906b70Schristos continue; 45769a906b70Schristos 45779a906b70Schristos list_del(&bo->list); 45789a906b70Schristos 45799a906b70Schristos if (bo->tiling != tiling || bo->pitch != pitch) { 45809a906b70Schristos if (bo->delta) { 45819a906b70Schristos kgem_bo_rmfb(kgem, bo); 45829a906b70Schristos bo->delta = 0; 45839a906b70Schristos } 45849a906b70Schristos 45859a906b70Schristos if (gem_set_tiling(kgem->fd, bo->handle, 45869a906b70Schristos tiling, pitch)) { 45879a906b70Schristos bo->tiling = tiling; 45889a906b70Schristos bo->pitch = pitch; 45899a906b70Schristos } else { 45909a906b70Schristos kgem_bo_free(kgem, bo); 45919a906b70Schristos break; 45929a906b70Schristos } 45939a906b70Schristos } 45949a906b70Schristos 45959a906b70Schristos VG_CLEAR(arg); 45969a906b70Schristos arg.width = width; 45979a906b70Schristos arg.height = height; 45989a906b70Schristos arg.pitch = bo->pitch; 45999a906b70Schristos arg.bpp = scrn->bitsPerPixel; 46009a906b70Schristos arg.depth = scrn->depth; 46019a906b70Schristos arg.handle = bo->handle; 46029a906b70Schristos 46039a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg)) { 46049a906b70Schristos kgem_bo_free(kgem, bo); 46059a906b70Schristos break; 46069a906b70Schristos } 46079a906b70Schristos 46089a906b70Schristos bo->delta = arg.fb_id; 46099a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 46109a906b70Schristos 46119a906b70Schristos DBG((" 2:from scanout: pitch=%d, tiling=%d, handle=%d, id=%d\n", 46129a906b70Schristos bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 46139a906b70Schristos assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 46149a906b70Schristos assert_tiling(kgem, bo); 46159a906b70Schristos bo->refcnt = 1; 46169a906b70Schristos return bo; 46179a906b70Schristos } 46189a906b70Schristos } 46199a906b70Schristos 462003b705cfSriastradh bo = __kgem_bo_create_as_display(kgem, size, tiling, pitch); 462103b705cfSriastradh if (bo) 462203b705cfSriastradh return bo; 46239a906b70Schristos 46249a906b70Schristos flags |= CREATE_INACTIVE; 462503b705cfSriastradh } 462603b705cfSriastradh 462703b705cfSriastradh if (bucket >= NUM_CACHE_BUCKETS) { 462803b705cfSriastradh DBG(("%s: large bo num pages=%d, bucket=%d\n", 462903b705cfSriastradh __FUNCTION__, size, bucket)); 463003b705cfSriastradh 463103b705cfSriastradh if (flags & CREATE_INACTIVE) 463203b705cfSriastradh goto large_inactive; 463303b705cfSriastradh 463403b705cfSriastradh tiled_height = kgem_aligned_height(kgem, height, tiling); 463503b705cfSriastradh 463603b705cfSriastradh list_for_each_entry(bo, &kgem->large, list) { 463703b705cfSriastradh assert(!bo->purged); 463803b705cfSriastradh assert(!bo->scanout); 463903b705cfSriastradh assert(bo->refcnt == 0); 464003b705cfSriastradh assert(bo->reusable); 464103b705cfSriastradh assert_tiling(kgem, bo); 464203b705cfSriastradh 464303b705cfSriastradh if (kgem->gen < 040) { 464403b705cfSriastradh if (bo->pitch < pitch) { 464503b705cfSriastradh DBG(("tiled and pitch too small: tiling=%d, (want %d), pitch=%d, need %d\n", 464603b705cfSriastradh bo->tiling, tiling, 464703b705cfSriastradh bo->pitch, pitch)); 464803b705cfSriastradh continue; 464903b705cfSriastradh } 465003b705cfSriastradh 465103b705cfSriastradh if (bo->pitch * tiled_height > bytes(bo)) 465203b705cfSriastradh continue; 465303b705cfSriastradh } else { 465403b705cfSriastradh if (num_pages(bo) < size) 465503b705cfSriastradh continue; 465603b705cfSriastradh 465703b705cfSriastradh if (bo->pitch != pitch || bo->tiling != tiling) { 465803b705cfSriastradh if (!gem_set_tiling(kgem->fd, bo->handle, 465903b705cfSriastradh tiling, pitch)) 466003b705cfSriastradh continue; 466103b705cfSriastradh 466203b705cfSriastradh bo->pitch = pitch; 466303b705cfSriastradh bo->tiling = tiling; 466403b705cfSriastradh } 466503b705cfSriastradh } 466603b705cfSriastradh 466703b705cfSriastradh kgem_bo_remove_from_active(kgem, bo); 466803b705cfSriastradh 466903b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 467003b705cfSriastradh bo->delta = 0; 467103b705cfSriastradh DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 467203b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 467303b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 467403b705cfSriastradh assert_tiling(kgem, bo); 467503b705cfSriastradh bo->refcnt = 1; 467603b705cfSriastradh return bo; 467703b705cfSriastradh } 467803b705cfSriastradh 467903b705cfSriastradhlarge_inactive: 468003b705cfSriastradh __kgem_throttle_retire(kgem, flags); 468103b705cfSriastradh list_for_each_entry(bo, &kgem->large_inactive, list) { 468203b705cfSriastradh assert(bo->refcnt == 0); 468303b705cfSriastradh assert(bo->reusable); 468403b705cfSriastradh assert(!bo->scanout); 468503b705cfSriastradh assert_tiling(kgem, bo); 468603b705cfSriastradh 468703b705cfSriastradh if (size > num_pages(bo)) 468803b705cfSriastradh continue; 468903b705cfSriastradh 469003b705cfSriastradh if (bo->tiling != tiling || 469103b705cfSriastradh (tiling != I915_TILING_NONE && bo->pitch != pitch)) { 469203b705cfSriastradh if (!gem_set_tiling(kgem->fd, bo->handle, 469303b705cfSriastradh tiling, pitch)) 469403b705cfSriastradh continue; 469503b705cfSriastradh 469603b705cfSriastradh bo->tiling = tiling; 469703b705cfSriastradh bo->pitch = pitch; 469803b705cfSriastradh } 469903b705cfSriastradh 470003b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { 470103b705cfSriastradh kgem_bo_free(kgem, bo); 470203b705cfSriastradh break; 470303b705cfSriastradh } 470403b705cfSriastradh 470503b705cfSriastradh list_del(&bo->list); 470603b705cfSriastradh 470703b705cfSriastradh assert(bo->domain != DOMAIN_GPU); 470803b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 470903b705cfSriastradh bo->pitch = pitch; 471003b705cfSriastradh bo->delta = 0; 471103b705cfSriastradh DBG((" 1:from large inactive: pitch=%d, tiling=%d, handle=%d, id=%d\n", 471203b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 471303b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 471403b705cfSriastradh assert_tiling(kgem, bo); 471503b705cfSriastradh bo->refcnt = 1; 47169a906b70Schristos 47179a906b70Schristos if (flags & CREATE_SCANOUT) 47189a906b70Schristos __kgem_bo_make_scanout(kgem, bo, width, height); 47199a906b70Schristos 472003b705cfSriastradh return bo; 472103b705cfSriastradh } 472203b705cfSriastradh 472303b705cfSriastradh goto create; 472403b705cfSriastradh } 472503b705cfSriastradh 472603b705cfSriastradh if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) { 472703b705cfSriastradh int for_cpu = !!(flags & CREATE_CPU_MAP); 472803b705cfSriastradh if (kgem->has_llc && tiling == I915_TILING_NONE) 472903b705cfSriastradh for_cpu = 1; 473003b705cfSriastradh /* We presume that we will need to upload to this bo, 473103b705cfSriastradh * and so would prefer to have an active VMA. 473203b705cfSriastradh */ 473303b705cfSriastradh cache = &kgem->vma[for_cpu].inactive[bucket]; 473403b705cfSriastradh do { 473503b705cfSriastradh list_for_each_entry(bo, cache, vma) { 473603b705cfSriastradh assert(bucket(bo) == bucket); 473703b705cfSriastradh assert(bo->refcnt == 0); 473803b705cfSriastradh assert(!bo->scanout); 47399a906b70Schristos assert(for_cpu ? bo->map__cpu : bo->map__gtt); 474003b705cfSriastradh assert(bo->rq == NULL); 47419a906b70Schristos assert(bo->exec == NULL); 474203b705cfSriastradh assert(list_is_empty(&bo->request)); 474303b705cfSriastradh assert(bo->flush == false); 474403b705cfSriastradh assert_tiling(kgem, bo); 474503b705cfSriastradh 474603b705cfSriastradh if (size > num_pages(bo)) { 474703b705cfSriastradh DBG(("inactive too small: %d < %d\n", 474803b705cfSriastradh num_pages(bo), size)); 474903b705cfSriastradh continue; 475003b705cfSriastradh } 475103b705cfSriastradh 47529a906b70Schristos if (flags & UNCACHED && !kgem->has_llc && bo->domain != DOMAIN_CPU) 47539a906b70Schristos continue; 47549a906b70Schristos 475503b705cfSriastradh if (bo->tiling != tiling || 475603b705cfSriastradh (tiling != I915_TILING_NONE && bo->pitch != pitch)) { 47579a906b70Schristos if (bo->map__gtt || 47589a906b70Schristos !gem_set_tiling(kgem->fd, bo->handle, 47599a906b70Schristos tiling, pitch)) { 47609a906b70Schristos DBG(("inactive GTT vma with wrong tiling: %d < %d\n", 47619a906b70Schristos bo->tiling, tiling)); 47629a906b70Schristos continue; 47639a906b70Schristos } 47649a906b70Schristos bo->tiling = tiling; 47659a906b70Schristos bo->pitch = pitch; 476603b705cfSriastradh } 476703b705cfSriastradh 476803b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { 476903b705cfSriastradh kgem_bo_free(kgem, bo); 477003b705cfSriastradh break; 477103b705cfSriastradh } 477203b705cfSriastradh 477303b705cfSriastradh assert(bo->tiling == tiling); 477403b705cfSriastradh bo->pitch = pitch; 477503b705cfSriastradh bo->delta = 0; 477603b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 477703b705cfSriastradh 477803b705cfSriastradh kgem_bo_remove_from_inactive(kgem, bo); 47799a906b70Schristos assert(list_is_empty(&bo->list)); 47809a906b70Schristos assert(list_is_empty(&bo->vma)); 478103b705cfSriastradh 478203b705cfSriastradh DBG((" from inactive vma: pitch=%d, tiling=%d: handle=%d, id=%d\n", 478303b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 478403b705cfSriastradh assert(bo->reusable); 478503b705cfSriastradh assert(bo->domain != DOMAIN_GPU); 478603b705cfSriastradh ASSERT_IDLE(kgem, bo->handle); 478703b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 478803b705cfSriastradh assert_tiling(kgem, bo); 478903b705cfSriastradh bo->refcnt = 1; 479003b705cfSriastradh return bo; 479103b705cfSriastradh } 479203b705cfSriastradh } while (!list_is_empty(cache) && 479303b705cfSriastradh __kgem_throttle_retire(kgem, flags)); 479403b705cfSriastradh 479503b705cfSriastradh if (flags & CREATE_CPU_MAP && !kgem->has_llc) { 479603b705cfSriastradh if (list_is_empty(&kgem->active[bucket][tiling]) && 479703b705cfSriastradh list_is_empty(&kgem->inactive[bucket])) 479803b705cfSriastradh flags &= ~CREATE_CACHED; 479903b705cfSriastradh 480003b705cfSriastradh goto create; 480103b705cfSriastradh } 480203b705cfSriastradh } 480303b705cfSriastradh 480403b705cfSriastradh if (flags & CREATE_INACTIVE) 480503b705cfSriastradh goto skip_active_search; 480603b705cfSriastradh 480703b705cfSriastradh /* Best active match */ 480803b705cfSriastradh retry = NUM_CACHE_BUCKETS - bucket; 480903b705cfSriastradh if (retry > 3 && (flags & CREATE_TEMPORARY) == 0) 481003b705cfSriastradh retry = 3; 48119a906b70Schristossearch_active: 481203b705cfSriastradh assert(bucket < NUM_CACHE_BUCKETS); 481303b705cfSriastradh cache = &kgem->active[bucket][tiling]; 481403b705cfSriastradh if (tiling) { 481503b705cfSriastradh tiled_height = kgem_aligned_height(kgem, height, tiling); 481603b705cfSriastradh list_for_each_entry(bo, cache, list) { 481703b705cfSriastradh assert(!bo->purged); 481803b705cfSriastradh assert(bo->refcnt == 0); 481903b705cfSriastradh assert(bucket(bo) == bucket); 482003b705cfSriastradh assert(bo->reusable); 482103b705cfSriastradh assert(bo->tiling == tiling); 482203b705cfSriastradh assert(bo->flush == false); 482303b705cfSriastradh assert(!bo->scanout); 482403b705cfSriastradh assert_tiling(kgem, bo); 482503b705cfSriastradh 482603b705cfSriastradh if (kgem->gen < 040) { 482703b705cfSriastradh if (bo->pitch < pitch) { 482803b705cfSriastradh DBG(("tiled and pitch too small: tiling=%d, (want %d), pitch=%d, need %d\n", 482903b705cfSriastradh bo->tiling, tiling, 483003b705cfSriastradh bo->pitch, pitch)); 483103b705cfSriastradh continue; 483203b705cfSriastradh } 483303b705cfSriastradh 483403b705cfSriastradh if (bo->pitch * tiled_height > bytes(bo)) 483503b705cfSriastradh continue; 483603b705cfSriastradh } else { 483703b705cfSriastradh if (num_pages(bo) < size) 483803b705cfSriastradh continue; 483903b705cfSriastradh 484003b705cfSriastradh if (bo->pitch != pitch) { 484103b705cfSriastradh if (!gem_set_tiling(kgem->fd, 484203b705cfSriastradh bo->handle, 484303b705cfSriastradh tiling, pitch)) 484403b705cfSriastradh continue; 484503b705cfSriastradh 484603b705cfSriastradh bo->pitch = pitch; 484703b705cfSriastradh } 484803b705cfSriastradh } 484903b705cfSriastradh 485003b705cfSriastradh kgem_bo_remove_from_active(kgem, bo); 485103b705cfSriastradh 485203b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 485303b705cfSriastradh bo->delta = 0; 485403b705cfSriastradh DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 485503b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 485603b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 485703b705cfSriastradh assert_tiling(kgem, bo); 485803b705cfSriastradh bo->refcnt = 1; 485903b705cfSriastradh return bo; 486003b705cfSriastradh } 486103b705cfSriastradh } else { 486203b705cfSriastradh list_for_each_entry(bo, cache, list) { 486303b705cfSriastradh assert(bucket(bo) == bucket); 486403b705cfSriastradh assert(!bo->purged); 486503b705cfSriastradh assert(bo->refcnt == 0); 486603b705cfSriastradh assert(bo->reusable); 486703b705cfSriastradh assert(!bo->scanout); 486803b705cfSriastradh assert(bo->tiling == tiling); 486903b705cfSriastradh assert(bo->flush == false); 487003b705cfSriastradh assert_tiling(kgem, bo); 487103b705cfSriastradh 487203b705cfSriastradh if (num_pages(bo) < size) 487303b705cfSriastradh continue; 487403b705cfSriastradh 487503b705cfSriastradh kgem_bo_remove_from_active(kgem, bo); 487603b705cfSriastradh 487703b705cfSriastradh bo->pitch = pitch; 487803b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 487903b705cfSriastradh bo->delta = 0; 488003b705cfSriastradh DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 488103b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 488203b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 488303b705cfSriastradh assert_tiling(kgem, bo); 488403b705cfSriastradh bo->refcnt = 1; 488503b705cfSriastradh return bo; 488603b705cfSriastradh } 488703b705cfSriastradh } 488803b705cfSriastradh 48899a906b70Schristos if (kgem->gen >= 040) { 48909a906b70Schristos for (i = I915_TILING_Y; i >= I915_TILING_NONE; i--) { 48919a906b70Schristos cache = &kgem->active[bucket][i]; 48929a906b70Schristos list_for_each_entry(bo, cache, list) { 48939a906b70Schristos assert(!bo->purged); 48949a906b70Schristos assert(bo->refcnt == 0); 48959a906b70Schristos assert(bo->reusable); 48969a906b70Schristos assert(!bo->scanout); 48979a906b70Schristos assert(bo->flush == false); 48989a906b70Schristos assert_tiling(kgem, bo); 489903b705cfSriastradh 49009a906b70Schristos if (num_pages(bo) < size) 49019a906b70Schristos continue; 490203b705cfSriastradh 49039a906b70Schristos if (bo->tiling != tiling || 49049a906b70Schristos (tiling != I915_TILING_NONE && bo->pitch != pitch)) { 490503b705cfSriastradh if (!gem_set_tiling(kgem->fd, 490603b705cfSriastradh bo->handle, 490703b705cfSriastradh tiling, pitch)) 490803b705cfSriastradh continue; 49099a906b70Schristos } 491003b705cfSriastradh 49119a906b70Schristos kgem_bo_remove_from_active(kgem, bo); 491203b705cfSriastradh 49139a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 49149a906b70Schristos bo->pitch = pitch; 49159a906b70Schristos bo->tiling = tiling; 49169a906b70Schristos bo->delta = 0; 49179a906b70Schristos DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 49189a906b70Schristos bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 49199a906b70Schristos assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 49209a906b70Schristos assert_tiling(kgem, bo); 49219a906b70Schristos bo->refcnt = 1; 49229a906b70Schristos return bo; 492303b705cfSriastradh } 492403b705cfSriastradh } 49259a906b70Schristos } else if (!exact) { /* allow an active near-miss? */ 49269a906b70Schristos for (i = tiling; i >= I915_TILING_NONE; i--) { 492703b705cfSriastradh tiled_height = kgem_surface_size(kgem, kgem->has_relaxed_fencing, flags, 492803b705cfSriastradh width, height, bpp, tiling, &pitch); 492903b705cfSriastradh cache = active(kgem, tiled_height / PAGE_SIZE, i); 493003b705cfSriastradh tiled_height = kgem_aligned_height(kgem, height, i); 493103b705cfSriastradh list_for_each_entry(bo, cache, list) { 493203b705cfSriastradh assert(!bo->purged); 493303b705cfSriastradh assert(bo->refcnt == 0); 493403b705cfSriastradh assert(bo->reusable); 493503b705cfSriastradh assert(!bo->scanout); 493603b705cfSriastradh assert(bo->flush == false); 493703b705cfSriastradh assert_tiling(kgem, bo); 493803b705cfSriastradh 493903b705cfSriastradh if (bo->tiling) { 494003b705cfSriastradh if (bo->pitch < pitch) { 494103b705cfSriastradh DBG(("tiled and pitch too small: tiling=%d, (want %d), pitch=%d, need %d\n", 494203b705cfSriastradh bo->tiling, tiling, 494303b705cfSriastradh bo->pitch, pitch)); 494403b705cfSriastradh continue; 494503b705cfSriastradh } 494603b705cfSriastradh } else 494703b705cfSriastradh bo->pitch = pitch; 494803b705cfSriastradh 494903b705cfSriastradh if (bo->pitch * tiled_height > bytes(bo)) 495003b705cfSriastradh continue; 495103b705cfSriastradh 495203b705cfSriastradh kgem_bo_remove_from_active(kgem, bo); 495303b705cfSriastradh 495403b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 495503b705cfSriastradh bo->delta = 0; 495603b705cfSriastradh DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 495703b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 495803b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 495903b705cfSriastradh assert_tiling(kgem, bo); 496003b705cfSriastradh bo->refcnt = 1; 496103b705cfSriastradh return bo; 496203b705cfSriastradh } 496303b705cfSriastradh } 496403b705cfSriastradh } 496503b705cfSriastradh 49669a906b70Schristos if (--retry) { 49679a906b70Schristos bucket++; 49689a906b70Schristos goto search_active; 49699a906b70Schristos } 49709a906b70Schristos 497103b705cfSriastradhskip_active_search: 497203b705cfSriastradh bucket = cache_bucket(size); 497303b705cfSriastradh retry = NUM_CACHE_BUCKETS - bucket; 497403b705cfSriastradh if (retry > 3) 497503b705cfSriastradh retry = 3; 497603b705cfSriastradhsearch_inactive: 497703b705cfSriastradh /* Now just look for a close match and prefer any currently active */ 497803b705cfSriastradh assert(bucket < NUM_CACHE_BUCKETS); 497903b705cfSriastradh cache = &kgem->inactive[bucket]; 498003b705cfSriastradh list_for_each_entry(bo, cache, list) { 498103b705cfSriastradh assert(bucket(bo) == bucket); 498203b705cfSriastradh assert(bo->reusable); 498303b705cfSriastradh assert(!bo->scanout); 498403b705cfSriastradh assert(bo->flush == false); 498503b705cfSriastradh assert_tiling(kgem, bo); 498603b705cfSriastradh 498703b705cfSriastradh if (size > num_pages(bo)) { 498803b705cfSriastradh DBG(("inactive too small: %d < %d\n", 498903b705cfSriastradh num_pages(bo), size)); 499003b705cfSriastradh continue; 499103b705cfSriastradh } 499203b705cfSriastradh 499303b705cfSriastradh if (bo->tiling != tiling || 499403b705cfSriastradh (tiling != I915_TILING_NONE && bo->pitch != pitch)) { 499503b705cfSriastradh if (!gem_set_tiling(kgem->fd, bo->handle, 499603b705cfSriastradh tiling, pitch)) 499703b705cfSriastradh continue; 499803b705cfSriastradh } 499903b705cfSriastradh 500003b705cfSriastradh if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { 500103b705cfSriastradh kgem_bo_free(kgem, bo); 500203b705cfSriastradh break; 500303b705cfSriastradh } 500403b705cfSriastradh 500503b705cfSriastradh kgem_bo_remove_from_inactive(kgem, bo); 50069a906b70Schristos assert(list_is_empty(&bo->list)); 50079a906b70Schristos assert(list_is_empty(&bo->vma)); 500803b705cfSriastradh 500903b705cfSriastradh bo->pitch = pitch; 501003b705cfSriastradh bo->tiling = tiling; 501103b705cfSriastradh 501203b705cfSriastradh bo->delta = 0; 501303b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 501403b705cfSriastradh assert(bo->pitch); 501503b705cfSriastradh DBG((" from inactive: pitch=%d, tiling=%d: handle=%d, id=%d\n", 501603b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 501703b705cfSriastradh assert(bo->refcnt == 0); 501803b705cfSriastradh assert(bo->reusable); 501903b705cfSriastradh assert((flags & CREATE_INACTIVE) == 0 || bo->domain != DOMAIN_GPU); 502003b705cfSriastradh ASSERT_MAYBE_IDLE(kgem, bo->handle, flags & CREATE_INACTIVE); 502103b705cfSriastradh assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 502203b705cfSriastradh assert_tiling(kgem, bo); 502303b705cfSriastradh bo->refcnt = 1; 50249a906b70Schristos 50259a906b70Schristos if (flags & CREATE_SCANOUT) 50269a906b70Schristos __kgem_bo_make_scanout(kgem, bo, width, height); 50279a906b70Schristos 502803b705cfSriastradh return bo; 502903b705cfSriastradh } 503003b705cfSriastradh 50319a906b70Schristos if ((flags & CREATE_NO_RETIRE) == 0) { 50329a906b70Schristos list_for_each_entry_reverse(bo, &kgem->active[bucket][tiling], list) { 50339a906b70Schristos if (bo->exec) 50349a906b70Schristos break; 50359a906b70Schristos 50369a906b70Schristos if (size > num_pages(bo)) 50379a906b70Schristos continue; 50389a906b70Schristos 50399a906b70Schristos if (__kgem_busy(kgem, bo->handle)) { 50409a906b70Schristos if (flags & CREATE_NO_THROTTLE) 50419a906b70Schristos goto no_retire; 50429a906b70Schristos 50439a906b70Schristos do { 50449a906b70Schristos if (!kgem->need_throttle) { 50459a906b70Schristos DBG(("%s: not throttling for active handle=%d\n", __FUNCTION__, bo->handle)); 50469a906b70Schristos goto no_retire; 50479a906b70Schristos } 50489a906b70Schristos 50499a906b70Schristos __kgem_throttle(kgem, false); 50509a906b70Schristos } while (__kgem_busy(kgem, bo->handle)); 50519a906b70Schristos } 50529a906b70Schristos 50539a906b70Schristos DBG(("%s: flushed active handle=%d\n", __FUNCTION__, bo->handle)); 50549a906b70Schristos 50559a906b70Schristos kgem_bo_remove_from_active(kgem, bo); 50569a906b70Schristos __kgem_bo_clear_busy(bo); 50579a906b70Schristos 50589a906b70Schristos if (tiling != I915_TILING_NONE && bo->pitch != pitch) { 50599a906b70Schristos if (!gem_set_tiling(kgem->fd, bo->handle, tiling, pitch)) { 50609a906b70Schristos kgem_bo_free(kgem, bo); 50619a906b70Schristos goto no_retire; 50629a906b70Schristos } 50639a906b70Schristos } 50649a906b70Schristos 50659a906b70Schristos bo->pitch = pitch; 50669a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 50679a906b70Schristos bo->delta = 0; 50689a906b70Schristos DBG((" 2:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n", 50699a906b70Schristos bo->pitch, bo->tiling, bo->handle, bo->unique_id)); 50709a906b70Schristos assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); 50719a906b70Schristos assert_tiling(kgem, bo); 50729a906b70Schristos bo->refcnt = 1; 50739a906b70Schristos 50749a906b70Schristos if (flags & CREATE_SCANOUT) 50759a906b70Schristos __kgem_bo_make_scanout(kgem, bo, width, height); 50769a906b70Schristos 50779a906b70Schristos return bo; 50789a906b70Schristos } 50799a906b70Schristosno_retire: 50809a906b70Schristos flags |= CREATE_NO_RETIRE; 508103b705cfSriastradh } 508203b705cfSriastradh 508303b705cfSriastradh if (--retry) { 508403b705cfSriastradh bucket++; 508503b705cfSriastradh goto search_inactive; 508603b705cfSriastradh } 508703b705cfSriastradh 508803b705cfSriastradhcreate: 50899a906b70Schristos if (flags & CREATE_CACHED) { 50909a906b70Schristos DBG(("%s: no cached bo found, requested not to create a new bo\n", __FUNCTION__)); 509103b705cfSriastradh return NULL; 50929a906b70Schristos } 509303b705cfSriastradh 509403b705cfSriastradh if (bucket >= NUM_CACHE_BUCKETS) 509503b705cfSriastradh size = ALIGN(size, 1024); 509603b705cfSriastradh handle = gem_create(kgem->fd, size); 50979a906b70Schristos if (handle == 0) { 50989a906b70Schristos DBG(("%s: kernel allocation (gem_create) failure\n", __FUNCTION__)); 509903b705cfSriastradh return NULL; 51009a906b70Schristos } 510103b705cfSriastradh 510203b705cfSriastradh bo = __kgem_bo_alloc(handle, size); 510303b705cfSriastradh if (!bo) { 51049a906b70Schristos DBG(("%s: malloc failed\n", __FUNCTION__)); 510503b705cfSriastradh gem_close(kgem->fd, handle); 510603b705cfSriastradh return NULL; 510703b705cfSriastradh } 510803b705cfSriastradh 510903b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 511003b705cfSriastradh if (tiling == I915_TILING_NONE || 511103b705cfSriastradh gem_set_tiling(kgem->fd, handle, tiling, pitch)) { 511203b705cfSriastradh bo->tiling = tiling; 511303b705cfSriastradh bo->pitch = pitch; 51149a906b70Schristos if (flags & CREATE_SCANOUT) 51159a906b70Schristos __kgem_bo_make_scanout(kgem, bo, width, height); 511603b705cfSriastradh } else { 511703b705cfSriastradh if (flags & CREATE_EXACT) { 51189a906b70Schristos DBG(("%s: failed to set exact tiling (gem_set_tiling)\n", __FUNCTION__)); 51199a906b70Schristos gem_close(kgem->fd, handle); 51209a906b70Schristos free(bo); 51219a906b70Schristos return NULL; 512203b705cfSriastradh } 512303b705cfSriastradh } 512403b705cfSriastradh 512503b705cfSriastradh assert(bytes(bo) >= bo->pitch * kgem_aligned_height(kgem, height, bo->tiling)); 512603b705cfSriastradh assert_tiling(kgem, bo); 512703b705cfSriastradh 512803b705cfSriastradh debug_alloc__bo(kgem, bo); 512903b705cfSriastradh 513003b705cfSriastradh DBG((" new pitch=%d, tiling=%d, handle=%d, id=%d, num_pages=%d [%d], bucket=%d\n", 513103b705cfSriastradh bo->pitch, bo->tiling, bo->handle, bo->unique_id, 513203b705cfSriastradh size, num_pages(bo), bucket(bo))); 513303b705cfSriastradh return bo; 513403b705cfSriastradh} 513503b705cfSriastradh 513603b705cfSriastradhstruct kgem_bo *kgem_create_cpu_2d(struct kgem *kgem, 513703b705cfSriastradh int width, 513803b705cfSriastradh int height, 513903b705cfSriastradh int bpp, 514003b705cfSriastradh uint32_t flags) 514103b705cfSriastradh{ 514203b705cfSriastradh struct kgem_bo *bo; 514303b705cfSriastradh int stride, size; 514403b705cfSriastradh 514503b705cfSriastradh if (DBG_NO_CPU) 514603b705cfSriastradh return NULL; 514703b705cfSriastradh 514803b705cfSriastradh DBG(("%s(%dx%d, bpp=%d)\n", __FUNCTION__, width, height, bpp)); 514903b705cfSriastradh 515003b705cfSriastradh if (kgem->has_llc) { 515103b705cfSriastradh bo = kgem_create_2d(kgem, width, height, bpp, 515203b705cfSriastradh I915_TILING_NONE, flags); 515303b705cfSriastradh if (bo == NULL) 515403b705cfSriastradh return bo; 515503b705cfSriastradh 515603b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 515703b705cfSriastradh assert_tiling(kgem, bo); 515803b705cfSriastradh 515903b705cfSriastradh if (kgem_bo_map__cpu(kgem, bo) == NULL) { 516003b705cfSriastradh kgem_bo_destroy(kgem, bo); 516103b705cfSriastradh return NULL; 516203b705cfSriastradh } 516303b705cfSriastradh 516403b705cfSriastradh return bo; 516503b705cfSriastradh } 516603b705cfSriastradh 516703b705cfSriastradh assert(width > 0 && height > 0); 516803b705cfSriastradh stride = ALIGN(width, 2) * bpp >> 3; 516903b705cfSriastradh stride = ALIGN(stride, 4); 517003b705cfSriastradh size = stride * ALIGN(height, 2); 517103b705cfSriastradh assert(size >= PAGE_SIZE); 517203b705cfSriastradh 517303b705cfSriastradh DBG(("%s: %dx%d, %d bpp, stride=%d\n", 517403b705cfSriastradh __FUNCTION__, width, height, bpp, stride)); 517503b705cfSriastradh 517603b705cfSriastradh bo = search_snoop_cache(kgem, NUM_PAGES(size), 0); 517703b705cfSriastradh if (bo) { 517803b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 517903b705cfSriastradh assert_tiling(kgem, bo); 518003b705cfSriastradh assert(bo->snoop); 518103b705cfSriastradh bo->refcnt = 1; 518203b705cfSriastradh bo->pitch = stride; 518303b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 518403b705cfSriastradh return bo; 518503b705cfSriastradh } 518603b705cfSriastradh 518703b705cfSriastradh if (kgem->has_caching) { 518803b705cfSriastradh bo = kgem_create_linear(kgem, size, flags); 518903b705cfSriastradh if (bo == NULL) 519003b705cfSriastradh return NULL; 519103b705cfSriastradh 519203b705cfSriastradh assert(bo->tiling == I915_TILING_NONE); 519303b705cfSriastradh assert_tiling(kgem, bo); 519403b705cfSriastradh 519503b705cfSriastradh if (!gem_set_caching(kgem->fd, bo->handle, SNOOPED)) { 519603b705cfSriastradh kgem_bo_destroy(kgem, bo); 519703b705cfSriastradh return NULL; 519803b705cfSriastradh } 519903b705cfSriastradh bo->snoop = true; 520003b705cfSriastradh 520103b705cfSriastradh if (kgem_bo_map__cpu(kgem, bo) == NULL) { 520203b705cfSriastradh kgem_bo_destroy(kgem, bo); 520303b705cfSriastradh return NULL; 520403b705cfSriastradh } 520503b705cfSriastradh 520603b705cfSriastradh bo->pitch = stride; 520703b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 520803b705cfSriastradh return bo; 520903b705cfSriastradh } 521003b705cfSriastradh 521103b705cfSriastradh if (kgem->has_userptr) { 521203b705cfSriastradh void *ptr; 521303b705cfSriastradh 521403b705cfSriastradh /* XXX */ 521503b705cfSriastradh //if (posix_memalign(&ptr, 64, ALIGN(size, 64))) 521603b705cfSriastradh if (posix_memalign(&ptr, PAGE_SIZE, ALIGN(size, PAGE_SIZE))) 521703b705cfSriastradh return NULL; 521803b705cfSriastradh 521903b705cfSriastradh bo = kgem_create_map(kgem, ptr, size, false); 522003b705cfSriastradh if (bo == NULL) { 522103b705cfSriastradh free(ptr); 522203b705cfSriastradh return NULL; 522303b705cfSriastradh } 522403b705cfSriastradh 522503b705cfSriastradh bo->pitch = stride; 522603b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 522703b705cfSriastradh return bo; 522803b705cfSriastradh } 522903b705cfSriastradh 523003b705cfSriastradh return NULL; 523103b705cfSriastradh} 523203b705cfSriastradh 523303b705cfSriastradhvoid _kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo) 523403b705cfSriastradh{ 523503b705cfSriastradh DBG(("%s: handle=%d, proxy? %d\n", 523603b705cfSriastradh __FUNCTION__, bo->handle, bo->proxy != NULL)); 523703b705cfSriastradh 523803b705cfSriastradh if (bo->proxy) { 52399a906b70Schristos assert(!bo->reusable); 52409a906b70Schristos kgem_bo_binding_free(kgem, bo); 52419a906b70Schristos 52429a906b70Schristos assert(list_is_empty(&bo->list)); 524303b705cfSriastradh _list_del(&bo->vma); 524403b705cfSriastradh _list_del(&bo->request); 52459a906b70Schristos 52469a906b70Schristos if (bo->io && bo->domain == DOMAIN_CPU) 524703b705cfSriastradh _kgem_bo_delete_buffer(kgem, bo); 52489a906b70Schristos 524903b705cfSriastradh kgem_bo_unref(kgem, bo->proxy); 525003b705cfSriastradh 52519a906b70Schristos if (DBG_NO_MALLOC_CACHE) { 52529a906b70Schristos free(bo); 52539a906b70Schristos } else { 52549a906b70Schristos *(struct kgem_bo **)bo = __kgem_freed_bo; 52559a906b70Schristos __kgem_freed_bo = bo; 52569a906b70Schristos } 52579a906b70Schristos } else 52589a906b70Schristos __kgem_bo_destroy(kgem, bo); 525903b705cfSriastradh} 526003b705cfSriastradh 526103b705cfSriastradhstatic void __kgem_flush(struct kgem *kgem, struct kgem_bo *bo) 526203b705cfSriastradh{ 526303b705cfSriastradh assert(bo->rq); 526403b705cfSriastradh assert(bo->exec == NULL); 526503b705cfSriastradh assert(bo->needs_flush); 526603b705cfSriastradh 526703b705cfSriastradh /* The kernel will emit a flush *and* update its own flushing lists. */ 526803b705cfSriastradh if (!__kgem_busy(kgem, bo->handle)) 526903b705cfSriastradh __kgem_bo_clear_busy(bo); 527003b705cfSriastradh 527103b705cfSriastradh DBG(("%s: handle=%d, busy?=%d\n", 527203b705cfSriastradh __FUNCTION__, bo->handle, bo->rq != NULL)); 527303b705cfSriastradh} 527403b705cfSriastradh 527503b705cfSriastradhvoid kgem_scanout_flush(struct kgem *kgem, struct kgem_bo *bo) 527603b705cfSriastradh{ 527703b705cfSriastradh if (!bo->needs_flush) 527803b705cfSriastradh return; 527903b705cfSriastradh 52809a906b70Schristos kgem_bo_submit(kgem, bo); 52819a906b70Schristos 528203b705cfSriastradh /* If the kernel fails to emit the flush, then it will be forced when 528303b705cfSriastradh * we assume direct access. And as the usual failure is EIO, we do 528403b705cfSriastradh * not actually care. 528503b705cfSriastradh */ 528603b705cfSriastradh assert(bo->exec == NULL); 528703b705cfSriastradh if (bo->rq) 528803b705cfSriastradh __kgem_flush(kgem, bo); 528903b705cfSriastradh 529003b705cfSriastradh /* Whatever actually happens, we can regard the GTT write domain 529103b705cfSriastradh * as being flushed. 529203b705cfSriastradh */ 529303b705cfSriastradh bo->gtt_dirty = false; 529403b705cfSriastradh bo->needs_flush = false; 529503b705cfSriastradh bo->domain = DOMAIN_NONE; 529603b705cfSriastradh} 529703b705cfSriastradh 52989a906b70Schristosinline static bool nearly_idle(struct kgem *kgem) 52999a906b70Schristos{ 53009a906b70Schristos int ring = kgem->ring == KGEM_BLT; 53019a906b70Schristos 53029a906b70Schristos if (list_is_singular(&kgem->requests[ring])) 53039a906b70Schristos return true; 53049a906b70Schristos 53059a906b70Schristos return __kgem_ring_is_idle(kgem, ring); 53069a906b70Schristos} 53079a906b70Schristos 530803b705cfSriastradhinline static bool needs_semaphore(struct kgem *kgem, struct kgem_bo *bo) 530903b705cfSriastradh{ 53109a906b70Schristos if (kgem->needs_semaphore) 53119a906b70Schristos return false; 53129a906b70Schristos 53139a906b70Schristos if (bo->rq == NULL || RQ_RING(bo->rq) == kgem->ring) 53149a906b70Schristos return false; 53159a906b70Schristos 53169a906b70Schristos kgem->needs_semaphore = true; 53179a906b70Schristos return true; 53189a906b70Schristos} 53199a906b70Schristos 53209a906b70Schristosinline static bool needs_reservation(struct kgem *kgem, struct kgem_bo *bo) 53219a906b70Schristos{ 53229a906b70Schristos if (kgem->needs_reservation) 53239a906b70Schristos return false; 53249a906b70Schristos 53259a906b70Schristos if (bo->presumed_offset) 53269a906b70Schristos return false; 53279a906b70Schristos 53289a906b70Schristos kgem->needs_reservation = true; 53299a906b70Schristos return nearly_idle(kgem); 53309a906b70Schristos} 53319a906b70Schristos 53329a906b70Schristosinline static bool needs_batch_flush(struct kgem *kgem, struct kgem_bo *bo) 53339a906b70Schristos{ 53349a906b70Schristos bool flush = false; 53359a906b70Schristos 53369a906b70Schristos if (needs_semaphore(kgem, bo)) { 53379a906b70Schristos DBG(("%s: flushing before handle=%d for required semaphore\n", __FUNCTION__, bo->handle)); 53389a906b70Schristos flush = true; 53399a906b70Schristos } 53409a906b70Schristos 53419a906b70Schristos if (needs_reservation(kgem, bo)) { 53429a906b70Schristos DBG(("%s: flushing before handle=%d for new reservation\n", __FUNCTION__, bo->handle)); 53439a906b70Schristos flush = true; 53449a906b70Schristos } 53459a906b70Schristos 53469a906b70Schristos return kgem->nreloc ? flush : false; 53479a906b70Schristos} 53489a906b70Schristos 53499a906b70Schristosstatic bool aperture_check(struct kgem *kgem, unsigned num_pages) 53509a906b70Schristos{ 53519a906b70Schristos struct drm_i915_gem_get_aperture aperture; 53529a906b70Schristos int reserve; 53539a906b70Schristos 53549a906b70Schristos if (kgem->aperture) 53559a906b70Schristos return false; 53569a906b70Schristos 53579a906b70Schristos /* Leave some space in case of alignment issues */ 53589a906b70Schristos reserve = kgem->aperture_mappable / 2; 53599a906b70Schristos if (kgem->gen < 033 && reserve < kgem->aperture_max_fence) 53609a906b70Schristos reserve = kgem->aperture_max_fence; 53619a906b70Schristos if (!kgem->has_llc) 53629a906b70Schristos reserve += kgem->nexec * PAGE_SIZE * 2; 53639a906b70Schristos 53649a906b70Schristos DBG(("%s: num_pages=%d, holding %d pages in reserve, total aperture %d\n", 53659a906b70Schristos __FUNCTION__, num_pages, reserve, kgem->aperture_total)); 53669a906b70Schristos num_pages += reserve; 53679a906b70Schristos 53689a906b70Schristos VG_CLEAR(aperture); 53699a906b70Schristos aperture.aper_available_size = kgem->aperture_total; 53709a906b70Schristos aperture.aper_available_size *= PAGE_SIZE; 53719a906b70Schristos (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture); 53729a906b70Schristos 53739a906b70Schristos DBG(("%s: aperture required %ld bytes, available %ld bytes\n", 53749a906b70Schristos __FUNCTION__, 53759a906b70Schristos (long)num_pages * PAGE_SIZE, 53769a906b70Schristos (long)aperture.aper_available_size)); 53779a906b70Schristos 53789a906b70Schristos return num_pages <= aperture.aper_available_size / PAGE_SIZE; 53799a906b70Schristos} 53809a906b70Schristos 53819a906b70Schristosstatic inline bool kgem_flush(struct kgem *kgem, bool flush) 53829a906b70Schristos{ 53839a906b70Schristos if (unlikely(kgem->wedged)) 53849a906b70Schristos return false; 53859a906b70Schristos 53869a906b70Schristos if (kgem->nreloc == 0) 53879a906b70Schristos return true; 53889a906b70Schristos 53899a906b70Schristos if (container_of(kgem, struct sna, kgem)->flags & SNA_POWERSAVE) 53909a906b70Schristos return true; 53919a906b70Schristos 53929a906b70Schristos if (kgem->flush == flush && kgem->aperture < kgem->aperture_low) 53939a906b70Schristos return true; 53949a906b70Schristos 53959a906b70Schristos DBG(("%s: opportunistic flushing? flush=%d,%d, aperture=%d/%d, idle?=%d\n", 53969a906b70Schristos __FUNCTION__, kgem->flush, flush, kgem->aperture, kgem->aperture_low, kgem_ring_is_idle(kgem, kgem->ring))); 53979a906b70Schristos return !kgem_ring_is_idle(kgem, kgem->ring); 539803b705cfSriastradh} 539903b705cfSriastradh 540003b705cfSriastradhbool kgem_check_bo(struct kgem *kgem, ...) 540103b705cfSriastradh{ 540203b705cfSriastradh va_list ap; 540303b705cfSriastradh struct kgem_bo *bo; 540403b705cfSriastradh int num_exec = 0; 540503b705cfSriastradh int num_pages = 0; 540603b705cfSriastradh bool flush = false; 54079a906b70Schristos bool busy = true; 540803b705cfSriastradh 540903b705cfSriastradh va_start(ap, kgem); 541003b705cfSriastradh while ((bo = va_arg(ap, struct kgem_bo *))) { 541103b705cfSriastradh while (bo->proxy) 541203b705cfSriastradh bo = bo->proxy; 541303b705cfSriastradh if (bo->exec) 541403b705cfSriastradh continue; 541503b705cfSriastradh 54169a906b70Schristos if (needs_batch_flush(kgem, bo)) { 54179a906b70Schristos va_end(ap); 541803b705cfSriastradh return false; 54199a906b70Schristos } 542003b705cfSriastradh 542103b705cfSriastradh num_pages += num_pages(bo); 542203b705cfSriastradh num_exec++; 542303b705cfSriastradh 542403b705cfSriastradh flush |= bo->flush; 54259a906b70Schristos busy &= bo->rq != NULL; 542603b705cfSriastradh } 542703b705cfSriastradh va_end(ap); 542803b705cfSriastradh 542903b705cfSriastradh DBG(("%s: num_pages=+%d, num_exec=+%d\n", 543003b705cfSriastradh __FUNCTION__, num_pages, num_exec)); 543103b705cfSriastradh 543203b705cfSriastradh if (!num_pages) 543303b705cfSriastradh return true; 543403b705cfSriastradh 54359a906b70Schristos if (kgem->nexec + num_exec >= KGEM_EXEC_SIZE(kgem)) { 54369a906b70Schristos DBG(("%s: out of exec slots (%d + %d / %d)\n", __FUNCTION__, 54379a906b70Schristos kgem->nexec, num_exec, KGEM_EXEC_SIZE(kgem))); 543803b705cfSriastradh return false; 543903b705cfSriastradh } 544003b705cfSriastradh 544103b705cfSriastradh if (num_pages + kgem->aperture > kgem->aperture_high) { 54429a906b70Schristos DBG(("%s: final aperture usage (%d + %d) is greater than high water mark (%d)\n", 54439a906b70Schristos __FUNCTION__, kgem->aperture, num_pages, kgem->aperture_high)); 54449a906b70Schristos return aperture_check(kgem, num_pages); 544503b705cfSriastradh } 544603b705cfSriastradh 54479a906b70Schristos if (busy) 54489a906b70Schristos return true; 544903b705cfSriastradh 54509a906b70Schristos return kgem_flush(kgem, flush); 545103b705cfSriastradh} 545203b705cfSriastradh 545303b705cfSriastradhbool kgem_check_bo_fenced(struct kgem *kgem, struct kgem_bo *bo) 545403b705cfSriastradh{ 545503b705cfSriastradh assert(bo->refcnt); 545603b705cfSriastradh while (bo->proxy) 545703b705cfSriastradh bo = bo->proxy; 545803b705cfSriastradh assert(bo->refcnt); 545903b705cfSriastradh 546003b705cfSriastradh if (bo->exec) { 546103b705cfSriastradh if (kgem->gen < 040 && 546203b705cfSriastradh bo->tiling != I915_TILING_NONE && 546303b705cfSriastradh (bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0) { 54649a906b70Schristos uint32_t size; 54659a906b70Schristos 54669a906b70Schristos assert(bo->tiling == I915_TILING_X); 54679a906b70Schristos 546803b705cfSriastradh if (kgem->nfence >= kgem->fence_max) 546903b705cfSriastradh return false; 547003b705cfSriastradh 54719a906b70Schristos if (kgem->aperture_fenced) { 54729a906b70Schristos size = 3*kgem->aperture_fenced; 54739a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 54749a906b70Schristos size += kgem->aperture; 54759a906b70Schristos if (size > kgem->aperture_fenceable && 54769a906b70Schristos kgem_ring_is_idle(kgem, kgem->ring)) { 54779a906b70Schristos DBG(("%s: opportunistic fence flush\n", __FUNCTION__)); 54789a906b70Schristos return false; 54799a906b70Schristos } 54809a906b70Schristos } 548103b705cfSriastradh 54829a906b70Schristos size = kgem_bo_fenced_size(kgem, bo); 54839a906b70Schristos if (size > kgem->aperture_max_fence) 54849a906b70Schristos kgem->aperture_max_fence = size; 54859a906b70Schristos size += kgem->aperture_fenced; 54869a906b70Schristos if (kgem->gen < 033 && size < 2 * kgem->aperture_max_fence) 54879a906b70Schristos size = 2 * kgem->aperture_max_fence; 54889a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 54899a906b70Schristos size += kgem->aperture; 54909a906b70Schristos if (size > kgem->aperture_fenceable) { 54919a906b70Schristos DBG(("%s: estimated fence space required %d (fenced=%d, max_fence=%d, aperture=%d) exceeds fenceable aperture %d\n", 54929a906b70Schristos __FUNCTION__, size, kgem->aperture_fenced, kgem->aperture_max_fence, kgem->aperture, kgem->aperture_fenceable)); 549303b705cfSriastradh return false; 54949a906b70Schristos } 549503b705cfSriastradh } 549603b705cfSriastradh 549703b705cfSriastradh return true; 549803b705cfSriastradh } 549903b705cfSriastradh 550003b705cfSriastradh if (kgem->nexec >= KGEM_EXEC_SIZE(kgem) - 1) 550103b705cfSriastradh return false; 550203b705cfSriastradh 55039a906b70Schristos if (needs_batch_flush(kgem, bo)) 550403b705cfSriastradh return false; 550503b705cfSriastradh 550603b705cfSriastradh assert_tiling(kgem, bo); 550703b705cfSriastradh if (kgem->gen < 040 && bo->tiling != I915_TILING_NONE) { 55089a906b70Schristos uint32_t size; 55099a906b70Schristos 55109a906b70Schristos assert(bo->tiling == I915_TILING_X); 55119a906b70Schristos 551203b705cfSriastradh if (kgem->nfence >= kgem->fence_max) 551303b705cfSriastradh return false; 551403b705cfSriastradh 55159a906b70Schristos if (kgem->aperture_fenced) { 55169a906b70Schristos size = 3*kgem->aperture_fenced; 55179a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 55189a906b70Schristos size += kgem->aperture; 55199a906b70Schristos if (size > kgem->aperture_fenceable && 55209a906b70Schristos kgem_ring_is_idle(kgem, kgem->ring)) { 55219a906b70Schristos DBG(("%s: opportunistic fence flush\n", __FUNCTION__)); 55229a906b70Schristos return false; 55239a906b70Schristos } 55249a906b70Schristos } 552503b705cfSriastradh 55269a906b70Schristos size = kgem_bo_fenced_size(kgem, bo); 55279a906b70Schristos if (size > kgem->aperture_max_fence) 55289a906b70Schristos kgem->aperture_max_fence = size; 55299a906b70Schristos size += kgem->aperture_fenced; 55309a906b70Schristos if (kgem->gen < 033 && size < 2 * kgem->aperture_max_fence) 55319a906b70Schristos size = 2 * kgem->aperture_max_fence; 55329a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 55339a906b70Schristos size += kgem->aperture; 55349a906b70Schristos if (size > kgem->aperture_fenceable) { 55359a906b70Schristos DBG(("%s: estimated fence space required %d (fenced=%d, max_fence=%d, aperture=%d) exceeds fenceable aperture %d\n", 55369a906b70Schristos __FUNCTION__, size, kgem->aperture_fenced, kgem->aperture_max_fence, kgem->aperture, kgem->aperture_fenceable)); 553703b705cfSriastradh return false; 55389a906b70Schristos } 553903b705cfSriastradh } 554003b705cfSriastradh 55419a906b70Schristos if (kgem->aperture + kgem->aperture_fenced + num_pages(bo) > kgem->aperture_high) { 55429a906b70Schristos DBG(("%s: final aperture usage (%d + %d) is greater than high water mark (%d)\n", 55439a906b70Schristos __FUNCTION__, kgem->aperture, num_pages(bo), kgem->aperture_high)); 55449a906b70Schristos return aperture_check(kgem, num_pages(bo)); 55459a906b70Schristos } 55469a906b70Schristos 55479a906b70Schristos if (bo->rq) 55489a906b70Schristos return true; 55499a906b70Schristos 55509a906b70Schristos return kgem_flush(kgem, bo->flush); 555103b705cfSriastradh} 555203b705cfSriastradh 555303b705cfSriastradhbool kgem_check_many_bo_fenced(struct kgem *kgem, ...) 555403b705cfSriastradh{ 555503b705cfSriastradh va_list ap; 555603b705cfSriastradh struct kgem_bo *bo; 555703b705cfSriastradh int num_fence = 0; 555803b705cfSriastradh int num_exec = 0; 555903b705cfSriastradh int num_pages = 0; 556003b705cfSriastradh int fenced_size = 0; 556103b705cfSriastradh bool flush = false; 55629a906b70Schristos bool busy = true; 556303b705cfSriastradh 556403b705cfSriastradh va_start(ap, kgem); 556503b705cfSriastradh while ((bo = va_arg(ap, struct kgem_bo *))) { 556603b705cfSriastradh assert(bo->refcnt); 556703b705cfSriastradh while (bo->proxy) 556803b705cfSriastradh bo = bo->proxy; 556903b705cfSriastradh assert(bo->refcnt); 557003b705cfSriastradh if (bo->exec) { 557103b705cfSriastradh if (kgem->gen >= 040 || bo->tiling == I915_TILING_NONE) 557203b705cfSriastradh continue; 557303b705cfSriastradh 557403b705cfSriastradh if ((bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0) { 557503b705cfSriastradh fenced_size += kgem_bo_fenced_size(kgem, bo); 557603b705cfSriastradh num_fence++; 557703b705cfSriastradh } 557803b705cfSriastradh 557903b705cfSriastradh continue; 558003b705cfSriastradh } 558103b705cfSriastradh 55829a906b70Schristos if (needs_batch_flush(kgem, bo)) { 55839a906b70Schristos va_end(ap); 558403b705cfSriastradh return false; 55859a906b70Schristos } 558603b705cfSriastradh 558703b705cfSriastradh assert_tiling(kgem, bo); 558803b705cfSriastradh num_pages += num_pages(bo); 558903b705cfSriastradh num_exec++; 559003b705cfSriastradh if (kgem->gen < 040 && bo->tiling) { 55919a906b70Schristos uint32_t size = kgem_bo_fenced_size(kgem, bo); 55929a906b70Schristos if (size > kgem->aperture_max_fence) 55939a906b70Schristos kgem->aperture_max_fence = size; 55949a906b70Schristos fenced_size += size; 559503b705cfSriastradh num_fence++; 559603b705cfSriastradh } 559703b705cfSriastradh 559803b705cfSriastradh flush |= bo->flush; 55999a906b70Schristos busy &= bo->rq != NULL; 560003b705cfSriastradh } 560103b705cfSriastradh va_end(ap); 560203b705cfSriastradh 560303b705cfSriastradh if (num_fence) { 56049a906b70Schristos uint32_t size; 56059a906b70Schristos 560603b705cfSriastradh if (kgem->nfence + num_fence > kgem->fence_max) 560703b705cfSriastradh return false; 560803b705cfSriastradh 56099a906b70Schristos if (kgem->aperture_fenced) { 56109a906b70Schristos size = 3*kgem->aperture_fenced; 56119a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 56129a906b70Schristos size += kgem->aperture; 56139a906b70Schristos if (size > kgem->aperture_fenceable && 56149a906b70Schristos kgem_ring_is_idle(kgem, kgem->ring)) { 56159a906b70Schristos DBG(("%s: opportunistic fence flush\n", __FUNCTION__)); 56169a906b70Schristos return false; 56179a906b70Schristos } 56189a906b70Schristos } 561903b705cfSriastradh 56209a906b70Schristos size = kgem->aperture_fenced; 56219a906b70Schristos size += fenced_size; 56229a906b70Schristos if (kgem->gen < 033 && size < 2 * kgem->aperture_max_fence) 56239a906b70Schristos size = 2 * kgem->aperture_max_fence; 56249a906b70Schristos if (kgem->aperture_total == kgem->aperture_mappable) 56259a906b70Schristos size += kgem->aperture; 56269a906b70Schristos if (size > kgem->aperture_fenceable) { 56279a906b70Schristos DBG(("%s: estimated fence space required %d (fenced=%d, max_fence=%d, aperture=%d) exceeds fenceable aperture %d\n", 56289a906b70Schristos __FUNCTION__, size, kgem->aperture_fenced, kgem->aperture_max_fence, kgem->aperture, kgem->aperture_fenceable)); 562903b705cfSriastradh return false; 56309a906b70Schristos } 563103b705cfSriastradh } 563203b705cfSriastradh 56339a906b70Schristos if (num_pages == 0) 56349a906b70Schristos return true; 563503b705cfSriastradh 56369a906b70Schristos if (kgem->nexec + num_exec >= KGEM_EXEC_SIZE(kgem)) 56379a906b70Schristos return false; 563803b705cfSriastradh 56399a906b70Schristos if (num_pages + kgem->aperture > kgem->aperture_high - kgem->aperture_fenced) { 56409a906b70Schristos DBG(("%s: final aperture usage (%d + %d + %d) is greater than high water mark (%d)\n", 56419a906b70Schristos __FUNCTION__, kgem->aperture, kgem->aperture_fenced, num_pages, kgem->aperture_high)); 56429a906b70Schristos return aperture_check(kgem, num_pages); 564303b705cfSriastradh } 564403b705cfSriastradh 56459a906b70Schristos if (busy) 56469a906b70Schristos return true; 56479a906b70Schristos 56489a906b70Schristos return kgem_flush(kgem, flush); 564903b705cfSriastradh} 565003b705cfSriastradh 565103b705cfSriastradhuint32_t kgem_add_reloc(struct kgem *kgem, 565203b705cfSriastradh uint32_t pos, 565303b705cfSriastradh struct kgem_bo *bo, 565403b705cfSriastradh uint32_t read_write_domain, 565503b705cfSriastradh uint32_t delta) 565603b705cfSriastradh{ 565703b705cfSriastradh int index; 565803b705cfSriastradh 565903b705cfSriastradh DBG(("%s: handle=%d, pos=%d, delta=%d, domains=%08x\n", 566003b705cfSriastradh __FUNCTION__, bo ? bo->handle : 0, pos, delta, read_write_domain)); 566103b705cfSriastradh 56629a906b70Schristos assert(kgem->gen < 0100); 566303b705cfSriastradh assert((read_write_domain & 0x7fff) == 0 || bo != NULL); 566403b705cfSriastradh 566503b705cfSriastradh index = kgem->nreloc++; 566603b705cfSriastradh assert(index < ARRAY_SIZE(kgem->reloc)); 566703b705cfSriastradh kgem->reloc[index].offset = pos * sizeof(kgem->batch[0]); 566803b705cfSriastradh if (bo) { 56699a906b70Schristos assert(kgem->mode != KGEM_NONE); 567003b705cfSriastradh assert(bo->refcnt); 567103b705cfSriastradh while (bo->proxy) { 567203b705cfSriastradh DBG(("%s: adding proxy [delta=%d] for handle=%d\n", 567303b705cfSriastradh __FUNCTION__, bo->delta, bo->handle)); 567403b705cfSriastradh delta += bo->delta; 567503b705cfSriastradh assert(bo->handle == bo->proxy->handle); 567603b705cfSriastradh /* need to release the cache upon batch submit */ 567703b705cfSriastradh if (bo->exec == NULL) { 567803b705cfSriastradh list_move_tail(&bo->request, 567903b705cfSriastradh &kgem->next_request->buffers); 568003b705cfSriastradh bo->rq = MAKE_REQUEST(kgem->next_request, 568103b705cfSriastradh kgem->ring); 568203b705cfSriastradh bo->exec = &_kgem_dummy_exec; 56839a906b70Schristos bo->domain = DOMAIN_GPU; 568403b705cfSriastradh } 568503b705cfSriastradh 568603b705cfSriastradh if (read_write_domain & 0x7fff && !bo->gpu_dirty) 568703b705cfSriastradh __kgem_bo_mark_dirty(bo); 568803b705cfSriastradh 568903b705cfSriastradh bo = bo->proxy; 569003b705cfSriastradh assert(bo->refcnt); 569103b705cfSriastradh } 569203b705cfSriastradh assert(bo->refcnt); 569303b705cfSriastradh 569403b705cfSriastradh if (bo->exec == NULL) 569503b705cfSriastradh kgem_add_bo(kgem, bo); 569603b705cfSriastradh assert(bo->rq == MAKE_REQUEST(kgem->next_request, kgem->ring)); 569703b705cfSriastradh assert(RQ_RING(bo->rq) == kgem->ring); 569803b705cfSriastradh 569903b705cfSriastradh if (kgem->gen < 040 && read_write_domain & KGEM_RELOC_FENCED) { 570003b705cfSriastradh if (bo->tiling && 570103b705cfSriastradh (bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0) { 57029a906b70Schristos assert(bo->tiling == I915_TILING_X); 570303b705cfSriastradh assert(kgem->nfence < kgem->fence_max); 570403b705cfSriastradh kgem->aperture_fenced += 570503b705cfSriastradh kgem_bo_fenced_size(kgem, bo); 570603b705cfSriastradh kgem->nfence++; 570703b705cfSriastradh } 570803b705cfSriastradh bo->exec->flags |= EXEC_OBJECT_NEEDS_FENCE; 570903b705cfSriastradh } 571003b705cfSriastradh 571103b705cfSriastradh kgem->reloc[index].delta = delta; 571203b705cfSriastradh kgem->reloc[index].target_handle = bo->target_handle; 571303b705cfSriastradh kgem->reloc[index].presumed_offset = bo->presumed_offset; 571403b705cfSriastradh 571503b705cfSriastradh if (read_write_domain & 0x7fff && !bo->gpu_dirty) { 571603b705cfSriastradh assert(!bo->snoop || kgem->can_blt_cpu); 571703b705cfSriastradh __kgem_bo_mark_dirty(bo); 571803b705cfSriastradh } 571903b705cfSriastradh 572003b705cfSriastradh delta += bo->presumed_offset; 572103b705cfSriastradh } else { 572203b705cfSriastradh kgem->reloc[index].delta = delta; 572303b705cfSriastradh kgem->reloc[index].target_handle = ~0U; 572403b705cfSriastradh kgem->reloc[index].presumed_offset = 0; 572503b705cfSriastradh if (kgem->nreloc__self < 256) 572603b705cfSriastradh kgem->reloc__self[kgem->nreloc__self++] = index; 572703b705cfSriastradh } 572803b705cfSriastradh kgem->reloc[index].read_domains = read_write_domain >> 16; 572903b705cfSriastradh kgem->reloc[index].write_domain = read_write_domain & 0x7fff; 573003b705cfSriastradh 573103b705cfSriastradh return delta; 573203b705cfSriastradh} 573303b705cfSriastradh 57349a906b70Schristosuint64_t kgem_add_reloc64(struct kgem *kgem, 57359a906b70Schristos uint32_t pos, 57369a906b70Schristos struct kgem_bo *bo, 57379a906b70Schristos uint32_t read_write_domain, 57389a906b70Schristos uint64_t delta) 57399a906b70Schristos{ 57409a906b70Schristos int index; 57419a906b70Schristos 57429a906b70Schristos DBG(("%s: handle=%d, pos=%d, delta=%ld, domains=%08x\n", 57439a906b70Schristos __FUNCTION__, bo ? bo->handle : 0, pos, (long)delta, read_write_domain)); 57449a906b70Schristos 57459a906b70Schristos assert(kgem->gen >= 0100); 57469a906b70Schristos assert((read_write_domain & 0x7fff) == 0 || bo != NULL); 57479a906b70Schristos 57489a906b70Schristos index = kgem->nreloc++; 57499a906b70Schristos assert(index < ARRAY_SIZE(kgem->reloc)); 57509a906b70Schristos kgem->reloc[index].offset = pos * sizeof(kgem->batch[0]); 57519a906b70Schristos if (bo) { 57529a906b70Schristos assert(kgem->mode != KGEM_NONE); 57539a906b70Schristos assert(bo->refcnt); 57549a906b70Schristos while (bo->proxy) { 57559a906b70Schristos DBG(("%s: adding proxy [delta=%ld] for handle=%d\n", 57569a906b70Schristos __FUNCTION__, (long)bo->delta, bo->handle)); 57579a906b70Schristos delta += bo->delta; 57589a906b70Schristos assert(bo->handle == bo->proxy->handle); 57599a906b70Schristos /* need to release the cache upon batch submit */ 57609a906b70Schristos if (bo->exec == NULL) { 57619a906b70Schristos list_move_tail(&bo->request, 57629a906b70Schristos &kgem->next_request->buffers); 57639a906b70Schristos bo->rq = MAKE_REQUEST(kgem->next_request, 57649a906b70Schristos kgem->ring); 57659a906b70Schristos bo->exec = &_kgem_dummy_exec; 57669a906b70Schristos bo->domain = DOMAIN_GPU; 57679a906b70Schristos } 57689a906b70Schristos 57699a906b70Schristos if (read_write_domain & 0x7fff && !bo->gpu_dirty) 57709a906b70Schristos __kgem_bo_mark_dirty(bo); 57719a906b70Schristos 57729a906b70Schristos bo = bo->proxy; 57739a906b70Schristos assert(bo->refcnt); 57749a906b70Schristos } 57759a906b70Schristos assert(bo->refcnt); 57769a906b70Schristos 57779a906b70Schristos if (bo->exec == NULL) 57789a906b70Schristos kgem_add_bo(kgem, bo); 57799a906b70Schristos assert(bo->rq == MAKE_REQUEST(kgem->next_request, kgem->ring)); 57809a906b70Schristos assert(RQ_RING(bo->rq) == kgem->ring); 57819a906b70Schristos 57829a906b70Schristos DBG(("%s[%d] = (delta=%d, target handle=%d, presumed=%llx)\n", 57839a906b70Schristos __FUNCTION__, index, delta, bo->target_handle, (long long)bo->presumed_offset)); 57849a906b70Schristos kgem->reloc[index].delta = delta; 57859a906b70Schristos kgem->reloc[index].target_handle = bo->target_handle; 57869a906b70Schristos kgem->reloc[index].presumed_offset = bo->presumed_offset; 57879a906b70Schristos 57889a906b70Schristos if (read_write_domain & 0x7fff && !bo->gpu_dirty) { 57899a906b70Schristos assert(!bo->snoop || kgem->can_blt_cpu); 57909a906b70Schristos __kgem_bo_mark_dirty(bo); 57919a906b70Schristos } 57929a906b70Schristos 57939a906b70Schristos delta += bo->presumed_offset; 57949a906b70Schristos } else { 57959a906b70Schristos DBG(("%s[%d] = (delta=%d, target handle=batch)\n", 57969a906b70Schristos __FUNCTION__, index, delta)); 57979a906b70Schristos kgem->reloc[index].delta = delta; 57989a906b70Schristos kgem->reloc[index].target_handle = ~0U; 57999a906b70Schristos kgem->reloc[index].presumed_offset = 0; 58009a906b70Schristos if (kgem->nreloc__self < 256) 58019a906b70Schristos kgem->reloc__self[kgem->nreloc__self++] = index; 58029a906b70Schristos } 58039a906b70Schristos kgem->reloc[index].read_domains = read_write_domain >> 16; 58049a906b70Schristos kgem->reloc[index].write_domain = read_write_domain & 0x7fff; 58059a906b70Schristos 58069a906b70Schristos return delta; 58079a906b70Schristos} 58089a906b70Schristos 580903b705cfSriastradhstatic void kgem_trim_vma_cache(struct kgem *kgem, int type, int bucket) 581003b705cfSriastradh{ 581103b705cfSriastradh int i, j; 581203b705cfSriastradh 581303b705cfSriastradh DBG(("%s: type=%d, count=%d (bucket: %d)\n", 581403b705cfSriastradh __FUNCTION__, type, kgem->vma[type].count, bucket)); 581503b705cfSriastradh if (kgem->vma[type].count <= 0) 581603b705cfSriastradh return; 581703b705cfSriastradh 581803b705cfSriastradh if (kgem->need_purge) 581903b705cfSriastradh kgem_purge_cache(kgem); 582003b705cfSriastradh 582103b705cfSriastradh /* vma are limited on a per-process basis to around 64k. 582203b705cfSriastradh * This includes all malloc arenas as well as other file 582303b705cfSriastradh * mappings. In order to be fair and not hog the cache, 582403b705cfSriastradh * and more importantly not to exhaust that limit and to 582503b705cfSriastradh * start failing mappings, we keep our own number of open 582603b705cfSriastradh * vma to within a conservative value. 582703b705cfSriastradh */ 582803b705cfSriastradh i = 0; 582903b705cfSriastradh while (kgem->vma[type].count > 0) { 583003b705cfSriastradh struct kgem_bo *bo = NULL; 58319a906b70Schristos void **ptr; 583203b705cfSriastradh 583303b705cfSriastradh for (j = 0; 583403b705cfSriastradh bo == NULL && j < ARRAY_SIZE(kgem->vma[type].inactive); 583503b705cfSriastradh j++) { 583603b705cfSriastradh struct list *head = &kgem->vma[type].inactive[i++%ARRAY_SIZE(kgem->vma[type].inactive)]; 583703b705cfSriastradh if (!list_is_empty(head)) 583803b705cfSriastradh bo = list_last_entry(head, struct kgem_bo, vma); 583903b705cfSriastradh } 584003b705cfSriastradh if (bo == NULL) 584103b705cfSriastradh break; 584203b705cfSriastradh 584303b705cfSriastradh DBG(("%s: discarding inactive %s vma cache for %d\n", 58449a906b70Schristos __FUNCTION__, type ? "CPU" : "GTT", bo->handle)); 58459a906b70Schristos 58469a906b70Schristos ptr = type ? &bo->map__cpu : &bo->map__gtt; 584703b705cfSriastradh assert(bo->rq == NULL); 584803b705cfSriastradh 58499a906b70Schristos VG(if (type) VALGRIND_MAKE_MEM_NOACCESS(MAP(*ptr), bytes(bo))); 58509a906b70Schristos munmap(MAP(*ptr), bytes(bo)); 58519a906b70Schristos *ptr = NULL; 585203b705cfSriastradh list_del(&bo->vma); 585303b705cfSriastradh kgem->vma[type].count--; 585403b705cfSriastradh 585503b705cfSriastradh if (!bo->purged && !kgem_bo_set_purgeable(kgem, bo)) { 585603b705cfSriastradh DBG(("%s: freeing unpurgeable old mapping\n", 585703b705cfSriastradh __FUNCTION__)); 585803b705cfSriastradh kgem_bo_free(kgem, bo); 585903b705cfSriastradh } 586003b705cfSriastradh } 586103b705cfSriastradh} 586203b705cfSriastradh 586303b705cfSriastradhvoid *kgem_bo_map__async(struct kgem *kgem, struct kgem_bo *bo) 586403b705cfSriastradh{ 586503b705cfSriastradh void *ptr; 586603b705cfSriastradh 58679a906b70Schristos DBG(("%s: handle=%d, offset=%ld, tiling=%d, map=%p:%p, domain=%d\n", __FUNCTION__, 58689a906b70Schristos bo->handle, (long)bo->presumed_offset, bo->tiling, bo->map__gtt, bo->map__cpu, bo->domain)); 586903b705cfSriastradh 587003b705cfSriastradh assert(bo->proxy == NULL); 587103b705cfSriastradh assert(list_is_empty(&bo->list)); 587203b705cfSriastradh assert_tiling(kgem, bo); 58739a906b70Schristos assert(!bo->purged || bo->reusable); 587403b705cfSriastradh 587503b705cfSriastradh if (bo->tiling == I915_TILING_NONE && !bo->scanout && kgem->has_llc) { 587603b705cfSriastradh DBG(("%s: converting request for GTT map into CPU map\n", 587703b705cfSriastradh __FUNCTION__)); 587803b705cfSriastradh return kgem_bo_map__cpu(kgem, bo); 587903b705cfSriastradh } 588003b705cfSriastradh 58819a906b70Schristos ptr = MAP(bo->map__gtt); 588203b705cfSriastradh if (ptr == NULL) { 58839a906b70Schristos assert(num_pages(bo) <= kgem->aperture_mappable / 2); 588403b705cfSriastradh 588503b705cfSriastradh kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo)); 588603b705cfSriastradh 588703b705cfSriastradh ptr = __kgem_bo_map__gtt(kgem, bo); 588803b705cfSriastradh if (ptr == NULL) 588903b705cfSriastradh return NULL; 589003b705cfSriastradh 589103b705cfSriastradh /* Cache this mapping to avoid the overhead of an 589203b705cfSriastradh * excruciatingly slow GTT pagefault. This is more an 589303b705cfSriastradh * issue with compositing managers which need to frequently 589403b705cfSriastradh * flush CPU damage to their GPU bo. 589503b705cfSriastradh */ 58969a906b70Schristos bo->map__gtt = ptr; 589703b705cfSriastradh DBG(("%s: caching GTT vma for %d\n", __FUNCTION__, bo->handle)); 589803b705cfSriastradh } 589903b705cfSriastradh 590003b705cfSriastradh return ptr; 590103b705cfSriastradh} 590203b705cfSriastradh 590303b705cfSriastradhvoid *kgem_bo_map(struct kgem *kgem, struct kgem_bo *bo) 590403b705cfSriastradh{ 590503b705cfSriastradh void *ptr; 590603b705cfSriastradh 59079a906b70Schristos DBG(("%s: handle=%d, offset=%ld, tiling=%d, map=%p:%p, domain=%d\n", __FUNCTION__, 59089a906b70Schristos bo->handle, (long)bo->presumed_offset, bo->tiling, bo->map__gtt, bo->map__cpu, bo->domain)); 590903b705cfSriastradh 591003b705cfSriastradh assert(bo->proxy == NULL); 591103b705cfSriastradh assert(list_is_empty(&bo->list)); 591203b705cfSriastradh assert(bo->exec == NULL); 591303b705cfSriastradh assert_tiling(kgem, bo); 59149a906b70Schristos assert(!bo->purged || bo->reusable); 591503b705cfSriastradh 591603b705cfSriastradh if (bo->tiling == I915_TILING_NONE && !bo->scanout && 591703b705cfSriastradh (kgem->has_llc || bo->domain == DOMAIN_CPU)) { 591803b705cfSriastradh DBG(("%s: converting request for GTT map into CPU map\n", 591903b705cfSriastradh __FUNCTION__)); 592003b705cfSriastradh ptr = kgem_bo_map__cpu(kgem, bo); 592103b705cfSriastradh if (ptr) 592203b705cfSriastradh kgem_bo_sync__cpu(kgem, bo); 592303b705cfSriastradh return ptr; 592403b705cfSriastradh } 592503b705cfSriastradh 59269a906b70Schristos ptr = MAP(bo->map__gtt); 592703b705cfSriastradh if (ptr == NULL) { 59289a906b70Schristos assert(num_pages(bo) <= kgem->aperture_mappable / 2); 592903b705cfSriastradh assert(kgem->gen != 021 || bo->tiling != I915_TILING_Y); 593003b705cfSriastradh 593103b705cfSriastradh kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo)); 593203b705cfSriastradh 593303b705cfSriastradh ptr = __kgem_bo_map__gtt(kgem, bo); 593403b705cfSriastradh if (ptr == NULL) 593503b705cfSriastradh return NULL; 593603b705cfSriastradh 593703b705cfSriastradh /* Cache this mapping to avoid the overhead of an 593803b705cfSriastradh * excruciatingly slow GTT pagefault. This is more an 593903b705cfSriastradh * issue with compositing managers which need to frequently 594003b705cfSriastradh * flush CPU damage to their GPU bo. 594103b705cfSriastradh */ 59429a906b70Schristos bo->map__gtt = ptr; 594303b705cfSriastradh DBG(("%s: caching GTT vma for %d\n", __FUNCTION__, bo->handle)); 594403b705cfSriastradh } 594503b705cfSriastradh 594603b705cfSriastradh if (bo->domain != DOMAIN_GTT || FORCE_MMAP_SYNC & (1 << DOMAIN_GTT)) { 594703b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 594803b705cfSriastradh 594903b705cfSriastradh DBG(("%s: sync: needs_flush? %d, domain? %d, busy? %d\n", __FUNCTION__, 595003b705cfSriastradh bo->needs_flush, bo->domain, __kgem_busy(kgem, bo->handle))); 595103b705cfSriastradh 595203b705cfSriastradh /* XXX use PROT_READ to avoid the write flush? */ 595303b705cfSriastradh 595403b705cfSriastradh VG_CLEAR(set_domain); 595503b705cfSriastradh set_domain.handle = bo->handle; 595603b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_GTT; 595703b705cfSriastradh set_domain.write_domain = I915_GEM_DOMAIN_GTT; 59589a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 59599a906b70Schristos DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 59609a906b70Schristos kgem_throttle(kgem); 596103b705cfSriastradh } 59629a906b70Schristos kgem_bo_retire(kgem, bo); 59639a906b70Schristos bo->domain = DOMAIN_GTT; 59649a906b70Schristos bo->gtt_dirty = true; 596503b705cfSriastradh } 596603b705cfSriastradh 596703b705cfSriastradh return ptr; 596803b705cfSriastradh} 596903b705cfSriastradh 597003b705cfSriastradhvoid *kgem_bo_map__gtt(struct kgem *kgem, struct kgem_bo *bo) 597103b705cfSriastradh{ 597203b705cfSriastradh void *ptr; 597303b705cfSriastradh 59749a906b70Schristos DBG(("%s: handle=%d, offset=%ld, tiling=%d, map=%p:%p, domain=%d\n", __FUNCTION__, 59759a906b70Schristos bo->handle, (long)bo->presumed_offset, bo->tiling, bo->map__gtt, bo->map__cpu, bo->domain)); 597603b705cfSriastradh 59779a906b70Schristos assert(bo->proxy == NULL); 597803b705cfSriastradh assert(bo->exec == NULL); 597903b705cfSriastradh assert(list_is_empty(&bo->list)); 598003b705cfSriastradh assert_tiling(kgem, bo); 59819a906b70Schristos assert(!bo->purged || bo->reusable); 598203b705cfSriastradh 59839a906b70Schristos ptr = MAP(bo->map__gtt); 598403b705cfSriastradh if (ptr == NULL) { 59859a906b70Schristos assert(num_pages(bo) <= kgem->aperture_mappable / 4); 598603b705cfSriastradh 598703b705cfSriastradh kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo)); 598803b705cfSriastradh 598903b705cfSriastradh ptr = __kgem_bo_map__gtt(kgem, bo); 599003b705cfSriastradh if (ptr == NULL) 599103b705cfSriastradh return NULL; 599203b705cfSriastradh 599303b705cfSriastradh /* Cache this mapping to avoid the overhead of an 599403b705cfSriastradh * excruciatingly slow GTT pagefault. This is more an 599503b705cfSriastradh * issue with compositing managers which need to frequently 599603b705cfSriastradh * flush CPU damage to their GPU bo. 599703b705cfSriastradh */ 59989a906b70Schristos bo->map__gtt = ptr; 599903b705cfSriastradh DBG(("%s: caching GTT vma for %d\n", __FUNCTION__, bo->handle)); 600003b705cfSriastradh } 600103b705cfSriastradh 600203b705cfSriastradh return ptr; 600303b705cfSriastradh} 600403b705cfSriastradh 600503b705cfSriastradhvoid *kgem_bo_map__debug(struct kgem *kgem, struct kgem_bo *bo) 600603b705cfSriastradh{ 60079a906b70Schristos return kgem_bo_map__async(kgem, bo); 600803b705cfSriastradh} 600903b705cfSriastradh 601003b705cfSriastradhvoid *kgem_bo_map__cpu(struct kgem *kgem, struct kgem_bo *bo) 601103b705cfSriastradh{ 601203b705cfSriastradh struct drm_i915_gem_mmap mmap_arg; 60139a906b70Schristos int err; 601403b705cfSriastradh 60159a906b70Schristos DBG(("%s(handle=%d, size=%d, map=%p:%p)\n", 60169a906b70Schristos __FUNCTION__, bo->handle, bytes(bo), bo->map__gtt, bo->map__cpu)); 601703b705cfSriastradh assert(!bo->purged); 601803b705cfSriastradh assert(list_is_empty(&bo->list)); 601903b705cfSriastradh assert(bo->proxy == NULL); 60209a906b70Schristos assert_tiling(kgem, bo); 602103b705cfSriastradh 60229a906b70Schristos if (bo->map__cpu) 60239a906b70Schristos return MAP(bo->map__cpu); 602403b705cfSriastradh 602503b705cfSriastradh kgem_trim_vma_cache(kgem, MAP_CPU, bucket(bo)); 602603b705cfSriastradh 602703b705cfSriastradhretry: 602803b705cfSriastradh VG_CLEAR(mmap_arg); 602903b705cfSriastradh mmap_arg.handle = bo->handle; 603003b705cfSriastradh mmap_arg.offset = 0; 603103b705cfSriastradh mmap_arg.size = bytes(bo); 60329a906b70Schristos if ((err = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg))) { 603303b705cfSriastradh assert(err != EINVAL); 603403b705cfSriastradh 603503b705cfSriastradh if (__kgem_throttle_retire(kgem, 0)) 603603b705cfSriastradh goto retry; 603703b705cfSriastradh 60389a906b70Schristos if (kgem_cleanup_cache(kgem)) 603903b705cfSriastradh goto retry; 604003b705cfSriastradh 60419a906b70Schristos ERR(("%s: failed to mmap handle=%d, %d bytes, into CPU domain: %d\n", 60429a906b70Schristos __FUNCTION__, bo->handle, bytes(bo), -err)); 604303b705cfSriastradh return NULL; 604403b705cfSriastradh } 604503b705cfSriastradh 604603b705cfSriastradh VG(VALGRIND_MAKE_MEM_DEFINED(mmap_arg.addr_ptr, bytes(bo))); 604703b705cfSriastradh 604803b705cfSriastradh DBG(("%s: caching CPU vma for %d\n", __FUNCTION__, bo->handle)); 60499a906b70Schristos return bo->map__cpu = (void *)(uintptr_t)mmap_arg.addr_ptr; 605003b705cfSriastradh} 605103b705cfSriastradh 605203b705cfSriastradhuint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo) 605303b705cfSriastradh{ 605403b705cfSriastradh struct drm_gem_flink flink; 605503b705cfSriastradh 605603b705cfSriastradh VG_CLEAR(flink); 605703b705cfSriastradh flink.handle = bo->handle; 60589a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_GEM_FLINK, &flink)) 605903b705cfSriastradh return 0; 606003b705cfSriastradh 606103b705cfSriastradh DBG(("%s: flinked handle=%d to name=%d, marking non-reusable\n", 606203b705cfSriastradh __FUNCTION__, flink.handle, flink.name)); 606303b705cfSriastradh 606403b705cfSriastradh /* Ordinarily giving the name aware makes the buffer non-reusable. 606503b705cfSriastradh * However, we track the lifetime of all clients and their hold 606603b705cfSriastradh * on the buffer, and *presuming* they do not pass it on to a third 606703b705cfSriastradh * party, we track the lifetime accurately. 606803b705cfSriastradh */ 606903b705cfSriastradh bo->reusable = false; 607003b705cfSriastradh 607103b705cfSriastradh kgem_bo_unclean(kgem, bo); 607203b705cfSriastradh 607303b705cfSriastradh return flink.name; 607403b705cfSriastradh} 607503b705cfSriastradh 607603b705cfSriastradhstruct kgem_bo *kgem_create_map(struct kgem *kgem, 607703b705cfSriastradh void *ptr, uint32_t size, 607803b705cfSriastradh bool read_only) 607903b705cfSriastradh{ 608003b705cfSriastradh struct kgem_bo *bo; 608103b705cfSriastradh uintptr_t first_page, last_page; 608203b705cfSriastradh uint32_t handle; 608303b705cfSriastradh 608403b705cfSriastradh assert(MAP(ptr) == ptr); 608503b705cfSriastradh 60869a906b70Schristos DBG(("%s(%p size=%d, read-only?=%d) - has_userptr?=%d\n", __FUNCTION__, 60879a906b70Schristos ptr, size, read_only, kgem->has_userptr)); 608803b705cfSriastradh if (!kgem->has_userptr) 608903b705cfSriastradh return NULL; 609003b705cfSriastradh 609103b705cfSriastradh first_page = (uintptr_t)ptr; 609203b705cfSriastradh last_page = first_page + size + PAGE_SIZE - 1; 609303b705cfSriastradh 609403b705cfSriastradh first_page &= ~(PAGE_SIZE-1); 609503b705cfSriastradh last_page &= ~(PAGE_SIZE-1); 609603b705cfSriastradh assert(last_page > first_page); 609703b705cfSriastradh 609803b705cfSriastradh handle = gem_userptr(kgem->fd, 609903b705cfSriastradh (void *)first_page, last_page-first_page, 610003b705cfSriastradh read_only); 61019a906b70Schristos if (handle == 0) { 61029a906b70Schristos DBG(("%s: import failed, errno=%d\n", __FUNCTION__, errno)); 610303b705cfSriastradh return NULL; 61049a906b70Schristos } 610503b705cfSriastradh 610603b705cfSriastradh bo = __kgem_bo_alloc(handle, (last_page - first_page) / PAGE_SIZE); 610703b705cfSriastradh if (bo == NULL) { 610803b705cfSriastradh gem_close(kgem->fd, handle); 610903b705cfSriastradh return NULL; 611003b705cfSriastradh } 611103b705cfSriastradh 61129a906b70Schristos bo->unique_id = kgem_get_unique_id(kgem); 611303b705cfSriastradh bo->snoop = !kgem->has_llc; 611403b705cfSriastradh debug_alloc__bo(kgem, bo); 611503b705cfSriastradh 611603b705cfSriastradh if (first_page != (uintptr_t)ptr) { 611703b705cfSriastradh struct kgem_bo *proxy; 611803b705cfSriastradh 611903b705cfSriastradh proxy = kgem_create_proxy(kgem, bo, 612003b705cfSriastradh (uintptr_t)ptr - first_page, size); 612103b705cfSriastradh kgem_bo_destroy(kgem, bo); 612203b705cfSriastradh if (proxy == NULL) 612303b705cfSriastradh return NULL; 612403b705cfSriastradh 612503b705cfSriastradh bo = proxy; 612603b705cfSriastradh } 612703b705cfSriastradh 61289a906b70Schristos bo->map__cpu = MAKE_USER_MAP(ptr); 612903b705cfSriastradh 613003b705cfSriastradh DBG(("%s(ptr=%p, size=%d, pages=%d, read_only=%d) => handle=%d (proxy? %d)\n", 613103b705cfSriastradh __FUNCTION__, ptr, size, NUM_PAGES(size), read_only, handle, bo->proxy != NULL)); 613203b705cfSriastradh return bo; 613303b705cfSriastradh} 613403b705cfSriastradh 613503b705cfSriastradhvoid kgem_bo_sync__cpu(struct kgem *kgem, struct kgem_bo *bo) 613603b705cfSriastradh{ 613703b705cfSriastradh DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle)); 613803b705cfSriastradh assert(!bo->scanout); 61399a906b70Schristos assert_tiling(kgem, bo); 61409a906b70Schristos 614103b705cfSriastradh kgem_bo_submit(kgem, bo); 614203b705cfSriastradh 614303b705cfSriastradh /* SHM pixmaps use proxies for subpage offsets */ 614403b705cfSriastradh assert(!bo->purged); 614503b705cfSriastradh while (bo->proxy) 614603b705cfSriastradh bo = bo->proxy; 614703b705cfSriastradh assert(!bo->purged); 614803b705cfSriastradh 614903b705cfSriastradh if (bo->domain != DOMAIN_CPU || FORCE_MMAP_SYNC & (1 << DOMAIN_CPU)) { 615003b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 615103b705cfSriastradh 615203b705cfSriastradh DBG(("%s: SYNC: handle=%d, needs_flush? %d, domain? %d, busy? %d\n", 615303b705cfSriastradh __FUNCTION__, bo->handle, 615403b705cfSriastradh bo->needs_flush, bo->domain, 615503b705cfSriastradh __kgem_busy(kgem, bo->handle))); 615603b705cfSriastradh 615703b705cfSriastradh VG_CLEAR(set_domain); 615803b705cfSriastradh set_domain.handle = bo->handle; 615903b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_CPU; 616003b705cfSriastradh set_domain.write_domain = I915_GEM_DOMAIN_CPU; 616103b705cfSriastradh 61629a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 61639a906b70Schristos DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 61649a906b70Schristos kgem_throttle(kgem); 616503b705cfSriastradh } 61669a906b70Schristos kgem_bo_retire(kgem, bo); 61679a906b70Schristos bo->domain = DOMAIN_CPU; 616803b705cfSriastradh } 616903b705cfSriastradh} 617003b705cfSriastradh 617103b705cfSriastradhvoid kgem_bo_sync__cpu_full(struct kgem *kgem, struct kgem_bo *bo, bool write) 617203b705cfSriastradh{ 617303b705cfSriastradh DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle)); 617403b705cfSriastradh assert(!bo->scanout || !write); 61759a906b70Schristos assert_tiling(kgem, bo); 617603b705cfSriastradh 617703b705cfSriastradh if (write || bo->needs_flush) 617803b705cfSriastradh kgem_bo_submit(kgem, bo); 617903b705cfSriastradh 618003b705cfSriastradh /* SHM pixmaps use proxies for subpage offsets */ 618103b705cfSriastradh assert(!bo->purged); 618203b705cfSriastradh assert(bo->refcnt); 618303b705cfSriastradh while (bo->proxy) 618403b705cfSriastradh bo = bo->proxy; 618503b705cfSriastradh assert(bo->refcnt); 618603b705cfSriastradh assert(!bo->purged); 618703b705cfSriastradh 618803b705cfSriastradh if (bo->domain != DOMAIN_CPU || FORCE_MMAP_SYNC & (1 << DOMAIN_CPU)) { 618903b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 619003b705cfSriastradh 619103b705cfSriastradh DBG(("%s: SYNC: handle=%d, needs_flush? %d, domain? %d, busy? %d\n", 619203b705cfSriastradh __FUNCTION__, bo->handle, 619303b705cfSriastradh bo->needs_flush, bo->domain, 619403b705cfSriastradh __kgem_busy(kgem, bo->handle))); 619503b705cfSriastradh 619603b705cfSriastradh VG_CLEAR(set_domain); 619703b705cfSriastradh set_domain.handle = bo->handle; 619803b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_CPU; 619903b705cfSriastradh set_domain.write_domain = write ? I915_GEM_DOMAIN_CPU : 0; 620003b705cfSriastradh 62019a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 62029a906b70Schristos DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 62039a906b70Schristos kgem_throttle(kgem); 62049a906b70Schristos } 62059a906b70Schristos if (write) { 62069a906b70Schristos kgem_bo_retire(kgem, bo); 62079a906b70Schristos bo->domain = DOMAIN_CPU; 62089a906b70Schristos } else { 620903b705cfSriastradh if (bo->exec == NULL) 62109a906b70Schristos kgem_bo_maybe_retire(kgem, bo); 62119a906b70Schristos bo->domain = DOMAIN_NONE; 621203b705cfSriastradh } 621303b705cfSriastradh } 621403b705cfSriastradh} 621503b705cfSriastradh 621603b705cfSriastradhvoid kgem_bo_sync__gtt(struct kgem *kgem, struct kgem_bo *bo) 621703b705cfSriastradh{ 621803b705cfSriastradh DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle)); 621903b705cfSriastradh assert(bo->refcnt); 622003b705cfSriastradh assert(bo->proxy == NULL); 62219a906b70Schristos assert_tiling(kgem, bo); 622203b705cfSriastradh 622303b705cfSriastradh kgem_bo_submit(kgem, bo); 622403b705cfSriastradh 622503b705cfSriastradh if (bo->domain != DOMAIN_GTT || FORCE_MMAP_SYNC & (1 << DOMAIN_GTT)) { 622603b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 622703b705cfSriastradh 622803b705cfSriastradh DBG(("%s: SYNC: handle=%d, needs_flush? %d, domain? %d, busy? %d\n", 622903b705cfSriastradh __FUNCTION__, bo->handle, 623003b705cfSriastradh bo->needs_flush, bo->domain, 623103b705cfSriastradh __kgem_busy(kgem, bo->handle))); 623203b705cfSriastradh 623303b705cfSriastradh VG_CLEAR(set_domain); 623403b705cfSriastradh set_domain.handle = bo->handle; 623503b705cfSriastradh set_domain.read_domains = I915_GEM_DOMAIN_GTT; 623603b705cfSriastradh set_domain.write_domain = I915_GEM_DOMAIN_GTT; 623703b705cfSriastradh 62389a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 62399a906b70Schristos DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 62409a906b70Schristos kgem_throttle(kgem); 624103b705cfSriastradh } 62429a906b70Schristos kgem_bo_retire(kgem, bo); 62439a906b70Schristos bo->domain = DOMAIN_GTT; 62449a906b70Schristos bo->gtt_dirty = true; 624503b705cfSriastradh } 624603b705cfSriastradh} 624703b705cfSriastradh 624803b705cfSriastradhvoid kgem_clear_dirty(struct kgem *kgem) 624903b705cfSriastradh{ 625003b705cfSriastradh struct list * const buffers = &kgem->next_request->buffers; 625103b705cfSriastradh struct kgem_bo *bo; 625203b705cfSriastradh 625303b705cfSriastradh list_for_each_entry(bo, buffers, request) { 625403b705cfSriastradh if (!bo->gpu_dirty) 625503b705cfSriastradh break; 625603b705cfSriastradh 625703b705cfSriastradh bo->gpu_dirty = false; 625803b705cfSriastradh } 625903b705cfSriastradh} 626003b705cfSriastradh 626103b705cfSriastradhstruct kgem_bo *kgem_create_proxy(struct kgem *kgem, 626203b705cfSriastradh struct kgem_bo *target, 626303b705cfSriastradh int offset, int length) 626403b705cfSriastradh{ 626503b705cfSriastradh struct kgem_bo *bo; 626603b705cfSriastradh 626703b705cfSriastradh DBG(("%s: target handle=%d [proxy? %d], offset=%d, length=%d, io=%d\n", 626803b705cfSriastradh __FUNCTION__, target->handle, target->proxy ? target->proxy->delta : -1, 626903b705cfSriastradh offset, length, target->io)); 627003b705cfSriastradh 627103b705cfSriastradh bo = __kgem_bo_alloc(target->handle, length); 627203b705cfSriastradh if (bo == NULL) 627303b705cfSriastradh return NULL; 627403b705cfSriastradh 627503b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 627603b705cfSriastradh bo->reusable = false; 627703b705cfSriastradh bo->size.bytes = length; 627803b705cfSriastradh 627903b705cfSriastradh bo->io = target->io && target->proxy == NULL; 628003b705cfSriastradh bo->gpu_dirty = target->gpu_dirty; 628103b705cfSriastradh bo->tiling = target->tiling; 628203b705cfSriastradh bo->pitch = target->pitch; 628303b705cfSriastradh bo->flush = target->flush; 628403b705cfSriastradh bo->snoop = target->snoop; 628503b705cfSriastradh 628603b705cfSriastradh assert(!bo->scanout); 628703b705cfSriastradh bo->proxy = kgem_bo_reference(target); 628803b705cfSriastradh bo->delta = offset; 628903b705cfSriastradh 62909a906b70Schristos /* Proxies are only tracked for busyness on the current rq */ 62919a906b70Schristos if (target->exec && !bo->io) { 62929a906b70Schristos assert(RQ(target->rq) == kgem->next_request); 629303b705cfSriastradh list_move_tail(&bo->request, &kgem->next_request->buffers); 629403b705cfSriastradh bo->exec = &_kgem_dummy_exec; 62959a906b70Schristos bo->rq = target->rq; 629603b705cfSriastradh } 629703b705cfSriastradh 629803b705cfSriastradh return bo; 629903b705cfSriastradh} 630003b705cfSriastradh 630103b705cfSriastradhstatic struct kgem_buffer * 630203b705cfSriastradhbuffer_alloc(void) 630303b705cfSriastradh{ 630403b705cfSriastradh struct kgem_buffer *bo; 630503b705cfSriastradh 630603b705cfSriastradh bo = malloc(sizeof(*bo)); 630703b705cfSriastradh if (bo == NULL) 630803b705cfSriastradh return NULL; 630903b705cfSriastradh 631003b705cfSriastradh bo->mem = NULL; 631103b705cfSriastradh bo->need_io = false; 63129a906b70Schristos bo->mmapped = MMAPPED_CPU; 631303b705cfSriastradh 631403b705cfSriastradh return bo; 631503b705cfSriastradh} 631603b705cfSriastradh 631703b705cfSriastradhstatic struct kgem_buffer * 631803b705cfSriastradhbuffer_alloc_with_data(int num_pages) 631903b705cfSriastradh{ 632003b705cfSriastradh struct kgem_buffer *bo; 632103b705cfSriastradh 632203b705cfSriastradh bo = malloc(sizeof(*bo) + 2*UPLOAD_ALIGNMENT + num_pages * PAGE_SIZE); 632303b705cfSriastradh if (bo == NULL) 632403b705cfSriastradh return NULL; 632503b705cfSriastradh 632603b705cfSriastradh bo->mem = (void *)ALIGN((uintptr_t)bo + sizeof(*bo), UPLOAD_ALIGNMENT); 632703b705cfSriastradh bo->mmapped = false; 632803b705cfSriastradh return bo; 632903b705cfSriastradh} 633003b705cfSriastradh 633103b705cfSriastradhstatic inline bool 633203b705cfSriastradhuse_snoopable_buffer(struct kgem *kgem, uint32_t flags) 633303b705cfSriastradh{ 633403b705cfSriastradh if ((flags & KGEM_BUFFER_WRITE) == 0) 633503b705cfSriastradh return kgem->gen >= 030; 633603b705cfSriastradh 633703b705cfSriastradh return true; 633803b705cfSriastradh} 633903b705cfSriastradh 634003b705cfSriastradhstatic void 634103b705cfSriastradhinit_buffer_from_bo(struct kgem_buffer *bo, struct kgem_bo *old) 634203b705cfSriastradh{ 634303b705cfSriastradh DBG(("%s: reusing handle=%d for buffer\n", 634403b705cfSriastradh __FUNCTION__, old->handle)); 634503b705cfSriastradh 634603b705cfSriastradh assert(old->proxy == NULL); 634703b705cfSriastradh 634803b705cfSriastradh memcpy(&bo->base, old, sizeof(*old)); 634903b705cfSriastradh if (old->rq) 635003b705cfSriastradh list_replace(&old->request, &bo->base.request); 635103b705cfSriastradh else 635203b705cfSriastradh list_init(&bo->base.request); 635303b705cfSriastradh list_replace(&old->vma, &bo->base.vma); 635403b705cfSriastradh list_init(&bo->base.list); 635503b705cfSriastradh free(old); 635603b705cfSriastradh 635703b705cfSriastradh assert(bo->base.tiling == I915_TILING_NONE); 635803b705cfSriastradh 635903b705cfSriastradh bo->base.refcnt = 1; 636003b705cfSriastradh} 636103b705cfSriastradh 636203b705cfSriastradhstatic struct kgem_buffer * 636303b705cfSriastradhsearch_snoopable_buffer(struct kgem *kgem, unsigned alloc) 636403b705cfSriastradh{ 636503b705cfSriastradh struct kgem_buffer *bo; 636603b705cfSriastradh struct kgem_bo *old; 636703b705cfSriastradh 636803b705cfSriastradh old = search_snoop_cache(kgem, alloc, 0); 636903b705cfSriastradh if (old) { 637003b705cfSriastradh if (!old->io) { 637103b705cfSriastradh bo = buffer_alloc(); 637203b705cfSriastradh if (bo == NULL) 637303b705cfSriastradh return NULL; 637403b705cfSriastradh 637503b705cfSriastradh init_buffer_from_bo(bo, old); 637603b705cfSriastradh } else { 637703b705cfSriastradh bo = (struct kgem_buffer *)old; 637803b705cfSriastradh bo->base.refcnt = 1; 637903b705cfSriastradh } 638003b705cfSriastradh 638103b705cfSriastradh DBG(("%s: created CPU handle=%d for buffer, size %d\n", 638203b705cfSriastradh __FUNCTION__, bo->base.handle, num_pages(&bo->base))); 638303b705cfSriastradh 638403b705cfSriastradh assert(bo->base.snoop); 638503b705cfSriastradh assert(bo->base.tiling == I915_TILING_NONE); 638603b705cfSriastradh assert(num_pages(&bo->base) >= alloc); 63879a906b70Schristos assert(bo->mmapped == MMAPPED_CPU); 638803b705cfSriastradh assert(bo->need_io == false); 638903b705cfSriastradh 639003b705cfSriastradh bo->mem = kgem_bo_map__cpu(kgem, &bo->base); 639103b705cfSriastradh if (bo->mem == NULL) { 639203b705cfSriastradh bo->base.refcnt = 0; 639303b705cfSriastradh kgem_bo_free(kgem, &bo->base); 639403b705cfSriastradh bo = NULL; 639503b705cfSriastradh } 639603b705cfSriastradh 639703b705cfSriastradh return bo; 639803b705cfSriastradh } 639903b705cfSriastradh 640003b705cfSriastradh return NULL; 640103b705cfSriastradh} 640203b705cfSriastradh 640303b705cfSriastradhstatic struct kgem_buffer * 640403b705cfSriastradhcreate_snoopable_buffer(struct kgem *kgem, unsigned alloc) 640503b705cfSriastradh{ 640603b705cfSriastradh struct kgem_buffer *bo; 640703b705cfSriastradh uint32_t handle; 640803b705cfSriastradh 640903b705cfSriastradh if (kgem->has_llc) { 641003b705cfSriastradh struct kgem_bo *old; 641103b705cfSriastradh 641203b705cfSriastradh bo = buffer_alloc(); 641303b705cfSriastradh if (bo == NULL) 641403b705cfSriastradh return NULL; 641503b705cfSriastradh 641603b705cfSriastradh old = search_linear_cache(kgem, alloc, 641703b705cfSriastradh CREATE_INACTIVE | CREATE_CPU_MAP | CREATE_EXACT); 641803b705cfSriastradh if (old) { 641903b705cfSriastradh init_buffer_from_bo(bo, old); 642003b705cfSriastradh } else { 642103b705cfSriastradh handle = gem_create(kgem->fd, alloc); 642203b705cfSriastradh if (handle == 0) { 642303b705cfSriastradh free(bo); 642403b705cfSriastradh return NULL; 642503b705cfSriastradh } 642603b705cfSriastradh 642703b705cfSriastradh __kgem_bo_init(&bo->base, handle, alloc); 64289a906b70Schristos debug_alloc__bo(kgem, &bo->base); 642903b705cfSriastradh DBG(("%s: created CPU (LLC) handle=%d for buffer, size %d\n", 643003b705cfSriastradh __FUNCTION__, bo->base.handle, alloc)); 643103b705cfSriastradh } 643203b705cfSriastradh 643303b705cfSriastradh assert(bo->base.refcnt == 1); 64349a906b70Schristos assert(bo->mmapped == MMAPPED_CPU); 643503b705cfSriastradh assert(bo->need_io == false); 643603b705cfSriastradh 643703b705cfSriastradh bo->mem = kgem_bo_map__cpu(kgem, &bo->base); 643803b705cfSriastradh if (bo->mem != NULL) 643903b705cfSriastradh return bo; 644003b705cfSriastradh 644103b705cfSriastradh bo->base.refcnt = 0; /* for valgrind */ 644203b705cfSriastradh kgem_bo_free(kgem, &bo->base); 644303b705cfSriastradh } 644403b705cfSriastradh 644503b705cfSriastradh if (kgem->has_caching) { 644603b705cfSriastradh struct kgem_bo *old; 644703b705cfSriastradh 644803b705cfSriastradh bo = buffer_alloc(); 644903b705cfSriastradh if (bo == NULL) 645003b705cfSriastradh return NULL; 645103b705cfSriastradh 645203b705cfSriastradh old = search_linear_cache(kgem, alloc, 645303b705cfSriastradh CREATE_INACTIVE | CREATE_CPU_MAP | CREATE_EXACT); 645403b705cfSriastradh if (old) { 645503b705cfSriastradh init_buffer_from_bo(bo, old); 645603b705cfSriastradh } else { 645703b705cfSriastradh handle = gem_create(kgem->fd, alloc); 645803b705cfSriastradh if (handle == 0) { 645903b705cfSriastradh free(bo); 646003b705cfSriastradh return NULL; 646103b705cfSriastradh } 646203b705cfSriastradh 646303b705cfSriastradh __kgem_bo_init(&bo->base, handle, alloc); 64649a906b70Schristos debug_alloc__bo(kgem, &bo->base); 646503b705cfSriastradh DBG(("%s: created CPU handle=%d for buffer, size %d\n", 646603b705cfSriastradh __FUNCTION__, bo->base.handle, alloc)); 646703b705cfSriastradh } 646803b705cfSriastradh 646903b705cfSriastradh assert(bo->base.refcnt == 1); 64709a906b70Schristos assert(bo->mmapped == MMAPPED_CPU); 647103b705cfSriastradh assert(bo->need_io == false); 647203b705cfSriastradh 647303b705cfSriastradh if (!gem_set_caching(kgem->fd, bo->base.handle, SNOOPED)) 647403b705cfSriastradh goto free_caching; 647503b705cfSriastradh 647603b705cfSriastradh bo->base.snoop = true; 647703b705cfSriastradh 647803b705cfSriastradh bo->mem = kgem_bo_map__cpu(kgem, &bo->base); 647903b705cfSriastradh if (bo->mem == NULL) 648003b705cfSriastradh goto free_caching; 648103b705cfSriastradh 648203b705cfSriastradh return bo; 648303b705cfSriastradh 648403b705cfSriastradhfree_caching: 648503b705cfSriastradh bo->base.refcnt = 0; /* for valgrind */ 648603b705cfSriastradh kgem_bo_free(kgem, &bo->base); 648703b705cfSriastradh } 648803b705cfSriastradh 648903b705cfSriastradh if (kgem->has_userptr) { 649003b705cfSriastradh bo = buffer_alloc(); 649103b705cfSriastradh if (bo == NULL) 649203b705cfSriastradh return NULL; 649303b705cfSriastradh 649403b705cfSriastradh //if (posix_memalign(&ptr, 64, ALIGN(size, 64))) 649503b705cfSriastradh if (posix_memalign(&bo->mem, PAGE_SIZE, alloc * PAGE_SIZE)) { 649603b705cfSriastradh free(bo); 649703b705cfSriastradh return NULL; 649803b705cfSriastradh } 649903b705cfSriastradh 650003b705cfSriastradh handle = gem_userptr(kgem->fd, bo->mem, alloc * PAGE_SIZE, false); 650103b705cfSriastradh if (handle == 0) { 650203b705cfSriastradh free(bo->mem); 650303b705cfSriastradh free(bo); 650403b705cfSriastradh return NULL; 650503b705cfSriastradh } 650603b705cfSriastradh 650703b705cfSriastradh __kgem_bo_init(&bo->base, handle, alloc); 65089a906b70Schristos debug_alloc__bo(kgem, &bo->base); 650903b705cfSriastradh DBG(("%s: created snoop handle=%d for buffer\n", 651003b705cfSriastradh __FUNCTION__, bo->base.handle)); 651103b705cfSriastradh 65129a906b70Schristos assert(bo->mmapped == MMAPPED_CPU); 651303b705cfSriastradh assert(bo->need_io == false); 651403b705cfSriastradh 651503b705cfSriastradh bo->base.refcnt = 1; 651603b705cfSriastradh bo->base.snoop = true; 65179a906b70Schristos bo->base.map__cpu = MAKE_USER_MAP(bo->mem); 651803b705cfSriastradh 651903b705cfSriastradh return bo; 652003b705cfSriastradh } 652103b705cfSriastradh 652203b705cfSriastradh return NULL; 652303b705cfSriastradh} 652403b705cfSriastradh 652503b705cfSriastradhstruct kgem_bo *kgem_create_buffer(struct kgem *kgem, 652603b705cfSriastradh uint32_t size, uint32_t flags, 652703b705cfSriastradh void **ret) 652803b705cfSriastradh{ 652903b705cfSriastradh struct kgem_buffer *bo; 653003b705cfSriastradh unsigned offset, alloc; 653103b705cfSriastradh struct kgem_bo *old; 653203b705cfSriastradh 653303b705cfSriastradh DBG(("%s: size=%d, flags=%x [write?=%d, inplace?=%d, last?=%d]\n", 653403b705cfSriastradh __FUNCTION__, size, flags, 653503b705cfSriastradh !!(flags & KGEM_BUFFER_WRITE), 653603b705cfSriastradh !!(flags & KGEM_BUFFER_INPLACE), 653703b705cfSriastradh !!(flags & KGEM_BUFFER_LAST))); 653803b705cfSriastradh assert(size); 653903b705cfSriastradh /* we should never be asked to create anything TOO large */ 654003b705cfSriastradh assert(size <= kgem->max_object_size); 654103b705cfSriastradh 654203b705cfSriastradh#if !DBG_NO_UPLOAD_CACHE 654303b705cfSriastradh list_for_each_entry(bo, &kgem->batch_buffers, base.list) { 654403b705cfSriastradh assert(bo->base.io); 654503b705cfSriastradh assert(bo->base.refcnt >= 1); 654603b705cfSriastradh 654703b705cfSriastradh /* We can reuse any write buffer which we can fit */ 654803b705cfSriastradh if (flags == KGEM_BUFFER_LAST && 654903b705cfSriastradh bo->write == KGEM_BUFFER_WRITE && 65509a906b70Schristos bo->base.refcnt == 1 && 65519a906b70Schristos bo->mmapped == MMAPPED_NONE && 655203b705cfSriastradh size <= bytes(&bo->base)) { 655303b705cfSriastradh DBG(("%s: reusing write buffer for read of %d bytes? used=%d, total=%d\n", 655403b705cfSriastradh __FUNCTION__, size, bo->used, bytes(&bo->base))); 65559a906b70Schristos gem_write__cachealigned(kgem->fd, bo->base.handle, 65569a906b70Schristos 0, bo->used, bo->mem); 65579a906b70Schristos assert(list_is_empty(&bo->base.vma)); 655803b705cfSriastradh bo->need_io = 0; 655903b705cfSriastradh bo->write = 0; 656003b705cfSriastradh offset = 0; 656103b705cfSriastradh bo->used = size; 656203b705cfSriastradh goto done; 656303b705cfSriastradh } 656403b705cfSriastradh 656503b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) { 656603b705cfSriastradh if ((bo->write & KGEM_BUFFER_WRITE) == 0 || 656703b705cfSriastradh (((bo->write & ~flags) & KGEM_BUFFER_INPLACE) && 656803b705cfSriastradh !bo->base.snoop)) { 656903b705cfSriastradh DBG(("%s: skip write %x buffer, need %x\n", 657003b705cfSriastradh __FUNCTION__, bo->write, flags)); 657103b705cfSriastradh continue; 657203b705cfSriastradh } 657303b705cfSriastradh assert(bo->mmapped || bo->need_io); 657403b705cfSriastradh } else { 657503b705cfSriastradh if (bo->write & KGEM_BUFFER_WRITE) { 657603b705cfSriastradh DBG(("%s: skip write %x buffer, need %x\n", 657703b705cfSriastradh __FUNCTION__, bo->write, flags)); 657803b705cfSriastradh continue; 657903b705cfSriastradh } 658003b705cfSriastradh } 658103b705cfSriastradh 658203b705cfSriastradh if (bo->used + size <= bytes(&bo->base)) { 658303b705cfSriastradh DBG(("%s: reusing buffer? used=%d + size=%d, total=%d\n", 658403b705cfSriastradh __FUNCTION__, bo->used, size, bytes(&bo->base))); 658503b705cfSriastradh offset = bo->used; 658603b705cfSriastradh bo->used += size; 658703b705cfSriastradh goto done; 658803b705cfSriastradh } 658903b705cfSriastradh } 659003b705cfSriastradh 659103b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) { 659203b705cfSriastradh list_for_each_entry(bo, &kgem->active_buffers, base.list) { 659303b705cfSriastradh assert(bo->base.io); 659403b705cfSriastradh assert(bo->base.refcnt >= 1); 65959a906b70Schristos assert(bo->base.exec == NULL); 659603b705cfSriastradh assert(bo->mmapped); 65979a906b70Schristos assert(bo->mmapped == MMAPPED_GTT || kgem->has_llc || bo->base.snoop); 659803b705cfSriastradh 65999a906b70Schristos if ((bo->write & ~flags) & KGEM_BUFFER_INPLACE && !bo->base.snoop) { 660003b705cfSriastradh DBG(("%s: skip write %x buffer, need %x\n", 660103b705cfSriastradh __FUNCTION__, bo->write, flags)); 660203b705cfSriastradh continue; 660303b705cfSriastradh } 660403b705cfSriastradh 660503b705cfSriastradh if (bo->used + size <= bytes(&bo->base)) { 660603b705cfSriastradh DBG(("%s: reusing buffer? used=%d + size=%d, total=%d\n", 660703b705cfSriastradh __FUNCTION__, bo->used, size, bytes(&bo->base))); 660803b705cfSriastradh offset = bo->used; 660903b705cfSriastradh bo->used += size; 661003b705cfSriastradh list_move(&bo->base.list, &kgem->batch_buffers); 661103b705cfSriastradh goto done; 661203b705cfSriastradh } 66139a906b70Schristos 66149a906b70Schristos if (bo->base.refcnt == 1 && 66159a906b70Schristos size <= bytes(&bo->base) && 66169a906b70Schristos (bo->base.rq == NULL || 66179a906b70Schristos !__kgem_busy(kgem, bo->base.handle))) { 66189a906b70Schristos DBG(("%s: reusing whole buffer? size=%d, total=%d\n", 66199a906b70Schristos __FUNCTION__, size, bytes(&bo->base))); 66209a906b70Schristos __kgem_bo_clear_busy(&bo->base); 66219a906b70Schristos assert(list_is_empty(&bo->base.vma)); 66229a906b70Schristos 66239a906b70Schristos switch (bo->mmapped) { 66249a906b70Schristos case MMAPPED_CPU: 66259a906b70Schristos kgem_bo_sync__cpu(kgem, &bo->base); 66269a906b70Schristos break; 66279a906b70Schristos case MMAPPED_GTT: 66289a906b70Schristos kgem_bo_sync__gtt(kgem, &bo->base); 66299a906b70Schristos break; 66309a906b70Schristos } 66319a906b70Schristos 66329a906b70Schristos offset = 0; 66339a906b70Schristos bo->used = size; 66349a906b70Schristos list_move(&bo->base.list, &kgem->batch_buffers); 66359a906b70Schristos goto done; 66369a906b70Schristos } 663703b705cfSriastradh } 663803b705cfSriastradh } 663903b705cfSriastradh#endif 664003b705cfSriastradh 664103b705cfSriastradh#if !DBG_NO_MAP_UPLOAD 664203b705cfSriastradh /* Be a little more generous and hope to hold fewer mmappings */ 664303b705cfSriastradh alloc = ALIGN(2*size, kgem->buffer_size); 664403b705cfSriastradh if (alloc > MAX_CACHE_SIZE) 664503b705cfSriastradh alloc = ALIGN(size, kgem->buffer_size); 664603b705cfSriastradh if (alloc > MAX_CACHE_SIZE) 664703b705cfSriastradh alloc = PAGE_ALIGN(size); 664803b705cfSriastradh assert(alloc); 664903b705cfSriastradh 66509a906b70Schristos alloc /= PAGE_SIZE; 665103b705cfSriastradh if (alloc > kgem->aperture_mappable / 4) 665203b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 665303b705cfSriastradh 665403b705cfSriastradh if (kgem->has_llc && 665503b705cfSriastradh (flags & KGEM_BUFFER_WRITE_INPLACE) != KGEM_BUFFER_WRITE_INPLACE) { 665603b705cfSriastradh bo = buffer_alloc(); 665703b705cfSriastradh if (bo == NULL) 665803b705cfSriastradh goto skip_llc; 665903b705cfSriastradh 666003b705cfSriastradh old = NULL; 666103b705cfSriastradh if ((flags & KGEM_BUFFER_WRITE) == 0) 666203b705cfSriastradh old = search_linear_cache(kgem, alloc, CREATE_CPU_MAP); 666303b705cfSriastradh if (old == NULL) 666403b705cfSriastradh old = search_linear_cache(kgem, alloc, CREATE_INACTIVE | CREATE_CPU_MAP); 666503b705cfSriastradh if (old == NULL) 666603b705cfSriastradh old = search_linear_cache(kgem, NUM_PAGES(size), CREATE_INACTIVE | CREATE_CPU_MAP); 666703b705cfSriastradh if (old) { 666803b705cfSriastradh DBG(("%s: found LLC handle=%d for buffer\n", 666903b705cfSriastradh __FUNCTION__, old->handle)); 667003b705cfSriastradh 667103b705cfSriastradh init_buffer_from_bo(bo, old); 667203b705cfSriastradh } else { 667303b705cfSriastradh uint32_t handle = gem_create(kgem->fd, alloc); 667403b705cfSriastradh if (handle == 0) { 667503b705cfSriastradh free(bo); 667603b705cfSriastradh goto skip_llc; 667703b705cfSriastradh } 667803b705cfSriastradh __kgem_bo_init(&bo->base, handle, alloc); 66799a906b70Schristos debug_alloc__bo(kgem, &bo->base); 668003b705cfSriastradh DBG(("%s: created LLC handle=%d for buffer\n", 668103b705cfSriastradh __FUNCTION__, bo->base.handle)); 668203b705cfSriastradh } 668303b705cfSriastradh 668403b705cfSriastradh assert(bo->mmapped); 668503b705cfSriastradh assert(!bo->need_io); 668603b705cfSriastradh 668703b705cfSriastradh bo->mem = kgem_bo_map__cpu(kgem, &bo->base); 668803b705cfSriastradh if (bo->mem) { 668903b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) 669003b705cfSriastradh kgem_bo_sync__cpu(kgem, &bo->base); 669103b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 669203b705cfSriastradh goto init; 669303b705cfSriastradh } else { 669403b705cfSriastradh bo->base.refcnt = 0; /* for valgrind */ 669503b705cfSriastradh kgem_bo_free(kgem, &bo->base); 669603b705cfSriastradh } 669703b705cfSriastradh } 669803b705cfSriastradhskip_llc: 669903b705cfSriastradh 670003b705cfSriastradh if ((flags & KGEM_BUFFER_WRITE_INPLACE) == KGEM_BUFFER_WRITE_INPLACE) { 670103b705cfSriastradh /* The issue with using a GTT upload buffer is that we may 670203b705cfSriastradh * cause eviction-stalls in order to free up some GTT space. 670303b705cfSriastradh * An is-mappable? ioctl could help us detect when we are 670403b705cfSriastradh * about to block, or some per-page magic in the kernel. 670503b705cfSriastradh * 670603b705cfSriastradh * XXX This is especially noticeable on memory constrained 670703b705cfSriastradh * devices like gen2 or with relatively slow gpu like i3. 670803b705cfSriastradh */ 670903b705cfSriastradh DBG(("%s: searching for an inactive GTT map for upload\n", 671003b705cfSriastradh __FUNCTION__)); 671103b705cfSriastradh old = search_linear_cache(kgem, alloc, 671203b705cfSriastradh CREATE_EXACT | CREATE_INACTIVE | CREATE_GTT_MAP); 671303b705cfSriastradh#if HAVE_I915_GEM_BUFFER_INFO 671403b705cfSriastradh if (old) { 671503b705cfSriastradh struct drm_i915_gem_buffer_info info; 671603b705cfSriastradh 671703b705cfSriastradh /* An example of such a non-blocking ioctl might work */ 671803b705cfSriastradh 671903b705cfSriastradh VG_CLEAR(info); 672003b705cfSriastradh info.handle = handle; 67219a906b70Schristos if (do_ioctl(kgem->fd, 672203b705cfSriastradh DRM_IOCTL_I915_GEM_BUFFER_INFO, 672303b705cfSriastradh &fino) == 0) { 672403b705cfSriastradh old->presumed_offset = info.addr; 672503b705cfSriastradh if ((info.flags & I915_GEM_MAPPABLE) == 0) { 672603b705cfSriastradh kgem_bo_move_to_inactive(kgem, old); 672703b705cfSriastradh old = NULL; 672803b705cfSriastradh } 672903b705cfSriastradh } 673003b705cfSriastradh } 673103b705cfSriastradh#endif 673203b705cfSriastradh if (old == NULL) 673303b705cfSriastradh old = search_linear_cache(kgem, NUM_PAGES(size), 673403b705cfSriastradh CREATE_EXACT | CREATE_INACTIVE | CREATE_GTT_MAP); 673503b705cfSriastradh if (old == NULL) { 673603b705cfSriastradh old = search_linear_cache(kgem, alloc, CREATE_INACTIVE); 67379a906b70Schristos if (old && !kgem_bo_can_map(kgem, old)) { 673803b705cfSriastradh _kgem_bo_destroy(kgem, old); 673903b705cfSriastradh old = NULL; 674003b705cfSriastradh } 674103b705cfSriastradh } 674203b705cfSriastradh if (old) { 674303b705cfSriastradh DBG(("%s: reusing handle=%d for buffer\n", 674403b705cfSriastradh __FUNCTION__, old->handle)); 67459a906b70Schristos assert(kgem_bo_can_map(kgem, old)); 674603b705cfSriastradh assert(!old->snoop); 674703b705cfSriastradh assert(old->rq == NULL); 674803b705cfSriastradh 674903b705cfSriastradh bo = buffer_alloc(); 675003b705cfSriastradh if (bo == NULL) 675103b705cfSriastradh return NULL; 675203b705cfSriastradh 675303b705cfSriastradh init_buffer_from_bo(bo, old); 675403b705cfSriastradh assert(num_pages(&bo->base) >= NUM_PAGES(size)); 675503b705cfSriastradh 675603b705cfSriastradh assert(bo->mmapped); 675703b705cfSriastradh assert(bo->base.refcnt == 1); 675803b705cfSriastradh 675903b705cfSriastradh bo->mem = kgem_bo_map(kgem, &bo->base); 676003b705cfSriastradh if (bo->mem) { 67619a906b70Schristos if (bo->mem == MAP(bo->base.map__cpu)) 676203b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 67639a906b70Schristos else 67649a906b70Schristos bo->mmapped = MMAPPED_GTT; 676503b705cfSriastradh goto init; 676603b705cfSriastradh } else { 676703b705cfSriastradh bo->base.refcnt = 0; 676803b705cfSriastradh kgem_bo_free(kgem, &bo->base); 676903b705cfSriastradh } 677003b705cfSriastradh } 677103b705cfSriastradh } 677203b705cfSriastradh#else 677303b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 677403b705cfSriastradh#endif 677503b705cfSriastradh /* Be more parsimonious with pwrite/pread/cacheable buffers */ 677603b705cfSriastradh if ((flags & KGEM_BUFFER_INPLACE) == 0) 677703b705cfSriastradh alloc = NUM_PAGES(size); 677803b705cfSriastradh 677903b705cfSriastradh if (use_snoopable_buffer(kgem, flags)) { 678003b705cfSriastradh bo = search_snoopable_buffer(kgem, alloc); 678103b705cfSriastradh if (bo) { 678203b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) 678303b705cfSriastradh kgem_bo_sync__cpu(kgem, &bo->base); 678403b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 678503b705cfSriastradh goto init; 678603b705cfSriastradh } 678703b705cfSriastradh 678803b705cfSriastradh if ((flags & KGEM_BUFFER_INPLACE) == 0) { 678903b705cfSriastradh bo = create_snoopable_buffer(kgem, alloc); 679003b705cfSriastradh if (bo) 679103b705cfSriastradh goto init; 679203b705cfSriastradh } 679303b705cfSriastradh } 679403b705cfSriastradh 679503b705cfSriastradh flags &= ~KGEM_BUFFER_INPLACE; 679603b705cfSriastradh 679703b705cfSriastradh old = NULL; 679803b705cfSriastradh if ((flags & KGEM_BUFFER_WRITE) == 0) 679903b705cfSriastradh old = search_linear_cache(kgem, alloc, 0); 680003b705cfSriastradh if (old == NULL) 680103b705cfSriastradh old = search_linear_cache(kgem, alloc, CREATE_INACTIVE); 680203b705cfSriastradh if (old) { 680303b705cfSriastradh DBG(("%s: reusing ordinary handle %d for io\n", 680403b705cfSriastradh __FUNCTION__, old->handle)); 680503b705cfSriastradh bo = buffer_alloc_with_data(num_pages(old)); 680603b705cfSriastradh if (bo == NULL) 680703b705cfSriastradh return NULL; 680803b705cfSriastradh 680903b705cfSriastradh init_buffer_from_bo(bo, old); 681003b705cfSriastradh bo->need_io = flags & KGEM_BUFFER_WRITE; 681103b705cfSriastradh } else { 681203b705cfSriastradh unsigned hint; 681303b705cfSriastradh 681403b705cfSriastradh if (use_snoopable_buffer(kgem, flags)) { 681503b705cfSriastradh bo = create_snoopable_buffer(kgem, alloc); 681603b705cfSriastradh if (bo) 681703b705cfSriastradh goto init; 681803b705cfSriastradh } 681903b705cfSriastradh 682003b705cfSriastradh bo = buffer_alloc(); 682103b705cfSriastradh if (bo == NULL) 682203b705cfSriastradh return NULL; 682303b705cfSriastradh 682403b705cfSriastradh hint = CREATE_INACTIVE; 682503b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) 682603b705cfSriastradh hint |= CREATE_CPU_MAP; 682703b705cfSriastradh old = search_linear_cache(kgem, alloc, hint); 682803b705cfSriastradh if (old) { 682903b705cfSriastradh DBG(("%s: reusing handle=%d for buffer\n", 683003b705cfSriastradh __FUNCTION__, old->handle)); 683103b705cfSriastradh 683203b705cfSriastradh init_buffer_from_bo(bo, old); 683303b705cfSriastradh } else { 683403b705cfSriastradh uint32_t handle = gem_create(kgem->fd, alloc); 683503b705cfSriastradh if (handle == 0) { 683603b705cfSriastradh free(bo); 683703b705cfSriastradh return NULL; 683803b705cfSriastradh } 683903b705cfSriastradh 684003b705cfSriastradh DBG(("%s: created handle=%d for buffer\n", 684103b705cfSriastradh __FUNCTION__, handle)); 684203b705cfSriastradh 684303b705cfSriastradh __kgem_bo_init(&bo->base, handle, alloc); 68449a906b70Schristos debug_alloc__bo(kgem, &bo->base); 684503b705cfSriastradh } 684603b705cfSriastradh 684703b705cfSriastradh assert(bo->mmapped); 684803b705cfSriastradh assert(!bo->need_io); 684903b705cfSriastradh assert(bo->base.refcnt == 1); 685003b705cfSriastradh 685103b705cfSriastradh if (flags & KGEM_BUFFER_WRITE) { 685203b705cfSriastradh bo->mem = kgem_bo_map__cpu(kgem, &bo->base); 685303b705cfSriastradh if (bo->mem != NULL) { 685403b705cfSriastradh kgem_bo_sync__cpu(kgem, &bo->base); 685503b705cfSriastradh goto init; 685603b705cfSriastradh } 685703b705cfSriastradh } 685803b705cfSriastradh 685903b705cfSriastradh DBG(("%s: failing back to new pwrite buffer\n", __FUNCTION__)); 686003b705cfSriastradh old = &bo->base; 686103b705cfSriastradh bo = buffer_alloc_with_data(num_pages(old)); 686203b705cfSriastradh if (bo == NULL) { 686303b705cfSriastradh old->refcnt= 0; 686403b705cfSriastradh kgem_bo_free(kgem, old); 686503b705cfSriastradh return NULL; 686603b705cfSriastradh } 686703b705cfSriastradh 686803b705cfSriastradh init_buffer_from_bo(bo, old); 686903b705cfSriastradh 687003b705cfSriastradh assert(bo->mem); 687103b705cfSriastradh assert(!bo->mmapped); 687203b705cfSriastradh assert(bo->base.refcnt == 1); 687303b705cfSriastradh 687403b705cfSriastradh bo->need_io = flags & KGEM_BUFFER_WRITE; 687503b705cfSriastradh } 687603b705cfSriastradhinit: 687703b705cfSriastradh bo->base.io = true; 687803b705cfSriastradh assert(bo->base.refcnt == 1); 687903b705cfSriastradh assert(num_pages(&bo->base) >= NUM_PAGES(size)); 688003b705cfSriastradh assert(!bo->need_io || !bo->base.needs_flush); 688103b705cfSriastradh assert(!bo->need_io || bo->base.domain != DOMAIN_GPU); 688203b705cfSriastradh assert(bo->mem); 68839a906b70Schristos assert(bo->mmapped != MMAPPED_GTT || MAP(bo->base.map__gtt) == bo->mem); 68849a906b70Schristos assert(bo->mmapped != MMAPPED_CPU || MAP(bo->base.map__cpu) == bo->mem); 688503b705cfSriastradh 688603b705cfSriastradh bo->used = size; 688703b705cfSriastradh bo->write = flags & KGEM_BUFFER_WRITE_INPLACE; 688803b705cfSriastradh offset = 0; 688903b705cfSriastradh 689003b705cfSriastradh assert(list_is_empty(&bo->base.list)); 689103b705cfSriastradh list_add(&bo->base.list, &kgem->batch_buffers); 689203b705cfSriastradh 689303b705cfSriastradh DBG(("%s(pages=%d [%d]) new handle=%d, used=%d, write=%d\n", 689403b705cfSriastradh __FUNCTION__, num_pages(&bo->base), alloc, bo->base.handle, bo->used, bo->write)); 689503b705cfSriastradh 689603b705cfSriastradhdone: 689703b705cfSriastradh bo->used = ALIGN(bo->used, UPLOAD_ALIGNMENT); 68989a906b70Schristos assert(bo->used && bo->used <= bytes(&bo->base)); 689903b705cfSriastradh assert(bo->mem); 690003b705cfSriastradh *ret = (char *)bo->mem + offset; 690103b705cfSriastradh return kgem_create_proxy(kgem, &bo->base, offset, size); 690203b705cfSriastradh} 690303b705cfSriastradh 690403b705cfSriastradhbool kgem_buffer_is_inplace(struct kgem_bo *_bo) 690503b705cfSriastradh{ 690603b705cfSriastradh struct kgem_buffer *bo = (struct kgem_buffer *)_bo->proxy; 690703b705cfSriastradh return bo->write & KGEM_BUFFER_WRITE_INPLACE; 690803b705cfSriastradh} 690903b705cfSriastradh 691003b705cfSriastradhstruct kgem_bo *kgem_create_buffer_2d(struct kgem *kgem, 691103b705cfSriastradh int width, int height, int bpp, 691203b705cfSriastradh uint32_t flags, 691303b705cfSriastradh void **ret) 691403b705cfSriastradh{ 691503b705cfSriastradh struct kgem_bo *bo; 691603b705cfSriastradh int stride; 691703b705cfSriastradh 691803b705cfSriastradh assert(width > 0 && height > 0); 691903b705cfSriastradh assert(ret != NULL); 692003b705cfSriastradh stride = ALIGN(width, 2) * bpp >> 3; 692103b705cfSriastradh stride = ALIGN(stride, 4); 692203b705cfSriastradh 692303b705cfSriastradh DBG(("%s: %dx%d, %d bpp, stride=%d\n", 692403b705cfSriastradh __FUNCTION__, width, height, bpp, stride)); 692503b705cfSriastradh 692603b705cfSriastradh bo = kgem_create_buffer(kgem, stride * ALIGN(height, 2), flags, ret); 692703b705cfSriastradh if (bo == NULL) { 692803b705cfSriastradh DBG(("%s: allocation failure for upload buffer\n", 692903b705cfSriastradh __FUNCTION__)); 693003b705cfSriastradh return NULL; 693103b705cfSriastradh } 693203b705cfSriastradh assert(*ret != NULL); 693303b705cfSriastradh assert(bo->proxy != NULL); 693403b705cfSriastradh 693503b705cfSriastradh if (height & 1) { 693603b705cfSriastradh struct kgem_buffer *io = (struct kgem_buffer *)bo->proxy; 693703b705cfSriastradh int min; 693803b705cfSriastradh 693903b705cfSriastradh assert(io->used); 694003b705cfSriastradh 694103b705cfSriastradh /* Having padded this surface to ensure that accesses to 694203b705cfSriastradh * the last pair of rows is valid, remove the padding so 694303b705cfSriastradh * that it can be allocated to other pixmaps. 694403b705cfSriastradh */ 694503b705cfSriastradh min = bo->delta + height * stride; 694603b705cfSriastradh min = ALIGN(min, UPLOAD_ALIGNMENT); 694703b705cfSriastradh if (io->used != min) { 694803b705cfSriastradh DBG(("%s: trimming buffer from %d to %d\n", 694903b705cfSriastradh __FUNCTION__, io->used, min)); 695003b705cfSriastradh io->used = min; 695103b705cfSriastradh } 695203b705cfSriastradh bo->size.bytes -= stride; 695303b705cfSriastradh } 695403b705cfSriastradh 69559a906b70Schristos bo->map__cpu = *ret; 695603b705cfSriastradh bo->pitch = stride; 695703b705cfSriastradh bo->unique_id = kgem_get_unique_id(kgem); 695803b705cfSriastradh return bo; 695903b705cfSriastradh} 696003b705cfSriastradh 696103b705cfSriastradhstruct kgem_bo *kgem_upload_source_image(struct kgem *kgem, 696203b705cfSriastradh const void *data, 696303b705cfSriastradh const BoxRec *box, 696403b705cfSriastradh int stride, int bpp) 696503b705cfSriastradh{ 696603b705cfSriastradh int width = box->x2 - box->x1; 696703b705cfSriastradh int height = box->y2 - box->y1; 696803b705cfSriastradh struct kgem_bo *bo; 696903b705cfSriastradh void *dst; 697003b705cfSriastradh 697103b705cfSriastradh if (!kgem_can_create_2d(kgem, width, height, bpp)) 697203b705cfSriastradh return NULL; 697303b705cfSriastradh 697403b705cfSriastradh DBG(("%s : (%d, %d), (%d, %d), stride=%d, bpp=%d\n", 697503b705cfSriastradh __FUNCTION__, box->x1, box->y1, box->x2, box->y2, stride, bpp)); 697603b705cfSriastradh 697703b705cfSriastradh assert(data); 697803b705cfSriastradh assert(width > 0); 697903b705cfSriastradh assert(height > 0); 698003b705cfSriastradh assert(stride); 698103b705cfSriastradh assert(bpp); 698203b705cfSriastradh 698303b705cfSriastradh bo = kgem_create_buffer_2d(kgem, 698403b705cfSriastradh width, height, bpp, 698503b705cfSriastradh KGEM_BUFFER_WRITE_INPLACE, &dst); 69869a906b70Schristos if (bo == NULL) 69879a906b70Schristos return NULL; 69889a906b70Schristos 69899a906b70Schristos if (sigtrap_get()) { 69909a906b70Schristos kgem_bo_destroy(kgem, bo); 69919a906b70Schristos return NULL; 69929a906b70Schristos } 69939a906b70Schristos 69949a906b70Schristos memcpy_blt(data, dst, bpp, 69959a906b70Schristos stride, bo->pitch, 69969a906b70Schristos box->x1, box->y1, 69979a906b70Schristos 0, 0, 69989a906b70Schristos width, height); 699903b705cfSriastradh 70009a906b70Schristos sigtrap_put(); 700103b705cfSriastradh return bo; 700203b705cfSriastradh} 700303b705cfSriastradh 700403b705cfSriastradhvoid kgem_proxy_bo_attach(struct kgem_bo *bo, 700503b705cfSriastradh struct kgem_bo **ptr) 700603b705cfSriastradh{ 700703b705cfSriastradh DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle)); 70089a906b70Schristos assert(bo->map__gtt == NULL); 700903b705cfSriastradh assert(bo->proxy); 701003b705cfSriastradh list_add(&bo->vma, &bo->proxy->vma); 70119a906b70Schristos bo->map__gtt = ptr; 701203b705cfSriastradh *ptr = kgem_bo_reference(bo); 701303b705cfSriastradh} 701403b705cfSriastradh 701503b705cfSriastradhvoid kgem_buffer_read_sync(struct kgem *kgem, struct kgem_bo *_bo) 701603b705cfSriastradh{ 701703b705cfSriastradh struct kgem_buffer *bo; 701803b705cfSriastradh uint32_t offset = _bo->delta, length = _bo->size.bytes; 701903b705cfSriastradh 702003b705cfSriastradh /* We expect the caller to have already submitted the batch */ 702103b705cfSriastradh assert(_bo->io); 702203b705cfSriastradh assert(_bo->exec == NULL); 702303b705cfSriastradh assert(_bo->rq == NULL); 702403b705cfSriastradh assert(_bo->proxy); 702503b705cfSriastradh 702603b705cfSriastradh _bo = _bo->proxy; 702703b705cfSriastradh assert(_bo->proxy == NULL); 702803b705cfSriastradh assert(_bo->exec == NULL); 702903b705cfSriastradh 703003b705cfSriastradh bo = (struct kgem_buffer *)_bo; 703103b705cfSriastradh 703203b705cfSriastradh DBG(("%s(offset=%d, length=%d, snooped=%d)\n", __FUNCTION__, 703303b705cfSriastradh offset, length, bo->base.snoop)); 703403b705cfSriastradh 703503b705cfSriastradh if (bo->mmapped) { 703603b705cfSriastradh struct drm_i915_gem_set_domain set_domain; 703703b705cfSriastradh 703803b705cfSriastradh DBG(("%s: sync: needs_flush? %d, domain? %d, busy? %d\n", 703903b705cfSriastradh __FUNCTION__, 704003b705cfSriastradh bo->base.needs_flush, 704103b705cfSriastradh bo->base.domain, 704203b705cfSriastradh __kgem_busy(kgem, bo->base.handle))); 704303b705cfSriastradh 70449a906b70Schristos assert(bo->mmapped == MMAPPED_GTT || bo->base.snoop || kgem->has_llc); 704503b705cfSriastradh 704603b705cfSriastradh VG_CLEAR(set_domain); 704703b705cfSriastradh set_domain.handle = bo->base.handle; 704803b705cfSriastradh set_domain.write_domain = 0; 704903b705cfSriastradh set_domain.read_domains = 70509a906b70Schristos bo->mmapped == MMAPPED_CPU ? I915_GEM_DOMAIN_CPU : I915_GEM_DOMAIN_GTT; 705103b705cfSriastradh 70529a906b70Schristos if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) { 70539a906b70Schristos DBG(("%s: sync: GPU hang detected\n", __FUNCTION__)); 70549a906b70Schristos kgem_throttle(kgem); 70559a906b70Schristos } 705603b705cfSriastradh } else { 705703b705cfSriastradh if (gem_read(kgem->fd, 705803b705cfSriastradh bo->base.handle, (char *)bo->mem+offset, 705903b705cfSriastradh offset, length)) 706003b705cfSriastradh return; 706103b705cfSriastradh } 70629a906b70Schristos kgem_bo_maybe_retire(kgem, &bo->base); 706303b705cfSriastradh bo->base.domain = DOMAIN_NONE; 706403b705cfSriastradh} 706503b705cfSriastradh 706603b705cfSriastradhuint32_t kgem_bo_get_binding(struct kgem_bo *bo, uint32_t format) 706703b705cfSriastradh{ 706803b705cfSriastradh struct kgem_bo_binding *b; 706903b705cfSriastradh 70709a906b70Schristos assert(bo->refcnt); 70719a906b70Schristos 707203b705cfSriastradh for (b = &bo->binding; b && b->offset; b = b->next) 707303b705cfSriastradh if (format == b->format) 707403b705cfSriastradh return b->offset; 707503b705cfSriastradh 707603b705cfSriastradh return 0; 707703b705cfSriastradh} 707803b705cfSriastradh 707903b705cfSriastradhvoid kgem_bo_set_binding(struct kgem_bo *bo, uint32_t format, uint16_t offset) 708003b705cfSriastradh{ 708103b705cfSriastradh struct kgem_bo_binding *b; 708203b705cfSriastradh 70839a906b70Schristos assert(bo->refcnt); 70849a906b70Schristos 708503b705cfSriastradh for (b = &bo->binding; b; b = b->next) { 708603b705cfSriastradh if (b->offset) 708703b705cfSriastradh continue; 708803b705cfSriastradh 708903b705cfSriastradh b->offset = offset; 709003b705cfSriastradh b->format = format; 709103b705cfSriastradh 709203b705cfSriastradh if (b->next) 709303b705cfSriastradh b->next->offset = 0; 709403b705cfSriastradh 709503b705cfSriastradh return; 709603b705cfSriastradh } 709703b705cfSriastradh 709803b705cfSriastradh b = malloc(sizeof(*b)); 709903b705cfSriastradh if (b) { 710003b705cfSriastradh b->next = bo->binding.next; 710103b705cfSriastradh b->format = format; 710203b705cfSriastradh b->offset = offset; 710303b705cfSriastradh bo->binding.next = b; 710403b705cfSriastradh } 710503b705cfSriastradh} 710603b705cfSriastradh 710703b705cfSriastradhstruct kgem_bo * 710803b705cfSriastradhkgem_replace_bo(struct kgem *kgem, 710903b705cfSriastradh struct kgem_bo *src, 711003b705cfSriastradh uint32_t width, 711103b705cfSriastradh uint32_t height, 711203b705cfSriastradh uint32_t pitch, 711303b705cfSriastradh uint32_t bpp) 711403b705cfSriastradh{ 711503b705cfSriastradh struct kgem_bo *dst; 711603b705cfSriastradh uint32_t br00, br13; 711703b705cfSriastradh uint32_t handle; 711803b705cfSriastradh uint32_t size; 711903b705cfSriastradh uint32_t *b; 712003b705cfSriastradh 712103b705cfSriastradh DBG(("%s: replacing bo handle=%d, size=%dx%d pitch=%d, with pitch=%d\n", 712203b705cfSriastradh __FUNCTION__, src->handle, width, height, src->pitch, pitch)); 712303b705cfSriastradh 712403b705cfSriastradh /* We only expect to be called to fixup small buffers, hence why 712503b705cfSriastradh * we only attempt to allocate a linear bo. 712603b705cfSriastradh */ 712703b705cfSriastradh assert(src->tiling == I915_TILING_NONE); 71289a906b70Schristos assert(kgem_bo_can_blt(kgem, src)); 712903b705cfSriastradh 713003b705cfSriastradh size = height * pitch; 713103b705cfSriastradh size = NUM_PAGES(size); 713203b705cfSriastradh 713303b705cfSriastradh dst = search_linear_cache(kgem, size, 0); 713403b705cfSriastradh if (dst == NULL) 713503b705cfSriastradh dst = search_linear_cache(kgem, size, CREATE_INACTIVE); 713603b705cfSriastradh if (dst == NULL) { 713703b705cfSriastradh handle = gem_create(kgem->fd, size); 713803b705cfSriastradh if (handle == 0) 713903b705cfSriastradh return NULL; 714003b705cfSriastradh 714103b705cfSriastradh dst = __kgem_bo_alloc(handle, size); 714203b705cfSriastradh if (dst == NULL) { 714303b705cfSriastradh gem_close(kgem->fd, handle); 714403b705cfSriastradh return NULL; 714503b705cfSriastradh } 714603b705cfSriastradh 714703b705cfSriastradh debug_alloc__bo(kgem, dst); 714803b705cfSriastradh } 714903b705cfSriastradh dst->pitch = pitch; 715003b705cfSriastradh dst->unique_id = kgem_get_unique_id(kgem); 715103b705cfSriastradh dst->refcnt = 1; 71529a906b70Schristos assert(dst->tiling == I915_TILING_NONE); 71539a906b70Schristos assert(kgem_bo_can_blt(kgem, dst)); 715403b705cfSriastradh 715503b705cfSriastradh kgem_set_mode(kgem, KGEM_BLT, dst); 71569a906b70Schristos if (!kgem_check_batch(kgem, 10) || 715703b705cfSriastradh !kgem_check_reloc(kgem, 2) || 715803b705cfSriastradh !kgem_check_many_bo_fenced(kgem, src, dst, NULL)) { 715903b705cfSriastradh kgem_submit(kgem); 716003b705cfSriastradh if (!kgem_check_many_bo_fenced(kgem, src, dst, NULL)) { 716103b705cfSriastradh kgem_bo_destroy(kgem, dst); 716203b705cfSriastradh return NULL; 716303b705cfSriastradh } 716403b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 716503b705cfSriastradh } 716603b705cfSriastradh 716703b705cfSriastradh br00 = XY_SRC_COPY_BLT_CMD; 716803b705cfSriastradh br13 = pitch; 716903b705cfSriastradh pitch = src->pitch; 717003b705cfSriastradh if (kgem->gen >= 040 && src->tiling) { 717103b705cfSriastradh br00 |= BLT_SRC_TILED; 717203b705cfSriastradh pitch >>= 2; 717303b705cfSriastradh } 717403b705cfSriastradh 717503b705cfSriastradh br13 |= 0xcc << 16; 717603b705cfSriastradh switch (bpp) { 717703b705cfSriastradh default: 717803b705cfSriastradh case 32: br00 |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 717903b705cfSriastradh br13 |= 1 << 25; /* RGB8888 */ 718003b705cfSriastradh case 16: br13 |= 1 << 24; /* RGB565 */ 718103b705cfSriastradh case 8: break; 718203b705cfSriastradh } 718303b705cfSriastradh 718403b705cfSriastradh b = kgem->batch + kgem->nbatch; 71859a906b70Schristos if (kgem->gen >= 0100) { 71869a906b70Schristos b[0] = br00 | 8; 71879a906b70Schristos b[1] = br13; 71889a906b70Schristos b[2] = 0; 71899a906b70Schristos b[3] = height << 16 | width; 71909a906b70Schristos *(uint64_t *)(b+4) = 71919a906b70Schristos kgem_add_reloc64(kgem, kgem->nbatch + 4, dst, 71929a906b70Schristos I915_GEM_DOMAIN_RENDER << 16 | 71939a906b70Schristos I915_GEM_DOMAIN_RENDER | 71949a906b70Schristos KGEM_RELOC_FENCED, 71959a906b70Schristos 0); 71969a906b70Schristos b[6] = 0; 71979a906b70Schristos b[7] = pitch; 71989a906b70Schristos *(uint64_t *)(b+8) = 71999a906b70Schristos kgem_add_reloc64(kgem, kgem->nbatch + 8, src, 72009a906b70Schristos I915_GEM_DOMAIN_RENDER << 16 | 72019a906b70Schristos KGEM_RELOC_FENCED, 72029a906b70Schristos 0); 72039a906b70Schristos kgem->nbatch += 10; 72049a906b70Schristos } else { 72059a906b70Schristos b[0] = br00 | 6; 72069a906b70Schristos b[1] = br13; 72079a906b70Schristos b[2] = 0; 72089a906b70Schristos b[3] = height << 16 | width; 72099a906b70Schristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst, 72109a906b70Schristos I915_GEM_DOMAIN_RENDER << 16 | 72119a906b70Schristos I915_GEM_DOMAIN_RENDER | 72129a906b70Schristos KGEM_RELOC_FENCED, 72139a906b70Schristos 0); 72149a906b70Schristos b[5] = 0; 72159a906b70Schristos b[6] = pitch; 72169a906b70Schristos b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src, 72179a906b70Schristos I915_GEM_DOMAIN_RENDER << 16 | 72189a906b70Schristos KGEM_RELOC_FENCED, 72199a906b70Schristos 0); 72209a906b70Schristos kgem->nbatch += 8; 72219a906b70Schristos } 722203b705cfSriastradh 722303b705cfSriastradh return dst; 722403b705cfSriastradh} 72259a906b70Schristos 72269a906b70Schristosbool kgem_bo_convert_to_gpu(struct kgem *kgem, 72279a906b70Schristos struct kgem_bo *bo, 72289a906b70Schristos unsigned flags) 72299a906b70Schristos{ 72309a906b70Schristos DBG(("%s: converting handle=%d from CPU to GPU, flags=%x\n", __FUNCTION__, bo->handle)); 72319a906b70Schristos assert(bo->tiling == I915_TILING_NONE); 72329a906b70Schristos 72339a906b70Schristos if (kgem->has_llc) 72349a906b70Schristos return true; 72359a906b70Schristos 72369a906b70Schristos if (flags & MOVE_ASYNC_HINT && __kgem_bo_is_busy(kgem, bo)) 72379a906b70Schristos return false; 72389a906b70Schristos 72399a906b70Schristos assert(bo->snoop); 72409a906b70Schristos 72419a906b70Schristos kgem_bo_submit(kgem, bo); 72429a906b70Schristos 72439a906b70Schristos if (!gem_set_caching(kgem->fd, bo->handle, UNCACHED)) 72449a906b70Schristos return false; 72459a906b70Schristos 72469a906b70Schristos bo->snoop = false; 72479a906b70Schristos return true; 72489a906b70Schristos} 7249