From patchwork Thu Jan 28 10:21:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wang, Zhi A" X-Patchwork-Id: 8148501 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 96D6F9F440 for ; Thu, 28 Jan 2016 10:24:12 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2E0E82035B for ; Thu, 28 Jan 2016 10:24:11 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 5140120364 for ; Thu, 28 Jan 2016 10:24:09 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C48956E7F2; Thu, 28 Jan 2016 02:24:08 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by gabe.freedesktop.org (Postfix) with ESMTP id BA0B86E7F2 for ; Thu, 28 Jan 2016 02:24:06 -0800 (PST) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP; 28 Jan 2016 02:24:07 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.22,358,1449561600"; d="scan'208";a="870588019" Received: from dev-inno.bj.intel.com ([10.238.135.69]) by orsmga001.jf.intel.com with ESMTP; 28 Jan 2016 02:24:03 -0800 From: Zhi Wang To: intel-gfx@lists.freedesktop.org, igvt-g@lists.01.org Date: Thu, 28 Jan 2016 18:21:31 +0800 Message-Id: <1453976511-27322-10-git-send-email-zhi.a.wang@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1453976511-27322-1-git-send-email-zhi.a.wang@intel.com> References: <1453976511-27322-1-git-send-email-zhi.a.wang@intel.com> Cc: daniel.vetter@ffwll.ch, david.j.cowperthwaite@intel.com Subject: [Intel-gfx] [RFC 09/29] drm/i915: gvt: Resource allocator X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Yulei Zhang 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 Signed-off-by: Zhi Wang --- 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