drm/i915/gvt: Introduce a framework for tracking HW registers.
authorZhi Wang <zhi.a.wang@intel.com>
Tue, 30 Aug 2016 03:06:17 +0000 (11:06 +0800)
committerZhenyu Wang <zhenyuw@linux.intel.com>
Fri, 14 Oct 2016 10:11:33 +0000 (18:11 +0800)
This patch introduces a framework for tracking HW registers on different
GEN platforms.

Accesses to GEN HW registers from VMs will be trapped by hypervisor. It
will forward these emulation requests to GVT-g device model, which
requires this framework to search for related register descriptions.

Each MMIO entry in this framework describes a GEN HW registers, e.g.
offset, length, whether it contains RO bits, whether it can be accessed by
LRIs...and also emulation handlers for emulating register reading and
writing.

- Use i915 MMIO register definition & statement.(Joonas)

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/gvt.c
drivers/gpu/drm/i915/gvt/gvt.h
drivers/gpu/drm/i915/gvt/handlers.c [new file with mode: 0644]
drivers/gpu/drm/i915/gvt/mmio.h [new file with mode: 0644]

index 867910902b825d66d14e7d93f82b7834174fd87b..61b5b61f01f5bfae44463bcbf9fe11b80ae7b59d 100644 (file)
@@ -1,5 +1,5 @@
 GVT_DIR := gvt
-GVT_SOURCE := gvt.o aperture_gm.o
+GVT_SOURCE := gvt.o aperture_gm.o handlers.o
 
 ccflags-y                      += -I$(src) -I$(src)/$(GVT_DIR) -Wall
 i915-y                        += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE))
index 6ec5b937af6309c6a3b74f70a0c8e4c561d214ea..9f5c9bd83bc973837c1177d127568591e700f402 100644 (file)
  * 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:
+ *    Kevin Tian <kevin.tian@intel.com>
+ *    Eddie Dong <eddie.dong@intel.com>
+ *
+ * Contributors:
+ *    Niu Bing <bing.niu@intel.com>
+ *    Zhi Wang <zhi.a.wang@intel.com>
+ *
  */
 
 #include <linux/types.h>
@@ -84,9 +93,12 @@ int intel_gvt_init_host(void)
 
 static void init_device_info(struct intel_gvt *gvt)
 {
-       if (IS_BROADWELL(gvt->dev_priv) || IS_SKYLAKE(gvt->dev_priv))
-               gvt->device_info.max_support_vgpus = 8;
-       /* This function will grow large in GVT device model patches. */
+       struct intel_gvt_device_info *info = &gvt->device_info;
+
+       if (IS_BROADWELL(gvt->dev_priv) || IS_SKYLAKE(gvt->dev_priv)) {
+               info->max_support_vgpus = 8;
+               info->mmio_size = 2 * 1024 * 1024;
+       }
 }
 
 /**
@@ -104,7 +116,7 @@ void intel_gvt_clean_device(struct drm_i915_private *dev_priv)
        if (WARN_ON(!gvt->initialized))
                return;
 
-       /* Other de-initialization of GVT components will be introduced. */
+       intel_gvt_clean_mmio_info(gvt);
 
        gvt->initialized = false;
 }
