Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ca5d4b4 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'vmwgfx-fixes-3.14-2014-02-05' of...

Merge tag 'vmwgfx-fixes-3.14-2014-02-05' of git://people.freedesktop.org/~thomash/linux into drm-next

A couple of vmwgfx fixes together with missing bits of legacy device
emulation to facilitate old user-space drivers on new devices.

The shader emulation bits are a bit large, but since they mostly touch the
new device code, regressions are unlikely. I figure the gain of having
this from the start clearly outweighs the risc of adding these bits at
this point.

Pull request of 2014-02-05

* tag 'vmwgfx-fixes-3.14-2014-02-05' of git://people.freedesktop.org/~thomash/linux:
  vmwgfx: Fix unitialized stack read in vmw_setup_otable_base
  drm/vmwgfx: Reemit context bindings when necessary v2
  drm/vmwgfx: Detect old user-space drivers and set up legacy emulation v2
  drm/vmwgfx: Emulate legacy shaders on guest-backed devices v2
  drm/vmwgfx: Fix legacy surface reference size copyback
  drm/vmwgfx: Fix SET_SHADER_CONST emulation on guest-backed devices
  drm/vmwgfx: Fix regression caused by "drm/ttm: make ttm reservation calls behave like reservation calls"
  drm/vmwgfx: Don't commit staged bindings if execbuf fails
parents 9df5a9b0 cd9a21a8
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -2583,4 +2583,28 @@ typedef union {
   float  f;
} SVGA3dDevCapResult;

typedef enum {
   SVGA3DCAPS_RECORD_UNKNOWN        = 0,
   SVGA3DCAPS_RECORD_DEVCAPS_MIN    = 0x100,
   SVGA3DCAPS_RECORD_DEVCAPS        = 0x100,
   SVGA3DCAPS_RECORD_DEVCAPS_MAX    = 0x1ff,
} SVGA3dCapsRecordType;

typedef
struct SVGA3dCapsRecordHeader {
   uint32 length;
   SVGA3dCapsRecordType type;
}
SVGA3dCapsRecordHeader;

typedef
struct SVGA3dCapsRecord {
   SVGA3dCapsRecordHeader header;
   uint32 data[1];
}
SVGA3dCapsRecord;


typedef uint32 SVGA3dCapPair[2];

#endif /* _SVGA3D_REG_H_ */
+123 −21
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ struct vmw_user_context {



typedef int (*vmw_scrub_func)(struct vmw_ctx_bindinfo *);
typedef int (*vmw_scrub_func)(struct vmw_ctx_bindinfo *, bool);

static void vmw_user_context_free(struct vmw_resource *res);
static struct vmw_resource *
@@ -50,9 +50,11 @@ static int vmw_gb_context_unbind(struct vmw_resource *res,
				 bool readback,
				 struct ttm_validate_buffer *val_buf);
static int vmw_gb_context_destroy(struct vmw_resource *res);
static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi);
static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi);
static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi);
static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind);
static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi,
					   bool rebind);
static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi, bool rebind);
static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs);
static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs);
static uint64_t vmw_user_context_size;

@@ -111,10 +113,14 @@ static void vmw_hw_context_destroy(struct vmw_resource *res)

	if (res->func->destroy == vmw_gb_context_destroy) {
		mutex_lock(&dev_priv->cmdbuf_mutex);
		mutex_lock(&dev_priv->binding_mutex);
		(void) vmw_context_binding_state_kill
			(&container_of(res, struct vmw_user_context, res)->cbs);
		(void) vmw_gb_context_destroy(res);
		if (dev_priv->pinned_bo != NULL &&
		    !dev_priv->query_cid_valid)
			__vmw_execbuf_release_pinned_bo(dev_priv, NULL);
		mutex_unlock(&dev_priv->binding_mutex);
		mutex_unlock(&dev_priv->cmdbuf_mutex);
		return;
	}
@@ -328,7 +334,7 @@ static int vmw_gb_context_unbind(struct vmw_resource *res,
	BUG_ON(bo->mem.mem_type != VMW_PL_MOB);

	mutex_lock(&dev_priv->binding_mutex);
	vmw_context_binding_state_kill(&uctx->cbs);
	vmw_context_binding_state_scrub(&uctx->cbs);

	submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);

