Blame intel/intel_bufmgr_fake.c

Packit Service 103f6b
/**************************************************************************
Packit Service 103f6b
 * 
Packit Service 103f6b
 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
Packit Service 103f6b
 * All Rights Reserved.
Packit Service 103f6b
 * 
Packit Service 103f6b
 * Permission is hereby granted, free of charge, to any person obtaining a
Packit Service 103f6b
 * copy of this software and associated documentation files (the
Packit Service 103f6b
 * "Software"), to deal in the Software without restriction, including
Packit Service 103f6b
 * without limitation the rights to use, copy, modify, merge, publish,
Packit Service 103f6b
 * distribute, sub license, and/or sell copies of the Software, and to
Packit Service 103f6b
 * permit persons to whom the Software is furnished to do so, subject to
Packit Service 103f6b
 * the following conditions:
Packit Service 103f6b
 * 
Packit Service 103f6b
 * The above copyright notice and this permission notice (including the
Packit Service 103f6b
 * next paragraph) shall be included in all copies or substantial portions
Packit Service 103f6b
 * of the Software.
Packit Service 103f6b
 * 
Packit Service 103f6b
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
Packit Service 103f6b
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit Service 103f6b
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
Packit Service 103f6b
 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
Packit Service 103f6b
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
Packit Service 103f6b
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
Packit Service 103f6b
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit Service 103f6b
 * 
Packit Service 103f6b
 **************************************************************************/
Packit Service 103f6b
Packit Service 103f6b
/* Originally a fake version of the buffer manager so that we can
Packit Service 103f6b
 * prototype the changes in a driver fairly quickly, has been fleshed
Packit Service 103f6b
 * out to a fully functional interim solution.
Packit Service 103f6b
 *
Packit Service 103f6b
 * Basically wraps the old style memory management in the new
Packit Service 103f6b
 * programming interface, but is more expressive and avoids many of
Packit Service 103f6b
 * the bugs in the old texture manager.
Packit Service 103f6b
 */
Packit Service 103f6b
Packit Service 103f6b
#include <stdlib.h>
Packit Service 103f6b
#include <string.h>
Packit Service 103f6b
#include <assert.h>
Packit Service 103f6b
#include <errno.h>
Packit Service 103f6b
#include <strings.h>
Packit Service 103f6b
#include <xf86drm.h>
Packit Service 103f6b
#include <pthread.h>
Packit Service 103f6b
#include "intel_bufmgr.h"
Packit Service 103f6b
#include "intel_bufmgr_priv.h"
Packit Service 103f6b
#include "drm.h"
Packit Service 103f6b
#include "i915_drm.h"
Packit Service 103f6b
#include "mm.h"
Packit Service 103f6b
#include "libdrm_macros.h"
Packit Service 103f6b
#include "libdrm_lists.h"
Packit Service 103f6b
Packit Service 103f6b
#define DBG(...) do {					\
Packit Service 103f6b
	if (bufmgr_fake->bufmgr.debug)			\
Packit Service 103f6b
		drmMsg(__VA_ARGS__);			\
Packit Service 103f6b
} while (0)
Packit Service 103f6b
Packit Service 103f6b
/* Internal flags:
Packit Service 103f6b
 */
Packit Service 103f6b
#define BM_NO_BACKING_STORE			0x00000001
Packit Service 103f6b
#define BM_NO_FENCE_SUBDATA			0x00000002
Packit Service 103f6b
#define BM_PINNED				0x00000004
Packit Service 103f6b
Packit Service 103f6b
/* Wrapper around mm.c's mem_block, which understands that you must
Packit Service 103f6b
 * wait for fences to expire before memory can be freed.  This is
Packit Service 103f6b
 * specific to our use of memcpy for uploads - an upload that was
Packit Service 103f6b
 * processed through the command queue wouldn't need to care about
Packit Service 103f6b
 * fences.
Packit Service 103f6b
 */
Packit Service 103f6b
#define MAX_RELOCS 4096
Packit Service 103f6b
Packit Service 103f6b
struct fake_buffer_reloc {
Packit Service 103f6b
	/** Buffer object that the relocation points at. */
Packit Service 103f6b
	drm_intel_bo *target_buf;
Packit Service 103f6b
	/** Offset of the relocation entry within reloc_buf. */
Packit Service 103f6b
	uint32_t offset;
Packit Service 103f6b
	/**
Packit Service 103f6b
	 * Cached value of the offset when we last performed this relocation.
Packit Service 103f6b
	 */
Packit Service 103f6b
	uint32_t last_target_offset;
Packit Service 103f6b
	/** Value added to target_buf's offset to get the relocation entry. */
Packit Service 103f6b
	uint32_t delta;
Packit Service 103f6b
	/** Cache domains the target buffer is read into. */
Packit Service 103f6b
	uint32_t read_domains;
Packit Service 103f6b
	/** Cache domain the target buffer will have dirty cachelines in. */
Packit Service 103f6b
	uint32_t write_domain;
Packit Service 103f6b
};
Packit Service 103f6b
Packit Service 103f6b
struct block {
Packit Service 103f6b
	struct block *next, *prev;
Packit Service 103f6b
	struct mem_block *mem;	/* BM_MEM_AGP */
Packit Service 103f6b
Packit Service 103f6b
	/**
Packit Service 103f6b
	 * Marks that the block is currently in the aperture and has yet to be
Packit Service 103f6b
	 * fenced.
Packit Service 103f6b
	 */
Packit Service 103f6b
	unsigned on_hardware:1;
Packit Service 103f6b
	/**
Packit Service 103f6b
	 * Marks that the block is currently fenced (being used by rendering)
Packit Service 103f6b
	 * and can't be freed until @fence is passed.
Packit Service 103f6b
	 */
Packit Service 103f6b
	unsigned fenced:1;
Packit Service 103f6b
Packit Service 103f6b
	/** Fence cookie for the block. */
Packit Service 103f6b
	unsigned fence;		/* Split to read_fence, write_fence */
Packit Service 103f6b
Packit Service 103f6b
	drm_intel_bo *bo;
Packit Service 103f6b
	void *virtual;
Packit Service 103f6b
};
Packit Service 103f6b
Packit Service 103f6b
typedef struct _bufmgr_fake {
Packit Service 103f6b
	drm_intel_bufmgr bufmgr;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_t lock;
Packit Service 103f6b
Packit Service 103f6b
	unsigned long low_offset;
Packit Service 103f6b
	unsigned long size;
Packit Service 103f6b
	void *virtual;
Packit Service 103f6b
Packit Service 103f6b
	struct mem_block *heap;
Packit Service 103f6b
Packit Service 103f6b
	unsigned buf_nr;	/* for generating ids */
Packit Service 103f6b
Packit Service 103f6b
	/**
Packit Service 103f6b
	 * List of blocks which are currently in the GART but haven't been
Packit Service 103f6b
	 * fenced yet.
Packit Service 103f6b
	 */
Packit Service 103f6b
	struct block on_hardware;
Packit Service 103f6b
	/**
Packit Service 103f6b
	 * List of blocks which are in the GART and have an active fence on
Packit Service 103f6b
	 * them.
Packit Service 103f6b
	 */
Packit Service 103f6b
	struct block fenced;
Packit Service 103f6b
	/**
Packit Service 103f6b
	 * List of blocks which have an expired fence and are ready to be
Packit Service 103f6b
	 * evicted.
Packit Service 103f6b
	 */
Packit Service 103f6b
	struct block lru;
Packit Service 103f6b
Packit Service 103f6b
	unsigned int last_fence;
Packit Service 103f6b
Packit Service 103f6b
	unsigned fail:1;
Packit Service 103f6b
	unsigned need_fence:1;
Packit Service 103f6b
	int thrashing;
Packit Service 103f6b
Packit Service 103f6b
	/**
Packit Service 103f6b
	 * Driver callback to emit a fence, returning the cookie.
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * This allows the driver to hook in a replacement for the DRM usage in
Packit Service 103f6b
	 * bufmgr_fake.
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * Currently, this also requires that a write flush be emitted before
Packit Service 103f6b
	 * emitting the fence, but this should change.
Packit Service 103f6b
	 */
Packit Service 103f6b
	unsigned int (*fence_emit) (void *private);
Packit Service 103f6b
	/** Driver callback to wait for a fence cookie to have passed. */
Packit Service 103f6b
	void (*fence_wait) (unsigned int fence, void *private);
Packit Service 103f6b
	void *fence_priv;
Packit Service 103f6b
Packit Service 103f6b
	/**
Packit Service 103f6b
	 * Driver callback to execute a buffer.
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * This allows the driver to hook in a replacement for the DRM usage in
Packit Service 103f6b
	 * bufmgr_fake.
Packit Service 103f6b
	 */
Packit Service 103f6b
	int (*exec) (drm_intel_bo *bo, unsigned int used, void *priv);
Packit Service 103f6b
	void *exec_priv;
Packit Service 103f6b
Packit Service 103f6b
	/** Driver-supplied argument to driver callbacks */
Packit Service 103f6b
	void *driver_priv;
Packit Service 103f6b
	/**
Packit Service 103f6b
	 * Pointer to kernel-updated sarea data for the last completed user irq
Packit Service 103f6b
	 */
Packit Service 103f6b
	volatile int *last_dispatch;
Packit Service 103f6b
Packit Service 103f6b
	int fd;
Packit Service 103f6b
Packit Service 103f6b
	int debug;
Packit Service 103f6b
Packit Service 103f6b
	int performed_rendering;
Packit Service 103f6b
} drm_intel_bufmgr_fake;
Packit Service 103f6b
Packit Service 103f6b
typedef struct _drm_intel_bo_fake {
Packit Service 103f6b
	drm_intel_bo bo;
Packit Service 103f6b
Packit Service 103f6b
	unsigned id;		/* debug only */
Packit Service 103f6b
	const char *name;
Packit Service 103f6b
Packit Service 103f6b
	unsigned dirty:1;
Packit Service 103f6b
	/**
Packit Service 103f6b
	 * has the card written to this buffer - we make need to copy it back
Packit Service 103f6b
	 */
Packit Service 103f6b
	unsigned card_dirty:1;
Packit Service 103f6b
	unsigned int refcount;
Packit Service 103f6b
	/* Flags may consist of any of the DRM_BO flags, plus
Packit Service 103f6b
	 * DRM_BO_NO_BACKING_STORE and BM_NO_FENCE_SUBDATA, which are the
Packit Service 103f6b
	 * first two driver private flags.
Packit Service 103f6b
	 */
Packit Service 103f6b
	uint64_t flags;
Packit Service 103f6b
	/** Cache domains the target buffer is read into. */
Packit Service 103f6b
	uint32_t read_domains;
Packit Service 103f6b
	/** Cache domain the target buffer will have dirty cachelines in. */
Packit Service 103f6b
	uint32_t write_domain;
Packit Service 103f6b
Packit Service 103f6b
	unsigned int alignment;
Packit Service 103f6b
	int is_static, validated;
Packit Service 103f6b
	unsigned int map_count;
Packit Service 103f6b
Packit Service 103f6b
	/** relocation list */
Packit Service 103f6b
	struct fake_buffer_reloc *relocs;
Packit Service 103f6b
	int nr_relocs;
Packit Service 103f6b
	/**
Packit Service 103f6b
	 * Total size of the target_bos of this buffer.
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * Used for estimation in check_aperture.
Packit Service 103f6b
	 */
Packit Service 103f6b
	unsigned int child_size;
Packit Service 103f6b
Packit Service 103f6b
	struct block *block;
Packit Service 103f6b
	void *backing_store;
Packit Service 103f6b
	void (*invalidate_cb) (drm_intel_bo *bo, void *ptr);
Packit Service 103f6b
	void *invalidate_ptr;
Packit Service 103f6b
} drm_intel_bo_fake;
Packit Service 103f6b
Packit Service 103f6b
static int clear_fenced(drm_intel_bufmgr_fake *bufmgr_fake,
Packit Service 103f6b
			unsigned int fence_cookie);
