Commit 9b4d0598 authored by Tvrtko Ursulin's avatar Tvrtko Ursulin Committed by Daniel Vetter
Browse files

drm/i915: Request watchdog infrastructure



Prepares the plumbing for setting request/fence expiration time. All code
is put in place but is never activated due yet missing ability to actually
configure the timer.

Outline of the basic operation:

A timer is started when request is ready for execution. If the request
completes (retires) before the timer fires, timer is cancelled and nothing
further happens.

If the timer fires request is added to a lockless list and worker queued.
Purpose of this is twofold: a) It allows request cancellation from a more
friendly context and b) coalesces multiple expirations into a single event
of consuming the list.

Worker locklessly consumes the list of expired requests and cancels them
all using previous added i915_request_cancel().

Associated timeout value is stored in rq->context.watchdog.timeout_us.

v2:
 * Log expiration.

v3:
 * Include more information about user timeline in the log message.

v4:
 * Remove obsolete comment and fix formatting. (Matt)

Signed-off-by: default avatarTvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: default avatarMatthew Auld <matthew.auld@intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20210324121335.2307063-6-tvrtko.ursulin@linux.intel.com
parent 90a79a91
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -97,6 +97,10 @@ struct intel_context {
#define CONTEXT_FORCE_SINGLE_SUBMISSION	7
#define CONTEXT_FORCE_SINGLE_SUBMISSION	7
#define CONTEXT_NOPREEMPT		8
#define CONTEXT_NOPREEMPT		8


	struct {
		u64 timeout_us;
	} watchdog;

	u32 *lrc_reg_state;
	u32 *lrc_reg_state;
	union {
	union {
		struct {
		struct {
+2 −0
Original line number Original line Diff line number Diff line
@@ -6,6 +6,7 @@
#ifndef __INTEL_EXECLISTS_SUBMISSION_H__
#ifndef __INTEL_EXECLISTS_SUBMISSION_H__
#define __INTEL_EXECLISTS_SUBMISSION_H__
#define __INTEL_EXECLISTS_SUBMISSION_H__


#include <linux/llist.h>
#include <linux/types.h>
#include <linux/types.h>


struct drm_printer;
struct drm_printer;
@@ -13,6 +14,7 @@ struct drm_printer;
struct i915_request;
struct i915_request;
struct intel_context;
struct intel_context;
struct intel_engine_cs;
struct intel_engine_cs;
struct intel_gt;


enum {
enum {
	INTEL_CONTEXT_SCHEDULE_IN = 0,
	INTEL_CONTEXT_SCHEDULE_IN = 0,
+3 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,9 @@ void intel_gt_init_early(struct intel_gt *gt, struct drm_i915_private *i915)
	INIT_LIST_HEAD(&gt->closed_vma);
	INIT_LIST_HEAD(&gt->closed_vma);
	spin_lock_init(&gt->closed_lock);
	spin_lock_init(&gt->closed_lock);


	init_llist_head(&gt->watchdog.list);
	INIT_WORK(&gt->watchdog.work, intel_gt_watchdog_work);

	intel_gt_init_buffer_pool(gt);
	intel_gt_init_buffer_pool(gt);
	intel_gt_init_reset(gt);
	intel_gt_init_reset(gt);
	intel_gt_init_requests(gt);
	intel_gt_init_requests(gt);
+2 −0
Original line number Original line Diff line number Diff line
@@ -77,4 +77,6 @@ static inline bool intel_gt_is_wedged(const struct intel_gt *gt)
void intel_gt_info_print(const struct intel_gt_info *info,
void intel_gt_info_print(const struct intel_gt_info *info,
			 struct drm_printer *p);
			 struct drm_printer *p);


void intel_gt_watchdog_work(struct work_struct *work);

#endif /* __INTEL_GT_H__ */
#endif /* __INTEL_GT_H__ */
+28 −0
Original line number Original line Diff line number Diff line
@@ -9,6 +9,7 @@
#include "i915_drv.h" /* for_each_engine() */
#include "i915_drv.h" /* for_each_engine() */
#include "i915_request.h"
#include "i915_request.h"
#include "intel_engine_heartbeat.h"
#include "intel_engine_heartbeat.h"
#include "intel_execlists_submission.h"
#include "intel_gt.h"
#include "intel_gt.h"
#include "intel_gt_pm.h"
#include "intel_gt_pm.h"
#include "intel_gt_requests.h"
#include "intel_gt_requests.h"
@@ -243,4 +244,31 @@ void intel_gt_fini_requests(struct intel_gt *gt)
{
{
	/* Wait until the work is marked as finished before unloading! */
	/* Wait until the work is marked as finished before unloading! */
	cancel_delayed_work_sync(&gt->requests.retire_work);
	cancel_delayed_work_sync(&gt->requests.retire_work);

	flush_work(&gt->watchdog.work);
}

void intel_gt_watchdog_work(struct work_struct *work)
{
	struct intel_gt *gt =
		container_of(work, typeof(*gt), watchdog.work);
	struct i915_request *rq, *rn;
	struct llist_node *first;

	first = llist_del_all(&gt->watchdog.list);
	if (!first)
		return;

	llist_for_each_entry_safe(rq, rn, first, watchdog.link) {
		if (!i915_request_completed(rq)) {
			struct dma_fence *f = &rq->fence;

			pr_notice("Fence expiration time out i915-%s:%s:%llx!\n",
				  f->ops->get_driver_name(f),
				  f->ops->get_timeline_name(f),
				  f->seqno);
			i915_request_cancel(rq, -EINTR);
		}
		i915_request_put(rq);
	}
}
}
Loading