Skip to content

Commit 2b25fb3

Browse files
committed
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: Jani Nikula <[email protected]> From: Zhenyu Wang <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
2 parents 41ed400 + 9317f35 commit 2b25fb3

File tree

9 files changed

+355
-115
lines changed

9 files changed

+355
-115
lines changed

drivers/gpu/drm/i915/gvt/display.c

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -516,11 +516,27 @@ static void clean_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num)
516516
port->dpcd = NULL;
517517
}
518518

519+
static enum hrtimer_restart vblank_timer_fn(struct hrtimer *data)
520+
{
521+
struct intel_vgpu_vblank_timer *vblank_timer;
522+
struct intel_vgpu *vgpu;
523+
524+
vblank_timer = container_of(data, struct intel_vgpu_vblank_timer, timer);
525+
vgpu = container_of(vblank_timer, struct intel_vgpu, vblank_timer);
526+
527+
/* Set vblank emulation request per-vGPU bit */
528+
intel_gvt_request_service(vgpu->gvt,
529+
INTEL_GVT_REQUEST_EMULATE_VBLANK + vgpu->id);
530+
hrtimer_add_expires_ns(&vblank_timer->timer, vblank_timer->period);
531+
return HRTIMER_RESTART;
532+
}
533+
519534
static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num,
520535
int type, unsigned int resolution)
521536
{
522537
struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
523538
struct intel_vgpu_port *port = intel_vgpu_port(vgpu, port_num);
539+
struct intel_vgpu_vblank_timer *vblank_timer = &vgpu->vblank_timer;
524540

525541
if (drm_WARN_ON(&i915->drm, resolution >= GVT_EDID_NUM))
526542
return -EINVAL;
@@ -544,48 +560,59 @@ static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num,
544560
port->dpcd->data[DPCD_SINK_COUNT] = 0x1;
545561
port->type = type;
546562
port->id = resolution;
563+
port->vrefresh_k = GVT_DEFAULT_REFRESH_RATE * MSEC_PER_SEC;
564+
vgpu->display.port_num = port_num;
565+
566+
/* Init hrtimer based on default refresh rate */
567+
hrtimer_init(&vblank_timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
568+
vblank_timer->timer.function = vblank_timer_fn;
569+
vblank_timer->vrefresh_k = port->vrefresh_k;
570+
vblank_timer->period = DIV64_U64_ROUND_CLOSEST(NSEC_PER_SEC * MSEC_PER_SEC, vblank_timer->vrefresh_k);
547571

548572
emulate_monitor_status_change(vgpu);
549573

550574
return 0;
551575
}
552576

553577
/**
554-
* intel_gvt_check_vblank_emulation - check if vblank emulation timer should
555-
* be turned on/off when a virtual pipe is enabled/disabled.
556-
* @gvt: a GVT device
578+
* vgpu_update_vblank_emulation - Update per-vGPU vblank_timer
579+
* @vgpu: vGPU operated
580+
* @turnon: Turn ON/OFF vblank_timer
557581
*
558-
* This function is used to turn on/off vblank timer according to currently
559-
* enabled/disabled virtual pipes.
582+
* This function is used to turn on/off or update the per-vGPU vblank_timer
583+
* when PIPECONF is enabled or disabled. vblank_timer period is also updated
584+
* if guest changed the refresh rate.
560585
*
561586
*/
562-
void intel_gvt_check_vblank_emulation(struct intel_gvt *gvt)
587+
void vgpu_update_vblank_emulation(struct intel_vgpu *vgpu, bool turnon)
563588
{
564-
struct intel_gvt_irq *irq = &gvt->irq;
565-
struct intel_vgpu *vgpu;
566-
int pipe, id;
567-
int found = false;
568-
569-
mutex_lock(&gvt->lock);
570-
for_each_active_vgpu(gvt, vgpu, id) {
571-
for (pipe = 0; pipe < I915_MAX_PIPES; pipe++) {
572-
if (pipe_is_enabled(vgpu, pipe)) {
573-
found = true;
574-
break;
575-
}
589+
struct intel_vgpu_vblank_timer *vblank_timer = &vgpu->vblank_timer;
590+
struct intel_vgpu_port *port =
591+
intel_vgpu_port(vgpu, vgpu->display.port_num);
592+
593+
if (turnon) {
594+
/*
595+
* Skip the re-enable if already active and vrefresh unchanged.
596+
* Otherwise, stop timer if already active and restart with new
597+
* period.
598+
*/
599+
if (vblank_timer->vrefresh_k != port->vrefresh_k ||
600+
!hrtimer_active(&vblank_timer->timer)) {
601+
/* Stop timer before start with new period if active */
602+
if (hrtimer_active(&vblank_timer->timer))
603+
hrtimer_cancel(&vblank_timer->timer);
604+
605+
/* Make sure new refresh rate updated to timer period */
606+
vblank_timer->vrefresh_k = port->vrefresh_k;
607+
vblank_timer->period = DIV64_U64_ROUND_CLOSEST(NSEC_PER_SEC * MSEC_PER_SEC, vblank_timer->vrefresh_k);
608+
hrtimer_start(&vblank_timer->timer,
609+
ktime_add_ns(ktime_get(), vblank_timer->period),
610+
HRTIMER_MODE_ABS);
576611
}
577-
if (found)
578-
break;
612+
} else {
613+
/* Caller request to stop vblank */
614+
hrtimer_cancel(&vblank_timer->timer);
579615
}
580-
581-
/* all the pipes are disabled */
582-
if (!found)
583-
hrtimer_cancel(&irq->vblank_timer.timer);
584-
else
585-
hrtimer_start(&irq->vblank_timer.timer,
586-
ktime_add_ns(ktime_get(), irq->vblank_timer.period),
587-
HRTIMER_MODE_ABS);
588-
mutex_unlock(&gvt->lock);
589616
}
590617

591618
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)
617644
}
618645
}
619646

