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