40 changes: 39 additions & 1 deletion drivers/gpu/drm/i915/gvt/cmd_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ static bool is_shadowed_mmio(unsigned int offset)
return ret;
}

static inline bool is_force_nonpriv_mmio(unsigned int offset)
bool is_force_nonpriv_mmio(unsigned int offset)
{
return (offset >= 0x24d0 && offset < 0x2500);
}
Expand Down Expand Up @@ -917,6 +917,15 @@ static int cmd_reg_handler(struct parser_exec_state *s,
}
}

/* Re-direct the non-context MMIO access to VGT_SCRATCH_REG, it
* has no functional impact to HW.
*/
if (!strcmp(cmd, "lri") || !strcmp(cmd, "lrr-dst")
|| !strcmp(cmd, "lrm") || !strcmp(cmd, "pipe_ctrl")) {
if (intel_gvt_mmio_is_non_context(gvt, offset))
patch_value(s, cmd_ptr(s, index), VGT_SCRATCH_REG);
}

/* TODO: Update the global mask if this MMIO is a masked-MMIO */
intel_gvt_mmio_set_cmd_accessed(gvt, offset);
return 0;
Expand Down Expand Up @@ -956,6 +965,35 @@ static int cmd_handler_lri(struct parser_exec_state *s)
ret |= cmd_reg_handler(s, cmd_reg(s, i), i, "lri");
if (ret)
break;

if (s->vgpu->entire_nonctxmmio_checked
&& intel_gvt_mmio_is_non_context(s->vgpu->gvt,
cmd_reg(s, i))) {
int offset = cmd_reg(s, i);
int value = cmd_val(s, i + 1);
u32 *host_cache = s->vgpu->gvt->mmio.mmio_host_cache;

if (intel_gvt_mmio_has_mode_mask(s->vgpu->gvt, offset)) {
u32 mask = value >> 16;

vgpu_vreg(s->vgpu, offset) =
(vgpu_vreg(s->vgpu, offset) & ~mask)
| (value & mask);
} else {
vgpu_vreg(s->vgpu, offset) = value;
}

if (host_cache[cmd_reg(s, i) >> 2] !=
vgpu_vreg(s->vgpu, offset)) {

gvt_err("vgpu%d unexpected non-context MMIOs"
"access by cmd 0x%x:0x%x,0x%x\n",
s->vgpu->id,
(u32)cmd_reg(s, i),
cmd_val(s, i + 1),
host_cache[cmd_reg(s, i) >> 2]);
}
}
}
return ret;
}
Expand Down
39 changes: 36 additions & 3 deletions drivers/gpu/drm/i915/gvt/gvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ struct intel_vgpu {
struct completion vblank_done;

u32 scan_nonprivbb;

bool entire_nonctxmmio_checked;
};

/* validating GM healthy status*/
Expand Down Expand Up @@ -253,7 +255,7 @@ struct gvt_mmio_block {
#define INTEL_GVT_MMIO_HASH_BITS 11

struct intel_gvt_mmio {
u8 *mmio_attribute;
u16 *mmio_attribute;
/* Register contains RO bits */
#define F_RO (1 << 0)
/* Register contains graphics address */
Expand All @@ -270,10 +272,14 @@ struct intel_gvt_mmio {
#define F_UNALIGN (1 << 6)
/* This reg is saved/restored in context */
#define F_IN_CTX (1 << 7)
/* This reg is not in the context */
#define F_NON_CONTEXT (1 << 8)

struct gvt_mmio_block *mmio_block;
unsigned int num_mmio_block;

void *mmio_host_cache;
bool host_cache_initialized;
DECLARE_HASHTABLE(mmio_info_table, INTEL_GVT_MMIO_HASH_BITS);
unsigned long num_tracked_mmio;
};
Expand Down Expand Up @@ -651,7 +657,7 @@ static inline bool intel_gvt_mmio_has_mode_mask(
*
*/
static inline bool intel_gvt_mmio_is_in_ctx(
struct intel_gvt *gvt, unsigned int offset)
struct intel_gvt *gvt, unsigned int offset)
{
return gvt->mmio.mmio_attribute[offset >> 2] & F_IN_CTX;
}
Expand All @@ -663,17 +669,44 @@ static inline bool intel_gvt_mmio_is_in_ctx(
*
*/
static inline void intel_gvt_mmio_set_in_ctx(
struct intel_gvt *gvt, unsigned int offset)
struct intel_gvt *gvt, unsigned int offset)
{
gvt->mmio.mmio_attribute[offset >> 2] |= F_IN_CTX;
}

/**
* intel_gvt_mmio_is_non_context - check a MMIO is non-context
* @gvt: a GVT device
* @offset: register offset
*
*/
static inline bool intel_gvt_mmio_is_non_context(
struct intel_gvt *gvt, unsigned int offset)
{
return gvt->mmio.mmio_attribute[offset >> 2] & F_NON_CONTEXT;
}

/**
* intel_gvt_mmio_set_non_context - mark a MMIO is non-context
* @gvt: a GVT device
* @offset: register offset
*
*/
static inline void intel_gvt_mmio_set_non_context(
struct intel_gvt *gvt, unsigned int offset)
{
gvt->mmio.mmio_attribute[offset >> 2] |= F_NON_CONTEXT;
}

int intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu);
void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu);
int intel_gvt_debugfs_init(struct intel_gvt *gvt);
void intel_gvt_debugfs_clean(struct intel_gvt *gvt);