@@ -378,10 +384,6 @@ static int vmw_gb_context_destroy(struct vmw_resource *res)
		SVGA3dCmdHeader header;
		SVGA3dCmdDestroyGBContext body;
	} *cmd;
	struct vmw_user_context *uctx =
		container_of(res, struct vmw_user_context, res);

	BUG_ON(!list_empty(&uctx->cbs.list));

	if (likely(res->id == -1))
		return 0;
@@ -528,8 +530,9 @@ out_unlock:
 * vmw_context_scrub_shader - scrub a shader binding from a context.
 *
 * @bi: single binding information.
 * @rebind: Whether to issue a bind instead of scrub command.
 */
static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi)
static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind)
{
	struct vmw_private *dev_priv = bi->ctx->dev_priv;
	struct {
@@ -548,7 +551,8 @@ static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi)
	cmd->header.size = sizeof(cmd->body);
	cmd->body.cid = bi->ctx->id;
	cmd->body.type = bi->i1.shader_type;
	cmd->body.shid = SVGA3D_INVALID_ID;
	cmd->body.shid =
		cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
	vmw_fifo_commit(dev_priv, sizeof(*cmd));

	return 0;
@@ -559,8 +563,10 @@ static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi)
 * from a context.
 *
 * @bi: single binding information.
 * @rebind: Whether to issue a bind instead of scrub command.
 */
static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi)
static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi,
					   bool rebind)
{
	struct vmw_private *dev_priv = bi->ctx->dev_priv;
	struct {
@@ -579,7 +585,8 @@ static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi)
	cmd->header.size = sizeof(cmd->body);
	cmd->body.cid = bi->ctx->id;
	cmd->body.type = bi->i1.rt_type;
	cmd->body.target.sid = SVGA3D_INVALID_ID;
	cmd->body.target.sid =
		cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
	cmd->body.target.face = 0;
	cmd->body.target.mipmap = 0;
	vmw_fifo_commit(dev_priv, sizeof(*cmd));
@@ -591,11 +598,13 @@ static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi)
 * vmw_context_scrub_texture - scrub a texture binding from a context.
 *
 * @bi: single binding information.
 * @rebind: Whether to issue a bind instead of scrub command.
 *
 * TODO: Possibly complement this function with a function that takes
 * a list of texture bindings and combines them to a single command.
 */
static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi)
static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi,
				     bool rebind)
{
	struct vmw_private *dev_priv = bi->ctx->dev_priv;
	struct {
@@ -619,7 +628,8 @@ static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi)
	cmd->body.c.cid = bi->ctx->id;
	cmd->body.s1.stage = bi->i1.texture_stage;
	cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE;
	cmd->body.s1.value = (uint32) SVGA3D_INVALID_ID;
	cmd->body.s1.value =
		cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
	vmw_fifo_commit(dev_priv, sizeof(*cmd));

	return 0;
@@ -692,6 +702,7 @@ int vmw_context_binding_add(struct vmw_ctx_binding_state *cbs,
		vmw_context_binding_drop(loc);

	loc->bi = *bi;
	loc->bi.scrubbed = false;
	list_add_tail(&loc->ctx_list, &cbs->list);
	INIT_LIST_HEAD(&loc->res_list);

@@ -727,12 +738,11 @@ static void vmw_context_binding_transfer(struct vmw_ctx_binding_state *cbs,
	if (loc->bi.ctx != NULL)
		vmw_context_binding_drop(loc);

	if (bi->res != NULL) {
		loc->bi = *bi;
		list_add_tail(&loc->ctx_list, &cbs->list);
	if (bi->res != NULL)
		list_add_tail(&loc->res_list, &bi->res->binding_head);
	else
		INIT_LIST_HEAD(&loc->res_list);
	}
}

/**
@@ -746,7 +756,10 @@ static void vmw_context_binding_transfer(struct vmw_ctx_binding_state *cbs,
 */
static void vmw_context_binding_kill(struct vmw_ctx_binding *cb)
{
	(void) vmw_scrub_funcs[cb->bi.bt](&cb->bi);
	if (!cb->bi.scrubbed) {
		(void) vmw_scrub_funcs[cb->bi.bt](&cb->bi, false);
		cb->bi.scrubbed = true;
	}
	vmw_context_binding_drop(cb);
}

@@ -767,6 +780,27 @@ static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs)
		vmw_context_binding_kill(entry);
}

