Skip to content

Commit

Permalink
Merge tag 'gvt-next-2021-03-16' of https://github.com/intel/gvt-linux
Browse files Browse the repository at this point in the history
…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 <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
  • Loading branch information
Jani Nikula committed Mar 16, 2021
2 parents 41ed400 + 9317f35 commit 2b25fb3
Show file tree
Hide file tree
Showing 9 changed files with 355 additions and 115 deletions.
107 changes: 59 additions & 48 deletions drivers/gpu/drm/i915/gvt/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -544,48 +560,59 @@ 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);

return 0;
}

/**
* 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)
Expand Down Expand Up @@ -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;

Expand All @@ -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
Expand Down Expand Up @@ -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);
}

/**
Expand Down
14 changes: 12 additions & 2 deletions drivers/gpu/drm/i915/gvt/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#define _GVT_DISPLAY_H_

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

struct intel_gvt;
struct intel_vgpu;
Expand Down Expand Up @@ -157,13 +158,22 @@ 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;
/* per display DPCD information */
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)
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/i915/gvt/gtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
25 changes: 18 additions & 7 deletions drivers/gpu/drm/i915/gvt/gvt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) ||
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
13 changes: 9 additions & 4 deletions drivers/gpu/drm/i915/gvt/gvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
};
Expand Down Expand Up @@ -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,
Expand Down
Loading

0 comments on commit 2b25fb3

Please sign in to comment.