mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'drm-intel-next-2017-11-17-1' of git://anongit.freedesktop.org/drm/drm-intel into drm-next
More change sets for 4.16: - Many improvements for selftests and other igt tests (Chris) - Forcewake with PUNIT->PMIC bus fixes and robustness (Hans) - Define an engine class for uABI (Tvrtko) - Context switch fixes and improvements (Chris) - GT powersavings and power gating simplification and fixes (Chris) - Other general driver clean-ups (Chris, Lucas, Ville) - Removing old, useless and/or bad workarounds (Chris, Oscar, Radhakrishna) - IPS, pipe config, etc in preparation for another Fast Boot attempt (Maarten) - OA perf fixes and support to Coffee Lake and Cannonlake (Lionel) - Fixes around GPU fault registers (Michel) - GEM Proxy (Tina) - Refactor of Geminilake and Cannonlake plane color handling (James) - Generalize transcoder loop (Mika Kahola) - New HW Workaround for Cannonlake and Geminilake (Rodrigo) - Resume GuC before using GEM (Chris) - Stolen Memory handling improvements (Ville) - Initialize entry in PPAT for older compilers (Chris) - Other fixes and robustness improvements on execbuf (Chris) - Improve logs of GEM_BUG_ON (Mika Kuoppala) - Rework with massive rename of GuC functions and files (Sagar) - Don't sanitize frame start delay if pipe is off (Ville) - Cannonlake clock fixes (Rodrigo) - Cannonlake HDMI 2.0 support (Rodrigo) - Add a GuC doorbells selftest (Michel) - Add might_sleep() check to our wait_for() (Chris) Many GVT changes for 4.16: - CSB HWSP update support (Weinan) - GVT debug helpers, dyndbg and debugfs (Chuanxiao, Shuo) - full virtualized opregion (Xiaolin) - VM health check for sane fallback (Fred) - workload submission code refactor for future enabling (Zhi) - Updated repo URL in MAINTAINERS (Zhenyu) - other many misc fixes * tag 'drm-intel-next-2017-11-17-1' of git://anongit.freedesktop.org/drm/drm-intel: (260 commits) drm/i915: Update DRIVER_DATE to 20171117 drm/i915: Add a policy note for removing workarounds drm/i915/selftests: Report ENOMEM clearly for an allocation failure Revert "drm/i915: Display WA #1133 WaFbcSkipSegments:cnl, glk" drm/i915: Calculate g4x intermediate watermarks correctly drm/i915: Calculate vlv/chv intermediate watermarks correctly, v3. drm/i915: Pass crtc_state to ips toggle functions, v2 drm/i915: Pass idle crtc_state to intel_dp_sink_crc drm/i915: Enable FIFO underrun reporting after initial fastset, v4. drm/i915: Mark the userptr invalidate workqueue as WQ_MEM_RECLAIM drm/i915: Add might_sleep() check to wait_for() drm/i915/selftests: Add a GuC doorbells selftest drm/i915/cnl: Extend HDMI 2.0 support to CNL. drm/i915/cnl: Simplify dco_fraction calculation. drm/i915/cnl: Don't blindly replace qdiv. drm/i915/cnl: Fix wrpll math for higher freqs. drm/i915/cnl: Fix, simplify and unify wrpll variable sizes. drm/i915/cnl: Remove useless conversion. drm/i915/cnl: Remove spurious central_freq. drm/i915/selftests: exercise_ggtt may have nothing to do ...
This commit is contained in:
commit
ca797d29cd
129 files changed
+6554
-3182
No files matched your search
@@ -350,10 +350,10 @@ GuC-specific firmware loader
|
||||
GuC-based command submission
|
||||
----------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/i915_guc_submission.c
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_guc_submission.c
|
||||
:doc: GuC-based command submission
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/i915_guc_submission.c
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/intel_guc_submission.c
|
||||
:internal:
|
||||
|
||||
GuC Firmware Layout
|
||||
|
||||
+1
-1
@@ -7030,7 +7030,7 @@ M: Zhi Wang <zhi.a.wang@intel.com>
|
||||
L: intel-gvt-dev@lists.freedesktop.org
|
||||
L: intel-gfx@lists.freedesktop.org
|
||||
W: https://01.org/igvt-g
|
||||
T: git https://github.com/01org/gvt-linux.git
|
||||
T: git https://github.com/intel/gvt-linux.git
|
||||
S: Supported
|
||||
F: drivers/gpu/drm/i915/gvt/
|
||||
|
||||
|
||||
@@ -146,6 +146,18 @@ int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb);
|
||||
*/
|
||||
int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb);
|
||||
|
||||
/**
|
||||
* iosf_mbi_unregister_pmic_bus_access_notifier_unlocked - Unregister PMIC bus
|
||||
* notifier, unlocked
|
||||
*
|
||||
* Like iosf_mbi_unregister_pmic_bus_access_notifier(), but for use when the
|
||||
* caller has already called iosf_mbi_punit_acquire() itself.
|
||||
*
|
||||
* @nb: notifier_block to unregister
|
||||
*/
|
||||
int iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
|
||||
struct notifier_block *nb);
|
||||
|
||||
/**
|
||||
* iosf_mbi_call_pmic_bus_access_notifier_chain - Call PMIC bus notifier chain
|
||||
*
|
||||
@@ -154,6 +166,11 @@ int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb);
|
||||
*/
|
||||
int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v);
|
||||
|
||||
/**
|
||||
* iosf_mbi_assert_punit_acquired - Assert that the P-Unit has been acquired.
|
||||
*/
|
||||
void iosf_mbi_assert_punit_acquired(void);
|
||||
|
||||
#else /* CONFIG_IOSF_MBI is not enabled */
|
||||
static inline
|
||||
bool iosf_mbi_available(void)
|
||||
@@ -197,12 +214,20 @@ int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void iosf_mbi_assert_punit_acquired(void) {}
|
||||
|
||||
#endif /* CONFIG_IOSF_MBI */
|
||||
|
||||
#endif /* IOSF_MBI_SYMS_H */
|
||||
@@ -218,14 +218,23 @@ int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb)
|
||||
}
|
||||
EXPORT_SYMBOL(iosf_mbi_register_pmic_bus_access_notifier);
|
||||
|
||||
int iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
iosf_mbi_assert_punit_acquired();
|
||||
|
||||
return blocking_notifier_chain_unregister(
|
||||
&iosf_mbi_pmic_bus_access_notifier, nb);
|
||||
}
|
||||
EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier_unlocked);
|
||||
|
||||
int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Wait for the bus to go inactive before unregistering */
|
||||
mutex_lock(&iosf_mbi_punit_mutex);
|
||||
ret = blocking_notifier_chain_unregister(
|
||||
&iosf_mbi_pmic_bus_access_notifier, nb);
|
||||
ret = iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(nb);
|
||||
mutex_unlock(&iosf_mbi_punit_mutex);
|
||||
|
||||
return ret;
|
||||
@@ -239,6 +248,12 @@ int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v)
|
||||
}
|
||||
EXPORT_SYMBOL(iosf_mbi_call_pmic_bus_access_notifier_chain);
|
||||
|
||||
void iosf_mbi_assert_punit_acquired(void)
|
||||
{
|
||||
WARN_ON(!mutex_is_locked(&iosf_mbi_punit_mutex));
|
||||
}
|
||||
EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired);
|
||||
|
||||
#ifdef CONFIG_IOSF_MBI_DEBUG
|
||||
static u32 dbg_mdr;
|
||||
static u32 dbg_mcr;
|
||||
|
||||
@@ -28,6 +28,7 @@ config DRM_I915_DEBUG
|
||||
select SW_SYNC # signaling validation framework (igt/syncobj*)
|
||||
select DRM_I915_SW_FENCE_DEBUG_OBJECTS
|
||||
select DRM_I915_SELFTEST
|
||||
select DRM_I915_TRACE_GEM
|
||||
default n
|
||||
help
|
||||
Choose this option to turn on extra driver debugging that may affect
|
||||
@@ -49,6 +50,19 @@ config DRM_I915_DEBUG_GEM
|
||||
|
||||
If in doubt, say "N".
|
||||
|
||||
config DRM_I915_TRACE_GEM
|
||||
bool "Insert extra ftrace output from the GEM internals"
|
||||
select TRACING
|
||||
default n
|
||||
help
|
||||
Enable additional and verbose debugging output that will spam
|
||||
ordinary tests, but may be vital for post-mortem debugging when
|
||||
used with /proc/sys/kernel/ftrace_dump_on_oops
|
||||
|
||||
Recommended for driver developers only.
|
||||
|
||||
If in doubt, say "N".
|
||||
|
||||
config DRM_I915_SW_FENCE_DEBUG_OBJECTS
|
||||
bool "Enable additional driver debugging for fence objects"
|
||||
depends on DRM_I915
|
||||
@@ -90,6 +104,20 @@ config DRM_I915_SELFTEST
|
||||
|
||||
If in doubt, say "N".
|
||||
|
||||
config DRM_I915_SELFTEST_BROKEN
|
||||
bool "Enable broken and dangerous selftests"
|
||||
depends on DRM_I915_SELFTEST
|
||||
depends on BROKEN
|
||||
default n
|
||||
help
|
||||
This option enables the execution of selftests that are "dangerous"
|
||||
and may trigger unintended HW side-effects as they break strict
|
||||
rules given in the HW specification. For science.
|
||||
|
||||
Recommended for masochistic driver developers only.
|
||||
|
||||
If in doubt, say "N".
|
||||
|
||||
config DRM_I915_LOW_LEVEL_TRACEPOINTS
|
||||
bool "Enable low level request tracing events"
|
||||
depends on DRM_I915
|
||||
|
||||
@@ -3,7 +3,26 @@
|
||||
# Makefile for the drm device driver. This driver provides support for the
|
||||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||
|
||||
subdir-ccflags-$(CONFIG_DRM_I915_WERROR) := -Werror
|
||||
# Add a set of useful warning flags and enable -Werror for CI to prevent
|
||||
# trivial mistakes from creeping in. We have to do this piecemeal as we reject
|
||||
# any patch that isn't warning clean, so turning on -Wall -Wextra (or W=1) we
|
||||
# need to filter out dubious warnings. Still it is our interest
|
||||
# to keep running locally with W=1 C=1 until we are completely clean.
|
||||
#
|
||||
# Note the danger in using -Wall -Wextra is that when CI updates gcc we
|
||||
# will most likely get a sudden build breakage... Hopefully we will fix
|
||||
# new warnings before CI updates!
|
||||
subdir-ccflags-y := -Wall -Wextra
|
||||
subdir-ccflags-y += $(call cc-disable-warning, unused-parameter)
|
||||
subdir-ccflags-y += $(call cc-disable-warning, type-limits)
|
||||
subdir-ccflags-y += $(call cc-disable-warning, missing-field-initializers)
|
||||
subdir-ccflags-y += $(call cc-disable-warning, implicit-fallthrough)
|
||||
subdir-ccflags-$(CONFIG_DRM_I915_WERROR) += -Werror
|
||||
|
||||
# Fine grained warnings disable
|
||||
CFLAGS_i915_pci.o = $(call cc-disable-warning, override-init)
|
||||
CFLAGS_intel_fbdev.o = $(call cc-disable-warning, override-init)
|
||||
|
||||
subdir-ccflags-y += \
|
||||
$(call as-instr,movntdqa (%eax)$(comma)%xmm0,-DCONFIG_AS_MOVNTDQA)
|
||||
|
||||
@@ -64,10 +83,10 @@ i915-y += intel_uc.o \
|
||||
intel_uc_fw.o \
|
||||
intel_guc.o \
|
||||
intel_guc_ct.o \
|
||||
intel_guc_log.o \
|
||||
intel_guc_fw.o \
|
||||
intel_huc.o \
|
||||
i915_guc_submission.o
|
||||
intel_guc_log.o \
|
||||
intel_guc_submission.o \
|
||||
intel_huc.o
|
||||
|
||||
# autogenerated null render state
|
||||
i915-y += intel_renderstate_gen6.o \
|
||||
@@ -144,7 +163,9 @@ i915-y += i915_perf.o \
|
||||
i915_oa_kblgt2.o \
|
||||
i915_oa_kblgt3.o \
|
||||
i915_oa_glk.o \
|
||||
i915_oa_cflgt2.o
|
||||
i915_oa_cflgt2.o \
|
||||
i915_oa_cflgt3.o \
|
||||
i915_oa_cnl.o
|
||||
|
||||
ifeq ($(CONFIG_DRM_I915_GVT),y)
|
||||
i915-y += intel_gvt.o
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
GVT_DIR := gvt
|
||||
GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o trace_points.o firmware.o \
|
||||
interrupt.o gtt.o cfg_space.o opregion.o mmio.o display.o edid.o \
|
||||
execlist.o scheduler.o sched_policy.o render.o cmd_parser.o
|
||||
execlist.o scheduler.o sched_policy.o render.o cmd_parser.o debugfs.o
|
||||
|
||||
ccflags-y += -I$(src) -I$(src)/$(GVT_DIR)
|
||||
i915-y += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE))
|
||||
|
||||
@@ -208,6 +208,20 @@ static int emulate_pci_command_write(struct intel_vgpu *vgpu,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emulate_pci_rom_bar_write(struct intel_vgpu *vgpu,
|
||||
unsigned int offset, void *p_data, unsigned int bytes)
|
||||
{
|
||||
u32 *pval = (u32 *)(vgpu_cfg_space(vgpu) + offset);
|
||||
u32 new = *(u32 *)(p_data);
|
||||
|
||||
if ((new & PCI_ROM_ADDRESS_MASK) == PCI_ROM_ADDRESS_MASK)
|
||||
/* We don't have rom, return size of 0. */
|
||||
*pval = 0;
|
||||
else
|
||||
vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
void *p_data, unsigned int bytes)
|
||||
{
|
||||
@@ -300,6 +314,11 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
}
|
||||
|
||||
switch (rounddown(offset, 4)) {
|
||||
case PCI_ROM_ADDRESS:
|
||||
if (WARN_ON(!IS_ALIGNED(offset, 4)))
|
||||
return -EINVAL;
|
||||
return emulate_pci_rom_bar_write(vgpu, offset, p_data, bytes);
|
||||
|
||||
case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5:
|
||||
if (WARN_ON(!IS_ALIGNED(offset, 4)))
|
||||
return -EINVAL;
|
||||
@@ -375,6 +394,8 @@ void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
|
||||
pci_resource_len(gvt->dev_priv->drm.pdev, 0);
|
||||
vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].size =
|
||||
pci_resource_len(gvt->dev_priv->drm.pdev, 2);
|
||||
|
||||
memset(vgpu_cfg_space(vgpu) + PCI_ROM_ADDRESS, 0, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -709,18 +709,13 @@ static void parser_exec_state_dump(struct parser_exec_state *s)
|
||||
|
||||
print_opcode(cmd_val(s, 0), s->ring_id);
|
||||
|
||||
/* print the whole page to trace */
|
||||
pr_err(" ip_va=%p: %08x %08x %08x %08x\n",
|
||||
s->ip_va, cmd_val(s, 0), cmd_val(s, 1),
|
||||
cmd_val(s, 2), cmd_val(s, 3));
|
||||
|
||||
s->ip_va = (u32 *)((((u64)s->ip_va) >> 12) << 12);
|
||||
|
||||
while (cnt < 1024) {
|
||||
pr_err("ip_va=%p: ", s->ip_va);
|
||||
gvt_dbg_cmd("ip_va=%p: ", s->ip_va);
|
||||
for (i = 0; i < 8; i++)
|
||||
pr_err("%08x ", cmd_val(s, i));
|
||||
pr_err("\n");
|
||||
gvt_dbg_cmd("%08x ", cmd_val(s, i));
|
||||
gvt_dbg_cmd("\n");
|
||||
|
||||
s->ip_va += 8 * sizeof(u32);
|
||||
cnt += 8;
|
||||
@@ -825,7 +820,7 @@ static int force_nonpriv_reg_handler(struct parser_exec_state *s,
|
||||
if (!intel_gvt_in_force_nonpriv_whitelist(gvt, data)) {
|
||||
gvt_err("Unexpected forcenonpriv 0x%x LRI write, value=0x%x\n",
|
||||
offset, data);
|
||||
return -EINVAL;
|
||||
return -EPERM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -839,7 +834,7 @@ static int cmd_reg_handler(struct parser_exec_state *s,
|
||||
if (offset + 4 > gvt->device_info.mmio_size) {
|
||||
gvt_vgpu_err("%s access to (%x) outside of MMIO range\n",
|
||||
cmd, offset);
|
||||
return -EINVAL;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!intel_gvt_mmio_is_cmd_access(gvt, offset)) {
|
||||
@@ -854,8 +849,8 @@ static int cmd_reg_handler(struct parser_exec_state *s,
|
||||
}
|
||||
|
||||
if (is_force_nonpriv_mmio(offset) &&
|
||||
force_nonpriv_reg_handler(s, offset, index))
|
||||
return -EINVAL;
|
||||
force_nonpriv_reg_handler(s, offset, index))
|
||||
return -EPERM;
|
||||
|
||||
if (offset == i915_mmio_reg_offset(DERRMR) ||
|
||||
offset == i915_mmio_reg_offset(FORCEWAKE_MT)) {
|
||||
@@ -894,11 +889,14 @@ static int cmd_handler_lri(struct parser_exec_state *s)
|
||||
i915_mmio_reg_offset(DERRMR))
|
||||
ret |= 0;
|
||||
else
|
||||
ret |= (cmd_reg_inhibit(s, i)) ? -EINVAL : 0;
|
||||
ret |= (cmd_reg_inhibit(s, i)) ?
|
||||
-EBADRQC : 0;
|
||||
}
|
||||
if (ret)
|
||||
break;
|
||||
ret |= cmd_reg_handler(s, cmd_reg(s, i), i, "lri");
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -912,11 +910,15 @@ static int cmd_handler_lrr(struct parser_exec_state *s)
|
||||
if (IS_BROADWELL(s->vgpu->gvt->dev_priv))
|
||||
ret |= ((cmd_reg_inhibit(s, i) ||
|
||||
(cmd_reg_inhibit(s, i + 1)))) ?
|
||||
-EINVAL : 0;
|
||||
-EBADRQC : 0;
|
||||
if (ret)
|
||||
break;
|
||||
ret |= cmd_reg_handler(s, cmd_reg(s, i), i, "lrr-src");
|
||||
if (ret)
|
||||
break;
|
||||
ret |= cmd_reg_handler(s, cmd_reg(s, i + 1), i, "lrr-dst");
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -934,15 +936,19 @@ static int cmd_handler_lrm(struct parser_exec_state *s)
|
||||
|
||||
for (i = 1; i < cmd_len;) {
|
||||
if (IS_BROADWELL(gvt->dev_priv))
|
||||
ret |= (cmd_reg_inhibit(s, i)) ? -EINVAL : 0;
|
||||
ret |= (cmd_reg_inhibit(s, i)) ? -EBADRQC : 0;
|
||||
if (ret)
|
||||
break;
|
||||
ret |= cmd_reg_handler(s, cmd_reg(s, i), i, "lrm");
|
||||
if (ret)
|
||||
break;
|
||||
if (cmd_val(s, 0) & (1 << 22)) {
|
||||
gma = cmd_gma(s, i + 1);
|
||||
if (gmadr_bytes == 8)
|
||||
gma |= (cmd_gma_hi(s, i + 2)) << 32;
|
||||
ret |= cmd_address_audit(s, gma, sizeof(u32), false);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
i += gmadr_dw_number(s) + 1;
|
||||
}
|
||||
@@ -958,11 +964,15 @@ static int cmd_handler_srm(struct parser_exec_state *s)
|
||||
|
||||
for (i = 1; i < cmd_len;) {
|
||||
ret |= cmd_reg_handler(s, cmd_reg(s, i), i, "srm");
|
||||
if (ret)
|
||||
break;
|
||||
if (cmd_val(s, 0) & (1 << 22)) {
|
||||
gma = cmd_gma(s, i + 1);
|
||||
if (gmadr_bytes == 8)
|
||||
gma |= (cmd_gma_hi(s, i + 2)) << 32;
|
||||
ret |= cmd_address_audit(s, gma, sizeof(u32), false);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
i += gmadr_dw_number(s) + 1;
|
||||
}
|
||||
@@ -1116,7 +1126,7 @@ static int gen8_decode_mi_display_flip(struct parser_exec_state *s,
|
||||
|
||||
v = (dword0 & GENMASK(21, 19)) >> 19;
|
||||
if (WARN_ON(v >= ARRAY_SIZE(gen8_plane_code)))
|
||||
return -EINVAL;
|
||||
return -EBADRQC;
|
||||
|
||||
info->pipe = gen8_plane_code[v].pipe;
|
||||
info->plane = gen8_plane_code[v].plane;
|
||||
@@ -1136,7 +1146,7 @@ static int gen8_decode_mi_display_flip(struct parser_exec_state *s,
|
||||
info->surf_reg = SPRSURF(info->pipe);
|
||||
} else {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
return -EBADRQC;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1185,7 +1195,7 @@ static int skl_decode_mi_display_flip(struct parser_exec_state *s,
|
||||
|
||||
default:
|
||||
gvt_vgpu_err("unknown plane code %d\n", plane);
|
||||
return -EINVAL;
|
||||
return -EBADRQC;
|
||||
}
|
||||
|
||||
info->stride_val = (dword1 & GENMASK(15, 6)) >> 6;
|
||||
@@ -1348,10 +1358,13 @@ static unsigned long get_gma_bb_from_cmd(struct parser_exec_state *s, int index)
|
||||
{
|
||||
unsigned long addr;
|
||||
unsigned long gma_high, gma_low;
|
||||
int gmadr_bytes = s->vgpu->gvt->device_info.gmadr_bytes_in_cmd;
|
||||
struct intel_vgpu *vgpu = s->vgpu;
|
||||
int gmadr_bytes = vgpu->gvt->device_info.gmadr_bytes_in_cmd;
|
||||
|
||||
if (WARN_ON(gmadr_bytes != 4 && gmadr_bytes != 8))
|
||||
if (WARN_ON(gmadr_bytes != 4 && gmadr_bytes != 8)) {
|
||||
gvt_vgpu_err("invalid gma bytes %d\n", gmadr_bytes);
|
||||
return INTEL_GVT_INVALID_ADDR;
|
||||
}
|
||||
|
||||
gma_low = cmd_val(s, index) & BATCH_BUFFER_ADDR_MASK;
|
||||
if (gmadr_bytes == 4) {
|
||||
@@ -1374,16 +1387,16 @@ static inline int cmd_address_audit(struct parser_exec_state *s,
|
||||
if (op_size > max_surface_size) {
|
||||
gvt_vgpu_err("command address audit fail name %s\n",
|
||||
s->info->name);
|
||||
return -EINVAL;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (index_mode) {
|
||||
if (guest_gma >= GTT_PAGE_SIZE / sizeof(u64)) {
|
||||
ret = -EINVAL;
|
||||
if (guest_gma >= I915_GTT_PAGE_SIZE / sizeof(u64)) {
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
} else if (!intel_gvt_ggtt_validate_range(vgpu, guest_gma, op_size)) {
|
||||
ret = -EINVAL;
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -1439,7 +1452,7 @@ static inline int unexpected_cmd(struct parser_exec_state *s)
|
||||
|
||||
gvt_vgpu_err("Unexpected %s in command buffer!\n", s->info->name);
|
||||
|
||||
return -EINVAL;
|
||||
return -EBADRQC;
|
||||
}
|
||||
|
||||
static int cmd_handler_mi_semaphore_wait(struct parser_exec_state *s)
|
||||
@@ -1545,10 +1558,10 @@ static int copy_gma_to_hva(struct intel_vgpu *vgpu, struct intel_vgpu_mm *mm,
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
offset = gma & (GTT_PAGE_SIZE - 1);
|
||||
offset = gma & (I915_GTT_PAGE_SIZE - 1);
|
||||
|
||||
copy_len = (end_gma - gma) >= (GTT_PAGE_SIZE - offset) ?
|
||||
GTT_PAGE_SIZE - offset : end_gma - gma;
|
||||
copy_len = (end_gma - gma) >= (I915_GTT_PAGE_SIZE - offset) ?
|
||||
I915_GTT_PAGE_SIZE - offset : end_gma - gma;
|
||||
|
||||
intel_gvt_hypervisor_read_gpa(vgpu, gpa, va + len, copy_len);
|
||||
|
||||
@@ -1576,110 +1589,113 @@ static int batch_buffer_needs_scan(struct parser_exec_state *s)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int find_bb_size(struct parser_exec_state *s)
|
||||
static int find_bb_size(struct parser_exec_state *s, unsigned long *bb_size)
|
||||
{
|
||||
unsigned long gma = 0;
|
||||
struct cmd_info *info;
|
||||
int bb_size = 0;
|
||||
uint32_t cmd_len = 0;
|
||||
bool met_bb_end = false;
|
||||
bool bb_end = false;
|
||||
struct intel_vgpu *vgpu = s->vgpu;
|
||||
u32 cmd;
|
||||
|
||||
*bb_size = 0;
|
||||
|
||||
/* get the start gm address of the batch buffer */
|
||||
gma = get_gma_bb_from_cmd(s, 1);
|
||||
cmd = cmd_val(s, 0);
|
||||
if (gma == INTEL_GVT_INVALID_ADDR)
|
||||
return -EFAULT;
|
||||
|
||||
cmd = cmd_val(s, 0);
|
||||
info = get_cmd_info(s->vgpu->gvt, cmd, s->ring_id);
|
||||
if (info == NULL) {
|
||||
gvt_vgpu_err("unknown cmd 0x%x, opcode=0x%x\n",
|
||||
cmd, get_opcode(cmd, s->ring_id));
|
||||
return -EINVAL;
|
||||
return -EBADRQC;
|
||||
}
|
||||
do {
|
||||
copy_gma_to_hva(s->vgpu, s->vgpu->gtt.ggtt_mm,
|
||||
gma, gma + 4, &cmd);
|
||||
if (copy_gma_to_hva(s->vgpu, s->vgpu->gtt.ggtt_mm,
|
||||
gma, gma + 4, &cmd) < 0)
|
||||
return -EFAULT;
|
||||
info = get_cmd_info(s->vgpu->gvt, cmd, s->ring_id);
|
||||
if (info == NULL) {
|
||||
gvt_vgpu_err("unknown cmd 0x%x, opcode=0x%x\n",
|
||||
cmd, get_opcode(cmd, s->ring_id));
|
||||
return -EINVAL;
|
||||
return -EBADRQC;
|
||||
}
|
||||
|
||||
if (info->opcode == OP_MI_BATCH_BUFFER_END) {
|
||||
met_bb_end = true;
|
||||
bb_end = true;
|
||||
} else if (info->opcode == OP_MI_BATCH_BUFFER_START) {
|
||||
if (BATCH_BUFFER_2ND_LEVEL_BIT(cmd) == 0) {
|
||||
if (BATCH_BUFFER_2ND_LEVEL_BIT(cmd) == 0)
|
||||
/* chained batch buffer */
|
||||
met_bb_end = true;
|
||||
}
|
||||
bb_end = true;
|
||||
}
|
||||
cmd_len = get_cmd_length(info, cmd) << 2;
|
||||
bb_size += cmd_len;
|
||||
*bb_size += cmd_len;
|
||||
gma += cmd_len;
|
||||
} while (!bb_end);
|
||||
|
||||
} while (!met_bb_end);
|
||||
|
||||
return bb_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perform_bb_shadow(struct parser_exec_state *s)
|
||||
{
|
||||
struct intel_shadow_bb_entry *entry_obj;
|
||||
struct intel_vgpu *vgpu = s->vgpu;
|
||||
struct intel_vgpu_shadow_bb *bb;
|
||||
unsigned long gma = 0;
|
||||
int bb_size;
|
||||
void *dst = NULL;
|
||||
unsigned long bb_size;
|
||||
int ret = 0;
|
||||
|
||||
/* get the start gm address of the batch buffer */
|
||||
gma = get_gma_bb_from_cmd(s, 1);
|
||||
if (gma == INTEL_GVT_INVALID_ADDR)
|
||||
return -EFAULT;
|
||||
|
||||
/* get the size of the batch buffer */
|
||||
bb_size = find_bb_size(s);
|
||||
if (bb_size < 0)
|
||||
return -EINVAL;
|
||||
ret = find_bb_size(s, &bb_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* allocate shadow batch buffer */
|
||||
entry_obj = kmalloc(sizeof(*entry_obj), GFP_KERNEL);
|
||||
if (entry_obj == NULL)
|
||||
bb = kzalloc(sizeof(*bb), GFP_KERNEL);
|
||||
if (!bb)
|
||||
return -ENOMEM;
|
||||
|
||||
entry_obj->obj =
|
||||
i915_gem_object_create(s->vgpu->gvt->dev_priv,
|
||||
roundup(bb_size, PAGE_SIZE));
|
||||
if (IS_ERR(entry_obj->obj)) {
|
||||
ret = PTR_ERR(entry_obj->obj);
|
||||
goto free_entry;
|
||||
}
|
||||
entry_obj->len = bb_size;
|
||||
INIT_LIST_HEAD(&entry_obj->list);
|
||||
|
||||
dst = i915_gem_object_pin_map(entry_obj->obj, I915_MAP_WB);
|
||||
if (IS_ERR(dst)) {
|
||||
ret = PTR_ERR(dst);
|
||||
goto put_obj;
|
||||
bb->obj = i915_gem_object_create(s->vgpu->gvt->dev_priv,
|
||||
roundup(bb_size, PAGE_SIZE));
|
||||
if (IS_ERR(bb->obj)) {
|
||||
ret = PTR_ERR(bb->obj);
|
||||
goto err_free_bb;
|
||||
}
|
||||
|
||||
ret = i915_gem_object_set_to_cpu_domain(entry_obj->obj, false);
|
||||
if (ret) {
|
||||
gvt_vgpu_err("failed to set shadow batch to CPU\n");
|
||||
goto unmap_src;
|
||||
ret = i915_gem_obj_prepare_shmem_write(bb->obj, &bb->clflush);
|
||||
if (ret)
|
||||
goto err_free_obj;
|
||||
|
||||
bb->va = i915_gem_object_pin_map(bb->obj, I915_MAP_WB);
|
||||
if (IS_ERR(bb->va)) {
|
||||
ret = PTR_ERR(bb->va);
|
||||
goto err_finish_shmem_access;
|
||||
}
|
||||
|
||||
entry_obj->va = dst;
|
||||
entry_obj->bb_start_cmd_va = s->ip_va;
|
||||
if (bb->clflush & CLFLUSH_BEFORE) {
|
||||
drm_clflush_virt_range(bb->va, bb->obj->base.size);
|
||||
bb->clflush &= ~CLFLUSH_BEFORE;
|
||||
}
|
||||
|
||||
/* copy batch buffer to shadow batch buffer*/
|
||||
ret = copy_gma_to_hva(s->vgpu, s->vgpu->gtt.ggtt_mm,
|
||||
gma, gma + bb_size,
|
||||
dst);
|
||||
bb->va);
|
||||
if (ret < 0) {
|
||||
gvt_vgpu_err("fail to copy guest ring buffer\n");
|
||||
goto unmap_src;
|
||||
ret = -EFAULT;
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
list_add(&entry_obj->list, &s->workload->shadow_bb);
|
||||
INIT_LIST_HEAD(&bb->list);
|
||||
list_add(&bb->list, &s->workload->shadow_bb);
|
||||
|
||||
bb->accessing = true;
|
||||
bb->bb_start_cmd_va = s->ip_va;
|
||||
|
||||
/*
|
||||
* ip_va saves the virtual address of the shadow batch buffer, while
|
||||
* ip_gma saves the graphics address of the original batch buffer.
|
||||
@@ -1688,17 +1704,17 @@ static int perform_bb_shadow(struct parser_exec_state *s)
|
||||
* buffer's gma in pair. After all, we don't want to pin the shadow
|
||||
* buffer here (too early).
|
||||
*/
|
||||
s->ip_va = dst;
|
||||
s->ip_va = bb->va;
|
||||
s->ip_gma = gma;
|
||||
|
||||
return 0;
|
||||
|
||||
unmap_src:
|
||||
i915_gem_object_unpin_map(entry_obj->obj);
|
||||
put_obj:
|
||||
i915_gem_object_put(entry_obj->obj);
|
||||
free_entry:
|
||||
kfree(entry_obj);
|
||||
err_unmap:
|
||||
i915_gem_object_unpin_map(bb->obj);
|
||||
err_finish_shmem_access:
|
||||
i915_gem_obj_finish_shmem_access(bb->obj);
|
||||
err_free_obj:
|
||||
i915_gem_object_put(bb->obj);
|
||||
err_free_bb:
|
||||
kfree(bb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1710,13 +1726,13 @@ static int cmd_handler_mi_batch_buffer_start(struct parser_exec_state *s)
|
||||
|
||||
if (s->buf_type == BATCH_BUFFER_2ND_LEVEL) {
|
||||
gvt_vgpu_err("Found MI_BATCH_BUFFER_START in 2nd level BB\n");
|
||||
return -EINVAL;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
second_level = BATCH_BUFFER_2ND_LEVEL_BIT(cmd_val(s, 0)) == 1;
|
||||
if (second_level && (s->buf_type != BATCH_BUFFER_INSTRUCTION)) {
|
||||
gvt_vgpu_err("Jumping to 2nd level BB from RB is not allowed\n");
|
||||
return -EINVAL;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
s->saved_buf_addr_type = s->buf_addr_type;
|
||||
@@ -1740,7 +1756,6 @@ static int cmd_handler_mi_batch_buffer_start(struct parser_exec_state *s)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2430,7 +2445,7 @@ static int cmd_parser_exec(struct parser_exec_state *s)
|
||||
if (info == NULL) {
|
||||
gvt_vgpu_err("unknown cmd 0x%x, opcode=0x%x\n",
|
||||
cmd, get_opcode(cmd, s->ring_id));
|
||||
return -EINVAL;
|
||||
return -EBADRQC;
|
||||
}
|
||||
|
||||
s->info = info;
|
||||
@@ -2465,6 +2480,10 @@ static inline bool gma_out_of_range(unsigned long gma,
|
||||
return (gma > gma_tail) && (gma < gma_head);
|
||||
}
|
||||
|
||||
/* Keep the consistent return type, e.g EBADRQC for unknown
|
||||
* cmd, EFAULT for invalid address, EPERM for nonpriv. later
|
||||
* works as the input of VM healthy status.
|
||||
*/
|
||||
static int command_scan(struct parser_exec_state *s,
|
||||
unsigned long rb_head, unsigned long rb_tail,
|
||||
unsigned long rb_start, unsigned long rb_len)
|
||||
@@ -2487,7 +2506,7 @@ static int command_scan(struct parser_exec_state *s,
|
||||
s->ip_gma, rb_start,
|
||||
gma_bottom);
|
||||
parser_exec_state_dump(s);
|
||||
return -EINVAL;
|
||||
return -EFAULT;
|
||||
}
|
||||
if (gma_out_of_range(s->ip_gma, gma_head, gma_tail)) {
|
||||
gvt_vgpu_err("ip_gma %lx out of range."
|
||||
@@ -2516,7 +2535,7 @@ static int scan_workload(struct intel_vgpu_workload *workload)
|
||||
int ret = 0;
|
||||
|
||||
/* ring base is page aligned */
|
||||
if (WARN_ON(!IS_ALIGNED(workload->rb_start, GTT_PAGE_SIZE)))
|
||||
if (WARN_ON(!IS_ALIGNED(workload->rb_start, I915_GTT_PAGE_SIZE)))
|
||||
return -EINVAL;
|
||||
|
||||
gma_head = workload->rb_start + workload->rb_head;
|
||||
@@ -2565,7 +2584,8 @@ static int scan_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
|
||||
wa_ctx);
|
||||
|
||||
/* ring base is page aligned */
|
||||
if (WARN_ON(!IS_ALIGNED(wa_ctx->indirect_ctx.guest_gma, GTT_PAGE_SIZE)))
|
||||
if (WARN_ON(!IS_ALIGNED(wa_ctx->indirect_ctx.guest_gma,
|
||||
I915_GTT_PAGE_SIZE)))
|
||||
return -EINVAL;
|
||||
|
||||
ring_tail = wa_ctx->indirect_ctx.size + 3 * sizeof(uint32_t);
|
||||
@@ -2604,6 +2624,7 @@ out:
|
||||
static int shadow_workload_ring_buffer(struct intel_vgpu_workload *workload)
|
||||
{
|
||||
struct intel_vgpu *vgpu = workload->vgpu;
|
||||
struct intel_vgpu_submission *s = &vgpu->submission;
|
||||
unsigned long gma_head, gma_tail, gma_top, guest_rb_size;
|
||||
void *shadow_ring_buffer_va;
|
||||
int ring_id = workload->ring_id;
|
||||
@@ -2619,19 +2640,21 @@ static int shadow_workload_ring_buffer(struct intel_vgpu_workload *workload)
|
||||
gma_tail = workload->rb_start + workload->rb_tail;
|
||||
gma_top = workload->rb_start + guest_rb_size;
|
||||
|
||||
if (workload->rb_len > vgpu->reserve_ring_buffer_size[ring_id]) {
|
||||
void *va = vgpu->reserve_ring_buffer_va[ring_id];
|
||||
if (workload->rb_len > s->ring_scan_buffer_size[ring_id]) {
|
||||
void *p;
|
||||
|
||||
/* realloc the new ring buffer if needed */
|
||||
vgpu->reserve_ring_buffer_va[ring_id] =
|
||||
krealloc(va, workload->rb_len, GFP_KERNEL);
|
||||
if (!vgpu->reserve_ring_buffer_va[ring_id]) {
|
||||
gvt_vgpu_err("fail to alloc reserve ring buffer\n");
|
||||
p = krealloc(s->ring_scan_buffer[ring_id], workload->rb_len,
|
||||
GFP_KERNEL);
|
||||
if (!p) {
|
||||
gvt_vgpu_err("fail to re-alloc ring scan buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
vgpu->reserve_ring_buffer_size[ring_id] = workload->rb_len;
|
||||
s->ring_scan_buffer[ring_id] = p;
|
||||
s->ring_scan_buffer_size[ring_id] = workload->rb_len;
|
||||
}
|
||||
|
||||
shadow_ring_buffer_va = vgpu->reserve_ring_buffer_va[ring_id];
|
||||
shadow_ring_buffer_va = s->ring_scan_buffer[ring_id];
|
||||
|
||||
/* get shadow ring buffer va */
|
||||
workload->shadow_ring_buffer_va = shadow_ring_buffer_va;
|
||||
|
||||
@@ -25,41 +25,41 @@
|
||||
#define __GVT_DEBUG_H__
|
||||
|
||||
#define gvt_err(fmt, args...) \
|
||||
DRM_ERROR("gvt: "fmt, ##args)
|
||||
pr_err("gvt: "fmt, ##args)
|
||||
|
||||
#define gvt_vgpu_err(fmt, args...) \
|
||||
do { \
|
||||
if (IS_ERR_OR_NULL(vgpu)) \
|
||||
DRM_DEBUG_DRIVER("gvt: "fmt, ##args); \
|
||||
pr_err("gvt: "fmt, ##args); \
|
||||
else \
|
||||
DRM_DEBUG_DRIVER("gvt: vgpu %d: "fmt, vgpu->id, ##args);\
|
||||
pr_err("gvt: vgpu %d: "fmt, vgpu->id, ##args);\
|
||||
} while (0)
|
||||
|
||||
#define gvt_dbg_core(fmt, args...) \
|
||||
DRM_DEBUG_DRIVER("gvt: core: "fmt, ##args)
|
||||
pr_debug("gvt: core: "fmt, ##args)
|
||||
|
||||
#define gvt_dbg_irq(fmt, args...) \
|
||||
DRM_DEBUG_DRIVER("gvt: irq: "fmt, ##args)
|
||||
pr_debug("gvt: irq: "fmt, ##args)
|
||||
|
||||
#define gvt_dbg_mm(fmt, args...) \
|
||||
DRM_DEBUG_DRIVER("gvt: mm: "fmt, ##args)
|
||||
pr_debug("gvt: mm: "fmt, ##args)
|
||||
|
||||
#define gvt_dbg_mmio(fmt, args...) \
|
||||
DRM_DEBUG_DRIVER("gvt: mmio: "fmt, ##args)
|
||||
pr_debug("gvt: mmio: "fmt, ##args)
|
||||
|
||||
#define gvt_dbg_dpy(fmt, args...) \
|
||||
DRM_DEBUG_DRIVER("gvt: dpy: "fmt, ##args)
|
||||
pr_debug("gvt: dpy: "fmt, ##args)
|
||||
|
||||
#define gvt_dbg_el(fmt, args...) \
|
||||
DRM_DEBUG_DRIVER("gvt: el: "fmt, ##args)
|
||||
pr_debug("gvt: el: "fmt, ##args)
|
||||
|
||||
#define gvt_dbg_sched(fmt, args...) \
|
||||
DRM_DEBUG_DRIVER("gvt: sched: "fmt, ##args)
|
||||
pr_debug("gvt: sched: "fmt, ##args)
|
||||
|
||||
#define gvt_dbg_render(fmt, args...) \
|
||||
DRM_DEBUG_DRIVER("gvt: render: "fmt, ##args)
|
||||
pr_debug("gvt: render: "fmt, ##args)
|
||||
|
||||
#define gvt_dbg_cmd(fmt, args...) \
|
||||
DRM_DEBUG_DRIVER("gvt: cmd: "fmt, ##args)
|
||||
pr_debug("gvt: cmd: "fmt, ##args)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright(c) 2011-2017 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/list_sort.h>
|
||||
#include "i915_drv.h"
|
||||
#include "gvt.h"
|
||||
|
||||
struct mmio_diff_param {
|
||||
struct intel_vgpu *vgpu;
|
||||
int total;
|
||||
int diff;
|
||||
struct list_head diff_mmio_list;
|
||||
};
|
||||
|
||||
struct diff_mmio {
|
||||
struct list_head node;
|
||||
u32 offset;
|
||||
u32 preg;
|
||||
u32 vreg;
|
||||
};
|
||||
|
||||
/* Compare two diff_mmio items. */
|
||||
static int mmio_offset_compare(void *priv,
|
||||
struct list_head *a, struct list_head *b)
|
||||
{
|
||||
struct diff_mmio *ma;
|
||||
struct diff_mmio *mb;
|
||||
|
||||
ma = container_of(a, struct diff_mmio, node);
|
||||
mb = container_of(b, struct diff_mmio, node);
|
||||
if (ma->offset < mb->offset)
|
||||
return -1;
|
||||
else if (ma->offset > mb->offset)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int mmio_diff_handler(struct intel_gvt *gvt,
|
||||
u32 offset, void *data)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = gvt->dev_priv;
|
||||
struct mmio_diff_param *param = data;
|
||||
struct diff_mmio *node;
|
||||
u32 preg, vreg;
|
||||
|
||||
preg = I915_READ_NOTRACE(_MMIO(offset));
|
||||
vreg = vgpu_vreg(param->vgpu, offset);
|
||||
|
||||
if (preg != vreg) {
|
||||
node = kmalloc(sizeof(*node), GFP_KERNEL);
|
||||
if (!node)
|
||||
return -ENOMEM;
|
||||
|
||||
node->offset = offset;
|
||||
node->preg = preg;
|
||||
node->vreg = vreg;
|
||||
list_add(&node->node, ¶m->diff_mmio_list);
|
||||
param->diff++;
|
||||
}
|
||||
param->total++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Show the all the different values of tracked mmio. */
|
||||
static int vgpu_mmio_diff_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct intel_vgpu *vgpu = s->private;
|
||||
struct intel_gvt *gvt = vgpu->gvt;
|
||||
struct mmio_diff_param param = {
|
||||
.vgpu = vgpu,
|
||||
.total = 0,
|
||||
.diff = 0,
|
||||
};
|
||||
struct diff_mmio *node, *next;
|
||||
|
||||
INIT_LIST_HEAD(¶m.diff_mmio_list);
|
||||
|
||||
mutex_lock(&gvt->lock);
|
||||
spin_lock_bh(&gvt->scheduler.mmio_context_lock);
|
||||
|
||||
mmio_hw_access_pre(gvt->dev_priv);
|
||||
/* Recognize all the diff mmios to list. */
|
||||
intel_gvt_for_each_tracked_mmio(gvt, mmio_diff_handler, ¶m);
|
||||
mmio_hw_access_post(gvt->dev_priv);
|
||||
|
||||
spin_unlock_bh(&gvt->scheduler.mmio_context_lock);
|
||||
mutex_unlock(&gvt->lock);
|
||||
|
||||
/* In an ascending order by mmio offset. */
|
||||
list_sort(NULL, ¶m.diff_mmio_list, mmio_offset_compare);
|
||||
|
||||
seq_printf(s, "%-8s %-8s %-8s %-8s\n", "Offset", "HW", "vGPU", "Diff");
|
||||
list_for_each_entry_safe(node, next, ¶m.diff_mmio_list, node) {
|
||||
u32 diff = node->preg ^ node->vreg;
|
||||
|
||||
seq_printf(s, "%08x %08x %08x %*pbl\n",
|
||||
node->offset, node->preg, node->vreg,
|
||||
32, &diff);
|
||||
list_del(&node->node);
|
||||
kfree(node);
|
||||
}
|
||||
seq_printf(s, "Total: %d, Diff: %d\n", param.total, param.diff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vgpu_mmio_diff_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, vgpu_mmio_diff_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations vgpu_mmio_diff_fops = {
|
||||
.open = vgpu_mmio_diff_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* intel_gvt_debugfs_add_vgpu - register debugfs entries for a vGPU
|
||||
* @vgpu: a vGPU
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative error code if failed.
|
||||
*/
|
||||
int intel_gvt_debugfs_add_vgpu(struct intel_vgpu *vgpu)
|
||||
{
|
||||
struct dentry *ent;
|
||||
char name[10] = "";
|
||||
|
||||
sprintf(name, "vgpu%d", vgpu->id);
|
||||
vgpu->debugfs = debugfs_create_dir(name, vgpu->gvt->debugfs_root);
|
||||
if (!vgpu->debugfs)
|
||||
return -ENOMEM;
|
||||
|
||||
ent = debugfs_create_bool("active", 0444, vgpu->debugfs,
|
||||
&vgpu->active);
|
||||
if (!ent)
|
||||
return -ENOMEM;
|
||||
|
||||
ent = debugfs_create_file("mmio_diff", 0444, vgpu->debugfs,
|
||||
vgpu, &vgpu_mmio_diff_fops);
|
||||
if (!ent)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_debugfs_remove_vgpu - remove debugfs entries of a vGPU
|
||||
* @vgpu: a vGPU
|
||||
*/
|
||||
void intel_gvt_debugfs_remove_vgpu(struct intel_vgpu *vgpu)
|
||||
{
|
||||
debugfs_remove_recursive(vgpu->debugfs);
|
||||
vgpu->debugfs = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_debugfs_init - register gvt debugfs root entry
|
||||
* @gvt: GVT device
|
||||
*
|
||||
* Returns:
|
||||
* zero on success, negative if failed.
|
||||
*/
|
||||
int intel_gvt_debugfs_init(struct intel_gvt *gvt)
|
||||
{
|
||||
struct drm_minor *minor = gvt->dev_priv->drm.primary;
|
||||
struct dentry *ent;
|
||||
|
||||
gvt->debugfs_root = debugfs_create_dir("gvt", minor->debugfs_root);
|
||||
if (!gvt->debugfs_root) {
|
||||
gvt_err("Cannot create debugfs dir\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ent = debugfs_create_ulong("num_tracked_mmio", 0444, gvt->debugfs_root,
|
||||
&gvt->mmio.num_tracked_mmio);
|
||||
if (!ent)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_debugfs_clean - remove debugfs entries
|
||||
* @gvt: GVT device
|
||||
*/
|
||||
void intel_gvt_debugfs_clean(struct intel_gvt *gvt)
|
||||
{
|
||||
debugfs_remove_recursive(gvt->debugfs_root);
|
||||
gvt->debugfs_root = NULL;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -36,10 +36,6 @@
|
||||
#define _GVT_EXECLIST_H_
|
||||
|
||||
struct execlist_ctx_descriptor_format {
|
||||
union {
|
||||
u32 udw;
|
||||
u32 context_id;
|
||||
};
|
||||
union {
|
||||
u32 ldw;
|
||||
struct {
|
||||
@@ -54,6 +50,10 @@ struct execlist_ctx_descriptor_format {
|
||||
u32 lrca : 20;
|
||||
};
|
||||
};
|
||||
union {
|
||||
u32 udw;
|
||||
u32 context_id;
|
||||
};
|
||||
};
|
||||
|
||||
struct execlist_status_format {
|
||||
|
||||
@@ -66,20 +66,23 @@ static struct bin_attribute firmware_attr = {
|
||||
.mmap = NULL,
|
||||
};
|
||||
|
||||
static int expose_firmware_sysfs(struct intel_gvt *gvt)
|
||||
static int mmio_snapshot_handler(struct intel_gvt *gvt, u32 offset, void *data)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = gvt->dev_priv;
|
||||
|
||||
*(u32 *)(data + offset) = I915_READ_NOTRACE(_MMIO(offset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int expose_firmware_sysfs(struct intel_gvt *gvt)
|
||||
{
|
||||
struct intel_gvt_device_info *info = &gvt->device_info;
|
||||
struct pci_dev *pdev = gvt->dev_priv->drm.pdev;
|
||||
struct intel_gvt_mmio_info *e;
|
||||
struct gvt_mmio_block *block = gvt->mmio.mmio_block;
|
||||
int num = gvt->mmio.num_mmio_block;
|
||||
struct gvt_firmware_header *h;
|
||||
void *firmware;
|
||||
void *p;
|
||||
unsigned long size, crc32_start;
|
||||
int i, j;
|
||||
int ret;
|
||||
int i, ret;
|
||||
|
||||
size = sizeof(*h) + info->mmio_size + info->cfg_space_size;
|
||||
firmware = vzalloc(size);
|
||||
@@ -104,15 +107,8 @@ static int expose_firmware_sysfs(struct intel_gvt *gvt)
|
||||
|
||||
p = firmware + h->mmio_offset;
|
||||
|
||||
hash_for_each(gvt->mmio.mmio_info_table, i, e, node)
|
||||
*(u32 *)(p + e->offset) = I915_READ_NOTRACE(_MMIO(e->offset));
|
||||
|
||||
for (i = 0; i < num; i++, block++) {
|
||||
for (j = 0; j < block->size; j += 4)
|
||||
*(u32 *)(p + INTEL_GVT_MMIO_OFFSET(block->offset) + j) =
|
||||
I915_READ_NOTRACE(_MMIO(INTEL_GVT_MMIO_OFFSET(
|
||||
block->offset) + j));
|
||||
}
|
||||
/* Take a snapshot of hw mmio registers. */
|
||||
intel_gvt_for_each_tracked_mmio(gvt, mmio_snapshot_handler, p);
|
||||
|
||||
memcpy(gvt->firmware.mmio, p, info->mmio_size);
|
||||
|
||||
|
||||
+163
-120
File diff suppressed because it is too large.
Load diff
@@ -34,9 +34,8 @@
|
||||
#ifndef _GVT_GTT_H_
|
||||
#define _GVT_GTT_H_
|
||||
|
||||
#define GTT_PAGE_SHIFT 12
|
||||
#define GTT_PAGE_SIZE (1UL << GTT_PAGE_SHIFT)
|
||||
#define GTT_PAGE_MASK (~(GTT_PAGE_SIZE-1))
|
||||
#define I915_GTT_PAGE_SHIFT 12
|
||||
#define I915_GTT_PAGE_MASK (~(I915_GTT_PAGE_SIZE - 1))
|
||||
|
||||
struct intel_vgpu_mm;
|
||||
|
||||
@@ -63,6 +62,7 @@ struct intel_gvt_gtt_pte_ops {
|
||||
struct intel_vgpu *vgpu);
|
||||
bool (*test_present)(struct intel_gvt_gtt_entry *e);
|
||||
void (*clear_present)(struct intel_gvt_gtt_entry *e);
|
||||
void (*set_present)(struct intel_gvt_gtt_entry *e);
|
||||
bool (*test_pse)(struct intel_gvt_gtt_entry *e);
|
||||
void (*set_pfn)(struct intel_gvt_gtt_entry *e, unsigned long pfn);
|
||||
unsigned long (*get_pfn)(struct intel_gvt_gtt_entry *e);
|
||||
@@ -86,8 +86,8 @@ struct intel_gvt_gtt {
|
||||
struct list_head oos_page_free_list_head;
|
||||
struct list_head mm_lru_list_head;
|
||||
|
||||
struct page *scratch_ggtt_page;
|
||||
unsigned long scratch_ggtt_mfn;
|
||||
struct page *scratch_page;
|
||||
unsigned long scratch_mfn;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -193,18 +193,16 @@ struct intel_vgpu_scratch_pt {
|
||||
unsigned long page_mfn;
|
||||
};
|
||||
|
||||
|
||||
struct intel_vgpu_gtt {
|
||||
struct intel_vgpu_mm *ggtt_mm;
|
||||
unsigned long active_ppgtt_mm_bitmap;
|
||||
struct list_head mm_list_head;
|
||||
DECLARE_HASHTABLE(shadow_page_hash_table, INTEL_GVT_GTT_HASH_BITS);
|
||||
DECLARE_HASHTABLE(guest_page_hash_table, INTEL_GVT_GTT_HASH_BITS);
|
||||
atomic_t n_write_protected_guest_page;
|
||||
DECLARE_HASHTABLE(tracked_guest_page_hash_table, INTEL_GVT_GTT_HASH_BITS);
|
||||
atomic_t n_tracked_guest_page;
|
||||
struct list_head oos_page_list_head;
|
||||
struct list_head post_shadow_list_head;
|
||||
struct intel_vgpu_scratch_pt scratch_pt[GTT_TYPE_MAX];
|
||||
|
||||
};
|
||||
|
||||
extern int intel_vgpu_init_gtt(struct intel_vgpu *vgpu);
|
||||
@@ -228,12 +226,16 @@ struct intel_vgpu_shadow_page {
|
||||
unsigned long mfn;
|
||||
};
|
||||
|
||||
struct intel_vgpu_guest_page {
|
||||
struct intel_vgpu_page_track {
|
||||
struct hlist_node node;
|
||||
bool writeprotection;
|
||||
bool tracked;
|
||||
unsigned long gfn;
|
||||
int (*handler)(void *, u64, void *, int);
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct intel_vgpu_guest_page {
|
||||
struct intel_vgpu_page_track track;
|
||||
unsigned long write_cnt;
|
||||
struct intel_vgpu_oos_page *oos_page;
|
||||
};
|
||||
@@ -243,7 +245,7 @@ struct intel_vgpu_oos_page {
|
||||
struct list_head list;
|
||||
struct list_head vm_list;
|
||||
int id;
|
||||
unsigned char mem[GTT_PAGE_SIZE];
|
||||
unsigned char mem[I915_GTT_PAGE_SIZE];
|
||||
};
|
||||
|
||||
#define GTT_ENTRY_NUM_IN_ONE_PAGE 512
|
||||
@@ -258,22 +260,16 @@ struct intel_vgpu_ppgtt_spt {
|
||||
struct list_head post_shadow_list;
|
||||
};
|
||||
|
||||
int intel_vgpu_init_guest_page(struct intel_vgpu *vgpu,
|
||||
struct intel_vgpu_guest_page *guest_page,
|
||||
int intel_vgpu_init_page_track(struct intel_vgpu *vgpu,
|
||||
struct intel_vgpu_page_track *t,
|
||||
unsigned long gfn,
|
||||
int (*handler)(void *gp, u64, void *, int),
|
||||
void *data);
|
||||
|
||||
void intel_vgpu_clean_guest_page(struct intel_vgpu *vgpu,
|
||||
struct intel_vgpu_guest_page *guest_page);
|
||||
void intel_vgpu_clean_page_track(struct intel_vgpu *vgpu,
|
||||
struct intel_vgpu_page_track *t);
|
||||
|
||||
int intel_vgpu_set_guest_page_writeprotection(struct intel_vgpu *vgpu,
|
||||
struct intel_vgpu_guest_page *guest_page);
|
||||
|
||||
void intel_vgpu_clear_guest_page_writeprotection(struct intel_vgpu *vgpu,
|
||||
struct intel_vgpu_guest_page *guest_page);
|
||||
|
||||
struct intel_vgpu_guest_page *intel_vgpu_find_guest_page(
|
||||
struct intel_vgpu_page_track *intel_vgpu_find_tracked_page(
|
||||
struct intel_vgpu *vgpu, unsigned long gfn);
|
||||
|
||||
int intel_vgpu_sync_oos_pages(struct intel_vgpu *vgpu);
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#include "i915_drv.h"
|
||||
#include "gvt.h"
|
||||
#include <linux/vfio.h>
|
||||
#include <linux/mdev.h>
|
||||
|
||||
struct intel_gvt_host intel_gvt_host;
|
||||
|
||||
@@ -44,6 +46,129 @@ static const char * const supported_hypervisors[] = {
|
||||
[INTEL_GVT_HYPERVISOR_KVM] = "KVM",
|
||||
};
|
||||
|
||||
static struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
struct intel_vgpu_type *t;
|
||||
const char *driver_name = dev_driver_string(
|
||||
&gvt->dev_priv->drm.pdev->dev);
|
||||
|
||||
for (i = 0; i < gvt->num_types; i++) {
|
||||
t = &gvt->types[i];
|
||||
if (!strncmp(t->name, name + strlen(driver_name) + 1,
|
||||
sizeof(t->name)))
|
||||
return t;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t available_instances_show(struct kobject *kobj,
|
||||
struct device *dev, char *buf)
|
||||
{
|
||||
struct intel_vgpu_type *type;
|
||||
unsigned int num = 0;
|
||||
void *gvt = kdev_to_i915(dev)->gvt;
|
||||
|
||||
type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
|
||||
if (!type)
|
||||
num = 0;
|
||||
else
|
||||
num = type->avail_instance;
|
||||
|
||||
return sprintf(buf, "%u\n", num);
|
||||
}
|
||||
|
||||
static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING);
|
||||
}
|
||||
|
||||
static ssize_t description_show(struct kobject *kobj, struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct intel_vgpu_type *type;
|
||||
void *gvt = kdev_to_i915(dev)->gvt;
|
||||
|
||||
type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
|
||||
if (!type)
|
||||
return 0;
|
||||
|
||||
return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n"
|
||||
"fence: %d\nresolution: %s\n"
|
||||
"weight: %d\n",
|
||||
BYTES_TO_MB(type->low_gm_size),
|
||||
BYTES_TO_MB(type->high_gm_size),
|
||||
type->fence, vgpu_edid_str(type->resolution),
|
||||
type->weight);
|
||||
}
|
||||
|
||||
static MDEV_TYPE_ATTR_RO(available_instances);
|
||||
static MDEV_TYPE_ATTR_RO(device_api);
|
||||
static MDEV_TYPE_ATTR_RO(description);
|
||||
|
||||
static struct attribute *gvt_type_attrs[] = {
|
||||
&mdev_type_attr_available_instances.attr,
|
||||
&mdev_type_attr_device_api.attr,
|
||||
&mdev_type_attr_description.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group *gvt_vgpu_type_groups[] = {
|
||||
[0 ... NR_MAX_INTEL_VGPU_TYPES - 1] = NULL,
|
||||
};
|
||||
|
||||
static bool intel_get_gvt_attrs(struct attribute ***type_attrs,
|
||||
struct attribute_group ***intel_vgpu_type_groups)
|
||||
{
|
||||
*type_attrs = gvt_type_attrs;
|
||||
*intel_vgpu_type_groups = gvt_vgpu_type_groups;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool intel_gvt_init_vgpu_type_groups(struct intel_gvt *gvt)
|
||||
{
|
||||
int i, j;
|
||||
struct intel_vgpu_type *type;
|
||||
struct attribute_group *group;
|
||||
|
||||
for (i = 0; i < gvt->num_types; i++) {
|
||||
type = &gvt->types[i];
|
||||
|
||||
group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL);
|
||||
if (WARN_ON(!group))
|
||||
goto unwind;
|
||||
|
||||
group->name = type->name;
|
||||
group->attrs = gvt_type_attrs;
|
||||
gvt_vgpu_type_groups[i] = group;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
unwind:
|
||||
for (j = 0; j < i; j++) {
|
||||
group = gvt_vgpu_type_groups[j];
|
||||
kfree(group);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void intel_gvt_cleanup_vgpu_type_groups(struct intel_gvt *gvt)
|
||||
{
|
||||
int i;
|
||||
struct attribute_group *group;
|
||||
|
||||
for (i = 0; i < gvt->num_types; i++) {
|
||||
group = gvt_vgpu_type_groups[i];
|
||||
gvt_vgpu_type_groups[i] = NULL;
|
||||
kfree(group);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct intel_gvt_ops intel_gvt_ops = {
|
||||
.emulate_cfg_read = intel_vgpu_emulate_cfg_read,
|
||||
.emulate_cfg_write = intel_vgpu_emulate_cfg_write,
|
||||
@@ -54,6 +179,8 @@ static const struct intel_gvt_ops intel_gvt_ops = {
|
||||
.vgpu_reset = intel_gvt_reset_vgpu,
|
||||
.vgpu_activate = intel_gvt_activate_vgpu,
|
||||
.vgpu_deactivate = intel_gvt_deactivate_vgpu,
|
||||
.gvt_find_vgpu_type = intel_gvt_find_vgpu_type,
|
||||
.get_gvt_attrs = intel_get_gvt_attrs,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -191,17 +318,18 @@ void intel_gvt_clean_device(struct drm_i915_private *dev_priv)
|
||||
if (WARN_ON(!gvt))
|
||||
return;
|
||||
|
||||
intel_gvt_debugfs_clean(gvt);
|
||||
clean_service_thread(gvt);
|
||||
intel_gvt_clean_cmd_parser(gvt);
|
||||
intel_gvt_clean_sched_policy(gvt);
|
||||
intel_gvt_clean_workload_scheduler(gvt);
|
||||
intel_gvt_clean_opregion(gvt);
|
||||
intel_gvt_clean_gtt(gvt);
|
||||
intel_gvt_clean_irq(gvt);
|
||||
intel_gvt_clean_mmio_info(gvt);
|
||||
intel_gvt_free_firmware(gvt);
|
||||
|
||||
intel_gvt_hypervisor_host_exit(&dev_priv->drm.pdev->dev, gvt);
|
||||
intel_gvt_cleanup_vgpu_type_groups(gvt);
|
||||
intel_gvt_clean_vgpu_types(gvt);
|
||||
|
||||
idr_destroy(&gvt->vgpu_idr);
|
||||
@@ -268,13 +396,9 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
|
||||
if (ret)
|
||||
goto out_clean_irq;
|
||||
|
||||
ret = intel_gvt_init_opregion(gvt);
|
||||
if (ret)
|
||||
goto out_clean_gtt;
|
||||
|
||||
ret = intel_gvt_init_workload_scheduler(gvt);
|
||||
if (ret)
|
||||
goto out_clean_opregion;
|
||||
goto out_clean_gtt;
|
||||
|
||||
ret = intel_gvt_init_sched_policy(gvt);
|
||||
if (ret)
|
||||
@@ -292,6 +416,12 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
|
||||
if (ret)
|
||||
goto out_clean_thread;
|
||||
|
||||
ret = intel_gvt_init_vgpu_type_groups(gvt);
|
||||
if (ret == false) {
|
||||
gvt_err("failed to init vgpu type groups: %d\n", ret);
|
||||
goto out_clean_types;
|
||||
}
|
||||
|
||||
ret = intel_gvt_hypervisor_host_init(&dev_priv->drm.pdev->dev, gvt,
|
||||
&intel_gvt_ops);
|
||||
if (ret) {
|
||||
@@ -307,6 +437,10 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
|
||||
}
|
||||
gvt->idle_vgpu = vgpu;
|
||||
|
||||
ret = intel_gvt_debugfs_init(gvt);
|
||||
if (ret)
|
||||
gvt_err("debugfs registeration failed, go on.\n");
|
||||
|
||||
gvt_dbg_core("gvt device initialization is done\n");
|
||||
dev_priv->gvt = gvt;
|
||||
return 0;
|
||||
@@ -321,8 +455,6 @@ out_clean_sched_policy:
|
||||
intel_gvt_clean_sched_policy(gvt);
|
||||
out_clean_workload_scheduler:
|
||||
intel_gvt_clean_workload_scheduler(gvt);
|
||||
out_clean_opregion:
|
||||
intel_gvt_clean_opregion(gvt);
|
||||
out_clean_gtt:
|
||||
intel_gvt_clean_gtt(gvt);
|
||||
out_clean_irq:
|
||||
|
||||
@@ -125,7 +125,6 @@ struct intel_vgpu_irq {
|
||||
struct intel_vgpu_opregion {
|
||||
void *va;
|
||||
u32 gfn[INTEL_GVT_OPREGION_PAGES];
|
||||
struct page *pages[INTEL_GVT_OPREGION_PAGES];
|
||||
};
|
||||
|
||||
#define vgpu_opregion(vgpu) (&(vgpu->opregion))
|
||||
@@ -142,6 +141,33 @@ struct vgpu_sched_ctl {
|
||||
int weight;
|
||||
};
|
||||
|
||||
enum {
|
||||
INTEL_VGPU_EXECLIST_SUBMISSION = 1,
|
||||
INTEL_VGPU_GUC_SUBMISSION,
|
||||
};
|
||||
|
||||
struct intel_vgpu_submission_ops {
|
||||
const char *name;
|
||||
int (*init)(struct intel_vgpu *vgpu);
|
||||
void (*clean)(struct intel_vgpu *vgpu);
|
||||
void (*reset)(struct intel_vgpu *vgpu, unsigned long engine_mask);
|
||||
};
|
||||
|
||||
struct intel_vgpu_submission {
|
||||
struct intel_vgpu_execlist execlist[I915_NUM_ENGINES];
|
||||
struct list_head workload_q_head[I915_NUM_ENGINES];
|
||||
struct kmem_cache *workloads;
|
||||
atomic_t running_workload_num;
|
||||
struct i915_gem_context *shadow_ctx;
|
||||
DECLARE_BITMAP(shadow_ctx_desc_updated, I915_NUM_ENGINES);
|
||||
DECLARE_BITMAP(tlb_handle_pending, I915_NUM_ENGINES);
|
||||
void *ring_scan_buffer[I915_NUM_ENGINES];
|
||||
int ring_scan_buffer_size[I915_NUM_ENGINES];
|
||||
const struct intel_vgpu_submission_ops *ops;
|
||||
int virtual_submission_interface;
|
||||
bool active;
|
||||
};
|
||||
|
||||
struct intel_vgpu {
|
||||
struct intel_gvt *gvt;
|
||||
int id;
|
||||
@@ -161,16 +187,10 @@ struct intel_vgpu {
|
||||
struct intel_vgpu_gtt gtt;
|
||||
struct intel_vgpu_opregion opregion;
|
||||
struct intel_vgpu_display display;
|
||||
struct intel_vgpu_execlist execlist[I915_NUM_ENGINES];
|
||||
struct list_head workload_q_head[I915_NUM_ENGINES];
|
||||
struct kmem_cache *workloads;
|
||||
atomic_t running_workload_num;
|
||||
/* 1/2K for each reserve ring buffer */
|
||||
void *reserve_ring_buffer_va[I915_NUM_ENGINES];
|
||||
int reserve_ring_buffer_size[I915_NUM_ENGINES];
|
||||
DECLARE_BITMAP(tlb_handle_pending, I915_NUM_ENGINES);
|
||||
struct i915_gem_context *shadow_ctx;
|
||||
DECLARE_BITMAP(shadow_ctx_desc_updated, I915_NUM_ENGINES);
|
||||
struct intel_vgpu_submission submission;
|
||||
u32 hws_pga[I915_NUM_ENGINES];
|
||||
|
||||
struct dentry *debugfs;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_I915_GVT_KVMGT)
|
||||
struct {
|
||||
@@ -190,6 +210,10 @@ struct intel_vgpu {
|
||||
#endif
|
||||
};
|
||||
|
||||
/* validating GM healthy status*/
|
||||
#define vgpu_is_vm_unhealthy(ret_val) \
|
||||
(((ret_val) == -EBADRQC) || ((ret_val) == -EFAULT))
|
||||
|
||||
struct intel_gvt_gm {
|
||||
unsigned long vgpu_allocated_low_gm_size;
|
||||
unsigned long vgpu_allocated_high_gm_size;
|
||||
@@ -231,7 +255,7 @@ struct intel_gvt_mmio {
|
||||
unsigned int num_mmio_block;
|
||||
|
||||
DECLARE_HASHTABLE(mmio_info_table, INTEL_GVT_MMIO_HASH_BITS);
|
||||
unsigned int num_tracked_mmio;
|
||||
unsigned long num_tracked_mmio;
|
||||
};
|
||||
|
||||
struct intel_gvt_firmware {
|
||||
@@ -240,11 +264,6 @@ struct intel_gvt_firmware {
|
||||
bool firmware_loaded;
|
||||
};
|
||||
|
||||
struct intel_gvt_opregion {
|
||||
void *opregion_va;
|
||||
u32 opregion_pa;
|
||||
};
|
||||
|
||||
#define NR_MAX_INTEL_VGPU_TYPES 20
|
||||
struct intel_vgpu_type {
|
||||
char name[16];
|
||||
@@ -268,7 +287,6 @@ struct intel_gvt {
|
||||
struct intel_gvt_firmware firmware;
|
||||
struct intel_gvt_irq irq;
|
||||
struct intel_gvt_gtt gtt;
|
||||
struct intel_gvt_opregion opregion;
|
||||
struct intel_gvt_workload_scheduler scheduler;
|
||||
struct notifier_block shadow_ctx_notifier_block[I915_NUM_ENGINES];
|
||||
DECLARE_HASHTABLE(cmd_table, GVT_CMD_HASH_BITS);
|
||||
@@ -279,6 +297,8 @@ struct intel_gvt {
|
||||
struct task_struct *service_thread;
|
||||
wait_queue_head_t service_thread_wq;
|
||||
unsigned long service_request;
|
||||
|
||||
struct dentry *debugfs_root;
|
||||
};
|
||||
|
||||
static inline struct intel_gvt *to_gvt(struct drm_i915_private *i915)
|
||||
@@ -484,9 +504,6 @@ static inline u64 intel_vgpu_get_bar_gpa(struct intel_vgpu *vgpu, int bar)
|
||||
PCI_BASE_ADDRESS_MEM_MASK;
|
||||
}
|
||||
|
||||
void intel_gvt_clean_opregion(struct intel_gvt *gvt);
|
||||
int intel_gvt_init_opregion(struct intel_gvt *gvt);
|
||||
|
||||
void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu);
|
||||
int intel_vgpu_init_opregion(struct intel_vgpu *vgpu, u32 gpa);
|
||||
|
||||
@@ -494,6 +511,7 @@ int intel_vgpu_emulate_opregion_request(struct intel_vgpu *vgpu, u32 swsci);
|
||||
void populate_pvinfo_page(struct intel_vgpu *vgpu);
|
||||
|
||||
int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload);
|
||||
void enter_failsafe_mode(struct intel_vgpu *vgpu, int reason);
|
||||
|
||||
struct intel_gvt_ops {
|
||||
int (*emulate_cfg_read)(struct intel_vgpu *, unsigned int, void *,
|
||||
@@ -510,12 +528,17 @@ struct intel_gvt_ops {
|
||||
void (*vgpu_reset)(struct intel_vgpu *);
|
||||
void (*vgpu_activate)(struct intel_vgpu *);
|
||||
void (*vgpu_deactivate)(struct intel_vgpu *);
|
||||
struct intel_vgpu_type *(*gvt_find_vgpu_type)(struct intel_gvt *gvt,
|
||||
const char *name);
|
||||
bool (*get_gvt_attrs)(struct attribute ***type_attrs,
|
||||
struct attribute_group ***intel_vgpu_type_groups);
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
GVT_FAILSAFE_UNSUPPORTED_GUEST,
|
||||
GVT_FAILSAFE_INSUFFICIENT_RESOURCE,
|
||||
GVT_FAILSAFE_GUEST_ERR,
|
||||
};
|
||||
|
||||
static inline void mmio_hw_access_pre(struct drm_i915_private *dev_priv)
|
||||
@@ -591,6 +614,12 @@ static inline bool intel_gvt_mmio_has_mode_mask(
|
||||
return gvt->mmio.mmio_attribute[offset >> 2] & F_MODE_MASK;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
#include "trace.h"
|
||||
#include "mpt.h"
|
||||
|
||||
|
||||
@@ -137,17 +137,26 @@ static int new_mmio_info(struct intel_gvt *gvt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int render_mmio_to_ring_id(struct intel_gvt *gvt, unsigned int reg)
|
||||
/**
|
||||
* intel_gvt_render_mmio_to_ring_id - convert a mmio offset into ring id
|
||||
* @gvt: a GVT device
|
||||
* @offset: register offset
|
||||
*
|
||||
* Returns:
|
||||
* Ring ID on success, negative error code if failed.
|
||||
*/
|
||||
int intel_gvt_render_mmio_to_ring_id(struct intel_gvt *gvt,
|
||||
unsigned int offset)
|
||||
{
|
||||
enum intel_engine_id id;
|
||||
struct intel_engine_cs *engine;
|
||||
|
||||
reg &= ~GENMASK(11, 0);
|
||||
offset &= ~GENMASK(11, 0);
|
||||
for_each_engine(engine, gvt->dev_priv, id) {
|
||||
if (engine->mmio_base == reg)
|
||||
if (engine->mmio_base == offset)
|
||||
return id;
|
||||
}
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#define offset_to_fence_num(offset) \
|
||||
@@ -157,7 +166,7 @@ static int render_mmio_to_ring_id(struct intel_gvt *gvt, unsigned int reg)
|
||||
(num * 8 + i915_mmio_reg_offset(FENCE_REG_GEN6_LO(0)))
|
||||
|
||||
|
||||
static void enter_failsafe_mode(struct intel_vgpu *vgpu, int reason)
|
||||
void enter_failsafe_mode(struct intel_vgpu *vgpu, int reason)
|
||||
{
|
||||
switch (reason) {
|
||||
case GVT_FAILSAFE_UNSUPPORTED_GUEST:
|
||||
@@ -165,6 +174,8 @@ static void enter_failsafe_mode(struct intel_vgpu *vgpu, int reason)
|
||||
break;
|
||||
case GVT_FAILSAFE_INSUFFICIENT_RESOURCE:
|
||||
pr_err("Graphics resource is not enough for the guest\n");
|
||||
case GVT_FAILSAFE_GUEST_ERR:
|
||||
pr_err("GVT Internal error for the guest\n");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1369,6 +1380,34 @@ static int mailbox_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
return intel_vgpu_default_mmio_write(vgpu, offset, &value, bytes);
|
||||
}
|
||||
|
||||
static int hws_pga_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
void *p_data, unsigned int bytes)
|
||||
{
|
||||
u32 value = *(u32 *)p_data;
|
||||
int ring_id = intel_gvt_render_mmio_to_ring_id(vgpu->gvt, offset);
|
||||
|
||||
if (!intel_gvt_ggtt_validate_range(vgpu, value, I915_GTT_PAGE_SIZE)) {
|
||||
gvt_vgpu_err("VM(%d) write invalid HWSP address, reg:0x%x, value:0x%x\n",
|
||||
vgpu->id, offset, value);
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* Need to emulate all the HWSP register write to ensure host can
|
||||
* update the VM CSB status correctly. Here listed registers can
|
||||
* support BDW, SKL or other platforms with same HWSP registers.
|
||||
*/
|
||||
if (unlikely(ring_id < 0 || ring_id > I915_NUM_ENGINES)) {
|
||||
gvt_vgpu_err("VM(%d) access unknown hardware status page register:0x%x\n",
|
||||
vgpu->id, offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
vgpu->hws_pga[ring_id] = value;
|
||||
gvt_dbg_mmio("VM(%d) write: 0x%x to HWSP: 0x%x\n",
|
||||
vgpu->id, value, offset);
|
||||
|
||||
return intel_vgpu_default_mmio_write(vgpu, offset, &value, bytes);
|
||||
}
|
||||
|
||||
static int skl_power_well_ctl_write(struct intel_vgpu *vgpu,
|
||||
unsigned int offset, void *p_data, unsigned int bytes)
|
||||
{
|
||||
@@ -1398,18 +1437,36 @@ static int skl_lcpll_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
static int mmio_read_from_hw(struct intel_vgpu *vgpu,
|
||||
unsigned int offset, void *p_data, unsigned int bytes)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
|
||||
struct intel_gvt *gvt = vgpu->gvt;
|
||||
struct drm_i915_private *dev_priv = gvt->dev_priv;
|
||||
int ring_id;
|
||||
u32 ring_base;
|
||||
|
||||
ring_id = intel_gvt_render_mmio_to_ring_id(gvt, offset);
|
||||
/**
|
||||
* Read HW reg in following case
|
||||
* a. the offset isn't a ring mmio
|
||||
* b. the offset's ring is running on hw.
|
||||
* c. the offset is ring time stamp mmio
|
||||
*/
|
||||
if (ring_id >= 0)
|
||||
ring_base = dev_priv->engine[ring_id]->mmio_base;
|
||||
|
||||
if (ring_id < 0 || vgpu == gvt->scheduler.engine_owner[ring_id] ||
|
||||
offset == i915_mmio_reg_offset(RING_TIMESTAMP(ring_base)) ||
|
||||
offset == i915_mmio_reg_offset(RING_TIMESTAMP_UDW(ring_base))) {
|
||||
mmio_hw_access_pre(dev_priv);
|
||||
vgpu_vreg(vgpu, offset) = I915_READ(_MMIO(offset));
|
||||
mmio_hw_access_post(dev_priv);
|
||||
}
|
||||
|
||||
mmio_hw_access_pre(dev_priv);
|
||||
vgpu_vreg(vgpu, offset) = I915_READ(_MMIO(offset));
|
||||
mmio_hw_access_post(dev_priv);
|
||||
return intel_vgpu_default_mmio_read(vgpu, offset, p_data, bytes);
|
||||
}
|
||||
|
||||
static int elsp_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
void *p_data, unsigned int bytes)
|
||||
{
|
||||
int ring_id = render_mmio_to_ring_id(vgpu->gvt, offset);
|
||||
int ring_id = intel_gvt_render_mmio_to_ring_id(vgpu->gvt, offset);
|
||||
struct intel_vgpu_execlist *execlist;
|
||||
u32 data = *(u32 *)p_data;
|
||||
int ret = 0;
|
||||
@@ -1417,9 +1474,9 @@ static int elsp_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
if (WARN_ON(ring_id < 0 || ring_id > I915_NUM_ENGINES - 1))
|
||||
return -EINVAL;
|
||||
|
||||
execlist = &vgpu->execlist[ring_id];
|
||||
execlist = &vgpu->submission.execlist[ring_id];
|
||||
|
||||
execlist->elsp_dwords.data[execlist->elsp_dwords.index] = data;
|
||||
execlist->elsp_dwords.data[3 - execlist->elsp_dwords.index] = data;
|
||||
if (execlist->elsp_dwords.index == 3) {
|
||||
ret = intel_vgpu_submit_execlist(vgpu, ring_id);
|
||||
if(ret)
|
||||
@@ -1435,9 +1492,11 @@ static int elsp_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
static int ring_mode_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
void *p_data, unsigned int bytes)
|
||||
{
|
||||
struct intel_vgpu_submission *s = &vgpu->submission;
|
||||
u32 data = *(u32 *)p_data;
|
||||
int ring_id = render_mmio_to_ring_id(vgpu->gvt, offset);
|
||||
int ring_id = intel_gvt_render_mmio_to_ring_id(vgpu->gvt, offset);
|
||||
bool enable_execlist;
|
||||
int ret;
|
||||
|
||||
write_vreg(vgpu, offset, p_data, bytes);
|
||||
|
||||
@@ -1459,8 +1518,18 @@ static int ring_mode_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
(enable_execlist ? "enabling" : "disabling"),
|
||||
ring_id);
|
||||
|
||||
if (enable_execlist)
|
||||
intel_vgpu_start_schedule(vgpu);
|
||||
if (!enable_execlist)
|
||||
return 0;
|
||||
|
||||
if (s->active)
|
||||
return 0;
|
||||
|
||||
ret = intel_vgpu_select_submission_ops(vgpu,
|
||||
INTEL_VGPU_EXECLIST_SUBMISSION);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
intel_vgpu_start_schedule(vgpu);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1492,7 +1561,7 @@ static int gvt_reg_tlb_control_handler(struct intel_vgpu *vgpu,
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
set_bit(id, (void *)vgpu->tlb_handle_pending);
|
||||
set_bit(id, (void *)vgpu->submission.tlb_handle_pending);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2478,7 +2547,7 @@ static int init_broadwell_mmio_info(struct intel_gvt *gvt)
|
||||
MMIO_RING_F(RING_REG, 32, 0, 0, 0, D_BDW_PLUS, NULL, NULL);
|
||||
#undef RING_REG
|
||||
|
||||
MMIO_RING_GM_RDR(RING_HWS_PGA, D_BDW_PLUS, NULL, NULL);
|
||||
MMIO_RING_GM_RDR(RING_HWS_PGA, D_BDW_PLUS, NULL, hws_pga_write);
|
||||
|
||||
MMIO_DFH(HDC_CHICKEN0, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
|
||||
|
||||
@@ -2879,14 +2948,46 @@ int intel_gvt_setup_mmio_info(struct intel_gvt *gvt)
|
||||
gvt->mmio.mmio_block = mmio_blocks;
|
||||
gvt->mmio.num_mmio_block = ARRAY_SIZE(mmio_blocks);
|
||||
|
||||
gvt_dbg_mmio("traced %u virtual mmio registers\n",
|
||||
gvt->mmio.num_tracked_mmio);
|
||||
return 0;
|
||||
err:
|
||||
intel_gvt_clean_mmio_info(gvt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_gvt_for_each_tracked_mmio - iterate each tracked mmio
|
||||
* @gvt: a GVT device
|
||||
* @handler: the handler
|
||||
* @data: private data given to handler
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative error code if failed.
|
||||
*/
|
||||
int intel_gvt_for_each_tracked_mmio(struct intel_gvt *gvt,
|
||||
int (*handler)(struct intel_gvt *gvt, u32 offset, void *data),
|
||||
void *data)
|
||||
{
|
||||
struct gvt_mmio_block *block = gvt->mmio.mmio_block;
|
||||
struct intel_gvt_mmio_info *e;
|
||||
int i, j, ret;
|
||||
|
||||
hash_for_each(gvt->mmio.mmio_info_table, i, e, node) {
|
||||
ret = handler(gvt, e->offset, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < gvt->mmio.num_mmio_block; i++, block++) {
|
||||
for (j = 0; j < block->size; j += 4) {
|
||||
ret = handler(gvt,
|
||||
INTEL_GVT_MMIO_OFFSET(block->offset) + j,
|
||||
data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_vgpu_default_mmio_read - default MMIO read handler
|
||||
|
||||
@@ -248,120 +248,6 @@ static void gvt_cache_destroy(struct intel_vgpu *vgpu)
|
||||
}
|
||||
}
|
||||
|
||||
static struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
struct intel_vgpu_type *t;
|
||||
const char *driver_name = dev_driver_string(
|
||||
&gvt->dev_priv->drm.pdev->dev);
|
||||
|
||||
for (i = 0; i < gvt->num_types; i++) {
|
||||
t = &gvt->types[i];
|
||||
if (!strncmp(t->name, name + strlen(driver_name) + 1,
|
||||
sizeof(t->name)))
|
||||
return t;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t available_instances_show(struct kobject *kobj,
|
||||
struct device *dev, char *buf)
|
||||
{
|
||||
struct intel_vgpu_type *type;
|
||||
unsigned int num = 0;
|
||||
void *gvt = kdev_to_i915(dev)->gvt;
|
||||
|
||||
type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
|
||||
if (!type)
|
||||
num = 0;
|
||||
else
|
||||
num = type->avail_instance;
|
||||
|
||||
return sprintf(buf, "%u\n", num);
|
||||
}
|
||||
|
||||
static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING);
|
||||
}
|
||||
|
||||
static ssize_t description_show(struct kobject *kobj, struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct intel_vgpu_type *type;
|
||||
void *gvt = kdev_to_i915(dev)->gvt;
|
||||
|
||||
type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
|
||||
if (!type)
|
||||
return 0;
|
||||
|
||||
return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n"
|
||||
"fence: %d\nresolution: %s\n"
|
||||
"weight: %d\n",
|
||||
BYTES_TO_MB(type->low_gm_size),
|
||||
BYTES_TO_MB(type->high_gm_size),
|
||||
type->fence, vgpu_edid_str(type->resolution),
|
||||
type->weight);
|
||||
}
|
||||
|
||||
static MDEV_TYPE_ATTR_RO(available_instances);
|
||||
static MDEV_TYPE_ATTR_RO(device_api);
|
||||
static MDEV_TYPE_ATTR_RO(description);
|
||||
|
||||
static struct attribute *type_attrs[] = {
|
||||
&mdev_type_attr_available_instances.attr,
|
||||
&mdev_type_attr_device_api.attr,
|
||||
&mdev_type_attr_description.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group *intel_vgpu_type_groups[] = {
|
||||
[0 ... NR_MAX_INTEL_VGPU_TYPES - 1] = NULL,
|
||||
};
|
||||
|
||||
static bool intel_gvt_init_vgpu_type_groups(struct intel_gvt *gvt)
|
||||
{
|
||||
int i, j;
|
||||
struct intel_vgpu_type *type;
|
||||
struct attribute_group *group;
|
||||
|
||||
for (i = 0; i < gvt->num_types; i++) {
|
||||
type = &gvt->types[i];
|
||||
|
||||
group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL);
|
||||
if (WARN_ON(!group))
|
||||
goto unwind;
|
||||
|
||||
group->name = type->name;
|
||||
group->attrs = type_attrs;
|
||||
intel_vgpu_type_groups[i] = group;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
unwind:
|
||||
for (j = 0; j < i; j++) {
|
||||
group = intel_vgpu_type_groups[j];
|
||||
kfree(group);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void intel_gvt_cleanup_vgpu_type_groups(struct intel_gvt *gvt)
|
||||
{
|
||||
int i;
|
||||
struct attribute_group *group;
|
||||
|
||||
for (i = 0; i < gvt->num_types; i++) {
|
||||
group = intel_vgpu_type_groups[i];
|
||||
kfree(group);
|
||||
}
|
||||
}
|
||||
|
||||
static void kvmgt_protect_table_init(struct kvmgt_guest_info *info)
|
||||
{
|
||||
hash_init(info->ptable);
|
||||
@@ -441,7 +327,7 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev)
|
||||
pdev = mdev_parent_dev(mdev);
|
||||
gvt = kdev_to_i915(pdev)->gvt;
|
||||
|
||||
type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
|
||||
type = intel_gvt_ops->gvt_find_vgpu_type(gvt, kobject_name(kobj));
|
||||
if (!type) {
|
||||
gvt_vgpu_err("failed to find type %s to create\n",
|
||||
kobject_name(kobj));
|
||||
@@ -1188,7 +1074,7 @@ hw_id_show(struct device *dev, struct device_attribute *attr,
|
||||
struct intel_vgpu *vgpu = (struct intel_vgpu *)
|
||||
mdev_get_drvdata(mdev);
|
||||
return sprintf(buf, "%u\n",
|
||||
vgpu->shadow_ctx->hw_id);
|
||||
vgpu->submission.shadow_ctx->hw_id);
|
||||
}
|
||||
return sprintf(buf, "\n");
|
||||
}
|
||||
@@ -1212,8 +1098,7 @@ static const struct attribute_group *intel_vgpu_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct mdev_parent_ops intel_vgpu_ops = {
|
||||
.supported_type_groups = intel_vgpu_type_groups,
|
||||
static struct mdev_parent_ops intel_vgpu_ops = {
|
||||
.mdev_attr_groups = intel_vgpu_groups,
|
||||
.create = intel_vgpu_create,
|
||||
.remove = intel_vgpu_remove,
|
||||
@@ -1229,17 +1114,20 @@ static const struct mdev_parent_ops intel_vgpu_ops = {
|
||||
|
||||
static int kvmgt_host_init(struct device *dev, void *gvt, const void *ops)
|
||||
{
|
||||
if (!intel_gvt_init_vgpu_type_groups(gvt))
|
||||
return -EFAULT;
|
||||
struct attribute **kvm_type_attrs;
|
||||
struct attribute_group **kvm_vgpu_type_groups;
|
||||
|
||||
intel_gvt_ops = ops;
|
||||
if (!intel_gvt_ops->get_gvt_attrs(&kvm_type_attrs,
|
||||
&kvm_vgpu_type_groups))
|
||||
return -EFAULT;
|
||||
intel_vgpu_ops.supported_type_groups = kvm_vgpu_type_groups;
|
||||
|
||||
return mdev_register_device(dev, &intel_vgpu_ops);
|
||||
}
|
||||
|
||||
static void kvmgt_host_exit(struct device *dev, void *gvt)
|
||||
{
|
||||
intel_gvt_cleanup_vgpu_type_groups(gvt);
|
||||
mdev_unregister_device(dev);
|
||||
}
|
||||
|
||||
|
||||
Loaded 20 of 129 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user