bool is_force_nonpriv_mmio(unsigned int offset);

#include "trace.h"
#include "mpt.h"

Expand Down
9 changes: 9 additions & 0 deletions drivers/gpu/drm/i915/gvt/handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -2915,6 +2915,9 @@ void intel_gvt_clean_mmio_info(struct intel_gvt *gvt)

vfree(gvt->mmio.mmio_attribute);
gvt->mmio.mmio_attribute = NULL;

vfree(gvt->mmio.mmio_host_cache);
gvt->mmio.mmio_host_cache = NULL;
}

/* Special MMIO blocks. */
Expand Down Expand Up @@ -2949,6 +2952,12 @@ int intel_gvt_setup_mmio_info(struct intel_gvt *gvt)
if (!gvt->mmio.mmio_attribute)
return -ENOMEM;

gvt->mmio.mmio_host_cache = vzalloc(info->mmio_size);
if (!gvt->mmio.mmio_host_cache) {
vfree(gvt->mmio.mmio_attribute);
return -ENOMEM;
}

ret = init_generic_mmio_info(gvt);
if (ret)
goto err;
Expand Down
11 changes: 11 additions & 0 deletions drivers/gpu/drm/i915/gvt/mmio.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,15 @@ int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, uint64_t pa,
if (ret < 0)
goto err;

if (vgpu->entire_nonctxmmio_checked
&& intel_gvt_mmio_is_non_context(vgpu->gvt, offset)
&& vgpu_vreg(vgpu, offset)
!= *(u32 *)(vgpu->gvt->mmio.mmio_host_cache + offset)) {
gvt_err("vgpu%d unexpected non-context MMIO change at 0x%x:0x%x,0x%x\n",
vgpu->id, offset, vgpu_vreg(vgpu, offset),
*(u32 *)(vgpu->gvt->mmio.mmio_host_cache + offset));
}

intel_gvt_mmio_set_accessed(gvt, offset);
ret = 0;
goto out;
Expand Down Expand Up @@ -254,6 +263,8 @@ void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu, bool dmlr)
memcpy(vgpu->mmio.sreg, mmio, GVT_GEN8_MMIO_RESET_OFFSET);
}

/* Non-context MMIOs need entire check again if mmio/vgpu reset */
vgpu->entire_nonctxmmio_checked = false;
}

/**
Expand Down
88 changes: 87 additions & 1 deletion drivers/gpu/drm/i915/gvt/mmio_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,89 @@ void intel_gvt_switch_mmio(struct intel_vgpu *pre,
intel_runtime_pm_put(dev_priv);
}

#define gvt_host_reg(gvt, reg) \
(*(u32 *)(gvt->mmio.mmio_host_cache + reg)) \

#define MMIO_COMPARE(vgpu, reg, mask) ({ \
int ret; \
u32 value = vgpu_vreg(vgpu, reg); \
u32 host_value = gvt_host_reg(vgpu->gvt, reg); \
\
if (mask) { \
value &= mask; \
host_value &= mask; \
} \
if (host_value == value) { \
ret = 0; \
} else { \
gvt_err("vgpu%d unconformance mmio 0x%x:0x%x,0x%x\n", \
vgpu->id, reg, \
vgpu_vreg(vgpu, reg), \
gvt_host_reg(vgpu->gvt, reg)); \
ret = -EINVAL; \
} \
ret; \
})

static int noncontext_mmio_compare(struct intel_vgpu *vgpu, int ring_id)
{
struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
struct engine_mmio *mmio, *mmio_list;
struct intel_engine_cs *engine = dev_priv->engine[ring_id];

mmio_list = vgpu->gvt->engine_mmio_list.mmio;

for (mmio = mmio_list; i915_mmio_reg_valid(mmio->reg); mmio++) {
if (mmio->ring_id != ring_id || mmio->in_context
|| is_force_nonpriv_mmio(mmio->reg.reg)
|| mmio->reg.reg == RING_MODE_GEN7(engine).reg)
continue;

if (MMIO_COMPARE(vgpu, mmio->reg.reg, mmio->mask))
return -EINVAL;
}

return 0;
}

static void get_host_mmio_snapshot(struct intel_gvt *gvt)
{
struct drm_i915_private *dev_priv = gvt->dev_priv;
struct engine_mmio *mmio, *mmio_list;

mmio_list = gvt->engine_mmio_list.mmio;

if (!gvt->mmio.host_cache_initialized) {
/* Snapshot all the non-context MMIOs */
for (mmio = mmio_list; i915_mmio_reg_valid(mmio->reg); mmio++) {
if (mmio->in_context)
continue;

gvt_host_reg(gvt, mmio->reg.reg) =
I915_READ_FW(mmio->reg);
if (mmio->mask)
gvt_host_reg(gvt, mmio->reg.reg) &= mmio->mask;
}
gvt->mmio.host_cache_initialized = true;
}
}

