drm/i915/gvt: vGPU context switch
authorZhi Wang <zhi.a.wang@intel.com>
Sun, 1 May 2016 23:02:37 +0000 (19:02 -0400)
committerZhenyu Wang <zhenyuw@linux.intel.com>
Fri, 14 Oct 2016 10:15:13 +0000 (18:15 +0800)
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>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
drivers/gpu/drm/i915/gvt/Makefile
drivers/gpu/drm/i915/gvt/debug.h
drivers/gpu/drm/i915/gvt/gvt.h
drivers/gpu/drm/i915/gvt/handlers.c
drivers/gpu/drm/i915/gvt/render.c [new file with mode: 0644]
drivers/gpu/drm/i915/gvt/render.h [new file with mode: 0644]
drivers/gpu/drm/i915/gvt/scheduler.c
drivers/gpu/drm/i915/gvt/vgpu.c

index 21000b183b951d3804f80e464fa2af6a1442f97d..e05556cd0f787b64319d4270db9669722f96a76e 100644 (file)
@@ -1,7 +1,7 @@
 GVT_DIR := gvt
 GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o trace_points.o firmware.o \
        interrupt.o gtt.o cfg_space.o opregion.o mmio.o display.o edid.o \
-       execlist.o scheduler.o sched_policy.o
+       execlist.o scheduler.o sched_policy.o render.o
 
 ccflags-y                      += -I$(src) -I$(src)/$(GVT_DIR) -Wall
 i915-y                        += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE))
index a3f49d544bdbc8d0d2858684f73d84ebf4f31a42..76e50eeef7f3f796b0b9b4a1f990c79e087a9d20 100644 (file)
@@ -48,4 +48,7 @@
 #define gvt_dbg_sched(fmt, args...) \
        DRM_DEBUG_DRIVER("gvt: sched: "fmt, ##args)
 
+#define gvt_dbg_render(fmt, args...) \
+       DRM_DEBUG_DRIVER("gvt: render: "fmt, ##args)
+
 #endif
index 6d37468631b7e973662f6c1a5542a9bf900ac45d..dfe398d474960ab0f5c68019560dbc14c7d47a86 100644 (file)
@@ -44,6 +44,7 @@
 #include "execlist.h"
 #include "scheduler.h"
 #include "sched_policy.h"
+#include "render.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -154,6 +155,7 @@ struct intel_vgpu {
        struct list_head workload_q_head[I915_NUM_ENGINES];
        struct kmem_cache *workloads;
        atomic_t running_workload_num;
+       DECLARE_BITMAP(tlb_handle_pending, I915_NUM_ENGINES);
        struct i915_gem_context *shadow_ctx;
        struct notifier_block shadow_ctx_notifier_block;
 };
index 8e8bda584c941a1678f83791b23b22ad8a9d3473..d59a934b6e3245e8c938cf2d7fbe698bb0dd2502 100644 (file)
@@ -1340,6 +1340,37 @@ static int ring_mode_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
        return 0;
 }
 
+static int gvt_reg_tlb_control_handler(struct intel_vgpu *vgpu,
+               unsigned int offset, void *p_data, unsigned int bytes)
+{
+       int rc = 0;
+       unsigned int id = 0;
+
+       switch (offset) {
+       case 0x4260:
+               id = RCS;
+               break;
+       case 0x4264:
+               id = VCS;
+               break;
+       case 0x4268:
+               id = VCS2;
+               break;
+       case 0x426c:
+               id = BCS;
+               break;
+       case 0x4270:
+               id = VECS;
+               break;
+       default:
+               rc = -EINVAL;
+               break;
+       }
+       set_bit(id, (void *)vgpu->tlb_handle_pending);
+
+       return rc;
+}
+
 #define MMIO_F(reg, s, f, am, rm, d, r, w) do { \
        ret = new_mmio_info(gvt, INTEL_GVT_MMIO_OFFSET(reg), \
                f, s, am, rm, d, r, w); \
@@ -2147,11 +2178,11 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
        MMIO_F(CL_PRIMITIVES_COUNT, 8, 0, 0, 0, D_ALL, NULL, NULL);
        MMIO_F(PS_INVOCATION_COUNT, 8, 0, 0, 0, D_ALL, NULL, NULL);
        MMIO_F(PS_DEPTH_COUNT, 8, 0, 0, 0, D_ALL, NULL, NULL);