620-
static void emulate_vblank(struct intel_vgpu *vgpu)
647+
void intel_vgpu_emulate_vblank(struct intel_vgpu *vgpu)
621648
{
622649
int pipe;
623650

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

630-
/**
631-
* intel_gvt_emulate_vblank - trigger vblank events for vGPUs on GVT device
632-
* @gvt: a GVT device
633-
*
634-
* This function is used to trigger vblank interrupts for vGPUs on GVT device
635-
*
636-
*/
637-
void intel_gvt_emulate_vblank(struct intel_gvt *gvt)
638-
{
639-
struct intel_vgpu *vgpu;
640-
int id;
641-
642-
mutex_lock(&gvt->lock);
643-
for_each_active_vgpu(gvt, vgpu, id)
644-
emulate_vblank(vgpu);
645-
mutex_unlock(&gvt->lock);
646-
}
647-
648657
/**
649658
* intel_vgpu_emulate_hotplug - trigger hotplug event for vGPU
650659
* @vgpu: a vGPU
@@ -753,6 +762,8 @@ void intel_vgpu_clean_display(struct intel_vgpu *vgpu)
753762
clean_virtual_dp_monitor(vgpu, PORT_D);
754763
else
755764
clean_virtual_dp_monitor(vgpu, PORT_B);
765+
766+
vgpu_update_vblank_emulation(vgpu, false);
756767
}
757768

758769
/**

drivers/gpu/drm/i915/gvt/display.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#define _GVT_DISPLAY_H_
3737

3838
#include <linux/types.h>
39+
#include <linux/hrtimer.h>
3940

4041
struct intel_gvt;
4142
struct intel_vgpu;
@@ -157,13 +158,22 @@ enum intel_vgpu_edid {
157158
GVT_EDID_NUM,
158159
};
159160

161+
#define GVT_DEFAULT_REFRESH_RATE 60
160162
struct intel_vgpu_port {
161163
/* per display EDID information */
162164
struct intel_vgpu_edid_data *edid;
163165
/* per display DPCD information */
164166
struct intel_vgpu_dpcd_data *dpcd;
165167
int type;
166168
enum intel_vgpu_edid id;
169+
/* x1000 to get accurate 59.94, 24.976, 29.94, etc. in timing std. */
170+
u32 vrefresh_k;
171+
};
172+
173+
struct intel_vgpu_vblank_timer {
174+
struct hrtimer timer;
175+
u32 vrefresh_k;
176+
u64 period;
167177
};
168178

169179
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)
202212
}
203213
}
204214

205-
void intel_gvt_emulate_vblank(struct intel_gvt *gvt);
206-
void intel_gvt_check_vblank_emulation(struct intel_gvt *gvt);
215+
void intel_vgpu_emulate_vblank(struct intel_vgpu *vgpu);
216+
void vgpu_update_vblank_emulation(struct intel_vgpu *vgpu, bool turnon);
207217

208218
int intel_vgpu_init_display(struct intel_vgpu *vgpu, u64 resolution);
209219
void intel_vgpu_reset_display(struct intel_vgpu *vgpu);

drivers/gpu/drm/i915/gvt/gtt.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,8 +1159,8 @@ static inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se,
11591159
* @vgpu: target vgpu
11601160
* @entry: target pfn's gtt entry
11611161
*
1162-
* Return 1 if 2MB huge gtt shadowing is possilbe, 0 if miscondition,
1163-
* negtive if found err.
1162+
* Return 1 if 2MB huge gtt shadowing is possible, 0 if miscondition,
1163+
* negative if found err.
11641164
*/
11651165
static int is_2MB_gtt_possible(struct intel_vgpu *vgpu,
11661166
struct intel_gvt_gtt_entry *entry)

