From 5dda8fa356587832e5373498d8b973d66735762d Mon Sep 17 00:00:00 2001 From: Yu Zhang Date: Tue, 10 Feb 2015 19:05:48 +0800 Subject: [PATCH] drm/i915: Adds graphic address space ballooning logic With Intel GVT-g, the global graphic memory space is partitioned by multiple vGPU instances in different VMs. The ballooning code is called 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. With ballooning, host side does not need to translate a grahpic address from guest view to host view. By now, current implementation only support the static ballooning, but in the future, with more cooperation from guest driver, the same interfaces can be extended to grow/shrink the guest graphic memory dynamically. v2: take Chris and Daniel's comments: - no guard page between different VMs - use drm_mm_reserve_node() to do the reservation for ballooning, instead of the previous drm_mm_insert_node_in_range_generic() v3: take Daniel's comments: - move ballooning functions into i915_vgpu.c - add kerneldoc to ballooning functions v4: take Tvrtko's comments: - more accurate comments and commit message Signed-off-by: Yu Zhang Signed-off-by: Jike Song Signed-off-by: Zhi Wang Signed-off-by: Eddie Dong Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 17 ++- drivers/gpu/drm/i915/i915_vgpu.c | 178 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_vgpu.h | 2 + 3 files changed, 194 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b48b586dc287..057f905b25b0 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -27,6 +27,7 @@ #include #include #include "i915_drv.h" +#include "i915_vgpu.h" #include "i915_trace.h" #include "intel_drv.h" @@ -1756,6 +1757,16 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev, /* 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)) { + ret = intel_vgt_balloon(dev); + if (ret) + return ret; + } + if (!HAS_LLC(dev)) dev_priv->gtt.base.mm.color_adjust = i915_gtt_color_adjust; @@ -1775,9 +1786,6 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev, vma->bound |= GLOBAL_BIND; } - 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", @@ -1829,6 +1837,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); } diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c index 995a6003ed78..5eee75bff170 100644 --- a/drivers/gpu/drm/i915/i915_vgpu.c +++ b/drivers/gpu/drm/i915/i915_vgpu.c @@ -84,3 +84,181 @@ void i915_check_vgpu(struct drm_device *dev) dev_priv->vgpu.active = true; DRM_INFO("Virtual GPU for Intel GVT-g detected.\n"); } + +struct _balloon_info_ { + /* + * There are up to 2 regions per mappable/unmappable graphic + * memory that might be ballooned. Here, index 0/1 is for mappable + * graphic memory, 2/3 for unmappable graphic memory. + */ + struct drm_mm_node space[4]; +}; + +static struct _balloon_info_ bl_info; + +/** + * intel_vgt_deballoon - deballoon reserved graphics address trunks + * + * This function is called to deallocate the ballooned-out graphic memory, when + * driver is unloaded or when ballooning fails. + */ +void intel_vgt_deballoon(void) +{ + int i; + + DRM_DEBUG("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 KiB.\n", + start, end, size / 1024); + + node->start = start; + node->size = size; + + return drm_mm_reserve_node(mm, node); +} + +/** + * intel_vgt_balloon - balloon out reserved graphics address trunks + * @dev: drm device + * + * This function is called at the initialization stage, to balloon out the + * graphic address space allocated to other vGPUs, by marking these spaces as + * reserved. The ballooning related knowledge(starting address and size of + * the mappable/unmappable graphic memory) is described in the vgt_if structure + * in a reserved mmio range. + * + * To give an example, the drawing below depicts one typical scenario after + * ballooning. Here the vGPU1 has 2 pieces of graphic address spaces ballooned + * out each for the mappable and the non-mappable part. From the vGPU1 point of + * view, the total size is the same as the physical one, with the start address + * of its graphic space being zero. Yet there are some portions ballooned out( + * the shadow part, which are marked as reserved by drm allocator). From the + * host point of view, the graphic address space is partitioned by multiple + * vGPUs in different VMs. + * + * vGPU1 view Host view + * 0 ------> +-----------+ +-----------+ + * ^ |///////////| | vGPU3 | + * | |///////////| +-----------+ + * | |///////////| | vGPU2 | + * | +-----------+ +-----------+ + * mappable GM | available | ==> | vGPU1 | + * | +-----------+ +-----------+ + * | |///////////| | | + * v |///////////| | Host | + * +=======+===========+ +===========+ + * ^ |///////////| | vGPU3 | + * | |///////////| +-----------+ + * | |///////////| | vGPU2 | + * | +-----------+ +-----------+ + * unmappable GM | available | ==> | vGPU1 | + * | +-----------+ +-----------+ + * | |///////////| | | + * | |///////////| | Host | + * v |///////////| | | + * total GM size ------> +-----------+ +-----------+ + * + * Returns: + * zero on success, non-zero if configuration invalid or ballooning failed + */ +int intel_vgt_balloon(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + struct i915_address_space *ggtt_vm = &dev_priv->gtt.base; + unsigned long ggtt_vm_end = ggtt_vm->start + ggtt_vm->total; + + unsigned long mappable_base, mappable_size, mappable_end; + unsigned long unmappable_base, unmappable_size, unmappable_end; + int ret; + + mappable_base = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.base)); + mappable_size = I915_READ(vgtif_reg(avail_rs.mappable_gmadr.size)); + unmappable_base = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.base)); + unmappable_size = I915_READ(vgtif_reg(avail_rs.nonmappable_gmadr.size)); + + mappable_end = mappable_base + mappable_size; + unmappable_end = unmappable_base + unmappable_size; + + DRM_INFO("VGT ballooning configuration:\n"); + DRM_INFO("Mappable graphic memory: base 0x%lx size %ldKiB\n", + mappable_base, mappable_size / 1024); + DRM_INFO("Unmappable graphic memory: base 0x%lx size %ldKiB\n", + unmappable_base, unmappable_size / 1024); + + if (mappable_base < ggtt_vm->start || + mappable_end > dev_priv->gtt.mappable_end || + unmappable_base < dev_priv->gtt.mappable_end || + unmappable_end > ggtt_vm_end) { + DRM_ERROR("Invalid ballooning configuration!\n"); + return -EINVAL; + } + + /* Unmappable graphic memory ballooning */ + if (unmappable_base > dev_priv->gtt.mappable_end) { + ret = vgt_balloon_space(&ggtt_vm->mm, + &bl_info.space[2], + dev_priv->gtt.mappable_end, + unmappable_base); + + if (ret) + goto err; + } + + /* + * No need to partition out the last physical page, + * because it is reserved to the guard page. + */ + if (unmappable_end < ggtt_vm_end - PAGE_SIZE) { + ret = vgt_balloon_space(&ggtt_vm->mm, + &bl_info.space[3], + unmappable_end, + ggtt_vm_end - PAGE_SIZE); + if (ret) + goto err; + } + + /* Mappable graphic memory ballooning */ + if (mappable_base > ggtt_vm->start) { + ret = vgt_balloon_space(&ggtt_vm->mm, + &bl_info.space[0], + ggtt_vm->start, mappable_base); + + if (ret) + goto err; + } + + if (mappable_end < dev_priv->gtt.mappable_end) { + ret = vgt_balloon_space(&ggtt_vm->mm, + &bl_info.space[1], + mappable_end, + 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 ret; +} diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h index aa72e146d6c8..3ed01a7ac48e 100644 --- a/drivers/gpu/drm/i915/i915_vgpu.h +++ b/drivers/gpu/drm/i915/i915_vgpu.h @@ -81,5 +81,7 @@ struct vgt_if { (VGT_PVINFO_PAGE + (long)&((struct vgt_if *)NULL)->x) extern void i915_check_vgpu(struct drm_device *dev); +extern int intel_vgt_balloon(struct drm_device *dev); +extern void intel_vgt_deballoon(void); #endif /* _I915_VGPU_H_ */ -- 2.39.5