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

Commit 1f7e3050 authored by Jani Nikula's avatar Jani Nikula
Browse files

Merge tag 'gvt-next-2018-04-23' of https://github.com/intel/gvt-linux into drm-intel-next-queued



- Minor condition check improvment (Gustavo A. R. Silva)
- Non-priviliged batch buffer scan (Yan Zhao)
- Scheduling optimizations (Zhipeng Gong)

Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/5dafba29-b2bd-6b94-630e-db5c009da7e3@intel.com
parents 011f22eb 3eda0d22
Loading
Loading
Loading
Loading
+42 −13
Original line number Original line Diff line number Diff line
@@ -1603,7 +1603,8 @@ static int batch_buffer_needs_scan(struct parser_exec_state *s)
	if (IS_BROADWELL(gvt->dev_priv) || IS_SKYLAKE(gvt->dev_priv)
	if (IS_BROADWELL(gvt->dev_priv) || IS_SKYLAKE(gvt->dev_priv)
		|| IS_KABYLAKE(gvt->dev_priv)) {
		|| IS_KABYLAKE(gvt->dev_priv)) {
		/* BDW decides privilege based on address space */
		/* BDW decides privilege based on address space */
		if (cmd_val(s, 0) & (1 << 8))
		if (cmd_val(s, 0) & (1 << 8) &&
			!(s->vgpu->scan_nonprivbb & (1 << s->ring_id)))
			return 0;
			return 0;
	}
	}
	return 1;
	return 1;
@@ -1617,6 +1618,8 @@ static int find_bb_size(struct parser_exec_state *s, unsigned long *bb_size)
	bool bb_end = false;
	bool bb_end = false;
	struct intel_vgpu *vgpu = s->vgpu;
	struct intel_vgpu *vgpu = s->vgpu;
	u32 cmd;
	u32 cmd;
	struct intel_vgpu_mm *mm = (s->buf_addr_type == GTT_BUFFER) ?
		s->vgpu->gtt.ggtt_mm : s->workload->shadow_mm;


	*bb_size = 0;
	*bb_size = 0;


