From patchwork Thu Feb 14 14:57:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Matthew Auld X-Patchwork-Id: 10812905 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4076E13B5 for ; Thu, 14 Feb 2019 14:57:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2DA702E900 for ; Thu, 14 Feb 2019 14:57:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 217D82E907; Thu, 14 Feb 2019 14:57:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id C690A2E900 for ; Thu, 14 Feb 2019 14:57:54 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 8ADF16E916; Thu, 14 Feb 2019 14:57:52 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by gabe.freedesktop.org (Postfix) with ESMTPS id 0313C6E90E for ; Thu, 14 Feb 2019 14:57:47 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 14 Feb 2019 06:57:47 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.58,369,1544515200"; d="scan'208";a="114920428" Received: from jhbrinke-mobl3.amr.corp.intel.com (HELO mwahaha.ger.corp.intel.com) ([10.252.11.151]) by orsmga007.jf.intel.com with ESMTP; 14 Feb 2019 06:57:46 -0800 From: Matthew Auld To: intel-gfx@lists.freedesktop.org Date: Thu, 14 Feb 2019 14:57:02 +0000 Message-Id: <20190214145740.14521-5-matthew.auld@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190214145740.14521-1-matthew.auld@intel.com> References: <20190214145740.14521-1-matthew.auld@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [RFC PATCH 04/42] drm/i915: introduce intel_memory_region X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP Support memory regions, as defined by a given (start, end), and allow creating GEM objects which are backed by said region. Signed-off-by: Matthew Auld Signed-off-by: Abdiel Janulgue Cc: Joonas Lahtinen --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 1 + drivers/gpu/drm/i915/i915_gem_object.h | 9 + drivers/gpu/drm/i915/intel_memory_region.c | 232 ++++++++++++++++++ drivers/gpu/drm/i915/intel_memory_region.h | 126 ++++++++++ drivers/gpu/drm/i915/selftests/huge_pages.c | 81 ++++++ .../drm/i915/selftests/i915_mock_selftests.h | 1 + .../drm/i915/selftests/intel_memory_region.c | 128 ++++++++++ .../gpu/drm/i915/selftests/mock_gem_device.c | 1 + drivers/gpu/drm/i915/selftests/mock_region.c | 71 ++++++ drivers/gpu/drm/i915/selftests/mock_region.h | 35 +++ 12 files changed, 687 insertions(+) create mode 100644 drivers/gpu/drm/i915/intel_memory_region.c create mode 100644 drivers/gpu/drm/i915/intel_memory_region.h create mode 100644 drivers/gpu/drm/i915/selftests/intel_memory_region.c create mode 100644 drivers/gpu/drm/i915/selftests/mock_region.c create mode 100644 drivers/gpu/drm/i915/selftests/mock_region.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index e5ce813d1936..96be264fa382 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -88,6 +88,7 @@ i915-y += \ intel_engine_cs.o \ intel_hangcheck.o \ intel_lrc.o \ + intel_memory_region.o \ intel_mocs.o \ intel_ringbuffer.o \ intel_uncore.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 17fe942eaafa..0bea7d889284 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -72,6 +72,7 @@ #include "intel_wopcm.h" #include "intel_workarounds.h" #include "intel_uc.h" +#include "intel_memory_region.h" #include "i915_gem.h" #include "i915_gem_context.h" diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b421bc7a2e26..92768ab294a4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5706,4 +5706,5 @@ int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align) #include "selftests/i915_gem_object.c" #include "selftests/i915_gem_coherency.c" #include "selftests/i915_gem.c" +#include "selftests/intel_memory_region.c" #endif diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h index fab040331cdb..ac52f61e8ad1 100644 --- a/drivers/gpu/drm/i915/i915_gem_object.h +++ b/drivers/gpu/drm/i915/i915_gem_object.h @@ -87,6 +87,15 @@ struct drm_i915_gem_object { const struct drm_i915_gem_object_ops *ops; + /** + * Memory region for this object. + */ + struct intel_memory_region *memory_region; + /** + * List of memory region blocks allocated for this object. + */ + struct list_head blocks; + struct { /** * @vma.lock: protect the list/tree of vmas diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c new file mode 100644 index 000000000000..405d6d51194f --- /dev/null +++ b/drivers/gpu/drm/i915/intel_memory_region.c @@ -0,0 +1,232 @@ +/* + * Copyright © 2018 Intel Corporation + * + * 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 "intel_memory_region.h" +#include "i915_drv.h" + +static void +memory_region_free_pages(struct drm_i915_gem_object *obj, + struct sg_table *pages) +{ + + struct i915_gem_buddy_block *block, *on; + + lockdep_assert_held(&obj->memory_region->mm_lock); + + list_for_each_entry_safe(block, on, &obj->blocks, link) { + list_del_init(&block->link); + i915_gem_buddy_free(&obj->memory_region->mm, block); + } + + sg_free_table(pages); + kfree(pages); +} + +void +i915_memory_region_put_pages_buddy(struct drm_i915_gem_object *obj, + struct sg_table *pages) +{ + mutex_lock(&obj->memory_region->mm_lock); + memory_region_free_pages(obj, pages); + mutex_unlock(&obj->memory_region->mm_lock); + + obj->mm.dirty = false; +} + +int +i915_memory_region_get_pages_buddy(struct drm_i915_gem_object *obj) +{ + struct intel_memory_region *mem = obj->memory_region; + resource_size_t size = obj->base.size; + struct sg_table *st; + struct scatterlist *sg; + unsigned int sg_page_sizes; + unsigned long n_pages; + + GEM_BUG_ON(!IS_ALIGNED(size, mem->mm.min_size)); + GEM_BUG_ON(!list_empty(&obj->blocks)); + + st = kmalloc(sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + n_pages = div64_u64(size, mem->mm.min_size); + + if (sg_alloc_table(st, n_pages, GFP_KERNEL)) { + kfree(st); + return -ENOMEM; + } + + sg = st->sgl; + st->nents = 0; + sg_page_sizes = 0; + + mutex_lock(&mem->mm_lock); + + do { + struct i915_gem_buddy_block *block; + unsigned int order; + u64 block_size; + u64 offset; + + order = fls(n_pages) - 1; + GEM_BUG_ON(order > mem->mm.max_order); + + do { + block = i915_gem_buddy_alloc(&mem->mm, order); + if (!IS_ERR(block)) + break; + + /* XXX: some kind of eviction pass, local to the device */ + if (!order--) + goto err_free_blocks; + } while (1); + + n_pages -= 1 << order; + + INIT_LIST_HEAD(&block->link); + list_add(&block->link, &obj->blocks); + + block_size = i915_gem_buddy_block_size(&mem->mm, block); + offset = i915_gem_buddy_block_offset(block); + + sg_dma_address(sg) = mem->region.start + offset; + sg_dma_len(sg) = block_size; + + sg->length = block_size; + sg_page_sizes |= block_size; + st->nents++; + + if (!n_pages) { + sg_mark_end(sg); + break; + } + + sg = __sg_next(sg); + } while (1); + + mutex_unlock(&mem->mm_lock); + + i915_sg_trim(st); + + __i915_gem_object_set_pages(obj, st, sg_page_sizes); + + return 0; + +err_free_blocks: + memory_region_free_pages(obj, st); + mutex_unlock(&mem->mm_lock); + return -ENOSPC; +} + +int i915_memory_region_init_buddy(struct intel_memory_region *mem) +{ + return i915_gem_buddy_init(&mem->mm, resource_size(&mem->region), + mem->min_page_size); +} + +void i915_memory_region_release_buddy(struct intel_memory_region *mem) +{ + i915_gem_buddy_fini(&mem->mm); +} + +struct drm_i915_gem_object * +i915_gem_object_create_region(struct intel_memory_region *mem, + resource_size_t size, + unsigned int flags) +{ + struct drm_i915_gem_object *obj; + + if (!mem) + return ERR_PTR(-ENODEV); + + size = round_up(size, mem->min_page_size); + + GEM_BUG_ON(!size); + GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_MIN_ALIGNMENT)); + + if (size >> PAGE_SHIFT > INT_MAX) + return ERR_PTR(-E2BIG); + + if (overflows_type(size, obj->base.size)) + return ERR_PTR(-E2BIG); + + obj = mem->ops->object_create(mem, size, flags); + if (IS_ERR(obj)) + return obj; + + INIT_LIST_HEAD(&obj->blocks); + obj->memory_region = mem; + + i915_gem_object_set_cache_coherency(obj, obj->cache_level); + + return obj; +} + +struct intel_memory_region * +intel_memory_region_create(struct drm_i915_private *i915, + resource_size_t start, + resource_size_t size, + resource_size_t min_page_size, + resource_size_t io_start, + const struct intel_memory_region_ops *ops) +{ + struct intel_memory_region *mem; + int err; + + mem = kzalloc(sizeof(*mem), GFP_KERNEL); + if (!mem) + return ERR_PTR(-ENOMEM); + + mem->i915 = i915; + mem->region = (struct resource)DEFINE_RES_MEM(start, size); + mem->io_start = io_start; + mem->min_page_size = min_page_size; + mem->ops = ops; + + mutex_init(&mem->mm_lock); + + if (ops->init) { + err = ops->init(mem); + if (err) { + kfree(mem); + mem = ERR_PTR(err); + } + } + + return mem; +} + +void +intel_memory_region_destroy(struct intel_memory_region *mem) +{ + if (mem->ops->release) + mem->ops->release(mem); + + kfree(mem); +} + +#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) +#include "selftests/mock_region.c" +#endif diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h new file mode 100644 index 000000000000..6d8a954ca75e --- /dev/null +++ b/drivers/gpu/drm/i915/intel_memory_region.h @@ -0,0 +1,126 @@ +/* + * Copyright © 2018 Intel Corporation + * + * 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. + * + */ + +#ifndef __INTEL_MEMORY_REGION_H__ +#define __INTEL_MEMORY_REGION_H__ + +#include +#include +#include + +#include "i915_gem_buddy.h" + +struct drm_i915_private; +struct drm_i915_gem_object; +struct intel_memory_region; +struct sg_table; + +/** + * Base memory type + */ +enum intel_memory_type { + INTEL_SMEM = 0, + INTEL_LMEM, + INTEL_STOLEN, +}; + +enum intel_region_id { + INTEL_MEMORY_SMEM = 0, + INTEL_MEMORY_LMEM, + INTEL_MEMORY_STOLEN, + INTEL_MEMORY_UKNOWN, /* Should be last */ +}; + +#define REGION_SMEM BIT(INTEL_MEMORY_SMEM) +#define REGION_LMEM BIT(INTEL_MEMORY_LMEM) +#define REGION_STOLEN BIT(INTEL_MEMORY_STOLEN) + +#define INTEL_MEMORY_TYPE_SHIFT 16 + +#define MEMORY_TYPE_FROM_REGION(r) (ilog2(r >> INTEL_MEMORY_TYPE_SHIFT)) +#define MEMORY_INSTANCE_FROM_REGION(r) (ilog2(r & 0xffff)) + +/** + * Memory regions encoded as type | instance + */ +static const u32 intel_region_map[] = { + [INTEL_MEMORY_SMEM] = BIT(INTEL_SMEM + INTEL_MEMORY_TYPE_SHIFT) | BIT(0), + [INTEL_MEMORY_LMEM] = BIT(INTEL_LMEM + INTEL_MEMORY_TYPE_SHIFT) | BIT(0), + [INTEL_MEMORY_STOLEN] = BIT(INTEL_STOLEN + INTEL_MEMORY_TYPE_SHIFT) | BIT(0), +}; + +struct intel_memory_region_ops { + unsigned int flags; + + int (*init)(struct intel_memory_region *); + void (*release)(struct intel_memory_region *); + + struct drm_i915_gem_object * + (*object_create)(struct intel_memory_region *, + resource_size_t, + unsigned int); +}; + +struct intel_memory_region { + struct drm_i915_private *i915; + + const struct intel_memory_region_ops *ops; + + struct io_mapping iomap; + struct resource region; + + struct i915_gem_buddy_mm mm; + struct mutex mm_lock; + + resource_size_t io_start; + resource_size_t min_page_size; + + unsigned int type; + unsigned int instance; + unsigned int id; +}; + +int i915_memory_region_init_buddy(struct intel_memory_region *mem); +void i915_memory_region_release_buddy(struct intel_memory_region *mem); + +int i915_memory_region_get_pages_buddy(struct drm_i915_gem_object *obj); +void i915_memory_region_put_pages_buddy(struct drm_i915_gem_object *obj, + struct sg_table *pages); + +struct intel_memory_region * +intel_memory_region_create(struct drm_i915_private *i915, + resource_size_t start, + resource_size_t size, + resource_size_t min_page_size, + resource_size_t io_start, + const struct intel_memory_region_ops *ops); +void +intel_memory_region_destroy(struct intel_memory_region *mem); + +struct drm_i915_gem_object * +i915_gem_object_create_region(struct intel_memory_region *mem, + resource_size_t size, + unsigned int flags); + +#endif diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index b6d84939592b..b0c8b4955f14 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -458,6 +458,86 @@ static int igt_mock_exhaust_device_supported_pages(void *arg) return err; } + +static int igt_mock_memory_region_huge_pages(void *arg) +{ + struct i915_hw_ppgtt *ppgtt = arg; + struct drm_i915_private *i915 = ppgtt->vm.i915; + unsigned long supported = INTEL_INFO(i915)->page_sizes; + struct intel_memory_region *mem; + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + int bit; + int err = 0; + + mem = mock_region_create(i915, 0, SZ_2G, + I915_GTT_PAGE_SIZE_4K, 0); + if (IS_ERR(mem)) { + pr_err("failed to create memory region\n"); + return PTR_ERR(mem); + } + + for_each_set_bit(bit, &supported, ilog2(I915_GTT_MAX_PAGE_SIZE) + 1) { + unsigned int page_size = BIT(bit); + resource_size_t phys; + + obj = i915_gem_object_create_region(mem, page_size, 0); + if (IS_ERR(obj)) { + err = PTR_ERR(obj); + goto out_destroy_device; + } + + pr_info("memory region start(%pa)\n", + &obj->memory_region->region.start); + pr_info("creating object, size=%x\n", page_size); + + vma = i915_vma_instance(obj, &ppgtt->vm, NULL); + if (IS_ERR(vma)) { + err = PTR_ERR(vma); + goto out_put; + } + + err = i915_vma_pin(vma, 0, 0, PIN_USER); + if (err) + goto out_close; + + phys = i915_gem_object_get_dma_address(obj, 0); + if (!IS_ALIGNED(phys, page_size)) { + pr_err("memory region misaligned(%pa)\n", &phys); + err = -EINVAL; + goto out_close; + } + + if (vma->page_sizes.gtt != page_size) { + pr_err("page_sizes.gtt=%u, expected=%u\n", + vma->page_sizes.gtt, page_size); + err = -EINVAL; + goto out_unpin; + } + + i915_vma_unpin(vma); + i915_vma_close(vma); + + i915_gem_object_put(obj); + } + + goto out_destroy_device; + +out_unpin: + i915_vma_unpin(vma); +out_close: + i915_vma_close(vma); +out_put: + i915_gem_object_put(obj); +out_destroy_device: + mutex_unlock(&i915->drm.struct_mutex); + i915_gem_drain_freed_objects(i915); + mutex_lock(&i915->drm.struct_mutex); + intel_memory_region_destroy(mem); + + return err; +} + static int igt_mock_ppgtt_misaligned_dma(void *arg) { struct i915_hw_ppgtt *ppgtt = arg; @@ -1697,6 +1777,7 @@ int i915_gem_huge_page_mock_selftests(void) { static const struct i915_subtest tests[] = { SUBTEST(igt_mock_exhaust_device_supported_pages), + SUBTEST(igt_mock_memory_region_huge_pages), SUBTEST(igt_mock_ppgtt_misaligned_dma), SUBTEST(igt_mock_ppgtt_huge_fill), SUBTEST(igt_mock_ppgtt_64K), diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h index 984e07ed65e5..3e34ee2255db 100644 --- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h +++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h @@ -25,3 +25,4 @@ selftest(gtt, i915_gem_gtt_mock_selftests) selftest(hugepages, i915_gem_huge_page_mock_selftests) selftest(contexts, i915_gem_context_mock_selftests) selftest(buddy, i915_gem_buddy_mock_selftests) +selftest(memory_region, intel_memory_region_mock_selftests) diff --git a/drivers/gpu/drm/i915/selftests/intel_memory_region.c b/drivers/gpu/drm/i915/selftests/intel_memory_region.c new file mode 100644 index 000000000000..2b8d28216d87 --- /dev/null +++ b/drivers/gpu/drm/i915/selftests/intel_memory_region.c @@ -0,0 +1,128 @@ +/* + * Copyright © 2018 Intel Corporation + * + * 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 "../i915_selftest.h" + +#include "mock_gem_device.h" +#include "mock_context.h" +#include "mock_drm.h" + +static void close_objects(struct list_head *objects) +{ + struct drm_i915_gem_object *obj, *on; + + list_for_each_entry_safe(obj, on, objects, st_link) { + if (i915_gem_object_has_pinned_pages(obj)) + i915_gem_object_unpin_pages(obj); + /* No polluting the memory region between tests */ + __i915_gem_object_put_pages(obj, I915_MM_NORMAL); + i915_gem_object_put(obj); + list_del(&obj->st_link); + } +} + +static int igt_mock_fill(void *arg) +{ + struct intel_memory_region *mem = arg; + resource_size_t total = resource_size(&mem->region); + resource_size_t page_size; + resource_size_t rem; + unsigned long max_pages; + unsigned long page_num; + LIST_HEAD(objects); + int err = 0; + + page_size = mem->mm.min_size; + max_pages = total / page_size; + rem = total; + + for_each_prime_number_from(page_num, 1, max_pages) { + resource_size_t size = page_num * page_size; + struct drm_i915_gem_object *obj; + + obj = i915_gem_object_create_region(mem, size, 0); + if (IS_ERR(obj)) { + err = PTR_ERR(obj); + break; + } + + err = i915_gem_object_pin_pages(obj); + if (err) { + i915_gem_object_put(obj); + break; + } + + list_add(&obj->st_link, &objects); + rem -= size; + } + + if (err == -ENOMEM) + err = 0; + if (err == -ENOSPC) { + if (page_num * page_size <= rem) { + pr_err("igt_mock_fill failed, space still left in region\n"); + err = -EINVAL; + } else { + err = 0; + } + } + + close_objects(&objects); + + return err; +} + +int intel_memory_region_mock_selftests(void) +{ + static const struct i915_subtest tests[] = { + SUBTEST(igt_mock_fill), + }; + struct intel_memory_region *mem; + struct drm_i915_private *i915; + int err; + + i915 = mock_gem_device(); + if (!i915) + return -ENOMEM; + + mem = mock_region_create(i915, 0, SZ_2G, + I915_GTT_PAGE_SIZE_4K, 0); + if (IS_ERR(mem)) { + pr_err("failed to create memory region\n"); + err = PTR_ERR(mem); + goto out_unref; + } + + mutex_lock(&i915->drm.struct_mutex); + err = i915_subtests(tests, mem); + mutex_unlock(&i915->drm.struct_mutex); + + i915_gem_drain_freed_objects(i915); + intel_memory_region_destroy(mem); + +out_unref: + drm_dev_put(&i915->drm); + + return err; +} diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c index 876f4e6dadac..f8901cd12180 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c @@ -32,6 +32,7 @@ #include "mock_gem_object.h" #include "mock_gtt.h" #include "mock_uncore.h" +#include "mock_region.h" void mock_device_flush(struct drm_i915_private *i915) { diff --git a/drivers/gpu/drm/i915/selftests/mock_region.c b/drivers/gpu/drm/i915/selftests/mock_region.c new file mode 100644 index 000000000000..2c83711f780d --- /dev/null +++ b/drivers/gpu/drm/i915/selftests/mock_region.c @@ -0,0 +1,71 @@ +/* + * Copyright © 2019 Intel Corporation + * + * 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 "mock_region.h" + +static const struct drm_i915_gem_object_ops mock_region_obj_ops = { + .get_pages = i915_memory_region_get_pages_buddy, + .put_pages = i915_memory_region_put_pages_buddy, +}; + +static struct drm_i915_gem_object * +mock_object_create(struct intel_memory_region *mem, + resource_size_t size, + unsigned int flags) +{ + struct drm_i915_private *i915 = mem->i915; + struct drm_i915_gem_object *obj; + + if (size > BIT(mem->mm.max_order) * mem->mm.min_size) + return ERR_PTR(-E2BIG); + + obj = i915_gem_object_alloc(i915); + if (!obj) + return ERR_PTR(-ENOMEM); + + drm_gem_private_object_init(&i915->drm, &obj->base, size); + i915_gem_object_init(obj, &mock_region_obj_ops); + + obj->read_domains = I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT; + obj->cache_level = HAS_LLC(i915) ? I915_CACHE_LLC : I915_CACHE_NONE; + + return obj; +} + +static const struct intel_memory_region_ops mock_region_ops = { + .init = i915_memory_region_init_buddy, + .release = i915_memory_region_release_buddy, + .object_create = mock_object_create, +}; + +struct intel_memory_region * +mock_region_create(struct drm_i915_private *i915, + resource_size_t start, + resource_size_t size, + resource_size_t min_page_size, + resource_size_t io_start) +{ + return intel_memory_region_create(i915, start, size, min_page_size, + io_start, &mock_region_ops); +} diff --git a/drivers/gpu/drm/i915/selftests/mock_region.h b/drivers/gpu/drm/i915/selftests/mock_region.h new file mode 100644 index 000000000000..47718313fa58 --- /dev/null +++ b/drivers/gpu/drm/i915/selftests/mock_region.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2019 Intel Corporation + * + * 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. + * + */ + +#ifndef __MOCK_REGION_H +#define __MOCK_REGION_H + +struct intel_memory_region * +mock_region_create(struct drm_i915_private *i915, + resource_size_t start, + resource_size_t size, + resource_size_t min_page_size, + resource_size_t io_start); + +#endif /* !__MOCK_REGION_H */