-       MMIO_DH(0x4260, D_BDW_PLUS, NULL, NULL);
-       MMIO_DH(0x4264, D_BDW_PLUS, NULL, NULL);
-       MMIO_DH(0x4268, D_BDW_PLUS, NULL, NULL);
-       MMIO_DH(0x426c, D_BDW_PLUS, NULL, NULL);
-       MMIO_DH(0x4270, D_BDW_PLUS, NULL, NULL);
+       MMIO_DH(0x4260, D_BDW_PLUS, NULL, gvt_reg_tlb_control_handler);
+       MMIO_DH(0x4264, D_BDW_PLUS, NULL, gvt_reg_tlb_control_handler);
+       MMIO_DH(0x4268, D_BDW_PLUS, NULL, gvt_reg_tlb_control_handler);
+       MMIO_DH(0x426c, D_BDW_PLUS, NULL, gvt_reg_tlb_control_handler);
+       MMIO_DH(0x4270, D_BDW_PLUS, NULL, gvt_reg_tlb_control_handler);
        MMIO_DFH(0x4094, D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL);
 
        return 0;
diff --git a/drivers/gpu/drm/i915/gvt/render.c b/drivers/gpu/drm/i915/gvt/render.c
new file mode 100644 (file)
index 0000000..f54ab85
--- /dev/null
@@ -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.
+ *
+ * Authors:
+ *    Eddie Dong <eddie.dong@intel.com>
+ *    Kevin Tian <kevin.tian@intel.com>
+ *
+ * Contributors:
+ *    Zhi Wang <zhi.a.wang@intel.com>
+ *    Changbin Du <changbin.du@intel.com>
+ *    Zhenyu Wang <zhenyuw@linux.intel.com>
+ *    Tina Zhang <tina.zhang@intel.com>
+ *    Bing Niu <bing.niu@intel.com>
+ *
+ */
+
+#include "i915_drv.h"
+
+struct render_mmio {
+       int ring_id;
+       i915_reg_t reg;
+       u32 mask;
+       bool in_context;
+       u32 value;
+};
+
+static struct render_mmio gen8_render_mmio_list[] = {
+       {RCS, _MMIO(0x229c), 0xffff, false},
+       {RCS, _MMIO(0x2248), 0x0, false},
+       {RCS, _MMIO(0x2098), 0x0, false},
+       {RCS, _MMIO(0x20c0), 0xffff, true},
+       {RCS, _MMIO(0x24d0), 0, false},
+       {RCS, _MMIO(0x24d4), 0, false},
+       {RCS, _MMIO(0x24d8), 0, false},
+       {RCS, _MMIO(0x24dc), 0, false},
+       {RCS, _MMIO(0x7004), 0xffff, true},
+       {RCS, _MMIO(0x7008), 0xffff, true},
+       {RCS, _MMIO(0x7000), 0xffff, true},
+       {RCS, _MMIO(0x7010), 0xffff, true},
+       {RCS, _MMIO(0x7300), 0xffff, true},
+       {RCS, _MMIO(0x83a4), 0xffff, true},
+
+       {BCS, _MMIO(0x2229c), 0xffff, false},
+       {BCS, _MMIO(0x2209c), 0xffff, false},
+       {BCS, _MMIO(0x220c0), 0xffff, false},
+       {BCS, _MMIO(0x22098), 0x0, false},
+       {BCS, _MMIO(0x22028), 0x0, false},
+};
+
+static struct render_mmio gen9_render_mmio_list[] = {
+       {RCS, _MMIO(0x229c), 0xffff, false},
+       {RCS, _MMIO(0x2248), 0x0, false},
+       {RCS, _MMIO(0x2098), 0x0, false},
+       {RCS, _MMIO(0x20c0), 0xffff, true},
+       {RCS, _MMIO(0x24d0), 0, false},
+       {RCS, _MMIO(0x24d4), 0, false},
+       {RCS, _MMIO(0x24d8), 0, false},
+       {RCS, _MMIO(0x24dc), 0, false},
+       {RCS, _MMIO(0x7004), 0xffff, true},
+       {RCS, _MMIO(0x7008), 0xffff, true},
+       {RCS, _MMIO(0x7000), 0xffff, true},
+       {RCS, _MMIO(0x7010), 0xffff, true},
+       {RCS, _MMIO(0x7300), 0xffff, true},
+       {RCS, _MMIO(0x83a4), 0xffff, true},
+
+       {RCS, _MMIO(0x40e0), 0, false},
+       {RCS, _MMIO(0x40e4), 0, false},
+       {RCS, _MMIO(0x2580), 0xffff, true},
+       {RCS, _MMIO(0x7014), 0xffff, true},
+       {RCS, _MMIO(0x20ec), 0xffff, false},
+       {RCS, _MMIO(0xb118), 0, false},
+       {RCS, _MMIO(0xe100), 0xffff, true},
+       {RCS, _MMIO(0xe180), 0xffff, true},
+       {RCS, _MMIO(0xe184), 0xffff, true},
+       {RCS, _MMIO(0xe188), 0xffff, true},
+       {RCS, _MMIO(0xe194), 0xffff, true},
+       {RCS, _MMIO(0x4de0), 0, false},
+       {RCS, _MMIO(0x4de4), 0, false},
+       {RCS, _MMIO(0x4de8), 0, false},
+       {RCS, _MMIO(0x4dec), 0, false},
+       {RCS, _MMIO(0x4df0), 0, false},
+       {RCS, _MMIO(0x4df4), 0, false},
+
+       {BCS, _MMIO(0x2229c), 0xffff, false},
+       {BCS, _MMIO(0x2209c), 0xffff, false},
+       {BCS, _MMIO(0x220c0), 0xffff, false},
+       {BCS, _MMIO(0x22098), 0x0, false},
+       {BCS, _MMIO(0x22028), 0x0, false},
+
+       {VCS2, _MMIO(0x1c028), 0xffff, false},
+
+       {VECS, _MMIO(0x1a028), 0xffff, false},
+};
+
+static u32 gen9_render_mocs[I915_NUM_ENGINES][64];
+static u32 gen9_render_mocs_L3[32];
+
+static void handle_tlb_pending_event(struct intel_vgpu *vgpu, int ring_id)
+{
+       struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
+       i915_reg_t reg;
+       u32 regs[] = {
+               [RCS] = 0x4260,
+               [VCS] = 0x4264,
+               [VCS2] = 0x4268,
+               [BCS] = 0x426c,
+               [VECS] = 0x4270,
+       };
+
+       if (WARN_ON(ring_id >= ARRAY_SIZE(regs)))
+               return;
+
+       if (!test_and_clear_bit(ring_id, (void *)vgpu->tlb_handle_pending))
+               return;
+
+       reg = _MMIO(regs[ring_id]);
+
+       I915_WRITE(reg, 0x1);
+
+       if (wait_for_atomic((I915_READ(reg) == 0), 50))
+               gvt_err("timeout in invalidate ring (%d) tlb\n", ring_id);
+
+       gvt_dbg_core("invalidate TLB for ring %d\n", ring_id);
+}
+
+static void load_mocs(struct intel_vgpu *vgpu, int ring_id)
+{
+       struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
+       i915_reg_t offset, l3_offset;
+       u32 regs[] = {
+               [RCS] = 0xc800,
+               [VCS] = 0xc900,
+               [VCS2] = 0xca00,
+               [BCS] = 0xcc00,
+               [VECS] = 0xcb00,
+       };
+       int i;
+
+       if (WARN_ON(ring_id >= ARRAY_SIZE(regs)))
+               return;
+
+       if (!IS_SKYLAKE(dev_priv))
+               return;
+
+       for (i = 0; i < 64; i++) {
+               gen9_render_mocs[ring_id][i] = I915_READ(offset);
+               I915_WRITE(offset, vgpu_vreg(vgpu, offset));
+               POSTING_READ(offset);
+               offset.reg += 4;
+       }
+
+       if (ring_id == RCS) {
+               l3_offset.reg = 0xb020;
+               for (i = 0; i < 32; i++) {
+                       gen9_render_mocs_L3[i] = I915_READ(l3_offset);
+                       I915_WRITE(l3_offset, vgpu_vreg(vgpu, offset));
+                       POSTING_READ(l3_offset);
+                       l3_offset.reg += 4;
+               }
+       }
+}
+
+static void restore_mocs(struct intel_vgpu *vgpu, int ring_id)
+{
+       struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
+       i915_reg_t offset, l3_offset;
+       u32 regs[] = {
+               [RCS] = 0xc800,
+               [VCS] = 0xc900,
+               [VCS2] = 0xca00,
+               [BCS] = 0xcc00,
+               [VECS] = 0xcb00,
+       };
+       int i;
+
+       if (WARN_ON(ring_id >= ARRAY_SIZE(regs)))
+               return;
+
+       if (!IS_SKYLAKE(dev_priv))
+               return;
+
+       for (i = 0; i < 64; i++) {
+               vgpu_vreg(vgpu, offset) = I915_READ(offset);
+               I915_WRITE(offset, gen9_render_mocs[ring_id][i]);
+               POSTING_READ(offset);
+               offset.reg += 4;
+       }
+
+       if (ring_id == RCS) {
+               l3_offset.reg = 0xb020;
+               for (i = 0; i < 32; i++) {
+                       vgpu_vreg(vgpu, l3_offset) = I915_READ(l3_offset);
+                       I915_WRITE(l3_offset, gen9_render_mocs_L3[i]);
+                       POSTING_READ(l3_offset);
+                       l3_offset.reg += 4;
+               }
+       }
+}
+
+void intel_gvt_load_render_mmio(struct intel_vgpu *vgpu, int ring_id)
+{
+       struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
+       struct render_mmio *mmio;
+       u32 v;
+       int i, array_size;
+
+       if (IS_SKYLAKE(vgpu->gvt->dev_priv)) {
+               mmio = gen9_render_mmio_list;
+               array_size = ARRAY_SIZE(gen9_render_mmio_list);
+               load_mocs(vgpu, ring_id);
+       } else {
+               mmio = gen8_render_mmio_list;
+               array_size = ARRAY_SIZE(gen8_render_mmio_list);
+       }
+
+       for (i = 0; i < array_size; i++, mmio++) {
+               if (mmio->ring_id != ring_id)
+                       continue;
+
+               mmio->value = I915_READ(mmio->reg);
+               if (mmio->mask)
+                       v = vgpu_vreg(vgpu, mmio->reg) | (mmio->mask << 16);
+               else
+                       v = vgpu_vreg(vgpu, mmio->reg);
+
+               I915_WRITE(mmio->reg, v);
+               POSTING_READ(mmio->reg);
+
+               gvt_dbg_render("load reg %x old %x new %x\n",
+                               i915_mmio_reg_offset(mmio->reg),
+                               mmio->value, v);
+       }
+       handle_tlb_pending_event(vgpu, ring_id);
+}
+
+void intel_gvt_restore_render_mmio(struct intel_vgpu *vgpu, int ring_id)
+{
+       struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
+       struct render_mmio *mmio;
+       u32 v;
+       int i, array_size;
+
+       if (IS_SKYLAKE(dev_priv)) {
+               mmio = gen9_render_mmio_list;
+               array_size = ARRAY_SIZE(gen9_render_mmio_list);
+               restore_mocs(vgpu, ring_id);
+       } else {
+               mmio = gen8_render_mmio_list;
+               array_size = ARRAY_SIZE(gen8_render_mmio_list);
+       }
+
+       for (i = 0; i < array_size; i++, mmio++) {
+               if (mmio->ring_id != ring_id)
+                       continue;
+
+               vgpu_vreg(vgpu, mmio->reg) = I915_READ(mmio->reg);
+
+               if (mmio->mask) {
+                       vgpu_vreg(vgpu, mmio->reg) &= ~(mmio->mask << 16);
+                       v = mmio->value | (mmio->mask << 16);
+               } else
+                       v = mmio->value;
+
+               I915_WRITE(mmio->reg, v);
+               POSTING_READ(mmio->reg);
+
+               gvt_dbg_render("restore reg %x old %x new %x\n",
+                               i915_mmio_reg_offset(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 (file)
index 0000000..dac1a3c
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ *
+ * Authors:
+ *    Eddie Dong <eddie.dong@intel.com>
+ *    Kevin Tian <kevin.tian@intel.com>
+ *
+ * Contributors:
+ *    Zhi Wang <zhi.a.wang@intel.com>
+ *    Changbin Du <changbin.du@intel.com>
+ *    Zhenyu Wang <zhenyuw@linux.intel.com>
+ *    Tina Zhang <tina.zhang@intel.com>
+ *    Bing Niu <bing.niu@intel.com>
+ *
+ */
+
+#ifndef __GVT_RENDER_H__
+#define __GVT_RENDER_H__
+
+void intel_gvt_load_render_mmio(struct intel_vgpu *vgpu, int ring_id);
+
+void intel_gvt_restore_render_mmio(struct intel_vgpu *vgpu, int ring_id);
+
+#endif
index 2302a97cebf69bfb5e0e4641630d306a26a9a29e..2f96302c7b21cddd359f81bd90054405c5ba5eee 100644 (file)
@@ -139,9 +139,13 @@ static int shadow_context_status_change(struct notifier_block *nb,
 
        switch (action) {
        case INTEL_CONTEXT_SCHEDULE_IN:
+               intel_gvt_load_render_mmio(workload->vgpu,
+                                          workload->ring_id);
                atomic_set(&workload->shadow_ctx_active, 1);
                break;
        case INTEL_CONTEXT_SCHEDULE_OUT:
+               intel_gvt_restore_render_mmio(workload->vgpu,
+                                             workload->ring_id);
                atomic_set(&workload->shadow_ctx_active, 0);
                break;
        default:
index c9b8e184f5cbd4a8b310ce3a7847c3ce78926ab4..e5e0a72336c83ba3102e950a18374dbfdc6a7ec8 100644 (file)
@@ -200,6 +200,7 @@ struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt,
        vgpu->id = ret;
        vgpu->handle = param->handle;
        vgpu->gvt = gvt;
+       bitmap_zero(vgpu->tlb_handle_pending, I915_NUM_ENGINES);
 
        setup_vgpu_cfg_space(vgpu, param);