@@ -123,6 +135,8 @@ void intel_gvt_clean_device(struct drm_i915_private *dev_priv)
 int intel_gvt_init_device(struct drm_i915_private *dev_priv)
 {
        struct intel_gvt *gvt = &dev_priv->gvt;
+       int ret;
+
        /*
         * Cannot initialize GVT device without intel_gvt_host gets
         * initialized first.
@@ -139,9 +153,11 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
        gvt->dev_priv = dev_priv;
 
        init_device_info(gvt);
-       /*
-        * Other initialization of GVT components will be introduce here.
-        */
+
+       ret = intel_gvt_setup_mmio_info(gvt);
+       if (ret)
+               return ret;
+
        gvt_dbg_core("gvt device creation is done\n");
        gvt->initialized = true;
        return 0;
index f42cdf74d5774ca47badb63a8273444e0cd69d06..024ad97eba12023c63b06a0b6da9c340cb0f2e3a 100644 (file)
  * 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:
+ *    Kevin Tian <kevin.tian@intel.com>
+ *    Eddie Dong <eddie.dong@intel.com>
+ *
+ * Contributors:
+ *    Niu Bing <bing.niu@intel.com>
+ *    Zhi Wang <zhi.a.wang@intel.com>
+ *
  */
 
 #ifndef _GVT_H_
@@ -26,6 +35,7 @@
 
 #include "debug.h"
 #include "hypercall.h"
+#include "mmio.h"
 
 #define GVT_MAX_VGPU 8
 
@@ -45,7 +55,7 @@ extern struct intel_gvt_host intel_gvt_host;
 /* Describe per-platform limitations. */
 struct intel_gvt_device_info {
        u32 max_support_vgpus;
-       /* This data structure will grow bigger in GVT device model patches */
+       u32 mmio_size;
 };
 
 /* GM resources owned by a vGPU */
@@ -83,6 +93,13 @@ struct intel_gvt_fence {
        unsigned long vgpu_allocated_fence_num;
 };
 
+#define INTEL_GVT_MMIO_HASH_BITS 9
+
+struct intel_gvt_mmio {
+       u32 *mmio_attribute;
+       DECLARE_HASHTABLE(mmio_info_table, INTEL_GVT_MMIO_HASH_BITS);
+};
+
 struct intel_gvt {
        struct mutex lock;
        bool initialized;
@@ -93,6 +110,7 @@ struct intel_gvt {
        struct intel_gvt_device_info device_info;
        struct intel_gvt_gm gm;
        struct intel_gvt_fence fence;
+       struct intel_gvt_mmio mmio;
 };
 
 /* Aperture/GM space definitions for GVT device */
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
new file mode 100644 (file)
index 0000000..6222218
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * 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:
+ *    Kevin Tian <kevin.tian@intel.com>
+ *    Eddie Dong <eddie.dong@intel.com>
+ *    Zhiyuan Lv <zhiyuan.lv@intel.com>
+ *
+ * Contributors:
+ *    Min He <min.he@intel.com>
+ *    Tina Zhang <tina.zhang@intel.com>
+ *    Pei Zhang <pei.zhang@intel.com>
+ *    Niu Bing <bing.niu@intel.com>
+ *    Ping Gao <ping.a.gao@intel.com>
+ *    Zhi Wang <zhi.a.wang@intel.com>
+ *
+
+ */
+
+#include "i915_drv.h"
+
+/* Register contains RO bits */
+#define F_RO           (1 << 0)
+/* Register contains graphics address */
+#define F_GMADR                (1 << 1)
+/* Mode mask registers with high 16 bits as the mask bits */
+#define F_MODE_MASK    (1 << 2)
+/* This reg can be accessed by GPU commands */
+#define F_CMD_ACCESS   (1 << 3)
+/* This reg has been accessed by a VM */
+#define F_ACCESSED     (1 << 4)
+/* This reg has been accessed through GPU commands */
+#define F_CMD_ACCESSED (1 << 5)
+/* This reg could be accessed by unaligned address */
+#define F_UNALIGN      (1 << 6)
+
+unsigned long intel_gvt_get_device_type(struct intel_gvt *gvt)
+{
+       if (IS_BROADWELL(gvt->dev_priv))
+               return D_BDW;
+       else if (IS_SKYLAKE(gvt->dev_priv))
+               return D_SKL;
+
+       return 0;
+}
+
+bool intel_gvt_match_device(struct intel_gvt *gvt,
+               unsigned long device)
+{
+       return intel_gvt_get_device_type(gvt) & device;
+}
+
+static int new_mmio_info(struct intel_gvt *gvt,
+               u32 offset, u32 flags, u32 size,
+               u32 addr_mask, u32 ro_mask, u32 device,
+               void *read, void *write)
+{
+       struct intel_gvt_mmio_info *info, *p;
+       u32 start, end, i;
+
+       if (!intel_gvt_match_device(gvt, device))
+               return 0;
+
+       if (WARN_ON(!IS_ALIGNED(offset, 4)))
+               return -EINVAL;
+
+       start = offset;
+       end = offset + size;
+
+       for (i = start; i < end; i += 4) {
+               info = kzalloc(sizeof(*info), GFP_KERNEL);
+               if (!info)
+                       return -ENOMEM;
+
+               info->offset = i;
+               p = intel_gvt_find_mmio_info(gvt, info->offset);
+               if (p)
+                       gvt_err("dup mmio definition offset %x\n",
+                               info->offset);
+               info->size = size;
+               info->length = (i + 4) < end ? 4 : (end - i);
+               info->addr_mask = addr_mask;
+               info->device = device;
+               info->read = read;
+               info->write = write;
+               gvt->mmio.mmio_attribute[info->offset / 4] = flags;
+               INIT_HLIST_NODE(&info->node);
+               hash_add(gvt->mmio.mmio_info_table, &info->node, info->offset);
+       }
+       return 0;
+}
+
+#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); \
+       if (ret) \
+               return ret; \
+} while (0)
+
+#define MMIO_D(reg, d) \
+       MMIO_F(reg, 4, 0, 0, 0, d, NULL, NULL)
+
+#define MMIO_DH(reg, d, r, w) \
+       MMIO_F(reg, 4, 0, 0, 0, d, r, w)
+
+#define MMIO_DFH(reg, d, f, r, w) \
+       MMIO_F(reg, 4, f, 0, 0, d, r, w)
+
+#define MMIO_GM(reg, d, r, w) \
+       MMIO_F(reg, 4, F_GMADR, 0xFFFFF000, 0, d, r, w)
+
+#define MMIO_RO(reg, d, f, rm, r, w) \
+       MMIO_F(reg, 4, F_RO | f, 0, rm, d, r, w)
+
+#define MMIO_RING_F(prefix, s, f, am, rm, d, r, w) do { \
+       MMIO_F(prefix(RENDER_RING_BASE), s, f, am, rm, d, r, w); \
+       MMIO_F(prefix(BLT_RING_BASE), s, f, am, rm, d, r, w); \
+       MMIO_F(prefix(GEN6_BSD_RING_BASE), s, f, am, rm, d, r, w); \
+       MMIO_F(prefix(VEBOX_RING_BASE), s, f, am, rm, d, r, w); \
+} while (0)
+
+#define MMIO_RING_D(prefix, d) \
+       MMIO_RING_F(prefix, 4, 0, 0, 0, d, NULL, NULL)
+
+#define MMIO_RING_DFH(prefix, d, f, r, w) \
+       MMIO_RING_F(prefix, 4, f, 0, 0, d, r, w)
+
+#define MMIO_RING_GM(prefix, d, r, w) \
+       MMIO_RING_F(prefix, 4, F_GMADR, 0xFFFF0000, 0, d, r, w)
+
+#define MMIO_RING_RO(prefix, d, f, rm, r, w) \
+       MMIO_RING_F(prefix, 4, F_RO | f, 0, rm, d, r, w)
+
+static int init_generic_mmio_info(struct intel_gvt *gvt)
+{
+       int ret;
+
+       MMIO_F(0, 0, 0, 0, 0, D_ALL, NULL, NULL);
+       return 0;
+}
+
+static int init_broadwell_mmio_info(struct intel_gvt *gvt)
+{
+       int ret;
+
+       MMIO_F(0, 0, 0, 0, 0, D_ALL, NULL, NULL);
+       return 0;
+}
+
+/**
+ * intel_gvt_find_mmio_info - find MMIO information entry by aligned offset
+ * @gvt: GVT device
+ * @offset: register offset
+ *
+ * This function is used to find the MMIO information entry from hash table
+ *
+ * Returns:
+ * pointer to MMIO information entry, NULL if not exists
+ */
+struct intel_gvt_mmio_info *intel_gvt_find_mmio_info(struct intel_gvt *gvt,
+       unsigned int offset)
+{
+       struct intel_gvt_mmio_info *e;
+
+       WARN_ON(!IS_ALIGNED(offset, 4));
+
+       hash_for_each_possible(gvt->mmio.mmio_info_table, e, node, offset) {
+               if (e->offset == offset)
+                       return e;
+       }
+       return NULL;
+}
+
+/**
+ * intel_gvt_clean_mmio_info - clean up MMIO information table for GVT device
+ * @gvt: GVT device
+ *
+ * This function is called at the driver unloading stage, to clean up the MMIO
+ * information table of GVT device
+ *
+ */
+void intel_gvt_clean_mmio_info(struct intel_gvt *gvt)
+{
+       struct hlist_node *tmp;
+       struct intel_gvt_mmio_info *e;
+       int i;
+
+       hash_for_each_safe(gvt->mmio.mmio_info_table, i, tmp, e, node)
+               kfree(e);
+
+       vfree(gvt->mmio.mmio_attribute);
+       gvt->mmio.mmio_attribute = NULL;
+}
+
+/**
+ * intel_gvt_setup_mmio_info - setup MMIO information table for GVT device
+ * @gvt: GVT device
+ *
+ * This function is called at the initialization stage, to setup the MMIO
+ * information table for GVT device
+ *
+ * Returns:
+ * zero on success, negative if failed.
+ */
+int intel_gvt_setup_mmio_info(struct intel_gvt *gvt)
+{
+       struct intel_gvt_device_info *info = &gvt->device_info;
+       struct drm_i915_private *dev_priv = gvt->dev_priv;
+       int ret;
+
+       gvt->mmio.mmio_attribute = vzalloc(info->mmio_size);
+       if (!gvt->mmio.mmio_attribute)
+               return -ENOMEM;
+
+       ret = init_generic_mmio_info(gvt);
+       if (ret)
+               goto err;
+
+       if (IS_BROADWELL(dev_priv)) {
+               ret = init_broadwell_mmio_info(gvt);
+               if (ret)
+                       goto err;
+       }
+       return 0;
+err:
+       intel_gvt_clean_mmio_info(gvt);
+       return ret;
+}
diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h
new file mode 100644 (file)
index 0000000..1fb1b49
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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:
+ *    Ke Yu
+ *    Kevin Tian <kevin.tian@intel.com>
+ *    Dexuan Cui
+ *
+ * Contributors:
+ *    Tina Zhang <tina.zhang@intel.com>
+ *    Min He <min.he@intel.com>
+ *    Niu Bing <bing.niu@intel.com>
+ *    Zhi Wang <zhi.a.wang@intel.com>
+ *
+ */
+
+#ifndef _GVT_MMIO_H_
+#define _GVT_MMIO_H_
+
+struct intel_gvt;
+struct intel_vgpu;
+
+#define D_SNB   (1 << 0)
+#define D_IVB   (1 << 1)
+#define D_HSW   (1 << 2)
+#define D_BDW   (1 << 3)
+#define D_SKL  (1 << 4)
+
+#define D_GEN9PLUS     (D_SKL)
+#define D_GEN8PLUS     (D_BDW | D_SKL)
+#define D_GEN75PLUS    (D_HSW | D_BDW | D_SKL)
+#define D_GEN7PLUS     (D_IVB | D_HSW | D_BDW | D_SKL)
+
+#define D_SKL_PLUS     (D_SKL)
+#define D_BDW_PLUS     (D_BDW | D_SKL)
+#define D_HSW_PLUS     (D_HSW | D_BDW | D_SKL)
+#define D_IVB_PLUS     (D_IVB | D_HSW | D_BDW | D_SKL)
+
+#define D_PRE_BDW      (D_SNB | D_IVB | D_HSW)
+#define D_PRE_SKL      (D_SNB | D_IVB | D_HSW | D_BDW)
+#define D_ALL          (D_SNB | D_IVB | D_HSW | D_BDW | D_SKL)
+
+struct intel_gvt_mmio_info {
+       u32 offset;
+       u32 size;
+       u32 length;
+       u32 addr_mask;
+       u64 ro_mask;
+       u32 device;
+       int (*read)(struct intel_vgpu *, unsigned int, void *, unsigned int);
+       int (*write)(struct intel_vgpu *, unsigned int, void *, unsigned int);
+       u32 addr_range;
+       struct hlist_node node;
+};
+
+unsigned long intel_gvt_get_device_type(struct intel_gvt *gvt);
+bool intel_gvt_match_device(struct intel_gvt *gvt, unsigned long device);
+
+int intel_gvt_setup_mmio_info(struct intel_gvt *gvt);
+void intel_gvt_clean_mmio_info(struct intel_gvt *gvt);
+
+struct intel_gvt_mmio_info *intel_gvt_find_mmio_info(struct intel_gvt *gvt,
+                                                    unsigned int offset);
+#define INTEL_GVT_MMIO_OFFSET(reg) ({ \
+       typeof(reg) __reg = reg; \
+       u32 *offset = (u32 *)&__reg; \
+       *offset; \
+})
+
+#endif