Commit 2b25fb31 authored by Jani Nikula's avatar Jani Nikula
Browse files

Merge tag 'gvt-next-2021-03-16' of https://github.com/intel/gvt-linux into drm-intel-next



gvt-next-2021-03-16

- Parse accurate vGPU virtual display rate (Colin)
- Convert vblank timer as per-vGPU based on current rate (Colin)
- spelling fix (Bhaskar)

Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
From: Zhenyu Wang <zhenyuw@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210316074330.GC1551@zhen-hp.sh.intel.com
parents 41ed4005 9317f356
Loading
Loading
Loading
Loading
+59 −48
Original line number Diff line number Diff line
@@ -516,11 +516,27 @@ static void clean_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num)
	port->dpcd = NULL;
}

static enum hrtimer_restart vblank_timer_fn(struct hrtimer *data)
{
	struct intel_vgpu_vblank_timer *vblank_timer;
	struct intel_vgpu *vgpu;

	vblank_timer = container_of(data, struct intel_vgpu_vblank_timer, timer);
	vgpu = container_of(vblank_timer, struct intel_vgpu, vblank_timer);

	/* Set vblank emulation request per-vGPU bit */
	intel_gvt_request_service(vgpu->gvt,
				  INTEL_GVT_REQUEST_EMULATE_VBLANK + vgpu->id);
	hrtimer_add_expires_ns(&vblank_timer->timer, vblank_timer->period);
	return HRTIMER_RESTART;
}