int intel_gvt_vgpu_conformance_check(struct intel_vgpu *vgpu, int ring_id)
{
int ret;

get_host_mmio_snapshot(vgpu->gvt);

ret = noncontext_mmio_compare(vgpu, ring_id);
if (ret)
goto err;

return 0;
err:
return ret;
}


/**
* intel_gvt_init_engine_mmio_context - Initiate the engine mmio list
* @gvt: GVT device
Expand All @@ -574,7 +657,8 @@ void intel_gvt_init_engine_mmio_context(struct intel_gvt *gvt)
{
struct engine_mmio *mmio;

if (IS_SKYLAKE(gvt->dev_priv) || IS_KABYLAKE(gvt->dev_priv))
if (IS_SKYLAKE(gvt->dev_priv) || IS_KABYLAKE(gvt->dev_priv)
||IS_BROXTON(gvt->dev_priv))
gvt->engine_mmio_list.mmio = gen9_engine_mmio_list;
else
gvt->engine_mmio_list.mmio = gen8_engine_mmio_list;
Expand All @@ -584,6 +668,8 @@ void intel_gvt_init_engine_mmio_context(struct intel_gvt *gvt)
if (mmio->in_context) {
gvt->engine_mmio_list.ctx_mmio_count[mmio->ring_id]++;
intel_gvt_mmio_set_in_ctx(gvt, mmio->reg.reg);
}else {
intel_gvt_mmio_set_non_context(gvt, mmio->reg.reg);
}
}
}
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/gvt/mmio_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ bool is_inhibit_context(struct i915_gem_context *ctx, int ring_id);
int intel_vgpu_restore_inhibit_context(struct intel_vgpu *vgpu,
struct i915_request *req);

int intel_gvt_vgpu_conformance_check(struct intel_vgpu *vgpu, int ring_id);
#endif
5 changes: 5 additions & 0 deletions drivers/gpu/drm/i915/gvt/scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,11 @@ static int dispatch_workload(struct intel_vgpu_workload *workload)
mutex_lock(&dev_priv->drm.struct_mutex);

ret = intel_gvt_scan_and_shadow_workload(workload);

if (i915_modparams.enable_conformance_check
&& intel_gvt_vgpu_conformance_check(vgpu, ring_id))
gvt_err("vgpu%d unconformance guest detected\n", vgpu->id);

if (ret)
goto out;

Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/i915/i915_params.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ i915_param_named(enable_dpcd_backlight, bool, 0600,
i915_param_named(enable_gvt, bool, 0400,
"Enable support for Intel GVT-g graphics virtualization host support(default:false)");

i915_param_named(enable_conformance_check, bool, 0400,
"To toggle the GVT guest conformance feature(default:true)");

static __always_inline void _print_param(struct drm_printer *p,
const char *name,
const char *type,
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/i915/i915_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ struct drm_printer;
param(bool, nuclear_pageflip, false) \
param(bool, enable_dp_mst, true) \
param(bool, enable_dpcd_backlight, false) \
param(bool, enable_gvt, false)
param(bool, enable_gvt, false) \
param(bool, enable_conformance_check, true)

#define MEMBER(T, member, ...) T member;
struct i915_params {
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/i915/i915_pvinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
#define VGT_PVINFO_PAGE 0x78000
#define VGT_PVINFO_SIZE 0x1000

/* Scratch reg used for redirecting command access to registers, any
* command access to PVINFO page would be discarded, so it has no HW
* impact.
*/
#define VGT_SCRATCH_REG VGT_PVINFO_PAGE

/*
* The following structure pages are defined in GEN MMIO space
* for virtualization. (One page for now)
Expand Down