[RFC,09/29] drm/i915: gvt: Resource allocator

Submitted by Wang, Zhi A on Jan. 28, 2016, 10:21 a.m.

Details

Message ID 1453976511-27322-10-git-send-email-zhi.a.wang@intel.com
State New
Headers show
Series "iGVT-g implementation in i915" ( rev: 1 ) in Intel GFX

Not browsing as part of any series.

Commit Message

Wang, Zhi A Jan. 28, 2016, 10:21 a.m.
From: Yulei Zhang <yulei.zhang@intel.com>

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

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

Patch hide | download patch | download mbox

diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile
index 6935b78..6655929 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -1,4 +1,4 @@ 
-GVT_SOURCE := gvt.o params.o fb_decoder.o
+GVT_SOURCE := gvt.o params.o aperture_gm.o fb_decoder.o
 
 ccflags-y			+= -I$(src) -I$(src)/.. -Wall -Werror -Wno-unused-function
 i915_gvt-y			:= $(GVT_SOURCE)
diff --git a/drivers/gpu/drm/i915/gvt/aperture_gm.c b/drivers/gpu/drm/i915/gvt/aperture_gm.c
new file mode 100644
index 0000000..7cb15c1
--- /dev/null
+++ b/drivers/gpu/drm/i915/gvt/aperture_gm.c
@@ -0,0 +1,225 @@ 
+/*
+ * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "gvt.h"
+
+void init_gm_allocator(struct pgt_device *pdev,
+		u64 start, u64 size, bool mappable)
+{
+	struct drm_mm *mm = mappable ?
+		&pdev->gm_allocator.low_gm : &pdev->gm_allocator.high_gm;
+
+	drm_mm_init(mm, start, size);
+}
+
+void clean_gm_allocator(struct pgt_device *pdev)
+{
+	if (!drm_mm_initialized(&pdev->gm_allocator.low_gm)
+			|| !drm_mm_initialized(&pdev->gm_allocator.high_gm))
+		return;
+
+	drm_mm_takedown(&pdev->gm_allocator.low_gm);
+	drm_mm_takedown(&pdev->gm_allocator.high_gm);
+}
+
+struct drm_mm_node *alloc_gm_node(struct pgt_device *pdev, u32 size, bool mappable)
+{
+	struct drm_mm_node *node;
+	struct drm_mm *mm = mappable ?
+		&pdev->gm_allocator.low_gm : &pdev->gm_allocator.high_gm;
+	int ret;
+
+	if (!drm_mm_initialized(mm))
+		return NULL;
+
+	DRM_DEBUG_KMS("creating vgt %s object: size=%x\n",
+			mappable ? "mappable" : "unmappable", size);
+	if (size == 0)
+		return NULL;
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node)
+		return NULL;
+
+	ret = drm_mm_insert_node(mm, node, size,
+			PAGE_SIZE, DRM_MM_SEARCH_DEFAULT);
+	if (ret) {
+		kfree(node);
+		return NULL;
+	}
+
+	return node;
+}
+
+void free_gm_node(struct drm_mm_node *node)
+{
+	drm_mm_remove_node(node);
+	kfree(node);
+}
+
+static bool check_instance_info(struct vgt_device *vgt,
+		struct gvt_instance_info *info)
+{
+	struct pgt_device *pdev = vgt->pdev;
+
+	if (gvt_aperture_base(vgt)) {
+		gvt_err("resources have already been allocated");
+		return false;
+	}
+
+	if (!info->low_gm_sz || !info->high_gm_sz || !info->fence_sz ||
+		info->low_gm_sz > phys_aperture_sz(pdev) ||
+		info->high_gm_sz > gm_sz(pdev) - phys_aperture_sz(pdev)) {
+		gvt_err("invalid resource configuration");
+		gvt_err("demand low GM size %u max low GM size %llu",
+			info->low_gm_sz, phys_aperture_sz(pdev));
+		gvt_err("demand high GM size %u max high GM size %llu",
+			info->high_gm_sz, gm_sz(pdev) - phys_aperture_sz(pdev));
+		gvt_err("fence size %u", info->fence_sz);
+		return false;
+	}
+
+	return true;
+}
+
+static void clear_fence(struct vgt_device *vgt)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	int i;
+
+	for (i = 0; i < gvt_fence_sz(vgt); i++)
+		gvt_mmio_write64(pdev,
+			i915_mmio_reg_offset(FENCE_REG_GEN6_LO(i + gvt_fence_base(vgt))), 0);
+}
+
+void gvt_free_gm_and_fence_resource(struct vgt_device *vgt)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	unsigned long *fence_bitmap = pdev->fence_bitmap;
+
+	if (vgt->state.gm.node.low_gm_node) {
+		free_gm_node(vgt->state.gm.node.low_gm_node);
+		vgt->state.gm.node.low_gm_node = NULL;
+	}
+
+	if (vgt->state.gm.node.high_gm_node) {
+		free_gm_node(vgt->state.gm.node.high_gm_node);
+		vgt->state.gm.node.high_gm_node = NULL;
+	}
+
+	if (gvt_fence_sz(vgt) && gvt_fence_base(vgt)) {
+		bitmap_clear(fence_bitmap, gvt_fence_base(vgt), gvt_fence_sz(vgt));
+		clear_fence(vgt);
+		gvt_fence_sz(vgt) = gvt_fence_base(vgt) = 0;
+	}
+}
+
+int gvt_alloc_gm_and_fence_resource(struct vgt_device *vgt,
+	struct gvt_instance_info *info)
+{
+	struct pgt_device *pdev = vgt->pdev;
+	struct drm_mm_node *node;
+	unsigned long *fence_bitmap = pdev->fence_bitmap;
+	unsigned long fence_base;
+
+	if (!check_instance_info(vgt, info)) {
+		gvt_err("invalid resoure configuration");
+		return -EINVAL;
+	}
+
+	node = alloc_gm_node(pdev, info->low_gm_sz << 20, true);
+	if (!node) {
+		gvt_err("fail to allocate low GM space");
+		goto err;
+	}
+
+	vgt->state.gm.node.low_gm_node = node;
+
+	gvt_aperture_base(vgt) = phys_aperture_base(vgt->pdev) + node->start;
+	gvt_aperture_sz(vgt) = info->low_gm_sz << 20;
+
+	node = alloc_gm_node(pdev, info->high_gm_sz << 20, false);
+	if (!node) {
+		gvt_err("fail to allocate high GM space");
+		goto err;
+	}
+
+	vgt->state.gm.node.high_gm_node = node;
+
+	gvt_hidden_gm_offset(vgt) = node->start;
+	gvt_gm_sz(vgt) = (info->low_gm_sz + info->high_gm_sz) << 20;
+
+	fence_base = bitmap_find_next_zero_area(fence_bitmap,
+				GVT_FENCE_BITMAP_BITS, 0, info->fence_sz, 0);
+	if (fence_base >= GVT_MAX_NUM_FENCES) {
+		gvt_err("fail to allocate fence");
+		goto err;
+	}
+
+	gvt_fence_base(vgt) = fence_base;
+	gvt_fence_sz(vgt) = info->fence_sz;
+
+	bitmap_set(fence_bitmap, fence_base, info->fence_sz);
+
+	clear_fence(vgt);
+
+	return 0;
+err:
+	gvt_free_gm_and_fence_resource(vgt);
+	return -ENOMEM;
+}
+
+void gvt_init_resource_allocator(struct pgt_device *pdev)
+{
+	struct gvt_device_info *info = &pdev->device_info;
+	int i;
+	unsigned long *fence_bitmap = pdev->fence_bitmap;
+
+	gvt_info("total aperture: 0x%llx bytes, total GM space: 0x%llx bytes\n",
+		phys_aperture_sz(pdev), gm_sz(pdev));
+
+	ASSERT(phys_aperture_sz(pdev) % (1 << 20) == 0);
+	ASSERT(gm_sz(pdev) % (1 << 20) == 0);
+	ASSERT(phys_aperture_sz(pdev) <= gm_sz(pdev) && gm_sz(pdev) <= info->max_gtt_gm_sz);
+	ASSERT(info->max_gtt_gm_sz <= GVT_MAX_GM_SIZE);
+
+	/* Basic memrange allocator for vgt low memory */
+	init_gm_allocator(pdev, gvt.dom0_low_gm_sz << 20,
+			(phys_aperture_sz(pdev) - (gvt.dom0_low_gm_sz << 20)), true);
+
+	/* Basic memrange allocate for vgt high memory */
+	init_gm_allocator(pdev,
+			(phys_aperture_sz(pdev) + (gvt.dom0_high_gm_sz << 20)),
+			(gm_sz(pdev) - (gvt.dom0_high_gm_sz << 20)), false);
+
+	/* Reserve fence region for dom0 */
+	bitmap_set(fence_bitmap, 0, gvt.dom0_fence_sz);
+
+	for (i = 0; i < gvt.dom0_fence_sz; i++)
+		gvt_mmio_write64(pdev, i915_mmio_reg_offset(FENCE_REG_GEN6_LO(i)), 0);
+}
+
+void gvt_clean_resource_allocator(struct pgt_device *pdev)
+{
+	clean_gm_allocator(pdev);
+}
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index 041d10f..f31e9f7 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -234,6 +234,7 @@  static void clean_pgt_device(struct pgt_device *pdev)
 {
 	clean_service_thread(pdev);
 	clean_initial_mmio_state(pdev);
+	gvt_clean_resource_allocator(pdev);
 }
 
 static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *dev_priv)
