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