static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num,
				    int type, unsigned int resolution)
{
	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
	struct intel_vgpu_port *port = intel_vgpu_port(vgpu, port_num);
	struct intel_vgpu_vblank_timer *vblank_timer = &vgpu->vblank_timer;

	if (drm_WARN_ON(&i915->drm, resolution >= GVT_EDID_NUM))
		return -EINVAL;
@@ -544,6 +560,14 @@ static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num,
	port->dpcd->data[DPCD_SINK_COUNT] = 0x1;
	port->type = type;
	port->id = resolution;
	port->vrefresh_k = GVT_DEFAULT_REFRESH_RATE * MSEC_PER_SEC;
	vgpu->display.port_num = port_num;

	/* Init hrtimer based on default refresh rate */
	hrtimer_init(&vblank_timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
	vblank_timer->timer.function = vblank_timer_fn;
	vblank_timer->vrefresh_k = port->vrefresh_k;
	vblank_timer->period = DIV64_U64_ROUND_CLOSEST(NSEC_PER_SEC * MSEC_PER_SEC, vblank_timer->vrefresh_k);

	emulate_monitor_status_change(vgpu);

@@ -551,41 +575,44 @@ static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num,
}

/**
 * intel_gvt_check_vblank_emulation - check if vblank emulation timer should
 * be turned on/off when a virtual pipe is enabled/disabled.
 * @gvt: a GVT device
 * vgpu_update_vblank_emulation - Update per-vGPU vblank_timer
 * @vgpu: vGPU operated
 * @turnon: Turn ON/OFF vblank_timer
 *
 * This function is used to turn on/off vblank timer according to currently
 * enabled/disabled virtual pipes.
 * This function is used to turn on/off or update the per-vGPU vblank_timer
 * when PIPECONF is enabled or disabled. vblank_timer period is also updated
 * if guest changed the refresh rate.
 *
 */
void intel_gvt_check_vblank_emulation(struct intel_gvt *gvt)
void vgpu_update_vblank_emulation(struct intel_vgpu *vgpu, bool turnon)
{
	struct intel_gvt_irq *irq = &gvt->irq;
	struct intel_vgpu *vgpu;
	int pipe, id;
	int found = false;
	struct intel_vgpu_vblank_timer *vblank_timer = &vgpu->vblank_timer;
	struct intel_vgpu_port *port =
		intel_vgpu_port(vgpu, vgpu->display.port_num);

	mutex_lock(&gvt->lock);
	for_each_active_vgpu(gvt, vgpu, id) {
		for (pipe = 0; pipe < I915_MAX_PIPES; pipe++) {
			if (pipe_is_enabled(vgpu, pipe)) {
				found = true;
				break;
			}
	if (turnon) {
		/*
		 * Skip the re-enable if already active and vrefresh unchanged.
		 * Otherwise, stop timer if already active and restart with new
		 *   period.
		 */
		if (vblank_timer->vrefresh_k != port->vrefresh_k ||
		    !hrtimer_active(&vblank_timer->timer)) {
			/* Stop timer before start with new period if active */
			if (hrtimer_active(&vblank_timer->timer))
				hrtimer_cancel(&vblank_timer->timer);

			/* Make sure new refresh rate updated to timer period */
			vblank_timer->vrefresh_k = port->vrefresh_k;
			vblank_timer->period = DIV64_U64_ROUND_CLOSEST(NSEC_PER_SEC * MSEC_PER_SEC, vblank_timer->vrefresh_k);
			hrtimer_start(&vblank_timer->timer,
				      ktime_add_ns(ktime_get(), vblank_timer->period),
				      HRTIMER_MODE_ABS);
		}
		if (found)
			break;
	} else {
		/* Caller request to stop vblank */
		hrtimer_cancel(&vblank_timer->timer);
	}

	/* all the pipes are disabled */
	if (!found)
		hrtimer_cancel(&irq->vblank_timer.timer);
	else
		hrtimer_start(&irq->vblank_timer.timer,
			ktime_add_ns(ktime_get(), irq->vblank_timer.period),
			HRTIMER_MODE_ABS);
	mutex_unlock(&gvt->lock);
}

static void emulate_vblank_on_pipe(struct intel_vgpu *vgpu, int pipe)
@@ -617,7 +644,7 @@ static void emulate_vblank_on_pipe(struct intel_vgpu *vgpu, int pipe)
	}
}

static void emulate_vblank(struct intel_vgpu *vgpu)
void intel_vgpu_emulate_vblank(struct intel_vgpu *vgpu)
{
	int pipe;

@@ -627,24 +654,6 @@ static void emulate_vblank(struct intel_vgpu *vgpu)
	mutex_unlock(&vgpu->vgpu_lock);
}

/**
 * intel_gvt_emulate_vblank - trigger vblank events for vGPUs on GVT device
 * @gvt: a GVT device
 *
 * This function is used to trigger vblank interrupts for vGPUs on GVT device
 *
 */
void intel_gvt_emulate_vblank(struct intel_gvt *gvt)
{
	struct intel_vgpu *vgpu;
	int id;

	mutex_lock(&gvt->lock);
	for_each_active_vgpu(gvt, vgpu, id)
		emulate_vblank(vgpu);
	mutex_unlock(&gvt->lock);
}

/**
 * intel_vgpu_emulate_hotplug - trigger hotplug event for vGPU
 * @vgpu: a vGPU
@@ -753,6 +762,8 @@ void intel_vgpu_clean_display(struct intel_vgpu *vgpu)
		clean_virtual_dp_monitor(vgpu, PORT_D);
	else
		clean_virtual_dp_monitor(vgpu, PORT_B);

	vgpu_update_vblank_emulation(vgpu, false);
}

/**
+12 −2
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#define _GVT_DISPLAY_H_

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

struct intel_gvt;
struct intel_vgpu;
@@ -157,6 +158,7 @@ enum intel_vgpu_edid {
	GVT_EDID_NUM,
};

#define GVT_DEFAULT_REFRESH_RATE 60
struct intel_vgpu_port {
	/* per display EDID information */
	struct intel_vgpu_edid_data *edid;
@@ -164,6 +166,14 @@ struct intel_vgpu_port {
	struct intel_vgpu_dpcd_data *dpcd;
	int type;
	enum intel_vgpu_edid id;
	/* x1000 to get accurate 59.94, 24.976, 29.94, etc. in timing std. */
	u32 vrefresh_k;
};

struct intel_vgpu_vblank_timer {
	struct hrtimer timer;
	u32 vrefresh_k;
	u64 period;
};

static inline char *vgpu_edid_str(enum intel_vgpu_edid id)
@@ -202,8 +212,8 @@ static inline unsigned int vgpu_edid_yres(enum intel_vgpu_edid id)
	}
}

void intel_gvt_emulate_vblank(struct intel_gvt *gvt);
void intel_gvt_check_vblank_emulation(struct intel_gvt *gvt);
void intel_vgpu_emulate_vblank(struct intel_vgpu *vgpu);
void vgpu_update_vblank_emulation(struct intel_vgpu *vgpu, bool turnon);

int intel_vgpu_init_display(struct intel_vgpu *vgpu, u64 resolution);
void intel_vgpu_reset_display(struct intel_vgpu *vgpu);
+2 −2
Original line number Diff line number Diff line
@@ -1159,8 +1159,8 @@ static inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se,
 * @vgpu: target vgpu
 * @entry: target pfn's gtt entry
 *
 * Return 1 if 2MB huge gtt shadowing is possilbe, 0 if miscondition,
 * negtive if found err.
 * Return 1 if 2MB huge gtt shadowing is possible, 0 if miscondition,
 * negative if found err.
 */