/**
 * vmw_context_binding_state_scrub - Scrub all bindings associated with a
 * struct vmw_ctx_binding state structure.
 *
 * @cbs: Pointer to the context binding state tracker.
 *
 * Emits commands to scrub all bindings associated with the
 * context binding state tracker.
 */
static void vmw_context_binding_state_scrub(struct vmw_ctx_binding_state *cbs)
{
	struct vmw_ctx_binding *entry;

	list_for_each_entry(entry, &cbs->list, ctx_list) {
		if (!entry->bi.scrubbed) {
			(void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false);
			entry->bi.scrubbed = true;
		}
	}
}

/**
 * vmw_context_binding_res_list_kill - Kill all bindings on a
 * resource binding list
@@ -784,6 +818,27 @@ void vmw_context_binding_res_list_kill(struct list_head *head)
		vmw_context_binding_kill(entry);
}

/**
 * vmw_context_binding_res_list_scrub - Scrub all bindings on a
 * resource binding list
 *
 * @head: list head of resource binding list
 *
 * Scrub all bindings associated with a specific resource. Typically
 * called before the resource is evicted.
 */
void vmw_context_binding_res_list_scrub(struct list_head *head)
{
	struct vmw_ctx_binding *entry;

	list_for_each_entry(entry, head, res_list) {
		if (!entry->bi.scrubbed) {
			(void) vmw_scrub_funcs[entry->bi.bt](&entry->bi, false);
			entry->bi.scrubbed = true;
		}
	}
}

/**
 * vmw_context_binding_state_transfer - Commit staged binding info
 *
@@ -803,3 +858,50 @@ void vmw_context_binding_state_transfer(struct vmw_resource *ctx,
	list_for_each_entry_safe(entry, next, &from->list, ctx_list)
		vmw_context_binding_transfer(&uctx->cbs, &entry->bi);
}

/**
 * vmw_context_rebind_all - Rebind all scrubbed bindings of a context
 *
 * @ctx: The context resource
 *
 * Walks through the context binding list and rebinds all scrubbed
 * resources.
 */
int vmw_context_rebind_all(struct vmw_resource *ctx)
{
	struct vmw_ctx_binding *entry;
	struct vmw_user_context *uctx =
		container_of(ctx, struct vmw_user_context, res);
	struct vmw_ctx_binding_state *cbs = &uctx->cbs;
	int ret;

	list_for_each_entry(entry, &cbs->list, ctx_list) {
		if (likely(!entry->bi.scrubbed))
			continue;

		if (WARN_ON(entry->bi.res == NULL || entry->bi.res->id ==
			    SVGA3D_INVALID_ID))
			continue;

		ret = vmw_scrub_funcs[entry->bi.bt](&entry->bi, true);
		if (unlikely(ret != 0))
			return ret;

		entry->bi.scrubbed = false;
	}

	return 0;
}

/**
 * vmw_context_binding_list - Return a list of context bindings
 *
 * @ctx: The context resource
 *
 * Returns the current list of bindings of the given context. Note that
 * this list becomes stale as soon as the dev_priv::binding_mutex is unlocked.
 */
struct list_head *vmw_context_binding_list(struct vmw_resource *ctx)
{
	return &(container_of(ctx, struct vmw_user_context, res)->cbs.list);
}
+7 −0
Original line number Diff line number Diff line
@@ -941,6 +941,7 @@ static void vmw_postclose(struct drm_device *dev,
		drm_master_put(&vmw_fp->locked_master);
	}

	vmw_compat_shader_man_destroy(vmw_fp->shman);
	ttm_object_file_release(&vmw_fp->tfile);
	kfree(vmw_fp);
}
@@ -960,11 +961,17 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv)
	if (unlikely(vmw_fp->tfile == NULL))
		goto out_no_tfile;

	vmw_fp->shman = vmw_compat_shader_man_create(dev_priv);
	if (IS_ERR(vmw_fp->shman))
		goto out_no_shman;

	file_priv->driver_priv = vmw_fp;
	dev_priv->bdev.dev_mapping = dev->dev_mapping;

	return 0;