@@ -246,6 +247,8 @@  static bool init_pgt_device(struct pgt_device *pdev, struct drm_i915_private *de
 	if (!init_initial_mmio_state(pdev))
 		goto err;
 
+	gvt_init_resource_allocator(pdev);
+
 	if (!init_service_thread(pdev))
 		goto err;
 
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
index 6c85bba..aa4851c 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -36,6 +36,11 @@ 
 
 #define GVT_MAX_VGPU 8
 
+#define GVT_MAX_GM_SIZE		(1UL << 32)
+#define GVT_GM_BITMAP_BITS	(GVT_MAX_GM_SIZE >> 20)
+#define GVT_MAX_NUM_FENCES	32
+#define GVT_FENCE_BITMAP_BITS	GVT_MAX_NUM_FENCES
+
 enum {
 	GVT_HYPERVISOR_TYPE_XEN = 0,
 	GVT_HYPERVISOR_TYPE_KVM,
@@ -62,11 +67,38 @@  struct gvt_device_info {
 	u32 gmadr_bytes_in_cmd;
 };
 
+struct gvt_gm_node {
+	struct drm_mm_node *low_gm_node;
+	struct drm_mm_node *high_gm_node;
+};
+
+struct gvt_virtual_gm_state {
+	u64 aperture_base;
+	void *aperture_base_va;
+	u64 aperture_sz;
+	u64 gm_sz;
+	u64 aperture_offset;        /* address fix for visible GM */
+	u64 hidden_gm_offset;       /* address fix for invisible GM */
+	int fence_base;
+	int fence_sz;
+	struct gvt_gm_node node;
+};
+
+struct gvt_virtual_device_state {
+	struct gvt_virtual_gm_state gm;
+};
+
 struct vgt_device {
 	int id;
 	int vm_id;
 	struct pgt_device *pdev;
 	bool warn_untrack;
+	struct gvt_virtual_device_state state;
+};
+
+struct gvt_gm_allocator {
+	struct drm_mm low_gm;
+	struct drm_mm high_gm;
 };
 
 struct pgt_device {
@@ -93,8 +125,81 @@  struct pgt_device {
 	wait_queue_head_t service_thread_wq;
 	struct task_struct *service_thread;
 	unsigned long service_request;
+
+	/* 1 bit corresponds to 1MB in the GM space */
+	DECLARE_BITMAP(gm_bitmap, GVT_GM_BITMAP_BITS);
+
+	/* 1 bit corresponds to 1 fence register */
+	DECLARE_BITMAP(fence_bitmap, GVT_FENCE_BITMAP_BITS);
+
+	u64 total_gm_sz;
+	struct gvt_gm_allocator gm_allocator;
 };
 
+/* definitions for physical aperture/GM space */
+#define phys_aperture_sz(pdev)          (pdev->bar_size[1])
+#define phys_aperture_pages(pdev)       (phys_aperture_sz(pdev) >> GTT_PAGE_SHIFT)
+#define phys_aperture_base(pdev)        (pdev->gmadr_base)
+#define phys_aperture_vbase(pdev)       (pdev->gmadr_va)
+
+#define gm_sz(pdev)                     (pdev->total_gm_sz)
+#define gm_base(pdev)                   (0ULL)
+#define gm_pages(pdev)                  (gm_sz(pdev) >> GTT_PAGE_SHIFT)
+#define hidden_gm_base(pdev)            (phys_aperture_sz(pdev))
+
+#define aperture_2_gm(pdev, addr)       (addr - phys_aperture_base(pdev))
+#define v_aperture(pdev, addr)          (phys_aperture_vbase(pdev) + (addr))
+
+/* definitions for vgt's aperture/gm space */
+#define gvt_aperture_base(vgt)		(vgt->state.gm.aperture_base)
+#define gvt_aperture_vbase(vgt)		(vgt->state.gm.aperture_base_va)
+#define gvt_aperture_offset(vgt)	(vgt->state.gm.aperture_offset)
+#define gvt_hidden_gm_offset(vgt)	(vgt->state.gm.hidden_gm_offset)
+#define gvt_aperture_sz(vgt)		(vgt->state.gm.aperture_sz)
+#define gvt_gm_sz(vgt)			(vgt->state.gm.gm_sz)
+#define gvt_hidden_gm_sz(vgt)		(gvt_gm_sz(vgt) - gvt_aperture_sz(vgt))
+#define gvt_fence_base(vgt)		(vgt->state.gm.fence_base)
+#define gvt_fence_sz(vgt)		(vgt->state.gm.fence_sz)
+
+#define gvt_aperture_end(vgt)           \
+	(gvt_aperture_base(vgt) + gvt_aperture_sz(vgt) - 1)
+#define gvt_visible_gm_base(vgt)        \
+	(gm_base(vgt->pdev) + gvt_aperture_offset(vgt))
+#define gvt_visible_gm_end(vgt)         \
+	(gvt_visible_gm_base(vgt) + gvt_aperture_sz(vgt) - 1)
+#define gvt_hidden_gm_base(vgt) \
+	(gm_base(vgt->pdev) + gvt_hidden_gm_offset(vgt))
+#define gvt_hidden_gm_end(vgt)          \
+	(gvt_hidden_gm_base(vgt) + gvt_hidden_gm_sz(vgt) - 1)
+
+/*
+ * the view of the aperture/gm space from the VM's p.o.v
+ *
+ * when the VM supports ballooning, this view is the same as the
+ * view of vGT driver.
+ *
+ * when the VM does not support ballooning, this view starts from
+ * GM space ZERO
+ */
+#define gvt_guest_aperture_base(vgt)    \
+	((*((u32*)&vgt->state.cfg.space[GVT_REG_CFG_SPACE_BAR1]) & ~0xf) + gvt_aperture_offset(vgt))
+#define gvt_guest_aperture_end(vgt)     \
+        (gvt_guest_aperture_base(vgt) + gvt_aperture_sz(vgt) - 1)
+#define gvt_guest_visible_gm_base(vgt)  \
+        (gvt_visible_gm_base(vgt))
+#define gvt_guest_visible_gm_end(vgt)   \
+        (gvt_guest_visible_gm_base(vgt) + gvt_aperture_sz(vgt) - 1)
+#define gvt_guest_hidden_gm_base(vgt)   \
+	gvt_hidden_gm_base(vgt)
+#define gvt_guest_hidden_gm_end(vgt)    \
+        (gvt_guest_hidden_gm_base(vgt) + gvt_hidden_gm_sz(vgt) - 1)
+
+extern void gvt_init_resource_allocator(struct pgt_device *pdev);
+extern void gvt_clean_resource_allocator(struct pgt_device *pdev);
+extern int gvt_alloc_gm_and_fence_resource(struct vgt_device *vgt,
+		struct gvt_instance_info *info);
+extern void gvt_free_gm_and_fence_resource(struct vgt_device *vgt);
+
 static inline u32 gvt_mmio_read(struct pgt_device *pdev,
 		u32 reg)
 {
diff --git a/drivers/gpu/drm/i915/gvt/params.c b/drivers/gpu/drm/i915/gvt/params.c
index dfc33c3..6cd324c 100644
--- a/drivers/gpu/drm/i915/gvt/params.c
+++ b/drivers/gpu/drm/i915/gvt/params.c
@@ -26,4 +26,16 @@ 
 struct gvt_kernel_params gvt = {
 	.enable = true,
 	.debug = 0,
+	.dom0_low_gm_sz = 96,
+	.dom0_high_gm_sz = 384,
+	.dom0_fence_sz = 4,
 };
+
+module_param_named(dom0_low_gm_sz, gvt.dom0_low_gm_sz, int, 0600);
+MODULE_PARM_DESC(dom0_low_gm_sz, "Amount of aperture size of DOM0");
+
+module_param_named(dom0_high_gm_sz, gvt.dom0_high_gm_sz, int, 0600);
+MODULE_PARM_DESC(dom0_high_gm_sz, "Amount of high memory size of DOM0");
+
+module_param_named(dom0_fence_sz, gvt.dom0_fence_sz, int, 0600);
+MODULE_PARM_DESC(dom0_fence_sz, "Amount of fence size of DOM0");
diff --git a/drivers/gpu/drm/i915/gvt/params.h b/drivers/gpu/drm/i915/gvt/params.h
index 0656a98..0507870 100644
--- a/drivers/gpu/drm/i915/gvt/params.h
+++ b/drivers/gpu/drm/i915/gvt/params.h
@@ -34,4 +34,12 @@  struct gvt_kernel_params {
 
 extern struct gvt_kernel_params gvt;
 
+struct gvt_instance_info {
+	u32 domid;
+	u32 low_gm_sz;
+	u32 high_gm_sz;
+	u32 fence_sz;
+	s32 primary;
+};
+
 #endif