All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 00/29] iGVT-g implementation in i915
@ 2016-01-28 10:21 Zhi Wang
  2016-01-28 10:21 ` [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g Zhi Wang
                   ` (29 more replies)
  0 siblings, 30 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This patchset implements the core part of Intel GVT-g [1] for graphics
virtualization. The patchset consists of two subsets: One is the
device model implementation of vGPUs for virtual machines (patch 09 -
29) Another is the needed i915 native driver changes for that
implementation (patch 01 - 08). We hope to get feedbacks of the native
driver changes from i915 developers, while the device model part can
be a reference to see how we utilize those changes.

Background
----------

Back to 1 year ago, we ever sent RFC of iGVT-g changes to native i915
drivers, so called "host mediation"[2]. The architecture is that host
i915 driver runs on top of iGVT-g device model, and device model
controls hardware directly if it is enabled. After discussion, we
agreed an architecture change to let native driver on host controls
hardware directly, and integrate virtualization changes into i915.

Last year we followed this direction to remove host mediation, and
move some virtualization related logics into i915. For instance, the
interrupt part [3]. Later we found that the i915 changes can be much
reduced if we virtualize more resources for VMs. Now we are happy to
see that the i915 changes are very limited.

Major i915 changes
------------------

In the new architecture, device-model works as a client. We do not
mediate any i915 accesses of hardware resources. VM's vGPU resources
keep virtual as much as possible. One example is interrupt. vGPU's
interrupt will be triggered either through virtual timer (vblnk) or
workload status changes (ctx_switch), not directly bound to hardware
interrupts. Hence we do not need to touch i915 interrupt framework at
all.

The remaining i915 changes are:

- vGPU guest framebuffer GEM object support

Wrap a guest framebuffer into a host i915 GEM object. So host graphics
application could be able to access guest display surface easily via
DRM/GL APIs.

Related commits:

drm/i915: Support vGPU guest framebuffer GEM object

- Host i915 GGTT graphics memory space/fence registers balloon

i915 host owns limited GGTT graphics memory space/fence registers
under GVT environment, others are managed by GVT resource allocator,
which allocates/de-allocates these resources for GVT guest.

Related commits:

drm/i915: Introduce host graphics memory balloon

- GVT context creation

GVT workload scheduler needs special host LRC contexts, so called
"shadow LRC context" to submit guest workload to host i915. During the
guest workload submission. GVT fills the shadow LRC context with the
content guest LRC context: engine context is copied without changes,
ring context is mostly owned by host i915, except the PPGTT root
pointers, which will be filled with the shadow PPGTT page table root
pointers managed by GVT-g.

Related commits:

drm/i915: gem: Introduce i915_gem_create_gvt_context()
drm/i915: Ondemand populate context addressing mode bit
drm/i915: Do not initialize the engine state of GVT context
drm/i915: Do not populate PPGTT root pointers for GVT context

- GVT context scheduling

Since GVT guest workload will also be dispatched through i915 GEM
submission system, the GVT context mentioned above is also scheduled
by host i915 LRC routines. The workload inside a GVT context may come
from different GVT guests, some render MMIOs have to be configured
with the guest render MMIOs before the GVT context gets kicked out.
It's hard to submit a GVT context with a host LRC context in the same
ELSP combo.

The LRC context submission policy for GVT context is adjusted as:

 * If ELSP submission routines pick a GVT context, then stop to pick
   next context. (Single ELSP submission - for easy render MMIOs save/restore)

 * If ELSP submission routines pick a i915 context, and the next
   context is a GVT context, then stop pick the next context.  (Single
   ELSP submission - we cannot skip the GVT context, as the seqno of
   workload in GVT context may be passed, but the workload in GVT context
   haven't be executed yet)

Related commits:
drm/i915: GVT context scheduling

Difference from community release
---------------------------------

This patchset is different from regular iGVT-g code release[4], which
is still based on old host-mediated architecture. Furthermore, this
patchset only supports BDW whereas code release supports HSW/BDW/SKL.
We will add SKL support later based on this RFC code and HSW support
will be dropped.

Internally we tested this RFC patchset with both linux and windows VM
and the architecture changes work fine.

Acknowledgement
---------------

iGVT-g implementation is several years effort and many people
contributed to the code. There names are not here yet. In later formal
patchset we will reflect individual's contribution.

Meanwhile, in the previous iGVT-g related discussion, Daniel, Chris
and Joonas ever gave very good inputs. We appreciate them and look
forward to more comments/suggestions from community.

We are trying to get more familiar with i915 and willing to adopt
suggestions to keep improving. We hope to work with community together
to make iGVT-g a great component in i915 to support graphics 
virtualization. Thanks!

Reference
---------

[1] https://01.org/igvt-g
[2] http://lists.freedesktop.org/archives/intel-gfx/2014-September/053098.html
[3] http://lists.freedesktop.org/archives/intel-gfx/2015-September/075397.html
[4] http://lists.freedesktop.org/archives/intel-gfx/2016-January/086372.html
*** BLURB HERE ***

Bing Niu (2):
  drm/i915: Introduce host graphics memory balloon for gvt
  drm/i915: gvt: Full display virtualization

Niu Bing (1):
  drm/i915: gvt: vGPU framebuffer format decoder

Niu,Bing (1):
  drm/i915: gvt: vGPU MMIO register emulation

Yi Sun (1):
  drm/i915: gvt: Introduce GVT control interface

Yulei Zhang (2):
  drm/i915: gvt: Resource allocator
  drm/i915: gvt: vGPU command scanner

Zhi Wang (21):
  drm/i915/gvt: Introduce the basic architecture of GVT-g
  drm/i915: Introduce GVT context creation API
  drm/i915: Ondemand populate context addressing mode bit
  drm/i915: Do not populate PPGTT root pointers for GVT context
  drm/i915: Do not initialize the engine state of GVT context
  drm/i915: GVT context scheduling
  drm/i915: gvt: Basic mmio emulation state
  drm/i915: gvt: update PVINFO page definition in i915_vgpu.h
  drm/i915: gvt: vGPU life cycle management
  drm/i915: gvt: trace stub
  drm/i915: gvt: vGPU interrupt emulation framework
  drm/i915: gvt: vGPU graphics memory emulation framework
  drm/i915: gvt: Generic MPT framework
  gvt: Xen hypervisor GVT-g MPT module
  drm/i915: gvt: vGPU configuration emulation
  drm/i915: gvt: vGPU OpRegion emulation
  drm/i915: gvt: Full execlist status emulation
  drm/i915: gvt: vGPU execlist workload submission
  drm/i915: gvt: workload scheduler
  drm/i915: gvt: vGPU schedule policy framework
  drm/i915: gvt: vGPU context switch

Zhiyuan Lv (1):
  drm/i915: Support vGPU guest framebuffer GEM object

 arch/x86/include/asm/xen/hypercall.h      |    7 +
 arch/x86/include/asm/xen/interface.h      |    4 +
 arch/x86/xen/mmu.c                        |   83 ++
 drivers/gpu/drm/i915/Kconfig              |   16 +
 drivers/gpu/drm/i915/Makefile             |    3 +
 drivers/gpu/drm/i915/gvt/Makefile         |    8 +
 drivers/gpu/drm/i915/gvt/aperture_gm.c    |  225 +++
 drivers/gpu/drm/i915/gvt/cfg_space.c      |  190 +++
 drivers/gpu/drm/i915/gvt/cfg_space.h      |   33 +
 drivers/gpu/drm/i915/gvt/cmd_parser.c     | 2018 +++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/cmd_parser.h     |  466 +++++++
 drivers/gpu/drm/i915/gvt/control.c        |  181 +++
 drivers/gpu/drm/i915/gvt/debug.h          |  103 ++
 drivers/gpu/drm/i915/gvt/display.c        |  233 ++++
 drivers/gpu/drm/i915/gvt/display.h        |  129 ++
 drivers/gpu/drm/i915/gvt/edid.c           |  493 +++++++
 drivers/gpu/drm/i915/gvt/edid.h           |  184 +++
 drivers/gpu/drm/i915/gvt/execlist.c       |  612 +++++++++
 drivers/gpu/drm/i915/gvt/execlist.h       |  179 +++
 drivers/gpu/drm/i915/gvt/fb_decoder.c     |  325 +++++
 drivers/gpu/drm/i915/gvt/fb_decoder.h     |  110 ++
 drivers/gpu/drm/i915/gvt/gtt.c            | 1912 ++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/gtt.h            |  305 ++++
 drivers/gpu/drm/i915/gvt/gvt.c            |  446 ++++++
 drivers/gpu/drm/i915/gvt/gvt.h            |  715 ++++++++++
 drivers/gpu/drm/i915/gvt/handlers.c       | 2141 +++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/hypercall.h      |   56 +
 drivers/gpu/drm/i915/gvt/instance.c       |  272 ++++
 drivers/gpu/drm/i915/gvt/interrupt.c      |  721 ++++++++++
 drivers/gpu/drm/i915/gvt/interrupt.h      |  257 ++++
 drivers/gpu/drm/i915/gvt/mmio.c           |  545 ++++++++
 drivers/gpu/drm/i915/gvt/mmio.h           |  105 ++
 drivers/gpu/drm/i915/gvt/mpt.h            |  169 +++
 drivers/gpu/drm/i915/gvt/opregion.c       |  314 +++++
 drivers/gpu/drm/i915/gvt/opregion.h       |   34 +
 drivers/gpu/drm/i915/gvt/params.c         |   54 +
 drivers/gpu/drm/i915/gvt/params.h         |   49 +
 drivers/gpu/drm/i915/gvt/perf.h           |   69 +
 drivers/gpu/drm/i915/gvt/reg.h            |  889 ++++++++++++
 drivers/gpu/drm/i915/gvt/render.c         |  104 ++
 drivers/gpu/drm/i915/gvt/render.h         |   31 +
 drivers/gpu/drm/i915/gvt/sched_policy.c   |  295 ++++
 drivers/gpu/drm/i915/gvt/sched_policy.h   |   48 +
 drivers/gpu/drm/i915/gvt/scheduler.c      |  501 +++++++
 drivers/gpu/drm/i915/gvt/scheduler.h      |   85 ++
 drivers/gpu/drm/i915/gvt/trace.h          |  260 ++++
 drivers/gpu/drm/i915/gvt/trace_points.c   |   29 +
 drivers/gpu/drm/i915/gvt/utility.c        |   91 ++
 drivers/gpu/drm/i915/i915_dma.c           |   20 +
 drivers/gpu/drm/i915/i915_drv.h           |   29 +
 drivers/gpu/drm/i915/i915_gem.c           |    3 +
 drivers/gpu/drm/i915/i915_gem_context.c   |   38 +
 drivers/gpu/drm/i915/i915_gem_gtt.c       |    4 +-
 drivers/gpu/drm/i915/i915_gem_gvtbuffer.c |  247 ++++
 drivers/gpu/drm/i915/i915_vgpu.c          |   16 +-
 drivers/gpu/drm/i915/i915_vgpu.h          |   94 +-
 drivers/gpu/drm/i915/intel_lrc.c          |   64 +-
 drivers/xen/Kconfig                       |    5 +
 drivers/xen/Makefile                      |    6 +
 drivers/xen/xengt.c                       | 1153 ++++++++++++++++
 include/uapi/drm/i915_drm.h               |   38 +
 include/xen/interface/hvm/hvm_op.h        |  177 ++-
 include/xen/interface/hvm/ioreq.h         |  132 ++
 include/xen/interface/memory.h            |   28 +
 include/xen/interface/xen.h               |  107 ++
 include/xen/xen-ops.h                     |    5 +
 66 files changed, 18222 insertions(+), 43 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/Makefile
 create mode 100644 drivers/gpu/drm/i915/gvt/aperture_gm.c
 create mode 100644 drivers/gpu/drm/i915/gvt/cfg_space.c
 create mode 100644 drivers/gpu/drm/i915/gvt/cfg_space.h
 create mode 100644 drivers/gpu/drm/i915/gvt/cmd_parser.c
 create mode 100644 drivers/gpu/drm/i915/gvt/cmd_parser.h
 create mode 100644 drivers/gpu/drm/i915/gvt/control.c
 create mode 100644 drivers/gpu/drm/i915/gvt/debug.h
 create mode 100644 drivers/gpu/drm/i915/gvt/display.c
 create mode 100644 drivers/gpu/drm/i915/gvt/display.h
 create mode 100644 drivers/gpu/drm/i915/gvt/edid.c
 create mode 100644 drivers/gpu/drm/i915/gvt/edid.h
 create mode 100644 drivers/gpu/drm/i915/gvt/execlist.c
 create mode 100644 drivers/gpu/drm/i915/gvt/execlist.h
 create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.c
 create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.h
 create mode 100644 drivers/gpu/drm/i915/gvt/gtt.c
 create mode 100644 drivers/gpu/drm/i915/gvt/gtt.h
 create mode 100644 drivers/gpu/drm/i915/gvt/gvt.c
 create mode 100644 drivers/gpu/drm/i915/gvt/gvt.h
 create mode 100644 drivers/gpu/drm/i915/gvt/handlers.c
 create mode 100644 drivers/gpu/drm/i915/gvt/hypercall.h
 create mode 100644 drivers/gpu/drm/i915/gvt/instance.c
 create mode 100644 drivers/gpu/drm/i915/gvt/interrupt.c
 create mode 100644 drivers/gpu/drm/i915/gvt/interrupt.h
 create mode 100644 drivers/gpu/drm/i915/gvt/mmio.c
 create mode 100644 drivers/gpu/drm/i915/gvt/mmio.h
 create mode 100644 drivers/gpu/drm/i915/gvt/mpt.h
 create mode 100644 drivers/gpu/drm/i915/gvt/opregion.c
 create mode 100644 drivers/gpu/drm/i915/gvt/opregion.h
 create mode 100644 drivers/gpu/drm/i915/gvt/params.c
 create mode 100644 drivers/gpu/drm/i915/gvt/params.h
 create mode 100644 drivers/gpu/drm/i915/gvt/perf.h
 create mode 100644 drivers/gpu/drm/i915/gvt/reg.h
 create mode 100644 drivers/gpu/drm/i915/gvt/render.c
 create mode 100644 drivers/gpu/drm/i915/gvt/render.h
 create mode 100644 drivers/gpu/drm/i915/gvt/sched_policy.c
 create mode 100644 drivers/gpu/drm/i915/gvt/sched_policy.h
 create mode 100644 drivers/gpu/drm/i915/gvt/scheduler.c
 create mode 100644 drivers/gpu/drm/i915/gvt/scheduler.h
 create mode 100644 drivers/gpu/drm/i915/gvt/trace.h
 create mode 100644 drivers/gpu/drm/i915/gvt/trace_points.c
 create mode 100644 drivers/gpu/drm/i915/gvt/utility.c
 create mode 100644 drivers/gpu/drm/i915/i915_gem_gvtbuffer.c
 create mode 100644 drivers/xen/xengt.c
 create mode 100644 include/xen/interface/hvm/ioreq.h

-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-29 13:57   ` Joonas Lahtinen
  2016-01-28 10:21 ` [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt Zhi Wang
                   ` (28 subsequent siblings)
  29 siblings, 1 reply; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This patch introduces the very basic framework of GVT-g device model,
includes basic prototypes, definitions, initialization.
---
 arch/x86/include/asm/xen/interface.h  |   3 +
 drivers/gpu/drm/i915/Kconfig          |  16 ++
 drivers/gpu/drm/i915/Makefile         |   2 +
 drivers/gpu/drm/i915/gvt/Makefile     |   5 +
 drivers/gpu/drm/i915/gvt/debug.h      |  72 +++++++
 drivers/gpu/drm/i915/gvt/fb_decoder.c |  34 ++++
 drivers/gpu/drm/i915/gvt/fb_decoder.h | 110 ++++++++++
 drivers/gpu/drm/i915/gvt/gvt.c        | 366 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/gvt.h        | 130 ++++++++++++
 drivers/gpu/drm/i915/gvt/hypercall.h  |  30 +++
 drivers/gpu/drm/i915/gvt/mpt.h        |  97 +++++++++
 drivers/gpu/drm/i915/gvt/params.c     |  29 +++
 drivers/gpu/drm/i915/gvt/params.h     |  34 ++++
 drivers/gpu/drm/i915/gvt/reg.h        |  34 ++++
 drivers/gpu/drm/i915/i915_dma.c       |  19 ++
 drivers/gpu/drm/i915/i915_drv.h       |   6 +
 drivers/gpu/drm/i915/i915_vgpu.h      |   3 +
 include/xen/interface/xen.h           |   1 +
 18 files changed, 991 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/gvt/Makefile
 create mode 100644 drivers/gpu/drm/i915/gvt/debug.h
 create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.c
 create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.h
 create mode 100644 drivers/gpu/drm/i915/gvt/gvt.c
 create mode 100644 drivers/gpu/drm/i915/gvt/gvt.h
 create mode 100644 drivers/gpu/drm/i915/gvt/hypercall.h
 create mode 100644 drivers/gpu/drm/i915/gvt/mpt.h
 create mode 100644 drivers/gpu/drm/i915/gvt/params.c
 create mode 100644 drivers/gpu/drm/i915/gvt/params.h
 create mode 100644 drivers/gpu/drm/i915/gvt/reg.h

diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h
index 62ca03e..6ff4986 100644
--- a/arch/x86/include/asm/xen/interface.h
+++ b/arch/x86/include/asm/xen/interface.h
@@ -73,6 +73,9 @@
 #endif
 
 #ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
 /* Explicitly size integers that represent pfns in the public interface
  * with Xen so that on ARM we can have one ABI that works for 32 and 64
  * bit guests. */
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 051eab3..89ff723 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -47,3 +47,19 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT
 	  option changes the default for that module option.
 
 	  If in doubt, say "N".
+
+config I915_GVT
+        tristate "GVT-g host driver"
+        depends on DRM_I915
+        select IRQ_WORK
+        default y
+        help
+          Enabling GVT-g mediated graphics passthrough technique for Intel i915
+          based integrated graphics card. With GVT-g, it's possible to have one
+          integrated i915 device shared by multiple VMs. Performance critical
+          opterations such as apperture accesses and ring buffer operations
+          are pass-throughed to VM, with a minimal set of conflicting resources
+          (e.g. display settings) mediated by vGT driver. The benefit of vGT
+          is on both the performance, given that each VM could directly operate
+          its aperture space and submit commands like running on native, and
+          the feature completeness, given that a true GEN hardware is exposed.
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0851de07..d4df410 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -91,6 +91,8 @@ i915-y += dvo_ch7017.o \
 	  intel_sdvo.o \
 	  intel_tv.o
 
+obj-$(CONFIG_I915_GVT)  += gvt/
+
 # virtual gpu code
 i915-y += i915_vgpu.o
 
diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
new file mode 100644
index 0000000..6935b78
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -0,0 +1,5 @@
+GVT_SOURCE := gvt.o params.o fb_decoder.o
+
+ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
+i915_gvt-y			:= $(GVT_SOURCE)
+obj-$(CONFIG_I915_GVT)		+= i915_gvt.o
diff --git a/drivers/gpu/drm/i915/gvt/debug.h b/drivers/gpu/drm/i915/gvt/debug.h
new file mode 100644
index 0000000..18e1467
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/debug.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef __GVT_DEBUG_H__
+#define __GVT_DEBUG_H__
+
+#define ASSERT(x)                                                       \
+        do {                                                            \
+                if (!(x)) {                                             \
+                        printk("Assert at %s line %d\n",                \
+                                __FILE__, __LINE__);                    \
+                }                                                       \
+        } while (0);
+
+#define ASSERT_NUM(x, y)                                                \
+        do {                                                            \
+                if (!(x)) {                                             \
+                        printk("Assert at %s line %d para 0x%llx\n",    \
+                                __FILE__, __LINE__, (u64)y);            \
+                }                                                       \
+        } while (0);
+
+#define gvt_info(fmt, args...) \
+	printk(KERN_INFO"[GVT-g] "fmt"\n", ##args)
+
+#define gvt_err(fmt, args...) \
+	printk(KERN_ERR"%s() - %d: "fmt"\n", __func__, __LINE__, ##args)
+
+#define gvt_warn(fmt, args...) \
+	printk(KERN_WARNING"%s() - %d: "fmt"\n", __func__, __LINE__, ##args)
+
+#define gvt_dbg(level, fmt, args...) do { \
+		if (gvt.debug & level) \
+			printk(KERN_DEBUG"%s() - %d: "fmt"\n", __func__, __LINE__, ##args); \
+	}while(0)
+
+enum {
+	GVT_DBG_CORE = (1 << 0),
+	GVT_DBG_MM = (1 << 1),
+	GVT_DBG_IRQ = (1 << 2),
+};
+
+#define gvt_dbg_core(fmt, args...) \
+	gvt_dbg(GVT_DBG_CORE, fmt, ##args)
+
+#define gvt_dbg_mm(fmt, args...) \
+	gvt_dbg(GVT_DBG_MM, fmt, ##args)
+
+#define gvt_dbg_irq(fmt, args...) \
+	gvt_dbg(GVT_DBG_IRQ, fmt, ##args)
+
+#endif
diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c b/drivers/gpu/drm/i915/gvt/fb_decoder.c
new file mode 100644
index 0000000..a219819
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+int gvt_decode_fb_format(struct pgt_device *pdev, int vmid, struct gvt_fb_format *fb)
+{
+	return 0;
+}
+
+int gvt_fb_notifier_call_chain(unsigned long val, void *data)
+{
+	return 0;
+}
diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.h b/drivers/gpu/drm/i915/gvt/fb_decoder.h
new file mode 100644
index 0000000..2c29ed4
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/fb_decoder.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_FB_DECODER_H_
+#define _GVT_FB_DECODER_H_
+
+typedef enum {
+	FB_MODE_SET_START = 1,
+	FB_MODE_SET_END,
+	FB_DISPLAY_FLIP,
+}gvt_fb_event_t;
+
+typedef enum {
+	DDI_PORT_NONE	= 0,
+	DDI_PORT_B	= 1,
+	DDI_PORT_C	= 2,
+	DDI_PORT_D	= 3,
+	DDI_PORT_E	= 4
+} ddi_port_t;
+
+struct pgt_device;
+
+struct gvt_fb_notify_msg {
+	unsigned vm_id;
+	unsigned pipe_id; /* id starting from 0 */
+	unsigned plane_id; /* primary, cursor, or sprite */
+};
+
+/* color space conversion and gamma correction are not included */
+struct gvt_primary_plane_format {
+	u8	enabled;	/* plane is enabled */
+	u8	tiled;		/* X-tiled */
+	u8	bpp;		/* bits per pixel */
+	u32	hw_format;	/* format field in the PRI_CTL register */
+	u32	drm_format;	/* format in DRM definition */
+	u32	base;		/* framebuffer base in graphics memory */
+	u32	x_offset;	/* in pixels */
+	u32	y_offset;	/* in lines */
+	u32	width;		/* in pixels */
+	u32	height;		/* in lines */
+	u32	stride;		/* in bytes */
+};
+
+struct gvt_sprite_plane_format {
+	u8	enabled;	/* plane is enabled */
+	u8	tiled;		/* X-tiled */
+	u8	bpp;		/* bits per pixel */
+	u32	hw_format;	/* format field in the SPR_CTL register */
+	u32	drm_format;	/* format in DRM definition */
+	u32	base;		/* sprite base in graphics memory */
+	u32	x_pos;		/* in pixels */
+	u32	y_pos;		/* in lines */
+	u32	x_offset;	/* in pixels */
+	u32	y_offset;	/* in lines */
+	u32	width;		/* in pixels */
+	u32	height;		/* in lines */
+};
+
+struct gvt_cursor_plane_format {
+	u8	enabled;
+	u8	mode;		/* cursor mode select */
+	u8	bpp;		/* bits per pixel */
+	u32	drm_format;	/* format in DRM definition */
+	u32	base;		/* cursor base in graphics memory */
+	u32	x_pos;		/* in pixels */
+	u32	y_pos;		/* in lines */
+	u8	x_sign;		/* X Position Sign */
+	u8	y_sign;		/* Y Position Sign */
+	u32	width;		/* in pixels */
+	u32	height;		/* in lines */
+	u32	x_hot;		/* in pixels */
+	u32	y_hot;		/* in pixels */
+};
+
+struct gvt_pipe_format {
+	struct gvt_primary_plane_format	primary;
+	struct gvt_sprite_plane_format	sprite;
+	struct gvt_cursor_plane_format	cursor;
+	ddi_port_t ddi_port;  /* the DDI port that the pipe is connected to */
+};
+
+struct gvt_fb_format{
+	struct gvt_pipe_format	pipes[I915_MAX_PIPES];
+};
+
+extern int gvt_fb_notifier_call_chain(unsigned long val, void *data);
+extern int gvt_decode_fb_format(struct pgt_device *pdev, int vmid,
+				struct gvt_fb_format *fb);
+
+#endif
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
new file mode 100644
index 0000000..041d10f
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright(c) 2011-2016 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 <xen/xen.h>
+#include <linux/kthread.h>
+
+#include "gvt.h"
+
+struct gvt_host gvt_host;
+
+extern struct gvt_kernel_dm xengt_kdm;
+extern struct gvt_kernel_dm kvmgt_kdm;
+
+static const char *supported_hypervisors[] = {
+	[GVT_HYPERVISOR_TYPE_XEN] = "Xen Hypervisor",
+	[GVT_HYPERVISOR_TYPE_KVM] = "KVM",
+};
+
+static bool gvt_init_host(void)
+{
+	struct gvt_host *host = &gvt_host;
+
+	if (!gvt.enable) {
+		gvt_dbg_core("GVT-g has been disabled by kernel parameter");
+		return false;
+	}
+
+	if (host->initialized) {
+		gvt_err("GVT-g has already been initialized!");
+		return false;
+	}
+
+	if (xen_initial_domain()) {
+		/* Xen Dom0 */
+		host->kdm = try_then_request_module(symbol_get(xengt_kdm), "xengt");
+		host->hypervisor_type = GVT_HYPERVISOR_TYPE_XEN;
+	} else if(xen_domain()) {
+		/* Xen DomU */
+		return false;
+	} else {
+		/* not in Xen. Try KVMGT */
+		host->kdm = try_then_request_module(symbol_get(kvmgt_kdm), "kvm");
+		host->hypervisor_type = GVT_HYPERVISOR_TYPE_KVM;
+	}
+
+	if (!host->kdm)
+		return false;
+
+	if (!hypervisor_detect_host())
+		return false;
+
+	gvt_info("Running with hypervisor %s in host mode",
+			supported_hypervisors[host->hypervisor_type]);
+
+	idr_init(&host->device_idr);
+	mutex_init(&host->device_idr_lock);
+
+	host->initialized = true;
+	return true;
+}
+
+static bool init_device_info(struct pgt_device *pdev)
+{
+	struct gvt_device_info *info = &pdev->device_info;
+
+	if (!IS_BROADWELL(pdev->dev_priv)) {
+		gvt_err("Unsupported GEN device");
+		return false;
+	}
+
+	if (IS_BROADWELL(pdev->dev_priv)) {
+		info->max_gtt_gm_sz = (1UL << 32);
+		/*
+		 * The layout of BAR0 in BDW:
+		 * |< - MMIO 2MB ->|<- Reserved 6MB ->|<- MAX GTT 8MB->|
+		 *
+		 * GTT offset in BAR0 starts from 8MB to 16MB, and
+		 * Whatever GTT size is configured in BIOS,
+		 * the size of BAR0 is always 16MB. The actual configured
+		 * GTT size can be found in GMCH_CTRL.
+		 */
+		info->gtt_start_offset = (1UL << 23);
+		info->max_gtt_size = (1UL << 23);
+		info->gtt_entry_size = 8;
+		info->gtt_entry_size_shift = 3;
+		info->gmadr_bytes_in_cmd = 8;
+	}
+
+	gvt_info("Device info:");
+	printk("        max_gtt_gm_sz: %llx\n", info->max_gtt_gm_sz);
+	printk("        max_gtt_size: %x\n", info->max_gtt_size);
+	printk("        gtt_size_entry: %x\n", info->gtt_entry_size);
+	printk("        gtt_entry_size_shift: %x\n", info->gtt_entry_size_shift);
+	printk("        gtt_start_offset: %x\n", info->gtt_start_offset);
+	printk("        gtt_end_offset: %x\n", info->gtt_end_offset);
+
+	return true;
+}
+
+static void init_initial_cfg_space_state(struct pgt_device *pdev)
+{
+	struct pci_dev *pci_dev = pdev->dev_priv->dev->pdev;
+	int i;
+
+	gvt_dbg_core("init initial cfg space, id %d", pdev->id);
+
+	for (i = 0; i < GVT_CFG_SPACE_SZ; i += 4)
+		pci_read_config_dword(pci_dev, i,
+				(u32 *)&pdev->initial_cfg_space[i]);
+
+	for (i = 0; i < 3; i++) {
+		pdev->bar_size[i] = pci_resource_len(pci_dev, i * 2);
+		gvt_info("bar %d size: %llx", i, pdev->bar_size[i]);
+	}
+}
+
+static void clean_initial_mmio_state(struct pgt_device *pdev)
+{
+	if (pdev->gttmmio_va) {
+		iounmap(pdev->gttmmio_va);
+		pdev->gttmmio_va = NULL;
+	}
+
+	if (pdev->gmadr_va) {
+		iounmap(pdev->gmadr_va);
+		pdev->gmadr_va = NULL;
+	}
+}
+
+static bool init_initial_mmio_state(struct pgt_device *pdev)
+{
+	u64 bar0, bar1;
+
+	gvt_dbg_core("init initial mmio state, id %d", pdev->id);
+
+	bar0 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR0];
+	bar1 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR1];
+
+	pdev->gttmmio_base = bar0 & ~0xf;
+	pdev->mmio_size = 2 * 1024 * 1024;
+	pdev->reg_num = pdev->mmio_size / 4;
+	pdev->gmadr_base = bar1 & ~0xf;
+
+	pdev->gttmmio_va = ioremap(pdev->gttmmio_base, pdev->bar_size[0]);
+	if (!pdev->gttmmio_va) {
+		gvt_err("fail to map GTTMMIO BAR.");
+		return false;
+	}
+
+	pdev->gmadr_va = ioremap(pdev->gmadr_base, pdev->bar_size[2]);
+	if (!pdev->gmadr_va) {
+		gvt_err("fail to map GMADR BAR.");
+		goto err;
+	}
+
+	gvt_info("bar0: 0x%llx, bar1: 0x%llx", bar0, bar1);
+	gvt_info("mmio size: %x", pdev->mmio_size);
+	gvt_info("gttmmio: 0x%llx, gmadr: 0x%llx", pdev->gttmmio_base, pdev->gmadr_base);
+	gvt_info("gttmmio_va: %p", pdev->gttmmio_va);
+	gvt_info("gmadr_va: %p", pdev->gmadr_va);
+
+	return true;
+err:
+	clean_initial_mmio_state(pdev);
+	return false;
+}
+
+static int gvt_service_thread(void *data)
+{
+	struct pgt_device *pdev = (struct pgt_device *)data;
+	int r;
+
+	gvt_dbg_core("service thread start, pgt %d", pdev->id);
+
+	while(!kthread_should_stop()) {
+		r = wait_event_interruptible(pdev->service_thread_wq,
+				kthread_should_stop() || pdev->service_request);
+
+		if (kthread_should_stop())
+			break;
+
+		if (r) {
+			gvt_warn("service thread is waken up by unexpected signal.");
+			continue;
+		}
+	}
+	return 0;
+}
+
+static void clean_service_thread(struct pgt_device *pdev)
+{
+	if (pdev->service_thread) {
+		kthread_stop(pdev->service_thread);
+		pdev->service_thread = NULL;
+	}
+}
+
+static bool init_service_thread(struct pgt_device *pdev)
+{
+	init_waitqueue_head(&pdev->service_thread_wq);
+
+	pdev->service_thread = kthread_run(gvt_service_thread,
+			pdev, "gvt_service_thread%d", pdev->id);
+
+	if (!pdev->service_thread) {
+		gvt_err("fail to start service thread.");
+		return false;
+	}
+
+	return true;
+}
+
+static void clean_pgt_device(struct pgt_device *pdev)
+{
+	clean_service_thread(pdev);
+	clean_initial_mmio_state(pdev);
+}
+
+static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *dev_priv)
+{
+	if (!init_device_info(pdev))
+		return false;
+
+	init_initial_cfg_space_state(pdev);
+
+	if (!init_initial_mmio_state(pdev))
+		goto err;
+
+	if (!init_service_thread(pdev))
+		goto err;
+
+	return true;
+err:
+	clean_pgt_device(pdev);
+	return false;
+}
+
+static bool post_init_pgt_device(struct pgt_device *pdev)
+{
+	return true;
+}
+
+static void free_pgt_device(struct pgt_device *pdev)
+{
+	struct gvt_host *host = &gvt_host;
+
+	mutex_lock(&host->device_idr_lock);
+	idr_remove(&host->device_idr, pdev->id);
+	mutex_unlock(&host->device_idr_lock);
+
+	vfree(pdev);
+}
+
+static struct pgt_device *alloc_pgt_device(struct drm_i915_private *dev_priv)
+{
+	struct gvt_host *host = &gvt_host;
+	struct pgt_device *pdev = NULL;
+
+	pdev = vzalloc(sizeof(*pdev));
+	if (!pdev) {
+		gvt_err("fail to allocate memory for pgt device.");
+		return NULL;
+	}
+
+	mutex_lock(&host->device_idr_lock);
+	pdev->id = idr_alloc(&host->device_idr, pdev, 0, 0, GFP_KERNEL);
+	mutex_unlock(&host->device_idr_lock);
+
+	if (pdev->id < 0) {
+		gvt_err("fail to allocate pgt device id.");
+		goto err;
+	}
+
+	mutex_init(&pdev->lock);
+	pdev->dev_priv = dev_priv;
+	idr_init(&pdev->instance_idr);
+
+	return pdev;
+err:
+	free_pgt_device(pdev);
+	return NULL;
+}
+
+void gvt_destroy_pgt_device(void *private_data)
+{
+	struct pgt_device *pdev = (struct pgt_device *)private_data;
+
+	clean_pgt_device(pdev);
+	free_pgt_device(pdev);
+}
+
+void *gvt_create_pgt_device(struct drm_i915_private *dev_priv)
+{
+	struct pgt_device *pdev = NULL;
+	struct gvt_host *host = &gvt_host;
+
+	if (!host->initialized && !gvt_init_host()) {
+		gvt_err("gvt_init_host fail");
+		return NULL;
+	}
+
+	gvt_dbg_core("create new pgt device, i915 dev_priv: %p", dev_priv);
+
+	pdev = alloc_pgt_device(dev_priv);
+	if (!pdev) {
+		gvt_err("fail to allocate memory for pgt device.");
+		goto err;
+	}
+
+	gvt_dbg_core("init pgt device, id %d", pdev->id);
+
+	if (!init_pgt_device(pdev, dev_priv)) {
+		gvt_err("fail to init physical device state.");
+		goto err;
+	}
+
+	gvt_dbg_core("pgt device creation done, id %d", pdev->id);
+
+	return pdev;
+err:
+	if (pdev) {
+		gvt_destroy_pgt_device(pdev);
+		pdev = NULL;
+	}
+	return NULL;
+}
+
+bool gvt_post_init_pgt_device(void *private_data)
+{
+	struct pgt_device *pdev = (struct pgt_device *)private_data;
+	struct gvt_host *host = &gvt_host;
+
+	if (!host->initialized) {
+		gvt_err("gvt_host haven't been initialized.");
+		return false;
+	}
+
+	gvt_dbg_core("post init pgt device %d", pdev->id);
+
+	if (!post_init_pgt_device(pdev)) {
+		gvt_err("fail to post init physical device state.");
+		return false;
+	}
+
+	return true;
+}
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
new file mode 100644
index 0000000..6c85bba
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_H_
+#define _GVT_H_
+
+#include "i915_drv.h"
+#include "i915_vgpu.h"
+
+#include "debug.h"
+#include "params.h"
+#include "reg.h"
+#include "hypercall.h"
+#include "mpt.h"
+#include "fb_decoder.h"
+
+#define GVT_MAX_VGPU 8
+
+enum {
+	GVT_HYPERVISOR_TYPE_XEN = 0,
+	GVT_HYPERVISOR_TYPE_KVM,
+};
+
+struct gvt_host {
+	bool initialized;
+	int hypervisor_type;
+	struct mutex device_idr_lock;
+	struct idr device_idr;
+	struct gvt_kernel_dm *kdm;
+};
+
+extern struct gvt_host gvt_host;
+
+/* Describe the limitation of HW.*/
+struct gvt_device_info {
+	u64 max_gtt_gm_sz;
+	u32 gtt_start_offset;
+	u32 gtt_end_offset;
+	u32 max_gtt_size;
+	u32 gtt_entry_size;
+	u32 gtt_entry_size_shift;
+	u32 gmadr_bytes_in_cmd;
+};
+
+struct vgt_device {
+	int id;
+	int vm_id;
+	struct pgt_device *pdev;
+	bool warn_untrack;
+};
+
+struct pgt_device {
+	struct mutex lock;
+	int id;
+
+	struct drm_i915_private *dev_priv;
+	struct idr instance_idr;
+
+	struct gvt_device_info device_info;
+
+	u8 initial_cfg_space[GVT_CFG_SPACE_SZ];
+	u64 bar_size[GVT_BAR_NUM];
+
+	u64 gttmmio_base;
+	void *gttmmio_va;
+
+	u64 gmadr_base;
+	void *gmadr_va;
+
+	u32 mmio_size;
+	u32 reg_num;
+
+	wait_queue_head_t service_thread_wq;
+	struct task_struct *service_thread;
+	unsigned long service_request;
+};
+
+static inline u32 gvt_mmio_read(struct pgt_device *pdev,
+		u32 reg)
+{
+	struct drm_i915_private *dev_priv = pdev->dev_priv;
+	i915_reg_t tmp = {.reg = reg};
+	return I915_READ(tmp);
+}
+
+static inline void gvt_mmio_write(struct pgt_device *pdev,
+		u32 reg, u32 val)
+{
+	struct drm_i915_private *dev_priv = pdev->dev_priv;
+	i915_reg_t tmp = {.reg = reg};
+	I915_WRITE(tmp, val);
+}
+
+static inline u64 gvt_mmio_read64(struct pgt_device *pdev,
+		u32 reg)
+{
+	struct drm_i915_private *dev_priv = pdev->dev_priv;
+	i915_reg_t tmp = {.reg = reg};
+	return I915_READ64(tmp);
+}
+
+static inline void gvt_mmio_write64(struct pgt_device *pdev,
+		u32 reg, u64 val)
+{
+	struct drm_i915_private *dev_priv = pdev->dev_priv;
+	i915_reg_t tmp = {.reg = reg};
+	I915_WRITE64(tmp, val);
+}
+
+#endif
diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h b/drivers/gpu/drm/i915/gvt/hypercall.h
new file mode 100644
index 0000000..0a41874
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/hypercall.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_HYPERCALL_H_
+#define _GVT_HYPERCALL_H_
+
+struct gvt_kernel_dm {
+};
+
+#endif /* _GVT_HYPERCALL_H_ */
diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h
new file mode 100644
index 0000000..bbe4465
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/mpt.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_MPT_H_
+#define _GVT_MPT_H_
+
+struct vgt_device;
+
+static inline unsigned long hypervisor_g2m_pfn(struct vgt_device *vgt,
+	unsigned long g_pfn)
+{
+	return 0;
+}
+
+static inline int hypervisor_pause_domain(struct vgt_device *vgt)
+{
+	return 0;
+}
+
+static inline int hypervisor_shutdown_domain(struct vgt_device *vgt)
+{
+	return 0;
+}
+
+static inline int hypervisor_set_trap_area(struct vgt_device *vgt,
+	uint64_t start, uint64_t end, bool map)
+{
+	return 0;
+}
+
+static inline bool hypervisor_detect_host(void)
+{
+	return false;
+}
+
+static inline int hypervisor_virt_to_mfn(void *addr)
+{
+	return 0;
+}
+
+static inline void *hypervisor_mfn_to_virt(int mfn)
+{
+	return NULL;
+}
+
+static inline void hypervisor_inject_msi(struct vgt_device *vgt)
+{
+	return;
+}
+
+static inline int hypervisor_hvm_init(struct vgt_device *vgt)
+{
+	return 0;
+}
+
+static inline void hypervisor_hvm_exit(struct vgt_device *vgt)
+{
+}
+
+static inline void *hypervisor_gpa_to_va(struct vgt_device *vgt, unsigned long gpa)
+{
+	return NULL;
+}
+
+static inline bool hypervisor_read_va(struct vgt_device *vgt, void *va,
+		void *val, int len, int atomic)
+{
+	return false;
+}
+
+static inline bool hypervisor_write_va(struct vgt_device *vgt, void *va,
+		void *val, int len, int atomic)
+{
+	return false;
+}
+
+#endif /* _GVT_MPT_H_ */
diff --git a/drivers/gpu/drm/i915/gvt/params.c b/drivers/gpu/drm/i915/gvt/params.c
new file mode 100644
index 0000000..dfc33c3
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/params.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+struct gvt_kernel_params gvt = {
+	.enable = true,
+	.debug = 0,
+};
diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
new file mode 100644
index 0000000..d2955b9
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/params.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_PARAMS_H_
+#define _GVT_PARAMS_H_
+
+struct gvt_kernel_params {
+	bool enable;
+	int debug;
+};
+
+extern struct gvt_kernel_params gvt;
+
+#endif
diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
new file mode 100644
index 0000000..d363b74
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/reg.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_REG_H
+#define _GVT_REG_H
+
+#define GVT_CFG_SPACE_SZ	256
+#define GVT_BAR_NUM		4
+
+#define GVT_REG_CFG_SPACE_BAR0	0x10
+#define GVT_REG_CFG_SPACE_BAR1	0x18
+#define GVT_REG_CFG_SPACE_BAR2	0x20
+
+#endif
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 4725e8d..eca8e50 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -943,6 +943,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
 	intel_uncore_init(dev);
 
+	dev_priv->vgpu.host_private_data = gvt_create_pgt_device(dev_priv);
+	if(intel_gvt_host_active(dev))
+		DRM_INFO("GVT-g is running in host mode\n");
+
 	ret = i915_gem_gtt_init(dev);
 	if (ret)
 		goto out_freecsr;
@@ -1067,6 +1071,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 		goto out_power_well;
 	}
 
+	if (intel_gvt_host_active(dev)) {
+		if (!gvt_post_init_pgt_device(dev_priv->vgpu.host_private_data)) {
+			DRM_ERROR("failed to post init pgt device\n");
+			goto out_power_well;
+		}
+	}
+
 	/*
 	 * Notify a valid surface after modesetting,
 	 * when running inside a VM.
@@ -1117,6 +1128,10 @@ out_gtt:
 	i915_global_gtt_cleanup(dev);
 out_freecsr:
 	intel_csr_ucode_fini(dev_priv);
+	if (intel_gvt_host_active(dev)) {
+		gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
+		dev_priv->vgpu.host_private_data = NULL;
+	}
 	intel_uncore_fini(dev);
 	pci_iounmap(dev->pdev, dev_priv->regs);
 put_bridge:
@@ -1165,6 +1180,10 @@ int i915_driver_unload(struct drm_device *dev)
 
 	intel_modeset_cleanup(dev);
 
+	if (intel_gvt_host_active(dev)) {
+		gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
+		dev_priv->vgpu.host_private_data = NULL;
+	}
 	/*
 	 * free the memory space allocated for the child device
 	 * config parsed from VBT
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 01cc982..db3c79b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1673,6 +1673,7 @@ struct i915_workarounds {
 
 struct i915_virtual_gpu {
 	bool active;
+	void *host_private_data;
 };
 
 struct i915_execbuffer_params {
@@ -2747,6 +2748,11 @@ static inline bool intel_vgpu_active(struct drm_device *dev)
 	return to_i915(dev)->vgpu.active;
 }
 
+static inline bool intel_gvt_host_active(struct drm_device *dev)
+{
+	return to_i915(dev)->vgpu.host_private_data ? true : false;
+}
+
 void
 i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
 		     u32 status_mask);
diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
index 3c83b47..942490a 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.h
+++ b/drivers/gpu/drm/i915/i915_vgpu.h
@@ -113,5 +113,8 @@ struct vgt_if {
 extern void i915_check_vgpu(struct drm_device *dev);
 extern int intel_vgt_balloon(struct drm_device *dev);
 extern void intel_vgt_deballoon(void);
+extern void *gvt_create_pgt_device(struct drm_i915_private *dev_priv);
+extern bool gvt_post_init_pgt_device(void *private_data);
+extern void gvt_destroy_pgt_device(void *private_data);
 
 #endif /* _I915_VGPU_H_ */
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index d133112..78a38f1 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -28,6 +28,7 @@
 #define __XEN_PUBLIC_XEN_H__
 
 #include <asm/xen/interface.h>
+#include <linux/types.h>
 
 /*
  * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
  2016-01-28 10:21 ` [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-02-04 11:27   ` Joonas Lahtinen
  2016-02-10  8:08   ` Daniel Vetter
  2016-01-28 10:21 ` [RFC 03/29] drm/i915: Introduce GVT context creation API Zhi Wang
                   ` (27 subsequent siblings)
  29 siblings, 2 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

From: Bing Niu <bing.niu@intel.com>

This patch introduces host graphics memory ballon when GVT-g is enabled.

As under GVT-g, i915 only owned limited graphics resources, others are
managed by GVT-g resource allocator and kept for other vGPUs.

For graphics memory space partition, a typical layout looks like:

+-------+-----------------------+------+-----------------------+
|* Host |   *GVT-g Resource     |* Host|   *GVT-g Resource     |
| Owned |   Allocator Managed   | Owned|   Allocator Managed   |
|       |                       |      |                       |
+---------------+-------+----------------------+-------+-------+
|       |       |       |       |      |       |       |       |
| i915  | vm 1  | vm 2  | vm 3  | i915 | vm 1  | vm 2  | vm 3  |
|       |       |       |       |      |       |       |       |
+-------+-------+-------+--------------+-------+-------+-------+
|           Aperture            |            Hidden            |
+-------------------------------+------------------------------+
|                       GGTT memory space                      |
+--------------------------------------------------------------+

Similar with fence registers partition:

 +------ +-----------------------+
 | * Host|    GVT-g Resource     |
 | Owned |   Allocator Managed   +
 0       |                       31
 +---------------+-------+-------+
 |       |       |       |       |
 | i915  | vm 1  | vm 2  | vm 3  |
 |       |       |       |       |
 +-------+-------+-------+-------+

i915 host will read the amount of allocated resources via GVT-g kernel parameters.

Signed-off-by: Bing Niu <bing.niu@intel.com>
Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/params.h   |  3 +++
 drivers/gpu/drm/i915/i915_gem.c     |  3 +++
 drivers/gpu/drm/i915/i915_gem_gtt.c |  4 ++--
 drivers/gpu/drm/i915/i915_vgpu.c    | 16 ++++++++++++----
 drivers/gpu/drm/i915/i915_vgpu.h    |  1 +
 5 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
index d2955b9..0656a98 100644
--- a/drivers/gpu/drm/i915/gvt/params.h
+++ b/drivers/gpu/drm/i915/gvt/params.h
@@ -27,6 +27,9 @@
 struct gvt_kernel_params {
 	bool enable;
 	int debug;
+	int dom0_low_gm_sz;
+	int dom0_high_gm_sz;
+	int dom0_fence_sz;
 };
 
 extern struct gvt_kernel_params gvt;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 799a53a..e916e43 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -5080,6 +5080,9 @@ i915_gem_load(struct drm_device *dev)
 	else
 		dev_priv->num_fence_regs = 8;
 
+	if(intel_gvt_host_active(dev))
+		dev_priv->num_fence_regs = gvt.dom0_fence_sz;
+
 	if (intel_vgpu_active(dev))
 		dev_priv->num_fence_regs =
 				I915_READ(vgtif_reg(avail_rs.fence_num));
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 7377b67..0540de2 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -2713,7 +2713,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
 	i915_address_space_init(ggtt_vm, dev_priv);
 	ggtt_vm->total += PAGE_SIZE;
 
-	if (intel_vgpu_active(dev)) {
+	if (intel_vgpu_active(dev) || intel_gvt_host_active(dev)) {
 		ret = intel_vgt_balloon(dev);
 		if (ret)
 			return ret;
@@ -2810,7 +2810,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev)
 	}
 
 	if (drm_mm_initialized(&vm->mm)) {
-		if (intel_vgpu_active(dev))
+		if (intel_vgpu_active(dev) || intel_gvt_host_active(dev))
 			intel_vgt_deballoon();
 
 		drm_mm_takedown(&vm->mm);
diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
index dea7429..fbe6114 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.c
+++ b/drivers/gpu/drm/i915/i915_vgpu.c
@@ -188,10 +188,18 @@ int intel_vgt_balloon(struct drm_device *dev)
 	unsigned long unmappable_base, unmappable_size, unmappable_end;
 	int ret;
 
-	mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
-	mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
-	unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
-	unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
+	if(intel_gvt_host_active(dev)) {
+		mappable_base = 0;
+		mappable_size = gvt.dom0_low_gm_sz << 20;
+		unmappable_base = dev_priv->gtt.mappable_end;
+		unmappable_size = gvt.dom0_high_gm_sz << 20;
+	} else if (intel_vgpu_active(dev)) {
+		mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
+		mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
+		unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
+		unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
+	} else
+		return -ENODEV;
 
 	mappable_end = mappable_base + mappable_size;
 	unmappable_end = unmappable_base + unmappable_size;
diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
index 942490a..b8a49e6 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.h
+++ b/drivers/gpu/drm/i915/i915_vgpu.h
@@ -24,6 +24,7 @@
 #ifndef _I915_VGPU_H_
 #define _I915_VGPU_H_
 
+#include "gvt/params.h"
 /* The MMIO offset of the shared info between guest and host emulator */
 #define VGT_PVINFO_PAGE	0x78000
 #define VGT_PVINFO_SIZE	0x1000
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 03/29] drm/i915: Introduce GVT context creation API
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
  2016-01-28 10:21 ` [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g Zhi Wang
  2016-01-28 10:21 ` [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 04/29] drm/i915: Ondemand populate context addressing mode bit Zhi Wang
                   ` (26 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

GVT workload scheduler needs special host LRC contexts, the so called "shadow
LRC context" to submit guest workload to host i915. During the guest
workload submission, GVT fills the shadow LRC context with the content of
guest LRC context: engine context is copied without changes, ring context is
mostly owned by host i915, except the PPGTT root pointers, which will be
filled with the shadow PPGTT page table root pointers managed by GVT-g.

The GVT-g workload scheduler flow:

         +-----------+                   +-----------+
         | GVT Guest |                   | GVT Guest |
         +-+-----^---+                   +-+-----^---+
           |     |                         |     |
           |     | GVT-g                   |     | GVT-g
vELSP write|     | emulates     vELSP write|     | emulates
           |     | Execlist/CSB            |     | Execlist/CSB
           |     | Status                  |     | Status
           |     |                         |     |
    +------v-----+-------------------------v-----+---------+
    |           GVT Virtual Execlist Submission            |
    +------+-------------------------------+---------------+
           |                               |
           | Per-VM/Ring Workoad Q         | Per-VM/Ring Workload Q
   +---------------------+--+      +------------------------+
       +---v--------+    ^             +---v--------+
       |GVT Workload|... |             |GVT Workload|...
       +------------+    |             +------------+
                         |
                         | Pick Workload from Q
    +--------------------+---------------------------------+
    |                GVT Workload Scheduler                |
    +--------------------+---------------------------------+
                         |         * Shadow guest LRC context
                  +------v------+  * Shadow guest ring buffer
                  | GVT Context |  * Scan/Patch guest RB instructions
                  +------+------+
                         |
                         v
              Host i915 GEM Submission

Guest ELSP submission will be wrapped into a GVT workload data structure.
When a guest is scheduled, workload scheduler picks the GVT workload from
the per-VM/ring Q, then prepare to dispatch it through host i915 GEM
submission.

The GVT workload lifecycle:

- Workload scheduler populates the GVT LRC context with the content of
guest LRC context
- Workload scheduler populates the GVT ring buffer with the instructions
from guest ring buffer
- Workload scheduler populates the PDPs in the GVT LRC context with shadow
PPGTT PDPs
- Workload scheduler submits this context through i915 GEM submission
interface
- Once the i915 gem request is finished, GVT-g waits until the GVT LRC context
is idle.
- i915 LRC routines notifies workload scheduler the LRC context is idle.
- Workload scheduler updates the guest LRC context with the content of GVT LRC
context
- Emulate CSB and context switch interrupt to guest

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h         | 20 +++++++++++++++++
 drivers/gpu/drm/i915/i915_gem_context.c | 38 +++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index db3c79b..fc5ddee 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -890,6 +890,24 @@ struct intel_context {
 	} engine[I915_NUM_RINGS];
 
 	struct list_head link;
+
+	/* Is a GVT context ? */
+	bool gvt_context;
+	/* Used by GVT workload scheduler. */
+	void *gvt_context_private_data[I915_NUM_RINGS];
+	/*
+	 * As GVT context may comes from different guest,
+	 * the addressing mode may be different
+	 */
+	u32 gvt_context_addressing_mode[I915_NUM_RINGS];
+	/*
+	 * Called when GVT context is scheduled-in
+	 */
+	void (*gvt_context_schedule_in)(void *data);
+	/*
+	 * Called when GVT context is scheduled-out
+	 */
+	void (*gvt_context_schedule_out)(void *data);
 };
 
 enum fb_op_origin {
@@ -2866,6 +2884,8 @@ struct drm_i915_gem_object *i915_gem_object_create_from_data(
 void i915_gem_free_object(struct drm_gem_object *obj);
 void i915_gem_vma_destroy(struct i915_vma *vma);
 
+struct intel_context * i915_gem_create_gvt_context(struct drm_device *dev);
+
 /* Flags used by pin/bind&friends. */
 #define PIN_MAPPABLE	(1<<0)
 #define PIN_NONBLOCK	(1<<1)
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 6a4f64b..410540a 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -260,6 +260,44 @@ err_out:
 	return ERR_PTR(ret);
 }
 
+struct intel_context *
+i915_gem_create_gvt_context(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_context *ctx;
+	int ret;
+	int i;
+
+	mutex_lock(&dev->struct_mutex);
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (ctx == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	kref_init(&ctx->ref);
+	list_add_tail(&ctx->link, &dev_priv->context_list);
+
+	ctx->i915 = dev_priv;
+	ctx->file_priv = NULL;
+	ctx->user_handle = -1;
+	ctx->remap_slice = (1 << NUM_L3_SLICES(dev)) - 1;
+	ctx->hang_stats.ban_period_seconds = DRM_I915_CTX_BAN_PERIOD;
+
+	ctx->gvt_context = true;
+
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		ret = intel_lr_context_deferred_alloc(ctx, &dev_priv->ring[i]);
+		if (ret) {
+			i915_gem_context_unreference(ctx);
+			ctx = NULL;
+			goto out;
+		}
+	}
+out:
+	mutex_unlock(&dev->struct_mutex);
+	return ctx;
+}
+
 /**
  * The default context needs to exist per ring that uses contexts. It stores the
  * context state of the GPU for applications that don't utilize HW contexts, as
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 04/29] drm/i915: Ondemand populate context addressing mode bit
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (2 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 03/29] drm/i915: Introduce GVT context creation API Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 05/29] drm/i915: Do not populate PPGTT root pointers for GVT context Zhi Wang
                   ` (25 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

As GVT-g workload scheduler may submit workloads from different VMs to i915,
some VM may use 32bit PPGTT addressing mode, while some VMs may use 48bit
addressing mode, the context addressing mode bit in the context descriptor
has to be aligned with guest workload. If the to-be-submitted context is
a GVT context.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/intel_lrc.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index da97bc5..48e8ca2 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -302,7 +302,8 @@ logical_ring_init_platform_invariants(struct intel_engine_cs *ring)
  * which remains valid until the context is unpinned.
  *
  * This is what a descriptor looks like, from LSB to MSB:
- *    bits 0-11:    flags, GEN8_CTX_* (cached in ctx_desc_template)
+ *    bits 0-2,3-11: flags, GEN8_CTX_* (cached in ctx_desc_template)
+ *    bits 3:        Context addressing mode
  *    bits 12-31:    LRCA, GTT address of (the HWSP of) this context
  *    bits 32-51:    ctx ID, a globally unique tag (the LRCA again!)
  *    bits 52-63:    reserved, may encode the engine ID (for GuC)
@@ -317,6 +318,13 @@ intel_lr_context_descriptor_update(struct intel_context *ctx,
 	       LRC_PPHWSP_PN * PAGE_SIZE;
 
 	desc = ring->ctx_desc_template;			   /* bits  0-11 */
+
+	if (!ctx->gvt_context)
+		desc |= GEN8_CTX_ADDRESSING_MODE(dev) <<   /* bit 3 */
+			GEN8_CTX_ADDRESSING_MODE_SHIFT;
+	else
+		desc |= ctx->gvt_context_addressing_mode[ring->id];
+
 	desc |= lrca;					   /* bits 12-31 */
 	desc |= (lrca >> PAGE_SHIFT) << GEN8_CTX_ID_SHIFT; /* bits 32-51 */
 
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 05/29] drm/i915: Do not populate PPGTT root pointers for GVT context
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (3 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 04/29] drm/i915: Ondemand populate context addressing mode bit Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 06/29] drm/i915: Do not initialize the engine state of " Zhi Wang
                   ` (24 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

As the GVT context will use the shadow PPGTT page table generated by GVT
itself from guest PPGTT page table, the GVT context doesn't need a host
PPGTT page table, so host i915 doesn't need to populate PPGTT root pointers
for it as well.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/intel_lrc.c | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 48e8ca2..631ed96 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -2399,22 +2399,24 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
 	ASSIGN_CTX_REG(reg_state, CTX_PDP0_UDW, GEN8_RING_PDP_UDW(ring, 0), 0);
 	ASSIGN_CTX_REG(reg_state, CTX_PDP0_LDW, GEN8_RING_PDP_LDW(ring, 0), 0);
 
-	if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
-		/* 64b PPGTT (48bit canonical)
-		 * PDP0_DESCRIPTOR contains the base address to PML4 and
-		 * other PDP Descriptors are ignored.
-		 */
-		ASSIGN_CTX_PML4(ppgtt, reg_state);
-	} else {
-		/* 32b PPGTT
-		 * PDP*_DESCRIPTOR contains the base address of space supported.
-		 * With dynamic page allocation, PDPs may not be allocated at
-		 * this point. Point the unallocated PDPs to the scratch page
-		 */
-		ASSIGN_CTX_PDP(ppgtt, reg_state, 3);
-		ASSIGN_CTX_PDP(ppgtt, reg_state, 2);
-		ASSIGN_CTX_PDP(ppgtt, reg_state, 1);
-		ASSIGN_CTX_PDP(ppgtt, reg_state, 0);
+	if (!ctx->gvt_context) {
+		if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
+			/* 64b PPGTT (48bit canonical)
+			 * PDP0_DESCRIPTOR contains the base address to PML4 and
+			 * other PDP Descriptors are ignored.
+			 */
+			ASSIGN_CTX_PML4(ppgtt, reg_state);
+		} else {
+			/* 32b PPGTT
+			 * PDP*_DESCRIPTOR contains the base address of space supported.
+			 * With dynamic page allocation, PDPs may not be allocated at
+			 * this point. Point the unallocated PDPs to the scratch page
+			 */
+			ASSIGN_CTX_PDP(ppgtt, reg_state, 3);
+			ASSIGN_CTX_PDP(ppgtt, reg_state, 2);
+			ASSIGN_CTX_PDP(ppgtt, reg_state, 1);
+			ASSIGN_CTX_PDP(ppgtt, reg_state, 0);
+		}
 	}
 
 	if (ring->id == RCS) {
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 06/29] drm/i915: Do not initialize the engine state of GVT context
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (4 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 05/29] drm/i915: Do not populate PPGTT root pointers for GVT context Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 07/29] drm/i915: GVT context scheduling Zhi Wang
                   ` (23 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

As the guest context will be copied into GVT context, during the context
shadow. It's not necessary for host i915 to initialize the engine state of
GVT context.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/intel_lrc.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 631ed96..830133d 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -2569,7 +2569,9 @@ int intel_lr_context_deferred_alloc(struct intel_context *ctx,
 	ctx->engine[ring->id].ringbuf = ringbuf;
 	ctx->engine[ring->id].state = ctx_obj;
 
-	if (ctx != ctx->i915->kernel_context && ring->init_context) {
+	if (ctx != ctx->i915->kernel_context &&
+		!ctx->gvt_context && ring->init_context) {
+
 		struct drm_i915_gem_request *req;
 
 		req = i915_gem_request_alloc(ring, ctx);
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 07/29] drm/i915: GVT context scheduling
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (5 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 06/29] drm/i915: Do not initialize the engine state of " Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 08/29] drm/i915: Support vGPU guest framebuffer GEM object Zhi Wang
                   ` (22 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

Due to render mmio switch, GVT context cannot be scheduled with the host
i915 context together in a ELSP combo. Currently we will only allow the
a single submission if host i915 will schedule a GVT context.

At the time of schedule-in/out a GVT context, host i915 has to notify
GVT-g the status of GVT context has been changed. so that GVT-g can copy
the content of a GVT context back into the guest execlist context.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/intel_lrc.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 830133d..42638e0 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -449,6 +449,9 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 				 execlist_link) {
 		if (!req0) {
 			req0 = cursor;
+			/* single submission for gvt context */
+			if (req0->ctx->gvt_context)
+				break;
 		} else if (req0->ctx == cursor->ctx) {
 			/* Same ctx: ignore first request, as second request
 			 * will update tail past first request's workload */
@@ -457,7 +460,9 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 				       &ring->execlist_retired_req_list);
 			req0 = cursor;
 		} else {
-			req1 = cursor;
+			if (!cursor->ctx->gvt_context)
+				req1 = cursor;
+
 			break;
 		}
 	}
@@ -484,6 +489,11 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 
 	WARN_ON(req1 && req1->elsp_submitted);
 
+	if (req0->ctx->gvt_context) {
+		struct intel_context *ctx = req0->ctx;
+		ctx->gvt_context_schedule_in(ctx->gvt_context_private_data[ring->id]);
+	}
+
 	execlists_submit_requests(req0, req1);
 }
 
@@ -504,6 +514,10 @@ static bool execlists_check_remove_request(struct intel_engine_cs *ring,
 			     "Never submitted head request\n");
 
 			if (--head_req->elsp_submitted <= 0) {
+				if (head_req->ctx->gvt_context) {
+					struct intel_context *ctx = head_req->ctx;
+					ctx->gvt_context_schedule_out(ctx->gvt_context_private_data[ring->id]);
+				}
 				list_move_tail(&head_req->execlist_link,
 					       &ring->execlist_retired_req_list);
 				return true;
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 08/29] drm/i915: Support vGPU guest framebuffer GEM object
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (6 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 07/29] drm/i915: GVT context scheduling Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 09/29] drm/i915: gvt: Resource allocator Zhi Wang
                   ` (21 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

From: Zhiyuan Lv <zhiyuan.lv@intel.com>

In the compositor mode of display, dom0/host needs to get the guest
framebuffer to do more rendering, so that the guest VM's screen can
show up in more fancy way, e.g., in an X window of dom0/host.

In order to do that, a new gem object type "gvtbuffer" is introduced
to i915. Different from normal gem object in i915, gvtbuffer does not
have its own backing storage. Instead, it borrows the page frames
of guest VM's framebuffer as its own backing storage.

From high level, it works this way:
	a) gvt notifies kernel/userspace the guest OS page flip by
	   monitoring the related guest MMIO changes and commands.
	b) user space issue IOCTL to create gvtbuffer gem object.
	c) kernel creates the gem object, and record the guest FB base
           address (gfx address) from MMIO.
	d) When needed, the gvtbuffer will be bound to graphics
	   memory, and be used as normal gem object for rendering.

Guest framebuffer must be inside GGTT, whereas the gvtbuffer can be
in either GGTT or PPGTT, depending on the requirement of the
rendering.

Since the gvtbuffer corresponds to the guest framebuffer, which is
from guest physical memory, we may not be able to get "page struct"
for them. But i915 gem framework has had similar cases. A gem
object can have stolen memory as its backing storage. In such case,
the backing storage does not have "page struct" as well, and i915 has
handled the case in the framework well.

This patch was originally from daivid.j.cowperthwaite@intel.com, and
pretty some changes were made since then.

Signed-off-by: Zhiyuan Lv <zhiyuan.lv@intel.com>
---
 drivers/gpu/drm/i915/Makefile             |   1 +
 drivers/gpu/drm/i915/i915_dma.c           |   1 +
 drivers/gpu/drm/i915/i915_drv.h           |   3 +
 drivers/gpu/drm/i915/i915_gem_gvtbuffer.c | 247 ++++++++++++++++++++++++++++++
 include/uapi/drm/i915_drm.h               |  38 +++++
 5 files changed, 290 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/i915_gem_gvtbuffer.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index d4df410..c4a6615 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -33,6 +33,7 @@ i915-y += i915_cmd_parser.o \
 	  i915_gem_stolen.o \
 	  i915_gem_tiling.o \
 	  i915_gem_userptr.o \
+	  i915_gem_gvtbuffer.o \
 	  i915_gpu_error.o \
 	  i915_trace_points.o \
 	  intel_lrc.o \
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index eca8e50..f150602 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1351,6 +1351,7 @@ const struct drm_ioctl_desc i915_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(I915_GEM_GVTBUFFER, i915_gem_gvtbuffer_ioctl, DRM_RENDER_ALLOW),
 };
 
 int i915_max_ioctl = ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index fc5ddee..d387754 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3238,6 +3238,9 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
 				    struct drm_file *file_priv);
 
+int i915_gem_gvtbuffer_ioctl(struct drm_device *dev, void *data,
+			     struct drm_file *file);
+
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct drm_device *dev,
 					  struct i915_address_space *vm,
diff --git a/drivers/gpu/drm/i915/i915_gem_gvtbuffer.c b/drivers/gpu/drm/i915/i915_gem_gvtbuffer.c
new file mode 100644
index 0000000..3aa2ee8
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem_gvtbuffer.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright © 2012 - 2015 Intel Corporation
+ *
+ * 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 "i915_drv.h"
+#include "i915_trace.h"
+#include "intel_drv.h"
+#include <linux/swap.h>
+
+#include "gvt/fb_decoder.h"
+
+static int i915_gem_gvtbuffer_get_pages(struct drm_i915_gem_object *obj)
+{
+	BUG();
+	return -EINVAL;
+}
+
+static void i915_gem_gvtbuffer_put_pages(struct drm_i915_gem_object *obj)
+{
+	/* like stolen memory, this should only be called during free
+	 * after clearing pin count.
+	 */
+	sg_free_table(obj->pages);
+	kfree(obj->pages);
+}
+
+static const struct drm_i915_gem_object_ops i915_gem_gvtbuffer_ops = {
+	.get_pages = i915_gem_gvtbuffer_get_pages,
+	.put_pages = i915_gem_gvtbuffer_put_pages,
+};
+
+#define GEN8_DECODE_PTE(pte) \
+	((dma_addr_t)(((((u64)pte) >> 12) & 0x7ffffffULL) << 12))
+
+#define GEN7_DECODE_PTE(pte) \
+	((dma_addr_t)(((((u64)pte) & 0x7f0) << 28) | (u64)(pte & 0xfffff000)))
+
+static struct sg_table *
+i915_create_sg_pages_for_gvtbuffer(struct drm_device *dev,
+			     u32 start, u32 num_pages)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct sg_table *st;
+	struct scatterlist *sg;
+	int i;
+
+	st = kmalloc(sizeof(*st), GFP_KERNEL);
+	if (st == NULL)
+		return NULL;
+
+	if (sg_alloc_table(st, num_pages, GFP_KERNEL)) {
+		kfree(st);
+		return NULL;
+	}
+
+	if (INTEL_INFO(dev)->gen >= 8) {
+		gen8_pte_t __iomem *gtt_entries =
+			(gen8_pte_t __iomem *)dev_priv->gtt.gsm +
+			(start >> PAGE_SHIFT);
+		for_each_sg(st->sgl, sg, num_pages, i) {
+			sg->offset = 0;
+			sg->length = PAGE_SIZE;
+			sg_dma_address(sg) =
+				GEN8_DECODE_PTE(readq(&gtt_entries[i]));
+			sg_dma_len(sg) = PAGE_SIZE;
+		}
+	} else {
+		gen6_pte_t __iomem *gtt_entries =
+			(gen6_pte_t __iomem *)dev_priv->gtt.gsm +
+			(start >> PAGE_SHIFT);
+		for_each_sg(st->sgl, sg, num_pages, i) {
+			sg->offset = 0;
+			sg->length = PAGE_SIZE;
+			sg_dma_address(sg) =
+				GEN7_DECODE_PTE(readq(&gtt_entries[i]));
+			sg_dma_len(sg) = PAGE_SIZE;
+		}
+	}
+
+	return st;
+}
+
+struct drm_i915_gem_object *
+i915_gem_object_create_gvtbuffer(struct drm_device *dev,
+				 u32 start, u32 num_pages)
+{
+	struct drm_i915_gem_object *obj;
+	obj = i915_gem_object_alloc(dev);
+	if (obj == NULL)
+		return NULL;
+
+	drm_gem_private_object_init(dev, &obj->base, num_pages << PAGE_SHIFT);
+	i915_gem_object_init(obj, &i915_gem_gvtbuffer_ops);
+
+	obj->pages = i915_create_sg_pages_for_gvtbuffer(dev, start, num_pages);
+	if (obj->pages == NULL) {
+		i915_gem_object_free(obj);
+		return NULL;
+	}
+
+	i915_gem_object_pin_pages(obj);
+	obj->cache_level = I915_CACHE_L3_LLC;
+
+	DRM_DEBUG_DRIVER("GVT_GEM: backing store base = 0x%x pages = 0x%x\n",
+			 start, num_pages);
+	return obj;
+}
+
+static int gvt_decode_information(struct drm_device *dev,
+				  struct drm_i915_gem_gvtbuffer *args)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 vmid = args->vmid;
+	struct gvt_fb_format fb;
+	struct gvt_primary_plane_format *p;
+	struct gvt_cursor_plane_format *c;
+	struct gvt_pipe_format *pipe;
+
+	if (gvt_decode_fb_format(dev_priv->vgpu.host_private_data, vmid, &fb))
+		return -EINVAL;
+
+	pipe = ((args->pipe_id >= I915_MAX_PIPES) ?
+		NULL : &fb.pipes[args->pipe_id]);
+
+	if (!pipe || !pipe->primary.enabled) {
+		DRM_DEBUG_DRIVER("GVT_GEM: Invalid pipe_id: %d\n",
+				 args->pipe_id);
+		return -EINVAL;
+	}
+
+	if ((args->plane_id) == I915_GVT_PLANE_PRIMARY) {
+		p = &pipe->primary;
+		args->enabled = p->enabled;
+		args->x_offset = p->x_offset;
+		args->y_offset = p->y_offset;
+		args->start = p->base;
+		args->width = p->width;
+		args->height = p->height;
+		args->stride = p->stride;
+		args->bpp = p->bpp;
+		args->hw_format = p->hw_format;
+		args->drm_format = p->drm_format;
+		args->tiled = p->tiled;
+	} else if ((args->plane_id) == I915_GVT_PLANE_CURSOR) {
+		c = &pipe->cursor;
+		args->enabled = c->enabled;
+		args->x_offset = c->x_hot;
+		args->y_offset = c->y_hot;
+		args->x_pos = c->x_pos;
+		args->y_pos = c->y_pos;
+		args->start = c->base;
+		args->width = c->width;
+		args->height = c->height;
+		args->stride = c->width * (c->bpp / 8);
+		args->bpp = c->bpp;
+		args->tiled = 0;
+	} else {
+		DRM_DEBUG_DRIVER("GVT_GEM: Invalid plaine_id: %d\n",
+				 args->plane_id);
+		return -EINVAL;
+	}
+
+	args->size = (((args->width * args->height * args->bpp) / 8) +
+		      (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+
+	if (args->start & (PAGE_SIZE - 1)) {
+		DRM_DEBUG_DRIVER("GVT_GEM: Not aligned fb start address: "
+				 "0x%x\n", args->start);
+		return -EINVAL;
+	}
+
+	if (((args->start >> PAGE_SHIFT) + args->size) >
+	    gtt_total_entries(dev_priv->gtt)) {
+		DRM_DEBUG_DRIVER("GVT: Invalid GTT offset or size\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * Creates a new mm object that wraps some user memory.
+ */
+int
+i915_gem_gvtbuffer_ioctl(struct drm_device *dev, void *data,
+			 struct drm_file *file)
+{
+	struct drm_i915_gem_gvtbuffer *args = data;
+	struct drm_i915_gem_object *obj;
+	u32 handle;
+	int ret;
+
+	if (INTEL_INFO(dev)->gen < 7)
+		return -EPERM;
+#if 0
+	if (!gvt_check_host())
+		return -EPERM;
+#endif
+	ret = gvt_decode_information(dev, args);
+	if (ret)
+		return ret;
+
+	if (args->flags & I915_GVTBUFFER_QUERY_ONLY)
+		return 0;
+
+	obj = i915_gem_object_create_gvtbuffer(dev, args->start, args->size);
+	if (!obj) {
+		DRM_DEBUG_DRIVER("GVT_GEM: Failed to create gem object"
+					" for VM FB!\n");
+		return -EINVAL;
+	}
+
+	obj->tiling_mode = args->tiled ? I915_TILING_X : I915_TILING_NONE;
+	obj->stride = args->tiled ? args->stride : 0;
+
+	ret = drm_gem_handle_create(file, &obj->base, &handle);
+	if (ret) {
+		/* TODO: Double confirm the error handling path */
+		i915_gem_object_free(obj);
+		return ret;
+	}
+
+	/* drop reference from allocate - handle holds it now */
+	drm_gem_object_unreference(&obj->base);
+
+	args->handle = handle;
+	return 0;
+}
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 6a19371..5ba115a 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -230,6 +230,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_GEM_USERPTR		0x33
 #define DRM_I915_GEM_CONTEXT_GETPARAM	0x34
 #define DRM_I915_GEM_CONTEXT_SETPARAM	0x35
+#define DRM_I915_GEM_GVTBUFFER          0x36
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -283,6 +284,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GEM_USERPTR			DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_USERPTR, struct drm_i915_gem_userptr)
 #define DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_GETPARAM, struct drm_i915_gem_context_param)
 #define DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_SETPARAM, struct drm_i915_gem_context_param)
+#define DRM_IOCTL_I915_GEM_GVTBUFFER		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_GVTBUFFER, struct drm_i915_gem_gvtbuffer)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -1168,4 +1170,40 @@ struct drm_i915_gem_context_param {
 	__u64 value;
 };
 
+struct drm_i915_gem_gvtbuffer {
+        __u32 vmid;
+	__u32 plane_id;
+#define I915_GVT_PLANE_PRIMARY 1
+#define I915_GVT_PLANE_SPRITE 2
+#define I915_GVT_PLANE_CURSOR 3
+	__u32 pipe_id;
+	__u32 phys_pipe_id;
+	__u8  enabled;
+	__u8  tiled;
+	__u32 bpp;
+	__u32 hw_format;
+	__u32 drm_format;
+	__u32 start;
+	__u32 x_pos;
+	__u32 y_pos;
+	__u32 x_offset;
+	__u32 y_offset;
+	__u32 size;
+	__u32 width;
+	__u32 height;
+	__u32 stride;
+	__u64 user_ptr;
+	__u32 user_size;
+	__u32 flags;
+#define I915_GVTBUFFER_READ_ONLY (1<<0)
+#define I915_GVTBUFFER_QUERY_ONLY (1<<1)
+#define I915_GVTBUFFER_UNSYNCHRONIZED 0x80000000
+	/**
+	 * Returned handle for the object.
+	 *
+	 * Object handles are nonzero.
+	 */
+	__u32 handle;
+};
+
 #endif /* _UAPI_I915_DRM_H_ */
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 09/29] drm/i915: gvt: Resource allocator
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (7 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 08/29] drm/i915: Support vGPU guest framebuffer GEM object Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 10/29] drm/i915: gvt: Basic mmio emulation state Zhi Wang
                   ` (20 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

From: Yulei Zhang <yulei.zhang@intel.com>

This patch introduces the GVT-g resource allocator. Under virtualization
environment, GGTT and fences are partitioned. GGTT memory space and fences
for i915 are limited. Only a part of GGTT memory space and fences is owned
by host. The left resources are mananged by GVT-g resource allocators.

Signed-off-by: Yulei Zhang <yulei.zhang@intel.com>
Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile      |   2 +-
 drivers/gpu/drm/i915/gvt/aperture_gm.c | 225 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/gvt.c         |   3 +
 drivers/gpu/drm/i915/gvt/gvt.h         | 105 +++++++++++++++
 drivers/gpu/drm/i915/gvt/params.c      |  12 ++
 drivers/gpu/drm/i915/gvt/params.h      |   8 ++
 6 files changed, 354 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/aperture_gm.c

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index 6935b78..6655929 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,4 +1,4 @@
-GVT_SOURCE := gvt.o params.o fb_decoder.o
+GVT_SOURCE := gvt.o params.o aperture_gm.o fb_decoder.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/aperture_gm.c b/drivers/gpu/drm/i915/gvt/aperture_gm.c
new file mode 100644
index 0000000..7cb15c1
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/aperture_gm.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+void init_gm_allocator(struct pgt_device *pdev,
+		u64 start, u64 size, bool mappable)
+{
+	struct drm_mm *mm = mappable ?
+		&pdev->gm_allocator.low_gm : &pdev->gm_allocator.high_gm;
+
+	drm_mm_init(mm, start, size);
+}
+
+void clean_gm_allocator(struct pgt_device *pdev)
+{
+	if (!drm_mm_initialized(&pdev->gm_allocator.low_gm)
+			|| !drm_mm_initialized(&pdev->gm_allocator.high_gm))
+		return;
+
+	drm_mm_takedown(&pdev->gm_allocator.low_gm);
+	drm_mm_takedown(&pdev->gm_allocator.high_gm);
+}
+
+struct drm_mm_node *alloc_gm_node(struct pgt_device *pdev, u32 size, bool mappable)
+{
+	struct drm_mm_node *node;
+	struct drm_mm *mm = mappable ?
+		&pdev->gm_allocator.low_gm : &pdev->gm_allocator.high_gm;
+	int ret;
+
+	if (!drm_mm_initialized(mm))
+		return NULL;
+
+	DRM_DEBUG_KMS("creating vgt %s object: size=%x\n",
+			mappable ? "mappable" : "unmappable", size);
+	if (size == 0)
+		return NULL;
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node)
+		return NULL;
+
+	ret = drm_mm_insert_node(mm, node, size,
+			PAGE_SIZE, DRM_MM_SEARCH_DEFAULT);
+	if (ret) {
+		kfree(node);
+		return NULL;
+	}
+
+	return node;
+}
+
+void free_gm_node(struct drm_mm_node *node)
+{
+	drm_mm_remove_node(node);
+	kfree(node);
+}
+
+static bool check_instance_info(struct vgt_device *vgt,
+		struct gvt_instance_info *info)
+{
+	struct pgt_device *pdev = vgt->pdev;
+
+	if (gvt_aperture_base(vgt)) {
+		gvt_err("resources have already been allocated");
+		return false;
+	}
+
+	if (!info->low_gm_sz || !info->high_gm_sz || !info->fence_sz ||
+		info->low_gm_sz > phys_aperture_sz(pdev) ||
+		info->high_gm_sz > gm_sz(pdev) - phys_aperture_sz(pdev)) {
+		gvt_err("invalid resource configuration");
+		gvt_err("demand low GM size %u max low GM size %llu",
+			info->low_gm_sz, phys_aperture_sz(pdev));
+		gvt_err("demand high GM size %u max high GM size %llu",
+			info->high_gm_sz, gm_sz(pdev) - phys_aperture_sz(pdev));
+		gvt_err("fence size %u", info->fence_sz);
+		return false;
+	}
+
+	return true;
+}
+
+static void clear_fence(struct vgt_device *vgt)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	int i;
+
+	for (i = 0; i < gvt_fence_sz(vgt); i++)
+		gvt_mmio_write64(pdev,
+			i915_mmio_reg_offset(FENCE_REG_GEN6_LO(i + gvt_fence_base(vgt))), 0);
+}
+
+void gvt_free_gm_and_fence_resource(struct vgt_device *vgt)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	unsigned long *fence_bitmap = pdev->fence_bitmap;
+
+	if (vgt->state.gm.node.low_gm_node) {
+		free_gm_node(vgt->state.gm.node.low_gm_node);
+		vgt->state.gm.node.low_gm_node = NULL;
+	}
+
+	if (vgt->state.gm.node.high_gm_node) {
+		free_gm_node(vgt->state.gm.node.high_gm_node);
+		vgt->state.gm.node.high_gm_node = NULL;
+	}
+
+	if (gvt_fence_sz(vgt) && gvt_fence_base(vgt)) {
+		bitmap_clear(fence_bitmap, gvt_fence_base(vgt), gvt_fence_sz(vgt));
+		clear_fence(vgt);
+		gvt_fence_sz(vgt) = gvt_fence_base(vgt) = 0;
+	}
+}
+
+int gvt_alloc_gm_and_fence_resource(struct vgt_device *vgt,
+	struct gvt_instance_info *info)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	struct drm_mm_node *node;
+	unsigned long *fence_bitmap = pdev->fence_bitmap;
+	unsigned long fence_base;
+
+	if (!check_instance_info(vgt, info)) {
+		gvt_err("invalid resoure configuration");
+		return -EINVAL;
+	}
+
+	node = alloc_gm_node(pdev, info->low_gm_sz << 20, true);
+	if (!node) {
+		gvt_err("fail to allocate low GM space");
+		goto err;
+	}
+
+	vgt->state.gm.node.low_gm_node = node;
+
+	gvt_aperture_base(vgt) = phys_aperture_base(vgt->pdev) + node->start;
+	gvt_aperture_sz(vgt) = info->low_gm_sz << 20;
+
+	node = alloc_gm_node(pdev, info->high_gm_sz << 20, false);
+	if (!node) {
+		gvt_err("fail to allocate high GM space");
+		goto err;
+	}
+
+	vgt->state.gm.node.high_gm_node = node;
+
+	gvt_hidden_gm_offset(vgt) = node->start;
+	gvt_gm_sz(vgt) = (info->low_gm_sz + info->high_gm_sz) << 20;
+
+	fence_base = bitmap_find_next_zero_area(fence_bitmap,
+				GVT_FENCE_BITMAP_BITS, 0, info->fence_sz, 0);
+	if (fence_base >= GVT_MAX_NUM_FENCES) {
+		gvt_err("fail to allocate fence");
+		goto err;
+	}
+
+	gvt_fence_base(vgt) = fence_base;
+	gvt_fence_sz(vgt) = info->fence_sz;
+
+	bitmap_set(fence_bitmap, fence_base, info->fence_sz);
+
+	clear_fence(vgt);
+
+	return 0;
+err:
+	gvt_free_gm_and_fence_resource(vgt);
+	return -ENOMEM;
+}
+
+void gvt_init_resource_allocator(struct pgt_device *pdev)
+{
+	struct gvt_device_info *info = &pdev->device_info;
+	int i;
+	unsigned long *fence_bitmap = pdev->fence_bitmap;
+
+	gvt_info("total aperture: 0x%llx bytes, total GM space: 0x%llx bytes\n",
+		phys_aperture_sz(pdev), gm_sz(pdev));
+
+	ASSERT(phys_aperture_sz(pdev) % (1 << 20) == 0);
+	ASSERT(gm_sz(pdev) % (1 << 20) == 0);
+	ASSERT(phys_aperture_sz(pdev) <= gm_sz(pdev) && gm_sz(pdev) <= info->max_gtt_gm_sz);
+	ASSERT(info->max_gtt_gm_sz <= GVT_MAX_GM_SIZE);
+
+	/* Basic memrange allocator for vgt low memory */
+	init_gm_allocator(pdev, gvt.dom0_low_gm_sz << 20,
+			(phys_aperture_sz(pdev) - (gvt.dom0_low_gm_sz << 20)), true);
+
+	/* Basic memrange allocate for vgt high memory */
+	init_gm_allocator(pdev,
+			(phys_aperture_sz(pdev) + (gvt.dom0_high_gm_sz << 20)),
+			(gm_sz(pdev) - (gvt.dom0_high_gm_sz << 20)), false);
+
+	/* Reserve fence region for dom0 */
+	bitmap_set(fence_bitmap, 0, gvt.dom0_fence_sz);
+
+	for (i = 0; i < gvt.dom0_fence_sz; i++)
+		gvt_mmio_write64(pdev, i915_mmio_reg_offset(FENCE_REG_GEN6_LO(i)), 0);
+}
+
+void gvt_clean_resource_allocator(struct pgt_device *pdev)
+{
+	clean_gm_allocator(pdev);
+}
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index 041d10f..f31e9f7 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -234,6 +234,7 @@ static void clean_pgt_device(struct pgt_device *pdev)
 {
 	clean_service_thread(pdev);
 	clean_initial_mmio_state(pdev);
+	gvt_clean_resource_allocator(pdev);
 }
 
 static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *dev_priv)
@@ -246,6 +247,8 @@ static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *de
 	if (!init_initial_mmio_state(pdev))
 		goto err;
 
+	gvt_init_resource_allocator(pdev);
+
 	if (!init_service_thread(pdev))
 		goto err;
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 6c85bba..aa4851c 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -36,6 +36,11 @@
 
 #define GVT_MAX_VGPU 8
 
+#define GVT_MAX_GM_SIZE		(1UL << 32)
+#define GVT_GM_BITMAP_BITS	(GVT_MAX_GM_SIZE >> 20)
+#define GVT_MAX_NUM_FENCES	32
+#define GVT_FENCE_BITMAP_BITS	GVT_MAX_NUM_FENCES
+
 enum {
 	GVT_HYPERVISOR_TYPE_XEN = 0,
 	GVT_HYPERVISOR_TYPE_KVM,
@@ -62,11 +67,38 @@ struct gvt_device_info {
 	u32 gmadr_bytes_in_cmd;
 };
 
+struct gvt_gm_node {
+	struct drm_mm_node *low_gm_node;
+	struct drm_mm_node *high_gm_node;
+};
+
+struct gvt_virtual_gm_state {
+	u64 aperture_base;
+	void *aperture_base_va;
+	u64 aperture_sz;
+	u64 gm_sz;
+	u64 aperture_offset;        /* address fix for visible GM */
+	u64 hidden_gm_offset;       /* address fix for invisible GM */
+	int fence_base;
+	int fence_sz;
+	struct gvt_gm_node node;
+};
+
+struct gvt_virtual_device_state {
+	struct gvt_virtual_gm_state gm;
+};
+
 struct vgt_device {
 	int id;
 	int vm_id;
 	struct pgt_device *pdev;
 	bool warn_untrack;
+	struct gvt_virtual_device_state state;
+};
+
+struct gvt_gm_allocator {
+	struct drm_mm low_gm;
+	struct drm_mm high_gm;
 };
 
 struct pgt_device {
@@ -93,8 +125,81 @@ struct pgt_device {
 	wait_queue_head_t service_thread_wq;
 	struct task_struct *service_thread;
 	unsigned long service_request;
+
+	/* 1 bit corresponds to 1MB in the GM space */
+	DECLARE_BITMAP(gm_bitmap, GVT_GM_BITMAP_BITS);
+
+	/* 1 bit corresponds to 1 fence register */
+	DECLARE_BITMAP(fence_bitmap, GVT_FENCE_BITMAP_BITS);
+
+	u64 total_gm_sz;
+	struct gvt_gm_allocator gm_allocator;
 };
 
+/* definitions for physical aperture/GM space */
+#define phys_aperture_sz(pdev)          (pdev->bar_size[1])
+#define phys_aperture_pages(pdev)       (phys_aperture_sz(pdev) >> GTT_PAGE_SHIFT)
+#define phys_aperture_base(pdev)        (pdev->gmadr_base)
+#define phys_aperture_vbase(pdev)       (pdev->gmadr_va)
+
+#define gm_sz(pdev)                     (pdev->total_gm_sz)
+#define gm_base(pdev)                   (0ULL)
+#define gm_pages(pdev)                  (gm_sz(pdev) >> GTT_PAGE_SHIFT)
+#define hidden_gm_base(pdev)            (phys_aperture_sz(pdev))
+
+#define aperture_2_gm(pdev, addr)       (addr - phys_aperture_base(pdev))
+#define v_aperture(pdev, addr)          (phys_aperture_vbase(pdev) + (addr))
+
+/* definitions for vgt's aperture/gm space */
+#define gvt_aperture_base(vgt)		(vgt->state.gm.aperture_base)
+#define gvt_aperture_vbase(vgt)		(vgt->state.gm.aperture_base_va)
+#define gvt_aperture_offset(vgt)	(vgt->state.gm.aperture_offset)
+#define gvt_hidden_gm_offset(vgt)	(vgt->state.gm.hidden_gm_offset)
+#define gvt_aperture_sz(vgt)		(vgt->state.gm.aperture_sz)
+#define gvt_gm_sz(vgt)			(vgt->state.gm.gm_sz)
+#define gvt_hidden_gm_sz(vgt)		(gvt_gm_sz(vgt) - gvt_aperture_sz(vgt))
+#define gvt_fence_base(vgt)		(vgt->state.gm.fence_base)
+#define gvt_fence_sz(vgt)		(vgt->state.gm.fence_sz)
+
+#define gvt_aperture_end(vgt)           \
+	(gvt_aperture_base(vgt) + gvt_aperture_sz(vgt) - 1)
+#define gvt_visible_gm_base(vgt)        \
+	(gm_base(vgt->pdev) + gvt_aperture_offset(vgt))
+#define gvt_visible_gm_end(vgt)         \
+	(gvt_visible_gm_base(vgt) + gvt_aperture_sz(vgt) - 1)
+#define gvt_hidden_gm_base(vgt) \
+	(gm_base(vgt->pdev) + gvt_hidden_gm_offset(vgt))
+#define gvt_hidden_gm_end(vgt)          \
+	(gvt_hidden_gm_base(vgt) + gvt_hidden_gm_sz(vgt) - 1)
+
+/*
+ * the view of the aperture/gm space from the VM's p.o.v
+ *
+ * when the VM supports ballooning, this view is the same as the
+ * view of vGT driver.
+ *
+ * when the VM does not support ballooning, this view starts from
+ * GM space ZERO
+ */
+#define gvt_guest_aperture_base(vgt)    \
+	((*((u32*)&vgt->state.cfg.space[GVT_REG_CFG_SPACE_BAR1]) & ~0xf) + gvt_aperture_offset(vgt))
+#define gvt_guest_aperture_end(vgt)     \
+        (gvt_guest_aperture_base(vgt) + gvt_aperture_sz(vgt) - 1)
+#define gvt_guest_visible_gm_base(vgt)  \
+        (gvt_visible_gm_base(vgt))
+#define gvt_guest_visible_gm_end(vgt)   \
+        (gvt_guest_visible_gm_base(vgt) + gvt_aperture_sz(vgt) - 1)
+#define gvt_guest_hidden_gm_base(vgt)   \
+	gvt_hidden_gm_base(vgt)
+#define gvt_guest_hidden_gm_end(vgt)    \
+        (gvt_guest_hidden_gm_base(vgt) + gvt_hidden_gm_sz(vgt) - 1)
+
+extern void gvt_init_resource_allocator(struct pgt_device *pdev);
+extern void gvt_clean_resource_allocator(struct pgt_device *pdev);
+extern int gvt_alloc_gm_and_fence_resource(struct vgt_device *vgt,
+		struct gvt_instance_info *info);
+extern void gvt_free_gm_and_fence_resource(struct vgt_device *vgt);
+
 static inline u32 gvt_mmio_read(struct pgt_device *pdev,
 		u32 reg)
 {
diff --git a/drivers/gpu/drm/i915/gvt/params.c b/drivers/gpu/drm/i915/gvt/params.c
index dfc33c3..6cd324c 100644
--- a/drivers/gpu/drm/i915/gvt/params.c
+++ b/drivers/gpu/drm/i915/gvt/params.c
@@ -26,4 +26,16 @@
 struct gvt_kernel_params gvt = {
 	.enable = true,
 	.debug = 0,
+	.dom0_low_gm_sz = 96,
+	.dom0_high_gm_sz = 384,
+	.dom0_fence_sz = 4,
 };
+
+module_param_named(dom0_low_gm_sz, gvt.dom0_low_gm_sz, int, 0600);
+MODULE_PARM_DESC(dom0_low_gm_sz, "Amount of aperture size of DOM0");
+
+module_param_named(dom0_high_gm_sz, gvt.dom0_high_gm_sz, int, 0600);
+MODULE_PARM_DESC(dom0_high_gm_sz, "Amount of high memory size of DOM0");
+
+module_param_named(dom0_fence_sz, gvt.dom0_fence_sz, int, 0600);
+MODULE_PARM_DESC(dom0_fence_sz, "Amount of fence size of DOM0");
diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
index 0656a98..0507870 100644
--- a/drivers/gpu/drm/i915/gvt/params.h
+++ b/drivers/gpu/drm/i915/gvt/params.h
@@ -34,4 +34,12 @@ struct gvt_kernel_params {
 
 extern struct gvt_kernel_params gvt;
 
+struct gvt_instance_info {
+	u32 domid;
+	u32 low_gm_sz;
+	u32 high_gm_sz;
+	u32 fence_sz;
+	s32 primary;
+};
+
 #endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 10/29] drm/i915: gvt: Basic mmio emulation state
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (8 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 09/29] drm/i915: gvt: Resource allocator Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 11/29] drm/i915: gvt: update PVINFO page definition in i915_vgpu.h Zhi Wang
                   ` (19 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This patch introduces the basic prototypes and definitions for GVT guest
MMIO emulation.

- Save an original MMIO snaphot when system boot up, which will
be used as the initial guest MMIO content.

- Introduce a framework to tracked all kinds of GEN MMIO registers,
each tracked MMIO register may have a handler to emulate the HW registers
change.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile   |   2 +-
 drivers/gpu/drm/i915/gvt/gvt.c      |   9 ++
 drivers/gpu/drm/i915/gvt/gvt.h      | 127 ++++++++++++++++
 drivers/gpu/drm/i915/gvt/handlers.c |  47 ++++++
 drivers/gpu/drm/i915/gvt/mmio.c     | 290 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/mmio.h     |  87 +++++++++++
 drivers/gpu/drm/i915/gvt/reg.h      |   4 +
 7 files changed, 565 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/handlers.c
 create mode 100644 drivers/gpu/drm/i915/gvt/mmio.c
 create mode 100644 drivers/gpu/drm/i915/gvt/mmio.h

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index 6655929..5d28ed1 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,4 +1,4 @@
-GVT_SOURCE := gvt.o params.o aperture_gm.o fb_decoder.o
+GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o fb_decoder.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index f31e9f7..f5066bc 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -136,6 +136,8 @@ static void init_initial_cfg_space_state(struct pgt_device *pdev)
 
 static void clean_initial_mmio_state(struct pgt_device *pdev)
 {
+	gvt_clean_initial_mmio_state(pdev);
+
 	if (pdev->gttmmio_va) {
 		iounmap(pdev->gttmmio_va);
 		pdev->gttmmio_va = NULL;
@@ -179,6 +181,9 @@ static bool init_initial_mmio_state(struct pgt_device *pdev)
 	gvt_info("gttmmio_va: %p", pdev->gttmmio_va);
 	gvt_info("gmadr_va: %p", pdev->gmadr_va);
 
+	if (!gvt_setup_initial_mmio_state(pdev))
+		goto err;
+
 	return true;
 err:
 	clean_initial_mmio_state(pdev);
@@ -233,6 +238,7 @@ static bool init_service_thread(struct pgt_device *pdev)
 static void clean_pgt_device(struct pgt_device *pdev)
 {
 	clean_service_thread(pdev);
+	gvt_clean_mmio_emulation_state(pdev);
 	clean_initial_mmio_state(pdev);
 	gvt_clean_resource_allocator(pdev);
 }
@@ -249,6 +255,9 @@ static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *de
 
 	gvt_init_resource_allocator(pdev);
 
+	if (!gvt_setup_mmio_emulation_state(pdev))
+		goto err;
+
 	if (!init_service_thread(pdev))
 		goto err;
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index aa4851c..798e216 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -33,6 +33,7 @@
 #include "hypercall.h"
 #include "mpt.h"
 #include "fb_decoder.h"
+#include "mmio.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -41,6 +42,8 @@
 #define GVT_MAX_NUM_FENCES	32
 #define GVT_FENCE_BITMAP_BITS	GVT_MAX_NUM_FENCES
 
+#define GVT_HASH_BITS 9
+
 enum {
 	GVT_HYPERVISOR_TYPE_XEN = 0,
 	GVT_HYPERVISOR_TYPE_KVM,
@@ -133,7 +136,16 @@ struct pgt_device {
 	DECLARE_BITMAP(fence_bitmap, GVT_FENCE_BITMAP_BITS);
 
 	u64 total_gm_sz;
+
 	struct gvt_gm_allocator gm_allocator;
+
+	u32 *initial_mmio_state;
+	u32 *reg_info;
+
+	gvt_aux_entry_t aux_table[GVT_AUX_TABLE_NUM];
+	u32 aux_table_index;
+
+	DECLARE_HASHTABLE(mmio_table, GVT_HASH_BITS);
 };
 
 /* definitions for physical aperture/GM space */
@@ -200,6 +212,108 @@ extern int gvt_alloc_gm_and_fence_resource(struct vgt_device *vgt,
 		struct gvt_instance_info *info);
 extern void gvt_free_gm_and_fence_resource(struct vgt_device *vgt);
 
+#define REG_INDEX(reg) ((reg) >> 2)
+
+#define D_SNB   (1 << 0)
+#define D_IVB   (1 << 1)
+#define D_HSW   (1 << 2)
+#define D_BDW   (1 << 3)
+
+#define D_GEN8PLUS      (D_BDW)
+#define D_GEN75PLUS     (D_HSW | D_BDW)
+#define D_GEN7PLUS      (D_IVB | D_HSW | D_BDW)
+
+#define D_BDW_PLUS      (D_BDW)
+#define D_HSW_PLUS      (D_HSW | D_BDW)
+#define D_IVB_PLUS      (D_IVB | D_HSW | D_BDW)
+
+#define D_PRE_BDW       (D_SNB | D_IVB | D_HSW)
+
+#define D_ALL           (D_SNB | D_IVB | D_HSW | D_BDW)
+
+#define reg_addr_fix(pdev, reg)		(pdev->reg_info[REG_INDEX(reg)] & GVT_REG_ADDR_FIX)
+#define reg_hw_status(pdev, reg)	(pdev->reg_info[REG_INDEX(reg)] & GVT_REG_HW_STATUS)
+#define reg_virt(pdev, reg)		(pdev->reg_info[REG_INDEX(reg)] & GVT_REG_VIRT)
+#define reg_mode_ctl(pdev, reg)		(pdev->reg_info[REG_INDEX(reg)] & GVT_REG_MODE_CTL)
+#define reg_is_tracked(pdev, reg)	(pdev->reg_info[REG_INDEX(reg)] & GVT_REG_TRACKED)
+#define reg_is_accessed(pdev, reg)	(pdev->reg_info[REG_INDEX(reg)] & GVT_REG_ACCESSED)
+#define reg_is_saved(pdev, reg)		(pdev->reg_info[REG_INDEX(reg)] & GVT_REG_SAVED)
+
+#define reg_aux_index(pdev, reg)	\
+	((pdev->reg_info[REG_INDEX(reg)] & GVT_REG_INDEX_MASK) >> GVT_REG_INDEX_SHIFT)
+#define reg_has_aux_info(pdev, reg)	(reg_mode_ctl(pdev, reg) | reg_addr_fix(pdev, reg))
+#define reg_aux_mode_mask(pdev, reg)	\
+	(pdev->aux_table[reg_aux_index(pdev, reg)].mode_ctl.mask)
+#define reg_aux_addr_mask(pdev, reg)	\
+	(pdev->aux_table[reg_aux_index(pdev, reg)].addr_fix.mask)
+#define reg_aux_addr_size(pdev, reg)	\
+	(pdev->aux_table[reg_aux_index(pdev, reg)].addr_fix.size)
+
+static inline void reg_set_hw_status(struct pgt_device *pdev, u32 reg)
+{
+	ASSERT_NUM(!reg_is_tracked(pdev, reg), reg);
+	pdev->reg_info[REG_INDEX(reg)] |= GVT_REG_HW_STATUS;
+}
+
+static inline void reg_set_virt(struct pgt_device *pdev, u32 reg)
+{
+	ASSERT_NUM(!reg_is_tracked(pdev, reg), reg);
+	pdev->reg_info[REG_INDEX(reg)] |= GVT_REG_VIRT;
+}
+
+/* mask bits for addr fix */
+static inline void reg_set_addr_fix(struct pgt_device *pdev,
+		u32 reg, u32 mask)
+{
+	ASSERT(!reg_has_aux_info(pdev, reg));
+	ASSERT(pdev->aux_table_index <= GVT_AUX_TABLE_NUM - 1);
+	ASSERT_NUM(!reg_is_tracked(pdev, reg), reg);
+
+	pdev->aux_table[pdev->aux_table_index].addr_fix.mask = mask;
+	pdev->reg_info[REG_INDEX(reg)] |= GVT_REG_ADDR_FIX |
+		(pdev->aux_table_index << GVT_REG_INDEX_SHIFT);
+	pdev->aux_table_index++;
+}
+
+/* mask bits for mode mask */
+static inline void reg_set_mode_ctl(struct pgt_device *pdev,
+		u32 reg)
+{
+	ASSERT(!reg_has_aux_info(pdev, reg));
+	ASSERT(pdev->aux_table_index <= GVT_AUX_TABLE_NUM - 1);
+	ASSERT_NUM(!reg_is_tracked(pdev, reg), reg);
+
+	pdev->reg_info[REG_INDEX(reg)] |= GVT_REG_MODE_CTL |
+		(pdev->aux_table_index << GVT_REG_INDEX_SHIFT);
+	pdev->aux_table_index++;
+}
+
+static inline void reg_set_tracked(struct pgt_device *pdev,
+		u32 reg)
+{
+	ASSERT_NUM(!reg_is_tracked(pdev, reg), reg);
+	pdev->reg_info[REG_INDEX(reg)] |= GVT_REG_TRACKED;
+}
+
+static inline void reg_set_accessed(struct pgt_device *pdev,
+		u32 reg)
+{
+	pdev->reg_info[REG_INDEX(reg)] |= GVT_REG_ACCESSED;
+}
+
+static inline void reg_set_saved(struct pgt_device *pdev,
+		u32 reg)
+{
+	pdev->reg_info[REG_INDEX(reg)] |= GVT_REG_SAVED;
+}
+
+static inline void reg_set_cmd_access(struct pgt_device *pdev,
+		u32 reg)
+{
+	pdev->reg_info[REG_INDEX(reg)] |= GVT_REG_CMD_ACCESS;
+	reg_set_accessed(pdev, reg);
+}
+
 static inline u32 gvt_mmio_read(struct pgt_device *pdev,
 		u32 reg)
 {
@@ -232,4 +346,17 @@ static inline void gvt_mmio_write64(struct pgt_device *pdev,
 	I915_WRITE64(tmp, val);
 }
 
+static inline void gvt_mmio_posting_read(struct pgt_device *pdev, u32 reg)
+{
+	struct drm_i915_private *dev_priv = pdev->dev_priv;
+	i915_reg_t tmp = {.reg = reg};
+	POSTING_READ(tmp);
+}
+
+extern void gvt_clean_initial_mmio_state(struct pgt_device *pdev);
+extern bool gvt_setup_initial_mmio_state(struct pgt_device *pdev);
+
+extern void gvt_clean_mmio_emulation_state(struct pgt_device *pdev);
+extern bool gvt_setup_mmio_emulation_state(struct pgt_device *pdev);
+
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
new file mode 100644
index 0000000..a6ec4f3
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+/* TODO: Merge register definition from i915. */
+struct gvt_reg_info gvt_general_reg_info[] = {
+{0, 0, 0, 0, 0, NULL, NULL},
+};
+
+struct gvt_reg_info gvt_broadwell_reg_info[] = {
+{0, 0, 0, 0, 0, NULL, NULL},
+};
+
+int gvt_get_reg_num(int type)
+{
+        switch(type){
+                case D_ALL:
+                        return ARRAY_SIZE(gvt_general_reg_info);
+                case D_BDW:
+                        return ARRAY_SIZE(gvt_broadwell_reg_info);
+                default:
+			return 0;
+        }
+
+        return 0;
+}
diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c
new file mode 100644
index 0000000..0fbabd2
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/mmio.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+static inline unsigned int get_device_type(struct pgt_device *pdev)
+{
+	if (IS_BROADWELL(pdev->dev_priv))
+		return D_BDW;
+	return 0;
+}
+
+static inline bool match_device(struct pgt_device *pdev, struct gvt_reg_info *info)
+{
+	return info->device & get_device_type(pdev);
+}
+
+static void save_initial_mmio_state(struct pgt_device *pdev,
+		struct gvt_reg_info *info, int num)
+{
+	u32 *mmio = pdev->initial_mmio_state;
+	int i, j;
+
+	for (i = 0; i < num; i++, info++) {
+		if (!match_device(pdev, info))
+			continue;
+
+		for (j = 0; j < info->size; j += 4)
+			mmio[REG_INDEX(info->reg + j)] =
+				gvt_mmio_read(pdev, info->reg + j);
+	}
+
+	gvt_dbg_core("save %d registers as initial mmio values", num);
+}
+
+static void patch_display_mmio_state(u32 *mmio_array)
+{
+	gvt_dbg_core("patch display initial mmio state");
+
+	/* TODO: vgt_dpy_init_modes. */
+	mmio_array[REG_INDEX(_WRPLL_CTL1)] &= ~(1 << 31);
+	mmio_array[REG_INDEX(_WRPLL_CTL2)] &= ~(1 << 31);
+}
+
+static void patch_initial_mmio_state(struct pgt_device *pdev)
+{
+	u32 *mmio_array = pdev->initial_mmio_state;
+
+	gvt_dbg_core("patch initial mmio state");
+
+	/* customize the initial MMIO
+	 * 1, GMBUS status
+	 * 2, Initial port status.
+	 */
+
+	/* GMBUS2 has an in-use bit as the hw semaphore, and we should recover
+	 * it after the snapshot.
+	 */
+	mmio_array[REG_INDEX(_PCH_GMBUS2)] &= ~0x8000;
+
+	gvt_mmio_write(pdev, _PCH_GMBUS2,
+			gvt_mmio_read(pdev, _PCH_GMBUS2) | 0x8000);
+
+	patch_display_mmio_state(mmio_array);
+}
+
+void gvt_clean_initial_mmio_state(struct pgt_device *pdev)
+{
+	if (pdev->initial_mmio_state) {
+		vfree(pdev->initial_mmio_state);
+		pdev->initial_mmio_state = NULL;
+	}
+}
+
+bool gvt_setup_initial_mmio_state(struct pgt_device *pdev)
+{
+	gvt_dbg_core("setup initial mmio state");
+
+	pdev->initial_mmio_state = vzalloc(pdev->mmio_size);
+	if (!pdev->initial_mmio_state) {
+		gvt_info("fail to allocate initial mmio state");
+		return false;
+	}
+
+	gvt_dbg_core("save generic initial mmio state");
+
+	save_initial_mmio_state(pdev, gvt_general_reg_info, gvt_get_reg_num(D_ALL));
+
+	if(IS_BROADWELL(pdev->dev_priv)) {
+		gvt_dbg_core("save broadwell initial mmio state");
+		save_initial_mmio_state(pdev, gvt_broadwell_reg_info, gvt_get_reg_num(D_BDW));
+	}
+
+	patch_initial_mmio_state(pdev);
+
+	return true;
+}
+
+static void add_mmio_entry(struct pgt_device *pdev, struct gvt_mmio_entry *e)
+{
+        hash_add(pdev->mmio_table, &e->hlist, e->base);
+}
+
+static struct gvt_mmio_entry *find_mmio_entry(struct pgt_device *pdev, unsigned int base)
+{
+        struct gvt_mmio_entry *e;
+
+        hash_for_each_possible(pdev->mmio_table, e, hlist, base) {
+                if (base == e->base)
+                        return e;
+        }
+        return NULL;
+}
+
+void remove_mmio_entry(struct pgt_device *pdev, unsigned int base)
+{
+        struct gvt_mmio_entry *e;
+
+        if ((e = find_mmio_entry(pdev, base))) {
+                hash_del(&e->hlist);
+                kfree(e);
+        }
+}
+
+void free_mmio_table(struct pgt_device *pdev)
+{
+        struct hlist_node *tmp;
+        struct gvt_mmio_entry *e;
+        int i;
+
+        hash_for_each_safe(pdev->mmio_table, i, tmp, e, hlist)
+                kfree(e);
+
+        hash_init(pdev->mmio_table);
+}
+
+bool register_mmio_handler(struct pgt_device *pdev, unsigned int start, int bytes,
+	gvt_mmio_handler_t read, gvt_mmio_handler_t write)
+{
+	unsigned int i, end;
+	struct gvt_mmio_entry *e;
+
+	end = start + bytes -1;
+
+	ASSERT((start & 3) == 0);
+	ASSERT(((end+1) & 3) == 0);
+
+	for (i = start; i < end; i += 4) {
+		e = find_mmio_entry(pdev, i);
+		if (e) {
+			e->read = read;
+			e->write = write;
+			continue;
+		}
+
+		e = kzalloc(sizeof(*e), GFP_KERNEL);
+		if (e == NULL) {
+			gvt_err("fail to allocate memory for mmio entry");
+			return false;
+		}
+
+		e->base = i;
+
+		/*
+		 * Win7 GFX driver uses memcpy to access the GVT PVINFO regs,
+		 * hence align_bytes can be 1.
+		 */
+		if (start >= VGT_PVINFO_PAGE &&
+			start < VGT_PVINFO_PAGE + VGT_PVINFO_SIZE)
+			e->align_bytes = 1;
+		else
+			e->align_bytes = 4;
+
+		e->read = read;
+		e->write = write;
+		INIT_HLIST_NODE(&e->hlist);
+		add_mmio_entry(pdev, e);
+	}
+	return true;
+}
+
+static void set_reg_attribute(struct pgt_device *pdev,
+		u32 reg, struct gvt_reg_info *info)
+{
+	/* ensure one entry per reg */
+	ASSERT_NUM(!reg_is_tracked(pdev, reg), reg);
+
+	if (reg_is_tracked(pdev, reg))
+		return;
+
+	if (info->flags & GVT_REG_ADDR_FIX) {
+		if (!info->addr_mask)
+			gvt_info("ZERO addr fix mask for %x", reg);
+
+		reg_set_addr_fix(pdev, reg, info->addr_mask);
+		/* set the default range size to 4, might be updated later */
+		reg_aux_addr_size(pdev, reg) = 4;
+	}
+
+	if (info->flags & GVT_REG_MODE_CTL)
+		reg_set_mode_ctl(pdev, reg);
+	if (info->flags & GVT_REG_VIRT)
+		reg_set_virt(pdev, reg);
+	if (info->flags & GVT_REG_HW_STATUS)
+		reg_set_hw_status(pdev, reg);
+
+	reg_set_tracked(pdev, reg);
+}
+
+static bool setup_reg_info(struct pgt_device *pdev, struct gvt_reg_info *info, int num)
+{
+	int i, count = 0, total = 0;
+	u32 reg;
+
+	for (i = 0; i < num; i++, info++) {
+		if (!match_device(pdev, info))
+			continue;
+
+		count++;
+
+		for (reg = info->reg;
+				reg < info->reg + info->size;
+				reg += 4) {
+			set_reg_attribute(pdev, reg, info);
+			total++;
+		}
+
+		if (info->read || info->write)
+			if (!register_mmio_handler(pdev, info->reg, info->size,
+					info->read, info->write))
+				return false;
+	}
+
+	gvt_info("total register tracked %d, total mmio entry %d",
+		count, total);
+
+	return true;
+}
+
+void gvt_clean_mmio_emulation_state(struct pgt_device *pdev)
+{
+	free_mmio_table(pdev);
+}
+
+bool gvt_setup_mmio_emulation_state(struct pgt_device *pdev)
+{
+        struct gvt_mmio_entry *e;
+
+	gvt_dbg_core("setup generic register info");
+
+	if (!setup_reg_info(pdev, gvt_general_reg_info, gvt_get_reg_num(D_ALL)))
+		goto err;
+
+	if(IS_BROADWELL(pdev->dev_priv)) {
+		gvt_dbg_core("setup broadwell register info");
+
+		if (!setup_reg_info(pdev, gvt_broadwell_reg_info, gvt_get_reg_num(D_BDW)))
+			goto err;
+	}
+
+	/* GDRST can be accessed by byte */
+	e = find_mmio_entry(pdev, _GEN6_GDRST);
+	if (e)
+		e->align_bytes = 1;
+
+	return true;
+err:
+	gvt_clean_mmio_emulation_state(pdev);
+	return false;
+}
diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h
new file mode 100644
index 0000000..caca60f
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/mmio.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_MMIO_H_
+#define _GVT_MMIO_H_
+
+#include "i915_drv.h"
+
+/* reg contains address, requiring fix */
+#define GVT_REG_ADDR_FIX	(1 << 5)
+/* Status bit updated from HW */
+#define GVT_REG_HW_STATUS	(1 << 6)
+/* Virtualized */
+#define GVT_REG_VIRT		(1 << 7)
+/* Mode ctl registers with high 16 bits as the mask bits */
+#define GVT_REG_MODE_CTL	(1 << 8)
+/* This reg has been tracked in vgt_base_reg_info */
+#define GVT_REG_TRACKED		(1 << 10)
+/* This reg has been accessed by a VM */
+#define GVT_REG_ACCESSED	(1 << 11)
+/* This reg is saved/restored at context switch time */
+#define GVT_REG_SAVED		(1 << 12)
+/* Accessed through GPU commands */
+#define GVT_REG_CMD_ACCESS	(1 << 14)
+/* index into another auxillary table. Maximum 256 entries now */
+#define GVT_REG_INDEX_SHIFT	16
+#define GVT_REG_INDEX_MASK	(0xFFFF << GVT_REG_INDEX_SHIFT)
+
+#define GVT_AUX_TABLE_NUM	256
+
+/* suppose a reg won't set both bits */
+typedef union {
+	struct {
+		u32 mask;
+	} mode_ctl;
+	struct {
+		u32 mask;
+		uint32_t  size;
+	} addr_fix;
+} gvt_aux_entry_t;
+
+struct vgt_device;
+
+typedef bool (*gvt_mmio_handler_t)(struct vgt_device *, unsigned int, void *, unsigned int);
+
+struct gvt_mmio_entry {
+	struct hlist_node hlist;
+	unsigned int base;
+	unsigned int align_bytes;
+	gvt_mmio_handler_t read;
+	gvt_mmio_handler_t write;
+};
+
+struct gvt_reg_info {
+	u32 reg;
+	u32 size;
+	u32 flags;
+	u32 addr_mask;
+	u32 device;
+	gvt_mmio_handler_t read;
+	gvt_mmio_handler_t write;
+};
+
+extern struct gvt_reg_info gvt_general_reg_info[];
+extern struct gvt_reg_info gvt_broadwell_reg_info[];
+extern int gvt_get_reg_num(int type);
+#endif
diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
index d363b74..5682e1c 100644
--- a/drivers/gpu/drm/i915/gvt/reg.h
+++ b/drivers/gpu/drm/i915/gvt/reg.h
@@ -31,4 +31,8 @@
 #define GVT_REG_CFG_SPACE_BAR1	0x18
 #define GVT_REG_CFG_SPACE_BAR2	0x20
 
+#define _PCH_GMBUS2			0xc5108
+
+#define _GEN6_GDRST			0x941c
+
 #endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 11/29] drm/i915: gvt: update PVINFO page definition in i915_vgpu.h
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (9 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 10/29] drm/i915: gvt: Basic mmio emulation state Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 12/29] drm/i915: gvt: vGPU life cycle management Zhi Wang
                   ` (18 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/i915_vgpu.h | 85 +++++++++++++++++++++++++++++++++-------
 1 file changed, 70 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
index b8a49e6..21c77a2 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.h
+++ b/drivers/gpu/drm/i915/i915_vgpu.h
@@ -42,24 +42,47 @@
 	INTEL_VGT_IF_VERSION_ENCODE(VGT_VERSION_MAJOR, VGT_VERSION_MINOR)
 
 /*
- * notifications from guest to vgpu device model
+ * The information set by the guest gfx driver, through the display_ready field
+ */
+#define    VGT_DRV_DISPLAY_NOT_READY	(0 << 0)
+#define    VGT_DRV_DISPLAY_READY	(1 << 0)	/* ready for display switch */
+#define    VGT_DRV_LEGACY_VGA_MODE	(1 << 1)	/* in the legacy VGA mode */
+
+/*
+ * guest-to-vgt notifications
  */
 enum vgt_g2v_type {
-	VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE = 2,
+	VGT_G2V_DISPLAY_REFRESH,
+	VGT_G2V_SET_POINTER_SHAPE,
+	VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE,
 	VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY,
 	VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE,
 	VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY,
-	VGT_G2V_EXECLIST_CONTEXT_CREATE,
-	VGT_G2V_EXECLIST_CONTEXT_DESTROY,
+	VGT_G2V_EXECLIST_CONTEXT_ELEMENT_CREATE,
+	VGT_G2V_EXECLIST_CONTEXT_ELEMENT_DESTROY,
 	VGT_G2V_MAX,
 };
 
+/*
+ * vgt-to-guest notifications
+ */
+enum vgt_v2g_type {
+	VGT_V2G_SET_HW_CURSOR,
+	VGT_V2G_SET_SW_CURSOR,
+	VGT_V2G_MAX,
+};
+
+enum vgt_caps_type {
+	VGT_CAPS_PREEMPTION = (1 << 0),
+};
+
 struct vgt_if {
 	uint64_t magic;		/* VGT_MAGIC */
 	uint16_t version_major;
 	uint16_t version_minor;
 	uint32_t vgt_id;	/* ID of vGT instance */
-	uint32_t rsv1[12];	/* pad to offset 0x40 */
+	uint32_t vgt_caps;     /* VGT capabilties */
+	uint32_t rsv1[11];	/* pad to offset 0x40 */
 	/*
 	 *  Data structure to describe the balooning info of resources.
 	 *  Each VM can only have one portion of continuous area for now.
@@ -85,13 +108,44 @@ struct vgt_if {
 	/*
 	 * The bottom half page is for response from Gfx driver to hypervisor.
 	 */
-	uint32_t rsv4;
-	uint32_t display_ready;	/* ready for display owner switch */
+	uint16_t  drv_version_major;
+	uint16_t  drv_version_minor;
+	uint32_t  display_ready;/* ready for display owner switch */
+	/*
+	 * driver reported status/error code
+	 *     0: if the avail_rs is sufficient to driver
+	 *  Bit 2,1,0 set indicating
+	 *       Insufficient low_gmadr, high_gmadr, fence resources.
+	 *  Other bits are reserved.
+	 */
+	uint32_t  rs_insufficient;
+	/*
+	 * The driver is required to update the following field with minimal
+	 * required resource size.
+	 */
+	uint32_t  min_low_gmadr;
+	uint32_t  min_high_gmadr;
+	uint32_t  min_fence_num;
+
+	/*
+	 * notifications between guest and vgt
+	 */
+	uint32_t  g2v_notify;
+	uint32_t  v2g_notify;
 
-	uint32_t rsv5[4];
+	/*
+	 * PPGTT PTE table info
+	 */
+	uint32_t  gmm_gtt_seg_base;
+	uint32_t  rsv4;
+	uint32_t  gmm_gtt_seg_size;
+	uint32_t  rsv5;
 
-	uint32_t g2v_notify;
-	uint32_t rsv6[7];
+	/*
+	 * Cursor hotspot info
+	 */
+	uint32_t  xhot;
+	uint32_t  yhot;
 
 	struct {
 		uint32_t lo;
@@ -101,16 +155,17 @@ struct vgt_if {
 	uint32_t execlist_context_descriptor_lo;
 	uint32_t execlist_context_descriptor_hi;
 
-	uint32_t  rsv7[0x200 - 24];    /* pad to one page */
+	/*
+	 * scratch space for debugging
+	 */
+	uint32_t  scratch;;
+
+	uint32_t  rsv6[0x200-25];    /* pad to one page */
 } __packed;
 
 #define vgtif_reg(x) \
 	_MMIO((VGT_PVINFO_PAGE + (long)&((struct vgt_if *)NULL)->x))
 
-/* vGPU display status to be used by the host side */
-#define VGT_DRV_DISPLAY_NOT_READY 0
-#define VGT_DRV_DISPLAY_READY     1  /* ready for display switch */
-
 extern void i915_check_vgpu(struct drm_device *dev);
 extern int intel_vgt_balloon(struct drm_device *dev);
 extern void intel_vgt_deballoon(void);
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 12/29] drm/i915: gvt: vGPU life cycle management
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (10 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 11/29] drm/i915: gvt: update PVINFO page definition in i915_vgpu.h Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 13/29] drm/i915: gvt: trace stub Zhi Wang
                   ` (17 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This patch introduces vGPU life cycle management framework. vGPU instance
is a collection of virtual GEN hardware status, like virtual CFG/MMIO registers,
how much GGTT memory space/Fence this vGPU owns, etc.

A vGPU instance consists following virtualized/limited resources:

- Configuration space(virtualized)
- MMIO registers(virtualized)
- GGTT memory space(limited)
- GGTT page table(shadowed)
- Fence(limited)

The framework is responsible for createing/destroying a vGPU instance,
allocating/freeing the per-vGPU resource from GVT-g resource allocator,
presenting them in the virtual PVINFO page located in virtual MMIO bar, which
provides the basic foundation blocks to GVT-g CFG/MMIO emulation framework.

A big picture here looks like:

+-----------------------------------------------------------------------+
|                      XEN/KVM Hypervisor                               |
+---------------------------+--------^----------------------------------+
   CFG/MMIO emulate request |        | Emulation is done
    from hypervisor         |        | Return the result to hypervisor
                            |        |
+---------------------------v--------+-----------------------------------+
|                  GVT-g  CFG/MMIO emulation framework                   |
+-----+-----^----------------+-----^---------------------+-------^-------+
      |     |                |     |                     |       |
      |     | *vGPU instance |     |             *vGPU 2 |       |
+-----v-----+----------+-----v-----+-------------+ +-----v-------+-------+
| vConfiguration Space |vGTT/MMIO/Fence registers| |  ...                |
+----------------------+-------------------------+ +---------------------+
                          vGPU life cycle management

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile   |   2 +-
 drivers/gpu/drm/i915/gvt/gvt.h      |  66 ++++++++++
 drivers/gpu/drm/i915/gvt/instance.c | 235 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/mmio.c     |  32 +++++
 drivers/gpu/drm/i915/gvt/params.c   |   1 +
 drivers/gpu/drm/i915/gvt/params.h   |   1 +
 drivers/gpu/drm/i915/gvt/reg.h      |  29 ++++-
 drivers/gpu/drm/i915/i915_vgpu.h    |   5 +-
 8 files changed, 365 insertions(+), 6 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/instance.c

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index 5d28ed1..f4dcf9a 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,4 +1,4 @@
-GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o fb_decoder.o
+GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o fb_decoder.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 798e216..c58305f 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -75,6 +75,17 @@ struct gvt_gm_node {
 	struct drm_mm_node *high_gm_node;
 };
 
+struct gvt_virtual_mmio_state {
+	void *vreg;
+	void *sreg;
+};
+
+struct gvt_virtual_cfg_state {
+	unsigned char space[GVT_CFG_SPACE_SZ];
+	bool bar_mapped[GVT_BAR_NUM];
+	u64 bar_size[GVT_BAR_NUM];
+};
+
 struct gvt_virtual_gm_state {
 	u64 aperture_base;
 	void *aperture_base_va;
@@ -89,6 +100,8 @@ struct gvt_virtual_gm_state {
 
 struct gvt_virtual_device_state {
 	struct gvt_virtual_gm_state gm;
+	struct gvt_virtual_mmio_state mmio;
+	struct gvt_virtual_cfg_state cfg;
 };
 
 struct vgt_device {
@@ -96,6 +109,7 @@ struct vgt_device {
 	int vm_id;
 	struct pgt_device *pdev;
 	bool warn_untrack;
+	atomic_t active;
 	struct gvt_virtual_device_state state;
 };
 
@@ -359,4 +373,56 @@ extern bool gvt_setup_initial_mmio_state(struct pgt_device *pdev);
 extern void gvt_clean_mmio_emulation_state(struct pgt_device *pdev);
 extern bool gvt_setup_mmio_emulation_state(struct pgt_device *pdev);
 
+static inline void gvt_pci_bar_write_32(struct vgt_device *vgt, uint32_t bar_offset, uint32_t val)
+{
+	uint32_t* cfg_reg;
+
+	/* BAR offset should be 32 bits algiend */
+	cfg_reg = (u32 *)&vgt->state.cfg.space[bar_offset & ~3];
+
+	/* only write the bits 31-4, leave the 3-0 bits unchanged, as they are read-only */
+	*cfg_reg = (val & 0xFFFFFFF0) | (*cfg_reg & 0xF);
+}
+
+static inline int gvt_pci_mmio_is_enabled(struct vgt_device *vgt)
+{
+	return vgt->state.cfg.space[GVT_REG_CFG_COMMAND] &
+		_REGBIT_CFG_COMMAND_MEMORY;
+}
+
+#define __vreg(vgt, off) (*(u32*)(vgt->state.mmio.vreg + off))
+#define __vreg8(vgt, off) (*(u8*)(vgt->state.mmio.vreg + off))
+#define __vreg16(vgt, off) (*(u16*)(vgt->state.mmio.vreg + off))
+#define __vreg64(vgt, off) (*(u64*)(vgt->state.mmio.vreg + off))
+
+#define __sreg(vgt, off) (*(u32*)(vgt->state.mmio.sreg + off))
+#define __sreg8(vgt, off) (*(u8*)(vgt->state.mmio.sreg + off))
+#define __sreg16(vgt, off) (*(u16*)(vgt->state.mmio.sreg + off))
+#define __sreg64(vgt, off) (*(u64*)(vgt->state.mmio.sreg + off))
+
+static inline void gvt_set_instance_online(struct vgt_device *vgt)
+{
+	atomic_set(&vgt->active, 1);
+}
+
+static inline void gvt_set_instance_offline(struct vgt_device *vgt)
+{
+	atomic_set(&vgt->active, 0);
+}
+
+static inline bool gvt_instance_is_online(struct vgt_device *vgt)
+{
+	return atomic_read(&vgt->active);
+}
+
+#define for_each_online_instance(pdev, vgt, id) \
+       idr_for_each_entry(&pdev->instance_idr, vgt, id) \
+               if (gvt_instance_is_online(vgt))
+
+extern void gvt_init_shadow_mmio_register(struct vgt_device *pdev);
+extern void gvt_init_virtual_mmio_register(struct vgt_device *pdev);
+extern struct vgt_device *gvt_create_instance(struct pgt_device *pdev,
+		struct gvt_instance_info *info);
+extern void gvt_destroy_instance(struct vgt_device *vgt);
+
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/instance.c b/drivers/gpu/drm/i915/gvt/instance.c
new file mode 100644
index 0000000..07b797a
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/instance.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+#include "i915_vgpu.h"
+
+static void destroy_virtual_mmio_state(struct vgt_device *vgt)
+{
+	struct gvt_virtual_device_state *state = &vgt->state;
+
+	if (state->mmio.vreg) {
+		vfree(state->mmio.vreg);
+		state->mmio.vreg = NULL;
+	}
+	if (state->mmio.sreg) {
+		vfree(state->mmio.sreg);
+		state->mmio.sreg = NULL;
+	}
+}
+
+static bool create_virtual_mmio_state(struct vgt_device *vgt)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_virtual_device_state *state = &vgt->state;
+
+	state->mmio.vreg = vzalloc(pdev->mmio_size);
+	state->mmio.sreg = vzalloc(pdev->mmio_size);
+
+	if (state->mmio.vreg == NULL || state->mmio.sreg == NULL ) {
+		gvt_err("fail to allocate memory for virtual states.");
+		goto err;
+	}
+
+	gvt_init_shadow_mmio_register(vgt);
+	gvt_init_virtual_mmio_register(vgt);
+
+	return true;
+err:
+	destroy_virtual_mmio_state(vgt);
+	return false;
+}
+
+static void init_virtual_cfg_space_state(struct vgt_device *vgt,
+	struct gvt_instance_info *info)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_virtual_device_state *state = &vgt->state;
+	int i;
+
+	char *cfg_space;
+	u16 *gmch_ctl;
+
+	cfg_space = state->cfg.space;
+
+	memcpy(cfg_space, pdev->initial_cfg_space, GVT_CFG_SPACE_SZ);
+	cfg_space[GVT_REG_CFG_SPACE_MSAC] = state->cfg.bar_size[1];
+
+	if (info->primary == 0 || ((info->primary == -1) && !gvt.primary)) {
+		cfg_space[GVT_REG_CFG_CLASS_CODE] = GVT_PCI_CLASS_VGA;
+		cfg_space[GVT_REG_CFG_SUB_CLASS_CODE] = GVT_PCI_CLASS_VGA_OTHER;
+		cfg_space[GVT_REG_CFG_CLASS_PROG_IF] = GVT_PCI_CLASS_VGA_OTHER;
+	}
+
+	/* Show guest that there isn't any stolen memory.*/
+	gmch_ctl = (u16 *)(cfg_space + _REG_GMCH_CONTROL);
+	*gmch_ctl &= ~(_REGBIT_BDW_GMCH_GMS_MASK << _REGBIT_BDW_GMCH_GMS_SHIFT);
+
+	gvt_pci_bar_write_32(vgt, GVT_REG_CFG_SPACE_BAR1, phys_aperture_base(pdev));
+
+	cfg_space[GVT_REG_CFG_COMMAND] &= ~(_REGBIT_CFG_COMMAND_IO |
+			_REGBIT_CFG_COMMAND_MEMORY |
+			_REGBIT_CFG_COMMAND_MASTER);
+
+	/* Clear the bar upper 32bit and let hvmloader to assign the new value */
+	memset(&cfg_space[GVT_REG_CFG_SPACE_BAR0 + 4], 0, 4);
+	memset(&cfg_space[GVT_REG_CFG_SPACE_BAR1 + 4], 0, 4);
+
+	state->cfg.bar_size[0] = pdev->bar_size[0];	/* MMIOGTT */
+	state->cfg.bar_size[1] = pdev->bar_size[1];
+	state->cfg.bar_size[2] = pdev->bar_size[2];	/* PIO */
+	state->cfg.bar_size[3] = pdev->bar_size[3];	/* ROM */
+
+	for (i = 0; i < GVT_BAR_NUM; i++)
+		state->cfg.bar_mapped[i] = false;
+}
+
+static void destroy_virtual_gm_state(struct vgt_device *vgt)
+{
+	gvt_free_gm_and_fence_resource(vgt);
+}
+
+static void populate_pvinfo_page(struct vgt_device *vgt)
+{
+	/* setup the ballooning information */
+	__vreg64(vgt, _vgtif_reg(magic)) = VGT_MAGIC;
+	__vreg(vgt, _vgtif_reg(version_major)) = 1;
+	__vreg(vgt, _vgtif_reg(version_minor)) = 0;
+	__vreg(vgt, _vgtif_reg(display_ready)) = 0;
+	__vreg(vgt, _vgtif_reg(vgt_id)) = vgt->id;
+	__vreg(vgt, _vgtif_reg(avail_rs.mappable_gmadr.base)) = gvt_visible_gm_base(vgt);
+	__vreg(vgt, _vgtif_reg(avail_rs.mappable_gmadr.size)) = gvt_aperture_sz(vgt);
+	__vreg(vgt, _vgtif_reg(avail_rs.nonmappable_gmadr.base)) = gvt_hidden_gm_base(vgt);
+	__vreg(vgt, _vgtif_reg(avail_rs.nonmappable_gmadr.size)) = gvt_hidden_gm_sz(vgt);
+
+	__vreg(vgt, _vgtif_reg(avail_rs.fence_num)) = gvt_fence_sz(vgt);
+	gvt_info("filling VGT_PVINFO_PAGE for dom%d:"
+			"   visable_gm_base=0x%llx, size=0x%llx"
+			"   hidden_gm_base=0x%llx, size=0x%llx"
+			"   fence_base=%d, num=%d",
+			vgt->id,
+			gvt_visible_gm_base(vgt), gvt_aperture_sz(vgt),
+			gvt_hidden_gm_base(vgt), gvt_hidden_gm_sz(vgt),
+			gvt_fence_base(vgt), gvt_fence_sz(vgt));
+
+	ASSERT(sizeof(struct vgt_if) == VGT_PVINFO_SIZE);
+}
+
+static bool create_virtual_gm_state(struct vgt_device *vgt,
+		struct gvt_instance_info *info)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_virtual_device_state *state = &vgt->state;
+
+	if (gvt_alloc_gm_and_fence_resource(vgt, info) < 0) {
+		gvt_err("fail to allocate graphics memory and fence");
+		return false;
+	}
+
+	state->gm.aperture_offset = aperture_2_gm(pdev, state->gm.aperture_base);
+	state->gm.aperture_base_va = phys_aperture_vbase(pdev) + state->gm.aperture_offset;
+
+	populate_pvinfo_page(vgt);
+
+	return true;
+}
+
+static void destroy_virtual_device_state(struct vgt_device *vgt)
+{
+	destroy_virtual_mmio_state(vgt);
+	destroy_virtual_gm_state(vgt);
+}
+
+static bool create_virtual_device_state(struct vgt_device *vgt,
+		struct gvt_instance_info *info)
+{
+	if (!create_virtual_mmio_state(vgt))
+		return false;
+
+	if (!create_virtual_gm_state(vgt, info))
+		return false;
+
+	init_virtual_cfg_space_state(vgt, info);
+
+	return true;
+}
+
+void gvt_destroy_instance(struct vgt_device *vgt)
+{
+	struct pgt_device *pdev = vgt->pdev;
+
+	mutex_lock(&pdev->lock);
+	gvt_set_instance_offline(vgt);
+	if (vgt->id != -1)
+		idr_remove(&pdev->instance_idr, vgt->id);
+	mutex_unlock(&pdev->lock);
+
+	hypervisor_hvm_exit(vgt);
+	destroy_virtual_device_state(vgt);
+	vfree(vgt);
+}
+
+struct vgt_device *gvt_create_instance(struct pgt_device *pdev,
+		struct gvt_instance_info *info)
+{
+	struct vgt_device *vgt = NULL;
+	int id;
+
+	gvt_info("vm_id=%d, low_gm_sz=%dMB, high_gm_sz=%dMB, fence_sz=%d",
+		info->domid, info->low_gm_sz, info->high_gm_sz, info->fence_sz);
+
+	vgt = vzalloc(sizeof(*vgt));
+	if (vgt == NULL) {
+		gvt_err("fail to allocate memory for instance.");
+		return NULL;
+	}
+
+	mutex_lock(&pdev->lock);
+
+	gvt_set_instance_offline(vgt);
+	id = idr_alloc(&pdev->instance_idr, vgt, 1, GVT_MAX_VGPU - 1, GFP_KERNEL);
+	if (id < 0) {
+		gvt_err("fail to allocate id for vgt instance.");
+		goto err;
+	}
+
+	mutex_unlock(&pdev->lock);
+
+	vgt->vm_id = info->domid;
+	vgt->id = id;
+	vgt->pdev = pdev;
+
+	if (!create_virtual_device_state(vgt, info))
+		goto err;
+
+	if (hypervisor_hvm_init(vgt) < 0)
+		goto err;
+
+	gvt_set_instance_online(vgt);
+
+	return vgt;
+err:
+	mutex_unlock(&pdev->lock);
+	gvt_destroy_instance(vgt);
+	return NULL;
+}
diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c
index 0fbabd2..28e1393 100644
--- a/drivers/gpu/drm/i915/gvt/mmio.c
+++ b/drivers/gpu/drm/i915/gvt/mmio.c
@@ -288,3 +288,35 @@ err:
 	gvt_clean_mmio_emulation_state(pdev);
 	return false;
 }
+
+void gvt_init_virtual_mmio_register(struct vgt_device *vgt)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	int i;
+
+        for (i = 0; i < pdev->mmio_size; i += sizeof(u32)) {
+                /*
+                 * skip the area of VGT PV INFO PAGE because we need keep
+                 * its content across Dom0 S3.
+                */
+                if (i >= VGT_PVINFO_PAGE &&
+                        i < VGT_PVINFO_PAGE + VGT_PVINFO_SIZE)
+                        continue;
+
+                __vreg(vgt, i) = pdev->initial_mmio_state[REG_INDEX(i)];
+        }
+
+        /* set the bit 0:2 (Thread C-State) to C0
+         * TODO: consider other bit 3:31
+         */
+        __vreg(vgt, _GEN6_GT_THREAD_STATUS_REG) = 0;
+
+        /* set the bit 0:2(Core C-State ) to C0 */
+        __vreg(vgt, _GEN6_GT_CORE_STATUS) = 0;
+}
+
+void gvt_init_shadow_mmio_register(struct vgt_device *vgt)
+{
+	struct gvt_virtual_device_state *state = &vgt->state;
+        memcpy (state->mmio.sreg, vgt->pdev->initial_mmio_state, vgt->pdev->mmio_size);
+}
diff --git a/drivers/gpu/drm/i915/gvt/params.c b/drivers/gpu/drm/i915/gvt/params.c
index 6cd324c..fca49b0 100644
--- a/drivers/gpu/drm/i915/gvt/params.c
+++ b/drivers/gpu/drm/i915/gvt/params.c
@@ -25,6 +25,7 @@
 
 struct gvt_kernel_params gvt = {
 	.enable = true,
+	.primary = true,
 	.debug = 0,
 	.dom0_low_gm_sz = 96,
 	.dom0_high_gm_sz = 384,
diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
index 0507870..80255c3 100644
--- a/drivers/gpu/drm/i915/gvt/params.h
+++ b/drivers/gpu/drm/i915/gvt/params.h
@@ -26,6 +26,7 @@
 
 struct gvt_kernel_params {
 	bool enable;
+	bool primary;
 	int debug;
 	int dom0_low_gm_sz;
 	int dom0_high_gm_sz;
diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
index 5682e1c..2edaf7c 100644
--- a/drivers/gpu/drm/i915/gvt/reg.h
+++ b/drivers/gpu/drm/i915/gvt/reg.h
@@ -27,12 +27,35 @@
 #define GVT_CFG_SPACE_SZ	256
 #define GVT_BAR_NUM		4
 
-#define GVT_REG_CFG_SPACE_BAR0	0x10
-#define GVT_REG_CFG_SPACE_BAR1	0x18
-#define GVT_REG_CFG_SPACE_BAR2	0x20
+#define GVT_PCI_CLASS_VGA			0x03
+#define GVT_PCI_CLASS_VGA_OTHER			0x80
+
+#define GVT_REG_CFG_VENDOR_ID                   0x00
+#define GVT_REG_CFG_COMMAND                     0x04
+#define _REGBIT_CFG_COMMAND_IO                  (1 << 0)
+#define _REGBIT_CFG_COMMAND_MEMORY              (1 << 1)
+#define _REGBIT_CFG_COMMAND_MASTER              (1 << 2)
+#define GVT_REG_CFG_CLASS_PROG_IF               0x09
+#define GVT_REG_CFG_SUB_CLASS_CODE              0x0A
+#define GVT_REG_CFG_CLASS_CODE                  0x0B
+#define GVT_REG_CFG_SPACE_BAR0                  0x10
+#define GVT_REG_CFG_SPACE_BAR1                  0x18
+#define GVT_REG_CFG_SPACE_BAR2                  0x20
+#define GVT_REG_CFG_SPACE_BAR_ROM               0x30
+#define GVT_REG_CFG_SPACE_MSAC                  0x62
+#define GVT_REG_CFG_SWSCI_TRIGGER               0xE8
+#define _REGBIT_CFG_SWSCI_SCI_SELECT            (1 << 15)
+#define _REGBIT_CFG_SWSCI_SCI_TRIGGER           1
+#define GVT_REG_CFG_OPREGION                    0xFC
+
+#define _REG_GMCH_CONTROL               0x50
+#define    _REGBIT_BDW_GMCH_GMS_SHIFT   8
+#define    _REGBIT_BDW_GMCH_GMS_MASK    0xff
 
 #define _PCH_GMBUS2			0xc5108
 
 #define _GEN6_GDRST			0x941c
+#define _GEN6_GT_THREAD_STATUS_REG	0x13805c
+#define _GEN6_GT_CORE_STATUS		0x138060
 
 #endif
diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
index 21c77a2..b6d9fc7 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.h
+++ b/drivers/gpu/drm/i915/i915_vgpu.h
@@ -163,8 +163,9 @@ struct vgt_if {
 	uint32_t  rsv6[0x200-25];    /* pad to one page */
 } __packed;
 
-#define vgtif_reg(x) \
-	_MMIO((VGT_PVINFO_PAGE + (long)&((struct vgt_if *)NULL)->x))
+#define _vgtif_reg(x) \
+	((VGT_PVINFO_PAGE + (long)&((struct vgt_if *)NULL)->x))
+#define vgtif_reg(x) _MMIO(_vgtif_reg(x))
 
 extern void i915_check_vgpu(struct drm_device *dev);
 extern int intel_vgt_balloon(struct drm_device *dev);
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 13/29] drm/i915: gvt: trace stub
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (11 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 12/29] drm/i915: gvt: vGPU life cycle management Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 14/29] drm/i915: gvt: vGPU interrupt emulation framework Zhi Wang
                   ` (16 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile       |  3 ++-
 drivers/gpu/drm/i915/gvt/trace.h        | 36 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/trace_points.c | 29 ++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/trace.h
 create mode 100644 drivers/gpu/drm/i915/gvt/trace_points.c

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index f4dcf9a..285eb84 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,4 +1,5 @@
-GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o fb_decoder.o
+GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
+		trace_points.o fb_decoder.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/trace.h b/drivers/gpu/drm/i915/gvt/trace.h
new file mode 100644
index 0000000..c98600a
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/trace.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of Version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#if !defined(_GVT_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _GVT_TRACE_H_
+
+#include <linux/types.h>
+#include <linux/stringify.h>
+#include <linux/tracepoint.h>
+#include <asm/tsc.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM gvt
+
+#endif /* _GVT_TRACE_H_ */
+
+/* This part must be out of protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
diff --git a/drivers/gpu/drm/i915/gvt/trace_points.c b/drivers/gpu/drm/i915/gvt/trace_points.c
new file mode 100644
index 0000000..6d0ad19
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/trace_points.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright(c) 2011-2016 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 "trace.h"
+
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+#endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 14/29] drm/i915: gvt: vGPU interrupt emulation framework
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (12 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 13/29] drm/i915: gvt: trace stub Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 15/29] drm/i915: gvt: vGPU graphics memory " Zhi Wang
                   ` (15 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This patch introduces vGPU interrupt emulation framework.

The vGPU intrerrupt emulation framework is an event-based interrupt emulation
framework. It's responsible for emulating GEN hardware interrupts demanded
by other GVT-g emulation core component.

It consists serveral components:

- Descriptions of interrupt register bit definition
- Upper level <-> lower level interrupt mapping
- GEN HW IER/IMR/IIR register emulation routines
- Event-based interrupt propagation interface

The specific GVT-g component wants to emulate an interrupt to a VM just need
to specify an event: e.g RCS_MI_USER_INTERRUPT to the framework. The framework
will:

- Generate related virtual IIR bit according to guest virtual IER and IMRs,
- Generate related upper level interrupt virtual IIR bit accodring to the
cascade interrupt mapping
- Inject a MSI to guest

Then guest GEN driver will see a virtual GEN interrupt is asserted.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile    |   2 +-
 drivers/gpu/drm/i915/gvt/gvt.c       |   4 +
 drivers/gpu/drm/i915/gvt/gvt.h       |   6 +
 drivers/gpu/drm/i915/gvt/interrupt.c | 648 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/interrupt.h | 232 +++++++++++++
 drivers/gpu/drm/i915/gvt/perf.h      |  39 +++
 drivers/gpu/drm/i915/gvt/reg.h       |  31 ++
 7 files changed, 961 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/interrupt.c
 create mode 100644 drivers/gpu/drm/i915/gvt/interrupt.h
 create mode 100644 drivers/gpu/drm/i915/gvt/perf.h

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index 285eb84..78deefc 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,5 +1,5 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
-		trace_points.o fb_decoder.o
+		trace_points.o interrupt.o fb_decoder.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index f5066bc..a0a9667 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -238,6 +238,7 @@ static bool init_service_thread(struct pgt_device *pdev)
 static void clean_pgt_device(struct pgt_device *pdev)
 {
 	clean_service_thread(pdev);
+	gvt_irq_exit(pdev);
 	gvt_clean_mmio_emulation_state(pdev);
 	clean_initial_mmio_state(pdev);
 	gvt_clean_resource_allocator(pdev);
@@ -258,6 +259,9 @@ static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *de
 	if (!gvt_setup_mmio_emulation_state(pdev))
 		goto err;
 
+	if (!gvt_irq_init(pdev))
+		goto err;
+
 	if (!init_service_thread(pdev))
 		goto err;
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index c58305f..fad56b1 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -34,6 +34,8 @@
 #include "mpt.h"
 #include "fb_decoder.h"
 #include "mmio.h"
+#include "interrupt.h"
+#include "perf.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -111,6 +113,7 @@ struct vgt_device {
 	bool warn_untrack;
 	atomic_t active;
 	struct gvt_virtual_device_state state;
+	struct gvt_statistics stat;
 };
 
 struct gvt_gm_allocator {
@@ -160,6 +163,9 @@ struct pgt_device {
 	u32 aux_table_index;
 
 	DECLARE_HASHTABLE(mmio_table, GVT_HASH_BITS);
+
+	struct gvt_irq_state irq_state;
+	struct pgt_statistics stat;
 };
 
 /* definitions for physical aperture/GM space */
diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c
new file mode 100644
index 0000000..23d40ce
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/interrupt.c
@@ -0,0 +1,648 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+#include "interrupt.h"
+
+static void update_upstream_irq(struct vgt_device *vgt,
+		struct gvt_irq_info *info);
+
+static int gvt_irq_warn_once[GVT_MAX_VGPU+1][GVT_EVENT_MAX];
+
+char *gvt_irq_name[GVT_EVENT_MAX] = {
+	// GT
+	[RCS_MI_USER_INTERRUPT] = "Render Command Streamer MI USER INTERRUPT",
+	[RCS_DEBUG] = "Render EU debug from SVG",
+	[RCS_MMIO_SYNC_FLUSH] = "Render MMIO sync flush status",
+	[RCS_CMD_STREAMER_ERR] = "Render Command Streamer error interrupt",
+	[RCS_PIPE_CONTROL] = "Render PIPE CONTROL notify",
+	[RCS_WATCHDOG_EXCEEDED] = "Render Command Streamer Watchdog counter exceeded",
+	[RCS_PAGE_DIRECTORY_FAULT] = "Render page directory faults",
+	[RCS_AS_CONTEXT_SWITCH] = "Render AS Context Switch Interrupt",
+
+	[VCS_MI_USER_INTERRUPT] = "Video Command Streamer MI USER INTERRUPT",
+	[VCS_MMIO_SYNC_FLUSH] = "Video MMIO sync flush status",
+	[VCS_CMD_STREAMER_ERR] = "Video Command Streamer error interrupt",
+	[VCS_MI_FLUSH_DW] = "Video MI FLUSH DW notify",
+	[VCS_WATCHDOG_EXCEEDED] = "Video Command Streamer Watchdog counter exceeded",
+	[VCS_PAGE_DIRECTORY_FAULT] = "Video page directory faults",
+	[VCS_AS_CONTEXT_SWITCH] = "Video AS Context Switch Interrupt",
+	[VCS2_MI_USER_INTERRUPT] = "VCS2 Video Command Streamer MI USER INTERRUPT",
+	[VCS2_MI_FLUSH_DW] = "VCS2 Video MI FLUSH DW notify",
+	[VCS2_AS_CONTEXT_SWITCH] = "VCS2 Context Switch Interrupt",
+
+	[BCS_MI_USER_INTERRUPT] = "Blitter Command Streamer MI USER INTERRUPT",
+	[BCS_MMIO_SYNC_FLUSH] = "Billter MMIO sync flush status",
+	[BCS_CMD_STREAMER_ERR] = "Blitter Command Streamer error interrupt",
+	[BCS_MI_FLUSH_DW] = "Blitter MI FLUSH DW notify",
+	[BCS_PAGE_DIRECTORY_FAULT] = "Blitter page directory faults",
+	[BCS_AS_CONTEXT_SWITCH] = "Blitter AS Context Switch Interrupt",
+
+	[VECS_MI_FLUSH_DW] = "Video Enhanced Streamer MI FLUSH DW notify",
+	[VECS_AS_CONTEXT_SWITCH] = "VECS Context Switch Interrupt",
+
+	// DISPLAY
+	[PIPE_A_FIFO_UNDERRUN] = "Pipe A FIFO underrun",
+	[PIPE_A_CRC_ERR] = "Pipe A CRC error",
+	[PIPE_A_CRC_DONE] = "Pipe A CRC done",
+	[PIPE_A_VSYNC] = "Pipe A vsync",
+	[PIPE_A_LINE_COMPARE] = "Pipe A line compare",
+	[PIPE_A_ODD_FIELD] = "Pipe A odd field",
+	[PIPE_A_EVEN_FIELD] = "Pipe A even field",
+	[PIPE_A_VBLANK] = "Pipe A vblank",
+	[PIPE_B_FIFO_UNDERRUN] = "Pipe B FIFO underrun",
+	[PIPE_B_CRC_ERR] = "Pipe B CRC error",
+	[PIPE_B_CRC_DONE] = "Pipe B CRC done",
+	[PIPE_B_VSYNC] = "Pipe B vsync",
+	[PIPE_B_LINE_COMPARE] = "Pipe B line compare",
+	[PIPE_B_ODD_FIELD] = "Pipe B odd field",
+	[PIPE_B_EVEN_FIELD] = "Pipe B even field",
+	[PIPE_B_VBLANK] = "Pipe B vblank",
+	[PIPE_C_VBLANK] = "Pipe C vblank",
+	[DPST_PHASE_IN] = "DPST phase in event",
+	[DPST_HISTOGRAM] = "DPST histogram event",
+	[GSE] = "GSE",
+	[DP_A_HOTPLUG] = "DP A Hotplug",
+	[AUX_CHANNEL_A] = "AUX Channel A",
+	[PERF_COUNTER] = "Performance counter",
+	[POISON] = "Poison",
+	[GTT_FAULT] = "GTT fault",
+	[PRIMARY_A_FLIP_DONE] = "Primary Plane A flip done",
+	[PRIMARY_B_FLIP_DONE] = "Primary Plane B flip done",
+	[PRIMARY_C_FLIP_DONE] = "Primary Plane C flip done",
+	[SPRITE_A_FLIP_DONE] = "Sprite Plane A flip done",
+	[SPRITE_B_FLIP_DONE] = "Sprite Plane B flip done",
+	[SPRITE_C_FLIP_DONE] = "Sprite Plane C flip done",
+
+	[PCU_THERMAL] = "PCU Thermal Event",
+	[PCU_PCODE2DRIVER_MAILBOX] = "PCU pcode2driver mailbox event",
+
+	// PCH
+	[FDI_RX_INTERRUPTS_TRANSCODER_A] = "FDI RX Interrupts Combined A",
+	[AUDIO_CP_CHANGE_TRANSCODER_A] = "Audio CP Change Transcoder A",
+	[AUDIO_CP_REQUEST_TRANSCODER_A] = "Audio CP Request Transcoder A",
+	[FDI_RX_INTERRUPTS_TRANSCODER_B] = "FDI RX Interrupts Combined B",
+	[AUDIO_CP_CHANGE_TRANSCODER_B] = "Audio CP Change Transcoder B",
+	[AUDIO_CP_REQUEST_TRANSCODER_B] = "Audio CP Request Transcoder B",
+	[FDI_RX_INTERRUPTS_TRANSCODER_C] = "FDI RX Interrupts Combined C",
+	[AUDIO_CP_CHANGE_TRANSCODER_C] = "Audio CP Change Transcoder C",
+	[AUDIO_CP_REQUEST_TRANSCODER_C] = "Audio CP Request Transcoder C",
+	[ERR_AND_DBG] = "South Error and Debug Interupts Combined",
+	[GMBUS] = "Gmbus",
+	[SDVO_B_HOTPLUG] = "SDVO B hotplug",
+	[CRT_HOTPLUG] = "CRT Hotplug",
+	[DP_B_HOTPLUG] = "DisplayPort/HDMI/DVI B Hotplug",
+	[DP_C_HOTPLUG] = "DisplayPort/HDMI/DVI C Hotplug",
+	[DP_D_HOTPLUG] = "DisplayPort/HDMI/DVI D Hotplug",
+	[AUX_CHENNEL_B] = "AUX Channel B",
+	[AUX_CHENNEL_C] = "AUX Channel C",
+	[AUX_CHENNEL_D] = "AUX Channel D",
+	[AUDIO_POWER_STATE_CHANGE_B] = "Audio Power State change Port B",
+	[AUDIO_POWER_STATE_CHANGE_C] = "Audio Power State change Port C",
+	[AUDIO_POWER_STATE_CHANGE_D] = "Audio Power State change Port D",
+
+	[GVT_EVENT_RESERVED] = "RESERVED EVENTS!!!",
+};
+
+static inline struct gvt_irq_info *regbase_to_irq_info(struct pgt_device *pdev,
+		unsigned int reg)
+{
+	struct gvt_irq_state *state = &pdev->irq_state;
+	int i;
+
+	for_each_set_bit(i, state->irq_info_bitmap, GVT_IRQ_INFO_MAX) {
+		if (state->info[i]->reg_base == reg)
+			return state->info[i];
+	}
+
+	return NULL;
+}
+
+bool gvt_reg_imr_handler(struct vgt_device *vgt,
+	unsigned int reg, void *p_data, unsigned int bytes)
+{
+	uint32_t changed, masked, unmasked;
+	uint32_t imr = *(u32 *)p_data;
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_irq_ops *ops = gvt_get_irq_ops(pdev);
+
+	gvt_dbg_irq("IRQ: capture IMR write on reg (%x) with val (%x)",
+		reg, imr);
+
+	gvt_dbg_irq("IRQ: old vIMR(%x), pIMR(%x)",
+		 __vreg(vgt, reg), gvt_mmio_read(pdev, reg));
+
+	/* figure out newly masked/unmasked bits */
+	changed = __vreg(vgt, reg) ^ imr;
+	masked = (__vreg(vgt, reg) & changed) ^ changed;
+	unmasked = masked ^ changed;
+
+	gvt_dbg_irq("IRQ: changed (%x), masked(%x), unmasked (%x)",
+		changed, masked, unmasked);
+
+	__vreg(vgt, reg) = imr;
+
+	ops->check_pending_irq(vgt);
+	gvt_dbg_irq("IRQ: new vIMR(%x), pIMR(%x)",
+		 __vreg(vgt, reg), gvt_mmio_read(pdev, reg));
+	return true;
+}
+
+bool gvt_reg_master_irq_handler(struct vgt_device *vgt,
+	unsigned int reg, void *p_data, unsigned int bytes)
+{
+	uint32_t changed, enabled, disabled;
+	uint32_t ier = *(u32 *)p_data;
+	uint32_t virtual_ier = __vreg(vgt, reg);
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_irq_ops *ops = gvt_get_irq_ops(pdev);
+
+	gvt_dbg_irq("IRQ: capture master irq write on reg (%x) with val (%x)",
+		reg, ier);
+
+	gvt_dbg_irq("IRQ: old vreg(%x), preg(%x)",
+		 __vreg(vgt, reg), gvt_mmio_read(pdev, reg));
+
+	/*
+	 * GEN8_MASTER_IRQ is a special irq register,
+	 * only bit 31 is allowed to be modified
+	 * and treated as an IER bit.
+	 */
+	ier &= GEN8_MASTER_IRQ_CONTROL;
+	virtual_ier &= GEN8_MASTER_IRQ_CONTROL;
+	__vreg(vgt, reg) &= ~GEN8_MASTER_IRQ_CONTROL;
+	__vreg(vgt, reg) |= ier;
+
+	/* figure out newly enabled/disable bits */
+	changed = virtual_ier ^ ier;
+	enabled = (virtual_ier & changed) ^ changed;
+	disabled = enabled ^ changed;
+
+	gvt_dbg_irq("vGT_IRQ: changed (%x), enabled(%x), disabled(%x)",
+			changed, enabled, disabled);
+
+	ops->check_pending_irq(vgt);
+	gvt_dbg_irq("IRQ: new vreg(%x), preg(%x)",
+		 __vreg(vgt, reg), gvt_mmio_read(pdev, reg));
+	return true;
+}
+
+bool gvt_reg_ier_handler(struct vgt_device *vgt,
+	unsigned int reg, void *p_data, unsigned int bytes)
+{
+	uint32_t changed, enabled, disabled;
+	uint32_t ier = *(u32 *)p_data;
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_irq_ops *ops = gvt_get_irq_ops(pdev);
+	struct gvt_irq_info *info;
+
+	gvt_dbg_irq("IRQ: capture IER write on reg (%x) with val (%x)",
+		reg, ier);
+
+	gvt_dbg_irq("IRQ: old vIER(%x), pIER(%x)",
+		 __vreg(vgt, reg), gvt_mmio_read(pdev, reg));
+
+	/* figure out newly enabled/disable bits */
+	changed = __vreg(vgt, reg) ^ ier;
+	enabled = (__vreg(vgt, reg) & changed) ^ changed;
+	disabled = enabled ^ changed;
+
+	gvt_dbg_irq("vGT_IRQ: changed (%x), enabled(%x), disabled(%x)",
+			changed, enabled, disabled);
+	__vreg(vgt, reg) = ier;
+
+	info = regbase_to_irq_info(pdev, ier_to_regbase(reg));
+	if (!info)
+		return false;
+
+	if (info->has_upstream_irq)
+		update_upstream_irq(vgt, info);
+
+	ops->check_pending_irq(vgt);
+	gvt_dbg_irq("IRQ: new vIER(%x), pIER(%x)",
+		 __vreg(vgt, reg), gvt_mmio_read(pdev, reg));
+	return true;
+}
+
+bool gvt_reg_iir_handler(struct vgt_device *vgt, unsigned int reg,
+	void *p_data, unsigned int bytes)
+{
+	struct gvt_irq_info *info = regbase_to_irq_info(vgt->pdev, iir_to_regbase(reg));
+	u32 iir = *(u32 *)p_data;
+
+	gvt_dbg_irq("IRQ: capture IIR write on reg (%x) with val (%x)",
+		reg, iir);
+
+	if (!info)
+		return false;
+
+	/* TODO: need use an atomic operation. Now it's safe due to big lock */
+	__vreg(vgt, reg) &= ~iir;
+
+	if (info->has_upstream_irq)
+		update_upstream_irq(vgt, info);
+
+	return true;
+}
+
+bool gvt_reg_isr_write(struct vgt_device *vgt, unsigned int reg,
+	void *p_data, unsigned int bytes)
+{
+	gvt_dbg_irq("IRQ: capture ISR write on reg (%x) with val (%x)." \
+		" Will be ignored!", reg, *(u32 *)p_data);
+
+	return true;
+}
+
+struct gvt_irq_map gen8_irq_map[] = {
+	{ GVT_IRQ_INFO_MASTER, 0, GVT_IRQ_INFO_GT0, 0xffff },
+	{ GVT_IRQ_INFO_MASTER, 1, GVT_IRQ_INFO_GT0, 0xffff0000 },
+	{ GVT_IRQ_INFO_MASTER, 2, GVT_IRQ_INFO_GT1, 0xffff },
+	{ GVT_IRQ_INFO_MASTER, 3, GVT_IRQ_INFO_GT1, 0xffff0000 },
+	{ GVT_IRQ_INFO_MASTER, 4, GVT_IRQ_INFO_GT2, 0xffff },
+	{ GVT_IRQ_INFO_MASTER, 6, GVT_IRQ_INFO_GT3, 0xffff },
+	{ GVT_IRQ_INFO_MASTER, 16, GVT_IRQ_INFO_DE_PIPE_A, ~0 },
+	{ GVT_IRQ_INFO_MASTER, 17, GVT_IRQ_INFO_DE_PIPE_B, ~0 },
+	{ GVT_IRQ_INFO_MASTER, 18, GVT_IRQ_INFO_DE_PIPE_C, ~0 },
+	{ GVT_IRQ_INFO_MASTER, 20, GVT_IRQ_INFO_DE_PORT, ~0 },
+	{ GVT_IRQ_INFO_MASTER, 22, GVT_IRQ_INFO_DE_MISC, ~0 },
+	{ GVT_IRQ_INFO_MASTER, 23, GVT_IRQ_INFO_PCH, ~0 },
+	{ GVT_IRQ_INFO_MASTER, 30, GVT_IRQ_INFO_PCU, ~0 },
+	{ -1, -1, ~0 },
+};
+
+static void update_upstream_irq(struct vgt_device *vgt,
+		struct gvt_irq_info *info)
+{
+	struct gvt_irq_state *state = &vgt->pdev->irq_state;
+	struct gvt_irq_map *map = state->irq_map;
+	struct gvt_irq_info *up_irq_info = NULL;
+	u32 set_bits = 0;
+	u32 clear_bits = 0;
+	int bit;
+	u32 val = __vreg(vgt, regbase_to_iir(info->reg_base))
+			& __vreg(vgt, regbase_to_ier(info->reg_base));
+
+	if (!info->has_upstream_irq)
+		return;
+
+	for (map = state->irq_map; map->up_irq_bit != -1; map++) {
+		if (info->group != map->down_irq_group)
+			continue;
+
+		if (!up_irq_info)
+			up_irq_info = state->info[map->up_irq_group];
+		else
+			ASSERT(up_irq_info == state->info[map->up_irq_group]);
+
+		bit = map->up_irq_bit;
+
+		if (val & map->down_irq_bitmask)
+			set_bits |= (1 << bit);
+		else
+			clear_bits |= (1 << bit);
+	}
+
+	ASSERT(up_irq_info);
+
+	if (up_irq_info->group == GVT_IRQ_INFO_MASTER) {
+		u32 isr = up_irq_info->reg_base;
+		__vreg(vgt, isr) &= ~clear_bits;
+		__vreg(vgt, isr) |= set_bits;
+	} else {
+		u32 iir = regbase_to_iir(up_irq_info->reg_base);
+		u32 imr = regbase_to_imr(up_irq_info->reg_base);
+		__vreg(vgt, iir) |= (set_bits & ~__vreg(vgt, imr));
+	}
+
+	if (up_irq_info->has_upstream_irq)
+		update_upstream_irq(vgt, up_irq_info);
+}
+
+static void gvt_irq_map_init(struct gvt_irq_state *state)
+{
+	struct gvt_irq_map *map;
+	struct gvt_irq_info *up_info, *down_info;
+	int up_bit;
+
+	for (map = state->irq_map; map->up_irq_bit != -1; map++) {
+		up_info = state->info[map->up_irq_group];
+		up_bit = map->up_irq_bit;
+		down_info = state->info[map->down_irq_group];
+
+		set_bit(up_bit, up_info->downstream_irq_bitmap);
+		down_info->has_upstream_irq = true;
+
+		gvt_dbg_irq("irq map [upstream] group: %d, bit: %d -> [downstream] group: %d, bitmask: 0x%x",
+			up_info->group, up_bit, down_info->group, map->down_irq_bitmask);
+	}
+}
+
+/* =======================vEvent injection===================== */
+static int gvt_inject_virtual_interrupt(struct vgt_device *vgt)
+{
+	hypervisor_inject_msi(vgt);
+
+	vgt->stat.irq_num++;
+	vgt->stat.last_injection = get_cycles();
+	return 0;
+}
+
+static void propagate_event(struct gvt_irq_state *state,
+	enum gvt_event_type event, struct vgt_device *vgt)
+{
+	int bit;
+	struct gvt_irq_info *info;
+	unsigned int reg_base;
+
+	info = gvt_get_irq_info(state, event);
+	if (!info) {
+		gvt_err("IRQ(%d): virt-inject: no irq reg info!!!",
+			vgt->vm_id);
+		return;
+	}
+
+	reg_base = info->reg_base;
+	bit = state->events[event].bit;
+
+	if (!test_bit(bit, (void*)&__vreg(vgt, regbase_to_imr(reg_base)))) {
+		gvt_dbg_irq("IRQ: set bit (%d) for (%s) for VM (%d)",
+			bit, gvt_irq_name[event], vgt->vm_id);
+		set_bit(bit, (void*)&__vreg(vgt, regbase_to_iir(reg_base)));
+	}
+}
+
+/* =======================vEvent Handlers===================== */
+static void handle_default_event_virt(struct gvt_irq_state *state,
+	enum gvt_event_type event, struct vgt_device *vgt)
+{
+	if (!gvt_irq_warn_once[vgt->id][event]) {
+		gvt_info("IRQ: VM(%d) receive event %d (%s)",
+			vgt->vm_id, event, gvt_irq_name[event]);
+		gvt_irq_warn_once[vgt->id][event] = 1;
+	}
+	propagate_event(state, event, vgt);
+	vgt->stat.events[event]++;
+}
+
+/* =====================GEN specific logic======================= */
+/* GEN8 interrupt routines. */
+
+#define DEFINE_GVT_GEN8_GVT_IRQ_INFO(regname, regbase) \
+       static struct gvt_irq_info gen8_##regname##_info = { \
+               .name = #regname"-IRQ", \
+               .reg_base = regbase, \
+               .bit_to_event = {[0 ... GVT_IRQ_BITWIDTH-1] = GVT_EVENT_RESERVED}, \
+       };
+
+DEFINE_GVT_GEN8_GVT_IRQ_INFO(gt0, _GEN8_GT_ISR(0));
+DEFINE_GVT_GEN8_GVT_IRQ_INFO(gt1, _GEN8_GT_ISR(1));
+DEFINE_GVT_GEN8_GVT_IRQ_INFO(gt2, _GEN8_GT_ISR(2));
+DEFINE_GVT_GEN8_GVT_IRQ_INFO(gt3, _GEN8_GT_ISR(3));
+DEFINE_GVT_GEN8_GVT_IRQ_INFO(de_pipe_a, _GEN8_DE_PIPE_ISR(PIPE_A));
+DEFINE_GVT_GEN8_GVT_IRQ_INFO(de_pipe_b, _GEN8_DE_PIPE_ISR(PIPE_B));
+DEFINE_GVT_GEN8_GVT_IRQ_INFO(de_pipe_c, _GEN8_DE_PIPE_ISR(PIPE_C));
+DEFINE_GVT_GEN8_GVT_IRQ_INFO(de_port, _GEN8_DE_PORT_ISR);
+DEFINE_GVT_GEN8_GVT_IRQ_INFO(de_misc, _GEN8_DE_MISC_ISR);
+DEFINE_GVT_GEN8_GVT_IRQ_INFO(pcu, _GEN8_PCU_ISR);
+DEFINE_GVT_GEN8_GVT_IRQ_INFO(master, _GEN8_MASTER_IRQ);
+
+static struct gvt_irq_info gvt_base_pch_info = {
+        .name = "PCH-IRQ",
+        .reg_base = _SDEISR,
+        .bit_to_event = {[0 ... GVT_IRQ_BITWIDTH-1] = GVT_EVENT_RESERVED},
+};
+
+static void gen8_check_pending_irq(struct vgt_device *vgt)
+{
+	struct gvt_irq_state *state = &vgt->pdev->irq_state;
+	int i;
+
+	if (!(__vreg(vgt, _GEN8_MASTER_IRQ) &
+				GEN8_MASTER_IRQ_CONTROL))
+		return;
+
+	for_each_set_bit(i, state->irq_info_bitmap, GVT_IRQ_INFO_MAX) {
+		struct gvt_irq_info *info = state->info[i];
+
+		if (!info->has_upstream_irq)
+			continue;
+
+		if ((__vreg(vgt, regbase_to_iir(info->reg_base))
+					& __vreg(vgt, regbase_to_ier(info->reg_base))))
+			update_upstream_irq(vgt, info);
+	}
+
+	if (__vreg(vgt, _GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL)
+		gvt_inject_virtual_interrupt(vgt);
+}
+
+static void gen8_init_irq(
+		struct gvt_irq_state *state)
+{
+	struct pgt_device *pdev = gvt_irq_state_to_pdev(state);
+
+#define SET_BIT_INFO(s, b, e, i)		\
+	do {					\
+		s->events[e].bit = b;		\
+		s->events[e].info = s->info[i];	\
+		s->info[i]->bit_to_event[b] = e;\
+	} while (0);
+
+#define SET_IRQ_GROUP(s, g, i) \
+	do { \
+		s->info[g] = i; \
+		(i)->group = g; \
+		set_bit(g, s->irq_info_bitmap); \
+	} while (0);
+
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_MASTER, &gen8_master_info);
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_GT0, &gen8_gt0_info);
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_GT1, &gen8_gt1_info);
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_GT2, &gen8_gt2_info);
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_GT3, &gen8_gt3_info);
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_DE_PIPE_A, &gen8_de_pipe_a_info);
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_DE_PIPE_B, &gen8_de_pipe_b_info);
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_DE_PIPE_C, &gen8_de_pipe_c_info);
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_DE_PORT, &gen8_de_port_info);
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_DE_MISC, &gen8_de_misc_info);
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_PCU, &gen8_pcu_info);
+	SET_IRQ_GROUP(state, GVT_IRQ_INFO_PCH, &gvt_base_pch_info);
+
+	/* GEN8 level 2 interrupts. */
+
+	/* GEN8 interrupt GT0 events */
+	SET_BIT_INFO(state, 0, RCS_MI_USER_INTERRUPT, GVT_IRQ_INFO_GT0);
+	SET_BIT_INFO(state, 4, RCS_PIPE_CONTROL, GVT_IRQ_INFO_GT0);
+	SET_BIT_INFO(state, 8, RCS_AS_CONTEXT_SWITCH, GVT_IRQ_INFO_GT0);
+
+	SET_BIT_INFO(state, 16, BCS_MI_USER_INTERRUPT, GVT_IRQ_INFO_GT0);
+	SET_BIT_INFO(state, 20, BCS_MI_FLUSH_DW, GVT_IRQ_INFO_GT0);
+	SET_BIT_INFO(state, 24, BCS_AS_CONTEXT_SWITCH, GVT_IRQ_INFO_GT0);
+
+	/* GEN8 interrupt GT1 events */
+	SET_BIT_INFO(state, 0, VCS_MI_USER_INTERRUPT, GVT_IRQ_INFO_GT1);
+	SET_BIT_INFO(state, 4, VCS_MI_FLUSH_DW, GVT_IRQ_INFO_GT1);
+	SET_BIT_INFO(state, 8, VCS_AS_CONTEXT_SWITCH, GVT_IRQ_INFO_GT1);
+
+	if (IS_BDW_GT3(pdev->dev_priv)) {
+		SET_BIT_INFO(state, 16, VCS2_MI_USER_INTERRUPT, GVT_IRQ_INFO_GT1);
+		SET_BIT_INFO(state, 20, VCS2_MI_FLUSH_DW, GVT_IRQ_INFO_GT1);
+		SET_BIT_INFO(state, 24, VCS2_AS_CONTEXT_SWITCH, GVT_IRQ_INFO_GT1);
+	}
+
+	/* GEN8 interrupt GT3 events */
+	SET_BIT_INFO(state, 0, VECS_MI_USER_INTERRUPT, GVT_IRQ_INFO_GT3);
+	SET_BIT_INFO(state, 4, VECS_MI_FLUSH_DW, GVT_IRQ_INFO_GT3);
+	SET_BIT_INFO(state, 8, VECS_AS_CONTEXT_SWITCH, GVT_IRQ_INFO_GT3);
+
+	SET_BIT_INFO(state, 0, PIPE_A_VBLANK, GVT_IRQ_INFO_DE_PIPE_A);
+	SET_BIT_INFO(state, 4, PRIMARY_A_FLIP_DONE, GVT_IRQ_INFO_DE_PIPE_A);
+	SET_BIT_INFO(state, 5, SPRITE_A_FLIP_DONE, GVT_IRQ_INFO_DE_PIPE_A);
+
+	SET_BIT_INFO(state, 0, PIPE_B_VBLANK, GVT_IRQ_INFO_DE_PIPE_B);
+	SET_BIT_INFO(state, 4, PRIMARY_B_FLIP_DONE, GVT_IRQ_INFO_DE_PIPE_B);
+	SET_BIT_INFO(state, 5, SPRITE_B_FLIP_DONE, GVT_IRQ_INFO_DE_PIPE_B);
+
+	SET_BIT_INFO(state, 0, PIPE_C_VBLANK, GVT_IRQ_INFO_DE_PIPE_C);
+	SET_BIT_INFO(state, 4, PRIMARY_C_FLIP_DONE, GVT_IRQ_INFO_DE_PIPE_C);
+	SET_BIT_INFO(state, 5, SPRITE_C_FLIP_DONE, GVT_IRQ_INFO_DE_PIPE_C);
+
+	/* GEN8 interrupt DE PORT events */
+	SET_BIT_INFO(state, 0, AUX_CHANNEL_A, GVT_IRQ_INFO_DE_PORT);
+	SET_BIT_INFO(state, 3, DP_A_HOTPLUG, GVT_IRQ_INFO_DE_PORT);
+
+	/* GEN8 interrupt DE MISC events */
+	SET_BIT_INFO(state, 0, GSE, GVT_IRQ_INFO_DE_MISC);
+
+	/* PCH events */
+	SET_BIT_INFO(state, 17, GMBUS, GVT_IRQ_INFO_PCH);
+	SET_BIT_INFO(state, 19, CRT_HOTPLUG, GVT_IRQ_INFO_PCH);
+	SET_BIT_INFO(state, 21, DP_B_HOTPLUG, GVT_IRQ_INFO_PCH);
+	SET_BIT_INFO(state, 22, DP_C_HOTPLUG, GVT_IRQ_INFO_PCH);
+	SET_BIT_INFO(state, 23, DP_D_HOTPLUG, GVT_IRQ_INFO_PCH);
+	SET_BIT_INFO(state, 25, AUX_CHENNEL_B, GVT_IRQ_INFO_PCH);
+	SET_BIT_INFO(state, 26, AUX_CHENNEL_C, GVT_IRQ_INFO_PCH);
+	SET_BIT_INFO(state, 27, AUX_CHENNEL_D, GVT_IRQ_INFO_PCH);
+
+	/* GEN8 interrupt PCU events */
+	SET_BIT_INFO(state, 24, PCU_THERMAL, GVT_IRQ_INFO_PCU);
+	SET_BIT_INFO(state, 25, PCU_PCODE2DRIVER_MAILBOX, GVT_IRQ_INFO_PCU);
+}
+
+struct gvt_irq_ops gen8_irq_ops = {
+	.init_irq = gen8_init_irq,
+	.check_pending_irq = gen8_check_pending_irq,
+};
+
+/* ======================common event logic====================== */
+
+/*
+ * Trigger a virtual event which comes from other requests like hotplug agent
+ * instead of from pirq.
+ */
+void gvt_trigger_virtual_event(struct vgt_device *vgt,
+	enum gvt_event_type event)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_irq_state *state = &pdev->irq_state;
+	gvt_event_virt_handler_t handler;
+	struct gvt_irq_ops *ops = gvt_get_irq_ops(pdev);
+
+	handler = gvt_get_event_virt_handler(state, event);
+	ASSERT(handler);
+
+	handler(state, event, vgt);
+
+	ops->check_pending_irq(vgt);
+}
+
+/* default handler will be invoked, if not explicitly specified here */
+static void gvt_init_events(
+	struct gvt_irq_state *state)
+{
+	int i;
+
+#define SET_POLICY_ALL(h, e)	\
+	((h)->events[e].policy = GVT_EVENT_FW_ALL)
+#define SET_POLICY_NONE(h, e)	\
+	((h)->events[e].policy = GVT_EVENT_FW_NONE)
+#define SET_V_HANDLER(s, e, h)	\
+	((s)->events[e].v_handler = h)
+
+	for (i = 0; i < GVT_EVENT_MAX; i++) {
+		state->events[i].info = NULL;
+		/* Default forwarding to all VMs (render and most display events) */
+		SET_POLICY_ALL(state, i);
+		state->events[i].v_handler = handle_default_event_virt;;
+	}
+}
+
+/*
+ * Do interrupt initialization for vGT driver
+ */
+bool gvt_irq_init(struct pgt_device *pdev)
+{
+	struct gvt_irq_state *state = &pdev->irq_state;
+
+	gvt_dbg_core("init irq framework");
+
+	if (IS_BROADWELL(pdev->dev_priv)) {
+		state->ops = &gen8_irq_ops;
+		state->irq_map = gen8_irq_map;
+	} else {
+		gvt_err("Unsupported device");
+		return false;
+	}
+
+	/* common event initialization */
+	gvt_init_events(state);
+
+	/* gen specific initialization */
+	state->ops->init_irq(state);
+
+	gvt_irq_map_init(state);
+
+	return true;
+}
+
+void gvt_irq_exit(struct pgt_device *pdev)
+{
+	return;
+}
+
+void gvt_inject_flip_done(struct vgt_device *vgt, int pipe)
+{
+	enum gvt_event_type event = GVT_EVENT_MAX;
+
+	if (pipe == PIPE_A) {
+		event = PRIMARY_A_FLIP_DONE;
+	} else if (pipe == PIPE_B) {
+		event = PRIMARY_B_FLIP_DONE;
+	} else if (pipe == PIPE_C) {
+		event = PRIMARY_C_FLIP_DONE;
+	}
+
+	if (event != GVT_EVENT_MAX)
+		gvt_trigger_virtual_event(vgt, event);
+}
diff --git a/drivers/gpu/drm/i915/gvt/interrupt.h b/drivers/gpu/drm/i915/gvt/interrupt.h
new file mode 100644
index 0000000..cee85b6
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/interrupt.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_INTERRUPT_H_
+#define _GVT_INTERRUPT_H_
+
+enum gvt_event_type {
+	// GT
+	RCS_MI_USER_INTERRUPT = 0,
+	RCS_DEBUG,
+	RCS_MMIO_SYNC_FLUSH,
+	RCS_CMD_STREAMER_ERR,
+	RCS_PIPE_CONTROL,
+	RCS_L3_PARITY_ERR,		/* IVB */
+	RCS_WATCHDOG_EXCEEDED,
+	RCS_PAGE_DIRECTORY_FAULT,
+	RCS_AS_CONTEXT_SWITCH,
+	RCS_MONITOR_BUFF_HALF_FULL,	/* IVB */
+
+	VCS_MI_USER_INTERRUPT,
+	VCS_MMIO_SYNC_FLUSH,
+	VCS_CMD_STREAMER_ERR,
+	VCS_MI_FLUSH_DW,
+	VCS_WATCHDOG_EXCEEDED,
+	VCS_PAGE_DIRECTORY_FAULT,
+	VCS_AS_CONTEXT_SWITCH,
+
+	VCS2_MI_USER_INTERRUPT,
+	VCS2_MI_FLUSH_DW,
+	VCS2_AS_CONTEXT_SWITCH,
+
+	BCS_MI_USER_INTERRUPT,
+	BCS_MMIO_SYNC_FLUSH,
+	BCS_CMD_STREAMER_ERR,
+	BCS_MI_FLUSH_DW,
+	BCS_PAGE_DIRECTORY_FAULT,
+	BCS_AS_CONTEXT_SWITCH,
+
+	VECS_MI_USER_INTERRUPT,
+	VECS_MI_FLUSH_DW,
+	VECS_AS_CONTEXT_SWITCH,
+
+	// DISPLAY
+	PIPE_A_FIFO_UNDERRUN,	/* This is an active high level for the duration of the Pipe A FIFO underrun */
+	PIPE_B_FIFO_UNDERRUN,	/* This is an active high level for the duration of the Pipe B FIFO underrun */
+	PIPE_A_CRC_ERR,	/* This is an active high pulse on the Pipe A CRC error */
+	PIPE_B_CRC_ERR,	/* This is an active high pulse on the Pipe B CRC error */
+	PIPE_A_CRC_DONE,	/* This is an active high pulse on the Pipe A CRC done */
+	PIPE_B_CRC_DONE,	/* This is an active high pulse on the Pipe B CRC done */
+	PIPE_A_ODD_FIELD,	/* This is an active high level for the duration of the Pipe A interlaced odd field */
+	PIPE_B_ODD_FIELD,	/* This is an active high level for the duration of the Pipe B interlaced odd field */
+	PIPE_A_EVEN_FIELD,	/* This is an active high level for the duration of the Pipe A interlaced even field */
+	PIPE_B_EVEN_FIELD,	/* This is an active high level for the duration of the Pipe B interlaced even field */
+	PIPE_A_LINE_COMPARE,	/* This is an active high level for the duration of the selected Pipe A scan lines */
+	PIPE_B_LINE_COMPARE,	/* This is an active high level for the duration of the selected Pipe B scan lines */
+	PIPE_C_LINE_COMPARE,	/* This is an active high level for the duration of the selected Pipe C scan lines */
+	PIPE_A_VBLANK,	/* This is an active high level for the duration of the Pipe A vertical blank */
+	PIPE_B_VBLANK,	/* This is an active high level for the duration of the Pipe B vertical blank */
+	PIPE_C_VBLANK,	/* This is an active high level for the duration of the Pipe C vertical blank */
+	PIPE_A_VSYNC,	/* This is an active high level for the duration of the Pipe A vertical sync */
+	PIPE_B_VSYNC,	/* This is an active high level for the duration of the Pipe B vertical sync */
+	PIPE_C_VSYNC,	/* This is an active high level for the duration of the Pipe C vertical sync */
+	PRIMARY_A_FLIP_DONE,	/* This is an active high pulse when a primary plane A flip is done */
+	PRIMARY_B_FLIP_DONE,	/* This is an active high pulse when a primary plane B flip is done */
+	PRIMARY_C_FLIP_DONE,	/* This is an active high pulse when a primary plane C flip is done */
+	SPRITE_A_FLIP_DONE,	/* This is an active high pulse when a sprite plane A flip is done */
+	SPRITE_B_FLIP_DONE,	/* This is an active high pulse when a sprite plane B flip is done */
+	SPRITE_C_FLIP_DONE,	/* This is an active high pulse when a sprite plane C flip is done */
+
+	PCU_THERMAL,
+	PCU_PCODE2DRIVER_MAILBOX,
+
+	DPST_PHASE_IN,	// This is an active high pulse on the DPST phase in event
+	DPST_HISTOGRAM,	// This is an active high pulse on the AUX A done event.
+	GSE,
+	DP_A_HOTPLUG,
+	AUX_CHANNEL_A,	// This is an active high pulse on the AUX A done event.
+	PERF_COUNTER,	// This is an active high pulse when the performance counter reaches the threshold value programmed in the Performance Counter Source register
+	POISON,		// This is an active high pulse on receiving the poison message
+	GTT_FAULT,	// This is an active high level while either of the GTT Fault Status register bits are set
+	ERROR_INTERRUPT_COMBINED,
+
+	// PCH
+	FDI_RX_INTERRUPTS_TRANSCODER_A,	// This is an active high level while any of the FDI_RX_ISR bits are set for transcoder A
+	AUDIO_CP_CHANGE_TRANSCODER_A,	// This is an active high level while any of the FDI_RX_ISR bits are set for transcoder A
+	AUDIO_CP_REQUEST_TRANSCODER_A,	// This is an active high level indicating content protection is requested by audio azalia verb programming for transcoder A
+	FDI_RX_INTERRUPTS_TRANSCODER_B,
+	AUDIO_CP_CHANGE_TRANSCODER_B,
+	AUDIO_CP_REQUEST_TRANSCODER_B,
+	FDI_RX_INTERRUPTS_TRANSCODER_C,
+	AUDIO_CP_CHANGE_TRANSCODER_C,
+	AUDIO_CP_REQUEST_TRANSCODER_C,
+	ERR_AND_DBG,
+	GMBUS,
+	SDVO_B_HOTPLUG,
+	CRT_HOTPLUG,
+	DP_B_HOTPLUG,
+	DP_C_HOTPLUG,
+	DP_D_HOTPLUG,
+	AUX_CHENNEL_B,
+	AUX_CHENNEL_C,
+	AUX_CHENNEL_D,
+	AUDIO_POWER_STATE_CHANGE_B,
+	AUDIO_POWER_STATE_CHANGE_C,
+	AUDIO_POWER_STATE_CHANGE_D,
+
+	GVT_EVENT_RESERVED,
+	GVT_EVENT_MAX,
+};
+
+struct gvt_irq_state;
+struct pgt_device;
+
+typedef void (*gvt_event_phys_handler_t)(struct gvt_irq_state *hstate,
+	enum gvt_event_type event);
+typedef void (*gvt_event_virt_handler_t)(struct gvt_irq_state *hstate,
+	enum gvt_event_type event, struct vgt_device *vgt);
+
+struct gvt_irq_ops {
+	void (*init_irq) (struct gvt_irq_state *hstate);
+	void (*check_pending_irq) (struct vgt_device *vgt);
+};
+
+/* the list of physical interrupt control register groups */
+enum gvt_irq_type {
+	GVT_IRQ_INFO_GT,
+	GVT_IRQ_INFO_DPY,
+	GVT_IRQ_INFO_PCH,
+	GVT_IRQ_INFO_PM,
+
+	GVT_IRQ_INFO_MASTER,
+	GVT_IRQ_INFO_GT0,
+	GVT_IRQ_INFO_GT1,
+	GVT_IRQ_INFO_GT2,
+	GVT_IRQ_INFO_GT3,
+	GVT_IRQ_INFO_DE_PIPE_A,
+	GVT_IRQ_INFO_DE_PIPE_B,
+	GVT_IRQ_INFO_DE_PIPE_C,
+	GVT_IRQ_INFO_DE_PORT,
+	GVT_IRQ_INFO_DE_MISC,
+	GVT_IRQ_INFO_AUD,
+	GVT_IRQ_INFO_PCU,
+
+	GVT_IRQ_INFO_MAX,
+};
+
+#define GVT_IRQ_BITWIDTH	32
+
+/* device specific interrupt bit definitions */
+struct gvt_irq_info {
+	char *name;
+	int reg_base;
+	enum gvt_event_type bit_to_event[GVT_IRQ_BITWIDTH];
+	unsigned long warned;
+	int group;
+	DECLARE_BITMAP(downstream_irq_bitmap, GVT_IRQ_BITWIDTH);
+	bool has_upstream_irq;
+};
+
+#define	GVT_EVENT_FW_ALL 0	/* event forwarded to all instances */
+#define	GVT_EVENT_FW_NONE 1	/* no forward */
+
+/* per-event information */
+struct gvt_event_info {
+	/* device specific info */
+	int			bit;	/* map to register bit */
+	struct gvt_irq_info	*info;	/* register info */
+
+	/* device neutral info */
+	int			policy;	/* forwarding policy */
+	gvt_event_phys_handler_t	p_handler;	/* for p_event */
+	gvt_event_virt_handler_t	v_handler;	/* for v_event */
+};
+
+struct gvt_irq_map {
+	int up_irq_group;
+	int up_irq_bit;
+	int down_irq_group;
+	u32 down_irq_bitmask;
+};
+
+/* structure containing device specific IRQ state */
+struct gvt_irq_state {
+	struct gvt_irq_ops *ops;
+	struct gvt_irq_info	*info[GVT_IRQ_INFO_MAX];
+	DECLARE_BITMAP(irq_info_bitmap, GVT_IRQ_INFO_MAX);
+	struct gvt_event_info	events[GVT_EVENT_MAX];
+	DECLARE_BITMAP(pending_events, GVT_EVENT_MAX);
+	struct gvt_irq_map *irq_map;
+};
+
+#define gvt_get_event_virt_handler(h, e)	(h->events[e].v_handler)
+#define gvt_get_event_policy(h, e)		(h->events[e].policy)
+#define gvt_get_irq_info(h, e)			(h->events[e].info)
+#define gvt_get_irq_ops(p)			(p->irq_state.ops)
+
+/* common offset among interrupt control registers */
+#define regbase_to_isr(base)	(base)
+#define regbase_to_imr(base)	(base + 0x4)
+#define regbase_to_iir(base)	(base + 0x8)
+#define regbase_to_ier(base)	(base + 0xC)
+
+#define iir_to_regbase(iir)    (iir - 0x8)
+#define ier_to_regbase(ier)    (ier - 0xC)
+
+#define gvt_irq_state_to_pdev(state) \
+	container_of(state, struct pgt_device, irq_state)
+
+bool gvt_irq_init(struct pgt_device *pdev);
+void gvt_irq_exit(struct pgt_device *pdev);
+
+#endif /* _GVT_INTERRUPT_H_ */
diff --git a/drivers/gpu/drm/i915/gvt/perf.h b/drivers/gpu/drm/i915/gvt/perf.h
new file mode 100644
index 0000000..8f0cd15
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/perf.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_PERF_H_
+#define _GVT_PERF_H_
+
+struct gvt_statistics {
+	u64	irq_num;
+	u64	events[GVT_EVENT_MAX];
+	u64	last_injection;
+};
+
+struct pgt_statistics {
+	u64	irq_num;
+	u64	irq_delay_cycles;
+	u64	events[GVT_EVENT_MAX];
+};
+
+#endif
diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
index 2edaf7c..0e28a71 100644
--- a/drivers/gpu/drm/i915/gvt/reg.h
+++ b/drivers/gpu/drm/i915/gvt/reg.h
@@ -58,4 +58,35 @@
 #define _GEN6_GT_THREAD_STATUS_REG	0x13805c
 #define _GEN6_GT_CORE_STATUS		0x138060
 
+#define _GEN8_DE_PORT_IMR (0x44444)
+#define _GEN8_DE_PORT_IER (0x4444c)
+#define _GEN8_DE_PORT_IIR (0x44448)
+#define _GEN8_DE_PORT_ISR (0x44440)
+
+#define _GEN8_DE_MISC_IMR (0x44464)
+#define _GEN8_DE_MISC_IER (0x4446c)
+#define _GEN8_DE_MISC_IIR (0x44468)
+#define _GEN8_DE_MISC_ISR (0x44460)
+
+#define _GEN8_PCU_IMR (0x444e4)
+#define _GEN8_PCU_IER (0x444ec)
+#define _GEN8_PCU_IIR (0x444e8)
+#define _GEN8_PCU_ISR (0x444e0)
+#define _GEN8_MASTER_IRQ			(0x44200)
+
+#define _SDEIMR  (0xc4004)
+#define _SDEIER  (0xc400c)
+#define _SDEIIR  (0xc4008)
+#define _SDEISR  (0xc4000)
+
+#define _GEN8_GT_ISR(which) (0x44300 + (0x10 * (which)))
+#define _GEN8_GT_IMR(which) (0x44304 + (0x10 * (which)))
+#define _GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
+#define _GEN8_GT_IER(which) (0x4430c + (0x10 * (which)))
+
+#define _GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe)))
+#define _GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe)))
+#define _GEN8_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe)))
+#define _GEN8_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe)))
+
 #endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 15/29] drm/i915: gvt: vGPU graphics memory emulation framework
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (13 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 14/29] drm/i915: gvt: vGPU interrupt emulation framework Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 16/29] drm/i915: gvt: Generic MPT framework Zhi Wang
                   ` (14 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

The vGPU graphics memory emulation framework is responsible for graphics
memory table virtualization/shadow. Under virtualization environment,
the guest will populate the page table with guest page frame number(GFN).
The relationship between GFN and MFN(Machine frame number) is managed by
hypervisor, while GEN HW doesn't have such knowledge to translate a GFN.

To solve this kinds of gap, shadow GGTT/PPGTT page table is introdcued.

For GGTT, the GFN inside the guest GGTT page table entry will be translated
into MFN and written into physical GTT MMIO registers when guest write
virtual GTT MMIO registers.

For PPGTT, a shadow PPGTT page table will be created and write-protected
translated from guest PPGTT page table.  And the shadow page table root
pointers will be written into the shadow context after a guest workload
is shadowed.

vGPU graphics memory emulation framework consists:

- Per-GEN HW platform page table entry bits extract/de-extract routines.
- GTT MMIO register emulation handlers, which will call hypercall to do
GFN->MFN translation when guest write GTT MMIO register
- PPGTT shadow page table routines, e.g. shadow create/destroy/out-of-sync

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile   |    2 +-
 drivers/gpu/drm/i915/gvt/gtt.c      | 1912 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/gtt.h      |  305 ++++++
 drivers/gpu/drm/i915/gvt/gvt.c      |    8 +
 drivers/gpu/drm/i915/gvt/gvt.h      |  148 +++
 drivers/gpu/drm/i915/gvt/instance.c |    7 +
 drivers/gpu/drm/i915/gvt/mpt.h      |   11 +
 drivers/gpu/drm/i915/gvt/params.c   |   12 +
 drivers/gpu/drm/i915/gvt/params.h   |    3 +
 drivers/gpu/drm/i915/gvt/perf.h     |   23 +
 drivers/gpu/drm/i915/gvt/trace.h    |  172 ++++
 11 files changed, 2602 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/gtt.c
 create mode 100644 drivers/gpu/drm/i915/gvt/gtt.h

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index 78deefc..360539c 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,5 +1,5 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
-		trace_points.o interrupt.o fb_decoder.o
+		trace_points.o interrupt.o gtt.o fb_decoder.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c
new file mode 100644
index 0000000..d7e4314
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/gtt.c
@@ -0,0 +1,1912 @@
+/*
+ * GTT virtualization
+ *
+ * Copyright(c) 2011-2016 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 "gvt.h"
+#include "trace.h"
+
+/*
+ * Mappings between GTT_TYPE* enumerations.
+ * Following informations can be found according to the given type:
+ * - type of next level page table
+ * - type of entry inside this level page table
+ * - type of entry with PSE set
+ *
+ * If the given type doesn't have such a kind of information,
+ * e.g. give a l4 root entry type, then request to get its PSE type,
+ * give a PTE page table type, then request to get its next level page
+ * table type, as we know l4 root entry doesn't have a PSE bit,
+ * and a PTE page table doesn't have a next level page table type,
+ * GTT_TYPE_INVALID will be returned. This is useful when traversing a
+ * page table.
+ */
+
+struct gtt_type_table_entry {
+	gtt_type_t entry_type;
+	gtt_type_t next_pt_type;
+	gtt_type_t pse_entry_type;
+};
+
+#define GTT_TYPE_TABLE_ENTRY(type, e_type, npt_type, pse_type) \
+	[type] = { \
+		.entry_type = e_type, \
+		.next_pt_type = npt_type, \
+		.pse_entry_type = pse_type, \
+	}
+
+static struct gtt_type_table_entry gtt_type_table[] = {
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_ROOT_L4_ENTRY,
+			GTT_TYPE_PPGTT_ROOT_L4_ENTRY,
+			GTT_TYPE_PPGTT_PML4_PT,
+			GTT_TYPE_INVALID),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PML4_PT,
+			GTT_TYPE_PPGTT_PML4_ENTRY,
+			GTT_TYPE_PPGTT_PDP_PT,
+			GTT_TYPE_INVALID),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PML4_ENTRY,
+			GTT_TYPE_PPGTT_PML4_ENTRY,
+			GTT_TYPE_PPGTT_PDP_PT,
+			GTT_TYPE_INVALID),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDP_PT,
+			GTT_TYPE_PPGTT_PDP_ENTRY,
+			GTT_TYPE_PPGTT_PDE_PT,
+			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_ROOT_L3_ENTRY,
+			GTT_TYPE_PPGTT_ROOT_L3_ENTRY,
+			GTT_TYPE_PPGTT_PDE_PT,
+			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDP_ENTRY,
+			GTT_TYPE_PPGTT_PDP_ENTRY,
+			GTT_TYPE_PPGTT_PDE_PT,
+			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDE_PT,
+			GTT_TYPE_PPGTT_PDE_ENTRY,
+			GTT_TYPE_PPGTT_PTE_PT,
+			GTT_TYPE_PPGTT_PTE_2M_ENTRY),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PDE_ENTRY,
+			GTT_TYPE_PPGTT_PDE_ENTRY,
+			GTT_TYPE_PPGTT_PTE_PT,
+			GTT_TYPE_PPGTT_PTE_2M_ENTRY),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_PT,
+			GTT_TYPE_PPGTT_PTE_4K_ENTRY,
+			GTT_TYPE_INVALID,
+			GTT_TYPE_INVALID),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_4K_ENTRY,
+			GTT_TYPE_PPGTT_PTE_4K_ENTRY,
+			GTT_TYPE_INVALID,
+			GTT_TYPE_INVALID),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_2M_ENTRY,
+			GTT_TYPE_PPGTT_PDE_ENTRY,
+			GTT_TYPE_INVALID,
+			GTT_TYPE_PPGTT_PTE_2M_ENTRY),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_PPGTT_PTE_1G_ENTRY,
+			GTT_TYPE_PPGTT_PDP_ENTRY,
+			GTT_TYPE_INVALID,
+			GTT_TYPE_PPGTT_PTE_1G_ENTRY),
+	GTT_TYPE_TABLE_ENTRY(GTT_TYPE_GGTT_PTE,
+			GTT_TYPE_GGTT_PTE,
+			GTT_TYPE_INVALID,
+			GTT_TYPE_INVALID),
+};
+
+static inline gtt_type_t get_next_pt_type(gtt_type_t type) {
+	return gtt_type_table[type].next_pt_type;
+}
+
+static inline gtt_type_t get_entry_type(gtt_type_t type) {
+	return gtt_type_table[type].entry_type;
+}
+
+static inline gtt_type_t get_pse_type(gtt_type_t type) {
+	return gtt_type_table[type].pse_entry_type;
+}
+
+static inline gtt_entry_t *gtt_get_entry64(void *pt, gtt_entry_t *e,
+		unsigned long index, bool hypervisor_access,
+		struct vgt_device *vgt)
+{
+	struct gvt_device_info *info = &e->pdev->device_info;
+
+	ASSERT(info->gtt_entry_size == 8);
+
+	if (!pt)
+		e->val64 = gvt_read_gtt64(e->pdev, index);
+	else {
+		if (!hypervisor_access)
+			e->val64 = *((u64 *)pt + index);
+		else
+			hypervisor_read_va(vgt, (u64 *)pt + index, &e->val64, 8, 1);
+	}
+	return e;
+}
+
+static inline gtt_entry_t *gtt_set_entry64(void *pt, gtt_entry_t *e,
+		unsigned long index, bool hypervisor_access,
+		struct vgt_device *vgt)
+{
+	struct gvt_device_info *info = &e->pdev->device_info;
+
+	ASSERT(info->gtt_entry_size == 8);
+
+	if (!pt)
+		gvt_write_gtt64(e->pdev, index, e->val64);
+	else {
+		if (!hypervisor_access)
+			*((u64 *)pt + index) = e->val64;
+		else
+			hypervisor_write_va(vgt, (u64 *)pt + index, &e->val64, 8, 1);
+	}
+	return e;
+}
+
+static unsigned long gen8_gtt_get_pfn(gtt_entry_t *e)
+{
+	if (e->type == GTT_TYPE_PPGTT_PTE_1G_ENTRY)
+		return (e->val64 & (0x1ff << 30)) >> 12;
+	else if (e->type == GTT_TYPE_PPGTT_PTE_2M_ENTRY)
+		return (e->val64 & (0x3ffff << 21)) >> 12;
+	else
+		return (e->val64 >> 12) & 0x7ffffff;
+}
+
+static void gen8_gtt_set_pfn(gtt_entry_t *e, unsigned long pfn)
+{
+	if (e->type == GTT_TYPE_PPGTT_PTE_1G_ENTRY) {
+		e->val64 &= ~(0x1ff << 30);
+		pfn &= ((0x1ff << 30) >> 12);
+	} else if (e->type == GTT_TYPE_PPGTT_PTE_2M_ENTRY) {
+		e->val64 &= ~(0x3ffff << 21);
+		pfn &= ((0x3ffff << 21) >> 12);
+	} else {
+		e->val64 &= ~(0x7ffffff << 12);
+		pfn &= 0x7ffffff;
+	}
+
+	e->val64 |= (pfn << 12);
+}
+
+static bool gen8_gtt_test_pse(gtt_entry_t *e)
+{
+	/* Entry doesn't have PSE bit. */
+	if (get_pse_type(e->type) == GTT_TYPE_INVALID)
+		return false;
+
+	e->type = get_entry_type(e->type);
+	if (!(e->val64 & (1 << 7)))
+		return false;
+
+	e->type = get_pse_type(e->type);
+	return true;
+}
+
+static bool gen8_gtt_test_present(gtt_entry_t *e)
+{
+	/*
+	 * i915 writes PDP root pointer registers without present bit,
+	 * it also works, so we need to treat root pointer entry
+	 * specifically.
+	 */
+	if (e->type == GTT_TYPE_PPGTT_ROOT_L3_ENTRY
+			|| e->type == GTT_TYPE_PPGTT_ROOT_L4_ENTRY)
+		return (e->val64 != 0);
+	else
+		return (e->val32[0] & (1 << 0));
+}
+
+static void gtt_entry_clear_present(gtt_entry_t *e)
+{
+	e->val32[0] &= ~(1 << 0);
+}
+
+/*
+ * Per-platform GMA routines.
+ */
+static unsigned long gma_to_ggtt_pte_index(unsigned long gma)
+{
+	unsigned long x = (gma >> GTT_PAGE_SHIFT);
+	trace_gma_index(__func__, gma, x);
+	return x;
+}
+
+#define DEFINE_PPGTT_GMA_TO_INDEX(prefix, ename, exp) \
+	static unsigned long prefix##_gma_to_##ename##_index(unsigned long gma) { \
+		unsigned long x = (exp); \
+		trace_gma_index(__func__, gma, x); \
+		return x; \
+	}
+
+DEFINE_PPGTT_GMA_TO_INDEX(gen8, pte, (gma >> 12 & 0x1ff));
+DEFINE_PPGTT_GMA_TO_INDEX(gen8, pde, (gma >> 21 & 0x1ff));
+DEFINE_PPGTT_GMA_TO_INDEX(gen8, l3_pdp, (gma >> 30 & 0x3));
+DEFINE_PPGTT_GMA_TO_INDEX(gen8, l4_pdp, (gma >> 30 & 0x1ff));
+DEFINE_PPGTT_GMA_TO_INDEX(gen8, pml4, (gma >> 39 & 0x1ff));
+
+struct gvt_gtt_pte_ops gen8_gtt_pte_ops = {
+	.get_entry = gtt_get_entry64,
+	.set_entry = gtt_set_entry64,
+	.clear_present = gtt_entry_clear_present,
+	.test_present = gen8_gtt_test_present,
+	.test_pse = gen8_gtt_test_pse,
+	.get_pfn = gen8_gtt_get_pfn,
+	.set_pfn = gen8_gtt_set_pfn,
+};
+
+struct gvt_gtt_gma_ops gen8_gtt_gma_ops = {
+	.gma_to_ggtt_pte_index = gma_to_ggtt_pte_index,
+	.gma_to_pte_index = gen8_gma_to_pte_index,
+	.gma_to_pde_index = gen8_gma_to_pde_index,
+	.gma_to_l3_pdp_index = gen8_gma_to_l3_pdp_index,
+	.gma_to_l4_pdp_index = gen8_gma_to_l4_pdp_index,
+	.gma_to_pml4_index = gen8_gma_to_pml4_index,
+};
+
+static bool gtt_entry_p2m(struct vgt_device *vgt, gtt_entry_t *p, gtt_entry_t *m)
+{
+        struct gvt_gtt_pte_ops *ops = vgt->pdev->gtt.pte_ops;
+        unsigned long gfn, mfn;
+
+        *m = *p;
+
+        if (!ops->test_present(p))
+                return true;
+
+        gfn = ops->get_pfn(p);
+
+        mfn = hypervisor_g2m_pfn(vgt, gfn);
+        if (mfn == INVALID_MFN) {
+                gvt_err("fail to translate gfn: 0x%lx", gfn);
+                return false;
+        }
+
+        ops->set_pfn(m, mfn);
+
+        return true;
+}
+
+/*
+ * MM helpers.
+ */
+gtt_entry_t *gvt_mm_get_entry(struct gvt_mm *mm,
+		void *page_table, gtt_entry_t *e,
+		unsigned long index)
+{
+	struct pgt_device *pdev = mm->vgt->pdev;
+	struct gvt_gtt_pte_ops *ops = pdev->gtt.pte_ops;
+
+	e->pdev = pdev;
+	e->type = mm->page_table_entry_type;
+
+	ops->get_entry(page_table, e, index, false, NULL);
+	ops->test_pse(e);
+
+	return e;
+}
+
+gtt_entry_t *gvt_mm_set_entry(struct gvt_mm *mm,
+		void *page_table, gtt_entry_t *e,
+		unsigned long index)
+{
+	struct pgt_device *pdev = mm->vgt->pdev;
+	struct gvt_gtt_pte_ops *ops = pdev->gtt.pte_ops;
+
+	e->pdev = pdev;
+
+	return ops->set_entry(page_table, e, index, false, NULL);
+}
+
+/*
+ * PPGTT shadow page table helpers.
+ */
+static inline gtt_entry_t *ppgtt_spt_get_entry(ppgtt_spt_t *spt,
+		void *page_table, gtt_type_t type,
+		gtt_entry_t *e, unsigned long index,
+		bool guest)
+{
+	struct pgt_device *pdev = spt->vgt->pdev;
+	struct gvt_gtt_pte_ops *ops = pdev->gtt.pte_ops;
+
+	e->pdev = pdev;
+	e->type = get_entry_type(type);
+
+	ASSERT(gtt_type_is_entry(e->type));
+
+	ops->get_entry(page_table, e, index, guest, spt->vgt);
+	ops->test_pse(e);
+
+	return e;
+}
+
+static inline gtt_entry_t *ppgtt_spt_set_entry(ppgtt_spt_t *spt,
+		void *page_table, gtt_type_t type,
+		gtt_entry_t *e, unsigned long index,
+		bool guest)
+{
+	struct pgt_device *pdev = spt->vgt->pdev;
+	struct gvt_gtt_pte_ops *ops = pdev->gtt.pte_ops;
+
+	e->pdev = pdev;
+
+	ASSERT(gtt_type_is_entry(e->type));
+
+	return ops->set_entry(page_table, e, index, guest, spt->vgt);
+}
+
+#define ppgtt_get_guest_entry(spt, e, index) \
+	ppgtt_spt_get_entry(spt, spt->guest_page.vaddr, \
+		spt->guest_page_type, e, index, true)
+
+#define ppgtt_set_guest_entry(spt, e, index) \
+	ppgtt_spt_set_entry(spt, spt->guest_page.vaddr, \
+		spt->guest_page_type, e, index, true)
+
+#define ppgtt_get_shadow_entry(spt, e, index) \
+	ppgtt_spt_get_entry(spt, spt->shadow_page.vaddr, \
+		spt->shadow_page.type, e, index, false)
+
+#define ppgtt_set_shadow_entry(spt, e, index) \
+	ppgtt_spt_set_entry(spt, spt->shadow_page.vaddr, \
+		spt->shadow_page.type, e, index, false)
+
+
+bool gvt_init_guest_page(struct vgt_device *vgt, guest_page_t *guest_page,
+		unsigned long gfn, guest_page_handler_t handler, void *data)
+{
+	INIT_HLIST_NODE(&guest_page->node);
+
+	guest_page->vaddr = hypervisor_gpa_to_va(vgt, gfn << GTT_PAGE_SHIFT);
+	if (!guest_page->vaddr)
+		return false;
+
+	guest_page->writeprotection = false;
+	guest_page->gfn = gfn;
+	guest_page->handler = handler;
+	guest_page->data = data;
+	guest_page->oos_page = NULL;
+	guest_page->write_cnt = 0;
+
+	hash_add(vgt->gtt.guest_page_hash_table, &guest_page->node, guest_page->gfn);
+
+	return true;
+}
+
+static bool gvt_detach_oos_page(struct vgt_device *vgt, oos_page_t *oos_page);
+
+void gvt_clean_guest_page(struct vgt_device *vgt, guest_page_t *guest_page)
+{
+	if(!hlist_unhashed(&guest_page->node))
+		hash_del(&guest_page->node);
+
+	if (guest_page->oos_page)
+		gvt_detach_oos_page(vgt, guest_page->oos_page);
+
+	if (guest_page->writeprotection)
+		hypervisor_unset_wp_pages(vgt, guest_page);
+
+	if (guest_page == vgt->gtt.last_partial_ppgtt_access_gpt)
+		vgt->gtt.last_partial_ppgtt_access_index = -1;
+}
+
+guest_page_t *gvt_find_guest_page(struct vgt_device *vgt, unsigned long gfn)
+{
+	guest_page_t *guest_page;
+	struct gvt_statistics *stat = &vgt->stat;
+	cycles_t t0, t1;
+
+	t0 = get_cycles();
+
+	hash_for_each_possible(vgt->gtt.guest_page_hash_table, guest_page, node, gfn) {
+		if (guest_page->gfn == gfn) {
+			t1 = get_cycles();
+			stat->gpt_find_hit_cnt++;
+			stat->gpt_find_hit_cycles += t1 - t0;
+			return guest_page;
+		}
+	}
+
+	t1 = get_cycles();
+	stat->gpt_find_miss_cnt++;
+	stat->gpt_find_miss_cycles += t1 - t0;
+
+	return NULL;
+}
+
+/*
+ * Shadow page manipulation routines.
+ */
+static inline bool gvt_init_shadow_page(struct vgt_device *vgt,
+		shadow_page_t *sp, gtt_type_t type)
+{
+	sp->vaddr = page_address(sp->page);
+	sp->type = type;
+	memset(sp->vaddr, 0, PAGE_SIZE);
+
+	INIT_HLIST_NODE(&sp->node);
+	sp->mfn = hypervisor_virt_to_mfn(sp->vaddr);
+	hash_add(vgt->gtt.shadow_page_hash_table, &sp->node, sp->mfn);
+
+	return true;
+}
+
+static inline void gvt_clean_shadow_page(shadow_page_t *sp)
+{
+	if(!hlist_unhashed(&sp->node))
+		hash_del(&sp->node);
+}
+
+static inline shadow_page_t *gvt_find_shadow_page(struct vgt_device *vgt,
+		unsigned long mfn)
+{
+	shadow_page_t *shadow_page;
+	struct gvt_statistics *stat = &vgt->stat;
+	cycles_t t0, t1;
+
+	t0 = get_cycles();
+
+	hash_for_each_possible(vgt->gtt.shadow_page_hash_table, shadow_page, node, mfn) {
+		if (shadow_page->mfn == mfn) {
+			t1 = get_cycles();
+			stat->spt_find_hit_cnt++;
+			stat->spt_find_hit_cycles += t1 - t0;
+			return shadow_page;
+		}
+	}
+
+	t1 = get_cycles();
+	stat->spt_find_miss_cnt++;
+	stat->spt_find_miss_cycles += t1 - t0;
+
+	return NULL;
+}
+
+#define guest_page_to_ppgtt_spt(ptr) \
+	container_of(ptr, ppgtt_spt_t, guest_page)
+
+#define shadow_page_to_ppgtt_spt(ptr) \
+	container_of(ptr, ppgtt_spt_t, shadow_page)
+
+static void ppgtt_free_shadow_page(ppgtt_spt_t *spt)
+{
+	trace_spt_free(spt->vgt->vm_id, spt, spt->shadow_page.type);
+
+	gvt_clean_shadow_page(&spt->shadow_page);
+	gvt_clean_guest_page(spt->vgt, &spt->guest_page);
+
+	mempool_free(spt, spt->vgt->pdev->gtt.mempool);
+}
+
+static void ppgtt_free_all_shadow_page(struct vgt_device *vgt)
+{
+	struct hlist_node *n;
+	shadow_page_t *sp;
+	int i;
+
+	hash_for_each_safe(vgt->gtt.shadow_page_hash_table, i, n, sp, node)
+		ppgtt_free_shadow_page(shadow_page_to_ppgtt_spt(sp));
+
+	return;
+}
+
+static bool ppgtt_handle_guest_write_page_table_bytes(void *gp,
+		uint64_t pa, void *p_data, int bytes);
+
+static bool ppgtt_write_protection_handler(void *gp, uint64_t pa, void *p_data, int bytes)
+{
+	guest_page_t *gpt = (guest_page_t *)gp;
+	ppgtt_spt_t *spt = guest_page_to_ppgtt_spt(gpt);
+	struct vgt_device *vgt = spt->vgt;
+	struct gvt_statistics *stat = &vgt->stat;
+	cycles_t t0, t1;
+
+	if (bytes != 4 && bytes != 8)
+		return false;
+
+	if (!gpt->writeprotection)
+		return false;
+
+	t0 = get_cycles();
+
+	if (!ppgtt_handle_guest_write_page_table_bytes(gp,
+		pa, p_data, bytes))
+		return false;
+
+	t1 = get_cycles();
+	stat->ppgtt_wp_cnt++;
+	stat->ppgtt_wp_cycles += t1 - t0;
+
+	return true;
+}
+
+static ppgtt_spt_t *ppgtt_alloc_shadow_page(struct vgt_device *vgt,
+		gtt_type_t type, unsigned long gpt_gfn)
+{
+	ppgtt_spt_t *spt = NULL;
+
+	spt = mempool_alloc(vgt->pdev->gtt.mempool, GFP_ATOMIC);
+	if (!spt) {
+		gvt_err("fail to allocate ppgtt shadow page.");
+		return NULL;
+	}
+
+	spt->vgt = vgt;
+	spt->guest_page_type = type;
+	atomic_set(&spt->refcount, 1);
+
+	/*
+	 * TODO: Guest page may be different with shadow page type,
+	 *	 if we support PSE page in future.
+	 */
+	if (!gvt_init_shadow_page(vgt, &spt->shadow_page, type)) {
+		gvt_err("fail to initialize shadow_page_t for spt.");
+		goto err;
+	}
+
+	if (!gvt_init_guest_page(vgt, &spt->guest_page,
+				gpt_gfn, ppgtt_write_protection_handler, NULL)) {
+		gvt_err("fail to initialize shadow_page_t for spt.");
+		goto err;
+	}
+
+	trace_spt_alloc(vgt->vm_id, spt, type, spt->shadow_page.mfn, gpt_gfn);
+
+	return spt;
+err:
+	ppgtt_free_shadow_page(spt);
+	return NULL;
+}
+
+static ppgtt_spt_t *ppgtt_find_shadow_page(struct vgt_device *vgt, unsigned long mfn)
+{
+	shadow_page_t *sp = gvt_find_shadow_page(vgt, mfn);
+
+	if (sp)
+		return shadow_page_to_ppgtt_spt(sp);
+
+	gvt_err("VM %d fail to find ppgtt shadow page: 0x%lx.",
+			vgt->vm_id, mfn);
+
+	return NULL;
+}
+
+#define pt_entry_size_shift(spt) \
+	((spt)->vgt->pdev->device_info.gtt_entry_size_shift)
+
+#define pt_entries(spt) \
+	(PAGE_SIZE >> pt_entry_size_shift(spt))
+
+#define for_each_present_guest_entry(spt, e, i) \
+	for (i = 0; i < pt_entries(spt); i++) \
+	if (spt->vgt->pdev->gtt.pte_ops->test_present(ppgtt_get_guest_entry(spt, e, i)))
+
+#define for_each_present_shadow_entry(spt, e, i) \
+	for (i = 0; i < pt_entries(spt); i++) \
+	if (spt->vgt->pdev->gtt.pte_ops->test_present(ppgtt_get_shadow_entry(spt, e, i)))
+
+static void ppgtt_get_shadow_page(ppgtt_spt_t *spt)
+{
+	int v = atomic_read(&spt->refcount);
+
+	trace_spt_refcount(spt->vgt->vm_id, "inc", spt, v, (v + 1));
+
+	atomic_inc(&spt->refcount);
+}
+
+static bool ppgtt_invalidate_shadow_page(ppgtt_spt_t *spt);
+
+static bool ppgtt_invalidate_shadow_page_by_shadow_entry(struct vgt_device *vgt,
+		gtt_entry_t *e)
+{
+	struct gvt_gtt_pte_ops *ops = vgt->pdev->gtt.pte_ops;
+	ppgtt_spt_t *s;
+
+	if (!gtt_type_is_pt(get_next_pt_type(e->type)))
+		return false;
+
+	s = ppgtt_find_shadow_page(vgt, ops->get_pfn(e));
+	if (!s) {
+		gvt_err("VM %d fail to find shadow page: mfn: 0x%lx.",
+				vgt->vm_id, ops->get_pfn(e));
+		return false;
+	}
+
+	return ppgtt_invalidate_shadow_page(s);
+}
+
+static bool ppgtt_invalidate_shadow_page(ppgtt_spt_t *spt)
+{
+	gtt_entry_t e;
+	unsigned long index;
+	int v = atomic_read(&spt->refcount);
+
+	trace_spt_change(spt->vgt->vm_id, "die", spt,
+			spt->guest_page.gfn, spt->shadow_page.type);
+
+	trace_spt_refcount(spt->vgt->vm_id, "dec", spt, v, (v - 1));
+
+	if (atomic_dec_return(&spt->refcount) > 0)
+		return true;
+
+	if (gtt_type_is_pte_pt(spt->shadow_page.type))
+		goto release;
+
+	for_each_present_shadow_entry(spt, &e, index) {
+		if (!gtt_type_is_pt(get_next_pt_type(e.type))) {
+			gvt_err("GVT doesn't support pse bit now.");
+			return false;
+		}
+		if (!ppgtt_invalidate_shadow_page_by_shadow_entry(spt->vgt, &e))
+			goto fail;
+	}
+
+release:
+	trace_spt_change(spt->vgt->vm_id, "release", spt,
+			spt->guest_page.gfn, spt->shadow_page.type);
+	ppgtt_free_shadow_page(spt);
+	return true;
+fail:
+	gvt_err("fail: shadow page %p shadow entry 0x%llx type %d.",
+			spt, e.val64, e.type);
+	return false;
+}
+
+static bool ppgtt_populate_shadow_page(ppgtt_spt_t *spt);
+
+static ppgtt_spt_t *ppgtt_populate_shadow_page_by_guest_entry(struct vgt_device *vgt,
+		gtt_entry_t *we)
+{
+	struct gvt_gtt_pte_ops *ops = vgt->pdev->gtt.pte_ops;
+	ppgtt_spt_t *s = NULL;
+	guest_page_t *g;
+
+	if (!gtt_type_is_pt(get_next_pt_type(we->type)))
+		goto fail;
+
+	g = gvt_find_guest_page(vgt, ops->get_pfn(we));
+	if (g) {
+		s = guest_page_to_ppgtt_spt(g);
+		ppgtt_get_shadow_page(s);
+	} else {
+		gtt_type_t type = get_next_pt_type(we->type);
+		s = ppgtt_alloc_shadow_page(vgt, type, ops->get_pfn(we));
+		if (!s)
+			goto fail;
+
+		if (!hypervisor_set_wp_pages(vgt, &s->guest_page))
+			goto fail;
+
+		if (!ppgtt_populate_shadow_page(s))
+			goto fail;
+
+		trace_spt_change(vgt->vm_id, "new", s, s->guest_page.gfn, s->shadow_page.type);
+	}
+	return s;
+fail:
+	gvt_err("fail: shadow page %p guest entry 0x%llx type %d.",
+			s, we->val64, we->type);
+	return NULL;
+}
+
+static inline void ppgtt_generate_shadow_entry(gtt_entry_t *se,
+		ppgtt_spt_t *s, gtt_entry_t *ge)
+{
+	struct gvt_gtt_pte_ops *ops = s->vgt->pdev->gtt.pte_ops;
+
+	se->type = ge->type;
+	se->val64 = ge->val64;
+	se->pdev = ge->pdev;
+
+	ops->set_pfn(se, s->shadow_page.mfn);
+}
+
+static bool ppgtt_populate_shadow_page(ppgtt_spt_t *spt)
+{
+	struct vgt_device *vgt = spt->vgt;
+	ppgtt_spt_t *s;
+	gtt_entry_t se, ge;
+	unsigned long i;
+
+	trace_spt_change(spt->vgt->vm_id, "born", spt,
+			spt->guest_page.gfn, spt->shadow_page.type);
+
+	if (gtt_type_is_pte_pt(spt->shadow_page.type)) {
+		for_each_present_guest_entry(spt, &ge, i) {
+			if (!gtt_entry_p2m(vgt, &ge, &se))
+				goto fail;
+			ppgtt_set_shadow_entry(spt, &se, i);
+		}
+		return true;
+	}
+
+	for_each_present_guest_entry(spt, &ge, i) {
+		if (!gtt_type_is_pt(get_next_pt_type(ge.type))) {
+			gvt_err("GVT doesn't support pse bit now.");
+			goto fail;
+		}
+
+		s = ppgtt_populate_shadow_page_by_guest_entry(vgt, &ge);
+		if (!s)
+			goto fail;
+		ppgtt_get_shadow_entry(spt, &se, i);
+		ppgtt_generate_shadow_entry(&se, s, &ge);
+		ppgtt_set_shadow_entry(spt, &se, i);
+	}
+	return true;
+fail:
+	gvt_err("fail: shadow page %p guest entry 0x%llx type %d.",
+			spt, ge.val64, ge.type);
+	return false;
+}
+
+static bool ppgtt_handle_guest_entry_removal(guest_page_t *gpt,
+		gtt_entry_t *we, unsigned long index)
+{
+	ppgtt_spt_t *spt = guest_page_to_ppgtt_spt(gpt);
+	shadow_page_t *sp = &spt->shadow_page;
+	struct vgt_device *vgt = spt->vgt;
+	struct gvt_gtt_pte_ops *ops = vgt->pdev->gtt.pte_ops;
+	gtt_entry_t e;
+
+	trace_gpt_change(spt->vgt->vm_id, "remove", spt, sp->type, we->val64, index);
+
+	ppgtt_get_shadow_entry(spt, &e, index);
+	if (!ops->test_present(&e))
+		return true;
+
+	if (gtt_type_is_pt(get_next_pt_type(we->type))) {
+		guest_page_t *g = gvt_find_guest_page(vgt, ops->get_pfn(we));
+		if (!g) {
+			gvt_err("fail to find guest page.");
+			goto fail;
+		}
+		if (!ppgtt_invalidate_shadow_page(guest_page_to_ppgtt_spt(g)))
+			goto fail;
+	}
+	e.val64 = 0;
+	ppgtt_set_shadow_entry(spt, &e, index);
+	return true;
+fail:
+	gvt_err("fail: shadow page %p guest entry 0x%llx type %d.",
+			spt, we->val64, we->type);
+	return false;
+}
+
+static bool ppgtt_handle_guest_entry_add(guest_page_t *gpt,
+		gtt_entry_t *we, unsigned long index)
+{
+	ppgtt_spt_t *spt = guest_page_to_ppgtt_spt(gpt);
+	shadow_page_t *sp = &spt->shadow_page;
+	struct vgt_device *vgt = spt->vgt;
+	gtt_entry_t m;
+	ppgtt_spt_t *s;
+
+	trace_gpt_change(spt->vgt->vm_id, "add", spt, sp->type, we->val64, index);
+
+	if (gtt_type_is_pt(get_next_pt_type(we->type))) {
+		s = ppgtt_populate_shadow_page_by_guest_entry(vgt, we);
+		if (!s)
+			goto fail;
+		ppgtt_get_shadow_entry(spt, &m, index);
+		ppgtt_generate_shadow_entry(&m, s, we);
+		ppgtt_set_shadow_entry(spt, &m, index);
+	} else {
+		if (!gtt_entry_p2m(vgt, we, &m))
+			goto fail;
+		ppgtt_set_shadow_entry(spt, &m, index);
+	}
+
+	return true;
+
+fail:
+	gvt_err("fail: spt %p guest entry 0x%llx type %d.", spt, we->val64, we->type);
+	return false;
+}
+
+static bool vgt_sync_oos_page(struct vgt_device *vgt, oos_page_t *oos_page)
+{
+	struct gvt_device_info *info = &vgt->pdev->device_info;
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_gtt_pte_ops *ops = pdev->gtt.pte_ops;
+	ppgtt_spt_t *spt = guest_page_to_ppgtt_spt(oos_page->guest_page);
+	gtt_entry_t old, new, m;
+	int index;
+
+	trace_oos_change(vgt->vm_id, "sync", oos_page->id,
+			oos_page->guest_page, spt->guest_page_type);
+
+	old.type = new.type = get_entry_type(spt->guest_page_type);
+	old.pdev = new.pdev = pdev;
+	old.val64 = new.val64 = 0;
+
+	for (index = 0; index < (GTT_PAGE_SIZE >> info->gtt_entry_size_shift); index++) {
+		ops->get_entry(oos_page->mem, &old, index, false, NULL);
+		ops->get_entry(oos_page->guest_page->vaddr, &new, index, true, vgt);
+
+		if (old.val64 == new.val64)
+			continue;
+
+		trace_oos_sync(vgt->vm_id, oos_page->id,
+				oos_page->guest_page, spt->guest_page_type,
+				new.val64, index);
+
+		if (!gtt_entry_p2m(vgt, &new, &m))
+			return false;
+
+		ops->set_entry(oos_page->mem, &new, index, false, NULL);
+		ppgtt_set_shadow_entry(spt, &m, index);
+	}
+
+	oos_page->guest_page->write_cnt = 0;
+
+	return true;
+}
+
+static bool gvt_detach_oos_page(struct vgt_device *vgt, oos_page_t *oos_page)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	ppgtt_spt_t *spt = guest_page_to_ppgtt_spt(oos_page->guest_page);
+
+	trace_oos_change(vgt->vm_id, "detach", oos_page->id,
+			oos_page->guest_page, spt->guest_page_type);
+
+	oos_page->guest_page->write_cnt = 0;
+	oos_page->guest_page->oos_page = NULL;
+	oos_page->guest_page = NULL;
+
+	list_del_init(&oos_page->vm_list);
+	list_move_tail(&oos_page->list, &pdev->gtt.oos_page_free_list_head);
+
+	pdev->stat.oos_page_cur_avail_cnt++;
+	pdev->stat.oos_page_detach_cnt++;
+
+	return true;
+}
+
+static oos_page_t *gvt_attach_oos_page(struct vgt_device *vgt,
+		oos_page_t *oos_page, guest_page_t *gpt)
+{
+	struct pgt_device *pdev = vgt->pdev;
+
+	if (!hypervisor_read_va(vgt, gpt->vaddr, oos_page->mem, GTT_PAGE_SIZE, 1))
+		return NULL;
+
+	oos_page->guest_page = gpt;
+	gpt->oos_page = oos_page;
+
+	list_move_tail(&oos_page->list, &pdev->gtt.oos_page_use_list_head);
+
+	if (--pdev->stat.oos_page_cur_avail_cnt < pdev->stat.oos_page_min_avail_cnt)
+		pdev->stat.oos_page_min_avail_cnt = pdev->stat.oos_page_cur_avail_cnt;
+
+	trace_oos_change(vgt->vm_id, "attach", gpt->oos_page->id,
+			gpt, guest_page_to_ppgtt_spt(gpt)->guest_page_type);
+
+	pdev->stat.oos_page_attach_cnt++;
+
+	return oos_page;
+}
+
+static bool ppgtt_set_guest_page_sync(struct vgt_device *vgt, guest_page_t *gpt)
+{
+	if (!hypervisor_set_wp_pages(vgt, gpt))
+		return false;
+
+	trace_oos_change(vgt->vm_id, "set page sync", gpt->oos_page->id,
+			gpt, guest_page_to_ppgtt_spt(gpt)->guest_page_type);
+
+	list_del_init(&gpt->oos_page->vm_list);
+	return vgt_sync_oos_page(vgt, gpt->oos_page);
+}
+
+static bool ppgtt_allocate_oos_page(struct vgt_device *vgt, guest_page_t *gpt)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_gtt_info *gtt = &pdev->gtt;
+	oos_page_t *oos_page = gpt->oos_page;
+
+	/* oos_page should be NULL at this point */
+	ASSERT(!oos_page);
+
+	if (list_empty(&gtt->oos_page_free_list_head)) {
+		oos_page = container_of(gtt->oos_page_use_list_head.next, oos_page_t, list);
+		if (!ppgtt_set_guest_page_sync(vgt, oos_page->guest_page)
+			|| !gvt_detach_oos_page(vgt, oos_page))
+			return false;
+		ASSERT(!list_empty(&gtt->oos_page_free_list_head));
+		pdev->stat.oos_page_steal_cnt++;
+	} else
+		oos_page = container_of(gtt->oos_page_free_list_head.next, oos_page_t, list);
+
+	return gvt_attach_oos_page(vgt, oos_page, gpt);
+}
+
+static bool ppgtt_set_guest_page_oos(struct vgt_device *vgt, guest_page_t *gpt)
+{
+	oos_page_t *oos_page = gpt->oos_page;
+
+	ASSERT(oos_page);
+
+	trace_oos_change(vgt->vm_id, "set page out of sync", gpt->oos_page->id,
+			gpt, guest_page_to_ppgtt_spt(gpt)->guest_page_type);
+
+	list_add_tail(&oos_page->vm_list, &vgt->gtt.oos_page_list_head);
+	return hypervisor_unset_wp_pages(vgt, gpt);
+}
+
+bool ppgtt_sync_oos_pages(struct vgt_device *vgt)
+{
+	struct list_head *pos, *n;
+	oos_page_t *oos_page;
+
+	if (!gvt.spt_out_of_sync)
+		return true;
+
+	list_for_each_safe(pos, n, &vgt->gtt.oos_page_list_head) {
+		oos_page = container_of(pos, oos_page_t, vm_list);
+		if (!ppgtt_set_guest_page_sync(vgt, oos_page->guest_page))
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * The heart of PPGTT shadow page table.
+ */
+static bool ppgtt_handle_guest_write_page_table(guest_page_t *gpt, gtt_entry_t *we,
+		unsigned long index)
+{
+	ppgtt_spt_t *spt = guest_page_to_ppgtt_spt(gpt);
+	struct vgt_device *vgt = spt->vgt;
+	struct gvt_gtt_pte_ops *ops = vgt->pdev->gtt.pte_ops;
+	gtt_entry_t ge;
+
+	int old_present, new_present;
+
+	ppgtt_get_guest_entry(spt, &ge, index);
+
+	old_present = ops->test_present(&ge);
+	new_present = ops->test_present(we);
+
+	ppgtt_set_guest_entry(spt, we, index);
+
+	if (old_present && new_present) {
+		if (!ppgtt_handle_guest_entry_removal(gpt, &ge, index)
+		|| !ppgtt_handle_guest_entry_add(gpt, we, index))
+			goto fail;
+	} else if (!old_present && new_present) {
+		if (!ppgtt_handle_guest_entry_add(gpt, we, index))
+			goto fail;
+	} else if (old_present && !new_present) {
+		if (!ppgtt_handle_guest_entry_removal(gpt, &ge, index))
+			goto fail;
+	}
+	return true;
+fail:
+	gvt_err("fail: shadow page %p guest entry 0x%llx type %d.",
+			spt, we->val64, we->type);
+	return false;
+}
+
+static inline bool can_do_out_of_sync(guest_page_t *gpt)
+{
+	return gvt.spt_out_of_sync
+		&& gtt_type_is_pte_pt(guest_page_to_ppgtt_spt(gpt)->guest_page_type)
+		&& gpt->write_cnt >= 2;
+}
+
+bool ppgtt_check_partial_access(struct vgt_device *vgt)
+{
+	struct gvt_vgtt_info *gtt = &vgt->gtt;
+
+	if (gtt->last_partial_ppgtt_access_index == -1)
+		return true;
+
+	if (!gtt->warn_partial_ppgtt_access_once) {
+		gvt_warn("Incomplete PPGTT page table access sequence.");
+		gtt->warn_partial_ppgtt_access_once = true;
+	}
+
+	if (!ppgtt_handle_guest_write_page_table(
+			gtt->last_partial_ppgtt_access_gpt,
+			&gtt->last_partial_ppgtt_access_entry,
+			gtt->last_partial_ppgtt_access_index))
+		return false;
+
+	gtt->last_partial_ppgtt_access_index = -1;
+	return true;
+}
+
+static bool ppgtt_handle_guest_write_page_table_bytes(void *gp,
+		uint64_t pa, void *p_data, int bytes)
+{
+	guest_page_t *gpt = (guest_page_t *)gp;
+	ppgtt_spt_t *spt = guest_page_to_ppgtt_spt(gpt);
+	struct vgt_device *vgt = spt->vgt;
+	struct gvt_gtt_pte_ops *ops = vgt->pdev->gtt.pte_ops;
+	struct gvt_device_info *info = &vgt->pdev->device_info;
+	struct gvt_vgtt_info *gtt = &vgt->gtt;
+	gtt_entry_t we, se;
+	unsigned long index;
+
+	bool partial_access = (bytes != info->gtt_entry_size);
+	bool hi = (partial_access && (pa & (info->gtt_entry_size - 1)));
+
+	index = (pa & (PAGE_SIZE - 1)) >> info->gtt_entry_size_shift;
+
+	ppgtt_get_guest_entry(spt, &we, index);
+	memcpy(&we.val64 + (pa & (info->gtt_entry_size - 1)), p_data, bytes);
+
+	if (partial_access && !hi) {
+		trace_gpt_change(vgt->vm_id, "partial access - LOW",
+				NULL, we.type, *(u32 *)(p_data), index);
+
+		ppgtt_check_partial_access(vgt);
+
+		ppgtt_set_guest_entry(spt, &we, index);
+		ppgtt_get_shadow_entry(spt, &se, index);
+
+		if (!ops->test_present(&se))
+			return true;
+
+		if (gtt_type_is_pt(get_next_pt_type(se.type)))
+			if (!ppgtt_invalidate_shadow_page_by_shadow_entry(vgt, &se))
+				return false;
+
+		se.val64 = 0;
+		ppgtt_set_shadow_entry(spt, &se, index);
+
+		gtt->last_partial_ppgtt_access_index = index;
+		gtt->last_partial_ppgtt_access_gpt = gpt;
+		gtt->last_partial_ppgtt_access_entry = we;
+
+		return true;
+	} else
+		gtt->last_partial_ppgtt_access_index = -1;
+
+	if (hi)
+		trace_gpt_change(vgt->vm_id, "partial access - HIGH",
+				NULL, we.type, *(u32 *)(p_data), index);
+
+	ops->test_pse(&we);
+
+	gpt->write_cnt++;
+
+	if (!ppgtt_handle_guest_write_page_table(gpt, &we, index))
+		return false;
+
+	if (gvt.spt_out_of_sync) {
+		if (gpt->oos_page) {
+			/* 1. only GTT_PTE type has oos_page assocaited
+			 * 2. update oos_page according to wp guest page change
+			 */
+			ops->set_entry(gpt->oos_page->mem, &we, index, false, NULL);
+		}
+
+		if (can_do_out_of_sync(gpt)) {
+			if (!gpt->oos_page)
+				ppgtt_allocate_oos_page(vgt, gpt);
+
+			if (!ppgtt_set_guest_page_oos(vgt, gpt)) {
+				/* should not return false since we can handle it*/
+				ppgtt_set_guest_page_sync(vgt, gpt);
+			}
+		}
+
+	}
+
+	return true;
+}
+
+bool ppgtt_handle_guest_write_root_pointer(struct gvt_mm *mm,
+		gtt_entry_t *we, unsigned long index)
+{
+	struct vgt_device *vgt = mm->vgt;
+	struct gvt_gtt_pte_ops *ops = vgt->pdev->gtt.pte_ops;
+	ppgtt_spt_t *spt = NULL;
+	gtt_entry_t e;
+
+	if (mm->type != GVT_MM_PPGTT || !mm->shadowed)
+		return false;
+
+	trace_gpt_change(vgt->vm_id, __func__, NULL,
+			we->type, we->val64, index);
+
+	ppgtt_get_guest_root_entry(mm, &e, index);
+
+	if (ops->test_present(&e)) {
+		ppgtt_get_shadow_root_entry(mm, &e, index);
+
+		trace_gpt_change(vgt->vm_id, "destroy old root pointer",
+				spt, e.type, e.val64, index);
+
+		if (gtt_type_is_pt(get_next_pt_type(e.type))) {
+			if (!ppgtt_invalidate_shadow_page_by_shadow_entry(vgt, &e))
+				goto fail;
+		} else {
+			gvt_err("GVT doesn't support pse bit now.");
+			goto fail;
+		}
+		e.val64 = 0;
+		ppgtt_set_shadow_root_entry(mm, &e, index);
+	}
+
+	if (ops->test_present(we)) {
+		if (gtt_type_is_pt(get_next_pt_type(we->type))) {
+			spt = ppgtt_populate_shadow_page_by_guest_entry(vgt, we);
+			if (!spt) {
+				gvt_err("fail to populate root pointer.");
+				goto fail;
+			}
+			ppgtt_generate_shadow_entry(&e, spt, we);
+			ppgtt_set_shadow_root_entry(mm, &e, index);
+		} else {
+			gvt_err("GVT doesn't support pse bit now.");
+			goto fail;
+		}
+		trace_gpt_change(vgt->vm_id, "populate root pointer",
+				spt, e.type, e.val64, index);
+	}
+	return true;
+fail:
+	gvt_err("fail: shadow page %p guest entry 0x%llx type %d.",
+			spt, we->val64, we->type);
+	return false;
+}
+
+/*
+ * mm page table allocation policy for pre-bdw:
+ *  - for ggtt, a virtual page table will be allocated.
+ *  - for ppgtt, the virtual page table(root entry) will use a part of
+ *	virtual page table from ggtt.
+ */
+bool gen7_mm_alloc_page_table(struct gvt_mm *mm)
+{
+	struct vgt_device *vgt = mm->vgt;
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_vgtt_info *gtt = &vgt->gtt;
+	struct gvt_device_info *info = &pdev->device_info;
+	void *mem;
+
+	if (mm->type == GVT_MM_PPGTT) {
+		struct gvt_mm *ggtt_mm = gtt->ggtt_mm;
+		if (!ggtt_mm) {
+			gvt_err("ggtt mm hasn't been created.");
+			return false;
+		}
+		mm->page_table_entry_cnt = 512;
+		mm->page_table_entry_size = mm->page_table_entry_cnt *
+			info->gtt_entry_size;
+		mm->virtual_page_table = ggtt_mm->virtual_page_table +
+			(mm->pde_base_index << info->gtt_entry_size_shift);
+		/* shadow page table resides in the hw mmio entries. */
+	} else if (mm->type == GVT_MM_GGTT) {
+		mm->page_table_entry_cnt = (gm_sz(pdev) >> GTT_PAGE_SHIFT);
+		mm->page_table_entry_size = mm->page_table_entry_cnt *
+			info->gtt_entry_size;
+		mem = vzalloc(mm->page_table_entry_size);
+		if (!mem) {
+			gvt_err("fail to allocate memory.");
+			return false;
+		}
+		mm->virtual_page_table = mem;
+	}
+	return true;
+}
+
+void gen7_mm_free_page_table(struct gvt_mm *mm)
+{
+	if (mm->type == GVT_MM_GGTT) {
+		if (mm->virtual_page_table)
+			vfree(mm->virtual_page_table);
+	}
+	mm->virtual_page_table = mm->shadow_page_table = NULL;
+}
+
+/*
+ * mm page table allocation policy for bdw+
+ *  - for ggtt, only virtual page table will be allocated.
+ *  - for ppgtt, dedicated virtual/shadow page table will be allocated.
+ */
+bool gen8_mm_alloc_page_table(struct gvt_mm *mm)
+{
+	struct vgt_device *vgt = mm->vgt;
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_device_info *info = &pdev->device_info;
+	void *mem;
+
+	if (mm->type == GVT_MM_PPGTT) {
+		mm->page_table_entry_cnt = 4;
+		mm->page_table_entry_size = mm->page_table_entry_cnt *
+			info->gtt_entry_size;
+		mem = kzalloc(mm->has_shadow_page_table ?
+			mm->page_table_entry_size * 2 : mm->page_table_entry_size,
+			GFP_ATOMIC);
+		if (!mem) {
+			gvt_err("fail to allocate memory.");
+			return false;
+		}
+		mm->virtual_page_table = mem;
+		if (!mm->has_shadow_page_table)
+			return true;
+		mm->shadow_page_table = mem + mm->page_table_entry_size;
+	} else if (mm->type == GVT_MM_GGTT) {
+		mm->page_table_entry_cnt = (gm_sz(pdev) >> GTT_PAGE_SHIFT);
+		mm->page_table_entry_size = mm->page_table_entry_cnt *
+			info->gtt_entry_size;
+		mem = vzalloc(mm->page_table_entry_size);
+		if (!mem) {
+			gvt_err("fail to allocate memory.");
+			return false;
+		}
+		mm->virtual_page_table = mem;
+	}
+	return true;
+}
+
+void gen8_mm_free_page_table(struct gvt_mm *mm)
+{
+	if (mm->type == GVT_MM_PPGTT) {
+		if (mm->virtual_page_table)
+			kfree(mm->virtual_page_table);
+	} else if (mm->type == GVT_MM_GGTT) {
+		if (mm->virtual_page_table)
+			vfree(mm->virtual_page_table);
+	}
+	mm->virtual_page_table = mm->shadow_page_table = NULL;
+}
+
+void gvt_destroy_mm(struct gvt_mm *mm)
+{
+	struct vgt_device *vgt = mm->vgt;
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_gtt_info *gtt = &pdev->gtt;
+	struct gvt_gtt_pte_ops *ops = gtt->pte_ops;
+	gtt_entry_t se;
+	int i;
+
+	if (!mm->initialized)
+		goto out;
+
+	if (atomic_dec_return(&mm->refcount) > 0)
+		return;
+
+	list_del(&mm->list);
+
+	if (mm->has_shadow_page_table && mm->shadowed) {
+		for (i = 0; i < mm->page_table_entry_cnt; i++) {
+			ppgtt_get_shadow_root_entry(mm, &se, i);
+			if (!ops->test_present(&se))
+				continue;
+			ppgtt_invalidate_shadow_page_by_shadow_entry(vgt, &se);
+			se.val64 = 0;
+			ppgtt_set_shadow_root_entry(mm, &se, i);
+
+			trace_gpt_change(vgt->vm_id, "destroy root pointer",
+					NULL, se.type, se.val64, i);
+		}
+	}
+	gtt->mm_free_page_table(mm);
+out:
+	kfree(mm);
+}
+
+struct gvt_mm *gvt_create_mm(struct vgt_device *vgt,
+		gvt_mm_type_t mm_type, gtt_type_t page_table_entry_type,
+		void *virtual_page_table, int page_table_level,
+		u32 pde_base_index)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_gtt_info *gtt = &pdev->gtt;
+	struct gvt_gtt_pte_ops *ops = gtt->pte_ops;
+	struct gvt_mm *mm;
+	ppgtt_spt_t *spt;
+	gtt_entry_t ge, se;
+	int i;
+
+	mm = kzalloc(sizeof(*mm), GFP_ATOMIC);
+	if (!mm) {
+		gvt_err("fail to allocate memory for mm.");
+		goto fail;
+	}
+
+	mm->type = mm_type;
+	mm->page_table_entry_type = page_table_entry_type;
+	mm->page_table_level = page_table_level;
+	mm->pde_base_index = pde_base_index;
+
+	mm->vgt = vgt;
+	mm->has_shadow_page_table = (vgt->vm_id != 0 && mm_type == GVT_MM_PPGTT);
+
+	atomic_set(&mm->refcount, 1);
+	INIT_LIST_HEAD(&mm->list);
+	list_add_tail(&mm->list, &vgt->gtt.mm_list_head);
+
+	if (!gtt->mm_alloc_page_table(mm)) {
+		gvt_err("fail to allocate page table for mm.");
+		goto fail;
+	}
+
+	mm->initialized = true;
+
+	if (virtual_page_table)
+		memcpy(mm->virtual_page_table, virtual_page_table,
+				mm->page_table_entry_size);
+
+	if (mm->has_shadow_page_table) {
+		for (i = 0; i < mm->page_table_entry_cnt; i++) {
+			ppgtt_get_guest_root_entry(mm, &ge, i);
+			if (!ops->test_present(&ge))
+				continue;
+
+			trace_gpt_change(vgt->vm_id, __func__, NULL,
+					ge.type, ge.val64, i);
+
+			spt = ppgtt_populate_shadow_page_by_guest_entry(vgt, &ge);
+			if (!spt) {
+				gvt_err("fail to populate guest root pointer.");
+				goto fail;
+			}
+			ppgtt_generate_shadow_entry(&se, spt, &ge);
+			ppgtt_set_shadow_root_entry(mm, &se, i);
+
+			trace_gpt_change(vgt->vm_id, "populate root pointer",
+					NULL, se.type, se.val64, i);
+		}
+		mm->shadowed = true;
+	}
+	return mm;
+fail:
+	gvt_err("fail to create mm.");
+	if (mm)
+		gvt_destroy_mm(mm);
+	return NULL;
+}
+
+/*
+ * GMA translation APIs.
+ */
+static inline bool ppgtt_get_next_level_entry(struct gvt_mm *mm,
+		gtt_entry_t *e, unsigned long index, bool guest)
+{
+	struct vgt_device *vgt = mm->vgt;
+	struct gvt_gtt_pte_ops *ops = vgt->pdev->gtt.pte_ops;
+	ppgtt_spt_t *s;
+	void *pt;
+
+	if (mm->has_shadow_page_table) {
+		if (!(s = ppgtt_find_shadow_page(vgt, ops->get_pfn(e))))
+			return false;
+		if (!guest)
+			ppgtt_get_shadow_entry(s, e, index);
+		else
+			ppgtt_get_guest_entry(s, e, index);
+	} else {
+		pt = hypervisor_mfn_to_virt(ops->get_pfn(e));
+		ops->get_entry(pt, e, index, false, NULL);
+		e->type = get_entry_type(get_next_pt_type(e->type));
+	}
+	return true;
+}
+
+static inline unsigned long gvt_gma_to_gpa(struct gvt_mm *mm, unsigned long gma)
+{
+	struct vgt_device *vgt = mm->vgt;
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_gtt_pte_ops *pte_ops = pdev->gtt.pte_ops;
+	struct gvt_gtt_gma_ops *gma_ops = pdev->gtt.gma_ops;
+
+	unsigned long gpa = INVALID_ADDR;
+	unsigned long gma_index[4];
+	gtt_entry_t e;
+	int i, index;
+
+	if (mm->type != GVT_MM_GGTT && mm->type != GVT_MM_PPGTT)
+		return INVALID_ADDR;
+
+	if (mm->type == GVT_MM_GGTT) {
+		if (!g_gm_is_valid(vgt, gma))
+			goto err;
+
+		ggtt_get_guest_entry(mm, &e, gma_ops->gma_to_ggtt_pte_index(gma));
+		gpa = (pte_ops->get_pfn(&e) << GTT_PAGE_SHIFT) + (gma & ~GTT_PAGE_MASK);
+
+		trace_gma_translate(vgt->vm_id, "ggtt", 0, 0, gma, gpa);
+
+		return gpa;
+	}
+
+	switch (mm->page_table_level) {
+		case 4:
+			ppgtt_get_shadow_root_entry(mm, &e, 0);
+			gma_index[0] = gma_ops->gma_to_pml4_index(gma);
+			gma_index[1] = gma_ops->gma_to_l4_pdp_index(gma);
+			gma_index[2] = gma_ops->gma_to_pde_index(gma);
+			gma_index[3] = gma_ops->gma_to_pte_index(gma);
+			index = 4;
+			break;
+		case 3:
+			ppgtt_get_shadow_root_entry(mm, &e, gma_ops->gma_to_l3_pdp_index(gma));
+			gma_index[0] = gma_ops->gma_to_pde_index(gma);
+			gma_index[1] = gma_ops->gma_to_pte_index(gma);
+			index = 2;
+			break;
+		case 2:
+			ppgtt_get_shadow_root_entry(mm, &e, gma_ops->gma_to_pde_index(gma));
+			gma_index[0] = gma_ops->gma_to_pte_index(gma);
+			index = 1;
+			break;
+		default:
+			BUG();
+	}
+	/* walk into the last level shadow page table and get gpa from guest entry */
+	for (i = 0; i < index; i++)
+		if (!ppgtt_get_next_level_entry(mm, &e, gma_index[i],
+			(i == index - 1)))
+			goto err;
+
+	gpa = (pte_ops->get_pfn(&e) << GTT_PAGE_SHIFT) + (gma & ~GTT_PAGE_MASK);
+
+	trace_gma_translate(vgt->vm_id, "ppgtt", 0, mm->page_table_level, gma, gpa);
+
+	return gpa;
+err:
+	gvt_err("invalid mm type: %d, gma %lx", mm->type, gma);
+	return INVALID_ADDR;
+}
+
+void *gvt_gma_to_va(struct gvt_mm *mm, unsigned long gma)
+{
+	struct vgt_device *vgt = mm->vgt;
+	unsigned long gpa;
+
+	gpa = gvt_gma_to_gpa(mm, gma);
+	if (gpa == INVALID_ADDR) {
+		gvt_warn("invalid gpa! gma 0x%lx, mm type %d", gma, mm->type);
+		return NULL;
+	}
+
+	return hypervisor_gpa_to_va(vgt, gpa);
+}
+
+/*
+ * GTT MMIO emulation.
+ */
+bool gtt_mmio_read(struct vgt_device *vgt,
+	unsigned int off, void *p_data, unsigned int bytes)
+{
+	struct gvt_mm *ggtt_mm = vgt->gtt.ggtt_mm;
+	struct gvt_device_info *info = &vgt->pdev->device_info;
+	unsigned long index = off >> info->gtt_entry_size_shift;
+	gtt_entry_t e;
+
+	if (bytes != 4 && bytes != 8)
+		return false;
+
+	ggtt_get_guest_entry(ggtt_mm, &e, index);
+	memcpy(p_data, &e.val64 + (off & (info->gtt_entry_size - 1)), bytes);
+
+	return true;
+}
+
+bool gtt_emulate_read(struct vgt_device *vgt, unsigned int off,
+	void *p_data, unsigned int bytes)
+{
+	struct gvt_device_info *info = &vgt->pdev->device_info;
+	int ret;
+	cycles_t t0, t1;
+	struct gvt_statistics *stat = &vgt->stat;
+
+	if (bytes != 4 && bytes != 8)
+		return false;
+
+	t0 = get_cycles();
+	stat->gtt_mmio_rcnt++;
+
+	off -= info->gtt_start_offset;
+
+	ret = gtt_mmio_read(vgt, off, p_data, bytes);
+
+	t1 = get_cycles();
+	stat->gtt_mmio_rcycles += (u64) (t1 - t0);
+	return ret;
+}
+
+bool gtt_mmio_write(struct vgt_device *vgt, unsigned int off,
+	void *p_data, unsigned int bytes)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_device_info *info = &pdev->device_info;
+	struct gvt_mm *ggtt_mm = vgt->gtt.ggtt_mm;
+	unsigned long g_gtt_index = off >> info->gtt_entry_size_shift;
+	bool partial_access = (bytes != info->gtt_entry_size);
+	bool hi = (partial_access && (off & (info->gtt_entry_size - 1)));
+	unsigned long gma;
+	gtt_entry_t e, m;
+	int rc;
+
+	if (bytes != 4 && bytes != 8)
+		return false;
+
+	gma = g_gtt_index << GTT_PAGE_SHIFT;
+	/* the VM may configure the whole GM space when ballooning is used */
+	if (!g_gm_is_valid(vgt, gma)) {
+		static int count = 0;
+
+		/* print info every 32MB */
+		if (!(count % 8192))
+			gvt_dbg_mm("[vgt %d]capture ballooned write for %d times (%x)",
+				vgt->vm_id, count, off);
+
+		count++;
+		/* in this case still return true since the impact is on vgtt only */
+		return true;
+	}
+
+	ggtt_get_guest_entry(ggtt_mm, &e, g_gtt_index);
+
+	memcpy(&e.val64 + (off & (info->gtt_entry_size - 1)), p_data, bytes);
+
+	if (partial_access && !hi)
+		goto out;
+
+	rc = gtt_entry_p2m(vgt, &e, &m);
+	if (!rc) {
+		gvt_err("VM %d: failed to translate guest gtt entry", vgt->vm_id);
+		return false;
+	}
+
+	ggtt_set_shadow_entry(ggtt_mm, &m, g_gtt_index);
+out:
+	ggtt_set_guest_entry(ggtt_mm, &e, g_gtt_index);
+	return true;
+}
+
+bool gtt_emulate_write(struct vgt_device *vgt, unsigned int off,
+	void *p_data, unsigned int bytes)
+{
+	struct gvt_device_info *info = &vgt->pdev->device_info;
+	int ret;
+	cycles_t t0, t1;
+	struct gvt_statistics *stat = &vgt->stat;
+
+	if (bytes != 4 && bytes != 8)
+		return false;
+
+	t0 = get_cycles();
+	stat->gtt_mmio_wcnt++;
+
+	off -= info->gtt_start_offset;
+
+	ret = gtt_mmio_write(vgt, off, p_data, bytes);
+
+	t1 = get_cycles();
+	stat->gtt_mmio_wcycles += (u64) (t1 - t0);
+	return ret;
+}
+
+bool vgt_expand_shadow_page_mempool(struct pgt_device *pdev)
+{
+	mempool_t *mempool = pdev->gtt.mempool;
+	bool rc = true;
+	int new_min_nr;
+
+	mutex_lock(&pdev->gtt.mempool_lock);
+
+	if (mempool->curr_nr >= gvt.preallocated_shadow_pages / 3)
+		goto out;
+
+	/*
+	 * Have to do this to let the pool expand directly.
+	 */
+	new_min_nr = gvt.preallocated_shadow_pages - 1;
+	if (mempool_resize(mempool, new_min_nr)) {
+		gvt_err("fail to resize the mempool.");
+		rc = false;
+		goto out;
+	}
+
+	new_min_nr = gvt.preallocated_shadow_pages;
+	if (mempool_resize(mempool, new_min_nr)) {
+		gvt_err("fail to resize the mempool.");
+		rc = false;
+		goto out;
+	}
+
+out:
+	mutex_unlock(&pdev->gtt.mempool_lock);
+	return rc;
+}
+
+static void *mempool_alloc_spt(gfp_t gfp_mask, void *pool_data)
+{
+	ppgtt_spt_t *spt;
+
+	spt = kzalloc(sizeof(*spt), gfp_mask);
+	if (!spt)
+		return NULL;
+
+	spt->shadow_page.page = alloc_page(gfp_mask);
+	if (!spt->shadow_page.page) {
+		kfree(spt);
+		return NULL;
+	}
+	return spt;
+}
+
+static void mempool_free_spt(void *element, void *pool_data)
+{
+	ppgtt_spt_t *spt = element;
+
+	__free_page(spt->shadow_page.page);
+	kfree(spt);
+}
+
+bool gvt_init_vgtt(struct vgt_device *vgt)
+{
+	struct gvt_vgtt_info *gtt = &vgt->gtt;
+	struct gvt_mm *ggtt_mm;
+
+	hash_init(gtt->guest_page_hash_table);
+	hash_init(gtt->shadow_page_hash_table);
+
+	INIT_LIST_HEAD(&gtt->mm_list_head);
+	INIT_LIST_HEAD(&gtt->oos_page_list_head);
+
+	gtt->last_partial_ppgtt_access_index = -1;
+
+	if (!vgt_expand_shadow_page_mempool(vgt->pdev)) {
+		gvt_err("fail to expand the shadow page mempool.");
+		return false;
+	}
+
+	ggtt_mm = gvt_create_mm(vgt, GVT_MM_GGTT,
+			GTT_TYPE_GGTT_PTE, NULL, 1, 0);
+	if (!ggtt_mm) {
+		gvt_err("fail to create mm for ggtt.");
+		return false;
+	}
+
+	gtt->ggtt_mm = ggtt_mm;
+	return true;
+}
+
+void gvt_clean_vgtt(struct vgt_device *vgt)
+{
+	struct list_head *pos, *n;
+	struct gvt_mm *mm;
+
+	ppgtt_free_all_shadow_page(vgt);
+
+	list_for_each_safe(pos, n, &vgt->gtt.mm_list_head) {
+		mm = container_of(pos, struct gvt_mm, list);
+		vgt->pdev->gtt.mm_free_page_table(mm);
+		kfree(mm);
+	}
+
+	return;
+}
+
+static void gvt_clean_spt_oos(struct pgt_device *pdev)
+{
+	struct gvt_gtt_info *gtt = &pdev->gtt;
+	struct list_head *pos, *n;
+	oos_page_t *oos_page;
+
+	ASSERT(list_empty(&gtt->oos_page_use_list_head));
+
+	list_for_each_safe(pos, n, &gtt->oos_page_free_list_head) {
+		oos_page = container_of(pos, oos_page_t, list);
+		list_del(&oos_page->list);
+		kfree(oos_page);
+	}
+}
+
+static bool gvt_setup_spt_oos(struct pgt_device *pdev)
+{
+	struct gvt_gtt_info *gtt = &pdev->gtt;
+	oos_page_t *oos_page;
+	int i;
+
+	INIT_LIST_HEAD(&gtt->oos_page_free_list_head);
+	INIT_LIST_HEAD(&gtt->oos_page_use_list_head);
+
+	for (i = 0; i < gvt.preallocated_oos_pages; i++) {
+		oos_page = kzalloc(sizeof(*oos_page), GFP_KERNEL);
+		if (!oos_page) {
+			gvt_err("fail to pre-allocate oos page.");
+			goto fail;
+		}
+
+		INIT_LIST_HEAD(&oos_page->list);
+		INIT_LIST_HEAD(&oos_page->vm_list);
+		oos_page->id = i;
+		list_add_tail(&oos_page->list, &gtt->oos_page_free_list_head);
+	}
+
+	pdev->stat.oos_page_cur_avail_cnt = gvt.preallocated_oos_pages;
+	pdev->stat.oos_page_min_avail_cnt = gvt.preallocated_oos_pages;
+	pdev->stat.oos_page_steal_cnt = 0;
+	pdev->stat.oos_page_attach_cnt = 0;
+	pdev->stat.oos_page_detach_cnt = 0;
+
+	gvt_info("%d oos pages preallocated", gvt.preallocated_oos_pages);
+
+	return true;
+fail:
+	gvt_clean_spt_oos(pdev);
+	return false;
+}
+
+bool gvt_init_avail_gtt_size(struct pgt_device *pdev)
+{
+	struct gvt_device_info *info = &pdev->device_info;
+	struct drm_i915_private *dev_priv = pdev->dev_priv;
+	u16 gmch_ctrl;
+	u64 gtt_size;
+
+	pci_read_config_word(dev_priv->dev->pdev, SNB_GMCH_CTRL, &gmch_ctrl);
+
+	gmch_ctrl = (gmch_ctrl >> 6) & 3;
+	if (gmch_ctrl)
+		gmch_ctrl = 1 << gmch_ctrl;
+
+	switch (gmch_ctrl) {
+		case 2:
+		case 4:
+		case 8:
+			gtt_size = gmch_ctrl << 20;
+			break;
+		default:
+			gvt_err("invalid GTT memory size: %x", gmch_ctrl);
+			return false;
+	}
+
+	info->gtt_end_offset = info->gtt_start_offset + gtt_size;
+	pdev->total_gm_sz = gtt_size >> info->gtt_entry_size_shift << GTT_PAGE_SHIFT;
+
+	gvt_info("Available GTT size: 0x%llx availible GM size: 0x%llx",
+		gtt_size, pdev->total_gm_sz);
+
+	return true;
+}
+
+bool gvt_init_gtt(struct pgt_device *pdev)
+{
+	gvt_dbg_core("init gtt");
+
+	if (IS_BROADWELL(pdev->dev_priv)) {
+		pdev->gtt.pte_ops = &gen8_gtt_pte_ops;
+		pdev->gtt.gma_ops = &gen8_gtt_gma_ops;
+		pdev->gtt.mm_alloc_page_table = gen8_mm_alloc_page_table;
+		pdev->gtt.mm_free_page_table = gen8_mm_free_page_table;
+
+		if (gvt.preallocated_shadow_pages == -1)
+			gvt.preallocated_shadow_pages = 8192;
+		if (gvt.preallocated_oos_pages == -1)
+			gvt.preallocated_oos_pages = 4096;
+	} else {
+		gvt_err("Unsupported platform.");
+		return false;
+	}
+
+	if (gvt.spt_out_of_sync) {
+		if (!gvt_setup_spt_oos(pdev)) {
+			gvt_err("fail to initialize SPT oos.");
+			return false;
+		}
+	}
+
+	mutex_init(&pdev->gtt.mempool_lock);
+
+	pdev->gtt.mempool = mempool_create(gvt.preallocated_shadow_pages,
+		mempool_alloc_spt, mempool_free_spt, pdev);
+	if (!pdev->gtt.mempool) {
+		gvt_err("fail to create mempool.");
+		gvt_clean_spt_oos(pdev);
+		return false;
+	}
+
+	return true;
+}
+
+void gvt_clean_gtt(struct pgt_device *pdev)
+{
+	if (gvt.spt_out_of_sync)
+		gvt_clean_spt_oos(pdev);
+
+	mempool_destroy(pdev->gtt.mempool);
+}
+
+struct gvt_mm *gen8_find_ppgtt_mm(struct vgt_device *vgt,
+		int page_table_level, void *root_entry)
+{
+	struct list_head *pos;
+	struct gvt_mm *mm;
+	u64 *src, *dst;
+
+	list_for_each(pos, &vgt->gtt.mm_list_head) {
+		mm = container_of(pos, struct gvt_mm, list);
+		if (mm->type != GVT_MM_PPGTT)
+			continue;
+
+		if (mm->page_table_level != page_table_level)
+			continue;
+
+		src = root_entry;
+		dst = mm->virtual_page_table;
+
+		if (page_table_level == 3) {
+			if (src[0] == dst[0]
+					&& src[1] == dst[1]
+					&& src[2] == dst[2]
+					&& src[3] == dst[3])
+				return mm;
+		} else {
+			if (src[0] == dst[0])
+				return mm;
+		}
+	}
+
+	return NULL;
+}
+
+bool gvt_g2v_create_ppgtt_mm(struct vgt_device *vgt, int page_table_level)
+{
+	u64 *pdp = (u64 *)&__vreg64(vgt, _vgtif_reg(pdp[0].lo));
+	gtt_type_t root_entry_type = page_table_level == 4 ?
+		GTT_TYPE_PPGTT_ROOT_L4_ENTRY : GTT_TYPE_PPGTT_ROOT_L3_ENTRY;
+
+	struct gvt_mm *mm;
+
+	ASSERT(page_table_level == 4 || page_table_level == 3);
+
+	mm = gen8_find_ppgtt_mm(vgt, page_table_level, pdp);
+	if (mm) {
+		atomic_inc(&mm->refcount);
+	} else {
+		mm = gvt_create_mm(vgt, GVT_MM_PPGTT, root_entry_type,
+				pdp, page_table_level, 0);
+		if (!mm)
+			return false;
+	}
+
+	return true;
+}
+
+bool gvt_g2v_destroy_ppgtt_mm(struct vgt_device *vgt, int page_table_level)
+{
+	u64 *pdp = (u64 *)&__vreg64(vgt, _vgtif_reg(pdp[0].lo));
+	struct gvt_mm *mm;
+
+	ASSERT(page_table_level == 4 || page_table_level == 3);
+
+	mm = gen8_find_ppgtt_mm(vgt, page_table_level, pdp);
+	if (!mm) {
+		gvt_err("fail to find ppgtt instance.");
+		return false;
+	}
+
+	gvt_destroy_mm(mm);
+
+	return true;
+}
diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h
new file mode 100644
index 0000000..9fd123aa
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/gtt.h
@@ -0,0 +1,305 @@
+/*
+ * vGT gtt header
+ *
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_GTT_H_
+#define _GVT_GTT_H_
+
+#include <linux/mempool.h>
+
+struct gvt_mm;
+
+#define GVT_GTT_HASH_BITS 8
+
+#define GTT_PAGE_SHIFT		12
+#define GTT_PAGE_SIZE		(1UL << GTT_PAGE_SHIFT)
+#define GTT_PAGE_MASK		(~(GTT_PAGE_SIZE-1))
+#define GTT_PAE_MASK		((1UL <<12) - (1UL << 4)) /* bit 11:4 */
+
+#define INVALID_ADDR (~0UL)
+
+#define INVALID_MFN	(~0UL)
+
+#define gtt_type_is_entry(type) \
+	(type > GTT_TYPE_INVALID && type < GTT_TYPE_PPGTT_ENTRY \
+	 && type != GTT_TYPE_PPGTT_PTE_ENTRY \
+	 && type != GTT_TYPE_PPGTT_ROOT_ENTRY)
+
+#define gtt_type_is_pt(type) \
+	(type >= GTT_TYPE_PPGTT_PTE_PT && type < GTT_TYPE_MAX)
+
+#define gtt_type_is_pte_pt(type) \
+	(type == GTT_TYPE_PPGTT_PTE_PT)
+
+#define gtt_type_is_root_pointer(type) \
+	(gtt_type_is_entry(type) && type > GTT_TYPE_PPGTT_ROOT_ENTRY)
+
+#define gtt_init_entry(e, t, p, v) do { \
+	(e)->type = t; \
+	(e)->pdev = p; \
+	memcpy(&(e)->val64, &v, sizeof(v)); \
+}while(0)
+
+typedef enum {
+	GTT_TYPE_INVALID = -1,
+
+	GTT_TYPE_GGTT_PTE,
+
+	GTT_TYPE_PPGTT_PTE_4K_ENTRY,
+	GTT_TYPE_PPGTT_PTE_2M_ENTRY,
+	GTT_TYPE_PPGTT_PTE_1G_ENTRY,
+
+	GTT_TYPE_PPGTT_PTE_ENTRY,
+
+	GTT_TYPE_PPGTT_PDE_ENTRY,
+	GTT_TYPE_PPGTT_PDP_ENTRY,
+	GTT_TYPE_PPGTT_PML4_ENTRY,
+
+	GTT_TYPE_PPGTT_ROOT_ENTRY,
+
+	GTT_TYPE_PPGTT_ROOT_L3_ENTRY,
+	GTT_TYPE_PPGTT_ROOT_L4_ENTRY,
+
+	GTT_TYPE_PPGTT_ENTRY,
+
+	GTT_TYPE_PPGTT_PTE_PT,
+	GTT_TYPE_PPGTT_PDE_PT,
+	GTT_TYPE_PPGTT_PDP_PT,
+	GTT_TYPE_PPGTT_PML4_PT,
+
+	GTT_TYPE_MAX,
+}gtt_type_t;
+
+typedef struct {
+	union {
+		u32 val32[2];
+		u64 val64;
+	};
+	gtt_type_t type;
+	struct pgt_device *pdev;
+}gtt_entry_t;
+
+struct gvt_gtt_pte_ops {
+	gtt_entry_t *(*get_entry)(void *pt, gtt_entry_t *e, unsigned long index,
+			bool hypervisor_access, struct vgt_device *vgt);
+	gtt_entry_t *(*set_entry)(void *pt, gtt_entry_t *e, unsigned long index,
+			bool hypervisor_access, struct vgt_device *vgt);
+	bool (*test_present)(gtt_entry_t *e);
+	void (*clear_present)(gtt_entry_t *e);
+	bool (*test_pse)(gtt_entry_t *e);
+	void (*set_pfn)(gtt_entry_t *e, unsigned long pfn);
+	unsigned long (*get_pfn)(gtt_entry_t *e);
+};
+
+struct gvt_gtt_gma_ops {
+	unsigned long (*gma_to_ggtt_pte_index)(unsigned long gma);
+	unsigned long (*gma_to_pte_index)(unsigned long gma);
+	unsigned long (*gma_to_pde_index)(unsigned long gma);
+	unsigned long (*gma_to_l3_pdp_index)(unsigned long gma);
+	unsigned long (*gma_to_l4_pdp_index)(unsigned long gma);
+	unsigned long (*gma_to_pml4_index)(unsigned long gma);
+};
+
+struct gvt_gtt_info {
+	struct gvt_gtt_pte_ops *pte_ops;
+	struct gvt_gtt_gma_ops *gma_ops;
+	bool (*mm_alloc_page_table)(struct gvt_mm *mm);
+	void (*mm_free_page_table)(struct gvt_mm *mm);
+	mempool_t *mempool;
+	struct mutex mempool_lock;
+	struct list_head oos_page_use_list_head;
+	struct list_head oos_page_free_list_head;
+};
+
+typedef struct {
+	void *vaddr;
+	struct page *page;
+	gtt_type_t type;
+	struct hlist_node node;
+	unsigned long mfn;
+}shadow_page_t;
+
+typedef enum {
+	GVT_MM_GGTT = 0,
+	GVT_MM_PPGTT,
+} gvt_mm_type_t;
+
+struct gvt_mm {
+	gvt_mm_type_t type;
+	bool initialized;
+	bool shadowed;
+
+	gtt_type_t page_table_entry_type;
+	u32 page_table_entry_size;
+	u32 page_table_entry_cnt;
+	void *virtual_page_table;
+	void *shadow_page_table;
+
+	int page_table_level;
+	bool has_shadow_page_table;
+	u32 pde_base_index;
+
+	struct list_head list;
+	atomic_t refcount;
+	struct vgt_device *vgt;
+};
+
+extern struct gvt_gtt_pte_ops gen8_gtt_pte_ops;
+extern struct gvt_gtt_gma_ops gen8_gtt_gma_ops;
+
+extern gtt_entry_t *gvt_mm_get_entry(struct gvt_mm *mm,
+                void *page_table, gtt_entry_t *e,
+                unsigned long index);
+
+extern gtt_entry_t *gvt_mm_set_entry(struct gvt_mm *mm,
+                void *page_table, gtt_entry_t *e,
+                unsigned long index);
+
+#define ggtt_get_guest_entry(mm, e, index) \
+	(mm->vgt->vm_id == 0) ? \
+	gvt_mm_get_entry(mm, NULL, e, index) : \
+	gvt_mm_get_entry(mm, mm->virtual_page_table, e, index)
+
+#define ggtt_set_guest_entry(mm, e, index) \
+	gvt_mm_set_entry(mm, mm->virtual_page_table, e, index)
+
+#define ggtt_get_shadow_entry(mm, e, index) \
+	gvt_mm_get_entry(mm, mm->shadow_page_table, e, index)
+
+#define ggtt_set_shadow_entry(mm, e, index) \
+	gvt_mm_set_entry(mm, mm->shadow_page_table, e, index)
+
+#define ppgtt_get_guest_root_entry(mm, e, index) \
+	gvt_mm_get_entry(mm, mm->virtual_page_table, e, index)
+
+#define ppgtt_set_guest_root_entry(mm, e, index) \
+	gvt_mm_set_entry(mm, mm->virtual_page_table, e, index)
+
+#define ppgtt_get_shadow_root_entry(mm, e, index) \
+	gvt_mm_get_entry(mm, mm->shadow_page_table, e, index)
+
+#define ppgtt_set_shadow_root_entry(mm, e, index) \
+	gvt_mm_set_entry(mm, mm->shadow_page_table, e, index)
+
+extern struct gvt_mm *gvt_create_mm(struct vgt_device *vgt,
+		gvt_mm_type_t mm_type, gtt_type_t page_table_entry_type,
+		void *virtual_page_table, int page_table_level,
+		u32 pde_base_index);
+extern void gvt_destroy_mm(struct gvt_mm *mm);
+
+extern bool gen8_mm_alloc_page_table(struct gvt_mm *mm);
+extern void gen8_mm_free_page_table(struct gvt_mm *mm);
+
+struct guest_page;
+
+struct gvt_vgtt_info {
+	struct gvt_mm *ggtt_mm;
+	unsigned long active_ppgtt_mm_bitmap;
+	struct list_head mm_list_head;
+	DECLARE_HASHTABLE(shadow_page_hash_table, GVT_GTT_HASH_BITS);
+	DECLARE_HASHTABLE(guest_page_hash_table, GVT_GTT_HASH_BITS);
+	atomic_t n_write_protected_guest_page;
+	struct list_head oos_page_list_head;
+	int last_partial_ppgtt_access_index;
+	gtt_entry_t last_partial_ppgtt_access_entry;
+	struct guest_page *last_partial_ppgtt_access_gpt;
+	bool warn_partial_ppgtt_access_once;
+};
+
+extern bool gvt_init_vgtt(struct vgt_device *vgt);
+extern void gvt_clean_vgtt(struct vgt_device *vgt);
+
+extern bool gvt_init_gtt(struct pgt_device *pdev);
+extern void gvt_clean_gtt(struct pgt_device *pdev);
+
+extern bool gvt_init_avail_gtt_size(struct pgt_device *pdev);
+
+extern bool gvt_expand_shadow_page_mempool(struct pgt_device *pdev);
+
+extern bool gvt_g2v_create_ppgtt_mm(struct vgt_device *vgt, int page_table_level);
+extern bool gvt_g2v_destroy_ppgtt_mm(struct vgt_device *vgt, int page_table_level);
+
+extern struct gvt_mm *gen8_find_ppgtt_mm(struct vgt_device *vgt,
+                int page_table_level, void *root_entry);
+
+extern bool ppgtt_check_partial_access(struct vgt_device *vgt);
+
+typedef bool guest_page_handler_t(void *gp, uint64_t pa, void *p_data, int bytes);
+
+struct oos_page;
+
+struct guest_page {
+	struct hlist_node node;
+	int writeprotection;
+	unsigned long gfn;
+	void *vaddr;
+	guest_page_handler_t *handler;
+	void *data;
+	unsigned long write_cnt;
+	struct oos_page *oos_page;
+};
+
+typedef struct guest_page guest_page_t;
+
+struct oos_page {
+	guest_page_t *guest_page;
+	struct list_head list;
+	struct list_head vm_list;
+	int id;
+	unsigned char mem[GTT_PAGE_SIZE];
+};
+typedef struct oos_page oos_page_t;
+
+typedef struct {
+	shadow_page_t shadow_page;
+	guest_page_t guest_page;
+	gtt_type_t guest_page_type;
+	atomic_t refcount;
+	struct vgt_device *vgt;
+} ppgtt_spt_t;
+
+extern bool gvt_init_guest_page(struct vgt_device *vgt, guest_page_t *guest_page,
+		unsigned long gfn, guest_page_handler_t handler, void *data);
+
+extern void gvt_clean_guest_page(struct vgt_device *vgt, guest_page_t *guest_page);
+
+extern bool gvt_set_guest_page_writeprotection(struct vgt_device *vgt,
+		guest_page_t *guest_page);
+
+extern bool gvt_clear_guest_page_writeprotection(struct vgt_device *vgt,
+		guest_page_t *guest_page);
+
+extern guest_page_t *gvt_find_guest_page(struct vgt_device *vgt, unsigned long gfn);
+
+extern bool ppgtt_sync_oos_pages(struct vgt_device *vgt);
+
+extern void* gvt_gma_to_va(struct gvt_mm *mm, unsigned long gma);
+
+extern bool gtt_emulate_read(struct vgt_device *vgt, unsigned int off,
+	void *p_data, unsigned int bytes);
+
+extern bool gtt_emulate_write(struct vgt_device *vgt, unsigned int off,
+	void *p_data, unsigned int bytes);
+
+#endif /* _GVT_GTT_H_ */
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index a0a9667..13fecdf 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -114,6 +114,10 @@ static bool init_device_info(struct pgt_device *pdev)
 	printk("        gtt_start_offset: %x\n", info->gtt_start_offset);
 	printk("        gtt_end_offset: %x\n", info->gtt_end_offset);
 
+	if (!gvt_init_avail_gtt_size(pdev)) {
+		gvt_err("fail to get avail gtt size");
+		return false;
+	}
 	return true;
 }
 
@@ -238,6 +242,7 @@ static bool init_service_thread(struct pgt_device *pdev)
 static void clean_pgt_device(struct pgt_device *pdev)
 {
 	clean_service_thread(pdev);
+	gvt_clean_gtt(pdev);
 	gvt_irq_exit(pdev);
 	gvt_clean_mmio_emulation_state(pdev);
 	clean_initial_mmio_state(pdev);
@@ -262,6 +267,9 @@ static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *de
 	if (!gvt_irq_init(pdev))
 		goto err;
 
+	if (!gvt_init_gtt(pdev))
+		goto err;
+
 	if (!init_service_thread(pdev))
 		goto err;
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index fad56b1..542f3e6 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -36,6 +36,7 @@
 #include "mmio.h"
 #include "interrupt.h"
 #include "perf.h"
+#include "gtt.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -114,6 +115,7 @@ struct vgt_device {
 	atomic_t active;
 	struct gvt_virtual_device_state state;
 	struct gvt_statistics stat;
+	struct gvt_vgtt_info gtt;
 };
 
 struct gvt_gm_allocator {
@@ -166,6 +168,8 @@ struct pgt_device {
 
 	struct gvt_irq_state irq_state;
 	struct pgt_statistics stat;
+
+	struct gvt_gtt_info gtt;
 };
 
 /* definitions for physical aperture/GM space */
@@ -366,6 +370,22 @@ static inline void gvt_mmio_write64(struct pgt_device *pdev,
 	I915_WRITE64(tmp, val);
 }
 
+static inline u64 gvt_read_gtt64(struct pgt_device *pdev, u32 index)
+{
+	struct gvt_device_info *info = &pdev->device_info;
+	unsigned int off = index << info->gtt_entry_size_shift;
+
+	return readq(pdev->gttmmio_va + info->gtt_start_offset + off);
+}
+
+static inline void gvt_write_gtt64(struct pgt_device *pdev, u32 index, u64 val)
+{
+	struct gvt_device_info *info = &pdev->device_info;
+	unsigned int off = index << info->gtt_entry_size_shift;
+
+	writeq(val, pdev->gttmmio_va + info->gtt_start_offset + off);
+}
+
 static inline void gvt_mmio_posting_read(struct pgt_device *pdev, u32 reg)
 {
 	struct drm_i915_private *dev_priv = pdev->dev_priv;
@@ -431,4 +451,132 @@ extern struct vgt_device *gvt_create_instance(struct pgt_device *pdev,
 		struct gvt_instance_info *info);
 extern void gvt_destroy_instance(struct vgt_device *vgt);
 
+/* check whether a guest GM address is within the CPU visible range */
+static inline bool g_gm_is_visible(struct vgt_device *vgt, u64 g_addr)
+{
+	return (g_addr >= gvt_guest_visible_gm_base(vgt)) &&
+		(g_addr <= gvt_guest_visible_gm_end(vgt));
+}
+
+/* check whether a guest GM address is out of the CPU visible range */
+static inline bool g_gm_is_hidden(struct vgt_device *vgt, u64 g_addr)
+{
+	return (g_addr >= gvt_guest_hidden_gm_base(vgt)) &&
+		(g_addr <= gvt_guest_hidden_gm_end(vgt));
+}
+
+static inline bool g_gm_is_valid(struct vgt_device *vgt, u64 g_addr)
+{
+	return g_gm_is_visible(vgt, g_addr) || g_gm_is_hidden(vgt, g_addr);
+}
+
+/* check whether a host GM address is within the CPU visible range */
+static inline bool h_gm_is_visible(struct vgt_device *vgt, u64 h_addr)
+{
+	return (h_addr >= gvt_visible_gm_base(vgt)) &&
+		(h_addr <= gvt_visible_gm_end(vgt));
+}
+
+/* check whether a host GM address is out of the CPU visible range */
+static inline bool h_gm_is_hidden(struct vgt_device *vgt, u64 h_addr)
+{
+	return (h_addr >= gvt_hidden_gm_base(vgt)) &&
+		(h_addr <= gvt_hidden_gm_end(vgt));
+}
+
+static inline bool h_gm_is_valid(struct vgt_device *vgt, u64 h_addr)
+{
+	return h_gm_is_visible(vgt, h_addr) || h_gm_is_hidden(vgt, h_addr);
+}
+
+/* for a guest GM address, return the offset within the CPU visible range */
+static inline u64 g_gm_visible_offset(struct vgt_device *vgt, uint64_t g_addr)
+{
+	return g_addr - gvt_guest_visible_gm_base(vgt);
+}
+
+/* for a guest GM address, return the offset within the hidden range */
+static inline u64 g_gm_hidden_offset(struct vgt_device *vgt, uint64_t g_addr)
+{
+	return g_addr - gvt_guest_hidden_gm_base(vgt);
+}
+
+/* for a host GM address, return the offset within the CPU visible range */
+static inline u64 h_gm_visible_offset(struct vgt_device *vgt, uint64_t h_addr)
+{
+	return h_addr - gvt_visible_gm_base(vgt);
+}
+
+/* for a host GM address, return the offset within the hidden range */
+static inline u64 h_gm_hidden_offset(struct vgt_device *vgt, uint64_t h_addr)
+{
+	return h_addr - gvt_hidden_gm_base(vgt);
+}
+
+/* validate a gm address and related range size, translate it to host gm address */
+static inline int g2h_gm_range(struct vgt_device *vgt, u64 *addr, u32 size)
+{
+	ASSERT(addr);
+
+	if ((!g_gm_is_valid(vgt, *addr)) || (size && !g_gm_is_valid(vgt, *addr + size - 1))) {
+		gvt_err("VM(%d): invalid address range: g_addr(0x%llx), size(0x%x)\n",
+			vgt->vm_id, *addr, size);
+		return -EACCES;
+	}
+
+	if (g_gm_is_visible(vgt, *addr))	/* aperture */
+		*addr = gvt_visible_gm_base(vgt) +
+			g_gm_visible_offset(vgt, *addr);
+	else	/* hidden GM space */
+		*addr = gvt_hidden_gm_base(vgt) +
+			g_gm_hidden_offset(vgt, *addr);
+	return 0;
+}
+
+/* translate a guest gm address to host gm address */
+static inline int g2h_gm(struct vgt_device *vgt, u64 *addr)
+{
+	return g2h_gm_range(vgt, addr, 4);
+}
+
+/* translate a host gm address to guest gm address */
+static inline u64 h2g_gm(struct vgt_device *vgt, uint64_t h_addr)
+{
+	u64 g_addr;
+
+	ASSERT_NUM(h_gm_is_valid(vgt, h_addr), h_addr);
+
+	if (h_gm_is_visible(vgt, h_addr))
+		g_addr = gvt_guest_visible_gm_base(vgt) +
+			h_gm_visible_offset(vgt, h_addr);
+	else
+		g_addr = gvt_guest_hidden_gm_base(vgt) +
+			h_gm_hidden_offset(vgt, h_addr);
+
+	return g_addr;
+}
+
+#define reg_is_mmio(pdev, reg)	\
+	(reg >= 0 && reg < pdev->mmio_size)
+
+#define reg_is_gtt(pdev, reg)	\
+	(reg >= pdev->device_info.gtt_start_offset \
+	&& reg < pdev->device_info.gtt_end_offset)
+
+static inline u32 g2h_gtt_index(struct vgt_device *vgt, uint32_t g_index)
+{
+	u64 addr = g_index << GTT_PAGE_SHIFT;
+
+	g2h_gm(vgt, &addr);
+
+	return (u32)(addr >> GTT_PAGE_SHIFT);
+}
+
+static inline u32 h2g_gtt_index(struct vgt_device *vgt, uint32_t h_index)
+{
+	u64 h_addr = h_index << GTT_PAGE_SHIFT;
+
+	return (u32)(h2g_gm(vgt, h_addr) >> GTT_PAGE_SHIFT);
+}
+
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/instance.c b/drivers/gpu/drm/i915/gvt/instance.c
index 07b797a..1540661 100644
--- a/drivers/gpu/drm/i915/gvt/instance.c
+++ b/drivers/gpu/drm/i915/gvt/instance.c
@@ -106,6 +106,7 @@ static void init_virtual_cfg_space_state(struct vgt_device *vgt,
 
 static void destroy_virtual_gm_state(struct vgt_device *vgt)
 {
+	gvt_clean_vgtt(vgt);
 	gvt_free_gm_and_fence_resource(vgt);
 }
 
@@ -151,11 +152,17 @@ static bool create_virtual_gm_state(struct vgt_device *vgt,
 
 	populate_pvinfo_page(vgt);
 
+	if (!gvt_init_vgtt(vgt)) {
+		gvt_err("fail to init vgtt");
+		return false;
+	}
+
 	return true;
 }
 
 static void destroy_virtual_device_state(struct vgt_device *vgt)
 {
+	gvt_clean_vgtt(vgt);
 	destroy_virtual_mmio_state(vgt);
 	destroy_virtual_gm_state(vgt);
 }
diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h
index bbe4465..99acf3d 100644
--- a/drivers/gpu/drm/i915/gvt/mpt.h
+++ b/drivers/gpu/drm/i915/gvt/mpt.h
@@ -24,6 +24,7 @@
 #ifndef _GVT_MPT_H_
 #define _GVT_MPT_H_
 
+struct guest_page;
 struct vgt_device;
 
 static inline unsigned long hypervisor_g2m_pfn(struct vgt_device *vgt,
@@ -63,6 +64,16 @@ static inline void *hypervisor_mfn_to_virt(int mfn)
 	return NULL;
 }
 
+static inline int hypervisor_set_wp_pages(struct vgt_device *vgt, struct guest_page *p)
+{
+        return 0;
+}
+
+static inline int hypervisor_unset_wp_pages(struct vgt_device *vgt, struct guest_page *p)
+{
+        return 0;
+}
+
 static inline void hypervisor_inject_msi(struct vgt_device *vgt)
 {
 	return;
diff --git a/drivers/gpu/drm/i915/gvt/params.c b/drivers/gpu/drm/i915/gvt/params.c
index fca49b0..b6eab30 100644
--- a/drivers/gpu/drm/i915/gvt/params.c
+++ b/drivers/gpu/drm/i915/gvt/params.c
@@ -30,6 +30,9 @@ struct gvt_kernel_params gvt = {
 	.dom0_low_gm_sz = 96,
 	.dom0_high_gm_sz = 384,
 	.dom0_fence_sz = 4,
+	.preallocated_shadow_pages = -1,
+	.preallocated_oos_pages = -1,
+	.spt_out_of_sync = false,
 };
 
 module_param_named(dom0_low_gm_sz, gvt.dom0_low_gm_sz, int, 0600);
@@ -40,3 +43,12 @@ MODULE_PARM_DESC(dom0_high_gm_sz, "Amount of high memory size of DOM0");
 
 module_param_named(dom0_fence_sz, gvt.dom0_fence_sz, int, 0600);
 MODULE_PARM_DESC(dom0_fence_sz, "Amount of fence size of DOM0");
+
+module_param_named(preallocated_shadow_pages, gvt.preallocated_shadow_pages, int, 0600);
+MODULE_PARM_DESC(preallocated_shadow_pages, "Amount of pre-allocated shadow pages");
+
+module_param_named(preallocated_oos_pages, gvt.preallocated_oos_pages, int, 0600);
+MODULE_PARM_DESC(preallocated_oos_pages, "Amount of pre-allocated oos pages");
+
+module_param_named(spt_out_of_sync, gvt.spt_out_of_sync, bool, 0600);
+MODULE_PARM_DESC(spt_out_of_sync, "Enable SPT out of sync");
diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
index 80255c3..4e7f568 100644
--- a/drivers/gpu/drm/i915/gvt/params.h
+++ b/drivers/gpu/drm/i915/gvt/params.h
@@ -31,6 +31,9 @@ struct gvt_kernel_params {
 	int dom0_low_gm_sz;
 	int dom0_high_gm_sz;
 	int dom0_fence_sz;
+	int preallocated_shadow_pages;
+	int preallocated_oos_pages;
+	bool spt_out_of_sync;
 };
 
 extern struct gvt_kernel_params gvt;
diff --git a/drivers/gpu/drm/i915/gvt/perf.h b/drivers/gpu/drm/i915/gvt/perf.h
index 8f0cd15..146a1cb 100644
--- a/drivers/gpu/drm/i915/gvt/perf.h
+++ b/drivers/gpu/drm/i915/gvt/perf.h
@@ -28,12 +28,35 @@ struct gvt_statistics {
 	u64	irq_num;
 	u64	events[GVT_EVENT_MAX];
 	u64	last_injection;
+	u64	gtt_mmio_rcnt;
+	u64	gtt_mmio_wcnt;
+	u64	gtt_mmio_wcycles;
+	u64	gtt_mmio_rcycles;
+	u64	wp_cnt;
+	u64	wp_cycles;
+	u64	ppgtt_wp_cnt;
+	u64	ppgtt_wp_cycles;
+	u64	spt_find_hit_cnt;
+	u64	spt_find_hit_cycles;
+	u64	spt_find_miss_cnt;
+	u64	spt_find_miss_cycles;
+	u64	gpt_find_hit_cnt;
+	u64	gpt_find_hit_cycles;
+	u64	gpt_find_miss_cnt;
+	u64	gpt_find_miss_cycles;
+
 };
 
 struct pgt_statistics {
 	u64	irq_num;
 	u64	irq_delay_cycles;
 	u64	events[GVT_EVENT_MAX];
+	u64	oos_page_cur_avail_cnt;
+	u64	oos_page_min_avail_cnt;
+	u64	oos_page_steal_cnt;
+	u64	oos_page_attach_cnt;
+	u64	oos_page_detach_cnt;
+
 };
 
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/trace.h b/drivers/gpu/drm/i915/gvt/trace.h
index c98600a..b6a9f3f 100644
--- a/drivers/gpu/drm/i915/gvt/trace.h
+++ b/drivers/gpu/drm/i915/gvt/trace.h
@@ -26,6 +26,178 @@
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM gvt
 
+TRACE_EVENT(spt_alloc,
+		TP_PROTO(int id, void *spt, int type, unsigned long mfn, unsigned long gpt_gfn),
+
+		TP_ARGS(id, spt, type, mfn, gpt_gfn),
+
+		TP_STRUCT__entry(
+			__field(int, id)
+			__field(void *, spt)
+			__field(int, type)
+			__field(unsigned long, mfn)
+			__field(unsigned long, gpt_gfn)
+			),
+
+		TP_fast_assign(
+			__entry->id = id;
+			__entry->spt = spt;
+			__entry->type = type;
+			__entry->mfn = mfn;
+			__entry->gpt_gfn = gpt_gfn;
+		),
+
+		TP_printk("VM%d [alloc] spt %p type %d mfn 0x%lx gpt_gfn 0x%lx\n",
+				__entry->id,
+				__entry->spt,
+				__entry->type,
+				__entry->mfn,
+				__entry->gpt_gfn)
+);
+
+TRACE_EVENT(spt_free,
+		TP_PROTO(int id, void *spt, int type),
+
+		TP_ARGS(id, spt, type),
+
+		TP_STRUCT__entry(
+			__field(int, id)
+			__field(void *, spt)
+			__field(int, type)
+			),
+
+		TP_fast_assign(
+			__entry->id = id;
+			__entry->spt = spt;
+			__entry->type = type;
+		),
+
+		TP_printk("VM%u [free] spt %p type %d\n",
+				__entry->id,
+				__entry->spt,
+				__entry->type)
+);
+
+#define MAX_BUF_LEN 256
+
+TRACE_EVENT(gma_index,
+		TP_PROTO(const char *prefix, unsigned long gma, unsigned long index),
+
+		TP_ARGS(prefix, gma, index),
+
+		TP_STRUCT__entry(
+			__array(char, buf, MAX_BUF_LEN)
+		),
+
+		TP_fast_assign(
+			snprintf(__entry->buf, MAX_BUF_LEN, "%s gma 0x%lx index 0x%lx\n", prefix, gma, index);
+		),
+
+		TP_printk("%s", __entry->buf)
+);
+
+TRACE_EVENT(gma_translate,
+		TP_PROTO(int id, char *type, int ring_id, int pt_level, unsigned long gma, unsigned long gpa),
+
+		TP_ARGS(id, type, ring_id, pt_level, gma, gpa),
+
+		TP_STRUCT__entry(
+			__array(char, buf, MAX_BUF_LEN)
+		),
+
+		TP_fast_assign(
+			snprintf(__entry->buf, MAX_BUF_LEN, "VM%d %s ring %d pt_level %d gma 0x%lx -> gpa 0x%lx\n",
+					id, type, ring_id, pt_level, gma, gpa);
+		),
+
+		TP_printk("%s", __entry->buf)
+);
+
+TRACE_EVENT(spt_refcount,
+		TP_PROTO(int id, char *action, void *spt, int before, int after),
+
+		TP_ARGS(id, action, spt, before, after),
+
+		TP_STRUCT__entry(
+			__array(char, buf, MAX_BUF_LEN)
+		),
+
+		TP_fast_assign(
+			snprintf(__entry->buf, MAX_BUF_LEN, "VM%d [%s] spt %p before %d -> after %d\n",
+					id, action, spt, before, after);
+		),
+
+		TP_printk("%s", __entry->buf)
+);
+
+TRACE_EVENT(spt_change,
+		TP_PROTO(int id, char *action, void *spt, unsigned long gfn, int type),
+
+		TP_ARGS(id, action, spt, gfn, type),
+
+		TP_STRUCT__entry(
+			__array(char, buf, MAX_BUF_LEN)
+		),
+
+		TP_fast_assign(
+			snprintf(__entry->buf, MAX_BUF_LEN, "VM%d [%s] spt %p gfn 0x%lx type %d\n",
+					id, action, spt, gfn, type);
+		),
+
+		TP_printk("%s", __entry->buf)
+);
+
+TRACE_EVENT(gpt_change,
+		TP_PROTO(int id, const char *tag, void *spt, int type, u64 v, unsigned long index),
+
+		TP_ARGS(id, tag, spt, type, v, index),
+
+		TP_STRUCT__entry(
+			__array(char, buf, MAX_BUF_LEN)
+		),
+
+		TP_fast_assign(
+			snprintf(__entry->buf, MAX_BUF_LEN, "VM%d [%s] spt %p type %d entry 0x%llx index 0x%lx\n",
+					id, tag, spt, type, v, index);
+		),
+
+		TP_printk("%s", __entry->buf)
+);
+
+TRACE_EVENT(oos_change,
+		TP_PROTO(int id, const char *tag, int page_id, void *gpt, int type),
+
+		TP_ARGS(id, tag, page_id, gpt, type),
+
+		TP_STRUCT__entry(
+			__array(char, buf, MAX_BUF_LEN)
+		),
+
+		TP_fast_assign(
+			snprintf(__entry->buf, MAX_BUF_LEN, "VM%d [oos %s] page id %d gpt %p type %d\n",
+					id, tag, page_id, gpt, type);
+		),
+
+		TP_printk("%s", __entry->buf)
+);
+
+TRACE_EVENT(oos_sync,
+		TP_PROTO(int id, int page_id, void *gpt, int type, u64 v, unsigned long index),
+
+		TP_ARGS(id, page_id, gpt, type, v, index),
+
+		TP_STRUCT__entry(
+			__array(char, buf, MAX_BUF_LEN)
+		),
+
+		TP_fast_assign(
+			snprintf(__entry->buf, MAX_BUF_LEN, "VM%d [oos sync] page id %d gpt %p type %d entry 0x%llx index 0x%lx\n",
+					id, page_id, gpt, type, v, index);
+		),
+
+		TP_printk("%s", __entry->buf)
+);
+
 #endif /* _GVT_TRACE_H_ */
 
 /* This part must be out of protection */
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 16/29] drm/i915: gvt: Generic MPT framework
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (14 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 15/29] drm/i915: gvt: vGPU graphics memory " Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 17/29] gvt: Xen hypervisor GVT-g MPT module Zhi Wang
                   ` (13 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

GVT-g supports both Xen/KVM hypervisors and requires a couple of hypervisor
services to work. The MPT framework is a kinds of abstraction which provides
a unique hypervisor APIs to GVT-g core logics.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/gvt.c       |   6 ++
 drivers/gpu/drm/i915/gvt/gvt.h       |  11 +-
 drivers/gpu/drm/i915/gvt/hypercall.h |  26 +++++
 drivers/gpu/drm/i915/gvt/mmio.c      | 194 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/mmio.h      |   4 +
 drivers/gpu/drm/i915/gvt/mpt.h       | 103 +++++++++++++++----
 drivers/gpu/drm/i915/gvt/perf.h      |   4 +
 7 files changed, 326 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index 13fecdf..a71873c 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -31,6 +31,11 @@ struct gvt_host gvt_host;
 extern struct gvt_kernel_dm xengt_kdm;
 extern struct gvt_kernel_dm kvmgt_kdm;
 
+static struct gvt_io_emulation_ops default_io_emulation_ops = {
+	.emulate_mmio_read = gvt_emulate_mmio_read,
+	.emulate_mmio_write = gvt_emulate_mmio_write,
+};
+
 static const char *supported_hypervisors[] = {
 	[GVT_HYPERVISOR_TYPE_XEN] = "Xen Hypervisor",
 	[GVT_HYPERVISOR_TYPE_KVM] = "KVM",
@@ -72,6 +77,7 @@ static bool gvt_init_host(void)
 	gvt_info("Running with hypervisor %s in host mode",
 			supported_hypervisors[host->hypervisor_type]);
 
+	host->emulate_ops = &default_io_emulation_ops;
 	idr_init(&host->device_idr);
 	mutex_init(&host->device_idr_lock);
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 542f3e6..eb5fd47 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -31,7 +31,6 @@
 #include "params.h"
 #include "reg.h"
 #include "hypercall.h"
-#include "mpt.h"
 #include "fb_decoder.h"
 #include "mmio.h"
 #include "interrupt.h"
@@ -52,12 +51,20 @@ enum {
 	GVT_HYPERVISOR_TYPE_KVM,
 };
 
+struct gvt_io_emulation_ops {
+	bool (*emulate_mmio_read)(struct vgt_device *, uint64_t, void *, int);
+	bool (*emulate_mmio_write)(struct vgt_device *, uint64_t, void *, int);
+	bool (*emulate_cfg_read)(struct vgt_device *, unsigned int, void *, int);
+	bool (*emulate_cfg_write)(struct vgt_device *, unsigned int, void *, int);
+};
+
 struct gvt_host {
 	bool initialized;
 	int hypervisor_type;
 	struct mutex device_idr_lock;
 	struct idr device_idr;
 	struct gvt_kernel_dm *kdm;
+	struct gvt_io_emulation_ops *emulate_ops;
 };
 
 extern struct gvt_host gvt_host;
@@ -579,4 +586,6 @@ static inline u32 h2g_gtt_index(struct vgt_device *vgt, uint32_t h_index)
 	return (u32)(h2g_gm(vgt, h_addr) >> GTT_PAGE_SHIFT);
 }
 
+#include "mpt.h"
+
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h b/drivers/gpu/drm/i915/gvt/hypercall.h
index 0a41874..d30f5a7 100644
--- a/drivers/gpu/drm/i915/gvt/hypercall.h
+++ b/drivers/gpu/drm/i915/gvt/hypercall.h
@@ -24,7 +24,33 @@
 #ifndef _GVT_HYPERCALL_H_
 #define _GVT_HYPERCALL_H_
 
+struct vgt_device;
+struct guest_page;
+
+enum map_type {
+        GVT_MAP_APERTURE,
+        GVT_MAP_OPREGION,
+};
+
 struct gvt_kernel_dm {
+        const char *name;
+        unsigned long (*g2m_pfn)(int vm_id, unsigned long g_pfn);
+        int (*pause_domain)(int vm_id);
+        int (*shutdown_domain)(int vm_id);
+        int (*map_mfn_to_gpfn)(int vm_id, unsigned long gpfn,
+                unsigned long mfn, int nr, int map, enum map_type type);
+        int (*set_trap_area)(struct vgt_device *vgt, uint64_t start, uint64_t end, bool map);
+        bool (*set_wp_pages)(struct vgt_device *vgt, struct guest_page *p);
+        bool (*unset_wp_pages)(struct vgt_device *vgt, struct guest_page *p);
+        int (*detect_host)(void);
+        int (*from_virt_to_mfn)(void *addr);
+        void *(*from_mfn_to_virt)(int mfn);
+        int (*inject_msi)(int vm_id, u32 addr, u16 data);
+        int (*hvm_init)(struct vgt_device *vgt);
+        void (*hvm_exit)(struct vgt_device *vgt);
+        void *(*gpa_to_va)(struct vgt_device *vgt, unsigned long gap);
+        bool (*read_va)(struct vgt_device *vgt, void *va, void *val, int len, int atomic);
+        bool (*write_va)(struct vgt_device *vgt, void *va, void *val, int len, int atomic);
 };
 
 #endif /* _GVT_HYPERCALL_H_ */
diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c
index 28e1393..3297d82 100644
--- a/drivers/gpu/drm/i915/gvt/mmio.c
+++ b/drivers/gpu/drm/i915/gvt/mmio.c
@@ -320,3 +320,197 @@ void gvt_init_shadow_mmio_register(struct vgt_device *vgt)
 	struct gvt_virtual_device_state *state = &vgt->state;
         memcpy (state->mmio.sreg, vgt->pdev->initial_mmio_state, vgt->pdev->mmio_size);
 }
+
+unsigned int pa_to_mmio_offset(struct vgt_device *vgt,
+               uint64_t pa)
+{
+#define PCI_BAR_ADDR_MASK (~0xFUL)  /* 4 LSB bits are not address */
+       return pa - ((*(u64*)(vgt->state.cfg.space + GVT_REG_CFG_SPACE_BAR0))
+                       & PCI_BAR_ADDR_MASK);
+}
+
+static inline bool valid_mmio_alignment(struct gvt_mmio_entry *e,
+               unsigned int offset, int bytes)
+{
+       if ((bytes >= e->align_bytes) && !(offset & (bytes - 1)))
+               return true;
+       gvt_err("invalid MMIO offset %08x len %d", offset, bytes);
+       return false;
+}
+
+bool gvt_default_mmio_read(struct vgt_device *vgt, unsigned int offset,
+               void *p_data, unsigned int bytes)
+{
+       memcpy(p_data, (char *)vgt->state.mmio.vreg + offset, bytes);
+       return true;
+}
+
+bool gvt_default_mmio_write(struct vgt_device *vgt, unsigned int offset,
+               void *p_data, unsigned int bytes)
+{
+       memcpy((char *)vgt->state.mmio.vreg + offset, p_data, bytes);
+       return true;
+}
+
+bool gvt_emulate_mmio_read(struct vgt_device *vgt, uint64_t pa, void *p_data,int bytes)
+{
+       struct pgt_device *pdev = vgt->pdev;
+       struct gvt_statistics *stat = &vgt->stat;
+       struct gvt_mmio_entry *mmio_entry;
+       unsigned int offset;
+       cycles_t t0, t1;
+       bool r;
+
+       t0 = get_cycles();
+
+       mutex_lock(&pdev->lock);
+
+       if (atomic_read(&vgt->gtt.n_write_protected_guest_page)) {
+               guest_page_t *gp;
+               gp = gvt_find_guest_page(vgt, pa >> PAGE_SHIFT);
+               if (gp) {
+                       memcpy(p_data, gp->vaddr + (pa & ~PAGE_MASK), bytes);
+                       mutex_unlock(&pdev->lock);
+                       return true;
+               }
+       }
+
+       offset = pa_to_mmio_offset(vgt, pa);
+
+       if (bytes > 8 || (offset & (bytes - 1)))
+               goto err;
+
+       if (reg_is_gtt(pdev, offset)) {
+               r = gtt_emulate_read(vgt, offset, p_data, bytes);
+               mutex_unlock(&pdev->lock);
+               return r;
+       }
+
+       if (!reg_is_mmio(pdev, offset + bytes))
+               goto err;
+
+       mmio_entry = find_mmio_entry(pdev, offset);
+       if (mmio_entry && mmio_entry->read) {
+               if (!valid_mmio_alignment(mmio_entry, offset, bytes))
+                       goto err;
+               if (!mmio_entry->read(vgt, offset, p_data, bytes))
+                       goto err;
+       } else
+               if (!gvt_default_mmio_read(vgt, offset, p_data, bytes))
+                       goto err;
+
+       if (!reg_is_tracked(pdev, offset) && vgt->warn_untrack) {
+               gvt_warn("[ vgt%d ] untracked MMIO read, offset %x len %d val 0x%x",
+                       vgt->vm_id, offset, bytes, *(u32 *)p_data);
+
+               if (offset == 0x206c) {
+                       printk("------------------------------------------\n");
+                       printk("VM(%d) likely triggers a gfx reset\n", vgt->vm_id);
+                       printk("Disable untracked MMIO warning for VM(%d)\n", vgt->vm_id);
+                       printk("------------------------------------------\n");
+                       vgt->warn_untrack = 0;
+               }
+       }
+
+       reg_set_accessed(pdev, offset);
+       mutex_unlock(&pdev->lock);
+
+       t1 = get_cycles();
+       stat->mmio_rcnt++;
+       stat->mmio_rcycles += t1 - t0;
+       return true;
+err:
+       gvt_err("[ vgt%d ] fail to emulate MMIO read, offset %08x len %d",
+                       vgt->id, offset, bytes);
+       mutex_unlock(&pdev->lock);
+       return false;
+}
+
+bool gvt_emulate_mmio_write(struct vgt_device *vgt, uint64_t pa,
+       void *p_data, int bytes)
+{
+       struct pgt_device *pdev = vgt->pdev;
+       struct gvt_mmio_entry *mmio_entry;
+       struct gvt_statistics *stat = &vgt->stat;
+       unsigned int offset;
+       u32 old_vreg = 0, old_sreg = 0;
+       cycles_t t0, t1;
+       bool r;
+
+       t0 = get_cycles();
+
+       mutex_lock(&pdev->lock);
+
+       if (atomic_read(&vgt->gtt.n_write_protected_guest_page)) {
+               guest_page_t *guest_page;
+               guest_page = gvt_find_guest_page(vgt, pa >> PAGE_SHIFT);
+               if (guest_page) {
+                       r = guest_page->handler(guest_page, pa, p_data, bytes);
+                       t1 = get_cycles();
+                       stat->wp_cycles += t1 - t0;
+                       stat->wp_cnt++;
+                       mutex_unlock(&pdev->lock);
+                       return r;
+               }
+       }
+
+       offset = pa_to_mmio_offset(vgt, pa);
+
+       /* FENCE registers / GTT entries(sometimes) are accessed in 8 bytes. */
+       if (bytes > 8 || (offset & (bytes - 1)))
+               goto err;
+
+       if (reg_is_gtt(pdev, offset)) {
+               r = gtt_emulate_write(vgt, offset, p_data, bytes);
+               mutex_unlock(&pdev->lock);
+               return r;
+       }
+
+       if (!reg_is_mmio(pdev, offset + bytes))
+               goto err;
+
+       if (reg_mode_ctl(pdev, offset)) {
+               old_vreg = __vreg(vgt, offset);
+               old_sreg = __sreg(vgt, offset);
+       }
+
+       if (!reg_is_tracked(pdev, offset) && vgt->warn_untrack) {
+               gvt_warn("[ vgt%d ] untracked MMIO write, offset %x len %d val 0x%x",
+                       vgt->vm_id, offset, bytes, *(u32 *)p_data);
+       }
+
+       mmio_entry = find_mmio_entry(pdev, offset);
+       if (mmio_entry && mmio_entry->write ) {
+               if (!valid_mmio_alignment(mmio_entry, offset, bytes))
+                       goto err;
+               if (!mmio_entry->write(vgt, offset, p_data, bytes))
+                       goto err;
+       } else
+               if (!gvt_default_mmio_write(vgt, offset, p_data, bytes))
+                       goto err;
+
+       /* higher 16bits of mode ctl regs are mask bits for change */
+       if (reg_mode_ctl(pdev, offset)) {
+               u32 mask = __vreg(vgt, offset) >> 16;
+               /*
+                * share the global mask among VMs, since having one VM touch a bit
+                * not changed by another VM should be still saved/restored later
+                */
+               reg_aux_mode_mask(pdev, offset) |= mask << 16;
+               __vreg(vgt, offset) = (old_vreg & ~mask) | (__vreg(vgt, offset) & mask);
+               __sreg(vgt, offset) = (old_sreg & ~mask) | (__sreg(vgt, offset) & mask);
+       }
+
+       reg_set_accessed(pdev, offset);
+       mutex_unlock(&pdev->lock);
+
+       t1 = get_cycles();
+       stat->mmio_wcycles += t1 - t0;
+       stat->mmio_wcnt++;
+       return true;
+err:
+       gvt_err("[ vgt%d ] fail to emulate MMIO write, offset %08x len %d",
+                       vgt->id, offset, bytes);
+       mutex_unlock(&pdev->lock);
+       return false;
+}
diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h
index caca60f..4301655 100644
--- a/drivers/gpu/drm/i915/gvt/mmio.h
+++ b/drivers/gpu/drm/i915/gvt/mmio.h
@@ -84,4 +84,8 @@ struct gvt_reg_info {
 extern struct gvt_reg_info gvt_general_reg_info[];
 extern struct gvt_reg_info gvt_broadwell_reg_info[];
 extern int gvt_get_reg_num(int type);
+
+bool gvt_emulate_mmio_read(struct vgt_device *vgt, uint64_t pa, void *p_data,int bytes);
+bool gvt_emulate_mmio_write(struct vgt_device *vgt, uint64_t pa, void *p_data,int bytes);
+
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h
index 99acf3d..f837dd1 100644
--- a/drivers/gpu/drm/i915/gvt/mpt.h
+++ b/drivers/gpu/drm/i915/gvt/mpt.h
@@ -24,85 +24,146 @@
 #ifndef _GVT_MPT_H_
 #define _GVT_MPT_H_
 
-struct guest_page;
-struct vgt_device;
-
 static inline unsigned long hypervisor_g2m_pfn(struct vgt_device *vgt,
 	unsigned long g_pfn)
 {
-	return 0;
+	return gvt_host.kdm->g2m_pfn(vgt->vm_id, g_pfn);
 }
 
 static inline int hypervisor_pause_domain(struct vgt_device *vgt)
 {
-	return 0;
+	return gvt_host.kdm->pause_domain(vgt->vm_id);
 }
 
 static inline int hypervisor_shutdown_domain(struct vgt_device *vgt)
 {
+	return gvt_host.kdm->shutdown_domain(vgt->vm_id);
+}
+
+static inline int hypervisor_map_mfn_to_gpfn(struct vgt_device *vgt,
+	unsigned long gpfn, unsigned long mfn, int nr, int map, enum map_type type)
+{
+	if (gvt_host.kdm && gvt_host.kdm->map_mfn_to_gpfn)
+		return gvt_host.kdm->map_mfn_to_gpfn(vgt->vm_id, gpfn, mfn, nr, map, type);
+
 	return 0;
 }
 
 static inline int hypervisor_set_trap_area(struct vgt_device *vgt,
-	uint64_t start, uint64_t end, bool map)
+	u64 start, u64 end, bool map)
 {
-	return 0;
+	return gvt_host.kdm->set_trap_area(vgt, start, end, map);
 }
 
-static inline bool hypervisor_detect_host(void)
+static inline int hypervisor_set_wp_pages(struct vgt_device *vgt, guest_page_t *p)
 {
-	return false;
+	return gvt_host.kdm->set_wp_pages(vgt, p);
 }
 
-static inline int hypervisor_virt_to_mfn(void *addr)
+static inline int hypervisor_unset_wp_pages(struct vgt_device *vgt, guest_page_t *p)
 {
-	return 0;
+	return gvt_host.kdm->unset_wp_pages(vgt, p);
 }
 
-static inline void *hypervisor_mfn_to_virt(int mfn)
+static inline int hypervisor_detect_host(void)
 {
-	return NULL;
+	return gvt_host.kdm->detect_host();
 }
 
-static inline int hypervisor_set_wp_pages(struct vgt_device *vgt, struct guest_page *p)
+static inline int hypervisor_virt_to_mfn(void *addr)
 {
-        return 0;
+	return gvt_host.kdm->from_virt_to_mfn(addr);
 }
 
-static inline int hypervisor_unset_wp_pages(struct vgt_device *vgt, struct guest_page *p)
+static inline void *hypervisor_mfn_to_virt(int mfn)
 {
-        return 0;
+	return gvt_host.kdm->from_mfn_to_virt(mfn);
 }
 
 static inline void hypervisor_inject_msi(struct vgt_device *vgt)
 {
-	return;
+#define MSI_CAP_OFFSET 0x90	/* FIXME. need to get from cfg emulation */
+#define MSI_CAP_CONTROL (MSI_CAP_OFFSET + 2)
+#define MSI_CAP_ADDRESS (MSI_CAP_OFFSET + 4)
+#define MSI_CAP_DATA	(MSI_CAP_OFFSET + 8)
+#define MSI_CAP_EN 0x1
+
+	char *cfg_space = &vgt->state.cfg.space[0];
+	u16 control = *(u16 *)(cfg_space + MSI_CAP_CONTROL);
+	u32 addr = *(u32 *)(cfg_space + MSI_CAP_ADDRESS);
+	u16 data = *(u16 *)(cfg_space + MSI_CAP_DATA);
+	int r;
+
+	/* Do not generate MSI if MSIEN is disable */
+	if (!(control & MSI_CAP_EN))
+		return;
+
+	/* FIXME: currently only handle one MSI format */
+	ASSERT_NUM(!(control & 0xfffe), control);
+
+	gvt_dbg(GVT_DBG_IRQ, "VM %d hvm injections. address (%x) data(%x)!",
+			vgt->vm_id, addr, data);
+	r = gvt_host.kdm->inject_msi(vgt->vm_id, addr, data);
+	if (r < 0)
+		gvt_err("VGT %d failed to inject vmsi", vgt->id);
 }
 
 static inline int hypervisor_hvm_init(struct vgt_device *vgt)
 {
+	if (gvt_host.kdm && gvt_host.kdm->hvm_init)
+		return gvt_host.kdm->hvm_init(vgt);
+
 	return 0;
 }
 
 static inline void hypervisor_hvm_exit(struct vgt_device *vgt)
 {
+	if (gvt_host.kdm && gvt_host.kdm->hvm_exit)
+		gvt_host.kdm->hvm_exit(vgt);
 }
 
 static inline void *hypervisor_gpa_to_va(struct vgt_device *vgt, unsigned long gpa)
 {
-	return NULL;
+	if (!vgt->vm_id)
+		return (char *)hypervisor_mfn_to_virt(gpa >> PAGE_SHIFT) + offset_in_page(gpa);
+
+	return gvt_host.kdm->gpa_to_va(vgt, gpa);
 }
 
 static inline bool hypervisor_read_va(struct vgt_device *vgt, void *va,
 		void *val, int len, int atomic)
 {
-	return false;
+	bool ret;
+
+	if (!vgt->vm_id) {
+		memcpy(val, va, len);
+		return true;
+	}
+
+	ret = gvt_host.kdm->read_va(vgt, va, val, len, atomic);
+	if (unlikely(!ret))
+		gvt_err("VM(%d): read va failed, va: 0x%p, atomic : %s\n", vgt->vm_id,
+				va, atomic ? "yes" : "no");
+
+	return ret;
 }
 
 static inline bool hypervisor_write_va(struct vgt_device *vgt, void *va,
 		void *val, int len, int atomic)
 {
-	return false;
+	bool ret;
+
+	if (!vgt->vm_id) {
+		memcpy(va, val, len);
+		return true;
+	}
+
+	ret = gvt_host.kdm->write_va(vgt, va, val, len, atomic);
+	if (unlikely(!ret))
+		gvt_err("VM(%d): write va failed, va: 0x%p, atomic : %s\n", vgt->vm_id,
+				va, atomic ? "yes" : "no");
+
+	return ret;
 }
 
 #endif /* _GVT_MPT_H_ */
diff --git a/drivers/gpu/drm/i915/gvt/perf.h b/drivers/gpu/drm/i915/gvt/perf.h
index 146a1cb..21b0637 100644
--- a/drivers/gpu/drm/i915/gvt/perf.h
+++ b/drivers/gpu/drm/i915/gvt/perf.h
@@ -28,6 +28,10 @@ struct gvt_statistics {
 	u64	irq_num;
 	u64	events[GVT_EVENT_MAX];
 	u64	last_injection;
+	u64	mmio_rcnt;
+	u64	mmio_wcnt;
+	u64	mmio_wcycles;
+	u64	mmio_rcycles;
 	u64	gtt_mmio_rcnt;
 	u64	gtt_mmio_wcnt;
 	u64	gtt_mmio_wcycles;
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 17/29] gvt: Xen hypervisor GVT-g MPT module
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (15 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 16/29] drm/i915: gvt: Generic MPT framework Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 11:33   ` Joonas Lahtinen
  2016-01-28 10:21 ` [RFC 18/29] drm/i915: gvt: vGPU configuration emulation Zhi Wang
                   ` (12 subsequent siblings)
  29 siblings, 1 reply; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This is the xen hypervisor MPT module which let GVT-g be able to run under
Xen hypervisor.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 arch/x86/include/asm/xen/hypercall.h |    7 +
 arch/x86/include/asm/xen/interface.h |    1 +
 arch/x86/xen/mmu.c                   |   83 +++
 drivers/gpu/drm/i915/gvt/gvt.c       |   10 +
 drivers/gpu/drm/i915/gvt/gvt.h       |   14 +
 drivers/xen/Kconfig                  |    5 +
 drivers/xen/Makefile                 |    6 +
 drivers/xen/xengt.c                  | 1153 ++++++++++++++++++++++++++++++++++
 include/xen/interface/hvm/hvm_op.h   |  177 +++++-
 include/xen/interface/hvm/ioreq.h    |  132 ++++
 include/xen/interface/memory.h       |   28 +
 include/xen/interface/xen.h          |  106 ++++
 include/xen/xen-ops.h                |    5 +
 13 files changed, 1726 insertions(+), 1 deletion(-)
 create mode 100644 drivers/xen/xengt.c
 create mode 100644 include/xen/interface/hvm/ioreq.h

diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h
index 3bcdcc8..aea97e3 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -459,6 +459,13 @@ HYPERVISOR_hvm_op(int op, void *arg)
 }
 
 static inline int
+HYPERVISOR_domctl(
+        struct xen_domctl *arg)
+{
+        return _hypercall1(int, domctl, arg);
+}
+
+static inline int
 HYPERVISOR_tmem_op(
 	struct tmem_op *op)
 {
diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h
index 6ff4986..a4ee3f4 100644
--- a/arch/x86/include/asm/xen/interface.h
+++ b/arch/x86/include/asm/xen/interface.h
@@ -89,6 +89,7 @@ typedef long xen_long_t;
 /* Guest handles for primitive C types. */
 __DEFINE_GUEST_HANDLE(uchar, unsigned char);
 __DEFINE_GUEST_HANDLE(uint,  unsigned int);
+__DEFINE_GUEST_HANDLE(ulong,  unsigned long);
 DEFINE_GUEST_HANDLE(char);
 DEFINE_GUEST_HANDLE(int);
 DEFINE_GUEST_HANDLE(void);
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index c913ca4..da95d45 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2931,3 +2931,86 @@ int xen_unmap_domain_gfn_range(struct vm_area_struct *vma,
 #endif
 }
 EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range);
+
+/* Note: here 'mfn' is actually gfn!!! */
+struct vm_struct * xen_remap_domain_mfn_range_in_kernel(unsigned long mfn,
+		int nr, unsigned domid)
+{
+	struct vm_struct *area;
+	struct remap_data rmd;
+	struct mmu_update mmu_update[REMAP_BATCH_SIZE];
+	int batch;
+	unsigned long range, addr;
+	pgprot_t prot;
+	int err;
+
+	WARN_ON(in_interrupt() || irqs_disabled());
+
+	area = alloc_vm_area(nr << PAGE_SHIFT, NULL);
+	if (!area)
+		return NULL;
+
+	addr = (unsigned long)area->addr;
+
+	prot = __pgprot(pgprot_val(PAGE_KERNEL));
+
+	rmd.mfn = &mfn;
+	rmd.prot = prot;
+
+	while (nr) {
+		batch = min(REMAP_BATCH_SIZE, nr);
+		range = (unsigned long)batch << PAGE_SHIFT;
+
+		rmd.mmu_update = mmu_update;
+		err = apply_to_page_range(&init_mm, addr, range,
+				remap_area_mfn_pte_fn, &rmd);
+		if (err || HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid) < 0)
+			goto err;
+
+		nr -= batch;
+		addr += range;
+	}
+
+	xen_flush_tlb_all();
+	return area;
+err:
+	free_vm_area(area);
+	xen_flush_tlb_all();
+	return NULL;
+}
+EXPORT_SYMBOL(xen_remap_domain_mfn_range_in_kernel);
+
+void xen_unmap_domain_mfn_range_in_kernel(struct vm_struct *area, int nr,
+		unsigned domid)
+{
+	struct remap_data rmd;
+	struct mmu_update mmu_update[REMAP_BATCH_SIZE];
+	int batch;
+	unsigned long range, addr = (unsigned long)area->addr;
+#define INVALID_MFN (~0UL)
+	unsigned long invalid_mfn = INVALID_MFN;
+	int err;
+
+	WARN_ON(in_interrupt() || irqs_disabled());
+
+	rmd.mfn = &invalid_mfn;
+	rmd.prot = PAGE_NONE;
+
+	while (nr) {
+		batch = min(REMAP_BATCH_SIZE, nr);
+		range = (unsigned long)batch << PAGE_SHIFT;
+
+		rmd.mmu_update = mmu_update;
+		err = apply_to_page_range(&init_mm, addr, range,
+				remap_area_mfn_pte_fn, &rmd);
+		BUG_ON(err);
+		BUG_ON(HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid) < 0);
+
+		nr -= batch;
+		addr += range;
+	}
+
+	free_vm_area(area);
+	xen_flush_tlb_all();
+}
+EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range_in_kernel);
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index a71873c..28a51d9 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -21,12 +21,14 @@
  * SOFTWARE.
  */
 
+#include <linux/types.h>
 #include <xen/xen.h>
 #include <linux/kthread.h>
 
 #include "gvt.h"
 
 struct gvt_host gvt_host;
+EXPORT_SYMBOL(gvt_host);
 
 extern struct gvt_kernel_dm xengt_kdm;
 extern struct gvt_kernel_dm kvmgt_kdm;
@@ -36,6 +38,13 @@ static struct gvt_io_emulation_ops default_io_emulation_ops = {
 	.emulate_mmio_write = gvt_emulate_mmio_write,
 };
 
+unsigned int pa_to_mmio_offset(struct vgt_device *vgt,
+               uint64_t pa);
+
+static struct gvt_mpt_ops default_export_mpt_ops = {
+	.pa_to_mmio_offset = pa_to_mmio_offset,
+};
+
 static const char *supported_hypervisors[] = {
 	[GVT_HYPERVISOR_TYPE_XEN] = "Xen Hypervisor",
 	[GVT_HYPERVISOR_TYPE_KVM] = "KVM",
@@ -78,6 +87,7 @@ static bool gvt_init_host(void)
 			supported_hypervisors[host->hypervisor_type]);
 
 	host->emulate_ops = &default_io_emulation_ops;
+	host->mpt_ops = &default_export_mpt_ops;
 	idr_init(&host->device_idr);
 	mutex_init(&host->device_idr_lock);
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index eb5fd47..83f90a2 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -58,6 +58,10 @@ struct gvt_io_emulation_ops {
 	bool (*emulate_cfg_write)(struct vgt_device *, unsigned int, void *, int);
 };
 
+struct gvt_mpt_ops {
+	unsigned int (*pa_to_mmio_offset)(struct vgt_device *, u64);
+};
+
 struct gvt_host {
 	bool initialized;
 	int hypervisor_type;
@@ -65,6 +69,7 @@ struct gvt_host {
 	struct idr device_idr;
 	struct gvt_kernel_dm *kdm;
 	struct gvt_io_emulation_ops *emulate_ops;
+	struct gvt_mpt_ops *mpt_ops;
 };
 
 extern struct gvt_host gvt_host;
@@ -123,6 +128,9 @@ struct vgt_device {
 	struct gvt_virtual_device_state state;
 	struct gvt_statistics stat;
 	struct gvt_vgtt_info gtt;
+	void *hypervisor_data;
+	unsigned long low_mem_max_gpfn;
+	atomic_t crashing;
 };
 
 struct gvt_gm_allocator {
@@ -423,6 +431,12 @@ static inline int gvt_pci_mmio_is_enabled(struct vgt_device *vgt)
 		_REGBIT_CFG_COMMAND_MEMORY;
 }
 
+static inline uint64_t gvt_mmio_bar_base(struct vgt_device *vgt)
+{
+        char *cfg_space = &vgt->state.cfg.space[0];
+        return *(u64 *)(cfg_space + GVT_REG_CFG_SPACE_BAR0);
+}
+
 #define __vreg(vgt, off) (*(u32*)(vgt->state.mmio.vreg + off))
 #define __vreg8(vgt, off) (*(u8*)(vgt->state.mmio.vreg + off))
 #define __vreg16(vgt, off) (*(u16*)(vgt->state.mmio.vreg + off))
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 73708ac..9ee2033 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -291,4 +291,9 @@ config XEN_SYMS
 config XEN_HAVE_VPMU
        bool
 
+config XENGT
+        tristate "Xen Dom0 support for i915 gvt device model"
+        depends on XEN_DOM0 && I915_GVT
+        default m
+
 endmenu
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 9b7a35c..ff75c36 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -9,6 +9,10 @@ CFLAGS_features.o			:= $(nostackp)
 
 CFLAGS_efi.o				+= -fshort-wchar
 
+
+I915                     := drivers/gpu/drm/i915
+CFLAGS_xengt.o          += -Wall -Werror -I$(I915) -I$(I915)/gvt
+
 dom0-$(CONFIG_PCI) += pci.o
 dom0-$(CONFIG_USB_SUPPORT) += dbgp.o
 dom0-$(CONFIG_XEN_ACPI) += acpi.o $(xen-pad-y)
@@ -36,6 +40,8 @@ obj-$(CONFIG_XEN_ACPI_PROCESSOR)	+= xen-acpi-processor.o
 obj-$(CONFIG_XEN_EFI)			+= efi.o
 obj-$(CONFIG_XEN_SCSI_BACKEND)		+= xen-scsiback.o
 obj-$(CONFIG_XEN_AUTO_XLATE)		+= xlate_mmu.o
+obj-$(CONFIG_XENGT)                     += xengt.o
+
 xen-evtchn-y				:= evtchn.o
 xen-gntdev-y				:= gntdev.o
 xen-gntalloc-y				:= gntalloc.o
diff --git a/drivers/xen/xengt.c b/drivers/xen/xengt.c
new file mode 100644
index 0000000..6c600adc
--- /dev/null
+++ b/drivers/xen/xengt.c
@@ -0,0 +1,1153 @@
+/*
+ * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of Version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * NOTE:
+ * This file contains hypervisor specific interactions to
+ * implement the concept of mediated pass-through framework.
+ * What this file provides is actually a general abstraction
+ * of in-kernel device model, which is not vgt specific.
+ *
+ * Now temporarily in vgt code. long-term this should be
+ * in hypervisor (xen/kvm) specific directory
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/kthread.h>
+#include <linux/time.h>
+#include <linux/freezer.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/page.h>
+#include <xen/xen-ops.h>
+#include <xen/events.h>
+#include <xen/interface/hvm/params.h>
+#include <xen/interface/hvm/hvm_op.h>
+#include <xen/interface/hvm/ioreq.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/platform.h>
+#include <xen/interface/vcpu.h>
+
+#include "gvt.h"
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("XenGT mediated passthrough driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
+
+#define MAX_HVM_VCPUS_SUPPORTED 128
+struct gvt_hvm_info {
+	/* iopage_vma->addr is just iopage. We need iopage_vma on VM destroy */
+	shared_iopage_t *iopage;
+	struct vm_struct *iopage_vma;
+	int *evtchn_irq; /* the event channle irqs to handle HVM io request
+				index is vcpu id */
+
+	DECLARE_BITMAP(ioreq_pending, MAX_HVM_VCPUS_SUPPORTED);
+	wait_queue_head_t io_event_wq;
+	struct task_struct *emulation_thread;
+
+	int nr_vcpu;
+
+	ioservid_t iosrv_id;    /* io-request server id */
+
+#define VMEM_1MB		(1ULL << 20)	/* the size of the first 1MB */
+#define VMEM_BUCK_SHIFT		20
+#define VMEM_BUCK_SIZE		(1ULL << VMEM_BUCK_SHIFT)
+#define VMEM_BUCK_MASK		(~(VMEM_BUCK_SIZE - 1))
+	uint64_t vmem_sz;
+	/* for the 1st 1MB memory of HVM: each vm_struct means one 4K-page */
+	struct vm_struct **vmem_vma_low_1mb;
+	/* for >1MB memory of HVM: each vm_struct means 1MB */
+	struct vm_struct **vmem_vma;
+	/* for >1MB memory of HVM: each vm_struct means 4KB */
+	struct vm_struct **vmem_vma_4k;
+};
+
+static int xen_pause_domain(int vm_id);
+static int xen_shutdown_domain(int vm_id);
+static void *xen_gpa_to_va(struct vgt_device *vgt, unsigned long gpa);
+
+#define XEN_ASSERT_VM(x, vgt)						\
+	do {								\
+		if (!(x)) {						\
+			printk("Assert at %s line %d\n",		\
+				__FILE__, __LINE__);			\
+			if (atomic_cmpxchg(&(vgt)->crashing, 0, 1))	\
+				break;					\
+			gvt_err("Killing VM%d\n", (vgt)->vm_id);	\
+			if (!xen_pause_domain((vgt->vm_id)))		\
+				xen_shutdown_domain((vgt->vm_id));	\
+		}							\
+	} while (0)
+
+/* Translate from VM's guest pfn to machine pfn */
+static unsigned long xen_g2m_pfn(int vm_id, unsigned long g_pfn)
+{
+	struct xen_get_mfn_from_pfn pfn_arg;
+	int rc;
+	unsigned long pfn_list[1];
+
+	pfn_list[0] = g_pfn;
+
+	set_xen_guest_handle(pfn_arg.pfn_list, pfn_list);
+	pfn_arg.nr_pfns = 1;
+	pfn_arg.domid = vm_id;
+
+	rc = HYPERVISOR_memory_op(XENMEM_get_mfn_from_pfn, &pfn_arg);
+	if(rc < 0){
+		printk("failed to get mfn for gpfn(0x%lx)\n, errno=%d\n", g_pfn, rc);
+		return INVALID_MFN;
+	}
+
+	return pfn_list[0];
+}
+
+static int xen_get_max_gpfn(int vm_id)
+{
+	domid_t dom_id = vm_id;
+	int max_gpfn = HYPERVISOR_memory_op(XENMEM_maximum_gpfn, &dom_id);
+	BUG_ON(max_gpfn < 0);
+	return max_gpfn;
+}
+
+static int xen_pause_domain(int vm_id)
+{
+	int rc;
+	struct xen_domctl domctl;
+
+	domctl.domain = vm_id;
+	domctl.cmd = XEN_DOMCTL_pausedomain;
+	domctl.interface_version = XEN_DOMCTL_INTERFACE_VERSION;
+
+	rc = HYPERVISOR_domctl(&domctl);
+	if (rc != 0)
+		printk("HYPERVISOR_domctl pausedomain fail with %d!\n", rc);
+
+	return rc;
+}
+
+static int xen_shutdown_domain(int vm_id)
+{
+	int rc;
+	struct sched_remote_shutdown r;
+
+	r.reason = SHUTDOWN_crash;
+	r.domain_id = vm_id;
+	rc = HYPERVISOR_sched_op(SCHEDOP_remote_shutdown, &r);
+	if (rc != 0)
+		printk("HYPERVISOR_sched_op failed: %d\n", rc);
+	return rc;
+}
+
+static int xen_domain_iomem_perm(uint32_t domain_id, uint64_t first_mfn,
+                               uint64_t nr_mfns, uint8_t allow_access)
+{
+	struct xen_domctl arg;
+	int rc;
+
+	arg.domain = domain_id;
+	arg.cmd = XEN_DOMCTL_iomem_permission;
+	arg.interface_version = XEN_DOMCTL_INTERFACE_VERSION;
+	arg.u.iomem_perm.first_mfn = first_mfn;
+	arg.u.iomem_perm.nr_mfns = nr_mfns;
+	arg.u.iomem_perm.allow_access = allow_access;
+	rc = HYPERVISOR_domctl(&arg);
+
+	return rc;
+}
+
+static int xen_hvm_memory_mapping(int vm_id, uint64_t first_gfn, uint64_t first_mfn,
+				  uint32_t nr_mfns, uint32_t add_mapping)
+{
+	struct xen_domctl arg;
+	int rc;
+
+	if (add_mapping) {
+		rc = xen_domain_iomem_perm(vm_id, first_mfn, nr_mfns, 1);
+	        if (rc < 0) {
+			printk(KERN_ERR "xen_domain_iomem_perm failed: %d\n", rc);
+			return rc;
+		}
+	}
+
+	arg.domain = vm_id;
+	arg.cmd = XEN_DOMCTL_memory_mapping;
+	arg.interface_version = XEN_DOMCTL_INTERFACE_VERSION;
+	arg.u.memory_mapping.first_gfn = first_gfn;
+	arg.u.memory_mapping.first_mfn = first_mfn;
+	arg.u.memory_mapping.nr_mfns = nr_mfns;
+	arg.u.memory_mapping.add_mapping = add_mapping;
+
+	rc = HYPERVISOR_domctl(&arg);
+	if (rc < 0) {
+		printk(KERN_ERR "HYPERVISOR_domctl failed: %d\n", rc);
+		return rc;
+	}
+
+	if (!add_mapping) {
+		rc = xen_domain_iomem_perm(vm_id, first_mfn, nr_mfns, 0);
+	        if (rc < 0) {
+			printk(KERN_ERR "xen_domain_iomem_perm failed: %d\n", rc);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int xen_map_mfn_to_gpfn(int vm_id, unsigned long gpfn,
+	unsigned long mfn, int nr, int map, enum map_type type)
+{
+	int rc;
+	rc = xen_hvm_memory_mapping(vm_id, gpfn, mfn, nr,
+			map ? DPCI_ADD_MAPPING : DPCI_REMOVE_MAPPING);
+	if (rc != 0)
+		printk("xen_hvm_memory_mapping failed: %d\n", rc);
+	return rc;
+}
+
+static int xen_get_nr_vcpu(int vm_id)
+{
+	struct xen_domctl arg;
+	int rc;
+
+	arg.domain = vm_id;
+	arg.cmd = XEN_DOMCTL_getdomaininfo;
+	arg.interface_version = XEN_DOMCTL_INTERFACE_VERSION;
+
+	rc = HYPERVISOR_domctl(&arg);
+	if (rc<0){
+		printk(KERN_ERR "HYPERVISOR_domctl fail ret=%d\n",rc);
+		/* assume it is UP */
+		return 1;
+	}
+
+	return arg.u.getdomaininfo.max_vcpu_id + 1;
+}
+
+static int hvm_create_iorequest_server(struct vgt_device *vgt)
+{
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+	struct xen_hvm_create_ioreq_server arg;
+	int r;
+
+	arg.domid = vgt->vm_id;
+	arg.handle_bufioreq = 0;
+	r = HYPERVISOR_hvm_op(HVMOP_create_ioreq_server, &arg);
+	if (r < 0) {
+		printk(KERN_ERR "Cannot create io-requset server: %d!\n", r);
+		return r;
+	}
+	info->iosrv_id = arg.id;
+
+	return r;
+}
+
+static int hvm_toggle_iorequest_server(struct vgt_device *vgt, bool enable)
+{
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+	struct xen_hvm_set_ioreq_server_state arg;
+	int r;
+
+	arg.domid = vgt->vm_id;
+	arg.id = info->iosrv_id;
+	arg.enabled = enable;
+	r = HYPERVISOR_hvm_op(HVMOP_set_ioreq_server_state, &arg);
+	if (r < 0) {
+		printk(KERN_ERR "Cannot %s io-request server: %d!\n",
+			enable ? "enable" : "disbale",  r);
+		return r;
+	}
+
+       return r;
+}
+
+static int hvm_get_ioreq_pfn(struct vgt_device *vgt, uint64_t *value)
+{
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+	struct xen_hvm_get_ioreq_server_info arg;
+	int r;
+
+	arg.domid = vgt->vm_id;
+	arg.id = info->iosrv_id;
+	r = HYPERVISOR_hvm_op(HVMOP_get_ioreq_server_info, &arg);
+	if (r < 0) {
+		printk(KERN_ERR "Cannot get ioreq pfn: %d!\n", r);
+		return r;
+	}
+	*value = arg.ioreq_pfn;
+	return r;
+}
+
+static int hvm_destroy_iorequest_server(struct vgt_device *vgt)
+{
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+	struct xen_hvm_destroy_ioreq_server arg;
+	int r;
+
+	arg.domid = vgt->vm_id;
+	arg.id = info->iosrv_id;
+	r = HYPERVISOR_hvm_op(HVMOP_destroy_ioreq_server, &arg);
+	if (r < 0) {
+		printk(KERN_ERR "Cannot destroy io-request server(%d): %d!\n",
+			info->iosrv_id, r);
+		return r;
+	}
+	info->iosrv_id = 0;
+
+	return r;
+}
+
+static int hvm_map_io_range_to_ioreq_server(struct vgt_device *vgt,
+	int is_mmio, uint64_t start, uint64_t end, int map)
+{
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+	xen_hvm_io_range_t arg;
+	int rc;
+
+	arg.domid = vgt->vm_id;
+	arg.id = info->iosrv_id;
+	arg.type = is_mmio ? HVMOP_IO_RANGE_MEMORY : HVMOP_IO_RANGE_PORT;
+	arg.start = start;
+	arg.end = end;
+
+	if (map)
+		rc = HYPERVISOR_hvm_op(HVMOP_map_io_range_to_ioreq_server, &arg);
+	else
+		rc = HYPERVISOR_hvm_op(HVMOP_unmap_io_range_from_ioreq_server, &arg);
+
+	return rc;
+}
+
+static int hvm_map_pcidev_to_ioreq_server(struct vgt_device *vgt, uint64_t sbdf)
+{
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+	xen_hvm_io_range_t arg;
+	int rc;
+
+	arg.domid = vgt->vm_id;
+	arg.id = info->iosrv_id;
+	arg.type = HVMOP_IO_RANGE_PCI;
+	arg.start = arg.end = sbdf;
+	rc = HYPERVISOR_hvm_op(HVMOP_map_io_range_to_ioreq_server, &arg);
+	if (rc < 0) {
+		printk(KERN_ERR "Cannot map pci_dev to ioreq_server: %d!\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int hvm_set_mem_type(struct vgt_device *vgt,
+	uint16_t mem_type, uint64_t first_pfn, uint64_t nr)
+{
+	xen_hvm_set_mem_type_t args;
+	int rc;
+
+	args.domid = vgt->vm_id;
+	args.hvmmem_type = mem_type;
+	args.first_pfn = first_pfn;
+	args.nr = 1;
+	rc = HYPERVISOR_hvm_op(HVMOP_set_mem_type, &args);
+
+	return rc;
+}
+
+static int hvm_wp_page_to_ioreq_server(struct vgt_device *vgt, unsigned long page, int set)
+{
+	int rc = 0;
+	uint64_t start, end;
+	uint16_t mem_type;
+
+	start = page << PAGE_SHIFT;
+	end = ((page + 1) << PAGE_SHIFT) - 1;
+
+	rc = hvm_map_io_range_to_ioreq_server(vgt, 1, start, end, set);
+	if (rc < 0) {
+		printk(KERN_ERR "Failed to %s page 0x%lx to ioreq_server: %d!\n",
+			set ? "map":"unmap", page , rc);
+		return rc;
+	}
+
+	mem_type = set ? HVMMEM_mmio_write_dm : HVMMEM_ram_rw;
+	rc = hvm_set_mem_type(vgt, mem_type, page, 1);
+	if (rc < 0) {
+		printk(KERN_ERR "Failed to set mem type of page 0x%lx to %s!\n", page,
+			set ? "HVMMEM_mmio_write_dm":"HVMMEM_ram_rw");
+		return rc;
+	}
+	return rc;
+}
+
+static int xen_set_trap_area(struct vgt_device *vgt, uint64_t start, uint64_t end, bool map)
+{
+	if (!gvt_pci_mmio_is_enabled(vgt))
+		return 0;
+
+	return hvm_map_io_range_to_ioreq_server(vgt, 1, start, end, map);
+}
+
+static struct vm_struct *xen_map_iopage(struct vgt_device *vgt)
+{
+	uint64_t ioreq_pfn;
+	int rc;
+
+	rc = hvm_create_iorequest_server(vgt);
+	if (rc < 0)
+		return NULL;
+	rc = hvm_get_ioreq_pfn(vgt, &ioreq_pfn);
+	if (rc < 0) {
+		hvm_destroy_iorequest_server(vgt);
+		return NULL;
+	}
+
+	return xen_remap_domain_mfn_range_in_kernel(ioreq_pfn, 1, vgt->vm_id);
+}
+
+static bool xen_set_guest_page_writeprotection(struct vgt_device *vgt,
+		guest_page_t *guest_page)
+{
+	int r;
+
+	if (guest_page->writeprotection)
+		return true;
+
+	r = hvm_wp_page_to_ioreq_server(vgt, guest_page->gfn, 1);
+	if (r) {
+		gvt_err("fail to set write protection.\n");
+		return false;
+	}
+
+	guest_page->writeprotection = true;
+
+	atomic_inc(&vgt->gtt.n_write_protected_guest_page);
+
+	return true;
+}
+
+static bool xen_clear_guest_page_writeprotection(struct vgt_device *vgt,
+		guest_page_t *guest_page)
+{
+	int r;
+
+	if (!guest_page->writeprotection)
+		return true;
+
+	r = hvm_wp_page_to_ioreq_server(vgt, guest_page->gfn, 0);
+	if (r) {
+		gvt_err("fail to clear write protection.\n");
+		return false;
+	}
+
+	guest_page->writeprotection = false;
+
+	atomic_dec(&vgt->gtt.n_write_protected_guest_page);
+
+	return true;
+}
+
+static int xen_detect_host(void)
+{
+	return xen_initial_domain();
+}
+
+static int xen_virt_to_mfn(void *addr)
+{
+	return virt_to_mfn(addr);
+}
+
+static void *xen_mfn_to_virt(int mfn)
+{
+	return mfn_to_virt(mfn);
+}
+
+static int xen_inject_msi(int vm_id, u32 addr_lo, u16 data)
+{
+	struct xen_hvm_inject_msi info = {
+		.domid	= vm_id,
+		.addr	= addr_lo, /* only low addr used */
+		.data	= data,
+	};
+
+	return HYPERVISOR_hvm_op(HVMOP_inject_msi, &info);
+}
+
+static int vgt_hvm_vmem_init(struct vgt_device *vgt)
+{
+	unsigned long i, j, gpfn, count;
+	unsigned long nr_low_1mb_bkt, nr_high_bkt, nr_high_4k_bkt;
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+
+	if (!vgt->vm_id)
+		return 0;
+
+	ASSERT(info->vmem_vma == NULL && info->vmem_vma_low_1mb == NULL);
+
+	info->vmem_sz = xen_get_max_gpfn(vgt->vm_id) + 1;
+	info->vmem_sz <<= PAGE_SHIFT;
+
+	/* warn on non-1MB-aligned memory layout of HVM */
+	if (info->vmem_sz & ~VMEM_BUCK_MASK)
+		gvt_err("VM%d: vmem_sz=0x%llx!\n", vgt->vm_id, info->vmem_sz);
+
+	nr_low_1mb_bkt = VMEM_1MB >> PAGE_SHIFT;
+	nr_high_bkt = (info->vmem_sz >> VMEM_BUCK_SHIFT);
+	nr_high_4k_bkt = (info->vmem_sz >> PAGE_SHIFT);
+
+	info->vmem_vma_low_1mb =
+		vzalloc(sizeof(*info->vmem_vma) * nr_low_1mb_bkt);
+	info->vmem_vma =
+		vzalloc(sizeof(*info->vmem_vma) * nr_high_bkt);
+	info->vmem_vma_4k =
+		vzalloc(sizeof(*info->vmem_vma) * nr_high_4k_bkt);
+
+	if (info->vmem_vma_low_1mb == NULL || info->vmem_vma == NULL ||
+		info->vmem_vma_4k == NULL) {
+		gvt_err("Insufficient memory for vmem_vma, vmem_sz=0x%llx\n",
+				info->vmem_sz );
+		goto err;
+	}
+
+	/* map the low 1MB memory */
+	for (i = 0; i < nr_low_1mb_bkt; i++) {
+		info->vmem_vma_low_1mb[i] =
+			xen_remap_domain_mfn_range_in_kernel(i, 1, vgt->vm_id);
+
+		if (info->vmem_vma_low_1mb[i] != NULL)
+			continue;
+
+		/* Don't warn on [0xa0000, 0x100000): a known non-RAM hole */
+		if (i < (0xa0000 >> PAGE_SHIFT))
+			printk(KERN_ERR "GVT: VM%d: can't map GPFN %ld!\n",
+				vgt->vm_id, i);
+	}
+
+	printk("start vmem_map\n");
+	count = 0;
+	/* map the >1MB memory */
+	for (i = 1; i < nr_high_bkt; i++) {
+		gpfn = i << (VMEM_BUCK_SHIFT - PAGE_SHIFT);
+		info->vmem_vma[i] = xen_remap_domain_mfn_range_in_kernel(
+				gpfn, VMEM_BUCK_SIZE >> PAGE_SHIFT, vgt->vm_id);
+
+		if (info->vmem_vma[i] != NULL)
+			continue;
+
+
+		/* for <4G GPFNs: skip the hole after low_mem_max_gpfn */
+		if (gpfn < (1 << (32 - PAGE_SHIFT)) &&
+			vgt->low_mem_max_gpfn != 0 &&
+			gpfn > vgt->low_mem_max_gpfn)
+			continue;
+
+		for (j = gpfn;
+		     j < ((i + 1) << (VMEM_BUCK_SHIFT - PAGE_SHIFT));
+		     j++) {
+			info->vmem_vma_4k[j] = xen_remap_domain_mfn_range_in_kernel(j, 1, vgt->vm_id);
+
+			if (info->vmem_vma_4k[j]) {
+				count++;
+				printk(KERN_ERR "map 4k gpa (%lx)\n", j << PAGE_SHIFT);
+			}
+		}
+
+		/* To reduce the number of err messages(some of them, due to
+		 * the MMIO hole, are spurious and harmless) we only print a
+		 * message if it's at every 64MB boundary or >4GB memory.
+		 */
+		if ((i % 64 == 0) || (i >= (1ULL << (32 - VMEM_BUCK_SHIFT))))
+			printk(KERN_ERR "GVT: VM%d: can't map %ldKB\n",
+				vgt->vm_id, i);
+	}
+	printk("end vmem_map (%ld 4k mappings)\n", count);
+
+	return 0;
+err:
+	vfree(info->vmem_vma);
+	vfree(info->vmem_vma_low_1mb);
+	vfree(info->vmem_vma_4k);
+	info->vmem_vma = info->vmem_vma_low_1mb = info->vmem_vma_4k = NULL;
+	return -ENOMEM;
+}
+
+static void vgt_vmem_destroy(struct vgt_device *vgt)
+{
+	int i, j;
+	unsigned long nr_low_1mb_bkt, nr_high_bkt, nr_high_bkt_4k;
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+
+	if (vgt->vm_id == 0)
+		return;
+
+	/*
+	 * Maybe the VM hasn't accessed GEN MMIO(e.g., still in the legacy VGA
+	 * mode), so no mapping is created yet.
+	 */
+	if (info->vmem_vma == NULL && info->vmem_vma_low_1mb == NULL)
+		return;
+
+	ASSERT(info->vmem_vma != NULL && info->vmem_vma_low_1mb != NULL);
+
+	nr_low_1mb_bkt = VMEM_1MB >> PAGE_SHIFT;
+	nr_high_bkt = (info->vmem_sz >> VMEM_BUCK_SHIFT);
+	nr_high_bkt_4k = (info->vmem_sz >> PAGE_SHIFT);
+
+	for (i = 0; i < nr_low_1mb_bkt; i++) {
+		if (info->vmem_vma_low_1mb[i] == NULL)
+			continue;
+		xen_unmap_domain_mfn_range_in_kernel(info->vmem_vma_low_1mb[i],
+				1, vgt->vm_id);
+	}
+
+	for (i = 1; i < nr_high_bkt; i++) {
+		if (info->vmem_vma[i] == NULL) {
+			for (j = (i << (VMEM_BUCK_SHIFT - PAGE_SHIFT));
+			     j < ((i + 1) << (VMEM_BUCK_SHIFT - PAGE_SHIFT));
+			     j++) {
+				if (info->vmem_vma_4k[j] == NULL)
+					continue;
+				xen_unmap_domain_mfn_range_in_kernel(
+					info->vmem_vma_4k[j], 1, vgt->vm_id);
+			}
+			continue;
+		}
+		xen_unmap_domain_mfn_range_in_kernel(
+			info->vmem_vma[i], VMEM_BUCK_SIZE >> PAGE_SHIFT,
+			vgt->vm_id);
+	}
+
+	vfree(info->vmem_vma);
+	vfree(info->vmem_vma_low_1mb);
+	vfree(info->vmem_vma_4k);
+}
+
+static int _hvm_mmio_emulation(struct vgt_device *vgt, struct ioreq *req)
+{
+	int i, sign;
+	void *gva;
+	unsigned long gpa;
+	uint64_t base = gvt_mmio_bar_base(vgt);
+	uint64_t tmp;
+	int pvinfo_page;
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+
+	if (info->vmem_vma == NULL) {
+		tmp = gvt_host.mpt_ops->pa_to_mmio_offset(vgt, req->addr);
+		pvinfo_page = (tmp >= VGT_PVINFO_PAGE
+				&& tmp < (VGT_PVINFO_PAGE + VGT_PVINFO_SIZE));
+		/*
+		 * hvmloader will read PVINFO to identify if HVM is in GVT
+		 * or VTD. So we don't trigger HVM mapping logic here.
+		 */
+		if (!pvinfo_page && vgt_hvm_vmem_init(vgt) < 0) {
+			gvt_err("can not map the memory of VM%d!!!\n", vgt->vm_id);
+			XEN_ASSERT_VM(info->vmem_vma != NULL, vgt);
+			return -EINVAL;
+		}
+	}
+
+	sign = req->df ? -1 : 1;
+
+	if (req->dir == IOREQ_READ) {
+		/* MMIO READ */
+		if (!req->data_is_ptr) {
+			if (req->count != 1)
+				goto err_ioreq_count;
+
+			//vgt_dbg(GVT_DBG_GENERIC,"HVM_MMIO_read: target register (%lx).\n",
+			//	(unsigned long)req->addr);
+			if (!gvt_host.emulate_ops->emulate_mmio_read(vgt, req->addr, &req->data, req->size))
+				return -EINVAL;
+		}
+		else {
+			if ((req->addr + sign * req->count * req->size < base)
+			   || (req->addr + sign * req->count * req->size >=
+				base + vgt->state.cfg.bar_size[0]))
+				goto err_ioreq_range;
+			//vgt_dbg(GVT_DBG_GENERIC,"HVM_MMIO_read: rep %d target memory %lx, slow!\n",
+			//	req->count, (unsigned long)req->addr);
+
+			for (i = 0; i < req->count; i++) {
+				if (!gvt_host.emulate_ops->emulate_mmio_read(vgt, req->addr + sign * i * req->size,
+					&tmp, req->size))
+					return -EINVAL;
+				gpa = req->data + sign * i * req->size;
+				if(!vgt->vm_id)
+					gva = (char *)xen_mfn_to_virt(gpa >> PAGE_SHIFT) + offset_in_page(gpa);
+				else
+					gva = xen_gpa_to_va(vgt, gpa);
+				if (gva) {
+					memcpy(gva, &tmp, req->size);
+				} else
+					gvt_err("VM %d is trying to store mmio data block to invalid gpa: 0x%lx.\n", vgt->vm_id, gpa);
+			}
+		}
+	}
+	else { /* MMIO Write */
+		if (!req->data_is_ptr) {
+			if (req->count != 1)
+				goto err_ioreq_count;
+			//vgt_dbg(GVT_DBG_GENERIC,"HVM_MMIO_write: target register (%lx).\n", (unsigned long)req->addr);
+			if (!gvt_host.emulate_ops->emulate_mmio_write(vgt, req->addr, &req->data, req->size))
+				return -EINVAL;
+		}
+		else {
+			if ((req->addr + sign * req->count * req->size < base)
+			    || (req->addr + sign * req->count * req->size >=
+				base + vgt->state.cfg.bar_size[0]))
+				goto err_ioreq_range;
+			//vgt_dbg(GVT_DBG_GENERIC,"HVM_MMIO_write: rep %d target memory %lx, slow!\n",
+			//	req->count, (unsigned long)req->addr);
+
+			for (i = 0; i < req->count; i++) {
+				gpa = req->data + sign * i * req->size;
+				if(!vgt->vm_id)
+					gva = (char *)xen_mfn_to_virt(gpa >> PAGE_SHIFT) + offset_in_page(gpa);
+				else
+					gva = xen_gpa_to_va(vgt, gpa);
+
+				if (gva != NULL)
+					memcpy(&tmp, gva, req->size);
+				else {
+					tmp = 0;
+					printk(KERN_ERR "GVT: can not read gpa = 0x%lx!!!\n", gpa);
+				}
+				if (!gvt_host.emulate_ops->emulate_mmio_write(vgt, req->addr + sign * i * req->size, &tmp, req->size))
+					return -EINVAL;
+			}
+		}
+	}
+
+	return 0;
+
+err_ioreq_count:
+	gvt_err("VM(%d): Unexpected %s request count(%d)\n",
+		vgt->vm_id, req->dir == IOREQ_READ ? "read" : "write",
+		req->count);
+	return -EINVAL;
+
+err_ioreq_range:
+	gvt_err("VM(%d): Invalid %s request addr end(%016llx)\n",
+		vgt->vm_id, req->dir == IOREQ_READ ? "read" : "write",
+		req->addr + sign * req->count * req->size);
+	return -ERANGE;
+}
+
+static bool vgt_hvm_write_cfg_space(struct vgt_device *vgt,
+	uint64_t addr, unsigned int bytes, unsigned long val)
+{
+	/* Low 32 bit of addr is real address, high 32 bit is bdf */
+	unsigned int port = addr & 0xffffffff;
+
+	ASSERT(((bytes == 4) && ((port & 3) == 0)) ||
+		((bytes == 2) && ((port & 1) == 0)) || (bytes == 1));
+	gvt_host.emulate_ops->emulate_cfg_write(vgt, port, &val, bytes);
+	return true;
+}
+
+static bool vgt_hvm_read_cfg_space(struct vgt_device *vgt,
+	uint64_t addr, unsigned int bytes, unsigned long *val)
+{
+	unsigned long data;
+	/* Low 32 bit of addr is real address, high 32 bit is bdf */
+	unsigned int port = addr & 0xffffffff;
+
+	ASSERT (((bytes == 4) && ((port & 3) == 0)) ||
+		((bytes == 2) && ((port & 1) == 0)) || (bytes == 1));
+	gvt_host.emulate_ops->emulate_cfg_read(vgt, port, &data, bytes);
+	memcpy(val, &data, bytes);
+	return true;
+}
+
+static int _hvm_pio_emulation(struct vgt_device *vgt, struct ioreq *ioreq)
+{
+	int sign;
+
+	sign = ioreq->df ? -1 : 1;
+
+	if (ioreq->dir == IOREQ_READ) {
+		/* PIO READ */
+		if (!ioreq->data_is_ptr) {
+			if(!vgt_hvm_read_cfg_space(vgt,
+				ioreq->addr,
+				ioreq->size,
+				(unsigned long*)&ioreq->data))
+				return -EINVAL;
+		} else {
+			printk(KERN_ERR "GVT: _hvm_pio_emulation read data_ptr %lx\n",
+			(long)ioreq->data);
+			goto err_data_ptr;
+		}
+	} else {
+		/* PIO WRITE */
+		if (!ioreq->data_is_ptr) {
+			if (!vgt_hvm_write_cfg_space(vgt,
+				ioreq->addr,
+				ioreq->size,
+				(unsigned long)ioreq->data))
+				return -EINVAL;
+		} else {
+			printk(KERN_ERR "GVT: _hvm_pio_emulation write data_ptr %lx\n",
+			(long)ioreq->data);
+			goto err_data_ptr;
+		}
+	}
+	return 0;
+err_data_ptr:
+	/* The data pointer of emulation is guest physical address
+	 * so far, which goes to Qemu emulation, but hard for
+	 * GVT driver which doesn't know gpn_2_mfn translation.
+	 * We may ask hypervisor to use mfn for GVT driver.
+	 * We mark it as unsupported in case guest really it.
+	 */
+	gvt_err("VM(%d): Unsupported %s data_ptr(%lx)\n",
+		vgt->vm_id, ioreq->dir == IOREQ_READ ? "read" : "write",
+		(long)ioreq->data);
+	return -EINVAL;
+}
+
+#define PCI_BDF2(b,df)  ((((b) & 0xff) << 8) | ((df) & 0xff))
+
+static int vgt_hvm_do_ioreq(struct vgt_device *vgt, struct ioreq *ioreq)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	struct pci_dev *pci_dev = pdev->dev_priv->dev->pdev;
+	uint64_t bdf = PCI_BDF2(pci_dev->bus->number, pci_dev->devfn);
+
+	/* When using ioreq-server, sometimes an event channal
+	 * notification is received with invalid ioreq. Don't
+	 * know the root cause. Put the workaround here.
+	 */
+	if (ioreq->state == STATE_IOREQ_NONE)
+		return 0;
+
+	if (ioreq->type == IOREQ_TYPE_INVALIDATE)
+		return 0;
+
+	switch (ioreq->type) {
+		case IOREQ_TYPE_PCI_CONFIG:
+		/* High 32 bit of ioreq->addr is bdf */
+		if ((ioreq->addr >> 32) != bdf) {
+			printk(KERN_ERR "GVT: Unexpected PCI Dev %lx emulation\n",
+				(unsigned long) (ioreq->addr>>32));
+				return -EINVAL;
+			} else
+				return _hvm_pio_emulation(vgt, ioreq);
+			break;
+		case IOREQ_TYPE_COPY:	/* MMIO */
+			return _hvm_mmio_emulation(vgt, ioreq);
+			break;
+		default:
+			printk(KERN_ERR "GVT: Unknown ioreq type %x addr %llx size %u state %u\n",
+				ioreq->type, ioreq->addr, ioreq->size, ioreq->state);
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct ioreq *vgt_get_hvm_ioreq(struct vgt_device *vgt, int vcpu)
+{
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+	return &(info->iopage->vcpu_ioreq[vcpu]);
+}
+
+static int vgt_emulation_thread(void *priv)
+{
+	struct vgt_device *vgt = (struct vgt_device *)priv;
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+
+	int vcpu;
+	int nr_vcpus = info->nr_vcpu;
+
+	struct ioreq *ioreq;
+	int irq, ret;
+
+	gvt_info("start kthread for VM%d\n", vgt->vm_id);
+
+	ASSERT(info->nr_vcpu <= MAX_HVM_VCPUS_SUPPORTED);
+
+	set_freezable();
+	while (1) {
+		ret = wait_event_freezable(info->io_event_wq,
+			kthread_should_stop() ||
+			bitmap_weight(info->ioreq_pending, nr_vcpus));
+
+		if (kthread_should_stop())
+			return 0;
+
+		if (ret)
+			gvt_err("Emulation thread(%d) waken up"
+				 "by unexpected signal!\n", vgt->vm_id);
+
+		for (vcpu = 0; vcpu < nr_vcpus; vcpu++) {
+			if (!test_and_clear_bit(vcpu, info->ioreq_pending))
+				continue;
+
+			ioreq = vgt_get_hvm_ioreq(vgt, vcpu);
+
+			if (vgt_hvm_do_ioreq(vgt, ioreq)) {
+				xen_pause_domain(vgt->vm_id);
+				xen_shutdown_domain(vgt->vm_id);
+			}
+
+			ioreq->state = STATE_IORESP_READY;
+
+			irq = info->evtchn_irq[vcpu];
+			notify_remote_via_irq(irq);
+		}
+	}
+
+	BUG(); /* It's actually impossible to reach here */
+	return 0;
+}
+
+static inline void vgt_raise_emulation_request(struct vgt_device *vgt,
+	int vcpu)
+{
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+	set_bit(vcpu, info->ioreq_pending);
+	if (waitqueue_active(&info->io_event_wq))
+		wake_up(&info->io_event_wq);
+}
+
+static irqreturn_t vgt_hvm_io_req_handler(int irq, void* dev)
+{
+	struct vgt_device *vgt;
+	struct gvt_hvm_info *info;
+	int vcpu;
+
+	vgt = (struct vgt_device *)dev;
+	info = vgt->hypervisor_data;
+
+	for(vcpu=0; vcpu < info->nr_vcpu; vcpu++){
+		if(info->evtchn_irq[vcpu] == irq)
+			break;
+	}
+	if (vcpu == info->nr_vcpu){
+		/*opps, irq is not the registered one*/
+		gvt_info("Received a IOREQ w/o vcpu target\n");
+		gvt_info("Possible a false request from event binding\n");
+		return IRQ_NONE;
+	}
+
+	vgt_raise_emulation_request(vgt, vcpu);
+
+	return IRQ_HANDLED;
+}
+
+static void xen_hvm_exit(struct vgt_device *vgt)
+{
+	struct gvt_hvm_info *info;
+	int vcpu;
+
+	info = vgt->hypervisor_data;
+
+	if (info == NULL)
+		return;
+
+	if (info->emulation_thread != NULL)
+		kthread_stop(info->emulation_thread);
+
+	if (!info->nr_vcpu || info->evtchn_irq == NULL)
+		goto out1;
+
+	if (info->iosrv_id != 0)
+		hvm_destroy_iorequest_server(vgt);
+
+	for (vcpu = 0; vcpu < info->nr_vcpu; vcpu++){
+		if(info->evtchn_irq[vcpu] >= 0)
+			unbind_from_irqhandler(info->evtchn_irq[vcpu], vgt);
+	}
+
+	if (info->iopage_vma != NULL)
+		xen_unmap_domain_mfn_range_in_kernel(info->iopage_vma, 1, vgt->vm_id);
+
+	kfree(info->evtchn_irq);
+
+out1:
+	vgt_vmem_destroy(vgt);
+	kfree(info);
+}
+
+static int xen_hvm_init(struct vgt_device *vgt)
+{
+	struct gvt_hvm_info *info;
+	int vcpu, irq, rc = 0;
+	struct task_struct *thread;
+	struct pgt_device *pdev = vgt->pdev;
+	struct pci_dev *pci_dev = pdev->dev_priv->dev->pdev;
+
+	info = kzalloc(sizeof(struct gvt_hvm_info), GFP_KERNEL);
+	if (info == NULL)
+		return -ENOMEM;
+
+	vgt->hypervisor_data = info;
+
+	info->iopage_vma = xen_map_iopage(vgt);
+	if (info->iopage_vma == NULL) {
+		printk(KERN_ERR "Failed to map HVM I/O page for VM%d\n", vgt->vm_id);
+		rc = -EFAULT;
+		goto err;
+	}
+	info->iopage = info->iopage_vma->addr;
+
+	init_waitqueue_head(&info->io_event_wq);
+
+	info->nr_vcpu = xen_get_nr_vcpu(vgt->vm_id);
+	ASSERT(info->nr_vcpu > 0);
+	ASSERT(info->nr_vcpu <= MAX_HVM_VCPUS_SUPPORTED);
+
+	info->evtchn_irq = kmalloc(info->nr_vcpu * sizeof(int), GFP_KERNEL);
+	if (info->evtchn_irq == NULL){
+		rc = -ENOMEM;
+		goto err;
+	}
+	for( vcpu = 0; vcpu < info->nr_vcpu; vcpu++ )
+		info->evtchn_irq[vcpu] = -1;
+
+	rc = hvm_map_pcidev_to_ioreq_server(vgt, PCI_BDF2(pci_dev->bus->number, pci_dev->devfn));
+	if (rc < 0)
+		goto err;
+	rc = hvm_toggle_iorequest_server(vgt, 1);
+	if (rc < 0)
+		goto err;
+
+	for (vcpu = 0; vcpu < info->nr_vcpu; vcpu++){
+		irq = bind_interdomain_evtchn_to_irqhandler( vgt->vm_id,
+				info->iopage->vcpu_ioreq[vcpu].vp_eport,
+				vgt_hvm_io_req_handler, 0,
+				"vgt", vgt );
+		if ( irq < 0 ){
+			rc = irq;
+			printk(KERN_ERR "Failed to bind event channle for vgt HVM IO handler, rc=%d\n", rc);
+			goto err;
+		}
+		info->evtchn_irq[vcpu] = irq;
+	}
+
+	thread = kthread_run(vgt_emulation_thread, vgt,
+			"vgt_emulation:%d", vgt->vm_id);
+	if(IS_ERR(thread))
+		goto err;
+	info->emulation_thread = thread;
+
+	return 0;
+
+err:
+	xen_hvm_exit(vgt);
+	return rc;
+}
+
+static void *xen_gpa_to_va(struct vgt_device *vgt, unsigned long gpa)
+{
+	unsigned long buck_index, buck_4k_index;
+	struct gvt_hvm_info *info = vgt->hypervisor_data;
+
+	if (!vgt->vm_id)
+		return (char*)xen_mfn_to_virt(gpa>>PAGE_SHIFT) + (gpa & (PAGE_SIZE-1));
+	/*
+	 * At the beginning of _hvm_mmio_emulation(), we already initialize
+	 * info->vmem_vma and info->vmem_vma_low_1mb.
+	 */
+	ASSERT(info->vmem_vma != NULL && info->vmem_vma_low_1mb != NULL);
+
+	/* handle the low 1MB memory */
+	if (gpa < VMEM_1MB) {
+		buck_index = gpa >> PAGE_SHIFT;
+		if (!info->vmem_vma_low_1mb[buck_index])
+			return NULL;
+
+		return (char*)(info->vmem_vma_low_1mb[buck_index]->addr) +
+			(gpa & ~PAGE_MASK);
+
+	}
+
+	/* handle the >1MB memory */
+	buck_index = gpa >> VMEM_BUCK_SHIFT;
+
+	if (!info->vmem_vma[buck_index]) {
+		buck_4k_index = gpa >> PAGE_SHIFT;
+		if (!info->vmem_vma_4k[buck_4k_index]) {
+			if (buck_4k_index > vgt->low_mem_max_gpfn)
+				gvt_err("GVT failed to map gpa=0x%lx?\n", gpa);
+			return NULL;
+		}
+
+		return (char*)(info->vmem_vma_4k[buck_4k_index]->addr) +
+			(gpa & ~PAGE_MASK);
+	}
+
+	return (char*)(info->vmem_vma[buck_index]->addr) +
+		(gpa & (VMEM_BUCK_SIZE -1));
+}
+
+static bool xen_read_va(struct vgt_device *vgt, void *va, void *val,
+		int len, int atomic)
+{
+	memcpy(val, va, len);
+
+	return true;
+}
+
+static bool xen_write_va(struct vgt_device *vgt, void *va, void *val,
+		int len, int atomic)
+{
+	memcpy(va, val, len);
+	return true;
+}
+
+static struct gvt_kernel_dm xengt_kdm = {
+	.name = "xengt_kdm",
+	.g2m_pfn = xen_g2m_pfn,
+	.pause_domain = xen_pause_domain,
+	.shutdown_domain = xen_shutdown_domain,
+	.map_mfn_to_gpfn = xen_map_mfn_to_gpfn,
+	.set_trap_area = xen_set_trap_area,
+	.set_wp_pages = xen_set_guest_page_writeprotection,
+	.unset_wp_pages = xen_clear_guest_page_writeprotection,
+	.detect_host = xen_detect_host,
+	.from_virt_to_mfn = xen_virt_to_mfn,
+	.from_mfn_to_virt = xen_mfn_to_virt,
+	.inject_msi = xen_inject_msi,
+	.hvm_init = xen_hvm_init,
+	.hvm_exit = xen_hvm_exit,
+	.gpa_to_va = xen_gpa_to_va,
+	.read_va = xen_read_va,
+	.write_va = xen_write_va,
+};
+EXPORT_SYMBOL(xengt_kdm);
+
+static int __init xengt_init(void)
+{
+       if (!xen_initial_domain())
+               return -EINVAL;
+       printk(KERN_INFO "xengt: loaded\n");
+       return 0;
+}
+
+static void __exit xengt_exit(void)
+{
+	printk(KERN_INFO "xengt: unloaded\n");
+}
+
+module_init(xengt_init);
+module_exit(xengt_exit);
diff --git a/include/xen/interface/hvm/hvm_op.h b/include/xen/interface/hvm/hvm_op.h
index 956a046..20577cc 100644
--- a/include/xen/interface/hvm/hvm_op.h
+++ b/include/xen/interface/hvm/hvm_op.h
@@ -21,6 +21,8 @@
 #ifndef __XEN_PUBLIC_HVM_HVM_OP_H__
 #define __XEN_PUBLIC_HVM_HVM_OP_H__
 
+#include <xen/interface/event_channel.h>
+
 /* Get/set subcommands: the second argument of the hypercall is a
  * pointer to a xen_hvm_param struct. */
 #define HVMOP_set_param           0
@@ -42,12 +44,41 @@ struct xen_hvm_pagetable_dying {
 };
 typedef struct xen_hvm_pagetable_dying xen_hvm_pagetable_dying_t;
 DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_pagetable_dying_t);
- 
+
+/* MSI injection for emulated devices */
+#define HVMOP_inject_msi         16
+struct xen_hvm_inject_msi {
+    /* Domain to be injected */
+    domid_t   domid;
+    /* Data -- lower 32 bits */
+    uint32_t  data;
+    /* Address (0xfeexxxxx) */
+    uint64_t  addr;
+};
+typedef struct xen_hvm_inject_msi xen_hvm_inject_msi_t;
+DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_inject_msi_t);
+
 enum hvmmem_type_t {
     HVMMEM_ram_rw,             /* Normal read/write guest RAM */
     HVMMEM_ram_ro,             /* Read-only; writes are discarded */
     HVMMEM_mmio_dm,            /* Reads and write go to the device model */
+    HVMMEM_mmio_write_dm       /* Read-only; writes go to the device model */
+};
+
+#define HVMOP_set_mem_type    8
+/* Notify that a region of memory is to be treated in a specific way. */
+struct xen_hvm_set_mem_type {
+        /* Domain to be updated. */
+        domid_t domid;
+        /* Memory type */
+        uint16_t hvmmem_type;
+        /* Number of pages. */
+        uint32_t nr;
+        /* First pfn. */
+        uint64_t first_pfn;
 };
+typedef struct xen_hvm_set_mem_type xen_hvm_set_mem_type_t;
+DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_set_mem_type_t);
 
 #define HVMOP_get_mem_type    15
 /* Return hvmmem_type_t for the specified pfn. */
@@ -62,4 +93,148 @@ struct xen_hvm_get_mem_type {
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_get_mem_type);
 
+#define HVMOP_vgt_wp_pages         27  /* writeprotection to guest pages */
+#define MAX_WP_BATCH_PAGES         128
+struct xen_hvm_vgt_wp_pages {
+	uint16_t domid;
+	uint16_t set;            /* 1: set WP, 0: remove WP */
+	uint16_t nr_pages;
+	unsigned long  wp_pages[MAX_WP_BATCH_PAGES];
+};
+typedef struct xen_hvm_vgt_wp_pages xen_hvm_vgt_wp_pages_t;
+
+/*
+ * IOREQ Servers
+ *
+ * The interface between an I/O emulator an Xen is called an IOREQ Server.
+ * A domain supports a single 'legacy' IOREQ Server which is instantiated if
+ * parameter...
+ *
+ * HVM_PARAM_IOREQ_PFN is read (to get the gmfn containing the synchronous
+ * ioreq structures), or...
+ * HVM_PARAM_BUFIOREQ_PFN is read (to get the gmfn containing the buffered
+ * ioreq ring), or...
+ * HVM_PARAM_BUFIOREQ_EVTCHN is read (to get the event channel that Xen uses
+ * to request buffered I/O emulation).
+ *
+ * The following hypercalls facilitate the creation of IOREQ Servers for
+ * 'secondary' emulators which are invoked to implement port I/O, memory, or
+ * PCI config space ranges which they explicitly register.
+ */
+typedef uint16_t ioservid_t;
+
+/*
+ * HVMOP_create_ioreq_server: Instantiate a new IOREQ Server for a secondary
+ *                            emulator servicing domain <domid>.
+ *
+ * The <id> handed back is unique for <domid>. If <handle_bufioreq> is zero
+ * the buffered ioreq ring will not be allocated and hence all emulation
+ * requestes to this server will be synchronous.
+ */
+#define HVMOP_create_ioreq_server 17
+struct xen_hvm_create_ioreq_server {
+    domid_t domid;           /* IN - domain to be serviced */
+    uint8_t handle_bufioreq; /* IN - should server handle buffered ioreqs */
+    ioservid_t id;           /* OUT - server id */
+};
+typedef struct xen_hvm_create_ioreq_server xen_hvm_create_ioreq_server_t;
+DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_create_ioreq_server_t);
+
+/*
+ * HVMOP_get_ioreq_server_info: Get all the information necessary to access
+ *                              IOREQ Server <id>.
+ *
+ * The emulator needs to map the synchronous ioreq structures and buffered
+ * ioreq ring (if it exists) that Xen uses to request emulation. These are
+ * hosted in domain <domid>'s gmfns <ioreq_pfn> and <bufioreq_pfn>
+ * respectively. In addition, if the IOREQ Server is handling buffered
+ * emulation requests, the emulator needs to bind to event channel
+ * <bufioreq_port> to listen for them. (The event channels used for
+ * synchronous emulation requests are specified in the per-CPU ioreq
+ * structures in <ioreq_pfn>).
+ * If the IOREQ Server is not handling buffered emulation requests then the
+ * values handed back in <bufioreq_pfn> and <bufioreq_port> will both be 0.
+ */
+#define HVMOP_get_ioreq_server_info 18
+struct xen_hvm_get_ioreq_server_info {
+    domid_t domid;                 /* IN - domain to be serviced */
+    ioservid_t id;                 /* IN - server id */
+    evtchn_port_t bufioreq_port;   /* OUT - buffered ioreq port */
+    uint64_t ioreq_pfn;    /* OUT - sync ioreq pfn */
+    uint64_t bufioreq_pfn; /* OUT - buffered ioreq pfn */
+};
+typedef struct xen_hvm_get_ioreq_server_info xen_hvm_get_ioreq_server_info_t;
+DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_get_ioreq_server_info_t);
+
+/*
+ * HVM_map_io_range_to_ioreq_server: Register an I/O range of domain <domid>
+ *                                   for emulation by the client of IOREQ
+ *                                   Server <id>
+ * HVM_unmap_io_range_from_ioreq_server: Deregister an I/O range of <domid>
+ *                                       for emulation by the client of IOREQ
+ *                                       Server <id>
+ *
+ * There are three types of I/O that can be emulated: port I/O, memory accesses
+ * and PCI config space accesses. The <type> field denotes which type of range
+ * the <start> and <end> (inclusive) fields are specifying.
+ * PCI config space ranges are specified by segment/bus/device/function values
+ * which should be encoded using the HVMOP_PCI_SBDF helper macro below.
+ *
+ * NOTE: unless an emulation request falls entirely within a range mapped
+ * by a secondary emulator, it will not be passed to that emulator.
+ */
+#define HVMOP_map_io_range_to_ioreq_server 19
+#define HVMOP_unmap_io_range_from_ioreq_server 20
+struct xen_hvm_io_range {
+    domid_t domid;               /* IN - domain to be serviced */
+    ioservid_t id;               /* IN - server id */
+    uint32_t type;               /* IN - type of range */
+# define HVMOP_IO_RANGE_PORT   0 /* I/O port range */
+# define HVMOP_IO_RANGE_MEMORY 1 /* MMIO range */
+# define HVMOP_IO_RANGE_PCI    2 /* PCI segment/bus/dev/func range */
+    uint64_t start, end; /* IN - inclusive start and end of range */
+};
+typedef struct xen_hvm_io_range xen_hvm_io_range_t;
+DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_io_range_t);
+
+#define HVMOP_PCI_SBDF(s,b,d,f)                 \
+       ((((s) & 0xffff) << 16) |                   \
+        (((b) & 0xff) << 8) |                      \
+        (((d) & 0x1f) << 3) |                      \
+        ((f) & 0x07))
+
+/*
+ * HVMOP_destroy_ioreq_server: Destroy the IOREQ Server <id> servicing domain
+ *                             <domid>.
+ *
+ * Any registered I/O ranges will be automatically deregistered.
+ */
+#define HVMOP_destroy_ioreq_server 21
+struct xen_hvm_destroy_ioreq_server {
+    domid_t domid; /* IN - domain to be serviced */
+    ioservid_t id; /* IN - server id */
+};
+typedef struct xen_hvm_destroy_ioreq_server xen_hvm_destroy_ioreq_server_t;
+DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_destroy_ioreq_server_t);
+
+
+/*
+ * HVMOP_set_ioreq_server_state: Enable or disable the IOREQ Server <id> servicing
+ *                               domain <domid>.
+ *
+ * The IOREQ Server will not be passed any emulation requests until it is in the
+ * enabled state.
+ * Note that the contents of the ioreq_pfn and bufioreq_fn (see
+ * HVMOP_get_ioreq_server_info) are not meaningful until the IOREQ Server is in
+ * the enabled state.
+ */
+#define HVMOP_set_ioreq_server_state 22
+struct xen_hvm_set_ioreq_server_state {
+    domid_t domid;   /* IN - domain to be serviced */
+    ioservid_t id;   /* IN - server id */
+    uint8_t enabled; /* IN - enabled? */
+};
+typedef struct xen_hvm_set_ioreq_server_state xen_hvm_set_ioreq_server_state_t;
+DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_set_ioreq_server_state_t);
+
 #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */
diff --git a/include/xen/interface/hvm/ioreq.h b/include/xen/interface/hvm/ioreq.h
new file mode 100644
index 0000000..6bbf4e4
--- /dev/null
+++ b/include/xen/interface/hvm/ioreq.h
@@ -0,0 +1,132 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef _IOREQ_H_
+#define _IOREQ_H_
+
+#define IOREQ_READ      1
+#define IOREQ_WRITE     0
+
+#define STATE_IOREQ_NONE        0
+#define STATE_IOREQ_READY       1
+#define STATE_IOREQ_INPROCESS   2
+#define STATE_IORESP_READY      3
+
+#define IOREQ_TYPE_PIO          0 /* pio */
+#define IOREQ_TYPE_COPY         1 /* mmio ops */
+#define IOREQ_TYPE_PCI_CONFIG   2
+#define IOREQ_TYPE_TIMEOFFSET   7
+#define IOREQ_TYPE_INVALIDATE   8 /* mapcache */
+
+/*
+ * VMExit dispatcher should cooperate with instruction decoder to
+ * prepare this structure and notify service OS and DM by sending
+ * virq
+ */
+struct ioreq {
+    uint64_t addr;          /* physical address */
+    uint64_t data;          /* data (or paddr of data) */
+    uint32_t count;         /* for rep prefixes */
+    uint32_t size;          /* size in bytes */
+    uint32_t vp_eport;      /* evtchn for notifications to/from device model */
+    uint16_t _pad0;
+    uint8_t state:4;
+    uint8_t data_is_ptr:1;  /* if 1, data above is the guest paddr
+                             * of the real data to use. */
+    uint8_t dir:1;          /* 1=read, 0=write */
+    uint8_t df:1;
+    uint8_t _pad1:1;
+    uint8_t type;           /* I/O type */
+};
+typedef struct ioreq ioreq_t;
+
+struct shared_iopage {
+    struct ioreq vcpu_ioreq[1];
+};
+typedef struct shared_iopage shared_iopage_t;
+
+struct buf_ioreq {
+    uint8_t  type;   /* I/O type                    */
+    uint8_t  pad:1;
+    uint8_t  dir:1;  /* 1=read, 0=write             */
+    uint8_t  size:2; /* 0=>1, 1=>2, 2=>4, 3=>8. If 8, use two buf_ioreqs */
+    uint32_t addr:20;/* physical address            */
+    uint32_t data;   /* data                        */
+};
+typedef struct buf_ioreq buf_ioreq_t;
+
+#define IOREQ_BUFFER_SLOT_NUM     511 /* 8 bytes each, plus 2 4-byte indexes */
+struct buffered_iopage {
+    unsigned int read_pointer;
+    unsigned int write_pointer;
+    buf_ioreq_t buf_ioreq[IOREQ_BUFFER_SLOT_NUM];
+}; /* NB. Size of this structure must be no greater than one page. */
+typedef struct buffered_iopage buffered_iopage_t;
+
+#if defined(__ia64__)
+struct pio_buffer {
+    uint32_t page_offset;
+    uint32_t pointer;
+    uint32_t data_end;
+    uint32_t buf_size;
+    void *opaque;
+};
+
+#define PIO_BUFFER_IDE_PRIMARY   0 /* I/O port = 0x1F0 */
+#define PIO_BUFFER_IDE_SECONDARY 1 /* I/O port = 0x170 */
+#define PIO_BUFFER_ENTRY_NUM     2
+struct buffered_piopage {
+    struct pio_buffer pio[PIO_BUFFER_ENTRY_NUM];
+    uint8_t buffer[1];
+};
+#endif /* defined(__ia64__) */
+
+/*
+ * ACPI Control/Event register locations. Location is controlled by a
+ * version number in HVM_PARAM_ACPI_IOPORTS_LOCATION.
+ */
+
+/* Version 0 (default): Traditional Xen locations. */
+#define ACPI_PM1A_EVT_BLK_ADDRESS_V0 0x1f40
+#define ACPI_PM1A_CNT_BLK_ADDRESS_V0 (ACPI_PM1A_EVT_BLK_ADDRESS_V0 + 0x04)
+#define ACPI_PM_TMR_BLK_ADDRESS_V0   (ACPI_PM1A_EVT_BLK_ADDRESS_V0 + 0x08)
+#define ACPI_GPE0_BLK_ADDRESS_V0     (ACPI_PM_TMR_BLK_ADDRESS_V0 + 0x20)
+#define ACPI_GPE0_BLK_LEN_V0         0x08
+
+/* Version 1: Locations preferred by modern Qemu. */
+#define ACPI_PM1A_EVT_BLK_ADDRESS_V1 0xb000
+#define ACPI_PM1A_CNT_BLK_ADDRESS_V1 (ACPI_PM1A_EVT_BLK_ADDRESS_V1 + 0x04)
+#define ACPI_PM_TMR_BLK_ADDRESS_V1   (ACPI_PM1A_EVT_BLK_ADDRESS_V1 + 0x08)
+#define ACPI_GPE0_BLK_ADDRESS_V1     0xafe0
+#define ACPI_GPE0_BLK_LEN_V1         0x04
+
+/* Compatibility definitions for the default location (version 0). */
+#define ACPI_PM1A_EVT_BLK_ADDRESS    ACPI_PM1A_EVT_BLK_ADDRESS_V0
+#define ACPI_PM1A_CNT_BLK_ADDRESS    ACPI_PM1A_CNT_BLK_ADDRESS_V0
+#define ACPI_PM_TMR_BLK_ADDRESS      ACPI_PM_TMR_BLK_ADDRESS_V0
+#define ACPI_GPE0_BLK_ADDRESS        ACPI_GPE0_BLK_ADDRESS_V0
+#define ACPI_GPE0_BLK_LEN            ACPI_GPE0_BLK_LEN_V0
+
+
+#endif /* _IOREQ_H_ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
index 2ecfe4f..92f18c5 100644
--- a/include/xen/interface/memory.h
+++ b/include/xen/interface/memory.h
@@ -9,6 +9,7 @@
 #ifndef __XEN_PUBLIC_MEMORY_H__
 #define __XEN_PUBLIC_MEMORY_H__
 
+#include <xen/interface/event_channel.h>
 #include <linux/spinlock.h>
 
 /*
@@ -141,6 +142,11 @@ struct xen_machphys_mfn_list {
 DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list);
 
 /*
+ * Returns the maximum GPFN in use by the guest, or -ve errcode on failure.
+ */
+#define XENMEM_maximum_gpfn         14
+
+/*
  * Returns the location in virtual address space of the machine_to_phys
  * mapping table. Architectures which do not have a m2p table, or which do not
  * map it by default into guest address space, do not implement this command.
@@ -263,4 +269,26 @@ struct xen_remove_from_physmap {
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
 
+/*
+ * Translate the given guest PFNs to MFNs
+ */
+#define XENMEM_get_mfn_from_pfn    25
+struct xen_get_mfn_from_pfn {
+    /*
+     * Pointer to buffer to fill with list of pfn.
+     * for IN, it contains the guest PFN that need to translated
+     * for OUT, it contains the translated MFN. or INVALID_MFN if no valid translation
+     */
+    GUEST_HANDLE(ulong) pfn_list;
+
+    /*
+     * IN: Size of the pfn_array.
+     */
+    unsigned int nr_pfns;
+
+    /* IN: which domain */
+    domid_t domid;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_get_mfn_from_pfn);
+
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index 78a38f1..c7e0f32 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -756,6 +756,112 @@ struct tmem_op {
 
 DEFINE_GUEST_HANDLE(u64);
 
+/* XEN_DOMCTL_getdomaininfo */
+struct xen_domctl_getdomaininfo {
+        /* OUT variables. */
+        domid_t  domain;              /* Also echoed in domctl.domain */
+        /* Domain is scheduled to die. */
+#define _XEN_DOMINF_dying     0
+#define XEN_DOMINF_dying      (1U<<_XEN_DOMINF_dying)
+        /* Domain is an HVM guest (as opposed to a PV guest). */
+#define _XEN_DOMINF_hvm_guest 1
+#define XEN_DOMINF_hvm_guest  (1U<<_XEN_DOMINF_hvm_guest)
+        /* The guest OS has shut down. */
+#define _XEN_DOMINF_shutdown  2
+#define XEN_DOMINF_shutdown   (1U<<_XEN_DOMINF_shutdown)
+        /* Currently paused by control software. */
+#define _XEN_DOMINF_paused    3
+#define XEN_DOMINF_paused     (1U<<_XEN_DOMINF_paused)
+        /* Currently blocked pending an event.     */
+#define _XEN_DOMINF_blocked   4
+#define XEN_DOMINF_blocked    (1U<<_XEN_DOMINF_blocked)
+        /* Domain is currently running.            */
+#define _XEN_DOMINF_running   5
+#define XEN_DOMINF_running    (1U<<_XEN_DOMINF_running)
+        /* Being debugged.  */
+#define _XEN_DOMINF_debugged  6
+#define XEN_DOMINF_debugged   (1U<<_XEN_DOMINF_debugged)
+        /* XEN_DOMINF_shutdown guest-supplied code.  */
+#define XEN_DOMINF_shutdownmask 255
+#define XEN_DOMINF_shutdownshift 16
+        uint32_t flags;              /* XEN_DOMINF_* */
+        aligned_u64 tot_pages;
+        aligned_u64 max_pages;
+        aligned_u64 outstanding_pages;
+        aligned_u64 shr_pages;
+        aligned_u64 paged_pages;
+        aligned_u64 shared_info_frame; /* GMFN of shared_info struct */
+        aligned_u64 cpu_time;
+        uint32_t nr_online_vcpus;    /* Number of VCPUs currently online. */
+        uint32_t max_vcpu_id;        /* Maximum VCPUID in use by this domain. */
+        uint32_t ssidref;
+        xen_domain_handle_t handle;
+        uint32_t cpupool;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getdomaininfo);
+
+#define XEN_DOMCTL_INTERFACE_VERSION 0x0000000a
+#define XEN_DOMCTL_pausedomain                    3
+#define XEN_DOMCTL_getdomaininfo                  5
+#define XEN_DOMCTL_memory_mapping                 39
+#define XEN_DOMCTL_iomem_permission               20
+
+
+#define XEN_DOMCTL_vgt_io_trap                    700
+
+#define MAX_VGT_IO_TRAP_INFO 4
+
+struct vgt_io_trap_info {
+        uint64_t s;
+        uint64_t e;
+};
+
+struct xen_domctl_vgt_io_trap {
+        uint32_t n_pio;
+        struct vgt_io_trap_info pio[MAX_VGT_IO_TRAP_INFO];
+
+        uint32_t n_mmio;
+        struct vgt_io_trap_info mmio[MAX_VGT_IO_TRAP_INFO];
+};
+
+/* Bind machine I/O address range -> HVM address range. */
+/* XEN_DOMCTL_memory_mapping */
+#define DPCI_ADD_MAPPING        1
+#define DPCI_REMOVE_MAPPING     0
+struct xen_domctl_memory_mapping {
+        aligned_u64 first_gfn; /* first page (hvm guest phys page) in range */
+        aligned_u64 first_mfn; /* first page (machine page) in range. */
+        aligned_u64 nr_mfns;   /* number of pages in range (>0) */
+        uint32_t add_mapping;  /* Add or remove mapping */
+        uint32_t padding;      /* padding for 64-bit aligned struct */
+};
+typedef struct xen_domctl_memory_mapping xen_domctl_memory_mapping_t;
+DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_memory_mapping_t);
+
+/* XEN_DOMCTL_iomem_permission */
+struct xen_domctl_iomem_permission {
+    aligned_u64 first_mfn;/* first page (physical page number) in range */
+    aligned_u64 nr_mfns;  /* number of pages in range (>0) */
+    uint8_t  allow_access;     /* allow (!0) or deny (0) access to range? */
+};
+typedef struct xen_domctl_iomem_permission xen_domctl_iomem_permission_t;
+DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_iomem_permission_t);
+
+struct xen_domctl {
+        uint32_t cmd;
+        uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
+        domid_t  domain;
+        union {
+                struct xen_domctl_getdomaininfo     getdomaininfo;
+                struct xen_domctl_vgt_io_trap       vgt_io_trap;
+                struct xen_domctl_memory_mapping    memory_mapping;
+                struct xen_domctl_iomem_permission      iomem_perm;
+                uint8_t                             pad[256];
+        }u;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_domctl);
+
+
 #else /* __ASSEMBLY__ */
 
 /* In assembly code we cannot use C numeric constant suffixes. */
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index 86abe07..dde9eb0 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -123,4 +123,9 @@ static inline void xen_preemptible_hcall_end(void)
 
 #endif /* CONFIG_PREEMPT */
 
+struct vm_struct * xen_remap_domain_mfn_range_in_kernel(unsigned long mfn,
+        int nr, unsigned domid);
+void xen_unmap_domain_mfn_range_in_kernel(struct vm_struct *area, int nr,
+                unsigned domid);
+
 #endif /* INCLUDE_XEN_OPS_H */
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 18/29] drm/i915: gvt: vGPU configuration emulation
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (16 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 17/29] gvt: Xen hypervisor GVT-g MPT module Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 19/29] drm/i915: gvt: vGPU OpRegion emulation Zhi Wang
                   ` (11 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This patch introduces the vGPU configuration space handlers built on the
generic MPT framework.

In vGPU configuration space emulation, GVT-g will:

- Adjust the trapped GPFN(Guest Page Frame Number) of virtual GEN PCI BAR 0,
when guest BIOS/OS modify the BAR address.

- Emulate OpRegion when guest BIOS configure the OpRegion 3 pages.

- Pass-through a part of aperture to guest accodint to the GVT resource allocator.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile    |   2 +-
 drivers/gpu/drm/i915/gvt/cfg_space.c | 177 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/cfg_space.h |  33 +++++++
 drivers/gpu/drm/i915/gvt/gvt.c       |   2 +
 drivers/gpu/drm/i915/gvt/gvt.h       |  10 ++
 drivers/gpu/drm/i915/gvt/reg.h       |  16 ++++
 drivers/gpu/drm/i915/gvt/utility.c   |  91 ++++++++++++++++++
 7 files changed, 330 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/cfg_space.c
 create mode 100644 drivers/gpu/drm/i915/gvt/cfg_space.h
 create mode 100644 drivers/gpu/drm/i915/gvt/utility.c

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index 360539c..a821d3d 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,5 +1,5 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
-		trace_points.o interrupt.o gtt.o fb_decoder.o
+		trace_points.o interrupt.o gtt.o cfg_space.o utility.o fb_decoder.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c
new file mode 100644
index 0000000..bda0e9d
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/cfg_space.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+static bool cfg_sci_read(struct vgt_device *vgt, unsigned int offset,
+	void *p_data, int bytes)
+{
+	gvt_info("[vgt %d] Read SCI Trigger Register, bytes=%d value=0x%x",
+			vgt->id, bytes, *(u16*)p_data);
+
+	return true;
+}
+
+bool gvt_emulate_cfg_read(struct vgt_device *vgt, unsigned int offset, void *p_data, int bytes)
+{
+	ASSERT((offset + bytes) <= GVT_CFG_SPACE_SZ);
+	memcpy(p_data, &vgt->state.cfg.space[offset], bytes);
+
+	/* TODO: hooks */
+	offset &= ~3;
+	switch (offset) {
+		case 0:
+		case 4:
+			break;
+		case GVT_REG_CFG_SWSCI_TRIGGER:
+			cfg_sci_read(vgt, offset, p_data, bytes);
+			break;
+		default:
+			break;
+	}
+	return true;
+}
+
+bool gvt_emulate_cfg_write(struct vgt_device *vgt, unsigned int off,
+	void *p_data, int bytes)
+{
+	char *cfg_space = &vgt->state.cfg.space[0];
+	u32 *cfg_reg, new;
+	u64 size;
+	u8 old_cmd, cmd_changed; /* we don't care the high 8 bits */
+	bool rc = true;
+	u32 low_mem_max_gpfn;
+
+	ASSERT ((off + bytes) <= GVT_CFG_SPACE_SZ);
+	cfg_reg = (u32*)(cfg_space + (off & ~3));
+	switch (off & ~3) {
+		case GVT_REG_CFG_VENDOR_ID:
+			low_mem_max_gpfn = *(u32 *)p_data;
+			gvt_info("low_mem_max_gpfn: 0x%x", low_mem_max_gpfn);
+			if (bytes != 4 ||
+				low_mem_max_gpfn >= (1UL << (32-PAGE_SHIFT))) {
+				gvt_err("invalid low_mem_max_gpfn!");
+				break;
+			}
+			if (vgt->low_mem_max_gpfn == 0)
+				vgt->low_mem_max_gpfn = low_mem_max_gpfn;
+			break;
+
+		case GVT_REG_CFG_COMMAND:
+			old_cmd = vgt->state.cfg.space[off];
+			cmd_changed = old_cmd ^ (*(u8*)p_data);
+			memcpy (&vgt->state.cfg.space[off], p_data, bytes);
+			if (cmd_changed & _REGBIT_CFG_COMMAND_MEMORY) {
+				if (old_cmd & _REGBIT_CFG_COMMAND_MEMORY) {
+					 gvt_hvm_map_aperture(vgt, 0);
+				} else {
+					if(!vgt->state.cfg.bar_mapped[1]) {
+						gvt_hvm_map_aperture(vgt, 1);
+						gvt_hvm_set_trap_area(vgt, 1);
+					}
+				}
+			} else {
+				gvt_dbg(GVT_DBG_CORE, "need to trap the PIO BAR? "
+					"old_cmd=0x%x, cmd_changed=%0x",
+					old_cmd, cmd_changed);
+			}
+			break;
+		case GVT_REG_CFG_SPACE_BAR0:	/* GTTMMIO */
+		case GVT_REG_CFG_SPACE_BAR1:	/* GMADR */
+		case GVT_REG_CFG_SPACE_BAR2:	/* IO */
+			ASSERT((bytes == 4) && (off & 3) == 0);
+			new = *(u32 *)p_data;
+			gvt_info("Programming bar 0x%x with 0x%x", off, new);
+			size = vgt->state.cfg.bar_size[(off - GVT_REG_CFG_SPACE_BAR0)/8];
+			if (new == 0xFFFFFFFF) {
+				/*
+				 * Power-up software can determine how much address
+				 * space the device requires by writing a value of
+				 * all 1's to the register and then reading the value
+				 * back. The device will return 0's in all don't-care
+				 * address bits.
+				 */
+				new = new & ~(size-1);
+				if ((off & ~3) == GVT_REG_CFG_SPACE_BAR1)
+					gvt_hvm_map_aperture(vgt, 0);
+				if ((off & ~3) == GVT_REG_CFG_SPACE_BAR0)
+					gvt_hvm_set_trap_area(vgt, 0);
+				gvt_pci_bar_write_32(vgt, off, new);
+			} else {
+				if ((off & ~3) == GVT_REG_CFG_SPACE_BAR1)
+					gvt_hvm_map_aperture(vgt, 0);
+				if ((off & ~3) == GVT_REG_CFG_SPACE_BAR0)
+					gvt_hvm_set_trap_area(vgt, 0);
+				gvt_pci_bar_write_32(vgt, off, new);
+				if ((off & ~3) == GVT_REG_CFG_SPACE_BAR1)
+					gvt_hvm_map_aperture(vgt, 1);
+				if ((off & ~3) == GVT_REG_CFG_SPACE_BAR0)
+					gvt_hvm_set_trap_area(vgt, 1);
+			}
+			break;
+
+		case GVT_REG_CFG_SPACE_MSAC:
+			gvt_info("Guest write MSAC %x, %d: Not supported yet",
+					*(char *)p_data, bytes);
+			break;
+
+		case GVT_REG_CFG_SPACE_BAR1+4:
+		case GVT_REG_CFG_SPACE_BAR0+4:
+		case GVT_REG_CFG_SPACE_BAR2+4:
+			ASSERT((bytes == 4) && (off & 3) == 0);
+			new = *(u32 *)p_data;
+			gvt_info("Programming bar 0x%x with 0x%x", off, new);
+			size = vgt->state.cfg.bar_size[(off - (GVT_REG_CFG_SPACE_BAR0 + 4))/8];
+			/* for 32bit mode bar it returns all-0 in upper 32 bit, for 64bit
+			 * mode bar it will calculate the size with lower 32bit and return
+			 * the corresponding value
+			 */
+			if (new == 0xFFFFFFFF) {
+				if (GVT_GET_BITS(*(cfg_space + off - 4), 2, 1) == 2)
+					new &= ~(size-1) >> 32;
+				else
+					new = 0;
+				*cfg_reg = new;
+			} else {
+				if ((off & ~3) == GVT_REG_CFG_SPACE_BAR1 + 4)
+					gvt_hvm_map_aperture(vgt, 0);
+				if ((off & ~3) == GVT_REG_CFG_SPACE_BAR0 + 4)
+					gvt_hvm_set_trap_area(vgt, 0);
+				*cfg_reg = new;
+				if ((off & ~3) == GVT_REG_CFG_SPACE_BAR1 + 4)
+					gvt_hvm_map_aperture(vgt, 1);
+				if ((off & ~3) == GVT_REG_CFG_SPACE_BAR0 + 4)
+					gvt_hvm_set_trap_area(vgt, 1);
+			}
+			break;
+
+		case 0x90:
+		case 0x94:
+		case 0x98:
+			gvt_info("write to MSI capa(%x) with val (%x)", off, *(u32 *)p_data);
+		default:
+			memcpy(&vgt->state.cfg.space[off], p_data, bytes);
+			break;
+	}
+	return rc;
+}
diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.h b/drivers/gpu/drm/i915/gvt/cfg_space.h
new file mode 100644
index 0000000..6d9301b
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/cfg_space.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef __GVT_CFG_SPACE_H__
+#define __GVT_CFG_SPACE_H__
+
+bool gvt_emulate_cfg_read(struct vgt_device *vgt,
+	unsigned int offset, void *p_data, int bytes);
+
+bool gvt_emulate_cfg_write(struct vgt_device *vgt,
+	unsigned int offset, void *p_data, int bytes);
+
+#endif
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index 28a51d9..32853b2 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -36,6 +36,8 @@ extern struct gvt_kernel_dm kvmgt_kdm;
 static struct gvt_io_emulation_ops default_io_emulation_ops = {
 	.emulate_mmio_read = gvt_emulate_mmio_read,
 	.emulate_mmio_write = gvt_emulate_mmio_write,
+	.emulate_cfg_read = gvt_emulate_cfg_read,
+	.emulate_cfg_write = gvt_emulate_cfg_write,
 };
 
 unsigned int pa_to_mmio_offset(struct vgt_device *vgt,
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 83f90a2..244d8764 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -36,6 +36,7 @@
 #include "interrupt.h"
 #include "perf.h"
 #include "gtt.h"
+#include "cfg_space.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -99,6 +100,7 @@ struct gvt_virtual_cfg_state {
 	unsigned char space[GVT_CFG_SPACE_SZ];
 	bool bar_mapped[GVT_BAR_NUM];
 	u64 bar_size[GVT_BAR_NUM];
+	void *opregion_va;
 };
 
 struct gvt_virtual_gm_state {
@@ -600,6 +602,14 @@ static inline u32 h2g_gtt_index(struct vgt_device *vgt, uint32_t h_index)
 	return (u32)(h2g_gm(vgt, h_addr) >> GTT_PAGE_SHIFT);
 }
 
+/* get the bits high:low of the data, high and low is starting from zero*/
+#define GVT_GET_BITS(data, high, low)   (((data) & ((1 << ((high) + 1)) - 1)) >> (low))
+/* get one bit of the data, bit is starting from zeor */
+#define GVT_GET_BIT(data, bit)          GVT_GET_BITS(data, bit, bit)
+
+int gvt_hvm_map_aperture(struct vgt_device *vgt, int map);
+int gvt_hvm_set_trap_area(struct vgt_device *vgt, int map);
+
 #include "mpt.h"
 
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
index 0e28a71..3fb4495 100644
--- a/drivers/gpu/drm/i915/gvt/reg.h
+++ b/drivers/gpu/drm/i915/gvt/reg.h
@@ -48,6 +48,22 @@
 #define _REGBIT_CFG_SWSCI_SCI_TRIGGER           1
 #define GVT_REG_CFG_OPREGION                    0xFC
 
+#define GVT_OPREGION_PAGES                      2
+#define GVT_OPREGION_PORDER                     1
+#define GVT_OPREGION_SIZE                       (8 * 1024)
+#define GVT_OPREGION_REG_CLID                   0x1AC
+#define GVT_OPREGION_REG_SCIC                   0x200
+#define _REGBIT_OPREGION_SCIC_FUNC_MASK         0x1E
+#define _REGBIT_OPREGION_SCIC_FUNC_SHIFT        1
+#define _REGBIT_OPREGION_SCIC_SUBFUNC_MASK      0xFF00
+#define _REGBIT_OPREGION_SCIC_SUBFUNC_SHIFT     8
+#define _REGBIT_OPREGION_SCIC_EXIT_MASK         0xE0
+#define GVT_OPREGION_SCIC_F_GETBIOSDATA         4
+#define GVT_OPREGION_SCIC_F_GETBIOSCALLBACKS    6
+#define GVT_OPREGION_SCIC_SF_SUPPRTEDCALLS      0
+#define GVT_OPREGION_SCIC_SF_REQEUSTEDCALLBACKS 1
+#define GVT_OPREGION_REG_PARM			0x204
+
 #define _REG_GMCH_CONTROL               0x50
 #define    _REGBIT_BDW_GMCH_GMS_SHIFT   8
 #define    _REGBIT_BDW_GMCH_GMS_MASK    0xff
diff --git a/drivers/gpu/drm/i915/gvt/utility.c b/drivers/gpu/drm/i915/gvt/utility.c
new file mode 100644
index 0000000..e5e5183
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/utility.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+int gvt_hvm_map_aperture(struct vgt_device *vgt, int map)
+{
+	char *cfg_space = &vgt->state.cfg.space[0];
+	uint64_t bar_s;
+	int r, nr_mfns;
+	unsigned long first_gfn, first_mfn;
+
+	if (!gvt_pci_mmio_is_enabled(vgt))
+		return 0;
+
+	/* guarantee the sequence of map -> unmap -> map -> unmap */
+	if (map == vgt->state.cfg.bar_mapped[1])
+		return 0;
+
+	cfg_space += GVT_REG_CFG_SPACE_BAR1;	/* APERTUR */
+	if (GVT_GET_BITS(*cfg_space, 2, 1) == 2){
+		/* 64 bits MMIO bar */
+		bar_s = * (uint64_t *) cfg_space;
+	} else {
+		/* 32 bits MMIO bar */
+		bar_s = * (uint32_t*) cfg_space;
+	}
+
+	first_gfn = (bar_s + gvt_aperture_offset(vgt)) >> PAGE_SHIFT;
+	first_mfn = gvt_aperture_base(vgt) >> PAGE_SHIFT;
+	nr_mfns = gvt_aperture_sz(vgt) >> PAGE_SHIFT;
+
+	printk("%s: domid=%d gfn_s=0x%lx mfn_s=0x%lx nr_mfns=0x%x\n", map==0? "remove_map":"add_map",
+		vgt->vm_id, first_gfn, first_mfn, nr_mfns);
+
+	r = hypervisor_map_mfn_to_gpfn(vgt, first_gfn, first_mfn,
+		nr_mfns, map, GVT_MAP_APERTURE);
+
+	if (r != 0)
+		printk(KERN_ERR "gvt_hvm_map_aperture fail with %d!\n", r);
+	else
+		vgt->state.cfg.bar_mapped[1] = map;
+
+	return r;
+}
+
+/*
+ * Zap the GTTMMIO bar area for vGT trap and emulation.
+ */
+int gvt_hvm_set_trap_area(struct vgt_device *vgt, int map)
+{
+	char *cfg_space = &vgt->state.cfg.space[0];
+	uint64_t bar_s, bar_e;
+
+	if (!gvt_pci_mmio_is_enabled(vgt))
+		return 0;
+
+	cfg_space += GVT_REG_CFG_SPACE_BAR0;
+	if (GVT_GET_BITS(*cfg_space, 2, 1) == 2) {
+		/* 64 bits MMIO bar */
+		bar_s = * (uint64_t *) cfg_space;
+	} else {
+		/* 32 bits MMIO bar */
+		bar_s = * (uint32_t*) cfg_space;
+	}
+
+	bar_s &= ~0xF; /* clear the LSB 4 bits */
+	bar_e = bar_s + vgt->state.cfg.bar_size[0] - 1;
+
+	return hypervisor_set_trap_area(vgt, bar_s, bar_e, map);
+}
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 19/29] drm/i915: gvt: vGPU OpRegion emulation
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (17 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 18/29] drm/i915: gvt: vGPU configuration emulation Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 20/29] drm/i915: gvt: vGPU framebuffer format decoder Zhi Wang
                   ` (10 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This patch introduces the vGPU OpRegion emulation routines based on the
MPT services and GVT-g CFG/MMIO emulation framework to support guest OpRegion
facilities.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile    |   2 +-
 drivers/gpu/drm/i915/gvt/cfg_space.c |  13 ++
 drivers/gpu/drm/i915/gvt/gvt.c       |   4 +
 drivers/gpu/drm/i915/gvt/gvt.h       |  12 +-
 drivers/gpu/drm/i915/gvt/instance.c  |   6 +
 drivers/gpu/drm/i915/gvt/opregion.c  | 314 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/opregion.h  |  34 ++++
 7 files changed, 383 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/opregion.c
 create mode 100644 drivers/gpu/drm/i915/gvt/opregion.h

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index a821d3d..8f59bbc 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,5 +1,5 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
-		trace_points.o interrupt.o gtt.o cfg_space.o utility.o fb_decoder.o
+		trace_points.o interrupt.o gtt.o cfg_space.o opregion.o utility.o fb_decoder.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c
index bda0e9d..ab351e0 100644
--- a/drivers/gpu/drm/i915/gvt/cfg_space.c
+++ b/drivers/gpu/drm/i915/gvt/cfg_space.c
@@ -135,6 +135,19 @@ bool gvt_emulate_cfg_write(struct vgt_device *vgt, unsigned int off,
 					*(char *)p_data, bytes);
 			break;
 
+		case GVT_REG_CFG_SWSCI_TRIGGER:
+			new = *(u32 *)p_data;
+			gvt_emulate_opregion_request(vgt, new);
+			break;
+
+		case GVT_REG_CFG_OPREGION:
+			new = *(u32 *)p_data;
+			if (!gvt_init_instance_opregion(vgt, new))
+				return false;
+
+			memcpy(&vgt->state.cfg.space[off], p_data, bytes);
+			break;
+
 		case GVT_REG_CFG_SPACE_BAR1+4:
 		case GVT_REG_CFG_SPACE_BAR0+4:
 		case GVT_REG_CFG_SPACE_BAR2+4:
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index 32853b2..63eb02c 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -263,6 +263,7 @@ static void clean_pgt_device(struct pgt_device *pdev)
 	gvt_clean_gtt(pdev);
 	gvt_irq_exit(pdev);
 	gvt_clean_mmio_emulation_state(pdev);
+	gvt_clean_opregion(pdev);
 	clean_initial_mmio_state(pdev);
 	gvt_clean_resource_allocator(pdev);
 }
@@ -277,6 +278,9 @@ static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *de
 	if (!init_initial_mmio_state(pdev))
 		goto err;
 
+	if (!gvt_init_opregion(pdev))
+		goto err;
+
 	gvt_init_resource_allocator(pdev);
 
 	if (!gvt_setup_mmio_emulation_state(pdev))
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 244d8764..cf88bd6 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -37,6 +37,7 @@
 #include "perf.h"
 #include "gtt.h"
 #include "cfg_space.h"
+#include "opregion.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -100,7 +101,12 @@ struct gvt_virtual_cfg_state {
 	unsigned char space[GVT_CFG_SPACE_SZ];
 	bool bar_mapped[GVT_BAR_NUM];
 	u64 bar_size[GVT_BAR_NUM];
-	void *opregion_va;
+};
+
+struct gvt_virtual_opregion_state {
+	void *va;
+	u64 gfn[GVT_OPREGION_PAGES];
+	struct page *pages[GVT_OPREGION_PAGES];
 };
 
 struct gvt_virtual_gm_state {
@@ -119,6 +125,7 @@ struct gvt_virtual_device_state {
 	struct gvt_virtual_gm_state gm;
 	struct gvt_virtual_mmio_state mmio;
 	struct gvt_virtual_cfg_state cfg;
+	struct gvt_virtual_opregion_state opregion;
 };
 
 struct vgt_device {
@@ -161,6 +168,9 @@ struct pgt_device {
 	u32 mmio_size;
 	u32 reg_num;
 
+	void *opregion_va;
+	u32 opregion_pa;
+
 	wait_queue_head_t service_thread_wq;
 	struct task_struct *service_thread;
 	unsigned long service_request;
diff --git a/drivers/gpu/drm/i915/gvt/instance.c b/drivers/gpu/drm/i915/gvt/instance.c
index 1540661..91f52c6 100644
--- a/drivers/gpu/drm/i915/gvt/instance.c
+++ b/drivers/gpu/drm/i915/gvt/instance.c
@@ -165,6 +165,7 @@ static void destroy_virtual_device_state(struct vgt_device *vgt)
 	gvt_clean_vgtt(vgt);
 	destroy_virtual_mmio_state(vgt);
 	destroy_virtual_gm_state(vgt);
+	gvt_clean_instance_opregion(vgt);
 }
 
 static bool create_virtual_device_state(struct vgt_device *vgt,
@@ -199,6 +200,7 @@ void gvt_destroy_instance(struct vgt_device *vgt)
 struct vgt_device *gvt_create_instance(struct pgt_device *pdev,
 		struct gvt_instance_info *info)
 {
+	struct gvt_host *host = &gvt_host;
 	struct vgt_device *vgt = NULL;
 	int id;
 
@@ -232,6 +234,10 @@ struct vgt_device *gvt_create_instance(struct pgt_device *pdev,
 	if (hypervisor_hvm_init(vgt) < 0)
 		goto err;
 
+	if (host->hypervisor_type == GVT_HYPERVISOR_TYPE_KVM)
+		if (!gvt_init_instance_opregion(vgt, 0))
+			goto err;
+
 	gvt_set_instance_online(vgt);
 
 	return vgt;
diff --git a/drivers/gpu/drm/i915/gvt/opregion.c b/drivers/gpu/drm/i915/gvt/opregion.c
new file mode 100644
index 0000000..0640918
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/opregion.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright(c) 2011-2016 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/acpi.h>
+
+#include "gvt.h"
+
+static bool init_virtual_opregion(struct vgt_device *vgt, u64 gpa)
+{
+	struct gvt_virtual_opregion_state *opregion = &vgt->state.opregion;
+	void *host_va = vgt->pdev->opregion_va;
+	u8 *buf;
+	int i;
+
+	if (opregion->va) {
+		gvt_err("[vgt %d] is trying to init opregion multiple times",
+				vgt->id);
+		return false;
+	}
+
+	opregion->va = (void *)__get_free_pages(GFP_ATOMIC |
+			GFP_DMA32 | __GFP_ZERO,
+			GVT_OPREGION_PORDER);
+
+	if (!opregion->va) {
+		gvt_err("fail to allocate memory for opregion pages");
+		return false;
+	}
+
+	memcpy_fromio(opregion->va, host_va, GVT_OPREGION_SIZE);
+
+	for (i = 0; i < GVT_OPREGION_PAGES; i++)
+		opregion->gfn[i] = (gpa >> PAGE_SHIFT) + i;
+
+	/* for unknown reason, the value in LID field is incorrect
+	 * which block the windows guest, so workaround it by force
+	 * setting it to "OPEN"
+	 */
+	buf = (u8 *)opregion->va;
+	buf[GVT_OPREGION_REG_CLID] = 0x3;
+
+	return true;
+}
+
+static bool map_virtual_opregion(struct vgt_device *vgt, int map)
+{
+	struct gvt_virtual_opregion_state *opregion = &vgt->state.opregion;
+	int r;
+	int i;
+
+	for (i = 0; i < GVT_OPREGION_PAGES; i++) {
+		r = hypervisor_map_mfn_to_gpfn(vgt,
+				opregion->gfn[i],
+				hypervisor_virt_to_mfn(opregion->va + i * PAGE_SIZE),
+				1,
+				map,
+				GVT_MAP_OPREGION);
+		if (r != 0) {
+			gvt_err("hypervisor_map_mfn_to_gpfn fail with %d!\n", r);
+			return false;
+		}
+	}
+	return true;
+}
+
+void gvt_clean_instance_opregion(struct vgt_device *vgt)
+{
+	struct gvt_host *host = &gvt_host;
+	struct gvt_virtual_opregion_state *opregion = &vgt->state.opregion;
+	int i;
+
+	gvt_dbg_core("clean instance opregion, id %d", vgt->id);
+
+	if (!opregion->va)
+		return;
+
+	if (host->hypervisor_type == GVT_HYPERVISOR_TYPE_KVM) {
+		vunmap(opregion->va);
+		for (i = 0; i < GVT_OPREGION_PAGES; i++) {
+			if (opregion->pages[i]) {
+				put_page(opregion->pages[i]);
+				opregion->pages[i] = NULL;
+			}
+		}
+	} else {
+		map_virtual_opregion(vgt, 0);
+		free_pages((unsigned long)opregion->va,
+				GVT_OPREGION_PORDER);
+	}
+
+	opregion->va = NULL;
+}
+
+bool gvt_init_instance_opregion(struct vgt_device *vgt, u64 gpa)
+{
+	struct gvt_host *host = &gvt_host;
+
+	gvt_dbg_core("init instance opregion, id %d", vgt->id);
+
+	if (host->hypervisor_type == GVT_HYPERVISOR_TYPE_XEN) {
+		gvt_dbg_core("emulate opregion from kernel");
+
+		if (!init_virtual_opregion(vgt, gpa))
+			return false;
+
+		if (!map_virtual_opregion(vgt, 1))
+			return false;
+	} else {
+		gvt_dbg_core("emulate opregion from userspace");
+
+		/* If opregion pages are not allocated from host kenrel, most of
+		 * the params are meaningless */
+		hypervisor_map_mfn_to_gpfn(vgt,
+				0, //not used
+				0, //not used
+				2, //not used
+				1,
+				GVT_MAP_OPREGION);
+	}
+
+	return true;
+}
+
+void gvt_clean_opregion(struct pgt_device *pdev)
+{
+	if (pdev->opregion_va) {
+		iounmap(pdev->opregion_va);
+		pdev->opregion_va = NULL;
+	}
+}
+
+bool gvt_init_opregion(struct pgt_device *pdev)
+{
+	gvt_dbg_core("init host opregion");
+
+	pci_read_config_dword(pdev->dev_priv->dev->pdev, GVT_REG_CFG_OPREGION,
+			&pdev->opregion_pa);
+
+	pdev->opregion_va = acpi_os_ioremap(pdev->opregion_pa,
+			GVT_OPREGION_SIZE);
+
+	if (!pdev->opregion_va) {
+		gvt_err("fail to map host opregion");
+		return false;
+	}
+	return true;
+}
+
+#define GVT_OPREGION_FUNC(scic)						\
+	({								\
+	 u32 __ret;						\
+	 __ret = (scic & _REGBIT_OPREGION_SCIC_FUNC_MASK) >>	\
+	 _REGBIT_OPREGION_SCIC_FUNC_SHIFT;			\
+	 __ret;							\
+	 })
+
+#define GVT_OPREGION_SUBFUNC(scic)					\
+	({								\
+	 u32 __ret;						\
+	 __ret = (scic & _REGBIT_OPREGION_SCIC_SUBFUNC_MASK) >>	\
+	 _REGBIT_OPREGION_SCIC_SUBFUNC_SHIFT;		\
+	 __ret;							\
+	 })
+
+static const char *opregion_func_name(u32 func)
+{
+	const char *name = NULL;
+
+	switch (func) {
+		case 0 ... 3:
+		case 5:
+		case 7 ... 15:
+			name = "Reserved";
+			break;
+
+		case 4:
+			name = "Get BIOS Data";
+			break;
+
+		case 6:
+			name = "System BIOS Callbacks";
+			break;
+
+		default:
+			name = "Unknown";
+			break;
+	}
+	return name;
+}
+
+static const char *opregion_subfunc_name(u32 subfunc)
+{
+	const char *name = NULL;
+	switch (subfunc) {
+		case 0:
+			name = "Supported Calls";
+			break;
+
+		case 1:
+			name = "Requested Callbacks";
+			break;
+
+		case 2 ... 3:
+		case 8 ... 9:
+			name = "Reserved";
+			break;
+
+		case 5:
+			name = "Boot Display";
+			break;
+
+		case 6:
+			name = "TV-Standard/Video-Connector";
+			break;
+
+		case 7:
+			name = "Internal Graphics";
+			break;
+
+		case 10:
+			name = "Spread Spectrum Clocks";
+			break;
+
+		case 11:
+			name = "Get AKSV";
+			break;
+
+		default:
+			name = "Unknown";
+			break;
+	}
+	return name;
+};
+
+/* Only allowing capability queries */
+static bool opregion_is_capability_get(u32 scic)
+{
+	u32 func, subfunc;
+
+	func = GVT_OPREGION_FUNC(scic);
+	subfunc = GVT_OPREGION_SUBFUNC(scic);
+
+	if ((func == GVT_OPREGION_SCIC_F_GETBIOSDATA &&
+				subfunc == GVT_OPREGION_SCIC_SF_SUPPRTEDCALLS) ||
+			(func == GVT_OPREGION_SCIC_F_GETBIOSDATA &&
+			 subfunc == GVT_OPREGION_SCIC_SF_REQEUSTEDCALLBACKS) ||
+			(func == GVT_OPREGION_SCIC_F_GETBIOSCALLBACKS &&
+			 subfunc == GVT_OPREGION_SCIC_SF_SUPPRTEDCALLS)) {
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * emulate multiple capability query requests
+ */
+void gvt_emulate_opregion_request(struct vgt_device *vgt, u32 swsci)
+{
+	struct gvt_virtual_opregion_state *opregion = &vgt->state.opregion;
+	u32 *scic, *parm;
+	u32 func, subfunc;
+	scic = opregion->va + GVT_OPREGION_REG_SCIC;
+	parm = opregion->va + GVT_OPREGION_REG_PARM;
+
+	if (!(swsci & _REGBIT_CFG_SWSCI_SCI_SELECT)) {
+		gvt_err("[vgt %d] requesting SMI service\n", vgt->id);
+		return;
+	}
+	/* ignore non 0->1 trasitions */
+	if ((vgt->state.cfg.space[GVT_REG_CFG_SWSCI_TRIGGER] &
+				_REGBIT_CFG_SWSCI_SCI_TRIGGER) ||
+			!(swsci & _REGBIT_CFG_SWSCI_SCI_TRIGGER)) {
+		return;
+	}
+
+	func = GVT_OPREGION_FUNC(*scic);
+	subfunc = GVT_OPREGION_SUBFUNC(*scic);
+	if (!opregion_is_capability_get(*scic)) {
+		gvt_err("[vgt %d] requesting runtime service: func \"%s\", subfunc \"%s\"\n",
+				vgt->id,
+				opregion_func_name(func),
+				opregion_subfunc_name(subfunc));
+		/*
+		 * emulate exit status of function call, '0' means
+		 * "failure, generic, unsupported or unkown cause"
+		 */
+		*scic &= ~_REGBIT_OPREGION_SCIC_EXIT_MASK;
+		return;
+	}
+
+	*scic = 0;
+	*parm = 0;
+}
diff --git a/drivers/gpu/drm/i915/gvt/opregion.h b/drivers/gpu/drm/i915/gvt/opregion.h
new file mode 100644
index 0000000..02d80c3
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/opregion.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef __GVT_OPREGION_H__
+#define __GVT_OPREGION_H__
+
+void gvt_clean_instance_opregion(struct vgt_device *vgt);
+bool gvt_init_instance_opregion(struct vgt_device *vgt, u64 gpa);
+void gvt_clean_opregion(struct pgt_device *pdev);
+bool gvt_init_opregion(struct pgt_device *pdev);
+
+void gvt_emulate_opregion_request(struct vgt_device *vgt, u32 swsci);
+
+#endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 20/29] drm/i915: gvt: vGPU framebuffer format decoder
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (18 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 19/29] drm/i915: gvt: vGPU OpRegion emulation Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 21/29] drm/i915: gvt: vGPU MMIO register emulation Zhi Wang
                   ` (9 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

From: Niu Bing <bing.niu@intel.com>

GVT-g supports an indirect display mode by mapping guest display framebuffer
into host graphics memory space as a GEM object, so that host windows system
/ GL can easily manipulate it like a common GEM object.

For example, use an EGL extension to wrap a guest framebuffer GEM object into
an EGL image, or just use i915 MMAP_GTT ioctl to map it into host aperture,
so that userspace application can easily use them.

To create this special GEM object, GVT-g has to know the surface format of
guest framebuffer, like RGB/NV12, stride, tiling format. vGPU framebuffer
format decoder will extract these information from guest virtual plane
registers and expose them to GVT GEM object logics.

Signed-off-by: Bing Niu <bing.niu@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile     |   3 +-
 drivers/gpu/drm/i915/gvt/fb_decoder.c | 295 ++++++++++++++++++++++++-
 drivers/gpu/drm/i915/gvt/gvt.h        |   1 +
 drivers/gpu/drm/i915/gvt/reg.h        | 404 ++++++++++++++++++++++++++++++++++
 4 files changed, 700 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index 8f59bbc..b0a3a1a 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,5 +1,6 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
-		trace_points.o interrupt.o gtt.o cfg_space.o opregion.o utility.o fb_decoder.o
+		trace_points.o interrupt.o gtt.o cfg_space.o opregion.o utility.o \
+		fb_decoder.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c b/drivers/gpu/drm/i915/gvt/fb_decoder.c
index a219819..dfb8cb3 100644
--- a/drivers/gpu/drm/i915/gvt/fb_decoder.c
+++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c
@@ -23,12 +23,303 @@
 
 #include "gvt.h"
 
-int gvt_decode_fb_format(struct pgt_device *pdev, int vmid, struct gvt_fb_format *fb)
+#define FORMAT_NUM	16
+struct pixel_format {
+	int	drm_format;	/* Pixel format in DRM definition */
+	int	bpp;		/* Bits per pixel, 0 indicates invalid */
+	char	*desc;		/* The description */
+};
+
+/* non-supported format has bpp default to 0 */
+static struct pixel_format primary_pixel_formats[FORMAT_NUM] = {
+	[0b0010]  = {DRM_FORMAT_C8, 8, "8-bit Indexed"},
+	[0b0101]  = {DRM_FORMAT_RGB565, 16, "16-bit BGRX (5:6:5 MSB-R:G:B)"},
+	[0b0110]  = {DRM_FORMAT_XRGB8888, 32, "32-bit BGRX (8:8:8:8 MSB-X:R:G:B)"},
+	[0b1000]  = {DRM_FORMAT_XBGR2101010, 32, "32-bit RGBX (2:10:10:10 MSB-X:B:G:R)"},
+	[0b1010] = {DRM_FORMAT_XRGB2101010, 32, "32-bit BGRX (2:10:10:10 MSB-X:R:G:B)"},
+	[0b1110] = {DRM_FORMAT_XBGR8888, 32, "32-bit RGBX (8:8:8:8 MSB-X:B:G:R)"},
+};
+
+/* non-supported format has bpp default to 0 */
+static struct pixel_format skl_pixel_formats[FORMAT_NUM] = {
+	[0b1100]  = {DRM_FORMAT_C8, 8, "8-bit Indexed"},
+	[0b1110]  = {DRM_FORMAT_RGB565, 16, "16-bit BGRX (5:6:5 MSB-R:G:B)"},
+	[0b0100]  = {DRM_FORMAT_XRGB8888, 32, "32-bit BGRX (8:8:8:8 MSB-X:R:G:B)"},
+	[0b1010]  = {DRM_FORMAT_XRGB2101010, 32, "32-bit BGRX (2:10:10:10 MSB-X:R:G:B)"},
+};
+
+static ATOMIC_NOTIFIER_HEAD(gvt_fb_notifier_list);
+
+int gvt_decode_primary_plane_format(struct vgt_device *vgt,
+	int pipe, struct gvt_primary_plane_format *plane)
 {
+	u32	val, fmt;
+	struct drm_device *dev = vgt->pdev->dev_priv->dev;
+
+	val = __vreg(vgt, GVT_DSPCNTR(pipe));
+	plane->enabled = !!(val & DISPLAY_PLANE_ENABLE);
+	if (!plane->enabled)
+		return 0;
+
+	if (IS_SKYLAKE(dev)) {
+		plane->tiled = !!(val & PLANE_CTL_TILED_MASK);
+		fmt = (val & PLANE_CTL_FORMAT_MASK) >> 24;
+	} else {
+		plane->tiled = !!(val & DISPPLANE_TILED);
+		fmt = (val & DISPPLANE_PIXFORMAT_MASK) >> _PRI_PLANE_FMT_SHIFT;
+	}
+
+	if ((IS_SKYLAKE(dev) && !skl_pixel_formats[fmt].bpp)
+			|| (!IS_SKYLAKE(dev) && !primary_pixel_formats[fmt].bpp)) {
+		gvt_err("Non-supported pixel format (0x%x)\n", fmt);
+		return -EINVAL;
+	}
+
+	plane->hw_format = fmt;
+	plane->bpp = primary_pixel_formats[fmt].bpp;
+	plane->drm_format = primary_pixel_formats[fmt].drm_format;
+
+	plane->base = __vreg(vgt, GVT_DSPSURF(pipe)) & GTT_PAGE_MASK;
+	plane->stride = __vreg(vgt, GVT_DSPSTRIDE(pipe)) &
+		_PRI_PLANE_STRIDE_MASK;
+	plane->width = (__vreg(vgt, GVT_PIPESRC(pipe)) & _PIPE_H_SRCSZ_MASK) >>
+		_PIPE_H_SRCSZ_SHIFT;
+	plane->width += 1;
+	plane->height = (__vreg(vgt, GVT_PIPESRC(pipe)) &
+			_PIPE_V_SRCSZ_MASK) >> _PIPE_V_SRCSZ_SHIFT;
+	plane->height += 1;	/* raw height is one minus the real value */
+
+	val = __vreg(vgt, GVT_DSPTILEOFF(pipe));
+	plane->x_offset = (val & _PRI_PLANE_X_OFF_MASK) >>
+		_PRI_PLANE_X_OFF_SHIFT;
+	plane->y_offset = (val & _PRI_PLANE_Y_OFF_MASK) >>
+		_PRI_PLANE_Y_OFF_SHIFT;
+
 	return 0;
 }
 
-int gvt_fb_notifier_call_chain(unsigned long val, void *data)
+#define CURSOR_MODE_NUM	(1 << 6)
+struct cursor_mode_format {
+	int	drm_format;	/* Pixel format in DRM definition */
+	u8	bpp;		/* Bits per pixel; 0 indicates invalid */
+	u32	width;		/* In pixel */
+	u32	height;		/* In lines */
+	char	*desc;		/* The description */
+};
+
+/* non-supported format has bpp default to 0 */
+static struct cursor_mode_format cursor_pixel_formats[CURSOR_MODE_NUM] = {
+	[0b100010]  = {DRM_FORMAT_ARGB8888, 32, 128, 128,"128x128 32bpp ARGB"},
+	[0b100011]  = {DRM_FORMAT_ARGB8888, 32, 256, 256, "256x256 32bpp ARGB"},
+	[0b100111]  = {DRM_FORMAT_ARGB8888, 32, 64, 64, "64x64 32bpp ARGB"},
+	[0b000111]  = {DRM_FORMAT_ARGB8888, 32, 64, 64, "64x64 32bpp ARGB"},//actually inverted... figure this out later
+};
+
+int gvt_decode_cursor_plane_format(struct vgt_device *vgt,
+	int pipe, struct gvt_cursor_plane_format *plane)
 {
+	u32 val, mode;
+	u32 alpha_plane, alpha_force;
+
+	val = __vreg(vgt, GVT_CURCNTR(pipe));
+	mode = val & _CURSOR_MODE;
+	plane->enabled = (mode != _CURSOR_MODE_DISABLE);
+	if (!plane->enabled)
+		return 0;
+
+	if (!cursor_pixel_formats[mode].bpp) {
+		gvt_err("Non-supported cursor mode (0x%x)\n", mode);
+		return -EINVAL;
+	}
+	plane->mode = mode;
+	plane->bpp = cursor_pixel_formats[mode].bpp;
+	plane->drm_format = cursor_pixel_formats[mode].drm_format;
+	plane->width = cursor_pixel_formats[mode].width;
+	plane->height = cursor_pixel_formats[mode].height;
+
+	alpha_plane = (val & _CURSOR_ALPHA_PLANE_MASK) >>
+				_CURSOR_ALPHA_PLANE_SHIFT;
+	alpha_force = (val & _CURSOR_ALPHA_FORCE_MASK) >>
+				_CURSOR_ALPHA_FORCE_SHIFT;
+	if (alpha_plane || alpha_force)
+		gvt_warn("alpha_plane=0x%x, alpha_force=0x%x\n",
+			alpha_plane, alpha_force);
+
+	plane->base = __vreg(vgt, GVT_CURBASE(pipe)) & GTT_PAGE_MASK;
+
+	val = __vreg(vgt, GVT_CURPOS(pipe));
+	plane->x_pos = (val & _CURSOR_POS_X_MASK) >> _CURSOR_POS_X_SHIFT;
+	plane->x_sign = (val & _CURSOR_SIGN_X_MASK) >> _CURSOR_SIGN_X_SHIFT;
+	plane->y_pos = (val & _CURSOR_POS_Y_MASK) >> _CURSOR_POS_Y_SHIFT;
+	plane->y_sign = (val & _CURSOR_SIGN_Y_MASK) >> _CURSOR_SIGN_Y_SHIFT;
+	plane->x_hot = __vreg(vgt, _vgtif_reg(xhot));
+	plane->y_hot = __vreg(vgt, _vgtif_reg(xhot));
+
+	return 0;
+}
+
+#define FORMAT_NUM_SRRITE	(1 << 3)
+
+static struct pixel_format sprite_pixel_formats[FORMAT_NUM_SRRITE] = {
+	[0b000]  = {DRM_FORMAT_YUV422, 16, "YUV 16-bit 4:2:2 packed"},
+	[0b001]  = {DRM_FORMAT_XRGB2101010, 32, "RGB 32-bit 2:10:10:10"},
+	[0b010]  = {DRM_FORMAT_XRGB8888, 32, "RGB 32-bit 8:8:8:8"},
+	[0b100] = {DRM_FORMAT_AYUV, 32, "YUV 32-bit 4:4:4 packed (8:8:8:8 MSB-X:Y:U:V)"},
+};
+
+int gvt_decode_sprite_plane_format(struct vgt_device *vgt,
+	int pipe, struct gvt_sprite_plane_format *plane)
+{
+	u32 val, fmt;
+	u32 width;
+	u32 color_order, yuv_order;
+	int drm_format;
+
+	val = __vreg(vgt, GVT_SPRCTL(pipe));
+	plane->enabled = !!(val & SPRITE_ENABLE);
+	if (!plane->enabled)
+		return 0;
+
+	plane->tiled = !!(val & SPRITE_TILED);
+	color_order = !!(val & SPRITE_RGB_ORDER_RGBX);
+	yuv_order = (val & SPRITE_YUV_BYTE_ORDER_MASK) >>
+				_SPRITE_YUV_ORDER_SHIFT;
+
+	fmt = (val & SPRITE_PIXFORMAT_MASK) >> _SPRITE_FMT_SHIFT;
+	if (!sprite_pixel_formats[fmt].bpp) {
+		gvt_err("Non-supported pixel format (0x%x)\n", fmt);
+		return -EINVAL;
+	}
+	plane->hw_format = fmt;
+	plane->bpp = sprite_pixel_formats[fmt].bpp;
+	drm_format = sprite_pixel_formats[fmt].drm_format;
+
+	/* Order of RGB values in an RGBxxx buffer may be ordered RGB or
+	 * BGR depending on the state of the color_order field
+	 */
+	if (!color_order) {
+		if (drm_format == DRM_FORMAT_XRGB2101010)
+			drm_format = DRM_FORMAT_XBGR2101010;
+		else if (drm_format == DRM_FORMAT_XRGB8888)
+			drm_format = DRM_FORMAT_XBGR8888;
+	}
+
+	if (drm_format == DRM_FORMAT_YUV422) {
+		switch (yuv_order){
+		case	0:
+			drm_format = DRM_FORMAT_YUYV;
+			break;
+		case	1:
+			drm_format = DRM_FORMAT_UYVY;
+			break;
+		case	2:
+			drm_format = DRM_FORMAT_YVYU;
+			break;
+		case	3:
+			drm_format = DRM_FORMAT_VYUY;
+			break;
+		default:
+			/* yuv_order has only 2 bits */
+			BUG();
+			break;
+		}
+	}
+
+	plane->drm_format = drm_format;
+
+	plane->base = __vreg(vgt, GVT_SPRSURF(pipe)) & GTT_PAGE_MASK;
+	plane->width = __vreg(vgt, GVT_SPRSTRIDE(pipe)) &
+				_SPRITE_STRIDE_MASK;
+	plane->width /= plane->bpp / 8;	/* raw width in bytes */
+
+	val = __vreg(vgt, GVT_SPRSIZE(pipe));
+	plane->height = (val & _SPRITE_SIZE_HEIGHT_MASK) >>
+		_SPRITE_SIZE_HEIGHT_SHIFT;
+	width = (val & _SPRITE_SIZE_WIDTH_MASK) >> _SPRITE_SIZE_WIDTH_SHIFT;
+	plane->height += 1;	/* raw height is one minus the real value */
+	width += 1;		/* raw width is one minus the real value */
+	if (plane->width != width)
+		gvt_warn("sprite_plane: plane->width=%d, width=%d\n",
+			plane->width, width);
+
+	val = __vreg(vgt, GVT_SPRPOS(pipe));
+	plane->x_pos = (val & _SPRITE_POS_X_MASK) >> _SPRITE_POS_X_SHIFT;
+	plane->y_pos = (val & _SPRITE_POS_Y_MASK) >> _SPRITE_POS_Y_SHIFT;
+
+	val = __vreg(vgt, GVT_SPROFFSET(pipe));
+	plane->x_offset = (val & _SPRITE_OFFSET_START_X_MASK) >>
+			   _SPRITE_OFFSET_START_X_SHIFT;
+	plane->y_offset = (val & _SPRITE_OFFSET_START_Y_MASK) >>
+			   _SPRITE_OFFSET_START_Y_SHIFT;
 	return 0;
 }
+
+/*
+ * Decode framebuffer information from raw vMMIO
+ *
+ * INPUT:
+ *   [domid] - specify the VM
+ * OUTPUT:
+ *   [format] - contain the decoded format info
+ *
+ * NOTE: The caller is expected to poll this interface, and reconstruct
+ * previous reference to the new format information
+ */
+
+int gvt_decode_fb_format(struct pgt_device *pdev, int vmid, struct gvt_fb_format *fb)
+{
+	int i;
+	struct vgt_device *vgt = NULL;
+	int ret = 0;
+
+	if (!fb)
+		return -EINVAL;
+
+	/* TODO: use fine-grained refcnt later */
+	mutex_lock(&pdev->lock);
+
+	for_each_online_instance(pdev, vgt, i)
+		if (vgt->vm_id == vmid)
+			break;
+
+	if (!vgt) {
+		gvt_err("Invalid domain ID (%d)\n", vmid);
+		mutex_unlock(&pdev->lock);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < I915_MAX_PIPES; i++) {
+		struct gvt_pipe_format *pipe = &fb->pipes[i];
+		u32 ddi_func_ctl = __vreg(vgt, _GVT_TRANS_DDI_FUNC_CTL(i));
+
+		if (!(ddi_func_ctl & TRANS_DDI_FUNC_ENABLE)) {
+			pipe->ddi_port = DDI_PORT_NONE;
+		} else {
+			u32 port = (ddi_func_ctl & TRANS_DDI_PORT_MASK) >>
+						TRANS_DDI_PORT_SHIFT;
+			if (port <= DDI_PORT_E)
+				pipe->ddi_port = port;
+			else
+				pipe->ddi_port = DDI_PORT_NONE;
+		}
+
+		ret |= gvt_decode_primary_plane_format(vgt, i, &pipe->primary);
+		ret |= gvt_decode_sprite_plane_format(vgt, i, &pipe->sprite);
+		ret |= gvt_decode_cursor_plane_format(vgt, i, &pipe->cursor);
+
+		if (ret) {
+			gvt_err("Decode format error for pipe(%d)\n", i);
+			ret = -EINVAL;
+			break;
+		}
+	}
+
+	mutex_unlock(&pdev->lock);
+
+	return ret;
+}
+
+int gvt_fb_notifier_call_chain(unsigned long val, void *data)
+{
+	return atomic_notifier_call_chain(&gvt_fb_notifier_list, val, data);
+}
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index cf88bd6..456b332 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -38,6 +38,7 @@
 #include "gtt.h"
 #include "cfg_space.h"
 #include "opregion.h"
+#include "fb_decoder.h"
 
 #define GVT_MAX_VGPU 8
 
diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
index 3fb4495..c66a2dc 100644
--- a/drivers/gpu/drm/i915/gvt/reg.h
+++ b/drivers/gpu/drm/i915/gvt/reg.h
@@ -68,6 +68,407 @@
 #define    _REGBIT_BDW_GMCH_GMS_SHIFT   8
 #define    _REGBIT_BDW_GMCH_GMS_MASK    0xff
 
+#define	_PRI_PLANE_FMT_SHIFT	26
+#define	_PRI_PLANE_TILE_SHIFT	10
+
+#define	_PRI_PLANE_STRIDE_SHIFT	6
+#define	_PRI_PLANE_STRIDE_MASK	(0x3ff << _PRI_PLANE_STRIDE_SHIFT)
+
+#define	_PRI_PLANE_X_OFF_SHIFT	0
+#define	_PRI_PLANE_X_OFF_MASK	(0x1fff << _PRI_PLANE_X_OFF_SHIFT)
+#define	_PRI_PLANE_Y_OFF_SHIFT	16
+#define	_PRI_PLANE_Y_OFF_MASK	(0xfff << _PRI_PLANE_Y_OFF_SHIFT)
+
+#define     _PIPE_V_SRCSZ_SHIFT	0
+#define     _PIPE_V_SRCSZ_MASK	(0xfff << _PIPE_V_SRCSZ_SHIFT)
+#define     _PIPE_H_SRCSZ_SHIFT	16
+#define     _PIPE_H_SRCSZ_MASK	(0x1fff << _PIPE_H_SRCSZ_SHIFT)
+
+#define _CURSOR_MODE	0x3f
+#define _CURSOR_MODE_DISABLE	0x00
+#define _CURSOR_ALPHA_FORCE_SHIFT	8
+#define _CURSOR_ALPHA_FORCE_MASK	(0x3 << _CURSOR_ALPHA_FORCE_SHIFT)
+#define _CURSOR_ALPHA_PLANE_SHIFT	10
+#define _CURSOR_ALPHA_PLANE_MASK	(0x3 << _CURSOR_ALPHA_PLANE_SHIFT)
+#define _CURSOR_POS_X_SHIFT	0
+#define _CURSOR_POS_X_MASK	(0x1fff << _CURSOR_POS_X_SHIFT)
+#define _CURSOR_SIGN_X_SHIFT	15
+#define _CURSOR_SIGN_X_MASK	(1 << _CURSOR_SIGN_X_SHIFT)
+#define _CURSOR_POS_Y_SHIFT		16
+#define _CURSOR_POS_Y_MASK	(0xfff << _CURSOR_POS_Y_SHIFT)
+#define _CURSOR_SIGN_Y_SHIFT	31
+#define _CURSOR_SIGN_Y_MASK	(1 << _CURSOR_SIGN_Y_SHIFT)
+
+#define GVT_CURCNTR(pipe)	_PIPE(pipe, _CURACNTR, _CURBCNTR_IVB)
+#define GVT_CURBASE(pipe)	_PIPE(pipe, _CURABASE, _CURBBASE_IVB)
+#define GVT_CURPOS(pipe)	_PIPE(pipe, _CURAPOS, _CURBPOS_IVB)
+
+#define	_SPRITE_FMT_SHIFT	25
+#define	_SPRITE_COLOR_ORDER_SHIFT	20
+#define	_SPRITE_YUV_ORDER_SHIFT	16
+
+#define	_SPRITE_STRIDE_SHIFT	6
+#define	_SPRITE_STRIDE_MASK	(0x1ff << _SPRITE_STRIDE_SHIFT)
+
+#define	_SPRITE_POS_X_SHIFT	0
+#define	_SPRITE_POS_Y_SHIFT	16
+#define	_SPRITE_POS_X_MASK	(0x1fff << _SPRITE_POS_X_SHIFT)
+#define	_SPRITE_POS_Y_MASK	(0xfff << _SPRITE_POS_Y_SHIFT)
+
+#define	_SPRITE_SIZE_WIDTH_SHIFT	0
+#define	_SPRITE_SIZE_HEIGHT_SHIFT	16
+#define	_SPRITE_SIZE_WIDTH_MASK	(0x1fff << _SPRITE_SIZE_WIDTH_SHIFT)
+#define	_SPRITE_SIZE_HEIGHT_MASK	(0xfff << _SPRITE_SIZE_HEIGHT_SHIFT)
+
+#define	_SPRITE_OFFSET_START_X_SHIFT	0
+#define	_SPRITE_OFFSET_START_Y_SHIFT	16
+#define	_SPRITE_OFFSET_START_X_MASK	(0x1fff << _SPRITE_OFFSET_START_X_SHIFT)
+#define	_SPRITE_OFFSET_START_Y_MASK	(0xfff << _SPRITE_OFFSET_START_Y_SHIFT)
+
+#define GVT_SPRCTL(pipe)	_PIPE(pipe, _SPRA_CTL, _PLANE_CTL_2_B)
+#define GVT_SPRSTRIDE(pipe)	_PIPE(pipe, _SPRA_STRIDE, _PLANE_STRIDE_2_B)
+#define GVT_SPRPOS(pipe)	_PIPE(pipe, _PLANE_POS_2_A, _PLANE_POS_2_B)
+#define GVT_SPRSIZE(pipe)	_PIPE(pipe, _PLANE_SIZE_2_A, _PLANE_SIZE_2_B)
+#define GVT_SPROFFSET(pipe)	_PIPE(pipe, _PLANE_OFFSET_2_A, _PLANE_OFFSET_2_B)
+
+#define GVT_DSPCNTR(pipe) _PIPE(pipe, _DSPACNTR, 0x71180)
+#define GVT_DSPCNTRPIPE(dspcntr) _GVT_GET_PIPE(dspcntr, _DSPACNTR, 0x71180)
+
+#define GVT_DSPLINOFF(pipe) _PIPE(pipe, _DSPAADDR, 0x71184)
+#define GVT_DSPSTRIDE(pipe) _PIPE(pipe, _DSPASTRIDE, 0x71188)
+#define GVT_DSPTILEOFF(pipe) _PIPE(pipe, _DSPATILEOFF, 0x711A4)
+
+#define GVT_DSPSURF(pipe) _PIPE(pipe, _DSPASURF, 0x7119C)
+#define GVT_DSPSURFPIPE(dspsurf) _GVT_GET_PIPE(dspsurf, _DSPASURF, 0x7119C)
+
+#define GVT_DSPSURFLIVE(pipe) _PIPE(pipe, _DSPASURFLIVE, 0x711AC)
+#define GVT_DSPSURFLIVEPIPE(dspsurf) _GVT_GET_PIPE(dspsurf, _DSPASURFLIVE, 0x711AC)
+
+#define GVT_DSPPOS(pipe) _PIPE(pipe, _DSPAPOS, 0x7118C)
+#define GVT_DSPSIZE(pipe) _PIPE(pipe, _DSPASIZE, 0x71190)
+
+#define GVT_CURSURF(pipe) _PIPE(pipe, _CURABASE, _CURBBASE_IVB)
+#define GVT_CURCNTR(pipe) _PIPE(pipe, _CURACNTR, _CURBCNTR_IVB)
+#define GVT_CURPOS(pipe)	_PIPE(pipe, _CURAPOS, _CURBPOS_IVB)
+#define GVT_CURSURFLIVE(pipe) _PIPE(pipe, 0x700AC, 0x710AC)
+
+#define GVT_CURSURFPIPE(cursurf) _GVT_GET_PIPE(cursurf, _CURABASE, _CURBBASE_IVB)
+#define GVT_CURCNTRPIPE(curcntr) _GVT_GET_PIPE(curcntr, _CURACNTR,_CURBCNTR_IVB)
+
+#define GVT_SPRSURF(pipe) _PIPE(pipe, _SPRA_SURF, _SPRB_SURF)
+#define GVT_SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE)
+#define GVT_SPRSURFPIPE(sprsurf) _GVT_GET_PIPE(sprsurf, _SPRA_SURF, _SPRB_SURF)
+
+#define GVT_SPRCNTR(pipe) _PIPE(pipe, _SPRA_CTL, _SPRB_CTL)
+#define GVT_SPRCNTRPIPE(sprcntr) _GVT_GET_PIPE(sprcntr, _SPRA_CTL, _SPRB_CTL)
+
+/*
+ * We use _IMM instead of _INDEX, to avoid switching hardware
+ * status page
+ */
+#define MI_STORE_DATA_IMM		((0x20<<23) | 2)
+#define MI_STORE_DATA_IMM_QWORD		((0x20<<23) | 3)
+#define   MI_SDI_USE_GTT		(1<<22)
+#define MI_LRI_CMD			(0x22<<23 | 1)
+#define   MI_LRI_BYTE0_DISABLE		(1<<8)
+#define   MI_LRI_BYTE1_DISABLE		(1<<9)
+#define   MI_LRI_BYTE2_DISABLE		(1<<10)
+#define   MI_LRI_BYTE3_DISABLE		(1<<11)
+
+#define   MI_WAIT_FOR_PLANE_C_FLIP_PENDING      (1<<15)
+#define   MI_WAIT_FOR_PLANE_B_FLIP_PENDING      (1<<9)
+#define   MI_WAIT_FOR_PLANE_A_FLIP_PENDING      (1<<1)
+
+#define   MI_WAIT_FOR_SPRITE_C_FLIP_PENDING      (1<<20)
+#define   MI_WAIT_FOR_SPRITE_B_FLIP_PENDING      (1<<10)
+#define   MI_WAIT_FOR_SPRITE_A_FLIP_PENDING      (1<<2)
+
+#define	PIPE_CONTROL_DC_FLUSH_ENABLE			(1<<5)
+#define DUMMY_3D		(0x6d800005)
+#define PRIM_TRILIST		(0x4)
+
+/*
+ * Display engine regs
+ */
+
+#define _REG_SWF		0x4f000
+#define _REG_PIPE_MISC_C	0x72030
+
+/* CPU panel fitter */
+#define _REG_PF_CTL_2			0x69080
+#define _REG_PF_WIN_SZ_2		0x69074
+#define _REG_PF_WIN_POS_2		0x69070
+
+#define GVT_HTOTAL(pipe)	_PIPE(pipe, _HTOTAL_A, _HTOTAL_B)
+#define GVT_HBLANK(pipe)	_PIPE(pipe, _HBLANK_A, _HBLANK_B)
+#define GVT_HSYNC(pipe)		_PIPE(pipe, _HSYNC_A, _HSYNC_B)
+#define GVT_VTOTAL(pipe)	_PIPE(pipe, _VTOTAL_A, _VTOTAL_B)
+#define GVT_VBLANK(pipe)	_PIPE(pipe, _VBLANK_A, _VBLANK_B)
+#define GVT_VSYNC(pipe)		_PIPE(pipe, _VSYNC_A, _VSYNC_B)
+#define GVT_BCLRPAT(pipe)	_PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
+#define GVT_VSYNCSHIFT(pipe)	_PIPE(pipe, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
+#define GVT_PIPESRC(pipe)	_PIPE(pipe, _PIPEASRC, _PIPEBSRC)
+
+#define GVT_PCH_DPLL(pipe)	_PIPE(pipe, _REG_PCH_DPLL_A, _REG_PCH_DPLL_B)
+
+#define GVT_PCH_FP0(pipe)	_PIPE(pipe, _REG_PCH_FPA0, _REG_PCH_FPB0)
+#define GVT_PCH_FP1(pipe)	_PIPE(pipe, _REG_PCH_FPA1, _REG_PCH_FPB1)
+
+/* PIPE C timing regs are same start from 0x61000 */
+#define _REG_PIPEC_DATA_M1		0x62030
+#define _REG_PIPEC_DATA_N1		0x62034
+#define _REG_PIPEC_LINK_M1		0x62040
+#define _REG_PIPEC_LINK_N1		0x62044
+
+#define _REG_PIPEC_DATA_M2		0x62038
+#define _REG_PIPEC_DATA_N2		0x6203c
+#define _REG_PIPEC_LINK_M2		0x62048
+#define _REG_PIPEC_LINK_N2		0x6204c
+
+#define GVT_PIPE_DATA_M1(pipe) _PIPE(pipe, _REG_PIPEA_DATA_M1, _REG_PIPEB_DATA_M1)
+#define GVT_PIPE_DATA_N1(pipe) _PIPE(pipe, _REG_PIPEA_DATA_N1, _REG_PIPEB_DATA_N1)
+#define GVT_PIPE_DATA_M2(pipe) _PIPE(pipe, _REG_PIPEA_DATA_M2, _REG_PIPEB_DATA_M2)
+#define GVT_PIPE_DATA_N2(pipe) _PIPE(pipe, _REG_PIPEA_DATA_N2, _REG_PIPEB_DATA_N2)
+#define GVT_PIPE_LINK_M1(pipe) _PIPE(pipe, _REG_PIPEA_LINK_M1, _REG_PIPEB_LINK_M1)
+#define GVT_PIPE_LINK_N1(pipe) _PIPE(pipe, _REG_PIPEA_LINK_N1, _REG_PIPEB_LINK_N1)
+#define GVT_PIPE_LINK_M2(pipe) _PIPE(pipe, _REG_PIPEA_LINK_M2, _REG_PIPEB_LINK_M2)
+#define GVT_PIPE_LINK_N2(pipe) _PIPE(pipe, _REG_PIPEA_LINK_N2, _REG_PIPEB_LINK_N2)
+
+/* FDI_RX, FDI_X is hard-wired to Transcoder_X */
+
+#define _REG_FDI_RXC_CTL			0xf200c
+#define _REGBIT_FDI_RX_PORT_WIDTH_MASK		(0x7 << 19)
+#define _REGBIT_FDI_RX_FDI_AUTO_TRAIN_ENABLE	(0x1 << 10)
+
+#define _REG_FDI_RXC_IIR			0xf2014
+#define _REG_FDI_RXC_IMR			0xf2018
+
+#define GVT_FDI_RX_IIR(pipe) _PIPE(pipe, _FDI_RXA_IIR, _FDI_RXB_IIR)
+#define GVT_FDI_RX_IMR(pipe) _PIPE(pipe, _FDI_RXA_IMR, _FDI_RXB_IMR)
+
+#define _REGBIT_FDI_RX_INTER_LANE_ALIGN		(1<<10)
+#define _REGBIT_FDI_RX_SYMBOL_LOCK		(1 << 9) /* train 2*/
+#define _REGBIT_FDI_RX_BIT_LOCK			(1 << 8) /* train 1*/
+#define _REGBIT_FDI_RX_TRAIN_PATTERN_2_FAIL	(1<<7)
+#define _REGBIT_FDI_RX_FS_CODE_ERR		(1<<6)
+#define _REGBIT_FDI_RX_FE_CODE_ERR		(1<<5)
+#define _REGBIT_FDI_RX_SYMBOL_ERR_RATE_ABOVE	(1<<4)
+#define _REGBIT_FDI_RX_HDCP_LINK_FAIL		(1<<3)
+#define _REGBIT_FDI_RX_PIXEL_FIFO_OVERFLOW	(1<<2)
+#define _REGBIT_FDI_RX_CROSS_CLOCK_OVERFLOW	(1<<1)
+#define _REGBIT_FDI_RX_SYMBOL_QUEUE_OVERFLOW	(1<<0)
+
+
+#define GVT_FDI_RX_CTL_BPC_MASK		(0x7 << 16)
+#define GVT_FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL)
+
+#define GVT_FDI_RX_TUSIZE1(pipe) _PIPE(pipe, _REG_FDI_RXA_TUSIZE1,_REG_FDI_RXB_TUSIZE1)
+
+/* CPU: FDI_TX */
+#define _REG_FDI_TXC_CTL		0x62100
+
+#define _REGBIT_FDI_TX_ENABLE				(1 << 31)
+#define _REGBIT_FDI_TX_PLL_ENABLE			(1 << 14)
+#define _REGBIT_FDI_TX_ENHANCE_FRAME_ENABLE		(1<<18)
+
+#define GVT_FDI_TX_CTL(pipe) _PIPE(pipe, _FDI_TXA_CTL, _FDI_TXB_CTL)
+
+/* CRT */
+#define _REGBIT_ADPA_DAC_ENABLE			(1 << 31)
+#define PORT_TRANS_SEL_SHIFT			29
+#define GVT_PORT_TRANS_SEL_CPT(pipe)		((pipe) << PORT_TRANS_SEL_SHIFT)
+#define _REGBIT_ADPA_VSYNC_ACTIVE_HIGH		(1 << 4)
+#define _REGBIT_ADPA_HSYNC_ACTIVE_HIGH		(1 << 3)
+
+/*Intermediate Pixel Storage*/
+union _PCH_PP_CTL
+{
+	uint32_t data;
+	struct
+	{
+		uint32_t power_state_target	: 1; // bit 0
+		uint32_t power_down_on_reset	: 1; // bit 1
+		uint32_t backlight_enable	: 1; // bit 2
+		uint32_t edp_vdd_override_for_aux : 1; // bit 3
+		uint32_t reserve : 12;			// bits 15:4
+		uint32_t write_protect_key :16; // bits 31:16 0xABCD to disable protected)
+	};
+};
+
+union _PCH_PP_STAUTS
+{
+	uint32_t data;
+	struct
+	{
+		uint32_t reserv1	: 4;	// bit 3:0
+		uint32_t reserv2	: 23;	// bit 26:4
+		uint32_t power_cycle_delay_active	:1;	// bit 27
+		uint32_t power_sequence_progress	:2;	// bits 29:28
+		uint32_t require_asset_status		:1;	// bit 30
+		uint32_t panel_powere_on_statue		:1;	// bit 31 (0 - Disable, 1 - Enable)
+	};
+};
+
+/* Per-transcoder DIP controls */
+
+#define GVT_TRANSCONF(plane)	_PIPE(plane, _PCH_TRANSACONF, _PCH_TRANSBCONF)
+
+union _TRANS_CONFIG
+{
+	uint32_t data;
+	struct
+	{
+		uint32_t reserve1 : 10;			// bit 9:0
+		uint32_t xvycc_color_range_limit : 1;	// bit 10
+		uint32_t reserve2 : 10;			// bit 20:11
+		uint32_t interlaced_mode: 3;		// bit 23:21
+		uint32_t reserve3 : 6;			// bit 29:24
+		uint32_t transcoder_state : 1;		// bit 30
+		uint32_t transcoder_enable : 1;		// bit 31
+	};
+};
+
+#define _REG_TRANSC_VIDEO_DIP_CTL	0xE2200
+#define _REG_TRANSC_VIDEO_DIP_DATA	0xE2208
+#define _REG_TRANSC_VIDEO_DIP_GCP	0xE2210
+
+/* eDP */
+#define _REG_PIPE_EDP_CONF	0x7f008
+
+/* bit fields of pipestat */
+#define GVT_PIPEDSL(pipe)	_PIPE(pipe, _PIPEADSL, 0x71000)
+#define GVT_PIPECONF(pipe)	_PIPE(pipe, _PIPEACONF, 0x71008)
+#define GVT_PIPESTAT(pipe)	_PIPE(pipe, _PIPEASTAT, 0x71024)
+#define GVT_PIPE_FRMCOUNT(pipe)	_PIPE(pipe, _PIPEA_FRMCOUNT_G4X, 0x71040)
+#define GVT_PIPE_FLIPCOUNT(pipe) _PIPE(pipe, _PIPEA_FLIPCOUNT_G4X, 0x71044)
+
+#define GVT_PIPECONFPIPE(pipeconf) _GVT_GET_PIPE(pipeconf, _PIPEACONF, 0x71008)
+#define GVT_FRMCOUNTPIPE(frmcount) _GVT_GET_PIPE(frmcount, _PIPEA_FRMCOUNT_G4X, 0x71040)
+
+#define GVT_PALETTE(pipe) _PIPE(pipe, _PALETTE_A_OFFSET, _PALETTE_B_OFFSET)
+
+/* legacy palette */
+#define _REG_LGC_PALETTE_C		0x4b000
+
+/* Display Port */
+#define _REG_DP_TP_CTL_C		0x64240
+#define _REG_DP_TP_CTL_D		0x64340
+#define _REG_DP_TP_CTL_E		0x64440
+#define  _REGBIT_DP_TP_FDI_AUTO_TRAIN_ENABLE	(1 << 15)
+#define  _DDI_BUFCTL_DETECT_MASK	0x1
+#define  _REGBIT_DDI_BUF_ENABLE		(1 << 31)
+#define  _REGBIT_DDI_BUF_IS_IDLE	(1<<7)
+#define _REG_DDI_BUF_CTL_C		0x64200
+#define _REG_DDI_BUF_CTL_D		0x64300
+#define _REG_DDI_BUF_CTL_E		0x64400
+#define _REG_DP_TP_STATUS_C			0x64244
+#define _REG_DP_TP_STATUS_D			0x64344
+#define _REG_DP_TP_STATUS_E			0x64444
+#define GVT_DP_TP_CTL(port)		_PORT(port, _DP_TP_CTL_A, \
+		_DP_TP_CTL_B)
+
+#define DP_TP_PORT(reg)		_GVT_GET_PORT(reg, _DP_TP_CTL_A, \
+		_DP_TP_CTL_B)
+
+#define DRM_MODE_DPMS_ON		0
+
+#define _PCH_DPA_AUX_CH_CTL	0x64010
+#define _PCH_DPB_AUX_CH_CTL	0xe4110
+#define _PCH_DPC_AUX_CH_CTL	0xe4210
+#define _PCH_DPD_AUX_CH_CTL	0xe4310
+
+/* DPCD */
+#define DP_SET_POWER		0x600
+#define DP_SET_POWER_D0		0x1
+#define AUX_NATIVE_WRITE	0x8
+#define AUX_NATIVE_READ		0x9
+
+#define AUX_NATIVE_REPLY_MASK	(0x3 << 4)
+#define AUX_NATIVE_REPLY_ACK	(0x0 << 4)
+#define AUX_NATIVE_REPLY_NAK	(0x1 << 4)
+#define AUX_NATIVE_REPLY_DEFER	(0x2 << 4)
+
+#define AUX_BURST_SIZE		16
+
+/* DPCD 0x106 */
+
+#define DP_TRAINING_PATTERN_SET			0x102
+#define DP_TRAINING_PATTERN_DISABLE		0
+#define DP_TRAINING_PATTERN_1			1
+#define DP_TRAINING_PATTERN_2			2
+#define DP_LINK_SCRAMBLING_DISABLE		(1 << 5)
+
+#define DP_LINK_CONFIGURATION_SIZE		9
+#define    DP_LINK_BW_SET			0x100
+# define DP_SET_ANSI_8B10B			(1 << 0)
+
+#define DP_LINK_STATUS_SIZE			6
+#define DP_TRAIN_MAX_SWING_REACHED		(1 << 2)
+
+#define DP_TRAINING_LANE0_SET			0x103
+
+#define DP_TRAIN_VOLTAGE_SWING_MASK		0x3
+#define DP_TRAIN_VOLTAGE_SWING_SHIFT		0
+#define DP_TRAIN_VOLTAGE_SWING_400		(0 << 0)
+#define DP_TRAIN_VOLTAGE_SWING_600		(1 << 0)
+#define DP_TRAIN_VOLTAGE_SWING_800		(2 << 0)
+#define DP_TRAIN_VOLTAGE_SWING_1200		(3 << 0)
+
+#define DP_TRAIN_PRE_EMPHASIS_MASK		(3 << 3)
+#define DP_TRAIN_PRE_EMPHASIS_0			(0 << 3)
+#define DP_TRAIN_PRE_EMPHASIS_3_5		(1 << 3)
+#define DP_TRAIN_PRE_EMPHASIS_6			(2 << 3)
+#define DP_TRAIN_PRE_EMPHASIS_9_5		(3 << 3)
+
+#define DP_TRAIN_PRE_EMPHASIS_SHIFT		3
+#define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED	(1 << 5)
+
+#define DP_LANE0_1_STATUS			0x202
+#define DP_LANE_CR_DONE				(1 << 0)
+
+#define DP_LANE_ALIGN_STATUS_UPDATED		0x204
+#define DP_INTERLANE_ALIGN_DONE			(1 << 0)
+#define DP_LANE_CHANNEL_EQ_DONE			(1 << 1)
+#define DP_LANE_SYMBOL_LOCKED			(1 << 2)
+
+#define DP_ADJUST_REQUEST_LANE0_1		0x206
+
+#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
+#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
+#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT  2
+#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT  6
+/* Ironlake */
+#define	_REG_CPU_VGACNTRL	CPU_VGACNTRL
+#define _REGBIT_VGA_DISPLAY_DISABLE	(1UL << 31)
+#define _REG_DPFC_CB_BASE		0x43200
+#define _REG_DPFC_CONTROL		0x43208
+#define _REG_DPFC_RECOMP_CTL		0x4320c
+#define _REG_DPFC_CPU_FENCE_OFFSET	0x43218
+#define _REG_DPFC_CONTROL_SA		0x100100
+#define _REG_DPFC_CPU_FENCE_OFFSET_SA	0x100104
+
+#define _REG_CSC_A_COEFFICIENTS		0x49010
+#define _REG_CSC_A_MODE			0x49028
+#define _REG_PRECSC_A_HIGH_COLOR_CHANNEL_OFFSET		0x49030
+#define _REG_PRECSC_A_MEDIUM_COLOR_CHANNEL_OFFSET	0x49034
+#define _REG_PRECSC_A_LOW_COLOR_CHANNEL_OFFSET		0x49038
+
+#define _REG_CSC_B_COEFFICIENTS		0x49110
+#define _REG_CSC_B_MODE			0x49128
+#define _REG_PRECSC_B_HIGH_COLOR_CHANNEL_OFFSET		0x49130
+#define _REG_PRECSC_B_MEDIUM_COLOR_CHANNEL_OFFSET	0x49134
+#define _REG_PRECSC_B_LOW_COLOR_CHANNEL_OFFSET		0x49138
+
+#define _REG_CSC_C_COEFFICIENTS		0x49210
+#define _REG_CSC_C_MODE			0x49228
+#define _REG_PRECSC_C_HIGH_COLOR_CHANNEL_OFFSET		0x49230
+#define _REG_PRECSC_C_MEDIUM_COLOR_CHANNEL_OFFSET	0x49234
+#define _REG_PRECSC_C_LOW_COLOR_CHANNEL_OFFSET		0x49238
+
+#define _REG_DP_BUFTRANS		0xe4f00
+
+#define _PCH_GMBUS0			0xc5100
+#define _PCH_GMBUS1			0xc5104
 #define _PCH_GMBUS2			0xc5108
 
 #define _GEN6_GDRST			0x941c
@@ -105,4 +506,7 @@
 #define _GEN8_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe)))
 #define _GEN8_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe)))
 
+#define _GVT_TRANS_DDI_FUNC_CTL(tran)   _TRANS(tran, _TRANS_DDI_FUNC_CTL_A, \
+		_TRANS_DDI_FUNC_CTL_B)
+
 #endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 21/29] drm/i915: gvt: vGPU MMIO register emulation
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (19 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 20/29] drm/i915: gvt: vGPU framebuffer format decoder Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 22/29] drm/i915: gvt: Full display virtualization Zhi Wang
                   ` (8 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

From: "Niu,Bing" <bing.niu@intel.com>

This patch introduces vGPU MMIO register emulation core logics.

Under virtualization environment, all GEN MMIO register access will be trapped
by hypervisor and forwarded to GVT-g. GVT-g will handle these MMIO register
emulation request by different policies.

For some kinds of virtual registers, accessing one or more bit may cause other
bit changes, a mmio emulation read/write handler will be called when GVT-g is
handling the emulation request.

Signed-off-by: Niu,Bing <bing.niu@intel.com>
---
 drivers/gpu/drm/i915/gvt/debug.h     |   16 +
 drivers/gpu/drm/i915/gvt/gvt.c       |   18 +-
 drivers/gpu/drm/i915/gvt/gvt.h       |   83 ++-
 drivers/gpu/drm/i915/gvt/handlers.c  | 1098 +++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/gvt/instance.c  |    2 +
 drivers/gpu/drm/i915/gvt/interrupt.h |   14 +
 drivers/gpu/drm/i915/gvt/mmio.c      |   33 +-
 drivers/gpu/drm/i915/gvt/mmio.h      |   16 +-
 drivers/gpu/drm/i915/gvt/reg.h       |  374 ++++++++++++
 9 files changed, 1631 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i915/gvt/debug.h b/drivers/gpu/drm/i915/gvt/debug.h
index 18e1467..807d9e8 100644
--- a/drivers/gpu/drm/i915/gvt/debug.h
+++ b/drivers/gpu/drm/i915/gvt/debug.h
@@ -40,6 +40,19 @@
                 }                                                       \
         } while (0);
 
+#define ASSERT_VM(x, vgt)                                              \
+        do {                                                            \
+                if (!(x)) {                                             \
+                        printk("Assert at %s line %d\n",                \
+                                        __FILE__, __LINE__);                    \
+                        if (atomic_cmpxchg(&(vgt)->crashing, 0, 1))     \
+                        break;                                  \
+                        gvt_warn("Killing VM%d", (vgt)->vm_id);       \
+                        if (!hypervisor_pause_domain((vgt)))            \
+                        hypervisor_shutdown_domain((vgt));      \
+                }                                                       \
+        } while (0)
+
 #define gvt_info(fmt, args...) \
 	printk(KERN_INFO"[GVT-g] "fmt"\n", ##args)
 
@@ -58,6 +71,9 @@ enum {
 	GVT_DBG_CORE = (1 << 0),
 	GVT_DBG_MM = (1 << 1),
 	GVT_DBG_IRQ = (1 << 2),
+	GVT_DBG_DPY = (1 << 3),
+	GVT_DBG_RENDER = (1 << 4),
+	GVT_DBG_EDID = (1 << 5)
 };
 
 #define gvt_dbg_core(fmt, args...) \
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index 63eb02c..84549a0 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -169,6 +169,11 @@ static void clean_initial_mmio_state(struct pgt_device *pdev)
 		iounmap(pdev->gmadr_va);
 		pdev->gmadr_va = NULL;
 	}
+
+	if(pdev->reg_info) {
+		vfree(pdev->reg_info);
+		pdev->reg_info = NULL;
+	}
 }
 
 static bool init_initial_mmio_state(struct pgt_device *pdev)
@@ -197,6 +202,12 @@ static bool init_initial_mmio_state(struct pgt_device *pdev)
 		goto err;
 	}
 
+	pdev->reg_info = vzalloc(pdev->reg_num * sizeof(u32));
+	if (!pdev->reg_info) {
+		printk("vGT: failed to allocate reg_info\n");
+		goto err;
+	}
+
 	gvt_info("bar0: 0x%llx, bar1: 0x%llx", bar0, bar1);
 	gvt_info("mmio size: %x", pdev->mmio_size);
 	gvt_info("gttmmio: 0x%llx, gmadr: 0x%llx", pdev->gttmmio_base, pdev->gmadr_base);
@@ -226,6 +237,12 @@ static int gvt_service_thread(void *data)
 		if (kthread_should_stop())
 			break;
 
+		if (test_and_clear_bit(GVT_REQUEST_UEVENT,
+					(void *)&pdev->service_request)) {
+			gvt_dpy_ready_uevent_handler(pdev);
+		}
+
+
 		if (r) {
 			gvt_warn("service thread is waken up by unexpected signal.");
 			continue;
@@ -340,7 +357,6 @@ static struct pgt_device *alloc_pgt_device(struct drm_i915_private *dev_priv)
 	mutex_init(&pdev->lock);
 	pdev->dev_priv = dev_priv;
 	idr_init(&pdev->instance_idr);
-
 	return pdev;
 err:
 	free_pgt_device(pdev);
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 456b332..62cbb62 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -28,6 +28,7 @@
 #include "i915_vgpu.h"
 
 #include "debug.h"
+
 #include "params.h"
 #include "reg.h"
 #include "hypercall.h"
@@ -129,18 +130,23 @@ struct gvt_virtual_device_state {
 	struct gvt_virtual_opregion_state opregion;
 };
 
+struct gvt_uevent {
+	int vm_id;
+};
+
 struct vgt_device {
 	int id;
 	int vm_id;
 	struct pgt_device *pdev;
-	bool warn_untrack;
 	atomic_t active;
 	struct gvt_virtual_device_state state;
 	struct gvt_statistics stat;
 	struct gvt_vgtt_info gtt;
 	void *hypervisor_data;
 	unsigned long low_mem_max_gpfn;
+	unsigned long last_reset_time;
 	atomic_t crashing;
+	bool warn_untrack;
 };
 
 struct gvt_gm_allocator {
@@ -156,6 +162,7 @@ struct pgt_device {
 	struct idr instance_idr;
 
 	struct gvt_device_info device_info;
+	struct gvt_uevent       uevent;
 
 	u8 initial_cfg_space[GVT_CFG_SPACE_SZ];
 	u64 bar_size[GVT_BAR_NUM];
@@ -200,6 +207,32 @@ struct pgt_device {
 	struct gvt_gtt_info gtt;
 };
 
+/* request types to wake up main thread */
+#define GVT_REQUEST_IRQ                        0       /* a new irq pending from device */
+#define GVT_REQUEST_UEVENT             1
+#define GVT_REQUEST_CTX_SWITCH         2       /* immediate reschedule(context switch) requested */
+#define GVT_REQUEST_EMUL_DPY_EVENTS    3
+#define GVT_REQUEST_DEVICE_RESET       4
+#define GVT_REQUEST_SCHED              5
+#define GVT_REQUEST_CTX_EMULATION_RCS  6 /* Emulate context switch irq of Gen8 */
+#define GVT_REQUEST_CTX_EMULATION_VCS  7 /* Emulate context switch irq of Gen8 */
+#define GVT_REQUEST_CTX_EMULATION_BCS  8 /* Emulate context switch irq of Gen8 */
+#define GVT_REQUEST_CTX_EMULATION_VECS 9 /* Emulate context switch irq of Gen8 */
+#define GVT_REQUEST_CTX_EMULATION_VCS2 10 /* Emulate context switch irq of Gen8 */
+
+static inline void gvt_raise_request(struct pgt_device *pdev, uint32_t flag)
+{
+       set_bit(flag, (void *)&pdev->service_request);
+       if (waitqueue_active(&pdev->service_thread_wq))
+               wake_up(&pdev->service_thread_wq);
+}
+
+static inline bool vgt_chk_raised_request(struct pgt_device *pdev, uint32_t flag)
+{
+       return !!(test_bit(flag, (void *)&pdev->service_request));
+}
+
+
 /* definitions for physical aperture/GM space */
 #define phys_aperture_sz(pdev)          (pdev->bar_size[1])
 #define phys_aperture_pages(pdev)       (phys_aperture_sz(pdev) >> GTT_PAGE_SHIFT)
@@ -266,22 +299,12 @@ extern void gvt_free_gm_and_fence_resource(struct vgt_device *vgt);
 
 #define REG_INDEX(reg) ((reg) >> 2)
 
-#define D_SNB   (1 << 0)
-#define D_IVB   (1 << 1)
-#define D_HSW   (1 << 2)
-#define D_BDW   (1 << 3)
+#define D_HSW	(1 << 0)
+#define D_BDW	(1 << 1)
 
 #define D_GEN8PLUS      (D_BDW)
-#define D_GEN75PLUS     (D_HSW | D_BDW)
-#define D_GEN7PLUS      (D_IVB | D_HSW | D_BDW)
-
 #define D_BDW_PLUS      (D_BDW)
-#define D_HSW_PLUS      (D_HSW | D_BDW)
-#define D_IVB_PLUS      (D_IVB | D_HSW | D_BDW)
-
-#define D_PRE_BDW       (D_SNB | D_IVB | D_HSW)
-
-#define D_ALL           (D_SNB | D_IVB | D_HSW | D_BDW)
+#define D_ALL           (D_HSW | D_BDW)
 
 #define reg_addr_fix(pdev, reg)		(pdev->reg_info[REG_INDEX(reg)] & GVT_REG_ADDR_FIX)
 #define reg_hw_status(pdev, reg)	(pdev->reg_info[REG_INDEX(reg)] & GVT_REG_HW_STATUS)
@@ -421,6 +444,29 @@ static inline void gvt_mmio_posting_read(struct pgt_device *pdev, u32 reg)
 	POSTING_READ(tmp);
 }
 
+static inline void  gvt_set_dpy_uevent(struct vgt_device *vgt)
+{
+	struct gvt_uevent *event =  &vgt->pdev->uevent;
+
+	event->vm_id = vgt->vm_id;
+}
+
+static inline bool gvt_dpy_ready_uevent_handler(struct pgt_device *pdev)
+{
+	int retval;
+	struct kobject *kobj = &(pdev->dev_priv->dev->primary->kdev->kobj);
+	char *env[3] = {"VGT_DISPLAY_READY=1", NULL, NULL};
+	char vmid_str[20];
+	snprintf(vmid_str, 20, "VMID=%d", pdev->uevent.vm_id);
+	env[1] = vmid_str;
+
+	retval = kobject_uevent_env(kobj, KOBJ_ADD, env);
+	if (retval == 0)
+		return true;
+	else
+		return false;
+}
+
 extern void gvt_clean_initial_mmio_state(struct pgt_device *pdev);
 extern bool gvt_setup_initial_mmio_state(struct pgt_device *pdev);
 
@@ -618,9 +664,18 @@ static inline u32 h2g_gtt_index(struct vgt_device *vgt, uint32_t h_index)
 /* get one bit of the data, bit is starting from zeor */
 #define GVT_GET_BIT(data, bit)          GVT_GET_BITS(data, bit, bit)
 
+int gvt_render_mmio_to_ring_id(unsigned int reg);
+int gvt_ring_id_to_render_mmio_base(int ring_id);
+
 int gvt_hvm_map_aperture(struct vgt_device *vgt, int map);
 int gvt_hvm_set_trap_area(struct vgt_device *vgt, int map);
 
+bool gvt_default_mmio_read(struct vgt_device *vgt, unsigned int offset, void *p_data, unsigned int bytes);
+bool gvt_default_mmio_write(struct vgt_device *vgt, unsigned int offset, void *p_data, unsigned int bytes);
+
+bool register_mmio_handler(struct pgt_device *pdev, unsigned int start, int bytes,
+	gvt_mmio_handler_t read, gvt_mmio_handler_t write);
+
 #include "mpt.h"
 
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index a6ec4f3..ba29c9c 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -23,18 +23,1107 @@
 
 #include "gvt.h"
 
-/* TODO: Merge register definition from i915. */
+static bool mmio_not_allow_read(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	gvt_err("[vgt %d]: reading MMIO reg 0x%x is not allowed.", vgt->id, offset);
+	memset(p_data, 0, bytes);
+	return true;
+}
+
+static bool mmio_not_allow_write(struct vgt_device *vgt,
+		unsigned int offset, void *p_data, unsigned int bytes)
+{
+	gvt_err("[vgt %d]: writing MMIO reg 0x%x is not allowed.",
+			vgt->id, offset);
+	return true;
+}
+
+/* Fence MMIO handlers. */
+static bool check_fence_mmio_access(struct vgt_device *vgt,
+		unsigned int off, void *p_data, unsigned int bytes)
+{
+	unsigned long fence_num;
+
+	ASSERT(off >= i915_mmio_reg_offset(FENCE_REG_GEN6_LO(0)) &&
+			off <= i915_mmio_reg_offset(FENCE_REG_GEN6_HI(GVT_MAX_NUM_FENCES)));
+
+	if (bytes > 8 && (off & (bytes - 1))) {
+		gvt_err("[vgt %d] unsupported access pattern, off %x bytes %x",
+				vgt->id, off, bytes);
+		return false;
+	}
+
+	fence_num = (off - i915_mmio_reg_offset(FENCE_REG_GEN6_LO(0))) >> 3;
+
+	if (fence_num >= vgt->state.gm.fence_sz)
+		gvt_warn("[vgt %d] access unassigned fence reg %x, total: %x",
+				vgt->id, off, vgt->state.gm.fence_sz);
+	return true;
+}
+
+static bool fence_mmio_read(struct vgt_device *vgt, unsigned int off,
+		void *p_data, unsigned int bytes)
+{
+	if (!check_fence_mmio_access(vgt, off, p_data, bytes))
+		return false;
+
+	return gvt_default_mmio_read(vgt, off, p_data, bytes);
+}
+
+static bool fence_mmio_write(struct vgt_device *vgt, unsigned int off,
+		void *p_data, unsigned int bytes)
+{
+	if (!check_fence_mmio_access(vgt, off, p_data, bytes))
+		return false;
+
+	if (!gvt_default_mmio_write(vgt, off, p_data, bytes))
+		return false;
+
+	/* TODO: Check address space */
+
+	/* FENCE registers are physically assigned, update! */
+	if (bytes < 8)
+		gvt_mmio_write(vgt->pdev, off + vgt->state.gm.fence_base * 8,
+				__sreg(vgt, off));
+	else
+		gvt_mmio_write64(vgt->pdev, off + vgt->state.gm.fence_base * 8,
+				__sreg64(vgt, off));
+	return true;
+}
+
+static bool mt_force_wake_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	u32 data, mask, wake, old_wake, new_wake;
+
+	data = *(u32*) p_data;
+
+	/* bit 16-31: mask
+	   bit 0-15: force wake
+	   forcewake bit apply only if its mask bit is 1
+	 */
+	mask = data >> 16;
+	wake = data & 0xFFFF;
+	old_wake = __vreg(vgt, _FORCEWAKE_MT) & 0xFFFF;
+
+	new_wake = (old_wake & ~mask) + (wake & mask);
+	__vreg(vgt, _FORCEWAKE_MT) = (data & 0xFFFF0000) + new_wake;
+	__vreg(vgt, _FORCEWAKE_ACK_HSW) = new_wake;
+
+	return true;
+}
+
+static bool gdrst_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	u32 data = *(u32 *)p_data;
+
+	if (data & GEN6_GRDOM_FULL) {
+		gvt_info("VM %d request Full GPU Reset\n", vgt->vm_id);
+	}
+
+	if (data & GEN6_GRDOM_RENDER) {
+		gvt_info("VM %d request GPU Render Reset\n", vgt->vm_id);
+	}
+
+	if (data & GEN6_GRDOM_MEDIA) {
+		gvt_info("VM %d request GPU Media Reset\n", vgt->vm_id);
+	}
+
+	if (data & GEN6_GRDOM_BLT) {
+		gvt_info("VM %d request GPU BLT Reset\n", vgt->vm_id);
+	}
+
+	return true;
+}
+
+static bool ring_mode_write(struct vgt_device *vgt, unsigned int off,
+		void *p_data, unsigned int bytes)
+{
+	return true;
+}
+
+static bool pvinfo_read(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	bool rc = gvt_default_mmio_read(vgt, offset, p_data, bytes);
+	bool invalid_read = false;
+
+	switch (offset) {
+		case _vgtif_reg(magic) ... _vgtif_reg(vgt_id):
+			if (offset + bytes > _vgtif_reg(vgt_id) + 4)
+			invalid_read = true;
+			break;
+
+			case _vgtif_reg(avail_rs.mappable_gmadr.base) ...
+				_vgtif_reg(avail_rs.fence_num):
+					if (offset + bytes >
+							_vgtif_reg(avail_rs.fence_num) + 4)
+					invalid_read = true;
+			break;
+
+			case _vgtif_reg(drv_version_major) ...
+				_vgtif_reg(min_fence_num):
+					if (offset + bytes > _vgtif_reg(min_fence_num) + 4)
+					invalid_read = true;
+			break;
+		case _vgtif_reg(v2g_notify):
+			/* set cursor setting here.  For example:
+			 *   *((unsigned int *)p_data)) = VGT_V2G_SET_SW_CURSOR;
+			 */
+			break;
+		case _vgtif_reg(vgt_caps):
+			break;
+		default:
+			invalid_read = true;
+			break;
+	}
+
+	if (invalid_read)
+		gvt_warn("invalid pvinfo read: [%x:%x] = %x!!!\n",
+				offset, bytes, *(u32 *)p_data);
+
+	return rc;
+}
+
+static bool pvinfo_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	u32 val = *(u32 *)p_data;
+	u32 min;
+	bool rc = true;
+
+	switch (offset) {
+		case _vgtif_reg(min_low_gmadr):
+			min = val;
+			if (vgt->state.gm.aperture_sz < min) {
+				gvt_err("VM(%d): aperture size(%llx) is less than"
+						"its driver's minimum requirement(%x)!\n",
+						vgt->vm_id, vgt->state.gm.aperture_sz, min);
+				rc = false;
+			}
+			break;
+		case _vgtif_reg(min_high_gmadr):
+			min = val;
+			if (vgt->state.gm.gm_sz - vgt->state.gm.aperture_sz < min) {
+				gvt_err("VM(%d): hiden gm size(%llx) is less than"
+						"its driver's minimum requirement(%x)!\n",
+						vgt->vm_id, vgt->state.gm.gm_sz - vgt->state.gm.aperture_sz,
+						min);
+				rc = false;
+			}
+			break;
+		case _vgtif_reg(min_fence_num):
+			min = val;
+			if (vgt->state.gm.fence_sz < min) {
+				gvt_err("VM(%d): fence size(%x) is less than"
+						"its drivers minimum requirement(%x)!\n",
+						vgt->vm_id, vgt->state.gm.fence_sz, min);
+				rc = false;
+			}
+			break;
+		case _vgtif_reg(g2v_notify):
+				if (val == VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE) {
+					rc = gvt_g2v_create_ppgtt_mm(vgt, 3);
+				} else if (val == VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY) {
+					rc = gvt_g2v_destroy_ppgtt_mm(vgt, 3);
+				} else if (val == VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE) {
+					rc = gvt_g2v_create_ppgtt_mm(vgt, 4);
+				} else if (val == VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY) {
+					rc = gvt_g2v_destroy_ppgtt_mm(vgt, 4);
+				} else {
+					gvt_warn("Invalid PV notification. %x\n", val);
+				}
+			break;
+		case _vgtif_reg(pdp[0].lo):
+		case _vgtif_reg(pdp[0].hi):
+		case _vgtif_reg(pdp[1].lo):
+		case _vgtif_reg(pdp[1].hi):
+		case _vgtif_reg(pdp[2].lo):
+		case _vgtif_reg(pdp[2].hi):
+		case _vgtif_reg(pdp[3].lo):
+		case _vgtif_reg(pdp[3].hi):
+		case _vgtif_reg(execlist_context_descriptor_lo):
+		case _vgtif_reg(execlist_context_descriptor_hi):
+			break;
+
+		default:
+			/* keep rc's default value: true.
+			 * NOTE: returning false will crash the VM.
+			 */
+			gvt_warn("invalid pvinfo write: [%x:%x] = %x!!!\n",
+					offset, bytes, val);
+			break;
+	}
+
+	if (rc == true)
+		rc = gvt_default_mmio_write(vgt, offset, p_data, bytes);
+	return rc;
+}
+
+bool fpga_dbg_write(struct vgt_device *vgt, unsigned int reg,
+        void *p_data, unsigned int bytes)
+{
+        u32 v = *(u32 *)p_data;
+
+	if (v & FPGA_DBG_RM_NOCLAIM)
+		v &= ~ FPGA_DBG_RM_NOCLAIM;
+
+        return gvt_default_mmio_write(vgt, reg, &v, bytes);
+}
+
 struct gvt_reg_info gvt_general_reg_info[] = {
-{0, 0, 0, 0, 0, NULL, NULL},
+	/* Interrupt registers - GT */
+	{_RING_IMR(RENDER_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, gvt_reg_imr_handler},
+	{_RING_IMR(BLT_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, gvt_reg_imr_handler},
+	{_RING_IMR(GEN6_BSD_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, gvt_reg_imr_handler},
+	{_RING_IMR(VEBOX_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, gvt_reg_imr_handler},
+
+	/* Interrupt registers - PCH */
+	{_SDEIMR, 4, F_VIRT, 0, D_ALL, NULL, gvt_reg_imr_handler},
+	{_SDEIER, 4, F_VIRT, 0, D_ALL, NULL, gvt_reg_ier_handler},
+	{_SDEIIR, 4, F_VIRT, 0, D_ALL, NULL, gvt_reg_iir_handler},
+	{_SDEISR, 4, F_VIRT, 0, D_ALL, NULL, gvt_reg_isr_write},
+
+	/* -------render regs---------- */
+	{_RING_HWSTAM(RENDER_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_HWSTAM(BLT_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_HWSTAM(GEN6_BSD_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_HWSTAM(VEBOX_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+
+	{_RENDER_HWS_PGA_GEN7, 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+	{_BSD_HWS_PGA_GEN7, 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+	{_BLT_HWS_PGA_GEN7, 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+	{_VEBOX_HWS_PGA_GEN7, 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+
+	/* maybe an error in Linux driver. meant for VCS_HWS_PGA */
+	{_REG_RCS_EXCC, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_REG_VCS_EXCC, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_REG_BCS_EXCC, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_REG_RCS_UHPTR, 4, F_RDR_HWSTS, 0, D_ALL, NULL, NULL},
+	{_REG_VCS_UHPTR, 4, F_RDR_HWSTS, 0, D_ALL, NULL, NULL},
+	{_REG_BCS_UHPTR, 4, F_RDR_HWSTS, 0, D_ALL, NULL, NULL},
+	{_REG_VECS_UHPTR, 4, F_RDR_HWSTS, 0, D_ALL, NULL, NULL},
+	{_REG_RCS_BB_PREEMPT_ADDR, 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+
+	{0x12198, 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+
+	{_RING_TAIL(RENDER_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_HEAD(RENDER_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_START(RENDER_RING_BASE), 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL,
+		NULL, NULL},
+	{_RING_CTL(RENDER_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_ACTHD(RENDER_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+
+	{_RING_TAIL(GEN6_BSD_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_HEAD(GEN6_BSD_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_START(GEN6_BSD_RING_BASE), 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL,
+		NULL, NULL},
+	{_RING_CTL(GEN6_BSD_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_ACTHD(GEN6_BSD_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+
+	{_RING_TAIL(BLT_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_HEAD(BLT_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_START(BLT_RING_BASE), 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL,
+		NULL, NULL},
+	{_RING_CTL(BLT_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_ACTHD(BLT_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+
+	{_RING_TAIL(VEBOX_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_HEAD(VEBOX_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_START(VEBOX_RING_BASE), 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL,
+		NULL, NULL},
+	{_RING_CTL(VEBOX_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_RING_ACTHD(VEBOX_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, NULL},
+
+	{GVT_RING_MODE(RENDER_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, ring_mode_write},
+	{GVT_RING_MODE(BLT_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, ring_mode_write},
+	{GVT_RING_MODE(GEN6_BSD_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, ring_mode_write},
+	{GVT_RING_MODE(VEBOX_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, ring_mode_write},
+
+	{_RING_MI_MODE(RENDER_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{_RING_MI_MODE(BLT_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{_RING_MI_MODE(GEN6_BSD_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{_RING_MI_MODE(VEBOX_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+
+	{_RING_INSTPM(RENDER_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{_RING_INSTPM(BLT_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{_RING_INSTPM(GEN6_BSD_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{_RING_INSTPM(VEBOX_RING_BASE), 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+
+	{_GEN7_GT_MODE, 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{_CACHE_MODE_0_GEN7, 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{_CACHE_MODE_1, 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{_REG_RCS_BB_ADDR, 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+	{_REG_VCS_BB_ADDR, 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+	{_REG_BCS_BB_ADDR, 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+	{_REG_VECS_BB_ADDR, 4, F_RDR_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+
+	{0x2050, 4, F_PT, 0, D_ALL, NULL, NULL},
+	{0x12050, 4, F_PT, 0, D_ALL, NULL, NULL},
+	{0x22050, 4, F_PT, 0, D_ALL, NULL, NULL},
+	{0x1A050, 4, F_PT, 0, D_ALL, NULL, NULL},
+
+	{0x20dc, 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{__3D_CHICKEN3, 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{0x2088, 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{0x20e4, 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{_REG_VFSKPD, 4, F_RDR_MODE, 0, D_ALL, NULL, NULL},
+	{_GAM_ECOCHK, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_GEN7_COMMON_SLICE_CHICKEN1, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_COMMON_SLICE_CHICKEN2, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{0x9030, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{0x20a0, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_REG_RCS_TIMESTAMP, 8, F_PT, 0, D_ALL, NULL, NULL},
+	{_REG_VCS_TIMESTAMP, 8, F_PT, 0, D_ALL, NULL, NULL},
+	{0x1a358, 8, F_PT, 0, D_ALL, NULL, NULL},
+	{_REG_BCS_TIMESTAMP, 8, F_PT, 0, D_ALL, NULL, NULL},
+	{0x2420, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{0x2430, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{0x2434, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{0x2438, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{0x243c, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{0x7018, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{0xe184, 4, F_RDR, 0, D_ALL, NULL, NULL},
+
+	/* -------display regs---------- */
+	{0x60220, 0x20, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x602a0, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{0x65050, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x650b4, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{VGA_CR_INDEX_MDA, 1, F_DPY, 0, D_ALL, NULL, NULL},
+	{VGA_ST01_MDA, 1, F_DPY, 0, D_ALL, NULL, NULL},
+	{VGA_AR_INDEX, 1, F_DPY, 0, D_ALL, NULL, NULL},
+	{VGA_DACMASK, 1, F_DPY, 0, D_ALL, NULL, NULL},
+	{VGA_MSR_READ, 1, F_DPY, 0, D_ALL, NULL, NULL},
+	{_VGA0, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_VGA1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_VGA_PD, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{0x42080, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{0xc4040, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{_DERRMR, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{GVT_CURSURF(PIPE_A), 4, F_DPY_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+	{GVT_CURCNTR(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_CURPOS(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_CURSURFLIVE(PIPE_A), 4, F_DPY_HWSTS_ADRFIX, 0xFFFFF000, D_ALL, NULL,
+		mmio_not_allow_write},
+
+	{GVT_CURSURF(PIPE_B), 4, F_DPY_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+	{GVT_CURCNTR(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_CURPOS(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_CURSURFLIVE(PIPE_B), 4, F_DPY_HWSTS_ADRFIX, 0xFFFFF000, D_ALL, NULL,
+		mmio_not_allow_write},
+
+	{GVT_CURSURF(PIPE_C), 4, F_DPY_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
+	{GVT_CURCNTR(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_CURPOS(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_CURSURFLIVE(PIPE_C), 4, F_DPY_HWSTS_ADRFIX, 0xFFFFF000, D_ALL, NULL,
+		mmio_not_allow_write},
+
+	{_REG_CURAPALET_0, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_CURAPALET_1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_CURAPALET_2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_CURAPALET_3, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_LGC_PALETTE_A, 4 * 256, F_DPY, 0, D_ALL, NULL, NULL},
+	{_LGC_PALETTE_B, 4 * 256, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_LGC_PALETTE_C, 4 * 256, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{0x701b0, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{GVT_HTOTAL(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_HBLANK(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_HSYNC(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VTOTAL(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VBLANK(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VSYNC(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPESRC(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_BCLRPAT(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VSYNCSHIFT(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{GVT_HTOTAL(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_HBLANK(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_HSYNC(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VTOTAL(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VBLANK(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VSYNC(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPESRC(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_BCLRPAT(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VSYNCSHIFT(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{GVT_HTOTAL(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_HBLANK(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_HSYNC(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VTOTAL(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VBLANK(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VSYNC(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPESRC(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_BCLRPAT(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_VSYNCSHIFT(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{0x6F000, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6F004, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6F008, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6F00C, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6F010, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6F014, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6F028, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6F030, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6F034, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6F040, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6F044, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_PIPEA_DATA_M1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PIPEA_DATA_N1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PIPEA_LINK_M1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PIPEA_LINK_N1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_PIPEB_DATA_M1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PIPEB_DATA_N1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PIPEB_LINK_M1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PIPEB_LINK_N1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_REG_PIPEC_DATA_M1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PIPEC_DATA_N1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PIPEC_LINK_M1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PIPEC_LINK_N1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_PFA_CTL_1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PFA_WIN_SZ, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PFA_WIN_POS, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PFB_CTL_1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PFB_WIN_SZ, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PFB_WIN_POS, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PF_CTL_2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PF_WIN_SZ_2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PF_WIN_POS_2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_WM0_PIPEA_ILK, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_WM0_PIPEB_ILK, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_WM0_PIPEC_IVB, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_WM1_LP_ILK, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_WM2_LP_ILK, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_WM3_LP_ILK, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_WM1S_LP_ILK, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_WM2S_LP_IVB, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_WM3S_LP_IVB, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_REG_HISTOGRAM_THRSH, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_BLC_PWM_CPU_CTL2, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_BLC_PWM_CPU_CTL, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_BLC_PWM_PCH_CTL1, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_BLC_PWM_PCH_CTL2, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+
+	{_PCH_TRANS_HTOTAL_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_HBLANK_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_HSYNC_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_VTOTAL_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_VBLANK_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_VSYNC_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_VSYNCSHIFT_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_PCH_TRANS_HTOTAL_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_HBLANK_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_HSYNC_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_VTOTAL_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_VBLANK_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_VSYNC_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANS_VSYNCSHIFT_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_PCH_TRANSA_DATA_M1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANSA_DATA_N1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANSA_DATA_M2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANSA_DATA_N2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANSA_LINK_M1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANSA_LINK_N1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANSA_LINK_M2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_TRANSA_LINK_N2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_VIDEO_DIP_CTL_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_VIDEO_DIP_DATA_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_VIDEO_DIP_GCP_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANS_DP_CTL_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_VIDEO_DIP_CTL_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_VIDEO_DIP_DATA_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_VIDEO_DIP_GCP_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANS_DP_CTL_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_TRANSC_VIDEO_DIP_CTL, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_TRANSC_VIDEO_DIP_DATA, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_TRANSC_VIDEO_DIP_GCP, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANS_DP_CTL_C, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_FDI_RXA_MISC, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_FDI_RXB_MISC, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_FDI_RXA_TUSIZE1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_FDI_RXA_TUSIZE2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_FDI_RXB_TUSIZE1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_FDI_RXB_TUSIZE2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_PCH_LVDS, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_DPLL_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_DPLL_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_FPA0, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_FPA1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_FPB0, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_FPB1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_DREF_CONTROL, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_RAWCLK_FREQ, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_DPLL_SEL, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	/* Linux defines as PP_ON_DEPLAY/PP_OFF_DELAY. Not in spec */
+	{0x61208, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6120c, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_PP_ON_DELAYS, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_PP_OFF_DELAYS, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_FUSE_STRAP, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_DIGITAL_PORT_HOTPLUG_CNTRL, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_DISP_ARB_CTL, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_DISP_ARB_CTL2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_ILK_DISPLAY_CHICKEN1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_ILK_DISPLAY_CHICKEN2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_ILK_DSPCLK_GATE_D, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_TRANSA_CHICKEN1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANSB_CHICKEN1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_SOUTH_DSPCLK_GATE_D, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANSA_CHICKEN2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANSB_CHICKEN2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	/*
+	 * framebuffer compression is disabled for now
+	 * until it's handled at display context switch
+	 * and we figure out how stolen memory should be virtualized (FBC needs use
+	 * stolen memory).
+	 */
+	{_REG_DPFC_CB_BASE, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{_REG_DPFC_CONTROL, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{_REG_DPFC_RECOMP_CTL, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{_REG_DPFC_CPU_FENCE_OFFSET, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{_REG_DPFC_CONTROL_SA, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{_REG_DPFC_CPU_FENCE_OFFSET_SA, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{_IPS_CTL, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+
+	{_REG_CSC_A_COEFFICIENTS, 4*6, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_CSC_A_MODE, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PRECSC_A_HIGH_COLOR_CHANNEL_OFFSET, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PRECSC_A_MEDIUM_COLOR_CHANNEL_OFFSET, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PRECSC_A_LOW_COLOR_CHANNEL_OFFSET, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_REG_CSC_B_COEFFICIENTS, 4*6, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_CSC_B_MODE, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PRECSC_B_HIGH_COLOR_CHANNEL_OFFSET, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PRECSC_B_MEDIUM_COLOR_CHANNEL_OFFSET, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PRECSC_B_LOW_COLOR_CHANNEL_OFFSET, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_REG_CSC_C_COEFFICIENTS, 4*6, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_CSC_C_MODE, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PRECSC_C_HIGH_COLOR_CHANNEL_OFFSET, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PRECSC_C_MEDIUM_COLOR_CHANNEL_OFFSET, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PRECSC_C_LOW_COLOR_CHANNEL_OFFSET, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{0x60110, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x61110, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x70400, 0x40, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x71400, 0x40, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x72400, 0x40, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{0x70440, 0xc, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x71440, 0xc, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x72440, 0xc, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{0x7044c, 0xc, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x7144c, 0xc, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x7244c, 0xc, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_PIPE_WM_LINETIME_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PIPE_WM_LINETIME_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x45278, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_SPLL_CTL, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_WRPLL_CTL1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_WRPLL_CTL2, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PORT_CLK_SEL_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PORT_CLK_SEL_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PORT_CLK_SEL_DDIC, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PORT_CLK_SEL_DDID, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_PORT_CLK_SEL_DDIE, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANS_CLK_SEL_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANS_CLK_SEL_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_TRANS_CLK_SEL_C, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x46408, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x46508, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x49040, 0xc, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x49140, 0xc, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x49240, 0xc, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x49080, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x49090, 0x14, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x49180, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x49190, 0x14, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x49280, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x49290, 0x14, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x4A400, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x4A480, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x4AC00, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x4AC80, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x4B400, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x4B480, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{0x6002C, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_HSW_VIDEO_DIP_CTL_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_HSW_VIDEO_DIP_CTL_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_HSW_VIDEO_DIP_CTL_C, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_REG_HSW_VIDEO_DIP_CTL_EDP, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_SFUSE_STRAP, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_SBI_ADDR, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PIXCLK_GATE, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{0x64E60, 0x50, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x64Ec0, 0x50, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x64F20, 0x50, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x64F80, 0x50, F_DPY, 0, D_ALL, NULL, NULL},
+	{_HSW_AUD_CONFIG_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x650C0, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_TRANS_DDI_FUNC_CTL_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANS_DDI_FUNC_CTL_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANS_DDI_FUNC_CTL_C, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANS_DDI_FUNC_CTL_EDP, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_TRANSA_MSA_MISC, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANSB_MSA_MISC, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_TRANSC_MSA_MISC, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{0x6F410, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	/* -------others---------- */
+	{_FORCEWAKE_MT, 4, F_VIRT, 0, D_ALL, NULL, mt_force_wake_write},
+	{_FORCEWAKE_ACK_HSW, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{_ECOBUS, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC_CONTROL, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC_STATE, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RPNSWREQ, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC_VIDEO_FREQ, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_DOWN_TIMEOUT, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_INTERRUPT_LIMITS, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RPSTAT1, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_CONTROL, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_UP_THRESHOLD, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_DOWN_THRESHOLD, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_CUR_UP_EI, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_CUR_UP, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_PREV_UP, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_CUR_DOWN_EI, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_CUR_DOWN, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_PREV_DOWN, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_UP_EI, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_DOWN_EI, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RP_IDLE_HYSTERSIS, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC1_WAKE_RATE_LIMIT, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC6_WAKE_RATE_LIMIT, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC6pp_WAKE_RATE_LIMIT, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC_EVALUATION_INTERVAL, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC_IDLE_HYSTERSIS, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC_SLEEP, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC1e_THRESHOLD, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC6_THRESHOLD, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC6p_THRESHOLD, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_RC6pp_THRESHOLD, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_PMINTRMSK, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_GDRST, 4, F_DOM0, 0, D_ALL, NULL, gdrst_mmio_write},
+
+	{0x100000, 0x80, F_VIRT, 0, D_ALL, fence_mmio_read, fence_mmio_write},
+	{VGT_PVINFO_PAGE, VGT_PVINFO_SIZE, F_VIRT, 0, D_ALL, pvinfo_read, pvinfo_write},
+
+	/* TODO: MCHBAR, suppose read-only */
+	{MCHBAR_MIRROR_BASE_SNB, 0x40000, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{_TILECTL, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+
+	{_GEN6_UCGCTL1, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_UCGCTL2, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+
+	{_REG_SWF, 0x90, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{_GEN6_PCODE_MAILBOX, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN6_PCODE_DATA, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{0x13812c, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GEN7_ERR_INT, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0x120010, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0x9008, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{_GFX_FLSH_CNTL_GEN6, 4, F_PT, 0, D_ALL, NULL, NULL},
+
+	/* -------un-categorized regs--------- */
+	{0x3c, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{0x860, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	/* no definition on this. from Linux */
+	{_ECOSKPD, 4, F_PT, 0, D_ALL, NULL, NULL},
+	{0x121d0, 4, F_PT, 0, D_ALL, NULL, NULL},
+	{_GEN6_BLITTER_ECOSKPD, 4, F_PT, 0, D_ALL, NULL, NULL},
+	{0x41d0, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{_GAC_ECO_BITS, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{_REG_2D_CG_DIS, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{_REG_3D_CG_DIS, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{_REG_3D_CG_DIS2, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0x7118, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0x7180, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0x7408, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0x7c00, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{_GEN6_MBCTL, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0x911c, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0x9120, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{_GAB_CTL, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0x48800, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xce044, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xe6500, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xe6504, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xe6600, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xe6604, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xe6700, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xe6704, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xe6800, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xe6804, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{_REG_SUPER_QUEUE_CONFIG, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec008, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec00c, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec008+0x18, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec00c+0x18, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec008+0x18*2, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec00c+0x18*2, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec008+0x18*3, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec00c+0x18*3, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec408, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec40c, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec408+0x18, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec40c+0x18, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec408+0x18*2, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec40c+0x18*2, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec408+0x18*3, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xec40c+0x18*3, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfc810, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfc81c, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfc828, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfc834, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfcc00, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfcc0c, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfcc18, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfcc24, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfd000, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfd00c, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfd018, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfd024, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	{0xfd034, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	/* MAXCNT means max idle count */
+	{_REG_RC_PWRCTX_MAXCNT, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{0x12054, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{0x22054, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+	{0x1A054, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+
+	{0x44070, 4, F_DOM0, 0, D_ALL, NULL, NULL},
+
+	{_FPGA_DBG, 4, F_VIRT, 0, D_ALL, NULL, fpga_dbg_write},
+	{_GEN6_GT_THREAD_STATUS_REG, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	/*command accessed registers, supplement for reg audit in cmd parser*/
+	{0x2178, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{0x217c, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{0x12178, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{0x1217c, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_BCS_SWCTRL, 4, F_RDR, 0, D_ALL, NULL, NULL},
+	{_HS_INVOCATION_COUNT, 8, F_RDR, 0, D_ALL, NULL, NULL},
+	{_DS_INVOCATION_COUNT, 8, F_RDR, 0, D_ALL, NULL, NULL},
+	{_IA_VERTICES_COUNT  , 8, F_RDR, 0, D_ALL, NULL, NULL},
+	{_IA_PRIMITIVES_COUNT, 8, F_RDR, 0, D_ALL, NULL, NULL},
+	{_VS_INVOCATION_COUNT, 8, F_RDR, 0, D_ALL, NULL, NULL},
+	{_GS_INVOCATION_COUNT, 8, F_RDR, 0, D_ALL, NULL, NULL},
+	{_GS_PRIMITIVES_COUNT, 8, F_RDR, 0, D_ALL, NULL, NULL},
+	{_CL_INVOCATION_COUNT, 8, F_RDR, 0, D_ALL, NULL, NULL},
+	{_CL_PRIMITIVES_COUNT, 8, F_RDR, 0, D_ALL, NULL, NULL},
+	{_PS_INVOCATION_COUNT, 8, F_RDR, 0, D_ALL, NULL, NULL},
+	{_PS_DEPTH_COUNT, 8, F_RDR, 0, D_ALL, NULL, NULL},
+
+	/* BDW */
+	{0xe100, 4, F_RDR, 0, D_ALL, NULL, NULL},
 };
 
 struct gvt_reg_info gvt_broadwell_reg_info[] = {
-{0, 0, 0, 0, 0, NULL, NULL},
+	/* Interrupt registers - GT */
+	{_RING_IMR(GEN8_BSD2_RING_BASE), 4, F_RDR, 0, D_BDW_PLUS, NULL, gvt_reg_imr_handler},
+
+	/* Interrupt registers - BDW */
+	{_REG_GT_IMR(0), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_imr_handler},
+	{_REG_GT_IER(0), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_ier_handler},
+	{_REG_GT_IIR(0), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_iir_handler},
+	{_REG_GT_ISR(0), 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_GT_IMR(1), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_imr_handler},
+	{_REG_GT_IER(1), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_ier_handler},
+	{_REG_GT_IIR(1), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_iir_handler},
+	{_REG_GT_ISR(1), 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_GT_IMR(2), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_imr_handler},
+	{_REG_GT_IER(2), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_ier_handler},
+	{_REG_GT_IIR(2), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_iir_handler},
+	{_REG_GT_ISR(2), 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_GT_IMR(3), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_imr_handler},
+	{_REG_GT_IER(3), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_ier_handler},
+	{_REG_GT_IIR(3), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_iir_handler},
+	{_REG_GT_ISR(3), 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_DE_PIPE_IMR(PIPE_A), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_imr_handler},
+	{_REG_DE_PIPE_IER(PIPE_A), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_ier_handler},
+	{_REG_DE_PIPE_IIR(PIPE_A), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_iir_handler},
+	{_REG_DE_PIPE_ISR(PIPE_A), 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_DE_PIPE_IMR(PIPE_B), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_imr_handler},
+	{_REG_DE_PIPE_IER(PIPE_B), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_ier_handler},
+	{_REG_DE_PIPE_IIR(PIPE_B), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_iir_handler},
+	{_REG_DE_PIPE_ISR(PIPE_B), 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_DE_PIPE_IMR(PIPE_C), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_imr_handler},
+	{_REG_DE_PIPE_IER(PIPE_C), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_ier_handler},
+	{_REG_DE_PIPE_IIR(PIPE_C), 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_iir_handler},
+	{_REG_DE_PIPE_ISR(PIPE_C), 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_GEN8_DE_PORT_IMR, 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_imr_handler},
+	{_GEN8_DE_PORT_IER, 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_ier_handler},
+	{_GEN8_DE_PORT_IIR, 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_iir_handler},
+	{_GEN8_DE_PORT_ISR, 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_GEN8_DE_MISC_IMR, 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_imr_handler},
+	{_GEN8_DE_MISC_IER, 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_ier_handler},
+	{_GEN8_DE_MISC_IIR, 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_iir_handler},
+	{_GEN8_DE_MISC_ISR, 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_GEN8_PCU_IMR, 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_imr_handler},
+	{_GEN8_PCU_IER, 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_ier_handler},
+	{_GEN8_PCU_IIR, 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_iir_handler},
+	{_GEN8_PCU_ISR, 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_GEN8_MASTER_IRQ, 4, F_VIRT, 0, D_BDW_PLUS, NULL, gvt_reg_master_irq_handler},
+
+	/* -------render regs---------- */
+	{_RING_HWSTAM(GEN8_BSD2_RING_BASE), 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+
+	/* maybe an error in Linux driver. meant for VCS_HWS_PGA */
+	{_REG_VCS2_UHPTR, 4, F_RDR_HWSTS, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_RING_TAIL(GEN8_BSD2_RING_BASE), 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{_RING_HEAD(GEN8_BSD2_RING_BASE), 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{_RING_START(GEN8_BSD2_RING_BASE), 4, F_RDR_ADRFIX, 0xFFFFF000, D_BDW_PLUS,
+		NULL, NULL},
+	{_RING_CTL(GEN8_BSD2_RING_BASE), 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{_RING_ACTHD(GEN8_BSD2_RING_BASE), 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{GVT_RING_MODE(GEN8_BSD2_RING_BASE), 4, F_RDR_MODE, 0, D_BDW_PLUS, NULL, ring_mode_write},
+	{_RING_MI_MODE(GEN8_BSD2_RING_BASE), 4, F_RDR_MODE, 0, D_BDW_PLUS, NULL, NULL},
+	{_RING_INSTPM(GEN8_BSD2_RING_BASE), 4, F_RDR_MODE, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_RCS_ACTHD_UDW, 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_BCS_ACTHD_UDW, 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS_ACTHD_UDW, 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS2_ACTHD_UDW, 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VECS_ACTHD_UDW, 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+
+	/* TODO: need a handler */
+	{0x1c050, 4, F_PT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VCS2_TIMESTAMP, 8, F_PT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_RCS_EXECLIST_SUBMITPORT, 4, F_VIRT, 0, D_BDW_PLUS,
+		mmio_not_allow_read, NULL},
+	{_REG_VCS_EXECLIST_SUBMITPORT, 4, F_VIRT, 0, D_BDW_PLUS,
+		mmio_not_allow_read, NULL},
+	{_REG_VECS_EXECLIST_SUBMITPORT, 4, F_VIRT, 0, D_BDW_PLUS,
+		mmio_not_allow_read, NULL},
+	{_REG_VCS2_EXECLIST_SUBMITPORT, 4, F_VIRT, 0, D_BDW_PLUS,
+		mmio_not_allow_read, NULL},
+	{_REG_BCS_EXECLIST_SUBMITPORT, 4, F_VIRT, 0, D_BDW_PLUS,
+		mmio_not_allow_read, NULL},
+
+	{_REG_RCS_EXECLIST_STATUS, 8, F_RDR, 0, D_BDW_PLUS, NULL,
+		mmio_not_allow_write},
+	{_REG_VCS_EXECLIST_STATUS, 8, F_RDR, 0, D_BDW_PLUS, NULL,
+		mmio_not_allow_write},
+	{_REG_VECS_EXECLIST_STATUS, 8, F_RDR, 0, D_BDW_PLUS, NULL,
+		mmio_not_allow_write},
+	{_REG_VCS2_EXECLIST_STATUS, 8, F_RDR, 0, D_BDW_PLUS, NULL,
+		mmio_not_allow_write},
+	{_REG_BCS_EXECLIST_STATUS, 8, F_RDR, 0, D_BDW_PLUS, NULL,
+		mmio_not_allow_write},
+
+	{_REG_RCS_CTX_SR_CTL, 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS_CTX_SR_CTL, 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VECS_CTX_SR_CTL, 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS2_CTX_SR_CTL, 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_BCS_CTX_SR_CTL, 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_RCS_CTX_STATUS_BUF, 48, F_VIRT, 0, D_BDW_PLUS, NULL,
+		mmio_not_allow_write},
+	{_REG_VCS_CTX_STATUS_BUF, 48, F_VIRT, 0, D_BDW_PLUS, NULL,
+		mmio_not_allow_write},
+	{_REG_VECS_CTX_STATUS_BUF, 48, F_VIRT, 0, D_BDW_PLUS, NULL,
+		mmio_not_allow_write},
+	{_REG_VCS2_CTX_STATUS_BUF, 48, F_VIRT, 0, D_BDW_PLUS, NULL,
+		mmio_not_allow_write},
+	{_REG_BCS_CTX_STATUS_BUF, 48, F_VIRT, 0, D_BDW_PLUS, NULL,
+		mmio_not_allow_write},
+
+	{_REG_RCS_CTX_STATUS_PTR, 4, F_VIRT | GVT_REG_MODE_CTL, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS_CTX_STATUS_PTR, 4, F_VIRT | GVT_REG_MODE_CTL, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VECS_CTX_STATUS_PTR, 4, F_VIRT | GVT_REG_MODE_CTL, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS2_CTX_STATUS_PTR, 4, F_VIRT | GVT_REG_MODE_CTL, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_BCS_CTX_STATUS_PTR, 4, F_VIRT | GVT_REG_MODE_CTL, 0, D_BDW_PLUS, NULL, NULL},
+	/* -------display regs---------- */
+
+	{_PIPE_MISC_A, 4, F_DPY, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_PIPE_MISC_B, 4, F_DPY, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_PIPE_MISC_C, 4, F_DPY, 0, D_BDW_PLUS, NULL, NULL},
+
+	/* -------others---------- */
+
+	/* -------un-categorized regs--------- */
+	/* no definition on this. from Linux */
+	{0x1c1d0, 4, F_PT, 0, D_BDW_PLUS, NULL, NULL},
+	{_GEN6_MBCUNIT_SNPCR, 4, F_PT, 0, D_BDW_PLUS, NULL, NULL},
+	{_GEN7_MISCCPCTL, 4, F_PT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{0x1C054, 4, F_DOM0, 0, D_BDW_PLUS, NULL, NULL},
+	/* BDW */
+	{_GEN8_PRIVATE_PAT_LO, 4, F_PT, 0, D_BDW_PLUS, NULL, NULL},
+	{_GEN8_PRIVATE_PAT_HI, 4, F_PT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_GAMTARBMODE, 4, F_DOM0, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_RCS_PDP_UDW(0) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_RCS_PDP_LDW(0) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_RCS_PDP_UDW(1) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_RCS_PDP_LDW(1) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_RCS_PDP_UDW(2) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_RCS_PDP_LDW(2) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_RCS_PDP_UDW(3) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_RCS_PDP_LDW(3) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VCS_PDP_UDW(0) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS_PDP_LDW(0) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VCS_PDP_UDW(1) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS_PDP_LDW(1) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VCS_PDP_UDW(2) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS_PDP_LDW(2) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VCS_PDP_UDW(3) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS_PDP_LDW(3) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VECS_PDP_UDW(0) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VECS_PDP_LDW(0) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VECS_PDP_UDW(1) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VECS_PDP_LDW(1) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VECS_PDP_UDW(2) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VECS_PDP_LDW(2) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VECS_PDP_UDW(3) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VECS_PDP_LDW(3) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VCS2_PDP_UDW(0) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS2_PDP_LDW(0) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VCS2_PDP_UDW(1) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS2_PDP_LDW(1) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VCS2_PDP_UDW(2) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS2_PDP_LDW(2) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_VCS2_PDP_UDW(3) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_VCS2_PDP_LDW(3) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_BCS_PDP_UDW(0) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_BCS_PDP_LDW(0) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_BCS_PDP_UDW(1) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_BCS_PDP_LDW(1) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_BCS_PDP_UDW(2) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_BCS_PDP_LDW(2) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{_REG_BCS_PDP_UDW(3) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{_REG_BCS_PDP_LDW(3) , 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+
+	{0x2080, 4, F_RDR_ADRFIX, 0xFFFFF000, D_BDW_PLUS, NULL, NULL},
+	{0x12080, 4, F_RDR_ADRFIX, 0xFFFFF000, D_BDW_PLUS, NULL, NULL},
+	{0x1c080, 4, F_RDR_ADRFIX, 0xFFFFF000, D_BDW_PLUS, NULL, NULL},
+	{0x1a080, 4, F_RDR_ADRFIX, 0xFFFFF000, D_BDW_PLUS, NULL, NULL},
+	{0x22080, 4, F_RDR_ADRFIX, 0xFFFFF000, D_BDW_PLUS, NULL, NULL},
+
+	{0x7300, 4, F_RDR, 0, D_BDW_PLUS, NULL, NULL},
+
+	{0x420b0, 4, F_DPY, 0, D_BDW, NULL, NULL},
+	{0x420b4, 4, F_DPY, 0, D_BDW, NULL, NULL},
+	{0x420b8, 4, F_DPY, 0, D_BDW, NULL, NULL},
+
+	{0x45260, 4, F_DPY, 0, D_BDW, NULL, NULL},
+	{0x6f800, 4, F_DPY, 0, D_BDW, NULL, NULL},
+
+	{0x66c00, 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
+	{0x66c04, 4, F_VIRT, 0, D_BDW, NULL, NULL},
+
+	{0x4024, 4, F_DOM0, 0, D_BDW, NULL, NULL},
+
+	{0x9134, 4, F_VIRT, 0, D_BDW, NULL, NULL},
+	{0x9138, 4, F_VIRT, 0, D_BDW, NULL, NULL},
+	{0x913c, 4, F_VIRT, 0, D_BDW, NULL, NULL},
+
+	/* WA */
+	{0xfdc, 4, F_DOM0, 0, D_BDW, NULL, NULL},
+	{0xe4f0, 4, F_RDR, 0, D_BDW, NULL, NULL},
+	{0xe4f4, 4, F_RDR, 0, D_BDW, NULL, NULL},
+	{0x9430, 4, F_RDR, 0, D_BDW, NULL, NULL},
+
+	/* L3 */
+	{0xb1f0, 4, F_RDR, 0, D_BDW, NULL, NULL},
+	{0xb1c0, 4, F_RDR, 0, D_BDW, NULL, NULL},
+	{0xb118, 4, F_RDR, 0, D_BDW, NULL, NULL},
+	{0xb100, 4, F_RDR, 0, D_BDW, NULL, NULL},
+	{0xb10c, 4, F_RDR, 0, D_BDW, NULL, NULL},
+	{0xb110, 4, F_PT, 0, D_BDW, NULL, NULL},
+
+	/* NON-PRIV */
+	{0x24d0, 4, F_RDR, 0, D_BDW, NULL, NULL},
+	{0x24d4, 4, F_RDR, 0, D_BDW, NULL, NULL},
+	{0x24d8, 4, F_RDR, 0, D_BDW, NULL, NULL},
+	{0x24dc, 4, F_RDR, 0, D_BDW, NULL, NULL},
+
+	{0x83a4, 4, F_RDR, 0, D_BDW, NULL, NULL},
+	{0x4dd4, 4, F_PT, 0, D_BDW, NULL, NULL},
+
+	/* UCG */
+	{0x8430, 4, F_PT, 0, D_BDW, NULL, NULL},
+
+	{0x110000, 4, F_VIRT, 0, D_BDW_PLUS, NULL, NULL},
 };
 
 int gvt_get_reg_num(int type)
 {
-        switch(type){
+        switch (type) {
                 case D_ALL:
                         return ARRAY_SIZE(gvt_general_reg_info);
                 case D_BDW:
@@ -42,6 +1131,5 @@ int gvt_get_reg_num(int type)
                 default:
 			return 0;
         }
-
         return 0;
 }
diff --git a/drivers/gpu/drm/i915/gvt/instance.c b/drivers/gpu/drm/i915/gvt/instance.c
index 91f52c6..0bf62e4 100644
--- a/drivers/gpu/drm/i915/gvt/instance.c
+++ b/drivers/gpu/drm/i915/gvt/instance.c
@@ -228,6 +228,8 @@ struct vgt_device *gvt_create_instance(struct pgt_device *pdev,
 	vgt->id = id;
 	vgt->pdev = pdev;
 
+	vgt->warn_untrack = true;
+
 	if (!create_virtual_device_state(vgt, info))
 		goto err;
 
diff --git a/drivers/gpu/drm/i915/gvt/interrupt.h b/drivers/gpu/drm/i915/gvt/interrupt.h
index cee85b6..3142ed6 100644
--- a/drivers/gpu/drm/i915/gvt/interrupt.h
+++ b/drivers/gpu/drm/i915/gvt/interrupt.h
@@ -229,4 +229,18 @@ struct gvt_irq_state {
 bool gvt_irq_init(struct pgt_device *pdev);
 void gvt_irq_exit(struct pgt_device *pdev);
 
+bool gvt_reg_imr_handler(struct vgt_device *vgt,
+	unsigned int reg, void *p_data, unsigned int bytes);
+bool gvt_reg_ier_handler(struct vgt_device *vgt,
+	unsigned int reg, void *p_data, unsigned int bytes);
+bool gvt_reg_iir_handler(struct vgt_device *vgt, unsigned int reg,
+	void *p_data, unsigned int bytes);
+bool gvt_reg_isr_write(struct vgt_device *vgt, unsigned int reg,
+	void *p_data, unsigned int bytes);
+bool gvt_reg_master_irq_handler(struct vgt_device *vgt,
+	unsigned int reg, void *p_data, unsigned int bytes);
+void gvt_trigger_virtual_event(struct vgt_device *vgt,
+	enum gvt_event_type event);
+void gvt_inject_flip_done(struct vgt_device *vgt, int pipe);
+
 #endif /* _GVT_INTERRUPT_H_ */
diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c
index 3297d82..e83ad1e 100644
--- a/drivers/gpu/drm/i915/gvt/mmio.c
+++ b/drivers/gpu/drm/i915/gvt/mmio.c
@@ -23,7 +23,7 @@
 
 #include "gvt.h"
 
-static inline unsigned int get_device_type(struct pgt_device *pdev)
+unsigned int gvt_get_device_type(struct pgt_device *pdev)
 {
 	if (IS_BROADWELL(pdev->dev_priv))
 		return D_BDW;
@@ -32,7 +32,7 @@ static inline unsigned int get_device_type(struct pgt_device *pdev)
 
 static inline bool match_device(struct pgt_device *pdev, struct gvt_reg_info *info)
 {
-	return info->device & get_device_type(pdev);
+	return info->device & gvt_get_device_type(pdev);
 }
 
 static void save_initial_mmio_state(struct pgt_device *pdev,
@@ -514,3 +514,32 @@ err:
        mutex_unlock(&pdev->lock);
        return false;
 }
+
+static unsigned long ring_mmio_base[] = {
+	[RCS] = RENDER_RING_BASE,
+	[BCS] = BLT_RING_BASE,
+	[VCS] = GEN6_BSD_RING_BASE,
+	[VECS] = VEBOX_RING_BASE,
+	[VCS2] = GEN8_BSD2_RING_BASE,
+};
+
+int gvt_render_mmio_to_ring_id(unsigned int reg)
+{
+	int i;
+
+	reg &= ~0xfff;
+
+	for (i = 0; i < ARRAY_SIZE(ring_mmio_base); i++) {
+		if (ring_mmio_base[i] == reg)
+			return i;
+	}
+
+	ASSERT(0);
+	return -1;
+}
+
+int gvt_ring_id_to_render_mmio_base(int ring_id)
+{
+	ASSERT(ring_id >= 0 && ring_id < (ARRAY_SIZE(ring_mmio_base)));
+	return ring_mmio_base[ring_id];
+}
diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h
index 4301655..71ae47b 100644
--- a/drivers/gpu/drm/i915/gvt/mmio.h
+++ b/drivers/gpu/drm/i915/gvt/mmio.h
@@ -48,6 +48,18 @@
 
 #define GVT_AUX_TABLE_NUM	256
 
+#define F_VIRT			GVT_REG_VIRT
+
+#define F_DOM0			F_VIRT
+#define F_RDR			F_VIRT
+#define F_RDR_ADRFIX		F_VIRT
+#define F_RDR_HWSTS		F_VIRT
+#define F_RDR_MODE		F_VIRT
+#define F_DPY			F_VIRT
+#define F_DPY_ADRFIX		F_VIRT
+#define F_DPY_HWSTS_ADRFIX	F_VIRT
+#define F_PT			F_VIRT
+
 /* suppose a reg won't set both bits */
 typedef union {
 	struct {
@@ -81,11 +93,13 @@ struct gvt_reg_info {
 	gvt_mmio_handler_t write;
 };
 
+struct pgt_device;
+
 extern struct gvt_reg_info gvt_general_reg_info[];
 extern struct gvt_reg_info gvt_broadwell_reg_info[];
 extern int gvt_get_reg_num(int type);
+extern unsigned int gvt_get_device_type(struct pgt_device *pdev);
 
 bool gvt_emulate_mmio_read(struct vgt_device *vgt, uint64_t pa, void *p_data,int bytes);
 bool gvt_emulate_mmio_write(struct vgt_device *vgt, uint64_t pa, void *p_data,int bytes);
-
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
index c66a2dc..1758092 100644
--- a/drivers/gpu/drm/i915/gvt/reg.h
+++ b/drivers/gpu/drm/i915/gvt/reg.h
@@ -68,6 +68,107 @@
 #define    _REGBIT_BDW_GMCH_GMS_SHIFT   8
 #define    _REGBIT_BDW_GMCH_GMS_MASK    0xff
 
+#define _GVT_MMIO_THROUGH_OFFSET(index, a, b)	((a) + (index)*((b)-(a)))
+#define _GVT_MMIO_GET_INDEX(reg, a, b)		(((reg)-(a))/((b)-(a)))
+
+#define _GVT_GET_PIPE(reg, a, b)	_GVT_MMIO_GET_INDEX(reg, a, b)
+#define _GVT_GET_PORT(reg, a, b)	_GVT_MMIO_GET_INDEX(reg, a, b)
+
+#define _REG_GAC_MODE		0x120A0
+#define _REG_GAB_MODE		0x220A0
+
+#define _REG_RCS_BB_ADDR	0x2140
+#define _REG_VCS_BB_ADDR	0x12140
+#define _REG_BCS_BB_ADDR	0x22140
+#define _REG_VECS_BB_ADDR	0x1A140
+#define _REG_VCS2_BB_ADDR	0x1c140
+
+#define _REG_VECS_CTX_WA_BB_ADDR 0x1A144
+
+#define _REG_RCS_EXCC		0x2028
+#define _REG_VCS_EXCC		0x12028
+#define _REG_BCS_EXCC		0x22028
+#define _REG_VECS_EXCC		0x1A028
+#define _REG_VCS2_EXCC		0x1c028
+
+#define _REG_RCS_UHPTR		0x2134
+#define _REG_VCS_UHPTR		0x12134
+#define _REG_BCS_UHPTR		0x22134
+#define _REG_VECS_UHPTR		0x1A134
+#define _REG_VCS2_UHPTR		0x1c134
+
+#define _REG_RCS_ACTHD_UDW	0x205c
+#define _REG_VCS_ACTHD_UDW	0x1205c
+#define _REG_BCS_ACTHD_UDW	0x2205c
+#define _REG_VECS_ACTHD_UDW	0x1A05c
+#define _REG_VCS2_ACTHD_UDW	0x1c05c
+
+#define _REG_RCS_BB_PREEMPT_ADDR	0x2148
+#define _REG_RCS_BB_ADDR_DIFF		0x2154
+
+#define _REG_RCS_TIMESTAMP	0x2358
+#define _REG_VCS_TIMESTAMP	0x12358
+#define _REG_VCS2_TIMESTAMP	0x1c358
+#define _REG_BCS_TIMESTAMP	0x22358
+
+#define GVT_RING_MODE(base) (base + 0x29c)
+
+#define RB_HEAD_OFF_MASK        ((1U << 21) - (1U << 2))
+#define RB_TAIL_OFF_MASK       ((1U << 21) - (1U << 3))        /* bit 3 to 20 */
+#define RB_TAIL_SIZE_MASK      ((1U << 21) - (1U << 12))       /* bit 12 to 20 */
+#define _RING_CTL_BUF_SIZE(ctl)        (((ctl) & RB_TAIL_SIZE_MASK) + GTT_PAGE_SIZE)
+
+#define _EL_BASE_RCS		0x02000
+#define _EL_BASE_VCS		0x12000
+#define _EL_BASE_VECS		0x1A000
+#define _EL_BASE_VCS2		0x1C000
+#define _EL_BASE_BCS		0x22000
+
+#define _EL_OFFSET_SUBMITPORT	0x230
+#define _EL_OFFSET_STATUS	0x234
+#define _EL_OFFSET_SR_CTL	0x244
+#define _EL_OFFSET_STATUS_BUF	0x370
+#define _EL_OFFSET_STATUS_PTR	0x3A0
+
+#define _REG_RCS_EXECLIST_SUBMITPORT	0x02230
+#define _REG_VCS_EXECLIST_SUBMITPORT	0x12230
+#define _REG_VECS_EXECLIST_SUBMITPORT	0x1A230
+#define _REG_VCS2_EXECLIST_SUBMITPORT	0x1C230
+#define _REG_BCS_EXECLIST_SUBMITPORT	0x22230
+
+#define _EXECLIST_LRCA_MASK		0xfffff000
+
+#define _REG_RCS_EXECLIST_STATUS	0x02234
+#define _REG_VCS_EXECLIST_STATUS	0x12234
+#define _REG_VECS_EXECLIST_STATUS	0x1A234
+#define _REG_VCS2_EXECLIST_STATUS	0x1C234
+#define _REG_BCS_EXECLIST_STATUS	0x22234
+
+#define _REG_RCS_CTX_SR_CTL	0x02244
+#define _REG_VCS_CTX_SR_CTL	0x12244
+#define _REG_VECS_CTX_SR_CTL	0x1A244
+#define _REG_VCS2_CTX_SR_CTL	0x1C244
+#define _REG_BCS_CTX_SR_CTL	0x22244
+
+#define _REG_RCS_CTX_STATUS_BUF		0x02370
+#define _REG_VCS_CTX_STATUS_BUF		0x12370
+#define _REG_VECS_CTX_STATUS_BUF	0x1A370
+#define _REG_VCS2_CTX_STATUS_BUF	0x1C370
+#define _REG_BCS_CTX_STATUS_BUF		0x22370
+
+#define _REG_RCS_CTX_STATUS_PTR		0x023A0
+#define _REG_VCS_CTX_STATUS_PTR		0x123A0
+#define _REG_VECS_CTX_STATUS_PTR	0x1A3A0
+#define _REG_VCS2_CTX_STATUS_PTR	0x1C3A0
+#define _REG_BCS_CTX_STATUS_PTR		0x223A0
+
+#define _REG_CURASURFLIVE	0x700AC
+
+#define _REG_CURAPALET_0	0x70090
+#define _REG_CURAPALET_1	0x70094
+#define _REG_CURAPALET_2	0x70098
+#define _REG_CURAPALET_3	0x7009C
+
 #define	_PRI_PLANE_FMT_SHIFT	26
 #define	_PRI_PLANE_TILE_SHIFT	10
 
@@ -475,6 +576,80 @@ union _TRANS_CONFIG
 #define _GEN6_GT_THREAD_STATUS_REG	0x13805c
 #define _GEN6_GT_CORE_STATUS		0x138060
 
+#define _FORCEWAKE_MT			0xa188
+#define _FORCEWAKE_ACK_HSW		0x130044
+#define _SBI_ADDR			0xC6000
+#define _SBI_DATA			0xC6004
+#define _SBI_CTL_STAT			0xC6008
+
+#define _RING_IMR(base)			((base) + 0xa8)
+#define _SPLL_CTL			0x46020
+#define _SFUSE_STRAP			0xc2014
+#define _PIXCLK_GATE			0xC6020
+#define _ECOBUS				0xa180
+#define _GEN6_RC_CONTROL		0xA090
+#define _GEN6_RC_STATE			0xA094
+#define _GEN6_RPNSWREQ				(0xA008)
+#define _GEN6_RC_VIDEO_FREQ			(0xA00C)
+#define _GEN6_RP_DOWN_TIMEOUT			(0xA010)
+#define _GEN6_RP_INTERRUPT_LIMITS		(0xA014)
+#define _GEN6_RPSTAT1				(0xA01C)
+#define _GEN6_RP_CONTROL				(0xA024)
+#define _GEN6_RP_UP_THRESHOLD			(0xA02C)
+#define _GEN6_RP_DOWN_THRESHOLD			(0xA030)
+#define _GEN6_RP_CUR_UP_EI			(0xA050)
+#define _GEN6_RP_CUR_UP				(0xA054)
+#define _GEN6_RP_PREV_UP				(0xA058)
+#define _GEN6_RP_CUR_DOWN_EI			(0xA05C)
+#define _GEN6_RP_CUR_DOWN			(0xA060)
+#define _GEN6_RP_PREV_DOWN			(0xA064)
+#define _GEN6_RP_UP_EI				(0xA068)
+#define _GEN6_RP_DOWN_EI				(0xA06C)
+#define _GEN6_RP_IDLE_HYSTERSIS			(0xA070)
+#define _GEN6_RC1_WAKE_RATE_LIMIT		(0xA098)
+#define _GEN6_RC6_WAKE_RATE_LIMIT		(0xA09C)
+#define _GEN6_RC6pp_WAKE_RATE_LIMIT		(0xA0A0)
+#define _GEN6_RC_EVALUATION_INTERVAL		(0xA0A8)
+#define _GEN6_RC_IDLE_HYSTERSIS			(0xA0AC)
+#define _GEN6_RC_SLEEP				(0xA0B0)
+#define _GEN6_RC1e_THRESHOLD			(0xA0B4)
+#define _GEN6_RC6_THRESHOLD			(0xA0B8)
+#define _GEN6_RC6p_THRESHOLD			(0xA0BC)
+#define _GEN6_RC6pp_THRESHOLD			(0xA0C0)
+#define _GEN6_PMINTRMSK				(0xA168)
+#define _HSW_PWR_WELL_BIOS			(0x45400)
+#define _HSW_PWR_WELL_DRIVER			(0x45404)
+#define _HSW_PWR_WELL_KVMR			(0x45408)
+#define _HSW_PWR_WELL_DEBUG			(0x4540C)
+#define _HSW_PWR_WELL_CTL5			(0x45410)
+#define _HSW_PWR_WELL_CTL6			(0x45414)
+#define _CPU_VGACNTRL	(0x41000)
+#define _TILECTL				(0x101000)
+#define _GEN6_UCGCTL1				(0x9400)
+#define _GEN6_UCGCTL2				(0x9404)
+#define _GEN6_PCODE_MAILBOX			(0x138124)
+#define _GEN6_PCODE_DATA				(0x138128)
+#define _GEN7_ERR_INT	(0x44040)
+#define _GFX_FLSH_CNTL_GEN6	(0x101008)
+#define _ECOSKPD		(0x21d0)
+#define _GEN6_BLITTER_ECOSKPD	(0x221d0)
+#define _GAC_ECO_BITS			(0x14090)
+#define _GEN6_MBCTL		(0x0907c)
+#define _GAB_CTL				(0x24000)
+#define _FPGA_DBG		(0x42300)
+#define _BCS_SWCTRL (0x22200)
+#define _HS_INVOCATION_COUNT             (0x2300)
+#define _DS_INVOCATION_COUNT             (0x2308)
+#define _IA_VERTICES_COUNT               (0x2310)
+#define _IA_PRIMITIVES_COUNT             (0x2318)
+#define _VS_INVOCATION_COUNT             (0x2320)
+#define _GS_INVOCATION_COUNT             (0x2328)
+#define _GS_PRIMITIVES_COUNT             (0x2330)
+#define _CL_INVOCATION_COUNT             (0x2338)
+#define _CL_PRIMITIVES_COUNT             (0x2340)
+#define _PS_INVOCATION_COUNT             (0x2348)
+#define _PS_DEPTH_COUNT                  (0x2350)
+
 #define _GEN8_DE_PORT_IMR (0x44444)
 #define _GEN8_DE_PORT_IER (0x4444c)
 #define _GEN8_DE_PORT_IIR (0x44448)
@@ -491,11 +666,75 @@ union _TRANS_CONFIG
 #define _GEN8_PCU_ISR (0x444e0)
 #define _GEN8_MASTER_IRQ			(0x44200)
 
+#define _RING_HWSTAM(base)	((base)+0x98)
+#define _RING_TAIL(base)		((base)+0x30)
+#define _RING_HEAD(base)		((base)+0x34)
+#define _RING_START(base)	((base)+0x38)
+#define _RING_CTL(base)		((base)+0x3c)
+#define _RING_ACTHD(base)	((base)+0x74)
+#define _RING_MI_MODE(base)	((base)+0x9c)
+#define _RING_INSTPM(base)	((base)+0xc0)
+
+#define _GEN6_MBCUNIT_SNPCR	(0x900c)
+#define _GEN7_MISCCPCTL				(0x9424)
+#define _GEN8_PRIVATE_PAT_LO	(0x40e0)
+#define _GEN8_PRIVATE_PAT_HI	(0x40e0 + 4)
+#define _GAMTARBMODE		(0x04a08)
+
 #define _SDEIMR  (0xc4004)
 #define _SDEIER  (0xc400c)
 #define _SDEIIR  (0xc4008)
 #define _SDEISR  (0xc4000)
 
+#define _RENDER_HWS_PGA_GEN7	(0x04080)
+#define _BSD_HWS_PGA_GEN7	(0x04180)
+#define _BLT_HWS_PGA_GEN7	(0x04280)
+#define _VEBOX_HWS_PGA_GEN7	(0x04380)
+#define _RING_MI_MODE(base)	((base)+0x9c)
+#define _GEN7_GT_MODE	(0x7008)
+#define _CACHE_MODE_0_GEN7	(0x7000) /* IVB+ */
+#define _CACHE_MODE_1		(0x7004) /* IVB+ */
+#define _GAM_ECOCHK			(0x4090)
+#define _GEN7_COMMON_SLICE_CHICKEN1		(0x7010)
+#define _COMMON_SLICE_CHICKEN2			(0x7014)
+#define _VGA0	(0x6000)
+#define _VGA1	(0x6004)
+#define _VGA_PD	(0x6010)
+#define _DERRMR		(0x44050)
+#define _WM0_PIPEA_ILK		(0x45100)
+#define _WM0_PIPEB_ILK		(0x45104)
+#define _WM0_PIPEC_IVB		(0x45200)
+#define _WM1_LP_ILK		(0x45108)
+#define _WM2_LP_ILK		(0x4510c)
+#define _WM3_LP_ILK		(0x45110)
+#define _WM1S_LP_ILK		(0x45120)
+#define _WM2S_LP_IVB		(0x45124)
+#define _WM3S_LP_IVB		(0x45128)
+#define _BLC_PWM_CPU_CTL2	(0x48250)
+#define _BLC_PWM_CPU_CTL		(0x48254)
+#define _BLC_PWM_PCH_CTL1	(0xc8250)
+#define _BLC_PWM_PCH_CTL2	(0xc8254)
+#define _PCH_GPIOA               (0xc5010)
+#define _PCH_ADPA                (0xe1100)
+#define __3D_CHICKEN3		(0x2090)
+#define _PCH_LVDS	(0xe1180)
+#define _PCH_DREF_CONTROL        (0xC6200)
+#define _PCH_RAWCLK_FREQ         (0xc6204)
+#define _PCH_DPLL_SEL		(0xc7000)
+#define _PCH_PORT_HOTPLUG		(0xc4030)	/* SHOTPLUG_CTL */
+#define _LCPLL_CTL			(0x130040)
+#define _FUSE_STRAP			(0x42014)
+#define _DIGITAL_PORT_HOTPLUG_CNTRL	(0x44030)
+#define _DISP_ARB_CTL	(0x45000)
+#define _DISP_ARB_CTL2	(0x45004)
+#define _ILK_DISPLAY_CHICKEN1	(0x42000)
+#define _ILK_DISPLAY_CHICKEN2	(0x42004)
+#define _ILK_DSPCLK_GATE_D			(0x42020)
+#define _SOUTH_CHICKEN1		(0xc2000)
+#define _SOUTH_CHICKEN2		(0xc2004)
+#define _SOUTH_DSPCLK_GATE_D	(0xc2020)
+#define _IPS_CTL		(0x43408)
+
 #define _GEN8_GT_ISR(which) (0x44300 + (0x10 * (which)))
 #define _GEN8_GT_IMR(which) (0x44304 + (0x10 * (which)))
 #define _GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
@@ -506,7 +745,142 @@ union _TRANS_CONFIG
 #define _GEN8_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe)))
 #define _GEN8_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe)))
 
+/* digital port hotplug */
+/* GMBUS1 bits definitions */
+
+#define GMBUS1_TOTAL_BYTES_SHIFT 16
+#define GMBUS1_TOTAL_BYTES_MASK 0x1ff
+#define gmbus1_total_byte_count(v) (((v) >> GMBUS1_TOTAL_BYTES_SHIFT) & GMBUS1_TOTAL_BYTES_MASK)
+#define gmbus1_slave_addr(v) (((v) & 0xff) >> 1)
+#define gmbus1_slave_index(v) (((v) >> 8) & 0xff)
+#define gmbus1_bus_cycle(v) (((v) >> 25) & 0x7)
+
+/* GMBUS0 bits definitions */
+#define _GMBUS_PIN_SEL_MASK	(0x7)
+
+#define _REG_RC_PWRCTX_MAXCNT		0x2054
+#define _REG_VFSKPD			0x2470
+#define _REG_2D_CG_DIS			0x6200
+#define _REG_3D_CG_DIS			0x6204
+#define _REG_3D_CG_DIS2			0x6208
+#define _REG_SUPER_QUEUE_CONFIG		0x902c
+
+/* interrupt related definitions */
+#define	_REGSHIFT_MASTER_INTERRUPT	31
+#define	_REGSHIFT_PCH	21
+#define	_REGBIT_PCH	(1 << 21)
+/* GEN7 */
+#define	_REGSHIFT_PCH_GEN7	28
+#define	_REGBIT_PCH_GEN7	(1 << 28)
+
+#define	_REGBIT_DP_A_PULSE_DURATION	(3 << 2)
+
+#define	_REGBIT_CRT_HOTPLUG	(1 << 19)
+#define	_REGBIT_DP_B_HOTPLUG	(1 << 21)
+#define	_REGBIT_DP_C_HOTPLUG	(1 << 22)
+#define	_REGBIT_DP_D_HOTPLUG	(1 << 23)
+
+#define        _REGBIT_DP_B_STATUS			(3 << 0)
+#define        _REGBIT_DP_B_PULSE_DURATION		(3 << 2)
+#define        _REGBIT_DP_B_ENABLE			(1 << 4)
+#define        _REGBIT_DP_C_STATUS			(3 << 8)
+#define        _REGBIT_DP_C_PULSE_DURATION		(3 << 10)
+#define        _REGBIT_DP_C_ENABLE			(1 << 12)
+#define        _REGBIT_DP_D_STATUS			(3 << 16)
+#define        _REGBIT_DP_D_PULSE_DURATION		(3 << 18)
+#define        _REGBIT_DP_D_ENABLE			(1 << 20)
+
+#define _REG_RCS_WATCHDOG_CTL	0x2178
+#define _REG_RCS_WATCHDOG_THRSH	0x217C
+#define _REG_RCS_WATCHDOG_CTR	0x2190
+#define _REG_VCS_WATCHDOG_CTR	0x12178
+#define _REG_VCS_WATCHDOG_THRSH	0x1217C
+#define _REG_BCS_EIR	0x220B0
+#define _REG_BCS_EMR	0x220B4
+#define _REG_BCS_ESR	0x220B8
+#define _REG_VCS_EIR	0x120B0
+#define _REG_VCS_EMR	0x120B4
+#define _REG_VCS_ESR	0x120B8
+#define _REG_VECS_EIR	0x1A0B0
+#define _REG_VECS_EMR	0x1A0B4
+#define _REG_VECS_ESR	0x1A0B8
+
+/* blacklight PWM control */
+#define _REG_HISTOGRAM_THRSH	0x48268
+#define        _REGBIT_HISTOGRAM_IRQ_ENABLE	(1 << 31)
+#define        _REGBIT_HISTOGRAM_IRQ_STATUS	(1 << 30)
+
+/*
+ * Configuration register definition for BDF: 0:0:0.
+ */
+#define _REG_GMCH_CONTRL		0x50
+#define    _REGBIT_SNB_GMCH_GMS_SHIFT   3 /* Graphics Mode Select */
+#define    _REGBIT_SNB_GMCH_GMS_MASK    0x1f
+#define    _REGBIT_BDW_GMCH_GMS_SHIFT   8
+#define    _REGBIT_BDW_GMCH_GMS_MASK    0xff
+
+/* HSW */
+#define  _REGBIT_SPLL_CTL_ENABLE	(1 << 31)
+
+#define _REG_PORT_CLK_SEL_DDIC	0x46108
+#define _REG_PORT_CLK_SEL_DDID	0x4610C
+#define _REG_PORT_CLK_SEL_DDIE	0x46110
+
+#define _REG_TRANS_CLK_SEL_C	0x46148
+#define SBI_RESPONSE_MASK		0x3
+#define SBI_RESPONSE_SHIFT		0x1
+#define SBI_STAT_MASK			0x1
+#define SBI_STAT_SHIFT			0x0
+#define SBI_OPCODE_SHIFT		8
+#define SBI_OPCODE_MASK		(0xff << SBI_OPCODE_SHIFT)
+#define SBI_CMD_IORD			2
+#define SBI_CMD_IOWR			3
+#define SBI_CMD_CRRD			6
+#define SBI_CMD_CRWR			7
+#define SBI_ADDR_OFFSET_SHIFT		16
+#define SBI_ADDR_OFFSET_MASK		(0xffff << SBI_ADDR_OFFSET_SHIFT)
+
 #define _GVT_TRANS_DDI_FUNC_CTL(tran)   _TRANS(tran, _TRANS_DDI_FUNC_CTL_A, \
 		_TRANS_DDI_FUNC_CTL_B)
 
+/* Those bits are ignored by pipe EDP since it can only connect to DDI A */
+#define  _TRANS_DDI_MODE_SELECT_HIFT		24
+#define  _TRANS_DDI_EDP_INPUT_SHIFT		12
+
+#define _REG_GEN7_SQ_CHICKEN_MBCUNIT_CONFIG		0x9030
+
+#define _REG_PIPE_WM_LINETIME_C			0x45278
+
+#define _REG_HSW_VIDEO_DIP_CTL_C		0x62200
+#define _REG_HSW_VIDEO_DIP_CTL_EDP		0x6F200
+
+/* GEN8 interrupt registers definations */
+#define _REG_GT_ISR(which) (0x44300 + (0x10 * (which)))
+#define _REG_GT_IMR(which) (0x44304 + (0x10 * (which)))
+#define _REG_GT_IIR(which) (0x44308 + (0x10 * (which)))
+#define _REG_GT_IER(which) (0x4430c + (0x10 * (which)))
+
+#define _REG_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe)))
+#define _REG_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe)))
+#define _REG_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe)))
+#define _REG_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe)))
+
+#define _REG_RING_PDP_UDW(base, n)      (base + 0x270 + ((n) * 8 + 4))
+#define _REG_RING_PDP_LDW(base, n)      (base + 0x270 + (n) * 8)
+
+#define _REG_RCS_PDP_UDW(n)	_REG_RING_PDP_UDW(0x2000, n)
+#define _REG_RCS_PDP_LDW(n)	_REG_RING_PDP_LDW(0x2000, n)
+
+#define _REG_VCS_PDP_UDW(n)	_REG_RING_PDP_UDW(0x12000, n)
+#define _REG_VCS_PDP_LDW(n)	_REG_RING_PDP_LDW(0x12000, n)
+
+#define _REG_VCS2_PDP_UDW(n)	_REG_RING_PDP_UDW(0x1c000, n)
+#define _REG_VCS2_PDP_LDW(n)	_REG_RING_PDP_LDW(0x1c000, n)
+
+#define _REG_VECS_PDP_UDW(n)	_REG_RING_PDP_UDW(0x1a000, n)
+#define _REG_VECS_PDP_LDW(n)	_REG_RING_PDP_LDW(0x1a000, n)
+
+#define _REG_BCS_PDP_UDW(n)	_REG_RING_PDP_UDW(0x22000, n)
+#define _REG_BCS_PDP_LDW(n)	_REG_RING_PDP_LDW(0x22000, n)
+
 #endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 22/29] drm/i915: gvt: Full display virtualization
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (20 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 21/29] drm/i915: gvt: vGPU MMIO register emulation Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 23/29] drm/i915: gvt: Introduce GVT control interface Zhi Wang
                   ` (7 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

From: Bing Niu <bing.niu@intel.com>

This patch introduces the GVT-g full display virtualization subsystem.

It consists a collection of display MMIO handlers, like power well register
handler, pipe register handler, plane register handler, which will emulate
all display MMIOs behavior to support virtual mode setting sequence for
guest.

Signed-off-by: Bing Niu <bing.niu@intel.com>
Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile    |   2 +-
 drivers/gpu/drm/i915/gvt/display.c   | 233 +++++++++
 drivers/gpu/drm/i915/gvt/display.h   | 129 +++++
 drivers/gpu/drm/i915/gvt/edid.c      | 493 ++++++++++++++++++
 drivers/gpu/drm/i915/gvt/edid.h      | 184 +++++++
 drivers/gpu/drm/i915/gvt/gvt.c       |   6 +
 drivers/gpu/drm/i915/gvt/gvt.h       |  12 +
 drivers/gpu/drm/i915/gvt/handlers.c  | 974 ++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/gvt/instance.c  |   4 +
 drivers/gpu/drm/i915/gvt/interrupt.c |  26 +-
 drivers/gpu/drm/i915/gvt/interrupt.h |   7 +
 drivers/gpu/drm/i915/gvt/reg.h       |   3 +
 12 files changed, 2069 insertions(+), 4 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/display.c
 create mode 100644 drivers/gpu/drm/i915/gvt/display.h
 create mode 100644 drivers/gpu/drm/i915/gvt/edid.c
 create mode 100644 drivers/gpu/drm/i915/gvt/edid.h

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index b0a3a1a..c146c57 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,6 +1,6 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
 		trace_points.o interrupt.o gtt.o cfg_space.o opregion.o utility.o \
-		fb_decoder.o
+		fb_decoder.o display.o edid.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c
new file mode 100644
index 0000000..c951150
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/display.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+int gvt_get_edp_pipe(struct vgt_device *vgt)
+{
+	u32 data = __vreg(vgt, _TRANS_DDI_FUNC_CTL_EDP);
+	int pipe = I915_MAX_PIPES;
+
+	switch (data & TRANS_DDI_EDP_INPUT_MASK) {
+		case TRANS_DDI_EDP_INPUT_A_ON:
+		case TRANS_DDI_EDP_INPUT_A_ONOFF:
+			pipe = PIPE_A;
+			break;
+		case TRANS_DDI_EDP_INPUT_B_ONOFF:
+			pipe = PIPE_B;
+			break;
+		case TRANS_DDI_EDP_INPUT_C_ONOFF:
+			pipe = PIPE_C;
+			break;
+	}
+	return pipe;
+}
+
+bool gvt_edp_pipe_is_enabled(struct vgt_device *vgt)
+{
+	if (!(__vreg(vgt, _REG_PIPE_EDP_CONF) & PIPECONF_ENABLE))
+		return false;
+
+	if (!(__vreg(vgt, _TRANS_DDI_FUNC_CTL_EDP) & TRANS_DDI_FUNC_ENABLE))
+		return false;
+
+	return true;
+}
+
+bool gvt_pipe_is_enabled(struct vgt_device *vgt, int pipe)
+{
+	ASSERT(pipe >= PIPE_A && pipe < I915_MAX_PIPES);
+
+	if (__vreg(vgt, GVT_PIPECONF(pipe)) & PIPECONF_ENABLE)
+		return true;
+
+	if (gvt_edp_pipe_is_enabled(vgt) &&
+			gvt_get_edp_pipe(vgt) == pipe)
+		return true;
+
+	return false;
+}
+
+static const unsigned char virtual_dp_monitor_edid[] = {
+	0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x22,0xf0,0x54,0x29,
+	0x00,0x00,0x00,0x00,0x04,0x17,0x01,0x04,0xa5,0x34,0x20,0x78,
+	0x23,0xfc,0x81,0xa4,0x55,0x4d,0x9d,0x25,0x12,0x50,0x54,0x21,
+	0x08,0x00,0xd1,0xc0,0x81,0xc0,0x81,0x40,0x81,0x80,0x95,0x00,
+	0xa9,0x40,0xb3,0x00,0x01,0x01,0x28,0x3c,0x80,0xa0,0x70,0xb0,
+	0x23,0x40,0x30,0x20,0x36,0x00,0x06,0x44,0x21,0x00,0x00,0x1a,
+	0x00,0x00,0x00,0xfd,0x00,0x18,0x3c,0x18,0x50,0x11,0x00,0x0a,
+	0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xfc,0x00,0x48,
+	0x50,0x20,0x5a,0x52,0x32,0x34,0x34,0x30,0x77,0x0a,0x20,0x20,
+	0x00,0x00,0x00,0xff,0x00,0x43,0x4e,0x34,0x33,0x30,0x34,0x30,
+	0x44,0x58,0x51,0x0a,0x20,0x20,0x01,0x44,0x02,0x03,0x19,0xc1,
+	0x4c,0x90,0x1f,0x05,0x14,0x04,0x13,0x03,0x02,0x07,0x06,0x12,
+	0x01,0x23,0x09,0x07,0x07,0x83,0x01,0x00,0x00,0x02,0x3a,0x80,
+	0x18,0x71,0x38,0x2d,0x40,0x58,0x2c,0x45,0x00,0x06,0x44,0x21,
+	0x00,0x00,0x1e,0x02,0x3a,0x80,0xd0,0x72,0x38,0x2d,0x40,0x10,
+	0x2c,0x45,0x80,0x06,0x44,0x21,0x00,0x00,0x1e,0x01,0x1d,0x00,
+	0x72,0x51,0xd0,0x1e,0x20,0x6e,0x28,0x55,0x00,0x06,0x44,0x21,
+	0x00,0x00,0x1e,0x01,0x1d,0x00,0xbc,0x52,0xd0,0x1e,0x20,0xb8,
+	0x28,0x55,0x40,0x06,0x44,0x21,0x00,0x00,0x1e,0x8c,0x0a,0xd0,
+	0x8a,0x20,0xe0,0x2d,0x10,0x10,0x3e,0x96,0x00,0x06,0x44,0x21,
+	0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x7b,
+};
+
+#define DPCD_HEADER_SIZE        0xb
+
+u8 dpcd_fix_data[DPCD_HEADER_SIZE] = {
+        0x11, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static void emulate_monitor_status_change(struct vgt_device *vgt)
+{
+	__vreg(vgt, _SDEISR) &= ~(_REGBIT_DP_B_HOTPLUG |
+			_REGBIT_DP_C_HOTPLUG |
+			_REGBIT_DP_D_HOTPLUG);
+
+	if (dpy_has_monitor_on_port(vgt, PORT_B))
+		__vreg(vgt, _SDEISR) |= _REGBIT_DP_B_HOTPLUG;
+
+	if (dpy_has_monitor_on_port(vgt, PORT_C))
+		__vreg(vgt, _SDEISR) |= _REGBIT_DP_C_HOTPLUG;
+
+	if (dpy_has_monitor_on_port(vgt, PORT_D))
+		__vreg(vgt, _SDEISR) |= _REGBIT_DP_D_HOTPLUG;
+
+	if (dpy_has_monitor_on_port(vgt, PORT_A))
+		__vreg(vgt, _GEN8_DE_PORT_ISR) |= GEN8_PORT_DP_A_HOTPLUG;
+}
+
+static void clean_virtual_dp_monitor(struct vgt_device *vgt)
+{
+	struct gt_port *port = gvt_vport(vgt, PORT_A);
+
+	if (port->edid) {
+		kfree(port->edid);
+		port->edid = NULL;
+	}
+
+	if (port->dpcd) {
+		kfree(port->dpcd);
+		port->dpcd = NULL;
+	}
+}
+
+static bool setup_virtual_dp_monitor(struct vgt_device *vgt)
+{
+	struct gt_port *port = gvt_vport(vgt, PORT_A);
+
+	port->edid = kzalloc(sizeof(*(port->edid)), GFP_KERNEL);
+	if (!port->edid)
+		goto err;
+
+	port->dpcd = kzalloc(sizeof(*(port->dpcd)), GFP_KERNEL);
+	if (!port->dpcd)
+		goto err;
+
+	memcpy(port->edid->edid_block, virtual_dp_monitor_edid,
+			EDID_SIZE);
+	port->edid->data_valid = true;
+
+	memcpy(port->dpcd->data, dpcd_fix_data, DPCD_HEADER_SIZE);
+	port->dpcd->data_valid = true;
+
+	port->type = GVT_DP_A;
+
+	emulate_monitor_status_change(vgt);
+	return true;
+err:
+	clean_virtual_dp_monitor(vgt);
+	return false;
+}
+
+bool gvt_update_display_events_emulation(struct pgt_device *pdev)
+{
+	struct gvt_irq_state *irq = &pdev->irq_state;
+	struct vgt_device *vgt;
+	bool have_enabled_pipe = false;
+	int pipe, id;
+
+	ASSERT(mutex_is_locked(&pdev->lock));
+
+	hrtimer_cancel(&irq->dpy_timer.timer);
+
+	for_each_online_instance(pdev, vgt, id) {
+		for (pipe = 0; pipe < I915_MAX_PIPES; pipe++) {
+			have_enabled_pipe =
+				gvt_pipe_is_enabled(vgt, pipe);
+			if (have_enabled_pipe)
+				break;
+		}
+	}
+
+	if (have_enabled_pipe)
+		hrtimer_start(&irq->dpy_timer.timer,
+				ktime_add_ns(ktime_get(), irq->dpy_timer.period),
+				HRTIMER_MODE_ABS);
+	return true;
+}
+
+static void emulate_vblank_on_pipe(struct vgt_device *vgt, int pipe)
+{
+	int vblank_event[] = {
+		[PIPE_A] = PIPE_A_VBLANK,
+		[PIPE_B] = PIPE_B_VBLANK,
+		[PIPE_C] = PIPE_C_VBLANK,
+	};
+
+	ASSERT(pipe >= PIPE_A && pipe <= PIPE_C);
+
+	if (gvt_pipe_is_enabled(vgt, pipe))
+		gvt_trigger_virtual_event(vgt, vblank_event[pipe]);
+}
+
+static void emulate_vblank_for_instance(struct vgt_device *vgt)
+{
+	int pipe;
+
+	for (pipe = 0; pipe < I915_MAX_PIPES; pipe++)
+		emulate_vblank_on_pipe(vgt, pipe);
+}
+
+void gvt_emulate_display_events(struct pgt_device *pdev)
+{
+	struct vgt_device *vgt;
+	int id;
+
+	ASSERT(mutex_is_locked(&pdev->lock));
+
+	for_each_online_instance(pdev, vgt, id)
+		emulate_vblank_for_instance(vgt);
+}
+
+void gvt_clean_virtual_display_state(struct vgt_device *vgt)
+{
+	clean_virtual_dp_monitor(vgt);
+}
+
+bool gvt_init_virtual_display_state(struct vgt_device *vgt)
+{
+	gvt_init_i2c_edid(vgt);
+	return setup_virtual_dp_monitor(vgt);
+}
diff --git a/drivers/gpu/drm/i915/gvt/display.h b/drivers/gpu/drm/i915/gvt/display.h
new file mode 100644
index 0000000..3aa8aaa
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/display.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_DISPLAY_H_
+#define _GVT_DISPLAY_H_
+
+#define SBI_REG_MAX	20
+#define DPCD_SIZE	0x700
+
+#define dpy_is_valid_port(port)							\
+		(((port) >= PORT_A) && ((port) < I915_MAX_PORTS))
+
+#define gvt_vport(vgt, port) \
+	(&(vgt)->state.display.ports[port])
+
+#define dpy_has_monitor_on_port(vgt, port)					\
+		(vgt && dpy_is_valid_port(port) &&				\
+		gvt_vport(vgt, port)->edid && gvt_vport(vgt, port)->edid->data_valid)
+
+#define dpy_port_is_dp(vgt, port)						\
+		((vgt) && dpy_is_valid_port(port)				\
+		&& ((gvt_vport(vgt, port)->type == GVT_DP_A) ||			\
+		    (gvt_vport(vgt, port)->type == GVT_DP_B) ||			\
+		    (gvt_vport(vgt, port)->type == GVT_DP_C) ||			\
+		    (gvt_vport(vgt, port)->type == GVT_DP_D)))
+
+#define GVT_MAX_UEVENT_VARS	3
+/* DPCD start */
+#define DPCD_SIZE	0x700
+
+/* DPCD addresses */
+#define DPCD_REV			0x000
+#define DPCD_MAX_LINK_RATE		0x001
+#define DPCD_MAX_LANE_COUNT		0x002
+
+#define DPCD_TRAINING_PATTERN_SET	0x102
+#define	DPCD_SINK_COUNT			0x200
+#define DPCD_LANE0_1_STATUS		0x202
+#define DPCD_LANE2_3_STATUS		0x203
+#define DPCD_LANE_ALIGN_STATUS_UPDATED	0x204
+#define DPCD_SINK_STATUS		0x205
+
+/* link training */
+#define DPCD_TRAINING_PATTERN_SET_MASK	0x03
+#define DPCD_LINK_TRAINING_DISABLED	0x00
+#define DPCD_TRAINING_PATTERN_1		0x01
+#define DPCD_TRAINING_PATTERN_2		0x02
+
+#define DPCD_CP_READY_MASK		(1 << 6)
+
+/* lane status */
+#define DPCD_LANES_CR_DONE		0x11
+#define DPCD_LANES_EQ_DONE		0x22
+#define DPCD_SYMBOL_LOCKED		0x44
+
+#define DPCD_INTERLANE_ALIGN_DONE	0x01
+
+#define DPCD_SINK_IN_SYNC		0x03
+
+/* DPCD end */
+
+struct sbi_register {
+	unsigned int offset;
+	u32 value;
+};
+
+struct sbi_registers {
+	int number;
+	struct sbi_register registers[SBI_REG_MAX];
+};
+
+enum gvt_plane_type {
+	PRIMARY_PLANE = 0,
+	CURSOR_PLANE,
+	SPRITE_PLANE,
+	MAX_PLANE
+};
+
+struct gvt_dpcd_data {
+	bool data_valid;
+	u8 data[DPCD_SIZE];
+};
+
+enum gvt_port_type {
+	GVT_CRT = 0,
+	GVT_DP_A,
+	GVT_DP_B,
+	GVT_DP_C,
+	GVT_DP_D,
+	GVT_HDMI_B,
+	GVT_HDMI_C,
+	GVT_HDMI_D,
+	GVT_PORT_MAX
+};
+
+struct gt_port {
+	struct gvt_edid_data_t	*edid;	/* per display EDID information */
+	struct gvt_dpcd_data	*dpcd;	/* per display DPCD information */
+	enum gvt_port_type	type;
+};
+
+extern int gvt_get_edp_pipe(struct vgt_device *vgt);
+extern bool gvt_edp_pipe_is_enabled(struct vgt_device *vgt);
+extern bool gvt_pipe_is_enabled(struct vgt_device *vgt, int pipe);
+
+bool gvt_init_virtual_display_state(struct vgt_device *vgt);
+void gvt_clean_virtual_display_state(struct vgt_device *vgt);
+
+#endif
diff --git a/drivers/gpu/drm/i915/gvt/edid.c b/drivers/gpu/drm/i915/gvt/edid.c
new file mode 100644
index 0000000..dd10ba3
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/edid.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+static unsigned char edid_get_byte(struct vgt_device *vgt)
+{
+	unsigned char chr = 0;
+	struct gvt_i2c_edid_t *edid = &vgt->state.display.gvt_i2c_edid;
+
+	if (edid->state == I2C_NOT_SPECIFIED || !edid->slave_selected) {
+		gvt_warn("Driver tries to read EDID without proper sequence!\n");
+		return 0;
+	}
+	if (edid->current_edid_read >= EDID_SIZE) {
+		gvt_warn("edid_get_byte() exceeds the size of EDID!\n");
+		return 0;
+	}
+
+	if (!edid->edid_available) {
+		gvt_warn("Reading EDID but EDID is not available!"
+			" Will return 0.\n");
+		return 0;
+	}
+
+	if (dpy_has_monitor_on_port(vgt, edid->port)) {
+		struct gvt_edid_data_t *edid_data = gvt_vport(vgt, edid->port)->edid;
+		chr = edid_data->edid_block[edid->current_edid_read];
+		gvt_dbg(GVT_DBG_EDID,
+			"edid_get_byte with offset %d and value %d\n",
+			edid->current_edid_read, chr);
+		edid->current_edid_read ++;
+	} else {
+		gvt_warn("No EDID available during the reading?\n");
+	}
+
+	return chr;
+}
+
+static inline enum port gvt_get_port_from_gmbus0(u32 gmbus0){
+	enum port port = I915_MAX_PORTS;
+	int port_select = gmbus0 & _GMBUS_PIN_SEL_MASK;
+
+	if (port_select == 2)
+		port = PORT_E;
+	else if (port_select == 4)
+		port = PORT_C;
+	else if (port_select == 5)
+		port = PORT_B;
+	else if (port_select == 6)
+		port = PORT_D;
+
+	return port;
+}
+
+void gvt_reset_gmbus_controller(struct vgt_device *vgt)
+{
+	__vreg(vgt, _PCH_GMBUS2) = GMBUS_HW_RDY;
+	if (!vgt->state.display.gvt_i2c_edid.edid_available) {
+		__vreg(vgt, _PCH_GMBUS2) |= GMBUS_SATOER;
+	}
+	vgt->state.display.gvt_i2c_edid.gmbus.phase = GMBUS_IDLE_PHASE;
+}
+
+
+/* GMBUS0 */
+static bool gvt_gmbus0_mmio_write(struct vgt_device *vgt,
+			unsigned int offset, void *p_data, unsigned int bytes)
+{
+	u32 wvalue = *(u32 *)p_data;
+	enum port port = I915_MAX_PORTS;
+	int pin_select = wvalue & _GMBUS_PIN_SEL_MASK;
+
+	gvt_init_i2c_edid(vgt);
+
+	if (pin_select == 0)
+		return true;
+
+	vgt->state.display.gvt_i2c_edid.state = I2C_GMBUS;
+	port = gvt_get_port_from_gmbus0(pin_select);
+	if (!dpy_is_valid_port(port)) {
+		gvt_dbg(GVT_DBG_EDID,
+			"VM(%d): Driver tries GMBUS write not on valid port!\n"
+			"gmbus write value is: 0x%x\n", vgt->id, wvalue);
+		return true;
+	}
+
+	vgt->state.display.gvt_i2c_edid.gmbus.phase = GMBUS_IDLE_PHASE;
+
+	/* FIXME: never clear GMBUS_HW_WAIT_PHASE */
+	__vreg(vgt, _PCH_GMBUS2) &= ~ GMBUS_ACTIVE;
+	__vreg(vgt, _PCH_GMBUS2) |= GMBUS_HW_RDY | GMBUS_HW_WAIT_PHASE;
+
+	if (dpy_has_monitor_on_port(vgt, port) && !dpy_port_is_dp(vgt, port)) {
+		vgt->state.display.gvt_i2c_edid.port = port;
+		vgt->state.display.gvt_i2c_edid.edid_available = true;
+		__vreg(vgt, _PCH_GMBUS2) &= ~GMBUS_SATOER;
+	} else {
+		__vreg(vgt, _PCH_GMBUS2) |= GMBUS_SATOER;
+	}
+
+	memcpy(p_data, (char *)vgt->state.mmio.vreg + offset, bytes);
+	return true;
+}
+
+static bool gvt_gmbus1_mmio_write(struct vgt_device *vgt, unsigned int offset,
+void *p_data, unsigned int bytes)
+{
+	u32 slave_addr;
+	struct gvt_i2c_edid_t *i2c_edid = &vgt->state.display.gvt_i2c_edid;
+
+	u32 wvalue = *(u32 *)p_data;
+	if (__vreg(vgt, offset) & GMBUS_SW_CLR_INT) {
+		if (!(wvalue & GMBUS_SW_CLR_INT)) {
+			__vreg(vgt, offset) &= ~GMBUS_SW_CLR_INT;
+			gvt_reset_gmbus_controller(vgt);
+		}
+		/* TODO: "This bit is cleared to zero when an event
+		 * causes the HW_RDY bit transition to occur "*/
+	} else {
+		/* per bspec setting this bit can cause:
+		 1) INT status bit cleared
+		 2) HW_RDY bit asserted
+		 */
+		if (wvalue & GMBUS_SW_CLR_INT) {
+			__vreg(vgt, _PCH_GMBUS2) &= ~GMBUS_INT;
+			__vreg(vgt, _PCH_GMBUS2) |= GMBUS_HW_RDY;
+		}
+
+		/* For virtualization, we suppose that HW is always ready,
+		 * so GMBUS_SW_RDY should always be cleared
+		 */
+		if (wvalue & GMBUS_SW_RDY)
+			wvalue &= ~GMBUS_SW_RDY;
+
+		i2c_edid->gmbus.total_byte_count =
+			gmbus1_total_byte_count(wvalue);
+		slave_addr = gmbus1_slave_addr(wvalue);
+
+		/* vgt gmbus only support EDID */
+		if (slave_addr == EDID_ADDR) {
+			i2c_edid->slave_selected = true;
+		} else if (slave_addr != 0) {
+			gvt_dbg(GVT_DBG_DPY,
+				"vGT(%d): unsupported gmbus slave addr(0x%x)\n"
+				"	gmbus operations will be ignored.\n",
+					vgt->id, slave_addr);
+		}
+
+		if (wvalue & GMBUS_CYCLE_INDEX) {
+			i2c_edid->current_edid_read = gmbus1_slave_index(wvalue);
+		}
+
+		i2c_edid->gmbus.cycle_type = gmbus1_bus_cycle(wvalue);
+		switch (gmbus1_bus_cycle(wvalue)) {
+			case GMBUS_NOCYCLE:
+				break;
+			case GMBUS_STOP:
+				/* From spec:
+				This can only cause a STOP to be generated
+				if a GMBUS cycle is generated, the GMBUS is
+				currently in a data/wait/idle phase, or it is in a
+				WAIT phase
+				 */
+				if (gmbus1_bus_cycle(__vreg(vgt, offset)) != GMBUS_NOCYCLE) {
+					gvt_init_i2c_edid(vgt);
+					/* After the 'stop' cycle, hw state would become
+					 * 'stop phase' and then 'idle phase' after a few
+					 * milliseconds. In emulation, we just set it as
+					 * 'idle phase' ('stop phase' is not
+					 * visible in gmbus interface)
+					 */
+					i2c_edid->gmbus.phase = GMBUS_IDLE_PHASE;
+					/*
+					FIXME: never clear GMBUS_WAIT
+					__vreg(vgt, _PCH_GMBUS2) &=
+						~(GMBUS_ACTIVE | GMBUS_HW_WAIT_PHASE);
+					*/
+					__vreg(vgt, _PCH_GMBUS2) &= ~GMBUS_ACTIVE;
+				}
+				break;
+			case NIDX_NS_W:
+			case IDX_NS_W:
+			case NIDX_STOP:
+			case IDX_STOP:
+				/* From hw spec the GMBUS phase
+				 * transition like this:
+				 * START (-->INDEX) -->DATA
+				 */
+				i2c_edid->gmbus.phase = GMBUS_DATA_PHASE;
+				__vreg(vgt, _PCH_GMBUS2) |= GMBUS_ACTIVE;
+				/* FIXME: never clear GMBUS_WAIT */
+				//__vreg(vgt, _PCH_GMBUS2) &= ~GMBUS_HW_WAIT_PHASE;
+				break;
+			default:
+				gvt_err("Unknown/reserved GMBUS cycle detected!");
+				break;
+		}
+		/* From hw spec the WAIT state will be
+		 * cleared:
+		 * (1) in a new GMBUS cycle
+		 * (2) by generating a stop
+		 */
+		/* FIXME: never clear GMBUS_WAIT
+		if (gmbus1_bus_cycle(wvalue) != GMBUS_NOCYCLE)
+			__vreg(vgt, _PCH_GMBUS2) &= ~GMBUS_HW_WAIT_PHASE;
+		*/
+
+		__vreg(vgt, offset) = wvalue;
+	}
+	return true;
+}
+
+bool gvt_gmbus3_mmio_write(struct vgt_device *vgt, unsigned int offset,
+	void *p_data, unsigned int bytes)
+{
+	ASSERT_VM(0, vgt);
+	return true;
+}
+
+bool gvt_gmbus3_mmio_read(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	int i;
+	unsigned char byte_data;
+	struct gvt_i2c_edid_t *i2c_edid = &vgt->state.display.gvt_i2c_edid;
+	int byte_left = i2c_edid->gmbus.total_byte_count -
+				i2c_edid->current_edid_read;
+	int byte_count = byte_left;
+	u32 reg_data = 0;
+
+	/* Data can only be recevied if previous settings correct */
+	if (__vreg(vgt, _PCH_GMBUS1) & GMBUS_SLAVE_READ) {
+		if (byte_left <= 0) {
+			memcpy((char *)p_data, (char *)vgt->state.mmio.vreg + offset, bytes);
+			return true;
+		}
+
+		if (byte_count > 4)
+			byte_count = 4;
+		for (i = 0; i< byte_count; i++) {
+			byte_data = edid_get_byte(vgt);
+			reg_data |= (byte_data << (i << 3));
+		}
+
+		memcpy((char *)p_data, (char *)&reg_data, byte_count);
+		memcpy((char *)vgt->state.mmio.vreg + offset, (char *)&reg_data, byte_count);
+
+		if (byte_left <= 4) {
+			switch (i2c_edid->gmbus.cycle_type) {
+				case NIDX_STOP:
+				case IDX_STOP:
+					i2c_edid->gmbus.phase = GMBUS_IDLE_PHASE;
+					break;
+				case NIDX_NS_W:
+				case IDX_NS_W:
+				default:
+					i2c_edid->gmbus.phase = GMBUS_WAIT_PHASE;
+					break;
+			}
+			gvt_init_i2c_edid(vgt);
+		}
+
+		/* Read GMBUS3 during send operation, return the latest written value */
+	} else {
+		memcpy((char *)p_data, (char *)vgt->state.mmio.vreg + offset, bytes);
+		printk("vGT(%d): warning: gmbus3 read with nothing retuned\n",
+				vgt->id);
+	}
+
+	return true;
+}
+
+static bool gvt_gmbus2_mmio_read(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	u32 value = __vreg(vgt, offset);
+	if (!(__vreg(vgt, offset) & GMBUS_INUSE)) {
+		__vreg(vgt, offset) |= GMBUS_INUSE;
+	}
+
+	memcpy(p_data, (void *)&value, bytes);
+	return true;
+}
+
+bool gvt_gmbus2_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	u32 wvalue = *(u32 *)p_data;
+	if (wvalue & GMBUS_INUSE)
+		__vreg(vgt, offset) &= ~GMBUS_INUSE;
+	/* All other bits are read-only */
+	return true;
+}
+
+bool gvt_i2c_handle_gmbus_read(struct vgt_device *vgt, unsigned int offset,
+	void *p_data, unsigned int bytes)
+{
+	ASSERT(bytes <= 8 && !(offset & (bytes - 1)));
+	switch (offset) {
+		case _PCH_GMBUS2:
+			return gvt_gmbus2_mmio_read(vgt, offset, p_data, bytes);
+		case _PCH_GMBUS3:
+			return gvt_gmbus3_mmio_read(vgt, offset, p_data, bytes);
+		default:
+			memcpy(p_data, (char *)vgt->state.mmio.vreg + offset, bytes);
+	}
+	return true;
+}
+
+bool gvt_i2c_handle_gmbus_write(struct vgt_device *vgt, unsigned int offset,
+	void *p_data, unsigned int bytes)
+{
+	ASSERT(bytes <= 8 && !(offset & (bytes - 1)));
+	switch (offset) {
+		case _PCH_GMBUS0:
+			return gvt_gmbus0_mmio_write(vgt, offset, p_data, bytes);
+		case _PCH_GMBUS1:
+			return gvt_gmbus1_mmio_write(vgt, offset, p_data, bytes);
+		case _PCH_GMBUS2:
+			return gvt_gmbus2_mmio_write(vgt, offset, p_data, bytes);
+		/* TODO: */
+		case _PCH_GMBUS3:
+			BUG();
+			return false;
+		default:
+			memcpy((char *)vgt->state.mmio.vreg + offset, p_data, bytes);
+	}
+	return true;
+}
+
+static inline AUX_CH_REGISTERS gvt_get_aux_ch_reg(unsigned int offset)
+{
+	AUX_CH_REGISTERS reg;
+	switch (offset & 0xff) {
+	case 0x10:
+		reg = AUX_CH_CTL;
+		break;
+	case 0x14:
+		reg = AUX_CH_DATA1;
+		break;
+	case 0x18:
+		reg = AUX_CH_DATA2;
+		break;
+	case 0x1c:
+		reg = AUX_CH_DATA3;
+		break;
+	case 0x20:
+		reg = AUX_CH_DATA4;
+		break;
+	case 0x24:
+		reg = AUX_CH_DATA5;
+		break;
+	default:
+		reg = AUX_CH_INV;
+		break;
+	}
+	return reg;
+}
+
+#define AUX_CTL_MSG_LENGTH(reg) \
+	((reg & _DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >> \
+		_DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT)
+
+void gvt_i2c_handle_aux_ch_write(struct vgt_device *vgt,
+				enum port port_idx,
+				unsigned int offset,
+				void *p_data)
+{
+	struct gvt_i2c_edid_t *i2c_edid = &vgt->state.display.gvt_i2c_edid;
+	int msg_length, ret_msg_size;
+	int msg, addr, ctrl, op;
+	int value = *(int *)p_data;
+	int aux_data_for_write = 0;
+	AUX_CH_REGISTERS reg = gvt_get_aux_ch_reg(offset);
+
+	if (reg != AUX_CH_CTL) {
+		__vreg(vgt, offset) = value;
+		return;
+	}
+
+	msg_length = AUX_CTL_MSG_LENGTH(value);
+	// check the msg in DATA register.
+	msg = __vreg(vgt, offset + 4);
+	addr = (msg >> 8) & 0xffff;
+	ctrl = (msg >> 24)& 0xff;
+	op = ctrl >> 4;
+	if (!(value & _REGBIT_DP_AUX_CH_CTL_SEND_BUSY)) {
+		/* The ctl write to clear some states */
+		return;
+	}
+
+	/* Always set the wanted value for vms. */
+	ret_msg_size = (((op & 0x1) == GVT_AUX_I2C_READ) ? 2 : 1);
+	__vreg(vgt, offset) =
+		_REGBIT_DP_AUX_CH_CTL_DONE |
+		((ret_msg_size << _DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) &
+		_DP_AUX_CH_CTL_MESSAGE_SIZE_MASK);
+
+	if (msg_length == 3) {
+		if (!(op & GVT_AUX_I2C_MOT)) {
+			/* stop */
+			gvt_dbg(GVT_DBG_EDID,
+				"AUX_CH: stop. reset I2C!\n");
+			gvt_init_i2c_edid(vgt);
+		} else {
+			/* start or restart */
+			gvt_dbg(GVT_DBG_EDID,
+				"AUX_CH: start or restart I2C!\n");
+			i2c_edid->aux_ch.i2c_over_aux_ch = true;
+			i2c_edid->aux_ch.aux_ch_mot = true;
+			if (addr == 0) {
+				/* reset the address */
+				gvt_dbg(GVT_DBG_EDID,
+					"AUX_CH: reset I2C!\n");
+				gvt_init_i2c_edid(vgt);
+			} else if (addr == EDID_ADDR) {
+				gvt_dbg(GVT_DBG_EDID,
+					"AUX_CH: setting EDID_ADDR!\n");
+				i2c_edid->state = I2C_AUX_CH;
+				i2c_edid->port = port_idx;
+				i2c_edid->slave_selected = true;
+				if (dpy_has_monitor_on_port(vgt, port_idx) &&
+					dpy_port_is_dp(vgt, port_idx))
+					i2c_edid->edid_available = true;
+			} else {
+				gvt_dbg(GVT_DBG_EDID,
+		"Not supported address access [0x%x]with I2C over AUX_CH!\n",
+				addr);
+			}
+		}
+	} else if ((op & 0x1) == GVT_AUX_I2C_WRITE) {
+		/* TODO
+		 * We only support EDID reading from I2C_over_AUX. And
+		 * we do not expect the index mode to be used. Right now
+		 * the WRITE operation is ignored. It is good enough to
+		 * support the gfx driver to do EDID access.
+		 */
+	} else {
+		ASSERT((op & 0x1) == GVT_AUX_I2C_READ);
+		ASSERT(msg_length == 4);
+		if (i2c_edid->edid_available && i2c_edid->slave_selected) {
+			unsigned char val = edid_get_byte(vgt);
+			aux_data_for_write = (val << 16);
+		}
+	}
+
+	/* write the return value in AUX_CH_DATA reg which includes:
+	 * ACK of I2C_WRITE
+	 * returned byte if it is READ
+	 */
+	aux_data_for_write |= (GVT_AUX_I2C_REPLY_ACK & 0xff) << 24;
+	__vreg(vgt, offset + 4) = aux_data_for_write;
+
+	return;
+}
+
+void gvt_init_i2c_edid(struct vgt_device *vgt)
+{
+	struct gvt_i2c_edid_t *edid = &vgt->state.display.gvt_i2c_edid;
+
+	edid->state = I2C_NOT_SPECIFIED;
+
+	edid->port = I915_MAX_PORTS;
+	edid->slave_selected = false;
+	edid->edid_available = false;
+	edid->current_edid_read = 0;
+
+	memset(&edid->gmbus, 0, sizeof(struct gvt_i2c_gmbus_t));
+
+	edid->aux_ch.i2c_over_aux_ch = false;
+	edid->aux_ch.aux_ch_mot = false;
+}
diff --git a/drivers/gpu/drm/i915/gvt/edid.h b/drivers/gpu/drm/i915/gvt/edid.h
new file mode 100644
index 0000000..aa80ffd
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/edid.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_EDID_H_
+#define _GVT_EDID_H_
+
+#define EDID_SIZE		128
+#define EDID_ADDR		0x50 /* Linux hvm EDID addr */
+
+#define GVT_AUX_NATIVE_WRITE			0x8
+#define GVT_AUX_NATIVE_READ			0x9
+#define GVT_AUX_I2C_WRITE			0x0
+#define GVT_AUX_I2C_READ			0x1
+#define GVT_AUX_I2C_STATUS			0x2
+#define GVT_AUX_I2C_MOT				0x4
+#define GVT_AUX_I2C_REPLY_ACK			(0x0 << 6)
+
+#define _REGBIT_DP_AUX_CH_CTL_SEND_BUSY (1 << 31)
+#define _REGBIT_DP_AUX_CH_CTL_DONE (1 << 30)
+#define _DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT 	20
+#define _DP_AUX_CH_CTL_MESSAGE_SIZE_MASK 	(0x1f << 20)
+
+struct gvt_edid_data_t{
+	bool data_valid;
+	unsigned char edid_block[EDID_SIZE];
+};
+
+enum gmbus_cycle_type_t{
+	GMBUS_NOCYCLE	= 0x0,
+	NIDX_NS_W	= 0x1,
+	IDX_NS_W	= 0x3,
+	GMBUS_STOP	= 0x4,
+	NIDX_STOP	= 0x5,
+	IDX_STOP	= 0x7
+};
+
+/*
+ * States of GMBUS
+ *
+ * GMBUS0-3 could be related to the EDID virtualization. Another two GMBUS
+ * registers, GMBUS4 (interrupt mask) and GMBUS5 (2 byte indes register), are
+ * not considered here. Below describes the usage of GMBUS registers that are
+ * cared by the EDID virtualization
+ *
+ * GMBUS0:
+ * 	R/W
+ * 	port selection. value of bit0 - bit2 corresponds to the GPIO registers.
+ *
+ * GMBUS1:
+ * 	R/W Protect
+ * 	Command and Status.
+ * 	bit0 is the direction bit: 1 is read; 0 is write.
+ * 	bit1 - bit7 is slave 7-bit address.
+ * 	bit16 - bit24 total byte count (ignore?)
+ *
+ * GMBUS2:
+ * 	Most of bits are read only except bit 15 (IN_USE)
+ * 	Status register
+ * 	bit0 - bit8 current byte count
+ * 	bit 11: hardware ready;
+ *
+ * GMBUS3:
+ *	Read/Write
+ *	Data for transfer
+ */
+
+/* From hw specs, Other phases like START, ADDRESS, INDEX
+ * are invisible to GMBUS MMIO interface. So no definitions
+ * in below enum types
+ */
+enum gvt_gmbus_phase_t{
+	GMBUS_IDLE_PHASE = 0,
+	GMBUS_DATA_PHASE,
+	GMBUS_WAIT_PHASE,
+	//GMBUS_STOP_PHASE,
+	GMBUS_MAX_PHASE
+};
+
+struct gvt_i2c_gmbus_t {
+	unsigned total_byte_count; /* from GMBUS1 */
+	enum gmbus_cycle_type_t cycle_type;
+	enum gvt_gmbus_phase_t phase;
+};
+
+struct gvt_i2c_aux_ch_t{
+	bool i2c_over_aux_ch;
+	bool aux_ch_mot;
+};
+
+enum i2c_state_t {
+	I2C_NOT_SPECIFIED = 0,
+	I2C_GMBUS = 1,
+	I2C_AUX_CH = 2
+};
+
+/* I2C sequences cannot interleave.
+ * GMBUS and AUX_CH sequences cannot interleave.
+ */
+struct gvt_i2c_edid_t {
+	enum i2c_state_t state;
+
+	unsigned port;
+	bool slave_selected;
+	bool edid_available;
+	unsigned current_edid_read;
+
+	struct gvt_i2c_gmbus_t gmbus;
+	struct gvt_i2c_aux_ch_t aux_ch;
+};
+
+void gvt_init_i2c_edid(struct vgt_device *vgt);
+
+bool gvt_i2c_handle_gmbus_read(struct vgt_device *vgt, unsigned int offset,
+	void *p_data, unsigned int bytes);
+
+bool gvt_i2c_handle_gmbus_write(struct vgt_device *vgt, unsigned int offset,
+	void *p_data, unsigned int bytes);
+
+void gvt_i2c_handle_aux_ch_write(struct vgt_device *vgt,
+				enum port port_idx,
+				unsigned int offset,
+				void *p_data);
+
+bool gvt_is_edid_valid(u8 *raw_edid);
+
+#define AUX_REGISTER_NUM 6
+typedef enum {
+	AUX_CH_INV = -1,
+	AUX_CH_CTL = 0,
+	AUX_CH_DATA1,
+	AUX_CH_DATA2,
+	AUX_CH_DATA3,
+	AUX_CH_DATA4,
+	AUX_CH_DATA5
+}AUX_CH_REGISTERS;
+
+static inline enum port gvt_get_dp_port_idx(unsigned int offset)
+{
+	enum port port_idx;
+
+	if (offset >= _PCH_DPA_AUX_CH_CTL
+		&& offset <= _PCH_DPA_AUX_CH_CTL +
+				AUX_REGISTER_NUM * sizeof(u32)) {
+		return PORT_A;
+	}
+
+	switch (((offset & 0xff00) >> 8) - 0x41) {
+	case 0:
+		port_idx = PORT_B;
+		break;
+	case 1:
+		port_idx = PORT_C;
+		break;
+	case 2:
+		port_idx = PORT_D;
+		break;
+	default:
+		port_idx = I915_MAX_PORTS;
+		break;
+	}
+	return port_idx;
+}
+
+#endif /*_GVT_EDID_H_*/
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index 84549a0..ea871cd 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -242,6 +242,12 @@ static int gvt_service_thread(void *data)
 			gvt_dpy_ready_uevent_handler(pdev);
 		}
 
+		if (test_and_clear_bit(GVT_REQUEST_EMUL_DPY_EVENTS,
+					(void *)&pdev->service_request)) {
+			mutex_lock(&pdev->lock);
+			gvt_emulate_display_events(pdev);
+			mutex_unlock(&pdev->lock);
+		}
 
 		if (r) {
 			gvt_warn("service thread is waken up by unexpected signal.");
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 62cbb62..b44b5b5 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -40,6 +40,8 @@
 #include "cfg_space.h"
 #include "opregion.h"
 #include "fb_decoder.h"
+#include "edid.h"
+#include "display.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -123,11 +125,18 @@ struct gvt_virtual_gm_state {
 	struct gvt_gm_node node;
 };
 
+struct gvt_virtual_display_state {
+	struct gvt_i2c_edid_t   gvt_i2c_edid;
+	struct gt_port          ports[I915_MAX_PORTS];
+	struct sbi_registers sbi_regs;
+};
+
 struct gvt_virtual_device_state {
 	struct gvt_virtual_gm_state gm;
 	struct gvt_virtual_mmio_state mmio;
 	struct gvt_virtual_cfg_state cfg;
 	struct gvt_virtual_opregion_state opregion;
+	struct gvt_virtual_display_state display;
 };
 
 struct gvt_uevent {
@@ -676,6 +685,9 @@ bool gvt_default_mmio_write(struct vgt_device *vgt, unsigned int offset, void *p
 bool register_mmio_handler(struct pgt_device *pdev, unsigned int start, int bytes,
 	gvt_mmio_handler_t read, gvt_mmio_handler_t write);
 
+bool gvt_update_display_events_emulation(struct pgt_device *pdev);
+void gvt_emulate_display_events(struct pgt_device *pdev);
+
 #include "mpt.h"
 
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index ba29c9c..638a295 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -39,6 +39,18 @@ static bool mmio_not_allow_write(struct vgt_device *vgt,
 	return true;
 }
 
+static bool gmbus_mmio_read(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	return gvt_i2c_handle_gmbus_read(vgt, offset, p_data, bytes);
+}
+
+static bool gmbus_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	return gvt_i2c_handle_gmbus_write(vgt, offset, p_data, bytes);
+}
+
 /* Fence MMIO handlers. */
 static bool check_fence_mmio_access(struct vgt_device *vgt,
 		unsigned int off, void *p_data, unsigned int bytes)
@@ -138,12 +150,777 @@ static bool gdrst_mmio_write(struct vgt_device *vgt, unsigned int offset,
 	return true;
 }
 
+static bool pch_pp_control_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	u32 data;
+	u32 reg;
+	union _PCH_PP_CTL pp_control;
+	union _PCH_PP_STAUTS pp_status;
+
+	reg = offset & ~(bytes - 1);
+
+	data = *(u32*)p_data;
+
+	__vreg(vgt, _PCH_PP_CONTROL) = data;
+
+	pp_control.data = data;
+	pp_status.data = __vreg(vgt, _PCH_PP_STATUS);
+	if (pp_control.power_state_target == 1){
+		/* power on panel */
+		pp_status.panel_powere_on_statue = 1;
+		pp_status.power_sequence_progress = 0;
+		pp_status.power_cycle_delay_active = 0;
+	} else {
+		/* power down panel */
+		pp_status.panel_powere_on_statue = 0;
+		pp_status.power_sequence_progress = 0;
+		pp_status.power_cycle_delay_active = 0;
+	}
+	__vreg(vgt, _PCH_PP_STATUS) = pp_status.data;
+
+	return true;
+}
+
+static bool transaconf_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	union _TRANS_CONFIG config;
+
+	config.data = *(u32*)p_data;
+	config.transcoder_state = config.transcoder_enable;
+
+	__vreg(vgt, offset) = config.data;
+	return true;
+}
+
+/*
+ * TODO: Check the hotplug bit definitions on BDW+
+ */
+static bool shotplug_ctl_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	u32 val = *(u32 *)p_data;
+	u32 sticky_mask = _REGBIT_DP_B_STATUS |
+		_REGBIT_DP_C_STATUS |
+		_REGBIT_DP_D_STATUS;
+
+	__vreg(vgt, offset) = (val & ~sticky_mask) |
+		(__vreg(vgt, offset) & sticky_mask);
+	__vreg(vgt, offset) &= ~(val & sticky_mask);
+
+	__sreg(vgt, offset) = val;
+
+	return true;
+}
+
+static bool lcpll_ctl_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	u32 data = *(u32 *)p_data;
+
+	if (data & LCPLL_PLL_DISABLE)
+		data &= ~LCPLL_PLL_LOCK;
+	else
+		data |= LCPLL_PLL_LOCK;
+
+	if (data & LCPLL_CD_SOURCE_FCLK)
+		data |= LCPLL_CD_SOURCE_FCLK_DONE;
+	else
+		data &= ~LCPLL_CD_SOURCE_FCLK_DONE;
+
+	return gvt_default_mmio_write(vgt, offset, &data, bytes);
+}
+
+static bool dpy_reg_mmio_read(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	*(u32*)p_data = (1<<17);
+
+	return true;
+}
+
+static bool dpy_reg_mmio_read_2(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	*(u32*)p_data = 3;
+
+	return true;
+}
+
+static bool dpy_reg_mmio_read_3(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	*(u32*)p_data = (0x2F << 16);
+
+	return true;
+}
+
 static bool ring_mode_write(struct vgt_device *vgt, unsigned int off,
 		void *p_data, unsigned int bytes)
 {
 	return true;
 }
 
+static bool pipe_conf_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	u32 wr_data = *((u32 *)p_data);
+
+	/* vreg status will be updated when when read hardware status */
+	if (wr_data & PIPECONF_ENABLE)
+		wr_data |= I965_PIPECONF_ACTIVE;
+	else if (!(wr_data & PIPECONF_ENABLE))
+		wr_data &= I965_PIPECONF_ACTIVE;
+
+	if (!gvt_default_mmio_write(vgt, offset, &wr_data, bytes))
+		return false;
+
+	return gvt_update_display_events_emulation(vgt->pdev);
+}
+
+static bool ddi_buf_ctl_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	bool rc;
+	u32 reg_val;
+	reg_val = *(u32 *)p_data;
+
+	// set the fully virtualized RO bit with its original value
+	reg_val = (reg_val & ~_DDI_BUFCTL_DETECT_MASK)
+		| (__vreg(vgt, offset) & _DDI_BUFCTL_DETECT_MASK);
+
+	rc = gvt_default_mmio_write(vgt, offset, &reg_val, bytes);
+
+	//update idle status when enable/disable DDI buf
+	reg_val = __vreg(vgt, offset);
+
+	if (reg_val & _REGBIT_DDI_BUF_ENABLE)
+		reg_val &= ~_REGBIT_DDI_BUF_IS_IDLE;
+	else
+		reg_val |= _REGBIT_DDI_BUF_IS_IDLE;
+
+	__vreg(vgt, offset) = reg_val;
+
+	// clear the auto_training done bit
+	if ((offset == _REG_DDI_BUF_CTL_E) &&
+			(!(reg_val & _REGBIT_DDI_BUF_ENABLE))) {
+		__vreg(vgt, _REG_DP_TP_STATUS_E) &=
+			~DP_TP_STATUS_AUTOTRAIN_DONE;
+	}
+
+	return rc;
+}
+
+static bool fdi_rx_iir_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	unsigned int reg;
+	u32 wr_data, old_iir;
+	bool rc;
+	reg = offset & ~(bytes -1);
+
+	wr_data = *(u32 *)p_data;
+	old_iir = __vreg(vgt, reg);
+
+	rc = gvt_default_mmio_write(vgt, offset, p_data, bytes);
+
+	/* FIXME: sreg will be updated only when reading hardware status happened,
+	 * so when dumping sreg space, the "hardware status" related bits may not
+	 * be trusted */
+	__vreg(vgt, reg) = old_iir ^ wr_data;
+	return rc;
+}
+
+#define FDI_LINK_TRAIN_PATTERN1		0
+#define FDI_LINK_TRAIN_PATTERN2		1
+
+static bool fdi_auto_training_started(struct vgt_device *vgt)
+{
+	bool rc = false;
+
+	u32 ddi_buf_ctl = __vreg(vgt, _REG_DDI_BUF_CTL_E);
+	u32 rx_ctl = __vreg(vgt, _FDI_RXA_CTL);
+	u32 tx_ctl = __vreg(vgt, _REG_DP_TP_CTL_E);
+
+	if ((ddi_buf_ctl & _REGBIT_DDI_BUF_ENABLE) &&
+			(rx_ctl & FDI_RX_ENABLE) &&
+			(rx_ctl & _REGBIT_FDI_RX_FDI_AUTO_TRAIN_ENABLE) &&
+			(tx_ctl & DP_TP_CTL_ENABLE) &&
+			(tx_ctl & _REGBIT_DP_TP_FDI_AUTO_TRAIN_ENABLE)) {
+		rc = true;
+	}
+
+	return rc;
+}
+
+/* FIXME: this function is highly platform-dependent (SNB + CPT) */
+static bool check_fdi_rx_train_status(struct vgt_device *vgt,
+		enum pipe pipe, unsigned int train_pattern)
+{
+	unsigned int fdi_rx_imr, fdi_tx_ctl, fdi_rx_ctl;
+	unsigned int fdi_rx_check_bits, fdi_tx_check_bits;
+	unsigned int fdi_rx_train_bits, fdi_tx_train_bits;
+	unsigned int fdi_iir_check_bits;
+	fdi_rx_imr = GVT_FDI_RX_IMR(pipe);
+	fdi_tx_ctl = GVT_FDI_TX_CTL(pipe);
+	fdi_rx_ctl = GVT_FDI_RX_CTL(pipe);
+
+	if (train_pattern == FDI_LINK_TRAIN_PATTERN1) {
+		fdi_rx_train_bits =FDI_LINK_TRAIN_PATTERN_1_CPT;
+		fdi_tx_train_bits = FDI_LINK_TRAIN_PATTERN_1;
+		fdi_iir_check_bits = _REGBIT_FDI_RX_BIT_LOCK;
+	} else if (train_pattern == FDI_LINK_TRAIN_PATTERN2) {
+		fdi_rx_train_bits = FDI_LINK_TRAIN_PATTERN_2_CPT;
+		fdi_tx_train_bits = FDI_LINK_TRAIN_PATTERN_2;
+		fdi_iir_check_bits = _REGBIT_FDI_RX_SYMBOL_LOCK;
+	} else {
+		BUG();
+	}
+
+	fdi_rx_check_bits = FDI_RX_ENABLE | fdi_rx_train_bits;
+	fdi_tx_check_bits = _REGBIT_FDI_TX_ENABLE | fdi_tx_train_bits;
+
+	/* If imr bit not been masked */
+	if (((__vreg(vgt, fdi_rx_imr) & fdi_iir_check_bits) == 0)
+			&& ((__vreg(vgt, fdi_tx_ctl)
+					& fdi_tx_check_bits) == fdi_tx_check_bits)
+			&& ((__vreg(vgt, fdi_rx_ctl)
+					& fdi_rx_check_bits) == fdi_rx_check_bits))
+		return true;
+	else
+		return false;
+}
+
+static bool update_fdi_rx_iir_status(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	enum pipe pipe;
+	unsigned int reg, fdi_rx_iir;
+	bool rc;
+	reg = offset & ~(bytes - 1);
+
+	switch (offset) {
+		case _FDI_RXA_CTL:
+		case _FDI_TXA_CTL:
+		case _FDI_RXA_IMR:
+			pipe = PIPE_A;
+			break;
+
+		case _FDI_RXB_CTL:
+		case _FDI_TXB_CTL:
+		case _FDI_RXB_IMR:
+			pipe = PIPE_B;
+			break;
+
+		case _REG_FDI_RXC_CTL:
+		case _REG_FDI_TXC_CTL:
+		case _REG_FDI_RXC_IMR:
+			pipe = PIPE_C;
+			break;
+
+		default:
+			BUG();
+	}
+
+	fdi_rx_iir = GVT_FDI_RX_IIR(pipe);
+
+	rc = gvt_default_mmio_write(vgt, offset, p_data, bytes);
+	if (check_fdi_rx_train_status(vgt, pipe, FDI_LINK_TRAIN_PATTERN1))
+		__vreg(vgt, fdi_rx_iir) |= _REGBIT_FDI_RX_BIT_LOCK;
+	if (check_fdi_rx_train_status(vgt, pipe, FDI_LINK_TRAIN_PATTERN2))
+		__vreg(vgt, fdi_rx_iir) |= _REGBIT_FDI_RX_SYMBOL_LOCK;
+	if (offset == _FDI_RXA_CTL) {
+		if (fdi_auto_training_started(vgt))
+			__vreg(vgt, _REG_DP_TP_STATUS_E) |=
+				DP_TP_STATUS_AUTOTRAIN_DONE;
+	}
+	return rc;
+}
+
+#define DP_TP_CTL_10_8_MASK	0x00000700
+#define DP_TP_CTL_8_SHIFT	0x8
+#define DP_TP_STATUS_25_SHIFT	25
+
+static bool dp_tp_ctl_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	enum port port;
+	unsigned int dp_tp_status_reg, val;
+	u32 ctl_val;
+	bool rc;
+	rc = gvt_default_mmio_write(vgt, offset, p_data, bytes);
+
+	port = DP_TP_PORT(offset);
+	ctl_val = __vreg(vgt, offset);
+	val = (ctl_val & DP_TP_CTL_10_8_MASK) >> DP_TP_CTL_8_SHIFT;
+
+	if (val == 0x2) {
+		dp_tp_status_reg = i915_mmio_reg_offset(DP_TP_STATUS(port));
+		__vreg(vgt, dp_tp_status_reg) |= (1 << DP_TP_STATUS_25_SHIFT);
+		__sreg(vgt, dp_tp_status_reg) = __vreg(vgt, dp_tp_status_reg);
+	}
+	return rc;
+}
+
+#define BIT_27		27
+#define BIT_26		26
+#define BIT_24		24
+
+static bool dp_tp_status_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	bool rc = true;
+	u32 reg_val;
+	u32 sticky_mask;
+	reg_val = *((u32 *)p_data);
+	sticky_mask = (1 << BIT_27) | (1 << BIT_26) | (1 << BIT_24);
+
+	__vreg(vgt, offset) = (reg_val & ~sticky_mask) |
+		(__vreg(vgt, offset) & sticky_mask);
+	__vreg(vgt, offset) &= ~(reg_val & sticky_mask);
+
+	__sreg(vgt, offset) = reg_val;
+
+	return rc;
+}
+
+static bool pch_adpa_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	u32 old = __vreg(vgt, offset);
+	u32 new = *(u32 *)p_data;
+
+	if (new & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) {
+		new &= ~(ADPA_CRT_HOTPLUG_FORCE_TRIGGER |
+				ADPA_CRT_HOTPLUG_MONITOR_MASK);
+	} else {
+		/* ignore the status bits in new value
+		 * since they are read only actually
+		 */
+		new = (new & ~ADPA_CRT_HOTPLUG_MONITOR_MASK) |
+			(old & ADPA_CRT_HOTPLUG_MONITOR_MASK);
+	}
+
+	return gvt_default_mmio_write(vgt, offset, &new, bytes);
+}
+
+static bool pri_surf_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	struct gvt_fb_notify_msg msg;
+	enum pipe pipe = GVT_DSPSURFPIPE(offset);
+	u32 surflive_reg = GVT_DSPSURFLIVE(pipe);
+
+	if (!gvt_default_mmio_write(vgt, offset, p_data, bytes))
+		return false;
+
+	/* Update virtual surflive register */
+	if (!gvt_default_mmio_write(vgt, surflive_reg, p_data, bytes))
+		return false;
+
+	__vreg(vgt, GVT_PIPE_FLIPCOUNT(pipe))++;
+	gvt_inject_flip_done(vgt, GVT_DSPSURFPIPE(offset));
+
+	msg.vm_id = vgt->vm_id;
+	msg.plane_id = PRIMARY_PLANE;
+	msg.pipe_id = GVT_DSPSURFPIPE(offset);
+	gvt_fb_notifier_call_chain(FB_DISPLAY_FLIP, &msg);
+
+	return true;
+}
+
+static bool spr_surf_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	struct gvt_fb_notify_msg msg;
+	enum pipe pipe = GVT_SPRSURFPIPE(offset);
+	u32 surflive_reg = GVT_SPRSURFLIVE(pipe);
+
+	if (!gvt_default_mmio_write(vgt, offset, p_data, bytes))
+		return false;
+
+	/* Update virtual surflive register */
+	if (!gvt_default_mmio_write(vgt, surflive_reg, p_data, bytes))
+		return false;
+
+	msg.vm_id = vgt->vm_id;
+	msg.plane_id = SPRITE_PLANE;
+	msg.pipe_id = GVT_SPRSURFPIPE(offset);
+	gvt_fb_notifier_call_chain(FB_DISPLAY_FLIP, &msg);
+
+	return true;
+}
+
+static bool south_chicken2_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	u32 data = *(u32 *)p_data;
+
+	if (data & FDI_MPHY_IOSFSB_RESET_CTL)
+		data |= FDI_MPHY_IOSFSB_RESET_STATUS;
+	else
+		data &= ~FDI_MPHY_IOSFSB_RESET_STATUS;
+
+	return gvt_default_mmio_write(vgt, offset, &data, bytes);
+}
+
+static void dp_aux_ch_trigger_interrupt_on_done(struct vgt_device *vgt, u32 value,
+		unsigned int reg)
+{
+	enum gvt_event_type event = GVT_EVENT_MAX;
+	if (reg == _PCH_DPA_AUX_CH_CTL) {
+		event = AUX_CHANNEL_A;
+	} else if (reg == _PCH_DPB_AUX_CH_CTL) {
+		event = AUX_CHENNEL_B;
+	} else if (reg == _PCH_DPC_AUX_CH_CTL) {
+		event = AUX_CHENNEL_C;
+	} else if (reg == _PCH_DPD_AUX_CH_CTL) {
+		event = AUX_CHENNEL_D;
+	}
+
+	if (event != GVT_EVENT_MAX && (DP_AUX_CH_CTL_INTERRUPT & value)) {
+		gvt_trigger_virtual_event(vgt, event);
+	}
+}
+
+static void dp_aux_ch_ctl_trans_done(struct vgt_device *vgt, u32 value,
+		unsigned int reg, int len, bool data_valid)
+{
+	/* mark transaction done */
+	value |= _REGBIT_DP_AUX_CH_CTL_DONE;
+	value &= ~_REGBIT_DP_AUX_CH_CTL_SEND_BUSY;
+	value &= ~DP_AUX_CH_CTL_RECEIVE_ERROR;
+
+	if (data_valid) {
+		value &= ~DP_AUX_CH_CTL_TIME_OUT_ERROR;
+	} else {
+		value |= DP_AUX_CH_CTL_TIME_OUT_ERROR;
+	}
+
+	/* message size */
+	value &= ~(0xf << 20);
+	value |= (len << 20);
+	__vreg(vgt, reg) = value;
+
+	dp_aux_ch_trigger_interrupt_on_done(vgt, value, reg);
+}
+
+static void dp_aux_ch_ctl_link_training(struct gvt_dpcd_data *dpcd, uint8_t t)
+{
+	if ((t & DPCD_TRAINING_PATTERN_SET_MASK) == DPCD_TRAINING_PATTERN_1) {
+
+		/* training pattern 1 for CR */
+		/* set LANE0_CR_DONE, LANE1_CR_DONE */
+		dpcd->data[DPCD_LANE0_1_STATUS] |= DPCD_LANES_CR_DONE;
+		/* set LANE2_CR_DONE, LANE3_CR_DONE */
+		dpcd->data[DPCD_LANE2_3_STATUS] |= DPCD_LANES_CR_DONE;
+
+	} else if ((t & DPCD_TRAINING_PATTERN_SET_MASK) ==
+			DPCD_TRAINING_PATTERN_2) {
+
+		/* training pattern 2 for EQ */
+
+		/* Set CHANNEL_EQ_DONE and  SYMBOL_LOCKED for Lane0_1 */
+		dpcd->data[DPCD_LANE0_1_STATUS] |= DPCD_LANES_EQ_DONE;
+		dpcd->data[DPCD_LANE0_1_STATUS] |= DPCD_SYMBOL_LOCKED;
+
+		/* Set CHANNEL_EQ_DONE and  SYMBOL_LOCKED for Lane2_3 */
+		dpcd->data[DPCD_LANE2_3_STATUS] |= DPCD_LANES_EQ_DONE;
+		dpcd->data[DPCD_LANE2_3_STATUS] |= DPCD_SYMBOL_LOCKED;
+		/* set INTERLANE_ALIGN_DONE */
+		dpcd->data[DPCD_LANE_ALIGN_STATUS_UPDATED] |=
+			DPCD_INTERLANE_ALIGN_DONE;
+
+	} else if ((t & DPCD_TRAINING_PATTERN_SET_MASK) ==
+			DPCD_LINK_TRAINING_DISABLED) {
+
+		/* finish link training */
+		/* set sink status as synchronized */
+		dpcd->data[DPCD_SINK_STATUS] = DPCD_SINK_IN_SYNC;
+	}
+}
+
+static bool dp_aux_ch_ctl_mmio_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	unsigned int reg = 0;
+	u32 value = *(u32 *)p_data;
+	int msg, addr, ctrl, op, len;
+	struct gvt_dpcd_data *dpcd = NULL;
+	enum port port_idx = gvt_get_dp_port_idx(offset);
+	struct gt_port *port = NULL;
+	ASSERT(bytes == 4);
+	ASSERT((offset & (bytes - 1)) == 0);
+
+	reg = offset & ~(bytes - 1);
+
+	gvt_default_mmio_write(vgt, offset, p_data, bytes);
+
+	if (reg != _PCH_DPA_AUX_CH_CTL &&
+			reg != _PCH_DPB_AUX_CH_CTL &&
+			reg != _PCH_DPC_AUX_CH_CTL &&
+			reg != _PCH_DPD_AUX_CH_CTL) {
+		/* write to the data registers */
+		return true;
+	}
+
+	if (!(value & _REGBIT_DP_AUX_CH_CTL_SEND_BUSY)) {
+		/* just want to clear the sticky bits */
+		__vreg(vgt, reg) = 0;
+		return true;
+	}
+
+	if (!dpy_is_valid_port(port_idx)) {
+		gvt_warn("vGT(%d): Unsupported DP port access!\n",
+				vgt->id);
+		return true;
+	}
+
+	port = gvt_vport(vgt, port_idx);
+
+	if (port) {
+		dpcd = port->dpcd;
+	}
+
+	/* read out message from DATA1 register */
+	msg = __vreg(vgt, reg + 4);
+	addr = (msg >> 8) & 0xffff;
+	ctrl = (msg >> 24) & 0xff;
+	len = msg & 0xff;
+	op = ctrl >> 4;
+
+	if (op == GVT_AUX_NATIVE_WRITE) {
+		int t;
+		uint8_t buf[16];
+
+		if ((addr + len + 1) >= DPCD_SIZE) {
+			/*
+			 * Write request exceeds what we supported,
+			 * DCPD spec: When a Source Device is writing a DPCD
+			 * address not supported by the Sink Device, the Sink
+			 * Device shall reply with AUX NACK and “M” equal to zero.
+			 */
+
+			/* NAK the write */
+			__vreg(vgt, reg + 4) = AUX_NATIVE_REPLY_NAK;
+
+			dp_aux_ch_ctl_trans_done(vgt, value, reg, 2, true);
+
+			return true;
+		}
+
+		/*
+		 * Write request format: (command + address) occupies
+		 * 3 bytes, followed by (len + 1) bytes of data.
+		 */
+		ASSERT((len + 4) <= AUX_BURST_SIZE);
+
+		/* unpack data from vreg to buf */
+		for (t = 0; t < 4; t ++) {
+			u32 r = __vreg(vgt, reg + 8 + t*4);
+
+			buf[t*4] = (r >> 24) & 0xff;
+			buf[t*4 + 1] = (r >> 16) & 0xff;
+			buf[t*4 + 2] = (r >> 8) & 0xff;
+			buf[t*4 + 3] = r & 0xff;
+		}
+
+		/* write to virtual DPCD */
+		if (dpcd && dpcd->data_valid) {
+			for (t = 0; t <= len; t ++) {
+				int p = addr + t;
+
+				dpcd->data[p] = buf[t];
+
+				/* check for link training */
+				if (p == DPCD_TRAINING_PATTERN_SET)
+					dp_aux_ch_ctl_link_training(dpcd, buf[t]);
+			}
+		}
+
+		/* ACK the write */
+		__vreg(vgt, reg + 4) = 0;
+
+		dp_aux_ch_ctl_trans_done(vgt, value, reg, 1, dpcd && dpcd->data_valid);
+
+		return true;
+	}
+
+	if (op == GVT_AUX_NATIVE_READ) {
+		int idx, i, ret = 0;
+
+		if ((addr + len + 1) >= DPCD_SIZE) {
+			/*
+			 * read request exceeds what we supported
+			 * DPCD spec: A Sink Device receiving a Native AUX CH
+			 * read request for an unsupported DPCD address must
+			 * reply with an AUX ACK and read data set equal to
+			 * zero instead of replying with AUX NACK.
+			 */
+
+			/* ACK the READ*/
+			__vreg(vgt, reg + 4) = 0;
+			__vreg(vgt, reg + 8) = 0;
+			__vreg(vgt, reg + 12) = 0;
+			__vreg(vgt, reg + 16) = 0;
+			__vreg(vgt, reg + 20) = 0;
+
+			dp_aux_ch_ctl_trans_done(vgt ,value, reg, len + 2, true);
+
+			return true;
+		}
+
+		for (idx = 1; idx <= 5; idx ++) {
+			/* clear the data registers */
+			__vreg(vgt, reg + 4 * idx) = 0;
+		}
+
+		/*
+		 * Read reply format: ACK (1 byte) plus (len + 1) bytes of data.
+		 */
+		ASSERT((len + 2) <= AUX_BURST_SIZE);
+
+		/* read from virtual DPCD to vreg */
+		/* first 4 bytes: [ACK][addr][addr+1][addr+2] */
+		if (dpcd && dpcd->data_valid) {
+			for (i = 1; i <= (len + 1); i ++) {
+				int t;
+
+				t = dpcd->data[addr + i - 1];
+				t <<= (24 - 8*(i%4));
+				ret |= t;
+
+				if ((i%4 == 3) || (i == (len + 1))) {
+					__vreg(vgt, reg + (i/4 + 1)*4) = ret;
+					ret = 0;
+				}
+			}
+		}
+
+		dp_aux_ch_ctl_trans_done(vgt, value, reg, len + 2, dpcd && dpcd->data_valid);
+
+		return true;
+	}
+
+	/* i2c transaction starts */
+	gvt_i2c_handle_aux_ch_write(vgt, port_idx, offset, p_data);
+
+	dp_aux_ch_trigger_interrupt_on_done(vgt, value, reg);
+	return true;
+}
+
+static void gvt_dpy_stat_notify(struct vgt_device *vgt)
+{
+	struct pgt_device *pdev = vgt->pdev;
+
+	gvt_set_dpy_uevent(vgt);
+	gvt_raise_request(pdev, GVT_REQUEST_UEVENT);
+}
+
+static bool vga_control_w(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	bool vga_disable;
+	gvt_default_mmio_write(vgt, offset, p_data, bytes);
+
+	vga_disable = __vreg(vgt, offset) & _REGBIT_VGA_DISPLAY_DISABLE;
+
+	gvt_info("VM(%d): %s VGA mode %x\n", vgt->vm_id,
+			vga_disable ? "Disable" : "Enable",
+			(unsigned int)__vreg(vgt, offset));
+	return true;
+}
+
+static u32 get_sbi_reg_cached_value(struct vgt_device *vgt,
+		unsigned int sbi_offset)
+{
+	int i;
+	int num = vgt->state.display.sbi_regs.number;
+	u32 value = 0;
+	for (i = 0; i < num; ++ i) {
+		if (vgt->state.display.sbi_regs.registers[i].offset == sbi_offset)
+			break;
+	}
+
+	if (i < num) {
+		value = vgt->state.display.sbi_regs.registers[i].value;
+	} else {
+		gvt_warn("vGT(%d): SBI reading did not find the cached value"
+				" for offset 0x%x. 0 will be returned!\n",
+				vgt->id, sbi_offset);
+	}
+	return value;
+}
+
+static void cache_sbi_reg_value(struct vgt_device *vgt, unsigned int sbi_offset,
+		u32 value)
+{
+	int i;
+	int num = vgt->state.display.sbi_regs.number;
+	for (i = 0; i < num; ++ i) {
+		if (vgt->state.display.sbi_regs.registers[i].offset == sbi_offset)
+			break;
+	}
+
+	if (i == num) {
+		if (num < SBI_REG_MAX) {
+			vgt->state.display.sbi_regs.number ++;
+		} else {
+			gvt_warn("vGT(%d): SBI caching meets maximum limits!\n",
+					vgt->id);
+			return;
+		}
+	}
+
+	vgt->state.display.sbi_regs.registers[i].offset = sbi_offset;
+	vgt->state.display.sbi_regs.registers[i].value = value;
+}
+
+static bool sbi_mmio_data_read(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	bool rc = 0;
+	rc = gvt_default_mmio_read(vgt, offset, p_data, bytes);
+
+	if (((__vreg(vgt, _SBI_CTL_STAT) & SBI_OPCODE_MASK) >>
+				SBI_OPCODE_SHIFT) == SBI_CMD_CRRD) {
+		unsigned int sbi_offset = (__vreg(vgt, _SBI_ADDR) &
+				SBI_ADDR_OFFSET_MASK) >> SBI_ADDR_OFFSET_SHIFT;
+		u32 val = get_sbi_reg_cached_value(vgt, sbi_offset);
+		*(u32 *)p_data = val;
+	}
+	return rc;
+}
+
+static bool sbi_mmio_ctl_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	bool rc = 0;
+	u32 data;
+	rc = gvt_default_mmio_write(vgt, offset, p_data, bytes);
+
+	data = __vreg(vgt, offset);
+
+	data &= ~(SBI_STAT_MASK << SBI_STAT_SHIFT);
+	data |= SBI_READY;
+
+	data &= ~(SBI_RESPONSE_MASK << SBI_RESPONSE_SHIFT);
+	data |= SBI_RESPONSE_SUCCESS;
+
+	__vreg(vgt, offset) = data;
+
+	if (((__vreg(vgt, _SBI_CTL_STAT) & SBI_OPCODE_MASK) >>
+				SBI_OPCODE_SHIFT) == SBI_CMD_CRWR) {
+		unsigned int sbi_offset = (__vreg(vgt, _SBI_ADDR) &
+				SBI_ADDR_OFFSET_MASK) >> SBI_ADDR_OFFSET_SHIFT;
+		u32 val = __vreg(vgt, _SBI_DATA);
+		cache_sbi_reg_value(vgt, sbi_offset, val);
+	}
+
+	return rc;
+}
+
 static bool pvinfo_read(struct vgt_device *vgt, unsigned int offset,
 		void *p_data, unsigned int bytes)
 {
@@ -193,6 +970,7 @@ static bool pvinfo_write(struct vgt_device *vgt, unsigned int offset,
 	u32 val = *(u32 *)p_data;
 	u32 min;
 	bool rc = true;
+	bool invalid_event = false;
 
 	switch (offset) {
 		case _vgtif_reg(min_low_gmadr):
@@ -223,8 +1001,30 @@ static bool pvinfo_write(struct vgt_device *vgt, unsigned int offset,
 				rc = false;
 			}
 			break;
+		case _vgtif_reg(display_ready):
+			switch (val) {
+				case 0:
+				case 1:
+				case 2:
+					break;
+				default:
+					invalid_event = true;
+					gvt_warn("invalid display event: %d\n", val);
+					break;
+			}
+
+			if (!invalid_event)
+				gvt_dpy_stat_notify(vgt);
+
+				break;
 		case _vgtif_reg(g2v_notify):
-				if (val == VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE) {
+				if (val == VGT_G2V_SET_POINTER_SHAPE) {
+					struct gvt_fb_notify_msg msg;
+					msg.vm_id = vgt->vm_id;
+					msg.plane_id = CURSOR_PLANE;
+					msg.pipe_id = 0;
+					gvt_fb_notifier_call_chain(FB_DISPLAY_FLIP, &msg);
+				} else if (val == VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE) {
 					rc = gvt_g2v_create_ppgtt_mm(vgt, 3);
 				} else if (val == VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY) {
 					rc = gvt_g2v_destroy_ppgtt_mm(vgt, 3);
@@ -236,6 +1036,17 @@ static bool pvinfo_write(struct vgt_device *vgt, unsigned int offset,
 					gvt_warn("Invalid PV notification. %x\n", val);
 				}
 			break;
+		case _vgtif_reg(xhot):
+		case _vgtif_reg(yhot):
+			{
+				struct gvt_fb_notify_msg msg;
+				msg.vm_id = vgt->vm_id;
+				msg.plane_id = CURSOR_PLANE;
+				msg.pipe_id = 0;
+				gvt_fb_notifier_call_chain(FB_DISPLAY_FLIP, &msg);
+			}
+			break;
+
 		case _vgtif_reg(pdp[0].lo):
 		case _vgtif_reg(pdp[0].hi):
 		case _vgtif_reg(pdp[1].lo):
@@ -262,6 +1073,22 @@ static bool pvinfo_write(struct vgt_device *vgt, unsigned int offset,
 	return rc;
 }
 
+static bool power_well_ctl_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	bool rc = true;
+	u32 value = *(u32 *)p_data;
+	memcpy ((char *)vgt->state.mmio.vreg + offset, p_data, bytes);
+
+	if (value & HSW_PWR_WELL_ENABLE_REQUEST) {
+		__vreg(vgt, offset) |= HSW_PWR_WELL_STATE_ENABLED;
+	} else {
+		__vreg(vgt, offset) &= ~HSW_PWR_WELL_STATE_ENABLED;
+	}
+
+	return rc;
+}
+
 bool fpga_dbg_write(struct vgt_device *vgt, unsigned int reg,
         void *p_data, unsigned int bytes)
 {
@@ -408,6 +1235,26 @@ struct gvt_reg_info gvt_general_reg_info[] = {
 
 	{_DERRMR, 4, F_VIRT, 0, D_ALL, NULL, NULL},
 
+	{GVT_PIPEDSL(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPECONF(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, pipe_conf_mmio_write},
+	{GVT_PIPESTAT(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPE_FRMCOUNT(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPE_FLIPCOUNT(PIPE_A), 4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{GVT_PIPEDSL(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPECONF(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, pipe_conf_mmio_write},
+	{GVT_PIPESTAT(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPE_FRMCOUNT(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPE_FLIPCOUNT(PIPE_B), 4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{GVT_PIPEDSL(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPECONF(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, pipe_conf_mmio_write},
+	{GVT_PIPESTAT(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPE_FRMCOUNT(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_PIPE_FLIPCOUNT(PIPE_C), 4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{_REG_PIPE_EDP_CONF, 4, F_DPY, 0, D_ALL, NULL, pipe_conf_mmio_write},
+
 	{GVT_CURSURF(PIPE_A), 4, F_DPY_ADRFIX, 0xFFFFF000, D_ALL, NULL, NULL},
 	{GVT_CURCNTR(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{GVT_CURPOS(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
@@ -431,6 +1278,57 @@ struct gvt_reg_info gvt_general_reg_info[] = {
 	{_REG_CURAPALET_2, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_REG_CURAPALET_3, 4, F_DPY, 0, D_ALL, NULL, NULL},
 
+	{GVT_DSPCNTR(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPSURF(PIPE_A), 4, F_DPY_ADRFIX, 0xFFFFF000, D_ALL, NULL,
+		pri_surf_mmio_write},
+	{GVT_DSPSURFLIVE(PIPE_A), 4, F_DPY_HWSTS_ADRFIX, 0xFFFFF000, D_ALL, NULL,
+		mmio_not_allow_write},
+	{GVT_DSPPOS(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPLINOFF(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPSTRIDE(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPSIZE(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPTILEOFF(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{GVT_DSPCNTR(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPSURF(PIPE_B), 4, F_DPY_ADRFIX, 0xFFFFF000, D_ALL, NULL,
+	    pri_surf_mmio_write},
+	{GVT_DSPSURFLIVE(PIPE_B), 4, F_DPY_HWSTS_ADRFIX, 0xFFFFF000, D_ALL, NULL,
+	    mmio_not_allow_write},
+	{GVT_DSPPOS(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPLINOFF(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPSTRIDE(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPSIZE(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPTILEOFF(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{GVT_DSPCNTR(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPSURF(PIPE_C), 4, F_DPY_ADRFIX, 0xFFFFF000, D_ALL, NULL,
+	    pri_surf_mmio_write},
+	{GVT_DSPSURFLIVE(PIPE_C), 4, F_DPY_HWSTS_ADRFIX, 0xFFFFF000, D_ALL, NULL,
+	    mmio_not_allow_write},
+	{GVT_DSPPOS(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPLINOFF(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPSTRIDE(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPSIZE(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{GVT_DSPTILEOFF(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{GVT_SPRSURF(PIPE_A), 4, F_DPY_ADRFIX, 0xFFFFF000, D_ALL,
+		NULL, spr_surf_mmio_write},
+	{GVT_SPRSURFLIVE(PIPE_A), 4, F_DPY_HWSTS_ADRFIX, 0xFFFFF000, D_ALL,
+		NULL, mmio_not_allow_write},
+	{GVT_SPRCNTR(PIPE_A), 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{GVT_SPRSURF(PIPE_B), 4, F_DPY_ADRFIX, 0xFFFFF000, D_ALL,
+		NULL, spr_surf_mmio_write},
+	{GVT_SPRSURFLIVE(PIPE_B), 4, F_DPY_HWSTS_ADRFIX, 0xFFFFF000, D_ALL,
+		NULL, mmio_not_allow_write},
+	{GVT_SPRCNTR(PIPE_B), 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{GVT_SPRSURF(PIPE_C), 4, F_DPY_ADRFIX, 0xFFFFF000, D_ALL,
+		NULL, spr_surf_mmio_write},
+	{GVT_SPRSURFLIVE(PIPE_C), 4, F_DPY_HWSTS_ADRFIX, 0xFFFFF000, D_ALL,
+		NULL, mmio_not_allow_write},
+	{GVT_SPRCNTR(PIPE_C), 4, F_DPY, 0, D_ALL, NULL, NULL},
+
 	{_LGC_PALETTE_A, 4 * 256, F_DPY, 0, D_ALL, NULL, NULL},
 	{_LGC_PALETTE_B, 4 * 256, F_DPY, 0, D_ALL, NULL, NULL},
 	{_REG_LGC_PALETTE_C, 4 * 256, F_DPY, 0, D_ALL, NULL, NULL},
@@ -521,6 +1419,31 @@ struct gvt_reg_info gvt_general_reg_info[] = {
 	{_BLC_PWM_PCH_CTL1, 4, F_DOM0, 0, D_ALL, NULL, NULL},
 	{_BLC_PWM_PCH_CTL2, 4, F_DOM0, 0, D_ALL, NULL, NULL},
 
+	{_PCH_GMBUS0, 4*4, F_DPY, 0, D_ALL, gmbus_mmio_read, gmbus_mmio_write},
+	{_PCH_GPIOA, 6*4, F_VIRT, 0, D_ALL, NULL, NULL},
+
+	{_REG_DP_BUFTRANS, 0x28, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_PCH_DPB_AUX_CH_CTL, 6*4, F_DPY, 0, D_ALL, NULL, dp_aux_ch_ctl_mmio_write},
+	{_PCH_DPC_AUX_CH_CTL, 6*4, F_DPY, 0, D_ALL, NULL, dp_aux_ch_ctl_mmio_write},
+	{_PCH_DPD_AUX_CH_CTL, 6*4, F_DPY, 0, D_ALL, NULL, dp_aux_ch_ctl_mmio_write},
+
+	{_PCH_ADPA, 4, F_DPY, 0, D_ALL, NULL, pch_adpa_mmio_write},
+	{_PCH_TRANSACONF, 4, F_DPY, 0, D_ALL, NULL, transaconf_mmio_write},
+	{_PCH_TRANSBCONF, 4, F_DPY, 0, D_ALL, NULL, transaconf_mmio_write},
+	{_FDI_RXA_IIR, 4, F_DPY, 0, D_ALL, NULL, fdi_rx_iir_mmio_write},
+	{_FDI_RXB_IIR, 4, F_DPY, 0, D_ALL, NULL, fdi_rx_iir_mmio_write},
+	{_REG_FDI_RXC_IIR, 4, F_DPY, 0, D_ALL, NULL, fdi_rx_iir_mmio_write},
+	{_FDI_RXA_CTL, 4, F_DPY, 0, D_ALL, NULL, update_fdi_rx_iir_status},
+	{_FDI_RXB_CTL, 4, F_DPY, 0, D_ALL, NULL, update_fdi_rx_iir_status},
+	{_REG_FDI_RXC_CTL, 4, F_DPY, 0, D_ALL, NULL, update_fdi_rx_iir_status},
+	{_FDI_TXA_CTL, 4, F_DPY, 0, D_ALL, NULL, update_fdi_rx_iir_status},
+	{_FDI_TXB_CTL, 4, F_DPY, 0, D_ALL, NULL, update_fdi_rx_iir_status},
+	{_REG_FDI_TXC_CTL, 4, F_DPY, 0, D_ALL, NULL, update_fdi_rx_iir_status},
+	{_FDI_RXA_IMR, 4, F_DPY, 0, D_ALL, NULL, update_fdi_rx_iir_status},
+	{_FDI_RXB_IMR, 4, F_DPY, 0, D_ALL, NULL, update_fdi_rx_iir_status},
+	{_REG_FDI_RXC_IMR, 4, F_DPY, 0, D_ALL, NULL, update_fdi_rx_iir_status},
+
 	{_PCH_TRANS_HTOTAL_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_PCH_TRANS_HBLANK_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_PCH_TRANS_HSYNC_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
@@ -566,6 +1489,9 @@ struct gvt_reg_info gvt_general_reg_info[] = {
 	{_FDI_RXB_TUSIZE1, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_FDI_RXB_TUSIZE2, 4, F_DPY, 0, D_ALL, NULL, NULL},
 
+	{_PCH_PP_CONTROL, 4, F_DPY, 0, D_ALL, NULL, pch_pp_control_mmio_write},
+	{_PCH_PP_DIVISOR, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_PP_STATUS, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_PCH_LVDS, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_PCH_DPLL_A, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_PCH_DPLL_B, 4, F_DPY, 0, D_ALL, NULL, NULL},
@@ -582,6 +1508,16 @@ struct gvt_reg_info gvt_general_reg_info[] = {
 	{_PCH_PP_ON_DELAYS, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_PCH_PP_OFF_DELAYS, 4, F_DPY, 0, D_ALL, NULL, NULL},
 
+	{0xE651C, 4, F_DPY, 0, D_ALL, dpy_reg_mmio_read, NULL},
+	{0xE661C, 4, F_DPY, 0, D_ALL, dpy_reg_mmio_read, NULL},
+	{0xE671C, 4, F_DPY, 0, D_ALL, dpy_reg_mmio_read, NULL},
+	{0xE681C, 4, F_DPY, 0, D_ALL, dpy_reg_mmio_read, NULL},
+	{0xE6C04, 4, F_DPY, 0, D_ALL,
+		dpy_reg_mmio_read_2, NULL},
+	{0xE6E1C, 4, F_DPY, 0, D_ALL,
+		dpy_reg_mmio_read_3, NULL},
+	{_PCH_PORT_HOTPLUG, 4, F_VIRT, 0, D_ALL, NULL, shotplug_ctl_mmio_write},
+	{_LCPLL_CTL, 4, F_DPY, 0, D_ALL, NULL, lcpll_ctl_mmio_write},
 	{_FUSE_STRAP, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_DIGITAL_PORT_HOTPLUG_CNTRL, 4, F_DPY, 0, D_ALL, NULL, NULL},
 
@@ -592,6 +1528,8 @@ struct gvt_reg_info gvt_general_reg_info[] = {
 	{_ILK_DISPLAY_CHICKEN2, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_ILK_DSPCLK_GATE_D, 4, F_DPY, 0, D_ALL, NULL, NULL},
 
+	{_SOUTH_CHICKEN1, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_SOUTH_CHICKEN2, 4, F_DPY, 0, D_ALL, NULL, south_chicken2_write},
 	{_TRANSA_CHICKEN1, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_TRANSB_CHICKEN1, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_SOUTH_DSPCLK_GATE_D, 4, F_DPY, 0, D_ALL, NULL, NULL},
@@ -685,8 +1623,30 @@ struct gvt_reg_info gvt_general_reg_info[] = {
 
 	{_SFUSE_STRAP, 4, F_DPY, 0, D_ALL, NULL, NULL},
 	{_SBI_ADDR, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_SBI_DATA, 4, F_DPY, 0, D_ALL, sbi_mmio_data_read, NULL},
+	{_SBI_CTL_STAT, 4, F_DPY, 0, D_ALL, NULL, sbi_mmio_ctl_write},
 	{_PIXCLK_GATE, 4, F_DPY, 0, D_ALL, NULL, NULL},
 
+	{_PCH_DPA_AUX_CH_CTL, 6*4, F_DPY, 0, D_ALL, NULL, dp_aux_ch_ctl_mmio_write},
+
+	{_DDI_BUF_CTL_A, 4, F_DPY, 0, D_ALL, NULL, ddi_buf_ctl_mmio_write},
+	{_DDI_BUF_CTL_B, 4, F_DPY, 0, D_ALL, NULL, ddi_buf_ctl_mmio_write},
+	{_REG_DDI_BUF_CTL_C, 4, F_DPY, 0, D_ALL, NULL, ddi_buf_ctl_mmio_write},
+	{_REG_DDI_BUF_CTL_D, 4, F_DPY, 0, D_ALL, NULL, ddi_buf_ctl_mmio_write},
+	{_REG_DDI_BUF_CTL_E, 4, F_DPY, 0, D_ALL, NULL, ddi_buf_ctl_mmio_write},
+
+	{_DP_TP_CTL_A, 4, F_DPY, 0, D_ALL, NULL, dp_tp_ctl_mmio_write},
+	{_DP_TP_CTL_B, 4, F_DPY, 0, D_ALL, NULL, dp_tp_ctl_mmio_write},
+	{_REG_DP_TP_CTL_C, 4, F_DPY, 0, D_ALL, NULL, dp_tp_ctl_mmio_write},
+	{_REG_DP_TP_CTL_D, 4, F_DPY, 0, D_ALL, NULL, dp_tp_ctl_mmio_write},
+	{_REG_DP_TP_CTL_E, 4, F_DPY, 0, D_ALL, NULL, NULL},
+
+	{_DP_TP_STATUS_A, 4, F_DPY, 0, D_ALL, NULL, dp_tp_status_mmio_write},
+	{_DP_TP_STATUS_B, 4, F_DPY, 0, D_ALL, NULL, dp_tp_status_mmio_write},
+	{_REG_DP_TP_STATUS_C, 4, F_DPY, 0, D_ALL, NULL, dp_tp_status_mmio_write},
+	{_REG_DP_TP_STATUS_D, 4, F_DPY, 0, D_ALL, NULL, dp_tp_status_mmio_write},
+	{_REG_DP_TP_STATUS_E, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_DDI_BUF_TRANS_A, 0x50, F_DPY, 0, D_ALL, NULL, NULL},
 	{0x64E60, 0x50, F_DPY, 0, D_ALL, NULL, NULL},
 	{0x64Ec0, 0x50, F_DPY, 0, D_ALL, NULL, NULL},
 	{0x64F20, 0x50, F_DPY, 0, D_ALL, NULL, NULL},
@@ -738,10 +1698,17 @@ struct gvt_reg_info gvt_general_reg_info[] = {
 	{_GEN6_RC6p_THRESHOLD, 4, F_DOM0, 0, D_ALL, NULL, NULL},
 	{_GEN6_RC6pp_THRESHOLD, 4, F_DOM0, 0, D_ALL, NULL, NULL},
 	{_GEN6_PMINTRMSK, 4, F_DOM0, 0, D_ALL, NULL, NULL},
-	{_GEN6_GDRST, 4, F_DOM0, 0, D_ALL, NULL, gdrst_mmio_write},
+	{_HSW_PWR_WELL_BIOS, 4, F_DOM0, 0, D_ALL, NULL, power_well_ctl_write},
+	{_HSW_PWR_WELL_DRIVER, 4, F_DOM0, 0, D_ALL, NULL, power_well_ctl_write},
+	{_HSW_PWR_WELL_KVMR, 4, F_DOM0, 0, D_ALL, NULL, power_well_ctl_write},
+	{_HSW_PWR_WELL_DEBUG, 4, F_DOM0, 0, D_ALL, NULL, power_well_ctl_write},
+	{_HSW_PWR_WELL_CTL5, 4, F_DOM0, 0, D_ALL, NULL, power_well_ctl_write},
+	{_HSW_PWR_WELL_CTL6, 4, F_DOM0, 0, D_ALL, NULL, power_well_ctl_write},
 
+	{_GEN6_GDRST, 4, F_DOM0, 0, D_ALL, NULL, gdrst_mmio_write},
 	{0x100000, 0x80, F_VIRT, 0, D_ALL, fence_mmio_read, fence_mmio_write},
 	{VGT_PVINFO_PAGE, VGT_PVINFO_SIZE, F_VIRT, 0, D_ALL, pvinfo_read, pvinfo_write},
+	{_CPU_VGACNTRL, 4, F_DOM0, 0, D_ALL, NULL, vga_control_w},
 
 	/* TODO: MCHBAR, suppose read-only */
 	{MCHBAR_MIRROR_BASE_SNB, 0x40000, F_VIRT, 0, D_ALL, NULL, NULL},
@@ -792,6 +1759,9 @@ struct gvt_reg_info gvt_general_reg_info[] = {
 	{0xe6704, 4, F_VIRT, 0, D_ALL, NULL, NULL},
 	{0xe6800, 4, F_VIRT, 0, D_ALL, NULL, NULL},
 	{0xe6804, 4, F_VIRT, 0, D_ALL, NULL, NULL},
+	/* FIXME: now looks gmbus handler can't cover 4/5 ports */
+	{_PCH_GMBUS4, 4, F_DPY, 0, D_ALL, NULL, NULL},
+	{_PCH_GMBUS5, 4, F_DPY, 0, D_ALL, NULL, NULL},
 
 	{_REG_SUPER_QUEUE_CONFIG, 4, F_VIRT, 0, D_ALL, NULL, NULL},
 	{0xec008, 4, F_VIRT, 0, D_ALL, NULL, NULL},
diff --git a/drivers/gpu/drm/i915/gvt/instance.c b/drivers/gpu/drm/i915/gvt/instance.c
index 0bf62e4..3015fdf 100644
--- a/drivers/gpu/drm/i915/gvt/instance.c
+++ b/drivers/gpu/drm/i915/gvt/instance.c
@@ -162,6 +162,7 @@ static bool create_virtual_gm_state(struct vgt_device *vgt,
 
 static void destroy_virtual_device_state(struct vgt_device *vgt)
 {
+	gvt_clean_virtual_display_state(vgt);
 	gvt_clean_vgtt(vgt);
 	destroy_virtual_mmio_state(vgt);
 	destroy_virtual_gm_state(vgt);
@@ -179,6 +180,9 @@ static bool create_virtual_device_state(struct vgt_device *vgt,
 
 	init_virtual_cfg_space_state(vgt, info);
 
+	if (!gvt_init_virtual_display_state(vgt))
+		return false;
+
 	return true;
 }
 
diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c
index 23d40ce..d0cc1a6 100644
--- a/drivers/gpu/drm/i915/gvt/interrupt.c
+++ b/drivers/gpu/drm/i915/gvt/interrupt.c
@@ -598,12 +598,29 @@ static void gvt_init_events(
 	}
 }
 
+static enum hrtimer_restart gvt_dpy_timer_fn(struct hrtimer *data)
+{
+	struct gvt_emul_timer *dpy_timer;
+	struct gvt_irq_state *state;
+	struct pgt_device *pdev;
+
+	dpy_timer = container_of(data, struct gvt_emul_timer, timer);
+	state = container_of(dpy_timer, struct gvt_irq_state, dpy_timer);
+	pdev = gvt_irq_state_to_pdev(state);
+
+	gvt_raise_request(pdev, GVT_REQUEST_EMUL_DPY_EVENTS);
+
+	hrtimer_add_expires_ns(&dpy_timer->timer, dpy_timer->period);
+	return HRTIMER_RESTART;
+}
+
 /*
  * Do interrupt initialization for vGT driver
  */
 bool gvt_irq_init(struct pgt_device *pdev)
 {
 	struct gvt_irq_state *state = &pdev->irq_state;
+	struct gvt_emul_timer *dpy_timer;
 
 	gvt_dbg_core("init irq framework");
 
@@ -623,12 +640,19 @@ bool gvt_irq_init(struct pgt_device *pdev)
 
 	gvt_irq_map_init(state);
 
+	dpy_timer = &state->dpy_timer;
+	hrtimer_init(&dpy_timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+	dpy_timer->timer.function = gvt_dpy_timer_fn;
+	dpy_timer->period = GVT_DPY_EMUL_PERIOD;
+
 	return true;
 }
 
 void gvt_irq_exit(struct pgt_device *pdev)
 {
-	return;
+	struct gvt_irq_state *state = &pdev->irq_state;
+
+	hrtimer_cancel(&state->dpy_timer.timer);
 }
 
 void gvt_inject_flip_done(struct vgt_device *vgt, int pipe)
diff --git a/drivers/gpu/drm/i915/gvt/interrupt.h b/drivers/gpu/drm/i915/gvt/interrupt.h
index 3142ed6..ff125fc 100644
--- a/drivers/gpu/drm/i915/gvt/interrupt.h
+++ b/drivers/gpu/drm/i915/gvt/interrupt.h
@@ -165,6 +165,7 @@ enum gvt_irq_type {
 };
 
 #define GVT_IRQ_BITWIDTH	32
+#define GVT_DPY_EMUL_PERIOD	16000000	// 16 ms for now
 
 /* device specific interrupt bit definitions */
 struct gvt_irq_info {
@@ -199,6 +200,11 @@ struct gvt_irq_map {
 	u32 down_irq_bitmask;
 };
 
+struct gvt_emul_timer {
+	struct hrtimer timer;
+	u64 period;
+};
+
 /* structure containing device specific IRQ state */
 struct gvt_irq_state {
 	struct gvt_irq_ops *ops;
@@ -206,6 +212,7 @@ struct gvt_irq_state {
 	DECLARE_BITMAP(irq_info_bitmap, GVT_IRQ_INFO_MAX);
 	struct gvt_event_info	events[GVT_EVENT_MAX];
 	DECLARE_BITMAP(pending_events, GVT_EVENT_MAX);
+	struct gvt_emul_timer dpy_timer;
 	struct gvt_irq_map *irq_map;
 };
 
diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
index 1758092..1186da5 100644
--- a/drivers/gpu/drm/i915/gvt/reg.h
+++ b/drivers/gpu/drm/i915/gvt/reg.h
@@ -571,6 +571,9 @@ union _TRANS_CONFIG
 #define _PCH_GMBUS0			0xc5100
 #define _PCH_GMBUS1			0xc5104
 #define _PCH_GMBUS2			0xc5108
+#define _PCH_GMBUS3			0xc510c
+#define _PCH_GMBUS4			0xc5110
+#define _PCH_GMBUS5			0xc5120
 
 #define _GEN6_GDRST			0x941c
 #define _GEN6_GT_THREAD_STATUS_REG	0x13805c
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 23/29] drm/i915: gvt: Introduce GVT control interface
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (21 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 22/29] drm/i915: gvt: Full display virtualization Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 24/29] drm/i915: gvt: Full execlist status emulation Zhi Wang
                   ` (6 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

From: Yi Sun <yi.sun@intel.com>

This patch introduces the control interface for creating/destroying vGPUs.

Signed-off-by: Yi Sun <yi.sun@intel.com>
Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile  |   2 +-
 drivers/gpu/drm/i915/gvt/control.c | 181 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/gvt.c     |   4 +
 drivers/gpu/drm/i915/gvt/gvt.h     |   8 ++
 4 files changed, 194 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/control.c

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index c146c57..8874fe0 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,6 +1,6 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
 		trace_points.o interrupt.o gtt.o cfg_space.o opregion.o utility.o \
-		fb_decoder.o display.o edid.o
+		fb_decoder.o display.o edid.o control.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/control.c b/drivers/gpu/drm/i915/gvt/control.c
new file mode 100644
index 0000000..625d213
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/control.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+#define GVT_TYPE (';')
+#define GVT_BASE 0xA0
+
+#define GVT_CREATE_INSTANCE _IOW(GVT_TYPE, GVT_BASE + 0, struct gvt_instance_info)
+#define GVT_DESTROY_INSTANCE _IOW(GVT_TYPE, GVT_BASE + 1, s32)
+
+struct misc_device_client_info {
+	struct pgt_device *pdev;
+	struct vgt_device *vgt;
+	struct mutex lock;
+};
+
+static int misc_device_open(struct inode *inode, struct file *filp)
+{
+	struct miscdevice *dev = filp->private_data;
+	struct pgt_device *pdev = container_of(dev, struct pgt_device, control.misc_device);
+	struct misc_device_client_info *info = NULL;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		gvt_err("fail to allocate memory");
+		return -ENOMEM;
+	}
+
+	info->pdev = pdev;
+	mutex_init(&info->lock);
+
+	filp->private_data = info;
+
+	return 0;
+}
+
+static int misc_device_close(struct inode *inode, struct file *filp)
+{
+	struct misc_device_client_info *info = filp->private_data;
+
+	if (info->vgt)
+		gvt_destroy_instance(info->vgt);
+
+	kfree(info);
+	filp->private_data = NULL;
+	return 0;
+}
+
+static long misc_device_ioctl(struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	struct misc_device_client_info *info = filp->private_data;
+	struct gvt_instance_info param;
+	int r = 0;
+
+	if (copy_from_user(&param, (void *)arg, sizeof(param)))
+		return -EFAULT;
+
+	mutex_lock(&info->lock);
+	switch(cmd) {
+		case GVT_CREATE_INSTANCE:
+			if (info->vgt) {
+				gvt_err("instance has already been created");
+				r = -EEXIST;
+				goto out;
+			}
+
+			info->vgt = gvt_create_instance(info->pdev, &param);
+
+			if (!info->vgt) {
+				gvt_err("fail to create instance");
+				r = -ENOMEM;
+				goto out;
+			}
+			break;
+		case GVT_DESTROY_INSTANCE:
+			if (!info->vgt) {
+				r = -ENODEV;
+				goto out;
+			}
+			gvt_destroy_instance(info->vgt);
+			info->vgt = NULL;
+			break;
+		default:
+			r = -EINVAL;
+			goto out;
+	}
+out:
+	mutex_unlock(&info->lock);
+	return r;
+}
+
+static struct file_operations misc_device_fops =
+{
+	.open = misc_device_open,
+	.release = misc_device_close,
+	.unlocked_ioctl = misc_device_ioctl,
+	.compat_ioctl = misc_device_ioctl,
+};
+
+void clean_misc_device(struct pgt_device *pdev)
+{
+	struct miscdevice *dev = &pdev->control.misc_device;
+
+	if (!list_empty(&dev->list))
+		misc_deregister(dev);
+
+	if (dev->name) {
+		kfree(dev->name);
+		dev->name = NULL;
+	}
+}
+
+bool setup_misc_device(struct pgt_device *pdev)
+{
+	struct miscdevice *dev = &pdev->control.misc_device;
+	unsigned long len;
+	char name[32];
+
+	len = snprintf(name, 32, "dri/gvt%d", pdev->id);
+	dev->name = kzalloc(len + 1, GFP_KERNEL);
+	if (!dev->name) {
+		gvt_err("fail to allocate memory");
+		return false;
+	}
+
+	dev->name = name;
+	dev->minor = MISC_DYNAMIC_MINOR;
+	dev->fops = &misc_device_fops;
+
+	INIT_LIST_HEAD(&dev->list);
+
+	if (misc_register(dev) < 0) {
+		gvt_err("fail to register miscdevice");
+		goto err;
+	}
+
+	return true;
+err:
+	clean_misc_device(pdev);
+	return false;
+}
+
+bool gvt_setup_control_interface(struct pgt_device *pdev)
+{
+	bool r;
+
+	r = setup_misc_device(pdev);
+	if (!r) {
+		gvt_err("fail to setup misc device node\n");
+		return false;
+	}
+
+	return true;
+}
+
+void gvt_clean_control_interface(struct pgt_device *pdev)
+{
+	clean_misc_device(pdev);
+}
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index ea871cd..77fe5d39 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -283,6 +283,7 @@ static bool init_service_thread(struct pgt_device *pdev)
 static void clean_pgt_device(struct pgt_device *pdev)
 {
 	clean_service_thread(pdev);
+	gvt_clean_control_interface(pdev);
 	gvt_clean_gtt(pdev);
 	gvt_irq_exit(pdev);
 	gvt_clean_mmio_emulation_state(pdev);
@@ -315,6 +316,9 @@ static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *de
 	if (!gvt_init_gtt(pdev))
 		goto err;
 
+	if (!gvt_setup_control_interface(pdev))
+		goto err;
+
 	if (!init_service_thread(pdev))
 		goto err;
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index b44b5b5..1d5c15c 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -163,6 +163,10 @@ struct gvt_gm_allocator {
 	struct drm_mm high_gm;
 };
 
+struct gvt_device_control {
+	struct miscdevice misc_device;
+};
+
 struct pgt_device {
 	struct mutex lock;
 	int id;
@@ -214,6 +218,7 @@ struct pgt_device {
 	struct pgt_statistics stat;
 
 	struct gvt_gtt_info gtt;
+	struct gvt_device_control control;
 };
 
 /* request types to wake up main thread */
@@ -688,6 +693,9 @@ bool register_mmio_handler(struct pgt_device *pdev, unsigned int start, int byte
 bool gvt_update_display_events_emulation(struct pgt_device *pdev);
 void gvt_emulate_display_events(struct pgt_device *pdev);
 
+bool gvt_setup_control_interface(struct pgt_device *pdev);
+void gvt_clean_control_interface(struct pgt_device *pdev);
+
 #include "mpt.h"
 
 #endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 24/29] drm/i915: gvt: Full execlist status emulation
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (22 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 23/29] drm/i915: gvt: Introduce GVT control interface Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 25/29] drm/i915: gvt: vGPU execlist workload submission Zhi Wang
                   ` (5 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This patch introduces a full execlist status emulation framework.

Under virtulization environment, the execlist status are fully emulated
including virtual CSB emulation, virtual execlist emulation. The framework
will emulate the virtual CSB according to the guest workload running status.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile   |   2 +-
 drivers/gpu/drm/i915/gvt/debug.h    |   6 +-
 drivers/gpu/drm/i915/gvt/execlist.c | 348 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/execlist.h | 126 +++++++++++++
 drivers/gpu/drm/i915/gvt/gvt.h      |   2 +
 drivers/gpu/drm/i915/gvt/instance.c |   2 +
 6 files changed, 484 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/execlist.c
 create mode 100644 drivers/gpu/drm/i915/gvt/execlist.h

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index 8874fe0..bb3170b 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,6 +1,6 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
 		trace_points.o interrupt.o gtt.o cfg_space.o opregion.o utility.o \
-		fb_decoder.o display.o edid.o control.o
+		fb_decoder.o display.o edid.o control.o execlist.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/debug.h b/drivers/gpu/drm/i915/gvt/debug.h
index 807d9e8..88b7d48 100644
--- a/drivers/gpu/drm/i915/gvt/debug.h
+++ b/drivers/gpu/drm/i915/gvt/debug.h
@@ -73,7 +73,8 @@ enum {
 	GVT_DBG_IRQ = (1 << 2),
 	GVT_DBG_DPY = (1 << 3),
 	GVT_DBG_RENDER = (1 << 4),
-	GVT_DBG_EDID = (1 << 5)
+	GVT_DBG_EDID = (1 << 5),
+	GVT_DBG_EL = (1 << 6),
 };
 
 #define gvt_dbg_core(fmt, args...) \
@@ -85,4 +86,7 @@ enum {
 #define gvt_dbg_irq(fmt, args...) \
 	gvt_dbg(GVT_DBG_IRQ, fmt, ##args)
 
+#define gvt_dbg_el(fmt, args...) \
+	gvt_dbg(GVT_DBG_EL, fmt, ##args)
+
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/execlist.c b/drivers/gpu/drm/i915/gvt/execlist.c
new file mode 100644
index 0000000..4d49d00
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/execlist.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+#define execlist_ring_mmio(ring_id, offset) \
+	(gvt_ring_id_to_render_mmio_base(ring_id) + (offset))
+
+#define valid_context(ctx) ((ctx)->valid)
+#define same_context(a, b) (((a)->context_id == (b)->context_id) && \
+		((a)->lrca == (b)->lrca))
+
+static int context_switch_events[] = {
+	[RCS] = RCS_AS_CONTEXT_SWITCH,
+	[BCS] = BCS_AS_CONTEXT_SWITCH,
+	[VCS] = VCS_AS_CONTEXT_SWITCH,
+	[VCS2] = VCS2_AS_CONTEXT_SWITCH,
+	[VECS] = VECS_AS_CONTEXT_SWITCH,
+};
+
+static int ring_id_to_context_switch_event(int ring_id)
+{
+	ASSERT(ring_id >= 0 && ring_id < ARRAY_SIZE(context_switch_events));
+	return context_switch_events[ring_id];
+}
+
+static void switch_virtual_execlist_slot(struct gvt_virtual_execlist_info *info)
+{
+	gvt_dbg_el("[before] running slot %d/context %x pending slot %d",
+		info->running_execlist ? info->running_execlist->index : -1,
+		info->running_context ? info->running_context->context_id : 0,
+		info->pending_execlist ? info->pending_execlist->index : -1);
+
+	info->running_execlist = info->pending_execlist;
+	info->pending_execlist = NULL;
+	info->running_context = info->running_context ?
+		&info->running_execlist->ctx[0] : NULL;
+
+	gvt_dbg_el("[after] running slot %d/context %x pending slot %d",
+		info->running_execlist ? info->running_execlist->index : -1,
+		info->running_context ? info->running_context->context_id : 0,
+		info->pending_execlist ? info->pending_execlist->index : -1);
+}
+
+static void emulate_execlist_status(struct gvt_virtual_execlist_info *info)
+{
+	struct gvt_execlist_state *running = info->running_execlist;
+	struct gvt_execlist_state *pending = info->pending_execlist;
+	struct execlist_ctx_descriptor_format *desc = info->running_context;
+	struct vgt_device *vgt = info->vgt;
+
+	struct execlist_status_format status;
+
+	u32 status_reg = execlist_ring_mmio(info->ring_id, _EL_OFFSET_STATUS);
+
+	status.ldw = __vreg(vgt, status_reg);
+	status.udw = __vreg(vgt, status_reg + 4);
+
+	if (running) {
+		status.current_execlist_pointer = !!running->index;
+		status.execlist_write_pointer = !!!running->index;
+		status.execlist_0_active = status.execlist_0_valid =
+			!!!(running->index);
+		status.execlist_1_active = status.execlist_1_valid =
+			!!(running->index);
+	} else {
+		status.context_id = 0;
+		status.execlist_0_active = status.execlist_0_valid = 0;
+		status.execlist_1_active = status.execlist_1_valid = 0;
+	}
+
+	status.context_id = desc ? desc->context_id : 0;
+	status.execlist_queue_full = !!(pending);
+
+	__vreg(vgt, status_reg) = status.ldw;
+	__vreg(vgt, status_reg + 4) = status.udw;
+
+	gvt_dbg_el("[vgt %d] status reg offset %x ldw %x udw %x",
+		vgt->id, status_reg, status.ldw, status.udw);
+}
+
+static void emulate_csb_update(struct gvt_virtual_execlist_info *info,
+		struct execlist_context_status_format *status)
+{
+	struct vgt_device *vgt = info->vgt;
+	struct execlist_context_status_pointer_format ctx_status_ptr;
+	u32 write_pointer;
+	u32 ctx_status_ptr_reg, ctx_status_buf_reg, offset;
+
+	ctx_status_ptr_reg = execlist_ring_mmio(info->ring_id,
+			_EL_OFFSET_STATUS_PTR);
+	ctx_status_buf_reg = execlist_ring_mmio(info->ring_id,
+			_EL_OFFSET_STATUS_BUF);
+
+	ctx_status_ptr.dw = __vreg(vgt, ctx_status_ptr_reg);
+
+	write_pointer = ctx_status_ptr.write_ptr;
+
+	if (write_pointer == 0x7)
+		write_pointer = 0;
+	else {
+		++write_pointer;
+		write_pointer %= 0x6;
+	}
+
+	offset = ctx_status_buf_reg + write_pointer * 8;
+
+	__vreg(vgt, offset) = status->ldw;
+	__vreg(vgt, offset + 4) = status->udw;
+
+	ctx_status_ptr.write_ptr = write_pointer;
+	__vreg(vgt, ctx_status_ptr_reg) = ctx_status_ptr.dw;
+
+	gvt_dbg_el("[vgt %d] w pointer %u reg %x csb l %x csb h %x",
+		vgt->id, write_pointer, offset, status->ldw, status->udw);
+
+	gvt_trigger_virtual_event(vgt, ring_id_to_context_switch_event(info->ring_id));
+}
+
+static bool emulate_execlist_ctx_schedule_out(struct gvt_virtual_execlist_info *info,
+		struct execlist_ctx_descriptor_format *ctx)
+{
+	struct gvt_execlist_state *running = info->running_execlist;
+	struct gvt_execlist_state *pending = info->pending_execlist;
+	struct execlist_ctx_descriptor_format *ctx0 = &running->ctx[0];
+	struct execlist_ctx_descriptor_format *ctx1 = &running->ctx[1];
+	struct execlist_context_status_format status;
+
+	memset(&status, 0, sizeof(status));
+
+	gvt_dbg_el("schedule out context id %x", ctx->context_id);
+
+	if (!same_context(ctx, info->running_context)) {
+		gvt_err("schedule out context is not running context,"
+				"ctx id %x running ctx id %x",
+				ctx->context_id,
+				info->running_context->context_id);
+		return false;
+	}
+
+	/* ctx1 is valid, ctx0/ctx is scheduled-out -> element switch */
+	if (valid_context(ctx1) && same_context(ctx0, ctx)) {
+		gvt_dbg_el("ctx 1 valid, ctx/ctx 0 is scheduled-out");
+
+		info->running_context = ctx1;
+
+		emulate_execlist_status(info);
+
+		status.context_complete = status.element_switch = 1;
+		status.context_id = ctx->context_id;
+
+		emulate_csb_update(info, &status);
+		/*
+		 * ctx1 is not valid, ctx == ctx0
+		 * ctx1 is valid, ctx1 == ctx
+		 * 	--> last element is finished
+		 * emulate:
+		 * 	active-to-idle if there is *no* pending execlist
+		 * 	context-complete if there *is* pending execlist
+		 */
+	} else if ((!valid_context(ctx1) && same_context(ctx0, ctx))
+			|| (valid_context(ctx1) && same_context(ctx1, ctx))) {
+		gvt_dbg_el("need to switch virtual execlist slot");
+
+		switch_virtual_execlist_slot(info);
+
+		emulate_execlist_status(info);
+
+		if (!pending)
+			status.context_complete = status.active_to_idle = 1;
+		else
+			status.context_complete = 1;
+
+		status.context_id = ctx->context_id;
+
+		emulate_csb_update(info, &status);
+	} else {
+		ASSERT(0);
+		return false;
+	}
+
+	return true;
+}
+
+static struct gvt_execlist_state *get_next_execlist_state(
+		struct gvt_virtual_execlist_info *info)
+{
+	u32 status_reg = execlist_ring_mmio(info->ring_id, _EL_OFFSET_STATUS);
+	struct vgt_device *vgt = info->vgt;
+	struct execlist_status_format status;
+
+	status.ldw = __vreg(vgt, status_reg);
+	status.udw = __vreg(vgt, status_reg + 4);
+
+	if (status.execlist_queue_full) {
+		gvt_err("virtual execlist slots are full");
+		return NULL;
+	}
+
+	return &info->execlist[status.execlist_write_pointer];
+}
+
+static bool emulate_execlist_schedule_in(struct gvt_virtual_execlist_info *info,
+		struct execlist_ctx_descriptor_format ctx[2])
+{
+	struct gvt_execlist_state *running = info->running_execlist;
+	struct gvt_execlist_state *execlist = get_next_execlist_state(info);
+
+	struct execlist_ctx_descriptor_format *ctx0, *ctx1;
+	struct execlist_context_status_format status;
+
+	gvt_dbg_el("emulate schedule-in");
+
+	if (!execlist) {
+		gvt_err("no avaiable execlist slot");
+		return false;
+	}
+
+	memset(&status, 0, sizeof(status));
+	memset(execlist->ctx, 0, sizeof(execlist->ctx));
+
+	execlist->ctx[0] = ctx[0];
+	execlist->ctx[1] = ctx[1];
+
+	gvt_dbg_el("alloc slot index %d ctx 0 %x ctx 1 %x",
+			execlist->index, ctx[0].context_id,
+			ctx[1].context_id);
+
+	/*
+	 * no running execlist, make this write bundle as running execlist
+	 * -> idle-to-active
+	 */
+	if (!running) {
+		gvt_dbg_el("no current running execlist");
+
+		info->running_execlist = execlist;
+		info->pending_execlist = NULL;
+		info->running_context = &execlist->ctx[0];
+
+		gvt_dbg_el("running slot index %d running context %x",
+				info->running_execlist->index,
+				info->running_context->context_id);
+
+		emulate_execlist_status(info);
+
+		status.idle_to_active = 1;
+		status.context_id = 0;
+
+		emulate_csb_update(info, &status);
+		return true;
+	}
+
+	ctx0 = &running->ctx[0];
+	ctx1 = &running->ctx[1];
+
+	gvt_dbg_el("current running execlist index %d ctx 0 %x ctx 1 %x",
+		running->index, ctx0->context_id, ctx1->context_id);
+
+	/*
+	 * already has an running execlist
+	 *	a. running ctx1 is valid,
+	 *	   ctx0 is finished, and running ctx1 == new execlist ctx[0]
+	 *	b. running ctx1 is not valid,
+	 *	   ctx0 == new execlist ctx[0]
+	 * ----> lite-restore + preempted
+	 */
+	if ((valid_context(ctx1) && same_context(ctx1, &execlist->ctx[0]) &&
+		(!same_context(ctx0, info->running_context))) || /* condition a */
+			(!valid_context(ctx1) &&
+			same_context(ctx0, &execlist->ctx[0]))) { /* condition b */
+		gvt_dbg_el("need to switch virtual execlist slot");
+
+		info->pending_execlist = execlist;
+		switch_virtual_execlist_slot(info);
+
+		emulate_execlist_status(info);
+
+		status.lite_restore = status.preempted = 1;
+		status.context_id = ctx0->context_id;
+
+		emulate_csb_update(info, &status);
+	} else {
+		gvt_dbg_el("emulate as pending slot");
+		/*
+		 * otherwise
+		 * --> emulate pending execlist exist + but no preemption case
+		 */
+		info->pending_execlist = execlist;
+		emulate_execlist_status(info);
+	}
+
+	return true;
+}
+
+static bool init_virtual_execlist_info(struct vgt_device *vgt,
+		int ring_id, struct gvt_virtual_execlist_info *info)
+{
+	struct execlist_context_status_pointer_format ctx_status_ptr;
+	u32 ctx_status_ptr_reg;
+
+	memset(info, 0, sizeof(*info));
+
+	info->vgt = vgt;
+	info->ring_id = ring_id;
+	info->execlist[0].index = 0;
+	info->execlist[1].index = 1;
+
+	ctx_status_ptr_reg = execlist_ring_mmio(info->ring_id,
+			_EL_OFFSET_STATUS_PTR);
+
+	ctx_status_ptr.dw = __vreg(vgt, ctx_status_ptr_reg);
+	ctx_status_ptr.read_ptr = ctx_status_ptr.write_ptr = 0x7;
+	__vreg(vgt, ctx_status_ptr_reg) = ctx_status_ptr.dw;
+
+	return true;
+}
+
+bool gvt_init_virtual_execlist_info(struct vgt_device *vgt)
+{
+	int i;
+
+	/* each ring has a virtual execlist engine */
+	for (i = 0; i < I915_NUM_RINGS; i++)
+		init_virtual_execlist_info(vgt,
+				i, &vgt->virtual_execlist_info[i]);
+
+	return true;
+}
diff --git a/drivers/gpu/drm/i915/gvt/execlist.h b/drivers/gpu/drm/i915/gvt/execlist.h
new file mode 100644
index 0000000..bcd5a9e
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/execlist.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_EXECLIST_H_
+#define _GVT_EXECLIST_H_
+
+struct execlist_ctx_descriptor_format {
+	union {
+		u32 udw;
+		u32 context_id;
+	};
+	union {
+		u32 ldw;
+		struct {
+			u32 valid                  : 1;
+			u32 force_pd_restore       : 1;
+			u32 force_restore          : 1;
+			u32 addressing_mode        : 2;
+			u32 llc_coherency          : 1;
+			u32 fault_handling         : 2;
+			u32 privilege_access       : 1;
+			u32 reserved               : 3;
+			u32 lrca                   : 20;
+		};
+	};
+};
+
+struct execlist_status_format {
+        union {
+                u32 ldw;
+                struct {
+                        u32 current_execlist_pointer       :1;
+                        u32 execlist_write_pointer         :1;
+                        u32 execlist_queue_full            :1;
+                        u32 execlist_1_valid               :1;
+                        u32 execlist_0_valid               :1;
+                        u32 last_ctx_switch_reason         :9;
+                        u32 current_active_elm_status      :2;
+                        u32 arbitration_enable             :1;
+                        u32 execlist_1_active              :1;
+                        u32 execlist_0_active              :1;
+                        u32 reserved                       :13;
+                };
+        };
+        union {
+                u32 udw;
+                u32 context_id;
+        };
+};
+
+struct execlist_context_status_pointer_format {
+	union {
+		u32 dw;
+		struct {
+			u32 write_ptr              :3;
+			u32 reserved               :5;
+			u32 read_ptr               :3;
+			u32 reserved2              :5;
+			u32 mask                   :16;
+		};
+	};
+};
+
+struct execlist_context_status_format {
+	union {
+		u32 ldw;
+		struct {
+			u32 idle_to_active         :1;
+			u32 preempted              :1;
+			u32 element_switch         :1;
+			u32 active_to_idle         :1;
+			u32 context_complete       :1;
+			u32 wait_on_sync_flip      :1;
+			u32 wait_on_vblank         :1;
+			u32 wait_on_semaphore      :1;
+			u32 wait_on_scanline       :1;
+			u32 reserved               :2;
+			u32 semaphore_wait_mode    :1;
+			u32 display_plane          :3;
+			u32 lite_restore           :1;
+			u32 reserved_2             :16;
+		};
+	};
+	union {
+		u32 udw;
+		u32 context_id;
+	};
+};
+
+struct gvt_execlist_state {
+	struct execlist_ctx_descriptor_format ctx[2];
+	u32 index;
+};
+
+struct gvt_virtual_execlist_info {
+	struct gvt_execlist_state execlist[2];
+	struct gvt_execlist_state *running_execlist;
+	struct gvt_execlist_state *pending_execlist;
+	struct execlist_ctx_descriptor_format *running_context;
+	int ring_id;
+	struct vgt_device *vgt;
+};
+
+bool gvt_init_virtual_execlist_info(struct vgt_device *vgt);
+
+#endif /*_GVT_EXECLIST_H_*/
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 1d5c15c..f40788b 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -42,6 +42,7 @@
 #include "fb_decoder.h"
 #include "edid.h"
 #include "display.h"
+#include "execlist.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -149,6 +150,7 @@ struct vgt_device {
 	struct pgt_device *pdev;
 	atomic_t active;
 	struct gvt_virtual_device_state state;
+	struct gvt_virtual_execlist_info virtual_execlist_info[I915_NUM_RINGS];
 	struct gvt_statistics stat;
 	struct gvt_vgtt_info gtt;
 	void *hypervisor_data;
diff --git a/drivers/gpu/drm/i915/gvt/instance.c b/drivers/gpu/drm/i915/gvt/instance.c
index 3015fdf..959c8ee 100644
--- a/drivers/gpu/drm/i915/gvt/instance.c
+++ b/drivers/gpu/drm/i915/gvt/instance.c
@@ -183,6 +183,8 @@ static bool create_virtual_device_state(struct vgt_device *vgt,
 	if (!gvt_init_virtual_display_state(vgt))
 		return false;
 
+	gvt_init_virtual_execlist_info(vgt);
+
 	return true;
 }
 
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 25/29] drm/i915: gvt: vGPU execlist workload submission
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (23 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 24/29] drm/i915: gvt: Full execlist status emulation Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 26/29] drm/i915: gvt: workload scheduler Zhi Wang
                   ` (4 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This patch introduces the vGPU execlist workload submission logics.

Under virtualization environment, guest will submit workload through virtual
execlist submit port. The submitted workload load will be wrapped into
an gvt workload which will be picked by GVT workload scheduler and executed
on host i915 later.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/execlist.c  | 264 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/execlist.h  |  53 +++++++
 drivers/gpu/drm/i915/gvt/gvt.h       |   4 +
 drivers/gpu/drm/i915/gvt/handlers.c  |  30 +++-
 drivers/gpu/drm/i915/gvt/scheduler.h |  59 ++++++++
 5 files changed, 405 insertions(+), 5 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/scheduler.h

diff --git a/drivers/gpu/drm/i915/gvt/execlist.c b/drivers/gpu/drm/i915/gvt/execlist.c
index 4d49d00..8d9dd1e 100644
--- a/drivers/gpu/drm/i915/gvt/execlist.c
+++ b/drivers/gpu/drm/i915/gvt/execlist.c
@@ -312,6 +312,266 @@ static bool emulate_execlist_schedule_in(struct gvt_virtual_execlist_info *info,
 	return true;
 }
 
+static bool execlist_workload_complete(struct gvt_workload *workload)
+{
+	struct vgt_device *vgt = workload->vgt;
+	struct gvt_virtual_execlist_info *info =
+		&vgt->virtual_execlist_info[workload->ring_id];
+	struct gvt_workload *next_workload;
+	struct list_head *next = workload_q_head(vgt, workload->ring_id);
+	bool lite_restore = false;
+
+	gvt_dbg_el("complete workload %p status %d", workload, workload->status);
+
+	if (workload->status)
+		goto out;
+
+	if (!list_empty(workload_q_head(vgt, workload->ring_id))) {
+		struct execlist_ctx_descriptor_format *this_desc, *next_desc;
+
+		next_workload = container_of(next, struct gvt_workload, list);
+		this_desc = &workload->ctx_desc;
+		next_desc = &next_workload->ctx_desc;
+
+		lite_restore = same_context(this_desc, next_desc);
+	}
+
+	if (lite_restore) {
+		gvt_dbg_el("next workload context is same as current - no schedule-out");
+		goto out;
+	}
+
+	if (!emulate_execlist_ctx_schedule_out(info, &workload->ctx_desc)) {
+		kfree(workload);
+		return false;
+	}
+
+out:
+	gvt_destroy_mm(workload->shadow_mm);
+	kfree(workload);
+	return true;
+}
+
+void gvt_get_context_pdp_root_pointer(struct vgt_device *vgt,
+		struct execlist_ring_context *ring_context,
+		u32 pdp[8])
+{
+	struct gvt_execlist_mmio_pair *pdp_pair = &ring_context->pdp3_UDW;
+	u32 v;
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		hypervisor_read_va(vgt, &pdp_pair[i].val, &v, 4, 1);
+		pdp[7 - i] = v;
+	}
+}
+
+void gvt_set_context_pdp_root_pointer(struct vgt_device *vgt,
+		struct execlist_ring_context *ring_context,
+		u32 pdp[8])
+{
+	struct gvt_execlist_mmio_pair *pdp_pair = &ring_context->pdp3_UDW;
+	int i;
+
+	for (i = 0; i < 8; i++)
+		pdp_pair[i].val = pdp[7 - i];
+}
+
+static struct execlist_ring_context *get_ring_context(struct vgt_device *vgt,
+		u32 lrca)
+{
+	struct execlist_ring_context *context;
+	u32 gma = (lrca + 1) << GTT_PAGE_SHIFT;
+
+	context = (struct execlist_ring_context *)
+		gvt_gma_to_va(vgt->gtt.ggtt_mm, gma);
+
+	return context;
+}
+
+static bool prepare_workload(struct gvt_workload *workload)
+{
+	struct execlist_ctx_descriptor_format *desc = &workload->ctx_desc;
+	struct gvt_mm *mm;
+	gtt_type_t root_entry_type;
+	int page_table_level;
+	u32 pdp[8];
+
+	if (desc->addressing_mode == 1) { /* legacy 32-bit */
+		page_table_level = 3;
+		root_entry_type = GTT_TYPE_PPGTT_ROOT_L3_ENTRY;
+	} else if (desc->addressing_mode == 3) { /* legacy 64 bit */
+		page_table_level = 4;
+		root_entry_type = GTT_TYPE_PPGTT_ROOT_L4_ENTRY;
+	} else {
+		gvt_err("Advanced Context mode(SVM) is not supported!\n");
+		return false;
+	}
+
+	gvt_get_context_pdp_root_pointer(workload->vgt, workload->ring_context, pdp);
+
+	mm = gvt_create_mm(workload->vgt, GVT_MM_PPGTT, root_entry_type,
+			pdp, page_table_level, 0);
+	if (!mm) {
+		gvt_err("fail to create mm object.\n");
+		return false;
+	}
+
+	workload->shadow_mm = mm;
+
+	return true;
+}
+
+bool submit_context(struct vgt_device *vgt, int ring_id,
+		struct execlist_ctx_descriptor_format *desc)
+{
+	struct list_head *q = workload_q_head(vgt, ring_id);
+	struct gvt_workload *last_workload = list_empty(q) ? NULL :
+			container_of(q->prev, struct gvt_workload, list);
+	struct gvt_workload *workload = NULL;
+
+	struct execlist_ring_context *ring_context = get_ring_context(
+			vgt, desc->lrca);
+
+	u32 head, tail, start, ctl;
+
+	if (!ring_context) {
+		gvt_err("invalid guest context LRCA: %x", desc->lrca);
+		return false;
+	}
+
+	hypervisor_read_va(vgt, &ring_context->ring_header.val,
+			&head, 4, 1);
+
+	hypervisor_read_va(vgt, &ring_context->ring_tail.val,
+			&tail, 4, 1);
+
+	head &= RB_HEAD_OFF_MASK;
+	tail &= RB_TAIL_OFF_MASK;
+
+	if (last_workload && same_context(&last_workload->ctx_desc, desc)) {
+		gvt_dbg_el("ring id %d same workload as last workload", ring_id);
+		if (last_workload->dispatched) {
+			gvt_dbg_el("ring id %d last workload has been dispatched",
+					ring_id);
+			gvt_dbg_el("ctx head %x real head %lx",
+					head, last_workload->rb_tail);
+			/*
+			 * cannot use guest context head pointer here,
+			 * as it might not be updated at this time
+			 */
+			head = last_workload->rb_tail;
+		} else {
+			gvt_dbg_el("ring id %d merged into last workload", ring_id);
+			/*
+			 * if last workload hasn't been dispatched (scanned + shadowed),
+			 * and the context for current submission is just the same as last
+			 * workload context, then we can merge this submission into
+			 * last workload.
+			 */
+			last_workload->rb_tail = tail;
+			return true;
+		}
+	}
+
+	gvt_dbg_el("ring id %d begin a new workload", ring_id);
+
+	workload = kzalloc(sizeof(*workload), GFP_KERNEL);
+	if (!workload) {
+		gvt_err("fail to allocate memory for workload");
+		return false;
+	}
+
+	/* record some ring buffer register values for scan and shadow */
+	hypervisor_read_va(vgt, &ring_context->rb_start.val,
+			&start, 4, 1);
+	hypervisor_read_va(vgt, &ring_context->rb_ctrl.val,
+			&ctl, 4, 1);
+
+	INIT_LIST_HEAD(&workload->list);
+
+	init_waitqueue_head(&workload->shadow_ctx_status_wq);
+	atomic_set(&workload->shadow_ctx_active, 0);
+
+	workload->vgt = vgt;
+	workload->ring_id = ring_id;
+	workload->ctx_desc = *desc;
+	workload->ring_context = ring_context;
+	workload->rb_head = head;
+	workload->rb_tail = tail;
+	workload->rb_start = start;
+	workload->rb_ctl = ctl;
+	workload->complete = execlist_workload_complete;
+	workload->status = -EINPROGRESS;
+
+	gvt_dbg_el("workload %p ring id %d head %x tail %x start %x ctl %x",
+			workload, ring_id, head, tail, start, ctl);
+
+	if (!prepare_workload(workload)) {
+		kfree(workload);
+		return false;
+	}
+
+	queue_workload(workload);
+
+	return true;
+}
+
+bool gvt_execlist_elsp_submit(struct vgt_device *vgt, int ring_id)
+{
+	struct gvt_virtual_execlist_info *info =
+		&vgt->virtual_execlist_info[ring_id];
+	struct execlist_ctx_descriptor_format *desc[2], valid_desc[2];
+	unsigned long valid_desc_bitmap = 0;
+	int i;
+
+	memset(valid_desc, 0, sizeof(valid_desc));
+
+	desc[0] = (struct execlist_ctx_descriptor_format *)&info->bundle.data[2];
+	desc[1] = (struct execlist_ctx_descriptor_format *)&info->bundle.data[0];
+
+	for (i = 0; i < 2; i++) {
+		if (!desc[i]->valid)
+			continue;
+
+		if (!desc[i]->privilege_access) {
+			gvt_err("[vgt %d] unexpected GGTT elsp submission", vgt->id);
+			return false;
+		}
+
+		/* TODO: add another guest context checks here. */
+		set_bit(i, &valid_desc_bitmap);
+		valid_desc[i] = *desc[i];
+	}
+
+	if (!valid_desc_bitmap) {
+		gvt_err("[vgt %d] no valid desc in a elsp submission",
+				vgt->id);
+		return false;
+	}
+
+	if (!test_bit(0, (void *)&valid_desc_bitmap) &&
+			test_bit(1, (void *)&valid_desc_bitmap)) {
+		gvt_err("[vgt %d] weird elsp submission, desc 0 is not valid",
+				vgt->id);
+		return false;
+	}
+
+	if (!emulate_execlist_schedule_in(info, valid_desc)) {
+		gvt_err("[vgt %d] fail to emulate execlist schedule-in", vgt->id);
+		return false;
+	}
+
+	/* submit workload */
+	for_each_set_bit(i, (void *)&valid_desc_bitmap, 2) {
+		if (!submit_context(vgt, ring_id, &valid_desc[i])) {
+			gvt_err("[vgt %d] fail to schedule workload", vgt->id);
+			return false;
+		}
+	}
+	return true;
+}
+
 static bool init_virtual_execlist_info(struct vgt_device *vgt,
 		int ring_id, struct gvt_virtual_execlist_info *info)
 {
@@ -325,6 +585,8 @@ static bool init_virtual_execlist_info(struct vgt_device *vgt,
 	info->execlist[0].index = 0;
 	info->execlist[1].index = 1;
 
+	INIT_LIST_HEAD(&info->workload_q_head);
+
 	ctx_status_ptr_reg = execlist_ring_mmio(info->ring_id,
 			_EL_OFFSET_STATUS_PTR);
 
@@ -339,6 +601,8 @@ bool gvt_init_virtual_execlist_info(struct vgt_device *vgt)
 {
 	int i;
 
+	atomic_set(&vgt->running_workload_num, 0);
+
 	/* each ring has a virtual execlist engine */
 	for (i = 0; i < I915_NUM_RINGS; i++)
 		init_virtual_execlist_info(vgt,
diff --git a/drivers/gpu/drm/i915/gvt/execlist.h b/drivers/gpu/drm/i915/gvt/execlist.h
index bcd5a9e..1b7b4e6 100644
--- a/drivers/gpu/drm/i915/gvt/execlist.h
+++ b/drivers/gpu/drm/i915/gvt/execlist.h
@@ -107,20 +107,73 @@ struct execlist_context_status_format {
 	};
 };
 
+struct gvt_execlist_mmio_pair {
+	u32 addr;
+	u32 val;
+};
+
+/* The first 52 dwords in register state context */
+struct execlist_ring_context {
+	u32 nop1;
+	u32 lri_cmd_1;
+	struct gvt_execlist_mmio_pair ctx_ctrl;
+	struct gvt_execlist_mmio_pair ring_header;
+	struct gvt_execlist_mmio_pair ring_tail;
+	struct gvt_execlist_mmio_pair rb_start;
+	struct gvt_execlist_mmio_pair rb_ctrl;
+	struct gvt_execlist_mmio_pair bb_cur_head_UDW;
+	struct gvt_execlist_mmio_pair bb_cur_head_LDW;
+	struct gvt_execlist_mmio_pair bb_state;
+	struct gvt_execlist_mmio_pair second_bb_addr_UDW;
+	struct gvt_execlist_mmio_pair second_bb_addr_LDW;
+	struct gvt_execlist_mmio_pair second_bb_state;
+	struct gvt_execlist_mmio_pair bb_per_ctx_ptr;
+	struct gvt_execlist_mmio_pair rcs_indirect_ctx;
+	struct gvt_execlist_mmio_pair rcs_indirect_ctx_offset;
+	u32 nop2;
+	u32 nop3;
+	u32 nop4;
+	u32 lri_cmd_2;
+	struct gvt_execlist_mmio_pair ctx_timestamp;
+	struct gvt_execlist_mmio_pair pdp3_UDW;
+	struct gvt_execlist_mmio_pair pdp3_LDW;
+	struct gvt_execlist_mmio_pair pdp2_UDW;
+	struct gvt_execlist_mmio_pair pdp2_LDW;
+	struct gvt_execlist_mmio_pair pdp1_UDW;
+	struct gvt_execlist_mmio_pair pdp1_LDW;
+	struct gvt_execlist_mmio_pair pdp0_UDW;
+	struct gvt_execlist_mmio_pair pdp0_LDW;
+};
+
 struct gvt_execlist_state {
 	struct execlist_ctx_descriptor_format ctx[2];
 	u32 index;
 };
 
+struct gvt_execlist_write_bundle {
+	u32 data[4];
+	u32 index;
+};
+
 struct gvt_virtual_execlist_info {
 	struct gvt_execlist_state execlist[2];
 	struct gvt_execlist_state *running_execlist;
 	struct gvt_execlist_state *pending_execlist;
 	struct execlist_ctx_descriptor_format *running_context;
+	struct gvt_execlist_write_bundle bundle;
 	int ring_id;
 	struct vgt_device *vgt;
+	struct list_head workload_q_head;
 };
 
 bool gvt_init_virtual_execlist_info(struct vgt_device *vgt);
 
+void gvt_get_context_pdp_root_pointer(struct vgt_device *vgt,
+		struct execlist_ring_context *ring_context,
+		u32 pdp[8]);
+
+void gvt_set_context_pdp_root_pointer(struct vgt_device *vgt,
+		struct execlist_ring_context *ring_context,
+		u32 pdp[8]);
+
 #endif /*_GVT_EXECLIST_H_*/
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index f40788b..02e5a6e 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -43,6 +43,7 @@
 #include "edid.h"
 #include "display.h"
 #include "execlist.h"
+#include "scheduler.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -151,6 +152,7 @@ struct vgt_device {
 	atomic_t active;
 	struct gvt_virtual_device_state state;
 	struct gvt_virtual_execlist_info virtual_execlist_info[I915_NUM_RINGS];
+	atomic_t running_workload_num;
 	struct gvt_statistics stat;
 	struct gvt_vgtt_info gtt;
 	void *hypervisor_data;
@@ -698,6 +700,8 @@ void gvt_emulate_display_events(struct pgt_device *pdev);
 bool gvt_setup_control_interface(struct pgt_device *pdev);
 void gvt_clean_control_interface(struct pgt_device *pdev);
 
+bool gvt_execlist_elsp_submit(struct vgt_device *vgt, int ring_id);
+
 #include "mpt.h"
 
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index 638a295..356cfc4 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -1100,6 +1100,26 @@ bool fpga_dbg_write(struct vgt_device *vgt, unsigned int reg,
         return gvt_default_mmio_write(vgt, reg, &v, bytes);
 }
 
+static bool elsp_write(struct vgt_device *vgt, unsigned int offset,
+		void *p_data, unsigned int bytes)
+{
+	int ring_id = gvt_render_mmio_to_ring_id(offset);
+	struct gvt_virtual_execlist_info *info =
+			&vgt->virtual_execlist_info[ring_id];
+	u32 data = *(u32 *)p_data;
+	bool rc = true;
+
+	info->bundle.data[info->bundle.index] = data;
+
+	if (info->bundle.index == 3)
+		rc = gvt_execlist_elsp_submit(vgt, ring_id);
+
+	++info->bundle.index;
+	info->bundle.index &= 0x3;
+
+	return rc;
+}
+
 struct gvt_reg_info gvt_general_reg_info[] = {
 	/* Interrupt registers - GT */
 	{_RING_IMR(RENDER_RING_BASE), 4, F_RDR, 0, D_ALL, NULL, gvt_reg_imr_handler},
@@ -1912,15 +1932,15 @@ struct gvt_reg_info gvt_broadwell_reg_info[] = {
 	{_REG_VCS2_TIMESTAMP, 8, F_PT, 0, D_BDW_PLUS, NULL, NULL},
 
 	{_REG_RCS_EXECLIST_SUBMITPORT, 4, F_VIRT, 0, D_BDW_PLUS,
-		mmio_not_allow_read, NULL},
+		mmio_not_allow_read, elsp_write},
 	{_REG_VCS_EXECLIST_SUBMITPORT, 4, F_VIRT, 0, D_BDW_PLUS,
-		mmio_not_allow_read, NULL},
+		mmio_not_allow_read, elsp_write},
 	{_REG_VECS_EXECLIST_SUBMITPORT, 4, F_VIRT, 0, D_BDW_PLUS,
-		mmio_not_allow_read, NULL},
+		mmio_not_allow_read, elsp_write},
 	{_REG_VCS2_EXECLIST_SUBMITPORT, 4, F_VIRT, 0, D_BDW_PLUS,
-		mmio_not_allow_read, NULL},
+		mmio_not_allow_read, elsp_write},
 	{_REG_BCS_EXECLIST_SUBMITPORT, 4, F_VIRT, 0, D_BDW_PLUS,
-		mmio_not_allow_read, NULL},
+		mmio_not_allow_read, elsp_write},
 
 	{_REG_RCS_EXECLIST_STATUS, 8, F_RDR, 0, D_BDW_PLUS, NULL,
 		mmio_not_allow_write},
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h
new file mode 100644
index 0000000..dd24fda
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/scheduler.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef _GVT_SCHEDULER_H_
+#define _GVT_SCHEDULER_H_
+
+struct gvt_workload {
+	struct vgt_device *vgt;
+	int ring_id;
+
+	struct drm_i915_gem_request *req;
+
+	/* if this workload has been dispatched to i915? */
+	bool dispatched;
+	int status;
+	atomic_t shadow_ctx_active;
+	wait_queue_head_t shadow_ctx_status_wq;
+
+	/* execlist context information */
+	struct execlist_ctx_descriptor_format ctx_desc;
+	struct execlist_ring_context *ring_context;
+	unsigned long rb_head, rb_tail, rb_ctl, rb_start;
+
+	struct gvt_mm *shadow_mm;
+
+	/* different submission model may need different complete handler */
+	bool (*complete)(struct gvt_workload *);
+
+	struct list_head list;
+};
+
+#define workload_q_head(vgt, ring_id) \
+	(&(vgt->virtual_execlist_info[ring_id].workload_q_head))
+
+#define queue_workload(workload) \
+	list_add_tail(&workload->list, \
+	workload_q_head(workload->vgt, workload->ring_id))
+
+#endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 26/29] drm/i915: gvt: workload scheduler
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (24 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 25/29] drm/i915: gvt: vGPU execlist workload submission Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 27/29] drm/i915: gvt: vGPU schedule policy framework Zhi Wang
                   ` (3 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This patch introduces the GVT workload scheduler routines.

GVT workload scheduler is responsible for picking and executing GVT workload
from current scheduled vGPU. Before the workload is submitted to host i915,
the guest execlist context will be shadowed in the host GVT shadow context.
the instructions in guest ring buffer will be copied into GVT shadow ring
buffer. Then GVT-g workload scheduler will scan the instructions in guest
ring buffer and submit it to host i915.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile    |   2 +-
 drivers/gpu/drm/i915/gvt/debug.h     |   4 +
 drivers/gpu/drm/i915/gvt/gvt.c       |   4 +
 drivers/gpu/drm/i915/gvt/gvt.h       |   2 +
 drivers/gpu/drm/i915/gvt/scheduler.c | 485 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/scheduler.h |  26 +-
 6 files changed, 519 insertions(+), 4 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/scheduler.c

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index bb3170b..46f71db 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,6 +1,6 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
 		trace_points.o interrupt.o gtt.o cfg_space.o opregion.o utility.o \
-		fb_decoder.o display.o edid.o control.o execlist.o
+		fb_decoder.o display.o edid.o control.o execlist.o scheduler.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/debug.h b/drivers/gpu/drm/i915/gvt/debug.h
index 88b7d48..c4c03ac 100644
--- a/drivers/gpu/drm/i915/gvt/debug.h
+++ b/drivers/gpu/drm/i915/gvt/debug.h
@@ -75,6 +75,7 @@ enum {
 	GVT_DBG_RENDER = (1 << 4),
 	GVT_DBG_EDID = (1 << 5),
 	GVT_DBG_EL = (1 << 6),
+	GVT_DBG_SCHED = (1 << 7),
 };
 
 #define gvt_dbg_core(fmt, args...) \
@@ -89,4 +90,7 @@ enum {
 #define gvt_dbg_el(fmt, args...) \
 	gvt_dbg(GVT_DBG_EL, fmt, ##args)
 
+#define gvt_dbg_sched(fmt, args...) \
+	gvt_dbg(GVT_DBG_SCHED, fmt, ##args)
+
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index 77fe5d39..8b56c00 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -283,6 +283,7 @@ static bool init_service_thread(struct pgt_device *pdev)
 static void clean_pgt_device(struct pgt_device *pdev)
 {
 	clean_service_thread(pdev);
+	gvt_clean_workload_scheduler(pdev);
 	gvt_clean_control_interface(pdev);
 	gvt_clean_gtt(pdev);
 	gvt_irq_exit(pdev);
@@ -330,6 +331,9 @@ err:
 
 static bool post_init_pgt_device(struct pgt_device *pdev)
 {
+	if (!gvt_init_workload_scheduler(pdev))
+		return false;
+
 	return true;
 }
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 02e5a6e..83f1017 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -223,6 +223,8 @@ struct pgt_device {
 
 	struct gvt_gtt_info gtt;
 	struct gvt_device_control control;
+
+	struct gvt_workload_scheduler workload_scheduler;
 };
 
 /* request types to wake up main thread */
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
new file mode 100644
index 0000000..cdf179f
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+#include <linux/kthread.h>
+
+static bool populate_shadow_context(struct gvt_workload *workload)
+{
+	struct vgt_device *vgt = workload->vgt;
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_workload_scheduler *scheduler = &pdev->workload_scheduler;
+	int ring_id = workload->ring_id;
+
+	struct intel_context *shadow_ctx = scheduler->shadow_ctx;
+	struct drm_i915_gem_object *ctx_obj = shadow_ctx->engine[ring_id].state;
+
+	struct execlist_ring_context *guest_ring_context, *shadow_ring_context;
+
+	struct page *page;
+	void *src, *dst;
+	unsigned long guest_context_pn, context_page_num;
+	int i;
+
+	gvt_dbg_sched("ring id %d workload lrca %x", ring_id, workload->ctx_desc.lrca);
+
+	guest_context_pn = workload->ctx_desc.lrca;
+
+	context_page_num = intel_lr_context_size(&pdev->dev_priv->ring[ring_id]);
+	context_page_num = context_page_num >> PAGE_SHIFT;
+
+	i = 2;
+
+	while (i < context_page_num) {
+		src = gvt_gma_to_va(vgt->gtt.ggtt_mm,
+				(guest_context_pn + i) << GTT_PAGE_SHIFT);
+		if (!src) {
+			gvt_err("invalid guest context descriptor");
+			return false;
+		}
+
+		page = i915_gem_object_get_page(ctx_obj, LRC_PPHWSP_PN + i);
+		dst = kmap_atomic(page);
+		hypervisor_read_va(vgt, src, dst, GTT_PAGE_SIZE, 1);
+		kunmap_atomic(dst);
+		i++;
+	}
+
+	guest_ring_context = gvt_gma_to_va(vgt->gtt.ggtt_mm,
+			(guest_context_pn + 1) << GTT_PAGE_SHIFT);
+	if (!guest_ring_context) {
+		gvt_err("invalid guest context descriptor");
+		return false;
+	}
+
+	page = i915_gem_object_get_page(ctx_obj, LRC_PPHWSP_PN + 1);
+	shadow_ring_context = kmap_atomic(page);
+
+#define COPY_REG(name) \
+	hypervisor_read_va(vgt, &guest_ring_context->name.val, \
+		&shadow_ring_context->name.val, 4, 1);
+
+	COPY_REG(ctx_ctrl);
+	COPY_REG(ctx_timestamp);
+
+	if (ring_id == RCS) {
+		COPY_REG(bb_per_ctx_ptr);
+		COPY_REG(rcs_indirect_ctx);
+		COPY_REG(rcs_indirect_ctx_offset);
+	}
+#undef COPY_REG
+
+	gvt_set_context_pdp_root_pointer(vgt, shadow_ring_context,
+			workload->shadow_mm->shadow_page_table);
+
+	hypervisor_read_va(vgt,
+			(void *)guest_ring_context + sizeof(*guest_ring_context),
+			(void *)shadow_ring_context + sizeof(*shadow_ring_context),
+			GTT_PAGE_SIZE - sizeof(*guest_ring_context), 1);
+
+	kunmap_atomic(shadow_ring_context);
+	return true;
+}
+
+static void shadow_context_schedule_in(void *data)
+{
+	struct gvt_workload *workload = (struct gvt_workload *)data;
+
+	atomic_set(&workload->shadow_ctx_active, 1);
+	wake_up(&workload->shadow_ctx_status_wq);
+}
+
+static void shadow_context_schedule_out(void *data)
+{
+	struct gvt_workload *workload = (struct gvt_workload *)data;
+
+	atomic_set(&workload->shadow_ctx_active, 0);
+	wake_up(&workload->shadow_ctx_status_wq);
+}
+
+static bool dispatch_workload(struct gvt_workload *workload)
+{
+	struct vgt_device *vgt = workload->vgt;
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_workload_scheduler *scheduler = &pdev->workload_scheduler;
+	int ring_id = workload->ring_id;
+	struct intel_context *shadow_ctx = scheduler->shadow_ctx;
+	struct drm_i915_private *dev_priv = workload->vgt->pdev->dev_priv;
+
+	gvt_dbg_sched("ring id %d prepare to dispatch workload %p",
+		ring_id, workload);
+
+	workload->req = i915_gem_request_alloc(&dev_priv->ring[ring_id],
+					       shadow_ctx);
+	if (IS_ERR_OR_NULL(workload->req)) {
+		gvt_err("fail to allocate gem request");
+		workload->status = PTR_ERR(workload->req);
+		return true;
+	}
+
+	gvt_dbg_sched("ring id %d get i915 gem request %p",
+			ring_id, workload->req);
+
+	mutex_lock(&pdev->lock);
+
+	if (!populate_shadow_context(workload)) {
+		workload->status = -EINVAL;
+		goto err;
+	}
+
+	mutex_unlock(&pdev->lock);
+
+	gvt_dbg_sched("ring id %d submit workload to i915 %p",
+			ring_id, workload->req);
+
+	shadow_ctx->gvt_context_private_data[ring_id] = workload;
+	shadow_ctx->gvt_context_addressing_mode[ring_id] =
+		workload->ctx_desc.addressing_mode << 3;
+	shadow_ctx->gvt_context_schedule_in = shadow_context_schedule_in;
+	shadow_ctx->gvt_context_schedule_out = shadow_context_schedule_out;
+
+	i915_gem_request_reference(workload->req);
+	i915_add_request_no_flush(workload->req);
+
+	workload->dispatched = true;
+	return true;
+err:
+	if (workload->req) {
+		i915_gem_request_cancel(workload->req);
+		workload->req = NULL;
+	}
+	mutex_unlock(&pdev->lock);
+	return false;
+}
+
+static struct gvt_workload *pick_next_workload(
+		struct pgt_device *pdev, int ring_id)
+{
+	struct gvt_workload_scheduler *scheduler = &pdev->workload_scheduler;
+	struct gvt_workload *workload = NULL;
+
+	mutex_lock(&pdev->lock);
+
+	/*
+	 * no current instance / will be scheduled out / no workload
+	 * bail out
+	 */
+	if (!scheduler->current_instance) {
+		gvt_dbg_sched("ring id %d stop - no current instance", ring_id);
+		goto out;
+	}
+
+	if (scheduler->need_reschedule) {
+		gvt_dbg_sched("ring id %d stop - will reschedule", ring_id);
+		goto out;
+	}
+
+	if (list_empty(workload_q_head(scheduler->current_instance, ring_id))) {
+		gvt_dbg_sched("ring id %d stop - no avaiable workload", ring_id);
+		goto out;
+	}
+
+	/*
+	 * still have current workload, maybe the workload disptacher
+	 * fail to submit it for some reason, resubmit it.
+	 */
+	if (scheduler->current_workload[ring_id]) {
+		workload = scheduler->current_workload[ring_id];
+		gvt_dbg_sched("ring id %d still have current workload %p",
+				ring_id, workload);
+		goto out;
+	}
+
+	/*
+	 * pick a workload as current workload
+	 * once current workload is set, schedule policy routines
+	 * will wait the current workload to NULL when trying to
+	 * schedule out an instance.
+	 */
+	scheduler->current_workload[ring_id] = container_of(
+			workload_q_head(scheduler->current_instance, ring_id)->next,
+			struct gvt_workload, list);
+
+	workload = scheduler->current_workload[ring_id];
+
+	gvt_dbg_sched("ring id %d pick new workload %p", ring_id, workload);
+
+	atomic_inc(&workload->vgt->running_workload_num);
+out:
+	mutex_unlock(&pdev->lock);
+
+	return workload;
+}
+
+static void update_guest_context(struct gvt_workload *workload)
+{
+	struct vgt_device *vgt = workload->vgt;
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_workload_scheduler *scheduler = &pdev->workload_scheduler;
+	int ring_id = workload->ring_id;
+
+	struct intel_context *shadow_ctx = scheduler->shadow_ctx;
+	struct drm_i915_gem_object *ctx_obj = shadow_ctx->engine[ring_id].state;
+
+	struct execlist_ring_context *guest_ring_context, *shadow_ring_context;
+
+	struct page *page;
+	void *src, *dst;
+	unsigned long guest_context_pn, context_page_num;
+	int i;
+
+	gvt_dbg_sched("ring id %d workload lrca %x", ring_id, workload->ctx_desc.lrca);
+
+	guest_context_pn = workload->ctx_desc.lrca;
+
+	context_page_num = intel_lr_context_size(&pdev->dev_priv->ring[ring_id]);
+	context_page_num = context_page_num >> PAGE_SHIFT;
+
+	i = 2;
+
+	while (i < context_page_num) {
+		dst = gvt_gma_to_va(vgt->gtt.ggtt_mm,
+				(guest_context_pn + i) << GTT_PAGE_SHIFT);
+		if (!dst) {
+			gvt_err("invalid guest context descriptor");
+			return;
+		}
+
+		page = i915_gem_object_get_page(ctx_obj, LRC_PPHWSP_PN + i);
+		src = kmap_atomic(page);
+		hypervisor_write_va(vgt, dst, src, GTT_PAGE_SIZE, 1);
+		kunmap_atomic(dst);
+		i++;
+	}
+
+	guest_ring_context = gvt_gma_to_va(vgt->gtt.ggtt_mm,
+			(guest_context_pn + 1) << GTT_PAGE_SHIFT);
+	if (!guest_ring_context) {
+		gvt_err("invalid guest context descriptor");
+		return;
+	}
+
+	hypervisor_write_va(vgt, &guest_ring_context->ring_header.val,
+		&workload->rb_tail, 4, 1);
+
+	page = i915_gem_object_get_page(ctx_obj, LRC_PPHWSP_PN + 1);
+	shadow_ring_context = kmap_atomic(page);
+
+#define COPY_REG(name) \
+	hypervisor_write_va(vgt, &guest_ring_context->name.val, \
+		&shadow_ring_context->name.val, 4, 1);
+
+	COPY_REG(ctx_ctrl);
+	COPY_REG(ctx_timestamp);
+
+#undef COPY_REG
+
+	hypervisor_write_va(vgt,
+			(void *)guest_ring_context + sizeof(*guest_ring_context),
+			(void *)shadow_ring_context + sizeof(*shadow_ring_context),
+			GTT_PAGE_SIZE - sizeof(*guest_ring_context), 1);
+
+	kunmap_atomic(shadow_ring_context);
+}
+
+static void complete_current_workload(struct pgt_device *pdev, int ring_id)
+{
+	struct gvt_workload_scheduler *scheduler = &pdev->workload_scheduler;
+	struct gvt_workload *workload;
+
+	mutex_lock(&pdev->lock);
+
+	workload = scheduler->current_workload[ring_id];
+
+	if (!workload->status) {
+		wait_event(workload->shadow_ctx_status_wq,
+				!atomic_read(&workload->shadow_ctx_active));
+		update_guest_context(workload);
+	}
+
+	if (workload->req)
+		i915_gem_request_unreference(workload->req);
+
+	gvt_dbg_sched("ring id %d complete workload %p status %d",
+			ring_id, workload, workload->status);
+
+	scheduler->current_workload[ring_id] = NULL;
+
+	atomic_dec(&workload->vgt->running_workload_num);
+
+	list_del_init(&workload->list);
+	workload->complete(workload);
+
+	if (waitqueue_active(&scheduler->workload_complete_wq))
+		wake_up(&scheduler->workload_complete_wq);
+
+	mutex_unlock(&pdev->lock);
+}
+
+struct workload_thread_param {
+	struct pgt_device *pdev;
+	int ring_id;
+};
+
+static int workload_thread(void *priv)
+{
+	struct workload_thread_param *p = (struct workload_thread_param *)priv;
+	struct pgt_device *pdev = p->pdev;
+	int ring_id = p->ring_id;
+	struct gvt_workload_scheduler *scheduler = &pdev->workload_scheduler;
+	struct gvt_workload *workload = NULL;
+	int r;
+
+	kfree(p);
+
+	gvt_dbg_core("workload thread for ring %d started", ring_id);
+
+	while (!kthread_should_stop()) {
+		r = wait_event_interruptible(scheduler->waitq[ring_id],
+				kthread_should_stop() ||
+				(workload = pick_next_workload(pdev, ring_id)));
+
+		if (r)
+			gvt_warn("workload thread waken up by unexpected signal!");
+
+		if (kthread_should_stop())
+			break;
+
+		gvt_dbg_sched("ring id %d next workload %p vgt %d",
+				workload->ring_id, workload, workload->vgt->id);
+
+		/*
+		 * Always take i915 big lock first
+		 */
+		r = i915_mutex_lock_interruptible(pdev->dev_priv->dev);
+		if (r < 0) {
+			gvt_warn("i915 submission channel is not available, retry");
+			schedule_timeout(1);
+			continue;
+		}
+
+		gvt_dbg_sched("ring id %d will dispatch workload %p",
+				workload->ring_id, workload);
+
+		if (!dispatch_workload(workload)) {
+			gvt_warn("fail to dispatch workload, skip");
+			goto complete;
+		}
+
+		gvt_dbg_sched("ring id %d wait workload %p",
+				workload->ring_id, workload);
+
+		workload->status = i915_wait_request(workload->req);
+		if (workload->status != 0)
+			gvt_warn("fail to wait workload, skip");
+
+complete:
+		gvt_dbg_sched("will complete workload %p, status: %d",
+				workload, workload->status);
+
+		complete_current_workload(pdev, ring_id);
+		mutex_unlock(&pdev->dev_priv->dev->struct_mutex);
+	}
+
+	return 0;
+}
+
+void gvt_wait_instance_idle(struct vgt_device *vgt)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	struct gvt_workload_scheduler *scheduler = &pdev->workload_scheduler;
+
+	if (atomic_read(&vgt->running_workload_num)) {
+		gvt_dbg_sched("wait instance idle");
+
+		wait_event(scheduler->workload_complete_wq,
+				!atomic_read(&vgt->running_workload_num));
+	}
+}
+
+void gvt_clean_workload_scheduler(struct pgt_device *pdev)
+{
+	struct gvt_workload_scheduler *scheduler = &pdev->workload_scheduler;
+	int i;
+
+	gvt_dbg_core("clean workload scheduler");
+
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		if (scheduler->thread[i]) {
+			kthread_stop(scheduler->thread[i]);
+			scheduler->thread[i] = NULL;
+		}
+	}
+
+	i915_gem_context_unreference(scheduler->shadow_ctx);
+	scheduler->shadow_ctx = NULL;
+}
+
+bool gvt_init_workload_scheduler(struct pgt_device *pdev)
+{
+	struct gvt_workload_scheduler *scheduler = &pdev->workload_scheduler;
+	struct workload_thread_param *param = NULL;
+	int i;
+
+	gvt_dbg_core("init workload scheduler");
+
+	memset(scheduler, 0, sizeof(*scheduler));
+
+	init_waitqueue_head(&scheduler->workload_complete_wq);
+
+	scheduler->shadow_ctx = i915_gem_create_gvt_context(pdev->dev_priv->dev);
+	if (!scheduler->shadow_ctx) {
+		gvt_err("fail to create shadow context");
+		goto err;
+	}
+
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		init_waitqueue_head(&scheduler->waitq[i]);
+
+		param = kzalloc(sizeof(*param), GFP_KERNEL);
+		if (!param) {
+			gvt_err("fail to allocate workload thread param");
+			goto err;
+		}
+
+		param->pdev = pdev;
+		param->ring_id = i;
+
+		scheduler->thread[i] = kthread_run(workload_thread, param,
+			"gvt workload %d", i);
+		if (!scheduler->thread[i]) {
+			gvt_err("fail to create workload thread");
+			goto err;
+		}
+	}
+
+	return true;
+err:
+	if (param) {
+		kfree(param);
+		param = NULL;
+	}
+	gvt_clean_workload_scheduler(pdev);
+	return false;
+}
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h
index dd24fda..c4e7fa2 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.h
+++ b/drivers/gpu/drm/i915/gvt/scheduler.h
@@ -24,6 +24,19 @@
 #ifndef _GVT_SCHEDULER_H_
 #define _GVT_SCHEDULER_H_
 
+struct gvt_workload_scheduler {
+	struct vgt_device *current_instance;
+	struct vgt_device *next_instance;
+	struct gvt_workload *current_workload[I915_NUM_RINGS];
+	bool need_reschedule;
+
+	struct intel_context *shadow_ctx;
+
+	wait_queue_head_t workload_complete_wq;
+	struct task_struct *thread[I915_NUM_RINGS];
+	wait_queue_head_t waitq[I915_NUM_RINGS];
+};
+
 struct gvt_workload {
 	struct vgt_device *vgt;
 	int ring_id;
@@ -52,8 +65,15 @@ struct gvt_workload {
 #define workload_q_head(vgt, ring_id) \
 	(&(vgt->virtual_execlist_info[ring_id].workload_q_head))
 
-#define queue_workload(workload) \
-	list_add_tail(&workload->list, \
-	workload_q_head(workload->vgt, workload->ring_id))
+#define queue_workload(workload) do { \
+	list_add_tail(&workload->list, workload_q_head(workload->vgt, workload->ring_id)); \
+	wake_up(&workload->vgt->pdev->workload_scheduler.waitq[workload->ring_id]); \
+}while(0)
+
+bool gvt_init_workload_scheduler(struct pgt_device *pdev);
+
+void gvt_clean_workload_scheduler(struct pgt_device *pdev);
+
+void gvt_wait_instance_idle(struct vgt_device *vgt);
 
 #endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 27/29] drm/i915: gvt: vGPU schedule policy framework
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (25 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 26/29] drm/i915: gvt: workload scheduler Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 28/29] drm/i915: gvt: vGPU context switch Zhi Wang
                   ` (2 subsequent siblings)
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

This patch introduces a vGPU schedule policy framework, with a timer based
schedule policy module for now

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile       |   3 +-
 drivers/gpu/drm/i915/gvt/gvt.h          |   2 +
 drivers/gpu/drm/i915/gvt/handlers.c     |  16 ++
 drivers/gpu/drm/i915/gvt/instance.c     |  16 ++
 drivers/gpu/drm/i915/gvt/sched_policy.c | 295 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/sched_policy.h |  48 ++++++
 drivers/gpu/drm/i915/gvt/scheduler.c    |   5 +
 drivers/gpu/drm/i915/gvt/scheduler.h    |   3 +
 8 files changed, 387 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/sched_policy.c
 create mode 100644 drivers/gpu/drm/i915/gvt/sched_policy.h

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index 46f71db..dcaf715 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,6 +1,7 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
 		trace_points.o interrupt.o gtt.o cfg_space.o opregion.o utility.o \
-		fb_decoder.o display.o edid.o control.o execlist.o scheduler.o
+		fb_decoder.o display.o edid.o control.o execlist.o scheduler.o \
+		sched_policy.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 83f1017..5788bb7 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -44,6 +44,7 @@
 #include "display.h"
 #include "execlist.h"
 #include "scheduler.h"
+#include "sched_policy.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -160,6 +161,7 @@ struct vgt_device {
 	unsigned long last_reset_time;
 	atomic_t crashing;
 	bool warn_untrack;
+	void *sched_data;
 };
 
 struct gvt_gm_allocator {
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index 356cfc4..a04d0cb 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -259,6 +259,22 @@ static bool dpy_reg_mmio_read_3(struct vgt_device *vgt, unsigned int offset,
 static bool ring_mode_write(struct vgt_device *vgt, unsigned int off,
 		void *p_data, unsigned int bytes)
 {
+	u32 data = *(u32 *)p_data;
+	int ring_id = gvt_render_mmio_to_ring_id(off);
+	bool enable_execlist;
+
+	if (_MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)
+			|| _MASKED_BIT_DISABLE(GFX_RUN_LIST_ENABLE)) {
+		enable_execlist = !!(data & GFX_RUN_LIST_ENABLE);
+
+		gvt_info("EXECLIST %s on ring %d.",
+				(enable_execlist ? "enabling" : "disabling"),
+				ring_id);
+
+		if (enable_execlist)
+			gvt_start_schedule(vgt);
+	}
+
 	return true;
 }
 
diff --git a/drivers/gpu/drm/i915/gvt/instance.c b/drivers/gpu/drm/i915/gvt/instance.c
index 959c8ee..0b7eb8f 100644
--- a/drivers/gpu/drm/i915/gvt/instance.c
+++ b/drivers/gpu/drm/i915/gvt/instance.c
@@ -193,9 +193,22 @@ void gvt_destroy_instance(struct vgt_device *vgt)
 	struct pgt_device *pdev = vgt->pdev;
 
 	mutex_lock(&pdev->lock);
+
+	gvt_stop_schedule(vgt);
+
+	mutex_unlock(&pdev->lock);
+
+	if (atomic_read(&vgt->running_workload_num))
+		gvt_wait_instance_idle(vgt);
+
+	mutex_lock(&pdev->lock);
+
+	gvt_clean_instance_sched_policy(vgt);
+
 	gvt_set_instance_offline(vgt);
 	if (vgt->id != -1)
 		idr_remove(&pdev->instance_idr, vgt->id);
+
 	mutex_unlock(&pdev->lock);
 
 	hypervisor_hvm_exit(vgt);
@@ -234,6 +247,9 @@ struct vgt_device *gvt_create_instance(struct pgt_device *pdev,
 	vgt->id = id;
 	vgt->pdev = pdev;
 
+	if (!gvt_init_instance_sched_policy(vgt))
+		goto err;
+
 	vgt->warn_untrack = true;
 
 	if (!create_virtual_device_state(vgt, info))
diff --git a/drivers/gpu/drm/i915/gvt/sched_policy.c b/drivers/gpu/drm/i915/gvt/sched_policy.c
new file mode 100644
index 0000000..14f4301
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/sched_policy.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+static bool instance_has_pending_workload(struct vgt_device *vgt)
+{
+	struct gvt_virtual_execlist_info *info;
+	int i;
+
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		info = &vgt->virtual_execlist_info[i];
+		if (!list_empty(workload_q_head(vgt, i)))
+			return true;
+	}
+
+	return false;
+}
+
+static void try_to_schedule_next_instance(struct pgt_device *pdev)
+{
+	struct gvt_workload_scheduler *scheduler =
+			&pdev->workload_scheduler;
+	int i;
+
+	/* no target to schedule */
+	if (!scheduler->next_instance)
+		return;
+
+	gvt_dbg_sched("try to schedule next instance %d",
+			scheduler->next_instance->id);
+
+	/*
+	 * after the flag is set, workload dispatch thread will
+	 * stop dispatching workload for current instance
+	 */
+	scheduler->need_reschedule = true;
+
+	/* still have uncompleted workload? */
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		if (scheduler->current_workload[i]) {
+			gvt_dbg_sched("still have running workload");
+			return;
+		}
+	}
+
+	gvt_dbg_sched("switch to next instance %d",
+			scheduler->next_instance->id);
+
+	/* switch current instance */
+	scheduler->current_instance = scheduler->next_instance;
+	scheduler->next_instance = NULL;
+
+	/* wake up workload dispatch thread */
+	for (i = 0; i < I915_NUM_RINGS; i++)
+		wake_up(&scheduler->waitq[i]);
+
+	scheduler->need_reschedule = false;
+}
+
+struct tbs_instance_data {
+	struct list_head list;
+	struct vgt_device *vgt;
+	/* put some per-instance sched stats here*/
+};
+
+struct tbs_sched_data {
+	struct pgt_device *pdev;
+	struct delayed_work work;
+	unsigned long period;
+	atomic_t runq_instance_num;
+	struct list_head runq_head;
+};
+
+#define GVT_DEFAULT_TIME_SLICE (16 * HZ / 1000)
+
+static void tbs_sched_func(struct work_struct *work)
+{
+	struct tbs_sched_data *sched_data = container_of(work,
+			struct tbs_sched_data, work.work);
+	struct tbs_instance_data *instance_data;
+
+	struct pgt_device *pdev = sched_data->pdev;
+	struct gvt_workload_scheduler *scheduler =
+			&pdev->workload_scheduler;
+
+	struct vgt_device *vgt = NULL;
+	struct list_head *pos, *head;
+
+	mutex_lock(&pdev->lock);
+
+	/* no instance or has already had a target */
+	if (list_empty(&sched_data->runq_head)|| scheduler->next_instance)
+		goto out;
+
+	if (scheduler->current_instance) {
+		instance_data = scheduler->current_instance->sched_data;
+		head = &instance_data->list;
+	} else {
+		gvt_dbg_sched("no current instance search from q head");
+		head = &sched_data->runq_head;
+	}
+
+	/* search a instance with pending workload */
+	list_for_each(pos, head) {
+		if (pos == &sched_data->runq_head)
+			continue;
+
+		instance_data = container_of(pos, struct tbs_instance_data, list);
+		if (!instance_has_pending_workload(instance_data->vgt))
+			continue;
+
+		vgt = instance_data->vgt;
+		break;
+	}
+
+	if (vgt) {
+		scheduler->next_instance = vgt;
+		gvt_dbg_sched("pick next instance %d", vgt->id);
+	}
+out:
+	if (scheduler->next_instance) {
+		gvt_dbg_sched("try to schedule next instance %d",
+				scheduler->next_instance->id);
+		try_to_schedule_next_instance(pdev);
+	}
+
+	/*
+	 * still have instance on runq
+	 * or last schedule haven't finished due to running workload
+	 */
+	if (atomic_read(&sched_data->runq_instance_num) || scheduler->next_instance)
+		schedule_delayed_work(&sched_data->work, sched_data->period);
+
+	mutex_unlock(&pdev->lock);
+}
+
+static bool tbs_sched_init(struct pgt_device *pdev)
+{
+	struct gvt_workload_scheduler *scheduler =
+		&pdev->workload_scheduler;
+
+	struct tbs_sched_data *data;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		gvt_err("fail to allocate sched data");
+		return false;
+	}
+
+	INIT_LIST_HEAD(&data->runq_head);
+	INIT_DELAYED_WORK(&data->work, tbs_sched_func);
+	data->period = GVT_DEFAULT_TIME_SLICE;
+	data->pdev = pdev;
+
+	atomic_set(&data->runq_instance_num, 0);
+	scheduler->sched_data = data;
+
+	return true;
+}
+
+static void tbs_sched_clean(struct pgt_device *pdev)
+{
+	struct gvt_workload_scheduler *scheduler =
+		&pdev->workload_scheduler;
+	struct tbs_sched_data *data = scheduler->sched_data;
+
+	cancel_delayed_work(&data->work);
+	kfree(data);
+	scheduler->sched_data = NULL;
+}
+
+static bool tbs_sched_instance_init(struct vgt_device *vgt)
+{
+	struct tbs_instance_data *data;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		gvt_err("fail to allocate memory");
+		return false;
+	}
+
+	data->vgt = vgt;
+	INIT_LIST_HEAD(&data->list);
+
+	vgt->sched_data = data;
+
+	return true;
+}
+
+static void tbs_sched_instance_clean(struct vgt_device *vgt)
+{
+	kfree(vgt->sched_data);
+	vgt->sched_data = NULL;
+}
+
+static void tbs_sched_start_schedule(struct vgt_device *vgt)
+{
+	struct tbs_sched_data *sched_data = vgt->pdev->workload_scheduler.sched_data;
+	struct tbs_instance_data *instance_data = vgt->sched_data;
+
+	if (!list_empty(&instance_data->list))
+		return;
+
+	list_add_tail(&instance_data->list, &sched_data->runq_head);
+	atomic_inc(&sched_data->runq_instance_num);
+
+	schedule_delayed_work(&sched_data->work, sched_data->period);
+}
+
+static void tbs_sched_stop_schedule(struct vgt_device *vgt)
+{
+	struct tbs_sched_data *sched_data = vgt->pdev->workload_scheduler.sched_data;
+	struct tbs_instance_data *instance_data = vgt->sched_data;
+
+	atomic_dec(&sched_data->runq_instance_num);
+	list_del_init(&instance_data->list);
+}
+
+struct gvt_schedule_policy_ops tbs_schedule_ops = {
+	.init = tbs_sched_init,
+	.clean = tbs_sched_clean,
+	.instance_init = tbs_sched_instance_init,
+	.instance_clean = tbs_sched_instance_clean,
+	.start_schedule = tbs_sched_start_schedule,
+	.stop_schedule = tbs_sched_stop_schedule,
+};
+
+bool gvt_init_sched_policy(struct pgt_device *pdev)
+{
+	pdev->workload_scheduler.sched_ops = &tbs_schedule_ops;
+
+	return pdev->workload_scheduler.sched_ops->init(pdev);
+}
+
+void gvt_clean_sched_policy(struct pgt_device *pdev)
+{
+	pdev->workload_scheduler.sched_ops->clean(pdev);
+}
+
+bool gvt_init_instance_sched_policy(struct vgt_device *vgt)
+{
+	return vgt->pdev->workload_scheduler.sched_ops->instance_init(vgt);
+}
+
+void gvt_clean_instance_sched_policy(struct vgt_device *vgt)
+{
+	vgt->pdev->workload_scheduler.sched_ops->instance_clean(vgt);
+}
+
+void gvt_start_schedule(struct vgt_device *vgt)
+{
+	gvt_info("[vgt %d] start schedule", vgt->id);
+
+	vgt->pdev->workload_scheduler.sched_ops->start_schedule(vgt);
+}
+
+void gvt_stop_schedule(struct vgt_device *vgt)
+{
+	struct gvt_workload_scheduler *scheduler =
+		&vgt->pdev->workload_scheduler;
+
+	gvt_info("[vgt %d] stop schedule", vgt->id);
+
+	scheduler->sched_ops->stop_schedule(vgt);
+
+	if (scheduler->next_instance == vgt)
+		scheduler->next_instance = NULL;
+
+	if (scheduler->current_instance == vgt) {
+		/* stop workload dispatching */
+		scheduler->need_reschedule = true;
+		scheduler->current_instance = NULL;
+	}
+}
diff --git a/drivers/gpu/drm/i915/gvt/sched_policy.h b/drivers/gpu/drm/i915/gvt/sched_policy.h
new file mode 100644
index 0000000..9cc1899
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/sched_policy.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef __GVT_SCHED_POLICY__
+#define __GVT_SCHED_POLICY__
+
+struct gvt_schedule_policy_ops {
+	bool (*init)(struct pgt_device *pdev);
+	void (*clean)(struct pgt_device *pdev);
+	bool (*instance_init)(struct vgt_device *vgt);
+	void (*instance_clean)(struct vgt_device *vgt);
+	void (*start_schedule)(struct vgt_device *vgt);
+	void (*stop_schedule)(struct vgt_device *vgt);
+};
+
+bool gvt_init_sched_policy(struct pgt_device *pdev);
+
+void gvt_clean_sched_policy(struct pgt_device *pdev);
+
+bool gvt_init_instance_sched_policy(struct vgt_device *vgt);
+
+void gvt_clean_instance_sched_policy(struct vgt_device *vgt);
+
+void gvt_start_schedule(struct vgt_device *vgt);
+
+void gvt_stop_schedule(struct vgt_device *vgt);
+
+#endif
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
index cdf179f..d8d2e23 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.c
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -434,6 +434,8 @@ void gvt_clean_workload_scheduler(struct pgt_device *pdev)
 
 	i915_gem_context_unreference(scheduler->shadow_ctx);
 	scheduler->shadow_ctx = NULL;
+
+	gvt_clean_sched_policy(pdev);
 }
 
 bool gvt_init_workload_scheduler(struct pgt_device *pdev)
@@ -474,6 +476,9 @@ bool gvt_init_workload_scheduler(struct pgt_device *pdev)
 		}
 	}
 
+	if (!gvt_init_sched_policy(pdev))
+		goto err;
+
 	return true;
 err:
 	if (param) {
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h
index c4e7fa2..7a8f1eb 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.h
+++ b/drivers/gpu/drm/i915/gvt/scheduler.h
@@ -35,6 +35,9 @@ struct gvt_workload_scheduler {
 	wait_queue_head_t workload_complete_wq;
 	struct task_struct *thread[I915_NUM_RINGS];
 	wait_queue_head_t waitq[I915_NUM_RINGS];
+
+	void *sched_data;
+	struct gvt_schedule_policy_ops *sched_ops;
 };
 
 struct gvt_workload {
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 28/29] drm/i915: gvt: vGPU context switch
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (26 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 27/29] drm/i915: gvt: vGPU schedule policy framework Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 10:21 ` [RFC 29/29] drm/i915: gvt: vGPU command scanner Zhi Wang
  2016-01-28 17:15 ` ✗ Fi.CI.BAT: failure for iGVT-g implementation in i915 Patchwork
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

As different VM may configure different render MMIOs when executing workload,
to schedule workloads between different VM, the render MMIOs have to be
switched.

Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile    |   2 +-
 drivers/gpu/drm/i915/gvt/debug.h     |   3 +
 drivers/gpu/drm/i915/gvt/gvt.h       |   1 +
 drivers/gpu/drm/i915/gvt/render.c    | 104 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/render.h    |  31 +++++++++++
 drivers/gpu/drm/i915/gvt/scheduler.c |   2 +
 6 files changed, 142 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/render.c
 create mode 100644 drivers/gpu/drm/i915/gvt/render.h

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index dcaf715..ccb0d32 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,7 +1,7 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
 		trace_points.o interrupt.o gtt.o cfg_space.o opregion.o utility.o \
 		fb_decoder.o display.o edid.o control.o execlist.o scheduler.o \
-		sched_policy.o
+		sched_policy.o render.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/debug.h b/drivers/gpu/drm/i915/gvt/debug.h
index c4c03ac..953ba08 100644
--- a/drivers/gpu/drm/i915/gvt/debug.h
+++ b/drivers/gpu/drm/i915/gvt/debug.h
@@ -87,6 +87,9 @@ enum {
 #define gvt_dbg_irq(fmt, args...) \
 	gvt_dbg(GVT_DBG_IRQ, fmt, ##args)
 
+#define gvt_dbg_render(fmt, args...) \
+	gvt_dbg(GVT_DBG_RENDER, fmt, ##args)
+
 #define gvt_dbg_el(fmt, args...) \
 	gvt_dbg(GVT_DBG_EL, fmt, ##args)
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 5788bb7..d7ff61e 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -45,6 +45,7 @@
 #include "execlist.h"
 #include "scheduler.h"
 #include "sched_policy.h"
+#include "render.h"
 
 #define GVT_MAX_VGPU 8
 
diff --git a/drivers/gpu/drm/i915/gvt/render.c b/drivers/gpu/drm/i915/gvt/render.c
new file mode 100644
index 0000000..2552c77
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/render.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright(c) 2011-2016 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 "gvt.h"
+
+struct render_mmio {
+	int ring_id;
+	u32 reg;
+	u32 value;
+	u32 mask;
+};
+
+static struct render_mmio gen8_render_mmio_list[] = {
+	{RCS, 0x229c, 0xffff},
+	{RCS, 0x2248, 0x0},
+	{RCS, 0x2098, 0x0},
+	{RCS, 0x20c0, 0xffff},
+	{RCS, 0x24d0, 0},
+	{RCS, 0x24d4, 0},
+	{RCS, 0x24d8, 0},
+	{RCS, 0x24dc, 0},
+	{RCS, 0x7004, 0xffff},
+	{RCS, 0x7008, 0xffff},
+	{RCS, 0x7000, 0xffff},
+	{RCS, 0x7010, 0xffff},
+	{RCS, 0x7300, 0xffff},
+	{RCS, 0x83a4, 0xffff},
+
+	{BCS, GVT_RING_MODE(BLT_RING_BASE), 0xffff},
+	{BCS, _RING_MI_MODE(BLT_RING_BASE), 0xffff},
+	{BCS, _RING_INSTPM(BLT_RING_BASE), 0xffff},
+	{BCS, _RING_HWSTAM(BLT_RING_BASE), 0xffff},
+	{BCS, 0x22028, 0x0},
+};
+
+void gvt_load_render_mmio(struct vgt_device *vgt, int ring_id)
+{
+	u32 v;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(gen8_render_mmio_list); i++) {
+		struct render_mmio *mmio = gen8_render_mmio_list + i;
+		if (mmio->ring_id != ring_id)
+			continue;
+
+		mmio->value = gvt_mmio_read(vgt->pdev, mmio->reg);
+		if (mmio->mask)
+			v = __vreg(vgt, mmio->reg) | (mmio->mask << 16);
+		else
+			v = __vreg(vgt, mmio->reg);
+
+		gvt_mmio_write(vgt->pdev, mmio->reg, v);
+		gvt_mmio_posting_read(vgt->pdev, mmio->reg);
+
+		gvt_dbg_render("reg %x value old %x new %x",
+				mmio->reg, mmio->value, v);
+	}
+}
+
+void gvt_restore_render_mmio(struct vgt_device *vgt, int ring_id)
+{
+	u32 v;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(gen8_render_mmio_list); i++) {
+		struct render_mmio *mmio = gen8_render_mmio_list + i;
+		if (mmio->ring_id != ring_id)
+			continue;
+
+		__vreg(vgt, mmio->reg) = gvt_mmio_read(vgt->pdev, mmio->reg);
+
+		if (mmio->mask) {
+			__vreg(vgt, mmio->reg) &= ~(mmio->mask << 16);
+			v = mmio->value | (mmio->mask << 16);
+		} else
+			v = mmio->value;
+
+		gvt_mmio_write(vgt->pdev, mmio->reg, v);
+		gvt_mmio_posting_read(vgt->pdev, mmio->reg);
+
+		gvt_dbg_render("reg %x value old %x new %x",
+				mmio->reg, mmio->value, v);
+	}
+}
diff --git a/drivers/gpu/drm/i915/gvt/render.h b/drivers/gpu/drm/i915/gvt/render.h
new file mode 100644
index 0000000..8058113
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/render.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#ifndef __GVT_RENDER_H__
+#define __GVT_RENDER_H__
+
+void gvt_load_render_mmio(struct vgt_device *vgt, int ring_id);
+
+void gvt_restore_render_mmio(struct vgt_device *vgt, int ring_id);
+
+#endif
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
index d8d2e23..d38aeb1 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.c
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -106,6 +106,7 @@ static void shadow_context_schedule_in(void *data)
 {
 	struct gvt_workload *workload = (struct gvt_workload *)data;
 
+	gvt_load_render_mmio(workload->vgt, workload->ring_id);
 	atomic_set(&workload->shadow_ctx_active, 1);
 	wake_up(&workload->shadow_ctx_status_wq);
 }
@@ -114,6 +115,7 @@ static void shadow_context_schedule_out(void *data)
 {
 	struct gvt_workload *workload = (struct gvt_workload *)data;
 
+	gvt_restore_render_mmio(workload->vgt, workload->ring_id);
 	atomic_set(&workload->shadow_ctx_active, 0);
 	wake_up(&workload->shadow_ctx_status_wq);
 }
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [RFC 29/29] drm/i915: gvt: vGPU command scanner
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (27 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 28/29] drm/i915: gvt: vGPU context switch Zhi Wang
@ 2016-01-28 10:21 ` Zhi Wang
  2016-01-28 17:15 ` ✗ Fi.CI.BAT: failure for iGVT-g implementation in i915 Patchwork
  29 siblings, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-01-28 10:21 UTC (permalink / raw)
  To: intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

From: Yulei Zhang <yulei.zhang@intel.com>

This patch introduces a command scanner to scan guest command buffers.

Signed-off-by: Yulei Zhang <yulei.zhang@intel.com>
Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
---
 drivers/gpu/drm/i915/gvt/Makefile     |    2 +-
 drivers/gpu/drm/i915/gvt/cmd_parser.c | 2018 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/gvt/cmd_parser.h |  466 ++++++++
 drivers/gpu/drm/i915/gvt/debug.h      |    4 +
 drivers/gpu/drm/i915/gvt/gvt.c        |    4 +
 drivers/gpu/drm/i915/gvt/gvt.h        |    3 +
 drivers/gpu/drm/i915/gvt/interrupt.c  |   49 +
 drivers/gpu/drm/i915/gvt/interrupt.h  |    4 +
 drivers/gpu/drm/i915/gvt/perf.h       |    3 +
 drivers/gpu/drm/i915/gvt/scheduler.c  |    9 +
 drivers/gpu/drm/i915/gvt/scheduler.h  |    5 +-
 drivers/gpu/drm/i915/gvt/trace.h      |   52 +
 12 files changed, 2617 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gvt/cmd_parser.c
 create mode 100644 drivers/gpu/drm/i915/gvt/cmd_parser.h

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index ccb0d32..6a631b6 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,7 +1,7 @@
 GVT_SOURCE := gvt.o params.o aperture_gm.o mmio.o handlers.o instance.o \
 		trace_points.o interrupt.o gtt.o cfg_space.o opregion.o utility.o \
 		fb_decoder.o display.o edid.o control.o execlist.o scheduler.o \
-		sched_policy.o render.o
+		sched_policy.o render.o cmd_parser.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c
new file mode 100644
index 0000000..d1bc9b0
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c
@@ -0,0 +1,2018 @@
+/*
+ * Copyright(c) 2011-2016 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/slab.h>
+#include "gvt.h"
+#include "trace.h"
+
+/* gvt uses below bits in NOOP_ID:
+ *	    bit 21 - 16 is command type.
+ *	    bit 15 - 0  holds command specific information.
+ *
+ * Assumption: Linux/Windows guest will not use bits 21 - bits 16 with
+ * non-zero value.
+ */
+#define GVT_NOOP_ID_CMD_SHIFT	16
+#define GVT_NOOP_ID_CMD_MASK	(0x3f << GVT_NOOP_ID_CMD_SHIFT)
+#define CMD_LENGTH_MASK		0xff
+#define gmadr_dw_number(s)	\
+	(s->vgt->pdev->device_info.gmadr_bytes_in_cmd >> 2)
+#define BIT_RANGE_MASK(a, b)	\
+	((1UL << ((a) + 1)) - (1UL << (b)))
+
+unsigned long bypass_scan_mask = 0;
+
+/* ring ALL, type = 0 */
+static struct sub_op_bits sub_op_mi[] = {
+	{31, 29},
+	{28, 23},
+};
+
+static struct decode_info decode_info_mi = {
+	"MI",
+	OP_LEN_MI,
+	ARRAY_SIZE(sub_op_mi),
+	sub_op_mi,
+};
+
+/* ring RCS, command type 2 */
+static struct sub_op_bits sub_op_2d[] = {
+	{31, 29},
+	{28, 22},
+};
+
+static struct decode_info decode_info_2d = {
+	"2D",
+	OP_LEN_2D,
+	ARRAY_SIZE(sub_op_2d),
+	sub_op_2d,
+};
+
+/* ring RCS, command type 3 */
+static struct sub_op_bits sub_op_3d_media[] = {
+	{31, 29},
+	{28, 27},
+	{26, 24},
+	{23, 16},
+};
+
+static struct decode_info decode_info_3d_media = {
+	"3D_Media",
+	OP_LEN_3D_MEDIA,
+	ARRAY_SIZE(sub_op_3d_media),
+	sub_op_3d_media,
+};
+
+/* ring VCS, command type 3 */
+static struct sub_op_bits sub_op_mfx_vc[] = {
+	{31, 29},
+	{28, 27},
+	{26, 24},
+	{23, 21},
+	{20, 16},
+};
+
+static struct decode_info decode_info_mfx_vc = {
+	"MFX_VC",
+	OP_LEN_MFX_VC,
+	ARRAY_SIZE(sub_op_mfx_vc),
+	sub_op_mfx_vc,
+};
+
+/* ring VECS, command type 3 */
+static struct sub_op_bits sub_op_vebox[] = {
+	{31, 29},
+	{28, 27},
+	{26, 24},
+	{23, 21},
+	{20, 16},
+};
+
+static struct decode_info decode_info_vebox = {
+	"VEBOX",
+	OP_LEN_VEBOX,
+	ARRAY_SIZE(sub_op_vebox),
+	sub_op_vebox,
+};
+
+static struct decode_info* ring_decode_info[I915_NUM_RINGS][8] = {
+	[RCS] = {
+		&decode_info_mi,
+		NULL,
+		NULL,
+		&decode_info_3d_media,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+	},
+
+	[VCS] = {
+		&decode_info_mi,
+		NULL,
+		NULL,
+		&decode_info_mfx_vc,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+	},
+
+	[BCS] = {
+		&decode_info_mi,
+		NULL,
+		&decode_info_2d,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+	},
+
+	[VECS] = {
+		&decode_info_mi,
+		NULL,
+		NULL,
+		&decode_info_vebox,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+	},
+
+	[VCS2] = {
+		&decode_info_mi,
+		NULL,
+		NULL,
+		&decode_info_mfx_vc,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+	},
+};
+
+static inline u32 get_opcode(u32 cmd, int ring_id)
+{
+	struct decode_info * d_info;
+
+	if (ring_id >= I915_NUM_RINGS)
+		return INVALID_OP;
+
+	d_info = ring_decode_info[ring_id][CMD_TYPE(cmd)];
+	if (d_info == NULL)
+		return INVALID_OP;
+
+	return cmd >> (32 - d_info->op_len);
+}
+
+static inline struct cmd_info* find_cmd_entry(struct pgt_device *pdev,
+		unsigned int opcode, int ring_id)
+{
+	struct gvt_cmd_entry *e;
+
+	hash_for_each_possible(pdev->cmd_table, e, hlist, opcode) {
+		if ((opcode == e->info->opcode) && (e->info->rings & (1<<ring_id)))
+			return e->info;
+	}
+	return NULL;
+}
+
+static inline struct cmd_info* gvt_get_cmd_info(struct pgt_device *pdev,
+		u32 cmd, int ring_id)
+{
+	u32 opcode;
+
+	opcode = get_opcode(cmd, ring_id);
+	if (opcode == INVALID_OP) {
+		return NULL;
+	}
+
+	return find_cmd_entry(pdev, opcode, ring_id);
+}
+
+static inline u32 sub_op_val(u32 cmd, u32 hi, u32 low)
+{
+	return (cmd >> low) & ((1U << (hi-low+1)) - 1);
+}
+
+static inline void gvt_print_opcode(u32 cmd, int ring_id)
+{
+	struct decode_info * d_info;
+	int i;
+
+	if (ring_id >= I915_NUM_RINGS)
+		return;
+
+	d_info = ring_decode_info[ring_id][CMD_TYPE(cmd)];
+	if (d_info == NULL)
+		return;
+
+	gvt_err("opcode=0x%x %s sub_ops:", cmd >> (32 - d_info->op_len), d_info->name);
+
+	for (i = 0; i< d_info->nr_sub_op; i++)
+		printk("0x%x ", sub_op_val(cmd, d_info->sub_op[i].hi,  d_info->sub_op[i].low));
+
+	printk("\n");
+}
+
+static inline u32 *cmd_ptr(struct parser_exec_state *s, int index)
+{
+	return s->ip_va + (index << 2);
+}
+
+static inline u32 cmd_val(struct parser_exec_state *s, int index)
+{
+	return *cmd_ptr(s, index);
+}
+
+static void parser_exec_state_dump(struct parser_exec_state *s)
+{
+	gvt_err("  vgt%d RING%d: ring_start(%08lx) ring_end(%08lx)"
+			" ring_head(%08lx) ring_tail(%08lx)", s->vgt->id,
+			s->ring_id, s->ring_start, s->ring_start + s->ring_size, s->ring_head, s->ring_tail);
+
+	gvt_err("  %s %s ip_gma(%08lx) ",
+			s->buf_type == RING_BUFFER_INSTRUCTION ? "RING_BUFFER": "BATCH_BUFFER",
+			s->buf_addr_type == GTT_BUFFER ? "GTT" : "PPGTT", s->ip_gma);
+
+	if (s->ip_va == NULL) {
+		gvt_err(" ip_va(NULL)");
+	} else {
+		int cnt = 0;
+		gvt_err("  ip_va=%p: %08x %08x %08x %08x ",
+				s->ip_va, cmd_val(s, 0), cmd_val(s, 1), cmd_val(s, 2), cmd_val(s, 3));
+
+		gvt_print_opcode(cmd_val(s, 0), s->ring_id);
+
+		/* print the whole page to trace */
+		trace_printk("ERROR ip_va=%p: %08x %08x %08x %08x ",
+				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) {
+		trace_printk("DUMP ip_va=%p: %08x %08x %08x %08x %08x %08x %08x %08x ",
+				s->ip_va, cmd_val(s, 0), cmd_val(s, 1), cmd_val(s, 2), cmd_val(s, 3),
+				          cmd_val(s, 4), cmd_val(s, 5), cmd_val(s, 6), cmd_val(s, 7));
+
+			s->ip_va+=8;
+			cnt+=8;
+		}
+
+	}
+}
+
+static inline void update_ip_va(struct parser_exec_state *s)
+{
+	unsigned long len = 0;
+
+	ASSERT(s->ring_head != s->ring_tail);
+
+	if (s->buf_type == RING_BUFFER_INSTRUCTION) {
+		unsigned long ring_top = s->ring_start + s->ring_size;
+		if (s->ring_head > s->ring_tail) {
+			if (s->ip_gma >= s->ring_head && ring_top)
+				len = (s->ip_gma - s->ring_head);
+			else if (s->ip_gma >= s->ring_start &&
+					s->ip_gma <= s->ring_tail)
+				len = (ring_top - s->ring_head) +
+					(s->ip_gma - s->ring_start);
+		} else
+			len = (s->ip_gma - s->ring_head);
+
+		s->ip_va = s->rb_va + len;
+	} else {
+		/* shadow batch buffer */
+		ASSERT(0);
+	}
+}
+
+static inline int ip_gma_set(struct parser_exec_state *s, unsigned long ip_gma)
+{
+	ASSERT(!(ip_gma & (4 - 1)));
+
+	s->ip_gma = ip_gma;
+
+	update_ip_va(s);
+
+	return 0;
+}
+
+static inline int ip_gma_advance(struct parser_exec_state *s, unsigned int dw_len)
+{
+	int rc = 0;
+
+	s->ip_gma += (dw_len << 2);
+
+	if (s->buf_type == RING_BUFFER_INSTRUCTION) {
+		/* cross page, reset ip_va */
+		if (s->ip_gma >= s->ring_start + s->ring_size) {
+			s->ip_gma -= s->ring_size;
+		}
+	}
+
+	update_ip_va(s);
+
+	return rc;
+}
+
+static inline int get_cmd_length(struct cmd_info *info, u32 cmd)
+{
+	/*
+	 * MI_NOOP is special as the replacement elements. It's fixed
+	 * length in definition, but variable length when using for
+	 * replacement purpose. Instead of having the same handler
+	 * invoke twice (may be postponed), special case length
+	 * handling for MI_NOOP.
+	 */
+	if (info->opcode == OP_MI_NOOP) {
+		unsigned int subop, length = info->len;
+		subop = (cmd & GVT_NOOP_ID_CMD_MASK) >>
+			GVT_NOOP_ID_CMD_SHIFT;
+		if (subop)
+			length = cmd & CMD_LENGTH_MASK;
+
+		return length;
+	} else if ((info->flag & F_LEN_MASK) == F_LEN_CONST) {
+		return info->len;
+	} else /* F_LEN_VAR */{
+		return (cmd & ((1U << info->len) - 1)) + 2;
+	}
+}
+
+static inline int cmd_length(struct parser_exec_state *s)
+{
+	return get_cmd_length(s->info, cmd_val(s, 0));
+}
+
+/* do not remove this, some platform may need clflush here */
+#define patch_value(s, addr, val) do {\
+	*addr = val; \
+}while(0);
+
+static bool addr_audit_32(struct parser_exec_state *s, int index)
+{
+	/* TODO:
+	 * Add the address audit implementation here. Right now do nothing
+	 */
+	return true;
+}
+
+static inline bool address_audit(struct parser_exec_state *s, int index)
+{
+	int gmadr_bytes = s->vgt->pdev->device_info.gmadr_bytes_in_cmd;
+
+	/* TODO:
+	 * Add the address audit implementation here. Right now do nothing
+	 */
+	ASSERT(gmadr_bytes == 4 || gmadr_bytes == 8);
+
+	return true;
+}
+
+/*
+ * Actually, we don't like to emulate register behavior in LRI handlers,
+ * But DE_RRMR is an exception, even we can modify i915 to access
+ * DE_RRMR via MMIO, the 2D driver will also access it via submitted
+ * batch buffer.
+ *
+ * So we have no choice and have to handle it here, as windows is
+ * using deferred filp from gen8+, MI_DISPLAY_FLIP and MI_WAIT_FOR_EVENT
+ * will not be in the same submission. If a i915 submission modify
+ * DE_RRMR after the filp submission, the wait submission of windows
+ * will hang as the needed events are disabled by i915. Only modify i915
+ * will not work, as 2D driver(xf86-video-intel) also modify it directly.
+ * */
+
+static int cmd_handler_lri_de_rrmr(struct parser_exec_state *s)
+{
+
+	int i;
+	int cmd_len = cmd_length(s);
+	unsigned long offset;
+	unsigned long val;
+
+	for (i = 1; i < cmd_len; i += 2) {
+		offset = cmd_val(s, i) & BIT_RANGE_MASK(22, 2);
+		val = cmd_val(s, i + 1);
+
+		if (offset == _DERRMR)
+			break;
+	}
+
+	if (i == cmd_len) {
+		gvt_err("No DE_RRMR in LRI?");
+		return -EINVAL;
+	}
+
+	patch_value(s, cmd_ptr(s, i), 0);
+	patch_value(s, cmd_ptr(s, i + 1), 0);
+	return 0;
+}
+
+static bool is_shadowed_mmio(unsigned int offset)
+{
+	bool ret = false;
+	if ((offset == 0x2168) || /*BB current head register UDW */
+	    (offset == 0x2140) || /*BB current header register */
+	    (offset == 0x211c) || /*second BB header register UDW */
+	    (offset == 0x2114)) { /*second BB header register UDW */
+		ret = true;
+	}
+
+	return ret;
+}
+
+static int cmd_reg_handler(struct parser_exec_state *s,
+	unsigned int offset, unsigned int index, char *cmd)
+{
+	struct vgt_device *vgt = s->vgt;
+	struct pgt_device *pdev = vgt->pdev;
+	int rc = -1;
+
+	if (!reg_is_mmio(pdev, offset + 4)){
+		rc = -1;
+		goto reg_handle;
+	}
+
+	if (is_shadowed_mmio(offset)) {
+		gvt_warn("VM-%d: !!! Found access of shadowed MMIO<0x%x>!",
+			 s->vgt->vm_id, offset);
+	}
+
+reg_handle:
+	if (!rc)
+		reg_set_cmd_access(pdev, offset);
+	else {
+		gvt_err("%s access to non-render register (%x)", cmd, offset);
+	}
+
+	return 0;
+}
+
+static int gvt_cmd_handler_lri(struct parser_exec_state *s)
+{
+	unsigned long offset;
+	int i, rc = 0;
+	int cmd_len = cmd_length(s);
+
+	for (i = 1; i < cmd_len; i += 2) {
+		offset = cmd_val(s, i) & BIT_RANGE_MASK(22, 2);
+		rc |= cmd_reg_handler(s, offset, i, "lri");
+
+		if (IS_BROADWELL(s->vgt->pdev->dev_priv) && offset == _DERRMR) {
+			rc = cmd_handler_lri_de_rrmr(s);
+			if (rc) {
+				gvt_err("fail to handle lri de rrmr case");
+				break;
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int gvt_cmd_handler_lrr(struct parser_exec_state *s)
+{
+	int i, rc = 0;
+	int cmd_len = cmd_length(s);
+
+	for (i = 1; i < cmd_len; i += 2) {
+		rc = cmd_reg_handler(s,
+			cmd_val(s, i) & BIT_RANGE_MASK(22, 2), i, "lrr-src");
+		rc |= cmd_reg_handler(s,
+			cmd_val(s, i+1) & BIT_RANGE_MASK(22, 2), i, "lrr-dst");
+	}
+
+	return rc;
+}
+
+static int gvt_cmd_handler_lrm(struct parser_exec_state *s)
+{
+	int i, rc = 0;
+	int cmd_len = cmd_length(s);
+
+	for (i = 1; i < cmd_len;) {
+		rc |= cmd_reg_handler(s,
+			cmd_val(s, i) & BIT_RANGE_MASK(22, 2), i, "lrm");
+		i += gmadr_dw_number(s) + 1;
+	}
+
+	return rc;
+}
+
+static int gvt_cmd_handler_srm(struct parser_exec_state *s)
+{
+	int i, rc = 0;
+	int cmd_len = cmd_length(s);
+
+	for (i = 1; i < cmd_len;) {
+		rc |= cmd_reg_handler(s,
+			cmd_val(s, i) & BIT_RANGE_MASK(22, 2), i, "srm");
+		i += gmadr_dw_number(s) + 1;
+	}
+
+	return rc;
+}
+
+static int gvt_cmd_handler_pipe_control(struct parser_exec_state *s)
+{
+	int i, rc = 0;
+	int cmd_len = cmd_length(s);
+
+
+	for (i = 1; i < cmd_len;) {
+		if (cmd_val(s, i) & PIPE_CONTROL_MMIO_WRITE)
+			rc |= cmd_reg_handler(s,
+				cmd_val(s, i+1) & BIT_RANGE_MASK(22, 2), i, "pipe_ctrl");
+		else if (cmd_val(s, i) & (2 << 14))
+			rc |= cmd_reg_handler(s, 0x2350, i, "pipe_ctrl");
+		else if (cmd_val(s, i) & (3 << 14))
+			rc |= cmd_reg_handler(s, _REG_RCS_TIMESTAMP, i, "pipe_ctrl");
+
+		if (!rc) {
+			if (cmd_val(s, i) & PIPE_CONTROL_NOTIFY) {
+				set_bit(gvt_ring_id_to_pipe_control_notify_event(s->ring_id),
+					s->workload->pending_events);
+			}
+		}
+		i += gmadr_dw_number(s) + 3;
+	}
+
+	return rc;
+}
+
+static int gvt_cmd_handler_mi_user_interrupt(struct parser_exec_state *s)
+{
+	set_bit(gvt_ring_id_to_mi_user_interrupt_event(s->ring_id), s->workload->pending_events);
+	return 0;
+}
+
+static int gvt_cmd_handler_mi_batch_buffer_end(struct parser_exec_state *s)
+{
+	int rc;
+
+	if (s->buf_type == BATCH_BUFFER_2ND_LEVEL) {
+		s->buf_type = BATCH_BUFFER_INSTRUCTION;
+		rc = ip_gma_set(s, s->ret_ip_gma_bb);
+		s->buf_addr_type = s->saved_buf_addr_type;
+	} else {
+		s->buf_type = RING_BUFFER_INSTRUCTION;
+		s->buf_addr_type = GTT_BUFFER;
+		rc = ip_gma_set(s, s->ret_ip_gma_ring);
+	}
+
+	return rc;
+}
+
+#define PLANE_SELECT_SHIFT	19
+#define PLANE_SELECT_MASK	(0x7 << PLANE_SELECT_SHIFT)
+#define SURF_MASK		0xFFFFF000
+#define PITCH_MASK		0x0000FFC0
+#define TILE_PARA_SHIFT		0x0
+#define TILE_PARA_MASK		0x1
+/* Primary plane and sprite plane has the same tile shift in control reg */
+#define PLANE_TILE_SHIFT	_PRI_PLANE_TILE_SHIFT
+#define PLANE_TILE_MASK		(0x1 << PLANE_TILE_SHIFT)
+#define FLIP_TYPE_MASK		0x3
+
+#define DISPLAY_FLIP_PLANE_A  0x0
+#define DISPLAY_FLIP_PLANE_B  0x1
+#define DISPLAY_FLIP_SPRITE_A  0x2
+#define DISPLAY_FLIP_SPRITE_B  0x3
+#define DISPLAY_FLIP_PLANE_C  0x4
+#define DISPLAY_FLIP_SPRITE_C  0x5
+
+/* The NOOP for MI_DISPLAY_FLIP has below information stored in NOOP_ID:
+ *
+ *	bit 21 - bit 16 is 0x14, opcode of MI_DISPLAY_FLIP;
+ *	bit 10 - bit 8  is plane select;
+ *	bit 7  - bit 0  is the cmd length
+ */
+#define PLANE_INFO_SHIFT	8
+#define PLANE_INFO_MASK		(0x7 << PLANE_INFO_SHIFT)
+
+static bool display_flip_decode_plane_info(u32  plane_code, enum pipe *pipe, enum gvt_plane_type *plane )
+{
+	switch (plane_code) {
+		case DISPLAY_FLIP_PLANE_A:
+			*pipe = PIPE_A;
+			*plane = PRIMARY_PLANE;
+			break;
+		case DISPLAY_FLIP_PLANE_B:
+			*pipe = PIPE_B;
+			*plane = PRIMARY_PLANE;
+			break;
+		case DISPLAY_FLIP_SPRITE_A:
+			*pipe = PIPE_A;
+			*plane = SPRITE_PLANE;
+			break;
+		case DISPLAY_FLIP_SPRITE_B:
+			*pipe = PIPE_B;
+			*plane = SPRITE_PLANE;
+			break;
+		case DISPLAY_FLIP_PLANE_C:
+			*pipe = PIPE_C;
+			*plane = PRIMARY_PLANE;
+			break;
+		case DISPLAY_FLIP_SPRITE_C:
+			*pipe = PIPE_C;
+			*plane = SPRITE_PLANE;
+			break;
+		default:
+			return false;
+	}
+
+	return true;
+
+}
+
+#define GET_INFO_FOR_FLIP(pipe, plane, 					\
+			ctrl_reg, surf_reg, stride_reg, stride_mask)	\
+do{									\
+	if (plane == PRIMARY_PLANE) {					\
+		ctrl_reg = GVT_DSPCNTR(pipe);				\
+		surf_reg = GVT_DSPSURF(pipe);				\
+		stride_reg = GVT_DSPSTRIDE(pipe);			\
+		stride_mask = _PRI_PLANE_STRIDE_MASK;			\
+	} else {							\
+		ASSERT (plane == SPRITE_PLANE);				\
+		ctrl_reg = GVT_SPRCTL(pipe);				\
+		surf_reg = GVT_SPRSURF(pipe);				\
+		stride_reg = GVT_SPRSTRIDE(pipe);			\
+		stride_mask = _SPRITE_STRIDE_MASK;			\
+	}								\
+}while(0);
+
+static bool gvt_flip_parameter_check(struct parser_exec_state *s,
+				u32 plane_code,
+				u32 stride_val,
+				u32 surf_val)
+{
+	enum pipe pipe = I915_MAX_PIPES;
+	enum gvt_plane_type plane = MAX_PLANE;
+	u32 surf_reg, ctrl_reg;
+	u32 stride_reg, stride_mask, phys_stride;
+	u32 tile_para, tile_in_ctrl;
+	bool async_flip;
+
+	if (!display_flip_decode_plane_info(plane_code, &pipe, &plane))
+		return false;
+
+	GET_INFO_FOR_FLIP(pipe, plane, ctrl_reg, surf_reg, stride_reg, stride_mask);
+
+	async_flip = ((surf_val & FLIP_TYPE_MASK) == 0x1);
+	tile_para = ((stride_val & TILE_PARA_MASK) >> TILE_PARA_SHIFT);
+	tile_in_ctrl = (__vreg(s->vgt, ctrl_reg) & PLANE_TILE_MASK)
+				>> PLANE_TILE_SHIFT;
+
+	phys_stride = __vreg(s->vgt, stride_reg);
+
+	if ((__vreg(s->vgt, stride_reg) & stride_mask)
+		!= (stride_val & PITCH_MASK)) {
+
+		if (async_flip) {
+			gvt_warn("Cannot change stride in async flip!");
+			return false;
+		}
+	}
+
+	if (tile_para != tile_in_ctrl) {
+
+		if (async_flip) {
+			gvt_warn("Cannot change tiling in async flip!");
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static int gvt_handle_mi_display_flip(struct parser_exec_state *s)
+{
+	u32 surf_reg, surf_val, ctrl_reg;
+	u32 stride_reg, stride_val, stride_mask;
+	u32 tile_para;
+	u32 opcode, plane_code;
+	enum pipe pipe;
+	enum gvt_plane_type plane;
+	int length, rc = 0;
+	struct gvt_fb_notify_msg msg;
+	int i;
+
+	opcode = cmd_val(s, 0);
+	stride_val = cmd_val(s, 1);
+	surf_val = cmd_val(s, 2);
+
+	plane_code = (opcode & PLANE_SELECT_MASK) >> PLANE_SELECT_SHIFT;
+	length = cmd_length(s);
+
+	if (!display_flip_decode_plane_info(plane_code, &pipe, &plane)) {
+		goto wrong_command;
+	}
+
+	if (length == 4) {
+		gvt_warn("Page flip of Stereo 3D is not supported!");
+		goto wrong_command;
+	} else if (length != 3) {
+		gvt_warn("Flip length not equal to 3, ignore handling flipping");
+		goto wrong_command;
+	}
+
+	if ((pipe == I915_MAX_PIPES) || (plane == MAX_PLANE)) {
+		gvt_warn("Invalid pipe/plane in MI_DISPLAY_FLIP!");
+		goto wrong_command;
+	}
+
+	if (!gvt_flip_parameter_check(s, plane_code, stride_val, surf_val))
+		goto wrong_command;
+
+	GET_INFO_FOR_FLIP(pipe, plane,
+			ctrl_reg, surf_reg, stride_reg, stride_mask);
+	tile_para = ((stride_val & TILE_PARA_MASK) >> TILE_PARA_SHIFT);
+
+	__vreg(s->vgt, stride_reg) = (stride_val & stride_mask) |
+		(__vreg(s->vgt, stride_reg) & (~stride_mask));
+	__vreg(s->vgt, ctrl_reg) = (tile_para << PLANE_TILE_SHIFT) |
+		(__vreg(s->vgt, ctrl_reg) & (~PLANE_TILE_MASK));
+	__vreg(s->vgt, surf_reg) = (surf_val & SURF_MASK) |
+		(__vreg(s->vgt, surf_reg) & (~SURF_MASK));
+	__sreg(s->vgt, stride_reg) = __vreg(s->vgt, stride_reg);
+	__sreg(s->vgt, ctrl_reg) = __vreg(s->vgt, ctrl_reg);
+	__sreg(s->vgt, surf_reg) = __vreg(s->vgt, surf_reg);
+
+	__vreg(s->vgt, GVT_PIPE_FLIPCOUNT(pipe))++;
+
+	msg.vm_id = s->vgt->vm_id;
+	msg.pipe_id = pipe;
+	msg.plane_id = plane;
+	gvt_fb_notifier_call_chain(FB_DISPLAY_FLIP, &msg);
+
+	gvt_dbg_cmd("VM %d: mi_display_flip to be ignored",
+			s->vgt->vm_id);
+
+	for (i = 0; i < length; i ++)
+		patch_value(s, cmd_ptr(s, i), MI_NOOP);
+
+	gvt_inject_flip_done(s->vgt, pipe);
+
+	return rc;
+
+wrong_command:
+	for (i = 0; i < length; i ++)
+		patch_value(s, cmd_ptr(s, i), MI_NOOP);
+	return rc;
+}
+
+static int gvt_cmd_handler_mi_display_flip(struct parser_exec_state *s)
+{
+	addr_audit_32(s, 2);
+	return gvt_handle_mi_display_flip(s);
+}
+
+static bool is_wait_for_flip_pending(u32 cmd)
+{
+	return cmd & (MI_WAIT_FOR_PLANE_A_FLIP_PENDING |
+		MI_WAIT_FOR_PLANE_B_FLIP_PENDING |
+		MI_WAIT_FOR_PLANE_C_FLIP_PENDING |
+		MI_WAIT_FOR_SPRITE_A_FLIP_PENDING |
+		MI_WAIT_FOR_SPRITE_B_FLIP_PENDING |
+		MI_WAIT_FOR_SPRITE_C_FLIP_PENDING);
+}
+
+static int gvt_cmd_handler_mi_wait_for_event(struct parser_exec_state *s)
+{
+	int rc = 0;
+	u32 cmd = cmd_val(s, 0);
+
+	if (!is_wait_for_flip_pending(cmd))
+		return rc;
+
+	patch_value(s, cmd_ptr(s, 0), MI_NOOP);
+	return rc;
+}
+
+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->vgt->pdev->device_info.gmadr_bytes_in_cmd;
+
+	ASSERT(gmadr_bytes == 4 || gmadr_bytes == 8);
+
+	gma_low = cmd_val(s, index) & BATCH_BUFFER_ADDR_MASK;
+
+	if (gmadr_bytes == 4) {
+		addr = gma_low;
+	} else {
+		gma_high = cmd_val(s, index + 1) & BATCH_BUFFER_ADDR_HIGH_MASK;
+		addr = (((unsigned long)gma_high) << 32) | gma_low;
+	}
+
+	return addr;
+}
+
+static inline bool gvt_cmd_addr_audit_with_bitmap(struct parser_exec_state *s,
+			unsigned long addr_bitmap)
+{
+	unsigned int bit;
+	unsigned int delta = 0;
+	int cmd_len = cmd_length(s);
+
+	if (!addr_bitmap)
+		return true;
+
+	for_each_set_bit(bit, &addr_bitmap, sizeof(addr_bitmap)*8) {
+		if (bit + delta >= cmd_len)
+			return false;
+		address_audit(s, bit + delta);
+		delta = delta + gmadr_dw_number(s) - 1;
+	}
+
+	return true;
+}
+
+static int gvt_cmd_handler_mi_update_gtt(struct parser_exec_state *s)
+{
+	gvt_err("Unexpectted mi_update_gtt in VM command buffer");
+	return -1;
+}
+
+static int gvt_cmd_handler_mi_flush_dw(struct parser_exec_state *s)
+{
+	int i, len;
+	int offset = 1;
+
+	/* Check post-sync bit */
+	if ((cmd_val(s, 0) >> 14) & 0x3)
+		address_audit(s, offset);
+	offset += gmadr_dw_number(s);
+
+	/* Check notify bit */
+	if ((cmd_val(s,0) & (1 << 8)))
+		set_bit(gvt_ring_id_to_mi_flush_dw_event(s->ring_id), s->workload->pending_events);
+
+	len = cmd_length(s);
+	for (i = 2; i < len; i++) {
+		address_audit(s, offset);
+		offset += gmadr_dw_number(s);
+	}
+
+	return 0;
+}
+
+static void addr_type_update_snb(struct parser_exec_state* s)
+{
+	if ((s->buf_type == RING_BUFFER_INSTRUCTION) &&
+			(BATCH_BUFFER_ADR_SPACE_BIT(cmd_val(s, 0)) == 1)) {
+		s->buf_addr_type = PPGTT_BUFFER;
+	}
+}
+
+/*
+ * Check whether a batch buffer needs to be scanned. Currently
+ * the only criteria is based on privilege.
+ */
+static int batch_buffer_needs_scan(struct parser_exec_state *s)
+{
+	struct pgt_device *pdev = s->vgt->pdev;
+
+	return 0;
+
+	if (IS_BROADWELL(pdev->dev_priv)) {
+		if (s->ring_id == BCS)
+			return 0;
+		/* BDW decides privilege based on address space */
+		if (cmd_val(s, 0) & (1 << 8))
+			return 0;
+	}
+
+	return 1;
+}
+
+static int gvt_cmd_handler_mi_batch_buffer_start(struct parser_exec_state *s)
+{
+	int rc = 0;
+	bool second_level;
+
+	if (s->buf_type == BATCH_BUFFER_2ND_LEVEL) {
+		gvt_err("MI_BATCH_BUFFER_START not allowd in 2nd level batch buffer");
+		return -EINVAL;
+	}
+
+	second_level = BATCH_BUFFER_2ND_LEVEL_BIT(cmd_val(s, 0)) == 1;
+	if (second_level && (s->buf_type != BATCH_BUFFER_INSTRUCTION)) {
+		gvt_err("Jumping to 2nd level batch buffer from ring buffer is not allowd");
+		return -EINVAL;
+	}
+
+	s->saved_buf_addr_type = s->buf_addr_type;
+
+	addr_type_update_snb(s);
+
+	if (s->buf_type == RING_BUFFER_INSTRUCTION) {
+		s->ret_ip_gma_ring = s->ip_gma + cmd_length(s) * sizeof(u32);
+		s->buf_type = BATCH_BUFFER_INSTRUCTION;
+	} else if (second_level) {
+		s->buf_type = BATCH_BUFFER_2ND_LEVEL;
+		s->ret_ip_gma_bb = s->ip_gma + cmd_length(s) * sizeof(u32);
+	}
+
+	address_audit(s, 1);
+
+	if (batch_buffer_needs_scan(s)) {
+		rc = ip_gma_set(s, get_gma_bb_from_cmd(s, 1));
+		if (rc < 0)
+			gvt_warn("invalid batch buffer addr, so skip scanning it");
+	} else {
+		struct gvt_statistics *stat = &s->vgt->stat;
+
+		stat->skip_bb_cnt++;
+		/* emulate a batch buffer end to do return right */
+		rc = gvt_cmd_handler_mi_batch_buffer_end(s);
+		if (rc < 0)
+			gvt_err("skip batch buffer error");
+	}
+
+	return rc;
+}
+
+static int gvt_cmd_handler_3dstate_vertex_buffers(struct parser_exec_state *s)
+{
+	int length, offset;
+
+	length = cmd_length(s);
+
+	for (offset = 1; offset < length; offset += 4) {
+		address_audit(s, offset + 1);
+		address_audit(s, offset + 2);
+	}
+
+	return 0;
+}
+
+static int gvt_cmd_handler_3dstate_vertex_buffers_bdw(struct parser_exec_state *s)
+{
+	int length, offset;
+
+	length = cmd_length(s);
+
+	for (offset = 1; offset < length; offset += 4) {
+		address_audit(s, offset + 1);
+	}
+
+	return 0;
+}
+
+static int gvt_cmd_handler_3dstate_index_buffer(struct parser_exec_state *s)
+{
+	address_audit(s, 1);
+
+	if (cmd_val(s, 2) != 0)
+		address_audit(s, 2);
+
+	return 0;
+}
+
+static int gvt_cmd_handler_3dstate_constant(struct parser_exec_state *s)
+{
+	int offset = 3;
+	int cmd_len = cmd_length(s);
+
+	while (offset < cmd_len) {
+		address_audit(s, offset);
+		offset += gmadr_dw_number(s);
+	}
+
+	return 0;
+}
+
+static int gvt_cmd_handler_mfx_pipe_buf_addr_state(struct parser_exec_state *s)
+{
+	/*  address pattern of the command is like below:
+	 *  from bit0: "01010101 01010111 11111111 11111010 1010"
+	 */
+	gvt_cmd_addr_audit_with_bitmap(s, 0x055fffeaaaUL);
+
+	return 0;
+}
+
+static int gvt_cmd_handler_mfx_ind_obj_base_addr_state(struct parser_exec_state *s)
+{
+	/*  address pattern of the command is like below:
+	 *  from bit0: "10110110 11011010"
+	 */
+	gvt_cmd_addr_audit_with_bitmap(s, 0x5b6d);
+
+	return 0;
+}
+
+static inline int base_and_upper_addr_fix(struct parser_exec_state *s)
+{
+	address_audit(s, 1);
+	/* Zero Bound is ignore */
+	if (cmd_val(s, 2) >> 12)
+		address_audit(s, 2);
+	return 0;
+}
+
+static int gvt_cmd_handler_mfx_2_6_0_0(struct parser_exec_state *s)
+{
+	base_and_upper_addr_fix(s);
+	address_audit(s, 2);
+	return 0;
+}
+
+static struct cmd_info cmd_info[] = {
+	{"MI_NOOP", OP_MI_NOOP, F_LEN_CONST|F_POST_HANDLE, R_ALL, D_ALL, 0, 1, NULL},
+
+	{"MI_SET_PREDICATE", OP_MI_SET_PREDICATE, F_LEN_CONST, R_ALL, D_ALL,
+		0, 1, NULL},
+
+	{"MI_USER_INTERRUPT", OP_MI_USER_INTERRUPT, F_LEN_CONST, R_ALL, D_ALL, 0, 1, gvt_cmd_handler_mi_user_interrupt},
+
+	{"MI_WAIT_FOR_EVENT", OP_MI_WAIT_FOR_EVENT, F_LEN_CONST | F_POST_HANDLE, R_RCS | R_BCS,
+		D_ALL, 0, 1, gvt_cmd_handler_mi_wait_for_event},
+
+	{"MI_FLUSH", OP_MI_FLUSH, F_LEN_CONST, R_ALL, D_ALL, 0, 1, NULL},
+
+	{"MI_ARB_CHECK", OP_MI_ARB_CHECK, F_LEN_CONST, R_ALL, D_ALL, 0, 1, NULL},
+
+	{"MI_RS_CONTROL", OP_MI_RS_CONTROL, F_LEN_CONST, R_RCS, D_ALL, 0, 1, NULL},
+
+	{"MI_REPORT_HEAD", OP_MI_REPORT_HEAD, F_LEN_CONST, R_ALL, D_ALL, 0, 1, NULL},
+
+	{"MI_ARB_ON_OFF", OP_MI_ARB_ON_OFF, F_LEN_CONST, R_ALL, D_ALL, 0, 1, NULL},
+
+	{"MI_URB_ATOMIC_ALLOC", OP_MI_URB_ATOMIC_ALLOC, F_LEN_CONST, R_RCS,
+		D_ALL, 0, 1, NULL},
+
+	{"MI_BATCH_BUFFER_END", OP_MI_BATCH_BUFFER_END, F_IP_ADVANCE_CUSTOM|F_LEN_CONST,
+		R_ALL, D_ALL, 0, 1, gvt_cmd_handler_mi_batch_buffer_end},
+
+	{"MI_SUSPEND_FLUSH", OP_MI_SUSPEND_FLUSH, F_LEN_CONST, R_ALL, D_ALL, 0, 1, NULL},
+
+	{"MI_PREDICATE", OP_MI_PREDICATE, F_LEN_CONST, R_RCS, D_ALL, 0, 1, NULL},
+
+	{"MI_TOPOLOGY_FILTER", OP_MI_TOPOLOGY_FILTER, F_LEN_CONST, R_ALL,
+		D_ALL, 0, 1, NULL},
+
+	{"MI_SET_APPID", OP_MI_SET_APPID, F_LEN_CONST, R_ALL, D_ALL, 0, 1, NULL},
+
+	{"MI_RS_CONTEXT", OP_MI_RS_CONTEXT, F_LEN_CONST, R_RCS, D_ALL, 0, 1, NULL},
+
+	{"MI_DISPLAY_FLIP", OP_MI_DISPLAY_FLIP, F_LEN_VAR|F_POST_HANDLE, R_RCS | R_BCS,
+		D_ALL, 0, 8, gvt_cmd_handler_mi_display_flip},
+
+	{"MI_SEMAPHORE_MBOX", OP_MI_SEMAPHORE_MBOX, F_LEN_VAR, R_ALL, D_ALL, 0, 8, NULL },
+
+	{"MI_MATH", OP_MI_MATH, F_LEN_VAR, R_ALL, D_ALL, 0, 8, NULL},
+
+	{"MI_URB_CLEAR", OP_MI_URB_CLEAR, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"ME_SEMAPHORE_SIGNAL", OP_MI_SEMAPHORE_SIGNAL, F_LEN_VAR, R_ALL, D_BDW, 0, 8, NULL},
+
+	{"ME_SEMAPHORE_WAIT", OP_MI_SEMAPHORE_WAIT, F_LEN_VAR, R_ALL, D_BDW, ADDR_FIX_1(2), 8, NULL},
+
+	{"MI_STORE_DATA_IMM", OP_MI_STORE_DATA_IMM, F_LEN_VAR, R_ALL, D_BDW,
+		ADDR_FIX_1(1), 10, NULL},
+
+	{"MI_STORE_DATA_INDEX", OP_MI_STORE_DATA_INDEX, F_LEN_VAR, R_ALL, D_ALL,
+		0, 8, NULL},
+
+	{"MI_LOAD_REGISTER_IMM", OP_MI_LOAD_REGISTER_IMM, F_LEN_VAR, R_ALL, D_ALL, 0, 8, gvt_cmd_handler_lri},
+
+	{"MI_UPDATE_GTT", OP_MI_UPDATE_GTT, F_LEN_VAR, R_ALL, D_BDW,
+		0, 10, gvt_cmd_handler_mi_update_gtt},
+
+	{"MI_STORE_REGISTER_MEM", OP_MI_STORE_REGISTER_MEM, F_LEN_VAR, R_ALL, D_ALL,
+		ADDR_FIX_1(2), 8, gvt_cmd_handler_srm},
+
+	{"MI_FLUSH_DW", OP_MI_FLUSH_DW, F_LEN_VAR, R_ALL, D_ALL,
+		0, 6, gvt_cmd_handler_mi_flush_dw},
+
+	{"MI_CLFLUSH", OP_MI_CLFLUSH, F_LEN_VAR, R_ALL, D_ALL,
+		ADDR_FIX_1(1), 10, NULL},
+
+	{"MI_REPORT_PERF_COUNT", OP_MI_REPORT_PERF_COUNT, F_LEN_VAR, R_ALL, D_ALL,
+		ADDR_FIX_1(1), 6, NULL},
+
+	{"MI_LOAD_REGISTER_MEM", OP_MI_LOAD_REGISTER_MEM, F_LEN_VAR, R_ALL, D_ALL,
+		ADDR_FIX_1(2), 8, gvt_cmd_handler_lrm},
+
+	{"MI_LOAD_REGISTER_REG", OP_MI_LOAD_REGISTER_REG, F_LEN_VAR, R_ALL, D_ALL,
+		0, 8, gvt_cmd_handler_lrr},
+
+	{"MI_RS_STORE_DATA_IMM", OP_MI_RS_STORE_DATA_IMM, F_LEN_VAR, R_RCS, D_ALL,
+		0, 8, NULL},
+
+	{"MI_LOAD_URB_MEM", OP_MI_LOAD_URB_MEM, F_LEN_VAR, R_RCS, D_ALL,
+		ADDR_FIX_1(2), 8, NULL},
+
+	{"MI_STORE_URM_MEM", OP_MI_STORE_URM_MEM, F_LEN_VAR, R_RCS, D_ALL,
+		ADDR_FIX_1(2), 8, NULL},
+
+	{"MI_OP_2E", OP_MI_2E, F_LEN_VAR, R_ALL, D_BDW, ADDR_FIX_2(1, 2), 8, NULL},
+
+	{"MI_OP_2F", OP_MI_2F, F_LEN_VAR, R_ALL, D_BDW, ADDR_FIX_1(1), 8, NULL},
+
+	{"MI_BATCH_BUFFER_START", OP_MI_BATCH_BUFFER_START, F_IP_ADVANCE_CUSTOM,
+		R_ALL, D_ALL, 0, 8, gvt_cmd_handler_mi_batch_buffer_start},
+
+	{"MI_CONDITIONAL_BATCH_BUFFER_END", OP_MI_CONDITIONAL_BATCH_BUFFER_END,
+		F_LEN_VAR, R_ALL, D_ALL, ADDR_FIX_1(2), 8, NULL},
+
+	{"MI_LOAD_SCAN_LINES_INCL", OP_MI_LOAD_SCAN_LINES_INCL, F_LEN_CONST, R_RCS | R_BCS, D_ALL,
+		0, 2, NULL},
+
+	{"XY_SETUP_BLT", OP_XY_SETUP_BLT, F_LEN_VAR, R_BCS, D_ALL,
+		ADDR_FIX_2(4, 7), 8, NULL},
+
+	{"XY_SETUP_CLIP_BLT", OP_XY_SETUP_CLIP_BLT, F_LEN_VAR, R_BCS, D_ALL,
+		0, 8, NULL},
+
+	{"XY_SETUP_MONO_PATTERN_SL_BLT", OP_XY_SETUP_MONO_PATTERN_SL_BLT, F_LEN_VAR,
+		R_BCS, D_ALL, ADDR_FIX_1(4), 8, NULL},
+
+	{"XY_PIXEL_BLT", OP_XY_PIXEL_BLT, F_LEN_VAR, R_BCS, D_ALL, 0, 8, NULL},
+
+	{"XY_SCANLINES_BLT", OP_XY_SCANLINES_BLT, F_LEN_VAR, R_BCS, D_ALL,
+		0, 8, NULL},
+
+	{"XY_TEXT_BLT", OP_XY_TEXT_BLT, F_LEN_VAR, R_BCS, D_ALL,
+		ADDR_FIX_1(3), 8, NULL},
+
+	{"XY_TEXT_IMMEDIATE_BLT", OP_XY_TEXT_IMMEDIATE_BLT, F_LEN_VAR, R_BCS,
+		D_ALL, 0, 8, NULL},
+
+	{"XY_COLOR_BLT", OP_XY_COLOR_BLT, F_LEN_VAR, R_BCS, D_ALL,
+		ADDR_FIX_1(4), 8, NULL},
+
+	{"XY_PAT_BLT", OP_XY_PAT_BLT, F_LEN_VAR, R_BCS, D_ALL,
+		ADDR_FIX_2(4, 5), 8, NULL},
+
+	{"XY_MONO_PAT_BLT", OP_XY_MONO_PAT_BLT, F_LEN_VAR, R_BCS, D_ALL,
+		ADDR_FIX_1(4), 8, NULL},
+
+	{"XY_SRC_COPY_BLT", OP_XY_SRC_COPY_BLT, F_LEN_VAR, R_BCS, D_ALL,
+		ADDR_FIX_2(4, 7), 8, NULL},
+
+	{"XY_MONO_SRC_COPY_BLT", OP_XY_MONO_SRC_COPY_BLT, F_LEN_VAR, R_BCS,
+		D_ALL, ADDR_FIX_2(4, 5), 8, NULL},
+
+	{"XY_FULL_BLT", OP_XY_FULL_BLT, F_LEN_VAR, R_BCS, D_ALL, 0, 8, NULL},
+
+	{"XY_FULL_MONO_SRC_BLT", OP_XY_FULL_MONO_SRC_BLT, F_LEN_VAR, R_BCS, D_ALL,
+		ADDR_FIX_3(4, 5, 8), 8, NULL},
+
+	{"XY_FULL_MONO_PATTERN_BLT", OP_XY_FULL_MONO_PATTERN_BLT, F_LEN_VAR,
+		R_BCS, D_ALL, ADDR_FIX_2(4, 7), 8, NULL},
+
+	{"XY_FULL_MONO_PATTERN_MONO_SRC_BLT", OP_XY_FULL_MONO_PATTERN_MONO_SRC_BLT,
+		F_LEN_VAR, R_BCS, D_ALL, ADDR_FIX_2(4, 5), 8, NULL},
+
+	{"XY_MONO_PAT_FIXED_BLT", OP_XY_MONO_PAT_FIXED_BLT, F_LEN_VAR, R_BCS, D_ALL,
+		ADDR_FIX_1(4), 8, NULL},
+
+	{"XY_MONO_SRC_COPY_IMMEDIATE_BLT", OP_XY_MONO_SRC_COPY_IMMEDIATE_BLT,
+		F_LEN_VAR, R_BCS, D_ALL, ADDR_FIX_1(4), 8, NULL},
+
+	{"XY_PAT_BLT_IMMEDIATE", OP_XY_PAT_BLT_IMMEDIATE, F_LEN_VAR, R_BCS,
+		D_ALL, ADDR_FIX_1(4), 8, NULL},
+
+	{"XY_SRC_COPY_CHROMA_BLT", OP_XY_SRC_COPY_CHROMA_BLT, F_LEN_VAR, R_BCS,
+		D_ALL, ADDR_FIX_2(4, 7), 8, NULL},
+
+	{"XY_FULL_IMMEDIATE_PATTERN_BLT", OP_XY_FULL_IMMEDIATE_PATTERN_BLT,
+		F_LEN_VAR, R_BCS, D_ALL, ADDR_FIX_2(4, 7), 8, NULL},
+
+	{"XY_FULL_MONO_SRC_IMMEDIATE_PATTERN_BLT", OP_XY_FULL_MONO_SRC_IMMEDIATE_PATTERN_BLT,
+		F_LEN_VAR, R_BCS, D_ALL, ADDR_FIX_2(4, 5), 8, NULL},
+
+	{"XY_PAT_CHROMA_BLT", OP_XY_PAT_CHROMA_BLT, F_LEN_VAR, R_BCS, D_ALL,
+		ADDR_FIX_2(4, 5), 8, NULL},
+
+	{"XY_PAT_CHROMA_BLT_IMMEDIATE", OP_XY_PAT_CHROMA_BLT_IMMEDIATE, F_LEN_VAR,
+		R_BCS, D_ALL, ADDR_FIX_1(4), 8, NULL},
+
+	{"3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP", OP_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_VIEWPORT_STATE_POINTERS_CC", OP_3DSTATE_VIEWPORT_STATE_POINTERS_CC,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_BLEND_STATE_POINTERS", OP_3DSTATE_BLEND_STATE_POINTERS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_DEPTH_STENCIL_STATE_POINTERS", OP_3DSTATE_DEPTH_STENCIL_STATE_POINTERS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_BINDING_TABLE_POINTERS_VS", OP_3DSTATE_BINDING_TABLE_POINTERS_VS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_BINDING_TABLE_POINTERS_HS", OP_3DSTATE_BINDING_TABLE_POINTERS_HS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_BINDING_TABLE_POINTERS_DS", OP_3DSTATE_BINDING_TABLE_POINTERS_DS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_BINDING_TABLE_POINTERS_GS", OP_3DSTATE_BINDING_TABLE_POINTERS_GS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_BINDING_TABLE_POINTERS_PS", OP_3DSTATE_BINDING_TABLE_POINTERS_PS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_SAMPLER_STATE_POINTERS_VS", OP_3DSTATE_SAMPLER_STATE_POINTERS_VS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_SAMPLER_STATE_POINTERS_HS", OP_3DSTATE_SAMPLER_STATE_POINTERS_HS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_SAMPLER_STATE_POINTERS_DS", OP_3DSTATE_SAMPLER_STATE_POINTERS_DS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_SAMPLER_STATE_POINTERS_GS", OP_3DSTATE_SAMPLER_STATE_POINTERS_GS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_SAMPLER_STATE_POINTERS_PS", OP_3DSTATE_SAMPLER_STATE_POINTERS_PS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_URB_VS", OP_3DSTATE_URB_VS, F_LEN_VAR, R_RCS, D_ALL,
+		0, 8, NULL},
+
+	{"3DSTATE_URB_HS", OP_3DSTATE_URB_HS, F_LEN_VAR, R_RCS, D_ALL,
+		0, 8, NULL},
+
+	{"3DSTATE_URB_DS", OP_3DSTATE_URB_DS, F_LEN_VAR, R_RCS, D_ALL,
+		0, 8, NULL},
+
+	{"3DSTATE_URB_GS", OP_3DSTATE_URB_GS, F_LEN_VAR, R_RCS, D_ALL,
+		0, 8, NULL},
+
+	{"3DSTATE_GATHER_CONSTANT_VS", OP_3DSTATE_GATHER_CONSTANT_VS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_GATHER_CONSTANT_GS", OP_3DSTATE_GATHER_CONSTANT_GS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_GATHER_CONSTANT_HS", OP_3DSTATE_GATHER_CONSTANT_HS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_GATHER_CONSTANT_DS", OP_3DSTATE_GATHER_CONSTANT_DS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_GATHER_CONSTANT_PS", OP_3DSTATE_GATHER_CONSTANT_PS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_DX9_CONSTANTF_VS", OP_3DSTATE_DX9_CONSTANTF_VS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 11, NULL},
+
+	{"3DSTATE_DX9_CONSTANTF_PS", OP_3DSTATE_DX9_CONSTANTF_PS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 11, NULL},
+
+	{"3DSTATE_DX9_CONSTANTI_VS", OP_3DSTATE_DX9_CONSTANTI_VS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_DX9_CONSTANTI_PS", OP_3DSTATE_DX9_CONSTANTI_PS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_DX9_CONSTANTB_VS", OP_3DSTATE_DX9_CONSTANTB_VS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_DX9_CONSTANTB_PS", OP_3DSTATE_DX9_CONSTANTB_PS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_DX9_LOCAL_VALID_VS", OP_3DSTATE_DX9_LOCAL_VALID_VS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_DX9_LOCAL_VALID_PS", OP_3DSTATE_DX9_LOCAL_VALID_PS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_DX9_GENERATE_ACTIVE_VS", OP_3DSTATE_DX9_GENERATE_ACTIVE_VS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_DX9_GENERATE_ACTIVE_PS", OP_3DSTATE_DX9_GENERATE_ACTIVE_PS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_BINDING_TABLE_EDIT_VS", OP_3DSTATE_BINDING_TABLE_EDIT_VS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 9, NULL},
+
+	{"3DSTATE_BINDING_TABLE_EDIT_GS", OP_3DSTATE_BINDING_TABLE_EDIT_GS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 9, NULL},
+
+	{"3DSTATE_BINDING_TABLE_EDIT_HS", OP_3DSTATE_BINDING_TABLE_EDIT_HS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 9, NULL},
+
+	{"3DSTATE_BINDING_TABLE_EDIT_DS", OP_3DSTATE_BINDING_TABLE_EDIT_DS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 9, NULL},
+
+	{"3DSTATE_BINDING_TABLE_EDIT_PS", OP_3DSTATE_BINDING_TABLE_EDIT_PS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 9, NULL},
+
+	{"3DSTATE_VF_INSTANCING", OP_3DSTATE_VF_INSTANCING, F_LEN_VAR, R_RCS, D_BDW, 0, 8, NULL},
+
+	{"3DSTATE_VF_SGVS", OP_3DSTATE_VF_SGVS, F_LEN_VAR, R_RCS, D_BDW, 0, 8, NULL},
+
+	{"3DSTATE_VF_TOPOLOGY", OP_3DSTATE_VF_TOPOLOGY, F_LEN_VAR, R_RCS, D_BDW, 0, 8, NULL},
+
+	{"3DSTATE_WM_CHROMAKEY", OP_3DSTATE_WM_CHROMAKEY, F_LEN_VAR, R_RCS, D_BDW, 0, 8, NULL},
+
+	{"3DSTATE_PS_BLEND", OP_3DSTATE_PS_BLEND, F_LEN_VAR, R_RCS, D_BDW, 0, 8, NULL},
+
+	{"3DSTATE_WM_DEPTH_STENCIL", OP_3DSTATE_WM_DEPTH_STENCIL, F_LEN_VAR, R_RCS, D_BDW, 0, 8, NULL},
+
+	{"3DSTATE_PS_EXTRA", OP_3DSTATE_PS_EXTRA, F_LEN_VAR, R_RCS, D_BDW, 0, 8, NULL},
+
+	{"3DSTATE_RASTER", OP_3DSTATE_RASTER, F_LEN_VAR, R_RCS, D_BDW, 0, 8, NULL},
+
+	{"3DSTATE_SBE_SWIZ", OP_3DSTATE_SBE_SWIZ, F_LEN_VAR, R_RCS, D_BDW, 0, 8, NULL},
+
+	{"3DSTATE_WM_HZ_OP", OP_3DSTATE_WM_HZ_OP, F_LEN_VAR, R_RCS, D_BDW, 0, 8, NULL},
+
+	{"3DSTATE_VERTEX_BUFFERS", OP_3DSTATE_VERTEX_BUFFERS, F_LEN_VAR, R_RCS,
+		D_BDW, 0, 8, gvt_cmd_handler_3dstate_vertex_buffers_bdw},
+
+	{"3DSTATE_VERTEX_ELEMENTS", OP_3DSTATE_VERTEX_ELEMENTS, F_LEN_VAR, R_RCS,
+		D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_INDEX_BUFFER", OP_3DSTATE_INDEX_BUFFER, F_LEN_VAR, R_RCS,
+		D_BDW, ADDR_FIX_1(2), 8, NULL},
+
+	{"3DSTATE_VF_STATISTICS", OP_3DSTATE_VF_STATISTICS, F_LEN_CONST,
+		R_RCS, D_ALL, 0, 1, NULL},
+
+	{"3DSTATE_VF", OP_3DSTATE_VF, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_CC_STATE_POINTERS", OP_3DSTATE_CC_STATE_POINTERS, F_LEN_VAR,
+		R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_SCISSOR_STATE_POINTERS", OP_3DSTATE_SCISSOR_STATE_POINTERS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_GS", OP_3DSTATE_GS, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_CLIP", OP_3DSTATE_CLIP, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_WM", OP_3DSTATE_WM, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_CONSTANT_GS", OP_3DSTATE_CONSTANT_GS, F_LEN_VAR, R_RCS,
+		D_BDW, 0, 8, gvt_cmd_handler_3dstate_constant},
+
+	{"3DSTATE_CONSTANT_PS", OP_3DSTATE_CONSTANT_PS, F_LEN_VAR, R_RCS,
+		D_BDW, 0, 8, gvt_cmd_handler_3dstate_constant},
+
+	{"3DSTATE_SAMPLE_MASK", OP_3DSTATE_SAMPLE_MASK, F_LEN_VAR, R_RCS,
+		D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_CONSTANT_HS", OP_3DSTATE_CONSTANT_HS, F_LEN_VAR, R_RCS,
+		D_BDW, 0, 8, gvt_cmd_handler_3dstate_constant},
+
+	{"3DSTATE_CONSTANT_DS", OP_3DSTATE_CONSTANT_DS, F_LEN_VAR, R_RCS,
+		D_BDW, 0, 8, gvt_cmd_handler_3dstate_constant},
+
+	{"3DSTATE_HS", OP_3DSTATE_HS, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_TE", OP_3DSTATE_TE, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_DS", OP_3DSTATE_DS, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_STREAMOUT", OP_3DSTATE_STREAMOUT, F_LEN_VAR, R_RCS,
+		D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_SBE", OP_3DSTATE_SBE, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_PS", OP_3DSTATE_PS, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_DRAWING_RECTANGLE", OP_3DSTATE_DRAWING_RECTANGLE, F_LEN_VAR,
+		R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_SAMPLER_PALETTE_LOAD0", OP_3DSTATE_SAMPLER_PALETTE_LOAD0,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_CHROMA_KEY", OP_3DSTATE_CHROMA_KEY, F_LEN_VAR, R_RCS, D_ALL,
+		0, 8, NULL},
+
+	{"3DSTATE_DEPTH_BUFFER", OP_3DSTATE_DEPTH_BUFFER, F_LEN_VAR, R_RCS,
+		D_ALL, ADDR_FIX_1(2), 8, NULL},
+
+	{"3DSTATE_POLY_STIPPLE_OFFSET", OP_3DSTATE_POLY_STIPPLE_OFFSET,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_POLY_STIPPLE_PATTERN", OP_3DSTATE_POLY_STIPPLE_PATTERN,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_LINE_STIPPLE", OP_3DSTATE_LINE_STIPPLE, F_LEN_VAR, R_RCS,
+		D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_AA_LINE_PARAMS", OP_3DSTATE_AA_LINE_PARAMS, F_LEN_VAR, R_RCS,
+		D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_GS_SVB_INDEX", OP_3DSTATE_GS_SVB_INDEX, F_LEN_VAR, R_RCS, D_ALL,
+		0, 8, NULL},
+
+	{"3DSTATE_SAMPLER_PALETTE_LOAD1", OP_3DSTATE_SAMPLER_PALETTE_LOAD1,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_MULTISAMPLE", OP_3DSTATE_MULTISAMPLE_BDW, F_LEN_VAR, R_RCS, D_BDW,
+		0, 8, NULL},
+
+	{"3DSTATE_STENCIL_BUFFER", OP_3DSTATE_STENCIL_BUFFER, F_LEN_VAR, R_RCS,
+		D_ALL, ADDR_FIX_1(2), 8, NULL},
+
+	{"3DSTATE_HIER_DEPTH_BUFFER", OP_3DSTATE_HIER_DEPTH_BUFFER, F_LEN_VAR,
+		R_RCS, D_ALL, ADDR_FIX_1(2), 8, NULL},
+
+	{"3DSTATE_CLEAR_PARAMS", OP_3DSTATE_CLEAR_PARAMS, F_LEN_VAR,
+		R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_PUSH_CONSTANT_ALLOC_VS", OP_3DSTATE_PUSH_CONSTANT_ALLOC_VS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_PUSH_CONSTANT_ALLOC_HS", OP_3DSTATE_PUSH_CONSTANT_ALLOC_HS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_PUSH_CONSTANT_ALLOC_DS", OP_3DSTATE_PUSH_CONSTANT_ALLOC_DS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_PUSH_CONSTANT_ALLOC_GS", OP_3DSTATE_PUSH_CONSTANT_ALLOC_GS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_PUSH_CONSTANT_ALLOC_PS", OP_3DSTATE_PUSH_CONSTANT_ALLOC_PS,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_MONOFILTER_SIZE", OP_3DSTATE_MONOFILTER_SIZE, F_LEN_VAR, R_RCS,
+		D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_SO_DECL_LIST", OP_3DSTATE_SO_DECL_LIST, F_LEN_VAR, R_RCS, D_ALL,
+		0, 9, NULL},
+
+	{"3DSTATE_SO_BUFFER", OP_3DSTATE_SO_BUFFER, F_LEN_VAR, R_RCS, D_BDW,
+		ADDR_FIX_2(2, 4), 8, NULL},
+
+	{"3DSTATE_BINDING_TABLE_POOL_ALLOC", OP_3DSTATE_BINDING_TABLE_POOL_ALLOC,
+		F_LEN_VAR, R_RCS, D_BDW, ADDR_FIX_1(1), 8, NULL},
+
+	{"3DSTATE_GATHER_POOL_ALLOC", OP_3DSTATE_GATHER_POOL_ALLOC,
+		F_LEN_VAR, R_RCS, D_BDW, ADDR_FIX_1(1), 8, NULL},
+
+	{"3DSTATE_DX9_CONSTANT_BUFFER_POOL_ALLOC", OP_3DSTATE_DX9_CONSTANT_BUFFER_POOL_ALLOC,
+		F_LEN_VAR, R_RCS, D_BDW, ADDR_FIX_1(1), 8, NULL},
+
+	{"3DSTATE_SAMPLE_PATTERN", OP_3DSTATE_SAMPLE_PATTERN, F_LEN_VAR, R_RCS, D_BDW, 0, 8, NULL},
+
+	{"PIPE_CONTROL", OP_PIPE_CONTROL, F_LEN_VAR, R_RCS, D_ALL,
+		ADDR_FIX_1(2), 8, gvt_cmd_handler_pipe_control},
+
+	{"3DPRIMITIVE", OP_3DPRIMITIVE, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"PIPELINE_SELECT", OP_PIPELINE_SELECT, F_LEN_CONST, R_RCS, D_ALL, 0, 1, NULL},
+
+	{"STATE_PREFETCH", OP_STATE_PREFETCH, F_LEN_VAR, R_RCS, D_ALL,
+		ADDR_FIX_1(1), 8, NULL},
+
+	{"STATE_SIP", OP_STATE_SIP, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"STATE_BASE_ADDRESS", OP_STATE_BASE_ADDRESS, F_LEN_VAR, R_RCS, D_BDW,
+		ADDR_FIX_5(1, 3, 4, 5, 6), 8, NULL},
+
+	{"OP_3D_MEDIA_0_1_4", OP_3D_MEDIA_0_1_4, F_LEN_VAR, R_RCS, D_ALL,
+		ADDR_FIX_1(1), 8, NULL},
+
+	{"3DSTATE_VS", OP_3DSTATE_VS, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_SF", OP_3DSTATE_SF, F_LEN_VAR, R_RCS, D_ALL, 0, 8, NULL},
+
+	{"3DSTATE_CONSTANT_VS", OP_3DSTATE_CONSTANT_VS, F_LEN_VAR, R_RCS, D_BDW,
+		0, 8, gvt_cmd_handler_3dstate_constant},
+
+	{"MEDIA_INTERFACE_DESCRIPTOR_LOAD", OP_MEDIA_INTERFACE_DESCRIPTOR_LOAD,
+		F_LEN_VAR, R_RCS, D_ALL, 0, 16, NULL},
+
+	{"MEDIA_GATEWAY_STATE", OP_MEDIA_GATEWAY_STATE, F_LEN_VAR, R_RCS, D_ALL,
+		0, 16, NULL},
+
+	{"MEDIA_STATE_FLUSH", OP_MEDIA_STATE_FLUSH, F_LEN_VAR, R_RCS, D_ALL,
+		0, 16, NULL},
+
+	{"MEDIA_OBJECT", OP_MEDIA_OBJECT, F_LEN_VAR, R_RCS, D_ALL, 0, 16, NULL},
+
+	{"MEDIA_CURBE_LOAD", OP_MEDIA_CURBE_LOAD, F_LEN_VAR, R_RCS, D_ALL,
+		0, 16, NULL},
+
+	{"MEDIA_OBJECT_PRT", OP_MEDIA_OBJECT_PRT, F_LEN_VAR, R_RCS, D_ALL,
+		0, 16, NULL},
+
+	{"MEDIA_OBJECT_WALKER", OP_MEDIA_OBJECT_WALKER, F_LEN_VAR, R_RCS, D_ALL,
+		0, 16, NULL},
+
+	{"GPGPU_WALKER", OP_GPGPU_WALKER, F_LEN_VAR, R_RCS, D_ALL,
+		0, 8, NULL},
+
+	{"MEDIA_VFE_STATE", OP_MEDIA_VFE_STATE, F_LEN_VAR, R_RCS, D_ALL, 0, 16, NULL},
+
+	{"3DSTATE_VF_STATISTICS_GM45", OP_3DSTATE_VF_STATISTICS_GM45, F_LEN_CONST,
+		R_ALL, D_ALL, 0, 1, NULL},
+
+	{"MFX_PIPE_MODE_SELECT", OP_MFX_PIPE_MODE_SELECT, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_SURFACE_STATE", OP_MFX_SURFACE_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_PIPE_BUF_ADDR_STATE", OP_MFX_PIPE_BUF_ADDR_STATE, F_LEN_VAR,
+		R_VCS, D_BDW, 0, 12, gvt_cmd_handler_mfx_pipe_buf_addr_state},
+
+	{"MFX_IND_OBJ_BASE_ADDR_STATE", OP_MFX_IND_OBJ_BASE_ADDR_STATE, F_LEN_VAR,
+		R_VCS, D_BDW, 0, 12, gvt_cmd_handler_mfx_ind_obj_base_addr_state},
+
+	{"MFX_BSP_BUF_BASE_ADDR_STATE", OP_MFX_BSP_BUF_BASE_ADDR_STATE, F_LEN_VAR,
+		R_VCS, D_BDW, ADDR_FIX_3(1, 3, 5), 12, NULL},
+
+	{"OP_2_0_0_5", OP_2_0_0_5, F_LEN_VAR, R_VCS, D_BDW, 0, 12, NULL},
+
+	{"MFX_STATE_POINTER", OP_MFX_STATE_POINTER, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_QM_STATE", OP_MFX_QM_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_FQM_STATE", OP_MFX_FQM_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_PAK_INSERT_OBJECT", OP_MFX_PAK_INSERT_OBJECT, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_STITCH_OBJECT", OP_MFX_STITCH_OBJECT, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFD_IT_OBJECT", OP_MFD_IT_OBJECT, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_WAIT", OP_MFX_WAIT, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 6, NULL},
+
+	{"MFX_AVC_IMG_STATE", OP_MFX_AVC_IMG_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_AVC_QM_STATE", OP_MFX_AVC_QM_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	/* to check: is "Direct MV Buffer Base Address" GMA ? */
+	{"MFX_AVC_DIRECTMODE_STATE", OP_MFX_AVC_DIRECTMODE_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_AVC_SLICE_STATE", OP_MFX_AVC_SLICE_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_AVC_REF_IDX_STATE", OP_MFX_AVC_REF_IDX_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_AVC_WEIGHTOFFSET_STATE", OP_MFX_AVC_WEIGHTOFFSET_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFD_AVC_PICID_STATE", OP_MFD_AVC_PICID_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+	{"MFD_AVC_DPB_STATE", OP_MFD_AVC_DPB_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFD_AVC_BSD_OBJECT", OP_MFD_AVC_BSD_OBJECT, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFD_AVC_SLICEADDR", OP_MFD_AVC_SLICEADDR, F_LEN_VAR,
+		R_VCS, D_ALL, ADDR_FIX_1(2), 12, NULL},
+
+	{"MFC_AVC_PAK_OBJECT", OP_MFC_AVC_PAK_OBJECT, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_VC1_PRED_PIPE_STATE", OP_MFX_VC1_PRED_PIPE_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_VC1_DIRECTMODE_STATE", OP_MFX_VC1_DIRECTMODE_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFD_VC1_SHORT_PIC_STATE", OP_MFD_VC1_SHORT_PIC_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFD_VC1_LONG_PIC_STATE", OP_MFD_VC1_LONG_PIC_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFD_VC1_BSD_OBJECT", OP_MFD_VC1_BSD_OBJECT, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFC_MPEG2_SLICEGROUP_STATE", OP_MFC_MPEG2_SLICEGROUP_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFC_MPEG2_PAK_OBJECT", OP_MFC_MPEG2_PAK_OBJECT, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_MPEG2_PIC_STATE", OP_MFX_MPEG2_PIC_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_MPEG2_QM_STATE", OP_MFX_MPEG2_QM_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFD_MPEG2_BSD_OBJECT", OP_MFD_MPEG2_BSD_OBJECT, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_2_6_0_0", OP_MFX_2_6_0_0, F_LEN_VAR, R_VCS, D_ALL,
+		0, 16, gvt_cmd_handler_mfx_2_6_0_0},
+
+	{"MFX_2_6_0_9", OP_MFX_2_6_0_9, F_LEN_VAR, R_VCS, D_ALL, 0, 16, NULL},
+
+	{"MFX_2_6_0_8", OP_MFX_2_6_0_8, F_LEN_VAR, R_VCS, D_ALL, 0, 16, NULL},
+
+	{"MFX_JPEG_PIC_STATE", OP_MFX_JPEG_PIC_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFX_JPEG_HUFF_TABLE_STATE", OP_MFX_JPEG_HUFF_TABLE_STATE, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"MFD_JPEG_BSD_OBJECT", OP_MFD_JPEG_BSD_OBJECT, F_LEN_VAR,
+		R_VCS, D_ALL, 0, 12, NULL},
+
+	{"VEBOX_STATE", OP_VEB_STATE, F_LEN_VAR, R_VECS, D_ALL, 0, 12, NULL},
+
+	{"VEBOX_SURFACE_STATE", OP_VEB_SURFACE_STATE, F_LEN_VAR, R_VECS, D_ALL, 0, 12, NULL},
+
+	{"VEB_DI_IECP", OP_VEB_DNDI_IECP_STATE, F_LEN_VAR, R_VECS, D_BDW_PLUS, 0, 20, NULL},
+};
+
+
+static int gvt_cmd_advance_default(struct parser_exec_state *s)
+{
+	return ip_gma_advance(s, cmd_length(s));
+}
+
+static void gvt_add_cmd_entry(struct pgt_device *pdev, struct gvt_cmd_entry *e)
+{
+	hash_add(pdev->cmd_table, &e->hlist, e->info->opcode);
+}
+
+#define GVT_MAX_CMD_LENGTH     20  /* In Dword */
+
+static void trace_cs_command(struct parser_exec_state *s, cycles_t cost_pre_cmd_handler, cycles_t cost_cmd_handler)
+{
+	/* This buffer is used by ftrace to store all commands copied from guest gma
+	* space. Sometimes commands can cross pages, this should not be handled in
+	 * ftrace logic. So this is just used as a 'bounce buffer' */
+	u32 cmd_trace_buf[GVT_MAX_CMD_LENGTH];
+	int i;
+	u32 cmd_len = cmd_length(s);
+	/* The chosen value of GVT_MAX_CMD_LENGTH are just based on
+	 * following two considerations:
+	 * 1) From observation, most common ring commands is not that long.
+	 *    But there are execeptions. So it indeed makes sence to observe
+	 *    longer commands.
+	 * 2) From the performance and debugging point of view, dumping all
+	 *    contents of very commands is not necessary.
+	 * We mgith shrink GVT_MAX_CMD_LENGTH or remove this trace event in
+	 * future for performance considerations.
+	 */
+	if (unlikely(cmd_len > GVT_MAX_CMD_LENGTH)) {
+		gvt_dbg_cmd("cmd length exceed tracing limitation!");
+		cmd_len = GVT_MAX_CMD_LENGTH;
+	}
+
+	for (i = 0; i < cmd_len; i++)
+		cmd_trace_buf[i] = cmd_val(s, i);
+
+	trace_gvt_command(s->vgt->vm_id, s->ring_id, s->ip_gma, cmd_trace_buf,
+			cmd_len, s->buf_type == RING_BUFFER_INSTRUCTION, cost_pre_cmd_handler, cost_cmd_handler);
+
+}
+
+/* call the cmd handler, and advance ip */
+static bool gvt_cmd_parser_exec(struct parser_exec_state *s)
+{
+	struct cmd_info *info;
+	u32 cmd;
+	int rc = 0;
+	cycles_t t0, t1, t2;
+
+	t0 = get_cycles();
+
+	cmd = cmd_val(s, 0);
+
+	info = gvt_get_cmd_info(s->vgt->pdev, cmd, s->ring_id);
+	if (info == NULL) {
+		gvt_err("ERROR: unknown cmd 0x%x, opcode=0x%x", cmd,
+				get_opcode(cmd, s->ring_id));
+		parser_exec_state_dump(s);
+		return false;
+	}
+
+	gvt_dbg_cmd("%s", info->name);
+
+	s->info = info;
+
+	gvt_cmd_addr_audit_with_bitmap(s, info->addr_bitmap);
+
+	t1 = get_cycles();
+
+	if (info->handler) {
+		rc = info->handler(s);
+		if (rc < 0) {
+			gvt_err("%s handler error", info->name);
+			return false;
+		}
+	}
+
+	t2 = get_cycles();
+
+	trace_cs_command(s, t1 - t0, t2 -t1);
+
+	if (!(info->flag & F_IP_ADVANCE_CUSTOM)) {
+		rc = gvt_cmd_advance_default(s);
+		if (rc < 0) {
+			gvt_err("%s IP advance error", info->name);
+			return false;
+		}
+	}
+	return true;
+}
+
+static inline bool gma_out_of_range(unsigned long gma, unsigned long gma_head, unsigned gma_tail)
+{
+	if ( gma_tail >= gma_head)
+		return (gma < gma_head) || (gma > gma_tail);
+	else
+		return (gma > gma_tail) && (gma < gma_head);
+
+}
+
+static bool scan_workload(struct gvt_workload *workload)
+{
+	unsigned long gma_head, gma_tail, gma_bottom;
+	struct parser_exec_state s;
+	bool rc = false;
+
+	/* ring base is page aligned */
+	ASSERT((workload->rb_start & (PAGE_SIZE-1)) == 0);
+
+	gma_head = workload->rb_start + workload->rb_head;
+	gma_tail = workload->rb_start + workload->rb_tail;
+	gma_bottom = workload->rb_start +  _RING_CTL_BUF_SIZE(workload->rb_ctl);
+
+	s.buf_type = RING_BUFFER_INSTRUCTION;
+	s.buf_addr_type = GTT_BUFFER;
+	s.vgt = workload->vgt;
+	s.ring_id = workload->ring_id;
+	s.ring_start = workload->rb_start;
+	s.ring_size = _RING_CTL_BUF_SIZE(workload->rb_ctl);
+	s.ring_head = gma_head;
+	s.ring_tail = gma_tail;
+	s.rb_va = workload->shadow_ring_buffer_va;
+	s.workload = workload;
+
+	if (bypass_scan_mask & (1 << workload->ring_id))
+		return true;
+
+	if (ip_gma_set(&s, gma_head) < 0)
+		goto out;
+
+	gvt_dbg_cmd("scan_start: start=%lx end=%lx", gma_head, gma_tail);
+
+	while(s.ip_gma != gma_tail) {
+		if (s.buf_type == RING_BUFFER_INSTRUCTION) {
+			if (!(s.ip_gma >= workload->rb_start) || !(s.ip_gma < gma_bottom)) {
+				gvt_err("ERROR: ip_gma %lx out of ring scope."
+					"(base:0x%lx, bottom: 0x%lx)",
+					s.ip_gma, workload->rb_start, gma_bottom);
+				return false;
+			}
+			if (gma_out_of_range(s.ip_gma, gma_head, gma_tail)) {
+				gvt_err("ERROR: ip_gma %lx out of range."
+					"(base:0x%lx, head: 0x%lx, tail: 0x%lx)",
+					s.ip_gma, workload->rb_start, workload->rb_head, workload->rb_tail);
+				break;
+			}
+		}
+
+		rc = gvt_cmd_parser_exec(&s);
+		if (!rc) {
+			gvt_err("cmd parser error");
+			break;
+		}
+	}
+
+	gvt_dbg_cmd("scan_end");
+out:
+	return rc;
+}
+
+static bool copy_gma_to_hva(struct vgt_device *vgt, struct gvt_mm *mm,
+		unsigned long gma, unsigned long end_gma, void *va)
+{
+	unsigned long copy_len, offset;
+	unsigned long len = 0;
+	void *gma_va;
+
+	while (gma != end_gma) {
+		gma_va = gvt_gma_to_va(mm, gma);
+		if (!gma_va) {
+			gvt_err("invalid gma address: %lx", gma);
+			return false;
+		}
+
+		offset = gma & (GTT_PAGE_SIZE - 1);
+		if (offset) {
+			copy_len = (end_gma - gma) >= (GTT_PAGE_SIZE - offset) ?
+				GTT_PAGE_SIZE - offset : end_gma - gma;
+		} else {
+			copy_len = (end_gma - gma) >= GTT_PAGE_SIZE ?
+				GTT_PAGE_SIZE : end_gma - gma;
+		}
+
+		gvt_dbg_cmd("end gma %lx gma %lx offset %lx copy len %lx",
+			end_gma, gma, offset, copy_len);
+
+		hypervisor_read_va(vgt, gma_va,
+			va + len, copy_len, 1);
+
+		len += copy_len;
+		gma += copy_len;
+	}
+
+	return true;
+}
+
+static bool shadow_workload_ring_buffer(struct gvt_workload *workload)
+{
+	struct vgt_device *vgt = workload->vgt;
+	struct pgt_device *pdev = vgt->pdev;
+
+	int ring_id = workload->ring_id;
+	struct gvt_workload_scheduler *scheduler = &pdev->workload_scheduler;
+	struct intel_context *shadow_ctx = scheduler->shadow_ctx;
+	struct intel_ringbuffer *ringbuf = shadow_ctx->engine[ring_id].ringbuf;
+
+	unsigned long gma_head, gma_tail, gma_top, guest_rb_size;
+	unsigned copy_len = 0;
+
+	int ret;
+
+	guest_rb_size = _RING_CTL_BUF_SIZE(workload->rb_ctl);
+
+	/* calculate workload ring buffer size */
+	workload->rb_len = (workload->rb_tail + guest_rb_size -
+			workload->rb_head) % guest_rb_size;
+
+	gma_head = workload->rb_start + workload->rb_head;
+	gma_tail = workload->rb_start + workload->rb_tail;
+	gma_top = workload->rb_start + guest_rb_size;
+
+	/* allocate shadow ring buffer */
+	ret = intel_logical_ring_begin(workload->req, workload->rb_len / 4);
+	if(ret)
+		return false;
+
+	/* get shadow ring buffer va */
+	workload->shadow_ring_buffer_va = ringbuf->virtual_start + ringbuf->tail;
+
+	/* head > tail --> copy head <-> top */
+	if (gma_head > gma_tail) {
+		if (!copy_gma_to_hva(vgt, vgt->gtt.ggtt_mm,
+					gma_head, gma_top, workload->shadow_ring_buffer_va)) {
+			gvt_err("fail to copy guest ring buffer");
+			return false;
+		}
+
+		copy_len = gma_top - gma_head;
+		gma_head = workload->rb_start;
+	}
+
+	/* copy head or start <-> tail */
+	if (!copy_gma_to_hva(vgt, vgt->gtt.ggtt_mm,
+				gma_head, gma_tail, workload->shadow_ring_buffer_va + copy_len)) {
+		gvt_err("fail to copy guest ring buffer");
+		return false;
+	}
+
+	ringbuf->tail += workload->rb_len;
+	intel_logical_ring_advance(ringbuf);
+
+	return true;
+}
+
+bool gvt_scan_and_shadow_workload(struct gvt_workload *workload)
+{
+	struct gvt_statistics *stat = &workload->vgt->stat;
+	cycles_t t0, t1;
+
+	t0 = get_cycles();
+
+	stat->vring_scan_cnt++;
+
+	if (!shadow_workload_ring_buffer(workload)) {
+		gvt_err("fail to shadow workload ring_buffer");
+		return false;
+	}
+
+	if (!scan_workload(workload)) {
+		gvt_err("scan workload error");
+		return false;
+	}
+
+	t1 = get_cycles();
+
+	stat->vring_scan_cycles += t1 - t0;
+	return true;
+}
+
+static struct cmd_info *find_cmd_entry_any_ring(struct pgt_device *pdev, unsigned int opcode, int rings)
+{
+	struct cmd_info* info = NULL;
+	unsigned int ring;
+	for_each_set_bit(ring, (unsigned long*)&rings, I915_NUM_RINGS) {
+		info = find_cmd_entry(pdev, opcode, ring);
+		if (info)
+			break;
+	}
+	return info;
+}
+
+static bool init_cmd_table(struct pgt_device *pdev)
+{
+	int i;
+	struct gvt_cmd_entry *e;
+	struct cmd_info	*info;
+	unsigned int gen_type;
+
+	gen_type = gvt_get_device_type(pdev);
+
+	for (i = 0; i < ARRAY_SIZE(cmd_info); i++) {
+		if (!(cmd_info[i].devices & gen_type)) {
+			gvt_dbg_cmd("CMD[%-30s] op[%04x] flag[%x] devs[%02x] rings[%02x] not registered",
+					cmd_info[i].name, cmd_info[i].opcode, cmd_info[i].flag,
+					cmd_info[i].devices, cmd_info[i].rings);
+			continue;
+		}
+
+		e = kzalloc(sizeof(*e), GFP_KERNEL);
+		if (e == NULL) {
+			gvt_err("Insufficient memory in %s", __FUNCTION__);
+			return false;
+		}
+
+		e->info = &cmd_info[i];
+
+		info = find_cmd_entry_any_ring(pdev, e->info->opcode, e->info->rings);
+		if (info) {
+			gvt_err("%s %s duplicated", e->info->name, info->name);
+			return false;;
+		}
+
+		INIT_HLIST_NODE(&e->hlist);
+		gvt_add_cmd_entry(pdev, e);
+		gvt_dbg_cmd("CMD[%-30s] op[%04x] flag[%x] devs[%02x] rings[%02x] registered",
+				e->info->name,e->info->opcode, e->info->flag, e->info->devices,
+				e->info->rings);
+	}
+	return true;
+}
+
+void clean_cmd_table(struct pgt_device *pdev)
+{
+	struct hlist_node *tmp;
+	struct gvt_cmd_entry *e;
+	int i;
+
+	hash_for_each_safe(pdev->cmd_table, i, tmp, e, hlist)
+		kfree(e);
+
+	hash_init(pdev->cmd_table);
+}
+
+void gvt_clean_cmd_parser(struct pgt_device *pdev)
+{
+	clean_cmd_table(pdev);
+}
+
+bool gvt_init_cmd_parser(struct pgt_device *pdev)
+{
+	if (!init_cmd_table(pdev)) {
+		gvt_clean_cmd_parser(pdev);
+		return false;
+	}
+	return true;
+}
diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.h b/drivers/gpu/drm/i915/gvt/cmd_parser.h
new file mode 100644
index 0000000..824ff32
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/cmd_parser.h
@@ -0,0 +1,466 @@
+/*
+ * Copyright(c) 2011-2016 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.
+ */
+
+#define VGT_UNHANDLEABLE 1
+
+#define INVALID_OP    (~0U)
+
+#define MAX_BB_SIZE	0x10000000
+
+#define OP_LEN_MI           9
+#define OP_LEN_2D           10
+#define OP_LEN_3D_MEDIA     16
+#define OP_LEN_MFX_VC       16
+#define OP_LEN_VEBOX	    16
+
+#define CMD_TYPE(cmd)	(((cmd) >> 29) & 7)
+
+struct sub_op_bits {
+	int hi;
+	int low;
+};
+struct decode_info {
+	char* name;
+	int op_len;
+	int nr_sub_op;
+	struct sub_op_bits *sub_op;
+};
+
+#define   MAX_CMD_BUDGET			0x7fffffff
+#define   MI_WAIT_FOR_PLANE_C_FLIP_PENDING      (1<<15)
+#define   MI_WAIT_FOR_PLANE_B_FLIP_PENDING      (1<<9)
+#define   MI_WAIT_FOR_PLANE_A_FLIP_PENDING      (1<<1)
+
+#define   MI_WAIT_FOR_SPRITE_C_FLIP_PENDING      (1<<20)
+#define   MI_WAIT_FOR_SPRITE_B_FLIP_PENDING      (1<<10)
+#define   MI_WAIT_FOR_SPRITE_A_FLIP_PENDING      (1<<2)
+
+/* Render Command Map */
+
+/* MI_* command Opcode (28:23) */
+#define OP_MI_NOOP                          0x0
+#define OP_MI_SET_PREDICATE                 0x1  /* HSW+ */
+#define OP_MI_USER_INTERRUPT                0x2
+#define OP_MI_WAIT_FOR_EVENT                0x3
+#define OP_MI_FLUSH                         0x4
+#define OP_MI_ARB_CHECK                     0x5
+#define OP_MI_RS_CONTROL                    0x6  /* HSW+ */
+#define OP_MI_REPORT_HEAD                   0x7
+#define OP_MI_ARB_ON_OFF                    0x8
+#define OP_MI_URB_ATOMIC_ALLOC              0x9  /* HSW+ */
+#define OP_MI_BATCH_BUFFER_END              0xA
+#define OP_MI_SUSPEND_FLUSH                 0xB
+#define OP_MI_PREDICATE                     0xC  /* IVB+ */
+#define OP_MI_TOPOLOGY_FILTER               0xD  /* IVB+ */
+#define OP_MI_SET_APPID                     0xE  /* IVB+ */
+#define OP_MI_RS_CONTEXT                    0xF  /* HSW+ */
+#define OP_MI_LOAD_SCAN_LINES_INCL          0x12 /* HSW+ */
+#define OP_MI_DISPLAY_FLIP                  0x14
+#define OP_MI_SEMAPHORE_MBOX                0x16
+#define OP_MI_SET_CONTEXT                   0x18
+#define OP_MI_MATH                          0x1A
+#define OP_MI_URB_CLEAR                     0x19
+#define OP_MI_SEMAPHORE_SIGNAL		    0x1B  /* BDW+ */
+#define OP_MI_SEMAPHORE_WAIT		    0x1C  /* BDW+ */
+
+#define OP_MI_STORE_DATA_IMM                0x20
+#define OP_MI_STORE_DATA_INDEX              0x21
+#define OP_MI_LOAD_REGISTER_IMM             0x22
+#define OP_MI_UPDATE_GTT                    0x23
+#define OP_MI_STORE_REGISTER_MEM            0x24
+#define OP_MI_FLUSH_DW                      0x26
+#define OP_MI_CLFLUSH                       0x27
+#define OP_MI_REPORT_PERF_COUNT             0x28
+#define OP_MI_LOAD_REGISTER_MEM             0x29  /* HSW+ */
+#define OP_MI_LOAD_REGISTER_REG             0x2A  /* HSW+ */
+#define OP_MI_RS_STORE_DATA_IMM             0x2B  /* HSW+ */
+#define OP_MI_LOAD_URB_MEM                  0x2C  /* HSW+ */
+#define OP_MI_STORE_URM_MEM                 0x2D  /* HSW+ */
+#define OP_MI_2E			    0x2E  /* BDW+ */
+#define OP_MI_2F			    0x2F  /* BDW+ */
+#define OP_MI_BATCH_BUFFER_START            0x31
+
+/* Bit definition for dword 0 */
+#define _CMDBIT_BB_START_IN_PPGTT	(1UL << 8)
+
+#define OP_MI_CONDITIONAL_BATCH_BUFFER_END  0x36
+
+#define BATCH_BUFFER_ADDR_MASK ((1UL << 32) - (1U <<2))
+#define BATCH_BUFFER_ADDR_HIGH_MASK ((1UL << 16) - (1U))
+#define BATCH_BUFFER_ADR_SPACE_BIT(x)	(((x)>>8) & 1U)
+#define BATCH_BUFFER_2ND_LEVEL_BIT(x)   ((x)>>22 & 1U)
+
+/* 2D command: Opcode (28:22) */
+#define OP_2D(x)    ((2<<7) | x)
+
+#define OP_XY_SETUP_BLT                             OP_2D(0x1)
+#define OP_XY_SETUP_CLIP_BLT                        OP_2D(0x3)
+#define OP_XY_SETUP_MONO_PATTERN_SL_BLT             OP_2D(0x11)
+#define OP_XY_PIXEL_BLT                             OP_2D(0x24)
+#define OP_XY_SCANLINES_BLT                         OP_2D(0x25)
+#define OP_XY_TEXT_BLT                              OP_2D(0x26)
+#define OP_XY_TEXT_IMMEDIATE_BLT                    OP_2D(0x31)
+#define OP_XY_COLOR_BLT                             OP_2D(0x50)
+#define OP_XY_PAT_BLT                               OP_2D(0x51)
+#define OP_XY_MONO_PAT_BLT                          OP_2D(0x52)
+#define OP_XY_SRC_COPY_BLT                          OP_2D(0x53)
+#define OP_XY_MONO_SRC_COPY_BLT                     OP_2D(0x54)
+#define OP_XY_FULL_BLT                              OP_2D(0x55)
+#define OP_XY_FULL_MONO_SRC_BLT                     OP_2D(0x56)
+#define OP_XY_FULL_MONO_PATTERN_BLT                 OP_2D(0x57)
+#define OP_XY_FULL_MONO_PATTERN_MONO_SRC_BLT        OP_2D(0x58)
+#define OP_XY_MONO_PAT_FIXED_BLT                    OP_2D(0x59)
+#define OP_XY_MONO_SRC_COPY_IMMEDIATE_BLT           OP_2D(0x71)
+#define OP_XY_PAT_BLT_IMMEDIATE                     OP_2D(0x72)
+#define OP_XY_SRC_COPY_CHROMA_BLT                   OP_2D(0x73)
+#define OP_XY_FULL_IMMEDIATE_PATTERN_BLT            OP_2D(0x74)
+#define OP_XY_FULL_MONO_SRC_IMMEDIATE_PATTERN_BLT   OP_2D(0x75)
+#define OP_XY_PAT_CHROMA_BLT                        OP_2D(0x76)
+#define OP_XY_PAT_CHROMA_BLT_IMMEDIATE              OP_2D(0x77)
+
+/* 3D/Media Command: Pipeline Type(28:27) Opcode(26:24) Sub Opcode(23:16) */
+#define OP_3D_MEDIA(sub_type, opcode, sub_opcode) \
+	( (3<<13) | ((sub_type)<<11) | ((opcode) <<8) | (sub_opcode))
+
+#define OP_STATE_PREFETCH                       OP_3D_MEDIA(0x0, 0x0, 0x03)
+
+#define OP_STATE_BASE_ADDRESS                   OP_3D_MEDIA(0x0, 0x1, 0x01)
+#define OP_STATE_SIP                            OP_3D_MEDIA(0x0, 0x1, 0x02)
+#define OP_3D_MEDIA_0_1_4			OP_3D_MEDIA(0x0, 0x1, 0x04)
+
+#define OP_3DSTATE_VF_STATISTICS_GM45           OP_3D_MEDIA(0x1, 0x0, 0x0B)
+
+#define OP_PIPELINE_SELECT                      OP_3D_MEDIA(0x1, 0x1, 0x04)
+
+#define OP_MEDIA_VFE_STATE                      OP_3D_MEDIA(0x2, 0x0, 0x0)
+#define OP_MEDIA_CURBE_LOAD                     OP_3D_MEDIA(0x2, 0x0, 0x1)
+#define OP_MEDIA_INTERFACE_DESCRIPTOR_LOAD      OP_3D_MEDIA(0x2, 0x0, 0x2)
+#define OP_MEDIA_GATEWAY_STATE                  OP_3D_MEDIA(0x2, 0x0, 0x3)
+#define OP_MEDIA_STATE_FLUSH                    OP_3D_MEDIA(0x2, 0x0, 0x4)
+
+#define OP_MEDIA_OBJECT                         OP_3D_MEDIA(0x2, 0x1, 0x0)
+#define OP_MEDIA_OBJECT_PRT                     OP_3D_MEDIA(0x2, 0x1, 0x2)
+#define OP_MEDIA_OBJECT_WALKER                  OP_3D_MEDIA(0x2, 0x1, 0x3)
+#define OP_GPGPU_WALKER                         OP_3D_MEDIA(0x2, 0x1, 0x5)
+
+#define OP_3DSTATE_CLEAR_PARAMS                 OP_3D_MEDIA(0x3, 0x0, 0x04) /* IVB+ */
+#define OP_3DSTATE_DEPTH_BUFFER                 OP_3D_MEDIA(0x3, 0x0, 0x05) /* IVB+ */
+#define OP_3DSTATE_STENCIL_BUFFER               OP_3D_MEDIA(0x3, 0x0, 0x06) /* IVB+ */
+#define OP_3DSTATE_HIER_DEPTH_BUFFER            OP_3D_MEDIA(0x3, 0x0, 0x07) /* IVB+ */
+#define OP_3DSTATE_VERTEX_BUFFERS               OP_3D_MEDIA(0x3, 0x0, 0x08)
+#define OP_3DSTATE_VERTEX_ELEMENTS              OP_3D_MEDIA(0x3, 0x0, 0x09)
+#define OP_3DSTATE_INDEX_BUFFER                 OP_3D_MEDIA(0x3, 0x0, 0x0A)
+#define OP_3DSTATE_VF_STATISTICS                OP_3D_MEDIA(0x3, 0x0, 0x0B)
+#define OP_3DSTATE_VF                           OP_3D_MEDIA(0x3, 0x0, 0x0C)  /* HSW+ */
+#define OP_3DSTATE_CC_STATE_POINTERS            OP_3D_MEDIA(0x3, 0x0, 0x0E)
+#define OP_3DSTATE_SCISSOR_STATE_POINTERS       OP_3D_MEDIA(0x3, 0x0, 0x0F)
+#define OP_3DSTATE_VS                           OP_3D_MEDIA(0x3, 0x0, 0x10)
+#define OP_3DSTATE_GS                           OP_3D_MEDIA(0x3, 0x0, 0x11)
+#define OP_3DSTATE_CLIP                         OP_3D_MEDIA(0x3, 0x0, 0x12)
+#define OP_3DSTATE_SF                           OP_3D_MEDIA(0x3, 0x0, 0x13)
+#define OP_3DSTATE_WM                           OP_3D_MEDIA(0x3, 0x0, 0x14)
+#define OP_3DSTATE_CONSTANT_VS                  OP_3D_MEDIA(0x3, 0x0, 0x15)
+#define OP_3DSTATE_CONSTANT_GS                  OP_3D_MEDIA(0x3, 0x0, 0x16)
+#define OP_3DSTATE_CONSTANT_PS                  OP_3D_MEDIA(0x3, 0x0, 0x17)
+#define OP_3DSTATE_SAMPLE_MASK                  OP_3D_MEDIA(0x3, 0x0, 0x18)
+#define OP_3DSTATE_CONSTANT_HS                  OP_3D_MEDIA(0x3, 0x0, 0x19) /* IVB+ */
+#define OP_3DSTATE_CONSTANT_DS                  OP_3D_MEDIA(0x3, 0x0, 0x1A) /* IVB+ */
+#define OP_3DSTATE_HS                           OP_3D_MEDIA(0x3, 0x0, 0x1B) /* IVB+ */
+#define OP_3DSTATE_TE                           OP_3D_MEDIA(0x3, 0x0, 0x1C) /* IVB+ */
+#define OP_3DSTATE_DS                           OP_3D_MEDIA(0x3, 0x0, 0x1D) /* IVB+ */
+#define OP_3DSTATE_STREAMOUT                    OP_3D_MEDIA(0x3, 0x0, 0x1E) /* IVB+ */
+#define OP_3DSTATE_SBE                          OP_3D_MEDIA(0x3, 0x0, 0x1F) /* IVB+ */
+#define OP_3DSTATE_PS                           OP_3D_MEDIA(0x3, 0x0, 0x20) /* IVB+ */
+#define OP_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP OP_3D_MEDIA(0x3, 0x0, 0x21) /* IVB+ */
+#define OP_3DSTATE_VIEWPORT_STATE_POINTERS_CC   OP_3D_MEDIA(0x3, 0x0, 0x23) /* IVB+ */
+#define OP_3DSTATE_BLEND_STATE_POINTERS         OP_3D_MEDIA(0x3, 0x0, 0x24) /* IVB+ */
+#define OP_3DSTATE_DEPTH_STENCIL_STATE_POINTERS OP_3D_MEDIA(0x3, 0x0, 0x25) /* IVB+ */
+#define OP_3DSTATE_BINDING_TABLE_POINTERS_VS    OP_3D_MEDIA(0x3, 0x0, 0x26) /* IVB+ */
+#define OP_3DSTATE_BINDING_TABLE_POINTERS_HS    OP_3D_MEDIA(0x3, 0x0, 0x27) /* IVB+ */
+#define OP_3DSTATE_BINDING_TABLE_POINTERS_DS    OP_3D_MEDIA(0x3, 0x0, 0x28) /* IVB+ */
+#define OP_3DSTATE_BINDING_TABLE_POINTERS_GS    OP_3D_MEDIA(0x3, 0x0, 0x29) /* IVB+ */
+#define OP_3DSTATE_BINDING_TABLE_POINTERS_PS    OP_3D_MEDIA(0x3, 0x0, 0x2A) /* IVB+ */
+#define OP_3DSTATE_SAMPLER_STATE_POINTERS_VS    OP_3D_MEDIA(0x3, 0x0, 0x2B) /* IVB+ */
+#define OP_3DSTATE_SAMPLER_STATE_POINTERS_HS    OP_3D_MEDIA(0x3, 0x0, 0x2C) /* IVB+ */
+#define OP_3DSTATE_SAMPLER_STATE_POINTERS_DS    OP_3D_MEDIA(0x3, 0x0, 0x2D) /* IVB+ */
+#define OP_3DSTATE_SAMPLER_STATE_POINTERS_GS    OP_3D_MEDIA(0x3, 0x0, 0x2E) /* IVB+ */
+#define OP_3DSTATE_SAMPLER_STATE_POINTERS_PS    OP_3D_MEDIA(0x3, 0x0, 0x2F) /* IVB+ */
+#define OP_3DSTATE_URB_VS                       OP_3D_MEDIA(0x3, 0x0, 0x30) /* IVB+ */
+#define OP_3DSTATE_URB_HS                       OP_3D_MEDIA(0x3, 0x0, 0x31) /* IVB+ */
+#define OP_3DSTATE_URB_DS                       OP_3D_MEDIA(0x3, 0x0, 0x32) /* IVB+ */
+#define OP_3DSTATE_URB_GS                       OP_3D_MEDIA(0x3, 0x0, 0x33) /* IVB+ */
+#define OP_3DSTATE_GATHER_CONSTANT_VS           OP_3D_MEDIA(0x3, 0x0, 0x34) /* HSW+ */
+#define OP_3DSTATE_GATHER_CONSTANT_GS           OP_3D_MEDIA(0x3, 0x0, 0x35) /* HSW+ */
+#define OP_3DSTATE_GATHER_CONSTANT_HS           OP_3D_MEDIA(0x3, 0x0, 0x36) /* HSW+ */
+#define OP_3DSTATE_GATHER_CONSTANT_DS           OP_3D_MEDIA(0x3, 0x0, 0x37) /* HSW+ */
+#define OP_3DSTATE_GATHER_CONSTANT_PS           OP_3D_MEDIA(0x3, 0x0, 0x38) /* HSW+ */
+#define OP_3DSTATE_DX9_CONSTANTF_VS             OP_3D_MEDIA(0x3, 0x0, 0x39) /* HSW+ */
+#define OP_3DSTATE_DX9_CONSTANTF_PS             OP_3D_MEDIA(0x3, 0x0, 0x3A) /* HSW+ */
+#define OP_3DSTATE_DX9_CONSTANTI_VS             OP_3D_MEDIA(0x3, 0x0, 0x3B) /* HSW+ */
+#define OP_3DSTATE_DX9_CONSTANTI_PS             OP_3D_MEDIA(0x3, 0x0, 0x3C) /* HSW+ */
+#define OP_3DSTATE_DX9_CONSTANTB_VS             OP_3D_MEDIA(0x3, 0x0, 0x3D) /* HSW+ */
+#define OP_3DSTATE_DX9_CONSTANTB_PS             OP_3D_MEDIA(0x3, 0x0, 0x3E) /* HSW+ */
+#define OP_3DSTATE_DX9_LOCAL_VALID_VS           OP_3D_MEDIA(0x3, 0x0, 0x3F) /* HSW+ */
+#define OP_3DSTATE_DX9_LOCAL_VALID_PS           OP_3D_MEDIA(0x3, 0x0, 0x40) /* HSW+ */
+#define OP_3DSTATE_DX9_GENERATE_ACTIVE_VS       OP_3D_MEDIA(0x3, 0x0, 0x41) /* HSW+ */
+#define OP_3DSTATE_DX9_GENERATE_ACTIVE_PS       OP_3D_MEDIA(0x3, 0x0, 0x42) /* HSW+ */
+#define OP_3DSTATE_BINDING_TABLE_EDIT_VS        OP_3D_MEDIA(0x3, 0x0, 0x43) /* HSW+ */
+#define OP_3DSTATE_BINDING_TABLE_EDIT_GS        OP_3D_MEDIA(0x3, 0x0, 0x44) /* HSW+ */
+#define OP_3DSTATE_BINDING_TABLE_EDIT_HS        OP_3D_MEDIA(0x3, 0x0, 0x45) /* HSW+ */
+#define OP_3DSTATE_BINDING_TABLE_EDIT_DS        OP_3D_MEDIA(0x3, 0x0, 0x46) /* HSW+ */
+#define OP_3DSTATE_BINDING_TABLE_EDIT_PS        OP_3D_MEDIA(0x3, 0x0, 0x47) /* HSW+ */
+
+#define OP_3DSTATE_VF_INSTANCING 		OP_3D_MEDIA(0x3, 0x0, 0x49) /* BDW+ */
+#define OP_3DSTATE_VF_SGVS  			OP_3D_MEDIA(0x3, 0x0, 0x4A) /* BDW+ */
+#define OP_3DSTATE_VF_TOPOLOGY   		OP_3D_MEDIA(0x3, 0x0, 0x4B) /* BDW+ */
+#define OP_3DSTATE_WM_CHROMAKEY   		OP_3D_MEDIA(0x3, 0x0, 0x4C) /* BDW+ */
+#define OP_3DSTATE_PS_BLEND   			OP_3D_MEDIA(0x3, 0x0, 0x4D) /* BDW+ */
+#define OP_3DSTATE_WM_DEPTH_STENCIL   		OP_3D_MEDIA(0x3, 0x0, 0x4E) /* BDW+ */
+#define OP_3DSTATE_PS_EXTRA   			OP_3D_MEDIA(0x3, 0x0, 0x4F) /* BDW+ */
+#define OP_3DSTATE_RASTER   			OP_3D_MEDIA(0x3, 0x0, 0x50) /* BDW+ */
+#define OP_3DSTATE_SBE_SWIZ   			OP_3D_MEDIA(0x3, 0x0, 0x51) /* BDW+ */
+#define OP_3DSTATE_WM_HZ_OP   			OP_3D_MEDIA(0x3, 0x0, 0x52) /* BDW+ */
+
+#define OP_3DSTATE_DRAWING_RECTANGLE            OP_3D_MEDIA(0x3, 0x1, 0x00)
+#define OP_3DSTATE_SAMPLER_PALETTE_LOAD0        OP_3D_MEDIA(0x3, 0x1, 0x02)
+#define OP_3DSTATE_CHROMA_KEY                   OP_3D_MEDIA(0x3, 0x1, 0x04)
+#define OP_SNB_3DSTATE_DEPTH_BUFFER             OP_3D_MEDIA(0x3, 0x1, 0x05)
+#define OP_3DSTATE_POLY_STIPPLE_OFFSET          OP_3D_MEDIA(0x3, 0x1, 0x06)
+#define OP_3DSTATE_POLY_STIPPLE_PATTERN         OP_3D_MEDIA(0x3, 0x1, 0x07)
+#define OP_3DSTATE_LINE_STIPPLE                 OP_3D_MEDIA(0x3, 0x1, 0x08)
+#define OP_3DSTATE_AA_LINE_PARAMS               OP_3D_MEDIA(0x3, 0x1, 0x0A)
+#define OP_3DSTATE_GS_SVB_INDEX                 OP_3D_MEDIA(0x3, 0x1, 0x0B)
+#define OP_3DSTATE_SAMPLER_PALETTE_LOAD1        OP_3D_MEDIA(0x3, 0x1, 0x0C)
+#define OP_3DSTATE_MULTISAMPLE_BDW		OP_3D_MEDIA(0x3, 0x0, 0x0D)
+#define OP_SNB_3DSTATE_STENCIL_BUFFER           OP_3D_MEDIA(0x3, 0x1, 0x0E)
+#define OP_SNB_3DSTATE_HIER_DEPTH_BUFFER        OP_3D_MEDIA(0x3, 0x1, 0x0F)
+#define OP_SNB_3DSTATE_CLEAR_PARAMS             OP_3D_MEDIA(0x3, 0x1, 0x10)
+#define OP_3DSTATE_MONOFILTER_SIZE              OP_3D_MEDIA(0x3, 0x1, 0x11)
+#define OP_3DSTATE_PUSH_CONSTANT_ALLOC_VS       OP_3D_MEDIA(0x3, 0x1, 0x12) /* IVB+ */
+#define OP_3DSTATE_PUSH_CONSTANT_ALLOC_HS       OP_3D_MEDIA(0x3, 0x1, 0x13) /* IVB+ */
+#define OP_3DSTATE_PUSH_CONSTANT_ALLOC_DS       OP_3D_MEDIA(0x3, 0x1, 0x14) /* IVB+ */
+#define OP_3DSTATE_PUSH_CONSTANT_ALLOC_GS       OP_3D_MEDIA(0x3, 0x1, 0x15) /* IVB+ */
+#define OP_3DSTATE_PUSH_CONSTANT_ALLOC_PS       OP_3D_MEDIA(0x3, 0x1, 0x16) /* IVB+ */
+#define OP_3DSTATE_SO_DECL_LIST                 OP_3D_MEDIA(0x3, 0x1, 0x17)
+#define OP_3DSTATE_SO_BUFFER                    OP_3D_MEDIA(0x3, 0x1, 0x18)
+#define OP_3DSTATE_BINDING_TABLE_POOL_ALLOC     OP_3D_MEDIA(0x3, 0x1, 0x19) /* HSW+ */
+#define OP_3DSTATE_GATHER_POOL_ALLOC            OP_3D_MEDIA(0x3, 0x1, 0x1A) /* HSW+ */
+#define OP_3DSTATE_DX9_CONSTANT_BUFFER_POOL_ALLOC OP_3D_MEDIA(0x3, 0x1, 0x1B) /* HSW+ */
+#define OP_3DSTATE_SAMPLE_PATTERN               OP_3D_MEDIA(0x3, 0x1, 0x1C)
+#define OP_PIPE_CONTROL                         OP_3D_MEDIA(0x3, 0x2, 0x00)
+#define OP_3DPRIMITIVE                          OP_3D_MEDIA(0x3, 0x3, 0x00)
+
+/* VCCP Command Parser */
+
+/*
+ * Below MFX and VBE cmd definition is from vaapi intel driver project (BSD License)
+ * git://anongit.freedesktop.org/vaapi/intel-driver
+ * src/i965_defines.h
+ *
+ */
+
+#define OP_MFX(pipeline, op, sub_opa, sub_opb)     \
+     (3 << 13 |                                  \
+     (pipeline) << 11 |                         \
+     (op) << 8 |                               \
+     (sub_opa) << 5 |                          \
+     (sub_opb))
+
+#define OP_MFX_PIPE_MODE_SELECT                    OP_MFX(2, 0, 0, 0)  /* ALL */
+#define OP_MFX_SURFACE_STATE                       OP_MFX(2, 0, 0, 1)  /* ALL */
+#define OP_MFX_PIPE_BUF_ADDR_STATE                 OP_MFX(2, 0, 0, 2)  /* ALL */
+#define OP_MFX_IND_OBJ_BASE_ADDR_STATE             OP_MFX(2, 0, 0, 3)  /* ALL */
+#define OP_MFX_BSP_BUF_BASE_ADDR_STATE             OP_MFX(2, 0, 0, 4)  /* ALL */
+#define OP_2_0_0_5                                 OP_MFX(2, 0, 0, 5)  /* ALL */
+#define OP_MFX_STATE_POINTER                       OP_MFX(2, 0, 0, 6)  /* ALL */
+#define OP_MFX_QM_STATE                            OP_MFX(2, 0, 0, 7)  /* IVB+ */
+#define OP_MFX_FQM_STATE                           OP_MFX(2, 0, 0, 8)  /* IVB+ */
+#define OP_MFX_PAK_INSERT_OBJECT                   OP_MFX(2, 0, 2, 8)  /* IVB+ */
+#define OP_MFX_STITCH_OBJECT                       OP_MFX(2, 0, 2, 0xA)  /* IVB+ */
+
+#define OP_MFD_IT_OBJECT                           OP_MFX(2, 0, 1, 9) /* ALL */
+
+#define OP_MFX_WAIT                                OP_MFX(1, 0, 0, 0) /* IVB+ */
+#define OP_MFX_AVC_IMG_STATE                       OP_MFX(2, 1, 0, 0) /* ALL */
+#define OP_MFX_AVC_QM_STATE                        OP_MFX(2, 1, 0, 1) /* ALL */
+#define OP_MFX_AVC_DIRECTMODE_STATE                OP_MFX(2, 1, 0, 2) /* ALL */
+#define OP_MFX_AVC_SLICE_STATE                     OP_MFX(2, 1, 0, 3) /* ALL */
+#define OP_MFX_AVC_REF_IDX_STATE                   OP_MFX(2, 1, 0, 4) /* ALL */
+#define OP_MFX_AVC_WEIGHTOFFSET_STATE              OP_MFX(2, 1, 0, 5) /* ALL */
+#define OP_MFD_AVC_PICID_STATE                     OP_MFX(2, 1, 1, 5) /* HSW+ */
+#define OP_MFD_AVC_DPB_STATE			   OP_MFX(2, 1, 1, 6) /* IVB+ */
+#define OP_MFD_AVC_SLICEADDR                       OP_MFX(2, 1, 1, 7) /* IVB+ */
+#define OP_MFD_AVC_BSD_OBJECT                      OP_MFX(2, 1, 1, 8) /* ALL */
+#define OP_MFC_AVC_PAK_OBJECT                      OP_MFX(2, 1, 2, 9) /* ALL */
+
+#define OP_MFX_VC1_PRED_PIPE_STATE                 OP_MFX(2, 2, 0, 1) /* ALL */
+#define OP_MFX_VC1_DIRECTMODE_STATE                OP_MFX(2, 2, 0, 2) /* ALL */
+#define OP_MFD_VC1_SHORT_PIC_STATE                 OP_MFX(2, 2, 1, 0) /* IVB+ */
+#define OP_MFD_VC1_LONG_PIC_STATE                  OP_MFX(2, 2, 1, 1) /* IVB+ */
+#define OP_MFD_VC1_BSD_OBJECT                      OP_MFX(2, 2, 1, 8) /* ALL */
+
+#define OP_MFX_MPEG2_PIC_STATE                     OP_MFX(2, 3, 0, 0) /* ALL */
+#define OP_MFX_MPEG2_QM_STATE                      OP_MFX(2, 3, 0, 1) /* ALL */
+#define OP_MFD_MPEG2_BSD_OBJECT                    OP_MFX(2, 3, 1, 8) /* ALL */
+#define OP_MFC_MPEG2_SLICEGROUP_STATE              OP_MFX(2, 3, 2, 3) /* ALL */
+#define OP_MFC_MPEG2_PAK_OBJECT                    OP_MFX(2, 3, 2, 9) /* ALL */
+
+#define OP_MFX_2_6_0_0                             OP_MFX(2, 6, 0, 0) /* IVB+ */
+#define OP_MFX_2_6_0_8                             OP_MFX(2, 6, 0, 8) /* IVB+ */
+#define OP_MFX_2_6_0_9                             OP_MFX(2, 6, 0, 9) /* IVB+ */
+
+#define OP_MFX_JPEG_PIC_STATE                      OP_MFX(2, 7, 0, 0)
+#define OP_MFX_JPEG_HUFF_TABLE_STATE               OP_MFX(2, 7, 0, 2)
+#define OP_MFD_JPEG_BSD_OBJECT                     OP_MFX(2, 7, 1, 8)
+
+/* copy from vaapi, but not found definition in PRM yet */
+#define OP_VEB(pipeline, op, sub_opa, sub_opb)     \
+     (3 << 13 |                                 \
+     (pipeline) << 11 |                         \
+     (op) << 8 |                               \
+     (sub_opa) << 5 |                          \
+     (sub_opb))
+
+#define OP_VEB_SURFACE_STATE                       OP_VEB(2, 4, 0, 0)
+#define OP_VEB_STATE                               OP_VEB(2, 4, 0, 2)
+#define OP_VEB_DNDI_IECP_STATE                     OP_VEB(2, 4, 0, 3)
+
+struct parser_exec_state;
+
+typedef int (*parser_cmd_handler)(struct parser_exec_state *s);
+
+#define GVT_CMD_HASH_BITS   7
+
+/* which DWords need address fix */
+#define ADDR_FIX_1(x1)                  (1<<(x1))
+#define ADDR_FIX_2(x1,x2)               (ADDR_FIX_1(x1) | ADDR_FIX_1(x2))
+#define ADDR_FIX_3(x1,x2,x3)            (ADDR_FIX_1(x1) | ADDR_FIX_2(x2,x3))
+#define ADDR_FIX_4(x1,x2,x3,x4)         (ADDR_FIX_1(x1) | ADDR_FIX_3(x2,x3,x4))
+#define ADDR_FIX_5(x1,x2,x3,x4,x5)      (ADDR_FIX_1(x1) | ADDR_FIX_4(x2,x3,x4,x5))
+
+struct cmd_info{
+	char* name;
+	u32 opcode;
+
+#define F_LEN_MASK	(1U<<0)
+#define F_LEN_CONST  1U
+#define F_LEN_VAR    0U
+
+/* command has its own ip advance logic
+   e.g. MI_BATCH_START, MI_BATCH_END
+*/
+#define F_IP_ADVANCE_CUSTOM (1<<1)
+
+#define F_POST_HANDLE	(1<<2)
+	u32 flag;
+
+#define R_RCS	(1 << RCS )
+#define R_VCS1  (1 << VCS)
+#define R_VCS2  (1 << VCS2)
+#define R_VCS	( R_VCS1 | R_VCS2)
+#define R_BCS	(1 << BCS )
+#define R_VECS	(1 << VECS )
+#define R_ALL (R_RCS | R_VCS | R_BCS | R_VECS)
+	/* rings that support this cmd: BLT/RCS/VCS/VECS */
+	uint16_t rings;
+
+	/* devices that support this cmd: SNB/IVB/HSW/... */
+	uint16_t devices;
+
+	/* which DWords are address that need fix up.
+	 * bit 0 means a 32-bit non address operand in command
+	 * bit 1 means address operand, which could be 32-bit
+	 * or 64-bit depending on different architectures.(
+	 * defined by "gmadr_bytes_in_cmd" in pgt_device.
+	 * No matter the address length, each address only takes
+	 * one bit in the bitmap.
+	 */
+	uint16_t addr_bitmap;
+
+	/*	flag == F_LEN_CONST : command length
+		flag == F_LEN_VAR : lenght bias bits
+		Note: length is in DWord
+	 */
+	uint8_t	len;
+
+	parser_cmd_handler handler;
+};
+
+struct gvt_cmd_entry {
+	struct hlist_node hlist;
+	struct cmd_info* info;
+};
+
+typedef enum {
+	RING_BUFFER_INSTRUCTION,
+	BATCH_BUFFER_INSTRUCTION,
+	BATCH_BUFFER_2ND_LEVEL,
+}cmd_buf_t;
+
+typedef enum{
+	GTT_BUFFER,
+	PPGTT_BUFFER
+}gtt_addr_t;
+
+struct parser_exec_state {
+	struct vgt_device *vgt;
+	int ring_id;
+
+	cmd_buf_t buf_type;
+
+	/* batch buffer address type */
+	gtt_addr_t buf_addr_type;
+
+	/* graphics memory address of ring buffer start */
+	unsigned long ring_start;
+	unsigned long ring_size;
+	unsigned long ring_head;
+	unsigned long ring_tail;
+
+	/* instruction graphics memory address */
+	unsigned long ip_gma;
+
+	/* mapped va of the instr_gma */
+	void *ip_va;
+	void *rb_va;
+
+	/* next instruction when return from  batch buffer to ring buffer */
+	unsigned long ret_ip_gma_ring;
+
+	/* next instruction when return from 2nd batch buffer to batch buffer */
+	unsigned long ret_ip_gma_bb;
+
+	/* batch buffer address type (GTT or PPGTT)
+	   used when ret from 2nd level batch buffer */
+	gtt_addr_t saved_buf_addr_type;
+
+	struct cmd_info* info;
+
+	struct gvt_workload *workload;
+};
+
+void gvt_clean_cmd_parser(struct pgt_device *pdev);
+
+bool gvt_init_cmd_parser(struct pgt_device *pdev);
+
+bool gvt_scan_and_shadow_workload(struct gvt_workload *workload);
diff --git a/drivers/gpu/drm/i915/gvt/debug.h b/drivers/gpu/drm/i915/gvt/debug.h
index 953ba08..7379bce 100644
--- a/drivers/gpu/drm/i915/gvt/debug.h
+++ b/drivers/gpu/drm/i915/gvt/debug.h
@@ -76,6 +76,7 @@ enum {
 	GVT_DBG_EDID = (1 << 5),
 	GVT_DBG_EL = (1 << 6),
 	GVT_DBG_SCHED = (1 << 7),
+	GVT_DBG_CMD = (1 << 8),
 };
 
 #define gvt_dbg_core(fmt, args...) \
@@ -96,4 +97,7 @@ enum {
 #define gvt_dbg_sched(fmt, args...) \
 	gvt_dbg(GVT_DBG_SCHED, fmt, ##args)
 
+#define gvt_dbg_cmd(fmt, args...) \
+	gvt_dbg(GVT_DBG_CMD, fmt, ##args)
+
 #endif
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index 8b56c00..3cca46b 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -283,6 +283,7 @@ static bool init_service_thread(struct pgt_device *pdev)
 static void clean_pgt_device(struct pgt_device *pdev)
 {
 	clean_service_thread(pdev);
+	gvt_clean_cmd_parser(pdev);
 	gvt_clean_workload_scheduler(pdev);
 	gvt_clean_control_interface(pdev);
 	gvt_clean_gtt(pdev);
@@ -320,6 +321,9 @@ static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *de
 	if (!gvt_setup_control_interface(pdev))
 		goto err;
 
+	if (!gvt_init_cmd_parser(pdev))
+		goto err;
+
 	if (!init_service_thread(pdev))
 		goto err;
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index d7ff61e..16bfdca 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -46,6 +46,7 @@
 #include "scheduler.h"
 #include "sched_policy.h"
 #include "render.h"
+#include "cmd_parser.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -228,6 +229,8 @@ struct pgt_device {
 	struct gvt_device_control control;
 
 	struct gvt_workload_scheduler workload_scheduler;
+
+	DECLARE_HASHTABLE(cmd_table, GVT_CMD_HASH_BITS);
 };
 
 /* request types to wake up main thread */
diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c
index d0cc1a6..8400258 100644
--- a/drivers/gpu/drm/i915/gvt/interrupt.c
+++ b/drivers/gpu/drm/i915/gvt/interrupt.c
@@ -124,6 +124,55 @@ char *gvt_irq_name[GVT_EVENT_MAX] = {
 	[GVT_EVENT_RESERVED] = "RESERVED EVENTS!!!",
 };
 
+struct ring_id_to_cmd_interrupt_event {
+	int pipe_control_notify;
+	int mi_flush_dw;
+	int mi_user_interrupt;
+};
+
+struct ring_id_to_cmd_interrupt_event ring_id_to_cmd_interrupt_event[] = {
+	[RCS] = {
+		.pipe_control_notify = RCS_PIPE_CONTROL,
+		.mi_flush_dw = GVT_EVENT_RESERVED,
+		.mi_user_interrupt = RCS_MI_USER_INTERRUPT,
+	},
+	[BCS] = {
+		.pipe_control_notify = GVT_EVENT_RESERVED,
+		.mi_flush_dw = BCS_MI_FLUSH_DW,
+		.mi_user_interrupt = BCS_MI_USER_INTERRUPT,
+	},
+	[VCS] = {
+		.pipe_control_notify = GVT_EVENT_RESERVED,
+		.mi_flush_dw = VCS_MI_FLUSH_DW,
+		.mi_user_interrupt = VCS_MI_USER_INTERRUPT,
+	},
+	[VCS2] = {
+		.pipe_control_notify = GVT_EVENT_RESERVED,
+		.mi_flush_dw = VCS2_MI_FLUSH_DW,
+		.mi_user_interrupt = VCS2_MI_USER_INTERRUPT,
+	},
+	[VECS] = {
+		.pipe_control_notify = GVT_EVENT_RESERVED,
+		.mi_flush_dw = VECS_MI_FLUSH_DW,
+		.mi_user_interrupt = VECS_MI_USER_INTERRUPT,
+	},
+};
+
+int gvt_ring_id_to_pipe_control_notify_event(int ring_id)
+{
+	return ring_id_to_cmd_interrupt_event[ring_id].pipe_control_notify;
+}
+
+int gvt_ring_id_to_mi_flush_dw_event(int ring_id)
+{
+	return ring_id_to_cmd_interrupt_event[ring_id].mi_flush_dw;
+}
+
+int gvt_ring_id_to_mi_user_interrupt_event(int ring_id)
+{
+	return ring_id_to_cmd_interrupt_event[ring_id].mi_user_interrupt;
+}
+
 static inline struct gvt_irq_info *regbase_to_irq_info(struct pgt_device *pdev,
 		unsigned int reg)
 {
diff --git a/drivers/gpu/drm/i915/gvt/interrupt.h b/drivers/gpu/drm/i915/gvt/interrupt.h
index ff125fc..d00a7d9 100644
--- a/drivers/gpu/drm/i915/gvt/interrupt.h
+++ b/drivers/gpu/drm/i915/gvt/interrupt.h
@@ -250,4 +250,8 @@ void gvt_trigger_virtual_event(struct vgt_device *vgt,
 	enum gvt_event_type event);
 void gvt_inject_flip_done(struct vgt_device *vgt, int pipe);
 
+int gvt_ring_id_to_pipe_control_notify_event(int ring_id);
+int gvt_ring_id_to_mi_flush_dw_event(int ring_id);
+int gvt_ring_id_to_mi_user_interrupt_event(int ring_id);
+
 #endif /* _GVT_INTERRUPT_H_ */
diff --git a/drivers/gpu/drm/i915/gvt/perf.h b/drivers/gpu/drm/i915/gvt/perf.h
index 21b0637..6f411cf 100644
--- a/drivers/gpu/drm/i915/gvt/perf.h
+++ b/drivers/gpu/drm/i915/gvt/perf.h
@@ -36,6 +36,8 @@ struct gvt_statistics {
 	u64	gtt_mmio_wcnt;
 	u64	gtt_mmio_wcycles;
 	u64	gtt_mmio_rcycles;
+	u64	vring_scan_cnt;
+	u64	vring_scan_cycles;
 	u64	wp_cnt;
 	u64	wp_cycles;
 	u64	ppgtt_wp_cnt;
@@ -48,6 +50,7 @@ struct gvt_statistics {
 	u64	gpt_find_hit_cycles;
 	u64	gpt_find_miss_cnt;
 	u64	gpt_find_miss_cycles;
+	u64	skip_bb_cnt;
 
 };
 
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
index d38aeb1..ea73b82 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.c
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -145,6 +145,11 @@ static bool dispatch_workload(struct gvt_workload *workload)
 
 	mutex_lock(&pdev->lock);
 
+	if (!gvt_scan_and_shadow_workload(workload)) {
+		workload->status = -EINVAL;
+		goto err;
+	}
+
 	if (!populate_shadow_context(workload)) {
 		workload->status = -EINVAL;
 		goto err;
@@ -309,6 +314,7 @@ static void complete_current_workload(struct pgt_device *pdev, int ring_id)
 {
 	struct gvt_workload_scheduler *scheduler = &pdev->workload_scheduler;
 	struct gvt_workload *workload;
+	int event;
 
 	mutex_lock(&pdev->lock);
 
@@ -318,6 +324,9 @@ static void complete_current_workload(struct pgt_device *pdev, int ring_id)
 		wait_event(workload->shadow_ctx_status_wq,
 				!atomic_read(&workload->shadow_ctx_active));
 		update_guest_context(workload);
+
+		for_each_set_bit(event, workload->pending_events, GVT_EVENT_MAX)
+			gvt_trigger_virtual_event(workload->vgt, event);
 	}
 
 	if (workload->req)
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h
index 7a8f1eb..6c87599 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.h
+++ b/drivers/gpu/drm/i915/gvt/scheduler.h
@@ -55,7 +55,7 @@ struct gvt_workload {
 	/* execlist context information */
 	struct execlist_ctx_descriptor_format ctx_desc;
 	struct execlist_ring_context *ring_context;
-	unsigned long rb_head, rb_tail, rb_ctl, rb_start;
+	unsigned long rb_head, rb_tail, rb_ctl, rb_start, rb_len;
 
 	struct gvt_mm *shadow_mm;
 
@@ -63,6 +63,9 @@ struct gvt_workload {
 	bool (*complete)(struct gvt_workload *);
 
 	struct list_head list;
+
+	DECLARE_BITMAP(pending_events, GVT_EVENT_MAX);
+	void *shadow_ring_buffer_va;
 };
 
 #define workload_q_head(vgt, ring_id) \
diff --git a/drivers/gpu/drm/i915/gvt/trace.h b/drivers/gpu/drm/i915/gvt/trace.h
index b6a9f3f..b2e20fb 100644
--- a/drivers/gpu/drm/i915/gvt/trace.h
+++ b/drivers/gpu/drm/i915/gvt/trace.h
@@ -198,6 +198,58 @@ TRACE_EVENT(oos_sync,
 		TP_printk("%s", __entry->buf)
 );
 
+#define MAX_CMD_STR_LEN	256
+TRACE_EVENT(gvt_command,
+		TP_PROTO(u8 vm_id, u8 ring_id, u32 ip_gma, u32 *cmd_va, u32 cmd_len, bool ring_buffer_cmd, cycles_t cost_pre_cmd_handler, cycles_t cost_cmd_handler),
+
+		TP_ARGS(vm_id, ring_id, ip_gma, cmd_va, cmd_len, ring_buffer_cmd, cost_pre_cmd_handler, cost_cmd_handler),
+
+		TP_STRUCT__entry(
+			__field(u8, vm_id)
+			__field(u8, ring_id)
+			__field(int, i)
+			__array(char,tmp_buf, MAX_CMD_STR_LEN)
+			__array(char, cmd_str, MAX_CMD_STR_LEN)
+			),
+
+		TP_fast_assign(
+			__entry->vm_id = vm_id;
+			__entry->ring_id = ring_id;
+			__entry->cmd_str[0] = '\0';
+			snprintf(__entry->tmp_buf, MAX_CMD_STR_LEN, "VM(%d) Ring(%d): %s ip(%08x) pre handler cost (%llu), handler cost (%llu) ", vm_id, ring_id, ring_buffer_cmd ? "RB":"BB", ip_gma, cost_pre_cmd_handler, cost_cmd_handler);
+			strcat(__entry->cmd_str, __entry->tmp_buf);
+			entry->i = 0;
+			while (cmd_len > 0) {
+				if (cmd_len >= 8) {
+					snprintf(__entry->tmp_buf, MAX_CMD_STR_LEN, "%08x %08x %08x %08x %08x %08x %08x %08x ",
+						cmd_va[__entry->i], cmd_va[__entry->i+1], cmd_va[__entry->i+2], cmd_va[__entry->i+3],
+						cmd_va[__entry->i+4],cmd_va[__entry->i+5],cmd_va[__entry->i+6],cmd_va[__entry->i+7]);
+					__entry->i += 8;
+					cmd_len -= 8;
+					strcat(__entry->cmd_str, __entry->tmp_buf);
+				} else if (cmd_len >= 4) {
+					snprintf(__entry->tmp_buf, MAX_CMD_STR_LEN, "%08x %08x %08x %08x ",
+						cmd_va[__entry->i], cmd_va[__entry->i+1], cmd_va[__entry->i+2], cmd_va[__entry->i+3]);
+					__entry->i += 4;
+					cmd_len -= 4;
+					strcat(__entry->cmd_str, __entry->tmp_buf);
+				} else if (cmd_len >= 2) {
+					snprintf(__entry->tmp_buf, MAX_CMD_STR_LEN, "%08x %08x ", cmd_va[__entry->i], cmd_va[__entry->i+1]);
+					__entry->i += 2;
+					cmd_len -= 2;
+					strcat(__entry->cmd_str, __entry->tmp_buf);
+				} else if (cmd_len == 1) {
+					snprintf(__entry->tmp_buf, MAX_CMD_STR_LEN, "%08x ", cmd_va[__entry->i]);
+					__entry->i += 1;
+					cmd_len -= 1;
+					strcat(__entry->cmd_str, __entry->tmp_buf);
+				}
+			}
+			strcat(__entry->cmd_str, "\n");
+		),
+
+		TP_printk("%s", __entry->cmd_str)
+);
 #endif /* _GVT_TRACE_H_ */
 
 /* This part must be out of protection */
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [RFC 17/29] gvt: Xen hypervisor GVT-g MPT module
  2016-01-28 10:21 ` [RFC 17/29] gvt: Xen hypervisor GVT-g MPT module Zhi Wang
@ 2016-01-28 11:33   ` Joonas Lahtinen
  2016-01-28 12:50     ` Zhiyuan Lv
  0 siblings, 1 reply; 49+ messages in thread
From: Joonas Lahtinen @ 2016-01-28 11:33 UTC (permalink / raw)
  To: Zhi Wang, intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

Hi,

See the file MAINTAINERS and add Cc: lines according to "XEN HYPERVISOR
INTERFACE". Also I think it'll be useful to split the i915 changes to a
separate patch next int he series (as the reviewer will be different).

We will have to wait for Xen maintainers to take a position on this. Is
there KVM counterparts for this stuff incoming?

On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
> This is the xen hypervisor MPT module which let GVT-g be able to run
> under
> Xen hypervisor.
> 

Cc: xen-devel@lists.xenproject.org
...and so on...

Regards, Joonas

> Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
> ---
>  arch/x86/include/asm/xen/hypercall.h |    7 +
>  arch/x86/include/asm/xen/interface.h |    1 +
>  arch/x86/xen/mmu.c                   |   83 +++
>  drivers/gpu/drm/i915/gvt/gvt.c       |   10 +
>  drivers/gpu/drm/i915/gvt/gvt.h       |   14 +
>  drivers/xen/Kconfig                  |    5 +
>  drivers/xen/Makefile                 |    6 +
>  drivers/xen/xengt.c                  | 1153
> ++++++++++++++++++++++++++++++++++
>  include/xen/interface/hvm/hvm_op.h   |  177 +++++-
>  include/xen/interface/hvm/ioreq.h    |  132 ++++
>  include/xen/interface/memory.h       |   28 +
>  include/xen/interface/xen.h          |  106 ++++
>  include/xen/xen-ops.h                |    5 +
>  13 files changed, 1726 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/xen/xengt.c
>  create mode 100644 include/xen/interface/hvm/ioreq.h
> 
> diff --git a/arch/x86/include/asm/xen/hypercall.h
> b/arch/x86/include/asm/xen/hypercall.h
> index 3bcdcc8..aea97e3 100644
> --- a/arch/x86/include/asm/xen/hypercall.h
> +++ b/arch/x86/include/asm/xen/hypercall.h
> @@ -459,6 +459,13 @@ HYPERVISOR_hvm_op(int op, void *arg)
>  }
>  
>  static inline int
> +HYPERVISOR_domctl(
> +        struct xen_domctl *arg)
> +{
> +        return _hypercall1(int, domctl, arg);
> +}
> +
> +static inline int
>  HYPERVISOR_tmem_op(
>  	struct tmem_op *op)
>  {
> diff --git a/arch/x86/include/asm/xen/interface.h
> b/arch/x86/include/asm/xen/interface.h
> index 6ff4986..a4ee3f4 100644
> --- a/arch/x86/include/asm/xen/interface.h
> +++ b/arch/x86/include/asm/xen/interface.h
> @@ -89,6 +89,7 @@ typedef long xen_long_t;
>  /* Guest handles for primitive C types. */
>  __DEFINE_GUEST_HANDLE(uchar, unsigned char);
>  __DEFINE_GUEST_HANDLE(uint,  unsigned int);
> +__DEFINE_GUEST_HANDLE(ulong,  unsigned long);
>  DEFINE_GUEST_HANDLE(char);
>  DEFINE_GUEST_HANDLE(int);
>  DEFINE_GUEST_HANDLE(void);
> diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
> index c913ca4..da95d45 100644
> --- a/arch/x86/xen/mmu.c
> +++ b/arch/x86/xen/mmu.c
> @@ -2931,3 +2931,86 @@ int xen_unmap_domain_gfn_range(struct
> vm_area_struct *vma,
>  #endif
>  }
>  EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range);
> +
> +/* Note: here 'mfn' is actually gfn!!! */
> +struct vm_struct * xen_remap_domain_mfn_range_in_kernel(unsigned
> long mfn,
> +		int nr, unsigned domid)
> +{
> +	struct vm_struct *area;
> +	struct remap_data rmd;
> +	struct mmu_update mmu_update[REMAP_BATCH_SIZE];
> +	int batch;
> +	unsigned long range, addr;
> +	pgprot_t prot;
> +	int err;
> +
> +	WARN_ON(in_interrupt() || irqs_disabled());
> +
> +	area = alloc_vm_area(nr << PAGE_SHIFT, NULL);
> +	if (!area)
> +		return NULL;
> +
> +	addr = (unsigned long)area->addr;
> +
> +	prot = __pgprot(pgprot_val(PAGE_KERNEL));
> +
> +	rmd.mfn = &mfn;
> +	rmd.prot = prot;
> +
> +	while (nr) {
> +		batch = min(REMAP_BATCH_SIZE, nr);
> +		range = (unsigned long)batch << PAGE_SHIFT;
> +
> +		rmd.mmu_update = mmu_update;
> +		err = apply_to_page_range(&init_mm, addr, range,
> +				remap_area_mfn_pte_fn, &rmd);
> +		if (err || HYPERVISOR_mmu_update(mmu_update, batch,
> NULL, domid) < 0)
> +			goto err;
> +
> +		nr -= batch;
> +		addr += range;
> +	}
> +
> +	xen_flush_tlb_all();
> +	return area;
> +err:
> +	free_vm_area(area);
> +	xen_flush_tlb_all();
> +	return NULL;
> +}
> +EXPORT_SYMBOL(xen_remap_domain_mfn_range_in_kernel);
> +
> +void xen_unmap_domain_mfn_range_in_kernel(struct vm_struct *area,
> int nr,
> +		unsigned domid)
> +{
> +	struct remap_data rmd;
> +	struct mmu_update mmu_update[REMAP_BATCH_SIZE];
> +	int batch;
> +	unsigned long range, addr = (unsigned long)area->addr;
> +#define INVALID_MFN (~0UL)
> +	unsigned long invalid_mfn = INVALID_MFN;
> +	int err;
> +
> +	WARN_ON(in_interrupt() || irqs_disabled());
> +
> +	rmd.mfn = &invalid_mfn;
> +	rmd.prot = PAGE_NONE;
> +
> +	while (nr) {
> +		batch = min(REMAP_BATCH_SIZE, nr);
> +		range = (unsigned long)batch << PAGE_SHIFT;
> +
> +		rmd.mmu_update = mmu_update;
> +		err = apply_to_page_range(&init_mm, addr, range,
> +				remap_area_mfn_pte_fn, &rmd);
> +		BUG_ON(err);
> +		BUG_ON(HYPERVISOR_mmu_update(mmu_update, batch,
> NULL, domid) < 0);
> +
> +		nr -= batch;
> +		addr += range;
> +	}
> +
> +	free_vm_area(area);
> +	xen_flush_tlb_all();
> +}
> +EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range_in_kernel);
> diff --git a/drivers/gpu/drm/i915/gvt/gvt.c
> b/drivers/gpu/drm/i915/gvt/gvt.c
> index a71873c..28a51d9 100644
> --- a/drivers/gpu/drm/i915/gvt/gvt.c
> +++ b/drivers/gpu/drm/i915/gvt/gvt.c
> @@ -21,12 +21,14 @@
>   * SOFTWARE.
>   */
>  
> +#include <linux/types.h>
>  #include <xen/xen.h>
>  #include <linux/kthread.h>
>  
>  #include "gvt.h"
>  
>  struct gvt_host gvt_host;
> +EXPORT_SYMBOL(gvt_host);
>  
>  extern struct gvt_kernel_dm xengt_kdm;
>  extern struct gvt_kernel_dm kvmgt_kdm;
> @@ -36,6 +38,13 @@ static struct gvt_io_emulation_ops
> default_io_emulation_ops = {
>  	.emulate_mmio_write = gvt_emulate_mmio_write,
>  };
>  
> +unsigned int pa_to_mmio_offset(struct vgt_device *vgt,
> +               uint64_t pa);
> +
> +static struct gvt_mpt_ops default_export_mpt_ops = {
> +	.pa_to_mmio_offset = pa_to_mmio_offset,
> +};
> +
>  static const char *supported_hypervisors[] = {
>  	[GVT_HYPERVISOR_TYPE_XEN] = "Xen Hypervisor",
>  	[GVT_HYPERVISOR_TYPE_KVM] = "KVM",
> @@ -78,6 +87,7 @@ static bool gvt_init_host(void)
>  			supported_hypervisors[host-
> >hypervisor_type]);
>  
>  	host->emulate_ops = &default_io_emulation_ops;
> +	host->mpt_ops = &default_export_mpt_ops;
>  	idr_init(&host->device_idr);
>  	mutex_init(&host->device_idr_lock);
>  
> diff --git a/drivers/gpu/drm/i915/gvt/gvt.h
> b/drivers/gpu/drm/i915/gvt/gvt.h
> index eb5fd47..83f90a2 100644
> --- a/drivers/gpu/drm/i915/gvt/gvt.h
> +++ b/drivers/gpu/drm/i915/gvt/gvt.h
> @@ -58,6 +58,10 @@ struct gvt_io_emulation_ops {
>  	bool (*emulate_cfg_write)(struct vgt_device *, unsigned int,
> void *, int);
>  };
>  
> +struct gvt_mpt_ops {
> +	unsigned int (*pa_to_mmio_offset)(struct vgt_device *, u64);
> +};
> +
>  struct gvt_host {
>  	bool initialized;
>  	int hypervisor_type;
> @@ -65,6 +69,7 @@ struct gvt_host {
>  	struct idr device_idr;
>  	struct gvt_kernel_dm *kdm;
>  	struct gvt_io_emulation_ops *emulate_ops;
> +	struct gvt_mpt_ops *mpt_ops;
>  };
>  
>  extern struct gvt_host gvt_host;
> @@ -123,6 +128,9 @@ struct vgt_device {
>  	struct gvt_virtual_device_state state;
>  	struct gvt_statistics stat;
>  	struct gvt_vgtt_info gtt;
> +	void *hypervisor_data;
> +	unsigned long low_mem_max_gpfn;
> +	atomic_t crashing;
>  };
>  
>  struct gvt_gm_allocator {
> @@ -423,6 +431,12 @@ static inline int gvt_pci_mmio_is_enabled(struct
> vgt_device *vgt)
>  		_REGBIT_CFG_COMMAND_MEMORY;
>  }
>  
> +static inline uint64_t gvt_mmio_bar_base(struct vgt_device *vgt)
> +{
> +        char *cfg_space = &vgt->state.cfg.space[0];
> +        return *(u64 *)(cfg_space + GVT_REG_CFG_SPACE_BAR0);
> +}
> +
>  #define __vreg(vgt, off) (*(u32*)(vgt->state.mmio.vreg + off))
>  #define __vreg8(vgt, off) (*(u8*)(vgt->state.mmio.vreg + off))
>  #define __vreg16(vgt, off) (*(u16*)(vgt->state.mmio.vreg + off))
> diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
> index 73708ac..9ee2033 100644
> --- a/drivers/xen/Kconfig
> +++ b/drivers/xen/Kconfig
> @@ -291,4 +291,9 @@ config XEN_SYMS
>  config XEN_HAVE_VPMU
>         bool
>  
> +config XENGT
> +        tristate "Xen Dom0 support for i915 gvt device model"
> +        depends on XEN_DOM0 && I915_GVT
> +        default m
> +
>  endmenu
> diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
> index 9b7a35c..ff75c36 100644
> --- a/drivers/xen/Makefile
> +++ b/drivers/xen/Makefile
> @@ -9,6 +9,10 @@ CFLAGS_features.o			:=
> $(nostackp)
>  
>  CFLAGS_efi.o				+= -fshort-wchar
>  
> +
> +I915                     := drivers/gpu/drm/i915
> +CFLAGS_xengt.o          += -Wall -Werror -I$(I915) -I$(I915)/gvt
> +
>  dom0-$(CONFIG_PCI) += pci.o
>  dom0-$(CONFIG_USB_SUPPORT) += dbgp.o
>  dom0-$(CONFIG_XEN_ACPI) += acpi.o $(xen-pad-y)
> @@ -36,6 +40,8 @@ obj-$(CONFIG_XEN_ACPI_PROCESSOR)	+= xen-
> acpi-processor.o
>  obj-$(CONFIG_XEN_EFI)			+= efi.o
>  obj-$(CONFIG_XEN_SCSI_BACKEND)		+= xen-scsiback.o
>  obj-$(CONFIG_XEN_AUTO_XLATE)		+= xlate_mmu.o
> +obj-$(CONFIG_XENGT)                     += xengt.o
> +
>  xen-evtchn-y				:= evtchn.o
>  xen-gntdev-y				:= gntdev.o
>  xen-gntalloc-y				:= gntalloc.o
> diff --git a/drivers/xen/xengt.c b/drivers/xen/xengt.c
> new file mode 100644
> index 0000000..6c600adc
> --- /dev/null
> +++ b/drivers/xen/xengt.c
> @@ -0,0 +1,1153 @@
> +/*
> + * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> modify
> + * it under the terms of Version 2 of the GNU General Public License
> as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-
> 1301 USA.
> + */
> +
> +/*
> + * NOTE:
> + * This file contains hypervisor specific interactions to
> + * implement the concept of mediated pass-through framework.
> + * What this file provides is actually a general abstraction
> + * of in-kernel device model, which is not vgt specific.
> + *
> + * Now temporarily in vgt code. long-term this should be
> + * in hypervisor (xen/kvm) specific directory
> + */
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/types.h>
> +#include <linux/kthread.h>
> +#include <linux/time.h>
> +#include <linux/freezer.h>
> +#include <linux/wait.h>
> +#include <linux/sched.h>
> +
> +#include <asm/xen/hypercall.h>
> +#include <asm/xen/page.h>
> +#include <xen/xen-ops.h>
> +#include <xen/events.h>
> +#include <xen/interface/hvm/params.h>
> +#include <xen/interface/hvm/hvm_op.h>
> +#include <xen/interface/hvm/ioreq.h>
> +#include <xen/interface/memory.h>
> +#include <xen/interface/platform.h>
> +#include <xen/interface/vcpu.h>
> +
> +#include "gvt.h"
> +
> +MODULE_AUTHOR("Intel Corporation");
> +MODULE_DESCRIPTION("XenGT mediated passthrough driver");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION("0.1");
> +
> +#define MAX_HVM_VCPUS_SUPPORTED 128
> +struct gvt_hvm_info {
> +	/* iopage_vma->addr is just iopage. We need iopage_vma on VM
> destroy */
> +	shared_iopage_t *iopage;
> +	struct vm_struct *iopage_vma;
> +	int *evtchn_irq; /* the event channle irqs to handle HVM io
> request
> +				index is vcpu id */
> +
> +	DECLARE_BITMAP(ioreq_pending, MAX_HVM_VCPUS_SUPPORTED);
> +	wait_queue_head_t io_event_wq;
> +	struct task_struct *emulation_thread;
> +
> +	int nr_vcpu;
> +
> +	ioservid_t iosrv_id;    /* io-request server id */
> +
> +#define VMEM_1MB		(1ULL << 20)	/* the size of
> the first 1MB */
> +#define VMEM_BUCK_SHIFT		20
> +#define VMEM_BUCK_SIZE		(1ULL << VMEM_BUCK_SHIFT)
> +#define VMEM_BUCK_MASK		(~(VMEM_BUCK_SIZE - 1))
> +	uint64_t vmem_sz;
> +	/* for the 1st 1MB memory of HVM: each vm_struct means one
> 4K-page */
> +	struct vm_struct **vmem_vma_low_1mb;
> +	/* for >1MB memory of HVM: each vm_struct means 1MB */
> +	struct vm_struct **vmem_vma;
> +	/* for >1MB memory of HVM: each vm_struct means 4KB */
> +	struct vm_struct **vmem_vma_4k;
> +};
> +
> +static int xen_pause_domain(int vm_id);
> +static int xen_shutdown_domain(int vm_id);
> +static void *xen_gpa_to_va(struct vgt_device *vgt, unsigned long
> gpa);
> +
> +#define XEN_ASSERT_VM(x, vgt)					
> 	\
> +	do {								
> \
> +		if (!(x)) {						
> \
> +			printk("Assert at %s line %d\n",		
> \
> +				__FILE__, __LINE__);			
> \
> +			if (atomic_cmpxchg(&(vgt)->crashing, 0, 1))	
> \
> +				break;				
> 	\
> +			gvt_err("Killing VM%d\n", (vgt)->vm_id);	
> \
> +			if (!xen_pause_domain((vgt->vm_id)))		
> \
> +				xen_shutdown_domain((vgt->vm_id));	
> \
> +		}							
> \
> +	} while (0)
> +
> +/* Translate from VM's guest pfn to machine pfn */
> +static unsigned long xen_g2m_pfn(int vm_id, unsigned long g_pfn)
> +{
> +	struct xen_get_mfn_from_pfn pfn_arg;
> +	int rc;
> +	unsigned long pfn_list[1];
> +
> +	pfn_list[0] = g_pfn;
> +
> +	set_xen_guest_handle(pfn_arg.pfn_list, pfn_list);
> +	pfn_arg.nr_pfns = 1;
> +	pfn_arg.domid = vm_id;
> +
> +	rc = HYPERVISOR_memory_op(XENMEM_get_mfn_from_pfn,
> &pfn_arg);
> +	if(rc < 0){
> +		printk("failed to get mfn for gpfn(0x%lx)\n,
> errno=%d\n", g_pfn, rc);
> +		return INVALID_MFN;
> +	}
> +
> +	return pfn_list[0];
> +}
> +
> +static int xen_get_max_gpfn(int vm_id)
> +{
> +	domid_t dom_id = vm_id;
> +	int max_gpfn = HYPERVISOR_memory_op(XENMEM_maximum_gpfn,
> &dom_id);
> +	BUG_ON(max_gpfn < 0);
> +	return max_gpfn;
> +}
> +
> +static int xen_pause_domain(int vm_id)
> +{
> +	int rc;
> +	struct xen_domctl domctl;
> +
> +	domctl.domain = vm_id;
> +	domctl.cmd = XEN_DOMCTL_pausedomain;
> +	domctl.interface_version = XEN_DOMCTL_INTERFACE_VERSION;
> +
> +	rc = HYPERVISOR_domctl(&domctl);
> +	if (rc != 0)
> +		printk("HYPERVISOR_domctl pausedomain fail with
> %d!\n", rc);
> +
> +	return rc;
> +}
> +
> +static int xen_shutdown_domain(int vm_id)
> +{
> +	int rc;
> +	struct sched_remote_shutdown r;
> +
> +	r.reason = SHUTDOWN_crash;
> +	r.domain_id = vm_id;
> +	rc = HYPERVISOR_sched_op(SCHEDOP_remote_shutdown, &r);
> +	if (rc != 0)
> +		printk("HYPERVISOR_sched_op failed: %d\n", rc);
> +	return rc;
> +}
> +
> +static int xen_domain_iomem_perm(uint32_t domain_id, uint64_t
> first_mfn,
> +                               uint64_t nr_mfns, uint8_t
> allow_access)
> +{
> +	struct xen_domctl arg;
> +	int rc;
> +
> +	arg.domain = domain_id;
> +	arg.cmd = XEN_DOMCTL_iomem_permission;
> +	arg.interface_version = XEN_DOMCTL_INTERFACE_VERSION;
> +	arg.u.iomem_perm.first_mfn = first_mfn;
> +	arg.u.iomem_perm.nr_mfns = nr_mfns;
> +	arg.u.iomem_perm.allow_access = allow_access;
> +	rc = HYPERVISOR_domctl(&arg);
> +
> +	return rc;
> +}
> +
> +static int xen_hvm_memory_mapping(int vm_id, uint64_t first_gfn,
> uint64_t first_mfn,
> +				  uint32_t nr_mfns, uint32_t
> add_mapping)
> +{
> +	struct xen_domctl arg;
> +	int rc;
> +
> +	if (add_mapping) {
> +		rc = xen_domain_iomem_perm(vm_id, first_mfn,
> nr_mfns, 1);
> +	        if (rc < 0) {
> +			printk(KERN_ERR "xen_domain_iomem_perm
> failed: %d\n", rc);
> +			return rc;
> +		}
> +	}
> +
> +	arg.domain = vm_id;
> +	arg.cmd = XEN_DOMCTL_memory_mapping;
> +	arg.interface_version = XEN_DOMCTL_INTERFACE_VERSION;
> +	arg.u.memory_mapping.first_gfn = first_gfn;
> +	arg.u.memory_mapping.first_mfn = first_mfn;
> +	arg.u.memory_mapping.nr_mfns = nr_mfns;
> +	arg.u.memory_mapping.add_mapping = add_mapping;
> +
> +	rc = HYPERVISOR_domctl(&arg);
> +	if (rc < 0) {
> +		printk(KERN_ERR "HYPERVISOR_domctl failed: %d\n",
> rc);
> +		return rc;
> +	}
> +
> +	if (!add_mapping) {
> +		rc = xen_domain_iomem_perm(vm_id, first_mfn,
> nr_mfns, 0);
> +	        if (rc < 0) {
> +			printk(KERN_ERR "xen_domain_iomem_perm
> failed: %d\n", rc);
> +			return rc;
> +		}
> +	}
> +
> +	return rc;
> +}
> +
> +static int xen_map_mfn_to_gpfn(int vm_id, unsigned long gpfn,
> +	unsigned long mfn, int nr, int map, enum map_type type)
> +{
> +	int rc;
> +	rc = xen_hvm_memory_mapping(vm_id, gpfn, mfn, nr,
> +			map ? DPCI_ADD_MAPPING :
> DPCI_REMOVE_MAPPING);
> +	if (rc != 0)
> +		printk("xen_hvm_memory_mapping failed: %d\n", rc);
> +	return rc;
> +}
> +
> +static int xen_get_nr_vcpu(int vm_id)
> +{
> +	struct xen_domctl arg;
> +	int rc;
> +
> +	arg.domain = vm_id;
> +	arg.cmd = XEN_DOMCTL_getdomaininfo;
> +	arg.interface_version = XEN_DOMCTL_INTERFACE_VERSION;
> +
> +	rc = HYPERVISOR_domctl(&arg);
> +	if (rc<0){
> +		printk(KERN_ERR "HYPERVISOR_domctl fail
> ret=%d\n",rc);
> +		/* assume it is UP */
> +		return 1;
> +	}
> +
> +	return arg.u.getdomaininfo.max_vcpu_id + 1;
> +}
> +
> +static int hvm_create_iorequest_server(struct vgt_device *vgt)
> +{
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +	struct xen_hvm_create_ioreq_server arg;
> +	int r;
> +
> +	arg.domid = vgt->vm_id;
> +	arg.handle_bufioreq = 0;
> +	r = HYPERVISOR_hvm_op(HVMOP_create_ioreq_server, &arg);
> +	if (r < 0) {
> +		printk(KERN_ERR "Cannot create io-requset server:
> %d!\n", r);
> +		return r;
> +	}
> +	info->iosrv_id = arg.id;
> +
> +	return r;
> +}
> +
> +static int hvm_toggle_iorequest_server(struct vgt_device *vgt, bool
> enable)
> +{
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +	struct xen_hvm_set_ioreq_server_state arg;
> +	int r;
> +
> +	arg.domid = vgt->vm_id;
> +	arg.id = info->iosrv_id;
> +	arg.enabled = enable;
> +	r = HYPERVISOR_hvm_op(HVMOP_set_ioreq_server_state, &arg);
> +	if (r < 0) {
> +		printk(KERN_ERR "Cannot %s io-request server:
> %d!\n",
> +			enable ? "enable" : "disbale",  r);
> +		return r;
> +	}
> +
> +       return r;
> +}
> +
> +static int hvm_get_ioreq_pfn(struct vgt_device *vgt, uint64_t
> *value)
> +{
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +	struct xen_hvm_get_ioreq_server_info arg;
> +	int r;
> +
> +	arg.domid = vgt->vm_id;
> +	arg.id = info->iosrv_id;
> +	r = HYPERVISOR_hvm_op(HVMOP_get_ioreq_server_info, &arg);
> +	if (r < 0) {
> +		printk(KERN_ERR "Cannot get ioreq pfn: %d!\n", r);
> +		return r;
> +	}
> +	*value = arg.ioreq_pfn;
> +	return r;
> +}
> +
> +static int hvm_destroy_iorequest_server(struct vgt_device *vgt)
> +{
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +	struct xen_hvm_destroy_ioreq_server arg;
> +	int r;
> +
> +	arg.domid = vgt->vm_id;
> +	arg.id = info->iosrv_id;
> +	r = HYPERVISOR_hvm_op(HVMOP_destroy_ioreq_server, &arg);
> +	if (r < 0) {
> +		printk(KERN_ERR "Cannot destroy io-request
> server(%d): %d!\n",
> +			info->iosrv_id, r);
> +		return r;
> +	}
> +	info->iosrv_id = 0;
> +
> +	return r;
> +}
> +
> +static int hvm_map_io_range_to_ioreq_server(struct vgt_device *vgt,
> +	int is_mmio, uint64_t start, uint64_t end, int map)
> +{
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +	xen_hvm_io_range_t arg;
> +	int rc;
> +
> +	arg.domid = vgt->vm_id;
> +	arg.id = info->iosrv_id;
> +	arg.type = is_mmio ? HVMOP_IO_RANGE_MEMORY :
> HVMOP_IO_RANGE_PORT;
> +	arg.start = start;
> +	arg.end = end;
> +
> +	if (map)
> +		rc =
> HYPERVISOR_hvm_op(HVMOP_map_io_range_to_ioreq_server, &arg);
> +	else
> +		rc =
> HYPERVISOR_hvm_op(HVMOP_unmap_io_range_from_ioreq_server, &arg);
> +
> +	return rc;
> +}
> +
> +static int hvm_map_pcidev_to_ioreq_server(struct vgt_device *vgt,
> uint64_t sbdf)
> +{
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +	xen_hvm_io_range_t arg;
> +	int rc;
> +
> +	arg.domid = vgt->vm_id;
> +	arg.id = info->iosrv_id;
> +	arg.type = HVMOP_IO_RANGE_PCI;
> +	arg.start = arg.end = sbdf;
> +	rc = HYPERVISOR_hvm_op(HVMOP_map_io_range_to_ioreq_server,
> &arg);
> +	if (rc < 0) {
> +		printk(KERN_ERR "Cannot map pci_dev to ioreq_server:
> %d!\n", rc);
> +		return rc;
> +	}
> +
> +	return rc;
> +}
> +
> +static int hvm_set_mem_type(struct vgt_device *vgt,
> +	uint16_t mem_type, uint64_t first_pfn, uint64_t nr)
> +{
> +	xen_hvm_set_mem_type_t args;
> +	int rc;
> +
> +	args.domid = vgt->vm_id;
> +	args.hvmmem_type = mem_type;
> +	args.first_pfn = first_pfn;
> +	args.nr = 1;
> +	rc = HYPERVISOR_hvm_op(HVMOP_set_mem_type, &args);
> +
> +	return rc;
> +}
> +
> +static int hvm_wp_page_to_ioreq_server(struct vgt_device *vgt,
> unsigned long page, int set)
> +{
> +	int rc = 0;
> +	uint64_t start, end;
> +	uint16_t mem_type;
> +
> +	start = page << PAGE_SHIFT;
> +	end = ((page + 1) << PAGE_SHIFT) - 1;
> +
> +	rc = hvm_map_io_range_to_ioreq_server(vgt, 1, start, end,
> set);
> +	if (rc < 0) {
> +		printk(KERN_ERR "Failed to %s page 0x%lx to
> ioreq_server: %d!\n",
> +			set ? "map":"unmap", page , rc);
> +		return rc;
> +	}
> +
> +	mem_type = set ? HVMMEM_mmio_write_dm : HVMMEM_ram_rw;
> +	rc = hvm_set_mem_type(vgt, mem_type, page, 1);
> +	if (rc < 0) {
> +		printk(KERN_ERR "Failed to set mem type of page
> 0x%lx to %s!\n", page,
> +			set ?
> "HVMMEM_mmio_write_dm":"HVMMEM_ram_rw");
> +		return rc;
> +	}
> +	return rc;
> +}
> +
> +static int xen_set_trap_area(struct vgt_device *vgt, uint64_t start,
> uint64_t end, bool map)
> +{
> +	if (!gvt_pci_mmio_is_enabled(vgt))
> +		return 0;
> +
> +	return hvm_map_io_range_to_ioreq_server(vgt, 1, start, end,
> map);
> +}
> +
> +static struct vm_struct *xen_map_iopage(struct vgt_device *vgt)
> +{
> +	uint64_t ioreq_pfn;
> +	int rc;
> +
> +	rc = hvm_create_iorequest_server(vgt);
> +	if (rc < 0)
> +		return NULL;
> +	rc = hvm_get_ioreq_pfn(vgt, &ioreq_pfn);
> +	if (rc < 0) {
> +		hvm_destroy_iorequest_server(vgt);
> +		return NULL;
> +	}
> +
> +	return xen_remap_domain_mfn_range_in_kernel(ioreq_pfn, 1,
> vgt->vm_id);
> +}
> +
> +static bool xen_set_guest_page_writeprotection(struct vgt_device
> *vgt,
> +		guest_page_t *guest_page)
> +{
> +	int r;
> +
> +	if (guest_page->writeprotection)
> +		return true;
> +
> +	r = hvm_wp_page_to_ioreq_server(vgt, guest_page->gfn, 1);
> +	if (r) {
> +		gvt_err("fail to set write protection.\n");
> +		return false;
> +	}
> +
> +	guest_page->writeprotection = true;
> +
> +	atomic_inc(&vgt->gtt.n_write_protected_guest_page);
> +
> +	return true;
> +}
> +
> +static bool xen_clear_guest_page_writeprotection(struct vgt_device
> *vgt,
> +		guest_page_t *guest_page)
> +{
> +	int r;
> +
> +	if (!guest_page->writeprotection)
> +		return true;
> +
> +	r = hvm_wp_page_to_ioreq_server(vgt, guest_page->gfn, 0);
> +	if (r) {
> +		gvt_err("fail to clear write protection.\n");
> +		return false;
> +	}
> +
> +	guest_page->writeprotection = false;
> +
> +	atomic_dec(&vgt->gtt.n_write_protected_guest_page);
> +
> +	return true;
> +}
> +
> +static int xen_detect_host(void)
> +{
> +	return xen_initial_domain();
> +}
> +
> +static int xen_virt_to_mfn(void *addr)
> +{
> +	return virt_to_mfn(addr);
> +}
> +
> +static void *xen_mfn_to_virt(int mfn)
> +{
> +	return mfn_to_virt(mfn);
> +}
> +
> +static int xen_inject_msi(int vm_id, u32 addr_lo, u16 data)
> +{
> +	struct xen_hvm_inject_msi info = {
> +		.domid	= vm_id,
> +		.addr	= addr_lo, /* only low addr used */
> +		.data	= data,
> +	};
> +
> +	return HYPERVISOR_hvm_op(HVMOP_inject_msi, &info);
> +}
> +
> +static int vgt_hvm_vmem_init(struct vgt_device *vgt)
> +{
> +	unsigned long i, j, gpfn, count;
> +	unsigned long nr_low_1mb_bkt, nr_high_bkt, nr_high_4k_bkt;
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +
> +	if (!vgt->vm_id)
> +		return 0;
> +
> +	ASSERT(info->vmem_vma == NULL && info->vmem_vma_low_1mb ==
> NULL);
> +
> +	info->vmem_sz = xen_get_max_gpfn(vgt->vm_id) + 1;
> +	info->vmem_sz <<= PAGE_SHIFT;
> +
> +	/* warn on non-1MB-aligned memory layout of HVM */
> +	if (info->vmem_sz & ~VMEM_BUCK_MASK)
> +		gvt_err("VM%d: vmem_sz=0x%llx!\n", vgt->vm_id, info-
> >vmem_sz);
> +
> +	nr_low_1mb_bkt = VMEM_1MB >> PAGE_SHIFT;
> +	nr_high_bkt = (info->vmem_sz >> VMEM_BUCK_SHIFT);
> +	nr_high_4k_bkt = (info->vmem_sz >> PAGE_SHIFT);
> +
> +	info->vmem_vma_low_1mb =
> +		vzalloc(sizeof(*info->vmem_vma) * nr_low_1mb_bkt);
> +	info->vmem_vma =
> +		vzalloc(sizeof(*info->vmem_vma) * nr_high_bkt);
> +	info->vmem_vma_4k =
> +		vzalloc(sizeof(*info->vmem_vma) * nr_high_4k_bkt);
> +
> +	if (info->vmem_vma_low_1mb == NULL || info->vmem_vma == NULL
> ||
> +		info->vmem_vma_4k == NULL) {
> +		gvt_err("Insufficient memory for vmem_vma,
> vmem_sz=0x%llx\n",
> +				info->vmem_sz );
> +		goto err;
> +	}
> +
> +	/* map the low 1MB memory */
> +	for (i = 0; i < nr_low_1mb_bkt; i++) {
> +		info->vmem_vma_low_1mb[i] =
> +			xen_remap_domain_mfn_range_in_kernel(i, 1,
> vgt->vm_id);
> +
> +		if (info->vmem_vma_low_1mb[i] != NULL)
> +			continue;
> +
> +		/* Don't warn on [0xa0000, 0x100000): a known non-
> RAM hole */
> +		if (i < (0xa0000 >> PAGE_SHIFT))
> +			printk(KERN_ERR "GVT: VM%d: can't map GPFN
> %ld!\n",
> +				vgt->vm_id, i);
> +	}
> +
> +	printk("start vmem_map\n");
> +	count = 0;
> +	/* map the >1MB memory */
> +	for (i = 1; i < nr_high_bkt; i++) {
> +		gpfn = i << (VMEM_BUCK_SHIFT - PAGE_SHIFT);
> +		info->vmem_vma[i] =
> xen_remap_domain_mfn_range_in_kernel(
> +				gpfn, VMEM_BUCK_SIZE >> PAGE_SHIFT,
> vgt->vm_id);
> +
> +		if (info->vmem_vma[i] != NULL)
> +			continue;
> +
> +
> +		/* for <4G GPFNs: skip the hole after
> low_mem_max_gpfn */
> +		if (gpfn < (1 << (32 - PAGE_SHIFT)) &&
> +			vgt->low_mem_max_gpfn != 0 &&
> +			gpfn > vgt->low_mem_max_gpfn)
> +			continue;
> +
> +		for (j = gpfn;
> +		     j < ((i + 1) << (VMEM_BUCK_SHIFT -
> PAGE_SHIFT));
> +		     j++) {
> +			info->vmem_vma_4k[j] =
> xen_remap_domain_mfn_range_in_kernel(j, 1, vgt->vm_id);
> +
> +			if (info->vmem_vma_4k[j]) {
> +				count++;
> +				printk(KERN_ERR "map 4k gpa
> (%lx)\n", j << PAGE_SHIFT);
> +			}
> +		}
> +
> +		/* To reduce the number of err messages(some of
> them, due to
> +		 * the MMIO hole, are spurious and harmless) we only
> print a
> +		 * message if it's at every 64MB boundary or >4GB
> memory.
> +		 */
> +		if ((i % 64 == 0) || (i >= (1ULL << (32 -
> VMEM_BUCK_SHIFT))))
> +			printk(KERN_ERR "GVT: VM%d: can't map
> %ldKB\n",
> +				vgt->vm_id, i);
> +	}
> +	printk("end vmem_map (%ld 4k mappings)\n", count);
> +
> +	return 0;
> +err:
> +	vfree(info->vmem_vma);
> +	vfree(info->vmem_vma_low_1mb);
> +	vfree(info->vmem_vma_4k);
> +	info->vmem_vma = info->vmem_vma_low_1mb = info->vmem_vma_4k
> = NULL;
> +	return -ENOMEM;
> +}
> +
> +static void vgt_vmem_destroy(struct vgt_device *vgt)
> +{
> +	int i, j;
> +	unsigned long nr_low_1mb_bkt, nr_high_bkt, nr_high_bkt_4k;
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +
> +	if (vgt->vm_id == 0)
> +		return;
> +
> +	/*
> +	 * Maybe the VM hasn't accessed GEN MMIO(e.g., still in the
> legacy VGA
> +	 * mode), so no mapping is created yet.
> +	 */
> +	if (info->vmem_vma == NULL && info->vmem_vma_low_1mb ==
> NULL)
> +		return;
> +
> +	ASSERT(info->vmem_vma != NULL && info->vmem_vma_low_1mb !=
> NULL);
> +
> +	nr_low_1mb_bkt = VMEM_1MB >> PAGE_SHIFT;
> +	nr_high_bkt = (info->vmem_sz >> VMEM_BUCK_SHIFT);
> +	nr_high_bkt_4k = (info->vmem_sz >> PAGE_SHIFT);
> +
> +	for (i = 0; i < nr_low_1mb_bkt; i++) {
> +		if (info->vmem_vma_low_1mb[i] == NULL)
> +			continue;
> +		xen_unmap_domain_mfn_range_in_kernel(info-
> >vmem_vma_low_1mb[i],
> +				1, vgt->vm_id);
> +	}
> +
> +	for (i = 1; i < nr_high_bkt; i++) {
> +		if (info->vmem_vma[i] == NULL) {
> +			for (j = (i << (VMEM_BUCK_SHIFT -
> PAGE_SHIFT));
> +			     j < ((i + 1) << (VMEM_BUCK_SHIFT -
> PAGE_SHIFT));
> +			     j++) {
> +				if (info->vmem_vma_4k[j] == NULL)
> +					continue;
> +				xen_unmap_domain_mfn_range_in_kernel
> (
> +					info->vmem_vma_4k[j], 1,
> vgt->vm_id);
> +			}
> +			continue;
> +		}
> +		xen_unmap_domain_mfn_range_in_kernel(
> +			info->vmem_vma[i], VMEM_BUCK_SIZE >>
> PAGE_SHIFT,
> +			vgt->vm_id);
> +	}
> +
> +	vfree(info->vmem_vma);
> +	vfree(info->vmem_vma_low_1mb);
> +	vfree(info->vmem_vma_4k);
> +}
> +
> +static int _hvm_mmio_emulation(struct vgt_device *vgt, struct ioreq
> *req)
> +{
> +	int i, sign;
> +	void *gva;
> +	unsigned long gpa;
> +	uint64_t base = gvt_mmio_bar_base(vgt);
> +	uint64_t tmp;
> +	int pvinfo_page;
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +
> +	if (info->vmem_vma == NULL) {
> +		tmp = gvt_host.mpt_ops->pa_to_mmio_offset(vgt, req-
> >addr);
> +		pvinfo_page = (tmp >= VGT_PVINFO_PAGE
> +				&& tmp < (VGT_PVINFO_PAGE +
> VGT_PVINFO_SIZE));
> +		/*
> +		 * hvmloader will read PVINFO to identify if HVM is
> in GVT
> +		 * or VTD. So we don't trigger HVM mapping logic
> here.
> +		 */
> +		if (!pvinfo_page && vgt_hvm_vmem_init(vgt) < 0) {
> +			gvt_err("can not map the memory of
> VM%d!!!\n", vgt->vm_id);
> +			XEN_ASSERT_VM(info->vmem_vma != NULL, vgt);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	sign = req->df ? -1 : 1;
> +
> +	if (req->dir == IOREQ_READ) {
> +		/* MMIO READ */
> +		if (!req->data_is_ptr) {
> +			if (req->count != 1)
> +				goto err_ioreq_count;
> +
> +			//vgt_dbg(GVT_DBG_GENERIC,"HVM_MMIO_read:
> target register (%lx).\n",
> +			//	(unsigned long)req->addr);
> +			if (!gvt_host.emulate_ops-
> >emulate_mmio_read(vgt, req->addr, &req->data, req->size))
> +				return -EINVAL;
> +		}
> +		else {
> +			if ((req->addr + sign * req->count * req-
> >size < base)
> +			   || (req->addr + sign * req->count * req-
> >size >=
> +				base + vgt->state.cfg.bar_size[0]))
> +				goto err_ioreq_range;
> +			//vgt_dbg(GVT_DBG_GENERIC,"HVM_MMIO_read:
> rep %d target memory %lx, slow!\n",
> +			//	req->count, (unsigned long)req-
> >addr);
> +
> +			for (i = 0; i < req->count; i++) {
> +				if (!gvt_host.emulate_ops-
> >emulate_mmio_read(vgt, req->addr + sign * i * req->size,
> +					&tmp, req->size))
> +					return -EINVAL;
> +				gpa = req->data + sign * i * req-
> >size;
> +				if(!vgt->vm_id)
> +					gva = (char
> *)xen_mfn_to_virt(gpa >> PAGE_SHIFT) + offset_in_page(gpa);
> +				else
> +					gva = xen_gpa_to_va(vgt,
> gpa);
> +				if (gva) {
> +					memcpy(gva, &tmp, req-
> >size);
> +				} else
> +					gvt_err("VM %d is trying to
> store mmio data block to invalid gpa: 0x%lx.\n", vgt->vm_id, gpa);
> +			}
> +		}
> +	}
> +	else { /* MMIO Write */
> +		if (!req->data_is_ptr) {
> +			if (req->count != 1)
> +				goto err_ioreq_count;
> +			//vgt_dbg(GVT_DBG_GENERIC,"HVM_MMIO_write:
> target register (%lx).\n", (unsigned long)req->addr);
> +			if (!gvt_host.emulate_ops-
> >emulate_mmio_write(vgt, req->addr, &req->data, req->size))
> +				return -EINVAL;
> +		}
> +		else {
> +			if ((req->addr + sign * req->count * req-
> >size < base)
> +			    || (req->addr + sign * req->count * req-
> >size >=
> +				base + vgt->state.cfg.bar_size[0]))
> +				goto err_ioreq_range;
> +			//vgt_dbg(GVT_DBG_GENERIC,"HVM_MMIO_write:
> rep %d target memory %lx, slow!\n",
> +			//	req->count, (unsigned long)req-
> >addr);
> +
> +			for (i = 0; i < req->count; i++) {
> +				gpa = req->data + sign * i * req-
> >size;
> +				if(!vgt->vm_id)
> +					gva = (char
> *)xen_mfn_to_virt(gpa >> PAGE_SHIFT) + offset_in_page(gpa);
> +				else
> +					gva = xen_gpa_to_va(vgt,
> gpa);
> +
> +				if (gva != NULL)
> +					memcpy(&tmp, gva, req-
> >size);
> +				else {
> +					tmp = 0;
> +					printk(KERN_ERR "GVT: can
> not read gpa = 0x%lx!!!\n", gpa);
> +				}
> +				if (!gvt_host.emulate_ops-
> >emulate_mmio_write(vgt, req->addr + sign * i * req->size, &tmp, req-
> >size))
> +					return -EINVAL;
> +			}
> +		}
> +	}
> +
> +	return 0;
> +
> +err_ioreq_count:
> +	gvt_err("VM(%d): Unexpected %s request count(%d)\n",
> +		vgt->vm_id, req->dir == IOREQ_READ ? "read" :
> "write",
> +		req->count);
> +	return -EINVAL;
> +
> +err_ioreq_range:
> +	gvt_err("VM(%d): Invalid %s request addr end(%016llx)\n",
> +		vgt->vm_id, req->dir == IOREQ_READ ? "read" :
> "write",
> +		req->addr + sign * req->count * req->size);
> +	return -ERANGE;
> +}
> +
> +static bool vgt_hvm_write_cfg_space(struct vgt_device *vgt,
> +	uint64_t addr, unsigned int bytes, unsigned long val)
> +{
> +	/* Low 32 bit of addr is real address, high 32 bit is bdf */
> +	unsigned int port = addr & 0xffffffff;
> +
> +	ASSERT(((bytes == 4) && ((port & 3) == 0)) ||
> +		((bytes == 2) && ((port & 1) == 0)) || (bytes ==
> 1));
> +	gvt_host.emulate_ops->emulate_cfg_write(vgt, port, &val,
> bytes);
> +	return true;
> +}
> +
> +static bool vgt_hvm_read_cfg_space(struct vgt_device *vgt,
> +	uint64_t addr, unsigned int bytes, unsigned long *val)
> +{
> +	unsigned long data;
> +	/* Low 32 bit of addr is real address, high 32 bit is bdf */
> +	unsigned int port = addr & 0xffffffff;
> +
> +	ASSERT (((bytes == 4) && ((port & 3) == 0)) ||
> +		((bytes == 2) && ((port & 1) == 0)) || (bytes ==
> 1));
> +	gvt_host.emulate_ops->emulate_cfg_read(vgt, port, &data,
> bytes);
> +	memcpy(val, &data, bytes);
> +	return true;
> +}
> +
> +static int _hvm_pio_emulation(struct vgt_device *vgt, struct ioreq
> *ioreq)
> +{
> +	int sign;
> +
> +	sign = ioreq->df ? -1 : 1;
> +
> +	if (ioreq->dir == IOREQ_READ) {
> +		/* PIO READ */
> +		if (!ioreq->data_is_ptr) {
> +			if(!vgt_hvm_read_cfg_space(vgt,
> +				ioreq->addr,
> +				ioreq->size,
> +				(unsigned long*)&ioreq->data))
> +				return -EINVAL;
> +		} else {
> +			printk(KERN_ERR "GVT: _hvm_pio_emulation
> read data_ptr %lx\n",
> +			(long)ioreq->data);
> +			goto err_data_ptr;
> +		}
> +	} else {
> +		/* PIO WRITE */
> +		if (!ioreq->data_is_ptr) {
> +			if (!vgt_hvm_write_cfg_space(vgt,
> +				ioreq->addr,
> +				ioreq->size,
> +				(unsigned long)ioreq->data))
> +				return -EINVAL;
> +		} else {
> +			printk(KERN_ERR "GVT: _hvm_pio_emulation
> write data_ptr %lx\n",
> +			(long)ioreq->data);
> +			goto err_data_ptr;
> +		}
> +	}
> +	return 0;
> +err_data_ptr:
> +	/* The data pointer of emulation is guest physical address
> +	 * so far, which goes to Qemu emulation, but hard for
> +	 * GVT driver which doesn't know gpn_2_mfn translation.
> +	 * We may ask hypervisor to use mfn for GVT driver.
> +	 * We mark it as unsupported in case guest really it.
> +	 */
> +	gvt_err("VM(%d): Unsupported %s data_ptr(%lx)\n",
> +		vgt->vm_id, ioreq->dir == IOREQ_READ ? "read" :
> "write",
> +		(long)ioreq->data);
> +	return -EINVAL;
> +}
> +
> +#define PCI_BDF2(b,df)  ((((b) & 0xff) << 8) | ((df) & 0xff))
> +
> +static int vgt_hvm_do_ioreq(struct vgt_device *vgt, struct ioreq
> *ioreq)
> +{
> +	struct pgt_device *pdev = vgt->pdev;
> +	struct pci_dev *pci_dev = pdev->dev_priv->dev->pdev;
> +	uint64_t bdf = PCI_BDF2(pci_dev->bus->number, pci_dev-
> >devfn);
> +
> +	/* When using ioreq-server, sometimes an event channal
> +	 * notification is received with invalid ioreq. Don't
> +	 * know the root cause. Put the workaround here.
> +	 */
> +	if (ioreq->state == STATE_IOREQ_NONE)
> +		return 0;
> +
> +	if (ioreq->type == IOREQ_TYPE_INVALIDATE)
> +		return 0;
> +
> +	switch (ioreq->type) {
> +		case IOREQ_TYPE_PCI_CONFIG:
> +		/* High 32 bit of ioreq->addr is bdf */
> +		if ((ioreq->addr >> 32) != bdf) {
> +			printk(KERN_ERR "GVT: Unexpected PCI Dev %lx
> emulation\n",
> +				(unsigned long) (ioreq->addr>>32));
> +				return -EINVAL;
> +			} else
> +				return _hvm_pio_emulation(vgt,
> ioreq);
> +			break;
> +		case IOREQ_TYPE_COPY:	/* MMIO */
> +			return _hvm_mmio_emulation(vgt, ioreq);
> +			break;
> +		default:
> +			printk(KERN_ERR "GVT: Unknown ioreq type %x
> addr %llx size %u state %u\n",
> +				ioreq->type, ioreq->addr, ioreq-
> >size, ioreq->state);
> +			return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct ioreq *vgt_get_hvm_ioreq(struct vgt_device *vgt, int
> vcpu)
> +{
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +	return &(info->iopage->vcpu_ioreq[vcpu]);
> +}
> +
> +static int vgt_emulation_thread(void *priv)
> +{
> +	struct vgt_device *vgt = (struct vgt_device *)priv;
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +
> +	int vcpu;
> +	int nr_vcpus = info->nr_vcpu;
> +
> +	struct ioreq *ioreq;
> +	int irq, ret;
> +
> +	gvt_info("start kthread for VM%d\n", vgt->vm_id);
> +
> +	ASSERT(info->nr_vcpu <= MAX_HVM_VCPUS_SUPPORTED);
> +
> +	set_freezable();
> +	while (1) {
> +		ret = wait_event_freezable(info->io_event_wq,
> +			kthread_should_stop() ||
> +			bitmap_weight(info->ioreq_pending,
> nr_vcpus));
> +
> +		if (kthread_should_stop())
> +			return 0;
> +
> +		if (ret)
> +			gvt_err("Emulation thread(%d) waken up"
> +				 "by unexpected signal!\n", vgt-
> >vm_id);
> +
> +		for (vcpu = 0; vcpu < nr_vcpus; vcpu++) {
> +			if (!test_and_clear_bit(vcpu, info-
> >ioreq_pending))
> +				continue;
> +
> +			ioreq = vgt_get_hvm_ioreq(vgt, vcpu);
> +
> +			if (vgt_hvm_do_ioreq(vgt, ioreq)) {
> +				xen_pause_domain(vgt->vm_id);
> +				xen_shutdown_domain(vgt->vm_id);
> +			}
> +
> +			ioreq->state = STATE_IORESP_READY;
> +
> +			irq = info->evtchn_irq[vcpu];
> +			notify_remote_via_irq(irq);
> +		}
> +	}
> +
> +	BUG(); /* It's actually impossible to reach here */
> +	return 0;
> +}
> +
> +static inline void vgt_raise_emulation_request(struct vgt_device
> *vgt,
> +	int vcpu)
> +{
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +	set_bit(vcpu, info->ioreq_pending);
> +	if (waitqueue_active(&info->io_event_wq))
> +		wake_up(&info->io_event_wq);
> +}
> +
> +static irqreturn_t vgt_hvm_io_req_handler(int irq, void* dev)
> +{
> +	struct vgt_device *vgt;
> +	struct gvt_hvm_info *info;
> +	int vcpu;
> +
> +	vgt = (struct vgt_device *)dev;
> +	info = vgt->hypervisor_data;
> +
> +	for(vcpu=0; vcpu < info->nr_vcpu; vcpu++){
> +		if(info->evtchn_irq[vcpu] == irq)
> +			break;
> +	}
> +	if (vcpu == info->nr_vcpu){
> +		/*opps, irq is not the registered one*/
> +		gvt_info("Received a IOREQ w/o vcpu target\n");
> +		gvt_info("Possible a false request from event
> binding\n");
> +		return IRQ_NONE;
> +	}
> +
> +	vgt_raise_emulation_request(vgt, vcpu);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void xen_hvm_exit(struct vgt_device *vgt)
> +{
> +	struct gvt_hvm_info *info;
> +	int vcpu;
> +
> +	info = vgt->hypervisor_data;
> +
> +	if (info == NULL)
> +		return;
> +
> +	if (info->emulation_thread != NULL)
> +		kthread_stop(info->emulation_thread);
> +
> +	if (!info->nr_vcpu || info->evtchn_irq == NULL)
> +		goto out1;
> +
> +	if (info->iosrv_id != 0)
> +		hvm_destroy_iorequest_server(vgt);
> +
> +	for (vcpu = 0; vcpu < info->nr_vcpu; vcpu++){
> +		if(info->evtchn_irq[vcpu] >= 0)
> +			unbind_from_irqhandler(info-
> >evtchn_irq[vcpu], vgt);
> +	}
> +
> +	if (info->iopage_vma != NULL)
> +		xen_unmap_domain_mfn_range_in_kernel(info-
> >iopage_vma, 1, vgt->vm_id);
> +
> +	kfree(info->evtchn_irq);
> +
> +out1:
> +	vgt_vmem_destroy(vgt);
> +	kfree(info);
> +}
> +
> +static int xen_hvm_init(struct vgt_device *vgt)
> +{
> +	struct gvt_hvm_info *info;
> +	int vcpu, irq, rc = 0;
> +	struct task_struct *thread;
> +	struct pgt_device *pdev = vgt->pdev;
> +	struct pci_dev *pci_dev = pdev->dev_priv->dev->pdev;
> +
> +	info = kzalloc(sizeof(struct gvt_hvm_info), GFP_KERNEL);
> +	if (info == NULL)
> +		return -ENOMEM;
> +
> +	vgt->hypervisor_data = info;
> +
> +	info->iopage_vma = xen_map_iopage(vgt);
> +	if (info->iopage_vma == NULL) {
> +		printk(KERN_ERR "Failed to map HVM I/O page for
> VM%d\n", vgt->vm_id);
> +		rc = -EFAULT;
> +		goto err;
> +	}
> +	info->iopage = info->iopage_vma->addr;
> +
> +	init_waitqueue_head(&info->io_event_wq);
> +
> +	info->nr_vcpu = xen_get_nr_vcpu(vgt->vm_id);
> +	ASSERT(info->nr_vcpu > 0);
> +	ASSERT(info->nr_vcpu <= MAX_HVM_VCPUS_SUPPORTED);
> +
> +	info->evtchn_irq = kmalloc(info->nr_vcpu * sizeof(int),
> GFP_KERNEL);
> +	if (info->evtchn_irq == NULL){
> +		rc = -ENOMEM;
> +		goto err;
> +	}
> +	for( vcpu = 0; vcpu < info->nr_vcpu; vcpu++ )
> +		info->evtchn_irq[vcpu] = -1;
> +
> +	rc = hvm_map_pcidev_to_ioreq_server(vgt, PCI_BDF2(pci_dev-
> >bus->number, pci_dev->devfn));
> +	if (rc < 0)
> +		goto err;
> +	rc = hvm_toggle_iorequest_server(vgt, 1);
> +	if (rc < 0)
> +		goto err;
> +
> +	for (vcpu = 0; vcpu < info->nr_vcpu; vcpu++){
> +		irq = bind_interdomain_evtchn_to_irqhandler( vgt-
> >vm_id,
> +				info->iopage-
> >vcpu_ioreq[vcpu].vp_eport,
> +				vgt_hvm_io_req_handler, 0,
> +				"vgt", vgt );
> +		if ( irq < 0 ){
> +			rc = irq;
> +			printk(KERN_ERR "Failed to bind event
> channle for vgt HVM IO handler, rc=%d\n", rc);
> +			goto err;
> +		}
> +		info->evtchn_irq[vcpu] = irq;
> +	}
> +
> +	thread = kthread_run(vgt_emulation_thread, vgt,
> +			"vgt_emulation:%d", vgt->vm_id);
> +	if(IS_ERR(thread))
> +		goto err;
> +	info->emulation_thread = thread;
> +
> +	return 0;
> +
> +err:
> +	xen_hvm_exit(vgt);
> +	return rc;
> +}
> +
> +static void *xen_gpa_to_va(struct vgt_device *vgt, unsigned long
> gpa)
> +{
> +	unsigned long buck_index, buck_4k_index;
> +	struct gvt_hvm_info *info = vgt->hypervisor_data;
> +
> +	if (!vgt->vm_id)
> +		return (char*)xen_mfn_to_virt(gpa>>PAGE_SHIFT) +
> (gpa & (PAGE_SIZE-1));
> +	/*
> +	 * At the beginning of _hvm_mmio_emulation(), we already
> initialize
> +	 * info->vmem_vma and info->vmem_vma_low_1mb.
> +	 */
> +	ASSERT(info->vmem_vma != NULL && info->vmem_vma_low_1mb !=
> NULL);
> +
> +	/* handle the low 1MB memory */
> +	if (gpa < VMEM_1MB) {
> +		buck_index = gpa >> PAGE_SHIFT;
> +		if (!info->vmem_vma_low_1mb[buck_index])
> +			return NULL;
> +
> +		return (char*)(info->vmem_vma_low_1mb[buck_index]-
> >addr) +
> +			(gpa & ~PAGE_MASK);
> +
> +	}
> +
> +	/* handle the >1MB memory */
> +	buck_index = gpa >> VMEM_BUCK_SHIFT;
> +
> +	if (!info->vmem_vma[buck_index]) {
> +		buck_4k_index = gpa >> PAGE_SHIFT;
> +		if (!info->vmem_vma_4k[buck_4k_index]) {
> +			if (buck_4k_index > vgt->low_mem_max_gpfn)
> +				gvt_err("GVT failed to map
> gpa=0x%lx?\n", gpa);
> +			return NULL;
> +		}
> +
> +		return (char*)(info->vmem_vma_4k[buck_4k_index]-
> >addr) +
> +			(gpa & ~PAGE_MASK);
> +	}
> +
> +	return (char*)(info->vmem_vma[buck_index]->addr) +
> +		(gpa & (VMEM_BUCK_SIZE -1));
> +}
> +
> +static bool xen_read_va(struct vgt_device *vgt, void *va, void *val,
> +		int len, int atomic)
> +{
> +	memcpy(val, va, len);
> +
> +	return true;
> +}
> +
> +static bool xen_write_va(struct vgt_device *vgt, void *va, void
> *val,
> +		int len, int atomic)
> +{
> +	memcpy(va, val, len);
> +	return true;
> +}
> +
> +static struct gvt_kernel_dm xengt_kdm = {
> +	.name = "xengt_kdm",
> +	.g2m_pfn = xen_g2m_pfn,
> +	.pause_domain = xen_pause_domain,
> +	.shutdown_domain = xen_shutdown_domain,
> +	.map_mfn_to_gpfn = xen_map_mfn_to_gpfn,
> +	.set_trap_area = xen_set_trap_area,
> +	.set_wp_pages = xen_set_guest_page_writeprotection,
> +	.unset_wp_pages = xen_clear_guest_page_writeprotection,
> +	.detect_host = xen_detect_host,
> +	.from_virt_to_mfn = xen_virt_to_mfn,
> +	.from_mfn_to_virt = xen_mfn_to_virt,
> +	.inject_msi = xen_inject_msi,
> +	.hvm_init = xen_hvm_init,
> +	.hvm_exit = xen_hvm_exit,
> +	.gpa_to_va = xen_gpa_to_va,
> +	.read_va = xen_read_va,
> +	.write_va = xen_write_va,
> +};
> +EXPORT_SYMBOL(xengt_kdm);
> +
> +static int __init xengt_init(void)
> +{
> +       if (!xen_initial_domain())
> +               return -EINVAL;
> +       printk(KERN_INFO "xengt: loaded\n");
> +       return 0;
> +}
> +
> +static void __exit xengt_exit(void)
> +{
> +	printk(KERN_INFO "xengt: unloaded\n");
> +}
> +
> +module_init(xengt_init);
> +module_exit(xengt_exit);
> diff --git a/include/xen/interface/hvm/hvm_op.h
> b/include/xen/interface/hvm/hvm_op.h
> index 956a046..20577cc 100644
> --- a/include/xen/interface/hvm/hvm_op.h
> +++ b/include/xen/interface/hvm/hvm_op.h
> @@ -21,6 +21,8 @@
>  #ifndef __XEN_PUBLIC_HVM_HVM_OP_H__
>  #define __XEN_PUBLIC_HVM_HVM_OP_H__
>  
> +#include <xen/interface/event_channel.h>
> +
>  /* Get/set subcommands: the second argument of the hypercall is a
>   * pointer to a xen_hvm_param struct. */
>  #define HVMOP_set_param           0
> @@ -42,12 +44,41 @@ struct xen_hvm_pagetable_dying {
>  };
>  typedef struct xen_hvm_pagetable_dying xen_hvm_pagetable_dying_t;
>  DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_pagetable_dying_t);
> - 
> +
> +/* MSI injection for emulated devices */
> +#define HVMOP_inject_msi         16
> +struct xen_hvm_inject_msi {
> +    /* Domain to be injected */
> +    domid_t   domid;
> +    /* Data -- lower 32 bits */
> +    uint32_t  data;
> +    /* Address (0xfeexxxxx) */
> +    uint64_t  addr;
> +};
> +typedef struct xen_hvm_inject_msi xen_hvm_inject_msi_t;
> +DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_inject_msi_t);
> +
>  enum hvmmem_type_t {
>      HVMMEM_ram_rw,             /* Normal read/write guest RAM */
>      HVMMEM_ram_ro,             /* Read-only; writes are discarded */
>      HVMMEM_mmio_dm,            /* Reads and write go to the device
> model */
> +    HVMMEM_mmio_write_dm       /* Read-only; writes go to the device
> model */
> +};
> +
> +#define HVMOP_set_mem_type    8
> +/* Notify that a region of memory is to be treated in a specific
> way. */
> +struct xen_hvm_set_mem_type {
> +        /* Domain to be updated. */
> +        domid_t domid;
> +        /* Memory type */
> +        uint16_t hvmmem_type;
> +        /* Number of pages. */
> +        uint32_t nr;
> +        /* First pfn. */
> +        uint64_t first_pfn;
>  };
> +typedef struct xen_hvm_set_mem_type xen_hvm_set_mem_type_t;
> +DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_set_mem_type_t);
>  
>  #define HVMOP_get_mem_type    15
>  /* Return hvmmem_type_t for the specified pfn. */
> @@ -62,4 +93,148 @@ struct xen_hvm_get_mem_type {
>  };
>  DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_get_mem_type);
>  
> +#define HVMOP_vgt_wp_pages         27  /* writeprotection to guest
> pages */
> +#define MAX_WP_BATCH_PAGES         128
> +struct xen_hvm_vgt_wp_pages {
> +	uint16_t domid;
> +	uint16_t set;            /* 1: set WP, 0: remove WP */
> +	uint16_t nr_pages;
> +	unsigned long  wp_pages[MAX_WP_BATCH_PAGES];
> +};
> +typedef struct xen_hvm_vgt_wp_pages xen_hvm_vgt_wp_pages_t;
> +
> +/*
> + * IOREQ Servers
> + *
> + * The interface between an I/O emulator an Xen is called an IOREQ
> Server.
> + * A domain supports a single 'legacy' IOREQ Server which is
> instantiated if
> + * parameter...
> + *
> + * HVM_PARAM_IOREQ_PFN is read (to get the gmfn containing the
> synchronous
> + * ioreq structures), or...
> + * HVM_PARAM_BUFIOREQ_PFN is read (to get the gmfn containing the
> buffered
> + * ioreq ring), or...
> + * HVM_PARAM_BUFIOREQ_EVTCHN is read (to get the event channel that
> Xen uses
> + * to request buffered I/O emulation).
> + *
> + * The following hypercalls facilitate the creation of IOREQ Servers
> for
> + * 'secondary' emulators which are invoked to implement port I/O,
> memory, or
> + * PCI config space ranges which they explicitly register.
> + */
> +typedef uint16_t ioservid_t;
> +
> +/*
> + * HVMOP_create_ioreq_server: Instantiate a new IOREQ Server for a
> secondary
> + *                            emulator servicing domain <domid>.
> + *
> + * The <id> handed back is unique for <domid>. If <handle_bufioreq>
> is zero
> + * the buffered ioreq ring will not be allocated and hence all
> emulation
> + * requestes to this server will be synchronous.
> + */
> +#define HVMOP_create_ioreq_server 17
> +struct xen_hvm_create_ioreq_server {
> +    domid_t domid;           /* IN - domain to be serviced */
> +    uint8_t handle_bufioreq; /* IN - should server handle buffered
> ioreqs */
> +    ioservid_t id;           /* OUT - server id */
> +};
> +typedef struct xen_hvm_create_ioreq_server
> xen_hvm_create_ioreq_server_t;
> +DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_create_ioreq_server_t);
> +
> +/*
> + * HVMOP_get_ioreq_server_info: Get all the information necessary to
> access
> + *                              IOREQ Server <id>.
> + *
> + * The emulator needs to map the synchronous ioreq structures and
> buffered
> + * ioreq ring (if it exists) that Xen uses to request emulation.
> These are
> + * hosted in domain <domid>'s gmfns <ioreq_pfn> and <bufioreq_pfn>
> + * respectively. In addition, if the IOREQ Server is handling
> buffered
> + * emulation requests, the emulator needs to bind to event channel
> + * <bufioreq_port> to listen for them. (The event channels used for
> + * synchronous emulation requests are specified in the per-CPU ioreq
> + * structures in <ioreq_pfn>).
> + * If the IOREQ Server is not handling buffered emulation requests
> then the
> + * values handed back in <bufioreq_pfn> and <bufioreq_port> will
> both be 0.
> + */
> +#define HVMOP_get_ioreq_server_info 18
> +struct xen_hvm_get_ioreq_server_info {
> +    domid_t domid;                 /* IN - domain to be serviced */
> +    ioservid_t id;                 /* IN - server id */
> +    evtchn_port_t bufioreq_port;   /* OUT - buffered ioreq port */
> +    uint64_t ioreq_pfn;    /* OUT - sync ioreq pfn */
> +    uint64_t bufioreq_pfn; /* OUT - buffered ioreq pfn */
> +};
> +typedef struct xen_hvm_get_ioreq_server_info
> xen_hvm_get_ioreq_server_info_t;
> +DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_get_ioreq_server_info_t);
> +
> +/*
> + * HVM_map_io_range_to_ioreq_server: Register an I/O range of domain
> <domid>
> + *                                   for emulation by the client of
> IOREQ
> + *                                   Server <id>
> + * HVM_unmap_io_range_from_ioreq_server: Deregister an I/O range of
> <domid>
> + *                                       for emulation by the client
> of IOREQ
> + *                                       Server <id>
> + *
> + * There are three types of I/O that can be emulated: port I/O,
> memory accesses
> + * and PCI config space accesses. The <type> field denotes which
> type of range
> + * the <start> and <end> (inclusive) fields are specifying.
> + * PCI config space ranges are specified by
> segment/bus/device/function values
> + * which should be encoded using the HVMOP_PCI_SBDF helper macro
> below.
> + *
> + * NOTE: unless an emulation request falls entirely within a range
> mapped
> + * by a secondary emulator, it will not be passed to that emulator.
> + */
> +#define HVMOP_map_io_range_to_ioreq_server 19
> +#define HVMOP_unmap_io_range_from_ioreq_server 20
> +struct xen_hvm_io_range {
> +    domid_t domid;               /* IN - domain to be serviced */
> +    ioservid_t id;               /* IN - server id */
> +    uint32_t type;               /* IN - type of range */
> +# define HVMOP_IO_RANGE_PORT   0 /* I/O port range */
> +# define HVMOP_IO_RANGE_MEMORY 1 /* MMIO range */
> +# define HVMOP_IO_RANGE_PCI    2 /* PCI segment/bus/dev/func range
> */
> +    uint64_t start, end; /* IN - inclusive start and end of range */
> +};
> +typedef struct xen_hvm_io_range xen_hvm_io_range_t;
> +DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_io_range_t);
> +
> +#define HVMOP_PCI_SBDF(s,b,d,f)                 \
> +       ((((s) & 0xffff) << 16) |                   \
> +        (((b) & 0xff) << 8) |                      \
> +        (((d) & 0x1f) << 3) |                      \
> +        ((f) & 0x07))
> +
> +/*
> + * HVMOP_destroy_ioreq_server: Destroy the IOREQ Server <id>
> servicing domain
> + *                             <domid>.
> + *
> + * Any registered I/O ranges will be automatically deregistered.
> + */
> +#define HVMOP_destroy_ioreq_server 21
> +struct xen_hvm_destroy_ioreq_server {
> +    domid_t domid; /* IN - domain to be serviced */
> +    ioservid_t id; /* IN - server id */
> +};
> +typedef struct xen_hvm_destroy_ioreq_server
> xen_hvm_destroy_ioreq_server_t;
> +DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_destroy_ioreq_server_t);
> +
> +
> +/*
> + * HVMOP_set_ioreq_server_state: Enable or disable the IOREQ Server
> <id> servicing
> + *                               domain <domid>.
> + *
> + * The IOREQ Server will not be passed any emulation requests until
> it is in the
> + * enabled state.
> + * Note that the contents of the ioreq_pfn and bufioreq_fn (see
> + * HVMOP_get_ioreq_server_info) are not meaningful until the IOREQ
> Server is in
> + * the enabled state.
> + */
> +#define HVMOP_set_ioreq_server_state 22
> +struct xen_hvm_set_ioreq_server_state {
> +    domid_t domid;   /* IN - domain to be serviced */
> +    ioservid_t id;   /* IN - server id */
> +    uint8_t enabled; /* IN - enabled? */
> +};
> +typedef struct xen_hvm_set_ioreq_server_state
> xen_hvm_set_ioreq_server_state_t;
> +DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_set_ioreq_server_state_t);
> +
>  #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */
> diff --git a/include/xen/interface/hvm/ioreq.h
> b/include/xen/interface/hvm/ioreq.h
> new file mode 100644
> index 0000000..6bbf4e4
> --- /dev/null
> +++ b/include/xen/interface/hvm/ioreq.h
> @@ -0,0 +1,132 @@
> +/*
> + * This program is free software; you can redistribute it and/or
> modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but
> WITHOUT
> + * ANY WARRANTY; without even the implied warranty of
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License
> along with
> + * this program; if not, write to the Free Software Foundation,
> Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +#ifndef _IOREQ_H_
> +#define _IOREQ_H_
> +
> +#define IOREQ_READ      1
> +#define IOREQ_WRITE     0
> +
> +#define STATE_IOREQ_NONE        0
> +#define STATE_IOREQ_READY       1
> +#define STATE_IOREQ_INPROCESS   2
> +#define STATE_IORESP_READY      3
> +
> +#define IOREQ_TYPE_PIO          0 /* pio */
> +#define IOREQ_TYPE_COPY         1 /* mmio ops */
> +#define IOREQ_TYPE_PCI_CONFIG   2
> +#define IOREQ_TYPE_TIMEOFFSET   7
> +#define IOREQ_TYPE_INVALIDATE   8 /* mapcache */
> +
> +/*
> + * VMExit dispatcher should cooperate with instruction decoder to
> + * prepare this structure and notify service OS and DM by sending
> + * virq
> + */
> +struct ioreq {
> +    uint64_t addr;          /* physical address */
> +    uint64_t data;          /* data (or paddr of data) */
> +    uint32_t count;         /* for rep prefixes */
> +    uint32_t size;          /* size in bytes */
> +    uint32_t vp_eport;      /* evtchn for notifications to/from
> device model */
> +    uint16_t _pad0;
> +    uint8_t state:4;
> +    uint8_t data_is_ptr:1;  /* if 1, data above is the guest paddr
> +                             * of the real data to use. */
> +    uint8_t dir:1;          /* 1=read, 0=write */
> +    uint8_t df:1;
> +    uint8_t _pad1:1;
> +    uint8_t type;           /* I/O type */
> +};
> +typedef struct ioreq ioreq_t;
> +
> +struct shared_iopage {
> +    struct ioreq vcpu_ioreq[1];
> +};
> +typedef struct shared_iopage shared_iopage_t;
> +
> +struct buf_ioreq {
> +    uint8_t  type;   /* I/O type                    */
> +    uint8_t  pad:1;
> +    uint8_t  dir:1;  /* 1=read, 0=write             */
> +    uint8_t  size:2; /* 0=>1, 1=>2, 2=>4, 3=>8. If 8, use two
> buf_ioreqs */
> +    uint32_t addr:20;/* physical address            */
> +    uint32_t data;   /* data                        */
> +};
> +typedef struct buf_ioreq buf_ioreq_t;
> +
> +#define IOREQ_BUFFER_SLOT_NUM     511 /* 8 bytes each, plus 2 4-byte 
> indexes */
> +struct buffered_iopage {
> +    unsigned int read_pointer;
> +    unsigned int write_pointer;
> +    buf_ioreq_t buf_ioreq[IOREQ_BUFFER_SLOT_NUM];
> +}; /* NB. Size of this structure must be no greater than one page.
> */
> +typedef struct buffered_iopage buffered_iopage_t;
> +
> +#if defined(__ia64__)
> +struct pio_buffer {
> +    uint32_t page_offset;
> +    uint32_t pointer;
> +    uint32_t data_end;
> +    uint32_t buf_size;
> +    void *opaque;
> +};
> +
> +#define PIO_BUFFER_IDE_PRIMARY   0 /* I/O port = 0x1F0 */
> +#define PIO_BUFFER_IDE_SECONDARY 1 /* I/O port = 0x170 */
> +#define PIO_BUFFER_ENTRY_NUM     2
> +struct buffered_piopage {
> +    struct pio_buffer pio[PIO_BUFFER_ENTRY_NUM];
> +    uint8_t buffer[1];
> +};
> +#endif /* defined(__ia64__) */
> +
> +/*
> + * ACPI Control/Event register locations. Location is controlled by
> a
> + * version number in HVM_PARAM_ACPI_IOPORTS_LOCATION.
> + */
> +
> +/* Version 0 (default): Traditional Xen locations. */
> +#define ACPI_PM1A_EVT_BLK_ADDRESS_V0 0x1f40
> +#define ACPI_PM1A_CNT_BLK_ADDRESS_V0 (ACPI_PM1A_EVT_BLK_ADDRESS_V0 +
> 0x04)
> +#define ACPI_PM_TMR_BLK_ADDRESS_V0   (ACPI_PM1A_EVT_BLK_ADDRESS_V0 +
> 0x08)
> +#define ACPI_GPE0_BLK_ADDRESS_V0     (ACPI_PM_TMR_BLK_ADDRESS_V0 +
> 0x20)
> +#define ACPI_GPE0_BLK_LEN_V0         0x08
> +
> +/* Version 1: Locations preferred by modern Qemu. */
> +#define ACPI_PM1A_EVT_BLK_ADDRESS_V1 0xb000
> +#define ACPI_PM1A_CNT_BLK_ADDRESS_V1 (ACPI_PM1A_EVT_BLK_ADDRESS_V1 +
> 0x04)
> +#define ACPI_PM_TMR_BLK_ADDRESS_V1   (ACPI_PM1A_EVT_BLK_ADDRESS_V1 +
> 0x08)
> +#define ACPI_GPE0_BLK_ADDRESS_V1     0xafe0
> +#define ACPI_GPE0_BLK_LEN_V1         0x04
> +
> +/* Compatibility definitions for the default location (version 0).
> */
> +#define ACPI_PM1A_EVT_BLK_ADDRESS    ACPI_PM1A_EVT_BLK_ADDRESS_V0
> +#define ACPI_PM1A_CNT_BLK_ADDRESS    ACPI_PM1A_CNT_BLK_ADDRESS_V0
> +#define ACPI_PM_TMR_BLK_ADDRESS      ACPI_PM_TMR_BLK_ADDRESS_V0
> +#define ACPI_GPE0_BLK_ADDRESS        ACPI_GPE0_BLK_ADDRESS_V0
> +#define ACPI_GPE0_BLK_LEN            ACPI_GPE0_BLK_LEN_V0
> +
> +
> +#endif /* _IOREQ_H_ */
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-set-style: "BSD"
> + * c-basic-offset: 4
> + * tab-width: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/include/xen/interface/memory.h
> b/include/xen/interface/memory.h
> index 2ecfe4f..92f18c5 100644
> --- a/include/xen/interface/memory.h
> +++ b/include/xen/interface/memory.h
> @@ -9,6 +9,7 @@
>  #ifndef __XEN_PUBLIC_MEMORY_H__
>  #define __XEN_PUBLIC_MEMORY_H__
>  
> +#include <xen/interface/event_channel.h>
>  #include <linux/spinlock.h>
>  
>  /*
> @@ -141,6 +142,11 @@ struct xen_machphys_mfn_list {
>  DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list);
>  
>  /*
> + * Returns the maximum GPFN in use by the guest, or -ve errcode on
> failure.
> + */
> +#define XENMEM_maximum_gpfn         14
> +
> +/*
>   * Returns the location in virtual address space of the
> machine_to_phys
>   * mapping table. Architectures which do not have a m2p table, or
> which do not
>   * map it by default into guest address space, do not implement this
> command.
> @@ -263,4 +269,26 @@ struct xen_remove_from_physmap {
>  };
>  DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
>  
> +/*
> + * Translate the given guest PFNs to MFNs
> + */
> +#define XENMEM_get_mfn_from_pfn    25
> +struct xen_get_mfn_from_pfn {
> +    /*
> +     * Pointer to buffer to fill with list of pfn.
> +     * for IN, it contains the guest PFN that need to translated
> +     * for OUT, it contains the translated MFN. or INVALID_MFN if no
> valid translation
> +     */
> +    GUEST_HANDLE(ulong) pfn_list;
> +
> +    /*
> +     * IN: Size of the pfn_array.
> +     */
> +    unsigned int nr_pfns;
> +
> +    /* IN: which domain */
> +    domid_t domid;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_get_mfn_from_pfn);
> +
>  #endif /* __XEN_PUBLIC_MEMORY_H__ */
> diff --git a/include/xen/interface/xen.h
> b/include/xen/interface/xen.h
> index 78a38f1..c7e0f32 100644
> --- a/include/xen/interface/xen.h
> +++ b/include/xen/interface/xen.h
> @@ -756,6 +756,112 @@ struct tmem_op {
>  
>  DEFINE_GUEST_HANDLE(u64);
>  
> +/* XEN_DOMCTL_getdomaininfo */
> +struct xen_domctl_getdomaininfo {
> +        /* OUT variables. */
> +        domid_t  domain;              /* Also echoed in
> domctl.domain */
> +        /* Domain is scheduled to die. */
> +#define _XEN_DOMINF_dying     0
> +#define XEN_DOMINF_dying      (1U<<_XEN_DOMINF_dying)
> +        /* Domain is an HVM guest (as opposed to a PV guest). */
> +#define _XEN_DOMINF_hvm_guest 1
> +#define XEN_DOMINF_hvm_guest  (1U<<_XEN_DOMINF_hvm_guest)
> +        /* The guest OS has shut down. */
> +#define _XEN_DOMINF_shutdown  2
> +#define XEN_DOMINF_shutdown   (1U<<_XEN_DOMINF_shutdown)
> +        /* Currently paused by control software. */
> +#define _XEN_DOMINF_paused    3
> +#define XEN_DOMINF_paused     (1U<<_XEN_DOMINF_paused)
> +        /* Currently blocked pending an event.     */
> +#define _XEN_DOMINF_blocked   4
> +#define XEN_DOMINF_blocked    (1U<<_XEN_DOMINF_blocked)
> +        /* Domain is currently running.            */
> +#define _XEN_DOMINF_running   5
> +#define XEN_DOMINF_running    (1U<<_XEN_DOMINF_running)
> +        /* Being debugged.  */
> +#define _XEN_DOMINF_debugged  6
> +#define XEN_DOMINF_debugged   (1U<<_XEN_DOMINF_debugged)
> +        /* XEN_DOMINF_shutdown guest-supplied code.  */
> +#define XEN_DOMINF_shutdownmask 255
> +#define XEN_DOMINF_shutdownshift 16
> +        uint32_t flags;              /* XEN_DOMINF_* */
> +        aligned_u64 tot_pages;
> +        aligned_u64 max_pages;
> +        aligned_u64 outstanding_pages;
> +        aligned_u64 shr_pages;
> +        aligned_u64 paged_pages;
> +        aligned_u64 shared_info_frame; /* GMFN of shared_info struct
> */
> +        aligned_u64 cpu_time;
> +        uint32_t nr_online_vcpus;    /* Number of VCPUs currently
> online. */
> +        uint32_t max_vcpu_id;        /* Maximum VCPUID in use by
> this domain. */
> +        uint32_t ssidref;
> +        xen_domain_handle_t handle;
> +        uint32_t cpupool;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getdomaininfo);
> +
> +#define XEN_DOMCTL_INTERFACE_VERSION 0x0000000a
> +#define XEN_DOMCTL_pausedomain                    3
> +#define XEN_DOMCTL_getdomaininfo                  5
> +#define XEN_DOMCTL_memory_mapping                 39
> +#define XEN_DOMCTL_iomem_permission               20
> +
> +
> +#define XEN_DOMCTL_vgt_io_trap                    700
> +
> +#define MAX_VGT_IO_TRAP_INFO 4
> +
> +struct vgt_io_trap_info {
> +        uint64_t s;
> +        uint64_t e;
> +};
> +
> +struct xen_domctl_vgt_io_trap {
> +        uint32_t n_pio;
> +        struct vgt_io_trap_info pio[MAX_VGT_IO_TRAP_INFO];
> +
> +        uint32_t n_mmio;
> +        struct vgt_io_trap_info mmio[MAX_VGT_IO_TRAP_INFO];
> +};
> +
> +/* Bind machine I/O address range -> HVM address range. */
> +/* XEN_DOMCTL_memory_mapping */
> +#define DPCI_ADD_MAPPING        1
> +#define DPCI_REMOVE_MAPPING     0
> +struct xen_domctl_memory_mapping {
> +        aligned_u64 first_gfn; /* first page (hvm guest phys page)
> in range */
> +        aligned_u64 first_mfn; /* first page (machine page) in
> range. */
> +        aligned_u64 nr_mfns;   /* number of pages in range (>0) */
> +        uint32_t add_mapping;  /* Add or remove mapping */
> +        uint32_t padding;      /* padding for 64-bit aligned struct
> */
> +};
> +typedef struct xen_domctl_memory_mapping
> xen_domctl_memory_mapping_t;
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_memory_mapping_t);
> +
> +/* XEN_DOMCTL_iomem_permission */
> +struct xen_domctl_iomem_permission {
> +    aligned_u64 first_mfn;/* first page (physical page number) in
> range */
> +    aligned_u64 nr_mfns;  /* number of pages in range (>0) */
> +    uint8_t  allow_access;     /* allow (!0) or deny (0) access to
> range? */
> +};
> +typedef struct xen_domctl_iomem_permission
> xen_domctl_iomem_permission_t;
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_iomem_permission_t);
> +
> +struct xen_domctl {
> +        uint32_t cmd;
> +        uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION
> */
> +        domid_t  domain;
> +        union {
> +                struct xen_domctl_getdomaininfo     getdomaininfo;
> +                struct xen_domctl_vgt_io_trap       vgt_io_trap;
> +                struct xen_domctl_memory_mapping    memory_mapping;
> +                struct xen_domctl_iomem_permission      iomem_perm;
> +                uint8_t                             pad[256];
> +        }u;
> +};
> +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl);
> +
> +
>  #else /* __ASSEMBLY__ */
>  
>  /* In assembly code we cannot use C numeric constant suffixes. */
> diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
> index 86abe07..dde9eb0 100644
> --- a/include/xen/xen-ops.h
> +++ b/include/xen/xen-ops.h
> @@ -123,4 +123,9 @@ static inline void
> xen_preemptible_hcall_end(void)
>  
>  #endif /* CONFIG_PREEMPT */
>  
> +struct vm_struct * xen_remap_domain_mfn_range_in_kernel(unsigned
> long mfn,
> +        int nr, unsigned domid);
> +void xen_unmap_domain_mfn_range_in_kernel(struct vm_struct *area,
> int nr,
> +                unsigned domid);
> +
>  #endif /* INCLUDE_XEN_OPS_H */
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 17/29] gvt: Xen hypervisor GVT-g MPT module
  2016-01-28 11:33   ` Joonas Lahtinen
@ 2016-01-28 12:50     ` Zhiyuan Lv
  0 siblings, 0 replies; 49+ messages in thread
From: Zhiyuan Lv @ 2016-01-28 12:50 UTC (permalink / raw)
  To: Joonas Lahtinen; +Cc: daniel.vetter, intel-gfx, david.j.cowperthwaite, igvt-g

Hi Joonas,

On Thu, Jan 28, 2016 at 01:33:33PM +0200, Joonas Lahtinen wrote:
> Hi,
> 
> See the file MAINTAINERS and add Cc: lines according to "XEN HYPERVISOR
> INTERFACE". Also I think it'll be useful to split the i915 changes to a
> separate patch next int he series (as the reviewer will be different).
> 
> We will have to wait for Xen maintainers to take a position on this. Is
> there KVM counterparts for this stuff incoming?

Yeah, we have KVM part as well. There will be separate mails to discuss
with Xen/KVM community the Mediate-Pass-Through (MPT) interface and its
implementation. This patch can be ignored right now. It is here just to make
the whole patchset functional. Thanks!

Regards,
-Zhiyuan

> 
> On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
> > This is the xen hypervisor MPT module which let GVT-g be able to run
> > under
> > Xen hypervisor.
> > 
> 
> Cc: xen-devel@lists.xenproject.org
> ...and so on...
> 
> Regards, Joonas
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* ✗ Fi.CI.BAT: failure for iGVT-g implementation in i915
  2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
                   ` (28 preceding siblings ...)
  2016-01-28 10:21 ` [RFC 29/29] drm/i915: gvt: vGPU command scanner Zhi Wang
@ 2016-01-28 17:15 ` Patchwork
  29 siblings, 0 replies; 49+ messages in thread
From: Patchwork @ 2016-01-28 17:15 UTC (permalink / raw)
  To: Wang, Zhi A; +Cc: intel-gfx

== Summary ==

Series 2895v1 iGVT-g implementation in i915
Apply patch: http://patchwork.freedesktop.org/api/1.0/series/2895/revisions/1/mbox/
Applying: drm/i915/gvt: Introduce the basic architecture of GVT-g
Using index info to reconstruct a base tree...
M	drivers/gpu/drm/i915/i915_dma.c
M	drivers/gpu/drm/i915/i915_drv.h
Falling back to patching base and 3-way merge...
Auto-merging drivers/gpu/drm/i915/i915_drv.h
Auto-merging drivers/gpu/drm/i915/i915_dma.c
CONFLICT (content): Merge conflict in drivers/gpu/drm/i915/i915_dma.c
Failed to merge in the changes.
Patch failed at 0001 drm/i915/gvt: Introduce the basic architecture of GVT-g
The copy of the patch that failed is found in:
   /home/builder/igt/drm-intel/.git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
Unstaged changes after reset:
M	arch/x86/include/asm/xen/interface.h
M	drivers/gpu/drm/i915/Kconfig
M	drivers/gpu/drm/i915/Makefile
M	drivers/gpu/drm/i915/i915_drv.h
M	drivers/gpu/drm/i915/i915_vgpu.h
M	include/xen/interface/xen.h
Series 2895 revision 1 failed at git-am

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g
  2016-01-28 10:21 ` [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g Zhi Wang
@ 2016-01-29 13:57   ` Joonas Lahtinen
  2016-01-29 16:48     ` Chris Wilson
  2016-02-03  6:01     ` Zhi Wang
  0 siblings, 2 replies; 49+ messages in thread
From: Joonas Lahtinen @ 2016-01-29 13:57 UTC (permalink / raw)
  To: Zhi Wang, intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

Hi,

TL;DR Overall, we have same problem as with the scheduler series, there
is too much placeholder stuff for easy review. Just squash enough code
into one commit so it actually does something logical that can be
reviewed and then extend it later. Then it can be reviewed and pushed.
Just splitting the code down to achieve smaller patches is not the
right thing to do.

Comments on the overall code: You need to document all header file
functions (in the source files), and it is good to document the static
functions within a file too, to make future maintenance easier.

It is not about splitting the code down to small chunks, but splitting
it down to small *logical* chunks. It doesn't make sense to commit
dozens of empty bodied functions for review, and then later add their
code.

If you add functions, only add them at a patch that takes them into use
too, unless we're talking about general purpose shared code. And also
remember to add the function body and documentation header. If you
simply add a "return 0;" or similar function body, do add a comment to
why the function does not exist and when it will.

Then, there is a trend of having a boolean return values in the code.
When possible, it should rather be int and the cause for failure should
be propagated from the last level all the way to up (-ENOMEN etc.).
This way debugging becomes easier and if new error conditions appear,
there is less of a maintenance burden to add the propagation later.

Finally, make sure to look at the existing driver parts and
	https://www.kernel.org/doc/Documentation/CodingStyle
for proper coding style. There are lots of whitespace fixes needed in
this series, like array initializations.

I hope to see this first patch rerolled so that you squash some of the
later commits into it so that all functions have a body and you add
documentation for the functions so I can both see what it should do and
what it actually does. Only reroll the first patch, to keep the
iterative step smaller. Lets only then continue with the rest of the
series once we've reached a consensus on the formatting and style
basics.

See more comments below.

On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
> This patch introduces the very basic framework of GVT-g device model,
> includes basic prototypes, definitions, initialization.
> ---
>  arch/x86/include/asm/xen/interface.h  |   3 +
>  drivers/gpu/drm/i915/Kconfig          |  16 ++
>  drivers/gpu/drm/i915/Makefile         |   2 +
>  drivers/gpu/drm/i915/gvt/Makefile     |   5 +
>  drivers/gpu/drm/i915/gvt/debug.h      |  72 +++++++
>  drivers/gpu/drm/i915/gvt/fb_decoder.c |  34 ++++
>  drivers/gpu/drm/i915/gvt/fb_decoder.h | 110 ++++++++++
>  drivers/gpu/drm/i915/gvt/gvt.c        | 366 ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/gvt/gvt.h        | 130 ++++++++++++
>  drivers/gpu/drm/i915/gvt/hypercall.h  |  30 +++
>  drivers/gpu/drm/i915/gvt/mpt.h        |  97 +++++++++
>  drivers/gpu/drm/i915/gvt/params.c     |  29 +++
>  drivers/gpu/drm/i915/gvt/params.h     |  34 ++++
>  drivers/gpu/drm/i915/gvt/reg.h        |  34 ++++
>  drivers/gpu/drm/i915/i915_dma.c       |  19 ++
>  drivers/gpu/drm/i915/i915_drv.h       |   6 +
>  drivers/gpu/drm/i915/i915_vgpu.h      |   3 +
>  include/xen/interface/xen.h           |   1 +
>  18 files changed, 991 insertions(+)
>  create mode 100644 drivers/gpu/drm/i915/gvt/Makefile
>  create mode 100644 drivers/gpu/drm/i915/gvt/debug.h
>  create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.c
>  create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.h
>  create mode 100644 drivers/gpu/drm/i915/gvt/gvt.c
>  create mode 100644 drivers/gpu/drm/i915/gvt/gvt.h
>  create mode 100644 drivers/gpu/drm/i915/gvt/hypercall.h
>  create mode 100644 drivers/gpu/drm/i915/gvt/mpt.h
>  create mode 100644 drivers/gpu/drm/i915/gvt/params.c
>  create mode 100644 drivers/gpu/drm/i915/gvt/params.h
>  create mode 100644 drivers/gpu/drm/i915/gvt/reg.h
> 
> diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h
> index 62ca03e..6ff4986 100644
> --- a/arch/x86/include/asm/xen/interface.h
> +++ b/arch/x86/include/asm/xen/interface.h
> @@ -73,6 +73,9 @@
>  #endif
>  
>  #ifndef __ASSEMBLY__
> +
> +#include 
> +

I don't follow why this would need to be added if the file is not
modified otherwise. Each header should only include what they use.

If this is an existing bug (that xen/interface.h can not be included
without including linux/types.h), it should be split to a separate
patch and sent to Xen team. Same for include/xen/interface/xen.h.

>  /* Explicitly size integers that represent pfns in the public interface
>   * with Xen so that on ARM we can have one ABI that works for 32 and 64
>   * bit guests. */
> diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
> index 051eab3..89ff723 100644
> --- a/drivers/gpu/drm/i915/Kconfig
> +++ b/drivers/gpu/drm/i915/Kconfig
> @@ -47,3 +47,19 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT
>  	  option changes the default for that module option.
>  
>  	  If in doubt, say "N".
> +
> +config I915_GVT
> +        tristate "GVT-g host driver"
> +        depends on DRM_I915
> +        select IRQ_WORK
> +        default y

Defaulting to "n" would make sense initially.

> +        help
> +          Enabling GVT-g mediated graphics passthrough technique for Intel i915
> +          based integrated graphics card. With GVT-g, it's possible to have one
> +          integrated i915 device shared by multiple VMs. Performance critical
> +          opterations such as apperture accesses and ring buffer operations
> +          are pass-throughed to VM, with a minimal set of conflicting resources
> +          (e.g. display settings) mediated by vGT driver. The benefit of vGT
> +          is on both the performance, given that each VM could directly operate
> +          its aperture space and submit commands like running on native, and
> +          the feature completeness, given that a true GEN hardware is exposed.
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 0851de07..d4df410 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -91,6 +91,8 @@ i915-y += dvo_ch7017.o \
>  	  intel_sdvo.o \
>  	  intel_tv.o
>  
> +obj-$(CONFIG_I915_GVT)  += gvt/
> +
>  # virtual gpu code
>  i915-y += i915_vgpu.o
>  
> diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
> new file mode 100644
> index 0000000..6935b78
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/Makefile
> @@ -0,0 +1,5 @@
> +GVT_SOURCE := gvt.o params.o fb_decoder.o
> +
> +ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
> +i915_gvt-y			:= $(GVT_SOURCE)
> +obj-$(CONFIG_I915_GVT)		+= i915_gvt.o
> diff --git a/drivers/gpu/drm/i915/gvt/debug.h b/drivers/gpu/drm/i915/gvt/debug.h
> new file mode 100644
> index 0000000..18e1467
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/debug.h
> @@ -0,0 +1,72 @@
> +/*
> + * Copyright(c) 2011-2016 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.
> + */
> +
> +#ifndef __GVT_DEBUG_H__
> +#define __GVT_DEBUG_H__
> +
> +#define ASSERT(x)                                                       \
> +        do {                                                            \
> +                if (!(x)) {                                             \
> +                        printk("Assert at %s line %d\n",                \
> +                                __FILE__, __LINE__);                    \
> +                }                                                       \
> +        } while (0);
> +
> +#define ASSERT_NUM(x, y)                                                \
> +        do {                                                            \
> +                if (!(x)) {                                             \
> +                        printk("Assert at %s line %d para 0x%llx\n",    \
> +                                __FILE__, __LINE__, (u64)y);            \
> +                }                                                       \
> +        } while (0);
> +

There already is WARN_ON (and i915_drv.h modifies it a little). Do not
introduce custom functions like this, if the existing ones need
improvement, improve them.

> +#define gvt_info(fmt, args...) \
> +	printk(KERN_INFO"[GVT-g] "fmt"\n", ##args)
> +
> +#define gvt_err(fmt, args...) \
> +	printk(KERN_ERR"%s() - %d: "fmt"\n", __func__, __LINE__, ##args)
> +
> +#define gvt_warn(fmt, args...) \
> +	printk(KERN_WARNING"%s() - %d: "fmt"\n", __func__, __LINE__, ##args)
> +
> +#define gvt_dbg(level, fmt, args...) do { \
> +		if (gvt.debug & level) \
> +			printk(KERN_DEBUG"%s() - %d: "fmt"\n", __func__, __LINE__, ##args); \
> +	}while(0)
> +
> +enum {
> +	GVT_DBG_CORE = (1 << 0),
> +	GVT_DBG_MM = (1 << 1),
> +	GVT_DBG_IRQ = (1 << 2),
> +};
> +
> +#define gvt_dbg_core(fmt, args...) \
> +	gvt_dbg(GVT_DBG_CORE, fmt, ##args)
> +
> +#define gvt_dbg_mm(fmt, args...) \
> +	gvt_dbg(GVT_DBG_MM, fmt, ##args)
> +
> +#define gvt_dbg_irq(fmt, args...) \
> +	gvt_dbg(GVT_DBG_IRQ, fmt, ##args)
> +
> +#endif

This should be integrated better to DRM debugging options, custom
debugging code only for i915 was rejected a while ago.

> diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c b/drivers/gpu/drm/i915/gvt/fb_decoder.c
> new file mode 100644
> index 0000000..a219819
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c
> @@ -0,0 +1,34 @@
> +/*
> + * Copyright(c) 2011-2016 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 "gvt.h"
> +
> +int gvt_decode_fb_format(struct pgt_device *pdev, int vmid, struct gvt_fb_format *fb)
> +{
> +	return 0;
> +}
> +
> +int gvt_fb_notifier_call_chain(unsigned long val, void *data)
> +{
> +	return 0;
> +}

Kerneldoc missing for these functions. It is all the same to squash
later patches to introduce the code to these functions already,
reviewing utility functions with no kerneldoc and no body makes it
somewhat difficult to see the big picture.

> diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.h b/drivers/gpu/drm/i915/gvt/fb_decoder.h
> new file mode 100644
> index 0000000..2c29ed4
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.h
> @@ -0,0 +1,110 @@
> +/*
> + * Copyright(c) 2011-2016 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.
> + */
> +
> +#ifndef _GVT_FB_DECODER_H_
> +#define _GVT_FB_DECODER_H_
> +
> +typedef enum {
> +	FB_MODE_SET_START = 1,
> +	FB_MODE_SET_END,
> +	FB_DISPLAY_FLIP,
> +}gvt_fb_event_t;
> +
> +typedef enum {
> +	DDI_PORT_NONE	= 0,
> +	DDI_PORT_B	= 1,
> +	DDI_PORT_C	= 2,
> +	DDI_PORT_D	= 3,
> +	DDI_PORT_E	= 4
> +} ddi_port_t;
> +
> +struct pgt_device;
> +
> +struct gvt_fb_notify_msg {
> +	unsigned vm_id;
> +	unsigned pipe_id; /* id starting from 0 */
> +	unsigned plane_id; /* primary, cursor, or sprite */
> +};
> +
> +/* color space conversion and gamma correction are not included */
> +struct gvt_primary_plane_format {
> +	u8	enabled;	/* plane is enabled */
> +	u8	tiled;		/* X-tiled */
> +	u8	bpp;		/* bits per pixel */
> +	u32	hw_format;	/* format field in the PRI_CTL register */
> +	u32	drm_format;	/* format in DRM definition */
> +	u32	base;		/* framebuffer base in graphics memory */
> +	u32	x_offset;	/* in pixels */
> +	u32	y_offset;	/* in lines */
> +	u32	width;		/* in pixels */
> +	u32	height;		/* in lines */
> +	u32	stride;		/* in bytes */
> +};
> +
> +struct gvt_sprite_plane_format {
> +	u8	enabled;	/* plane is enabled */
> +	u8	tiled;		/* X-tiled */
> +	u8	bpp;		/* bits per pixel */
> +	u32	hw_format;	/* format field in the SPR_CTL register */
> +	u32	drm_format;	/* format in DRM definition */
> +	u32	base;		/* sprite base in graphics memory */
> +	u32	x_pos;		/* in pixels */
> +	u32	y_pos;		/* in lines */
> +	u32	x_offset;	/* in pixels */
> +	u32	y_offset;	/* in lines */
> +	u32	width;		/* in pixels */
> +	u32	height;		/* in lines */
> +};
> +
> +struct gvt_cursor_plane_format {
> +	u8	enabled;
> +	u8	mode;		/* cursor mode select */
> +	u8	bpp;		/* bits per pixel */
> +	u32	drm_format;	/* format in DRM definition */
> +	u32	base;		/* cursor base in graphics memory */
> +	u32	x_pos;		/* in pixels */
> +	u32	y_pos;		/* in lines */
> +	u8	x_sign;		/* X Position Sign */
> +	u8	y_sign;		/* Y Position Sign */
> +	u32	width;		/* in pixels */
> +	u32	height;		/* in lines */
> +	u32	x_hot;		/* in pixels */
> +	u32	y_hot;		/* in pixels */
> +};
> +

The above structs have a lot in common, would it make sense to have the
common members + plane type and then union for the plane type specific
data. I suspect having it all split this way will lead to more utility
functions somewhere.

> +struct gvt_pipe_format {
> +	struct gvt_primary_plane_format	primary;
> +	struct gvt_sprite_plane_format	sprite;
> +	struct gvt_cursor_plane_format	cursor;
> +	ddi_port_t ddi_port;  /* the DDI port that the pipe is connected to */
> +};
> +
> +struct gvt_fb_format{
> +	struct gvt_pipe_format	pipes[I915_MAX_PIPES];
> +};
> +
> +extern int gvt_fb_notifier_call_chain(unsigned long val, void *data);
> +extern int gvt_decode_fb_format(struct pgt_device *pdev, int vmid,
> +				struct gvt_fb_format *fb);
> +
> +#endif
> diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
> new file mode 100644
> index 0000000..041d10f
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/gvt.c
> @@ -0,0 +1,366 @@
> +/*
> + * Copyright(c) 2011-2016 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 
> +#include 
> +
> +#include "gvt.h"
> +
> +struct gvt_host gvt_host;
> +
> +extern struct gvt_kernel_dm xengt_kdm;
> +extern struct gvt_kernel_dm kvmgt_kdm;
> +
> +static const char *supported_hypervisors[] = {

should be "static const char * const".

> +	[GVT_HYPERVISOR_TYPE_XEN] = "Xen Hypervisor",
> +	[GVT_HYPERVISOR_TYPE_KVM] = "KVM",
> +};
> +
> +static bool gvt_init_host(void)
> +{
> +	struct gvt_host *host = &gvt_host;
> +
> +	if (!gvt.enable) {
> +		gvt_dbg_core("GVT-g has been disabled by kernel parameter");
> +		return false;
> +	}
> +
> +	if (host->initialized) {
> +		gvt_err("GVT-g has already been initialized!");
> +		return false;
> +	}
> +
> +	if (xen_initial_domain()) {

Shouldn't Xen code be CONFIG_XEN_DOM0 and CONFIG_XEN #ifdef protected?

> +		/* Xen Dom0 */
> +		host->kdm = try_then_request_module(symbol_get(xengt_kdm), "xengt");
> +		host->hypervisor_type = GVT_HYPERVISOR_TYPE_XEN;
> +	} else if(xen_domain()) {
> +		/* Xen DomU */
> +		return false;
> +	} else {
> +		/* not in Xen. Try KVMGT */
> +		host->kdm = try_then_request_module(symbol_get(kvmgt_kdm), "kvm");
> +		host->hypervisor_type = GVT_HYPERVISOR_TYPE_KVM;
> +	}
> +

Why do we need to keep track of hypervisor type, are there plenty of
hypervisor specific behaviour differences? If it is just for printing
the below debug, I think it's better to move the debug into above code
that detects the hypervisor, wrap them with appropriate CONFIG #ifdefs.

> +	if (!host->kdm)
> +		return false;
> +
> +	if (!hypervisor_detect_host())
> +		return false;
> +
> +	gvt_info("Running with hypervisor %s in host mode",
> +			supported_hypervisors[host->hypervisor_type]);
> +
> +	idr_init(&host->device_idr);
> +	mutex_init(&host->device_idr_lock);
> +
> +	host->initialized = true;
> +	return true;
> +}
> +
> +static bool init_device_info(struct pgt_device *pdev)
> +{
> +	struct gvt_device_info *info = &pdev->device_info;
> +
> +	if (!IS_BROADWELL(pdev->dev_priv)) {
> +		gvt_err("Unsupported GEN device");
> +		return false;
> +	}
> +
> +	if (IS_BROADWELL(pdev->dev_priv)) {
> +		info->max_gtt_gm_sz = (1UL << 32);
> +		/*
> +		 * The layout of BAR0 in BDW:
> +		 * |< - MMIO 2MB ->|<- Reserved 6MB ->|<- MAX GTT 8MB->|
> +		 *
> +		 * GTT offset in BAR0 starts from 8MB to 16MB, and
> +		 * Whatever GTT size is configured in BIOS,
> +		 * the size of BAR0 is always 16MB. The actual configured
> +		 * GTT size can be found in GMCH_CTRL.
> +		 */
> +		info->gtt_start_offset = (1UL << 23);
> +		info->max_gtt_size = (1UL << 23);
> +		info->gtt_entry_size = 8;
> +		info->gtt_entry_size_shift = 3;
> +		info->gmadr_bytes_in_cmd = 8;

Would this information be useful in a header as #defines too?

> +	}
> +
> +	gvt_info("Device info:");
> +	printk("        max_gtt_gm_sz: %llx\n", info->max_gtt_gm_sz);
> +	printk("        max_gtt_size: %x\n", info->max_gtt_size);
> +	printk("        gtt_size_entry: %x\n", info->gtt_entry_size);
> +	printk("        gtt_entry_size_shift: %x\n", info->gtt_entry_size_shift);
> +	printk("        gtt_start_offset: %x\n", info->gtt_start_offset);
> +	printk("        gtt_end_offset: %x\n", info->gtt_end_offset);
> +

Just put this to kind of stuff to i915_debugfs.c.

> +	return true;
> +}
> +
> +static void init_initial_cfg_space_state(struct pgt_device *pdev)
> +{
> +	struct pci_dev *pci_dev = pdev->dev_priv->dev->pdev;
> +	int i;
> +
> +	gvt_dbg_core("init initial cfg space, id %d", pdev->id);
> +
> +	for (i = 0; i < GVT_CFG_SPACE_SZ; i += 4)

+= sizeof(...)

> +		pci_read_config_dword(pci_dev, i,
> +				(u32 *)&pdev->initial_cfg_space[i]);
> +
> +	for (i = 0; i < 3; i++) {

No magic numbers make a #define for 3 and give it a descriptive name.

> +		pdev->bar_size[i] = pci_resource_len(pci_dev, i * 2);
> +		gvt_info("bar %d size: %llx", i, pdev->bar_size[i]);
> +	}
> +}
> +
> +static void clean_initial_mmio_state(struct pgt_device *pdev)
> +{
> +	if (pdev->gttmmio_va) {
> +		iounmap(pdev->gttmmio_va);
> +		pdev->gttmmio_va = NULL;
> +	}
> +
> +	if (pdev->gmadr_va) {
> +		iounmap(pdev->gmadr_va);
> +		pdev->gmadr_va = NULL;
> +	}
> +}
> +
> +static bool init_initial_mmio_state(struct pgt_device *pdev)
> +{
> +	u64 bar0, bar1;
> +
> +	gvt_dbg_core("init initial mmio state, id %d", pdev->id);
> +
> +	bar0 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR0];
> +	bar1 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR1];
> +
> +	pdev->gttmmio_base = bar0 & ~0xf;
> +	pdev->mmio_size = 2 * 1024 * 1024;
> +	pdev->reg_num = pdev->mmio_size / 4;
> +	pdev->gmadr_base = bar1 & ~0xf;
> +

Many magic numbers.

> +	pdev->gttmmio_va = ioremap(pdev->gttmmio_base, pdev->bar_size[0]);
> +	if (!pdev->gttmmio_va) {
> +		gvt_err("fail to map GTTMMIO BAR.");

These should be if(WARN_ON(...))

> +		return false;
> +	}
> +
> +	pdev->gmadr_va = ioremap(pdev->gmadr_base, pdev->bar_size[2]);
> +	if (!pdev->gmadr_va) {
> +		gvt_err("fail to map GMADR BAR.");
> +		goto err;
> +	}
> +
> +	gvt_info("bar0: 0x%llx, bar1: 0x%llx", bar0, bar1);
> +	gvt_info("mmio size: %x", pdev->mmio_size);
> +	gvt_info("gttmmio: 0x%llx, gmadr: 0x%llx", pdev->gttmmio_base, pdev->gmadr_base);
> +	gvt_info("gttmmio_va: %p", pdev->gttmmio_va);
> +	gvt_info("gmadr_va: %p", pdev->gmadr_va);
> +
> +	return true;
> +err:
> +	clean_initial_mmio_state(pdev);
> +	return false;
> +}
> +
> +static int gvt_service_thread(void *data)
> +{
> +	struct pgt_device *pdev = (struct pgt_device *)data;
> +	int r;
> +
> +	gvt_dbg_core("service thread start, pgt %d", pdev->id);
> +
> +	while(!kthread_should_stop()) {
> +		r = wait_event_interruptible(pdev->service_thread_wq,
> +				kthread_should_stop() || pdev->service_request);
> +
> +		if (kthread_should_stop())
> +			break;
> +
> +		if (r) {
> +			gvt_warn("service thread is waken up by unexpected signal.");

Should be WARN_ONCE, to avoid future disasters with CI.

> +			continue;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static void clean_service_thread(struct pgt_device *pdev)
> +{
> +	if (pdev->service_thread) {
> +		kthread_stop(pdev->service_thread);
> +		pdev->service_thread = NULL;
> +	}
> +}
> +
> +static bool init_service_thread(struct pgt_device *pdev)
> +{
> +	init_waitqueue_head(&pdev->service_thread_wq);
> +
> +	pdev->service_thread = kthread_run(gvt_service_thread,
> +			pdev, "gvt_service_thread%d", pdev->id);
> +
> +	if (!pdev->service_thread) {
> +		gvt_err("fail to start service thread.");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +static void clean_pgt_device(struct pgt_device *pdev)
> +{
> +	clean_service_thread(pdev);
> +	clean_initial_mmio_state(pdev);
> +}
> +
> +static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *dev_priv)
> +{
> +	if (!init_device_info(pdev))
> +		return false;
> +
> +	init_initial_cfg_space_state(pdev);
> +
> +	if (!init_initial_mmio_state(pdev))
> +		goto err;
> +
> +	if (!init_service_thread(pdev))
> +		goto err;
> +
> +	return true;
> +err:
> +	clean_pgt_device(pdev);
> +	return false;
> +}
> +
> +static bool post_init_pgt_device(struct pgt_device *pdev)
> +{
> +	return true;
> +}
> +
> +static void free_pgt_device(struct pgt_device *pdev)
> +{
> +	struct gvt_host *host = &gvt_host;
> +
> +	mutex_lock(&host->device_idr_lock);
> +	idr_remove(&host->device_idr, pdev->id);
> +	mutex_unlock(&host->device_idr_lock);
> +
> +	vfree(pdev);
> +}
> +
> +static struct pgt_device *alloc_pgt_device(struct drm_i915_private *dev_priv)
> +{
> +	struct gvt_host *host = &gvt_host;
> +	struct pgt_device *pdev = NULL;
> +
> +	pdev = vzalloc(sizeof(*pdev));
> +	if (!pdev) {
> +		gvt_err("fail to allocate memory for pgt device.");
> +		return NULL;
> +	}
> +
> +	mutex_lock(&host->device_idr_lock);
> +	pdev->id = idr_alloc(&host->device_idr, pdev, 0, 0, GFP_KERNEL);
> +	mutex_unlock(&host->device_idr_lock);
> +
> +	if (pdev->id < 0) {
> +		gvt_err("fail to allocate pgt device id.");
> +		goto err;
> +	}
> +
> +	mutex_init(&pdev->lock);
> +	pdev->dev_priv = dev_priv;
> +	idr_init(&pdev->instance_idr);
> +
> +	return pdev;
> +err:
> +	free_pgt_device(pdev);
> +	return NULL;
> +}
> +
> +void gvt_destroy_pgt_device(void *private_data)
> +{
> +	struct pgt_device *pdev = (struct pgt_device *)private_data;
> +
> +	clean_pgt_device(pdev);
> +	free_pgt_device(pdev);
> +}
> +
> +void *gvt_create_pgt_device(struct drm_i915_private *dev_priv)
> +{
> +	struct pgt_device *pdev = NULL;
> +	struct gvt_host *host = &gvt_host;
> +
> +	if (!host->initialized && !gvt_init_host()) {
> +		gvt_err("gvt_init_host fail");
> +		return NULL;
> +	}
> +
> +	gvt_dbg_core("create new pgt device, i915 dev_priv: %p", dev_priv);
> +
> +	pdev = alloc_pgt_device(dev_priv);
> +	if (!pdev) {
> +		gvt_err("fail to allocate memory for pgt device.");
> +		goto err;
> +	}
> +
> +	gvt_dbg_core("init pgt device, id %d", pdev->id);
> +
> +	if (!init_pgt_device(pdev, dev_priv)) {
> +		gvt_err("fail to init physical device state.");
> +		goto err;
> +	}
> +
> +	gvt_dbg_core("pgt device creation done, id %d", pdev->id);
> +
> +	return pdev;
> +err:
> +	if (pdev) {
> +		gvt_destroy_pgt_device(pdev);
> +		pdev = NULL;
> +	}
> +	return NULL;
> +}
> +
> +bool gvt_post_init_pgt_device(void *private_data)
> +{
> +	struct pgt_device *pdev = (struct pgt_device *)private_data;
> +	struct gvt_host *host = &gvt_host;
> +
> +	if (!host->initialized) {
> +		gvt_err("gvt_host haven't been initialized.");
> +		return false;
> +	}
> +
> +	gvt_dbg_core("post init pgt device %d", pdev->id);
> +
> +	if (!post_init_pgt_device(pdev)) {
> +		gvt_err("fail to post init physical device state.");
> +		return false;
> +	}
> +
> +	return true;
> +}
> diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
> new file mode 100644
> index 0000000..6c85bba
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/gvt.h
> @@ -0,0 +1,130 @@
> +/*
> + * Copyright(c) 2011-2016 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.
> + */
> +
> +#ifndef _GVT_H_
> +#define _GVT_H_
> +
> +#include "i915_drv.h"
> +#include "i915_vgpu.h"
> +
> +#include "debug.h"
> +#include "params.h"
> +#include "reg.h"
> +#include "hypercall.h"
> +#include "mpt.h"
> +#include "fb_decoder.h"
> +
> +#define GVT_MAX_VGPU 8
> +
> +enum {
> +	GVT_HYPERVISOR_TYPE_XEN = 0,
> +	GVT_HYPERVISOR_TYPE_KVM,
> +};
> +
> +struct gvt_host {
> +	bool initialized;
> +	int hypervisor_type;
> +	struct mutex device_idr_lock;
> +	struct idr device_idr;
> +	struct gvt_kernel_dm *kdm;
> +};
> +
> +extern struct gvt_host gvt_host;
> +
> +/* Describe the limitation of HW.*/
> +struct gvt_device_info {
> +	u64 max_gtt_gm_sz;
> +	u32 gtt_start_offset;
> +	u32 gtt_end_offset;
> +	u32 max_gtt_size;
> +	u32 gtt_entry_size;
> +	u32 gtt_entry_size_shift;
> +	u32 gmadr_bytes_in_cmd;
> +};
> +
> +struct vgt_device {
> +	int id;
> +	int vm_id;
> +	struct pgt_device *pdev;
> +	bool warn_untrack;
> +};
> +
> +struct pgt_device {
> +	struct mutex lock;
> +	int id;
> +
> +	struct drm_i915_private *dev_priv;
> +	struct idr instance_idr;
> +
> +	struct gvt_device_info device_info;
> +
> +	u8 initial_cfg_space[GVT_CFG_SPACE_SZ];
> +	u64 bar_size[GVT_BAR_NUM];
> +
> +	u64 gttmmio_base;
> +	void *gttmmio_va;
> +
> +	u64 gmadr_base;
> +	void *gmadr_va;
> +
> +	u32 mmio_size;
> +	u32 reg_num;
> +
> +	wait_queue_head_t service_thread_wq;
> +	struct task_struct *service_thread;
> +	unsigned long service_request;
> +};
> +

Here-->

> +static inline u32 gvt_mmio_read(struct pgt_device *pdev,
> +		u32 reg)
> +{
> +	struct drm_i915_private *dev_priv = pdev->dev_priv;
> +	i915_reg_t tmp = {.reg = reg};
> +	return I915_READ(tmp);
> +}
> +
> +static inline void gvt_mmio_write(struct pgt_device *pdev,
> +		u32 reg, u32 val)
> +{
> +	struct drm_i915_private *dev_priv = pdev->dev_priv;
> +	i915_reg_t tmp = {.reg = reg};
> +	I915_WRITE(tmp, val);
> +}
> +
> +static inline u64 gvt_mmio_read64(struct pgt_device *pdev,
> +		u32 reg)
> +{
> +	struct drm_i915_private *dev_priv = pdev->dev_priv;
> +	i915_reg_t tmp = {.reg = reg};
> +	return I915_READ64(tmp);
> +}
> +
> +static inline void gvt_mmio_write64(struct pgt_device *pdev,
> +		u32 reg, u64 val)
> +{
> +	struct drm_i915_private *dev_priv = pdev->dev_priv;
> +	i915_reg_t tmp = {.reg = reg};
> +	I915_WRITE64(tmp, val);
> +}
> +

<-- Why? The i915_reg_t type was added to avoid problems, this code is
not used anywhere, and it has no documentation, so I can not review it.

I wrote comments at the top of the post.

Regards, Joonas

> +#endif
> diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h b/drivers/gpu/drm/i915/gvt/hypercall.h
> new file mode 100644
> index 0000000..0a41874
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/hypercall.h
> @@ -0,0 +1,30 @@
> +/*
> + * Copyright(c) 2011-2016 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.
> + */
> +
> +#ifndef _GVT_HYPERCALL_H_
> +#define _GVT_HYPERCALL_H_
> +
> +struct gvt_kernel_dm {
> +};
> +
> +#endif /* _GVT_HYPERCALL_H_ */
> diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h
> new file mode 100644
> index 0000000..bbe4465
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/mpt.h
> @@ -0,0 +1,97 @@
> +/*
> + * Copyright(c) 2011-2016 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.
> + */
> +
> +#ifndef _GVT_MPT_H_
> +#define _GVT_MPT_H_
> +
> +struct vgt_device;
> +
> +static inline unsigned long hypervisor_g2m_pfn(struct vgt_device *vgt,
> +	unsigned long g_pfn)
> +{
> +	return 0;
> +}
> +
> +static inline int hypervisor_pause_domain(struct vgt_device *vgt)
> +{
> +	return 0;
> +}
> +
> +static inline int hypervisor_shutdown_domain(struct vgt_device *vgt)
> +{
> +	return 0;
> +}
> +
> +static inline int hypervisor_set_trap_area(struct vgt_device *vgt,
> +	uint64_t start, uint64_t end, bool map)
> +{
> +	return 0;
> +}
> +
> +static inline bool hypervisor_detect_host(void)
> +{
> +	return false;
> +}
> +
> +static inline int hypervisor_virt_to_mfn(void *addr)
> +{
> +	return 0;
> +}
> +
> +static inline void *hypervisor_mfn_to_virt(int mfn)
> +{
> +	return NULL;
> +}
> +
> +static inline void hypervisor_inject_msi(struct vgt_device *vgt)
> +{
> +	return;
> +}
> +
> +static inline int hypervisor_hvm_init(struct vgt_device *vgt)
> +{
> +	return 0;
> +}
> +
> +static inline void hypervisor_hvm_exit(struct vgt_device *vgt)
> +{
> +}
> +
> +static inline void *hypervisor_gpa_to_va(struct vgt_device *vgt, unsigned long gpa)
> +{
> +	return NULL;
> +}
> +
> +static inline bool hypervisor_read_va(struct vgt_device *vgt, void *va,
> +		void *val, int len, int atomic)
> +{
> +	return false;
> +}
> +
> +static inline bool hypervisor_write_va(struct vgt_device *vgt, void *va,
> +		void *val, int len, int atomic)
> +{
> +	return false;
> +}
> +
> +#endif /* _GVT_MPT_H_ */
> diff --git a/drivers/gpu/drm/i915/gvt/params.c b/drivers/gpu/drm/i915/gvt/params.c
> new file mode 100644
> index 0000000..dfc33c3
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/params.c
> @@ -0,0 +1,29 @@
> +/*
> + * Copyright(c) 2011-2016 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 "gvt.h"
> +
> +struct gvt_kernel_params gvt = {
> +	.enable = true,
> +	.debug = 0,
> +};
> diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
> new file mode 100644
> index 0000000..d2955b9
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/params.h
> @@ -0,0 +1,34 @@
> +/*
> + * Copyright(c) 2011-2016 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.
> + */
> +
> +#ifndef _GVT_PARAMS_H_
> +#define _GVT_PARAMS_H_
> +
> +struct gvt_kernel_params {
> +	bool enable;
> +	int debug;
> +};
> +
> +extern struct gvt_kernel_params gvt;
> +
> +#endif
> diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
> new file mode 100644
> index 0000000..d363b74
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/gvt/reg.h
> @@ -0,0 +1,34 @@
> +/*
> + * Copyright(c) 2011-2016 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.
> + */
> +
> +#ifndef _GVT_REG_H
> +#define _GVT_REG_H
> +
> +#define GVT_CFG_SPACE_SZ	256
> +#define GVT_BAR_NUM		4
> +
> +#define GVT_REG_CFG_SPACE_BAR0	0x10
> +#define GVT_REG_CFG_SPACE_BAR1	0x18
> +#define GVT_REG_CFG_SPACE_BAR2	0x20
> +
> +#endif
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 4725e8d..eca8e50 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -943,6 +943,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>  
>  	intel_uncore_init(dev);
>  
> +	dev_priv->vgpu.host_private_data = gvt_create_pgt_device(dev_priv);
> +	if(intel_gvt_host_active(dev))
> +		DRM_INFO("GVT-g is running in host mode\n");
> +
>  	ret = i915_gem_gtt_init(dev);
>  	if (ret)
>  		goto out_freecsr;
> @@ -1067,6 +1071,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>  		goto out_power_well;
>  	}
>  
> +	if (intel_gvt_host_active(dev)) {
> +		if (!gvt_post_init_pgt_device(dev_priv->vgpu.host_private_data)) {
> +			DRM_ERROR("failed to post init pgt device\n");
> +			goto out_power_well;
> +		}
> +	}
> +
>  	/*
>  	 * Notify a valid surface after modesetting,
>  	 * when running inside a VM.
> @@ -1117,6 +1128,10 @@ out_gtt:
>  	i915_global_gtt_cleanup(dev);
>  out_freecsr:
>  	intel_csr_ucode_fini(dev_priv);
> +	if (intel_gvt_host_active(dev)) {
> +		gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
> +		dev_priv->vgpu.host_private_data = NULL;
> +	}
>  	intel_uncore_fini(dev);
>  	pci_iounmap(dev->pdev, dev_priv->regs);
>  put_bridge:
> @@ -1165,6 +1180,10 @@ int i915_driver_unload(struct drm_device *dev)
>  
>  	intel_modeset_cleanup(dev);
>  
> +	if (intel_gvt_host_active(dev)) {
> +		gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
> +		dev_priv->vgpu.host_private_data = NULL;
> +	}
>  	/*
>  	 * free the memory space allocated for the child device
>  	 * config parsed from VBT
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 01cc982..db3c79b 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1673,6 +1673,7 @@ struct i915_workarounds {
>  
>  struct i915_virtual_gpu {
>  	bool active;
> +	void *host_private_data;
>  };
>  
>  struct i915_execbuffer_params {
> @@ -2747,6 +2748,11 @@ static inline bool intel_vgpu_active(struct drm_device *dev)
>  	return to_i915(dev)->vgpu.active;
>  }
>  
> +static inline bool intel_gvt_host_active(struct drm_device *dev)
> +{
> +	return to_i915(dev)->vgpu.host_private_data ? true : false;
> +}
> +
>  void
>  i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
>  		     u32 status_mask);
> diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
> index 3c83b47..942490a 100644
> --- a/drivers/gpu/drm/i915/i915_vgpu.h
> +++ b/drivers/gpu/drm/i915/i915_vgpu.h
> @@ -113,5 +113,8 @@ struct vgt_if {
>  extern void i915_check_vgpu(struct drm_device *dev);
>  extern int intel_vgt_balloon(struct drm_device *dev);
>  extern void intel_vgt_deballoon(void);
> +extern void *gvt_create_pgt_device(struct drm_i915_private *dev_priv);
> +extern bool gvt_post_init_pgt_device(void *private_data);
> +extern void gvt_destroy_pgt_device(void *private_data);
>  
>  #endif /* _I915_VGPU_H_ */
> diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
> index d133112..78a38f1 100644
> --- a/include/xen/interface/xen.h
> +++ b/include/xen/interface/xen.h
> @@ -28,6 +28,7 @@
>  #define __XEN_PUBLIC_XEN_H__
>  
>  #include 
> +#include 
>  
>  /*
>   * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g
  2016-01-29 13:57   ` Joonas Lahtinen
@ 2016-01-29 16:48     ` Chris Wilson
  2016-02-03  6:28       ` Zhi Wang
  2016-02-05  7:02       ` Zhiyuan Lv
  2016-02-03  6:01     ` Zhi Wang
  1 sibling, 2 replies; 49+ messages in thread
From: Chris Wilson @ 2016-01-29 16:48 UTC (permalink / raw)
  To: Joonas Lahtinen; +Cc: daniel.vetter, intel-gfx, david.j.cowperthwaite, igvt-g

On Fri, Jan 29, 2016 at 03:57:09PM +0200, Joonas Lahtinen wrote:
> Hi,
> 
> TL;DR Overall, we have same problem as with the scheduler series, there
> is too much placeholder stuff for easy review. Just squash enough code
> into one commit so it actually does something logical that can be
> reviewed and then extend it later. Then it can be reviewed and pushed.
> Just splitting the code down to achieve smaller patches is not the
> right thing to do.
> 
> Comments on the overall code: You need to document all header file
> functions (in the source files), and it is good to document the static
> functions within a file too, to make future maintenance easier.
> 
> It is not about splitting the code down to small chunks, but splitting
> it down to small *logical* chunks. It doesn't make sense to commit
> dozens of empty bodied functions for review, and then later add their
> code.
> 
> If you add functions, only add them at a patch that takes them into use
> too, unless we're talking about general purpose shared code. And also
> remember to add the function body and documentation header. If you
> simply add a "return 0;" or similar function body, do add a comment to
> why the function does not exist and when it will.
> 
> Then, there is a trend of having a boolean return values in the code.
> When possible, it should rather be int and the cause for failure should
> be propagated from the last level all the way to up (-ENOMEN etc.).
> This way debugging becomes easier and if new error conditions appear,
> there is less of a maintenance burden to add the propagation later.
> 
> Finally, make sure to look at the existing driver parts and
> 	https://www.kernel.org/doc/Documentation/CodingStyle
> for proper coding style. There are lots of whitespace fixes needed in
> this series, like array initializations.
> 
> I hope to see this first patch rerolled so that you squash some of the
> later commits into it so that all functions have a body and you add
> documentation for the functions so I can both see what it should do and
> what it actually does. Only reroll the first patch, to keep the
> iterative step smaller. Lets only then continue with the rest of the
> series once we've reached a consensus on the formatting and style
> basics.
> 
> See more comments below.

I'm glad you did the nitpicking. As far as the integration goes, on the
whole I'm happy with the way it is structured and the reuse of existing
code. I tried to attack various aspects of the GVT contexts and came to
the conclusion I couldn't suggest a better approach (though maybe
tomorrow!). A few bits and pieces I got lost trying to pull together
(in particular like how we do is read back through the GTT entries
performed, the hypervisor_read_va abstraction iirc) and would appreciate
having a branch available to get the complete picture.
-Chris
-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g
  2016-01-29 13:57   ` Joonas Lahtinen
  2016-01-29 16:48     ` Chris Wilson
@ 2016-02-03  6:01     ` Zhi Wang
  2016-02-03  7:01       ` Zhiyuan Lv
                         ` (2 more replies)
  1 sibling, 3 replies; 49+ messages in thread
From: Zhi Wang @ 2016-02-03  6:01 UTC (permalink / raw)
  To: Joonas Lahtinen, intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

Hi Joonas:
     Thanks you very much! We're very excited for receiving your advice 
and continue to be open to any comments. :)

I'm supposed that we should make the agreements on i915 host change at 
the very beginning, as I'm concerned during the discussion of i915 host 
change, you know, maybe some code of GVT-g needs to be refined or 
re-designed. So we put the i915 host changes to the beginning of the 
patch set for the convenience of discussion.

I summarize your comments as below, very applicate. :)

- Replace boolean return value with int as much as possible.
- Replace customized debug ASSERT() function & macros with DRM_DEBUG_*
- Document all non-static functions like i915
- Fix all whitespace via scripts/cleanpatch.pl
- Commit function structure refinement.
- Change the register access behavior just like what i915 does.

For other comments, see my comments below. :)

On 01/29/16 21:57, Joonas Lahtinen wrote:
> Hi,
>
> TL;DR Overall, we have same problem as with the scheduler series, there
> is too much placeholder stuff for easy review. Just squash enough code
> into one commit so it actually does something logical that can be
> reviewed and then extend it later. Then it can be reviewed and pushed.
> Just splitting the code down to achieve smaller patches is not the
> right thing to do.
>
> Comments on the overall code: You need to document all header file
> functions (in the source files), and it is good to document the static
> functions within a file too, to make future maintenance easier.
>
> It is not about splitting the code down to small chunks, but splitting
> it down to small *logical* chunks. It doesn't make sense to commit
> dozens of empty bodied functions for review, and then later add their
> code.
>
> If you add functions, only add them at a patch that takes them into use
> too, unless we're talking about general purpose shared code. And also
> remember to add the function body and documentation header. If you
> simply add a "return 0;" or similar function body, do add a comment to
> why the function does not exist and when it will.
>
> Then, there is a trend of having a boolean return values in the code.
> When possible, it should rather be int and the cause for failure should
> be propagated from the last level all the way to up (-ENOMEN etc.).
> This way debugging becomes easier and if new error conditions appear,
> there is less of a maintenance burden to add the propagation later.
>
> Finally, make sure to look at the existing driver parts and
> 	https://www.kernel.org/doc/Documentation/CodingStyle
> for proper coding style. There are lots of whitespace fixes needed in
> this series, like array initializations.
>
> I hope to see this first patch rerolled so that you squash some of the
> later commits into it so that all functions have a body and you add
> documentation for the functions so I can both see what it should do and
> what it actually does. Only reroll the first patch, to keep the
> iterative step smaller. Lets only then continue with the rest of the
> series once we've reached a consensus on the formatting and style
> basics.
>
> See more comments below.
>
> On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
>> This patch introduces the very basic framework of GVT-g device model,
>> includes basic prototypes, definitions, initialization.
>> ---
>>   arch/x86/include/asm/xen/interface.h  |   3 +
>>   drivers/gpu/drm/i915/Kconfig          |  16 ++
>>   drivers/gpu/drm/i915/Makefile         |   2 +
>>   drivers/gpu/drm/i915/gvt/Makefile     |   5 +
>>   drivers/gpu/drm/i915/gvt/debug.h      |  72 +++++++
>>   drivers/gpu/drm/i915/gvt/fb_decoder.c |  34 ++++
>>   drivers/gpu/drm/i915/gvt/fb_decoder.h | 110 ++++++++++
>>   drivers/gpu/drm/i915/gvt/gvt.c        | 366 ++++++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/i915/gvt/gvt.h        | 130 ++++++++++++
>>   drivers/gpu/drm/i915/gvt/hypercall.h  |  30 +++
>>   drivers/gpu/drm/i915/gvt/mpt.h        |  97 +++++++++
>>   drivers/gpu/drm/i915/gvt/params.c     |  29 +++
>>   drivers/gpu/drm/i915/gvt/params.h     |  34 ++++
>>   drivers/gpu/drm/i915/gvt/reg.h        |  34 ++++
>>   drivers/gpu/drm/i915/i915_dma.c       |  19 ++
>>   drivers/gpu/drm/i915/i915_drv.h       |   6 +
>>   drivers/gpu/drm/i915/i915_vgpu.h      |   3 +
>>   include/xen/interface/xen.h           |   1 +
>>   18 files changed, 991 insertions(+)
>>   create mode 100644 drivers/gpu/drm/i915/gvt/Makefile
>>   create mode 100644 drivers/gpu/drm/i915/gvt/debug.h
>>   create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.c
>>   create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.h
>>   create mode 100644 drivers/gpu/drm/i915/gvt/gvt.c
>>   create mode 100644 drivers/gpu/drm/i915/gvt/gvt.h
>>   create mode 100644 drivers/gpu/drm/i915/gvt/hypercall.h
>>   create mode 100644 drivers/gpu/drm/i915/gvt/mpt.h
>>   create mode 100644 drivers/gpu/drm/i915/gvt/params.c
>>   create mode 100644 drivers/gpu/drm/i915/gvt/params.h
>>   create mode 100644 drivers/gpu/drm/i915/gvt/reg.h
>>
>> diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h
>> index 62ca03e..6ff4986 100644
>> --- a/arch/x86/include/asm/xen/interface.h
>> +++ b/arch/x86/include/asm/xen/interface.h
>> @@ -73,6 +73,9 @@
>>   #endif
>>
>>   #ifndef __ASSEMBLY__
>> +
>> +#include
>> +
>
> I don't follow why this would need to be added if the file is not
> modified otherwise. Each header should only include what they use.
>
> If this is an existing bug (that xen/interface.h can not be included
> without including linux/types.h), it should be split to a separate
> patch and sent to Xen team. Same for include/xen/interface/xen.h.
>
>>   /* Explicitly size integers that represent pfns in the public interface
>>    * with Xen so that on ARM we can have one ABI that works for 32 and 64
>>    * bit guests. */
>> diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
>> index 051eab3..89ff723 100644
>> --- a/drivers/gpu/drm/i915/Kconfig
>> +++ b/drivers/gpu/drm/i915/Kconfig
>> @@ -47,3 +47,19 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT
>>   	  option changes the default for that module option.
>>
>>   	  If in doubt, say "N".
>> +
>> +config I915_GVT
>> +        tristate "GVT-g host driver"
>> +        depends on DRM_I915
>> +        select IRQ_WORK
>> +        default y
>
> Defaulting to "n" would make sense initially.
>
[Zhi] Sure, will do.
>> +        help
>> +          Enabling GVT-g mediated graphics passthrough technique for Intel i915
>> +          based integrated graphics card. With GVT-g, it's possible to have one
>> +          integrated i915 device shared by multiple VMs. Performance critical
>> +          opterations such as apperture accesses and ring buffer operations
>> +          are pass-throughed to VM, with a minimal set of conflicting resources
>> +          (e.g. display settings) mediated by vGT driver. The benefit of vGT
>> +          is on both the performance, given that each VM could directly operate
>> +          its aperture space and submit commands like running on native, and
>> +          the feature completeness, given that a true GEN hardware is exposed.
>> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
>> index 0851de07..d4df410 100644
>> --- a/drivers/gpu/drm/i915/Makefile
>> +++ b/drivers/gpu/drm/i915/Makefile
>> @@ -91,6 +91,8 @@ i915-y += dvo_ch7017.o \
>>   	  intel_sdvo.o \
>>   	  intel_tv.o
>>
>> +obj-$(CONFIG_I915_GVT)  += gvt/
>> +
>>   # virtual gpu code
>>   i915-y += i915_vgpu.o
>>
>> diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
>> new file mode 100644
>> index 0000000..6935b78
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gvt/Makefile
>> @@ -0,0 +1,5 @@
>> +GVT_SOURCE := gvt.o params.o fb_decoder.o
>> +
>> +ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
>> +i915_gvt-y			:= $(GVT_SOURCE)
>> +obj-$(CONFIG_I915_GVT)		+= i915_gvt.o
>> diff --git a/drivers/gpu/drm/i915/gvt/debug.h b/drivers/gpu/drm/i915/gvt/debug.h
>> new file mode 100644
>> index 0000000..18e1467
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gvt/debug.h
>> @@ -0,0 +1,72 @@
>> +/*
>> + * Copyright(c) 2011-2016 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.
>> + */
>> +
>> +#ifndef __GVT_DEBUG_H__
>> +#define __GVT_DEBUG_H__
>> +
>> +#define ASSERT(x)                                                       \
>> +        do {                                                            \
>> +                if (!(x)) {                                             \
>> +                        printk("Assert at %s line %d\n",                \
>> +                                __FILE__, __LINE__);                    \
>> +                }                                                       \
>> +        } while (0);
>> +
>> +#define ASSERT_NUM(x, y)                                                \
>> +        do {                                                            \
>> +                if (!(x)) {                                             \
>> +                        printk("Assert at %s line %d para 0x%llx\n",    \
>> +                                __FILE__, __LINE__, (u64)y);            \
>> +                }                                                       \
>> +        } while (0);
>> +
>
> There already is WARN_ON (and i915_drv.h modifies it a little). Do not
> introduce custom functions like this, if the existing ones need
> improvement, improve them.
>
[Zhi] OK. Will do as what i915 does
>> +#define gvt_info(fmt, args...) \
>> +	printk(KERN_INFO"[GVT-g] "fmt"\n", ##args)
>> +
>> +#define gvt_err(fmt, args...) \
>> +	printk(KERN_ERR"%s() - %d: "fmt"\n", __func__, __LINE__, ##args)
>> +
>> +#define gvt_warn(fmt, args...) \
>> +	printk(KERN_WARNING"%s() - %d: "fmt"\n", __func__, __LINE__, ##args)
>> +
>> +#define gvt_dbg(level, fmt, args...) do { \
>> +		if (gvt.debug & level) \
>> +			printk(KERN_DEBUG"%s() - %d: "fmt"\n", __func__, __LINE__, ##args); \
>> +	}while(0)
>> +
>> +enum {
>> +	GVT_DBG_CORE = (1 << 0),
>> +	GVT_DBG_MM = (1 << 1),
>> +	GVT_DBG_IRQ = (1 << 2),
>> +};
>> +
>> +#define gvt_dbg_core(fmt, args...) \
>> +	gvt_dbg(GVT_DBG_CORE, fmt, ##args)
>> +
>> +#define gvt_dbg_mm(fmt, args...) \
>> +	gvt_dbg(GVT_DBG_MM, fmt, ##args)
>> +
>> +#define gvt_dbg_irq(fmt, args...) \
>> +	gvt_dbg(GVT_DBG_IRQ, fmt, ##args)
>> +
>> +#endif
>
> This should be integrated better to DRM debugging options, custom
> debugging code only for i915 was rejected a while ago.
>
[ZHI] Thanks for sharing the history. :) Will change that.
>> diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c b/drivers/gpu/drm/i915/gvt/fb_decoder.c
>> new file mode 100644
>> index 0000000..a219819
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c
>> @@ -0,0 +1,34 @@
>> +/*
>> + * Copyright(c) 2011-2016 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 "gvt.h"
>> +
>> +int gvt_decode_fb_format(struct pgt_device *pdev, int vmid, struct gvt_fb_format *fb)
>> +{
>> +	return 0;
>> +}
>> +
>> +int gvt_fb_notifier_call_chain(unsigned long val, void *data)
>> +{
>> +	return 0;
>> +}
>
> Kerneldoc missing for these functions. It is all the same to squash
> later patches to introduce the code to these functions already,
> reviewing utility functions with no kerneldoc and no body makes it
> somewhat difficult to see the big picture.
>

[Zhi] One question. I saw i915 put some function instruction in *.c. Is 
it also OK for kernel doc generating the proper doc files?

>> diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.h b/drivers/gpu/drm/i915/gvt/fb_decoder.h
>> new file mode 100644
>> index 0000000..2c29ed4
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.h
>> @@ -0,0 +1,110 @@
>> +/*
>> + * Copyright(c) 2011-2016 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.
>> + */
>> +
>> +#ifndef _GVT_FB_DECODER_H_
>> +#define _GVT_FB_DECODER_H_
>> +
>> +typedef enum {
>> +	FB_MODE_SET_START = 1,
>> +	FB_MODE_SET_END,
>> +	FB_DISPLAY_FLIP,
>> +}gvt_fb_event_t;
>> +
>> +typedef enum {
>> +	DDI_PORT_NONE	= 0,
>> +	DDI_PORT_B	= 1,
>> +	DDI_PORT_C	= 2,
>> +	DDI_PORT_D	= 3,
>> +	DDI_PORT_E	= 4
>> +} ddi_port_t;
>> +
>> +struct pgt_device;
>> +
>> +struct gvt_fb_notify_msg {
>> +	unsigned vm_id;
>> +	unsigned pipe_id; /* id starting from 0 */
>> +	unsigned plane_id; /* primary, cursor, or sprite */
>> +};
>> +
>> +/* color space conversion and gamma correction are not included */
>> +struct gvt_primary_plane_format {
>> +	u8	enabled;	/* plane is enabled */
>> +	u8	tiled;		/* X-tiled */
>> +	u8	bpp;		/* bits per pixel */
>> +	u32	hw_format;	/* format field in the PRI_CTL register */
>> +	u32	drm_format;	/* format in DRM definition */
>> +	u32	base;		/* framebuffer base in graphics memory */
>> +	u32	x_offset;	/* in pixels */
>> +	u32	y_offset;	/* in lines */
>> +	u32	width;		/* in pixels */
>> +	u32	height;		/* in lines */
>> +	u32	stride;		/* in bytes */
>> +};
>> +
>> +struct gvt_sprite_plane_format {
>> +	u8	enabled;	/* plane is enabled */
>> +	u8	tiled;		/* X-tiled */
>> +	u8	bpp;		/* bits per pixel */
>> +	u32	hw_format;	/* format field in the SPR_CTL register */
>> +	u32	drm_format;	/* format in DRM definition */
>> +	u32	base;		/* sprite base in graphics memory */
>> +	u32	x_pos;		/* in pixels */
>> +	u32	y_pos;		/* in lines */
>> +	u32	x_offset;	/* in pixels */
>> +	u32	y_offset;	/* in lines */
>> +	u32	width;		/* in pixels */
>> +	u32	height;		/* in lines */
>> +};
>> +
>> +struct gvt_cursor_plane_format {
>> +	u8	enabled;
>> +	u8	mode;		/* cursor mode select */
>> +	u8	bpp;		/* bits per pixel */
>> +	u32	drm_format;	/* format in DRM definition */
>> +	u32	base;		/* cursor base in graphics memory */
>> +	u32	x_pos;		/* in pixels */
>> +	u32	y_pos;		/* in lines */
>> +	u8	x_sign;		/* X Position Sign */
>> +	u8	y_sign;		/* Y Position Sign */
>> +	u32	width;		/* in pixels */
>> +	u32	height;		/* in lines */
>> +	u32	x_hot;		/* in pixels */
>> +	u32	y_hot;		/* in pixels */
>> +};
>> +
>
> The above structs have a lot in common, would it make sense to have the
> common members + plane type and then union for the plane type specific
> data. I suspect having it all split this way will lead to more utility
> functions somewhere.
>
[Zhi] Thanks. Will do that.

>> +struct gvt_pipe_format {
>> +	struct gvt_primary_plane_format	primary;
>> +	struct gvt_sprite_plane_format	sprite;
>> +	struct gvt_cursor_plane_format	cursor;
>> +	ddi_port_t ddi_port;  /* the DDI port that the pipe is connected to */
>> +};
>> +
>> +struct gvt_fb_format{
>> +	struct gvt_pipe_format	pipes[I915_MAX_PIPES];
>> +};
>> +
>> +extern int gvt_fb_notifier_call_chain(unsigned long val, void *data);
>> +extern int gvt_decode_fb_format(struct pgt_device *pdev, int vmid,
>> +				struct gvt_fb_format *fb);
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
>> new file mode 100644
>> index 0000000..041d10f
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gvt/gvt.c
>> @@ -0,0 +1,366 @@
>> +/*
>> + * Copyright(c) 2011-2016 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
>> +#include
>> +
>> +#include "gvt.h"
>> +
>> +struct gvt_host gvt_host;
>> +
>> +extern struct gvt_kernel_dm xengt_kdm;
>> +extern struct gvt_kernel_dm kvmgt_kdm;
>> +
>> +static const char *supported_hypervisors[] = {
>
> should be "static const char * const".
>
>> +	[GVT_HYPERVISOR_TYPE_XEN] = "Xen Hypervisor",
>> +	[GVT_HYPERVISOR_TYPE_KVM] = "KVM",
>> +};
>> +
>> +static bool gvt_init_host(void)
>> +{
>> +	struct gvt_host *host = &gvt_host;
>> +
>> +	if (!gvt.enable) {
>> +		gvt_dbg_core("GVT-g has been disabled by kernel parameter");
>> +		return false;
>> +	}
>> +
>> +	if (host->initialized) {
>> +		gvt_err("GVT-g has already been initialized!");
>> +		return false;
>> +	}
>> +
>> +	if (xen_initial_domain()) {
>
> Shouldn't Xen code be CONFIG_XEN_DOM0 and CONFIG_XEN #ifdef protected?
>
[Zhi] The following code piece shows xen_initial_domain()/xen_domain() 
could also be used when CONFIG_XEN_DOM0 is not set.

#ifdef CONFIG_XEN
extern enum xen_domain_type xen_domain_type;
#else
#define xen_domain_type         XEN_NATIVE
#endif

#define xen_domain()            (xen_domain_type != XEN_NATIVE)
#define xen_pv_domain()         (xen_domain() &&                        \
                                  xen_domain_type == XEN_PV_DOMAIN)
#define xen_hvm_domain()        (xen_domain() &&                        \
                                  xen_domain_type == XEN_HVM_DOMAIN)

#ifdef CONFIG_XEN_DOM0
#include <xen/interface/xen.h>
#include <asm/xen/hypervisor.h>

#define xen_initial_domain()    (xen_domain() && \
                                  xen_start_info && 
xen_start_info->flags & SIF_INITDOMAIN)
#else  /* !CONFIG_XEN_DOM0 */
#define xen_initial_domain()    (0)
#endif  /* CONFIG_XEN_DOM0 */

>> +		/* Xen Dom0 */
>> +		host->kdm = try_then_request_module(symbol_get(xengt_kdm), "xengt");
>> +		host->hypervisor_type = GVT_HYPERVISOR_TYPE_XEN;
>> +	} else if(xen_domain()) {
>> +		/* Xen DomU */
>> +		return false;
>> +	} else {
>> +		/* not in Xen. Try KVMGT */
>> +		host->kdm = try_then_request_module(symbol_get(kvmgt_kdm), "kvm");
>> +		host->hypervisor_type = GVT_HYPERVISOR_TYPE_KVM;
>> +	}
>> +
>
> Why do we need to keep track of hypervisor type, are there plenty of
> hypervisor specific behaviour differences?

[Zhi] As GVT-g needs some hypervisor services to work, we write a 
abstraction layer to connect GVT-g to different hypervisor. But still 
there are some emulation logic couldn't be fitted into that abstraction 
layer, like OpRegion emulation. In Xen, we emulates it in kernel space, 
while we emulates it in Qemu under KVM. I also agreed that we should 
find some approach to improve it just like what you said.

If it is just for printing
> the below debug, I think it's better to move the debug into above code
> that detects the hypervisor, wrap them with appropriate CONFIG #ifdefs.
>
>> +	if (!host->kdm)
>> +		return false;
>> +
>> +	if (!hypervisor_detect_host())
>> +		return false;
>> +
>> +	gvt_info("Running with hypervisor %s in host mode",
>> +			supported_hypervisors[host->hypervisor_type]);
>> +
>> +	idr_init(&host->device_idr);
>> +	mutex_init(&host->device_idr_lock);
>> +
>> +	host->initialized = true;
>> +	return true;
>> +}
>> +
>> +static bool init_device_info(struct pgt_device *pdev)
>> +{
>> +	struct gvt_device_info *info = &pdev->device_info;
>> +
>> +	if (!IS_BROADWELL(pdev->dev_priv)) {
>> +		gvt_err("Unsupported GEN device");
>> +		return false;
>> +	}
>> +
>> +	if (IS_BROADWELL(pdev->dev_priv)) {
>> +		info->max_gtt_gm_sz = (1UL << 32);
>> +		/*
>> +		 * The layout of BAR0 in BDW:
>> +		 * |< - MMIO 2MB ->|<- Reserved 6MB ->|<- MAX GTT 8MB->|
>> +		 *
>> +		 * GTT offset in BAR0 starts from 8MB to 16MB, and
>> +		 * Whatever GTT size is configured in BIOS,
>> +		 * the size of BAR0 is always 16MB. The actual configured
>> +		 * GTT size can be found in GMCH_CTRL.
>> +		 */
>> +		info->gtt_start_offset = (1UL << 23);
>> +		info->max_gtt_size = (1UL << 23);
>> +		info->gtt_entry_size = 8;
>> +		info->gtt_entry_size_shift = 3;
>> +		info->gmadr_bytes_in_cmd = 8;
>
> Would this information be useful in a header as #defines too?
>
[Zhi] Probably. Consider that one GVT-g featured kernel could be able to 
run on different platforms, the informaion data structure could be 
different. But I agree to define the magic numbers in a header files. :)

>> +	}
>> +
>> +	gvt_info("Device info:");
>> +	printk("        max_gtt_gm_sz: %llx\n", info->max_gtt_gm_sz);
>> +	printk("        max_gtt_size: %x\n", info->max_gtt_size);
>> +	printk("        gtt_size_entry: %x\n", info->gtt_entry_size);
>> +	printk("        gtt_entry_size_shift: %x\n", info->gtt_entry_size_shift);
>> +	printk("        gtt_start_offset: %x\n", info->gtt_start_offset);
>> +	printk("        gtt_end_offset: %x\n", info->gtt_end_offset);
>> +
>
> Just put this to kind of stuff to i915_debugfs.c.
>
[Zhi] Thanks.

>> +	return true;
>> +}
>> +
>> +static void init_initial_cfg_space_state(struct pgt_device *pdev)
>> +{
>> +	struct pci_dev *pci_dev = pdev->dev_priv->dev->pdev;
>> +	int i;
>> +
>> +	gvt_dbg_core("init initial cfg space, id %d", pdev->id);
>> +
>> +	for (i = 0; i < GVT_CFG_SPACE_SZ; i += 4)
>
> += sizeof(...)
>
>> +		pci_read_config_dword(pci_dev, i,
>> +				(u32 *)&pdev->initial_cfg_space[i]);
>> +
>> +	for (i = 0; i < 3; i++) {
>
> No magic numbers make a #define for 3 and give it a descriptive name.
>
>> +		pdev->bar_size[i] = pci_resource_len(pci_dev, i * 2);
>> +		gvt_info("bar %d size: %llx", i, pdev->bar_size[i]);
>> +	}
>> +}
>> +
>> +static void clean_initial_mmio_state(struct pgt_device *pdev)
>> +{
>> +	if (pdev->gttmmio_va) {
>> +		iounmap(pdev->gttmmio_va);
>> +		pdev->gttmmio_va = NULL;
>> +	}
>> +
>> +	if (pdev->gmadr_va) {
>> +		iounmap(pdev->gmadr_va);
>> +		pdev->gmadr_va = NULL;
>> +	}
>> +}
>> +
>> +static bool init_initial_mmio_state(struct pgt_device *pdev)
>> +{
>> +	u64 bar0, bar1;
>> +
>> +	gvt_dbg_core("init initial mmio state, id %d", pdev->id);
>> +
>> +	bar0 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR0];
>> +	bar1 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR1];
>> +
>> +	pdev->gttmmio_base = bar0 & ~0xf;
>> +	pdev->mmio_size = 2 * 1024 * 1024;
>> +	pdev->reg_num = pdev->mmio_size / 4;
>> +	pdev->gmadr_base = bar1 & ~0xf;
>> +
>
> Many magic numbers.
>
>> +	pdev->gttmmio_va = ioremap(pdev->gttmmio_base, pdev->bar_size[0]);
>> +	if (!pdev->gttmmio_va) {
>> +		gvt_err("fail to map GTTMMIO BAR.");
>
> These should be if(WARN_ON(...))
>
>> +		return false;
>> +	}
>> +
>> +	pdev->gmadr_va = ioremap(pdev->gmadr_base, pdev->bar_size[2]);
>> +	if (!pdev->gmadr_va) {
>> +		gvt_err("fail to map GMADR BAR.");
>> +		goto err;
>> +	}
>> +
>> +	gvt_info("bar0: 0x%llx, bar1: 0x%llx", bar0, bar1);
>> +	gvt_info("mmio size: %x", pdev->mmio_size);
>> +	gvt_info("gttmmio: 0x%llx, gmadr: 0x%llx", pdev->gttmmio_base, pdev->gmadr_base);
>> +	gvt_info("gttmmio_va: %p", pdev->gttmmio_va);
>> +	gvt_info("gmadr_va: %p", pdev->gmadr_va);
>> +
>> +	return true;
>> +err:
>> +	clean_initial_mmio_state(pdev);
>> +	return false;
>> +}
>> +
>> +static int gvt_service_thread(void *data)
>> +{
>> +	struct pgt_device *pdev = (struct pgt_device *)data;
>> +	int r;
>> +
>> +	gvt_dbg_core("service thread start, pgt %d", pdev->id);
>> +
>> +	while(!kthread_should_stop()) {
>> +		r = wait_event_interruptible(pdev->service_thread_wq,
>> +				kthread_should_stop() || pdev->service_request);
>> +
>> +		if (kthread_should_stop())
>> +			break;
>> +
>> +		if (r) {
>> +			gvt_warn("service thread is waken up by unexpected signal.");
>
> Should be WARN_ONCE, to avoid future disasters with CI.
>
[Zhi] Thanks.
>> +			continue;
>> +		}
>> +	}
>> +	return 0;
>> +}
>> +
>> +static void clean_service_thread(struct pgt_device *pdev)
>> +{
>> +	if (pdev->service_thread) {
>> +		kthread_stop(pdev->service_thread);
>> +		pdev->service_thread = NULL;
>> +	}
>> +}
>> +
>> +static bool init_service_thread(struct pgt_device *pdev)
>> +{
>> +	init_waitqueue_head(&pdev->service_thread_wq);
>> +
>> +	pdev->service_thread = kthread_run(gvt_service_thread,
>> +			pdev, "gvt_service_thread%d", pdev->id);
>> +
>> +	if (!pdev->service_thread) {
>> +		gvt_err("fail to start service thread.");
>> +		return false;
>> +	}
>> +
>> +	return true;
>> +}
>> +
>> +static void clean_pgt_device(struct pgt_device *pdev)
>> +{
>> +	clean_service_thread(pdev);
>> +	clean_initial_mmio_state(pdev);
>> +}
>> +
>> +static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *dev_priv)
>> +{
>> +	if (!init_device_info(pdev))
>> +		return false;
>> +
>> +	init_initial_cfg_space_state(pdev);
>> +
>> +	if (!init_initial_mmio_state(pdev))
>> +		goto err;
>> +
>> +	if (!init_service_thread(pdev))
>> +		goto err;
>> +
>> +	return true;
>> +err:
>> +	clean_pgt_device(pdev);
>> +	return false;
>> +}
>> +
>> +static bool post_init_pgt_device(struct pgt_device *pdev)
>> +{
>> +	return true;
>> +}
>> +
>> +static void free_pgt_device(struct pgt_device *pdev)
>> +{
>> +	struct gvt_host *host = &gvt_host;
>> +
>> +	mutex_lock(&host->device_idr_lock);
>> +	idr_remove(&host->device_idr, pdev->id);
>> +	mutex_unlock(&host->device_idr_lock);
>> +
>> +	vfree(pdev);
>> +}
>> +
>> +static struct pgt_device *alloc_pgt_device(struct drm_i915_private *dev_priv)
>> +{
>> +	struct gvt_host *host = &gvt_host;
>> +	struct pgt_device *pdev = NULL;
>> +
>> +	pdev = vzalloc(sizeof(*pdev));
>> +	if (!pdev) {
>> +		gvt_err("fail to allocate memory for pgt device.");
>> +		return NULL;
>> +	}
>> +
>> +	mutex_lock(&host->device_idr_lock);
>> +	pdev->id = idr_alloc(&host->device_idr, pdev, 0, 0, GFP_KERNEL);
>> +	mutex_unlock(&host->device_idr_lock);
>> +
>> +	if (pdev->id < 0) {
>> +		gvt_err("fail to allocate pgt device id.");
>> +		goto err;
>> +	}
>> +
>> +	mutex_init(&pdev->lock);
>> +	pdev->dev_priv = dev_priv;
>> +	idr_init(&pdev->instance_idr);
>> +
>> +	return pdev;
>> +err:
>> +	free_pgt_device(pdev);
>> +	return NULL;
>> +}
>> +
>> +void gvt_destroy_pgt_device(void *private_data)
>> +{
>> +	struct pgt_device *pdev = (struct pgt_device *)private_data;
>> +
>> +	clean_pgt_device(pdev);
>> +	free_pgt_device(pdev);
>> +}
>> +
>> +void *gvt_create_pgt_device(struct drm_i915_private *dev_priv)
>> +{
>> +	struct pgt_device *pdev = NULL;
>> +	struct gvt_host *host = &gvt_host;
>> +
>> +	if (!host->initialized && !gvt_init_host()) {
>> +		gvt_err("gvt_init_host fail");
>> +		return NULL;
>> +	}
>> +
>> +	gvt_dbg_core("create new pgt device, i915 dev_priv: %p", dev_priv);
>> +
>> +	pdev = alloc_pgt_device(dev_priv);
>> +	if (!pdev) {
>> +		gvt_err("fail to allocate memory for pgt device.");
>> +		goto err;
>> +	}
>> +
>> +	gvt_dbg_core("init pgt device, id %d", pdev->id);
>> +
>> +	if (!init_pgt_device(pdev, dev_priv)) {
>> +		gvt_err("fail to init physical device state.");
>> +		goto err;
>> +	}
>> +
>> +	gvt_dbg_core("pgt device creation done, id %d", pdev->id);
>> +
>> +	return pdev;
>> +err:
>> +	if (pdev) {
>> +		gvt_destroy_pgt_device(pdev);
>> +		pdev = NULL;
>> +	}
>> +	return NULL;
>> +}
>> +
>> +bool gvt_post_init_pgt_device(void *private_data)
>> +{
>> +	struct pgt_device *pdev = (struct pgt_device *)private_data;
>> +	struct gvt_host *host = &gvt_host;
>> +
>> +	if (!host->initialized) {
>> +		gvt_err("gvt_host haven't been initialized.");
>> +		return false;
>> +	}
>> +
>> +	gvt_dbg_core("post init pgt device %d", pdev->id);
>> +
>> +	if (!post_init_pgt_device(pdev)) {
>> +		gvt_err("fail to post init physical device state.");
>> +		return false;
>> +	}
>> +
>> +	return true;
>> +}
>> diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
>> new file mode 100644
>> index 0000000..6c85bba
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gvt/gvt.h
>> @@ -0,0 +1,130 @@
>> +/*
>> + * Copyright(c) 2011-2016 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.
>> + */
>> +
>> +#ifndef _GVT_H_
>> +#define _GVT_H_
>> +
>> +#include "i915_drv.h"
>> +#include "i915_vgpu.h"
>> +
>> +#include "debug.h"
>> +#include "params.h"
>> +#include "reg.h"
>> +#include "hypercall.h"
>> +#include "mpt.h"
>> +#include "fb_decoder.h"
>> +
>> +#define GVT_MAX_VGPU 8
>> +
>> +enum {
>> +	GVT_HYPERVISOR_TYPE_XEN = 0,
>> +	GVT_HYPERVISOR_TYPE_KVM,
>> +};
>> +
>> +struct gvt_host {
>> +	bool initialized;
>> +	int hypervisor_type;
>> +	struct mutex device_idr_lock;
>> +	struct idr device_idr;
>> +	struct gvt_kernel_dm *kdm;
>> +};
>> +
>> +extern struct gvt_host gvt_host;
>> +
>> +/* Describe the limitation of HW.*/
>> +struct gvt_device_info {
>> +	u64 max_gtt_gm_sz;
>> +	u32 gtt_start_offset;
>> +	u32 gtt_end_offset;
>> +	u32 max_gtt_size;
>> +	u32 gtt_entry_size;
>> +	u32 gtt_entry_size_shift;
>> +	u32 gmadr_bytes_in_cmd;
>> +};
>> +
>> +struct vgt_device {
>> +	int id;
>> +	int vm_id;
>> +	struct pgt_device *pdev;
>> +	bool warn_untrack;
>> +};
>> +
>> +struct pgt_device {
>> +	struct mutex lock;
>> +	int id;
>> +
>> +	struct drm_i915_private *dev_priv;
>> +	struct idr instance_idr;
>> +
>> +	struct gvt_device_info device_info;
>> +
>> +	u8 initial_cfg_space[GVT_CFG_SPACE_SZ];
>> +	u64 bar_size[GVT_BAR_NUM];
>> +
>> +	u64 gttmmio_base;
>> +	void *gttmmio_va;
>> +
>> +	u64 gmadr_base;
>> +	void *gmadr_va;
>> +
>> +	u32 mmio_size;
>> +	u32 reg_num;
>> +
>> +	wait_queue_head_t service_thread_wq;
>> +	struct task_struct *service_thread;
>> +	unsigned long service_request;
>> +};
>> +
>
> Here-->
>
>> +static inline u32 gvt_mmio_read(struct pgt_device *pdev,
>> +		u32 reg)
>> +{
>> +	struct drm_i915_private *dev_priv = pdev->dev_priv;
>> +	i915_reg_t tmp = {.reg = reg};
>> +	return I915_READ(tmp);
>> +}
>> +
>> +static inline void gvt_mmio_write(struct pgt_device *pdev,
>> +		u32 reg, u32 val)
>> +{
>> +	struct drm_i915_private *dev_priv = pdev->dev_priv;
>> +	i915_reg_t tmp = {.reg = reg};
>> +	I915_WRITE(tmp, val);
>> +}
>> +
>> +static inline u64 gvt_mmio_read64(struct pgt_device *pdev,
>> +		u32 reg)
>> +{
>> +	struct drm_i915_private *dev_priv = pdev->dev_priv;
>> +	i915_reg_t tmp = {.reg = reg};
>> +	return I915_READ64(tmp);
>> +}
>> +
>> +static inline void gvt_mmio_write64(struct pgt_device *pdev,
>> +		u32 reg, u64 val)
>> +{
>> +	struct drm_i915_private *dev_priv = pdev->dev_priv;
>> +	i915_reg_t tmp = {.reg = reg};
>> +	I915_WRITE64(tmp, val);
>> +}
>> +
>
> <-- Why? The i915_reg_t type was added to avoid problems, this code is
> not used anywhere, and it has no documentation, so I can not review it.
>
> I wrote comments at the top of the post.
>
[Zhi] Thanks, I will check that.

> Regards, Joonas
>
>> +#endif
>> diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h b/drivers/gpu/drm/i915/gvt/hypercall.h
>> new file mode 100644
>> index 0000000..0a41874
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gvt/hypercall.h
>> @@ -0,0 +1,30 @@
>> +/*
>> + * Copyright(c) 2011-2016 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.
>> + */
>> +
>> +#ifndef _GVT_HYPERCALL_H_
>> +#define _GVT_HYPERCALL_H_
>> +
>> +struct gvt_kernel_dm {
>> +};
>> +
>> +#endif /* _GVT_HYPERCALL_H_ */
>> diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h
>> new file mode 100644
>> index 0000000..bbe4465
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gvt/mpt.h
>> @@ -0,0 +1,97 @@
>> +/*
>> + * Copyright(c) 2011-2016 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.
>> + */
>> +
>> +#ifndef _GVT_MPT_H_
>> +#define _GVT_MPT_H_
>> +
>> +struct vgt_device;
>> +
>> +static inline unsigned long hypervisor_g2m_pfn(struct vgt_device *vgt,
>> +	unsigned long g_pfn)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline int hypervisor_pause_domain(struct vgt_device *vgt)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline int hypervisor_shutdown_domain(struct vgt_device *vgt)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline int hypervisor_set_trap_area(struct vgt_device *vgt,
>> +	uint64_t start, uint64_t end, bool map)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline bool hypervisor_detect_host(void)
>> +{
>> +	return false;
>> +}
>> +
>> +static inline int hypervisor_virt_to_mfn(void *addr)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline void *hypervisor_mfn_to_virt(int mfn)
>> +{
>> +	return NULL;
>> +}
>> +
>> +static inline void hypervisor_inject_msi(struct vgt_device *vgt)
>> +{
>> +	return;
>> +}
>> +
>> +static inline int hypervisor_hvm_init(struct vgt_device *vgt)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline void hypervisor_hvm_exit(struct vgt_device *vgt)
>> +{
>> +}
>> +
>> +static inline void *hypervisor_gpa_to_va(struct vgt_device *vgt, unsigned long gpa)
>> +{
>> +	return NULL;
>> +}
>> +
>> +static inline bool hypervisor_read_va(struct vgt_device *vgt, void *va,
>> +		void *val, int len, int atomic)
>> +{
>> +	return false;
>> +}
>> +
>> +static inline bool hypervisor_write_va(struct vgt_device *vgt, void *va,
>> +		void *val, int len, int atomic)
>> +{
>> +	return false;
>> +}
>> +
>> +#endif /* _GVT_MPT_H_ */
>> diff --git a/drivers/gpu/drm/i915/gvt/params.c b/drivers/gpu/drm/i915/gvt/params.c
>> new file mode 100644
>> index 0000000..dfc33c3
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gvt/params.c
>> @@ -0,0 +1,29 @@
>> +/*
>> + * Copyright(c) 2011-2016 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 "gvt.h"
>> +
>> +struct gvt_kernel_params gvt = {
>> +	.enable = true,
>> +	.debug = 0,
>> +};
>> diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
>> new file mode 100644
>> index 0000000..d2955b9
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gvt/params.h
>> @@ -0,0 +1,34 @@
>> +/*
>> + * Copyright(c) 2011-2016 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.
>> + */
>> +
>> +#ifndef _GVT_PARAMS_H_
>> +#define _GVT_PARAMS_H_
>> +
>> +struct gvt_kernel_params {
>> +	bool enable;
>> +	int debug;
>> +};
>> +
>> +extern struct gvt_kernel_params gvt;
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
>> new file mode 100644
>> index 0000000..d363b74
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/gvt/reg.h
>> @@ -0,0 +1,34 @@
>> +/*
>> + * Copyright(c) 2011-2016 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.
>> + */
>> +
>> +#ifndef _GVT_REG_H
>> +#define _GVT_REG_H
>> +
>> +#define GVT_CFG_SPACE_SZ	256
>> +#define GVT_BAR_NUM		4
>> +
>> +#define GVT_REG_CFG_SPACE_BAR0	0x10
>> +#define GVT_REG_CFG_SPACE_BAR1	0x18
>> +#define GVT_REG_CFG_SPACE_BAR2	0x20
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
>> index 4725e8d..eca8e50 100644
>> --- a/drivers/gpu/drm/i915/i915_dma.c
>> +++ b/drivers/gpu/drm/i915/i915_dma.c
>> @@ -943,6 +943,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>>
>>   	intel_uncore_init(dev);
>>
>> +	dev_priv->vgpu.host_private_data = gvt_create_pgt_device(dev_priv);
>> +	if(intel_gvt_host_active(dev))
>> +		DRM_INFO("GVT-g is running in host mode\n");
>> +
>>   	ret = i915_gem_gtt_init(dev);
>>   	if (ret)
>>   		goto out_freecsr;
>> @@ -1067,6 +1071,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>>   		goto out_power_well;
>>   	}
>>
>> +	if (intel_gvt_host_active(dev)) {
>> +		if (!gvt_post_init_pgt_device(dev_priv->vgpu.host_private_data)) {
>> +			DRM_ERROR("failed to post init pgt device\n");
>> +			goto out_power_well;
>> +		}
>> +	}
>> +
>>   	/*
>>   	 * Notify a valid surface after modesetting,
>>   	 * when running inside a VM.
>> @@ -1117,6 +1128,10 @@ out_gtt:
>>   	i915_global_gtt_cleanup(dev);
>>   out_freecsr:
>>   	intel_csr_ucode_fini(dev_priv);
>> +	if (intel_gvt_host_active(dev)) {
>> +		gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
>> +		dev_priv->vgpu.host_private_data = NULL;
>> +	}
>>   	intel_uncore_fini(dev);
>>   	pci_iounmap(dev->pdev, dev_priv->regs);
>>   put_bridge:
>> @@ -1165,6 +1180,10 @@ int i915_driver_unload(struct drm_device *dev)
>>
>>   	intel_modeset_cleanup(dev);
>>
>> +	if (intel_gvt_host_active(dev)) {
>> +		gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
>> +		dev_priv->vgpu.host_private_data = NULL;
>> +	}
>>   	/*
>>   	 * free the memory space allocated for the child device
>>   	 * config parsed from VBT
>> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>> index 01cc982..db3c79b 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.h
>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> @@ -1673,6 +1673,7 @@ struct i915_workarounds {
>>
>>   struct i915_virtual_gpu {
>>   	bool active;
>> +	void *host_private_data;
>>   };
>>
>>   struct i915_execbuffer_params {
>> @@ -2747,6 +2748,11 @@ static inline bool intel_vgpu_active(struct drm_device *dev)
>>   	return to_i915(dev)->vgpu.active;
>>   }
>>
>> +static inline bool intel_gvt_host_active(struct drm_device *dev)
>> +{
>> +	return to_i915(dev)->vgpu.host_private_data ? true : false;
>> +}
>> +
>>   void
>>   i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
>>   		     u32 status_mask);
>> diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
>> index 3c83b47..942490a 100644
>> --- a/drivers/gpu/drm/i915/i915_vgpu.h
>> +++ b/drivers/gpu/drm/i915/i915_vgpu.h
>> @@ -113,5 +113,8 @@ struct vgt_if {
>>   extern void i915_check_vgpu(struct drm_device *dev);
>>   extern int intel_vgt_balloon(struct drm_device *dev);
>>   extern void intel_vgt_deballoon(void);
>> +extern void *gvt_create_pgt_device(struct drm_i915_private *dev_priv);
>> +extern bool gvt_post_init_pgt_device(void *private_data);
>> +extern void gvt_destroy_pgt_device(void *private_data);
>>
>>   #endif /* _I915_VGPU_H_ */
>> diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
>> index d133112..78a38f1 100644
>> --- a/include/xen/interface/xen.h
>> +++ b/include/xen/interface/xen.h
>> @@ -28,6 +28,7 @@
>>   #define __XEN_PUBLIC_XEN_H__
>>
>>   #include
>> +#include
>>
>>   /*
>>    * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g
  2016-01-29 16:48     ` Chris Wilson
@ 2016-02-03  6:28       ` Zhi Wang
  2016-02-05  7:02       ` Zhiyuan Lv
  1 sibling, 0 replies; 49+ messages in thread
From: Zhi Wang @ 2016-02-03  6:28 UTC (permalink / raw)
  To: Chris Wilson, Joonas Lahtinen, intel-gfx, igvt-g, kevin.tian,
	zhiyuan.lv, bing.niu, jike.song, daniel.vetter,
	david.j.cowperthwaite

Hi Chris:
     Thanks for your feedback. :) Currently there are some host i915 
changes we need to discussion, need your advice and feedback. For GVT 
LRC context, as you see, we need it to do shadow context. All the 
modifications of LRC are for it. Need inputs to think a better approach 
or code placement. :)

---

The GGTT page table is shadowed in GVT-g. When guest writes the GTT 
MMIOs, this write will be trapped by hypervisor, GVT-g will check if 
it's a MMIO access which needs to be emulated, or a GGTT page table 
entry which needs to be shadowed, then the shadowed GGTT page table 
entry will be written into pGGTT page table. So that the mapping looks like:

 From guest point of view:

guest PFN -> guest GGTT page table entry -> guest GGTT MMIO

The GVT-g shadow process looks like:

guest PFN -> guest GGTT page table entry -> GVT-g translated guest PFN 
to machine PFN -> GVT-g writes the translated entry into physical GGTT MMIO.

---

The hypervisor_{read, write}_va() abstraction layer is to cover the 
different approaches between hypervisors to let the host i915 to access 
guest memory.

For example, guest writes the vELSP to submit a workload, then 
hypervisor traps these writes and forward them to GVT-g core logic. 
Actually, if GVT-g wants to access the guest context, only LRCA (GGTT 
address) could be extracted from guest context descriptor.

First GVT-g will try to get the guest PFN from guest GGTT page table 
(You can see the GGTT/PPGTT page table entry extraction routines in gtt.c),

Second GVT-g will try to get the host VA with the guest PFN via 
hypervisor specific routines. (The function gvt_gma_to_va())

Then call hypervisor_{read,write}_va() to let hypervisor specific 
routines to read/write the data from/to guest via hypervisor specific 
routines.

This is a typical scenario of how GVT-g access a guest GGTT mapped 
memory. For PPGTT, it becomes much more complicated.(Also in 
gvt_gma_to_va())

On 01/30/16 00:48, Chris Wilson wrote:
> On Fri, Jan 29, 2016 at 03:57:09PM +0200, Joonas Lahtinen wrote:
>> Hi,
>>
>> TL;DR Overall, we have same problem as with the scheduler series, there
>> is too much placeholder stuff for easy review. Just squash enough code
>> into one commit so it actually does something logical that can be
>> reviewed and then extend it later. Then it can be reviewed and pushed.
>> Just splitting the code down to achieve smaller patches is not the
>> right thing to do.
>>
>> Comments on the overall code: You need to document all header file
>> functions (in the source files), and it is good to document the static
>> functions within a file too, to make future maintenance easier.
>>
>> It is not about splitting the code down to small chunks, but splitting
>> it down to small *logical* chunks. It doesn't make sense to commit
>> dozens of empty bodied functions for review, and then later add their
>> code.
>>
>> If you add functions, only add them at a patch that takes them into use
>> too, unless we're talking about general purpose shared code. And also
>> remember to add the function body and documentation header. If you
>> simply add a "return 0;" or similar function body, do add a comment to
>> why the function does not exist and when it will.
>>
>> Then, there is a trend of having a boolean return values in the code.
>> When possible, it should rather be int and the cause for failure should
>> be propagated from the last level all the way to up (-ENOMEN etc.).
>> This way debugging becomes easier and if new error conditions appear,
>> there is less of a maintenance burden to add the propagation later.
>>
>> Finally, make sure to look at the existing driver parts and
>> 	https://www.kernel.org/doc/Documentation/CodingStyle
>> for proper coding style. There are lots of whitespace fixes needed in
>> this series, like array initializations.
>>
>> I hope to see this first patch rerolled so that you squash some of the
>> later commits into it so that all functions have a body and you add
>> documentation for the functions so I can both see what it should do and
>> what it actually does. Only reroll the first patch, to keep the
>> iterative step smaller. Lets only then continue with the rest of the
>> series once we've reached a consensus on the formatting and style
>> basics.
>>
>> See more comments below.
>
> I'm glad you did the nitpicking. As far as the integration goes, on the
> whole I'm happy with the way it is structured and the reuse of existing
> code. I tried to attack various aspects of the GVT contexts and came to
> the conclusion I couldn't suggest a better approach (though maybe
> tomorrow!). A few bits and pieces I got lost trying to pull together
> (in particular like how we do is read back through the GTT entries
> performed, the hypervisor_read_va abstraction iirc) and would appreciate
> having a branch available to get the complete picture.
> -Chris
>
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g
  2016-02-03  6:01     ` Zhi Wang
@ 2016-02-03  7:01       ` Zhiyuan Lv
  2016-02-04 11:25       ` Joonas Lahtinen
  2016-02-16  9:54       ` Zhi Wang
  2 siblings, 0 replies; 49+ messages in thread
From: Zhiyuan Lv @ 2016-02-03  7:01 UTC (permalink / raw)
  To: Zhi Wang, Joonas Lahtinen
  Cc: daniel.vetter, intel-gfx, david.j.cowperthwaite, igvt-g

On Wed, Feb 03, 2016 at 02:01:15PM +0800, Zhi Wang wrote:
> Hi Joonas:
>     Thanks you very much! We're very excited for receiving your
> advice and continue to be open to any comments. :)
> 
> I'm supposed that we should make the agreements on i915 host change
> at the very beginning, as I'm concerned during the discussion of
> i915 host change, you know, maybe some code of GVT-g needs to be
> refined or re-designed. So we put the i915 host changes to the
> beginning of the patch set for the convenience of discussion.
> 
> I summarize your comments as below, very applicate. :)
> 
> - Replace boolean return value with int as much as possible.
> - Replace customized debug ASSERT() function & macros with DRM_DEBUG_*
> - Document all non-static functions like i915
> - Fix all whitespace via scripts/cleanpatch.pl
> - Commit function structure refinement.
> - Change the register access behavior just like what i915 does.
> 
> For other comments, see my comments below. :)
> 
> On 01/29/16 21:57, Joonas Lahtinen wrote:

snip

> >>+		/* Xen Dom0 */
> >>+		host->kdm = try_then_request_module(symbol_get(xengt_kdm), "xengt");
> >>+		host->hypervisor_type = GVT_HYPERVISOR_TYPE_XEN;
> >>+	} else if(xen_domain()) {
> >>+		/* Xen DomU */
> >>+		return false;
> >>+	} else {
> >>+		/* not in Xen. Try KVMGT */
> >>+		host->kdm = try_then_request_module(symbol_get(kvmgt_kdm), "kvm");
> >>+		host->hypervisor_type = GVT_HYPERVISOR_TYPE_KVM;
> >>+	}
> >>+
> >
> >Why do we need to keep track of hypervisor type, are there plenty of
> >hypervisor specific behaviour differences?
> 
> [Zhi] As GVT-g needs some hypervisor services to work, we write a
> abstraction layer to connect GVT-g to different hypervisor. But
> still there are some emulation logic couldn't be fitted into that
> abstraction layer, like OpRegion emulation. In Xen, we emulates it
> in kernel space, while we emulates it in Qemu under KVM. I also

Just a small clarify: most likely the cfg-emulation for KVMGT will be
in kernel as well. This part is under discussion. But still we may
have code related to hypervisor type in device model, for instance,
VFIO based implementation for KVM only. Thanks!

Regards,
-Zhiyuan
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g
  2016-02-03  6:01     ` Zhi Wang
  2016-02-03  7:01       ` Zhiyuan Lv
@ 2016-02-04 11:25       ` Joonas Lahtinen
  2016-02-16  9:54       ` Zhi Wang
  2 siblings, 0 replies; 49+ messages in thread
From: Joonas Lahtinen @ 2016-02-04 11:25 UTC (permalink / raw)
  To: Zhi Wang, intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

Hi,

On ke, 2016-02-03 at 14:01 +0800, Zhi Wang wrote:
> Hi Joonas:
>      Thanks you very much! We're very excited for receiving your advice 
> and continue to be open to any comments. :)
> 
> I'm supposed that we should make the agreements on i915 host change at 
> the very beginning, as I'm concerned during the discussion of i915 host 
> change, you know, maybe some code of GVT-g needs to be refined or 
> re-designed. So we put the i915 host changes to the beginning of the 
> patch set for the convenience of discussion.
> 
> I summarize your comments as below, very applicate. :)
> 
> - Replace boolean return value with int as much as possible.
> - Replace customized debug ASSERT() function & macros with DRM_DEBUG_*
> - Document all non-static functions like i915
> - Fix all whitespace via scripts/cleanpatch.pl
> - Commit function structure refinement.
> - Change the register access behavior just like what i915 does.
> 
> For other comments, see my comments below. :)
> 
> On 01/29/16 21:57, Joonas Lahtinen wrote:
> > Hi,
> > 
> > TL;DR Overall, we have same problem as with the scheduler series, there
> > is too much placeholder stuff for easy review. Just squash enough code
> > into one commit so it actually does something logical that can be
> > reviewed and then extend it later. Then it can be reviewed and pushed.
> > Just splitting the code down to achieve smaller patches is not the
> > right thing to do.
> > 
> > Comments on the overall code: You need to document all header file
> > functions (in the source files), and it is good to document the static
> > functions within a file too, to make future maintenance easier.
> > 
> > It is not about splitting the code down to small chunks, but splitting
> > it down to small *logical* chunks. It doesn't make sense to commit
> > dozens of empty bodied functions for review, and then later add their
> > code.
> > 
> > If you add functions, only add them at a patch that takes them into use
> > too, unless we're talking about general purpose shared code. And also
> > remember to add the function body and documentation header. If you
> > simply add a "return 0;" or similar function body, do add a comment to
> > why the function does not exist and when it will.
> > 
> > Then, there is a trend of having a boolean return values in the code.
> > When possible, it should rather be int and the cause for failure should
> > be propagated from the last level all the way to up (-ENOMEN etc.).
> > This way debugging becomes easier and if new error conditions appear,
> > there is less of a maintenance burden to add the propagation later.
> > 
> > Finally, make sure to look at the existing driver parts and
> > 	https://www.kernel.org/doc/Documentation/CodingStyle
> > for proper coding style. There are lots of whitespace fixes needed in
> > this series, like array initializations.
> > 
> > I hope to see this first patch rerolled so that you squash some of the
> > later commits into it so that all functions have a body and you add
> > documentation for the functions so I can both see what it should do and
> > what it actually does. Only reroll the first patch, to keep the
> > iterative step smaller. Lets only then continue with the rest of the
> > series once we've reached a consensus on the formatting and style
> > basics.
> > 
> > See more comments below.
> > 
> > On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
> > > This patch introduces the very basic framework of GVT-g device model,
> > > includes basic prototypes, definitions, initialization.
> > > ---
> > >   arch/x86/include/asm/xen/interface.h  |   3 +
> > >   drivers/gpu/drm/i915/Kconfig          |  16 ++
> > >   drivers/gpu/drm/i915/Makefile         |   2 +
> > >   drivers/gpu/drm/i915/gvt/Makefile     |   5 +
> > >   drivers/gpu/drm/i915/gvt/debug.h      |  72 +++++++
> > >   drivers/gpu/drm/i915/gvt/fb_decoder.c |  34 ++++
> > >   drivers/gpu/drm/i915/gvt/fb_decoder.h | 110 ++++++++++
> > >   drivers/gpu/drm/i915/gvt/gvt.c        | 366 ++++++++++++++++++++++++++++++++++
> > >   drivers/gpu/drm/i915/gvt/gvt.h        | 130 ++++++++++++
> > >   drivers/gpu/drm/i915/gvt/hypercall.h  |  30 +++
> > >   drivers/gpu/drm/i915/gvt/mpt.h        |  97 +++++++++
> > >   drivers/gpu/drm/i915/gvt/params.c     |  29 +++
> > >   drivers/gpu/drm/i915/gvt/params.h     |  34 ++++
> > >   drivers/gpu/drm/i915/gvt/reg.h        |  34 ++++
> > >   drivers/gpu/drm/i915/i915_dma.c       |  19 ++
> > >   drivers/gpu/drm/i915/i915_drv.h       |   6 +
> > >   drivers/gpu/drm/i915/i915_vgpu.h      |   3 +
> > >   include/xen/interface/xen.h           |   1 +
> > >   18 files changed, 991 insertions(+)
> > >   create mode 100644 drivers/gpu/drm/i915/gvt/Makefile
> > >   create mode 100644 drivers/gpu/drm/i915/gvt/debug.h
> > >   create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.c
> > >   create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.h
> > >   create mode 100644 drivers/gpu/drm/i915/gvt/gvt.c
> > >   create mode 100644 drivers/gpu/drm/i915/gvt/gvt.h
> > >   create mode 100644 drivers/gpu/drm/i915/gvt/hypercall.h
> > >   create mode 100644 drivers/gpu/drm/i915/gvt/mpt.h
> > >   create mode 100644 drivers/gpu/drm/i915/gvt/params.c
> > >   create mode 100644 drivers/gpu/drm/i915/gvt/params.h
> > >   create mode 100644 drivers/gpu/drm/i915/gvt/reg.h
> > > 
> > > diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h
> > > index 62ca03e..6ff4986 100644
> > > --- a/arch/x86/include/asm/xen/interface.h
> > > +++ b/arch/x86/include/asm/xen/interface.h
> > > @@ -73,6 +73,9 @@
> > >   #endif
> > > 
> > >   #ifndef __ASSEMBLY__
> > > +
> > > +#include
> > > +
> > 
> > I don't follow why this would need to be added if the file is not
> > modified otherwise. Each header should only include what they use.
> > 
> > If this is an existing bug (that xen/interface.h can not be included
> > without including linux/types.h), it should be split to a separate
> > patch and sent to Xen team. Same for include/xen/interface/xen.h.
> > 
> > >   /* Explicitly size integers that represent pfns in the public interface
> > >    * with Xen so that on ARM we can have one ABI that works for 32 and 64
> > >    * bit guests. */
> > > diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
> > > index 051eab3..89ff723 100644
> > > --- a/drivers/gpu/drm/i915/Kconfig
> > > +++ b/drivers/gpu/drm/i915/Kconfig
> > > @@ -47,3 +47,19 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT
> > >   	  option changes the default for that module option.
> > > 
> > >   	  If in doubt, say "N".
> > > +
> > > +config I915_GVT
> > > +        tristate "GVT-g host driver"
> > > +        depends on DRM_I915
> > > +        select IRQ_WORK
> > > +        default y
> > 
> > Defaulting to "n" would make sense initially.
> > 
> [Zhi] Sure, will do.
> > > +        help
> > > +          Enabling GVT-g mediated graphics passthrough technique for Intel i915
> > > +          based integrated graphics card. With GVT-g, it's possible to have one
> > > +          integrated i915 device shared by multiple VMs. Performance critical
> > > +          opterations such as apperture accesses and ring buffer operations
> > > +          are pass-throughed to VM, with a minimal set of conflicting resources
> > > +          (e.g. display settings) mediated by vGT driver. The benefit of vGT
> > > +          is on both the performance, given that each VM could directly operate
> > > +          its aperture space and submit commands like running on native, and
> > > +          the feature completeness, given that a true GEN hardware is exposed.
> > > diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> > > index 0851de07..d4df410 100644
> > > --- a/drivers/gpu/drm/i915/Makefile
> > > +++ b/drivers/gpu/drm/i915/Makefile
> > > @@ -91,6 +91,8 @@ i915-y += dvo_ch7017.o \
> > >   	  intel_sdvo.o \
> > >   	  intel_tv.o
> > > 
> > > +obj-$(CONFIG_I915_GVT)  += gvt/
> > > +
> > >   # virtual gpu code
> > >   i915-y += i915_vgpu.o
> > > 
> > > diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
> > > new file mode 100644
> > > index 0000000..6935b78
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/i915/gvt/Makefile
> > > @@ -0,0 +1,5 @@
> > > +GVT_SOURCE := gvt.o params.o fb_decoder.o
> > > +
> > > +ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
> > > +i915_gvt-y			:= $(GVT_SOURCE)
> > > +obj-$(CONFIG_I915_GVT)		+= i915_gvt.o
> > > diff --git a/drivers/gpu/drm/i915/gvt/debug.h b/drivers/gpu/drm/i915/gvt/debug.h
> > > new file mode 100644
> > > index 0000000..18e1467
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/i915/gvt/debug.h
> > > @@ -0,0 +1,72 @@
> > > +/*
> > > + * Copyright(c) 2011-2016 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.
> > > + */
> > > +
> > > +#ifndef __GVT_DEBUG_H__
> > > +#define __GVT_DEBUG_H__
> > > +
> > > +#define ASSERT(x)                                                       \
> > > +        do {                                                            \
> > > +                if (!(x)) {                                             \
> > > +                        printk("Assert at %s line %d\n",                \
> > > +                                __FILE__, __LINE__);                    \
> > > +                }                                                       \
> > > +        } while (0);
> > > +
> > > +#define ASSERT_NUM(x, y)                                                \
> > > +        do {                                                            \
> > > +                if (!(x)) {                                             \
> > > +                        printk("Assert at %s line %d para 0x%llx\n",    \
> > > +                                __FILE__, __LINE__, (u64)y);            \
> > > +                }                                                       \
> > > +        } while (0);
> > > +
> > 
> > There already is WARN_ON (and i915_drv.h modifies it a little). Do not
> > introduce custom functions like this, if the existing ones need
> > improvement, improve them.
> > 
> [Zhi] OK. Will do as what i915 does
> > > +#define gvt_info(fmt, args...) \
> > > +	printk(KERN_INFO"[GVT-g] "fmt"\n", ##args)
> > > +
> > > +#define gvt_err(fmt, args...) \
> > > +	printk(KERN_ERR"%s() - %d: "fmt"\n", __func__, __LINE__, ##args)
> > > +
> > > +#define gvt_warn(fmt, args...) \
> > > +	printk(KERN_WARNING"%s() - %d: "fmt"\n", __func__, __LINE__, ##args)
> > > +
> > > +#define gvt_dbg(level, fmt, args...) do { \
> > > +		if (gvt.debug & level) \
> > > +			printk(KERN_DEBUG"%s() - %d: "fmt"\n", __func__, __LINE__, ##args); \
> > > +	}while(0)
> > > +
> > > +enum {
> > > +	GVT_DBG_CORE = (1 << 0),
> > > +	GVT_DBG_MM = (1 << 1),
> > > +	GVT_DBG_IRQ = (1 << 2),
> > > +};
> > > +
> > > +#define gvt_dbg_core(fmt, args...) \
> > > +	gvt_dbg(GVT_DBG_CORE, fmt, ##args)
> > > +
> > > +#define gvt_dbg_mm(fmt, args...) \
> > > +	gvt_dbg(GVT_DBG_MM, fmt, ##args)
> > > +
> > > +#define gvt_dbg_irq(fmt, args...) \
> > > +	gvt_dbg(GVT_DBG_IRQ, fmt, ##args)
> > > +
> > > +#endif
> > 
> > This should be integrated better to DRM debugging options, custom
> > debugging code only for i915 was rejected a while ago.
> > 
> [ZHI] Thanks for sharing the history. :) Will change that.
> > > diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c b/drivers/gpu/drm/i915/gvt/fb_decoder.c
> > > new file mode 100644
> > > index 0000000..a219819
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c
> > > @@ -0,0 +1,34 @@
> > > +/*
> > > + * Copyright(c) 2011-2016 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 "gvt.h"
> > > +
> > > +int gvt_decode_fb_format(struct pgt_device *pdev, int vmid, struct gvt_fb_format *fb)
> > > +{
> > > +	return 0;
> > > +}
> > > +
> > > +int gvt_fb_notifier_call_chain(unsigned long val, void *data)
> > > +{
> > > +	return 0;
> > > +}
> > 
> > Kerneldoc missing for these functions. It is all the same to squash
> > later patches to introduce the code to these functions already,
> > reviewing utility functions with no kerneldoc and no body makes it
> > somewhat difficult to see the big picture.
> > 
> 
> [Zhi] One question. I saw i915 put some function instruction in *.c. Is 
> it also OK for kernel doc generating the proper doc files?

Yes, (again referring to history) there was a suggestion to move all
the documentation to header files and it was decided on that the
documentation should RATHER be in the implementation than header files.
Then it's closer to the implementation when on is changing the function
and one has a higher chance of updating it, rather than switching
between header and implementation.

> 
> > > diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.h b/drivers/gpu/drm/i915/gvt/fb_decoder.h
> > > new file mode 100644
> > > index 0000000..2c29ed4
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.h
> > > @@ -0,0 +1,110 @@
> > > +/*
> > > + * Copyright(c) 2011-2016 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.
> > > + */
> > > +
> > > +#ifndef _GVT_FB_DECODER_H_
> > > +#define _GVT_FB_DECODER_H_
> > > +
> > > +typedef enum {
> > > +	FB_MODE_SET_START = 1,
> > > +	FB_MODE_SET_END,
> > > +	FB_DISPLAY_FLIP,
> > > +}gvt_fb_event_t;
> > > +
> > > +typedef enum {
> > > +	DDI_PORT_NONE	= 0,
> > > +	DDI_PORT_B	= 1,
> > > +	DDI_PORT_C	= 2,
> > > +	DDI_PORT_D	= 3,
> > > +	DDI_PORT_E	= 4
> > > +} ddi_port_t;
> > > +
> > > +struct pgt_device;
> > > +
> > > +struct gvt_fb_notify_msg {
> > > +	unsigned vm_id;
> > > +	unsigned pipe_id; /* id starting from 0 */
> > > +	unsigned plane_id; /* primary, cursor, or sprite */
> > > +};
> > > +
> > > +/* color space conversion and gamma correction are not included */
> > > +struct gvt_primary_plane_format {
> > > +	u8	enabled;	/* plane is enabled */
> > > +	u8	tiled;		/* X-tiled */
> > > +	u8	bpp;		/* bits per pixel */
> > > +	u32	hw_format;	/* format field in the PRI_CTL register */
> > > +	u32	drm_format;	/* format in DRM definition */
> > > +	u32	base;		/* framebuffer base in graphics memory */
> > > +	u32	x_offset;	/* in pixels */
> > > +	u32	y_offset;	/* in lines */
> > > +	u32	width;		/* in pixels */
> > > +	u32	height;		/* in lines */
> > > +	u32	stride;		/* in bytes */
> > > +};
> > > +
> > > +struct gvt_sprite_plane_format {
> > > +	u8	enabled;	/* plane is enabled */
> > > +	u8	tiled;		/* X-tiled */
> > > +	u8	bpp;		/* bits per pixel */
> > > +	u32	hw_format;	/* format field in the SPR_CTL register */
> > > +	u32	drm_format;	/* format in DRM definition */
> > > +	u32	base;		/* sprite base in graphics memory */
> > > +	u32	x_pos;		/* in pixels */
> > > +	u32	y_pos;		/* in lines */
> > > +	u32	x_offset;	/* in pixels */
> > > +	u32	y_offset;	/* in lines */
> > > +	u32	width;		/* in pixels */
> > > +	u32	height;		/* in lines */
> > > +};
> > > +
> > > +struct gvt_cursor_plane_format {
> > > +	u8	enabled;
> > > +	u8	mode;		/* cursor mode select */
> > > +	u8	bpp;		/* bits per pixel */
> > > +	u32	drm_format;	/* format in DRM definition */
> > > +	u32	base;		/* cursor base in graphics memory */
> > > +	u32	x_pos;		/* in pixels */
> > > +	u32	y_pos;		/* in lines */
> > > +	u8	x_sign;		/* X Position Sign */
> > > +	u8	y_sign;		/* Y Position Sign */
> > > +	u32	width;		/* in pixels */
> > > +	u32	height;		/* in lines */
> > > +	u32	x_hot;		/* in pixels */
> > > +	u32	y_hot;		/* in pixels */
> > > +};
> > > +
> > 
> > The above structs have a lot in common, would it make sense to have the
> > common members + plane type and then union for the plane type specific
> > data. I suspect having it all split this way will lead to more utility
> > functions somewhere.
> > 
> [Zhi] Thanks. Will do that.
> 
> > > +struct gvt_pipe_format {
> > > +	struct gvt_primary_plane_format	primary;
> > > +	struct gvt_sprite_plane_format	sprite;
> > > +	struct gvt_cursor_plane_format	cursor;
> > > +	ddi_port_t ddi_port;  /* the DDI port that the pipe is connected to */
> > > +};
> > > +
> > > +struct gvt_fb_format{
> > > +	struct gvt_pipe_format	pipes[I915_MAX_PIPES];
> > > +};
> > > +
> > > +extern int gvt_fb_notifier_call_chain(unsigned long val, void *data);
> > > +extern int gvt_decode_fb_format(struct pgt_device *pdev, int vmid,
> > > +				struct gvt_fb_format *fb);
> > > +
> > > +#endif
> > > diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
> > > new file mode 100644
> > > index 0000000..041d10f
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/i915/gvt/gvt.c
> > > @@ -0,0 +1,366 @@
> > > +/*
> > > + * Copyright(c) 2011-2016 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
> > > +#include
> > > +
> > > +#include "gvt.h"
> > > +
> > > +struct gvt_host gvt_host;
> > > +
> > > +extern struct gvt_kernel_dm xengt_kdm;
> > > +extern struct gvt_kernel_dm kvmgt_kdm;
> > > +
> > > +static const char *supported_hypervisors[] = {
> > 
> > should be "static const char * const".
> > 
> > > +	[GVT_HYPERVISOR_TYPE_XEN] = "Xen Hypervisor",
> > > +	[GVT_HYPERVISOR_TYPE_KVM] = "KVM",
> > > +};
> > > +
> > > +static bool gvt_init_host(void)
> > > +{
> > > +	struct gvt_host *host = &gvt_host;
> > > +
> > > +	if (!gvt.enable) {
> > > +		gvt_dbg_core("GVT-g has been disabled by kernel parameter");
> > > +		return false;
> > > +	}
> > > +
> > > +	if (host->initialized) {
> > > +		gvt_err("GVT-g has already been initialized!");
> > > +		return false;
> > > +	}
> > > +
> > > +	if (xen_initial_domain()) {
> > 
> > Shouldn't Xen code be CONFIG_XEN_DOM0 and CONFIG_XEN #ifdef protected?
> > 
> [Zhi] The following code piece shows xen_initial_domain()/xen_domain() 
> could also be used when CONFIG_XEN_DOM0 is not set.
> 
> #ifdef CONFIG_XEN
> extern enum xen_domain_type xen_domain_type;
> #else
> #define xen_domain_type         XEN_NATIVE
> #endif
> 

Ok, then it's cool. I missed this construct :)

> #define xen_domain()            (xen_domain_type != XEN_NATIVE)
> #define xen_pv_domain()         (xen_domain() &&                        \
>                                   xen_domain_type == XEN_PV_DOMAIN)
> #define xen_hvm_domain()        (xen_domain() &&                        \
>                                   xen_domain_type == XEN_HVM_DOMAIN)
> 
> #ifdef CONFIG_XEN_DOM0
> #include 
> #include 
> 
> #define xen_initial_domain()    (xen_domain() && \
>                                   xen_start_info && 
> xen_start_info->flags & SIF_INITDOMAIN)
> #else  /* !CONFIG_XEN_DOM0 */
> #define xen_initial_domain()    (0)
> #endif  /* CONFIG_XEN_DOM0 */
> 
> > > +		/* Xen Dom0 */
> > > +		host->kdm = try_then_request_module(symbol_get(xengt_kdm), "xengt");
> > > +		host->hypervisor_type = GVT_HYPERVISOR_TYPE_XEN;
> > > +	} else if(xen_domain()) {
> > > +		/* Xen DomU */
> > > +		return false;
> > > +	} else {
> > > +		/* not in Xen. Try KVMGT */
> > > +		host->kdm = try_then_request_module(symbol_get(kvmgt_kdm), "kvm");
> > > +		host->hypervisor_type = GVT_HYPERVISOR_TYPE_KVM;
> > > +	}
> > > +
> > 
> > Why do we need to keep track of hypervisor type, are there plenty of
> > hypervisor specific behaviour differences?
> 
> [Zhi] As GVT-g needs some hypervisor services to work, we write a 
> abstraction layer to connect GVT-g to different hypervisor. But still 
> there are some emulation logic couldn't be fitted into that abstraction 
> layer, like OpRegion emulation. In Xen, we emulates it in kernel space, 
> while we emulates it in Qemu under KVM. I also agreed that we should 
> find some approach to improve it just like what you said.
> 

Yep, if correcting it is not currently possible, I can live with it.
But host->hypervisor_type dependent code should be kept to absolute
minimum.

Regards, Joonas

> > If it is just for printing
> > the below debug, I think it's better to move the debug into above code
> > that detects the hypervisor, wrap them with appropriate CONFIG #ifdefs.
> > 
> > > +	if (!host->kdm)
> > > +		return false;
> > > +
> > > +	if (!hypervisor_detect_host())
> > > +		return false;
> > > +
> > > +	gvt_info("Running with hypervisor %s in host mode",
> > > +			supported_hypervisors[host->hypervisor_type]);
> > > +
> > > +	idr_init(&host->device_idr);
> > > +	mutex_init(&host->device_idr_lock);
> > > +
> > > +	host->initialized = true;
> > > +	return true;
> > > +}
> > > +
> > > +static bool init_device_info(struct pgt_device *pdev)
> > > +{
> > > +	struct gvt_device_info *info = &pdev->device_info;
> > > +
> > > +	if (!IS_BROADWELL(pdev->dev_priv)) {
> > > +		gvt_err("Unsupported GEN device");
> > > +		return false;
> > > +	}
> > > +
> > > +	if (IS_BROADWELL(pdev->dev_priv)) {
> > > +		info->max_gtt_gm_sz = (1UL << 32);
> > > +		/*
> > > +		 * The layout of BAR0 in BDW:
> > > +		 * |< - MMIO 2MB ->|<- Reserved 6MB ->|<- MAX GTT 8MB->|
> > > +		 *
> > > +		 * GTT offset in BAR0 starts from 8MB to 16MB, and
> > > +		 * Whatever GTT size is configured in BIOS,
> > > +		 * the size of BAR0 is always 16MB. The actual configured
> > > +		 * GTT size can be found in GMCH_CTRL.
> > > +		 */
> > > +		info->gtt_start_offset = (1UL << 23);
> > > +		info->max_gtt_size = (1UL << 23);
> > > +		info->gtt_entry_size = 8;
> > > +		info->gtt_entry_size_shift = 3;
> > > +		info->gmadr_bytes_in_cmd = 8;
> > 
> > Would this information be useful in a header as #defines too?
> > 
> [Zhi] Probably. Consider that one GVT-g featured kernel could be able to 
> run on different platforms, the informaion data structure could be 
> different. But I agree to define the magic numbers in a header files. :)
> 
> > > +	}
> > > +
> > > +	gvt_info("Device info:");
> > > +	printk("        max_gtt_gm_sz: %llx\n", info->max_gtt_gm_sz);
> > > +	printk("        max_gtt_size: %x\n", info->max_gtt_size);
> > > +	printk("        gtt_size_entry: %x\n", info->gtt_entry_size);
> > > +	printk("        gtt_entry_size_shift: %x\n", info->gtt_entry_size_shift);
> > > +	printk("        gtt_start_offset: %x\n", info->gtt_start_offset);
> > > +	printk("        gtt_end_offset: %x\n", info->gtt_end_offset);
> > > +
> > 
> > Just put this to kind of stuff to i915_debugfs.c.
> > 
> [Zhi] Thanks.
> 
> > > +	return true;
> > > +}
> > > +
> > > +static void init_initial_cfg_space_state(struct pgt_device *pdev)
> > > +{
> > > +	struct pci_dev *pci_dev = pdev->dev_priv->dev->pdev;
> > > +	int i;
> > > +
> > > +	gvt_dbg_core("init initial cfg space, id %d", pdev->id);
> > > +
> > > +	for (i = 0; i < GVT_CFG_SPACE_SZ; i += 4)
> > 
> > += sizeof(...)
> > 
> > > +		pci_read_config_dword(pci_dev, i,
> > > +				(u32 *)&pdev->initial_cfg_space[i]);
> > > +
> > > +	for (i = 0; i < 3; i++) {
> > 
> > No magic numbers make a #define for 3 and give it a descriptive name.
> > 
> > > +		pdev->bar_size[i] = pci_resource_len(pci_dev, i * 2);
> > > +		gvt_info("bar %d size: %llx", i, pdev->bar_size[i]);
> > > +	}
> > > +}
> > > +
> > > +static void clean_initial_mmio_state(struct pgt_device *pdev)
> > > +{
> > > +	if (pdev->gttmmio_va) {
> > > +		iounmap(pdev->gttmmio_va);
> > > +		pdev->gttmmio_va = NULL;
> > > +	}
> > > +
> > > +	if (pdev->gmadr_va) {
> > > +		iounmap(pdev->gmadr_va);
> > > +		pdev->gmadr_va = NULL;
> > > +	}
> > > +}
> > > +
> > > +static bool init_initial_mmio_state(struct pgt_device *pdev)
> > > +{
> > > +	u64 bar0, bar1;
> > > +
> > > +	gvt_dbg_core("init initial mmio state, id %d", pdev->id);
> > > +
> > > +	bar0 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR0];
> > > +	bar1 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR1];
> > > +
> > > +	pdev->gttmmio_base = bar0 & ~0xf;
> > > +	pdev->mmio_size = 2 * 1024 * 1024;
> > > +	pdev->reg_num = pdev->mmio_size / 4;
> > > +	pdev->gmadr_base = bar1 & ~0xf;
> > > +
> > 
> > Many magic numbers.
> > 
> > > +	pdev->gttmmio_va = ioremap(pdev->gttmmio_base, pdev->bar_size[0]);
> > > +	if (!pdev->gttmmio_va) {
> > > +		gvt_err("fail to map GTTMMIO BAR.");
> > 
> > These should be if(WARN_ON(...))
> > 
> > > +		return false;
> > > +	}
> > > +
> > > +	pdev->gmadr_va = ioremap(pdev->gmadr_base, pdev->bar_size[2]);
> > > +	if (!pdev->gmadr_va) {
> > > +		gvt_err("fail to map GMADR BAR.");
> > > +		goto err;
> > > +	}
> > > +
> > > +	gvt_info("bar0: 0x%llx, bar1: 0x%llx", bar0, bar1);
> > > +	gvt_info("mmio size: %x", pdev->mmio_size);
> > > +	gvt_info("gttmmio: 0x%llx, gmadr: 0x%llx", pdev->gttmmio_base, pdev->gmadr_base);
> > > +	gvt_info("gttmmio_va: %p", pdev->gttmmio_va);
> > > +	gvt_info("gmadr_va: %p", pdev->gmadr_va);
> > > +
> > > +	return true;
> > > +err:
> > > +	clean_initial_mmio_state(pdev);
> > > +	return false;
> > > +}
> > > +
> > > +static int gvt_service_thread(void *data)
> > > +{
> > > +	struct pgt_device *pdev = (struct pgt_device *)data;
> > > +	int r;
> > > +
> > > +	gvt_dbg_core("service thread start, pgt %d", pdev->id);
> > > +
> > > +	while(!kthread_should_stop()) {
> > > +		r = wait_event_interruptible(pdev->service_thread_wq,
> > > +				kthread_should_stop() || pdev->service_request);
> > > +
> > > +		if (kthread_should_stop())
> > > +			break;
> > > +
> > > +		if (r) {
> > > +			gvt_warn("service thread is waken up by unexpected signal.");
> > 
> > Should be WARN_ONCE, to avoid future disasters with CI.
> > 
> [Zhi] Thanks.
> > > +			continue;
> > > +		}
> > > +	}
> > > +	return 0;
> > > +}
> > > +
> > > +static void clean_service_thread(struct pgt_device *pdev)
> > > +{
> > > +	if (pdev->service_thread) {
> > > +		kthread_stop(pdev->service_thread);
> > > +		pdev->service_thread = NULL;
> > > +	}
> > > +}
> > > +
> > > +static bool init_service_thread(struct pgt_device *pdev)
> > > +{
> > > +	init_waitqueue_head(&pdev->service_thread_wq);
> > > +
> > > +	pdev->service_thread = kthread_run(gvt_service_thread,
> > > +			pdev, "gvt_service_thread%d", pdev->id);
> > > +
> > > +	if (!pdev->service_thread) {
> > > +		gvt_err("fail to start service thread.");
> > > +		return false;
> > > +	}
> > > +
> > > +	return true;
> > > +}
> > > +
> > > +static void clean_pgt_device(struct pgt_device *pdev)
> > > +{
> > > +	clean_service_thread(pdev);
> > > +	clean_initial_mmio_state(pdev);
> > > +}
> > > +
> > > +static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *dev_priv)
> > > +{
> > > +	if (!init_device_info(pdev))
> > > +		return false;
> > > +
> > > +	init_initial_cfg_space_state(pdev);
> > > +
> > > +	if (!init_initial_mmio_state(pdev))
> > > +		goto err;
> > > +
> > > +	if (!init_service_thread(pdev))
> > > +		goto err;
> > > +
> > > +	return true;
> > > +err:
> > > +	clean_pgt_device(pdev);
> > > +	return false;
> > > +}
> > > +
> > > +static bool post_init_pgt_device(struct pgt_device *pdev)
> > > +{
> > > +	return true;
> > > +}
> > > +
> > > +static void free_pgt_device(struct pgt_device *pdev)
> > > +{
> > > +	struct gvt_host *host = &gvt_host;
> > > +
> > > +	mutex_lock(&host->device_idr_lock);
> > > +	idr_remove(&host->device_idr, pdev->id);
> > > +	mutex_unlock(&host->device_idr_lock);
> > > +
> > > +	vfree(pdev);
> > > +}
> > > +
> > > +static struct pgt_device *alloc_pgt_device(struct drm_i915_private *dev_priv)
> > > +{
> > > +	struct gvt_host *host = &gvt_host;
> > > +	struct pgt_device *pdev = NULL;
> > > +
> > > +	pdev = vzalloc(sizeof(*pdev));
> > > +	if (!pdev) {
> > > +		gvt_err("fail to allocate memory for pgt device.");
> > > +		return NULL;
> > > +	}
> > > +
> > > +	mutex_lock(&host->device_idr_lock);
> > > +	pdev->id = idr_alloc(&host->device_idr, pdev, 0, 0, GFP_KERNEL);
> > > +	mutex_unlock(&host->device_idr_lock);
> > > +
> > > +	if (pdev->id < 0) {
> > > +		gvt_err("fail to allocate pgt device id.");
> > > +		goto err;
> > > +	}
> > > +
> > > +	mutex_init(&pdev->lock);
> > > +	pdev->dev_priv = dev_priv;
> > > +	idr_init(&pdev->instance_idr);
> > > +
> > > +	return pdev;
> > > +err:
> > > +	free_pgt_device(pdev);
> > > +	return NULL;
> > > +}
> > > +
> > > +void gvt_destroy_pgt_device(void *private_data)
> > > +{
> > > +	struct pgt_device *pdev = (struct pgt_device *)private_data;
> > > +
> > > +	clean_pgt_device(pdev);
> > > +	free_pgt_device(pdev);
> > > +}
> > > +
> > > +void *gvt_create_pgt_device(struct drm_i915_private *dev_priv)
> > > +{
> > > +	struct pgt_device *pdev = NULL;
> > > +	struct gvt_host *host = &gvt_host;
> > > +
> > > +	if (!host->initialized && !gvt_init_host()) {
> > > +		gvt_err("gvt_init_host fail");
> > > +		return NULL;
> > > +	}
> > > +
> > > +	gvt_dbg_core("create new pgt device, i915 dev_priv: %p", dev_priv);
> > > +
> > > +	pdev = alloc_pgt_device(dev_priv);
> > > +	if (!pdev) {
> > > +		gvt_err("fail to allocate memory for pgt device.");
> > > +		goto err;
> > > +	}
> > > +
> > > +	gvt_dbg_core("init pgt device, id %d", pdev->id);
> > > +
> > > +	if (!init_pgt_device(pdev, dev_priv)) {
> > > +		gvt_err("fail to init physical device state.");
> > > +		goto err;
> > > +	}
> > > +
> > > +	gvt_dbg_core("pgt device creation done, id %d", pdev->id);
> > > +
> > > +	return pdev;
> > > +err:
> > > +	if (pdev) {
> > > +		gvt_destroy_pgt_device(pdev);
> > > +		pdev = NULL;
> > > +	}
> > > +	return NULL;
> > > +}
> > > +
> > > +bool gvt_post_init_pgt_device(void *private_data)
> > > +{
> > > +	struct pgt_device *pdev = (struct pgt_device *)private_data;
> > > +	struct gvt_host *host = &gvt_host;
> > > +
> > > +	if (!host->initialized) {
> > > +		gvt_err("gvt_host haven't been initialized.");
> > > +		return false;
> > > +	}
> > > +
> > > +	gvt_dbg_core("post init pgt device %d", pdev->id);
> > > +
> > > +	if (!post_init_pgt_device(pdev)) {
> > > +		gvt_err("fail to post init physical device state.");
> > > +		return false;
> > > +	}
> > > +
> > > +	return true;
> > > +}
> > > diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
> > > new file mode 100644
> > > index 0000000..6c85bba
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/i915/gvt/gvt.h
> > > @@ -0,0 +1,130 @@
> > > +/*
> > > + * Copyright(c) 2011-2016 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.
> > > + */
> > > +
> > > +#ifndef _GVT_H_
> > > +#define _GVT_H_
> > > +
> > > +#include "i915_drv.h"
> > > +#include "i915_vgpu.h"
> > > +
> > > +#include "debug.h"
> > > +#include "params.h"
> > > +#include "reg.h"
> > > +#include "hypercall.h"
> > > +#include "mpt.h"
> > > +#include "fb_decoder.h"
> > > +
> > > +#define GVT_MAX_VGPU 8
> > > +
> > > +enum {
> > > +	GVT_HYPERVISOR_TYPE_XEN = 0,
> > > +	GVT_HYPERVISOR_TYPE_KVM,
> > > +};
> > > +
> > > +struct gvt_host {
> > > +	bool initialized;
> > > +	int hypervisor_type;
> > > +	struct mutex device_idr_lock;
> > > +	struct idr device_idr;
> > > +	struct gvt_kernel_dm *kdm;
> > > +};
> > > +
> > > +extern struct gvt_host gvt_host;
> > > +
> > > +/* Describe the limitation of HW.*/
> > > +struct gvt_device_info {
> > > +	u64 max_gtt_gm_sz;
> > > +	u32 gtt_start_offset;
> > > +	u32 gtt_end_offset;
> > > +	u32 max_gtt_size;
> > > +	u32 gtt_entry_size;
> > > +	u32 gtt_entry_size_shift;
> > > +	u32 gmadr_bytes_in_cmd;
> > > +};
> > > +
> > > +struct vgt_device {
> > > +	int id;
> > > +	int vm_id;
> > > +	struct pgt_device *pdev;
> > > +	bool warn_untrack;
> > > +};
> > > +
> > > +struct pgt_device {
> > > +	struct mutex lock;
> > > +	int id;
> > > +
> > > +	struct drm_i915_private *dev_priv;
> > > +	struct idr instance_idr;
> > > +
> > > +	struct gvt_device_info device_info;
> > > +
> > > +	u8 initial_cfg_space[GVT_CFG_SPACE_SZ];
> > > +	u64 bar_size[GVT_BAR_NUM];
> > > +
> > > +	u64 gttmmio_base;
> > > +	void *gttmmio_va;
> > > +
> > > +	u64 gmadr_base;
> > > +	void *gmadr_va;
> > > +
> > > +	u32 mmio_size;
> > > +	u32 reg_num;
> > > +
> > > +	wait_queue_head_t service_thread_wq;
> > > +	struct task_struct *service_thread;
> > > +	unsigned long service_request;
> > > +};
> > > +
> > 
> > Here-->
> > 
> > > +static inline u32 gvt_mmio_read(struct pgt_device *pdev,
> > > +		u32 reg)
> > > +{
> > > +	struct drm_i915_private *dev_priv = pdev->dev_priv;
> > > +	i915_reg_t tmp = {.reg = reg};
> > > +	return I915_READ(tmp);
> > > +}
> > > +
> > > +static inline void gvt_mmio_write(struct pgt_device *pdev,
> > > +		u32 reg, u32 val)
> > > +{
> > > +	struct drm_i915_private *dev_priv = pdev->dev_priv;
> > > +	i915_reg_t tmp = {.reg = reg};
> > > +	I915_WRITE(tmp, val);
> > > +}
> > > +
> > > +static inline u64 gvt_mmio_read64(struct pgt_device *pdev,
> > > +		u32 reg)
> > > +{
> > > +	struct drm_i915_private *dev_priv = pdev->dev_priv;
> > > +	i915_reg_t tmp = {.reg = reg};
> > > +	return I915_READ64(tmp);
> > > +}
> > > +
> > > +static inline void gvt_mmio_write64(struct pgt_device *pdev,
> > > +		u32 reg, u64 val)
> > > +{
> > > +	struct drm_i915_private *dev_priv = pdev->dev_priv;
> > > +	i915_reg_t tmp = {.reg = reg};
> > > +	I915_WRITE64(tmp, val);
> > > +}
> > > +
> > 
> > <-- Why? The i915_reg_t type was added to avoid problems, this code is
> > not used anywhere, and it has no documentation, so I can not review it.
> > 
> > I wrote comments at the top of the post.
> > 
> [Zhi] Thanks, I will check that.
> 
> > Regards, Joonas
> > 
> > > +#endif
> > > diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h b/drivers/gpu/drm/i915/gvt/hypercall.h
> > > new file mode 100644
> > > index 0000000..0a41874
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/i915/gvt/hypercall.h
> > > @@ -0,0 +1,30 @@
> > > +/*
> > > + * Copyright(c) 2011-2016 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.
> > > + */
> > > +
> > > +#ifndef _GVT_HYPERCALL_H_
> > > +#define _GVT_HYPERCALL_H_
> > > +
> > > +struct gvt_kernel_dm {
> > > +};
> > > +
> > > +#endif /* _GVT_HYPERCALL_H_ */
> > > diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h
> > > new file mode 100644
> > > index 0000000..bbe4465
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/i915/gvt/mpt.h
> > > @@ -0,0 +1,97 @@
> > > +/*
> > > + * Copyright(c) 2011-2016 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.
> > > + */
> > > +
> > > +#ifndef _GVT_MPT_H_
> > > +#define _GVT_MPT_H_
> > > +
> > > +struct vgt_device;
> > > +
> > > +static inline unsigned long hypervisor_g2m_pfn(struct vgt_device *vgt,
> > > +	unsigned long g_pfn)
> > > +{
> > > +	return 0;
> > > +}
> > > +
> > > +static inline int hypervisor_pause_domain(struct vgt_device *vgt)
> > > +{
> > > +	return 0;
> > > +}
> > > +
> > > +static inline int hypervisor_shutdown_domain(struct vgt_device *vgt)
> > > +{
> > > +	return 0;
> > > +}
> > > +
> > > +static inline int hypervisor_set_trap_area(struct vgt_device *vgt,
> > > +	uint64_t start, uint64_t end, bool map)
> > > +{
> > > +	return 0;
> > > +}
> > > +
> > > +static inline bool hypervisor_detect_host(void)
> > > +{
> > > +	return false;
> > > +}
> > > +
> > > +static inline int hypervisor_virt_to_mfn(void *addr)
> > > +{
> > > +	return 0;
> > > +}
> > > +
> > > +static inline void *hypervisor_mfn_to_virt(int mfn)
> > > +{
> > > +	return NULL;
> > > +}
> > > +
> > > +static inline void hypervisor_inject_msi(struct vgt_device *vgt)
> > > +{
> > > +	return;
> > > +}
> > > +
> > > +static inline int hypervisor_hvm_init(struct vgt_device *vgt)
> > > +{
> > > +	return 0;
> > > +}
> > > +
> > > +static inline void hypervisor_hvm_exit(struct vgt_device *vgt)
> > > +{
> > > +}
> > > +
> > > +static inline void *hypervisor_gpa_to_va(struct vgt_device *vgt, unsigned long gpa)
> > > +{
> > > +	return NULL;
> > > +}
> > > +
> > > +static inline bool hypervisor_read_va(struct vgt_device *vgt, void *va,
> > > +		void *val, int len, int atomic)
> > > +{
> > > +	return false;
> > > +}
> > > +
> > > +static inline bool hypervisor_write_va(struct vgt_device *vgt, void *va,
> > > +		void *val, int len, int atomic)
> > > +{
> > > +	return false;
> > > +}
> > > +
> > > +#endif /* _GVT_MPT_H_ */
> > > diff --git a/drivers/gpu/drm/i915/gvt/params.c b/drivers/gpu/drm/i915/gvt/params.c
> > > new file mode 100644
> > > index 0000000..dfc33c3
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/i915/gvt/params.c
> > > @@ -0,0 +1,29 @@
> > > +/*
> > > + * Copyright(c) 2011-2016 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 "gvt.h"
> > > +
> > > +struct gvt_kernel_params gvt = {
> > > +	.enable = true,
> > > +	.debug = 0,
> > > +};
> > > diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
> > > new file mode 100644
> > > index 0000000..d2955b9
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/i915/gvt/params.h
> > > @@ -0,0 +1,34 @@
> > > +/*
> > > + * Copyright(c) 2011-2016 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.
> > > + */
> > > +
> > > +#ifndef _GVT_PARAMS_H_
> > > +#define _GVT_PARAMS_H_
> > > +
> > > +struct gvt_kernel_params {
> > > +	bool enable;
> > > +	int debug;
> > > +};
> > > +
> > > +extern struct gvt_kernel_params gvt;
> > > +
> > > +#endif
> > > diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h
> > > new file mode 100644
> > > index 0000000..d363b74
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/i915/gvt/reg.h
> > > @@ -0,0 +1,34 @@
> > > +/*
> > > + * Copyright(c) 2011-2016 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.
> > > + */
> > > +
> > > +#ifndef _GVT_REG_H
> > > +#define _GVT_REG_H
> > > +
> > > +#define GVT_CFG_SPACE_SZ	256
> > > +#define GVT_BAR_NUM		4
> > > +
> > > +#define GVT_REG_CFG_SPACE_BAR0	0x10
> > > +#define GVT_REG_CFG_SPACE_BAR1	0x18
> > > +#define GVT_REG_CFG_SPACE_BAR2	0x20
> > > +
> > > +#endif
> > > diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> > > index 4725e8d..eca8e50 100644
> > > --- a/drivers/gpu/drm/i915/i915_dma.c
> > > +++ b/drivers/gpu/drm/i915/i915_dma.c
> > > @@ -943,6 +943,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
> > > 
> > >   	intel_uncore_init(dev);
> > > 
> > > +	dev_priv->vgpu.host_private_data = gvt_create_pgt_device(dev_priv);
> > > +	if(intel_gvt_host_active(dev))
> > > +		DRM_INFO("GVT-g is running in host mode\n");
> > > +
> > >   	ret = i915_gem_gtt_init(dev);
> > >   	if (ret)
> > >   		goto out_freecsr;
> > > @@ -1067,6 +1071,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
> > >   		goto out_power_well;
> > >   	}
> > > 
> > > +	if (intel_gvt_host_active(dev)) {
> > > +		if (!gvt_post_init_pgt_device(dev_priv->vgpu.host_private_data)) {
> > > +			DRM_ERROR("failed to post init pgt device\n");
> > > +			goto out_power_well;
> > > +		}
> > > +	}
> > > +
> > >   	/*
> > >   	 * Notify a valid surface after modesetting,
> > >   	 * when running inside a VM.
> > > @@ -1117,6 +1128,10 @@ out_gtt:
> > >   	i915_global_gtt_cleanup(dev);
> > >   out_freecsr:
> > >   	intel_csr_ucode_fini(dev_priv);
> > > +	if (intel_gvt_host_active(dev)) {
> > > +		gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
> > > +		dev_priv->vgpu.host_private_data = NULL;
> > > +	}
> > >   	intel_uncore_fini(dev);
> > >   	pci_iounmap(dev->pdev, dev_priv->regs);
> > >   put_bridge:
> > > @@ -1165,6 +1180,10 @@ int i915_driver_unload(struct drm_device *dev)
> > > 
> > >   	intel_modeset_cleanup(dev);
> > > 
> > > +	if (intel_gvt_host_active(dev)) {
> > > +		gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
> > > +		dev_priv->vgpu.host_private_data = NULL;
> > > +	}
> > >   	/*
> > >   	 * free the memory space allocated for the child device
> > >   	 * config parsed from VBT
> > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > > index 01cc982..db3c79b 100644
> > > --- a/drivers/gpu/drm/i915/i915_drv.h
> > > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > > @@ -1673,6 +1673,7 @@ struct i915_workarounds {
> > > 
> > >   struct i915_virtual_gpu {
> > >   	bool active;
> > > +	void *host_private_data;
> > >   };
> > > 
> > >   struct i915_execbuffer_params {
> > > @@ -2747,6 +2748,11 @@ static inline bool intel_vgpu_active(struct drm_device *dev)
> > >   	return to_i915(dev)->vgpu.active;
> > >   }
> > > 
> > > +static inline bool intel_gvt_host_active(struct drm_device *dev)
> > > +{
> > > +	return to_i915(dev)->vgpu.host_private_data ? true : false;
> > > +}
> > > +
> > >   void
> > >   i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
> > >   		     u32 status_mask);
> > > diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
> > > index 3c83b47..942490a 100644
> > > --- a/drivers/gpu/drm/i915/i915_vgpu.h
> > > +++ b/drivers/gpu/drm/i915/i915_vgpu.h
> > > @@ -113,5 +113,8 @@ struct vgt_if {
> > >   extern void i915_check_vgpu(struct drm_device *dev);
> > >   extern int intel_vgt_balloon(struct drm_device *dev);
> > >   extern void intel_vgt_deballoon(void);
> > > +extern void *gvt_create_pgt_device(struct drm_i915_private *dev_priv);
> > > +extern bool gvt_post_init_pgt_device(void *private_data);
> > > +extern void gvt_destroy_pgt_device(void *private_data);
> > > 
> > >   #endif /* _I915_VGPU_H_ */
> > > diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
> > > index d133112..78a38f1 100644
> > > --- a/include/xen/interface/xen.h
> > > +++ b/include/xen/interface/xen.h
> > > @@ -28,6 +28,7 @@
> > >   #define __XEN_PUBLIC_XEN_H__
> > > 
> > >   #include
> > > +#include
> > > 
> > >   /*
> > >    * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt
  2016-01-28 10:21 ` [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt Zhi Wang
@ 2016-02-04 11:27   ` Joonas Lahtinen
  2016-02-05 10:03     ` Zhiyuan Lv
  2016-02-10  8:08   ` Daniel Vetter
  1 sibling, 1 reply; 49+ messages in thread
From: Joonas Lahtinen @ 2016-02-04 11:27 UTC (permalink / raw)
  To: Zhi Wang, intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

Hi,

On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
> From: Bing Niu <bing.niu@intel.com>
> 
> This patch introduces host graphics memory ballon when GVT-g is enabled.
> 
> As under GVT-g, i915 only owned limited graphics resources, others are
> managed by GVT-g resource allocator and kept for other vGPUs.
> 
> For graphics memory space partition, a typical layout looks like:
> 
> +-------+-----------------------+------+-----------------------+
> > * Host |   *GVT-g Resource     |* Host|   *GVT-g Resource     |
> > Owned |   Allocator Managed   | Owned|   Allocator Managed   |
> >       |                       |      |                       |
> +---------------+-------+----------------------+-------+-------+
> >       |       |       |       |      |       |       |       |
> > i915  | vm 1  | vm 2  | vm 3  | i915 | vm 1  | vm 2  | vm 3  |
> >       |       |       |       |      |       |       |       |
> +-------+-------+-------+--------------+-------+-------+-------+
> >           Aperture            |            Hidden            |
> +-------------------------------+------------------------------+
> >                       GGTT memory space                      |
> +--------------------------------------------------------------+
> 
> Similar with fence registers partition:
> 
>  +------ +-----------------------+
>  | * Host|    GVT-g Resource     |
>  | Owned |   Allocator Managed   +
>  0       |                       31
>  +---------------+-------+-------+
>  |       |       |       |       |
>  | i915  | vm 1  | vm 2  | vm 3  |
>  |       |       |       |       |
>  +-------+-------+-------+-------+
> 
> i915 host will read the amount of allocated resources via GVT-g kernel parameters.
> 
> Signed-off-by: Bing Niu <bing.niu@intel.com>
> Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
> ---
>  drivers/gpu/drm/i915/gvt/params.h   |  3 +++
>  drivers/gpu/drm/i915/i915_gem.c     |  3 +++
>  drivers/gpu/drm/i915/i915_gem_gtt.c |  4 ++--
>  drivers/gpu/drm/i915/i915_vgpu.c    | 16 ++++++++++++----
>  drivers/gpu/drm/i915/i915_vgpu.h    |  1 +
>  5 files changed, 21 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
> index d2955b9..0656a98 100644
> --- a/drivers/gpu/drm/i915/gvt/params.h
> +++ b/drivers/gpu/drm/i915/gvt/params.h
> @@ -27,6 +27,9 @@
>  struct gvt_kernel_params {
>  	bool enable;
>  	int debug;
> +	int dom0_low_gm_sz;
> +	int dom0_high_gm_sz;
> +	int dom0_fence_sz;
>  };
>  
>  extern struct gvt_kernel_params gvt;
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 799a53a..e916e43 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -5080,6 +5080,9 @@ i915_gem_load(struct drm_device *dev)
>  	else
>  		dev_priv->num_fence_regs = 8;
>  
> +	if(intel_gvt_host_active(dev))

Space between "if" and "("

> +		dev_priv->num_fence_regs = gvt.dom0_fence_sz;
> +
>  	if (intel_vgpu_active(dev))
>  		dev_priv->num_fence_regs =
>  				I915_READ(vgtif_reg(avail_rs.fence_num));

I'd like to see the above as "else if" construct just like you have
below with the intel_vgt_balloon(). Could even do

	if (gvt_host)  {
		...
	} else if (vgpu_active) {
		...
	} else {
		per machine detection
	}

Right?

> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> index 7377b67..0540de2 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> @@ -2713,7 +2713,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
>  	i915_address_space_init(ggtt_vm, dev_priv);
>  	ggtt_vm->total += PAGE_SIZE;
>  
> -	if (intel_vgpu_active(dev)) {
> +	if (intel_vgpu_active(dev) || intel_gvt_host_active(dev)) {
>  		ret = intel_vgt_balloon(dev);
>  		if (ret)
>  			return ret;
> @@ -2810,7 +2810,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev)
>  	}
>  
>  	if (drm_mm_initialized(&vm->mm)) {
> -		if (intel_vgpu_active(dev))
> +		if (intel_vgpu_active(dev) || intel_gvt_host_active(dev))
>  			intel_vgt_deballoon();
>  
>  		drm_mm_takedown(&vm->mm);
> diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
> index dea7429..fbe6114 100644
> --- a/drivers/gpu/drm/i915/i915_vgpu.c
> +++ b/drivers/gpu/drm/i915/i915_vgpu.c
> @@ -188,10 +188,18 @@ int intel_vgt_balloon(struct drm_device *dev)
>  	unsigned long unmappable_base, unmappable_size, unmappable_end;
>  	int ret;
>  
> -	mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> -	mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> -	unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> -	unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> +	if(intel_gvt_host_active(dev)) {
> +		mappable_base = 0;
> +		mappable_size = gvt.dom0_low_gm_sz << 20;
> +		unmappable_base = dev_priv->gtt.mappable_end;
> +		unmappable_size = gvt.dom0_high_gm_sz << 20;
> +	} else if (intel_vgpu_active(dev)) {
> +		mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> +		mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> +		unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> +		unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> +	} else
> +		return -ENODEV;
>  
	} else {
		return -ENODEV;
	}

This must use braces too, according to the Kernel Coding Style.

>  	mappable_end = mappable_base + mappable_size;
>  	unmappable_end = unmappable_base + unmappable_size;
> diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
> index 942490a..b8a49e6 100644
> --- a/drivers/gpu/drm/i915/i915_vgpu.h
> +++ b/drivers/gpu/drm/i915/i915_vgpu.h
> @@ -24,6 +24,7 @@
>  #ifndef _I915_VGPU_H_
>  #define _I915_VGPU_H_
>  
> +#include "gvt/params.h"

This is not a good way of including headers, as this header itself
doesn't need it. Including unnecessary stuff in often included headers
contributes to increasing project compile times and makes it harder to
solve cross dependencies later. So put it into the implementation file
that needs it.

Regards, Joonas

>  /* The MMIO offset of the shared info between guest and host emulator */
>  #define VGT_PVINFO_PAGE	0x78000
>  #define VGT_PVINFO_SIZE	0x1000
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g
  2016-01-29 16:48     ` Chris Wilson
  2016-02-03  6:28       ` Zhi Wang
@ 2016-02-05  7:02       ` Zhiyuan Lv
  1 sibling, 0 replies; 49+ messages in thread
From: Zhiyuan Lv @ 2016-02-05  7:02 UTC (permalink / raw)
  To: Chris Wilson, Joonas Lahtinen, Zhi Wang, intel-gfx, igvt-g,
	kevin.tian, bing.niu, jike.song, daniel.vetter,
	david.j.cowperthwaite, Li, Susie

Hi Chris,

On Fri, Jan 29, 2016 at 04:48:07PM +0000, Chris Wilson wrote:
> On Fri, Jan 29, 2016 at 03:57:09PM +0200, Joonas Lahtinen wrote:
> > Hi,
> > 
> > TL;DR Overall, we have same problem as with the scheduler series, there
> > is too much placeholder stuff for easy review. Just squash enough code
> > into one commit so it actually does something logical that can be
> > reviewed and then extend it later. Then it can be reviewed and pushed.
> > Just splitting the code down to achieve smaller patches is not the
> > right thing to do.
> > 
> > Comments on the overall code: You need to document all header file
> > functions (in the source files), and it is good to document the static
> > functions within a file too, to make future maintenance easier.
> > 
> > It is not about splitting the code down to small chunks, but splitting
> > it down to small *logical* chunks. It doesn't make sense to commit
> > dozens of empty bodied functions for review, and then later add their
> > code.
> > 
> > If you add functions, only add them at a patch that takes them into use
> > too, unless we're talking about general purpose shared code. And also
> > remember to add the function body and documentation header. If you
> > simply add a "return 0;" or similar function body, do add a comment to
> > why the function does not exist and when it will.
> > 
> > Then, there is a trend of having a boolean return values in the code.
> > When possible, it should rather be int and the cause for failure should
> > be propagated from the last level all the way to up (-ENOMEN etc.).
> > This way debugging becomes easier and if new error conditions appear,
> > there is less of a maintenance burden to add the propagation later.
> > 
> > Finally, make sure to look at the existing driver parts and
> > 	https://www.kernel.org/doc/Documentation/CodingStyle
> > for proper coding style. There are lots of whitespace fixes needed in
> > this series, like array initializations.
> > 
> > I hope to see this first patch rerolled so that you squash some of the
> > later commits into it so that all functions have a body and you add
> > documentation for the functions so I can both see what it should do and
> > what it actually does. Only reroll the first patch, to keep the
> > iterative step smaller. Lets only then continue with the rest of the
> > series once we've reached a consensus on the formatting and style
> > basics.
> > 
> > See more comments below.
> 
> I'm glad you did the nitpicking. As far as the integration goes, on the
> whole I'm happy with the way it is structured and the reuse of existing
> code. I tried to attack various aspects of the GVT contexts and came to
> the conclusion I couldn't suggest a better approach (though maybe
> tomorrow!). A few bits and pieces I got lost trying to pull together
> (in particular like how we do is read back through the GTT entries
> performed, the hypervisor_read_va abstraction iirc) and would appreciate
> having a branch available to get the complete picture.

I pushed the RFC code into below repo:

https://github.com/01org/Igvtg-kernel.git

Branch: gvt-upstream-rfc

Thanks for review and look forward to more comments!

Regards,
-Zhiyuan

> -Chris
> -- 
> Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt
  2016-02-04 11:27   ` Joonas Lahtinen
@ 2016-02-05 10:03     ` Zhiyuan Lv
  2016-02-05 13:40       ` Joonas Lahtinen
  0 siblings, 1 reply; 49+ messages in thread
From: Zhiyuan Lv @ 2016-02-05 10:03 UTC (permalink / raw)
  To: Joonas Lahtinen; +Cc: daniel.vetter, intel-gfx, david.j.cowperthwaite, igvt-g

Hi Joonas,

Thanks much for the review! We will incorporate those review comments!

Meanwhile, is it good enough to do the host ballooning like below? The
pros is that it is very simple, especially consider that guest
ballooning logic has been there. Thanks!

Regards,
-Zhiyuan

On Thu, Feb 04, 2016 at 01:27:08PM +0200, Joonas Lahtinen wrote:
> Hi,
> 
> On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
> > From: Bing Niu <bing.niu@intel.com>
> > 
> > This patch introduces host graphics memory ballon when GVT-g is enabled.
> > 
> > As under GVT-g, i915 only owned limited graphics resources, others are
> > managed by GVT-g resource allocator and kept for other vGPUs.
> > 
> > For graphics memory space partition, a typical layout looks like:
> > 
> > +-------+-----------------------+------+-----------------------+
> > > * Host |   *GVT-g Resource     |* Host|   *GVT-g Resource     |
> > > Owned |   Allocator Managed   | Owned|   Allocator Managed   |
> > >       |                       |      |                       |
> > +---------------+-------+----------------------+-------+-------+
> > >       |       |       |       |      |       |       |       |
> > > i915  | vm 1  | vm 2  | vm 3  | i915 | vm 1  | vm 2  | vm 3  |
> > >       |       |       |       |      |       |       |       |
> > +-------+-------+-------+--------------+-------+-------+-------+
> > >           Aperture            |            Hidden            |
> > +-------------------------------+------------------------------+
> > >                       GGTT memory space                      |
> > +--------------------------------------------------------------+
> > 
> > Similar with fence registers partition:
> > 
> >  +------ +-----------------------+
> >  | * Host|    GVT-g Resource     |
> >  | Owned |   Allocator Managed   +
> >  0       |                       31
> >  +---------------+-------+-------+
> >  |       |       |       |       |
> >  | i915  | vm 1  | vm 2  | vm 3  |
> >  |       |       |       |       |
> >  +-------+-------+-------+-------+
> > 
> > i915 host will read the amount of allocated resources via GVT-g kernel parameters.
> > 
> > Signed-off-by: Bing Niu <bing.niu@intel.com>
> > Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
> > ---
> >  drivers/gpu/drm/i915/gvt/params.h   |  3 +++
> >  drivers/gpu/drm/i915/i915_gem.c     |  3 +++
> >  drivers/gpu/drm/i915/i915_gem_gtt.c |  4 ++--
> >  drivers/gpu/drm/i915/i915_vgpu.c    | 16 ++++++++++++----
> >  drivers/gpu/drm/i915/i915_vgpu.h    |  1 +
> >  5 files changed, 21 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
> > index d2955b9..0656a98 100644
> > --- a/drivers/gpu/drm/i915/gvt/params.h
> > +++ b/drivers/gpu/drm/i915/gvt/params.h
> > @@ -27,6 +27,9 @@
> >  struct gvt_kernel_params {
> >  	bool enable;
> >  	int debug;
> > +	int dom0_low_gm_sz;
> > +	int dom0_high_gm_sz;
> > +	int dom0_fence_sz;
> >  };
> >  
> >  extern struct gvt_kernel_params gvt;
> > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> > index 799a53a..e916e43 100644
> > --- a/drivers/gpu/drm/i915/i915_gem.c
> > +++ b/drivers/gpu/drm/i915/i915_gem.c
> > @@ -5080,6 +5080,9 @@ i915_gem_load(struct drm_device *dev)
> >  	else
> >  		dev_priv->num_fence_regs = 8;
> >  
> > +	if(intel_gvt_host_active(dev))
> 
> Space between "if" and "("

Thanks! Will correct it.

> 
> > +		dev_priv->num_fence_regs = gvt.dom0_fence_sz;
> > +
> >  	if (intel_vgpu_active(dev))
> >  		dev_priv->num_fence_regs =
> >  				I915_READ(vgtif_reg(avail_rs.fence_num));
> 
> I'd like to see the above as "else if" construct just like you have
> below with the intel_vgt_balloon(). Could even do
> 
> 	if (gvt_host)  {
> 		...
> 	} else if (vgpu_active) {
> 		...
> 	} else {
> 		per machine detection
> 	}
> 
> Right?

That looks better!

> 
> > diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> > index 7377b67..0540de2 100644
> > --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> > +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> > @@ -2713,7 +2713,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
> >  	i915_address_space_init(ggtt_vm, dev_priv);
> >  	ggtt_vm->total += PAGE_SIZE;
> >  
> > -	if (intel_vgpu_active(dev)) {
> > +	if (intel_vgpu_active(dev) || intel_gvt_host_active(dev)) {
> >  		ret = intel_vgt_balloon(dev);
> >  		if (ret)
> >  			return ret;
> > @@ -2810,7 +2810,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev)
> >  	}
> >  
> >  	if (drm_mm_initialized(&vm->mm)) {
> > -		if (intel_vgpu_active(dev))
> > +		if (intel_vgpu_active(dev) || intel_gvt_host_active(dev))
> >  			intel_vgt_deballoon();
> >  
> >  		drm_mm_takedown(&vm->mm);
> > diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
> > index dea7429..fbe6114 100644
> > --- a/drivers/gpu/drm/i915/i915_vgpu.c
> > +++ b/drivers/gpu/drm/i915/i915_vgpu.c
> > @@ -188,10 +188,18 @@ int intel_vgt_balloon(struct drm_device *dev)
> >  	unsigned long unmappable_base, unmappable_size, unmappable_end;
> >  	int ret;
> >  
> > -	mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> > -	mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> > -	unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> > -	unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> > +	if(intel_gvt_host_active(dev)) {
> > +		mappable_base = 0;
> > +		mappable_size = gvt.dom0_low_gm_sz << 20;
> > +		unmappable_base = dev_priv->gtt.mappable_end;
> > +		unmappable_size = gvt.dom0_high_gm_sz << 20;
> > +	} else if (intel_vgpu_active(dev)) {
> > +		mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> > +		mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> > +		unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> > +		unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> > +	} else
> > +		return -ENODEV;
> >  
> 	} else {
> 		return -ENODEV;
> 	}
> 
> This must use braces too, according to the Kernel Coding Style.

That's right. Thanks for pointing it out!

> 
> >  	mappable_end = mappable_base + mappable_size;
> >  	unmappable_end = unmappable_base + unmappable_size;
> > diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
> > index 942490a..b8a49e6 100644
> > --- a/drivers/gpu/drm/i915/i915_vgpu.h
> > +++ b/drivers/gpu/drm/i915/i915_vgpu.h
> > @@ -24,6 +24,7 @@
> >  #ifndef _I915_VGPU_H_
> >  #define _I915_VGPU_H_
> >  
> > +#include "gvt/params.h"
> 
> This is not a good way of including headers, as this header itself
> doesn't need it. Including unnecessary stuff in often included headers
> contributes to increasing project compile times and makes it harder to
> solve cross dependencies later. So put it into the implementation file
> that needs it.
> 

Will delete. Thanks!

> Regards, Joonas
> 
> >  /* The MMIO offset of the shared info between guest and host emulator */
> >  #define VGT_PVINFO_PAGE	0x78000
> >  #define VGT_PVINFO_SIZE	0x1000
> -- 
> Joonas Lahtinen
> Open Source Technology Center
> Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt
  2016-02-05 10:03     ` Zhiyuan Lv
@ 2016-02-05 13:40       ` Joonas Lahtinen
  2016-02-05 14:16         ` Zhiyuan Lv
  0 siblings, 1 reply; 49+ messages in thread
From: Joonas Lahtinen @ 2016-02-05 13:40 UTC (permalink / raw)
  To: Zhiyuan Lv; +Cc: daniel.vetter, intel-gfx, david.j.cowperthwaite, igvt-g

Hi,

On pe, 2016-02-05 at 18:03 +0800, Zhiyuan Lv wrote:
> Hi Joonas,
> 
> Thanks much for the review! We will incorporate those review comments!
> 
> Meanwhile, is it good enough to do the host ballooning like below? The
> pros is that it is very simple, especially consider that guest
> ballooning logic has been there. Thanks!
> 

I think slicing it down like that is fine. Is there going to be real
ballooning happening, as in, is the available memory dynamically going
to change during runtime, or just be fixed size since the beginning?

Regards, Joonas

> Regards,
> -Zhiyuan
> 
> On Thu, Feb 04, 2016 at 01:27:08PM +0200, Joonas Lahtinen wrote:
> > Hi,
> > 
> > On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
> > > From: Bing Niu <bing.niu@intel.com>
> > > 
> > > This patch introduces host graphics memory ballon when GVT-g is enabled.
> > > 
> > > As under GVT-g, i915 only owned limited graphics resources, others are
> > > managed by GVT-g resource allocator and kept for other vGPUs.
> > > 
> > > For graphics memory space partition, a typical layout looks like:
> > > 
> > > +-------+-----------------------+------+-----------------------+
> > > > * Host |   *GVT-g Resource     |* Host|   *GVT-g Resource     |
> > > > Owned |   Allocator Managed   | Owned|   Allocator Managed   |
> > > >       |                       |      |                       |
> > > +---------------+-------+----------------------+-------+-------+
> > > >       |       |       |       |      |       |       |       |
> > > > i915  | vm 1  | vm 2  | vm 3  | i915 | vm 1  | vm 2  | vm 3  |
> > > >       |       |       |       |      |       |       |       |
> > > +-------+-------+-------+--------------+-------+-------+-------+
> > > >           Aperture            |            Hidden            |
> > > +-------------------------------+------------------------------+
> > > >                       GGTT memory space                      |
> > > +--------------------------------------------------------------+
> > > 
> > > Similar with fence registers partition:
> > > 
> > >  +------ +-----------------------+
> > >  | * Host|    GVT-g Resource     |
> > >  | Owned |   Allocator Managed   +
> > >  0       |                       31
> > >  +---------------+-------+-------+
> > >  |       |       |       |       |
> > >  | i915  | vm 1  | vm 2  | vm 3  |
> > >  |       |       |       |       |
> > >  +-------+-------+-------+-------+
> > > 
> > > i915 host will read the amount of allocated resources via GVT-g kernel parameters.
> > > 
> > > Signed-off-by: Bing Niu <bing.niu@intel.com>
> > > Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/gvt/params.h   |  3 +++
> > >  drivers/gpu/drm/i915/i915_gem.c     |  3 +++
> > >  drivers/gpu/drm/i915/i915_gem_gtt.c |  4 ++--
> > >  drivers/gpu/drm/i915/i915_vgpu.c    | 16 ++++++++++++----
> > >  drivers/gpu/drm/i915/i915_vgpu.h    |  1 +
> > >  5 files changed, 21 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
> > > index d2955b9..0656a98 100644
> > > --- a/drivers/gpu/drm/i915/gvt/params.h
> > > +++ b/drivers/gpu/drm/i915/gvt/params.h
> > > @@ -27,6 +27,9 @@
> > >  struct gvt_kernel_params {
> > >  	bool enable;
> > >  	int debug;
> > > +	int dom0_low_gm_sz;
> > > +	int dom0_high_gm_sz;
> > > +	int dom0_fence_sz;

Some comment on the unit would be nice here, as there is a shift with
<< 20 later on.

Is "unsigned long" type and count in pages not acceptable? I think
that's the assumption one is going to make.

> > >  };
> > >  
> > >  extern struct gvt_kernel_params gvt;
> > > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> > > index 799a53a..e916e43 100644
> > > --- a/drivers/gpu/drm/i915/i915_gem.c
> > > +++ b/drivers/gpu/drm/i915/i915_gem.c
> > > @@ -5080,6 +5080,9 @@ i915_gem_load(struct drm_device *dev)
> > >  	else
> > >  		dev_priv->num_fence_regs = 8;
> > >  
> > > +	if(intel_gvt_host_active(dev))
> > 
> > Space between "if" and "("
> 
> Thanks! Will correct it.
> 
> > 
> > > +		dev_priv->num_fence_regs = gvt.dom0_fence_sz;
> > > +
> > >  	if (intel_vgpu_active(dev))
> > >  		dev_priv->num_fence_regs =
> > >  				I915_READ(vgtif_reg(avail_rs.fence_num));
> > 
> > I'd like to see the above as "else if" construct just like you have
> > below with the intel_vgt_balloon(). Could even do
> > 
> > 	if (gvt_host)  {
> > 		...
> > 	} else if (vgpu_active) {
> > 		...
> > 	} else {
> > 		per machine detection
> > 	}
> > 
> > Right?
> 
> That looks better!
> 
> > 
> > > diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> > > index 7377b67..0540de2 100644
> > > --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> > > +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> > > @@ -2713,7 +2713,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
> > >  	i915_address_space_init(ggtt_vm, dev_priv);
> > >  	ggtt_vm->total += PAGE_SIZE;
> > >  
> > > -	if (intel_vgpu_active(dev)) {
> > > +	if (intel_vgpu_active(dev) || intel_gvt_host_active(dev)) {
> > >  		ret = intel_vgt_balloon(dev);
> > >  		if (ret)
> > >  			return ret;
> > > @@ -2810,7 +2810,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev)
> > >  	}
> > >  
> > >  	if (drm_mm_initialized(&vm->mm)) {
> > > -		if (intel_vgpu_active(dev))
> > > +		if (intel_vgpu_active(dev) || intel_gvt_host_active(dev))
> > >  			intel_vgt_deballoon();
> > >  
> > >  		drm_mm_takedown(&vm->mm);
> > > diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
> > > index dea7429..fbe6114 100644
> > > --- a/drivers/gpu/drm/i915/i915_vgpu.c
> > > +++ b/drivers/gpu/drm/i915/i915_vgpu.c
> > > @@ -188,10 +188,18 @@ int intel_vgt_balloon(struct drm_device *dev)
> > >  	unsigned long unmappable_base, unmappable_size, unmappable_end;
> > >  	int ret;
> > >  
> > > -	mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> > > -	mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> > > -	unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> > > -	unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> > > +	if(intel_gvt_host_active(dev)) {
> > > +		mappable_base = 0;
> > > +		mappable_size = gvt.dom0_low_gm_sz << 20;
> > > +		unmappable_base = dev_priv->gtt.mappable_end;
> > > +		unmappable_size = gvt.dom0_high_gm_sz << 20;
> > > +	} else if (intel_vgpu_active(dev)) {
> > > +		mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> > > +		mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> > > +		unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> > > +		unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> > > +	} else
> > > +		return -ENODEV;
> > >  
> > 	} else {
> > 		return -ENODEV;
> > 	}
> > 
> > This must use braces too, according to the Kernel Coding Style.
> 
> That's right. Thanks for pointing it out!
> 
> > 
> > >  	mappable_end = mappable_base + mappable_size;
> > >  	unmappable_end = unmappable_base + unmappable_size;
> > > diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
> > > index 942490a..b8a49e6 100644
> > > --- a/drivers/gpu/drm/i915/i915_vgpu.h
> > > +++ b/drivers/gpu/drm/i915/i915_vgpu.h
> > > @@ -24,6 +24,7 @@
> > >  #ifndef _I915_VGPU_H_
> > >  #define _I915_VGPU_H_
> > >  
> > > +#include "gvt/params.h"
> > 
> > This is not a good way of including headers, as this header itself
> > doesn't need it. Including unnecessary stuff in often included headers
> > contributes to increasing project compile times and makes it harder to
> > solve cross dependencies later. So put it into the implementation file
> > that needs it.
> > 
> 
> Will delete. Thanks!
> 
> > Regards, Joonas
> > 
> > >  /* The MMIO offset of the shared info between guest and host emulator */
> > >  #define VGT_PVINFO_PAGE	0x78000
> > >  #define VGT_PVINFO_SIZE	0x1000
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt
  2016-02-05 13:40       ` Joonas Lahtinen
@ 2016-02-05 14:16         ` Zhiyuan Lv
  2016-02-08 11:52           ` Joonas Lahtinen
  0 siblings, 1 reply; 49+ messages in thread
From: Zhiyuan Lv @ 2016-02-05 14:16 UTC (permalink / raw)
  To: Joonas Lahtinen; +Cc: daniel.vetter, intel-gfx, david.j.cowperthwaite, igvt-g

Hi Joonas,

On Fri, Feb 05, 2016 at 03:40:49PM +0200, Joonas Lahtinen wrote:
> Hi,
> 
> On pe, 2016-02-05 at 18:03 +0800, Zhiyuan Lv wrote:
> > Hi Joonas,
> > 
> > Thanks much for the review! We will incorporate those review comments!
> > 
> > Meanwhile, is it good enough to do the host ballooning like below? The
> > pros is that it is very simple, especially consider that guest
> > ballooning logic has been there. Thanks!
> > 
> 
> I think slicing it down like that is fine. Is there going to be real
> ballooning happening, as in, is the available memory dynamically going
> to change during runtime, or just be fixed size since the beginning?

In our current design, once the gvt is enabled, it is fixed size of graphics
memory for host since beginning. The reserved memory is all for virtual
machines.

We ever considered to support dynamically enabling/disabling gvt, that host
i915 could boot without gvt enabled, and can use all the hardware resources.
When there is need to creat VM, we can reload i915 driver to reserve the
resources. Does that sound good? Thanks!

Regards,
-Zhiyuan

> 
> Regards, Joonas
> 
> > Regards,
> > -Zhiyuan
> > 
> > On Thu, Feb 04, 2016 at 01:27:08PM +0200, Joonas Lahtinen wrote:
> > > Hi,
> > > 
> > > On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
> > > > From: Bing Niu <bing.niu@intel.com>
> > > > 
> > > > This patch introduces host graphics memory ballon when GVT-g is enabled.
> > > > 
> > > > As under GVT-g, i915 only owned limited graphics resources, others are
> > > > managed by GVT-g resource allocator and kept for other vGPUs.
> > > > 
> > > > For graphics memory space partition, a typical layout looks like:
> > > > 
> > > > +-------+-----------------------+------+-----------------------+
> > > > > * Host |   *GVT-g Resource     |* Host|   *GVT-g Resource     |
> > > > > Owned |   Allocator Managed   | Owned|   Allocator Managed   |
> > > > >       |                       |      |                       |
> > > > +---------------+-------+----------------------+-------+-------+
> > > > >       |       |       |       |      |       |       |       |
> > > > > i915  | vm 1  | vm 2  | vm 3  | i915 | vm 1  | vm 2  | vm 3  |
> > > > >       |       |       |       |      |       |       |       |
> > > > +-------+-------+-------+--------------+-------+-------+-------+
> > > > >           Aperture            |            Hidden            |
> > > > +-------------------------------+------------------------------+
> > > > >                       GGTT memory space                      |
> > > > +--------------------------------------------------------------+
> > > > 
> > > > Similar with fence registers partition:
> > > > 
> > > >  +------ +-----------------------+
> > > >  | * Host|    GVT-g Resource     |
> > > >  | Owned |   Allocator Managed   +
> > > >  0       |                       31
> > > >  +---------------+-------+-------+
> > > >  |       |       |       |       |
> > > >  | i915  | vm 1  | vm 2  | vm 3  |
> > > >  |       |       |       |       |
> > > >  +-------+-------+-------+-------+
> > > > 
> > > > i915 host will read the amount of allocated resources via GVT-g kernel parameters.
> > > > 
> > > > Signed-off-by: Bing Niu <bing.niu@intel.com>
> > > > Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
> > > > ---
> > > >  drivers/gpu/drm/i915/gvt/params.h   |  3 +++
> > > >  drivers/gpu/drm/i915/i915_gem.c     |  3 +++
> > > >  drivers/gpu/drm/i915/i915_gem_gtt.c |  4 ++--
> > > >  drivers/gpu/drm/i915/i915_vgpu.c    | 16 ++++++++++++----
> > > >  drivers/gpu/drm/i915/i915_vgpu.h    |  1 +
> > > >  5 files changed, 21 insertions(+), 6 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
> > > > index d2955b9..0656a98 100644
> > > > --- a/drivers/gpu/drm/i915/gvt/params.h
> > > > +++ b/drivers/gpu/drm/i915/gvt/params.h
> > > > @@ -27,6 +27,9 @@
> > > >  struct gvt_kernel_params {
> > > >  	bool enable;
> > > >  	int debug;
> > > > +	int dom0_low_gm_sz;
> > > > +	int dom0_high_gm_sz;
> > > > +	int dom0_fence_sz;
> 
> Some comment on the unit would be nice here, as there is a shift with
> << 20 later on.
> 
> Is "unsigned long" type and count in pages not acceptable? I think
> that's the assumption one is going to make.
> 
> > > >  };
> > > >  
> > > >  extern struct gvt_kernel_params gvt;
> > > > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> > > > index 799a53a..e916e43 100644
> > > > --- a/drivers/gpu/drm/i915/i915_gem.c
> > > > +++ b/drivers/gpu/drm/i915/i915_gem.c
> > > > @@ -5080,6 +5080,9 @@ i915_gem_load(struct drm_device *dev)
> > > >  	else
> > > >  		dev_priv->num_fence_regs = 8;
> > > >  
> > > > +	if(intel_gvt_host_active(dev))
> > > 
> > > Space between "if" and "("
> > 
> > Thanks! Will correct it.
> > 
> > > 
> > > > +		dev_priv->num_fence_regs = gvt.dom0_fence_sz;
> > > > +
> > > >  	if (intel_vgpu_active(dev))
> > > >  		dev_priv->num_fence_regs =
> > > >  				I915_READ(vgtif_reg(avail_rs.fence_num));
> > > 
> > > I'd like to see the above as "else if" construct just like you have
> > > below with the intel_vgt_balloon(). Could even do
> > > 
> > > 	if (gvt_host)  {
> > > 		...
> > > 	} else if (vgpu_active) {
> > > 		...
> > > 	} else {
> > > 		per machine detection
> > > 	}
> > > 
> > > Right?
> > 
> > That looks better!
> > 
> > > 
> > > > diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> > > > index 7377b67..0540de2 100644
> > > > --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> > > > +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> > > > @@ -2713,7 +2713,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
> > > >  	i915_address_space_init(ggtt_vm, dev_priv);
> > > >  	ggtt_vm->total += PAGE_SIZE;
> > > >  
> > > > -	if (intel_vgpu_active(dev)) {
> > > > +	if (intel_vgpu_active(dev) || intel_gvt_host_active(dev)) {
> > > >  		ret = intel_vgt_balloon(dev);
> > > >  		if (ret)
> > > >  			return ret;
> > > > @@ -2810,7 +2810,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev)
> > > >  	}
> > > >  
> > > >  	if (drm_mm_initialized(&vm->mm)) {
> > > > -		if (intel_vgpu_active(dev))
> > > > +		if (intel_vgpu_active(dev) || intel_gvt_host_active(dev))
> > > >  			intel_vgt_deballoon();
> > > >  
> > > >  		drm_mm_takedown(&vm->mm);
> > > > diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
> > > > index dea7429..fbe6114 100644
> > > > --- a/drivers/gpu/drm/i915/i915_vgpu.c
> > > > +++ b/drivers/gpu/drm/i915/i915_vgpu.c
> > > > @@ -188,10 +188,18 @@ int intel_vgt_balloon(struct drm_device *dev)
> > > >  	unsigned long unmappable_base, unmappable_size, unmappable_end;
> > > >  	int ret;
> > > >  
> > > > -	mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> > > > -	mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> > > > -	unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> > > > -	unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> > > > +	if(intel_gvt_host_active(dev)) {
> > > > +		mappable_base = 0;
> > > > +		mappable_size = gvt.dom0_low_gm_sz << 20;
> > > > +		unmappable_base = dev_priv->gtt.mappable_end;
> > > > +		unmappable_size = gvt.dom0_high_gm_sz << 20;
> > > > +	} else if (intel_vgpu_active(dev)) {
> > > > +		mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> > > > +		mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> > > > +		unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> > > > +		unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> > > > +	} else
> > > > +		return -ENODEV;
> > > >  
> > > 	} else {
> > > 		return -ENODEV;
> > > 	}
> > > 
> > > This must use braces too, according to the Kernel Coding Style.
> > 
> > That's right. Thanks for pointing it out!
> > 
> > > 
> > > >  	mappable_end = mappable_base + mappable_size;
> > > >  	unmappable_end = unmappable_base + unmappable_size;
> > > > diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
> > > > index 942490a..b8a49e6 100644
> > > > --- a/drivers/gpu/drm/i915/i915_vgpu.h
> > > > +++ b/drivers/gpu/drm/i915/i915_vgpu.h
> > > > @@ -24,6 +24,7 @@
> > > >  #ifndef _I915_VGPU_H_
> > > >  #define _I915_VGPU_H_
> > > >  
> > > > +#include "gvt/params.h"
> > > 
> > > This is not a good way of including headers, as this header itself
> > > doesn't need it. Including unnecessary stuff in often included headers
> > > contributes to increasing project compile times and makes it harder to
> > > solve cross dependencies later. So put it into the implementation file
> > > that needs it.
> > > 
> > 
> > Will delete. Thanks!
> > 
> > > Regards, Joonas
> > > 
> > > >  /* The MMIO offset of the shared info between guest and host emulator */
> > > >  #define VGT_PVINFO_PAGE	0x78000
> > > >  #define VGT_PVINFO_SIZE	0x1000
> -- 
> Joonas Lahtinen
> Open Source Technology Center
> Intel Corporation
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt
  2016-02-05 14:16         ` Zhiyuan Lv
@ 2016-02-08 11:52           ` Joonas Lahtinen
  0 siblings, 0 replies; 49+ messages in thread
From: Joonas Lahtinen @ 2016-02-08 11:52 UTC (permalink / raw)
  To: Zhiyuan Lv; +Cc: daniel.vetter, intel-gfx, david.j.cowperthwaite, igvt-g

On pe, 2016-02-05 at 22:16 +0800, Zhiyuan Lv wrote:
> Hi Joonas,
> 
> On Fri, Feb 05, 2016 at 03:40:49PM +0200, Joonas Lahtinen wrote:
> > Hi,
> > 
> > On pe, 2016-02-05 at 18:03 +0800, Zhiyuan Lv wrote:
> > > Hi Joonas,
> > > 
> > > Thanks much for the review! We will incorporate those review comments!
> > > 
> > > Meanwhile, is it good enough to do the host ballooning like below? The
> > > pros is that it is very simple, especially consider that guest
> > > ballooning logic has been there. Thanks!
> > > 
> > 
> > I think slicing it down like that is fine. Is there going to be real
> > ballooning happening, as in, is the available memory dynamically going
> > to change during runtime, or just be fixed size since the beginning?
> 
> In our current design, once the gvt is enabled, it is fixed size of graphics
> memory for host since beginning. The reserved memory is all for virtual
> machines.
> 
> We ever considered to support dynamically enabling/disabling gvt, that host
> i915 could boot without gvt enabled, and can use all the hardware resources.
> When there is need to creat VM, we can reload i915 driver to reserve the
> resources. Does that sound good? Thanks!
> 

But is the VM graphics memory amount a fixed slice, or is there real
ballooning happening in there (increasing the memory amount of the VM
on demand when running)? Memory balloon ing might be the wrong term to
use if a fixed slice of the graphics memory is allocated to VM when it
boots.

Regards, Joonas

> Regards,
> -Zhiyuan
> 
> > 
> > Regards, Joonas
> > 
> > > Regards,
> > > -Zhiyuan
> > > 
> > > On Thu, Feb 04, 2016 at 01:27:08PM +0200, Joonas Lahtinen wrote:
> > > > Hi,
> > > > 
> > > > On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
> > > > > From: Bing Niu <bing.niu@intel.com>
> > > > > 
> > > > > This patch introduces host graphics memory ballon when GVT-g is enabled.
> > > > > 
> > > > > As under GVT-g, i915 only owned limited graphics resources, others are
> > > > > managed by GVT-g resource allocator and kept for other vGPUs.
> > > > > 
> > > > > For graphics memory space partition, a typical layout looks like:
> > > > > 
> > > > > +-------+-----------------------+------+-----------------------+
> > > > > > * Host |   *GVT-g Resource     |* Host|   *GVT-g Resource     |
> > > > > > Owned |   Allocator Managed   | Owned|   Allocator Managed   |
> > > > > >       |                       |      |                       |
> > > > > +---------------+-------+----------------------+-------+-------+
> > > > > >       |       |       |       |      |       |       |       |
> > > > > > i915  | vm 1  | vm 2  | vm 3  | i915 | vm 1  | vm 2  | vm 3  |
> > > > > >       |       |       |       |      |       |       |       |
> > > > > +-------+-------+-------+--------------+-------+-------+-------+
> > > > > >           Aperture            |            Hidden            |
> > > > > +-------------------------------+------------------------------+
> > > > > >                       GGTT memory space                      |
> > > > > +--------------------------------------------------------------+
> > > > > 
> > > > > Similar with fence registers partition:
> > > > > 
> > > > >  +------ +-----------------------+
> > > > >  | * Host|    GVT-g Resource     |
> > > > >  | Owned |   Allocator Managed   +
> > > > >  0       |                       31
> > > > >  +---------------+-------+-------+
> > > > >  |       |       |       |       |
> > > > >  | i915  | vm 1  | vm 2  | vm 3  |
> > > > >  |       |       |       |       |
> > > > >  +-------+-------+-------+-------+
> > > > > 
> > > > > i915 host will read the amount of allocated resources via GVT-g kernel parameters.
> > > > > 
> > > > > Signed-off-by: Bing Niu <bing.niu@intel.com>
> > > > > Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
> > > > > ---
> > > > >  drivers/gpu/drm/i915/gvt/params.h   |  3 +++
> > > > >  drivers/gpu/drm/i915/i915_gem.c     |  3 +++
> > > > >  drivers/gpu/drm/i915/i915_gem_gtt.c |  4 ++--
> > > > >  drivers/gpu/drm/i915/i915_vgpu.c    | 16 ++++++++++++----
> > > > >  drivers/gpu/drm/i915/i915_vgpu.h    |  1 +
> > > > >  5 files changed, 21 insertions(+), 6 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
> > > > > index d2955b9..0656a98 100644
> > > > > --- a/drivers/gpu/drm/i915/gvt/params.h
> > > > > +++ b/drivers/gpu/drm/i915/gvt/params.h
> > > > > @@ -27,6 +27,9 @@
> > > > >  struct gvt_kernel_params {
> > > > >  	bool enable;
> > > > >  	int debug;
> > > > > +	int dom0_low_gm_sz;
> > > > > +	int dom0_high_gm_sz;
> > > > > +	int dom0_fence_sz;
> > 
> > Some comment on the unit would be nice here, as there is a shift with
> > << 20 later on.
> > 
> > Is "unsigned long" type and count in pages not acceptable? I think
> > that's the assumption one is going to make.
> > 
> > > > >  };
> > > > >  
> > > > >  extern struct gvt_kernel_params gvt;
> > > > > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> > > > > index 799a53a..e916e43 100644
> > > > > --- a/drivers/gpu/drm/i915/i915_gem.c
> > > > > +++ b/drivers/gpu/drm/i915/i915_gem.c
> > > > > @@ -5080,6 +5080,9 @@ i915_gem_load(struct drm_device *dev)
> > > > >  	else
> > > > >  		dev_priv->num_fence_regs = 8;
> > > > >  
> > > > > +	if(intel_gvt_host_active(dev))
> > > > 
> > > > Space between "if" and "("
> > > 
> > > Thanks! Will correct it.
> > > 
> > > > 
> > > > > +		dev_priv->num_fence_regs = gvt.dom0_fence_sz;
> > > > > +
> > > > >  	if (intel_vgpu_active(dev))
> > > > >  		dev_priv->num_fence_regs =
> > > > >  				I915_READ(vgtif_reg(avail_rs.fence_num));
> > > > 
> > > > I'd like to see the above as "else if" construct just like you have
> > > > below with the intel_vgt_balloon(). Could even do
> > > > 
> > > > 	if (gvt_host)  {
> > > > 		...
> > > > 	} else if (vgpu_active) {
> > > > 		...
> > > > 	} else {
> > > > 		per machine detection
> > > > 	}
> > > > 
> > > > Right?
> > > 
> > > That looks better!
> > > 
> > > > 
> > > > > diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> > > > > index 7377b67..0540de2 100644
> > > > > --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> > > > > +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> > > > > @@ -2713,7 +2713,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
> > > > >  	i915_address_space_init(ggtt_vm, dev_priv);
> > > > >  	ggtt_vm->total += PAGE_SIZE;
> > > > >  
> > > > > -	if (intel_vgpu_active(dev)) {
> > > > > +	if (intel_vgpu_active(dev) || intel_gvt_host_active(dev)) {
> > > > >  		ret = intel_vgt_balloon(dev);
> > > > >  		if (ret)
> > > > >  			return ret;
> > > > > @@ -2810,7 +2810,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev)
> > > > >  	}
> > > > >  
> > > > >  	if (drm_mm_initialized(&vm->mm)) {
> > > > > -		if (intel_vgpu_active(dev))
> > > > > +		if (intel_vgpu_active(dev) || intel_gvt_host_active(dev))
> > > > >  			intel_vgt_deballoon();
> > > > >  
> > > > >  		drm_mm_takedown(&vm->mm);
> > > > > diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
> > > > > index dea7429..fbe6114 100644
> > > > > --- a/drivers/gpu/drm/i915/i915_vgpu.c
> > > > > +++ b/drivers/gpu/drm/i915/i915_vgpu.c
> > > > > @@ -188,10 +188,18 @@ int intel_vgt_balloon(struct drm_device *dev)
> > > > >  	unsigned long unmappable_base, unmappable_size, unmappable_end;
> > > > >  	int ret;
> > > > >  
> > > > > -	mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> > > > > -	mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> > > > > -	unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> > > > > -	unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> > > > > +	if(intel_gvt_host_active(dev)) {
> > > > > +		mappable_base = 0;
> > > > > +		mappable_size = gvt.dom0_low_gm_sz << 20;
> > > > > +		unmappable_base = dev_priv->gtt.mappable_end;
> > > > > +		unmappable_size = gvt.dom0_high_gm_sz << 20;
> > > > > +	} else if (intel_vgpu_active(dev)) {
> > > > > +		mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> > > > > +		mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> > > > > +		unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> > > > > +		unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> > > > > +	} else
> > > > > +		return -ENODEV;
> > > > >  
> > > > 	} else {
> > > > 		return -ENODEV;
> > > > 	}
> > > > 
> > > > This must use braces too, according to the Kernel Coding Style.
> > > 
> > > That's right. Thanks for pointing it out!
> > > 
> > > > 
> > > > >  	mappable_end = mappable_base + mappable_size;
> > > > >  	unmappable_end = unmappable_base + unmappable_size;
> > > > > diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
> > > > > index 942490a..b8a49e6 100644
> > > > > --- a/drivers/gpu/drm/i915/i915_vgpu.h
> > > > > +++ b/drivers/gpu/drm/i915/i915_vgpu.h
> > > > > @@ -24,6 +24,7 @@
> > > > >  #ifndef _I915_VGPU_H_
> > > > >  #define _I915_VGPU_H_
> > > > >  
> > > > > +#include "gvt/params.h"
> > > > 
> > > > This is not a good way of including headers, as this header itself
> > > > doesn't need it. Including unnecessary stuff in often included headers
> > > > contributes to increasing project compile times and makes it harder to
> > > > solve cross dependencies later. So put it into the implementation file
> > > > that needs it.
> > > > 
> > > 
> > > Will delete. Thanks!
> > > 
> > > > Regards, Joonas
> > > > 
> > > > >  /* The MMIO offset of the shared info between guest and host emulator */
> > > > >  #define VGT_PVINFO_PAGE	0x78000
> > > > >  #define VGT_PVINFO_SIZE	0x1000
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt
  2016-01-28 10:21 ` [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt Zhi Wang
  2016-02-04 11:27   ` Joonas Lahtinen
@ 2016-02-10  8:08   ` Daniel Vetter
  1 sibling, 0 replies; 49+ messages in thread
From: Daniel Vetter @ 2016-02-10  8:08 UTC (permalink / raw)
  To: Zhi Wang; +Cc: daniel.vetter, intel-gfx, david.j.cowperthwaite, igvt-g

On Thu, Jan 28, 2016 at 06:21:24PM +0800, Zhi Wang wrote:
> From: Bing Niu <bing.niu@intel.com>
> 
> This patch introduces host graphics memory ballon when GVT-g is enabled.
> 
> As under GVT-g, i915 only owned limited graphics resources, others are
> managed by GVT-g resource allocator and kept for other vGPUs.
> 
> For graphics memory space partition, a typical layout looks like:
> 
> +-------+-----------------------+------+-----------------------+
> |* Host |   *GVT-g Resource     |* Host|   *GVT-g Resource     |
> | Owned |   Allocator Managed   | Owned|   Allocator Managed   |
> |       |                       |      |                       |
> +---------------+-------+----------------------+-------+-------+
> |       |       |       |       |      |       |       |       |
> | i915  | vm 1  | vm 2  | vm 3  | i915 | vm 1  | vm 2  | vm 3  |
> |       |       |       |       |      |       |       |       |
> +-------+-------+-------+--------------+-------+-------+-------+
> |           Aperture            |            Hidden            |
> +-------------------------------+------------------------------+
> |                       GGTT memory space                      |
> +--------------------------------------------------------------+
> 
> Similar with fence registers partition:
> 
>  +------ +-----------------------+
>  | * Host|    GVT-g Resource     |
>  | Owned |   Allocator Managed   +
>  0       |                       31
>  +---------------+-------+-------+
>  |       |       |       |       |
>  | i915  | vm 1  | vm 2  | vm 3  |
>  |       |       |       |       |
>  +-------+-------+-------+-------+

This kind of pretty graphs should be in the kerneldoc - with the asciidoc
support we have already in drm-intel-nightly (and hopefully soonish in
upstream). See http://blog.ffwll.ch/2016/01/better-markup-for-kernel-gpu-docbook.html

Cheers, Daniel

> 
> i915 host will read the amount of allocated resources via GVT-g kernel parameters.
> 
> Signed-off-by: Bing Niu <bing.niu@intel.com>
> Signed-off-by: Zhi Wang <zhi.a.wang@intel.com>
> ---
>  drivers/gpu/drm/i915/gvt/params.h   |  3 +++
>  drivers/gpu/drm/i915/i915_gem.c     |  3 +++
>  drivers/gpu/drm/i915/i915_gem_gtt.c |  4 ++--
>  drivers/gpu/drm/i915/i915_vgpu.c    | 16 ++++++++++++----
>  drivers/gpu/drm/i915/i915_vgpu.h    |  1 +
>  5 files changed, 21 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
> index d2955b9..0656a98 100644
> --- a/drivers/gpu/drm/i915/gvt/params.h
> +++ b/drivers/gpu/drm/i915/gvt/params.h
> @@ -27,6 +27,9 @@
>  struct gvt_kernel_params {
>  	bool enable;
>  	int debug;
> +	int dom0_low_gm_sz;
> +	int dom0_high_gm_sz;
> +	int dom0_fence_sz;
>  };
>  
>  extern struct gvt_kernel_params gvt;
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 799a53a..e916e43 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -5080,6 +5080,9 @@ i915_gem_load(struct drm_device *dev)
>  	else
>  		dev_priv->num_fence_regs = 8;
>  
> +	if(intel_gvt_host_active(dev))
> +		dev_priv->num_fence_regs = gvt.dom0_fence_sz;
> +
>  	if (intel_vgpu_active(dev))
>  		dev_priv->num_fence_regs =
>  				I915_READ(vgtif_reg(avail_rs.fence_num));
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> index 7377b67..0540de2 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> @@ -2713,7 +2713,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
>  	i915_address_space_init(ggtt_vm, dev_priv);
>  	ggtt_vm->total += PAGE_SIZE;
>  
> -	if (intel_vgpu_active(dev)) {
> +	if (intel_vgpu_active(dev) || intel_gvt_host_active(dev)) {
>  		ret = intel_vgt_balloon(dev);
>  		if (ret)
>  			return ret;
> @@ -2810,7 +2810,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev)
>  	}
>  
>  	if (drm_mm_initialized(&vm->mm)) {
> -		if (intel_vgpu_active(dev))
> +		if (intel_vgpu_active(dev) || intel_gvt_host_active(dev))
>  			intel_vgt_deballoon();
>  
>  		drm_mm_takedown(&vm->mm);
> diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
> index dea7429..fbe6114 100644
> --- a/drivers/gpu/drm/i915/i915_vgpu.c
> +++ b/drivers/gpu/drm/i915/i915_vgpu.c
> @@ -188,10 +188,18 @@ int intel_vgt_balloon(struct drm_device *dev)
>  	unsigned long unmappable_base, unmappable_size, unmappable_end;
>  	int ret;
>  
> -	mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> -	mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> -	unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> -	unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> +	if(intel_gvt_host_active(dev)) {
> +		mappable_base = 0;
> +		mappable_size = gvt.dom0_low_gm_sz << 20;
> +		unmappable_base = dev_priv->gtt.mappable_end;
> +		unmappable_size = gvt.dom0_high_gm_sz << 20;
> +	} else if (intel_vgpu_active(dev)) {
> +		mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base));
> +		mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size));
> +		unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base));
> +		unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size));
> +	} else
> +		return -ENODEV;
>  
>  	mappable_end = mappable_base + mappable_size;
>  	unmappable_end = unmappable_base + unmappable_size;
> diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
> index 942490a..b8a49e6 100644
> --- a/drivers/gpu/drm/i915/i915_vgpu.h
> +++ b/drivers/gpu/drm/i915/i915_vgpu.h
> @@ -24,6 +24,7 @@
>  #ifndef _I915_VGPU_H_
>  #define _I915_VGPU_H_
>  
> +#include "gvt/params.h"
>  /* The MMIO offset of the shared info between guest and host emulator */
>  #define VGT_PVINFO_PAGE	0x78000
>  #define VGT_PVINFO_SIZE	0x1000
> -- 
> 1.9.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g
  2016-02-03  6:01     ` Zhi Wang
  2016-02-03  7:01       ` Zhiyuan Lv
  2016-02-04 11:25       ` Joonas Lahtinen
@ 2016-02-16  9:54       ` Zhi Wang
  2016-02-16 12:44         ` Jani Nikula
  2016-02-16 14:08         ` Joonas Lahtinen
  2 siblings, 2 replies; 49+ messages in thread
From: Zhi Wang @ 2016-02-16  9:54 UTC (permalink / raw)
  To: Joonas Lahtinen, intel-gfx, igvt-g; +Cc: daniel.vetter, david.j.cowperthwaite

Hi Joonas:
     For the debug function/macros, could we use DRM_DEBUG_DRIVER as 
output, but keep our internal debug switch & marcos, like:

#define gvt_dbg_xxx(xxx, xxx) \
	if (gvt_debug & xxx) \
		DRM_DEBUG_DRIVER(xxxxxx)

Is it OK for the maintainers? Or we have to use DRM_DEBUG_DRIVER 
directly :(.

Thanks,
Zhi.

于 02/03/16 14:01, Zhi Wang wrote:
> Hi Joonas:
>      Thanks you very much! We're very excited for receiving your advice
> and continue to be open to any comments. :)
>
> I'm supposed that we should make the agreements on i915 host change at
> the very beginning, as I'm concerned during the discussion of i915 host
> change, you know, maybe some code of GVT-g needs to be refined or
> re-designed. So we put the i915 host changes to the beginning of the
> patch set for the convenience of discussion.
>
> I summarize your comments as below, very applicate. :)
>
> - Replace boolean return value with int as much as possible.
> - Replace customized debug ASSERT() function & macros with DRM_DEBUG_*
> - Document all non-static functions like i915
> - Fix all whitespace via scripts/cleanpatch.pl
> - Commit function structure refinement.
> - Change the register access behavior just like what i915 does.
>
> For other comments, see my comments below. :)
>
> On 01/29/16 21:57, Joonas Lahtinen wrote:
>> Hi,
>>
>> TL;DR Overall, we have same problem as with the scheduler series, there
>> is too much placeholder stuff for easy review. Just squash enough code
>> into one commit so it actually does something logical that can be
>> reviewed and then extend it later. Then it can be reviewed and pushed.
>> Just splitting the code down to achieve smaller patches is not the
>> right thing to do.
>>
>> Comments on the overall code: You need to document all header file
>> functions (in the source files), and it is good to document the static
>> functions within a file too, to make future maintenance easier.
>>
>> It is not about splitting the code down to small chunks, but splitting
>> it down to small *logical* chunks. It doesn't make sense to commit
>> dozens of empty bodied functions for review, and then later add their
>> code.
>>
>> If you add functions, only add them at a patch that takes them into use
>> too, unless we're talking about general purpose shared code. And also
>> remember to add the function body and documentation header. If you
>> simply add a "return 0;" or similar function body, do add a comment to
>> why the function does not exist and when it will.
>>
>> Then, there is a trend of having a boolean return values in the code.
>> When possible, it should rather be int and the cause for failure should
>> be propagated from the last level all the way to up (-ENOMEN etc.).
>> This way debugging becomes easier and if new error conditions appear,
>> there is less of a maintenance burden to add the propagation later.
>>
>> Finally, make sure to look at the existing driver parts and
>>     https://www.kernel.org/doc/Documentation/CodingStyle
>> for proper coding style. There are lots of whitespace fixes needed in
>> this series, like array initializations.
>>
>> I hope to see this first patch rerolled so that you squash some of the
>> later commits into it so that all functions have a body and you add
>> documentation for the functions so I can both see what it should do and
>> what it actually does. Only reroll the first patch, to keep the
>> iterative step smaller. Lets only then continue with the rest of the
>> series once we've reached a consensus on the formatting and style
>> basics.
>>
>> See more comments below.
>>
>> On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
>>> This patch introduces the very basic framework of GVT-g device model,
>>> includes basic prototypes, definitions, initialization.
>>> ---
>>>   arch/x86/include/asm/xen/interface.h  |   3 +
>>>   drivers/gpu/drm/i915/Kconfig          |  16 ++
>>>   drivers/gpu/drm/i915/Makefile         |   2 +
>>>   drivers/gpu/drm/i915/gvt/Makefile     |   5 +
>>>   drivers/gpu/drm/i915/gvt/debug.h      |  72 +++++++
>>>   drivers/gpu/drm/i915/gvt/fb_decoder.c |  34 ++++
>>>   drivers/gpu/drm/i915/gvt/fb_decoder.h | 110 ++++++++++
>>>   drivers/gpu/drm/i915/gvt/gvt.c        | 366
>>> ++++++++++++++++++++++++++++++++++
>>>   drivers/gpu/drm/i915/gvt/gvt.h        | 130 ++++++++++++
>>>   drivers/gpu/drm/i915/gvt/hypercall.h  |  30 +++
>>>   drivers/gpu/drm/i915/gvt/mpt.h        |  97 +++++++++
>>>   drivers/gpu/drm/i915/gvt/params.c     |  29 +++
>>>   drivers/gpu/drm/i915/gvt/params.h     |  34 ++++
>>>   drivers/gpu/drm/i915/gvt/reg.h        |  34 ++++
>>>   drivers/gpu/drm/i915/i915_dma.c       |  19 ++
>>>   drivers/gpu/drm/i915/i915_drv.h       |   6 +
>>>   drivers/gpu/drm/i915/i915_vgpu.h      |   3 +
>>>   include/xen/interface/xen.h           |   1 +
>>>   18 files changed, 991 insertions(+)
>>>   create mode 100644 drivers/gpu/drm/i915/gvt/Makefile
>>>   create mode 100644 drivers/gpu/drm/i915/gvt/debug.h
>>>   create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.c
>>>   create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.h
>>>   create mode 100644 drivers/gpu/drm/i915/gvt/gvt.c
>>>   create mode 100644 drivers/gpu/drm/i915/gvt/gvt.h
>>>   create mode 100644 drivers/gpu/drm/i915/gvt/hypercall.h
>>>   create mode 100644 drivers/gpu/drm/i915/gvt/mpt.h
>>>   create mode 100644 drivers/gpu/drm/i915/gvt/params.c
>>>   create mode 100644 drivers/gpu/drm/i915/gvt/params.h
>>>   create mode 100644 drivers/gpu/drm/i915/gvt/reg.h
>>>
>>> diff --git a/arch/x86/include/asm/xen/interface.h
>>> b/arch/x86/include/asm/xen/interface.h
>>> index 62ca03e..6ff4986 100644
>>> --- a/arch/x86/include/asm/xen/interface.h
>>> +++ b/arch/x86/include/asm/xen/interface.h
>>> @@ -73,6 +73,9 @@
>>>   #endif
>>>
>>>   #ifndef __ASSEMBLY__
>>> +
>>> +#include
>>> +
>>
>> I don't follow why this would need to be added if the file is not
>> modified otherwise. Each header should only include what they use.
>>
>> If this is an existing bug (that xen/interface.h can not be included
>> without including linux/types.h), it should be split to a separate
>> patch and sent to Xen team. Same for include/xen/interface/xen.h.
>>
>>>   /* Explicitly size integers that represent pfns in the public
>>> interface
>>>    * with Xen so that on ARM we can have one ABI that works for 32
>>> and 64
>>>    * bit guests. */
>>> diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
>>> index 051eab3..89ff723 100644
>>> --- a/drivers/gpu/drm/i915/Kconfig
>>> +++ b/drivers/gpu/drm/i915/Kconfig
>>> @@ -47,3 +47,19 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT
>>>         option changes the default for that module option.
>>>
>>>         If in doubt, say "N".
>>> +
>>> +config I915_GVT
>>> +        tristate "GVT-g host driver"
>>> +        depends on DRM_I915
>>> +        select IRQ_WORK
>>> +        default y
>>
>> Defaulting to "n" would make sense initially.
>>
> [Zhi] Sure, will do.
>>> +        help
>>> +          Enabling GVT-g mediated graphics passthrough technique for
>>> Intel i915
>>> +          based integrated graphics card. With GVT-g, it's possible
>>> to have one
>>> +          integrated i915 device shared by multiple VMs. Performance
>>> critical
>>> +          opterations such as apperture accesses and ring buffer
>>> operations
>>> +          are pass-throughed to VM, with a minimal set of
>>> conflicting resources
>>> +          (e.g. display settings) mediated by vGT driver. The
>>> benefit of vGT
>>> +          is on both the performance, given that each VM could
>>> directly operate
>>> +          its aperture space and submit commands like running on
>>> native, and
>>> +          the feature completeness, given that a true GEN hardware
>>> is exposed.
>>> diff --git a/drivers/gpu/drm/i915/Makefile
>>> b/drivers/gpu/drm/i915/Makefile
>>> index 0851de07..d4df410 100644
>>> --- a/drivers/gpu/drm/i915/Makefile
>>> +++ b/drivers/gpu/drm/i915/Makefile
>>> @@ -91,6 +91,8 @@ i915-y += dvo_ch7017.o \
>>>         intel_sdvo.o \
>>>         intel_tv.o
>>>
>>> +obj-$(CONFIG_I915_GVT)  += gvt/
>>> +
>>>   # virtual gpu code
>>>   i915-y += i915_vgpu.o
>>>
>>> diff --git a/drivers/gpu/drm/i915/gvt/Makefile
>>> b/drivers/gpu/drm/i915/gvt/Makefile
>>> new file mode 100644
>>> index 0000000..6935b78
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/gvt/Makefile
>>> @@ -0,0 +1,5 @@
>>> +GVT_SOURCE := gvt.o params.o fb_decoder.o
>>> +
>>> +ccflags-y            += -I$(src) -I$(src)/.. -Wall -Werror
>>> -Wno-unused-function
>>> +i915_gvt-y            := $(GVT_SOURCE)
>>> +obj-$(CONFIG_I915_GVT)        += i915_gvt.o
>>> diff --git a/drivers/gpu/drm/i915/gvt/debug.h
>>> b/drivers/gpu/drm/i915/gvt/debug.h
>>> new file mode 100644
>>> index 0000000..18e1467
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/gvt/debug.h
>>> @@ -0,0 +1,72 @@
>>> +/*
>>> + * Copyright(c) 2011-2016 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.
>>> + */
>>> +
>>> +#ifndef __GVT_DEBUG_H__
>>> +#define __GVT_DEBUG_H__
>>> +
>>> +#define
>>> ASSERT(x)                                                       \
>>> +        do
>>> {                                                            \
>>> +                if (!(x))
>>> {                                             \
>>> +                        printk("Assert at %s line
>>> %d\n",                \
>>> +                                __FILE__,
>>> __LINE__);                    \
>>> +
>>> }                                                       \
>>> +        } while (0);
>>> +
>>> +#define ASSERT_NUM(x,
>>> y)                                                \
>>> +        do
>>> {                                                            \
>>> +                if (!(x))
>>> {                                             \
>>> +                        printk("Assert at %s line %d para
>>> 0x%llx\n",    \
>>> +                                __FILE__, __LINE__,
>>> (u64)y);            \
>>> +
>>> }                                                       \
>>> +        } while (0);
>>> +
>>
>> There already is WARN_ON (and i915_drv.h modifies it a little). Do not
>> introduce custom functions like this, if the existing ones need
>> improvement, improve them.
>>
> [Zhi] OK. Will do as what i915 does
>>> +#define gvt_info(fmt, args...) \
>>> +    printk(KERN_INFO"[GVT-g] "fmt"\n", ##args)
>>> +
>>> +#define gvt_err(fmt, args...) \
>>> +    printk(KERN_ERR"%s() - %d: "fmt"\n", __func__, __LINE__, ##args)
>>> +
>>> +#define gvt_warn(fmt, args...) \
>>> +    printk(KERN_WARNING"%s() - %d: "fmt"\n", __func__, __LINE__,
>>> ##args)
>>> +
>>> +#define gvt_dbg(level, fmt, args...) do { \
>>> +        if (gvt.debug & level) \
>>> +            printk(KERN_DEBUG"%s() - %d: "fmt"\n", __func__,
>>> __LINE__, ##args); \
>>> +    }while(0)
>>> +
>>> +enum {
>>> +    GVT_DBG_CORE = (1 << 0),
>>> +    GVT_DBG_MM = (1 << 1),
>>> +    GVT_DBG_IRQ = (1 << 2),
>>> +};
>>> +
>>> +#define gvt_dbg_core(fmt, args...) \
>>> +    gvt_dbg(GVT_DBG_CORE, fmt, ##args)
>>> +
>>> +#define gvt_dbg_mm(fmt, args...) \
>>> +    gvt_dbg(GVT_DBG_MM, fmt, ##args)
>>> +
>>> +#define gvt_dbg_irq(fmt, args...) \
>>> +    gvt_dbg(GVT_DBG_IRQ, fmt, ##args)
>>> +
>>> +#endif
>>
>> This should be integrated better to DRM debugging options, custom
>> debugging code only for i915 was rejected a while ago.
>>
> [ZHI] Thanks for sharing the history. :) Will change that.
>>> diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c
>>> b/drivers/gpu/drm/i915/gvt/fb_decoder.c
>>> new file mode 100644
>>> index 0000000..a219819
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c
>>> @@ -0,0 +1,34 @@
>>> +/*
>>> + * Copyright(c) 2011-2016 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 "gvt.h"
>>> +
>>> +int gvt_decode_fb_format(struct pgt_device *pdev, int vmid, struct
>>> gvt_fb_format *fb)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +int gvt_fb_notifier_call_chain(unsigned long val, void *data)
>>> +{
>>> +    return 0;
>>> +}
>>
>> Kerneldoc missing for these functions. It is all the same to squash
>> later patches to introduce the code to these functions already,
>> reviewing utility functions with no kerneldoc and no body makes it
>> somewhat difficult to see the big picture.
>>
>
> [Zhi] One question. I saw i915 put some function instruction in *.c. Is
> it also OK for kernel doc generating the proper doc files?
>
>>> diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.h
>>> b/drivers/gpu/drm/i915/gvt/fb_decoder.h
>>> new file mode 100644
>>> index 0000000..2c29ed4
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.h
>>> @@ -0,0 +1,110 @@
>>> +/*
>>> + * Copyright(c) 2011-2016 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.
>>> + */
>>> +
>>> +#ifndef _GVT_FB_DECODER_H_
>>> +#define _GVT_FB_DECODER_H_
>>> +
>>> +typedef enum {
>>> +    FB_MODE_SET_START = 1,
>>> +    FB_MODE_SET_END,
>>> +    FB_DISPLAY_FLIP,
>>> +}gvt_fb_event_t;
>>> +
>>> +typedef enum {
>>> +    DDI_PORT_NONE    = 0,
>>> +    DDI_PORT_B    = 1,
>>> +    DDI_PORT_C    = 2,
>>> +    DDI_PORT_D    = 3,
>>> +    DDI_PORT_E    = 4
>>> +} ddi_port_t;
>>> +
>>> +struct pgt_device;
>>> +
>>> +struct gvt_fb_notify_msg {
>>> +    unsigned vm_id;
>>> +    unsigned pipe_id; /* id starting from 0 */
>>> +    unsigned plane_id; /* primary, cursor, or sprite */
>>> +};
>>> +
>>> +/* color space conversion and gamma correction are not included */
>>> +struct gvt_primary_plane_format {
>>> +    u8    enabled;    /* plane is enabled */
>>> +    u8    tiled;        /* X-tiled */
>>> +    u8    bpp;        /* bits per pixel */
>>> +    u32    hw_format;    /* format field in the PRI_CTL register */
>>> +    u32    drm_format;    /* format in DRM definition */
>>> +    u32    base;        /* framebuffer base in graphics memory */
>>> +    u32    x_offset;    /* in pixels */
>>> +    u32    y_offset;    /* in lines */
>>> +    u32    width;        /* in pixels */
>>> +    u32    height;        /* in lines */
>>> +    u32    stride;        /* in bytes */
>>> +};
>>> +
>>> +struct gvt_sprite_plane_format {
>>> +    u8    enabled;    /* plane is enabled */
>>> +    u8    tiled;        /* X-tiled */
>>> +    u8    bpp;        /* bits per pixel */
>>> +    u32    hw_format;    /* format field in the SPR_CTL register */
>>> +    u32    drm_format;    /* format in DRM definition */
>>> +    u32    base;        /* sprite base in graphics memory */
>>> +    u32    x_pos;        /* in pixels */
>>> +    u32    y_pos;        /* in lines */
>>> +    u32    x_offset;    /* in pixels */
>>> +    u32    y_offset;    /* in lines */
>>> +    u32    width;        /* in pixels */
>>> +    u32    height;        /* in lines */
>>> +};
>>> +
>>> +struct gvt_cursor_plane_format {
>>> +    u8    enabled;
>>> +    u8    mode;        /* cursor mode select */
>>> +    u8    bpp;        /* bits per pixel */
>>> +    u32    drm_format;    /* format in DRM definition */
>>> +    u32    base;        /* cursor base in graphics memory */
>>> +    u32    x_pos;        /* in pixels */
>>> +    u32    y_pos;        /* in lines */
>>> +    u8    x_sign;        /* X Position Sign */
>>> +    u8    y_sign;        /* Y Position Sign */
>>> +    u32    width;        /* in pixels */
>>> +    u32    height;        /* in lines */
>>> +    u32    x_hot;        /* in pixels */
>>> +    u32    y_hot;        /* in pixels */
>>> +};
>>> +
>>
>> The above structs have a lot in common, would it make sense to have the
>> common members + plane type and then union for the plane type specific
>> data. I suspect having it all split this way will lead to more utility
>> functions somewhere.
>>
> [Zhi] Thanks. Will do that.
>
>>> +struct gvt_pipe_format {
>>> +    struct gvt_primary_plane_format    primary;
>>> +    struct gvt_sprite_plane_format    sprite;
>>> +    struct gvt_cursor_plane_format    cursor;
>>> +    ddi_port_t ddi_port;  /* the DDI port that the pipe is connected
>>> to */
>>> +};
>>> +
>>> +struct gvt_fb_format{
>>> +    struct gvt_pipe_format    pipes[I915_MAX_PIPES];
>>> +};
>>> +
>>> +extern int gvt_fb_notifier_call_chain(unsigned long val, void *data);
>>> +extern int gvt_decode_fb_format(struct pgt_device *pdev, int vmid,
>>> +                struct gvt_fb_format *fb);
>>> +
>>> +#endif
>>> diff --git a/drivers/gpu/drm/i915/gvt/gvt.c
>>> b/drivers/gpu/drm/i915/gvt/gvt.c
>>> new file mode 100644
>>> index 0000000..041d10f
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/gvt/gvt.c
>>> @@ -0,0 +1,366 @@
>>> +/*
>>> + * Copyright(c) 2011-2016 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
>>> +#include
>>> +
>>> +#include "gvt.h"
>>> +
>>> +struct gvt_host gvt_host;
>>> +
>>> +extern struct gvt_kernel_dm xengt_kdm;
>>> +extern struct gvt_kernel_dm kvmgt_kdm;
>>> +
>>> +static const char *supported_hypervisors[] = {
>>
>> should be "static const char * const".
>>
>>> +    [GVT_HYPERVISOR_TYPE_XEN] = "Xen Hypervisor",
>>> +    [GVT_HYPERVISOR_TYPE_KVM] = "KVM",
>>> +};
>>> +
>>> +static bool gvt_init_host(void)
>>> +{
>>> +    struct gvt_host *host = &gvt_host;
>>> +
>>> +    if (!gvt.enable) {
>>> +        gvt_dbg_core("GVT-g has been disabled by kernel parameter");
>>> +        return false;
>>> +    }
>>> +
>>> +    if (host->initialized) {
>>> +        gvt_err("GVT-g has already been initialized!");
>>> +        return false;
>>> +    }
>>> +
>>> +    if (xen_initial_domain()) {
>>
>> Shouldn't Xen code be CONFIG_XEN_DOM0 and CONFIG_XEN #ifdef protected?
>>
> [Zhi] The following code piece shows xen_initial_domain()/xen_domain()
> could also be used when CONFIG_XEN_DOM0 is not set.
>
> #ifdef CONFIG_XEN
> extern enum xen_domain_type xen_domain_type;
> #else
> #define xen_domain_type         XEN_NATIVE
> #endif
>
> #define xen_domain()            (xen_domain_type != XEN_NATIVE)
> #define xen_pv_domain()         (xen_domain() &&                        \
>                                   xen_domain_type == XEN_PV_DOMAIN)
> #define xen_hvm_domain()        (xen_domain() &&                        \
>                                   xen_domain_type == XEN_HVM_DOMAIN)
>
> #ifdef CONFIG_XEN_DOM0
> #include <xen/interface/xen.h>
> #include <asm/xen/hypervisor.h>
>
> #define xen_initial_domain()    (xen_domain() && \
>                                   xen_start_info &&
> xen_start_info->flags & SIF_INITDOMAIN)
> #else  /* !CONFIG_XEN_DOM0 */
> #define xen_initial_domain()    (0)
> #endif  /* CONFIG_XEN_DOM0 */
>
>>> +        /* Xen Dom0 */
>>> +        host->kdm = try_then_request_module(symbol_get(xengt_kdm),
>>> "xengt");
>>> +        host->hypervisor_type = GVT_HYPERVISOR_TYPE_XEN;
>>> +    } else if(xen_domain()) {
>>> +        /* Xen DomU */
>>> +        return false;
>>> +    } else {
>>> +        /* not in Xen. Try KVMGT */
>>> +        host->kdm = try_then_request_module(symbol_get(kvmgt_kdm),
>>> "kvm");
>>> +        host->hypervisor_type = GVT_HYPERVISOR_TYPE_KVM;
>>> +    }
>>> +
>>
>> Why do we need to keep track of hypervisor type, are there plenty of
>> hypervisor specific behaviour differences?
>
> [Zhi] As GVT-g needs some hypervisor services to work, we write a
> abstraction layer to connect GVT-g to different hypervisor. But still
> there are some emulation logic couldn't be fitted into that abstraction
> layer, like OpRegion emulation. In Xen, we emulates it in kernel space,
> while we emulates it in Qemu under KVM. I also agreed that we should
> find some approach to improve it just like what you said.
>
> If it is just for printing
>> the below debug, I think it's better to move the debug into above code
>> that detects the hypervisor, wrap them with appropriate CONFIG #ifdefs.
>>
>>> +    if (!host->kdm)
>>> +        return false;
>>> +
>>> +    if (!hypervisor_detect_host())
>>> +        return false;
>>> +
>>> +    gvt_info("Running with hypervisor %s in host mode",
>>> +            supported_hypervisors[host->hypervisor_type]);
>>> +
>>> +    idr_init(&host->device_idr);
>>> +    mutex_init(&host->device_idr_lock);
>>> +
>>> +    host->initialized = true;
>>> +    return true;
>>> +}
>>> +
>>> +static bool init_device_info(struct pgt_device *pdev)
>>> +{
>>> +    struct gvt_device_info *info = &pdev->device_info;
>>> +
>>> +    if (!IS_BROADWELL(pdev->dev_priv)) {
>>> +        gvt_err("Unsupported GEN device");
>>> +        return false;
>>> +    }
>>> +
>>> +    if (IS_BROADWELL(pdev->dev_priv)) {
>>> +        info->max_gtt_gm_sz = (1UL << 32);
>>> +        /*
>>> +         * The layout of BAR0 in BDW:
>>> +         * |< - MMIO 2MB ->|<- Reserved 6MB ->|<- MAX GTT 8MB->|
>>> +         *
>>> +         * GTT offset in BAR0 starts from 8MB to 16MB, and
>>> +         * Whatever GTT size is configured in BIOS,
>>> +         * the size of BAR0 is always 16MB. The actual configured
>>> +         * GTT size can be found in GMCH_CTRL.
>>> +         */
>>> +        info->gtt_start_offset = (1UL << 23);
>>> +        info->max_gtt_size = (1UL << 23);
>>> +        info->gtt_entry_size = 8;
>>> +        info->gtt_entry_size_shift = 3;
>>> +        info->gmadr_bytes_in_cmd = 8;
>>
>> Would this information be useful in a header as #defines too?
>>
> [Zhi] Probably. Consider that one GVT-g featured kernel could be able to
> run on different platforms, the informaion data structure could be
> different. But I agree to define the magic numbers in a header files. :)
>
>>> +    }
>>> +
>>> +    gvt_info("Device info:");
>>> +    printk("        max_gtt_gm_sz: %llx\n", info->max_gtt_gm_sz);
>>> +    printk("        max_gtt_size: %x\n", info->max_gtt_size);
>>> +    printk("        gtt_size_entry: %x\n", info->gtt_entry_size);
>>> +    printk("        gtt_entry_size_shift: %x\n",
>>> info->gtt_entry_size_shift);
>>> +    printk("        gtt_start_offset: %x\n", info->gtt_start_offset);
>>> +    printk("        gtt_end_offset: %x\n", info->gtt_end_offset);
>>> +
>>
>> Just put this to kind of stuff to i915_debugfs.c.
>>
> [Zhi] Thanks.
>
>>> +    return true;
>>> +}
>>> +
>>> +static void init_initial_cfg_space_state(struct pgt_device *pdev)
>>> +{
>>> +    struct pci_dev *pci_dev = pdev->dev_priv->dev->pdev;
>>> +    int i;
>>> +
>>> +    gvt_dbg_core("init initial cfg space, id %d", pdev->id);
>>> +
>>> +    for (i = 0; i < GVT_CFG_SPACE_SZ; i += 4)
>>
>> += sizeof(...)
>>
>>> +        pci_read_config_dword(pci_dev, i,
>>> +                (u32 *)&pdev->initial_cfg_space[i]);
>>> +
>>> +    for (i = 0; i < 3; i++) {
>>
>> No magic numbers make a #define for 3 and give it a descriptive name.
>>
>>> +        pdev->bar_size[i] = pci_resource_len(pci_dev, i * 2);
>>> +        gvt_info("bar %d size: %llx", i, pdev->bar_size[i]);
>>> +    }
>>> +}
>>> +
>>> +static void clean_initial_mmio_state(struct pgt_device *pdev)
>>> +{
>>> +    if (pdev->gttmmio_va) {
>>> +        iounmap(pdev->gttmmio_va);
>>> +        pdev->gttmmio_va = NULL;
>>> +    }
>>> +
>>> +    if (pdev->gmadr_va) {
>>> +        iounmap(pdev->gmadr_va);
>>> +        pdev->gmadr_va = NULL;
>>> +    }
>>> +}
>>> +
>>> +static bool init_initial_mmio_state(struct pgt_device *pdev)
>>> +{
>>> +    u64 bar0, bar1;
>>> +
>>> +    gvt_dbg_core("init initial mmio state, id %d", pdev->id);
>>> +
>>> +    bar0 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR0];
>>> +    bar1 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR1];
>>> +
>>> +    pdev->gttmmio_base = bar0 & ~0xf;
>>> +    pdev->mmio_size = 2 * 1024 * 1024;
>>> +    pdev->reg_num = pdev->mmio_size / 4;
>>> +    pdev->gmadr_base = bar1 & ~0xf;
>>> +
>>
>> Many magic numbers.
>>
>>> +    pdev->gttmmio_va = ioremap(pdev->gttmmio_base, pdev->bar_size[0]);
>>> +    if (!pdev->gttmmio_va) {
>>> +        gvt_err("fail to map GTTMMIO BAR.");
>>
>> These should be if(WARN_ON(...))
>>
>>> +        return false;
>>> +    }
>>> +
>>> +    pdev->gmadr_va = ioremap(pdev->gmadr_base, pdev->bar_size[2]);
>>> +    if (!pdev->gmadr_va) {
>>> +        gvt_err("fail to map GMADR BAR.");
>>> +        goto err;
>>> +    }
>>> +
>>> +    gvt_info("bar0: 0x%llx, bar1: 0x%llx", bar0, bar1);
>>> +    gvt_info("mmio size: %x", pdev->mmio_size);
>>> +    gvt_info("gttmmio: 0x%llx, gmadr: 0x%llx", pdev->gttmmio_base,
>>> pdev->gmadr_base);
>>> +    gvt_info("gttmmio_va: %p", pdev->gttmmio_va);
>>> +    gvt_info("gmadr_va: %p", pdev->gmadr_va);
>>> +
>>> +    return true;
>>> +err:
>>> +    clean_initial_mmio_state(pdev);
>>> +    return false;
>>> +}
>>> +
>>> +static int gvt_service_thread(void *data)
>>> +{
>>> +    struct pgt_device *pdev = (struct pgt_device *)data;
>>> +    int r;
>>> +
>>> +    gvt_dbg_core("service thread start, pgt %d", pdev->id);
>>> +
>>> +    while(!kthread_should_stop()) {
>>> +        r = wait_event_interruptible(pdev->service_thread_wq,
>>> +                kthread_should_stop() || pdev->service_request);
>>> +
>>> +        if (kthread_should_stop())
>>> +            break;
>>> +
>>> +        if (r) {
>>> +            gvt_warn("service thread is waken up by unexpected
>>> signal.");
>>
>> Should be WARN_ONCE, to avoid future disasters with CI.
>>
> [Zhi] Thanks.
>>> +            continue;
>>> +        }
>>> +    }
>>> +    return 0;
>>> +}
>>> +
>>> +static void clean_service_thread(struct pgt_device *pdev)
>>> +{
>>> +    if (pdev->service_thread) {
>>> +        kthread_stop(pdev->service_thread);
>>> +        pdev->service_thread = NULL;
>>> +    }
>>> +}
>>> +
>>> +static bool init_service_thread(struct pgt_device *pdev)
>>> +{
>>> +    init_waitqueue_head(&pdev->service_thread_wq);
>>> +
>>> +    pdev->service_thread = kthread_run(gvt_service_thread,
>>> +            pdev, "gvt_service_thread%d", pdev->id);
>>> +
>>> +    if (!pdev->service_thread) {
>>> +        gvt_err("fail to start service thread.");
>>> +        return false;
>>> +    }
>>> +
>>> +    return true;
>>> +}
>>> +
>>> +static void clean_pgt_device(struct pgt_device *pdev)
>>> +{
>>> +    clean_service_thread(pdev);
>>> +    clean_initial_mmio_state(pdev);
>>> +}
>>> +
>>> +static bool init_pgt_device(struct pgt_device *pdev, struct
>>> drm_i915_private *dev_priv)
>>> +{
>>> +    if (!init_device_info(pdev))
>>> +        return false;
>>> +
>>> +    init_initial_cfg_space_state(pdev);
>>> +
>>> +    if (!init_initial_mmio_state(pdev))
>>> +        goto err;
>>> +
>>> +    if (!init_service_thread(pdev))
>>> +        goto err;
>>> +
>>> +    return true;
>>> +err:
>>> +    clean_pgt_device(pdev);
>>> +    return false;
>>> +}
>>> +
>>> +static bool post_init_pgt_device(struct pgt_device *pdev)
>>> +{
>>> +    return true;
>>> +}
>>> +
>>> +static void free_pgt_device(struct pgt_device *pdev)
>>> +{
>>> +    struct gvt_host *host = &gvt_host;
>>> +
>>> +    mutex_lock(&host->device_idr_lock);
>>> +    idr_remove(&host->device_idr, pdev->id);
>>> +    mutex_unlock(&host->device_idr_lock);
>>> +
>>> +    vfree(pdev);
>>> +}
>>> +
>>> +static struct pgt_device *alloc_pgt_device(struct drm_i915_private
>>> *dev_priv)
>>> +{
>>> +    struct gvt_host *host = &gvt_host;
>>> +    struct pgt_device *pdev = NULL;
>>> +
>>> +    pdev = vzalloc(sizeof(*pdev));
>>> +    if (!pdev) {
>>> +        gvt_err("fail to allocate memory for pgt device.");
>>> +        return NULL;
>>> +    }
>>> +
>>> +    mutex_lock(&host->device_idr_lock);
>>> +    pdev->id = idr_alloc(&host->device_idr, pdev, 0, 0, GFP_KERNEL);
>>> +    mutex_unlock(&host->device_idr_lock);
>>> +
>>> +    if (pdev->id < 0) {
>>> +        gvt_err("fail to allocate pgt device id.");
>>> +        goto err;
>>> +    }
>>> +
>>> +    mutex_init(&pdev->lock);
>>> +    pdev->dev_priv = dev_priv;
>>> +    idr_init(&pdev->instance_idr);
>>> +
>>> +    return pdev;
>>> +err:
>>> +    free_pgt_device(pdev);
>>> +    return NULL;
>>> +}
>>> +
>>> +void gvt_destroy_pgt_device(void *private_data)
>>> +{
>>> +    struct pgt_device *pdev = (struct pgt_device *)private_data;
>>> +
>>> +    clean_pgt_device(pdev);
>>> +    free_pgt_device(pdev);
>>> +}
>>> +
>>> +void *gvt_create_pgt_device(struct drm_i915_private *dev_priv)
>>> +{
>>> +    struct pgt_device *pdev = NULL;
>>> +    struct gvt_host *host = &gvt_host;
>>> +
>>> +    if (!host->initialized && !gvt_init_host()) {
>>> +        gvt_err("gvt_init_host fail");
>>> +        return NULL;
>>> +    }
>>> +
>>> +    gvt_dbg_core("create new pgt device, i915 dev_priv: %p", dev_priv);
>>> +
>>> +    pdev = alloc_pgt_device(dev_priv);
>>> +    if (!pdev) {
>>> +        gvt_err("fail to allocate memory for pgt device.");
>>> +        goto err;
>>> +    }
>>> +
>>> +    gvt_dbg_core("init pgt device, id %d", pdev->id);
>>> +
>>> +    if (!init_pgt_device(pdev, dev_priv)) {
>>> +        gvt_err("fail to init physical device state.");
>>> +        goto err;
>>> +    }
>>> +
>>> +    gvt_dbg_core("pgt device creation done, id %d", pdev->id);
>>> +
>>> +    return pdev;
>>> +err:
>>> +    if (pdev) {
>>> +        gvt_destroy_pgt_device(pdev);
>>> +        pdev = NULL;
>>> +    }
>>> +    return NULL;
>>> +}
>>> +
>>> +bool gvt_post_init_pgt_device(void *private_data)
>>> +{
>>> +    struct pgt_device *pdev = (struct pgt_device *)private_data;
>>> +    struct gvt_host *host = &gvt_host;
>>> +
>>> +    if (!host->initialized) {
>>> +        gvt_err("gvt_host haven't been initialized.");
>>> +        return false;
>>> +    }
>>> +
>>> +    gvt_dbg_core("post init pgt device %d", pdev->id);
>>> +
>>> +    if (!post_init_pgt_device(pdev)) {
>>> +        gvt_err("fail to post init physical device state.");
>>> +        return false;
>>> +    }
>>> +
>>> +    return true;
>>> +}
>>> diff --git a/drivers/gpu/drm/i915/gvt/gvt.h
>>> b/drivers/gpu/drm/i915/gvt/gvt.h
>>> new file mode 100644
>>> index 0000000..6c85bba
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/gvt/gvt.h
>>> @@ -0,0 +1,130 @@
>>> +/*
>>> + * Copyright(c) 2011-2016 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.
>>> + */
>>> +
>>> +#ifndef _GVT_H_
>>> +#define _GVT_H_
>>> +
>>> +#include "i915_drv.h"
>>> +#include "i915_vgpu.h"
>>> +
>>> +#include "debug.h"
>>> +#include "params.h"
>>> +#include "reg.h"
>>> +#include "hypercall.h"
>>> +#include "mpt.h"
>>> +#include "fb_decoder.h"
>>> +
>>> +#define GVT_MAX_VGPU 8
>>> +
>>> +enum {
>>> +    GVT_HYPERVISOR_TYPE_XEN = 0,
>>> +    GVT_HYPERVISOR_TYPE_KVM,
>>> +};
>>> +
>>> +struct gvt_host {
>>> +    bool initialized;
>>> +    int hypervisor_type;
>>> +    struct mutex device_idr_lock;
>>> +    struct idr device_idr;
>>> +    struct gvt_kernel_dm *kdm;
>>> +};
>>> +
>>> +extern struct gvt_host gvt_host;
>>> +
>>> +/* Describe the limitation of HW.*/
>>> +struct gvt_device_info {
>>> +    u64 max_gtt_gm_sz;
>>> +    u32 gtt_start_offset;
>>> +    u32 gtt_end_offset;
>>> +    u32 max_gtt_size;
>>> +    u32 gtt_entry_size;
>>> +    u32 gtt_entry_size_shift;
>>> +    u32 gmadr_bytes_in_cmd;
>>> +};
>>> +
>>> +struct vgt_device {
>>> +    int id;
>>> +    int vm_id;
>>> +    struct pgt_device *pdev;
>>> +    bool warn_untrack;
>>> +};
>>> +
>>> +struct pgt_device {
>>> +    struct mutex lock;
>>> +    int id;
>>> +
>>> +    struct drm_i915_private *dev_priv;
>>> +    struct idr instance_idr;
>>> +
>>> +    struct gvt_device_info device_info;
>>> +
>>> +    u8 initial_cfg_space[GVT_CFG_SPACE_SZ];
>>> +    u64 bar_size[GVT_BAR_NUM];
>>> +
>>> +    u64 gttmmio_base;
>>> +    void *gttmmio_va;
>>> +
>>> +    u64 gmadr_base;
>>> +    void *gmadr_va;
>>> +
>>> +    u32 mmio_size;
>>> +    u32 reg_num;
>>> +
>>> +    wait_queue_head_t service_thread_wq;
>>> +    struct task_struct *service_thread;
>>> +    unsigned long service_request;
>>> +};
>>> +
>>
>> Here-->
>>
>>> +static inline u32 gvt_mmio_read(struct pgt_device *pdev,
>>> +        u32 reg)
>>> +{
>>> +    struct drm_i915_private *dev_priv = pdev->dev_priv;
>>> +    i915_reg_t tmp = {.reg = reg};
>>> +    return I915_READ(tmp);
>>> +}
>>> +
>>> +static inline void gvt_mmio_write(struct pgt_device *pdev,
>>> +        u32 reg, u32 val)
>>> +{
>>> +    struct drm_i915_private *dev_priv = pdev->dev_priv;
>>> +    i915_reg_t tmp = {.reg = reg};
>>> +    I915_WRITE(tmp, val);
>>> +}
>>> +
>>> +static inline u64 gvt_mmio_read64(struct pgt_device *pdev,
>>> +        u32 reg)
>>> +{
>>> +    struct drm_i915_private *dev_priv = pdev->dev_priv;
>>> +    i915_reg_t tmp = {.reg = reg};
>>> +    return I915_READ64(tmp);
>>> +}
>>> +
>>> +static inline void gvt_mmio_write64(struct pgt_device *pdev,
>>> +        u32 reg, u64 val)
>>> +{
>>> +    struct drm_i915_private *dev_priv = pdev->dev_priv;
>>> +    i915_reg_t tmp = {.reg = reg};
>>> +    I915_WRITE64(tmp, val);
>>> +}
>>> +
>>
>> <-- Why? The i915_reg_t type was added to avoid problems, this code is
>> not used anywhere, and it has no documentation, so I can not review it.
>>
>> I wrote comments at the top of the post.
>>
> [Zhi] Thanks, I will check that.
>
>> Regards, Joonas
>>
>>> +#endif
>>> diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h
>>> b/drivers/gpu/drm/i915/gvt/hypercall.h
>>> new file mode 100644
>>> index 0000000..0a41874
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/gvt/hypercall.h
>>> @@ -0,0 +1,30 @@
>>> +/*
>>> + * Copyright(c) 2011-2016 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.
>>> + */
>>> +
>>> +#ifndef _GVT_HYPERCALL_H_
>>> +#define _GVT_HYPERCALL_H_
>>> +
>>> +struct gvt_kernel_dm {
>>> +};
>>> +
>>> +#endif /* _GVT_HYPERCALL_H_ */
>>> diff --git a/drivers/gpu/drm/i915/gvt/mpt.h
>>> b/drivers/gpu/drm/i915/gvt/mpt.h
>>> new file mode 100644
>>> index 0000000..bbe4465
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/gvt/mpt.h
>>> @@ -0,0 +1,97 @@
>>> +/*
>>> + * Copyright(c) 2011-2016 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.
>>> + */
>>> +
>>> +#ifndef _GVT_MPT_H_
>>> +#define _GVT_MPT_H_
>>> +
>>> +struct vgt_device;
>>> +
>>> +static inline unsigned long hypervisor_g2m_pfn(struct vgt_device *vgt,
>>> +    unsigned long g_pfn)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +static inline int hypervisor_pause_domain(struct vgt_device *vgt)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +static inline int hypervisor_shutdown_domain(struct vgt_device *vgt)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +static inline int hypervisor_set_trap_area(struct vgt_device *vgt,
>>> +    uint64_t start, uint64_t end, bool map)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +static inline bool hypervisor_detect_host(void)
>>> +{
>>> +    return false;
>>> +}
>>> +
>>> +static inline int hypervisor_virt_to_mfn(void *addr)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +static inline void *hypervisor_mfn_to_virt(int mfn)
>>> +{
>>> +    return NULL;
>>> +}
>>> +
>>> +static inline void hypervisor_inject_msi(struct vgt_device *vgt)
>>> +{
>>> +    return;
>>> +}
>>> +
>>> +static inline int hypervisor_hvm_init(struct vgt_device *vgt)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +static inline void hypervisor_hvm_exit(struct vgt_device *vgt)
>>> +{
>>> +}
>>> +
>>> +static inline void *hypervisor_gpa_to_va(struct vgt_device *vgt,
>>> unsigned long gpa)
>>> +{
>>> +    return NULL;
>>> +}
>>> +
>>> +static inline bool hypervisor_read_va(struct vgt_device *vgt, void *va,
>>> +        void *val, int len, int atomic)
>>> +{
>>> +    return false;
>>> +}
>>> +
>>> +static inline bool hypervisor_write_va(struct vgt_device *vgt, void
>>> *va,
>>> +        void *val, int len, int atomic)
>>> +{
>>> +    return false;
>>> +}
>>> +
>>> +#endif /* _GVT_MPT_H_ */
>>> diff --git a/drivers/gpu/drm/i915/gvt/params.c
>>> b/drivers/gpu/drm/i915/gvt/params.c
>>> new file mode 100644
>>> index 0000000..dfc33c3
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/gvt/params.c
>>> @@ -0,0 +1,29 @@
>>> +/*
>>> + * Copyright(c) 2011-2016 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 "gvt.h"
>>> +
>>> +struct gvt_kernel_params gvt = {
>>> +    .enable = true,
>>> +    .debug = 0,
>>> +};
>>> diff --git a/drivers/gpu/drm/i915/gvt/params.h
>>> b/drivers/gpu/drm/i915/gvt/params.h
>>> new file mode 100644
>>> index 0000000..d2955b9
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/gvt/params.h
>>> @@ -0,0 +1,34 @@
>>> +/*
>>> + * Copyright(c) 2011-2016 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.
>>> + */
>>> +
>>> +#ifndef _GVT_PARAMS_H_
>>> +#define _GVT_PARAMS_H_
>>> +
>>> +struct gvt_kernel_params {
>>> +    bool enable;
>>> +    int debug;
>>> +};
>>> +
>>> +extern struct gvt_kernel_params gvt;
>>> +
>>> +#endif
>>> diff --git a/drivers/gpu/drm/i915/gvt/reg.h
>>> b/drivers/gpu/drm/i915/gvt/reg.h
>>> new file mode 100644
>>> index 0000000..d363b74
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/i915/gvt/reg.h
>>> @@ -0,0 +1,34 @@
>>> +/*
>>> + * Copyright(c) 2011-2016 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.
>>> + */
>>> +
>>> +#ifndef _GVT_REG_H
>>> +#define _GVT_REG_H
>>> +
>>> +#define GVT_CFG_SPACE_SZ    256
>>> +#define GVT_BAR_NUM        4
>>> +
>>> +#define GVT_REG_CFG_SPACE_BAR0    0x10
>>> +#define GVT_REG_CFG_SPACE_BAR1    0x18
>>> +#define GVT_REG_CFG_SPACE_BAR2    0x20
>>> +
>>> +#endif
>>> diff --git a/drivers/gpu/drm/i915/i915_dma.c
>>> b/drivers/gpu/drm/i915/i915_dma.c
>>> index 4725e8d..eca8e50 100644
>>> --- a/drivers/gpu/drm/i915/i915_dma.c
>>> +++ b/drivers/gpu/drm/i915/i915_dma.c
>>> @@ -943,6 +943,10 @@ int i915_driver_load(struct drm_device *dev,
>>> unsigned long flags)
>>>
>>>       intel_uncore_init(dev);
>>>
>>> +    dev_priv->vgpu.host_private_data = gvt_create_pgt_device(dev_priv);
>>> +    if(intel_gvt_host_active(dev))
>>> +        DRM_INFO("GVT-g is running in host mode\n");
>>> +
>>>       ret = i915_gem_gtt_init(dev);
>>>       if (ret)
>>>           goto out_freecsr;
>>> @@ -1067,6 +1071,13 @@ int i915_driver_load(struct drm_device *dev,
>>> unsigned long flags)
>>>           goto out_power_well;
>>>       }
>>>
>>> +    if (intel_gvt_host_active(dev)) {
>>> +        if
>>> (!gvt_post_init_pgt_device(dev_priv->vgpu.host_private_data)) {
>>> +            DRM_ERROR("failed to post init pgt device\n");
>>> +            goto out_power_well;
>>> +        }
>>> +    }
>>> +
>>>       /*
>>>        * Notify a valid surface after modesetting,
>>>        * when running inside a VM.
>>> @@ -1117,6 +1128,10 @@ out_gtt:
>>>       i915_global_gtt_cleanup(dev);
>>>   out_freecsr:
>>>       intel_csr_ucode_fini(dev_priv);
>>> +    if (intel_gvt_host_active(dev)) {
>>> +        gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
>>> +        dev_priv->vgpu.host_private_data = NULL;
>>> +    }
>>>       intel_uncore_fini(dev);
>>>       pci_iounmap(dev->pdev, dev_priv->regs);
>>>   put_bridge:
>>> @@ -1165,6 +1180,10 @@ int i915_driver_unload(struct drm_device *dev)
>>>
>>>       intel_modeset_cleanup(dev);
>>>
>>> +    if (intel_gvt_host_active(dev)) {
>>> +        gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
>>> +        dev_priv->vgpu.host_private_data = NULL;
>>> +    }
>>>       /*
>>>        * free the memory space allocated for the child device
>>>        * config parsed from VBT
>>> diff --git a/drivers/gpu/drm/i915/i915_drv.h
>>> b/drivers/gpu/drm/i915/i915_drv.h
>>> index 01cc982..db3c79b 100644
>>> --- a/drivers/gpu/drm/i915/i915_drv.h
>>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>>> @@ -1673,6 +1673,7 @@ struct i915_workarounds {
>>>
>>>   struct i915_virtual_gpu {
>>>       bool active;
>>> +    void *host_private_data;
>>>   };
>>>
>>>   struct i915_execbuffer_params {
>>> @@ -2747,6 +2748,11 @@ static inline bool intel_vgpu_active(struct
>>> drm_device *dev)
>>>       return to_i915(dev)->vgpu.active;
>>>   }
>>>
>>> +static inline bool intel_gvt_host_active(struct drm_device *dev)
>>> +{
>>> +    return to_i915(dev)->vgpu.host_private_data ? true : false;
>>> +}
>>> +
>>>   void
>>>   i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe
>>> pipe,
>>>                u32 status_mask);
>>> diff --git a/drivers/gpu/drm/i915/i915_vgpu.h
>>> b/drivers/gpu/drm/i915/i915_vgpu.h
>>> index 3c83b47..942490a 100644
>>> --- a/drivers/gpu/drm/i915/i915_vgpu.h
>>> +++ b/drivers/gpu/drm/i915/i915_vgpu.h
>>> @@ -113,5 +113,8 @@ struct vgt_if {
>>>   extern void i915_check_vgpu(struct drm_device *dev);
>>>   extern int intel_vgt_balloon(struct drm_device *dev);
>>>   extern void intel_vgt_deballoon(void);
>>> +extern void *gvt_create_pgt_device(struct drm_i915_private *dev_priv);
>>> +extern bool gvt_post_init_pgt_device(void *private_data);
>>> +extern void gvt_destroy_pgt_device(void *private_data);
>>>
>>>   #endif /* _I915_VGPU_H_ */
>>> diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
>>> index d133112..78a38f1 100644
>>> --- a/include/xen/interface/xen.h
>>> +++ b/include/xen/interface/xen.h
>>> @@ -28,6 +28,7 @@
>>>   #define __XEN_PUBLIC_XEN_H__
>>>
>>>   #include
>>> +#include
>>>
>>>   /*
>>>    * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g
  2016-02-16  9:54       ` Zhi Wang
@ 2016-02-16 12:44         ` Jani Nikula
  2016-02-16 14:08         ` Joonas Lahtinen
  1 sibling, 0 replies; 49+ messages in thread
From: Jani Nikula @ 2016-02-16 12:44 UTC (permalink / raw)
  To: Zhi Wang, Joonas Lahtinen, intel-gfx, igvt-g
  Cc: daniel.vetter, david.j.cowperthwaite

On Tue, 16 Feb 2016, Zhi Wang <zhi.a.wang@intel.com> wrote:
> Hi Joonas:
>      For the debug function/macros, could we use DRM_DEBUG_DRIVER as 
> output, but keep our internal debug switch & marcos, like:
>
> #define gvt_dbg_xxx(xxx, xxx) \
> 	if (gvt_debug & xxx) \
> 		DRM_DEBUG_DRIVER(xxxxxx)
>
> Is it OK for the maintainers? Or we have to use DRM_DEBUG_DRIVER 
> directly :(.

Rather than introducing new debug macros of your own, I think I'd rather
see any combination of the following:

* DRM_DEBUG_*, DRM_ERROR, and friends.

* dev_dbg, dev_info, dev_err, and friends. See the dynamic debug
  facilities for fine grained control of what is printed.

* pr_debug, pr_info, pr_err, and friends. See pr_fmt for defining custom
  prefixes for what is printed.

BR,
Jani.


>
> Thanks,
> Zhi.
>
> 于 02/03/16 14:01, Zhi Wang wrote:
>> Hi Joonas:
>>      Thanks you very much! We're very excited for receiving your advice
>> and continue to be open to any comments. :)
>>
>> I'm supposed that we should make the agreements on i915 host change at
>> the very beginning, as I'm concerned during the discussion of i915 host
>> change, you know, maybe some code of GVT-g needs to be refined or
>> re-designed. So we put the i915 host changes to the beginning of the
>> patch set for the convenience of discussion.
>>
>> I summarize your comments as below, very applicate. :)
>>
>> - Replace boolean return value with int as much as possible.
>> - Replace customized debug ASSERT() function & macros with DRM_DEBUG_*
>> - Document all non-static functions like i915
>> - Fix all whitespace via scripts/cleanpatch.pl
>> - Commit function structure refinement.
>> - Change the register access behavior just like what i915 does.
>>
>> For other comments, see my comments below. :)
>>
>> On 01/29/16 21:57, Joonas Lahtinen wrote:
>>> Hi,
>>>
>>> TL;DR Overall, we have same problem as with the scheduler series, there
>>> is too much placeholder stuff for easy review. Just squash enough code
>>> into one commit so it actually does something logical that can be
>>> reviewed and then extend it later. Then it can be reviewed and pushed.
>>> Just splitting the code down to achieve smaller patches is not the
>>> right thing to do.
>>>
>>> Comments on the overall code: You need to document all header file
>>> functions (in the source files), and it is good to document the static
>>> functions within a file too, to make future maintenance easier.
>>>
>>> It is not about splitting the code down to small chunks, but splitting
>>> it down to small *logical* chunks. It doesn't make sense to commit
>>> dozens of empty bodied functions for review, and then later add their
>>> code.
>>>
>>> If you add functions, only add them at a patch that takes them into use
>>> too, unless we're talking about general purpose shared code. And also
>>> remember to add the function body and documentation header. If you
>>> simply add a "return 0;" or similar function body, do add a comment to
>>> why the function does not exist and when it will.
>>>
>>> Then, there is a trend of having a boolean return values in the code.
>>> When possible, it should rather be int and the cause for failure should
>>> be propagated from the last level all the way to up (-ENOMEN etc.).
>>> This way debugging becomes easier and if new error conditions appear,
>>> there is less of a maintenance burden to add the propagation later.
>>>
>>> Finally, make sure to look at the existing driver parts and
>>>     https://www.kernel.org/doc/Documentation/CodingStyle
>>> for proper coding style. There are lots of whitespace fixes needed in
>>> this series, like array initializations.
>>>
>>> I hope to see this first patch rerolled so that you squash some of the
>>> later commits into it so that all functions have a body and you add
>>> documentation for the functions so I can both see what it should do and
>>> what it actually does. Only reroll the first patch, to keep the
>>> iterative step smaller. Lets only then continue with the rest of the
>>> series once we've reached a consensus on the formatting and style
>>> basics.
>>>
>>> See more comments below.
>>>
>>> On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
>>>> This patch introduces the very basic framework of GVT-g device model,
>>>> includes basic prototypes, definitions, initialization.
>>>> ---
>>>>   arch/x86/include/asm/xen/interface.h  |   3 +
>>>>   drivers/gpu/drm/i915/Kconfig          |  16 ++
>>>>   drivers/gpu/drm/i915/Makefile         |   2 +
>>>>   drivers/gpu/drm/i915/gvt/Makefile     |   5 +
>>>>   drivers/gpu/drm/i915/gvt/debug.h      |  72 +++++++
>>>>   drivers/gpu/drm/i915/gvt/fb_decoder.c |  34 ++++
>>>>   drivers/gpu/drm/i915/gvt/fb_decoder.h | 110 ++++++++++
>>>>   drivers/gpu/drm/i915/gvt/gvt.c        | 366
>>>> ++++++++++++++++++++++++++++++++++
>>>>   drivers/gpu/drm/i915/gvt/gvt.h        | 130 ++++++++++++
>>>>   drivers/gpu/drm/i915/gvt/hypercall.h  |  30 +++
>>>>   drivers/gpu/drm/i915/gvt/mpt.h        |  97 +++++++++
>>>>   drivers/gpu/drm/i915/gvt/params.c     |  29 +++
>>>>   drivers/gpu/drm/i915/gvt/params.h     |  34 ++++
>>>>   drivers/gpu/drm/i915/gvt/reg.h        |  34 ++++
>>>>   drivers/gpu/drm/i915/i915_dma.c       |  19 ++
>>>>   drivers/gpu/drm/i915/i915_drv.h       |   6 +
>>>>   drivers/gpu/drm/i915/i915_vgpu.h      |   3 +
>>>>   include/xen/interface/xen.h           |   1 +
>>>>   18 files changed, 991 insertions(+)
>>>>   create mode 100644 drivers/gpu/drm/i915/gvt/Makefile
>>>>   create mode 100644 drivers/gpu/drm/i915/gvt/debug.h
>>>>   create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.c
>>>>   create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.h
>>>>   create mode 100644 drivers/gpu/drm/i915/gvt/gvt.c
>>>>   create mode 100644 drivers/gpu/drm/i915/gvt/gvt.h
>>>>   create mode 100644 drivers/gpu/drm/i915/gvt/hypercall.h
>>>>   create mode 100644 drivers/gpu/drm/i915/gvt/mpt.h
>>>>   create mode 100644 drivers/gpu/drm/i915/gvt/params.c
>>>>   create mode 100644 drivers/gpu/drm/i915/gvt/params.h
>>>>   create mode 100644 drivers/gpu/drm/i915/gvt/reg.h
>>>>
>>>> diff --git a/arch/x86/include/asm/xen/interface.h
>>>> b/arch/x86/include/asm/xen/interface.h
>>>> index 62ca03e..6ff4986 100644
>>>> --- a/arch/x86/include/asm/xen/interface.h
>>>> +++ b/arch/x86/include/asm/xen/interface.h
>>>> @@ -73,6 +73,9 @@
>>>>   #endif
>>>>
>>>>   #ifndef __ASSEMBLY__
>>>> +
>>>> +#include
>>>> +
>>>
>>> I don't follow why this would need to be added if the file is not
>>> modified otherwise. Each header should only include what they use.
>>>
>>> If this is an existing bug (that xen/interface.h can not be included
>>> without including linux/types.h), it should be split to a separate
>>> patch and sent to Xen team. Same for include/xen/interface/xen.h.
>>>
>>>>   /* Explicitly size integers that represent pfns in the public
>>>> interface
>>>>    * with Xen so that on ARM we can have one ABI that works for 32
>>>> and 64
>>>>    * bit guests. */
>>>> diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
>>>> index 051eab3..89ff723 100644
>>>> --- a/drivers/gpu/drm/i915/Kconfig
>>>> +++ b/drivers/gpu/drm/i915/Kconfig
>>>> @@ -47,3 +47,19 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT
>>>>         option changes the default for that module option.
>>>>
>>>>         If in doubt, say "N".
>>>> +
>>>> +config I915_GVT
>>>> +        tristate "GVT-g host driver"
>>>> +        depends on DRM_I915
>>>> +        select IRQ_WORK
>>>> +        default y
>>>
>>> Defaulting to "n" would make sense initially.
>>>
>> [Zhi] Sure, will do.
>>>> +        help
>>>> +          Enabling GVT-g mediated graphics passthrough technique for
>>>> Intel i915
>>>> +          based integrated graphics card. With GVT-g, it's possible
>>>> to have one
>>>> +          integrated i915 device shared by multiple VMs. Performance
>>>> critical
>>>> +          opterations such as apperture accesses and ring buffer
>>>> operations
>>>> +          are pass-throughed to VM, with a minimal set of
>>>> conflicting resources
>>>> +          (e.g. display settings) mediated by vGT driver. The
>>>> benefit of vGT
>>>> +          is on both the performance, given that each VM could
>>>> directly operate
>>>> +          its aperture space and submit commands like running on
>>>> native, and
>>>> +          the feature completeness, given that a true GEN hardware
>>>> is exposed.
>>>> diff --git a/drivers/gpu/drm/i915/Makefile
>>>> b/drivers/gpu/drm/i915/Makefile
>>>> index 0851de07..d4df410 100644
>>>> --- a/drivers/gpu/drm/i915/Makefile
>>>> +++ b/drivers/gpu/drm/i915/Makefile
>>>> @@ -91,6 +91,8 @@ i915-y += dvo_ch7017.o \
>>>>         intel_sdvo.o \
>>>>         intel_tv.o
>>>>
>>>> +obj-$(CONFIG_I915_GVT)  += gvt/
>>>> +
>>>>   # virtual gpu code
>>>>   i915-y += i915_vgpu.o
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/gvt/Makefile
>>>> b/drivers/gpu/drm/i915/gvt/Makefile
>>>> new file mode 100644
>>>> index 0000000..6935b78
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/gvt/Makefile
>>>> @@ -0,0 +1,5 @@
>>>> +GVT_SOURCE := gvt.o params.o fb_decoder.o
>>>> +
>>>> +ccflags-y            += -I$(src) -I$(src)/.. -Wall -Werror
>>>> -Wno-unused-function
>>>> +i915_gvt-y            := $(GVT_SOURCE)
>>>> +obj-$(CONFIG_I915_GVT)        += i915_gvt.o
>>>> diff --git a/drivers/gpu/drm/i915/gvt/debug.h
>>>> b/drivers/gpu/drm/i915/gvt/debug.h
>>>> new file mode 100644
>>>> index 0000000..18e1467
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/gvt/debug.h
>>>> @@ -0,0 +1,72 @@
>>>> +/*
>>>> + * Copyright(c) 2011-2016 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.
>>>> + */
>>>> +
>>>> +#ifndef __GVT_DEBUG_H__
>>>> +#define __GVT_DEBUG_H__
>>>> +
>>>> +#define
>>>> ASSERT(x)                                                       \
>>>> +        do
>>>> {                                                            \
>>>> +                if (!(x))
>>>> {                                             \
>>>> +                        printk("Assert at %s line
>>>> %d\n",                \
>>>> +                                __FILE__,
>>>> __LINE__);                    \
>>>> +
>>>> }                                                       \
>>>> +        } while (0);
>>>> +
>>>> +#define ASSERT_NUM(x,
>>>> y)                                                \
>>>> +        do
>>>> {                                                            \
>>>> +                if (!(x))
>>>> {                                             \
>>>> +                        printk("Assert at %s line %d para
>>>> 0x%llx\n",    \
>>>> +                                __FILE__, __LINE__,
>>>> (u64)y);            \
>>>> +
>>>> }                                                       \
>>>> +        } while (0);
>>>> +
>>>
>>> There already is WARN_ON (and i915_drv.h modifies it a little). Do not
>>> introduce custom functions like this, if the existing ones need
>>> improvement, improve them.
>>>
>> [Zhi] OK. Will do as what i915 does
>>>> +#define gvt_info(fmt, args...) \
>>>> +    printk(KERN_INFO"[GVT-g] "fmt"\n", ##args)
>>>> +
>>>> +#define gvt_err(fmt, args...) \
>>>> +    printk(KERN_ERR"%s() - %d: "fmt"\n", __func__, __LINE__, ##args)
>>>> +
>>>> +#define gvt_warn(fmt, args...) \
>>>> +    printk(KERN_WARNING"%s() - %d: "fmt"\n", __func__, __LINE__,
>>>> ##args)
>>>> +
>>>> +#define gvt_dbg(level, fmt, args...) do { \
>>>> +        if (gvt.debug & level) \
>>>> +            printk(KERN_DEBUG"%s() - %d: "fmt"\n", __func__,
>>>> __LINE__, ##args); \
>>>> +    }while(0)
>>>> +
>>>> +enum {
>>>> +    GVT_DBG_CORE = (1 << 0),
>>>> +    GVT_DBG_MM = (1 << 1),
>>>> +    GVT_DBG_IRQ = (1 << 2),
>>>> +};
>>>> +
>>>> +#define gvt_dbg_core(fmt, args...) \
>>>> +    gvt_dbg(GVT_DBG_CORE, fmt, ##args)
>>>> +
>>>> +#define gvt_dbg_mm(fmt, args...) \
>>>> +    gvt_dbg(GVT_DBG_MM, fmt, ##args)
>>>> +
>>>> +#define gvt_dbg_irq(fmt, args...) \
>>>> +    gvt_dbg(GVT_DBG_IRQ, fmt, ##args)
>>>> +
>>>> +#endif
>>>
>>> This should be integrated better to DRM debugging options, custom
>>> debugging code only for i915 was rejected a while ago.
>>>
>> [ZHI] Thanks for sharing the history. :) Will change that.
>>>> diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c
>>>> b/drivers/gpu/drm/i915/gvt/fb_decoder.c
>>>> new file mode 100644
>>>> index 0000000..a219819
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c
>>>> @@ -0,0 +1,34 @@
>>>> +/*
>>>> + * Copyright(c) 2011-2016 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 "gvt.h"
>>>> +
>>>> +int gvt_decode_fb_format(struct pgt_device *pdev, int vmid, struct
>>>> gvt_fb_format *fb)
>>>> +{
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +int gvt_fb_notifier_call_chain(unsigned long val, void *data)
>>>> +{
>>>> +    return 0;
>>>> +}
>>>
>>> Kerneldoc missing for these functions. It is all the same to squash
>>> later patches to introduce the code to these functions already,
>>> reviewing utility functions with no kerneldoc and no body makes it
>>> somewhat difficult to see the big picture.
>>>
>>
>> [Zhi] One question. I saw i915 put some function instruction in *.c. Is
>> it also OK for kernel doc generating the proper doc files?
>>
>>>> diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.h
>>>> b/drivers/gpu/drm/i915/gvt/fb_decoder.h
>>>> new file mode 100644
>>>> index 0000000..2c29ed4
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.h
>>>> @@ -0,0 +1,110 @@
>>>> +/*
>>>> + * Copyright(c) 2011-2016 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.
>>>> + */
>>>> +
>>>> +#ifndef _GVT_FB_DECODER_H_
>>>> +#define _GVT_FB_DECODER_H_
>>>> +
>>>> +typedef enum {
>>>> +    FB_MODE_SET_START = 1,
>>>> +    FB_MODE_SET_END,
>>>> +    FB_DISPLAY_FLIP,
>>>> +}gvt_fb_event_t;
>>>> +
>>>> +typedef enum {
>>>> +    DDI_PORT_NONE    = 0,
>>>> +    DDI_PORT_B    = 1,
>>>> +    DDI_PORT_C    = 2,
>>>> +    DDI_PORT_D    = 3,
>>>> +    DDI_PORT_E    = 4
>>>> +} ddi_port_t;
>>>> +
>>>> +struct pgt_device;
>>>> +
>>>> +struct gvt_fb_notify_msg {
>>>> +    unsigned vm_id;
>>>> +    unsigned pipe_id; /* id starting from 0 */
>>>> +    unsigned plane_id; /* primary, cursor, or sprite */
>>>> +};
>>>> +
>>>> +/* color space conversion and gamma correction are not included */
>>>> +struct gvt_primary_plane_format {
>>>> +    u8    enabled;    /* plane is enabled */
>>>> +    u8    tiled;        /* X-tiled */
>>>> +    u8    bpp;        /* bits per pixel */
>>>> +    u32    hw_format;    /* format field in the PRI_CTL register */
>>>> +    u32    drm_format;    /* format in DRM definition */
>>>> +    u32    base;        /* framebuffer base in graphics memory */
>>>> +    u32    x_offset;    /* in pixels */
>>>> +    u32    y_offset;    /* in lines */
>>>> +    u32    width;        /* in pixels */
>>>> +    u32    height;        /* in lines */
>>>> +    u32    stride;        /* in bytes */
>>>> +};
>>>> +
>>>> +struct gvt_sprite_plane_format {
>>>> +    u8    enabled;    /* plane is enabled */
>>>> +    u8    tiled;        /* X-tiled */
>>>> +    u8    bpp;        /* bits per pixel */
>>>> +    u32    hw_format;    /* format field in the SPR_CTL register */
>>>> +    u32    drm_format;    /* format in DRM definition */
>>>> +    u32    base;        /* sprite base in graphics memory */
>>>> +    u32    x_pos;        /* in pixels */
>>>> +    u32    y_pos;        /* in lines */
>>>> +    u32    x_offset;    /* in pixels */
>>>> +    u32    y_offset;    /* in lines */
>>>> +    u32    width;        /* in pixels */
>>>> +    u32    height;        /* in lines */
>>>> +};
>>>> +
>>>> +struct gvt_cursor_plane_format {
>>>> +    u8    enabled;
>>>> +    u8    mode;        /* cursor mode select */
>>>> +    u8    bpp;        /* bits per pixel */
>>>> +    u32    drm_format;    /* format in DRM definition */
>>>> +    u32    base;        /* cursor base in graphics memory */
>>>> +    u32    x_pos;        /* in pixels */
>>>> +    u32    y_pos;        /* in lines */
>>>> +    u8    x_sign;        /* X Position Sign */
>>>> +    u8    y_sign;        /* Y Position Sign */
>>>> +    u32    width;        /* in pixels */
>>>> +    u32    height;        /* in lines */
>>>> +    u32    x_hot;        /* in pixels */
>>>> +    u32    y_hot;        /* in pixels */
>>>> +};
>>>> +
>>>
>>> The above structs have a lot in common, would it make sense to have the
>>> common members + plane type and then union for the plane type specific
>>> data. I suspect having it all split this way will lead to more utility
>>> functions somewhere.
>>>
>> [Zhi] Thanks. Will do that.
>>
>>>> +struct gvt_pipe_format {
>>>> +    struct gvt_primary_plane_format    primary;
>>>> +    struct gvt_sprite_plane_format    sprite;
>>>> +    struct gvt_cursor_plane_format    cursor;
>>>> +    ddi_port_t ddi_port;  /* the DDI port that the pipe is connected
>>>> to */
>>>> +};
>>>> +
>>>> +struct gvt_fb_format{
>>>> +    struct gvt_pipe_format    pipes[I915_MAX_PIPES];
>>>> +};
>>>> +
>>>> +extern int gvt_fb_notifier_call_chain(unsigned long val, void *data);
>>>> +extern int gvt_decode_fb_format(struct pgt_device *pdev, int vmid,
>>>> +                struct gvt_fb_format *fb);
>>>> +
>>>> +#endif
>>>> diff --git a/drivers/gpu/drm/i915/gvt/gvt.c
>>>> b/drivers/gpu/drm/i915/gvt/gvt.c
>>>> new file mode 100644
>>>> index 0000000..041d10f
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/gvt/gvt.c
>>>> @@ -0,0 +1,366 @@
>>>> +/*
>>>> + * Copyright(c) 2011-2016 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
>>>> +#include
>>>> +
>>>> +#include "gvt.h"
>>>> +
>>>> +struct gvt_host gvt_host;
>>>> +
>>>> +extern struct gvt_kernel_dm xengt_kdm;
>>>> +extern struct gvt_kernel_dm kvmgt_kdm;
>>>> +
>>>> +static const char *supported_hypervisors[] = {
>>>
>>> should be "static const char * const".
>>>
>>>> +    [GVT_HYPERVISOR_TYPE_XEN] = "Xen Hypervisor",
>>>> +    [GVT_HYPERVISOR_TYPE_KVM] = "KVM",
>>>> +};
>>>> +
>>>> +static bool gvt_init_host(void)
>>>> +{
>>>> +    struct gvt_host *host = &gvt_host;
>>>> +
>>>> +    if (!gvt.enable) {
>>>> +        gvt_dbg_core("GVT-g has been disabled by kernel parameter");
>>>> +        return false;
>>>> +    }
>>>> +
>>>> +    if (host->initialized) {
>>>> +        gvt_err("GVT-g has already been initialized!");
>>>> +        return false;
>>>> +    }
>>>> +
>>>> +    if (xen_initial_domain()) {
>>>
>>> Shouldn't Xen code be CONFIG_XEN_DOM0 and CONFIG_XEN #ifdef protected?
>>>
>> [Zhi] The following code piece shows xen_initial_domain()/xen_domain()
>> could also be used when CONFIG_XEN_DOM0 is not set.
>>
>> #ifdef CONFIG_XEN
>> extern enum xen_domain_type xen_domain_type;
>> #else
>> #define xen_domain_type         XEN_NATIVE
>> #endif
>>
>> #define xen_domain()            (xen_domain_type != XEN_NATIVE)
>> #define xen_pv_domain()         (xen_domain() &&                        \
>>                                   xen_domain_type == XEN_PV_DOMAIN)
>> #define xen_hvm_domain()        (xen_domain() &&                        \
>>                                   xen_domain_type == XEN_HVM_DOMAIN)
>>
>> #ifdef CONFIG_XEN_DOM0
>> #include <xen/interface/xen.h>
>> #include <asm/xen/hypervisor.h>
>>
>> #define xen_initial_domain()    (xen_domain() && \
>>                                   xen_start_info &&
>> xen_start_info->flags & SIF_INITDOMAIN)
>> #else  /* !CONFIG_XEN_DOM0 */
>> #define xen_initial_domain()    (0)
>> #endif  /* CONFIG_XEN_DOM0 */
>>
>>>> +        /* Xen Dom0 */
>>>> +        host->kdm = try_then_request_module(symbol_get(xengt_kdm),
>>>> "xengt");
>>>> +        host->hypervisor_type = GVT_HYPERVISOR_TYPE_XEN;
>>>> +    } else if(xen_domain()) {
>>>> +        /* Xen DomU */
>>>> +        return false;
>>>> +    } else {
>>>> +        /* not in Xen. Try KVMGT */
>>>> +        host->kdm = try_then_request_module(symbol_get(kvmgt_kdm),
>>>> "kvm");
>>>> +        host->hypervisor_type = GVT_HYPERVISOR_TYPE_KVM;
>>>> +    }
>>>> +
>>>
>>> Why do we need to keep track of hypervisor type, are there plenty of
>>> hypervisor specific behaviour differences?
>>
>> [Zhi] As GVT-g needs some hypervisor services to work, we write a
>> abstraction layer to connect GVT-g to different hypervisor. But still
>> there are some emulation logic couldn't be fitted into that abstraction
>> layer, like OpRegion emulation. In Xen, we emulates it in kernel space,
>> while we emulates it in Qemu under KVM. I also agreed that we should
>> find some approach to improve it just like what you said.
>>
>> If it is just for printing
>>> the below debug, I think it's better to move the debug into above code
>>> that detects the hypervisor, wrap them with appropriate CONFIG #ifdefs.
>>>
>>>> +    if (!host->kdm)
>>>> +        return false;
>>>> +
>>>> +    if (!hypervisor_detect_host())
>>>> +        return false;
>>>> +
>>>> +    gvt_info("Running with hypervisor %s in host mode",
>>>> +            supported_hypervisors[host->hypervisor_type]);
>>>> +
>>>> +    idr_init(&host->device_idr);
>>>> +    mutex_init(&host->device_idr_lock);
>>>> +
>>>> +    host->initialized = true;
>>>> +    return true;
>>>> +}
>>>> +
>>>> +static bool init_device_info(struct pgt_device *pdev)
>>>> +{
>>>> +    struct gvt_device_info *info = &pdev->device_info;
>>>> +
>>>> +    if (!IS_BROADWELL(pdev->dev_priv)) {
>>>> +        gvt_err("Unsupported GEN device");
>>>> +        return false;
>>>> +    }
>>>> +
>>>> +    if (IS_BROADWELL(pdev->dev_priv)) {
>>>> +        info->max_gtt_gm_sz = (1UL << 32);
>>>> +        /*
>>>> +         * The layout of BAR0 in BDW:
>>>> +         * |< - MMIO 2MB ->|<- Reserved 6MB ->|<- MAX GTT 8MB->|
>>>> +         *
>>>> +         * GTT offset in BAR0 starts from 8MB to 16MB, and
>>>> +         * Whatever GTT size is configured in BIOS,
>>>> +         * the size of BAR0 is always 16MB. The actual configured
>>>> +         * GTT size can be found in GMCH_CTRL.
>>>> +         */
>>>> +        info->gtt_start_offset = (1UL << 23);
>>>> +        info->max_gtt_size = (1UL << 23);
>>>> +        info->gtt_entry_size = 8;
>>>> +        info->gtt_entry_size_shift = 3;
>>>> +        info->gmadr_bytes_in_cmd = 8;
>>>
>>> Would this information be useful in a header as #defines too?
>>>
>> [Zhi] Probably. Consider that one GVT-g featured kernel could be able to
>> run on different platforms, the informaion data structure could be
>> different. But I agree to define the magic numbers in a header files. :)
>>
>>>> +    }
>>>> +
>>>> +    gvt_info("Device info:");
>>>> +    printk("        max_gtt_gm_sz: %llx\n", info->max_gtt_gm_sz);
>>>> +    printk("        max_gtt_size: %x\n", info->max_gtt_size);
>>>> +    printk("        gtt_size_entry: %x\n", info->gtt_entry_size);
>>>> +    printk("        gtt_entry_size_shift: %x\n",
>>>> info->gtt_entry_size_shift);
>>>> +    printk("        gtt_start_offset: %x\n", info->gtt_start_offset);
>>>> +    printk("        gtt_end_offset: %x\n", info->gtt_end_offset);
>>>> +
>>>
>>> Just put this to kind of stuff to i915_debugfs.c.
>>>
>> [Zhi] Thanks.
>>
>>>> +    return true;
>>>> +}
>>>> +
>>>> +static void init_initial_cfg_space_state(struct pgt_device *pdev)
>>>> +{
>>>> +    struct pci_dev *pci_dev = pdev->dev_priv->dev->pdev;
>>>> +    int i;
>>>> +
>>>> +    gvt_dbg_core("init initial cfg space, id %d", pdev->id);
>>>> +
>>>> +    for (i = 0; i < GVT_CFG_SPACE_SZ; i += 4)
>>>
>>> += sizeof(...)
>>>
>>>> +        pci_read_config_dword(pci_dev, i,
>>>> +                (u32 *)&pdev->initial_cfg_space[i]);
>>>> +
>>>> +    for (i = 0; i < 3; i++) {
>>>
>>> No magic numbers make a #define for 3 and give it a descriptive name.
>>>
>>>> +        pdev->bar_size[i] = pci_resource_len(pci_dev, i * 2);
>>>> +        gvt_info("bar %d size: %llx", i, pdev->bar_size[i]);
>>>> +    }
>>>> +}
>>>> +
>>>> +static void clean_initial_mmio_state(struct pgt_device *pdev)
>>>> +{
>>>> +    if (pdev->gttmmio_va) {
>>>> +        iounmap(pdev->gttmmio_va);
>>>> +        pdev->gttmmio_va = NULL;
>>>> +    }
>>>> +
>>>> +    if (pdev->gmadr_va) {
>>>> +        iounmap(pdev->gmadr_va);
>>>> +        pdev->gmadr_va = NULL;
>>>> +    }
>>>> +}
>>>> +
>>>> +static bool init_initial_mmio_state(struct pgt_device *pdev)
>>>> +{
>>>> +    u64 bar0, bar1;
>>>> +
>>>> +    gvt_dbg_core("init initial mmio state, id %d", pdev->id);
>>>> +
>>>> +    bar0 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR0];
>>>> +    bar1 = *(u64 *)&pdev->initial_cfg_space[GVT_REG_CFG_SPACE_BAR1];
>>>> +
>>>> +    pdev->gttmmio_base = bar0 & ~0xf;
>>>> +    pdev->mmio_size = 2 * 1024 * 1024;
>>>> +    pdev->reg_num = pdev->mmio_size / 4;
>>>> +    pdev->gmadr_base = bar1 & ~0xf;
>>>> +
>>>
>>> Many magic numbers.
>>>
>>>> +    pdev->gttmmio_va = ioremap(pdev->gttmmio_base, pdev->bar_size[0]);
>>>> +    if (!pdev->gttmmio_va) {
>>>> +        gvt_err("fail to map GTTMMIO BAR.");
>>>
>>> These should be if(WARN_ON(...))
>>>
>>>> +        return false;
>>>> +    }
>>>> +
>>>> +    pdev->gmadr_va = ioremap(pdev->gmadr_base, pdev->bar_size[2]);
>>>> +    if (!pdev->gmadr_va) {
>>>> +        gvt_err("fail to map GMADR BAR.");
>>>> +        goto err;
>>>> +    }
>>>> +
>>>> +    gvt_info("bar0: 0x%llx, bar1: 0x%llx", bar0, bar1);
>>>> +    gvt_info("mmio size: %x", pdev->mmio_size);
>>>> +    gvt_info("gttmmio: 0x%llx, gmadr: 0x%llx", pdev->gttmmio_base,
>>>> pdev->gmadr_base);
>>>> +    gvt_info("gttmmio_va: %p", pdev->gttmmio_va);
>>>> +    gvt_info("gmadr_va: %p", pdev->gmadr_va);
>>>> +
>>>> +    return true;
>>>> +err:
>>>> +    clean_initial_mmio_state(pdev);
>>>> +    return false;
>>>> +}
>>>> +
>>>> +static int gvt_service_thread(void *data)
>>>> +{
>>>> +    struct pgt_device *pdev = (struct pgt_device *)data;
>>>> +    int r;
>>>> +
>>>> +    gvt_dbg_core("service thread start, pgt %d", pdev->id);
>>>> +
>>>> +    while(!kthread_should_stop()) {
>>>> +        r = wait_event_interruptible(pdev->service_thread_wq,
>>>> +                kthread_should_stop() || pdev->service_request);
>>>> +
>>>> +        if (kthread_should_stop())
>>>> +            break;
>>>> +
>>>> +        if (r) {
>>>> +            gvt_warn("service thread is waken up by unexpected
>>>> signal.");
>>>
>>> Should be WARN_ONCE, to avoid future disasters with CI.
>>>
>> [Zhi] Thanks.
>>>> +            continue;
>>>> +        }
>>>> +    }
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static void clean_service_thread(struct pgt_device *pdev)
>>>> +{
>>>> +    if (pdev->service_thread) {
>>>> +        kthread_stop(pdev->service_thread);
>>>> +        pdev->service_thread = NULL;
>>>> +    }
>>>> +}
>>>> +
>>>> +static bool init_service_thread(struct pgt_device *pdev)
>>>> +{
>>>> +    init_waitqueue_head(&pdev->service_thread_wq);
>>>> +
>>>> +    pdev->service_thread = kthread_run(gvt_service_thread,
>>>> +            pdev, "gvt_service_thread%d", pdev->id);
>>>> +
>>>> +    if (!pdev->service_thread) {
>>>> +        gvt_err("fail to start service thread.");
>>>> +        return false;
>>>> +    }
>>>> +
>>>> +    return true;
>>>> +}
>>>> +
>>>> +static void clean_pgt_device(struct pgt_device *pdev)
>>>> +{
>>>> +    clean_service_thread(pdev);
>>>> +    clean_initial_mmio_state(pdev);
>>>> +}
>>>> +
>>>> +static bool init_pgt_device(struct pgt_device *pdev, struct
>>>> drm_i915_private *dev_priv)
>>>> +{
>>>> +    if (!init_device_info(pdev))
>>>> +        return false;
>>>> +
>>>> +    init_initial_cfg_space_state(pdev);
>>>> +
>>>> +    if (!init_initial_mmio_state(pdev))
>>>> +        goto err;
>>>> +
>>>> +    if (!init_service_thread(pdev))
>>>> +        goto err;
>>>> +
>>>> +    return true;
>>>> +err:
>>>> +    clean_pgt_device(pdev);
>>>> +    return false;
>>>> +}
>>>> +
>>>> +static bool post_init_pgt_device(struct pgt_device *pdev)
>>>> +{
>>>> +    return true;
>>>> +}
>>>> +
>>>> +static void free_pgt_device(struct pgt_device *pdev)
>>>> +{
>>>> +    struct gvt_host *host = &gvt_host;
>>>> +
>>>> +    mutex_lock(&host->device_idr_lock);
>>>> +    idr_remove(&host->device_idr, pdev->id);
>>>> +    mutex_unlock(&host->device_idr_lock);
>>>> +
>>>> +    vfree(pdev);
>>>> +}
>>>> +
>>>> +static struct pgt_device *alloc_pgt_device(struct drm_i915_private
>>>> *dev_priv)
>>>> +{
>>>> +    struct gvt_host *host = &gvt_host;
>>>> +    struct pgt_device *pdev = NULL;
>>>> +
>>>> +    pdev = vzalloc(sizeof(*pdev));
>>>> +    if (!pdev) {
>>>> +        gvt_err("fail to allocate memory for pgt device.");
>>>> +        return NULL;
>>>> +    }
>>>> +
>>>> +    mutex_lock(&host->device_idr_lock);
>>>> +    pdev->id = idr_alloc(&host->device_idr, pdev, 0, 0, GFP_KERNEL);
>>>> +    mutex_unlock(&host->device_idr_lock);
>>>> +
>>>> +    if (pdev->id < 0) {
>>>> +        gvt_err("fail to allocate pgt device id.");
>>>> +        goto err;
>>>> +    }
>>>> +
>>>> +    mutex_init(&pdev->lock);
>>>> +    pdev->dev_priv = dev_priv;
>>>> +    idr_init(&pdev->instance_idr);
>>>> +
>>>> +    return pdev;
>>>> +err:
>>>> +    free_pgt_device(pdev);
>>>> +    return NULL;
>>>> +}
>>>> +
>>>> +void gvt_destroy_pgt_device(void *private_data)
>>>> +{
>>>> +    struct pgt_device *pdev = (struct pgt_device *)private_data;
>>>> +
>>>> +    clean_pgt_device(pdev);
>>>> +    free_pgt_device(pdev);
>>>> +}
>>>> +
>>>> +void *gvt_create_pgt_device(struct drm_i915_private *dev_priv)
>>>> +{
>>>> +    struct pgt_device *pdev = NULL;
>>>> +    struct gvt_host *host = &gvt_host;
>>>> +
>>>> +    if (!host->initialized && !gvt_init_host()) {
>>>> +        gvt_err("gvt_init_host fail");
>>>> +        return NULL;
>>>> +    }
>>>> +
>>>> +    gvt_dbg_core("create new pgt device, i915 dev_priv: %p", dev_priv);
>>>> +
>>>> +    pdev = alloc_pgt_device(dev_priv);
>>>> +    if (!pdev) {
>>>> +        gvt_err("fail to allocate memory for pgt device.");
>>>> +        goto err;
>>>> +    }
>>>> +
>>>> +    gvt_dbg_core("init pgt device, id %d", pdev->id);
>>>> +
>>>> +    if (!init_pgt_device(pdev, dev_priv)) {
>>>> +        gvt_err("fail to init physical device state.");
>>>> +        goto err;
>>>> +    }
>>>> +
>>>> +    gvt_dbg_core("pgt device creation done, id %d", pdev->id);
>>>> +
>>>> +    return pdev;
>>>> +err:
>>>> +    if (pdev) {
>>>> +        gvt_destroy_pgt_device(pdev);
>>>> +        pdev = NULL;
>>>> +    }
>>>> +    return NULL;
>>>> +}
>>>> +
>>>> +bool gvt_post_init_pgt_device(void *private_data)
>>>> +{
>>>> +    struct pgt_device *pdev = (struct pgt_device *)private_data;
>>>> +    struct gvt_host *host = &gvt_host;
>>>> +
>>>> +    if (!host->initialized) {
>>>> +        gvt_err("gvt_host haven't been initialized.");
>>>> +        return false;
>>>> +    }
>>>> +
>>>> +    gvt_dbg_core("post init pgt device %d", pdev->id);
>>>> +
>>>> +    if (!post_init_pgt_device(pdev)) {
>>>> +        gvt_err("fail to post init physical device state.");
>>>> +        return false;
>>>> +    }
>>>> +
>>>> +    return true;
>>>> +}
>>>> diff --git a/drivers/gpu/drm/i915/gvt/gvt.h
>>>> b/drivers/gpu/drm/i915/gvt/gvt.h
>>>> new file mode 100644
>>>> index 0000000..6c85bba
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/gvt/gvt.h
>>>> @@ -0,0 +1,130 @@
>>>> +/*
>>>> + * Copyright(c) 2011-2016 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.
>>>> + */
>>>> +
>>>> +#ifndef _GVT_H_
>>>> +#define _GVT_H_
>>>> +
>>>> +#include "i915_drv.h"
>>>> +#include "i915_vgpu.h"
>>>> +
>>>> +#include "debug.h"
>>>> +#include "params.h"
>>>> +#include "reg.h"
>>>> +#include "hypercall.h"
>>>> +#include "mpt.h"
>>>> +#include "fb_decoder.h"
>>>> +
>>>> +#define GVT_MAX_VGPU 8
>>>> +
>>>> +enum {
>>>> +    GVT_HYPERVISOR_TYPE_XEN = 0,
>>>> +    GVT_HYPERVISOR_TYPE_KVM,
>>>> +};
>>>> +
>>>> +struct gvt_host {
>>>> +    bool initialized;
>>>> +    int hypervisor_type;
>>>> +    struct mutex device_idr_lock;
>>>> +    struct idr device_idr;
>>>> +    struct gvt_kernel_dm *kdm;
>>>> +};
>>>> +
>>>> +extern struct gvt_host gvt_host;
>>>> +
>>>> +/* Describe the limitation of HW.*/
>>>> +struct gvt_device_info {
>>>> +    u64 max_gtt_gm_sz;
>>>> +    u32 gtt_start_offset;
>>>> +    u32 gtt_end_offset;
>>>> +    u32 max_gtt_size;
>>>> +    u32 gtt_entry_size;
>>>> +    u32 gtt_entry_size_shift;
>>>> +    u32 gmadr_bytes_in_cmd;
>>>> +};
>>>> +
>>>> +struct vgt_device {
>>>> +    int id;
>>>> +    int vm_id;
>>>> +    struct pgt_device *pdev;
>>>> +    bool warn_untrack;
>>>> +};
>>>> +
>>>> +struct pgt_device {
>>>> +    struct mutex lock;
>>>> +    int id;
>>>> +
>>>> +    struct drm_i915_private *dev_priv;
>>>> +    struct idr instance_idr;
>>>> +
>>>> +    struct gvt_device_info device_info;
>>>> +
>>>> +    u8 initial_cfg_space[GVT_CFG_SPACE_SZ];
>>>> +    u64 bar_size[GVT_BAR_NUM];
>>>> +
>>>> +    u64 gttmmio_base;
>>>> +    void *gttmmio_va;
>>>> +
>>>> +    u64 gmadr_base;
>>>> +    void *gmadr_va;
>>>> +
>>>> +    u32 mmio_size;
>>>> +    u32 reg_num;
>>>> +
>>>> +    wait_queue_head_t service_thread_wq;
>>>> +    struct task_struct *service_thread;
>>>> +    unsigned long service_request;
>>>> +};
>>>> +
>>>
>>> Here-->
>>>
>>>> +static inline u32 gvt_mmio_read(struct pgt_device *pdev,
>>>> +        u32 reg)
>>>> +{
>>>> +    struct drm_i915_private *dev_priv = pdev->dev_priv;
>>>> +    i915_reg_t tmp = {.reg = reg};
>>>> +    return I915_READ(tmp);
>>>> +}
>>>> +
>>>> +static inline void gvt_mmio_write(struct pgt_device *pdev,
>>>> +        u32 reg, u32 val)
>>>> +{
>>>> +    struct drm_i915_private *dev_priv = pdev->dev_priv;
>>>> +    i915_reg_t tmp = {.reg = reg};
>>>> +    I915_WRITE(tmp, val);
>>>> +}
>>>> +
>>>> +static inline u64 gvt_mmio_read64(struct pgt_device *pdev,
>>>> +        u32 reg)
>>>> +{
>>>> +    struct drm_i915_private *dev_priv = pdev->dev_priv;
>>>> +    i915_reg_t tmp = {.reg = reg};
>>>> +    return I915_READ64(tmp);
>>>> +}
>>>> +
>>>> +static inline void gvt_mmio_write64(struct pgt_device *pdev,
>>>> +        u32 reg, u64 val)
>>>> +{
>>>> +    struct drm_i915_private *dev_priv = pdev->dev_priv;
>>>> +    i915_reg_t tmp = {.reg = reg};
>>>> +    I915_WRITE64(tmp, val);
>>>> +}
>>>> +
>>>
>>> <-- Why? The i915_reg_t type was added to avoid problems, this code is
>>> not used anywhere, and it has no documentation, so I can not review it.
>>>
>>> I wrote comments at the top of the post.
>>>
>> [Zhi] Thanks, I will check that.
>>
>>> Regards, Joonas
>>>
>>>> +#endif
>>>> diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h
>>>> b/drivers/gpu/drm/i915/gvt/hypercall.h
>>>> new file mode 100644
>>>> index 0000000..0a41874
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/gvt/hypercall.h
>>>> @@ -0,0 +1,30 @@
>>>> +/*
>>>> + * Copyright(c) 2011-2016 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.
>>>> + */
>>>> +
>>>> +#ifndef _GVT_HYPERCALL_H_
>>>> +#define _GVT_HYPERCALL_H_
>>>> +
>>>> +struct gvt_kernel_dm {
>>>> +};
>>>> +
>>>> +#endif /* _GVT_HYPERCALL_H_ */
>>>> diff --git a/drivers/gpu/drm/i915/gvt/mpt.h
>>>> b/drivers/gpu/drm/i915/gvt/mpt.h
>>>> new file mode 100644
>>>> index 0000000..bbe4465
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/gvt/mpt.h
>>>> @@ -0,0 +1,97 @@
>>>> +/*
>>>> + * Copyright(c) 2011-2016 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.
>>>> + */
>>>> +
>>>> +#ifndef _GVT_MPT_H_
>>>> +#define _GVT_MPT_H_
>>>> +
>>>> +struct vgt_device;
>>>> +
>>>> +static inline unsigned long hypervisor_g2m_pfn(struct vgt_device *vgt,
>>>> +    unsigned long g_pfn)
>>>> +{
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static inline int hypervisor_pause_domain(struct vgt_device *vgt)
>>>> +{
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static inline int hypervisor_shutdown_domain(struct vgt_device *vgt)
>>>> +{
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static inline int hypervisor_set_trap_area(struct vgt_device *vgt,
>>>> +    uint64_t start, uint64_t end, bool map)
>>>> +{
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static inline bool hypervisor_detect_host(void)
>>>> +{
>>>> +    return false;
>>>> +}
>>>> +
>>>> +static inline int hypervisor_virt_to_mfn(void *addr)
>>>> +{
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static inline void *hypervisor_mfn_to_virt(int mfn)
>>>> +{
>>>> +    return NULL;
>>>> +}
>>>> +
>>>> +static inline void hypervisor_inject_msi(struct vgt_device *vgt)
>>>> +{
>>>> +    return;
>>>> +}
>>>> +
>>>> +static inline int hypervisor_hvm_init(struct vgt_device *vgt)
>>>> +{
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static inline void hypervisor_hvm_exit(struct vgt_device *vgt)
>>>> +{
>>>> +}
>>>> +
>>>> +static inline void *hypervisor_gpa_to_va(struct vgt_device *vgt,
>>>> unsigned long gpa)
>>>> +{
>>>> +    return NULL;
>>>> +}
>>>> +
>>>> +static inline bool hypervisor_read_va(struct vgt_device *vgt, void *va,
>>>> +        void *val, int len, int atomic)
>>>> +{
>>>> +    return false;
>>>> +}
>>>> +
>>>> +static inline bool hypervisor_write_va(struct vgt_device *vgt, void
>>>> *va,
>>>> +        void *val, int len, int atomic)
>>>> +{
>>>> +    return false;
>>>> +}
>>>> +
>>>> +#endif /* _GVT_MPT_H_ */
>>>> diff --git a/drivers/gpu/drm/i915/gvt/params.c
>>>> b/drivers/gpu/drm/i915/gvt/params.c
>>>> new file mode 100644
>>>> index 0000000..dfc33c3
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/gvt/params.c
>>>> @@ -0,0 +1,29 @@
>>>> +/*
>>>> + * Copyright(c) 2011-2016 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 "gvt.h"
>>>> +
>>>> +struct gvt_kernel_params gvt = {
>>>> +    .enable = true,
>>>> +    .debug = 0,
>>>> +};
>>>> diff --git a/drivers/gpu/drm/i915/gvt/params.h
>>>> b/drivers/gpu/drm/i915/gvt/params.h
>>>> new file mode 100644
>>>> index 0000000..d2955b9
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/gvt/params.h
>>>> @@ -0,0 +1,34 @@
>>>> +/*
>>>> + * Copyright(c) 2011-2016 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.
>>>> + */
>>>> +
>>>> +#ifndef _GVT_PARAMS_H_
>>>> +#define _GVT_PARAMS_H_
>>>> +
>>>> +struct gvt_kernel_params {
>>>> +    bool enable;
>>>> +    int debug;
>>>> +};
>>>> +
>>>> +extern struct gvt_kernel_params gvt;
>>>> +
>>>> +#endif
>>>> diff --git a/drivers/gpu/drm/i915/gvt/reg.h
>>>> b/drivers/gpu/drm/i915/gvt/reg.h
>>>> new file mode 100644
>>>> index 0000000..d363b74
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/i915/gvt/reg.h
>>>> @@ -0,0 +1,34 @@
>>>> +/*
>>>> + * Copyright(c) 2011-2016 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.
>>>> + */
>>>> +
>>>> +#ifndef _GVT_REG_H
>>>> +#define _GVT_REG_H
>>>> +
>>>> +#define GVT_CFG_SPACE_SZ    256
>>>> +#define GVT_BAR_NUM        4
>>>> +
>>>> +#define GVT_REG_CFG_SPACE_BAR0    0x10
>>>> +#define GVT_REG_CFG_SPACE_BAR1    0x18
>>>> +#define GVT_REG_CFG_SPACE_BAR2    0x20
>>>> +
>>>> +#endif
>>>> diff --git a/drivers/gpu/drm/i915/i915_dma.c
>>>> b/drivers/gpu/drm/i915/i915_dma.c
>>>> index 4725e8d..eca8e50 100644
>>>> --- a/drivers/gpu/drm/i915/i915_dma.c
>>>> +++ b/drivers/gpu/drm/i915/i915_dma.c
>>>> @@ -943,6 +943,10 @@ int i915_driver_load(struct drm_device *dev,
>>>> unsigned long flags)
>>>>
>>>>       intel_uncore_init(dev);
>>>>
>>>> +    dev_priv->vgpu.host_private_data = gvt_create_pgt_device(dev_priv);
>>>> +    if(intel_gvt_host_active(dev))
>>>> +        DRM_INFO("GVT-g is running in host mode\n");
>>>> +
>>>>       ret = i915_gem_gtt_init(dev);
>>>>       if (ret)
>>>>           goto out_freecsr;
>>>> @@ -1067,6 +1071,13 @@ int i915_driver_load(struct drm_device *dev,
>>>> unsigned long flags)
>>>>           goto out_power_well;
>>>>       }
>>>>
>>>> +    if (intel_gvt_host_active(dev)) {
>>>> +        if
>>>> (!gvt_post_init_pgt_device(dev_priv->vgpu.host_private_data)) {
>>>> +            DRM_ERROR("failed to post init pgt device\n");
>>>> +            goto out_power_well;
>>>> +        }
>>>> +    }
>>>> +
>>>>       /*
>>>>        * Notify a valid surface after modesetting,
>>>>        * when running inside a VM.
>>>> @@ -1117,6 +1128,10 @@ out_gtt:
>>>>       i915_global_gtt_cleanup(dev);
>>>>   out_freecsr:
>>>>       intel_csr_ucode_fini(dev_priv);
>>>> +    if (intel_gvt_host_active(dev)) {
>>>> +        gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
>>>> +        dev_priv->vgpu.host_private_data = NULL;
>>>> +    }
>>>>       intel_uncore_fini(dev);
>>>>       pci_iounmap(dev->pdev, dev_priv->regs);
>>>>   put_bridge:
>>>> @@ -1165,6 +1180,10 @@ int i915_driver_unload(struct drm_device *dev)
>>>>
>>>>       intel_modeset_cleanup(dev);
>>>>
>>>> +    if (intel_gvt_host_active(dev)) {
>>>> +        gvt_destroy_pgt_device(dev_priv->vgpu.host_private_data);
>>>> +        dev_priv->vgpu.host_private_data = NULL;
>>>> +    }
>>>>       /*
>>>>        * free the memory space allocated for the child device
>>>>        * config parsed from VBT
>>>> diff --git a/drivers/gpu/drm/i915/i915_drv.h
>>>> b/drivers/gpu/drm/i915/i915_drv.h
>>>> index 01cc982..db3c79b 100644
>>>> --- a/drivers/gpu/drm/i915/i915_drv.h
>>>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>>>> @@ -1673,6 +1673,7 @@ struct i915_workarounds {
>>>>
>>>>   struct i915_virtual_gpu {
>>>>       bool active;
>>>> +    void *host_private_data;
>>>>   };
>>>>
>>>>   struct i915_execbuffer_params {
>>>> @@ -2747,6 +2748,11 @@ static inline bool intel_vgpu_active(struct
>>>> drm_device *dev)
>>>>       return to_i915(dev)->vgpu.active;
>>>>   }
>>>>
>>>> +static inline bool intel_gvt_host_active(struct drm_device *dev)
>>>> +{
>>>> +    return to_i915(dev)->vgpu.host_private_data ? true : false;
>>>> +}
>>>> +
>>>>   void
>>>>   i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe
>>>> pipe,
>>>>                u32 status_mask);
>>>> diff --git a/drivers/gpu/drm/i915/i915_vgpu.h
>>>> b/drivers/gpu/drm/i915/i915_vgpu.h
>>>> index 3c83b47..942490a 100644
>>>> --- a/drivers/gpu/drm/i915/i915_vgpu.h
>>>> +++ b/drivers/gpu/drm/i915/i915_vgpu.h
>>>> @@ -113,5 +113,8 @@ struct vgt_if {
>>>>   extern void i915_check_vgpu(struct drm_device *dev);
>>>>   extern int intel_vgt_balloon(struct drm_device *dev);
>>>>   extern void intel_vgt_deballoon(void);
>>>> +extern void *gvt_create_pgt_device(struct drm_i915_private *dev_priv);
>>>> +extern bool gvt_post_init_pgt_device(void *private_data);
>>>> +extern void gvt_destroy_pgt_device(void *private_data);
>>>>
>>>>   #endif /* _I915_VGPU_H_ */
>>>> diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
>>>> index d133112..78a38f1 100644
>>>> --- a/include/xen/interface/xen.h
>>>> +++ b/include/xen/interface/xen.h
>>>> @@ -28,6 +28,7 @@
>>>>   #define __XEN_PUBLIC_XEN_H__
>>>>
>>>>   #include
>>>> +#include
>>>>
>>>>   /*
>>>>    * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g
  2016-02-16  9:54       ` Zhi Wang
  2016-02-16 12:44         ` Jani Nikula
@ 2016-02-16 14:08         ` Joonas Lahtinen
  1 sibling, 0 replies; 49+ messages in thread
From: Joonas Lahtinen @ 2016-02-16 14:08 UTC (permalink / raw)
  To: Zhi Wang, daniel.vetter, Jani Nikula
  Cc: intel-gfx, david.j.cowperthwaite, igvt-g

Hi,

On ti, 2016-02-16 at 17:54 +0800, Zhi Wang wrote:
> Hi Joonas:
>      For the debug function/macros, could we use DRM_DEBUG_DRIVER as 
> output, but keep our internal debug switch & marcos, like:
> 
> #define gvt_dbg_xxx(xxx, xxx) \
> 	if (gvt_debug & xxx) \
> 		DRM_DEBUG_DRIVER(xxxxxx)
> 
> Is it OK for the maintainers? Or we have to use DRM_DEBUG_DRIVER 
> directly :(.
> 

I think from upstream kernel perspective the right answer is that code
like above really needs to use dynamic debugging instead of self-baked
system. When using dynamic debugging framework, debugging could be
enabled in different granularity levels (module, file, function, line,
or format). More at: https://lwn.net/Articles/434833/

Passing dynamic debug filter 'format "i915: gvt: core: " +p' would then
enable GVT core debugging.

On the other hand, Daniel does not want us to break drm.debug or add
i915.debug (so I guess i915.gvt_debug is not fine either). Discussion
occurred in this patch:

https://patchwork.freedesktop.org/patch/71412/

So I think best you can currently do is:

#define gvt_dbg_xxx(fmt, xxx) \
	DRM_DEBUG_DRIVER("gvt: xxx: " fmt, ...)>

And then we wait for DRM to get converted to dynamic debug.

I discussed this with Daniel, and it should be doable. Only down-fall
is that in order to make drm.debug=0x0e syntax still work, we need to
make make ddebug_exec_queries symbol exported and add code like this
for backwards compatability;

if (drm.debug & DRM_UT_CORE)
	ddebug_exec_queries("format \"drm: core: \" +p", ...);
if (drm.debug & DRM_UT_DRIVER)
	ddebug_exec_queries("format \"drm: drv: \" +p", ...);

What do you guys think? One could export more symbols and add the
filters in a more direct manner, but I'm not sure if it's worth the
effort.

Regards, Joonas

> Thanks,
> Zhi.
> 
> 于 02/03/16 14:01, Zhi Wang wrote:
> > Hi Joonas:
> >      Thanks you very much! We're very excited for receiving your
> > advice
> > and continue to be open to any comments. :)
> > 
> > I'm supposed that we should make the agreements on i915 host change
> > at
> > the very beginning, as I'm concerned during the discussion of i915
> > host
> > change, you know, maybe some code of GVT-g needs to be refined or
> > re-designed. So we put the i915 host changes to the beginning of
> > the
> > patch set for the convenience of discussion.
> > 
> > I summarize your comments as below, very applicate. :)
> > 
> > - Replace boolean return value with int as much as possible.
> > - Replace customized debug ASSERT() function & macros with
> > DRM_DEBUG_*
> > - Document all non-static functions like i915
> > - Fix all whitespace via scripts/cleanpatch.pl
> > - Commit function structure refinement.
> > - Change the register access behavior just like what i915 does.
> > 
> > For other comments, see my comments below. :)
> > 
> > On 01/29/16 21:57, Joonas Lahtinen wrote:
> > > Hi,
> > > 
> > > TL;DR Overall, we have same problem as with the scheduler series,
> > > there
> > > is too much placeholder stuff for easy review. Just squash enough
> > > code
> > > into one commit so it actually does something logical that can be
> > > reviewed and then extend it later. Then it can be reviewed and
> > > pushed.
> > > Just splitting the code down to achieve smaller patches is not
> > > the
> > > right thing to do.
> > > 
> > > Comments on the overall code: You need to document all header
> > > file
> > > functions (in the source files), and it is good to document the
> > > static
> > > functions within a file too, to make future maintenance easier.
> > > 
> > > It is not about splitting the code down to small chunks, but
> > > splitting
> > > it down to small *logical* chunks. It doesn't make sense to
> > > commit
> > > dozens of empty bodied functions for review, and then later add
> > > their
> > > code.
> > > 
> > > If you add functions, only add them at a patch that takes them
> > > into use
> > > too, unless we're talking about general purpose shared code. And
> > > also
> > > remember to add the function body and documentation header. If
> > > you
> > > simply add a "return 0;" or similar function body, do add a
> > > comment to
> > > why the function does not exist and when it will.
> > > 
> > > Then, there is a trend of having a boolean return values in the
> > > code.
> > > When possible, it should rather be int and the cause for failure
> > > should
> > > be propagated from the last level all the way to up (-ENOMEN
> > > etc.).
> > > This way debugging becomes easier and if new error conditions
> > > appear,
> > > there is less of a maintenance burden to add the propagation
> > > later.
> > > 
> > > Finally, make sure to look at the existing driver parts and
> > >     https://www.kernel.org/doc/Documentation/CodingStyle
> > > for proper coding style. There are lots of whitespace fixes
> > > needed in
> > > this series, like array initializations.
> > > 
> > > I hope to see this first patch rerolled so that you squash some
> > > of the
> > > later commits into it so that all functions have a body and you
> > > add
> > > documentation for the functions so I can both see what it should
> > > do and
> > > what it actually does. Only reroll the first patch, to keep the
> > > iterative step smaller. Lets only then continue with the rest of
> > > the
> > > series once we've reached a consensus on the formatting and style
> > > basics.
> > > 
> > > See more comments below.
> > > 
> > > On to, 2016-01-28 at 18:21 +0800, Zhi Wang wrote:
> > > > This patch introduces the very basic framework of GVT-g device
> > > > model,
> > > > includes basic prototypes, definitions, initialization.
> > > > ---
> > > >   arch/x86/include/asm/xen/interface.h  |   3 +
> > > >   drivers/gpu/drm/i915/Kconfig          |  16 ++
> > > >   drivers/gpu/drm/i915/Makefile         |   2 +
> > > >   drivers/gpu/drm/i915/gvt/Makefile     |   5 +
> > > >   drivers/gpu/drm/i915/gvt/debug.h      |  72 +++++++
> > > >   drivers/gpu/drm/i915/gvt/fb_decoder.c |  34 ++++
> > > >   drivers/gpu/drm/i915/gvt/fb_decoder.h | 110 ++++++++++
> > > >   drivers/gpu/drm/i915/gvt/gvt.c        | 366
> > > > ++++++++++++++++++++++++++++++++++
> > > >   drivers/gpu/drm/i915/gvt/gvt.h        | 130 ++++++++++++
> > > >   drivers/gpu/drm/i915/gvt/hypercall.h  |  30 +++
> > > >   drivers/gpu/drm/i915/gvt/mpt.h        |  97 +++++++++
> > > >   drivers/gpu/drm/i915/gvt/params.c     |  29 +++
> > > >   drivers/gpu/drm/i915/gvt/params.h     |  34 ++++
> > > >   drivers/gpu/drm/i915/gvt/reg.h        |  34 ++++
> > > >   drivers/gpu/drm/i915/i915_dma.c       |  19 ++
> > > >   drivers/gpu/drm/i915/i915_drv.h       |   6 +
> > > >   drivers/gpu/drm/i915/i915_vgpu.h      |   3 +
> > > >   include/xen/interface/xen.h           |   1 +
> > > >   18 files changed, 991 insertions(+)
> > > >   create mode 100644 drivers/gpu/drm/i915/gvt/Makefile
> > > >   create mode 100644 drivers/gpu/drm/i915/gvt/debug.h
> > > >   create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.c
> > > >   create mode 100644 drivers/gpu/drm/i915/gvt/fb_decoder.h
> > > >   create mode 100644 drivers/gpu/drm/i915/gvt/gvt.c
> > > >   create mode 100644 drivers/gpu/drm/i915/gvt/gvt.h
> > > >   create mode 100644 drivers/gpu/drm/i915/gvt/hypercall.h
> > > >   create mode 100644 drivers/gpu/drm/i915/gvt/mpt.h
> > > >   create mode 100644 drivers/gpu/drm/i915/gvt/params.c
> > > >   create mode 100644 drivers/gpu/drm/i915/gvt/params.h
> > > >   create mode 100644 drivers/gpu/drm/i915/gvt/reg.h
> > > > 
> > > > diff --git a/arch/x86/include/asm/xen/interface.h
> > > > b/arch/x86/include/asm/xen/interface.h
> > > > index 62ca03e..6ff4986 100644
> > > > --- a/arch/x86/include/asm/xen/interface.h
> > > > +++ b/arch/x86/include/asm/xen/interface.h
> > > > @@ -73,6 +73,9 @@
> > > >   #endif
> > > > 
> > > >   #ifndef __ASSEMBLY__
> > > > +
> > > > +#include
> > > > +
> > > 
> > > I don't follow why this would need to be added if the file is not
> > > modified otherwise. Each header should only include what they
> > > use.
> > > 
> > > If this is an existing bug (that xen/interface.h can not be
> > > included
> > > without including linux/types.h), it should be split to a
> > > separate
> > > patch and sent to Xen team. Same for include/xen/interface/xen.h.
> > > 
> > > >   /* Explicitly size integers that represent pfns in the public
> > > > interface
> > > >    * with Xen so that on ARM we can have one ABI that works for
> > > > 32
> > > > and 64
> > > >    * bit guests. */
> > > > diff --git a/drivers/gpu/drm/i915/Kconfig
> > > > b/drivers/gpu/drm/i915/Kconfig
> > > > index 051eab3..89ff723 100644
> > > > --- a/drivers/gpu/drm/i915/Kconfig
> > > > +++ b/drivers/gpu/drm/i915/Kconfig
> > > > @@ -47,3 +47,19 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT
> > > >         option changes the default for that module option.
> > > > 
> > > >         If in doubt, say "N".
> > > > +
> > > > +config I915_GVT
> > > > +        tristate "GVT-g host driver"
> > > > +        depends on DRM_I915
> > > > +        select IRQ_WORK
> > > > +        default y
> > > 
> > > Defaulting to "n" would make sense initially.
> > > 
> > [Zhi] Sure, will do.
> > > > +        help
> > > > +          Enabling GVT-g mediated graphics passthrough
> > > > technique for
> > > > Intel i915
> > > > +          based integrated graphics card. With GVT-g, it's
> > > > possible
> > > > to have one
> > > > +          integrated i915 device shared by multiple VMs.
> > > > Performance
> > > > critical
> > > > +          opterations such as apperture accesses and ring
> > > > buffer
> > > > operations
> > > > +          are pass-throughed to VM, with a minimal set of
> > > > conflicting resources
> > > > +          (e.g. display settings) mediated by vGT driver. The
> > > > benefit of vGT
> > > > +          is on both the performance, given that each VM could
> > > > directly operate
> > > > +          its aperture space and submit commands like running
> > > > on
> > > > native, and
> > > > +          the feature completeness, given that a true GEN
> > > > hardware
> > > > is exposed.
> > > > diff --git a/drivers/gpu/drm/i915/Makefile
> > > > b/drivers/gpu/drm/i915/Makefile
> > > > index 0851de07..d4df410 100644
> > > > --- a/drivers/gpu/drm/i915/Makefile
> > > > +++ b/drivers/gpu/drm/i915/Makefile
> > > > @@ -91,6 +91,8 @@ i915-y += dvo_ch7017.o \
> > > >         intel_sdvo.o \
> > > >         intel_tv.o
> > > > 
> > > > +obj-$(CONFIG_I915_GVT)  += gvt/
> > > > +
> > > >   # virtual gpu code
> > > >   i915-y += i915_vgpu.o
> > > > 
> > > > diff --git a/drivers/gpu/drm/i915/gvt/Makefile
> > > > b/drivers/gpu/drm/i915/gvt/Makefile
> > > > new file mode 100644
> > > > index 0000000..6935b78
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/i915/gvt/Makefile
> > > > @@ -0,0 +1,5 @@
> > > > +GVT_SOURCE := gvt.o params.o fb_decoder.o
> > > > +
> > > > +ccflags-y            += -I$(src) -I$(src)/.. -Wall -Werror
> > > > -Wno-unused-function
> > > > +i915_gvt-y            := $(GVT_SOURCE)
> > > > +obj-$(CONFIG_I915_GVT)        += i915_gvt.o
> > > > diff --git a/drivers/gpu/drm/i915/gvt/debug.h
> > > > b/drivers/gpu/drm/i915/gvt/debug.h
> > > > new file mode 100644
> > > > index 0000000..18e1467
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/i915/gvt/debug.h
> > > > @@ -0,0 +1,72 @@
> > > > +/*
> > > > + * Copyright(c) 2011-2016 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.
> > > > + */
> > > > +
> > > > +#ifndef __GVT_DEBUG_H__
> > > > +#define __GVT_DEBUG_H__
> > > > +
> > > > +#define
> > > > ASSERT(x)                                                      
> > > >  \
> > > > +        do
> > > > {                                                            \
> > > > +                if (!(x))
> > > > {                                             \
> > > > +                        printk("Assert at %s line
> > > > %d\n",                \
> > > > +                                __FILE__,
> > > > __LINE__);                    \
> > > > +
> > > > }                                                       \
> > > > +        } while (0);
> > > > +
> > > > +#define ASSERT_NUM(x,
> > > > y)                                                \
> > > > +        do
> > > > {                                                            \
> > > > +                if (!(x))
> > > > {                                             \
> > > > +                        printk("Assert at %s line %d para
> > > > 0x%llx\n",    \
> > > > +                                __FILE__, __LINE__,
> > > > (u64)y);            \
> > > > +
> > > > }                                                       \
> > > > +        } while (0);
> > > > +
> > > 
> > > There already is WARN_ON (and i915_drv.h modifies it a little).
> > > Do not
> > > introduce custom functions like this, if the existing ones need
> > > improvement, improve them.
> > > 
> > [Zhi] OK. Will do as what i915 does
> > > > +#define gvt_info(fmt, args...) \
> > > > +    printk(KERN_INFO"[GVT-g] "fmt"\n", ##args)
> > > > +
> > > > +#define gvt_err(fmt, args...) \
> > > > +    printk(KERN_ERR"%s() - %d: "fmt"\n", __func__, __LINE__,
> > > > ##args)
> > > > +
> > > > +#define gvt_warn(fmt, args...) \
> > > > +    printk(KERN_WARNING"%s() - %d: "fmt"\n", __func__,
> > > > __LINE__,
> > > > ##args)
> > > > +
> > > > +#define gvt_dbg(level, fmt, args...) do { \
> > > > +        if (gvt.debug & level) \
> > > > +            printk(KERN_DEBUG"%s() - %d: "fmt"\n", __func__,
> > > > __LINE__, ##args); \
> > > > +    }while(0)
> > > > +
> > > > +enum {
> > > > +    GVT_DBG_CORE = (1 << 0),
> > > > +    GVT_DBG_MM = (1 << 1),
> > > > +    GVT_DBG_IRQ = (1 << 2),
> > > > +};
> > > > +
> > > > +#define gvt_dbg_core(fmt, args...) \
> > > > +    gvt_dbg(GVT_DBG_CORE, fmt, ##args)
> > > > +
> > > > +#define gvt_dbg_mm(fmt, args...) \
> > > > +    gvt_dbg(GVT_DBG_MM, fmt, ##args)
> > > > +
> > > > +#define gvt_dbg_irq(fmt, args...) \
> > > > +    gvt_dbg(GVT_DBG_IRQ, fmt, ##args)
> > > > +
> > > > +#endif
> > > 
> > > This should be integrated better to DRM debugging options, custom
> > > debugging code only for i915 was rejected a while ago.
> > > 
> > [ZHI] Thanks for sharing the history. :) Will change that.
> > > > diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c
> > > > b/drivers/gpu/drm/i915/gvt/fb_decoder.c
> > > > new file mode 100644
> > > > index 0000000..a219819
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c
> > > > @@ -0,0 +1,34 @@
> > > > +/*
> > > > + * Copyright(c) 2011-2016 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 "gvt.h"
> > > > +
> > > > +int gvt_decode_fb_format(struct pgt_device *pdev, int vmid,
> > > > struct
> > > > gvt_fb_format *fb)
> > > > +{
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +int gvt_fb_notifier_call_chain(unsigned long val, void *data)
> > > > +{
> > > > +    return 0;
> > > > +}
> > > 
> > > Kerneldoc missing for these functions. It is all the same to
> > > squash
> > > later patches to introduce the code to these functions already,
> > > reviewing utility functions with no kerneldoc and no body makes
> > > it
> > > somewhat difficult to see the big picture.
> > > 
> > 
> > [Zhi] One question. I saw i915 put some function instruction in
> > *.c. Is
> > it also OK for kernel doc generating the proper doc files?
> > 
> > > > diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.h
> > > > b/drivers/gpu/drm/i915/gvt/fb_decoder.h
> > > > new file mode 100644
> > > > index 0000000..2c29ed4
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.h
> > > > @@ -0,0 +1,110 @@
> > > > +/*
> > > > + * Copyright(c) 2011-2016 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.
> > > > + */
> > > > +
> > > > +#ifndef _GVT_FB_DECODER_H_
> > > > +#define _GVT_FB_DECODER_H_
> > > > +
> > > > +typedef enum {
> > > > +    FB_MODE_SET_START = 1,
> > > > +    FB_MODE_SET_END,
> > > > +    FB_DISPLAY_FLIP,
> > > > +}gvt_fb_event_t;
> > > > +
> > > > +typedef enum {
> > > > +    DDI_PORT_NONE    = 0,
> > > > +    DDI_PORT_B    = 1,
> > > > +    DDI_PORT_C    = 2,
> > > > +    DDI_PORT_D    = 3,
> > > > +    DDI_PORT_E    = 4
> > > > +} ddi_port_t;
> > > > +
> > > > +struct pgt_device;
> > > > +
> > > > +struct gvt_fb_notify_msg {
> > > > +    unsigned vm_id;
> > > > +    unsigned pipe_id; /* id starting from 0 */
> > > > +    unsigned plane_id; /* primary, cursor, or sprite */
> > > > +};
> > > > +
> > > > +/* color space conversion and gamma correction are not
> > > > included */
> > > > +struct gvt_primary_plane_format {
> > > > +    u8    enabled;    /* plane is enabled */
> > > > +    u8    tiled;        /* X-tiled */
> > > > +    u8    bpp;        /* bits per pixel */
> > > > +    u32    hw_format;    /* format field in the PRI_CTL
> > > > register */
> > > > +    u32    drm_format;    /* format in DRM definition */
> > > > +    u32    base;        /* framebuffer base in graphics memory
> > > > */
> > > > +    u32    x_offset;    /* in pixels */
> > > > +    u32    y_offset;    /* in lines */
> > > > +    u32    width;        /* in pixels */
> > > > +    u32    height;        /* in lines */
> > > > +    u32    stride;        /* in bytes */
> > > > +};
> > > > +
> > > > +struct gvt_sprite_plane_format {
> > > > +    u8    enabled;    /* plane is enabled */
> > > > +    u8    tiled;        /* X-tiled */
> > > > +    u8    bpp;        /* bits per pixel */
> > > > +    u32    hw_format;    /* format field in the SPR_CTL
> > > > register */
> > > > +    u32    drm_format;    /* format in DRM definition */
> > > > +    u32    base;        /* sprite base in graphics memory */
> > > > +    u32    x_pos;        /* in pixels */
> > > > +    u32    y_pos;        /* in lines */
> > > > +    u32    x_offset;    /* in pixels */
> > > > +    u32    y_offset;    /* in lines */
> > > > +    u32    width;        /* in pixels */
> > > > +    u32    height;        /* in lines */
> > > > +};
> > > > +
> > > > +struct gvt_cursor_plane_format {
> > > > +    u8    enabled;
> > > > +    u8    mode;        /* cursor mode select */
> > > > +    u8    bpp;        /* bits per pixel */
> > > > +    u32    drm_format;    /* format in DRM definition */
> > > > +    u32    base;        /* cursor base in graphics memory */
> > > > +    u32    x_pos;        /* in pixels */
> > > > +    u32    y_pos;        /* in lines */
> > > > +    u8    x_sign;        /* X Position Sign */
> > > > +    u8    y_sign;        /* Y Position Sign */
> > > > +    u32    width;        /* in pixels */
> > > > +    u32    height;        /* in lines */
> > > > +    u32    x_hot;        /* in pixels */
> > > > +    u32    y_hot;        /* in pixels */
> > > > +};
> > > > +
> > > 
> > > The above structs have a lot in common, would it make sense to
> > > have the
> > > common members + plane type and then union for the plane type
> > > specific
> > > data. I suspect having it all split this way will lead to more
> > > utility
> > > functions somewhere.
> > > 
> > [Zhi] Thanks. Will do that.
> > 
> > > > +struct gvt_pipe_format {
> > > > +    struct gvt_primary_plane_format    primary;
> > > > +    struct gvt_sprite_plane_format    sprite;
> > > > +    struct gvt_cursor_plane_format    cursor;
> > > > +    ddi_port_t ddi_port;  /* the DDI port that the pipe is
> > > > connected
> > > > to */
> > > > +};
> > > > +
> > > > +struct gvt_fb_format{
> > > > +    struct gvt_pipe_format    pipes[I915_MAX_PIPES];
> > > > +};
> > > > +
> > > > +extern int gvt_fb_notifier_call_chain(unsigned long val, void
> > > > *data);
> > > > +extern int gvt_decode_fb_format(struct pgt_device *pdev, int
> > > > vmid,
> > > > +                struct gvt_fb_format *fb);
> > > > +
> > > > +#endif
> > > > diff --git a/drivers/gpu/drm/i915/gvt/gvt.c
> > > > b/drivers/gpu/drm/i915/gvt/gvt.c
> > > > new file mode 100644
> > > > index 0000000..041d10f
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/i915/gvt/gvt.c
> > > > @@ -0,0 +1,366 @@
> > > > +/*
> > > > + * Copyright(c) 2011-2016 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
> > > > +#include
> > > > +
> > > > +#include "gvt.h"
> > > > +
> > > > +struct gvt_host gvt_host;
> > > > +
> > > > +extern struct gvt_kernel_dm xengt_kdm;
> > > > +extern struct gvt_kernel_dm kvmgt_kdm;
> > > > +
> > > > +static const char *supported_hypervisors[] = {
> > > 
> > > should be "static const char * const".
> > > 
> > > > +    [GVT_HYPERVISOR_TYPE_XEN] = "Xen Hypervisor",
> > > > +    [GVT_HYPERVISOR_TYPE_KVM] = "KVM",
> > > > +};
> > > > +
> > > > +static bool gvt_init_host(void)
> > > > +{
> > > > +    struct gvt_host *host = &gvt_host;
> > > > +
> > > > +    if (!gvt.enable) {
> > > > +        gvt_dbg_core("GVT-g has been disabled by kernel
> > > > parameter");
> > > > +        return false;
> > > > +    }
> > > > +
> > > > +    if (host->initialized) {
> > > > +        gvt_err("GVT-g has already been initialized!");
> > > > +        return false;
> > > > +    }
> > > > +
> > > > +    if (xen_initial_domain()) {
> > > 
> > > Shouldn't Xen code be CONFIG_XEN_DOM0 and CONFIG_XEN #ifdef
> > > protected?
> > > 
> > [Zhi] The following code piece shows
> > xen_initial_domain()/xen_domain()
> > could also be used when CONFIG_XEN_DOM0 is not set.
> > 
> > #ifdef CONFIG_XEN
> > extern enum xen_domain_type xen_domain_type;
> > #else
> > #define xen_domain_type         XEN_NATIVE
> > #endif
> > 
> > #define xen_domain()            (xen_domain_type != XEN_NATIVE)
> > #define xen_pv_domain()         (xen_domain()
> > &&                        \
> >                                   xen_domain_type == XEN_PV_DOMAIN)
> > #define xen_hvm_domain()        (xen_domain()
> > &&                        \
> >                                   xen_domain_type ==
> > XEN_HVM_DOMAIN)
> > 
> > #ifdef CONFIG_XEN_DOM0
> > #include <xen/interface/xen.h>
> > #include <asm/xen/hypervisor.h>
> > 
> > #define xen_initial_domain()    (xen_domain() && \
> >                                   xen_start_info &&
> > xen_start_info->flags & SIF_INITDOMAIN)
> > #else  /* !CONFIG_XEN_DOM0 */
> > #define xen_initial_domain()    (0)
> > #endif  /* CONFIG_XEN_DOM0 */
> > 
> > > > +        /* Xen Dom0 */
> > > > +        host->kdm =
> > > > try_then_request_module(symbol_get(xengt_kdm),
> > > > "xengt");
> > > > +        host->hypervisor_type = GVT_HYPERVISOR_TYPE_XEN;
> > > > +    } else if(xen_domain()) {
> > > > +        /* Xen DomU */
> > > > +        return false;
> > > > +    } else {
> > > > +        /* not in Xen. Try KVMGT */
> > > > +        host->kdm =
> > > > try_then_request_module(symbol_get(kvmgt_kdm),
> > > > "kvm");
> > > > +        host->hypervisor_type = GVT_HYPERVISOR_TYPE_KVM;
> > > > +    }
> > > > +
> > > 
> > > Why do we need to keep track of hypervisor type, are there plenty
> > > of
> > > hypervisor specific behaviour differences?
> > 
> > [Zhi] As GVT-g needs some hypervisor services to work, we write a
> > abstraction layer to connect GVT-g to different hypervisor. But
> > still
> > there are some emulation logic couldn't be fitted into that
> > abstraction
> > layer, like OpRegion emulation. In Xen, we emulates it in kernel
> > space,
> > while we emulates it in Qemu under KVM. I also agreed that we
> > should
> > find some approach to improve it just like what you said.
> > 
> > If it is just for printing
> > > the below debug, I think it's better to move the debug into above
> > > code
> > > that detects the hypervisor, wrap them with appropriate CONFIG
> > > #ifdefs.
> > > 
> > > > +    if (!host->kdm)
> > > > +        return false;
> > > > +
> > > > +    if (!hypervisor_detect_host())
> > > > +        return false;
> > > > +
> > > > +    gvt_info("Running with hypervisor %s in host mode",
> > > > +            supported_hypervisors[host->hypervisor_type]);
> > > > +
> > > > +    idr_init(&host->device_idr);
> > > > +    mutex_init(&host->device_idr_lock);
> > > > +
> > > > +    host->initialized = true;
> > > > +    return true;
> > > > +}
> > > > +
> > > > +static bool init_device_info(struct pgt_device *pdev)
> > > > +{
> > > > +    struct gvt_device_info *info = &pdev->device_info;
> > > > +
> > > > +    if (!IS_BROADWELL(pdev->dev_priv)) {
> > > > +        gvt_err("Unsupported GEN device");
> > > > +        return false;
> > > > +    }
> > > > +
> > > > +    if (IS_BROADWELL(pdev->dev_priv)) {
> > > > +        info->max_gtt_gm_sz = (1UL << 32);
> > > > +        /*
> > > > +         * The layout of BAR0 in BDW:
> > > > +         * |< - MMIO 2MB ->|<- Reserved 6MB ->|<- MAX GTT 8MB-
> > > > >|
> > > > +         *
> > > > +         * GTT offset in BAR0 starts from 8MB to 16MB, and
> > > > +         * Whatever GTT size is configured in BIOS,
> > > > +         * the size of BAR0 is always 16MB. The actual
> > > > configured
> > > > +         * GTT size can be found in GMCH_CTRL.
> > > > +         */
> > > > +        info->gtt_start_offset = (1UL << 23);
> > > > +        info->max_gtt_size = (1UL << 23);
> > > > +        info->gtt_entry_size = 8;
> > > > +        info->gtt_entry_size_shift = 3;
> > > > +        info->gmadr_bytes_in_cmd = 8;
> > > 
> > > Would this information be useful in a header as #defines too?
> > > 
> > [Zhi] Probably. Consider that one GVT-g featured kernel could be
> > able to
> > run on different platforms, the informaion data structure could be
> > different. But I agree to define the magic numbers in a header
> > files. :)
> > 
> > > > +    }
> > > > +
> > > > +    gvt_info("Device info:");
> > > > +    printk("        max_gtt_gm_sz: %llx\n", info-
> > > > >max_gtt_gm_sz);
> > > > +    printk("        max_gtt_size: %x\n", info->max_gtt_size);
> > > > +    printk("        gtt_size_entry: %x\n", info-
> > > > >gtt_entry_size);
> > > > +    printk("        gtt_entry_size_shift: %x\n",
> > > > info->gtt_entry_size_shift);
> > > > +    printk("        gtt_start_offset: %x\n", info-
> > > > >gtt_start_offset);
> > > > +    printk("        gtt_end_offset: %x\n", info-
> > > > >gtt_end_offset);
> > > > +
> > > 
> > > Just put this to kind of stuff to i915_debugfs.c.
> > > 
> > [Zhi] Thanks.
> > 
> > > > +    return true;
> > > > +}
> > > > +
> > > > +static void init_initial_cfg_space_state(struct pgt_device
> > > > *pdev)
> > > > +{
> > > > +    struct pci_dev *pci_dev = pdev->dev_priv->dev->pdev;
> > > > +    int i;
> > > > +
> > > > +    gvt_dbg_core("init initial cfg space, id %d", pdev->id);
> > > > +
> > > > +    for (i = 0; i < GVT_CFG_SPACE_SZ; i += 4)
> > > 
> > > += sizeof(...)
> > > 
> > > > +        pci_read_config_dword(pci_dev, i,
> > > > +                (u32 *)&pdev->initial_cfg_space[i]);
> > > > +
> > > > +    for (i = 0; i < 3; i++) {
> > > 
> > > No magic numbers make a #define for 3 and give it a descriptive
> > > name.
> > > 
> > > > +        pdev->bar_size[i] = pci_resource_len(pci_dev, i * 2);
> > > > +        gvt_info("bar %d size: %llx", i, pdev->bar_size[i]);
> > > > +    }
> > > > +}
> > > > +
> > > > +static void clean_initial_mmio_state(struct pgt_device *pdev)
> > > > +{
> > > > +    if (pdev->gttmmio_va) {
> > > > +        iounmap(pdev->gttmmio_va);
> > > > +        pdev->gttmmio_va = NULL;
> > > > +    }
> > > > +
> > > > +    if (pdev->gmadr_va) {
> > > > +        iounmap(pdev->gmadr_va);
> > > > +        pdev->gmadr_va = NULL;
> > > > +    }
> > > > +}
> > > > +
> > > > +static bool init_initial_mmio_state(struct pgt_device *pdev)
> > > > +{
> > > > +    u64 bar0, bar1;
> > > > +
> > > > +    gvt_dbg_core("init initial mmio state, id %d", pdev->id);
> > > > +
> > > > +    bar0 = *(u64 *)&pdev-
> > > > >initial_cfg_space[GVT_REG_CFG_SPACE_BAR0];
> > > > +    bar1 = *(u64 *)&pdev-
> > > > >initial_cfg_space[GVT_REG_CFG_SPACE_BAR1];
> > > > +
> > > > +    pdev->gttmmio_base = bar0 & ~0xf;
> > > > +    pdev->mmio_size = 2 * 1024 * 1024;
> > > > +    pdev->reg_num = pdev->mmio_size / 4;
> > > > +    pdev->gmadr_base = bar1 & ~0xf;
> > > > +
> > > 
> > > Many magic numbers.
> > > 
> > > > +    pdev->gttmmio_va = ioremap(pdev->gttmmio_base, pdev-
> > > > >bar_size[0]);
> > > > +    if (!pdev->gttmmio_va) {
> > > > +        gvt_err("fail to map GTTMMIO BAR.");
> > > 
> > > These should be if(WARN_ON(...))
> > > 
> > > > +        return false;
> > > > +    }
> > > > +
> > > > +    pdev->gmadr_va = ioremap(pdev->gmadr_base, pdev-
> > > > >bar_size[2]);
> > > > +    if (!pdev->gmadr_va) {
> > > > +        gvt_err("fail to map GMADR BAR.");
> > > > +        goto err;
> > > > +    }
> > > > +
> > > > +    gvt_info("bar0: 0x%llx, bar1: 0x%llx", bar0, bar1);
> > > > +    gvt_info("mmio size: %x", pdev->mmio_size);
> > > > +    gvt_info("gttmmio: 0x%llx, gmadr: 0x%llx", pdev-
> > > > >gttmmio_base,
> > > > pdev->gmadr_base);
> > > > +    gvt_info("gttmmio_va: %p", pdev->gttmmio_va);
> > > > +    gvt_info("gmadr_va: %p", pdev->gmadr_va);
> > > > +
> > > > +    return true;
> > > > +err:
> > > > +    clean_initial_mmio_state(pdev);
> > > > +    return false;
> > > > +}
> > > > +
> > > > +static int gvt_service_thread(void *data)
> > > > +{
> > > > +    struct pgt_device *pdev = (struct pgt_device *)data;
> > > > +    int r;
> > > > +
> > > > +    gvt_dbg_core("service thread start, pgt %d", pdev->id);
> > > > +
> > > > +    while(!kthread_should_stop()) {
> > > > +        r = wait_event_interruptible(pdev->service_thread_wq,
> > > > +                kthread_should_stop() || pdev-
> > > > >service_request);
> > > > +
> > > > +        if (kthread_should_stop())
> > > > +            break;
> > > > +
> > > > +        if (r) {
> > > > +            gvt_warn("service thread is waken up by unexpected
> > > > signal.");
> > > 
> > > Should be WARN_ONCE, to avoid future disasters with CI.
> > > 
> > [Zhi] Thanks.
> > > > +            continue;
> > > > +        }
> > > > +    }
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static void clean_service_thread(struct pgt_device *pdev)
> > > > +{
> > > > +    if (pdev->service_thread) {
> > > > +        kthread_stop(pdev->service_thread);
> > > > +        pdev->service_thread = NULL;
> > > > +    }
> > > > +}
> > > > +
> > > > +static bool init_service_thread(struct pgt_device *pdev)
> > > > +{
> > > > +    init_waitqueue_head(&pdev->service_thread_wq);
> > > > +
> > > > +    pdev->service_thread = kthread_run(gvt_service_thread,
> > > > +            pdev, "gvt_service_thread%d", pdev->id);
> > > > +
> > > > +    if (!pdev->service_thread) {
> > > > +        gvt_err("fail to start service thread.");
> > > > +        return false;
> > > > +    }
> > > > +
> > > > +    return true;
> > > > +}
> > > > +
> > > > +static void clean_pgt_device(struct pgt_device *pdev)
> > > > +{
> > > > +    clean_service_thread(pdev);
> > > > +    clean_initial_mmio_state(pdev);
> > > > +}
> > > > +
> > > > +static bool init_pgt_device(struct pgt_device *pdev, struct
> > > > drm_i915_private *dev_priv)
> > > > +{
> > > > +    if (!init_device_info(pdev))
> > > > +        return false;
> > > > +
> > > > +    init_initial_cfg_space_state(pdev);
> > > > +
> > > > +    if (!init_initial_mmio_state(pdev))
> > > > +        goto err;
> > > > +
> > > > +    if (!init_service_thread(pdev))
> > > > +        goto err;
> > > > +
> > > > +    return true;
> > > > +err:
> > > > +    clean_pgt_device(pdev);
> > > > +    return false;
> > > > +}
> > > > +
> > > > +static bool post_init_pgt_device(struct pgt_device *pdev)
> > > > +{
> > > > +    return true;
> > > > +}
> > > > +
> > > > +static void free_pgt_device(struct pgt_device *pdev)
> > > > +{
> > > > +    struct gvt_host *host = &gvt_host;
> > > > +
> > > > +    mutex_lock(&host->device_idr_lock);
> > > > +    idr_remove(&host->device_idr, pdev->id);
> > > > +    mutex_unlock(&host->device_idr_lock);
> > > > +
> > > > +    vfree(pdev);
> > > > +}
> > > > +
> > > > +static struct pgt_device *alloc_pgt_device(struct
> > > > drm_i915_private
> > > > *dev_priv)
> > > > +{
> > > > +    struct gvt_host *host = &gvt_host;
> > > > +    struct pgt_device *pdev = NULL;
> > > > +
> > > > +    pdev = vzalloc(sizeof(*pdev));
> > > > +    if (!pdev) {
> > > > +        gvt_err("fail to allocate memory for pgt device.");
> > > > +        return NULL;
> > > > +    }
> > > > +
> > > > +    mutex_lock(&host->device_idr_lock);
> > > > +    pdev->id = idr_alloc(&host->device_idr, pdev, 0, 0,
> > > > GFP_KERNEL);
> > > > +    mutex_unlock(&host->device_idr_lock);
> > > > +
> > > > +    if (pdev->id < 0) {
> > > > +        gvt_err("fail to allocate pgt device id.");
> > > > +        goto err;
> > > > +    }
> > > > +
> > > > +    mutex_init(&pdev->lock);
> > > > +    pdev->dev_priv = dev_priv;
> > > > +    idr_init(&pdev->instance_idr);
> > > > +
> > > > +    return pdev;
> > > > +err:
> > > > +    free_pgt_device(pdev);
> > > > +    return NULL;
> > > > +}
> > > > +
> > > > +void gvt_destroy_pgt_device(void *private_data)
> > > > +{
> > > > +    struct pgt_device *pdev = (struct pgt_device
> > > > *)private_data;
> > > > +
> > > > +    clean_pgt_device(pdev);
> > > > +    free_pgt_device(pdev);
> > > > +}
> > > > +
> > > > +void *gvt_create_pgt_device(struct drm_i915_private *dev_priv)
> > > > +{
> > > > +    struct pgt_device *pdev = NULL;
> > > > +    struct gvt_host *host = &gvt_host;
> > > > +
> > > > +    if (!host->initialized && !gvt_init_host()) {
> > > > +        gvt_err("gvt_init_host fail");
> > > > +        return NULL;
> > > > +    }
> > > > +
> > > > +    gvt_dbg_core("create new pgt device, i915 dev_priv: %p",
> > > > dev_priv);
> > > > +
> > > > +    pdev = alloc_pgt_device(dev_priv);
> > > > +    if (!pdev) {
> > > > +        gvt_err("fail to allocate memory for pgt device.");
> > > > +        goto err;
> > > > +    }
> > > > +
> > > > +    gvt_dbg_core("init pgt device, id %d", pdev->id);
> > > > +
> > > > +    if (!init_pgt_device(pdev, dev_priv)) {
> > > > +        gvt_err("fail to init physical device state.");
> > > > +        goto err;
> > > > +    }
> > > > +
> > > > +    gvt_dbg_core("pgt device creation done, id %d", pdev->id);
> > > > +
> > > > +    return pdev;
> > > > +err:
> > > > +    if (pdev) {
> > > > +        gvt_destroy_pgt_device(pdev);
> > > > +        pdev = NULL;
> > > > +    }
> > > > +    return NULL;
> > > > +}
> > > > +
> > > > +bool gvt_post_init_pgt_device(void *private_data)
> > > > +{
> > > > +    struct pgt_device *pdev = (struct pgt_device
> > > > *)private_data;
> > > > +    struct gvt_host *host = &gvt_host;
> > > > +
> > > > +    if (!host->initialized) {
> > > > +        gvt_err("gvt_host haven't been initialized.");
> > > > +        return false;
> > > > +    }
> > > > +
> > > > +    gvt_dbg_core("post init pgt device %d", pdev->id);
> > > > +
> > > > +    if (!post_init_pgt_device(pdev)) {
> > > > +        gvt_err("fail to post init physical device state.");
> > > > +        return false;
> > > > +    }
> > > > +
> > > > +    return true;
> > > > +}
> > > > diff --git a/drivers/gpu/drm/i915/gvt/gvt.h
> > > > b/drivers/gpu/drm/i915/gvt/gvt.h
> > > > new file mode 100644
> > > > index 0000000..6c85bba
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/i915/gvt/gvt.h
> > > > @@ -0,0 +1,130 @@
> > > > +/*
> > > > + * Copyright(c) 2011-2016 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.
> > > > + */
> > > > +
> > > > +#ifndef _GVT_H_
> > > > +#define _GVT_H_
> > > > +
> > > > +#include "i915_drv.h"
> > > > +#include "i915_vgpu.h"
> > > > +
> > > > +#include "debug.h"
> > > > +#include "params.h"
> > > > +#include "reg.h"
> > > > +#include "hypercall.h"
> > > > +#include "mpt.h"
> > > > +#include "fb_decoder.h"
> > > > +
> > > > +#define GVT_MAX_VGPU 8
> > > > +
> > > > +enum {
> > > > +    GVT_HYPERVISOR_TYPE_XEN = 0,
> > > > +    GVT_HYPERVISOR_TYPE_KVM,
> > > > +};
> > > > +
> > > > +struct gvt_host {
> > > > +    bool initialized;
> > > > +    int hypervisor_type;
> > > > +    struct mutex device_idr_lock;
> > > > +    struct idr device_idr;
> > > > +    struct gvt_kernel_dm *kdm;
> > > > +};
> > > > +
> > > > +extern struct gvt_host gvt_host;
> > > > +
> > > > +/* Describe the limitation of HW.*/
> > > > +struct gvt_device_info {
> > > > +    u64 max_gtt_gm_sz;
> > > > +    u32 gtt_start_offset;
> > > > +    u32 gtt_end_offset;
> > > > +    u32 max_gtt_size;
> > > > +    u32 gtt_entry_size;
> > > > +    u32 gtt_entry_size_shift;
> > > > +    u32 gmadr_bytes_in_cmd;
> > > > +};
> > > > +
> > > > +struct vgt_device {
> > > > +    int id;
> > > > +    int vm_id;
> > > > +    struct pgt_device *pdev;
> > > > +    bool warn_untrack;
> > > > +};
> > > > +
> > > > +struct pgt_device {
> > > > +    struct mutex lock;
> > > > +    int id;
> > > > +
> > > > +    struct drm_i915_private *dev_priv;
> > > > +    struct idr instance_idr;
> > > > +
> > > > +    struct gvt_device_info device_info;
> > > > +
> > > > +    u8 initial_cfg_space[GVT_CFG_SPACE_SZ];
> > > > +    u64 bar_size[GVT_BAR_NUM];
> > > > +
> > > > +    u64 gttmmio_base;
> > > > +    void *gttmmio_va;
> > > > +
> > > > +    u64 gmadr_base;
> > > > +    void *gmadr_va;
> > > > +
> > > > +    u32 mmio_size;
> > > > +    u32 reg_num;
> > > > +
> > > > +    wait_queue_head_t service_thread_wq;
> > > > +    struct task_struct *service_thread;
> > > > +    unsigned long service_request;
> > > > +};
> > > > +
> > > 
> > > Here-->
> > > 
> > > > +static inline u32 gvt_mmio_read(struct pgt_device *pdev,
> > > > +        u32 reg)
> > > > +{
> > > > +    struct drm_i915_private *dev_priv = pdev->dev_priv;
> > > > +    i915_reg_t tmp = {.reg = reg};
> > > > +    return I915_READ(tmp);
> > > > +}
> > > > +
> > > > +static inline void gvt_mmio_write(struct pgt_device *pdev,
> > > > +        u32 reg, u32 val)
> > > > +{
> > > > +    struct drm_i915_private *dev_priv = pdev->dev_priv;
> > > > +    i915_reg_t tmp = {.reg = reg};
> > > > +    I915_WRITE(tmp, val);
> > > > +}
> > > > +
> > > > +static inline u64 gvt_mmio_read64(struct pgt_device *pdev,
> > > > +        u32 reg)
> > > > +{
> > > > +    struct drm_i915_private *dev_priv = pdev->dev_priv;
> > > > +    i915_reg_t tmp = {.reg = reg};
> > > > +    return I915_READ64(tmp);
> > > > +}
> > > > +
> > > > +static inline void gvt_mmio_write64(struct pgt_device *pdev,
> > > > +        u32 reg, u64 val)
> > > > +{
> > > > +    struct drm_i915_private *dev_priv = pdev->dev_priv;
> > > > +    i915_reg_t tmp = {.reg = reg};
> > > > +    I915_WRITE64(tmp, val);
> > > > +}
> > > > +
> > > 
> > > <-- Why? The i915_reg_t type was added to avoid problems, this
> > > code is
> > > not used anywhere, and it has no documentation, so I can not
> > > review it.
> > > 
> > > I wrote comments at the top of the post.
> > > 
> > [Zhi] Thanks, I will check that.
> > 
> > > Regards, Joonas
> > > 
> > > > +#endif
> > > > diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h
> > > > b/drivers/gpu/drm/i915/gvt/hypercall.h
> > > > new file mode 100644
> > > > index 0000000..0a41874
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/i915/gvt/hypercall.h
> > > > @@ -0,0 +1,30 @@
> > > > +/*
> > > > + * Copyright(c) 2011-2016 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.
> > > > + */
> > > > +
> > > > +#ifndef _GVT_HYPERCALL_H_
> > > > +#define _GVT_HYPERCALL_H_
> > > > +
> > > > +struct gvt_kernel_dm {
> > > > +};
> > > > +
> > > > +#endif /* _GVT_HYPERCALL_H_ */
> > > > diff --git a/drivers/gpu/drm/i915/gvt/mpt.h
> > > > b/drivers/gpu/drm/i915/gvt/mpt.h
> > > > new file mode 100644
> > > > index 0000000..bbe4465
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/i915/gvt/mpt.h
> > > > @@ -0,0 +1,97 @@
> > > > +/*
> > > > + * Copyright(c) 2011-2016 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.
> > > > + */
> > > > +
> > > > +#ifndef _GVT_MPT_H_
> > > > +#define _GVT_MPT_H_
> > > > +
> > > > +struct vgt_device;
> > > > +
> > > > +static inline unsigned long hypervisor_g2m_pfn(struct
> > > > vgt_device *vgt,
> > > > +    unsigned long g_pfn)
> > > > +{
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static inline int hypervisor_pause_domain(struct vgt_device
> > > > *vgt)
> > > > +{
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static inline int hypervisor_shutdown_domain(struct vgt_device
> > > > *vgt)
> > > > +{
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static inline int hypervisor_set_trap_area(struct vgt_device
> > > > *vgt,
> > > > +    uint64_t start, uint64_t end, bool map)
> > > > +{
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static inline bool hypervisor_detect_host(void)
> > > > +{
> > > > +    return false;
> > > > +}
> > > > +
> > > > +static inline int hypervisor_virt_to_mfn(void *addr)
> > > > +{
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static inline void *hypervisor_mfn_to_virt(int mfn)
> > > > +{
> > > > +    return NULL;
> > > > +}
> > > > +
> > > > +static inline void hypervisor_inject_msi(struct vgt_device
> > > > *vgt)
> > > > +{
> > > > +    return;
> > > > +}
> > > > +
> > > > +static inline int hypervisor_hvm_init(struct vgt_device *vgt)
> > > > +{
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static inline void hypervisor_hvm_exit(struct vgt_device *vgt)
> > > > +{
> > > > +}
> > > > +
> > > > +static inline void *hypervisor_gpa_to_va(struct vgt_device
> > > > *vgt,
> > > > unsigned long gpa)
> > > > +{
> > > > +    return NULL;
> > > > +}
> > > > +
> > > > +static inline bool hypervisor_read_va(struct vgt_device *vgt,
> > > > void *va,
> > > > +        void *val, int len, int atomic)
> > > > +{
> > > > +    return false;
> > > > +}
> > > > +
> > > > +static inline bool hypervisor_write_va(struct vgt_device *vgt,
> > > > void
> > > > *va,
> > > > +        void *val, int len, int atomic)
> > > > +{
> > > > +    return false;
> > > > +}
> > > > +
> > > > +#endif /* _GVT_MPT_H_ */
> > > > diff --git a/drivers/gpu/drm/i915/gvt/params.c
> > > > b/drivers/gpu/drm/i915/gvt/params.c
> > > > new file mode 100644
> > > > index 0000000..dfc33c3
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/i915/gvt/params.c
> > > > @@ -0,0 +1,29 @@
> > > > +/*
> > > > + * Copyright(c) 2011-2016 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 "gvt.h"
> > > > +
> > > > +struct gvt_kernel_params gvt = {
> > > > +    .enable = true,
> > > > +    .debug = 0,
> > > > +};
> > > > diff --git a/drivers/gpu/drm/i915/gvt/params.h
> > > > b/drivers/gpu/drm/i915/gvt/params.h
> > > > new file mode 100644
> > > > index 0000000..d2955b9
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/i915/gvt/params.h
> > > > @@ -0,0 +1,34 @@
> > > > +/*
> > > > + * Copyright(c) 2011-2016 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.
> > > > + */
> > > > +
> > > > +#ifndef _GVT_PARAMS_H_
> > > > +#define _GVT_PARAMS_H_
> > > > +
> > > > +struct gvt_kernel_params {
> > > > +    bool enable;
> > > > +    int debug;
> > > > +};
> > > > +
> > > > +extern struct gvt_kernel_params gvt;
> > > > +
> > > > +#endif
> > > > diff --git a/drivers/gpu/drm/i915/gvt/reg.h
> > > > b/drivers/gpu/drm/i915/gvt/reg.h
> > > > new file mode 100644
> > > > index 0000000..d363b74
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/i915/gvt/reg.h
> > > > @@ -0,0 +1,34 @@
> > > > +/*
> > > > + * Copyright(c) 2011-2016 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.
> > > > + */
> > > > +
> > > > +#ifndef _GVT_REG_H
> > > > +#define _GVT_REG_H
> > > > +
> > > > +#define GVT_CFG_SPACE_SZ    256
> > > > +#define GVT_BAR_NUM        4
> > > > +
> > > > +#define GVT_REG_CFG_SPACE_BAR0    0x10
> > > > +#define GVT_REG_CFG_SPACE_BAR1    0x18
> > > > +#define GVT_REG_CFG_SPACE_BAR2    0x20
> > > > +
> > > > +#endif
> > > > diff --git a/drivers/gpu/drm/i915/i915_dma.c
> > > > b/drivers/gpu/drm/i915/i915_dma.c
> > > > index 4725e8d..eca8e50 100644
> > > > --- a/drivers/gpu/drm/i915/i915_dma.c
> > > > +++ b/drivers/gpu/drm/i915/i915_dma.c
> > > > @@ -943,6 +943,10 @@ int i915_driver_load(struct drm_device
> > > > *dev,
> > > > unsigned long flags)
> > > > 
> > > >       intel_uncore_init(dev);
> > > > 
> > > > +    dev_priv->vgpu.host_private_data =
> > > > gvt_create_pgt_device(dev_priv);
> > > > +    if(intel_gvt_host_active(dev))
> > > > +        DRM_INFO("GVT-g is running in host mode\n");
> > > > +
> > > >       ret = i915_gem_gtt_init(dev);
> > > >       if (ret)
> > > >           goto out_freecsr;
> > > > @@ -1067,6 +1071,13 @@ int i915_driver_load(struct drm_device
> > > > *dev,
> > > > unsigned long flags)
> > > >           goto out_power_well;
> > > >       }
> > > > 
> > > > +    if (intel_gvt_host_active(dev)) {
> > > > +        if
> > > > (!gvt_post_init_pgt_device(dev_priv->vgpu.host_private_data)) {
> > > > +            DRM_ERROR("failed to post init pgt device\n");
> > > > +            goto out_power_well;
> > > > +        }
> > > > +    }
> > > > +
> > > >       /*
> > > >        * Notify a valid surface after modesetting,
> > > >        * when running inside a VM.
> > > > @@ -1117,6 +1128,10 @@ out_gtt:
> > > >       i915_global_gtt_cleanup(dev);
> > > >   out_freecsr:
> > > >       intel_csr_ucode_fini(dev_priv);
> > > > +    if (intel_gvt_host_active(dev)) {
> > > > +        gvt_destroy_pgt_device(dev_priv-
> > > > >vgpu.host_private_data);
> > > > +        dev_priv->vgpu.host_private_data = NULL;
> > > > +    }
> > > >       intel_uncore_fini(dev);
> > > >       pci_iounmap(dev->pdev, dev_priv->regs);
> > > >   put_bridge:
> > > > @@ -1165,6 +1180,10 @@ int i915_driver_unload(struct drm_device
> > > > *dev)
> > > > 
> > > >       intel_modeset_cleanup(dev);
> > > > 
> > > > +    if (intel_gvt_host_active(dev)) {
> > > > +        gvt_destroy_pgt_device(dev_priv-
> > > > >vgpu.host_private_data);
> > > > +        dev_priv->vgpu.host_private_data = NULL;
> > > > +    }
> > > >       /*
> > > >        * free the memory space allocated for the child device
> > > >        * config parsed from VBT
> > > > diff --git a/drivers/gpu/drm/i915/i915_drv.h
> > > > b/drivers/gpu/drm/i915/i915_drv.h
> > > > index 01cc982..db3c79b 100644
> > > > --- a/drivers/gpu/drm/i915/i915_drv.h
> > > > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > > > @@ -1673,6 +1673,7 @@ struct i915_workarounds {
> > > > 
> > > >   struct i915_virtual_gpu {
> > > >       bool active;
> > > > +    void *host_private_data;
> > > >   };
> > > > 
> > > >   struct i915_execbuffer_params {
> > > > @@ -2747,6 +2748,11 @@ static inline bool
> > > > intel_vgpu_active(struct
> > > > drm_device *dev)
> > > >       return to_i915(dev)->vgpu.active;
> > > >   }
> > > > 
> > > > +static inline bool intel_gvt_host_active(struct drm_device
> > > > *dev)
> > > > +{
> > > > +    return to_i915(dev)->vgpu.host_private_data ? true :
> > > > false;
> > > > +}
> > > > +
> > > >   void
> > > >   i915_enable_pipestat(struct drm_i915_private *dev_priv, enum
> > > > pipe
> > > > pipe,
> > > >                u32 status_mask);
> > > > diff --git a/drivers/gpu/drm/i915/i915_vgpu.h
> > > > b/drivers/gpu/drm/i915/i915_vgpu.h
> > > > index 3c83b47..942490a 100644
> > > > --- a/drivers/gpu/drm/i915/i915_vgpu.h
> > > > +++ b/drivers/gpu/drm/i915/i915_vgpu.h
> > > > @@ -113,5 +113,8 @@ struct vgt_if {
> > > >   extern void i915_check_vgpu(struct drm_device *dev);
> > > >   extern int intel_vgt_balloon(struct drm_device *dev);
> > > >   extern void intel_vgt_deballoon(void);
> > > > +extern void *gvt_create_pgt_device(struct drm_i915_private
> > > > *dev_priv);
> > > > +extern bool gvt_post_init_pgt_device(void *private_data);
> > > > +extern void gvt_destroy_pgt_device(void *private_data);
> > > > 
> > > >   #endif /* _I915_VGPU_H_ */
> > > > diff --git a/include/xen/interface/xen.h
> > > > b/include/xen/interface/xen.h
> > > > index d133112..78a38f1 100644
> > > > --- a/include/xen/interface/xen.h
> > > > +++ b/include/xen/interface/xen.h
> > > > @@ -28,6 +28,7 @@
> > > >   #define __XEN_PUBLIC_XEN_H__
> > > > 
> > > >   #include
> > > > +#include
> > > > 
> > > >   /*
> > > >    * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
-- 
Joonas Lahtinen
Open Source Technology Center
Intel Corporation

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 49+ messages in thread

end of thread, other threads:[~2016-02-16 14:10 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-28 10:21 [RFC 00/29] iGVT-g implementation in i915 Zhi Wang
2016-01-28 10:21 ` [RFC 01/29] drm/i915/gvt: Introduce the basic architecture of GVT-g Zhi Wang
2016-01-29 13:57   ` Joonas Lahtinen
2016-01-29 16:48     ` Chris Wilson
2016-02-03  6:28       ` Zhi Wang
2016-02-05  7:02       ` Zhiyuan Lv
2016-02-03  6:01     ` Zhi Wang
2016-02-03  7:01       ` Zhiyuan Lv
2016-02-04 11:25       ` Joonas Lahtinen
2016-02-16  9:54       ` Zhi Wang
2016-02-16 12:44         ` Jani Nikula
2016-02-16 14:08         ` Joonas Lahtinen
2016-01-28 10:21 ` [RFC 02/29] drm/i915: Introduce host graphics memory balloon for gvt Zhi Wang
2016-02-04 11:27   ` Joonas Lahtinen
2016-02-05 10:03     ` Zhiyuan Lv
2016-02-05 13:40       ` Joonas Lahtinen
2016-02-05 14:16         ` Zhiyuan Lv
2016-02-08 11:52           ` Joonas Lahtinen
2016-02-10  8:08   ` Daniel Vetter
2016-01-28 10:21 ` [RFC 03/29] drm/i915: Introduce GVT context creation API Zhi Wang
2016-01-28 10:21 ` [RFC 04/29] drm/i915: Ondemand populate context addressing mode bit Zhi Wang
2016-01-28 10:21 ` [RFC 05/29] drm/i915: Do not populate PPGTT root pointers for GVT context Zhi Wang
2016-01-28 10:21 ` [RFC 06/29] drm/i915: Do not initialize the engine state of " Zhi Wang
2016-01-28 10:21 ` [RFC 07/29] drm/i915: GVT context scheduling Zhi Wang
2016-01-28 10:21 ` [RFC 08/29] drm/i915: Support vGPU guest framebuffer GEM object Zhi Wang
2016-01-28 10:21 ` [RFC 09/29] drm/i915: gvt: Resource allocator Zhi Wang
2016-01-28 10:21 ` [RFC 10/29] drm/i915: gvt: Basic mmio emulation state Zhi Wang
2016-01-28 10:21 ` [RFC 11/29] drm/i915: gvt: update PVINFO page definition in i915_vgpu.h Zhi Wang
2016-01-28 10:21 ` [RFC 12/29] drm/i915: gvt: vGPU life cycle management Zhi Wang
2016-01-28 10:21 ` [RFC 13/29] drm/i915: gvt: trace stub Zhi Wang
2016-01-28 10:21 ` [RFC 14/29] drm/i915: gvt: vGPU interrupt emulation framework Zhi Wang
2016-01-28 10:21 ` [RFC 15/29] drm/i915: gvt: vGPU graphics memory " Zhi Wang
2016-01-28 10:21 ` [RFC 16/29] drm/i915: gvt: Generic MPT framework Zhi Wang
2016-01-28 10:21 ` [RFC 17/29] gvt: Xen hypervisor GVT-g MPT module Zhi Wang
2016-01-28 11:33   ` Joonas Lahtinen
2016-01-28 12:50     ` Zhiyuan Lv
2016-01-28 10:21 ` [RFC 18/29] drm/i915: gvt: vGPU configuration emulation Zhi Wang
2016-01-28 10:21 ` [RFC 19/29] drm/i915: gvt: vGPU OpRegion emulation Zhi Wang
2016-01-28 10:21 ` [RFC 20/29] drm/i915: gvt: vGPU framebuffer format decoder Zhi Wang
2016-01-28 10:21 ` [RFC 21/29] drm/i915: gvt: vGPU MMIO register emulation Zhi Wang
2016-01-28 10:21 ` [RFC 22/29] drm/i915: gvt: Full display virtualization Zhi Wang
2016-01-28 10:21 ` [RFC 23/29] drm/i915: gvt: Introduce GVT control interface Zhi Wang
2016-01-28 10:21 ` [RFC 24/29] drm/i915: gvt: Full execlist status emulation Zhi Wang
2016-01-28 10:21 ` [RFC 25/29] drm/i915: gvt: vGPU execlist workload submission Zhi Wang
2016-01-28 10:21 ` [RFC 26/29] drm/i915: gvt: workload scheduler Zhi Wang
2016-01-28 10:21 ` [RFC 27/29] drm/i915: gvt: vGPU schedule policy framework Zhi Wang
2016-01-28 10:21 ` [RFC 28/29] drm/i915: gvt: vGPU context switch Zhi Wang
2016-01-28 10:21 ` [RFC 29/29] drm/i915: gvt: vGPU command scanner Zhi Wang
2016-01-28 17:15 ` ✗ Fi.CI.BAT: failure for iGVT-g implementation in i915 Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.