diff options
Diffstat (limited to 'drivers/gpu/drm/i915/gvt/display.c')
| -rw-r--r-- | drivers/gpu/drm/i915/gvt/display.c | 107 | 
1 files changed, 59 insertions, 48 deletions
| diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index 62a5b0dd2003..034c060f89d4 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -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; - -	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; -			} +	struct intel_vgpu_vblank_timer *vblank_timer = &vgpu->vblank_timer; +	struct intel_vgpu_port *port = +		intel_vgpu_port(vgpu, vgpu->display.port_num); + +	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; @@ -628,24 +655,6 @@ static void emulate_vblank(struct intel_vgpu *vgpu)  }  /** - * 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   * @connected: link state @@ -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);  }  /** | 
