[Intel-gfx] [RFC PATCH 04/42] drm/i915: introduce intel_memory_region

Matthew Auld matthew.william.auld at gmail.com
Tue Feb 26 14:20:23 UTC 2019


On Tue, 26 Feb 2019 at 13:00, Tvrtko Ursulin
<tvrtko.ursulin at linux.intel.com> wrote:
>
>
> Hi,
>
> Just some quick comments, not a full review. Possibly a repeat of some
> same comments from way back, not sure.
>
> On 14/02/2019 14:57, Matthew Auld wrote:
> > 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 <matthew.auld at intel.com>
> > Signed-off-by: Abdiel Janulgue <abdiel.janulgue at linux.intel.com>
> > Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
> > ---
> >   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)) {
>
> sg_alloc_table takes unsigned int for nents so if you need to do this
> calculation in u64 you should probably add some checks against overflow.
> Although it would probably be simpler and more robust to have it as
> unsigned int and just check before hand the allocation request is not
> exceeding the sg_table API capabilities.

Yeah, the type stuff here is a little odd, but we do make sure that
the number of pages doesn't exceed INT_MAX at object creation.

>
> > +             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--)
>
> Is it interesting to propagate the more specific error code returned by
> i915_gem_buddy_alloc?

It will either return -ENOMEM or -ENOSPC, although I'm now wondering
if returning -ENOSPC from get_pages() is a bad idea. We normally just
return -ENOMEM if we can't satisfy the request for the other
backends...

>
> > +                             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->dma_len and sg->length are unsigned int so again I think block_size
> can follow with some limit checking earlier on.
>
> > +             sg_page_sizes |= block_size;
> > +             st->nents++;
>
> If address of this block is consecutive block to the previous one you
> can, considering the overflow of sg->dma_len and sg->length fields,
> coalesce the two by just bumping the lengths and not incrementing the
> st->nents++. That would make the i915_sg_trim below more effective. To
> be fair I have no idea how likely are you to get consecutive blocks with
> the buddy allocator so your decision.

Yup, makes sense.

>
> Regards,
>
> Tvrtko
>
> > +
> > +             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 <linux/ioport.h>
> > +#include <linux/mutex.h>
> > +#include <linux/io-mapping.h>
> > +
> > +#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 */
> >
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx


More information about the Intel-gfx mailing list