1d722e3fbSopenharmony_ci/**************************************************************************
2d722e3fbSopenharmony_ci *
3d722e3fbSopenharmony_ci * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
4d722e3fbSopenharmony_ci * All Rights Reserved.
5d722e3fbSopenharmony_ci *
6d722e3fbSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7d722e3fbSopenharmony_ci * copy of this software and associated documentation files (the
8d722e3fbSopenharmony_ci * "Software"), to deal in the Software without restriction, including
9d722e3fbSopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10d722e3fbSopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11d722e3fbSopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12d722e3fbSopenharmony_ci * the following conditions:
13d722e3fbSopenharmony_ci *
14d722e3fbSopenharmony_ci * The above copyright notice and this permission notice (including the
15d722e3fbSopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16d722e3fbSopenharmony_ci * of the Software.
17d722e3fbSopenharmony_ci *
18d722e3fbSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19d722e3fbSopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20d722e3fbSopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21d722e3fbSopenharmony_ci * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22d722e3fbSopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23d722e3fbSopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24d722e3fbSopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25d722e3fbSopenharmony_ci *
26d722e3fbSopenharmony_ci **************************************************************************/
27d722e3fbSopenharmony_ci
28d722e3fbSopenharmony_ci/* Originally a fake version of the buffer manager so that we can
29d722e3fbSopenharmony_ci * prototype the changes in a driver fairly quickly, has been fleshed
30d722e3fbSopenharmony_ci * out to a fully functional interim solution.
31d722e3fbSopenharmony_ci *
32d722e3fbSopenharmony_ci * Basically wraps the old style memory management in the new
33d722e3fbSopenharmony_ci * programming interface, but is more expressive and avoids many of
34d722e3fbSopenharmony_ci * the bugs in the old texture manager.
35d722e3fbSopenharmony_ci */
36d722e3fbSopenharmony_ci
37d722e3fbSopenharmony_ci#include <stdlib.h>
38d722e3fbSopenharmony_ci#include <string.h>
39d722e3fbSopenharmony_ci#include <assert.h>
40d722e3fbSopenharmony_ci#include <errno.h>
41d722e3fbSopenharmony_ci#include <strings.h>
42d722e3fbSopenharmony_ci#include <xf86drm.h>
43d722e3fbSopenharmony_ci#include <pthread.h>
44d722e3fbSopenharmony_ci#include "intel_bufmgr.h"
45d722e3fbSopenharmony_ci#include "intel_bufmgr_priv.h"
46d722e3fbSopenharmony_ci#include "drm.h"
47d722e3fbSopenharmony_ci#include "i915_drm.h"
48d722e3fbSopenharmony_ci#include "mm.h"
49d722e3fbSopenharmony_ci#include "libdrm_macros.h"
50d722e3fbSopenharmony_ci#include "libdrm_lists.h"
51d722e3fbSopenharmony_ci
52d722e3fbSopenharmony_ci#define DBG(...) do {					\
53d722e3fbSopenharmony_ci	if (bufmgr_fake->bufmgr.debug)			\
54d722e3fbSopenharmony_ci		drmMsg(__VA_ARGS__);			\
55d722e3fbSopenharmony_ci} while (0)
56d722e3fbSopenharmony_ci
57d722e3fbSopenharmony_ci/* Internal flags:
58d722e3fbSopenharmony_ci */
59d722e3fbSopenharmony_ci#define BM_NO_BACKING_STORE			0x00000001
60d722e3fbSopenharmony_ci#define BM_NO_FENCE_SUBDATA			0x00000002
61d722e3fbSopenharmony_ci#define BM_PINNED				0x00000004
62d722e3fbSopenharmony_ci
63d722e3fbSopenharmony_ci/* Wrapper around mm.c's mem_block, which understands that you must
64d722e3fbSopenharmony_ci * wait for fences to expire before memory can be freed.  This is
65d722e3fbSopenharmony_ci * specific to our use of memcpy for uploads - an upload that was
66d722e3fbSopenharmony_ci * processed through the command queue wouldn't need to care about
67d722e3fbSopenharmony_ci * fences.
68d722e3fbSopenharmony_ci */
69d722e3fbSopenharmony_ci#define MAX_RELOCS 4096
70d722e3fbSopenharmony_ci
71d722e3fbSopenharmony_cistruct fake_buffer_reloc {
72d722e3fbSopenharmony_ci	/** Buffer object that the relocation points at. */
73d722e3fbSopenharmony_ci	drm_intel_bo *target_buf;
74d722e3fbSopenharmony_ci	/** Offset of the relocation entry within reloc_buf. */
75d722e3fbSopenharmony_ci	uint32_t offset;
76d722e3fbSopenharmony_ci	/**
77d722e3fbSopenharmony_ci	 * Cached value of the offset when we last performed this relocation.
78d722e3fbSopenharmony_ci	 */
79d722e3fbSopenharmony_ci	uint32_t last_target_offset;
80d722e3fbSopenharmony_ci	/** Value added to target_buf's offset to get the relocation entry. */
81d722e3fbSopenharmony_ci	uint32_t delta;
82d722e3fbSopenharmony_ci	/** Cache domains the target buffer is read into. */
83d722e3fbSopenharmony_ci	uint32_t read_domains;
84d722e3fbSopenharmony_ci	/** Cache domain the target buffer will have dirty cachelines in. */
85d722e3fbSopenharmony_ci	uint32_t write_domain;
86d722e3fbSopenharmony_ci};
87d722e3fbSopenharmony_ci
88d722e3fbSopenharmony_cistruct block {
89d722e3fbSopenharmony_ci	struct block *next, *prev;
90d722e3fbSopenharmony_ci	struct mem_block *mem;	/* BM_MEM_AGP */
91d722e3fbSopenharmony_ci
92d722e3fbSopenharmony_ci	/**
93d722e3fbSopenharmony_ci	 * Marks that the block is currently in the aperture and has yet to be
94d722e3fbSopenharmony_ci	 * fenced.
95d722e3fbSopenharmony_ci	 */
96d722e3fbSopenharmony_ci	unsigned on_hardware:1;
97d722e3fbSopenharmony_ci	/**
98d722e3fbSopenharmony_ci	 * Marks that the block is currently fenced (being used by rendering)
99d722e3fbSopenharmony_ci	 * and can't be freed until @fence is passed.
100d722e3fbSopenharmony_ci	 */
101d722e3fbSopenharmony_ci	unsigned fenced:1;
102d722e3fbSopenharmony_ci
103d722e3fbSopenharmony_ci	/** Fence cookie for the block. */
104d722e3fbSopenharmony_ci	unsigned fence;		/* Split to read_fence, write_fence */
105d722e3fbSopenharmony_ci
106d722e3fbSopenharmony_ci	drm_intel_bo *bo;
107d722e3fbSopenharmony_ci	void *virtual;
108d722e3fbSopenharmony_ci};
109d722e3fbSopenharmony_ci
110d722e3fbSopenharmony_citypedef struct _bufmgr_fake {
111d722e3fbSopenharmony_ci	drm_intel_bufmgr bufmgr;
112d722e3fbSopenharmony_ci
113d722e3fbSopenharmony_ci	pthread_mutex_t lock;
114d722e3fbSopenharmony_ci
115d722e3fbSopenharmony_ci	unsigned long low_offset;
116d722e3fbSopenharmony_ci	unsigned long size;
117d722e3fbSopenharmony_ci	void *virtual;
118d722e3fbSopenharmony_ci
119d722e3fbSopenharmony_ci	struct mem_block *heap;
120d722e3fbSopenharmony_ci
121d722e3fbSopenharmony_ci	unsigned buf_nr;	/* for generating ids */
122d722e3fbSopenharmony_ci
123d722e3fbSopenharmony_ci	/**
124d722e3fbSopenharmony_ci	 * List of blocks which are currently in the GART but haven't been
125d722e3fbSopenharmony_ci	 * fenced yet.
126d722e3fbSopenharmony_ci	 */
127d722e3fbSopenharmony_ci	struct block on_hardware;
128d722e3fbSopenharmony_ci	/**
129d722e3fbSopenharmony_ci	 * List of blocks which are in the GART and have an active fence on
130d722e3fbSopenharmony_ci	 * them.
131d722e3fbSopenharmony_ci	 */
132d722e3fbSopenharmony_ci	struct block fenced;
133d722e3fbSopenharmony_ci	/**
134d722e3fbSopenharmony_ci	 * List of blocks which have an expired fence and are ready to be
135d722e3fbSopenharmony_ci	 * evicted.
136d722e3fbSopenharmony_ci	 */
137d722e3fbSopenharmony_ci	struct block lru;
138d722e3fbSopenharmony_ci
139d722e3fbSopenharmony_ci	unsigned int last_fence;
140d722e3fbSopenharmony_ci
141d722e3fbSopenharmony_ci	unsigned fail:1;
142d722e3fbSopenharmony_ci	unsigned need_fence:1;
143d722e3fbSopenharmony_ci	int thrashing;
144d722e3fbSopenharmony_ci
145d722e3fbSopenharmony_ci	/**
146d722e3fbSopenharmony_ci	 * Driver callback to emit a fence, returning the cookie.
147d722e3fbSopenharmony_ci	 *
148d722e3fbSopenharmony_ci	 * This allows the driver to hook in a replacement for the DRM usage in
149d722e3fbSopenharmony_ci	 * bufmgr_fake.
150d722e3fbSopenharmony_ci	 *
151d722e3fbSopenharmony_ci	 * Currently, this also requires that a write flush be emitted before
152d722e3fbSopenharmony_ci	 * emitting the fence, but this should change.
153d722e3fbSopenharmony_ci	 */
154d722e3fbSopenharmony_ci	unsigned int (*fence_emit) (void *private);
155d722e3fbSopenharmony_ci	/** Driver callback to wait for a fence cookie to have passed. */
156d722e3fbSopenharmony_ci	void (*fence_wait) (unsigned int fence, void *private);
157d722e3fbSopenharmony_ci	void *fence_priv;
158d722e3fbSopenharmony_ci
159d722e3fbSopenharmony_ci	/**
160d722e3fbSopenharmony_ci	 * Driver callback to execute a buffer.
161d722e3fbSopenharmony_ci	 *
162d722e3fbSopenharmony_ci	 * This allows the driver to hook in a replacement for the DRM usage in
163d722e3fbSopenharmony_ci	 * bufmgr_fake.
164d722e3fbSopenharmony_ci	 */
165d722e3fbSopenharmony_ci	int (*exec) (drm_intel_bo *bo, unsigned int used, void *priv);
166d722e3fbSopenharmony_ci	void *exec_priv;
167d722e3fbSopenharmony_ci
168d722e3fbSopenharmony_ci	/** Driver-supplied argument to driver callbacks */
169d722e3fbSopenharmony_ci	void *driver_priv;
170d722e3fbSopenharmony_ci	/**
171d722e3fbSopenharmony_ci	 * Pointer to kernel-updated sarea data for the last completed user irq
172d722e3fbSopenharmony_ci	 */
173d722e3fbSopenharmony_ci	volatile int *last_dispatch;
174d722e3fbSopenharmony_ci
175d722e3fbSopenharmony_ci	int fd;
176d722e3fbSopenharmony_ci
177d722e3fbSopenharmony_ci	int debug;
178d722e3fbSopenharmony_ci
179d722e3fbSopenharmony_ci	int performed_rendering;
180d722e3fbSopenharmony_ci} drm_intel_bufmgr_fake;
181d722e3fbSopenharmony_ci
182d722e3fbSopenharmony_citypedef struct _drm_intel_bo_fake {
183d722e3fbSopenharmony_ci	drm_intel_bo bo;
184d722e3fbSopenharmony_ci
185d722e3fbSopenharmony_ci	unsigned id;		/* debug only */
186d722e3fbSopenharmony_ci	const char *name;
187d722e3fbSopenharmony_ci
188d722e3fbSopenharmony_ci	unsigned dirty:1;
189d722e3fbSopenharmony_ci	/**
190d722e3fbSopenharmony_ci	 * has the card written to this buffer - we make need to copy it back
191d722e3fbSopenharmony_ci	 */
192d722e3fbSopenharmony_ci	unsigned card_dirty:1;
193d722e3fbSopenharmony_ci	unsigned int refcount;
194d722e3fbSopenharmony_ci	/* Flags may consist of any of the DRM_BO flags, plus
195d722e3fbSopenharmony_ci	 * DRM_BO_NO_BACKING_STORE and BM_NO_FENCE_SUBDATA, which are the
196d722e3fbSopenharmony_ci	 * first two driver private flags.
197d722e3fbSopenharmony_ci	 */
198d722e3fbSopenharmony_ci	uint64_t flags;
199d722e3fbSopenharmony_ci	/** Cache domains the target buffer is read into. */
200d722e3fbSopenharmony_ci	uint32_t read_domains;
201d722e3fbSopenharmony_ci	/** Cache domain the target buffer will have dirty cachelines in. */
202d722e3fbSopenharmony_ci	uint32_t write_domain;
203d722e3fbSopenharmony_ci
204d722e3fbSopenharmony_ci	unsigned int alignment;
205d722e3fbSopenharmony_ci	int is_static, validated;
206d722e3fbSopenharmony_ci	unsigned int map_count;
207d722e3fbSopenharmony_ci
208d722e3fbSopenharmony_ci	/** relocation list */
209d722e3fbSopenharmony_ci	struct fake_buffer_reloc *relocs;
210d722e3fbSopenharmony_ci	int nr_relocs;
211d722e3fbSopenharmony_ci	/**
212d722e3fbSopenharmony_ci	 * Total size of the target_bos of this buffer.
213d722e3fbSopenharmony_ci	 *
214d722e3fbSopenharmony_ci	 * Used for estimation in check_aperture.
215d722e3fbSopenharmony_ci	 */
216d722e3fbSopenharmony_ci	unsigned int child_size;
217d722e3fbSopenharmony_ci
218d722e3fbSopenharmony_ci	struct block *block;
219d722e3fbSopenharmony_ci	void *backing_store;
220d722e3fbSopenharmony_ci	void (*invalidate_cb) (drm_intel_bo *bo, void *ptr);
221d722e3fbSopenharmony_ci	void *invalidate_ptr;
222d722e3fbSopenharmony_ci} drm_intel_bo_fake;
223d722e3fbSopenharmony_ci
224d722e3fbSopenharmony_cistatic int clear_fenced(drm_intel_bufmgr_fake *bufmgr_fake,
225d722e3fbSopenharmony_ci			unsigned int fence_cookie);
226d722e3fbSopenharmony_ci
227d722e3fbSopenharmony_ci#define MAXFENCE 0x7fffffff
228d722e3fbSopenharmony_ci
229d722e3fbSopenharmony_cistatic int
230d722e3fbSopenharmony_ciFENCE_LTE(unsigned a, unsigned b)
231d722e3fbSopenharmony_ci{
232d722e3fbSopenharmony_ci	if (a == b)
233d722e3fbSopenharmony_ci		return 1;
234d722e3fbSopenharmony_ci
235d722e3fbSopenharmony_ci	if (a < b && b - a < (1 << 24))
236d722e3fbSopenharmony_ci		return 1;
237d722e3fbSopenharmony_ci
238d722e3fbSopenharmony_ci	if (a > b && MAXFENCE - a + b < (1 << 24))
239d722e3fbSopenharmony_ci		return 1;
240d722e3fbSopenharmony_ci
241d722e3fbSopenharmony_ci	return 0;
242d722e3fbSopenharmony_ci}
243d722e3fbSopenharmony_ci
244d722e3fbSopenharmony_cidrm_public void
245d722e3fbSopenharmony_cidrm_intel_bufmgr_fake_set_fence_callback(drm_intel_bufmgr *bufmgr,
246d722e3fbSopenharmony_ci					 unsigned int (*emit) (void *priv),
247d722e3fbSopenharmony_ci					 void (*wait) (unsigned int fence,
248d722e3fbSopenharmony_ci						       void *priv),
249d722e3fbSopenharmony_ci					 void *priv)
250d722e3fbSopenharmony_ci{
251d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
252d722e3fbSopenharmony_ci
253d722e3fbSopenharmony_ci	bufmgr_fake->fence_emit = emit;
254d722e3fbSopenharmony_ci	bufmgr_fake->fence_wait = wait;
255d722e3fbSopenharmony_ci	bufmgr_fake->fence_priv = priv;
256d722e3fbSopenharmony_ci}
257d722e3fbSopenharmony_ci
258d722e3fbSopenharmony_cistatic unsigned int
259d722e3fbSopenharmony_ci_fence_emit_internal(drm_intel_bufmgr_fake *bufmgr_fake)
260d722e3fbSopenharmony_ci{
261d722e3fbSopenharmony_ci	struct drm_i915_irq_emit ie;
262d722e3fbSopenharmony_ci	int ret, seq = 1;
263d722e3fbSopenharmony_ci
264d722e3fbSopenharmony_ci	if (bufmgr_fake->fence_emit != NULL) {
265d722e3fbSopenharmony_ci		seq = bufmgr_fake->fence_emit(bufmgr_fake->fence_priv);
266d722e3fbSopenharmony_ci		return seq;
267d722e3fbSopenharmony_ci	}
268d722e3fbSopenharmony_ci
269d722e3fbSopenharmony_ci	ie.irq_seq = &seq;
270d722e3fbSopenharmony_ci	ret = drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_IRQ_EMIT,
271d722e3fbSopenharmony_ci				  &ie, sizeof(ie));
272d722e3fbSopenharmony_ci	if (ret) {
273d722e3fbSopenharmony_ci		drmMsg("%s: drm_i915_irq_emit: %d\n", __func__, ret);
274d722e3fbSopenharmony_ci		abort();
275d722e3fbSopenharmony_ci	}
276d722e3fbSopenharmony_ci
277d722e3fbSopenharmony_ci	DBG("emit 0x%08x\n", seq);
278d722e3fbSopenharmony_ci	return seq;
279d722e3fbSopenharmony_ci}
280d722e3fbSopenharmony_ci
281d722e3fbSopenharmony_cistatic void
282d722e3fbSopenharmony_ci_fence_wait_internal(drm_intel_bufmgr_fake *bufmgr_fake, int seq)
283d722e3fbSopenharmony_ci{
284d722e3fbSopenharmony_ci	struct drm_i915_irq_wait iw;
285d722e3fbSopenharmony_ci	int hw_seq, busy_count = 0;
286d722e3fbSopenharmony_ci	int ret;
287d722e3fbSopenharmony_ci	int kernel_lied;
288d722e3fbSopenharmony_ci
289d722e3fbSopenharmony_ci	if (bufmgr_fake->fence_wait != NULL) {
290d722e3fbSopenharmony_ci		bufmgr_fake->fence_wait(seq, bufmgr_fake->fence_priv);
291d722e3fbSopenharmony_ci		clear_fenced(bufmgr_fake, seq);
292d722e3fbSopenharmony_ci		return;
293d722e3fbSopenharmony_ci	}
294d722e3fbSopenharmony_ci
295d722e3fbSopenharmony_ci	iw.irq_seq = seq;
296d722e3fbSopenharmony_ci
297d722e3fbSopenharmony_ci	DBG("wait 0x%08x\n", iw.irq_seq);
298d722e3fbSopenharmony_ci
299d722e3fbSopenharmony_ci	/* The kernel IRQ_WAIT implementation is all sorts of broken.
300d722e3fbSopenharmony_ci	 * 1) It returns 1 to 0x7fffffff instead of using the full 32-bit
301d722e3fbSopenharmony_ci	 *    unsigned range.
302d722e3fbSopenharmony_ci	 * 2) It returns 0 if hw_seq >= seq, not seq - hw_seq < 0 on the 32-bit
303d722e3fbSopenharmony_ci	 *    signed range.
304d722e3fbSopenharmony_ci	 * 3) It waits if seq < hw_seq, not seq - hw_seq > 0 on the 32-bit
305d722e3fbSopenharmony_ci	 *    signed range.
306d722e3fbSopenharmony_ci	 * 4) It returns -EBUSY in 3 seconds even if the hardware is still
307d722e3fbSopenharmony_ci	 *    successfully chewing through buffers.
308d722e3fbSopenharmony_ci	 *
309d722e3fbSopenharmony_ci	 * Assume that in userland we treat sequence numbers as ints, which
310d722e3fbSopenharmony_ci	 * makes some of the comparisons convenient, since the sequence
311d722e3fbSopenharmony_ci	 * numbers are all positive signed integers.
312d722e3fbSopenharmony_ci	 *
313d722e3fbSopenharmony_ci	 * From this we get several cases we need to handle.  Here's a timeline.
314d722e3fbSopenharmony_ci	 * 0x2   0x7                                    0x7ffffff8   0x7ffffffd
315d722e3fbSopenharmony_ci	 *   |    |                                             |    |
316d722e3fbSopenharmony_ci	 * ------------------------------------------------------------
317d722e3fbSopenharmony_ci	 *
318d722e3fbSopenharmony_ci	 * A) Normal wait for hw to catch up
319d722e3fbSopenharmony_ci	 * hw_seq seq
320d722e3fbSopenharmony_ci	 *   |    |
321d722e3fbSopenharmony_ci	 * ------------------------------------------------------------
322d722e3fbSopenharmony_ci	 * seq - hw_seq = 5.  If we call IRQ_WAIT, it will wait for hw to
323d722e3fbSopenharmony_ci	 * catch up.
324d722e3fbSopenharmony_ci	 *
325d722e3fbSopenharmony_ci	 * B) Normal wait for a sequence number that's already passed.
326d722e3fbSopenharmony_ci	 * seq    hw_seq
327d722e3fbSopenharmony_ci	 *   |    |
328d722e3fbSopenharmony_ci	 * ------------------------------------------------------------
329d722e3fbSopenharmony_ci	 * seq - hw_seq = -5.  If we call IRQ_WAIT, it returns 0 quickly.
330d722e3fbSopenharmony_ci	 *
331d722e3fbSopenharmony_ci	 * C) Hardware has already wrapped around ahead of us
332d722e3fbSopenharmony_ci	 * hw_seq                                                    seq
333d722e3fbSopenharmony_ci	 *   |                                                       |
334d722e3fbSopenharmony_ci	 * ------------------------------------------------------------
335d722e3fbSopenharmony_ci	 * seq - hw_seq = 0x80000000 - 5.  If we called IRQ_WAIT, it would wait
336d722e3fbSopenharmony_ci	 * for hw_seq >= seq, which may never occur.  Thus, we want to catch
337d722e3fbSopenharmony_ci	 * this in userland and return 0.
338d722e3fbSopenharmony_ci	 *
339d722e3fbSopenharmony_ci	 * D) We've wrapped around ahead of the hardware.
340d722e3fbSopenharmony_ci	 * seq                                                      hw_seq
341d722e3fbSopenharmony_ci	 *   |                                                       |
342d722e3fbSopenharmony_ci	 * ------------------------------------------------------------
343d722e3fbSopenharmony_ci	 * seq - hw_seq = -(0x80000000 - 5).  If we called IRQ_WAIT, it would
344d722e3fbSopenharmony_ci	 * return 0 quickly because hw_seq >= seq, even though the hardware
345d722e3fbSopenharmony_ci	 * isn't caught up. Thus, we need to catch this early return in
346d722e3fbSopenharmony_ci	 * userland and bother the kernel until the hardware really does
347d722e3fbSopenharmony_ci	 * catch up.
348d722e3fbSopenharmony_ci	 *
349d722e3fbSopenharmony_ci	 * E) Hardware might wrap after we test in userland.
350d722e3fbSopenharmony_ci	 *                                                  hw_seq  seq
351d722e3fbSopenharmony_ci	 *                                                      |    |
352d722e3fbSopenharmony_ci	 * ------------------------------------------------------------
353d722e3fbSopenharmony_ci	 * seq - hw_seq = 5.  If we call IRQ_WAIT, it will likely see seq >=
354d722e3fbSopenharmony_ci	 * hw_seq and wait.  However, suppose hw_seq wraps before we make it
355d722e3fbSopenharmony_ci	 * into the kernel.  The kernel sees hw_seq >= seq and waits for 3
356d722e3fbSopenharmony_ci	 * seconds then returns -EBUSY.  This is case C).  We should catch
357d722e3fbSopenharmony_ci	 * this and then return successfully.
358d722e3fbSopenharmony_ci	 *
359d722e3fbSopenharmony_ci	 * F) Hardware might take a long time on a buffer.
360d722e3fbSopenharmony_ci	 * hw_seq seq
361d722e3fbSopenharmony_ci	 *   |    |
362d722e3fbSopenharmony_ci	 * -------------------------------------------------------------------
363d722e3fbSopenharmony_ci	 * seq - hw_seq = 5.  If we call IRQ_WAIT, if sequence 2 through 5
364d722e3fbSopenharmony_ci	 * take too long, it will return -EBUSY.  Batchbuffers in the
365d722e3fbSopenharmony_ci	 * gltestperf demo were seen to take up to 7 seconds.  We should
366d722e3fbSopenharmony_ci	 * catch early -EBUSY return and keep trying.
367d722e3fbSopenharmony_ci	 */
368d722e3fbSopenharmony_ci
369d722e3fbSopenharmony_ci	do {
370d722e3fbSopenharmony_ci		/* Keep a copy of last_dispatch so that if the wait -EBUSYs
371d722e3fbSopenharmony_ci		 * because the hardware didn't catch up in 3 seconds, we can
372d722e3fbSopenharmony_ci		 * see if it at least made progress and retry.
373d722e3fbSopenharmony_ci		 */
374d722e3fbSopenharmony_ci		hw_seq = *bufmgr_fake->last_dispatch;
375d722e3fbSopenharmony_ci
376d722e3fbSopenharmony_ci		/* Catch case C */
377d722e3fbSopenharmony_ci		if (seq - hw_seq > 0x40000000)
378d722e3fbSopenharmony_ci			return;
379d722e3fbSopenharmony_ci
380d722e3fbSopenharmony_ci		ret = drmCommandWrite(bufmgr_fake->fd, DRM_I915_IRQ_WAIT,
381d722e3fbSopenharmony_ci				      &iw, sizeof(iw));
382d722e3fbSopenharmony_ci		/* Catch case D */
383d722e3fbSopenharmony_ci		kernel_lied = (ret == 0) && (seq - *bufmgr_fake->last_dispatch <
384d722e3fbSopenharmony_ci					     -0x40000000);
385d722e3fbSopenharmony_ci
386d722e3fbSopenharmony_ci		/* Catch case E */
387d722e3fbSopenharmony_ci		if (ret == -EBUSY
388d722e3fbSopenharmony_ci		    && (seq - *bufmgr_fake->last_dispatch > 0x40000000))
389d722e3fbSopenharmony_ci			ret = 0;
390d722e3fbSopenharmony_ci
391d722e3fbSopenharmony_ci		/* Catch case F: Allow up to 15 seconds chewing on one buffer. */
392d722e3fbSopenharmony_ci		if ((ret == -EBUSY) && (hw_seq != *bufmgr_fake->last_dispatch))
393d722e3fbSopenharmony_ci			busy_count = 0;
394d722e3fbSopenharmony_ci		else
395d722e3fbSopenharmony_ci			busy_count++;
396d722e3fbSopenharmony_ci	} while (kernel_lied || ret == -EAGAIN || ret == -EINTR ||
397d722e3fbSopenharmony_ci		 (ret == -EBUSY && busy_count < 5));
398d722e3fbSopenharmony_ci
399d722e3fbSopenharmony_ci	if (ret != 0) {
400d722e3fbSopenharmony_ci		drmMsg("%s:%d: Error waiting for fence: %s.\n", __FILE__,
401d722e3fbSopenharmony_ci		       __LINE__, strerror(-ret));
402d722e3fbSopenharmony_ci		abort();
403d722e3fbSopenharmony_ci	}
404d722e3fbSopenharmony_ci	clear_fenced(bufmgr_fake, seq);
405d722e3fbSopenharmony_ci}
406d722e3fbSopenharmony_ci
407d722e3fbSopenharmony_cistatic int
408d722e3fbSopenharmony_ci_fence_test(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence)
409d722e3fbSopenharmony_ci{
410d722e3fbSopenharmony_ci	/* Slight problem with wrap-around:
411d722e3fbSopenharmony_ci	 */
412d722e3fbSopenharmony_ci	return fence == 0 || FENCE_LTE(fence, bufmgr_fake->last_fence);
413d722e3fbSopenharmony_ci}
414d722e3fbSopenharmony_ci
415d722e3fbSopenharmony_ci/**
416d722e3fbSopenharmony_ci * Allocate a memory manager block for the buffer.
417d722e3fbSopenharmony_ci */
418d722e3fbSopenharmony_cistatic int
419d722e3fbSopenharmony_cialloc_block(drm_intel_bo *bo)
420d722e3fbSopenharmony_ci{
421d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
422d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
423d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
424d722e3fbSopenharmony_ci	struct block *block = (struct block *)calloc(sizeof *block, 1);
425d722e3fbSopenharmony_ci	unsigned int align_log2 = ffs(bo_fake->alignment) - 1;
426d722e3fbSopenharmony_ci	unsigned int sz;
427d722e3fbSopenharmony_ci
428d722e3fbSopenharmony_ci	if (!block)
429d722e3fbSopenharmony_ci		return 1;
430d722e3fbSopenharmony_ci
431d722e3fbSopenharmony_ci	sz = (bo->size + bo_fake->alignment - 1) & ~(bo_fake->alignment - 1);
432d722e3fbSopenharmony_ci
433d722e3fbSopenharmony_ci	block->mem = mmAllocMem(bufmgr_fake->heap, sz, align_log2, 0);
434d722e3fbSopenharmony_ci	if (!block->mem) {
435d722e3fbSopenharmony_ci		free(block);
436d722e3fbSopenharmony_ci		return 0;
437d722e3fbSopenharmony_ci	}
438d722e3fbSopenharmony_ci
439d722e3fbSopenharmony_ci	DRMINITLISTHEAD(block);
440d722e3fbSopenharmony_ci
441d722e3fbSopenharmony_ci	/* Insert at head or at tail??? */
442d722e3fbSopenharmony_ci	DRMLISTADDTAIL(block, &bufmgr_fake->lru);
443d722e3fbSopenharmony_ci
444d722e3fbSopenharmony_ci	block->virtual = (uint8_t *) bufmgr_fake->virtual +
445d722e3fbSopenharmony_ci	    block->mem->ofs - bufmgr_fake->low_offset;
446d722e3fbSopenharmony_ci	block->bo = bo;
447d722e3fbSopenharmony_ci
448d722e3fbSopenharmony_ci	bo_fake->block = block;
449d722e3fbSopenharmony_ci
450d722e3fbSopenharmony_ci	return 1;
451d722e3fbSopenharmony_ci}
452d722e3fbSopenharmony_ci
453d722e3fbSopenharmony_ci/* Release the card storage associated with buf:
454d722e3fbSopenharmony_ci */
455d722e3fbSopenharmony_cistatic void
456d722e3fbSopenharmony_cifree_block(drm_intel_bufmgr_fake *bufmgr_fake, struct block *block,
457d722e3fbSopenharmony_ci	   int skip_dirty_copy)
458d722e3fbSopenharmony_ci{
459d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake;
460d722e3fbSopenharmony_ci	DBG("free block %p %08x %d %d\n", block, block->mem->ofs,
461d722e3fbSopenharmony_ci	    block->on_hardware, block->fenced);
462d722e3fbSopenharmony_ci
463d722e3fbSopenharmony_ci	if (!block)
464d722e3fbSopenharmony_ci		return;
465d722e3fbSopenharmony_ci
466d722e3fbSopenharmony_ci	bo_fake = (drm_intel_bo_fake *) block->bo;
467d722e3fbSopenharmony_ci
468d722e3fbSopenharmony_ci	if (bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE))
469d722e3fbSopenharmony_ci		skip_dirty_copy = 1;
470d722e3fbSopenharmony_ci
471d722e3fbSopenharmony_ci	if (!skip_dirty_copy && (bo_fake->card_dirty == 1)) {
472d722e3fbSopenharmony_ci		memcpy(bo_fake->backing_store, block->virtual, block->bo->size);
473d722e3fbSopenharmony_ci		bo_fake->card_dirty = 0;
474d722e3fbSopenharmony_ci		bo_fake->dirty = 1;
475d722e3fbSopenharmony_ci	}
476d722e3fbSopenharmony_ci
477d722e3fbSopenharmony_ci	if (block->on_hardware) {
478d722e3fbSopenharmony_ci		block->bo = NULL;
479d722e3fbSopenharmony_ci	} else if (block->fenced) {
480d722e3fbSopenharmony_ci		block->bo = NULL;
481d722e3fbSopenharmony_ci	} else {
482d722e3fbSopenharmony_ci		DBG("    - free immediately\n");
483d722e3fbSopenharmony_ci		DRMLISTDEL(block);
484d722e3fbSopenharmony_ci
485d722e3fbSopenharmony_ci		mmFreeMem(block->mem);
486d722e3fbSopenharmony_ci		free(block);
487d722e3fbSopenharmony_ci	}
488d722e3fbSopenharmony_ci}
489d722e3fbSopenharmony_ci
490d722e3fbSopenharmony_cistatic void
491d722e3fbSopenharmony_cialloc_backing_store(drm_intel_bo *bo)
492d722e3fbSopenharmony_ci{
493d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
494d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
495d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
496d722e3fbSopenharmony_ci	assert(!bo_fake->backing_store);
497d722e3fbSopenharmony_ci	assert(!(bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE)));
498d722e3fbSopenharmony_ci
499d722e3fbSopenharmony_ci	bo_fake->backing_store = malloc(bo->size);
500d722e3fbSopenharmony_ci
501d722e3fbSopenharmony_ci	DBG("alloc_backing - buf %d %p %lu\n", bo_fake->id,
502d722e3fbSopenharmony_ci	    bo_fake->backing_store, bo->size);
503d722e3fbSopenharmony_ci	assert(bo_fake->backing_store);
504d722e3fbSopenharmony_ci}
505d722e3fbSopenharmony_ci
506d722e3fbSopenharmony_cistatic void
507d722e3fbSopenharmony_cifree_backing_store(drm_intel_bo *bo)
508d722e3fbSopenharmony_ci{
509d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
510d722e3fbSopenharmony_ci
511d722e3fbSopenharmony_ci	if (bo_fake->backing_store) {
512d722e3fbSopenharmony_ci		assert(!(bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE)));
513d722e3fbSopenharmony_ci		free(bo_fake->backing_store);
514d722e3fbSopenharmony_ci		bo_fake->backing_store = NULL;
515d722e3fbSopenharmony_ci	}
516d722e3fbSopenharmony_ci}
517d722e3fbSopenharmony_ci
518d722e3fbSopenharmony_cistatic void
519d722e3fbSopenharmony_ciset_dirty(drm_intel_bo *bo)
520d722e3fbSopenharmony_ci{
521d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
522d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
523d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
524d722e3fbSopenharmony_ci
525d722e3fbSopenharmony_ci	if (bo_fake->flags & BM_NO_BACKING_STORE
526d722e3fbSopenharmony_ci	    && bo_fake->invalidate_cb != NULL)
527d722e3fbSopenharmony_ci		bo_fake->invalidate_cb(bo, bo_fake->invalidate_ptr);
528d722e3fbSopenharmony_ci
529d722e3fbSopenharmony_ci	assert(!(bo_fake->flags & BM_PINNED));
530d722e3fbSopenharmony_ci
531d722e3fbSopenharmony_ci	DBG("set_dirty - buf %d\n", bo_fake->id);
532d722e3fbSopenharmony_ci	bo_fake->dirty = 1;
533d722e3fbSopenharmony_ci}
534d722e3fbSopenharmony_ci
535d722e3fbSopenharmony_cistatic int
536d722e3fbSopenharmony_cievict_lru(drm_intel_bufmgr_fake *bufmgr_fake, unsigned int max_fence)
537d722e3fbSopenharmony_ci{
538d722e3fbSopenharmony_ci	struct block *block, *tmp;
539d722e3fbSopenharmony_ci
540d722e3fbSopenharmony_ci	DBG("%s\n", __func__);
541d722e3fbSopenharmony_ci
542d722e3fbSopenharmony_ci	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
543d722e3fbSopenharmony_ci		drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
544d722e3fbSopenharmony_ci
545d722e3fbSopenharmony_ci		if (bo_fake != NULL && (bo_fake->flags & BM_NO_FENCE_SUBDATA))
546d722e3fbSopenharmony_ci			continue;
547d722e3fbSopenharmony_ci
548d722e3fbSopenharmony_ci		if (block->fence && max_fence && !FENCE_LTE(block->fence,
549d722e3fbSopenharmony_ci							    max_fence))
550d722e3fbSopenharmony_ci			return 0;
551d722e3fbSopenharmony_ci
552d722e3fbSopenharmony_ci		set_dirty(&bo_fake->bo);
553d722e3fbSopenharmony_ci		bo_fake->block = NULL;
554d722e3fbSopenharmony_ci
555d722e3fbSopenharmony_ci		free_block(bufmgr_fake, block, 0);
556d722e3fbSopenharmony_ci		return 1;
557d722e3fbSopenharmony_ci	}
558d722e3fbSopenharmony_ci
559d722e3fbSopenharmony_ci	return 0;
560d722e3fbSopenharmony_ci}
561d722e3fbSopenharmony_ci
562d722e3fbSopenharmony_cistatic int
563d722e3fbSopenharmony_cievict_mru(drm_intel_bufmgr_fake *bufmgr_fake)
564d722e3fbSopenharmony_ci{
565d722e3fbSopenharmony_ci	struct block *block, *tmp;
566d722e3fbSopenharmony_ci
567d722e3fbSopenharmony_ci	DBG("%s\n", __func__);
568d722e3fbSopenharmony_ci
569d722e3fbSopenharmony_ci	DRMLISTFOREACHSAFEREVERSE(block, tmp, &bufmgr_fake->lru) {
570d722e3fbSopenharmony_ci		drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
571d722e3fbSopenharmony_ci
572d722e3fbSopenharmony_ci		if (bo_fake && (bo_fake->flags & BM_NO_FENCE_SUBDATA))
573d722e3fbSopenharmony_ci			continue;
574d722e3fbSopenharmony_ci
575d722e3fbSopenharmony_ci		set_dirty(&bo_fake->bo);
576d722e3fbSopenharmony_ci		bo_fake->block = NULL;
577d722e3fbSopenharmony_ci
578d722e3fbSopenharmony_ci		free_block(bufmgr_fake, block, 0);
579d722e3fbSopenharmony_ci		return 1;
580d722e3fbSopenharmony_ci	}
581d722e3fbSopenharmony_ci
582d722e3fbSopenharmony_ci	return 0;
583d722e3fbSopenharmony_ci}
584d722e3fbSopenharmony_ci
585d722e3fbSopenharmony_ci/**
586d722e3fbSopenharmony_ci * Removes all objects from the fenced list older than the given fence.
587d722e3fbSopenharmony_ci */
588d722e3fbSopenharmony_cistatic int
589d722e3fbSopenharmony_ciclear_fenced(drm_intel_bufmgr_fake *bufmgr_fake, unsigned int fence_cookie)
590d722e3fbSopenharmony_ci{
591d722e3fbSopenharmony_ci	struct block *block, *tmp;
592d722e3fbSopenharmony_ci	int ret = 0;
593d722e3fbSopenharmony_ci
594d722e3fbSopenharmony_ci	bufmgr_fake->last_fence = fence_cookie;
595d722e3fbSopenharmony_ci	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->fenced) {
596d722e3fbSopenharmony_ci		assert(block->fenced);
597d722e3fbSopenharmony_ci
598d722e3fbSopenharmony_ci		if (_fence_test(bufmgr_fake, block->fence)) {
599d722e3fbSopenharmony_ci
600d722e3fbSopenharmony_ci			block->fenced = 0;
601d722e3fbSopenharmony_ci
602d722e3fbSopenharmony_ci			if (!block->bo) {
603d722e3fbSopenharmony_ci				DBG("delayed free: offset %x sz %x\n",
604d722e3fbSopenharmony_ci				    block->mem->ofs, block->mem->size);
605d722e3fbSopenharmony_ci				DRMLISTDEL(block);
606d722e3fbSopenharmony_ci				mmFreeMem(block->mem);
607d722e3fbSopenharmony_ci				free(block);
608d722e3fbSopenharmony_ci			} else {
609d722e3fbSopenharmony_ci				DBG("return to lru: offset %x sz %x\n",
610d722e3fbSopenharmony_ci				    block->mem->ofs, block->mem->size);
611d722e3fbSopenharmony_ci				DRMLISTDEL(block);
612d722e3fbSopenharmony_ci				DRMLISTADDTAIL(block, &bufmgr_fake->lru);
613d722e3fbSopenharmony_ci			}
614d722e3fbSopenharmony_ci
615d722e3fbSopenharmony_ci			ret = 1;
616d722e3fbSopenharmony_ci		} else {
617d722e3fbSopenharmony_ci			/* Blocks are ordered by fence, so if one fails, all
618d722e3fbSopenharmony_ci			 * from here will fail also:
619d722e3fbSopenharmony_ci			 */
620d722e3fbSopenharmony_ci			DBG("fence not passed: offset %x sz %x %d %d \n",
621d722e3fbSopenharmony_ci			    block->mem->ofs, block->mem->size, block->fence,
622d722e3fbSopenharmony_ci			    bufmgr_fake->last_fence);
623d722e3fbSopenharmony_ci			break;
624d722e3fbSopenharmony_ci		}
625d722e3fbSopenharmony_ci	}
626d722e3fbSopenharmony_ci
627d722e3fbSopenharmony_ci	DBG("%s: %d\n", __func__, ret);
628d722e3fbSopenharmony_ci	return ret;
629d722e3fbSopenharmony_ci}
630d722e3fbSopenharmony_ci
631d722e3fbSopenharmony_cistatic void
632d722e3fbSopenharmony_cifence_blocks(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence)
633d722e3fbSopenharmony_ci{
634d722e3fbSopenharmony_ci	struct block *block, *tmp;
635d722e3fbSopenharmony_ci
636d722e3fbSopenharmony_ci	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) {
637d722e3fbSopenharmony_ci		DBG("Fence block %p (sz 0x%x ofs %x buf %p) with fence %d\n",
638d722e3fbSopenharmony_ci		    block, block->mem->size, block->mem->ofs, block->bo, fence);
639d722e3fbSopenharmony_ci		block->fence = fence;
640d722e3fbSopenharmony_ci
641d722e3fbSopenharmony_ci		block->on_hardware = 0;
642d722e3fbSopenharmony_ci		block->fenced = 1;
643d722e3fbSopenharmony_ci
644d722e3fbSopenharmony_ci		/* Move to tail of pending list here
645d722e3fbSopenharmony_ci		 */
646d722e3fbSopenharmony_ci		DRMLISTDEL(block);
647d722e3fbSopenharmony_ci		DRMLISTADDTAIL(block, &bufmgr_fake->fenced);
648d722e3fbSopenharmony_ci	}
649d722e3fbSopenharmony_ci
650d722e3fbSopenharmony_ci	assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
651d722e3fbSopenharmony_ci}
652d722e3fbSopenharmony_ci
653d722e3fbSopenharmony_cistatic int
654d722e3fbSopenharmony_cievict_and_alloc_block(drm_intel_bo *bo)
655d722e3fbSopenharmony_ci{
656d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
657d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
658d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
659d722e3fbSopenharmony_ci
660d722e3fbSopenharmony_ci	assert(bo_fake->block == NULL);
661d722e3fbSopenharmony_ci
662d722e3fbSopenharmony_ci	/* Search for already free memory:
663d722e3fbSopenharmony_ci	 */
664d722e3fbSopenharmony_ci	if (alloc_block(bo))
665d722e3fbSopenharmony_ci		return 1;
666d722e3fbSopenharmony_ci
667d722e3fbSopenharmony_ci	/* If we're not thrashing, allow lru eviction to dig deeper into
668d722e3fbSopenharmony_ci	 * recently used textures.  We'll probably be thrashing soon:
669d722e3fbSopenharmony_ci	 */
670d722e3fbSopenharmony_ci	if (!bufmgr_fake->thrashing) {
671d722e3fbSopenharmony_ci		while (evict_lru(bufmgr_fake, 0))
672d722e3fbSopenharmony_ci			if (alloc_block(bo))
673d722e3fbSopenharmony_ci				return 1;
674d722e3fbSopenharmony_ci	}
675d722e3fbSopenharmony_ci
676d722e3fbSopenharmony_ci	/* Keep thrashing counter alive?
677d722e3fbSopenharmony_ci	 */
678d722e3fbSopenharmony_ci	if (bufmgr_fake->thrashing)
679d722e3fbSopenharmony_ci		bufmgr_fake->thrashing = 20;
680d722e3fbSopenharmony_ci
681d722e3fbSopenharmony_ci	/* Wait on any already pending fences - here we are waiting for any
682d722e3fbSopenharmony_ci	 * freed memory that has been submitted to hardware and fenced to
683d722e3fbSopenharmony_ci	 * become available:
684d722e3fbSopenharmony_ci	 */
685d722e3fbSopenharmony_ci	while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) {
686d722e3fbSopenharmony_ci		uint32_t fence = bufmgr_fake->fenced.next->fence;
687d722e3fbSopenharmony_ci		_fence_wait_internal(bufmgr_fake, fence);
688d722e3fbSopenharmony_ci
689d722e3fbSopenharmony_ci		if (alloc_block(bo))
690d722e3fbSopenharmony_ci			return 1;
691d722e3fbSopenharmony_ci	}
692d722e3fbSopenharmony_ci
693d722e3fbSopenharmony_ci	if (!DRMLISTEMPTY(&bufmgr_fake->on_hardware)) {
694d722e3fbSopenharmony_ci		while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) {
695d722e3fbSopenharmony_ci			uint32_t fence = bufmgr_fake->fenced.next->fence;
696d722e3fbSopenharmony_ci			_fence_wait_internal(bufmgr_fake, fence);
697d722e3fbSopenharmony_ci		}
698d722e3fbSopenharmony_ci
699d722e3fbSopenharmony_ci		if (!bufmgr_fake->thrashing) {
700d722e3fbSopenharmony_ci			DBG("thrashing\n");
701d722e3fbSopenharmony_ci		}
702d722e3fbSopenharmony_ci		bufmgr_fake->thrashing = 20;
703d722e3fbSopenharmony_ci
704d722e3fbSopenharmony_ci		if (alloc_block(bo))
705d722e3fbSopenharmony_ci			return 1;
706d722e3fbSopenharmony_ci	}
707d722e3fbSopenharmony_ci
708d722e3fbSopenharmony_ci	while (evict_mru(bufmgr_fake))
709d722e3fbSopenharmony_ci		if (alloc_block(bo))
710d722e3fbSopenharmony_ci			return 1;
711d722e3fbSopenharmony_ci
712d722e3fbSopenharmony_ci	DBG("%s 0x%lx bytes failed\n", __func__, bo->size);
713d722e3fbSopenharmony_ci
714d722e3fbSopenharmony_ci	return 0;
715d722e3fbSopenharmony_ci}
716d722e3fbSopenharmony_ci
717d722e3fbSopenharmony_ci/***********************************************************************
718d722e3fbSopenharmony_ci * Public functions
719d722e3fbSopenharmony_ci */
720d722e3fbSopenharmony_ci
721d722e3fbSopenharmony_ci/**
722d722e3fbSopenharmony_ci * Wait for hardware idle by emitting a fence and waiting for it.
723d722e3fbSopenharmony_ci */
724d722e3fbSopenharmony_cistatic void
725d722e3fbSopenharmony_cidrm_intel_bufmgr_fake_wait_idle(drm_intel_bufmgr_fake *bufmgr_fake)
726d722e3fbSopenharmony_ci{
727d722e3fbSopenharmony_ci	unsigned int cookie;
728d722e3fbSopenharmony_ci
729d722e3fbSopenharmony_ci	cookie = _fence_emit_internal(bufmgr_fake);
730d722e3fbSopenharmony_ci	_fence_wait_internal(bufmgr_fake, cookie);
731d722e3fbSopenharmony_ci}
732d722e3fbSopenharmony_ci
733d722e3fbSopenharmony_ci/**
734d722e3fbSopenharmony_ci * Wait for rendering to a buffer to complete.
735d722e3fbSopenharmony_ci *
736d722e3fbSopenharmony_ci * It is assumed that the batchbuffer which performed the rendering included
737d722e3fbSopenharmony_ci * the necessary flushing.
738d722e3fbSopenharmony_ci */
739d722e3fbSopenharmony_cistatic void
740d722e3fbSopenharmony_cidrm_intel_fake_bo_wait_rendering_locked(drm_intel_bo *bo)
741d722e3fbSopenharmony_ci{
742d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
743d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
744d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
745d722e3fbSopenharmony_ci
746d722e3fbSopenharmony_ci	if (bo_fake->block == NULL || !bo_fake->block->fenced)
747d722e3fbSopenharmony_ci		return;
748d722e3fbSopenharmony_ci
749d722e3fbSopenharmony_ci	_fence_wait_internal(bufmgr_fake, bo_fake->block->fence);
750d722e3fbSopenharmony_ci}
751d722e3fbSopenharmony_ci
752d722e3fbSopenharmony_cistatic void
753d722e3fbSopenharmony_cidrm_intel_fake_bo_wait_rendering(drm_intel_bo *bo)
754d722e3fbSopenharmony_ci{
755d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
756d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
757d722e3fbSopenharmony_ci
758d722e3fbSopenharmony_ci	pthread_mutex_lock(&bufmgr_fake->lock);
759d722e3fbSopenharmony_ci	drm_intel_fake_bo_wait_rendering_locked(bo);
760d722e3fbSopenharmony_ci	pthread_mutex_unlock(&bufmgr_fake->lock);
761d722e3fbSopenharmony_ci}
762d722e3fbSopenharmony_ci
763d722e3fbSopenharmony_ci/* Specifically ignore texture memory sharing.
764d722e3fbSopenharmony_ci *  -- just evict everything
765d722e3fbSopenharmony_ci *  -- and wait for idle
766d722e3fbSopenharmony_ci */
767d722e3fbSopenharmony_cidrm_public void
768d722e3fbSopenharmony_cidrm_intel_bufmgr_fake_contended_lock_take(drm_intel_bufmgr *bufmgr)
769d722e3fbSopenharmony_ci{
770d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
771d722e3fbSopenharmony_ci	struct block *block, *tmp;
772d722e3fbSopenharmony_ci
773d722e3fbSopenharmony_ci	pthread_mutex_lock(&bufmgr_fake->lock);
774d722e3fbSopenharmony_ci
775d722e3fbSopenharmony_ci	bufmgr_fake->need_fence = 1;
776d722e3fbSopenharmony_ci	bufmgr_fake->fail = 0;
777d722e3fbSopenharmony_ci
778d722e3fbSopenharmony_ci	/* Wait for hardware idle.  We don't know where acceleration has been
779d722e3fbSopenharmony_ci	 * happening, so we'll need to wait anyway before letting anything get
780d722e3fbSopenharmony_ci	 * put on the card again.
781d722e3fbSopenharmony_ci	 */
782d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
783d722e3fbSopenharmony_ci
784d722e3fbSopenharmony_ci	/* Check that we hadn't released the lock without having fenced the last
785d722e3fbSopenharmony_ci	 * set of buffers.
786d722e3fbSopenharmony_ci	 */
787d722e3fbSopenharmony_ci	assert(DRMLISTEMPTY(&bufmgr_fake->fenced));
788d722e3fbSopenharmony_ci	assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
789d722e3fbSopenharmony_ci
790d722e3fbSopenharmony_ci	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
791d722e3fbSopenharmony_ci		assert(_fence_test(bufmgr_fake, block->fence));
792d722e3fbSopenharmony_ci		set_dirty(block->bo);
793d722e3fbSopenharmony_ci	}
794d722e3fbSopenharmony_ci
795d722e3fbSopenharmony_ci	pthread_mutex_unlock(&bufmgr_fake->lock);
796d722e3fbSopenharmony_ci}
797d722e3fbSopenharmony_ci
798d722e3fbSopenharmony_cistatic drm_intel_bo *
799d722e3fbSopenharmony_cidrm_intel_fake_bo_alloc(drm_intel_bufmgr *bufmgr,
800d722e3fbSopenharmony_ci			const char *name,
801d722e3fbSopenharmony_ci			unsigned long size,
802d722e3fbSopenharmony_ci			unsigned int alignment)
803d722e3fbSopenharmony_ci{
804d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake;
805d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake;
806d722e3fbSopenharmony_ci
807d722e3fbSopenharmony_ci	bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
808d722e3fbSopenharmony_ci
809d722e3fbSopenharmony_ci	assert(size != 0);
810d722e3fbSopenharmony_ci
811d722e3fbSopenharmony_ci	bo_fake = calloc(1, sizeof(*bo_fake));
812d722e3fbSopenharmony_ci	if (!bo_fake)
813d722e3fbSopenharmony_ci		return NULL;
814d722e3fbSopenharmony_ci
815d722e3fbSopenharmony_ci	bo_fake->bo.size = size;
816d722e3fbSopenharmony_ci	bo_fake->bo.offset = -1;
817d722e3fbSopenharmony_ci	bo_fake->bo.virtual = NULL;
818d722e3fbSopenharmony_ci	bo_fake->bo.bufmgr = bufmgr;
819d722e3fbSopenharmony_ci	bo_fake->refcount = 1;
820d722e3fbSopenharmony_ci
821d722e3fbSopenharmony_ci	/* Alignment must be a power of two */
822d722e3fbSopenharmony_ci	assert((alignment & (alignment - 1)) == 0);
823d722e3fbSopenharmony_ci	if (alignment == 0)
824d722e3fbSopenharmony_ci		alignment = 1;
825d722e3fbSopenharmony_ci	bo_fake->alignment = alignment;
826d722e3fbSopenharmony_ci	bo_fake->id = ++bufmgr_fake->buf_nr;
827d722e3fbSopenharmony_ci	bo_fake->name = name;
828d722e3fbSopenharmony_ci	bo_fake->flags = 0;
829d722e3fbSopenharmony_ci	bo_fake->is_static = 0;
830d722e3fbSopenharmony_ci
831d722e3fbSopenharmony_ci	DBG("drm_bo_alloc: (buf %d: %s, %lu kb)\n", bo_fake->id, bo_fake->name,
832d722e3fbSopenharmony_ci	    bo_fake->bo.size / 1024);
833d722e3fbSopenharmony_ci
834d722e3fbSopenharmony_ci	return &bo_fake->bo;
835d722e3fbSopenharmony_ci}
836d722e3fbSopenharmony_ci
837d722e3fbSopenharmony_cistatic drm_intel_bo *
838d722e3fbSopenharmony_cidrm_intel_fake_bo_alloc_tiled(drm_intel_bufmgr * bufmgr,
839d722e3fbSopenharmony_ci			      const char *name,
840d722e3fbSopenharmony_ci			      int x, int y, int cpp,
841d722e3fbSopenharmony_ci			      uint32_t *tiling_mode,
842d722e3fbSopenharmony_ci			      unsigned long *pitch,
843d722e3fbSopenharmony_ci			      unsigned long flags)
844d722e3fbSopenharmony_ci{
845d722e3fbSopenharmony_ci	unsigned long stride, aligned_y;
846d722e3fbSopenharmony_ci
847d722e3fbSopenharmony_ci	/* No runtime tiling support for fake. */
848d722e3fbSopenharmony_ci	*tiling_mode = I915_TILING_NONE;
849d722e3fbSopenharmony_ci
850d722e3fbSopenharmony_ci	/* Align it for being a render target.  Shouldn't need anything else. */
851d722e3fbSopenharmony_ci	stride = x * cpp;
852d722e3fbSopenharmony_ci	stride = ROUND_UP_TO(stride, 64);
853d722e3fbSopenharmony_ci
854d722e3fbSopenharmony_ci	/* 965 subspan loading alignment */
855d722e3fbSopenharmony_ci	aligned_y = ALIGN(y, 2);
856d722e3fbSopenharmony_ci
857d722e3fbSopenharmony_ci	*pitch = stride;
858d722e3fbSopenharmony_ci
859d722e3fbSopenharmony_ci	return drm_intel_fake_bo_alloc(bufmgr, name, stride * aligned_y,
860d722e3fbSopenharmony_ci				       4096);
861d722e3fbSopenharmony_ci}
862d722e3fbSopenharmony_ci
863d722e3fbSopenharmony_cidrm_public drm_intel_bo *
864d722e3fbSopenharmony_cidrm_intel_bo_fake_alloc_static(drm_intel_bufmgr *bufmgr,
865d722e3fbSopenharmony_ci			       const char *name,
866d722e3fbSopenharmony_ci			       unsigned long offset,
867d722e3fbSopenharmony_ci			       unsigned long size, void *virtual)
868d722e3fbSopenharmony_ci{
869d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake;
870d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake;
871d722e3fbSopenharmony_ci
872d722e3fbSopenharmony_ci	bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
873d722e3fbSopenharmony_ci
874d722e3fbSopenharmony_ci	assert(size != 0);
875d722e3fbSopenharmony_ci
876d722e3fbSopenharmony_ci	bo_fake = calloc(1, sizeof(*bo_fake));
877d722e3fbSopenharmony_ci	if (!bo_fake)
878d722e3fbSopenharmony_ci		return NULL;
879d722e3fbSopenharmony_ci
880d722e3fbSopenharmony_ci	bo_fake->bo.size = size;
881d722e3fbSopenharmony_ci	bo_fake->bo.offset = offset;
882d722e3fbSopenharmony_ci	bo_fake->bo.virtual = virtual;
883d722e3fbSopenharmony_ci	bo_fake->bo.bufmgr = bufmgr;
884d722e3fbSopenharmony_ci	bo_fake->refcount = 1;
885d722e3fbSopenharmony_ci	bo_fake->id = ++bufmgr_fake->buf_nr;
886d722e3fbSopenharmony_ci	bo_fake->name = name;
887d722e3fbSopenharmony_ci	bo_fake->flags = BM_PINNED;
888d722e3fbSopenharmony_ci	bo_fake->is_static = 1;
889d722e3fbSopenharmony_ci
890d722e3fbSopenharmony_ci	DBG("drm_bo_alloc_static: (buf %d: %s, %lu kb)\n", bo_fake->id,
891d722e3fbSopenharmony_ci	    bo_fake->name, bo_fake->bo.size / 1024);
892d722e3fbSopenharmony_ci
893d722e3fbSopenharmony_ci	return &bo_fake->bo;
894d722e3fbSopenharmony_ci}
895d722e3fbSopenharmony_ci
896d722e3fbSopenharmony_cistatic void
897d722e3fbSopenharmony_cidrm_intel_fake_bo_reference(drm_intel_bo *bo)
898d722e3fbSopenharmony_ci{
899d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
900d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
901d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
902d722e3fbSopenharmony_ci
903d722e3fbSopenharmony_ci	pthread_mutex_lock(&bufmgr_fake->lock);
904d722e3fbSopenharmony_ci	bo_fake->refcount++;
905d722e3fbSopenharmony_ci	pthread_mutex_unlock(&bufmgr_fake->lock);
906d722e3fbSopenharmony_ci}
907d722e3fbSopenharmony_ci
908d722e3fbSopenharmony_cistatic void
909d722e3fbSopenharmony_cidrm_intel_fake_bo_reference_locked(drm_intel_bo *bo)
910d722e3fbSopenharmony_ci{
911d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
912d722e3fbSopenharmony_ci
913d722e3fbSopenharmony_ci	bo_fake->refcount++;
914d722e3fbSopenharmony_ci}
915d722e3fbSopenharmony_ci
916d722e3fbSopenharmony_cistatic void
917d722e3fbSopenharmony_cidrm_intel_fake_bo_unreference_locked(drm_intel_bo *bo)
918d722e3fbSopenharmony_ci{
919d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
920d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
921d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
922d722e3fbSopenharmony_ci	int i;
923d722e3fbSopenharmony_ci
924d722e3fbSopenharmony_ci	if (--bo_fake->refcount == 0) {
925d722e3fbSopenharmony_ci		assert(bo_fake->map_count == 0);
926d722e3fbSopenharmony_ci		/* No remaining references, so free it */
927d722e3fbSopenharmony_ci		if (bo_fake->block)
928d722e3fbSopenharmony_ci			free_block(bufmgr_fake, bo_fake->block, 1);
929d722e3fbSopenharmony_ci		free_backing_store(bo);
930d722e3fbSopenharmony_ci
931d722e3fbSopenharmony_ci		for (i = 0; i < bo_fake->nr_relocs; i++)
932d722e3fbSopenharmony_ci			drm_intel_fake_bo_unreference_locked(bo_fake->relocs[i].
933d722e3fbSopenharmony_ci							     target_buf);
934d722e3fbSopenharmony_ci
935d722e3fbSopenharmony_ci		DBG("drm_bo_unreference: free buf %d %s\n", bo_fake->id,
936d722e3fbSopenharmony_ci		    bo_fake->name);
937d722e3fbSopenharmony_ci
938d722e3fbSopenharmony_ci		free(bo_fake->relocs);
939d722e3fbSopenharmony_ci		free(bo);
940d722e3fbSopenharmony_ci	}
941d722e3fbSopenharmony_ci}
942d722e3fbSopenharmony_ci
943d722e3fbSopenharmony_cistatic void
944d722e3fbSopenharmony_cidrm_intel_fake_bo_unreference(drm_intel_bo *bo)
945d722e3fbSopenharmony_ci{
946d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
947d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
948d722e3fbSopenharmony_ci
949d722e3fbSopenharmony_ci	pthread_mutex_lock(&bufmgr_fake->lock);
950d722e3fbSopenharmony_ci	drm_intel_fake_bo_unreference_locked(bo);
951d722e3fbSopenharmony_ci	pthread_mutex_unlock(&bufmgr_fake->lock);
952d722e3fbSopenharmony_ci}
953d722e3fbSopenharmony_ci
954d722e3fbSopenharmony_ci/**
955d722e3fbSopenharmony_ci * Set the buffer as not requiring backing store, and instead get the callback
956d722e3fbSopenharmony_ci * invoked whenever it would be set dirty.
957d722e3fbSopenharmony_ci */
958d722e3fbSopenharmony_cidrm_public void
959d722e3fbSopenharmony_cidrm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo,
960d722e3fbSopenharmony_ci					void (*invalidate_cb) (drm_intel_bo *bo,
961d722e3fbSopenharmony_ci							       void *ptr),
962d722e3fbSopenharmony_ci					void *ptr)
963d722e3fbSopenharmony_ci{
964d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
965d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
966d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
967d722e3fbSopenharmony_ci
968d722e3fbSopenharmony_ci	pthread_mutex_lock(&bufmgr_fake->lock);
969d722e3fbSopenharmony_ci
970d722e3fbSopenharmony_ci	if (bo_fake->backing_store)
971d722e3fbSopenharmony_ci		free_backing_store(bo);
972d722e3fbSopenharmony_ci
973d722e3fbSopenharmony_ci	bo_fake->flags |= BM_NO_BACKING_STORE;
974d722e3fbSopenharmony_ci
975d722e3fbSopenharmony_ci	DBG("disable_backing_store set buf %d dirty\n", bo_fake->id);
976d722e3fbSopenharmony_ci	bo_fake->dirty = 1;
977d722e3fbSopenharmony_ci	bo_fake->invalidate_cb = invalidate_cb;
978d722e3fbSopenharmony_ci	bo_fake->invalidate_ptr = ptr;
979d722e3fbSopenharmony_ci
980d722e3fbSopenharmony_ci	/* Note that it is invalid right from the start.  Also note
981d722e3fbSopenharmony_ci	 * invalidate_cb is called with the bufmgr locked, so cannot
982d722e3fbSopenharmony_ci	 * itself make bufmgr calls.
983d722e3fbSopenharmony_ci	 */
984d722e3fbSopenharmony_ci	if (invalidate_cb != NULL)
985d722e3fbSopenharmony_ci		invalidate_cb(bo, ptr);
986d722e3fbSopenharmony_ci
987d722e3fbSopenharmony_ci	pthread_mutex_unlock(&bufmgr_fake->lock);
988d722e3fbSopenharmony_ci}
989d722e3fbSopenharmony_ci
990d722e3fbSopenharmony_ci/**
991d722e3fbSopenharmony_ci * Map a buffer into bo->virtual, allocating either card memory space (If
992d722e3fbSopenharmony_ci * BM_NO_BACKING_STORE or BM_PINNED) or backing store, as necessary.
993d722e3fbSopenharmony_ci */
994d722e3fbSopenharmony_cistatic int
995d722e3fbSopenharmony_ci drm_intel_fake_bo_map_locked(drm_intel_bo *bo, int write_enable)
996d722e3fbSopenharmony_ci{
997d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
998d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
999d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1000d722e3fbSopenharmony_ci
1001d722e3fbSopenharmony_ci	/* Static buffers are always mapped. */
1002d722e3fbSopenharmony_ci	if (bo_fake->is_static) {
1003d722e3fbSopenharmony_ci		if (bo_fake->card_dirty) {
1004d722e3fbSopenharmony_ci			drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
1005d722e3fbSopenharmony_ci			bo_fake->card_dirty = 0;
1006d722e3fbSopenharmony_ci		}
1007d722e3fbSopenharmony_ci		return 0;
1008d722e3fbSopenharmony_ci	}
1009d722e3fbSopenharmony_ci
1010d722e3fbSopenharmony_ci	/* Allow recursive mapping.  Mesa may recursively map buffers with
1011d722e3fbSopenharmony_ci	 * nested display loops, and it is used internally in bufmgr_fake
1012d722e3fbSopenharmony_ci	 * for relocation.
1013d722e3fbSopenharmony_ci	 */
1014d722e3fbSopenharmony_ci	if (bo_fake->map_count++ != 0)
1015d722e3fbSopenharmony_ci		return 0;
1016d722e3fbSopenharmony_ci
1017d722e3fbSopenharmony_ci	{
1018d722e3fbSopenharmony_ci		DBG("drm_bo_map: (buf %d: %s, %lu kb)\n", bo_fake->id,
1019d722e3fbSopenharmony_ci		    bo_fake->name, bo_fake->bo.size / 1024);
1020d722e3fbSopenharmony_ci
1021d722e3fbSopenharmony_ci		if (bo->virtual != NULL) {
1022d722e3fbSopenharmony_ci			drmMsg("%s: already mapped\n", __func__);
1023d722e3fbSopenharmony_ci			abort();
1024d722e3fbSopenharmony_ci		} else if (bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED)) {
1025d722e3fbSopenharmony_ci
1026d722e3fbSopenharmony_ci			if (!bo_fake->block && !evict_and_alloc_block(bo)) {
1027d722e3fbSopenharmony_ci				DBG("%s: alloc failed\n", __func__);
1028d722e3fbSopenharmony_ci				bufmgr_fake->fail = 1;
1029d722e3fbSopenharmony_ci				return 1;
1030d722e3fbSopenharmony_ci			} else {
1031d722e3fbSopenharmony_ci				assert(bo_fake->block);
1032d722e3fbSopenharmony_ci				bo_fake->dirty = 0;
1033d722e3fbSopenharmony_ci
1034d722e3fbSopenharmony_ci				if (!(bo_fake->flags & BM_NO_FENCE_SUBDATA) &&
1035d722e3fbSopenharmony_ci				    bo_fake->block->fenced) {
1036d722e3fbSopenharmony_ci					drm_intel_fake_bo_wait_rendering_locked
1037d722e3fbSopenharmony_ci					    (bo);
1038d722e3fbSopenharmony_ci				}
1039d722e3fbSopenharmony_ci
1040d722e3fbSopenharmony_ci				bo->virtual = bo_fake->block->virtual;
1041d722e3fbSopenharmony_ci			}
1042d722e3fbSopenharmony_ci		} else {
1043d722e3fbSopenharmony_ci			if (write_enable)
1044d722e3fbSopenharmony_ci				set_dirty(bo);
1045d722e3fbSopenharmony_ci
1046d722e3fbSopenharmony_ci			if (bo_fake->backing_store == 0)
1047d722e3fbSopenharmony_ci				alloc_backing_store(bo);
1048d722e3fbSopenharmony_ci
1049d722e3fbSopenharmony_ci			if ((bo_fake->card_dirty == 1) && bo_fake->block) {
1050d722e3fbSopenharmony_ci				if (bo_fake->block->fenced)
1051d722e3fbSopenharmony_ci					drm_intel_fake_bo_wait_rendering_locked
1052d722e3fbSopenharmony_ci					    (bo);
1053d722e3fbSopenharmony_ci
1054d722e3fbSopenharmony_ci				memcpy(bo_fake->backing_store,
1055d722e3fbSopenharmony_ci				       bo_fake->block->virtual,
1056d722e3fbSopenharmony_ci				       bo_fake->block->bo->size);
1057d722e3fbSopenharmony_ci				bo_fake->card_dirty = 0;
1058d722e3fbSopenharmony_ci			}
1059d722e3fbSopenharmony_ci
1060d722e3fbSopenharmony_ci			bo->virtual = bo_fake->backing_store;
1061d722e3fbSopenharmony_ci		}
1062d722e3fbSopenharmony_ci	}
1063d722e3fbSopenharmony_ci
1064d722e3fbSopenharmony_ci	return 0;
1065d722e3fbSopenharmony_ci}
1066d722e3fbSopenharmony_ci
1067d722e3fbSopenharmony_cistatic int
1068d722e3fbSopenharmony_ci drm_intel_fake_bo_map(drm_intel_bo *bo, int write_enable)
1069d722e3fbSopenharmony_ci{
1070d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
1071d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
1072d722e3fbSopenharmony_ci	int ret;
1073d722e3fbSopenharmony_ci
1074d722e3fbSopenharmony_ci	pthread_mutex_lock(&bufmgr_fake->lock);
1075d722e3fbSopenharmony_ci	ret = drm_intel_fake_bo_map_locked(bo, write_enable);
1076d722e3fbSopenharmony_ci	pthread_mutex_unlock(&bufmgr_fake->lock);
1077d722e3fbSopenharmony_ci
1078d722e3fbSopenharmony_ci	return ret;
1079d722e3fbSopenharmony_ci}
1080d722e3fbSopenharmony_ci
1081d722e3fbSopenharmony_cistatic int
1082d722e3fbSopenharmony_ci drm_intel_fake_bo_unmap_locked(drm_intel_bo *bo)
1083d722e3fbSopenharmony_ci{
1084d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
1085d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
1086d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1087d722e3fbSopenharmony_ci
1088d722e3fbSopenharmony_ci	/* Static buffers are always mapped. */
1089d722e3fbSopenharmony_ci	if (bo_fake->is_static)
1090d722e3fbSopenharmony_ci		return 0;
1091d722e3fbSopenharmony_ci
1092d722e3fbSopenharmony_ci	assert(bo_fake->map_count != 0);
1093d722e3fbSopenharmony_ci	if (--bo_fake->map_count != 0)
1094d722e3fbSopenharmony_ci		return 0;
1095d722e3fbSopenharmony_ci
1096d722e3fbSopenharmony_ci	DBG("drm_bo_unmap: (buf %d: %s, %lu kb)\n", bo_fake->id, bo_fake->name,
1097d722e3fbSopenharmony_ci	    bo_fake->bo.size / 1024);
1098d722e3fbSopenharmony_ci
1099d722e3fbSopenharmony_ci	bo->virtual = NULL;
1100d722e3fbSopenharmony_ci
1101d722e3fbSopenharmony_ci	return 0;
1102d722e3fbSopenharmony_ci}
1103d722e3fbSopenharmony_ci
1104d722e3fbSopenharmony_cistatic int drm_intel_fake_bo_unmap(drm_intel_bo *bo)
1105d722e3fbSopenharmony_ci{
1106d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
1107d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
1108d722e3fbSopenharmony_ci	int ret;
1109d722e3fbSopenharmony_ci
1110d722e3fbSopenharmony_ci	pthread_mutex_lock(&bufmgr_fake->lock);
1111d722e3fbSopenharmony_ci	ret = drm_intel_fake_bo_unmap_locked(bo);
1112d722e3fbSopenharmony_ci	pthread_mutex_unlock(&bufmgr_fake->lock);
1113d722e3fbSopenharmony_ci
1114d722e3fbSopenharmony_ci	return ret;
1115d722e3fbSopenharmony_ci}
1116d722e3fbSopenharmony_ci
1117d722e3fbSopenharmony_cistatic int
1118d722e3fbSopenharmony_cidrm_intel_fake_bo_subdata(drm_intel_bo *bo, unsigned long offset,
1119d722e3fbSopenharmony_ci			  unsigned long size, const void *data)
1120d722e3fbSopenharmony_ci{
1121d722e3fbSopenharmony_ci	int ret;
1122d722e3fbSopenharmony_ci
1123d722e3fbSopenharmony_ci	if (size == 0 || data == NULL)
1124d722e3fbSopenharmony_ci		return 0;
1125d722e3fbSopenharmony_ci
1126d722e3fbSopenharmony_ci	ret = drm_intel_bo_map(bo, 1);
1127d722e3fbSopenharmony_ci	if (ret)
1128d722e3fbSopenharmony_ci		return ret;
1129d722e3fbSopenharmony_ci	memcpy((unsigned char *)bo->virtual + offset, data, size);
1130d722e3fbSopenharmony_ci	drm_intel_bo_unmap(bo);
1131d722e3fbSopenharmony_ci	return 0;
1132d722e3fbSopenharmony_ci}
1133d722e3fbSopenharmony_ci
1134d722e3fbSopenharmony_cistatic void
1135d722e3fbSopenharmony_ci drm_intel_fake_kick_all_locked(drm_intel_bufmgr_fake *bufmgr_fake)
1136d722e3fbSopenharmony_ci{
1137d722e3fbSopenharmony_ci	struct block *block, *tmp;
1138d722e3fbSopenharmony_ci
1139d722e3fbSopenharmony_ci	bufmgr_fake->performed_rendering = 0;
1140d722e3fbSopenharmony_ci	/* okay for ever BO that is on the HW kick it off.
1141d722e3fbSopenharmony_ci	   seriously not afraid of the POLICE right now */
1142d722e3fbSopenharmony_ci	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) {
1143d722e3fbSopenharmony_ci		drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
1144d722e3fbSopenharmony_ci
1145d722e3fbSopenharmony_ci		block->on_hardware = 0;
1146d722e3fbSopenharmony_ci		free_block(bufmgr_fake, block, 0);
1147d722e3fbSopenharmony_ci		bo_fake->block = NULL;
1148d722e3fbSopenharmony_ci		bo_fake->validated = 0;
1149d722e3fbSopenharmony_ci		if (!(bo_fake->flags & BM_NO_BACKING_STORE))
1150d722e3fbSopenharmony_ci			bo_fake->dirty = 1;
1151d722e3fbSopenharmony_ci	}
1152d722e3fbSopenharmony_ci
1153d722e3fbSopenharmony_ci}
1154d722e3fbSopenharmony_ci
1155d722e3fbSopenharmony_cistatic int
1156d722e3fbSopenharmony_ci drm_intel_fake_bo_validate(drm_intel_bo *bo)
1157d722e3fbSopenharmony_ci{
1158d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake;
1159d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1160d722e3fbSopenharmony_ci
1161d722e3fbSopenharmony_ci	bufmgr_fake = (drm_intel_bufmgr_fake *) bo->bufmgr;
1162d722e3fbSopenharmony_ci
1163d722e3fbSopenharmony_ci	DBG("drm_bo_validate: (buf %d: %s, %lu kb)\n", bo_fake->id,
1164d722e3fbSopenharmony_ci	    bo_fake->name, bo_fake->bo.size / 1024);
1165d722e3fbSopenharmony_ci
1166d722e3fbSopenharmony_ci	/* Sanity check: Buffers should be unmapped before being validated.
1167d722e3fbSopenharmony_ci	 * This is not so much of a problem for bufmgr_fake, but TTM refuses,
1168d722e3fbSopenharmony_ci	 * and the problem is harder to debug there.
1169d722e3fbSopenharmony_ci	 */
1170d722e3fbSopenharmony_ci	assert(bo_fake->map_count == 0);
1171d722e3fbSopenharmony_ci
1172d722e3fbSopenharmony_ci	if (bo_fake->is_static) {
1173d722e3fbSopenharmony_ci		/* Add it to the needs-fence list */
1174d722e3fbSopenharmony_ci		bufmgr_fake->need_fence = 1;
1175d722e3fbSopenharmony_ci		return 0;
1176d722e3fbSopenharmony_ci	}
1177d722e3fbSopenharmony_ci
1178d722e3fbSopenharmony_ci	/* Allocate the card memory */
1179d722e3fbSopenharmony_ci	if (!bo_fake->block && !evict_and_alloc_block(bo)) {
1180d722e3fbSopenharmony_ci		bufmgr_fake->fail = 1;
1181d722e3fbSopenharmony_ci		DBG("Failed to validate buf %d:%s\n", bo_fake->id,
1182d722e3fbSopenharmony_ci		    bo_fake->name);
1183d722e3fbSopenharmony_ci		return -1;
1184d722e3fbSopenharmony_ci	}
1185d722e3fbSopenharmony_ci
1186d722e3fbSopenharmony_ci	assert(bo_fake->block);
1187d722e3fbSopenharmony_ci	assert(bo_fake->block->bo == &bo_fake->bo);
1188d722e3fbSopenharmony_ci
1189d722e3fbSopenharmony_ci	bo->offset = bo_fake->block->mem->ofs;
1190d722e3fbSopenharmony_ci
1191d722e3fbSopenharmony_ci	/* Upload the buffer contents if necessary */
1192d722e3fbSopenharmony_ci	if (bo_fake->dirty) {
1193d722e3fbSopenharmony_ci		DBG("Upload dirty buf %d:%s, sz %lu offset 0x%x\n", bo_fake->id,
1194d722e3fbSopenharmony_ci		    bo_fake->name, bo->size, bo_fake->block->mem->ofs);
1195d722e3fbSopenharmony_ci
1196d722e3fbSopenharmony_ci		assert(!(bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED)));
1197d722e3fbSopenharmony_ci
1198d722e3fbSopenharmony_ci		/* Actually, should be able to just wait for a fence on the
1199d722e3fbSopenharmony_ci		 * memory, which we would be tracking when we free it. Waiting
1200d722e3fbSopenharmony_ci		 * for idle is a sufficiently large hammer for now.
1201d722e3fbSopenharmony_ci		 */
1202d722e3fbSopenharmony_ci		drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
1203d722e3fbSopenharmony_ci
1204d722e3fbSopenharmony_ci		/* we may never have mapped this BO so it might not have any
1205d722e3fbSopenharmony_ci		 * backing store if this happens it should be rare, but 0 the
1206d722e3fbSopenharmony_ci		 * card memory in any case */
1207d722e3fbSopenharmony_ci		if (bo_fake->backing_store)
1208d722e3fbSopenharmony_ci			memcpy(bo_fake->block->virtual, bo_fake->backing_store,
1209d722e3fbSopenharmony_ci			       bo->size);
1210d722e3fbSopenharmony_ci		else
1211d722e3fbSopenharmony_ci			memset(bo_fake->block->virtual, 0, bo->size);
1212d722e3fbSopenharmony_ci
1213d722e3fbSopenharmony_ci		bo_fake->dirty = 0;
1214d722e3fbSopenharmony_ci	}
1215d722e3fbSopenharmony_ci
1216d722e3fbSopenharmony_ci	bo_fake->block->fenced = 0;
1217d722e3fbSopenharmony_ci	bo_fake->block->on_hardware = 1;
1218d722e3fbSopenharmony_ci	DRMLISTDEL(bo_fake->block);
1219d722e3fbSopenharmony_ci	DRMLISTADDTAIL(bo_fake->block, &bufmgr_fake->on_hardware);
1220d722e3fbSopenharmony_ci
1221d722e3fbSopenharmony_ci	bo_fake->validated = 1;
1222d722e3fbSopenharmony_ci	bufmgr_fake->need_fence = 1;
1223d722e3fbSopenharmony_ci
1224d722e3fbSopenharmony_ci	return 0;
1225d722e3fbSopenharmony_ci}
1226d722e3fbSopenharmony_ci
1227d722e3fbSopenharmony_cistatic void
1228d722e3fbSopenharmony_cidrm_intel_fake_fence_validated(drm_intel_bufmgr *bufmgr)
1229d722e3fbSopenharmony_ci{
1230d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
1231d722e3fbSopenharmony_ci	unsigned int cookie;
1232d722e3fbSopenharmony_ci
1233d722e3fbSopenharmony_ci	cookie = _fence_emit_internal(bufmgr_fake);
1234d722e3fbSopenharmony_ci	fence_blocks(bufmgr_fake, cookie);
1235d722e3fbSopenharmony_ci
1236d722e3fbSopenharmony_ci	DBG("drm_fence_validated: 0x%08x cookie\n", cookie);
1237d722e3fbSopenharmony_ci}
1238d722e3fbSopenharmony_ci
1239d722e3fbSopenharmony_cistatic void
1240d722e3fbSopenharmony_cidrm_intel_fake_destroy(drm_intel_bufmgr *bufmgr)
1241d722e3fbSopenharmony_ci{
1242d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
1243d722e3fbSopenharmony_ci
1244d722e3fbSopenharmony_ci	pthread_mutex_destroy(&bufmgr_fake->lock);
1245d722e3fbSopenharmony_ci	mmDestroy(bufmgr_fake->heap);
1246d722e3fbSopenharmony_ci	free(bufmgr);
1247d722e3fbSopenharmony_ci}
1248d722e3fbSopenharmony_ci
1249d722e3fbSopenharmony_cistatic int
1250d722e3fbSopenharmony_cidrm_intel_fake_emit_reloc(drm_intel_bo *bo, uint32_t offset,
1251d722e3fbSopenharmony_ci			  drm_intel_bo *target_bo, uint32_t target_offset,
1252d722e3fbSopenharmony_ci			  uint32_t read_domains, uint32_t write_domain)
1253d722e3fbSopenharmony_ci{
1254d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
1255d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
1256d722e3fbSopenharmony_ci	struct fake_buffer_reloc *r;
1257d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1258d722e3fbSopenharmony_ci	drm_intel_bo_fake *target_fake = (drm_intel_bo_fake *) target_bo;
1259d722e3fbSopenharmony_ci	int i;
1260d722e3fbSopenharmony_ci
1261d722e3fbSopenharmony_ci	pthread_mutex_lock(&bufmgr_fake->lock);
1262d722e3fbSopenharmony_ci
1263d722e3fbSopenharmony_ci	assert(bo);
1264d722e3fbSopenharmony_ci	assert(target_bo);
1265d722e3fbSopenharmony_ci
1266d722e3fbSopenharmony_ci	if (bo_fake->relocs == NULL) {
1267d722e3fbSopenharmony_ci		bo_fake->relocs =
1268d722e3fbSopenharmony_ci		    malloc(sizeof(struct fake_buffer_reloc) * MAX_RELOCS);
1269d722e3fbSopenharmony_ci	}
1270d722e3fbSopenharmony_ci
1271d722e3fbSopenharmony_ci	r = &bo_fake->relocs[bo_fake->nr_relocs++];
1272d722e3fbSopenharmony_ci
1273d722e3fbSopenharmony_ci	assert(bo_fake->nr_relocs <= MAX_RELOCS);
1274d722e3fbSopenharmony_ci
1275d722e3fbSopenharmony_ci	drm_intel_fake_bo_reference_locked(target_bo);
1276d722e3fbSopenharmony_ci
1277d722e3fbSopenharmony_ci	if (!target_fake->is_static) {
1278d722e3fbSopenharmony_ci		bo_fake->child_size +=
1279d722e3fbSopenharmony_ci		    ALIGN(target_bo->size, target_fake->alignment);
1280d722e3fbSopenharmony_ci		bo_fake->child_size += target_fake->child_size;
1281d722e3fbSopenharmony_ci	}
1282d722e3fbSopenharmony_ci	r->target_buf = target_bo;
1283d722e3fbSopenharmony_ci	r->offset = offset;
1284d722e3fbSopenharmony_ci	r->last_target_offset = target_bo->offset;
1285d722e3fbSopenharmony_ci	r->delta = target_offset;
1286d722e3fbSopenharmony_ci	r->read_domains = read_domains;
1287d722e3fbSopenharmony_ci	r->write_domain = write_domain;
1288d722e3fbSopenharmony_ci
1289d722e3fbSopenharmony_ci	if (bufmgr_fake->debug) {
1290d722e3fbSopenharmony_ci		/* Check that a conflicting relocation hasn't already been
1291d722e3fbSopenharmony_ci		 * emitted.
1292d722e3fbSopenharmony_ci		 */
1293d722e3fbSopenharmony_ci		for (i = 0; i < bo_fake->nr_relocs - 1; i++) {
1294d722e3fbSopenharmony_ci			struct fake_buffer_reloc *r2 = &bo_fake->relocs[i];
1295d722e3fbSopenharmony_ci
1296d722e3fbSopenharmony_ci			assert(r->offset != r2->offset);
1297d722e3fbSopenharmony_ci		}
1298d722e3fbSopenharmony_ci	}
1299d722e3fbSopenharmony_ci
1300d722e3fbSopenharmony_ci	pthread_mutex_unlock(&bufmgr_fake->lock);
1301d722e3fbSopenharmony_ci
1302d722e3fbSopenharmony_ci	return 0;
1303d722e3fbSopenharmony_ci}
1304d722e3fbSopenharmony_ci
1305d722e3fbSopenharmony_ci/**
1306d722e3fbSopenharmony_ci * Incorporates the validation flags associated with each relocation into
1307d722e3fbSopenharmony_ci * the combined validation flags for the buffer on this batchbuffer submission.
1308d722e3fbSopenharmony_ci */
1309d722e3fbSopenharmony_cistatic void
1310d722e3fbSopenharmony_cidrm_intel_fake_calculate_domains(drm_intel_bo *bo)
1311d722e3fbSopenharmony_ci{
1312d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1313d722e3fbSopenharmony_ci	int i;
1314d722e3fbSopenharmony_ci
1315d722e3fbSopenharmony_ci	for (i = 0; i < bo_fake->nr_relocs; i++) {
1316d722e3fbSopenharmony_ci		struct fake_buffer_reloc *r = &bo_fake->relocs[i];
1317d722e3fbSopenharmony_ci		drm_intel_bo_fake *target_fake =
1318d722e3fbSopenharmony_ci		    (drm_intel_bo_fake *) r->target_buf;
1319d722e3fbSopenharmony_ci
1320d722e3fbSopenharmony_ci		/* Do the same for the tree of buffers we depend on */
1321d722e3fbSopenharmony_ci		drm_intel_fake_calculate_domains(r->target_buf);
1322d722e3fbSopenharmony_ci
1323d722e3fbSopenharmony_ci		target_fake->read_domains |= r->read_domains;
1324d722e3fbSopenharmony_ci		target_fake->write_domain |= r->write_domain;
1325d722e3fbSopenharmony_ci	}
1326d722e3fbSopenharmony_ci}
1327d722e3fbSopenharmony_ci
1328d722e3fbSopenharmony_cistatic int
1329d722e3fbSopenharmony_cidrm_intel_fake_reloc_and_validate_buffer(drm_intel_bo *bo)
1330d722e3fbSopenharmony_ci{
1331d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
1332d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
1333d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1334d722e3fbSopenharmony_ci	int i, ret;
1335d722e3fbSopenharmony_ci
1336d722e3fbSopenharmony_ci	assert(bo_fake->map_count == 0);
1337d722e3fbSopenharmony_ci
1338d722e3fbSopenharmony_ci	for (i = 0; i < bo_fake->nr_relocs; i++) {
1339d722e3fbSopenharmony_ci		struct fake_buffer_reloc *r = &bo_fake->relocs[i];
1340d722e3fbSopenharmony_ci		drm_intel_bo_fake *target_fake =
1341d722e3fbSopenharmony_ci		    (drm_intel_bo_fake *) r->target_buf;
1342d722e3fbSopenharmony_ci		uint32_t reloc_data;
1343d722e3fbSopenharmony_ci
1344d722e3fbSopenharmony_ci		/* Validate the target buffer if that hasn't been done. */
1345d722e3fbSopenharmony_ci		if (!target_fake->validated) {
1346d722e3fbSopenharmony_ci			ret =
1347d722e3fbSopenharmony_ci			    drm_intel_fake_reloc_and_validate_buffer(r->target_buf);
1348d722e3fbSopenharmony_ci			if (ret != 0) {
1349d722e3fbSopenharmony_ci				if (bo->virtual != NULL)
1350d722e3fbSopenharmony_ci					drm_intel_fake_bo_unmap_locked(bo);
1351d722e3fbSopenharmony_ci				return ret;
1352d722e3fbSopenharmony_ci			}
1353d722e3fbSopenharmony_ci		}
1354d722e3fbSopenharmony_ci
1355d722e3fbSopenharmony_ci		/* Calculate the value of the relocation entry. */
1356d722e3fbSopenharmony_ci		if (r->target_buf->offset != r->last_target_offset) {
1357d722e3fbSopenharmony_ci			reloc_data = r->target_buf->offset + r->delta;
1358d722e3fbSopenharmony_ci
1359d722e3fbSopenharmony_ci			if (bo->virtual == NULL)
1360d722e3fbSopenharmony_ci				drm_intel_fake_bo_map_locked(bo, 1);
1361d722e3fbSopenharmony_ci
1362d722e3fbSopenharmony_ci			*(uint32_t *) ((uint8_t *) bo->virtual + r->offset) =
1363d722e3fbSopenharmony_ci			    reloc_data;
1364d722e3fbSopenharmony_ci
1365d722e3fbSopenharmony_ci			r->last_target_offset = r->target_buf->offset;
1366d722e3fbSopenharmony_ci		}
1367d722e3fbSopenharmony_ci	}
1368d722e3fbSopenharmony_ci
1369d722e3fbSopenharmony_ci	if (bo->virtual != NULL)
1370d722e3fbSopenharmony_ci		drm_intel_fake_bo_unmap_locked(bo);
1371d722e3fbSopenharmony_ci
1372d722e3fbSopenharmony_ci	if (bo_fake->write_domain != 0) {
1373d722e3fbSopenharmony_ci		if (!(bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED))) {
1374d722e3fbSopenharmony_ci			if (bo_fake->backing_store == 0)
1375d722e3fbSopenharmony_ci				alloc_backing_store(bo);
1376d722e3fbSopenharmony_ci		}
1377d722e3fbSopenharmony_ci		bo_fake->card_dirty = 1;
1378d722e3fbSopenharmony_ci		bufmgr_fake->performed_rendering = 1;
1379d722e3fbSopenharmony_ci	}
1380d722e3fbSopenharmony_ci
1381d722e3fbSopenharmony_ci	return drm_intel_fake_bo_validate(bo);
1382d722e3fbSopenharmony_ci}
1383d722e3fbSopenharmony_ci
1384d722e3fbSopenharmony_cistatic void
1385d722e3fbSopenharmony_cidrm_intel_bo_fake_post_submit(drm_intel_bo *bo)
1386d722e3fbSopenharmony_ci{
1387d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
1388d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
1389d722e3fbSopenharmony_ci	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1390d722e3fbSopenharmony_ci	int i;
1391d722e3fbSopenharmony_ci
1392d722e3fbSopenharmony_ci	for (i = 0; i < bo_fake->nr_relocs; i++) {
1393d722e3fbSopenharmony_ci		struct fake_buffer_reloc *r = &bo_fake->relocs[i];
1394d722e3fbSopenharmony_ci		drm_intel_bo_fake *target_fake =
1395d722e3fbSopenharmony_ci		    (drm_intel_bo_fake *) r->target_buf;
1396d722e3fbSopenharmony_ci
1397d722e3fbSopenharmony_ci		if (target_fake->validated)
1398d722e3fbSopenharmony_ci			drm_intel_bo_fake_post_submit(r->target_buf);
1399d722e3fbSopenharmony_ci
1400d722e3fbSopenharmony_ci		DBG("%s@0x%08x + 0x%08x -> %s@0x%08x + 0x%08x\n",
1401d722e3fbSopenharmony_ci		    bo_fake->name, (uint32_t) bo->offset, r->offset,
1402d722e3fbSopenharmony_ci		    target_fake->name, (uint32_t) r->target_buf->offset,
1403d722e3fbSopenharmony_ci		    r->delta);
1404d722e3fbSopenharmony_ci	}
1405d722e3fbSopenharmony_ci
1406d722e3fbSopenharmony_ci	assert(bo_fake->map_count == 0);
1407d722e3fbSopenharmony_ci	bo_fake->validated = 0;
1408d722e3fbSopenharmony_ci	bo_fake->read_domains = 0;
1409d722e3fbSopenharmony_ci	bo_fake->write_domain = 0;
1410d722e3fbSopenharmony_ci}
1411d722e3fbSopenharmony_ci
1412d722e3fbSopenharmony_cidrm_public void
1413d722e3fbSopenharmony_cidrm_intel_bufmgr_fake_set_exec_callback(drm_intel_bufmgr *bufmgr,
1414d722e3fbSopenharmony_ci					     int (*exec) (drm_intel_bo *bo,
1415d722e3fbSopenharmony_ci							  unsigned int used,
1416d722e3fbSopenharmony_ci							  void *priv),
1417d722e3fbSopenharmony_ci					     void *priv)
1418d722e3fbSopenharmony_ci{
1419d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
1420d722e3fbSopenharmony_ci
1421d722e3fbSopenharmony_ci	bufmgr_fake->exec = exec;
1422d722e3fbSopenharmony_ci	bufmgr_fake->exec_priv = priv;
1423d722e3fbSopenharmony_ci}
1424d722e3fbSopenharmony_ci
1425d722e3fbSopenharmony_cistatic int
1426d722e3fbSopenharmony_cidrm_intel_fake_bo_exec(drm_intel_bo *bo, int used,
1427d722e3fbSopenharmony_ci		       drm_clip_rect_t * cliprects, int num_cliprects, int DR4)
1428d722e3fbSopenharmony_ci{
1429d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
1430d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo->bufmgr;
1431d722e3fbSopenharmony_ci	drm_intel_bo_fake *batch_fake = (drm_intel_bo_fake *) bo;
1432d722e3fbSopenharmony_ci	struct drm_i915_batchbuffer batch;
1433d722e3fbSopenharmony_ci	int ret;
1434d722e3fbSopenharmony_ci	int retry_count = 0;
1435d722e3fbSopenharmony_ci
1436d722e3fbSopenharmony_ci	pthread_mutex_lock(&bufmgr_fake->lock);
1437d722e3fbSopenharmony_ci
1438d722e3fbSopenharmony_ci	bufmgr_fake->performed_rendering = 0;
1439d722e3fbSopenharmony_ci
1440d722e3fbSopenharmony_ci	drm_intel_fake_calculate_domains(bo);
1441d722e3fbSopenharmony_ci
1442d722e3fbSopenharmony_ci	batch_fake->read_domains = I915_GEM_DOMAIN_COMMAND;
1443d722e3fbSopenharmony_ci
1444d722e3fbSopenharmony_ci	/* we've ran out of RAM so blow the whole lot away and retry */
1445d722e3fbSopenharmony_cirestart:
1446d722e3fbSopenharmony_ci	ret = drm_intel_fake_reloc_and_validate_buffer(bo);
1447d722e3fbSopenharmony_ci	if (bufmgr_fake->fail == 1) {
1448d722e3fbSopenharmony_ci		if (retry_count == 0) {
1449d722e3fbSopenharmony_ci			retry_count++;
1450d722e3fbSopenharmony_ci			drm_intel_fake_kick_all_locked(bufmgr_fake);
1451d722e3fbSopenharmony_ci			bufmgr_fake->fail = 0;
1452d722e3fbSopenharmony_ci			goto restart;
1453d722e3fbSopenharmony_ci		} else		/* dump out the memory here */
1454d722e3fbSopenharmony_ci			mmDumpMemInfo(bufmgr_fake->heap);
1455d722e3fbSopenharmony_ci	}
1456d722e3fbSopenharmony_ci
1457d722e3fbSopenharmony_ci	assert(ret == 0);
1458d722e3fbSopenharmony_ci
1459d722e3fbSopenharmony_ci	if (bufmgr_fake->exec != NULL) {
1460d722e3fbSopenharmony_ci		ret = bufmgr_fake->exec(bo, used, bufmgr_fake->exec_priv);
1461d722e3fbSopenharmony_ci		if (ret != 0) {
1462d722e3fbSopenharmony_ci			pthread_mutex_unlock(&bufmgr_fake->lock);
1463d722e3fbSopenharmony_ci			return ret;
1464d722e3fbSopenharmony_ci		}
1465d722e3fbSopenharmony_ci	} else {
1466d722e3fbSopenharmony_ci		batch.start = bo->offset;
1467d722e3fbSopenharmony_ci		batch.used = used;
1468d722e3fbSopenharmony_ci		batch.cliprects = cliprects;
1469d722e3fbSopenharmony_ci		batch.num_cliprects = num_cliprects;
1470d722e3fbSopenharmony_ci		batch.DR1 = 0;
1471d722e3fbSopenharmony_ci		batch.DR4 = DR4;
1472d722e3fbSopenharmony_ci
1473d722e3fbSopenharmony_ci		if (drmCommandWrite
1474d722e3fbSopenharmony_ci		    (bufmgr_fake->fd, DRM_I915_BATCHBUFFER, &batch,
1475d722e3fbSopenharmony_ci		     sizeof(batch))) {
1476d722e3fbSopenharmony_ci			drmMsg("DRM_I915_BATCHBUFFER: %d\n", -errno);
1477d722e3fbSopenharmony_ci			pthread_mutex_unlock(&bufmgr_fake->lock);
1478d722e3fbSopenharmony_ci			return -errno;
1479d722e3fbSopenharmony_ci		}
1480d722e3fbSopenharmony_ci	}
1481d722e3fbSopenharmony_ci
1482d722e3fbSopenharmony_ci	drm_intel_fake_fence_validated(bo->bufmgr);
1483d722e3fbSopenharmony_ci
1484d722e3fbSopenharmony_ci	drm_intel_bo_fake_post_submit(bo);
1485d722e3fbSopenharmony_ci
1486d722e3fbSopenharmony_ci	pthread_mutex_unlock(&bufmgr_fake->lock);
1487d722e3fbSopenharmony_ci
1488d722e3fbSopenharmony_ci	return 0;
1489d722e3fbSopenharmony_ci}
1490d722e3fbSopenharmony_ci
1491d722e3fbSopenharmony_ci/**
1492d722e3fbSopenharmony_ci * Return an error if the list of BOs will exceed the aperture size.
1493d722e3fbSopenharmony_ci *
1494d722e3fbSopenharmony_ci * This is a rough guess and likely to fail, as during the validate sequence we
1495d722e3fbSopenharmony_ci * may place a buffer in an inopportune spot early on and then fail to fit
1496d722e3fbSopenharmony_ci * a set smaller than the aperture.
1497d722e3fbSopenharmony_ci */
1498d722e3fbSopenharmony_cistatic int
1499d722e3fbSopenharmony_cidrm_intel_fake_check_aperture_space(drm_intel_bo ** bo_array, int count)
1500d722e3fbSopenharmony_ci{
1501d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake =
1502d722e3fbSopenharmony_ci	    (drm_intel_bufmgr_fake *) bo_array[0]->bufmgr;
1503d722e3fbSopenharmony_ci	unsigned int sz = 0;
1504d722e3fbSopenharmony_ci	int i;
1505d722e3fbSopenharmony_ci
1506d722e3fbSopenharmony_ci	for (i = 0; i < count; i++) {
1507d722e3fbSopenharmony_ci		drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo_array[i];
1508d722e3fbSopenharmony_ci
1509d722e3fbSopenharmony_ci		if (bo_fake == NULL)
1510d722e3fbSopenharmony_ci			continue;
1511d722e3fbSopenharmony_ci
1512d722e3fbSopenharmony_ci		if (!bo_fake->is_static)
1513d722e3fbSopenharmony_ci			sz += ALIGN(bo_array[i]->size, bo_fake->alignment);
1514d722e3fbSopenharmony_ci		sz += bo_fake->child_size;
1515d722e3fbSopenharmony_ci	}
1516d722e3fbSopenharmony_ci
1517d722e3fbSopenharmony_ci	if (sz > bufmgr_fake->size) {
1518d722e3fbSopenharmony_ci		DBG("check_space: overflowed bufmgr size, %ukb vs %lukb\n",
1519d722e3fbSopenharmony_ci		    sz / 1024, bufmgr_fake->size / 1024);
1520d722e3fbSopenharmony_ci		return -1;
1521d722e3fbSopenharmony_ci	}
1522d722e3fbSopenharmony_ci
1523d722e3fbSopenharmony_ci	DBG("drm_check_space: sz %ukb vs bufgr %lukb\n", sz / 1024,
1524d722e3fbSopenharmony_ci	    bufmgr_fake->size / 1024);
1525d722e3fbSopenharmony_ci	return 0;
1526d722e3fbSopenharmony_ci}
1527d722e3fbSopenharmony_ci
1528d722e3fbSopenharmony_ci/**
1529d722e3fbSopenharmony_ci * Evicts all buffers, waiting for fences to pass and copying contents out
1530d722e3fbSopenharmony_ci * as necessary.
1531d722e3fbSopenharmony_ci *
1532d722e3fbSopenharmony_ci * Used by the X Server on LeaveVT, when the card memory is no longer our
1533d722e3fbSopenharmony_ci * own.
1534d722e3fbSopenharmony_ci */
1535d722e3fbSopenharmony_cidrm_public void
1536d722e3fbSopenharmony_cidrm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr)
1537d722e3fbSopenharmony_ci{
1538d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
1539d722e3fbSopenharmony_ci	struct block *block, *tmp;
1540d722e3fbSopenharmony_ci
1541d722e3fbSopenharmony_ci	pthread_mutex_lock(&bufmgr_fake->lock);
1542d722e3fbSopenharmony_ci
1543d722e3fbSopenharmony_ci	bufmgr_fake->need_fence = 1;
1544d722e3fbSopenharmony_ci	bufmgr_fake->fail = 0;
1545d722e3fbSopenharmony_ci
1546d722e3fbSopenharmony_ci	/* Wait for hardware idle.  We don't know where acceleration has been
1547d722e3fbSopenharmony_ci	 * happening, so we'll need to wait anyway before letting anything get
1548d722e3fbSopenharmony_ci	 * put on the card again.
1549d722e3fbSopenharmony_ci	 */
1550d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
1551d722e3fbSopenharmony_ci
1552d722e3fbSopenharmony_ci	/* Check that we hadn't released the lock without having fenced the last
1553d722e3fbSopenharmony_ci	 * set of buffers.
1554d722e3fbSopenharmony_ci	 */
1555d722e3fbSopenharmony_ci	assert(DRMLISTEMPTY(&bufmgr_fake->fenced));
1556d722e3fbSopenharmony_ci	assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
1557d722e3fbSopenharmony_ci
1558d722e3fbSopenharmony_ci	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
1559d722e3fbSopenharmony_ci		drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
1560d722e3fbSopenharmony_ci		/* Releases the memory, and memcpys dirty contents out if
1561d722e3fbSopenharmony_ci		 * necessary.
1562d722e3fbSopenharmony_ci		 */
1563d722e3fbSopenharmony_ci		free_block(bufmgr_fake, block, 0);
1564d722e3fbSopenharmony_ci		bo_fake->block = NULL;
1565d722e3fbSopenharmony_ci	}
1566d722e3fbSopenharmony_ci
1567d722e3fbSopenharmony_ci	pthread_mutex_unlock(&bufmgr_fake->lock);
1568d722e3fbSopenharmony_ci}
1569d722e3fbSopenharmony_ci
1570d722e3fbSopenharmony_cidrm_public void
1571d722e3fbSopenharmony_cidrm_intel_bufmgr_fake_set_last_dispatch(drm_intel_bufmgr *bufmgr,
1572d722e3fbSopenharmony_ci					volatile unsigned int
1573d722e3fbSopenharmony_ci					*last_dispatch)
1574d722e3fbSopenharmony_ci{
1575d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
1576d722e3fbSopenharmony_ci
1577d722e3fbSopenharmony_ci	bufmgr_fake->last_dispatch = (volatile int *)last_dispatch;
1578d722e3fbSopenharmony_ci}
1579d722e3fbSopenharmony_ci
1580d722e3fbSopenharmony_cidrm_public drm_intel_bufmgr *
1581d722e3fbSopenharmony_cidrm_intel_bufmgr_fake_init(int fd, unsigned long low_offset,
1582d722e3fbSopenharmony_ci			   void *low_virtual, unsigned long size,
1583d722e3fbSopenharmony_ci			   volatile unsigned int *last_dispatch)
1584d722e3fbSopenharmony_ci{
1585d722e3fbSopenharmony_ci	drm_intel_bufmgr_fake *bufmgr_fake;
1586d722e3fbSopenharmony_ci
1587d722e3fbSopenharmony_ci	bufmgr_fake = calloc(1, sizeof(*bufmgr_fake));
1588d722e3fbSopenharmony_ci
1589d722e3fbSopenharmony_ci	if (pthread_mutex_init(&bufmgr_fake->lock, NULL) != 0) {
1590d722e3fbSopenharmony_ci		free(bufmgr_fake);
1591d722e3fbSopenharmony_ci		return NULL;
1592d722e3fbSopenharmony_ci	}
1593d722e3fbSopenharmony_ci
1594d722e3fbSopenharmony_ci	/* Initialize allocator */
1595d722e3fbSopenharmony_ci	DRMINITLISTHEAD(&bufmgr_fake->fenced);
1596d722e3fbSopenharmony_ci	DRMINITLISTHEAD(&bufmgr_fake->on_hardware);
1597d722e3fbSopenharmony_ci	DRMINITLISTHEAD(&bufmgr_fake->lru);
1598d722e3fbSopenharmony_ci
1599d722e3fbSopenharmony_ci	bufmgr_fake->low_offset = low_offset;
1600d722e3fbSopenharmony_ci	bufmgr_fake->virtual = low_virtual;
1601d722e3fbSopenharmony_ci	bufmgr_fake->size = size;
1602d722e3fbSopenharmony_ci	bufmgr_fake->heap = mmInit(low_offset, size);
1603d722e3fbSopenharmony_ci
1604d722e3fbSopenharmony_ci	/* Hook in methods */
1605d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.bo_alloc = drm_intel_fake_bo_alloc;
1606d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.bo_alloc_for_render = drm_intel_fake_bo_alloc;
1607d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.bo_alloc_tiled = drm_intel_fake_bo_alloc_tiled;
1608d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.bo_reference = drm_intel_fake_bo_reference;
1609d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.bo_unreference = drm_intel_fake_bo_unreference;
1610d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.bo_map = drm_intel_fake_bo_map;
1611d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.bo_unmap = drm_intel_fake_bo_unmap;
1612d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.bo_subdata = drm_intel_fake_bo_subdata;
1613d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.bo_wait_rendering =
1614d722e3fbSopenharmony_ci	    drm_intel_fake_bo_wait_rendering;
1615d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.bo_emit_reloc = drm_intel_fake_emit_reloc;
1616d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.destroy = drm_intel_fake_destroy;
1617d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.bo_exec = drm_intel_fake_bo_exec;
1618d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.check_aperture_space =
1619d722e3fbSopenharmony_ci	    drm_intel_fake_check_aperture_space;
1620d722e3fbSopenharmony_ci	bufmgr_fake->bufmgr.debug = 0;
1621d722e3fbSopenharmony_ci
1622d722e3fbSopenharmony_ci	bufmgr_fake->fd = fd;
1623d722e3fbSopenharmony_ci	bufmgr_fake->last_dispatch = (volatile int *)last_dispatch;
1624d722e3fbSopenharmony_ci
1625d722e3fbSopenharmony_ci	return &bufmgr_fake->bufmgr;
1626d722e3fbSopenharmony_ci}
1627