Skip to content

Commit

Permalink
drm/i915: introduce intel_memory_region
Browse files Browse the repository at this point in the history
Support memory regions, as defined by a given (start, end), and allow
creating GEM objects which are backed by said region. The immediate goal
here is to have something to represent our device memory, but later on
we also want to represent every memory domain with a region, so stolen,
shmem, and of course device. At some point we are probably going to want
use a common struct here, such that we are better aligned with say TTM.

Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
Signed-off-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20191008160116.18379-2-matthew.auld@intel.com
  • Loading branch information
Matthew Auld authored and Chris Wilson committed Oct 8, 2019
1 parent d99f7b0 commit 232a6eb
Show file tree
Hide file tree
Showing 13 changed files with 729 additions and 0 deletions.
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ i915-y += i915_drv.o \
i915_utils.o \
intel_csr.o \
intel_device_info.o \
intel_memory_region.o \
intel_pch.o \
intel_pm.o \
intel_runtime_pm.o \
Expand Down Expand Up @@ -121,6 +122,7 @@ gem-y += \
gem/i915_gem_pages.o \
gem/i915_gem_phys.o \
gem/i915_gem_pm.o \
gem/i915_gem_region.o \
gem/i915_gem_shmem.o \
gem/i915_gem_shrinker.o \
gem/i915_gem_stolen.o \
Expand Down
9 changes: 9 additions & 0 deletions drivers/gpu/drm/i915/gem/i915_gem_object_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,15 @@ struct drm_i915_gem_object {
atomic_t pages_pin_count;
atomic_t shrink_pin;

/**
* Memory region for this object.
*/
struct intel_memory_region *region;
/**
* List of memory region blocks allocated for this object.
*/
struct list_head blocks;

struct sg_table *pages;
void *mapping;

Expand Down
145 changes: 145 additions & 0 deletions drivers/gpu/drm/i915/gem/i915_gem_region.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2019 Intel Corporation
*/

#include "intel_memory_region.h"
#include "i915_gem_region.h"
#include "i915_drv.h"

void
i915_gem_object_put_pages_buddy(struct drm_i915_gem_object *obj,
struct sg_table *pages)
{
__intel_memory_region_put_pages_buddy(obj->mm.region, &obj->mm.blocks);

obj->mm.dirty = false;
sg_free_table(pages);
kfree(pages);
}

int
i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj)
{
struct intel_memory_region *mem = obj->mm.region;
struct list_head *blocks = &obj->mm.blocks;
unsigned int flags = I915_ALLOC_MIN_PAGE_SIZE;
resource_size_t size = obj->base.size;
resource_size_t prev_end;
struct i915_buddy_block *block;
struct sg_table *st;
struct scatterlist *sg;
unsigned int sg_page_sizes;
int ret;

st = kmalloc(sizeof(*st), GFP_KERNEL);
if (!st)
return -ENOMEM;

if (sg_alloc_table(st, size >> ilog2(mem->mm.chunk_size), GFP_KERNEL)) {
kfree(st);
return -ENOMEM;
}

ret = __intel_memory_region_get_pages_buddy(mem, size, flags, blocks);
if (ret)
goto err_free_sg;

GEM_BUG_ON(list_empty(blocks));

sg = st->sgl;
st->nents = 0;
sg_page_sizes = 0;
prev_end = (resource_size_t)-1;

list_for_each_entry(block, blocks, link) {
u64 block_size, offset;

block_size = i915_buddy_block_size(&mem->mm, block);
offset = i915_buddy_block_offset(block);

GEM_BUG_ON(overflows_type(block_size, sg->length));

if (offset != prev_end ||
add_overflows_t(typeof(sg->length), sg->length, block_size)) {
if (st->nents) {
sg_page_sizes |= sg->length;
sg = __sg_next(sg);
}

sg_dma_address(sg) = mem->region.start + offset;
sg_dma_len(sg) = block_size;

sg->length = block_size;

st->nents++;
} else {
sg->length += block_size;
sg_dma_len(sg) += block_size;
}

prev_end = offset + block_size;
};

sg_page_sizes |= sg->length;
sg_mark_end(sg);
i915_sg_trim(st);

__i915_gem_object_set_pages(obj, st, sg_page_sizes);

return 0;

err_free_sg:
sg_free_table(st);
kfree(st);
return ret;
}

