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

Commit b0fd47ad authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915: Copy user requested buffers into the error state



Introduce a new execobject.flag (EXEC_OBJECT_CAPTURE) that userspace may
use to indicate that it wants the contents of this buffer preserved in
the error state (/sys/class/drm/cardN/error) following a GPU hang
involving this batch.

Use this at your discretion, the contents of the error state. although
compressed, are allocated with GFP_ATOMIC (i.e. limited) and kept for all
eternity (until the error state is destroyed).

Based on an earlier patch by Ben Widawsky <ben@bwidawsk.net>
Testcase: igt/gem_exec_capture
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Ben Widawsky <ben@bwidawsk.net>
Cc: Matt Turner <mattst88@gmail.com>
Acked-by: default avatarBen Widawsky <ben@bwidawsk.net>
Acked-by: default avatarMatt Turner <mattst88@gmail.com>
Reviewed-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170415093902.22581-1-chris@chris-wilson.co.uk
parent f4bf77b4
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -350,6 +350,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
	case I915_PARAM_HAS_EXEC_SOFTPIN:
	case I915_PARAM_HAS_EXEC_SOFTPIN:
	case I915_PARAM_HAS_EXEC_ASYNC:
	case I915_PARAM_HAS_EXEC_ASYNC:
	case I915_PARAM_HAS_EXEC_FENCE:
	case I915_PARAM_HAS_EXEC_FENCE:
	case I915_PARAM_HAS_EXEC_CAPTURE:
		/* For the time being all of these are always true;
		/* For the time being all of these are always true;
		 * if some supported hardware does not have one of these
		 * if some supported hardware does not have one of these
		 * features this value needs to be provided from
		 * features this value needs to be provided from
+3 −0
Original line number Original line Diff line number Diff line
@@ -1025,6 +1025,9 @@ struct i915_gpu_state {
			u32 *pages[0];
			u32 *pages[0];
		} *ringbuffer, *batchbuffer, *wa_batchbuffer, *ctx, *hws_page;
		} *ringbuffer, *batchbuffer, *wa_batchbuffer, *ctx, *hws_page;


		struct drm_i915_error_object **user_bo;
		long user_bo_count;

		struct drm_i915_error_object *wa_ctx;
		struct drm_i915_error_object *wa_ctx;


		struct drm_i915_error_request {
		struct drm_i915_error_request {
+12 −0
Original line number Original line Diff line number Diff line
@@ -1114,6 +1114,18 @@ i915_gem_execbuffer_move_to_gpu(struct drm_i915_gem_request *req,
	list_for_each_entry(vma, vmas, exec_list) {
	list_for_each_entry(vma, vmas, exec_list) {
		struct drm_i915_gem_object *obj = vma->obj;
		struct drm_i915_gem_object *obj = vma->obj;


		if (vma->exec_entry->flags & EXEC_OBJECT_CAPTURE) {
			struct i915_gem_capture_list *capture;

			capture = kmalloc(sizeof(*capture), GFP_KERNEL);
			if (unlikely(!capture))
				return -ENOMEM;

			capture->next = req->capture_list;
			capture->vma = vma;
			req->capture_list = capture;
		}

		if (vma->exec_entry->flags & EXEC_OBJECT_ASYNC)
		if (vma->exec_entry->flags & EXEC_OBJECT_ASYNC)
			continue;
			continue;


+16 −0
Original line number Original line Diff line number Diff line
@@ -292,6 +292,19 @@ static void advance_ring(struct drm_i915_gem_request *request)
	request->ring->head = tail;
	request->ring->head = tail;
}
}


static void free_capture_list(struct drm_i915_gem_request *request)
{
	struct i915_gem_capture_list *capture;

	capture = request->capture_list;
	while (capture) {
		struct i915_gem_capture_list *next = capture->next;

		kfree(capture);
		capture = next;
	}
}

static void i915_gem_request_retire(struct drm_i915_gem_request *request)
static void i915_gem_request_retire(struct drm_i915_gem_request *request)
{
{
	struct intel_engine_cs *engine = request->engine;
	struct intel_engine_cs *engine = request->engine;
@@ -317,6 +330,8 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request)
	unreserve_seqno(request->engine);
	unreserve_seqno(request->engine);
	advance_ring(request);
	advance_ring(request);


	free_capture_list(request);

	/* Walk through the active list, calling retire on each. This allows
	/* Walk through the active list, calling retire on each. This allows
	 * objects to track their GPU activity and mark themselves as idle
	 * objects to track their GPU activity and mark themselves as idle
	 * when their *last* active request is completed (updating state
	 * when their *last* active request is completed (updating state
@@ -615,6 +630,7 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
	req->global_seqno = 0;
	req->global_seqno = 0;
	req->file_priv = NULL;
	req->file_priv = NULL;
	req->batch = NULL;
	req->batch = NULL;
	req->capture_list = NULL;


	/*
	/*
	 * Reserve space in the ring buffer for all the commands required to
	 * Reserve space in the ring buffer for all the commands required to
+11 −0
Original line number Original line Diff line number Diff line
@@ -73,6 +73,11 @@ struct i915_priotree {
#define I915_PRIORITY_MIN (-I915_PRIORITY_MAX)
#define I915_PRIORITY_MIN (-I915_PRIORITY_MAX)
};
};


struct i915_gem_capture_list {
	struct i915_gem_capture_list *next;
	struct i915_vma *vma;
};

/**
/**
 * Request queue structure.
 * Request queue structure.
 *
 *
@@ -167,6 +172,12 @@ struct drm_i915_gem_request {
	 * error state dump only).
	 * error state dump only).
	 */
	 */
	struct i915_vma *batch;
	struct i915_vma *batch;
	/** Additional buffers requested by userspace to be captured upon
	 * a GPU hang. The vma/obj on this list are protected by their
	 * active reference - all objects on this list must also be
	 * on the active_list (of their final request).
	 */
	struct i915_gem_capture_list *capture_list;
	struct list_head active_list;
	struct list_head active_list;


	/** Time at which this request was emitted, in jiffies. */
	/** Time at which this request was emitted, in jiffies. */
Loading