out_no_shman:
	ttm_object_file_release(&vmw_fp->tfile);
out_no_tfile:
	kfree(vmw_fp);
	return ret;
+34 −1
Original line number Diff line number Diff line
@@ -75,10 +75,14 @@
#define VMW_RES_FENCE ttm_driver_type3
#define VMW_RES_SHADER ttm_driver_type4

struct vmw_compat_shader_manager;

struct vmw_fpriv {
	struct drm_master *locked_master;
	struct ttm_object_file *tfile;
	struct list_head fence_events;
	bool gb_aware;
	struct vmw_compat_shader_manager *shman;
};

struct vmw_dma_buffer {
@@ -272,6 +276,7 @@ struct vmw_ctx_bindinfo {
	struct vmw_resource *ctx;
	struct vmw_resource *res;
	enum vmw_ctx_binding_type bt;
	bool scrubbed;
	union {
		SVGA3dShaderType shader_type;
		SVGA3dRenderTargetType rt_type;
@@ -318,7 +323,7 @@ struct vmw_sw_context{
	struct drm_open_hash res_ht;
	bool res_ht_initialized;
	bool kernel; /**< is the called made from the kernel */
	struct ttm_object_file *tfile;
	struct vmw_fpriv *fp;
	struct list_head validate_nodes;
	struct vmw_relocation relocs[VMWGFX_MAX_RELOCATIONS];
	uint32_t cur_reloc;
@@ -336,6 +341,7 @@ struct vmw_sw_context{
	bool needs_post_query_barrier;
	struct vmw_resource *error_resource;
	struct vmw_ctx_binding_state staged_bindings;
	struct list_head staged_shaders;
};

struct vmw_legacy_display;
@@ -569,6 +575,8 @@ struct vmw_user_resource_conv;

extern void vmw_resource_unreference(struct vmw_resource **p_res);
extern struct vmw_resource *vmw_resource_reference(struct vmw_resource *res);
extern struct vmw_resource *
vmw_resource_reference_unless_doomed(struct vmw_resource *res);
extern int vmw_resource_validate(struct vmw_resource *res);
extern int vmw_resource_reserve(struct vmw_resource *res, bool no_backup);
extern bool vmw_resource_needs_backup(const struct vmw_resource *res);
@@ -957,6 +965,9 @@ extern void
vmw_context_binding_state_transfer(struct vmw_resource *res,
				   struct vmw_ctx_binding_state *cbs);
extern void vmw_context_binding_res_list_kill(struct list_head *head);
extern void vmw_context_binding_res_list_scrub(struct list_head *head);
extern int vmw_context_rebind_all(struct vmw_resource *ctx);
extern struct list_head *vmw_context_binding_list(struct vmw_resource *ctx);

/*
 * Surface management - vmwgfx_surface.c
@@ -991,6 +1002,28 @@ extern int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
				   struct drm_file *file_priv);
extern int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
				    struct drm_file *file_priv);
extern int vmw_compat_shader_lookup(struct vmw_compat_shader_manager *man,
				    SVGA3dShaderType shader_type,
				    u32 *user_key);
extern void vmw_compat_shaders_commit(struct vmw_compat_shader_manager *man,
				      struct list_head *list);
extern void vmw_compat_shaders_revert(struct vmw_compat_shader_manager *man,
				      struct list_head *list);
extern int vmw_compat_shader_remove(struct vmw_compat_shader_manager *man,
				    u32 user_key,
				    SVGA3dShaderType shader_type,
				    struct list_head *list);
extern int vmw_compat_shader_add(struct vmw_compat_shader_manager *man,
				 u32 user_key, const void *bytecode,
				 SVGA3dShaderType shader_type,
				 size_t size,
				 struct ttm_object_file *tfile,
				 struct list_head *list);
extern struct vmw_compat_shader_manager *
vmw_compat_shader_man_create(struct vmw_private *dev_priv);
extern void
vmw_compat_shader_man_destroy(struct vmw_compat_shader_manager *man);


/**
 * Inline helper functions
+291 −39

File changed.

Preview size limit exceeded, changes collapsed.

Loading