[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