drivers/gpu/drm/i915/gvt/gvt.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,22 @@ static void init_device_info(struct intel_gvt *gvt)
203203
info->msi_cap_offset = pdev->msi_cap;
204204
}
205205

206+
static void intel_gvt_test_and_emulate_vblank(struct intel_gvt *gvt)
207+
{
208+
struct intel_vgpu *vgpu;
209+
int id;
210+
211+
mutex_lock(&gvt->lock);
212+
idr_for_each_entry((&(gvt)->vgpu_idr), (vgpu), (id)) {
213+
if (test_and_clear_bit(INTEL_GVT_REQUEST_EMULATE_VBLANK + id,
214+
(void *)&gvt->service_request)) {
215+
if (vgpu->active)
216+
intel_vgpu_emulate_vblank(vgpu);
217+
}
218+
}
219+
mutex_unlock(&gvt->lock);
220+
}
221+
206222
static int gvt_service_thread(void *data)
207223
{
208224
struct intel_gvt *gvt = (struct intel_gvt *)data;
@@ -220,9 +236,7 @@ static int gvt_service_thread(void *data)
220236
if (WARN_ONCE(ret, "service thread is waken up by signal.\n"))
221237
continue;
222238

223-
if (test_and_clear_bit(INTEL_GVT_REQUEST_EMULATE_VBLANK,
224-
(void *)&gvt->service_request))
225-
intel_gvt_emulate_vblank(gvt);
239+
intel_gvt_test_and_emulate_vblank(gvt);
226240

227241
if (test_bit(INTEL_GVT_REQUEST_SCHED,
228242
(void *)&gvt->service_request) ||
@@ -278,7 +292,6 @@ void intel_gvt_clean_device(struct drm_i915_private *i915)
278292
intel_gvt_clean_sched_policy(gvt);
279293
intel_gvt_clean_workload_scheduler(gvt);
280294
intel_gvt_clean_gtt(gvt);
281-
intel_gvt_clean_irq(gvt);
282295
intel_gvt_free_firmware(gvt);
283296
intel_gvt_clean_mmio_info(gvt);
284297
idr_destroy(&gvt->vgpu_idr);
@@ -337,7 +350,7 @@ int intel_gvt_init_device(struct drm_i915_private *i915)
337350

338351
ret = intel_gvt_init_gtt(gvt);
339352
if (ret)
340-
goto out_clean_irq;
353+
goto out_free_firmware;
341354

342355
ret = intel_gvt_init_workload_scheduler(gvt);
343356
if (ret)
@@ -392,8 +405,6 @@ int intel_gvt_init_device(struct drm_i915_private *i915)
392405
intel_gvt_clean_workload_scheduler(gvt);
393406
out_clean_gtt:
394407
intel_gvt_clean_gtt(gvt);
395-
out_clean_irq:
396-
intel_gvt_clean_irq(gvt);
397408
out_free_firmware:
398409
intel_gvt_free_firmware(gvt);
399410
out_clean_mmio_info:

drivers/gpu/drm/i915/gvt/gvt.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ struct intel_vgpu_display {
133133
struct intel_vgpu_i2c_edid i2c_edid;
134134
struct intel_vgpu_port ports[I915_MAX_PORTS];
135135
struct intel_vgpu_sbi sbi;
136+
enum port port_num;
136137
};
137138

138139
struct vgpu_sched_ctl {
@@ -214,6 +215,7 @@ struct intel_vgpu {
214215
struct list_head dmabuf_obj_list_head;
215216
struct mutex dmabuf_lock;
216217
struct idr object_idr;
218+
struct intel_vgpu_vblank_timer vblank_timer;
217219

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

348350
enum {
349-
INTEL_GVT_REQUEST_EMULATE_VBLANK = 0,
350-
351351
/* Scheduling trigger by timer */
352-
INTEL_GVT_REQUEST_SCHED = 1,
352+
INTEL_GVT_REQUEST_SCHED = 0,
353353

354354
/* Scheduling trigger by event */
355-
INTEL_GVT_REQUEST_EVENT_SCHED = 2,
355+
INTEL_GVT_REQUEST_EVENT_SCHED = 1,
356+
357+
/* per-vGPU vblank emulation request */
358+
INTEL_GVT_REQUEST_EMULATE_VBLANK = 2,
359+
INTEL_GVT_REQUEST_EMULATE_VBLANK_MAX = INTEL_GVT_REQUEST_EMULATE_VBLANK
360+
+ GVT_MAX_VGPU,
356361
};
357362

358363
static inline void intel_gvt_request_service(struct intel_gvt *gvt,

0 commit comments

Comments
 (0)