Commit 5359b745 authored by Matthew Auld's avatar Matthew Auld

drm/i915/buddy: add some pretty printing

Implement the debug hook for the buddy resource manager. For this we
want to print out the status of the memory manager, including how much
memory is still allocatable, what page sizes we have etc. This will be
triggered when TTM is unable to fulfil an allocation request for device
local-memory.

v2(Thomas):
    - s/MB/MiB
    - s/KB/KiB
Signed-off-by: default avatarMatthew Auld <matthew.auld@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: default avatarThomas Hellström <thomas.hellstrom@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210819093419.295636-1-matthew.auld@intel.com
parent c9b6e949
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
#include <linux/kmemleak.h> #include <linux/kmemleak.h>
#include <linux/sizes.h>
#include "i915_buddy.h" #include "i915_buddy.h"
...@@ -82,6 +83,7 @@ int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size) ...@@ -82,6 +83,7 @@ int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size)
size = round_down(size, chunk_size); size = round_down(size, chunk_size);
mm->size = size; mm->size = size;
mm->avail = size;
mm->chunk_size = chunk_size; mm->chunk_size = chunk_size;
mm->max_order = ilog2(size) - ilog2(chunk_size); mm->max_order = ilog2(size) - ilog2(chunk_size);
...@@ -155,6 +157,8 @@ void i915_buddy_fini(struct i915_buddy_mm *mm) ...@@ -155,6 +157,8 @@ void i915_buddy_fini(struct i915_buddy_mm *mm)
i915_block_free(mm, mm->roots[i]); i915_block_free(mm, mm->roots[i]);
} }
GEM_WARN_ON(mm->avail != mm->size);
kfree(mm->roots); kfree(mm->roots);
kfree(mm->free_list); kfree(mm->free_list);
} }
...@@ -230,6 +234,7 @@ void i915_buddy_free(struct i915_buddy_mm *mm, ...@@ -230,6 +234,7 @@ void i915_buddy_free(struct i915_buddy_mm *mm,
struct i915_buddy_block *block) struct i915_buddy_block *block)
{ {
GEM_BUG_ON(!i915_buddy_block_is_allocated(block)); GEM_BUG_ON(!i915_buddy_block_is_allocated(block));
mm->avail += i915_buddy_block_size(mm, block);
__i915_buddy_free(mm, block); __i915_buddy_free(mm, block);
} }
...@@ -283,6 +288,7 @@ i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order) ...@@ -283,6 +288,7 @@ i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order)
} }
mark_allocated(block); mark_allocated(block);
mm->avail -= i915_buddy_block_size(mm, block);
kmemleak_update_trace(block); kmemleak_update_trace(block);
return block; return block;
...@@ -368,6 +374,7 @@ int i915_buddy_alloc_range(struct i915_buddy_mm *mm, ...@@ -368,6 +374,7 @@ int i915_buddy_alloc_range(struct i915_buddy_mm *mm,
} }
mark_allocated(block); mark_allocated(block);
mm->avail -= i915_buddy_block_size(mm, block);
list_add_tail(&block->link, &allocated); list_add_tail(&block->link, &allocated);
continue; continue;
} }
...@@ -402,6 +409,44 @@ int i915_buddy_alloc_range(struct i915_buddy_mm *mm, ...@@ -402,6 +409,44 @@ int i915_buddy_alloc_range(struct i915_buddy_mm *mm,
return err; return err;
} }
void i915_buddy_block_print(struct i915_buddy_mm *mm,
struct i915_buddy_block *block,
struct drm_printer *p)
{
u64 start = i915_buddy_block_offset(block);
u64 size = i915_buddy_block_size(mm, block);
drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size);
}
void i915_buddy_print(struct i915_buddy_mm *mm, struct drm_printer *p)
{
int order;
drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB\n",
mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20);
for (order = mm->max_order; order >= 0; order--) {
struct i915_buddy_block *block;
u64 count = 0, free;
list_for_each_entry(block, &mm->free_list[order], link) {
GEM_BUG_ON(!i915_buddy_block_is_free(block));
count++;
}
drm_printf(p, "order-%d ", order);
free = count * (mm->chunk_size << order);
if (free < SZ_1M)
drm_printf(p, "free: %lluKiB", free >> 10);
else
drm_printf(p, "free: %lluMiB", free >> 20);
drm_printf(p, ", pages: %llu\n", count);
}
}
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
#include "selftests/i915_buddy.c" #include "selftests/i915_buddy.c"
#endif #endif
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <drm/drm_print.h>
struct i915_buddy_block { struct i915_buddy_block {
#define I915_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12) #define I915_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12)
#define I915_BUDDY_HEADER_STATE GENMASK_ULL(11, 10) #define I915_BUDDY_HEADER_STATE GENMASK_ULL(11, 10)
...@@ -69,6 +71,7 @@ struct i915_buddy_mm { ...@@ -69,6 +71,7 @@ struct i915_buddy_mm {
/* Must be at least PAGE_SIZE */ /* Must be at least PAGE_SIZE */
u64 chunk_size; u64 chunk_size;
u64 size; u64 size;
u64 avail;
}; };
static inline u64 static inline u64
...@@ -129,6 +132,11 @@ void i915_buddy_free(struct i915_buddy_mm *mm, struct i915_buddy_block *block); ...@@ -129,6 +132,11 @@ void i915_buddy_free(struct i915_buddy_mm *mm, struct i915_buddy_block *block);
void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head *objects); void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head *objects);
void i915_buddy_print(struct i915_buddy_mm *mm, struct drm_printer *p);
void i915_buddy_block_print(struct i915_buddy_mm *mm,
struct i915_buddy_block *block,
struct drm_printer *p);
void i915_buddy_module_exit(void); void i915_buddy_module_exit(void);
int i915_buddy_module_init(void); int i915_buddy_module_init(void);
......
...@@ -126,12 +126,30 @@ static void i915_ttm_buddy_man_free(struct ttm_resource_manager *man, ...@@ -126,12 +126,30 @@ static void i915_ttm_buddy_man_free(struct ttm_resource_manager *man,
kfree(bman_res); kfree(bman_res);
} }
static void i915_ttm_buddy_man_debug(struct ttm_resource_manager *man,
struct drm_printer *printer)
{
struct i915_ttm_buddy_manager *bman = to_buddy_manager(man);
struct i915_buddy_block *block;
mutex_lock(&bman->lock);
drm_printf(printer, "default_page_size: %lluKiB\n",
bman->default_page_size >> 10);
i915_buddy_print(&bman->mm, printer);
drm_printf(printer, "reserved:\n");
list_for_each_entry(block, &bman->reserved, link)
i915_buddy_block_print(&bman->mm, block, printer);
mutex_unlock(&bman->lock);
}
static const struct ttm_resource_manager_func i915_ttm_buddy_manager_func = { static const struct ttm_resource_manager_func i915_ttm_buddy_manager_func = {
.alloc = i915_ttm_buddy_man_alloc, .alloc = i915_ttm_buddy_man_alloc,
.free = i915_ttm_buddy_man_free, .free = i915_ttm_buddy_man_free,
.debug = i915_ttm_buddy_man_debug,
}; };
/** /**
* i915_ttm_buddy_man_init - Setup buddy allocator based ttm manager * i915_ttm_buddy_man_init - Setup buddy allocator based ttm manager
* @bdev: The ttm device * @bdev: The ttm device
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment