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

Commit 91d0101a authored by Ping Gao's avatar Ping Gao Committed by Zhenyu Wang
Browse files

drm/i915/gvt: use hrtimer replace delayed_work in scheduler



Currently the scheduler is triggered by delayed_work, which doesn't
provide precision at microsecond level. Move to hrtimer instead for
more accurate control.

Signed-off-by: default avatarPing Gao <ping.a.gao@intel.com>
Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Signed-off-by: default avatarZhenyu Wang <zhenyuw@linux.intel.com>
parent 865f03d4
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -144,6 +144,11 @@ static int gvt_service_thread(void *data)
			intel_gvt_emulate_vblank(gvt);
			mutex_unlock(&gvt->lock);
		}

		if (test_and_clear_bit(INTEL_GVT_REQUEST_SCHED,
					(void *)&gvt->service_request)) {
			intel_gvt_schedule(gvt);
		}
	}

	return 0;
+1 −0
Original line number Diff line number Diff line
@@ -249,6 +249,7 @@ static inline struct intel_gvt *to_gvt(struct drm_i915_private *i915)

enum {
	INTEL_GVT_REQUEST_EMULATE_VBLANK = 0,
	INTEL_GVT_REQUEST_SCHED = 1,
};

static inline void intel_gvt_request_service(struct intel_gvt *gvt,
+33 −16
Original line number Diff line number Diff line
@@ -96,17 +96,16 @@ struct tbs_vgpu_data {

struct tbs_sched_data {
	struct intel_gvt *gvt;
	struct delayed_work work;
	struct hrtimer timer;
	unsigned long period;
	struct list_head runq_head;
};

#define GVT_DEFAULT_TIME_SLICE (msecs_to_jiffies(1))
/* in nanosecond */
#define GVT_DEFAULT_TIME_SLICE 1000000

static void tbs_sched_func(struct work_struct *work)
static void tbs_sched_func(struct tbs_sched_data *sched_data)
{
	struct tbs_sched_data *sched_data = container_of(work,
			struct tbs_sched_data, work.work);
	struct tbs_vgpu_data *vgpu_data;

	struct intel_gvt *gvt = sched_data->gvt;
@@ -115,8 +114,6 @@ static void tbs_sched_func(struct work_struct *work)
	struct intel_vgpu *vgpu = NULL;
	struct list_head *pos, *head;

	mutex_lock(&gvt->lock);

	/* no vgpu or has already had a target */
	if (list_empty(&sched_data->runq_head) || scheduler->next_vgpu)
		goto out;
@@ -151,17 +148,30 @@ static void tbs_sched_func(struct work_struct *work)
				scheduler->next_vgpu->id);
		try_to_schedule_next_vgpu(gvt);
	}
}

	/*
	 * still have vgpu on runq
	 * or last schedule haven't finished due to running workload
	 */
	if (!list_empty(&sched_data->runq_head) || scheduler->next_vgpu)
		schedule_delayed_work(&sched_data->work, sched_data->period);
void intel_gvt_schedule(struct intel_gvt *gvt)
{
	struct tbs_sched_data *sched_data = gvt->scheduler.sched_data;

	mutex_lock(&gvt->lock);
	tbs_sched_func(sched_data);
	mutex_unlock(&gvt->lock);
}

static enum hrtimer_restart tbs_timer_fn(struct hrtimer *timer_data)
{
	struct tbs_sched_data *data;

	data = container_of(timer_data, struct tbs_sched_data, timer);

	intel_gvt_request_service(data->gvt, INTEL_GVT_REQUEST_SCHED);

	hrtimer_add_expires_ns(&data->timer, data->period);

	return HRTIMER_RESTART;
}

static int tbs_sched_init(struct intel_gvt *gvt)
{
	struct intel_gvt_workload_scheduler *scheduler =
@@ -174,11 +184,13 @@ static int tbs_sched_init(struct intel_gvt *gvt)
		return -ENOMEM;

	INIT_LIST_HEAD(&data->runq_head);
	INIT_DELAYED_WORK(&data->work, tbs_sched_func);
	hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
	data->timer.function = tbs_timer_fn;
	data->period = GVT_DEFAULT_TIME_SLICE;
	data->gvt = gvt;

	scheduler->sched_data = data;

	return 0;
}

@@ -188,7 +200,8 @@ static void tbs_sched_clean(struct intel_gvt *gvt)
		&gvt->scheduler;
	struct tbs_sched_data *data = scheduler->sched_data;

	cancel_delayed_work(&data->work);
	hrtimer_cancel(&data->timer);

	kfree(data);
	scheduler->sched_data = NULL;
}
@@ -205,6 +218,7 @@ static int tbs_sched_init_vgpu(struct intel_vgpu *vgpu)
	INIT_LIST_HEAD(&data->list);

	vgpu->sched_data = data;

	return 0;
}

@@ -223,7 +237,10 @@ static void tbs_sched_start_schedule(struct intel_vgpu *vgpu)
		return;

	list_add_tail(&vgpu_data->list, &sched_data->runq_head);
	schedule_delayed_work(&sched_data->work, 0);

	if (!hrtimer_active(&sched_data->timer))
		hrtimer_start(&sched_data->timer, ktime_add_ns(ktime_get(),
			sched_data->period), HRTIMER_MODE_ABS);
}

static void tbs_sched_stop_schedule(struct intel_vgpu *vgpu)
+2 −0
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ struct intel_gvt_sched_policy_ops {
	void (*stop_schedule)(struct intel_vgpu *vgpu);
};

void intel_gvt_schedule(struct intel_gvt *gvt);

int intel_gvt_init_sched_policy(struct intel_gvt *gvt);

void intel_gvt_clean_sched_policy(struct intel_gvt *gvt);