void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
struct intel_memory_region *mem)
{
INIT_LIST_HEAD(&obj->mm.blocks);
obj->mm.region = intel_memory_region_get(mem);
}

void i915_gem_object_release_memory_region(struct drm_i915_gem_object *obj)
{
intel_memory_region_put(obj->mm.region);
}

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;

/*
* NB: Our use of resource_size_t for the size stems from using struct
* resource for the mem->region. We might need to revisit this in the
* future.
*/

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));

/*
* XXX: There is a prevalence of the assumption that we fit the
* object's page count inside a 32bit _signed_ variable. Let's document
* this and catch if we ever need to fix it. In the meantime, if you do
* spot such a local variable, please consider fixing!
*/

if (size >> PAGE_SHIFT > INT_MAX)
return ERR_PTR(-E2BIG);

if (overflows_type(size, obj->base.size))
return ERR_PTR(-E2BIG);

return mem->ops->create_object(mem, size, flags);
}
28 changes: 28 additions & 0 deletions drivers/gpu/drm/i915/gem/i915_gem_region.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2019 Intel Corporation
*/

#ifndef __I915_GEM_REGION_H__
#define __I915_GEM_REGION_H__

#include <linux/types.h>

struct intel_memory_region;
struct drm_i915_gem_object;
struct sg_table;

int i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj);
void i915_gem_object_put_pages_buddy(struct drm_i915_gem_object *obj,
struct sg_table *pages);

void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj,
struct intel_memory_region *mem);
void i915_gem_object_release_memory_region(struct drm_i915_gem_object *obj);

struct drm_i915_gem_object *
i915_gem_object_create_region(struct intel_memory_region *mem,
resource_size_t size,
unsigned int flags);

#endif
78 changes: 78 additions & 0 deletions drivers/gpu/drm/i915/gem/selftests/huge_pages.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "i915_selftest.h"

#include "gem/i915_gem_region.h"
#include "gem/i915_gem_pm.h"

#include "gt/intel_gt.h"
Expand All @@ -17,6 +18,7 @@

#include "selftests/mock_drm.h"
#include "selftests/mock_gem_device.h"
#include "selftests/mock_region.h"
#include "selftests/i915_random.h"

static const unsigned int page_sizes[] = {
Expand Down Expand Up @@ -452,6 +454,81 @@ static int igt_mock_exhaust_device_supported_pages(void *arg)
return err;
}

static int igt_mock_memory_region_huge_pages(void *arg)
{
struct i915_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("%s failed to create memory region\n", __func__);
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_region;
}

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;

err = igt_check_page_sizes(vma);
if (err)
goto out_unpin;

phys = i915_gem_object_get_dma_address(obj, 0);
if (!IS_ALIGNED(phys, page_size)) {
pr_err("%s addr misaligned(%pa) page_size=%u\n",
__func__, &phys, page_size);
err = -EINVAL;
goto out_unpin;
}

if (vma->page_sizes.gtt != page_size) {
pr_err("%s page_sizes.gtt=%u, expected=%u\n",
__func__, 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_region;

out_unpin:
i915_vma_unpin(vma);
out_close:
i915_vma_close(vma);
out_put:
i915_gem_object_put(obj);
out_region:
intel_memory_region_put(mem);
return err;
}

static int igt_mock_ppgtt_misaligned_dma(void *arg)
{
struct i915_ppgtt *ppgtt = arg;
Expand Down Expand Up @@ -1623,6 +1700,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),
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
#include "intel_device_info.h"
#include "intel_pch.h"
#include "intel_runtime_pm.h"
#include "intel_memory_region.h"
#include "intel_uncore.h"
#include "intel_wakeref.h"
#include "intel_wopcm.h"
Expand Down
Loading

0 comments on commit 232a6eb

Please sign in to comment.