static int is_2MB_gtt_possible(struct intel_vgpu *vgpu,
	struct intel_gvt_gtt_entry *entry)
+18 −7
Original line number Diff line number Diff line
@@ -203,6 +203,22 @@ static void init_device_info(struct intel_gvt *gvt)
	info->msi_cap_offset = pdev->msi_cap;
}

static void intel_gvt_test_and_emulate_vblank(struct intel_gvt *gvt)
{
	struct intel_vgpu *vgpu;
	int id;

	mutex_lock(&gvt->lock);
	idr_for_each_entry((&(gvt)->vgpu_idr), (vgpu), (id)) {
		if (test_and_clear_bit(INTEL_GVT_REQUEST_EMULATE_VBLANK + id,
				       (void *)&gvt->service_request)) {
			if (vgpu->active)
				intel_vgpu_emulate_vblank(vgpu);
		}
	}
	mutex_unlock(&gvt->lock);
}

static int gvt_service_thread(void *data)
{
	struct intel_gvt *gvt = (struct intel_gvt *)data;
@@ -220,9 +236,7 @@ static int gvt_service_thread(void *data)
		if (WARN_ONCE(ret, "service thread is waken up by signal.\n"))
			continue;

		if (test_and_clear_bit(INTEL_GVT_REQUEST_EMULATE_VBLANK,
					(void *)&gvt->service_request))
			intel_gvt_emulate_vblank(gvt);
		intel_gvt_test_and_emulate_vblank(gvt);

		if (test_bit(INTEL_GVT_REQUEST_SCHED,
				(void *)&gvt->service_request) ||
@@ -278,7 +292,6 @@ void intel_gvt_clean_device(struct drm_i915_private *i915)
	intel_gvt_clean_sched_policy(gvt);
	intel_gvt_clean_workload_scheduler(gvt);
	intel_gvt_clean_gtt(gvt);
	intel_gvt_clean_irq(gvt);
	intel_gvt_free_firmware(gvt);
	intel_gvt_clean_mmio_info(gvt);
	idr_destroy(&gvt->vgpu_idr);
@@ -337,7 +350,7 @@ int intel_gvt_init_device(struct drm_i915_private *i915)

	ret = intel_gvt_init_gtt(gvt);
	if (ret)
		goto out_clean_irq;
		goto out_free_firmware;

	ret = intel_gvt_init_workload_scheduler(gvt);
	if (ret)
@@ -392,8 +405,6 @@ int intel_gvt_init_device(struct drm_i915_private *i915)
	intel_gvt_clean_workload_scheduler(gvt);
out_clean_gtt:
	intel_gvt_clean_gtt(gvt);
out_clean_irq:
	intel_gvt_clean_irq(gvt);
out_free_firmware:
	intel_gvt_free_firmware(gvt);
out_clean_mmio_info:
+9 −4
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ struct intel_vgpu_display {
	struct intel_vgpu_i2c_edid i2c_edid;
	struct intel_vgpu_port ports[I915_MAX_PORTS];
	struct intel_vgpu_sbi sbi;
	enum port port_num;
};

struct vgpu_sched_ctl {
@@ -214,6 +215,7 @@ struct intel_vgpu {
	struct list_head dmabuf_obj_list_head;
	struct mutex dmabuf_lock;
	struct idr object_idr;
	struct intel_vgpu_vblank_timer vblank_timer;

	u32 scan_nonprivbb;
};
@@ -346,13 +348,16 @@ static inline struct intel_gvt *to_gvt(struct drm_i915_private *i915)
}

enum {
	INTEL_GVT_REQUEST_EMULATE_VBLANK = 0,

	/* Scheduling trigger by timer */
	INTEL_GVT_REQUEST_SCHED = 1,
	INTEL_GVT_REQUEST_SCHED = 0,

	/* Scheduling trigger by event */
	INTEL_GVT_REQUEST_EVENT_SCHED = 2,
	INTEL_GVT_REQUEST_EVENT_SCHED = 1,

	/* per-vGPU vblank emulation request */
	INTEL_GVT_REQUEST_EMULATE_VBLANK = 2,
	INTEL_GVT_REQUEST_EMULATE_VBLANK_MAX = INTEL_GVT_REQUEST_EMULATE_VBLANK
		+ GVT_MAX_VGPU,
};

static inline void intel_gvt_request_service(struct intel_gvt *gvt,
Loading