@@ -1628,18 +1631,22 @@ static int find_bb_size(struct parser_exec_state *s, unsigned long *bb_size)
	cmd = cmd_val(s, 0);
	cmd = cmd_val(s, 0);
	info = get_cmd_info(s->vgpu->gvt, cmd, s->ring_id);
	info = get_cmd_info(s->vgpu->gvt, cmd, s->ring_id);
	if (info == NULL) {
	if (info == NULL) {
		gvt_vgpu_err("unknown cmd 0x%x, opcode=0x%x\n",
		gvt_vgpu_err("unknown cmd 0x%x, opcode=0x%x, addr_type=%s, ring %d, workload=%p\n",
				cmd, get_opcode(cmd, s->ring_id));
				cmd, get_opcode(cmd, s->ring_id),
				(s->buf_addr_type == PPGTT_BUFFER) ?
				"ppgtt" : "ggtt", s->ring_id, s->workload);
		return -EBADRQC;
		return -EBADRQC;
	}
	}
	do {
	do {
		if (copy_gma_to_hva(s->vgpu, s->vgpu->gtt.ggtt_mm,
		if (copy_gma_to_hva(s->vgpu, mm,
				gma, gma + 4, &cmd) < 0)
				gma, gma + 4, &cmd) < 0)
			return -EFAULT;
			return -EFAULT;
		info = get_cmd_info(s->vgpu->gvt, cmd, s->ring_id);
		info = get_cmd_info(s->vgpu->gvt, cmd, s->ring_id);
		if (info == NULL) {
		if (info == NULL) {
			gvt_vgpu_err("unknown cmd 0x%x, opcode=0x%x\n",
			gvt_vgpu_err("unknown cmd 0x%x, opcode=0x%x, addr_type=%s, ring %d, workload=%p\n",
				cmd, get_opcode(cmd, s->ring_id));
				cmd, get_opcode(cmd, s->ring_id),
				(s->buf_addr_type == PPGTT_BUFFER) ?
				"ppgtt" : "ggtt", s->ring_id, s->workload);
			return -EBADRQC;
			return -EBADRQC;
		}
		}


@@ -1665,6 +1672,9 @@ static int perform_bb_shadow(struct parser_exec_state *s)
	unsigned long gma = 0;
	unsigned long gma = 0;
	unsigned long bb_size;
	unsigned long bb_size;
	int ret = 0;
	int ret = 0;
	struct intel_vgpu_mm *mm = (s->buf_addr_type == GTT_BUFFER) ?
		s->vgpu->gtt.ggtt_mm : s->workload->shadow_mm;
	unsigned long gma_start_offset = 0;


	/* get the start gm address of the batch buffer */
	/* get the start gm address of the batch buffer */
	gma = get_gma_bb_from_cmd(s, 1);
	gma = get_gma_bb_from_cmd(s, 1);
@@ -1679,8 +1689,24 @@ static int perform_bb_shadow(struct parser_exec_state *s)
	if (!bb)
	if (!bb)
		return -ENOMEM;
		return -ENOMEM;


	bb->ppgtt = (s->buf_addr_type == GTT_BUFFER) ? false : true;

	/* the gma_start_offset stores the batch buffer's start gma's
	 * offset relative to page boundary. so for non-privileged batch
	 * buffer, the shadowed gem object holds exactly the same page
	 * layout as original gem object. This is for the convience of
	 * replacing the whole non-privilged batch buffer page to this
	 * shadowed one in PPGTT at the same gma address. (this replacing
	 * action is not implemented yet now, but may be necessary in
	 * future).
	 * for prileged batch buffer, we just change start gma address to
	 * that of shadowed page.
	 */
	if (bb->ppgtt)
		gma_start_offset = gma & ~I915_GTT_PAGE_MASK;

	bb->obj = i915_gem_object_create(s->vgpu->gvt->dev_priv,
	bb->obj = i915_gem_object_create(s->vgpu->gvt->dev_priv,
					 roundup(bb_size, PAGE_SIZE));
			 roundup(bb_size + gma_start_offset, PAGE_SIZE));
	if (IS_ERR(bb->obj)) {
	if (IS_ERR(bb->obj)) {
		ret = PTR_ERR(bb->obj);
		ret = PTR_ERR(bb->obj);
		goto err_free_bb;
		goto err_free_bb;
@@ -1701,9 +1727,9 @@ static int perform_bb_shadow(struct parser_exec_state *s)
		bb->clflush &= ~CLFLUSH_BEFORE;
		bb->clflush &= ~CLFLUSH_BEFORE;
	}
	}


	ret = copy_gma_to_hva(s->vgpu, s->vgpu->gtt.ggtt_mm,
	ret = copy_gma_to_hva(s->vgpu, mm,
			      gma, gma + bb_size,
			      gma, gma + bb_size,
			      bb->va);
			      bb->va + gma_start_offset);
	if (ret < 0) {
	if (ret < 0) {
		gvt_vgpu_err("fail to copy guest ring buffer\n");
		gvt_vgpu_err("fail to copy guest ring buffer\n");
		ret = -EFAULT;
		ret = -EFAULT;
@@ -1729,7 +1755,7 @@ static int perform_bb_shadow(struct parser_exec_state *s)
	 * buffer's gma in pair. After all, we don't want to pin the shadow
	 * buffer's gma in pair. After all, we don't want to pin the shadow
	 * buffer here (too early).
	 * buffer here (too early).
	 */
	 */
	s->ip_va = bb->va;
	s->ip_va = bb->va + gma_start_offset;
	s->ip_gma = gma;
	s->ip_gma = gma;
	return 0;
	return 0;
err_unmap:
err_unmap:
@@ -2468,15 +2494,18 @@ static int cmd_parser_exec(struct parser_exec_state *s)


	info = get_cmd_info(s->vgpu->gvt, cmd, s->ring_id);
	info = get_cmd_info(s->vgpu->gvt, cmd, s->ring_id);
	if (info == NULL) {
	if (info == NULL) {
		gvt_vgpu_err("unknown cmd 0x%x, opcode=0x%x\n",
		gvt_vgpu_err("unknown cmd 0x%x, opcode=0x%x, addr_type=%s, ring %d, workload=%p\n",
				cmd, get_opcode(cmd, s->ring_id));
				cmd, get_opcode(cmd, s->ring_id),
				(s->buf_addr_type == PPGTT_BUFFER) ?
				"ppgtt" : "ggtt", s->ring_id, s->workload);
		return -EBADRQC;
		return -EBADRQC;
	}
	}


	s->info = info;
	s->info = info;


	trace_gvt_command(vgpu->id, s->ring_id, s->ip_gma, s->ip_va,
	trace_gvt_command(vgpu->id, s->ring_id, s->ip_gma, s->ip_va,
			  cmd_length(s), s->buf_type);
			  cmd_length(s), s->buf_type, s->buf_addr_type,
			  s->workload, info->name);


	if (info->handler) {
	if (info->handler) {
		ret = info->handler(s);
		ret = info->handler(s);
+67 −0
Original line number Original line Diff line number Diff line
@@ -124,6 +124,68 @@ static int vgpu_mmio_diff_show(struct seq_file *s, void *unused)
}
}
DEFINE_SHOW_ATTRIBUTE(vgpu_mmio_diff);
DEFINE_SHOW_ATTRIBUTE(vgpu_mmio_diff);


static int
vgpu_scan_nonprivbb_get(void *data, u64 *val)
{
	struct intel_vgpu *vgpu = (struct intel_vgpu *)data;
	*val = vgpu->scan_nonprivbb;
	return 0;
}

/*
 * set/unset bit engine_id of vgpu->scan_nonprivbb to turn on/off scanning
 * of non-privileged batch buffer. e.g.
 * if vgpu->scan_nonprivbb=3, then it will scan non-privileged batch buffer
 * on engine 0 and 1.
 */
static int
vgpu_scan_nonprivbb_set(void *data, u64 val)
{
	struct intel_vgpu *vgpu = (struct intel_vgpu *)data;
	struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
	enum intel_engine_id id;
	char buf[128], *s;
	int len;

	val &= (1 << I915_NUM_ENGINES) - 1;

	if (vgpu->scan_nonprivbb == val)
		return 0;

	if (!val)
		goto done;

	len = sprintf(buf,
		"gvt: vgpu %d turns on non-privileged batch buffers scanning on Engines:",
		vgpu->id);

	s = buf + len;

	for (id = 0; id < I915_NUM_ENGINES; id++) {
		struct intel_engine_cs *engine;

		engine = dev_priv->engine[id];
		if (engine && (val & (1 << id))) {
			len = snprintf(s, 4, "%d, ", engine->id);
			s += len;
		} else
			val &=  ~(1 << id);
	}

	if (val)
		sprintf(s, "low performance expected.");

	pr_warn("%s\n", buf);

done:
	vgpu->scan_nonprivbb = val;
	return 0;
}

DEFINE_SIMPLE_ATTRIBUTE(vgpu_scan_nonprivbb_fops,
			vgpu_scan_nonprivbb_get, vgpu_scan_nonprivbb_set,
			"0x%llx\n");

/**
/**
 * intel_gvt_debugfs_add_vgpu - register debugfs entries for a vGPU
 * intel_gvt_debugfs_add_vgpu - register debugfs entries for a vGPU
 * @vgpu: a vGPU
 * @vgpu: a vGPU
@@ -151,6 +213,11 @@ int intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu)
	if (!ent)
	if (!ent)
		return -ENOMEM;
		return -ENOMEM;


	ent = debugfs_create_file("scan_nonprivbb", 0644, vgpu->debugfs,
				 vgpu, &vgpu_scan_nonprivbb_fops);
	if (!ent)
		return -ENOMEM;

	return 0;
	return 0;
}
}


+1 −0
Original line number Original line Diff line number Diff line
@@ -226,6 +226,7 @@ struct intel_vgpu {


	struct completion vblank_done;
	struct completion vblank_done;


	u32 scan_nonprivbb;
};
};


/* validating GM healthy status*/
/* validating GM healthy status*/
+1 −0
Original line number Original line Diff line number Diff line
@@ -1150,6 +1150,7 @@ static int handle_g2v_notification(struct intel_vgpu *vgpu, int notification)
	switch (notification) {
	switch (notification) {
	case VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE:
	case VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE:
		root_entry_type = GTT_TYPE_PPGTT_ROOT_L3_ENTRY;
		root_entry_type = GTT_TYPE_PPGTT_ROOT_L3_ENTRY;
		/* fall through */
	case VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE:
	case VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE:
		mm = intel_vgpu_get_ppgtt_mm(vgpu, root_entry_type, pdps);
		mm = intel_vgpu_get_ppgtt_mm(vgpu, root_entry_type, pdps);
		return PTR_ERR_OR_ZERO(mm);
		return PTR_ERR_OR_ZERO(mm);
+18 −13
Original line number Original line Diff line number Diff line
@@ -53,7 +53,6 @@ struct vgpu_sched_data {
	bool active;
	bool active;


	ktime_t sched_in_time;
	ktime_t sched_in_time;
	ktime_t sched_out_time;
	ktime_t sched_time;
	ktime_t sched_time;
	ktime_t left_ts;
	ktime_t left_ts;
	ktime_t allocated_ts;
	ktime_t allocated_ts;
@@ -66,17 +65,22 @@ struct gvt_sched_data {
	struct hrtimer timer;
	struct hrtimer timer;
	unsigned long period;
	unsigned long period;
	struct list_head lru_runq_head;
	struct list_head lru_runq_head;
	ktime_t expire_time;
};
};


static void vgpu_update_timeslice(struct intel_vgpu *pre_vgpu)
static void vgpu_update_timeslice(struct intel_vgpu *vgpu, ktime_t cur_time)
{
{
	ktime_t delta_ts;
	ktime_t delta_ts;
	struct vgpu_sched_data *vgpu_data = pre_vgpu->sched_data;
	struct vgpu_sched_data *vgpu_data;


	delta_ts = vgpu_data->sched_out_time - vgpu_data->sched_in_time;
	if (!vgpu || vgpu == vgpu->gvt->idle_vgpu)
		return;


	vgpu_data->sched_time += delta_ts;
	vgpu_data = vgpu->sched_data;
	vgpu_data->left_ts -= delta_ts;
	delta_ts = ktime_sub(cur_time, vgpu_data->sched_in_time);
	vgpu_data->sched_time = ktime_add(vgpu_data->sched_time, delta_ts);
	vgpu_data->left_ts = ktime_sub(vgpu_data->left_ts, delta_ts);
	vgpu_data->sched_in_time = cur_time;
}
}


#define GVT_TS_BALANCE_PERIOD_MS 100
#define GVT_TS_BALANCE_PERIOD_MS 100
@@ -150,11 +154,7 @@ static void try_to_schedule_next_vgpu(struct intel_gvt *gvt)
	}
	}


	cur_time = ktime_get();
	cur_time = ktime_get();
	if (scheduler->current_vgpu) {
	vgpu_update_timeslice(scheduler->current_vgpu, cur_time);
		vgpu_data = scheduler->current_vgpu->sched_data;
		vgpu_data->sched_out_time = cur_time;
		vgpu_update_timeslice(scheduler->current_vgpu);
	}
	vgpu_data = scheduler->next_vgpu->sched_data;
	vgpu_data = scheduler->next_vgpu->sched_data;
	vgpu_data->sched_in_time = cur_time;
	vgpu_data->sched_in_time = cur_time;


@@ -226,17 +226,22 @@ static void tbs_sched_func(struct gvt_sched_data *sched_data)
void intel_gvt_schedule(struct intel_gvt *gvt)
void intel_gvt_schedule(struct intel_gvt *gvt)
{
{
	struct gvt_sched_data *sched_data = gvt->scheduler.sched_data;
	struct gvt_sched_data *sched_data = gvt->scheduler.sched_data;
	static uint64_t timer_check;
	ktime_t cur_time;


	mutex_lock(&gvt->lock);
	mutex_lock(&gvt->lock);
	cur_time = ktime_get();


	if (test_and_clear_bit(INTEL_GVT_REQUEST_SCHED,
	if (test_and_clear_bit(INTEL_GVT_REQUEST_SCHED,
				(void *)&gvt->service_request)) {
				(void *)&gvt->service_request)) {
		if (!(timer_check++ % GVT_TS_BALANCE_PERIOD_MS))
		if (cur_time >= sched_data->expire_time) {
			gvt_balance_timeslice(sched_data);
			gvt_balance_timeslice(sched_data);
			sched_data->expire_time = ktime_add_ms(
				cur_time, GVT_TS_BALANCE_PERIOD_MS);
		}
	}
	}
	clear_bit(INTEL_GVT_REQUEST_EVENT_SCHED, (void *)&gvt->service_request);
	clear_bit(INTEL_GVT_REQUEST_EVENT_SCHED, (void *)&gvt->service_request);


	vgpu_update_timeslice(gvt->scheduler.current_vgpu, cur_time);
	tbs_sched_func(sched_data);
	tbs_sched_func(sched_data);


	mutex_unlock(&gvt->lock);
	mutex_unlock(&gvt->lock);
Loading