[Intel-gfx] [RFC 14/29] drm/i915: gvt: vGPU interrupt emulation framework

Zhi Wang zhi.a.wang at intel.com
Thu Jan 28 02:21:36 PST 2016


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 at 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



More information about the Intel-gfx mailing list