[Intel-gfx] [PATCH 2/8] drm/i915: Adds graphic address space ballooning logic

Jike Song jike.song at intel.com
Fri Sep 19 20:47:02 CEST 2014


From: Yu Zhang <yu.c.zhang at intel.com>

In XenGT, the global graphic memory space is partitioned by multiple
vgpu instances in different VMs. The ballooning code is added in
i915_gem_setup_global_gtt(), utilizing the drm mm allocator APIs to
mark the graphic address space which are partitioned out to other
vgpus as reserved.
One special treatment for this scenario is that the guard page is
added at the end of both aperture and non-aperture spaces. This is
to follow the behavior pattern in native case. However here we have
a question: does the prefetch issue mentioned at the begining of
i915_gem_setup_global_gtt() happens for all the GTT entries, or just
at then end of the BAR0 space? If all entries may have prefetch issues,
then this special guard page is necessary, to protect unexpected
accesses into GTT entries partitioned out by other VMs. Otherwise,
we may only need one guard page at the end of the physical GTT space.

Signed-off-by: Yu Zhang <yu.c.zhang at intel.com>
Signed-off-by: Jike Song <jike.song at intel.com>
Signed-off-by: Zhi Wang <zhi.a.wang at intel.com>
Signed-off-by: Eddie Dong <eddie.dong at intel.com>
---
 drivers/gpu/drm/i915/i915_gem_gtt.c | 179 ++++++++++++++++++++++++++++++++++--
 1 file changed, 171 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 0309a2d..368262d 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -30,6 +30,159 @@
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+struct _balloon_info_ {
+	/*
+	 * There are up to 2 regions per low/high GM that
+	 * might be ballooned. Here, index 0/1 is for low
+	 * GM, 2/3 for high GM.
+	 */
+	struct drm_mm_node space[4];
+} bl_info;
+
+void intel_vgt_deballoon(void)
+{
+	int i;
+
+	DRM_INFO("VGT deballoon.\n");
+
+	for (i = 0; i < 4; i++) {
+		if (bl_info.space[i].allocated)
+			drm_mm_remove_node(&bl_info.space[i]);
+	}
+
+	memset(&bl_info, 0, sizeof(bl_info));
+}
+
+static int vgt_balloon_space(struct drm_mm *mm,
+			     struct drm_mm_node *node,
+			     unsigned long start, unsigned long end)
+{
+	unsigned long size = end - start;
+
+	if (start == end)
+		return -EINVAL;
+
+	DRM_INFO("balloon space: range [ 0x%lx - 0x%lx ] %lu KB.\n",
+		 start, end, size / 1024);
+
+	return drm_mm_insert_node_in_range_generic(mm, node, size, 0, 0,
+						   start, end,
+						   DRM_MM_SEARCH_DEFAULT,
+						   DRM_MM_CREATE_DEFAULT);
+}
+
+static int intel_vgt_balloon(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct i915_address_space *ggtt_vm = &dev_priv->gtt.base;
+
+	unsigned long low_gm_base, low_gm_size, low_gm_end;
+	unsigned long high_gm_base, high_gm_size, high_gm_end;
+	int ret;
+
+	low_gm_base = I915_READ(vgt_info_off(avail_rs.low_gmadr.my_base));
+	low_gm_size = I915_READ(vgt_info_off(avail_rs.low_gmadr.my_size));
+	high_gm_base = I915_READ(vgt_info_off(avail_rs.high_gmadr.my_base));
+	high_gm_size = I915_READ(vgt_info_off(avail_rs.high_gmadr.my_size));
+
+	low_gm_end = low_gm_base + low_gm_size;
+	high_gm_end = high_gm_base + high_gm_size;
+
+	DRM_INFO("VGT ballooning configuration:\n");
+	DRM_INFO("Low GM: base 0x%lx size %ldKB\n",
+		 low_gm_base, low_gm_size / 1024);
+	DRM_INFO("High GM: base 0x%lx size %ldKB\n",
+		 high_gm_base, high_gm_size / 1024);
+
+	if (low_gm_base < ggtt_vm->start
+	    || low_gm_end > dev_priv->gtt.mappable_end
+	    || high_gm_base < dev_priv->gtt.mappable_end
+	    || high_gm_end > ggtt_vm->start + ggtt_vm->total) {
+		DRM_ERROR("Invalid ballooning configuration!\n");
+		return -EINVAL;
+	}
+
+	memset(&bl_info, 0, sizeof(bl_info));
+
+	/* High GM ballooning */
+	if (high_gm_base > dev_priv->gtt.mappable_end) {
+		ret = vgt_balloon_space(&ggtt_vm->mm,
+					&bl_info.space[2],
+					dev_priv->gtt.mappable_end,
+					high_gm_base);
+
+		if (ret)
+			goto err;
+	}
+
+	if (high_gm_end <= ggtt_vm->start + ggtt_vm->total) {
+		/*
+		 * We need a guard page per low/high GM for each vgpu.
+		 * Here, leave one page at the end of the allocated high
+		 * GM reserved to the scratch page, and balloon it out,
+		 * to serve as guard page.
+		 */
+		if (high_gm_size > PAGE_SIZE) {
+			high_gm_size -= PAGE_SIZE;
+			ggtt_vm->clear_range(ggtt_vm,
+					     high_gm_base + high_gm_size,
+					     PAGE_SIZE, true);
+		} else {
+			BUG_ON(high_gm_size != 0);
+		}
+
+		ret = vgt_balloon_space(&ggtt_vm->mm,
+					&bl_info.space[3],
+					high_gm_base + high_gm_size,
+					ggtt_vm->start + ggtt_vm->total);
+		if (ret)
+			goto err;
+	}
+
+	/* Low GM ballooning */
+	if (low_gm_base > ggtt_vm->start) {
+		ret = vgt_balloon_space(&ggtt_vm->mm,
+					&bl_info.space[0],
+					ggtt_vm->start, low_gm_base);
+
+		if (ret)
+			goto err;
+	}
+
+	if (low_gm_end <= dev_priv->gtt.mappable_end) {
+		/*
+		 * We need a guard page per low/high GM for each vgpu.
+		 * Here, leave one page at the end of the allocated low
+		 * GM reserved to the scratch page, and balloon it out,
+		 * to serve as guard page.
+		 */
+		if (low_gm_size > PAGE_SIZE) {
+			low_gm_size -= PAGE_SIZE;
+			ggtt_vm->clear_range(ggtt_vm,
+					     low_gm_base + low_gm_size,
+					     PAGE_SIZE, true);
+		} else {
+			BUG_ON(low_gm_size != 0);
+		}
+
+		ret = vgt_balloon_space(&ggtt_vm->mm,
+					&bl_info.space[1],
+					low_gm_base + low_gm_size,
+					dev_priv->gtt.mappable_end);
+
+		if (ret)
+			goto err;
+	}
+
+	DRM_INFO("VGT balloon successfully\n");
+	return 0;
+
+err:
+	DRM_ERROR("VGT balloon fail\n");
+	intel_vgt_deballoon();
+	return -ENOMEM;
+}
+
 void i915_check_vgpu(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1682,8 +1835,21 @@ int i915_gem_setup_global_gtt(struct drm_device *dev,
 
 	BUG_ON(mappable_end > end);
 
-	/* Subtract the guard page ... */
-	drm_mm_init(&ggtt_vm->mm, start, end - start - PAGE_SIZE);
+	dev_priv->gtt.base.start = start;
+	dev_priv->gtt.base.total = end - start;
+
+	if (intel_vgpu_active(dev)) {
+		drm_mm_init(&ggtt_vm->mm, start, end - start);
+		ret = intel_vgt_balloon(dev);
+		if (ret)
+			return ret;
+	} else {
+		/* Subtract the guard page ... */
+		drm_mm_init(&ggtt_vm->mm, start, end - start - PAGE_SIZE);
+		/* Clear the reserved guard page */
+		ggtt_vm->clear_range(ggtt_vm, end - PAGE_SIZE, PAGE_SIZE, true);
+	}
+
 	if (!HAS_LLC(dev))
 		dev_priv->gtt.base.mm.color_adjust = i915_gtt_color_adjust;
 
@@ -1703,9 +1869,6 @@ int i915_gem_setup_global_gtt(struct drm_device *dev,
 		obj->has_global_gtt_mapping = 1;
 	}
 
-	dev_priv->gtt.base.start = start;
-	dev_priv->gtt.base.total = end - start;
-
 	/* Clear any non-preallocated blocks */
 	drm_mm_for_each_hole(entry, &ggtt_vm->mm, hole_start, hole_end) {
 		DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n",
@@ -1714,9 +1877,6 @@ int i915_gem_setup_global_gtt(struct drm_device *dev,
 				     hole_end - hole_start, true);
 	}
 
-	/* And finally clear the reserved guard page */
-	ggtt_vm->clear_range(ggtt_vm, end - PAGE_SIZE, PAGE_SIZE, true);
-
 	if (USES_PPGTT(dev) && !USES_FULL_PPGTT(dev)) {
 		struct i915_hw_ppgtt *ppgtt;
 
@@ -1757,6 +1917,9 @@ void i915_global_gtt_cleanup(struct drm_device *dev)
 	}
 
 	if (drm_mm_initialized(&vm->mm)) {
+		if (intel_vgpu_active(dev))
+			intel_vgt_deballoon();
+
 		drm_mm_takedown(&vm->mm);
 		list_del(&vm->global_link);
 	}
-- 
1.9.1




More information about the Intel-gfx mailing list