From: Yulei Zhang <yulei.zhang@xxxxxxxxx> 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@xxxxxxxxx> Signed-off-by: Zhi Wang <zhi.a.wang@xxxxxxxxx> --- 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 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx