[Intel-gfx] [RFC 09/29] drm/i915: gvt: Resource allocator
Zhi Wang
zhi.a.wang at intel.com
Thu Jan 28 02:21:31 PST 2016
From: Yulei Zhang <yulei.zhang at 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 at intel.com>
Signed-off-by: Zhi Wang <zhi.a.wang at 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
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
--
1.9.1
More information about the Intel-gfx
mailing list