kgem.h revision 03b705cf
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#ifndef KGEM_H
2903b705cfSriastradh#define KGEM_H
3003b705cfSriastradh
3103b705cfSriastradh#include <stdint.h>
3203b705cfSriastradh#include <stdbool.h>
3303b705cfSriastradh#include <stdarg.h>
3403b705cfSriastradh
3503b705cfSriastradh#include <i915_drm.h>
3603b705cfSriastradh
3703b705cfSriastradh#include "compiler.h"
3803b705cfSriastradh
3903b705cfSriastradh#if HAS_DEBUG_FULL
4003b705cfSriastradh#define DBG(x) ErrorF x
4103b705cfSriastradh#else
4203b705cfSriastradh#define DBG(x)
4303b705cfSriastradh#endif
4403b705cfSriastradh
4503b705cfSriastradhstruct kgem_bo {
4603b705cfSriastradh	struct kgem_request *rq;
4703b705cfSriastradh#define RQ(rq) ((struct kgem_request *)((uintptr_t)(rq) & ~3))
4803b705cfSriastradh#define RQ_RING(rq) ((uintptr_t)(rq) & 3)
4903b705cfSriastradh#define RQ_IS_BLT(rq) (RQ_RING(rq) == KGEM_BLT)
5003b705cfSriastradh	struct drm_i915_gem_exec_object2 *exec;
5103b705cfSriastradh
5203b705cfSriastradh	struct kgem_bo *proxy;
5303b705cfSriastradh
5403b705cfSriastradh	struct list list;
5503b705cfSriastradh	struct list request;
5603b705cfSriastradh	struct list vma;
5703b705cfSriastradh
5803b705cfSriastradh	void *map;
5903b705cfSriastradh#define IS_CPU_MAP(ptr) ((uintptr_t)(ptr) & 1)
6003b705cfSriastradh#define IS_GTT_MAP(ptr) (ptr && ((uintptr_t)(ptr) & 1) == 0)
6103b705cfSriastradh#define MAP(ptr) ((void*)((uintptr_t)(ptr) & ~3))
6203b705cfSriastradh
6303b705cfSriastradh	struct kgem_bo_binding {
6403b705cfSriastradh		struct kgem_bo_binding *next;
6503b705cfSriastradh		uint32_t format;
6603b705cfSriastradh		uint16_t offset;
6703b705cfSriastradh	} binding;
6803b705cfSriastradh
6903b705cfSriastradh	uint32_t unique_id;
7003b705cfSriastradh	uint32_t refcnt;
7103b705cfSriastradh	uint32_t handle;
7203b705cfSriastradh	uint32_t target_handle;
7303b705cfSriastradh	uint32_t presumed_offset;
7403b705cfSriastradh	uint32_t delta;
7503b705cfSriastradh	union {
7603b705cfSriastradh		struct {
7703b705cfSriastradh			uint32_t count:27;
7803b705cfSriastradh#define PAGE_SIZE 4096
7903b705cfSriastradh			uint32_t bucket:5;
8003b705cfSriastradh#define NUM_CACHE_BUCKETS 16
8103b705cfSriastradh#define MAX_CACHE_SIZE (1 << (NUM_CACHE_BUCKETS+12))
8203b705cfSriastradh		} pages;
8303b705cfSriastradh		uint32_t bytes;
8403b705cfSriastradh	} size;
8503b705cfSriastradh	uint32_t pitch : 18; /* max 128k */
8603b705cfSriastradh	uint32_t tiling : 2;
8703b705cfSriastradh	uint32_t reusable : 1;
8803b705cfSriastradh	uint32_t gpu_dirty : 1;
8903b705cfSriastradh	uint32_t gtt_dirty : 1;
9003b705cfSriastradh	uint32_t domain : 2;
9103b705cfSriastradh	uint32_t needs_flush : 1;
9203b705cfSriastradh	uint32_t snoop : 1;
9303b705cfSriastradh	uint32_t io : 1;
9403b705cfSriastradh	uint32_t flush : 1;
9503b705cfSriastradh	uint32_t scanout : 1;
9603b705cfSriastradh	uint32_t purged : 1;
9703b705cfSriastradh};
9803b705cfSriastradh#define DOMAIN_NONE 0
9903b705cfSriastradh#define DOMAIN_CPU 1
10003b705cfSriastradh#define DOMAIN_GTT 2
10103b705cfSriastradh#define DOMAIN_GPU 3
10203b705cfSriastradh
10303b705cfSriastradhstruct kgem_request {
10403b705cfSriastradh	struct list list;
10503b705cfSriastradh	struct kgem_bo *bo;
10603b705cfSriastradh	struct list buffers;
10703b705cfSriastradh	int ring;
10803b705cfSriastradh};
10903b705cfSriastradh
11003b705cfSriastradhenum {
11103b705cfSriastradh	MAP_GTT = 0,
11203b705cfSriastradh	MAP_CPU,
11303b705cfSriastradh	NUM_MAP_TYPES,
11403b705cfSriastradh};
11503b705cfSriastradh
11603b705cfSriastradhstruct kgem {
11703b705cfSriastradh	int fd;
11803b705cfSriastradh	int wedged;
11903b705cfSriastradh	unsigned gen;
12003b705cfSriastradh
12103b705cfSriastradh	uint32_t unique_id;
12203b705cfSriastradh
12303b705cfSriastradh	enum kgem_mode {
12403b705cfSriastradh		/* order matches I915_EXEC_RING ordering */
12503b705cfSriastradh		KGEM_NONE = 0,
12603b705cfSriastradh		KGEM_RENDER,
12703b705cfSriastradh		KGEM_BSD,
12803b705cfSriastradh		KGEM_BLT,
12903b705cfSriastradh	} mode, ring;
13003b705cfSriastradh
13103b705cfSriastradh	struct list flushing;
13203b705cfSriastradh	struct list large;
13303b705cfSriastradh	struct list large_inactive;
13403b705cfSriastradh	struct list active[NUM_CACHE_BUCKETS][3];
13503b705cfSriastradh	struct list inactive[NUM_CACHE_BUCKETS];
13603b705cfSriastradh	struct list pinned_batches[2];
13703b705cfSriastradh	struct list snoop;
13803b705cfSriastradh	struct list scanout;
13903b705cfSriastradh	struct list batch_buffers, active_buffers;
14003b705cfSriastradh
14103b705cfSriastradh	struct list requests[2];
14203b705cfSriastradh	struct kgem_request *next_request;
14303b705cfSriastradh	struct kgem_request static_request;
14403b705cfSriastradh
14503b705cfSriastradh	struct {
14603b705cfSriastradh		struct list inactive[NUM_CACHE_BUCKETS];
14703b705cfSriastradh		int16_t count;
14803b705cfSriastradh	} vma[NUM_MAP_TYPES];
14903b705cfSriastradh
15003b705cfSriastradh	uint32_t batch_flags;
15103b705cfSriastradh	uint32_t batch_flags_base;
15203b705cfSriastradh#define I915_EXEC_SECURE (1<<9)
15303b705cfSriastradh#define LOCAL_EXEC_OBJECT_WRITE (1<<2)
15403b705cfSriastradh
15503b705cfSriastradh	uint16_t nbatch;
15603b705cfSriastradh	uint16_t surface;
15703b705cfSriastradh	uint16_t nexec;
15803b705cfSriastradh	uint16_t nreloc;
15903b705cfSriastradh	uint16_t nreloc__self;
16003b705cfSriastradh	uint16_t nfence;
16103b705cfSriastradh	uint16_t batch_size;
16203b705cfSriastradh	uint16_t min_alignment;
16303b705cfSriastradh
16403b705cfSriastradh	uint32_t flush:1;
16503b705cfSriastradh	uint32_t need_expire:1;
16603b705cfSriastradh	uint32_t need_purge:1;
16703b705cfSriastradh	uint32_t need_retire:1;
16803b705cfSriastradh	uint32_t need_throttle:1;
16903b705cfSriastradh	uint32_t scanout_busy:1;
17003b705cfSriastradh	uint32_t busy:1;
17103b705cfSriastradh
17203b705cfSriastradh	uint32_t has_create2 :1;
17303b705cfSriastradh	uint32_t has_userptr :1;
17403b705cfSriastradh	uint32_t has_blt :1;
17503b705cfSriastradh	uint32_t has_relaxed_fencing :1;
17603b705cfSriastradh	uint32_t has_relaxed_delta :1;
17703b705cfSriastradh	uint32_t has_semaphores :1;
17803b705cfSriastradh	uint32_t has_secure_batches :1;
17903b705cfSriastradh	uint32_t has_pinned_batches :1;
18003b705cfSriastradh	uint32_t has_caching :1;
18103b705cfSriastradh	uint32_t has_llc :1;
18203b705cfSriastradh	uint32_t has_wt :1;
18303b705cfSriastradh	uint32_t has_no_reloc :1;
18403b705cfSriastradh	uint32_t has_handle_lut :1;
18503b705cfSriastradh
18603b705cfSriastradh	uint32_t can_blt_cpu :1;
18703b705cfSriastradh
18803b705cfSriastradh	uint16_t fence_max;
18903b705cfSriastradh	uint16_t half_cpu_cache_pages;
19003b705cfSriastradh	uint32_t aperture_total, aperture_high, aperture_low, aperture_mappable;
19103b705cfSriastradh	uint32_t aperture, aperture_fenced;
19203b705cfSriastradh	uint32_t max_upload_tile_size, max_copy_tile_size;
19303b705cfSriastradh	uint32_t max_gpu_size, max_cpu_size;
19403b705cfSriastradh	uint32_t large_object_size, max_object_size;
19503b705cfSriastradh	uint32_t buffer_size;
19603b705cfSriastradh
19703b705cfSriastradh	void (*context_switch)(struct kgem *kgem, int new_mode);
19803b705cfSriastradh	void (*retire)(struct kgem *kgem);
19903b705cfSriastradh	void (*expire)(struct kgem *kgem);
20003b705cfSriastradh
20103b705cfSriastradh	void (*memcpy_to_tiled_x)(const void *src, void *dst, int bpp,
20203b705cfSriastradh				  int32_t src_stride, int32_t dst_stride,
20303b705cfSriastradh				  int16_t src_x, int16_t src_y,
20403b705cfSriastradh				  int16_t dst_x, int16_t dst_y,
20503b705cfSriastradh				  uint16_t width, uint16_t height);
20603b705cfSriastradh	void (*memcpy_from_tiled_x)(const void *src, void *dst, int bpp,
20703b705cfSriastradh				    int32_t src_stride, int32_t dst_stride,
20803b705cfSriastradh				    int16_t src_x, int16_t src_y,
20903b705cfSriastradh				    int16_t dst_x, int16_t dst_y,
21003b705cfSriastradh				    uint16_t width, uint16_t height);
21103b705cfSriastradh
21203b705cfSriastradh	uint16_t reloc__self[256];
21303b705cfSriastradh	uint32_t batch[64*1024-8] page_aligned;
21403b705cfSriastradh	struct drm_i915_gem_exec_object2 exec[384] page_aligned;
21503b705cfSriastradh	struct drm_i915_gem_relocation_entry reloc[8192] page_aligned;
21603b705cfSriastradh
21703b705cfSriastradh#ifdef DEBUG_MEMORY
21803b705cfSriastradh	struct {
21903b705cfSriastradh		int bo_allocs;
22003b705cfSriastradh		size_t bo_bytes;
22103b705cfSriastradh	} debug_memory;
22203b705cfSriastradh#endif
22303b705cfSriastradh};
22403b705cfSriastradh
22503b705cfSriastradh#define KGEM_MAX_DEFERRED_VBO 16
22603b705cfSriastradh
22703b705cfSriastradh#define KGEM_BATCH_RESERVED 1
22803b705cfSriastradh#define KGEM_RELOC_RESERVED (KGEM_MAX_DEFERRED_VBO)
22903b705cfSriastradh#define KGEM_EXEC_RESERVED (1+KGEM_MAX_DEFERRED_VBO)
23003b705cfSriastradh
23103b705cfSriastradh#ifndef ARRAY_SIZE
23203b705cfSriastradh#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
23303b705cfSriastradh#endif
23403b705cfSriastradh
23503b705cfSriastradh#define KGEM_BATCH_SIZE(K) ((K)->batch_size-KGEM_BATCH_RESERVED)
23603b705cfSriastradh#define KGEM_EXEC_SIZE(K) (int)(ARRAY_SIZE((K)->exec)-KGEM_EXEC_RESERVED)
23703b705cfSriastradh#define KGEM_RELOC_SIZE(K) (int)(ARRAY_SIZE((K)->reloc)-KGEM_RELOC_RESERVED)
23803b705cfSriastradh
23903b705cfSriastradhvoid kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen);
24003b705cfSriastradhvoid kgem_reset(struct kgem *kgem);
24103b705cfSriastradh
24203b705cfSriastradhstruct kgem_bo *kgem_create_map(struct kgem *kgem,
24303b705cfSriastradh				void *ptr, uint32_t size,
24403b705cfSriastradh				bool read_only);
24503b705cfSriastradh
24603b705cfSriastradhstruct kgem_bo *kgem_create_for_name(struct kgem *kgem, uint32_t name);
24703b705cfSriastradhstruct kgem_bo *kgem_create_for_prime(struct kgem *kgem, int name, uint32_t size);
24803b705cfSriastradhint kgem_bo_export_to_prime(struct kgem *kgem, struct kgem_bo *bo);
24903b705cfSriastradh
25003b705cfSriastradhstruct kgem_bo *kgem_create_linear(struct kgem *kgem, int size, unsigned flags);
25103b705cfSriastradhstruct kgem_bo *kgem_create_proxy(struct kgem *kgem,
25203b705cfSriastradh				  struct kgem_bo *target,
25303b705cfSriastradh				  int offset, int length);
25403b705cfSriastradh
25503b705cfSriastradhstruct kgem_bo *kgem_upload_source_image(struct kgem *kgem,
25603b705cfSriastradh					 const void *data,
25703b705cfSriastradh					 const BoxRec *box,
25803b705cfSriastradh					 int stride, int bpp);
25903b705cfSriastradhvoid kgem_proxy_bo_attach(struct kgem_bo *bo, struct kgem_bo **ptr);
26003b705cfSriastradh
26103b705cfSriastradhint kgem_choose_tiling(struct kgem *kgem,
26203b705cfSriastradh		       int tiling, int width, int height, int bpp);
26303b705cfSriastradhunsigned kgem_can_create_2d(struct kgem *kgem, int width, int height, int depth);
26403b705cfSriastradh#define KGEM_CAN_CREATE_GPU	0x1
26503b705cfSriastradh#define KGEM_CAN_CREATE_CPU	0x2
26603b705cfSriastradh#define KGEM_CAN_CREATE_LARGE	0x4
26703b705cfSriastradh#define KGEM_CAN_CREATE_GTT	0x8
26803b705cfSriastradh
26903b705cfSriastradhuint32_t kgem_get_unique_id(struct kgem *kgem);
27003b705cfSriastradh
27103b705cfSriastradhstruct kgem_bo *
27203b705cfSriastradhkgem_replace_bo(struct kgem *kgem,
27303b705cfSriastradh		struct kgem_bo *src,
27403b705cfSriastradh		uint32_t width,
27503b705cfSriastradh		uint32_t height,
27603b705cfSriastradh		uint32_t pitch,
27703b705cfSriastradh		uint32_t bpp);
27803b705cfSriastradhenum {
27903b705cfSriastradh	CREATE_EXACT = 0x1,
28003b705cfSriastradh	CREATE_INACTIVE = 0x2,
28103b705cfSriastradh	CREATE_CPU_MAP = 0x4,
28203b705cfSriastradh	CREATE_GTT_MAP = 0x8,
28303b705cfSriastradh	CREATE_SCANOUT = 0x10,
28403b705cfSriastradh	CREATE_PRIME = 0x20,
28503b705cfSriastradh	CREATE_TEMPORARY = 0x40,
28603b705cfSriastradh	CREATE_CACHED = 0x80,
28703b705cfSriastradh	CREATE_NO_RETIRE = 0x100,
28803b705cfSriastradh	CREATE_NO_THROTTLE = 0x200,
28903b705cfSriastradh};
29003b705cfSriastradhstruct kgem_bo *kgem_create_2d(struct kgem *kgem,
29103b705cfSriastradh			       int width,
29203b705cfSriastradh			       int height,
29303b705cfSriastradh			       int bpp,
29403b705cfSriastradh			       int tiling,
29503b705cfSriastradh			       uint32_t flags);
29603b705cfSriastradhstruct kgem_bo *kgem_create_cpu_2d(struct kgem *kgem,
29703b705cfSriastradh				   int width,
29803b705cfSriastradh				   int height,
29903b705cfSriastradh				   int bpp,
30003b705cfSriastradh				   uint32_t flags);
30103b705cfSriastradh
30203b705cfSriastradhuint32_t kgem_bo_get_binding(struct kgem_bo *bo, uint32_t format);
30303b705cfSriastradhvoid kgem_bo_set_binding(struct kgem_bo *bo, uint32_t format, uint16_t offset);
30403b705cfSriastradh
30503b705cfSriastradhbool kgem_retire(struct kgem *kgem);
30603b705cfSriastradh
30703b705cfSriastradhbool __kgem_ring_is_idle(struct kgem *kgem, int ring);
30803b705cfSriastradhstatic inline bool kgem_ring_is_idle(struct kgem *kgem, int ring)
30903b705cfSriastradh{
31003b705cfSriastradh	ring = ring == KGEM_BLT;
31103b705cfSriastradh
31203b705cfSriastradh	if (list_is_empty(&kgem->requests[ring]))
31303b705cfSriastradh		return true;
31403b705cfSriastradh
31503b705cfSriastradh	return __kgem_ring_is_idle(kgem, ring);
31603b705cfSriastradh}
31703b705cfSriastradh
31803b705cfSriastradhstatic inline bool kgem_is_idle(struct kgem *kgem)
31903b705cfSriastradh{
32003b705cfSriastradh	if (!kgem->need_retire)
32103b705cfSriastradh		return true;
32203b705cfSriastradh
32303b705cfSriastradh	return kgem_ring_is_idle(kgem, kgem->ring);
32403b705cfSriastradh}
32503b705cfSriastradh
32603b705cfSriastradhstatic inline bool __kgem_ring_empty(struct kgem *kgem)
32703b705cfSriastradh{
32803b705cfSriastradh	return list_is_empty(&kgem->requests[kgem->ring == KGEM_BLT]);
32903b705cfSriastradh}
33003b705cfSriastradh
33103b705cfSriastradhvoid _kgem_submit(struct kgem *kgem);
33203b705cfSriastradhstatic inline void kgem_submit(struct kgem *kgem)
33303b705cfSriastradh{
33403b705cfSriastradh	if (kgem->nbatch)
33503b705cfSriastradh		_kgem_submit(kgem);
33603b705cfSriastradh}
33703b705cfSriastradh
33803b705cfSriastradhstatic inline bool kgem_flush(struct kgem *kgem, bool flush)
33903b705cfSriastradh{
34003b705cfSriastradh	if (kgem->nreloc == 0)
34103b705cfSriastradh		return false;
34203b705cfSriastradh
34303b705cfSriastradh	return (kgem->flush ^ flush) && kgem_ring_is_idle(kgem, kgem->ring);
34403b705cfSriastradh}
34503b705cfSriastradh
34603b705cfSriastradhstatic inline void kgem_bo_submit(struct kgem *kgem, struct kgem_bo *bo)
34703b705cfSriastradh{
34803b705cfSriastradh	if (bo->exec)
34903b705cfSriastradh		_kgem_submit(kgem);
35003b705cfSriastradh}
35103b705cfSriastradh
35203b705cfSriastradhvoid kgem_scanout_flush(struct kgem *kgem, struct kgem_bo *bo);
35303b705cfSriastradh
35403b705cfSriastradhstatic inline struct kgem_bo *kgem_bo_reference(struct kgem_bo *bo)
35503b705cfSriastradh{
35603b705cfSriastradh	assert(bo->refcnt);
35703b705cfSriastradh	bo->refcnt++;
35803b705cfSriastradh	return bo;
35903b705cfSriastradh}
36003b705cfSriastradh
36103b705cfSriastradhvoid _kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo);
36203b705cfSriastradhstatic inline void kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
36303b705cfSriastradh{
36403b705cfSriastradh	assert(bo->refcnt);
36503b705cfSriastradh	if (--bo->refcnt == 0)
36603b705cfSriastradh		_kgem_bo_destroy(kgem, bo);
36703b705cfSriastradh}
36803b705cfSriastradh
36903b705cfSriastradhvoid kgem_clear_dirty(struct kgem *kgem);
37003b705cfSriastradh
37103b705cfSriastradhstatic inline void kgem_set_mode(struct kgem *kgem,
37203b705cfSriastradh				 enum kgem_mode mode,
37303b705cfSriastradh				 struct kgem_bo *bo)
37403b705cfSriastradh{
37503b705cfSriastradh	assert(!kgem->wedged);
37603b705cfSriastradh
37703b705cfSriastradh#if DEBUG_FLUSH_BATCH
37803b705cfSriastradh	kgem_submit(kgem);
37903b705cfSriastradh#endif
38003b705cfSriastradh
38103b705cfSriastradh	if (kgem->nreloc && bo->exec == NULL && kgem_ring_is_idle(kgem, kgem->ring))
38203b705cfSriastradh		_kgem_submit(kgem);
38303b705cfSriastradh
38403b705cfSriastradh	if (kgem->mode == mode)
38503b705cfSriastradh		return;
38603b705cfSriastradh
38703b705cfSriastradh	kgem->context_switch(kgem, mode);
38803b705cfSriastradh	kgem->mode = mode;
38903b705cfSriastradh}
39003b705cfSriastradh
39103b705cfSriastradhstatic inline void _kgem_set_mode(struct kgem *kgem, enum kgem_mode mode)
39203b705cfSriastradh{
39303b705cfSriastradh	assert(kgem->mode == KGEM_NONE);
39403b705cfSriastradh	assert(kgem->nbatch == 0);
39503b705cfSriastradh	assert(!kgem->wedged);
39603b705cfSriastradh	kgem->context_switch(kgem, mode);
39703b705cfSriastradh	kgem->mode = mode;
39803b705cfSriastradh}
39903b705cfSriastradh
40003b705cfSriastradhstatic inline bool kgem_check_batch(struct kgem *kgem, int num_dwords)
40103b705cfSriastradh{
40203b705cfSriastradh	assert(num_dwords > 0);
40303b705cfSriastradh	assert(kgem->nbatch < kgem->surface);
40403b705cfSriastradh	assert(kgem->surface <= kgem->batch_size);
40503b705cfSriastradh	return likely(kgem->nbatch + num_dwords + KGEM_BATCH_RESERVED <= kgem->surface);
40603b705cfSriastradh}
40703b705cfSriastradh
40803b705cfSriastradhstatic inline bool kgem_check_reloc(struct kgem *kgem, int n)
40903b705cfSriastradh{
41003b705cfSriastradh	assert(kgem->nreloc <= KGEM_RELOC_SIZE(kgem));
41103b705cfSriastradh	return likely(kgem->nreloc + n <= KGEM_RELOC_SIZE(kgem));
41203b705cfSriastradh}
41303b705cfSriastradh
41403b705cfSriastradhstatic inline bool kgem_check_exec(struct kgem *kgem, int n)
41503b705cfSriastradh{
41603b705cfSriastradh	assert(kgem->nexec <= KGEM_EXEC_SIZE(kgem));
41703b705cfSriastradh	return likely(kgem->nexec + n <= KGEM_EXEC_SIZE(kgem));
41803b705cfSriastradh}
41903b705cfSriastradh
42003b705cfSriastradhstatic inline bool kgem_check_reloc_and_exec(struct kgem *kgem, int n)
42103b705cfSriastradh{
42203b705cfSriastradh	return kgem_check_reloc(kgem, n) && kgem_check_exec(kgem, n);
42303b705cfSriastradh}
42403b705cfSriastradh
42503b705cfSriastradhstatic inline bool kgem_check_batch_with_surfaces(struct kgem *kgem,
42603b705cfSriastradh						  int num_dwords,
42703b705cfSriastradh						  int num_surfaces)
42803b705cfSriastradh{
42903b705cfSriastradh	return (int)(kgem->nbatch + num_dwords + KGEM_BATCH_RESERVED) <= (int)(kgem->surface - num_surfaces*8) &&
43003b705cfSriastradh		kgem_check_reloc(kgem, num_surfaces) &&
43103b705cfSriastradh		kgem_check_exec(kgem, num_surfaces);
43203b705cfSriastradh}
43303b705cfSriastradh
43403b705cfSriastradhstatic inline uint32_t *kgem_get_batch(struct kgem *kgem)
43503b705cfSriastradh{
43603b705cfSriastradh	if (kgem->nreloc) {
43703b705cfSriastradh		unsigned mode = kgem->mode;
43803b705cfSriastradh		_kgem_submit(kgem);
43903b705cfSriastradh		_kgem_set_mode(kgem, mode);
44003b705cfSriastradh	}
44103b705cfSriastradh
44203b705cfSriastradh	return kgem->batch + kgem->nbatch;
44303b705cfSriastradh}
44403b705cfSriastradh
44503b705cfSriastradhbool kgem_check_bo(struct kgem *kgem, ...) __attribute__((sentinel(0)));
44603b705cfSriastradhbool kgem_check_bo_fenced(struct kgem *kgem, struct kgem_bo *bo);
44703b705cfSriastradhbool kgem_check_many_bo_fenced(struct kgem *kgem, ...) __attribute__((sentinel(0)));
44803b705cfSriastradh
44903b705cfSriastradh#define KGEM_RELOC_FENCED 0x8000
45003b705cfSriastradhuint32_t kgem_add_reloc(struct kgem *kgem,
45103b705cfSriastradh			uint32_t pos,
45203b705cfSriastradh			struct kgem_bo *bo,
45303b705cfSriastradh			uint32_t read_write_domains,
45403b705cfSriastradh			uint32_t delta);
45503b705cfSriastradh
45603b705cfSriastradhvoid *kgem_bo_map(struct kgem *kgem, struct kgem_bo *bo);
45703b705cfSriastradhvoid *kgem_bo_map__async(struct kgem *kgem, struct kgem_bo *bo);
45803b705cfSriastradhvoid *kgem_bo_map__gtt(struct kgem *kgem, struct kgem_bo *bo);
45903b705cfSriastradhvoid kgem_bo_sync__gtt(struct kgem *kgem, struct kgem_bo *bo);
46003b705cfSriastradhvoid *kgem_bo_map__debug(struct kgem *kgem, struct kgem_bo *bo);
46103b705cfSriastradhvoid *kgem_bo_map__cpu(struct kgem *kgem, struct kgem_bo *bo);
46203b705cfSriastradhvoid kgem_bo_sync__cpu(struct kgem *kgem, struct kgem_bo *bo);
46303b705cfSriastradhvoid kgem_bo_sync__cpu_full(struct kgem *kgem, struct kgem_bo *bo, bool write);
46403b705cfSriastradhvoid *__kgem_bo_map__cpu(struct kgem *kgem, struct kgem_bo *bo);
46503b705cfSriastradhvoid __kgem_bo_unmap__cpu(struct kgem *kgem, struct kgem_bo *bo, void *ptr);
46603b705cfSriastradhuint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo);
46703b705cfSriastradh
46803b705cfSriastradhbool kgem_bo_write(struct kgem *kgem, struct kgem_bo *bo,
46903b705cfSriastradh		   const void *data, int length);
47003b705cfSriastradh
47103b705cfSriastradhint kgem_bo_fenced_size(struct kgem *kgem, struct kgem_bo *bo);
47203b705cfSriastradhvoid kgem_get_tile_size(struct kgem *kgem, int tiling,
47303b705cfSriastradh			int *tile_width, int *tile_height, int *tile_size);
47403b705cfSriastradh
47503b705cfSriastradhstatic inline int __kgem_buffer_size(struct kgem_bo *bo)
47603b705cfSriastradh{
47703b705cfSriastradh	assert(bo->proxy != NULL);
47803b705cfSriastradh	return bo->size.bytes;
47903b705cfSriastradh}
48003b705cfSriastradh
48103b705cfSriastradhstatic inline int __kgem_bo_size(struct kgem_bo *bo)
48203b705cfSriastradh{
48303b705cfSriastradh	assert(bo->proxy == NULL);
48403b705cfSriastradh	return PAGE_SIZE * bo->size.pages.count;
48503b705cfSriastradh}
48603b705cfSriastradh
48703b705cfSriastradhstatic inline int kgem_bo_size(struct kgem_bo *bo)
48803b705cfSriastradh{
48903b705cfSriastradh	if (bo->proxy)
49003b705cfSriastradh		return __kgem_buffer_size(bo);
49103b705cfSriastradh	else
49203b705cfSriastradh		return __kgem_bo_size(bo);
49303b705cfSriastradh}
49403b705cfSriastradh
49503b705cfSriastradhstatic inline bool kgem_bo_blt_pitch_is_ok(struct kgem *kgem,
49603b705cfSriastradh					   struct kgem_bo *bo)
49703b705cfSriastradh{
49803b705cfSriastradh	int pitch = bo->pitch;
49903b705cfSriastradh	if (kgem->gen >= 040 && bo->tiling)
50003b705cfSriastradh		pitch /= 4;
50103b705cfSriastradh	if (pitch > MAXSHORT) {
50203b705cfSriastradh		DBG(("%s: can not blt to handle=%d, adjusted pitch=%d\n",
50303b705cfSriastradh		     __FUNCTION__, bo->handle, pitch));
50403b705cfSriastradh		return false;
50503b705cfSriastradh	}
50603b705cfSriastradh
50703b705cfSriastradh	return true;
50803b705cfSriastradh}
50903b705cfSriastradh
51003b705cfSriastradhstatic inline bool kgem_bo_can_blt(struct kgem *kgem,
51103b705cfSriastradh				   struct kgem_bo *bo)
51203b705cfSriastradh{
51303b705cfSriastradh	if (bo->tiling == I915_TILING_Y) {
51403b705cfSriastradh		DBG(("%s: can not blt to handle=%d, tiling=Y\n",
51503b705cfSriastradh		     __FUNCTION__, bo->handle));
51603b705cfSriastradh		return false;
51703b705cfSriastradh	}
51803b705cfSriastradh
51903b705cfSriastradh	return kgem_bo_blt_pitch_is_ok(kgem, bo);
52003b705cfSriastradh}
52103b705cfSriastradh
52203b705cfSriastradhstatic inline bool __kgem_bo_is_mappable(struct kgem *kgem,
52303b705cfSriastradh					 struct kgem_bo *bo)
52403b705cfSriastradh{
52503b705cfSriastradh	if (bo->domain == DOMAIN_GTT)
52603b705cfSriastradh		return true;
52703b705cfSriastradh
52803b705cfSriastradh	if (kgem->gen < 040 && bo->tiling &&
52903b705cfSriastradh	    bo->presumed_offset & (kgem_bo_fenced_size(kgem, bo) - 1))
53003b705cfSriastradh		return false;
53103b705cfSriastradh
53203b705cfSriastradh	if (kgem->gen == 021 && bo->tiling == I915_TILING_Y)
53303b705cfSriastradh		return false;
53403b705cfSriastradh
53503b705cfSriastradh	if (kgem->has_llc && bo->tiling == I915_TILING_NONE)
53603b705cfSriastradh		return true;
53703b705cfSriastradh
53803b705cfSriastradh	if (!bo->presumed_offset)
53903b705cfSriastradh		return kgem_bo_size(bo) <= kgem->aperture_mappable / 4;
54003b705cfSriastradh
54103b705cfSriastradh	return bo->presumed_offset + kgem_bo_size(bo) <= kgem->aperture_mappable;
54203b705cfSriastradh}
54303b705cfSriastradh
54403b705cfSriastradhstatic inline bool kgem_bo_is_mappable(struct kgem *kgem,
54503b705cfSriastradh				       struct kgem_bo *bo)
54603b705cfSriastradh{
54703b705cfSriastradh	DBG(("%s: domain=%d, offset: %d size: %d\n",
54803b705cfSriastradh	     __FUNCTION__, bo->domain, bo->presumed_offset, kgem_bo_size(bo)));
54903b705cfSriastradh	assert(bo->refcnt);
55003b705cfSriastradh	return __kgem_bo_is_mappable(kgem, bo);
55103b705cfSriastradh}
55203b705cfSriastradh
55303b705cfSriastradhstatic inline bool kgem_bo_mapped(struct kgem *kgem, struct kgem_bo *bo)
55403b705cfSriastradh{
55503b705cfSriastradh	DBG(("%s: map=%p, tiling=%d, domain=%d\n",
55603b705cfSriastradh	     __FUNCTION__, bo->map, bo->tiling, bo->domain));
55703b705cfSriastradh	assert(bo->refcnt);
55803b705cfSriastradh
55903b705cfSriastradh	if (bo->map == NULL)
56003b705cfSriastradh		return bo->tiling == I915_TILING_NONE && bo->domain == DOMAIN_CPU;
56103b705cfSriastradh
56203b705cfSriastradh	return IS_CPU_MAP(bo->map) == !bo->tiling;
56303b705cfSriastradh}
56403b705cfSriastradh
56503b705cfSriastradhstatic inline bool kgem_bo_can_map(struct kgem *kgem, struct kgem_bo *bo)
56603b705cfSriastradh{
56703b705cfSriastradh	if (kgem_bo_mapped(kgem, bo))
56803b705cfSriastradh		return true;
56903b705cfSriastradh
57003b705cfSriastradh	if (!bo->tiling && (kgem->has_llc || bo->domain == DOMAIN_CPU))
57103b705cfSriastradh		return true;
57203b705cfSriastradh
57303b705cfSriastradh	if (kgem->gen == 021 && bo->tiling == I915_TILING_Y)
57403b705cfSriastradh		return false;
57503b705cfSriastradh
57603b705cfSriastradh	return kgem_bo_size(bo) <= kgem->aperture_mappable / 4;
57703b705cfSriastradh}
57803b705cfSriastradh
57903b705cfSriastradhstatic inline bool kgem_bo_can_map__cpu(struct kgem *kgem,
58003b705cfSriastradh					struct kgem_bo *bo,
58103b705cfSriastradh					bool write)
58203b705cfSriastradh{
58303b705cfSriastradh	if (bo->purged || (bo->scanout && write))
58403b705cfSriastradh		return false;
58503b705cfSriastradh
58603b705cfSriastradh	if (kgem->has_llc)
58703b705cfSriastradh		return true;
58803b705cfSriastradh
58903b705cfSriastradh	if (bo->domain != DOMAIN_CPU)
59003b705cfSriastradh		return false;
59103b705cfSriastradh
59203b705cfSriastradh	return !write || bo->exec == NULL;
59303b705cfSriastradh}
59403b705cfSriastradh
59503b705cfSriastradhstatic inline bool kgem_bo_is_snoop(struct kgem_bo *bo)
59603b705cfSriastradh{
59703b705cfSriastradh	assert(bo->refcnt);
59803b705cfSriastradh	while (bo->proxy)
59903b705cfSriastradh		bo = bo->proxy;
60003b705cfSriastradh	return bo->snoop;
60103b705cfSriastradh}
60203b705cfSriastradh
60303b705cfSriastradhvoid kgem_bo_undo(struct kgem *kgem, struct kgem_bo *bo);
60403b705cfSriastradh
60503b705cfSriastradhbool __kgem_busy(struct kgem *kgem, int handle);
60603b705cfSriastradh
60703b705cfSriastradhstatic inline void kgem_bo_mark_busy(struct kgem_bo *bo, int ring)
60803b705cfSriastradh{
60903b705cfSriastradh	bo->rq = (struct kgem_request *)((uintptr_t)bo->rq | ring);
61003b705cfSriastradh}
61103b705cfSriastradh
61203b705cfSriastradhinline static void __kgem_bo_clear_busy(struct kgem_bo *bo)
61303b705cfSriastradh{
61403b705cfSriastradh	bo->rq = NULL;
61503b705cfSriastradh	list_del(&bo->request);
61603b705cfSriastradh
61703b705cfSriastradh	bo->domain = DOMAIN_NONE;
61803b705cfSriastradh	bo->needs_flush = false;
61903b705cfSriastradh	bo->gtt_dirty = false;
62003b705cfSriastradh}
62103b705cfSriastradh
62203b705cfSriastradhstatic inline bool kgem_bo_is_busy(struct kgem_bo *bo)
62303b705cfSriastradh{
62403b705cfSriastradh	DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__,
62503b705cfSriastradh	     bo->handle, bo->domain, bo->exec != NULL, bo->rq != NULL));
62603b705cfSriastradh	assert(bo->refcnt);
62703b705cfSriastradh	return bo->rq;
62803b705cfSriastradh}
62903b705cfSriastradh
63003b705cfSriastradhstatic inline bool __kgem_bo_is_busy(struct kgem *kgem, struct kgem_bo *bo)
63103b705cfSriastradh{
63203b705cfSriastradh	DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__,
63303b705cfSriastradh	     bo->handle, bo->domain, bo->exec != NULL, bo->rq != NULL));
63403b705cfSriastradh	assert(bo->refcnt);
63503b705cfSriastradh
63603b705cfSriastradh	if (bo->exec)
63703b705cfSriastradh		return true;
63803b705cfSriastradh
63903b705cfSriastradh	if (kgem_flush(kgem, bo->flush))
64003b705cfSriastradh		kgem_submit(kgem);
64103b705cfSriastradh
64203b705cfSriastradh	if (bo->rq && !__kgem_busy(kgem, bo->handle))
64303b705cfSriastradh		__kgem_bo_clear_busy(bo);
64403b705cfSriastradh
64503b705cfSriastradh	return kgem_bo_is_busy(bo);
64603b705cfSriastradh}
64703b705cfSriastradh
64803b705cfSriastradhstatic inline bool kgem_bo_is_render(struct kgem_bo *bo)
64903b705cfSriastradh{
65003b705cfSriastradh	DBG(("%s: handle=%d, rq? %d [%d]\n", __FUNCTION__,
65103b705cfSriastradh	     bo->handle, bo->rq != NULL, RQ_RING(bo->rq)));
65203b705cfSriastradh	assert(bo->refcnt);
65303b705cfSriastradh	return bo->rq && RQ_RING(bo->rq) == I915_EXEC_RENDER;
65403b705cfSriastradh}
65503b705cfSriastradh
65603b705cfSriastradhstatic inline void kgem_bo_mark_unreusable(struct kgem_bo *bo)
65703b705cfSriastradh{
65803b705cfSriastradh	while (bo->proxy) {
65903b705cfSriastradh		bo->flush = true;
66003b705cfSriastradh		bo = bo->proxy;
66103b705cfSriastradh	}
66203b705cfSriastradh	bo->flush = true;
66303b705cfSriastradh	bo->reusable = false;
66403b705cfSriastradh}
66503b705cfSriastradh
66603b705cfSriastradhstatic inline bool kgem_bo_is_dirty(struct kgem_bo *bo)
66703b705cfSriastradh{
66803b705cfSriastradh	if (bo == NULL)
66903b705cfSriastradh		return false;
67003b705cfSriastradh
67103b705cfSriastradh	assert(bo->refcnt);
67203b705cfSriastradh	return bo->gpu_dirty;
67303b705cfSriastradh}
67403b705cfSriastradh
67503b705cfSriastradhstatic inline void kgem_bo_unclean(struct kgem *kgem, struct kgem_bo *bo)
67603b705cfSriastradh{
67703b705cfSriastradh	/* The bo is outside of our control, so presume it is written to */
67803b705cfSriastradh	bo->needs_flush = true;
67903b705cfSriastradh	if (bo->rq == NULL)
68003b705cfSriastradh		bo->rq = (void *)kgem;
68103b705cfSriastradh
68203b705cfSriastradh	if (bo->domain != DOMAIN_GPU)
68303b705cfSriastradh		bo->domain = DOMAIN_NONE;
68403b705cfSriastradh}
68503b705cfSriastradh
68603b705cfSriastradhstatic inline void __kgem_bo_mark_dirty(struct kgem_bo *bo)
68703b705cfSriastradh{
68803b705cfSriastradh	DBG(("%s: handle=%d (proxy? %d)\n", __FUNCTION__,
68903b705cfSriastradh	     bo->handle, bo->proxy != NULL));
69003b705cfSriastradh
69103b705cfSriastradh	bo->exec->flags |= LOCAL_EXEC_OBJECT_WRITE;
69203b705cfSriastradh	bo->needs_flush = bo->gpu_dirty = true;
69303b705cfSriastradh	list_move(&bo->request, &RQ(bo->rq)->buffers);
69403b705cfSriastradh}
69503b705cfSriastradh
69603b705cfSriastradhstatic inline void kgem_bo_mark_dirty(struct kgem_bo *bo)
69703b705cfSriastradh{
69803b705cfSriastradh	assert(bo->refcnt);
69903b705cfSriastradh	do {
70003b705cfSriastradh		assert(bo->exec);
70103b705cfSriastradh		assert(bo->rq);
70203b705cfSriastradh
70303b705cfSriastradh		if (bo->gpu_dirty)
70403b705cfSriastradh			return;
70503b705cfSriastradh
70603b705cfSriastradh		__kgem_bo_mark_dirty(bo);
70703b705cfSriastradh	} while ((bo = bo->proxy));
70803b705cfSriastradh}
70903b705cfSriastradh
71003b705cfSriastradh#define KGEM_BUFFER_WRITE	0x1
71103b705cfSriastradh#define KGEM_BUFFER_INPLACE	0x2
71203b705cfSriastradh#define KGEM_BUFFER_LAST	0x4
71303b705cfSriastradh
71403b705cfSriastradh#define KGEM_BUFFER_WRITE_INPLACE (KGEM_BUFFER_WRITE | KGEM_BUFFER_INPLACE)
71503b705cfSriastradh
71603b705cfSriastradhstruct kgem_bo *kgem_create_buffer(struct kgem *kgem,
71703b705cfSriastradh				   uint32_t size, uint32_t flags,
71803b705cfSriastradh				   void **ret);
71903b705cfSriastradhstruct kgem_bo *kgem_create_buffer_2d(struct kgem *kgem,
72003b705cfSriastradh				      int width, int height, int bpp,
72103b705cfSriastradh				      uint32_t flags,
72203b705cfSriastradh				      void **ret);
72303b705cfSriastradhbool kgem_buffer_is_inplace(struct kgem_bo *bo);
72403b705cfSriastradhvoid kgem_buffer_read_sync(struct kgem *kgem, struct kgem_bo *bo);
72503b705cfSriastradh
72603b705cfSriastradhvoid kgem_throttle(struct kgem *kgem);
72703b705cfSriastradh#define MAX_INACTIVE_TIME 10
72803b705cfSriastradhbool kgem_expire_cache(struct kgem *kgem);
72903b705cfSriastradhvoid kgem_purge_cache(struct kgem *kgem);
73003b705cfSriastradhvoid kgem_cleanup_cache(struct kgem *kgem);
73103b705cfSriastradh
73203b705cfSriastradhvoid kgem_clean_scanout_cache(struct kgem *kgem);
73303b705cfSriastradhvoid kgem_clean_large_cache(struct kgem *kgem);
73403b705cfSriastradh
73503b705cfSriastradh#if HAS_DEBUG_FULL
73603b705cfSriastradhvoid __kgem_batch_debug(struct kgem *kgem, uint32_t nbatch);
73703b705cfSriastradh#else
73803b705cfSriastradhstatic inline void __kgem_batch_debug(struct kgem *kgem, uint32_t nbatch)
73903b705cfSriastradh{
74003b705cfSriastradh	(void)kgem;
74103b705cfSriastradh	(void)nbatch;
74203b705cfSriastradh}
74303b705cfSriastradh#endif
74403b705cfSriastradh
74503b705cfSriastradhstatic inline void
74603b705cfSriastradhmemcpy_to_tiled_x(struct kgem *kgem,
74703b705cfSriastradh		  const void *src, void *dst, int bpp,
74803b705cfSriastradh		  int32_t src_stride, int32_t dst_stride,
74903b705cfSriastradh		  int16_t src_x, int16_t src_y,
75003b705cfSriastradh		  int16_t dst_x, int16_t dst_y,
75103b705cfSriastradh		  uint16_t width, uint16_t height)
75203b705cfSriastradh{
75303b705cfSriastradh	return kgem->memcpy_to_tiled_x(src, dst, bpp,
75403b705cfSriastradh				       src_stride, dst_stride,
75503b705cfSriastradh				       src_x, src_y,
75603b705cfSriastradh				       dst_x, dst_y,
75703b705cfSriastradh				       width, height);
75803b705cfSriastradh}
75903b705cfSriastradh
76003b705cfSriastradhstatic inline void
76103b705cfSriastradhmemcpy_from_tiled_x(struct kgem *kgem,
76203b705cfSriastradh		    const void *src, void *dst, int bpp,
76303b705cfSriastradh		    int32_t src_stride, int32_t dst_stride,
76403b705cfSriastradh		    int16_t src_x, int16_t src_y,
76503b705cfSriastradh		    int16_t dst_x, int16_t dst_y,
76603b705cfSriastradh		    uint16_t width, uint16_t height)
76703b705cfSriastradh{
76803b705cfSriastradh	return kgem->memcpy_from_tiled_x(src, dst, bpp,
76903b705cfSriastradh					 src_stride, dst_stride,
77003b705cfSriastradh					 src_x, src_y,
77103b705cfSriastradh					 dst_x, dst_y,
77203b705cfSriastradh					 width, height);
77303b705cfSriastradh}
77403b705cfSriastradh
77503b705cfSriastradhvoid choose_memcpy_tiled_x(struct kgem *kgem, int swizzling);
77603b705cfSriastradh
77703b705cfSriastradh#endif /* KGEM_H */
778