From d16415ac264777e00546ee3435818c5ee94baba0 Mon Sep 17 00:00:00 2001 From: Alex Waterman Date: Tue, 16 Aug 2016 17:01:44 -0700 Subject: gpu: nvgpu: Implement carveout support in the buddy allocator Implement carveout support in the buddy allocator so that the WPR space in the VIDMEM can be carved out. This is needed since the buddy allocator is used internally by the page allocator which is what manages the VIDMEM space. Jira DNVGPU-84 Change-Id: I864faa7e20fca5547cc3a8f85f1bc4c36af53ee0 Signed-off-by: Alex Waterman Reviewed-on: http://git-master/r/1203391 (cherry picked from commit a8a5fd265a8ae33093d144cd6ec5222e93280a0f) Reviewed-on: http://git-master/r/1223453 GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom --- drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c | 134 +++++++++++++++++++++--- 1 file changed, 121 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c') diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c b/drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c index dd7f4d27..70a10c24 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a_allocator_buddy.c @@ -844,6 +844,8 @@ static u64 gk20a_buddy_balloc(struct gk20a_allocator *__a, u64 len) alloc_dbg(balloc_owner(a), "Alloc failed: no mem!\n"); } + a->alloc_made = 1; + alloc_unlock(__a); gk20a_alloc_trace_func_done(); @@ -851,15 +853,10 @@ static u64 gk20a_buddy_balloc(struct gk20a_allocator *__a, u64 len) } /* - * Allocate a fixed address allocation. The address of the allocation is @base - * and the length is @len. This is not a typical buddy allocator operation and - * as such has a high posibility of failure if the address space is heavily in - * use. - * - * Please do not use this function unless _absolutely_ necessary. + * Requires @__a to be locked. */ -static u64 gk20a_balloc_fixed_buddy(struct gk20a_allocator *__a, - u64 base, u64 len) +static u64 __gk20a_balloc_fixed_buddy(struct gk20a_allocator *__a, + u64 base, u64 len) { u64 ret, real_bytes = 0; struct gk20a_buddy *bud; @@ -883,7 +880,6 @@ static u64 gk20a_balloc_fixed_buddy(struct gk20a_allocator *__a, falloc->start = base; falloc->end = base + len; - alloc_lock(__a); if (!balloc_is_range_free(a, base, base + len)) { alloc_dbg(balloc_owner(a), "Range not free: 0x%llx -> 0x%llx\n", @@ -907,7 +903,6 @@ static u64 gk20a_balloc_fixed_buddy(struct gk20a_allocator *__a, a->bytes_alloced += len; a->bytes_alloced_real += real_bytes; - alloc_unlock(__a); alloc_dbg(balloc_owner(a), "Alloc (fixed) 0x%llx\n", base); gk20a_alloc_trace_func_done(); @@ -921,6 +916,28 @@ fail: return 0; } +/* + * Allocate a fixed address allocation. The address of the allocation is @base + * and the length is @len. This is not a typical buddy allocator operation and + * as such has a high posibility of failure if the address space is heavily in + * use. + * + * Please do not use this function unless _absolutely_ necessary. + */ +static u64 gk20a_balloc_fixed_buddy(struct gk20a_allocator *__a, + u64 base, u64 len) +{ + u64 alloc; + struct gk20a_buddy_allocator *a = __a->priv; + + alloc_lock(__a); + alloc = __gk20a_balloc_fixed_buddy(__a, base, len); + a->alloc_made = 1; + alloc_unlock(__a); + + return alloc; +} + /* * Free the passed allocation. */ @@ -968,6 +985,81 @@ done: return; } +static bool gk20a_buddy_reserve_is_possible(struct gk20a_buddy_allocator *a, + struct gk20a_alloc_carveout *co) +{ + struct gk20a_alloc_carveout *tmp; + u64 co_base, co_end; + + co_base = co->base; + co_end = co->base + co->length; + + /* + * Not the fastest approach but we should not have that many carveouts + * for any reasonable allocator. + */ + list_for_each_entry(tmp, &a->co_list, co_entry) { + if ((co_base >= tmp->base && + co_base < (tmp->base + tmp->length)) || + (co_end >= tmp->base && + co_end < (tmp->base + tmp->length))) + return false; + } + + return true; +} + +/* + * Carveouts can only be reserved before any regular allocations have been + * made. + */ +static int gk20a_buddy_reserve_co(struct gk20a_allocator *__a, + struct gk20a_alloc_carveout *co) +{ + struct gk20a_buddy_allocator *a = __a->priv; + u64 addr; + int err = 0; + + if (co->base < a->start || (co->base + co->length) > a->end || + a->alloc_made) + return -EINVAL; + + alloc_lock(__a); + + if (!gk20a_buddy_reserve_is_possible(a, co)) { + err = -EBUSY; + goto done; + } + + /* Should not be possible to fail... */ + addr = __gk20a_balloc_fixed_buddy(__a, co->base, co->length); + if (!addr) { + err = -ENOMEM; + pr_warn("%s: Failed to reserve a valid carveout!\n", __func__); + goto done; + } + + list_add(&co->co_entry, &a->co_list); + +done: + alloc_unlock(__a); + return err; +} + +/* + * Carveouts can be release at any time. + */ +static void gk20a_buddy_release_co(struct gk20a_allocator *__a, + struct gk20a_alloc_carveout *co) +{ + alloc_lock(__a); + + list_del_init(&co->co_entry); + gk20a_free(__a, co->base); + + alloc_unlock(__a); +} + static u64 gk20a_buddy_alloc_length(struct gk20a_allocator *a) { struct gk20a_buddy_allocator *ba = a->priv; @@ -1004,9 +1096,10 @@ static u64 gk20a_buddy_alloc_end(struct gk20a_allocator *a) static void gk20a_buddy_print_stats(struct gk20a_allocator *__a, struct seq_file *s, int lock) { - int i; + int i = 0; struct rb_node *node; struct gk20a_fixed_alloc *falloc; + struct gk20a_alloc_carveout *tmp; struct gk20a_buddy_allocator *a = __a->priv; __alloc_pstat(s, __a, "base = %llu, limit = %llu, blk_size = %llu\n", @@ -1018,12 +1111,23 @@ static void gk20a_buddy_print_stats(struct gk20a_allocator *__a, __alloc_pstat(s, __a, " blks = 0x%llx\n", a->blks); __alloc_pstat(s, __a, " max_order = %llu\n", a->max_order); + if (lock) + alloc_lock(__a); + + if (!list_empty(&a->co_list)) { + __alloc_pstat(s, __a, "\n"); + __alloc_pstat(s, __a, "Carveouts:\n"); + list_for_each_entry(tmp, &a->co_list, co_entry) + __alloc_pstat(s, __a, + " CO %2d: %-20s 0x%010llx + 0x%llx\n", + i++, tmp->name, tmp->base, tmp->length); + } + + __alloc_pstat(s, __a, "\n"); __alloc_pstat(s, __a, "Buddy blocks:\n"); __alloc_pstat(s, __a, " Order Free Alloced Split\n"); __alloc_pstat(s, __a, " ----- ---- ------- -----\n"); - if (lock) - alloc_lock(__a); for (i = a->max_order; i >= 0; i--) { if (a->buddy_list_len[i] == 0 && a->buddy_list_alloced[i] == 0 && @@ -1067,6 +1171,9 @@ static const struct gk20a_allocator_ops buddy_ops = { .alloc_fixed = gk20a_balloc_fixed_buddy, /* .free_fixed not needed. */ + .reserve_carveout = gk20a_buddy_reserve_co, + .release_carveout = gk20a_buddy_release_co, + .base = gk20a_buddy_alloc_base, .length = gk20a_buddy_alloc_length, .end = gk20a_buddy_alloc_end, @@ -1172,6 +1279,7 @@ int __gk20a_buddy_allocator_init(struct gk20a_allocator *__a, a->alloced_buddies = RB_ROOT; a->fixed_allocs = RB_ROOT; + INIT_LIST_HEAD(&a->co_list); err = balloc_init_lists(a); if (err) goto fail; -- cgit v1.2.2