Re: [Intel-gfx] [PATCH 1/6] drm/i915/ttm: add ttm_buddy_man
On 6/8/21 10:11 AM, Matthew Auld wrote: On 08/06/2021 08:11, Thomas Hellström wrote: On Mon, 2021-06-07 at 19:22 +0100, Matthew Auld wrote: Add back our standalone i915_buddy allocator and integrate it into a ttm_resource_manager. This will plug into our ttm backend for managing device local-memory in the next couple of patches. Signed-off-by: Matthew Auld Cc: Thomas Hellström --- Since the buddy + selftests have been part of the driver before, I didn't review them separately, but for the TTM interface, some minor comments below. With those fixed, Acked-by: Thomas Hellström diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c new file mode 100644 index ..d7bf37be1932 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include + +#include +#include + +#include "i915_ttm_buddy_manager.h" + +#include "i915_buddy.h" +#include "i915_gem.h" + +struct i915_ttm_buddy_manager { + struct ttm_resource_manager manager; + struct i915_buddy_mm mm; + struct list_head reserved; + struct mutex lock; +}; + +static inline struct i915_ttm_buddy_manager * "inline" shouldn't be needed here. +to_buddy_manager(struct ttm_resource_manager *man) +{ + return container_of(man, struct i915_ttm_buddy_manager, manager); +} + +static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, + struct ttm_buffer_object *bo, + const struct ttm_place *place, + struct ttm_resource **res) +{ + struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); + struct i915_ttm_buddy_resource *bman_res; + struct i915_buddy_mm *mm = >mm; + unsigned long n_pages; + unsigned int min_order; + u64 size; + int err; + + GEM_BUG_ON(place->fpfn || place->lpfn); + GEM_BUG_ON(bo->page_alignment < mm->chunk_size); + + bman_res = kzalloc(sizeof(*bman_res), GFP_KERNEL); + if (!bman_res) + return -ENOMEM; + + ttm_resource_init(bo, place, _res->base); + INIT_LIST_HEAD(_res->blocks); + bman_res->mm = mm; + + GEM_BUG_ON(!bman_res->base.num_pages); + size = bman_res->base.num_pages << PAGE_SHIFT; + + min_order = ilog2(bo->page_alignment) - ilog2(mm- chunk_size); + if (place->flags & TTM_PL_FLAG_CONTIGUOUS) { + size = roundup_pow_of_two(size); + min_order = ilog2(size) - ilog2(mm->chunk_size); + } + + if (size > mm->size) { + err = -E2BIG; + goto err_free_res; + } + + n_pages = size >> ilog2(mm->chunk_size); + + do { + struct i915_buddy_block *block; + unsigned int order; + + order = fls(n_pages) - 1; + GEM_BUG_ON(order > mm->max_order); + GEM_BUG_ON(order < min_order); + + do { + mutex_lock(>lock); + block = i915_buddy_alloc(mm, order); + mutex_unlock(>lock); + if (!IS_ERR(block)) + break; + + if (order-- == min_order) { + err = -ENXIO; IIRC, TTM relies on -ENOSPC to retry with evictions. Ah, right. We convert that back to -ENXIO in the upper levels somewhere? Yes, that's done in the ttm bo backend after ttm_bo_validate() and bo initialization. /Thomas ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [Intel-gfx] [PATCH 1/6] drm/i915/ttm: add ttm_buddy_man
On 08/06/2021 08:11, Thomas Hellström wrote: On Mon, 2021-06-07 at 19:22 +0100, Matthew Auld wrote: Add back our standalone i915_buddy allocator and integrate it into a ttm_resource_manager. This will plug into our ttm backend for managing device local-memory in the next couple of patches. Signed-off-by: Matthew Auld Cc: Thomas Hellström --- Since the buddy + selftests have been part of the driver before, I didn't review them separately, but for the TTM interface, some minor comments below. With those fixed, Acked-by: Thomas Hellström diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c new file mode 100644 index ..d7bf37be1932 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include + +#include +#include + +#include "i915_ttm_buddy_manager.h" + +#include "i915_buddy.h" +#include "i915_gem.h" + +struct i915_ttm_buddy_manager { + struct ttm_resource_manager manager; + struct i915_buddy_mm mm; + struct list_head reserved; + struct mutex lock; +}; + +static inline struct i915_ttm_buddy_manager * "inline" shouldn't be needed here. +to_buddy_manager(struct ttm_resource_manager *man) +{ + return container_of(man, struct i915_ttm_buddy_manager, manager); +} + +static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, + struct ttm_buffer_object *bo, + const struct ttm_place *place, + struct ttm_resource **res) +{ + struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); + struct i915_ttm_buddy_resource *bman_res; + struct i915_buddy_mm *mm = >mm; + unsigned long n_pages; + unsigned int min_order; + u64 size; + int err; + + GEM_BUG_ON(place->fpfn || place->lpfn); + GEM_BUG_ON(bo->page_alignment < mm->chunk_size); + + bman_res = kzalloc(sizeof(*bman_res), GFP_KERNEL); + if (!bman_res) + return -ENOMEM; + + ttm_resource_init(bo, place, _res->base); + INIT_LIST_HEAD(_res->blocks); + bman_res->mm = mm; + + GEM_BUG_ON(!bman_res->base.num_pages); + size = bman_res->base.num_pages << PAGE_SHIFT; + + min_order = ilog2(bo->page_alignment) - ilog2(mm- chunk_size); + if (place->flags & TTM_PL_FLAG_CONTIGUOUS) { + size = roundup_pow_of_two(size); + min_order = ilog2(size) - ilog2(mm->chunk_size); + } + + if (size > mm->size) { + err = -E2BIG; + goto err_free_res; + } + + n_pages = size >> ilog2(mm->chunk_size); + + do { + struct i915_buddy_block *block; + unsigned int order; + + order = fls(n_pages) - 1; + GEM_BUG_ON(order > mm->max_order); + GEM_BUG_ON(order < min_order); + + do { + mutex_lock(>lock); + block = i915_buddy_alloc(mm, order); + mutex_unlock(>lock); + if (!IS_ERR(block)) + break; + + if (order-- == min_order) { + err = -ENXIO; IIRC, TTM relies on -ENOSPC to retry with evictions. Ah, right. We convert that back to -ENXIO in the upper levels somewhere? + goto err_free_blocks; + } + } while (1); + + n_pages -= BIT(order); + + list_add_tail(>link, _res->blocks); + + if (!n_pages) + break; + } while (1); + + *res = _res->base; + return 0; + +err_free_blocks: + mutex_lock(>lock); + i915_buddy_free_list(mm, _res->blocks); + mutex_unlock(>lock); +err_free_res: + kfree(bman_res); + return err; +} + /Thomas ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [Intel-gfx] [PATCH 1/6] drm/i915/ttm: add ttm_buddy_man
On Mon, 2021-06-07 at 19:22 +0100, Matthew Auld wrote: > Add back our standalone i915_buddy allocator and integrate it into a > ttm_resource_manager. This will plug into our ttm backend for > managing > device local-memory in the next couple of patches. > > Signed-off-by: Matthew Auld > Cc: Thomas Hellström > --- > Since the buddy + selftests have been part of the driver before, I didn't review them separately, but for the TTM interface, some minor comments below. With those fixed, Acked-by: Thomas Hellström > diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c > b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c > new file mode 100644 > index ..d7bf37be1932 > --- /dev/null > +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c > @@ -0,0 +1,246 @@ > +// SPDX-License-Identifier: MIT > +/* > + * Copyright © 2021 Intel Corporation > + */ > + > +#include > + > +#include > +#include > + > +#include "i915_ttm_buddy_manager.h" > + > +#include "i915_buddy.h" > +#include "i915_gem.h" > + > +struct i915_ttm_buddy_manager { > + struct ttm_resource_manager manager; > + struct i915_buddy_mm mm; > + struct list_head reserved; > + struct mutex lock; > +}; > + > +static inline struct i915_ttm_buddy_manager * "inline" shouldn't be needed here. > +to_buddy_manager(struct ttm_resource_manager *man) > +{ > + return container_of(man, struct i915_ttm_buddy_manager, > manager); > +} > + > +static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager > *man, > + struct ttm_buffer_object *bo, > + const struct ttm_place *place, > + struct ttm_resource **res) > +{ > + struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); > + struct i915_ttm_buddy_resource *bman_res; > + struct i915_buddy_mm *mm = >mm; > + unsigned long n_pages; > + unsigned int min_order; > + u64 size; > + int err; > + > + GEM_BUG_ON(place->fpfn || place->lpfn); > + GEM_BUG_ON(bo->page_alignment < mm->chunk_size); > + > + bman_res = kzalloc(sizeof(*bman_res), GFP_KERNEL); > + if (!bman_res) > + return -ENOMEM; > + > + ttm_resource_init(bo, place, _res->base); > + INIT_LIST_HEAD(_res->blocks); > + bman_res->mm = mm; > + > + GEM_BUG_ON(!bman_res->base.num_pages); > + size = bman_res->base.num_pages << PAGE_SHIFT; > + > + min_order = ilog2(bo->page_alignment) - ilog2(mm- > >chunk_size); > + if (place->flags & TTM_PL_FLAG_CONTIGUOUS) { > + size = roundup_pow_of_two(size); > + min_order = ilog2(size) - ilog2(mm->chunk_size); > + } > + > + if (size > mm->size) { > + err = -E2BIG; > + goto err_free_res; > + } > + > + n_pages = size >> ilog2(mm->chunk_size); > + > + do { > + struct i915_buddy_block *block; > + unsigned int order; > + > + order = fls(n_pages) - 1; > + GEM_BUG_ON(order > mm->max_order); > + GEM_BUG_ON(order < min_order); > + > + do { > + mutex_lock(>lock); > + block = i915_buddy_alloc(mm, order); > + mutex_unlock(>lock); > + if (!IS_ERR(block)) > + break; > + > + if (order-- == min_order) { > + err = -ENXIO; IIRC, TTM relies on -ENOSPC to retry with evictions. > + goto err_free_blocks; > + } > + } while (1); > + > + n_pages -= BIT(order); > + > + list_add_tail(>link, _res->blocks); > + > + if (!n_pages) > + break; > + } while (1); > + > + *res = _res->base; > + return 0; > + > +err_free_blocks: > + mutex_lock(>lock); > + i915_buddy_free_list(mm, _res->blocks); > + mutex_unlock(>lock); > +err_free_res: > + kfree(bman_res); > + return err; > +} > + /Thomas ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
[Intel-gfx] [PATCH 1/6] drm/i915/ttm: add ttm_buddy_man
Add back our standalone i915_buddy allocator and integrate it into a ttm_resource_manager. This will plug into our ttm backend for managing device local-memory in the next couple of patches. Signed-off-by: Matthew Auld Cc: Thomas Hellström --- drivers/gpu/drm/i915/Makefile | 2 + drivers/gpu/drm/i915/i915_buddy.c | 412 + drivers/gpu/drm/i915/i915_buddy.h | 133 +++ drivers/gpu/drm/i915/i915_ttm_buddy_manager.c | 246 ++ drivers/gpu/drm/i915/i915_ttm_buddy_manager.h | 56 ++ drivers/gpu/drm/i915/selftests/i915_buddy.c | 789 ++ 6 files changed, 1638 insertions(+) create mode 100644 drivers/gpu/drm/i915/i915_buddy.c create mode 100644 drivers/gpu/drm/i915/i915_buddy.h create mode 100644 drivers/gpu/drm/i915/i915_ttm_buddy_manager.c create mode 100644 drivers/gpu/drm/i915/i915_ttm_buddy_manager.h create mode 100644 drivers/gpu/drm/i915/selftests/i915_buddy.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index f57dfc74d6ce..6c84e96ab26a 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -162,6 +162,7 @@ gem-y += \ i915-y += \ $(gem-y) \ i915_active.o \ + i915_buddy.o \ i915_cmd_parser.o \ i915_gem_evict.o \ i915_gem_gtt.o \ @@ -171,6 +172,7 @@ i915-y += \ i915_request.o \ i915_scheduler.o \ i915_trace_points.o \ + i915_ttm_buddy_manager.o \ i915_vma.o \ intel_wopcm.o diff --git a/drivers/gpu/drm/i915/i915_buddy.c b/drivers/gpu/drm/i915/i915_buddy.c new file mode 100644 index ..29dd7d0310c1 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_buddy.c @@ -0,0 +1,412 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include + +#include "i915_buddy.h" + +#include "i915_gem.h" +#include "i915_utils.h" + +static struct i915_buddy_block *i915_block_alloc(struct i915_buddy_mm *mm, +struct i915_buddy_block *parent, +unsigned int order, +u64 offset) +{ + struct i915_buddy_block *block; + + GEM_BUG_ON(order > I915_BUDDY_MAX_ORDER); + + block = kmem_cache_zalloc(mm->slab_blocks, GFP_KERNEL); + if (!block) + return NULL; + + block->header = offset; + block->header |= order; + block->parent = parent; + + GEM_BUG_ON(block->header & I915_BUDDY_HEADER_UNUSED); + return block; +} + +static void i915_block_free(struct i915_buddy_mm *mm, + struct i915_buddy_block *block) +{ + kmem_cache_free(mm->slab_blocks, block); +} + +static void mark_allocated(struct i915_buddy_block *block) +{ + block->header &= ~I915_BUDDY_HEADER_STATE; + block->header |= I915_BUDDY_ALLOCATED; + + list_del(>link); +} + +static void mark_free(struct i915_buddy_mm *mm, + struct i915_buddy_block *block) +{ + block->header &= ~I915_BUDDY_HEADER_STATE; + block->header |= I915_BUDDY_FREE; + + list_add(>link, +>free_list[i915_buddy_block_order(block)]); +} + +static void mark_split(struct i915_buddy_block *block) +{ + block->header &= ~I915_BUDDY_HEADER_STATE; + block->header |= I915_BUDDY_SPLIT; + + list_del(>link); +} + +int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size) +{ + unsigned int i; + u64 offset; + + if (size < chunk_size) + return -EINVAL; + + if (chunk_size < PAGE_SIZE) + return -EINVAL; + + if (!is_power_of_2(chunk_size)) + return -EINVAL; + + size = round_down(size, chunk_size); + + mm->size = size; + mm->chunk_size = chunk_size; + mm->max_order = ilog2(size) - ilog2(chunk_size); + + GEM_BUG_ON(mm->max_order > I915_BUDDY_MAX_ORDER); + + mm->slab_blocks = KMEM_CACHE(i915_buddy_block, SLAB_HWCACHE_ALIGN); + if (!mm->slab_blocks) + return -ENOMEM; + + mm->free_list = kmalloc_array(mm->max_order + 1, + sizeof(struct list_head), + GFP_KERNEL); + if (!mm->free_list) + goto out_destroy_slab; + + for (i = 0; i <= mm->max_order; ++i) + INIT_LIST_HEAD(>free_list[i]); + + mm->n_roots = hweight64(size); + + mm->roots = kmalloc_array(mm->n_roots, + sizeof(struct i915_buddy_block *), + GFP_KERNEL); + if (!mm->roots) + goto out_free_list; + + offset = 0; + i = 0; + + /* +* Split into power-of-two blocks, in case we are given a size that is +* not itself a power-of-two. +*/ + do { + struct i915_buddy_block *root; +