Packit Service 103f6b
Packit Service 103f6b
#define MAXFENCE 0x7fffffff
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
FENCE_LTE(unsigned a, unsigned b)
Packit Service 103f6b
{
Packit Service 103f6b
	if (a == b)
Packit Service 103f6b
		return 1;
Packit Service 103f6b
Packit Service 103f6b
	if (a < b && b - a < (1 << 24))
Packit Service 103f6b
		return 1;
Packit Service 103f6b
Packit Service 103f6b
	if (a > b && MAXFENCE - a + b < (1 << 24))
Packit Service 103f6b
		return 1;
Packit Service 103f6b
Packit Service 103f6b
	return 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
drm_public void
Packit Service 103f6b
drm_intel_bufmgr_fake_set_fence_callback(drm_intel_bufmgr *bufmgr,
Packit Service 103f6b
					 unsigned int (*emit) (void *priv),
Packit Service 103f6b
					 void (*wait) (unsigned int fence,
Packit Service 103f6b
						       void *priv),
Packit Service 103f6b
					 void *priv)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake->fence_emit = emit;
Packit Service 103f6b
	bufmgr_fake->fence_wait = wait;
Packit Service 103f6b
	bufmgr_fake->fence_priv = priv;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static unsigned int
Packit Service 103f6b
_fence_emit_internal(drm_intel_bufmgr_fake *bufmgr_fake)
Packit Service 103f6b
{
Packit Service 103f6b
	struct drm_i915_irq_emit ie;
Packit Service 103f6b
	int ret, seq = 1;
Packit Service 103f6b
Packit Service 103f6b
	if (bufmgr_fake->fence_emit != NULL) {
Packit Service 103f6b
		seq = bufmgr_fake->fence_emit(bufmgr_fake->fence_priv);
Packit Service 103f6b
		return seq;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	ie.irq_seq = &seq;
Packit Service 103f6b
	ret = drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_IRQ_EMIT,
Packit Service 103f6b
				  &ie, sizeof(ie));
Packit Service 103f6b
	if (ret) {
Packit Service 103f6b
		drmMsg("%s: drm_i915_irq_emit: %d\n", __func__, ret);
Packit Service 103f6b
		abort();
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	DBG("emit 0x%08x\n", seq);
Packit Service 103f6b
	return seq;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
_fence_wait_internal(drm_intel_bufmgr_fake *bufmgr_fake, int seq)
Packit Service 103f6b
{
Packit Service 103f6b
	struct drm_i915_irq_wait iw;
Packit Service 103f6b
	int hw_seq, busy_count = 0;
Packit Service 103f6b
	int ret;
Packit Service 103f6b
	int kernel_lied;
Packit Service 103f6b
Packit Service 103f6b
	if (bufmgr_fake->fence_wait != NULL) {
Packit Service 103f6b
		bufmgr_fake->fence_wait(seq, bufmgr_fake->fence_priv);
Packit Service 103f6b
		clear_fenced(bufmgr_fake, seq);
Packit Service 103f6b
		return;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	iw.irq_seq = seq;
Packit Service 103f6b
Packit Service 103f6b
	DBG("wait 0x%08x\n", iw.irq_seq);
Packit Service 103f6b
Packit Service 103f6b
	/* The kernel IRQ_WAIT implementation is all sorts of broken.
Packit Service 103f6b
	 * 1) It returns 1 to 0x7fffffff instead of using the full 32-bit
Packit Service 103f6b
	 *    unsigned range.
Packit Service 103f6b
	 * 2) It returns 0 if hw_seq >= seq, not seq - hw_seq < 0 on the 32-bit
Packit Service 103f6b
	 *    signed range.
Packit Service 103f6b
	 * 3) It waits if seq < hw_seq, not seq - hw_seq > 0 on the 32-bit
Packit Service 103f6b
	 *    signed range.
Packit Service 103f6b
	 * 4) It returns -EBUSY in 3 seconds even if the hardware is still
Packit Service 103f6b
	 *    successfully chewing through buffers.
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * Assume that in userland we treat sequence numbers as ints, which
Packit Service 103f6b
	 * makes some of the comparisons convenient, since the sequence
Packit Service 103f6b
	 * numbers are all positive signed integers.
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * From this we get several cases we need to handle.  Here's a timeline.
Packit Service 103f6b
	 * 0x2   0x7                                    0x7ffffff8   0x7ffffffd
Packit Service 103f6b
	 *   |    |                                             |    |
Packit Service 103f6b
	 * ------------------------------------------------------------
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * A) Normal wait for hw to catch up
Packit Service 103f6b
	 * hw_seq seq
Packit Service 103f6b
	 *   |    |
Packit Service 103f6b
	 * ------------------------------------------------------------
Packit Service 103f6b
	 * seq - hw_seq = 5.  If we call IRQ_WAIT, it will wait for hw to
Packit Service 103f6b
	 * catch up.
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * B) Normal wait for a sequence number that's already passed.
Packit Service 103f6b
	 * seq    hw_seq
Packit Service 103f6b
	 *   |    |
Packit Service 103f6b
	 * ------------------------------------------------------------
Packit Service 103f6b
	 * seq - hw_seq = -5.  If we call IRQ_WAIT, it returns 0 quickly.
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * C) Hardware has already wrapped around ahead of us
Packit Service 103f6b
	 * hw_seq                                                    seq
Packit Service 103f6b
	 *   |                                                       |
Packit Service 103f6b
	 * ------------------------------------------------------------
Packit Service 103f6b
	 * seq - hw_seq = 0x80000000 - 5.  If we called IRQ_WAIT, it would wait
Packit Service 103f6b
	 * for hw_seq >= seq, which may never occur.  Thus, we want to catch
Packit Service 103f6b
	 * this in userland and return 0.
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * D) We've wrapped around ahead of the hardware.
Packit Service 103f6b
	 * seq                                                      hw_seq
Packit Service 103f6b
	 *   |                                                       |
Packit Service 103f6b
	 * ------------------------------------------------------------
Packit Service 103f6b
	 * seq - hw_seq = -(0x80000000 - 5).  If we called IRQ_WAIT, it would
Packit Service 103f6b
	 * return 0 quickly because hw_seq >= seq, even though the hardware
Packit Service 103f6b
	 * isn't caught up. Thus, we need to catch this early return in
Packit Service 103f6b
	 * userland and bother the kernel until the hardware really does
Packit Service 103f6b
	 * catch up.
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * E) Hardware might wrap after we test in userland.
Packit Service 103f6b
	 *                                                  hw_seq  seq
Packit Service 103f6b
	 *                                                      |    |
Packit Service 103f6b
	 * ------------------------------------------------------------
Packit Service 103f6b
	 * seq - hw_seq = 5.  If we call IRQ_WAIT, it will likely see seq >=
Packit Service 103f6b
	 * hw_seq and wait.  However, suppose hw_seq wraps before we make it
Packit Service 103f6b
	 * into the kernel.  The kernel sees hw_seq >= seq and waits for 3
Packit Service 103f6b
	 * seconds then returns -EBUSY.  This is case C).  We should catch
Packit Service 103f6b
	 * this and then return successfully.
Packit Service 103f6b
	 *
Packit Service 103f6b
	 * F) Hardware might take a long time on a buffer.
Packit Service 103f6b
	 * hw_seq seq
Packit Service 103f6b
	 *   |    |
Packit Service 103f6b
	 * -------------------------------------------------------------------
Packit Service 103f6b
	 * seq - hw_seq = 5.  If we call IRQ_WAIT, if sequence 2 through 5
Packit Service 103f6b
	 * take too long, it will return -EBUSY.  Batchbuffers in the
Packit Service 103f6b
	 * gltestperf demo were seen to take up to 7 seconds.  We should
Packit Service 103f6b
	 * catch early -EBUSY return and keep trying.
Packit Service 103f6b
	 */
Packit Service 103f6b
Packit Service 103f6b
	do {
Packit Service 103f6b
		/* Keep a copy of last_dispatch so that if the wait -EBUSYs
Packit Service 103f6b
		 * because the hardware didn't catch up in 3 seconds, we can
Packit Service 103f6b
		 * see if it at least made progress and retry.
Packit Service 103f6b
		 */
Packit Service 103f6b
		hw_seq = *bufmgr_fake->last_dispatch;
Packit Service 103f6b
Packit Service 103f6b
		/* Catch case C */
Packit Service 103f6b
		if (seq - hw_seq > 0x40000000)
Packit Service 103f6b
			return;
Packit Service 103f6b
Packit Service 103f6b
		ret = drmCommandWrite(bufmgr_fake->fd, DRM_I915_IRQ_WAIT,
Packit Service 103f6b
				      &iw, sizeof(iw));
Packit Service 103f6b
		/* Catch case D */
Packit Service 103f6b
		kernel_lied = (ret == 0) && (seq - *bufmgr_fake->last_dispatch <
Packit Service 103f6b
					     -0x40000000);
Packit Service 103f6b
Packit Service 103f6b
		/* Catch case E */
Packit Service 103f6b
		if (ret == -EBUSY
Packit Service 103f6b
		    && (seq - *bufmgr_fake->last_dispatch > 0x40000000))
Packit Service 103f6b
			ret = 0;
Packit Service 103f6b
Packit Service 103f6b
		/* Catch case F: Allow up to 15 seconds chewing on one buffer. */
Packit Service 103f6b
		if ((ret == -EBUSY) && (hw_seq != *bufmgr_fake->last_dispatch))
Packit Service 103f6b
			busy_count = 0;
Packit Service 103f6b
		else
Packit Service 103f6b
			busy_count++;
Packit Service 103f6b
	} while (kernel_lied || ret == -EAGAIN || ret == -EINTR ||
Packit Service 103f6b
		 (ret == -EBUSY && busy_count < 5));
Packit Service 103f6b
Packit Service 103f6b
	if (ret != 0) {
Packit Service 103f6b
		drmMsg("%s:%d: Error waiting for fence: %s.\n", __FILE__,
Packit Service 103f6b
		       __LINE__, strerror(-ret));
Packit Service 103f6b
		abort();
Packit Service 103f6b
	}
Packit Service 103f6b
	clear_fenced(bufmgr_fake, seq);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
_fence_test(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence)
Packit Service 103f6b
{
Packit Service 103f6b
	/* Slight problem with wrap-around:
Packit Service 103f6b
	 */
Packit Service 103f6b
	return fence == 0 || FENCE_LTE(fence, bufmgr_fake->last_fence);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
/**
Packit Service 103f6b
 * Allocate a memory manager block for the buffer.
Packit Service 103f6b
 */
Packit Service 103f6b
static int
Packit Service 103f6b
alloc_block(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	struct block *block = (struct block *)calloc(sizeof *block, 1);
Packit Service 103f6b
	unsigned int align_log2 = ffs(bo_fake->alignment) - 1;
Packit Service 103f6b
	unsigned int sz;
Packit Service 103f6b
Packit Service 103f6b
	if (!block)
Packit Service 103f6b
		return 1;
Packit Service 103f6b
Packit Service 103f6b
	sz = (bo->size + bo_fake->alignment - 1) & ~(bo_fake->alignment - 1);
Packit Service 103f6b
Packit Service 103f6b
	block->mem = mmAllocMem(bufmgr_fake->heap, sz, align_log2, 0);
Packit Service 103f6b
	if (!block->mem) {
Packit Service 103f6b
		free(block);
Packit Service 103f6b
		return 0;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	DRMINITLISTHEAD(block);
Packit Service 103f6b
Packit Service 103f6b
	/* Insert at head or at tail??? */
Packit Service 103f6b
	DRMLISTADDTAIL(block, &bufmgr_fake->lru);
Packit Service 103f6b
Packit Service 103f6b
	block->virtual = (uint8_t *) bufmgr_fake->virtual +
Packit Service 103f6b
	    block->mem->ofs - bufmgr_fake->low_offset;
Packit Service 103f6b
	block->bo = bo;
Packit Service 103f6b
Packit Service 103f6b
	bo_fake->block = block;
Packit Service 103f6b
Packit Service 103f6b
	return 1;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
/* Release the card storage associated with buf:
Packit Service 103f6b
 */
Packit Service 103f6b
static void
Packit Service 103f6b
free_block(drm_intel_bufmgr_fake *bufmgr_fake, struct block *block,
Packit Service 103f6b
	   int skip_dirty_copy)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake;
Packit Service 103f6b
	DBG("free block %p %08x %d %d\n", block, block->mem->ofs,
Packit Service 103f6b
	    block->on_hardware, block->fenced);
Packit Service 103f6b
Packit Service 103f6b
	if (!block)
Packit Service 103f6b
		return;
Packit Service 103f6b
Packit Service 103f6b
	bo_fake = (drm_intel_bo_fake *) block->bo;
Packit Service 103f6b
Packit Service 103f6b
	if (bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE))
Packit Service 103f6b
		skip_dirty_copy = 1;
Packit Service 103f6b
Packit Service 103f6b
	if (!skip_dirty_copy && (bo_fake->card_dirty == 1)) {
Packit Service 103f6b
		memcpy(bo_fake->backing_store, block->virtual, block->bo->size);
Packit Service 103f6b
		bo_fake->card_dirty = 0;
Packit Service 103f6b
		bo_fake->dirty = 1;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	if (block->on_hardware) {
Packit Service 103f6b
		block->bo = NULL;
Packit Service 103f6b
	} else if (block->fenced) {
Packit Service 103f6b
		block->bo = NULL;
Packit Service 103f6b
	} else {
Packit Service 103f6b
		DBG("    - free immediately\n");
Packit Service 103f6b
		DRMLISTDEL(block);
Packit Service 103f6b
Packit Service 103f6b
		mmFreeMem(block->mem);
Packit Service 103f6b
		free(block);
Packit Service 103f6b
	}
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
alloc_backing_store(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
	assert(!bo_fake->backing_store);
Packit Service 103f6b
	assert(!(bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE)));
Packit Service 103f6b
Packit Service 103f6b
	bo_fake->backing_store = malloc(bo->size);
Packit Service 103f6b
Packit Service 103f6b
	DBG("alloc_backing - buf %d %p %lu\n", bo_fake->id,
Packit Service 103f6b
	    bo_fake->backing_store, bo->size);
Packit Service 103f6b
	assert(bo_fake->backing_store);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
free_backing_store(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
Packit Service 103f6b
	if (bo_fake->backing_store) {
Packit Service 103f6b
		assert(!(bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE)));
Packit Service 103f6b
		free(bo_fake->backing_store);
Packit Service 103f6b
		bo_fake->backing_store = NULL;
Packit Service 103f6b
	}
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
set_dirty(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
Packit Service 103f6b
	if (bo_fake->flags & BM_NO_BACKING_STORE
Packit Service 103f6b
	    && bo_fake->invalidate_cb != NULL)
Packit Service 103f6b
		bo_fake->invalidate_cb(bo, bo_fake->invalidate_ptr);
Packit Service 103f6b
Packit Service 103f6b
	assert(!(bo_fake->flags & BM_PINNED));
Packit Service 103f6b
Packit Service 103f6b
	DBG("set_dirty - buf %d\n", bo_fake->id);
Packit Service 103f6b
	bo_fake->dirty = 1;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
evict_lru(drm_intel_bufmgr_fake *bufmgr_fake, unsigned int max_fence)
Packit Service 103f6b
{
Packit Service 103f6b
	struct block *block, *tmp;
Packit Service 103f6b
Packit Service 103f6b
	DBG("%s\n", __func__);
Packit Service 103f6b
Packit Service 103f6b
	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
Packit Service 103f6b
		drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
Packit Service 103f6b
Packit Service 103f6b
		if (bo_fake != NULL && (bo_fake->flags & BM_NO_FENCE_SUBDATA))
Packit Service 103f6b
			continue;
Packit Service 103f6b
Packit Service 103f6b
		if (block->fence && max_fence && !FENCE_LTE(block->fence,
Packit Service 103f6b
							    max_fence))
Packit Service 103f6b
			return 0;
Packit Service 103f6b
Packit Service 103f6b
		set_dirty(&bo_fake->bo);
Packit Service 103f6b
		bo_fake->block = NULL;
Packit Service 103f6b
Packit Service 103f6b
		free_block(bufmgr_fake, block, 0);
Packit Service 103f6b
		return 1;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	return 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
evict_mru(drm_intel_bufmgr_fake *bufmgr_fake)
Packit Service 103f6b
{
Packit Service 103f6b
	struct block *block, *tmp;
Packit Service 103f6b
Packit Service 103f6b
	DBG("%s\n", __func__);
Packit Service 103f6b
Packit Service 103f6b
	DRMLISTFOREACHSAFEREVERSE(block, tmp, &bufmgr_fake->lru) {
Packit Service 103f6b
		drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
Packit Service 103f6b
Packit Service 103f6b
		if (bo_fake && (bo_fake->flags & BM_NO_FENCE_SUBDATA))
Packit Service 103f6b
			continue;
Packit Service 103f6b
Packit Service 103f6b
		set_dirty(&bo_fake->bo);
Packit Service 103f6b
		bo_fake->block = NULL;
Packit Service 103f6b
Packit Service 103f6b
		free_block(bufmgr_fake, block, 0);
Packit Service 103f6b
		return 1;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	return 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
/**
Packit Service 103f6b
 * Removes all objects from the fenced list older than the given fence.
Packit Service 103f6b
 */
Packit Service 103f6b
static int
Packit Service 103f6b
clear_fenced(drm_intel_bufmgr_fake *bufmgr_fake, unsigned int fence_cookie)
Packit Service 103f6b
{
Packit Service 103f6b
	struct block *block, *tmp;
Packit Service 103f6b
	int ret = 0;
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake->last_fence = fence_cookie;
Packit Service 103f6b
	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->fenced) {
Packit Service 103f6b
		assert(block->fenced);
Packit Service 103f6b
Packit Service 103f6b
		if (_fence_test(bufmgr_fake, block->fence)) {
Packit Service 103f6b
Packit Service 103f6b
			block->fenced = 0;
Packit Service 103f6b
Packit Service 103f6b
			if (!block->bo) {
Packit Service 103f6b
				DBG("delayed free: offset %x sz %x\n",
Packit Service 103f6b
				    block->mem->ofs, block->mem->size);
Packit Service 103f6b
				DRMLISTDEL(block);
Packit Service 103f6b
				mmFreeMem(block->mem);
Packit Service 103f6b
				free(block);
Packit Service 103f6b
			} else {
Packit Service 103f6b
				DBG("return to lru: offset %x sz %x\n",
Packit Service 103f6b
				    block->mem->ofs, block->mem->size);
Packit Service 103f6b
				DRMLISTDEL(block);
Packit Service 103f6b
				DRMLISTADDTAIL(block, &bufmgr_fake->lru);
Packit Service 103f6b
			}
Packit Service 103f6b
Packit Service 103f6b
			ret = 1;
Packit Service 103f6b
		} else {
Packit Service 103f6b
			/* Blocks are ordered by fence, so if one fails, all
Packit Service 103f6b
			 * from here will fail also:
Packit Service 103f6b
			 */
Packit Service 103f6b
			DBG("fence not passed: offset %x sz %x %d %d \n",
Packit Service 103f6b
			    block->mem->ofs, block->mem->size, block->fence,
Packit Service 103f6b
			    bufmgr_fake->last_fence);
Packit Service 103f6b
			break;
Packit Service 103f6b
		}
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	DBG("%s: %d\n", __func__, ret);
Packit Service 103f6b
	return ret;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
fence_blocks(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence)
Packit Service 103f6b
{
Packit Service 103f6b
	struct block *block, *tmp;
Packit Service 103f6b
Packit Service 103f6b
	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) {
Packit Service 103f6b
		DBG("Fence block %p (sz 0x%x ofs %x buf %p) with fence %d\n",
Packit Service 103f6b
		    block, block->mem->size, block->mem->ofs, block->bo, fence);
Packit Service 103f6b
		block->fence = fence;
Packit Service 103f6b
Packit Service 103f6b
		block->on_hardware = 0;
Packit Service 103f6b
		block->fenced = 1;
Packit Service 103f6b
Packit Service 103f6b
		/* Move to tail of pending list here
Packit Service 103f6b
		 */
Packit Service 103f6b
		DRMLISTDEL(block);
Packit Service 103f6b
		DRMLISTADDTAIL(block, &bufmgr_fake->fenced);
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
evict_and_alloc_block(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
Packit Service 103f6b
	assert(bo_fake->block == NULL);
Packit Service 103f6b
Packit Service 103f6b
	/* Search for already free memory:
Packit Service 103f6b
	 */
Packit Service 103f6b
	if (alloc_block(bo))
Packit Service 103f6b
		return 1;
Packit Service 103f6b
Packit Service 103f6b
	/* If we're not thrashing, allow lru eviction to dig deeper into
Packit Service 103f6b
	 * recently used textures.  We'll probably be thrashing soon:
Packit Service 103f6b
	 */
Packit Service 103f6b
	if (!bufmgr_fake->thrashing) {
Packit Service 103f6b
		while (evict_lru(bufmgr_fake, 0))
Packit Service 103f6b
			if (alloc_block(bo))
Packit Service 103f6b
				return 1;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	/* Keep thrashing counter alive?
Packit Service 103f6b
	 */
Packit Service 103f6b
	if (bufmgr_fake->thrashing)
Packit Service 103f6b
		bufmgr_fake->thrashing = 20;
Packit Service 103f6b
Packit Service 103f6b
	/* Wait on any already pending fences - here we are waiting for any
Packit Service 103f6b
	 * freed memory that has been submitted to hardware and fenced to
Packit Service 103f6b
	 * become available:
Packit Service 103f6b
	 */
Packit Service 103f6b
	while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) {
Packit Service 103f6b
		uint32_t fence = bufmgr_fake->fenced.next->fence;
Packit Service 103f6b
		_fence_wait_internal(bufmgr_fake, fence);
Packit Service 103f6b
Packit Service 103f6b
		if (alloc_block(bo))
Packit Service 103f6b
			return 1;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	if (!DRMLISTEMPTY(&bufmgr_fake->on_hardware)) {
Packit Service 103f6b
		while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) {
Packit Service 103f6b
			uint32_t fence = bufmgr_fake->fenced.next->fence;
Packit Service 103f6b
			_fence_wait_internal(bufmgr_fake, fence);
Packit Service 103f6b
		}
Packit Service 103f6b
Packit Service 103f6b
		if (!bufmgr_fake->thrashing) {
Packit Service 103f6b
			DBG("thrashing\n");
Packit Service 103f6b
		}
Packit Service 103f6b
		bufmgr_fake->thrashing = 20;
Packit Service 103f6b
Packit Service 103f6b
		if (alloc_block(bo))
Packit Service 103f6b
			return 1;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	while (evict_mru(bufmgr_fake))
Packit Service 103f6b
		if (alloc_block(bo))
Packit Service 103f6b
			return 1;
Packit Service 103f6b
Packit Service 103f6b
	DBG("%s 0x%lx bytes failed\n", __func__, bo->size);
Packit Service 103f6b
Packit Service 103f6b
	return 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
/***********************************************************************
Packit Service 103f6b
 * Public functions
Packit Service 103f6b
 */
Packit Service 103f6b
Packit Service 103f6b
/**
Packit Service 103f6b
 * Wait for hardware idle by emitting a fence and waiting for it.
Packit Service 103f6b
 */
Packit Service 103f6b
static void
Packit Service 103f6b
drm_intel_bufmgr_fake_wait_idle(drm_intel_bufmgr_fake *bufmgr_fake)
Packit Service 103f6b
{
Packit Service 103f6b
	unsigned int cookie;
Packit Service 103f6b
Packit Service 103f6b
	cookie = _fence_emit_internal(bufmgr_fake);
Packit Service 103f6b
	_fence_wait_internal(bufmgr_fake, cookie);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
/**
Packit Service 103f6b
 * Wait for rendering to a buffer to complete.
Packit Service 103f6b
 *
Packit Service 103f6b
 * It is assumed that the batchbuffer which performed the rendering included
Packit Service 103f6b
 * the necessary flushing.
Packit Service 103f6b
 */
Packit Service 103f6b
static void
Packit Service 103f6b
drm_intel_fake_bo_wait_rendering_locked(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
Packit Service 103f6b
	if (bo_fake->block == NULL || !bo_fake->block->fenced)
Packit Service 103f6b
		return;
Packit Service 103f6b
Packit Service 103f6b
	_fence_wait_internal(bufmgr_fake, bo_fake->block->fence);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
drm_intel_fake_bo_wait_rendering(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_lock(&bufmgr_fake->lock);
Packit Service 103f6b
	drm_intel_fake_bo_wait_rendering_locked(bo);
Packit Service 103f6b
	pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
/* Specifically ignore texture memory sharing.
Packit Service 103f6b
 *  -- just evict everything
Packit Service 103f6b
 *  -- and wait for idle
Packit Service 103f6b
 */
Packit Service 103f6b
drm_public void
Packit Service 103f6b
drm_intel_bufmgr_fake_contended_lock_take(drm_intel_bufmgr *bufmgr)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
Packit Service 103f6b
	struct block *block, *tmp;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_lock(&bufmgr_fake->lock);
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake->need_fence = 1;
Packit Service 103f6b
	bufmgr_fake->fail = 0;
Packit Service 103f6b
Packit Service 103f6b
	/* Wait for hardware idle.  We don't know where acceleration has been
Packit Service 103f6b
	 * happening, so we'll need to wait anyway before letting anything get
Packit Service 103f6b
	 * put on the card again.
Packit Service 103f6b
	 */
Packit Service 103f6b
	drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
Packit Service 103f6b
Packit Service 103f6b
	/* Check that we hadn't released the lock without having fenced the last
Packit Service 103f6b
	 * set of buffers.
Packit Service 103f6b
	 */
Packit Service 103f6b
	assert(DRMLISTEMPTY(&bufmgr_fake->fenced));
Packit Service 103f6b
	assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
Packit Service 103f6b
Packit Service 103f6b
	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
Packit Service 103f6b
		assert(_fence_test(bufmgr_fake, block->fence));
Packit Service 103f6b
		set_dirty(block->bo);
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static drm_intel_bo *
Packit Service 103f6b
drm_intel_fake_bo_alloc(drm_intel_bufmgr *bufmgr,
Packit Service 103f6b
			const char *name,
Packit Service 103f6b
			unsigned long size,
Packit Service 103f6b
			unsigned int alignment)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake;
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
Packit Service 103f6b
Packit Service 103f6b
	assert(size != 0);
Packit Service 103f6b
Packit Service 103f6b
	bo_fake = calloc(1, sizeof(*bo_fake));
Packit Service 103f6b
	if (!bo_fake)
Packit Service 103f6b
		return NULL;
Packit Service 103f6b
Packit Service 103f6b
	bo_fake->bo.size = size;
Packit Service 103f6b
	bo_fake->bo.offset = -1;
Packit Service 103f6b
	bo_fake->bo.virtual = NULL;
Packit Service 103f6b
	bo_fake->bo.bufmgr = bufmgr;
Packit Service 103f6b
	bo_fake->refcount = 1;
Packit Service 103f6b
Packit Service 103f6b
	/* Alignment must be a power of two */
Packit Service 103f6b
	assert((alignment & (alignment - 1)) == 0);
Packit Service 103f6b
	if (alignment == 0)
Packit Service 103f6b
		alignment = 1;
Packit Service 103f6b
	bo_fake->alignment = alignment;
Packit Service 103f6b
	bo_fake->id = ++bufmgr_fake->buf_nr;
Packit Service 103f6b
	bo_fake->name = name;
Packit Service 103f6b
	bo_fake->flags = 0;
Packit Service 103f6b
	bo_fake->is_static = 0;
Packit Service 103f6b
Packit Service 103f6b
	DBG("drm_bo_alloc: (buf %d: %s, %lu kb)\n", bo_fake->id, bo_fake->name,
Packit Service 103f6b
	    bo_fake->bo.size / 1024);
Packit Service 103f6b
Packit Service 103f6b
	return &bo_fake->bo;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static drm_intel_bo *
Packit Service 103f6b
drm_intel_fake_bo_alloc_tiled(drm_intel_bufmgr * bufmgr,
Packit Service 103f6b
			      const char *name,
Packit Service 103f6b
			      int x, int y, int cpp,
Packit Service 103f6b
			      uint32_t *tiling_mode,
Packit Service 103f6b
			      unsigned long *pitch,
Packit Service 103f6b
			      unsigned long flags)
Packit Service 103f6b
{
Packit Service 103f6b
	unsigned long stride, aligned_y;
Packit Service 103f6b
Packit Service 103f6b
	/* No runtime tiling support for fake. */
Packit Service 103f6b
	*tiling_mode = I915_TILING_NONE;
Packit Service 103f6b
Packit Service 103f6b
	/* Align it for being a render target.  Shouldn't need anything else. */
Packit Service 103f6b
	stride = x * cpp;
Packit Service 103f6b
	stride = ROUND_UP_TO(stride, 64);
Packit Service 103f6b
Packit Service 103f6b
	/* 965 subspan loading alignment */
Packit Service 103f6b
	aligned_y = ALIGN(y, 2);
Packit Service 103f6b
Packit Service 103f6b
	*pitch = stride;
Packit Service 103f6b
Packit Service 103f6b
	return drm_intel_fake_bo_alloc(bufmgr, name, stride * aligned_y,
Packit Service 103f6b
				       4096);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
drm_public drm_intel_bo *
Packit Service 103f6b
drm_intel_bo_fake_alloc_static(drm_intel_bufmgr *bufmgr,
Packit Service 103f6b
			       const char *name,
Packit Service 103f6b
			       unsigned long offset,
Packit Service 103f6b
			       unsigned long size, void *virtual)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake;
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
Packit Service 103f6b
Packit Service 103f6b
	assert(size != 0);
Packit Service 103f6b
Packit Service 103f6b
	bo_fake = calloc(1, sizeof(*bo_fake));
Packit Service 103f6b
	if (!bo_fake)
Packit Service 103f6b
		return NULL;
Packit Service 103f6b
Packit Service 103f6b
	bo_fake->bo.size = size;
Packit Service 103f6b
	bo_fake->bo.offset = offset;
Packit Service 103f6b
	bo_fake->bo.virtual = virtual;
Packit Service 103f6b
	bo_fake->bo.bufmgr = bufmgr;
Packit Service 103f6b
	bo_fake->refcount = 1;
Packit Service 103f6b
	bo_fake->id = ++bufmgr_fake->buf_nr;
Packit Service 103f6b
	bo_fake->name = name;
Packit Service 103f6b
	bo_fake->flags = BM_PINNED;
Packit Service 103f6b
	bo_fake->is_static = 1;
Packit Service 103f6b
Packit Service 103f6b
	DBG("drm_bo_alloc_static: (buf %d: %s, %lu kb)\n", bo_fake->id,
Packit Service 103f6b
	    bo_fake->name, bo_fake->bo.size / 1024);
Packit Service 103f6b
Packit Service 103f6b
	return &bo_fake->bo;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
drm_intel_fake_bo_reference(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_lock(&bufmgr_fake->lock);
Packit Service 103f6b
	bo_fake->refcount++;
Packit Service 103f6b
	pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
drm_intel_fake_bo_reference_locked(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
Packit Service 103f6b
	bo_fake->refcount++;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
drm_intel_fake_bo_unreference_locked(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
	int i;
Packit Service 103f6b
Packit Service 103f6b
	if (--bo_fake->refcount == 0) {
Packit Service 103f6b
		assert(bo_fake->map_count == 0);
Packit Service 103f6b
		/* No remaining references, so free it */
Packit Service 103f6b
		if (bo_fake->block)
Packit Service 103f6b
			free_block(bufmgr_fake, bo_fake->block, 1);
Packit Service 103f6b
		free_backing_store(bo);
Packit Service 103f6b
Packit Service 103f6b
		for (i = 0; i < bo_fake->nr_relocs; i++)
Packit Service 103f6b
			drm_intel_fake_bo_unreference_locked(bo_fake->relocs[i].
Packit Service 103f6b
							     target_buf);
Packit Service 103f6b
Packit Service 103f6b
		DBG("drm_bo_unreference: free buf %d %s\n", bo_fake->id,
Packit Service 103f6b
		    bo_fake->name);
Packit Service 103f6b
Packit Service 103f6b
		free(bo_fake->relocs);
Packit Service 103f6b
		free(bo);
Packit Service 103f6b
	}
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
drm_intel_fake_bo_unreference(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_lock(&bufmgr_fake->lock);
Packit Service 103f6b
	drm_intel_fake_bo_unreference_locked(bo);
Packit Service 103f6b
	pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
/**
Packit Service 103f6b
 * Set the buffer as not requiring backing store, and instead get the callback
Packit Service 103f6b
 * invoked whenever it would be set dirty.
Packit Service 103f6b
 */
Packit Service 103f6b
drm_public void
Packit Service 103f6b
drm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo,
Packit Service 103f6b
					void (*invalidate_cb) (drm_intel_bo *bo,
Packit Service 103f6b
							       void *ptr),
Packit Service 103f6b
					void *ptr)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_lock(&bufmgr_fake->lock);
Packit Service 103f6b
Packit Service 103f6b
	if (bo_fake->backing_store)
Packit Service 103f6b
		free_backing_store(bo);
Packit Service 103f6b
Packit Service 103f6b
	bo_fake->flags |= BM_NO_BACKING_STORE;
Packit Service 103f6b
Packit Service 103f6b
	DBG("disable_backing_store set buf %d dirty\n", bo_fake->id);
Packit Service 103f6b
	bo_fake->dirty = 1;
Packit Service 103f6b
	bo_fake->invalidate_cb = invalidate_cb;
Packit Service 103f6b
	bo_fake->invalidate_ptr = ptr;
Packit Service 103f6b
Packit Service 103f6b
	/* Note that it is invalid right from the start.  Also note
Packit Service 103f6b
	 * invalidate_cb is called with the bufmgr locked, so cannot
Packit Service 103f6b
	 * itself make bufmgr calls.
Packit Service 103f6b
	 */
Packit Service 103f6b
	if (invalidate_cb != NULL)
Packit Service 103f6b
		invalidate_cb(bo, ptr);
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
/**
Packit Service 103f6b
 * Map a buffer into bo->virtual, allocating either card memory space (If
Packit Service 103f6b
 * BM_NO_BACKING_STORE or BM_PINNED) or backing store, as necessary.
Packit Service 103f6b
 */
Packit Service 103f6b
static int
Packit Service 103f6b
 drm_intel_fake_bo_map_locked(drm_intel_bo *bo, int write_enable)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
Packit Service 103f6b
	/* Static buffers are always mapped. */
Packit Service 103f6b
	if (bo_fake->is_static) {
Packit Service 103f6b
		if (bo_fake->card_dirty) {
Packit Service 103f6b
			drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
Packit Service 103f6b
			bo_fake->card_dirty = 0;
Packit Service 103f6b
		}
Packit Service 103f6b
		return 0;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	/* Allow recursive mapping.  Mesa may recursively map buffers with
Packit Service 103f6b
	 * nested display loops, and it is used internally in bufmgr_fake
Packit Service 103f6b
	 * for relocation.
Packit Service 103f6b
	 */
Packit Service 103f6b
	if (bo_fake->map_count++ != 0)
Packit Service 103f6b
		return 0;
Packit Service 103f6b
Packit Service 103f6b
	{
Packit Service 103f6b
		DBG("drm_bo_map: (buf %d: %s, %lu kb)\n", bo_fake->id,
Packit Service 103f6b
		    bo_fake->name, bo_fake->bo.size / 1024);
Packit Service 103f6b
Packit Service 103f6b
		if (bo->virtual != NULL) {
Packit Service 103f6b
			drmMsg("%s: already mapped\n", __func__);
Packit Service 103f6b
			abort();
Packit Service 103f6b
		} else if (bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED)) {
Packit Service 103f6b
Packit Service 103f6b
			if (!bo_fake->block && !evict_and_alloc_block(bo)) {
Packit Service 103f6b
				DBG("%s: alloc failed\n", __func__);
Packit Service 103f6b
				bufmgr_fake->fail = 1;
Packit Service 103f6b
				return 1;
Packit Service 103f6b
			} else {
Packit Service 103f6b
				assert(bo_fake->block);
Packit Service 103f6b
				bo_fake->dirty = 0;
Packit Service 103f6b
Packit Service 103f6b
				if (!(bo_fake->flags & BM_NO_FENCE_SUBDATA) &&
Packit Service 103f6b
				    bo_fake->block->fenced) {
Packit Service 103f6b
					drm_intel_fake_bo_wait_rendering_locked
Packit Service 103f6b
					    (bo);
Packit Service 103f6b
				}
Packit Service 103f6b
Packit Service 103f6b
				bo->virtual = bo_fake->block->virtual;
Packit Service 103f6b
			}
Packit Service 103f6b
		} else {
Packit Service 103f6b
			if (write_enable)
Packit Service 103f6b
				set_dirty(bo);
Packit Service 103f6b
Packit Service 103f6b
			if (bo_fake->backing_store == 0)
Packit Service 103f6b
				alloc_backing_store(bo);
Packit Service 103f6b
Packit Service 103f6b
			if ((bo_fake->card_dirty == 1) && bo_fake->block) {
Packit Service 103f6b
				if (bo_fake->block->fenced)
Packit Service 103f6b
					drm_intel_fake_bo_wait_rendering_locked
Packit Service 103f6b
					    (bo);
Packit Service 103f6b
Packit Service 103f6b
				memcpy(bo_fake->backing_store,
Packit Service 103f6b
				       bo_fake->block->virtual,
Packit Service 103f6b
				       bo_fake->block->bo->size);
Packit Service 103f6b
				bo_fake->card_dirty = 0;
Packit Service 103f6b
			}
Packit Service 103f6b
Packit Service 103f6b
			bo->virtual = bo_fake->backing_store;
Packit Service 103f6b
		}
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	return 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
 drm_intel_fake_bo_map(drm_intel_bo *bo, int write_enable)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	int ret;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_lock(&bufmgr_fake->lock);
Packit Service 103f6b
	ret = drm_intel_fake_bo_map_locked(bo, write_enable);
Packit Service 103f6b
	pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
Packit Service 103f6b
	return ret;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
 drm_intel_fake_bo_unmap_locked(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
Packit Service 103f6b
	/* Static buffers are always mapped. */
Packit Service 103f6b
	if (bo_fake->is_static)
Packit Service 103f6b
		return 0;
Packit Service 103f6b
Packit Service 103f6b
	assert(bo_fake->map_count != 0);
Packit Service 103f6b
	if (--bo_fake->map_count != 0)
Packit Service 103f6b
		return 0;
Packit Service 103f6b
Packit Service 103f6b
	DBG("drm_bo_unmap: (buf %d: %s, %lu kb)\n", bo_fake->id, bo_fake->name,
Packit Service 103f6b
	    bo_fake->bo.size / 1024);
Packit Service 103f6b
Packit Service 103f6b
	bo->virtual = NULL;
Packit Service 103f6b
Packit Service 103f6b
	return 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int drm_intel_fake_bo_unmap(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	int ret;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_lock(&bufmgr_fake->lock);
Packit Service 103f6b
	ret = drm_intel_fake_bo_unmap_locked(bo);
Packit Service 103f6b
	pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
Packit Service 103f6b
	return ret;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
drm_intel_fake_bo_subdata(drm_intel_bo *bo, unsigned long offset,
Packit Service 103f6b
			  unsigned long size, const void *data)
Packit Service 103f6b
{
Packit Service 103f6b
	int ret;
Packit Service 103f6b
Packit Service 103f6b
	if (size == 0 || data == NULL)
Packit Service 103f6b
		return 0;
Packit Service 103f6b
Packit Service 103f6b
	ret = drm_intel_bo_map(bo, 1);
Packit Service 103f6b
	if (ret)
Packit Service 103f6b
		return ret;
Packit Service 103f6b
	memcpy((unsigned char *)bo->virtual + offset, data, size);
Packit Service 103f6b
	drm_intel_bo_unmap(bo);
Packit Service 103f6b
	return 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
 drm_intel_fake_kick_all_locked(drm_intel_bufmgr_fake *bufmgr_fake)
Packit Service 103f6b
{
Packit Service 103f6b
	struct block *block, *tmp;
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake->performed_rendering = 0;
Packit Service 103f6b
	/* okay for ever BO that is on the HW kick it off.
Packit Service 103f6b
	   seriously not afraid of the POLICE right now */
Packit Service 103f6b
	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) {
Packit Service 103f6b
		drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
Packit Service 103f6b
Packit Service 103f6b
		block->on_hardware = 0;
Packit Service 103f6b
		free_block(bufmgr_fake, block, 0);
Packit Service 103f6b
		bo_fake->block = NULL;
Packit Service 103f6b
		bo_fake->validated = 0;
Packit Service 103f6b
		if (!(bo_fake->flags & BM_NO_BACKING_STORE))
Packit Service 103f6b
			bo_fake->dirty = 1;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
 drm_intel_fake_bo_validate(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake = (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
Packit Service 103f6b
	DBG("drm_bo_validate: (buf %d: %s, %lu kb)\n", bo_fake->id,
Packit Service 103f6b
	    bo_fake->name, bo_fake->bo.size / 1024);
Packit Service 103f6b
Packit Service 103f6b
	/* Sanity check: Buffers should be unmapped before being validated.
Packit Service 103f6b
	 * This is not so much of a problem for bufmgr_fake, but TTM refuses,
Packit Service 103f6b
	 * and the problem is harder to debug there.
Packit Service 103f6b
	 */
Packit Service 103f6b
	assert(bo_fake->map_count == 0);
Packit Service 103f6b
Packit Service 103f6b
	if (bo_fake->is_static) {
Packit Service 103f6b
		/* Add it to the needs-fence list */
Packit Service 103f6b
		bufmgr_fake->need_fence = 1;
Packit Service 103f6b
		return 0;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	/* Allocate the card memory */
Packit Service 103f6b
	if (!bo_fake->block && !evict_and_alloc_block(bo)) {
Packit Service 103f6b
		bufmgr_fake->fail = 1;
Packit Service 103f6b
		DBG("Failed to validate buf %d:%s\n", bo_fake->id,
Packit Service 103f6b
		    bo_fake->name);
Packit Service 103f6b
		return -1;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	assert(bo_fake->block);
Packit Service 103f6b
	assert(bo_fake->block->bo == &bo_fake->bo);
Packit Service 103f6b
Packit Service 103f6b
	bo->offset = bo_fake->block->mem->ofs;
Packit Service 103f6b
Packit Service 103f6b
	/* Upload the buffer contents if necessary */
Packit Service 103f6b
	if (bo_fake->dirty) {
Packit Service 103f6b
		DBG("Upload dirty buf %d:%s, sz %lu offset 0x%x\n", bo_fake->id,
Packit Service 103f6b
		    bo_fake->name, bo->size, bo_fake->block->mem->ofs);
Packit Service 103f6b
Packit Service 103f6b
		assert(!(bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED)));
Packit Service 103f6b
Packit Service 103f6b
		/* Actually, should be able to just wait for a fence on the
Packit Service 103f6b
		 * memory, which we would be tracking when we free it. Waiting
Packit Service 103f6b
		 * for idle is a sufficiently large hammer for now.
Packit Service 103f6b
		 */
Packit Service 103f6b
		drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
Packit Service 103f6b
Packit Service 103f6b
		/* we may never have mapped this BO so it might not have any
Packit Service 103f6b
		 * backing store if this happens it should be rare, but 0 the
Packit Service 103f6b
		 * card memory in any case */
Packit Service 103f6b
		if (bo_fake->backing_store)
Packit Service 103f6b
			memcpy(bo_fake->block->virtual, bo_fake->backing_store,
Packit Service 103f6b
			       bo->size);
Packit Service 103f6b
		else
Packit Service 103f6b
			memset(bo_fake->block->virtual, 0, bo->size);
Packit Service 103f6b
Packit Service 103f6b
		bo_fake->dirty = 0;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	bo_fake->block->fenced = 0;
Packit Service 103f6b
	bo_fake->block->on_hardware = 1;
Packit Service 103f6b
	DRMLISTDEL(bo_fake->block);
Packit Service 103f6b
	DRMLISTADDTAIL(bo_fake->block, &bufmgr_fake->on_hardware);
Packit Service 103f6b
Packit Service 103f6b
	bo_fake->validated = 1;
Packit Service 103f6b
	bufmgr_fake->need_fence = 1;
Packit Service 103f6b
Packit Service 103f6b
	return 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
drm_intel_fake_fence_validated(drm_intel_bufmgr *bufmgr)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
Packit Service 103f6b
	unsigned int cookie;
Packit Service 103f6b
Packit Service 103f6b
	cookie = _fence_emit_internal(bufmgr_fake);
Packit Service 103f6b
	fence_blocks(bufmgr_fake, cookie);
Packit Service 103f6b
Packit Service 103f6b
	DBG("drm_fence_validated: 0x%08x cookie\n", cookie);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
drm_intel_fake_destroy(drm_intel_bufmgr *bufmgr)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_destroy(&bufmgr_fake->lock);
Packit Service 103f6b
	mmDestroy(bufmgr_fake->heap);
Packit Service 103f6b
	free(bufmgr);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
drm_intel_fake_emit_reloc(drm_intel_bo *bo, uint32_t offset,
Packit Service 103f6b
			  drm_intel_bo *target_bo, uint32_t target_offset,
Packit Service 103f6b
			  uint32_t read_domains, uint32_t write_domain)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	struct fake_buffer_reloc *r;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
	drm_intel_bo_fake *target_fake = (drm_intel_bo_fake *) target_bo;
Packit Service 103f6b
	int i;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_lock(&bufmgr_fake->lock);
Packit Service 103f6b
Packit Service 103f6b
	assert(bo);
Packit Service 103f6b
	assert(target_bo);
Packit Service 103f6b
Packit Service 103f6b
	if (bo_fake->relocs == NULL) {
Packit Service 103f6b
		bo_fake->relocs =
Packit Service 103f6b
		    malloc(sizeof(struct fake_buffer_reloc) * MAX_RELOCS);
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	r = &bo_fake->relocs[bo_fake->nr_relocs++];
Packit Service 103f6b
Packit Service 103f6b
	assert(bo_fake->nr_relocs <= MAX_RELOCS);
Packit Service 103f6b
Packit Service 103f6b
	drm_intel_fake_bo_reference_locked(target_bo);
Packit Service 103f6b
Packit Service 103f6b
	if (!target_fake->is_static) {
Packit Service 103f6b
		bo_fake->child_size +=
Packit Service 103f6b
		    ALIGN(target_bo->size, target_fake->alignment);
Packit Service 103f6b
		bo_fake->child_size += target_fake->child_size;
Packit Service 103f6b
	}
Packit Service 103f6b
	r->target_buf = target_bo;
Packit Service 103f6b
	r->offset = offset;
Packit Service 103f6b
	r->last_target_offset = target_bo->offset;
Packit Service 103f6b
	r->delta = target_offset;
Packit Service 103f6b
	r->read_domains = read_domains;
Packit Service 103f6b
	r->write_domain = write_domain;
Packit Service 103f6b
Packit Service 103f6b
	if (bufmgr_fake->debug) {
Packit Service 103f6b
		/* Check that a conflicting relocation hasn't already been
Packit Service 103f6b
		 * emitted.
Packit Service 103f6b
		 */
Packit Service 103f6b
		for (i = 0; i < bo_fake->nr_relocs - 1; i++) {
Packit Service 103f6b
			struct fake_buffer_reloc *r2 = &bo_fake->relocs[i];
Packit Service 103f6b
Packit Service 103f6b
			assert(r->offset != r2->offset);
Packit Service 103f6b
		}
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
Packit Service 103f6b
	return 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
/**
Packit Service 103f6b
 * Incorporates the validation flags associated with each relocation into
Packit Service 103f6b
 * the combined validation flags for the buffer on this batchbuffer submission.
Packit Service 103f6b
 */
Packit Service 103f6b
static void
Packit Service 103f6b
drm_intel_fake_calculate_domains(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
	int i;
Packit Service 103f6b
Packit Service 103f6b
	for (i = 0; i < bo_fake->nr_relocs; i++) {
Packit Service 103f6b
		struct fake_buffer_reloc *r = &bo_fake->relocs[i];
Packit Service 103f6b
		drm_intel_bo_fake *target_fake =
Packit Service 103f6b
		    (drm_intel_bo_fake *) r->target_buf;
Packit Service 103f6b
Packit Service 103f6b
		/* Do the same for the tree of buffers we depend on */
Packit Service 103f6b
		drm_intel_fake_calculate_domains(r->target_buf);
Packit Service 103f6b
Packit Service 103f6b
		target_fake->read_domains |= r->read_domains;
Packit Service 103f6b
		target_fake->write_domain |= r->write_domain;
Packit Service 103f6b
	}
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
drm_intel_fake_reloc_and_validate_buffer(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
	int i, ret;
Packit Service 103f6b
Packit Service 103f6b
	assert(bo_fake->map_count == 0);
Packit Service 103f6b
Packit Service 103f6b
	for (i = 0; i < bo_fake->nr_relocs; i++) {
Packit Service 103f6b
		struct fake_buffer_reloc *r = &bo_fake->relocs[i];
Packit Service 103f6b
		drm_intel_bo_fake *target_fake =
Packit Service 103f6b
		    (drm_intel_bo_fake *) r->target_buf;
Packit Service 103f6b
		uint32_t reloc_data;
Packit Service 103f6b
Packit Service 103f6b
		/* Validate the target buffer if that hasn't been done. */
Packit Service 103f6b
		if (!target_fake->validated) {
Packit Service 103f6b
			ret =
Packit Service 103f6b
			    drm_intel_fake_reloc_and_validate_buffer(r->target_buf);
Packit Service 103f6b
			if (ret != 0) {
Packit Service 103f6b
				if (bo->virtual != NULL)
Packit Service 103f6b
					drm_intel_fake_bo_unmap_locked(bo);
Packit Service 103f6b
				return ret;
Packit Service 103f6b
			}
Packit Service 103f6b
		}
Packit Service 103f6b
Packit Service 103f6b
		/* Calculate the value of the relocation entry. */
Packit Service 103f6b
		if (r->target_buf->offset != r->last_target_offset) {
Packit Service 103f6b
			reloc_data = r->target_buf->offset + r->delta;
Packit Service 103f6b
Packit Service 103f6b
			if (bo->virtual == NULL)
Packit Service 103f6b
				drm_intel_fake_bo_map_locked(bo, 1);
Packit Service 103f6b
Packit Service 103f6b
			*(uint32_t *) ((uint8_t *) bo->virtual + r->offset) =
Packit Service 103f6b
			    reloc_data;
Packit Service 103f6b
Packit Service 103f6b
			r->last_target_offset = r->target_buf->offset;
Packit Service 103f6b
		}
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	if (bo->virtual != NULL)
Packit Service 103f6b
		drm_intel_fake_bo_unmap_locked(bo);
Packit Service 103f6b
Packit Service 103f6b
	if (bo_fake->write_domain != 0) {
Packit Service 103f6b
		if (!(bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED))) {
Packit Service 103f6b
			if (bo_fake->backing_store == 0)
Packit Service 103f6b
				alloc_backing_store(bo);
Packit Service 103f6b
		}
Packit Service 103f6b
		bo_fake->card_dirty = 1;
Packit Service 103f6b
		bufmgr_fake->performed_rendering = 1;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	return drm_intel_fake_bo_validate(bo);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static void
Packit Service 103f6b
drm_intel_bo_fake_post_submit(drm_intel_bo *bo)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
	int i;
Packit Service 103f6b
Packit Service 103f6b
	for (i = 0; i < bo_fake->nr_relocs; i++) {
Packit Service 103f6b
		struct fake_buffer_reloc *r = &bo_fake->relocs[i];
Packit Service 103f6b
		drm_intel_bo_fake *target_fake =
Packit Service 103f6b
		    (drm_intel_bo_fake *) r->target_buf;
Packit Service 103f6b
Packit Service 103f6b
		if (target_fake->validated)
Packit Service 103f6b
			drm_intel_bo_fake_post_submit(r->target_buf);
Packit Service 103f6b
Packit Service 103f6b
		DBG("%s@0x%08x + 0x%08x -> %s@0x%08x + 0x%08x\n",
Packit Service 103f6b
		    bo_fake->name, (uint32_t) bo->offset, r->offset,
Packit Service 103f6b
		    target_fake->name, (uint32_t) r->target_buf->offset,
Packit Service 103f6b
		    r->delta);
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	assert(bo_fake->map_count == 0);
Packit Service 103f6b
	bo_fake->validated = 0;
Packit Service 103f6b
	bo_fake->read_domains = 0;
Packit Service 103f6b
	bo_fake->write_domain = 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
drm_public void
Packit Service 103f6b
drm_intel_bufmgr_fake_set_exec_callback(drm_intel_bufmgr *bufmgr,
Packit Service 103f6b
					     int (*exec) (drm_intel_bo *bo,
Packit Service 103f6b
							  unsigned int used,
Packit Service 103f6b
							  void *priv),
Packit Service 103f6b
					     void *priv)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake->exec = exec;
Packit Service 103f6b
	bufmgr_fake->exec_priv = priv;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
static int
Packit Service 103f6b
drm_intel_fake_bo_exec(drm_intel_bo *bo, int used,
Packit Service 103f6b
		       drm_clip_rect_t * cliprects, int num_cliprects, int DR4)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo->bufmgr;
Packit Service 103f6b
	drm_intel_bo_fake *batch_fake = (drm_intel_bo_fake *) bo;
Packit Service 103f6b
	struct drm_i915_batchbuffer batch;
Packit Service 103f6b
	int ret;
Packit Service 103f6b
	int retry_count = 0;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_lock(&bufmgr_fake->lock);
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake->performed_rendering = 0;
Packit Service 103f6b
Packit Service 103f6b
	drm_intel_fake_calculate_domains(bo);
Packit Service 103f6b
Packit Service 103f6b
	batch_fake->read_domains = I915_GEM_DOMAIN_COMMAND;
Packit Service 103f6b
Packit Service 103f6b
	/* we've ran out of RAM so blow the whole lot away and retry */
Packit Service 103f6b
restart:
Packit Service 103f6b
	ret = drm_intel_fake_reloc_and_validate_buffer(bo);
Packit Service 103f6b
	if (bufmgr_fake->fail == 1) {
Packit Service 103f6b
		if (retry_count == 0) {
Packit Service 103f6b
			retry_count++;
Packit Service 103f6b
			drm_intel_fake_kick_all_locked(bufmgr_fake);
Packit Service 103f6b
			bufmgr_fake->fail = 0;
Packit Service 103f6b
			goto restart;
Packit Service 103f6b
		} else		/* dump out the memory here */
Packit Service 103f6b
			mmDumpMemInfo(bufmgr_fake->heap);
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	assert(ret == 0);
Packit Service 103f6b
Packit Service 103f6b
	if (bufmgr_fake->exec != NULL) {
Packit Service 103f6b
		ret = bufmgr_fake->exec(bo, used, bufmgr_fake->exec_priv);
Packit Service 103f6b
		if (ret != 0) {
Packit Service 103f6b
			pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
			return ret;
Packit Service 103f6b
		}
Packit Service 103f6b
	} else {
Packit Service 103f6b
		batch.start = bo->offset;
Packit Service 103f6b
		batch.used = used;
Packit Service 103f6b
		batch.cliprects = cliprects;
Packit Service 103f6b
		batch.num_cliprects = num_cliprects;
Packit Service 103f6b
		batch.DR1 = 0;
Packit Service 103f6b
		batch.DR4 = DR4;
Packit Service 103f6b
Packit Service 103f6b
		if (drmCommandWrite
Packit Service 103f6b
		    (bufmgr_fake->fd, DRM_I915_BATCHBUFFER, &batch,
Packit Service 103f6b
		     sizeof(batch))) {
Packit Service 103f6b
			drmMsg("DRM_I915_BATCHBUFFER: %d\n", -errno);
Packit Service 103f6b
			pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
			return -errno;
Packit Service 103f6b
		}
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	drm_intel_fake_fence_validated(bo->bufmgr);
Packit Service 103f6b
Packit Service 103f6b
	drm_intel_bo_fake_post_submit(bo);
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
Packit Service 103f6b
	return 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
/**
Packit Service 103f6b
 * Return an error if the list of BOs will exceed the aperture size.
Packit Service 103f6b
 *
Packit Service 103f6b
 * This is a rough guess and likely to fail, as during the validate sequence we
Packit Service 103f6b
 * may place a buffer in an inopportune spot early on and then fail to fit
Packit Service 103f6b
 * a set smaller than the aperture.
Packit Service 103f6b
 */
Packit Service 103f6b
static int
Packit Service 103f6b
drm_intel_fake_check_aperture_space(drm_intel_bo ** bo_array, int count)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake =
Packit Service 103f6b
	    (drm_intel_bufmgr_fake *) bo_array[0]->bufmgr;
Packit Service 103f6b
	unsigned int sz = 0;
Packit Service 103f6b
	int i;
Packit Service 103f6b
Packit Service 103f6b
	for (i = 0; i < count; i++) {
Packit Service 103f6b
		drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo_array[i];
Packit Service 103f6b
Packit Service 103f6b
		if (bo_fake == NULL)
Packit Service 103f6b
			continue;
Packit Service 103f6b
Packit Service 103f6b
		if (!bo_fake->is_static)
Packit Service 103f6b
			sz += ALIGN(bo_array[i]->size, bo_fake->alignment);
Packit Service 103f6b
		sz += bo_fake->child_size;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	if (sz > bufmgr_fake->size) {
Packit Service 103f6b
		DBG("check_space: overflowed bufmgr size, %ukb vs %lukb\n",
Packit Service 103f6b
		    sz / 1024, bufmgr_fake->size / 1024);
Packit Service 103f6b
		return -1;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	DBG("drm_check_space: sz %ukb vs bufgr %lukb\n", sz / 1024,
Packit Service 103f6b
	    bufmgr_fake->size / 1024);
Packit Service 103f6b
	return 0;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
/**
Packit Service 103f6b
 * Evicts all buffers, waiting for fences to pass and copying contents out
Packit Service 103f6b
 * as necessary.
Packit Service 103f6b
 *
Packit Service 103f6b
 * Used by the X Server on LeaveVT, when the card memory is no longer our
Packit Service 103f6b
 * own.
Packit Service 103f6b
 */
Packit Service 103f6b
drm_public void
Packit Service 103f6b
drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
Packit Service 103f6b
	struct block *block, *tmp;
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_lock(&bufmgr_fake->lock);
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake->need_fence = 1;
Packit Service 103f6b
	bufmgr_fake->fail = 0;
Packit Service 103f6b
Packit Service 103f6b
	/* Wait for hardware idle.  We don't know where acceleration has been
Packit Service 103f6b
	 * happening, so we'll need to wait anyway before letting anything get
Packit Service 103f6b
	 * put on the card again.
Packit Service 103f6b
	 */
Packit Service 103f6b
	drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
Packit Service 103f6b
Packit Service 103f6b
	/* Check that we hadn't released the lock without having fenced the last
Packit Service 103f6b
	 * set of buffers.
Packit Service 103f6b
	 */
Packit Service 103f6b
	assert(DRMLISTEMPTY(&bufmgr_fake->fenced));
Packit Service 103f6b
	assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
Packit Service 103f6b
Packit Service 103f6b
	DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
Packit Service 103f6b
		drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
Packit Service 103f6b
		/* Releases the memory, and memcpys dirty contents out if
Packit Service 103f6b
		 * necessary.
Packit Service 103f6b
		 */
Packit Service 103f6b
		free_block(bufmgr_fake, block, 0);
Packit Service 103f6b
		bo_fake->block = NULL;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	pthread_mutex_unlock(&bufmgr_fake->lock);
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
drm_public void
Packit Service 103f6b
drm_intel_bufmgr_fake_set_last_dispatch(drm_intel_bufmgr *bufmgr,
Packit Service 103f6b
					volatile unsigned int
Packit Service 103f6b
					*last_dispatch)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake->last_dispatch = (volatile int *)last_dispatch;
Packit Service 103f6b
}
Packit Service 103f6b
Packit Service 103f6b
drm_public drm_intel_bufmgr *
Packit Service 103f6b
drm_intel_bufmgr_fake_init(int fd, unsigned long low_offset,
Packit Service 103f6b
			   void *low_virtual, unsigned long size,
Packit Service 103f6b
			   volatile unsigned int *last_dispatch)
Packit Service 103f6b
{
Packit Service 103f6b
	drm_intel_bufmgr_fake *bufmgr_fake;
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake = calloc(1, sizeof(*bufmgr_fake));
Packit Service 103f6b
Packit Service 103f6b
	if (pthread_mutex_init(&bufmgr_fake->lock, NULL) != 0) {
Packit Service 103f6b
		free(bufmgr_fake);
Packit Service 103f6b
		return NULL;
Packit Service 103f6b
	}
Packit Service 103f6b
Packit Service 103f6b
	/* Initialize allocator */
Packit Service 103f6b
	DRMINITLISTHEAD(&bufmgr_fake->fenced);
Packit Service 103f6b
	DRMINITLISTHEAD(&bufmgr_fake->on_hardware);
Packit Service 103f6b
	DRMINITLISTHEAD(&bufmgr_fake->lru);
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake->low_offset = low_offset;
Packit Service 103f6b
	bufmgr_fake->virtual = low_virtual;
Packit Service 103f6b
	bufmgr_fake->size = size;
Packit Service 103f6b
	bufmgr_fake->heap = mmInit(low_offset, size);
Packit Service 103f6b
Packit Service 103f6b
	/* Hook in methods */
Packit Service 103f6b
	bufmgr_fake->bufmgr.bo_alloc = drm_intel_fake_bo_alloc;
Packit Service 103f6b
	bufmgr_fake->bufmgr.bo_alloc_for_render = drm_intel_fake_bo_alloc;
Packit Service 103f6b
	bufmgr_fake->bufmgr.bo_alloc_tiled = drm_intel_fake_bo_alloc_tiled;
Packit Service 103f6b
	bufmgr_fake->bufmgr.bo_reference = drm_intel_fake_bo_reference;
Packit Service 103f6b
	bufmgr_fake->bufmgr.bo_unreference = drm_intel_fake_bo_unreference;
Packit Service 103f6b
	bufmgr_fake->bufmgr.bo_map = drm_intel_fake_bo_map;
Packit Service 103f6b
	bufmgr_fake->bufmgr.bo_unmap = drm_intel_fake_bo_unmap;
Packit Service 103f6b
	bufmgr_fake->bufmgr.bo_subdata = drm_intel_fake_bo_subdata;
Packit Service 103f6b
	bufmgr_fake->bufmgr.bo_wait_rendering =
Packit Service 103f6b
	    drm_intel_fake_bo_wait_rendering;
Packit Service 103f6b
	bufmgr_fake->bufmgr.bo_emit_reloc = drm_intel_fake_emit_reloc;
Packit Service 103f6b
	bufmgr_fake->bufmgr.destroy = drm_intel_fake_destroy;
Packit Service 103f6b
	bufmgr_fake->bufmgr.bo_exec = drm_intel_fake_bo_exec;
Packit Service 103f6b
	bufmgr_fake->bufmgr.check_aperture_space =
Packit Service 103f6b
	    drm_intel_fake_check_aperture_space;
Packit Service 103f6b
	bufmgr_fake->bufmgr.debug = 0;
Packit Service 103f6b
Packit Service 103f6b
	bufmgr_fake->fd = fd;
Packit Service 103f6b
	bufmgr_fake->last_dispatch = (volatile int *)last_dispatch;
Packit Service 103f6b
Packit Service 103f6b
	return &bufmgr_fake->bufmgr;
Packit Service 103f6b
}